<?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>Dvel&#39;s Blog</title>
    <link>https://dvel.me/</link>
    <description>Recent content on Dvel&#39;s Blog</description>
    <generator>Hugo -- 0.140.1</generator>
    <language>zh</language>
    <lastBuildDate>Thu, 18 Dec 2025 20:36:42 +0800</lastBuildDate>
    <atom:link href="https://dvel.me/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Rime 全拼双拼混输</title>
      <link>https://dvel.me/posts/rime-full-pinyin-double-pinyin-mixed-input/</link>
      <pubDate>Mon, 20 Nov 2023 00:00:41 +0800</pubDate>
      <guid>https://dvel.me/posts/rime-full-pinyin-double-pinyin-mixed-input/</guid>
      <description>在 Rime 中通过在拼写运算 speller/algebra 下把 xform 替换为 derive 来实现全拼双拼混输。</description>
      <content:encoded><![CDATA[<p>有朋友提了个 issue 后发现的，Rime 实现全拼双拼混输很简单，只要在拼写运算 <code>speller/algebra</code> 下把 <code>xform</code> 替换为 <code>derive</code> 就可以了。</p>
<p>非常适合初学双拼时使用。</p>
<br>
<h2 id="原理">原理</h2>
<p>例如小鹤双拼的 z 键：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="l">xform/(.)ou$/$1Ⓩ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">xlit/Ⓩ/z/</span><span class="w">
</span></span></span></code></pre></div><p><code>ou</code> 最终转为了韵母的 z，输入 <code>zz</code> 就可以得到「走 zou」了，<code>xform</code>（变形）不保留原型，<code>(.)ou</code> 就没了，改为保留原型的 <code>abbrev</code>（派生）就可以同时支持全拼和双拼了。（<a href="https://github.com/rime/home/wiki/SpellingAlgebra#%E6%8B%BC%E5%AF%AB%E9%81%8B%E7%AE%97%E7%9A%84%E9%81%8B%E7%AE%97%E5%AD%90" target="_blank" rel="noopener">官方文档 - 拼写运算的运算子</a>）</p>
<h2 id="解决副作用">解决副作用</h2>
<h4 id="显示效果">显示效果</h4>
<p>为了全拼双拼混输的显示效果，也要清空 <code>translator/preedit_format</code> 中对双拼转全拼的转换。</p>
<h4 id="全拼与双拼的冲突">全拼与双拼的冲突</h4>
<p>例如全拼的 jing（静）与小鹤双拼的 ji&rsquo;ng（技能），Rime 默认 jing 永远排在 ji&rsquo;ng 前面，这不太符合双拼为主的情况。</p>
<p>正好全拼的长词优先在这里可以发挥作用了，用 <code>long_word_filter.lua</code> 将「技能」提到「静」的前面。</p>
<h2 id="示例">示例</h2>
<p><a href="https://github.com/iDvel/rime-ice" target="_blank" rel="noopener">雾凇拼音</a> - 小鹤双拼的补丁示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># double_pinyin_flypy.custom.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">patch</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"># 双拼不转换为全拼编码</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">translator/preedit_format</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></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># 在 engine/filters 插入长词优先的 Lua</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">engine/filters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*corrector</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">reverse_lookup_filter@radical_reverse_lookup</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*autocap_filter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*pin_cand_filter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*long_word_filter   </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">lua_filter@*reduce_english_filter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">simplifier@emoji</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">simplifier@traditionalize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*search@radical_pinyin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">uniquifier</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"># 长词优先设置为提升 10 个词到第 1 个位置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">long_word_filter</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">count</span><span class="p">:</span><span class="w"> </span><span class="m">10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">idx</span><span class="p">:</span><span class="w"> </span><span class="m">1</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"># xform 变形改为 derive 派生</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">speller/algebra</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^([jqxy])u$/$1v/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^([aoe])([ioun])$/$1$1$2/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^([aoe])(ng)?$/$1$1$2/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/iu$/Ⓠ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)ei$/$1Ⓦ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/uan$/Ⓡ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/[uv]e$/Ⓣ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/un$/Ⓨ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^sh/Ⓤ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^ch/Ⓘ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/^zh/Ⓥ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/uo$/Ⓞ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/ie$/Ⓟ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)i?ong$/$1Ⓢ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/ing$|uai$/Ⓚ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)ai$/$1Ⓓ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)en$/$1Ⓕ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)eng$/$1Ⓖ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/[iu]ang$/Ⓛ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)ang$/$1Ⓗ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/ian$/Ⓜ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)an$/$1Ⓙ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)ou$/$1Ⓩ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/[iu]a$/Ⓧ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/iao$/Ⓝ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/(.)ao$/$1Ⓒ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/ui$/Ⓥ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">derive/in$/Ⓑ/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">xlit/ⓆⓌⓇⓉⓎⓊⒾⓄⓅⓈⒹⒻⒼⒽⒿⓀⓁⓏⓍⒸⓋⒷⓃⓂ/qwrtyuiopsdfghjklzxcvbnm/</span><span class="w">
</span></span></span></code></pre></div><p>效果展示：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-11-20-002011.webp"
            alt="2023-11-20-002011"
            width="406"
            height="418"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>CHD 油猴脚本：每日签到自动答题</title>
      <link>https://dvel.me/posts/chd-quiz-answer/</link>
      <pubDate>Thu, 16 Mar 2023 00:03:36 +0800</pubDate>
      <guid>https://dvel.me/posts/chd-quiz-answer/</guid>
      <description>GPT-4 辅助编写油猴脚本，实现自动获取 ChatGPT API 解析的答案，无需查阅教程或文档。示例为 CHD 自动答题脚本，可优化输出位置、自动选中正确答案等。安装链接：https://greasyfork.org/zh-CN/scripts/461944-chd-quiz-answer。</description>
      <content:encoded><![CDATA[<p>用 ChatGPT 写一些小脚本真是太方便了。</p>
<p>GPT-4 发布后试了试，还是蛮不错的，代码是 ChatGPT 生成的。</p>
<p>几个来回就可以编写一个能正常使用的油猴脚本：</p>
<pre tabindex="0"><code>（略，HTML 代码）
在 https://chdbits.co/bakatest.php 有如上内容。
我要为这个网页编写一个油猴脚本。
通过自动获取 ChatGPT 的 API 来解析此问题的答案，供用户参考。

将内容输出到 `#outer &gt; h1` 的下面，同时输出你提取到的问题内容和答案，以便我看看你是否提取正确。

获取错啦。
问题的获取路径是 `#outer &gt; form &gt; table &gt; tbody &gt; tr:nth-child(1) &gt; td`
选项的获取路径是 `#outer &gt; form &gt; table &gt; tbody &gt; tr:nth-child(2) &gt; td`

使用这个 API：
```
curl https://api.openai.com/v1/chat/completions \
  -H &#39;Content-Type: application/json&#39; \
  -H &#39;Authorization: Bearer YOUR_API_KEY&#39; \
  -d &#39;{
  &#34;model&#34;: &#34;gpt-3.5-turbo&#34;,
  &#34;messages&#34;: [{&#34;role&#34;: &#34;user&#34;, &#34;content&#34;: &#34;Say this is a test!&#34;}],
  &#34;temperature&#34;: 0.7
}&#39;
```
响应格式为：
```
{
   &#34;id&#34;:&#34;chatcmpl-abc123&#34;,
   &#34;object&#34;:&#34;chat.completion&#34;,
   &#34;created&#34;:1677858242,
   &#34;model&#34;:&#34;gpt-3.5-turbo-0301&#34;,
   &#34;usage&#34;:{
      &#34;prompt_tokens&#34;:13,
      &#34;completion_tokens&#34;:7,
      &#34;total_tokens&#34;:20
   },
   &#34;choices&#34;:[
      {
         &#34;message&#34;:{
            &#34;role&#34;:&#34;assistant&#34;,
            &#34;content&#34;:&#34;\n\nThis is a test!&#34;
         },
         &#34;finish_reason&#34;:&#34;stop&#34;,
         &#34;index&#34;:0
      }
   ]
}
```
</code></pre><p>它没有最近的互联网数据，所以还是需要把 API 的使用方式发给它。</p>
<p>然后它就帮我写好了，我不用复习 JavaScript，不用看油猴脚本的教程和文档，也不用查 <code>@grant</code> 等等标记是干嘛的。</p>
<p>可以再继续要求它改进一些，比如换个输出位置，优化 prompt，自动选中正确回答，支持单选题和多选题等等。</p>
<p>效果展示：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-03-16-001490.gif"
            alt="CHD 自动答题"
            width="800"
            height="489"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>安装： <a href="https://greasyfork.org/zh-CN/scripts/461944-chd-quiz-answer" target="_blank" rel="noopener">https://greasyfork.org/zh-CN/scripts/461944-chd-quiz-answer</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Rime 配置：雾凇拼音</title>
      <link>https://dvel.me/posts/rime-ice/</link>
      <pubDate>Fri, 20 Jan 2023 00:33:36 +0800</pubDate>
      <guid>https://dvel.me/posts/rime-ice/</guid>
      <description>Rime 配置——雾凇拼音的简介；长期维护的 Rime 简体拼音词库；Rime 教程，新手指引。</description>
      <content:encoded><![CDATA[<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-08-07.webp"
            alt="雾凇拼音 demo"
            width="2660"
            height="1777"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>雾凇拼音，功能齐全，词库体验良好，长期更新修订，仓库：<a href="https://github.com/iDvel/rime-ice" target="_blank" rel="noopener">iDvel/rime-ice</a></p>
<br>
<p><a href="https://rime.im/" target="_blank" rel="noopener">Rime Input Method Engine / 中州韵输入法引擎</a> 是一个跨平台的输入法算法框架。</p>
<p>基于这一框架，Rime 开发者与其他开源社区的参与者在多个平台上创造了不同的输入法前端实现。</p>
<p><strong>雾凇拼音</strong>是 Rime 的一份配置仓库，用户需要下载 <a href="https://github.com/rime/librime/#frontends" target="_blank" rel="noopener">各平台对应的前端</a>，并将此配置应用到配置目录。</p>
<p><strong>雾凇拼音</strong>提供了一套开箱即用的完整配置，包含输入方案（全拼、常见双拼）、长期维护的开源词库及各项扩展功能。</p>
<p><a href="https://github.com/iDvel/rime-ice/issues/133" target="_blank" rel="noopener">常见问题</a> | <a href="https://github.com/iDvel/rime-ice/blob/main/others/CHANGELOG.md" target="_blank" rel="noopener">更新日志</a></p>
<h2 id="基本套路">基本套路</h2>
<ul>
<li>简体 | 全拼 | 双拼</li>
<li>主要功能
<ul>
<li>轻量的英文输入，支持中英混输</li>
<li><a href="https://dvel.me/posts/make-rime-en-better/" target="_blank" rel="noopener">优化英文输入体验</a></li>
<li>拆字反查（<kbd>uU</kbd>+拼音），拆字辅码（拼音+<kbd>`</kbd>+拆字辅码）</li>
<li>自整理的 Emoji</li>
<li>以词定字（左右中括号：<kbd>[</kbd>、<kbd>]</kbd>）</li>
<li>长词优先</li>
<li>Unicode（<kbd>U</kbd>+Unicode 码位）</li>
<li>数字、人民币大写（<kbd>R</kbd>+数字）</li>
<li>日期、时间、星期（详见方案 <code>/date_translator</code> 节点）</li>
<li>农历（转写：<kbd>N</kbd>+八位数字；获取当前农历：全拼<kbd>nl</kbd>，双拼<kbd>lunar</kbd>）</li>
<li>简易计算器（<kbd>cC</kbd>+算式）</li>
<li>UUID（<kbd>uuid</kbd>）</li>
<li>常见错音错字提示</li>
<li>置顶候选项（详见方案 <code>/pin_cand_filter</code> 节点）</li>
<li>所有标点符号直接上屏</li>
<li>特殊符号、字符输入（全拼<kbd>v</kbd>+首字母缩写；双拼<kbd>V</kbd>+首字母缩写）</li>
<li>拼音纠错（模糊音）</li>
<li>更多默认未启用的功能请参考 <code>lua/</code> 及方案注释</li>
</ul>
</li>
<li>简体字表、词库
<ul>
<li><a href="https://github.com/iDvel/The-Table-of-General-Standard-Chinese-Characters" target="_blank" rel="noopener">通用规范汉字表</a>（by 中华人民共和国教育部）8K 常用汉字</li>
<li><a href="https://www.unicode.org/Public/" target="_blank" rel="noopener">Unihan 字库</a>（by Unicode lnc | <a href="https://www.unicode.org/license.txt" target="_blank" rel="noopener">UNICODE LICENSE V3</a>）40K 大字库， <strong>默认未启用</strong></li>
<li><a href="https://zh.wikipedia.org/wiki/%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E8%AF%8D%E8%A1%A8" target="_blank" rel="noopener">现代汉语常用词表</a>（by 中国国家语言文字工作委员会）</li>
<li><a href="http://bbs.pinyin.thunisoft.com/forum.php?mod=viewthread&amp;tid=30049" target="_blank" rel="noopener">华宇野风词库</a>（by 野风）</li>
<li><a href="https://github.com/rime/rime-essay-simp" target="_blank" rel="noopener">简化字八股文</a>（by rime | <a href="https://github.com/rime/rime-essay-simp/blob/master/LICENSE" target="_blank" rel="noopener">LGPL</a>）</li>
<li><a href="https://github.com/thunlp/THUOCL" target="_blank" rel="noopener">清华大学开源词库</a>（by THUNLP | <a href="https://github.com/thunlp/THUOCL/blob/master/LICENSE" target="_blank" rel="noopener">MIT</a>）</li>
<li><a href="https://ai.tencent.com/ailab/nlp/en/download.html" target="_blank" rel="noopener">腾讯词向量</a>（@Huandeep <a href="https://github.com/iDvel/rime-ice/issues/24" target="_blank" rel="noopener">整理</a> | by Tencent AI Lab | <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank" rel="noopener">CC BY 3.0</a>）</li>
</ul>
</li>
<li>词库修订
<ul>
<li>校对大量异形词、错别字、错误注音</li>
<li>全词库完成注音</li>
<li>同义多音字注音</li>
<li>参考
<ul>
<li>《现代汉语词典》</li>
<li>《同义词词林》</li>
<li>《新华成语大词典》</li>
<li><a href="http://www.jiaodui.org/bbs/" target="_blank" rel="noopener">校对标准论坛</a></li>
</ul>
</li>
</ul>
</li>
<li>Rime、Squirrel、Weasel 常用配置项的详尽注释</li>
</ul>
<h2 id="方案设计">方案设计</h2>
<pre tabindex="0"><code>.
├── default.yaml   # 一些全局设置

├── rime_ice.schema.yaml  # 全拼方案
├── double_pinyin*.yaml   # 双拼方案
├── rime_ice.dict.yaml    # 挂载词库
├── cn_dicts/             # 词库目录

├── melt_eng.schema.yaml  # 英文方案，作为次翻译器挂载到拼音方案
├── melt_eng.dict.yaml    # 挂载词库
├── en_dicts/             # 词库目录

├── radical_pinyin.schema.yaml  # 部件拆字方案，作为反查挂载到拼音方案
├── radical_pinyin.dict.yaml    # 部件拆字词库

├── custom_phrase.txt    # 自定义短语
├── symbols_v.yaml       # 全拼 v 模式
├── symbols_caps_v.yaml  # 双拼 V 模式
├── opencc/              # 词语映射，Emoji
├── lua/                 # 各个 Lua 脚本

├── squirrel.yaml  # 鼠须管的前端配置文件
└── weasel.yaml    # 小狼毫的前端配置文件
</code></pre><p>支持了全拼和部分双拼。</p>
<p>对于英文输入做了一些 hack，详见<a href="/posts/make-rime-en-better/">优化英文输入体验</a>。</p>
<p>启用了自定义短语，全拼为 <code>custom_phrase.txt</code>，双拼为 <code>custom_phrase_double.txt</code> 需要手动创建。</p>
<p>将 Rime 默认的「/」模式改为了「v」模式，全拼为小写 v 开头，双拼为大写 V 开头，分别在 <code>symbols_v.yaml</code> 和 <code>symbols_caps_v.yaml</code> 中定义。</p>
<p>支持了 Emoji 和部分词语映射，在 <code>opencc/</code> 文件夹中定义。</p>
<p><strong>Lua 设置：</strong></p>
<p>提取了一些可配置的选项出来，触发关键字及前缀都可以直接在方案里修改，不用修改 <code>.lua</code> 文件。</p>
<p><strong>以词定字</strong>：的快捷键写在了 <code>default.yaml</code>，因为可能和方括号翻页冲突，其余的 Lua 都在方案文件中设定，参考注释即可。</p>
<p><strong>长词优先</strong>（全拼）：默认是提升 2 个词提到第 4 个位置。</p>
<p><strong>以词定字</strong>：默认快捷键为左右中括号 <code>[</code> <code>]</code>，分别取第一个和最后一个字。</p>
<p><strong>日期时间</strong>：全拼的触发编码为 <code>rq sj xq dt ts</code>，双拼为 <code>date time week datetime timestamp</code>。</p>
<p><strong>农历</strong>：全拼 <code>nl</code>，双拼 <code>lunar</code>。</p>
<p>在 <code>lua/</code> 中还有一些默认未启用的脚本，可自行配置。</p>
<p><strong>一些前缀功能的默认设置：</strong></p>
<ul>
<li>
<p>symbols：全拼 <code>v</code> 开头、双拼大写 <code>V</code> 开头</p>
</li>
<li>
<p>部件拆字的反查：<code>uU</code> 开头，反查时前缀会消失影响打英文所以设定为两个字母，或可改成一个非字母符号。</p>
</li>
<li>
<p>部件拆字的辅码：<code>`</code> 触发。</p>
</li>
<li>
<p>计算机：<code>cC</code> 开头，前缀会消失影响打英文所以设定为两个字母，或可改成一个非字母符号。</p>
</li>
<li>
<p>Unicode：大写 <code>U</code> 开头，如 <code>U62fc</code> 得到「拼」。</p>
</li>
<li>
<p>数字、金额大写：大写 <code>R</code> 开头，如 <code>R1234</code> 得到「一千二百三十四、壹仟贰佰叁拾肆元整」。</p>
</li>
<li>
<p>农历指定日期：大写 <code>N</code> 开头，如 <code>N20240210</code> 得到「二〇二四年正月初一」。</p>
</li>
</ul>
<p><strong>置顶候选项：</strong></p>
<p>自定义短语 custom_phrase 实现置顶是以一个新的高权重的 table_translator 诞生一个新的词汇。
如果在 custom_phrase 里写了 <code>的	de</code>，输入 de 时「的」排在了候选项最前面，接着经过去重，拼音翻译器自己的「的」没了，只保留了 custom_phrase 的「的」。
由于两个翻译器之间无法造词，所以「的」这个字失去了造词效果，因此之前建议只写非完整拼音的编码，如 <code>的	d</code>。</p>
<p>现在由 <code>pin_cand_filter.lua</code> 实现置顶，这个 Lua 仅仅是调整候选项的顺序（没有创造词汇编码的功能），被置顶的「的」仍然是拼音翻译器自己的「的」，可以造词，也就可以置顶完整的拼音。</p>
<p>此功能通过对比去掉空格后的 <code>cand.preedit</code> 来实现，编码一致时，按顺序置顶配置中的词汇；</p>
<p>并与 <code>env.engine.context:get_preedit().text</code> 的字母部分做对比来实现在句子中时仍然置顶。</p>
<img src="/img/2024-02-05-002442.png" alt="2024-02-05-002442" style="zoom:50%;" />
<h2 id="上手修改">上手修改</h2>
<p>简单来说，<code>default.yaml</code> 是入口文件，决定了一份配置使用哪些方案，可以只保留自己需要的方案。</p>
<p>里面还有一些特殊设定，候选词个数、方案选单、中西文切换等等，另外将一些所有方案较为通用的配置项也写在 <code>default</code> 里了，再在方案中引用。</p>
<br>
<p>方案文件 <code>rime_ice.schema.yaml</code>（全拼）或 <code>double_pinyin*.yaml</code>（双拼）是最主要的配置文件，所有功能的引用和实现都在方案文件中。</p>
<p>自定义短语、opencc、symbols 等等是引用的哪个文件、启用了什么 Lua 等等，都是在方案文件中体现的。</p>
<br>
<p><code>melt_eng</code> 与 <code>radical_pinyin</code> 没有作为单独的输入方案，而是作为辅助功能挂载到拼音方案中，以支持在拼音方案下输入英文和拼字。</p>
<br>
<p>因为中英文的词库文件较多，<code>rime_ice.dict.yaml</code> 与 <code>melt_eng.dict.yaml</code> 也是作为入口文件，将具体词库放到了文件夹中，让配置目录清爽一些。</p>
<br>
<p>无论您是折腾能手还是只想一键使用，都建议至少大概翻看一下 <code>default.yaml</code> 和所使用的方案文件，可以了解到所有功能。</p>
<p>配置中基本都写了注释，大多数修改都非常简单，如候选项个数、各种触发关键字等等，如果只做小修改，通读一遍即可。</p>
<p>尝试折腾期间，直接在现有文件上修改比较方便。若要考虑拉取更新导致的覆盖问题，可参考下文的打补丁方式。</p>
<h2 id="长期维护词库">长期维护词库</h2>
<p>因为没有找到一份比较好的词库，干脆自己维护一个。综合了几个不错的词库，精心调教了很多。</p>
<p>词库简介：</p>
<ul>
<li>字表：
<ul>
<li><code>8105</code> 常用字表，《通用规范汉字表》+基本的扩充。</li>
<li><code>41448</code> Unihan 大字表，默认未启用。</li>
</ul>
</li>
<li>词库：
<ul>
<li><code>base</code> 基础词库，含两字词及调频。</li>
<li><code>ext</code> 扩展词库，小词库，含多音字注音。</li>
<li><code>tencent</code> 扩展词库，大词库，无注音（由 Rime 自动注音），含非多音字、只发一种音的多音字、同义多音字。</li>
</ul>
</li>
<li>纯手搓的 Emoji</li>
<li>英文词库：
<ul>
<li><code>en</code> 20k 左右的常见单词 + 少许补充。</li>
<li><code>en_ext</code> 扩展词库，大部分是缩写或互联网相关。</li>
</ul>
</li>
</ul>
<p>维护内容主要是异形词、错别字的校对，错误注音的修正，缺失的常用词汇的增添，词频的调整。</p>
<p>欢迎在词库方面提 issue <a href="https://github.com/iDvel/rime-ice/issues/666" target="_blank" rel="noopener">#666</a> ，我会及时更新修正。</p>
<h2 id="词库的设计">词库的设计</h2>
<p>Rime 自带的「朙月拼音·简化字」方案其实是繁体词库加上一个自动繁转简的设定，出词仍旧是经过 OpenCC 转换，用户词典中保存的输入历史还是繁体的。</p>
<p>简体用户推荐使用简体词库，引入一些第三方词库也比较方便，还可以避免 OpenCC 的少数转换错误，修订词汇时也只需要按照大陆简体标准修订。</p>
<h3 id="多音字">多音字</h3>
<p>已经为全词库完成注音。</p>
<p><code>tencent</code> 词库包含的多音字过于庞大，对于没有编码的词库文件，Rime 会根据方案的字表进行自动注音。</p>
<blockquote>
<p>当含有多音字的词组缺少编码字段时，自动注音程序会利用权重百分比高于 5% 的读音进行组合、生成全部可能的注音。—— <a href="https://github.com/rime/home/wiki/RimeWithSchemata#%E7%A2%BC%E8%A1%A8%E8%88%87%E8%A9%9E%E5%85%B8" target="_blank" rel="noopener">Rime 输入方案设计书</a></p>
</blockquote>
<p>如果不做处理，多音字可以被多种注音打出来，有一些会造成困扰，比如「没发展」可以被 mo fa zhan（魔法战）打出来。</p>
<p>目前的解决方案：</p>
<p>保证 <code>tencent</code> 词库只被一种音注音，手动注音其他音。</p>
<p>例如「的 de di」，手动注音包含 di 音的所有词汇，然后确保字表权重 <code>de * 0.05 &gt; di</code>；</p>
<p>对于「长 chang zhang」这样不易区分的，全部注音并用勤劳的双手完成校对。</p>
<p><code>tencent</code> 词库还保留了一些同义多音字、文白异读的「血、熟、爪、薄」等等将会自动进行多种注音。</p>
<h3 id="两字词">两字词</h3>
<p>两字词统一放到 <code>base.dict.yaml</code> 中，便于平时修订和调频。</p>
<p>因为两字词的排序基本决定了词库舒适度，重码较多，所以都加上注音和权重，并大量增删和调频。</p>
<p>扩展词库的两字词都没有自动加入，平时扩充时都是肉眼检查后再添加。</p>
<h3 id="扩展词库">扩展词库</h3>
<p>主词库缺少了很多常用词和流行小短句，挂载扩展词库后体验会好很多。</p>
<p><code>tencent.dict.yaml</code> 只取了腾讯词向量的一百万个词条，算是比较平衡的选择。</p>
<p><code>base.dict.yaml</code>、<code>ext.dict.yaml</code> 与 <code>tencent.dict.yaml</code> 已经遭受过大量交叉修改，目前的区别就是 <code>ext</code> 里可能包含需要明确注音的多音字，<code>base</code> 里可能包含需要明确调频的同音词。</p>
<h2 id="新手指引">新手指引</h2>
<p>一些桌面发行版：</p>
<ul>
<li>
<p><a href="https://github.com/rime/squirrel" target="_blank" rel="noopener">鼠须管 Squirrel</a> —— 官方 macOS 发行版</p>
</li>
<li>
<p><a href="https://github.com/fcitx-contrib/fcitx5-macos" target="_blank" rel="noopener">fcitx5-macos</a> —— 小企鹅 Mac 版，支持全局状态和卷轴模式</p>
</li>
<li>
<p><a href="https://github.com/rime/weasel" target="_blank" rel="noopener">小狼毫 Weasel</a> —— 官方 Windows 发行版</p>
</li>
<li>
<p>Linux 下有 ibus-rime、fcitx-rime、fcitx5，不太了解。</p>
</li>
</ul>
<p>一些参考、文档、教程：</p>
<ul>
<li><a href="https://github.com/rime/home/wiki" target="_blank" rel="noopener">官方 wiki</a></li>
<li><a href="https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/Rime_description.md" target="_blank" rel="noopener">方案制作详解</a></li>
<li><a href="https://www.hawu.me/others/2666" target="_blank" rel="noopener">鼠须管输入法配置</a></li>
<li><a href="https://ssnhd.com/2022/01/06/rime/" target="_blank" rel="noopener">Rime Squirrel 鼠须管输入法配置详解</a></li>
<li><a href="https://github.com/rime/home/discussions" target="_blank" rel="noopener">Rime 官方讨论区</a></li>
</ul>
<p>配置中并没有列出属性的所有可选项，有特殊需求可以看看文档。</p>
<p>如果要折腾配置，建议将 <a href="https://github.com/rime/home/wiki" target="_blank" rel="noopener">官方 wiki</a> 和 <a href="https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/Rime_description.md" target="_blank" rel="noopener">方案制作详解</a> 下载下来放在一起，需要查找一些配置项的时候，全局搜索一下即可。</p>
<p>还有很多，已经很全面了，下面的只是结合本配置随便写一点。</p>
<h3 id="字体">字体</h3>
<p>推荐<a href="https://github.com/lxgw/LxgwWenKai" target="_blank" rel="noopener">霞鹜文楷</a>，它能识别简体的「𰻝𰻝面 biang biang mian」中的「𰻝」😄，而且拿它做 Rime 的字体也不错。</p>
<p>如果要用大字表，候选项中可能充满问号，推荐参考 <a href="https://github.com/iDvel/rime-ice/issues/841" target="_blank" rel="noopener">issues#841</a> 的推荐字体。</p>
<h3 id="目录">目录</h3>
<ul>
<li>
<p>配置目录 / 用户文件夹：</p>
<ul>
<li>
<p>鼠须管： <code>~/Library/Rime</code></p>
</li>
<li>
<p>小狼毫： <code>%APPDATA%\Rime</code></p>
</li>
</ul>
</li>
<li>
<p>共享目录 / 程序文件夹：</p>
<ul>
<li>鼠须管： <code>/Library/Input Methods/Squirrel.app/Contents/SharedSupport</code></li>
<li>小狼毫： <code>&lt;安装目录&gt;\data</code></li>
</ul>
</li>
</ul>
<p>自己的配置放到配置目录里就可以。共享目录提供了一些自带的方案及各项默认配置，可以直接引用；无特殊需求，不要修改共享目录的文件。</p>
<p>比如 OpenCC 简繁转换的配置可以直接书写 <code>s2t.json</code>，因为共享目录里已经有相关文件了。</p>
<h3 id="tab-与空格">Tab 与空格</h3>
<p>注意编辑器的缩进配置。</p>
<p>Rime 的 YAML 配置文件需要严格的缩进，使用两个空格缩进，不要用 Tab。</p>
<p>词库文件的词条是用 Tab 分割的：</p>
<pre tabindex="0"><code>拼音	pin yin 1234
拼音&lt;Tab&gt;pin&lt;Space&gt;yin&lt;Tab&gt;1234
</code></pre><p>对于普通用户来说，推荐使用 VSCode 这种能配置和区分空格与 Tab 的编辑器（而不是记事本），同时使用等宽字体。</p>
<h3 id="其他杂项小说明">其他杂项小说明</h3>
<p>完成部署后，首先在 <code>default.yaml</code> 中查看呼出方案选单的快捷键。</p>
<p><code>build/</code> 目录是部署后自动生成的，不要修改，出错时可以看看里面生成的是否正确。</p>
<p>首次部署较慢，主要是拼音方案词库很大，如果下次部署前没有修改词库，就会很快完成部署。</p>
<p><code>translator/enable_user_dict</code> 是默认开启的，即记录用户输入内容。</p>
<p>用户词典类型 <code>translator/db_class</code> 的值默认为 <code>userdb</code>，即二进制文件，输入过的内容会记录在 <code>*.userdb/</code> 文件夹中，只有在同步后才能在同步目录看到人类可读的用户词典；另一个值是 <code>tabledb</code>，会直接在配置目录生成一个人类可读的 txt 文件。如有多平台同步需求，使用默认值 <code>userdb</code>。</p>
<h3 id="配置的引用">配置的引用</h3>
<p>Rime 的配置可以很灵活复杂，比如设置一个快捷键：</p>
<ul>
<li>可以在方案文件 <code>xxx.schema.yaml</code> 中设定；</li>
<li>也可以在方案的补丁文件 <code>xxx.custom.yaml</code> 中设定；</li>
<li>也可以写在 <code>default.yaml</code> 或 <code>defaut.custom.yaml</code> 中，再在方案中引用；</li>
<li>也可以额外创建一个 YAML 文件，再在方案中中引用。</li>
</ul>
<p>比如我想让所有方案共用同一套快捷键，不用写很多份。写在 <code>default</code> 中就比较合适，然后再在多个方案中进行引用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 1. 在 default.yaml 或 default.custom.yaml 中配置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">key_binder</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">bindings</span><span class="p">:</span><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></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></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># 2. 在多个方案 xxx.schema.yaml 或 xxx.custom.yaml 中引用</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">key_binder</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">import_preset</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w"> </span><span class="c"># 从 default 继承快捷键的相关配置</span><span class="w">
</span></span></span></code></pre></div><p><code>import_preset</code> 是导入成套的配置。</p>
<p><code>__include</code> 是在当前位置包含另一 YAML 节点的内容。</p>
<p>具体用法参考官方 wiki。</p>
<p>下面是一个典型的示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 方案文件 xxx.schema.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">punctuator</span><span class="p">:</span><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></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># __include: punctuation:/  # 从共享目录引入预设的 punctuation.yaml</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"># import_preset: symbols    # 从共享目录引入预设的 symbols.yaml</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">full_shape</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">__include</span><span class="p">:</span><span class="w"> </span><span class="l">default:/punctuator/full_shape </span><span class="w"> </span><span class="c"># 从 default.yaml 导入配置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">half_shape</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">__include</span><span class="p">:</span><span class="w"> </span><span class="l">default:/punctuator/half_shape </span><span class="w"> </span><span class="c"># 从 default.yaml 导入配置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">symbols</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">__include</span><span class="p">:</span><span class="w"> </span><span class="l">symbols_v:/symbols             </span><span class="w"> </span><span class="c"># 从 symbols_v.yaml 导入配置</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="c"># full_shape:</span><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="c"># half_shape:</span><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="c"># symbols:</span><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></code></pre></div><h3 id="以-patch-的方式打补丁">以 patch 的方式打补丁</h3>
<p>文件名为 <code>xxx.custom.yaml</code>，内容以 <code>patch:</code> 开头的，是补丁文件，<strong>注意缩进</strong>，可以对原配置进行覆盖和追加。</p>
<ul>
<li>方案 <code>xxx.schema.yaml</code> 的补丁文件是 <code>xxx.custom.yaml</code></li>
<li><code>default.yaml</code> <code>squirrel.yaml</code> 就是把结尾的 <code>.yaml</code> 改成 <code>.custom.yaml</code></li>
</ul>
<p>具体语法参考官方 wiki：<a href="https://github.com/rime/home/wiki/CustomizationGuide#%E5%AE%9A%E8%A3%BD%E6%8C%87%E5%8D%97" target="_blank" rel="noopener">定製指南</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">patch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;一级设定项/二级设定项/三级设定项&#34;: </span><span class="l">新的设定值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;另一个设定项&#34;: </span><span class="l">新的设定值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;再一个设定项&#34;: </span><span class="l">新的设定值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/@n&#34;: </span><span class="l">列表第n个元素新的设定值，从0开始计数</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/@last&#34;: </span><span class="l">列表最后一个元素新的设定值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/@before 0&#34;: </span><span class="l">在列表第一个元素之前插入新的设定值（不建议在补靪中使用）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/@after last&#34;: </span><span class="l">在列表最后一个元素之后插入新的设定值（不建议在补靪中使用）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/@next&#34;: </span><span class="l">在列表最后一个元素之后插入新的设定值（不建议在补靪中使用）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含列表的设定项/+&#34;: </span><span class="l">与列表合并的设定值（必须为列表）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">&#34;含字典的设定项/+&#34;: </span><span class="l">与字典合并的设定值（必须为字典，注意YAML字典的无序性）</span><span class="w">
</span></span></span></code></pre></div><p>patch 时支持用 <code>/</code> 来分隔节点，打补丁时可以这样写（比如有如下文件 <code>rime_ice.custom.yaml</code>）：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">patch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">a/b</span><span class="p">:</span><span class="w"> </span><span class="l">new_value</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">c/d/e</span><span class="p">:</span><span class="w"> </span><span class="l">new_value</span><span class="w">
</span></span></span></code></pre></div><p>但是非补丁的文件只能展开来写（比如 <code>rime_ice.schema.yaml</code>）：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">a</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">b</span><span class="p">:</span><span class="w"> </span><span class="l">value</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">c</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">d</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">e</span><span class="p">:</span><span class="w"> </span><span class="l">value</span><span class="w">
</span></span></span></code></pre></div><h4 id="几个打补丁的示例">几个打补丁的示例</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 以 patch: 开头，后面的内容都需要缩进</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">patch</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">##### 修改单项</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># 正确 ✅ 这种方式只覆盖 Shift_L，不影响其他选项</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ascii_composer/switch_key/Shift_L</span><span class="p">:</span><span class="w"> </span><span class="l">commit_code</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"># 错误 ❌ 这样导致 switch_key 下将只有 Shift_L 一个选项</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ascii_composer/switch_key</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Shift_L</span><span class="p">:</span><span class="w"> </span><span class="l">commit_code</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">ascii_composer</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">good_old_caps_lock</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">switch_key</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Caps_Lock</span><span class="p">:</span><span class="w"> </span><span class="l">commit_code</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Shift_L</span><span class="p">:</span><span class="w"> </span><span class="l">commit_code</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Shift_R</span><span class="p">:</span><span class="w"> </span><span class="l">noop</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Control_L</span><span class="p">:</span><span class="w"> </span><span class="l">noop</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Control_R</span><span class="p">:</span><span class="w"> </span><span class="l">noop</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="c"># 保留已有的快捷键，追加一个逗号句号翻页</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">key_binder/bindings/+</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 class="nt">when: paging, accept: comma, send</span><span class="p">:</span><span class="w"> </span><span class="l">Page_Up }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- {<span class="w"> </span><span class="nt">when: has_menu, accept: period, send</span><span class="p">:</span><span class="w"> </span><span class="l">Page_Down }</span><span class="w">
</span></span></span></code></pre></div><p>如果选项是数组，比如 <code>switches</code>，得用 <code>switches/@n:</code> 什么的，可读性不好，改多了就乱了，万一原始方案文件更改了顺序就会造成错误，不如全部复制过来再改。</p>
<h3 id="编写词库">编写词库</h3>
<p>由于 Rime 的设计，拼音词库中并不适用非拼音编码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="l">hello	hello</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">世界	s j</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">蒙奇·D·路飞	meng qi d lu fei</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">非拼音编码	asdasdasd</span><span class="w">
</span></span></span></code></pre></div><p>Rime 在部署时会综合词库中所有音节和拼写规则生成一个映射表，如果开启了简拼，过多的英文单词会导致打字时极其卡顿。上面单个的编码也会导致 <code>s</code>、<code>j</code>、<code>d</code> 结尾时无法响应超级简拼。</p>
<p>英文建议放到英文方案，非常规的注音建议放到自定义短语 <code>custom_phrase.txt</code>。</p>
<p>词库默认的列是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><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">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;版本号&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sort</span><span class="p">:</span><span class="w"> </span><span class="l">by_weight（按权重排序） | original（按码表顺序排序）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">columns</span><span class="p">:</span><span class="w">    </span><span class="c"># 不写 columns 属性时，默认顺序为：</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">text   </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">code   </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">weight </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">stem   </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="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">你好	ni hao	123</span><span class="w">
</span></span></span></code></pre></div><p>对于没有注音，又想设置权重的词库文件，修改列即可：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">xxx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sort</span><span class="p">:</span><span class="w"> </span><span class="l">by_weight</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">columns</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">text   </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">weight </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="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">你好	123</span><span class="w">
</span></span></span></code></pre></div><h3 id="挂载自己的词库">挂载自己的词库</h3>
<p>词库文件以 <code>.dict.yaml</code> 结尾。</p>
<p>词库由具体方案指定：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># rime_ice.schema.yaml</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">translator</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">rime_ice</span><span class="w"> </span><span class="c"># 挂载词库文件 rime_ice.dict.yaml</span><span class="w">
</span></span></span></code></pre></div><p>可以把所有词条堆在这个文件，也可以将这个文件作为一个入口，通过 <code>import_tables</code> 再挂载多个词库：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># rime_ice.dict.yaml</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="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">rime_ice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">import_tables</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">mydict           </span><span class="w"> </span><span class="c"># 挂载配置目录下的 mydict.dict.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">cn_dicts/mydict2 </span><span class="w"> </span><span class="c"># 挂载 cn_dicts/ 目录下的 mydict2.dict.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># mydict.dict.yaml</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="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">mydict</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sort</span><span class="p">:</span><span class="w"> </span><span class="l">by_weight</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">你好	ni hao	1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">世界	shi jie	1</span><span class="w">
</span></span></span></code></pre></div><p>词库名 <code>xxx.dict.yaml</code> 和词库中的属性 <code>name: xxx</code> 可以不同，但建议设置为一样的。</p>
<p>其他类型的词库，可以通过 <a href="https://github.com/lewangdev/scel2txt" target="_blank" rel="noopener">一些脚本</a> 或 <a href="https://github.com/studyzy/imewlconverter" target="_blank" rel="noopener">深蓝词库转换 </a>转为 Rime 格式的。</p>
<h3 id="自定义文本">自定义文本</h3>
<p>在 <code>custom_phrase.txt</code> 中可以放置一些特定的词汇与编码，比如输入 vmail 得到自己的邮箱，输入 vphone 得到手机号，输入 vuser 得到用户名等等。</p>
<p>我自己的理解：每个方案都有一个主翻译器，例如拼音；也可以增加一个次翻译器，例如英文；还可以再增加其他的，例如自定义文本。</p>
<p><code>custom_phrase.txt</code> 文件内的字词会占据最高权重，即排在候选项的最前面。（默认是这样的，但可以通过 <code>initial_quality</code> 调整各个翻译器的权重）</p>
<p>自定义文本不与其他翻译器互相造词，如果使用了完整编码，那么这个字或词将无法参与造词，即自造词无法被记住。</p>
<blockquote>
<p>所以建议只固定非完整编码的字词，「的de」应为「的d」，「是shi」应为「是s」，「仙剑xianjian」应为「仙剑xj」。</p>
<p>注意全拼的 <code>a o e</code> 也是完整拼写，不宜将 <code>a o e</code> 的单字写进自定义文本，否则「啊 哦 呃」无法进行造词。</p>
</blockquote>
<p>💡 置顶已经由 <code>pin_cand_filter.lua</code> 实现，可参与造词。</p>
<h3 id="同步">同步</h3>
<p><code>installation.yaml</code> 文件在第一次部署后会自动生成，在这里可以编辑当前设备的 ID 和同步目录，如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 本机的 ID 标志，默认是一串 UUID</span><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">installation_id</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;MBP-001&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># 同步的路径，默认是当前配置目录下的 `sync/`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sync_dir</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;/file/path/sync&#34;</span><span class="w">
</span></span></span></code></pre></div><p>在你输入过内容后，配置目录下会生成 <code>*.userdb/</code> 文件夹，里面是二进制的用户词典。</p>
<p>点击「同步用户数据」后，Rime 会和配置目录下的 <code>*.userdb/</code> 进行双向更新同步，并在同步目录（<code>/file/path/sync/MBP-001</code>）下生成的 <code>*.userdb.txt</code>，里面都是输入过的内容。</p>
<blockquote>
<p>同步目录里还有其他一些没用的文件，Rime 额外单向备份了配置目录下的 YAML 和 TXT 文件，但只有根目录的，比如文件夹里的词库、八股文模型、<code>rime.lua</code> 就没有被同步过来。</p>
</blockquote>
<p>⚠️ Windows 用户注意 YAML 语法，反斜杠在双引号中转义，在单引号中不转义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">sync_dir</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;c:\\file\\path\\sync&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sync_dir</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;c:\file\path\sync&#39;</span><span class="w">
</span></span></span></code></pre></div><h4 id="多设备同步">多设备同步</h4>
<p>将所有平台的 <code>sync_dir</code> 设定为同一个目录，比如 iCloud、Dropbox 的目录。</p>
<p>多个设备在这个目录中会生成并列的文件夹，里面是用户词典。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-04-06-000118.webp"
            alt=""
            width="1056"
            height="166"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>PC-1 里点【同步】，通过网盘同步到 PC-2，PC-2 再点同步，才可以获得 PC-1 输入过的内容。</p>
<h4 id="用户词典迁移">用户词典迁移</h4>
<p>如果之前在用别的方案，如 <code>pinyin_simp</code> 或 <code>luna_pinyin</code>。</p>
<ol>
<li>将之前的 <code>pinyin_simp.userdb.txt</code> 或 <code>luna_pinyin[_simp].userdb.txt</code> 放到同步目录</li>
<li>命名为 <code>rime_ice.userdb.txt</code></li>
<li>修改文件里面的 <code>#@/db_name</code> 为 <code>rime_ice</code></li>
<li>点击【同步用户数据】后就可以了</li>
</ol>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-04-06-000122.webp"
            alt=""
            width="1584"
            height="288"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>如果之前用的是繁体词库，还需要提前做一个简繁转换，注意不要把 Tab 全转为空格了。</p>
<p>简单的方法，比如 Mac 上通过 VSCode 打开 ➡️ 全选 ➡️ 左上角 Code ➡️ 服务 ➡️ 将文本转换为简体中文。</p>
<p>或者用 <a href="https://github.com/BYVoid/OpenCC" target="_blank" rel="noopener">opencc</a>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ opencc -c t2s -i in.txt -o out.txt
</span></span></code></pre></div><h3 id="开关记忆">开关记忆</h3>
<p>方案中有几个开关（<code>switches</code>），比如简繁开关、Emoji 开关、中英标点开关。。。</p>
<p>如果设定了 reset，值为 0 或 1，则默认使用第一个或第二个值，即便使用时修改了，切换程序后还是默认值。</p>
<p>如果想让输入法永远记住，需要取消设置 <code>reset</code>，并在 <code>default.custom.yaml</code> 中写入 <code>save_options</code>。</p>
<p>永远记住的前提是通过方案选单选择，而不是快捷键切换 (╯&rsquo;-&rsquo;)╯︵┻━┻</p>
<blockquote>
<p>部分前端（如小企鹅），实现了全局状态，切换后在任何焦点都会记住；</p>
<p>部分前端（如鼠须管），仅在当前会话中记住，每个App或一个App的不同输入框都会单独管理；</p>
<p>部分前端（如小狼毫），仅实现了中英全局状态，其他开关仍然是单独管理。</p>
</blockquote>
<h3 id="如何删除相关功能">如何删除相关功能</h3>
<p>比如删除英文输入，所有的相关配置是这些：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># dependencies 下的：</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">melt_eng</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"># engine/translators 下的：</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">table_translator@melt_eng</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">melt_eng</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">melt_eng</span><span class="w">
</span></span></span></code></pre></div><p>拼字方案同样，此外还有一些 Lua 的功能，直接在 <code>engine</code> 下注释掉那一行就禁用了。</p>
<h3 id="皮肤">皮肤</h3>
<ul>
<li>鼠须管文档：<a href="https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/%e9%bc%a0%e9%ac%9a%e7%ae%a1%e4%bb%8b%e9%9d%a2%e9%85%8d%e7%bd%ae%e6%8c%87%e5%8d%97.md" target="_blank" rel="noopener">鼠须管界面配置指南</a></li>
<li>小狼毫文档：<a href="https://github.com/rime/weasel/wiki/Weasel-%e5%ae%9a%e8%a3%bd%e5%8c%96" target="_blank" rel="noopener">Weasel 定制化</a></li>
</ul>
<p>在 <code>squirrel[.custom].yaml</code> 或 <code>weasel[.custom].yaml</code> 中配置鼠须管或小狼毫的皮肤，各平台的前端并不一致，鼠须管的皮肤无法用在小狼毫上。</p>
<p>这里有一个鼠须管内置皮肤的展示图：<a href="https://github.com/NavisLab/rime-pifu" target="_blank" rel="noopener">NavisLab/rime-pifu</a>（<a href="/img/2022-04-24-000576.webp">图片备份</a>），小狼毫自带皮肤预览。</p>
<p>需要自己设计皮肤的，鼠须管推荐用这个图形化的皮肤设计器，鼠须管主要维护者写的：<a href="https://github.com/LEOYoon-Tsaw/Squirrel-Designer" target="_blank" rel="noopener">LEOYoon-Tsaw/Squirrel-Designer</a></p>
<p>小狼毫的在线设计网页：<a href="https://fxliang.github.io/RimeSeeMe/" target="_blank" rel="noopener">RIME 西米</a> （小狼毫主要维护者的）</p>
<h3 id="查看日志">查看日志</h3>
<ul>
<li>
<p>【中州韵】 <code>/tmp/rime.ibus.*</code></p>
</li>
<li>
<p>【小狼毫】 <code>%TEMP%\rime.weasel.*</code></p>
</li>
<li>
<p>【鼠须管】 <code>$TMPDIR/rime.squirrel.*</code></p>
</li>
</ul>
<p>日志级别分为 <code>INFO</code> <code>WARNING</code> <code>ERROR</code>，查看示例：</p>
<pre tabindex="0"><code>$ cat $TMPDIR/rime.squirrel.INFO
</code></pre><p>鼠须管我经常碰到一个小问题，有时候都弹通知报错了，但是日志是空的，根本没有这个文件。可以直接结束鼠须管进程，它自动重启后就好了。</p>
<h3 id="删词-or-降权">删词 or 降权</h3>
<p>可以删除自造词，或降低词库中已有词语的权重（回到原始权重，不是降到最低）。</p>
<ul>
<li>鼠须管使用 Fn + ⇧ + ⌫</li>
<li>小狼毫使用 Ctrl/Shift + Del</li>
</ul>
<p>想永久删除一个词库中存在的词汇，只能编辑词库，重新部署。</p>
<p>如果各位有在使用过程中有发现什么错别字，希望可以提个 issue。</p>
<h3 id="tab-切光标">Tab 切光标</h3>
<p>这功能挺好用的，每次用别人的电脑打字都会怀念这个功能。</p>
<p>已经默认开启，可以使用 Tab 或 Shift + Tab 在拼音中前后移动。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-03-22-000487.gif"
            alt=""
            width="452"
            height="496"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>对于「xian西安」「tian提案」这种拼音，如果想切到「xi、ti」的后面，只能用左右方向键移动。</p>
<p>另外 Shift + ⌫ 可以删除单个汉字的拼音。</p>
<h3 id="不同的上屏方式">不同的上屏方式</h3>
<p>按下空格会上屏汉字，按下回车会上屏字母（可临时输入一些词库中没有的英文）。</p>
<p>以输入「虐心 nue&rsquo;xin」为例：</p>
<ul>
<li>按回车，上屏的是 <code>nuexin</code>。</li>
<li>按 Ctrl/Shift + 回车，上屏的是 <code>nve xin</code>。（u → v，中间有空格）</li>
</ul>
<p><code>translator/preedit_format</code> 这里会影响输入框和 shift + 回车时的显示，比如是显示 nue、nve 或 nüe。</p>
<p>如果是双拼方案，<code>preedit_format</code> 还可以选择是否在输入框进行转换，比如小鹤双拼输入 <code>zz</code> 时，是显示 <code>zz</code> 还是 <code>zou</code>。</p>
<p>要设置双拼不转换为全拼，可以直接把 <code>preedit_format</code> 及下面那些 <code>xform</code> 都删除，或者这样打补丁：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">patch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">translator/preedit_format</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span></code></pre></div><h3 id="opencc">opencc</h3>
<p>opencc 除了做简繁转换，也可以做词语映射。</p>
<p>比如想输入摄氏度的符号 °C ，可以自定义文本 <code>custom_phrase.txt</code> 中写上：</p>
<pre tabindex="0"><code>°C	sheshidu
</code></pre><p>但这样，这个符号会顶到第一个候选项，重码时影响平时打汉字。推荐用 opencc 的方法，Emoji 就是这样实现的。</p>
<pre tabindex="0"><code>摄氏度	摄氏度 °C
足球	足球 ⚽
输入内容&lt;Tab&gt;响应内容1&lt;Space&gt;响应内容2&lt;Space&gt;响应内容3...
</code></pre><p>输入  <code>摄氏度</code>，第一个候选项是其本身，后续则是映射的其他内容。类似输入 <code>提手旁</code> 会得到 <code>提手旁 扌</code>，输入 <code>相泽南</code> 会得到 <code>相泽南 相沢みなみ</code> 等等都是这么做的。</p>
<p>这个「输入内容」其本身应该在词库中存在，否则只能输入过一次后才会有响应。</p>
<p>还有个用法是 <code>show_in_comment: true</code>，可以让「响应内容」放到 <code>comment</code> 里面。</p>
<p><code>show_in_comment: true</code> 可以实现显示英文单词的翻译，类似<a href="https://github.com/dongyuwei/hallelujahIM" target="_blank" rel="noopener">哈利路亚输入法</a>，尝试过加入这个功能，一是没有找到比较好的简短翻译数据；二是 Rime 的 <code>comment</code> 区域并不是一个独立存在的窗口，翻译和候选项挤在一起看起来乱糟糟的。</p>
<h3 id="东风破">东风破</h3>
<blockquote>
<p>「東風破早梅，向暖一枝開。」</p>
</blockquote>
<p>东风破 <a href="https://github.com/rime/plum" target="_blank" rel="noopener">plum</a> 是 Rime 官方的一个配置管理工具。</p>
<p>下面是一个简单使用示例，可以在任意文件夹下运行（使用前请备份并清空配置目录）：</p>
<pre tabindex="0"><code>$ git clone --depth=1 https://github.com/rime/plum
$ cd plum
$ bash rime-install iDvel/rime-ice:others/recipes/full
</code></pre><p>得，这就安装完了雾凇拼音。</p>
<p>全量更新，再用一次 full 配方即可：</p>
<pre tabindex="0"><code>$ bash rime-install iDvel/rime-ice:others/recipes/full
</code></pre><p>单独更新词库可以用另一个配方：</p>
<pre tabindex="0"><code>$ bash rime-install iDvel/rime-ice:others/recipes/all_dicts
</code></pre><p>例如小鹤双拼，可以在首次安装后再自动打一个补丁：</p>
<pre tabindex="0"><code>bash rime-install iDvel/rime-ice:others/recipes/config:schema=flypy
</code></pre><p>可以查看配置仓库中的 <code>*.recipe.yaml</code> 配方文件，来查看这个配方到底更新了什么。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Hammerspoon 自动切换输入法</title>
      <link>https://dvel.me/posts/hammerspoon-auto-change-input-method/</link>
      <pubDate>Thu, 19 Jan 2023 00:09:28 +0800</pubDate>
      <guid>https://dvel.me/posts/hammerspoon-auto-change-input-method/</guid>
      <description>利用 Hammerspoon 在 macOS 中自动切换输入法，实现无论当前是什么输入法，在指定程序内部切换到英文输入法，在离开程序后恢复原先的输入法。</description>
      <content:encoded><![CDATA[<p>在 macOS 中利用 <a href="https://github.com/Hammerspoon/hammerspoon" target="_blank" rel="noopener">Hammerspoon</a> 自动切换输入法。</p>
<p>因为 Rime 目前的中英切换不是特别好用：</p>
<ul>
<li>不能 Shift 全局切换中英：<a href="https://github.com/rime/squirrel/issues/145" target="_blank" rel="noopener">是否有可能将中英文输入状态作全局管理？ #145</a></li>
<li>Rime 的自动切换仍然会记住上一次的状态：<a href="https://github.com/rime/squirrel/issues/164" target="_blank" rel="noopener">请问如何设置打开某app始终切换到英文模式？ #164 </a></li>
<li>菜单栏不能显示中英状态</li>
</ul>
<p>Rime 全局状态功能的进展：<a href="https://github.com/rime/librime/issues/294" target="_blank" rel="noopener">global input session, state shared by all client apps #294</a></p>
<br>
<p>我希望的是：无论当前是什么输入法，切换到 iTerm，就是英文，离开 iTerm，回到我原先的输入法。</p>
<p>类似于 Alfred 目前的功能（高级设置中的 Force Keyboard 设置为 ABC）。</p>
<p>我在 Typora 写中文，呼出 Alfred，变成英文输入法，用完了回到 Typora，变回中文输入法。</p>
<br>
<p>代码参考于：<a href="https://gist.github.com/ibreathebsb/65fae9d742c5ebdb409960bceaf934de" target="_blank" rel="noopener">ibreathebsb/hammerspoon自动切换输入法.lua</a></p>
<p>使用方法：放到 <code>~/.hammerspoon/init.lua</code> 重新部署就可以了。</p>
<p>可以用 <code>Cmd + Ctrl + .</code> 来查看当前窗口的 name 或 path；</p>
<p>可以在 Hammerspoon 的控制台输入 <code>hs.keycodes.currentSourceID()</code> 来查看当前输入法的 ID。</p>
<p>做的修改：</p>
<ul>
<li>以 App name 作为参数，看起来舒服点</li>
<li>退出指定的程序后，恢复到原先的输入法</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="c1">-- 当选中某窗口按下 ctrl+command+. 时会显示应用的路径、名字等信息</span>
</span></span><span class="line"><span class="cl"><span class="n">hs.hotkey</span><span class="p">.</span><span class="n">bind</span><span class="p">({</span><span class="s1">&#39;ctrl&#39;</span><span class="p">,</span> <span class="s1">&#39;cmd&#39;</span><span class="p">},</span> <span class="s2">&#34;.&#34;</span><span class="p">,</span> <span class="kr">function</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">hs.pasteboard</span><span class="p">.</span><span class="n">setContents</span><span class="p">(</span><span class="n">hs.window</span><span class="p">.</span><span class="n">focusedWindow</span><span class="p">():</span><span class="n">application</span><span class="p">():</span><span class="n">path</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">    <span class="n">hs.alert</span><span class="p">.</span><span class="n">show</span><span class="p">(</span><span class="s2">&#34;App path:        &#34;</span> <span class="o">..</span> <span class="n">hs.window</span><span class="p">.</span><span class="n">focusedWindow</span><span class="p">():</span><span class="n">application</span><span class="p">():</span><span class="n">path</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="o">..</span> <span class="s2">&#34;App name:      &#34;</span> <span class="o">..</span>
</span></span><span class="line"><span class="cl">                      <span class="n">hs.window</span><span class="p">.</span><span class="n">focusedWindow</span><span class="p">():</span><span class="n">application</span><span class="p">():</span><span class="n">name</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="o">..</span> <span class="s2">&#34;IM source id:  &#34;</span> <span class="o">..</span>
</span></span><span class="line"><span class="cl">                      <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</span><span class="p">(),</span> <span class="n">hs.alert</span><span class="p">.</span><span class="n">defaultStyle</span><span class="p">,</span> <span class="n">hs.screen</span><span class="p">.</span><span class="n">mainScreen</span><span class="p">(),</span> <span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">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">-- 这里指定中文和英文输入法的 ID</span>
</span></span><span class="line"><span class="cl"><span class="kd">local</span> <span class="kr">function</span> <span class="nf">Chinese</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</span><span class="p">(</span><span class="s2">&#34;im.rime.inputmethod.Squirrel.Rime&#34;</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="kd">local</span> <span class="kr">function</span> <span class="nf">English</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</span><span class="p">(</span><span class="s2">&#34;com.apple.keylayout.ABC&#34;</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></span><span class="line"><span class="cl"><span class="c1">-- 指定程序</span>
</span></span><span class="line"><span class="cl"><span class="kd">local</span> <span class="n">appInputMethod</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">iTerm2</span> <span class="o">=</span> <span class="n">English</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="s1">&#39;EuDic LightPeek&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">English</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">Bitwarden</span> <span class="o">=</span> <span class="n">English</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">SnippetsLab</span> <span class="o">=</span> <span class="n">English</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="s1">&#39;微信&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Chinese</span><span 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">-- activated 时切换到指定的输入法，deactivated 时恢复之前的状态</span>
</span></span><span class="line"><span class="cl"><span class="n">currentID</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kr">function</span> <span class="nf">applicationWatcher</span><span class="p">(</span><span class="n">appName</span><span class="p">,</span> <span class="n">eventType</span><span class="p">,</span> <span class="n">appObject</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">eventType</span> <span class="o">==</span> <span class="n">hs.application</span><span class="p">.</span><span class="n">watcher.activated</span><span class="p">)</span> <span class="kr">then</span>
</span></span><span class="line"><span class="cl">        <span class="kr">for</span> <span class="n">app</span><span class="p">,</span> <span class="n">fn</span> <span class="kr">in</span> <span class="n">pairs</span><span class="p">(</span><span class="n">appInputMethod</span><span class="p">)</span> <span class="kr">do</span>
</span></span><span class="line"><span class="cl">            <span class="kr">if</span> <span class="n">app</span> <span class="o">==</span> <span class="n">appName</span> <span class="kr">then</span>
</span></span><span class="line"><span class="cl">                <span class="n">currentID</span> <span class="o">=</span> <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                <span class="n">fn</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><span class="line"><span class="cl">    <span class="kr">end</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="n">eventType</span> <span class="o">==</span> <span class="n">hs.application</span><span class="p">.</span><span class="n">watcher.deactivated</span> <span class="kr">then</span>
</span></span><span class="line"><span class="cl">        <span class="kr">for</span> <span class="n">app</span><span class="p">,</span> <span class="n">fn</span> <span class="kr">in</span> <span class="n">pairs</span><span class="p">(</span><span class="n">appInputMethod</span><span class="p">)</span> <span class="kr">do</span>
</span></span><span class="line"><span class="cl">            <span class="kr">if</span> <span class="n">app</span> <span class="o">==</span> <span class="n">appName</span> <span class="kr">then</span>
</span></span><span class="line"><span class="cl">                <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</span><span class="p">(</span><span class="n">currentID</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">currentID</span> <span class="o">=</span> <span class="n">hs.keycodes</span><span class="p">.</span><span class="n">currentSourceID</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><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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">appWatcher</span> <span class="o">=</span> <span class="n">hs.application</span><span class="p">.</span><span class="n">watcher.new</span><span class="p">(</span><span class="n">applicationWatcher</span><span class="p">):</span><span class="n">start</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">-- hs.keycodes.inputSourceChanged(function()</span>
</span></span><span class="line"><span class="cl"><span class="c1">--     if hs.keycodes.currentMethod() == nil then</span>
</span></span><span class="line"><span class="cl"><span class="c1">--         hs.alert.show(&#34;ABC&#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2)</span>
</span></span><span class="line"><span class="cl"><span class="c1">--     else</span>
</span></span><span class="line"><span class="cl"><span class="c1">--         hs.alert.show(&#34;拼音&#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2)</span>
</span></span><span class="line"><span class="cl"><span class="c1">--     end</span>
</span></span><span class="line"><span class="cl"><span class="c1">-- end)</span>
</span></span></code></pre></div><p>小问题：</p>
<p>无法识别 Alfred 的窗口，不过 Alfred 自带这个功能，和本配置功能一样。</p>
<p>本来想弄个提示的，但是每次切换时都会产生意料之外的多次切换，比如「ABC → ABC → ABC」或「ABC → 拼音 → ABC」，不知为何中间发生了多次切换，这导致菜单栏的输入法图标发生了一阵短暂而急促的抖动，不过好在结果都是正确的。</p>
<p>我看 Alfred 自己的功能也有这个问题，不知道有没有可能是 macOS 的 Bug。</p>
<p>最后只好注释掉 <code>hs.alert.show</code> 的提示了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>修复 Hugo 本地图片的累计布局偏移（CLS）问题</title>
      <link>https://dvel.me/posts/fix-hugo-cls/</link>
      <pubDate>Sun, 08 Jan 2023 19:49:29 +0800</pubDate>
      <guid>https://dvel.me/posts/fix-hugo-cls/</guid>
      <description>如何修复 Hugo 本地图片的累计布局偏移（CLS）问题？通过利用 Hugo 的 Render Hooks 功能重新渲染图片相关代码，自动获取图片的宽高并加上 width 和 height 属性，解决本地图片的偏移问题。</description>
      <content:encoded><![CDATA[<h2 id="布局偏移">布局偏移</h2>
<p>累计布局偏移 Cumulative Layout Shift（CLS）是一项 Web 指标。</p>
<p>布局偏移如图所示，元素突然变化的高度影响了用户交互体验：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-01-08.gif"
            alt="CLS problem"
            width="498"
            height="282"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>一般给图片一个高度就可以了，但最好是能自动化，而不是手写。</p>
<p>看到了这篇博文 <a href="https://liudon.com/posts/hugo-auto-generate-image-width-and-height/" target="_blank" rel="noopener">累计布局偏移修复方案改进 —— 自动生成图片宽高</a>，不过他是从腾讯云对象存储获取的图片宽高，而我都将图片存储在了 Hugo 配置目录的 <code>static/img/</code> 文件夹。</p>
<p>我平时在 Markdown 里都是直接写的 path：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">![](/img/example.webp)
</span></span></code></pre></div><h2 id="解决本地图片的偏移问题">解决本地图片的偏移问题</h2>
<p>参考 <a href="https://ianmuchina.com/blog/14-cls-hugo/" target="_blank" rel="noopener">How to prevent CLS in Hugo</a>，利用 Hugo 的 <a href="https://gohugo.io/templates/render-hooks/" target="_blank" rel="noopener">Render Hooks</a> 功能重新渲染图片相关代码，获取图片的宽高，在 <code>&lt;img&gt;</code> 标签里加上 <code>width</code> 和 <code>height</code> 属性。</p>
<p>不知道为什么照他的办法，在配置中加入了 <code>mounts</code> 相关属性，仍然不起作用，不太会前端和 Hugo，摸索着改了改。</p>
<p>创建 <code>layouts/_default/_markup/render-image.html</code> 文件：</p>
<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>
</span></span><span class="line"><span class="cl">{{ if hasPrefix .Destination &#34;/img&#34; }}
</span></span><span class="line"><span class="cl">    {{ $img := os.ReadFile (path.Join &#34;/static&#34; .Destination) | resources.FromString .Destination }}
</span></span><span class="line"><span class="cl">    {{ if ne $img.MediaType.SubType &#34;svg&#34; }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">img</span> <span class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#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></span><span class="line"><span class="cl">            <span class="na">width</span><span class="o">=</span><span class="s">&#34;{{ $img.Width }}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">height</span><span class="o">=</span><span class="s">&#34;{{ $img.Height }}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">style</span><span class="o">=</span><span class="s">&#34;max-width: 100%; height: auto;&#34;</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">    {{ if or (not $img) (eq $img.MediaType.SubType &#34;svg&#34;) }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">img</span> <span class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ .Text }}&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    {{ end }}
</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 class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ .Text }}&#34;</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">p</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>在他的基础上手动加上了 <code>/static</code> 地址前缀，不然这个 <code>os.ReadFile</code> 方法一直报错；</p>
<p>加上了 <code>style=&quot;max-width: 100%; height: auto;&quot;</code>，保持宽度超过父容器的图片的比例；</p>
<p>套了个 <code>if else</code>，只处理图片地址为 <code>/img</code> 开头的本地图片，并可以显示网络图片，但是网络图片仍然会产生偏移。</p>
<br>
<p>我用的是 <a href="https://github.com/adityatelange/hugo-PaperMod" target="_blank" rel="noopener">Hugo PaperMod</a> 主题，主页的封面图也存在这个问题，得修改 <code>cover.html</code>，看不太懂，我看上面那位博主是修改的这里，确实起作用。</p>
<p>修改最外层的 <code>{{- else }}</code> 里的内容（Hugo PaperMod 6.0 版本），和之前的一样，就是替换一下 <code>src</code> 和 <code>alt</code> 的属性值：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- else }}{{/* For absolute urls and external links, no img processing here */}}
</span></span><span class="line"><span class="cl">    {{- if $addLink }}<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ (.Params.cover.image) | absURL }}&#34;</span> <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;noopener noreferrer&#34;</span><span class="p">&gt;</span>{{ end -}}
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- &lt;img loading=&#34;lazy&#34; src=&#34;{{ (.Params.cover.image) | absURL }}&#34; alt=&#34;{{ $alt }}&#34;&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- 修改，将上面那行改成下面这些： --&gt;</span>
</span></span><span class="line"><span class="cl">        {{ if hasPrefix .Params.cover.image &#34;/img&#34; }}
</span></span><span class="line"><span class="cl">            {{ $img := os.ReadFile (path.Join &#34;/static&#34; .Params.cover.image) | resources.FromString .Params.cover.image }}
</span></span><span class="line"><span class="cl">            {{ if ne $img.MediaType.SubType &#34;svg&#34; }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">img</span> <span class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Params.cover.image | safeURL }}&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ $alt }}&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">width</span><span class="o">=</span><span class="s">&#34;{{ $img.Width }}&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">height</span><span class="o">=</span><span class="s">&#34;{{ $img.Height }}&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">style</span><span class="o">=</span><span class="s">&#34;max-width: 100%; height: auto;&#34;</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">            {{ if or (not $img) (eq $img.MediaType.SubType &#34;svg&#34;) }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">img</span> <span class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Params.cover.image | safeURL }}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ $alt }}&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">            {{ end }}
</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 class="na">loading</span><span class="o">=</span><span class="s">&#34;lazy&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Params.cover.image | safeURL }}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ $alt }}&#34;</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></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位</title>
      <link>https://dvel.me/posts/macos-karabiner-key-binding/</link>
      <pubDate>Fri, 25 Nov 2022 20:09:31 +0800</pubDate>
      <guid>https://dvel.me/posts/macos-karabiner-key-binding/</guid>
      <description>利用 Karabiner 将 macOS 默认的 Emacs-like 键位修改为自定义的 Vim 键位。</description>
      <content:encoded><![CDATA[<p>上一篇博文用修改 <code>~/Library/KeyBindings/DefaultKeyBinding.dict</code> 的方法修改按键绑定，但很多地方依然无法响应新的键位设置，体验比较割裂，于是换到 <a href="https://karabiner-elements.pqrs.org/" target="_blank" rel="noopener">Karabiner</a>。</p>
<h2 id="实现方式的区别">实现方式的区别</h2>
<h3 id="defaultkeybinding">DefaultKeyBinding</h3>
<p>在 <code>DefaultKeyBinding.dict</code> 中，用 Ctrl+h 来向左移动，macOS 是通过这样实现的：</p>
<pre tabindex="0"><code>&#34;^h&#34; = &#34;moveBackward:&#34;;
</code></pre><p>如果想继续实现 Shift+left（向左移动时选中文本）这个功能，还得需要调用另一个方法：</p>
<pre tabindex="0"><code>&#34;^H&#34; = &#34;moveBackwardAndModifySelection:&#34;;
</code></pre><p>苹果原生的方式是直接作用的，比如删除到行首（Ctrl + u）就等于一步操作：直接删除到行首。</p>
<h3 id="karabiner">Karabiner</h3>
<p>Karabiner 要实现删除到行首，它是先通过 Command + Shift + left 来选中光标之前所有的文本，再按下删除键，这样的方式来实现的。</p>
<p>影响可能是有的，比如终端上无法响应，如果自己定义了一个 Ctrl + u，反而还覆盖了其本身正常的功能，不过可以屏蔽掉不需要的 App。</p>
<p>另外无须单独实现带选区的那种，因为 Ctrl+h 已经被映射为左箭头了，自己再加上 Shift 就可以了。</p>
<p>Karabiner 还可以实现更多的功能，比如作者直接写了个全局 Vim 映射，还可以启动 App，设置只限定特定设备、特定 App 等等，功能着实强大，还开源免费。</p>
<h2 id="简单使用">简单使用</h2>
<ul>
<li>Simple Modifications，可以简单映射，比如 CapsLock → Control</li>
<li>Complex Modifications，可以引用别人已经写好了的规则。
<ul>
<li>或者打开 <code>~/.config/karabiner/assets/complex_modifications</code> 增加自己的规则。</li>
</ul>
</li>
<li>Devices，选择要应用到的设备，比如内置键盘。</li>
<li>Profiles，定义多套方案，按需选择。</li>
</ul>
<p>官方文档：<a href="https://karabiner-elements.pqrs.org/docs/" target="_blank" rel="noopener">https://karabiner-elements.pqrs.org/docs/</a></p>
<p>社区分享：<a href="https://ke-complex-modifications.pqrs.org/" target="_blank" rel="noopener">https://ke-complex-modifications.pqrs.org/</a></p>
<p>建议查看官方文档熟悉一点小例子，然后下载别人实现类似的功能的 JSON 代码来参考。</p>
<p>文档最下面有个 <a href="https://karabiner-elements.pqrs.org/docs/json/external-json-generators/" target="_blank" rel="noopener">External JSON generators</a>，比如用这个 <a href="https://genesy.github.io/karabiner-complex-rules-generator/" target="_blank" rel="noopener">Karabiner Complex Modification</a> 可以自动生成 JSON，不过简单的映射还是直接写 JSON 方便。</p>
<h2 id="我的键位设置">我的键位设置</h2>
<p>原始的 Emacs-like 键位：</p>
<pre tabindex="0"><code>Ctrl + ...
a 移动到行首
e 移动到行尾
b 左
f 右
p 上
n 下
h 往左删除一个
d 往右删除一个
w 往左删除单词
u 往左删除到行首
k 往右删除到行尾
</code></pre><p>自定义的的键位：</p>
<pre tabindex="0"><code>Ctrl + ...
a 移动到行首
e 移动到行尾
h 左
l 右
k 上
j 下
o 插入一行
s 往左删除一个
d 往右删除一个
u 往左删除到行首
i 往右删除到行尾
w 往左删除单词
</code></pre><p>pnbf 仍然可以使用，没有冲突。</p>
<p>a e 不进行任何改动，我还没有发现有不支持的地方。</p>
<p>w u 的功能虽然和上面一样，但有些地方比如 Typora 就不支持，自己实现一遍确保全局有效。</p>
<h2 id="代码">代码</h2>
<ul>
<li>(1) CapsLock 短按为 Esc，组合为 Control</li>
<li>(2) Ctrl + hjkl 移动光标，排除 JetBrains
<ul>
<li>上下左右修改为 hjkl，与原来的 pnbf 不冲突，仍然可以使用；</li>
<li>排除 JetBrains，IDEA 自己单独实现普通模式和插入模式不同的行为。</li>
</ul>
</li>
<li>(3) Ctrl + aeosduiw，排除 JetBrains 和终端
<ul>
<li>ae 不改动，wu 重新实现了一遍；</li>
<li>o 和 Vim 的功能类似，在本行的任何位置直接新建一行并切换过去；</li>
<li>增加了 s、i 两个键位在原来的 d、u 旁边，左边的往左删，右边的往右删，很好记忆；</li>
<li>排除 JetBrains 和终端。</li>
</ul>
</li>
<li>(4) Option + [Shift] + hjkl
<ul>
<li>可以用 Option [+ Shift] + Ctrl + h/l，但按键太多，改成直接按 h/l 也生效；</li>
<li>Option + j/k 用于 VSCode 默认快捷键，上下移动此行；</li>
<li>Option + Shift + j/k 用于 VSCode 默认快捷键，复制一行；</li>
</ul>
</li>
</ul>
<p>将代码保存到 <code>~/.config/karabiner/assets/complex_modifications</code>。</p>
<p>因为这个 <a href="https://github.com/pqrs-org/Karabiner-Elements/issues/2774" target="_blank" rel="noopener">issue#2774</a> 没有解决，还不能全局限定或屏蔽某 App，代码像面条一样，<code>frontmost_application_unless</code> 相关配置每次修改时都需要同时改动多处地方。</p>
<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;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Dvel&#39;s hjkl&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;rules&#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;description&#34;</span><span class="p">:</span> <span class="s2">&#34;(1) CapsLock 短按为 Esc，组合为 Control&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;manipulators&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;caps_lock&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;any&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;left_control&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;lazy&#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="p">],</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;to_if_alone&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;escape&#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><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;description&#34;</span><span class="p">:</span> <span class="s2">&#34;(2) Ctrl + hjkl 移动光标，排除 JetBrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;manipulators&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;h&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;any&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;left_arrow&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;j&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;any&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;down_arrow&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;any&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;up_arrow&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;any&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;right_arrow&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#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><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;description&#34;</span><span class="p">:</span> <span class="s2">&#34;(3) Ctrl + aeosduiw，排除 JetBrains 和终端&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;manipulators&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;o&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;right_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_command&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;return_or_enter&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;s&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;delete_or_backspace&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;delete_forward&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;u&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;left_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_shift&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;delete_or_backspace&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;i&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;right_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_shift&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;delete_forward&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#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="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;left_control&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;left_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;shift&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;delete_or_backspace&#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;conditions&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;frontmost_application_unless&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;bundle_identifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;jetbrains&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Terminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;iterm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;Warp&#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><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;description&#34;</span><span class="p">:</span> <span class="s2">&#34;(4) Option [+ Shift] + hjkl&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;manipulators&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;h&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;shift&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;left_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;j&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;shift&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;down_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;shift&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;up_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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><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;basic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;from&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;mandatory&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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;optional&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;shift&#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;to&#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;key_code&#34;</span><span class="p">:</span> <span class="s2">&#34;right_arrow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#34;modifiers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;option&#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><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>]]></content:encoded>
    </item>
    <item>
      <title>macOS 修改 Emacs 键位为 Vim 键位</title>
      <link>https://dvel.me/posts/macos-default-key-binding/</link>
      <pubDate>Thu, 24 Nov 2022 19:11:14 +0800</pubDate>
      <guid>https://dvel.me/posts/macos-default-key-binding/</guid>
      <description>通过修改 DefaultKeyBinding.dict 来将 macOS 默认的 Emacs-like 键位修改为自定义的 Vim 键位。</description>
      <content:encoded><![CDATA[<p>macOS 默认在文本编辑中使用 pnbf 来进行上下左右，还有一些其他键位，但我习惯使用 Vim 的 hjkl 来移动。</p>
<p>我已经在 Vim 中设置好了，但希望这个键位应用到全局。</p>
<br>
<p>通过修改 <code>DefaultKeyBinding.dict</code> 来完成。</p>
<p>但只能适配一般输入框的快捷键，很多编辑器都还是老样子，无法覆盖。</p>
<p>比如 Firefox 的输入框、Alfred 的输入框是可以的，但是很多网页编辑框、终端、代码编辑器、Typora 等等还是老键位。</p>
<br>
<p>因为这个方法的不一致性，我已经改用 Karabiner 了。</p>
<p>通过 <a href="https://github.com/pqrs-org/Karabiner-Elements" target="_blank" rel="noopener">Karabiner</a> 修改，则会真·强制·全局。</p>
<p>不过还是记录一下这种方法。</p>
<p>下一篇博文：<a href="/posts/macos-karabiner-key-binding/">macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位</a>。</p>
<h2 id="macos-默认的-emacs-like-键位">macOS 默认的 Emacs-like 键位</h2>
<p>官方支持文档：<a href="https://support.apple.com/zh-cn/HT201236" target="_blank" rel="noopener">Mac 键盘快捷键</a></p>
<p>Control-A：移至行或段落的开头。</p>
<p>Control-E：移至行或段落的末尾。</p>
<p>Control-F：向前移动一个字符。</p>
<p>Control-B：向后移动一个字符。</p>
<p>Control-L：将光标或所选内容置于可见区域中央。</p>
<p>Control-P：上移一行。</p>
<p>Control-N：下移一行。</p>
<p>Control-O：在插入点后新插入一行。</p>
<p>Control-T：将插入点后面的字符与插入点前面的字符交换。</p>
<p>Control-H：删除插入点左边的字符。也可以使用 Delete 键。</p>
<p>Control-D：删除插入点右边的字符。也可以使用 Fn-Delete。</p>
<p>Control-K：删除插入点与行或段落末尾处之间的文本。</p>
<h2 id="键位映射文件">键位映射文件</h2>
<p>默认的键位设置在：</p>
<pre tabindex="0"><code>/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict
</code></pre><p>可以自己增加一个来覆盖默认的：（默认没有 <code>KeyBindings</code> 目录，可以自己创建）</p>
<pre tabindex="0"><code>~/Library/KeyBindings/DefaultKeyBinding.dict
</code></pre><h2 id="查看-standardkeybindingdict-的方法">查看 <code>StandardKeyBinding.dict</code> 的方法：</h2>
<p>可以用 Xcode 打开，选择文件类型为 Property List Binary。</p>
<p>或者可以用 <code>plutil</code> 转换为 XML：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">plutil -convert xml1 -o StandardKeyBinding.xml  /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict
</span></span></code></pre></div><p>转换完成后，可以得到类似下面这样的代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^a<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>moveToBeginningOfParagraph:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^b<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>moveBackward:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^d<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>deleteForward:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^e<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>moveToEndOfParagraph:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^f<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>moveForward:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^h<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>deleteBackward:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^k<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>deleteToEndOfParagraph:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^l<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>centerSelectionInVisibleArea:<span class="nt">&lt;/string&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;key&gt;</span>^n<span class="nt">&lt;/key&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;string&gt;</span>moveDown:<span class="nt">&lt;/string&gt;</span>
</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>字符</th>
          <th>按键</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&quot;@&quot;</code></td>
          <td>Command</td>
      </tr>
      <tr>
          <td><code>&quot;^&quot;</code></td>
          <td>Control</td>
      </tr>
      <tr>
          <td><code>&quot;~&quot;</code></td>
          <td>Option</td>
      </tr>
  </tbody>
</table>
<p><code>^A</code> 这样的代表  Control + Shift + a。</p>
<h2 id="修改示例">修改示例</h2>
<p>我自己的习惯，除了 hjkl 移动还改了一点别的。</p>
<p>创建并编辑 <code>~/Library/KeyBindings/DefaultKeyBinding.dict</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-properties" data-lang="properties"><span class="line"><span class="cl"><span class="err">{</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^a&#34;</span> <span class="o">=</span> <span class="s">&#34;moveToBeginningOfParagraph:&#34;;  // 移动到行首</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^e&#34;</span> <span class="o">=</span> <span class="s">&#34;moveToEndOfParagraph:&#34;;        // 移动到行尾</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^h&#34;</span> <span class="o">=</span> <span class="s">&#34;moveBackward:&#34;;                // 左</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^l&#34;</span> <span class="o">=</span> <span class="s">&#34;moveForward:&#34;;                 // 右</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^k&#34;</span> <span class="o">=</span> <span class="s">&#34;moveUp:&#34;;                      // 上</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^j&#34;</span> <span class="o">=</span> <span class="s">&#34;moveDown:&#34;;                    // 下</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^o&#34;</span> <span class="o">=</span> <span class="s">&#34;insertNewline:&#34;;               // 插入一行</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^s&#34;</span> <span class="o">=</span> <span class="s">&#34;deleteBackward:&#34;;              // 往左删除一个</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^d&#34;</span> <span class="o">=</span> <span class="s">&#34;deleteForward:&#34;;               // 往右删除一个</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^w&#34;</span> <span class="o">=</span> <span class="s">&#34;deleteWordBackward:&#34;;          // 往左删除单词</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^u&#34;</span> <span class="o">=</span> <span class="s">&#34;deleteToBeginningOfLine:&#34;;     // 往左删除到行首</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^i&#34;</span> <span class="o">=</span> <span class="s">&#34;deleteToEndOfParagraph:&#34;;      // 往右删除到行尾</span>
</span></span><span class="line"><span class="cl">  <span class="na">//</span> <span class="s">有 Shift 的（产生选区）</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^A&#34;</span> <span class="o">=</span> <span class="s">&#34;moveToBeginningOfParagraphAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^E&#34;</span> <span class="o">=</span> <span class="s">&#34;moveToEndOfParagraphAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^H&#34;</span> <span class="o">=</span> <span class="s">&#34;moveBackwardAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^L&#34;</span> <span class="o">=</span> <span class="s">&#34;moveForwardAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^K&#34;</span> <span class="o">=</span> <span class="s">&#34;moveUpAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;^J&#34;</span> <span class="o">=</span> <span class="s">&#34;moveDownAndModifySelection:&#34;;</span>
</span></span><span class="line"><span class="cl"><span class="err">}</span>
</span></span></code></pre></div><p>保存后需要重启 App 来查看效果。</p>
<h2 id="参考">参考：</h2>
<p><a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/TextDefaultsBindings/TextDefaultsBindings.html" target="_blank" rel="noopener">Cocoa Event Handling Guide</a></p>
<p><a href="https://developer.apple.com/documentation/appkit/nsstandardkeybindingresponding" target="_blank" rel="noopener">NSStandardKeyBindingResponding</a></p>
<p><a href="https://github.com/jrus/cocoa-text-system/blob/master/cocoa-text.md" target="_blank" rel="noopener">Customizing the Cocoa Text System</a></p>
<p><a href="https://apple.stackexchange.com/questions/22156/what-are-the-control-keys-available-when-working-in-a-text-field" target="_blank" rel="noopener">What are the control keys available when working in a text field?</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Surge 配置</title>
      <link>https://dvel.me/posts/my-surge-conf/</link>
      <pubDate>Thu, 17 Nov 2022 20:40:01 +0800</pubDate>
      <guid>https://dvel.me/posts/my-surge-conf/</guid>
      <description>一个关于Surge配置的指南，提供了一些教程、指引和仓库等资源，以及常见的配置方法和作者个人的配置。</description>
      <content:encoded><![CDATA[<p>原来一直在用机场订阅自带的配置，这回快到期了想换换，同时在用多家，顺便学习了一下 Surge 配置。</p>
<h2 id="一些教程和指引">一些教程和指引</h2>
<ul>
<li>
<p><a href="https://manual.nssurge.com/book/understanding-surge/cn/" target="_blank" rel="noopener">Surge 官方中文指引：理解 Surge 原理</a></p>
</li>
<li>
<p><a href="https://manual.nssurge.com/" target="_blank" rel="noopener">Surge 官方手册（英文）</a></p>
</li>
<li>
<p><a href="https://github.com/FlintyLemming/SurgeHandbook" target="_blank" rel="noopener">Surge 官方手册（汉化）</a></p>
</li>
<li>
<p><a href="https://nssurge.zendesk.com/" target="_blank" rel="noopener">官方帮助中心</a></p>
</li>
<li>
<p><a href="https://community.nssurge.com/" target="_blank" rel="noopener">官方讨论区</a></p>
</li>
<li>
<p><a href="https://zhuangzhuang.io/2018/11/14/surge.html" target="_blank" rel="noopener">Surge 配置详解</a></p>
</li>
</ul>
<h2 id="一些仓库">一些仓库</h2>
<ul>
<li>
<p><a href="https://github.com/DivineEngine/Profiles" target="_blank" rel="noopener">神机</a> （进入后点击分支，选择有内容的那个分支）</p>
<ul>
<li><a href="https://raw.githubusercontent.com/DivineEngine/Profiles/master/Surge/Outbound.conf" target="_blank" rel="noopener">懒人配置</a></li>
</ul>
</li>
<li>
<p><a href="https://github.com/dler-io/Rules" target="_blank" rel="noopener">Dler</a></p>
<ul>
<li><a href="https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Prototype.conf" target="_blank" rel="noopener">懒人配置</a></li>
</ul>
</li>
<li>
<p><a href="https://github.com/Hackl0us/SS-Rule-Snippet" target="_blank" rel="noopener">Hackl0us</a></p>
<ul>
<li><a href="https://github.com/Hackl0us/SS-Rule-Snippet/wiki/" target="_blank" rel="noopener">懒人配置</a></li>
</ul>
</li>
<li>
<p><a href="https://github.com/blackmatrix7/ios_rule_script/" target="_blank" rel="noopener">blackmatrix7/ios_rule_script</a> 分流规则、重写写规则及脚本。这个比较全面，一般我找规则就来这里找。</p>
</li>
<li>
<p><a href="https://github.com/Hackl0us/GeoIP2-CN" target="_blank" rel="noopener">GeoIP2-CN</a> 只包含 CN 的 GeoIP，适合白名单模式。</p>
</li>
</ul>
<h2 id="常见的配置方法">常见的配置方法</h2>
<p>黑名单模式：除了我规定的走代理，剩下统统走直连。</p>
<p>白名单模式：除了我规定的走直连，剩下统统走代理。</p>
<p>我个人是觉得白名单模式比较好，省事儿，搭配一些需要直连的规则和 <code>GEOIP,CN,DIRECT</code> 很方便。</p>
<p>配置思路就是：</p>
<ul>
<li>把特殊的规则放在最上面。比如 JetBrains 在国内是可以访问的，Steam 下载游戏和 BT 之类的没必要走代理浪费流量。</li>
<li>需要配置开关的，可以单独弄一个类型，比如是测速时是走代理还是直连的 SpeedTest。</li>
<li>接下来是国内的规则集，命中就直连。
<ul>
<li>还有一个 <a href="https://github.com/blackmatrix7/ios_rule_script/blob/master/rule/Surge/ChinaMax/README.md" target="_blank" rel="noopener">ChinaMax</a> 规则集，比较大，我没试过。</li>
</ul>
</li>
<li>最后是判断 GeoIP，是 CN 的就直连</li>
<li>规则全部检查完了，<code>FINAL</code> 走代理。</li>
</ul>
<h2 id="我的配置">我的配置</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-properties" data-lang="properties"><span class="line"><span class="cl"><span class="err">[General]</span>
</span></span><span class="line"><span class="cl"><span class="na">loglevel</span> <span class="o">=</span> <span class="s">notify</span>
</span></span><span class="line"><span class="cl"><span class="na">skip-proxy</span> <span class="o">=</span> <span class="s">127.0.0.1, 192.168.0.0/16, 193.168.0.0/24, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, localhost, *.local</span>
</span></span><span class="line"><span class="cl"><span class="na">exclude-simple-hostnames</span> <span class="o">=</span> <span class="s">true</span>
</span></span><span class="line"><span class="cl"><span class="na">internet-test-url</span> <span class="o">=</span> <span class="s">http://taobao.com/</span>
</span></span><span class="line"><span class="cl"><span class="na">proxy-test-url</span> <span class="o">=</span> <span class="s">http://cp.cloudflare.com/generate_204</span>
</span></span><span class="line"><span class="cl"><span class="na">test-timeout</span> <span class="o">=</span> <span class="s">2</span>
</span></span><span class="line"><span class="cl"><span class="na">geoip-maxmind-url</span> <span class="o">=</span> <span class="s">https://github.com/Hackl0us/GeoIP2-CN/raw/release/Country.mmdb</span>
</span></span><span class="line"><span class="cl"><span class="na">dns-server</span> <span class="o">=</span> <span class="s">223.5.5.5, 223.6.6.6, 119.29.29.29, 114.114.114.114, system</span>
</span></span><span class="line"><span class="cl"><span class="na">encrypted-dns-server</span> <span class="o">=</span> <span class="s">https://dns.alidns.com/dns-query, https://doh.pub/dns-query</span>
</span></span><span class="line"><span class="cl"><span class="na">use-local-host-item-for-proxy</span> <span class="o">=</span> <span class="s">true</span>
</span></span><span class="line"><span class="cl"><span class="na">show-error-page-for-reject</span> <span class="o">=</span> <span class="s">true</span>
</span></span><span class="line"><span class="cl"><span class="na">ipv6</span> <span class="o">=</span> <span class="s">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">[Proxy]</span>
</span></span><span class="line"><span class="cl"><span class="na">🇨🇳Direct</span> <span class="o">=</span> <span class="s">direct</span>
</span></span><span class="line"><span class="cl"><span class="na">⛔️Reject</span> <span class="o">=</span> <span class="s">reject</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">[Proxy</span> <span class="s">Group]</span>
</span></span><span class="line"><span class="cl"><span class="na">Final</span> <span class="o">=</span> <span class="s">select, 🌎Proxy, 🇨🇳Direct</span>
</span></span><span class="line"><span class="cl"><span class="na">SpeedTest</span> <span class="o">=</span> <span class="s">select, 🇨🇳Direct, 🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="na">🛡Guard</span> <span class="o">=</span> <span class="s">select, ⛔️Reject, 🇨🇳Direct</span>
</span></span><span class="line"><span class="cl"><span class="na">🌎Proxy</span> <span class="o">=</span> <span class="s">select, 机场1, 机场2</span>
</span></span><span class="line"><span class="cl"><span class="na">机场1</span> <span class="o">=</span> <span class="s">url-test, policy-path=订阅地址</span>
</span></span><span class="line"><span class="cl"><span class="na">机场2</span> <span class="o">=</span> <span class="s">url-test, policy-path=订阅地址</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">[Rule]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ################## 置顶一些特殊的</span>
</span></span><span class="line"><span class="cl"><span class="err">DOMAIN-SUFFIX,jetbrains.com,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">DOMAIN-SUFFIX,bing.com,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ################## 下载类</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,aria2c,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,fdm,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,Folx,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,NetTransport,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,Transmission,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,uTorrent,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,WebTorrent,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="na">PROCESS-NAME,WebTorrent</span> <span class="s">Helper,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,qbittorrent,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,Motrix,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,Thunder,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="na">PROCESS-NAME,nwjs,DIRECT</span> <span class="s">// 城通网盘</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,qiyimac,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">PROCESS-NAME,QQLive,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ################## 规则集 https://github.com/blackmatrix7/ios_rule_script</span>
</span></span><span class="line"><span class="cl"><span class="c1"># SystemOTA</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SystemOTA/SystemOTA.list,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># SteamCN</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SteamCN/SteamCN.list,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 测速</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Speedtest/Speedtest.list,SpeedTest</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 去广告</span>
</span></span><span class="line"><span class="cl"><span class="na">DOMAIN-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising_Domain.list,🛡Guard</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising.list,🛡Guard</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 🇨🇳国内</span>
</span></span><span class="line"><span class="cl"><span class="na">DOMAIN-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China_Domain.list,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China.list,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="na">RULE-SET,https</span><span class="o">:</span><span class="s">//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/ChinaMedia/ChinaMedia.list,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 🌎国际</span>
</span></span><span class="line"><span class="cl"><span class="c1"># DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia_Domain.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy_Domain.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global_Domain.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global.list,🌎Proxy</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 系统请求 &amp; 局域网 &amp; GeoIP China</span>
</span></span><span class="line"><span class="cl"><span class="err">RULE-SET,SYSTEM,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">RULE-SET,LAN,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="err">GEOIP,CN,DIRECT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 最终</span>
</span></span><span class="line"><span class="cl"><span class="err">FINAL,Final,dns-failed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">[Host]</span>
</span></span><span class="line"><span class="cl"><span class="na">amplifi.lan</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">router.synology.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">sila.razer.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">router.asus.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">routerlogin.net</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">orbilogin.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">www.LinksysSmartWiFi.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">LinksysSmartWiFi.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">myrouter.local</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">www.miwifi.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">miwifi.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">mediarouter.home</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">tplogin.cn</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">tplinklogin.net</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">melogin.cn</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">falogin.cn</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">_hotspot_.m2m</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">hotspot.cslwifi.com</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl"><span class="na">*.lan</span> <span class="o">=</span> <span class="s">server:syslib</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">[URL</span> <span class="s">Rewrite]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># wiki 的 m 移动站点及其他语言的重写</span>
</span></span><span class="line"><span class="cl"><span class="na">https</span><span class="o">:</span><span class="s">//zh.(m.)?wikipedia.org/(wiki|zh|zh-sg|zh-tw|zh-hans)/(.*) https://zh.wikipedia.org/zh-cn/$3 302</span>
</span></span></code></pre></div><p>白名单模式，除了命中的规则外，全部走代理。</p>
<p>把 <code>Final</code> 改成直连，解开「🌎国际」的那些规则，就是黑名单模式。</p>
<p>额外再用上 <a href="https://github.com/blackmatrix7/ios_rule_script" target="_blank" rel="noopener">blackmatrix7/ios_rule_script</a> 的一些复写和脚本去广告模块：Advertising 和 AdvertisingScript。</p>
<p>Firefox 额外需要手动设置，不会自动信任本地的证书。</p>
<h2 id="分流规则">分流规则</h2>
<p><a href="https://github.com/blackmatrix7/ios_rule_script/" target="_blank" rel="noopener">blackmatrix7/ios_rule_script</a></p>
<p>按目录找到需要的规则，比如 rule → Surge → Advertising</p>
<p>在里面的 README 里写有此规则的大概说明。</p>
<p>但只给出了一个订阅链接，比如这个去广告的。除了复制  Advertising.list 的链接，还需要手动找到 Advertising_Domain.list 的，然后再把 Advertising_MITM.sgmodule 这个模块装上。</p>
<h2 id="订阅筛选">订阅筛选</h2>
<p>因为订阅的节点经常会有变动，又想用自己的配置，还是使用 <code>policy-path</code> 的功能比较好。</p>
<p>可以用正则表达式过滤或挑选，常用的一些：</p>
<h4 id="过滤">过滤</h4>
<pre tabindex="0"><code>xxx = url-test, policy-path=订阅地址, policy-regex-filter=^((?!(关键字一|关键字二)).)*$
</code></pre><h4 id="只包含">只包含</h4>
<pre tabindex="0"><code>iepl = url-test, policy-path=订阅地址, policy-regex-filter=IEPL
新加坡 = url-test, policy-path=订阅地址, policy-regex-filter=新加坡
</code></pre><h4 id="包含任意">包含任意</h4>
<pre tabindex="0"><code>policy-regex-filter=关键字一|关键字二
</code></pre><h4 id="同时包含">同时包含</h4>
<pre tabindex="0"><code>policy-regex-filter=(?=.*关键字一)(?=.*关键字二).*
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>汉字的混乱</title>
      <link>https://dvel.me/posts/chinese-character-confusion/</link>
      <pubDate>Mon, 01 Aug 2022 21:26:03 +0800</pubDate>
      <guid>https://dvel.me/posts/chinese-character-confusion/</guid>
      <description>在为自己的 Rime 输入法的词库进行修订时，发现了很多以前不曾了解的汉字规范。从修订记录里翻出了一些，算是自己的吐槽吧。</description>
      <content:encoded><![CDATA[<p>在为自己的 <a href="https://github.com/iDvel/rime-ice" target="_blank" rel="noopener">Rime 词库</a> 进行修订时，发现了很多以前不曾了解的汉字规范。</p>
<p>从修订记录里翻出了一些，算是自己的吐槽吧。。。</p>
<h2 id="模棱两可">模棱两可</h2>
<p>「滴里耷拉、滴里搭拉、滴哩答拉」→「嘀哩嗒啦」，「啰哩啰唆」→「啰里啰唆」，「劈哩叭啦」→「噼里叭啦」，「嘁哩喀喳」→ 「嘁里咔嚓」。。。</p>
<p>为什么上面这些除了「里」都是口字旁，却不用同样是口字旁的「哩」呢？</p>
<p>「暗淡」「黯淡」。</p>
<p>「呆会」「待会」，表「停留」时，《现汉》未作推荐但有一个「待dāi」的一声读音专门用于这个意思，《现规》推荐使用「呆」。</p>
<p>「标识zhi」「标志」，「标识zhi」一直是「标志」的异形词，但《现汉》6、7 开始有了「标识shi」，《现规》直接推荐使用「标志」。</p>
<p>「勾拳」「钩拳」，Hook 本就是钩子的意思，我站「钩拳」。</p>
<p>「抗不住、抗得住」「扛不住、扛得住」。</p>
<p>「嚎叫」「号叫」「嗥叫」。</p>
<p>「定亲」是「定」，「订婚」是「订」。</p>
<p>各种「词」与各种「辞」。</p>
<p>「贻 X」与「遗 X」。</p>
<p>「杆」与「竿」。</p>
<p>「得意洋洋/洋洋得意」「得意扬扬/扬扬得意」。</p>
<p>「发愤图强」「奋发图强」。</p>
<p>「鱼钩」「渔竿」「钓鱼竿」。</p>
<p>「嘁嘁嚓嚓」→「嘁嘁喳喳」，「嘁哩咔喳」→「嘁里咔嚓」，不同的地方用不同的 cha。。。</p>
<p>「下功夫」「费工夫」。</p>
<p>「悲催」「悲摧」。</p>
<p>「备受」「倍受」。</p>
<p>「比划」「比画」。</p>
<p>「西瓜子」「西瓜籽」。</p>
<p>「鄙人」「敝人」。</p>
<p>「闭塞」「蔽塞」。</p>
<p>「侧足」「厕足」。</p>
<p>「闺中密友」的「闺密」与「闺蜜」。</p>
<p>「激凸」「激突」。</p>
<p>「叫作」「叫做」。</p>
<p>「做出」「作出」，以及各种「做 X」和「作 X」。</p>
<p>「绝不」「决不」。</p>
<p>「谩骂」「漫骂」。</p>
<p>「避邪」「辟邪」。</p>
<p>「泄气」「懈气」。</p>
<p>「佚/轶/逸」+「名/事」。。。</p>
<p>「蒸气」「蒸汽 = 水蒸气」。</p>
<p>「属望」「瞩望」。</p>
<p>「启航」「起航」。</p>
<p>「乐呵」「乐呵呵」「乐乐和和」。</p>
<p>「当啷」与「郎当」。</p>
<p>「作何」「做何」。</p>
<p>「订做」「定做」。</p>
<p>「订制」「定制」。</p>
<p>「实验」「试验」。</p>
<p>「畜生」「牲畜」。</p>
<p>「无名火」「无明火」。</p>
<p>「去除」「祛除」「驱除」。</p>
<p>「碾压」「碾轧」</p>
<p>「阵势」「阵式」</p>
<h2 id="过于细致的拆分">过于细致的拆分</h2>
<p><strong>很多字词没有作为异形词，而是分别赋予了不同的意思，或运用在不同的语境下。</strong></p>
<p>校对网还看到一个 <a href="http://www.jiaodui.com/bbs/read.php?tid=34028&amp;page=10" target="_blank" rel="noopener">校对疑难问题分享搜集</a>。</p>
<p>细致的 cha：「道路分岔」「树木分杈」「头发分叉」「河流分汊」，还有个「裤裆开衩」。😅</p>
<p>「群山曼延」「杂草蔓延」「洪水漫延」。</p>
<p>「声音/水势洪大」「规模宏大」。</p>
<p>「作客」「做客」。</p>
<p>「用作」「用做」。</p>
<p>「年青」「年轻」。</p>
<p>「莫名其妙」「莫明其妙」居然不是异形词，而分别代表不同的意思，有细微的差别。</p>
<p>「谐调」「协调」，「协调」包含「谐调」，但多一个「使配合得当」的意思。</p>
<p>「嘀嗒」「滴答」，「嘀嗒」和喇叭钟表等相关，「滴答」和雨滴相关。</p>
<p>「淤斑」「瘀斑」、「淤血、瘀血」，前者表血液凝滞，接近西医；后者一般用于中医。</p>
<p>「赢利」「盈利」「营利」。</p>
<p>各种 meng long，日光不明用「曚昽」，月光不明用「朦胧」，目光和其余的都是「蒙眬」。</p>
<p>「含意」「含义」，「含义」表字词句具体的意义；「含意」表言语行为事件含有的意思（隐含的深意或言外之意）。</p>
<p>「片段」「片断」，前者表完整段落，后者表零碎段落。</p>
<p>「纯朴」「淳朴」，意思基本一致。</p>
<p>「泄露」「泄漏」，一般来说是「泄露秘密」和「泄漏原油」，但《现汉》里「泄露」下面写了一个「同泄漏」，「泄漏」下面写一个「同泄露」，《现规》甚至还弄了一个「泄漏消息」的例句。</p>
<p>「蕴含」「蕴涵」，前者是常用的，后者多用于一些学术上的。</p>
<p>「查/察看」「检查/察」「考查/察」「审查/察」。</p>
<p>「腆着胸脯」「觍着脸」是不同的 tian。</p>
<p>「辨证」「辩证」。</p>
<p>「传授」「传受」。</p>
<p>「画外音」「话外音」。</p>
<p>「见谅」「鉴谅」。</p>
<p>「交代」「交待」。</p>
<p>「宽洪」「宽宏」。</p>
<p>「联合」「连合」，「连合」居然不是异形词。</p>
<p>「弥蒙」「迷蒙」。</p>
<p>「起程」「启程」，《现汉》几个版本折腾两遍后，又全都收录了。</p>
<p>「善于」「擅于」。</p>
<p>「蛊惑」「鼓惑」。</p>
<p>「受让」「授让」。</p>
<p>「萦绕」「潆绕」。</p>
<p>「执掌」「职掌」。</p>
<p>「受命」「授命」。</p>
<p>「农田龟jun裂」与「皮肤皲jun裂」。</p>
<p>「撅屁股」与「噘嘴」。</p>
<p>「报料」「爆料」。</p>
<p>「抚养」「扶养」。</p>
<p>「急须」「急需」「亟须」「亟需」。。。</p>
<p>「神志」「神智」。</p>
<p>「肤浅」「浮浅」。</p>
<h2 id="词典的问题">词典的问题</h2>
<p>「嘀里嘟噜」「滴里嘟噜」，《现规》说不宜写作「滴里嘟噜」，《现汉》则都收录了，并且表示的意思不一样。</p>
<p>「不惟」「不唯」，《现汉》收录的是「不惟」，但怎么想也应该是「唯」，「唯」才有「但、仅、只是」的意思。</p>
<p>《现汉》推荐「钩心斗角」，《现规》推荐「勾心斗角」。</p>
<p>「蓬门荜户」「蓬门筚户」《现汉》推荐「荜」，《现规》推荐「荜」，按字义来看，「荜」是植物，「筚」是用植物做的东西，应该用「筚」比较合适。</p>
<p>《现汉》推荐「比画」，《现规》推荐「比划」。</p>
<p>「鱼钩」「渔钩」，早期《现汉》《现规》都推荐「渔钩」，后来《现汉》推荐「鱼钩」；虽然《现规》的推荐是「鱼钩→渔钩」，但是它还推荐了「渔汛→鱼汛」，好乱。</p>
<p>「德行」「德性」，表骂人时，《现汉》推荐「德行」，《现规》推荐「德性」。</p>
<p>《现汉》推荐「蹚浑水」，《现规》推荐《趟浑水》，《现规》直接将「蹚」作为「趟」的异形词，而《现汉》对「趟（一声）」的解释是「旧同蹚」。</p>
<p>《现汉》将「高招儿、高着儿」「绝招儿、绝着儿」「妙招儿、妙着儿」按照是否下棋作为区分，但对「昏招儿、昏着儿」却按异形词进行处理。</p>
<p>《现汉》推荐了「瓷器」与「磁漆」，两个 ci 并不统一。</p>
<p>「繁琐」「烦琐」，现在《现汉》首选「烦琐」了，感觉「繁琐」用的更多。</p>
<p>《现汉》推荐「榴梿」，全国科学技术名词审定委员会推荐「榴莲」（目前使用较为广泛的）。</p>
<p>《现汉》对「旋涡」「漩涡」来回折腾，一会这个是异形词，一会那个是异形词。</p>
<p>《现汉》前几版及《现规》推荐「称钱」，《现汉》现在推荐「趁钱」。</p>
<p>《现汉》推荐「轧马路」，《现规》推荐「压马路」。</p>
<p>有很多字词，全国科学技术名词审定委员会、《现代汉语词典》、《现代汉语规范词典》都不同。</p>
<p>对于多音字，词典没有给出那些少数的特殊读音的全部用例，比如「棱leng」还有一个 ling 音，《现汉》和《现规》的解释中都只提到「穆棱ling」，其实还有一个「丹棱ling」。这让普通人就更难寻找到正确的读法，尤其是中文搜索本就比较艰难，百度百科也没有一丁点儿可信度。比如一大堆含有多音字「陂bei pi po」的地名，完全无从寻找，难道只能问当地人吗？</p>
<h2 id="专业术语的用字选择">专业术语的用字选择</h2>
<p>「桔子」是「橘子」的俗写，但「橘斑幅尺蛾」根本搜不到什么，只能用「桔斑幅尺蛾」，在很多食物中也使用了「桔」。</p>
<p>很多计算机的书籍、论文仍在用「标识符」，应该用「标志符」，《第一批异形词整理表》就将「标识zhi」替换为了「标志」，但《现汉》同时收录了「标识zhi」和「标识shi」。</p>
<p>到底是「安纽夜蛾」还是「安钮夜蛾」呢。</p>
<p>「桑葚」「桑椹」混用的情况极多。</p>
<h2 id="历史包袱">历史包袱</h2>
<p>「做戏」「逢场作戏」的「做/作」。</p>
<p>「褴褛」「筚路蓝缕」的「褴/蓝」与「褛/缕」。</p>
<p>「反照」「回光返照」的「反/返」，另外《现汉》推荐的是「反照」，《现规》推荐的是「返照」。</p>
<p>「屏除、屏弃、屏绝」「摒除、摒弃、摒绝」，「象/像」做了细致的区分，但「屏/摒」没有做。</p>
<p>「伶仃洋」「零丁洋里叹零丁」。</p>
<p>「丰都」「酆都鬼城」。</p>
<p>「二心」「忠贞不贰」。</p>
<p>「拾遗补阙」「补缺」。</p>
<p>「飞语」「流言蜚语」。</p>
<p>「句践」→「勾践」，但是「高句丽」仍然在用「句」。</p>
<p>词典和民众使用习惯都已经完成转换的词汇，比如「折衷」→「折中」，但是在一些专业领域仍保留原始的写法。例如「折中」与「折衷主义疗法」、「艾鲁岛折衷鹦鹉」，又例如「鲇鱼」与许多冷门生物名词「XX鲶」。</p>
<h2 id="特殊的读音">特殊的读音</h2>
<p><strong>极度坑爹的读音。</strong></p>
<p>「杉shan树」的木头不叫「杉shan木」，叫「杉sha木」 (╯°Д°)╯︵ ┻━┻</p>
<p>「栅shan极」的字典解释是：一种栅zha状电极  (╯°Д°)╯︵ ┻━┻</p>
<p>「溃hui脓」的字典解释是：伤口溃kui烂  (╯°Д°)╯︵ ┻━┻</p>
<p>「雀qiao子」的字典解释是：雀que斑  (╯°Д°)╯︵ ┻━┻</p>
<p>「疟yao子」的字典解释是：疟nue疾  (╯°Д°)╯︵ ┻━┻</p>
<p>「桑葚ren儿」 = 「桑葚shen」  (╯°Д°)╯︵ ┻━┻</p>
<p>「貉he」通称「貉hao子」  (╯°Д°)╯︵ ┻━┻</p>
<p>「荨qian麻」「荨xun麻疹」，这个应该是误读过多的影响。</p>
<p>「摩挲」念 mo suo 时表示「用手抚摩」，念 ma sa 时表示「用于轻轻按着并一下一下地移动」😰</p>
<p><strong>几乎只在某一固定词语或中使用的读音，多数为地名，不太了解这种读音是怎么产生的，为什么在历史发展的过程中没有被其他常用读音给替换掉。</strong></p>
<p>「豸zhi」的「冠豸zhai山」。</p>
<p>「蚌beng埠」的「蚌bang」。</p>
<p>「咀ju」的「尖沙咀zui」。</p>
<p>「厦sha」的「厦xia门」。</p>
<p>「柞zuo」的「柞zha水」。</p>
<p>「栎li」的「栎yue阳」。</p>
<p>「栟bing」的「栟ben茶」。</p>
<p>「泌mi」的「泌bi阳」。</p>
<p>「桧gui」唯独在人名里念「hui」，「秦桧hui」，应该是自秦桧以后没人起带「桧」的名字了。</p>
<p>「絜xie」唯独在人名里念「jie」，应该是简化时的附带问题。</p>
<p>「殖zhi」的「骨殖shi」。</p>
<p>「氏shi」的「阏氏zhi」。</p>
<p>「峙zhi」的「繁峙shi」。</p>
<p>「筠yun」的「筠jun连」。</p>
<p>「泷long」的「泷shuang水」。</p>
<p>「洞dong」的「洪洞tong」。</p>
<p>「浚jun」的「浚xun县」。</p>
<p>「单dan」的「单shan县」和「单chan于」。</p>
<p>「浰li」的「洴浰lian」。</p>
<p>「牟mou」的「牟mu平、中牟mu」。</p>
<p>「番fan」的「番pan禺」。</p>
<p>「磅bang」的「磅pang礴」。</p>
<p>「筠yun」的「筠jun连」。</p>
<p>「绿lv」的「绿lu林、鸭绿lu江」。</p>
<p>「缩suo」的「缩su砂密」。</p>
<p>「荠ji」的「荸荠qi」。</p>
<p>「荥xing阳」「荥ying经」两个地名两个音，且这个字基本上只在这两个地名中使用。</p>
<p>「莞wan」的「东莞guan」。</p>
<p>「迫po」的「迫pai击炮」。</p>
<p>「铅qian」的「铅yan山」。</p>
<p>「阿e房pang宫」。</p>
<p>「育yu」的「杭育yo」。</p>
<p>「瀑pu」的「瀑bao河」。</p>
<p>「缩suo」的「缩su砂密」，这个读音简直莫名其妙！</p>
<p><strong>前面的读音不知道是如何产生的，但是下面这些外来的音译也用了一个很生僻的发音，感觉莫名其妙。</strong></p>
<p>「哪ne吒」。</p>
<p>佛教用语「南na无mo」。</p>
<p>「呗bei」的「梵呗fan bai」。</p>
<p>「犍qian陀罗」，「犍qian/jian」，又生僻又是多音字。</p>
<p>「戛jia/ga」发 ga 音时，只用于「戛ga纳」，那为什么不用一个本来就发 ga 音的字呢？</p>
<p>「秘mi/bi」发 bi 音时，只用于「秘bi鲁」，那为什么不用一个本来就发 bi 音的字呢？为什么而且 Peru 的发音类似 po 而不是 bi。</p>
<p>「派pai/pa」发 pa 音时，只用于「派司」，表示 pass，那为什么不用一个本来就发 pa 音的字呢？</p>
<h2 id="字典与日常常用的不太一样">字典与日常常用的不太一样</h2>
<p>「别介jie」（天津话的「别这样啊」），字典正字是「别价jie」。</p>
<p>「干嘛má」（干啥），字典正字是「干吗má」。</p>
<p>「瞅你咋地di」，字典正字是「咋的di」。</p>
<h2 id="音译用字的混乱">音译用字的混乱</h2>
<p>「傅立叶」「傅里叶」。</p>
<p>「菲利浦」「飞利浦」「菲利普」。</p>
<p>「笛卡儿」「笛卡尔」。</p>
<p>「喜玛拉雅」「喜马拉雅」。</p>
<p>「碧昂斯」「碧昂丝」。</p>
<p>「汉摩拉比、汉漠拉比、汉漠拉比、汉莫拉比」「汉谟拉比」。</p>
<p>「札」与「扎」的混用。</p>
<p>「诺亚方舟」「挪亚方舟」。</p>
<p>「克里Kerry」「克利Klee」。</p>
<p>「克利斯Klis」「克里斯Chris」「克莉丝Chris」「克丽丝Kris」「科利斯Corlys」。。。</p>
<p>「峇株巴辖」这种译名更扯淡，「峇厘岛」已经改译为「巴厘岛」了，这译名居然弄了两个不同的 ba。</p>
<p>「恺撒」与「凯撒」。</p>
<p>还有一大堆这种混用的音译字：</p>
<p>爱、艾、埃</p>
<p>里、力、立、利、丽</p>
<p>思、丝、司、斯</p>
<p>亚、娅</p>
<p>哥、歌、戈、格</p>
<p>尼、妮</p>
<p>帝、迪、蒂、狄</p>
<p>儿、尔</p>
<p>伯、勃、博</p>
<p>福、弗、富、辅、芙、佛、</p>
<p>最经典的还得是下面这条修订记录：</p>
<p>「玛丽雅、玛丽亚、马丽娅、马里亚、马丽亚、玛利娅、玛丽娅、玛莉亚、玛俐亚」→「马利亚、玛利亚」🤦‍♂️</p>
<br>
<p>古希腊文学翻译家罗念生先生针对后面是否接元音分别使用了「忒」和「特」做不同的译名，如「忒修斯」「忒弥斯」都没有用「特」，而是用一个生僻的多音字「忒te tei tui」（在这里念 tè）。</p>
<p>这种「规则」的优劣且不说，但「统一用字」是好的，「制定并完全遵守规则」也是好的，而目前则是没有统一，也没有规则。</p>
<p>有朋友提了个 issue 说《原神》角色「优菈」打不出来，不明白为什么米哈游要使用一个没人用的「菈」而不使用常见的「拉」，谷歌图片搜索「菈」，出来的全是原神的内容。要是都不遵守惯用套路，译名选字还要选《通用规范汉字表》和《现代汉语词典》都没有收录的字，那真是乱套了。</p>
<br>
<p>最让人无语的状况莫过于一个多音字在译名中以多种发音出现，例如：</p>
<ul>
<li>
<p>伽 jia ga qie</p>
<ul>
<li>伽利略 jia li lve</li>
<li>奥米伽 ao mi ga</li>
<li>伽蓝 qie lan</li>
</ul>
</li>
<li>
<p>佛 fo fu</p>
<ul>
<li>佛罗里达 fo luo li da</li>
<li>雪佛兰 xue fu lan</li>
</ul>
</li>
</ul>
<p>另外「伽」在外语原文发音为 ga，但在译名中念 jia 的情况有很多。</p>
<p>（╯&rsquo; - &lsquo;)╯︵ ┻━┻</p>
<p>（╯&rsquo; - &lsquo;)╯︵ ┻━┻</p>
<p>(╯°Д°)╯︵ ┻━┻</p>
<h2 id="简繁或地区的一些不同">简繁或地区的一些不同</h2>
<p>表示打招呼或惊诧时的语气词，繁体有个「誒」，但《现汉》《现规》《通用汉字规范表》都没有收录「诶」，大陆用的是「欸」。</p>
<p>「蕃茄」「番茄」，其他使用汉语的地区基本都是「蕃」，中国大陆是「番」。</p>
<p>简化字没有简化「噹 → 𪠽」，这个拟声词还是很常用的，字典中是以「当」代替的。</p>
<p>简化字没有简化「襬 → 䙓」，而是使用了「摆」，「衣摆、裙摆」。</p>
<h2 id="热门但错误的商用">热门但错误的商用</h2>
<p>「比萨」「匹萨」「披萨」，「比萨」是《现汉》推荐的，但 pizza 发音明明是 pi，很多商家都在用后两个，不过比萨行业龙头之一的必胜客使用了「比萨」，现在用「比萨」的也比较多了。但日常发音与广告中都在使用 pi 的音，《现汉》却至今没有更改推荐字或读音。</p>
<p>「拉钩」是正确用字，但「拉勾网」用的是「勾」。</p>
<p>表汽车喇叭时用「嘀嘀」，但「滴滴打车」是「滴」。</p>
<p>告五人的歌曲《披星戴月的想你》应该用「地」。</p>
<p>希腊字母 sigma 的正确写法是「西格马」，但行业术语「六西格玛」使用了不同的 ma。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Netflix 中英双语字幕的好办法</title>
      <link>https://dvel.me/posts/netflix-chinese-english-bilingual-subtitles/</link>
      <pubDate>Fri, 17 Jun 2022 00:38:46 +0800</pubDate>
      <guid>https://dvel.me/posts/netflix-chinese-english-bilingual-subtitles/</guid>
      <description>了解如何在 Netflix 中使用双语字幕？使用 Language Reactor 插件可以轻松设置中英字幕。</description>
      <content:encoded><![CDATA[<p>使用插件 <a href="https://www.languagereactor.com/" target="_blank" rel="noopener">Language Reactor</a>，目前只支持 Chrome，Firefox 很久了一直处于 coming soon 状态。</p>
<p>相比较其他双语插件，它本身就是个学外语的好插件，有方便的快捷键可以穿梭字幕。</p>
<p>但是双语字幕时有一些问题，就是英文字幕为主会带有很多拟声词之类的，太影响体验了。</p>
<p>而且是英文在上面，中文在下面，和平常使用的字幕反了。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-06-17-000977.webp"
            alt="2022-06-17-000977"
            width="1294"
            height="539"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<br>
<hr>
<br>
<ul>
<li>将主字幕设置为中文</li>
<li>在 Language Reactor 设置界面的「翻译语言」设置为英文</li>
<li>「显示音译」设置为「无音译」</li>
</ul>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-06-17-000979.webp"
            alt="2022-06-17-000979"
            width="1702"
            height="1157"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>这样体验就好多啦：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-06-17-000980.webp"
            alt="2022-06-17-000980"
            width="2150"
            height="326"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>优化 Rime 英文输入体验</title>
      <link>https://dvel.me/posts/make-rime-en-better/</link>
      <pubDate>Thu, 12 May 2022 03:01:28 +0800</pubDate>
      <guid>https://dvel.me/posts/make-rime-en-better/</guid>
      <description>通过挂载英文方案到主输入方案中，实现 Rime 拼音方案中同时输入英文单词。解决短单词置顶、重码等问题，提高输入效率和体验。</description>
      <content:encoded><![CDATA[<h2 id="在-rime-拼音方案中输入英文">在 Rime 拼音方案中输入英文</h2>
<p>用 <a href="https://github.com/BlindingDark/rime-easy-en" target="_blank" rel="noopener">easy_en</a> 方案挂载到自己的主输入方案（全拼、双拼、五笔等），就可以同时输入英文单词。</p>
<p>我用的是 <a href="https://github.com/tumuyan/rime-melt" target="_blank" rel="noopener">melt_eng</a> 方案，差不多，就是拼写规则的大小写方面改了一点。</p>
<p>引入示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dependencies</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">melt_eng</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">engine</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">translators</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">table_translator@melt_eng</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">melt_eng</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">melt_eng</span><span class="w">
</span></span></span></code></pre></div><p>这样挂载了英文方案与英文词库，在拼音方案下就可以输入英文单词。</p>
<p>因为不是同一个翻译器，英文不会和拼音共同造词，比如输入「applediannao」，并不会自动生成「Apple电脑」，只能给常用的中英混合词汇单独弄一个词典。</p>
<h2 id="期望的行为">期望的行为：</h2>
<ul>
<li>拼音优先</li>
</ul>
<p>输入「ma」，前几个候选项应为「吗 嘛 马」，而不是「Mac mad man」。</p>
<ul>
<li>重码时拼音优先</li>
</ul>
<p>如「四则」与 size 冲突时，希望「四则」排在第一位</p>
<ul>
<li>短单词优先</li>
</ul>
<p>输入 <code>mac</code>，第一候选项应为 <code>Mac</code>，而不是「马车」。</p>
<p>可以降低个别短单词在候选项的位置，<a href="#%e7%9f%ad%e5%8d%95%e8%af%8d%e7%bd%ae%e9%a1%b6%e7%9a%84%e9%97%ae%e9%a2%98">在下文</a>。</p>
<ul>
<li>未输入完全时的英文长单词：</li>
</ul>
<p>输入 <code>googl</code>，第一候选项应为 <code>Google</code>，而不是「个哦讴歌来」这种无意义的内容。</p>
<h2 id="目前的问题">目前的问题：</h2>
<p>目前的问题是这样的，输入完整的短单词权重低，输入不完整的长单词时第一候选项总是一个莫名其妙的中文。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-05-11-000708.webp"
            alt="Rime 默认的问题"
            width="938"
            height="384"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="权重设定">权重设定</h2>
<p>经过多次尝试，最后是给拼音和英文都设置一个权重来搞定的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 拼音</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">translator</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">rime_ice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">initial_quality</span><span class="p">:</span><span class="w"> </span><span class="l">x</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">melt_eng</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">melt_eng</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">initial_quality</span><span class="p">:</span><span class="w"> </span><span class="kc">y</span><span class="w">
</span></span></span></code></pre></div><p>尝试过「不设置:-1」「不设置:0」「不设置:1」「1:0」「2:1」「3:2」「2:1.x」。。。</p>
<p>最后发现一个神奇的比例是 2 &gt; x &gt; y &gt; 1。</p>
<p>使用了 1.2:1.1，各方面都比较合适，有点玄学😂。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-05-11-000717.webp"
            alt="期望的行为"
            width="1282"
            height="390"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="重码问题">重码问题</h2>
<p>比如 can you she he size man，既是完整拼音，也是完整单词，在输入过该单词后，会有这样的问题：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-05-10-000693.webp"
            alt="重码问题"
            width="560"
            height="400"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>如果不希望这样，可以直接在词库删掉重码的单词，或永远不输入这个单词，或手动 Fn+Shift+Del 降低权重。</p>
<p>但推荐直接在配置文件中禁用用户词典，因为英文方案不需要造词，自然也就不需要记录到用户词典；没有用户词典，就没有调频。</p>
<p>禁用用户词典还有一个小优点，例如写了这样的固定顺序：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="l">macOS	macOS	999</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Sierra	macOS	1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS High Sierra	macOS	2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Mojave	macOS	3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Catalina	macOS	4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Big Sur	macOS	5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Monterey	macOS	6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Ventura	macOS	7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">macOS Sonoma	macOS	8</span><span class="w">
</span></span></span></code></pre></div><p>那么输入 <code>macos</code> 后，候选项将始终是 <code>macOS</code> 排在第一，接着是最新的系统 <code>macOS Sonoma</code>、<code>macOS Ventura</code> ……</p>
<h2 id="完整的参考配置">完整的参考配置</h2>
<p>参考配置仓库：<a href="https://github.com/iDvel/rime-ice" target="_blank" rel="noopener">iDvel/rime-ice</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># rime_ice.schema.yaml</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">custom_phrase</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">user_dict</span><span class="p">:</span><span class="w"> </span><span class="l">custom_phrase</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">db_class</span><span class="p">:</span><span class="w"> </span><span class="l">stabledb</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">enable_completion</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">enable_sentence</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">initial_quality</span><span class="p">:</span><span class="w"> </span><span class="m">99</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">translator</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">rime_ice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">initial_quality</span><span class="p">:</span><span class="w"> </span><span class="m">1.2</span><span class="w">  </span><span class="c"># 拼音权重 1.2</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">melt_eng</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dictionary</span><span class="p">:</span><span class="w"> </span><span class="l">melt_eng</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">enable_sentence</span><span class="p">:</span><span class="w"> </span><span class="kc">false</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="nt">enable_user_dict</span><span class="p">:</span><span class="w"> </span><span class="kc">false</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="nt">initial_quality</span><span class="p">:</span><span class="w"> </span><span class="m">1.1</span><span class="w">     </span><span class="c"># 英文权重 1.1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">comment_format</span><span class="p">:</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">xform/.*//          </span><span class="w"> </span><span class="c"># 清空提示码（就是没有那个小尾巴）</span><span class="w">
</span></span></span></code></pre></div><h2 id="解决副作用">解决副作用</h2>
<h3 id="日期时间">日期时间</h3>
<p>拼音的 <code>initial_quality</code> 大于 1 后，日期时间的 Lua 脚本 <code>yield</code> 的候选项会跑到最后面，输入 rq/sj 或 date/time 后，候选项处于最末端，date/time 还好，rq/sj 需要翻好多页。解决方法是在 <code>yield()</code> 前设置一个高权重：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gd">- yield(Candidate(&#34;date&#34;, seg.start, seg._end, os.date(&#34;%Y-%m-%d&#34;), &#34;&#34;))
</span></span></span><span class="line"><span class="cl"><span class="gd"></span><span class="gi">+ local cand = Candidate(&#34;date&#34;, seg.start, seg._end, os.date(&#34;%Y-%m-%d&#34;), &#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="gi">+ cand.quality = 100
</span></span></span><span class="line"><span class="cl"><span class="gi">+ yield(cand)
</span></span></span></code></pre></div><h3 id="v-模式">v 模式</h3>
<p>英文的 <code>initial_quality</code> 大于 1 后，方案中的「v 模式」的候选项也跑到最后面了，输入「va」的候选项是「van vain &hellip;」，而不是「ā á ǎ à &hellip;」，可以通过 Lua 脚本解决。</p>
<h3 id="短单词置顶的问题">短单词置顶的问题</h3>
<p>一般输入 Mac 时，可能确实想输入这个单词，那么它在第一个候选项就没问题。</p>
<p>但是输入 rug 这种冷门单词时，用户大概率是想输入「如果」。</p>
<p>这种词汇并不多，日常使用也碰不到几个，可以手动处理。</p>
<p>用 Lua 解决了这个问题。（不会 Lua，感谢大佬 @<a href="https://github.com/shewer" target="_blank" rel="noopener">Shewer Lu</a> 指点）</p>
<p>然后在方案文件 <code>xxx.schema.yaml</code> 中可以配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># 增加一个 lua_filter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">engine</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">filters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">lua_filter@*reduce_english_filter</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">reduce_english_filter</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">idx</span><span class="p">:</span><span class="w"> </span><span class="m">2</span><span class="w">                   </span><span class="c"># 降低到第 idx 个位置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">words</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">rug, bus, ship] </span><span class="w"> </span><span class="c"># 要降低的单词</span><span class="w">
</span></span></span></code></pre></div><p>效果：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2023-02-10-001137.webp"
            alt="改变顺序后的效果"
            width="468"
            height="408"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="自动大写">自动大写</h2>
<p>由 <code>autocap_filter.lua</code> 实现，感谢 <a href="https://github.com/abcdefg233" target="_blank" rel="noopener">@abcdefg233</a> <a href="https://github.com/mirtlecn" target="_blank" rel="noopener">@mirtlecn</a> 的几个 PR。</p>
<p>目前雾凇拼音用的是 20k 小词库，只是方便打一些常见英文，并且纯手动调整了一些大小写。</p>
<p>一般情况输入小写即可得到普通单词的小写形式，和大多数人名、地名、专有名词的大写形式。</p>
<p>通过 <code>autocap_filter.lua</code> 可以再将结果进行大写转换，目前的的行为：</p>
<table>
  <thead>
      <tr>
          <th>说明</th>
          <th>code</th>
          <th>text</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>输入小写，得到词库中的原样</td>
          <td>latex</td>
          <td>LaTeX</td>
      </tr>
      <tr>
          <td>输入首字母大写，得到首字母大写</td>
          <td>Hello</td>
          <td>Hello</td>
      </tr>
      <tr>
          <td>输入前2~n个字母大写，得到全大写</td>
          <td>HEllo</td>
          <td>HELLO</td>
      </tr>
      <tr>
          <td>同上，输入全大写，得到全大写</td>
          <td>HELLO</td>
          <td>HELLO</td>
      </tr>
  </tbody>
</table>
<h2 id="拼写派生">拼写派生</h2>
<p>在 <code>melt_eng.schema.yaml</code> 中修改了大量派生规则，感谢 <a href="https://github.com/mirtlecn" target="_blank" rel="noopener">@mirtlecn</a> 的 PR（<a href="https://github.com/iDvel/rime-ice/pull/326" target="_blank" rel="noopener">#326</a>）。</p>
<p>派生了一些单词的拼写，对于数字同时支持了英文、全拼及双拼的拼音，也支持了部分符号标点：</p>
<table>
  <thead>
      <tr>
          <th>单词</th>
          <th>支持的输入方式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>i18n</td>
          <td>ishiban | ieighteenn</td>
      </tr>
      <tr>
          <td>K8s</td>
          <td>kbas | keights</td>
      </tr>
      <tr>
          <td>.NET</td>
          <td>dotnet</td>
      </tr>
      <tr>
          <td>Windows 11</td>
          <td>windowsshiyi | windowseleven</td>
      </tr>
      <tr>
          <td>Windows 2000</td>
          <td>windowsliangqian | windowserqian<br />windowstwoooo | windowserooo</td>
      </tr>
      <tr>
          <td>D&amp;D</td>
          <td>dandd</td>
      </tr>
  </tbody>
</table>
<p>对于中英混输词库，所有词条的编码加上了一个特殊符号前缀，防止英文方案拼写派生时派生出全大写字母：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="l">T恤	ⓘTxu</span><span class="w">
</span></span></span></code></pre></div><p>示例：输入 <code>txu</code> 得到「T恤」；输入 <code>Txu</code> 得到「T恤」； 输入 <code>TXU</code> 则只会得到 TXU。</p>
]]></content:encoded>
    </item>
    <item>
      <title>判断字符是否为简体字或繁体字</title>
      <link>https://dvel.me/posts/judge-characters-simplified-or-traditional/</link>
      <pubDate>Thu, 28 Apr 2022 00:01:19 +0800</pubDate>
      <guid>https://dvel.me/posts/judge-characters-simplified-or-traditional/</guid>
      <description>判断一个字符是简体字还是繁体字，可以通过 Unicode 字符集中的简繁字符的映射表 Unihan_Variants.txt 进行判断。另外，也可以用 opencc 做简繁转换，然后对比原字符。但是要注意，Unicode 字符集中简繁字符的映射表不完全，opencc 的简繁转换也可能会出现一些问题。</description>
      <content:encoded><![CDATA[<p>判断一个字符是简体字还是繁体字。</p>
<h2 id="unicode-范围">Unicode 范围</h2>
<p>开始以为可以用 Unicode 范围来表示，了解后发现简繁之间在 Unicode 字符集中位置存在交集，并且不是连续的，没办法用这种方法搞定。</p>
<p>如果真要靠这种办法，需要在茫茫字表中进行超级详细和繁杂的范围指定。</p>
<p>看到叶典网有一个<a href="http://yedict.com/zsts.htm" target="_blank" rel="noopener">字符集</a>范围，但没有区分简繁。</p>
<p>Golang 也有一个 <code>unicode.Han</code>，也没有区分简繁。</p>
<h2 id="unihan_variantstxt"><code>Unihan_Variants.txt</code></h2>
<p>在 <a href="http://www.unicode.org/Public/UCD/latest/ucd/" target="_blank" rel="noopener">http://www.unicode.org/Public/UCD/latest/ucd/</a> 下载 <code>Unihan.zip</code>，打开里面的 <code>Unihan_Variants.txt</code>。</p>
<p>比如「战斗」的「斗」（繁体是「鬥」）这两行：</p>
<p>「斗」是 <code>U+6597</code>，「鬥」是 <code>U+9B25</code>。</p>
<pre tabindex="0"><code>U+6597	kTraditionalVariant	U+9B25
U+9B25	kSimplifiedVariant	U+6597
</code></pre><ul>
<li>
<p><code>kTraditionalVariant</code> 前面是简体专用，后面是繁体专用；</p>
</li>
<li>
<p><code>kSimplifiedVariant</code> 前面是繁体专用，后面是简体专用。</p>
</li>
</ul>
<p>另外有「后U+540E、後U+5F8C」这种的字，「皇后」是简繁体通用，但表示 behind 时，简体用「后面」，繁体用「後面」。</p>
<p>所以就有以下这些行：</p>
<pre tabindex="0"><code>U+540E	kSimplifiedVariant	U+540E
U+5F8C	kSimplifiedVariant	U+540E
U+540E	kTraditionalVariant	U+540E U+5F8C
------- 翻译一下： -------
后	kSimplifiedVariant	后
後	kSimplifiedVariant	后
后	kTraditionalVariant	后 後
</code></pre><p>这种一对多、多对一的转换，除了「后/後」，还有「干/幹」等。</p>
<p>还有 <code>kSpecializedSemanticVariant</code> 这种「井/丼」的。</p>
<p>还有 <code>kSpoofingVariant</code> 这种欺骗性变体，比如「胶 U+80F6」和「㬵 U+3B35」不是同一个字。</p>
<br>
<p>参照 <a href="http://www.unicode.org/reports/tr38/#SCTC" target="_blank" rel="noopener">http://www.unicode.org/reports/tr38/#SCTC</a> 查看各种标记的说明。</p>
<p>用不到这么精细的，不过这是个好工具啊，以后可能会用到。</p>
<h2 id="自己弄个简体字表">自己弄个简体字表</h2>
<p>适合简单的场景。</p>
<p>比如《<a href="https://github.com/iDvel/The-Table-of-General-Standard-Chinese-Characters" target="_blank" rel="noopener">通用汉字规范表</a>》，但只有 8105 个字，并没有涵盖全部的简体字，比如「肏」「屄」「〇」「屌」「囧」等等很多字不在其中。</p>
<p>但《通用汉字规范表》缺失了大量生僻字，比如一大堆以鸟字旁、鱼字旁做为偏旁的汉字，不知道去哪里找到比较全面的字表。</p>
<h2 id="opencc">opencc</h2>
<p>如果不是太严谨的需求，临时使用的脚本等，可以考虑这个。</p>
<p>用 <a href="https://github.com/BYVoid/OpenCC" target="_blank" rel="noopener">opencc</a> 做简繁转换，然后对比原字符。</p>
<br>
<p>示例，判断字符是否为繁体字：</p>
<p>把字符进行繁转简。</p>
<p><code>c1</code> 和繁转简后一致，则 <code>c1</code> 是简体字；</p>
<p><code>c2</code> 和繁转简后不同，则 <code>c2</code> 是繁体字。</p>
<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">opencc</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">converter</span> <span class="o">=</span> <span class="n">opencc</span><span class="o">.</span><span class="n">OpenCC</span><span class="p">(</span><span class="s1">&#39;t2s.json&#39;</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">c1</span> <span class="o">=</span> <span class="s1">&#39;门&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">c1</span> <span class="o">==</span> <span class="n">converter</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">c1</span><span class="p">))</span>  <span class="c1"># &#39;门&#39; == &#39;门&#39; True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">c2</span> <span class="o">=</span> <span class="s1">&#39;門&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">c2</span> <span class="o">==</span> <span class="n">converter</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">c2</span><span class="p">))</span>  <span class="c1"># &#39;門&#39; != &#39;门&#39; False</span>
</span></span></code></pre></div><br>
<p>但并不完全成功：</p>
<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">opencc</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">converter</span> <span class="o">=</span> <span class="n">opencc</span><span class="o">.</span><span class="n">OpenCC</span><span class="p">(</span><span class="s1">&#39;t2s.json&#39;</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="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</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 class="s1">&#39;鮡&#39;</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 class="s1">&#39;鮋&#39;</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 class="s1">&#39;鰺&#39;</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">c</span><span class="o">+</span><span class="s1">&#39; -&gt; &#39;</span><span class="o">+</span><span class="n">converter</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="n">converter</span><span class="o">.</span><span class="n">convert</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="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鴞 -&gt; 鸮</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鶲 -&gt; 鹟</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鮡 -&gt; 鮡</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; 鮠</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; 䲟</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鮋 -&gt; 鲉</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鮈 -&gt; 鮈</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; 鲌</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鰺 -&gt; 鲹</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鰏 -&gt; 鲾</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 鰟 -&gt; 鳑</span>
</span></span></code></pre></div><p>试了一些超冷门的字，如「鮡 鮠 鮈」并没有被转换为「𬶐 𬶏 𬶋」。</p>
<p>另外还有一些问题，如「乾」会被识别为繁体字，转换为「干」。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Cloudflare 转入域名提示「出现了问题。请重试转移此域。尚未向您收费。」</title>
      <link>https://dvel.me/posts/cloudflare-domain-transfer-something-went-wrong/</link>
      <pubDate>Sat, 22 Jan 2022 01:38:14 +0800</pubDate>
      <guid>https://dvel.me/posts/cloudflare-domain-transfer-something-went-wrong/</guid>
      <description>当 Cloudflare 转入域名提示「出现了问题。请重试转移此域。尚未向您收费。」时，可能是因为付款信息出现问题。提示 &amp;#34;Account specified does not exist&amp;#34; 时也可能是付款信息问题。</description>
      <content:encoded><![CDATA[<p>Cloudflare 转入域名时出现错误提示：</p>
<p>「出现了问题。」</p>
<p>「请重试转移此域。尚未向您收费。」</p>
<p>英文版的：</p>
<p>&ldquo;Something went wrong.&rdquo;</p>
<p>&ldquo;Please retry transferring this domain. You have not been charged.&rdquo;</p>
<img src="/img/2022-01-22-000157.webp" alt="Cloudflare 出现了问题" style="zoom:50%;" />
<p>可能是付款问题。</p>
<p>提示的信息过于宽泛了没有想到是这个问题，也不知道其实 Cloudflare 会在这一步直接收取费用，应该提示「付款方式出现了问题」才对。</p>
<p>我 Cloudflare 一直都在用免费套餐，没想着会付款，忘记了之前有一次将它从 PayPal 的「自动付款」选项中删除了。</p>
<p>在 Cloudflare 「控制台 - 管理账户 - 账单」中重新添加或编辑一下，再绑定上 PayPal 就好了。</p>
<img src="/img/2022-01-22-000158.webp" alt="Cloudflare 域名正在转移" style="zoom:50%;" />
<hr>
<p>提示 &ldquo;Account specified does not exist&rdquo; 时也可能是付款信息问题，比如未添加付款方式。</p>
]]></content:encoded>
    </item>
    <item>
      <title>图片压缩：Squoosh、TinyPNG、ImageOptim、WebP</title>
      <link>https://dvel.me/posts/compression-image-squoosh-tinypng-webp/</link>
      <pubDate>Fri, 21 Jan 2022 18:39:40 +0800</pubDate>
      <guid>https://dvel.me/posts/compression-image-squoosh-tinypng-webp/</guid>
      <description>本文介绍了四种图片压缩的方法：Squoosh、TinyPNG、ImageOptim、WebP。</description>
      <content:encoded><![CDATA[<p>一些方便的图片压缩方法：</p>
<ul>
<li>
<p>用 Squoosh 进行格式转换、压缩。</p>
</li>
<li>
<p>用 TinyPNG 对 JPEG、PNG、WebP 的压缩。</p>
</li>
<li>
<p>用 ImageOptim 进行本地的 JPEG、PNG 压缩。</p>
</li>
<li>
<p>用 Google 的 WebP CLI 工具转换为 WebP。（速度最快，推荐）</p>
</li>
</ul>
<h2 id="squoosh">Squoosh</h2>
<p>可以直接在浏览器打开 <a href="https://squoosh.app/" target="_blank" rel="noopener">https://squoosh.app/</a> 进行压缩，支持即时预览、格式转换和很多参数调节。</p>
<p>也可以用 Squoosh 的 CLI 在本地压缩或转换。</p>
<h2 id="tinypng">TinyPNG</h2>
<p>支持 JPEG、PNG、WebP，压缩效果和 Squoosh 差不太多，但是速度快了很多。</p>
<p>可以直接在浏览器打开 <a href="https://tinypng.com/" target="_blank" rel="noopener">https://tinypng.com/</a> 上传 - 压缩 - 下载。</p>
<p>点击导航栏的 <a href="https://tinypng.com/third-party" target="_blank" rel="noopener">THIRD-PARTY</a>，下面也有一些第三方的客户端，比如这个 <a href="https://github.com/kyleduo" target="_blank" rel="noopener">kyleduo</a>/<strong><a href="https://github.com/kyleduo/TinyPNG4Mac" target="_blank" rel="noopener">TinyPNG4Mac</a></strong> 就不错。</p>
<h2 id="compress-pngjpg">Compress PNG/JPG</h2>
<p><a href="https://www.websiteplanet.com/zh-hans/webtools/imagecompressor/" target="_blank" rel="noopener">https://www.websiteplanet.com/zh-hans/webtools/imagecompressor/</a></p>
<p>免费又方便的线上工具，可选三种压缩模式。</p>
<h2 id="imageoptim">ImageOptim</h2>
<p><a href="https://imageoptim.com/" target="_blank" rel="noopener">https://imageoptim.com/</a></p>
<p>ImageOptim 也超棒，提供了 Windows/macOS/Linux 客户端，完全本地操作，但是不支持 WebP。</p>
<h2 id="webp">WebP</h2>
<p>WebP 是 Google 于 2010 年 09 月 30 日推出的，同时提供了有损压缩与无损压缩（可逆压缩）的图片文件格式。WebP 的设计目标是在减少文件大小的同时，达到和 JPEG、PNG、GIF 格式相同的图片质量。压缩率很高，10M 的 PNG 图片转换成 WebP 只需要大约 1~2M，而肉眼几乎不可分辨的有损压缩能压到 500KB 左右。</p>
<p>主流浏览器均已支持，2020 年 9 月 Safari 14 也已支持。。。</p>
<p>可在 <a href="https://developers.google.com/speed/webp/" target="_blank" rel="noopener">https://developers.google.com/speed/webp/</a> 上下载。</p>
<p>macOS 用户可以直接使用 Homebrew 安装，安装完成后即可使用 <code>cwebp</code>、<code>dwebp</code> 、<code>gif2webp</code> 等命令：</p>
<ul>
<li><code>cwebp</code>：转换/压缩到 WebP</li>
<li><code>dwebp</code>： 将 WebP 转回 PNG</li>
<li><code>gif2webp</code>： GIF 转 WebP</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ brew install webp
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">$ cwebp <span class="o">[</span>options<span class="o">]</span> -q quality input.png -o output.webp
</span></span><span class="line"><span class="cl">$ dwebp in_file <span class="o">[</span>options<span class="o">]</span> <span class="o">[</span>-o out_file<span class="o">]</span>
</span></span><span class="line"><span class="cl">$ gif2webp <span class="o">[</span>options<span class="o">]</span> gif_file -o webp_file
</span></span></code></pre></div><hr>
<p>默认的压缩率是 75%：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ cwebp input_file.png -o output_file.webp
</span></span></code></pre></div><p>可以使用 <code>-q</code> 参数调整压缩质量：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ cwebp -q <span class="m">100</span> input_file.png -o output_file.webp
</span></span></code></pre></div><p>限定大小（bytes）的有损压缩：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ cwebp -size <span class="m">102400</span> input_file.png -o output_file.webp
</span></span></code></pre></div><hr>
<p>WebP 转回 PNG：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ dwebp in_file <span class="o">[</span>options<span class="o">]</span> <span class="o">[</span>-o out_file<span class="o">]</span>
</span></span></code></pre></div><hr>
<p>还有一个 <code>gif2webp</code> 命令，由于 macOS 目前还不支持预览动态 WebP 图片，本地不能直接看到很费劲（只能看到第一帧），动图依然在用 GIF。</p>
<hr>
<p>也可以写个小脚本，放进 Alfred 里，用起来很方便：</p>
<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">sys</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></span><span class="line"><span class="cl"><span class="n">q</span> <span class="o">=</span> <span class="mi">75</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">file</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</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">dirname</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">dirname</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">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">splitext</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">basename</span><span class="p">(</span><span class="n">file</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">file</span> <span class="o">=</span> <span class="n">file</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;</span><span class="se">\\</span><span class="s1"> &#39;</span><span class="p">,)</span>
</span></span><span class="line"><span class="cl">    <span class="n">filename</span> <span class="o">=</span> <span class="n">filename</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;</span><span class="se">\\</span><span class="s1"> &#39;</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="sa">f</span><span class="s1">&#39;cwebp -q </span><span class="si">{</span><span class="n">q</span><span class="si">}</span><span class="s1"> </span><span class="si">{</span><span class="n">file</span><span class="si">}</span><span class="s1"> -o </span><span class="si">{</span><span class="n">dirname</span><span class="si">}</span><span class="s1">/</span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s1">.webp&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;&#34;</span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s1">.webp&#34; done.</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span></code></pre></div><p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-05-23.gif"
            alt="2022-01-23"
            width="800"
            height="596"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>GUI 找到一个 <a href="https://github.com/iSparta/iSparta" target="_blank" rel="noopener">isparta</a>，但是两年多没更新了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>macOS grep &#43; sed 批量替换多个文件的内容</title>
      <link>https://dvel.me/posts/macos-replace-contents-multiple-files/</link>
      <pubDate>Fri, 14 Jan 2022 00:14:27 +0800</pubDate>
      <guid>https://dvel.me/posts/macos-replace-contents-multiple-files/</guid>
      <description>本文介绍如何使用 grep &#43; sed 命令进行批量替换多个文件的内容，使用 -i 选项在文件内编辑替换，同时使用 -l 和 --null 选项，使其能够处理有空格的路径。通过区分大小写或大小写不敏感的方式进行替换，实现快捷的替换需求。</description>
      <content:encoded><![CDATA[<p>偶尔的替换用 VSCode 或 JetBrains IDE 的类似 Cmd + Shift + H 的文件替换就可以了。</p>
<p>经常或快捷的使用，可以用 <code>grep</code> + <code>sed</code> 命令进行替换。</p>
<br>
<p>搜索试了几个命令，发现有空格的路径会导致一些错误。</p>
<p>一顿搜索，找到了一个解决办法，参考 <a href="https://unix.stackexchange.com/questions/297006/grep-word-within-a-file-then-copy-the-file" target="_blank" rel="noopener">Grep word within a file then copy the file</a>：</p>
<ul>
<li><code>--null</code> 告诉 <code>grep</code> 以 NUL 字符分割文件名</li>
<li><code>-0</code> 告诉 <code>sed</code> 以 NUL 分割输入</li>
</ul>
<br>
<p>最终命令示例，以 <code>bar</code> 替换 <code>foo</code>。</p>
<p>区分大小写：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ grep -lr --null <span class="s1">&#39;foo&#39;</span> * <span class="p">|</span> xargs -0 sed -i <span class="s1">&#39;&#39;</span> <span class="s1">&#39;s/foo/bar/g&#39;</span>
</span></span></code></pre></div><p>不区分大小写：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ grep -ilr --null <span class="s1">&#39;foo&#39;</span> * <span class="p">|</span> xargs -0 sed -i <span class="s1">&#39;&#39;</span> <span class="s1">&#39;s/foo/bar/gI&#39;</span>
</span></span></code></pre></div><br>
<ul>
<li><code>grep</code>
<ul>
<li><code>-i, --ignore-case</code> 查找文件时不区分大小写</li>
<li><code>-l, --files-with-matches</code> 返回文件名</li>
<li><code>-R, -r, --recursive</code>  递归搜索子目录</li>
</ul>
</li>
<li><code>sed</code>
<ul>
<li><code>-i</code> 默认 <code>sed</code> 会打印到标准输出，使用 <code>-i</code> 将直接在文件内编辑替换</li>
<li><code>s</code> 替换</li>
<li><code>g</code> 全局替换标志</li>
<li><code>I</code> 大小写不敏感标志</li>
</ul>
</li>
</ul>
<hr>
<p>示例。</p>
<p>替换需求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gd">- ![](/img/xxx.webp)
</span></span></span><span class="line"><span class="cl"><span class="gd"></span><span class="gi">+ ![](https://example.com/img/xxx.webp)
</span></span></span></code></pre></div><p>可能有需要转义的：</p>
<pre tabindex="0"><code>查找的字符串、替换的内容：
](/img
](https://example.com/img

转义后：
](\/img
https:\/\/example.com\/img
</code></pre><p>将转义后的内容代入就可以了，完整的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ grep -lr --null <span class="s1">&#39;](\/img&#39;</span> <span class="p">|</span> xargs -0 sed -i <span class="s1">&#39;&#39;</span> <span class="s1">&#39;s/](\/img/](https:\/\/example.com\/img/g&#39;</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>在 macOS 根目录创建文件夹</title>
      <link>https://dvel.me/posts/macos-create-root-dir/</link>
      <pubDate>Thu, 13 Jan 2022 22:43:02 +0800</pubDate>
      <guid>https://dvel.me/posts/macos-create-root-dir/</guid>
      <description>本文介绍在 macOS 中如何在根目录创建文件夹的方法，通过关闭 SIP 或使用 synthetic.conf 文件来创建虚拟链接，实现在根目录创建文件夹的目的。同时也提到了 Tab 写成空格的解决办法。</description>
      <content:encoded><![CDATA[<p>可能有一些无法更改源码的老项目或智障项目会使用根目录来搞事情，但现在默认已经不支持对根目录进行修改了。</p>
<h2 id="macos-1015-catalina">macOS 10.15 Catalina</h2>
<p>在恢复模式关闭 SIP：</p>
<ol>
<li>重启并按住 Cmd + R 进入恢复模式</li>
<li>菜单栏 - 实用工具 - 终端</li>
<li>输入命令 <code>csrutil disable</code></li>
<li>重启</li>
</ol>
<p>后接着执行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ sudo mount -uw /
</span></span></code></pre></div><p>重启后就可以在根目录创建文件夹了。</p>
<h2 id="macos-11-big-sur-和-macos-12-monterey">macOS 11 Big Sur 和 macOS 12 Monterey</h2>
<p>不需要关闭 SIP。</p>
<p>直接对根目录进行软链接会报错：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ ln -s /Users/dvel/foo/bar /bar
</span></span><span class="line"><span class="cl">ln: /bar: Read-only file system
</span></span></code></pre></div><p>现在根目录是只读的，但可以使用 <code>synthetic.conf</code> 文件来创建一个虚拟链接连接到数据盘，类似 <code>ln -s</code> 的软链接。</p>
<hr>
<p>假设要在根目录创建 <code>abc</code> 文件夹。</p>
<p>编辑或创建 <code>synthetic.conf</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ sudo vim /etc/synthetic.conf
</span></span></code></pre></div><p>输入内容（<strong>中间是 <mark>Tab</mark>，不是空格，切勿敲错</strong>）：</p>
<pre tabindex="0"><code>abc	/Users/dvel/abc
</code></pre><p>第一个是要创建的文件夹名，第二个是要链接到的现有路径。</p>
<p>保存后重启即可。</p>
<p>示例，创建后的文件夹：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-13A.webp"
            alt="在根目录创建文件夹"
            width="1348"
            height="990"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="tab-写成空格的解决办法">Tab 写成空格的解决办法</h2>
<p>如果写成了空格，会导致频繁重启，无法进入系统。</p>
<p>进入恢复模式，打开终端输入命令来挂载磁盘后删除 <code>/etc/synthetic.conf</code> 文件：：</p>
<pre tabindex="0"><code>$ diskutil apfs unlock &#34;Macintosh HD - Data&#34;
$ cd /Volumes/&#34;Macintosh HD - Data&#34;
$ cd private/etc
$ rm synthetic.conf
</code></pre><p>重启即可。</p>
<h2 id="参考">参考</h2>
<p><a href="https://stackoverflow.com/questions/58396821/what-is-the-proper-way-to-create-a-root-sym-link-in-catalina" target="_blank" rel="noopener">What is the proper way to create a root sym link in Catalina</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>博客图床小妙招</title>
      <link>https://dvel.me/posts/blog-image-host-coup/</link>
      <pubDate>Wed, 12 Jan 2022 21:57:00 +0800</pubDate>
      <guid>https://dvel.me/posts/blog-image-host-coup/</guid>
      <description>本文介绍如何在使用 Cloudflare Pages 或 GitHub Pages 等服务搭建的博客中实现本地 Typora 直接看图，并且提交部署后在网站也能直接看到图的小妙招。通过在 macOS 根目录创建文件夹，使用 Markdown 写法和 Typora 贴图等方法，使图床更加便捷易用。</description>
      <content:encoded><![CDATA[<p>不想单弄个图床了，Pages 又不花钱。</p>
<p>我是用在 Cloudflare Pages 或 GitHub Pages 等服务搭建的博客。</p>
<p>macOS 环境。</p>
<p>我想实现的样子：</p>
<ul>
<li>本地 Typora 能直接看图</li>
<li>不修改图片路径就 push</li>
<li>提交部署后，在网站也能直接看到图</li>
</ul>
<h2 id="markdown-写法">Markdown 写法</h2>
<p>Hugo 的 <code>static/</code> 目录中的内容会自动放到网站根目录。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">![](/img/xxx.webp)
</span></span></code></pre></div><p>但是这样只能在网站上显示。</p>
<p>只要在本机电脑上的根目录创建相同的 <code>/img/</code> 文件夹就可以了。</p>
<h2 id="在-macos-根目录创建文件夹">在 macOS 根目录创建文件夹</h2>
<p>详细的 <a href="/posts/macos-create-root-dir/">在 macOS 根目录创建文件夹</a>，以下是 Big Sur 和 Monterey 的方法。</p>
<p>编辑 <code>synthetic.conf</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ sudo vim /etc/synthetic.conf
</span></span></code></pre></div><p>输入内容（<strong>中间是 <mark>Tab</mark>，不是空格</strong>）：</p>
<pre tabindex="0"><code>img	/Users/dvel/Dropbox/hugo/static/img
</code></pre><p>重启后就能看到根目录有了。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-13A.webp"
            alt="在根目录创建文件夹"
            width="1348"
            height="990"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>大功告成了，使用 <code>![](/img/xxx.webp)</code> 同时支持本地和网站看图。</p>
<h2 id="typora-贴图">Typora 贴图</h2>
<p>设置好，直接把图片粘贴到 Typora 就能得到正确路径了。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-12-3379760.webp"
            alt="Typora 图像设置"
            width="1664"
            height="1184"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>删除也方便，不用找到文件夹，在 Typora 里右键删除文件就可以了。</p>
<h2 id="其他设备">其他设备</h2>
<p>缺点就是没有发布的博文和笔记只能在自己的电脑上看图，如果经常用手机或别的电脑看的话</p>
<p>只能修改成完整的路径如 <code>![](https://example.com/img/xxx.webp)</code> 才可以。</p>
<p>有多设备观看需求的，可以用一个小命令快速快捷地进行替换。</p>
<p>详细：<a href="/posts/macos-replace-contents-multiple-files/">macOS 批量替换多个文件的内容</a></p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ grep -lr --null <span class="s1">&#39;](\/img&#39;</span> <span class="p">|</span> xargs -0 sed -i <span class="s1">&#39;&#39;</span> <span class="s1">&#39;s/](\/img/](https:\/\/example.com\/img/g&#39;</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>折腾 Hugo &amp; PaperMod 主题</title>
      <link>https://dvel.me/posts/hugo-papermod-config/</link>
      <pubDate>Tue, 11 Jan 2022 15:15:38 +0800</pubDate>
      <guid>https://dvel.me/posts/hugo-papermod-config/</guid>
      <description>探讨使用 Hugo 的 PaperMod 主题进行博客搭建，分享优化过程及样式定制。包含主题导入、HTML lang 配置、悬浮目录、文章链接新标签打开、本地图片累计布局偏移（CLS）修复、最后更新时间设置、评论功能、浏览量统计、代码高亮等内容。</description>
      <content:encoded><![CDATA[<p>无意浏览了一下 Hugo 官网的主题目录，发现了一个简约风格的 <a href="https://github.com/nanxiaobei/hugo-paper" target="_blank" rel="noopener">Paper</a> 主题，非常喜欢，第二天发现了一个 <a href="https://github.com/adityatelange/hugo-PaperMod" target="_blank" rel="noopener">PaperMod</a>，差不多算是增强版。</p>
<p>之前就没遇到过心爱的主题，一直将就着，好多功能也没有弄，这两天一顿折腾，记录一下折腾经过。</p>
<p>使用的版本是 <code>hugo-PaperMod-7.0</code>。</p>
<h2 id="开始">开始</h2>
<p>更新 Hugo，新建站点，导入 PaperMod 主题。</p>
<p>示例配置在另一个分支里，导入 PaperMod 演示站的 <code>config.yml</code>。</p>
<p>配置时可以参考着 Hugo 官方文档的 <a href="https://gohugo.io/getting-started/configuration/" target="_blank" rel="noopener">Configure Hugo</a>。</p>
<p>另外要看看 <a href="https://github.com/adityatelange/hugo-PaperMod/wiki/Variables" target="_blank" rel="noopener">PaperMod Wiki</a>，PaperMod 的示例文件里好多参数都没写，比如这些参数很好用：</p>
<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="c"># ...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">DateFormat</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;2006-01-02&#34;</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="nt">ShowFullTextinRSS</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">   </span><span class="c"># RSS 输出全文</span><span class="w">
</span></span></span></code></pre></div><h2 id="html-lang">HTML lang</h2>
<p>单语言的站点可以直接设置 <code>languageCode</code> 并在 <code>baseof.html</code> 修改为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gd">- &lt;html lang=&#34;{{ .Site.Language }}&#34; dir=&#34;{{ .Language.LanguageDirection | default &#34;auto&#34; }}&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="gd"></span><span class="gi">+ &lt;html lang=&#34;{{ .Site.LanguageCode }}&#34;&gt;
</span></span></span></code></pre></div><h2 id="papermod-的悬浮目录">PaperMod 的悬浮目录</h2>
<p>参考一：<a href="https://www.sulvblog.cn/posts/blog/hugo_toc_side/" target="_blank" rel="noopener">Hugo博客目录放在侧边 | PaperMod主题 | Sulv&rsquo;s Blog</a></p>
<p>参考二：<a href="https://github.com/JannikArndt/jannikarndt.github.io/commit/8b99f6cbc61c6b4f0238c592d5315cefe07c0599" target="_blank" rel="noopener">JannikArndt/jannikarndt.github.io@<code>8b99f6c</code></a></p>
<h2 id="设置文章中链接以新标签的方式打开">设置文章中链接以新标签的方式打开</h2>
<p>参考：<a href="/posts/hugo-goldmark-markdown-new-tab/">在 Hugo Goldmark Markdown 中设置以新标签打开链接</a></p>
<h2 id="修复本地图片的累计布局偏移cls问题">修复本地图片的累计布局偏移（CLS）问题</h2>
<p>参考：<a href="/posts/fix-hugo-cls/">修复 Hugo 本地图片的累计布局偏移（CLS）问题</a></p>
<h2 id="最后更新时间">最后更新时间</h2>
<p>看到一篇 <a href="https://www.jacksonlucky.net/posts/use-lastmod-with-papermod/" target="_blank" rel="noopener">Use Lastmod with PaperMod</a>，这个可以和 Git 搭配，不过我希望可以手动输入。</p>
<p>在 PaperMod 的 <code>post_meta.html</code> 中加上三行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- if gt .Lastmod .Date -}}
</span></span><span class="line"><span class="cl">{{- $scratch.Add &#34;meta&#34; (slice (printf &#34;<span class="p">&lt;</span><span class="nt">span</span> <span class="na">title</span><span class="o">=</span><span class="s">&#39;%s&#39;</span><span class="p">&gt;</span>(updated: %s)<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>&#34; (.Lastmod) (.Lastmod | time.Format (default &#34;January 2, 2006&#34; .Site.Params.DateFormat)))) }}
</span></span><span class="line"><span class="cl">{{- end }}
</span></span></code></pre></div><p>在 Hugo 的 Front Matter 下手动加上 <code>lastmod</code> 属性即可：</p>
<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">折腾 Hugo &amp; PaperMod 主题</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">slug</span><span class="p">:</span><span class="w"> </span><span class="l">hugo-papermod-config</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">Dvel</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">2022-01-11T15:15:38</span><span class="m">+08</span><span class="p">:</span><span class="m">00</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">lastmod</span><span class="p">:</span><span class="w"> </span><span class="ld">2023-02-14T00:40:08</span><span class="m">+08</span><span class="p">:</span><span class="m">00</span><span class="w">
</span></span></span></code></pre></div><h2 id="评论功能">评论功能</h2>
<p>试用了一下 Disqus，但是界面好杂乱，就换到了 Waline。</p>
<p>官方教程非常详尽，就是配置麻烦点，不能像 Disqus 那样一键搞定。</p>
<p>部署在了 Vercel，按照 <a href="https://www.vercel-status.com/incidents/r758bhbklgfd" target="_blank" rel="noopener">Errors Accessing From China</a> 将 CANME 记录修改成官方推荐的地址 <code>cname-china.vercel-dns.com</code>。（现在那个页面访问不了了，不知道是否还推荐这个。）</p>
<p>适配 Waline 的黑暗模式，在 PaperMod 中以 <code>body.dark</code> 作为选择器：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* # Waline 黑暗模式 */</span>
</span></span><span class="line"><span class="cl"><span class="nt">body</span><span class="p">.</span><span class="nc">dark</span> <span class="p">{</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 class="nv">--waline-white</span><span class="p">:</span> <span class="mh">#000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-light-grey</span><span class="p">:</span> <span class="mh">#666</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-dark-grey</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</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="nv">--waline-color</span><span class="p">:</span> <span class="mh">#888</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-bgcolor</span><span class="p">:</span> <span class="mh">#1e1e1e</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-bgcolor-light</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-border-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="nv">--waline-disable-bgcolor</span><span class="p">:</span> <span class="mh">#444</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-disable-color</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</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="nv">--waline-bq-color</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</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="nv">--waline-info-bgcolor</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--waline-info-color</span><span class="p">:</span> <span class="mh">#666</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="浏览量统计">浏览量统计</h2>
<p>不蒜子的：</p>
<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">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">总浏览量：<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="na">id</span><span class="o">=</span><span class="s">&#34;busuanzi_value_page_pv&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Waline 的：</p>
<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">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;waline-visitor-count&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;{{ .RelPermalink }}&#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">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;waline-pageview-count&#34;</span> <span class="na">data-path</span><span class="o">=</span><span class="s">&#34;{{ .RelPermalink }}&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><h2 id="代码高亮">代码高亮</h2>
<p>Hugo 自带的配色方案是 Chroma，但 PaperMod 用的 highlight.js，用 Chroma 时样式有点问题。</p>
<p>设置 <code>disableHLJS: false</code> 选择 highlight.js 作为高亮方案。</p>
<p>自定义的话，由于 PaperMod 是读取写死了的文件名：</p>
<ul>
<li><code>assets/js/highlight.min.js</code></li>
<li><code>assets/css/hljs/an-old-hope.min.css</code></li>
</ul>
<p>我是直接从 <a href="https://highlightjs.org/download/" target="_blank" rel="noopener">highlight.js</a> 下载最新版的 JS 和 CSS 文件，不修改文件名，直接替换掉里面的内容。</p>
<p>PaperMod 的代码块背景颜色是写死了的，可以在 <code>blank.css</code> 中设定代码块在博客为亮/暗色主题时不同的背景色。</p>
<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">--hljs-bg</span><span class="p">:</span> <span class="mh">#282C34</span><span class="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></span><span class="line"><span class="cl">    <span class="nv">--hljs-bg</span><span class="p">:</span> <span class="mh">#272b33</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="sri">SRI</h2>
<p>今天发现了 SRI（完整性检查）的问题，浏览器提示「Failed to find a valid digest in the &lsquo;integrity&rsquo; attribute for resource &hellip;」，导致语法高亮失效了。</p>
<p>搜索后发现是因为 Hugo 的「minify」与 Cloudflare 的「Auto Minify」发生了冲突，Cloudflare 在再次压缩后导致文件哈希值改变，校验失败。</p>
<p>解决办法是要么关闭 SRI，要么取消 Cloudflare 的「Auto Minify」。</p>
<p>Cloudflare 关闭的方法：速度 - 优化 - Auto Minify。</p>
<p>在 Hugo 中关闭的方法：</p>
<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 class="w">
</span></span></span></code></pre></div><h2 id="markdown-渲染风格">Markdown 渲染风格</h2>
<p>自定义了一些渲染风格，参考了一点 <a href="https://simplecss.org/" target="_blank" rel="noopener">Simple.css</a> 和 GitHub。</p>
<p>由于习惯了在 Typora 的 H2 标题前打一个空行，标准 Markdown 都不会渲染空行，所以直接增加上边距了。</p>
<p>PaperMod 的表格有点空洞，用了 GitHub 那种样式的表格：</p>
<table>
  <thead>
      <tr>
          <th>样式</th>
          <th>体验</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PaperMod</td>
          <td>有点空洞</td>
      </tr>
      <tr>
          <td>GitHub</td>
          <td>感觉刚刚好</td>
      </tr>
  </tbody>
</table>
<p>和一些杂七杂八的调整。</p>
<p>在 <code>blank.css</code> 中新增自定义样式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* # Markdown 风格 */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* 标题、正文、行内代码 - 颜色 */</span>
</span></span><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">--primary</span><span class="p">:</span> <span class="mh">#212121</span><span class="p">;</span>  <span class="c">/* rgb(30, 30, 30); */</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--content</span><span class="p">:</span> <span class="mh">#333333</span><span class="p">;</span>  <span class="c">/* rgb(31, 31, 31); */</span>
</span></span><span class="line"><span class="cl">    <span class="nv">--code-bg</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">175</span><span class="p">,</span> <span class="mi">184</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">);</span> <span class="c">/* rgb(245, 245, 245); */</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></span><span class="line"><span class="cl">    <span class="nv">--code-bg</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">175</span><span class="p">,</span> <span class="mi">184</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">);</span> <span class="c">/* rgb(55, 56, 62); */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* 链接样式 */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</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="mh">#0969da</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="kc">none</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">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 class="nc">post-content</span> <span class="nt">a</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">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="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* 行内代码 - 左右间距 */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">code</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</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 class="c">/* 代码块 - 最大高度 */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* .post-content pre code {
</span></span></span><span class="line"><span class="cl"><span class="c">    max-height: 40rem;
</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 class="p">.</span><span class="nc">post-content</span> <span class="nt">img</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</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><span class="line"><span class="cl"><span class="c">/* 行文风格 */</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-family</span><span class="p">:</span> <span class="o">-</span><span class="n">apple-system</span><span class="p">,</span> <span class="n">BlinkMacSystemFont</span><span class="p">,</span> <span class="s2">&#34;Avenir Next&#34;</span><span class="p">,</span> <span class="n">Avenir</span><span class="p">,</span> <span class="s2">&#34;Nimbus Sans L&#34;</span><span class="p">,</span> <span class="n">Roboto</span><span class="p">,</span> <span class="n">Noto</span><span class="p">,</span> <span class="s2">&#34;Segoe UI&#34;</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="s2">&#34;Helvetica Neue&#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">1</span><span class="kt">rem</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="mf">1.5</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 class="p">.</span><span class="nc">post-content</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">1</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="nc">post-content</span> <span class="nt">blockquote</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">#808080</span><span class="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">post-content</span> <span class="nt">p</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">blockquote</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">figure</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></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mf">1.15</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="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">hr</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">4</span><span class="kt">rem</span> <span class="mi">8</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="nc">post-content</span> <span class="nt">ul</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">ol</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">dl</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">li</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mf">0.5</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="p">}</span>
</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="o">,</span>
</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="o">,</span>
</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="o">,</span>
</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="o">,</span>
</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="o">,</span>
</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">margin-bottom</span><span class="p">:</span> <span class="mf">1.15</span><span class="kt">rem</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="p">}</span>
</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">font-size</span><span class="p">:</span> <span class="mf">2.6</span><span class="kt">rem</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">4</span><span class="kt">rem</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="mh">#ccc</span><span class="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">post-content</span> <span class="nt">h2</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.8</span><span class="kt">rem</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">4</span><span class="kt">rem</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="mh">#ccc</span><span class="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">post-content</span> <span class="nt">h3</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.6</span><span class="kt">rem</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">2</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="nc">post-content</span> <span class="nt">h4</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.4</span><span class="kt">rem</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="mf">1.44</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="nc">post-content</span> <span class="nt">h5</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.2</span><span class="kt">rem</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="mf">1.15</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="nc">post-content</span> <span class="nt">h6</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">1</span><span class="kt">rem</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 class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* GitHub 样式的表格 */</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="nt">tr</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="mh">#979da3</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 class="nc">post-content</span> <span class="nt">table</span> <span class="nt">tr</span><span class="p">:</span><span class="nd">nth-child</span><span class="o">(</span><span class="nt">2n</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">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="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">code</span><span class="o">-</span><span class="n">bg</span><span class="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">post-content</span> <span class="nt">table</span> <span class="nt">th</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="mh">#979da3</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 class="nc">post-content</span> <span class="nt">table</span> <span class="nt">td</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="mh">#979da3</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>]]></content:encoded>
    </item>
    <item>
      <title>利用 Cloudflare Workers 进行批量 301 重定向</title>
      <link>https://dvel.me/posts/cloudflare-workers-redirect/</link>
      <pubDate>Sun, 09 Jan 2022 23:06:41 +0800</pubDate>
      <guid>https://dvel.me/posts/cloudflare-workers-redirect/</guid>
      <description>Cloudflare Workers 可以用来实现个性化的 URL 重定向。本文将介绍如何在 Cloudflare 中创建一个 Worker 并进行简单的重定向操作。同时，作者还提供了一些扩展的应用场景和示例供读者参考。</description>
      <content:encoded><![CDATA[<p>在 Cloudflare 的「网站 - 规则 - 页面规则」中可以设置 URL 转发，免费默认可以使用 3 个规则，可以进行简单的通配符转换，如果这个能满足需求那最好了。</p>
<p>如下：将带 www 的网址 301 重定向到不带 www 的。</p>
<table>
  <thead>
      <tr>
          <th>匹配 URL</th>
          <th>转发 URL</th>
          <th>重定向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>www.dvel.me/*</code></td>
          <td><code>https://dvel.me/$1</code></td>
          <td>301</td>
      </tr>
  </tbody>
</table>
<p>但是很多时候需要更复杂的 URL 转发，比如个人博客瞎折腾，网站的后缀甚至域名来回改，无法仅仅通过通配符做到全部的 301 重定向，这时候还得用 Workers。</p>
<h2 id="update批量重定向">Update：批量重定向</h2>
<p>今天打开 Cloudflare 一看，出了个「批量重定向 Beta」。。。</p>
<p>但是免费版限制了 5 个列表，每个列表 20 个，如果量小的话建议用用这个，量大的用 Workers。</p>
<h2 id="创建一个-worker">创建一个 Worker</h2>
<p>创建后选择「资源 - 快速编辑」，默认代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><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="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span 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">// 返回一个只包含&#34;Hello world&#34;的响应
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</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="nx">Response</span><span class="p">(</span><span class="s2">&#34;Hello world&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>点击「发送」即可测试：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-09A.webp"
            alt="Cloudflare Workers"
            width="2250"
            height="580"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="301-一个-url-试试">301 一个 URL 试试</h2>
<p>将上面代码改为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span 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">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <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">redirect</span><span class="p">(</span><span class="s2">&#34;https://www.google.com&#34;</span><span class="p">,</span> <span class="mi">301</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>再点击「发送」进行测试：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-09B.webp"
            alt="Cloudflare Workers"
            width="2202"
            height="472"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>再在「触发器 - 路由 - 添加路由」中添加一个 URL 进行测试 <code>dvel.me/test</code>：</p>
<p>然后在浏览器中进行访问此网址，发现这个 URL 已经成功 301 到 Google 了。</p>
<p>大致的做法就是这样，批量重定向只需要将路由改为 <code>dvel.me/*</code>，再将需要跳转的新老 URL 在代码中处理即可。</p>
<h2 id="官方示例">官方示例</h2>
<p>在上图点击右上角的「示例」，可以找到<a href="https://developers.cloudflare.com/workers/examples/redirect" target="_blank" rel="noopener">两个 Redirect 的示例</a>。</p>
<p>第一个示例将所有的请求重定向到一个 URL：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Redirect all requests to one URL
</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">destinationURL</span> <span class="o">=</span> <span class="s2">&#34;https://example.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">statusCode</span> <span class="o">=</span> <span class="mi">301</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <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">redirect</span><span class="p">(</span><span class="nx">destinationURL</span><span class="p">,</span> <span class="nx">statusCode</span><span 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">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#34;</span><span class="p">,</span> <span class="kr">async</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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>第二个示例是仅域名互换，保留后面的 path。即 <code>foo.com/a?b=c</code> 转 <code>bar.com/a?b=c</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Redirect requests from one domain to another
</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">base</span> <span class="o">=</span> <span class="s2">&#34;https://example.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">statusCode</span> <span class="o">=</span> <span class="mi">301</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</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">url</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">URL</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">pathname</span><span class="p">,</span> <span class="nx">search</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">url</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">destinationURL</span> <span class="o">=</span> <span class="nx">base</span> <span class="o">+</span> <span class="nx">pathname</span> <span class="o">+</span> <span class="nx">search</span>
</span></span><span class="line"><span class="cl">
</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">redirect</span><span class="p">(</span><span class="nx">destinationURL</span><span class="p">,</span> <span class="nx">statusCode</span><span 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">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#34;</span><span class="p">,</span> <span class="kr">async</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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>这两个完全没必要，因为用「页面规则」的「URL 转发」就可以完成了，除非你 3 个免费的规则都用完了。</p>
<h2 id="手写更通用的转换">手写更通用的转换</h2>
<p>一个简单的示例：如果访问的地址和 <code>old_url</code> 撞上了，则返回 <code>new_url</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span 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">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</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">old_url</span> <span class="o">=</span> <span class="s2">&#34;https://dvel.xyz/posts/1234/&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">new_url</span> <span class="o">=</span> <span class="s2">&#34;https://dvel.me/posts/ba-la-ba-la/&#34;</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">request</span><span class="p">.</span><span class="nx">url</span> <span class="o">===</span> <span class="nx">old_url</span><span class="p">)</span> <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">redirect</span><span class="p">(</span><span class="nx">new_url</span><span class="p">,</span> <span class="mi">301</span><span 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="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="p">}</span>
</span></span></code></pre></div><h2 id="完整版同一个域名下跳转">完整版（同一个域名下跳转）</h2>
<p>效果：只重定向当前域名下指定的路径。以后要是修改路径了就在这更新一下。</p>
<table>
  <thead>
      <tr>
          <th>旧地址</th>
          <th>新地址</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>dvel.me/posts/1234/</code></td>
          <td><code>dvel.me/posts/ba-la-ba-la/</code></td>
      </tr>
  </tbody>
</table>
<p>添加触发器的路由：<code>dvel.me/*</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span 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">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</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">arr</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;https://dvel.me/posts/1234/ https://dvel.me/posts/ba-la-ba-la/&#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="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">old_url</span><span class="p">,</span> <span class="nx">new_url</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">u2</span> <span class="k">of</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="nx">old_url</span><span class="p">,</span> <span class="nx">new_url</span><span class="p">]</span> <span class="o">=</span> <span class="nx">u2</span><span class="p">.</span><span class="nx">split</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">if</span> <span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span> <span class="o">===</span> <span class="nx">old_url</span><span class="p">)</span> <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">redirect</span><span class="p">(</span><span class="nx">new_url</span><span class="p">,</span> <span class="mi">301</span><span class="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="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="p">}</span>
</span></span></code></pre></div><h3 id="cloudflare-pages-的重定向">Cloudflare Pages 的重定向</h3>
<p>如果在用 Cloudflare Pages 的话，用 Pages 的重定向更简单。</p>
<p>在构件目录创建 <code>_redirects</code> 文件（也就是 Hugo 的 <code>static</code> 目录），参考 <a href="https://developers.cloudflare.com/pages/platform/redirects" target="_blank" rel="noopener">Redirects</a> 文档创建规则，限制是 100 个。</p>
<h2 id="完整版域名-a-跳转域名-b">完整版（域名 A 跳转域名 B）</h2>
<p>效果：默认只转换域名，并保留后面的 path 和 search；后缀和域名都变了的，需要一个一个写进数组。</p>
<table>
  <thead>
      <tr>
          <th>旧地址</th>
          <th>新地址</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>dvel.xyz/posts/1234/</code></td>
          <td><code>dvel.me/posts/ba-la-ba-la/</code></td>
      </tr>
  </tbody>
</table>
<p>添加触发器的路由：<code>dvel.xyz/*</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;fetch&#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">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nx">handleRequest</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">request</span><span 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">async</span> <span class="kd">function</span> <span class="nx">handleRequest</span><span class="p">(</span><span class="nx">request</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">arr</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;https://dvel.xyz/posts/1234/ https://dvel.me/posts/ba-la-ba-la/&#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="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">old_url</span><span class="p">,</span> <span class="nx">new_url</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">u2</span> <span class="k">of</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="nx">old_url</span><span class="p">,</span> <span class="nx">new_url</span><span class="p">]</span> <span class="o">=</span> <span class="nx">u2</span><span class="p">.</span><span class="nx">split</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">if</span> <span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span> <span class="o">===</span> <span class="nx">old_url</span><span class="p">)</span> <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">redirect</span><span class="p">(</span><span class="nx">new_url</span><span class="p">,</span> <span class="mi">301</span><span class="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">base</span> <span class="o">=</span> <span class="s2">&#34;https://dvel.me&#34;</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">request</span><span class="p">.</span><span class="nx">url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">pathname</span><span class="p">,</span> <span class="nx">search</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">url</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">destinationURL</span> <span class="o">=</span> <span class="nx">base</span> <span class="o">+</span> <span class="nx">pathname</span> <span class="o">+</span> <span class="nx">search</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">redirect</span><span class="p">(</span><span class="nx">destinationURL</span><span class="p">,</span> <span class="mi">301</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>将博客部署在 Cloudflare Pages</title>
      <link>https://dvel.me/posts/deploy-blog-in-cloudflare-pages/</link>
      <pubDate>Sat, 08 Jan 2022 21:16:39 +0800</pubDate>
      <guid>https://dvel.me/posts/deploy-blog-in-cloudflare-pages/</guid>
      <description>将个人博客部署在 Cloudflare Pages，了解它的免费政策、特点和部署方法，以及一些可能会遇到的问题与解决方案。</description>
      <content:encoded><![CDATA[<h2 id="cloudflare-pages-的免费政策">Cloudflare Pages 的免费政策</h2>
<p>以下摘自 <a href="https://pages.cloudflare.com/" target="_blank" rel="noopener">Cloudflare Pages 首页</a> 和 <a href="https://developers.cloudflare.com/pages/platform/limits" target="_blank" rel="noopener">Cloudflare Pages 文档 - Limits</a>（里面有更详细的）。</p>
<ul>
<li>同一时间只能部署一个 Pages</li>
<li>每月 500 次提交</li>
<li>无限站点</li>
<li>无限请求</li>
<li>无限带宽</li>
<li>每个项目最多 10 个自定义域名</li>
<li>每个站点最多 20000 个文件</li>
<li>单个文件最大 25 MB</li>
</ul>
<p>总之对于个人博客来说是绰绰有余了。</p>
<p><del>实测每次部署大概是 2~3 分钟</del>，今天发现出了 <strong>Fast builds</strong> 功能，可以在设置中启用，在 2022-04-01 后将自动启用，新版的快速部署大约就 10 秒钟。</p>
<h2 id="特点">特点</h2>
<p>相比 GitHub Pages，可以直接从 GitHub 的私有仓库部署，GitHub Pages 却不能。</p>
<p>支持 Hugo、Hexo 等自动部署。</p>
<p>CDN 大陆效果一般，直连大约至少 <del>几百毫秒</del> 一千毫秒。</p>
<p>可以配合 Workers 等其他免费或付费功能完成多种类的 URL 转发。</p>
<p>另外 Cloudflare 的 DNS 支持裸域的 CNAME 与 MX 共存，自动搞定，这太方便了，之前 CloudXNS 至少还要自己手动操作一个其自定义的 LINK 类型及另一个域名作为跳板，Cloudflare 完全自动处理。我自己的的邮件用的也是裸域，在 Google Workspace，完全没有影响，收发件正常。</p>
<h2 id="部署">部署</h2>
<p>十分简单，现在也都有简体中文了，就照着提示给予 GitHub 仓库权限就可以了。</p>
<p>默认就自动响应 Git 的新提交来部署。</p>
<p>一种是直接将生成好的静态文件作为部署内容，一种是 Cloudflare 自动用 Hugo 等支持的系统做自动化部署。</p>
<p>没试过第二种，我选择前者，主要是保证和本地的一致性。</p>
<h2 id="重定向">重定向</h2>
<p>将带 www 的或不带 www 的也设定为自定义域名。</p>
<p>部署妥善后，可在「页面规则」中设定 www 与不带 www 的互相跳转，例如：</p>
<table>
  <thead>
      <tr>
          <th>匹配 URL</th>
          <th>转发 URL</th>
          <th>重定向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>www.dvel.me/*</code></td>
          <td><code>https://dvel.me/$1</code></td>
          <td>301</td>
      </tr>
  </tbody>
</table>
<p>会自动将带 www 的地址 301 重定向到裸域，免费用户可以使用最多三个规则。</p>
<p>其他重定向可参考：<a href="/posts/cloudflare-workers-redirect/">利用 Cloudflare Workers 进行批量 301 重定向</a></p>
<h2 id="sri">SRI</h2>
<p>今天发现了 SRI（完整性检查）的问题，浏览器提示「Failed to find a valid digest in the &lsquo;integrity&rsquo; attribute for resource &hellip;」，导致语法高亮失效了。</p>
<p>搜索后发现是因为 Hugo 的「minify」与 Cloudflare 的「Auto Minify」发生了冲突，Cloudflare 在再次压缩后导致文件哈希值改变，校验失败。</p>
<p>解决办法是要么关闭 SRI，要么取消 Cloudflare 的「Auto Minify」。</p>
<p>Cloudflare 关闭的方法：速度 - 优化 - Auto Minify。</p>
<p>在 Hugo 中关闭的方法：</p>
<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 class="w">
</span></span></span></code></pre></div><h2 id="cdn-cgi">/cdn-cgi/</h2>
<p>因为 <a href="https://developers.cloudflare.com/fundamentals/get-started/reference/cdn-cgi-endpoint/" target="_blank" rel="noopener">/cdn-cgi/ endpoint</a> 这个问题，建议在 <code>robots.txt</code> 禁止抓取这个目录：</p>
<pre tabindex="0"><code>Disallow: /cdn-cgi/
</code></pre><p>不然 Google Search Console 中会有几百个此目录下的「已抓取-尚未编入索引」。。。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Alfred File Navigation（文件导航器）详解</title>
      <link>https://dvel.me/posts/alfred-file-navigation/</link>
      <pubDate>Thu, 06 Jan 2022 16:14:23 +0800</pubDate>
      <guid>https://dvel.me/posts/alfred-file-navigation/</guid>
      <description>Alfred 文件导航器的高效使用方法，轻松实现文件路径直达、隐藏文件打开、通配符选项、Buffer 功能批量移动等功能。让你的 macOS 使用更加便捷。</description>
      <content:encoded><![CDATA[<p>在 macOS 上，Alfred、Spotlight 相似产品极多，另外不错的软件也有 uTools、Raycast 等。</p>
<p>但一直让我留在 Alfred 的原因之一就是它的「文件导航器」功能，每次换去其他软件尝试一会儿之后，马上就开始怀念这个功能。</p>
<p>没见过有文章去介绍这个功能的，闲来无事随便写点。</p>
<h2 id="我的-alfred-快捷键">我的 Alfred 快捷键</h2>
<p>仅供参考：</p>
<ul>
<li>双击 Command：呼出 Alfred 窗口</li>
<li>双击 Option：Alfred 剪贴板工具</li>
<li>双击 Control：呼出 uTools 窗口</li>
<li>双击 Shift：留给了 JetBrains 全家桶的内置快捷键</li>
<li>Command + 空格：切换输入法</li>
<li>Option + 空格：Alfred 文件导航器</li>
<li>Control + 空格：呼出 Spotlight 窗口</li>
<li>Shift + 空格：iTerm 2</li>
</ul>
<h2 id="file-search">File Search</h2>
<h3 id="search">Search</h3>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-06A.webp"
            alt="Alfred"
            width="2432"
            height="1388"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>这里是对「open」「find」「in」「tags」四个指令的命令设置，其中「in」是搜索文件内字符串的功能，「open」和「find」其实用「Quick Search」代替就可以了，也就是「空格」，输入「空格」+「文件名」就可以了。</p>
<h3 id="navigation">Navigation</h3>
<p>文件导航器相关设置</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-06B.webp"
            alt="Alfred"
            width="2432"
            height="1388"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>取消勾选「Use ⏎ to open folders in Finder」，回车就变成「→」的功能，不过也可以用「⌘+⏎」来在 Finder 中打开。</p>
<h3 id="buffer">Buffer</h3>
<p>这个功能是在文件导航器中，可以批量处理一些文件。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2022-01-06C.webp"
            alt="Alfred"
            width="2432"
            height="1388"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<ul>
<li><code>⌥↑</code> 将文件加入 buffer，如果已经加入，则移除</li>
<li><code>⌥↓</code> 将文件加入 buffer，并移至下一个文件（适用于批量选择时）</li>
<li><code>⌥←</code> 将最后一个加入 buffer 的文件移除</li>
<li><code>⌥→</code> 最后，对所有加入 buffer 的文件进行统一操作</li>
</ul>
<h3 id="advanced">Advanced</h3>
<p>这里可以设置家目录的指令符号，默认就是 <code>~</code>，也可以修改家目录的位置，没必要修改。</p>
<h3 id="actions-设置">Actions 设置</h3>
<p>Alfred 新版已经将 Actions 抽离出来，并可通过扩展进行自定义，在「Universal Actions」中可以设置快捷键。</p>
<p>我设置的是「fn」或「ctrl」。</p>
<p>在文件导航器中，选中一个文件后，按「ctrl」即可进入 Actions 菜单，可对文件进行打开、移动、删除、复制等等操作。</p>
<p>比如 Spotlight 不支持「使用 xx 应用程序打开文件」，Alfred 就可以很方便的搞定。</p>
<h2 id="示例零路径直达">示例零：路径直达</h2>
<p>将路径直接粘贴到 Alfred 窗口，则自动激活文件导航器。</p>
<p>支持绝对路径和以 <code>~</code> 开头的路径。</p>
<p>输入 <code>~</code> 或 <code>/</code> 则直接跳转到家目录与根目录。</p>
<h2 id="示例一快捷打开隐藏的配置文件">示例一：快捷打开隐藏的配置文件</h2>
<p>呼出 Alfred 窗口，输入 <code>~</code>，则自动跳转到文件导航器的家目录。</p>
<p>接着输入 <code>.zshrc</code> 就可以找到 zsh 的配置文件。</p>
<img src="/img/2022-01-06D.webp" alt="Alfred" style="zoom: 33%;" />
<p>这功能其他软件都没有实现，编辑个隐藏文件用 Alfred 就很方便了。</p>
<h2 id="示例二快捷打开搜索到的文件夹内的某一文件">示例二：快捷打开搜索到的文件夹内的某一文件</h2>
<p>比如我想快捷地查看或编辑一下 Rime 的配置文件。</p>
<p>在 Alfred 窗口输入「空格」+「rime」：</p>
<img src="/img/2022-01-06E.webp" alt="Alfred" style="zoom:33%;" />
<p>这时按「→」即可进入文件导航器：</p>
<img src="/img/2022-01-06F.webp" alt="Alfred" style="zoom:33%;" />
<p>我就可以选择我想要预览或编辑的文件了。</p>
<h2 id="示例三支持通配符选项">示例三：支持通配符选项</h2>
<img src="/img/2022-01-06I.webp" alt="Alfred" style="zoom:33%;" />
<p>在很多轻量场景中，找一些文件比用 Finder 方便多了。</p>
<h2 id="示例四利用-buffer-功能批量移动文件">示例四：利用 Buffer 功能批量移动文件</h2>
<p>有时候下载的电视剧字幕文件，每一集都单独放进了一个文件夹，我想把它们全都集合到同一个文件夹。</p>
<p>如：</p>
<pre tabindex="0"><code>.
└── 某电视剧字幕/
    ├── e1/
    │   └── e1.ass
    ├── e2/
    │   └── e2.ass
    └── e3/
        └── e3.ass
</code></pre><p>变成：</p>
<pre tabindex="0"><code>.
└── 某电视剧字幕/
    ├── e1.ass
    ├── e2.ass
    └── e3.ass
</code></pre><p>将三个文件都加入 buffer：</p>
<img src="/img/2022-01-06G.webp" alt="Alfred" style="zoom:33%;" />
<p>然后按 <code>⌥ →</code> 进入 Actions 菜单，选择移动到 xx 目录：</p>
<img src="/img/2022-01-06H.webp" alt="Alfred" style="zoom:33%;" />
<p>接下来用 ← → 选择好目录，按回车就可以了。</p>
<p>Buffer 的批量选择功能也可以结合通配符功能，快速选中一些同一文件夹下具有相同元素名称的文件。</p>
]]></content:encoded>
    </item>
    <item>
      <title>在 Hugo Goldmark Markdown 中设置以新标签打开链接</title>
      <link>https://dvel.me/posts/hugo-goldmark-markdown-new-tab/</link>
      <pubDate>Wed, 05 Jan 2022 20:44:44 +0800</pubDate>
      <guid>https://dvel.me/posts/hugo-goldmark-markdown-new-tab/</guid>
      <description>在Hugo Goldmark Markdown中设置以新标签打开链接，使用HTML标签的方法、Blackfriday渲染器和Goldmark的Markdown Render Hooks，逐一介绍了各种方法的实现。</description>
      <content:encoded><![CDATA[<h2 id="方法一html-标签的方法">方法一：HTML 标签的方法</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">markup</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="nx">markup</span><span class="p">.</span><span class="nx">goldmark</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="nx">markup</span><span class="p">.</span><span class="nx">goldmark</span><span class="p">.</span><span class="nx">renderer</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="nx">unsafe</span> <span class="p">=</span> <span class="kc">true</span>
</span></span></code></pre></div><p>这样支持了 HTML 标签：</p>
<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://example.com&#34;</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span><span class="p">&gt;</span>example.com<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>但比较麻烦，不推荐，不过建议开启这个功能以支持 HTML 语法。</p>
<h2 id="方法二在-blackfriday-中渲染">方法二：在 blackFriday 中渲染</h2>
<p>Hugo 已在 v0.60 后默认使用了符合 CommonMark 标准的  Goldmark 渲染器。</p>
<p>不过仍然可以启用 blackFriday 渲染器来设定其 <code>hrefTargetBlank</code> 属性为 <code>true</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">markup</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">defaultMarkdownHandler</span> <span class="p">=</span> <span class="s1">&#39;blackFriday&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="nx">markup</span><span class="p">.</span><span class="nx">blackFriday</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="nx">hrefTargetBlank</span> <span class="p">=</span> <span class="kc">true</span>
</span></span></code></pre></div><p>但这样就放弃了更快更标准的 Goldmark Markdown 渲染器。</p>
<h2 id="方法三推荐使用-goldmark-的-markdown-render-hooks">方法三（推荐）：使用 Goldmark 的 Markdown Render Hooks</h2>
<p>需要 Hugo 版本大于 v0.62.0 并启用 Goldmark（默认就是）。</p>
<p>创建 <code>render-link.html</code> 文件在 <code>./themes/&lt;你的主题&gt;/layouts/_default/_markup/</code> 目录。</p>
<p>内容：（参考<a href="https://gohugo.io/templates/render-hooks/#link-with-title-markdown-example" target="_blank" rel="noopener">官方文档</a>）</p>
<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 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><p>推荐使用此方法，自动为所有文章内的链接加上了 <code>target=&quot;_blank&quot; rel=&quot;noopener&quot;</code>。</p>
<hr>
<p>但是站内链接也都加上了 <code>target=&quot;_blank&quot; rel=&quot;noopener&quot;</code>。</p>
<p>站内链接建议写 path：</p>
<pre tabindex="0"><code>[title](/foo/bar/)
↓ 会被简单解析为： ↓
&lt;a href=&#34;https://dvel.me/foo/bar/&#34;&gt;title&lt;/a&gt;
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>日期与时间（UTC、GMT、时间戳、时区）</title>
      <link>https://dvel.me/posts/datetime-note/</link>
      <pubDate>Sat, 29 May 2021 22:14:04 +0800</pubDate>
      <guid>https://dvel.me/posts/datetime-note/</guid>
      <description>UTC、GMT、时间戳、时区和日期时间表示的基本概念和用法。如何获取当前时间戳，以及 Python、Golang 中常用的日期和时间方法。</description>
      <content:encoded><![CDATA[<p>总是记错弄乱，自己整理一份。</p>
<h2 id="基本概念">基本概念</h2>
<h3 id="格林尼治标准时间gmt">格林尼治标准时间（GMT）</h3>
<p>英语：<strong>G</strong>reenwich <strong>M</strong>ean <strong>T</strong>ime，简称 <strong>GMT</strong>。</p>
<p>是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时，因为本初子午线被定义为通过那里的经线。</p>
<p>由于地球每天的自转是有些不规则的，而且正在缓慢减速，<strong>GMT 已经被原子钟报时的 UTC 顶替</strong>。</p>
<h3 id="协调世界时utc">协调世界时（UTC）</h3>
<p>英语：<strong>C</strong>oordinated <strong>U</strong>niversal <strong>T</strong>ime，法语：<strong>T</strong>emps <strong>U</strong>niversel <strong>C</strong>oordonné，简称 <strong>UTC</strong>。</p>
<p>其以原子时秒长为基础，是最主要的世界时间标准。</p>
<blockquote>
<p>关于缩写：</p>
<p>国际电信联盟希望协调世界时能够在所有语言有单一的缩写。英语和法语区的人同时希望各自的语言缩写－CUT 和 TUC 能够成为国际标准，结果最后妥协使用 UTC。</p>
</blockquote>
<h3 id="gmt-与-utc">GMT 与 UTC</h3>
<p>目前能看到 GMT 字眼的，常见于 JavaScript 的 <code>Date()</code> 和谷歌搜索「伦敦时间」时展示的。</p>
<p>我也不是很理解为什么显示 GMT，但是即便显示的是 GMT，也是经过校准的，与正确时间相差不到一秒。</p>
<h3 id="网络时间协议ntp">网络时间协议（NTP）</h3>
<p>英语：<strong>N</strong>etwork <strong>T</strong>ime <strong>P</strong>rotocol，缩写：<strong>NTP</strong>。</p>
<p>NTP 是一个在电脑系统之间进行时钟同步的网络协议，意图将所有参与电脑的协调世界时（UTC）时间同步到几毫秒的误差内。</p>
<p>自1985年以来，NTP是目前仍在使用的最古老的互联网协议之一。</p>
<h3 id="时区与本地时间">时区与本地时间</h3>
<p>一般说 UTC 时间也就是指零时区 +00:00（或写成 UTC+0、UTC±00:00） 时间，比北京时间早八个小时。</p>
<p><code>2021-01-01 08:00:00 +08:00</code> 也就是北京时间的上午八点钟，而这时 UTC 时间为 <code>2021-01-01 00:00:00 +00:00</code>，英国伦敦的午夜，这是同一个时刻。</p>
<h3 id="时间戳">时间戳</h3>
<p>这里指的时间戳是指代码中的 timestamp 那一串长数字。</p>
<p>编程中大家讨论和使用的皆是 <strong>Unix 时间戳</strong>（Unix timestamp 或 POSIX timestamp），是从 <strong>1970 年 1 月 1 日 0 时 0 分 0 秒</strong>到现在的秒数，有的语言也支持了毫秒、微秒等等。</p>
<ul>
<li>1 秒 = 1000 毫秒</li>
<li>1 毫秒 =  1000 微秒</li>
</ul>
<p>很多编程语言都有生成当前时间戳的方法，目前的时间戳长度：</p>
<ul>
<li>10 位长度，精确到秒</li>
<li>13 位长度，精确到毫秒</li>
<li>16 位长度，精确到微秒</li>
</ul>
<p>在 2286 年 11 月 21 日 1 时 46 分 39 秒之后，时间戳会加长一位数。</p>
<h3 id="时间戳有时区吗">时间戳有时区吗？</h3>
<p>当我们讨论时间戳的时候，也就是前后端交换数据，数据库存储日期时间时，皆是 Unix 时间戳，时间戳是没有时区概念的。</p>
<p>或者可以理解为，时间戳是固定死零时区的。</p>
<p><code>2021-01-01 00:00:00+00:00</code> 与 <code>2021-01-01 08:00:00+08:00</code> 的时间戳都是 <code>1609459200</code>。</p>
<p>所以建议在数据库或数据传输时使用 Unix 时间戳，时间戳可以被简单地解析为 UTC 时间或任何时区的时间，不会被时区概念束缚和混淆。</p>
<h3 id="iso-8601">ISO 8601</h3>
<p>国际标准 ISO 8601，是国际标准化组织的日期和时间的表示方法，全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。</p>
<p>简单来说，日期与时间的规定写法是这样的：</p>
<pre tabindex="0"><code>2000-01-23                # 年使用四位数，月、日、时、分、秒皆使用两位数，不够的前面补零。
2000-01-23T04:05:06       # 用 T 分割日期与时间。
2000-01-23T04:05:06Z      # 用 Z 代表 UTC+0（零时区）
2000-01-23T04:05:06+00:00 # 也可以使用 +00:00 表示零时区
2000-01-23T04:05:06+08:00 # 东八区
2000-01-23T04:05:06.123456  # Python 中 datetime.now().isoformat() 的默认格式
</code></pre><p>实际上 ISO 8601 也允许了一些其他的写法。</p>
<h3 id="rfc-3339-与-iso-8601">RFC 3339 与 ISO 8601</h3>
<p>Python 用的是 ISO 8601：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><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">isoformat</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><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">isoformat</span><span class="p">()</span>
</span></span></code></pre></div><p>Golang 用的是 RFC 3339：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Format</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">RFC3339</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UTC</span><span class="p">().</span><span class="nf">Format</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">RFC3339</span><span class="p">)</span>
</span></span></code></pre></div><blockquote>
<p><a href="https://stackoverflow.com/questions/522251/whats-the-difference-between-iso-8601-and-rfc-3339-date-formats" target="_blank" rel="noopener">What&rsquo;s the difference between ISO 8601 and RFC 3339 Date Formats?</a></p>
<p>RFC 3339 被列为 ISO 8601 的配置文件。有一些很小的差异，比如 RFC 3339 不允许两位数的年份，RFC 3339 允许用空格代替 <code>T</code>。</p>
<p>就一般的使用情况来说，两者之间可视为没有差异。</p>
</blockquote>
<h2 id="获取时间戳">获取时间戳</h2>
<h3 id="python">Python：</h3>
<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></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="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">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">timestamp</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="nb">print</span><span class="p">(</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">timestamp</span><span class="p">())</span>
</span></span></code></pre></div><p><code>timestamp()</code> 经过了 Python 内部处理的，将当前的系统时间（无论你在哪个时区）转换为正确的标准的 Unix 时间戳。</p>
<p>而最下面的那个为什么错了，因为 <code>timestamp()</code> 默认你给的 <code>datetime</code> 是当前系统的时区，如果你在零时区，那的确没有问题；如果不在零时区，<code>timestamp()</code> 会认为我给的是东八区，所以最后返回了错误的时间戳。</p>
<p>可以解决这个错误，只需要在 <code>timestamp()</code> 之前将 <code>datetime</code> 的时区确定即可。</p>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">d1</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">d1</span> <span class="o">=</span> <span class="n">d1</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">8</span><span class="p">)))</span> <span class="c1"># 绑定时区为东八区</span>
</span></span><span class="line"><span class="cl"><span class="n">ts1</span> <span class="o">=</span> <span class="n">d1</span><span class="o">.</span><span class="n">timestamp</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">ts1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">d2</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">d2</span> <span class="o">=</span> <span class="n">d2</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span> <span class="c1"># 绑定时区为零时区</span>
</span></span><span class="line"><span class="cl"><span class="n">ts2</span> <span class="o">=</span> <span class="n">d2</span><span class="o">.</span><span class="n">timestamp</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">ts2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ts1 和 ts2 基本相等，只有程序运行顺序的微秒级差距。</span>
</span></span></code></pre></div><h3 id="golang">Golang：</h3>
<p>Golang 中是一样的:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Unix</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UTC</span><span class="p">().</span><span class="nf">Unix</span><span class="p">()</span>
</span></span></code></pre></div><p>因为 Golang 的 <code>time.Now()</code> 中默认就带有时区信息。</p>
<h2 id="python-常用的日期与时间方法">Python 常用的日期与时间方法</h2>
<h3 id="datetime-转-str">datetime 转 str</h3>
<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">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">d</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">s</span> <span class="o">=</span> <span class="n">d</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></span></code></pre></div><h3 id="str-转-datetime">str 转 datetime</h3>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span><span class="p">,</span> <span class="n">time</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">s</span> <span class="o">=</span> <span class="s2">&#34;2001-02-03 04:05:06&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">d</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">s</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></span><span class="line"><span class="cl"><span class="c1"># 为得到的 datetime 增加时区</span>
</span></span><span class="line"><span class="cl"><span class="n">d_with_timezone</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">8</span><span class="p">)))</span>
</span></span></code></pre></div><h3 id="获取当前-utc-时间带时区">获取当前 UTC 时间（带时区）</h3>
<p>不加后面的 <code>replace</code> 就不带时区信息了，下同。</p>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><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">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-05-29 15:28:10.913530+00:00</span>
</span></span></code></pre></div><h3 id="获取当前系统时间带时区">获取当前系统时间（带时区）</h3>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</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">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">8</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-05-29 23:38:21.006309+08:00</span>
</span></span></code></pre></div><h3 id="datetime-转-时间戳">datetime 转 时间戳</h3>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span><span class="p">,</span> <span class="n">timedelta</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">dt</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="nb">print</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="s1">&#39;datetime.now() 当前系统时间（不含时区）&#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">dt</span><span class="o">.</span><span class="n">timestamp</span><span class="p">(),</span> <span class="s1">&#39;不含时区的时间，会认为是系统时间，会自动转换为正确的 UTC 时间戳&#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">dt</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">8</span><span class="p">)))</span><span class="o">.</span><span class="n">timestamp</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"># 2021-07-16 00:15:02.730997 datetime.now() 当前系统时间（不含时区）</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1626365702.730997 不含时区的时间，会认为是系统时间，会自动转换为正确的 Unix 时间戳</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1626365702.730997 包含东八区时区信息的，同上</span>
</span></span></code></pre></div><h3 id="时间戳-转-datetime">时间戳 转 datetime</h3>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="mi">1609459200</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-01-01 00:00:00</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="mi">1609459200</span><span class="p">,</span> <span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-01-01 00:00:00+00:00</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="mi">1609459200</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-01-01 08:00:00</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="mi">1609459200</span><span class="p">,</span> <span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">8</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2021-01-01 08:00:00+08:00</span>
</span></span></code></pre></div><h3 id="datetime-转换时区">datetime 转换时区</h3>
<p>转换前需要先确定被转换的 <code>datetime</code> 对象的时区，拥有时区属性的 <code>datetime</code> 对象可以转换为任意一个时区的日期时间。</p>
<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">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">utc_dt</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">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</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">utc_dt</span><span class="p">)</span>   <span class="c1"># 2021-01-01 00:00:00+00:00</span>
</span></span><span class="line"><span class="cl"><span class="n">bj_dt</span> <span class="o">=</span> <span class="n">utc_dt</span><span class="o">.</span><span class="n">astimezone</span><span class="p">(</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</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="n">bj_dt</span><span class="p">)</span>    <span class="c1"># 2021-01-01 08:00:00+08:00</span>
</span></span><span class="line"><span class="cl"><span class="n">tokyo_dt</span> <span class="o">=</span> <span class="n">bj_dt</span><span class="o">.</span><span class="n">astimezone</span><span class="p">(</span><span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">9</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">tokyo_dt</span><span class="p">)</span> <span class="c1"># 2021-01-01 09:00:00+09:00</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>让 Alfred 以新标签的方式打开 Finder</title>
      <link>https://dvel.me/posts/alfred-finder-new-tab/</link>
      <pubDate>Wed, 19 May 2021 16:16:08 +0800</pubDate>
      <guid>https://dvel.me/posts/alfred-finder-new-tab/</guid>
      <description>每次从 Alfred 打开的文件夹都是以 Finder 新建窗口的方式打开的，通过以下两个设置让 Finder 使用新标签打开窗口。</description>
      <content:encoded><![CDATA[<p>升级到了 macOS Monterey 后发现 <a href="https://www.trankynam.com/xtrafinder/" target="_blank" rel="noopener">XtraFinder</a> 失效了，官方暂未跟进 macOS 12，迫不得已用回原始的 Finder。</p>
<p>但是发现每次从 Alfred 打开的文件夹都是以 Finder 新建窗口的方式打开的。</p>
<hr>
<ol>
<li>确保 Finder 偏好设置中打开「<strong>在新标签页中打开文件夹</strong>」。</li>
</ol>
<img src="/img/2021-05-19A.webp" alt="通用偏好设置" style="zoom: 33%;" />
<ol start="2">
<li>在系统偏好设置中将「<strong>首选以标签页方式打开文稿</strong>」的选项设置为「<strong>始终</strong>」。</li>
</ol>
<img src="/img/2021-05-19B.webp" alt="访达偏好设置" style="zoom:50%;" />
<p>总之目前（macOS Monterey 12.0.1）这样设置是可行的。</p>
<p>苹果这个行为逻辑给人整迷了。</p>
<p>很明显设置一针对的应该是所有有标签页的应用，设置二针对的是 Finder 单个应用，但必须同时设定才起作用。</p>
<p>服了苹果。</p>
]]></content:encoded>
    </item>
    <item>
      <title>用 git filter-branch 给 Git 仓库瘦身</title>
      <link>https://dvel.me/posts/git-filter-branch-slim/</link>
      <pubDate>Sun, 09 May 2021 20:22:12 +0800</pubDate>
      <guid>https://dvel.me/posts/git-filter-branch-slim/</guid>
      <description>使用git filter-branch操作可以清理Git仓库中不需要的大文件，从而节省存储空间。本文将介绍清理步骤，包括使用git gc打包对象、查找最大的3个文件、删除文件、清除缓存和查看成果等。</description>
      <content:encoded><![CDATA[<p>有时候项目里引用了一些大文件，导致 <code>.git</code> 容量高达几个 G。</p>
<p>如果这些大文件丢失并不敏感，也没什么用处，可以清理掉来节约一下空间。</p>
<p>操作前建议备份。</p>
<h2 id="1-gc">1. gc</h2>
<p>使用 <a href="https://git-scm.com/docs/git-gc" target="_blank" rel="noopener">git-gc</a> 将对象打包。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git gc --prune<span class="o">=</span>now
</span></span></code></pre></div><p><code>.git</code> 已经从 4 个 G 变成了 322M。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ du -sh .git
</span></span><span class="line"><span class="cl">322M	.git
</span></span></code></pre></div><h2 id="2-查找最大的-3-个文件">2. 查找最大的 3 个文件</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git rev-list --objects --all <span class="p">|</span> grep <span class="s2">&#34;</span><span class="k">$(</span>git verify-pack -v .git/objects/pack/*.idx <span class="p">|</span> sort -k <span class="m">3</span> -n <span class="p">|</span> tail -3 <span class="p">|</span> awk <span class="s1">&#39;{print$1}&#39;</span><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">4badfe287e3f1d6e4e288b2c3b47261119ce2fca foo/bar1.xxx
</span></span><span class="line"><span class="cl">00e7645c93c2368b0634bda72507b40c936dd1b3 foo/bar2.xxx
</span></span><span class="line"><span class="cl">4088cefbbc3dcd6a17dfa656423ad20137fad9dd foo/bar3.xxx
</span></span></code></pre></div><h2 id="3-删除文件">3. 删除文件</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git filter-branch --force --index-filter <span class="s2">&#34;git rm -rf --cached --ignore-unmatch &lt;filename&gt;&#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></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ git filter-branch --force --index-filter <span class="s2">&#34;git rm -rf --cached --ignore-unmatch foo/bar1.xxx&#34;</span>  --prune-empty --tag-name-filter cat -- --all
</span></span></code></pre></div><p>1000 多个提交大概运行了 2 分钟。</p>
<h2 id="4-清除缓存">4. 清除缓存</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><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></code></pre></div><h2 id="5-查看成果">5. 查看成果</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ du -sh .git
</span></span><span class="line"><span class="cl">212M	.git
</span></span></code></pre></div><p>一个几十 M 的文件清除后，整个包减小了大概 100 M，多清理几个就降下来了。</p>
<p>最后 Push 时需使用 <code>--force</code> 参数覆盖远端。</p>
<h2 id="参考--感谢">参考 &amp; 感谢</h2>
<p><a href="https://www.jianshu.com/p/7ace3767986a" target="_blank" rel="noopener">Git清理删除历史提交文件</a></p>
<p><a href="https://www.zhihu.com/question/29769130/answer/315745139" target="_blank" rel="noopener">如何解决 GitHub 提交次数过多 .git 文件过大的问题？</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>qBittorrent 设置教程</title>
      <link>https://dvel.me/posts/qbittorrent-config/</link>
      <pubDate>Tue, 06 Apr 2021 00:01:22 +0800</pubDate>
      <guid>https://dvel.me/posts/qbittorrent-config/</guid>
      <description>本文为您提供了qBittorrent设置的详细教程，包括Peer链接、加密、Tracker和高级设置等内容。</description>
      <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>qBittorrent 是一个跨平台的自由 BitTorrent 客户端。（<a href="https://www.qbittorrent.org/" target="_blank" rel="noopener">官方网站</a>、<a href="https://github.com/qbittorrent/qBittorrent" target="_blank" rel="noopener">GitHub</a>）</p>
<p>GitHub 社区亦有一个 <a href="https://github.com/SuperNG6/Docker-qBittorrent-Enhanced-Edition" target="_blank" rel="noopener">qBittorrent Enhanced Edition</a> （qBittorrent 增强版本），主要特点是自动屏蔽了迅雷、自动更新 trackers。</p>
<p>如果只进行 BT 下载，推荐使用 qBittorrent Enhanced Edition，但是像馒头这样的 PT 社区不支持，可以使用原版。</p>
<p>耽误了一阵子在 qBittorrent 的配置方面，这里简单记录一下主要的配置。</p>
<h2 id="为了发现更多的-peer">为了发现更多的 Peer</h2>
<p>Peer 链接协议都开启。</p>
<p>开启 UPnP/NAT-PMP 端口转发。</p>
<p>启用 DHT，PeX、本地用户，无需关心 PT，PT 会自动禁止，只使用 Tracker。</p>
<p>最好桥接，可以被更多的 Peer 发现。</p>
<p>有些光猫是可以破解的，可以参考我另一篇博文：<a href="/posts/hack-unicom-modem-bridge/">光猫破解+桥接记录</a></p>
<h2 id="加密">加密</h2>
<p>有些 ISP 会限制 BT 流量，尽量使用「强制加密」和「匿名模式」。</p>
<h2 id="trackers">trackers</h2>
<p>目前国际最主流的是这个仓库：<a href="https://github.com/ngosang" target="_blank" rel="noopener">ngosang</a>/<strong><a href="https://github.com/ngosang/trackerslist" target="_blank" rel="noopener">trackerslist</a></strong> 。</p>
<p>也有国人维护的一个 <a href="https://trackerslist.com" target="_blank" rel="noopener">XIU2/TrackersListCollection</a>，来源包括上面的。</p>
<h2 id="高级设置">高级设置</h2>
<p>图片来源：<a href="https://www.jianshu.com/p/ac70172767ed" target="_blank" rel="noopener">https://www.jianshu.com/p/ac70172767ed</a></p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2021-04-06.webp"
            alt="qBittorrent"
            width="1080"
            height="1960"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>其中最关键的配置项，这两个必须打开，否则有些 Tracker 总是连不上：</p>
<ul>
<li>总是向同级的所有 Tracker 汇报</li>
<li>总是向所有等级的 Tracker 汇报</li>
</ul>
<p>另外对于 PT 用户一定要设置的地方：</p>
<ul>
<li>上传窗口策略：
<ul>
<li>固定窗口数 ✓</li>
<li>基于上传速度 ✗（经过测试使用此项配置会导致上传速度大大降低）</li>
</ul>
</li>
<li>上传连接策略：
<ul>
<li>轮流上传（没试过）</li>
<li>最快上传（PT 推荐）</li>
<li>反吸血（BT 推荐）</li>
</ul>
</li>
</ul>
<p>仅使用上两个修改，其他默认，百兆左右的上传带宽即可跑满 10M/s。</p>
]]></content:encoded>
    </item>
    <item>
      <title>联通光猫破解&#43;桥接记录</title>
      <link>https://dvel.me/posts/hack-unicom-modem-bridge/</link>
      <pubDate>Mon, 05 Apr 2021 23:24:14 +0800</pubDate>
      <guid>https://dvel.me/posts/hack-unicom-modem-bridge/</guid>
      <description>联通光猫烽火HG6543C的破解过程，包括启用隐藏账户、Telnet获取超级用户密码和桥接流程等。通过本文，您可以学习如何将光猫切换到桥接模式并测试BT端口。</description>
      <content:encoded><![CDATA[<p>实操是联通光猫烽火 HG6543C，主要目的就是桥接。</p>
<p>如果你的光猫普通用户登录后就可以改桥接，就没必要破解超级用户密码了。</p>
<h2 id="破解流程">破解流程</h2>
<blockquote>
<p>请直接尝试第五步，默认密码可能为 <code>cuadmin</code> 或 <code>CUAdmin</code>，如果密码错误则从第一步开始。</p>
</blockquote>
<h3 id="1启用隐藏账户">1、启用隐藏账户</h3>
<p>http://192.168.1.1/logoffaccount.html</p>
<p>在这个网址下可以开启隐藏用户。</p>
<p>也可以「允许 TR069 修改」，可以禁用远程管理。</p>
<h3 id="2登录">2、登录</h3>
<p>http://192.168.1.1</p>
<p>用户名：fiberhomehg2x0
密码：hg2x0</p>
<blockquote>
<p>实测在启用隐藏账户后的跳转页面，直接输入 <code>hg2x0</code> 就进入服务设置了，我这个型号的光猫并没有要求我输入用户名。</p>
</blockquote>
<h3 id="3开启-telnet-服务">3、开启 Telnet 服务</h3>
<p>服务设置 - 服务设置 - 启用 Telnet 服务器，设置好账号密码，保存/应用。</p>
<p>服务设置 - 服务设置 - 服务访问控制，我这里 <code>TELNET</code> 选项默认为 <code>Disable</code>，改成 <code>LAN</code> 才可以连接。</p>
<h3 id="4telnet-获取超级用户密码">4、Telnet 获取超级用户密码</h3>
<p>进入终端，Telnet 连接上后如果想进行其他操作，输入 <code>sh</code> 以解锁 Linux 所有命令行，否则只有有限的几个命令。</p>
<pre tabindex="0"><code>$ telnet 192.168.1.1                                                                                                                                     ✔
	Trying 192.168.1.1...
	Connected to 192.168.1.1.
	Escape character is &#39;^]&#39;.
	BCM96848 Broadband Router
Login: admin
Password:
&gt; get telname
	cuadmin
&gt; get telpwd
	cuadmin
</code></pre><h3 id="5以超级用户进入管理页面">5、以超级用户进入管理页面</h3>
<p>http://192.168.1.1/cu.html 账号密码为上一步所得。</p>
<h3 id="其他">其他</h3>
<p>在 Telnet 之后，<code>top</code> 看到了网上有人说的光猫 javmm 服务，占了三分之一以上的内存，kill 之后也一切正常，不知道这个服务是干嘛的。</p>
<h2 id="桥接流程">桥接流程</h2>
<h3 id="光猫">光猫</h3>
<p>以管理员用户登入 http://192.168.1.1/cu.html - 基本设置 - 宽带设置。</p>
<p>「连接名称」应该有三种或以上：</p>
<ul>
<li>TR069（远程管理、语音）</li>
<li>INTERNET（互联网连接）</li>
<li>IPTV（电视）</li>
</ul>
<p>选中「INTERNET」。</p>
<p>将「模式」从「Route（路由模式）」改为「Bridge（桥接模式）」。</p>
<p>点击「保存/应用」。</p>
<h3 id="路由器">路由器</h3>
<p>改成拨号模式（PPPoE），输入宽带账号密码就可以了。</p>
<h2 id="测试-bt-端口">测试 BT 端口</h2>
<p>打开 BT 软件，设置好端口 xxxxx。</p>
<p><a href="https://www.yougetsignal.com/tools/open-ports/" target="_blank" rel="noopener">https://www.yougetsignal.com/tools/open-ports/</a> 在这个网站上可以检测。</p>
<p>Port xxxxx is open on xxx.xxx.xxx.xxx 则表示 ping 通。</p>
]]></content:encoded>
    </item>
    <item>
      <title>配置 Mac 终端走代理</title>
      <link>https://dvel.me/posts/mac-terminal-proxy/</link>
      <pubDate>Fri, 23 Oct 2020 22:13:41 +0800</pubDate>
      <guid>https://dvel.me/posts/mac-terminal-proxy/</guid>
      <description>在Mac终端配置代理，以便通过终端访问GitHub、Homebrew等网站。通过Surge或手动配置HTTP代理，设置终端自动走代理，并提供开关代理的命令，同时还介绍了如何配置SSH代理。</description>
      <content:encoded><![CDATA[<p>因为 Terminal 或 iTerm 2 是不走系统代理的，有时候访问 GitHub、Homebrew 等有点龟速，体验很差，最好设置其走代理访问。</p>
<h2 id="使用工具">使用工具</h2>
<ul>
<li>Surge 或 ClashX 等代理软件的增强模式</li>
<li>Proxifier 也可以配置一些软件强制走代理</li>
<li>终端使用 ProxyChains</li>
</ul>
<p>没用过 ProxyChains，Proxifier 太贵了且功能雷同，又不想一直开着增强模式。</p>
<h2 id="http-代理">HTTP 代理</h2>
<p>Surge 在菜单栏按 ⌘+C 就会自动生成代理命令，假设端口是 <code>8888</code> 和 <code>8889</code>：</p>
<pre tabindex="0"><code>$ export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889
</code></pre><p>每次都输入比较麻烦，可以写进  <code>~/.zshrc</code> 中，示例：</p>
<pre tabindex="0"><code># 自动代理
export https_proxy=http://127.0.0.1:8888
export http_proxy=http://127.0.0.1:8888
export all_proxy=socks5://127.0.0.1:8889

# 开关代理
alias setproxy=&#34;export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889;echo \&#34;Set proxy successfully\&#34; &#34;
alias unsetproxy=&#34;unset http_proxy;unset https_proxy;unset all_proxy;echo \&#34;Unset proxy successfully\&#34; &#34; 

# 测试
alias lip=&#34;curl cip.cc; curl ifconfig.me&#34;
</code></pre><p>让 shell 默认就走代理，并设置一个开关。</p>
<p>最后的测试，随便找两个 IP 查询服务就可以了，并在自己的代理规则中设定一个直连、一个代理。</p>
<h2 id="ssh-代理">SSH 代理</h2>
<p>Git 可以设置 <code>git config --global http.proxy</code> 和 <code>git config --global https.proxy</code> 。</p>
<p>或者直接用下面这个，一劳永逸。</p>
<pre tabindex="0"><code>Host *
    ProxyCommand nc -X 5 -x 127.0.0.1:8889 %h %p
# * 代表所有的 SSH 主机
# 第二行代表让所有的 SSH 的主机在连接的时候，通过本地的端口为 8889 的 socks5 代理去连接
</code></pre><p><code>nc</code> 的参数说明：<a href="https://man.openbsd.org/nc" target="_blank" rel="noopener">https://man.openbsd.org/nc</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Steam for Mac 中文游戏推荐</title>
      <link>https://dvel.me/posts/steam-for-mac-game-recommend/</link>
      <pubDate>Thu, 15 Oct 2020 22:13:53 +0800</pubDate>
      <guid>https://dvel.me/posts/steam-for-mac-game-recommend/</guid>
      <description>为长期使用 MacBook Pro 的用户推荐一些支持 macOS 的 Steam 平台的中文游戏。</description>
      <content:encoded><![CDATA[<p>由于长期在使用 MBP，但还是想打打游戏，这里推荐一些我玩过的，MBP 能带得动的游戏。</p>
<p>我用的是 Intel MBP 带独显的高配，目前看来 M1 基本都可以胜任，如果兼容的话。</p>
<h2 id="倾情推荐">倾情推荐</h2>
<h3 id="portal--portal-2-传送门">Portal &amp; Portal 2 传送门</h3>
<p><a href="https://store.steampowered.com/app/400/Portal/" target="_blank" rel="noopener">Portal</a> &amp; <a href="https://store.steampowered.com/app/620/Portal_2/" target="_blank" rel="noopener">Portal 2</a></p>
<p>世界第一，目前最好玩的游戏，哪怕过了这么多年。</p>
<p>在 2 通关后，建议进行双人联机，联机模式还有一整套关卡，当然也有社区作品。</p>
<h3 id="rimworld-边缘世界">RimWorld 边缘世界</h3>
<p><a href="https://store.steampowered.com/app/294100/RimWorld/" target="_blank" rel="noopener">RimWorld</a></p>
<p>从 A15 玩到 1.0，感谢伟大的作者，也感谢各个 Mod 的贡献者。</p>
<p>这是我玩过的时间最长的单机游戏了，评论区时间过千的比比皆是，时间过百的熙熙攘攘。</p>
<p>这也是我第一款安装过 100 多个 Mod 的游戏，真乃是装 Mod 一时爽，一直装一直爽。每天早上听到「Waiting for the sun」的闹铃，我都会回想起那里的春夏秋冬，伴随着火箭升空后留下的心里空白 —— 这里才是家啊！</p>
<p>沙盒、模拟、生存、经营、人事管理、建筑规划、工作安排、战斗策略。。。这还是游戏嘛，这他妈就是男人的浪漫啊！</p>
<h3 id="factorio-异星工厂">Factorio 异星工厂</h3>
<p><a href="https://store.steampowered.com/app/427520/Factorio/" target="_blank" rel="noopener">Factorio</a></p>
<p>这是我玩过的时间第二长的单机游戏，即便不打 Mod，游戏本身的可玩性就高到不知哪里去了。</p>
<p>游戏的核心是在异星建造一个完备的自动化工厂，同时抵御虫族的入侵，最后造个火箭发射回家，和 RimWorld 的最终目的一样。</p>
<p>在这款游戏里你将通过传送带、机械臂组建你自己的工厂，不断的扩充、优化、整改、升级你的生产线。不知道其他人从这款游戏里体会到了什么，我发现了很多类编程的思想，不断的迭代又不断的重构，多个小组件的封装与调用就像模块一样，最初构造的时候就要留好日后扩展的余地，时不时产生的 Bug。。。</p>
<p>最初的通关，我用面向对象与模块化的方式将所有问题简化：一条总线管运输，一排一种组件模块留好扩展空间，对采矿、发电、运输、每个组件的生产、每个科技瓶的生产、科技瓶的消耗进行分隔，一个一个的设计、量化、扩充，终于把火箭给发射了。</p>
<p>除此之外在 B 站、油管有各种设计大师，自由度极高，玩家可发挥的空间太大了，有时只优化几条产品线天就亮了，增加一个矿区刚铺好火车站天就黑了，如果戒毒所能引进这款游戏，谁他妈的还吸毒呢？</p>
<h3 id="slay-the-spire-杀戮尖塔">Slay the Spire 杀戮尖塔</h3>
<p><a href="https://store.steampowered.com/app/646570/Slay_the_Spire/" target="_blank" rel="noopener">Slay the Spire</a></p>
<p>卡牌+Roguelike 的典范！至今没找到第二款能超越它的。</p>
<p>无尽模式真是无脑杀时间，<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=2137404781&amp;searchtext=" target="_blank" rel="noopener">The Hermit</a> 是我装过的最好的 Mod，百玩不腻。</p>
<h3 id="hades-哈迪斯">Hades 哈迪斯</h3>
<p><a href="https://store.steampowered.com/app/1145360/Hades/" target="_blank" rel="noopener">Hades</a></p>
<p>动作类 Roguelike，画风和动作做得非常到位。</p>
<p>相比《杀戮尖塔》，《哈迪斯》多了冲塔前后的一些元素，多了剧情。</p>
<p>玩到 50 小时差不多才审美疲劳，不过这 50 小时感觉非常棒。</p>
<p><strong>In the name of Hades! Olympus! I accept this message.</strong></p>
<h3 id="shadow-tactics-blades-of-the-shogun-影子战术将军之刃">Shadow Tactics: Blades of the Shogun 影子战术：将军之刃</h3>
<p><a href="https://store.steampowered.com/app/418240/Shadow_Tactics_Blades_of_the_Shogun/" target="_blank" rel="noopener">Shadow Tactics: Blades of the Shogun</a></p>
<p>稀缺的即时战术类游戏，出就买系列，太好玩了，我要屠城。</p>
<h3 id="desperados-iii-赏金奇兵-">Desperados III 赏金奇兵 Ⅲ</h3>
<p><a href="https://store.steampowered.com/app/610370/Desperados_III/" target="_blank" rel="noopener">Desperados III</a></p>
<p>《影子战术》的续作。</p>
<p>稀缺的即时战术类游戏，出就买系列，太好玩了，我要屠城。</p>
<h3 id="dome-keeper-穹顶守护者">Dome Keeper 穹顶守护者</h3>
<p><a href="https://store.steampowered.com/app/1637320/Dome_Keeper/" target="_blank" rel="noopener">Dome Keeper</a></p>
<p>挖矿、升级、战斗。</p>
<p>开发已经尽可能地让这个游戏变得耐玩了，但还是不太耐玩（也至少能玩个几十小时），建议打折入。</p>
<h3 id="sid-meiers-civilization-vi-文明-6">Sid Meier&rsquo;s Civilization VI 文明 6</h3>
<p><a href="https://store.steampowered.com/app/289070/Sid_Meiers_Civilization_VI/" target="_blank" rel="noopener">Sid Meier&rsquo;s Civilization VI</a></p>
<blockquote>
<p>下一回合就睡觉。。。</p>
</blockquote>
<p>无需多介绍，在 MBP 上稍卡，我一般都是用战略视图游玩的。</p>
<h3 id="gorogoa">Gorogoa</h3>
<p><a href="https://store.steampowered.com/app/557600/Gorogoa/" target="_blank" rel="noopener">Gorogoa</a></p>
<p>一款独具特色的解谜游戏，全手绘画风，隐含了一个追逐梦想的故事。</p>
<p>精美的像艺术品，强烈推荐，玩法独一无二、新鲜有趣，这真的是艺术品。</p>
<h3 id="life-is-strange-奇异人生">Life is Strange 奇异人生</h3>
<p><a href="https://store.steampowered.com/app/319630/Life_is_Strange__Episode_1/" target="_blank" rel="noopener">Life is Strange</a></p>
<p>互动性+剧情选择向的电影游戏，剧情方面好评如潮，整部下来大约是 10 小时。</p>
<p>汉化包建议搜索「奇异人生 虎头汉化」，支持 Win/Mac。</p>
<h3 id="to-the-moon-去月球">To the Moon 去月球</h3>
<p><a href="https://store.steampowered.com/app/206440/To_the_Moon/" target="_blank" rel="noopener">To the Moon</a></p>
<p>自由鸟出品，感人的故事，约 5 小时通关。</p>
<p>这应该是目前看来自由鸟最好的一个作品了。</p>
<blockquote>
<p>“还有吗？”</p>
<p>“还有吗？”</p>
<p>“还有吗？”</p>
<p>。。。</p>
<p>“在那儿，对吗？？有两只耳朵和头！”
——这或许是 River 最想听到的回答。</p>
</blockquote>
<h3 id="finding-paradise-寻找天堂">Finding Paradise 寻找天堂</h3>
<p><a href="https://store.steampowered.com/app/337340/Finding_Paradise/" target="_blank" rel="noopener">Finding Paradise</a></p>
<p>自由鸟出品，感人的故事，约 5 小时通关，主题曲很好听：<a href="https://open.spotify.com/track/4KDCB4J2Yh123ZdwPQShvO" target="_blank" rel="noopener">Wish My Life Away</a></p>
<h3 id="impostor-factory">Impostor Factory</h3>
<p><a href="https://store.steampowered.com/app/1182620/Impostor_Factory/" target="_blank" rel="noopener">Impostor Factory</a></p>
<p>自由鸟出品，感人的故事，约 3.5 小时通关。</p>
<h3 id="kingdom-rush-全系列">Kingdom Rush 全系列</h3>
<p>如果不刷星，这真是目前世界上最好玩的 TD 了。</p>
<p>如果刷星，不久便会产生疲惫感，因为重复带来枯燥，枯燥导致无聊。</p>
<h3 id="firewatch-看火人">Firewatch 看火人</h3>
<p><a href="https://store.steampowered.com/app/383870/Firewatch/" target="_blank" rel="noopener">Firewatch</a></p>
<p>说是冒险游戏，不如说是 ASMR 游戏或看风景游戏。很喜欢小姐姐的声音，中期的剧情还会让人浮想联翩。。。</p>
<p>是那种闲暇的一天，泡一杯咖啡，关掉手机，静静的欣赏与探索的好游戏。</p>
<h3 id="plague-inc-evolved-瘟疫公司">Plague Inc: Evolved 瘟疫公司</h3>
<p><a href="https://store.steampowered.com/app/246620/Plague_Inc_Evolved/" target="_blank" rel="noopener">Plague Inc: Evolved</a></p>
<p>Win/Mac 版非常良心，没有手机上那么多收费项目，还支持 Mod。</p>
<h3 id="cities-skylines-城市天际线">Cities: Skylines 城市：天际线</h3>
<p><a href="https://store.steampowered.com/app/255710/Cities_Skylines/" target="_blank" rel="noopener">Cities: Skylines</a></p>
<p>好玩自然不用多说，但是 MBP 运行起来过于卡顿。。。</p>
<h3 id="spiritfarer-灵魂旅者">Spiritfarer 灵魂旅者</h3>
<p><a href="https://store.steampowered.com/app/972660/SpiritfarerFarewell/" target="_blank" rel="noopener">Spiritfarer</a></p>
<p>喜怒哀乐、生老病死、悲欢离合。</p>
<p>总游戏时间 30 小时左右。</p>
<p>游戏主题不错，但是有太多繁琐、重复的小作业。</p>
<p>如果能压缩到 10 小时以内，这是个满分游戏，由于这些琐碎消耗了我太多精力，我只能给 6/10 分。</p>
<p>超 · 友情提示！！！</p>
<ul>
<li>你可以不对任何人和动物进行喂食，他们不会死，也不会跑，不会有任何问题</li>
<li>菜园、田地不用浇水，一样会生长，只是慢些</li>
<li>最后有一个圣坛是强化钓鱼和挖矿</li>
<li>强化钓鱼后再去找金枪鱼更节省时间</li>
<li>强化挖矿后，注意每个石头对应额外的宝物，比如挖煤必出一个钻石（对于最后的差事有很大帮助）</li>
</ul>
<h3 id="stardew-valley-星露谷物语">Stardew Valley 星露谷物语</h3>
<p><a href="https://store.steampowered.com/app/413150/Stardew_Valley/" target="_blank" rel="noopener">Stardew Valley</a></p>
<p>好评如潮的佛系养生类<del>休闲</del>爆肝游戏。</p>
<h3 id="rise-of-the-tomb-raider-古墓丽影崛起">Rise of the Tomb Raider 古墓丽影：崛起</h3>
<p><a href="https://store.steampowered.com/app/391220/Rise_of_the_Tomb_Raider/" target="_blank" rel="noopener">Rise of the Tomb Raider</a></p>
<p>MBP 完全带得动，而且还支持了 MBP 的 Touch Bar。</p>
<p>第一次玩古墓丽影系列，如果去掉捡垃圾这种操作，这个游戏还真是挺好玩的。</p>
<h3 id="beholder-旁观者">Beholder 旁观者</h3>
<p><a href="https://store.steampowered.com/agecheck/app/475550/" target="_blank" rel="noopener">Beholder</a></p>
<p>一个「1984」式的反乌托邦设定，创意很特别，主要玩法在于道德选择。</p>
<h3 id="opus-magnum">Opus Magnum</h3>
<p><a href="https://store.steampowered.com/app/558990/Opus_Magnum/" target="_blank" rel="noopener">Opus Magnum</a></p>
<p>非常奇妙的模拟、编程、设计、自动化、解密类游戏。</p>
<p>喜欢编程或动脑的可以试试，每个关卡都存在最快解法、最省解法，很考验大脑。</p>
<p>还特别适合中小学生游玩，锻炼思维罗辑。</p>
<p>但对 Mac 的分辨率支持不是很好，不过问题不大。</p>
<h3 id="vampire-survivors-吸血鬼幸存者">Vampire Survivors 吸血鬼幸存者</h3>
<p><a href="https://steamcommunity.com/app/1794680" target="_blank" rel="noopener">Vampire Survivors</a></p>
<p>一款 Roguelike 弹幕射击生存游戏，有很多抄袭作品，原版这个可以说是大道至简（画面）了。</p>
<p>内容很丰富，游戏时间很长。</p>
<h3 id="game-dev-tycoon-游戏开发大亨">Game Dev Tycoon 游戏开发大亨</h3>
<p><a href="https://store.steampowered.com/app/239820/Game_Dev_Tycoon/" target="_blank" rel="noopener">Game Dev Tycoon</a></p>
<p>玩过开罗的《游戏发展国》的玩家肯定会找回那份惊喜。这么多年游戏开发类游戏一直比较冷清，没有几个好玩的，难得有一个还不错的。</p>
<h3 id="mini-metro--mini-motorways-迷你地铁--迷你公路">Mini Metro &amp; Mini Motorways 迷你地铁 &amp; 迷你公路</h3>
<p><a href="https://store.steampowered.com/app/287980/Mini_Metro/" target="_blank" rel="noopener">Mini Metro</a> &amp; <a href="https://store.steampowered.com/app/1127500/Mini_Motorways/" target="_blank" rel="noopener">Mini Motorways</a></p>
<p>休闲模拟小游戏，但说实话我觉得可改进空间非常大，目前的流程设计非常低级。</p>
<h3 id="two-point-hospital-双点医院">Two Point Hospital 双点医院</h3>
<p><a href="https://store.steampowered.com/app/535930/_/" target="_blank" rel="noopener">Two Point Hospital</a></p>
<p>首发之后 Bug 很多，管理方式糟糕，人物AI智障。</p>
<p>这都不耽误我打通45星，当我最终要在最后一关铺设一间大医院的时候，没有「房间模板」或「复制房间」这个功能，让我崩溃了。</p>
<p>当我得知官方修复大量 Bug、更新中文语音、提供了复制房间功能时，我已经玩腻了。</p>
<p>现在玩的话还是比较合适的，游戏已经比较完善了。</p>
<h3 id="katana-zero">Katana ZERO</h3>
<p><a href="https://store.steampowered.com/app/460950/Katana_ZERO/" target="_blank" rel="noopener">Katana ZERO</a></p>
<p>横版过关动作类游戏，6 小时通关，打击感不错，而且不算太难，画风、故事、战斗系统都挺不错的，剧情也不算太长，值得一玩。</p>
<h3 id="townscaper-城镇叠叠乐">Townscaper 城镇叠叠乐</h3>
<p><a href="https://store.steampowered.com/app/1291340/_/" target="_blank" rel="noopener">Townscaper</a></p>
<p>解压、休闲的建造游戏，我外甥很喜欢玩。</p>
<h3 id="doom--destiny">Doom &amp; Destiny</h3>
<p><a href="https://store.steampowered.com/app/318130/Doom__Destiny/" target="_blank" rel="noopener">Doom &amp; Destiny</a></p>
<p>恶搞也很正经的 D&amp;D，独立开发的日式 RPG 回合制游戏，对白喜剧向，</p>
<h3 id="mirror">Mirror</h3>
<p><a href="https://store.steampowered.com/app/644560/Mirror/" target="_blank" rel="noopener">Mirror</a></p>
<p>很好的国产小黄油，去掉黄色部分也可以玩一玩的。</p>
<h3 id="icey-艾希">ICEY 艾希</h3>
<p><a href="https://store.steampowered.com/app/553640/ICEY/" target="_blank" rel="noopener">ICEY</a></p>
<p>国产的动作游戏，做得还不错，7 小时左右通关，最有特点的要属其一直在吐槽的旁白。</p>
<h3 id="candleman-the-complete-journey-蜡烛人">Candleman: The Complete Journey 蜡烛人</h3>
<p><a href="https://store.steampowered.com/app/591630/Candleman_The_Complete_Journey/" target="_blank" rel="noopener">Candleman: The Complete Journey</a></p>
<p>感人又温馨的冒险小故事。</p>
<h3 id="mindustry">Mindustry</h3>
<p><a href="https://store.steampowered.com/app/1127400/Mindustry/" target="_blank" rel="noopener">Mindustry</a></p>
<p>有一点《异星工厂》的影子，也是很杀时间，喜欢的话可能会很入迷。</p>
<h3 id="shapez-异形工厂">Shapez 异形工厂</h3>
<p><a href="https://store.steampowered.com/app/1318690/Shapez/" target="_blank" rel="noopener">Shapez</a></p>
<p>《异星工厂》的简化版，看译名就能看出一些。。。</p>
<p>没有电力系统，不用费力找矿，矿产不会枯竭，上来就是传送带噼里啪啦地干。</p>
<p>但我还是觉得《异星工厂》更好玩。</p>
<h3 id="crashlands-崩溃大陆">Crashlands 崩溃大陆</h3>
<p><a href="https://store.steampowered.com/app/391730/Crashlands/" target="_blank" rel="noopener">Crashlands</a></p>
<p>类似《饥荒》风格的 ARPG，本地化包括宣传片很地道，对白喜剧向的。</p>
<h3 id="iron-snout">Iron Snout</h3>
<p><a href="https://store.steampowered.com/app/424280/Iron_Snout/" target="_blank" rel="noopener">Iron Snout</a></p>
<p>一款挺魔性的 2D 原地格斗类免费小游戏，第一次下载就玩了 4 个小时。</p>
<h3 id="quest-hunter">Quest Hunter</h3>
<p><a href="https://store.steampowered.com/app/487000/Quest_Hunter/" target="_blank" rel="noopener">Quest Hunter</a></p>
<p>即时战斗的 RPG，没有玩下去，Mac 带不动，比较吃力。</p>
<h3 id="refunct">Refunct</h3>
<p><a href="https://store.steampowered.com/app/406150/Refunct/" target="_blank" rel="noopener">Refunct</a></p>
<p>休闲放松的禅游戏，佛。</p>
<h3 id="unheard-疑案追声">Unheard 疑案追声</h3>
<p><a href="https://store.steampowered.com/app/942970/Unheard/" target="_blank" rel="noopener">Unheard</a></p>
<p>玩法比较新颖，但其实在游戏性上没有难度，只要全听一遍就行了，是那种上帝视觉自己摸索出剧情的感觉。最后的结局倒是没想到，有种《禁闭岛》的感觉。</p>
<h3 id="a-monsters-expedition-怪兽远征">A Monster&rsquo;s Expedition 怪兽远征</h3>
<p><a href="https://store.steampowered.com/app/1052990/_/" target="_blank" rel="noopener">A Monster&rsquo;s Expedition</a></p>
<p>类似推箱子的解密冒险类小游戏。</p>
<h3 id="oxygen-not-included-缺氧">Oxygen Not Included 缺氧</h3>
<p><a href="https://store.steampowered.com/app/457140/_/" target="_blank" rel="noopener">Oxygen Not Included</a></p>
<p>殖民模拟+基地建设，很杀时间的游戏，但我看着满屏的按钮，没有一个舒适的新引导真的不想玩下去。</p>
<p>不过玩进去的话，好评如潮，应该是很不错的，不知道现在有没有更新新手引导。</p>
<h3 id="storyteller">Storyteller</h3>
<p><a href="https://store.steampowered.com/app/1624540/Storyteller/" target="_blank" rel="noopener">Storyteller</a></p>
<p>利用不同场景+不同人物编 X 格漫画的小游戏。很有新鲜感，不过游戏时间太短了。</p>
<h3 id="chrono-trigger-时空之轮时空之钥超时空之钥">Chrono Trigger 时空之轮/时空之钥/超时空之钥</h3>
<p><a href="https://store.steampowered.com/app/613830/CHRONO_TRIGGER/" target="_blank" rel="noopener">Chrono Trigger</a></p>
<p>御剑乘风来，除魔天地间。</p>
<p>能在虚拟机里流畅运行，<a href="https://gong-lue.com/PC-ChronoTrigger.html" target="_blank" rel="noopener">参考攻略</a>(<a href="/download/%e8%b6%85%e6%97%b6%e7%a9%ba%e4%b9%8b%e9%92%a5.zip">备份</a>)。</p>
<p>中文名《时空之轮》应该是港台名《超時空之鑰》的错误翻译。</p>
<p>打通之后才发现竟然是将近三十年的老游戏了，这应该是那个时代的神了。</p>
<p>友情提示：“龙之领域”的额外任务没有任何意义，不用拿这一系列的装备也可以轻松通关，“龙之领域”系列任务要在两个时间线之间跑断腿，比魔兽世界外域任务还恶心。（因为右下角的山需要手动上山，再手动下山，来回无数趟。）</p>
<h3 id="terraria-泰拉瑞亚">Terraria 泰拉瑞亚</h3>
<p><a href="https://store.steampowered.com/app/105600/Terraria/" target="_blank" rel="noopener">Terraria</a></p>
<p>好评如潮的游戏，花时间入门后，应该能找到很大的乐趣，我还没有入门。</p>
<h3 id="inscryption-邪恶冥刻">Inscryption 邪恶冥刻</h3>
<p><a href="https://store.steampowered.com/app/1092790/_/" target="_blank" rel="noopener">Inscryption</a></p>
<p>恐怖画风的卡牌对战游戏，各个元素做得都比较丰富。</p>
<h3 id="shogun-showdown-将军对决">Shogun Showdown 将军对决</h3>
<p><a href="https://store.steampowered.com/app/2084000/_/" target="_blank" rel="noopener">Shogun Showdown</a></p>
<p>很有创意的忍者题材像素风 rouge 回合制小游戏。</p>
<p>玩法新颖，按照敌人的血量和动机，每次使用不同的技能搭配和走位来过关。</p>
<p>设计得也非常好，不同的组合都有一战之力。</p>
<h3 id="patricks-parabox">Patrick&rsquo;s Parabox</h3>
<p><a href="https://store.steampowered.com/app/1260520/Patricks_Parabox/" target="_blank" rel="noopener">Patrick&rsquo;s Parabox</a></p>
<p>加入了很多创新元素的推箱子。</p>
<h2 id="感觉一般">感觉一般</h2>
<h3 id="stacklands">Stacklands</h3>
<p><a href="https://store.steampowered.com/app/1948280/Stacklands/" target="_blank" rel="noopener">Stacklands</a></p>
<p>将生存建造简化为卡牌，不断地合成、发展、升级、战斗。</p>
<p>建议打折入，通关一次后着实不想打开第二次。</p>
<h3 id="soulstone-survivors-灵魂石幸存者">Soulstone Survivors 灵魂石幸存者</h3>
<p>类似吸血鬼幸存者和土豆兄弟，但也就刚玩的时候爽一点，尝试技能搭配后，马上就变成重复的劳动作业，需要毫无乐趣地刷刷刷然后解锁东西和升科技。</p>
<p>最后技能范围很大，已经眼花缭乱了，关闭特效，变成一个躲红圈的游戏，几个小时的游戏时间就腻了。</p>
<h3 id="wildermyth-漫野奇谭">Wildermyth 漫野奇谭</h3>
<p><a href="https://store.steampowered.com/app/763890/_/" target="_blank" rel="noopener">Wildermyth</a></p>
<p>好评如潮的策略 RPG 游戏，但我觉得有些无聊，玩不下去。</p>
<h3 id="home-behind-归家异途">Home Behind 归家异途</h3>
<p><a href="https://store.steampowered.com/app/467960/_/" target="_blank" rel="noopener">Home Behind</a></p>
<p>轻度 Roguelike 横版冒险游戏。</p>
<p>但设计方面有些诡异，我真就是一直在考虑丢什么东西，背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。</p>
<h3 id="pyre">Pyre</h3>
<p><a href="https://store.steampowered.com/app/462770/Pyre/" target="_blank" rel="noopener">Pyre</a></p>
<p>画风很棒的角色扮演游戏，但要是没有这个无聊3V3模式（其实就是一个套路虐杀电脑），我没准还能玩下去。</p>
<h3 id="cat-quest-猫咪斗恶龙">Cat Quest 猫咪斗恶龙</h3>
<p><a href="https://store.steampowered.com/app/593280/Cat_Quest/" target="_blank" rel="noopener">Cat Quest</a></p>
<p>画风可爱，支持手柄的动作 RPG，但是整个游戏的玩法比较单一，走任务，下洞穴，打怪兽，无限重复。</p>
<h3 id="circle-empires-环形帝国">Circle Empires 环形帝国</h3>
<p><a href="https://store.steampowered.com/app/834740/Circle_Empires/" target="_blank" rel="noopener">Circle Empires</a></p>
<p>休闲策略小游戏，建议打折入，生命力并不是很持久，很快就腻了。</p>
<h3 id="glass-masquerade">Glass Masquerade</h3>
<p><a href="https://store.steampowered.com/app/511470/Glass_Masquerade/" target="_blank" rel="noopener">Glass Masquerade</a></p>
<p>无聊的拼图游戏，却做的很认真。适合修身养性，闲来无事的时候可以搞一把，建议打折入。</p>
<h3 id="goat-simulator-山羊模拟器">Goat Simulator 山羊模拟器</h3>
<p><a href="https://store.steampowered.com/app/265930/Goat_Simulator/" target="_blank" rel="noopener">Goat Simulator</a></p>
<p>并无什么可取之处，休闲娱乐解压的游戏。</p>
<h3 id="lost-castle-失落城堡">Lost Castle 失落城堡</h3>
<p><a href="https://store.steampowered.com/app/434650/Lost_Castle/" target="_blank" rel="noopener">Lost Castle</a></p>
<p>Roguelike 类的动作冒险类游戏，给朋友买了一份一起联机玩的，但个人感觉一般，和朋友都没啥兴趣。</p>
<h3 id="love-esquire-小兵求爱记">Love Esquire 小兵求爱记</h3>
<p><a href="https://store.steampowered.com/app/849740/_Love_Esquire/" target="_blank" rel="noopener">Love Esquire</a></p>
<p>恋爱养成类小游戏，配音和立绘都不错，就是比较无聊。</p>
<h3 id="meteor-60-seconds-地球灭亡前60秒">Meteor 60 Seconds! 地球灭亡前60秒</h3>
<p><a href="https://store.steampowered.com/app/788770/Meteor_60_Seconds/" target="_blank" rel="noopener">Meteor 60 Seconds!</a></p>
<p>没啥意义的免费游戏，图个乐。</p>
<h3 id="kingdom-two-crowns-王国两位君主">Kingdom Two Crowns 王国：两位君主</h3>
<p><a href="https://store.steampowered.com/app/701160/" target="_blank" rel="noopener">Kingdom Two Crowns</a></p>
<p>建造、生产、防御、进攻。</p>
<p>其实更适合双人游戏，我一个人双线操作的，找不到多大乐趣。</p>
<p>初始的 1~5 岛挺没劲的，重复操作，跑断腿，后面的我也没玩，太杀时间了，还没怎么样呢，天亮了。</p>
<h3 id="ftl-faster-than-light">FTL: Faster Than Light</h3>
<p><a href="https://store.steampowered.com/app/212680/FTL_Faster_Than_Light/" target="_blank" rel="noopener">FTL: Faster Than Light</a></p>
<p>类似《杀戮尖塔》的爬塔，只不过改成了星际。</p>
<p>非简单难度过于困难，Rogue 元素太看脸，玩了几天再也没打开，最主要的是我没有找到乐趣。</p>
<h2 id="不推荐">不推荐</h2>
<h3 id="hacknet">Hacknet</h3>
<p><a href="https://store.steampowered.com/app/365450/Hacknet/" target="_blank" rel="noopener">Hacknet</a></p>
<p>模拟黑客的小游戏，Mac 上全屏有卡死的 Bug。</p>
<h3 id="mount--blade-warband-骑马与砍杀">Mount &amp; Blade: Warband 骑马与砍杀</h3>
<p><a href="https://store.steampowered.com/app/48700/Mount__Blade_Warband/" target="_blank" rel="noopener">Mount &amp; Blade: Warband</a></p>
<p>是个口碑很好的老游戏，但没有修复 Mac 版的闪退问题，不建议购买。</p>
<h3 id="hyper-knights">Hyper Knights</h3>
<p><a href="https://store.steampowered.com/app/597150/Hyper_Knights/" target="_blank" rel="noopener">Hyper Knights</a></p>
<p>策略 + 动作的攻城略地游戏，但新鲜感很快就会过去，最后既不「策略」，也玩腻了「杀人」。</p>
<h3 id="project-highrise">Project Highrise</h3>
<p><a href="https://store.steampowered.com/app/423580/Project_Highrise/" target="_blank" rel="noopener">Project Highrise</a></p>
<p>模拟经营游戏，看着感觉还行，但其实在数值上没有下工夫，很多设定都做得不合理，做得很糟糕。</p>
<h3 id="startup-company">Startup Company</h3>
<p><a href="https://store.steampowered.com/app/606800/Startup_Company/" target="_blank" rel="noopener">Startup Company</a></p>
<p>我还预购了这款游戏，但其实做得很一般。</p>
<ul>
<li>游戏需要雇佣员工开发15种【组件】。</li>
<li>再雇佣另一个工种将15种【组件】升级为不同的17种【模块】</li>
<li>以【模块】为原材料，可以研发不同的4种【产品】。</li>
<li>以【模块】为原材料，升级自己的【产品】。</li>
</ul>
<p>以上，操作流程极其简单、无聊、繁琐、重复。</p>
<h3 id="super-star">Super Star</h3>
<p><a href="https://store.steampowered.com/app/503300/Super_Star/" target="_blank" rel="noopener">Super Star</a></p>
<p>又一个国产小黄油，但玩法单一无聊。</p>
<h3 id="will-a-wonderful-world--will美好世界">WILL: A Wonderful World  WILL：美好世界</h3>
<p><a href="https://store.steampowered.com/app/588040/WILL_A_Wonderful_World__WILL/" target="_blank" rel="noopener">WILL: A Wonderful World</a></p>
<p>文字类游戏，但剧本真的是太差了。</p>
<p>剧情那叫个幼稚无聊。。。</p>
<p>改变剧情全靠主观臆测，毫无逻辑性，作为一个改变剧情的游戏，是最大的失败。</p>
<p>游戏性无限接近于零。</p>
<h3 id="mahjongsoul-雀魂">MahjongSoul 雀魂</h3>
<p><a href="https://store.steampowered.com/app/1329410/MahjongSoul/" target="_blank" rel="noopener">MahjongSoul</a></p>
<p>再玩雀魂我是傻逼。</p>
<h3 id="worldbox---god-simulator-上帝模拟器">WorldBox - God Simulator 上帝模拟器</h3>
<p><a href="https://steamcommunity.com/app/1206560" target="_blank" rel="noopener">WorldBox - God Simulator</a></p>
<p>上帝模拟器，看小人生，看小人打，看小人死。。。</p>
<p>第一次玩很新鲜，一口气干了 4 个小时，但我没打开第二次，还在 early access，价格也偏高。</p>
<h3 id="richman-10-大富翁-10">RichMan 10 大富翁 10</h3>
<p><a href="https://store.steampowered.com/app/1162520/10_RichMan_10/" target="_blank" rel="noopener">RichMan 10</a></p>
<p>爱之深则恨之切，小时候很喜欢的游戏，现在却这副模样。</p>
<p>一家老牌游戏公司，一款 30 周年续作，能做出个这么个东西。</p>
<p>实际体验，这是一个赶工的粗糙作品，Bug 一堆。</p>
<p>姚仙居然还是监制。</p>
<p>在仙剑七进入最终开发阶段出了一个大富翁 10，这是在给仙剑七筹（骗）钱。</p>
<h2 id="优秀黄油">优秀黄油</h2>
<p>能在虚拟机里流畅运行。</p>
<p><a href="https://store.steampowered.com/app/1227890" target="_blank" rel="noopener">夏日狂想曲</a> 。。。</p>
<p><a href="https://store.steampowered.com/app/1786790" target="_blank" rel="noopener">魔法少女天穹法妮雅</a> しもばしら工房出品，黄油天花板，天花板中板。。。</p>
<p><a href="https://store.steampowered.com/app/1078350/Ambrosia/" target="_blank" rel="noopener">仙肴圣餐</a> しもばしら工房的早期作品。</p>
<p><a href="https://www.dlsite.com/maniax/work/=/product_id/RJ386773" target="_blank" rel="noopener">エニシアと契約紋 ～馬蹄通りの小聖女～</a> しもばしら工房最新作品，暂时还没有上架 Steam。</p>
]]></content:encoded>
    </item>
    <item>
      <title>我的 Mac 软件/工具列表</title>
      <link>https://dvel.me/posts/my-mac-software-list/</link>
      <pubDate>Sat, 01 Aug 2020 21:56:58 +0800</pubDate>
      <guid>https://dvel.me/posts/my-mac-software-list/</guid>
      <description>这是一份 macOS 下的软件/工具清单，涵盖了效率、编程、日常等各个领域，其中包括密碼管理器、窗口管理、播放器、PDF 编辑器等工具。总之，这个清单可以帮助您在新的 Mac 上迅速获得良好的使用体验。</description>
      <content:encoded><![CDATA[<blockquote>
<p>又双叒叕 Mac 换新，之前的一堆软件、服务弄得太乱，迫于洁癖没用时光机恢复，这里记录一下 macOS 下我常用的软件/工具列表，算是个推荐清单，也便于自己以后查阅。</p>
</blockquote>
<h2 id="新机快速还原使用体验">新机快速还原使用体验</h2>
<ul>
<li><a href="https://mimestream.com/" target="_blank" rel="noopener">Mimestream</a> 一个 Gmail API 的邮箱客户端</li>
<li><a href="https://bitwarden.com/" target="_blank" rel="noopener">Bitwarden</a> 密码管理器，确实没有 1Password 体验好，但一年才十刀</li>
<li><a href="https://nssurge.com/" target="_blank" rel="noopener">Surge</a> 科学上网</li>
<li><a href="https://www.dropbox.com/" target="_blank" rel="noopener">Dropbox</a> 同步了大部分的软件配置及重要备份</li>
<li><a href="https://www.alfredapp.com/" target="_blank" rel="noopener">Alfred</a> macOS 第一效率工具</li>
<li><a href="https://qspace.awehunt.com/zh-cn/index.html" target="_blank" rel="noopener">QSpace</a> Finder 增强</li>
<li><a href="https://rime.im/" target="_blank" rel="noopener">Rime</a> 输入法</li>
</ul>
<h2 id="效率">效率</h2>
<ul>
<li><a href="https://flexibits.com/fantastical" target="_blank" rel="noopener">Fantastical</a> 日历</li>
<li><a href="https://culturedcode.com/things/" target="_blank" rel="noopener">Things</a> GTD</li>
<li><a href="https://imazing.com/" target="_blank" rel="noopener">iMazing</a> iPhone 备份</li>
<li><a href="https://bjango.com/mac/istatmenus/" target="_blank" rel="noopener">iStat Menus</a> 菜单栏状态监控</li>
<li><a href="https://github.com/aonez/Keka" target="_blank" rel="noopener">Keka</a> 解压缩</li>
<li><a href="https://magnet.crowdcafe.com/" target="_blank" rel="noopener">Magnet</a> 窗口管理</li>
<li><a href="https://www.macbartender.com/Bartender4/" target="_blank" rel="noopener">Bartender 4</a> 菜单栏管理</li>
<li><a href="https://cleanshot.com/" target="_blank" rel="noopener">CleanShot X</a> 截图</li>
<li><a href="https://karabiner-elements.pqrs.org/" target="_blank" rel="noopener">Karabiner</a> 键位映射神器</li>
</ul>
<h2 id="编程">编程</h2>
<ul>
<li><a href="https://www.jetbrains.com/" target="_blank" rel="noopener">JetBrains 全家桶</a></li>
<li><a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a></li>
<li><a href="https://git-fork.com/" target="_blank" rel="noopener">Fork</a> Git GUI</li>
<li><a href="https://iterm2.com/" target="_blank" rel="noopener">iTerm 2</a> 终端</li>
<li><a href="https://paw.cloud/" target="_blank" rel="noopener">Paw</a> API 工具</li>
<li><a href="https://www.renfei.org/snippets-lab/" target="_blank" rel="noopener">SnippetsLab</a> 代码片段管理</li>
</ul>
<h2 id="日常">日常</h2>
<ul>
<li><a href="https://iina.io/" target="_blank" rel="noopener">IINA</a> 播放器</li>
<li><a href="https://www.spotify.com/" target="_blank" rel="noopener">Spotify</a> &amp; <a href="https://github.com/ddddxxx/LyricsX" target="_blank" rel="noopener">LyricsX</a> 音乐</li>
<li><a href="https://typora.io/" target="_blank" rel="noopener">Typora</a> Markdown 编辑器</li>
<li><a href="https://netnewswire.com/" target="_blank" rel="noopener">NetNewsWire</a> RSS 订阅</li>
<li><a href="https://pdfexpert.com/" target="_blank" rel="noopener">PDF Expert</a> PDF 编辑器</li>
<li><a href="https://wl879.github.io/apps/picview/" target="_blank" rel="noopener">PictureView</a> 大量图片浏览</li>
<li><a href="https://www.qbittorrent.org/" target="_blank" rel="noopener">qBittorrent</a> 或 <a href="https://github.com/c0re100/qBittorrent-Enhanced-Edition" target="_blank" rel="noopener">qBittorrent Enhanced Edition</a> 下载</li>
<li><a href="https://freemacsoft.net/appcleaner/" target="_blank" rel="noopener">AppCleaner</a> 卸载工具</li>
<li><a href="https://rustdesk.com/" target="_blank" rel="noopener">RustDesk</a> 远程控制</li>
</ul>
<h2 id="翻译字典">翻译/字典</h2>
<ul>
<li><a href="https://www.eudic.net/" target="_blank" rel="noopener">欧路词典</a> 查单词</li>
<li><a href="http://goldendict.org/" target="_blank" rel="noopener">GoldenDict</a> 支持 mdx 格式的免费字典</li>
<li><a href="https://github.com/ripperhe/Bob" target="_blank" rel="noopener">Bob</a> 句子翻译（搭配插件 <a href="https://github.com/roojay520" target="_blank" rel="noopener">roojay520</a>/<strong><a href="https://github.com/roojay520/bobplugin-google-translate" target="_blank" rel="noopener">bobplugin-google-translate</a></strong>）
<ul>
<li>免费开源的平替：<a href="https://github.com/tisfeng/Easydict" target="_blank" rel="noopener">Easydict</a></li>
</ul>
</li>
</ul>
<h2 id="小工具">小工具</h2>
<ul>
<li><a href="https://apps.apple.com/us/app/amphetamine/id937984704" target="_blank" rel="noopener">Amphetamine</a> 防止自动熄屏</li>
<li><a href="https://apps.apple.com/us/app/balance-lock/id1019371109" target="_blank" rel="noopener">Balance Lock</a> 锁定声道平衡，防止祖传 bug</li>
<li><a href="https://www.omnigroup.com/more" target="_blank" rel="noopener">OmniDiskSweeper</a> 小巧的查找大文件工具</li>
<li><a href="https://github.com/michaelvillar/timer-app" target="_blank" rel="noopener">Timer</a> 简易计时器</li>
<li><a href="http://tbswitcher.rugarciap.com/" target="_blank" rel="noopener">Turbo Boost Switcher</a> 关闭 Intel CPU 的 Turbo Boost 功能</li>
</ul>
<h2 id="字体">字体</h2>
<ul>
<li><a href="https://sourcefoundry.org/hack/" target="_blank" rel="noopener">Hack</a> 代码和终端都用它，这字体看着太舒服了</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>《Flask Web 开发》笔记</title>
      <link>https://dvel.me/posts/flask-web-development-note/</link>
      <pubDate>Sat, 22 Feb 2020 23:44:23 +0800</pubDate>
      <guid>https://dvel.me/posts/flask-web-development-note/</guid>
      <description>书籍《Flask Web 开发》的学习笔记。粗略的记录了一些大纲、每小节重点、难点、可能会遗忘、懒得记忆、方便查阅的东西，配合目录查阅。</description>
      <content:encoded><![CDATA[<p>《Flask Web 开发》第二版</p>
<p>豆瓣地址：<a href="https://book.douban.com/subject/30293851/" target="_blank" rel="noopener">https://book.douban.com/subject/30293851/</a></p>
<h2 id="第-1-章---安装">第 1 章 - 安装</h2>
<h3 id="flask-哲学">Flask 哲学</h3>
<p>Flask 自开发伊始就被设计为可扩展的框架，它具有一个包含基本服务的强健核心，其他功能则可通过扩展实现。</p>
<p>Flask 有 3 个主要依赖：</p>
<ul>
<li>路由、调试和 Web 服务器网关接口（WSGI，Web server gateway interface）子系统由 Werkzeug 提供；</li>
<li>模板系统由 Jinja2 提供；</li>
<li>命令行集成由 Click 提供。</li>
</ul>
<p>开发者可以任意挑选符合项目需求的扩展，甚至可以自行开发。这和大型框架的做法相反，大型框架往往已经替你做出了大多数决定，难以（有时甚至不允许）使用替代方案。</p>
<h3 id="venv">venv</h3>
<p>在 Python 3 中由标准库 <code>venv</code> 创建虚拟环境：</p>
<pre tabindex="0"><code>$ python3 -m venv virtual-environment-name
</code></pre><p>激活虚拟环境：</p>
<pre tabindex="0"><code>$ source venv/bin/activate
</code></pre><p>取消：</p>
<pre tabindex="0"><code>$ deactivate
</code></pre><p>另一种使用虚拟环境的方法：</p>
<p>在终端中执行 <code>$ venv/bin/python</code> 直接激活虚拟环境中的交互模式，退出时直接按下 ctrl + D。</p>
<br/>
<h2 id="第-2-章---应用的基本结构">第 2 章 - 应用的基本结构</h2>
<h3 id="初始化">初始化</h3>
<p>所有 Flask 应用都必须创建一个<strong>应用实例</strong>，通常由下述代码创建：</p>
<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="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></code></pre></div><p>Web 服务器使用 WSGI 协议，把接受自客户端的所有请求转发给这个对象处理。</p>
<h3 id="路由和视图函数">路由和视图函数</h3>
<p>客户端(浏览器)把请求发送给 Web 服务器，Web 服务器再把请求发送给 Flask 应用实例。</p>
<p>应用实例需要知道对每个 URL 的请求要运行哪些代码，所有保存了一个 URL 到 Python 函数的映射关系。</p>
<p>处理 URL 和函数之间关系的程序称为<strong>路由</strong>。</p>
<p>Flask 使用  <code>app.route</code> 装饰器或者更传统的 <code>app.add_url_rule()</code> 方法构建映射：</p>
<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;/user/&lt;name&gt;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">user</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;&lt;h1&gt;Hello </span><span class="si">{}</span><span class="s1">!&lt;/h1&gt;&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
</span></span></code></pre></div><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">index</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;&lt;h1&gt;Hello World!&lt;/h1&gt;&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="s1">&#39;index&#39;</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
</span></span></code></pre></div><p><code>index()</code> 这样处理入站请求的函数称为<strong>视图函数</strong>。</p>
<h3 id="一个完整的应用">一个完整的应用</h3>
<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="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></span><span class="line"><span class="cl"><span class="nd">@app.route</span><span class="p">(</span><span class="s1">&#39;/)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">index</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;&lt;h1&gt;Hello World!&lt;/h1&gt;&#39;</span>
</span></span></code></pre></div><h3 id="web-开发服务器">Web 开发服务器</h3>
<p>Flask 自带 Web 开发服务器，通过 <code>flask run</code> 命令启动。这个命令在 <code>FLASK_APP</code> 环境变量指定的 Python 脚本中寻找应用实例。</p>
<pre tabindex="0"><code>$ export FLASK_APP=hello.py
$ flask run
</code></pre><h3 id="动态路由">动态路由</h3>
<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;/user/&lt;name&gt;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">user</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s1">&#39;&lt;h1&gt;Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">!&lt;/h1&gt;&#39;</span>
</span></span></code></pre></div><h3 id="调试模式">调试模式</h3>
<p>Flask 应用可以在<strong>调试模式</strong>中运行，在调试模式下，开发服务器会默认加载<strong>重载器</strong>和<strong>调试器</strong>。</p>
<p>**重载器：**Flask 会监视项目中的所有源码文件，发现变动时自动重启服务器。</p>
<p>**调试器：**调试器是一个基于 Web 的工具，当应用抛出未处理的异常时，它会出现在浏览器中。</p>
<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">FLASK_APP</span><span class="o">=</span>hello.py
</span></span><span class="line"><span class="cl">$ <span class="nb">export</span> <span class="nv">FLASK_DEBUG</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">export</span> <span class="nv">FLASK_ENV</span><span class="o">=</span>development <span class="o">(</span>效果同上<span class="o">)</span>
</span></span><span class="line"><span class="cl">$ flask run
</span></span></code></pre></div><h3 id="命令行选项">命令行选项</h3>
<p><code>flask shell</code> 命令在应用上下文中打开一个 Python shell 会话，可以运行维护任务、测试、调试问题。</p>
<h3 id="请求-响应循环">请求-响应循环</h3>
<h4 id="上下文">上下文</h4>
<p>为了避免大量可有可无的参数把视图函数弄得一团糟，Flask 使用上下文临时把某些对象变为全局可访问。在多线程服务器中，Flask 使用上下文让特点的变量在一个线程中全局可访问，与此同时不会干扰其他线程。</p>
<table>
  <thead>
      <tr>
          <th>变量名</th>
          <th>上下文</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>current_app</td>
          <td>应用上下文</td>
          <td>当前应用的应用实例</td>
      </tr>
      <tr>
          <td>g</td>
          <td>应用上下文</td>
          <td>处理请求时用作临时存储的对象，每次请求都会重设这个变量</td>
      </tr>
      <tr>
          <td>request</td>
          <td>请求上下文</td>
          <td>请求对象，封装了客户端发出的 HTTP 请求中的内容</td>
      </tr>
      <tr>
          <td>session</td>
          <td>请求上下文</td>
          <td>用户会话，值为一个字典，存储请求之间需要『记住』的值</td>
      </tr>
  </tbody>
</table>
<h4 id="flask-请求对象-request">Flask 请求对象 (request)</h4>
<table>
  <thead>
      <tr>
          <th>属性或方法</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>form</td>
          <td>一个字典，存储请求提交的所有表单字段</td>
      </tr>
      <tr>
          <td>args</td>
          <td>一个字典，存储通过 URL 查询字符串传递的所有参数</td>
      </tr>
      <tr>
          <td>values</td>
          <td>一个字典，form 和 args 的合集</td>
      </tr>
      <tr>
          <td>cookies</td>
          <td>一个字典，存储请求的所有 cookies</td>
      </tr>
      <tr>
          <td>headers</td>
          <td>一个字典，存储请求的所有 HTTP 首部</td>
      </tr>
      <tr>
          <td>files</td>
          <td>一个字典，存储请求上传的所有文件</td>
      </tr>
      <tr>
          <td>get_data()</td>
          <td>返回请求主体缓冲的数据</td>
      </tr>
      <tr>
          <td>get_json()</td>
          <td>返回一个 Python 字典，包含解析请求主体后得到的 JSON</td>
      </tr>
      <tr>
          <td>blueprint</td>
          <td>处理请求的 Flask 蓝本的名称；蓝本在第 7 章介绍</td>
      </tr>
      <tr>
          <td>endpoint</td>
          <td>处理请求的 Flask 端点的名称；Flask 把视图函数的名称用作路由端点的名称</td>
      </tr>
      <tr>
          <td>scheme</td>
          <td>URL 方案（http 或 https）</td>
      </tr>
      <tr>
          <td>is_secure()</td>
          <td>通过安全的连接（HTTPS）发送请求时返回 True</td>
      </tr>
      <tr>
          <td>host</td>
          <td>请求定义的主机名，如果客户端定义了端口号，还包括端口号</td>
      </tr>
      <tr>
          <td>path</td>
          <td>URL 的路径部分</td>
      </tr>
      <tr>
          <td>query_string</td>
          <td>URL 的查询字符串部分，返回原始二进制值</td>
      </tr>
      <tr>
          <td>full_path</td>
          <td>URL 的路径和查询字符串部分</td>
      </tr>
      <tr>
          <td>url</td>
          <td>客户端请求的完整 URL</td>
      </tr>
      <tr>
          <td>base_url</td>
          <td>同 url，但没有查询字符串部分</td>
      </tr>
      <tr>
          <td>remote_addr</td>
          <td>客户端的 IP 地址</td>
      </tr>
      <tr>
          <td>environ</td>
          <td>请求的原始 WSGI 环境字典</td>
      </tr>
  </tbody>
</table>
<h4 id="请求钩子">请求钩子</h4>
<p>有时在处理请求之前或之后执行代码会很有用，但为了避免每个视图函数中都重复编写代码，Flask 提供了注册通用函数的功能，通过装饰器实现。</p>
<table>
  <thead>
      <tr>
          <th>装饰器</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>before_request</code></td>
          <td>注册一个函数，在每次请求之前运行。</td>
      </tr>
      <tr>
          <td><code>before_first_request</code></td>
          <td>注册一个函数，只在处理第一个请求之前运行。可以通过这个钩子添加服务器初始化任务。</td>
      </tr>
      <tr>
          <td><code>after_request</code></td>
          <td>注册一个函数，如果没有未处理的异常抛出，在每次请求之后运行。</td>
      </tr>
      <tr>
          <td><code>teardown_request</code></td>
          <td>注册一个函数，即使有未处理的异常抛出，也在每次请求之后运行。</td>
      </tr>
  </tbody>
</table>
<p>在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 <code>g</code>。</p>
<h4 id="响应">响应</h4>
<p>如果视图函数返回的响应需要使用不同的状态码，可以把数字代码作为第二个返回值。</p>
<p>Flask 视图函数还可以返回一个响应对象——<code>make_response()</code>。</p>
<p>重定向，由于使用频繁，Flask 提供了 <code>redirect()</code> 辅助函数。</p>
<br/>
<h2 id="第-3-章---模板">第 3 章 - 模板</h2>
<h3 id="jinja2-模板引擎">Jinja2 模板引擎</h3>
<p><strong>渲染模板</strong></p>
<p>Flask 提供的 <code>render_template()</code> 函数把 Jinja2 模板引擎集成到了应用中。</p>
<p><strong>变量</strong></p>
<p>模板中使用 <code>{{ name }}</code> 结构表示一个变量，支持复杂类型如列表、字典、对象。</p>
<p>支持过滤器：<code>{{ name|capitalize }}</code>。</p>
<p>支持结构控制、宏（类似函数）。</p>
<p>支持模板继承：<code>{% extends &quot;bootstrap/base.html&quot; %}</code> 及 <code>{{ super() }}</code>。</p>
<h3 id="初始化扩展">初始化扩展</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">bootstrap</span> <span class="o">=</span> <span class="n">Bootstrap</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</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"><span class="n">bootstrap</span> <span class="o">=</span> <span class="n">Bootstrap</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_app</span><span class="p">(</span><span class="n">config_name</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">bootstrap</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># ...</span>
</span></span></code></pre></div><h3 id="自定义错误页面">自定义错误页面</h3>
<p>使用 <code>@app.errorhandler(404)</code> 装饰器。</p>
<h3 id="链接">链接</h3>
<p><code>url_for()</code> 辅助函数帮助在模板中构建正确的 URL。</p>
<p>用法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 以视图函数名作为参数，以 app.add_url_route() 定义路由时，使用端点名</span>
</span></span><span class="line"><span class="cl"><span class="n">url_for</span><span class="p">(</span><span class="s1">&#39;index&#39;</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="c1"># 绝对地址</span>
</span></span><span class="line"><span class="cl"><span class="n">url_for</span><span class="p">(</span><span class="s1">&#39;index&#39;</span><span class="p">,</span> <span class="n">_external</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># http://localhost:5000/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 动态 URL</span>
</span></span><span class="line"><span class="cl"><span class="n">url_for</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;john&#39;</span><span class="p">,</span> <span class="n">page</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># /user/john?page=2&amp;version=1</span>
</span></span></code></pre></div><br/>
<h2 id="第-4-章---web-表单">第 4 章 - Web 表单</h2>
<h3 id="表单">表单</h3>
<p>使用 <code>Flask-WTF</code>  定义表单：</p>
<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_wtf</span> <span class="kn">import</span> <span class="n">FlaskForm</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">wtforms</span> <span class="kn">import</span> <span class="n">StringField</span><span class="p">,</span> <span class="n">SubmitField</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">wtforms.validators</span> <span class="kn">import</span> <span class="n">DataRequired</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">NameForm</span><span class="p">(</span><span class="n">FlaskForm</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span> <span class="o">=</span> <span class="n">StringField</span><span class="p">(</span><span class="s1">&#39;What is your name?&#39;</span><span class="p">,</span> <span class="n">validators</span><span class="o">=</span><span class="p">[</span><span class="n">DataRequired</span><span class="p">()])</span>
</span></span><span class="line"><span class="cl">    <span class="n">submit</span> <span class="o">=</span> <span class="n">SubmitField</span><span class="p">(</span><span class="s1">&#39;Submit&#39;</span><span class="p">)</span>
</span></span></code></pre></div><p>使用 <code>Flask-Bootstrap</code> 提供的高层级辅助函数 <code>quick_form()</code> 渲染 <code>Flask-WTF</code> 表单：</p>
<pre tabindex="0"><code>{% import &#34;bootstrap/wtf.html&#34; as wtf %}
{{ wtf.quick_form(form) }}
</code></pre><p>在视图函数中处理表单：</p>
<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;/&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;GET&#39;</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">index</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">form</span> <span class="o">=</span> <span class="n">NameForm</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">validate_on_submit</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="n">name</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">data</span>
</span></span><span class="line"><span class="cl">        <span class="n">form</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s1">&#39;&#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;index.html&#39;</span><span class="p">,</span> <span class="n">form</span><span class="o">=</span><span class="n">form</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="post--redirect--get-模式">Post / Redirect / Get 模式</h3>
<p>Post / Redirect / Get 简称 PRG，是一种用来防止表单重复提交数据的一种 Web 设计模式。</p>
<p>​</p>
<h3 id="闪现消息">闪现消息</h3>
<p><code>flaks.flash</code> 的简单使用。</p>
<br/>
<h2 id="第-5-章-数据库">第 5 章 数据库</h2>
<h3 id="flask-sqlalchemy-简单配置-sqlite-数据库">Flask-SQLAlchemy 简单配置 SQLite 数据库</h3>
<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">flask_sqlalchemy</span> <span class="kn">import</span> <span class="n">SQLAlchemy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">basedir</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">abspath</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">dirname</span><span class="p">(</span><span class="vm">__file__</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">config</span><span class="p">[</span><span class="s1">&#39;SQLALCHEMY_DATABASE_URI&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;sqlite:///&#39;</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">basedir</span><span class="p">,</span> <span class="s1">&#39;data.sqlite&#39;</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">config</span><span class="p">[</span><span class="s1">&#39;SQLALCHEMY_TRACK_MODIFICATIONS&#39;</span><span class="p">]</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">db</span> <span class="o">=</span> <span class="n">SQLAlchemy</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="模型-一对多">模型 （一对多）</h3>
<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">Role</span><span class="p">(</span><span class="n">db</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">__tablename__</span> <span class="o">=</span> <span class="s1">&#39;roles&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</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">name</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">64</span><span class="p">),</span> <span class="n">unique</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">users</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="n">backref</span><span class="o">=</span><span class="s1">&#39;role&#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">def</span> <span class="fm">__repr__</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">return</span> <span class="s1">&#39;&lt;Role </span><span class="si">%r</span><span class="s1">&gt;&#39;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</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">User</span><span class="p">(</span><span class="n">db</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">__tablename__</span> <span class="o">=</span> <span class="s1">&#39;users&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</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">username</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">64</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">index</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">role_id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">db</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s1">&#39;roles.id&#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">def</span> <span class="fm">__repr__</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">return</span> <span class="s1">&#39;&lt;User </span><span class="si">%r</span><span class="s1">&gt;&#39;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">username</span>
</span></span></code></pre></div><h3 id="数据库操作-flask-shell">数据库操作 （flask shell）</h3>
<p><strong>创建表</strong></p>
<pre tabindex="0"><code>&gt;&gt;&gt; from hello import db
&gt;&gt;&gt; db.create_all()
# 如果数据库文件已经存在，暴力删除再重新生成：
&gt;&gt;&gt; db.drop_all()
&gt;&gt;&gt; db.create_all()
</code></pre><p><strong>插入行</strong></p>
<pre tabindex="0"><code>&gt;&gt;&gt; from hello import Role,User
&gt;&gt;&gt; admin_role = Role(name=&#39;Admin&#39;)
&gt;&gt;&gt; mod_role = Role(name=&#39;Moderator&#39;)
&gt;&gt;&gt; user_role = Role(name=&#39;User&#39;)
&gt;&gt;&gt; user_john = User(username=&#39;john&#39;, role=admin_role)
&gt;&gt;&gt; user_susan = User(username=&#39;susan&#39;, role=user_role)
&gt;&gt;&gt; user_david = User(username=&#39;david&#39;, role=user_role)
# 数据库会话（事务）
&gt;&gt;&gt; db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david])
&gt;&gt;&gt; db.session.commit()
# 数据库会话支持回滚
&gt;&gt;&gt; db.session.rollback()
</code></pre><p><strong>修改行</strong></p>
<pre tabindex="0"><code>&gt;&gt;&gt; admin_role.name = &#39;Administrator&#39;
&gt;&gt;&gt; db.session.add(admin_role)
&gt;&gt;&gt; db.session.commit()
</code></pre><p><strong>删除行</strong></p>
<pre tabindex="0"><code>&gt;&gt;&gt; db.session.delete(mod_role)
&gt;&gt;&gt; db.session.commit()
</code></pre><p><strong>查询行</strong></p>
<pre tabindex="0"><code># 基本 all()
&gt;&gt;&gt; Role.query.all()
[&lt;Role &#39;Administrator&#39;&gt;, &lt;Role &#39;User&#39;&gt;]
&gt;&gt;&gt; User.query.all()
[&lt;User &#39;john&#39;&gt;, &lt;User &#39;susan&#39;&gt;, &lt;User &#39;david&#39;&gt;]

# 过滤器
&gt;&gt;&gt; User.query.filter_by(role=user_role).all()
[&lt;User &#39;susan&#39;&gt;, &lt;User &#39;david&#39;&gt;]

# 查看生成的原生 SQL 语句
&gt;&gt;&gt; str(User.query.filter_by(role=user_role))
&#39;SELECT users.id AS users_id, users.username AS users_username, users.role_id AS users_role_id \nFROM users \nWHERE ? = users.role_id&#39;

# 如果中途退出 shell 会话，加载示例：
user_role = Role.query.filter_by(name=&#39;User&#39;).first()

# 关闭自动执行查询
&gt;&gt;&gt; user_role.users
[&lt;User &#39;susan&#39;&gt;, &lt;User &#39;david&#39;&gt;]
# 在模型中加入 lazy=&#39;dynamic&#39; 参数
users = db.relationship(&#39;User&#39;, backref=&#39;role&#39;, lazy=&#39;dynamic&#39;)
# 可以使用过滤器了
&gt;&gt;&gt; user_role.users.order_by(User.username).all()
[&lt;User &#39;david&#39;&gt;, &lt;User &#39;susan&#39;&gt;]
</code></pre><h3 id="集成-python-shell">集成 Python shell</h3>
<p>通过 <code>app.shell_context_processor</code> 装饰器，在每次启动 <code>flask shell</code> 会话时自动导入数据库示例和模型：</p>
<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.shell_context_processor</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_shell_context</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="n">db</span><span class="p">,</span> <span class="n">User</span><span class="o">=</span><span class="n">User</span><span class="p">,</span> <span class="n">Role</span><span class="o">=</span><span class="n">Role</span><span class="p">)</span>
</span></span></code></pre></div><br/>
<h2 id="第-6-章-电子邮件">第 6 章 电子邮件</h2>
<p>使用 Flask-Mail 提供电子邮件支持，Python 的 <code>smtplib</code> 库不支持 OAuth2 验证方法，需要设置 Google 账户的「允许不够安全的应用的访问权限」。</p>
<p>配置：</p>
<pre tabindex="0"><code>app.config[&#39;MAIL_SERVER&#39;] = &#39;smtp.gmail.com&#39;
app.config[&#39;MAIL_PORT&#39;] = 587
app.config[&#39;MAIL_USE_TLS&#39;] = True
app.config[&#39;MAIL_USERNAME&#39;] = os.environ.get(&#39;MAIL_USERNAME&#39;)
app.config[&#39;MAIL_PASSWORD&#39;] = os.environ.get(&#39;MAIL_PASSWORD&#39;)
app.config[&#39;FLASKY_MAIL_SUBJECT_PREFIX&#39;] = &#39;[前缀]&#39;
app.config[&#39;FLASKY_MAIL_SENDER&#39;] = &#39;Flasky Admin &lt;xxx@gmail.com&gt;&#39;
app.config[&#39;FLASKY_ADMIN&#39;] = os.environ.get(&#39;FLASKY_ADMIN&#39;)
</code></pre><p>将敏感信息写入环境变量：</p>
<pre tabindex="0"><code>$ export MAIL_USERNAME=xxx@gmail.com       
$ export MAIL_PASSWORD=xxxxxxxx               
$ export FLASKY_ADMIN=xxx@gmail.com # 接收邮件的管理员
</code></pre><p>集成邮件发送功能：</p>
<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_mail</span> <span class="kn">import</span> <span class="n">Mail</span><span class="p">,</span> <span class="n">Message</span>
</span></span><span class="line"><span class="cl"><span class="n">mail</span> <span class="o">=</span> <span class="n">Mail</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_email</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">template</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">msg</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;FLASKY_MAIL_SUBJECT_PREFIX&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">subject</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                  <span class="n">sender</span><span class="o">=</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;FLASKY_MAIL_SENDER&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                  <span class="n">recipients</span><span class="o">=</span><span class="p">[</span><span class="n">to</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">msg</span><span class="o">.</span><span class="n">body</span> <span class="o">=</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template</span> <span class="o">+</span> <span class="s1">&#39;.txt&#39;</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">msg</span><span class="o">.</span><span class="n">html</span> <span class="o">=</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template</span> <span class="o">+</span> <span class="s1">&#39;.html&#39;</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">mail</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
</span></span></code></pre></div><p>编写视图函数：</p>
<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">if</span> <span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;FLASKY_ADMIN&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="n">send_email</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;FLASKY_ADMIN&#39;</span><span class="p">],</span> <span class="s1">&#39;New User&#39;</span><span class="p">,</span> <span class="s1">&#39;mail/new_user&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="n">user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span></code></pre></div><h2 id="第-7-章-大型应用的结构">第 7 章 大型应用的结构</h2>
<blockquote>
<p>提供一个可供中大型程序使用的应用结构</p>
</blockquote>
<h4 id="项目结构">项目结构：</h4>
<pre tabindex="0"><code>.
├── app/
│   ├── /__init__.py  
│   ├── /email.py
│   ├── /models.py
│   ├── /static/
│   ├── /templates/
│   ├── /main/
│      ├── /__init__.py
│      ├── /errors.py	
│      ├── /forms.py
│      ├── /views.py
├── migrations/
├── tests/
└── venv/
├── config.py
├── flasky.py
├── requirements.txt
</code></pre><p>编写配置模块，配合工厂函数可以创建多个实例，便于测试。</p>
<p>Flask 提供蓝本(blueprint)功能，蓝本中定义的路由和错误处理程序处于休眠状态，直到蓝本注册到应用上后才生效。</p>
<p>定义相关的环境变量启动 Flask：</p>
<pre tabindex="0"><code>$ export FLASKY_ADMIN=xxx@xxx.com
$ export MAIL_USERNAME=xxx@xxx.com
$ export MAIL_PASSWORD=xxx

$ export FLASK_APP=flasky.py
$ export FLASK_DEBUG=1

$ flask run
</code></pre><h4 id="需求文件-requirementstxt">需求文件 requirements.txt</h4>
<p>用 pip 生成 requirements.txt 文件：</p>
<pre tabindex="0"><code>$ pip freeze &gt;requirements.txt
</code></pre><p>安装或升级包后，需手动更新。</p>
<p>其他人利用 requirements.txt 文件创建副本，先创建好虚拟环境，执行以下命令：</p>
<pre tabindex="0"><code>$ pip install -r requirements.txt
</code></pre><h4 id="蓝本">蓝本</h4>
<p><a href="https://spacewander.github.io/explore-flask-zh" target="_blank" rel="noopener">Flask 之旅</a></p>
<p><a href="https://www.zhihu.com/question/31748237" target="_blank" rel="noopener">如何理解Flask中的蓝本</a></p>
<p>​</p>
<h2 id="其他">其他</h2>
<p>后续章节就是实战了，代码量太多了，没有做笔记了。。。</p>
]]></content:encoded>
    </item>
    <item>
      <title>用 sleepwatcher 让 Mac 在睡眠及唤醒时自动执行一些脚本</title>
      <link>https://dvel.me/posts/sleepwatcher-mac-auto-script/</link>
      <pubDate>Thu, 20 Feb 2020 18:18:09 +0800</pubDate>
      <guid>https://dvel.me/posts/sleepwatcher-mac-auto-script/</guid>
      <description>macOS 自带的 Automator.app 并没有给出睡眠及唤醒时的条件变量，不过可以通过 sleepwatcher 来监测并执行一些脚本。</description>
      <content:encoded><![CDATA[<p>macOS 自带的 Automator.app 并没有给出睡眠及唤醒时的条件变量，不过可以通过 <code>sleepwatcher</code> 来监测并执行一些脚本。</p>
<h2 id="sleepwatcher">sleepwatcher</h2>
<p>安装:</p>
<pre tabindex="0"><code>brew install sleepwatcher
</code></pre><p>安装完成后有使用提示，sleepwatcher 会在睡眠和唤醒时自动运行 <code>~/.sleep</code> 和 <code>~/.wakeup</code>。</p>
<p>服务由 brew services 管理：</p>
<pre tabindex="0"><code>brew services -h
</code></pre><p>创建文件并给予运行权限：</p>
<pre tabindex="0"><code>touch ~/.sleep &amp;&amp; chmod +x ~/.sleep
touch ~/.wakeup &amp;&amp; chmod +x ~/.wakeup
</code></pre><p>由于系统限制，睡眠时的操作不能运行超过 15 秒。</p>
<p>可以在 <code>~/.sleep</code> 写入一个创建文件夹的操作作为测试：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/zsh
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">mkdir ~/Desktop/test
</span></span></code></pre></div><p>盒盖、打开，桌面应该就有一个 <code>test/</code> 目录了。</p>
<h2 id="睡眠时关闭-qq">睡眠时关闭 QQ</h2>
<p>QQ for Mac 多年以来一直会在合盖状态下不知何时突然响起登录声，真的是让人无语，经常是合盖睡觉了，躺床上刚要睡着的时候 QQ 突然响了。</p>
<p>一个 python 脚本，关闭 QQ 的进程：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/local/bin/python3</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">psutil</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">pid</span> <span class="ow">in</span> <span class="n">psutil</span><span class="o">.</span><span class="n">pids</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span> <span class="o">=</span> <span class="n">psutil</span><span class="o">.</span><span class="n">Process</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span><span class="o">.</span><span class="n">name</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="o">==</span> <span class="s1">&#39;QQ jietu plugin&#39;</span> <span class="ow">or</span> <span class="n">name</span> <span class="o">==</span> <span class="s1">&#39;QQ&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">psutil</span><span class="o">.</span><span class="n">Process</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span><span class="o">.</span><span class="n">terminate</span><span class="p">()</span>
</span></span></code></pre></div><p>给予脚本权限并在 <code>~/.sleep</code> 中执行脚本就可以了。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/local/bin/zsh
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">/.../terminate_QQ.py
</span></span></code></pre></div><h2 id="同步-rime">同步 Rime</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/local/bin/zsh
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">/Library/Input<span class="se">\ </span>Methods/Squirrel.app/Contents/MacOS/Squirrel --sync
</span></span></code></pre></div><h2 id="其他">其他</h2>
<p>能干的事情很多，比如启动/关闭程序，开关蓝牙，播放音乐啥的。。。</p>
]]></content:encoded>
    </item>
    <item>
      <title>解决 pyenv 导致的 brew warning</title>
      <link>https://dvel.me/posts/solve-pyenv-brew-warning/</link>
      <pubDate>Fri, 31 Jan 2020 10:01:57 +0800</pubDate>
      <guid>https://dvel.me/posts/solve-pyenv-brew-warning/</guid>
      <description>解决因为安装 pyenv 导致的 brew doctor 产生的 brew warning。</description>
      <content:encoded><![CDATA[<p><code>brew doctor</code> 的错误提示：</p>
<pre tabindex="0"><code>Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don&#39;t worry or file an issue; just ignore this. Thanks!

Warning: &#34;config&#34; scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and which additional flags to use when
compiling and linking.

Having additional scripts in your path can confuse software installed via
Homebrew if the config script overrides a system or Homebrew-provided
script of the same name. We found the following &#34;config&#34; scripts:
  /Users/username/.pyenv/shims/python2-config
  /Users/username/.pyenv/shims/python2.7-config
  /Users/username/.pyenv/shims/python-config
  /Users/username/.pyenv/shims/python3-config
  /Users/username/.pyenv/shims/python3.8-config
</code></pre><p>解决方法：https://github.com/pyenv/pyenv/issues/106 <code>randy3k commented on 22 Apr 2015</code></p>
<p>写入 <code>~/.bash_profile</code> 或 <code>~/.zshrc</code> 中：</p>
<pre tabindex="0"><code>alias brew=&#34;env PATH=${PATH//$(pyenv root)\/shims:/} brew&#34;
</code></pre><p>如果你安装了 VMware Fusion，可能会出现错误提示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ brew doctor
</span></span><span class="line"><span class="cl">env: Fusion.app/Contents/Public:/Library/Apple/usr/bin: No such file or directory
</span></span></code></pre></div><p>执行 <code>echo ${PATH//$(pyenv root)\/shims:/}</code> 会看到原因：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">.../Applications/VMware Fusion.app/Contents/Public...
</span></span></code></pre></div><p>VMware Fusion 的环境变量没有被 <code>\&lt;space&gt;</code> 转义，这个 <code>PATH</code> 似乎在大部分情况下都可以正常运行，甚至直接在终端执行 <code>env PATH=${PATH//$(pyenv root)\/shims:/} brew doctor</code> 都可以正常运行，但是在 <code>alias</code> 命令下却因为这个没有转义的空格而发生错误了。</p>
<p>所以自己加一个转义就好了，编辑 <code>/etc/paths.d/com.vmware.fusion.public</code>：</p>
<pre tabindex="0"><code>/Applications/VMware Fusion.app/Contents/Public
</code></pre><p>更改为：</p>
<pre tabindex="0"><code>/Applications/VMware\ Fusion.app/Contents/Public
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>《SQL 必知必会》笔记</title>
      <link>https://dvel.me/posts/sql-in-10-minutes-a-day-note/</link>
      <pubDate>Wed, 29 Jan 2020 21:14:41 +0800</pubDate>
      <guid>https://dvel.me/posts/sql-in-10-minutes-a-day-note/</guid>
      <description>书籍《SQL 必知必会》的学习笔记。</description>
      <content:encoded><![CDATA[<p>《SQL 必知必会》第 4 版</p>
<p>豆瓣：<a href="https://book.douban.com/subject/24250054/" target="_blank" rel="noopener">https://book.douban.com/subject/24250054/</a></p>
<p>SQL 文件下载地址：<a href="https://forta.com/books/0672336073/" target="_blank" rel="noopener">https://forta.com/books/0672336073/</a></p>
<h2 id="1---了解-sql">1 - 了解 SQL</h2>
<h3 id="数据库">数据库</h3>
<p>保存有组织的数据的容器（通常是一个文件或多个文件）。</p>
<p>数据库软件应称为数据库管理系统（DBMS）.</p>
<h3 id="表">表</h3>
<p>某种特定类型数据的结构化清单。</p>
<h3 id="列">列</h3>
<p>表中的一个子段。所有表都是由一个或多个列组成的。</p>
<h4 id="主键">主键：</h4>
<p>表中的任何列都可以作为主键，只要它满足以下条件：</p>
<ul>
<li>任意两行都不具备有相同的主键值；</li>
<li>每一行都必须具有一个主键值（主键列不允许 NULL 值）；</li>
<li>主键列中的值不允许修改或更新；</li>
<li>主键值不能重用（如果某行从表中删除，它的主键不能赋给以后的新行）。</li>
</ul>
<h2 id="2---检索数据">2 - 检索数据</h2>
<h3 id="查询语句-select">查询语句 <code>SELECT</code></h3>
<p>检索一个或多个列。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">列名</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">表名</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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="err">表名</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="注释">注释</h3>
<p>在大多数数据库软件中，支持 <code>#</code> <code>--</code> <code>/**/</code> 等单行和多行注释。</p>
<h3 id="结果集去重-distinct">结果集去重 <code>DISTINCT</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">DISTINCT</span><span class="w"> </span><span class="err">列名</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="err">表名</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p><code>DISTINCT</code> 关键字限制所有的列，如果后接多列，除非两列内容完全相同，否则都会被纳入结果集。</p>
<h3 id="限制结果-limit">限制结果 <code>LIMIT</code></h3>
<p>大多用于分页显示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 从第 0 行开始，显示 5 个。第一页：
</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="err">表名</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="n">OFFSET</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 从第 5 行开始，现实 5 个。第二页：
</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="err">表名</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="n">OFFSET</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>MySQL、MariaDB、SQLite 简化语法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1"># 从 n 起，取 m 行。 n 可省略，默认为 0。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </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="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">表</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">m</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="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">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="err">表名</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">5</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">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="err">表名</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="mi">5</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">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="err">表名</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="3---排序检索数据">3 - 排序检索数据</h2>
<p><code>ASC</code> 默认，升序，全称 ascending。</p>
<p><code>DESC</code> 降序，全称 descending。</p>
<h3 id="排序数据-order-by">排序数据 <code>ORDER BY</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">列名</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="err">表名</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="err">列名</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p><code>ORDER BY</code> 子句中用非检索的列排序也是合法的。</p>
<h3 id="按多个列排序">按多个列排序</h3>
<p>写在前面的优先级高。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">列名</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="err">表名</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="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="p">;</span><span class="w">
</span></span></span></code></pre></div><p>按列位置排序，可以使用列名的书写位置，不推荐：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </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="p">,</span><span class="w"> </span><span class="err">列名</span><span class="mi">3</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="err">表名</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="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="降序排列">降序排列</h3>
<p><code>ORDER BY</code> 默认为升序排列。（从上至下，越来越大（0→100，a→z））</p>
<p><code>DESC</code> 只对前面那一列生效，如果想多列使用降序排序，必须对每一列指定 <code>DESC</code> 关键字。</p>
<p>示例：（prod_price 列降序排序，prod_name 仍按升序排序）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">prod_id</span><span class="p">,</span><span class="w"> </span><span class="n">prod_price</span><span class="p">,</span><span class="w"> </span><span class="n">prod_name</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">Products</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">prod_price</span><span class="w"> </span><span class="k">DESC</span><span class="p">,</span><span class="w"> </span><span class="n">prod_name</span><span class="w">
</span></span></span></code></pre></div><h2 id="4---过滤数据">4 - 过滤数据</h2>
<h3 id="where"><code>WHERE</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">列名</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="err">表名</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="err">条件</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="操作符">操作符</h3>
<p>常见操作符：&lt; &gt; = &lt;= &gt;= != 。。。</p>
<p><code>BTEWEEN</code>  操作符，左闭右闭。</p>
<p><code>IS NULL</code></p>
<h2 id="5---高级数据过滤">5 - 高级数据过滤</h2>
<h3 id="and-or"><code>AND</code> <code>OR</code></h3>
<p><code>AND</code> 优先级大于 <code>OR</code>。</p>
<p>使用小括号，不依赖优先级顺序，可以消除歧义。</p>
<h3 id="in"><code>IN</code></h3>
<p>指定范围，集合中的每个条件都可以进行匹配。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</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="k">FROM</span><span class="w"> </span><span class="err">表名</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">xxx_id</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="n">no1</span><span class="p">,</span><span class="w"> </span><span class="n">no2</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p>加强版的 <code>OR</code>，使逻辑更清晰。</p>
<h3 id="not"><code>NOT</code></h3>
<p>否定紧跟的条件。</p>
<h2 id="6---用通配符进行过滤">6 - 用通配符进行过滤</h2>
<h3 id="like"><code>LIKE</code></h3>
<p><code>LIKE</code> 指示 DBMS 后跟的搜索模式利用通配符而不是简单的相等匹配进行比较。</p>
<h3 id="-通配符"><code>%</code> 通配符</h3>
<p><code>%</code> 能匹配 0 个、1 个或多个字符。</p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">Products</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s2">&#34;fish%&#34;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="_-通配符"><code>_</code> 通配符</h3>
<p><code>_</code> 总是刚好匹配一个字符，不能多也不能少。</p>
<p>示例：（与 <code>%</code> 的区别与对比）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">Products</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s2">&#34;% inch teddy bear&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 8 inch teddy bear
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 12 inch teddy bear
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 18 inch teddy bear
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">Products</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s2">&#34;__ inch teddy bear&#34;</span><span class="p">;</span><span class="w"> </span><span class="c1">-- 两个下划线
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 12 inch teddy bear
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 18 inch teddy bear
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">Products</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">prod_name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s2">&#34;_ inch teddy bear&#34;</span><span class="p">;</span><span class="w"> </span><span class="c1">-- 一个下划线
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 8 inch teddy bear
</span></span></span></code></pre></div><h3 id="注意">注意</h3>
<ul>
<li>不要过度使用通配符。如果其他操作符能达到相同的目的，应该使用其他操作符。</li>
<li>在确实需要使用通配符时，也尽量不要把它们用在搜索模式的开始处，搜索起来是最慢的。</li>
<li>仔细注意通配符的位置。如果放错地方，可能不会返回想要的数据。</li>
</ul>
<h2 id="7---创建计算字段">7 - 创建计算字段</h2>
<h3 id="拼接字段">拼接字段</h3>
<p>MySQL 和 MariaSQL 使用 <code>CONCAT()</code> 函数拼接字符串；</p>
<p>使用 <code>TRIM()</code>、<code>LTRIM()</code>、<code>RTRIM</code> 去掉字符串两边、左、右的空格。</p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nf">CONCAT</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nf">TRIM</span><span class="p">(</span><span class="w"> </span><span class="n">vend_name</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="s1">&#39;\t\t(&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nf">TRIM</span><span class="p">(</span><span class="w"> </span><span class="n">vend_country</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="s1">&#39;)&#39;</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="k">FROM</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Vendors</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="as-别名"><code>AS</code> 别名</h3>
<h3 id="计算字段">计算字段</h3>
<p>对检索出的数据进行算术计算：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">prod_id</span><span class="p">,</span><span class="w"> </span><span class="n">quantity</span><span class="p">,</span><span class="w"> </span><span class="n">item_price</span><span class="p">,</span><span class="w"> </span><span class="n">quantity</span><span class="o">*</span><span class="n">item_price</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">expanded_price</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">OrderItems</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">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">20008</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="8---使用函数处理数据">8 - 使用函数处理数据</h2>
<h3 id="函数">函数</h3>
<ul>
<li>文本处理函数</li>
<li>日期和时间处理函数</li>
<li>数值处理函数</li>
</ul>
<p>需要参考相应 DBMS 文档。</p>
<h2 id="9---汇总数据">9 - 汇总数据</h2>
<h3 id="聚集函数">聚集函数</h3>
<p>对某些行运行的函数，计算并返回一个值。</p>
<h4 id="avg--平均值"><code>AVG()</code>  平均值</h4>
<p>只适用于单列，忽略值为 <code>NULL</code> 的行。</p>
<h4 id="count-计数"><code>COUNT()</code> 计数</h4>
<p><code>COUNT(*)</code> 对表中行的数目进行计算，不管表列中是否包含 <code>NULL</code> 值。</p>
<p><code>COUNT(列名)</code> 会忽略值为 <code>NULL</code> 的行。</p>
<h4 id="max-最大值"><code>MAX()</code> 最大值</h4>
<h4 id="min-最小值"><code>MIN()</code> 最小值</h4>
<h4 id="sum-求和"><code>SUM()</code> 求和</h4>
<h3 id="聚集不同值">聚集不同值</h3>
<p>对以上 5 个聚集函数都可以使用如下参数：</p>
<ul>
<li><code>ALL</code> 默认，对所有行执行计算。</li>
<li><code>DISTINCT</code> 只包含不同的值。（不能用于 <code>COUNT(*)</code>，只能用于列名。）</li>
</ul>
<p>例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="nf">AVG</span><span class="p">(</span><span class="k">DISTINCT</span><span class="w"> </span><span class="n">salary</span><span class="p">)</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">employee</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>会忽略工资相同的员工工资，来计算平均值。</p>
<h2 id="10---分组数据">10 - 分组数据</h2>
<h3 id="group-by-分组"><code>GROUP BY</code> 分组</h3>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">vend_id</span><span class="p">,</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">num_prods</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">Products</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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">vend_id</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="c1">-- vend_id	num_prods
</span></span></span><span class="line"><span class="cl"><span class="c1">-- BRS01	3
</span></span></span><span class="line"><span class="cl"><span class="c1">-- DLL01	4
</span></span></span><span class="line"><span class="cl"><span class="c1">-- FNG01	2
</span></span></span></code></pre></div><ul>
<li><code>GROUP BY</code> 子句可以包含任意数目的列，因而可以对分组进行嵌套，更细致地进行数据分组。
<ul>
<li>如果嵌套了分组，数据将在最后指定的分组上进行汇总。</li>
</ul>
</li>
<li><code>GROUP BY</code> 子句中列出的每一列都必须是检索列或有效的表达式（但不能是聚集函数）。</li>
<li>除聚集计算语句外，<code>SELECT</code> 语句中的每一列都必须在 <code>GROUP BY</code> 子句中给出。</li>
<li>如果分组列中包含 <code>NULL</code> 值的行，则 <code>NULL</code> 将作为一个分组返回。如果列中有多行 <code>NULL</code> 只，它们将分为一组。</li>
</ul>
<h3 id="having-过滤分组"><code>HAVING</code> 过滤分组</h3>
<p>示例：（列出具有 2 个以上产品且其价格大于等于 4 的供应商）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">vend_id</span><span class="p">,</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</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">Products</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">prod_price</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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">vend_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">HAVING</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;=</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></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- vend_id	COUNT(*)
</span></span></span><span class="line"><span class="cl"><span class="c1">-- BRS01	3
</span></span></span><span class="line"><span class="cl"><span class="c1">-- FNG01	2
</span></span></span></code></pre></div><p><code>HAVING</code> 支持所有 <code>WHERE</code> 的操作符。</p>
<p>紧接 <code>GROUP BY</code>，不能单独存在。</p>
<p>聚合函数只能与具体数据做条件判断，不能与字段做条件判断。（可用表连接实现）</p>
<h4 id="where-与-having-的差别"><code>WHERE</code> 与 <code>HAVING</code> 的差别：</h4>
<p><code>WHERE</code> 不能使用聚合函数，<code>HAVING</code> 可以在分组后使用聚合函数。</p>
<p><code>WHERE</code> 在数据分组前进行过滤，<code>HAVING</code> 在数据分组后进行过滤。</p>
<p>所以 <code>WHERE</code> 排除的行不包括在分组中，这可能会改变计算值，从而影响 <code>HAVING</code> 子句中基于这些值过滤掉的分组。</p>
<h3 id="order-by-分组和排序"><code>ORDER BY</code> 分组和排序</h3>
<p>一般在使用 <code>GROUP BY</code> 子句时，应该也给出 <code>ORDER BY</code> 子句。这时保证数据正确排序的唯一方法。千万不要尽依赖 <code>GROUP BY</code> 排序数据。</p>
<h3 id="select-子句书写顺序"><code>SELECT</code> 子句书写顺序</h3>
<table>
  <thead>
      <tr>
          <th>子句</th>
          <th>说明</th>
          <th>是否必须使用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>SELECT</code></td>
          <td>要返回的列或表达式</td>
          <td>是</td>
      </tr>
      <tr>
          <td><code>FROM</code></td>
          <td>从中检索数据的表</td>
          <td>仅在从表选择数据时使用</td>
      </tr>
      <tr>
          <td><code>WHERE</code></td>
          <td>行级过滤</td>
          <td>否</td>
      </tr>
      <tr>
          <td><code>GROUP BY</code></td>
          <td>组级过滤</td>
          <td>仅在按组计算聚集时使用</td>
      </tr>
      <tr>
          <td><code>HAVING</code></td>
          <td>组级过滤</td>
          <td>否</td>
      </tr>
      <tr>
          <td><code>ORDER BY</code></td>
          <td>输出排序顺序</td>
          <td>否</td>
      </tr>
  </tbody>
</table>
<h2 id="11---使用子查询">11 - 使用子查询</h2>
<h3 id="利用子查询进行过滤">利用子查询进行过滤</h3>
<p><strong>作为子查询的 <code>SELECT</code> 语句只能查询单个列。</strong></p>
<p>示例，列出订购物品 RGAN01 的所有顾客：</p>
<h4 id="1检索包含物品-rgan01-的所有订单的编号">1：检索包含物品 RGAN01 的所有订单的编号</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">order_num</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">OrderIterms</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">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="2检索具有前一步骤列出的订单编号的所有顾客的-id">2：检索具有前一步骤列出的订单编号的所有顾客的 ID</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_id</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">Orders</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">order_num</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">order_num</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">OrderIterms</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">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><h4 id="3检索前一步骤返回的所有顾客-id-的顾客信息">3：检索前一步骤返回的所有顾客 ID 的顾客信息</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</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">Customers</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">cust_id</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_id</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">Orders</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">order_num</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">order_num</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">OrderIterms</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">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="p">));</span><span class="w">
</span></span></span></code></pre></div><p>内连接写法：（第 12 课）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 列出订购物品 RGAN01 的所有顾客：
</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">cust_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">cust_contact</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">OrderItems</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Orders</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Customers</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">OrderItems</span><span class="p">.</span><span class="n">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="作为计算字段使用子查询">作为计算字段使用子查询</h3>
<p>示例，现实 <code>Customers</code> 表中每个顾客的订单总数：</p>
<h4 id="1从-customers-表中检索顾客列表">1：从 <code>Customers</code> 表中检索顾客列表；</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">orders</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">Orders</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">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;1000000001&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="2对于检索出的每个顾客统计其在-orders-表中的订单数目">2：对于检索出的每个顾客，统计其在 <code>Orders</code> 表中的订单数目</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_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">cust_state</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="k">SELECT</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</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">Orders</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">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">orders</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">Customers</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">cust_name</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="12---连接表">12 - 连接表</h2>
<h3 id="连接">连接</h3>
<p>为什么使用连接？</p>
<p>如果数据存储在多个表中，怎么用一条 <code>SELECT</code> 语句就检索出数据呢？</p>
<p>答案是使用连接。</p>
<h3 id="内连接inner-join">内连接（inner join）</h3>
<p>内连接，又称等值连接（equijoin），它基于两个表之间的相等测试。</p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">vend_name</span><span class="p">,</span><span class="w"> </span><span class="n">prod_name</span><span class="p">,</span><span class="w"> </span><span class="n">prod_price</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">Vendors</span><span class="p">,</span><span class="w"> </span><span class="n">Products</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">Vendors</span><span class="p">.</span><span class="n">vend_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Products</span><span class="p">.</span><span class="n">vend_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="mysql-中的多种写法">MySQL 中的多种写法：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </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="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="err">连接条件</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">表</span><span class="mi">1</span><span class="w"> </span><span class="p">[</span><span class="k">INNER</span><span class="p">]</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">表</span><span class="mi">2</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">连接条件</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">表</span><span class="mi">1</span><span class="w"> </span><span class="p">[</span><span class="k">INNER</span><span class="p">]</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">表</span><span class="mi">2</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="err">连接条件</span><span class="p">;</span><span class="w"> </span><span class="err">（在使用外连接时，使用</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="err">会出问题）</span><span class="w">
</span></span></span></code></pre></div><h3 id="笛卡尔积叉连接cross-join">笛卡尔积：（叉连接）（cross join）</h3>
<p>没有连接条件的表关系返回的结果为笛卡尔积，检索出的行数将是第一个表中的行数乘以第二个表中的行数。</p>
<h3 id="连接多个表">连接多个表</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 显示订单 20007 中的物品。
</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">prod_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">vend_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">prod_price</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">quantity</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">OrderItems</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Products</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Vendors</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">20007</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Products</span><span class="p">.</span><span class="n">prod_id</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">Products</span><span class="p">.</span><span class="n">vend_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Vendors</span><span class="p">.</span><span class="n">vend_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 列出订购物品 RGAN01 的所有顾客：
</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">cust_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">cust_contact</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">OrderItems</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Orders</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">Customers</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></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">OrderItems</span><span class="p">.</span><span class="n">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="13---创建高级连接">13 - 创建高级连接</h2>
<h3 id="使用表别名">使用表别名</h3>
<p>除了之前的给列起别名，也可以在 <code>FROM</code> 子句中给表起别名，以供在 <code>SELECT</code>、<code>WHERE</code> 子句中使用。</p>
<p>可以缩短 SQL 语句。允许在一条 <code>SELECT</code> 语句中方便多次使用相同的表。</p>
<h3 id="自连接self-join">自连接（self-join）</h3>
<p>内连接的一种，连接的是同一个表。</p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 给 Jim Jones 同一公司的所有顾客发送一封信件。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">c1</span><span class="p">.</span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">c1</span><span class="p">.</span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">c1</span><span class="p">.</span><span class="n">cust_email</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">Customers</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="n">Customers</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">c2</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">c2</span><span class="p">.</span><span class="n">cust_contact</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Jim Jones&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">AND</span><span class="w"> </span><span class="n">c1</span><span class="p">.</span><span class="n">cust_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c2</span><span class="p">.</span><span class="n">cust_name</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_name	cust_contact		cust_email
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All		Jim Jones			jjones@fun4all.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All		Denise L. Stephens	dstephens@fun4all.com
</span></span></span></code></pre></div><p>自连接比子查询性能更好。</p>
<h3 id="自然连接natural-join">自然连接（natural join）</h3>
<p>自然连接排除多次出现，使每一列只返回一次。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">Customers</span><span class="w"> </span><span class="k">NATURAL</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">Orders</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 两个表中都有 cust_id 列，但只返回了一个。
</span></span></span></code></pre></div><p>*感觉没什么用啊。。。除非真的要查询这么多字段。</p>
<h3 id="外连接outer-join">外连接（outer join）</h3>
<ul>
<li>内连接只返回符合条件的记录，外连接还返回不符合条件的记录。</li>
<li>左外连接即保留左表的所有记录，与右表连接；</li>
<li>右外连接即保留右表的所有记录，与左表连接。</li>
<li>左外连接（left outer join）与右外连接（right outer join）可以互相转换。（SQLite 即便不支持右外连接，也可以用左外连接代替）</li>
</ul>
<p>内外连接的区别，示例：（查询每个顾客的订单计数，外连接可以查询出尚未下过订单的顾客）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 内连接，只查询出条件关联的行
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 查询不到顾客 1000000002，因为他没有下过订单
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">,</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</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">Customers</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">Orders</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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_id		order_num
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000001	20005
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000001	20009
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000003	20006
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000004	20007
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000005	20008
</span></span></span><span class="line"><span class="cl"><span class="c1"></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">-- 可以查询到 1000000002
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">,</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</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">Customers</span><span class="w"> </span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">Orders</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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_id		order_num
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000001	20005
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000001	20009
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000002	(NULL)
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000003	20006
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000004	20007
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000005	20008
</span></span></span><span class="line"><span class="cl"><span class="c1"></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></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">,</span><span class="w"> </span><span class="nf">COUNT</span><span class="p">(</span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</span><span class="p">)</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">Customers</span><span class="w"> </span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">Orders</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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_id		COUNT(Orders.order_num)
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000001	2
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000002	0
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000003	1
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000004	1
</span></span></span><span class="line"><span class="cl"><span class="c1">-- 1000000005	1
</span></span></span></code></pre></div><p>其他外连接示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">SELECT</span><span class="w"> </span><span class="n">Products</span><span class="p">.</span><span class="n">prod_id</span><span class="p">,</span><span class="w"> </span><span class="nf">SUM</span><span class="p">(</span><span class="nf">IFNULL</span><span class="p">(</span><span class="n">OrderItems</span><span class="p">.</span><span class="n">quantity</span><span class="p">,</span><span class="mi">0</span><span class="p">))</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">Products</span><span class="w"> </span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">OrderItems</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">Products</span><span class="p">.</span><span class="n">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">prod_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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">Products</span><span class="p">.</span><span class="n">prod_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="全外连接full-outer-join">全外连接（full outer join）</h3>
<p>MySQL、MariaSQL、SQLite、Access、Open Office Base 不支持全外连接。</p>
<p>全外连接检索两个表中的所有行并关联那些可以关联的行。</p>
<h2 id="14---组合查询">14 - 组合查询</h2>
<h3 id="组合查询-union">组合查询（ <code>UNION</code>）</h3>
<p>SQL 允许执行多个查询（多条 <code>SELECT</code> 语句），并将结果作为一个查询结果返回。</p>
<p>主要有两种情况需要使用组合查询：</p>
<ul>
<li>在一个查询中从不同的表返回结果数据；</li>
<li>对一个表执行多个查询，按一个查询返回数据。</li>
</ul>
<p>提示：多数情况下，组合相同表的两个查询，通过具有多个 <code>WHERE</code> 子句的 <code>SELECT</code> 语句都可以作为一个组合查询。</p>
<h3 id="创建组合查询">创建组合查询</h3>
<p>示例：（需要 Illinois、Indiana、Michigan 等美国几个州的所有顾客的报表，还想包括不管位于哪个州的所有的 Fun4All）</p>
<p>单条语句 1：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">cust_email</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">Customers</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">cust_state</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;IL&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;IN&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;MI&#39;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_name		cust_contact	cust_email
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Village Toys		John Smith		sales@villagetoys.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All			Jim Jones		jjones@fun4all.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- The Toy Store	Kim Howard		(NULL)
</span></span></span></code></pre></div><p>单条语句 2：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">cust_email</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">Customers</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">cust_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Fun4All&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_name	cust_contact		cust_email
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All		Jim Jones			jjones@fun4all.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All		Denise L. Stephens	dstephens@fun4all.com
</span></span></span></code></pre></div><p><code>UNION</code> 组合：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">cust_email</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">Customers</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">cust_state</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;IL&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;IN&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;MI&#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">UNION</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">cust_email</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">Customers</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">cust_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Fun4All&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- cust_name		cust_contact			cust_email
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Village Toys		John Smith				sales@villagetoys.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All			Jim Jones				jjones@fun4all.com
</span></span></span><span class="line"><span class="cl"><span class="c1">-- The Toy Store	Kim Howard				(NULL)
</span></span></span><span class="line"><span class="cl"><span class="c1">-- Fun4All			Denise 	L. Stephens		dstephens@fun4all.com
</span></span></span></code></pre></div><p>使用 <code>WHERE</code>，效果相同：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">cust_email</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">Customers</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">cust_state</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;IL&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;IN&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;MI&#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">OR</span><span class="w"> </span><span class="n">cust_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Fun4All&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="包含或取消重复的行">包含或取消重复的行：</h4>
<p>上面例子中，<code>Fun4All		Jim Jones			jjones@fun4all.com</code> 这一行在两个 <code>SELECT</code> 语句中均被查询出，但 <code>UNION</code> 取消了重复的行。</p>
<p><code>UNION ALL</code> 可以让每个条件的匹配行全部出现。</p>
<h4 id="排序">排序：</h4>
<p>使用 <code>UNION</code> 组合查询时，只能使用一条 <code>ORDER BY</code> 子句进行排序，它必须位于最后一条 <code>SELECT</code> 语句之后。</p>
<h3 id="union-规则">UNION 规则</h3>
<ul>
<li>
<p><code>UNION</code> 必须由两条或两条以上的 <code>SELECT</code> 语句组成，语句之间用关键字 <code>UNION</code> 分割。</p>
</li>
<li>
<p><code>UNION</code> 中的每个查询必须包含<strong>相同数量</strong>的列、表达式或聚集函数。</p>
</li>
<li>
<p>列数据类型必须兼容：类型不必完全相同但必须兼容（如不同长度的字符串）</p>
<p>​</p>
</li>
</ul>
<h2 id="15---插入数据">15 - 插入数据</h2>
<h3 id="数据插入">数据插入</h3>
<p><code>INTERT</code> 语句：用来将行插入（或添加）到数据库表，插入有几种方式：</p>
<ul>
<li>插入完整的行；</li>
<li>插入行的一部分；</li>
<li>插入某些查询的结果。</li>
</ul>
<h3 id="插入完整的行mysql-中可以省略-into">插入完整的行：（MySQL 中可以省略 <code>INTO</code>）</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">Customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">VALUES</span><span class="p">(</span><span class="s1">&#39;1000000006&#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;Toy Land&#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;123 Any Street&#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;New York&#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;NY&#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;11111&#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;USA&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="no">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="no">NULL</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p>这种插入方法必须完整的按顺序提供列名所对应的数据。</p>
<p>由于较为依赖于表中列的定义次序，在表结构变动后会变得不安全或更改更麻烦。</p>
<h3 id="更安全的方法-or-插入部分字段">更安全的方法 or 插入部分字段：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="nf">Customers</span><span class="p">(</span><span class="n">cust_id</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_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">cust_address</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_city</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_state</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_zip</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_country</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_contact</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_email</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">VALUES</span><span class="p">(</span><span class="s1">&#39;1000000006&#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;Toy Land&#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;123 Any Street&#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;New York&#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;NY&#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;11111&#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;USA&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="no">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="no">NULL</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p>这样 DBMS 将用 <code>VALUES</code> 列表中的值按次序一一对应填入列表中的对应项。</p>
<p>也可以省略部分字段，只要这些省略的字段允许 <code>NULL</code> 值或提供默认值。</p>
<h3 id="一次插入多行数据">一次插入多行数据</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</span><span class="p">[(</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="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="p">,</span><span class="w"> </span><span class="err">值</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="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="err">表名</span><span class="p">[(</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="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="p">,</span><span class="w"> </span><span class="err">值</span><span class="mi">2</span><span class="p">...),</span><span class="w"> </span><span class="p">(</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="p">...)</span><span class="w"> </span><span class="p">...;</span><span class="w">
</span></span></span></code></pre></div><h3 id="插入检索出的数据">插入检索出的数据</h3>
<p><code>INSERT SELECT</code> 语句可以插入检索出的行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="nf">Customers</span><span class="p">(</span><span class="n">cust_id</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_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">cust_address</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_city</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_state</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_zip</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_country</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_contact</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">					  </span><span class="n">cust_email</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_id</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_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">cust_address</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_city</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_state</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_zip</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_country</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_contact</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	   </span><span class="n">cust_email</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">CustNew</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>插入行数取决于 <code>SELECT</code> 语句查询出多少行。</p>
<p>DBMS 不在乎 <code>SELECT</code> 返回的列名，会将查询出的字段按 <code>INSERT</code> 语句给出的次序一一对应。</p>
<h3 id="从一个表复制到另一个表">从一个表复制到另一个表</h3>
<p>SQL 语法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">SELECT</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="k">INTO</span><span class="w"> </span><span class="n">CustCopy</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">Customers</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p><strong>MySQL、MariaDB、SQLite、Oracle、PostgreSQL 语法：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="n">CustCopy</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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">Customers</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><blockquote>
<p>message:</p>
<p>There is no primary key here. Update will only use exact matching of the old values of the columns here. Thus, it may update more than one record.</p>
</blockquote>
<p>*MySQL 在复制时没有复制主键约束。</p>
<h2 id="16---更新和删除数据">16 - 更新和删除数据</h2>
<p><strong>在更新和删除数据时，如果不指定 <code>WHERE</code> 条件，将会更新或删除所有行。</strong></p>
<h3 id="更新数据update">更新数据（<code>UPDATE</code>）</h3>
<p>基本的 <code>UPDATE</code> 语句由三部分组成：</p>
<ul>
<li>要更新的表；</li>
<li>列名和它们的新值；</li>
<li>确定要更新哪些行的过滤条件。</li>
</ul>
<h4 id="更新一列">更新一列：</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">UPDATE</span><span class="w"> </span><span class="n">Customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">SET</span><span class="w"> </span><span class="n">cust_email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;kim@thetoystore.com&#39;</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">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;1000000005&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="更新多列">更新多列：</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">UPDATE</span><span class="w"> </span><span class="n">Customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">SET</span><span class="w"> </span><span class="n">cust_contact</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Sam Roberts&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">cust_email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;sam@toyland.com&#39;</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">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;1000000006&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="在-update-语句中进行表连接">在 <code>UPDATE</code> 语句中进行表连接</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1"># 把ALLEN调往RESEARCH部门,职务调整为ANALYST
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">t_emp</span><span class="w"> </span><span class="n">e</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">t_dept</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">ename</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;ALLEN&#39;</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">d</span><span class="p">.</span><span class="n">dname</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RESEARCH&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">SET</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">deptno</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">d</span><span class="p">.</span><span class="n">deptno</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">job</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;ANALYST&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">d</span><span class="p">.</span><span class="n">loc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;北京&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h4 id="支持内连接另一个结果集">支持内连接另一个结果集：</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1"># 把底薪低于公司平均底薪的员工,底薪增加150元
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">t_emp</span><span class="w"> </span><span class="n">e</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="nf">AVG</span><span class="p">(</span><span class="n">sal</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">avg</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">t_emp</span><span class="p">)</span><span class="w"> </span><span class="n">e2</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">sal</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">e2</span><span class="p">.</span><span class="n">avg</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">SET</span><span class="w"> </span><span class="n">sal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sal</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">150</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>同样支持外连接。</p>
<h3 id="删除数据delete">删除数据（<code>DELETE</code>）</h3>
<p>关于删除所有的行：</p>
<p>不指定 <code>WHERE</code> 条件时，<code>DELETE</code> 将会删除所有的行，但如果你明确要这么做，使用 <code>TRUNCATE TABLE</code> 可以更快的删除整个表的数据（因为不记录数据的变动（没有事务））。</p>
<p>删除行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">Customers</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">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;1000000006&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>同样支持表连接：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">DELETE</span><span class="w"> </span><span class="err">表</span><span class="mi">1</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="k">FROM</span><span class="w"> </span><span class="err">表</span><span class="mi">1</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">表</span><span class="mi">2</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">条件</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">[</span><span class="k">WHERE</span><span class="w"> </span><span class="err">条件</span><span class="w"> </span><span class="p">...];</span><span class="w">
</span></span></span></code></pre></div><p>可以一次性删除多个表的内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1"># 删除SALES部门和该部门的全部员工记录
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">DELETE</span><span class="w"> </span><span class="n">e</span><span class="p">,</span><span class="n">d</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">t_emp</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">t_dept</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">deptno</span><span class="o">=</span><span class="n">d</span><span class="p">.</span><span class="n">deptno</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">d</span><span class="p">.</span><span class="n">dname</span><span class="o">=</span><span class="s2">&#34;SALES&#34;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>同样支持外连接。</p>
<h2 id="17---创建和操纵表">17 - 创建和操纵表</h2>
<h3 id="创建表">创建表：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</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="err">列名</span><span class="mi">1</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</span><span class="p">],</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="err">列名</span><span class="mi">2</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</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="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)[</span><span class="n">COMMENT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">注释</span><span class="p">];</span><span class="w">
</span></span></span></code></pre></div><h3 id="删除表">删除表：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">DROP</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="err">表名</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="n">TRUNCATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="err">表名</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="添加列">添加列：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</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="err">列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</span><span class="p">],</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="err">列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</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="w">
</span></span></span></code></pre></div><h3 id="修改列类型">修改列类型：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">MODIFY</span><span class="w"> </span><span class="err">列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</span><span class="p">],</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">MODIFY</span><span class="w"> </span><span class="err">列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</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="w">
</span></span></span></code></pre></div><h3 id="修改列名">修改列名：</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CHANGE</span><span class="w"> </span><span class="err">列名</span><span class="w"> </span><span class="err">新列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</span><span class="p">],</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CHANGE</span><span class="w"> </span><span class="err">列名</span><span class="w"> </span><span class="err">新列名</span><span class="w"> </span><span class="err">数据类型</span><span class="w"> </span><span class="p">[</span><span class="err">约束</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">COMMENT</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="w">
</span></span></span></code></pre></div><h3 id="删除列">删除列</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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="err">表名</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="err">列</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">DROP</span><span class="w"> </span><span class="err">列</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="p">...;</span><span class="w">
</span></span></span></code></pre></div><h2 id="18---使用视图">18 - 使用视图</h2>
<p>视图提供了一种封装 <code>SELECT</code> 语句的层次，可用来简化数据处理，重新格式化或保护基础数据。</p>
<h3 id="为什么使用视图">为什么使用视图</h3>
<ul>
<li>重用 SQL 语句；</li>
<li>简化复杂的 SQL 操作。在编写查询后，可以方便的重用它而不必知道其基本查询细节。</li>
<li>使用表的一部分而不是整个表；</li>
<li>保护数据。可以授予用户访问表的特定部分的权限，而不是整个表的访问权限。</li>
<li>更改数据格式和表示。视图可以返回与底层表的表示和格式不同的数据。</li>
</ul>
<p><strong>视图仅仅是用来查看存储在别处数据的一种设施。视图本身不包含数据，因此返回的数据是从其他表中检索出来的。在添加或更改这些表中的数据时，视图将返回改变过的数据。</strong></p>
<p>性能问题：每次使用视图时，都必须处理查询执行时需要的所有检索。检索过于复杂，性能可能会下降的很厉害。</p>
<h3 id="视图的规则和限制">视图的规则和限制</h3>
<ul>
<li>视图必须唯一命名（视图与表也不能重名）；</li>
<li>视图不能索引，也不能有关联的触发器或默认值。</li>
<li>。。。</li>
</ul>
<h3 id="使用视图">使用视图</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">CREATE</span><span class="w"> </span><span class="n">VIEW</span><span class="w"> </span><span class="err">视图名</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</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></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="n">VIEW</span><span class="w"> </span><span class="err">视图名</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>视图重命名：覆盖或更新视图，必须先删除它，然后再重新创建。</p>
<p>示例：（利用视图简化复杂的连接）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><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">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">prod_id</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">Customers</span><span class="p">,</span><span class="w"> </span><span class="n">Orders</span><span class="p">,</span><span class="w"> </span><span class="n">OrderItems</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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">AND</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">order_num</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="c1">-- 为上面的 SQL 语句创建视图
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">CREATE</span><span class="w"> </span><span class="n">VIEW</span><span class="w"> </span><span class="n">ProductCustomers</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">cust_name</span><span class="p">,</span><span class="w"> </span><span class="n">cust_contact</span><span class="p">,</span><span class="w"> </span><span class="n">prod_id</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">Customers</span><span class="p">,</span><span class="w"> </span><span class="n">Orders</span><span class="p">,</span><span class="w"> </span><span class="n">OrderItems</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">Customers</span><span class="p">.</span><span class="n">cust_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">cust_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">AND</span><span class="w"> </span><span class="n">Orders</span><span class="p">.</span><span class="n">order_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OrderItems</span><span class="p">.</span><span class="n">order_num</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="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">ProductCustomers</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="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="n">VIEW</span><span class="w"> </span><span class="n">ProductCustomers</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>从视图检索数据时如果使用了一条 <code>WHERE</code> 语句，则两组句子（一组在视图中，另一组是传递给视图的）将自动组合。</p>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1">-- 用 ProductCustomers 视图查询订购了 RGAN01 的顾客
</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">ProductCustomers</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">prod_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;RGAN01&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="19---使用存储过程">19 - 使用存储过程</h2>
<blockquote>
<p>一组可编程的函数，是为了完成特定功能的 SQL 语句集，经编译创建并保存在数据库中，用户可通过指定存储过程的名字并给定参数（需要时）来调用执行。</p>
<p>优点(为什么要用存储过程？)：</p>
<ol>
<li>将重复性很高的一些操作，封装到一个存储过程中，简化了对这些SQL的调用</li>
<li>批量处理：SQL+循环，减少流量，也就是“跑批”</li>
<li>统一接口，确保数据的安全</li>
</ol>
<p>相对于 Oracle 数据库来说，MySQL的存储过程相对功能较弱，使用较少。</p>
</blockquote>
<p>—— <a href="https://www.cnblogs.com/geaozhang/p/6797357.html" target="_blank" rel="noopener">MySQL存储过程的创建及调用</a></p>
<h2 id="20---管理事务处理">20 - 管理事务处理</h2>
<p>使用事务处理（transaction processing），通过确保成批的 SQL 操作要么完全执行，要么完全不执行，来维护数据库的完整性。</p>
<p>事务处理用来管理 <code>INSERT</code>、<code>UPDATE</code> 和 <code>DELETE</code> 语句。不能回退 <code>SELECT</code> 语句（回退 <code>SELECT</code> 语句也没有必要）。</p>
<p>也不能回退 <code>CREATE</code> 或 <code>DROP</code> 操作。事务处理中可以使用这些语句，但进行回退时，这些操作也不撤销。</p>
<p>具体语法应参考相应的 DBMS 文档。</p>
<h2 id="21---使用游标">21 - 使用游标</h2>
<p>有时需要在检索出来的行中前进或后退一行或多行，这就是游标的用途所在。</p>
<p>游标（cursor）是一个存储在 DBMS 服务器上的数据库查询，它不是一条 <code>SELECT</code> 语句，而是被该语句检索出来的结果集。在存储了游标之后，应用程序可以根据需要滚动或浏览其中的数据。</p>
<p>具体语法应参考相应的 DBMS 文档。</p>
<h2 id="22---高级-sql-特性">22 - 高级 SQL 特性</h2>
<h3 id="约束">约束</h3>
<p>管理如何插入或处理数据库数据的规则。</p>
<ul>
<li>主键（<code>PRIMARY KEY</code>）</li>
<li>外键（<code>REFERENCES</code>）</li>
<li>唯一约束（<code>UNIQUE</code>）</li>
<li>检查约束（<code>CHECK</code>）</li>
</ul>
<h3 id="索引">索引</h3>
<p>索引用来排序数据以加快搜索和排序操作的速度。</p>
<p>可以在一个或多个列上定义索引，使 DBMS 保存其内容的一个排过序的列表。</p>
<ul>
<li>索引改善检索操作的性能，但降低了数据插入、修改、删除的性能。在执行这些操作时，DBMS 必须动态地更新索引。</li>
<li>索引数据可能要占用大量的存储空间。</li>
<li>并非所有数据都适合做索引。取值不多的数据（如省）不如具有更多可能值的数据（如姓、名）能通过索引得到更大的提升。</li>
<li>索引用于数据过滤和数据排序。如果你经常以某种特定的顺序排序数据，则该数据可能适合做索引。</li>
<li>可能在索引中定义多个列（如州+城市）。这样索引仅在以州+城市的顺序排序时有用。如果想按城市排序，则这种索引没有用处。</li>
</ul>
<h3 id="触发器">触发器</h3>
<p>触发器是特殊的存储过程，它在特定的数据库活动发生时自动执行。</p>
<p>触发器可以与特定表上的 <code>INSERT</code>、<code>UPDATE</code>、<code>DELETE</code> 操作（或组合）相关联。</p>
<p>与存储过程不一样（存储过程只是简单的存储 SQL 语句），触发器与单个的表相关联。（例如：与 Orders 表上的 <code>INSERT</code> 操作相关联的触发器只在 Orders 表中插入行时执行。类似的，Customers 表上的 <code>INSERT</code> 和 <code>UPDATE</code> 操作的触发器只在表上出现这些操作时执行。）</p>
<p>触发器内的代码具有一下数据库的访问权：</p>
<ul>
<li><code>INSERT</code> 操作中的所有新数据；</li>
<li><code>UPDATE</code> 操作中的所有新数据和旧数据；</li>
<li><code>DELETE</code> 操作中删除的数据。</li>
</ul>
<p>根据所使用的 DBMS 不同，触发器可在特定操作执行之前或之后执行。</p>
<p>触发器的常见用途：</p>
<ul>
<li>保证数据一致。（如：在 <code>INSERT</code> 或 <code>UPDATE</code> 操作中将所有州名转换为大写）</li>
<li>基于某个表的变动在其他表上执行活动。（如：每当更新或删除一行时将审计跟踪记录写入某个日志表）</li>
<li>进行额外的验证并根据需要回退数据。（如：保证某个顾客的可用资金不超限定，如果已经超出，则阻塞插入）</li>
<li>计算计算列的值或更新时间戳。</li>
</ul>
<p>不同 DBMS 的触发器创建于法差异很大。</p>
<h3 id="数据库安全">数据库安全</h3>
<p>一般来说，需要保护的操作有：</p>
<ul>
<li>对数据库管理功能的访问（创建表、更改或删除已存在的表等）；</li>
<li>对特定数据库或表的访问；</li>
<li>访问的类型（制度、对特定列的访问等）；</li>
<li>仅通过视图或存储过程对表进行访问；</li>
<li>创建多层次的安全措施，从而允许多种基于登录的访问和控制；</li>
<li>闲置管理用户账号的能力。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Git 自总结</title>
      <link>https://dvel.me/posts/git-summary/</link>
      <pubDate>Sun, 07 Apr 2019 20:44:44 +0800</pubDate>
      <guid>https://dvel.me/posts/git-summary/</guid>
      <description>对 GitHub 官方的 Git 教程的学习与总结。</description>
      <content:encoded><![CDATA[<blockquote>
<p>虽然用了很久的 Git 了，但基本上只是 add、commit、push、pull，这次系统性的学习了一遍。</p>
<p>整体是按照 <a href="https://www.nowcoder.com/courses/2" target="_blank" rel="noopener">Github 官方教程，由牛客网翻译的视频</a> 的顺序排下来的。</p>
<p>内容上外加网上的各种博文总结和补充了一些。</p>
</blockquote>
<h2 id="setup">Setup</h2>
<pre tabindex="0"><code>$ brew install git
</code></pre><h2 id="config">Config</h2>
<p>Git 希望知道每次提交的作者信息，来说明是谁进行的本次提交，这会随着版本迭代永久纳入历史记录中。</p>
<pre tabindex="0"><code>$ git config --global user.name &#34;my name&#34;
$ git config --global user.email xxx@example.com
</code></pre><p>user.email 最好与 github 中的邮件地址相同，否则 push 后在 github 上并不会准确显示出是自己。</p>
<h3 id="配置文件">配置文件：</h3>
<p>在 <code>~/.gitconfig</code> 中同样可以修改和查看上述配置，或修改 Git 全局忽略的位置信息等。</p>
<h3 id="ssh">SSH</h3>
<p>配合 SSH Key 在 Github 中可以免去输入密码的环节。</p>
<p>生成密钥：</p>
<pre tabindex="0"><code>$ ssh-keygen -t rsa -C &#34;youremail@example.com&#34;
</code></pre><p>在 <code>~/.ssh/id_rsa.pub</code> 中取得公钥并上传 GitHub。</p>
<h2 id="init">Init</h2>
<h3 id="创建本地仓库">创建本地仓库：</h3>
<pre tabindex="0"><code>$ git init
</code></pre><h3 id="github-上创建仓库可遵循-github-的提示">Github 上创建仓库，可遵循 Github 的提示：</h3>
<ul>
<li>create a new repository on the command line：</li>
</ul>
<pre tabindex="0"><code>echo &#34;# test&#34; &gt;&gt; README.md
git init
git add README.md
git commit -m &#34;first commit&#34;
git remote add origin https://github.com/xxx/test.git
git push -u origin master
</code></pre><pre tabindex="0"><code>git remote add origin https://github.com/xxx/test.git
git push -u origin master
</code></pre><br/>
<h2 id="status">status</h2>
<p>查看状态：</p>
<pre tabindex="0"><code>$ git status
</code></pre><p>可以查看目前所有文件的状态，改动文件较多时推荐使用更简洁易读的：</p>
<pre tabindex="0"><code>$ git status -s
</code></pre><ul>
<li><code>??</code> 新文件，未跟踪</li>
<li><code>A</code> 新文件，已跟踪</li>
<li><code>M</code> 修改</li>
<li><code>D</code> 删除</li>
</ul>
<p>接下来是 Git 的提交三部曲：</p>
<ul>
<li>新建或修改文件</li>
<li>加入到暂存区</li>
<li>提交到仓库</li>
</ul>
<br/>
<h2 id="add">Add</h2>
<h3 id="add将改动登记到暂存区">Add：将改动登记到暂存区：</h3>
<p>单一文件的新建、修改、删除：</p>
<pre tabindex="0"><code>$ git add filename
</code></pre><p>也可以一次性 add 所有变更：</p>
<pre tabindex="0"><code>$ git add .
</code></pre><p>在简单操作中，add 被理解为把文件添加到暂存区没太大问题，但实际是它暂存的是修改而不是文件。</p>
<pre tabindex="0"><code>$ echo aaa &gt; file
$ git add file
$ echo bbb &gt;&gt; file
$ git commit -m &#34;bug fix&#34;
</code></pre><p>上例中，只有 <code>aaa</code> 这一行的修改被暂存，所以版本库中只有 <code>aaa</code>，现在使用 <code>diff</code> 命令仍然可以看到 <code>bbb</code> 并没有被提交。</p>
<h3 id="关于-git-add-">关于 <code>git add .</code></h3>
<p>在谷歌前几页几乎所有的博客中都强调了这一点：</p>
<p><code>git add -A</code>  = <code>git add -u</code> + <code>git add .</code> （错误的，见下文）</p>
<ul>
<li><code>git add .</code>       将文件的修改、<strong>新建</strong>，登记到暂存区（错误的，见下文）</li>
<li><code>git add -u</code>     将文件的修改、<strong>删除</strong>，登记到暂存区</li>
<li><code>git add -A</code>     将文件的修改、新建、删除，登记到暂存区</li>
</ul>
<p>macOS 自带的 git 默认都是 2.20 版本了，在 stackoverflow 中的评论中看到，<strong>2.0 版本后 <code>git add .</code> 已经和 <code>git add -A</code> 效果相同</strong>。(<a href="https://stackoverflow.com/questions/15011311/whats-the-difference-between-git-add-u-and-git-add-a/27854048" target="_blank" rel="noopener">https://stackoverflow.com/questions/15011311/whats-the-difference-between-git-add-u-and-git-add-a/27854048</a>)</p>
<p>所以在大部分情况，只需要记住 <code>git add .</code> 这一个命令就足够了。</p>
<br/>
<h2 id="commit">Commit</h2>
<p>commit: 将暂存区提交到版本库：</p>
<pre tabindex="0"><code>$ git commit -m &#34;message...&#34;
</code></pre><p>如果不使用 -m 参数填写提交信息，git 会打开一个文本编辑器让你输入</p>
<br/>
<h2 id="工作区暂存区仓库区">工作区、暂存区、仓库区</h2>
<blockquote>
<p>diff 在 GUI 中观察更为舒适，但下一章 diff 的三种比较模式可以让新手深入了解三大区的变更状态。</p>
</blockquote>
<p><strong>工作区（Workspace）</strong></p>
<p>即你肉眼可见的项目目录。</p>
<p><strong>暂存区（Index/Stage）</strong></p>
<p>一般存放在 &ldquo;.git目录下&rdquo; 下的index文件（.git/index）中，所以我们把暂存区有时也叫作索引（index）。它保存了下次将提交的文件列表信息，Git 对暂存区在命名和命令上有多个名字，包括Index，Stage，Cache。</p>
<p><strong>本地仓库（Repository）</strong></p>
<p>版本库即 <code>.git</code> 这个隐藏目录，真正存储各版本代码库的地方。</p>
<p><strong>远程仓库（Remote）</strong></p>
<p>协作开发时或个人备份用，存储在 GitHub 等平台或自建 git 的远端仓库，可用于多方共同开发。</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2019-04-07A.webp"
            alt="Git"
            width="683"
            height="357"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2019-04-07B.webp"
            alt="Git"
            width="640"
            height="186"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<p>日常操作与几大区的关系：</p>
<p>-&gt; 修改代码、新建文件等操作，工作区发生改动</p>
<p>-&gt; add：将改动内容&quot;登记&quot;到暂存区</p>
<p>-&gt; commit：将暂存区的所有内容提交到本地仓库。</p>
<p>只有 commit 了，我们的代码才真正的进入到 git 仓库了。</p>
<p>-&gt; push: 将本地仓库推送到远程仓库</p>
<h2 id="diff">Diff</h2>
<h3 id="三种比较模式">三种比较模式</h3>
<pre tabindex="0"><code>$ git diff
</code></pre><p>比较对象：工作区 与 暂存区(此时暂存区的内容是上一次提交的内容)</p>
<p>使用情景：日常命令，看看这次改动了什么。</p>
<br/>
<pre tabindex="0"><code>$ git diff --staged
$ git diff --cached # 效果同上
</code></pre><p>比较对象：暂存区 与 版本库(上一次提交的内容)</p>
<p>使用情景： <code>add</code> 所有改动后，<code>git diff</code> 将不会显示任何东西了，在 <code>commit</code> 之前，仍可以使用 <code>--staged</code> 进行对比。</p>
<br/>
<pre tabindex="0"><code>$ git diff HEAD
</code></pre><p>比较对象：工作区 与 版本库(上一次提交的内容)</p>
<p>使用情景：比如 <code>add</code> 后，又对这个文件进行了修改，在再次 <code>add</code> 之前，想看看在上一次提交之前都做了哪些改动。</p>
<br/>
<p>经过自己动手测试，通过 Diff 章节应该能基本掌握工作区、暂存区、版本库之间的关系了。</p>
<h3 id="diff-修饰命令">diff 修饰命令</h3>
<p>diff 默认是按行显示区别的，这两个命令会获得一种对长行小改动而言更易读的报告：</p>
<pre tabindex="0"><code>$ git diff --color-words
$ git diff --word-diff
</code></pre><br/>
<p>不输出代码改动，仅仅告诉你哪些文件遭遇了改动：</p>
<pre tabindex="0"><code>$ git diff --stat
</code></pre><h2 id="log">Log</h2>
<p>了解仓库的提交历史：</p>
<pre tabindex="0"><code>$ git log
</code></pre><p>关于 40 位的 16 进制字符：(Git 保证完整性)</p>
<blockquote>
<p>Git 中所有数据在存储前都计算校验和，然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层，是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件，Git 就能发现。</p>
<p>Git 用以计算校验和的机制叫做 SHA-1 散列（hash，哈希）。 这是一个由 40 个十六进制字符（0-9 和 a-f）组成的字符串，基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样：</p>
</blockquote>
<pre tabindex="0"><code>24b9da6552252987aa493b52f8696cd6d3b00373
</code></pre><blockquote>
<p>Git 中使用这种哈希值的情况很多，你将经常看到这种哈希值。 实际上，Git 数据库中保存的信息都是以文件内容的哈希值来索引，而不是文件名。</p>
</blockquote>
<br/>
<pre tabindex="0"><code>$ git log --oneline
</code></pre><p>每行一个简短的概要：标识符+提交信息</p>
<br/>
<pre tabindex="0"><code>$ git log --patch
</code></pre><p>在原始 log 显示内容的基础上，增加每次提交的代码改动情况。</p>
<br/>
<pre tabindex="0"><code>$ git log --stat
</code></pre><p>在原始 log 显示内容的基础上，增加每次提交的代码改动情况。(不输出代码改动，仅仅告诉你哪些文件遭遇了改动，类似 diff 中的 <code>--stat</code> 效果)</p>
<br/>
<pre tabindex="0"><code>$ git log -- directory/filename.ext
</code></pre><p>后接 <code>--</code> 再接文件名，可以查看仅针对此文件的 log 记录。</p>
<br/>
<p>常用组合命令</p>
<pre tabindex="0"><code>$ git log --graph --all --decorate --oneline
</code></pre><p>支持分支、标签的查看，快速了解整个项目的发展历程。</p>
<h2 id="remove">Remove</h2>
<h3 id="-git-rm"><code>$ git rm</code></h3>
<blockquote>
<p>可以不用学习的命令，增删改都可以用 add 命令登记。</p>
</blockquote>
<pre tabindex="0"><code>$ git rm xxx
</code></pre><p>该命令完成两件事：</p>
<ol>
<li>删除文件</li>
<li>将删除文件这个操作&rsquo;&lsquo;登记&rsquo;&lsquo;到暂存区</li>
</ol>
<p>如果你在本次变更中只进行了此次操作，可以直接 <code>commit</code>，不用再 <code>add</code>  登记了。</p>
<p>如果你通过终端执行了 <code>rm</code> 操作 / 在编辑器或 IDE 中执行了删除操作 / 在电脑上直接删除文件：</p>
<p>则只完成了第一步的内容，仍然可以通过 <code>git rm xxx</code> 命令将删除文件这个改动登记到暂存区。</p>
<br/>
<br/>
<h3 id="-git-rm---cached"><code>$ git rm --cached</code></h3>
<p>这个命令将删除一个文件，但并不是从系统中真正的删除。只是告诉 git 请不要再跟踪这个文件，这个文件将仍然保留在我的工作区中。</p>
<p>情景说明：当我使用 JetBrains 全家桶时，项目下面会有一个 <code>.idea/</code> 的目录，里面也许会包含一些个人信息或无用信息，这个目录已经被纳入 git 管理了。</p>
<p>目的：并不在本地删除 <code>.idea/</code> 目录及其中文件，只是取消被 git 追踪。</p>
<p>需配合 <code>.gitignore</code> 文件使用。</p>
<ol>
<li>创建 <code>.gitignore</code> 文件，写入一行内容：<code>.idea/</code> 即可。</li>
<li><code>$ git rm -r --cached .idea/</code> （-r 是递归目录，如果只是单个文件可取消这个参数）</li>
<li>add 与 commit 完成本次修改</li>
</ol>
<p>以后即使 <code>.idea/</code> 目录里面发生了文件的增删改，git 也不会理会。</p>
<h2 id="move">Move</h2>
<pre tabindex="0"><code>$ git mv file.ext xxx/file.ext
</code></pre><p>与 <code>rm</code> 类似，同时完成移动与 add。</p>
<p>基本很少用到，一般都用系统自带的文件管理器或 IDE、编辑器来移动文件，然后 <code>add</code> 即可。</p>
<p>建议使用情景：在同一次提交前，既修改了超过 50% 的代码，又想修改文件名。（参考忒修斯之船）</p>
<br/>
<pre tabindex="0"><code>$ git log --stat -M --follow directory/file.ext
</code></pre><p>加上 <code>-M —follow</code> 参数，可以 log 出文件的移动。</p>
<h2 id="ship-of-theseus-忒修斯之船">Ship of Theseus (忒修斯之船)</h2>
<p>用<a href="https://zh.wikipedia.org/zh-hans/%E5%BF%92%E4%BF%AE%E6%96%AF%E4%B9%8B%E8%88%B9" target="_blank" rel="noopener">忒修斯悖论</a>来比喻代码修改：</p>
<ul>
<li>某些 CVS：当移动文件后，它认为只是一个完全不同的东西，无法追踪文件的移动过程。</li>
<li>某些企业版 CVS：每个文件都有标识，有个数据库来记录，可以轻易的追踪文件的移动。</li>
<li>Git：当一个文件至少有 50% 相似度时，这是同一个文件，小于 50% 时，这是一个新文件。</li>
</ul>
<p>在移动并修改文件后 commit，Git 会反馈出一个百分比：</p>
<pre tabindex="0"><code>[master 48f02f2] 本次提交信息
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename xxx =&gt; xxx/xxx (100%)
</code></pre><p>100% 即代表是纯移动，未做修改。</p>
<p>默认为 50%，低于这个阈值时，Git 会直接显示创建与删除：</p>
<pre tabindex="0"><code>[master 9a28f41] 本次提交信息
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 xxx
 delete mode 100644 xxx/xxx
</code></pre><p>50% 这个默认数值是可以修改的，视频只是简单打了个示例代码并未详细说明，我觉得这可能是个几乎永远不会用到的功能。</p>
<h2 id="ignore">Ignore</h2>
<p>创建 <code>.gitignore</code> 文件并写入规则，来使 Git 去忽略哪些你不想纳入版本控制的文件与文件夹。</p>
<p>在被 gitignore 之前已经被 Git 追踪的文件不受 gitignore 规则的影响。</p>
<p>比如 Python 生成的 <code>__pycache__</code> 文件夹，JB 全家桶的 <code>.idea</code> 文件夹，macOS 的 <code>.DS_Store</code> 文件，都属于无用文件。或者存储了数据库密码的配置文件，是绝对不能纳入版本控制的。</p>
<h3 id="gitignore-书写规则">.gitignore 书写规则</h3>
<pre tabindex="0"><code># 注释行以 # 开头
# 文件名中有 # 怎么办 -&gt; 加一个反斜杠转义
# 文件名中有 ! 怎么办 -&gt; 加一个反斜杠转义
# 文件名最后有空格怎么办 -&gt; 加一个反斜杠转义

# 忽略文件，直接书写文件名
.DS_Store

# 忽略目录，以 / 结尾
# foo/ 会忽略 foo 目录及此目录下所有内容（但不忽略同名的 foo 文件）
foo/

# 支持通配符 *，忽略所有以 .log 结尾的文件
*.log

# 此文件除外
!a.log
# 如果 a.log 父级目录被忽略，Git 并不会递归这个目录来寻找 a.log
# 即如果 a.log 在 foo/ 中（foo/ 目录已被忽略），写这条规则也没用

# 忽略 bar/ 目录内除了 abc.txt 的文件
bar/*
!abc.txt

# 递归忽略所有 foo 文件和目录
**/foo

# 递归忽略所有 foo 目录及其子目录下的 bar.txt 文件
foo/**/bar.txt
</code></pre><h3 id="全局忽略">全局忽略</h3>
<p>在 <code>~/.gitconfig</code> 中查看全局忽略文件的配置（默认即可）：</p>
<pre tabindex="0"><code>...
[core]
	excludesfile = /Users/xxx/.gitignore_global
...
</code></pre><p>如果没有配置，可以复制粘贴上面的，或者：</p>
<pre tabindex="0"><code>$ git config --global core.excludesfile ~/.gitignore_global
</code></pre><p>编辑 <code>~/.gitignore_global</code> 文件，规则相同。</p>
<p>在 macOS 中安装完 Git，默认的 <code>.gitignore_global</code> 应该是这样的：</p>
<pre tabindex="0"><code>*~
.DS_Store
</code></pre><p>忽略了所有以 <code>~</code> 结尾的文件，忽略了所有 <code>.DS_Store</code> 文件。</p>
<p>全局忽略适用于那些无论使用任何语言或 IDE 都需要忽略的文件，但是此文件只对自己有效，如果想让忽略规则对协作开发的所有成员有效，需要在项目目录正常建立 <code>.gitignore</code> 文件并纳入版本控制。</p>
<h3 id="查看当前已被忽略的所有内容">查看当前已被忽略的所有内容</h3>
<pre tabindex="0"><code>$ git ls-files --others --ignored --exclude-standard
</code></pre><h3 id="强制-add-被-gitignore-忽略的文件">强制 add 被 gitignore 忽略的文件</h3>
<pre tabindex="0"><code>$ git add -f filename
</code></pre><h3 id="检测-gitignore-规则">检测 gitignore 规则</h3>
<p>在日常 <code>git add .</code> 时发现某一文件并不想忽略，但是已经被忽略了，检测命令：</p>
<pre tabindex="0"><code>$ git check-ignore -v filename
</code></pre><h2 id="branch">Branch</h2>
<h3 id="查看分支">查看分支</h3>
<pre tabindex="0"><code>$ git branch
</code></pre><p>显示分支一览表，当前所在分支前面有 * 表示。</p>
<h3 id="创建分支">创建分支</h3>
<pre tabindex="0"><code>$ git branch 新分支名
</code></pre><h3 id="删除分支">删除分支</h3>
<pre tabindex="0"><code>$ git branch -d 分支名
</code></pre><p>如果分支没有完全合并，Git 会抛出一个 error，提示你需要将 <code>-d</code> 改成 <code>-D</code>。</p>
<h4 id="切换分支">切换分支</h4>
<pre tabindex="0"><code>$ git checkout 分支名
</code></pre><h2 id="checkout">Checkout</h2>
<h3 id="切换分支-1">切换分支</h3>
<pre tabindex="0"><code>$ git checkout 分支名
</code></pre><h3 id="创建并切换分支">创建并切换分支</h3>
<pre tabindex="0"><code>$ git checkout -b 分支名
</code></pre><p>相当于同时执行了 <code>git branch 分支名</code> 和 <code>git checkout 分支名</code>。</p>
<h3 id="detached-head-头指针分离">Detached head (头指针分离)</h3>
<p>先通过 log 查找到某一时刻的 commit 16 进制标识码。</p>
<p>这个命令会让你的工作区会改变为这次提交时的状态：</p>
<pre tabindex="0"><code>$ git checkout 12563de6382baaaaf78c58085b4b9abbe5b26608
</code></pre><p>Git 会提示：</p>
<pre tabindex="0"><code>注意：正在检出 &#39;12563de6382baaaaf78c58085b4b9abbe5b26608&#39;。

您正处于分离头指针状态。您可以查看、做试验性的修改及提交，并且您可以通过另外
的检出分支操作丢弃在这个状态下所做的任何提交。

如果您想要通过创建分支来保留在此状态下所做的提交，您可以通过在检出命令添加
参数 -b 来实现（现在或稍后）。例如：

  git checkout -b &lt;新分支名&gt;

HEAD 目前位于 12563de 本次的commit message
</code></pre><p>这时 checkout 命令相当于一个时光穿梭机，你可以检出任意一次提交时的状态。</p>
<p>注意这不是版本回退。如果你强行修改 + add + commit，Git 会自动帮你创建一个分支。</p>
<p>退出时光穿梭机：</p>
<pre tabindex="0"><code>$ git checkout 分支名
</code></pre><h3 id="discarding-edits-撤销修改">Discarding edits (撤销修改)</h3>
<p><a href="#%e6%92%a4%e9%94%80%e4%bf%ae%e6%94%b9%e4%b8%8e%e7%89%88%e6%9c%ac%e5%9b%9e%e9%80%80">见下面章节</a></p>
<h2 id="merge">Merge</h2>
<h3 id="合并分支">合并分支</h3>
<pre tabindex="0"><code>$ git merge dev
</code></pre><p>将 dev 分支合并到当前分支，dev 分支会仍然存在。</p>
<h3 id="fast-forward">Fast-forward</h3>
<ol>
<li>假设当前只有 master 分支</li>
<li>创建并切换到 dev 分支</li>
<li>进行了一次或 N 次的修改，但是 master 分支根本没人动</li>
<li>切换到 master 分支，合并 dev 分支</li>
</ol>
<p>即便会导致冲突的地方，也会被 dev 分支的内容覆盖。</p>
<p>这就是 Fast-forward （快进）合并模式，关键点在于 master 分支无人推进。</p>
<p>缺点：历史记录是一条冗长的直线，删除分支后会丢失分支信息。</p>
<h3 id="解决冲突">解决冲突</h3>
<p>当 master 和 dev 两条分支都并行推进的时候，在 master 分支合并 dev 分支时，如果同一行都被修改了，就会产生冲突。</p>
<pre tabindex="0"><code>自动合并 xxx
冲突（内容）：合并冲突于 xxx
自动合并失败，修正冲突然后提交修正的结果。
</code></pre><p>冲突以  <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>  <code>=======</code>  <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code> 隔开，分别展示两个分支的不同内容。</p>
<pre tabindex="0"><code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
master!!!
=======
dev!!!
&gt;&gt;&gt;&gt;&gt;&gt;&gt; dev
</code></pre><p>取其一或将这一整体变成你想要的内容即可。</p>
<h3 id="--abort"><code>--abort</code></h3>
<pre tabindex="0"><code>$ git merge dev
... (发现冲突)
$ git merge --abort
</code></pre><p><code>--abort</code> 选项会尝试恢复到你运行合并前的状态，相当于你没有进行本次合并。</p>
<h3 id="--suqash"><code>--suqash</code></h3>
<pre tabindex="0"><code>$ git merge --squash dev
$ git commit -m &#34;提交信息&#34;
</code></pre><p>与直接合并结果相同，但是不提交、不移动 <code>HEAD</code>，因此需要一条额外的 <code>commit</code> 命令。</p>
<p>合并后 master 分支很干净，只保留一条记录。</p>
<p>删除 dev 分支后，dev 分支信息消失。</p>
<h3 id="--no-ff"><code>--no-ff</code></h3>
<pre tabindex="0"><code>$ git merge --no-ff dev -m &#34;提交信息&#34;
</code></pre><p>禁用 Fast-forward 模式，这样在删除分支后也会保留分支信息。</p>
<p>我觉得这个命令记录的提交内容比较全面且容易理解，但分支多的时候会让历史记录看起来比较混乱。</p>
<p>删除 dev 分支后，dev 分支信息仍然保留。</p>
<h2 id="network">Network</h2>
<h3 id="remotes">Remotes</h3>
<pre tabindex="0"><code>$ git remote add 远端名称 远端地址
# 例如：
$ git remote add origin https://github.com/aaa/bbb

# 修改 URL
$ git remote set-url origin https://github.com/aaa/ccc

# 删除远端链接
$ git remote rm 远端名称
# 例如：
$ git remote rm origin

# 查看所有远端链接
$ git remote -v

# 查看所有远端分支名
$ git branch -r
# 所有远端的分支前都加上了远端名称，例如 origin/master、origin/dev
</code></pre><blockquote>
<p>终于知道 origin 到底是什么意思了。</p>
<p>其实没什么意思，就是约定俗成的，如果你只有一个远端，比如这份代码只放在 Github 上，或只放在 码云 或 Coding 上，那就把远端起名叫 origin，这样大家看到了都懂。</p>
<p>如果你这份代码在本地修改后，既要 push 到 Github，又要 push 到其它某平台，那两个远端名称就可以自己定制。</p>
</blockquote>
<h3 id="fetch-pull-push">Fetch, Pull, Push</h3>
<pre tabindex="0"><code>$ git fetch origin master # 先拉取更新，fetch 不会更改本地工作区内容
$ git merge origin/master master # 将远程内容与本地内容合并
</code></pre><pre tabindex="0"><code>$ git pull origin master # 拉取并合并
</code></pre><pre tabindex="0"><code>$ git push origin master # 将本地内容推送到远程仓库
</code></pre><p>只有单个远程主机时，一般都命名为 origin。</p>
<p>在任何分支第一次 push 时，Git 会提示：</p>
<pre tabindex="0"><code>fatal: 当前分支 xxx 没有对应的上游分支。
为推送当前分支并建立与远程上游的跟踪，使用

    git push --set-upstream origin xxx
</code></pre><p>你可以输入这个命令让本地分支与远程分支建立连接。</p>
<p>也可以在每个分支的第一次 push 时使用 <code>-u</code> 参数：</p>
<pre tabindex="0"><code>$ git push -u origin xxx
</code></pre><p>以后就可以使用简化命令 <code>git push</code> 了。</p>
<p>Push 所有分支到远端：</p>
<pre tabindex="0"><code>$ git push --all
</code></pre><p>有多个远程主机时，比如 Hexo、Hugo 博客可能同时会部署到 GitHub 和 Coding，也会起不同的远程主机名，这时 <code>-u</code> 参数可以指定一个默认主机，不带参数时就默认 push 到这个远程主机。</p>
<h2 id="github-相关章节">GitHub 相关章节</h2>
<p>GUI：主要是 GitHub Desktop 的介绍，我个人日常操作更喜欢用命令行，但是 GUI 在查看历史进度和 Diff 时更方便快捷。</p>
<p>GitHub：GitHub 的相关介绍</p>
<p>Forking：GitHub 的 Fork 功能相关介绍。</p>
<p>Pull Requests：GitHub 的 Pull Requests 功能相关介绍。</p>
<h2 id="reset">Reset</h2>
<p><a href="#%e6%92%a4%e9%94%80%e4%bf%ae%e6%94%b9%e4%b8%8e%e7%89%88%e6%9c%ac%e5%9b%9e%e9%80%80">见下面章节</a></p>
<h2 id="撤销修改与版本回退">撤销修改与版本回退</h2>
<p>必须理解的概念：</p>
<p>三个区：工作区、暂存区、版本库，或三棵树：Working Directory、Index、HEAD。</p>
<p>→ 改动代码，工作区改动</p>
<p>→ add，将改动登记到暂存区</p>
<p>→ commit，将暂存区提交到版本库，HEAD 指向当前分支的最后一次提交</p>
<p>→ &hellip;</p>
<p>→ 又一次 commit，将暂存区提交到版本库，HEAD 依然指向当前分支的最后一次提交</p>
<blockquote>
<p>HEAD 是当前分支引用的指针，它总是指向该分支上的最后一次提交。 这表示 HEAD 将是下一次提交的父结点。 通常，理解 HEAD 的最简方式，就是将它看做 <strong>你的上一次提交</strong> 的快照。</p>
</blockquote>
<h3 id="撤销修改">撤销修改</h3>
<p>当你对修改不太满意，想恢复初始状态：</p>
<pre tabindex="0"><code># 单个文件撤销
$ git checkout -- 文件名
# 所有文件撤销
$ git checkout . 
</code></pre><p>如果 <code>add</code> 进暂存区了，先撤销暂存区，再撤销工作区：</p>
<pre tabindex="0"><code># 单个文件：
$ git reset HEAD 文件名
$ git checkout -- 文件名
# 多个文件：
$ git reset HEAD
$ git checkout .
</code></pre><p>如果 <code>commit</code> 进版本库了，那就用 <code>reset</code> 进行版本回退。</p>
<h3 id="reset-1">Reset</h3>
<p>reset 分为三种模式：</p>
<ul>
<li><code>--soft</code>  保持本地所有改动（工作区、暂存区不变）</li>
<li><code>--mixed</code> 默认，保持工作副本但重置索引（工作区不变）</li>
<li><code>--hard</code> 丢弃所有改动</li>
</ul>
<p>它们的主要区别在于作用覆盖的区域（工作区、暂存区）不一样，HEAD 的指向是必变的，在敲完命令后可以用 diff 的三种比较模式去验证。</p>
<p>以一个例子来讲，这是目前的状况。</p>
<pre tabindex="0"><code>$ git log --oneline
4a9dabc (HEAD -&gt; master) 3
e285589 2
116eee9 1
</code></pre><pre tabindex="0"><code>$ git reset --soft e285589
</code></pre><ul>
<li>工作区：无变化</li>
<li>暂存区：无变化</li>
<li>版本库：HEAD 指向此版本</li>
</ul>
<pre tabindex="0"><code>$ git reset e285589
$ git reset --mixed e285589 # 同上
</code></pre><ul>
<li>工作区：无变化</li>
<li>暂存区：变成此版本</li>
<li>版本库：HEAD 指向此版本</li>
</ul>
<pre tabindex="0"><code>$ git reset --hard e285589
</code></pre><ul>
<li>工作区：变成此版本</li>
<li>暂存区：变成此版本</li>
<li>版本库：HEAD 指向此版本</li>
</ul>
<h2 id="压缩提交--合并提交">压缩提交 / 合并提交</h2>
<p>例子：</p>
<pre tabindex="0"><code>$ git log --oneline
900db85 (HEAD -&gt; master) 修复刚才修复刚才修复错误导致的错误导致的错误
656915e 修复刚才修复错误导致的错误
2d7e668 修复错误
57335f5 5
ed32739 4
6a15af1 3
e285589 2
116eee9 1
</code></pre><p>我认为最后三次这种 commit message 应该合并成一个。</p>
<pre tabindex="0"><code>$ git reset --soft 57335f5
</code></pre><p>HEAD 指向了&quot;版本5&quot;，但是工作区和暂存区都是目前的状态，直接 commit 即可。</p>
<pre tabindex="0"><code>$ git commit -m &#34;fixed a big bug&#34;
</code></pre><p>再 log 查看：</p>
<pre tabindex="0"><code>$ git log --oneline
5827469 (HEAD -&gt; master) fixed a big bug
57335f5 5
ed32739 4
6a15af1 3
e285589 2
116eee9 1
</code></pre><p>除了用 <code>reset</code>，在图形化工具 GitHub Desktop 中，选中多个 commit 后点击“Squash n(选中的个数) Commit”，就可以将选中的 n 个提交合并成一个。</p>
<h2 id="tag">Tag</h2>
<p>比起混乱的 commit id，标签可以更方便的标记出重要的版本。</p>
<p>狗书《Flask Web 开发》作者配合使用 Tag 功能做了一个相当方便的时光穿梭机，比如第一章第一部分代码使用 1a 作为标签，第二章第三部分代码使用 2c 作为标签，读者只需执行 <code>git checkout 2c</code> 即可查看此次代码。</p>
<br/>
<p>查看所有标签：</p>
<pre tabindex="0"><code>$ git tag
</code></pre><br/>
<p>打标签：</p>
<pre tabindex="0"><code># 给最新的 commit 打标签：
$ git tag 标签内容

# 给指定 commit ID 打标签，如：
$ git tag 标签内容 116eee9

# 创建带有说明的标签，用-a指定标签名，-m指定说明文字，可用`git show 标签内容`查看：
$ git tag -a v0.1 -m &#34;version 0.1 released&#34; 1094adb
</code></pre><br/>
<p>删除标签：</p>
<pre tabindex="0"><code>$ git tag -d 标签内容
</code></pre><br/>
<p>删除远端标签：</p>
<p>如果已经 push 到了 GitHub 上，想删除 GitHub 上的标签：</p>
<pre tabindex="0"><code>$ git push --delete &lt;远端名成&gt; &lt;标签名称&gt;
</code></pre><p>例如：</p>
<pre tabindex="0"><code>$ git push --delete origin v1.0
</code></pre><br/>
<p>默认 push 时不推送标签，推送标签命令：</p>
<pre tabindex="0"><code># 推送单个标签
$ git push 标签内容

# 推送所有标签
$ git push --tags
</code></pre><h2 id="rebase-变基">Rebase (变基)</h2>
<p><a href="https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/rebase" target="_blank" rel="noopener">https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/rebase</a></p>
<p>推荐看一些文章后用 <a href="https://learngitbranching.js.org/" target="_blank" rel="noopener">https://learngitbranching.js.org/</a> 这个教程试一试。</p>
<p>一个简洁的工作流教程：<a href="https://www.bilibili.com/video/BV19e4y1q7JJ" target="_blank" rel="noopener">https://www.bilibili.com/video/BV19e4y1q7JJ</a></p>
<h2 id="补充">补充</h2>
<h3 id="命令行显示-utf-8-字符">命令行显示 utf-8 字符</h3>
<p>在 <code>git status</code> 等命令下使 Git 使用 utf-8 编码显示中文等字符，而不是<code>\123\123\123\123</code> 这样的格式。</p>
<p>参考：<a href="https://stackoverflow.com/questions/22827239/how-to-make-git-properly-display-utf-8-encoded-pathnames-in-the-console-window" target="_blank" rel="noopener">https://stackoverflow.com/questions/22827239/how-to-make-git-properly-display-utf-8-encoded-pathnames-in-the-console-window</a></p>
<pre tabindex="0"><code>$ git config core.quotepath off
</code></pre><p>全局：</p>
<pre tabindex="0"><code>$ git config --global core.quotepath off
</code></pre><p>还原：<code>off</code> 改成 <code>on</code>。</p>
<h3 id="bisect">bisect</h3>
<p>看到一个 <code>git bisect</code> 命令挺好玩的，用类似二分法去快速定位是哪次提交引起了当前的错误：</p>
<p><a href="http://www.ruanyifeng.com/blog/2018/12/git-bisect.html" target="_blank" rel="noopener">git bisect 命令教程 - 阮一峰的网络日志</a></p>
<h3 id="提交时关闭-issue">提交时关闭 issue</h3>
<p>参考：https://stackoverflow.com/questions/60027222/github-how-can-i-close-the-two-issues-with-commit-message</p>
<p>可以使用 <code>close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved</code> 等单词，如：</p>
<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;巴啦巴啦； close #233&#34;</span>
</span></span></code></pre></div><p>可以同时关闭多个 issue：</p>
<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;closes #1, closes #2, closes #3; YOUR COMMIT MESSAGE&#34;</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Python 异步 IO 笔记</title>
      <link>https://dvel.me/posts/python-asynchronous-io/</link>
      <pubDate>Thu, 03 Jan 2019 20:01:22 +0800</pubDate>
      <guid>https://dvel.me/posts/python-asynchronous-io/</guid>
      <description>Python异步IO编程中的协程初探、yield/send()函数、@asyncio.coroutine/yield from以及async/await的使用方法，帮助您更好地了解和应用Python异步IO编程技术。</description>
      <content:encoded><![CDATA[<h2 id="协程初探">协程初探</h2>
<p><a href="https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432090171191d05dae6e129940518d1d6cf6eeaaa969000" target="_blank" rel="noopener">协程 - 廖雪峰 Python 教程</a></p>
<p>多进程与多线程均由操作系统调度，不过协程由程序员在协程的代码里显式调度。</p>
<p>协程没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。</p>
<h2 id="yieldsend">yield/send()</h2>
<p>刚看廖老师协程一章的代码时是一脸懵逼，那么从 0 开始，了解 <code>yield</code>。</p>
<p>10 年前的好文章： <a href="http://www.cnblogs.com/coderzh/articles/1202040.html" target="_blank" rel="noopener">深入理解 yield</a></p>
<p>看完再回顾廖老师的 [生产者-消费者] 模型：</p>
<pre tabindex="0"><code class="language-pytho" data-lang="pytho">def c():
	...
	n = yield r
	...

def p(c):
	...
	r = c.send(n)
	...
</code></pre><p>终于理解 <code>yield</code> 表达式与<code>send()</code> 函数两者皆可发送与反馈，协同工作，相辅相成。</p>
<p><code>send(n)</code>，p 发送了 <code>n</code> 给 c，c 怎么接收，<code>yield</code> 的返回值即是。</p>
<p><code>yield r</code>，c 反馈了 <code>r</code> 给 p，p 怎么接收，<code>send()</code> 的返回值即是。</p>
<h2 id="asynciocoroutineyield-from">@asyncio.coroutine/yield from</h2>
<p><code>yield from</code> 语法由 Python 3.3 引进。</p>
<p>附：<a href="https://juejin.im/posts/5b3af9fb51882507d4487144" target="_blank" rel="noopener">深入理解Python的yield from语法 </a> ，摘抄部分代码：</p>
<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">def</span> <span class="nf">average_gen</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="n">average</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">new_num</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">average</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">total</span> <span class="o">+=</span> <span class="n">new_num</span>
</span></span><span class="line"><span class="cl">        <span class="n">average</span> <span class="o">=</span> <span class="n">total</span><span class="o">/</span><span class="n">count</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">proxy_gen</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield from</span> <span class="n">average_gen</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">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">calc_average</span> <span class="o">=</span> <span class="n">proxy_gen</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nb">next</span><span class="p">(</span><span class="n">calc_average</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">calc_average</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>  <span class="c1"># 打印：10.0</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">calc_average</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="mi">20</span><span class="p">))</span>  <span class="c1"># 打印：15.0</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">calc_average</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="mi">30</span><span class="p">))</span>  <span class="c1"># 打印：20.0</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">main</span><span class="p">()</span>
</span></span></code></pre></div><p><code>asyncio  </code>是 Python 3.4 版本引入的标准库，直接内置了对异步 IO 的支持。</p>
<blockquote>
<p>用 <code>asyncio</code> 提供的 <code>@asyncio.coroutine</code> 可以把一个 generator 标记为 coroutine 类型，然后在 coroutine 内部用 <code>yield from</code> 调用另一个 coroutine 实现异步操作。</p>
<p>使用 <code>yield from</code> 关键字将一个 <code>asyncio.Future</code> 对象向下传递给事件循环，当这个 <code>Future</code> 对象还未就绪时，该协程就暂时挂起以处理其他任务。一旦 <code>Future</code> 对象完成，事件循环将会侦测到状态变化，会将 <code>Future</code> 对象的结果通过 <code>send</code> 方法方法返回给生成器协程，然后生成器恢复工作。</p>
</blockquote>
<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">asyncio</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@asyncio.coroutine</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">foo</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;foo start&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</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;foo end&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@asyncio.coroutine</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">bar</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;bar start&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">10</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;bar end&#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">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">asyncio</span><span class="o">.</span><span class="n">wait</span><span class="p">([</span><span class="n">foo</span><span class="p">(),</span> <span class="n">bar</span><span class="p">()]))</span>
</span></span><span class="line"><span class="cl"><span class="n">loop</span><span class="o">.</span><span class="n">close</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"># bar start</span>
</span></span><span class="line"><span class="cl"><span class="c1"># foo start</span>
</span></span><span class="line"><span class="cl"><span class="c1"># (等了5秒的IO操作)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># foo end</span>
</span></span><span class="line"><span class="cl"><span class="c1">#（又等了5秒的IO操作）</span>
</span></span><span class="line"><span class="cl"><span class="c1"># bar end</span>
</span></span></code></pre></div><h2 id="asyncawait">async/await</h2>
<p>Python3.5 中引入的新语法 <strong>async</strong> 和 <strong>await</strong> 可以让协程代码更简洁易读，也让协程表面上与生成器区分开。</p>
<p>代码仅需进行简单的替换：</p>
<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">asyncio</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">foo</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;foo start&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</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;foo end&#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">async</span> <span class="k">def</span> <span class="nf">bar</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;bar start&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">10</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;bar end&#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">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">asyncio</span><span class="o">.</span><span class="n">wait</span><span class="p">([</span><span class="n">foo</span><span class="p">(),</span> <span class="n">bar</span><span class="p">()]))</span>
</span></span><span class="line"><span class="cl"><span class="n">loop</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span></code></pre></div><p>另推荐一篇好文章：<a href="http://bigsec.com/bigsec-news/wechat-20171130-Python" target="_blank" rel="noopener">谈谈Python协程技术的演进</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>再见，双点医院！</title>
      <link>https://dvel.me/posts/goodbye-two-point-hospital/</link>
      <pubDate>Sun, 09 Sep 2018 18:42:24 +0800</pubDate>
      <guid>https://dvel.me/posts/goodbye-two-point-hospital/</guid>
      <description>游戏《双点医院》的介绍、攻略与评价。</description>
      <content:encoded><![CDATA[<blockquote>
<p>终于肝完了主题医院的精神续作——双点医院。。。</p>
<p>太肝了。。。</p>
</blockquote>
<p>这一代的病人依然没有摒弃「请病人不要死在走廊上」的优良传统，如果你把一个病人治死了，他会坚持换完衣服走出病房，然后再在走廊死掉，再化为鬼魂，为周围的病人启动一个「加速行走」的Buff。。。</p>
<p>因为这个加速行走的Buff，我甚至都不招聘有抓鬼技能的员工了。</p>
<h2 id="游戏进程">游戏进程</h2>
<ol>
<li>入场</li>
<li>接待</li>
<li>诊断</li>
<li>治疗</li>
<li>离场</li>
</ol>
<p>中途可能包含「愤怒离开」「治疗效果不佳」「死亡」。</p>
<p>在接受治疗前就死亡，是因为排队排太久，健康值降为 0。</p>
<p>愤怒离开的主要原因是心情降为 0。</p>
<h2 id="诊断流程-妈的智障">诊断流程 （妈的智障）</h2>
<p>→ 全科 → 诊断 → 全科 → 诊断 → 全科 → 治疗</p>
<p>如果第一次全科就100%，直接治疗。</p>
<p>即便到诊断室已经100%了，病人也会再次返回全科。（大夫可能是说你去照个X光回来给我看看）</p>
<p>如果已有的诊断室已经用完，仍没到100%，会发出消息，问你是送回家、等待、治疗？</p>
<p>在后期基本只有这两种情况：</p>
<ul>
<li>
<p>进场 → 全科 → 治疗 → 离场或死亡</p>
</li>
<li>
<p>进场 → 全科 → 某个诊断室 → 全科 → 治疗 → 离场或死亡</p>
</li>
</ul>
<p>全科技能跟上的话，很少有第三次复诊。</p>
<h2 id="科室">科室</h2>
<table>
  <thead>
      <tr>
          <th style="text-align: left">设施</th>
          <th></th>
          <th>护士</th>
          <th></th>
          <th></th>
          <th>医生</th>
          <th></th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">接待处</td>
          <td></td>
          <td>药房</td>
          <td>3 x 3</td>
          <td></td>
          <td>【全科】</td>
          <td>3 x 3</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left">休息室</td>
          <td></td>
          <td>【综合诊断】</td>
          <td>3 x 3</td>
          <td></td>
          <td><strong>【精神病学】</strong></td>
          <td>3 x 3</td>
          <td>精神学</td>
      </tr>
      <tr>
          <td style="text-align: left">厕所</td>
          <td></td>
          <td>【心脏病科】</td>
          <td>3 x 3</td>
          <td></td>
          <td>脱光诊所</td>
          <td>3 x 3</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left">培训</td>
          <td></td>
          <td>注射室</td>
          <td>3 x 3</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left">研究</td>
          <td></td>
          <td>【体液分析】</td>
          <td>3 x 3</td>
          <td></td>
          <td><strong>【DNA实验室】</strong></td>
          <td>4 x 3</td>
          <td>遗传学</td>
      </tr>
      <tr>
          <td style="text-align: left">营销学</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left">咖啡厅</td>
          <td></td>
          <td><strong>【病房】</strong></td>
          <td>4 x 3</td>
          <td></td>
          <td>流行锅实验室</td>
          <td>4 x 4</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td>骨科病房</td>
          <td>4 x 3</td>
          <td></td>
          <td>拔头室</td>
          <td>4 x 4</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td>色疗室</td>
          <td>4 x 3</td>
          <td></td>
          <td>电疗</td>
          <td>4 x 4</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td>木乃伊</td>
          <td>4 x 3</td>
          <td></td>
          <td>分辨率</td>
          <td>4 x 4</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td>【X 光】</td>
          <td>4 x 4</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td>有害动物</td>
          <td>4 x 4</td>
          <td></td>
          <td>【超级磁力共振】</td>
          <td>4 x 4</td>
          <td>放射学</td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td>小丑诊所</td>
          <td>4 x 4</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td>折疗室</td>
          <td>5 x 3</td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: left"></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td>手术室（医+护）</td>
          <td>4 x 3</td>
          <td>外科学</td>
      </tr>
  </tbody>
</table>
<p>上表【 】中为具有诊断功能的科室。</p>
<p>加粗项「病房」「精神病」「DNA」都是既可以诊断又可以治疗的。</p>
<ul>
<li>培训室：一个就够，至少弄 50 个 4% 加成的书柜，增加培训效率。</li>
<li>研究：一个都不要，之前地图的研究是通用的。（你在这关如果有新研究，回老地图研发也是可以的）</li>
</ul>
<p>房间等级，5 级封顶，豪华房间对员工有加成，￥300 的奖章是最高性价比。</p>
<h2 id="人物需求">人物需求</h2>
<blockquote>
<p>人生在世，无外乎吃喝玩乐。</p>
</blockquote>
<ul>
<li>温度</li>
<li>卫生</li>
</ul>
<p>上面两个洗手液和暖气/空调可以简单解决。</p>
<ul>
<li>吃</li>
<li>喝</li>
<li>玩</li>
</ul>
<p>售货机解决吃喝。</p>
<p>游戏机解决玩。</p>
<p>咖啡厅可以同时解决「吃」和「喝」，并赐予一个开心 Buff。</p>
<ul>
<li>厕所</li>
</ul>
<p>如果你建了一些吃喝建筑，但没有厕所。。。</p>
<p>他就会把新鲜的大便拉到地上，地上时而出现的一滩水就是病人撒的尿。</p>
<h2 id="技能选择">技能选择</h2>
<p>简单来说，方便管理的话。。。</p>
<p>因为后期全科技能很高，一个往返基本能就诊断 100%。</p>
<ul>
<li>勤杂工：留一个升级，剩下全维护。</li>
<li>客服：无脑接待</li>
<li>护士：全部治疗，不要诊断，无需任何管理操作，自动轮换。</li>
<li>医生：全部治疗，不要诊断，无需任何管理操作，自动轮换。</li>
</ul>
<p>这么玩主要还是因为放弃了很多诊断室，治疗技能是为了保障治愈率。</p>
<p>其中需要规划一下全科大夫，全部加全科，只负责全科科室，20级以下的医院十个足够。</p>
<h2 id="核心战略">核心战略</h2>
<ul>
<li>让员工开心，Buff 加成，咖啡厅 + 休息室 + 厕所 + 5级全科科室。（咖啡厅与厕所设置成只允许员工使用）</li>
</ul>
<p>科室里不放咖啡机和零食，让员工休息时去咖啡厅吃喝。</p>
<ul>
<li>让病人迅速滚蛋，不要让他吃、喝、玩乐、拉撒，150天内要么把他治好，要么把他治死。</li>
</ul>
<p>这是一个塔防游戏。</p>
<ul>
<li>
<p>让病人保持高效率，除了已经避免的吃喝和上厕所，长椅也不摆，让病人在排队时一直排排站好。</p>
</li>
<li>
<p>无论病人得了什么病，任何诊断室（包括全科）都能检查出来</p>
</li>
<li>
<p>地域分配——集中诊断：集中全科与诊断室，让病人走最少的步数完成诊断。</p>
</li>
<li>
<p>治疗区：随便放，放远处，这是病人的最后一步，在进入治疗室付款前别死了就行。</p>
</li>
<li>
<p>舍弃无用的诊断室，「病房」、「精神」、「DNA」充当诊断室。</p>
</li>
</ul>
<p>为保持循环效率，「病房」的床位、「精神」与「DNA」的数量要适当增加。</p>
<p>超级磁力共振是收费最高的诊断科室，可以考虑。</p>
<h2 id="前期迅速赚钱战略">前期迅速赚钱战略</h2>
<p>落地：一接待一全科一病房。</p>
<p>除了病房这样的，全部按最小空间建造，方便后期调整位置。</p>
<p>全科慢慢增加。</p>
<p>病房吞吐量大，多弄几个护士和床位。</p>
<p>然后一个一个的补治疗室，先不补「精神」和「DNA」。</p>
<p>病人在完成「全科 → 病房 → 全科」这个诊断流程后就会弹出信息，诊断率只有xxx，治疗还是送回家？送去治疗就好，前期不要在乎治愈率，能赚钱就好。</p>
<p>期间招聘跟上，然后完善科室就可以了，这样是稳赚不赔的。</p>
<p>在满足人员配置后，一次性补足「精神」和「DNA」，如果先补这俩但是数量不足，病人就会去排大长队。</p>
<p>所有规划完毕后，上培训，慢慢就进入后期了。</p>
<h2 id="摩天塔通关配置">摩天塔通关配置</h2>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2018-09-09A.webp"
            alt="双点医院摩天塔"
            width="3360"
            height="2100"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<blockquote>
<p>中间为集中诊断区，左下为治疗区，右下就放了个培训室。</p>
</blockquote>
<p>这是我第三次干摩天塔了，之前铺的满地图都是，13 个场地铺满 9 个了，然后铺烦了删档重来了。</p>
<p>这个低配简配，本来是想着舍弃外围 8 个场地，只玩内围 4 个场地的，没想到直接干到通关了。</p>
<p>全科：8 个房间，10 个员工。</p>
<p>精神：4 个房间，4 个员工。</p>
<p>DNA：4 个房间，4 个员工。</p>
<p>病房：1 个 6 床及以上的房间，4 个及以上的员工，因为员工老瞎溜达，效率不够，人数来凑。</p>
<p>每个治疗室 1 个，员工自己可以补三四个轮休的。</p>
<p>手术室太费时间，适当增加。</p>
<p>等级压到 20 级以下，这样全科不会产生排队。</p>
<h2 id="评价">评价</h2>
<p><strong>差评。</strong></p>
<ul>
<li>没有「房间模板」或「复制房间」这个功能。（关键点，有这个功能就是好评）</li>
</ul>
<p>前期造全科就够烦的了。</p>
<p>最后一关摩天塔，我第一次想铺开玩大医院，病人数量增加的太多，没有复制功能烦的我重新开档了。</p>
<ul>
<li>
<p>价格偏高，关卡游戏性重复。</p>
</li>
<li>
<p>伤肝。。。</p>
</li>
<li>
<p>没有一键「让所有已诊断病人滚去治疗」选项，前期拥堵的时候得一个一个点。</p>
</li>
<li>
<p>人物 AI 智障</p>
</li>
</ul>
<p>比如病房排队人多的时候，有人同时开门和关门，能把人挤出去。</p>
<p>休息室、培训室这种大量进出，员工都跟傻子似的，开关门效率低。</p>
<p>病房的屏风，如果你在门左右各方一个，病人只会去右边的，即便左边是空的，病人还会去右边排队，除非右边已经有人排队，他才会去左边的，利用效率低下。</p>
<p>排队，科室没有病人，2 号位已经站在门前，1 号位刚拉完屎从远方赶来，2 号位就干等着他。</p>
<p>如果你仔细看一会病房，包括骨科，护士们的治疗效率真是太低了急死人，各种不知所谓乱走动。</p>
<ul>
<li>各种 BUG，据说病房 BUG 已经修复，这个 BUG 是真tm烦。</li>
<li>逼死强迫症！</li>
</ul>
<p>最后一关了，45 星全部到手了，玩家要真真正正的开始创造大医院了，不能复制房间我都忍了。</p>
<p>结果最后一关居然是不对称的。。。最外围有两处和别的长得不一样，偏小还少了个门。</p>
<ul>
<li>管理方式弱智</li>
</ul>
<p>玩过 Rimworld 后很难接受这种糟糕的管理方式了，尤其是最后一关铺大医院的时候，我需要统计全科的员工人数、精神和DNA的员工人数，病房专属的员工人数等等来方便我招聘，你只能一页一页的翻。</p>
<p>逼得我自己使用表格进行管理，如图。。。：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2018-09-09B.webp"
            alt="双点医院"
            width="2908"
            height="1224"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<blockquote>
<p>绿底色为【诊断】，红色字为【诊断+治疗】</p>
<p>表格我放谷歌文档上了 <a href="https://docs.google.com/spreadsheets/d/1n93n7JlrkRTsPIibfZGoCDb4gzwXMyQmjeulHPflnJk/edit?usp=sharing" target="_blank" rel="noopener">https://docs.google.com/spreadsheets/d/1n93n7JlrkRTsPIibfZGoCDb4gzwXMyQmjeulHPflnJk/edit?usp=sharing</a></p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>用 CloudXNS 解决 CNAME 与 MX 记录冲突</title>
      <link>https://dvel.me/posts/use-cloudxns-solve-cname-mx-conflict/</link>
      <pubDate>Wed, 01 Aug 2018 22:14:54 +0800</pubDate>
      <guid>https://dvel.me/posts/use-cloudxns-solve-cname-mx-conflict/</guid>
      <description>使用 CloudXNS LINK 记录，快速解决 CNAME 与 MX 记录冲突。详细教程介绍如何使用 LINK 记录实现博客与域名邮箱同时使用。</description>
      <content:encoded><![CDATA[<h2 id="需求">需求</h2>
<p>需求是这样的：</p>
<ol>
<li>我的博客是 dvel.me，已经部署在 Coding Pages 或 Github Pages 上，域名解析用的是 <strong>CNAME</strong> 记录。</li>
<li>我希望我的域名邮箱是后缀是 @dvel.me，域名解析用的是 <strong>MX</strong> 记录。</li>
<li>冲突了。。。</li>
</ol>
<pre tabindex="0"><code>@	CNAME	-	pages.coding.me
@	MX	1	aspmx.l.google.com
</code></pre><p>因为都用了裸域，如果要放弃裸域，采用 <code>www.dvel.me</code> 又觉得强迫症，Coding 又不提供 A 解析。</p>
<h2 id="用-cloudxns-快速解决">用 CloudXNS 快速解决</h2>
<p>CloudXNS 有一个 <strong>LINK</strong> 记录：</p>
<pre tabindex="0"><code>LINK：CloudXNS的私有类型，可将用户配置的CNAME隐藏。
别名链接记录，隐式将解析权委托给目标域名。
</code></pre><p>官方详解：<a href="https://www.cloudxns.net/Support/detail/id/126.html" target="_blank" rel="noopener">CloudXNS之详解LINK记录</a></p>
<p>需要额外使用一个域名，假设这个域名为 another.com。</p>
<p>将裸域的 <strong>CNAME</strong> 记录改成 <strong>LINK</strong>，记录值为 <code>@another.com</code>：</p>
<pre tabindex="0"><code>@	LINK	-	@another.com
@	MX	1	aspmx.l.google.com
</code></pre><p>进入 another.com 的解析设置页面正常设置：</p>
<pre tabindex="0"><code>@	CNAME	-	pages.coding.me
</code></pre><p>以上，相当于绕了个弯。</p>
<p>我用的是 Coding Pages 与 G Suite，博客访问与邮件收发均无问题。</p>
]]></content:encoded>
    </item>
    <item>
      <title>你好，Hugo！</title>
      <link>https://dvel.me/posts/hello-hugo/</link>
      <pubDate>Tue, 31 Jul 2018 20:03:04 +0800</pubDate>
      <guid>https://dvel.me/posts/hello-hugo/</guid>
      <description>Hugo 是一种快速、简单的静态网站生成器，该指南提供了入门指南，介绍了建站、主题添加、博客编写、URL 管理和前置物等方面。</description>
      <content:encoded><![CDATA[<p>曾经升级完 Node 后对 Hexo 一顿折腾，感觉有点麻烦，新 MBP 入手后懒得再折腾一遍，想换到 Hugo 试试。</p>
<h2 id="quick-start">Quick Start</h2>
<h3 id="安装">安装：</h3>
<pre tabindex="0"><code>$ brew install hugo
</code></pre><h3 id="查看">查看：</h3>
<pre tabindex="0"><code>$ hugo version
</code></pre><h3 id="建站">建站：</h3>
<pre tabindex="0"><code>$ hugo new site site-name
</code></pre><h3 id="快速添加主题">快速添加主题：</h3>
<p><em>（以我正在使用的 Jane 为例）</em></p>
<pre tabindex="0"><code>$ cd site-name
$ git init
$ git clone https://github.com/xianmin/hugo-theme-jane.git --depth=1 themes/jane
$ echo &#39;theme = &#34;jane&#34;&#39; &gt;&gt; config.toml
</code></pre><h3 id="写博客">写博客：</h3>
<p>页面：</p>
<pre tabindex="0"><code>$ hugo new page-name.md
</code></pre><p>文章：</p>
<pre tabindex="0"><code>$ hugo new posts/post-name.md
</code></pre><h3 id="预览调试">预览、调试：</h3>
<pre tabindex="0"><code>$ hugo server
$ hugo server -D  # 将标记为 draft: true 的草稿也生成预览
</code></pre><p>浏览器打开 <a href="http://localhost:1313/" target="_blank" rel="noopener">http://localhost:1313/</a> 即可预览。</p>
<h3 id="生成">生成：</h3>
<pre tabindex="0"><code>$ hugo
</code></pre><p>生成速度超级快！</p>
<h3 id="部署">部署：</h3>
<p>将 <code>public</code> 中所有内容部署到 Github Pages 等即可。</p>
<h2 id="url-管理">URL 管理</h2>
<p>我喜欢这样的 url ：<code>dvel.me/posts/1</code> <code>dvel.me/posts/2</code> &hellip;</p>
<p>编辑 <code>config.toml</code> ，修改或增加：</p>
<pre tabindex="0"><code>[permalinks]
  post = &#34;/posts/:slug&#34;
</code></pre><p>在文章的 Front Matter 中新增 <code>slug</code> 并正确填写即可。</p>
<p>也可以参考官方文档的 <a href="https://gohugo.io/content-management/urls/" target="_blank" rel="noopener">URL Management</a> 修改成 <code>&quot;/posts/:year-:month-:day&quot;</code> 等各种格式。</p>
<h2 id="front-matter">Front Matter</h2>
<p>支持 YAML、TOML、JSON 格式，推荐使用 YAML 格式，可以少敲一些引号。</p>
<p>编辑 <code>&lt;your site&gt;/archetypes/default.md</code> 文件可以设定模板，使用 <code>$ hugo new page-name.md</code> 命令后可以自动生成。</p>
<pre tabindex="0"><code>---
title: {{ replaceRE &#34;[0-9]{2,}&#34; &#34;&#34; .Name | replaceRE &#34;^-*&#34; &#34;&#34; | replaceRE &#34;-&#34; &#34; &#34; | title }}
author: Dvel

date: {{ .Date }}
lastmod: 

tags:
- 

draft: true
---
</code></pre><h2 id="参考--感谢">参考 &amp; 感谢</h2>
<ul>
<li><a href="https://blog.olowolo.com/posts/hugo-quick-start/" target="_blank" rel="noopener">Hugo 从入门到会用</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>为 Mac 打造 zsh command line 环境</title>
      <link>https://dvel.me/posts/build-zsh-command-line-environment-for-mac/</link>
      <pubDate>Mon, 30 Jul 2018 21:22:32 +0800</pubDate>
      <guid>https://dvel.me/posts/build-zsh-command-line-environment-for-mac/</guid>
      <description>如何在Mac上打造zsh命令行环境。从安装iTerm2和zsh，到安装oh-my-zsh插件和设置powerlevel9k主题，都将一一介绍。还有其他的一些终端代理方法等。</description>
      <content:encoded><![CDATA[<blockquote>
<p>折腾完，做个备忘</p>
</blockquote>
<p>样图：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2018-07-30.webp"
            alt="zsh"
            width="2000"
            height="1184"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
<h2 id="iterm-2">iTerm 2</h2>
<ul>
<li>主题</li>
</ul>
<p><a href="https://github.com/chriskempson/tomorrow-theme" target="_blank" rel="noopener">Tomorrow Night</a> - Tomorrow Night Eighties</p>
<ul>
<li>Hotkey Window</li>
</ul>
<p>我习惯只保留一个窗口，并使用 <strong>shift+空格</strong> 来从左侧或上侧呼出，在 Profiles - Window - Style 可以设置。</p>
<p>呼出的快捷键在 Profiles → Keys → Hotkey Window 设置。</p>
<ul>
<li>Natural Text Editing</li>
</ul>
<p>Profiles → Keys → Presets → Natural Text Editing</p>
<p>这个可以让你在输入时使用 command/option + ←/→ 来移动光标</p>
<h2 id="zsh">zsh：</h2>
<p>zsh 有很多优点，比如兼容 <code>!#/bin/bash</code>，更强大的 tab 补全功能，大小写自动更正，丰富的主题，命令智能纠错等等。</p>
<p>现在 macOS 默认就是 zsh 而不是 bash 了，不过我习惯不使用系统自带的东西，可以用 brew 自己装一个。</p>
<pre tabindex="0"><code>$ brew install zsh
</code></pre><p>查看当前已经安装的 shell：</p>
<pre tabindex="0"><code>$ cat /etc/shells
</code></pre><p>将 <code>/usr/local/bin/zsh</code> 加入到 <code>/etc/shells</code> 中：</p>
<pre tabindex="0"><code>$ sudo sh -c &#34;echo $(which zsh) &gt;&gt; /etc/shells&#34;
</code></pre><p>设置默认 shell：</p>
<pre tabindex="0"><code>$ chsh -s $(which zsh)
</code></pre><p>重启终端，查看默认 shell：</p>
<pre tabindex="0"><code>$ echo $SHELL
/usr/local/bin/zsh
</code></pre><p>OK.</p>
<h2 id="oh-my-zshhttpsgithubcomrobbyrusselloh-my-zsh"><a href="https://github.com/robbyrussell/oh-my-zsh" target="_blank" rel="noopener">oh-my-zsh</a>：</h2>
<p>oh-my-zsh 是一款社区驱动的、基于 zsh 的的扩展工具集，用它可以方便的更新和定制 zsh，提供了方便的主题配置、插件配置和一些内置的便捷操作。</p>
<p>安装：</p>
<pre tabindex="0"><code>$ sh -c &#34;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&#34;
</code></pre><p>安装后出现目录 <code>~/.oh-my-zsh/</code> 及配置文件 <code>~/.zshrc</code>。</p>
<h2 id="zsh-主题-powerlevel9khttpsgithubcombhilburnpowerlevel9k">zsh 主题 <a href="https://github.com/bhilburn/powerlevel9k" target="_blank" rel="noopener">powerlevel9k</a>：</h2>
<pre tabindex="0"><code>$ git clone https://github.com/bhilburn/powerlevel9k.git ~/.oh-my-zsh/custom/themes/powerlevel9k
</code></pre><p>设置主题，编辑 <code>~/.zshrc</code>：</p>
<pre tabindex="0"><code>ZSH_THEME=&#34;powerlevel9k/powerlevel9k&#34;
</code></pre><p>重启终端，OK。</p>
<p>如果字体显示问号，需要换成 <strong>powerline font</strong> 字体。</p>
<p>快速安装一个 powerline font：</p>
<pre tabindex="0"><code>$ brew cask install homebrew/cask-fonts/font-hack
</code></pre><p>在 iTerm 2 中更换字体。</p>
<h2 id="oh-my-zsh-插件">oh-my-zsh 插件</h2>
<p><code>/Users/user/.oh-my-zsh/plugins</code> 是官方自带插件，可自行激活。</p>
<p><code> /Users/user/.oh-my-zsh/custom/plugins</code> 是第三方插件，等同于 <code>$ZSH_CUSTOM/plugins</code>，可以用 git 将一些插件 clone 到这个地方。</p>
<p>另一种安装第三方插件的方法：某些插件可以用 brew 安装。</p>
<p>使用下面的方法进行安装和启用。</p>
<pre tabindex="0"><code>$ brew install zsh-syntax-highlighting # 高亮
$ brew install zsh-autosuggestions # 根据历史输入的补全建议
</code></pre><p>遵循提示，在 <code>~/.zshrc</code> 中加入以下语句：</p>
<pre tabindex="0"><code>source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
source /usr/local/share/zsh-autosuggestions/zsh-autosuggestions.zsh
</code></pre><p><code>$ source ~/.zshrc</code> 使之生效。（试了并不成功，非得重启 iTerm 才行）</p>
<h2 id="一些配置">一些配置</h2>
<p>编辑 <code>~/.zshrc</code>：</p>
<pre tabindex="0"><code># 激活自带插件，一行写一个
plugins=(
    git
    z
)

# 解决 powerlevel9k 主题下的 Python 虚拟环境没有提示：
POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(status virtualenv)
# 左侧主机名，默认是`%n@%m` 用户名@电脑名，可以改成自己喜欢的。
POWERLEVEL9K_CONTEXT_TEMPLATE=&#34;&#34;
</code></pre><h2 id="一些终端代理方法包括-https-和-ssh比如-git">一些终端代理方法：包括 http(s) 和 ssh（比如 git）。</h2>
<p><a href="/posts/mac-terminal-proxy/">配置 Mac 终端走代理</a></p>
<h2 id="参考--感谢">参考 &amp; 感谢</h2>
<ul>
<li><a href="https://medium.com/statementdog-engineering/prettify-your-zsh-command-line-prompt-3ca2acc967f" target="_blank" rel="noopener">超簡單！十分鐘打造漂亮又好用的 zsh command line 環境</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>新 Mac 新装修</title>
      <link>https://dvel.me/posts/new-mac-new-decoration/</link>
      <pubDate>Fri, 27 Jul 2018 20:22:33 +0800</pubDate>
      <guid>https://dvel.me/posts/new-mac-new-decoration/</guid>
      <description>给新到货的 MacBook Pro 重新进行各种偏好设定，和软件相关的安装与设置。</description>
      <content:encoded><![CDATA[<blockquote>
<p>新 MBP 到手后，我就预感要折腾好一阵子，因为之前把系统整的太凌乱，决定不使用 Time Machine，从头开始对 MBP 新装新居。</p>
<p>记录一下，为了以后再次更换设备时参考。</p>
<p>再次记录一下。。。因为苹果莫名其妙的 BUG 导致新电脑无法从时光机器中恢复，只好重头折腾。</p>
</blockquote>
<h2 id="偏好设置">偏好设置</h2>
<ul>
<li>
<p>系统所有偏好设置</p>
<ul>
<li>通用：关闭文稿时要求保存更改</li>
<li>Dock：将窗口最小化为应用程序图标，连按最小化
<ul>
<li>吮吸效果：<code>defaults write com.apple.dock mineffect suck; Killall Dock</code></li>
<li>添加空白格：<code> defaults write com.apple.dock persistent-apps -array-add '{&quot;tile-type&quot;=&quot;spacer-tile&quot;;}'; Killall Dock</code></li>
<li>更小的空白格：<code>defaults write com.apple.dock persistent-apps -array-add '{&quot;tile-type&quot;=&quot;small-spacer-tile&quot;;}'; Killall Dock</code></li>
<li>堆栈区网格高亮：<code>defaults write com.apple.dock mouse-over-hilite-stack -bool TRUE;killall Dock</code></li>
</ul>
</li>
<li>调度中心：关闭仪表盘（新版已经没有了），设置触发角（右下角显示桌面）</li>
<li>触摸板：滚动方向</li>
<li>Siri：关闭</li>
<li>辅助功能 - 指针控制（或鼠标与触控板） - 触控板选项：启动拖移(三指拖移)</li>
</ul>
</li>
<li>
<p>Finder 偏好设置</p>
<ul>
<li>边栏调整</li>
<li>显示所有文件扩展名</li>
<li>显示 - 显示各种栏</li>
<li>标题栏显示完整路径：<code>defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES;killall Finder</code></li>
</ul>
</li>
<li>
<p>部分快捷键重设（个人偏好）</p>
<ul>
<li>双击 command：Alfred</li>
<li>双击 option：Alfred 剪贴板</li>
<li>command + 空格：切换输入法</li>
<li>option + 空格：Alfred - File search - Navigation</li>
<li>control + 空格：spotlight</li>
<li>shift + 空格：iTerm</li>
</ul>
</li>
<li>
<p>禁用大部分 iCloud 同步</p>
</li>
</ul>
<h2 id="先安装能快速还原使用习惯的app">先安装能快速还原使用习惯的App</h2>
<ul>
<li>提前挂好 Xcode 的下载，这个比较大</li>
<li>代理工具 Surge</li>
<li>同步网盘 Dropbox</li>
<li>输入法
<ul>
<li>Rime，还原配置，同步用户词典</li>
</ul>
</li>
<li>浏览器 Firefox / Chrome
<ul>
<li>一般是自动同步，像油暴力猴、uBlacklist等插件是可以和 Dropbox 同步配置的</li>
</ul>
</li>
<li>Alfred</li>
<li>密码管理器 Bitwarden</li>
<li>邮箱 Spark</li>
</ul>
<p>如果没有用时间机器恢复，也可以从未加密的备份盘中找回备份的文件，直接复制粘贴。</p>
<p>至此，基本上只差功能性App了，大部分的使用习惯都找了回来。</p>
<p>Dropbox 可以保存的一些配置：</p>
<ul>
<li>Alfred 设置</li>
<li>JB 家的设置文件（换到云同步了）</li>
<li>代码碎片</li>
<li>IINA 的快捷键设置</li>
<li>个别浏览器插件的配置</li>
</ul>
<h2 id="app库">App库</h2>
<p>开始一个一个的下载App，这时才发现还是 Time Machine 好啊。</p>
<p>也需要注意个别 App 的反激活与同步。</p>
<ul>
<li>NTFS 需要在官网反激活一下，看到 Licences 有点变化（好像被微软收购了）
<ul>
<li><strong>Microsoft NTFS for Mac by Paragon Software</strong> 新版可用的</li>
<li><strong>Paragon NTFS For Mac 14 (Multilingual)</strong> 好像是曾经的叫法，已不可用，下载14也无法打开</li>
</ul>
</li>
</ul>
<p>参考老Mac导出的App列表，由于数量庞大几乎大部分时间都花在App的下载与设置上了。</p>
<h2 id="配置-command-line">配置 command line</h2>
<p>一步一步重新折腾。</p>
<ul>
<li>iTerm</li>
<li>homebrew</li>
<li>zsh</li>
<li>oh-my-zsh</li>
<li>powerlevel9k</li>
<li>zsh-syntax-highlighting</li>
<li>其他一些插件</li>
<li>brew 一些开发包</li>
</ul>
<h2 id="完事了洗洗睡了">完事了，洗洗睡了</h2>
]]></content:encoded>
    </item>
    <item>
      <title>秦皇岛暑期自驾的烦恼</title>
      <link>https://dvel.me/posts/troubles-qinhuangdao-self-drive/</link>
      <pubDate>Mon, 31 Jul 2017 06:47:55 +0800</pubDate>
      <guid>https://dvel.me/posts/troubles-qinhuangdao-self-drive/</guid>
      <description>自驾去秦皇岛旅游的烦恼，包括交通拥堵、停车难、景区停车位不足等问题，提醒避开周六日出行。此外，还分享了晒伤的经历，提醒游客要涂抹防晒霜。</description>
      <content:encoded><![CDATA[<p><strong>注意不要周六日去。</strong></p>
<p>周六早上 7 点出发，大概 3 个小时车程的京哈高速，足足开了 6 个多小时。</p>
<p>小宾馆没有停车位，大宾馆贵几十块钱，有停车位，有警察叔叔在路边贴条。</p>
<p>景点停车位告急。</p>
<p>新澳海底世界路上拥堵，10 分钟的路程堵了半个多小时，完事又告诉我没车位了，说前面还有停车场。</p>
<p>尼玛前面没有停车场了好不！！！</p>
<p>我再开出去 10 分钟，大热天的再背着东西走回来，太难受了。</p>
<p>干脆饶了回来，在停车场入口死等，一直等到有车位空出来。</p>
<p>周日返程同样耗费了双倍时间。</p>
<p>开车时长超过玩耍时长。。。</p>
<p>整个京哈高速，约 200 公里左右，开的非常难受。</p>
<p>不断的超车超车超车，还走了 6 个小时，不知道那些快车道慢悠悠的司机怎么想的。</p>
<p>那两天太阳不算烈，没涂防晒霜，最好还是涂上，这次又晒脱皮了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>苹果公司开发者账号申请流程</title>
      <link>https://dvel.me/posts/apple-developer-company-registration/</link>
      <pubDate>Thu, 11 May 2017 13:45:55 +0800</pubDate>
      <guid>https://dvel.me/posts/apple-developer-company-registration/</guid>
      <description>苹果开发者账号申请流程，包括邓白氏编码、开发者账号注册、付款等步骤。详细介绍了整个申请流程，有助于快速了解并成功申请。</description>
      <content:encoded><![CDATA[<blockquote>
<p>刚申请完（2017-04-19 至 2017-05-11），简单记录。</p>
<p>申请类型为：公司（Company）</p>
</blockquote>
<h2 id="提前准备">提前准备</h2>
<ul>
<li>公司网站域名</li>
<li>请公司提供邮箱（公司的域名邮箱，即网站的域名后缀）
<ul>
<li>尴尬的是我们公司没有企业域名邮箱，于是我试了试 <code>公司名称拼音@sina.com</code>，总之顺利申请下来了。</li>
</ul>
</li>
<li><del>请公司提供 VISA + 银联，或 万事达 + 银联 的双标信用卡（VISA单标卡目前不可用）</del></li>
<li>准备一个公司高层领导的姓名、性别、职位、电话</li>
<li>准备一个公司备用联系人的姓名、电话、邮箱</li>
<li>公司的一些细节（在下面）</li>
</ul>
<h2 id="注册-apple-id">注册 Apple ID</h2>
<p>2017年4月19日</p>
<p>拿这个邮箱，先去注册 Apple ID，姓名我填我自己的了，反正也能改。。。</p>
<p>注意保存好密码、密保什么的，离职时留给下一任。</p>
<h2 id="申请邓白氏编码">申请邓白氏编码</h2>
<p>2017年4月19日</p>
<ul>
<li><a href="https://developer.apple.com/programs/cn/" target="_blank" rel="noopener">https://developer.apple.com/programs/cn/</a></li>
<li>按流程操作</li>
<li>选择类型时，选择 <strong>Company / Organization</strong></li>
<li>会弹出一个警告，很多文字，在 <code>A D-U-N-S Number</code> 这栏有一个 <code>Check now &gt;</code></li>
<li>开始查询是否已经有邓白氏编码，如果没有直接按填写的信息进行注册了</li>
</ul>
<p>注意全部使用英文，要公司的英文名、英文地址之类的。</p>
<p>英文地址我直接参考了公司营业执照，自己翻译了一下。</p>
<h3 id="坑">坑：</h3>
<p>这个页面同时让我填写了公司座机；和所谓的 &ldquo;Your work contact infomation&rdquo;（我填的自己的联系方式）。</p>
<p>事实上，邓白氏会联系你填写的座机。（妈蛋，那要我的工作联系方式干啥？？？）</p>
<h3 id="邓白氏回应">邓白氏回应</h3>
<p>2017年4月21日</p>
<pre tabindex="0"><code>Thank you for submitting your D-U-N-S Number request / update to D&amp;B. It should be completed by 05/04/2017, or sooner.
Your request id is: xxxxxx-xxxxxx. 
A D&amp;B representative may be contacting you directly. Your cooperation will help to expedite the resolution of this request.
Please contact applecs@dnb.com if you have any questions.
</code></pre><p><code>xxxxxx-xxxxxx</code> 是一串数字，也就是你的 request id。邓白氏跟我说最晚会在 5月4日 处理完毕。</p>
<pre tabindex="0"><code>开始漫长的等待，期间我拨打了上海邓白氏总部的电话来查询进度：

1. 上海总部 021 2321 3636，用了一口流利上海话跟我说10点以后再打过来
2. 再次拨打，让我转邓氏编码热线：400 820 2669
3. 邓氏编码热线，让我转专门负责苹果开发者账号这方面的同事的电话：021-26107457
4. 021-26107457，打了两次，不接
5. mlgb
6. 继续等
</code></pre><p>2017年4月28日</p>
<p>再次回复，看邮件是没打通我们公司座机，所以建议留一个你能接到的座机。</p>
<p>还好我查了一下邮箱，居然让我下午3点前回复，我下午2点多看到的。。。</p>
<pre tabindex="0"><code>您好，
我是上海华夏邓白氏公司，我们需要向您核实一下企业信息。由于拨打电话xxxx-xxxxxxx无人接听，请收到邮件于4月28日下午3点前回复以下信息：
请提供
公司中文名(工商注册的中文名，如有更名请提供更名前和更名后的名称):
英文名（如无正式的英文名按字面翻译，每个单词首字母大写，英文名后缀请以Co., Ltd./LLC/Inc.结尾）：
中文地址（办公地址）:
英文地址：
邮编:
企业类型:
是否是独立企业(下设有分公司或办事处吗):
公司英文简称或英文商标:
主营业务（公司最主要从事的业务）:
员工人数：
联系人姓名：
性别：
电话（公司座机和手机）：
职位:
营业执照：
 
如果您用其它邮箱回复请在邮件中注明一下之前的邮箱以便我们区分.
 
谢谢！
</code></pre><p>和部门经理沟通后回复了邮件，1小时内，收到回复：</p>
<pre tabindex="0"><code>好的，我这边收到了您的回复，正在核实你们公司的信息，稍后办理好，24小时内系统会自动发编码到苹果注册邮箱内，最晚14个工作日编码才能使用。若着急使用，可以在一周后尝试，但请注意尝试次数不要超过3次，超过次数编码会被锁住，解锁及注册方面问题请找苹果客服，电话：4006701855
注：包含邓白氏编码的邮件是由系统自动发送的，里面的信息是当时您自己在苹果网站上提交的原始信息，并不是核实好的内容。由于使用编码时需要再次填写公司信息，请和今天核实好的公司名字与地址保持一致。
</code></pre><h2 id="邓白氏申请成功">邓白氏申请成功</h2>
<p>2017年5月2日</p>
<p>收到邮件，邓白氏申请成功。</p>
<pre tabindex="0"><code>Your D-U-N-S Number request/update submitted on 4/20/2017 with ID Number 102122-419095 has been completed. You may start using your number in 14 days.
D-U-N-S Number: xxxxxxxxx
Resolution Description: New Record Created
The following information was submitted as part of your request:
Business Name: xxxx Technology Co., Ltd 
City: xx 
Country: CHINA PEOPLES REP
Thank you for using D&amp;B&#39;s Mini Investigation Service.
</code></pre><h2 id="申请开发者账号">申请开发者账号</h2>
<p>2017年5月9日</p>
<p>之前告诉我了14天后才可以使用邓白氏编码，我侥幸试了一下，已经可以使用了，但如果失败的话，建议不要尝试超过2次。</p>
<p>这个步骤就简单了，这回我留了公司副总的手机号。</p>
<p>申请完后就显示正在处理，等两三天就行了。</p>
<p>2017年5月10日</p>
<p>副总接到了 Apple 的电话，到办公室找到我= =。。。</p>
<p>我问客服有什么事情，客服说让我留一个公司备份联系人的电话。</p>
<p>我说必须现在立马给您吗，客服说邮件解决也行。</p>
<p>一来一回收发了下邮件。</p>
<pre tabindex="0"><code>您好：

我们负责跟进您的 Apple Developer Program 注册 ID xxxxxxxxxxx 所存在的问题。
为了在紧急情况下能够联系到您的组织，我们希望存档一位备用联系人。当我们无法直接联系您时，我们会联系这位备用联系人。
请回复此电子邮件，并提供该备用联系人的信息。

名字：
姓氏：
电话号码：
电子邮件地址：
</code></pre><pre tabindex="0"><code>我们收到了您的请求，并会在一个工作日内给您回复。您的案例编号是 xxxxxxxxxxx.
如果您想与开发者支持顾问通话，请联系我们 https://developer.apple.com/contact/phone/cn。
</code></pre><p>同日下午的邮件：</p>
<pre tabindex="0"><code>Dear xxx,

Your enrollment request has been accepted. You may now review the Program License Agreement to continue your organization&#39;s enrollment in the Apple Developer Program. 

Review now 

Best regards, 
Apple Developer Program Support
</code></pre><p>万事俱备，只差钱了。</p>
<h2 id="付款">付款</h2>
<p>2017年5月11日</p>
<p>据说是 $99 美元，但我实际上在网页看到的是明确的￥688人民币。（之前给财务写的申请单写少了= =）</p>
<p>只支持 VISA 或 万事达。</p>
<p>一开始用的是副总的 VISA单标卡，一直付款失败。</p>
<p>后换到 VISA+银联双标卡，成功。</p>
<p>此处可以申请纸质发票。</p>
<h2 id="总结">总结</h2>
<p>如果有什么不懂的地方，请大家尽情拨打 Apple 的 400 客服电话，台湾腔、声音温柔甜美。</p>
]]></content:encoded>
    </item>
    <item>
      <title>UIScrollView 中使用 Masonry</title>
      <link>https://dvel.me/posts/use-masonry-in-uiscrollview/</link>
      <pubDate>Tue, 25 Apr 2017 20:44:44 +0800</pubDate>
      <guid>https://dvel.me/posts/use-masonry-in-uiscrollview/</guid>
      <description>在iOS开发中，为了实现UIScrollView中的子视图纵向排列，需要使用容器视图来撑起contentSize。本文提供了一个简单的代码示例来说明如何实现。</description>
      <content:encoded><![CDATA[<p>昨天耽误了一阵子在 scrollView 的布局上，记录一下。</p>
<p>如果可以提前确定 <code>scrollView</code> 的 <code>contentSize</code>，就简单多了，但这种情况很少。</p>
<p>一般还是按照 <code>subViews</code> 自适应的比较合适，这样就需要一个 <code>containerView</code> 来撑起 <code>scrollView</code> 的 <code>contentSize</code>。</p>
<h2 id="简单的代码示例">简单的代码示例：</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objective-c" data-lang="objective-c"><span class="line"><span class="cl"><span class="n">UIScrollView</span> <span class="o">*</span><span class="n">scrollView</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIScrollVie</span> <span class="n">new</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nb">self</span><span class="p">.</span><span class="n">view</span> <span class="nl">addSubview</span><span class="p">:</span><span class="n">scrollView</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                            
</span></span><span class="line"><span class="cl"><span class="n">UIView</span> <span class="o">*</span><span class="n">containerView</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIView</span> <span class="n">new</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">scrollView</span> <span class="nl">addSubview</span><span class="p">:</span><span class="n">containerView</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                            
</span></span><span class="line"><span class="cl"><span class="n">UIView</span> <span class="o">*</span><span class="n">v1</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIView</span> <span class="n">new</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">v1</span><span class="p">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIColor</span> <span class="n">redColor</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">containerView</span> <span class="nl">addSubview</span><span class="p">:</span><span class="n">v1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                            
</span></span><span class="line"><span class="cl"><span class="n">UIView</span> <span class="o">*</span><span class="n">v2</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIView</span> <span class="n">new</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">v2</span><span class="p">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIColor</span> <span class="n">blueColor</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">containerView</span> <span class="nl">addSubview</span><span class="p">:</span><span class="n">v2</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">如上，我想让v1、v2纵向排列，让scrollView可以上下滚动。
</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">// scrollView正常进行约束
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">[</span><span class="n">scrollView</span> <span class="nl">mas_makeConstraints</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">MASConstraintMaker</span> <span class="o">*</span><span class="n">make</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">edges</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="nb">self</span><span class="p">.</span><span class="n">view</span><span 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="p">[</span><span class="n">containerView</span> <span class="nl">mas_makeConstraints</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">MASConstraintMaker</span> <span class="o">*</span><span class="n">make</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">edges</span><span class="p">.</span><span class="n">width</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="n">scrollView</span><span class="p">);</span> <span class="c1">// 试了发现这里好像必须要约束一下width
</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="c1">// v1、v2都放在容器里
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">[</span><span class="n">v1</span> <span class="nl">mas_makeConstraints</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">MASConstraintMaker</span> <span class="o">*</span><span class="n">make</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">top</span><span class="p">.</span><span class="n">left</span><span class="p">.</span><span class="n">right</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="n">containerView</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">height</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="mi">@400</span><span class="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="n">v2</span> <span class="nl">mas_makeConstraints</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">MASConstraintMaker</span> <span class="o">*</span><span class="n">make</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">top</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="n">v1</span><span class="p">.</span><span class="n">mas_bottom</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">left</span><span class="p">.</span><span class="n">right</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="n">v1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">height</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="mi">@400</span><span 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">// 这里需要补刀，来撑起contentSize
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">[</span><span class="n">containerView</span> <span class="nl">mas_makeConstraints</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">MASConstraintMaker</span> <span class="o">*</span><span class="n">make</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">make</span><span class="p">.</span><span class="n">bottom</span><span class="p">.</span><span class="n">equalTo</span><span class="p">(</span><span class="n">v2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}];</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>解决 CocoaPods 的类库 import 没有提示</title>
      <link>https://dvel.me/posts/solve-cocoapods-without-import/</link>
      <pubDate>Mon, 24 Apr 2017 20:43:53 +0800</pubDate>
      <guid>https://dvel.me/posts/solve-cocoapods-without-import/</guid>
      <description>添加 $(PODS_ROOT)/Headers/Public 以解决 CocoaPods 的类库 import 时没有提示的问题。</description>
      <content:encoded><![CDATA[<p>网上搜了一些，添加 <code>$(PODS_ROOT)</code> 到 <strong>User Header Search Paths</strong> 就行了。</p>
<p>但是提示中会多出一些不想要的东西。</p>
<p>改成这个就好了：</p>
<pre tabindex="0"><code>$(PODS_ROOT)/Headers/Public
</code></pre><p>图：</p>
<p>
<p>

    
    
        <img loading="lazy"
            src="/img/2017-04-24.webp"
            alt="Xcode"
            width="2558"
            height="1192"
            style="max-width: 100%; height: auto;"
        />
    
    

</p>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>iOS 使用 CocoaPods 的快速回顾</title>
      <link>https://dvel.me/posts/use-cocoapods-in-ios/</link>
      <pubDate>Mon, 17 Apr 2017 20:37:35 +0800</pubDate>
      <guid>https://dvel.me/posts/use-cocoapods-in-ios/</guid>
      <description>学习iOS使用CocoaPods进行第三方库管理：安装，更新与使用。包括最低版本支持iOS 8和更新框架的操作。</description>
      <content:encoded><![CDATA[<h2 id="安装">安装</h2>
<p>Mac 自带 Ruby 环境，查看：</p>
<pre tabindex="0"><code>$ gem -v
</code></pre><p>通过 surge 等工具实现终端科学上网，或更改 gem 源。</p>
<p>安装 &amp; 更新 Pod：</p>
<pre tabindex="0"><code>$ sudo gem install cocoapods
</code></pre><p>确认：</p>
<pre tabindex="0"><code>$ pod --version
</code></pre><h2 id="使用">使用</h2>
<p>进入工程根目录，创建 <code>Podfile</code> 文件。</p>
<p>写入：</p>
<pre tabindex="0"><code>platform :ios, &#39;8.0&#39;
target &#39;svnt&#39; do
pod &#39;AFNetworking&#39;, &#39;~&gt; 3.0&#39;
end
</code></pre><p>即最低支持 iOS 8，第三方框架 AFN 的版本为 3.0。</p>
<p><code>cd</code> 进 <code>Podfile</code> 所在目录，进行安装第三方库：</p>
<pre tabindex="0"><code>$ pod install
</code></pre><h2 id="后续使用">后续使用</h2>
<p>查询框架是否有新版本：</p>
<pre tabindex="0"><code>$ pod outdated
</code></pre><p>更新框架：</p>
<pre tabindex="0"><code>$ pod update
</code></pre><h2 id="参考--感谢">参考 &amp; 感谢</h2>
<ul>
<li><a href="http://www.jianshu.com/p/82d0ba43f8c3" target="_blank" rel="noopener">iOS开发 - CocoaPods安装和使用教程</a></li>
<li><a href="http://www.jianshu.com/p/689368568cf7" target="_blank" rel="noopener">CocoaPods相关问题总结</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>GitBook 简单生成本地静态 HTML 的方法</title>
      <link>https://dvel.me/posts/gitbook-generate-local-html/</link>
      <pubDate>Thu, 23 Feb 2017 20:47:55 +0800</pubDate>
      <guid>https://dvel.me/posts/gitbook-generate-local-html/</guid>
      <description>使用 Gitbook 生成本地静态 HTML 的方法，包括安装和常用命令。此外，还介绍了解决 Gitbook 生成的 website 左侧目录无法点击的问题的方法。</description>
      <content:encoded><![CDATA[<p>偶尔可能要写一些生成本地文件发给朋友看，所以。。。</p>
<h2 id="简单生成本地静态-html-的方法">简单生成本地静态 HTML 的方法</h2>
<ul>
<li>
<p>安装：<code>$ npm install gitbook-cli -g</code></p>
</li>
<li>
<p>生成：<code>$ gitbook build</code></p>
</li>
<li>
<p>结果：左侧目录无法点击。</p>
</li>
<li>
<p><code>$ gitbook serve</code> 可通过localhost访问，没有任何问题。</p>
</li>
</ul>
<p><strong>问题：</strong></p>
<p>自某版本后 <code>$ gitbook build</code> 生成的 website 不支持 local 打开了，具体哪个版本未实践。</p>
<p><strong>解决办法：</strong></p>
<pre tabindex="0"><code>$ gitbook build --gitbook=2.6.7
</code></pre><p>使用2.6.7版本，会自动安装并生成，左侧目录可点击，Firefox、Chrome暂无任何问题。</p>
<h2 id="常用命令">常用命令</h2>
<p><strong>帮助</strong></p>
<pre tabindex="0"><code>$ gitbook help
</code></pre><p><strong>更新</strong></p>
<pre tabindex="0"><code>$ gitbook update
</code></pre><p><strong>生成静态网页</strong></p>
<pre tabindex="0"><code>$ gitbook build
$ gitbook build --gitbook=2.6.7 // 生成对应版本的，本地无此版本会自动下载
</code></pre><p><strong>生成静态网页并运行到服务器</strong></p>
<pre tabindex="0"><code>$ gitbook serve
</code></pre><p><strong>列出远程所有可用版本</strong></p>
<pre tabindex="0"><code>$ gitbook ls-remote
</code></pre><p><strong>列出本地所有已安装版本</strong></p>
<pre tabindex="0"><code>$ gitbook ls
</code></pre><p><strong>卸载本地某版本</strong></p>
<pre tabindex="0"><code>$ gitbook uninstall x.x.x
</code></pre><h2 id="参考感谢">参考&amp;感谢</h2>
<p><a href="https://github.com/zhangjikai/gitbook-use" target="_blank" rel="noopener">hangjikai/gitbook-use</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>你好, Hexo！</title>
      <link>https://dvel.me/posts/hello-hexo/</link>
      <pubDate>Sun, 27 Nov 2016 00:20:02 +0800</pubDate>
      <guid>https://dvel.me/posts/hello-hexo/</guid>
      <description>使用 Hexo 搭建博客的方法，包括本地搭建和 VPS 端搭建两种方式，以及使用 Coding Pages 的方法。阐述了其中的坑点和遇到的问题，以及文章的结构和必填参数。</description>
      <content:encoded><![CDATA[<p>因为之前的 WordPress 博客域名被墙，加上 Hexo 正好满足于简单的书写要求，所以更换为 Hexo。</p>
<p>主要还是记录了自己的搭建过程，因为对 Linux 不太熟悉，以备忘为主。</p>
<p>后面换到了Coding Pages 上搭建，主要是简单方便省心，自带了 https，速度也凑合。</p>
<h2 id="方法一">方法一：</h2>
<h3 id="本地搭建">本地搭建</h3>
<h4 id="安装-nodejs">安装 node.js</h4>
<pre tabindex="0"><code>$ brew install node
</code></pre><h4 id="安装-hexo">安装 Hexo</h4>
<p>先cd进入创建好的hexo目录：</p>
<pre tabindex="0"><code>$ sudo npm install -g hexo-cli
$ hexo init
$ npm install
$ hexo d -fg
$ hexo serve
</code></pre><p>打开 <a href="http://localhost:4000" target="_blank" rel="noopener">http://localhost:4000</a> 如果看到 Hexo 的初始页面证明安装成功。</p>
<h4 id="ssh-秘钥">ssh 秘钥</h4>
<p>一路回车生成公钥和私钥：</p>
<pre tabindex="0"><code>$ ssh-keygen -t rsa -C &#34;email@example.com&#34;
</code></pre><p>之后在本地目录 <code>~/.ssh/</code> 下可以看到私钥 <code>id_rsa</code> 和公钥 <code>id_rsa.pub</code> 已经生成。</p>
<p>安装 <code>ssh-copy-id</code> 等会用，方便上传公钥。</p>
<pre tabindex="0"><code>$ brew install ssh-copy-id
</code></pre><h3 id="vps-端搭建">VPS 端搭建</h3>
<h4 id="更新与安装centos">更新与安装（centOS）</h4>
<pre tabindex="0"><code>$ yum update
$ yum install nginx -y
$ yum install git-core
</code></pre><h4 id="创建-git-用户及设置-ssh-免密码登陆">创建 git 用户及设置 ssh 免密码登陆</h4>
<pre tabindex="0"><code>$ adduser git
$ passwd git
$ chmod 740 /etc/sudoers
$ vim /etc/sudoers
(提示没有安装vim的可以用vi命令，或安装vim:)
$ yum -y install vim*
</code></pre><p>在编辑器中找到以下内容并添加一行：</p>
<pre tabindex="0"><code>## Allow root to run any commands anywhere
root    ALL=(ALL)     ALL
git     ALL=(ALL)     ALL (这行是添加的)
</code></pre><p>保存退出并执行：</p>
<pre tabindex="0"><code>$ chmod 440 /etc/sudoers
</code></pre><p>接下来切到本地的终端，上传公钥：</p>
<pre tabindex="0"><code>$ ssh-copy-id -i ~/.ssh/id_rsa.pub git@123.123.123.123
</code></pre><p>测试一下，如果 <code>$ ssh git@VPS的IP地址</code> ,能够免密码登录的话，则表示成功。</p>
<h4 id="回到-vps创建-git-仓库">回到 VPS，创建 git 仓库:</h4>
<pre tabindex="0"><code>$ su git
$ cd ~
$ mkdir hexo.git &amp;&amp; cd hexo.git
$ git init --bare
</code></pre><h4 id="创建网站目录并赋予-git-对网站目录的所有权">创建网站目录并赋予 git 对网站目录的所有权</h4>
<pre tabindex="0"><code>$ su root
$ cd /var/www
$ mkdir hexo
$ chown git:git -R /var/www/hexo
</code></pre><h4 id="配置-git-hooks">配置 git hooks</h4>
<pre tabindex="0"><code>$ su git
$ cd /home/git/hexo.git/hooks
$ vim post-receive
</code></pre><p>写入以下内容：</p>
<pre tabindex="0"><code>#!/bin/bash
GIT_REPO=/home/git/hexo.git #git仓库
TMP_GIT_CLONE=/tmp/hexo
PUBLIC_WWW=/var/www/hexo #网站目录
rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}
</code></pre><p>然后赋予脚本的执行权限</p>
<pre tabindex="0"><code>$ chmod +x post-receive
</code></pre><h4 id="配置-nginx">配置 Nginx</h4>
<p>启动 nginX:</p>
<pre tabindex="0"><code>systemctl status nginx.service      // 查看服务当前状态
systemctl start nginx.service       // 启动nginx服务
systemctl restart nginx.service     // 重新启动服务

systemctl enable nginx.service      // 设置开机自启动
systemctl disable nginx.service     // 停止开机自启动

systemctl list-units --type=service // 查看所有已启动的服务
</code></pre><p>然后：</p>
<pre tabindex="0"><code>$ vim /etc/nginx/conf.d/hexo.conf
</code></pre><p>插入如下代码：</p>
<pre tabindex="0"><code>server {
    listen         80 ;
    root /var/www/hexo;//这里可以改成你的网站目录地址，我将网站放在/var/www/hexo
    server_name example.com www.example.com;//这里输入你的域名或IP地址
    access_log  /var/log/nginx/hexo_access.log;
    error_log   /var/log/nginx/hexo_error.log;
    location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
            root /var/www/hexo;
            access_log   off;
            expires      1d;
    }
    location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
        root /var/www/hexo;
        access_log   off;
        expires      10m;
    }
    location / {
        root /var/www/hexo;//这里可以改成你的网站目录地址，我将网站放在/var/www/hexo
        if (-f $request_filename) {
            rewrite ^/(.*)$  /$1 break;
        }
    }
}
</code></pre><p>然后重启nginx，此时刷新网页应该显示的是403。</p>
<h3 id="本机的最后配置">本机的最后配置</h3>
<p>位于 <code>hexo</code> 文件夹下，<code>_config.yml </code>,修改 <code>deploy</code> 选项，例如：</p>
<pre tabindex="0"><code>deploy:
  type: git
  message: update  # 这个可以不写，会默认生成update日期
  repo: git@123.123.123.123:hexo.git,master # 逗号后面写分支
</code></pre><p>部署到多个仓库可以这么写：</p>
<pre tabindex="0"><code>deploy: 
  - type: git
    repo: git@git.coding.net:Dvel/Dvel.git,master
  - type: git
    repo: git@github.com:iDvel/Dvel-Hexo.git,master
</code></pre><p>每次更新博客也可以让github上长点绿草了。。。</p>
<p>接下来安装 <strong>hexo-deployer-git</strong> ，否则部署时会报这个错&quot;<em>ERROR Deployer not found: git</em>&quot;。</p>
<pre tabindex="0"><code>$ npm install hexo-deployer-git --save
</code></pre><p>接着<code>$ hexo g &amp;&amp; hexo d</code>，如果一切正常，静态文件已经被成功的push到了blog的仓库里。</p>
<p>期间我忘了还出了个什么错，删除<code>hexo</code>目录下的<code>.deploy_git</code>后再次<code>hexo g &amp;&amp; hexo d</code>就可以了。</p>
<p>以上，博客已经完全建好了。</p>
<p><code>$ hexo generate</code>是生成静态文件。</p>
<p><code>$ hexo deploy</code>是部署，我们这里选择了Git，Hexo还支持其他部署形式。</p>
<p>所以每次写完文章，执行这两个命令后，就对网站完成了更新。</p>
<p>简化操作就是：<code>$ hexo g &amp;&amp; hexo d</code> ，再简化就是<code>$ hexo d -g</code>，效果一样。</p>
<h2 id="方法二利用一键安装包">方法二，利用一键安装包</h2>
<p>因为不太熟悉 Linux，所以我选择了一键安装包，多站点管理方便些。</p>
<p>我用的这个 -&gt; <a href="https://oneinstack.com/" target="_blank" rel="noopener">OneinStack官网</a></p>
<p>步骤和上面差不多，但是很多路径要改一下，也可以很简单的搭建出Hexo。</p>
<h2 id="方法三coding-pages">方法三，Coding Pages</h2>
<ol>
<li>
<p>coding 中创建项目</p>
</li>
<li>
<p>站点配置文件<code>_config.yml</code> 中 <code>deploy</code> 中写好 coding 项目的 git 地址</p>
</li>
<li>
<p>push 上去：<code>$ hexo d -g</code></p>
</li>
<li>
<p>在 coding 上你的项目，开启 Pages 服务：可以自定义分支，绑定域名，开启 https</p>
</li>
<li>
<p>大功告成</p>
</li>
</ol>
<p>这个相对简单一些，Coding Pages 服务目前提供 100M 空间的支持，一般来说没有写文章的话，生成的 <code>public</code> 文件夹大约小于5M。</p>
<p>100M 基本够写很多年的博客，至于图片应该另寻图床，不要放到 coding 上，否则空间很快用完。</p>
<h2 id="编写文章更新博客">编写文章、更新博客</h2>
<p>使用一款 MarkDown 编辑器写文章 ，写完后将文件以 *.md 的格式保存在本地 <code>[网站目录]\source_posts</code> 中。</p>
<p>Markdown 编辑器，强烈安利 Typora。</p>
<p>每篇 Blog 都有固定的参数必须填写，参数如下，注意每个参数的 : 后都有一个空格。</p>
<pre tabindex="0"><code>title: title
date: yyyy-mm-dd
categories: category  
tags: tag
#多标签请这样写：  
#tags: [tag1,tag2,tag3]
#或者这样写： 
#tags:
#- tag1 
#- tag2  
#- tag3  
---  
正文  
</code></pre><p>或者使用 <code>$ hexo new</code> 命令，具体官网有详细说明。</p>
<p>编写完后，只需要在hexo文件夹下执行 <code>hexo g &amp;&amp; hexo d</code>，博客即可更新。</p>
<h2 id="遇到的坑">遇到的坑</h2>
<p>设置了 ssh 免密码登陆后，依然需要密码</p>
<pre tabindex="0"><code>这整段是以前使用的方法，过时了。。。
设置ssh免密码登陆：
su git
cd ~
mkdir .ssh &amp;&amp; cd .ssh
touch authorized_keys
vim authorized_keys  //在这个文件中粘贴进刚刚申请的key（在id_rsa.pub文件中）
设置权限：
chmod o-w ~/
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

测试免密码登陆
ssh -vvT git@123.123.123.123   // 你的VPS的IP地址
发现依然需要密码，搜了好几天没找到解决办法，后来采用了ssh-copy-id，解决了这个问题。
</code></pre><p>如果过程中重新初始化过 VPS 的磁盘，ssh 连接 VPS 的时候可能会提示 <code>Host key verification failed.</code> 。</p>
<p>运行此命令即可：<code>$ ssh-keygen -R 123.123.123.123</code>，将 123.123.123.123 改成你的 VPS 的 IP。</p>
<p>或者简单粗暴直接删除 <code>known_hosts</code> 文件。</p>
]]></content:encoded>
    </item>
    <item>
      <title>About</title>
      <link>https://dvel.me/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://dvel.me/about/</guid>
      <description>&lt;p&gt;Hi 👋&lt;/p&gt;
&lt;p&gt;欢迎来到我的博客。&lt;/p&gt;
&lt;h2 id=&#34;朋友们&#34;&gt;朋友们&lt;/h2&gt;
&lt;a target=&#34;_blank&#34; href=https://www.sulvblog.cn title=Sulv&amp;#39;s&amp;#32;Blog class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://dvel.me/friends/sulvblog.cn.gif /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;Sulv&amp;#39;s Blog&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;一个记录技术、阅读、生活的博客&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;a target=&#34;_blank&#34; href=https://wangyunzi.com title=长街短梦 class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://blog.wangyunzi.com/avatar.png /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;长街短梦&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;此行山高路远，我只剩口袋玫瑰一片&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;a target=&#34;_blank&#34; href=https://liudon.com title=流动 class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://liudon.com/avatar.png /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;流动&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;生活就是一个流动的过程&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;a target=&#34;_blank&#34; href=https://bugcoder.asia/ title=写bug的代码人 class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://bugcoder.asia/headLogo.jpg /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;写bug的代码人&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;没有比这再简陋的网站了&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;a target=&#34;_blank&#34; href=https://idzc.top title=IGNORANT class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://idzc.top/avatar.png /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;IGNORANT&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;笔记乱写、代码乱敲的调参侠&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;a target=&#34;_blank&#34; href=https://www.mintimate.cn title=Mintimate’s&amp;#32;Blog class=&#34;friendurl&#34;&gt;
  &lt;div class=&#34;frienddiv&#34;&gt;
    &lt;div class=&#34;frienddivleft&#34;&gt;
      &lt;img class=&#34;myfriend&#34; src=https://mintimate.cn/custom/img/favicon/favicon.png /&gt;
    &lt;/div&gt;
    &lt;div class=&#34;frienddivright&#34;&gt;
      &lt;div class=&#34;friendname&#34;&gt;Mintimate’s Blog&lt;/div&gt;
      &lt;div class=&#34;friendinfo&#34;&gt;专注与你分享技术教程～&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;div class=&#34;footer-img-link&#34;&gt;
    &lt;a href=&#34;https://www.travellings.cn/go.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; title=&#34;开往-友链接力&#34;&gt;
        &lt;img
            src=&#34;https://dvel.me/img/travelling.gif&#34;
            width=&#34;120&#34;
            alt=&#34;开往-友链接力&#34;
            title=&#34;开往-友链接力&#34;
            style=&#34;display: inline; vertical-align: middle;&#34;
        /&gt;
    &lt;/a&gt;
    &lt;a href=&#34;https://www.foreverblog.cn/go.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; title=&#34;穿梭虫洞-随机访问十年之约友链博客&#34;&gt;
        &lt;img
            src=&#34;https://dvel.me/img/wormhole.gif&#34;
            width=&#34;120&#34;
            alt=&#34;穿梭虫洞-随机访问十年之约友链博客&#34;
            title=&#34;穿梭虫洞-随机访问十年之约友链博客&#34;
            style=&#34;display: inline; vertical-align: middle;&#34;
        /&gt;
    &lt;/a&gt;
&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>Hi 👋</p>
<p>欢迎来到我的博客。</p>
<h2 id="朋友们">朋友们</h2>
<a target="_blank" href=https://www.sulvblog.cn title=Sulv&#39;s&#32;Blog class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://dvel.me/friends/sulvblog.cn.gif />
    </div>
    <div class="frienddivright">
      <div class="friendname">Sulv&#39;s Blog</div>
      <div class="friendinfo">一个记录技术、阅读、生活的博客</div>
    </div>
  </div>
</a>
<a target="_blank" href=https://wangyunzi.com title=长街短梦 class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://blog.wangyunzi.com/avatar.png />
    </div>
    <div class="frienddivright">
      <div class="friendname">长街短梦</div>
      <div class="friendinfo">此行山高路远，我只剩口袋玫瑰一片</div>
    </div>
  </div>
</a>
<a target="_blank" href=https://liudon.com title=流动 class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://liudon.com/avatar.png />
    </div>
    <div class="frienddivright">
      <div class="friendname">流动</div>
      <div class="friendinfo">生活就是一个流动的过程</div>
    </div>
  </div>
</a>
<a target="_blank" href=https://bugcoder.asia/ title=写bug的代码人 class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://bugcoder.asia/headLogo.jpg />
    </div>
    <div class="frienddivright">
      <div class="friendname">写bug的代码人</div>
      <div class="friendinfo">没有比这再简陋的网站了</div>
    </div>
  </div>
</a>
<a target="_blank" href=https://idzc.top title=IGNORANT class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://idzc.top/avatar.png />
    </div>
    <div class="frienddivright">
      <div class="friendname">IGNORANT</div>
      <div class="friendinfo">笔记乱写、代码乱敲的调参侠</div>
    </div>
  </div>
</a>
<a target="_blank" href=https://www.mintimate.cn title=Mintimate’s&#32;Blog class="friendurl">
  <div class="frienddiv">
    <div class="frienddivleft">
      <img class="myfriend" src=https://mintimate.cn/custom/img/favicon/favicon.png />
    </div>
    <div class="frienddivright">
      <div class="friendname">Mintimate’s Blog</div>
      <div class="friendinfo">专注与你分享技术教程～</div>
    </div>
  </div>
</a>
<hr>
<div class="footer-img-link">
    <a href="https://www.travellings.cn/go.html" target="_blank" rel="noopener" title="开往-友链接力">
        <img
            src="/img/travelling.gif"
            width="120"
            alt="开往-友链接力"
            title="开往-友链接力"
            style="display: inline; vertical-align: middle;"
        />
    </a>
    <a href="https://www.foreverblog.cn/go.html" target="_blank" rel="noopener" title="穿梭虫洞-随机访问十年之约友链博客">
        <img
            src="/img/wormhole.gif"
            width="120"
            alt="穿梭虫洞-随机访问十年之约友链博客"
            title="穿梭虫洞-随机访问十年之约友链博客"
            style="display: inline; vertical-align: middle;"
        />
    </a>
</div>
]]></content:encoded>
    </item>
  </channel>
</rss>
