<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh_CN">
  <id>https://silverrainz.me/</id>
  <title>银色子弹</title>
  <updated>2026-03-11T19:02:50.004804+00:00</updated>
  <link href="https://silverrainz.me/"/>
  <link href="https://silverrainz.me/blog/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.10.13.dev247+g7d0a76540">ABlog</generator>
  <subtitle>Yes silver bullet here.</subtitle>
  <entry>
    <id>https://silverrainz.me/blog/2025-10-sphinxnotes-incrbuild.html</id>
    <title>sphinxnotes-incrbuild: Enabling Sphinx incremental builds in CI/CD environment</title>
    <updated>2025-10-15T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="sphinxnotes-incrbuild-enabling-sphinx-incremental-builds-in-ci-cd-environment"&gt;

&lt;p&gt;As we know, Sphinx supports incremental HTML build, and it works well locally. But for CI/CD, the environment is usually brand new, which causes Sphinx always to rebuild everything. The project wraps &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx-build&lt;/span&gt;&lt;/code&gt; and ensures the environment is &amp;quot;incremental build&amp;quot;-able before running the real &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx-build&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2025-10-sphinxnotes-incrbuild.html"/>
    <summary>As we know, Sphinx supports incremental HTML build, and it works well locally. But for CI/CD, the environment is usually brand new, which causes Sphinx always to rebuild everything. The project wraps sphinx-build and ensures the environment is "incremental build"-able before running the real sphinx-build.</summary>
    <category term="CI" label="CI"/>
    <category term="Sphinx" label="Sphinx"/>
    <published>2025-10-15T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2025-09-chezetc.html</id>
    <title>chezetc: Extending chezmoi to manage files under /etc</title>
    <updated>2025-09-22T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="chezetc-extending-chezmoi-to-manage-files-under-etc"&gt;

&lt;p&gt;If you are Chzemoi user and want to use Chzemoi to manage files outside &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$HOME&lt;/span&gt;&lt;/code&gt;. This script is for you :D&lt;/p&gt;
&lt;p&gt;Chezetc enhances chezmoi, transforming it from a &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$HOME&lt;/span&gt;&lt;/code&gt; manager into a tool that can seamlessly:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Manage files in /etc and other directories owned by root.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manage multiple chezmoi repositories without manually specifying &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--config&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;PATH&amp;gt;&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2025-09-chezetc.html"/>
    <summary>If you are Chzemoi user and want to use Chzemoi to manage files outside $HOME. This script is for you :D</summary>
    <category term="Chezmoi" label="Chezmoi"/>
    <category term="DevOps" label="DevOps"/>
    <category term="Shell" label="Shell"/>
    <published>2025-09-22T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2025-09-systemd-fzf-aliases.html</id>
    <title>A set of smooth, fzf-powered shell aliases&amp;functions for systemctl</title>
    <updated>2025-09-12T00:00:00+00:00</updated>
    <author>
      <name>AI</name>
    </author>
    <content type="html">&lt;section id="a-set-of-smooth-fzf-powered-shell-aliases-functions-for-systemctl"&gt;

&lt;p&gt;If you've ever found yourself repeatedly typing long systemctl commands or struggling to remember exact service names, this post is for you.&lt;/p&gt;
&lt;p&gt;A while ago I implemented a set of shell aliases and functions, and now I can manage my systemd services very smoothly:&lt;/p&gt;
&lt;div id="asciicast-/_assets/systemd.v2.cast"&gt;&lt;/div&gt;
            &lt;script&gt;
                document.addEventListener("DOMContentLoaded", function() {
                    AsciinemaPlayer.create(
                        "data:text/plain;base64,eyJ2ZXJzaW9uIjoyLCJ3aWR0aCI6ODAsImhlaWdodCI6MjAsInRpbWVzdGFtcCI6MTc1NzY4OTI5NiwiZW52Ijp7IlNIRUxMIjoiL3Vzci9iaW4venNoIn0sInRoZW1lIjp7ImZnIjoiI2Q4ZGVlOSIsImJnIjoiIzJlMzQ0MCIsInBhbGV0dGUiOiIjM2I0MjUyOiNiZjYxNmE6I2EzYmU4YzojZWJjYjhiOiM4MWExYzE6I2I0OGVhZDojODhjMGQwOiNlNWU5ZjA6IzRjNTY2YTojYmY2MTZhOiNhM2JlOGM6I2ViY2I4YjojODFhMWMxOiNiNDhlYWQ6IzhmYmNiYjojZWNlZmY0In19ClswLjE2ODQ1NSwgIm8iLCAiXHUwMDFiWzFtXHUwMDFiWzdtJVx1MDAxYlsyN21cdTAwMWJbMW1cdTAwMWJbMG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHIgXHIiXQpbMC4xODA1ODMsICJvIiwgIlxyXHUwMDFiWzBtXHUwMDFiWzI3bVx1MDAxYlsyNG1cdTAwMWJbSlx1MDAxYlszMm0vXHUwMDFiWzM5bSBcdTAwMWJbMW1cdTAwMWJbMzZtbGFcdTAwMWJbMzltIFx1MDAxYlszN21AXHUwMDFiWzM5bSBcdTAwMWJbMzVteDFjXHUwMDFiWzM5bSBcdTAwMWJbMzBtMjM6MDFcdTAwMWJbMzltIFx1MDAxYlszN20tPlx1MDAxYlszOW0gXHUwMDFiWzMybX5cdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlswbVxyXG5cdTAwMWJbMzJtXFxcdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNG0kIFx1MDAxYlszN21cdTAwMWJbMG1cdTAwMWJbMzdtXHUwMDFiW0tcdTAwMWJbPzIwMDRoIl0KWzEuNzUzMTA1LCAibyIsICJ0Il0KWzEuNzU2OTE2LCAibyIsICJcYlx1MDAxYlszMm10XHUwMDFiWzM5bSJdClsxLjc1NzMzMywgIm8iLCAiXGJcdTAwMWJbMzJtdFx1MDAxYlszOW1cdTAwMWJbOTBtaW1lIHN5c3RlbWN0bCBsaXN0LXVuaXQtZmlsZXMgLS1zdGF0ZT1kaXNhYmxlZCAtLXF1aWV0IC0tbm8tcGFnZXIgPi9kZXYvbnVsXHUwMDFiWzkwbWxcdTAwMWJbMzltXHUwMDFiW0tcdTAwMWJbQVx1MDAxYls0QyJdClsxLjg5NzA2OCwgIm8iLCAiXGJcdTAwMWJbMzJtdFx1MDAxYlszMm15XHUwMDFiWzM5bVx1MDAxYltLXHUwMDFiWzFCXHJcdTAwMWJbS1x1MDAxYltBXHUwMDFiWzZDIl0KWzEuODk4NDI1LCAibyIsICJcYlxiXHUwMDFiWzFtXHUwMDFiWzMxbXRcdTAwMWJbMW1cdTAwMWJbMzFteVx1MDAxYlswbVx1MDAxYlszOW0iXQpbMi4wNDIxNjgsICJvIiwgIlxiXGJcdTAwMWJbMW1cdTAwMWJbMzFtdFx1MDAxYlsxbVx1MDAxYlszMW15XHUwMDFiWzFtXHUwMDFiWzMxbXBcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzIuMTkwMTI2LCAibyIsICJcYlx1MDAxYlsxbVx1MDAxYlszMW1wXHUwMDFiWzFtXHUwMDFiWzMxbWVcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzIuMTkyNTE4LCAibyIsICJcYlxiXGJcYlx1MDAxYlswbVx1MDAxYlszMm10XHUwMDFiWzBtXHUwMDFiWzMybXlcdTAwMWJbMG1cdTAwMWJbMzJtcFx1MDAxYlswbVx1MDAxYlszMm1lXHUwMDFiWzM5bSJdClsyLjMxMDIwNCwgIm8iLCAiXGJcdTAwMWJbMzJtZVx1MDAxYlszMm0gXHUwMDFiWzM5bSJdClsyLjMxMDk4MiwgIm8iLCAiXGJcYlx1MDAxYlszMm1lXHUwMDFiWzM5bVx1MDAxYlszOW0gIl0KWzIuODk3Mzc1LCAibyIsICJcIiJdClsyLjg5ODU3NSwgIm8iLCAiXGJcdTAwMWJbMzNtXCJcdTAwMWJbMzltIl0KWzMuMTI4NjUsICJvIiwgIlxiXHUwMDFiWzMzbVwiXHUwMDFiWzMzbXNcdTAwMWJbMzltIl0KWzMuMjgzNTg0LCAibyIsICJcYlx1MDAxYlszM21zXHUwMDFiWzMzbXNcdTAwMWJbMzltIl0KWzMuNTYyNTkyLCAibyIsICJcYlx1MDAxYlszM21zXHUwMDFiWzMzbXRcdTAwMWJbMzltIl0KWzMuNzEwNTA2LCAibyIsICJcYlx1MDAxYlszM210XHUwMDFiWzMzbWFcdTAwMWJbMzltIl0KWzMuNzk4MDI2LCAibyIsICJcYlx1MDAxYlszM21hXHUwMDFiWzMzbXJcdTAwMWJbMzltIl0KWzMuOTU0MzM2LCAibyIsICJcYlx1MDAxYlszM21yXHUwMDFiWzMzbXRcdTAwMWJbMzltIl0KWzQuMzIzNzk2LCAibyIsICJcYlx1MDAxYlszM210XHUwMDFiWzMzbVwiXHUwMDFiWzM5bSJdCls0LjU1NDM2OCwgIm8iLCAiXGJcdTAwMWJbMzNtXCJcdTAwMWJbMzNtIFx1MDAxYlszOW0iXQpbNC41NTU1MjUsICJvIiwgIlxiXGJcdTAwMWJbMzNtXCJcdTAwMWJbMzltXHUwMDFiWzM5bSAiXQpbNS4wMjI3MDIsICJvIiwgInQiXQpbNS4xMTA3OTUsICJvIiwgIm8iXQpbNS4yMDM3MTQsICJvIiwgIiAiXQpbNS4zMTA1MTksICJvIiwgInMiXQpbNS4zMTMxODMsICJvIiwgIlxiXHUwMDFiWzRtc1x1MDAxYlsyNG0iXQpbNS43NTUxMjIsICJvIiwgIlxiXHUwMDFiWzRtc1x1MDAxYls0bXRcdTAwMWJbMjRtIl0KWzUuNzYwMDA1LCAibyIsICJcYlxiXHUwMDFiWzI0bXNcdTAwMWJbMjRtdCJdCls1Ljk3NTE0OCwgIm8iLCAiYSJdCls2LjAzOTg5NCwgIm8iLCAiciJdCls2LjE5OTYyMiwgIm8iLCAidCJdCls2LjM2MTI3NCwgIm8iLCAiICJdCls2Ljk1NzU0MiwgIm8iLCAiYSJdCls2Ljk1OTYxOSwgIm8iLCAiXGJcdTAwMWJbNG1hXHUwMDFiWzI0bSJdCls3LjA0NzUxMywgIm8iLCAiXGJcdTAwMWJbNG1hXHUwMDFiWzRtIFx1MDAxYlsyNG0iXQpbNy4wNDk0MDQsICJvIiwgIlxiXGJcdTAwMWJbMjRtYVx1MDAxYlsyNG0gIl0KWzcuMjE0NjAzLCAibyIsICJzIl0KWzcuMjE2ODM3LCAibyIsICJcYlx1MDAxYls0bXNcdTAwMWJbMjRtIl0KWzcuMzQ4NDIxLCAibyIsICJcYlx1MDAxYls0bXNcdTAwMWJbNG15XHUwMDFiWzI0bSJdCls3LjM5MzY4NCwgIm8iLCAiXGJcdTAwMWJbNG15XHUwMDFiWzRtc1x1MDAxYlsyNG0iXQpbNy42NTYxMDcsICJvIiwgIlxiXHUwMDFiWzRtc1x1MDAxYls0bXRcdTAwMWJbMjRtIl0KWzcuNjkzMTAxLCAibyIsICJcYlx1MDAxYls0bXRcdTAwMWJbNG1lXHUwMDFiWzI0bSJdCls3LjgzMjk2LCAibyIsICJcYlx1MDAxYls0bWVcdTAwMWJbNG1tXHUwMDFiWzI0bSJdCls3LjkwMzY2NywgIm8iLCAiXGJcdTAwMWJbNG1tXHUwMDFiWzRtZFx1MDAxYlsyNG0iXQpbOC4xMTEzMzMsICJvIiwgIlxiXHUwMDFiWzRtZFx1MDAxYls0bSBcdTAwMWJbMjRtIl0KWzguMTE4NjQzLCAibyIsICJcdTAwMWJbOERcdTAwMWJbMjRtc1x1MDAxYlsyNG15XHUwMDFiWzI0bXNcdTAwMWJbMjRtdFx1MDAxYlsyNG1lXHUwMDFiWzI0bW1cdTAwMWJbMjRtZFx1MDAxYlsyNG0gIl0KWzguNDA2MjM0LCAibyIsICJzIl0KWzguNDA4Njg3LCAibyIsICJcYlx1MDAxYls0bXNcdTAwMWJbMjRtIl0KWzguNDg1Mjc0LCAibyIsICJcYlx1MDAxYls0bXNcdTAwMWJbNG1lXHUwMDFiWzI0bSJdCls4LjQ4Nzg3MywgIm8iLCAiXGJcYlx1MDAxYlsyNG1zXHUwMDFiWzI0bWUiXQpbOC41NTUxNzgsICJvIiwgInIiXQpbOC43NDk5MDIsICJvIiwgInYiXQpbOC44NDkzMjYsICJvIiwgImkiXQpbOC45MTk5ODEsICJvIiwgImMiXQpbOC45NTY0OTcsICJvIiwgImUiXQpbOS4wNjk4NzgsICJvIiwgIiAiXQpbOS40NzM2MzIsICJvIiwgImEiXQpbOS40NzYyNjYsICJvIiwgIlxiXHUwMDFiWzRtYVx1MDAxYlsyNG0iXQpbOS41Njk4MjUsICJvIiwgIlxiXHUwMDFiWzRtYVx1MDAxYls0bW5cdTAwMWJbMjRtIl0KWzkuNTcyNDE3LCAibyIsICJcYlxiXHUwMDFiWzI0bWFcdTAwMWJbMjRtbiJdCls5LjYzMDYxNSwgIm8iLCAiZCJdCls5LjcxMTMxNSwgIm8iLCAiICJdCls5Ljg2Mjk0NywgIm8iLCAicyJdCls5Ljg2NTg3MywgIm8iLCAiXGJcdTAwMWJbNG1zXHUwMDFiWzI0bSJdCls5LjkyODI4OSwgIm8iLCAiXGJcdTAwMWJbNG1zXHUwMDFiWzRtaFx1MDAxYlsyNG0iXQpbOS45MzQyMTUsICJvIiwgIlxiXGJcdTAwMWJbMjRtc1x1MDAxYlsyNG1oIl0KWzkuOTk5NzEzLCAibyIsICJvIl0KWzEwLjMyNTQ2NSwgIm8iLCAidyJdClsxMC40ODQ2NjcsICJvIiwgIiAiXQpbMTAuNzEzMTg4LCAibyIsICJpIl0KWzEwLjgyOTEzMiwgIm8iLCAidCJdClsxMC44NzM3MjEsICJvIiwgInMiXQpbMTEuMDAyNjQzLCAibyIsICIgIl0KWzExLjQzMDUwOSwgIm8iLCAicyJdClsxMS40MzM4NzgsICJvIiwgIlxiXHUwMDFiWzRtc1x1MDAxYlsyNG0iXQpbMTEuNjQzMjM4LCAibyIsICJcYlx1MDAxYls0bXNcdTAwMWJbNG10XHUwMDFiWzI0bSJdClsxMS42NDY0NDgsICJvIiwgIlxiXGJcdTAwMWJbMjRtc1x1MDAxYlsyNG10Il0KWzExLjcyMzM0MiwgIm8iLCAiYSJdClsxMS43OTIwNDYsICJvIiwgInQiXQpbMTEuOTcyNTMzLCAibyIsICJ1Il0KWzEyLjAxNjMxOCwgIm8iLCAicyJdClsxMy4yNzEzNzIsICJvIiwgIlx1MDAxYls/MjAwNGxcdTAwMWJbMUJcciJdClsxMy4yNzE1MzcsICJvIiwgIlx1MDAxYlsxbVx1MDAxYls3bSVcdTAwMWJbMjdtXHUwMDFiWzFtXHUwMDFiWzBtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyIFxyIl0KWzEzLjI4MTQzNywgIm8iLCAiXHJcdTAwMWJbMG1cdTAwMWJbMjdtXHUwMDFiWzI0bVx1MDAxYltKXHUwMDFiWzMybS9cdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNm1sYVx1MDAxYlszOW0gXHUwMDFiWzM3bUBcdTAwMWJbMzltIFx1MDAxYlszNW14MWNcdTAwMWJbMzltIFx1MDAxYlszMG0yMzowMVx1MDAxYlszOW0gXHUwMDFiWzM3bS0+XHUwMDFiWzMxbVsxMzBdXHUwMDFiWzM5bSBcdTAwMWJbMzJtflx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzBtXHJcblx1MDAxYlszMm1cXFx1MDAxYlszOW0gXHUwMDFiWzFtXHUwMDFiWzM0bSQgXHUwMDFiWzM3bVx1MDAxYlswbVx1MDAxYlszN21cdTAwMWJbS1x1MDAxYls/MjAwNGgiXQpbMTMuODAxNjIzLCAibyIsICJzIl0KWzEzLjgwMjcxMiwgIm8iLCAiXGJcdTAwMWJbMzJtc1x1MDAxYlszOW0iXQpbMTMuODAyNzk5LCAibyIsICJcYlx1MDAxYlszMm1zXHUwMDFiWzM5bVx1MDAxYls5MG0gc3RhcnQgZG9ja2VyLnNlcnZpY2UgJiYgcyBzdGF0dXMgJF8gfHwgc2ogLXhldSAkX1x1MDAxYlszOW1cdTAwMWJbNTBEIl0KWzEzLjkzMzQ2NCwgIm8iLCAiXGJcdTAwMWJbMzJtc1x1MDAxYlszMm1zXHUwMDFiWzM5bVx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzQ5RCJdClsxMy45MzY2NDIsICJvIiwgIlx1MDAxYls5MG10YXJ0XHUwMDFiWzM5bVxiXGJcYlxiIl0KWzE0LjMxNzkzNCwgIm8iLCAiXGJcYlx1MDAxYlszMm1zXHUwMDFiWzMybXNcdTAwMWJbMzJtdFx1MDAxYlszOW0iXQpbMTQuMzE5NDk3LCAibyIsICJcYlxiXGJcdTAwMWJbMW1cdTAwMWJbMzFtc1x1MDAxYlsxbVx1MDAxYlszMW1zXHUwMDFiWzFtXHUwMDFiWzMxbXRcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzE0LjQ1NjMwNywgIm8iLCAiXGJcdTAwMWJbMW1cdTAwMWJbMzFtdFx1MDAxYlsxbVx1MDAxYlszMW1hXHUwMDFiWzBtXHUwMDFiWzM5bSJdClsxNC41MjgwOTUsICJvIiwgIlxiXHUwMDFiWzFtXHUwMDFiWzMxbWFcdTAwMWJbMW1cdTAwMWJbMzFtclx1MDAxYlswbVx1MDAxYlszOW0iXQpbMTQuNjk2MjA4LCAibyIsICJcYlx1MDAxYlsxbVx1MDAxYlszMW1yXHUwMDFiWzFtXHUwMDFiWzMxbXRcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzE0LjY5ODMzMywgIm8iLCAiXGJcYlxiXGJcYlxiXHUwMDFiWzBtXHUwMDFiWzMybXNcdTAwMWJbMG1cdTAwMWJbMzJtc1x1MDAxYlswbVx1MDAxYlszMm10XHUwMDFiWzBtXHUwMDFiWzMybWFcdTAwMWJbMG1cdTAwMWJbMzJtclx1MDAxYlswbVx1MDAxYlszMm10XHUwMDFiWzM5bSJdClsxNS4xNDU5MTgsICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQpbMTUuMTUwNjE1LCAibyIsICJcdTAwMWJbPzEwNDloIl0KWzE1LjE3MTcwMiwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWz8xMDAwaFx1MDAxYls/MTAwMmhcdTAwMWJbPzEwMDZoXHUwMDFiWz8yMDA0aFx1MDAxYlsxOUFcdTAwMWJbR1x1MDAxYltLXHUwMDFiWzEwQlxyXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pWt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pWuXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OENcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OENcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKVsOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKVr1x1MDAxYlswbVx1MDAxYls4QVxyXHUwMDFiWzJDXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzdBXHJcdTAwMWJbMkNcdTAwMWJbMTFBXHJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYlsxQlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMUJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYlsxQlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMUJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYlsxQlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMUJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzlBXHJcdTAwMWJbOUJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzsxOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybT5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4qC5XHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0wLzBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAIl0KWzE1LjE3MTcwOSwgIm8iLCAi4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE1LjI1MTE2NiwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzFBXHJcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybeKguFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMC8wXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTUuMzUxODE2LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMUFcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4qC8XHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0wLzBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNS40NTIxMzEsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYlsxQVxyXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm3ioLRcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTAvMFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE1LjU1MjI5OSwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzFBXHJcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybeKgplx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMC8wXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTUuNTUyNDUxLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMkFcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgXHUwMDFiWzBtXHUwMDFiWzszODsyOzE2MzsxOTA7MTM5OzQ4OzI7NTk7NjY7ODJtVU5JVC9GSUxFICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExPQUQvU1RBVEUgIEFDVElWRS9QUkVTRVQgIFNVwrfCt1x1MDAxYlswbVx1MDAxYlsyQlxyXHUwMDFiWzJDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE1LjU2MjU5OCwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzFBXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMC80NjZcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNS41NjMwNjIsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYlszQVxyXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm3iloxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1nZXR0eUBmb28uc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZGVkICAgICAgZmFpbGVkICAgICAgICAgZmHCt8K3XHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXByb2Mtc3lzLWZzLWJpbmZtdF9taXNjLmF1dG9tb3VudCAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZGV2LWh1Z2VwYWdlcy5tb3VudCAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpYyAgICAgIC0gICAgICAgICAgICAgICAgwrfCt1x1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1kZXYtbXF1ZXVlLm1vdW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXByb2Mtc3lzLWZzLWJpbmZtdF9taXNjLm1vdW50ICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc3lzLWZzLWZ1c2UtY29ubmVjdGlvbnMubW91bnQgICAgICAgICAgICAgICAgIHN0YXRpYyAgICAgIC0gICAgICAgICAgICAgICAgwrfCt1x1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXMta2VybmVsLWNvbmZpZy5tb3VudCAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOEJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm00NjYvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTUuNTcxNTcxLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMkJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDXHUwMDFiWzsxOzMxOzQ4OzI7NTk7NjY7ODJtw5dcdTAwMWJbMG1cclx1MDAxYlszQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBnZXR0eUBmb28uc2VydmljZSAtIEdldHR5IG9uIGZvb1x1MDAxYlswbVxyXHUwMDFiWzM2Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYlszNkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMzZDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzFBXHJcdTAwMWJbNzRDXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzc7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTEvMTRcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtICAgICBMb2FkZWQ6IGxvYWRlZCAoXHUwMDFiWzBtXHUwMDFiXTg7O2ZpbGU6Ly94MWMvdXNyL2xpYi9zeXN0ZW1kL3N5c3RlbS9nZXR0eUAuc2VydmljZVx1MDAxYlxcXHJcdTAwMWJbMjNDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtL3Vzci9saWIvc3lzdGVtZC9zeXN0ZW0vZ2V0dHlALnNlcnZpY2VcdTAwMWJbMG1cdTAwMWJdODs7XHUwMDFiXFxcclx1MDAxYls2MUNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm07IFx1MDAxYlswbVxyXHUwMDFiWzYzQ1x1MDAxYls7MTszODs1OzE4NTs0ODsyOzU5OzY2OzgybWRpc2FibGVkXHUwMDFiWzBtXHJcdTAwMWJbNzFDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtOyBwcmVzZVx1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgIEFjdGl2ZTogXHUwMDFiWzBtXHJcdTAwMWJbMTVDXHUwMDFiWzsxOzMxOzQ4OzI7NTk7NjY7ODJtZmFpbGVkXHUwMDFiWzBtXHJcdTAwMWJbMjFDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIChSZXN1bHQ6IHN0YXJ0LWxpbWl0LWhpdCkgc2luY2UgRnJpIDIwMjUtMDktMTIgMjA6NDc6MzkgXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgIER1cmF0aW9uOiAybXNcdTAwMWJbMG1cclx1MDAxYlsxOENcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMThDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzE4Q1x1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIEludm9jYXRpb246IDEyNjA0YzAzNjJlNTQ3YzNhNGFmMTI1OGY3MzkwOGEzXHUwMDFiWzBtXHJcdTAwMWJbNDdDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzQ3Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbNDdDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgICAgRG9jczogXHUwMDFiWzBtXHUwMDFiXTg7O21hbjphZ2V0dHkoOClcdTAwMWJcXFxyXHUwMDFiWzE1Q1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybW1hbjphZ2V0dHkoOClcdTAwMWJbMG1cdTAwMWJdODs7XHUwMDFiXFxcclx1MDAxYlsyOENcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMjhDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMjhDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgXHUwMDFiWzBtXHUwMDFiXTg7O21hbjpzeXN0ZW1kLWdldHR5LWdlbmVyYXRvcig4KVx1MDAxYlxcXHJcdTAwMWJbMTVDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtbWFuOnN5c3RlbWQtZ2V0dHktZ2VuZXJhdG9yKDgpXHUwMDFiWzBtXHUwMDFiXTg7O1x1MDAxYlxcXHJcdTAwMWJbNDVDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzQ1Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls0NUNcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICBcdTAwMWJbMG1cdTAwMWJdODs7aHR0cHM6Ly8wcG9pbnRlci5kZS9ibG9nL3Byb2plY3RzL3NlcmlhbC1jb25zb2xlLmh0bWxcdTAwMWJcXFxyXHUwMDFiWzE1Q1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWh0dHBzOi8vMHBvaW50ZXIuZGUvYmxvZy9wcm9qZWN0cy9zZXJpYWwtY29uc29sZS5odG1sXHUwMDFiWzBtXHUwMDFiXTg7O1x1MDAxYlxcXHJcdTAwMWJbNjhDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzY4Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbNjhDXHUwMDFiWzdBXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls3OENcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls3QVxyXHUwMDFiWzc0Q1x1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzs3OzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0xLzE0XHUwMDFiWzBtXHUwMDFiWzJBXHJcdTAwMWJbMkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTUuNjUyNjk0LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMUFcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm00NjYvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTUuOTc2MywgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls7MTszODsyOzE5MTs5NjsxMDU7NDg7Mjs1OTs2Njs4Mm0+XHUwMDFiWzBtXHUwMDFiWzszODsyOzE5MTs5NjsxMDU7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVxyXHUwMDFiWzNDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE1Ljk3OTI0NSwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzNBXHJcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybeKWjFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZXYtaHVnZXBhZ2VzLm1vdW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZXYtbXF1ZXVlLm1vdW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYXhkZXYtcmVjb25maWd1cmVALnNlcnZpY2UgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtaXJtbmdyQC5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtbS1ldmVudC5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYnVzLnNvY2tldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtaXJtbmdyQC5zb2NrZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzhCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMzgwLzQ2Nlx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzNDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE1Ljk4NDMzNiwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzJCXHJcdTAwMWJbMkNcclx1MDAxYlsyQ1x1MDAxYls7MTszMjs0ODsyOzU5OzY2OzgybeKXj1x1MDAxYlswbVxyXHUwMDFiWzNDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIGRldi1odWdlcGFnZXMubW91bnQgLSBIdWdlIFBhZ2VzIEZpbGUgU3lzdGVtXHUwMDFiWzBtXHJcdTAwMWJbNDhDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzQ4Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls0OENcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMUFcclx1MDAxYls3NENcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7NzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMS8xMlx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzJDXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgIExvYWRlZDogbG9hZGVkIChcdTAwMWJbMG1cdTAwMWJdODs7ZmlsZTovL3gxYy9wcm9jL3NlbGYvbW91bnRpbmZvXHUwMDFiXFxcclx1MDAxYlsyM0NcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0vcHJvYy9zZWxmL21vdW50aW5mb1x1MDAxYlswbVx1MDAxYl04OztcdTAwMWJcXFxyXHUwMDFiWzQzQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybTsgc3RhdGljXHUwMDFiWzBtXHJcdTAwMWJbNTFDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtKVx1MDAxYlswbVxyXHUwMDFiWzUyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYls1MkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls1MkNcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgICAgQWN0aXZlOiBcdTAwMWJbMG1cclx1MDAxYlsxNUNcdTAwMWJbOzE7MzI7NDg7Mjs1OTs2Njs4Mm1hY3RpdmUgKG1vdW50ZWQpXHUwMDFiWzBtXHJcdTAwMWJbMzFDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIHNpbmNlIEZyaSAyMDI1LTA5LTEyIDE3OjMzOjM0IENTVDsgNWggMjhtaW4gYWdcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIEludm9jYXRpb246IDE5MzY0OWVhZTk2NzQ4NGZiMDBiZWYzNjdlYjJjNzA1XHUwMDFiWzBtXHJcdTAwMWJbNDdDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzQ3Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbNDdDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgICBXaGVyZTogL2Rldi9odWdlcGFnZXNcdTAwMWJbMG1cclx1MDAxYlsyOUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMjlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYlsyOUNcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgICAgICBXaGF0OiBodWdldGxiZnNcdTAwMWJbMG1cclx1MDAxYlsyNENcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMjRDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzI0Q1x1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtICAgICAgIERvY3M6IFx1MDAxYlswbVx1MDAxYl04OztodHRwczovL2RvY3Mua2VybmVsLm9yZy9hZG1pbi1ndWlkZS9tbS9odWdldGxicGFnZS5odG1sXHUwMDFiXFxcclx1MDAxYlsxNUNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1odHRwczovL2RvY3Mua2VybmVsLm9yZy9hZG1pbi1ndWlkZS9tbS9odWdldGxicGFnZS5odG1sXHUwMDFiWzBtXHUwMDFiXTg7O1x1MDAxYlxcXHJcdTAwMWJbNzBDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzcwQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzcwQ1x1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgIFx1MDAxYlswbVx1MDAxYl04OztodHRwczovL3N5c3RlbWQuaW8vQVBJX0ZJTEVfU1lTVEVNU1x1MDAxYlxcXHJcdTAwMWJbMTVDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtaHR0cHM6Ly9zeXN0ZW1kLmlvL0FQSV9GSUxFX1NZU1RFTVNcdTAwMWJbMG1cdTAwMWJdODs7XHUwMDFiXFxcclx1MDAxYls1MENcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbNTBDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls1MENcdTAwMWJbM0Fcclx1MDAxYls3OENcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbNEFcclx1MDAxYls3NENcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7NzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtMS8xMlx1MDAxYlswbVx1MDAxYlsyQVxyXHUwMDFiWzNDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE2LjEwMTA5NiwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls7MTszODsyOzE5MTs5NjsxMDU7NDg7Mjs1OTs2Njs4Mm0+XHUwMDFiWzBtXHUwMDFiWzszODsyOzE5MTs5NjsxMDU7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtZG9cdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cclx1MDAxYls0Q1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNi4xMDE2NTIsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYlszQVxyXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm3iloxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtY2tlci1jb21wb3NlQC5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtY2tlci5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtY2tlci5zb2NrZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXN5c3RlbWQtdXBkYXRlLVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtbmUuc2VydmljZSAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1idXMuc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ja2V0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1idXMtYnJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJta2VyLnNlcnZpY2UgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWdpdC1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYWVtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybW5ALnNlcnZpY2UgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbOEJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0xODkvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNENcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuMTA1MDIyLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMkJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDXHUwMDFiWzsxOzMxOzQ4OzI7NTk7NjY7ODJtRmFpbGVkIHRvIGdldCBwcm9wZXJ0aWVzOiBVbml0IG5hbWUgZG9ja2VyLWNvbXBvc2VALnNlcnZpY2UgaXMgbmVpdGhlciBhIHZhbFx1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzsxOzMxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzdBXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls3OENcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzc4Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbNkFcclx1MDAxYls0Q1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNi4xODY3NDksICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbOzE7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtPlx1MDAxYlswbVx1MDAxYls7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybWRvY1x1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVxyXHUwMDFiWzVDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE2LjE4NzM2MSwgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzNBXHJcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybeKWjFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWtlci1jb21wb3NlQC5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWtlci5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWtlci5zb2NrZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1idXMuc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJta2V0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXN5c3RlbWQtdXBkYXRlLVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtbmUuc2VydmlcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZSAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1pcm1uZ3JALnNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWtldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1tLWV2ZW50LnNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWtldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbOEJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0xODQvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNUNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuMjY1NTE0LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzsxOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybT5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1kb2NrXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbNkNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuMjY2NDA5LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbM0Fcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4paMXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lci1jb21wb3NlQC5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lci5zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lci5zb2NrZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1idXMuc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWV0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1pcm1uZ3JALnNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1tLWV2ZW50LnNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aWMgICAgICAtICAgICAgICAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWF2YWhpLVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1hZW1vbi5zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZXQgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbOEJcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm05Ni80NjZcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYls2Q1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNi4zMTA5MTQsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbOzE7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtPlx1MDAxYlswbVx1MDAxYls7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybWRvY2tlXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbN0NcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuMzEyNzAzLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbM0Fcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4paMXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXItY29tcG9zZUAuc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXIuc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXIuc29ja2V0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYnVzLnNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtaXJtbmdyQC5zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtbS1ldmVudC5zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGljICAgICAgLSAgICAgICAgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1hdmFoaS1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYWVtb24uc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm10ICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzhCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtOTYvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1Il0KWzE2LjMxMjczMSwgIm8iLCAiOzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbN0NcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuMzgyMTMxLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzsxOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybT5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1kb2NrZXJcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cclx1MDAxYls4Q1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNi4zODM0OTUsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYlszQVxyXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm3iloxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tY29tcG9zZUAuc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0uc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIJcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS5zb2NrZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybeKUglx1MDAxYlswbVx1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc3lzdGVtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1wY3JsXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtQC5zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm12aWNlICAgICAgICAgICAgICAgICAgICAgIHN0YXRpYyAgICAgIC0gICAgICAgICAgICAgICAgwrfCt1x1MDAxYlswbVx1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc3lzdGVtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1wY3JsXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtY3VcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZWJvb3QtYXV0aG9yaXR5LnNlcnZpY2UgIGRpc2FibGVkICAgIGRpc2FibGVkICAgICAgICAgwrfCt1x1MDAxYlswbVx1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc3lzdGVtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1wY3JsXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtY3VcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtZWJvb3QtcG9saWN5LnNlcnZpY2UgICAgIGRpc2FibGVkICAgIGRpc2FibGVkICAgICAgICAgwrfCt1x1MDAxYlswbVx1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszOCJdClsxNi4zODM1MDYsICJvIiwgIjsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc3lzdGVtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1xdVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm10YWNoZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtQC5zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm12aWNlICAgICAgICAgICAgICAgICAgIHN0YXRpYyAgICAgIC0gICAgICAgICAgICAgICAgwrfCt1x1MDAxYlswbVx1MDAxYls4QlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTE0LzQ2Nlx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm3ilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYlsxQlxyXHUwMDFiWzhDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE2Ljc1NjI1LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzsxOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybT5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1kb2NrZXIuXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbOUNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuNzU3OTQyLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbM0Fcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4paMXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zZXJ2aWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYlsxQVxyXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtLlx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXNvY2tldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkICAgIGRpc2FibGVkICAgICAgICAgwrfCt1x1MDAxYlswbVxyXHUwMDFiWzc5Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tY29tcG9zZUBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtc2VydmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHJcdTAwMWJbNzlDXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cclx1MDAxYls3OUNcdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXN5c3RlbVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tcGNybFx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1zXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWN1XHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWVib290LXBvbGljeVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybS5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zZXJ2aWNlICAgICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybXN5c3RlbVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tcGNybFx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS1zZWN1clx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ib290LWF1dGhvXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWl0eVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybS5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zZXJ2aWNlICBkaXNhYmxlZCAgICBkaXNhYmxlZCAgICAgICAgIMK3wrdcdTAwMWJbMG1cdTAwMWJbMUFcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzFBXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls4QlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTUvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzYiXQpbMTYuNzU3OTY5LCAibyIsICI2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbOUNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTYuNzY1Mjk3LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbMkJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDXHUwMDFiWzsxOzMyOzQ4OzI7NTk7NjY7ODJt4pePXHUwMDFiWzBtXHJcdTAwMWJbM0NcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gZG9ja2VyLnNlcnZpY2UgLSBEb2NrZXIgQXBwbGljYXRpb24gQ29udGFpbmVyIEVuZ2luZVx1MDAxYlswbVxyXHUwMDFiWzU2Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYls1NkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzU2Q1x1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVx1MDAxYlsxQVxyXHUwMDFiWzc0Q1x1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzs3OzM4OzI7MjM0OzIwMzsxMzg7NDg7Mjs1OTs2Njs4Mm0xLzI1XHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMkNcclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgICAgTG9hZGVkOiBsb2FkZWQgKFx1MDAxYlswbVx1MDAxYl04OztmaWxlOi8veDFjL3Vzci9saWIvc3lzdGVtZC9zeXN0ZW0vZG9ja2VyLnNlcnZpY2VcdTAwMWJcXFxyXHUwMDFiWzIzQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybS91c3IvbGliL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlXHUwMDFiWzBtXHUwMDFiXTg7O1x1MDAxYlxcXHJcdTAwMWJbNjFDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtOyBcdTAwMWJbMG1cclx1MDAxYls2M0NcdTAwMWJbOzE7Mzg7NTsxODU7NDg7Mjs1OTs2Njs4Mm1kaXNhYmxlZFx1MDAxYlswbVxyXHUwMDFiWzcxQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybTsgcHJlc2VcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtICAgIERyb3AtSW46IC9ldGMvc3lzdGVtZC9zeXN0ZW0vZG9ja2VyLnNlcnZpY2UuZFx1MDAxYlswbVxyXHUwMDFiWzUxQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYls1MUNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbNTFDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAg4pSU4pSAXHUwMDFiWzBtXHUwMDFiXTg7O2ZpbGU6Ly94MWMvZXRjL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlLmQvb3ZlcnJpZGUuY29uZlx1MDAxYlxcXHJcdTAwMWJbMTdDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtb3ZlcnJpZGUuY29uZlx1MDAxYlswbVx1MDAxYl04OztcdTAwMWJcXFxyXHUwMDFiWzMwQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSwgXHUwMDFiWzBtXHUwMDFiXTg7O2ZpbGU6Ly94MWMvZXRjL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlLmQvcHJveHkuY29uZlx1MDAxYlxcXHJcdTAwMWJbMzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtcHJveHkuY29uZlx1MDAxYlswbVx1MDAxYl04OztcdTAwMWJcXFxyXHUwMDFiWzQyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYls0MkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbNDJDXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gICAgIEFjdGl2ZTogXHUwMDFiWzBtXHJcdTAwMWJbMTVDXHUwMDFiWzsxOzMyOzQ4OzI7NTk7NjY7ODJtYWN0aXZlIChydW5uaW5nKVx1MDAxYlswbVxyXHUwMDFiWzMxQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBzaW5jZSBGcmkgMjAyNS0wOS0xMiAyMjo1OTowMCBDU1Q7IDJtaW4gNTJzIGFnXHUwMDFiWzFCXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBJbnZvY2F0aW9uOiBhZDQzYzhjZGQxZGE0ODlmOGQyZDgxMzA3NTY3OGJhZlx1MDAxYlswbVxyXHUwMDFiWzQ3Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYls0N0NcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzQ3Q1x1MDAxYlsxQlxyXHUwMDFiWzJDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzJDXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtVHJpZ2dlcmVkQnk6IFx1MDAxYlswbVxyXHUwMDFiWzE1Q1x1MDAxYls7MTszMjs0ODsyOzU5OzY2OzgybeKXj1x1MDAxYlswbVxyXHUwMDFiWzE2Q1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBkb2NrZXIuc29ja2V0XHUwMDFiWzBtXHJcdTAwMWJbMzBDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzMwQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYlszMENcdTAwMWJbMUJcclx1MDAxYlsyQ1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm1cclx1MDAxYlsyQ1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSAgICAgICBEb2NzOiBcdTAwMWJbMG1cdTAwMWJdODs7aHR0cHM6Ly9kb2NzLmRvY2tlci5jb21cdTAwMWJcXFxyXHUwMDFiWzE1Q1x1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWh0dHBzOi8vZG9jcy5kb2NrZXIuY29tXHUwMDFiWzBtXHUwMDFiXTg7O1x1MDAxYlxcXHJcdTAwMWJbMzhDXHUwMDFiWzs0ODsyOzU5OzY2OzgybVxyXHUwMDFiWzM4Q1x1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbMzhDXHUwMDFiWzdBXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbNzhDXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSCXHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbNzRDXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzc7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTEvMjVcdTAwMWJbMG1cdTAwMWJbMkFcclx1MDAxYls5Q1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNi45MjkyMDMsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbOzE7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtPlx1MDAxYlswbVx1MDAxYls7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybWRvY2tlci5zXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbMTBDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE2LjkzMDc4LCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcdTAwMWJbM0Fcclx1MDAxYls7MTszODsyOzE4MDsxNDE7MTcyOzQ4OzI7NTk7NjY7ODJt4paMXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybW9cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXNcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWVydmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybW9ja2V0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tY29tcG9zZUBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWVydmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1jdVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lYm9vdC1wb2xpY3lcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWVydmljZSAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc2VjdXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYm9vdC1hdXRob1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1pdHlcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybWVydmljZSAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzZCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7Il0KWzE2LjkzMDgwMiwgIm8iLCAiNTk7NjY7ODJtNS80NjZcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsxMENcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTcuMTE3MDIsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzBtXHJcdTAwMWJbOzE7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtPlx1MDAxYlswbVx1MDAxYls7Mzg7MjsxOTE7OTY7MTA1OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybWRvY2tlci5zZVx1MDAxYlswbVx1MDAxYls7MTs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVxyXHUwMDFiWzExQ1x1MDAxYls/MjVoXHUwMDFiWz83aCJdClsxNy4xMTg1ODYsICJvIiwgIlx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYlszQVxyXHUwMDFiWzsxOzM4OzI7MTgwOzE0MTsxNzI7NDg7Mjs1OTs2Njs4Mm3iloxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWRcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1jXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybS5cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ydmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybW9ja1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm10ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tY29tcG9zZUBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ydmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1jdVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lYm9vdC1wb2xpY3lcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ydmljZSAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc2VjdXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYm9vdC1hdXRob1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbIl0KWzE3LjExODYwNywgIm8iLCAiOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1pdHlcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1ydmljZSAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzZCXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODsyOzIzNDsyMDM7MTM4OzQ4OzI7NTk7NjY7ODJtNS80NjZcdTAwMWJbMG1cdTAwMWJbOzM4OzU7NTk7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJt4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbMUJcclx1MDAxYlsxMUNcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTcuMTcxNTgzLCAibyIsICJcdTAwMWJbPzdsXHUwMDFiWz8yNWxcclx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlswbVxyXHUwMDFiWzsxOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybT5cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTkxOzk2OzEwNTs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7NDg7Mjs1OTs2Njs4Mm1kb2NrZXIuc2VyXHUwMDFiWzBtXHUwMDFiWzsxOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHJcdTAwMWJbMTJDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE3LjE3Mjg0MywgIm8iLCAiXHUwMDFiWz83bFx1MDAxYls/MjVsXHUwMDFiWzNBXHJcdTAwMWJbOzE7Mzg7MjsxODA7MTQxOzE3Mjs0ODsyOzU5OzY2OzgybeKWjFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZFx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJta1x1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtLlx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1zXHUwMDFiWzBtXHUwMDFiWzsxOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzE7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7MTszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtclx1MDAxYlswbVx1MDAxYls7MTszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtdmljZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtb1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWNcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1rXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtZVx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tY29tcG9zZUBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtdmljZSAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1jdVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1lYm9vdC1wb2xpY3lcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtdmljZSAgICAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1zeXN0ZW1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1kXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtLXBjcmxcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1vXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtY1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWtcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm0tc2VjdXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1lXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtYm9vdC1hdXRob1x1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybXJcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1pdHlcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm0uXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtXHUwMDFiWzBtXHUwMDFiWzszODsyOzEyOTsxNjE7MTkzOzQ4OzI7NTk7NjY7ODJtc1x1MDAxYlswbVx1MDAxYls7Mzg7MjsyMjk7MjMzOzI0MDs0ODsyOzU5OzY2OzgybVx1MDAxYlswbVx1MDAxYls7Mzg7MjsxMjk7MTYxOzE5Mzs0ODsyOzU5OzY2OzgybWVcdTAwMWJbMG1cdTAwMWJbOzM4OzI7MjI5OzIzMzsyNDA7NDg7Mjs1OTs2Njs4Mm1cdTAwMWJbMG1cdTAwMWJbOzM4OzI7MTI5OzE2MTsxOTM7NDg7Mjs1OTs2Njs4Mm1yXHUwMDFiWzBtXHUwMDFiWzszODsyOzIyOTsyMzM7MjQwOzQ4OzI7NTk7NjY7ODJtdmljZSAgZGlzYWJsZWQgICAgZGlzYWJsZWQgICAgICAgICDCt8K3XHUwMDFiWzBtXHUwMDFiWzFBXHJcdTAwMWJbOzQ4OzI7NTk7NjY7ODJtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMG1cclx1MDAxYls2QlxyXHUwMDFiWzs0ODsyOzU5OzY2OzgybSBcdTAwMWJbMG1cdTAwMWJbOzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7MjsyMzQ7MjAzOzEzODs0ODsyOzU5OzY2OzgybTQvNDY2XHUwMDFiWzBtXHUwMDFiWzszODs1OzU5OzQ4OzI7NTk7NjY7ODJtIFx1MDAxYlswbVx1MDAxYls7Mzg7NTs1OTs0ODsyOzU5OzYiXQpbMTcuMTcyODY2LCAibyIsICI2OzgybeKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFx1MDAxYlswbVx1MDAxYls7NDg7Mjs1OTs2Njs4Mm0gXHUwMDFiWzBtXHUwMDFiWzFCXHJcdTAwMWJbMTJDXHUwMDFiWz8yNWhcdTAwMWJbPzdoIl0KWzE3Ljc5NDQ0OCwgIm8iLCAiXHUwMDFiWz8xMDQ5bFx1MDAxYls/N2xcdTAwMWJbPzI1bFx1MDAxYls/MTAwMGxcdTAwMWJbPzEwMDJsXHUwMDFiWz8xMDA2bFx1MDAxYls/MjAwNGxcdTAwMWJbPzI1aFx1MDAxYls/N2giXQpbMTcuODIxMzM3LCAibyIsICJcdTAwMWJbPzFoXHIiXQpbMTcuODIzNjc0LCAibyIsICJcdTAwMWJbMDsxOzMybeKXj1x1MDAxYlswbSBkb2NrZXIuc2VydmljZSAtIERvY2tlciBBcHBsaWNhdGlvbiBDb250YWluZXIgRW5naW5lXHUwMDFiW21cclxuICAgICBMb2FkZWQ6IGxvYWRlZCAoXHUwMDFiXTg7O2ZpbGU6Ly94MWMvdXNyL2xpYi9zeXN0ZW1kL3N5c3RlbS9kb2NrZXIuc2VydmljZVx1MDAxYlxcL3Vzci9saWIvc3lzdGVtZC9zeXN0ZW0vZG9ja2VyLnNlcnZpY2VcdTAwMWJdODs7XHUwMDFiXFw7IFx1MDAxYlswOzE7Mzg6NToxODVtZGlzYWJsZWRcdTAwMWJbMG07IHByZXNldDogXHUwMDFiWzA7MTszODo1OjE4NW1cdTAwMWJbbVx1MDAxYl04OztcdTAwMWJcXFx1MDAxYls3bT5cdTAwMWJbMjdtXHJcbiAgICBEcm9wLUluOiAvZXRjL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlLmRcdTAwMWJbbVxyXG4gICAgICAgICAgICAg4pSU4pSAXHUwMDFiXTg7O2ZpbGU6Ly94MWMvZXRjL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlLmQvb3ZlcnJpZGUuY29uZlx1MDAxYlxcb3ZlcnJpZGUuY29uZlx1MDAxYl04OztcdTAwMWJcXCwgXHUwMDFiXTg7O2ZpbGU6Ly94MWMvZXRjL3N5c3RlbWQvc3lzdGVtL2RvY2tlci5zZXJ2aWNlLmQvcHJveHkuY29uZlx1MDAxYlxccHJveHkuY29uZlx1MDAxYl04OztcdTAwMWJcXFx1MDAxYlttXHUwMDFiXTg7O1x1MDAxYlxcXHJcbiAgICAgQWN0aXZlOiBcdTAwMWJbMDsxOzMybWFjdGl2ZSAocnVubmluZylcdTAwMWJbMG0gc2luY2UgRnJpIDIwMjUtMDktMTIgMjI6NTk6MDAgQ1NUOyAybWluIDUzcyBhZ29cdTAwMWJbbVxyXG4gSW52b2NhdGlvbjogYWQ0M2M4Y2RkMWRhNDg5ZjhkMmQ4MTMwNzU2NzhiYWZcdTAwMWJbbVxyXG5UcmlnZ2VyZWRCeTogXHUwMDFiWzA7MTszMm3il49cdTAwMWJbMG0gZG9ja2VyLnNvY2tldFx1MDAxYlttXHJcbiAgICAgICBEb2NzOiBcdTAwMWJdODs7aHR0cHM6Ly9kb2NzLmRvY2tlci5jb21cdTAwMWJcXGh0dHBzOi8vZG9jcy5kb2NrZXIuY29tXHUwMDFiXTg7O1x1MDAxYlxcXHUwMDFiW21cdTAwMWJdODs7XHUwMDFiXFxcclxuICAgTWFpbiBQSUQ6IDI5NTExOCAoZG9ja2VyZClcdTAwMWJbbVxyXG4gICAgICBUYXNrczogMTRcdTAwMWJbbVxyXG4gICAgIE1lbW9yeTogMjZNIChwZWFrOiAzMS45TSlcdTAwMWJbbVxyXG4gICAgICAgIENQVTogMTkxbXNcdTAwMWJbbVxyXG4gICAgIENHcm91cDogL3N5c3RlbS5zbGljZS9kb2NrZXIuc2VydmljZVx1MDAxYlttXHJcbiAgICAgICAgICAgICDilJTilIBcdTAwMWJbMDszODs1OzI0NW0yOTUxMTggL3Vzci9iaW4vZG9ja2VyZCAtSCBmZDovLyAtLWNvbnRhaW4iXQpbMTcuODIzNzA5LCAibyIsICJlcmQ9L3J1bi9jb250YWluZXJkL2NvXHUwMDFiW21cdTAwMWJbN20+XHUwMDFiWzI3bVxyXG5cdTAwMWJbbVxyXG5TZXAgMTIgMjI6NTk6MDAgeDFjIGRvY2tlcmRbMjk1MTE4XTogdGltZT1cIjIwMjUtMDktMTJUMjI6NTk6MDAuMTcxNjE5NTU3KzA4OjAwXCJcdTAwMWJbbVx1MDAxYls3bT5cdTAwMWJbMjdtXHJcblNlcCAxMiAyMjo1OTowMCB4MWMgZG9ja2VyZFsyOTUxMThdOiB0aW1lPVwiMjAyNS0wOS0xMlQyMjo1OTowMC43NDg4Mjc3OTYrMDg6MDBcIlx1MDAxYlttXHUwMDFiWzdtPlx1MDAxYlsyN21cclxuU2VwIDEyIDIyOjU5OjAwIHgxYyBkb2NrZXJkWzI5NTExOF06IHRpbWU9XCIyMDI1LTA5LTEyVDIyOjU5OjAwLjc4MjQ2MDI1MSswODowMFwiXHUwMDFiW21cdTAwMWJbN20+XHUwMDFiWzI3bVxyXG5TZXAgMTIgMjI6NTk6MDAgeDFjIGRvY2tlcmRbMjk1MTE4XTogdGltZT1cIjIwMjUtMDktMTJUMjI6NTk6MDAuNzkyNTU3MDU5KzA4OjAwXCJcdTAwMWJbbVx1MDAxYls3bT5cdTAwMWJbMjdtXHJcblx1MDAxYls3bWxpbmVzIDEtMTlcdTAwMWJbMjdtXHUwMDFiW0siXQpbMjAuNjU5ODA2LCAibyIsICJcclx1MDAxYltLXHUwMDFiWz8xbCJdClsyMC42NjEyOTYsICJvIiwgIlx1MDAxYlsxbVx1MDAxYls3bSVcdTAwMWJbMjdtXHUwMDFiWzFtXHUwMDFiWzBtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyIFxyIl0KWzIwLjY3MTI5NCwgIm8iLCAiXHJcdTAwMWJbMG1cdTAwMWJbMjdtXHUwMDFiWzI0bVx1MDAxYltKXHUwMDFiWzMybS9cdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNm1sYVx1MDAxYlszOW0gXHUwMDFiWzM3bUBcdTAwMWJbMzltIFx1MDAxYlszNW14MWNcdTAwMWJbMzltIFx1MDAxYlszMG0yMzowMVx1MDAxYlszOW0gXHUwMDFiWzM3bS0+XHUwMDFiWzM5bSBcdTAwMWJbMzJtflx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzBtXHJcblx1MDAxYlszMm1cXFx1MDAxYlszOW0gXHUwMDFiWzFtXHUwMDFiWzM0bSQgXHUwMDFiWzM3bVx1MDAxYlswbVx1MDAxYlszN21cdTAwMWJbS1x1MDAxYls/MjAwNGgiXQpbMjIuNjY3MTQ1LCAibyIsICJ0Il0KWzIyLjY2ODMwNSwgIm8iLCAiXGJcdTAwMWJbMzJtdFx1MDAxYlszOW0iXQpbMjIuNjY4NDA5LCAibyIsICJcYlx1MDAxYlszMm10XHUwMDFiWzM5bVx1MDAxYls5MG1pbWUgc3lzdGVtY3RsIGxpc3QtdW5pdC1maWxlcyAtLXN0YXRlPWRpc2FibGVkIC0tcXVpZXQgLS1uby1wYWdlciA+L2Rldi9udWxcdTAwMWJbOTBtbFx1MDAxYlszOW1cdTAwMWJbS1x1MDAxYltBXHUwMDFiWzRDIl0KWzIyLjc0NTc5NiwgIm8iLCAiXGJcdTAwMWJbMzJtdFx1MDAxYlszMm1oXHUwMDFiWzM5bVx1MDAxYltLXHUwMDFiWzFCXHJcdTAwMWJbS1x1MDAxYltBXHUwMDFiWzZDIl0KWzIyLjc0ODA0MywgIm8iLCAiXGJcYlx1MDAxYlsxbVx1MDAxYlszMW10XHUwMDFiWzFtXHUwMDFiWzMxbWhcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzIyLjc5ODY0MSwgIm8iLCAiXGJcYlx1MDAxYlsxbVx1MDAxYlszMW10XHUwMDFiWzFtXHUwMDFiWzMxbWhcdTAwMWJbMW1cdTAwMWJbMzFtZVx1MDAxYlswbVx1MDAxYlszOW0iXQpbMjIuODcwNzQ0LCAibyIsICJcYlx1MDAxYlsxbVx1MDAxYlszMW1lXHUwMDFiWzFtXHUwMDFiWzMxbSBcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzIyLjg3MTU1MiwgIm8iLCAiXGJcYlx1MDAxYlsxbVx1MDAxYlszMW1lXHUwMDFiWzBtXHUwMDFiWzM5bVx1MDAxYlswbVx1MDAxYlszOW0gIl0KWzIzLjA5OTI2MywgIm8iLCAiYyJdClsyMy4xODc1ODUsICJvIiwgIm8iXQpbMjMuNDY1MTE3LCAibyIsICJtIl0KWzIzLjU5ODE5MSwgIm8iLCAibSJdClsyMy42OTAzNTUsICJvIiwgImEiXQpbMjMuNzcyMjI4LCAibyIsICJuIl0KWzIzLjg1NTU1OCwgIm8iLCAiZCJdClsyMy45MjAyMTksICJvIiwgIiAiXQpbMjQuMTEwNTMyLCAibyIsICJqIl0KWzI0LjI4NzUyMywgIm8iLCAidSJdClsyNC4zNDcxNDQsICJvIiwgInMiXQpbMjQuNDI1NDM2LCAibyIsICJ0Il0KWzI0LjUwNjc5LCAibyIsICIgIl0KWzI0LjcxODMyOCwgIm8iLCAiZSJdClsyNC44Nzg4NTcsICJvIiwgIngiXQpbMjUuMDEyNTgyLCAibyIsICJlIl0KWzI1LjIwMzAyMiwgIm8iLCAiYyJdClsyNS40MjMzNDMsICJvIiwgInUiXQpbMjUuNTgwNzU1LCAibyIsICJ0Il0KWzI1LjYyNjkwMSwgIm8iLCAiZSJdClsyNS43ODQ5MTUsICJvIiwgImQiXQpbMjUuOTExNDk0LCAibyIsICIgIl0KWzI2LjU2MDI1NywgIm8iLCAiaCJdClsyNi42MTMwOTksICJvIiwgImEiXQpbMjYuNjg0MjA1LCAibyIsICJzIl0KWzI2Ljc5MTczMywgIm8iLCAiICJdClsyNi45NzkxMTUsICJvIiwgImIiXQpbMjYuOTgxMzUyLCAibyIsICJcYlx1MDAxYls0bWJcdTAwMWJbMjRtIl0KWzI3LjA0ODQ5OSwgIm8iLCAiXGJcdTAwMWJbNG1iXHUwMDFiWzRtZVx1MDAxYlsyNG0iXQpbMjcuMDUzMjgxLCAibyIsICJcYlxiXHUwMDFiWzI0bWJcdTAwMWJbMjRtZSJdClsyNy4yMDYxMDksICJvIiwgIm4iXQpbMjcuMzMzMzA5LCAibyIsICJuIl0KWzI3LjY5MTA5LCAibyIsICJcYiBcYiJdClsyNy44MTE1NjksICJvIiwgIlxiIFxiIl0KWzI3Ljg3MzYzLCAibyIsICJlIl0KWzI4LjAwNTM4MSwgIm8iLCAibiJdClsyOC4yMDA0MTMsICJvIiwgIiAiXQpbMjguMzY1NzM3LCAibyIsICJzIl0KWzI4LjM2OTEzMywgIm8iLCAiXGJcdTAwMWJbNG1zXHUwMDFiWzI0bSJdClsyOC41NTM5NTgsICJvIiwgIlxiXHUwMDFiWzRtc1x1MDAxYls0bWFcdTAwMWJbMjRtIl0KWzI4LjU1NjM1MiwgIm8iLCAiXGJcYlx1MDAxYlsyNG1zXHUwMDFiWzI0bWEiXQpbMjguNjkxNDEzLCAibyIsICJ2Il0KWzI4LjcyMTgwNCwgIm8iLCAiZSJdClsyOC44MjM1MTIsICJvIiwgIiAiXQpbMjkuMjM2OTk0LCAibyIsICJpIl0KWzI5LjM2NzAxNCwgIm8iLCAibiJdClsyOS40MzkwODgsICJvIiwgIiAiXQpbMjkuNTMwMiwgIm8iLCAidCJdClsyOS42MzEyOTMsICJvIiwgImgiXQpbMjkuNjc2OTY0LCAibyIsICJlIl0KWzI5Ljc2NzMwMywgIm8iLCAiICJdClsyOS44ODg3MDQsICJvIiwgImgiXQpbMjkuOTQ1NTUzLCAibyIsICJpIl0KWzMwLjAzNjgwOSwgIm8iLCAicyJdClszMC4yNDcxMjMsICJvIiwgInQiXQpbMzAuNDAxODE1LCAibyIsICJvIl0KWzMwLjQ4OTMwNiwgIm8iLCAiciJdClszMC42MDgwOTYsICJvIiwgInkiXQpbMzAuNzYzNjY1LCAibyIsICIgIl0KWzMwLjk0MzAxOCwgIm8iLCAidCJdClszMS4wMjE2NjcsICJvIiwgIm8iXQpbMzEuMTI1OTY5LCAibyIsICJvIl0KWzMxLjM1Nzg5OSwgIm8iLCAiLiJdClszMi4wODc1MjksICJvIiwgIlx1MDAxYls/MjAwNGxcdTAwMWJbMUJcciJdClszMi4wODc5NTksICJvIiwgIlx1MDAxYlsxbVx1MDAxYls3bSVcdTAwMWJbMjdtXHUwMDFiWzFtXHUwMDFiWzBtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyIFxyIl0KWzMyLjA5ODQ2MSwgIm8iLCAiXHJcdTAwMWJbMG1cdTAwMWJbMjdtXHUwMDFiWzI0bVx1MDAxYltKXHUwMDFiWzMybS9cdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNm1sYVx1MDAxYlszOW0gXHUwMDFiWzM3bUBcdTAwMWJbMzltIFx1MDAxYlszNW14MWNcdTAwMWJbMzltIFx1MDAxYlszMG0yMzowMlx1MDAxYlszOW0gXHUwMDFiWzM3bS0+XHUwMDFiWzMxbVsxMzBdXHUwMDFiWzM5bSBcdTAwMWJbMzJtflx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzBtXHJcblx1MDAxYlszMm1cXFx1MDAxYlszOW0gXHUwMDFiWzFtXHUwMDFiWzM0bSQgXHUwMDFiWzM3bVx1MDAxYlswbVx1MDAxYlszN21cdTAwMWJbS1x1MDAxYls/MjAwNGgiXQpbMzIuNzkyNDA0LCAibyIsICJoIl0KWzMyLjc5NDMwNCwgIm8iLCAiXGJcdTAwMWJbMW1cdTAwMWJbMzFtaFx1MDAxYlswbVx1MDAxYlszOW1cYlx1MDAxYlsxbVx1MDAxYlszMW1oXHUwMDFiWzBtXHUwMDFiWzM5bVx1MDAxYls5MG1pc3RvcnkgfCB0YWlsIC1uMlx1MDAxYlszOW1cdTAwMWJbMTdEIl0KWzMyLjg2MjYzNiwgIm8iLCAiXGJcdTAwMWJbMW1cdTAwMWJbMzFtaFx1MDAxYlsxbVx1MDAxYlszMW1pXHUwMDFiWzBtXHUwMDFiWzM5bSJdClszMi45Nzg5NTYsICJvIiwgIlxiXGJcdTAwMWJbMW1cdTAwMWJbMzFtaFx1MDAxYlsxbVx1MDAxYlszMW1pXHUwMDFiWzFtXHUwMDFiWzMxbXNcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzMzLjQxNTc3MSwgIm8iLCAiXHUwMDFiWzM5bXRcdTAwMWJbMzltb1x1MDAxYlszOW1yXHUwMDFiWzM5bXlcdTAwMWJbMzltIFx1MDAxYlszOW18XHUwMDFiWzM5bSBcdTAwMWJbMzltdFx1MDAxYlszOW1hXHUwMDFiWzM5bWlcdTAwMWJbMzltbFx1MDAxYlszOW0gXHUwMDFiWzM5bS1cdTAwMWJbMzltblx1MDAxYlszOW0yIl0KWzMzLjQxNzUyMSwgIm8iLCAiXHUwMDFiWzE4RFx1MDAxYlswbVx1MDAxYlszMm1oXHUwMDFiWzBtXHUwMDFiWzMybWlcdTAwMWJbMG1cdTAwMWJbMzJtc1x1MDAxYlszMm10XHUwMDFiWzMybW9cdTAwMWJbMzJtclx1MDAxYlszMm15XHUwMDFiWzM5bVx1MDAxYlszQ1x1MDAxYlszMm10XHUwMDFiWzMybWFcdTAwMWJbMzJtaVx1MDAxYlszMm1sXHUwMDFiWzM5bVx1MDAxYls0QyJdClszNS4zMjI3MjksICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQpbMzUuMzI0MTYsICJvIiwgIjEwMDAzICBzc3RhcnRcclxuMTAwMDQgIHMgc3RhcnQgZG9ja2VyLnNlcnZpY2UgJiYgcyBzdGF0dXMgJF8gfHwgc2ogLXhldSAkX1xyXG4iXQpbMzUuMzI0MjQsICJvIiwgIlx1MDAxYlsxbVx1MDAxYls3bSVcdTAwMWJbMjdtXHUwMDFiWzFtXHUwMDFiWzBtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyIFxyIl0KWzM1LjMzNDQ5NiwgIm8iLCAiXHJcdTAwMWJbMG1cdTAwMWJbMjdtXHUwMDFiWzI0bVx1MDAxYltKXHUwMDFiWzMybS9cdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNm1sYVx1MDAxYlszOW0gXHUwMDFiWzM3bUBcdTAwMWJbMzltIFx1MDAxYlszNW14MWNcdTAwMWJbMzltIFx1MDAxYlszMG0yMzowMlx1MDAxYlszOW0gXHUwMDFiWzM3bS0+XHUwMDFiWzM5bSBcdTAwMWJbMzJtflx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzBtXHJcblx1MDAxYlszMm1cXFx1MDAxYlszOW0gXHUwMDFiWzFtXHUwMDFiWzM0bSQgXHUwMDFiWzM3bVx1MDAxYlswbVx1MDAxYlszN21cdTAwMWJbS1x1MDAxYls/MjAwNGgiXQpbMzguMzc4NjQyLCAibyIsICJlIl0KWzM4LjM4MDUsICJvIiwgIlxiXHUwMDFiWzFtXHUwMDFiWzMxbWVcdTAwMWJbMG1cdTAwMWJbMzltIl0KWzM4LjM4MDYxLCAibyIsICJcYlx1MDAxYlsxbVx1MDAxYlszMW1lXHUwMDFiWzBtXHUwMDFiWzM5bVx1MDAxYls5MG14aXRcdTAwMWJbMzltXGJcYlxiIl0KWzM4LjY0MDM3MiwgIm8iLCAiXGJcdTAwMWJbMW1cdTAwMWJbMzFtZVx1MDAxYlsxbVx1MDAxYlszMW14XHUwMDFiWzBtXHUwMDFiWzM5bSJdClszOC42NDEyMjMsICJvIiwgIlxiXGJcdTAwMWJbMG1cdTAwMWJbMzJtZVx1MDAxYlswbVx1MDAxYlszMm14XHUwMDFiWzM5bSJdClszOC43ODk0NDYsICJvIiwgIlxiXGJcdTAwMWJbMzJtZVx1MDAxYlszMm14XHUwMDFiWzMybWlcdTAwMWJbMzltIl0KWzM4Ljc5MTE0MywgIm8iLCAiXGJcYlxiXHUwMDFiWzFtXHUwMDFiWzMxbWVcdTAwMWJbMW1cdTAwMWJbMzFteFx1MDAxYlsxbVx1MDAxYlszMW1pXHUwMDFiWzBtXHUwMDFiWzM5bSJdClszOC45ODU4NzYsICJvIiwgIlxiXHUwMDFiWzFtXHUwMDFiWzMxbWlcdTAwMWJbMW1cdTAwMWJbMzFtdFx1MDAxYlswbVx1MDAxYlszOW0iXQpbMzguOTg4NDYzLCAibyIsICJcYlxiXGJcYlx1MDAxYlswbVx1MDAxYlszMm1lXHUwMDFiWzBtXHUwMDFiWzMybXhcdTAwMWJbMG1cdTAwMWJbMzJtaVx1MDAxYlswbVx1MDAxYlszMm10XHUwMDFiWzM5bSJdCls0MC44MjU4NDMsICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQpbNDAuODMwMjQsICJ4IiwgIjAiXQo=",
                        document.getElementById('asciicast-/_assets/systemd.v2.cast'),
                        { });
                });
            &lt;/script&gt;&lt;section id="motivation-the-pain-point"&gt;
&lt;h2&gt;Motivation: The Pain Point&lt;/h2&gt;
&lt;p&gt;Let's acknowledge a universal sysadmin/developer experience: typing &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt;&lt;/code&gt; over and over, managing long unit names.&lt;/p&gt;
&lt;p&gt;Beside, the current shell completion implementation is is quite slow, especially on thin client (for example: Raspberry Pi). I am not familiar with the shell completion, so I am not tended to improve it.&lt;/p&gt;
&lt;p&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/joehillen/sysz"&gt;⛺ joehillen/sysz&lt;/a&gt; is a TUI for systemd, which is a great inspiration that proves &lt;a class="reference external" href="https://junegunn.github.io/fzf/"&gt;fzf&lt;/a&gt; is perfect for this job: &lt;em&gt;Fuzzy completion is much more efficient than prefix completion&lt;/em&gt;. It is quite frustrating that:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;sysz is a TUI program; it is not a one-command action, you have to &lt;span class="menuselection"&gt;1. type &amp;quot;sysz&amp;quot; ‣ 2. fuzzy search service name ‣ 3. select action (start, stop, ...)&lt;/span&gt; step-by-step. If you have to start and stop service frequently (for example, when debugging), you have to repeat these steps over and over&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sysz is unmaintained since 2022 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:'(&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So I decided to build a custom set of shell functions and aliases that supercharges &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt;&lt;/code&gt; and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;journalctl&lt;/span&gt;&lt;/code&gt; with fuzzy-finding magic for my personal usage.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-vision-what-i-wanted-to-build"&gt;
&lt;h2&gt;The Vision: What I Wanted to Build&lt;/h2&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;Core Principle&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;Keep it in the shell. No new binaries, just Shell functions and aliases.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Desired Features&lt;/dt&gt;&lt;dd&gt;&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;Easy to type&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;no need to type long command name and unit name&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;Easy to repeat&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;history operations can be easily performed&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;Easy to maintain&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;just like any other programming, keep it simple and avoid repetition.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;Dual Support&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;seamlessly handle both &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;--system&lt;/span&gt;&lt;/code&gt; (sudo) and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;--user&lt;/span&gt;&lt;/code&gt; units.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;Error handling&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;print detailed information when operation failed&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;One for one&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;each operation corresponds to a command/alias, which is completion friendly constrast to subcommand&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="implementation-breaking-down-the-script"&gt;
&lt;h2&gt;Implementation: Breaking Down the Script&lt;/h2&gt;
&lt;section id="the-basics-aliases"&gt;
&lt;h3&gt;1. The Basics: Aliases&lt;/h3&gt;
&lt;p&gt;We can easily define some extremely short aliases for the long &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;journalctl&lt;/span&gt;&lt;/code&gt; commands:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sudo systemctl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sj&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;journalctl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;u&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;systemctl --user&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;uj&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;journalctl --user&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Operating on &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt;&lt;/code&gt; unit require root privilege, so a &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sudo&lt;/span&gt;&lt;/code&gt; is required.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-heart-taming-systemd-with-fzf"&gt;
&lt;h3&gt;2. The Heart: Taming Systemd with FZF&lt;/h3&gt;
&lt;p&gt;Using fzf to fuzzy complete can greatly improve the efficiency of inputting SystemD units.&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;list-units&lt;/span&gt; &lt;span class="pre"&gt;|&lt;/span&gt; &lt;span class="pre"&gt;fzf&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;The output of &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;list-units&lt;/span&gt;&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;UNIT                           LOAD   ACTIVE SUB       DESCRIPTION
&lt;/span&gt;&lt;span data-line="2"&gt;...                            ...    ...    ...       ...
&lt;/span&gt;&lt;span data-line="3"&gt;-.mount                        loaded active mounted   Root Mount
&lt;/span&gt;&lt;span data-line="4"&gt;boot.mount                     loaded active mounted   /boot
&lt;/span&gt;&lt;span data-line="5"&gt;dev-hugepages.mount            loaded active mounted   Huge Pages File System
&lt;/span&gt;&lt;span data-line="6"&gt;dev-mqueue.mount               loaded active mounted   POSIX Message Queue File System
&lt;/span&gt;&lt;span data-line="7"&gt;proc-sys-fs-binfmt_misc.mount  loaded active mounted   Arbitrary Executable File Formats File System
&lt;/span&gt;&lt;span data-line="8"&gt;run-user-1000-doc.mount        loaded active mounted   /run/user/1000/doc
&lt;/span&gt;&lt;span data-line="9"&gt;...                            ...    ...    ...       ...
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;Legend: LOAD   → Reflects whether the unit definition was properly loaded.
&lt;/span&gt;&lt;span data-line="12"&gt;        ACTIVE → The high-level unit activation state, i.e. generalization of SUB.
&lt;/span&gt;&lt;span data-line="13"&gt;        SUB    → The low-level unit activation state, values depend on unit type.
&lt;/span&gt;&lt;span data-line="14"&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;162 loaded units listed. Pass --all to see loaded but inactive units, too.
&lt;/span&gt;&lt;span data-line="16"&gt;To show all installed unit files use &amp;#39;systemctl list-unit-files&amp;#39;.
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can easily write a script like that:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-units&lt;span class="w"&gt; &lt;/span&gt;--legend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fzf&lt;span class="w"&gt; &lt;/span&gt;--accept-nth&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--no-hscroll&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;systemctl status {1}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview-window&lt;span class="o"&gt;=&lt;/span&gt;down
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--legend=false&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;can hide the trailing hints of outputs, but the column is also hidden&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--accept-nth=1&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;ask fzf only print the first column (aka the unit name) of the select row&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--preview=&amp;quot;...&lt;/span&gt; &lt;span class="pre"&gt;{1}&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;{num}&lt;/span&gt;&lt;/code&gt; syntax means pass the num&lt;sup&gt;th&lt;/sup&gt; colmun of highlighting row. We can therefore preview the service status in real-time&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;dt&gt;Merging &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-units&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-unit-files&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;As &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-units&lt;/span&gt;&lt;/code&gt; only list units currently in memory, we usually need to start from the unit that has not yet been loaded, so we also need to list all installed unit files via &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-unit-files&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-units&lt;span class="w"&gt; &lt;/span&gt;--legend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-unit-files&lt;span class="w"&gt; &lt;/span&gt;--legend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fzf&lt;span class="w"&gt; &lt;/span&gt;--accept-nth&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--no-hscroll&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;systemctl status {1}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview-window&lt;span class="o"&gt;=&lt;/span&gt;down
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;(systemctl&lt;/span&gt; &lt;span class="pre"&gt;...)&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;Use the &lt;a class="reference external" href="https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html"&gt;Process Substitution Syntax&lt;/a&gt; to merge stdout from multiple &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt;&lt;/code&gt; commands&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;dt&gt;Columnating&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;The above script doesn't work well, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-units&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;list-unit-files&lt;/span&gt;&lt;/code&gt; have different output formats: the former one has 5 columns and the latter has 3, which will mess up fzf's UI:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UNIT/FILE LOAD/STATE ACTIVE/PRESET SUB DESCRIPTION&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-units&lt;span class="w"&gt; &lt;/span&gt;--legend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-unit-files&lt;span class="w"&gt; &lt;/span&gt;--legend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;column&lt;span class="w"&gt; &lt;/span&gt;--table&lt;span class="w"&gt; &lt;/span&gt;--table-columns-limit&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/●/ /&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fzf&lt;span class="w"&gt; &lt;/span&gt;--header-lines&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--accept-nth&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--no-hscroll&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SYSTEMD_COLORS=1 systemctl status {1}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;      &lt;/span&gt;--preview-window&lt;span class="o"&gt;=&lt;/span&gt;down
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;echo&lt;/span&gt; &lt;span class="pre"&gt;'UNIT/FILE&lt;/span&gt; &lt;span class="pre"&gt;...'&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;a hardcoded table header that can tell the user the meaning of the column&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;column&lt;/span&gt; &lt;span class="pre"&gt;--table&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;column&lt;/span&gt;&lt;/code&gt; command from &lt;a class="reference external" href="https://github.com/util-linux/util-linux"&gt;util-linux&lt;/a&gt; can columnate the text and output as a table, set &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--table-columns-limit&lt;/span&gt;&lt;/code&gt; to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;5&lt;/span&gt;&lt;/code&gt; to prevent the &amp;quot;DESCRIPTION&amp;quot; column from being trimmed&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sed&lt;/span&gt; &lt;span class="pre"&gt;'s/●/&lt;/span&gt; &lt;span class="pre"&gt;/'&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;to strip the dot (&amp;quot;●&amp;quot;) unit state which breaks the colmun&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;grep&lt;/span&gt; &lt;span class="pre"&gt;.&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;to strip the empty line&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SYSTEMD_COLORS=1&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;force enabled colorful output&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;dt&gt;Reusable for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--user&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;As we want to handle both &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--system&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--user&lt;/span&gt;&lt;/code&gt; units, we can encapsulate the script to a function:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# SystemD unit selector.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;_sysls&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;WIDE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;--state=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UNIT/FILE LOAD/STATE ACTIVE/PRESET SUB DESCRIPTION&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WIDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;list-units&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$STATE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WIDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;list-unit-files&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$STATE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/●/ /&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;column&lt;span class="w"&gt; &lt;/span&gt;--table&lt;span class="w"&gt; &lt;/span&gt;--table-columns-limit&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fzf&lt;span class="w"&gt; &lt;/span&gt;--header-lines&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;          &lt;/span&gt;--accept-nth&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;          &lt;/span&gt;--no-hscroll&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;          &lt;/span&gt;--preview&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SYSTEMD_COLORS=1 systemctl &lt;/span&gt;&lt;span class="nv"&gt;$WIDE&lt;/span&gt;&lt;span class="s2"&gt; status {1}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;          &lt;/span&gt;--preview-window&lt;span class="o"&gt;=&lt;/span&gt;down
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_sysls --system&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;uls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_sysls --user&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$1&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;is &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--system&lt;/span&gt;&lt;/code&gt; or &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--user&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$2&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;is service states, see also &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;list-units&lt;/span&gt; &lt;span class="pre"&gt;--state=help&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Then we can use &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sls&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;uls&lt;/span&gt;&lt;/code&gt; to get the full service name by fuzzy matching.&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="the-complete-function"&gt;
&lt;h3&gt;3. The Complete Function&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;Error handling&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;When performing &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;start&lt;/span&gt; &lt;span class="pre"&gt;xxx.service&lt;/span&gt;&lt;/code&gt;, if the service does not start successfully, it only tell you to run &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;journalctl&lt;/span&gt; &lt;span class="pre"&gt;-xeu&lt;/span&gt;&lt;/code&gt; to see the log:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;docker.service
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;Job for docker.service failed because the control process exited with error code.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="go"&gt;See &amp;quot;systemctl status docker.service&amp;quot; and &amp;quot;journalctl -xeu docker.service&amp;quot; for details.&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In another situation, if a service immediately dies after launched, systemctl even tells you nothing:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;getty@foo
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="go"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;getty@foo
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="go"&gt;× getty@foo.service - Getty on foo&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="go"&gt;     Loaded: loaded (/usr/lib/systemd/system/getty@.service; disabled; preset: enabled)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="go"&gt;     Active: failed (Result: start-limit-hit) since Fri 2025-09-12 20:44:26 CST; 1s ago&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="go"&gt;        ...: ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="go"&gt;Sep 12 20:44:26 x1c systemd[1]: ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="go"&gt;Sep 12 20:44:26 x1c systemd[1]: Failed to start Getty on foo.&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To help users get detailed service status after launching a service, we can use the following pattern:&lt;/p&gt;
&lt;div class="highlight-shell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;s&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;foo.service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sj&lt;span class="w"&gt; &lt;/span&gt;-xeu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;A&lt;/span&gt; &lt;span class="pre"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="pre"&gt;B&lt;/span&gt; &lt;span class="pre"&gt;||&lt;/span&gt; &lt;span class="pre"&gt;C&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;if A success, performing B, else C&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$_&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;is the last argument of the previous command, in this case it is &amp;quot;foo.service&amp;quot;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;dt&gt;Repeatable&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;The key to efficient debugging is repeatability. After fuzzy-selecting and starting a service once, I should be able to simply press the &lt;kbd class="kbd docutils literal notranslate"&gt;↑&lt;/kbd&gt; arrow and &lt;kbd class="kbd docutils literal notranslate"&gt;Enter&lt;/kbd&gt; to run the exact same command again, without going through the fuzzy selection process every time:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;sstart&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s start &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;sls&lt;span class="w"&gt; &lt;/span&gt;static,disabled,failed&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; s status \$_ || sj -xeu \$_&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$BASH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;history&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$ZSH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sls&lt;/span&gt; &lt;span class="pre"&gt;static,...&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;pre-filtering services by states, services that need to be &amp;quot;start&amp;quot;-ed must not be in active state, filter by these states can reduce the number of outputs, accelerate the command to some extent &lt;sup&gt;&lt;abbr title="笔者对此断言存有疑惑，请谨慎参考"&gt;存疑&lt;/abbr&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;\$_&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;prevent the variable from being expanded before eval&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;history&lt;/span&gt; &lt;span class="pre"&gt;-s&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;print&lt;/span&gt; &lt;span class="pre"&gt;-s&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;push the command to history, facilitating subsequent repetition&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="the-magic-dynamic-function-generation"&gt;
&lt;h3&gt;4. The Magic: Dynamic Function Generation&lt;/h3&gt;
&lt;p&gt;After implementing &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sstart&lt;/span&gt;&lt;/code&gt;, we also have to implement:&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sstop&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;stop&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sre&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;restart&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ustart&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;--user&lt;/span&gt; &lt;span class="pre"&gt;start&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ustop&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;--user&lt;/span&gt; &lt;span class="pre"&gt;stop&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ure&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;--user&lt;/span&gt; &lt;span class="pre"&gt;restart&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Repeatedly implementing these functions is tedious and boring. Fortunately, we can dynamically generate them in a loop:&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;This dynamic generation approach avoids repetitive code but adds some complexity. For clarity, you could instead explicitly define each function.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nv"&gt;_SYS_ALIASES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;sstart&lt;span class="w"&gt; &lt;/span&gt;sstop&lt;span class="w"&gt; &lt;/span&gt;sre
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;ustart&lt;span class="w"&gt; &lt;/span&gt;ustop&lt;span class="w"&gt; &lt;/span&gt;ure
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nv"&gt;_SYS_CMDS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s start $(sls static,disabled,failed)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s stop $(sls running,failed)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s restart $(sls)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;u start $(uls static,disabled,failed)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;u stop $(uls running,failed)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;u restart $(uls)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;_sysexec&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;j&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;_SYS_ALIASES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;j++&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_SYS_ALIASES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_SYS_CMDS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# expand service name&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;wide&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;wide&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; status \$_ || &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;wide&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;j -xeu \$_&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# Push to history.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$BASH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;history&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$ZSH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="c1"&gt;# Generate bash function/zsh widgets.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_SYS_ALIASES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/stdin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="s"&gt;$i() {&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="s"&gt;    _sysexec $i&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="s"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;for&lt;/span&gt; &lt;span class="pre"&gt;((j=0;&lt;/span&gt; &lt;span class="pre"&gt;j&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pre"&gt;...;&lt;/span&gt; &lt;span class="pre"&gt;j++))&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;is a bash and zsh compatible &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;for&lt;/span&gt;&lt;/code&gt; loop syntax&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;_sysexec&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;a wrapper for dynamically dispatching function&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;source&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt;&lt;/code&gt;&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;a way for generating function dynamically&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="final-thoughts"&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Now you can &lt;span class="menuselection"&gt;1. type &amp;quot;sstart&amp;quot; ‣ 2. fuzzy search service name&lt;/span&gt; to start a service. If service is failed, the related logs are print automaticlly. You also can press &lt;kbd class="kbd docutils literal notranslate"&gt;↑&lt;/kbd&gt; to browse commands history to repeat the previous operation.&lt;/p&gt;
&lt;p&gt;Using this script saved me a lot of unnecessary keystrokes, just an &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;s&lt;/span&gt;&lt;/code&gt; gives me more happiness than &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt;&lt;/code&gt;. The fuzzy search algorithm of fzf is good enough that I can get the desired result in one go even with a casual keystroke. It also works well on my Raspberry Pi 3B.&lt;/p&gt;
&lt;p&gt;Feel free to grab the script from &lt;a class="reference external" href="https://github.com/SilverRainZ/dotfiles/blob/c5d1b4bd14f2b4c1dd1198d9540adb63ac23cfc1/.sh/systemd.sh"&gt;my dotfiles repository&lt;/a&gt; and adapt it to your own workflow. I'd love to hear about your own systemd productivity tricks in the comments!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2025-09-systemd-fzf-aliases.html"/>
    <summary>If you've ever found yourself repeatedly typing long systemctl commands or struggling to remember exact service names, this post is for you.</summary>
    <category term="DevOps" label="DevOps"/>
    <category term="Fzf" label="Fzf"/>
    <category term="Shell" label="Shell"/>
    <category term="Systemd" label="Systemd"/>
    <category term="Zsh" label="Zsh"/>
    <published>2025-09-12T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2024-changelog.html</id>
    <title>2024 更新日志</title>
    <updated>2025-03-02T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;p&gt;今年的时间过得飞快，总感觉 2023 还近在眼前。看朋友圈和相册的时候觉得上半年的回忆很稀薄，似乎那段时间是空白的；下半年密集发生了很多重要的事情，回想起来又觉得很陌生。&lt;/p&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;工作？不用了&lt;/h2&gt;
&lt;p&gt;今年上半年一直延续着和之前类似的工作状态，但因为熟练度上升了，工作体验也有所好转。九月一号我入职满三周年，也是劳动合同到期的日子，按说在两个月前应该有续签邮件发来，但我迟迟没有等到。七月底的时候，老板找我聊天告知我公司将不会和我续约。&lt;/p&gt;
&lt;p&gt;其实这在我的预期之内：从 &lt;a class="reference internal" href="blog/2023-changelog.html#work-sumup"&gt;&lt;span class="std std-ref"&gt;23 年的工作总结&lt;/span&gt;&lt;/a&gt; 可以看出，工作对我来说已经如同鸡肋。我开始像 &lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;被抛弃的预感&lt;/span&gt;&lt;/code&gt; 里描述的一样，强化「自己很快就要离职」的想法，在没有 deadline 的情况下做离开前的准备：不再办理任何的预付费卡、抓紧上剩下的羽毛球课、利用在职身份办港卡、办签证等等。&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id22"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-28_185721.png" src="https://silverrainz.me/_images/2025-01-28_185721.png" style="width: 80%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;一年前想着如果要离开的话，趁还在能做些什么呢？&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id23"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-28_190103.png" src="https://silverrainz.me/_images/2025-01-28_190103.png" style="width: 90%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;一年后的今天就被老板约谈了 ahhhh&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;被约谈时的心情可以用「欣喜若狂」来形容，毕竟不需要自己做决定的同时还能获得一份赔偿金（合同到期不续是 N，而非 N+1，小小失望），想要回去画画的心愿也可以实现了。现在写下这些话的时候心情反而比之前复杂一些，这也并非不可预料：辞退某种意义上是公司、团队对我的一种否定。买断了我一天中黄金时间的雇主，他们有权力强制改变我的生活状态，并且也确实这么做了。假设说我的内心有其他事物可以依靠的话，这否定尚且不能影响我的心境，问题是 &lt;em&gt;在自我的审视里，我好像已经对画画这件事情失去信念了&lt;/em&gt;。&lt;/p&gt;
&lt;section id="id3"&gt;
&lt;h3&gt;泡在名为「溢出的价值」的温水里&lt;/h3&gt;
&lt;p&gt;前司以工作强度高而著称，但平心而论我并不很忙：我牺牲上升通道换取相对轻松的工作。这已经比大部分人幸运了—— 至少我可以选择。&lt;/p&gt;
&lt;p&gt;那这三年我获得了一些什么呢？一份对我来说相当丰厚的薪水、一段在国内不差的工作经历、一点差强人意的技术进步、不算特别少的业余时间，这些我都心存感激。&lt;/p&gt;
&lt;p&gt;让我遗憾的是，明明有着一流的工作环境，优秀的员工，大规模的应用场景，为什么许多人总是在做一些没有意义，甚至愚蠢的工作？也许这是组织规模扩大的必然结果，总有有人在做有价值的事情，其他人只是被公司溢出的价值浸泡着的青蛙—— 尽管这并不是公司的本意。&lt;/p&gt;
&lt;p&gt;在经济下行的大背景下，大家已经不谈什么理想了，「溢出的价值」短时间内还不会消失，但增量吃习惯了，原地踏步就是罪过。焦虑开始弥漫：表面上所有员工都遵循公司规定的价值观行事，事实上大家都只为自己利益的来源负责，基层的工作用来缓解上层的焦虑，上层的工作再用来缓解更上一层的焦虑……&lt;/p&gt;
&lt;p&gt;写完我发现我还是太幼稚了，年景不好就别谈理想了。工作，是用来赚钱的。&lt;em&gt;前司，谢谢你给我赚钱的机会，现在不能赚了，也谢谢你给我自由&lt;/em&gt;。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h3&gt;来日后会相予期，去去莫迟疑&lt;/h3&gt;
&lt;p&gt;老板明面上还是给了转岗的机会，但我自然不想转。在确定离职之后，我开始做准备。工作以外的部分是：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;写了一篇离职文档，在离开前做一些自我展示。以前不敢多要的虚荣，现在一次性吃下&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;和内部认识的一些朋友加微信保持联系&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;以前在公司偶尔会收到搭讪，因为不方便所以都显得很冷淡，现在一一回应一下：虽然不是特别体面，但我有这个自由&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;勇敢约陌生人吃饭：也许能有一些新思路呢&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;聚虽好，别虽悲，世事堪玩味&lt;/div&gt;
&lt;div class="line"&gt;来日后会相予期，&lt;em&gt;去去莫迟疑&lt;/em&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这是 &lt;a class="reference internal" href="p/lyscores/index.html#songbie"&gt;&lt;span class="std std-ref"&gt;送别&lt;/span&gt;&lt;/a&gt; 歌词的一个版本，最后一句在我入职的时候就用来当公司内部系统的密码，用来当离职文档的标题再合适不过。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="the-day-after-last-day"&gt;
&lt;h2&gt;The day after last day&lt;/h2&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;再见杭州&lt;/h3&gt;
&lt;p&gt;系统上的 Last day 是 8.31，但从 16 号开始我就不再需要去公司了。我订了 9.12 回家的机票，在这期间我开始处理一些离开杭州相关的事务：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;断舍离：卖掉带不走的大件、送出对自己没价值的东西、扔掉没人要的东西&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;收拾行李：一部分寄往燕郊画室，一部分寄回广东老家&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;练球：把大柳的羽毛球课上完，偶尔也去阿里西溪 B 区打夜场&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;看病：趁着医保和商保还在把需要看的都看了，算是把医保套现&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h3&gt;肺炎夺走的是什么？&lt;/h3&gt;
&lt;p&gt;回到家后，我筹划着和家里人一起出去旅游。我自己对旅游有一些恐惧，按流行的话说是一些东亚小孩长大后的后遗症，但爸妈年纪大了，以后这样的机会肯定越来越少了。正好阿姐也赋闲在家，规划了一番后我们决定去桂林玩五天，很可惜对我来说是噩梦的开始。&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;第一天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;在去桂林的高铁上我就开始感到不适，到了酒店开始发烧 39.5°C、咳嗽&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;第二天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;一大早去桂林人民医院看病，开了抗菌药，无效&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;第三天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;去阳朔医院接着看，开了抗病毒药，无效&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;第四天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;家里人决定提前返回，回深圳看病，在社区医院查出了支原体，吃特效药阿奇霉素—— 以为事情到这里就只剩下吃药了&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;第五～七天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;在深圳呆了两天后返回老家，阿奇吃完一个流程后依然没有退烧&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;第八天&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;去区里的私立医院拍了 CT，这下知道为什么阿奇霉素没用了：已经转成了肺炎。于是当场住院，阿妈从家里收拾了住院的东西过来。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;虽说是肺炎，但也没有到重症的程度，只需要每天吸氧、打点滴和雾化吸入药物。阿爸阿妈一直陪护，生活上也没有什么不便。在这个过程里我都是迷迷糊糊的，所以肉体上也谈不上痛苦，让人感到恐惧的也许只是安全感和信念的流失。&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-2 sd-row-cols-xs-2 sd-row-cols-sm-4 sd-row-cols-md-4 sd-row-cols-lg-4 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id24"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-07_223509.png" src="https://silverrainz.me/_images/2025-02-07_223509.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;桂林的好山水，可惜无福消受&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id25"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-07_223617.png" src="https://silverrainz.me/_images/2025-02-07_223617.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;病床上写 &lt;a class="reference internal" href="p/how-sphinx-default-role-works.html"&gt;&lt;span class="doc"&gt;How Sphinx Default Role Works&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id26"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-07_231233.png" src="https://silverrainz.me/_images/2025-02-07_231233.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;病房里的写生&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id27"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-07_231141.png" src="https://silverrainz.me/_images/2025-02-07_231141.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;左肺在迷雾中&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;失业引发的焦虑在这时候才体现出来：住院每天要花一千出头，而如果我有职工医保的话，80% 费用都可以报销。更让人恐惧的是：我失去了稳定的现金收入，而这样躺着就要花钱的日子说来就来了。我知道失业了就是会有这样的风险，也知道自己的存款足以应付这场病，但危机真的摆在眼前的时候，我还是会害怕，想要去画画的心也开始动摇。&lt;/p&gt;
&lt;p&gt;原定国庆出发去燕郊，出院时已经是 10 月 6 号。恰逢入冬，我怕我脆弱的肺承受不住北方的严寒和画室的松节油，动身的时间推迟到了十一月。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;失去信念的人，举起画笔&lt;/h2&gt;
&lt;p&gt;和四年前辞职画画（&lt;span class="xref std std-doc"&gt;./new-boy&lt;/span&gt;）的心情不同，我不再满怀期待，反而心中有很多忧虑。出发之前我给 &lt;a class="any any-people reference internal" href="about/people.html#people-0" title="people 晓飞老师"&gt;&lt;a href="#report-11"&gt;&lt;span class="problematic" id="problematic-11"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-11"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-11"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 发了长长的消息：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;老师，我大概定下 11.4 号去画室。之前应该还没跟您说，我现在没在工作了了，所以这次打算学长期一点。&lt;/p&gt;
&lt;p&gt;这几年里小创作画得确实很少，但几次自我怀疑之后我发现我总是还能画出东西来，但让我更痛苦的是我还是我的技术不止没有长进，更是一直在慢慢的退步，在我看来已经不够支持我画创作了，我有时候会有点子想画画，但又畏惧复杂的东西，在失去了这个点子的同时我又失去了一次练手的机会，我又几乎不做其他练习，于是两者互相促进，我感觉我的想法慢慢开始枯竭，手也特别生疏，没法再继续画画了（虽然如此，还是也会逼着自己画小创作，只是很烂）。&lt;/p&gt;
&lt;p&gt;老师，所以我这次的打算是：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;把去年的 &lt;a class="reference internal" href="notes/zxsys/color.html"&gt;&lt;span class="doc"&gt;色彩训练&lt;/span&gt;&lt;/a&gt; 课程上完&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;画点素描，把光影和造型再找回来&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我现在脑子里只剩下一些概念了，手和眼睛都是笨的。当然这个过程里创作也不会停，在画室手应该不会生。最后，我想试着把小创作转化成作品，我觉得只是把一个点子画出来，好像不算完整的创作，只是像在做梦而已。我自己好像没法完成完整的作品，在之前创作课，我在 &lt;a class="reference internal" href="notes/zxsys/way-to-artist/find-language.html"&gt;&lt;span class="doc"&gt;找语言&lt;/span&gt;&lt;/a&gt; 那里卡了很久，觉得自己不懂其他材料，迟迟下不了笔，心理负担很大，实在有愧于老师的教导。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;总结起来就是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;我丧失了曾经「掌握」的写实技术，无法自主地在技术上进步，&lt;em&gt;畏惧画面上的复杂度&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;创作一直停留在灵感阶段，&lt;em&gt;不知道如何将创作转化为更完整的作品&lt;/em&gt;，导致创作的热情减退&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这甚至是我的忧虑里积极的一面：因为失去了所以想要取回，因为遇到瓶颈所以要寻求帮助。那么，没有说出来的是什么呢？其实前面已经提到了：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;在自我的审视里，我好像已经对画画这件事情失去信念了。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;在对造型的理解更多之后，我开始觉得架上绘画是过时的、要被淘汰的技术，&lt;em&gt;潜意识里不再愿意为它付出努力了&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我习惯于用负面情绪画创作，但我 &lt;em&gt;不想为了创作咀嚼甚至创造痛苦&lt;/em&gt;，我害怕自己越陷越深。如果我要坚持画画，我是否就没法成为一个幸福的人呢？假如有一天我成为一个幸福的人，画画又会出现在我人生中的什么位置呢？&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些忧虑并没有阻止我回画室的进程，我总要回去做点什么：要不把这些忧虑解开，要不亲手把画画杀死。&lt;/p&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;到目前为止，这些忧虑也一个都没有解决。当然，画画也没有被杀死。&lt;/p&gt;
&lt;/div&gt;
&lt;section id="id8"&gt;
&lt;h3&gt;造型：遗忘、拖沓和平淡的获得&lt;/h3&gt;
&lt;p&gt;回到画室的我，其实憋着一股劲：只要天天上课，失去的技术就会顺利成章地再次回来，对吧？！我同时付出了 &lt;a class="reference internal" href="blog/resign-for-painting.html#id4"&gt;&lt;span class="std std-ref"&gt;努力与选择&lt;/span&gt;&lt;/a&gt;，我还不配获得这些吗？&lt;/p&gt;
&lt;p&gt;好可惜，我心里似乎有什么东西在阻止我学会。前两个月我努力地天天上课，但眼睛是模糊的，脑子是迟钝的，看不到斑驳的石膏上有哪些凸起的 &lt;a class="any any-term reference internal" href="notes/zxsys/modeling.html#term-bacd3b5" title="term 形体"&gt;&lt;a href="#report-10"&gt;&lt;span class="problematic" id="problematic-10"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-10"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-10"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，也想象不出来在纸面上它们应该如何 &lt;a class="reference internal" href="notes/zxsys/modeling.html#id10"&gt;&lt;span class="std std-ref"&gt;对应和对称&lt;/span&gt;&lt;/a&gt;。老师的指点听过了就忘，又或者每一句话都记住了，但不知道如何用上。我画画的速度也非常慢，经常擦了改改了擦，或者磨蹭半天不知道如何下笔，慢到了令人发指的程度。愚笨和迟缓纠结在一起，这样的日子一直持续了一个多月。这期间我画了两张四开的石膏，在第二张结尾的时候总算有一些进步：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-1 sd-row-cols-xs-1 sd-row-cols-sm-2 sd-row-cols-md-2 sd-row-cols-lg-2 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;万幸，我没有把所有东西都忘掉，但我的感受是含糊的。我到底是掌握了熟练度，还是掌握了造型的知识？我时常会质疑自己在画 &lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;高乃依像&lt;/span&gt;&lt;/code&gt; 的时候，是真正理解了造型还是只是在老师的步步搀扶下「突破」了自我？之前的笔记并不能帮我画出一样的画，除了文字化的知识，我还欠缺了关键的、未知的什么东西。&lt;/p&gt;
&lt;p&gt;12 月下旬，我开始画半开的摩西像。没能再和以前一样顿悟，我拖沓又笨拙地取回关键的东西：仅凭知识是无法作画的，需要配合正确的观察方法才能在纸上实践。而何谓「正确的观察方法」，这又是难以言传的，我在这里尽力记录，希望以后不要再忘记：&lt;/p&gt;
&lt;dl class="any term"&gt;
&lt;dt class="sig sig-object any" id="term-e867ad9"&gt;
&lt;span class="sig-name descname"&gt;&lt;span class="pre"&gt;形体的观察方法&lt;/span&gt;&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;dl&gt;
&lt;dt&gt;目的&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;搞清楚 &lt;a class="any any-term reference internal" href="notes/zxsys/modeling.html#term-bacd3b5" title="term 形体"&gt;&lt;a href="#report-9"&gt;&lt;span class="problematic" id="problematic-9"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-9"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-9"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 边界在哪里，由几个面组成，每个面的形状如何。&lt;/p&gt;
&lt;div class="admonition warning"&gt;
&lt;p class="admonition-title"&gt;警告&lt;/p&gt;
&lt;p&gt;不搞清楚这些问题而画出来的形体，只是通过经验或者模仿产生，是油滑或者虚伪的&lt;/p&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;要利用多年来日常生活的视觉经验去感受空间，感受形体的饱满度。反之，拒绝死盯着一点看的片面观察方法。
在看不清形体的时候要穷尽手段去观察，看不清的情况可能有：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;距离太远：靠近看、拍照片放大&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;角度存在错觉或盲区：多角度观看、&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;石膏脏污：拿刷子扫去浮灰、上手触摸&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;物象结构复杂、特征不明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;先画确定的部分：先画更大的形体、再画大形体中清晰的小形体、最后画（or 放弃）含糊的小形体&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;该物象需要拆分成更好理解的多个形体，&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;观察同类型形体的共性：对于石膏像写生，可以看其他大师的雕像同部位&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;从其他途径学习其 &lt;code class="xref any any-term docutils literal notranslate"&gt;&lt;span class="pre"&gt;内部构造&lt;/span&gt;&lt;/code&gt; （解剖知识）&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;dl&gt;
&lt;dt&gt;形体的边界&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;形体的边界要通过感受物象的凸起获得，或者反过来说，观察低点。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;面的形状&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;面的形状是通过感受形体的特征得到的，而非盯着形体尝试看出面的边界。&lt;/p&gt;
&lt;p&gt;最机械的特征可以是：「这个形体像什么标准的几何体」，假如形体像一个椎体，那么组成该形体的面一定是三角形的。在自然物象中经常出现的几何体：椎体、柱体、方体、圆球、椭圆、梭形&lt;/p&gt;
&lt;p&gt;特征也可以用清晰的语言描述：这个形体是 一边大一边小/两边大中间小/中间大两边小，由此可推测出面的形状。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;务必明确面的形状后再下笔。当形状难以确定的时候，可参见「物象结构复杂、特征不明显」的处理方法。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;在画比较大的形体的时候，组成形体的面不一定是物理上存在的，而是多个更小的形体组合的虚拟的面，需要主动去归纳（归纳 != 概括）。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;figure class="align-default" id="id28"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-21_160441.png" src="https://silverrainz.me/_images/2025-02-21_160441.png" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="any any-artwork reference internal" href="notes/zxsys/modeling.html#artwork-m-006" title="artwork m-006"&gt;&lt;a href="#report-8"&gt;&lt;span class="problematic" id="problematic-8"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-8"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-8"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; （未完成）&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;我现在确信，自己之前并没有掌握正确的造型知识。我不知道这次有没有，应该更接近一些了吧。也许因为是抱着「取回失物」的心态而来，也可能是因为对画画失去了信念，获得这些知识时我并没有觉得快乐，只是感觉心头有一个疙瘩被稍稍解开。&lt;/p&gt;
&lt;div class="admonition-todo admonition" id="id9"&gt;
&lt;p class="admonition-title"&gt;待处理&lt;/p&gt;
&lt;p&gt;更新形体笔记&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id10"&gt;
&lt;h3&gt;创作：叔本华的钟摆&lt;/h3&gt;
&lt;p&gt;今年大概画了 &lt;a class="any any-artwork reference internal" href="any-artwork.date%2Bby-year.html#cap-2024 年" title="artwork 2024"&gt;&lt;code class="xref any any-artwork.date+by-year docutils literal notranslate"&gt;&lt;span class="pre"&gt;60+&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; 张小创作，上班时画的和来燕郊后画的各占一半。如前面提到的，我本不太担心自己画不出来，只要我在生活，就总是能画出东西来。但在平淡生活里画出来的东西确实如同清汤寡水，痛苦太剧烈又会让自己失去行动力。当下有轻微的真切的痛苦，而稍远处是巨大的绝望，这似乎是最适合创作的生活状态。&lt;/p&gt;
&lt;p&gt;可是有谁会喜欢这样的生活呢？为了创作追求这样的生活，也是一种不真诚吧。我需要和上天祈祷赐予我不幸福的生活吗？&lt;/p&gt;
&lt;p&gt;下面几张画是上班期间比较满意的部分：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-1 sd-row-cols-xs-1 sd-row-cols-sm-2 sd-row-cols-md-4 sd-row-cols-lg-4 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id29"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_130244.png" src="https://silverrainz.me/_images/2025-03-02_130244.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;日记&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id30"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_134817.png" src="https://silverrainz.me/_images/2025-03-02_134817.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;树&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id31"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_120217.png" src="https://silverrainz.me/_images/2025-03-02_120217.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;等&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id32"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_121024.png" src="https://silverrainz.me/_images/2025-03-02_121024.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;跳龙门&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这是来燕郊后的部分：&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 249)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;data:template&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Trying &amp;quot;data:template&amp;quot; as canonical directive name.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/3 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 249)&lt;/p&gt;
&lt;p&gt;Unknown directive type &amp;quot;data:template&amp;quot;.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;   &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;      &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;artwork&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;         &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_assets&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;aw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;{{ id }}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;{{ name }}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 260)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;data:schema&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Trying &amp;quot;data:schema&amp;quot; as canonical directive name.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/3 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 260)&lt;/p&gt;
&lt;p&gt;Unknown directive type &amp;quot;data:schema&amp;quot;.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-1 sd-row-cols-xs-1 sd-row-cols-sm-2 sd-row-cols-md-5 sd-row-cols-lg-5 docutils"&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 266)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;data:def&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Trying &amp;quot;data:def&amp;quot; as canonical directive name.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/3 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 266)&lt;/p&gt;
&lt;p&gt;Unknown directive type &amp;quot;data:def&amp;quot;.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;008&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;012&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;013&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;016&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;021&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;022&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;023&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;025&lt;/span&gt; &lt;span class="n"&gt;bflv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;028&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以明显看到来燕郊后的画更稳定地有意思一点儿，一方面上班挤占了我大部分的精力，另一方面在燕郊的生活有了些插曲，为我带来了多样的情绪。嗯，我&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;又&lt;/span&gt;谈恋爱了。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id11"&gt;
&lt;h2&gt;那个让我放下笔的人&lt;/h2&gt;
&lt;section id="id12"&gt;
&lt;h3&gt;《有星星和微风的夜晚》的预言之子&lt;/h3&gt;
&lt;p&gt;21 年我离开画室，入职前司。彼时还未完全从上一段感情带给我的痛苦里完全 &lt;a class="any any-artwork reference internal" href="notes/zxsys/way-to-artist/find-topic.html#artwork-xfczk2-017" title="artwork 漫长的剥离"&gt;&lt;a href="#report-7"&gt;&lt;span class="problematic" id="problematic-7"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-7"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-7"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 出来，同时也对自己在异性眼里的「价值」充满怀疑。我需要一些拥抱用来敷在伤口上，但不受欢迎的人去哪里获得这些呢？梦里。&lt;/p&gt;
&lt;p&gt;网易云有一个「一起听」的功能，会按红心歌曲匹配两个陌生人，双方的面容和身形被一个面具素材盖住，若是尽力展示谈吐，倒也能获得一些陌生人的善意。可这有什么用呢？陌生人的善意轻飘飘的，我不想要这样的东西，我想做一个含糊又浪漫的梦。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;src/blog/2024-changelog-dynamic-story.txt&lt;/span&gt;, line 1)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;sup&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;sup&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;是一个有星星的夜晚，窗户敞开着，窗帘在微风下轻轻摆动。A 蜷缩在被子里 &lt;sup&gt;1&lt;/sup&gt;，手机里的网易云对面的那个人是谁呢？&lt;sup&gt;2&lt;/sup&gt; 她的善意是真实存在的吗？1853 公里外发来的文本还有余温，仔细闻闻还有淡淡的香气。&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;「&lt;/div&gt;
&lt;div class="line-block"&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;我想不太可能吧，&lt;/div&gt;
&lt;div class="line"&gt;怎么会有人对这样的我投以善意呢？&lt;/div&gt;
&lt;div class="line"&gt;…&lt;/div&gt;
&lt;div class="line"&gt;…&lt;/div&gt;
&lt;div class="line"&gt;…&lt;/div&gt;
&lt;div class="line"&gt;要是真的就好了…&lt;/div&gt;
&lt;/div&gt;
&lt;div class="line"&gt;」&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 14)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;raw&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;raw&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;眼泪偷偷从 A 的眼角里滑落，&lt;span class="distance-number"&gt;1853&lt;/span&gt; 公里这个数字好像开始闪烁，A 耳边传来呼呼的风声，窗户也开始摇晃，他起身来跪坐在床上。&lt;/p&gt;

&lt;button id="dreamBtn"&gt;梦！&lt;/button&gt;

&lt;p class="typewriter"&gt;&lt;/p&gt;

&lt;p class="hide-content" style="display: none"&gt;于是 A 张开了双手…  &lt;sup&gt;3&lt;/sup&gt; 抱住了从天而降的少女。&lt;sup&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;script&gt;
const btn = document.querySelector('#dreamBtn');
btn.addEventListener('click', () =&gt; {
  // 获取目标数字元素
  const numberElement = document.querySelector('.distance-number');
  const hiddenContent = document.querySelector('.hide-content');
  const typewriter = document.querySelector('.typewriter');
  const cutsceneText = "数字越来越小，越来越小…窗外不远处的似乎有什么动静…";

  let currentNumber = parseInt(numberElement.textContent);
  const duration = 10000; // 10秒
  const startTime = Date.now();
  let isTypingStarted = false; // 防止重复触发

  // 数字递减动画
  const animate = () =&gt; {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const remaining = duration - elapsed;

    // 计算当前数值并更新
    const targetNumber = Math.max(0, Math.floor(1853 - (1853 * progress)));
    numberElement.textContent = targetNumber;

    // 触发逐字动画（剩余3秒时启动）
    if (remaining &lt;= 3000 &amp;&amp; !isTypingStarted) {
      startTypewriter();
      isTypingStarted = true;
    }

    // 保持动画直到结束
    if (progress &lt; 1) {
      requestAnimationFrame(animate);
    } else {
      numberElement.textContent = '0'; // 确保最终归零
      hiddenContent.style.display = 'block';
    }
  };

const startTypewriter = () =&gt; {
    // 动态创建字符节点实现更精准控制
    let index = 0;
    typewriter.style.display = 'block';

    const typeInterval = setInterval(() =&gt; {
      if (index &gt;= cutsceneText.length) {
        clearInterval(typeInterval);
        typewriter.classList.add('typing'); // 启动CSS动画收尾
        return;
      }
      typewriter.textContent += cutsceneText[index];
      index++;
    }, 80); // 通过调整间隔(ms)控制打字速度

    // 同步剩余时间自动加速
    const speedBoost = remaining =&gt; {
      if (remaining &lt; 1000) {
        clearInterval(typeInterval);
        typewriter.textContent = cutsceneText; // 强制完成
      } else if (remaining &lt; 1853) {
        clearInterval(typeInterval);
        typeInterval = setInterval(/* 更快的间隔 */);
      }
    }
  };

  requestAnimationFrame(animate);
});
&lt;/script&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;两年后，这个故事真实发生了，这个少女是 &lt;a class="any any-people reference internal" href="about/people.html#people-Swan" title="people Swan"&gt;&lt;a href="#report-6"&gt;&lt;span class="problematic" id="problematic-6"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-6"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-6"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;。&lt;/p&gt;
&lt;iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&amp;id=1823210550&amp;auto=0&amp;height=66" style="display:block;  margin: auto;"&gt;&lt;/iframe&gt;&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-3 sd-row-cols-xs-3 sd-row-cols-sm-3 sd-row-cols-md-3 sd-row-cols-lg-3 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-03_131147.png" src="https://silverrainz.me/_images/2025-03-03_131147.png" /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-03_131156.png" src="https://silverrainz.me/_images/2025-03-03_131156.png" /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-03_131202.png" src="https://silverrainz.me/_images/2025-03-03_131202.png" /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id13"&gt;
&lt;h3&gt;几个亮晶晶的问号和一撮毛茸茸的阳光&lt;/h3&gt;
&lt;p&gt;Swan 是我的前同事。22 年我还保留着画小创作的惯性，在画画方面也尚且留有最后一点自信。偶尔会大胆地拿自信去换取虚荣，具体方式就是在内网发自己的画并且等待一些赞扬，也因此认识了不少朋友。Swan 是其中的一位，她告诉我她特别喜欢我在西溪北苑画的《蓝色失眠》：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;从飞书里有限的沟通我知道她 base 北京，是一个干练的产品经理，很手巧会钩针编织，热爱旅游会在世界各地潜水，符合我对光鲜亮丽的大厂人的美好生活的想象。八月的时候我在内网发离职文档，彼此交换了微信，并约好在北京有空吃个饭，算是建立了联系。&lt;/p&gt;
&lt;p&gt;后面的联系越来越多，有日常的闲聊也偶有交心的谈话。我是一个情感上混乱又迟钝的人，很难在短时间内上建立一个人的形象，在认识 Swan 一段时间后，我反而更加迷惑了，她是什么样的人呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;是鸟群里飞得最快的海鸥？地球只是她的游乐场，临时起意的一个夜里就能从挪威西南部飞到英国的东海岸。努力振翅，再有一个多月的时间就能从北京飞到旧金山。好可惜，太平洋的水是咸的。&lt;/p&gt;
&lt;p&gt;是一头站在路边的小熊？身上每一撮毛都有阳光的味道。它会对我展现出不知道来由的友好，好像我是什么样的人都好，好像很难有什么事情能动摇她的内心，但她的拥抱依然温暖又柔软。&lt;/p&gt;
&lt;p&gt;可能她还是一朵孤零零开的小花？有点营养不良。在某个晚上无风也无雨，她只是突然想要凋落，便自己凋落了。&lt;/p&gt;
&lt;p&gt;可能她就是我，敏感内敛又不稳定，拥有相似的脑回路，奇怪的知识和一点点外人会羡慕的特长。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;我不知道，我不知道，但我很在意，这个人越靠越近，她身上贴着的问号也越来越挤满我的视野。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id14"&gt;
&lt;h3&gt;局促又绵长的第一天&lt;/h3&gt;
&lt;p&gt;我开始变得柔软，全身的肌肉失去力气，视线开始模糊，脑袋也得昏昏沉沉。颤抖的双手不敢撕下面前的问号，双腿依然在往那边迈去。每天画素描的时候完全不在状态，我回忆起一些恐惧：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;恐惧让我心生犹豫，但我的预感又告诉我，这一天还是会到来：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;我想她不是海鸥也不是我，她是一头孤零零的小熊吧。&lt;/p&gt;
&lt;p&gt;Swan 说，&lt;em&gt;这张画作为小创作过于直白，作为表白又过于含蓄&lt;/em&gt;，我深以为然。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id15"&gt;
&lt;h3&gt;放下笔的日子&lt;/h3&gt;
&lt;p&gt;尽管嘴上说着画画比她重要，实际上还是把很多本该画画的时间匀给了谈恋爱。画室的课程至今进行了近四个月，其中只有 69 天在上课，可以看到从 12 月 5 日的那个周末起，这位滴答清单用户的心就不安分了：&lt;/p&gt;
&lt;figure class="align-default" id="id33"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-02-21_173525.png" src="https://silverrainz.me/_images/2025-02-21_173525.png" style="width: 40%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;滴答清单的打卡数据&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;因为北京和燕郊距离还是比较远，只能尽力创造见面的机会，有时候我进城，更多的时候是辛苦她下乡。进城的大多是去 798 看展，下乡则是逛菜市场合作做饭。&lt;/p&gt;
&lt;p&gt;看展，主要是老师布置的任务：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-1 sd-row-cols-xs-1 sd-row-cols-sm-2 sd-row-cols-md-4 sd-row-cols-lg-4 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id34"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_223841.png" src="https://silverrainz.me/_images/2025-03-02_223841.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="any any-artist reference internal" href="p/artistory/index.html#artist-d1da2be" title="artist 冷广敏"&gt;&lt;a href="#report-5"&gt;&lt;span class="problematic" id="problematic-5"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-5"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-5"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 作品&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id35"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_223945.png" src="https://silverrainz.me/_images/2025-03-02_223945.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artist docutils literal notranslate"&gt;&lt;span class="pre"&gt;向帅&lt;/span&gt;&lt;/code&gt; 作品&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id36"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_223926.png" src="https://silverrainz.me/_images/2025-03-02_223926.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;code class="xref any any-artist docutils literal notranslate"&gt;&lt;span class="pre"&gt;图伊曼斯&lt;/span&gt;&lt;/code&gt; 作品&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id37"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_224008.png" src="https://silverrainz.me/_images/2025-03-02_224008.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="any any-people reference internal" href="about/people.html#people-6" title="people 胡林昊"&gt;&lt;a href="#report-4"&gt;&lt;span class="problematic" id="problematic-4"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-4"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-4"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 作品&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;做饭，尽是一些自己根本不可能做的大菜：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-1 sd-row-cols-xs-1 sd-row-cols-sm-2 sd-row-cols-md-4 sd-row-cols-lg-4 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id38"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_220145.png" src="https://silverrainz.me/_images/2025-03-02_220145.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;精心堆料的红烧牛肉面&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id39"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_220240.png" src="https://silverrainz.me/_images/2025-03-02_220240.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;南北通力包饺子&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id40"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_220224.png" src="https://silverrainz.me/_images/2025-03-02_220224.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;备菜巨麻烦的虾枣&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;俩人连轴转了一下午。唯一的优点当然是好吃啦&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id41"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-03-02_220253.png" src="https://silverrainz.me/_images/2025-03-02_220253.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;妹妹的爱心早餐，凑合吃吧&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;从 &lt;a class="any any-artwork reference internal" href="any-artwork.date%2Bby-year.html#cap-2024 年" title="artwork 2024"&gt;&lt;code class="xref any any-artwork.date+by-year docutils literal notranslate"&gt;&lt;span class="pre"&gt;2024&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; 也可以看到，12 月中旬后我就再没画什么画了，因为「当下有轻微的真切的痛苦，而稍远处是巨大的绝望」的生活状态被打破了。我假象的困境出现了：我有机会成为，或者已经是一个幸福的人了，那我还能依靠什么画画呢？这个问题到现在还没有答案。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id16"&gt;
&lt;h2&gt;巨变之下的其他生活&lt;/h2&gt;
&lt;p&gt;除了上面聊到的重要事件，其他的生活也依然在继续着。&lt;/p&gt;
&lt;section id="id17"&gt;
&lt;h3&gt;开源&lt;/h3&gt;
&lt;p&gt;今年写的开源代码显著变少了，基本也都是 Sphinx 和 reStructuredText 衍生的项目：&lt;/p&gt;
&lt;section id="id18"&gt;
&lt;h4&gt;社区贡献&lt;/h4&gt;
&lt;p&gt;也许这部分的贡献会让这个世界变得更好吧？至少是有人在用的东西。今年希望能多多地帮 Sphinx 写代码，也许能成为 maintainer 呢？&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;为了加快 &lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinx-notes/pages"&gt;⛺ sphinx-notes/pages&lt;/a&gt; 的构建速度去改了 actions/upload-pages-artifact：&lt;a class="reference external" href="https://github.com/actions/upload-pages-artifact/pull/94"&gt;Group tar's output to prevent it from messing up action logs by SilverRainZ · Pull Request #94 · actions/upload-pages-artifact&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给 Sphinx 交了三个 PR，只有一个是有意义的 fix：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/sphinx-doc/sphinx/pull/12514"&gt;intersphinx: Handle the case where intersphinx_cache_limit is negative by SilverRainZ · Pull Request #12514 · sphinx-doc/sphinx&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/sphinx-doc/sphinx/pull/12804"&gt;Fix docstring of index domain by SilverRainZ · Pull Request #12804 · sphinx-doc/sphinx&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/sphinx-doc/sphinx/pull/12820"&gt;Document sphinx.domains.IndexEntry by SilverRainZ · Pull Request #12820 · sphinx-doc/sphinx&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改善了一下 TreeSitter 的 reStructuredText parser，对于 parser generator 一直一知半解，都是一半猜一半写：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;识别 reStructuredText 中的非 ASCII （主要是 CJK 的）标点符号：&lt;a class="reference external" href="https://github.com/stsewd/tree-sitter-rst/pull/54"&gt;Recognize non-ASCII punctuation chars by SilverRainZ · Pull Request #54 · stsewd/tree-sitter-rst&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;识别一些流行 Sphinx 扩展里的 directives：&lt;a class="reference external" href="https://github.com/stsewd/sphinx.nvim/pull/21"&gt;Add queries for sphinxnotes-strike and sphinx-design by SilverRainZ · Pull Request #21 · stsewd/sphinx.nvim&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;修正对标题的捕获：&lt;a class="reference external" href="https://github.com/nvim-treesitter/nvim-treesitter/pull/7302"&gt;fix(rst): adornment should be captured as &amp;#64;markup.heading by SilverRainZ · Pull Request #7302 · nvim-treesitter/nvim-treesitter&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="sphinx-notes"&gt;
&lt;h4&gt;Sphinx Notes 过家家&lt;/h4&gt;
&lt;p&gt;这些项目都过于小众，很难让人不觉得代码开源是为了方便我自己访问。&lt;/p&gt;
&lt;p&gt;今年写了两个新项目：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-comboroles"&gt;📦 sphinxnotes-comboroles&lt;/a&gt;：通过现有的 reStructuredText role 合成新的 role&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;弥补了 reStructuredText 不支持 nested markup 的缺陷。已经写了一篇文章来介绍它的原理：&lt;span class="xref std std-doc"&gt;sphinxnotes-comboroles&lt;/span&gt;。&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`:literal:`bold&lt;/span&gt; &lt;span class="pre"&gt;code``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;:literal:`bold code`&lt;/strong&gt;&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-changelog.rst&lt;/span&gt;, line 476)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;strong&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;strong&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong_literal:`bold&lt;/span&gt; &lt;span class="pre"&gt;code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;bold&lt;/span&gt; &lt;span class="pre"&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-fasthtml"&gt;📦 sphinxnotes-fasthtml&lt;/a&gt;：快速的增量构建&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;尽管 Sphinx 支持增量构建，但我的笔记过于庞大了，标准的增量构建都需要十几秒，配合 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinx-autobuild"&gt;📦 sphinx-autobuild&lt;/a&gt; 实时预览时体验很差。
实际上实时预览仅关注正在修改的单个页面，而并不关注文档整体的正确性。&lt;/p&gt;
&lt;p&gt;Sphinx 的增量构建会做额外的很多事情：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;在修改配置（&lt;code class="file docutils literal notranslate"&gt;&lt;span class="pre"&gt;conf.py&lt;/span&gt;&lt;/code&gt;）时会 fallback 到全量构建&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;根据情况需要额外：更新 toctree、构建 always-reread 的文档、生成 additional pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;索引（Index）不支持增量构建&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;其他的正确性检查&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;fasthtml 则根据实时预览的需求做了激进的优化，基本做法就是 hook 掉了 &lt;a class="reference internal" href="notes/man/sphinx/how-sphinx-builder-works.html"&gt;&lt;span class="doc"&gt;Sphinx HTML builder&lt;/span&gt;&lt;/a&gt; 里耗时的部分，因此可能对未来的 Sphinx 大版本有兼容性问题，也就没有发 stable release。&lt;/p&gt;
&lt;p&gt;用 fasthtml 构建 Sphinx 自己的文档，能比标准的增量构建快 0.6 秒左右（在我自己的笔记系统会快大概 10 秒）：&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id42"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://github.com/sphinx-notes/fasthtml/blob/master/utils/bench.sh"&gt;https://github.com/sphinx-notes/fasthtml/blob/master/utils/bench.sh&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;Python&lt;/span&gt; &lt;span class="mf"&gt;3.13.1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;Sphinx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.3.7&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="n"&gt;sphinxnotes&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fasthtml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="n"&gt;b1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Standard&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="hll"&gt;&lt;span class="n"&gt;real&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="mf"&gt;.590&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="n"&gt;user&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="mf"&gt;.519&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="n"&gt;sys&lt;/span&gt;     &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="mf"&gt;.067&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Fast&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="hll"&gt;&lt;span class="n"&gt;real&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="mf"&gt;.996&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="n"&gt;user&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="mf"&gt;.918&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="n"&gt;sys&lt;/span&gt;     &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="mf"&gt;.073&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;今年还重构了两个我自己重度使用的项目：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-any"&gt;📦 sphinxnotes-any&lt;/a&gt;：生成 reStructuredText directives 用来创建对象，并且可以用 role 引用它&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;今年加强了索引功能，在支持了日期索引和路径索引，现在可以：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;按时间顺序来浏览我的画：&lt;a class="reference internal" href="any-artwork.date%2Bby-year.html"&gt;&lt;span class="std std-ref"&gt;Artwork Date Reference Index by Year&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;按系列来浏览我的画：&lt;a class="reference internal" href="any-artwork.id%2Bby-hyphen.html"&gt;&lt;span class="std std-ref"&gt;Artwork Id Reference Index by Hyphen&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-snippet"&gt;📦 sphinxnotes-snippet&lt;/a&gt;：从命令行快速访问 Sphinx 文档&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;因为 1. 文档写的很糟糕 + 2. 只对中文文档有优势 + 3. 配置麻烦，所以完全没有其他用户在用。&lt;/p&gt;
&lt;p&gt;今年主要：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;整理了项目的结构，让它和其他的 Sphinx Notes 项目保持一致&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持了 Code snippet，为快速执行文档里的代码块做准备，实际上还没实现…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;写了一个 Vim input helper，方便自动插入 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;doc:`docname`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id19"&gt;
&lt;h3&gt;衣食住行&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;衣&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;毫无变化的一年。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;食&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;托妹妹的福，厨艺慢慢得到恢复，做饭速度也上来了。现在可以用粘锅煎荷包蛋，大火炒菜，甚至颠锅技能也回来了！调料也不再局限于只用油盐酱，耗油、糖、胡椒粉这些都会试下。&lt;/p&gt;
&lt;p&gt;乡下人第一次吃到北极虾、冻青花鱼，味道是真不错。&lt;/p&gt;
&lt;p&gt;从家里买来的牛肉丸也得到了妹妹的好评。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;住&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;从杭州的 LOFT 搬到了燕郊的二房一厅，租金从 3200 掉到 1200，还是挺爽的。难受的点在前屋主太不讲究房子太旧且会有些霉味儿清不掉，小区的电梯老化太厉害，三天两头坏一次。好在便宜嘛，咬咬牙忍住。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;行&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;带妹妹去了躺潮州，又被妹妹带回大连，都是蛮愉快的体验。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="id20"&gt;
&lt;h3&gt;娱乐&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;游戏&lt;/dt&gt;&lt;dd&gt;&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;席德梅尔的文明 VI&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;主要还是上班的时候玩…但因为垃圾时间太多也慢慢懒得开游戏了&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;王国之泪&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;开了个新档重新打。没打多久就又搁置了，可以做的事情太多导致没什么方向&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;饥荒联机版&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;和妹妹的娱乐档，想来那时候就可以预见我们做饭的合作模式&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;OverCook 2&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;和妹妹玩，手柄经常误触把厨房烧了&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;马里奥奥德赛&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;我是一个无情旋转的帽子&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/dd&gt;
&lt;dt&gt;吉他&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;谈恋爱前还在缓慢地练去年提到的 CAGED system，歌只多练了一首《亚细亚的孤儿》。谈恋爱后统统搁置了。&lt;/p&gt;
&lt;p&gt;之前的木琴一直在南方而且面板有裂的迹象，担心带到北京坏了，于是换了一把无头电吉他 &lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Chillman-ERA" title="dev Chillman ERA"&gt;&lt;a href="#report-3"&gt;&lt;span class="problematic" id="problematic-3"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-3"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，目前就是当一把低弦距的木琴弹，完全不考虑什么音色。&lt;/p&gt;
&lt;p&gt;倒是有两件有意思的事情：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="any any-friend reference internal" href="about/friends.html#friend-frantic1048" title="friend frantic1048"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 邀请我去他们的乐队了玩，快乐排练了一首《恋曲 1980》，希望今年能多蹭一下这样的排练&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;妹妹虽然是弹钢琴的，但吉他上手很快。在家里我们也会拿上 &lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Ibanez-EWP14" title="dev Ibanez EWP14"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 合奏一些简单的曲子。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/dd&gt;
&lt;dt&gt;羽毛球&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;八月在大柳羽球密集上了十来节课后感觉有大进步，可惜歇了几个月没打感觉又回去了。
现在在燕郊也找到了合适的俱乐部，大家水平相当，感觉还算不错。不过因为事情太多，对羽毛球的热情倒也并不高涨。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id21"&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;写完这篇总结已经是 25 年的 3 月，我做什么事情（画画、写文章）都很慢，不知道怎么做能更快呢？&lt;/p&gt;
&lt;p&gt;2024 年对我来说是动荡的一年：被裁员了也不争取转岗；医保空窗期生了大病；脱产画画又学不好，还分心谈恋爱。这么听起来似乎我过得很窝心，想来我就是爱用这种糟糕的叙事。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;裁员：之前过得太舒坦了，如果因为我只做了份内工作而不力争上游就开除我，我只能说大家道不同不相为谋&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;空窗期生病：纯纯倒霉，没什么办法&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;画画学不好：以我的悟性，在晓飞老师那里学画一直是一件艰难的事情&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;谈恋爱：尽管花了很多时间，但我也获得了一些珍贵的感受和体验。妹妹并不会阻止我以后画画，如果把它当成长期投资的话，当下多花的时间倒也是有价值的&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2025 年，我正儿八经三十岁了，被球场的 00 后小孩问年龄会感到难以启齿，我还有多少时间可以挥霍呢？新的一年要做这些事情：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;继续学造型、学色彩、学创作，读艺术史&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用妹妹留下的 RTX 3060 开启 AI 的学习&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;学英语&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;练琴&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;希望写明年的总结的时候它们都有满意的结果。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2024-changelog.html"/>
    <summary>今年的时间过得飞快，总感觉 2023 还近在眼前。看朋友圈和相册的时候觉得上半年的回忆很稀薄，似乎那段时间是空白的；下半年密集发生了很多重要的事情，回想起来又觉得很陌生。</summary>
    <category term="生活" label="生活"/>
    <category term="绘画" label="绘画"/>
    <published>2025-03-02T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/transfer-domain-from-godaddy-to-cloudflare.html</id>
    <title>将域名从 GoDaddy 转移至 Cloudflare</title>
    <updated>2025-01-27T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="godaddy-cloudflare"&gt;

&lt;section id="id1"&gt;
&lt;h2&gt;大家都知道的基础知识&lt;/h2&gt;
&lt;p&gt;DNS 协议能将一个域名解析为主机的 IP 地址，从而访问对应的主机，在移动互联网时代，流量的入口是各类 APP 而非浏览器，域名的意义早已不那么重大。不过对于希望保持数据独立性的内容生产者来说，持有一个域名还是有必要的。&lt;/p&gt;
&lt;p&gt;域名有点像手机号码，表面上用户可以在域名注册商（Domain Name Registrar）处「购买」域名，但实际上所有的域名都归非营利的 &lt;em&gt;互联网名称与数字地址分配机构（ICANN）&lt;/em&gt; 所有，域名注册商只是租赁代理，用户也只是租客。因此，对于同一个域名，用户既可以在注册商 A 处购买，也可以在注册商 B 处购买，在 ICANN 的管理下，注册商能够保证租给你的域名是唯一的。&lt;/p&gt;
&lt;p&gt;中心化的 ICANN 保证了域名可以被唯一地分配，而分布式的 DNS 协议则保证了，无论域名由哪个注册商管理，都能在全球范围内被正确地解析和访问。&lt;/p&gt;
&lt;p&gt;此外，已租用域名的用户，也可以选择将租赁协议从一家注册商转移到另一家（类似携号转网），转移费用等同于域名一年的租金。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;老用户不如狗&lt;/h2&gt;
&lt;p&gt;转移域名的原因常常是因为 &lt;em&gt;注册商提价&lt;/em&gt;。不同注册商对统一域名的定价不同，且因为域名的转移/迁移成本较高，注册商会倾向于逐年提高域名的续费价格。但根据上面的基础知识可知，用户可以选择将域名转移到另一注册商。&lt;/p&gt;
&lt;p&gt;2017 年我在狗爹（godaddy.com）购入了域名 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;silverrainz.me&lt;/span&gt;&lt;/code&gt;，前几年价格大概在 100 CNY/yr 出头，也就一直续费着，23 涨到了 199，我开始考虑将域名转移到其他提供商。由于域名临近到期时不允许转出，也不想刚续费就马上转出浪费钱，就把事情推到了 24 年底，GoDaddy 又变本加厉地加价到了 219：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-22_154813.png" src="https://silverrainz.me/_images/2025-01-22_154813.png" style="width: 50%;" /&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;货比三家&lt;/h2&gt;
&lt;p&gt;在转移之前首先要确定哪里的注册商比较便宜且靠谱，&lt;a class="reference external" href="https://www.nazhumi.com/domain/me/transfer/1"&gt;哪煮米&lt;/a&gt; 提供了域名比价的功能，可以看到我的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;.me&lt;/span&gt;&lt;/code&gt; 域名在 90~100 CNY 的区间就能买到，GoDaddy 属实是欺负人了。前两个注册商我都不太熟，排第三的是大名鼎鼎的云厂商 Cloudflare：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-27_222614.png" src="https://silverrainz.me/_images/2025-01-27_222614.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;CF 有个缺点是其托管的域名没法使用第三方的 nameserver，不过它作为（也许是全世界最好的）nameserver 服务提供商，用别的 nameserver 确实也说不过去。&lt;a class="extlink-ghuser reference external" href="https://github.com/pandada8"&gt;👤 pandada8&lt;/a&gt; 也说 CF 的免费解析服务在国内的可访问性也还行，于是就决定选 Cloudflare 了。&lt;/p&gt;
&lt;div class="admonition seealso"&gt;
&lt;p class="admonition-title"&gt;参见&lt;/p&gt;
&lt;p&gt;「哪煮米」诙谐的网站介绍&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-23_230213.png" src="https://silverrainz.me/_images/2025-01-23_230213.png" style="width: 80%;" /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;域名转移流程&lt;/h2&gt;
&lt;p&gt;将原有注册商称为 A，常规的转移流程是，确定需要转入的新注册商 B，在 A 处申请域名转出，获得一个 &lt;em&gt;转移密码&lt;/em&gt;，在 B 处申请域名转入，填入转移密码，然后等待 A 同意转出，这个过程大概需要 5 天左右。&lt;/p&gt;
&lt;p&gt;直观地想，当域名转出的时候，域名在 A 处的设置会全部失效，例如 nameserver 设置和 DNS 设置，而 B 处会让新的域名使用自家的 nameserver，DNS 设置则还是一片空白，网站会陷入一段时间的不可用状态。因此合理的转移方式应该是，&lt;em&gt;先在 A 处设置域名使用第三方的 nameserver，当然就是说「使用 B 的 nameserver」，再在 B 处导入该域名的所有 DNS 设置&lt;/em&gt;，如此一来，可以在域名转移前就将所有的解析工作交给 B，让域名在转移前后都正常工作。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;小小坑点&lt;/h2&gt;
&lt;p&gt;我分别查阅了 &lt;a class="reference external" href="https://www.godaddy.com/zh-sg/help/transfer-my-domain-away-from-godaddy-3560"&gt;GoDaddy 的转出指南&lt;/a&gt; 和 &lt;a class="reference external" href="https://blog.cloudflare.com/zh-cn/a-step-by-step-guide-to-transferring-domains-to-cloudflare"&gt;Cloudflare 的转入指南&lt;/a&gt;，基本上按文档操作的来，就没啥问题了。&lt;/p&gt;
&lt;p&gt;唯一卡住我的地方是文档说，在「域名组合」页面（点开来的标题是「域名总览」）如此操作即可转移域名：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-27_231235.png" src="https://silverrainz.me/_images/2025-01-27_231235.png" style="width: 80%;" /&gt;
&lt;/figure&gt;
&lt;p&gt;但无论在 &lt;a class="reference external" href="https://dcc.godaddy.com/control/portfolio"&gt;Portfolio 页面中，选中域名时的弹出菜单项&lt;/a&gt; 里，还是在 &lt;a class="reference external" href="https://dcc.godaddy.com/control/transfers"&gt;转移页面&lt;/a&gt; 里，都不存在文档里提及的「转移至另一注册商/Transfer to Another Registrar」的选项。&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id8"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-27_233454.png" src="https://silverrainz.me/_images/2025-01-27_233454.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;Portfolio 页面，选中域名时的弹出菜单项&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id9"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-27_233644.png" src="https://silverrainz.me/_images/2025-01-27_233644.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;转移页面&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但实际上文档也没写错，在 Portfolio 点击域名的超链接，进入域名详情，就有对应的转移选项了：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2025-01-27_233908.png" src="https://silverrainz.me/_images/2025-01-27_233908.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;大家新年快乐，&lt;a class="any any-people reference internal" href="about/people.html#people-Swan" title="people Swan"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 生日快乐～&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/transfer-domain-from-godaddy-to-cloudflare.html"/>
    <summary>DNS 协议能将一个域名解析为主机的 IP 地址，从而访问对应的主机，在移动互联网时代，流量的入口是各类 APP 而非浏览器，域名的意义早已不那么重大。不过对于希望保持数据独立性的内容生产者来说，持有一个域名还是有必要的。</summary>
    <category term="运维域名" label="运维 域名"/>
    <published>2025-01-27T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/the-correct-to-prevent-bytes-string-conv.html</id>
    <title>Golang 中避免 []bytes 和 string 转换开销的正确方法</title>
    <updated>2024-05-19T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="golang-bytes-string"&gt;

&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;本文写于 2024 年 5 月，基于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;go&lt;/span&gt; &lt;span class="pre"&gt;version&lt;/span&gt; &lt;span class="pre"&gt;go1.22.3&lt;/span&gt; &lt;span class="pre"&gt;linux/amd64&lt;/span&gt;&lt;/code&gt; 展开讨论。
一些事实（尤其是编译优化的条件）会随着时间发生改变。&lt;/p&gt;
&lt;p&gt;本文涉及的所有测试脚本与代码可在 &lt;a class="reference external" href="https://github.com/SilverRainZ/bullet/tree/master/src/_assets/bsconv"&gt;此处&lt;/a&gt; 获取。&lt;/p&gt;
&lt;/div&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;背景和现状&lt;/h2&gt;
&lt;p&gt;在 Golang 中，绝大部分的 type conversion 的运行时开销较小，但 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; ⇆  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 是一个
特例：由于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 类型不可变（immutable），而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 类型可变（mutable），
两者转换时会导致内存的拷贝 &lt;a class="footnote-reference brackets" href="#id24" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 会导致运行时的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;runtime.stringtoslicebyte&lt;/span&gt;&lt;/code&gt; 开销&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 会导致运行时的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;runtime.slicebytetostring&lt;/span&gt;&lt;/code&gt; 开销&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不少开发人员对此类转换缺乏足够的敏感，导致编码中这样的开销随处可见。
另一方面这也是 Go 语言本身的缺陷：无法对变量的可变性进行约束，无法做更精准的
逃逸分析，导致 runtime 对此类转换的开销优化相当有限。&lt;/p&gt;
&lt;section id="unsafe-is-not-safe"&gt;
&lt;h3&gt;unsafe is not safe&lt;/h3&gt;
&lt;p&gt;而当开销逐渐累计为性能瓶颈时，开发人员又会开始寻求快速优化的途径，且往往会
尝试简单粗暴的操作：通过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;unsafe&lt;/span&gt;&lt;/code&gt; 包强制将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 指向 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 的底层数据，
或反之，以避免内存的拷贝。&lt;/p&gt;
&lt;p&gt;unsafe 绝非理想的解决方案，首先它打破了类型上 immutable 和 mutable 的约定，
可能导致程序的逻辑错误，在广泛使用并发的 Go 里就更容易出问题了；其次，使用
unsafe 时稍有不当就会导致非预期的内存 BUG，即使是有经验的开发者也很难
不踩坑：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/modern-go/reflect2/pull/13"&gt;modern-go/reflect2#12&lt;/a&gt;: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 转 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 的过程中，将构造好的
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;reflect.SliceHeader&lt;/span&gt;&lt;/code&gt; 转回 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 之前，GC 可能将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SliceHeader.Data&lt;/span&gt;&lt;/code&gt; 指向的
数据回收&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/DataDog/zstd/pull/91"&gt;DataDog/zstd#91&lt;/a&gt;: 将栈上分配的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 强转为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 后，栈扩张导致 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 底层数据
失效&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;不完美的解决方案们&lt;/h2&gt;
&lt;p&gt;Go Team 在编译器和标准库层面提供了一些方案，但总的来说不够好：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;指标不治本：不够通用，不能覆盖所有场景&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;手段不一致：有些是编译器优化，有些是标准库 API&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些方案在不同的 Go 版本中被陆续加入，文档也散落在不同的地方，在我印象里似乎没有
人好好地把他们收集起来捋一捋。比起在网上的哪个旮旯里随便找个博客抄一段易燃易爆炸
的 unsafe 代码，我更希望使用官方推荐的解决方案，这对项目的稳定性和可维护性都
是大有裨益的。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;编译优化&lt;/h2&gt;
&lt;p&gt;在以下的情况，编译器已经能直接省略 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; ⇆  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 的开销了。如果你的应用对性能比较敏感，
你需要了解如何编写代码才能让它享受到编译器的优化，必要时可借助编译器的日志和
benchmark 做进一步的确认。&lt;/p&gt;
&lt;section id="go1-22-zero-copy-s2b-conversions"&gt;
&lt;h3&gt;Go1.22: zero-copy &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; conversions&lt;/h3&gt;
&lt;p&gt;Go1.22 默认启用了一项叫 zerocopy 的优化 &lt;a class="footnote-reference brackets" href="#id25" id="id8" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，如果一个由 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 转化
而来的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 没有逃逸到堆上（&lt;a class="reference external" href="https://golang2.eddycjy.com/posts/ch6/08-stack-heap/"&gt;什么是逃逸？&lt;/a&gt;），且在它所有代码路径上都是
只读的（没有进行任何修改操作），那么转换的开销可以被省略。如下代码：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="linenos"&gt; 7&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BenchmarkZeroCopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="linenos"&gt; 8&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;202405&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="linenos"&gt; 9&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="linenos"&gt;10&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="linenos"&gt;11&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="linenos"&gt;12&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;我们通过分别设置 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-gcflags='-d&lt;/span&gt; &lt;span class="pre"&gt;zerocopy=1'&lt;/span&gt;&lt;/code&gt; &lt;a class="footnote-reference brackets" href="#id26" id="id9" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-gcflags='-d&lt;/span&gt; &lt;span class="pre"&gt;zerocopy=0'&lt;/span&gt;&lt;/code&gt;
来开启和关闭优化，在此基础上进行测试：&lt;/p&gt;
&lt;p&gt;结果如下：&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;// zerocopy=1
&lt;/span&gt;&lt;span data-line="2"&gt;goos: linux
&lt;/span&gt;&lt;span data-line="3"&gt;goarch: amd64
&lt;/span&gt;&lt;span data-line="4"&gt;cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="hll"&gt;BenchmarkZeroCopy-8   	1000000000	         0.2157 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="6"&gt;PASS
&lt;/span&gt;&lt;span data-line="7"&gt;ok  	command-line-arguments	0.241s
&lt;/span&gt;&lt;span data-line="8"&gt;// zerocopy=0
&lt;/span&gt;&lt;span data-line="9"&gt;goos: linux
&lt;/span&gt;&lt;span data-line="10"&gt;goarch: amd64
&lt;/span&gt;&lt;span data-line="11"&gt;cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="hll"&gt;BenchmarkZeroCopy-8   	418946652	         3.056 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="13"&gt;PASS
&lt;/span&gt;&lt;span data-line="14"&gt;ok  	command-line-arguments	1.573s
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在测试的同时，我们还可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-gcflags&lt;/span&gt; &lt;span class="pre"&gt;'-m'&lt;/span&gt;&lt;/code&gt; &lt;a class="footnote-reference brackets" href="#id26" id="id10" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 输出编译器的优化日志，
通过对比可以发现，第 10 行的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 转换在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zerocopy=1&lt;/span&gt;&lt;/code&gt; 的情况下被正确识别了：&lt;/p&gt;
&lt;div class="highlight-udiff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gd"&gt;--- /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/bsconv/zerocopy0.log&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gi"&gt;+++ /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/bsconv/zerocopy1.log&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gu"&gt;@@ -2,6 +2,7 @@&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt; &lt;/span&gt;./zerocopy_test.go:7:6: can inline BenchmarkZeroCopy
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt; &lt;/span&gt;./zerocopy_test.go:7:24: b does not escape
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt; &lt;/span&gt;./zerocopy_test.go:10:14: ([]byte)(s) does not escape
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="gi"&gt;+./zerocopy_test.go:10:14: zero-copy string-&amp;gt;[]byte conversion&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt; &lt;/span&gt;# command-line-arguments.test
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt; &lt;/span&gt;_testmain.go:37:6: can inline init.0
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt; &lt;/span&gt;_testmain.go:45:24: inlining call to testing.MainStart
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;这个优化并不支持另一个方向 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 的 zero copy，&lt;a class="reference external" href="https://github.com/golang/go/issues/2205#issuecomment-1067303496"&gt;&amp;#64;randall77 说&lt;/a&gt; 难以实现
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; &lt;em&gt;在 conversions 之后是只读的&lt;/em&gt; 这样的检查，并且多个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 可以指向同一份
数据，难以追踪。我其实没有完全理解，因为将优化的条件再收紧一些，
感觉是可以做的？&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;要求 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 完全地只读，而非在 conversions 之后只读&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 没有逃逸的话，完全跟踪所有指向底层存储的 slice 也非难事？&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两点都已经在当前的 zerocopy 优化里实现了，好奇为什么不这么做。如果有熟悉
编译器的朋友知道原因，希望不吝赐教。&lt;/p&gt;
&lt;p&gt;我纠结它为什么不实现的原因是，编译器在下面两种特殊情况下已经实现了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; →  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;，
但只允许转换出来的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 用于特定的内置操作（map查找和字符串运算），不能赋值给
变量也不能传递给其他函数，非常受限。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="go1-5-bytes-comparison"&gt;
&lt;h3&gt;Go1.5: bytes comparison&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]bytes&lt;/span&gt;&lt;/code&gt; 本质上是 slice 类型，无法直接判等，可以通过标准库 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bytes.Equal&lt;/span&gt;&lt;/code&gt; 实现。
Go1.5 引入了一个优化 &lt;a class="footnote-reference brackets" href="#id27" id="id13" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 临时转化为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 用于判等时，不会产生额外的内存
分配。例如：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="linenos"&gt;12&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Optimized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="linenos"&gt;13&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="linenos"&gt;14&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="linenos"&gt;15&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="linenos"&gt;16&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但如果你用一个变量储存转换出来的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;，哪怕逻辑上完全等价，优化会失效：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="linenos"&gt;17&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NotOptimized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="linenos"&gt;18&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="linenos"&gt;19&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;s1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="linenos"&gt;20&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;s2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="linenos"&gt;21&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="linenos"&gt;22&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="linenos"&gt;23&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其他的字符串操作，例如比较大小 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;&lt;/span&gt;&lt;/code&gt; 或者连接 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;+&lt;/span&gt;&lt;/code&gt; 也同样支持该优化：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="linenos"&gt;24&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Optimized2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="linenos"&gt;25&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="linenos"&gt;26&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="linenos"&gt;27&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="linenos"&gt;28&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Benchmark 结果如下：&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;goos: linux
&lt;/span&gt;&lt;span data-line="2"&gt;goarch: amd64
&lt;/span&gt;&lt;span data-line="3"&gt;cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
&lt;/span&gt;&lt;span data-line="4"&gt;BenchmarkEqual/Optimized-8         	1000000000	         0.2547 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="hll"&gt;BenchmarkEqual/NotOptimized-8      	26003533	        46.33 ns/op	     160 B/op	       2 allocs/op
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="6"&gt;BenchmarkEqual/Optimized2-8        	382775796	         3.174 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;span data-line="7"&gt;BenchmarkEqual/bytes.Equal-8       	1000000000	         0.2310 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;span data-line="8"&gt;PASS
&lt;/span&gt;&lt;span data-line="9"&gt;ok  	command-line-arguments	3.328s
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bytes.Equal&lt;/span&gt;&lt;/code&gt; 的结果看起来也是优化过的，这是因为在 Go1.13 以后
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bytes.Equal&lt;/span&gt;&lt;/code&gt; 就是简单地用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;==&lt;/span&gt;&lt;/code&gt; 实现了 &lt;a class="footnote-reference brackets" href="#id28" id="id14" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;5&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;：&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id32"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://pkg.go.dev/bytes#Equal"&gt;https://pkg.go.dev/bytes#Equal&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// Equal reports whether a and b&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;// are the same length and contain the same bytes.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;// A nil argument is equivalent to an empty slice.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Neither cmd/compile nor gccgo allocates for these string conversions.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="hll"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="go1-3-map-lookup"&gt;
&lt;h3&gt;Go1.3: map lookup&lt;/h3&gt;
&lt;p&gt;Go1.3 引入了一个优化 &lt;a class="footnote-reference brackets" href="#id29" id="id15" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;6&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，当将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 临时转化为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 并用于查询 map 时，
可以免去转换：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="linenos"&gt;13&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Optimized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="linenos"&gt;14&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="linenos"&gt;15&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="linenos"&gt;16&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="linenos"&gt;17&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;和上面类似，如果你用一个变量储存转换出来的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;，优化会失效：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="linenos"&gt;18&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NotOptimized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="linenos"&gt;19&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="linenos"&gt;20&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="linenos"&gt;21&lt;/span&gt;&lt;span class="w"&gt;			&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="linenos"&gt;22&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Benchmark 结果如下：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;goos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;goarch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amd64&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="n"&gt;Gen&lt;/span&gt; &lt;span class="n"&gt;Intel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1165&lt;/span&gt;&lt;span class="n"&gt;G7&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="mf"&gt;2.80&lt;/span&gt;&lt;span class="n"&gt;GHz&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;BenchmarkMapLookup&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Optimized&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;         	&lt;span class="mi"&gt;222915559&lt;/span&gt;	         &lt;span class="mf"&gt;5.483&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;	       &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;	       &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="n"&gt;BenchmarkMapLookup&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;NotOptimized&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;      	&lt;span class="mi"&gt;49391640&lt;/span&gt;	        &lt;span class="mf"&gt;33.78&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;	      &lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;	       &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="n"&gt;PASS&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="n"&gt;ok&lt;/span&gt;  	&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;	&lt;span class="mf"&gt;3.465&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id16"&gt;
&lt;h2&gt;标准库使用姿势&lt;/h2&gt;
&lt;p&gt;Go1.18 之前不支持泛型，因此标准库中有关 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;/&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 的接口如果需要另一种类型的支持，
基本就要加一个新接口。&lt;/p&gt;
&lt;p&gt;当然，即使在已经有了泛型的 2024 年，标准库还是没有统一的方式来操作它们。
具体可以看这里的讨论：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/golang/go/issues/48643"&gt;proposal: byteseq: add a generic byte string manipulation package · Issue #48643 · golang/go&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/golang/go/issues/5376"&gt;proposal: spec: byte view: type that can represent a []byte or string · Issue #5376 · golang/go&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id="strings-bytes"&gt;
&lt;h3&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strings&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bytes&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;两个库提供了基本相同的功能，但分别针对 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 类型，
合理挑选函数可以避免转换：&lt;/p&gt;
&lt;div class="highlight-diff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="w"&gt; &lt;/span&gt; var s = []byte(&amp;quot;hello world&amp;quot;)
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gd"&gt;- strings.HasPrefix(string(s), &amp;quot;hello&amp;quot;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gi"&gt;+ bytes.HasPrefix(s, []byte(&amp;quot;hello&amp;quot;))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="io-writer-io-stringwriter"&gt;
&lt;h3&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Writer&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.StringWriter&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;往 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Writer&lt;/span&gt;&lt;/code&gt; 写入数据时，如果 writer 还同时实现了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.StringWriter&lt;/span&gt;&lt;/code&gt;，
可以根据数据的类型选择调用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Write&lt;/span&gt;&lt;/code&gt; 方法或者 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;WriteString&lt;/span&gt;&lt;/code&gt; 方法以避免转换：&lt;/p&gt;
&lt;div class="highlight-diff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="w"&gt; &lt;/span&gt; var s = &amp;quot;hello world&amp;quot;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gd"&gt;- w.Write([]byte(s))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gi"&gt;+ w.(io.StringWriter).WriteString(s)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;标准库的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.WriteString&lt;/span&gt;&lt;/code&gt; 就帮用户自动实现了这个逻辑：&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id33"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://pkg.go.dev/io#WriteString"&gt;https://pkg.go.dev/io#WriteString&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// WriteString writes the contents of the string s to w, which accepts a slice of bytes.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;// If w implements [StringWriter], [StringWriter.WriteString] is invoked directly.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;// Otherwise, [Writer.Write] is called exactly once.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;StringWriter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;于是刚刚的代码就可以简化为：&lt;/p&gt;
&lt;div class="highlight-diff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="w"&gt; &lt;/span&gt; var s = &amp;quot;hello world&amp;quot;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt; &lt;/span&gt; var w io.Writer
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gd"&gt;- w.Write([]byte(s))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="gi"&gt;+ io.WriteString(w, s)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;比较遗憾的是，要求每个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Writer&lt;/span&gt;&lt;/code&gt; 都实现 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.StringWriter&lt;/span&gt;&lt;/code&gt; 是不现实的，
很多情况下，我们持有一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;，要喂给 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Writer&lt;/span&gt;&lt;/code&gt; 时还是只能乖乖地转换。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Writer.Write&lt;/span&gt;&lt;/code&gt; 的入参在约定上是只读的：&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id34"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://pkg.go.dev/io#Writer"&gt;https://pkg.go.dev/io#Writer&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// Writer is the interface that wraps the basic Write method.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;// Write writes len(p) bytes from p to the underlying data stream.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="c1"&gt;// It returns the number of bytes written from p (0 &amp;lt;= n &amp;lt;= len(p))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="c1"&gt;// and any error encountered that caused the write to stop early.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="c1"&gt;// Write must return a non-nil error if it returns n &amp;lt; len(p).&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="hll"&gt;&lt;span class="c1"&gt;// Write must not modify the slice data, even temporarily.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="c1"&gt;// Implementations must not retain p.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Writer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;我们可以畅想一下，编译器其实可以考虑直接省略该转换，但约定毕竟只是约定，
没有强制力，如何识别修改 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 的边角 case 是个问题。社区对此有一些讨论：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/golang/go/issues/2205#issuecomment-726468940"&gt;cmd/compile: read-only escape analysis and avoiding string -&amp;gt; []byte copies #2205&lt;/a&gt;
已经由刚才提到的 zerocopy &lt;a class="footnote-reference brackets" href="#id25" id="id17" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 优化部分实现了&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/golang/go/issues/18822"&gt;cmd/compile: optimize Write([]byte(stringVal)) to not copy the string #18822&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="strconv-appendxxx"&gt;
&lt;h3&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.AppendXXX&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.FormatXXX&lt;/span&gt;&lt;/code&gt; 系列函数将其他的基本类型（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;float64&lt;/span&gt;&lt;/code&gt; 等）转化为
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;。某些情况下我们需要 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 形式的结果，可以使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.AppendXXX&lt;/span&gt;&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-diff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="w"&gt; &lt;/span&gt; var data []byte
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gd"&gt;- data = []byte(strconv.FormatInt(1234, 10))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gi"&gt;+ data = strconv.AppendInt(nil, 1234, 10)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="go1-20-strconv-parsexxx"&gt;
&lt;h3&gt;Go1.20: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.ParseXXX&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;很遗憾，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ParseXXX&lt;/span&gt;&lt;/code&gt; 系列函数至今没有等价的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt; 版本实现，在 &lt;a class="reference external" href="https://github.com/golang/go/issues/2632"&gt;strconv: add
equivalents of Parsexxx() with []byte arguments&lt;/a&gt; 有过讨论但最终没有下文。
不过鉴于这类函数的合法入参总是比较短（不超过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;math.Max{Uint,Float64}&lt;/span&gt;&lt;/code&gt;），
在栈上多复制一份也没什么大不了。&lt;/p&gt;
&lt;p&gt;但有一个问题：当 parse 发生错误时，为了方便调试，错误信息会包含输入参数，例如执行
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.ParseInt(&amp;quot;a&amp;quot;)&lt;/span&gt;&lt;/code&gt; 会返回错误 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strconv.ParseInt:&lt;/span&gt; &lt;span class="pre"&gt;parsing&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;a&amp;quot;:&lt;/span&gt; &lt;span class="pre"&gt;invalid&lt;/span&gt; &lt;span class="pre"&gt;syntax&lt;/span&gt;&lt;/code&gt;。
在 Go1.20 前 &lt;a class="footnote-reference brackets" href="#id30" id="id20" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;7&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，这会导致从而导致参数逃逸到堆上。&lt;/p&gt;
&lt;p&gt;以下代码：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="linenos"&gt; 8&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BenchmarkStrconv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="linenos"&gt; 9&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="linenos"&gt;10&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="linenos"&gt;11&lt;/span&gt;&lt;span class="w"&gt;		&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="linenos"&gt;12&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="linenos"&gt;13&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在 Go1.22 和 Go1.19 分别运行可以明显看到区别：&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;// go1.22
&lt;/span&gt;&lt;span data-line="2"&gt;goos: linux
&lt;/span&gt;&lt;span data-line="3"&gt;goarch: amd64
&lt;/span&gt;&lt;span data-line="4"&gt;cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="hll"&gt;BenchmarkStrconv-8   	86147509	        12.70 ns/op	       0 B/op	       0 allocs/op
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="6"&gt;PASS
&lt;/span&gt;&lt;span data-line="7"&gt;ok  	command-line-arguments	1.111s
&lt;/span&gt;&lt;span data-line="8"&gt;// go1.19
&lt;/span&gt;&lt;span data-line="9"&gt;goos: linux
&lt;/span&gt;&lt;span data-line="10"&gt;goarch: amd64
&lt;/span&gt;&lt;span data-line="11"&gt;cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="hll"&gt;BenchmarkStrconv-8   	51321450	        21.73 ns/op	       8 B/op	       1 allocs/op
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="13"&gt;PASS
&lt;/span&gt;&lt;span data-line="14"&gt;ok  	command-line-arguments	1.142s
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对比两个版本的编译器的优化日志，临时变量 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string(s)&lt;/span&gt;&lt;/code&gt; 在 1.22 是不会发生逃逸的：&lt;/p&gt;
&lt;div class="highlight-udiff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gd"&gt;--- /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/bsconv/strconv119.log&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gi"&gt;+++ /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/bsconv/strconv122.log&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gu"&gt;@@ -1,7 +1,7 @@&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt; &lt;/span&gt;# command-line-arguments [command-line-arguments.test]
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt; &lt;/span&gt;./strconv_test.go:8:23: b does not escape
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt; &lt;/span&gt;./strconv_test.go:9:13: []byte{...} does not escape
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="gd"&gt;-./strconv_test.go:11:33: string(s) escapes to heap&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="gi"&gt;+./strconv_test.go:11:34: string(s) does not escape&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt; &lt;/span&gt;# command-line-arguments.test
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt; &lt;/span&gt;_testmain.go:37:6: can inline init.0
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt; &lt;/span&gt;_testmain.go:45:24: inlining call to testing.MainStart
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="go1-19-fmt-append-f-ln"&gt;
&lt;h3&gt;Go1.19: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fmt.Append{,f,ln}&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fmt.Sprint{,f,ln}&lt;/span&gt;&lt;/code&gt; 的返回值是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;string&lt;/span&gt;&lt;/code&gt;，Go1.19 引入 &lt;a class="footnote-reference brackets" href="#id31" id="id22" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;8&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fmt.Append{,f,ln}&lt;/span&gt;&lt;/code&gt; 可以
直接格式化地输出 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]byte&lt;/span&gt;&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-diff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="w"&gt; &lt;/span&gt; var data []byte
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gd"&gt;- data = []byte(fmt.Sprintf(&amp;quot;hello %s&amp;quot;, &amp;quot;alice&amp;quot;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gi"&gt;+ data = fmt.Appendf(nil, (&amp;quot;hello %s&amp;quot;, &amp;quot;alice&amp;quot;))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id23"&gt;
&lt;h2&gt;脚注&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id24" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go.dev/src/runtime/string.go"&gt;Source file src/runtime/string.go&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id25" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="backrefs"&gt;(&lt;a role="doc-backlink" href="#id8"&gt;1&lt;/a&gt;,&lt;a role="doc-backlink" href="#id17"&gt;2&lt;/a&gt;)&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go-review.googlesource.com/c/go/+/520600"&gt;cmd/compile: enable -d=zerocopy by default (520600) · Gerrit Code Review&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id26" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="backrefs"&gt;(&lt;a role="doc-backlink" href="#id9"&gt;1&lt;/a&gt;,&lt;a role="doc-backlink" href="#id10"&gt;2&lt;/a&gt;)&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://pkg.go.dev/cmd/compile"&gt;compile command - cmd/compile - Go Packages&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id27" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id13"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go-review.googlesource.com/c/go/+/3410"&gt;cmd/gc: don't copy []byte during string comparison (3410) · Gerrit Code Review&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id28" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id14"&gt;5&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/golang/go/issues/31587"&gt;bytes: Equal more expensive than string equality · Issue #31587 · golang/go&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id29" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id15"&gt;6&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://codereview.appspot.com/83740044"&gt;Issue 83740044: code review 83740044: cmd/gc, runtime: optimize map[string] lookup from []byte key - Code Review&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id30" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id20"&gt;7&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go-review.googlesource.com/c/go/+/345488"&gt;strconv: optimize Parse for []byte arguments (345488) · Gerrit Code Review&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id31" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id22"&gt;8&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go-review.googlesource.com/c/go/+/406177"&gt;fmt: add Append, Appendln, Appendf (406177) · Gerrit Code Review&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/the-correct-to-prevent-bytes-string-conv.html"/>
    <summary>本文写于 2024 年 5 月，基于 go version go1.22.3 linux/amd64 展开讨论。
一些事实（尤其是编译优化的条件）会随着时间发生改变。</summary>
    <category term="Golang" label="Golang"/>
    <category term="性能优化" label="性能优化"/>
    <published>2024-05-19T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2024-05-linux-recording.html</id>
    <title>在 Linux 环境下录音</title>
    <updated>2024-05-03T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="linux"&gt;

&lt;p&gt;通过运行 GNU/Linux 的个人电脑录制乐器和人声。
环境：Arch Linux, kernel 6.8.8, pipewire 1.0.5，所以才需要写这么篇文章…
目前的拓扑是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;吉他/麦克风 →  &lt;sup&gt;6.5mm TS&lt;/sup&gt; →  效果器 →  &lt;sup&gt;6.5mm TS&lt;/sup&gt; →
声卡 →  &lt;sup&gt;USB&lt;/sup&gt; →  电脑 →  DAW&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2024-05-linux-recording.rst&lt;/span&gt;, line 19)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;sup&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;sup&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;设备&lt;/h2&gt;
&lt;section id="id2"&gt;
&lt;h3&gt;独立声卡&lt;/h3&gt;
&lt;p&gt;之前一直不理解为什么录音需要声卡？主板上不是有声卡么？不是麦克风连电脑不就好了吗？&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;需要有音频接口：即使完全不考虑音质，我们也需要一个让电脑能够接收音频信号的接口，
我的电脑有 3.5mm TRRS 的输入接口（能插有通话功能的耳机）。
吉他及其周边输出用的是 6.5mm 的 TS 口 &lt;a class="footnote-reference brackets" href="#id11" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，相对专业的麦克风用的则是卡农口，
规格不一、用途不同。而独立声卡这些都会提供，再通过 USB 将数据传给电脑。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;需要及格的音频处理能力：（据说）板载声卡 &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;采样率低&lt;/span&gt;，抗干扰能力弱，
得到的声音质量差。但对比参数：就采样率而言没啥区别，其他有区别但我看不懂：&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id14"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;arecord&lt;/span&gt; &lt;span class="pre"&gt;--list-device&lt;/span&gt;&lt;/code&gt; + &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;arecord&lt;/span&gt; &lt;span class="pre"&gt;--dump-hw-params&lt;/span&gt; &lt;span class="pre"&gt;-D&lt;/span&gt; &lt;span class="pre"&gt;hw:&amp;lt;CARD_NUM&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-udiff notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gd"&gt;--- /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/2025-10-linux-recording/onboard.txt&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gi"&gt;+++ /home/runner/work/silverrainz.github.io/silverrainz.github.io/src/_assets/2025-10-linux-recording/thr5a.txt&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="gu"&gt;@@ -1,22 +1,21 @@&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="gd"&gt;-HW Params of device &amp;quot;hw:0&amp;quot;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="gi"&gt;+HW Params of device &amp;quot;hw:1&amp;quot;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt; &lt;/span&gt;--------------------
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt; &lt;/span&gt;ACCESS:  MMAP_INTERLEAVED RW_INTERLEAVED
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="gd"&gt;-FORMAT:  S16_LE S24_LE&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="gi"&gt;+FORMAT:  S24_3LE&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt; &lt;/span&gt;SUBFORMAT:  STD MSBITS_MAX
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="gd"&gt;-SAMPLE_BITS: [16 32]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="gd"&gt;-FRAME_BITS: [32 64]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="gd"&gt;-CHANNELS: 2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="gd"&gt;-RATE: 48000&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="gd"&gt;-PERIOD_TIME: [500 85334)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="gd"&gt;-PERIOD_SIZE: [24 4096]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="gd"&gt;-PERIOD_BYTES: [192 16384]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="gd"&gt;-PERIODS: [2 16]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="gd"&gt;-BUFFER_TIME: [1000 341334)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="gd"&gt;-BUFFER_SIZE: [48 16384]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="gd"&gt;-BUFFER_BYTES: [192 65536]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="gi"&gt;+SAMPLE_BITS: 24&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="gi"&gt;+FRAME_BITS: 96&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="gi"&gt;+CHANNELS: 4&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="gi"&gt;+RATE: 44100&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="gi"&gt;+PERIOD_TIME: (136 1000000]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="gi"&gt;+PERIOD_SIZE: [6 44100]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="gi"&gt;+PERIOD_BYTES: [72 529200]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="gi"&gt;+PERIODS: [2 1024]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="gi"&gt;+BUFFER_TIME: (272 2000000]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="gi"&gt;+BUFFER_SIZE: [12 88200]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="gi"&gt;+BUFFER_BYTES: [144 1058400]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="w"&gt; &lt;/span&gt;TICK_TIME: ALL
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt; &lt;/span&gt;--------------------
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="w"&gt; &lt;/span&gt;arecord: set_params:1387: Sample format non available
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="w"&gt; &lt;/span&gt;Available formats:
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="gd"&gt;-- S16_LE&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="gd"&gt;-- S24_LE&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="39"&gt;&lt;span class="gi"&gt;+- S24_3LE&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;实际上，我的 &lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Yamaha-THR5a" title="dev thr5a"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 和 &lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Nux-MG300" title="dev mg300"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 都自带了声卡，内核也能正常识别，但
后者录音的时候总是捕捉不到，怀疑和 &lt;a class="reference external" href="https://blog.nostatic.org/2021/01/nux-mg-300-guitar-processor-under-linux.html"&gt;这里&lt;/a&gt; 遇到了同样的问题，折腾不动，
故使用 thr5a 录音。&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id15"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;需要 &lt;a class="extlink-archpkg reference external" href="https://archlinux.org/packages/wireplumber"&gt;📦 wireplumber&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;wpctl&lt;span class="w"&gt; &lt;/span&gt;status
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="go"&gt;Audio&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="go"&gt; ├─ Devices:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="go"&gt; │     …&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="go"&gt; │     101. NUX MG-300 AUDIO                    [alsa]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="go"&gt; │     148. THR5A                               [alsa]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="go"&gt; │&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="go"&gt; ├─ Sinks:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="go"&gt; │  *  …&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="go"&gt; │     122. NUX MG-300 AUDIO Analog Stereo      [vol: 0.40]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="go"&gt; │     166. THR5A Analog Stereo                 [vol: 0.40]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="go"&gt; │&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="go"&gt; ├─ Sources:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="go"&gt; │     …&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="hll"&gt;&lt;span class="go"&gt; │  *   97. THR5A Analog Surround 4.0           [vol: 1.00]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="hll"&gt;&lt;span class="go"&gt; │     127. NUX MG-300 AUDIO Analog Stereo      [vol: 1.00]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="go"&gt; │&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="go"&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;录制&lt;/h2&gt;
&lt;section id="the-unix-way"&gt;
&lt;h3&gt;The Unix way: 直接录制&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;GUI&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;对于最简单的录制音频场景，可以考虑用 &lt;a class="extlink-archpkg reference external" href="https://archlinux.org/packages/gnome-sound-recorder"&gt;📦 gnome-sound-recorder&lt;/a&gt;。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;ALSA&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;需要 &lt;a class="extlink-archpkg reference external" href="https://archlinux.org/packages/alsa-utils"&gt;📦 alsa-utils&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;arecord&lt;span class="w"&gt; &lt;/span&gt;--list-device
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;**** List of CAPTURE Hardware Devices ****&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="go"&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="go"&gt;card 1: THR5A [THR5A], device 0: USB Audio [USB Audio]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="go"&gt;  Subdevices: 1/1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="go"&gt;  Subdevice #0: subdevice #0&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;设备号是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;HW:&amp;lt;CARD&amp;gt;,&amp;lt;DEV&amp;gt;&lt;/span&gt;&lt;/code&gt;，也就是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;hw:1,0&lt;/span&gt;&lt;/code&gt;，开始录音:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;arecord&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;S24_3LE&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;44100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;hw:1,0&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test.wav
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;Recording WAVE &amp;#39;test.wav&amp;#39; : Signed 24 bit Little Endian in 3bytes, Rate 44100 Hz, Channels 4&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="go"&gt;^C&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="go"&gt;Aborted by signal 中断...&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;播放:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;aplay&lt;span class="w"&gt; &lt;/span&gt;test.wav
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;Playing WAVE &amp;#39;test.wav&amp;#39; : Signed 24 bit Little Endian in 3bytes, Rate 44100 Hz, Channels 4&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;Pipewire&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;Target ID 从 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;wpctl&lt;/span&gt; &lt;span class="pre"&gt;status&lt;/span&gt;&lt;/code&gt; 获取:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;pw-record&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;121&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test.wav
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;^C&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="the-pro-way-digital-audio-workstation-daw"&gt;
&lt;h3&gt;The Pro way: Digital Audio Workstation (DAW)&lt;/h3&gt;
&lt;p&gt;实际上，正经一点的录制工作都不会像上面一样用命令行工具或者简陋的 GUI，
而是使用集成化的 DAW 软件，随便找了个视频扫盲一下：&lt;/p&gt;
&lt;div class="video_wrapper" style=""&gt;
&lt;iframe allowfullscreen="true" src="https://www.youtube.com/embed/UqOTEqAE9D8" style="border: 0; height: 345px; width: 560px"&gt;
&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;当然在 Linux 上，DAW 软件选择比较有限 &lt;a class="footnote-reference brackets" href="#id12" id="id6" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; &lt;a class="footnote-reference brackets" href="#id13" id="id7" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;：&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;Reaper&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;跨三平台（wine on Linux），使用简单，但是收费&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;Ardour&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;老牌开源，一直在更新，看起来不错&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;LMMS&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;新潮漂亮，但看起来完全是给电子音乐用的，不支持录制功能&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;Presonus Studio One&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;商业软件但免费，原生 Wayland 和 Pipewire 支持，但 arch 没包&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;简单试用了下选择了 Ardour，有 &lt;a class="reference external" href="https://wiki.ubuntu.org.cn/Ardour%E5%AE%8C%E5%85%A8%E6%95%99%E7%A8%8B"&gt;中文教程&lt;/a&gt;，对于本文来说，看 &lt;a class="reference external" href="https://wiki.ubuntu.org.cn/Ardour4_%E5%88%9D%E5%AD%A6%E8%80%85%E6%95%99%E7%A8%8B_02_%E5%BC%80%E5%A7%8B%E5%85%A5%E9%97%A8#.E5.BD.95.E5.88.B6.E9.9F.B3.E9.A2.91"&gt;录制音频&lt;/a&gt; 一节即可。&lt;/p&gt;
&lt;p&gt;更多内容参看 &lt;a class="reference internal" href="notes/man/ardour.html"&gt;&lt;span class="doc"&gt;Ardour&lt;/span&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id10"&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id11" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://dashi.streetvoice.cn/article/20221226/001/"&gt;你真的了解“吉他线”吗？ | 街声 - StreetVoice&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id12" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id6"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="extlink-archwiki reference external" href="https://wiki.archlinux.org/index.php/List_of_applications/Multimedia#Digital_audio_workstations"&gt;📖 List_of_applications/Multimedia#Digital_audio_workstations&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id13" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id7"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://alternativeto.net/software/cubase/?platform=linux"&gt;https://alternativeto.net/software/cubase/?platform=linux&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2024-05-linux-recording.html"/>
    <summary>通过运行 GNU/Linux 的个人电脑录制乐器和人声。
环境：Arch Linux, kernel 6.8.8, pipewire 1.0.5，所以才需要写这么篇文章…
目前的拓扑是这样的：</summary>
    <category term="Linux" label="Linux"/>
    <category term="录音" label="录音"/>
    <category term="音乐" label="音乐"/>
    <published>2024-05-03T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2023-changelog.html</id>
    <title>2023 更新日志</title>
    <updated>2024-02-03T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;p&gt;其实每个年初都有写年度总结的冲动，但每年都因为拖延而不了了之。快元旦的时候
&lt;a class="any any-people reference internal" href="about/people.html#people-soyking" title="people 豆豆"&gt;&lt;a href="#report-9"&gt;&lt;span class="problematic" id="problematic-9"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-9"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-9"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 就在群里催大家写总结，现在豆豆和小杰 已各自完成 &lt;a class="footnote-reference brackets" href="#id49" id="id2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; &lt;a class="footnote-reference brackets" href="#id50" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，
我也该动动笔了。&lt;/p&gt;
&lt;section id="work-sumup"&gt;
&lt;span id="id4"&gt;&lt;/span&gt;&lt;h2&gt;工作&lt;/h2&gt;
&lt;p&gt;作为一年内耗时最多的人类行为，理当排第一。&lt;/p&gt;
&lt;p&gt;23 年是我工作的第 5 年，也是在字节工作的第 2 年。我的运气不错，一直以来的工作内
容还算有趣，压力也并不太大，所以一直觉得还蛮有意思的。但今年心态也开始有了一
些转变：&lt;/p&gt;
&lt;figure class="align-default" id="id58"&gt;
&lt;img alt="https://silverrainz.me/_images/work.jpg" src="https://silverrainz.me/_images/work.jpg" style="width: 40%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;工作焦虑&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;受挫、从探索到计件&lt;/h3&gt;
&lt;p&gt;22 年中，整个团队的目标转向性能优化，自己发起的项目被要求减少投入，且开源无望。
项目在内部还算受欢迎，也有不少用户，要继续开发就要在正常工作的基础上额外抽自己的
时间，我不愿意，于是项目只好停滞，只保持最低程度的维护。&lt;/p&gt;
&lt;p&gt;后面我转而尝试一些静态分析的工作。折腾了大半年东西是做出来了，但效果一般，落地困
难。有些灰心，转移目标去给其他成熟项目打下手去了，想着以后就做计件制的工作吧，就
不会有这样的挫败感了。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;探索性的项目会有失败的风险，但有意思且可以自己预估
&lt;abbr title="一个人一天做的工作量"&gt;人天&lt;/abbr&gt;，排期相对自由&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;做常规的需求则不需要太动脑子，但无聊且排期紧凑：
做一个活儿的平均时间是很明确的，干完这个就会有下一个，不会空出时间让你歇着&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;是啊，工作就是这样，这已经是很好的职场环境了，老板不会跟你说只许成功不许失败，也
没有 PM 给你加需求说明天就要。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h3&gt;摆烂、屎的制作与食用、报应、字节强度&lt;/h3&gt;
&lt;p&gt;9 月老板让我做个项目，平心而论并不是什么复杂项目，但我搞砸了：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;我抱着计件制心态做这件事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;没有 push 自己在关键的时间点完成该做的事情&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;很多技术决策都很随意，项目没成型就挖了坑&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;美名曰赶工，没有写测试&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;为了满足中期的进度审查，写了很多临时的，不可复用、屎一样的代码&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;第一次大量接触公司内部的基建，以前以为还堪一用，实际上：是屎，
每个需要用的平台几乎都有可用性问题而不得不 oncall&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/boe.png" src="https://silverrainz.me/_images/boe.png" style="width: 20%;" /&gt;
&lt;/figure&gt;
&lt;p&gt;结果就是项目到了 12 月也没能做好，被老板一直 push，还麻烦了同事来救火。
最终在 24 年的 1 月加了两周班才堪堪摆平，算是体验了一把字节的平均强度。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h3&gt;无法成为专家&lt;/h3&gt;
&lt;p&gt;如上所述，今年做的都是一些提不起劲的工作，我也开始发现自己好像没什么竞争力。
周围的朋友和组里的同事已经成为了某个领域的专家，或者在成为专家的路上，
而我好像一直在做不太难的事情，也一直没有一个聚焦的领域：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;泛型库只是一堆小工具的合集，有点意思的是易用性和功能上的各种
trade-off，但我也总结不出什么来&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;想向资深同事多学习，混个 Go Committer，发现没有余力&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;静态分析一直做得很浮躁。即使有搞过静态分析的同事 &lt;a class="extlink-ghuser reference external" href="https://github.com/zhangruoxu"&gt;👤 zhangruoxu&lt;/a&gt; 帮助，
论文还是只看了半篇，&lt;a class="reference internal" href="p/nju-static-program-analysis.html"&gt;&lt;span class="doc"&gt;课程&lt;/span&gt;&lt;/a&gt;
也没有学完，最后项目也凉了&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在开源社区做的工作倒是持续了很长时间，可惜只是并没有什么难度，不配称为聚焦。
小众社区的事情很多事情没人做只是因为它小众，做了能累积写了写代码的熟练度，
但要靠这些形成技术壁垒，就是天方夜谭了&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="id8"&gt;
&lt;h3&gt;迷茫的生活可以辞职吗？&lt;/h3&gt;
&lt;p&gt;现在的工作其实很好了，没有什么无法忍受的事情，无法忍受的是在迷茫中度日。
辞职不一定能解决我的迷茫，我可能还会迎来降薪、更差的工作环境甚至找不到工作。&lt;/p&gt;
&lt;p&gt;现在的想法是：当一日和尚撞一日钟，当然还是要尽量保持专业。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h2&gt;开源&lt;/h2&gt;
&lt;p&gt;今年依然花了很多时间在玩自己的开源过家家，即使是过家家也是有些新鲜事的：&lt;/p&gt;
&lt;section id="id10"&gt;
&lt;h3&gt;第一笔开源捐赠&lt;/h3&gt;
&lt;p&gt;&lt;a class="reference external" href="https://srain.silverrainz.me/"&gt;Srain&lt;/a&gt; 在今年五月的时候收到了 50 美元的捐赠，让我开心了好几天。只可惜我已经不再
积极地维护它，在失去热情之前没能让 Srain 成为流行的 IRC 客户端，也确实是自己能力
有限。&lt;/p&gt;
&lt;figure class="align-default" id="id59"&gt;
&lt;img alt="https://silverrainz.me/_images/srain.png" src="https://silverrainz.me/_images/srain.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://opencollective.com/srain"&gt;https://opencollective.com/srain&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;捐赠者 &lt;a class="extlink-ghuser reference external" href="https://github.com/kennylevinsen"&gt;👤 kennylevinsen&lt;/a&gt; 看起来是 &lt;a class="reference external" href="https://swaywm.org/"&gt;Sway&lt;/a&gt; 的活跃开发者，
看起来这种捐赠只在开发者之间流通啊 :D&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="the-sphinx-notes-project"&gt;
&lt;h3&gt;The Sphinx Notes Project&lt;/h3&gt;
&lt;p&gt;我的笔记系统由 Sphinx 搭建，&lt;a class="extlink-ghorg reference external" href="https://github.com/sphinx-notes"&gt;👥 sphinx-notes&lt;/a&gt; 是我用来补充原生 Sphinx 能力的
一系列项目。Sphinx 在编程文档编写领域（尤其是 Python）相当流行，但鲜有人用来记笔
记，所以这些项目的 star 数也寥寥。&lt;/p&gt;
&lt;section id="id11"&gt;
&lt;h4&gt;简单粗暴的东西好流行&lt;/h4&gt;
&lt;p&gt;在不同的项目上我花的力气不同，一些项目我觉得很酷，花了大力气，没有人用；
而一些项目很简单，我只是为了方便随手一写，就会有不知哪里来的用户：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinx-notes/pages"&gt;⛺ sphinx-notes/pages&lt;/a&gt; 用来把 Sphinx 项目推到 GitHub Pages 上，现在有
&lt;a class="reference external" href="https://github.com/sphinx-notes/pages/network/dependents"&gt;1000+ 的用户&lt;/a&gt;，其中包括了 &lt;a class="reference external" href="https://github.com/microsoft/python-package-template"&gt;微软的开源 Python 项目模板&lt;/a&gt; 和 &lt;a class="reference external" href="https://github.com/php/php-src/commit/19d2b84788df500a62d7cb668d72419f70b73ca9"&gt;PHP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinx-notes/strike"&gt;⛺ sphinx-notes/strike&lt;/a&gt; 用来给 reStructuredText 添加 &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;删除线&lt;/span&gt;
（Markdown 用户可能会觉得不可思议），仅有数十个用户，不过包括了 Haskell 的
包管理器 &lt;a class="reference external" href="https://github.com/haskell/cabal"&gt;cabal&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="sphinxnotes-lilypond"&gt;
&lt;span id="id17"&gt;&lt;/span&gt;&lt;h4&gt;凯尔特歌集、简谱和说中文的剑桥科学家 &lt;a class="footnote-reference brackets" href="#id51" id="id16" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;23 年最花力气的项目应该是 &lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinx-notes/lilypond"&gt;⛺ sphinx-notes/lilypond&lt;/a&gt;，用来把自由打谱软件
LilyPond 的生成的乐谱插入到 Sphinx 文档里。&lt;/p&gt;
&lt;p&gt;&lt;a class="extlink-ghuser reference external" href="https://github.com/kjcole"&gt;👤 kjcole&lt;/a&gt; 是我唯一认识的用户，他用 Sphinx + LilyPond 重新整理了
&lt;a class="reference external" href="https://ubuntourist.codeberg.page/Celtic_Song_Book/"&gt;《Celtic Song Book》&lt;/a&gt; &lt;a class="footnote-reference brackets" href="#id52" id="id18" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;。他向我汇报了不少 bug，有些比较难解，但在一轮轮
迭代中还是都修掉了。2.0 有几个破坏性的改动，不知道他会不会更新。&lt;/p&gt;
&lt;p&gt;为了练琴的仪式感，我尝试在插件里支持简谱。
多年前看过 Tuna 的康哥 &amp;#64;scateu 用 &lt;a class="reference external" href="http://scateu.me/2014/03/07/gnu-lilypond-example.html"&gt;LilyPond 打二胡的简谱&lt;/a&gt;，顺着博客找到了
Silas S. Brown 写的 &lt;code class="docutils literal notranslate"&gt;&lt;a class="reference external" href="http://ssb22.user.srcf.net/mwrhome/jianpu-ly.html"&gt;&lt;span class="pre"&gt;jianpu-ly.py&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Silas 定义了一套简谱语法，并提供了一个脚本 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;jianpu-ly.py&lt;/span&gt;&lt;/code&gt; 将其翻译为 LilyPond
源码。这个脚本只支持从命令行调用，并且有些复杂，不太好修改。于是我去提了
&lt;a class="reference external" href="https://github.com/ssb22/jianpu-ly/issues/15"&gt;Feature Request&lt;/a&gt;，希望他能帮我把脚本变得可以被我的扩展复用。
Silas 懂一些中文，于是我特地在 issue 里说了点中文期望能刷好感度 ;-P
而他也快速的满足了我的请求。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;jianpu-ly.py&lt;/span&gt;&lt;/code&gt; 的集成工作并没有什么值得聊的，总之我们现在也能在 Sphinx 里面
写简谱了：&lt;/p&gt;
&lt;div class="sphinxnotes-lilypond" id="sphinxnotes-lilypond-0"&gt;
&lt;p&gt;&lt;img class="sphinxnotes-lilypond" src=".././_lilypond/eb2f7d92577487d90b5e9429ee80cffe63586db4/music.cropped.png" alt="\version &amp;quot;2.20.0&amp;quot;
#(set-global-staff-size 20)

% un-comment the next line to remove Lilypond tagline:
% \header { tagline=&amp;quot;&amp;quot; }

% comment out the next line if you're debugging jianpu-ly
% (but best leave it un-commented in production, since
% the point-and-click locations won't go to the user input)
\pointAndClickOff

\paper {
  print-all-headers = ##t %% allow per-score headers

  % un-comment the next line for A5:
  % #(set-default-paper-size &amp;quot;a5&amp;quot; )

  % un-comment the next line for no page numbers:
  % print-page-number = ##f

  % un-comment the next 3 lines for a binding edge:
  % two-sided = ##t
  % inner-margin = 20\mm
  % outer-margin = 10\mm

  % un-comment the next line for a more space-saving header layout:
  % scoreTitleMarkup = \markup { \center-column { \fill-line { \magnify #1.5 { \bold { \fromproperty #'header:dedication } } \magnify #1.5 { \bold { \fromproperty #'header:title } } \fromproperty #'header:composer } \fill-line { \fromproperty #'header:instrument \fromproperty #'header:subtitle \smaller{\fromproperty #'header:subsubtitle } } } }
}

%% 2-dot and 3-dot articulations
#(append! default-script-alist
   (list
    `(two-dots
       . (
           (stencil . ,ly:text-interface::print)
           (text . ,#{ \markup \override #'(font-encoding . latin1) \center-align \bold &amp;quot;:&amp;quot; #})
           (padding . 0.20)
           (avoid-slur . inside)
           (direction . ,UP)))))
#(append! default-script-alist
   (list
    `(three-dots
       . (
           (stencil . ,ly:text-interface::print)
           (text . ,#{ \markup \override #'(font-encoding . latin1) \center-align \bold &amp;quot;⋮&amp;quot; #})
           (padding . 0.30)
           (avoid-slur . inside)
           (direction . ,UP)))))
&amp;quot;two-dots&amp;quot; =
#(make-articulation 'two-dots)

&amp;quot;three-dots&amp;quot; =
#(make-articulation 'three-dots)

\layout {
  \context {
    \Score
    scriptDefinitions = #default-script-alist
  }
}

note-mod =
#(define-music-function
     (text note)
     (markup? ly:music?)
   #{
     \tweak NoteHead.stencil #ly:text-interface::print
     \tweak NoteHead.text
        \markup \lower #0.5 \sans \bold #text
     \tweak Rest.stencil #ly:text-interface::print
     \tweak Rest.text
        \markup \lower #0.5 \sans \bold #text
     #note
   #})
#(define (flip-beams grob)
   (ly:grob-set-property!
    grob 'stencil
    (ly:stencil-translate
     (let* ((stl (ly:grob-property grob 'stencil))
            (centered-stl (ly:stencil-aligned-to stl Y DOWN)))
       (ly:stencil-translate-axis
        (ly:stencil-scale centered-stl 1 -1)
        (* (- (car (ly:stencil-extent stl Y)) (car (ly:stencil-extent centered-stl Y))) 0) Y))
     (cons 0 -0.8))))

%=======================================================
#(define-event-class 'jianpu-grace-curve-event 'span-event)

#(define (add-grob-definition grob-name grob-entry)
   (set! all-grob-descriptions
         (cons ((&amp;#64;&amp;#64; (lily) completize-grob-entry)
                (cons grob-name grob-entry))
               all-grob-descriptions)))

#(define (jianpu-grace-curve-stencil grob)
   (let* ((elts (ly:grob-object grob 'elements))
          (refp-X (ly:grob-common-refpoint-of-array grob elts X))
          (X-ext (ly:relative-group-extent elts refp-X X))
          (refp-Y (ly:grob-common-refpoint-of-array grob elts Y))
          (Y-ext (ly:relative-group-extent elts refp-Y Y))
          (direction (ly:grob-property grob 'direction RIGHT))
          (x-start (* 0.5 (+ (car X-ext) (cdr X-ext))))
          (y-start (+ (car Y-ext) 0.32))
          (x-start2 (if (eq? direction RIGHT)(+ x-start 0.5)(- x-start 0.5)))
          (x-end (if (eq? direction RIGHT)(+ (cdr X-ext) 0.2)(- (car X-ext) 0.2)))
          (y-end (- y-start 0.5))
          (stil (ly:make-stencil `(path 0.1
                                        (moveto ,x-start ,y-start
                                         curveto ,x-start ,y-end ,x-start ,y-end ,x-start2 ,y-end
                                         lineto ,x-end ,y-end))
                                  X-ext
                                  Y-ext))
          (offset (ly:grob-relative-coordinate grob refp-X X)))
     (ly:stencil-translate-axis stil (- offset) X)))

#(add-grob-definition
  'JianpuGraceCurve
  `(
     (stencil . ,jianpu-grace-curve-stencil)
     (meta . ((class . Spanner)
              (interfaces . ())))))

#(define jianpu-grace-curve-types
   '(
      (JianpuGraceCurveEvent
       . ((description . &amp;quot;Used to signal where curve encompassing music start and stop.&amp;quot;)
          (types . (general-music jianpu-grace-curve-event span-event event))
          ))
      ))

#(set!
  jianpu-grace-curve-types
  (map (lambda (x)
         (set-object-property! (car x)
           'music-description
           (cdr (assq 'description (cdr x))))
         (let ((lst (cdr x)))
           (set! lst (assoc-set! lst 'name (car x)))
           (set! lst (assq-remove! lst 'description))
           (hashq-set! music-name-to-property-table (car x) lst)
           (cons (car x) lst)))
    jianpu-grace-curve-types))

#(set! music-descriptions
       (append jianpu-grace-curve-types music-descriptions))

#(set! music-descriptions
       (sort music-descriptions alist&amp;lt;?))


#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
       (ly:spanner-set-bound! spanner LEFT item)
       (ly:spanner-set-bound! spanner RIGHT item)))

jianpuGraceCurveEngraver =
#(lambda (context)
   (let ((span '())
         (finished '())
         (current-event '())
         (event-start '())
         (event-stop '()))
     `(
       (listeners
        (jianpu-grace-curve-event .
          ,(lambda (engraver event)
             (if (= START (ly:event-property event 'span-direction))
                 (set! event-start event)
                 (set! event-stop event)))))

       (acknowledgers
        (note-column-interface .
          ,(lambda (engraver grob source-engraver)
             (if (ly:spanner? span)
                 (begin
                  (ly:pointer-group-interface::add-grob span 'elements grob)
                  (add-bound-item span grob)))
             (if (ly:spanner? finished)
                 (begin
                  (ly:pointer-group-interface::add-grob finished 'elements grob)
                  (add-bound-item finished grob)))))
        (inline-accidental-interface .
          ,(lambda (engraver grob source-engraver)
             (if (ly:spanner? span)
                 (begin
                  (ly:pointer-group-interface::add-grob span 'elements grob)))
             (if (ly:spanner? finished)
                 (ly:pointer-group-interface::add-grob finished 'elements grob))))
        (script-interface .
          ,(lambda (engraver grob source-engraver)
             (if (ly:spanner? span)
                 (begin
                  (ly:pointer-group-interface::add-grob span 'elements grob)))
             (if (ly:spanner? finished)
                 (ly:pointer-group-interface::add-grob finished 'elements grob)))))
       
       (process-music .
         ,(lambda (trans)
            (if (ly:stream-event? event-stop)
                (if (null? span)
                    (ly:warning &amp;quot;No start to this curve.&amp;quot;)
                    (begin
                     (set! finished span)
                     (ly:engraver-announce-end-grob trans finished event-start)
                     (set! span '())
                     (set! event-stop '()))))
            (if (ly:stream-event? event-start)
                (begin
                 (set! span (ly:engraver-make-grob trans 'JianpuGraceCurve event-start))
                 (set! event-start '())))))
       
       (stop-translation-timestep .
         ,(lambda (trans)
            (if (and (ly:spanner? span)
                     (null? (ly:spanner-bound span LEFT)))
                (ly:spanner-set-bound! span LEFT
                  (ly:context-property context 'currentMusicalColumn)))
            (if (ly:spanner? finished)
                (begin
                 (if (null? (ly:spanner-bound finished RIGHT))
                     (ly:spanner-set-bound! finished RIGHT
                       (ly:context-property context 'currentMusicalColumn)))
                 (set! finished '())
                 (set! event-start '())
                 (set! event-stop '())))))
       
       (finalize
        (lambda (trans)
          (if (ly:spanner? finished)
              (begin
               (if (null? (ly:spanner-bound finished RIGHT))
                   (set! (ly:spanner-bound finished RIGHT)
                         (ly:context-property context 'currentMusicalColumn)))
               (set! finished '())))))
       )))

jianpuGraceCurveStart =
#(make-span-event 'JianpuGraceCurveEvent START)

jianpuGraceCurveEnd =
#(make-span-event 'JianpuGraceCurveEvent STOP)
%===========================================================

%{ The jianpu-ly input was:
1=E
6/8
4=110

q1' q1' q6 1' q6
5 q3 1 q4
3 q3 2 q2
1. ~ 1.
q5, q7, q#2 q5 q7 q4'
5'. ~ 5'.
%}


\score {
&amp;lt;&amp;lt; \override Score.BarNumber.break-visibility = #center-visible
\override Score.BarNumber.Y-offset = -1
\set Score.barNumberVisibility = #(every-nth-bar-number-visible 5)

%% === BEGIN JIANPU STAFF ===
    \new RhythmicStaff \with {
    \consists &amp;quot;Accidental_engraver&amp;quot; 
    \consists \jianpuGraceCurveEngraver
    % Get rid of the stave but not the barlines:
    \override StaffSymbol.line-count = #0 % tested in 2.15.40, 2.16.2, 2.18.0, 2.18.2, 2.20.0 and 2.22.2
    \override BarLine.bar-extent = #'(-2 . 2) % LilyPond 2.18: please make barlines as high as the time signature even though we're on a RhythmicStaff (2.16 and 2.15 don't need this although its presence doesn't hurt; Issue 3685 seems to indicate they'll fix it post-2.18)
    $(add-grace-property 'Voice 'Stem 'direction DOWN)
    $(add-grace-property 'Voice 'Slur 'direction UP)
    $(add-grace-property 'Voice 'Stem 'length-fraction 0.5)
    $(add-grace-property 'Voice 'Beam 'beam-thickness 0.1)
    $(add-grace-property 'Voice 'Beam 'length-fraction 0.3)
    $(add-grace-property 'Voice 'Beam 'after-line-breaking flip-beams)
    $(add-grace-property 'Voice 'Beam 'Y-offset 2.5)
    $(add-grace-property 'Voice 'NoteHead 'Y-offset 2.5)
    }
    { \new Voice=&amp;quot;W&amp;quot; {
    \override Beam.transparent = ##f
    \override Stem.direction = #DOWN
    \override Tie.staff-position = #2.5
    \tupletUp
    \tieUp
    \override Stem.length-fraction = #0
    \override Beam.beam-thickness = #0.1
    \override Beam.length-fraction = #0.5
    \override Beam.after-line-breaking = #flip-beams
    \override Voice.Rest.style = #'neomensural % this size tends to line up better (we'll override the appearance anyway)
    \override Accidental.font-size = #-4
    \override TupletBracket.bracket-visibility = ##t

    \override Staff.TimeSignature.style = #'numbered
    \override Staff.Stem.transparent = ##t
     \mark \markup{1=E} \time 6/8 \tempo 4=110 \set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;1&amp;quot; c8^.[
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;1&amp;quot; c8^.
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;6&amp;quot; a8]
 \note-mod &amp;quot;1&amp;quot; c4^. \set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;6&amp;quot; a8[]
| %{ bar 2: %}
 \note-mod &amp;quot;5&amp;quot; g4
\set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;3&amp;quot; e8[]
 \note-mod &amp;quot;1&amp;quot; c4 \set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;4&amp;quot; f8[]
| %{ bar 3: %}
 \note-mod &amp;quot;3&amp;quot; e4
\set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;3&amp;quot; e8[]
 \note-mod &amp;quot;2&amp;quot; d4 \set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;2&amp;quot; d8[]
| %{ bar 4: %}
 \note-mod &amp;quot;1&amp;quot; c4.
~  \note-mod &amp;quot;1&amp;quot; c4. | %{ bar 5: %} \set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;5&amp;quot; g8-\tweak #'X-offset #0.6 _. [
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;7&amp;quot; b8-\tweak #'X-offset #0.6 _. 
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;2&amp;quot; \once \tweak Accidental.extra-offset #'(0 . 0.7)dis8]
\set stemLeftBeamCount = #0
\set stemRightBeamCount = #1
 \note-mod &amp;quot;5&amp;quot; g8[
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;7&amp;quot; b8
\set stemLeftBeamCount = #1
\set stemRightBeamCount = #1
 \note-mod &amp;quot;4&amp;quot; f8^.]
| %{ bar 6: %}
 \note-mod &amp;quot;5&amp;quot; g4.^.
~  \note-mod &amp;quot;5&amp;quot; g4.^. \bar &amp;quot;|.&amp;quot; } }
% === END JIANPU STAFF ===

&amp;gt;&amp;gt;
\layout{
  \context {
    \Global
    \grobdescriptions #all-grob-descriptions
  }
} }
\score {
\unfoldRepeats
&amp;lt;&amp;lt; 

% === BEGIN MIDI STAFF ===
    \new Staff { \new Voice=&amp;quot;X&amp;quot; { \transpose c e { \key c \major  \time 6/8 \tempo 4=110 c''8 c''8 a'8 c''4 a'8 | %{ bar 2: %} g'4 e'8 c'4 f'8 | %{ bar 3: %} e'4 e'8 d'4 d'8 | %{ bar 4: %} c'2. | %{ bar 5: %} g8 b8 dis'8 g'8 b'8 f''8 | %{ bar 6: %} g''2. } } }
% === END MIDI STAFF ===

&amp;gt;&amp;gt;
\midi { \context { \Score tempoWholesPerMinute = #(ly:make-moment 84 4)}} }" style="width: 100%;"/&gt;&lt;audio controls class="sphinxnotes-lilypond" style="width: 100%" src=".././_lilypond/eb2f7d92577487d90b5e9429ee80cffe63586db4/music.mp3" &gt;&lt;/audio&gt;&lt;/p&gt;&lt;/div&gt;&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id23"&gt;
&lt;h2&gt;画画&lt;/h2&gt;
&lt;section id="id24"&gt;
&lt;h3&gt;迷茫的生活不能画画吗？&lt;/h3&gt;
&lt;p&gt;22 年中开始，我就
{&lt;abbr title="没有意义"&gt;不愿&lt;/abbr&gt;, &lt;abbr title="技术生疏"&gt;不会&lt;/abbr&gt;, &lt;abbr title="缺乏冲动"&gt;不想&lt;/abbr&gt;}
画画了。整个 23 年，我大概只画了 15、6 张小创作，这可能是「迷茫」在我生活
里最直接的体现。&lt;/p&gt;
&lt;p&gt;思想上我有不少的忧虑，每个忧虑单独拿出来似乎又并非不可消解；行动上我看起来很忙，
下班后有大半时间沉浸在刷视频这种「报复性休息」上，余下的时间又用来写代码练琴
打球，而画画总是被排到最后。我应该放弃一些事情吗，还是它们有共存的可能？
嘴上总是不离画画，但为什么我总是抗拒它呢？&lt;/p&gt;
&lt;figure class="align-default" id="id60"&gt;
&lt;img alt="https://silverrainz.me/_images/ai.jpg" src="https://silverrainz.me/_images/ai.jpg" style="width: 40%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;AI 恐惧（未完成）&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;尽管如此，23 年还是发生了一些与画画有关的，甚至激励了我画画的事情：&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id26"&gt;
&lt;h3&gt;怀柔的机器人 &lt;a class="footnote-reference brackets" href="#id53" id="id25" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;5&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;3 月 &lt;a class="any any-people reference internal" href="about/people.html#people-6" title="people 胡林昊"&gt;&lt;a href="#report-8"&gt;&lt;span class="problematic" id="problematic-8"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-8"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-8"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 和我说到他参加了羽呈会，在怀柔租了个工作空间，说有空过去玩
玩。6 月出差去北京参加 GopherCon，便有机会去找他，过程都记录在纸上了。&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row sd-row-cols-2 sd-row-cols-xs-2 sd-row-cols-sm-2 sd-row-cols-md-2 sd-row-cols-lg-2 docutils"&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id61"&gt;
&lt;img alt="https://silverrainz.me/_images/hlh.jpg" src="https://silverrainz.me/_images/hlh.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;胡林昊的工作室&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-column docutils"&gt;
&lt;figure class="align-default" id="id62"&gt;
&lt;img alt="https://silverrainz.me/_images/hlh2.jpg" src="https://silverrainz.me/_images/hlh2.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;写在背面的小作文&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id27"&gt;
&lt;h3&gt;重返燕郊&lt;/h3&gt;
&lt;p&gt;尽管我已经能画一些东西了，但色彩上一直缺乏理论，全凭本能。&lt;a class="any any-book reference internal" href="notes/books/the-art-of-color.html#book-0" title="book 色彩艺术"&gt;&lt;a href="#report-7"&gt;&lt;span class="problematic" id="problematic-7"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-7"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-7"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;
是 &lt;a class="any any-people reference internal" href="about/people.html#people-0" title="people 晓飞老师"&gt;&lt;a href="#report-6"&gt;&lt;span class="problematic" id="problematic-6"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-6"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-6"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 非常推崇的书，我屡次尝试读它都没能有收获，只好当面去求教。
8 月我开始做准备，因为长时间没有画画怕面对老师心生愧疚，于是开始画小创作，
今年的大部分小创作都是这个时候完成的。&lt;/p&gt;
&lt;p&gt;9 月动身，用尽所有的年假搭上国庆假期，进行了为期两周的 &lt;a class="reference internal" href="notes/zxsys/color.html"&gt;&lt;span class="doc"&gt;色彩训练&lt;/span&gt;&lt;/a&gt;
，在一套相对融洽的理论下锻炼调色能力和感知能力，收获颇丰。只可惜时间不够，
未能完整地完成训练。&lt;/p&gt;
&lt;figure class="align-default" id="id63"&gt;
&lt;img alt="https://silverrainz.me/_images/zxsys.jpg" src="https://silverrainz.me/_images/zxsys.jpg" style="width: 70%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;阔别两年的画室&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="id28"&gt;
&lt;h3&gt;厕所画室&lt;/h3&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/2023-changelog.rst&lt;/span&gt;, line 251)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;sidebar&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;sidebar&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="sidebar"&gt;
&lt;figure class="align-default" id="id64"&gt;
&lt;img alt="https://silverrainz.me/_images/tiolet.jpg" src="https://silverrainz.me/_images/tiolet.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;厕所画室&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/aside&gt;
&lt;p&gt;回来前老师叮嘱我，因为时间问题训练还没到存档点，回去要自己继续画。
训练用的是油画，难整理，味道大且有一定毒性。我租的房子里没有独立空间，考虑了一段
时间要画还是要命，最后还是找到了解决方案 ——  厕所。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;厕所有门，是正儿八经的独立空间，房子里这个厕所刚好空间也大&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有排气扇，流通性甚至比只有单面窗的房间好&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;房东有个还没扔的大地毯，铺上刚好防止弄脏地面&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有个好处是训练需要稳定的光照，在房间里哪怕一直开着灯，早晚的光照还是有明显的变
化，而我这个厕所是暗卫，只要开着灯，从早到晚都是光照都是一样的。&lt;/p&gt;
&lt;p&gt;在这些基础上，我又做了一些保障狗命的措施：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;常闭厕所门，防止味道跑出来，每次画完都把画框调色盘放到柜子里&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用挥发性差、相对低毒的薰衣草油替代挥发性高，毒性大的松节油&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;把洗漱用品挪到外边，在别的地方刷牙洗脸&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个准备的过程让我很快乐，有种螺蛳壳里做道场的感觉。最终也算没辜负自己的准备，
在厕所里陆陆续续画了三周，完成了两张平面变调训练，勉强摸到了存档点。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id29"&gt;
&lt;h2&gt;生活&lt;/h2&gt;
&lt;section id="id30"&gt;
&lt;h3&gt;身体&lt;/h3&gt;
&lt;p&gt;相比北京的定点医院+起付线制度，杭州的医保到处都能刷，公司的商报报销也很方便，加
之我住的地方离浙一只有一公里，今年跑了很多次医院，应该是好事。&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;肺结节&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;5 月查出了的 4mm 磨玻璃肺结节，可能是新冠后遗症&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;7 月被银行经理游说买医疗保险，发现有肺结节不能买（非标准体）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;半年后复查无碍，改为年度复查&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;过敏&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;7 月眼睛痒、鼻子痒，发现 IgE 1000+，比较严重了。
查了过敏原，屋尘过敏，太常见以至于好像知道了也没用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;9 月觉得有时呼吸不上来（其实好早之前也有，但忽略了），诊出过敏性哮喘，
开始用 &lt;a class="reference external" href="https://www.symbicort.com.hk/"&gt;信必可&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;复诊几次后看起来控制住了&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;甲状腺结节&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;11 月体检发现 &lt;a class="reference external" href="https://zhuanlan.zhihu.com/p/31081939"&gt;TI-RADS&lt;/a&gt; 2/3 各一枚，复查后问题不大，等半年后复诊&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;头发&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;由于担心变秃， 6 月开始，开始用低浓度（2%）的米诺地尔，
半年后发现似乎有稍稍变茂密 ——  比较难观测，因为本来也还没秃，总之继续用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;8 月发现了第一根白头发&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;看起来似乎很多毛病，但所幸除了哮喘之外都是尚且不算问题，可能只是系统被观测得多了
，随之发现的 bug 也就变多了。&lt;/p&gt;
&lt;p&gt;睡眠相较 22 年有明显改善，大致都是 2:00 入睡，7 个小时左右，可能跟我买了小米手环
有关，某种程度上会为了好看的睡眠数据而好好睡觉。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id33"&gt;
&lt;h3&gt;衣食住行&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;衣&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;今年没有买衣服，之前锻炼出来的一点穿搭基础可能已经还回去了。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;食&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;身处美食荒漠，大部分时候工作日吃食堂，周末点陈八两。
老乡给我推荐的「鹅味研究所」应该是我的年度最佳，在杭州所有潮汕特色餐厅里，
它是最正宗的，没有之一。&lt;/p&gt;
&lt;p&gt;5 月在广州爽快吃的几天，几乎每一家都好评，一定要说谁最惊喜的话，可能是达扬炖品。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;住&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;8 月从回迁房的隔断搬到敞亮的网红 LOFT，房租怒涨 1000，体验也着实不错。
豆豆正好在我搬完家之后来睡了一宿，给了北京人民一点杭州震撼。
冬天还是要忍受楼上楼下近十度的温差，最近起居已经完全在楼上了。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;行&lt;/dt&gt;&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;5 月份和 &lt;a class="any any-people reference internal" href="about/people.html#people-YY" title="people YY"&gt;&lt;a href="#report-5"&gt;&lt;span class="problematic" id="problematic-5"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-5"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-5"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 去了趟广州，吃了四天，见了根兴和他老婆，一起逛了华农&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;6 月份去北京参加 GopherCon，借此参加春宇的全羊局，长亭老同事们都见了一遍，
要回了押金，而后去怀柔看胡林昊的工作室&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;9 月底去燕郊，国庆后 &lt;a class="extlink-ghuser reference external" href="https://github.com/jinzhu"&gt;👤 jinzhu&lt;/a&gt; 问我要不要顺路去北京出差，于是得以和
网友同事面基；和另一拨长亭同事吃了饭；和老朋友 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-VOID001" title="friend VOID001"&gt;&lt;a href="#report-4"&gt;&lt;span class="problematic" id="problematic-4"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-4"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-4"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 吃了饭；
和 GPY 吃了饭；还和群友 ysgg、收工小酌了一番&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;11 月组里团建，去了阳澄湖，第一次吃大闸蟹&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实应该多出去玩玩，能带上爸妈就更好了。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;购物&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;人到中年，可能没有暴富就会变抠，今年买小物件都是拼多多，大东西先看闲鱼再看
京东淘宝，而且都是挑便宜的。&lt;/p&gt;
&lt;p&gt;看了以下没什么特别的开销，颜料、羽毛球、羽毛球鞋（今年穿坏了一双）都是必要的。
闲鱼买了旅行琴、音箱啥的基本也是地板价。&lt;/p&gt;
&lt;p&gt;因为觉得东西太多了也在避免购物，实施了一段时间买一出一政策（每买入一件东西，
卖出或者扔掉现有的一件），卖了一些闲置的设备（路由器、Pico 啥的），今年还
入账小三千 :D&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;理财&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;尽管去年开始就意识到理财是个刚需，但我实在没兴趣+没时间，简单挣扎过后，
目前处于放弃状态。基本上就是 短债+招行的 XX 宝+大额存单+定存，年度收益
2.29%，甚至还不如我妈 Q_Q&lt;/p&gt;
&lt;p&gt;年中买了点寿险，明知很坑，但这钱也没有别的好去处，就这样吧。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="id34"&gt;
&lt;h3&gt;游戏&lt;/h3&gt;
&lt;p&gt;今年打的游戏不多：&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;旷野之息&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;3 月的时候通关，可能是打通的时间跨度太大了, 总的来说没有那么享受&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;王国之泪&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;借日元下跌 + Paypal 国际支付优惠 + 任亏券的组合拳 200+ 入手了。
但打了不到一半就搁置了&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;席德梅尔的文明 VI&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;一切的灾厄的源头，浪费了我无数个病假用来补觉，今年足足花了
有 260 个小时在文明六上&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;section id="id35"&gt;
&lt;h4&gt;从水下第一个生命的萌芽开始…&lt;/h4&gt;
&lt;p&gt;我一直不喜欢玩策略类游戏，不想把为数不多的脑细胞用在游戏上，但文明六确是个特例，
玩文明甚至在一定程度上指导了我的生活。&lt;/p&gt;
&lt;p&gt;B 站网友通常认为文明六游戏时长要达到 1000+ 才能算入门，但只打了 200+ 小时的我已经
有了一些感悟：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;根据地图、国家和领袖尽早确定胜利方式（明确目标）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在每回合里做出有倾向性的、对胜利方式有利的决策（累积优势）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在关键的回合里把握住机会（厚积薄发）&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样的话雪球就很容易滚起来，到了后期就只需要坐牢了。
当然实际操作上：1 需要刷个好图， 3 需要熟练度和强大的运算能力，新手如我都是
靠打开「每回合自动存档」+ Save&amp;amp;Load 来凑一个好的 timing。
而 2 的话需要了解不同国家不同领袖的的特质（推荐 up 主 &lt;a class="reference external" href="https://space.bilibili.com/291333939/video"&gt;你好图图sdx&lt;/a&gt; 的真·教科书
式讲解），在此基础上再练习「有倾向性的决策」有种运筹帷幄的满足感。而这样的决策，
其实生活中也常常用得上：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;我的目标是什么？我下一步的行动对此有帮助吗？&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这么提问很简单，但每次要行动的时候并不会有个弹框出来让我确认，文明让我有更多这样
的自省。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id37"&gt;
&lt;h3&gt;音乐&lt;/h3&gt;
&lt;p&gt;之前工作的时候会打开网易云日推，听着顺耳的加入每月歌单，基本是 JPop。近几年不太
喜欢边坐牢边听了，于是能听到的新歌少很多。&lt;/p&gt;
&lt;p&gt;前半年基本上听 别野加奈+古川本舖；后半年突然发现了罗大佑的好，《童年》、
《滚滚红尘》这种国民级歌曲之前也听过；因为阿信采访里说《之乎者也》如何好 &lt;a class="footnote-reference brackets" href="#id54" id="id38" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;6&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;
我也专门去找来听，但真正打动我的是《未来的主人翁》。&lt;/p&gt;
&lt;p&gt;赵雷的《署前街少年》听着也很顺耳，并且惊讶于《我记得》真是火遍了大街小巷（以及
各种煽情小视频）。&lt;/p&gt;
&lt;section id="id39"&gt;
&lt;h4&gt;吉他&lt;/h4&gt;
&lt;p&gt;可能是因为今年太不想画画了，对吉他反而有了更大的兴趣，这也意外推动了
&lt;a class="reference internal" href="blog/2023-changelog.html#sphinxnotes-lilypond"&gt;&lt;span class="std std-ref"&gt;sphinx-notes/lilypond&lt;/span&gt;&lt;/a&gt; 的开发。&lt;/p&gt;
&lt;p&gt;最大的进步是搞懂了 &lt;a class="reference internal" href="notes/music-theory/cadge-system.html"&gt;&lt;span class="doc"&gt;CAGED 系统&lt;/span&gt;&lt;/a&gt; 到底有什么用并且开始
练习。对我起最大帮助的资料应该是 &amp;#64;BOHAN博涵 的
&lt;a class="reference external" href="https://zhuanlan.zhihu.com/p/476222589"&gt;如何用「CAGED系统」解锁所有【和弦、琶音、音阶】&lt;/a&gt; 以及 &lt;a class="reference external" href="https://space.bilibili.com/285766656"&gt;来玩吉他&lt;/a&gt; 的付费资料
。现在的话 CAGED 的大三已经比较熟练，能在各个把位弹 145 之类的，小三和属七反应还
是比较慢，一些指型按的质量也不够高。&lt;/p&gt;
&lt;p&gt;其次是发现了 &lt;a class="reference external" href="https://space.bilibili.com/88685018"&gt;老姚吉他&lt;/a&gt; 的良心教程，坚定了唱谱有用的信念，另外网络仓鼠症也得到了
极大的满足。&lt;/p&gt;
&lt;p&gt;歌的话完整的只练了《恋曲 1980》，《小妹》， 另外惊讶的发现很多简单的曲子（例如
《漠河舞厅》）已经能直接上手了，算是入门了吧。&lt;/p&gt;
&lt;p&gt;另外慢慢开始用拨片了，买了一堆一一尝试后，发现 PickBoy 用着最顺手，于是又买了几个，
其他的就打入冷宫了。&lt;/p&gt;
&lt;figure class="align-default" id="id65"&gt;
&lt;img alt="https://silverrainz.me/_images/pick.jpg" src="https://silverrainz.me/_images/pick.jpg" style="width: 40%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;离镜头最近的带孔的黑色拨片就是 PickBoy&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;按一年的跨度来讲，进步不大，但至少我明确了进步的路径。&lt;/p&gt;
&lt;aside class="sidebar"&gt;
&lt;figure class="align-default" id="id66"&gt;
&lt;img alt="https://silverrainz.me/_images/guitar.jpg" src="https://silverrainz.me/_images/guitar.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;左 Ibanez EWP14，右 Martinez MSCC-14RS&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/aside&gt;
&lt;dl&gt;
&lt;dt&gt;设备&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;我平时很少买设备，毕竟都还没学好，但今年闲鱼上瘾了，还是小剁了一下。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Yamaha-THR5a" title="dev Yamaha THR5a"&gt;&lt;a href="#report-3"&gt;&lt;span class="problematic" id="problematic-3"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-3"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 闲鱼 850 入手，偶尔连效果器用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Ibanez-EWP14" title="dev Ibanez EWP14"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 闲鱼 450 入手，当备用旅行琴&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;音响没什么可说，后面的琴可以聊一聊，我平时用的是一把尼龙弦的
&lt;a class="any any-dev reference internal" href="p/instruments.html#dev-Martinez-MSCC-14RS" title="dev Martinez MSCC-14RS"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，有一段时间很想要钢弦的音色，又不想要多一把琴占地方。
看了 &lt;a class="reference external" href="https://www.bilibili.com/video/BV13y4y1B7a7"&gt;潘高峰老师的视频&lt;/a&gt; 讲到这把琴，看价格合适于是收了一把。&lt;/p&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;好处：&lt;/dt&gt;&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;便宜，虽然原价 1000+，但它闲置率太高了，咸鱼随随便便三五百收一把&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;虽然调弦高了四度（1、6 弦是 A 而不是 E），但好歹是把全功能吉他&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;26 寸和尤克里里一样，出差带上毫无压力，没事就能摸摸&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;坏处：&lt;/dt&gt;&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;有效弦长短 + 做工一般带来了严重的音准问题，12 品就能有一个半音的偏差&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;品格太小，中高品位手指就放不太下了，能按的和弦有限&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;琴体太小带来的盒子音，不算大问题&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;现在的功夫用这把琴弹得很难听，还是欣赏一下 YouTube 的大佬吧：&lt;/p&gt;
&lt;div class="video_wrapper" style=""&gt;
&lt;iframe allowfullscreen="true" src="https://www.youtube.com/embed/jl2hsp3AaRI" style="border: 0; height: 345px; width: 560px"&gt;
&lt;/iframe&gt;&lt;/div&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;div class="admonition warning"&gt;
&lt;p class="admonition-title"&gt;警告&lt;/p&gt;
&lt;p&gt;另外吐槽一下，今年吃过最大的亏竟是买吉他课，咸鱼接盘了别人的吉他课，第一位老师勉
强还行，就是表达能力不好且完全不备课（草台班子+1），但好歹功夫有的。结果上了
5、6 节就跑路了。第二位老师是个无题弹磕磕巴巴但又洋洋得意的精神小伙，引发了我的生
理性厌恶，并且告知我课程是「无限课时，每课时只有 30 分钟」，之前那个老师给你上一
个小时是好心 blahblah。拜托，我来的单程就要 30 分钟了……&lt;/p&gt;
&lt;p&gt;点名批评杭州「生而非凡吉他（三坝店）」，因为我是收的二手课，并且对杭州流氓的
预付费服务有所领教，就没有和他们纠缠下去。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id44"&gt;
&lt;h3&gt;羽毛球&lt;/h3&gt;
&lt;p&gt;今年羽毛球也有不小进步，在 &lt;a class="reference external" href="https://space.bilibili.com/1657588946"&gt;大柳羽球&lt;/a&gt; 陆陆续续上了 20+ 节课；在网上也看了很多
&lt;a class="reference external" href="https://space.bilibili.com/695650470"&gt;刘辉教练&lt;/a&gt; 的视频，只是不知道有多少转化到了实战中。&lt;/p&gt;
&lt;p&gt;训练的大部分时间还是在练基本技术，矫正动作，全场步伐之类的。现在步伐自我感觉不错
，有启动步了，网前被晃的概率比以前小很多，正手头顶也能转过身去。主动的高吊杀
整体的失误率也低了。反手还是不好，顶多勉强回一个不加力的过渡。如果不考虑反手的话
，现在也许有个弱四级。&lt;/p&gt;
&lt;p&gt;今年也开始参加比赛了：一次公司内部比赛，被带飞到了第一名，但因为太弱几乎没有上场
机会（甚至因为队友整体实力太强，连被田忌赛马都没机会），所以毫无体验感；
另一次是大柳的学员赛，小组赛 7 场 1 胜 6 败，意识到自己在「会参加业余比赛的爱好者」
里还属于食物链的末端。但总之每参加一次，都会有衣服穿，挺好的。&lt;/p&gt;
&lt;p&gt;伤病方面， 轻微的膝盖、肩膀不适是有的，但都通过减少运动和矫正动作缓解/解决了，
唯一大点的毛病是因为新鞋不合脚导致右脚大拇指甲掉了… 以及最近觉得小腿酸痛，经
老中医球友提醒可能是胫夹症，每日提踵恢复中。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id47"&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;写累了，不总结了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id48"&gt;
&lt;h2&gt;脚注&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id49" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id2"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://blog.soyking.top/posts/20231225_2023s_changelog/"&gt;https://blog.soyking.top/posts/20231225_2023s_changelog/&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id50" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://blog.fflush.me/2023changelog/"&gt;https://blog.fflush.me/2023changelog/&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id51" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id16"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="http://ssb22.user.srcf.net/"&gt;Silas 的主页&lt;/a&gt; 说道他是一位在剑桥任教的计算机科学家，
同时也是一位视障人士，他还有一个 &lt;a class="reference external" href="http://ssb22.user.srcf.net/index-zh.html"&gt;中文主页&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id52" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id18"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;凯尔特人之间流传的一些民歌，听起来都是有些悲伤的单旋律木管乐&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id53" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id25"&gt;5&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;胡林昊的微信昵称叫「机器人胡林昊」&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id54" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id38"&gt;6&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;大概是在发《第一张创作专辑》的时候说：「罗大佑26岁的时候，就做出了
《之乎者也》这样的专辑。我们呢？」实际出处不详，有 &lt;a class="reference external" href="https://weibo.com/1410364817/L4siFvD86"&gt;邹小樱的微博&lt;/a&gt; 可考&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2023-changelog.html"/>
    <summary>其实每个年初都有写年度总结的冲动，但每年都因为拖延而不了了之。快元旦的时候
豆豆 就在群里催大家写总结，现在豆豆和小杰 已各自完成 1 2，
我也该动动笔了。</summary>
    <category term="生活" label="生活"/>
    <category term="画画" label="画画"/>
    <published>2024-02-03T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/sphinxnotes-comboroles.html</id>
    <title>Implementing "nested inline markup" in reStructuredText and Sphinx</title>
    <updated>2024-01-14T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="implementing-nested-inline-markup-in-restructuredtext-and-sphinx"&gt;

&lt;section id="background"&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;Sphinx is a famous documentation generator used by a lot of Open Source
communities. It uses reStructuredText (hereafter referred to rST) as markup
language by default.&lt;/p&gt;
&lt;p&gt;Unlike Markdown, rST does not yet support &lt;a class="reference external" href="https://docutils.sourceforge.io/FAQ.html#is-nested-inline-markup-possible"&gt;Nested Inline Markups&lt;/a&gt;, so text
like &amp;quot;bold code&amp;quot; or &amp;quot;italic link&amp;quot; doesn't render as expected:&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;**bold**&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;bold&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;``code``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;``**bold&lt;/span&gt; &lt;span class="pre"&gt;code**``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;**bold&lt;/span&gt; &lt;span class="pre"&gt;code**&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;**``bold&lt;/span&gt; &lt;span class="pre"&gt;code``**&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;``bold code``&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;In rST, all inline markups are implemented by
&lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#interpreted-text"&gt;Interpreted Text Roles&lt;/a&gt;. For example, markup &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;**foo**&lt;/span&gt;&lt;/code&gt; is equivalent to
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`foo`&lt;/span&gt;&lt;/code&gt;, &amp;quot;foo&amp;quot; is the interpreted text, and &amp;quot;strong&amp;quot; is the name of
roles, which tells the renderer that &amp;quot;foo&amp;quot; should be highlighted.
The same goes for markup &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;`foo`&lt;/span&gt;&lt;/code&gt; and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal:`foo`&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`bold`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;bold&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal:`code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinxnotes-comboroles.rst&lt;/span&gt;, line 40)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;literal&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;literal&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Interpreted text can only &amp;quot;be interpreted&amp;quot; once, so markups and roles inside
interpreted text will be treated as plain text, which means the syntax of role
is not nestable either:&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:```bold&lt;/span&gt; &lt;span class="pre"&gt;code```&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;:strong:&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;`bold&lt;/span&gt; &lt;span class="pre"&gt;code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal:`**bold&lt;/span&gt; &lt;span class="pre"&gt;code**`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;**bold&lt;/span&gt; &lt;span class="pre"&gt;code**&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`:literal:`bold&lt;/span&gt; &lt;span class="pre"&gt;code``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;:literal:`bold code`&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal:`:strong:`bold&lt;/span&gt; &lt;span class="pre"&gt;code``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`bold&lt;/span&gt; &lt;span class="pre"&gt;code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Fortunately, rST is extensible, it allows users to create custom roles.
Suppose we can create a role that combines the effects of two existing roles,
then creating &amp;quot;bold code&amp;quot; is possible and it is true:&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong_literal:`bold&lt;/span&gt; &lt;span class="pre"&gt;code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;bold&lt;/span&gt; &lt;span class="pre"&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="the-sphinxnotes-comboroles-extension"&gt;
&lt;h2&gt;The &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinxnotes-comboroles&lt;/span&gt;&lt;/code&gt; extension&lt;/h2&gt;
&lt;p&gt;I wrote a Sphinx extension &lt;code class="docutils literal notranslate"&gt;&lt;a class="reference external" href="https://sphinx.silverrainz.me/comboroles/"&gt;&lt;span class="pre"&gt;sphinxnotes-comboroles&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;,
which can dynamically create composite roles from existing roles.&lt;/p&gt;
&lt;p&gt;First, download the extension from PyPI:&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;sphinxnotes-comboroles
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, add the extension name to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;extensions&lt;/span&gt;&lt;/code&gt; configuration item in your &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;conf.py&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;          &lt;span class="c1"&gt;# …&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;          &lt;span class="s1"&gt;&amp;#39;sphinxnotes.comboroles&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;          &lt;span class="c1"&gt;# …&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;          &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To create a &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;strong_literal&lt;/span&gt;&lt;/code&gt; role that same as described above, add the following
configuration, which tells the extension to composite example roles
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;strong&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;literal&lt;/span&gt;&lt;/code&gt; into a new role
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;strong_literal&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;comboroles_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="s1"&gt;&amp;#39;strong_literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;strong&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, you can use it:&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong_literal:`bold&lt;/span&gt; &lt;span class="pre"&gt;code`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;strong&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;bold&lt;/span&gt; &lt;span class="pre"&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;section id="nested-parse"&gt;
&lt;h3&gt;Nested Parse&lt;/h3&gt;
&lt;p&gt;We have said that markups in interpreted text will not be parsed,
but the extension allows us to force parse the interpreted text, like this:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;comboroles_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="s1"&gt;&amp;#39;parsed_literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# enable nested_parse&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The above configuration creates a composite role &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;parsed_literal&lt;/span&gt;&lt;/code&gt; with
&lt;a class="reference external" href="https://sphinx.silverrainz.me/comboroles/usage.html#nested-parse"&gt;Nested Parse&lt;/a&gt; enabled, so the text &amp;quot;**bold code**&amp;quot; can be parsed.&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;``**bold&lt;/span&gt; &lt;span class="pre"&gt;code**``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;**bold&lt;/span&gt; &lt;span class="pre"&gt;code**&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;❌&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:parsed_literal:`**bold&lt;/span&gt; &lt;span class="pre"&gt;code**`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;strong&gt;&lt;span class="pre"&gt;bold&lt;/span&gt; &lt;span class="pre"&gt;code&lt;/span&gt;&lt;/strong&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;✔️&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Further, hyperlinks, substitutions, and even roles inside interpreted text can
be parsed too:&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:parsed_literal:`https://example.com``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;a class="reference external" href="https://example.com"&gt;&lt;span class="pre"&gt;https://example.com&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:parsed_literal:`|today|``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;2026&lt;/span&gt; &lt;span class="pre"&gt;年&lt;/span&gt; &lt;span class="pre"&gt;03&lt;/span&gt; &lt;span class="pre"&gt;月&lt;/span&gt; &lt;span class="pre"&gt;08&lt;/span&gt; &lt;span class="pre"&gt;日&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:parsed_literal:`RFC:&lt;/span&gt; &lt;span class="pre"&gt;:rfc:\`1459\``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;RFC:&lt;/span&gt; &lt;span class="target" id="index-0"&gt;&lt;/span&gt;&lt;a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc1459.html"&gt;&lt;strong&gt;&lt;span class="pre"&gt;RFC&lt;/span&gt; &lt;span class="pre"&gt;1459&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;For nested roles, the backquote &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;`&lt;/span&gt;&lt;/code&gt; in interpreted text needs to be escaped.&lt;/p&gt;
&lt;/div&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinxnotes-comboroles.rst&lt;/span&gt;, line 130); &lt;em&gt;&lt;a href="#id1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate implicit target name: &amp;quot;nested parse&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id="works-with-other-extensions"&gt;
&lt;h3&gt;Works with other Extensions&lt;/h3&gt;
&lt;p&gt;Not limited to &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/roles.html#standard-roles"&gt;Standard Roles&lt;/a&gt;, The extensions can also work with roles provided
by some other extensions.&lt;/p&gt;
&lt;section id="sphinx-ext-extlink"&gt;
&lt;h4&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.ext.extlink&lt;/span&gt;&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;a class="reference internal" href="#sphinx-ext-extlink"&gt;&lt;span class="pre"&gt;sphinx.ext.extlink&lt;/span&gt;&lt;/a&gt;&lt;/code&gt; is a Sphinx builtin extension to create
shortened external links.&lt;/p&gt;
&lt;p&gt;We have the following configuration, extlink creates the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;issue&lt;/span&gt;&lt;/code&gt; role,
then comboroles creates a &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;literal_issue&lt;/span&gt;&lt;/code&gt; role based on it:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;extlinks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="s1"&gt;&amp;#39;enwiki&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://wikipedia.org/wiki/&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;📖 &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="n"&gt;comboroles_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;    &lt;span class="s1"&gt;&amp;#39;literal_enwiki&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;enwiki&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:enwiki:`Lo&lt;/span&gt; &lt;span class="pre"&gt;Ta-yu`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Lo Ta-yu"&gt;📖 Lo Ta-yu&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal_enwiki:`Lo&lt;/span&gt; &lt;span class="pre"&gt;Ta-yu`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Lo Ta-yu"&gt;&lt;span class="pre"&gt;📖&lt;/span&gt; &lt;span class="pre"&gt;Lo&lt;/span&gt; &lt;span class="pre"&gt;Ta-yu&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonition seealso"&gt;
&lt;p class="admonition-title"&gt;参见&lt;/p&gt;
&lt;p&gt;Inspired by &lt;a class="reference external" href="https://github.com/sphinx-doc/sphinx/issues/11745"&gt;https://github.com/sphinx-doc/sphinx/issues/11745&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="sphinxnotes-strike"&gt;
&lt;h4&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinxnotes.strike&lt;/span&gt;&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;a class="reference internal" href="#sphinxnotes-strike"&gt;&lt;span class="pre"&gt;sphinxnotes.strike&lt;/span&gt;&lt;/a&gt;&lt;/code&gt; is another extension I wrote, which adds
&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;strikethrough text&lt;/span&gt; support to Sphinx:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;comboroles_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;   &lt;span class="s1"&gt;&amp;#39;literal_strike&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;literal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;strike&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strike:`text`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;text&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:literal_strike:`text``&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;&lt;span class="pre"&gt;text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="limitation"&gt;
&lt;h3&gt;Limitation&lt;/h3&gt;
&lt;div class="admonition warning"&gt;
&lt;p class="admonition-title"&gt;警告&lt;/p&gt;
&lt;p&gt;Due to internal implementation, the extension can only used to composite
simple roles and may CRASH Sphinx when compositing complex roles.
DO NOT report to Sphinx first if it crashes, please report to
&lt;a class="reference external" href="https://github.com/sphinx-notes/comboroles/issues/new"&gt;https://github.com/sphinx-notes/comboroles/issues/new&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="how-it-works"&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;Someone may be curious how the extension is implemented.
In fact, it is quite simple, about 30 lines of code.&lt;/p&gt;
&lt;section id="the-docutils-document-tree"&gt;
&lt;h3&gt;The Docutils Document Tree&lt;/h3&gt;
&lt;p&gt;Before going further, we need to have some basic understanding of
the &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/doctree.html"&gt;Document Tree&lt;/a&gt; of docutils &lt;a class="footnote-reference brackets" href="#id9" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; (hereafter referred to as doctree).
The doctree describes the data structure of a rST document (a &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.rst&lt;/span&gt;&lt;/code&gt; file) &lt;a class="footnote-reference brackets" href="#id10" id="id4" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;.
Here is a simplified diagram of the hierarchy of elements in the doctree,
we only focus on the highlighted lines:&lt;/p&gt;
&lt;div class="literal-block-wrapper docutils container" id="id16"&gt;
&lt;div class="code-block-caption"&gt;&lt;span class="caption-text"&gt;Element hierarchy of doctree &lt;a class="footnote-reference brackets" href="#id11" id="id5" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;+--------------------------------------------------------------------+
&lt;/span&gt;&lt;span data-line="2"&gt;| document  [may begin with a title, subtitle, decoration, docinfo]  |
&lt;/span&gt;&lt;span data-line="3"&gt;|                             +--------------------------------------+
&lt;/span&gt;&lt;span data-line="4"&gt;|                             | sections  [each begins with a title] |
&lt;/span&gt;&lt;span data-line="5"&gt;+-----------------------------+-------------------------+------------+
&lt;/span&gt;&lt;span data-line="6"&gt;| [body elements:]                                      | (sections) |
&lt;/span&gt;&lt;span data-line="7"&gt;|         | - literal | - lists  |       | - hyperlink  +------------+
&lt;/span&gt;&lt;span data-line="8"&gt;|         |   blocks  | - tables |       |   targets    |
&lt;/span&gt;&lt;span data-line="9"&gt;| para-   | - doctest | - block  | foot- | - sub. defs  |
&lt;/span&gt;&lt;span data-line="10"&gt;| graphs  |   blocks  |   quotes | notes | - comments   |
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="hll"&gt;+---------+-----------+----------+-------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="hll"&gt;| [text]+ | [text]    | (body elements)  | [text]       |
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="hll"&gt;| (inline +-----------+------------------+--------------+
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="hll"&gt;| markup) |
&lt;/span&gt;&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="hll"&gt;+---------+
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The highlight lines describe the content model of &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/doctree.html#toc-entry-14"&gt;Inline Elements&lt;/a&gt;.
All inline markups and roles we just discussed belong to inline elements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Inline elements &lt;em&gt;directly contain text data, and may also contain further inline elements&lt;/em&gt;. &lt;a class="footnote-reference brackets" href="#id12" id="id6" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;We already know that roles can not contain further roles, so we conclude that:
The limitation of inline nested markup is caused by rST's syntax, rather than
the rST's content model.&lt;/p&gt;
&lt;p&gt;By using the &lt;code class="docutils literal notranslate"&gt;&lt;a class="reference external" href="https://docutils.sourceforge.io/docs/user/tools.html#rst2pseudoxml"&gt;&lt;span class="pre"&gt;rst2pseudoxml&lt;/span&gt;&lt;/a&gt;&lt;/code&gt; command line, we can convert
rST source code to text representation of doctree:&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinxnotes-comboroles.rst&lt;/span&gt;, line 240)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;list-table&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;list-table&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;rST&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;doctree&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gs"&gt;**bold**&lt;/span&gt;  &lt;span class="s"&gt;``code``&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nt"&gt;&amp;lt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;source=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;untitled.rst&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;paragraph&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;         &lt;/span&gt;bold
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;         &lt;/span&gt;code
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Words enclosed in angle brackets &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;&lt;/span&gt;&lt;/code&gt; and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt; represent nodes of the doctree,
You can see that role &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:strong:`bold`&lt;/span&gt;&lt;/code&gt; is converted to a  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;/code&gt; node in
somehow (see next section) with interpreted text &amp;quot;bold&amp;quot; as its child.&lt;/p&gt;
&lt;p&gt;The doctree of &amp;quot;bold code&amp;quot; is a combination of &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;/code&gt; and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;literal&lt;/span&gt;&lt;/code&gt; node,
which looks like:&lt;/p&gt;
&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;       &lt;/span&gt;bold&lt;span class="w"&gt; &lt;/span&gt;code
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="dynamic-compositing"&gt;
&lt;h3&gt;Dynamic compositing&lt;/h3&gt;
&lt;p&gt;All roles of docutils are implemented in the same way &lt;a class="footnote-reference brackets" href="#id13" id="id7" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;5&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Define the Role Function, which receives the context of the parser,
creates and returns inline elements (nodes),
and does any additional processing required node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Register the Role, with a name, such as &amp;quot;strong&amp;quot;, then users can use it&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can simply create a role function, that returns a fixed combination like
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;text&lt;/span&gt;&lt;/code&gt;, but it is not cool. There may are many combinations of
various markups, I don’t want to implement them one by one. The better idea is:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;In the function, we look up role functions from a set of role names
and get the corresponding node by calling them&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nesting these nodes together&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note that not all node combinations make sense, it depends on the complexity
role function and the implementation of &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/builders/index.html"&gt;builders&lt;/a&gt;. Fortunately:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Most of markups's role function are very simple: They wrap
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;docutils.nodes.TextElement&lt;/span&gt;&lt;/code&gt; around the text &lt;a class="footnote-reference brackets" href="#id14" id="id8" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;6&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The most commonly used builder is HTML builder, in its view,
the combinations of nodes are combinations of HTML tags, which makes sense
in most cases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="the-code-implementation"&gt;
&lt;h3&gt;The code implementation&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.util.docutils.SphinxRole&lt;/span&gt;&lt;/code&gt; provides helper methods for creating roles
in Sphinx, we use it instead of defining role function directly:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;CompositeRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SphinxRole&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="c1"&gt;#: Rolenames to be composited&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;    &lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolenames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rolenames&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;run&lt;/span&gt;&lt;/code&gt; function is equivalent to the role function, but bounded with
the &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SphinxRole&lt;/span&gt;&lt;/code&gt; subclass we created:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;   &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here we look up role functions. &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_roles&lt;/span&gt;&lt;/code&gt; and &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_role_registr&lt;/span&gt;&lt;/code&gt; are unexported
variables of &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;docutils.parsers.rst.roles&lt;/span&gt;&lt;/code&gt; that store the mapping
from role name to role function:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;        &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_roles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_role_registry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;        &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_role_registry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;       &lt;span class="c1"&gt;# Error handling...&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;We can not look up during &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;__init__&lt;/span&gt;&lt;/code&gt;, some roles created by
3rd-party extension do not exist yet at that time.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Run all role function, pass parameters as is, then collect the returning nodes:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TextElement&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;    &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawtext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;                 &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inliner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;    &lt;span class="c1"&gt;# Error handling...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The returned nodes should be exactly one &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;docutils.nodes.TextElement&lt;/span&gt;&lt;/code&gt; and
contains exactly one &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;docutils.nodes.Text&lt;/span&gt;&lt;/code&gt; as a child, like this:&lt;/p&gt;
&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nt"&gt;&amp;lt;TextElement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Nesting nodes together by replace the &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Text&lt;/span&gt;&lt;/code&gt; node with the inner(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;i+1&lt;/span&gt;&lt;/code&gt;)
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;TextElement&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;before&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;replace&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;after&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;i=0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;i=1:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;i=0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;◄─┐
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;│&lt;span class="w"&gt; &lt;/span&gt;replace
&lt;/span&gt;&lt;span data-line="4"&gt;i=1:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;─┘
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="highlight-xml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;i=0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;literal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Now, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;nodes[0]&lt;/span&gt;&lt;/code&gt; is the root of node combination, just return it:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So the complete code looks like this:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;CompositeRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SphinxRole&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="c1"&gt;#: Rolenames to be composited&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;    &lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolenames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rolenames&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;        &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;                &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_roles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_role_registry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;                &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_role_registry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;               &lt;span class="c1"&gt;# Error handling...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;               &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;        &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TextElement&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;            &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawtext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;                         &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inliner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;            &lt;span class="c1"&gt;# Error handling...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;            &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;            &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The above code has been simplified for ease of explanation, for complete
implementation, please refer to &lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinx-notes/comboroles"&gt;⛺ sphinx-notes/comboroles&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="footnotes"&gt;
&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id9" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://docutils.sourceforge.io/"&gt;docutils&lt;/a&gt; is the main implementation of reStructuredText&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id10" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id4"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;It should be easy to understand if you know &lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Abstract Syntax Tree"&gt;📖 Abstract Syntax Tree&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id11" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id5"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;The Docutils &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/doctree.html"&gt;Document Tree&lt;/a&gt; - Element Hierarchy&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id12" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id6"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/doctree.html#toc-entry-14"&gt;Inline Elements&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id13" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id7"&gt;5&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="create-roles"&gt;Creating reStructuredText Interpreted Text Roles&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id14" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id8"&gt;6&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinxnotes-comboroles.rst&lt;/span&gt;, line 3); &lt;em&gt;&lt;a href="#id15"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate explicit target name: &amp;quot;creating restructuredtext interpreted text roles&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;a class="reference external" href="create-roles"&gt;Creating reStructuredText Interpreted Text Roles&lt;/a&gt; - Generic Roles&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/sphinxnotes-comboroles.html"/>
    <summary>Sphinx is a famous documentation generator used by a lot of Open Source
communities. It uses reStructuredText (hereafter referred to rST) as markup
language by default.</summary>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <published>2024-01-14T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/resign-for-painting.html</id>
    <title>辞职为学画（一）</title>
    <updated>2023-12-10T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇搁了好几年的草稿，后半段迟迟无法下笔，近年的心境已与那时大不相同，
现在写出来总觉得自己在说谎，只好把一部分摘出来，让它得以见天日。
希望有机会把后面的内容补完吧。&lt;/p&gt;
&lt;/div&gt;
&lt;p class="centered"&gt;
&lt;strong&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;如果有哪一天我获得了幸福，我就再也不画画了。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;今年&lt;/span&gt; &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;去年&lt;/span&gt; 前年 6 月的时候，我结束了在 &lt;a class="any any-event reference internal" href="notes/zxsys/index.html#event-c13f9cb" title="event 造型实验室"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，回家准备 &lt;a class="reference internal" href="notes/writeups/2021-interview/index.html"&gt;&lt;span class="doc"&gt;面试&lt;/span&gt;&lt;/a&gt;；9 月，入职杭州字节，还是写代码。这一年间有不少朋友听说了我的事情，问为什么突然辞了职去学画画；面试的时候也会被问，你为什么选择这么做，现在怎么又回来了云云，我也一遍又一遍地重复着准备好的说辞。&lt;/p&gt;
&lt;p&gt;我有个坏毛病，在人前时总想着说些漂亮话，羞于暴露自己「和别人不一样」的一面：&lt;/p&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;某&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;你辞职是为了追求梦想吗？&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;我&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;我就玩一玩，玩够了就接着回来打工，说不定到时候还要你帮忙内推呢😂️&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;回答差不多总是这样子，并不是说谎，我不期望这一年里能画出什么名堂，计划上过了一年就回来继续上班，结果上也确实如此。只是回想起这些话，总觉得难过，有些对不起自己。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我不是这样想的。&lt;/em&gt;&lt;/p&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;模糊的萌芽&lt;/h2&gt;
&lt;p&gt;我从小喜欢画画，但画画是什么东西？我从来没想过。&lt;/p&gt;
&lt;p&gt;三年级的时候因为搬家转学，新学校的体育老师是个白了一半头发的大肚子爷爷，村里的小学没有什么体育设施可言，每次上课的时候只要让大家在沙地上集合点名，从储物间里拉出两箩筐七零八落的器材，大家一拥而上，先到先得。箩筐里有凑不成对儿的铁质羽毛球拍、花花绿绿的跳绳、总是不太有精神的篮球。爱打球的小朋友要是没抢到打满了气的好球，可以跟老师要球针，憋红了脸吹一吹还能顶一节课。&lt;/p&gt;
&lt;p&gt;学校那会儿已经盖起了三层的教学楼，但体育老师的办公室还在平房的一个小单间里，没课的时候他在屋里画国画，那个时候他就是我的对画画认知的全部来源。我已经忘记我是怎么缠着他跟他要画儿的，能记得的是他给过我两张画，其中一张题字「小草」，前景是浓墨画的一奇石、两丛草，远景是淡淡的三座山。我将其视作珍宝，在还没长大的很长一段时间内，我的所谓「画画」就是一遍又一遍地，临摹老师送我的这张小画。&lt;/p&gt;
&lt;p&gt;那时候还太小，临摹里没有加入任何的思考，画了百十张自然也收获缺缺，尽管如此也能收获周围的小朋友的夸赞。现在想来，我和他们的区别仅仅是我能坐得住，能在不用上课的日子里，趴在顶层的楼梯间里一声不吭地画一个下午罢了。&lt;/p&gt;
&lt;p&gt;长大了一点开始能看懂非低龄向的动画片，星空、华娱那时候会播各种引进的动画片，《火影忍者》、《魔法少女小樱》、《犬夜叉》、《闪灵二人组》…… 我的兴趣就从涂墨水变成了临摹纸片人。现在回想起来感慨得很，我的哥哥姐姐那时候也和我一起看，为什么只有我长大之后成了老二次元呢？&lt;/p&gt;
&lt;p&gt;喜欢这些动画片很大原因是因为里边炫酷的打打杀杀，自己也会画很多小人打打杀杀的场面，大部分在课本上，哪一科的老师越无聊，书上的战斗就越精彩些。「正经」画画的时候会临摹各种印刷品上的纸片人，可能是作业本的封面，也可能是特地买的动画片贴纸。我不是一个非常耐心的人，用自动铅匆匆把线稿画好之后，就想着快点勾线，上色，享受「完成」的成就感。这样画出来的形象，其实是非常不准的，但和更小的时候一样，同学们都不画画，就显得我画得很好一样 —— 直到我的姐姐画了她的第一张画。&lt;/p&gt;
&lt;p&gt;姐姐是一个极聪明又有耐心的人，就我所知平时也不画画，有一天她突然窝在房间里很久，出来时给我看一张犬夜叉的线稿：非常干净的线，而我的纸上全是橡皮揉擦的痕迹。更重要的是，这太像了，和原画的观感一模一样，我甚至怀疑这是拓印的，但这显然不可能，姐姐不会说谎，两张画的大小也不一样。&lt;/p&gt;
&lt;p&gt;这件事情在当时让我有些妒忌，但长远看来没有什么其他影响。姐姐之后就不再画了，她的时间更多的花在课业上，而我也没有被触动然后奋发图强云云。现在想起，只是感叹 &lt;em&gt;自己「没有天赋」这件事情，从很早以前就有迹可循了&lt;/em&gt; 。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;勤奋的兴趣生&lt;/h2&gt;
&lt;p&gt;中考我差了三分没能上区一中，去到了顺位下来的另一个高中。这个学校文化课成绩不好不坏，美术倒是无可争议的全区第一（社团活动也很丰富，我在这里有了编程的启蒙）。那时我尚不懂「美术高考」为何物，只知道大家都是在教室里上课，一年升一级，参加一样的考试，划线决定下一个学校。对于这种认知外的选择，我根本不会去有什么妄想。&lt;/p&gt;
&lt;p&gt;学校在高一学生里招募打算参加艺考的学生组成专业班，同时也开设了画着玩儿的兴趣班。专业班的同学连续三年都由同一个美术老师指导，前两年下午放学后都要到艺术楼的画室里画画，最后一年则是外出集训，学生外出集训的当年老师便兼任兴趣班。因此兴趣班只持续一年，只接待高一的学生，强度上自然也不如专业班，退出机制也简单：不想上，就不上了呗。&lt;/p&gt;
&lt;p&gt;对这些事情有了解都是后来的事情了，当时听到兴趣班的消息的我充满了一种对未知的好奇，这听起来是在我认知内的：不需要慎重的考虑，一学期一百块钱的材料费就能上。于是我兴冲冲报了名，还反复考虑：「在要不要去的时候把以前的画给老师看」，「老师会不会夸我啊」云云。&lt;/p&gt;
&lt;p&gt;上课之前要准备铅笔和纸。我一直以为，只要是白纸就能画画，之前画「国画」虽然知道老师用的是宣纸，也从来没想过去买，一直用的是家里撕下的日历纸，白且大，当然「枯干渴润湿」的变化就不用想了，这样的纸仅仅是能沾上墨而已。当时住校也没有日历纸，我带上了平时做作业用的本子。&lt;/p&gt;
&lt;figure class="align-default" id="id12"&gt;
&lt;img alt="https://silverrainz.me/_images/14340257593_652377082.jpg" src="https://silverrainz.me/_images/14340257593_652377082.jpg" style="width: 70%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;网上找到的同款图片&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;封面看起来比小时候用的厚多了&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;到了画室才发现大家带的纸和我不一样，足足有一张小课桌那么大，装在一个同样大的袋子里。画室里的桌子看起来好少，中间的空地上摆了非常多的木架，架上放着一块块的「砧板」。在一大堆人里我开始局促不安，想给老师看画的念头完全抛到了脑后，取而代之的是各种各样的疑问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;为什大家的纸都和我不一样……&lt;/div&gt;
&lt;div class="line"&gt;桌子那么少，我现在是不是没位置了……&lt;/div&gt;
&lt;div class="line"&gt;我带着做作业的本子会不会很好笑……&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;老师让大家把纸贴在「砧板」上，竖着放上架子 —— 铅笔削尖 —— 手伸直 —— 练习「拉线」。我硬着头皮把从本子上小小的纸撕下，贴在了大大的板子上，拿起红黑相间的中华铅笔，僵硬地伸直手，左一下，右一下，拉起线来。&lt;/p&gt;
&lt;p&gt;不一会儿我就知道了，这是素描纸，这是画架，这是 &lt;a class="any any-artwork reference internal" href="any-artwork.size.html#cap-4k" title="artwork 4k"&gt;&lt;code class="xref any any-artwork.size docutils literal notranslate"&gt;&lt;span class="pre"&gt;四开&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; 大的画板，我要画的是 &lt;a class="any any-artwork reference internal" href="any-artwork.medium.html#cap-铅笔" title="artwork 铅笔"&gt;&lt;code class="xref any any-artwork.medium docutils literal notranslate"&gt;&lt;span class="pre"&gt;素描&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;。我当然听过「素描」，难堪里不由得又冒出几分激动，于是更认真地在小小的一方纸上来回拉线，满心想让老师快点注意到我，以后教我更多的东西。&lt;/p&gt;
&lt;p&gt;拉几条线当然不能让老师注意到我，但不久后这个愿望还是实现了：每上一堂课，周围的人就少一大半，也许是觉得整天画线很无聊吧，到了画几何体结构的时候，人员基本上稳定在了十来人。某天老师在衬布上摆了一个石膏罐和几个水果，说你们几个可以不用画几何体了，来画静物，带光影的。&lt;/p&gt;
&lt;p&gt;于是我们围着石膏罐坐下，换纸，削笔，一开始大家的画板都是横着放的，在下一张画的时候也未曾想要改变。可我却觉得面对这组静物，取景框是横的显得奇怪 —— 于是我把画板竖了起来。老师看见一堆画板里只有我的构图是竖着的，便过来夸奖了我一番，也许是从那个时候记住了我的名字？这就无从得知了。&lt;/p&gt;
&lt;figure class="align-default" id="id13"&gt;
&lt;img alt="https://silverrainz.me/_images/1634486382099.jpg" src="https://silverrainz.me/_images/1634486382099.jpg" style="width: 70%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;第一张全因素素描&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;初学者的第一张画，除了构图之外再没有可圈可点之处了。当然那时候不这么想，我是一个极渴望被夸奖但又不敢表露的人，老师的夸奖给了我非常大的动力。我开始严格规划自己的每一天：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;中午不休息，回寝室借着中午的太阳晒热的水洗澡（那时候宿舍没接热水，打水洗澡浪费时间）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;那时候已经参加了计算机社团，洗完澡有时会去图书馆看 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/电脑爱好者"&gt;📖 电脑爱好者&lt;/a&gt;，或者用自己的小小手机看提前下载好的技术资料&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;下午一放学就飞奔到艺术楼，开始上课&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;六点五十，匆匆下楼到小卖部买两块钱一杯的奶茶和一块钱一个的奶油面包，赶在七点夜自修铃响之前回教室吃&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样的生活持续了大半个高一，时至今日，想起奶油面包的味道我还是觉得想吐，&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;奶茶倒没有喝腻&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;努力当然就会有起色，与此同时隔壁专业班的学生还处于享受高中生活的懒散阶段，大家慢慢知道隔壁兴趣班有个画得比专业班还好的小个子，上课的时候会有人从隔壁探过头来看，我的虚荣心那时候得到了极大的满足。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;可惜留给我的时间不多了。&lt;/em&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;span id="id5"&gt;&lt;/span&gt;&lt;h2&gt;努力与选择&lt;/h2&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/resign-for-painting.rst&lt;/span&gt;, line 106); &lt;em&gt;&lt;a href="#id5"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate implicit target name: &amp;quot;努力与选择&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;艺术楼里有三间画室，在我高一那年，从外到里分别是，兴趣班，高一专业班，高二专业班。每天准备离开的时候，其他画室基本上都没人了，我会开灯溜进去看看他们在画什么。&lt;/p&gt;
&lt;p&gt;排除有童子功的同学，美术生的画力基本是按年级来分的。&lt;/p&gt;
&lt;p&gt;高一开始基本只用四开的板子，画瓶瓶罐罐石膏体，上学期末或者下学期开始摸一摸水粉。&lt;/p&gt;
&lt;p&gt;高二画石膏像、人像、更复杂的静物组合，画得好的同学可以开一张半开的 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/大卫像"&gt;📖 大卫像&lt;/a&gt;，收获一整个画室艳羡的目光。&lt;/p&gt;
&lt;p&gt;到了高三，画室慢慢变宽敞起来，学长学姐们已经把在基础课都走过一遍，放眼望去静物架上个个是老相识了。他们开始挑选集训的画室，想考清华央美的就去北京，想考国美的去杭州，想留在省内的，那就去广州。&lt;/p&gt;
&lt;p&gt;集训回来后的学长学姐明显不一样了：速写再不需要起稿，一出手型就是准的，画出的线条没有磕磕绊绊的感觉。完成的一张画里很难找出哪里有不和谐的地方，似乎他们对如何在纸面上模拟这个世界，有了十足的把握。&lt;/p&gt;
&lt;p&gt;这样的分层给我一种错觉：只要我升上高年级，我也能画得和他们一样好吧。我没有想到的是， &lt;em&gt;因为选择不同，我和专业生们走上了截然不同的道路。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;高一的第一个寒假，和我过去的任何一个长假一样：我在家里呆着，看电视，写作业。和之前不同的是，我是一个画画的人了，我得画画呀。我买了一本那时候很流行的于小冬速写集，只要把这本书临完，我也可以不用起稿了吧？我还想画素描，从画室借了一本静物书，没有画架，就把四开纸铺在地上趴着画。&lt;/p&gt;
&lt;figure class="align-default" id="id14"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_0274.jpg" src="https://silverrainz.me/_images/IMG_0274.jpg" style="width: 70%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;寒假在家临摹的唯一一张素描&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;签名是回学校之后让伟敏帮我签的，我那时候还没开始「练字」&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;看起来是很积极的规划，假期很快过去了，我并没有画多少张。&lt;/p&gt;
&lt;p&gt;回想起来我一直是这样的，总会在某个时间段的开始给自己画一张美好的蓝图，&lt;em&gt;填满时间表给我一种掌控一切的愉悦感，而这份愉悦总会在接下来的实施里统统还回去。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;寒假结束，回到画室，我一边懊悔着虚度的寒假，一边祈祷着同学们假期只顾着疯玩，最好一张都没有画。实际情况是，专业班的学生们按照惯例参加了校外的画室。这个寒假的几乎每一天，他们都在画画 ——&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;我兴奋地规划自己的时间表，他们在画画；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我不慌不忙地写寒假作业，他们在画画；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我看电视，写代码，他们在画画；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;当我终于觉得自己应该画画的时候，老师也许在给他们改画了；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个寒假过后，我已经画得不如他们了 —— &lt;em&gt;选择走专业的他们，在正确的引导下付出了压倒性的时间成本。在这些面前，我的那么点努力算什么呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;在之后的好多年里，我陷入了对自己是否热爱画画的反复质疑。&lt;/p&gt;
&lt;figure class="align-default" id="id15"&gt;
&lt;img alt="https://silverrainz.me/_images/%E7%81%AB%E7%8B%90%E6%88%AA%E5%9B%BE_2022-03-13T12-22-12.184Z.png" src="https://silverrainz.me/_images/%E7%81%AB%E7%8B%90%E6%88%AA%E5%9B%BE_2022-03-13T12-22-12.184Z.png" style="width: 70%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;挂在艺术楼里的优秀作业 &lt;a class="footnote-reference brackets" href="#id10" id="id6" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;我以为这是我「永远」都达不到的高度。&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;编外人员的挣扎&lt;/h2&gt;
&lt;p&gt;高二，文理分科。对于专业生而言，如果后悔学美术了，这是不算太晚的退出时机；而对于想要转专业的兴趣生，这也是能赶上进度的最后机会，如果不转的话，兴趣生的课程也就结束了。&lt;/p&gt;
&lt;p&gt;这时候专业生们要面临的道路，对我来说已经不再是认知外的事情了，甚至，它们成为了我生活中习以为常的一部分 —— 我动了一点想转专业的心思。&lt;/p&gt;
&lt;p&gt;拦在我面前的问题有两个：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;学画画很花钱，在 2012 年的时候，普通的外出集训的也要每月近万（其实我没有真正了解过，但印象是这样），即使集训完，艺术类专业的花销比普通专业依然大得多&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在家里人看来，画画是文化课不好的孩子的选择，我的成绩还不赖，没有冒险换赛道的必要&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我委婉地，旁敲侧击地跟父母表达了我的想法，自然没有得到支持。我也不争不吵，生了几天闷气后，一头扎进在时间的河里顺流而下。等再浮出水面的时候，我已经是高二的理科生了。&lt;/p&gt;
&lt;p&gt;高一带我兴趣班的 &lt;a class="any any-people reference internal" href="about/people.html#people-1" title="people 蔓纯老师"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，送走了带了三年的专业生，现在开始带高一的专业班，一直持续到他们高三出去集训。
其实我在之前就和蔓纯老师表达过我的忧虑，她说没关系，到时候你可以来高一的画室画。&lt;/p&gt;
&lt;p&gt;尽管得到了这样的许诺，开学后我也没有马上回到画室。每天下课后就和同学一样排队洗澡，去食堂吃热腾腾的饭菜，多出来的时间就四处游荡。可能是觉得回去搞特殊很害羞，也可能是心生了退意，毕竟我 ——「并不是真的热爱画画」。&lt;/p&gt;
&lt;p&gt;但学期近半的时候我还是回去了，那一天好像安排了大扫除，下午放学比平时早些。蔓纯老师看到我的时候挺惊讶，以为我不会再来了，怪我为什么没有一开学就过来，本来要交的材料费也帮我免掉了：是的，瞒着父母回画室的我，连一百块钱的都拿不出。就这样，我回归了画室生活。&lt;/p&gt;
&lt;p&gt;回看那段生活是沉闷的，我的痛苦就是从那时候开始悄悄滋长。在一堆高一的小同学面前我好像虚长了一级，明明是学长卻还怯生生的 —— 于是我用沉默来避免露怯。老师推荐我画水彩，说既然不考学，就没有必要画枯燥的素描（尽管我从来不这么觉得）。&lt;/p&gt;
&lt;p&gt;学新媒介是好事，可是水性材料并没有那么好入门，在竖着的画架上，流动的水更加难以控制，这样的困难让我变得很沮丧。老师很忙，顾不上我，绝大部分的时间我只能自己画；来画室不再是一件值得期待的事情。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;很后来才知道画水彩应该用水平式的画架，比如：&lt;a class="extlink-search reference external" href="https://duckduckgo.com/?q=荷尔拜因 WL-63"&gt;🔍 荷尔拜因 WL-63&lt;/a&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;后来慢慢和画室里的一些可爱学弟熟悉了，我才不那么沉默，但没办法开心起来：&lt;em&gt;我自然而然地升上了高二了，可我没有自然而然地变得厉害起来&lt;/em&gt;。我眼睁睁地看着隔壁同级的专业生开始画石膏，画人像，粗糙的线条慢慢收敛得干净，干瘪的造型也慢慢变得饱满。我们已经不在一条道路上了，差距越来越大本就正常。可是我却没理由地怪罪自己，把自己的止步不前和他们的飞速进步通通归咎于自己的不努力，自己不够热爱画画。&lt;/p&gt;
&lt;p&gt;在这样的自戕里，我变得自卑，敏感，外化出来的是情绪的剧烈波动和无休止的嗜睡。那个时候的小孩总会有些别的烦恼，我也一样不缺， &lt;em&gt;这些东西后来纠集在一起，滋生了一只黑狗紧跟我至今。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;无论狗来不来，时间都不会停下脚步，高二下学期，高考的紧张感已经慢慢浮现了，我开始觉得自己不应该把多余的精力分摊在画画和编程上了，于是我退出了社团，告别了画室。&lt;/p&gt;
&lt;p class="centered"&gt;
&lt;strong&gt;待续……&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section id="id8"&gt;
&lt;h2&gt;追记：害羞还是怯弱？&lt;/h2&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;在写下这段文字的时候才我意识到，那时候最遗憾的事情既不是没有钱，也不是父母的偏见，而是我从来都没有考虑表达自己的真实感受。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;从小到大我总是被教育要懂事，给人添麻烦是不懂事，想要喜欢的东西是不懂事。等我意识到自己被塑造成了一个羞于表达需求的小孩儿时，我的脸上早就没有一点小孩子的痕迹了。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;要是我那时候那时候和父母争吵一番呢？我想要画画，我想要和他们一样变得厉害，我想要确认自己不是不喜欢画画。结局我想不会改变，可是我心里那颗不甘心的种子，就不会种下了吧。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;写下上面这段话的时候还是 21 年的年底，两年过去，我又不太赞同那时候的自己了。我一直是个极端厌恶风险的人，所谓「没有表达自己的真实感受」也只是没有下定决心想要画画，如果我表达出来了，那我又该如何和别人展示自己那不存在的决心呢？&lt;/p&gt;
&lt;p&gt;2023 年 12 月 10 日，我觉得自己是个胆小鬼。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h2&gt;脚注&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id10" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id6"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://silverrainz.lofter.com/post/39aab0_3e1e1f2"&gt;谷月轩 &amp;#64; LOFTER 2014/11/25&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/resign-for-painting.html"/>
    <summary>这是一篇搁了好几年的草稿，后半段迟迟无法下笔，近年的心境已与那时大不相同，
现在写出来总觉得自己在说谎，只好把一部分摘出来，让它得以见天日。
希望有机会把后面的内容补完吧。</summary>
    <category term="生活" label="生活"/>
    <category term="绘画" label="绘画"/>
    <published>2023-12-10T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/paper-size.html</id>
    <title>纸张尺寸标准以及非标准纸张的收纳技巧</title>
    <updated>2022-06-26T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/paper-size.rst&lt;/span&gt;, line 11)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;math&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;math&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;之前画的大量小创作基本都是在 32K 的小张水彩纸上画的，然后装在蔓纯老师送我的正好 32K 的小画册 &lt;a class="any any-artwork reference internal" href="any-artwork.album.html#cap-album-32k-1" title="artwork album-32k-1"&gt;&lt;code class="xref any any-artwork.album docutils literal notranslate"&gt;&lt;span class="pre"&gt;album-32k-1&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; 里。后来画了一点 &lt;a class="any any-artwork reference internal" href="any-artwork.html#cap-铅笔" title="artwork 铅笔"&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;素描&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; 和 &lt;a class="any any-artwork reference internal" href="notes/zxsys/way-to-artist/find-language.html#artwork-xfczk3-ac-000" title="artwork 丙烯"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，分别用了阿诗的素描纸（310×230 mm）与哈内姆勒的水彩纸（300×240mm），他们的的尺寸比 A4（297×210 mm）大一点，又比 A3（420×297 mm）小不少，收纳起来很尴尬。&lt;/p&gt;
&lt;p&gt;我开始在网上寻找合适的收纳册，发现只有办公用的 A2 A3 A4 系列最好找，连老师送我的这种 32 开本都不是那么常见，更不用说上面这种国内不流行的尺寸了。&lt;/p&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;纸张尺寸标准&lt;/h2&gt;
&lt;p&gt;从 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/纸张尺寸"&gt;📖 纸张尺寸&lt;/a&gt; 入手，简单了解了一下现行的一些纸张尺寸的标准和习惯：&lt;/p&gt;
&lt;section id="sqrt-2-1"&gt;
&lt;h3&gt;&lt;span class="math notranslate nohighlight"&gt;\(\sqrt{2}:1\)&lt;/span&gt; 是巧妙的宽高比&lt;/h3&gt;
&lt;p&gt;&lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/ISO 216"&gt;📖 ISO 216&lt;/a&gt; 规定了纸张的宽高比为 &lt;span class="math notranslate nohighlight"&gt;\(\sqrt{2}:1\)&lt;/span&gt;，&lt;em&gt;这种比例的纸对折后得到面积变为原来的一半，但宽高比不变&lt;/em&gt;。设纸张的宽为 &lt;span class="math notranslate nohighlight"&gt;\(x\)&lt;/span&gt;，高为 &lt;span class="math notranslate nohighlight"&gt;\(y\)&lt;/span&gt;，列出 &lt;span class="math notranslate nohighlight"&gt;\(x/y = y/(x/2)\)&lt;/span&gt; 可以很容易得到 &lt;span class="math notranslate nohighlight"&gt;\(x:y = \sqrt{2}:1\)&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;ISO 216 的各系列纸张的不同规格，都由符合该比例的最大规格对裁得来。例如我们常说的 A4 纸就是 ISO 612 中 A 系列的一种规格。最大的 A0 的对裁得到 A1，再对裁是 A2，A3、A4 以此类推。&lt;/p&gt;
&lt;figure class="align-default" id="id23"&gt;
&lt;img alt="https://silverrainz.me/_images/791px-A_size_illustration2_with_letter_and_legal.svg.png" src="https://silverrainz.me/_images/791px-A_size_illustration2_with_letter_and_legal.svg.png" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Paper_size#/media/File:A_size_illustration2.svg"&gt;ISO 612 A 系列纸张&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;对裁的好处在于变换尺寸方便，厂商只需要生产最大规格的纸张，不会产生边角料。比例不变的好处在于扩印和缩印都不会影响排版。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="iso-612-abc"&gt;
&lt;h3&gt;ISO 612 A、B、C 系列&lt;/h3&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;A&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;A0 的面积为 1 平米。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;B&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;B0 的宽边长度为 1 米，因此面积为 &lt;span class="math notranslate nohighlight"&gt;\(\sqrt{2}\)&lt;/span&gt; 平米，相同规格的 B 系列比 A 系列大。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-odd"&gt;C&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;C 系列的尺寸是 A 和 B 尺寸的几何平均，即同规格纸的面积 &lt;span class="math notranslate nohighlight"&gt;\(B &amp;gt; C &amp;gt; A\)&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;C 系列主要用于信封、文件夹，例如邮政 EMS 的 A4 信封的大小为 324×229 mm &lt;a class="footnote-reference brackets" href="#id16" id="id4" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;，就是标准的 C4 大小。同理，A2 纸可被放进 C2 的信封。&lt;/p&gt;
&lt;figure class="align-default" id="id24"&gt;
&lt;img alt="https://silverrainz.me/_images/dbb4786bf848ce57.jpg" src="https://silverrainz.me/_images/dbb4786bf848ce57.jpg" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;京东上出售的邮政信封袋&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="d"&gt;
&lt;h3&gt;国标 D 系列、正度纸、大度纸&lt;/h3&gt;
&lt;p&gt;国标 &lt;a class="reference external" href="http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=20746CFEE63514B24DD64A415CB65377"&gt;GB/T 148-1997&lt;/a&gt; 增设了 D 系列的标准，称为「标准印张」。其不严格遵守 &lt;span class="math notranslate nohighlight"&gt;\(\sqrt{2}\)&lt;/span&gt; 的宽高比，仅仅是近似。D 系列规格短边的长度比更小一号规格的长边大 4mm ，而不是通过对裁得到。&lt;/p&gt;
&lt;p&gt;同规格的 D 系列纸比 A 系列稍小，因此国内又称 D 为正度纸，A 为大度纸 &lt;a class="footnote-reference brackets" href="#id17" id="id5" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="k"&gt;
&lt;h3&gt;K 是一个模糊概念&lt;/h3&gt;
&lt;p&gt;K，开，即 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/开本"&gt;📖 开本&lt;/a&gt; 。这个概念看起来只在部分东亚国家使用 &lt;a class="footnote-reference brackets" href="#id18" id="id7" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; ，你甚至可以看到有 &lt;a class="reference external" href="https://www.taobaotranslate.com/paper-size-guide-taobao/paper-sizes-guide.html"&gt;向外国人科普淘宝上 N 开纸多大&lt;/a&gt; 的教程。&lt;/p&gt;
&lt;p&gt;对于不同的标准印刷纸张，一张（全张）称之为全开（1K），半张称对开（2K），四分之一张称四开（4K），八开（8K）以此类推。 &lt;em&gt;N 开纸的具体大小取决于全张大小。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;通常情况下的 K 的大小是相对于 D 系列纸，也就是正度纸而言的&lt;/em&gt; ，例如国产的温州雪山素描纸，4K 的大小为 530×380 mm，接近于 D2 净尺寸 528×380 mm：&lt;/p&gt;
&lt;figure class="align-default" id="id25"&gt;
&lt;img alt="https://silverrainz.me/_images/2022-06-26_151801.png" src="https://silverrainz.me/_images/2022-06-26_151801.png" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="http://www.xueshanpaper.com/product.asp"&gt;雪山 180g 4K 20张 袋装素描纸&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;法国康颂在国内卖的 1557 水彩纸，4K 的大小为 540×390 mm，是 D2 的毛尺寸：&lt;/p&gt;
&lt;figure class="align-default" id="id26"&gt;
&lt;img alt="https://silverrainz.me/_images/2022-06-26_195006.png" src="https://silverrainz.me/_images/2022-06-26_195006.png" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;麦克美迪代理的康颂 1557 素描纸&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;但其实康颂官网上的 1557 并没有列出在国内卖的规格：&lt;/p&gt;
&lt;figure class="align-default" id="id27"&gt;
&lt;img alt="https://silverrainz.me/_images/2022-06-26_151850.png" src="https://silverrainz.me/_images/2022-06-26_151850.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="reference external" href="https://en.canson.com/1557r-180gm2"&gt;康颂官网上的 1557 规格表&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;也有相对于 A 系列的，也就是大度纸而言的说法， &lt;em&gt;比如大四开就是指 A2&lt;/em&gt; &lt;a class="footnote-reference brackets" href="#id19" id="id8" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id12"&gt;
&lt;h3&gt;纸张尺寸查询&lt;/h3&gt;
&lt;p&gt;&lt;a class="reference external" href="https://papersizes.io/chinese/"&gt;Papersizes&lt;/a&gt; 是个非常方便的查询各种纸张尺寸的网站，值得单独一列。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id14"&gt;
&lt;h2&gt;收纳非标准尺寸纸张&lt;/h2&gt;
&lt;p&gt;我要收纳的其实就是各种大小的纸本画，蔓纯老师又给我支了一招。如前述，常见的收纳册都是 A 系列的标准尺寸，不太可能找到大小和画一样的收纳册。这些册子内页往往是薄膜材质，把小一圈的画放进去会溜来溜去，甚至有掉出来的可能。&lt;/p&gt;
&lt;p&gt;举个例子，我买了这种 A4 收纳册（内页 297×210 mm）：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/1869452119.jpg" src="https://silverrainz.me/_images/1869452119.jpg" style="width: 60%;" /&gt;
&lt;/figure&gt;
&lt;p&gt;想要放入 260×180 mm 的 &lt;a class="any any-artwork reference internal" href="notes/zxsys/way-to-artist/find-topic.html#artwork-xfczk2-042" title="artwork 强盗的造访"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 我们可以用用 &lt;em&gt;A4 印刷纸作为内衬&lt;/em&gt; ，把画放在印刷纸中间，用笔标出沿着四个角的位置（不要画到画上）：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/2080164623.jpg" src="https://silverrainz.me/_images/2080164623.jpg" style="width: 60%;" /&gt;
&lt;/figure&gt;
&lt;p&gt;之后把画拿开，用小刀沿着标记在刚才被画覆盖到的部分划出一条缝，再把画插入刚刚划出的缝里。如果一个内页要放两张画，每张像这样只用两个角固定就好了：&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="https://silverrainz.me/_images/1681336658.jpg" src="https://silverrainz.me/_images/1681336658.jpg" style="width: 60%;" /&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="id15"&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id16" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id4"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.ems.com.cn/packaging_services"&gt;中国邮政速递物流&lt;/a&gt; 封套规格标准&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id17" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id5"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://zhidao.baidu.com/question/4734526"&gt;正度纸_百度百科&lt;/a&gt; 不知道为啥这里的正度纸尺寸比 D 类少了 4mm&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id18" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id7"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Paper_size#K"&gt;📖 Paper_size#K&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id19" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id8"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://zhidao.baidu.com/question/154617481.html"&gt;大4开的纸尺寸是多少&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/paper-size.html"/>
    <summary>No role entry for "math" in module "docutils.parsers.rst.languages.zh_cn".
Using English fallback for role "math".</summary>
    <category term="印刷" label="印刷"/>
    <category term="绘画" label="绘画"/>
    <published>2022-06-26T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/when-go-generics.html</id>
    <title>何时使用 Go 泛型</title>
    <updated>2022-06-03T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="go"&gt;

&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;这篇文章是 &lt;a class="reference external" href="https://go.dev/blog/when-generics"&gt;When To Use Generics&lt;/a&gt; 的中文翻译，作者是 Go Team 的 &lt;a class="extlink-ghuser reference external" href="https://github.com/ianlancetaylor"&gt;👤 ianlancetaylor&lt;/a&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;介绍&lt;/h2&gt;
&lt;p&gt;Go 1.18 新增了一个重大的语言特性：泛型。本文不会描述泛型是什么以及如何使用它们。本文的重点是：&lt;em&gt;什么时候应该在代码中使用泛型，什么时候不使用它们&lt;/em&gt;。&lt;/p&gt;
&lt;div class="admonition- admonition"&gt;
&lt;p class="admonition-title"&gt;译者注&lt;/p&gt;
&lt;p&gt;关于泛型的简要介绍，可以看看 &lt;a class="reference internal" href="blog/funtional-programming-in-go-generics.html"&gt;&lt;span class="doc"&gt;函数式编程在 Go 泛型下的实用性探索&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;需要明确的是，这里提供的是通用的准则而非硬性的规定。请结合你自己的判断。但如果你拿不准，建议还是采用本文提供的准则。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;编码&lt;/h2&gt;
&lt;p&gt;让我们从 Go 编程的一般准则开始：通过编写代码编写 Go 程序，而不是通过定义类型编写 Go 程序。&lt;/p&gt;
&lt;div class="admonition- admonition"&gt;
&lt;p class="admonition-title"&gt;译者注&lt;/p&gt;
&lt;p&gt;这里的意思可能类似软件工程中的「避免过度设计」。
对于一般的编程来讲，我们应优先选择通过编写代码来实现逻辑，而非设计符合该逻辑的类型。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;涉及到泛型，如果你通过定义类型参数约束（type parameter constraints）来作为编程的第一步，那么你可能走在了错误的道路上。请从编写函数开始。当你写完之后，你就会清楚泛型对这个函数是否有用，此时再添加类型参数（type parameters）也是非常简单的。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="type-parameter"&gt;
&lt;h2&gt;何时使用 type parameter&lt;/h2&gt;
&lt;p&gt;让我们看看在哪些情况下，类型参数是有用的。&lt;/p&gt;
&lt;section id="id4"&gt;
&lt;h3&gt;当使用内置容器类型时&lt;/h3&gt;
&lt;p&gt;一种情况是，当你编写对语言定义的器器类型进行操作的函数：slice、map 和 channel。 如果函数参数中存在对应的类型，并且函数代码没有对元素的类型做出任何特定假设，那么使用 type parameter 可能很有用。&lt;/p&gt;
&lt;p&gt;例如，这是一个返回任意类型 map 中所有 key 的函数:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// MapKeys returns a slice of all the keys in m.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;// The keys are not returned in any particular order.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MapKeys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nx"&gt;Val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这段代码对 map 的 key 的类型没有任何的假设，它也根本不使用 map 的 value。所以它适用于任何 map 类型，这使它成为使用 type parameter 的好选择。&lt;/p&gt;
&lt;p&gt;在这里，类型参数的替代实现通常是使用反射，但这是一个更别扭的编程模型：没有静态类型检查，并且在运行时通常更慢。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;当编写通用数据结构时&lt;/h3&gt;
&lt;p&gt;类型参数可能有用的另一种情况是用于编写通用数据结构。 通用数据结构类似于 slice 或 map，但不是语言内置的，例如链表或二叉树。&lt;/p&gt;
&lt;p&gt;在之前，这样的数据结构通常会有两种实现方式：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;硬编码，只支持特定的元素类型；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用 type parameter 替换特定元素类型可以生成更通用的数据结构，可以在程序的其他部分或其他程序中使用。用类型参数替换 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt; 则可以让数据更高效地存储数据，节省内存资源；它还可以允许代码避免类型断言（type assertion），并在编译时进行全面的类型检查。&lt;/p&gt;
&lt;p&gt;下面节选了用 type parameter 实现的二叉树作为例子:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// Tree is a binary tree.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="c1"&gt;// A node in a Tree.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="c1"&gt;// find returns a pointer to the node containing val,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="c1"&gt;// or, if val is not present, a pointer to where it&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="c1"&gt;// would be placed if added.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;bt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="c1"&gt;// Insert inserts val into bt if not already there,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="c1"&gt;// and reports whether it was inserted.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="39"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="40"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;树中的每个节点都包含类型参数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 的值。当使用特定类型参数实例化 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 类型时，该类型的值将直接存储在节点中，它们不会被存储为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这是对 type parameter 的一种合理使用，因为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 本身包括其方法的逻辑，在很大程度上是和元素类型 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 无关的。&lt;/p&gt;
&lt;p&gt;Tree 确实需要知道如何比较元素类型 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 的值，为此它使用了一个比较函数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func(T,&lt;/span&gt; &lt;span class="pre"&gt;T)&lt;/span&gt; &lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt;。 您可以在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;find&lt;/span&gt;&lt;/code&gt; 方法的第 4 行调用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bt.cmp&lt;/span&gt;&lt;/code&gt; 中看到这一点。除此之外，类型参数根本不重要。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="function-method"&gt;
&lt;h3&gt;优先函数（function）而非方法（method）&lt;/h3&gt;
&lt;div class="admonition- admonition"&gt;
&lt;p class="admonition-title"&gt;译者注&lt;/p&gt;
&lt;p&gt;function 和 method 的区别在于 method 会关联一个对象（receiver）。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func&lt;/span&gt; &lt;span class="pre"&gt;Name(){}&lt;/span&gt;&lt;/code&gt; 是 function ，而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func&lt;/span&gt; &lt;span class="pre"&gt;(f&lt;/span&gt; &lt;span class="pre"&gt;Foo)&lt;/span&gt; &lt;span class="pre"&gt;Name(){}&lt;/span&gt;&lt;/code&gt; 是 mehtod。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;上面 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 的例子说明了另一个准则：当你需要比较之类的操作时，优先使用函数而非方法。&lt;/p&gt;
&lt;p&gt;我们可以定义这样的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 类型，要求元素必须实现 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Compare&lt;/span&gt;&lt;/code&gt; 或 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Less&lt;/span&gt;&lt;/code&gt; 方法。这将通过编写带方法的的类型约束（type constraint that requires the method）完成，这意味着用于实例化 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 类型的任何类型都需要实现该方法。&lt;/p&gt;
&lt;p&gt;这样做的结果是，想要使用简单数据类型（如 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt;）的人都必须定义自己的整数类型并编写对应的方法。如果我们定义还是和上面一样，让 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 接受一个比较函数，那一切还是那么简单。编写比较函数就像编写方法一样容易。&lt;/p&gt;
&lt;p&gt;如果 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 的元素类型恰好已经有一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Compare&lt;/span&gt;&lt;/code&gt; 方法，那么我们可以简单地使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ElementType.Compare&lt;/span&gt;&lt;/code&gt; 之类的表达式来实现比较函数。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;换句话说，将「方法转换为函数」比将「方法添加到类型」要简单得多。因此，对于通用数据类型，优先使用函数，而非带方法的类型约束&lt;/em&gt;。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="method"&gt;
&lt;h3&gt;当实现通用的 method 时&lt;/h3&gt;
&lt;p&gt;类型参数有用的另一种情况是：当不同类型需要实现一些共同的方法，并且它们的实现都看起来都一样时。&lt;/p&gt;
&lt;p&gt;例如，考虑标准库的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Interface&lt;/span&gt;&lt;/code&gt;。它要求一个类型实现三种方法：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Len&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Swap&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Less&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;下面是一个泛型类型 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SliceFn&lt;/span&gt;&lt;/code&gt; 的示例，它为任意的 slice 类型实现了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Interface&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// SliceFn implements sort.Interface for a slice of T.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SliceFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;less&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SliceFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SliceFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SliceFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对于任何 slice 类型，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Len&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Swap&lt;/span&gt;&lt;/code&gt; 方法都是完全相同的。 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Less&lt;/span&gt;&lt;/code&gt; 方法需要一个比较函数，也就是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SliceFn&lt;/span&gt;&lt;/code&gt; 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Fn&lt;/span&gt;&lt;/code&gt; 部分（&lt;em&gt;F&lt;/em&gt;u&lt;em&gt;n&lt;/em&gt;ction 的缩写）。与前面的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tree&lt;/span&gt;&lt;/code&gt; 示例一样，我们将在创建 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SliceFn&lt;/span&gt;&lt;/code&gt; 时传入一个函数。&lt;/p&gt;
&lt;p&gt;下面展示了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;SliceFn&lt;/span&gt;&lt;/code&gt; 如何使用比较函数对 slice 进行排序:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// SortFn sorts s in place using a comparison function.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SortFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;less&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SliceFn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这类似于标准库里的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Slice&lt;/span&gt;&lt;/code&gt;，但比较函数的参数是值本身而不是值在 slice 中的索引。&lt;/p&gt;
&lt;p&gt;对这种代码使用 type parameter 是合适的，因为所有 slice 类型的方法看起来完全相同。&lt;/p&gt;
&lt;p&gt;这里应该提一下，Go 1.19（而不是 1.18）的标准库很可能引入一个通用函数来使用比较函数对 slice 进行排序，并且该函数很可能不使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Interface&lt;/span&gt;&lt;/code&gt;。参见提案 &lt;a class="reference external" href="https://github.com/golang/go/issues/47619"&gt;#47619&lt;/a&gt;。即使这个上面这个例子很可能不实用，但大体上的观点依然是正确的：&lt;em&gt;当你需要对所有相关类型实现看起来都相同的方法时，使用类型参数是合理的&lt;/em&gt;。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;这里插播一则新闻，Go 1.19 将会使用 pdqsort 作为默认的排序算法（包括 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Interface&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sort.Slice&lt;/span&gt;&lt;/code&gt;），在所有的场景下相比原来的实现都快 2 到 60 倍（包括了算法本身和使用泛型带来的收益）这部分工作由我们组的同事 &lt;a class="extlink-ghuser reference external" href="https://github.com/zhangyunhao116"&gt;👤 zhangyunhao116&lt;/a&gt; 在 &lt;a class="reference external" href="https://github.com/golang/go/issues/50154"&gt;#50154&lt;/a&gt; 提出并实现。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id8"&gt;
&lt;h2&gt;何时不使用 type parameter&lt;/h2&gt;
&lt;p&gt;现在让我们来讨论一下问题的另一面：什么时候不应该使用类型参数。&lt;/p&gt;
&lt;section id="type-parameter-interface"&gt;
&lt;h3&gt;不要使用 type parameter 替代 interface&lt;/h3&gt;
&lt;p&gt;众所周知，Go 支持接口（interface）类型。interface 在一定程度上允许你在实现泛型编程。&lt;/p&gt;
&lt;p&gt;例如，广泛使用的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Reader&lt;/span&gt;&lt;/code&gt; 接口提供了一种通用机制，用于从包含信息（例如文件）的对象或产生信息（例如随机数生成器）的对象中读取数据。如果你对某个类型的的所有操作就是对其值调用方法，请使用 interface，而不是 type parameter。直接使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Reader&lt;/span&gt;&lt;/code&gt; 的代码更加易于阅读、高效且有效。这里没有必要使用 type parameter 通过调用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Read&lt;/span&gt;&lt;/code&gt; 方法从值中读取数据。&lt;/p&gt;
&lt;p&gt;举个例子，这里将使用 interface 的第一个函数签名更改为使用 type parameter 的第二个版本，看起来也许很诱人:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ReadSome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ReadSome&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但请不要这么做，第一个省略类型参数的版本其实更易于编写、阅读，并且 &lt;em&gt;它们的执行时间可能相同&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;上面的最后一点值得强调：尽管泛型可以通过个好几种不同的方式实现，并且实现会随着时间的推移而改变和演进，但 Go 1.18 的实现在许多情况下会同等对待类型参数的值与接口类型的值。这意味着使用 type parameter 通常不会比使用 interface 快。所以不要仅仅为了速度而从 interface 更改为 type parameter，因为它可能不会运行得更快。&lt;/p&gt;
&lt;div class="admonition- admonition"&gt;
&lt;p class="admonition-title"&gt;译者注&lt;/p&gt;
&lt;p&gt;就是说在这种情况下，可以认为 type parameter 只是 interface 的语法糖。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="method-type-parameter"&gt;
&lt;h3&gt;不要对不同的 method 实现使用 type parameter&lt;/h3&gt;
&lt;p&gt;在决定是使用 type parameter 还是 interface 时，请考虑方法的实现是什么样的。前面我们说过，如果方法的实现对所有类型都相同，则使用 type parameter。反之，如果每种类型的实现都不一样，那就用 interface 写不同的方法实现。&lt;/p&gt;
&lt;p&gt;例如，从文件中读取的实现和从随机数生成器读取的实现完全不同，这意味着我们应该编写两个不同的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Read&lt;/span&gt;&lt;/code&gt; 方法，并使用像 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;io.Reader&lt;/span&gt;&lt;/code&gt; 这样的接口类型。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h3&gt;在适当的地方使用反射&lt;/h3&gt;
&lt;p&gt;Go 支持 &lt;a class="reference external" href="https://pkg.go.dev/reflect"&gt;运行时反射&lt;/a&gt;。反射也能一定程度地实现泛型编程，因为它允许你编写适用于任何类型的代码。&lt;/p&gt;
&lt;p&gt;如果某些操作支持的类型连方法都没有（因此没有办法定义 interface），并且针对每种类型的操作都不同（因此不适合使用 type parameter）的时候，请使用反射。&lt;/p&gt;
&lt;p&gt;一个例子是 &lt;a class="reference external" href="https://pkg.go.dev/encoding/json"&gt;encoding/json&lt;/a&gt; 包。我们不想要求我们编码的每个类型都有一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MarshalJSON&lt;/span&gt; &lt;span class="pre"&gt;方法&lt;/span&gt;&lt;/code&gt;，所以我们不能使用接口类型。但是编码一个 interface 与编码一个 struct 的实现完全不同，所以我们不应该使用 type parameter。因此 encoding/json 使用了反射。使用反射实现的代码并不简单，但它确实能用。如果你想了解更多详情，请参阅其源代码。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id12"&gt;
&lt;h2&gt;一言以蔽之&lt;/h2&gt;
&lt;p&gt;最后，关于何时使用泛型的讨论可以简化为一个简单的指导方针。&lt;/p&gt;
&lt;p&gt;如果你发现自己多次编写完全相同的代码，而副本之间的唯一区别是代码使用了不同的类型，请考虑是否需要使用 type parameter。&lt;/p&gt;
&lt;p&gt;换句话说，你应该避免使用 type parameter，直到你注意到你需要多次编写完全相同的代码。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/when-go-generics.html"/>
    <summary>这篇文章是 When To Use Generics 的中文翻译，作者是 Go Team 的 👤 ianlancetaylor。</summary>
    <category term="Golang" label="Golang"/>
    <category term="泛型" label="泛型"/>
    <category term="翻译" label="翻译"/>
    <published>2022-06-03T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/funtional-programming-in-go-generics.html</id>
    <title>函数式编程在 Go 泛型下的实用性探索</title>
    <updated>2021-10-27T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="go"&gt;

&lt;section id="id1"&gt;
&lt;h2&gt;背景&lt;/h2&gt;
&lt;p&gt;函数式编程（Functional Programming / FP）作为一种编程范式，具有无状态、无副作用、并发友好、抽象程度高等优点。目前流行的编程语言（C++、Python、Rust）都或多或少地引入了函数式特性，但在同作为流行语言的 Golang 中却少有讨论。&lt;/p&gt;
&lt;p&gt;究其原因，大部分的抱怨 &lt;a class="footnote-reference brackets" href="#id40" id="id2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; &lt;a class="footnote-reference brackets" href="#id41" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 集中于 Go 缺乏对范型的支持，难以写出类型间通用的函数。代码生成只能解决一部分已知类型的处理，且无法应对类型组合导致复杂度（比如实现一个通用的 TypeA → TypeB 的 map 函数）。&lt;/p&gt;
&lt;p&gt;有关泛型的提案 &lt;a class="reference external" href="https://github.com/golang/go/issues/43651"&gt;spec: add generic programming using type parameters #43651&lt;/a&gt; 已经被 Go 团队接受，并计划在 2022 年初发布支持范型的 Go 1.18，现在 golang/go 仓库的 master 分支已经支持范型。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;This design has been proposed and accepted as a future language change. We currently expect that this change will be available in the Go 1.18 release in early 2022. &lt;a class="footnote-reference brackets" href="#id39" id="id4" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;基于这个重大特性，我们有理由重新看看，函数式特性在 Go 范型的加持下，能否变得比以往更加实用。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;概述&lt;/h2&gt;
&lt;p&gt;这篇文章里，我们会尝试用 Go 的泛型循序渐进地实现一些常见的函数式特性，从而探索 Go 泛型的优势和不足。&lt;/p&gt;
&lt;p&gt;除非额外说明（例如注释中的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;//&lt;/span&gt; &lt;span class="pre"&gt;INVALID&lt;/span&gt; &lt;span class="pre"&gt;CODE!!!&lt;/span&gt;&lt;/code&gt;），文章里的代码都是可以运行的（为了缩减篇幅，部分删去了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;package&lt;/span&gt; &lt;span class="pre"&gt;main&lt;/span&gt;&lt;/code&gt; 声明和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;main&lt;/span&gt;&lt;/code&gt; 函数，请自行添加）。你可以自行 &lt;a class="reference external" href="https://golang.org/doc/install/source#install"&gt;从源码编译&lt;/a&gt; 一个 master 版本的 go 来提前体验 Go 的泛型，或者用 &lt;a class="reference external" href="https://go2goplay.golang.org/"&gt;The go2go Playground&lt;/a&gt; 提供的在线编译器运行单个文件。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h2&gt;泛型语法&lt;/h2&gt;
&lt;p&gt;提案的 &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#very-high-level-overview"&gt;#Very high level overview&lt;/a&gt; 一节中描述了为范型而添加的新语法，这里简单描述一下阅读本文所需要的语法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;函数名后可以附带一个方括号，包含了该函数涉及的类型参数（Type Paramters）的列表：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func&lt;/span&gt; &lt;span class="pre"&gt;F[T&lt;/span&gt; &lt;span class="pre"&gt;any](p&lt;/span&gt; &lt;span class="pre"&gt;T)&lt;/span&gt; &lt;span class="pre"&gt;{&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt; &lt;span class="pre"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;这些类型参数可以在函数参数和函数体中（作为类型）被使用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;自定义类型也可以有类型参数列表：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;M[T&lt;/span&gt; &lt;span class="pre"&gt;any]&lt;/span&gt; &lt;span class="pre"&gt;[]T&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;每个类型参数对应一个类型约束，上述的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;any&lt;/span&gt;&lt;/code&gt; 就是预定义的匹配任意类型的约束&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;类型约束在语法上以 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface&lt;/span&gt;&lt;/code&gt; 的形式存在，在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface&lt;/span&gt;&lt;/code&gt; 中嵌入类型 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 可以表示这个类型必须是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Integer1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;嵌入单个类型意义不大，我们可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;|&lt;/span&gt;&lt;/code&gt; 来描述类型的 union:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Integer2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~T&lt;/span&gt;&lt;/code&gt; 语法可以表示该类型的「基础类型」是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt;，比如说我们的自定义类型 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;MyInt&lt;/span&gt; &lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt; 不满足上述的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Integer1&lt;/span&gt;&lt;/code&gt; 约束，但满足以下的约束:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Integer3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;「基础类型」在提案中为 &amp;quot;underlying type&amp;quot;，目前尚无权威翻译，在本文中使用仅为方便描述。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id11"&gt;
&lt;h2&gt;高阶函数&lt;/h2&gt;
&lt;p&gt;在函数式编程语言中，&lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/高阶函数"&gt;📖 高阶函数&lt;/a&gt; （Higher-order function）是一个重要的特性。高阶函数是至少满足下列一个条件的函数：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;接受一个或多个函数作为输入&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;输出一个函数&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Golang 支持闭包，所以实现高阶函数毫无问题:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;foobar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="c1"&gt;// foo bar&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;filter 操作是高阶函数的经典应用，它接受一个函数 f（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func&lt;/span&gt; &lt;span class="pre"&gt;(T)&lt;/span&gt; &lt;span class="pre"&gt;bool&lt;/span&gt;&lt;/code&gt;）和一个线性表 l（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]&lt;/span&gt; &lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt;），对 l 中的每个元素应用函数 f，如结果为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;true&lt;/span&gt;&lt;/code&gt;，则将该元素加入新的线性表里，否则丢弃该元素，最后返回新的线性表。&lt;/p&gt;
&lt;p&gt;根据上面的泛型语法，我们可以很容易地写出一个简单的 filter 函数:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="c1"&gt;// [0 1 2]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="id12"&gt;
&lt;h3&gt;代码生成之困&lt;/h3&gt;
&lt;p&gt;在 1.17 或者更早前的 Go 版本中，要实现通用的 Filter 函数有两种方式：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt; 配合反射，牺牲一定程度的类型安全和运行效率&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;为不同数据类型实现不同的 Filter 变种，例如 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FilterInt&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FilterString&lt;/span&gt;&lt;/code&gt; 等，缺点在于冗余度高，维护难度大&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;方式 2 的缺点可以通过代码生成规避，具体来说就使用相同的一份模版，以数据类型为变量生成不同的实现。我们在 Golang 内部可以看到不少 &lt;a class="reference external" href="https://github.com/golang/go/search?q=filename%3Agen.go"&gt;代码生成的例子&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;那么，有了代码生成，我们是不是就不需要泛型了呢？&lt;/p&gt;
&lt;p&gt;答案是否定的：&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;代码生成只能针对已知的类型生成代码，明明这份模版对 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;float64&lt;/span&gt;&lt;/code&gt; 也有效，但作者只生成了处理 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt; 的版本，我们作为用户无能为力（用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt; 同理，我们能使用什么类型，取决于作者列出了多少个 type switch 的 cases）&lt;/p&gt;
&lt;p&gt;而在泛型里，新的类型约束语法可以统一地处理「基础类型」相同的所有类型:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;float32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;complex64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;complex128&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Neg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;signed&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MyInt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="c1"&gt;// -1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="c1"&gt;// -1.1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="c1"&gt;// -1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;代码生成难以应对需要类型组合的场景，我们来看另一个高阶函数 map：接受一个函数 f（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;func&lt;/span&gt; &lt;span class="pre"&gt;(T1)&lt;/span&gt; &lt;span class="pre"&gt;T2&lt;/span&gt;&lt;/code&gt;）和一个线性表 l1（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]T1&lt;/span&gt;&lt;/code&gt;），对 l1 中的每个元素应用函数 f，返回的结果组成新的线性表 l2（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]T2&lt;/span&gt;&lt;/code&gt;）&lt;/p&gt;
&lt;p&gt;如果使用代码生成的话，为了避免命名冲突，我们不得不写出 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MapIntInt&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MapIntUint&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MapIntString&lt;/span&gt;&lt;/code&gt; 这样的奇怪名字，而且由于类型的组合，代码生成的量将大大膨胀。&lt;/p&gt;
&lt;p&gt;我们可以发现在现有的支持 FP 特性的 Go library 里：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;有的（ &lt;a class="reference external" href="https://pkg.go.dev/github.com/DylanMeeus/hasgo/types?utm_source=godoc#Ints.Map"&gt;hasgo&lt;/a&gt; ）选择将 map 实现成了闭合运算（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]T&lt;/span&gt; &lt;span class="pre"&gt;→&lt;/span&gt; &lt;span class="pre"&gt;[]T&lt;/span&gt;&lt;/code&gt;），牺牲了表达能力&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有的（ &lt;a class="reference external" href="https://pkg.go.dev/github.com/logic-building/functional-go/fp"&gt;functional-go&lt;/a&gt; ）强行用代码生成导致接口数目爆炸&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有的（ &lt;a class="reference external" href="https://pkg.go.dev/github.com/TeaEntityLab/fpGo#Map"&gt;fpGo&lt;/a&gt; ）选择牺牲类型安全用 interface{} 实现&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果使用泛型的话，只需要定义这样的签名就好了:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id="id17"&gt;
&lt;h3&gt;无糖的泛型&lt;/h3&gt;
&lt;p&gt;Go 的语法在一众的编程语言里绝对算不上简洁优雅。在官网上看到操作 channel 时 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;-&lt;/span&gt;&lt;/code&gt; 的直观便捷让你心下暗喜，而一旦你开始写 real world 的代码，这个语言就处处难掩设计上的简陋。泛型即将到来，而这个语言的其他部分似乎没有做好准备：&lt;/p&gt;
&lt;section id="id18"&gt;
&lt;h4&gt;闭包语法&lt;/h4&gt;
&lt;p&gt;在 Haskell 中的匿名函数形式非常简洁：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;-- Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;-- [0,1,2]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;而在 Golang 里，函数的类型签名不可省略，无论高阶函数要求何种签名，调用者在构造闭包的时候总是要完完整整地将其照抄一遍 &lt;a class="footnote-reference brackets" href="#id40" id="id19" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;foobar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个问题可以归结于 Go 团队为了保持所谓的「大道至简」，而对类型推导这样提升效率降低冗余的特性的忽视（泛型的姗姗来迟又何尝不是如此呢？）。 &lt;a class="reference external" href="https://github.com/golang/go/issues/21498"&gt;proposal: Go 2: Lightweight anonymous function syntax #21498&lt;/a&gt; 提出了一个简化闭包调用语法的提案，但即使该提案被 accept，我们最快也只能在 Go 2 里见到它了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id21"&gt;
&lt;h4&gt;方法类型参数&lt;/h4&gt;
&lt;p&gt;&lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Method_chaining"&gt;链式调用&lt;/a&gt; （Method chaining）是一种调用函数的语法，每个调用都会返回一个对象，紧接着又可以调用该对象关联的方法，该方法同样也返回一个对象。链式调用能显著地消除调用的嵌套，可读性好。我们熟悉的 GORM 的 API 里就大量使用了链式调用:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name = ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;jinzhu&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;age = ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在函数式编程中，每个高阶函数往往只实现了简单的功能，通过它们的组合实现复杂的数据操纵。&lt;/p&gt;
&lt;p&gt;在无法使用链式调用的情况下，高阶函数的互相组合是这样子的（这仅仅是两层的嵌套）:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如果用链式调用呢？我们继续沿用前面的 filter ，改成以下形式:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;// [0 1]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看起来很美好，但为什么不用 map 操作举例呢？我们很容易写出这样的方法签名:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// INVALID CODE!!!&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;很遗憾这样的代码是没法通过编译的，我们会获得以下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;invalid AST: method must have no type parameter&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;提案的 &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#No-parameterized-methods"&gt;#No parameterized methods&lt;/a&gt; 一节明确表示了方法（method，也就是有 recevier 的函数）不支持单独指定类型参数：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;This design does not permit methods to declare type parameters that are specific to the method. The receiver may have type parameters, but the method may not add any type parameters. &lt;a class="footnote-reference brackets" href="#id39" id="id22" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这个决定实际上是个不得已的妥协。假设我们实现了上述的方法，就意味对于一个已经实例化了的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;List[T]&lt;/span&gt;&lt;/code&gt; 对象（比如说 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;List[int]&lt;/span&gt;&lt;/code&gt;），它的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Map&lt;/span&gt;&lt;/code&gt; 方法可能有多个版本：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Map(func&lt;/span&gt; &lt;span class="pre"&gt;(int)&lt;/span&gt; &lt;span class="pre"&gt;int)&lt;/span&gt; &lt;span class="pre"&gt;List[int]&lt;/span&gt;&lt;/code&gt; 或者 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Map(func&lt;/span&gt; &lt;span class="pre"&gt;(int)&lt;/span&gt; &lt;span class="pre"&gt;string)&lt;/span&gt; &lt;span class="pre"&gt;List[string]&lt;/span&gt;&lt;/code&gt;，当用户的代码调用它们时，它们的代码必然在之前的某个时刻生成了，那么应该在什么时候呢？&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;在编译期，更准确地说，在编译的 link 阶段，这需要 linker 去遍历整个 call graph，确定程序中到底使用了几个版本的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Map&lt;/span&gt;&lt;/code&gt;。问题在于反射（reflection）的存在：用户可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;reflect.MethodByName&lt;/span&gt;&lt;/code&gt; 动态地调用对象的方法，所以即使遍历了整个 call graph，我们也无法确保用户的代码到底调用了几个版本的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Map&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在运行期，在第一次调用方法时 yield 到 runtime 中，生成对应版本的函数后 resume 回去，这要求 runtime 支持 JIT（Just-in-time compilation），而目前 Go 并不支持，即使未来 JIT 的支持提上日程，这也不是一蹴而就的事情&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;综上，Go 团队选择了不支持给 method 指定类型参数，完美了解决这个问题 🎉。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id24"&gt;
&lt;h2&gt;惰性求值&lt;/h2&gt;
&lt;p&gt;&lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/惰性求值"&gt;📖 惰性求值&lt;/a&gt; （Lazy Evaluation）是另一个重要的函数式特性，一个不严谨的描述是：在定义运算时候，计算不会发生，直到我们需要这个值的时候才进行。其优点在于能使计算在空间复杂度上得到极大的优化。&lt;/p&gt;
&lt;p&gt;下面的代码展示了一个平平无奇的 Add 函数和它的 Lazy 版本，后者在给出加数的时候不会立刻计算，而是返回一个闭包:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LazyAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面这个例子没有体现出惰性求值节省空间的优点。基于我们之前实现的高阶函数，做以下的运算:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;计算过程中会产生 3 个新的长度为 5 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]int&lt;/span&gt;&lt;/code&gt;，空间复杂度为 &lt;span class="math notranslate nohighlight"&gt;\(O(3 * N)\)&lt;/span&gt;，尽管常数在复杂度分析时经常被省略，但在程序实际运行的时候，这里的 3 就意味着 3 倍的内存占用。&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/funtional-programming-in-go-generics.rst&lt;/span&gt;, line 294)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;math&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;math&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;假设这些高阶函数的求值是惰性的，则计算只会在对 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fmt.Println&lt;/span&gt;&lt;/code&gt; 对参数求值的时候发生，元素从原始的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;l&lt;/span&gt;&lt;/code&gt; 中被取出，判断 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;if&lt;/span&gt; &lt;span class="pre"&gt;v&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;-2&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;if&lt;/span&gt; &lt;span class="pre"&gt;v&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt;&lt;/code&gt;，最后执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;v&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;1&lt;/span&gt;&lt;/code&gt;，放入新的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]int&lt;/span&gt;&lt;/code&gt; 中，空间复杂度依然是 &lt;span class="math notranslate nohighlight"&gt;\(O(N)\)&lt;/span&gt;，但毫无疑问地我们只使用了一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]int`&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;泛型的引入对惰性求值的好处有限，大致和前文所述一致，但至少我们可以定义类型通用的 接口了:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// 一个适用于线性结构的迭代器接口&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="c1"&gt;// 用于将任意 slice 包装成 Iter[T]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SliceIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IterOfSlice&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;SliceIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;SliceIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;接着实现惰性版本的 filter:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filterIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;filterIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;filterIter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看到这个版本的 filter 仅仅返回了一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Iter[T]`（`*filterIter[T]&lt;/span&gt;&lt;/code&gt;），实际的运算在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*filterIter[T].Next()&lt;/span&gt;&lt;/code&gt; 中进行。&lt;/p&gt;
&lt;p&gt;我们还需要一个将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Iter[T]&lt;/span&gt;&lt;/code&gt; 转回 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]T&lt;/span&gt;&lt;/code&gt; 的函数:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后实现一个和上面等价的运算，但实际的计算工作是在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;List(i)&lt;/span&gt;&lt;/code&gt; 的调用中发生的:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IterOfSlice&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="map"&gt;
&lt;h3&gt;Map 的迭代器&lt;/h3&gt;
&lt;p&gt;Golang 中的 Hashmap &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map[K]V&lt;/span&gt;&lt;/code&gt; 和 Slice &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]T&lt;/span&gt;&lt;/code&gt; 一样是常用的数据结构，如果我们能将 map 转化为上述的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Iter[T]&lt;/span&gt;&lt;/code&gt;，那么 map 就能直接使用已经实现的各种高阶函数。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map[K]V&lt;/span&gt;&lt;/code&gt; 的迭代只能通过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;for&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt; &lt;span class="pre"&gt;range&lt;/span&gt;&lt;/code&gt; 进行，我们无法通过常规的手段获得一个 iterator。反射当然可以做到，但 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;reflect.MapIter&lt;/span&gt;&lt;/code&gt; 太重了。&lt;a class="extlink-ghrepo reference external" href="https://github.com/modern-go/reflect2"&gt;⛺ modern-go/reflect2&lt;/a&gt; 提供了一个 &lt;a class="reference external" href="https://pkg.go.dev/github.com/modern-go/reflect2#UnsafeMapIterator"&gt;更快的实现&lt;/a&gt; ，但已经超出了本文的讨论范围，此处不展开，有兴趣的朋友可以自行研究。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id26"&gt;
&lt;h2&gt;局部应用&lt;/h2&gt;
&lt;p&gt;&lt;a class="extlink-enwiki reference external" href="https://wikipedia.org/wiki/Partial_application"&gt;局部应用&lt;/a&gt; （Partial Application）是一种固定多参函数的部分参数，并返回一个可以接受剩余部分参数的函数的操作。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;局部应用不同于 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/柯里化"&gt;📖 柯里化&lt;/a&gt; （Currying） &lt;a class="footnote-reference brackets" href="#id42" id="id27" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; ，柯里化是一种用多个单参函数来表示多参函数的技术，在 Go 已经支持多参函数的情况下，本文暂时不讨论 Currying 的实现。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;我们定义一个有返回值的接收单个参数的函数类型:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith1Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对一个只接受一个参数的函数进行一次 partial application，其实就相当于求值:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith1Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;接受两个参数的函数被 partial application 后，一个参数被固定，自然返回一个上述的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith1Args&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith1Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;我们来试用一下，将我们之前实现的 filter 包装成一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith2Args&lt;/span&gt;&lt;/code&gt;，从左到右固定两个参数，最后得到结果:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]](&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IterOfSlice&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="c1"&gt;// [-1 0 1 2]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="id28"&gt;
&lt;h3&gt;类型参数推导&lt;/h3&gt;
&lt;p&gt;我们勉强实现了 partial application，可是把 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Filter&lt;/span&gt;&lt;/code&gt; 转换为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith2Args&lt;/span&gt;&lt;/code&gt; 的过程太过繁琐，在上面的例子中，我们把类型参数完整地指定了一遍，是不是重新感受到了 &lt;a class="reference internal" href="#id18"&gt;闭包语法&lt;/a&gt; 带给你的无奈？&lt;/p&gt;
&lt;p&gt;这一次我们并非无能为力，提案中的 &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#type-inference"&gt;#Type inference&lt;/a&gt; 一节描述了对类型参数推导的支持情况。上例的转换毫无歧义，那我们把类型参数去掉:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// INVALID CODE!!!&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;编译器如是抱怨：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;cannot use generic type FuncWith2Args without instantiation&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;提案里的类型参数推导仅针对函数调用，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith2Args(XXX)&lt;/span&gt;&lt;/code&gt; 虽然看起来像是函数调用语法，但其实是一个类型的实例化，针对类型实例化的参数类型推导（ &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#type-inference-for-composite-literals"&gt;#Type inference for composite literals&lt;/a&gt; ）还是一个待定的 feature。&lt;/p&gt;
&lt;p&gt;如果我们写一个函数来实例化这个对象呢？很遗憾，做不到：我们用什么表示入参呢？只能写出这样「听君一席话，如听一席话」的函数:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Cast&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FuncWith2Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;A2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但是它能工作！当我们直接传入 Filter 的时候，编译器会帮我们隐式地转换成一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith2Args[func(int)&lt;/span&gt; &lt;span class="pre"&gt;bool,&lt;/span&gt; &lt;span class="pre"&gt;Iter[int],&lt;/span&gt; &lt;span class="pre"&gt;Iter[int]]&lt;/span&gt;&lt;/code&gt;！同时因为函数类型参数推导的存在，我们不需要指定任何的类型参数了:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IterOfSlice&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="c1"&gt;// [-1 0 1 2]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id31"&gt;
&lt;h3&gt;可变类型参数&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith1Args&lt;/span&gt;&lt;/code&gt; 、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith2Args&lt;/span&gt;&lt;/code&gt; 这些名字让我们有些恍惚，仿佛回到了代码生成的时代。为了处理更多的参数，我们还得写 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith3Args&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;FuncWith4Args&lt;/span&gt;&lt;/code&gt;… 吗？&lt;/p&gt;
&lt;p&gt;是的， &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#omissions"&gt;#Omissions&lt;/a&gt; 一节提到：Go 的泛型不支持可变数目的类型参数：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;No variadic type parameters. There is no support for variadic type parameters, which would permit writing a single generic function that takes different numbers of both type parameters and regular parameters.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;对应到函数签名，我们也没有语法来声明拥有不同类型的可变参数。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id33"&gt;
&lt;h2&gt;类型系统&lt;/h2&gt;
&lt;p&gt;众多函数式特性的实现依赖于一个强大类型系统，Go 的类型系统显然不足以胜任，作者不是专业人士，这里我们不讨论其他语言里让人羡慕的类型类（Type Class）、代数数据类型（Algebraic Data Type），只讨论在 Go 语言中引入泛型之后，我们的类型系统有哪些水土不服的地方。&lt;/p&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;其实上文的大部分问题都和类型系统息息相关，case by case 的话我们可以列出非常多的问题，因此以下只展示明显不合理那部分。&lt;/p&gt;
&lt;/div&gt;
&lt;section id="id34"&gt;
&lt;h3&gt;编译期类型判断&lt;/h3&gt;
&lt;p&gt;当我们在写一段泛型代码里的时候，有时候会需要根据 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 实际上的类型决定接下来的流程，可 Go 的完全没有提供在编译期操作类型的能力。运行期的 workaround 当然有，怎么做呢：将 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 转化为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;interface{}&lt;/span&gt;&lt;/code&gt;，然后做一次 type assertion:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// do sth...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id35"&gt;
&lt;h3&gt;无法辨认「基础类型」&lt;/h3&gt;
&lt;p&gt;我们在 &lt;a class="reference internal" href="#id12"&gt;代码生成之困&lt;/a&gt; 提到过，在类型约束中可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~T&lt;/span&gt;&lt;/code&gt; 的语法约束所有 基础类型为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;T&lt;/span&gt;&lt;/code&gt; 的类型，这是 Go 在语法层面上首次暴露出「基础类型」的概念，在之前我们只能通过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;reflect.(Value).Kind&lt;/span&gt;&lt;/code&gt; 获取。而在 type assertion 和 type switch 里并没有对应的语法处理「基础类型」:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IsSigned&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;signed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unsigned&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MyInt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;IsSigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;IsSigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;// signed&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="c1"&gt;// unsigned&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;乍一看很合理，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MyInt&lt;/span&gt;&lt;/code&gt; 确实不是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt;。那我们要如何在函数不了解 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;MyInt&lt;/span&gt;&lt;/code&gt; 的情况下把它当 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt;&lt;/code&gt; 处理呢？答案是还不能： &lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#identifying-the-matched-predeclared-type"&gt;#Identifying the matched predeclared type&lt;/a&gt; 表示这是个未决的问题，需要在后续的版本中讨论新语法。总之，在 1.18 中，我们是见不到它了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="type-assertion"&gt;
&lt;h3&gt;类型约束不可用于 type assertion&lt;/h3&gt;
&lt;p&gt;一个直观的想法是单独定义一个 Signed 约束，然后判断 T 是否满足 Signed:&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IsSigned&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).(&lt;/span&gt;&lt;span class="nx"&gt;Signed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;signed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unsigned&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但很可惜，类型约束不能用于 type assertion/switch，编译器报错如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;interface contains type constraints&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;尽管让类型约束用于 type assertion 可能会引入额外的问题，但牺牲这个支持让 Go 的类型表达能力大大地打了折扣。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id37"&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;函数式编程的特性不止于此，代数数据类型、引用透明（Referential Transparency）等在本文中都未能覆盖到。
总得来说，Go 泛型的引入：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;使的部分 &lt;em&gt;函数式特性能以更通用的方式被实现&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;灵活度比代码生成更高&lt;/em&gt; ，用法更自然，但细节上的小问题很多&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1.18 的泛型在引入 type paramters 语法之外并没有其他大刀阔斧的改变，导致泛型和这个语言的其他部分显得有些格格不入，也使得泛型的能力受限。 &lt;em&gt;至少在 1.18 里，我们要忍受泛型中存在的种种不一致&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;受制于 Go 类型系统的表达能力，我们无法表示复杂的类型约束，自然也 &lt;em&gt;无法实现完备的函数式特性&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id="id38"&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id39" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="backrefs"&gt;(&lt;a role="doc-backlink" href="#id4"&gt;1&lt;/a&gt;,&lt;a role="doc-backlink" href="#id22"&gt;2&lt;/a&gt;)&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md"&gt;Type Parameters Proposal&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id40" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="backrefs"&gt;(&lt;a role="doc-backlink" href="#id2"&gt;1&lt;/a&gt;,&lt;a role="doc-backlink" href="#id19"&gt;2&lt;/a&gt;)&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://hedzr.com/golang/fp/golang-functional-programming-in-brief/"&gt;Golang 函数式编程简述&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id41" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.youtube.com/watch?v=wqs8n5Uk5OM"&gt;GopherCon 2020: Dylan Meeus - Functional Programming with Go&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id42" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id27"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.uncarved.com/articles/not-currying/"&gt;Partial Function Application is not Currying&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/funtional-programming-in-go-generics.html"/>
    <summary>函数式编程（Functional Programming / FP）作为一种编程范式，具有无状态、无副作用、并发友好、抽象程度高等优点。目前流行的编程语言（C++、Python、Rust）都或多或少地引入了函数式特性，但在同作为流行语言的 Golang 中却少有讨论。</summary>
    <category term="Golang" label="Golang"/>
    <category term="函数式编程" label="函数式编程"/>
    <category term="泛型" label="泛型"/>
    <published>2021-10-27T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/xzzh-after-40-yrs.html</id>
    <title>四十年后再看西藏组画</title>
    <updated>2021-07-03T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;
&lt;h1 class="any any-header event-header" id="event-5c0be90"&gt;四十年后再看西藏组画&lt;/h1&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt class="field-odd"&gt;日期&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-odd"&gt;&lt;p&gt;&lt;a class="any any-event reference internal" href="any-event.date%2Bby-year.html#cap-2021 年" title="event 2021-06-30"&gt;&lt;code class="xref any any-event.date+by-year docutils literal notranslate"&gt;&lt;span class="pre"&gt;2021-06-30&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="field-even"&gt;位置&lt;span class="colon"&gt;:&lt;/span&gt;&lt;/dt&gt;
&lt;dd class="field-even"&gt;&lt;p&gt;&lt;a class="any any-event reference internal" href="blog/xzzh-after-40-yrs.html#event-5c0be90" title="event 北京 中国油画院"&gt;&lt;a href="#report-3"&gt;&lt;span class="problematic" id="problematic-3"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-3"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;从油画院公众号上看到 &lt;a class="any any-artist reference internal" href="p/artistory/index.html#artist-e7525b8" title="artist 陈丹青"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 的西藏组画要再展 &lt;a class="footnote-reference brackets" href="#id12" id="id2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;。刚好我从燕郊回广东要在北京中转几天，有机会看看陈老师最负盛名的这组作品到底是什么样子的。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;这也是我在 &lt;a class="any any-event reference internal" href="notes/zxsys/index.html#event-c13f9cb" title="event 造型实验室"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 学习一年之后的首次看展，我很期待这个不一样的我是否能看到不一样的东西。&lt;/p&gt;
&lt;/div&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;最佳习作&lt;/h2&gt;
&lt;p&gt;展览展出 7 张油画和 200 余张速写，很可惜除了进门第一张《意大利女孩》是原作之外，其他的全是高清喷绘，速写倒多是原作。&lt;/p&gt;
&lt;p&gt;从《意大利女孩》能看出陈丹青不错的造型功底，画的感觉也非常好，颇有大师风范：&lt;/p&gt;
&lt;figure class="align-default" id="id16"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_144543.jpg" src="https://silverrainz.me/_images/IMG_20210627_144543.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;意大利女孩&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;陈老师在下面用歪歪扭扭的笔迹追记：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;这张画居然没有丢失。这次画展，这张最好！&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;我心里暗生喜悦：原来陈老师也最喜欢这一张，我眼光不错。后来写此文的时候一查，其实这张是陈老师在 15 岁的时候临摹 &lt;code class="xref any any-artist docutils literal notranslate"&gt;&lt;span class="pre"&gt;阿列克谢&lt;/span&gt;&lt;/code&gt; 的习作，对比一下：&lt;/p&gt;
&lt;figure class="align-default" id="id17"&gt;
&lt;img alt="https://silverrainz.me/_images/Alexei-Harlamoff-Italian-Girls.jpg" src="https://silverrainz.me/_images/Alexei-Harlamoff-Italian-Girls.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;em&gt;Italian Girls&lt;/em&gt; by Alexei Harlamoff&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;自然是不如原作，倒也明白陈丹青为何这么说了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;草图和创作思路&lt;/h2&gt;
&lt;p&gt;这次展览，除了画本身，还节选了陈老师的绘画日记和在美术期刊上的一些文章。配合大量的小稿，陈当年创作的思路可见一二：&lt;/p&gt;
&lt;figure class="align-default" id="id18"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_150342.jpg" src="https://silverrainz.me/_images/IMG_20210627_150342.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;我不怕不成熟的草图，一旦草图上画出精彩的效果我反而会担心，因为戏毕竟在油画上。我尽可能让我在上正稿时仿佛处在第一次画这副画的状态中，那样整个创作过程是主动积极的，充满自信和写生般的敏锐，情绪亦很愉快。为此我常把草图搁置很久才画正稿（有时放几个月），并且一旦画起来，我差不多不看草稿。这不是做不到的，既然一个演员能从头背下一台戏来，一个画家也该有这点背写的能力。事实上打腹稿已经是个默记于心的过程，而草图就是对画面各个角落熟悉把握的过程，如果到了正稿时还处处求证与草图资料，那么作者对于自己要画的还不是很还有底，至少是在被动地创作。&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;—— 陈丹青《中国美术》1981 年 第 2 期&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id19"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_151615.jpg" src="https://silverrainz.me/_images/IMG_20210627_151615.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;如果我们去到一个地方，想要一些创作，那我以为最好别画太多的写生，至少别光顾写生。创作不全是想出来的，也不全是画出来的，倒是留心看看看来的。到处走走转转，兴许就带回一二个有意思的印象，日后可能搞成一张创作。如果一头插进去写生，当然能带回来一大沓很像样的投降、风景，不过常常仅此而已，你心中的东西不会比写生更多。我有时为这回没画油画写生一遗憾，但念及我获得了比写生更有意思的东西，另一头则满足啦。&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;—— 陈丹青《中国美术》1981 年 第 2 期&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;在大量的小稿中，有不少带上了文字，用来补充未能用画面良好记录的信息：&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_145646.jpg" src="https://silverrainz.me/_images/IMG_20210627_145646.jpg" style="width: 30%;" /&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_144838.jpg" src="https://silverrainz.me/_images/IMG_20210627_144838.jpg" style="width: 30%;" /&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_144932.jpg" src="https://silverrainz.me/_images/IMG_20210627_144932.jpg" style="width: 30%;" /&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;四十年后追记&lt;/h2&gt;
&lt;p&gt;刚才提及展览节选了陈老师的旧文，有意思的是油画院请陈在四十年后对自己当年的文字评价一番，用歪歪扭扭的手写体注在一旁，有感慨，有自嘲。在我的感受是漂亮话居多，自嘲中有一些坦言了自己的退步：&lt;/p&gt;
&lt;figure class="align-default" id="id20"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_151201.jpg" src="https://silverrainz.me/_images/IMG_20210627_151201.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;谢天谢地，创作的激情一直都没有离开我
&lt;sub&gt;追记：现在，创作的激情早就离开我了&lt;/sub&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/xzzh-after-40-yrs.rst&lt;/span&gt;, line 75)&lt;/p&gt;
&lt;p&gt;No role entry for &amp;quot;sub&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for role &amp;quot;sub&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id21"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_145435.jpg" src="https://silverrainz.me/_images/IMG_20210627_145435.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;继续画「三个母亲」，我觉得灵感和技巧一天比一天照顾我
&lt;sub&gt;追记：如今，不肯照顾我了&lt;/sub&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;这几日刚好有看到了今年陈老师的新作 &lt;a class="footnote-reference brackets" href="#id13" id="id6" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; ，看了一眼后我想所言非虚：&lt;/p&gt;
&lt;figure class="align-default" id="id22"&gt;
&lt;img alt="https://silverrainz.me/_images/1000.webp" src="https://silverrainz.me/_images/1000.webp" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;时尚模特写生系列，2021&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;西藏组画好&lt;/h2&gt;
&lt;figure class="align-default" id="id23"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_150753.jpg" src="https://silverrainz.me/_images/IMG_20210627_150753.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;康巴汉子 &lt;sub&gt;高清喷绘&lt;/sub&gt; &lt;sub&gt;局部&lt;/sub&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id24"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_145244.jpg" src="https://silverrainz.me/_images/IMG_20210627_145244.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;母与子 &lt;sub&gt;高清喷绘&lt;/sub&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;我想对艺术作品的评价，不能脱离其历史背景，1980 年西藏组画问世，彼时文化大革命刚结束 4 年：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;… 毕业作品《西藏组画》比他以前的作品在全国产生了更广泛的影响，被认为是冲击文革教条化创作模式的代表作品。&lt;a class="footnote-reference brackets" href="#id14" id="id8" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;那时候的绘画作品多是什么样子的呢？我们从 &lt;a class="reference external" href="https://zhuanlan.zhihu.com/p/58488380"&gt;文化大革命时期的绘画艺术&lt;/a&gt; 和 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/Template:文革时期艺术"&gt;📖 Template:文革时期艺术&lt;/a&gt; 可窥一二。&lt;/p&gt;
&lt;figure class="align-default" id="id25"&gt;
&lt;img alt="https://silverrainz.me/_images/220px-%E6%AF%9B%E4%B8%BB%E5%B8%AD%E5%8E%BB%E5%AE%89%E6%BA%90%E9%83%B5%E7%A5%A8.jpg" src="https://silverrainz.me/_images/220px-%E6%AF%9B%E4%B8%BB%E5%B8%AD%E5%8E%BB%E5%AE%89%E6%BA%90%E9%83%B5%E7%A5%A8.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;毛主席去安源郵票 &lt;a class="footnote-reference brackets" href="#id15" id="id9" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;在这个重大历史事件的余波后，西藏组画选择了一个新颖的、安全的主题，同时（即便抛开了时代背景）它又是真诚的，质朴的，有力的。它当之无愧地成为了中国艺术史上的一个里程碑。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id11"&gt;
&lt;h2&gt;比正稿更好的&lt;/h2&gt;
&lt;p&gt;相比最终的油画，我更喜欢陈老师为了这些油画而画的大量小稿：&lt;/p&gt;
&lt;figure class="align-default" id="id26"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_151718.jpg" src="https://silverrainz.me/_images/IMG_20210627_151718.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;进城 草稿之一&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;三人神态各异，男人喜笑颜开挽着女人走；女人怯生生垂下眉来，紧紧攥住孩子的手；孩子也稍稍露怯，但更多的是好奇，拉着女人的手到处张望。&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id27"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_152420.jpg" src="https://silverrainz.me/_images/IMG_20210627_152420.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;我非常喜欢这张，放牧的男人在从背后搂住正在喝水的女人，贴在女人背上粗犷的五官组合起来却是一脸的撒娇和宠溺。&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;我从这张画读到了 &lt;em&gt;「毫无廉耻」的爱和欲望&lt;/em&gt; ：草原辽阔但不至于毫无人迹，男人也不管周围可能有别的牧民，按捺不住对女人的喜欢，就在这天地之间搂抱在一起，天知道接下来还会发生什么。&lt;/p&gt;
&lt;p&gt;我所受的教育把我塑造成了羞于表达欲望的人，在我的潜意识里甚至会攻击敢于表达欲望的人—— 可是为什么这张画，能让我给「毫无廉耻」这四个字打上引号呢？&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id28"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_144927.jpg" src="https://silverrainz.me/_images/IMG_20210627_144927.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;喜欢这样拙拙的五官&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id29"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_145043.jpg" src="https://silverrainz.me/_images/IMG_20210627_145043.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;母与子 草稿之一&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id30"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_152435.jpg" src="https://silverrainz.me/_images/IMG_20210627_152435.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;忘记下面写的啥了，其实这张看起来单薄了。&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id31"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_152144.jpg" src="https://silverrainz.me/_images/IMG_20210627_152144.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;当街洗头的藏民&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;陈老师提及不敢细看裸体，所以这部分是回去后在补充的，我依然觉得画得好。&lt;/p&gt;
&lt;p&gt;垂下的头发和背景的形式感很好。&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="align-default" id="id32"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210627_150450.jpg" src="https://silverrainz.me/_images/IMG_20210627_150450.jpg" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;康巴汉子 草稿之一&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;为数不多的水彩草稿，右边的三角形汉子非常好。&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class="rubric"&gt;脚注&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id12" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id2"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.xinhuanet.com/shuhua/2021-05/12/c_1127435958.htm"&gt;http://www.xinhuanet.com/shuhua/2021-05/12/c_1127435958.htm&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id13" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id6"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://new.qq.com/omn/20210622/20210622A0AJG500.html"&gt;https://new.qq.com/omn/20210622/20210622A0AJG500.html&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id14" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id8"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/陈丹青#生平"&gt;📖 陈丹青#生平&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id15" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id9"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/毛主席去安源"&gt;📖 毛主席去安源&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/xzzh-after-40-yrs.html"/>
    <summary>2021-06-30</summary>
    <category term="展览" label="展览"/>
    <category term="绘画" label="绘画"/>
    <category term="陈丹青" label="陈丹青"/>
    <published>2021-07-03T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/sphinx-as-note-taking-system-2.html</id>
    <title>我如何用 Sphinx 建立笔记系统（二）系统架构</title>
    <updated>2021-05-25T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="sphinx"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是 &lt;a class="reference internal" href="blog/category/%E6%88%91%E5%A6%82%E4%BD%95%E7%94%A8-sphinx-%E5%BB%BA%E7%AB%8B%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F.html" title="我如何用 Sphinx 建立笔记系统"&gt;&lt;em&gt;我如何用 Sphinx 建立笔记系统&lt;/em&gt;&lt;/a&gt; 系列的第 二 篇，你可以通过订阅 &lt;a class="reference external" href="https://silverrainz.me/blog/atom.xml" title="银色子弹 Feed"&gt;&lt;span class="xref std std-ref"&gt;RSS&lt;/span&gt;&lt;/a&gt; 来获取后续更新。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;截至目前，我的笔记系统看起来是这样子的（使用 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib-plantuml"&gt;📦 sphinxcontrib-plantuml&lt;/a&gt; 生成）：&lt;/p&gt;
&lt;figure class="align-default" id="id8"&gt;
&lt;p class="plantuml"&gt;
&lt;img src="https://silverrainz.me/_images/plantuml-5c74529f9be50374765238d71047a84182c63b58.png" alt="folder &amp;quot;Git 仓库&amp;quot;  as repo {
   file &amp;quot;Sphinx 配置&amp;quot;
   file &amp;quot;reStructuredText 文档&amp;quot; as rst
   file &amp;quot;HTML 文档&amp;quot; as html
}

package &amp;quot;Sphinx&amp;quot; as sphinx {
   component &amp;quot;Snippet 扩展&amp;quot; as snippet.ext
}
sphinx -u-&amp;gt; html: 输出
rst -u-&amp;gt; sphinx: 构建

cloud pages.github as &amp;quot;Github Pages（主站）&amp;quot;
cloud pages.gitee as &amp;quot;Gitee Pages（镜像）&amp;quot;
repo -u-&amp;gt; pages.github: Github Action
pages.github -&amp;gt; pages.gitee: Github Action

file &amp;quot;Snippet 索引&amp;quot;  as snippet.cache
agent &amp;quot;Snippet 命令行工具&amp;quot; as snippet.cli
snippet.cli .u.&amp;gt; snippet.cache: 读取
snippet.ext .d.&amp;gt; snippet.cache: 写入
snippet.cli -u-&amp;gt; html: 浏览
snippet.cli -u-&amp;gt; rst: 浏览，编辑

node shell as &amp;quot;Z Shell&amp;quot;
node editor as &amp;quot;Neo(vim)&amp;quot;
shell -u-&amp;gt; snippet.cli: 浏览，编辑
editor -u-&amp;gt; snippet.cli: 浏览，编辑"/&gt;
&lt;/p&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;笔记系统架构&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;section id="git"&gt;
&lt;h2&gt;Git&lt;/h2&gt;
&lt;p&gt;我用 Git 仓库来管理整个 Sphinx 项目的版本，用 GitLFS 管理图片资源（后来因为 gitee 不支持又去掉了），仓库沿用之前建立的 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;一般来说 Sphinx 文档都会托管到 &lt;a class="reference external" href="https://readthedocs.io"&gt;ReadTheDocs&lt;/a&gt;，但出于部署和访问的方便，我基于 GitHub Action 写了 &lt;a class="extlink-ghrepo reference external" href="https://github.com/sphinxnotes/pages"&gt;⛺ sphinxnotes/pages&lt;/a&gt;，用来自动部署到 GitHub Pages，并使用 &lt;a class="extlink-ghrepo reference external" href="https://github.com/spyoungtech/mirror-action"&gt;⛺ spyoungtech/mirror-action&lt;/a&gt; 和 &lt;a class="extlink-ghrepo reference external" href="https://github.com/yanglbme/gitee-pages-action"&gt;⛺ yanglbme/gitee-pages-action&lt;/a&gt; 建立了国内的 Gitee 镜像。&lt;/p&gt;
&lt;div class="admonition tip"&gt;
&lt;p class="admonition-title"&gt;小技巧&lt;/p&gt;
&lt;p&gt;Github 和其他托管平台会在 Languages 统计时忽略常见的 Markup Languages（如 Markdown、restructuredText），为了让它能被统计 ，可以建立 &lt;code class="file docutils literal notranslate"&gt;&lt;span class="pre"&gt;.gitattributes&lt;/span&gt;&lt;/code&gt; 文件加入以下内容 &lt;a class="footnote-reference brackets" href="#id7" id="id1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;*.rst linguist-detectable=true
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在 GitHub 上可以看到 reStructuredText 被正确统计了：&lt;/p&gt;
&lt;figure class="align-default" id="id9"&gt;
&lt;img alt="https://silverrainz.me/_images/rst-language-stat.png" src="https://silverrainz.me/_images/rst-language-stat.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 的 Languages 统计&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="neo-vim"&gt;
&lt;h2&gt;Neo(Vim)&lt;/h2&gt;
&lt;p&gt;我用 Neovim 搭配各种插件编写 reST 文档，关于如何在舒服地用 (Neo)Vim 写 reST，我会再写一篇文章展开。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="vim"&gt;
&lt;h2&gt;从终端和 Vim 快速访问&lt;/h2&gt;
&lt;p&gt;浏览器、Vim 和终端模拟器是我最常待的 Workspaces，前者当然可以方便的访问 Sphinx 生成的 HTML 文档，为了满足从后两者操作文档的需求，我写了 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-snippet"&gt;📦 sphinxnotes-snippet&lt;/a&gt; ，包含一个 Sphinx 的扩展和一个命令行工具，你可以在刚才的架构图上看到它的角色。&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Snippet 扩展&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;会在构建文档的时候：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;自动提取文档片段：标题、代码、图片、段落等&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;中英文分词&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;简单地 normalize&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;提取关键字&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;中文转化为拼音&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;建立到文档的 &lt;em&gt;索引&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;然后保存在磁盘上待检索。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;扩展本身是「非侵入性」的，不需要用特定的格式编写文档，而是根据 reST 的文档树（doctree）进行提取&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Snippet 命令行工具&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;提供了简洁的命令行接口用以访问上述的 &lt;em&gt;索引&lt;/em&gt; ，基于此在 Zsh 和 Neovim 上实现了对应的插件：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;（在 Zsh 或者 Neovim 里）按下快捷键 &lt;kbd class="kbd docutils literal notranslate"&gt;C&lt;/kbd&gt;-&lt;kbd class="kbd docutils literal notranslate"&gt;k&lt;/kbd&gt;，后续一个按键给出操作方式，目前支持：
&lt;kbd class="kbd docutils literal notranslate"&gt;v&lt;/kbd&gt; 浏览、&lt;kbd class="kbd docutils literal notranslate"&gt;e&lt;/kbd&gt; 编辑、&lt;kbd class="kbd docutils literal notranslate"&gt;u&lt;/kbd&gt; 打开 URL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在 &lt;a class="extlink-ghrepo reference external" href="https://github.com/junegunn/fzf"&gt;Fzf&lt;/a&gt; 中输入关键词以筛选文档片段，支持拼音&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对你选中的文档片段执行指定操作&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;在这之前我「检索外脑」的延迟为 &lt;em&gt;数十秒&lt;/em&gt; ，根据所在 Workspace 的不同有不同的操作：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;在浏览器&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;打开主站或者 Gitee 镜像&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;根据记忆中的笔记结构一层层点进去&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 Sphinx 的内建搜索&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;事实上 Sphinx 内建的搜索不支持中文分词，因此实用程度基本为零&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;在 Vim&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;根据记忆中的笔记结构，打开 NERDTree 的侧边栏一层层展开&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;在终端&lt;/dt&gt;&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cd&lt;/span&gt;&lt;/code&gt; 到笔记所在目录执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;grep&lt;/span&gt; &lt;span class="pre"&gt;-r&lt;/span&gt; &lt;span class="pre"&gt;关键字&lt;/span&gt;&lt;/code&gt;，然而我的笔记中文内容居多
（一段时间内我甚至在考虑要不要用英文记笔记方便检索）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;根据记忆中的笔记结构一层层 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cd&lt;/span&gt;&lt;/code&gt; 进去，用 Vim 浏览&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;在使用 Snippet 后这一过程可以压缩到一秒内：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;在浏览器&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;切换到 Vim 或者终端&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;在 Vim&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;唤醒 Snippet，输入关键词（使用 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib.asciinema"&gt;📦 sphinxcontrib.asciinema&lt;/a&gt; 生成）&lt;/p&gt;
&lt;div id="asciicast-/_assets/snippet-with-vim.cast"&gt;&lt;/div&gt;
            &lt;script&gt;
                document.addEventListener("DOMContentLoaded", function() {
                    AsciinemaPlayer.create(
                        "data:text/plain;base64,eyJ2ZXJzaW9uIjogMiwgIndpZHRoIjogODAsICJoZWlnaHQiOiAyMiwgInRpbWVzdGFtcCI6IDE2MjE5Mjc5MTMsICJlbnYiOiB7IlNIRUxMIjogIi9iaW4venNoIiwgIlRFUk0iOiAieHRlcm0tMjU2Y29sb3IifX0KWzAuMjgwNTE4LCAibyIsICJcdTAwMWJbMW1cdTAwMWJbN20lXHUwMDFiWzI3bVx1MDAxYlsxbVx1MDAxYlswbSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcciBcciJdClswLjM0MTM0NiwgIm8iLCAiYyJdClswLjM0NTkwOCwgIm8iLCAiXHUwMDFiXTc7ZmlsZTovLy9ob21lL2xhL3dvcmtzcGFjZS9zcGhpbngtYXNpY2NuZW1hXHUwMDFiXFwiXQpbMC4zNzE4MjUsICJvIiwgIlxyXHUwMDFiWzBtXHUwMDFiWzI3bVx1MDAxYlsyNG1cdTAwMWJbSlx1MDAxYlszMm0vXHUwMDFiWzM5bSBcdTAwMWJbMW1cdTAwMWJbMzZtbGFcdTAwMWJbMzltIFx1MDAxYlszN21AXHUwMDFiWzM5bSBcdTAwMWJbMzVtbGEtdHBsNDUwXHUwMDFiWzM5bSBcdTAwMWJbMzBtMTU6MzFcdTAwMWJbMzltIFx1MDAxYlszN20tPlx1MDAxYlszOW0gXHUwMDFiWzMybX4vd29ya3NwYWNlL3NwaGlueC1hc2ljY25lbWFcdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlswbVxyXG5cdTAwMWJbMzJtXFxcdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNG0kIFx1MDAxYlszN21cdTAwMWJbMG1cdTAwMWJbMzdtXHUwMDFiW0tcdTAwMWJbPzIwMDRoIl0KWzAuMzc3MjE3LCAibyIsICJcdTAwMWJbMW1cdTAwMWJbMzFtY1x1MDAxYlswbVx1MDAxYlszOW1cdTAwMWJbOTBtZCAtMVx1MDAxYlszOW1cYlxiXGJcYiJdClswLjUzMjk0LCAibyIsICJcYlx1MDAxYlsxbVx1MDAxYlszMW1jXHUwMDFiWzFtXHUwMDFiWzMxbWFcdTAwMWJbMG1cdTAwMWJbMzltXHUwMDFiWzkwbXRcdTAwMWJbOTBtIFx1MDAxYls5MG1SXHUwMDFiWzkwbUVBRE1FLnJzdFx1MDAxYlszOW1cdTAwMWJbMTJEIl0KWzAuODY0NzM0LCAibyIsICJcYlxiXHUwMDFiWzBtXHUwMDFiWzMybWNcdTAwMWJbMG1cdTAwMWJbMzJtYVx1MDAxYlszMm10XHUwMDFiWzM5bSJdClsxLjAxMzIzOCwgIm8iLCAiXHUwMDFiWzM5bSAiXQpbMS4zNTIxNywgIm8iLCAiXHUwMDFiWzM5bVx1MDAxYls0bVJcdTAwMWJbMjRtIl0KWzEuMzY1NzQxLCAibyIsICJcYlx1MDAxYls0bVJcdTAwMWJbMzltXHUwMDFiWzRtRVx1MDAxYlsyNG0iXQpbMi4yMDUxMDksICJvIiwgIlxiXGJcdTAwMWJbMjRtXHUwMDFiWzkwbVJcdTAwMWJbMjRtXHUwMDFiWzkwbUVcYlxiIl0KWzIuMzM0Njg2LCAibyIsICJcYlxiXGJcYlx1MDAxYlszOW1cdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSAgXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMzltIFx1MDAxYlszOW0gXHUwMDFiWzM5bSBcdTAwMWJbMTREIl0KWzIuNTg3NDc1LCAibyIsICJcdTAwMWJbMzJtdlx1MDAxYlszOW1cdTAwMWJbOTBtaW0gUkVBRE1FLnJzdFx1MDAxYlszOW1cdTAwMWJbMTNEIl0KWzIuNjkxMzU1LCAibyIsICJcYlx1MDAxYlszMm12XHUwMDFiWzMybWlcdTAwMWJbMzltIl0KWzIuODI2NTE3LCAibyIsICJcYlxiXHUwMDFiWzMybXZcdTAwMWJbMzJtaVx1MDAxYlszMm1tXHUwMDFiWzM5bSJdClsyLjg3ODY1NSwgIm8iLCAiXHUwMDFiWzM5bSAiXQpbMy4xMjA3NCwgIm8iLCAiXHUwMDFiWzM5bVx1MDAxYls0bVJcdTAwMWJbMjRtIl0KWzMuMTM3OTczLCAibyIsICJcYlx1MDAxYls0bVJcdTAwMWJbMzltXHUwMDFiWzRtRVx1MDAxYlsyNG0iXQpbMy4zMjczMjYsICJvIiwgIlxiXHUwMDFiWzRtRVx1MDAxYlszOW1cdTAwMWJbNG1BXHUwMDFiWzM5bVx1MDAxYls0bURcdTAwMWJbMzltXHUwMDFiWzRtTVx1MDAxYlszOW1cdTAwMWJbNG1FXHUwMDFiWzM5bVx1MDAxYls0bS5cdTAwMWJbMzltXHUwMDFiWzRtclx1MDAxYlszOW1cdTAwMWJbNG1zXHUwMDFiWzM5bVx1MDAxYls0bXRcdTAwMWJbMjRtXHUwMDFiWzFtIFx1MDAxYlswbSJdClszLjY2NDU3OSwgIm8iLCAiXGJcdTAwMWJbMG0gXGIiXQpbMy42Njk2MjQsICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQpbMy42NzcxNjYsICJvIiwgIlx1MDAxYls/MTA0OWhcdTAwMWJbMjI7MDswdFx1MDAxYlsyMjswOzB0XHUwMDFiWz8xaFx1MDAxYj1cdTAwMWJbSFx1MDAxYlsySlx1MDAxYl0xMTs/XHUwMDA3XHUwMDFiWz8yMDA0aFx1MDAxYls/MjVoIl0KWzMuNjk3OTk3LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYihCXHUwMDFiW21cdTAwMWJbSFx1MDAxYlsySlx1MDAxYls/MTAwMmhcdTAwMWJbPzEwMDZoXHUwMDFiXTExMlx1MDAwN1x1MDAxYlsxIHFcdTAwMWJdMTEyXHUwMDA3XHUwMDFiWzEgcSJdClszLjkyODY1NywgIm8iLCAiXHUwMDFiWz8xMDA0aFx1MDAxYl0xMTJcdTAwMDdcdTAwMWJbMiBxXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0tcblx1MDAxYltLXG5cdTAwMWJbS1xuXHUwMDFiW0pcdTAwMWJbSCJdCls0LjA1NDA5MywgIm8iLCAiXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4bSAxIFJFQURNRS5yc3QgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEzNjsxOTI7MjA4bVx1MDAxYls0ODsyOzc2Ozg2OzEwNm3ugrBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjI5OzIzMzsyNDBtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs3Njs4NjsxMDZtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6Cslx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKzIFggXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs1OTs2Njs4Mm0gIDEgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybUkgd2lsbCBwcmVzcyBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7NTk7NjY7ODJtYGBjdHJsK2ssdmBgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybSB0byBcInZpZXcgcmVTVCBzbmlwcGV0c1wiLiAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG1OT1JNQUxcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMzY7MTkyOzIwOG1cdTAwMWJbNDg7MjsxMjk7MTYxOzE5M23ugrBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6CsFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZtIFJFQURNRS5yc3QgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzc2Ozg2OzEwNm1cdTAwMWJbNDg7Mjs3Njs4NjsiXQpbNC4wNTQyMzQsICJvIiwgIjEwNm3ugrJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjI5OzIzMzsyNDBtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2bSByc3QgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm3ugrJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTM2OzE5MjsyMDhtXHUwMDFiWzQ4OzI7MTI5OzE2MTsxOTNt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4bSA4VyDugrMgMTAwJSBcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDht4piwICAgIDEvMSDugqFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIDogIDEgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIzNTsyMDM7MTM5bVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4be6Cslx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxOTE7OTc7MTA2bVx1MDAxYls0ODsyOzIzNTsyMDM7MTM5be6Cslx1MDAxYlsyOzVIXHUwMDFiWz8yNWgiXQpbNC45NDY5OTcsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1eSyAgICAgICAgXHUwMDFiWzI7NUhcdTAwMWJbPzI1aCJdCls1LjI1OTM0OSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcclx1MDAxYlsyMjsxSFx1MDAxYltKOlx1MDAxYltBXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4bUNPTU1BTkRcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMzY7MTkyOzIwOG1cdTAwMWJbNDg7MjsxMjk7MTYxOzE5M23ugrBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6CsFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZtIFJFQURNRS5yc3RcdTAwMWJbMjI7MkhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtY2FsbFx1MDAxYltDZzpTcGhpbnhOb3Rlc1NuaXBwZXRMaXN0QW5kVmlldygpXHUwMDFiXTExMlx1MDAwN1x1MDAxYlsyIHFcclx1MDAxYlsyMjsxSFx1MDAxYls/MjVoIl0KWzUuMjc1NTQ0LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYl0xMTJcdTAwMDdcdTAwMWJbMiBxXHUwMDFiWz8yNWgiXQpbNS4yODYyODIsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bS0tIFRFUk1JTkFMIC0tXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bVx1MDAxYlsyNVhcdTAwMWJbMTs0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG10Ly8uLy82L3Qvbi8yOyNGWkYgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEzNjsxOTI7MjA4bVx1MDAxYls0ODsyOzEyOTsxNjE7MTkzbe6CsFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMjk7MTYxOzE5M20gMSBSRUFETUUucnN0IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKwXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm0gICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NzY7ODY7MTA2bVx1MDAxYls0ODsyOzc2Ozg2OzEwNm3ugrJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjI5OzIzMzsyNDBtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6CsyBYIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzE2MzsxOTA7MTQwbSB0YWIgMS8yIFxyXG5cdTAwMWIoQlx1MDAxYlswOzdtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXQpbNS4yODYzOTUsICJvIiwgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXQpbNS4yODY0MzEsICJvIiwgIiAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjI1OzM4OzExNG1cdTAwMWJbNDg7Mjs4Njs4Njs4Nm0gPiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTg4OzIyMTsxODltXHUwMDFiWzQ4OzI7ODY7ODY7ODZtZnpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE3OzIxNzsyMTdtXHUwMDFiWzQ4OzI7ODY7ODY7ODZtZiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMTlBIl0KWzUuMzA5OTQ3LCAibyIsICJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFxyXHUwMDFiWzE3Qlx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsxNTM7MjA0OzBtXHUwMDFiWzQ4OzI7NDY7NTI7NjRt4qC5XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTUzOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtMC8wXHJcblx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsxMDI7MTUzOzIwNG1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0+XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcdTAwMWIoQlx1MDAxYlswOzdtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFxyXHUwMDFiWzIwOzFIIl0KWzUuMzYzNDMsICJvIiwgIlx1MDAxYlsxODszSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzE1M21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1LSU5EICBFWENFUlBUICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUEFUSCAgICAgICAgICAgICAgICAgICAuLlxyXG5cbiJdCls1LjM4NDI4NCwgIm8iLCAiXHUwMDFiWzE4QVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0NDs0NDs0NG0gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBbZF0gICA8R1NvQyAyMDE2IOWwj+iusCAtIOivr+aJk+ivr+aSnuS4ieS4quaciD4gICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlxyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDQ7NDQ7NDRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gW2RdICAgPEdTb0MgMjAxNj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDzojrflj5YgdGVld29ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlxyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDQ7NDQ7NDRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gW2RdICAgPOS7jiBDIOa6kOeggeeUn+aIkCDlh73mlbAv5qih5Z2XIOiwg+eUqOWbvj4gICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDzku44gSmVreWxsIOi/geenu+WIsCBTcGhpbng+ICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlxyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDQ7NDQ7NDRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gW2RdICAgPOeriyBGbGFnPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbIl0KWzUuMzg0NDYxLCAibyIsICIzODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDxQeXRob24g5Yid6K+VPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDxkbyDorrDms5XlkowgPj49IOeahOetieaViOihqOi+vj4gICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDxBcmNoIExpbnV4IOaKmOiFvuWwj+iusD4gICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlxyXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDQ7NDQ7NDRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gW2RdICAgPEFkZCBJc3NvIENvbW1lbnRzIHRvIFlvdXIgU3BoaW54IERvY3VtZW50Li4gIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDwyMDE1IOWNjuWxseadryBDVEYgUmV2ZXJzZSAzMDA+ICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0NDs0NDs0NG0gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBbZF0gICA85pys56uZPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0NDsiXQpbNS4zODQ1MSwgIm8iLCAiNDQ7NDRtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gW2RdICAgPOW8oOebm+Wuhz4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFib3V0ICAgICAgICAgICAgICAgICAgLi5cclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFtkXSAgIDxNZT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0NDs0NDs0NG0gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBbZF0gICA85Y+L5Lq65biQPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWJvdXQgICAgICAgICAgICAgICAgICAuLlxyXG5cdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7MjA0OzA7NTFtXHUwMDFiWzQ4OzI7NDQ7NDQ7NDRtPlx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0NDs0NDs0NG0gXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzI0MzsyNDM7MjQzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0bVtkXSAgIDxFbmVteT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHJcblxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE1MzsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bTIwOC8yMDhcclxuIl0KWzUuNzI5ODc1LCAibyIsICJcdTAwMWJbQ1x1MDAxYltDIl0KWzUuNzQxMTI4LCAibyIsICJcdTAwMWJbMjs0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1jXSAgIC9iYXNoLyBTaGVsbCB2YXJpYWJsZXMgaW4gaGVyZWRvYyBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1pbGwgYmUgLi4gIE1hbiBcdTAwMWJbMzsxMEhWaW0gfkJ5IHRoZSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1heSBJIHVzZSBOZW9WaW0gOi0pfj4gICAgICAgICAgIE1hbiBcdTAwMWJbNDs0SGNdICAgL2NvbnNvbGUvIOS4reaWh+i3r+W+hOS5seeggTogICAgICAgICAgICAgICAgICAgICAgIE1hbiBcdTAwMWJbNTsxMEhPdmVyVGhlV2lyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYls2OzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1PdmVyVGhlV2lyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYls3OzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1PdmVyVGhlV2lyZSBCYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYls4OzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1PdmVyVGhlV2lyZSBCYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYls5OzEwSHdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Il0KWzUuNzQxMjc2LCAibyIsICI0Njs1Mjs2NG1hcmdhbWUtbGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL0NhcHR1cmUuLlx1MDAxYlsxMDs0SGNdICAgL3B5dGhvbi8gVGVtcCBmaWxlIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWl0aCByZWFsIHBhdGg6ICAgICAgICAgICAgTWFuIFx1MDAxYlsxMTsxMEjlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxMjsxMEjlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgIFx1MDAxYlsxMzsxMEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1hcmdtZS1iYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL0NhcHR1cmUuLlx1MDAxYlsxNDsxMEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1hcmdhbWUtbmFybmlhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL0NhcHR1cmUuLlx1MDAxYlsxNTsxMEjmmrTpnLLpl67popg+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm90ZXMv6YCg5Z6L5a6e6aqMLi5cdTAwMWJbMTY7NEhjXSAgIC92aW0vIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bTogd2luZG93OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbiAgXHUwMDFiWzE3OzEwSFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsyNDM7MjQzOzI0M21cdTAwMWJbNDg7Mjs0NDs0NDs0NG3pgLjpl7s+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL+WinumHj+iJuuacry4uXHUwMDFiWzE5OzNIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE1MzsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bTM5LzIwOFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTYiXQpbNS43NDEzMTYsICJvIiwgIjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcdTAwMWJbMjA7M0hcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiWzA7N21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gXGIiXQpbNS44Mjg4NTEsICJvIiwgIlx1MDAxYlsxOEFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZF0gICA8T3ZlclRoZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1XXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWlyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYlszOzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1PdmVyVGhlXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bVdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaXJlIExldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bS4uXHUwMDFiWzQ7NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZF0gICA8T3ZlclRoZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1XXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWlyZSBCYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYls1OzE3SFdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2dcdTAwMWJbNjsxMEhNaW5peCB2MSDmlofku7bns7vnu5/nmoTlrp7njrA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYls3OzEwSE1pbml4IHYxIOaWh+S7tuezu+e7n+eahOWunueOsD4gICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiWzg7MTBIVmltIH5CeSB0aGUgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwIl0KWzUuODI5MDk2LCAibyIsICIyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1heSBJIHVzZSBOZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bVZpbSA6LSl+PiAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYls5OzEwSOiOt+WPliB0ZWVcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd29cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtcmxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxMDs0SGRdICAgPOiOt+WPliB0ZWVcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd29cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtcmxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgIEJsb2dcdTAwMWJbMTE7MTBI5oqKIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1XXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWluZFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdzIOS4reaWh+eUqOaIt+WQjeaUueS4uuiLseaWhz5cdTAwMWJbMTI7MTBI5oqKIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1XXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWluZFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdzIOS4reaWh+eUqOaIt+WQjeaUueS4uuiLseaWhz5cdTAwMWJbMTM7NEhjXSAgIC92aW0vIHc6IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMiXQpbNS44MjkyMDMsICJvIiwgIjNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaW5kXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bW9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICBcdTAwMWJbMTQ7MTBIQXJ0IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1Xb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1ya3MgfkFsbCB0aGluZ3MgbGlzdCBoZXJlIGlzIG5vdCDigJxhLi4gIENvbGxlY3QuLiAgICAgIFx1MDAxYlsxNTsxMEjmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n++8iOS4gO+8iemAieaLqSBTcC4uICDml6Xlv5cgICAgICAgICAgICBcdTAwMWJbMTY7NEhkXSAgIDzlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE3OzEwSFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsyNDM7MjQzOzI0M21cdTAwMWJbNDg7Mjs0NDs0NDs0NG3lmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgIFx1MDAxYlsxOTszSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNTM7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0yOFx1MDAxYlsyMDs0SFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbMDs3bVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcYiJdCls2LjAzNjMzMiwgIm8iLCAiXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcdTAwMWIoQlx1MDAxYlswOzdtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFxiXGJcYiJdCls2LjIyOTk4NiwgIm8iLCAiXHUwMDFiW0NcdTAwMWJbQyJdCls2LjI0MDg4MiwgIm8iLCAiXHUwMDFiWzI7MTBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtYVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWdhbWUtbGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG10ZXMvQ2FwdHVyZS4uICAgICAgICAuLlx1MDAxYlszOzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtclx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1nbWUtYmFuZGl0PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bW9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdGVzL0NhcHR1cmUuLiAgICAgICAgLi5cdTAwMWJbNDsxMEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1hXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZ2FtZS1uYXJuaWE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTlx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXRlcy9DYXB0dXJlLi4gICAgICAgIC4uXHUwMDFiWzU7MTBIRmxvXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdcdTAwMWIoQiJdCls2LjI0MTA4NiwgIm8iLCAiXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG10ZXMvU1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWFpbiBBLi4gICAgICAgIC4uXHUwMDFiWzY7NEhjXSAgIC9weXRob24vIE5lXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIGluIHB5dGhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1uIDMuNy4gICAgICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtLi5cdTAwMWJbNzsxMEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtT3ZlXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtVGhlXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bVdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaXJlIExldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bS4uXHUwMDFiWzg7MTBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bU92ZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bVRoZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMyJdCls2LjI0MTE2NywgIm8iLCAiODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bVdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaXJlIExldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bS4uXHUwMDFiWzk7MTBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bU92ZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bVRoZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1XXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWlyZSBCYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYlsxMDsxMEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtT3ZlXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtVGhlXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bVdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bS4uXHUwMDFiWzExOzRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWNdICAgL2NvbnNvbGUvIOWwhuiiq+W/veeVpeeahOivreiogO+8iOWmgiBNYXJrZG9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1u44CBXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMiJdCls2LjI0MTE5NiwgIm8iLCAiOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtclx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1lcy4uICBNYW5cdTAwMWJbMTI7NEhjXSAgIC9hXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtay8gUHJpbnQgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZW1haW5pbmcgY1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1vXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWx1bW5zIDEgICAgICAgICAgICAgICBNYW4gXHUwMDFiWzEzOzEwSGFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1rLyBVc2UgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZWd1bGFyIGV4cHJlc3NpXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bW9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtbjpcdTAwMWJbMTQ7MTBI6I635Y+WIHRlZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13b3JcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtbGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE1OzEwSOiOt+WPliB0ZWVcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd29yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgIEJsb2dcdTAwMWJbMTY7MTBIQVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszOCJdCls2LjI0MTIxNywgIm8iLCAiOzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdCBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtV29cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtcmtzIH5BbGwgdGhpbmdzIGxpc3QgaGVyZSBpcyBub3Qg4oCcYS4uICBDb2xsZWN0Li5cdTAwMWJbMTc7MTBIXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzI0MzsyNDM7MjQzbVx1MDAxYls0ODsyOzQ0OzQ0OzQ0beaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf77yI5LiA77yJ6YCJ5oupIFNwLi4gIOaXpeW/l1x1MDAxYlsxOTszSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNTM7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0xOVx1MDAxYlsyMDs2SFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbMDs3bVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcYiJdCls2LjM4NzA2MiwgIm8iLCAiXHJcdTAwMWJbMThBXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYls3OzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtclx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1nYW1lLWxldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bW9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdGVzL0NhcHRcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yZS4uICAgICAgICAuLlx1MDAxYls4OzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtclx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Il0KWzYuMzg3MjUxLCAibyIsICIyOzY0bWdtZS1iYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG10ZXMvQ2FwdFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG11XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJlLi4gICAgICAgIC4uXHUwMDFiWzk7MTBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtYXJnYW1lLW5hXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtbmlhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG10ZXMvQ2FwdFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG11XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJlLi4gICAgICAgIC4uXHUwMDFiWzEwOzRIY10gICAvYVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWsvIFByaW50IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWVtYWluaW5nIGNcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1sXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXVcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtbW5zIDEgICAgICAgICAgICAiXQpbNi4zODczMDMsICJvIiwgIiAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbMTE7MTBIYXdrLyBkYXRlMjAyMC0xMi0yNSAgICAgICAgICAgICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtLi5cdTAwMWJbMTI7NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZF0gICA86I635Y+WIHRlZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13b1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzEzOzRIZF0gICA86I635Y+WIHRlZVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13b1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgQmxvZ1x1MDAxYlsxNDs0SGNdICAgL2FcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtd1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1rLyBVc2UgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZWdcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1sYXIgZXhwcmVzc2lcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1uOiAgICAgICAgICAgICAgICAgTWFuXHUwMDFiWzE1OzRIY10gICAvY29uc29sZS8g5bCG6KKr5b+955Wl55qE6K+t6KiA77yI5aaCIE1hcmtkb1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bW7jgIFyZXMiXQpbNi4zODczMywgIm8iLCAiLi4gIE1hbiBcdTAwMWJbMTY7MTFIcnQgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bVdvXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bXJrcyB+QWxsIHRoaW5ncyBsaXN0IGhlcmUgaXMgbm90IOKAnGEuLiAgQ29sbGVjdC4uICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtLi5cdTAwMWJbMTk7NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTUzOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtMVx1MDAxYlsyMDs3SFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG11XHUwMDFiKEJcdTAwMWJbMDs3bVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSBcYiJdCls2LjYyMzQ0NCwgIm8iLCAiXHJcdTAwMWJbMTNBXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzEzOzEwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG13XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtclx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1nYW1lLWxldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEwMjsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bW9cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdGVzL0NhcHRcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtdVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1yZS4uICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTAyOzE1MzsxMDJtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtLi5cdTAwMWJbMTQ7MTFIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOyJdCls2LjYyMzU5NywgIm8iLCAiNjRtd2svIGRhdGUyMDIwLTEyLTI1ICAgICAgICAgICAgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMDI7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0uLlx1MDAxYlsxOTszSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNTM7MTUzOzEwMm1cdTAwMWJbNDg7Mjs0Njs1Mjs2NG01LzIwOFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gXHUwMDFiWzIwOzhIXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWhcdTAwMWIoQlx1MDAxYlswOzdtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtIFxiIl0KWzYuNzU0NjQ4LCAibyIsICJcclx1MDAxYls3QVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE5OzNIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE1MzsxNTM7MTAybVx1MDAxYls0ODsyOzQ2OzUyOzY0bTRcdTAwMWJbMjA7OUhcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtZVx1MDAxYihCXHUwMDFiWzA7N21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG0gXGIiXQpbNy4xMjgxNjIsICJvIiwgIlxyXHUwMDFiWzE4QSJdCls3LjIzNDIxLCAibyIsICJcdTAwMWJbMjBCIl0KWzcuMzYxODUxLCAibyIsICJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtMzM2IG1vcmUgbGluZXNcclx1MDAxYlsyMjsxSCJdCls3LjM5NDQ2MywgIm8iLCAiXHUwMDFiWzE0WFx1MDAxYlsxOzJIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4bTIgW05vIE5hbWVdIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMzY7MTkyOzIwOG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKwXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzc2Ozg2OzEwNm1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm3ugrMgWCBcclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybSAgMSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NTk7NjY7ODJtSSB3aWxsIHByZXNzIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs1OTs2Njs4Mm1gYGN0cmwrayx2YGBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NTk7NjY7ODJtIHRvIFwidmlldyByZVNUIHNuaXBwZXRzXCIuICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzQ2OzUyOzY0bX5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcbn5cdTAwMWJbS1xyXG5+XHUwMDFiW0tcclxuflx1MDAxYltLXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZtIFJFQURNRS5yc3QgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzc2Ozg2OzEwNm1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm0gcnN0IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs3Njs4NjsxMDZtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6Csu6Cslx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZtIDhXIO6CsyAxMDAlIOKYsCAgICAxLzEg7oKhIDogIDEgXHJcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbIl0KWzcuMzk0NjIyLCAibyIsICI0ODsyOzQ2OzUyOzY0bTMzNiBtb3JlIGxpbmVzXHUwMDFiWzQ4QzMzNywwLTEgICAgICAgQm90XHUwMDFiWzU7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIFsjXSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtaHR0cHM6Ly9kb2N1dGlscy5zb3VyY2Vmb3JnZS5pby9yc3QuaHRtbFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICBcdTAwMWJbNjsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gWyNdIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1odHRwczovL3d3dy5zcGhpbngtZG9jLm9yZ1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICAgIFx1MDAxYls3OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBbI10gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bTpkb2M6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bWAvbWFuL2dpdGAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzg7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbOTsxNEgtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVx1MDAxYlsxMDsxNEgtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs1OTs2Njs4Mm0tXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzExOzE0SCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzEyOzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBpc3NvOjpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAiXQpbNy4zOTQ2NTMsICJvIiwgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxMzsxNEggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxNDsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszbVx1MDAxYlszODsyOzk3OzExMDsxMzZtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtSW5zZXJ0ZWQgQnkgc3BoaW54bm90ZXMtc25pcHBldDpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgXHUwMDFiWzE1OzE0SCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE2OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbM21cdTAwMWJbMzg7Mjs5NzsxMTA7MTM2bVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICAgUHJlc3MgPEVOVEVSPiB0byByZXR1cm5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxNzsxNEggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxMzsxNEhcdTAwMWJbPzI1aCJdCls4LjE3NjM1MywgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWcgICAgICAgICBcdTAwMWJbMTM7MTRIXHUwMDFiWz8yNWgiXQpbOC4yNjc4ODEsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCBcdTAwMWJbMTM7MTRIXHUwMDFiWz8yNWhcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEhnZ1x1MDAxYlsxMzsxNEhcdTAwMWJbPzI1aCJdCls4LjI3MTA4MSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbNTsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbNjsxNEg9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVx1MDAxYls3OzE0SOaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf77yI5LiA77yJ6YCJ5Z6L5LiO5oiQ5b2iXHUwMDFiWzg7MTRIPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cdTAwMWJbOTsxNEggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsxMDsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gcG9zdDo6IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0yMDIxLTA1LTI1XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICAgICBcdTAwMWJbMTE7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDp0YWdzOiBTcGhpbnhcdTAwMWJbMTI7MTRIICAgOmF1dGhvcjogTEFcdTAwMWJbMTM7MTRIICAgOmNhdGVnb3J5OiDmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n1x1MDAxYlsxNDsxNEggICA6bGFuZ3VhZ2U6IHpoX0NOXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICAgICAgICAgICAgICBcdTAwMWJbMTY7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIG5vdGU6OiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt6L+Z5piv44CK5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/jgIvns7vliJfnmoRcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7Njc7NzY7OTRtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPlx1MDAxYlsxNzsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt56ys5LiA56+H44CCXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyIl0KWzguMjcxMjUzLCAibyIsICI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybSBcdTAwMWJbMjI7NjNIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bTEsMC0xICAgICAgICAgVG9wXHUwMDFiWzU7MTRIXHUwMDFiWz8yNWgiXQpbOC42MTU2NCwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIZ2ogICAgICAgIFx1MDAxYls1OzE0SFx1MDAxYls/MjVoIl0KWzguNjE2NTYyLCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEggIFx1MDAxYls5RDIsMSAgICAgICAgICAgVG9wXHUwMDFiWzY7MTRIXHUwMDFiWz8yNWgiXQpbOS4yMTY3MTgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbNjsxNEhcdTAwMWJbPzI1aCJdCls5LjIxNzQxOCwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbOUQzLDEgICAgICAgICAgIFRvcFx1MDAxYls3OzE0SFx1MDAxYls/MjVoIl0KWzkuMjU2NDUzLCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEhnaiAgICAgICAgXHUwMDFiWzc7MTRIXHUwMDFiWz8yNWgiXQpbOS4yNTcyNDQsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzlENCwxICAgICAgICAgICBUb3BcdTAwMWJbODsxNEhcdTAwMWJbPzI1aCJdCls5LjI5NTYxOCwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIZ2ogICAgICAgIFx1MDAxYls4OzE0SFx1MDAxYls/MjVoIl0KWzkuMjk2MDg2LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEggIFx1MDAxYls5RDUsMC0xICAgICAgICAgVG9wXHUwMDFiWzk7MTRIXHUwMDFiWz8yNWgiXQpbOS4zMzQzMTMsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbOTsxNEhcdTAwMWJbPzI1aCJdCls5LjMzNDYzNSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbOUQ2LDEgICAgICAgICAgIFRvcFx1MDAxYlsxMDsxNEhcdTAwMWJbPzI1aCJdCls5LjM3NTA4OCwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIZ2ogICAgICAgIFx1MDAxYlsxMDsxNEhcdTAwMWJbPzI1aCJdCls5LjM3NjMxNSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbOUQ3LDEgICAgICAgICAgIFRvcFx1MDAxYlsxMTsxNEhcdTAwMWJbPzI1aCJdCls5LjQxNjMyMywgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIZ2ogICAgICAgIFx1MDAxYlsxMTsxNEhcdTAwMWJbPzI1aCJdCls5LjQxNzA2MSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbOUQ4LDEgICAgICAgICAgIFRvcFx1MDAxYlsxMjsxNEhcdTAwMWJbPzI1aCJdCls5LjQ1NTUsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS40NTYwNzksICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzE3OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsyMjs2M0hcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtOSwxICAgICAgICAgICAgMCVcdTAwMWJbNTsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cdTAwMWJbOVhcdTAwMWJbNjsxNEjmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n++8iOS4gO+8iemAieWei+S4juaIkOW9olx1MDAxYls5WFx1MDAxYls3OzE0SD09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHUwMDFiWzlYXHUwMDFiWzg7MTRIXHUwMDFiWzUzWFxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIHBvc3Q6OiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtMjAyMS0wNS0yNVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzNYXHUwMDFiWzEwOzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6dGFnczogU3BoaW54XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszN1hcdTAwMWJbMTE7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDphdXRob3I6IExBXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszOVhcdTAwMWJbMTI7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDpjYXRlZ29yeTog5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu59cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzExWFx1MDAxYlsxMzsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgOmxhbmd1YWdlOiB6aF9DTlx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyIl0KWzkuNDU2MjE1LCAibyIsICI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszNFhcdTAwMWJbMTQ7MTRIXHUwMDFiWzUzWFxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIG5vdGU6OiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt6L+Z5piv44CK5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/jgIvns7vliJfnmoRcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7Njc7NzY7OTRtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPlx1MDAxYlsxNjsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt56ys5LiA56+H44CCXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICAgICAgICAgICAgICAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs1OTs2Njs4Mm0gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlsyNlhcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS40OTU0NSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWdqICAgICAgICBcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS40OTc1NjQsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzE3OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBub3RlOjpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMjI7NjNIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bTEwLDEgICAgICAgICAgIDAlXHUwMDFiWzU7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0beaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf77yI5LiA77yJ6YCJ5Z6L5LiO5oiQ5b2iXHUwMDFiWzlYXHUwMDFiWzY7MTRIPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cdTAwMWJbOVhcdTAwMWJbNzsxNEhcdTAwMWJbNTNYXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gcG9zdDo6IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0yMDIxLTA1LTI1XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszM1hcdTAwMWJbOTsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgOnRhZ3M6IFNwaGlueFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzdYXHUwMDFiWzEwOzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6YXV0aG9yOiBMQVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzlYXHUwMDFiWzExOzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6Y2F0ZWdvcnk6IOaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757ufXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlsxMVhcdTAwMWJbMTI7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDpsYW5ndWFnZTogemhfQ05cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7Il0KWzkuNDk3OTczLCAibyIsICI3Njs5NG1cdTAwMWJbMzRYXHUwMDFiWzEzOzE0SFx1MDAxYls1M1hcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBub3RlOjogXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bei/meaYr+OAiuaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf44CL57O75YiX55qEXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzY3Ozc2Ozk0bVx1MDAxYls0ODsyOzY3Ozc2Ozk0bT5cdTAwMWJbMTU7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0beesrOS4gOevh+OAglx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NTk7NjY7ODJtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMjZYXHUwMDFiWzE2OzE0SFx1MDAxYls1M1hcdTAwMWJbNEFcdTAwMWJbPzI1aCJdCls5LjUzNDcxNiwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWdqICAgICAgICBcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS41MzUzODgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzE3OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsyMjs2NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtMSwwLTEgICAgICAgICAwJVx1MDAxYls1OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVx1MDAxYls5WFx1MDAxYls2OzE0SFx1MDAxYls1M1hcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBwb3N0OjogXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bTIwMjEtMDUtMjVcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzMzWFx1MDAxYls4OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6dGFnczogU3BoaW54XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszN1hcdTAwMWJbOTsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgOmF1dGhvcjogTEFcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzM5WFx1MDAxYlsxMDsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgOmNhdGVnb3J5OiDmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n1x1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMTFYXHUwMDFiWzExOzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6bGFuZ3VhZ2U6IHpoX0NOXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszNFhcdTAwMWJbMTI7MTRIXHUwMDFiWzUzWFxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIG5vdGU6OiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTQiXQpbOS41MzU1OTQsICJvIiwgIm3ov5nmmK/jgIrmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n+OAi+ezu+WIl+eahFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7Mjs2Nzs3Njs5NG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0+XHUwMDFiWzE0OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG3nrKzkuIDnr4fjgIJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzI2WFx1MDAxYlsxNTsxNEhcdTAwMWJbNTNYXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gbm90ZTo6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYls0NFhcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS41NzQ3OTQsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1naiAgICAgICAgXHUwMDFiWzEyOzE0SFx1MDAxYls/MjVoIl0KWzkuNTc2MDgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzE0OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICDov5nkuKrnrJTorrDns7vnu5/mmK/luKbmnInlvLrng4jkuKrkurroibLlvannmoQgOnJlZjpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtYOeslOiusOezu+e7n+Wculx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7Mjs2Nzs3Njs5NG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0+XHUwMDFiWzE1OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICDmma9gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSDkuK3or57nlJ/nmoTvvIzlubbkuI3pgILlkIjmiYDmnInkurrvvIzkvaDlj6/ku6XnqI3kvZzkuobop6PvvIzlho3lhrNcdTAwMWJbMTY7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG3lrprmmK/lkKbnu6fnu63pmIXor7vjgILlj6bvvIzlvIDlpLTorrLkuobkuIDkupvlhbPkuo7nrJTorrDnmoTml6DogYrlvoDkuotcdTAwMWJbMTc7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG3vvIznm7TmjqXot7Pov4fkuZ/ml6DlpqjjgIJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzMyWFx1MDAxYlsyMjs2NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtMiwxICAgICAgICAgICAyJVx1MDAxYls1OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6YXV0aG9yOiBMQVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzlYXHUwMDFiWzY7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDpjYXRlZ29yeTog5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu59cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4Il0KWzkuNTc2MjAxLCAibyIsICI7Mjs2Nzs3Njs5NG1cdTAwMWJbMTFYXHUwMDFiWzc7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgIDpsYW5ndWFnZTogemhfQ05cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzM0WFx1MDAxYls4OzE0SFx1MDAxYls1M1hcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBub3RlOjogXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bei/meaYr+OAiuaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf44CL57O75YiX55qEXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzY3Ozc2Ozk0bVx1MDAxYls0ODsyOzY3Ozc2Ozk0bT5cdTAwMWJbMTA7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0beesrOS4gOevh+OAglx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NTk7NjY7ODJtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMjZYXHUwMDFiWzExOzE0SFx1MDAxYls1M1hcblx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0uLiBub3RlOjpcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzQ0WFx1MDAxYlsxMzsxNEhcdTAwMWJbNTNYXHUwMDFiWzRBXHUwMDFiWz8yNWgiXQpbOS42MTQ2NjgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1naiAgICAgICAgXHUwMDFiWzk7MTRIXHUwMDFiWz8yNWgiXQpbOS42MTUwMzksICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzZENzAtNTQgICAgICAgMiVcdTAwMWJbMTA7MTRIXHUwMDFiWz8yNWgiXQpbOS42NTQ1MjgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbMTA7MTRIXHUwMDFiWz8yNWgiXQpbOS42NTQ4NjUsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzhEMywwLTEgICAgICAgICAyJVx1MDAxYlsxMTsxNEhcdTAwMWJbPzI1aCJdCls5LjY5NTU0NSwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIZ2ogICAgICAgIFx1MDAxYlsxMTsxNEhcdTAwMWJbPzI1aCJdCls5LjY5NTk2MywgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbOEQ0LDEgICAgICAgICAgIDIlXHUwMDFiWzEyOzE0SFx1MDAxYls/MjVoIl0KWzkuNzM2ODM5LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEhnaiAgICAgICAgXHUwMDFiWzEyOzE0SFx1MDAxYls/MjVoIl0KWzkuNzM4MTQsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzE3OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlsyMjs2NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtNSwwLTEgICAgICAgICAyJVx1MDAxYls1OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICA6Y2F0ZWdvcnk6IOaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757ufXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlsxMVhcdTAwMWJbNjsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgOmxhbmd1YWdlOiB6aF9DTlx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzRYXHUwMDFiWzc7MTRIXHUwMDFiWzUzWFxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEyOTsxNjE7MTkzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bS4uIG5vdGU6OiBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt6L+Z5piv44CK5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/jgIvns7vliJfnmoRcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7Njc7NzY7OTRtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPlx1MDAxYls5OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG3nrKzkuIDnr4fjgIJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzU5OzY2OzgybSBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtXHUwMDFiWzI2WFx1MDAxYlsxMDsxNEhcdTAwMWJbNTNYXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gbm90ZTo6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYls0NFhcdTAwMWJbMTI7MTRIXHUwMDFiWzUzWFxuXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSAgICJdCls5LjczODQ5MywgIm8iLCAi6L+Z5Liq56yU6K6w57O757uf5piv5bim5pyJ5by654OI5Liq5Lq66Imy5b2p55qEIDpyZWY6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bWDnrJTorrDns7vnu5/lnLpcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7Njc7NzY7OTRtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPlx1MDAxYlsxNDsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAg5pmvYFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxNjM7MTkwOzE0MG1cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0g5Lit6K+e55Sf55qE77yM5bm25LiN6YCC5ZCI5omA5pyJ5Lq677yM5L2g5Y+v5Lul56iN5L2c5LqG6Kej77yM5YaN5YazXHUwMDFiWzE1OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt5a6a5piv5ZCm57un57ut6ZiF6K+744CC5Y+m77yM5byA5aS06K6y5LqG5LiA5Lqb5YWz5LqO56yU6K6w55qE5peg6IGK5b6A5LqLXHUwMDFiWzE2OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRt77yM55u05o6l6Lez6L+H5Lmf5peg5aao44CCXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYlszMlhcdTAwMWJbMTI7MTRIXHUwMDFiWz8yNWgiXQpbOS43NzQxODYsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1naiAgICAgICAgXHUwMDFiWzEyOzE0SFx1MDAxYls/MjVoIl0KWzkuNzc1OTUxLCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEggIFx1MDAxYlsxMzsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE0OzE0SCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzE1OzE0SCAgICAg77yI5LiA55u05Lul5p2l77yM77yJOmZyaWVuZDpgU2lsdmVyUmFpblpgIO+8iOaMh+aIkeiHquW3se+8iVx1MDAxYlsxNjsxNEggICAgIOWcqOS9v+eUqOS4gOS4qui/mOacquWtmOWcqOeahOiHquW7uueslOiusOezu+e7n++8jOavj+asoeaDs+WGmeeCueS4nOilv1x1MDAxYlsxNzsxNEggICAgIOmDveWboOS4uuOAjOaXoOazleino+WGs+S+nei1luOAjeiAjOWksei0peOAgiBbI11fXHUwMDFiWzEzWFx1MDAxYlsyMjs2NEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtNiwxICAgICAgICAgICAzJVx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbNTsxNEhcdTAwMWJbNTNYXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtLi4gbm90ZTo6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bVx1MDAxYls0NFhcdTAwMWJbNzsxNEhcdTAwMWJbNTNYXG5cdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTYzOzE5MDsxNDBtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAg6L+Z5Liq56yU6K6w57O757uf5piv5bim5pyJ5by654OI5Liq5Lq66Imy5b2p55qEIDpyZWY6XHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bWDnrJTorrDns7vnu5/lnLpcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7Njc7NzY7OTRtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtPlx1MDAxYls5OzE0SFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG0gICDmma9gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0bSDkuK3or57nlJ/nmoTvvIzlubbkuI3pgILlkIjmiYDmnInkurrvvIzkvaDlj6/ku6XnqI3kvZwiXQpbOS43NzYyMzMsICJvIiwgIuS6huino++8jOWGjeWGs1x1MDAxYlsxMDsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0beWumuaYr+WQpue7p+e7remYheivu+OAguWPpu+8jOW8gOWktOiusuS6huS4gOS6m+WFs+S6jueslOiusOeahOaXoOiBiuW+gOS6i1x1MDAxYlsxMTsxNEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7Njc7NzY7OTRtICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzE2MzsxOTA7MTQwbVx1MDAxYls0ODsyOzY3Ozc2Ozk0be+8jOebtOaOpei3s+i/h+S5n+aXoOWmqOOAglx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs2Nzs3Njs5NG1cdTAwMWJbMzJYXHUwMDFiWzEyOzE0SFx1MDAxYls1M1hcdTAwMWJbNEFcdTAwMWJbPzI1aCJdCls5LjgxNTQ3OCwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIxNjsyMjI7MjMzbVx1MDAxYls0ODsyOzQ2OzUyOzY0bWdqICAgICAgICBcdTAwMWJbODsxNEhcdTAwMWJbPzI1aCJdCls5LjgxNjE3MiwgIm8iLCAiXHUwMDFiWz8yNWxcdTAwMWJbMjI7NzBIICBcdTAwMWJbNkQ3NC01NyAgICAgICAzJVx1MDAxYls5OzE3SFx1MDAxYls/MjVoIl0KWzkuODU1MjEzLCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEhnaiAgICAgICAgXHUwMDFiWzk7MTdIXHUwMDFiWz8yNWgiXQpbOS44NTU1OTgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzZEMTQ4LTExMCAgICAgMyVcdTAwMWJbMTA7MTdIXHUwMDFiWz8yNWgiXQpbOS44OTUwOTMsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbMTA7MTdIXHUwMDFiWz8yNWgiXQpbOS44OTU2MjMsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzZEMjIzLTE2MyAgICAgMyVcdTAwMWJbMTE7MTdIXHUwMDFiWz8yNWgiXQpbOS45MzUyMzYsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSGdqICAgICAgICBcdTAwMWJbMTE7MTdIXHUwMDFiWz8yNWgiXQpbOS45MzU2MjMsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzIyOzcwSCAgXHUwMDFiWzhENywwLTEgICAgICAgICAzJVx1MDAxYlsxMjsxNEhcdTAwMWJbPzI1aCJdClsxMC41MjA0ODksICJvIiwgIlx1MDAxYls/MjVsXHJcdTAwMWJbMTBCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzIyOzFIOmNhbGxcdTAwMWJbQ252aW1fd2luX2Nsb3NlKGc6c3BoaW54X25vdGVzX3NuaXBwZXRfd2luLFx1MDAxYltDdjp0cnVlKVx1MDAxYl0xMTJcdTAwMDdcdTAwMWJbMiBxXHJcdTAwMWJbMjI7MUhcdTAwMWJbPzI1aCJdClsxMC41ODM0NTgsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiWzU7MTRIXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzQ2OzUyOzY0bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzY7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbNzsxNEggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYls4OzE0SCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiWzk7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTA7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTE7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTI7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTM7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTQ7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTU7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTY7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTc7MTRIICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbMTsySFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG0xIFJFQURNRS5yc3QgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEzNjsxOTI7MjA4bVx1MDAxYls0ODsyOzc2Ozg2OzEwNm3ugrBcclx1MDAxYlsyMEJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIFx1MDAxYihCXHUwMDFiWzA7MW1cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyIl0KWzEwLjU4Mzg0NiwgIm8iLCAiOzIwOG1OT1JNQUxcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMzY7MTkyOzIwOG1cdTAwMWJbNDg7MjsxMjk7MTYxOzE5M23ugrBcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTI5OzE2MTsxOTNtXHUwMDFiWzQ4OzI7NzY7ODY7MTA2be6CsFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMjk7MjMzOzI0MG1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZtIFJFQURNRS5yc3QgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzc2Ozg2OzEwNm1cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm0gcnN0IFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKyXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEzNjsxOTI7MjA4bVx1MDAxYls0ODsyOzEyOTsxNjE7MTkzbe6Cslx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG0gOFcg7oKzIDEwMCUgXHUwMDFiKEJcdTAwMWJbMDsxbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4beKYsCAgICAxLzEg7oKhXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzU5OzY2OzgybVx1MDAxYls0ODsyOzEzNjsxOTI7MjA4bSA6ICAxIFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMzU7MjAzOzEzOW1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG3ugrJcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MTkxOzk3OzEwNm1cdTAwMWJbNDg7MjsyMzU7MjAzOzEzOW3ugrJcdTAwMWJdMTEyXHUwMDA3XHUwMDFiWzIgcVx1MDAxYlsyOzVIXHUwMDFiWz8yNWgiXQpbMTEuMzU1ODg3LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYlsyMjs3MEhcdTAwMWIoQlx1MDAxYlttXHUwMDFiWzM4OzI7MjE2OzIyMjsyMzNtXHUwMDFiWzQ4OzI7NDY7NTI7NjRtOlx1MDAxYlsyOzVIXHUwMDFiWz8yNWgiXQpbMTEuMzU5MDE0LCAibyIsICJcdTAwMWJbPzI1bFxyXHUwMDFiWzIwQlx1MDAxYls3MFg6XHUwMDFiW0FcdTAwMWIoQlx1MDAxYlswOzFtXHUwMDFiWzM4OzI7NTk7NjY7ODJtXHUwMDFiWzQ4OzI7MTM2OzE5MjsyMDhtQ09NTUFORFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7Mjs1OTs2Njs4Mm1cdTAwMWJbNDg7MjsxMzY7MTkyOzIwOG0gXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzEzNjsxOTI7MjA4bVx1MDAxYls0ODsyOzEyOTsxNjE7MTkzbe6CsFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsxMjk7MTYxOzE5M21cdTAwMWJbNDg7Mjs3Njs4NjsxMDZt7oKwXHUwMDFiKEJcdTAwMWJbbVx1MDAxYlszODsyOzIyOTsyMzM7MjQwbVx1MDAxYls0ODsyOzc2Ozg2OzEwNm0gUkVBRE1FLnJzdFx1MDAxYl0xMTJcdTAwMDdcdTAwMWJbMiBxXHUwMDFiWzIyOzJIXHUwMDFiWz8yNWgiXQpbMTEuNjMzNDc1LCAibyIsICJcdTAwMWJbPzI1bFx1MDAxYihCXHUwMDFiW21cdTAwMWJbMzg7MjsyMTY7MjIyOzIzM21cdTAwMWJbNDg7Mjs0Njs1Mjs2NG1xXHUwMDFiWz8yNWgiXQpbMTEuNzM0NTkyLCAibyIsICJcdTAwMWJbPzI1bGFcdTAwMWJbPzI1aCJdClsxMS44ODUzODEsICJvIiwgIlx1MDAxYls/MjVsXHJcdTAwMWJbMjI7MUhcdTAwMWJbPzI1aCJdClsxMS45MTg3NjQsICJvIiwgIlx1MDAxYls/MjVsXHUwMDFiXTExMlx1MDAwN1x1MDAxYlsyIHFcdTAwMWJbPzI1aFx1MDAxYls/MjVsXHUwMDFiXTExMlx1MDAwN1x1MDAxYlsyIHFcdTAwMWJbPzEwMDJsXHUwMDFiWz8xMDA2bFx1MDAxYihCXHUwMDFiW21cdTAwMWJbPzI1aFx1MDAxYls/MWxcdTAwMWI+XHUwMDFiWz8xMDQ5bFx1MDAxYlsyMzswOzB0XHUwMDFiWzIzOzA7MHRcdTAwMWJbPzIwMDRsXHUwMDFiWz8xMDA0bFx1MDAxYls/MjVoIl0KWzExLjk2MjQ1NywgIm8iLCAiXHUwMDFiWzFtXHUwMDFiWzdtJVx1MDAxYlsyN21cdTAwMWJbMW1cdTAwMWJbMG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHIgXHIiXQpbMTIuMDI3OTMsICJvIiwgIlx1MDAxYl03O2ZpbGU6Ly8vaG9tZS9sYS93b3Jrc3BhY2Uvc3BoaW54LWFzaWNjbmVtYVx1MDAxYlxcIl0KWzEyLjA0NzUzMSwgIm8iLCAiXHJcdTAwMWJbMG1cdTAwMWJbMjdtXHUwMDFiWzI0bVx1MDAxYltKXHUwMDFiWzMybS9cdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNm1sYVx1MDAxYlszOW0gXHUwMDFiWzM3bUBcdTAwMWJbMzltIFx1MDAxYlszNW1sYS10cGw0NTBcdTAwMWJbMzltIFx1MDAxYlszMG0xNTozMlx1MDAxYlszOW0gXHUwMDFiWzM3bS0+XHUwMDFiWzM5bSBcdTAwMWJbMzJtfi93b3Jrc3BhY2Uvc3BoaW54LWFzaWNjbmVtYVx1MDAxYlszOW0gXHUwMDFiWzMwbVx1MDAxYlszOW0gXHUwMDFiWzBtXHJcblx1MDAxYlszMm1cXFx1MDAxYlszOW0gXHUwMDFiWzFtXHUwMDFiWzM0bSQgXHUwMDFiWzM3bVx1MDAxYlswbVx1MDAxYlszN21cdTAwMWJbS1x1MDAxYls/MjAwNGgiXQpbMTIuNzcxNDYsICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQo=",
                        document.getElementById('asciicast-/_assets/snippet-with-vim.cast'),
                        { });
                });
            &lt;/script&gt;&lt;/dd&gt;
&lt;dt&gt;在终端&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;唤醒 Snippet，输入关键词&lt;/p&gt;
&lt;div id="asciicast-/_assets/snippet-with-zsh.cast"&gt;&lt;/div&gt;
            &lt;script&gt;
                document.addEventListener("DOMContentLoaded", function() {
                    AsciinemaPlayer.create(
                        "data:text/plain;base64,eyJ2ZXJzaW9uIjogMiwgIndpZHRoIjogODAsICJoZWlnaHQiOiAyMiwgInRpbWVzdGFtcCI6IDE2MjE5MjczMzMsICJlbnYiOiB7IlNIRUxMIjogIi9iaW4venNoIiwgIlRFUk0iOiAieHRlcm0tMjU2Y29sb3IifX0KWzAuMjg1ODA3LCAibyIsICJcdTAwMWJbMW1cdTAwMWJbN20lXHUwMDFiWzI3bVx1MDAxYlsxbVx1MDAxYlswbSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcciBcciJdClswLjM1MjQ5OSwgIm8iLCAiXHUwMDFiXTc7ZmlsZTovLy9ob21lL2xhL3dvcmtzcGFjZS9zcGhpbngtYXNpY2NuZW1hXHUwMDFiXFwiXQpbMC4zNzgxMTksICJvIiwgIlxyXHUwMDFiWzBtXHUwMDFiWzI3bVx1MDAxYlsyNG1cdTAwMWJbSlx1MDAxYlszMm0vXHUwMDFiWzM5bSBcdTAwMWJbMW1cdTAwMWJbMzZtbGFcdTAwMWJbMzltIFx1MDAxYlszN21AXHUwMDFiWzM5bSBcdTAwMWJbMzVtbGEtdHBsNDUwXHUwMDFiWzM5bSBcdTAwMWJbMzBtMTU6MjJcdTAwMWJbMzltIFx1MDAxYlszN20tPlx1MDAxYlszOW0gXHUwMDFiWzMybX4vd29ya3NwYWNlL3NwaGlueC1hc2ljY25lbWFcdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlswbVxyXG5cdTAwMWJbMzJtXFxcdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNG0kIFx1MDAxYlszN21cdTAwMWJbMG1cdTAwMWJbMzdtXHUwMDFiW0tcdTAwMWJbPzIwMDRoIl0KWzAuMzk0NDgsICJvIiwgIlx1MDAxYlsxbVx1MDAxYlszMW1jXHUwMDFiWzBtXHUwMDFiWzM5bVx1MDAxYls5MG1hdCBSRUFETUUucnN0XHUwMDFiWzM5bVx1MDAxYlsxM0QiXQpbMS4xMDcxODMsICJvIiwgIlxiXHUwMDFiWzFtXHUwMDFiWzMxbWNcdTAwMWJbMW1cdTAwMWJbMzFtYVx1MDAxYlswbVx1MDAxYlszOW0iXQpbMS4yMjQ2MzQsICJvIiwgIlxiXGJcdTAwMWJbMG1cdTAwMWJbMzJtY1x1MDAxYlswbVx1MDAxYlszMm1hXHUwMDFiWzMybXRcdTAwMWJbMzltIl0KWzEuMzIxNDg0LCAibyIsICJcdTAwMWJbMzltICJdClsxLjYxNDcxOSwgIm8iLCAiXHUwMDFiWzM5bVx1MDAxYls0bVJcdTAwMWJbMjRtIl0KWzEuNjU2NjY4LCAibyIsICJcYlx1MDAxYls0bVJcdTAwMWJbMzltXHUwMDFiWzRtRVx1MDAxYlsyNG0iXQpbMi4wNjYyMTcsICJvIiwgIlx1MDAxYlszOW1BXHUwMDFiWzM5bURcdTAwMWJbMzltTVx1MDAxYlszOW1FXHUwMDFiWzM5bS5cdTAwMWJbMzltclx1MDAxYlszOW1zXHUwMDFiWzM5bXQiXQpbMi42NTk2NzQsICJvIiwgIlx1MDAxYls5RFx1MDAxYls0bUVcdTAwMWJbNG1BXHUwMDFiWzRtRFx1MDAxYls0bU1cdTAwMWJbNG1FXHUwMDFiWzRtLlx1MDAxYls0bXJcdTAwMWJbNG1zXHUwMDFiWzRtdFx1MDAxYlsyNG0iXQpbMi42NjE4MTMsICJvIiwgIlx1MDAxYls/MjAwNGxcclxyXG4iXQpbMi42NjMzOTUsICJvIiwgIkkgd2lsbCBwcmVzcyBgYGN0cmwrayx2YGAgdG8gXCJ2aWV3IHJlU1Qgc25pcHBldHNcIi5cclxuIl0KWzIuNjYzNTU0LCAibyIsICJcdTAwMWJbMW1cdTAwMWJbN20lXHUwMDFiWzI3bVx1MDAxYlsxbVx1MDAxYlswbSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcciBcciJdClsyLjcyODAzNywgIm8iLCAiXHUwMDFiXTc7ZmlsZTovLy9ob21lL2xhL3dvcmtzcGFjZS9zcGhpbngtYXNpY2NuZW1hXHUwMDFiXFwiXQpbMi43NDcxNDIsICJvIiwgIlxyXHUwMDFiWzBtXHUwMDFiWzI3bVx1MDAxYlsyNG1cdTAwMWJbSlx1MDAxYlszMm0vXHUwMDFiWzM5bSBcdTAwMWJbMW1cdTAwMWJbMzZtbGFcdTAwMWJbMzltIFx1MDAxYlszN21AXHUwMDFiWzM5bSBcdTAwMWJbMzVtbGEtdHBsNDUwXHUwMDFiWzM5bSBcdTAwMWJbMzBtMTU6MjJcdTAwMWJbMzltIFx1MDAxYlszN20tPlx1MDAxYlszOW0gXHUwMDFiWzMybX4vd29ya3NwYWNlL3NwaGlueC1hc2ljY25lbWFcdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlswbVxyXG5cdTAwMWJbMzJtXFxcdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNG0kIFx1MDAxYlszN21cdTAwMWJbMG1cdTAwMWJbMzdtXHUwMDFiW0tcdTAwMWJbPzIwMDRoIl0KWzQuMzExNzMxLCAibyIsICJcdTAwMWJbPzEwNDloXHUwMDFiWz8xMDAwaFx1MDAxYlsyMUFcdTAwMWJbR1x1MDAxYltLXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICJdCls0LjMxMTg3OCwgIm8iLCAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXQpbNC4zMTE5MTMsICJvIiwgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYls7MTszODs1OzExMG0+XHUwMDFiW21cdTAwMWJbO20gXHUwMDFiW21cdTAwMWJbOzFtXHUwMDFiW21cdTAwMWJbOzFtXHUwMDFiW21cdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbOzE7Mzg7NTsxNDht4qCLXHUwMDFiW21cclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtMC8wXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYlsyQ1xyXHUwMDFiWzJDIl0KWzQuMzYwMTE2LCAibyIsICJcdTAwMWJbMkFcclx1MDAxYlsyQ1x1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzJDXHUwMDFiWzszODs1OzEwOW1LSU5EICBFWENFUlBUICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUEFUSCAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzJCXHJcdTAwMWJbMkMiXQpbNC4zNzM2MjQsICJvIiwgIlx1MDAxYls/MTA0OWhcdTAwMWJbSFx1MDAxYlsyMUFcclx1MDAxYltKIl0KWzQuMzc0MTIsICJvIiwgIlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXQpbNC4zNzQyMjQsICJvIiwgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl0KWzQuMzc0MzQ1LCAibyIsICIgICAgICAgICAgICAgXHJcdTAwMWJbOzE7Mzg7NTsxMTBtPlx1MDAxYlttXHUwMDFiWzttIFx1MDAxYlttXHUwMDFiWzsxbVx1MDAxYlttXHUwMDFiWzsxbVx1MDAxYlttXHUwMDFiWzFBXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzsxOzM4OzU7MTQ4beKgi1x1MDAxYlttXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzU7MTQ0bTAvMFx1MDAxYlttXHUwMDFiWzFBXHJcdTAwMWJbMkNcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxMDltS0lORCAgRVhDRVJQVCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBBVEggICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsyQlxyXHUwMDFiWzJDIl0KWzQuMzg1NzgzLCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtMjA4LzIwOFx1MDAxYlttXHUwMDFiWzIwQVxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFZpbSDmj5Lku7bmipjohb7orrDlvZU+ICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPElERiDlrp7pqozlrqTpgIblkJHpopjpg6jliIbpopjop6M+ICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxIZWxsbyBIYXNrZWxsPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxHU29DIDIwMTYg5bCP6K6wIC0g6K+v5omT6K+v5pKe5LiJ5Liq5pyIPiAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxHU29DIDIwMTY+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzojrflj5YgdGVld29ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85LuOIEMg5rqQ56CB55Sf5oiQIOWHveaVsC/mqKHlnZcg6LCD55So5Zu+PiAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85LuOIEpla3lsbCDov4Hnp7vliLAgU3BoaW54PiAgICAgICAgICAgICAgICAgICAgIEJsb2cgICJdCls0LjM4NTk3MSwgIm8iLCAiICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA856uLIEZsYWc+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFB5dGhvbiDliJ3or5U+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8ZG8g6K6w5rOV5ZKMID4+PSDnmoTnrYnmlYjooajovr4+ICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxBcmNoIExpbnV4IOaKmOiFvuWwj+iusD4gICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8QWRkIElzc28gQ29tbWVudHMgdG8gWW91ciBTcGhpbnggRG9jdW1lbnQuLiAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8MjAxNSDljY7lsbHmna8gQ1RGIFJldmVyc2UgMzAwPiAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85pys56uZPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzlvKDnm5vlroc+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxNZT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICJdCls0LjM4NjEyNiwgIm8iLCAiICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOWPi+S6uuW4kD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFib3V0ICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzsxOzM4OzU7MTYxOzQ4OzU7MjM2bT5cdTAwMWJbbVx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzsxOzM4OzU7MjU0OzQ4OzU7MjM2bVtkXSAgIDxFbmVteT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBYm91dCAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbM0Jcclx1MDAxYlsyQyJdCls0LjM5MjQxNSwgIm8iLCAiXHUwMDFiWzFBXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHJcdTAwMWJbMkNcdTAwMWJbOzM4OzU7MTQ0bTIwOC8yMDhcdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzJDIl0KWzUuMDY4NjIyLCAibyIsICJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbOzE7Mzg7NTsxMTBtPlx1MDAxYlttXHUwMDFiWzttIFx1MDAxYlttXHUwMDFiWzsxbXdcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVxyXHUwMDFiWzNDIl0KWzUuMDgyNzc0LCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtMzkvMjA4XHUwMDFiW21cdTAwMWJbMjBBXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA86I635Y+WIHRlZXdvcmxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOiOt+WPliB0ZWV3b3JsZHMg5pyN5Yqh5Zmo5L+h5oGvPiAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC92aW0vIOeUqCBhcmdzIOaJuemHj+aJk+W8gOaWh+S7tiwg55SoIGFyZ2RvIOaJuemHj+WkhC4uICBNYW4gICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2Jhc2gvIFNoZWxsIHZhcmlhYmxlcyBpbiBoZXJlZG9jIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21pbGwgYmUgLi4gIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFZpbSB+QnkgdGhlIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21heSBJIHVzZSBOZW9WaW0gOi0pfj4gICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2NvbnNvbGUvIOS4reaWh+i3r+W+hOS5seeggTogICAgICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPE92ZXJUaGVXaXJlIExldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVyVGhlV2lyIl0KWzUuMDgzMTY0LCAibyIsICJlIExldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVyVGhlV2lyZSBCYW5kaXQ+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8T3ZlclRoZVdpcmUgQmFuZGl0PiAgICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21hcmdhbWUtbGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL0NhcHR1cmUuLiAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL3B5dGhvbi8gVGVtcCBmaWxlIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21pdGggcmVhbCBwYXRoOiAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOWYv++8jOaIkeWOuyAyMDEwPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFyZ21lLWJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm90ZXMvQ2FwdHVyZS4uICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFyZ2FtZS1uYXJuaSJdCls1LjA4MzQxMSwgIm8iLCAiYT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOb3Rlcy9DYXB0dXJlLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzmmrTpnLLpl67popg+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm90ZXMv6YCg5Z6L5a6e6aqMLi4gICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL3ZpbS8gXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bTogd2luZG93OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzsxOzM4OzU7MTYxOzQ4OzU7MjM2bT5cdTAwMWJbbVx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzsxOzM4OzU7MjU0OzQ4OzU7MjM2bVtkXSAgIDzpgLjpl7s+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGVzL+WinumHj+iJuuacry4uICAgICAgIC4uXHUwMDFiW21cdTAwMWJbM0Jcclx1MDAxYlszQyJdCls1LjEzMTkyMywgIm8iLCAiXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzsxOzM4OzU7MTEwbT5cdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbbVx1MDAxYls7MW13b1x1MDAxYlttXHUwMDFiWzsxbVx1MDAxYlttXHJcdTAwMWJbNEMiXQpbNS4xMzU1ODUsICJvIiwgIlx1MDAxYlsxQVxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxyXHUwMDFiWzJDXHUwMDFiWzszODs1OzE0NG0yOC8yMDhcdTAwMWJbbVx1MDAxYlsyMEFcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttYXJnYW1lLW5hcm5pYT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9DYXB0dXJlLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxGbG9cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9TcmFpbiBBLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9weXRob24vIE5lXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bSBpbiBweXRoXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bW4gMy43LiAgICAgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVyVGhlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7bWlyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8T3ZlclRoZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pcmUgTGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPE92ZXJUaGVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUIiXQpbNS4xMzU2OTUsICJvIiwgIlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPE92ZXJUaGVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxNaW5peCB2MSDmlofku7bns7vnu5/nmoTlrp7njrA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8TWluaXggdjEg5paH5Lu257O757uf55qE5a6e546wPiAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFZpbSB+QnkgdGhlIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21heSBJIHVzZSBOZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21WaW0gOi0pfj4gICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOiOt+WPliB0ZWVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJsZHMg5pyN5Yqh5Zmo5L+h5oGvPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzojrflj5YgdGVlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oqKIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pbmRcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttd3Mg5Lit5paH55So5oi35ZCN5pS55Li66Iux5paHPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWyJdCls1LjEzNTc2MSwgIm8iLCAiOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oqKIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pbmRcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttd3Mg5Lit5paH55So5oi35ZCN5pS55Li66Iux5paHPiAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL3ZpbS8gdzogXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWluZFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO213OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPEFydCBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJrcyB+QWxsIHRoaW5ncyBsaXN0IGhlcmUgaXMgbm90IOKAnGEuLiAgQ29sbGVjdC4uICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/vvIjkuIDvvInpgInmi6kgU3AuLiAg5pel5b+XICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzE7Mzg7NTsxNjE7NDg7NTsyMzZtPlx1MDAxYlttXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbOzE7Mzg7NTsyNTQ7NDg7NTsyMzZtW2RdICAgPOWYv++8jOaIkeWOuyAyMDEwPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbM0Jcclx1MDAxYls0QyJdCls1LjI5NTMxNiwgIm8iLCAiXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzsxOzM4OzU7MTEwbT5cdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbbVx1MDAxYls7MW13byBcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVx1MDAxYlsxQVxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxyXHUwMDFiWzJDXHUwMDFiWzszODs1OzE0NG0yOC8yMDhcdTAwMWJbbVx1MDAxYlsyMEFcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttYXJnYW1lLW5hcm5pYT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9DYXB0dXJlLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxGbG9cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9TcmFpbiBBLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9weXRob24vIE5lXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bSBpbiBweXRoXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bW4gMy43LiAgICAgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVyVGhlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7bWlyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8T3ZlclRoZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pcmUgTGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiWyJdCls1LjI5NTY1OCwgIm8iLCAibVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8T3ZlclRoZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pcmUgQmFuZGl0PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPE92ZXJUaGVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxNaW5peCB2MSDmlofku7bns7vnu5/nmoTlrp7njrA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8TWluaXggdjEg5paH5Lu257O757uf55qE5a6e546wPiAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPFZpbSB+QnkgdGhlIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21heSBJIHVzZSBOZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21WaW0gOi0pfj4gICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOiOt+WPliB0ZWVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJsZHMg5pyN5Yqh5Zmo5L+h5oGvPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzojrflj5YgdGVlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21ybGRzIOacjeWKoeWZqOS/oeaBrz4gICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oqKIl0KWzUuMjk1OTM3LCAibyIsICIgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7bWluZFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO213cyDkuK3mlofnlKjmiLflkI3mlLnkuLroi7Hmloc+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oqKIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pbmRcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttd3Mg5Lit5paH55So5oi35ZCN5pS55Li66Iux5paHPiAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL3ZpbS8gdzogXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWluZFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO213OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPEFydCBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJrcyB+QWxsIHRoaW5ncyBsaXN0IGhlcmUgaXMgbm90IOKAnGEuLiAgQ29sbGVjdC4uICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA85oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/vvIjkuIDvvInpgInmi6kgU3AuLiAg5pel5b+XICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDzlmL/vvIzmiJHljrsgMjAxMD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzE7Mzg7NTsxNjE7NDg7NTsyMzZtPlx1MDAxYlttXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbOzE7Mzg7NTsyNTQ7NDg7NTsyMzZtW2RdICAgPOWYv++8jOaIkeWOuyAyMDEwPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbM0Jcclx1MDAxYls1QyJdCls1LjQwODg2LCAibyIsICJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbOzE7Mzg7NTsxMTBtPlx1MDAxYlttXHUwMDFiWzttIFx1MDAxYlttXHUwMDFiWzsxbXdvIHJcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVxyXHUwMDFiWzZDIl0KWzUuNDIyMzg0LCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtMTkvMjA4XHUwMDFiW21cdTAwMWJbMjBBXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bY10gICAvYXdrLyBkYXRlMjAyMC0xMi0yNSAgICAgICAgICAgICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2FcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttay8gUFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21pbnQgYSBjaGFyYWN0ZXIgYXJiaXRyYXJ5IHRpbWVzLCBwLi4gIE1hbiAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9iYXNoLyBTaGVsbCB2YVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21pYWJsZXMgaW4gaGVyZWRvYyBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttaWxsIGJlIC4uICBNYW4gICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZ2FtZS1sZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgTlx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO210ZXMvQ2FwdHVyZS4uICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZ21lLWJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTlx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO210ZXMvQ2FwdHVyZS4uICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZ2FtZS1uYXIiXQpbNS40MjI2NywgIm8iLCAibmlhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttdGVzL0NhcHR1cmUuLiAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPEZsb1x1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO20+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttdGVzL1NcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttYWluIEEuLiAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL3B5dGhvbi8gTmVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttIGluIHB5dGhcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttbiAzLjcuICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttVGhlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7bWlyZSBMZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8T3ZlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXJcdTAwMWJbbVx1MDAxYls7bVRoZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21pcmUgTGV2aWF0aGFuPiAgICAgICAgICAgICAgICAgICAgICAgQmxvZyAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPE92ZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21UaGVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxPdmVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttVGhlXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7Il0KWzUuNDIyOTAyLCAibyIsICJtaXJlIEJhbmRpdD4gICAgICAgICAgICAgICAgICAgICAgICAgIEJsb2cgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9jb25zb2xlLyDlsIbooqvlv73nlaXnmoTor63oqIDvvIjlpoIgTWFya2RvXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bW7jgIFcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZXMuLiAgTWFuICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bY10gICAvYVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21rLyBQcmludCBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZW1haW5pbmcgY1x1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21sdW1ucyAxICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bY10gICAvYVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21rLyBVc2UgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXJcdTAwMWJbbVx1MDAxYls7bWVndWxhciBleHByZXNzaVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21uOiAgICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA86I635Y+WIHRlZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXJcdTAwMWJbbVx1MDAxYls7bWxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOiOt+WPliB0ZWVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21sZHMg5pyN5Yqh5Zmo5L+h5oGvPiAgICAgICAgICAgICAgICAgICBCbG9nICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxBXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXJcdTAwMWJbbVx1MDAxYls7bSJdCls1LjQyMzE2NiwgIm8iLCAidCBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJrcyB+QWxsIHRoaW5ncyBsaXN0IGhlcmUgaXMgbm90IOKAnGEuLiAgQ29sbGVjdC4uICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzE7Mzg7NTsxNjE7NDg7NTsyMzZtPlx1MDAxYlttXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbOzE7Mzg7NTsyNTQ7NDg7NTsyMzZtW2RdICAgPOaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf77yI5LiA77yJ6YCJ5oupIFNwLi4gIOaXpeW/lyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzNCXHJcdTAwMWJbNkMiXQpbNS40ODQxMDgsICJvIiwgIlxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYls7MTszODs1OzExMG0+XHUwMDFiW21cdTAwMWJbO20gXHUwMDFiW21cdTAwMWJbOzFtd28gcnVcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVxyXHUwMDFiWzdDIl0KWzUuNDg2MjE0LCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtMTEvMjA4XHUwMDFiW21cdTAwMWJbMjBBXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWFcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtclx1MDAxYlttXHUwMDFiWzttZ2FtZS1sZXZpYXRoYW4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgTlx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO210ZXMvQ2FwdFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG11XHUwMDFiW21cdTAwMWJbO21yZS4uICAiXQpbNS40ODYzMzYsICJvIiwgIiAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttYVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21nbWUtYmFuZGl0PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9DYXB0XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXVcdTAwMWJbbVx1MDAxYls7bXJlLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttYXJnYW1lLW5hXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXJcdTAwMWJbbVx1MDAxYls7bW5pYT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9DYXB0XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXVcdTAwMWJbbVx1MDAxYls7bXJlLi4gICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9hXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bWsvIFByaW50IFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21lbWFpbmluZyBjXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bWxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtdVx1MDAxYlttXHUwMDFiWzttbW5zIDEgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9hd2svIGRhdGUyMDIwLTEyLTI1ICAgICAgICAgICAgICAgICAgICAgICAgICBNYW4gICAgICAgICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA86I635Y+WIHRlZVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttcmxkcyDmnI3liqHlmajkv6Hmga8+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPOiOt+WPliB0ZWVcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJsZHMg5pyN5Yqh5Zmo5L+h5oGvPiAgICAgICAgICAgICAgICAgICAiXQpbNS40ODY1MDksICJvIiwgIkJsb2cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2FcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttay8gVXNlIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21lZ1x1MDAxYlttXHUwMDFiWzszODs1OzEwOG11XHUwMDFiW21cdTAwMWJbO21sYXIgZXhwcmVzc2lcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttbjogICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2NvbnNvbGUvIOWwhuiiq+W/veeVpeeahOivreiogO+8iOWmgiBNYXJrZG9cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttbuOAgXJlcy4uICBNYW4gICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxBcnQgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bVdcdTAwMWJbbVx1MDAxYls7bVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1vXHUwMDFiW21cdTAwMWJbO21ya3MgfkFsbCB0aGluZ3MgbGlzdCBoZXJlIGlzIG5vdCDigJxhLi4gIENvbGxlY3QuLiAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7MTszODs1OzE2MTs0ODs1OzIzNm0+XHUwMDFiW21cdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7MTszODs1OzI1NDs0ODs1OzIzNm1bZF0gICA85oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/vvIjkuIDvvInpgInmi6kgU3AuLiAg5pel5b+XICAgICAgICAgICAgICAgICAgIC4uXHUwMDFiW21cdTAwMWJbM0Jcclx1MDAxYls3QyJdCls1Ljc4OTI5NSwgIm8iLCAiXHJcdTAwMWJbO20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxyXHUwMDFiWzsxOzM4OzU7MTEwbT5cdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbbVx1MDAxYls7MW13byBydWhcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVxyXHUwMDFiWzhDIl0KWzUuNzkyNjU2LCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtNS8yMDhcdTAwMWJbbVx1MDAxYlsxMkFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtkXSAgIDxcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtd1x1MDAxYlttXHUwMDFiWzttYVx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1yXHUwMDFiW21cdTAwMWJbO21nYW1lLWxldmlhdGhhbj4gICAgICAgICAgICAgICAgICAgICAgICAgICBOXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXRlcy9DYXB0XHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXVcdTAwMWJbbVx1MDAxYls7bXJlLi4gICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bY10gICAvYXdrLyBkYXRlMjAyMC0xMi0yNSAgICAgICAgICAgICAgICAgICAgICAgICAgTWFuICAgICAgICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttIl0KWzUuNzkyNzc2LCAibyIsICJbY10gICAvY29uc29sZS8g5bCG6KKr5b+955Wl55qE6K+t6KiA77yI5aaCIE1hcmtkb1x1MDAxYlttXHUwMDFiWzszODs1OzEwOG13XHUwMDFiW21cdTAwMWJbO21u44CBcmVzLi4gIE1hbiAgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2RdICAgPEFydCBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtV1x1MDAxYlttXHUwMDFiWzttXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bW9cdTAwMWJbbVx1MDAxYls7bXJrcyB+QWxsIHRoaW5ncyBsaXN0IGhlcmUgaXMgbm90IOKAnGEuLiAgQ29sbGVjdC4uICAgICAgICAgICAgICBcdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtLi5cdTAwMWJbbVx1MDAxYlsxQlxyXHUwMDFiWzsxOzM4OzU7MTYxOzQ4OzU7MjM2bT5cdTAwMWJbbVx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzsxOzM4OzU7MjU0OzQ4OzU7MjM2bVtkXSAgIDzmiJHlpoLkvZXnlKggU3BoaW54IOW7uueri+eslOiusOezu+e7n++8iOS4gO+8iemAieaLqSBTcC4uICDml6Xlv5cgICAgICAgICAgICAgICAgICAgLi5cdTAwMWJbbVx1MDAxYlszQlxyXHUwMDFiWzhDIl0KWzUuODc5ODMzLCAibyIsICJcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcdTAwMWJbOzE7Mzg7NTsxMTBtPlx1MDAxYlttXHUwMDFiWzttIFx1MDAxYlttXHUwMDFiWzsxbXdvIHJ1aGVcdTAwMWJbbVx1MDAxYls7MW1cdTAwMWJbbVxyXHUwMDFiWzlDIl0KWzUuODgyNTQ1LCAibyIsICJcdTAwMWJbMUFcclx1MDAxYls7bSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHJcclx1MDAxYlsyQ1x1MDAxYls7Mzg7NTsxNDRtNC8yMDhcdTAwMWJbbVx1MDAxYls2QVxyXHUwMDFiWzttICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclx1MDAxYlsxQlxyXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbO20gXHUwMDFiWzttW2NdICAgL2F3ay8gZGF0ZTIwMjAtMTItMjUgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbiAgICAgICAgICAgICAgICAgICAgXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bS4uXHUwMDFiW21cdTAwMWJbMUJcclx1MDAxYls7NDg7NTsyMzZtIFx1MDAxYlttXHUwMDFiWzttIFx1MDAxYls7bVtjXSAgIC9jb25zb2xlLyDlsIbooqvlv73nlaXnmoTor63oqIDvvIjlpoIgTWFya2RvXHUwMDFiW21cdTAwMWJbOzM4OzU7MTA4bXdcdTAwMWJbbVx1MDAxYls7bW7jgIFyZXMuLiAgTWFuICAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzQ4OzU7MjM2bSBcdTAwMWJbbVx1MDAxYls7bSBcdTAwMWJbO21bZF0gICA8QXJ0IFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG1XXHUwMDFiW21cdTAwMWJbO21cdTAwMWJbbVx1MDAxYls7Mzg7NTsxMDhtb1x1MDAxYlttXHUwMDFiWzttcmtzIH5BbGwgdGhpbmdzIGxpc3QgaGVyZSBpcyBub3Qg4oCcYS4uICBDb2xsZWN0Li4gICAgICAgICAgICAgIFx1MDAxYlttXHUwMDFiWzszODs1OzEwOG0uLlx1MDAxYlttXHUwMDFiWzFCXHJcdTAwMWJbOzE7Mzg7NTsxNjE7NDg7NTsyMzZtPlx1MDAxYlttXHUwMDFiWzs0ODs1OzIzNm0gXHUwMDFiW21cdTAwMWJbOzE7Mzg7NTsyNTQ7NDg7NTsyMzZtW2RdICAgPOaIkeWmguS9leeUqCBTcGhpbngg5bu656uL56yU6K6w57O757uf77yI5LiA77yJ6YCJ5oupIFNwLi4gIOaXpeW/lyAgICAgICAgICAgICAgICAgICAuLlx1MDAxYlttXHUwMDFiWzNCXHJcdTAwMWJbOUMiXQpbNi44MTM2ODQsICJvIiwgIlx1MDAxYls/MTA0OWxcdTAwMWJbPzEwMDBsIl0KWzYuODI4MTc2LCAibyIsICJcdTAwMWJbMzJtc25pcHBldFx1MDAxYlszOW0gZ2V0IC0tdGV4dCBmNmJlNzlmIHwgXHUwMDFiWzMybWJhdFx1MDAxYlszOW0gLS1sYW5ndWFnZSByc3QgLS1pdGFsaWMtdGV4dCBhbHdheXMgLS1zdHlsZSBwbGFpbiAtLXBhZ2luZyBhbHdheXNcdTAwMWJbS1x1MDAxYltBXHUwMDFiWzE4RCJdCls2LjgzOTU3OSwgIm8iLCAiXHUwMDFiWz8yMDA0bFx1MDAxYlsxQlxyXHJcbiJdCls2LjkwNTEyNywgIm8iLCAiXHUwMDFiWz8xMDQ5aFx1MDAxYlsyMjswOzB0XHUwMDFiWz8xaFx1MDAxYj1cciJdCls2LjkwOTkxNCwgIm8iLCAiXHUwMDFiWzM4OzI7MjUzOzE1MTszMW09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVx1MDAxYlswbVx1MDAxYlttXHJcbiJdCls2LjkxMDA5NiwgIm8iLCAiXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJt5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/vvIjkuIDvvInpgInlnovkuI7miJDlvaJcdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbMzg7MjsyNTM7MTUxOzMxbT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHUwMDFiWzBtXHUwMDFiW21cclxuXHUwMDFiW21cclxuXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtLi5cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0gcG9zdFx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybTo6XHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtIDIwMjEtMDUtMjVcdTAwMWJbMG1cdTAwMWJbbVxyXG4iXQpbNi45MTA0MzksICJvIiwgIlx1MDAxYlszODsyOzI0ODsyNDg7MjQybSAgIFx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtdGFnc1x1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybSBTcGhpbnhcdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0gICBcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bTpcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bWF1dGhvclx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybSBMQVx1MDAxYlswbVx1MDAxYlttXHJcblx1MDAxYlszODsyOzI0ODsyNDg7MjQybSAgIFx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtY2F0ZWdvcnlcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bTpcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0g5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu59cdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0gICBcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bTpcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bWxhbmd1YWdlXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ5OzM4OzExNG06XHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtIHpoX0NOXHUwMDFiWzBtXHUwMDFiW21cclxuXHUwMDFiW21cclxuIl0KWzYuOTEwNTMzLCAibyIsICJcdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0uLlx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybSBub3RlXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtOjpcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0g6L+Z5piv44CK5oiR5aaC5L2V55SoIFNwaGlueCDlu7rnq4vnrJTorrDns7vnu5/jgIvns7vliJfnmoTnrKzkuIDnr4fjgIJcdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbbVxyXG5cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0uLlx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybSBub3RlXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtOjpcdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbbVxyXG4iXQpbNi45MTA4MjMsICJvIiwgIlx1MDAxYlszODsyOzI0ODsyNDg7MjQybSAgIOi/meS4queslOiusOezu+e7n+aYr+W4puacieW8uueDiOS4quS6uuiJsuW9qeeahCBcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bTpcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bXJlZlx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybWBcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm3nrJTorrDns7vnu5/lnLrmma9cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm1gXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtIOS4reivnueUn+eahO+8jOW5tuS4jemAguWQiOaJgOacieS6ulx1MDAxYlttIFxiXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ5OzM4OzExNG1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bVx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJt77yM5L2g5Y+v5Lul56iN5L2c5LqG6Kej77yM5YaN5Yaz5a6a5piv5ZCm57un57ut6ZiF6K+744CC5Y+m77yM5byA5aS06K6y5LqG5LiA5Lqb5YWz5LqO56yU6K6w55qE5peg6IGK5b6A5LqL77yM55u05o6l6LezXHUwMDFiW20gXGJcdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bVx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ5OzM4OzExNG1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm1cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm3ov4fkuZ/ml6DlpqjjgIJcdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbbVxyXG4iXQpbNi45MTEwMjgsICJvIiwgIlx1MDAxYlszODsyOzExNzsxMTM7OTRtLi5cdTAwMWJbMG1cdTAwMWJbbVxyXG5cdTAwMWJbbVxyXG5cdTAwMWJbMzg7MjsxMTc7MTEzOzk0bSAgICAg77yI5LiA55u05Lul5p2l77yM77yJOmZyaWVuZDpgU2lsdmVyUmFpblpgIO+8iOaMh+aIkeiHquW3se+8ieWcqOS9v+eUqOS4gOS4qui/mOacquWtmOWcqOeahOiHquW7uueslFx1MDAxYlttXHJcbjpcdTAwMWJbSyJdCls4LjA4NTY1MSwgIm8iLCAiXHJcdTAwMWJbSyJdCls4LjA4NTk5NSwgIm8iLCAiXHUwMDFiWzM4OzI7MTE3OzExMzs5NG3orrDns7vnu5/vvIzmr4/mrKHmg7PlhpnngrnkuJzopb/pg73lm6DkuLrjgIzml6Dms5Xop6PlhrPkvp3otZbjgI3ogIzlpLHotKXjgIIgWyNdX1x1MDAxYlswbVx1MDAxYlttXHJcbjpcdTAwMWJbSyJdCls4LjI0NjAzLCAibyIsICJcclx1MDAxYltLXHUwMDFiW21cclxuOlx1MDAxYltLIl0KWzguNDIwMDE0LCAibyIsICJcclx1MDAxYltLIl0KWzguNDIwMzYsICJvIiwgIlx1MDAxYlszODsyOzI0ODsyNDg7MjQybeS4jeefpeS9leaXtuaIkeWFu+aIkOS6huS4gOenjeWlh+aAqueahOeZluWlve+8jOaDs+ivu+S4gOacrOacieS7t+WAvOeahOS5pu+8jOayoeacieWQiOmAguW3peWFt+iusOivu+S5pueslOiusO+8jOaJgOS7pVx1MDAxYlttIFxiOlx1MDAxYltLIl0KWzguNTYzNzYxLCAibyIsICJcclx1MDAxYltLIl0KWzguNTY0MTI0LCAibyIsICJcdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm3kuI3or7vjgIIg5oOz6K6w5b2V5LiA5Lqb5LiN5oiQ5L2T57O755qE55+l6K+G77yM5LiN55+l6YGT5aaC5L2V57uE57uH5YiG57G76L+Z5Lqb56KO54mH77yM5omA5Lul5LiN6K6w44CC5oOz5YaZ5LiA56+HXHUwMDFiW21cclxuOlx1MDAxYltLIl0KWzguNzIwOTgyLCAibyIsICJcclx1MDAxYltLIl0KWzguNzIxMzU5LCAibyIsICJcdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm3ljZrlrqLvvIzmlofnq6Dph4zmnInkuIDkupvkuqTlj4nlvJXnlKjvvIzkuI3mg7PnlKjnspfmmrTnmoQgXHUwMDFiWzBtXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtYFx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybTxhIGhyZWY9eHh4Plx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybWBcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0g77yM5omA5Lul5LiN5YaZ44CC5Zug5ZmO5bqf6aOf5aSn5qaCXHUwMDFiW20gXGI6XHUwMDFiW0siXQpbOC44NDc4MTksICJvIiwgIlxyXHUwMDFiW0siXQpbOC44NDgwMDMsICJvIiwgIlx1MDAxYlszODsyOzI0ODsyNDg7MjQybVx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybVx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybVx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybVx1MDAxYlswbVx1MDAxYlszODsyOzI0ODsyNDg7MjQybeWwseaYr+i/meagt+WQp+OAglx1MDAxYlswbVx1MDAxYlttXHJcbjpcdTAwMWJbSyJdCls4Ljk2Njg4NSwgIm8iLCAiXHJcdTAwMWJbS1x1MDAxYlttXHJcbjpcdTAwMWJbSyJdCls5LjE2MzI1MSwgIm8iLCAiXHJcdTAwMWJbSyJdCls5LjE2MzY0MywgIm8iLCAiXHUwMDFiWzM4OzI7MjQ4OzI0ODsyNDJtLi5cdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm0gY29udGVudHNcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm06Olx1MDAxYlswbVx1MDAxYlttXHJcbjpcdTAwMWJbSyJdCls5LjUzMTU2NiwgIm8iLCAiXHJcdTAwMWJbS1x1MDAxYlszODsyOzI0ODsyNDg7MjQybSAgIFx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtOlx1MDAxYlswbVx1MDAxYlszODsyOzI0OTszODsxMTRtbG9jYWxcdTAwMWJbMG1cdTAwMWJbMzg7MjsyNDk7Mzg7MTE0bTpcdTAwMWJbMG1cdTAwMWJbbVxyXG46XHUwMDFiW0siXQpbOS42OTYzNTMsICJvIiwgIlxyXHUwMDFiW0tcdTAwMWJbbVxyXG46XHUwMDFiW0siXQpbOS44NjMxMzgsICJvIiwgIlxyXHUwMDFiW0tcdTAwMWJbMzg7MjsyNDg7MjQ4OzI0Mm3mvKvplb/nmoTlsJ3or5VcdTAwMWJbMG1cdTAwMWJbbVxyXG46XHUwMDFiW0siXQpbMTAuMDMzNTI0LCAibyIsICJcclx1MDAxYltLXHUwMDFiWzM4OzI7MjUzOzE1MTszMW09PT09PT09PT09XHUwMDFiWzBtXHUwMDFiW21cclxuOlx1MDAxYltLIl0KWzEwLjUwMzU2MSwgIm8iLCAiXHJcdTAwMWJbS1x1MDAxYls/MWxcdTAwMWI+XHUwMDFiWz8xMDQ5bFx1MDAxYlsyMzswOzB0Il0KWzEwLjUwNzgyNiwgIm8iLCAiXHUwMDFiWzFtXHUwMDFiWzdtJVx1MDAxYlsyN21cdTAwMWJbMW1cdTAwMWJbMG0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXHIgXHIiXQpbMTAuNTc1Mzc1LCAibyIsICJcdTAwMWJdNztmaWxlOi8vL2hvbWUvbGEvd29ya3NwYWNlL3NwaGlueC1hc2ljY25lbWFcdTAwMWJcXCJdClsxMC41OTU3MjcsICJvIiwgIlxyXHUwMDFiWzBtXHUwMDFiWzI3bVx1MDAxYlsyNG1cdTAwMWJbSlx1MDAxYlszMm0vXHUwMDFiWzM5bSBcdTAwMWJbMW1cdTAwMWJbMzZtbGFcdTAwMWJbMzltIFx1MDAxYlszN21AXHUwMDFiWzM5bSBcdTAwMWJbMzVtbGEtdHBsNDUwXHUwMDFiWzM5bSBcdTAwMWJbMzBtMTU6MjJcdTAwMWJbMzltIFx1MDAxYlszN20tPlx1MDAxYlszOW0gXHUwMDFiWzMybX4vd29ya3NwYWNlL3NwaGlueC1hc2ljY25lbWFcdTAwMWJbMzltIFx1MDAxYlszMG1cdTAwMWJbMzltIFx1MDAxYlswbVxyXG5cdTAwMWJbMzJtXFxcdTAwMWJbMzltIFx1MDAxYlsxbVx1MDAxYlszNG0kIFx1MDAxYlszN21cdTAwMWJbMG1cdTAwMWJbMzdtXHUwMDFiW0tcdTAwMWJbPzIwMDRoIl0KWzExLjYxMzAxNCwgIm8iLCAiXHUwMDFiWz8yMDA0bFxyXHJcbiJdCg==",
                        document.getElementById('asciicast-/_assets/snippet-with-zsh.cast'),
                        { });
                });
            &lt;/script&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;这一时间的压缩让「记录一些偶尔用又总记不住的命令」有了实用价值：比开 Google 快了许多，更别提梯子挂了时候，命令就在嘴边又记不清的难受劲儿。&lt;/p&gt;
&lt;aside class="topic"&gt;
&lt;p class="topic-title"&gt;记录一些常用又总记不住的命令有哪些？&lt;/p&gt;
&lt;p&gt;对我来说是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;不常用的编程语言里的各种 type casting 的写法&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ImageMagick、FFmpeg 的冗长参数&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;各种清系统日志，包缓存的命令&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一些「高阶」 Git 操作&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/aside&gt;
&lt;p&gt;此外，编辑笔记的时候也不需要进到 git 仓库里一层一层找文件了，一步直达。&lt;/p&gt;
&lt;p&gt;关于 Snippet 的使用，我也会再写一篇文章展开，配合其他工具有非常多的玩法。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;span id="id3"&gt;&lt;/span&gt;&lt;h2&gt;描述、引用和索引&lt;/h2&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinx-as-note-taking-system-2.rst&lt;/span&gt;, line 152); &lt;em&gt;&lt;a href="#id3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate implicit target name: &amp;quot;描述、引用和索引&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;一个对象的描述，通常可以抽象为 Key-Value list，特别地，对象的名字和介绍是两个特殊的 Key。reST 中的 &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#directives"&gt;Directives&lt;/a&gt; 就能够用来写这样的描述：假设我们有一个名为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;book&lt;/span&gt;&lt;/code&gt; 的 directive，尝试用它来描述一本书:&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;book&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; 德米安
&lt;/span&gt;&lt;span data-line="2"&gt;   &lt;span class="nc"&gt;:ISBN:&lt;/span&gt; 9787509365786
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="nc"&gt;:作者:&lt;/span&gt; 黑塞
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;   我读过这本书，但好像又跟没读一样。
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但 Sphinx 其实并不存在这样的 directive ，它无法被正常地渲染成文档。
而 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-any"&gt;📦 sphinxnotes-any&lt;/a&gt; 就是用来做这种事情的：它根据你的配置生成 directives 来描述任意对象，所有的对象都会被保存在一个叫 “any” 的 &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html"&gt;Domain&lt;/a&gt; （理解为命名空间）中，对应的交叉索引用的 role 也会生成，这么说可能有些抽象，我拿用来描述一张画的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;artwork&lt;/span&gt;&lt;/code&gt; directive 来举个例子:&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;artwork&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; Bell Rock Lighthouse
&lt;/span&gt;&lt;span data-line="2"&gt;   &lt;span class="nc"&gt;:id:&lt;/span&gt; test-1
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="nc"&gt;:medium:&lt;/span&gt; 水彩 铅笔
&lt;/span&gt;&lt;span data-line="4"&gt;   &lt;span class="nc"&gt;:date:&lt;/span&gt; 1819
&lt;/span&gt;&lt;span data-line="5"&gt;   &lt;span class="nc"&gt;:size:&lt;/span&gt; 8k
&lt;/span&gt;&lt;span data-line="6"&gt;   &lt;span class="nc"&gt;:image:&lt;/span&gt; /_images/800px-Joseph_Mallord_William_Turner_-_Bell_Rock_Lighthouse_-_Google_Art_Project.jpg
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;   随便找的一张 &lt;span class="na"&gt;:zhwiki:&lt;/span&gt;&lt;span class="nv"&gt;`透纳`&lt;/span&gt; 的画。
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;会在文档中产生如下内容：&lt;/p&gt;
&lt;div class="admonition-todo admonition" id="id4"&gt;
&lt;p class="admonition-title"&gt;待处理&lt;/p&gt;
&lt;p&gt;待修复，see &lt;a class="reference external" href="https://github.com/SilverRainZ/silverrainz.github.io/pull/30"&gt;https://github.com/SilverRainZ/silverrainz.github.io/pull/30&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/3 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinx-as-note-taking-system-2.rst&lt;/span&gt;, line 178)&lt;/p&gt;
&lt;p&gt;Error in &amp;quot;any:artwork&amp;quot; directive:
unknown option: &amp;quot;image&amp;quot;.&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;any:artwork&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; Bell Rock Lighthouse
&lt;/span&gt;&lt;span data-line="2"&gt;   &lt;span class="nc"&gt;:id:&lt;/span&gt; test-1
&lt;/span&gt;&lt;span data-line="3"&gt;   &lt;span class="nc"&gt;:medium:&lt;/span&gt; 水彩 铅笔
&lt;/span&gt;&lt;span data-line="4"&gt;   &lt;span class="nc"&gt;:date:&lt;/span&gt; 1819
&lt;/span&gt;&lt;span data-line="5"&gt;   &lt;span class="nc"&gt;:size:&lt;/span&gt; 8k
&lt;/span&gt;&lt;span data-line="6"&gt;   &lt;span class="nc"&gt;:image:&lt;/span&gt; /_images/800px-Joseph_Mallord_William_Turner_-_Bell_Rock_Lighthouse_-_Google_Art_Project.jpg
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;   随便找的一张 &lt;span class="na"&gt;:zhwiki:&lt;/span&gt;&lt;span class="nv"&gt;`透纳`&lt;/span&gt; 的画。
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;可以看到生成的内容比 directive 里写的携带了更多的信息，这其实是 &lt;a class="reference external" href="https://github.com/SilverRainZ/bullet/blob/master/_templates/artwork.rst"&gt;Jinja Template&lt;/a&gt; 带来的。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;现在你可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;artwork&lt;/span&gt;&lt;/code&gt; 系列的 role 来索引这张画：&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;根据名字索引&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:artwork:`Bell&lt;/span&gt; &lt;span class="pre"&gt;Rock&lt;/span&gt; &lt;span class="pre"&gt;Lighthouse`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;Bell&lt;/span&gt; &lt;span class="pre"&gt;Rock&lt;/span&gt; &lt;span class="pre"&gt;Lighthouse&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;根据 ID 索引&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:artwork:`test-1`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="xref any any-artwork docutils literal notranslate"&gt;&lt;span class="pre"&gt;test-1&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;更精确一点&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:artwork.id:`test-1`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="xref any any-artwork.id docutils literal notranslate"&gt;&lt;span class="pre"&gt;test-1&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;所有水彩画&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:artwork.medium:`水彩`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="any any-artwork reference internal" href="any-artwork.medium.html#cap-水彩" title="artwork 水彩"&gt;&lt;code class="xref any any-artwork.medium docutils literal notranslate"&gt;&lt;span class="pre"&gt;水彩&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;所有媒介&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:ref:`any-artwork.medium`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="reference internal" href="any-artwork.medium.html"&gt;&lt;span class="std std-ref"&gt;Artwork Medium Reference Index&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;我现在用这个扩展来管理我的 &lt;a class="reference internal" href="any-book.html"&gt;&lt;span class="std std-ref"&gt;读书笔记&lt;/span&gt;&lt;/a&gt;、&lt;a class="reference internal" href="any-artwork.html"&gt;&lt;span class="std std-ref"&gt;习作&lt;/span&gt;&lt;/a&gt;、&lt;a class="reference internal" href="any-artist.html"&gt;&lt;span class="std std-ref"&gt;艺术家记录&lt;/span&gt;&lt;/a&gt;、&lt;a class="reference internal" href="any-friend.html"&gt;&lt;span class="std std-ref"&gt;友情链接&lt;/span&gt;&lt;/a&gt;。关于它如何工作，它还能怎么玩，也会有单独的文章来说明。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;博客&lt;/h2&gt;
&lt;p&gt;博客是最难办的一件事情，单纯靠安排笔记的排版确实可以让它看起来像一个博客，但关键的目录、标签、归档、评论功能统统都没有。好在这件事情已经有人做了，并且非常符合 Sphinx 的哲学。&lt;/p&gt;
&lt;p&gt;&lt;a class="extlink-ghorg reference external" href="https://github.com/sunpy"&gt;👥 sunpy&lt;/a&gt; 社区写了一个叫 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/ablog"&gt;📦 ablog&lt;/a&gt; 的扩展，用来在 Sphinx 里建立博客，保持兼容最新版的 Sphinx 为目标，开发也非常活跃。你可以看看 ABlog 在我的笔记系统上的效果：&lt;a class="reference internal" href="#" title="Posts"&gt;&lt;em&gt;Posts&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ABlog 支持 Disqus 评论，如果你想用 Self-hosted 的 &lt;a class="reference external" href="https://posativ.org/isso/"&gt;Isso&lt;/a&gt; 的话，可以试试我写的 &lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-isso"&gt;📦 sphinxnotes-isso&lt;/a&gt;，文章底部可以看到 Isso 的评论框。&lt;/p&gt;
&lt;p&gt;值得一提的是，Sphinx 生成的 HTML 文档里的侧边栏不是全局的，可以让不同的页面采用不同的侧边栏，因此 ABlog 引入的博客侧边栏不会影响现有的其他的文档：&lt;/p&gt;
&lt;figure class="align-default" id="id10"&gt;
&lt;img alt="https://silverrainz.me/_images/sphinx-sidebar-with-without-ablog.png" src="https://silverrainz.me/_images/sphinx-sidebar-with-without-ablog.png" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;左：默认 sidebar，右：博客 sidebar&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;比较遗憾的是，之前使用的 sphinx_rtd_theme 并不听 Sphinx 的 sidebar 配置 只能换成了默认的 Alabaster theme&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;其他扩展&lt;/h2&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;这里仅列出我正在使用的扩展及其效果，想了解它们的具体配置，请看 &lt;a class="reference external" href="https://github.com/SilverRainZ/bullet/blob/master/conf.py"&gt;conf.py&lt;/a&gt; ，也许我会写一篇文章里来它们的使用技巧。&lt;/p&gt;
&lt;/div&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-lilypond"&gt;📦 sphinxnotes-lilypond&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;用来显示音符 &lt;span class="sphinxnotes-lilypond" id="sphinxnotes-lilypond-0" style="display: inline-flex; vertical-align: middle;"&gt;
&lt;img class="sphinxnotes-lilypond" src=".././_lilypond/9b7759da7ffa17e3ce15414f33fa03e3bc2e8ff1/music.cropped.png" alt="\score{\relative { c' }}" style="height: 2.5em;"/&gt;&lt;/span&gt;  和 &lt;span class="xref std std-doc"&gt;带试听音频的乐谱&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxnotes-strike"&gt;📦 sphinxnotes-strike&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;提供了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;del&lt;/span&gt;&lt;/code&gt; role 用来显示 reST 不支持的删除线&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:del:`Sphinx`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;Sphinx&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;内置扩展 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.ext.extlink&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;来方便地生成外部链接&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:ghuser:`SilverRainZ`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="extlink-ghuser reference external" href="https://github.com/SilverRainZ"&gt;👤 SilverRainZ&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/executablebooks/sphinx-design"&gt;⛺ executablebooks/sphinx-design&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;提供了 reST 不支持的分栏功能（见下），顺便还享用了它内置的 &lt;span class="fa fa-font"&gt;&lt;/span&gt; Font Awesome 支持&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;内置扩展 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.ext.graphviz&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;用 Dot Language 绘制简单的流程图：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row docutils"&gt;
&lt;div class="sd-col sd-d-flex-row docutils"&gt;
&lt;div class="sd-card sd-sphinx-override sd-w-100 sd-shadow-sm docutils"&gt;
&lt;div class="sd-card-body docutils"&gt;
&lt;div class="sd-card-title sd-font-weight-bold docutils"&gt;
reST&lt;/div&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;digraph&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;: dot
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;   Alice -&amp;gt; Bob
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-row docutils"&gt;
&lt;div class="sd-card sd-sphinx-override sd-w-100 sd-shadow-sm docutils"&gt;
&lt;div class="sd-card-body docutils"&gt;
&lt;div class="sd-card-title sd-font-weight-bold docutils"&gt;
效果&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib-plantuml"&gt;📦 sphinxcontrib-plantuml&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;用 Plant UML 绘制各种图表：&lt;/p&gt;
&lt;div class="sd-container-fluid sd-sphinx-override sd-mb-4 docutils"&gt;
&lt;div class="sd-row docutils"&gt;
&lt;div class="sd-col sd-d-flex-row docutils"&gt;
&lt;div class="sd-card sd-sphinx-override sd-w-100 sd-shadow-sm docutils"&gt;
&lt;div class="sd-card-body docutils"&gt;
&lt;div class="sd-card-title sd-font-weight-bold docutils"&gt;
reST&lt;/div&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;uml&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;   [Alice] -&amp;gt; [Bob]
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sd-col sd-d-flex-row docutils"&gt;
&lt;div class="sd-card sd-sphinx-override sd-w-100 sd-shadow-sm docutils"&gt;
&lt;div class="sd-card-body docutils"&gt;
&lt;div class="sd-card-title sd-font-weight-bold docutils"&gt;
效果&lt;/div&gt;
&lt;p class="plantuml"&gt;
&lt;img src="https://silverrainz.me/_images/plantuml-e520c685b207a87c1a70a97feb6aa80696f9b0c4.png" alt="[Alice] -&amp;gt; [Bob]"/&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib.email"&gt;📦 sphinxcontrib.email&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;生成难以被爬虫抓取的邮件地址，防止 SPAM&lt;/p&gt;
&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;:email:`foo&amp;#64;example.com`&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;script type="text/javascript"&gt;document.write(
    "&lt;n pynff=\"ersrerapr rkgreany\" uers=\"znvygb:sbb\100rknzcyr\056pbz\"&gt;sbb\100rknzcyr\056pbz&lt;\057n&gt;".replace(/[a-zA-Z]/g,
        function(c){
            return String.fromCharCode(
                (c&lt;="Z"?90:122)&gt;=(c=c.charCodeAt(0)+13)?c:c-26
            );
        }
    )
);&lt;/script&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib.asciinema"&gt;📦 sphinxcontrib.asciinema&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;在文档中嵌入 asciinema 录制的终端操作：&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;asciinema&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; 117813
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;效果：&lt;/p&gt;
&lt;script async id="asciicast-117813" 
                src="https://asciinema.org/a/117813.js"&gt;&lt;/script&gt;&lt;/dd&gt;
&lt;dt&gt;内置扩展 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.ext.githubpages&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;用于生成部署 GitHub Pages 的 &lt;code class="file docutils literal notranslate"&gt;&lt;span class="pre"&gt;.nojekyll&lt;/span&gt;&lt;/code&gt; 文件&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;内置扩展 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx.ext.intersphinx&lt;/span&gt;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;非常有意思的扩展，允许在引用其他 Sphinx 文档的 &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html"&gt;Domain&lt;/a&gt; ，可惜现在没有这个需求&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinxcontrib.gtagjs"&gt;📦 sphinxcontrib.gtagjs&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;在页面中嵌入 Google Analytics 代码&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;a class="extlink-pypi reference external" href="https://pypi.org/project/sphinx_sitemap"&gt;📦 sphinx_sitemap&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;生成 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/站点地图"&gt;📖 站点地图&lt;/a&gt; 以优化搜索引擎排名&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p class="rubric"&gt;脚注&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id7" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference internal" href="notes/man/git.html"&gt;&lt;span class="doc"&gt;Git&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/sphinx-as-note-taking-system-2.html"/>
    <summary>这是 category-我如何用-sphinx-建立笔记系统 系列的第 二 篇，你可以通过订阅 RSS 来获取后续更新。</summary>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <category term="笔记系统" label="笔记系统"/>
    <published>2021-05-25T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/sphinx-as-note-taking-system-1.html</id>
    <title>我如何用 Sphinx 建立笔记系统（一）选择 Sphinx 的理由</title>
    <updated>2021-05-24T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="sphinx-sphinx"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是 &lt;a class="reference internal" href="blog/category/%E6%88%91%E5%A6%82%E4%BD%95%E7%94%A8-sphinx-%E5%BB%BA%E7%AB%8B%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F.html" title="我如何用 Sphinx 建立笔记系统"&gt;&lt;em&gt;我如何用 Sphinx 建立笔记系统&lt;/em&gt;&lt;/a&gt; 系列的第 一 篇，你可以通过订阅 &lt;a class="reference external" href="https://silverrainz.me/blog/atom.xml" title="银色子弹 Feed"&gt;&lt;span class="xref std std-ref"&gt;RSS&lt;/span&gt;&lt;/a&gt; 来获取后续更新。&lt;/p&gt;
&lt;/div&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/sphinx-as-note-taking-system-1.rst&lt;/span&gt;, line 13)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;replace&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;replace&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这个笔记系统是带有强烈个人色彩的 &lt;a class="reference internal" href="blog/sphinx-as-note-taking-system-1.html#id3"&gt;&lt;span class="std std-ref"&gt;需求&lt;/span&gt;&lt;/a&gt; 下诞生的，并不适合所有人，你可以稍作了解，再决定是否继续阅读。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这篇文章作为系列的开场白，非常切题地只讲了我选择 Sphinx 的理由，不感兴趣也可以直接看 &lt;a class="reference internal" href="blog/sphinx-as-note-taking-system-2.html"&gt;&lt;span class="doc"&gt;下一篇文章&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;&lt;a class="any any-friend reference internal" href="about/me.html#friend-SilverRainZ" title="friend SilverRainZ"&gt;&lt;a href="#report-3"&gt;&lt;span class="problematic" id="problematic-3"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-3"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; （指我自己）在使用一个还未存在的自建笔记系统，每次想写点东西都因为「无法解决依赖」而失败。 &lt;a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;不知何时我养成了一种奇怪的癖好，想读一本有价值的书，没有合适工具记读书笔记，所以不读。 想记录一些不成体系的知识，不知道如何组织分类这些碎片，所以不记。想写一篇博客，文章里有一些交叉引用，不想用粗暴的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="pre"&gt;href=xxx&amp;gt;&lt;/span&gt;&lt;/code&gt; ，所以不写。因噎废食大概就是这样吧。&lt;/p&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;漫长的尝试&lt;/h2&gt;
&lt;p&gt;我并非没有在找合适的记录工具，大学时用 OneNote，在我还热衷于成为一个黑客的时候，我用 OneNotes 记下了几十篇 OllyDBG 的学习笔记。那时候云同步功能还不够好，在一次误操作中丢失了部分笔记，从此成为软黑。&lt;/p&gt;
&lt;p&gt;后来 GitBook 流行起来，尝试用其管理笔记，缺点有三：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;太慢了&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Markdown 表达力太孱弱，索引靠手写，引用靠 HTML 链接&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;打包非常恶心：我曾在 AUR 维护过 &lt;a class="extlink-aur reference external" href="https://aur.archlinux.org/packages/nodejs-gitbook"&gt;📦 nodejs-gitbook&lt;/a&gt;，gitbook 提供了一个只许全局安装（Root 下而非 Home 下）的 gitbook-cli 作为安装器，而不允许用户单独安装 gitbook 本身：这让发行版的打包非常困难。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2017 年我开始用 &lt;a class="reference internal" href="blog/use-sphinx-and-rst-to-manage-your-notes.html"&gt;&lt;span class="doc"&gt;Sphinx 管理我的笔记&lt;/span&gt;&lt;/a&gt; ，reStructuredText 已经很接近我心中理想的 markup language 的样子，结果刚建起一个框架便开始荒废。从那时到现在已经过去了四年，我记录下了些什么呢？——什么都没有&lt;/p&gt;
&lt;p&gt;2020 年，3、4 月的时候我尝试用 Golang 从零开始写一个笔记软件，后来发现无论是设计和工作量都不是我单枪匹马能胜任的，最后只留下只有零星几个 commit 的仓库。&lt;/p&gt;
&lt;p&gt;5 月，我建立了 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 仓库准备再试试 Sphinx，之后学画需要记 &lt;a class="reference internal" href="notes/zxsys/index.html"&gt;&lt;span class="doc"&gt;大量的笔记&lt;/span&gt;&lt;/a&gt;，将他们电子化也是一个强大的驱动力。&lt;/p&gt;
&lt;p&gt;9 月的时候生病，居然也因祸得福，捡到了几个月的疗养时间。在家的时候里我好好学习了一下 Sphinx 和 Docutils，思考各种类型的文档要如何组织，尝试使用社区提供的 &lt;a class="extlink-ghorg reference external" href="https://github.com/sphinx-contrib"&gt;各种扩展&lt;/a&gt; 来增强文档的功能，再后来发现自己的需求社区并不能满足，便自己建立了一个一人社区 &lt;a class="extlink-ghorg reference external" href="https://github.com/sphinx-notes"&gt;👥 sphinx-notes&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;2021 年，在陆续完善一些关键的 Sphinx 扩展之后，我的笔记系统 &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;发出了响亮的第一声啼哭&lt;/span&gt; 开始慢慢形成了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;span id="id4"&gt;&lt;/span&gt;&lt;h2&gt;需求&lt;/h2&gt;
&lt;p&gt;在漫长的寻找中我慢慢明确了自己的需求，以及自己心目中的笔记系统是什么样子的。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;我希望 &lt;em&gt;笔记被良好分类且结构合理&lt;/em&gt; ，对目录（Table Of Content）、交叉引用（Cross Reference）有一定需求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;我有一个 &lt;a class="reference internal" href="#" title="Posts"&gt;&lt;span class="xref std std-ref"&gt;博客&lt;/span&gt;&lt;/a&gt;，我认为它一种 &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;生产级别的&lt;/span&gt; 笔记，应当作为系统的一部分&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一些不成体系的 &lt;a class="reference internal" href="jour/2021/index.html"&gt;&lt;span class="doc"&gt;笔记片段&lt;/span&gt;&lt;/a&gt; 有碎片化的属性，我需要他们能被合理组织&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我希望能 &lt;em&gt;结构化地描述笔记中的对象&lt;/em&gt; ，并对它们进行引用、索引和分类，听起来有些强迫症但并非空穴来风：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;我的 &lt;a class="reference internal" href="notes/zxsys/index.html"&gt;&lt;span class="doc"&gt;绘画训练计划&lt;/span&gt;&lt;/a&gt; 中包含大量的习作，我用希望用统一的方式记录他们的日期、尺幅、媒介，例如：&lt;a class="reference internal" href="any-artwork.medium.html"&gt;&lt;span class="std std-ref"&gt;Artwork Medium Reference Index&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我在学艺术史，以艺术家为脉络的话，我可以建立这样的索引：&lt;a class="reference internal" href="any-artist.html"&gt;&lt;span class="std std-ref"&gt;Artist Reference Index&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我的 &lt;a class="reference internal" href="any-friend.html"&gt;&lt;span class="std std-ref"&gt;朋友们&lt;/span&gt;&lt;/a&gt; 经常会出现在我的行文中，我想漂亮地 mention 到 TA，比如 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-quininer" title="friend quininer"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;，其实也是避免冗余的一个方式&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我是 Linux 用户（B.T.W. Arch Linux &lt;a class="footnote-reference brackets" href="#id12" id="id5" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;），我在终端下工作，&lt;em&gt;我希望我的笔记在终端能被良好地检索和浏览&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我偏爱纯文本，作为曾经的 Mircosoft Word 的用户，我不喜欢复杂的富文本带来的难以预测的排版问题，以及兼容问题&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我乐于折腾配置，有一定的编程经验：我清楚自己的需求特殊，愿意为此折腾，包括写一些代码&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;指标&lt;/h2&gt;
&lt;p&gt;我将上面的需求尽量转化为一些指标用于选型：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;使用纯文本&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;就编辑体验的一环来说，富文本往往绑定一个复杂的，羸弱（想想论坛编辑器）或者
难以预料的（想想 MS Word）的编辑器，这当然不能怪他们，富文本编辑真是是太难了&lt;/p&gt;
&lt;p&gt;纯文本给我一种踏实感：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;不会产生冗余代码 -- 你写什么它就是什么&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;不限制编辑器 -- 我可以继续用 (Neo)Vim&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;其实不一定，看看 VimWiki、Org-mode&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;容易自动化地修改&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;表达能力及格&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;笔记系统所使用的表达方式（Markup language、富文本）要有一定的表达能力，对于书写中的常用格式（链接，引用，代码块、脚注、表格、提示、图片）都要有足够支持。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;标准可扩展&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;在前面的指标里为什么我不要求「表达能力强」呢？&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;强实际上意味着集成度高，和后面某一条指标相悖&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;强也意味着 Domain Specified，所有的通用 Markup language 都无法做到方方面面让人满意，笔记写多了总有自己的特殊需求。富文本里能打的可能只有也 OneNote 一个 —— 但我怎么可能去用它呢（笑）&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，够用就行—— 只要系统是可扩展，我们自己动手把它变强。&lt;/p&gt;
&lt;p&gt;B.T.W. 我不喜欢所有使用 Markdown 方言的笔记软件，这是不「标准」的扩展方式。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;自由开源&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;我不信任商业软件、共享软件：软件项目会倒闭，会改变定价，会做 Breaking Change，会停止维护——当然自由软件也会，只是你和社区并非无能为力&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;组件化&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;我希望我的系统最终是由多个组件组合而成的，组件化意味着 &lt;em&gt;复杂度被分摊到了不同的组件上&lt;/em&gt; ，在未来某一个项目跑路的时候，我只需要寻找它那一部分的替代品就好了。&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;目的单纯&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;承上，在系统里负责解释和渲染笔记的核心组件几乎是不可替代的，那么我希望那个它是目的是单纯且稳定的。如果它还多做了很多事情。比如说发布系统、帐号体系、权限控制，甚至 APP 等，又或者它是某个庞大项目的附庸，那么我也倾向于不使用它。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;
&lt;section id="restructuredtext-sphinx"&gt;
&lt;h2&gt;reStructuredText + Sphinx&lt;/h2&gt;
&lt;p&gt;其实上面写一堆有些 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/先射箭再画靶"&gt;📖 先射箭再画靶&lt;/a&gt; 的意思了，如题，最终我选择了 reStructuredText + Sphinx 作为笔记系统的核心。&lt;/p&gt;
&lt;p&gt;现在介绍会不会太晚？&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;&lt;a class="reference external" href="https://docutils.sourceforge.io/rst.html"&gt;&lt;img alt="rst-badge" src="https://silverrainz.me/_images/rst.png" style="height: 1em;" /&gt;&lt;/a&gt; is an easy-to-read, what-you-see-is-what-you-get plaintext markup syntax and parser system. …  reStructuredText is designed for extensibility for specific application domains.  &lt;a class="footnote-reference brackets" href="#id13" id="id7" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.sphinx-doc.org"&gt;&lt;img alt="sphinx-badge" src="https://silverrainz.me/_images/sphinx.webp" style="height: 4em;" /&gt;&lt;/a&gt; Sphinx is a tool that makes it easy to create intelligent and beautiful documentation, written by Georg Brandl and licensed under the BSD license. It was originally created for the Python documentation, and it has excellent facilities for the documentation of software projects in a range of languages. &lt;a class="footnote-reference brackets" href="#id14" id="id8" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;针对上面的指标，reStructuredText（下称 reSt） + Sphinx 具有哪些优势呢？&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;reST 虽然稍显繁琐，但其表达能力非常优秀（从本文可见一斑）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;quot;reST is designed for extensibility for specific application&amp;quot; 这不就是我想要的吗？&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sphinx 作为 Python 官方的文档生产系统，久经考验，同时也被大量著名非 Python项目（Blender、DPDK、Linux Kernel）采用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sphinx 在 reST 的基础上实现了优秀的扩展机制，同时有 &lt;a class="reference external" href="https://pypi.org/search/?q=sphinxcontrib"&gt;大量的现成的扩展&lt;/a&gt; 可用&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;更细节一点，Sphinx 提供的功能直击我的痛点（&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;组合拳来一套&lt;/span&gt;）：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;toctree 指令能将文档以树状的形式组织起来&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;交叉引用功能非常全面&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html"&gt;Domain&lt;/a&gt; 机制为后续的 &lt;a class="reference internal" href="blog/sphinx-as-note-taking-system-2.html#id2"&gt;&lt;span class="std std-ref"&gt;描述、引用和索引&lt;/span&gt;&lt;/a&gt; 提供了基础&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除此之外，单纯靠 Sphinx 无法达到的指标，我用扩展 + 其他组件搞定，请看下一篇文章：&lt;a class="reference internal" href="blog/sphinx-as-note-taking-system-2.html"&gt;&lt;span class="doc"&gt;我如何用 Sphinx 建立笔记系统（二）系统架构&lt;/span&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p class="rubric"&gt;脚注&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id10" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;和 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-VOID001" title="friend VOID001"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 的 &lt;a class="reference external" href="https://void-shana.moe/linux/zh-taking-notes-with-vim.html#comment-530"&gt;对话节选&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id12" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id5"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.quora.com/What-is-meant-by-btw-I-use-arch"&gt;https://www.quora.com/What-is-meant-by-btw-I-use-arch&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id13" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id7"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://docutils.sourceforge.io/rst.html"&gt;https://docutils.sourceforge.io/rst.html&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id14" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id8"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.sphinx-doc.org"&gt;https://www.sphinx-doc.org&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/sphinx-as-note-taking-system-1.html"/>
    <summary>这是 category-我如何用-sphinx-建立笔记系统 系列的第 一 篇，你可以通过订阅 RSS 来获取后续更新。rst-badge</summary>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <category term="笔记系统" label="笔记系统"/>
    <published>2021-05-24T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/new-boy.html</id>
    <title>嘿，我去 2010</title>
    <updated>2021-03-21T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;p&gt;6 月我从长亭科技离职，去燕郊 &lt;a class="extlink-weibo reference external" href="https://weibo.com/lixiaofeiart"&gt;&amp;#64;李晓飞&lt;/a&gt; 老师处学画，
课题是基础素描。&lt;/p&gt;
&lt;p&gt;上次正经学素描还是高中，2010 年我上高一，一晃十年已经过去。看《乐队的夏天》，
盘尼西林唱了朴树的《New Boy》之后，张亚东哽咽道：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;「当年大家都是小孩，而且觉得 2000 年要来了，那时候我们写歌叫《我去 2000 年》。
大家对 2000 年都有很多期待，觉得一切都会变得很好。结果，好吧，就是我们都老了。」&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;我已经忘记了十年前我对未来的自己有什么期待，也或许那时没有许下任何期待。
我在离职那一天，在朋友圈发了五月天的《嘿，我要走了！》，配上的文字是：「我去 2010。」&lt;/p&gt;
&lt;p&gt;对，我好像对接下来的时间抱有很多期待，觉得一切都会变得很好，就像 2010 年的我
过得无忧无虑一样。&lt;/p&gt;
&lt;p&gt;新的时代是要来了，可惜是 &lt;a class="extlink-zhwiki reference external" href="https://zh.wikipedia.org/wiki/三体用语列表"&gt;乱纪元&lt;/a&gt; 。对于世界来说，
新时代是新冠，是名人的去世，是动乱的格局，对我来说，是重新被情绪打败，
是凝视深渊然后被深渊吞噬。&lt;/p&gt;
&lt;p&gt;9 月的时候生了病，经历了非常多痛苦的事情，有些人不请自来，伤害我，爱我，我也被伤害，
然后爱上，最后也伤害她。事情的收尾是不体面的，我从来不是一个完美受害者，
甚至我才是真正的加害者，我只是因为过分软弱，被宽容，被同情罢了。我什么都不能再做了，
再动弹一下都会让事情更坏。事件的余波到现在还在发挥着影响，但未来总是会落定吧。
时间会推着我往前走。只是我大不相同了。就如同画 &lt;a class="any any-artwork reference internal" href="notes/zxsys/way-to-artist/find-yourself.html#artwork-xfczk-010" title="artwork xfczk-010"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 时我所想的:&lt;/p&gt;
&lt;figure class="align-default" id="id2"&gt;
&lt;img alt="https://silverrainz.me/_images/IMG_20210204_145427__01__01.jpg" src="https://silverrainz.me/_images/IMG_20210204_145427__01__01.jpg" style="width: 60%;" /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;那时我的脑子里还没有辞职的念头，工作日的脑子装着代码和工单，
只有周末才能假扮艺术家。 每天夜里都有孤独的时候，醒来又是健全的一个人。&lt;/span&gt;&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;p&gt;现在的燕郊也下雪，脑子里是光和影子，看不懂的形体的和可爱的人儿。
我好像可以自诩艺术家，但无法称之为人了。每天要吃一大把的药，醒来和不醒来没有区别。&lt;/p&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;再见啦，我的 2010，再见啦，那个一点都不胖的人。&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/new-boy.html"/>
    <summary>6 月我从长亭科技离职，去燕郊 @李晓飞 老师处学画，
课题是基础素描。</summary>
    <category term="生活" label="生活"/>
    <published>2021-03-21T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/migrate-to-sphinx.html</id>
    <title>博客迁移到 Sphinx</title>
    <updated>2020-12-26T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="sphinx"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;因此标题是指「博客从 Jekyll 迁移到 Sphinx」&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;近半年发生了非常大的事情，死去又活来，居然也因祸得福，捡到了几个月的疗养时间。
在这段时间里我慢慢把自己理想中的 PIM 系统架设起来。&lt;/p&gt;
&lt;p&gt;2017 年我用 &lt;a class="reference internal" href="blog/use-sphinx-and-rst-to-manage-your-notes.html"&gt;&lt;span class="doc"&gt;Sphinx 管理我的笔记&lt;/span&gt;&lt;/a&gt;，
结果建完便开始荒废，那时候英语非常差，即使把 Sphinx 文档读下来也不明所以，用不好应该也是理所当然吧。&lt;/p&gt;
&lt;p&gt;5 月的时候，我已经建好了 SilverRainZ/bullet 仓库准备再试试 Sphinx，
之后学画需要记大量的笔记，将他们电子化也是一个强大的驱动力。&lt;/p&gt;
&lt;p&gt;于是在偷闲的这段时间里我好好学习了一下 Sphinx 和 Docutils，思考各种信息要如何组织，
试用社区提供的 &lt;a class="reference external" href="https://github.com/sphinx-contrib"&gt;各种扩展&lt;/a&gt; ，其中不少年久失修，
也就写了一些 &lt;a class="reference external" href="https://github.com/sphinx-notes"&gt;扩展&lt;/a&gt; 来满足自己的需求，顺便回馈社区。&lt;/p&gt;
&lt;p&gt;个人主页、笔记、画、随记，甚至谱子也都被我慢慢搬进了 Sphinx。
博客是最难办的一件事情，不用插件就不像博客，写个插件工作量又巨大，
好在这件事情已经有人做了，并且做得非常舒服，完全符合我的想象。&lt;/p&gt;
&lt;p&gt;sunpy 社区写了一个叫 &lt;a class="reference external" href="https://ablog.readthedocs.io"&gt;ablog&lt;/a&gt; 的 Sphinx 扩展，
归类、标签、归档、RSS 应有尽有，开发也非常活跃。&lt;/p&gt;
&lt;p&gt;很棒的一点是 Sphinx 的 sidebar 并不是全局的，可以用 glob pattern 让不同的页面用不同的
sidebar，ablog 引入的博客侧边栏并不会影响其他的文档。但遗憾的是，正在使用的 sphinx_rtd_theme 并不听 Sphinx 的 sidebar 配置，因此还是换到了 Alabaster。&lt;/p&gt;
&lt;p&gt;文章没有用，本着不做 breaking change 的原则，还是迁移过去了，所以有了这篇没有人看的通知。&lt;/p&gt;
&lt;p&gt;最重要的，新的博客地址是 &lt;a class="reference external" href="https://silverrainz.me/blog/"&gt;https://silverrainz.me/blog/&lt;/a&gt; , tech.silverrainz.me 之后会 redirect
到新地址。&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/migrate-to-sphinx.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Python" label="Python"/>
    <category term="Sphinx" label="Sphinx"/>
    <category term="变更" label="变更"/>
    <published>2020-12-26T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/srain-and-me.html</id>
    <title>Srain 1.0 发布了</title>
    <updated>2020-04-06T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="srain-1-0"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition- admonition"&gt;
&lt;p class="admonition-title"&gt;前注&lt;/p&gt;
&lt;p&gt;这篇短文之前在知乎和朋友圈都发过了，发到博客仅为存档，另也做了一些小的修正和改动。
不知道这里何时能够不荒废。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="extlink-ghrepo reference external" href="https://github.com/SrainApp/srain"&gt;⛺ SrainApp/srain&lt;/a&gt; 是一个我业余时间开发的 GTK3 IRC 客户端。代码托管在 github 上。&lt;/p&gt;
&lt;p&gt;2015 年末的时候，我刚写完了自己的玩具内核 OS67，处于一段不知道做点什么东西的过渡期。&lt;/p&gt;
&lt;p&gt;同年我已经开始用 openSUSE，为了解决一些问题尝试在 IRC 上提问。
再后来开始用 Arch Linux，整天挂在 #archlinux-cn （那个时候还没有 offtopic）里灌水，
大概在 2016 年年后，我开始了 Srain 的开发，初衷是因为没有一个用起来顺手的 IRC 客户端，
后来因为 GSoC、学画、沉迷 Minecraft、实习、毕业、工作各种各样的事情，也因为能力不足，
Srain 的开发进度一直很缓慢，甚至砍掉了一些规划好的功能。&lt;/p&gt;
&lt;p&gt;在开发过程中经常能收到一些嘲讽或者不解：你在玩自己的开源过家家游戏、IRC 正在慢慢死掉、
你在做没有意义的事情。 他们说得都对，但我是一个把沉没成本看得过分重的人，所以我做到了现在。&lt;/p&gt;
&lt;p&gt;我也能听到一些支持的声音：evacchi 在 Reddit 上帮我打广告；tim77 帮我做了俄文翻译；
xeirrr 帮我写了 gentoo 的构建脚本；cpba 和 Hexchat 作者 TingPing 帮我指出了一些 FreeDesktop 上不规范的地方；
Arch Linux CN 社区的 zwindl 和 VOID001 愿意和我共同维护这个项目（尽管最后「此事古难全」了）；
在漫长的开发过程里，Srain 也慢慢走进了 Flathub、Fedora、openSUSE、openBSD 的官方仓库中。
（Update：截至 2020-04-26，又多了 NetBSD、 Void Linux 和 OpenMandriva）&lt;/p&gt;
&lt;p&gt;下面这篇文章介绍了 Srain 1.0 所拥有的特性以及未来的开发计划，
如果有其他发行版的 maintainer 愿意将 Srain 加入你们的软件源，欢迎联系我。
Srain 未来会继续开发下去，跟着 IRC 一起慢慢消失在历史里。&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://srain.silverrainz.me/blog/introducing-srain.html"&gt;Modern IRC client written in GTK&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note update admonition"&gt;
&lt;p class="admonition-title"&gt;Updated on 2020-04-06&lt;/p&gt;
&lt;p&gt;从 02-29 发布后截至 2020-04-06，Srain 又进入了三个发行版的官方仓库，
合并了 8 位社区贡献者的 PR，收到了数十个来自社区的反馈，发布了三个版本，
尽管在（只能称之为火花的）宣传热度过去后，来自社区的贡献会慢慢变少，
但我相信是会有人受益于这个软件的吧，一切都会顺利进行的吧，I pray。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/srain-and-me.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="GTK" label="GTK"/>
    <category term="IRC" label="IRC"/>
    <category term="Srain" label="Srain"/>
    <published>2020-02-29T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/switch-from-duoshuo-to-isso.html</id>
    <title>从多说迁移到 Isso</title>
    <updated>2017-06-10T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="isso"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;前阵子多说 &lt;a class="reference external" href="http://dev.duoshuo.com/threads/58d1169ae293b89a20c57241"&gt;对外宣布&lt;/a&gt;
它将在 2017 年 6 月 1 日停止服务。截至 6 月 9 日，评论框已经无法使用，甚至我的
评论管理后台的域名也已经停止解析了。&lt;/p&gt;
&lt;p&gt;这其实是意料之中的事情，缺乏盈利途径的多说长久以来一直处于缺乏维护的状态，
三头两头挂一次，这次终于撑不下去了。总之还是感谢这一两年来多说它提供的方便又免费
的评论服务。即使是这么一个没人看的小博客，评论功能也是不可缺少的，感谢归感谢，
我还是得找个下家 :-) 。&lt;/p&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;为什么是 Isso&lt;/h2&gt;
&lt;p&gt;我所见的各种静态博客用得最多的还是 Disqus，曾经我也是 Disqus 的用户，但是 Disqus
存在着一些问题：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;被墙，这当然不是 Disqus 本身的问题，这甚至不算是个问题&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;评论无法彻底被删除，我曾经在 #archlinux-cn 讨论过这个问题，有人说既然你把数据
公开地 post 到网上来了，就别想着它能够被删除，因为任何人都可以将他备份起来。
我不敢苟同，数据是公开的没错，但作为这个评论系统的管理员，我应当有权利让这些
数据从我「管辖」的范围内删除，而 Disqus 并没有给我这样的权利。更重要的是，看着
这样删不掉的数据真的是太不爽了&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;非 Disqus 用户无法方便地评论，甚至会诱导你注册帐号&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;经过这次多说的关闭，我还是倾向于寻找一个开源的，能自己架设的评论系统。
&lt;a class="reference external" href="https://tomli.blog"&gt;biergaizi&lt;/a&gt; 在微博推荐了
Disqus 的开源替代：&lt;a class="reference external" href="https://posativ.org/isso/"&gt;Isso&lt;/a&gt;，Isso 在 Github 上有 2k+
的 stars，开发虽然看起来不活跃但也不至于死掉，官网的 Demo 看起来不错，
AUR 里面还有有现成的包能用，于是就决定是你了，Isso！&lt;/p&gt;
&lt;p&gt;我的博客托管在 Github 上，源码存放于：
&lt;a class="reference external" href="https://github.com/SilverRainZ/tech"&gt;https://github.com/SilverRainZ/tech&lt;/a&gt;，
Isso 则将部署在一台跑着 Arch Linux 的小破 vps 上。 &lt;em&gt;以下的操作均针对该代码仓库
以及 vps 上的 Arch 环境。&lt;/em&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;架设服务&lt;/h2&gt;
&lt;p&gt;首先从 AUR 安装安装 Isso：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$ yaourt -S isso
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其依赖 python-misaka-v1 和 python-html5lib-9x07 也是 AUR 包，yaourt 也会帮
我们安装上。AUR 虽好，但在安装的时候最好还是检查一下 PKGBUILD 和 .install 文件，
以避免来自收到来自一些混乱邪恶的打包者的恶意（比如前阵子就有人在 Pypi 和 Gem
投了恶意包 Orz）。&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;考虑把 Isso 收养到 archlinuxcn 源里，这个以后再说吧……&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;安装完成后，打开 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/etc/isso.conf&lt;/span&gt;&lt;/code&gt; 文件，文件对各个配置项都有详细的解释，
需要重点关注的配置如下：&lt;/p&gt;
&lt;div class="highlight-ini notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# Isso configuration file&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;[general]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;# 数据库地址，默认值是在 /tmp 里，无法持久化&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="na"&gt;dbpath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/lib/isso/comments.db&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="c1"&gt;# 使用 Isso 的网站地址，从不在这个列表里的地址发出的评论会被忽略&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;//tech.silverrainz.me/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;//tech.silverrainz.me/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="na"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="c1"&gt;# 日志&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="na"&gt;log-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/isso.log&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="k"&gt;[server]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="c1"&gt;# 监听端口&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="na"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="k"&gt;[guard]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;# 开启 SPAM 保护&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="c1"&gt;# 每分钟内最多五个新评论&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="na"&gt;ratelimit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="c1"&gt;# 评论不需要填写邮箱&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="na"&gt;require-email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="na"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;更详细的配置参考： &lt;a class="reference external" href="https://posativ.org/isso/docs/configuration/server/"&gt;Server Configuration&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;填写配置之后执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;systemctl&lt;/span&gt; &lt;span class="pre"&gt;start&lt;/span&gt; &lt;span class="pre"&gt;isso.service&lt;/span&gt;&lt;/code&gt; 就能启动 Isso 了。但注意配置文件
里监听的是本地地址的端口，这里将用 nginx 反向代理将连接转发给 Isso。&lt;/p&gt;
&lt;p&gt;nginx 配置如下（参考 &lt;a class="reference external" href="https://posativ.org/isso/docs/quickstart/#running-isso"&gt;Running Isso&lt;/a&gt;）：&lt;/p&gt;
&lt;div class="highlight-nginx notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[::]:80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;comments.silverrainz.me&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;comments.silverrainz.me&lt;/span&gt;&lt;/code&gt; 是指向 vps 的域名，你需要在域名所使用的 DNS
服务器提供者那里修改 A 记录。&lt;/p&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;邮件通知&lt;/h3&gt;
&lt;p&gt;// TODO&lt;/p&gt;
&lt;p&gt;还不会配 SMTP，先搁着。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;客户端&lt;/h2&gt;
&lt;p&gt;只要在网页中插入如下代码即可插入评论框：&lt;/p&gt;
&lt;div class="highlight-html notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;data-isso&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//comments.silverrainz.me/&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//comments.silverrainz.me/js/embed.min.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;isso-thread&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="jekyll-s-way"&gt;
&lt;h3&gt;Jekyll's Way&lt;/h3&gt;
&lt;p&gt;对于 Jekyll 博客，比较好的做法是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_includes&lt;/span&gt;&lt;/code&gt; 目录下在建立 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;comments&lt;/span&gt;&lt;/code&gt; 文件用来
存放评论框代码：&lt;/p&gt;
&lt;div class="highlight-html notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{ site.baseurl }}/assets/comments.css&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;data-isso&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//comments.silverrainz.me/&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//comments.silverrainz.me/js/embed.min.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;isso-thread&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;         &lt;span class="na"&gt;data-title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{ page.title }}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;         &lt;span class="na"&gt;data-isso-id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{ page.id }}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;data-isso-id&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;data-title&lt;/span&gt;&lt;/code&gt;  用来指定文章的唯一标识符和标题。
为每个文章指定标识符便于以后的各种迁移。&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;{{&lt;/span&gt; &lt;span class="pre"&gt;page.id&lt;/span&gt; &lt;span class="pre"&gt;}}&lt;/span&gt;&lt;/code&gt;
和  &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;{{&lt;/span&gt; &lt;span class="pre"&gt;page.title&lt;/span&gt; &lt;span class="pre"&gt;}}&lt;/span&gt;&lt;/code&gt;
是 Jekyll 提供的模板，用于获取本页面的 ID 和标题。
title 和 id 可以在文件的 yaml 头中设置，但 Jekyll 会为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_posts&lt;/span&gt;&lt;/code&gt; 中的文章自动生成 ID，
对于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_post/2017-06-10-switch-from-duoshuo-to-isso.md&lt;/span&gt;&lt;/code&gt;，
其 ID 是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/2017/06/10/switch-from-duoshuo-to-isso&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;然后在页面模板 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_layouts/page.html&lt;/span&gt;&lt;/code&gt; 里面引用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;comments&lt;/span&gt;&lt;/code&gt; 文件：
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;{%&lt;/span&gt; &lt;span class="pre"&gt;include&lt;/span&gt; &lt;span class="pre"&gt;comments&lt;/span&gt; &lt;span class="pre"&gt;%}&lt;/span&gt;&lt;/code&gt;
就可以在每个使用了 page 模板的网页上显示评论框了。&lt;/p&gt;
&lt;p&gt;详情请参见：&lt;a class="reference external" href="https://github.com/SilverRainZ/tech/commit/91fba1ed944ddc48d10df6dd21fceae5a0860b74"&gt;Commit: Replace duoshuo with isso&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="https"&gt;
&lt;h2&gt;HTTPS&lt;/h2&gt;
&lt;p&gt;对于启用了 HTTPS 的博客来说，部署还没有结束：在 HTTPS 页面（博客）中引用的
HTTP 脚本 (&lt;a class="reference external" href="http://comments.silverrainz.me/js/embed.min.js"&gt;http://comments.silverrainz.me/js/embed.min.js&lt;/a&gt;) 被认为是危险的
Mixed Content，现代浏览器会拒绝加载它们，因此评论框并不能显示出来。&lt;/p&gt;
&lt;p&gt;还好我们有 Let's Encrypt，给 Isso 上 HTTPS 并不是难事。&lt;/p&gt;
&lt;p&gt;只要验证了你对域名的所有权，Let's Encrypt 就为你签发证书，整个签发过程通过
certbot 完成，certbot 位于 [Community] 源中。验证所有权可以通过让
Let's Encrypt 访问你的网站上的随机验证文件完成，如果你使用 nginx 的话，更简单的
方式是安装软件包 certbot-nginx，指定 certbot 使用 nginx 验证方式即可。&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# pacman -S certbot certbot-nginx&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;运行 certbot 申请证书需要各种参数，参数也可以写在配置文件中，方便续签证书使用，
假设配置文件地址为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/etc/letsencrypt/cli.ini&lt;/span&gt;&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-ini notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="na"&gt;rsa-key-size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="na"&gt;domains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;comments.silverrainz.me&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;e-mail address&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="na"&gt;authenticator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;domains&lt;/span&gt;&lt;/code&gt; 是一个用逗号分隔的域名列表，可以让一个证书能用在多个域名上。
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;authenticator&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;nginx&lt;/span&gt;&lt;/code&gt; 需要你安装 certbot-nginx。&lt;/p&gt;
&lt;p&gt;certbot 的更多用法见：&lt;a class="reference external" href="https://certbot.eff.org/docs/using.html"&gt;User Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;执行以下命令申请证书：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# certbot -c /etc/letsencrypt/cli.ini certonly&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;接着按 certbot 的输出提示操作即可，当你看到类似信息的时候，说明证书已经申请成功了：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;IMPORTANT NOTES:
&lt;/span&gt;&lt;span data-line="2"&gt; - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/comments.silverrainz.me/fullchain.pem.
&lt;/span&gt;&lt;span data-line="3"&gt; - ...
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;获得证书后，修改 nginx 中 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;comments.silverrainz.me&lt;/span&gt;&lt;/code&gt; 的 server blcok：&lt;/p&gt;
&lt;div class="highlight-nginx notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[::]:443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/comments.silverrainz.me/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/comments.silverrainz.me/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_trusted_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/comments.silverrainz.me/chain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_session_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;1d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_session_cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;shared:SSL:50m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_session_tickets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;add_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;max-age=15768000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_stapling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_stapling_verify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;comments.silverrainz.me&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;至此，应当可以通过 HTTPS 访问 Isso 的脚本了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;样式&lt;/h2&gt;
&lt;p&gt;Isso 的评论框默认样式是配合亮色背景工作的，我用 CSS 稍稍做了一下调整，保存在
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;assets/comments.css&lt;/span&gt;&lt;/code&gt; 中：&lt;/p&gt;
&lt;div class="highlight-css notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;isso-postbox&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;auth-section&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;input-wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;auth-section&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;post-action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#DDD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;post-action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;hover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#FFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;isso-comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;hover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#FFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;isso-thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;isso-comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;isso-comment-header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#DDD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;larger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id8"&gt;
&lt;h2&gt;数据迁移&lt;/h2&gt;
&lt;p&gt;完成部署和简单的美化后，接下来就该把旧数据迁移过来了。&lt;/p&gt;
&lt;p&gt;在多说宣布关闭的时候我就从后台导出了我的所有评论数据，数据文件的格式是 JSON，
而 Isso 仅支持 Disqus 和 Wordpress 的 WXR 文件。本着不重复造轮子的原则，我找到了
这个脚本：&lt;a class="reference external" href="https://github.com/JamesPan/duoshuo-migrator"&gt;duoshuo-migrator&lt;/a&gt;，
注意脚本依赖 python2 和 python2-lxml。&lt;/p&gt;
&lt;p&gt;假设多说数据文件名为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;duoshuo.json&lt;/span&gt;&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$ wget https://raw.githubusercontent.com/JamesPan/duoshuo-migrator/master/duoshuo-migrator.py
&lt;/span&gt;&lt;span data-line="2"&gt;$ python2 duoshuo-migrator.py -i duoshuo.json -o wp.xml
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;然后导入 Isso 数据库：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# isso -c /etc/isso.conf import wp.xml&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;导入后到对应页面发现之前的评论并没有出现 :-(，使用以下命令将数据库的内容导出来看看&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$ echo -e &amp;#39;&amp;quot;page: URI&amp;quot;,&amp;quot;page: title&amp;quot;,&amp;quot;ID&amp;quot;,&amp;quot;mode&amp;quot;,&amp;quot;created on&amp;quot;,&amp;quot;modified on&amp;quot;,&amp;quot;author: name&amp;quot;,&amp;quot;author: email&amp;quot;,&amp;quot;author: website&amp;quot;,&amp;quot;author: IP&amp;quot;,&amp;quot;likes&amp;quot;,&amp;quot;dislikes&amp;quot;,&amp;quot;voters&amp;quot;,&amp;quot;text&amp;quot;\n&amp;#39;&amp;quot;$(sqlite3 /var/lib/isso/comments.db -csv &amp;#39;SELECT threads.uri, threads.title, comments.id, comments.mode, datetime(comments.created, &amp;quot;unixepoch&amp;quot;, &amp;quot;localtime&amp;quot;), datetime(comments.modified, &amp;quot;unixepoch&amp;quot;, &amp;quot;localtime&amp;quot;), comments.author, comments.email, comments.website, comments.remote_addr, comments.likes, comments.dislikes, comments.voters,comments.text FROM comments INNER JOIN threads ON comments.tid=threads.id&amp;#39;)&amp;quot; &amp;gt; export.csv
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这是导出来的 about 页面的一条评论：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="s2"&gt;&amp;quot;page: URI&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;page: title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;created on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;modified on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;author: name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;author: email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;author: website&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;author: IP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;likes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dislikes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;voters&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;about&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;关于&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2015-11-10 22:28:27&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Forrest Chang&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;*************&lt;/span&gt;&lt;span class="nd"&gt;@gmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;forrestchang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;***.**.***.*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;在知乎上看到，博主今年大二吗？&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;wp.xml&lt;/span&gt;&lt;/code&gt; 中对应的部分是：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;...
&lt;/span&gt;&lt;span data-line="2"&gt;    &amp;lt;item&amp;gt;
&lt;/span&gt;&lt;span data-line="3"&gt;      &amp;lt;title&amp;gt;关于&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;span data-line="4"&gt;      &amp;lt;link&amp;gt;http://lastavenger.github.io/about.html&amp;lt;/link&amp;gt;
&lt;/span&gt;&lt;span data-line="5"&gt;      &amp;lt;content:encoded&amp;gt;&amp;lt;![CDATA[]]&amp;gt;&amp;lt;/content:encoded&amp;gt;
&lt;/span&gt;&lt;span data-line="6"&gt;      &amp;lt;dsq:thread_identifier&amp;gt;5f3988f7e293c4ef57003c774e2a71aa&amp;lt;/dsq:thread_identifier&amp;gt;
&lt;/span&gt;&lt;span data-line="7"&gt;      &amp;lt;dsq:thread_identifier&amp;gt;5f3988f7e293c4ef57003c774e2a71aa&amp;lt;/dsq:thread_identifier&amp;gt;
&lt;/span&gt;&lt;span data-line="8"&gt;      &amp;lt;wp:post_date_gmt&amp;gt;&amp;lt;/wp:post_date_gmt&amp;gt;
&lt;/span&gt;&lt;span data-line="9"&gt;      &amp;lt;wp:comment_status&amp;gt;open&amp;lt;/wp:comment_status&amp;gt;
&lt;/span&gt;&lt;span data-line="10"&gt;      &amp;lt;wp:comment&amp;gt;
&lt;/span&gt;&lt;span data-line="11"&gt;        &amp;lt;dsq:remote&amp;gt;
&lt;/span&gt;&lt;span data-line="12"&gt;          &amp;lt;dsq:id&amp;gt;&amp;lt;/dsq:id&amp;gt;
&lt;/span&gt;&lt;span data-line="13"&gt;          &amp;lt;dsq:avatar&amp;gt;&amp;lt;/dsq:avatar&amp;gt;
&lt;/span&gt;&lt;span data-line="14"&gt;        &amp;lt;/dsq:remote&amp;gt;
&lt;/span&gt;&lt;span data-line="15"&gt;        &amp;lt;wp:comment_id&amp;gt;6215529386569892609&amp;lt;/wp:comment_id&amp;gt;
&lt;/span&gt;&lt;span data-line="16"&gt;        &amp;lt;wp:comment_author&amp;gt;Forrest Chang&amp;lt;/wp:comment_author&amp;gt;
&lt;/span&gt;&lt;span data-line="17"&gt;        &amp;lt;wp:comment_author_email&amp;gt;*************@gmail.com&amp;lt;/wp:comment_author_email&amp;gt;
&lt;/span&gt;&lt;span data-line="18"&gt;        &amp;lt;wp:comment_author_url&amp;gt;http://forrestchang.github.io/&amp;lt;/wp:comment_author_url&amp;gt;
&lt;/span&gt;&lt;span data-line="19"&gt;        &amp;lt;wp:comment_author_IP&amp;gt;***.**.***.***&amp;lt;/wp:comment_author_IP&amp;gt;
&lt;/span&gt;&lt;span data-line="20"&gt;        &amp;lt;wp:comment_date_gmt&amp;gt;2015-11-10 22:28:27&amp;lt;/wp:comment_date_gmt&amp;gt;
&lt;/span&gt;&lt;span data-line="21"&gt;        &amp;lt;wp:comment_content&amp;gt;&amp;lt;![CDATA[在知乎上看到，博主今年大二吗？]]&amp;gt;&amp;lt;/wp:comment_content&amp;gt;
&lt;/span&gt;&lt;span data-line="22"&gt;        &amp;lt;wp:comment_approved&amp;gt;1&amp;lt;/wp:comment_approved&amp;gt;
&lt;/span&gt;&lt;span data-line="23"&gt;        &amp;lt;wp:comment_parent&amp;gt;0&amp;lt;/wp:comment_parent&amp;gt;
&lt;/span&gt;&lt;span data-line="24"&gt;      &amp;lt;/wp:comment&amp;gt;
&lt;/span&gt;&lt;span data-line="25"&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;      ...
&lt;/span&gt;&lt;span data-line="27"&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;    &amp;lt;/item&amp;gt;
&lt;/span&gt;&lt;span data-line="29"&gt;...
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在多说中我使用 Jekyll 提供的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;{{&lt;/span&gt; &lt;span class="pre"&gt;page.id&lt;/span&gt; &lt;span class="pre"&gt;}}&lt;/span&gt;&lt;/code&gt; 来标识文章，
我在 about 页面设置的 id 是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/about&lt;/span&gt;&lt;/code&gt;，因此在 about 页面的评论框代码会请求获取
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/about&lt;/span&gt;&lt;/code&gt; 页面中的评论，而数据库中的 URI 却是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/about.html&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;从多说评论数据转换而来的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;wp.xml&lt;/span&gt;&lt;/code&gt; 中并没有保留之前的文章 ID (Thread ID)，Isso 应该是
直接从域名里把 URI 取出来当作文章 ID 的：
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;link&amp;gt;http://lastavenger.github.io/about.html&amp;lt;/link&amp;gt;&lt;/span&gt;&lt;/code&gt; =&amp;gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/about.html&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;于是尝试用 vim 把链接里面的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.html&lt;/span&gt;&lt;/code&gt; 去掉：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:%s/.html&amp;lt;/link&amp;gt;/&amp;lt;/link&amp;gt;/&lt;/span&gt;&lt;/code&gt;，重新导入，
评论就乖乖地出现了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h2&gt;安全&lt;/h2&gt;
&lt;p&gt;// TODO&lt;/p&gt;
&lt;p&gt;Isso 的安全性尚未考证，毫无安全技能点的我也只能先搁着了 :-(。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id10"&gt;
&lt;h2&gt;不足&lt;/h2&gt;
&lt;p&gt;当然 Isso 的缺点也是很多的……&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;没有管理界面，要管理评论只能手动操作数据库&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;交互并不好：从不在白名单的地址（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/etc/isso.conf&lt;/span&gt;&lt;/code&gt; 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;hosts&lt;/span&gt;&lt;/code&gt; 列表）发出评论，
评论框是没反应的；如果你的评论 字数不足/邮件地址格式不对/网址不对，点评论按钮也不会
有任何反馈&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;以后遇到了再补……&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/switch-from-duoshuo-to-isso.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Isso" label="Isso"/>
    <category term="多说" label="多说"/>
    <published>2017-06-10T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/use-sphinx-and-rst-to-manage-your-notes.html</id>
    <title>用 Sphinx + reStructuredText 构建笔记系统</title>
    <updated>2017-03-29T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="sphinx-restructuredtext"&gt;

&lt;div class="admonition attention"&gt;
&lt;p class="admonition-title"&gt;注意&lt;/p&gt;
&lt;p&gt;这是一次失败的尝试，在此基础上我建立了更完备、可持续的系统，请看 &lt;a class="reference internal" href="blog/category/%E6%88%91%E5%A6%82%E4%BD%95%E7%94%A8-sphinx-%E5%BB%BA%E7%AB%8B%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F.html" title="我如何用 Sphinx 建立笔记系统"&gt;&lt;em&gt;我如何用 Sphinx 建立笔记系统&lt;/em&gt;&lt;/a&gt; 系列&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;前几天把个人笔记从 GitBook 迁移到了 Sphinx 上，并在 &lt;a class="reference external" href="http://readthedocs.io/"&gt;Read The Docs&lt;/a&gt;
上发布，地址是 &lt;a class="reference external" href="http://notes.silverrainz.me"&gt;notes.silverrainz.me&lt;/a&gt;，旧域名在过期前也同样有效。&lt;/p&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;GitBook 是一个用于发布书籍的平台，允许你用 Markdown 编写书籍并使用 git 仓库管理，
还能通过这个平台发布到网络上，GitBook 同时也是 Gitbook 平台推出的书籍生成工具的名字。&lt;/p&gt;
&lt;p&gt;去年十月的的时候我开始用 GitBook + Markdown 维护自己的一些零碎的笔记。
为此在 Arch Linux 打包了 &lt;a class="reference external" href="https://aur.archlinux.org/packages/nodejs-gitbook/"&gt;nodejs-gitbook&lt;/a&gt;，
又写了一个自动生成目录摘要的 &lt;a class="reference external" href="https://github.com/SilverRainZ/dotfiles/blob/master/bin/gitbook-summary"&gt;小脚本&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;为什么现在我又迁移到 Sphinx + reStructuredText 呢？因为：&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;GitBook 是 Node.JS 写的&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Markdown 无法适应稍微复杂的写作场景&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id="node-js"&gt;
&lt;h2&gt;为什么我不喜欢 Node.js&lt;/h2&gt;
&lt;p&gt;我不知道 Node.js 开发者为何如此热衷于用它来造各种轮子甚至用来写各种本地应用。
Node 的包管理器 npm 会将一个应用的所有依赖都安装在项目目录下。
每个应用的依赖都是独立的 —— 这对部署来说很方便。并且 npm 的分包粒度相当细，
随便装个包都能带上几百个依赖，连一个字符串的 leftpad 函数都可以单独作为一个包。
去年愚人节的时候，&lt;a class="reference external" href="https://www.npmjs.com/package/left-pad"&gt;这个梗&lt;/a&gt;都玩得很开心……&lt;/p&gt;
&lt;p&gt;因此 Linux 发行版的打包者要打包一个 Node 包，就得打包并维护它附带的成百上千
的依赖，或者直接将包本身和依赖打在一起，代价就是要更新其中一个依赖就得更新整个包
以及接受系统中的文件重复。总之，Node.js 的打包只能在麻烦和冗余两者之间作出选择。
听说 openSUSE 社区还写了一套工具专门用来从多如牛毛的 npm 包自动生成 rpm 包。&lt;/p&gt;
&lt;p&gt;当然对于 Arch Linux 社区，肯定是拿起一把梭就干，即使是官方源的包也都是：&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;npm&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-g&lt;span class="w"&gt; &lt;/span&gt;--user&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$pkgdir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;/usr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$srcdir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;/&lt;span class="nv"&gt;$pkgname&lt;/span&gt;-&lt;span class="nv"&gt;$pkgver&lt;/span&gt;.tgz
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;依赖什么的？不管，例行公事地从 source 下载要安装的包，依赖的什么完全由 npm 处理。&lt;/p&gt;
&lt;p&gt;于是我打包的 nodejs-gitbook （事实上还包含了 nodejs-gitbook-cli）足足有 2w+
个文件，我仿佛看到无数细碎的 Javascript 脚本在我的 SSD 上蠕动……&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;/ la @ la-arch 10:35 -&amp;gt; ~
&lt;/span&gt;&lt;span data-line="2"&gt;$ pacman -Ql nodejs-gitbook | wc -l
&lt;/span&gt;&lt;span data-line="3"&gt;23009
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;相比之下 python-sphinx 清爽多了：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;/ la @ la-arch 21:27 -&amp;gt; ~
&lt;/span&gt;&lt;span data-line="2"&gt;$ pacman -Ql python-sphinx | wc -l
&lt;/span&gt;&lt;span data-line="3"&gt;922
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;除去打包上的槽点，nodejs-gitbook 这工具的使用体验也是相当差：目录文件 SUMMARY.md
需要自己手动写；在我 i5 + 8G + SSD 的电脑上生成一本有 24 个 md 文件的书籍需要 &lt;em&gt;8.6 秒&lt;/em&gt;
—— 它似乎并没有办法 incremental build；&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;gitbook&lt;/span&gt; &lt;span class="pre"&gt;serve&lt;/span&gt;&lt;/code&gt; 命令能在本地启动一个 HTTP Server
预览书籍，并且文件改变的时候网页会自动刷新，这很赞，可是你为什么没告诉我每次文件改动
都要 &lt;em&gt;重载所有插件，重启 HTTP Server 并且所有的文件重新生成一遍&lt;/em&gt; 呢？于是每次改动后你
需要十多秒后才能够「实时预览」。&lt;/p&gt;
&lt;p&gt;以上所述的问题针对 GitBook 3.2.1 及以下版本。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="markdown-vs-restructuredtext"&gt;
&lt;h2&gt;Markdown vs reStructuredText&lt;/h2&gt;
&lt;p&gt;Markdown 是啥这里就不说了……Markdown 的问题在于它太轻又没有一个统一的标准。
因此各个社区都自顾自地实现了一套自己的方言，同样是叫 Markdown，
你在这里可以显示的内容，换了一个地方就打回原型。
当然你可以选择使用这些方言里面所共有的语法，而这点语法可能只够在论坛回回帖用。&lt;/p&gt;
&lt;p&gt;目前最流行的 Markdown 方言应该是 GFM(GitHub Flavored Markdown) 了，
但即使你坚持只用 GFM 编写你的文档，你依然会遇到问题：
不同的 GFM 的实现存在细节上的差异。声明标题的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;#&lt;/span&gt;&lt;/code&gt; 后面需要空格么？
加粗字体的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;**&lt;/span&gt;&lt;/code&gt; 左右需要空格隔开么？直接跟非符号的文字会有问题么，
Unicode 的文字和符号能被分清么？在不将文件生成为 HTML 之前，你很难知道你的文档是
什么样子。&lt;/p&gt;
&lt;p&gt;另，程序员是 Markdown 的主要使用群体，而 Markdown 居然使用「在行末空两格」
作为换行标记，trailing whitespace 怎么能忍呢……（这个貌似是扩展语法）&lt;/p&gt;
&lt;p&gt;reStructuredText 同样是轻量标记语言的一种，Python Docutils 是其主要实现，
reStructuredText 的语法稍微复杂了一点，具体可以看
&lt;a class="reference external" href="http://zh-sphinx-doc.readthedocs.io/en/latest/rest.html"&gt;reStructuredText 简介&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;相对于 Markdown，reStructuredText：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;提供了更丰富的语法元素：原生 Markdown 并不能调整插图大小，不支持表格（GFM 支持），
不支持脚注，引用，注释 —— 当然这些 reStructuredText 都支持&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对格式的要求更高：我所见过 Markdown 渲染器对待 Mardkown 的态度和浏览器对于
HTML 类似，在处理无法识别的语法的时候会选择忽略。而 Docutils 在遇到未知语法的时候会报错。
因此 Markdown 用户可能需要多次的预览文档来排错，而 reStructuredText 用户可以从报错获得
出现错误的位置&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有更统一的实现：这一点貌似不太公平，因为 Markdown 的实现众多，而 reStructuredText
貌似就只有 Docutils 了？但实际上 reStructuredText 的标准也比 Markdown 明确得多&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在语法上提供了扩展的途径。而 Markdown 并没有，通用的扩展方法是在文档里插入 HTML 标签……&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;就我所知， reStructuredText 有两种支持扩展的语法： 解释文本（Interpreted Text）
和 指令（Directives）。&lt;/p&gt;
&lt;p&gt;在 reStructuredText 中，用单个反引号 `` ` 包围的字符串称为
&lt;a class="reference external" href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#interpreted-text"&gt;Interpreted Text&lt;/a&gt;
，反引号中的内容根据角色（Role）有不同解释方式。Role 由冒号 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:&lt;/span&gt;&lt;/code&gt; 包围，可以位于
Interpreted Text 的前后。reStructuredText 利用 Interpreted Text 实现了不少的内联标记。比如：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;:emphasis:`text` 等价于 *text*
&lt;/span&gt;&lt;span data-line="2"&gt;:strong:`text` 等价于 **text**
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Interpreted Text 只能作为行内元素使用（无法跨行），而
&lt;a class="reference external" href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#explicit-markup-blocks"&gt;Explicit Markup&lt;/a&gt;
。作用的对象则是文本块。Explicit Mark 以在行首的两个句号 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;..&lt;/span&gt;&lt;/code&gt; 开始，后跟一个空格，
接下来的行保持相同缩进，直到文本块结束。&lt;/p&gt;
&lt;p&gt;Explicit Markup 被用来实现&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;脚注：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;这是脚注&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#f1]_ ，这也是脚注 [#f2]_ 。&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#f1] 第一条脚注的文本.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#f2] 第二条脚注的文本.&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;引用：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;这篇笔记参考了&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;reStructuredText&lt;/span&gt; &lt;span class="n"&gt;简介&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;reStructuredText&lt;/span&gt; &lt;span class="n"&gt;简介&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;zh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sphinx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readthedocs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;显式的超链接：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;这是一个 `标题`_
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;.. _标题: http://silverrainz.me
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;指令（Directives）是 reStructuredText 的又一扩展机制：插入图片，
代码声明等语法均由 Directives 实现，和 Role 一样，指令可以被开发者定义。
指令名后跟两个冒号，冒号后是参数。在新的一行里可以指定选项，选项由 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:&lt;/span&gt;&lt;/code&gt; 包围，
后跟选项值。选项之后还可能有文本块。&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;.. 能够指定高宽，alt 文本，对齐的图片，比 Markdown 不知道高到哪里去了~
&lt;/span&gt;&lt;span data-line="2"&gt;.. image:: picture.jpeg
&lt;/span&gt;&lt;span data-line="3"&gt;    :height: 100px
&lt;/span&gt;&lt;span data-line="4"&gt;    :width: 200 px
&lt;/span&gt;&lt;span data-line="5"&gt;    :scale: 50 %
&lt;/span&gt;&lt;span data-line="6"&gt;    :alt: alternate text
&lt;/span&gt;&lt;span data-line="7"&gt;    :align: right
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="sphinx"&gt;
&lt;h2&gt;Sphinx 简介&lt;/h2&gt;
&lt;p&gt;Sphinx 是 Georg Brandl 用 Python 编写的文档创建工具，以 BSD 协议开源，使用
reStructuredText 作为标记语言。Sphinx 被用来编写 &lt;a class="reference external" href="https://docs.python.org/"&gt;Python 的官方文档&lt;/a&gt;。
去年 6 月的时候，&lt;a class="reference external" href="https://lwn.net/Articles/692704/"&gt;Linux Kernel 也开始使用 Sphinx + reStructuredText 管理内核文档&lt;/a&gt;。
这里有一个使用 Sphinx 创建文档的项目列表：&lt;a class="reference external" href="http://www.sphinx-doc.org/en/stable/examples.html"&gt;Projects using Sphinx&lt;/a&gt;。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Sphinx 能够将文档输出为 HTML，LaTex，Manuals page 等多种格式。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在 reStructuredText 的语法基础上提供了各种信息（文档，章节，函数，引用，术语）的交叉引用&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sphinx 还能轻松地定义文档的层次结构：自动生成目录树，自动发现目录下的其他文档&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sphinx 对 Python/C/C++ 等语言提供了良好的支持&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持扩展，你可以编写自己的模块&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;看起来 Sphinx 的功能比 GitBook 丰富得多，但其实它们之间没什么可比性，
因为 Sphinx 是文档生成工具而 GitBook 只是简单的书籍生成工具。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id="markdown-restructuredtext"&gt;
&lt;h2&gt;将 Markdown 笔记转化为 reStructuredText&lt;/h2&gt;
&lt;p&gt;使用 Sphinx 管理笔记的第一步是将之前笔记转成 rst 格式，Pandoc 大法好：&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;md&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*.md&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;--from&lt;span class="o"&gt;=&lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;--to&lt;span class="o"&gt;=&lt;/span&gt;rst&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$md&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;basename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$md&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;.rst&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$md&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="shpinx"&gt;
&lt;h2&gt;Shpinx 的安装和使用&lt;/h2&gt;
&lt;p&gt;执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;pip&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt; &lt;span class="pre"&gt;sphinx&lt;/span&gt;&lt;/code&gt; 即可安装 Sphinx，Arch Linux 用户可以执行
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;pacman&lt;/span&gt; &lt;span class="pre"&gt;-S&lt;/span&gt; &lt;span class="pre"&gt;python-sphinx&lt;/span&gt;&lt;/code&gt; 安装。Sphinx 提供了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx-quickstart&lt;/span&gt;&lt;/code&gt; 程序，
可以交互式地建立一个 Sphinx 项目。项目目录下的 conf.py 储存了 Sphinx 的配置，
index.rst 则是默认的文档首页。&lt;/p&gt;
&lt;p&gt;使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx-build&lt;/span&gt; &lt;span class="pre"&gt;-b&lt;/span&gt; &lt;span class="pre"&gt;html&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;srcdir&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;builddir&amp;gt;&lt;/span&gt;&lt;/code&gt; 可以从 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;srcdir&amp;gt;&lt;/span&gt;&lt;/code&gt; 生成 HTML
文档输出到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;lt;builddir&amp;gt;&lt;/span&gt;&lt;/code&gt;，如果在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sphinx-quickstart&lt;/span&gt;&lt;/code&gt; 中指定了生成 Makefile，通过
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;html&lt;/span&gt;&lt;/code&gt; 即可生成 HTML 文档到预定义的 build 目录。&lt;/p&gt;
&lt;p&gt;Sphinx 似乎没有提供类似 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;gitbook&lt;/span&gt; &lt;span class="pre"&gt;serve&lt;/span&gt;&lt;/code&gt; 在本地启动 HTTP 服务器的功能，Linux
用户在 Makefile 中增加如下内容则可方便的在默认浏览器打开文档的首页：&lt;/p&gt;
&lt;div class="highlight-makefile notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;xdg-open&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;BUILDDIR&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/html/index.html&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;组织和索引&lt;/h2&gt;
&lt;p&gt;Sphinx 定义了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;toctree&lt;/span&gt;&lt;/code&gt; 指令作为目录树，各个文档由目录树组织在一起，
在构建文档的时候，如果存在没有被引用到的文档，Sphinx 会发出警告。&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;toctree&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="nc"&gt;:maxdepth:&lt;/span&gt; 2
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;    intro
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面的 rst 指令定义了一个最大深度为 2 的目录树，包含了当前目录下的 intro.rst 文件。
在渲染出来的 HTML 文件中，目录树会显示到 intro.html 的链接，链接的标题则会和
intro.rst 中的标题保持一致。如果 intro.rst 中存在章节，也会在目录树中显示出来，
但整个目录树的深度不超过 2。&lt;/p&gt;
&lt;p&gt;如果只想要在目录树中显示文档的标题而不显示内部的章节，需要为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;toctree&lt;/span&gt;&lt;/code&gt; 指令开启
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:titlesonly:&lt;/span&gt;&lt;/code&gt; 选项。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;toctree&lt;/span&gt;&lt;/code&gt; 在开启 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:glob:&lt;/span&gt;&lt;/code&gt; 的情况下支持通配符，比如 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*&lt;/span&gt;&lt;/code&gt; 匹配当前目录下所有的
（排除自身，下同）rst 文档。&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;index*&lt;/span&gt;&lt;/code&gt; 匹配当前目录下所有以 index 开头的 rst 文档。&lt;/p&gt;
&lt;p&gt;我在笔记的不同分类的文件夹中都建立了如下内容的 index.rst：&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gh"&gt;Title&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="gh"&gt;=====&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;Description.
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;toctree&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;   &lt;span class="nc"&gt;:glob:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;   &lt;span class="nc"&gt;:titlesonly:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;   *
&lt;/span&gt;&lt;span data-line="11"&gt;   */index
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个 index.rst 会匹配当前目录所有的 rst 文档，并在所有的文件夹下寻找 index.rst。
所有的笔记通过 index.rst 被组织到一起。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;使用 Read The Docs 发布&lt;/h2&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/use-sphinx-and-rst-to-manage-your-notes.rst&lt;/span&gt;, line 3); &lt;em&gt;&lt;a href="#id6"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate explicit target name: &amp;quot;read the docs&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;a class="reference external" href="http://readthedocs.io/"&gt;Read The Docs&lt;/a&gt; 是一个托管和展示文档的平台，支持 Sphinx
项目。在网站上注册后，授权 Github 即可从 Github 那边导入仓库。&lt;/p&gt;
&lt;p&gt;因此可以将笔记本身托管在 Github 上，每次更新时会通过 webhook 自动更新
Read The Docs 上的文档。&lt;/p&gt;
&lt;p&gt;P.S. Read The Docs 的主站看起来很简陋…… 给我一种要完蛋了的感觉。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/use-sphinx-and-rst-to-manage-your-notes.html"/>
    <summary>这是一次失败的尝试，在此基础上我建立了更完备、可持续的系统，请看 category-我如何用-sphinx-建立笔记系统 系列</summary>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <category term="笔记系统" label="笔记系统"/>
    <published>2017-03-29T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/gsoc-2016-sum-up.html</id>
    <title>GSoC 2016 小记 - 误打误撞三个月</title>
    <updated>2016-09-29T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="gsoc-2016"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;这是一篇拖了一个月的流水帐……&lt;/p&gt;
&lt;p&gt;谷歌编程之夏（Google Summer of Code/GSoC）是 Google 举办的年度编程活动，
征集学生为开源社区编写代码，时间持续三个月，成功完成项目的学生可以得到 Google
$5500 的报酬，同时开源社区也能得到 $500 的赞助。&lt;/p&gt;
&lt;img alt="GSoC 2013 Project" src="https://silverrainz.me/_images/gsoc-2016-proj.png" /&gt;
&lt;p&gt;我有幸参加了 2016 年的 Google Summoer of Code，为 GNU/Hurd 项目工作并完成预期目标，
在此记录。&lt;/p&gt;
&lt;section id="proposal"&gt;
&lt;h2&gt;从写 Proposal 到放弃&lt;/h2&gt;
&lt;p&gt;三月初的时候在 #archlinux-cn 听 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-quininer" title="friend quininer"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 说今年 Tox
社区要参加 GSoC 并开始招人的事情， &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;当然也提及了 Tox 去年闹出的一桩事：&lt;/span&gt;
&lt;a class="reference external" href="https://github.com/irungentoo/toxcore/issues/1379"&gt;Current situation of Tox #1379&lt;/a&gt;
这时候我才知道 GSoC 的存在。简单在网上搜索了一下，正好大三下学期也基本没课了，
便萌生了要试试的想法。&lt;/p&gt;
&lt;p&gt;参与的学生需要在 &lt;a class="reference external" href="http://summerofcode.withgoogle.com/"&gt;Google Summer of Code&lt;/a&gt; 上注册，
并寻找你心仪的 organization，并在网站上针对 organization 的某个项目提交提案（Proposal），
这些组织一般都是著名的开源社区，比如 GNU、Linux Fundation、GNOME、KDE、Wine、Apache 等等。
Proposal 用来告诉社区你为什么认为自己能胜任这个项目，将如何做这个项目，以及你的时间安排等，
有些社区会提供一些 proposal 模板，告知你一些必须回答的问题。 一个学生可以提交至多五份提案。&lt;/p&gt;
&lt;p&gt;于是开始挑 organization，因为我比较熟悉的语言就只有 C，写过 toy kernel 和 GTK 程序，
因此最后敲定了两个组织： GNU 和 GNOME，前者有 Hurd 内核项目，后者用 GTK 框架写程序，
大概能算是我比较擅长的部分吧。&lt;/p&gt;
&lt;p&gt;接着开始在网上找资料写 proposal，上了一下 #hurd 频道打了一下招呼，然后就没有然后了……
看到其他人写的 proposal 和网上的描述，开始觉得 GSoC 以我的能力是参加不了的，
于是一字未写，在心里默默跟自己说放弃好了。&lt;/p&gt;
&lt;p&gt;到了 3 月 23 号，那天早上不知道为什么突然来了劲儿，决定只报一个项目：
GNU/Hurd 的 &lt;a class="reference external" href="https://www.gnu.org/software/hurd/community/gsoc/project_ideas/xattr.html"&gt;Implement xattr Support&lt;/a&gt;。
在当天早上把 proposal 写好并马上提交了最终版…… 然后给学生证拍了张照片作为入学证明上传。&lt;/p&gt;
&lt;p&gt;3 月 29 号，被邮件告知「Your GSoC 2016 Proof of Enrollment form was rejected because:
not english/missing translation.」，仅仅拍学生证不够，还需要加上写英文说明，
当时我的想法是，反正 proposal 也过不了，于是没搭理邮件。&lt;/p&gt;
&lt;p&gt;4 月 7 号，在我没有采取任何行动的情况下，Google 又发邮件说 Proof of Enrollment
已经通过验证了…… :-| 大概是找了华人员工来审核的吧，当时心理暗想 Google
的工作人员真的好负责啊……&lt;/p&gt;
&lt;p&gt;再往后，每天跟着舍友去图书馆，写还当时未成型的 &lt;a class="reference external" href="https://github.com/SilverRainZ/srain"&gt;Srain&lt;/a&gt;，
其间有 GNU 的成员在我的 proposal 上留言评论……我也没去回复，
渐渐把这件事忘记了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="welcome-to-gsoc-2016"&gt;
&lt;h2&gt;Welcome to GSoC 2016!&lt;/h2&gt;
&lt;p&gt;4 月 23 号，刚起床看到有封邮件，&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;GSoC 2016: Congratulations, your proposal with GNU Project has been accepted!&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;觉得有点激动又难以置信，还特意发了篇&lt;a class="reference internal" href="blog/gsoc-2016.html"&gt;&lt;span class="doc"&gt;博客&lt;/span&gt;&lt;/a&gt;得瑟了一下。&lt;/p&gt;
&lt;p&gt;接下来就根据邮件的要求：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;看&lt;a class="reference external" href="https://developers.google.com/open-source/gsoc/help/accepted-students"&gt;学生须知&lt;/a&gt;，&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;上传税务表（Tax form），国外的学生只需要下载
&lt;a class="reference external" href="https://developers.google.com/open-source/gsoc/help/images/foreign-certification.pdf"&gt;Foreign Certification Form&lt;/a&gt;
打印出来签名扫描上传便好&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;注册 Payoneer 帐号设置收款账户 :-D&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;完善个人信息&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;做完以上事情后，GSoC 就可以正式开始了，从 4 月 23 号到 5 月 22 号是 Community
Bonding Period，用来和社区成员交流，配置开发环境，熟悉工作流程等。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="community-bonding"&gt;
&lt;h2&gt;焦虑的 Community Bonding&lt;/h2&gt;
&lt;p&gt;Hurd 当前的开发者基本在欧洲，我的两位 mentor：
&lt;a class="reference external" href="https://www.sceen.net/~rbraun/resume.pdf"&gt;Richard Braun&lt;/a&gt; 和
&lt;a class="extlink-ghuser reference external" href="https://github.com/https://github.com/teythoon"&gt;Justus Winter&lt;/a&gt; 也是，
由于时区相差太大，一般在下午五点以后跟他们用 IRC 联系。&lt;/p&gt;
&lt;p&gt;在同 mentor 们联系之后，我开始看 Hurd 的&lt;a class="reference external" href="https://www.gnu.org/software/hurd/index.html"&gt;文档&lt;/a&gt;，
作为一个除了开发者之外几乎没人用的系统 :-( ……除了 Wiki 之外没有任何参考的资料，
甚至项目中的文档也是严重过期的。&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/gsoc-2016-sum-up.rst&lt;/span&gt;, line 3); &lt;em&gt;&lt;a href="#id3"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate explicit target name: &amp;quot;implement xattr support&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;我的项目是 &lt;a class="reference external" href="https://www.gnu.org/software/hurd/community/gsoc/project_ideas/xattr.html"&gt;Implement xattr Support&lt;/a&gt;：
在 Hurd 的 ext2 文件系统上（是的，Hurd 依然在用 1993 年发明的的文件系统 :-(）
上实现文件扩展属性（Extended file attributes/xattr），xattr 是一种文件系统的特性，
能为磁盘上的文件添加键值对（Key/Value pair），文件之于 xattr，类似进程之于环境变量。
并使用 xattr 来储存 Hurd 所需的元信息。&lt;/p&gt;
&lt;p&gt;Hurd 并不是一个内核，而只是一套微内核守护进程，真正的内核是 GNU Mach，
大部分的功能都使用 translator 实现在用户态。&lt;/p&gt;
&lt;p&gt;Translator 是一类程序，相当于一个 Server，translator 需要与一个文件绑定，
用户通过访问这个文件来实现对 Server 的请求，如下：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$ touch hello
&lt;/span&gt;&lt;span data-line="2"&gt;$ cat hello
&lt;/span&gt;&lt;span data-line="3"&gt;$ settrans hello /hurd/hello
&lt;/span&gt;&lt;span data-line="4"&gt;$ cat hello
&lt;/span&gt;&lt;span data-line="5"&gt;&amp;quot;Hello World!&amp;quot;
&lt;/span&gt;&lt;span data-line="6"&gt;$ settrans -g hello
&lt;/span&gt;&lt;span data-line="7"&gt;$ cat hello
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Translator 分为 passive translator 和 active translator，passive translator
只是一个命令行，储存在磁盘中，当该文件首次被访问时执行，在我实现 xattr 之前，
passive translator 一直是简单地储存在一个临时申请的块中（这就是 Hurd 需要 xattr
的原因：用更通用的方式来储存 passive translator）。&lt;/p&gt;
&lt;p&gt;ext2 文件系统的 translator 叫做 ext2fs，位于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/hurd&lt;/span&gt;&lt;/code&gt; 目录下，我的全部工作，就是
为 ext2fs 的代码添加 xattr 支持，因此，虽说是内核项目，但是全过程都在用户态下进行。&lt;/p&gt;
&lt;p&gt;这些东西也都是后来才慢慢知道的，一开始我只是埋头看文档，Hurd is not Linux，
很多概念都和 Linux 差别极大……我本来的英文就很差，效率也不行，越看越乱，
每天都坐在电脑前配合着 Google 翻译看文档，一天八九个小时下来，
集中精神看的时间可能不到十分之一，Braun 每天都会询问我进度，我又支支吾吾说不出来。&lt;/p&gt;
&lt;p&gt;有时候会遇到些看不懂的句子，问 mentor 们的时候又因为英文问题而交流不畅，那时候真恨不得
自己变成个外国人。&lt;/p&gt;
&lt;p&gt;那时候我开始觉得到我可能胜任不了这份工作，GSoC 每年大概有近 10% 的学生无法完成任务（Fail），
我会是那 10 % 么？&lt;/p&gt;
&lt;p&gt;这样焦虑的日子持续了一两个星期，终于有一天在讨论 Hurd 中 port 的概念时，Braun 说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;&amp;quot;i think next years, we'll make sure students understand this before they get accepted,
as part of the communit bonding period&amp;quot;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这个时候再不行动，被 fail 就是可预见的未来了，我已经没有心情和自制力去继续看文档了，
还是直接写代码吧。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;不过，看文档的这段时间虽然很痛苦，但是也不是没收获，我从中了解到了一些 micro kernel
的概念，并且也不再像以前那样害怕英文文档了。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;编程之夏&lt;/h2&gt;
&lt;p&gt;大概从 5 月 18 号开始，我从无脑看文档转为写代码， 写代码比看文档愉快多了 ——
这大概也是我编程能力止步不前的原因吧，瞎写代码不看书。
mentor 们显然对我之前看文档表现出来的低下的效率和理解力很不满意，但依然对我的问题有问必答。&lt;/p&gt;
&lt;p&gt;其实 Hurd 在  06 年的时候就有人提交过 xattr 的 patch：&lt;a class="reference external" href="https://savannah.gnu.org/patch/?5126"&gt;GNU Savannah patch #5126&lt;/a&gt;，
当然那个 patch 很不完善（于是就这样搁置了 10 年吗 orz），到现在更是完全跑不起来了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;所以其实项目的最小目标就是：把这个 patch 修好 —— 当然这是后话了，那时候我不知道项目原来这么简单……&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;于是我开始修 patch，参照 ext2fs 的其他代码，把旧函数用新函数替代，
把能看懂的地方看懂，加上注释，看不懂的地方标注出来，在接口代码上打洞，
方便从外部测试这些代码。&lt;/p&gt;
&lt;p&gt;修完之后便参考 &lt;a class="reference external" href="http://www.nongnu.org/ext2-doc/ext2.html#CONTRIB-EXTENDED-ATTRIBUTES"&gt;The Second Extended File System&lt;/a&gt;
和 &lt;a class="reference external" href="http://lxr.free-electrons.com/source/fs/ext2/xattr.c"&gt;Linux Kernel&lt;/a&gt; 的代码，
修正原来代码中的 Bug，补全缺失的 xattr 函数。&lt;/p&gt;
&lt;p&gt;写代码比起看文档有实实在在的产出，也就有东西向 mentor 们汇报了，相比他们对我的评价也有所上升，
从 5 月 18 号到 7 月 4 号，我完成了大部分的功能并进行了调试，实现并导出了如下四个函数：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="n"&gt;列出节点的所有&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;error_t&lt;/span&gt; &lt;span class="n"&gt;ext2_list_xattr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="n"&gt;获取节点指定&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;的值&lt;/span&gt; &lt;span class="o"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;error_t&lt;/span&gt; &lt;span class="n"&gt;ext2_get_xattr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="n"&gt;设置节点指定&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;的值&lt;/span&gt; &lt;span class="o"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="n"&gt;error_t&lt;/span&gt; &lt;span class="n"&gt;ext2_set_xattr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="n"&gt;删除储存&lt;/span&gt; &lt;span class="n"&gt;xattr&lt;/span&gt; &lt;span class="n"&gt;信息的块&lt;/span&gt; &lt;span class="o"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="n"&gt;error_t&lt;/span&gt; &lt;span class="n"&gt;ext2_free_xattr_block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;5 月 18 号到 6 月 28 号，这段时间每天都保持着 6-7 * 6 个小时的工作时长，
用这么长时间是为了弥补我的低下的工作效率…… 6 月 28 日后，由于脑残学院的规定，
我不得不离开宿舍到一个恶心的培训公司实训，并在那个公司度过了大量不愉快的时间，
详情不表。我从来没有这么讨厌过自己的学校，待我毕业后一定要上知乎狠狠撕一下这个愚蠢的实训制度。#FLAG&lt;/p&gt;
&lt;p&gt;这段时间的代码都提交在
&lt;a class="reference external" href="https://github.com/SilverRainZ/hurd/tree/gsoc-2016-xattr"&gt;SilverRainZ/hurd at gsoc-2016-xattr&lt;/a&gt; 上。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;夏日的怠惰尾声&lt;/h2&gt;
&lt;p&gt;就如同上面所说的，只要修好这个 patch 并补全 xattr 的功能，项目就算完成了，
「GSoC 原来这么水啊……」，我开始产生了这种想法，一旦完成了最小目标，我就开始松懈，
在接下来的时间我更多地把精力放在了 Srain 的开发上。&lt;/p&gt;
&lt;p&gt;对于 GSoC 那边，仅仅是整理了代码和 commit 并再次测试，两位 mentor 对我后期的怠惰倒是没什么意见，
虽然我本来可以做更多的…… 预期的目标是在实现 xattr 之后实现 libdiskfs
（文件系统 translator 库，类似 vfs）以及 libc 接口，并把 xattr 的一系列工具 port 过来：
这些最后都因为我的懒惰而没有动手。&lt;/p&gt;
&lt;p&gt;这段时间我也不再天天挂在 IRC 上，而是每隔两三天上一次，mentor 们也没有向我询问进度，
反而是我一直在催他们 review 我的代码，征求他们的建议。他们似乎很忙，总体来看并没有积极地
reivew，这让我有点失望。但建议还是收到一些的，改了一些关于兼容旧 passive translation
的代码，apply 了几个 justus 的小 patch。&lt;/p&gt;
&lt;p&gt;摸鱼的日子一天天过去，迎来了 final evaluations，根据 mentor 的指导写了 GNU style 的
changelog，把整理好的两个 patch 发给他们，并写了一封总结邮件
&lt;a class="reference external" href="http://lists.gnu.org/archive/html/bug-hurd/2016-08/msg00075.html"&gt;[GSoC] Implement xattr Support Update&lt;/a&gt;
到 Hurd 的邮件列表。接着又到 GSoC 的网站上完成了 final evaluations。&lt;/p&gt;
&lt;p&gt;8 月 30 号，收到了 GSoC 完成的通知，结束了这个不算完美的夏天。&lt;/p&gt;
&lt;/section&gt;
&lt;hr class="docutils" /&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;我之所以能被 accept，和我的选择是有密切关系的：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;内核项目门槛稍高&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hurd 是冷门（想也知道）项目，&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement xattr Support 是比较重要的项目&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;申请的学生里之前普遍没有参与过 Hurd 的开发&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，和我竞争的学生大概只有 6、7 位，Hurd 最终 accept 了两位学生，除我之外，
另一位是 &lt;a class="reference external" href="https://github.com/Phant0mas"&gt;Phant0mas&lt;/a&gt;，去年的 GSoC 也为 Hurd
贡献了代码，我觉得如果申请的学生中存在本项目的开发者的话，其他人大概都没什么戏。
当时在选择 Hurd 的时候，其实也怀着「冷门项目大概没什么人报吧」这样的想法。&lt;/p&gt;
&lt;p&gt;对于这次的 GSoC，我不满意，自己的参与度不够，一方面受制于自己的英语水平，
一方面自己依然没办法打败自己 —— 自制力太低，效率太低。导致我最终仅仅是名义上地完成了项目，
没有继续贡献社区，也没有交到什么朋友，甚至连自己的代码能不能 merge 到主线都说不准。&lt;/p&gt;
&lt;p&gt;在这其间我收到了 Google 的三笔付款 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;3234.86&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;14635.59&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;17959.75&lt;/span&gt;&lt;/code&gt; 总计 35830.2 元，
一只圆珠笔，一本本子，一封 PDF 形式的电子证书，还有一件还在路上的 T-shirt，
物质收入颇丰。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;相关链接&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://summerofcode.withgoogle.com/"&gt;GSoC 官网&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.gnu.org/software/hurd/hurd.html"&gt;Hurd 官网&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://summerofcode.withgoogle.com/archive/2016/projects/5786848613892096"&gt;我的项目链接&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/SilverRainZ/gsoc-2016"&gt;Patch 和脚本&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/SilverRainZ/hurd"&gt;我的 Hurd fork&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/gsoc-2016-sum-up.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈GSoC 2013 Project</summary>
    <category term="GSoC" label="GSoC"/>
    <published>2016-09-29T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/practical-makefile-for-packaging.html</id>
    <title>编写便于打包的 Makefile</title>
    <updated>2016-06-25T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="makefile"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Note: 这篇文章假设你已经知道基本的 Makefile 编写规则&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;安装基于 make 构建的程序基本上就是两个步骤：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt;&lt;/code&gt; 然后 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt;，
前者把程序按依赖关系编译，后者把文档、数据、编译出来的二进制安装到系统中。
网络上关于 GNU Make 的教程不少，但似乎都止于「如何用 Makefile 自动编译程序」（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt;&lt;/code&gt;），
而关于用 Makefile 编写安装脚本（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt;）的文章却寥寥无几。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;2016-08-10: 经 盖子 提醒，make 本来就不适合做这种事情，于是才有了 autotools
这「更好」的构建工具。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;最近在写 &lt;a class="reference external" href="https://github.com/SilverRainZ/srain"&gt;Srain&lt;/a&gt; 的时候，
算是摸索出了对于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 的比较正确的写法：&lt;/p&gt;
&lt;p&gt;首先，对于项目生成产物只是单个可执行文件的情况下，直接在 install 目标里写
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;install&lt;/span&gt; &lt;span class="pre"&gt;-Dm755&lt;/span&gt; &lt;span class="pre"&gt;xxx&lt;/span&gt; &lt;span class="pre"&gt;/usr/bin/xxx&lt;/span&gt;&lt;/code&gt; 就好了。
但是并非所有项目都只包含单个可执行文件，程序可能还包含了 man 文档，icons，
图片，配置文件等，这些都要被安装到文件系统相应的位置上。&lt;/p&gt;
&lt;p&gt;我们先假设项目的结构如下，代码写了什么不重要~&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;.
&lt;/span&gt;&lt;span data-line="2"&gt;├── build
&lt;/span&gt;&lt;span data-line="3"&gt;├── data
&lt;/span&gt;&lt;span data-line="4"&gt;│   ├── pixmaps
&lt;/span&gt;&lt;span data-line="5"&gt;│   │   └── srain-avatar.png
&lt;/span&gt;&lt;span data-line="6"&gt;│   └── icons
&lt;/span&gt;&lt;span data-line="7"&gt;│       └── 16x16
&lt;/span&gt;&lt;span data-line="8"&gt;│           └── srain-icon.png
&lt;/span&gt;&lt;span data-line="9"&gt;├── Makefile
&lt;/span&gt;&lt;span data-line="10"&gt;└── srain.c
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;build 是存放编译中间文件和编译出来的二进制文件的地方，srain.c 是主程序代码，
srain-avatar.png 是程序要用到的图片。srain-icon.png 是程序图标。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;安装图标&lt;/h2&gt;
&lt;p&gt;对于图标，Icon Theme Specification&lt;a class="footnote-reference brackets" href="#fn-icon-theme-spec" id="id3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;
规定了图标在文件系统上的位置，程序只需要根据图标的名称（即文件名去掉扩展名）
和大小就可以获得图标文件的路径
（当然要借助各种库函数，比如 gtk 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;gtk_image_new_from_icon_name&lt;/span&gt;&lt;/code&gt;），
因此我们只要将图标文件复制到对应的位置上即可。&lt;/p&gt;
&lt;p&gt;根据上面的 spec，程序寻找图标时应该依次检查 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$HOME/.icons&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$XDG_DATA_DIRS/icons&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/share/pixmaps&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;参照 XDG Base Directory Specification&lt;a class="footnote-reference brackets" href="#fn-xdg-base-dir-spec" id="id4" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 看，
当 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$XDG_DATA_DIRS&lt;/span&gt;&lt;/code&gt; 为空时，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$XDG_DATA_DIRS&lt;/span&gt;&lt;/code&gt; 会默认为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/local/share/:/usr/share/&lt;/span&gt;&lt;/code&gt;
（感谢 csslayer 指出）。&lt;/p&gt;
&lt;p&gt;因此把图标安装在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/share/pixmaps&lt;/span&gt;&lt;/code&gt;、&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/local/share/icons&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/share/icons&lt;/span&gt;&lt;/code&gt;
下都是可行的，Arch Linux 偏向于安装在最后一个目录。
于是安装 &lt;em&gt;大小为 16x16 的图标&lt;/em&gt; 的脚本可以这么写：&lt;/p&gt;
&lt;div class="highlight-shell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;data/icons/16x16&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;png&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*.png&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;        &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm644&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;DESTDIR&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/usr/share/icons/hicolor/16x16/apps/&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里先不管 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$(DESTDIR)&lt;/span&gt;&lt;/code&gt; 是什么东西，把它当作空变量即可：&lt;/p&gt;
&lt;div class="highlight-shell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm644&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/icons/hicolor/16x16/apps/&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="prefix"&gt;
&lt;h2&gt;PREFIX&lt;/h2&gt;
&lt;p&gt;除了图标之外，其他的数据文件应该如何组织？
至少我们应该做到的是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;保证程序一定能找到数据文件&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一定程度上允许用户自定义安装的位置&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GNU make 提供了 prefix 等变量确定各种文件安装的位置&lt;a class="footnote-reference brackets" href="#fn-prefix" id="id5" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;prefix&lt;/span&gt;&lt;/code&gt; 是下述变量的前缀，默认的 prefix 值应该是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/local&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;exec_prefix&lt;/span&gt;&lt;/code&gt; 是下述变量的前缀，通常和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;prefix&lt;/span&gt;&lt;/code&gt; 相等&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bindir&lt;/span&gt;&lt;/code&gt; 安装可执行文件的位置，其值应为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$(exec_prefix)/bin&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/practical-makefile-for-packaging.rst&lt;/span&gt;, line 110)&lt;/p&gt;
&lt;p&gt;Unexpected possible title overline or transition.
Treating it as ordinary text because it's so short.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;datarootdir&lt;/span&gt;&lt;/code&gt; 用来安装只读的，架构无关的数据文件，其值应为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$(prefix)/share&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sysconfdir&lt;/span&gt;&lt;/code&gt; 用来安装只读的配置文件，其值应为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$(predix)/etc&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/practical-makefile-for-packaging.rst&lt;/span&gt;, line 114)&lt;/p&gt;
&lt;p&gt;Unexpected possible title overline or transition.
Treating it as ordinary text because it's so short.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面列出了各种用途的变量，但事实上我们不需要把数据文件分成那么细的粒度。
对于简单的项目，只有 prefix 是必要的，其他路径都可以 hardcode。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 可以这么写（为了命名统一，prefix 用大写）：&lt;/p&gt;
&lt;div class="highlight-Makefile notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nv"&gt;PREFIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/local
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm755&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;build/srain&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/srain&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;data/pixmaps&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;png&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*.png&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;            &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm644&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/share/srain/pixmaps/&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;放置各种文件的规范有了，但程序应该如何找到他的数据文件呢？
用 gcc 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-D&lt;/span&gt;&lt;/code&gt; 参数声明一个宏，在编译的时候告诉程序的 prefix：&lt;/p&gt;
&lt;div class="highlight-Makefile notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gcc
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-Wall
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nv"&gt;DEFS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-DPACKAGE_DATA_DIR&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build/srain
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nf"&gt;$(TARGET)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;.&lt;span class="n"&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;CC&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;DEFS&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$^&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在程序中你就可以根据这个宏在获得你的数据文件：&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#ifndef PACKAGE_DATA_DIR&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#define PACKAGE_DATA_DIR &amp;quot;/usr/local&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="n"&gt;gchar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;get_pixmap_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gchar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;gchar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_build_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PACKAGE_DATA_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;share&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;srain&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pixmaps&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_file_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_FILE_TEST_EXISTS&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注意上面的代码使用了 glib 函数库，当指定 prefix 为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr&lt;/span&gt;&lt;/code&gt;，
程序便会从 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/share/srain/pixmaps&lt;/span&gt;&lt;/code&gt; 里寻找图片。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;自行编译安装的程序通常被安装在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/local&lt;/span&gt;&lt;/code&gt;, 这也是 GNU 推荐的 prefix，
Arch Linux 的包的 prefix 通常是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;如上一番设定后，程序经过编译和安装后便可以运行指定的任意目录上了，
你也可以指定为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$(PWD)/build&lt;/span&gt;&lt;/code&gt; 方便调试。&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/usr;&lt;/span&gt; &lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/usr&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 后，产生的文件如下：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pixmaps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;icons&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hicolor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="n"&gt;x16&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/home/la/tmp;&lt;/span&gt; &lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/home/la/tmp&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 则是：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pixmaps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;icons&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hicolor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="n"&gt;x16&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="destdir"&gt;
&lt;h2&gt;DESTDIR&lt;/h2&gt;
&lt;p&gt;上面的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 直接将各种文件安装在了目的文件系统上，如果 Makefile 写错的话，
可能对系统造成破坏，直接安装也不利于打包，正确的做法是，由 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt;
得到程序所有文件的列表和路径，再由包管理器把这些文件和路径存为软件包，
安装的时候根据路径把文件放到应该放的位置（这大概就是 Staged Install？）。
（这里感谢青蛙老师 &lt;a class="extlink-ghuser reference external" href="https://github.com/hexchain"&gt;👤 hexchain&lt;/a&gt; 的指导）&lt;/p&gt;
&lt;p&gt;变量 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;DESTDIR&lt;/span&gt;&lt;/code&gt;&lt;a class="footnote-reference brackets" href="#fn-destdir" id="id6" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; 就是用来实现 Staged Install 的，把之前的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 改成这样：&lt;/p&gt;
&lt;div class="highlight-Makefile notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nv"&gt;PREFIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/local
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm755&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;build/srain&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;DESTDIR&lt;span class="k"&gt;)$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/srain&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;data/pixmaps&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;png&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*.png&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;            &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-Dm644&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;DESTDIR&lt;span class="k"&gt;)$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/share/srain/pixmaps/&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注意 DESTDIR 变量只应该作用在 install 阶段，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/usr;&lt;/span&gt; &lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;PREFIX=/usr&lt;/span&gt; &lt;span class="pre"&gt;DESTDIR=/tmp/&lt;/span&gt;&lt;/code&gt;
会把所有文件都安装在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/tmp&lt;/span&gt;&lt;/code&gt; 下， 所有的影响都被限制在该目录内。这次生成的文件应该是：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pixmaps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;icons&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hicolor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="n"&gt;x16&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;srain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;之后再由包管理器把这些文件打成包，安装到系统中。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="configure"&gt;
&lt;h2&gt;Configure&lt;/h2&gt;
&lt;p&gt;上面的 Makefile 有处不优雅的地方是，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;make&lt;/span&gt; &lt;span class="pre"&gt;install&lt;/span&gt;&lt;/code&gt; 的时候必须指定相同的 PREFIX，
不然安装后的程序肯定是运行不了的，而 make 本身并不能解决这个问题，因为 make 是「无状态」的。&lt;/p&gt;
&lt;p&gt;这里&lt;a class="footnote-reference brackets" href="#fn-practical-makefiles" id="id7" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;5&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;提供了一个脚本来让解决这个问题，将 Makefile 改名为 Makefile.in，
运行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;./configure&lt;/span&gt; &lt;span class="pre"&gt;--prefix=xxx&lt;/span&gt;&lt;/code&gt; 来获得一个拥有指定 prefix 的 Makefile，
这样就可以不用每次敲 make 都输入 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PREFIX=xxx&lt;/span&gt;&lt;/code&gt; 了。&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;于是大家都去用 autotools 了&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight-sh notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;*&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/--prefix=//&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;--help&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;usage: ./configure [options]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;options:&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;  --prefix=&amp;lt;path&amp;gt;: installation prefix&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;all invalid options are silently ignored&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;generating makefile ...&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PREFIX = &lt;/span&gt;&lt;span class="nv"&gt;$prefix&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;Makefile
&lt;/span&gt;&lt;span data-line="23"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;Makefile.in&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;Makefile
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;configuration complete, type make to build.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如上，执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;./configure&lt;/span&gt; &lt;span class="pre"&gt;--prefix=/usr&lt;/span&gt;&lt;/code&gt; 就会把 Makefile.in 复制为 Makefile，并在
Makefile 最前面加上一句 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PREFIX&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;/usr&lt;/span&gt;&lt;/code&gt;（实际操作顺序是反过来的你们懂就好）。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="archlinux-pkgbuild"&gt;
&lt;h2&gt;编写 Archlinux 的打包脚本 PKGBUILD&lt;/h2&gt;
&lt;p&gt;这样的一个项目打包起来是很愉快的 :)&lt;/p&gt;
&lt;div class="highlight-sh notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nv"&gt;pkgname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;srain
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;...
&lt;/span&gt;&lt;span data-line="4"&gt;build&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pkgname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;./configure&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;/usr
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;make
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;package&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pkgname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;DESTDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$pkgdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;install
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;完整的脚本请见：&lt;a class="reference external" href="https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=srain"&gt;srain.git - AUR Package Repositories&lt;/a&gt;，
可能稍有出入。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id8"&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="fn-icon-theme-spec" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id3"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html"&gt;Icon Theme Specification&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="fn-xdg-base-dir-spec" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id4"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#Environment%20variables"&gt;XDG Base Directory Specification#Environment variables&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="fn-prefix" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id5"&gt;3&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.gnu.org/prep/standards/html_node/Directory-Variables.html"&gt;GNU Coding Standards#Variables for Installation Directories&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="fn-destdir" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id6"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.gnu.org/prep/standards/standards.html#DESTDIR"&gt;GNU Coding Standards#DESTDIR: Support for Staged Installs&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="fn-practical-makefiles" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id7"&gt;5&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="http://nuclear.mutantstargoat.com/articles/make"&gt;Practical Makefiles, by example&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/practical-makefile-for-packaging.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="C" label="C"/>
    <category term="Linux" label="Linux"/>
    <category term="Makefile" label="Makefile"/>
    <published>2016-06-25T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/gsoc-2016.html</id>
    <title>GSoC 2016</title>
    <updated>2016-04-23T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="gsoc-2016"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;;-) 难以置信。&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/gsoc-2016-mail.png" /&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/gsoc-2016.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="GSoC" label="GSoC"/>
    <published>2016-04-23T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/thinkpad-l450.html</id>
    <title>入手 ThinkPad L450</title>
    <updated>2016-03-11T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="thinkpad-l450"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;img alt="" src="https://silverrainz.me/_images/thinkpad-l450.jpg" /&gt;
&lt;p&gt;元宵的时候，我从师兄手里买下了这台机子，全新，i5 4300U，8G内存，256G SSD，14寸 1366x768 屏幕。
只有 SSD 而没有 HDD 这点颇合我意，毕竟我没有囤积资源的癖好，256G 足矣，而且还能省下一笔 HDD 的钱。
机子在 ebay 上是 ￥3200，到手花了 ￥3700，以国内的价格来算还是值得的。&lt;/p&gt;
&lt;p&gt;之前用的电脑是 Lenove G455，这台 10 年生产的机器陪伴着我姐走过了四年大学，
又在我的高强度使用下度过了大三上学期，现在它终于可以要退役了。这台电脑除了硬盘有点噪音之外，其实一切都运行良好。
单纯做编程的话其实够用，痛点主要是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;无法用 FlashPlayer 流畅地播放 720P 的视频（当然这和 FlashPlayer 糟糕的性能也有很大关系）；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;跑不起最近的 firefox 和 YCM：Gtk3 版的 FF 的 bugs 还是很多，
虽然平时的 UI 响应似乎比 Gtk2 的时候好了一点，但是打开某些网页的时候还是会完全卡住，
而 YCM 则有时会吃掉我 1G-1.5G 的内存，然而我的内存才 3G，实在是不堪重负。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在一切都没问题了，这样的配置在我这个不太关心硬件的人看来，暂时是够用了。&lt;/p&gt;
&lt;p&gt;ThinkPad 的外观比我想象中还要漂亮一些，塑料外壳摸起来很舒服，
机身还算薄（不插上那个凸起的电池的话），键盘手感也不错。
另外崔土豪说屏幕可以 180 度展开，试了一下果然可以！
说到屏幕…… 1366x768 其实还是低了，仔细看很容易看出像素点来。&lt;/p&gt;
&lt;p&gt;机器预装 Windows 7，尽管我已经不用 Windows 好几个月了，但毕竟是个正版系统，
用了这么多年盗版了，还是洗白一下吧。&lt;/p&gt;
&lt;p&gt;至此，我使用的全部软件，全都是自由软件 &amp;amp; 正版软件啦！&lt;/p&gt;
&lt;p&gt;Win7 可以升级到 10，升级的过程略坎坷，不知道是怪微软的更新服务器好还是怪国内糟糕的网络环境好。
Check Update 一直不动，从官网下载了在线升级器，下完了整个镜像之后死掉了。
最后还是手动从官网下了镜像才装上的。&lt;/p&gt;
&lt;p&gt;装完 Windows 后自然就装 Arch Linux 了，还好磁盘格式是 MBR（一直对 GPT 有莫名的恐惧），
但是机器预装系统的时候已经把四个主分区都占用了 :( ，于是只好把最后的一个不知道是什么的 OS/2 格式的分区删掉，
腾出主分区给 Arch。&lt;/p&gt;
&lt;p&gt;在 &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Beginners'_guide"&gt;Arch Wiki 的光芒照耀下&lt;/a&gt;，
安装过程一切正常。&lt;/p&gt;
&lt;p&gt;装好后尝试了一下 KDE，果然已经不适应了，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;pacman&lt;/span&gt; &lt;span class="pre"&gt;-Rsc&lt;/span&gt;&lt;/code&gt; 之，然后回到 XMoand。&lt;/p&gt;
&lt;p&gt;趁着重新配置的时候更新了一下配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;使用 aur/ttf-iosevka 代替 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Tsentsiu&lt;/span&gt; &lt;span class="pre"&gt;Mono&lt;/span&gt; &lt;span class="pre"&gt;HG&lt;/span&gt;&lt;/code&gt; 作为编辑器和终端的字体&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 xbindskey 管理快捷键，而不是用 xmoand 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;additionalKeys&lt;/span&gt;&lt;/code&gt;
（听小药壶说可以用 scheme 来写 .xbindskeyrc）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 terminator 代替 konsole&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 dzen2 + &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;condy&lt;/span&gt; conky 代替 xmobar&lt;/p&gt;
&lt;p&gt;需要启动两个 dzen2，一个接受 xmoand 的输出，一个接受 conky 的输出，
需要注意的是 dzen2 &lt;em&gt;不支持&lt;/em&gt; 按屏幕的百分比显示，
我在网上找到了&lt;a class="reference external" href="https://github.com/ervandew/dotfiles/blob/master/bin/dzen2"&gt;这个脚本&lt;/a&gt;，
可以从 xrandr 获取屏幕宽度，按指定的比例算出宽度来，我针对我的需要做了一点修改：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/usr/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;# Author: ervandew&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c1"&gt;# Source: https://github.com/ervandew/dotfiles/blob/master/bin/dzen2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="c1"&gt;# Wrapper around dzen2 that allows width and x to be defined as a screen&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="c1"&gt;# percentage.  The percentage width is define via the new &amp;#39;-wp&amp;#39; arg and&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="c1"&gt;# percentage x as -xp, both of which must be supplied before any other dzen&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="c1"&gt;# arguments.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="c1"&gt;#   $ dzen2 -wp 30 -xp 60 ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="c1"&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="nv"&gt;external&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^\(VGA\|DVI\|DP\|HDMI\)-\?[0-9]\+&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="nv"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^\(eDP\|LVDS\)-\?[0-9]\+&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;connected \(primary \)\?\([0-9]\+\)x.*&lt;/span&gt;$&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="c1"&gt;# get internal monitor&amp;#39;s width only&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="c1"&gt;# 仅获取笔记本屏幕的宽度&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$internal&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/&lt;/span&gt;&lt;span class="nv"&gt;$internal&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;/\3/&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;# width=$(xrandr 2&amp;gt; /dev/null | grep &amp;quot;$external $pattern&amp;quot; | sed &amp;quot;s/$external $pattern/\3/&amp;quot;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-wp&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt; -w `expr &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;expr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; / 100`&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;elif&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-xp&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt; -x `expr &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;expr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; / 100`&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;shift&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;shift&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="nv"&gt;FG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#aaaaaa&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="nv"&gt;BG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#1a1a1a&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="nv"&gt;FONT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-*-terminus-*-r-normal-*-*-110-*-*-*-*-iso8859-*&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dzen2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-bg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-fg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-fn&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FONT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;button2=;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-xs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;xmonad.hs 那边要这样写：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;myLogHook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xmproc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dynamicLogWithPP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defaultPP&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppCurrent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#87ceff&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppVisible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#aaaaaa&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppHidden&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#aaaaaa&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppUrgent&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#ff0000&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppWsSep&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppSep&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;  |  &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppLayout&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#87ceff&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Tall&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;^i(&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myBitmapsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tall.xbm)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mirror Tall&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;^i(&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myBitmapsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/mtall.xbm)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Full&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;^i(&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myBitmapsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/full.xbm)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Simple Float&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppTitle&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;white&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1a1a1a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dzenEscape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shorten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppOutput&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hPutStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xmproc&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;-- NB: dzen2 DOSEN&amp;#39;T support the option `-wp` and `-wx` (p =&amp;gt; percentage),&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="c1"&gt;-- I use a shell wrapper from https://github.com/ervandew/dotfiles/blob/master/bin/dzen2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="c1"&gt;-- {bg,fg}color and font are also set by this wrapper&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="c1"&gt;--&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="nf"&gt;myBitmapsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/la/.xmonad/dzen2&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="nf"&gt;myDzen2Wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/la/.xmonad/start_dzen2.sh&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="nf"&gt;myXmonadBar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myDzen2Wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; -wp 70 -h 18 -x 0 -y 0 -ta l&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="nf"&gt;myStatusBar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;conky | &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myDzen2Wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; -xp 70 -wp 20 -h 18 -y 0 -ta r&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xmproc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;spawnPipe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myXmonadBar&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myStatusBar&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xmonad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defaultConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="c1"&gt;--  ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;启用了 xmonad 的 smartBorder，这样在不需要边框的时候就不会有讨厌的边框了&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;XMonad.Layout.NoBorders&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;myLayoutHook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avoidStruts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layoutHook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defaultConfig&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xmonad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defaultConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="c1"&gt;--  ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;layoutHook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;smartBorders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myLayoutHook&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="c1"&gt;--  ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;受上面那个 dzen2 wrapper 启发，在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.xinitrc&lt;/span&gt;&lt;/code&gt; 里面增加了判断外接屏幕是否存在的脚本：&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;# Dual screens auto dectection&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nv"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^\(\(eDP\|LVDS\)-\?[0-9]\+\)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nv"&gt;external&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^\(\(VGA\|DVI\|DP\|HDMI\)-\?[0-9]\+\)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;connected \(primary \)\?\([0-9]\+\)x.*&lt;/span&gt;$&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nv"&gt;inter_scr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$internal&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/&lt;/span&gt;&lt;span class="nv"&gt;$internal&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;/\1/&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nv"&gt;exter_scr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$external&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/&lt;/span&gt;&lt;span class="nv"&gt;$external&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;/\1/&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="c1"&gt;# 笔记本屏幕为主显示器&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$exter_scr&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;exter_scr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--auto&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;inter_scr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--primary&lt;span class="w"&gt; &lt;/span&gt;--auto&lt;span class="w"&gt; &lt;/span&gt;--right-of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;exter_scr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;使用 pacman 来管理 vim 插件（反正肥猫打包了一切&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;all plugins are managed by pacman&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;community/vim-nerdtree&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;community/powerline-vim&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;community/vim-doxygentoolkit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;archlinuxcn/vim-fcitx&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;archlinuxcn/vim-youcompleteme-git&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后再贴一张图：&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/thinkpad-l450-screenshot.png" /&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/thinkpad-l450.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="ArchLinux" label="Arch Linux"/>
    <category term="设备" label="设备"/>
    <published>2016-03-11T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/get-teeworlds-server-information.html</id>
    <title>获取 teeworlds 服务器信息</title>
    <updated>2016-02-12T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="teeworlds"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;前阵子凤凰卷给 ArchliunxCN 社区开了个 teeworlds 游戏服务器
（什么是 &lt;a class="reference external" href="https://zh.wikipedia.org/wiki/Teeworlds"&gt;teeworlds&lt;/a&gt;？），
然而大家总是凑不到一块玩，于是就琢磨能不能做个查询游戏信息的 IRC bot，
有人进服务器是给个提示，bot 不难做，倒是对如何获取游戏信息没什么思路。&lt;/p&gt;
&lt;p&gt;一开始智商下线地想要在每个客户端套一个脚本，然后由脚本向 bot 报告自己的信息……
于是搞出来这么个东西：&lt;a class="reference external" href="https://github.com/SilverRainZ/teebot-nogood"&gt;teebot-nogood&lt;/a&gt;，
但是在每个人的客户端上都运行这个脚本一点都不现实，
最后我在 teeworlds 的论坛找到了&lt;a class="reference external" href="https://www.teeworlds.com/forum/viewtopic.php?id=7737"&gt;这个帖子&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;帖子里给出了几个 PHP 脚本，可以用来扫描 teeworlds 的 master 服务器信息和单个游戏服务器信息，
分别适用与 0.5 和 0.6 版本的服务端。我不懂 PHP，还好代码很简单，对于单个游戏服务信息的获取，
只要向服务器发送字节串 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xffxffxffxffxffxffxffxffxffxffx67x69x65x33x05&lt;/span&gt;&lt;/code&gt;，
服务器就会返回返回包含游戏的数据，我对照着&lt;a class="reference external" href="http://pastebin.com/W0qjxzvr"&gt;其中的一个脚本&lt;/a&gt;
写了个 Python 版本：&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;socket&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;121.199.73.170&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8303&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x05&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recvfrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NULL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[teeserver]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;recv data:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="n"&gt;map_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="n"&gt;cur_player_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="n"&gt;max_player_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="n"&gt;players&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cur_player_num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;    &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;    &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;            &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;            &lt;span class="s1"&gt;&amp;#39;clan&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;            &lt;span class="s1"&gt;&amp;#39;region&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;region_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;            &lt;span class="s1"&gt;&amp;#39;score&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;            &lt;span class="s1"&gt;&amp;#39;stat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;spectator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;player&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;])],&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;    &lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;从上面的代码就可以看出数据的形式了，没有什么好说的地方，仅仅是想用中文记录下来，
或许以后有人会需要吧。&lt;/p&gt;
&lt;p&gt;上面的代码被我整合进了 &lt;a class="reference external" href="https://github.com/SilverRainZ/teebot"&gt;SilverRainZ/teebot&lt;/a&gt; 里，
如果你在 #archlinux-cn 频道的话，输入 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.tee&lt;/span&gt;&lt;/code&gt; 就能知道现在社区的游戏服务器里有几个人啦。&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/get-teeworlds-server-information.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Teeworlds" label="Teeworlds"/>
    <published>2016-02-12T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/overthewire-leviathan.html</id>
    <title>OverTheWire Leviathan</title>
    <updated>2016-01-01T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="overthewire-leviathan"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;地址: &lt;a class="reference external" href="http://overthewire.org/wargames/leviathan/"&gt;OverTheWire: Leviathan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;说实话题目不难，可是从开始做题到做完的时间跨度却有一个多月，人家 rr 却做了一会儿就搞定了，我都在干嘛呢？&lt;/p&gt;
&lt;p&gt;完整的笔记在 &lt;a class="reference external" href="https://github.com/SilverRainZ/no-silver-bullet/blob/master/ctf/wargame-leviathan/wargame-leviathan.md"&gt;这里&lt;/a&gt;，
其中有点意思的是 leviathan3，所以特地摘抄出来：&lt;/p&gt;
&lt;p&gt;登入机器后发现家目录有个带 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;suid&lt;/span&gt;&lt;/code&gt; 权限的可执行文件 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;printfile&lt;/span&gt;&lt;/code&gt;，属主是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;leviathan3&lt;/span&gt;&lt;/code&gt;，用户组是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;leviathan2&lt;/span&gt;&lt;/code&gt;，带 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;suid&lt;/span&gt;&lt;/code&gt; 的程序执行时可以获得和 owner/grouper 相同的权限（euid/egid）。&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;leviathan2@melinda:~$ ll printfile
&lt;/span&gt;&lt;span data-line="2"&gt;-r-sr-x--- 1 leviathan3 leviathan2 7498 Nov 14  2014 printfile*
&lt;/span&gt;&lt;span data-line="3"&gt;leviathan2@melinda:~$ ./printfile
&lt;/span&gt;&lt;span data-line="4"&gt;*** File Printer ***
&lt;/span&gt;&lt;span data-line="5"&gt;Usage: ./printfile filename
&lt;/span&gt;&lt;span data-line="6"&gt;leviathan2@melinda:~$ ./printfile /etc/leviathan_pass/leviathan3
&lt;/span&gt;&lt;span data-line="7"&gt;You cant have that file...
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;从字面意思上看，这个程序接受一个文件路径然后把文件的内容显示出来，但是要求它打印 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/etc/leviathan_pass/leviathan3&lt;/span&gt;&lt;/code&gt; 却提示 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;You&lt;/span&gt; &lt;span class="pre"&gt;cant&lt;/span&gt; &lt;span class="pre"&gt;have&lt;/span&gt; &lt;span class="pre"&gt;that&lt;/span&gt; &lt;span class="pre"&gt;file...&lt;/span&gt;&lt;/code&gt;，上 gdb 分析看看。&lt;/p&gt;
&lt;p&gt;以下是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;diaasm&lt;/span&gt; &lt;span class="pre"&gt;main&lt;/span&gt;&lt;/code&gt; 的结果，假设执行了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;r&lt;/span&gt; &lt;span class="pre"&gt;filename&lt;/span&gt;&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-objdump notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;0x0804852d &amp;lt;+0&amp;gt;:     push   %ebp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="x"&gt;0x0804852e &amp;lt;+1&amp;gt;:     mov    %esp,%ebp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="x"&gt;0x08048530 &amp;lt;+3&amp;gt;:     and    $0xfffffff0,%esp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="x"&gt;0x08048533 &amp;lt;+6&amp;gt;:     sub    $0x230,%esp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="x"&gt;0x08048539 &amp;lt;+12&amp;gt;:    mov    0xc(%ebp),%eax           ; argv 参数地址&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="x"&gt;0x0804853c &amp;lt;+15&amp;gt;:    mov    %eax,0x1c(%esp)          ; argv 保存到 [esp + 0x1c]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="x"&gt;0x08048540 &amp;lt;+19&amp;gt;:    mov    %gs:0x14,%eax            ; Thread-Local Storage, 不知道是什么&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="x"&gt;0x08048546 &amp;lt;+25&amp;gt;:    mov    %eax,0x22c(%esp)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="x"&gt;0x0804854d &amp;lt;+32&amp;gt;:    xor    %eax,%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="x"&gt;0x0804854f &amp;lt;+34&amp;gt;:    cmpl   $0x1,0x8(%ebp)           ; argc 和 1 比较，此处 argc 应该为 2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="x"&gt;0x08048553 &amp;lt;+38&amp;gt;:    jg     0x804857e &amp;lt;main+81&amp;gt;      ; / argc &amp;gt; 1 则跳&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="x"&gt;0x08048555 &amp;lt;+40&amp;gt;:    movl   $0x8048690,(%esp)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="x"&gt;0x0804855c &amp;lt;+47&amp;gt;:    call   0x80483d0 &amp;lt;puts@plt&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="x"&gt;0x08048561 &amp;lt;+52&amp;gt;:    mov    0x1c(%esp),%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="x"&gt;0x08048565 &amp;lt;+56&amp;gt;:    mov    (%eax),%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="x"&gt;0x08048567 &amp;lt;+58&amp;gt;:    mov    %eax,0x4(%esp)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="x"&gt;0x0804856b &amp;lt;+62&amp;gt;:    movl   $0x80486a5,(%esp)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="x"&gt;0x08048572 &amp;lt;+69&amp;gt;:    call   0x80483b0 &amp;lt;printf@plt&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="x"&gt;0x08048577 &amp;lt;+74&amp;gt;:    mov    $0xffffffff,%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="x"&gt;0x0804857c &amp;lt;+79&amp;gt;:    jmp    0x80485e8 &amp;lt;main+187&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="x"&gt;; -&amp;gt; 来自 0x08048553 &amp;lt;+38&amp;gt; 的跳转，以上代码不必分析了&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="x"&gt;0x0804857e &amp;lt;+81&amp;gt;:    mov    0x1c(%esp),%eax          ; 取出储存的 argv&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="x"&gt;0x08048582 &amp;lt;+85&amp;gt;:    add    $0x4,%eax                ; 移动到 argv 的第一个参数（从 0 计数）&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="x"&gt;0x08048585 &amp;lt;+88&amp;gt;:    mov    (%eax),%eax              ; 取出 argv[1] 的值，指向字符串 ‘filename’&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="x"&gt;0x08048587 &amp;lt;+90&amp;gt;:    movl   $0x4,0x4(%esp)           ; 参数二：int amode&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="x"&gt;0x0804858f &amp;lt;+98&amp;gt;:    mov    %eax,(%esp)              ; | argv[1] 作参数一： char *path&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="x"&gt;0x08048592 &amp;lt;+101&amp;gt;:   call   0x8048420 &amp;lt;access@plt&amp;gt;   ; / access(argv[1], 4)，成功返回 0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="x"&gt;0x08048597 &amp;lt;+106&amp;gt;:   test   %eax,%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="x"&gt;0x08048599 &amp;lt;+108&amp;gt;:   je     0x80485ae &amp;lt;main+129&amp;gt;     ; 跳&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="x"&gt;0x0804859b &amp;lt;+110&amp;gt;:   movl   $0x80486b9,(%esp)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="x"&gt;0x080485a2 &amp;lt;+117&amp;gt;:   call   0x80483d0 &amp;lt;puts@plt&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="x"&gt;0x080485a7 &amp;lt;+122&amp;gt;:   mov    $0x1,%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="x"&gt;0x080485ac &amp;lt;+127&amp;gt;:   jmp    0x80485e8 &amp;lt;main+187&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="x"&gt;; -&amp;gt; 来自 0x08048599 &amp;lt;+108&amp;gt; 的跳转&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="x"&gt;0x080485ae &amp;lt;+129&amp;gt;:   mov    0x1c(%esp),%eax          ; \&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="x"&gt;0x080485b2 &amp;lt;+133&amp;gt;:   add    $0x4,%eax                ; | 取得 argv[1]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="39"&gt;&lt;span class="x"&gt;0x080485b5 &amp;lt;+136&amp;gt;:   mov    (%eax),%eax              ; /&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="40"&gt;&lt;span class="x"&gt;0x080485b7 &amp;lt;+138&amp;gt;:   mov    %eax,0xc(%esp)           ; ...: argv[1]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="41"&gt;&lt;span class="x"&gt;0x080485bb &amp;lt;+142&amp;gt;:   movl   $0x80486d4,0x8(%esp)     ; | char *format: string &amp;quot;/bin/cat %s&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="42"&gt;&lt;span class="x"&gt;0x080485c3 &amp;lt;+150&amp;gt;:   movl   $0x1ff,0x4(%esp)         ; | size_t size: 511&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="43"&gt;&lt;span class="x"&gt;0x080485cb &amp;lt;+158&amp;gt;:   lea    0x2c(%esp),%eax          ; |&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="44"&gt;&lt;span class="x"&gt;0x080485cf &amp;lt;+162&amp;gt;:   mov    %eax,(%esp)              ; | char *str&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="45"&gt;&lt;span class="x"&gt;0x080485d2 &amp;lt;+165&amp;gt;:   call   0x8048410 &amp;lt;snprintf@plt&amp;gt; ; / snprintf(str, 511, &amp;quot;/bin/cat %s&amp;quot;, argv[1]);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="46"&gt;&lt;span class="x"&gt;0x080485d7 &amp;lt;+170&amp;gt;:   lea    0x2c(%esp),%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="47"&gt;&lt;span class="x"&gt;0x080485db &amp;lt;+174&amp;gt;:   mov    %eax,(%esp)              ; \&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="48"&gt;&lt;span class="x"&gt;0x080485de &amp;lt;+177&amp;gt;:   call   0x80483e0 &amp;lt;system@plt&amp;gt;   ; / system(&amp;quot;/bin/cat filename&amp;quot;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="49"&gt;&lt;span class="x"&gt;0x080485e3 &amp;lt;+182&amp;gt;:   mov    $0x0,%eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="50"&gt;&lt;span class="x"&gt;0x080485e8 &amp;lt;+187&amp;gt;:   mov    0x22c(%esp),%edx&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="51"&gt;&lt;span class="x"&gt;0x080485ef &amp;lt;+194&amp;gt;:   xor    %gs:0x14,%edx&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="52"&gt;&lt;span class="x"&gt;0x080485f6 &amp;lt;+201&amp;gt;:   je     0x80485fd &amp;lt;main+208&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="53"&gt;&lt;span class="x"&gt;0x080485f8 &amp;lt;+203&amp;gt;:   call   0x80483c0 &amp;lt;__stack_chk_fail@plt&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="54"&gt;&lt;span class="x"&gt;0x080485fd &amp;lt;+208&amp;gt;:   leave&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="55"&gt;&lt;span class="x"&gt;0x080485fe &amp;lt;+209&amp;gt;:   ret&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看到程序接受一个文件路径，先检查对该文件的访问权限，然后执行 shell 命令 &amp;quot;/bin/cat filename&amp;quot;。&lt;/p&gt;
&lt;p&gt;问题出在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;access&lt;/span&gt;&lt;/code&gt; 函数， man 是这样说的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;The access() function shall check the file named by the pathname pointed to by the path argument for accessibility according to the bit pattern contained in amode, &lt;em&gt;using the real user ID in place of the effective user ID and the real group ID in place of the effective group ID.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;suid&lt;/span&gt;&lt;/code&gt; 权限改变的只是进程的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;euid&lt;/span&gt;&lt;/code&gt;，因此当你执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;./printfile&lt;/span&gt; &lt;span class="pre"&gt;/etc/leviathan_pass/leviathan3&lt;/span&gt;&lt;/code&gt; 的时候，access 函数总是失败的。&lt;/p&gt;
&lt;p&gt;但是用 gdb 改变程序的流程也是&lt;a class="reference external" href="http://unix.stackexchange.com/questions/15911/can-gdb-debug-suid-root-programs"&gt;*不可行*&lt;/a&gt;的，非 root 的 gdb 调试带 suid 权限的程序时，程序不会获得本来应该有的权限（否则 gdb 就可以任意地改变程序的行为了），即使绕过了 access 函数，你依然会得到一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Permission&lt;/span&gt; &lt;span class="pre"&gt;denied&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;到这里我就没辙了，只能看别人的 writeup 了：&lt;a class="reference external" href="https://rundata.wordpress.com/2013/03/27/overthewire-leviathan-wargame-solution-2/"&gt;OverTheWire Leviathan Wargame Solution 2&lt;/a&gt;，看完发现脑洞确实不够大。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Solution:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;access() 接受的是个字符串参数，而 cat 的参数却是由 shell 处理的，执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;./printfile&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;flag&lt;/span&gt; &lt;span class="pre"&gt;here&amp;quot;&lt;/span&gt;&lt;/code&gt;，对于 access 函数来说是执行了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;access(&amp;quot;flag&lt;/span&gt; &lt;span class="pre"&gt;here&amp;quot;,&lt;/span&gt; &lt;span class="pre"&gt;4)&lt;/span&gt;&lt;/code&gt;, 检查对 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;flag&lt;/span&gt; &lt;span class="pre"&gt;here&lt;/span&gt;&lt;/code&gt; 这个文件的访问权限，而对 cat 来说是这样的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;system(&amp;quot;cat&lt;/span&gt; &lt;span class="pre"&gt;flag&lt;/span&gt; &lt;span class="pre"&gt;here&amp;quot;)&lt;/span&gt;&lt;/code&gt;，因此可以利用这个区别来绕过 access 函数。&lt;/p&gt;
&lt;div class="highlight-shell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;leviathan2@melinda:/tmp$&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;slove
&lt;/span&gt;&lt;span data-line="2"&gt;leviathan2@melinda:/tmp$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;slove
&lt;/span&gt;&lt;span data-line="3"&gt;leviathan2@melinda:/tmp/slove$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;flag here&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# 带空格的文件名&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;leviathan2@melinda:/tmp/slove$&lt;span class="w"&gt; &lt;/span&gt;ln&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/etc/leviathan_pass/leviathan3&lt;span class="w"&gt; &lt;/span&gt;flag
&lt;/span&gt;&lt;span data-line="5"&gt;leviathan2@melinda:/tmp/slove$&lt;span class="w"&gt; &lt;/span&gt;ls
&lt;/span&gt;&lt;span data-line="6"&gt;flag&lt;span class="w"&gt;  &lt;/span&gt;flag&lt;span class="w"&gt; &lt;/span&gt;here
&lt;/span&gt;&lt;span data-line="7"&gt;leviathan2@melinda:/tmp/slove$&lt;span class="w"&gt; &lt;/span&gt;~/printfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;flag here&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# access 检测的是刚刚建立的新文件， cat 显示的则是 flag 和 here&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;Ahdiemoo1j
&lt;/span&gt;&lt;span data-line="9"&gt;/bin/cat:&lt;span class="w"&gt; &lt;/span&gt;here:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;另外发现了一个新工具 ltrace，能够跟踪库函数的调用，就不用像刚才那样分析整个程序了（后面的题目大多数是过一遍 ltrace 就行了）：&lt;/p&gt;
&lt;div class="highlight-shell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;leviathan2@melinda:~$&lt;span class="w"&gt; &lt;/span&gt;ltrace&lt;span class="w"&gt; &lt;/span&gt;~/printfile&lt;span class="w"&gt; &lt;/span&gt;/etc/leviathan_pass/leviathan2
&lt;/span&gt;&lt;span data-line="2"&gt;__libc_start_main&lt;span class="o"&gt;(&lt;/span&gt;0x804852d,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;0xffffd6f4,&lt;span class="w"&gt; &lt;/span&gt;0x8048600&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;unfinished&lt;span class="w"&gt; &lt;/span&gt;...&amp;gt;
&lt;/span&gt;&lt;span data-line="3"&gt;access&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc/leviathan_pass/leviathan2&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;snprintf&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/bin/cat /etc/leviathan_pass/lev&amp;quot;&lt;/span&gt;...,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;511&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/bin/cat %s&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc/leviathan_pass/leviathan2&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;39&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;system&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/bin/cat /etc/leviathan_pass/lev&amp;quot;&lt;/span&gt;...ougahZi8Ta
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;no&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;...&amp;gt;
&lt;/span&gt;&lt;span data-line="7"&gt;---&lt;span class="w"&gt; &lt;/span&gt;SIGCHLD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Child&lt;span class="w"&gt; &lt;/span&gt;exited&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;---
&lt;/span&gt;&lt;span data-line="8"&gt;&amp;lt;...&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;resumed&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                                                            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;+++&lt;span class="w"&gt; &lt;/span&gt;exited&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+++
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;元旦快乐，希望新的一年不要那么痛苦了。&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/overthewire-leviathan.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="CTF" label="CTF"/>
    <published>2016-01-01T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/gen-graph-from-c-code.html</id>
    <title>从 C 源码生成 函数/模块 调用图</title>
    <updated>2015-12-25T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="c"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;前天是操作系统课程设计的截止日期，这意味这 &lt;a class="reference external" href="https://github.com/SilverRainZ/OS67"&gt;OS67 这个坑&lt;/a&gt;
已经告一段落了，接下来的事情是写报告，不过鉴于 OS 的老师这一学期都没出现过，
报告应该可以随便水过去，据说连答辩都可以省掉了……&lt;/p&gt;
&lt;p&gt;前面说的都是废话，报告里要求画出函数调用图，于是就打算直接用软件生成好了。&lt;/p&gt;
&lt;p&gt;用到的软件有 graphviz，egypt&lt;sup&gt;AUR&lt;/sup&gt;，cinclude2dot&lt;sup&gt;AUR&lt;/sup&gt;，
&lt;a class="any any-friend reference internal" href="about/friends.html#friend-farseerfc" title="friend farseerfc"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 推荐了 &lt;a class="reference external" href="http://makepp.sourceforge.net/"&gt;makepp&lt;/a&gt;，
然而 AUR 里面没有就作罢了。&lt;/p&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;生成函数调用图&lt;/h2&gt;
&lt;p&gt;安装 egypt 直接 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;yaourt&lt;/span&gt; &lt;span class="pre"&gt;-S&lt;/span&gt; &lt;span class="pre"&gt;egypt&lt;/span&gt;&lt;/code&gt; 即可，
之后在 makefile 里面的 CFLAG 里面增加一句 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-fdump-rtl-expand&lt;/span&gt;&lt;/code&gt;，
再 make 一次，gcc 会在 bulid 目录下生成 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.expand&lt;/span&gt;&lt;/code&gt; 文件，
这是 egypt 生成 call graph 所需要的信息。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;我这里生成的文件的后缀都是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.192r.expand&lt;/span&gt;&lt;/code&gt;，并不知道是什么意思……&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;之后执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;egypt&lt;/span&gt; &lt;span class="pre"&gt;*.expand&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;main.dot&lt;/span&gt;&lt;/code&gt;
就能生成代表整个项目里所有的 C 函数的调用关系的 dot 文件了。&lt;/p&gt;
&lt;p&gt;dot 文件大概长这样，每一行代表连接两个顶点的边
用 Graphviz 的 dot 命令可以从 dot 文件生成 png。&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;digraph callgraph {
&lt;/span&gt;&lt;span data-line="2"&gt;&amp;quot;move_cur&amp;quot; -&amp;gt; &amp;quot;outb&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="3"&gt;&amp;quot;cls&amp;quot; -&amp;gt; &amp;quot;move_cur&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="4"&gt;&amp;quot;iunlock&amp;quot; -&amp;gt; &amp;quot;panic&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="5"&gt;&amp;quot;puts&amp;quot; -&amp;gt; &amp;quot;putchar&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="6"&gt;&amp;quot;puts&amp;quot; -&amp;gt; &amp;quot;_puts&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="7"&gt;&amp;quot;sys_sleep&amp;quot; -&amp;gt; &amp;quot;argint&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="8"&gt;&amp;quot;sys_sleep&amp;quot; -&amp;gt; &amp;quot;sleep&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="9"&gt;&amp;quot;sys_unlink&amp;quot; -&amp;gt; &amp;quot;iupdate&amp;quot; [style=solid];
&lt;/span&gt;&lt;span data-line="10"&gt;    ...
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dot&lt;/span&gt; &lt;span class="pre"&gt;main.dot&lt;/span&gt; &lt;span class="pre"&gt;-Tpng&lt;/span&gt; &lt;span class="pre"&gt;-o&lt;/span&gt; &lt;span class="pre"&gt;main.png&lt;/span&gt;&lt;/code&gt;，于是从整个 OS67 生成了这么一张可怕的图片：&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/os67-func-call-graph.png" /&gt;
&lt;p&gt;这么大的图片用在报告里显然是不行的，不过函数间的调用逻辑也就那样了，
没法做什么简化，所以对于整个项目我只生成了后面的模块调用图。&lt;/p&gt;
&lt;p&gt;既然整个项目的图太大了，那就生成模块内部的调用图好了，OS67 的项目结构长这样，
模块和文件夹基本上是一一对应的：&lt;/p&gt;
&lt;div class="highlight-console notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;tree&lt;span class="w"&gt; &lt;/span&gt;-d
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="go"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="go"&gt;├── bin&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="go"&gt;│   └── rootfs&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="go"&gt;├── boot    # bootloader&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="go"&gt;├── dev     # 设备文件&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="go"&gt;├── drv     # 驱动程序&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="go"&gt;├── fs      # 文件系统&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="go"&gt;├── inc     # 头文件&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="go"&gt;├── kern    # 保护模式相关代码&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="go"&gt;├── libs    # 库文件&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="go"&gt;├── lst&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="go"&gt;├── mm      # 内存管理&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="go"&gt;├── notes&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="go"&gt;├── proc    # 进程管理&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="go"&gt;├── script  # 各种配置文件和链接脚本&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="go"&gt;└── usr     # 用户例程&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;需要生成调用图的模块有 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dev&lt;/span&gt; &lt;span class="pre"&gt;drv&lt;/span&gt; &lt;span class="pre"&gt;fs&lt;/span&gt; &lt;span class="pre"&gt;kern&lt;/span&gt; &lt;span class="pre"&gt;libs&lt;/span&gt; &lt;span class="pre"&gt;mm&lt;/span&gt; &lt;span class="pre"&gt;proc&lt;/span&gt;&lt;/code&gt;，来写个小脚本自动生成好了：&lt;/p&gt;
&lt;div class="highlight-sh notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/usr/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nv"&gt;mods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dev drv fs kern libs mm proc&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mods&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\.c&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/\.c/.c.192r.expand/g&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bin
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;egypt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;.dot
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;dot&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;.dot&lt;span class="w"&gt; &lt;/span&gt;-Tpng&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;../&lt;span class="nv"&gt;$arg&lt;/span&gt;.png
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;..
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;生成出来的图片除了 fs 模块比较大之外其他都还行，下面是 kern 模块的 call graph
（用 kolourpaint 做了点调整）：&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/os67-kern-func-call-graph.png" /&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;注意：这里没有处理 boot 模块和 usr 模块，因为 boot 里面都是汇编程序，
而 usr 里面的用户程序都有 main 函数会导致冲突而画出奇怪的图，所以就没有包含了。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;另外 graphviz 还支持把 dot 文件转成 dia 格式，所以如果对各个顶点的位置不满意的话，我们可以用 Dia 来调整。&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;刚说完就被打脸了，graphviz 的 dia 输出支持在 2.26.0 的时候被移除了。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;生成模块调用图&lt;/h2&gt;
&lt;p&gt;接下来来生成模块间的调用图吧，
我在网上找到一个根据 #include 生成文件间调用关系的 dot 的 prel 脚本：
&lt;a class="reference external" href="https://www.flourish.org/cinclude2dot/"&gt;flourish.org/cinclude2dot/&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;AUR 里面没有所以顺手给打了一个包：
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cinclude2dot:sup:`AUR&lt;/span&gt;&lt;/code&gt; &amp;lt;&lt;a class="reference external" href="https://aur.archlinux.org/packages/cinclude2dot/"&gt;https://aur.archlinux.org/packages/cinclude2dot/&lt;/a&gt;&amp;gt;`_，
所以现在也可以直接用 yaourt 装 cinclude2dot 了。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cinclude2dot&lt;/span&gt; &lt;span class="pre"&gt;--include&lt;/span&gt; &lt;span class="pre"&gt;inc&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;main.dot&lt;/span&gt;&lt;/code&gt; 会在当前目录递归地找 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.c&lt;/span&gt;&lt;/code&gt; 文件，
然后在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;inc&lt;/span&gt;&lt;/code&gt; 目录找对应的头文件，生成 c 文件到头文件包含关系的 dot 文件。
如果启用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;--merge&lt;/span&gt; &lt;span class="pre"&gt;module&lt;/span&gt;&lt;/code&gt; 的话，会把 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xxx.c&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xxx.h&lt;/span&gt;&lt;/code&gt; 合并为一个模块 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xxx&lt;/span&gt;&lt;/code&gt;，
然而这样生成的图片还是太大了点。&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/os67-mod-include-graph.png" /&gt;
&lt;p&gt;cinclude2dot 还提供了一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;--merge&lt;/span&gt; &lt;span class="pre"&gt;directory&lt;/span&gt;&lt;/code&gt; 选项，把相同目录的文件合并为一个模块，
这正是我想要的功能，然而这样生成的图过分简单，
所有的目录都指向了存放头文件的目录 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;inc&lt;/span&gt;&lt;/code&gt;。试了一下 directory 和 module 选项也不能一起用，
果然还是得自己在 dot 文件上改一改。&lt;/p&gt;
&lt;p&gt;执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cinclude2dot&lt;/span&gt; &lt;span class="pre"&gt;--include&lt;/span&gt; &lt;span class="pre"&gt;inc&lt;/span&gt; &lt;span class="pre"&gt;--merge&lt;/span&gt; &lt;span class="pre"&gt;module&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;$dotfile&lt;/span&gt;&lt;/code&gt;，得到各个「文件」间的调用关系。&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;digraph &amp;quot;source tree&amp;quot; {
&lt;/span&gt;&lt;span data-line="2"&gt;    &amp;quot;ls&amp;quot; -&amp;gt; &amp;quot;usys&amp;quot;
&lt;/span&gt;&lt;span data-line="3"&gt;    &amp;quot;tty&amp;quot; -&amp;gt; &amp;quot;printk&amp;quot;
&lt;/span&gt;&lt;span data-line="4"&gt;    &amp;quot;ide&amp;quot; -&amp;gt; &amp;quot;isr&amp;quot;
&lt;/span&gt;&lt;span data-line="5"&gt;    &amp;quot;dev&amp;quot; -&amp;gt; &amp;quot;tty&amp;quot;
&lt;/span&gt;&lt;span data-line="6"&gt;    &amp;quot;isr&amp;quot; -&amp;gt; &amp;quot;vmm&amp;quot;
&lt;/span&gt;&lt;span data-line="7"&gt;    &amp;quot;cinit&amp;quot; -&amp;gt; &amp;quot;uio&amp;quot;
&lt;/span&gt;&lt;span data-line="8"&gt;    &amp;quot;p2i&amp;quot; -&amp;gt; &amp;quot;type&amp;quot;
&lt;/span&gt;&lt;span data-line="9"&gt;    &amp;quot;proc&amp;quot; -&amp;gt; &amp;quot;isr&amp;quot;
&lt;/span&gt;&lt;span data-line="10"&gt;    &amp;quot;fstest&amp;quot; -&amp;gt; &amp;quot;string&amp;quot;
&lt;/span&gt;&lt;span data-line="11"&gt;    &amp;quot;timer&amp;quot; -&amp;gt; &amp;quot;isr&amp;quot;
&lt;/span&gt;&lt;span data-line="12"&gt;    ...
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如果 dev/tty.c 包含了 inc/printk.h，说明它调用了 libs/printk.c 里的函数，
那就有关系 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;tty&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;printk&amp;quot;&lt;/span&gt;&lt;/code&gt;，
那可以考虑把文件名替换为该文件所在的目录名，那关系就变成了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;dev&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;libs&amp;quot;&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这样替换要注意的是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;不能将头文件目录当成一个模块，如 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;tty&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;printk&amp;quot;&lt;/span&gt;&lt;/code&gt; 的关系的右边本来就是一个头文件，
在这里它应当属于 libs 模块而不属于 inc，
如果强行加入 inc 的话结果就和上面用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;--merge&lt;/span&gt; &lt;span class="pre"&gt;directory&lt;/span&gt;&lt;/code&gt; 的效果差不多了：
每个顶点会都指向 inc&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;排除 inc 后，要注意的是有些只包含宏定义的头文件并没有对应的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.c&lt;/span&gt;&lt;/code&gt; 文件，
比如上面的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;p2i&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;/code&gt; 存在 inc/type.h ，但是并没有 type.c 这么一个文件，
那么这一行应当删除掉&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;将文件名替换成目录名后会出现重复的项目，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;ide&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;printk&amp;quot;&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;vga&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;printk&amp;quot;&lt;/span&gt;&lt;/code&gt;
替换后的结果都是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;drv&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;libs&amp;quot;&lt;/span&gt;&lt;/code&gt;，需要去重&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;把这些事情交给脚本吧，从每个要统计的模块（目录）里面取得文件列表，
把文件名替换为目录名，去除单独的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.h&lt;/span&gt;&lt;/code&gt; 文件对应的行，去除重复行。&lt;/p&gt;
&lt;div class="highlight-sh notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/usr/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nv"&gt;mods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kern drv proc mm usr dev fs libs&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nv"&gt;dotfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;main.dot
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;cinclude2dot&lt;span class="w"&gt; &lt;/span&gt;--include&lt;span class="w"&gt; &lt;/span&gt;inc&lt;span class="w"&gt; &lt;/span&gt;--merge&lt;span class="w"&gt; &lt;/span&gt;module&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mods&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;/\&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;/g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;inc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;/d&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; !x[$0]++&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;tmpfile
&lt;/span&gt;&lt;span data-line="16"&gt;mv&lt;span class="w"&gt; &lt;/span&gt;tmpfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;dot&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dotfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-Tpng&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dotfile&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;.png
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后我们得到了一张还算不错的， OS67 的模块调用关系图：&lt;/p&gt;
&lt;img alt="" src="https://silverrainz.me/_images/os67-mod-include-graph-good.png" /&gt;
&lt;p&gt;好困睡觉。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/gen-graph-from-c-code.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="C" label="C"/>
    <published>2015-12-25T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/2015-huashangctf-re300.html</id>
    <title>2015 华山杯 CTF Reverse 300</title>
    <updated>2015-11-02T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="ctf-reverse-300"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;程序在此： &lt;a class="reference external" href="http://jianguoyun.com/p/Dbz27p8QtNrvBRiq2w4"&gt;toetrix-crackme.exe&lt;/a&gt;， VC++ 6.0 编写，无壳， CLI 程序。&lt;/p&gt;
&lt;p&gt;这题本来我是一点都不会的，幸得尖刀某大牛指点思路，之后回头看反编译的代码
总算是摸清楚了程序的流程。因为这种复杂度的题目之前没有做出来过，特此记录。&lt;/p&gt;
&lt;p&gt;程序很像一个推箱子游戏，在一个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;9*9&lt;/span&gt;&lt;/code&gt; 的二维地图中有三种元素： 0，1，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;10&lt;/span&gt; &lt;span class="pre"&gt;*&lt;/span&gt; &lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt;&lt;/code&gt;
分别代表空气，障碍和箱子，你需要做的就是将所有的箱子推出地图。&lt;/p&gt;
&lt;p&gt;程序储存的地图如下：&lt;/p&gt;
&lt;div class="highlight-c-objdump notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;Ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;Ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;Eh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00407030&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;转化成十进制：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看到每个箱子都是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;X2&lt;/span&gt;&lt;/code&gt; 形式的数字。&lt;/p&gt;
&lt;p&gt;用 IDA 分析整理得到 main 函数代码如下：&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;__cdecl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;envp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// esi@1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// bl@2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// eax@2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// eax@13&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// [sp+8h] [bp-30h]@2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// [sp+Ch] [bp-2Ch]@2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// [sp+10h] [bp-28h]@1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// [sp+36h] [bp-2h]@1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aInputYourSn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;v10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;direct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;find_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;// 遍历数组 返回的 x y 是箱子坐标&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;direct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// &amp;#39;1&amp;#39; 左&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;go_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// &amp;#39;2&amp;#39; 右&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;go_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// &amp;#39;3&amp;#39; 上&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;go_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;direct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;goto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LABEL_12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="39"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;go_down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;// &amp;#39;4&amp;#39; 下&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="40"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="41"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="42"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="43"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="44"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="45"&gt;&lt;span class="nl"&gt;LABEL_12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="46"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;check_no_start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="47"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="48"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aBDBuzeBuDGoodJ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// ∑(っ °Д °;)っ  good job!&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="49"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="50"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="51"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="52"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="53"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aIsbuzebuIsjrII&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// (╯°Д°)╯︵ ┻━┻  try again!&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="54"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="55"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="56"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="57"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;程序接受的输入以两个十进制位位为一组，
第一位 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;start&lt;/span&gt;&lt;/code&gt; 来指定一个箱子： 地图中值为（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;10&lt;/span&gt; &lt;span class="pre"&gt;*&lt;/span&gt; &lt;span class="pre"&gt;start&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt;&lt;/code&gt;）的元素
（在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;find_start&lt;/span&gt;&lt;/code&gt; 函数中处理，返回 x，y 为箱子的坐标）；
第二位 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;direct&lt;/span&gt;&lt;/code&gt; 用来指定推箱子的方向，&lt;em&gt;字符&lt;/em&gt; 1 2 3 4 分别代表方向左右上下
（由 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;go_xx&lt;/span&gt;&lt;/code&gt; 函数处理）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;比如序列 2321 就是把值为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;2*10&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;22&lt;/span&gt;&lt;/code&gt; 的箱子往上 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;3&lt;/span&gt;&lt;/code&gt; 移动， 再把该箱子往左 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;1&lt;/span&gt;&lt;/code&gt; 移动。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;看一下 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;find_start&lt;/span&gt;&lt;/code&gt; 函数：&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;__cdecl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;find_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ecx@3&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// eax@5&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* *(&amp;amp;map + 9 * (*e_y) + *e_x)  -&amp;gt;  map[y][x] */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;函数遍历整个二维数组 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;，如果在 map 中发现等于 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;10&lt;/span&gt; &lt;span class="pre"&gt;*&lt;/span&gt; &lt;span class="pre"&gt;start&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt;&lt;/code&gt; 的数字就 return
此时 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;e_x&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;e_y&lt;/span&gt;&lt;/code&gt; 中便是该点坐标。&lt;/p&gt;
&lt;p&gt;接下来看 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;go_left&lt;/span&gt;&lt;/code&gt; 函数：&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kr"&gt;__cdecl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// eax@1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;// 遇到非 0 点&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;// 边缘检测&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xchg_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 交换本次起点和终点的值，如果到达边缘，交换的就是同一个点。&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;该函数接受箱子的坐标，然后往坐标的左边走（&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;0&lt;/span&gt;&lt;/code&gt;），
如果遇到一个非 0 点，即跳出循环。&lt;/p&gt;
&lt;p&gt;如果 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;i&lt;/span&gt; &lt;span class="pre"&gt;==&lt;/span&gt; &lt;span class="pre"&gt;-1&lt;/span&gt;&lt;/code&gt; 说明从该箱子左边到边界都是 0，箱子可以移出地图了，
于是把该箱子坐标处的值标记为 1（变成障碍了，便于接下来交换）。&lt;/p&gt;
&lt;p&gt;接下来函数把箱子的坐标 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;(x,&lt;/span&gt; &lt;span class="pre"&gt;y)&lt;/span&gt;&lt;/code&gt; 和 移动终点的坐标 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;(i+1,&lt;/span&gt; &lt;span class="pre"&gt;y)&lt;/span&gt;&lt;/code&gt; 传给函数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xchg_point&lt;/span&gt;&lt;/code&gt;，
函数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;xchg_point&lt;/span&gt;&lt;/code&gt; 比较简单，仅仅是交换两个点的值。&lt;/p&gt;
&lt;p&gt;这样就完成了一次左移，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;go_right&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;go_up&lt;/span&gt;&lt;/code&gt; 等函数同理。&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;如果终点是边界的话，箱子的值会被置为 1，交换后的结果就是：箱子处变为 0，终点变为 1。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;处理完一次移动之后 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;step&lt;/span&gt;&lt;/code&gt; 自增 2，进行下一次移动，直到整个序列结束。
就执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;check_no_start&lt;/span&gt;&lt;/code&gt; 做最后的检查：&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;check_no_start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// esi@1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ecx@2&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_BYTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// 有一个箱子&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;end_of_map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;检查整个 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt; 中是否有形如 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;X2&lt;/span&gt;&lt;/code&gt; 的数字，即是否还有箱子存在，
如果没有的话，返回 1，这就是我们期望的结果。&lt;/p&gt;
&lt;p&gt;根据以上流程我们就可以手动算出一个能移除所有箱子的序列，&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;每个箱子移动可以不是连续的，可以先移动一个箱子到一个地方，再去移动另一个。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;移动箱子的顺序的和路径如下：&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="mi"&gt;62&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="mi"&gt;52&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;515351&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="mi"&gt;82&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8183&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="mi"&gt;72&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7372&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4441&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;141114&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3431&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4244&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;因此得到 key： &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;625153518183737244411411143431234244&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;附上分析时使用的 &lt;a class="reference external" href="http://jianguoyun.com/p/DaHaiScQtNrvBRjo2w4"&gt;idb 数据库&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/2015-huashangctf-re300.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="CTF" label="CTF"/>
    <published>2015-11-02T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/process-scheduler-1.html</id>
    <title>用户态进程的简单实现及调度(一)</title>
    <updated>2015-09-14T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;在写这篇的时候, 我发觉我很难在这短短一篇博文里把进程的实现将清楚,
并且可能存在一些理解的偏差, 因此本篇仅供参考, 更加准确的表述,
还请参考 &lt;a class="reference external" href="https://th0ar.gitbooks.io/xv6-chinese/content/content/chapter5.html"&gt;第五章 调度 | xv6 中文文档&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;自从上次完成了 &lt;a class="reference internal" href="blog/minix-v1-file-system.html"&gt;&lt;span class="doc"&gt;Minix v1 文件系统的实现&lt;/span&gt;&lt;/a&gt; 之后,
就开始看 xv6 中进程相关的代码, 并把它抄进 OS67 中, 到今天为止, 总算是完成地差不多了.&lt;/p&gt;
&lt;p&gt;进程的实现可能是 xv6 中耦合度最高的一部分, 在完成大部分的代码
(GDT,TSS 的设置, 上下文保存和切换, 虚拟内存映射, 系统调用)之前,
你很难让你的内核跑起来.&lt;/p&gt;
&lt;p&gt;xv6 已经尽量使用容易理解的方式来书写这些代码了, 不过有些地方仍然比较晦涩(对我来说).
希望再这篇文章里能稍微梳理一下.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;注意: OS67 并不打算支持多核 CPU, 这极大地降低了实现进程的难度,
不需要考虑由于多核导致的进程间的竞争和同步, 因此 xv6 中关于锁的代码都可以忽略.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;特权级转换&lt;/h2&gt;
&lt;p&gt;几个关于特权级的概念:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;intel 8086 的特权级分为 0 1 2 3 四级, 这里只使用 0 和 3&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DPL: Descriptor Privilege 描述符特权级, 储存在 GDT 或 IDT 描述符中&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CPL: Current Privilege 当前特权级, 储存在 cs 寄存器的低二位&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RPL: Request Privilege 请求特权级, 请求访问的段的描述符的特权级&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="gdt"&gt;
&lt;h2&gt;GDT&lt;/h2&gt;
&lt;p&gt;这里使用的用户态的特权级为 3, 因此用户态的程序, 其所在的数据段代码段的 DPL,
段寄存器低 2 位的 RPL 都得是 3, 因此设置的 全局段描述符表(GDT) 如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/kern/gdt.c&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cm"&gt;/* kernel code segment type: code addr: 0 limit: 4G gran: 4KB sz: 32bit */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEL_KCODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xfffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_RW&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_EX&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_DPL_KERN&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_PR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GDT_GR&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;GDT_SZ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="cm"&gt;/* kernel data segment type: data addr: 0 limit: 4G gran: 4KB sz: bit 32bit */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEL_KDATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xfffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_RW&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_DPL_KERN&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_PR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GDT_GR&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;GDT_SZ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="cm"&gt;/* user code segment type: code addr: 0 limit: 4G gran: 4KB sz: 32bit */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEL_UCODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xfffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_RW&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_EX&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_DPL_USER&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_PR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GDT_GR&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;GDT_SZ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="cm"&gt;/* user data segment type: data addr: 0 limit: 4G gran: 4KB sz: 32bit */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEL_UDATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xfffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_RW&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_DPL_USER&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;AC_PR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GDT_GR&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;GDT_SZ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;第一二个描述符定义了内核的代码段和数据段, 第三四个描述符定义了用户的代码段和数据段.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;注意: 代码段必须是非一致性代码段, 因为一致性代码段对特权级的处理方式不同.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;当 GDT 初始化后, 第一二个描述符被使用, 内核跑在特权级为 0 的段上.
那如何让代码从特权级为 0 的段(内核态)转移到特权级为 3 的段(用户态)呢? 用中断.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="idt"&gt;
&lt;h2&gt;IDT&lt;/h2&gt;
&lt;p&gt;为了让用户空间的程序顺利进入内核态, 需要对 中断描述符表(IDT) 做一些设置.&lt;/p&gt;
&lt;p&gt;(以下内容摘自 xv6 中文文档, 有小改动)&lt;/p&gt;
&lt;p&gt;我们假设一个用户态程序执行&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;int&lt;/span&gt; &lt;span class="pre"&gt;n&lt;/span&gt;&lt;/code&gt;指令触发中断, 则 CPU 会取得中断号 n, 进行如下步骤:
(由 PIC 或者异常触发的中断不一定如此)&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;从 中断描述符表(IDT) 获得第 n 个描述符&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;检查描述符的特权级 DPL 是否 &lt;em&gt;数值上大于等于&lt;/em&gt; 当前的特权级 CPL
(即当前段的级别至少要高于要执行的中断的特权级), 是则继续,
否则触发一个通用保护中断(General Protection Fault, int 13)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;通过设置 DPL, 可以限制用户态能用 int 指令触发的中断号, 系统调用的实现即是如此&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;如果目标段描述符的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;RPL&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pre"&gt;CPL&lt;/span&gt;&lt;/code&gt;, 则在 CPU 内部保存&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ss&lt;/span&gt;&lt;/code&gt;的值.
这个时候意味这特权级转换要发生了.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;从一个任务状态段(TSS)加载&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ssX&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;espX&lt;/span&gt;&lt;/code&gt;, X 是 RPL 的值, 所以对于系统调用,
取出的会是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ss0&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp0&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;将&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ss&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;eflags&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cs&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;eip&lt;/span&gt;&lt;/code&gt;压栈&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;清除&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;eflags&lt;/span&gt;&lt;/code&gt;中的某些位&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;设置&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cs&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ip&lt;/span&gt;&lt;/code&gt;为 IDT[n] 中指定的值. (执行中断服务例程)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于普通的中断, 其中断返回地址是发生中断时的执行的那条指令的地址
(需要将 IDT 的类型设置为 中断门(Interrupt gate))
因为这种中断通常和当前进程没有什么关系.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;idt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;fault0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SEL_KCODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GATE_INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDT_PR&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;IDT_DPL_KERN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对于系统调用, 我们需要主动执行 int 指令, 并让其返回到下一条指令处.
因此要将处理系统调用的 IDT 设置为 陷阱门(Trap gate), 并且 DPL 为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;IDT_DPL_USER&lt;/span&gt;&lt;/code&gt;(3).
如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;idt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ISR_SYSCALL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;_syscall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SEL_KCODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GATE_TRAP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDT_PR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDT_DPL_USER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="tss"&gt;
&lt;h2&gt;TSS&lt;/h2&gt;
&lt;p&gt;在特权级转换的时候, 需要从任务状态段取出&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ss0&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp0&lt;/span&gt;&lt;/code&gt;, 因此在转换之前需要设置 TSS.&lt;/p&gt;
&lt;p&gt;CPU 会从寄存器&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;tr&lt;/span&gt;&lt;/code&gt;获得 TSS 的选择子, 然后从 GDT 表里面找出对应的描述符,
由描述符就可以获得 TSS 的基址了.&lt;/p&gt;
&lt;p&gt;TSS 的选择子放在 GDT 里, 但是其&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;AC_RE&lt;/span&gt;&lt;/code&gt;(ACCESS_REVERSE)位为 0 来表示
它是一个 TSS 描述符而不是 GDT 描述符.&lt;/p&gt;
&lt;p&gt;因此 TSS 的初始化是这样的:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tss_init&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;gdt_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEL_TSS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;AC_PR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_AC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AC_EX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GDT_GR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* for tss, access_reverse bit is 1 */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;gdt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;AC_RE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在从进程的内核态回到用户态的时候, 要设置一次 TSS, 以下函数在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;uvm_switch&lt;/span&gt;&lt;/code&gt;里面被调用:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tss_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esp0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ss0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;esp0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esp0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iopb_off&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tss&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;两个上下文&lt;/h2&gt;
&lt;section id="id4"&gt;
&lt;h3&gt;中断上下文&lt;/h3&gt;
&lt;p&gt;从上面关于中断过程的解释可以看到, 从用户态执行中断转入内核态是可能的,
重点在与设置一个 DPL = 3 的 IDT 和一个 TSS 段.&lt;/p&gt;
&lt;p&gt;那如何从内核态返回用户态呢? iret 指令会按 int 压栈的顺序逆序将寄存器们出栈,
程序就会从内核态又返回到用户态了.&lt;/p&gt;
&lt;p&gt;有意思的地方就是, 要从内核态到用户态, 我们可以构造一个栈, 然后执行 iret 指令,
iret 就会将我们特地安排的值覆盖到寄存器上, 这个工作由&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_alloc&lt;/span&gt;&lt;/code&gt;完成,
每个新建的进程都通过这种方式&amp;quot;假装回到&amp;quot;用户空间.&lt;/p&gt;
&lt;p&gt;为了方便地构造栈, 我们需要定义出中断时保存的上下文, int 指令保存的信息还不够,
我们需要自己保存更多的寄存器:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int_frame&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* segment registers */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* registers save by pusha */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;int_no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* save by `int` instruction */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eflags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_esp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 16 bits&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;只要完整地保存了以上信息并正确还原, 就能确保从中断返回时, 程序依然正常运行.
注意的是我们不必显式地建立以上的一个结构体(构建第一个进程的时候除外), 在中断发生时,
这个结构体会在进程的内核栈上被建立.中断返回时, 这些信息又会从栈里被弹出.&lt;/p&gt;
&lt;p&gt;中断上下文的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;err_code&lt;/span&gt;&lt;/code&gt;到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ss&lt;/span&gt;&lt;/code&gt;部分由 int 指令压入, 之后跳转到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/kern/loader.asm&lt;/span&gt;&lt;/code&gt;
中的由汇编编写的中断服务例程(ISR)入口. 有的中断不产生&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;err_code&lt;/span&gt;&lt;/code&gt;,
就由该中断入口压入一个假的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;err_code&lt;/span&gt;&lt;/code&gt;. 这些入口代码有两个宏生成,
分别是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;m_fault&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;m_irq&lt;/span&gt;&lt;/code&gt;, 负责处理异常中断和硬件中断.
另外还有&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_syscall&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_isr_unknown&lt;/span&gt;&lt;/code&gt;处理系统调用和未定义的中断.&lt;/p&gt;
&lt;p&gt;每个入口都会压入自己的中断号, 然后统一跳转到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_isr_stub&lt;/span&gt;&lt;/code&gt;, 压入上下文的剩余部分,
再调到由 C 编写的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;isr_stub&lt;/span&gt;&lt;/code&gt;, 由此再根据入口压入中断号调用真正的 ISR.
关于这些 ISR 的详情...太长了表示扯不下去了... :(&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;进程上下文&lt;/h3&gt;
&lt;p&gt;中断上下文已经让程序能够程序成功进入内核并从内核中返回,
接下来通过切换进程上下文来实现进程的切换.&lt;/p&gt;
&lt;p&gt;进程上下文看起来比中断上下文简单许多, 不过更富技巧性.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;context&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个上下文同样是建立在进程的内核栈上的,但是内核原来的栈也保存了一个.&lt;/p&gt;
&lt;p&gt;我们用下面这个函数来切换进程上下文:&lt;/p&gt;
&lt;div class="highlight-objdump-nasm notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;; context_switch(struct context **old, context *new)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="x"&gt;; 当你调用这个函数时, 会依次 压入 new, old 和 eip&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="x"&gt;[global context_switch]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="x"&gt;context_switch:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="x"&gt;    mov eax, [esp + 4]  ; 把 old 放到 eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="x"&gt;    mov edx, [esp + 8]  ; 把 new 放到 edx&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="x"&gt;    ; 这里已经隐式地保存了 eip&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="x"&gt;    push ebp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="x"&gt;    push ebx&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="x"&gt;    push esi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="x"&gt;    push edi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="x"&gt;; 此时的栈结构就是一个 `strcut context`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="x"&gt;    mov [eax], esp      ; 把 esp 保存到 old 指向的地址&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="x"&gt;    mov esp, edx        ; 切换到 new 指向的地址作为栈&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="x"&gt;    pop edi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="x"&gt;    pop esi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="x"&gt;    pop ebx&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="x"&gt;    pop ebp&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="x"&gt;    ; 还剩下一个 eip 未弹出, 刚好由 ret 弹出, 这样就切换到了 new 里面的 eip&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="x"&gt;    ret&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;eip&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp&lt;/span&gt;&lt;/code&gt; 的保存都非常巧妙, eip 在执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context_switch&lt;/span&gt;&lt;/code&gt; 时被压入,
又在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ret&lt;/span&gt;&lt;/code&gt; 的时候被弹出. 而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;esp&lt;/span&gt;&lt;/code&gt; 则直接作为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context&lt;/span&gt;&lt;/code&gt; 的地址被保存.&lt;/p&gt;
&lt;p&gt;可以看到这个函数可以切换当前的执行流到另一个执行流, 进程的切换就是这样实现的,
当然要切换的不止这个, 页表也要切换, 代表当前执行进程的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc&lt;/span&gt;&lt;/code&gt; 变量也要更新.
页表的切换由 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;uvm_switch&lt;/span&gt;&lt;/code&gt; 执行, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc&lt;/span&gt;&lt;/code&gt; 的更新则在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;scheduler&lt;/span&gt;&lt;/code&gt; 执行.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;虚拟内存映射&lt;/h2&gt;
&lt;p&gt;由于之前的思路问题, 因此 OS67 的内存管理方式不得不和 xv6 不太一样.&lt;/p&gt;
&lt;p&gt;OS67 的内存分配实现在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/mm/pmm.c&lt;/span&gt;&lt;/code&gt;, 使用一个简单的栈来存放未分配的内存页,
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;malloc&lt;/span&gt;&lt;/code&gt; 就是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;pop&lt;/span&gt;&lt;/code&gt; 而 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;mfree&lt;/span&gt;&lt;/code&gt; 就是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;push&lt;/span&gt;&lt;/code&gt;. 这么做简单明了,
虽然申请多个页的时候效率不高, 不过我们不考虑这种需要大量内存的情况.&lt;/p&gt;
&lt;p&gt;对于虚拟内存映射, 策略是这样的: 内核以及未分配的内存的虚拟地址和物理地址一一对应,
用户地址映射到 0xc0000000 上. 内核在初始化页表的时候, 建立一个映射所有物理内存的页表,
之后建立的进程页表中的内核部分就复用内核页表的页表项, 避免内存浪费,
同时在特权级转换时也不必切换页表, 亦能很方便地从内核空间访问到用户空间的内存.&lt;/p&gt;
&lt;p&gt;将用户地址映射到 0xc0000000 的好处是不需要在建立正式页表前建立临时页表来把内核映射到高处,
另外 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;malloc&lt;/span&gt;&lt;/code&gt; 出来的是物理地址, 可以直接对其读写而不必做转换.
缺点则是程序必须经过重定位(链接时使用参数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-Ttext&lt;/span&gt; &lt;span class="pre"&gt;0xc0000000&lt;/span&gt;&lt;/code&gt;)才能运行在高地址,
也许有更多的缺点还没发现.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;第一个进程&lt;/h2&gt;
&lt;section id="id8"&gt;
&lt;h3&gt;构造&lt;/h3&gt;
&lt;p&gt;结构体 proc 用来储存一个进程的信息, 内核中有一个数组&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;struct&lt;/span&gt; &lt;span class="pre"&gt;ptable[NPROC]&lt;/span&gt;&lt;/code&gt;来管理所有的进程.
结构体&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc&lt;/span&gt;&lt;/code&gt;定义如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;killed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NAME_LEN&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// context&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int_frame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// 中断上下文&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 进程上下文&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pde_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgdir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;// 进程页表&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;kern_stack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;// 内核栈&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ofile&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NOFILE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;inode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;proc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里主要关注的是两个上下文, 进程页表以及内核栈.&lt;/p&gt;
&lt;p&gt;这里涉及的代码都在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS37/proc/proc.c&lt;/span&gt;&lt;/code&gt;中.&lt;/p&gt;
&lt;p&gt;第一个进程需要手动创建, 由&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_init&lt;/span&gt;&lt;/code&gt;完成.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_inint&lt;/span&gt;&lt;/code&gt;首先调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_alloc&lt;/span&gt;&lt;/code&gt;从&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ptable&lt;/span&gt;&lt;/code&gt;获得一个空的进程结构体槽位,
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_alloc&lt;/span&gt;&lt;/code&gt;做了一些必要的初始化操作.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_alloc&lt;/span&gt;&lt;/code&gt;为新进程申请了内核栈, 并对他进行了一定的构造:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;为中断上下文&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fm&lt;/span&gt;&lt;/code&gt;留出空间, 并把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;fm&lt;/span&gt;&lt;/code&gt;指向该空间.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fm&lt;/span&gt;&lt;/code&gt;之后放置了指向中断返回函数&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_isr_stub_ret&lt;/span&gt;&lt;/code&gt;的指针&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;为进程上下文&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context&lt;/span&gt;&lt;/code&gt;留出空间, 并把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;content&lt;/span&gt;&lt;/code&gt;改空间,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;context-eip&lt;/span&gt;&lt;/code&gt;指向了函数&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork_ret&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 xv6 中&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork_ret&lt;/span&gt;&lt;/code&gt;被用来处理锁, 这 OS67 中, 这个函数碰巧被用来解决一个
奇怪的 bug &amp;lt;&lt;a class="reference external" href="https://github.com/SilverRainZ/OS67/commit/fc0e84caa1c3ae95998342f2b03125e2226d0dd6"&gt;https://github.com/SilverRainZ/OS67/commit/fc0e84caa1c3ae95998342f2b03125e2226d0dd6&lt;/a&gt;&amp;gt;`_ .
因此, 正常 alloc 出来的新进程都会返回到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork_ret&lt;/span&gt;&lt;/code&gt;. 从&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork_ret&lt;/span&gt;&lt;/code&gt;返回后,
又会跳转到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_isr_stub_ret&lt;/span&gt;&lt;/code&gt;准备从中断返回. 接下来就会逐步把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fm&lt;/span&gt;&lt;/code&gt;弹出,
尽管此时的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fm&lt;/span&gt;&lt;/code&gt;还没有初始化.&lt;/p&gt;
&lt;p&gt;之后&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_init&lt;/span&gt;&lt;/code&gt;为第一个进程申请了一个页目录&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;pgdir&lt;/span&gt;&lt;/code&gt;,
调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;kvm_init&lt;/span&gt;&lt;/code&gt;建立到内核的一对一的地址映射. 为之前的内核栈也建立地址映射.&lt;/p&gt;
&lt;p&gt;再接着, 通过声明在用户程序&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/proc/init.asm&lt;/span&gt;&lt;/code&gt;中的全局变量&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;__init_start&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;__init_end&lt;/span&gt;&lt;/code&gt;
的地址获得编译进内核里的用户程序的位置, 调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;uvm_init_fst&lt;/span&gt;&lt;/code&gt;把程序复制到一个新的页中,
并把该页映射到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;USER_BASE&lt;/span&gt;&lt;/code&gt;(0xc0000000).&lt;/p&gt;
&lt;p&gt;然后开始手动构建一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fm&lt;/span&gt;&lt;/code&gt;, 为各个段寄存器设置正确的段选择子,
为 eflags 寄存器加上 IF 标志(允许中断), 设置用户栈, 最后把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;eip&lt;/span&gt;&lt;/code&gt;设定为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;USER_BASE&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;最后把进程的状态&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;state&lt;/span&gt;&lt;/code&gt;设置为可运行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNABLE&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;以上是比较关键的步骤, 现在可以准备运行第一个进程了.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id9"&gt;
&lt;h3&gt;运行&lt;/h3&gt;
&lt;p&gt;执行了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc_init&lt;/span&gt;&lt;/code&gt;之后, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;scheduler&lt;/span&gt;&lt;/code&gt;紧接其后,
它在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ptable&lt;/span&gt;&lt;/code&gt;中寻找第一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;state&lt;/span&gt;&lt;/code&gt;为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNABLE&lt;/span&gt;&lt;/code&gt;的进程,
调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;uvm_switch&lt;/span&gt;&lt;/code&gt;切换到该进程的页表并设置好 TSS.&lt;/p&gt;
&lt;p&gt;接着更新&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc&lt;/span&gt;&lt;/code&gt;变量, 把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;state&lt;/span&gt;&lt;/code&gt;设置为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNNING&lt;/span&gt;&lt;/code&gt;.
最后调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context_switch&lt;/span&gt;&lt;/code&gt;切换到进程.  不出意外的话,
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context_switch&lt;/span&gt;&lt;/code&gt;会弹出&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;context&lt;/span&gt;&lt;/code&gt;中设定好的寄存器,
新进程返回到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork_ret&lt;/span&gt;&lt;/code&gt;之后返回到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_isr_stub_ret&lt;/span&gt;&lt;/code&gt;中, 又把&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;proc-&amp;gt;fm&lt;/span&gt;&lt;/code&gt;弹出.
于是第一个进程就成功运行在 0xc0000000 的用户空间上了.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id10"&gt;
&lt;h2&gt;调度&lt;/h2&gt;
&lt;p&gt;这里使用非常简单的轮转法, 每次触发时钟中断都会执行&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sched&lt;/span&gt;&lt;/code&gt;,
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sched&lt;/span&gt;&lt;/code&gt;把当前进程状态由&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNNING&lt;/span&gt;&lt;/code&gt;变更为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNABLE&lt;/span&gt;&lt;/code&gt;. 接着执行&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;context_switch&lt;/span&gt;&lt;/code&gt;.
这样 CPU 执行流就回到了刚才&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;scheduler&lt;/span&gt;&lt;/code&gt;中的循环,
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;scheduler&lt;/span&gt;&lt;/code&gt;继续寻找一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;P_RUNABLE&lt;/span&gt;&lt;/code&gt;的进程并切换到它.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="e-n-d"&gt;
&lt;h2&gt;E.N.D.&lt;/h2&gt;
&lt;p&gt;至此, 用户级进程已经成功实现并且被调度. 但是没有有效的接口来启动更多的进程.
我们需要实现一些系统调用比如&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fork&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;exec&lt;/span&gt;&lt;/code&gt;来做这些事情.
:( 但是我已经写不下去了... 如果可以话下次再写吧.&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;不一定有下次&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/process-scheduler-1.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="OS" label="OS"/>
    <published>2015-09-14T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/flag.html</id>
    <title>立 Flag</title>
    <updated>2015-09-09T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="flag"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;现在不开始的话, 以后也不会开始了.&lt;/p&gt;
&lt;img alt="http://imglf2.nosdn.127.net/img/bEd0djMvNWs3R0x3OVJSSHNCYnZvczBnVWtBVGdpNTZ3YUpFbnRuWEdCOHd2Y1JObEdiTW5RPT0.jpg" src="http://imglf2.nosdn.127.net/img/bEd0djMvNWs3R0x3OVJSSHNCYnZvczBnVWtBVGdpNTZ3YUpFbnRuWEdCOHd2Y1JObEdiTW5RPT0.jpg" /&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/flag.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <published>2015-09-09T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/minix-v1-file-system.html</id>
    <title>Minix v1 文件系统的实现</title>
    <updated>2015-08-07T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="minix-v1"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;section id="minix-fs"&gt;
&lt;h2&gt;Minix FS&lt;/h2&gt;
&lt;p&gt;Minix file system 是 Andrew S. Tanenbaum 在 198x 年发明的文件系统,
并随着 Minix 1.0 版一起于 1987 年释出, Linus 编写 Linux 0.11时,
使用的也是 Minix FS, Linux 至今依然提供了对 Minix FS 的支持.
Minix FS 结构简单, 易于理解, 并且资料相当丰富.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="xv-6"&gt;
&lt;h2&gt;xv 6&lt;/h2&gt;
&lt;p&gt;其实最开始并没有用 Minix FS 的想法, 在实现 Minix FS 之前,
我先看了 xv6 中的文件系统部分, 在抄了一遍它的代码之后,
才发现原来 xv6 实现的不是现有的任何一个文件系统, 虽然在原理上和 Minix 没有太大差别
(甚至某些方面比 Minix 更好, 比如 xv6 的 FS 有日志),
但是因为这不是一个被广泛使用的文件系统, 使得你在构建一个磁盘的时候得自己写代码...
(xv6/mkfs.c), 而且你没法很方便地验证你代码的正确性, 太麻烦, 弃之.&lt;/p&gt;
&lt;p&gt;Minix 则不同了, 作为曾经流行过的文件系统, 在 Linux 上至今都有方便的 mkfs.minix
和 fsck.minix 工具, 前者可以建立一个 Minix 文件系统, 后者检查该文件系统的正确性.
正因如此, 我在 xv6 的代码的基础上修改了代码, 在
&lt;a class="reference external" href="https://github.com/SilverRainZ/OS67"&gt;OS67&lt;/a&gt; 上实现了一个精简版的 Minix FS.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;建立磁盘&lt;/h2&gt;
&lt;p&gt;首先用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bximage&lt;/span&gt;&lt;/code&gt;建立一个硬盘镜像文件, 再用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;mkfs.minix&lt;/span&gt;&lt;/code&gt;建立文件系统,
如果需要复制文件进去的话, 用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;mount&lt;/span&gt;&lt;/code&gt;挂载.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;bximage&lt;span class="w"&gt; &lt;/span&gt;bin/rootfs.img&lt;span class="w"&gt; &lt;/span&gt;-hd&lt;span class="o"&gt;=&lt;/span&gt;10M&lt;span class="w"&gt; &lt;/span&gt;-imgmode&lt;span class="o"&gt;=&lt;/span&gt;flat&lt;span class="w"&gt; &lt;/span&gt;-mode&lt;span class="o"&gt;=&lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;-q
&lt;/span&gt;&lt;span data-line="2"&gt;mkfs.minix&lt;span class="w"&gt; &lt;/span&gt;bin/rootfs.img&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;-n14
&lt;/span&gt;&lt;span data-line="3"&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;loop&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;minix&lt;span class="w"&gt; &lt;/span&gt;bin/rootfs.img&lt;span class="w"&gt; &lt;/span&gt;/mnt/fs
&lt;/span&gt;&lt;span data-line="4"&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;usr/*&lt;span class="w"&gt; &lt;/span&gt;/mnt/fs/
&lt;/span&gt;&lt;span data-line="5"&gt;sleep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/mnt/fs
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这段脚本建立了一个大小为 10 M 的 Minix 文件系统镜像, 并且将 usr 目录下的文件复制进去.
当你需要检查文件系统的正确性, 执行&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fsck.minix&lt;/span&gt; &lt;span class="pre"&gt;-fsl&lt;/span&gt; &lt;span class="pre"&gt;./bin/rootfs.img&lt;/span&gt;&lt;/code&gt;,
检查无误的话, fsck 会输出该磁盘的超级块信息及里面包含的所有文件.
若出错, fsck 会给出详尽的错误信息, 比如下面这段:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;➜&lt;span class="w"&gt;  &lt;/span&gt;OS67&lt;span class="w"&gt; &lt;/span&gt;git:&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;✗&lt;span class="w"&gt;  &lt;/span&gt;fsck.minix&lt;span class="w"&gt; &lt;/span&gt;-fsl&lt;span class="w"&gt; &lt;/span&gt;./bin/rootfs.img
&lt;/span&gt;&lt;span data-line="2"&gt;Forcing&lt;span class="w"&gt; &lt;/span&gt;filesystem&lt;span class="w"&gt; &lt;/span&gt;check&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;./bin/rootfs.img.
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="m"&gt;3360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;inodes
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="m"&gt;10080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;blocks
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nv"&gt;Firstdatazone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;110&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nv"&gt;Zonesize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nv"&gt;Maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;268966912&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;Filesystem&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="nv"&gt;namelen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;/bin:
&lt;/span&gt;&lt;span data-line="12"&gt;/bin/README
&lt;/span&gt;&lt;span data-line="13"&gt;/README
&lt;/span&gt;&lt;span data-line="14"&gt;Inode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;unused,&lt;span class="w"&gt; &lt;/span&gt;but&lt;span class="w"&gt; &lt;/span&gt;used&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/TESTME&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;/TESTME
&lt;/span&gt;&lt;span data-line="16"&gt;Block&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;115&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/TESTME&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;use.
&lt;/span&gt;&lt;span data-line="17"&gt;Inode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;used,&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;used&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;bitmap.
&lt;/span&gt;&lt;span data-line="18"&gt;Inode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;used,&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;unused&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;bitmap.
&lt;/span&gt;&lt;span data-line="19"&gt;Zone&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;114&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;use,&lt;span class="w"&gt; &lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;uses&lt;span class="w"&gt; &lt;/span&gt;it.
&lt;/span&gt;&lt;span data-line="20"&gt;Zone&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;115&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;use,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;counted&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="minix"&gt;
&lt;h2&gt;Minix 文件系统结构&lt;/h2&gt;
&lt;p&gt;Minix 文件系统的结构如下:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;Minix&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt; &lt;span class="n"&gt;structure&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;           &lt;span class="mi"&gt;1&lt;/span&gt;              &lt;span class="mi"&gt;2&lt;/span&gt;             &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;imap_blk&lt;/span&gt;        &lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;+----------------------------------------------------------------------------------------+&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;bootsector&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;superblock&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inode&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;zone&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inodes&lt;/span&gt; &lt;span class="n"&gt;zone&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;zone&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="o"&gt;+----------------------------------------------------------------------------------------+&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;注意: Minix 文件系统的最小分配单位是 zone, 可以把它叫做虚拟块,
一个虚拟块的大小是 1024 byte, 而磁盘的物理扇区大小常常是 512 byte.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;section id="i"&gt;
&lt;h3&gt;i 节点&lt;/h3&gt;
&lt;p&gt;i 节点是 Minix FS 中最重要的结构体, 其定义如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/inc/minix.h&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cm"&gt;/* in-disk minix inode */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;d_inode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 文件类型和 RWX 访问控制位&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 文件属主的用户 ID            (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 文件大小, 以 byte 计数&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mtime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 自从 1970.1.1 以来的秒数     (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 文件属主 所属的组            (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nlinks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 该节点被多少个目录所链接&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="cm"&gt;     * zone[0] - zone[6] 分别指向 7 个直接块&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="cm"&gt;     * zone[7] 指向间接块&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="cm"&gt;     * zone[8] 指向双重间接块                       (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="cm"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="c1"&gt;// (标记有 unused 是 OS67 没有用到的元素)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;i 节点被储存在磁盘的 i 节点块(inodes zone)中, 并按排列顺序被编号,
其使用状况存储在磁盘的 i 节点位图块(inodes bitmap)中.&lt;/p&gt;
&lt;p&gt;一个 i 节点对应磁盘里的一个文件, 储存着文件的元信息.
值得注意的是 i 节点并未储存该文件的文件名.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zone&lt;/span&gt;&lt;/code&gt;中储存了虚拟块的号码, 这些号码指向磁盘的数据块(data zone),
这些块中直接或间接储存了文件的数据.&lt;/p&gt;
&lt;p&gt;目录被实现为一种特殊的文件, 目录的数据由一个或多个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dir_entry&lt;/span&gt;&lt;/code&gt;结构组成.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/inc/minix.h&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cm"&gt;/* minix directroy entry */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;dir_entry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NAME_LEN&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;第一个元素代表该目录下的文件的 i 节点号, 第二个元素则是文件名.
文件的文件名储存在引用它的目录文件中, 这使得一个文件可以有多个名字.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;在 Linux 下创建某个文件的硬连接, 其实就是为目标目录增加对指定文件对应的 i 节点的引用,
注意 i 节点号只在一个磁盘中唯一, 所以硬链接无法跨磁盘.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;nlinks&lt;/span&gt;&lt;/code&gt;元素指示了有多少个目录引用了这个文件, 当删除一个文件时,
对应的 i 节点的引用数就会减一, 当引用数为 0 时, 该节点就可以从磁盘上被释放了.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zone[0]&lt;/span&gt; &lt;span class="pre"&gt;-&lt;/span&gt; &lt;span class="pre"&gt;zone[6]&lt;/span&gt;&lt;/code&gt;指向的虚拟块直接储存了文件的数据.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zone[7]&lt;/span&gt;&lt;/code&gt;指向的虚拟块储存的是更多的虚拟块号码, 就是一个二级表.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zone[8]&lt;/span&gt;&lt;/code&gt; 指向一个双重间接块.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用图说话比较清晰:&lt;/p&gt;
&lt;img alt="Inode structure" src="https://silverrainz.me/_images/inode-struct.gif" /&gt;
&lt;p&gt;ref: &lt;a class="reference external" href="http://jan.newmarch.name/OS/l6_1.html"&gt;http://jan.newmarch.name/OS/l6_1.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;因此, Minix FS 支持的最大文件大小为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;(7&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;1024/2&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;1024/2*1024/2)&lt;/span&gt; &lt;span class="pre"&gt;*&lt;/span&gt; &lt;span class="pre"&gt;1024&lt;/span&gt; &lt;span class="pre"&gt;byte&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;256&lt;/span&gt; &lt;span class="pre"&gt;MB&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;OS67 并没有使用双重间接块, 因此支持的最大文件大小仅为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;(7&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;1024/2)&lt;/span&gt; &lt;span class="pre"&gt;*&lt;/span&gt; &lt;span class="pre"&gt;1024&lt;/span&gt; &lt;span class="pre"&gt;byte&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;519&lt;/span&gt; &lt;span class="pre"&gt;KB&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="boot-secotr"&gt;
&lt;h3&gt;引导扇区(boot secotr):&lt;/h3&gt;
&lt;p&gt;磁盘的第一个虚拟块作是引导扇区, 这个通常和文件系统没有关系.&lt;/p&gt;
&lt;p&gt;OS67 的 bootsector 实现在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/boot/bootsect.asm&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="super-block"&gt;
&lt;h3&gt;超级块(super block)&lt;/h3&gt;
&lt;p&gt;超级块(superblock), 用来存放整个文件系统的元信息, 比如磁盘大小, i节点数目,
虚拟块数目, Magic nubmer 等.  Minix FS 的超级块结构如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/inc/minix.h&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;super_block&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ninodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// number of inodes&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nzones&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// number of zones&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;imap_blk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// i 节点位图 占用块的数目&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zmap_blk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// 数据块位图 占用的块的数目&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fst_data_zone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 第一个 数据块 的块号&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log_zone_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 一个虚拟块的大小 = 1024 &amp;lt;&amp;lt; log_zone_size&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// 能存放的最大文件大小(以 byte 计数)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;// magic number&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="inode-zone-bitmap"&gt;
&lt;h3&gt;位图(inode &amp;amp; zone bitmap)&lt;/h3&gt;
&lt;p&gt;有关位图的实现在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/fs/bitmap.c&lt;/span&gt;&lt;/code&gt;中.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/inc/minix.h&lt;/span&gt;&lt;/code&gt;实现了两个宏来定位这些位图块.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cm"&gt;/* bit per block */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#define BPB (BSIZE*8)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cm"&gt;/* bitmap contain inode i*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="cp"&gt;#define IMAP_BLK(sb, i) (2 + (i - 1)/BPB)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="cm"&gt;/* bitmap contain block z */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="cp"&gt;#define ZMAP_BLK(sb, b) (2 + sb.imap_blk + (b)/BPB)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;inode bitmap: i 节点位图, 这些块每个位都对应一个 i 节点,
i 节点位图占据 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;superblock.imap_blk&lt;/span&gt;&lt;/code&gt;个块.
(注意 i 节点从 1 开始计数), 宏&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;IMP_BLK&lt;/span&gt;&lt;/code&gt;用来根据 i 节点号定位到对应的 bit 所在的块;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;zone bitmap: 数据块位图, 从编号为&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;superblock.fst_data_zone&lt;/span&gt;&lt;/code&gt;开始的块的使用情况
和这个位图上的位一一对应.
(块号依然从 0 开始计数)宏&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ZMAP_BLOCK&lt;/span&gt;&lt;/code&gt;根据块号 定位到对应的 bit 所在的块;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;虽然现在 bitmap.c 的代码工作正常, 不过我对他们的对应关系还是存有疑问...
暂时懒得去想了, 此处存疑. // TODO&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id="i-inode"&gt;
&lt;h3&gt;i 节点块(inode)&lt;/h3&gt;
&lt;p&gt;这些块用来储存 i 节点, 用宏&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;IBLK&lt;/span&gt;&lt;/code&gt;根据 i 节点号, 定位到块号, 同样注意 i 节点从 1 开始计数.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#define IBLK(sb, i) (2 + ((sb).imap_blk) + ((sb).zmap_blk) + ((i) - 1)/IPB)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="data"&gt;
&lt;h3&gt;数据块(data)&lt;/h3&gt;
&lt;p&gt;这些块被用来储存数据, 从&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;superblock.fst_data_zone&lt;/span&gt;&lt;/code&gt;开始.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;系统层次&lt;/h2&gt;
&lt;p&gt;整个文件系统的实现被分为五个层次, 代码基本上继承自 xv6, 在摸清楚代码的意思之后,
把 xv6 文件系统代码改成 Minix FS 是很简单的事情, 甚至有些文件不需要改动...&lt;/p&gt;
&lt;section id="os67-fs-ide-c"&gt;
&lt;h3&gt;磁盘驱动层 OS67/fs/ide.c&lt;/h3&gt;
&lt;p&gt;这一层通过 ins outs 指令, 负责从磁盘读取扇区到高速缓冲区 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;buf&lt;/span&gt;&lt;/code&gt;,
并且限制在一个块只能被一个进程访问(通过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;B_BUSY&lt;/span&gt;&lt;/code&gt; 锁住).&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;这里的 高速缓冲/块缓冲 只是把磁盘的数据读取到内存中暂存, 并且避免无意义的读取.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;注意: 这里一次读取的是一个虚拟块(1024 byte), 而不是一个物理意义上的扇区(常见大小是 512 byee),
因此得把上层传来的虚拟块号, 转化为物理扇区号, 并且一次读取两个扇区.&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;phy_blkn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;blkno&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BSIZE&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PHY_BSIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cm"&gt;/* number of sectors, read 2 sector for once  */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;outb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDE_PORT_SECT_COUNT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BSIZE&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PHY_BSIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="os67-fs-bcache-c"&gt;
&lt;h3&gt;块缓冲层 OS67/fs/bcache.c&lt;/h3&gt;
&lt;p&gt;维护了一个高速缓冲的链表(数组),  为上层提供了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bread&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bwrite&lt;/span&gt;&lt;/code&gt;函数,
而&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bget&lt;/span&gt;&lt;/code&gt;则用来分配缓冲区.&lt;/p&gt;
&lt;section id="braed"&gt;
&lt;h4&gt;braed&lt;/h4&gt;
&lt;p&gt;当请求一个块的数据的时候(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bread&lt;/span&gt;&lt;/code&gt;), 如果一个块已经被缓存, 并且这个块的内容是有效的(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;B_VAILD&lt;/span&gt;&lt;/code&gt;),
块缓存层可以直接返回当前缓冲区的内容, 而不用重新读取扇区.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;bread bwrite 封装了磁盘读写的操作,
你不会知道你这次读取的内容是从磁盘中读取的还是从块缓冲直接取出的,
但是数据一定是正确的.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id="bget"&gt;
&lt;h4&gt;bget&lt;/h4&gt;
&lt;p&gt;当根据虚拟块的块号(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;buf-&amp;gt;blkno&lt;/span&gt;&lt;/code&gt;)请求一个缓冲区的时候(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bget&lt;/span&gt;&lt;/code&gt;),
程序会沿着链表从头到尾寻找这个缓冲区是否被缓存,是的话直接返回, 如果没有被缓存,
会从链表从尾到头搜索第一个可用的空缓冲区, 每次释放缓冲区的时候(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;brelse&lt;/span&gt;&lt;/code&gt;),
都会把该缓冲区放在链表头, 保证每次从头查找到的是使用时间离现在最近的缓冲区,
而被分配的空缓冲是最久没使用的.&lt;/p&gt;
&lt;p&gt;以上的两个层次都和叫做块缓冲区的结构: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;buf&lt;/span&gt;&lt;/code&gt;密切相关, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;buf&lt;/span&gt;&lt;/code&gt;的结构如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/inc/buf.h&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;// B_BUSY B_VALID B_DIRTY&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;// only one disk, dev = 0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blkno&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// zone number&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// LRU Cache List 双向&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;qnext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 磁盘操作请求队列, 单向&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="i-os67-fs-inode-c-os67-fs-bitmap-c"&gt;
&lt;h3&gt;i 节点层 OS67/fs/inode.c OS67/fs/bitmap.c&lt;/h3&gt;
&lt;p&gt;这一层开始和文件系统密切相关, i 节点层为使用中的磁盘中的 i 节点(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;d_inode&lt;/span&gt;&lt;/code&gt;)
提供了内存中的拷贝(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;inode&lt;/span&gt;&lt;/code&gt;), 可以类比块缓冲和虚拟块的关系.&lt;/p&gt;
&lt;p&gt;磁盘中的 i 节点结构上面已经讲过了, 内存中的 i 节点&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;inode&lt;/span&gt;&lt;/code&gt;结构如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c1"&gt;// OS67/inc/minix.h&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cm"&gt;/* in-memorty inode */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;inode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// i 节点所在的磁盘, OS67 只支持单个磁盘, 所以始终为 0&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// i 节点号码&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 内存引用计数&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// flag 就是 flag&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="c1"&gt;// struct d_inode {&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mtime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// (unused)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nlinks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c1"&gt;// 可以看到后面部分其实是完整的一个`d_inode`.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这一层提供了对 inode 的各种操作&lt;/p&gt;
&lt;section id="id3"&gt;
&lt;h4&gt;申请和分配:&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_ialloc&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_ifree&lt;/span&gt;&lt;/code&gt; 在磁盘上分配和释放新的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;d_inode&lt;/span&gt;&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;balloc&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bfree&lt;/span&gt;&lt;/code&gt; 在磁盘上分配和释放新的数据块, 供 i 节点使用.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上的函数均在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OS67/fs/bitmap.c&lt;/span&gt;&lt;/code&gt;中实现.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ialloc&lt;/span&gt;&lt;/code&gt;则是对&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_ialloc&lt;/span&gt;&lt;/code&gt;的封装, 分配一个新的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;d_inode&lt;/span&gt;&lt;/code&gt;后,
把它和内存中的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;inode&lt;/span&gt;&lt;/code&gt;联系起来.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h4&gt;i 节点操作:&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;iget&lt;/span&gt;&lt;/code&gt; 从 i 节点缓冲中获得指定 i 节点号码的缓冲区, 类似&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bget&lt;/span&gt;&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ilock&lt;/span&gt;&lt;/code&gt; 将 i 节点锁住(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;I_BUSY&lt;/span&gt;&lt;/code&gt;), 并从磁盘中将 i 节点内容读出,
而&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;iunlock&lt;/span&gt;&lt;/code&gt;解锁 i 节点;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;idup&lt;/span&gt;&lt;/code&gt;增加该 i 节点的引用计数(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ip-&amp;gt;ref&lt;/span&gt;&lt;/code&gt;), &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;iput&lt;/span&gt;&lt;/code&gt;则将引用计数减 1,
当引用计数为 0 时, 该缓冲区被释放;
如果该节点在磁盘上的引用(&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;ip-&amp;gt;nlinks&lt;/span&gt;&lt;/code&gt;)也为 0,
调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;itrunc&lt;/span&gt;&lt;/code&gt;将该节点占有的数据块和元信息释放,
再调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;_ifree&lt;/span&gt;&lt;/code&gt;清空 inode 位图上的位;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bmap&lt;/span&gt;&lt;/code&gt;读取指定 i 节点的第 n 个块, 间接块和非间接块的区别就由该函数处理;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;iread&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;iwrite&lt;/span&gt;&lt;/code&gt;则在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bmap&lt;/span&gt;&lt;/code&gt;的基础上实现了对 i 节点的读取和写入.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="os67-fs-dir-c-os-fs-p2i-c"&gt;
&lt;h3&gt;目录层 OS67/fs/dir.c OS/fs/p2i.c&lt;/h3&gt;
&lt;p&gt;这一层开始有文件名和路径的出现, 为上层提供了一个将路径名转换为 对应 i 节点的函数.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dir_lookup&lt;/span&gt;&lt;/code&gt; 在一个类型为目录的 i 节点中寻找指定名字的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dir_entry&lt;/span&gt;&lt;/code&gt;
(判断 i 节点是否为目录用宏&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;IS_DIR&lt;/span&gt;&lt;/code&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dir_link&lt;/span&gt;&lt;/code&gt; 为一个目录文件增加一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;dir_entry&lt;/span&gt;&lt;/code&gt;, 链接到指定的一个 i 节点;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;p2i&lt;/span&gt;&lt;/code&gt; (path to inode) 解析路径名, 返回指定的未上锁的 i 节点.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h3&gt;文件和系统调用&lt;/h3&gt;
&lt;p&gt;这一层是最上一层, 文件是对 i 节点的简单封装, 提供了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fread&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fwrite&lt;/span&gt;&lt;/code&gt; &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fclose&lt;/span&gt;&lt;/code&gt;等函数.
此处涉及到进程的文件表, 因此这一层暂时没有&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;抄&lt;/span&gt;写.&lt;/p&gt;
&lt;p&gt;不过在前面几层的基础上, 实现这一层应该没什么问题.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://book.douban.com/subject/1231236/"&gt;《Linux 内核完全注释》&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/Fleurer/fleurix"&gt;fleurix&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://koala.cs.pub.ro/redmine/attachments/download/105/minix.pdf"&gt;Minix File System - Dr.John C.S.Lui&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://pdos.csail.mit.edu/6.828/2011/xv6.html"&gt;MIT 6.828 xv6&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/ranxian/xv6-chinese"&gt;xv6 中文文档&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/minix-v1-file-system.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈Inode structure</summary>
    <category term="OS" label="OS"/>
    <published>2015-08-07T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/overthewire-bandit.html</id>
    <title>OverTheWire Bandit</title>
    <updated>2015-07-26T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="overthewire-bandit"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;题目地址: &lt;a class="reference external" href="http://overthewire.org/wargames/bandit/"&gt;OverTheWire: Bandit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;考的都是些 Linux 下的基本操作, 虽然说是基本操作, 不过那些命令都没用过,
所以做了这些题依然觉得受益匪浅. 其中还有有几道题很有意思...
&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;有意思的意思是我不会做&lt;/span&gt;.&lt;/p&gt;
&lt;section id="wechall"&gt;
&lt;h2&gt;WeChall 计分板&lt;/h2&gt;
&lt;p&gt;OverTheWire 使用 Wechall 的计分板来计分,
具体参见 &lt;a class="reference external" href="http://overthewire.org/about/wechall.html"&gt;WeChall Scoreborad&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;因为题目都在远程的 ssh 主机上, 所以你需要让远程主机知道你是谁.
在你的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.bashrc&lt;/span&gt;&lt;/code&gt; 里加上两个环境变量:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WECHALLUSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;你在 WeChall 的用户名&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WECHALLTOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;你在 WeChall 的 WarToken&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;WarToken 可以在 WeChall 网站的
&lt;a class="reference external" href="http://www.wechall.net/warboxes"&gt;Account -&amp;gt; WarBoxes -&amp;gt; Your current WarToken&lt;/a&gt;
获得.&lt;/p&gt;
&lt;p&gt;在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.ssh/config&lt;/span&gt;&lt;/code&gt; 中添加:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="n"&gt;labs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overthewire&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;SendEnv&lt;/span&gt; &lt;span class="n"&gt;WECHALLTOKEN&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="n"&gt;SendEnv&lt;/span&gt; &lt;span class="n"&gt;WECHALLUSER&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在 ssh 连接的时候就会把你的帐号信息发送给远程主机.&lt;/p&gt;
&lt;p&gt;在登入一个新的关卡后, 执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;wechall&lt;/span&gt;&lt;/code&gt; 便可获得该关卡的分数.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;题目&lt;/h2&gt;
&lt;section id="bandit17"&gt;
&lt;h3&gt;bandit17&lt;/h3&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;The password for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. First find out which of these ports have a server listening on them. Then find out which of those speak SSL and which don’t. There is only 1 server that will give the next credentials, the others will simply send back to you whatever you send to it.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;要从 31000-32000 之间的端口中找出有开放的并且只是 SSL 连接的端口,
往该端口发送上一关的密码就会返回下一关的密码.&lt;/p&gt;
&lt;p&gt;找出所有有应答的端口:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;nc&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;localhost&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;31000&lt;/span&gt;-32000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;/tmp.tmpxxx/log
&lt;/span&gt;&lt;span data-line="2"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/tmp.tmpxxx/log&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Succ
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-v&lt;/span&gt;&lt;/code&gt; 用来给出连接的详细信息, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-w&lt;/span&gt; &lt;span class="pre"&gt;2&lt;/span&gt;&lt;/code&gt; 指定 timeout,
不知道为什么 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-v&lt;/span&gt;&lt;/code&gt; 的信息是直接输出到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;stderr&lt;/span&gt;&lt;/code&gt; 的.
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;tmp/tmp.xxx&lt;/span&gt;&lt;/code&gt; 使用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;mktemp&lt;/span&gt; &lt;span class="pre"&gt;-d&lt;/span&gt;&lt;/code&gt; 产生的临时目录.&lt;/p&gt;
&lt;p&gt;最后有应答的只有五个端口, 挨个挨个试.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;s_client&lt;span class="w"&gt; &lt;/span&gt;-connect&lt;span class="w"&gt; &lt;/span&gt;localhost:31xxx&lt;span class="w"&gt; &lt;/span&gt;-ssl3&lt;span class="w"&gt; &lt;/span&gt;-quiet
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;发现是 31790 端口, 返回一个 RSA 私钥, 所以:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;s_client&lt;span class="w"&gt; &lt;/span&gt;-connect&lt;span class="w"&gt; &lt;/span&gt;localhost:31790&lt;span class="w"&gt; &lt;/span&gt;-ssl3&lt;span class="w"&gt; &lt;/span&gt;-quiet&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;bandit17.private
&lt;/span&gt;&lt;span data-line="2"&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bandit17.private
&lt;/span&gt;&lt;span data-line="3"&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;bandit17.key&lt;span class="w"&gt; &lt;/span&gt;bandit17@bandit.labs.overthewire.org
&lt;/span&gt;&lt;span data-line="4"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/etc/bandit_pass/bandit17
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;xLYVMN9WE5zQ5vHacb0sZEVqbrp7nBTn&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="bandit21"&gt;
&lt;h3&gt;bandit21&lt;/h3&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;There is a setuid binary in the homedirectory that does the following: it makes a connection to localhost on the port you specify as a commandline argument. It then reads a line of text from the connection and compares it to the password in the previous level (bandit20). If the password is correct, it will transmit the password for the next level (bandit21).&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;To beat this level, you need to login twice: once to run the setuid command, and once to start a network daemon to which the setuid will connect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;Try connecting to your own network daemon to see if it works as you think&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit20&lt;/span&gt;&lt;/code&gt; 的家目录下提供了一个程序 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;suconnect&lt;/span&gt;&lt;/code&gt;, 会从你指定的端口读取 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit20&lt;/span&gt;&lt;/code&gt; 的密码,
如果正确的话返回本关卡的密码.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;GbKksEFF4yrVs6il55v6gwY5aVje5f0j&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1234&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./suconnect&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1234&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里主要是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;amp;&lt;/span&gt;&lt;/code&gt; 的用法, 使两个命令同时执行:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gE269g2h3mw3pwgrj0Ha9Uoqen1c9DGr&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="bandit24"&gt;
&lt;h3&gt;bandit24&lt;/h3&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;This level requires you to create your own first shell-script. This is a very big step and you should be proud of yourself when you beat this level!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;备注&lt;/p&gt;
&lt;p&gt;Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这题我觉得有点意思.&lt;/p&gt;
&lt;p&gt;cron 是一个定时执行工具, 任务可以通过命令 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;crontab&lt;/span&gt;&lt;/code&gt; 设定,
配置储存在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/etc/cron.d&lt;/span&gt;&lt;/code&gt; 中, 每分钟 cron 会被触发一次,
到该目录检测是否有任务要执行: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cat&lt;/span&gt; &lt;span class="pre"&gt;/etc/cron.d/cronjob_bandit24&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;bandit24&lt;span class="w"&gt; &lt;/span&gt;/usr/bin/cronjob_bandit24.sh&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;所以说 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/usr/bin/cronjob_bandit24.sh&lt;/span&gt;&lt;/code&gt; 会每分钟执行一次, 看看这个脚本的内容是什么:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nv"&gt;myname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;whoami&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/var/spool/&lt;span class="nv"&gt;$myname&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Executing and deleting all scripts in /var/spool/&lt;/span&gt;&lt;span class="nv"&gt;$myname&lt;/span&gt;&lt;span class="s2"&gt;:&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;.*&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;..&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Handling &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;timeout&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;每次都执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/var/spool/bandit24&lt;/span&gt;&lt;/code&gt; 下的所有可执行文件, 之后删除.
当然是以 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit24&lt;/span&gt;&lt;/code&gt; 的身份执行这些操作.&lt;/p&gt;
&lt;p&gt;所以我们可以构造一个脚本让他执行.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;cp&lt;span class="w"&gt; &lt;/span&gt;/etc/bandit_pass/bandit24&lt;span class="w"&gt; &lt;/span&gt;/tmp/tmp.xxx/psw
&lt;/span&gt;&lt;span data-line="3"&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;666&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp/tmp.xxx/
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个脚本把密码文件复制到临时目录并且更改他的权限(至少让所有人可读).&lt;/p&gt;
&lt;p&gt;中间出了很多愚蠢的错误, 比如写错目录,搞错 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sh&lt;/span&gt;&lt;/code&gt; 的路径什么的,
另外, 不能用重定向导出 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit24&lt;/span&gt;&lt;/code&gt; 的密码, 因为没有权限(为什么没有权限我就不清楚了).&lt;/p&gt;
&lt;p&gt;脚本写完后, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;chmod&lt;/span&gt; &lt;span class="pre"&gt;+x&lt;/span&gt;&lt;/code&gt;, 再把它复制到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/var/spool/bandit24&lt;/span&gt;&lt;/code&gt; 目录下, 记得备份,
每隔一分钟该目录就会被清空.&lt;/p&gt;
&lt;p&gt;脚本执行后, 到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/tmp/tmp.xxx&lt;/span&gt;&lt;/code&gt; 里就可以看到存有 key 的文件了:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id="bandit25"&gt;
&lt;h4&gt;bandit25&lt;/h4&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;A daemon is listening on port 30002 and will give you the password for bandit25 if given the password for bandit24 and a secret numeric 4-digit pincode. There is no way to retrieve the pincode except by going through all of the 10000 combinaties, called brute-forcing.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;有一个守护进程在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;30002&lt;/span&gt;&lt;/code&gt; 端口监听, 把 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit24&lt;/span&gt;&lt;/code&gt; 的密码和一个四位数字组成的 pincode 传给它,
如果密码和 pincode 都正确的话会返回 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit25&lt;/span&gt;&lt;/code&gt; 的密码.&lt;/p&gt;
&lt;p&gt;所以自然是爆破了, 直接用 nc 链接该端口会提示:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;am&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;pincode&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;bandit25&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Please&lt;/span&gt; &lt;span class="n"&gt;enter&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;bandit24&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="n"&gt;pincode&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separated&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;所以按照格式来, 生成 10000 个 密码 + pincode 的序列传给该端口.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="m"&gt;0000&lt;/span&gt;..9999&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp/pin&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/tmp/pin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc&lt;span class="w"&gt; &lt;/span&gt;localhost&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;30002&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp/log
&lt;/span&gt;&lt;span data-line="3"&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/tmp/log&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Corr&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n1
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其实答案就是最后一个端口:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;5670-Wrong! Please enter the correct pincode. Try again.
&lt;/span&gt;&lt;span data-line="2"&gt;5671:Correct!
&lt;/span&gt;&lt;span data-line="3"&gt;5672-The password of user bandit25 is uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;所以:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uNG9O58gUE7snukf3bvZ0rxhtnjzSGzG&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="bandit26"&gt;
&lt;h4&gt;bandit26&lt;/h4&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Logging in to bandit26 from bandit25 should be fairly easy… The shell for user bandit26 is not /bin/bash, but something else. Find out what it is, how it works and how to break out of it.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;这是 26 个 level 里面最有意思的一道题的, 可惜我没能做出来...
参考的答案是这个:
&lt;a class="reference external" href="http://codebluedev.blogspot.com/2015/07/overthewire-bandit-level-26.html"&gt;overthewire-bandit-level-26&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;题干里说 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit26&lt;/span&gt;&lt;/code&gt; 的 shell 并不是普通的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/bin/bash&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit25&lt;/span&gt;&lt;/code&gt; 的家目录下给出了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bandit26&lt;/span&gt;&lt;/code&gt; 的私钥,
登录上去只是打印出了 bandit26 的 ASCII Art 就退出了.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt; _                     _ _ _   ___   __
&lt;/span&gt;&lt;span data-line="2"&gt;| |                   | (_) | |__ / /
&lt;/span&gt;&lt;span data-line="3"&gt;| |__   __ _ _ __   __| |_| |_   ) / /_
&lt;/span&gt;&lt;span data-line="4"&gt;| &amp;#39;_ / _` | &amp;#39;_ / _` | | __| / / &amp;#39;_
&lt;/span&gt;&lt;span data-line="5"&gt;| |_) | (_| | | | | (_| | | |_ / /| (_) |
&lt;/span&gt;&lt;span data-line="6"&gt;|_.__/ \__,_|_| |_|\__,_|_|\__|____\___/
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;cat&lt;/span&gt; &lt;span class="pre"&gt;/etc/passwd&lt;/span&gt; &lt;span class="pre"&gt;|&lt;/span&gt; &lt;span class="pre"&gt;grep&lt;/span&gt; &lt;span class="pre"&gt;bandit26&lt;/span&gt;&lt;/code&gt; 得到:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bandit26&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;\ &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11026&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11026&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bandit&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;\ &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bandit26&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;\ &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;showtext&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(我到这里就卡住了)&lt;/p&gt;
&lt;p&gt;发现 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;showtext&lt;/span&gt;&lt;/code&gt; 是一个 shell 脚本, 内容如下&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;more&lt;span class="w"&gt; &lt;/span&gt;~/text.txt
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;即 ssh 连上去后执行默认 shell, 用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;more&lt;/span&gt;&lt;/code&gt; 打印出了 ~/text.txt 之后就退出了, 如图:&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/overthewire-bandit26-1.png" src="https://silverrainz.me/_images/overthewire-bandit26-1.png" /&gt;
&lt;p&gt;一连上就退出, 那我们怎么让它执行我们想要的命令呢? 直接用 ssh 的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-t&lt;/span&gt;&lt;/code&gt; + 命令 是不行的,
这个命令不会被解释, 因为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;bash&lt;/span&gt;&lt;/code&gt; 没有执行.&lt;/p&gt;
&lt;p&gt;正确答案是通过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;more&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;more&lt;/span&gt;&lt;/code&gt; 在要输出的内容行数多于终端行数的时候会停下来, 等待你翻页,
所以我们把当前的终端调小, 差不多四行, 再次 shh 上去, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;more&lt;/span&gt;&lt;/code&gt; 就停下来了. (好脑洞)&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/overthewire-bandit26-2.png" src="https://silverrainz.me/_images/overthewire-bandit26-2.png" /&gt;
&lt;p&gt;在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;more&lt;/span&gt;&lt;/code&gt; 里面按 v, 系统会调用默认的编辑器来编辑这个文件, 默认是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;vi&lt;/span&gt;&lt;/code&gt;,
有了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;vi&lt;/span&gt;&lt;/code&gt;, 就相当于有了一个终端.&lt;/p&gt;
&lt;p&gt;在命令模式执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:r&lt;/span&gt; &lt;span class="pre"&gt;/etc/bandit_pass/bandit26&lt;/span&gt;&lt;/code&gt;, 密码的内容就会被读入.&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/overthewire-bandit26-3.png" src="https://silverrainz.me/_images/overthewire-bandit26-3.png" /&gt;
&lt;p&gt;要打开 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sh&lt;/span&gt;&lt;/code&gt; 的话, 可以:&lt;/p&gt;
&lt;div class="highlight-vim notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="k"&gt;shell&lt;/span&gt; &lt;span class="k"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="sr"&gt;/bin/&lt;/span&gt;&lt;span class="k"&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这样就可以执行 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;wechall&lt;/span&gt;&lt;/code&gt; 拿分了:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;czgV9L3Xx8JPOyRbXh6lQbmIOWvPT6Z&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/overthewire-bandit.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="CTF" label="CTF"/>
    <published>2015-07-26T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/configure-of-archlinux.html</id>
    <title>Arch Linux 折腾小记</title>
    <updated>2015-07-20T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="arch-linux"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;这几天一直在折腾 Arch Linux 上的桌面, 弄到今天终于差不多了.
先上张图:&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/configure-of-archlinux.rst&lt;/span&gt;, line 16)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;image&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;image&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;img alt="" src="https://silverrainz.me/_images/archlinux-screenshot.png" /&gt;
&lt;section id="xmonad-wm"&gt;
&lt;h2&gt;以 XMonad 为 WM 的桌面&lt;/h2&gt;
&lt;p&gt;没有用 DE, WM 用的是 XMonad.&lt;/p&gt;
&lt;p&gt;关于 XMonad 的默认快捷键, &lt;a class="reference external" href="http://xmonad.org/tour.html"&gt;XMonad Guide Tour&lt;/a&gt;
这篇官方的这篇文档很容易看懂.&lt;/p&gt;
&lt;p&gt;需要安装的包如下:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;xmonad, xmonad-contrib&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;xmobar&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;dmenu&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;trayer&lt;/span&gt; trayer-srg&lt;sup&gt;AUR&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;feh&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;scrot&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;compton&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;xmobar, 配置文件在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.xmobarrc&lt;/span&gt;&lt;/code&gt;, 是个基于文字的状态栏, 可以显示从 stdin 接收到的内容,
也可以自己获取系统信息, &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;我这里的中文显示还有问题, 部分中文乱码, 应该是字体的锅.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;2015-8-30: 使用 ArchLinux Wiki 中建议的字体, 效果良好.
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;font&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;&amp;quot;xft:Bitstream&lt;/span&gt; &lt;span class="pre"&gt;Vera&lt;/span&gt; &lt;span class="pre"&gt;Sans&lt;/span&gt; &lt;span class="pre"&gt;Mono:size=9:bold:antialias=true&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;dmenu 是个启动器, 功能比较简单, 所以不需要什么特殊的配置, 在 XMonad 里按&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;mod&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;q&lt;/span&gt;&lt;/code&gt;触发.&lt;/p&gt;
&lt;p&gt;trayer 是个系统托盘, 用来容纳各种图标, 启动选项如下:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;2015-8-30: trayer 不支持多个屏幕, 建议使用 AUR 里的 trayer-srg&lt;sup&gt;AUR&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;trayer&lt;span class="w"&gt; &lt;/span&gt;--edge&lt;span class="w"&gt; &lt;/span&gt;top&lt;span class="w"&gt; &lt;/span&gt;--align&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;--widthtype&lt;span class="w"&gt; &lt;/span&gt;percent&lt;span class="w"&gt; &lt;/span&gt;--width&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;       &lt;/span&gt;--SetDockType&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--SetPartialStrut&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--transparent&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--alpha&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;       &lt;/span&gt;--tint&lt;span class="w"&gt; &lt;/span&gt;0x000000&lt;span class="w"&gt; &lt;/span&gt;--expand&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--heighttype&lt;span class="w"&gt; &lt;/span&gt;pixel&lt;span class="w"&gt; &lt;/span&gt;--height&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--monitor&lt;span class="w"&gt; &lt;/span&gt;primary
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;本来已经设置了 xmobar 占据屏幕的 90%, 而 trayer 占 10%,
不过这样仍然会在屏幕上留下间隙, 所以这里设置成占据屏幕的 11%.&lt;/p&gt;
&lt;p&gt;feh 用来设置桌面背景, 设置背景很有必要, 如果不设置的话,
关闭窗口的时候不会有明显的反馈, 浮动窗口也会留下难看的拖影.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;feh&lt;span class="w"&gt; &lt;/span&gt;--bg-scale&lt;span class="w"&gt; &lt;/span&gt;/home/la/Pictures/Wallpapers/blog-bg.jpg
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;scrot 截图的快捷键在 XMonad 的配置文件&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.xmonad/xmonad.hs&lt;/span&gt;&lt;/code&gt;里面绑定:&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;defaultConfig&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;additionalKeys&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controlMask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xK_Print&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sleep 0.2; scrot -s -e &lt;/span&gt;&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;mv $f ~/Pictures/Screenshots/&lt;/span&gt;&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xK_Print&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;scrot -e &lt;/span&gt;&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;mv $f ~/Pictures/Screenshots/&lt;/span&gt;&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-s&lt;/span&gt;&lt;/code&gt;参数可以让你自己选择截图的区域, 不过这个工具竟然没法指定图片的存放位置,
只能在截图后用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-e&lt;/span&gt; &lt;span class="pre"&gt;'mv&lt;/span&gt; &lt;span class="pre"&gt;$f&lt;/span&gt; &lt;span class="pre"&gt;~/Pictures/Screenshots'&lt;/span&gt;&lt;/code&gt;把截图放到指定目录.&lt;/p&gt;
&lt;p&gt;上面这些配置大多写在启动脚本&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;startup.sh&lt;/span&gt;&lt;/code&gt;里, 每个命令后边都得加上一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;amp;&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;无线网络管理&lt;/h2&gt;
&lt;p&gt;为了更方便地连接无线网络, 安装如下包:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;networkmanager&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;network-manager-applet&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gnome-keyring&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意如果你之前连接无线网络用的是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;netctl&lt;/span&gt;&lt;/code&gt;的话, 记得把有关的服务给 disable 了,
因为 networkmanager 和他有冲突, 安装完后执行 NetworkManager 启动服务.&lt;/p&gt;
&lt;p&gt;network-manager-applet 是 networkmanager 的前端.&lt;/p&gt;
&lt;p&gt;似乎不安装 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;gnome-keyring&lt;/span&gt;&lt;/code&gt;的话就无法连上加密的无线网络.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="im"&gt;
&lt;h2&gt;IM&lt;/h2&gt;
&lt;section id="qq"&gt;
&lt;h3&gt;QQ&lt;/h3&gt;
&lt;p&gt;TM2013 可能是运行在 Wine 上表现最好的一个版本了, 我下载了
&lt;a class="reference external" href="http://www.zhihu.com/question/23770274/answer/45703773"&gt;邓攀打包的TM2013&lt;/a&gt;,
似乎没有预期中的 out of box, 字体不行, 密码输入也不行.
不过根据错误提示和 Arch Linux Wiki, 装了几个包就解决问题了.&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;➜&lt;span class="w"&gt;  &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;lib32-ncurses&lt;span class="w"&gt; &lt;/span&gt;lib32-mpg123
&lt;/span&gt;&lt;span data-line="2"&gt;➜&lt;span class="w"&gt;  &lt;/span&gt;winetrick&lt;span class="w"&gt; &lt;/span&gt;riched20&lt;span class="w"&gt; &lt;/span&gt;ie6&lt;span class="w"&gt; &lt;/span&gt;mfc42&lt;span class="w"&gt; &lt;/span&gt;cjkfonts&lt;span class="w"&gt; &lt;/span&gt;wenquanyi
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h3&gt;其他&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;IRC 客户端用火狐的 ChatZilla&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Telegram 客户端用 Cutegram, 得装 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;fcitx-qt5&lt;/span&gt;&lt;/code&gt; 才能正常输入,
另 TG 似乎已经被墙(手机上却仍然可以登录), Cutegram 无法登录, 挂个代理就行.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;qTox 也还凑合, 主要是可以听歌.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="gtk"&gt;
&lt;h2&gt;GTK&lt;/h2&gt;
&lt;p&gt;默认的 gtk 界面在 XMonad 下相当地丑, 可以安装&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;lxappearance&lt;/span&gt;&lt;/code&gt;来调整 GTK 的主题.&lt;/p&gt;
&lt;p&gt;对于 Qt 程序, dolphin 有很好看的外观, 但是同为 kde-applications 的
konsole 的界面却依然很丑...&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/configure-of-archlinux.rst&lt;/span&gt;, line 141)&lt;/p&gt;
&lt;p&gt;No directive entry for &amp;quot;topic&amp;quot; in module &amp;quot;docutils.parsers.rst.languages.zh_cn&amp;quot;.
Using English fallback for directive &amp;quot;topic&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="topic"&gt;
&lt;p class="topic-title"&gt;Update&lt;/p&gt;
&lt;p&gt;2015-7-24: 经过 IRC 里 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-farseerfc" title="friend farseerfc"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 前辈和 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-quininer" title="friend quininer"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 的 &lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;调教&lt;/span&gt; ,
发现原来 dolphin 还是 kde4 而 konsole 已经是 kde5 了.&lt;/p&gt;
&lt;p&gt;2015-8-30: 安装社区源&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;gnome-breeze-git&lt;/span&gt;&lt;/code&gt;主题, 以及 plasma5 的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;breeze&lt;/span&gt;&lt;/code&gt;主题,
可以有比较统一的外表. 设置 Qt5 应用程序的主题可以设置环境变量&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;QT_STYLE_OVERRIDE=breeze&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;输入法:&lt;/h2&gt;
&lt;p&gt;在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.xprofile&lt;/span&gt;&lt;/code&gt;中加入:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GTK_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fcitx
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;QT_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fcitx
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;XMODIFIERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;@im=fcitx&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;并在启动脚本里启动 fcitx.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;配置文件&lt;/h2&gt;
&lt;p&gt;上面有提到的全部配置文件参见:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/SilverRainZ/dotfiles"&gt;SilverRainZ/dotfiles - Github&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/configure-of-archlinux.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Linux" label="Linux"/>
    <published>2015-07-20T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/install-vim-plugins.html</id>
    <title>Vim 插件折腾记录</title>
    <updated>2015-07-02T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="vim"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;今天考完计组, 有一个空闲的下午, 于是决定来配一配 vim, 装了几个插件, 记录如下:&lt;/p&gt;
&lt;p&gt;首先我把本来 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vimrc&lt;/span&gt;&lt;/code&gt; 里所有对于 Windows 的特殊配置都删除了, 反正现在也不怎么用 Windows,
同时维护兼容两个平台的配置文件实在是麻烦.&lt;/p&gt;
&lt;section id="fcitx-vim"&gt;
&lt;h2&gt;fcitx.vim&lt;/h2&gt;
&lt;p&gt;这个是 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-lilydjwg" title="friend lilydjwg"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 写的插件, 用来在普通模式关闭输入法, 插入模式自动恢复上次的输入法状态.
(当然你用的得是 fctix)&lt;/p&gt;
&lt;aside class="system-message"&gt;
&lt;p class="system-message-title"&gt;System Message: INFO/1 (&lt;span class="docutils literal"&gt;/home/runner/work/silverrainz.github.io/silverrainz.github.io/src/blog/install-vim-plugins.rst&lt;/span&gt;, line 3); &lt;em&gt;&lt;a href="#id1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Duplicate implicit target name: &amp;quot;fcitx.vim&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;从这里可以下载: &lt;a class="reference external" href="http://www.vim.org/scripts/script.php?script_id=3764"&gt;fcitx.vim&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;这个插件的安装很容易, 最简单的方式是直接把 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;so/fctix.vim&lt;/span&gt;&lt;/code&gt;
放到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vim/plugin&lt;/span&gt;&lt;/code&gt; 目录下就好, 最好在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vimrc&lt;/span&gt;&lt;/code&gt; 里加上一句: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;set&lt;/span&gt; &lt;span class="pre"&gt;ttimeoutlen=100&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果想要启用 Python 支持的话, 要加入一个环境变量:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FCITX_SOCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/fcitx-remote.sock
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;不过我试了试发现报错: socket connection error, 就不去用它了.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="vundle"&gt;
&lt;h2&gt;Vundle&lt;/h2&gt;
&lt;p&gt;神器, 用来管理插件的插件, 可以从 GitHub, 其他 Git 服务器或者本地的 Git 目录获取并安装插件,
把 &lt;a class="reference external" href="https://github.com/gmarik/Vundle.vim"&gt;gmarik/Vundle.vim&lt;/a&gt; clone 到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vim&lt;/span&gt;&lt;/code&gt; 下,
在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vimrc&lt;/span&gt;&lt;/code&gt; 里添加如下内容:&lt;/p&gt;
&lt;div class="highlight-vim notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;nocompatible&lt;/span&gt;              &lt;span class="c"&gt;&amp;quot; be iMproved, required&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;filetype&lt;/span&gt; off                  &lt;span class="c"&gt;&amp;quot; required&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="c"&gt;&amp;quot; set the runtime path to include Vundle and initialize&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;+=~&lt;/span&gt;&lt;span class="sr"&gt;/.vim/&lt;/span&gt;bundle/Vundle.&lt;span class="k"&gt;vim&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="k"&gt;call&lt;/span&gt; vundle#begin&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="c"&gt;&amp;quot; alternatively, pass a path where Vundle should install plugins&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="c"&gt;&amp;quot;call vundle#begin(&amp;#39;~/some/path/here&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="c"&gt;&amp;quot; let Vundle manage Vundle, required&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;Plugin &lt;span class="s1"&gt;&amp;#39;gmarik/Vundle.vim&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="c"&gt;&amp;quot; All of your Plugins must be added before the following line&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="k"&gt;call&lt;/span&gt; vundle#&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="c"&gt;&amp;quot; required&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="k"&gt;filetype&lt;/span&gt; plugin indent &lt;span class="k"&gt;on&lt;/span&gt;    &lt;span class="c"&gt;&amp;quot; required&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="c"&gt;&amp;quot; To ignore plugin indent changes, instead use:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="c"&gt;&amp;quot;filetype plugin on&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="c"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="c"&gt;&amp;quot; Brief help&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="c"&gt;&amp;quot; :PluginList       - lists configured plugins&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="c"&gt;&amp;quot; :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="c"&gt;&amp;quot; :PluginSearch foo - searches for foo; append `!` to refresh local cache&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="c"&gt;&amp;quot; :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="c"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="c"&gt;&amp;quot; see :h vundle for more details or wiki for FAQ&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="c"&gt;&amp;quot; Put your non-Plugin stuff after this line&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;然后重启 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:PluginInstall&lt;/span&gt;&lt;/code&gt;, 就安装好了, 如果想要添加新的插件, 在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Plugin&lt;/span&gt; &lt;span class="pre"&gt;'...'&lt;/span&gt;&lt;/code&gt;
那一句之后添加 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Plugin&lt;/span&gt; &lt;span class="pre"&gt;'插件地址'&lt;/span&gt;&lt;/code&gt; 再 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:PluginInstall&lt;/span&gt;&lt;/code&gt; 一下就好了.
对于在 GitHub 上的插件地址, 可以直接写 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;owner/repo-name&lt;/span&gt;&lt;/code&gt; 这样的形式.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="powerline"&gt;
&lt;h2&gt;PowerLine&lt;/h2&gt;
&lt;p&gt;漂亮的状态栏插件&lt;/p&gt;
&lt;p&gt;在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;.vimrc&lt;/span&gt;&lt;/code&gt; 相应位置里加一句 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Plugin&lt;/span&gt; &lt;span class="pre"&gt;'Lokaltog/vim-powerline'&lt;/span&gt;&lt;/code&gt;,
再 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;:PluginInstall&lt;/span&gt;&lt;/code&gt;, 加上如下配置:&lt;/p&gt;
&lt;div class="highlight-vim notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c"&gt;&amp;quot; powerline&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;nocompatible&lt;/span&gt;    &lt;span class="c"&gt;&amp;quot; 不兼容 vi&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;t_Co&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;256&lt;/span&gt;        &lt;span class="c"&gt;&amp;quot; 终端颜色&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;laststatus&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;    &lt;span class="c"&gt;&amp;quot; 显示状态栏&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;utf8
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:Powerline_symbols &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;compatible&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="c"&gt;&amp;quot; 值为&amp;#39;fancy&amp;#39;的话,状态栏会有好看的箭头, 但是要打过补丁的字体, 太麻烦了&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="nerdtree"&gt;
&lt;h2&gt;Nerdtree&lt;/h2&gt;
&lt;p&gt;文件浏览插件, 还是用 Vundle 安装.&lt;/p&gt;
&lt;div class="highlight-vim notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c"&gt;&amp;quot; A tree explorer plugin for vim.&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;Plugin &lt;span class="s1"&gt;&amp;#39;scrooloose/nerdtree&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="c"&gt;&amp;quot; nerdtree&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;map &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :NERDTreeToggle&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="youcompleteme"&gt;
&lt;h2&gt;YouCompleteMe&lt;/h2&gt;
&lt;p&gt;据说是最好的 C/C++ 补全插件? 这个安装略波折.
首先用 Vundle 安装:&lt;/p&gt;
&lt;div class="highlight-vim notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="c"&gt;&amp;quot; A code-completion engine for Vim&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;Plugin &lt;span class="s1"&gt;&amp;#39;Valloric/YouCompleteMe&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;安装时提示 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;YouCompleteMe&lt;/span&gt; &lt;span class="pre"&gt;unavailable:&lt;/span&gt; &lt;span class="pre"&gt;requires&lt;/span&gt; &lt;span class="pre"&gt;Vim&lt;/span&gt; &lt;span class="pre"&gt;compiled&lt;/span&gt; &lt;span class="pre"&gt;with&lt;/span&gt; &lt;span class="pre"&gt;Python&lt;/span&gt; &lt;span class="pre"&gt;2.x&lt;/span&gt; &lt;span class="pre"&gt;support.&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;即我这个版本的 vim 编译时没有 Python 2 的支持, 可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;vim&lt;/span&gt; &lt;span class="pre"&gt;--version&lt;/span&gt;&lt;/code&gt; 查看是否开启,
没有开启的话会有 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;-python&lt;/span&gt;&lt;/code&gt; 这一项.&lt;/p&gt;
&lt;p&gt;openSUSE 默认源里的 vim 是没有编译入 Python 2 支持的, 所以得手动编译.
(后来知道在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;editor&lt;/span&gt;&lt;/code&gt; 源里有vim)&lt;/p&gt;
&lt;p&gt;首先从 &lt;a class="reference external" href="ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2"&gt;vim-7.4.tar.bz2&lt;/a&gt;
下载 vim 7.4 的源码, 解压.&lt;/p&gt;
&lt;p&gt;删除原来的 vim&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;gvim
&lt;/span&gt;&lt;span data-line="2"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;vim
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;先安装各种依赖包:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python-devel
&lt;/span&gt;&lt;span data-line="2"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ruby-devel
&lt;/span&gt;&lt;span data-line="3"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;lua-devel
&lt;/span&gt;&lt;span data-line="4"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ncurses-devel
&lt;/span&gt;&lt;span data-line="5"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt;  &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;libx11-devel
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;编译:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;./configure&lt;span class="w"&gt; &lt;/span&gt;--with-features&lt;span class="o"&gt;=&lt;/span&gt;huge&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-rubyinterp&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-pythoninterp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--with-python-config-dir&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib64/python2.7/config&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-perlinterp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--with-x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-gui&lt;span class="o"&gt;=&lt;/span&gt;gtk2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-cscope&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-luainterp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-perlinterp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-multibyte&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;/usr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;            &lt;/span&gt;--enable-fail-if-missing
&lt;/span&gt;&lt;span data-line="14"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;make
&lt;/span&gt;&lt;span data-line="15"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;install
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;安装后就可以编译 YCM 了:&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;llvm-clang&lt;span class="w"&gt; &lt;/span&gt;cmake
&lt;/span&gt;&lt;span data-line="2"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.vim/bundle/YouCompleteMe
&lt;/span&gt;&lt;span data-line="3"&gt;$&lt;span class="w"&gt; &lt;/span&gt;~&lt;span class="w"&gt; &lt;/span&gt;./install.sh
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;安装完成.&lt;/p&gt;
&lt;p&gt;截图一张:&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/vim-plugin-screenshot.png" src="https://silverrainz.me/_images/vim-plugin-screenshot.png" /&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/install-vim-plugins.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Vim" label="Vim"/>
    <published>2015-07-02T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/first-attempt-of-python.html</id>
    <title>Python 初试</title>
    <updated>2015-06-15T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="python"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;因为现在经常在三个系统(Win, openSUSE, Arch)之间切换, 一些软件的配置文件的部署成了问题,
每次都从一台机复制到另一台实在麻烦, 而且不知道哪台电脑上使用的配置是最新改动的.&lt;/p&gt;
&lt;p&gt;所以后来就把配置文件托管到了GitCafe, 后来因为用不惯 GitCafe 的 web 界面,
还是在把配置文件放在 GitHub 上了:
&lt;a class="reference external" href="https://github.com/SilverRainZ/dotfiles"&gt;https://github.com/SilverRainZ/dotfiles&lt;/a&gt;
(不过还是觉得更新这些配置文件的 Commit 太影响我的 ContributionsCalendar 了)&lt;/p&gt;
&lt;p&gt;即使托管到 Github, 每次把文件拉下来都要复制到相应的位置上去, 依然麻烦,
所以就打算写个脚本来帮忙, 但是我并不会任何一门脚本
(Batch和Shell这些不跨平台的就算了...写起来又麻烦), 所以就现学现卖用 Python 试一试,
花了一个晚上, 写了个100来行的小脚本(有够慢的).
&lt;a class="reference external" href="https://github.com/SilverRainZ/dotfiles/blob/master/sync.py"&gt;https://github.com/SilverRainZ/dotfiles/blob/master/sync.py&lt;/a&gt;&lt;/p&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;脚本&lt;/h2&gt;
&lt;p&gt;这个脚本的功能很简单, 就是根据指定的参数, 把指定的配置从仓库中复制到用户目录(deploy),
或者把用户目录下的配置复制到仓库(collect).&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;这样都能写100多行!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;现在只支持我常用的三个软件的配置: vim, pentadacytl, zsh.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;sync&lt;/span&gt;   &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;simple&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;    &lt;span class="n"&gt;deploy&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s profiles form repo to local&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;    &lt;span class="n"&gt;collect&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s profiles form local to repo&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;    &lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;reomote&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;    &lt;span class="n"&gt;pull&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;pull&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="n"&gt;reomote&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;    &lt;span class="n"&gt;vim&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;    &lt;span class="n"&gt;zsh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;    &lt;span class="n"&gt;pen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pentadactyl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;    &lt;span class="nb"&gt;all&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;zsh&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pen&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;python3&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;缩进&lt;/h2&gt;
&lt;p&gt;Python 的一大特点就是用缩进来划分代码块, 这会让 if 的嵌套变得很不清晰,
偏偏又不提供 switch 语句或者 Pattern Matching, 所以代码中的各种 if 又省不了,
这个有点痛苦. 不过 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;if&lt;/span&gt; &lt;span class="pre"&gt;xx&lt;/span&gt; &lt;span class="pre"&gt;in&lt;/span&gt; &lt;span class="pre"&gt;[...]&lt;/span&gt;&lt;/code&gt; 这样的语法我倒是觉得挺好的,
避免了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;if&lt;/span&gt; &lt;span class="pre"&gt;a==xx&lt;/span&gt; &lt;span class="pre"&gt;||&lt;/span&gt; &lt;span class="pre"&gt;a&lt;/span&gt; &lt;span class="pre"&gt;==&lt;/span&gt; &lt;span class="pre"&gt;xxx&lt;/span&gt; &lt;span class="pre"&gt;||&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt;&lt;/code&gt; 这样的超长 if.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h2&gt;函数式特性&lt;/h2&gt;
&lt;p&gt;再跑一下题, 我在这学期看了 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-fleuria" title="friend fleuria"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 的 &lt;a class="any any-book reference internal" href="notes/books/index.html#book-Haskell" title="book Haskell 趣学指南"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt;, 自觉 Haskell 这门语言难以入门,
至今写过的代码也不过寥寥数行, 只能算是大概了解了他的语法, 却因此沾染上了一些「恶习」,
老想在其他语言里使用那些FP的语法特性, 或者是当用这些特定可以让代码更好的时候,
抱怨 xxx 怎么没有这个语法. 我自己都觉得有点可笑, 不过, Python 一定程度上满足了我这奇怪的要求.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h2&gt;高阶函数&lt;/h2&gt;
&lt;p&gt;很高兴 Python 里面提供了部分函数式语言的特性, 我在这个小脚本里用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;用得很爽.
sync.py 这个脚本是一个带参数运行的小工具, 需要输出 help 信息, 本来我是这样写的:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sync -- a simple script used to sync profile&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;python sync.py [operation]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;python sync.py [operation] [target]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;有了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;, 可以把所有的 help 信息放在一个 list 里面, 再用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;对每个元素应用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;print&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;helpstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sync -- a simple script used to sync profile&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;python sync.py [operation]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;python sync.py [operation] [target]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;          &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helpstr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注意这里不能直接&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map(print,&lt;/span&gt; &lt;span class="pre"&gt;helpstr)&lt;/span&gt;&lt;/code&gt;, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;返回一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;generator&lt;/span&gt;&lt;/code&gt;,
而&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;list()&lt;/span&gt;&lt;/code&gt;接受一个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;generator&lt;/span&gt;&lt;/code&gt;得到一个列表, 这样&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;print&lt;/span&gt;&lt;/code&gt;才会得以执行.(大概是这样?)&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;不仅在这里有用到, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;deploy&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;collect&lt;/span&gt;&lt;/code&gt;是两个相反的操作, 无非是把两个地址交换,
地址被存在一个二元组的列表里, 所以可以用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;翻转:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;deploy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="id5"&gt;
&lt;h2&gt;被弃用的元组参数解包&lt;/h2&gt;
&lt;p&gt;本来上面那个翻转元组的 lambda 在 Python 2+ 可以这么写:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;类似模式匹配的写法感觉很不错, 可是不知道为什么在 3.0 中这个语法被移除了.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id6"&gt;
&lt;h2&gt;部分应用&lt;/h2&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;map&lt;/span&gt;&lt;/code&gt;只能对 list 映射只有一个参数的函数, 在 Haskell 中我们可以用部分应用
获得一个只需要一个参数的函数, 在 Python 中似乎不能直接做到, 但我们有折衷的办法:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;g_target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;用一个 lambda 来使得&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;deploy&lt;/span&gt;&lt;/code&gt;对外只有一个参数.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id7"&gt;
&lt;h2&gt;库&lt;/h2&gt;
&lt;p&gt;Python 库大概是 Python 备受推崇的一个重要原因, 可惜我的脚本只是在做文件复制,
没有用到什么特别的库.&lt;/p&gt;
&lt;p&gt;不过拜 Python 良好的跨平台能力, 我不需要为处理 Windows 和 Linux 下不同的文件操作各写一份代码,
只需要对路径做些处理就行了.&lt;/p&gt;
&lt;p&gt;&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;感觉好像什么都没写啊(摔...&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/first-attempt-of-python.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Python" label="Python"/>
    <published>2015-06-15T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/threee-way-of-anti-debug.html</id>
    <title>几种简单的反调试方法</title>
    <updated>2015-05-19T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="id1"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;这里面没有什么自己的东西,
都是从看雪的&lt;a class="reference external" href="http://bbs.pediy.com/showthread.php?t=184679"&gt;OD从零系列教程&lt;/a&gt;里看来的.
最近看到的几章都是讲反调试的, 虽然对其本质还没有去深入了解,
还是觉得应该先把这些记下来.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;下面的一些信息是基于自己现有的知识推测出来的, 不一定对.&lt;/em&gt;
关于函数的说明, 都是基于MSDN的粗浅翻译, 要想了解更准确的信息, 请查阅MSDN.&lt;/p&gt;
&lt;section id="x0-isdebuggerparent"&gt;
&lt;h2&gt;0x0  利用IsDebuggerParent()&lt;/h2&gt;
&lt;section id="x0-0"&gt;
&lt;h3&gt;0x0.0 介绍&lt;/h3&gt;
&lt;p&gt;该函数检测程序是否正在被调试, 是的话返回1,否则返回0,
该函数位于&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Kernel32.dll&lt;/span&gt;&lt;/code&gt;中, 其代码如下:&lt;/p&gt;
&lt;div class="highlight-nasm notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;dword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mh"&gt;0x18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;dword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x30&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;movzx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;fs寄存器指示了(并不是储存了)&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PEB&lt;/span&gt;&lt;/code&gt;(Process Environment Block)的地址,
因为GDT的关系,fs寄存器中储存的只是选择子而不是地址,
因此要从fs的0x18偏移处取一个指向自己的self指针(这一步实际上是可以省略的).&lt;/p&gt;
&lt;p&gt;接下来从&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PEB&lt;/span&gt;&lt;/code&gt;的0x30偏移处取得&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;NT_TIB&lt;/span&gt;&lt;/code&gt;结构的首地址,
该结构的0x2偏移处是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;BeingDebugged&lt;/span&gt;&lt;/code&gt;字段, 表示当前进程是否被调试,
因此通过这个函数可以检测调试器.&lt;/p&gt;
&lt;p&gt;你可以在代码中直接使用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;IsDebuggerParent&lt;/span&gt;&lt;/code&gt;或者嵌入等价的汇编代码.
动态载入函数比直接引入好些.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x0-1"&gt;
&lt;h3&gt;0x0.1 栗子&lt;/h3&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="cm"&gt;/* 内联汇编 */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* 这里的 movl %fs:30, %ebx 就相当于&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="cm"&gt;     * mov eax, dword ptr fs:[0x18]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="cm"&gt;     * mov eax, dword ptr fs:[eax + 0x30]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="cm"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;asm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;movl %fs:0x30, %ebx; movzx 2(%ebx), %eax&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="cm"&gt;/* 动态载入 */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HINSTANCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kern_lib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LoadLibraryEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;kernel32.dll&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kern_lib&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FARPROC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lIsDebuggerPresent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetProcAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kern_lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IsDebuggerPresent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lIsDebuggerPresent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lIsDebuggerPresent&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FreeLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kern_lib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="cm"&gt;/* 测试的时候记得关掉OD的插件, 或者直接用原版 */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="x0-2"&gt;
&lt;h3&gt;0x0.2 绕过&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;如果能定位到函数的话, 修改他的流程.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可以在载入程序后, 把那个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;BeingDebugged&lt;/span&gt;&lt;/code&gt;位置0,
当然, HideDebugger插件已经替我们做了这件事.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="x1-i"&gt;
&lt;h2&gt;0x1 检测进程名I&lt;/h2&gt;
&lt;section id="x1-0"&gt;
&lt;h3&gt;0x1.0 介绍&lt;/h3&gt;
&lt;p&gt;通过检测特定调试器(常常是OD)的进程是否存在来防止被调试.&lt;/p&gt;
&lt;p&gt;用到了下面几个API:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;EnumProcesses&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumProcesses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pProcessIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pBytesReturned&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;EnumProcesses 枚举所有的进程PID, 第一个参数是缓冲区, 储存所有进程PID的列表,
参数二是以byte计数的数组长度, 参数三是阶收到的数组长度, 同样以byte计数.
函数执行成功返回非零值.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;GetModuleBaseNameA&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetModuleBaseName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;hProcess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_opt_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HMODULE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;LPTSTR&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;lpBaseName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;nSize&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;该函数取得某个模块的名称, 参数一是线程句柄,  参数二是模块句柄,
参数三是储存返回模块名的缓冲区, 最后是缓冲区的长度, 以char计数.
函数执行成功则返回接收到的模块名的长度&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;OpenProcess&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OpenProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dwDesiredAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bInheritHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dwProcessId&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;该函数通过PID(参数4)获得进程句柄失败则返回NULL.
(获得句柄后可以在OD的H窗口看到该句柄).&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;EnumProcessModules&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumProcessModules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;hProcess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HMODULE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lphModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LPDWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lpcbNeeded&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;函数枚举指定进程里的所有Modules, 取回句柄. 参数一指定了进程句柄,
参数二是返回的模块句柄缓冲区, 参数三是以byte计数的缓冲区大小,
四是最终取回句柄的大小, byte计数. 函数执行成功返回非零值.&lt;/p&gt;
&lt;p&gt;利用这些函数检测调试器的经典过程是这样的:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;首先用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;GetProcAddress&lt;/span&gt;&lt;/code&gt;动态载入上面的其他函数&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;EnumProcesses&lt;/span&gt;&lt;/code&gt;对所有进程进行枚举, 实际上是获得一个储存了所有进程PID的列表&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;以获取到的PID为参数调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OpenProcess&lt;/span&gt;&lt;/code&gt;, 取得进程句柄&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用获取到的句柄执行&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;EnumProcessModules&lt;/span&gt;&lt;/code&gt;枚举进程的模块, 只取第一个模块&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用进程句柄和模块句柄为参数调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;GetModuleBaseNameA&lt;/span&gt;&lt;/code&gt;得到进程名&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;和要检测的进程名作比较, 这决定了程序的流程&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果是待检测进程的话, 选择自行退出或者是结束调试器, 可能用到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;TerminatePorcess&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;CloseHandle&lt;/span&gt;&lt;/code&gt;关闭句柄&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id="x1-1"&gt;
&lt;h3&gt;0x1.1 栗子&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;//TODO&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x1-2"&gt;
&lt;h3&gt;0x1.2 绕过&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;令OpenProcess始终返回&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;NULL&lt;/span&gt;&lt;/code&gt;, 打不开任何进程.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;改动OpenProcess后的程序流程&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;更改OD的名字, 进程名也会同时被更改;(最简单的做法了)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="x2-ii"&gt;
&lt;h2&gt;0x2 检测进程名II&lt;/h2&gt;
&lt;section id="x2-0"&gt;
&lt;h3&gt;0x2.0 介绍&lt;/h3&gt;
&lt;p&gt;使用的API:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;CreateToolhelp32Snapshot&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateToolhelp32Snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dwFlags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;th32ProcessID&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;该函数对指定的进程做快照, dwFlags参数决定进程的那一部分会被包含在快照中.
参数二为PID, 返回快照句柄. 指定参数 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,&lt;/span&gt; &lt;span class="pre"&gt;0)&lt;/span&gt;&lt;/code&gt;
则对系统中所有的进程进行快照, 可以被&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Process32First&lt;/span&gt;&lt;/code&gt;进行枚举.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Process32First&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Process32First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;hSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Inout_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LPPROCESSENTRY32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lppe&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在快照中取得第一个进程的相关信息.
参数一: 由CreateToolhelp32Snapshot返回的快照句柄.
参数二: 指向PORCESSENTRY32结构体的指针, 包含可执行文件名, PID,和父进程PID等.
执行成功返回true.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Process32Next&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Process32Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HANDLE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;hSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_Out_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LPPROCESSENTRY32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lppe&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;取回快照中下一个进程的信息(然而你必须先用Process32First取第一个), 参数和Process32First基本相同.&lt;/p&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Process32First&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Process32Next&lt;/span&gt;&lt;/code&gt;中涉及到的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PPROCESSENTRY32&lt;/span&gt;&lt;/code&gt;结构体如下:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;PROCESSENTRY32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;structure&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;tagPROCESSENTRY32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;dwSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;cntUsage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;th32ProcessID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ULONG_PTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;th32DefaultHeapID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;th32ModuleID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;cntThreads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;th32ParentProcessID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;LONG&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;pcPriClassBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DWORD&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;dwFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;TCHAR&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;szExeFile&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_PATH&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCESSENTRY32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PPRO&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后一个参数就是进程名了好像.&lt;/p&gt;
&lt;p&gt;利用该方法检测进程的基本流程是:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;调用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,&lt;/span&gt; &lt;span class="pre"&gt;0)&lt;/span&gt;&lt;/code&gt;获得所有进程快照&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Process32First&lt;/span&gt;&lt;/code&gt;取得第一个进程的信息, 判断是否是要检测的进程&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Process32Next&lt;/span&gt;&lt;/code&gt;循环检测其他进程&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="x2-1"&gt;
&lt;h3&gt;0x2.1 栗子&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;//TODO&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x2-2"&gt;
&lt;h3&gt;0x2.2 绕过&lt;/h3&gt;
&lt;p&gt;绕过的做法基本同I.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;检测窗口类名&lt;/h2&gt;
&lt;section id="x3-0"&gt;
&lt;h3&gt;0x3.0 介绍&lt;/h3&gt;
&lt;p&gt;又是API...&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;FindWindowA&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;HWND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WINAPI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FindWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_opt_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LPCTSTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lpClassName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_In_opt_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LPCTSTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lpWindowName&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;该函数取回和参数匹配的顶级窗口的句柄, 大小写不敏感.&lt;/p&gt;
&lt;p&gt;参数一: 窗口类名
参数二: 窗口名
参数可选, 至少一个, 另一个可置NULL.
执行成功返回句柄.&lt;/p&gt;
&lt;p&gt;因为OD的窗口名常常不确定, 利用窗口类名往往比较靠谱;
将窗口名置NULL, 检测OD的顶级窗体类名即可, 该类名可以通过Spy++得到.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x3-1"&gt;
&lt;h3&gt;0x3.1 栗子&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;//TODO&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x3-2"&gt;
&lt;h3&gt;0x3.2 绕过&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;HideDebugger插件有绕过 FindWindowA/EnumWindows 的选项;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用RE-Pair为OD主程序打补丁, 可更改其类名&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="x3-unhandledexcepitonzwqueryinformationprocess"&gt;
&lt;h2&gt;0x3 UnhandledExcepiton和ZwQueryInformationProcess&lt;/h2&gt;
&lt;p&gt;这种反调试方法比前面的方法更具技巧性一些, 利用了Windows的异常处理机制,
但是我还不了解这些异常处理, 不敢胡说,暂时略过.&lt;/p&gt;
&lt;p style="display:none;"&gt;

* SetUnhandledExceptionFilter

``c
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
  _In_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
``
该函数让应用程序可以取代该进程中所有线程的系统异常处理函数.(大概是吧...)

&gt; Enables an application to supersede the top-level exception handler of each
&gt; thread of a process.

调用该函数后, 如果有异常发生, 且该进程当前没有被调试,
则该异常会被 `Unhandled Exception Filter`处理 , Filter会调用异常筛选(?)函数,
该函数由参数一指定.

&gt; After calling this function, if an exception occurs in a process that is not being debugged,
&gt; and the exception makes it to the unhandled exception filter,
&gt; that filter will call the exception filter function specified by the
&gt; lpTopLevelExceptionFilter parameter.

* UnhandledExceptionFilter

``c
LONG WINAPI UnhandledExceptionFilter(
  _In_ struct _EXCEPTION_POINTERS *ExceptionInfo
);
``

如果当前进程被调试的话, 程序定义的函数(?)会将未处理的异常传递给调试器.
否则, 它将可选地显示一个应用程序错误的消息框, 并使得异常处理函数执行.
该函数只能在异常处理例程中的Filter Expression中被调用.

&gt; An application-defined function that passes unhandled exceptions to the debugger,
&gt; if the process is being debugged. Otherwise,
&gt; it optionally displays an Application Error message box and causes the exception handler to be executed.
&gt; This function can be called only from within the filter expression of an exception handler.

该函数唯一的参数是一个`EXCEPTION_POINTERS`指针,
指定了对此异常的描述和发生异常时的上下文.

&gt; A pointer to an `EXCEPTION_POINTERS` structure that specifies a description
&gt; of the exception and the processor context at the time of the exception.

&gt; 发生异常时系统的处理顺序(by Jeremy Gordon, Hume):
&gt; 1. 系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应该发送,
&gt;    并且目标程序正在被调试,则系统挂起程序并向调试器发送`EXCEPTION_DEBUG_EVENT`消息.
&gt; 1. 如果你的程序没有被调试或者调试器未能处理异常,
&gt;    系统就会继续查找你是否安装了线程相关的异常处理例程,
&gt;    如果你安装了线程相关的异常处理例程,系统就把异常发送给你的程序seh处理例程,
&gt;    交由其处理.
&gt; 1. 每个线程相关的异常处理例程可以处理或者不处理这个异常,
&gt;    如果他不处理并且安装了多个线程相关的异常处理例程, 可交由链起来的其他例程处理.
&gt; 1. 如果这些例程均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知debugger.
&gt; 1. *如果程序未处于被调试状态或者debugger没有能够处理,
&gt;    并且你调用SetUnhandledExceptionFilter安装了最后异常处理例程的话,系统转向对它的调用.*
&gt; 1. *如果你没有安装最后异常处理例程或者他没有处理这个异常,
&gt;    系统会调用默认的系统处理程序(UnhandledExceptionFilter),通常显示一个对话框,
&gt;    你可以选择关闭或者最后将其附加到调试器上的调试按钮.
&gt;    如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用ExitProcess终结程序.*
&gt; 1. 不过在终结之前,系统仍然对发生异常的线程异常处理句柄来一次展开,
&gt;    这是线程异常处理例程最后清理的机会.

利用这两个函数的流程可能是:

1. 当点击CM中的check按钮时, 程序抛出不可忽略的异常, 因为程序正在被调试,
   所以系统将异常传递给调试器(EXCEPITON_DEBUG_EVENT),
   `SetUnhandledExceptionFilter`指定的异常处理函数并没有被执行
   (实际上这个函数里放置的应该是程序的真正流程).
2. 然而OD并不能处理这个异常, 因此最终将调用`UnhandledExceptionFilter`处理异常.

在`UnhandledExceptionFilter`中有函数`ZwQueryInfomationProcess`,
可以用来判断程序是否被调试, 它是随着`UnhandledExceptionFilter`被调用(在系统领空中),
但是这个函数也可以单独抽取出来被调用.

``c
NTSTATUS WINAPI ZwQueryInformationProcess(
  _In_      HANDLE           ProcessHandle,
  _In_      PROCESSINFOCLASS ProcessInformationClass,
  _Out_     PVOID            ProcessInformation,
  _In_      ULONG            ProcessInformationLength,
  _Out_opt_ PULONG           ReturnLength
);
``

取得特定进程的信息.
在这里只需要知道使ProcessInformationClass = ProcessDebugPort (7),
就可以从ProcessInformation缓冲区中取得ProcessInformationLength长度的信息,
返回FFFFFFFF的话表示正在被调试, 返回0反之. 对应上面步骤f的:

如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用ExitProcess终结程序.
如果正在调试(返回FFFFFFF)的话-&gt;异常传递给调试器-&gt;调试器处理不了-&gt;程序退出.
按教程的说法和实际测试的得到: 如果返回0的话跳转到SetUnhandledExceptionFilter指定的函数,
利用异常实现了反调试.

可是执行SetUnhandledExceptionFilter指定的函数不是在步骤c吗,
UnhandledExceptionFilter可是步骤6才执行的?

### 绕过

* 手动修改ZwQueryInformationProcess返回值
* HideDebugger插件的UnhandledExceptionTricks选项可以绕过此反调试.
* HideOD插件可以单独绕过ZwQueryInformationProcess(记住勾选AutoRun)
&lt;/p&gt;&lt;/section&gt;
&lt;section id="x4-ntglobalflag-processheap-outputdebugstringa"&gt;
&lt;h2&gt;0x4 NtGlobalFlag,ProcessHeap,OutputDebugStringA&lt;/h2&gt;
&lt;p&gt;这几个都比较简单, 从略.&lt;/p&gt;
&lt;section id="ntglobalflag"&gt;
&lt;h3&gt;NtGlobalFlag&lt;/h3&gt;
&lt;p&gt;该标志在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;PEB&lt;/span&gt;&lt;/code&gt;中,对于x86, 在0x68处
对于x64, 在 0xbc 处.&lt;/p&gt;
&lt;p&gt;定位到PEB:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;在EIP入口点定位到EBP的值;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;或者定位到FS:[0x18];&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NtGlobalFlag 默认总是0, 除非它被一个调试器所附加.
当调试器创建一个进程时, NtGlobalFlag会有如下的值:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FLG_HEAP_ENABLE_TAIL_CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FLG_HEAP_ENABLE_FREE_CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FLG_HEAP_VALIDATE_PARAMETERS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;因此, 如果&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;NtGlobalFlag&lt;/span&gt; &lt;span class="pre"&gt;==&lt;/span&gt; &lt;span class="pre"&gt;0x10&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;0x20&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;0x40&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt;&amp;#160; &lt;span class="pre"&gt;0x70&lt;/span&gt;&lt;/code&gt;时, 程序正在被调试.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="processheap"&gt;
&lt;h3&gt;ProcessHeap&lt;/h3&gt;
&lt;p&gt;在PEB的 0x10 偏移处的一个 DWORD, 不为0则表示正在被调试.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="outputdebugstringa"&gt;
&lt;h3&gt;OutputDebugStringA&lt;/h3&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;OutputDebugStringA&lt;/span&gt;&lt;/code&gt;是个函数, 该函数向调试器输出一个字符串,
它能用于反调试是因为OD的一个bug, 当用这个函数输出一长串的%s字串时, OD会崩溃.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x4-1"&gt;
&lt;h3&gt;0x4.1 栗子&lt;/h3&gt;
&lt;p&gt;无&lt;/p&gt;
&lt;/section&gt;
&lt;section id="x4-2"&gt;
&lt;h3&gt;0x4.2 绕过&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;修改对应的值&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HideOD 插件的 HideNtDebugBit选项, 以及 OutDebugStringA 选项或
Hide Debugger插件的OutputDebugString exploit选项&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/threee-way-of-anti-debug.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Reverse" label="Reverse"/>
    <published>2015-05-19T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/record-of-a-boring-hack.html</id>
    <title>记一次毫无技术含量的 Hack</title>
    <updated>2015-05-12T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="hack"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;早上起晚了, 八点的汇编实验课七点三十五才起床, 起来抄完待会要交的作业然后去等公交,
大概八点二十分到机房, 老师并没有说什么.&lt;/p&gt;
&lt;p&gt;这几天的心情不是太爽, 因此实验课没打算做作业. 然而桌面上有个OD, 就随便打开来看看了.&lt;/p&gt;
&lt;p&gt;「学校的用的防护软件不会这么渣吧?」我是这样想的, 但不妨一试, 反正试了也不花钱.&lt;/p&gt;
&lt;p&gt;系统是古旧的XP, 在托盘那里有SQLServer, 瑞星, 联想远程网络控制被控端,
联想硬盘保护工具(好像是这个名字), 因为是电脑联想品牌机, 所以后两个应该是买的时候送的,
点击退出硬盘保护工具, 一下子就能退出, 但这并没有什么卯用, 硬盘保护已经在系统启动前就先行启动了.
退出被控端需要管理员密码, 对这个密码我倒是有点兴趣, 用OD附加看看.&lt;/p&gt;
&lt;p&gt;附加了并没有办法运行, 提示该线程被挂起或者线程终止. 但是在网络控制软件下有个小工具,
叫ChangeIP.exe, 使用它更改电脑的IP也需要密码, 挑这个软柿子捏好了. OD打开,
发现他是用MFC写的(有MFC的模块), 查看导入函数, 没有GetWindowText 或者是 GetDlgItem 之类的函数,
但是有 IsDebugPresent(), 有反调试, 所幸这个OD里插件齐全,
打开HideOD插件把所有绕过的选项勾上, 重启.&lt;/p&gt;
&lt;p&gt;重启后, 程序正常地在OD里跑起来了. 到了输入密码这个窗口, 程序里并没有搜到什么有用的字符串,
那就内存断点吧. 随便输入一个密码, 然后回到内存窗口里搜索该密码...没有搜到.
那就点击确定-&amp;gt;提示密码错误, 之后再搜索, 有了. 对该地址下内存断点. 再输入一次,
点击确定, 程序断下来了.&lt;/p&gt;
&lt;p&gt;为什么说这是一次没有技术含量的Hack呢? 程序读取改地址的第一个字节,
写入 00(并不是我输入的值), 我并没有耐心分析他想做什么(当然分析了也不一定有结果),
所以直接F9让他继续执行, 继续触发断点, 果然瞎猫碰见死耗子了, F9几次后,
到了密码验证的环节了, esi寄存器里出现了一个字符串的地址 &amp;quot;jsjxxgmm&amp;quot;
(教师教学修改密码?及时进行修改密码?), 八九不离十. 我重开了ChangeIP.exe,
输入这个字串, Accepted.&lt;/p&gt;
&lt;p&gt;取得了这个密码除了脱离被控端外似乎没什么卯用, 但是整个机房的软件都是这个密码,
完全可以下载一个控制端软件, 通过这个对其他电脑进行控制(下次试试).
另外的很重要的一点是, 硬盘保护系统也是这个密码, 这样一来, 还原卡就失效了.
想往电脑里放什么就能放什么.&lt;/p&gt;
&lt;p&gt;嗯, 大致如此.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/record-of-a-boring-hack.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Reverse" label="Reverse"/>
    <published>2015-05-12T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/do-notation-and-bind-of-haskell.html</id>
    <title>do 记法和 &gt;&gt;= 的等效表达</title>
    <updated>2015-04-09T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="do"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;明明在开学的时候，&lt;a class="any any-book reference internal" href="notes/books/index.html#book-Haskell" title="book Haskell 趣学指南"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; 就只剩下三十来页了，但是还书日在即，
我就到图书馆问阿姨能不能还了马上再借，这样做的结果是，书还在我手里，
可是至今没看完。&lt;/p&gt;
&lt;p&gt;当然这和后面的内容有点难有关系（岂止是有点难？！），本来脑子就不够用，
看到State Monad那一段就懵了。&lt;/p&gt;
&lt;p&gt;今晚看了挺久的，勉强算有点思路，当然对它的理解应该还是在一个比较low的水平上。
就算是看了大半本书， 知乎上对Haskell的讨论还是又非常多看不懂。&lt;/p&gt;
&lt;p&gt;State Monad是一种函数，当然也是一种Monad，是一种带状态的计算，等待着一个状态，
如果得到状态后会产生一个值和新的状态。&lt;/p&gt;
&lt;p&gt;书里用栈作为例子，实现了push和pop，但是只提供了do记法的示例，自己尝试用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;改写并没有成功。&lt;/p&gt;
&lt;p&gt;State Monad对于bind(&amp;gt;&amp;gt;=)的一种解释是这样子的：
来自：&lt;a class="reference external" href="https://wiki.haskell.org/State_Monad"&gt;https://wiki.haskell.org/State_Monad&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;act1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fact2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;runState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;act2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;runState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;act1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="n"&gt;act2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fact2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iv&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;接受一个State，和一个生成State的函数，最后生成一个State，
注意最后生成的这个State是一个函数，还需要一个状态。&lt;/p&gt;
&lt;p&gt;act1是一个带状态计算，接受状态s后（不能直接接受，必须用runState「脱壳」）生成一个tuple，
左边是值，右边是新的状态。从fact2的类型签名可以知道，act2是fact2应用值iv后得到的 &lt;em&gt;带状态计算&lt;/em&gt; 。
那么它还需要一个状态，这个&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;函数的最终值就是act2脱壳后应用新状态的值。&lt;/p&gt;
&lt;p&gt;注意上面这段代码是表示了当带有&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;的运算遇到一个状态时所做的操作，似乎少了一个runState?&lt;/p&gt;
&lt;p&gt;那么对于：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;结果应该是:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;ghci&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runState&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;怎么用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;改写上面的do notation呢？&lt;/p&gt;
&lt;p&gt;do实际上是嵌套的&amp;gt;&amp;gt;=的一个语法糖，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="pre"&gt;foo&lt;/span&gt;&lt;/code&gt; 就是一个绑定， 而且一旦绑定，
在之后的语句里也可以使用x了，所以相当于&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;foo&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="pre"&gt;(x&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;后面的语句)&lt;/span&gt;&lt;/code&gt;。
下面的两段程序是等价的，第二段程序为了最后能用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;return&lt;/span&gt; &lt;span class="pre"&gt;（x*y）&lt;/span&gt;&lt;/code&gt;，
就得两个lambda嵌套起来。&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nf"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;但是do里面也可以不用绑定，不用绑定的话，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;也可以不必嵌套，而且和上面的不同，
这里有push和pop两个函数，pop相当于act1，push则是fact2，他们的行为不同，
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt; 的前面必须是一个act1类型，后面必须是fact2类型，
如果用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;串起来应该是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;pop&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="pre"&gt;push&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="pre"&gt;push&lt;/span&gt; &lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="pre"&gt;push&lt;/span&gt;&lt;/code&gt;，
但是要push三个值，push并不需要从&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;接收值，
可以用lambda来更改(因为没有利用到前面的值，所以这里嵌套与否都没问题)：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;test&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;test&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;ghci&amp;gt; runState test&amp;#39; []
&lt;/span&gt;&lt;span data-line="2"&gt;(5,[4,3])
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后，书里的&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt; 实现是这样子的：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newState&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;现在看来就好懂多了。对于State Monad，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;的意义是，等待一个初始状态，
取一个带状态计算，讲初始状态应用到带状态计算上，得到一个值和新状态，
值和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;右边的函数应用得到新的带状态计算，这个带状态计算又和新状态作用，
得到最终值和最终状态。当然这里的值和状态都可以继续传递下去，形成一条链。&lt;/p&gt;
&lt;p&gt;（我觉得State Monad有个反人类的地方就是，本来按顺序沿着&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;处理状态，
偏偏初始状态是放在最右的)&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/do-notation-and-bind-of-haskell.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Haskell" label="Haskell"/>
    <category term="函数式编程" label="函数式编程"/>
    <published>2015-04-09T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/some-minds-about-linux.html</id>
    <title>不求甚解者用不好 Linux</title>
    <updated>2015-03-27T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="linux"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;今晚无聊到写这么一篇废话, 很大程度上是想自我批评一下.&lt;/p&gt;
&lt;p&gt;因为这学期又开始做手头的OS67, 打代码的环境就又切换到Linux下来了, Linux用得频繁了,
自然就会想折腾了. 但是在这几天的折腾过程中, 我发现我似乎不是那么适合使用Linux.&lt;/p&gt;
&lt;p&gt;虽然从开始装双系统到现在小半年有余, 可我还是不能顺利的解决我遇到的问题,
并且每次的解决方案总是做到「刚刚好能解决问题」为止, 从遇到问题开始,
搜索答案 -&amp;gt; 尝试解决 -&amp;gt; 找到解决方案, 然后这个周期就结束了.&lt;/p&gt;
&lt;p&gt;我很少去仔细思考, 「为什么会发生这种问题」「为什么这样做能解决问题」,
而发生问题的时候我也很难冷静下来看资料, 经常是随便把页面里的代码试一遍,
我甚至不知道用什么关键词去Google.&lt;/p&gt;
&lt;p&gt;比如说呢, 这个暑假回家带了一台旧笔记本回来, 想要在上面只装一个openSUSE 13.2,
安装过程一切顺利, 安装完毕后把系统更新到最新后就没法开机了, grub似乎正常,
卡在了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;initrd&lt;/span&gt; &lt;span class="pre"&gt;/boot/initrd-3.16.7-7-desktop&lt;/span&gt;&lt;/code&gt;这里, 可选的另一个是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;initrd-3.16.6-2-desktop&lt;/span&gt;&lt;/code&gt;,
这似乎是内核版本? 在网上搜索了很久, 凡是贴近这种情况的资料几乎都是英文的,
基本看不懂. 而且我连Rescue CD都不会用, 谈何修复?  最后我只能忍着不&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;zypper&lt;/span&gt; &lt;span class="pre"&gt;up&lt;/span&gt;&lt;/code&gt;,
用着不更新的openSUSE.&lt;/p&gt;
&lt;p&gt;又比如今天折腾wine, (我甚至觉得这根本不是折腾...),
openSUSE社区的HillWood维护了一个项目叫winetricks-zh, 可以通过他很方便地安装
「符合中国国情」的各种软件, 比如QQ, 斗地主, 美图什么的.
当然我只是想用QQ(或许再加上个网易云音乐?). winetricks 本来是一个脚本,
用来快速下载wine下能跑的Windows软件的, 它的使用已经相当简单了:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nd"&gt;@github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;hillwoodroc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;winetricks&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;zh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;winetricks&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;zh&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;winetricks&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;winetricks&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;verb&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="n"&gt;winetricks&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最开始安装的是QQ轻聊版, 在winetricks qqlight.verb时遇到问题, 首先脚本要从Sourceforge上拉东西,
要备一张梯子(所以也折腾了一会儿的GoAgent), 安装好了之后打开来, QQ却莫名假死,
不能操作, 而且在安装完成后启动一次, 桌面上没有启动器, 我以为要自己去挂载的磁盘上找,
但是也找不到.&lt;/p&gt;
&lt;p&gt;尝试几次都得到错误的结果后我就怀疑是wine-64bit的问题, 如果你只安装wine-32bit的话,
winetricks就会提示 wineserver not found, 不能启动, 安装了完整的wine包,
默认的wine却是64bit的, 但是再切换32bit之后依然错误.&lt;/p&gt;
&lt;p&gt;在这之后我就把所有的配置&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.wine&lt;/span&gt;&lt;/code&gt;, &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.local/share/applictions&lt;/span&gt;&lt;/code&gt;和&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;~/.local/share/wineprefixs&lt;/span&gt;&lt;/code&gt;
全都删除了, 再把和wine有关的包统统删掉, 又重新安装了一次, 桌面终于出现了启动器,
但是依然卡死.  最后我放弃了用轻聊版, 用了QQ正式版, 出乎意料地顺利(checksum错误竟然没问题?)
勉强安装是安装成功了, 速度还好.&lt;/p&gt;
&lt;p&gt;但是在这整个的过程中, 我感觉我并没有学到了什么, 在不断地尝试中我只是把Linux看成了一种玄学,
「或许多试几次就成功了呢?」,「把这里改一下或许就不报错了呢?」&lt;/p&gt;
&lt;p&gt;然后在好不容易成功了之后, 我就几乎不想再去动它了, 我还是不明白为什么这样做成功了,
那样做为什么就不对...&lt;/p&gt;
&lt;p&gt;是否就是这种不求甚解的心态阻止了我的前进呢? 我怕麻烦, 觉得弄不懂, Linux的世界太复杂了,
不明白苏姐他们到底经过了怎样一番努力才能如此熟悉一个发行版.&lt;/p&gt;
&lt;p&gt;不求甚解者, 玩不好Linux, 这句话其实还可以继续推广,
不求甚解者, 当不好黑客, 写不好代码, 画不好画......&lt;/p&gt;
&lt;p&gt;我曾经在知乎上提了一个问题, &lt;a class="reference external" href="http://www.zhihu.com/question/26956394"&gt;发现自己不愿意思考怎么办&lt;/a&gt;,
现在想想, 「不求甚解」也是浮躁的一种表现吧?&lt;/p&gt;
&lt;p&gt;感觉我的问题, 白提了呢.&lt;/p&gt;
&lt;p&gt;睡觉吧, 或许明天起来后, 突然就知道应该这么做了.&lt;/p&gt;
&lt;p&gt;顺道一说, 今晚水了一道AliCTF的Reverse题...估计也就这一道了.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/some-minds-about-linux.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="瞎扯" label="瞎扯"/>
    <published>2015-03-27T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/matrix-arithmetic-in-haskell.html</id>
    <title>用 Haskell 实现的矩阵运算</title>
    <updated>2015-03-17T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="haskell"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;这学期开线性代数, 虽然我一向不喜欢数学, 本着将Haskell运用到实践中的精神,
想把上课教的几个矩阵运算写出来...虽然调试了半天, 回头一看,
好吧原来这么久简单的东西花了我那么多时间.&lt;/p&gt;
&lt;p&gt;虽然到现在的我都没把趣学指南看完因为课有点多&lt;span class="sphinxnotes-strike" style="text-decoration: line-through;"&gt;事实上是太懒了&lt;/span&gt;, 只看到了State Monad这里吧,
还不是太懂, 一旦碰到「作为Monad值的函数」,「作为Applicate值的函数」这种东西我就抓瞎了.&lt;/p&gt;
&lt;p&gt;说回矩阵吧, 用Haskell写这个还是挺爽的, 相较于C来说:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;不用和各种数组下标打交道&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;经常编译不过, 但一旦通过编译, 往往就得到正确的结果了&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;函数出乎意料地短, 数乘和矩阵加减本来都是用递归实现的, 写完后发现原来分别可以用map和zipWith来替代,
一下子长度就缩短了一半不止&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;各种类型错误让我想起了以前写Delphi的时候...&lt;/p&gt;
&lt;p&gt;实现矩阵转置的时候卡了一下, 我原来写的是&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;一直爆empty list exception, 因为pattern matching 不到 ys, 最后一步是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[[],[]...]&lt;/span&gt;&lt;/code&gt;
而不是&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]&lt;/span&gt;&lt;/code&gt;, 上网查了一下矩阵转置函数才知道可以用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[]:_&lt;/span&gt;&lt;/code&gt;来匹配.&lt;/p&gt;
&lt;p&gt;对于矩阵乘法, 我采取的是将右边那个矩阵转置, 这样就可以简化成行乘行, 左边矩阵拆成单行乘过去.&lt;/p&gt;
&lt;p&gt;在用&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;$&lt;/span&gt;&lt;/code&gt;的时候总是遇到问题...总是报错, 也不知道为什么...我把简单地$当成让函数右结合的操作符,
但是如果写: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;getMartix&lt;/span&gt; &lt;span class="pre"&gt;$&lt;/span&gt; &lt;span class="pre"&gt;Matrix&lt;/span&gt; &lt;span class="pre"&gt;xs&lt;/span&gt; &lt;span class="pre"&gt;`mmul&lt;/span&gt;&lt;/code&gt; ys` 就错误.
看来理解还是有偏差的.&lt;/p&gt;
&lt;p&gt;下面的代码分别实现了:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;矩阵加法 plus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;矩阵减法 sub&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;矩阵数乘 smul&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;矩阵乘积 mmul&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;矩阵的Eq实例和show实例&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;到底乘法用的是 multiplication 还是 product 呢... 好奇怪.&lt;/p&gt;
&lt;p&gt;因为定义矩阵直接用了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[[Int]]&lt;/span&gt;&lt;/code&gt;, 无法限制每个list的长度,
所以并不能保证这个Matrix里面肯定是一个符合定义的矩阵, 这个不知道怎么加以限制.&lt;/p&gt;
&lt;p&gt;看看接下来教的什么或许可以再往代码里加点东西, 改天看看别人是怎么写的.&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;getMartix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]]}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;smul&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nf"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;smul&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;[]:&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getMartix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="nf"&gt;mmul&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;mmul&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;mmul&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mul_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getMartix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getMartix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;mmul&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="nf"&gt;mul_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="nf"&gt;mul_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="nf"&gt;mul_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mul_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="kr"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zipWith&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="kr"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/matrix-arithmetic-in-haskell.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Haskell" label="Haskell"/>
    <category term="函数式编程" label="函数式编程"/>
    <published>2015-03-17T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/windows-chinese-username.html</id>
    <title>把 Windows 中文用户名改为英文</title>
    <updated>2015-03-08T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="windows"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;上次暑假回家重装系统, Win 8.1 和 openSUSE 13.2, 在同步Outlook账号的时候,
没注意到当前我的账户名是中文的. 导致了我在 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;C:\Users\&lt;/span&gt;&lt;/code&gt; 目录下的用户目录变成了中文的.
n
本来以为问题不大, 没想到有些程序对中文路径名的支持还是这么差.&lt;/p&gt;
&lt;p&gt;首先是Virtual Box, 虽然能够安装上, 但是无论如何虚拟机就是打不开, 经确认是因为路径的关系了,
再接着是Haskell Platform, cabal update 的时候也是报错说路径错误什么的.&lt;/p&gt;
&lt;p&gt;因为重装系统就要把两个一起重装了, 实在麻烦(事实上是我还不会用Grub).
我在网上稍微百度了一下怎么在不重装的情况下把用户目录给换成英文的.
但是实在找不到简单又靠谱的方法, 都是改注册表什么的, 也就作罢. 放假回来下午稍微一折腾, done.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;首先在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;我的电脑-&amp;gt;管理-&amp;gt;本地用户和组-&amp;gt;用户&lt;/span&gt;&lt;/code&gt; 新建一个用户,名字要是英文的, 全称就随便了,
我写了LA, 新建后右击选择这个新账户的属性, 在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;隶属于&lt;/span&gt;&lt;/code&gt;标签页输入对象&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;Administrators&lt;/span&gt;&lt;/code&gt;,
就是把它归入Administrators组的意思. 你可以在&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;本地用户和组-&amp;gt;组&lt;/span&gt;&lt;/code&gt;里面看到它.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;然后在开始屏幕先把自己注销, 再切换到这个新的账户LA, 刚刚进入的时候, 会做一些初始化的工作, 等就行了.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;进入系统到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;C:Users`目录,&lt;/span&gt; &lt;span class="pre"&gt;*在文件夹选项中选择显示隐藏文件*,&lt;/span&gt; &lt;span class="pre"&gt;对旧账户文件夹右键,&lt;/span&gt;
&lt;span class="pre"&gt;取得管理员所有权,&lt;/span&gt; &lt;span class="pre"&gt;然后把所有文件覆盖到`C:UsersLA&lt;/span&gt;&lt;/code&gt;下, 复制不过来的就算了.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;重启一次, 登陆到LA , 看看之前的软件的配置是否没哟改变.(桌面配置就无法保留了.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;回到中文名账户把Outlook连接关闭, 切换到本地账号, 注销回到LA, 把原来的账号删掉.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;把新账户连接到Outlook, 等他同步完.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;配置文件强制迁移后可能还是会有些问题, 有可能有些软件硬编码了你的用户路径,
这就只能把个别软件配置删掉了, 自行到 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;LAAppData&lt;/span&gt;&lt;/code&gt; 中找.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;我遇到的另一个问题是OneDrive同步失效了,打开OneDrive的Metro版, 显示&amp;quot;找不到此位置&amp;quot;,
在文件夹导航栏中也找不到OneDrive,图标栏也没有. 我的解决方案是:
到&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;LAAppDataLocalMicrosoftWindowsSkyDrive&lt;/span&gt;&lt;/code&gt; (我这里真的是SkyDrive)中把Setting文件夹剪切掉,
过一会OneDrive就自动开始同步了, 这个时候把同步暂停, 更改同步位置, 把以前的旧文件覆盖过去就行了.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Done.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/windows-chinese-username.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Windows" label="Windows"/>
    <published>2015-03-08T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/syntax-highlight-in-haskell.html</id>
    <title>Syntax Highligh.hs</title>
    <updated>2015-02-16T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="syntax-highligh-hs"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;书还没看完，不过还是很想用Haskell写点什么出来，所以简单地实现了一个基于替换的Java代码高亮。&lt;/p&gt;
&lt;p&gt;不过这种替换的做法有很大的问题，当你的字符串或者注释里出现了关键字，那么里面也会被高亮，
有个想法就是将整段代码按是否高亮划分为一些元素:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;关键字&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;字符&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;宏&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;字符串&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;块注释&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;行注释&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;数字&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;函数&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;空白&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;其他&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后按顺序一个个用正则取出，使得每一个元素都只能被着色一次，不过这个想法暂时没实现。&lt;/p&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;正则&lt;/h2&gt;
&lt;section id="id2"&gt;
&lt;h3&gt;双引号的转义&lt;/h3&gt;
&lt;p&gt;另外遇到的问题是正则表达式，首先是双引号内字符串的匹配问题，对正则不熟悉，
试了很多次都没法匹配，因为考虑了反斜杠 对引号的转义问题，从语言描述上可以说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;匹配两个引号之间的尽量短的所有内容，并且内容中不能包含回车和没有被转义的引号
（即只能包含左侧有奇数个反斜杠的引号）&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;写正则实在是太烧脑子了，匹配奇数个可以用 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[^\]((\\)*\&amp;quot;)&lt;/span&gt;&lt;/code&gt; ，
然后最后面的引号只能左侧包含偶数个引号 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[^\]((\\)*&amp;quot;)&lt;/span&gt;&lt;/code&gt;
（本来可以将两个分组用后向引用省略了，试了一下发现错误，也不知道怎么解决）
最后写出来是恶心的表达式：&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;(.|[^\](\\)*&amp;quot;)*?[^\](\\)*&amp;quot;&lt;/span&gt;&lt;/code&gt;，但是还是有问题:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;div class="table-wrapper docutils container"&gt;
&lt;table class="docutils align-default"&gt;
&lt;tbody&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&amp;quot;regexp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;匹配 &amp;quot;regexp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&amp;quot;regexp&amp;quot;regexp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;匹配 &amp;quot;regexp&amp;quot;regexp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&amp;quot;reg &amp;quot; exp&amp;quot;reg&amp;quot;exp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;匹配 &amp;quot;reg &amp;quot; 和 &amp;quot;reg&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&amp;quot;reg &amp;quot;&amp;quot;&amp;quot;regexp&amp;quot;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;匹配 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;reg&lt;/span&gt; &lt;span class="pre"&gt;\&amp;quot;&lt;/span&gt;&lt;/code&gt; 和 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;&amp;quot;regexp&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;就最后一个错了，因为&amp;quot;也是满足&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[^\](\\)*&amp;quot;&lt;/span&gt;&lt;/code&gt;的，懒得再想了。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id3"&gt;
&lt;h3&gt;反斜杠的转义&lt;/h3&gt;
&lt;p&gt;还有一个问题，也是转义，本来为了代码的简洁，将正则表达式写在了文件里，每行一个，
逐行读取，接下来读每个正则对应的颜色，代码很漂亮：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;keywords.txt&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ReadMode&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replicate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hGetLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replicate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lhGetLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;后来发现没法匹配块注释&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;/*(.|n)**/&lt;/span&gt;&lt;/code&gt;，原因在于表达式里面的n只是代表回车，
而当你从文件里面读 “n” 的时候，他就真的是“n” 了，他代表一个反斜杠和一个字符n。
你没法从文件的一行里面读取一个回车吧，并且n后面还有内容，所以这种方案失败，
我只把关键字放在了文件里。代码变成了：&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;pattern&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;*(.|&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;*/&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//.*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#.*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;(.|(&lt;/span&gt;&lt;span class="se"&gt;\\\\\\\\&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\\\\\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;)*[^&lt;/span&gt;&lt;span class="se"&gt;\\\\&lt;/span&gt;&lt;span class="s"&gt;](&lt;/span&gt;&lt;span class="se"&gt;\\\\\\\\&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Purple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Gray&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Red&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Green&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;keywords.txt&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里又引发一个问题是：之前本来不用转义的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt; 变成了 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;，需要转义一次的 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;\&lt;/span&gt;&lt;/code&gt;，变成了&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;\\&lt;/span&gt;&lt;/code&gt;，
表达式更难看了。 而且需要注意到的是最难看的那个表达式里面的懒惰匹配 “?” 没有出现，
我一加他就出错。所以出现了更多的问题，效果比在测试器里面的还差。&lt;/p&gt;
&lt;aside class="topic"&gt;
&lt;p class="topic-title"&gt;2015.3.2 update:&lt;/p&gt;
&lt;p&gt;事实上Haskell的Posix库的底层是C的Regex.h,并且Posix规范的正则并不支持懒惰匹配。&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="haskell"&gt;
&lt;h2&gt;Haskell&lt;/h2&gt;
&lt;p&gt;除了了上面那些讨厌的问题之外，对于Haskell本身，也有一些不适应的地方。&lt;/p&gt;
&lt;section id="io"&gt;
&lt;h3&gt;IO用起来束手束脚&lt;/h3&gt;
&lt;p&gt;Haskell的IO()像是一种具有传染性的代码（诶我说的不是GPL），一个函数中一旦出现了IO操作，
函数的返回值就被限定为 IO()，导致你没法往外传参数，除非你把值包裹在IO()里变成IO(String)这样一种结构，
调用这个函数的函数也必须是IO操作，这一循环直到main才终止。当然Haskell这样做肯定是有它的理由的，
但是他们所说的“纯粹与非纯粹的分离”，我还暂时体会不到这样做的好处。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id4"&gt;
&lt;h3&gt;不知道这么写是否合适&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;我将正则保存在一个列表，将每个正则对应的颜色保存在另一个列表，
再从文件里读取匹配关键字的正则加在第一个列表的尾部，合并两个列表；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;将要着色的文件读出，传给htmlen函数；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;htmlen函数调用rep函数对代码进行着色（用左折叠flodl的方式调用），
然后为返回的结果加上html的头部尾部标签还有样式；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rep函数接受htmlen传给的文件内容，以及存有正则和颜色的二元组，
每一次对文件中匹配该表达式的模式加上&amp;amp;lt;font color&amp;amp;gt;标签&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不知道这么写是否正确， 什么才是好的代码， 这个问题至今还是很模糊啊。
（不过谈论这个问题之前应该把前面那些问题先解决了才是）&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.IO&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Text.Regex.Posix&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="cm"&gt;{- Highlighter in Haskell -}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Reading config...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;keywords.txt&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Processing...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test.java&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;writeFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test.java.html&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Finished.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="nf"&gt;htmlHead&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta charset=&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;/head&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="nf"&gt;htmlStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;style&amp;gt;code{font: 14px/200% &lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Consolas&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;;}&amp;lt;/style&amp;gt;&amp;lt;body&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="nf"&gt;htmlLast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="nf"&gt;htmlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="nf"&gt;htmlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlHead&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;htmlLast&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="nf"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="nf"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patCol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;otherwise&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;font color=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;/font&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="nf"&gt;pattern&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;*(.|&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;*/&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//.*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#.*&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;(.|(&lt;/span&gt;&lt;span class="se"&gt;\\\\\\\\&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\\\\\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;)*[^&lt;/span&gt;&lt;span class="se"&gt;\\\\&lt;/span&gt;&lt;span class="s"&gt;](&lt;/span&gt;&lt;span class="se"&gt;\\\\\\\\&lt;/span&gt;&lt;span class="s"&gt;)*&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Purple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Gray&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Red&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Green&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后的结果如下：&lt;/p&gt;
&lt;img alt="https://silverrainz.me/_images/2021-02-12_14_56_46.png" src="https://silverrainz.me/_images/2021-02-12_14_56_46.png" /&gt;
&lt;p&gt;可以看到最后一个字符串是着色错误的。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/syntax-highlight-in-haskell.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Haskell" label="Haskell"/>
    <category term="函数式编程" label="函数式编程"/>
    <published>2015-02-16T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/haskell-beginning.html</id>
    <title>Hello Haskell</title>
    <updated>2015-01-30T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="hello-haskell"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;我想学Haskell的原因在很大程度上拜轮子叔所赐，前一阵子在图书馆意外发现了一本
&lt;a class="any any-book reference internal" href="notes/books/index.html#book-Haskell" title="book Haskell 趣学指南"&gt;&lt;a href="#report-2"&gt;&lt;span class="problematic" id="problematic-2"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-2"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-2"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; ，这下子更没有不学的理由了。&lt;/p&gt;
&lt;p&gt;多说一句，有趣的是这本书的译者之一竟然是 &lt;a class="any any-friend reference internal" href="about/friends.html#friend-fleuria" title="friend fleuria"&gt;&lt;a href="#report-1"&gt;&lt;span class="problematic" id="problematic-1"&gt; &lt;sup&gt;Render Report&lt;/sup&gt;&lt;/span&gt;&lt;/a&gt;&lt;aside class="system-message" id="report-1"&gt;
&lt;p class="system-message-title"&gt;System Message: ERROR/2 (&lt;span class="docutils literal"&gt;None&lt;/span&gt;, line None); &lt;em&gt;&lt;a href="#problematic-1"&gt;backlink&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Render Report:&lt;/p&gt;
&lt;p&gt;Failed to render markup text to inline nodes:&lt;/p&gt;
&lt;div class="highlight-pytb notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="x"&gt;&amp;#39;Values&amp;#39; object has no attribute &amp;#39;tab_width&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/a&gt; ，我曾经好几次发邮件询问他有关OS的事情，
没想到在图书馆借到了他的书。。。另一个译者是蓝莲花的 &lt;a class="extlink-ghuser reference external" href="https://github.com/MaskRay"&gt;👤 MaskRay&lt;/a&gt; ，曾经在中大听过蓝莲花的宣讲会，
可惜当时他并没有在场。 不得不说世界真是太小了.&lt;/p&gt;
&lt;aside class="topic"&gt;
&lt;p class="topic-title"&gt;2021-02-12&lt;/p&gt;
&lt;p&gt;当时在宣讲会上的是诸葛建伟老师和 &lt;a class="extlink-ghuser reference external" href="https://github.com/ztrix"&gt;👤 ztrix&lt;/a&gt; ，
后来我加入长亭科技，ztrix 自然也成为了我的老板。&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;好了说点正事。&lt;/p&gt;
&lt;section id="id1"&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;Haskell的编译器是GHC，我的系统是openSUSE，安装ghc可以直接&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sudo&lt;/span&gt; &lt;span class="pre"&gt;zypper&lt;/span&gt; &lt;span class="pre"&gt;in&lt;/span&gt; &lt;span class="pre"&gt;ghc&lt;/span&gt;&lt;/code&gt;,
但是比ghc更方便的是Haskell Platform, 安装同样可以&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;sudo&lt;/span&gt; &lt;span class="pre"&gt;zypper&lt;/span&gt; &lt;span class="pre"&gt;in&lt;/span&gt; &lt;span class="pre"&gt;haskell-platform&lt;/span&gt;&lt;/code&gt;,
在 Windows 上则可以直接去官网下载安装包。&lt;/p&gt;
&lt;/section&gt;
&lt;section id="id2"&gt;
&lt;h2&gt;随便说说&lt;/h2&gt;
&lt;p&gt;因为借书的时候已经是考试周的前夕，所以到现在翻看书的时间仅限于之前在阅览室里无聊的那一会还有回家的路上，
现在是第五章，似乎有点初窥门径的感觉，又怕是自己想得太简单了。 总得来说是这么些感受吧：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;列表推导式很神奇，&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;[x&lt;/span&gt; &lt;span class="pre"&gt;|&lt;/span&gt; &lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="pre"&gt;xs&lt;/span&gt; &lt;span class="pre"&gt;,&lt;/span&gt; &lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pre"&gt;100]&lt;/span&gt;&lt;/code&gt;,其形式类似于之前用来描述集合的公式，
之前上离散的时候不明白为什么要有谓词这个鸡肋的概念，原来可以用在这里;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;类型类（Type Class）: 有点像是接口之类的东西，这个类型类的实例具有特定的特征，
类型类也必须为这些实例提供对应的方法，两个数如果可比较（Ord），那么就能判断这两个数的相等性（Eq）;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;模式匹配（Pattern Macthing）: 一开始我自动脑补成了函数的重载，但其实不是重载，
因为函数的参数根本就没有改变。 是不是觉得模式匹配只是可以避免&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;if-else&lt;/span&gt;&lt;/code&gt;而已，
类似于case？ 后来书里也说到了模式匹配就是case的语法糖，我暂时是说不出模式匹配到底有什么特别的地方，
但是在写递归函数的时候模式匹配用起来特别顺手；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;递归： 拜模式匹配所赐，递归在Haskell写起来真是漂亮极了。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;柯里函数 （Curry Function）： 请注意他的命名来自于 Haskell Curry, 对，
和Haskell这个名字的来源一样。柯里函数的出现解释了为什么接受多个参数的函数的声明必须类似于&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;a&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;b&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;c&lt;/span&gt;&lt;/code&gt;
而不是 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;a,&lt;/span&gt; &lt;span class="pre"&gt;b&lt;/span&gt; &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pre"&gt;c&lt;/span&gt;&lt;/code&gt;, 柯里函数是一个一元函数， 每次调用只接受一个参数，
并返回一个固化了该参数的一元函数，书里的比喻非常有趣，对于代码：&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;multThree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;multThree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;你可以将函数看做小工厂， 它们会取一些原材料，然后生产一些东西，对于上面的代码，
执行 multThree 3 5 9，我们将数值3喂给multThree工厂，这个工厂产生了一个更小的工厂，
这家小工厂得到数值5，继续搞出来一家小工厂， 第三家工厂得到数值9,产出最终的结果，
也就是135。&lt;/p&gt;
&lt;div class="highlight-haskell notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nf"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Ord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lteq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lteq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对于我这种初学者来说，最有诱惑力也最后成就感的自然就是三行快排了。。。
诶，去掉声明就是三行了。当然还会有更加厉害的实现，不过，先这样好了。&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/haskell-beginning.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈</summary>
    <category term="Haskell" label="Haskell"/>
    <category term="函数式编程" label="函数式编程"/>
    <published>2015-01-30T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://silverrainz.me/blog/idf-reverse-writeup.html</id>
    <title>IDF 实验室逆向题部分题解</title>
    <updated>2015-01-02T00:00:00+00:00</updated>
    <author>
      <name>Shengyu Zhang</name>
    </author>
    <content type="html">&lt;section id="idf"&gt;

&lt;div class="admonition hint"&gt;
&lt;p class="admonition-title"&gt;提示&lt;/p&gt;
&lt;p&gt;这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 &lt;a class="extlink-ghrepo reference external" href="https://github.com/SilverRainZ/bullet"&gt;⛺ SilverRainZ/bullet&lt;/a&gt; 反馈&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;地址在这里：&lt;a class="reference external" href="http://ctf.idf.cn/index.php?g=game&amp;amp;m=list&amp;amp;a=index&amp;amp;id=21"&gt;IDF逆向题&lt;/a&gt;
这些题都比较水，好在我和它一样水。&lt;/p&gt;
&lt;section id="python-btyecode"&gt;
&lt;h2&gt;Python BtyeCode:&lt;/h2&gt;
&lt;p&gt;好像是用Cpython编译的, 手头没工具, 用的是师兄给的反编译出来的代码:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;    &lt;span class="n"&gt;rst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;        &lt;span class="n"&gt;rst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;        &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rst&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Welcome to idf&amp;#39;s python crackme&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;    &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Enter the Flag: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;    &lt;span class="n"&gt;KEY1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Maybe you are good at decryptint Byte Code, have a try!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;    &lt;span class="n"&gt;KEY2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;        &lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;        &lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;232&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;    &lt;span class="n"&gt;en_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KEY1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;KEY2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;en_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;You Win&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Try Again !&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;    &lt;span class="n"&gt;rst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;        &lt;span class="n"&gt;rst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;        &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rst&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Welcome to idf&amp;#39;s python crackme&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;    &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Enter the Flag: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;    &lt;span class="n"&gt;KEY1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Maybe you are good at decryptint Byte Code, have a try!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;    &lt;span class="n"&gt;KEY2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;        &lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;        &lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;232&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;    &lt;span class="n"&gt;en_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KEY1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;KEY2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;en_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;You Win&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Try Again !&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;正常人反着推肯定是写: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;arr[i]&lt;/span&gt; &lt;span class="pre"&gt;-&lt;/span&gt;&amp;#160; &lt;span class="pre"&gt;(key[seed]&lt;/span&gt; &lt;span class="pre"&gt;^&lt;/span&gt; &lt;span class="pre"&gt;seed)&lt;/span&gt;&lt;/code&gt; 不过这样肯定推不出来,
因为出题人写错了… (师兄想出来的… 打死我也不知道是题目错了啊…),
出题的用了正确的算法给出密文之后, 把 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;rst.append((ord(v)&lt;/span&gt; &lt;span class="pre"&gt;^&lt;/span&gt; &lt;span class="pre"&gt;ord(key[seed])&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;seed)&lt;/span&gt; &lt;span class="pre"&gt;%&lt;/span&gt; &lt;span class="pre"&gt;255)&lt;/span&gt;&lt;/code&gt;
写成了: &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;rst.append((ord(v)&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;seed&lt;/span&gt; &lt;span class="pre"&gt;^&lt;/span&gt; &lt;span class="pre"&gt;ord(key[seed]))&lt;/span&gt; &lt;span class="pre"&gt;%&lt;/span&gt; &lt;span class="pre"&gt;255)&lt;/span&gt;&lt;/code&gt;
所以没必要深究什么了,代码:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;232&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Maybe you are good at decryptint Byte Code, have a try!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//事实上为什么要%127也不太清楚&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;arr[%d] = %d; key[%d] = %d; ^ = %d flag[%d] = %d;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;flag:&lt;/span&gt; &lt;span class="pre"&gt;WCTF{ILOVEPYTHONSOMUCH}&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="elf"&gt;
&lt;h2&gt;简单的ELF逆向:&lt;/h2&gt;
&lt;p&gt;这题是ELFx64位的CrackMe, 只能用IDA啦, 载入之,师兄叫我用F4 F5,不过64位的IDA好像没有F5,
找到main函数, F4, 得到代码:&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nl"&gt;addr_0x400900_12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;v14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;uint1_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;v14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;eax15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;v14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;eax16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;eax18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;eax20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;eax22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eax24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;v25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;eax24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7d&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="25"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="26"&gt;
&lt;/span&gt;&lt;span data-line="27"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="28"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* v13 应该是一个标志变量 */&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="29"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="30"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u r wrong&lt;/span&gt;&lt;span class="se"&gt;\r\n\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="31"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rax26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u r wrong&lt;/span&gt;&lt;span class="se"&gt;\r\n\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="32"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="33"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u r right!&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="34"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="35"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="36"&gt;&lt;span class="nl"&gt;addr_0x4008ff_7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="37"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;goto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addr_0x400900_12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="38"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;果然代码的可读性不是很好, 前面的printf之类的被我省去了, 重点放在while循环和那个if上,
可以看到if要求的是几个变量必须分别为 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;0,&lt;/span&gt; &lt;span class="pre"&gt;8,&lt;/span&gt; &lt;span class="pre"&gt;2,&lt;/span&gt; &lt;span class="pre"&gt;3,}&lt;/span&gt;&lt;/code&gt;
应该就是flag 的后部分了, 从最后的判断right和wrong可以看出v13是判断正确与否的变量.&lt;/p&gt;
&lt;p&gt;while 循环实在是难懂, 乖乖回去看汇编好了. 右键选择Graphic View模式, 这样汇编代码显得很清晰,
把重点放在while循环对应的那部分, 简单分析得到, 红笔标注的地方就是程序内为数不多的循环了,
循环之后多条并排的绿线那里是多路if,最后的是正确与否的判断以及输出.&lt;/p&gt;
&lt;img alt="1" src="https://silverrainz.me/_images/idf-reverse-writeup-1.png" /&gt;
&lt;p&gt;关键代码如下, interator 对应var_14, arr_1 对应var_40, arr_2 对应 var_c0:&lt;/p&gt;
&lt;div class="highlight-nasm notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="nl"&gt;loc_40097C:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;10h&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; 循环总次数&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="nf"&gt;setle&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="nf"&gt;jnz&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;loc_40091D&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="nl"&gt;loc_40091D:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; 装入循环变量&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="nf"&gt;cdqe&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="nf"&gt;movzx&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;rax&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;arr_1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="nf"&gt;movsx&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;edx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; 取出(unsigned char)arr_1[iterator], 数组元素只有一个字节&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="nf"&gt;cdqe&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;rax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;arr_2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; 取出(int)arr_2[iterator], 四个字节&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; eax = eax - 1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; ecx = eax&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="nf"&gt;shr&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;1Fh&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; ecx = ecx &amp;gt;&amp;gt; 0x1f&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="nf"&gt;lea&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rcx&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; 装入地址其实就是 eax = ecx + eax;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="nf"&gt;sar&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; eax = eax &amp;gt;&amp;gt; 1&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;edx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; 比较arr_2[iterator]经过运算的值是否等于arr_1[iterator]&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;loc_400978&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; 等于则跳&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;
&lt;/span&gt;&lt;span data-line="23"&gt;&lt;span class="nl"&gt;loc_400978:&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="24"&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;经过以上分析可以知道 arr_1 应该是我们输入的key, 所以有必要知道arr_2 的值, 跳转到arr_2的定义:&lt;/p&gt;
&lt;img alt="2" src="https://silverrainz.me/_images/idf-reverse-writeup-2.png" /&gt;
&lt;p&gt;是空的…
但是我们回到代码中, 对arr_2有这样的操作:&lt;/p&gt;
&lt;img alt="3" src="https://silverrainz.me/_images/idf-reverse-writeup-3.png" /&gt;
&lt;p&gt;刚好17个项(0-10h),
所以说 &lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;arr_i[i]&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;((arr_2[i]&lt;/span&gt; &lt;span class="pre"&gt;–&lt;/span&gt; &lt;span class="pre"&gt;1)&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;(arr_2[i]&lt;/span&gt; &lt;span class="pre"&gt;–&lt;/span&gt; &lt;span class="pre"&gt;1)&amp;gt;&amp;gt;0x1f)&amp;gt;&amp;gt;1&lt;/span&gt;&lt;/code&gt;
(忽略了shr 和 sar 以及各种细节问题… 所幸没有出错)
(vim 来处理这些最爽了)&lt;/p&gt;
&lt;p&gt;代码:&lt;/p&gt;
&lt;div class="highlight-cpp notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="cp"&gt;#define N 17&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arr_2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x0EF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0C7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0E9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0F7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x8B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0D9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x8D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0BF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0D9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0DD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0B1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0BF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x87&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x0D7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0BF&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;arr_2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;arr_2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/*注意一下 &amp;gt;&amp;gt; 的优先级*/&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0823}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pause.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;flag:&lt;/span&gt; &lt;span class="pre"&gt;wctf{ElF_lnX_Ckm_0823}&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="pe"&gt;
&lt;h2&gt;简单的PE文件逆向:&lt;/h2&gt;
&lt;p&gt;x86平台, 双击没法运行, 应该需要某个古老的C++运行时, 那就放弃用OD了, IDA载入,
稍微翻一翻(其实是不知道如何有效定位), 0x4113a0处就是关键处, F5之, 这次代码好看多了,
可以看出和上一个CrackMe基本相同…&lt;/p&gt;
&lt;div class="highlight-c notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v76&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte_415768&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v53&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v77&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v78&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v79&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v81&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;v76&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v75&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub_411136&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u r wrong&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub_411136&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub_41113B&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="16"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="17"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="18"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="19"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u r right!&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="20"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub_411136&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="21"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="22"&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;同样是把flag分成两部分, 后面五个必须是1024},前面的在一个for循环里算出:
&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;v76[i]&lt;/span&gt; &lt;span class="pre"&gt;!=&lt;/span&gt; &lt;span class="pre"&gt;byte_415768[*(&amp;amp;v53&lt;/span&gt; &lt;span class="pre"&gt;+&lt;/span&gt; &lt;span class="pre"&gt;i)]&lt;/span&gt;&lt;/code&gt;
通过一个数组v53[]运算出下标, 再用下标从另一个数组byte_415768[]取出值来, 数组是:&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;v53 = 1;
&lt;/span&gt;&lt;span data-line="2"&gt;v54 = 4;
&lt;/span&gt;&lt;span data-line="3"&gt;v55 = 14;
&lt;/span&gt;&lt;span data-line="4"&gt;v56 = 10;
&lt;/span&gt;&lt;span data-line="5"&gt;v57 = 5;
&lt;/span&gt;&lt;span data-line="6"&gt;v58 = 36;
&lt;/span&gt;&lt;span data-line="7"&gt;v59 = 23;
&lt;/span&gt;&lt;span data-line="8"&gt;v60 = 42;
&lt;/span&gt;&lt;span data-line="9"&gt;v61 = 13;
&lt;/span&gt;&lt;span data-line="10"&gt;v62 = 19;
&lt;/span&gt;&lt;span data-line="11"&gt;v63 = 28;
&lt;/span&gt;&lt;span data-line="12"&gt;v64 = 13;
&lt;/span&gt;&lt;span data-line="13"&gt;v65 = 27;
&lt;/span&gt;&lt;span data-line="14"&gt;v66 = 39;
&lt;/span&gt;&lt;span data-line="15"&gt;v67 = 48;
&lt;/span&gt;&lt;span data-line="16"&gt;v68 = 41;
&lt;/span&gt;&lt;span data-line="17"&gt;v69 = 42;
&lt;/span&gt;&lt;span data-line="18"&gt;byte_415768 db 73h
&lt;/span&gt;&lt;span data-line="19"&gt;    db &amp;#39;wfxc{gdv}fwfctslydRddoepsckaNDMSRITPNsmr1_=2cdsef66246087138&amp;#39;,0
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;要注意byte_415768[]的一个元素s(73h)没有被识别.
所以:&lt;/p&gt;
&lt;div class="highlight-cpp notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-line="1"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="2"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="3"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v53&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="4"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="5"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="6"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="7"&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte_415768&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;swfxc{gdv}fwfctslydRddoepsckaNDMSRITPNsmr1_=2cdsef66246087138&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="8"&gt;
&lt;/span&gt;&lt;span data-line="9"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="10"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte_415768&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v53&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="12"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="13"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1024}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span data-line="15"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="code docutils literal notranslate"&gt;&lt;span class="pre"&gt;flag:&lt;/span&gt; &lt;span class="pre"&gt;wctf{Pe_cRackme1c1024}&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://silverrainz.me/blog/idf-reverse-writeup.html"/>
    <summary>这是一篇迁移自 Jekyll 的文章，如有格式问题，可到 ⛺ SilverRainZ/bullet 反馈1</summary>
    <category term="Reverse" label="Reverse"/>
    <published>2015-01-02T00:00:00+00:00</published>
  </entry>
</feed>
