<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>RSSBOX</title>
  <icon>https://blog.imc.re/RSSBOX/favicon.ico</icon>
  <subtitle>SMGoroのRSS订阅 | 一些好康的东西</subtitle>
  <link href="https://blog.imc.re/RSSBOX/atom.xml" rel="self"/>
  
  <link href="https://blog.imc.re/RSSBOX/"/>
  <updated>2025-01-10T20:16:13.000Z</updated>
  <id>https://blog.imc.re/RSSBOX/</id>
  
  <author>
    <name>SMGoro</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Vocaloid Opera - the End (720p)</title>
    <link href="https://blog.imc.re/RSSBOX/rss/44757927.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/44757927.html</id>
    <published>2025-01-10T20:16:13.000Z</published>
    <updated>2025-01-10T20:16:13.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919962">#1919962 | Vocaloid Opera - The End (720p)</a> | 687.0 MiB | Anime - English-translated | B4A02619AA1FD2A36691D6A2ECEEA07DF46313F4</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Vocaloid Opera - The End (720p)" href="https://nyaa.si/download/1919962.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Vocaloid Opera - The End (720p)</span><span class="cap link fs12">https://nyaa.si/download/1919962.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>いとしのムーコ 第01-17巻 [Itoshi No Muco Vol 01-17]</title>
    <link href="https://blog.imc.re/RSSBOX/rss/5d3e505.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/5d3e505.html</id>
    <published>2025-01-10T20:10:17.000Z</published>
    <updated>2025-01-10T20:10:17.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919961">#1919961 | いとしのムーコ 第01-17巻 [Itoshi no Muco vol 01-17]</a> | 1.1 GiB | Literature - Raw | B88EEC7B83118BD8F5A54C5D2D964F6D6968C0FF</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="いとしのムーコ 第01-17巻 [Itoshi no Muco vol 01-17]" href="https://nyaa.si/download/1919961.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">いとしのムーコ 第01-17巻 [Itoshi no Muco vol 01-17]</span><span class="cap link fs12">https://nyaa.si/download/1919961.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>Sorairo Utility S01E02 1080p WEB X264 AAC -Tsundere-Raws (ABEMA)</title>
    <link href="https://blog.imc.re/RSSBOX/rss/48910fa7.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/48910fa7.html</id>
    <published>2025-01-10T19:44:59.000Z</published>
    <updated>2025-01-10T19:44:59.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919956">#1919956 | Sorairo Utility S01E02 1080p WEB x264 AAC -Tsundere-Raws (ABEMA)</a> | 711.2 MiB | Anime - Raw | C949847BB40BD9F183E081D2846987E23DA0953C</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Sorairo Utility S01E02 1080p WEB x264 AAC -Tsundere-Raws (ABEMA)" href="https://nyaa.si/download/1919956.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Sorairo Utility S01E02 1080p WEB x264 AAC -Tsundere-Raws (ABEMA)</span><span class="cap link fs12">https://nyaa.si/download/1919956.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>Tying.the.Knot.with.an.Amagami.Sister.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ca53dfad.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ca53dfad.html</id>
    <published>2025-01-10T19:29:58.000Z</published>
    <updated>2025-01-10T19:29:58.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919953">#1919953 | Tying.the.Knot.with.an.Amagami.Sister.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</a> | 1.4 GiB | Anime - Non-English-translated | 3DE8A3CD955DD40CA526B698FFA314D178EEAE29</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Tying.the.Knot.with.an.Amagami.Sister.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi" href="https://nyaa.si/download/1919953.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Tying.the.Knot.with.an.Amagami.Sister.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</span><span class="cap link fs12">https://nyaa.si/download/1919953.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>I.ll.Become.a.Villainess.who.Goes.Down.in.History.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</title>
    <link href="https://blog.imc.re/RSSBOX/rss/c7690982.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/c7690982.html</id>
    <published>2025-01-10T19:29:54.000Z</published>
    <updated>2025-01-10T19:29:54.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919952">#1919952 | I.ll.Become.a.Villainess.who.Goes.Down.in.History.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</a> | 1.4 GiB | Anime - Non-English-translated | C4162E9E712C16E52ADDE07860B1363EA3E12CFA</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="I.ll.Become.a.Villainess.who.Goes.Down.in.History.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi" href="https://nyaa.si/download/1919952.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">I.ll.Become.a.Villainess.who.Goes.Down.in.History.S01E12.MULTi.1080p.WEB-DL.x264-T3KASHi</span><span class="cap link fs12">https://nyaa.si/download/1919952.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>浮世絵 EDO-LIFE「べらぼう」の世界　密着吉原２４時！歌麿　青楼十二時　続</title>
    <link href="https://blog.imc.re/RSSBOX/rss/d3f400ed.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/d3f400ed.html</id>
    <published>2025-01-10T19:16:50.000Z</published>
    <updated>2025-01-10T19:16:50.000Z</updated>
    
    <content type="html"><![CDATA[<div><a href="https://nyaa.si/view/1919950">#1919950 | 浮世絵 EDO-LIFE「べらぼう」の世界　密着吉原２４時！歌麿　青楼十二時　続</a> | 45.4 MiB | Live Action - Raw | 42AF16020AA9AC93C3AFEB7874448A239D3798A7</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="浮世絵 EDO-LIFE「べらぼう」の世界　密着吉原２４時！歌麿　青楼十二時　続" href="https://nyaa.si/download/1919950.torrent" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">浮世絵 EDO-LIFE「べらぼう」の世界　密着吉原２４時！歌麿　青楼十二時　続</span><span class="cap link fs12">https://nyaa.si/download/1919950.torrent</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/categories/acg/nyaa/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="nyaa" scheme="https://blog.imc.re/RSSBOX/tags/nyaa/"/>
    
  </entry>
  
  <entry>
    <title>恐怖体验交流大会，核市奇谭vol.84</title>
    <link href="https://blog.imc.re/RSSBOX/rss/55d9976e.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/55d9976e.html</id>
    <published>2025-01-10T15:00:00.000Z</published>
    <updated>2025-01-10T15:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/fc32d0821d5db5ba2202171c72586850-3200-1800.jpg?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>本期时间轴制作: 雏雏</p><p>欢迎收听！本期聊天主题是自己害怕的东西。我们聊了自己害怕的事物，以及分享了一些恐怖体验：比如觉得自己通灵的瞬间、回字形楼梯间灵异事件、墓地摄影探险等等（微恐）……第二部分的读书环节，闲聊了最近的三本新书：<span style="font-weight: bold;">《伊藤润二的漫画术》《世界鲨鱼大全》《英伟达之道》</span>。</p><p>祝大家2025年开年大吉！</p><div></p><p><a href="https://item.taobao.com/item.htm?ft=t&amp;id=874233922599&amp;spm=a21dvs.23580594.0.0.621e2c1biQ7ytH&amp;skuId=5709601692698">&lt;核市奇谭｜英伟达之道：黄仁勋和他的科技帝国&gt;</a></p></div><div><p><a href="https://item.taobao.com/item.htm?ft=t&amp;id=874056391645&amp;spm=a21dvs.23580594.0.0.621e2c1biQ7ytH&amp;skuId=5709618192601">&lt;核市奇谭｜伊藤润二的漫画术：恐怖诞生的地方&gt;</a></p></div><div><p><a href="https://item.taobao.com/item.htm?ft=t&amp;id=874240334514&amp;spm=a21dvs.23580594.0.0.621e2c1biQ7ytH">&lt;核市奇谭｜世界鲨鱼大全 一本献给鲨鱼爱好者的手绘图鉴&gt;</a></p></div><p></p><p></p><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="恐怖体验交流大会，核市奇谭vol.84" href="https://www.gcores.com/radios/193082" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">恐怖体验交流大会，核市奇谭vol.84</span><span class="cap link fs12">https://www.gcores.com/radios/193082</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>Highlights From Git 2.48</title>
    <link href="https://blog.imc.re/RSSBOX/rss/86d9f572.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/86d9f572.html</id>
    <published>2025-01-10T10:28:50.000Z</published>
    <updated>2025-01-10T10:28:50.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>The open source Git project just <a href="https://lore.kernel.org/git/xmqqplku7cvm.fsf@gitster.g/">released Git 2.48</a> with features and bug fixes from over 93 contributors, 35 of them new. We last caught up with you on the latest in Git back when <a href="https://github.blog/open-source/git/highlights-from-git-2-47/">2.47 was released</a>.</p><p>To celebrate this most recent release, here is GitHub’s look at some of the most interesting features and changes introduced since last time.</p><h2 id="faster-sha-1s-without-compromising-security">Faster SHA-1s without compromising security<a aria-label="Faster SHA-1s without compromising security" class="heading-link pl-2 text-italic text-bold" href="#faster-sha-1s-without-compromising-security"></a></h2><p>When we published our coverage of Git’s 2.47 release, we neglected to mention a handful of performance changes that went in toward the very end of the cycle. Because this version contains a bugfix related to those changes, we figured now was as good a time as any<sup id="fnref-81991-1"><a class="jetpack-footnote" href="#fn-81991-1" title="Read footnote.">1</a></sup> to discuss those changes.</p><p>You likely know that Git famously uses SHA-1 hashes by default to identify objects within your repository. (We <a href="https://github.blog/open-source/git/git-2-29-released">have covered</a> Git’s capability to use SHA-256 as its primary hash function instead, but for this tidbit we’ll focus on Git in its SHA-1 mode). What you may not know is that Git uses SHA-1 hashes internally in a couple of spots, too. Most notable for our purposes is that the <a href="https://git-scm.com/docs/pack-format">pack format</a> includes a trailing SHA-1 that stores the checksum of the preceding bytes. Git uses this data to validate that a pack’s contents matches what was advertised, and didn’t get corrupted in transit.</p><p>By default, Git uses a collision detecting implementation of SHA-1, hardening it against common SHA-1 attacks like <a href="https://shattered.io/">SHAttered</a> and <a href="https://sha-mbles.github.io/">Shambles</a>. (GitHub <a href="https://github.blog/news-insights/company-news/sha-1-collision-detection-on-github-com/">also uses</a> the collision detecting SHA-1 implementation). While the collision detecting SHA-1 implementation protects Git against collision attacks, it does so at the cost of a few extra CPU cycles to look for the telltale signs of these attacks while checksumming.</p><p>In most cases, the performance impact is negligible, and the benefit outweighs the minor performance cost. But when computing the checksum of a large pack (like when cloning a large repository), the cost adds up. For instance, we used <a href="https://valgrind.org/docs/manual/cl-manual.html">Callgrind</a> and measured that Git spends around 78% of its CPU computing a checksum during a simulated clone of <code>torvalds/linux</code>.</p><p>Luckily, the trailing checksum is a data integrity measure, not a security one. For our purposes, this means that we can safely use a faster, non-collision-detecting implementation of SHA-1 specifically when computing trailing checksums (but nowhere else) without compromising security. Git 2.47 introduced new build-time options to specify a separate hash function implementation used specifically when computing trailing checksums. GitHub has used this option, and as a result measured a 10-13% performance improvement in serving fetches/clones across all repositories.</p><p>You can try out Git’s ability to select alternative hash function implementations by building with <code>make OPENSSL_SHA1_UNSAFE=1</code>, or other <a href="https://github.com/git/git/blob/v2.48.0/Makefile#L513-L532"><code>_UNSAFE</code> variants</a>.</p><p>[<a href="https://github.com/git/git/compare/59ee4f70136a12feb47979ca90baaf7c7beafe73...1b9e9be8b4694ea52d8aae93f311b1607c3576b7">source</a>, <a href="https://github.com/git/git/compare/b1c6ed40cde2c0e2fd9b41c51555eba48bce49a8...4638250b7b9288c197c16600630cefd4e196b4fc">source</a>, <a href="https://github.com/git/git/compare/6d81fe64dd646654bdb84fa5832c717954bf1696...863f2459a2047406c93758e8c3352cd5d2836f1e">source</a>]</p><h2 id="bringing-remerge-diff-to-range-diff">Bringing <code>--remerge-diff</code> to range-diff<a aria-label="Bringing &lt;code&gt;--remerge-diff&lt;/code&gt; to range-diff" class="heading-link pl-2 text-italic text-bold" href="#bringing-remerge-diff-to-range-diff"></a></h2><p>Regular readers of this series will no doubt recall our coverage of <a href="https://github.blog/open-source/git/highlights-from-git-2-19/#user-content-compare-histories-with-git-range-diff">Git’s range-diff command</a> (introduced back in Git 2.19), and <a href="https://github.blog/open-source/git/highlights-from-git-2-36/#review-merge-conflict-resolution-with-remerge-diff">the newer –remerge-diff option</a> (released in Git 2.36). In case you’re a first-time reader, or neither of those ring a bell for you, don’t worry; here’s a brief refresher.</p><p>Git’s <code>range-diff</code> command allows you to compare two <em>sequences</em> of commits, including changes to their order, commit messages, and the actual content changes they introduce. This can be useful when comparing a sequence of commits that were rebased (potentially tweaking the order and changes within the patches along the way), to what that set of commits looked like before the rebase.</p><p>Git’s <code>--remerge-diff</code> option tells <code>git show</code>, <code>git log</code>, or various diff-related commands to view the differences between where Git would have stopped with the merge, and what is recorded in the merge. This can be useful when dealing with merge conflicts, since the <code>--remerge-diff</code> view will show you the difference between the conflicts and their resolution, showing you how a given merge conflict was handled.</p><p>In Git 2.48, these two features meet for the first time, and <code>range-diff</code> now accepts a <code>--remerge-diff</code> option, so that if someone rebases a sequence of commits with <a href="https://github.blog/open-source/git/highlights-from-git-2-22/#rebase-merges-interactively"><code>--rebase-merges</code></a> and potentially needs to make some changes, then the changes in merge commits can also be reviewed as part of the range-diff.</p><p>As a side effect of this work, a longstanding bug with <code>--remerge-diff</code> was also fixed, which in particular will allow <code>git log –remerge-diff</code> to be used together with options that change the order of commit traversal (such as <code>--reverse</code>).</p><p>[<a href="https://github.com/git/git/compare/c4cc685a62ffc06c86b1ecd1382c1b5cd0166189...88e59f8027ed0260584ccc0abd6fe435031614eb">source</a>, <a href="https://github.com/git/git/commit/f94bfa151623d7e675db9465ae7ff0b33e4825f3">source</a>]</p><h2 id="memory-leak-free-tests-in-git">Memory leak-free tests in Git<a aria-label="Memory leak-free tests in Git" class="heading-link pl-2 text-italic text-bold" href="#memory-leak-free-tests-in-git"></a></h2><p>Beginning <a href="https://github.blog/open-source/git/highlights-from-git-2-34/">all the way back in Git 2.34</a>, the Git project has been focused on reducing <a href="https://en.wikipedia.org/wiki/Memory_leak">memory leaks</a> with the goal of ultimately making Git leak-free. Since Git is a command line tool, each execution typically only lasts for a brief period of time, after which the kernel will free any memory allocated to Git that Git itself did not free. Because of this, memory leaks in Git have not posed a significant practical issue for everyday use.</p><p>But, having memory leaks in Git makes it difficult to convert much of Git’s internals into a callable library, where having memory leaks would be a significant issue. To address this, there has been a concerted effort over many years to reduce the number of memory leaks in Git’s codebase, with the ultimate goal of eliminating them altogether.</p><p>After much effort toward that end, Git can now run its test suite successfully with leak checking enabled. As a satisfying end result, much of the test infrastructure we talked about back in 2.34 was removed, resulting in a simpler test infrastructure. Making Git memory leak-free represents significant progress toward being able to convert parts of Git’s internals into a callable library.</p><p>[<a href="https://github.com/git/git/compare/98009afd24e2304bf923a64750340423473809ff...9972cd6004ac46a919d2e8773be976ef1e2d6a65">source</a>, <a href="https://github.com/git/git/compare/2a1a882890a3336f6f44d33793eedb70ff75d37a...fba95dad6ad83fd27eaf57cf526110faa8a20833">source</a>, <a href="https://github.com/git/git/compare/7b0defb3915eaa0bd118f0996e8c00b4eb2dc1ca...ebdbefa4fe9f618347124b37d44e517e0c6a3e4c">source</a>, <a href="https://github.com/git/git/compare/ecf7fc600a5218c9ee3863ee70d5a6e312164f30...fbf7a46d881429ef5495af7bbf3a6c3dacbf80b3">source</a>, <a href="https://github.com/git/git/compare/25673b1c476756ec0587fb0596ab3c22b96dc52a...f30bfafcd41d0f13575361957dc361aa2be4d4c5">source</a>, <a href="https://github.com/git/git/compare/3a7362eb9fad0c4838f5cfaa95ed3c51a4c18d93...77d4b3dd73c44b2c617345a6d9686d2f7f5b8a68">source</a>, <a href="https://github.com/git/git/compare/f123c19e72190e666fbcd827924fd1f090a9d6ae...13b23d2da552b9476a0025562bc4ab8954d5be45">source</a>, <a href="https://github.com/git/git/compare/2b800ec45e53051c41a85900009430704bfdf031...46f6ca2a68e02dd68132ed0b64cd55a8b6569e29">source</a>, <a href="https://github.com/git/git/compare/9293a931868f21029baf55935f2f092c3f06415f...12dfc2475ce4808df696fb67fc71a66793f78f06">source</a>, <a href="https://github.com/git/git/compare/d29d644d18737c7fbc2651ddbda64a3b552d9acb...66893a14d0c0d3850227def321312a7290317610">source</a>, <a href="https://github.com/git/git/compare/b31fb630c0fc6869a33ed717163e8a1210460d94...c810549be1dd31e1a0a1de5060a519a461533564">source</a>, <a href="https://github.com/git/git/compare/2f605347da0f6859175d6110cfd49b2d8937dea4...fc1ddf42af6742fae7e770cae20e30d7902014c0">source</a>]</p><h2 id="introducing-meson-into-git">Introducing Meson into Git<a aria-label="Introducing Meson into Git" class="heading-link pl-2 text-italic text-bold" href="#introducing-meson-into-git"></a></h2><p>The Git project uses <a href="https://www.gnu.org/software/make/manual/make.html">GNU Make</a> as the primary means to compile Git, meaning that if you can obtain a copy of Git’s source, running <code>make</code> should be all you need to get a working Git binary (provided you have the necessary dependencies, etc.). There are a couple of exceptions, namely that Git has some support for Autoconf and CMake, though they are not as up-to-date as Git’s <code>Makefile</code>.</p><p>But as the Git project approaches its 20th anniversary later this year, its <code>Makefile</code> is starting to show its age. There have been <a href="https://github.com/git/git/commits/v2.48.0/Makefile">over 2,000 commits</a> to the <code>Makefile</code>, resulting in a build script that is nearly 4,000 lines long.</p><p>In this release, the Git project has support for a new build system, <a href="https://en.wikipedia.org/wiki/Meson_(software)">Meson</a>, as an alternative to building with GNU Make. While support for Meson is not yet as robust as building with Make, Meson does offer a handful of advantages over Make. Meson is easier to use than Make, making the project more accessible to newcomers or contributors who don’t have significant experience working with Make. Meson also has extensive IDE support, and supports out-of-tree and cross-platform builds, which are both significant assets to the Git project.</p><p>Git will retain support for Make and CMake in addition to Meson for the foreseeable future, and retain support for Autoconf for a little longer. But if you’re curious to experiment with Git’s newest build system, you can run <code>meson setup build &amp;&amp; ninja -C build</code> on a fresh copy of Git 2.48 or newer.</p><p>[<a href="https://github.com/git/git/compare/ededd0d5dceefc308c670f4ed5f9fc727184e83d...904339edbd80ec5676616af6e072b41804c1c8eb">source</a>]</p><hr/><ul><li>As the Git project has grown over the years, it has accumulated a number of features and modes that, while reasonable when first introduced, have since become outdated or superseded and are now deprecated. In Git 2.48, the Git project began collecting these now-deprecated features in a list stored in <a href="https://github.com/git/git/blob/v2.48.0/Documentation/BreakingChanges.txt"><code>Documentation/BreakingChanges.txt</code></a>.<p>This document enables the Git project to discuss deprecating certain features and collects the project’s anticipated deprecations in a single place. On the other side of the equation, it allows users to see if they might be affected by an upcoming deprecation, and share their use-case of a particular feature with the project. Check out the list to see if there is anything on there that you might miss, and to get an early picture of what an eventual Git 3.0 release might look like!</p><p>[<a href="https://github.com/git/git/compare/23d289d273d861f0a6244480e89ff937f66efa77...2454970930851179fb6486e6faa6342f008e7d9d">source</a>]</p></li><li><p>If you’ve ever scripted around your repository’s references, you are likely familiar with Git’s <code>for-each-ref</code> command. In case you’re not, <code>for-each-ref</code> is a flexible tool that allows you to list references in your repository, apply custom formatting specifiers to them, and much more.</p><p>Back <a href="https://github.blog/open-source/git/highlights-from-git-2-44/">in Git 2.44</a>, we talked about <a href="https://github.com/git/git/compare/e020e55a62dc3281504858d4091847d18ca63b2d...294bfc24418e81dfb204d14a3c3c24af9b195179">some performance improvements</a> that allowed <code>git for-each-ref</code> to run significantly faster by combining reference filtering and formatting into the same codepath, eliminating the need to store and sort the results in certain conditions.</p><p>Git 2.48 extends those changes by allowing us to take advantage of the same optimizations even when asked to output the references in sorted order (under certain conditions). As long as those conditions are met, you can quickly output a small number of references even under <code>--sort=refname</code> independent of how many references your repository actually has.</p><p>[<a href="https://github.com/git/git/compare/bc627658b06155a0b1c3d0b1b0bf72db70770dc9...2e7c6d2f4112dd374f615f4e612e1cebbcb6d431">source</a>]</p></li><li><p>While we’re on the topic of references, the <a href="https://github.com/git/git/tree/v2.48.0-rc0/reftable">reftable subsystem</a> has received some more attention in this release. Git’s reftable implementation was updated to avoid explicit dependencies on some of Git’s convenience APIs, making further progress on being able to compile the reftable code without <code>libgit.a</code>. The reftable implementation was also updated to gracefully handle memory allocation failures instead of exiting the process immediately. Last but not least, the reftable code was updated to be able to reuse reference iterators, resulting in faster reference creation and lower memory usage when using reftables.</p><p>For more about reftables, check out <a href="https://github.blog/open-source/git/highlights-from-git-2-45/#preliminary-reftable-support">our previous coverage of reftables</a>.</p><p>[<a href="https://github.com/git/git/compare/799450316b606d4b6cd5db6a6cc814f1710d923f...2179b5c831f6bc286acda15c7c7f4a573291ee5c">source</a>, <a href="https://github.com/git/git/compare/6a11438f43469f3815f2f0fc997bd45792ff04c0...20590cd287ada9c96efdf804e2bcdac0117c01b8">source</a>, <a href="https://github.com/git/git/compare/35f40385e441d5aa885f5aa813539d5ed9dc2d26...988e7f5e952bbb7b6ae885f4da744f536f22693f">source</a>, <a href="https://github.com/git/git/compare/de9278127e107455fda269d2db280782d77e5eba...7cf65e266020f23d31863a1f9508f375be818071">source</a>]</p></li><li><p>When you clone from a remote repository, the default branch that the remote repository uses is reflected in <code>refs/remotes/origin/HEAD</code> locally<sup id="fnref-81991-2"><a class="jetpack-footnote" href="#fn-81991-2" title="Read footnote.">2</a></sup>. In prior versions of Git, subsequent fetches and pulls did not update this symbolic reference. With Git 2.48, if the remote has a default branch but <code>refs/remotes/origin/HEAD</code> is missing locally, then a fetch will update it.</p><p>If you want to take it a step further, you can set <code>remote.origin.followRemoteHead</code> configuration to <code>warn</code> or <code>always</code>; if you do so, when <code>refs/remotes/origin/HEAD</code> already exists but does not match the default branch on the remote side, then when you run <code>git fetch</code> it will either warn you about the change or just automatically update <code>refs/remote/origin/HEAD</code> to the appropriate value depending on what setting you used.</p><p>[<a href="https://github.com/git/git/compare/cc01bad4a9f566cf4453c7edd6b433851b0835e2...761e62a09a8248bbab065a7159977a5de6d12aba">source</a>, <a href="https://github.com/git/git/compare/ae75cefd94075045edeb1d23283a47e4e48a9360...a1f34d5955035dc64f2e25da0ba2cc0a0c73c21c">source</a>]</p></li><li><p>Partial clones also received some love this cycle, fixing an infinite loop and avoiding promisor to non-promisor references that could break the repository after a <code>git gc</code>.</p><p>For those unfamiliar with partial clones or want to learn more about their internals, you can read the guide “<a href="https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/">Get up to speed with partial clone and shallow clone</a>.”</p><p>[<a href="https://github.com/git/git/compare/51ba60116019e03dee4c1b98107fb376aabcf1b1...486c9d3995c432510457656332a810b4d4dab547">source</a>, <a href="https://github.com/git/git/compare/090d24e9af6e9f59c3f7bee97c42bb1ae3c7f559...0c11ef13565b7428437645d8c54cce4fbbc7df36">source</a>, <a href="https://github.com/git/git/compare/8eaa06590fe916d4f2baa1fdb93959f1cfa9ab47...1f3d9b981465a8320878c725d2dd5924f452e786">source</a>, <a href="https://github.com/git/git/compare/4007617fda480f18a879ee733a5bc6540e29352c...ededd0d5dceefc308c670f4ed5f9fc727184e83d">source</a>]</p></li></ul><hr/><h2 id="the-rest-of-the-iceberg">The rest of the iceberg<a aria-label="The rest of the iceberg" class="heading-link pl-2 text-italic text-bold" href="#the-rest-of-the-iceberg"></a></h2><p>That’s just a sample of changes from the latest release. For more, check out the release notes for <a href="https://github.com/git/git/blob/v2.48.0/Documentation/RelNotes/2.48.0.txt">2.48</a>, or <a href="https://github.com/git/git/tree/v2.48.0/Documentation/RelNotes">any previous version</a> in <a href="https://github.com/git/git">the Git repository</a>.</p><p><!-- Footnotes themselves at the bottom. --></p><h4 id="notes">Notes<a aria-label="Notes" class="heading-link pl-2 text-italic text-bold" href="#notes"></a></h4><div class="footnotes"><hr/><ol><li id="fn-81991-1">A better time would have been in the Highlights from Git 2.47 blog post, but who’s counting? <a href="#fnref-81991-1" title="Return to main content.">↩</a></li><li id="fn-81991-2">By default, anyway. You can specify a name other than “origin” with the <code>-o</code> option <a href="#fnref-81991-2" title="Return to main content.">↩</a></li></ol></div></body></html><p>The post <a href="https://github.blog/open-source/git/highlights-from-git-2-48/">Highlights from Git 2.48</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Highlights from Git 2.48" href="https://github.blog/open-source/git/highlights-from-git-2-48/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Highlights from Git 2.48</span><span class="cap link fs12">https://github.blog/open-source/git/highlights-from-git-2-48/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>年末聊胶2024！鬼鬼老师加盟畅谈拼装与把玩</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f162ecf3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f162ecf3.html</id>
    <published>2025-01-10T09:30:00.000Z</published>
    <updated>2025-01-10T09:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/c1c041a19f19517be237d8fc41c8e7a8-1600-750.jpg?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><ul></p><li>嘉宾：鬼鬼老师</li><li>企划、录制：Kazuya</li><li>后期：老斧子</li></ul><p>年末聊胶2024年底压轴节目，今年请到鬼鬼老师加盟，与我们痛快聊胶！</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="年末聊胶2024！鬼鬼老师加盟畅谈拼装与把玩" href="https://www.gcores.com/videos/193337" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">年末聊胶2024！鬼鬼老师加盟畅谈拼装与把玩</span><span class="cap link fs12">https://www.gcores.com/videos/193337</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>类FTL海战Roguelike游戏《夺海奇航》公布中文试玩版和全新宣传片</title>
    <link href="https://blog.imc.re/RSSBOX/rss/c93a9bc2.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/c93a9bc2.html</id>
    <published>2025-01-10T09:14:07.000Z</published>
    <updated>2025-01-10T09:14:07.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/b77938c5cf8f51e5c7de5720eb9d4bfa-1385-779.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p> 个人独立游戏团队1LastGame与独立游戏发行商 indienova 宣布，类FTL策略Roguelike游戏《夺海奇航》于2025年1月9日正式上线了中文试玩版本。团队也公开了全新的预告片，展示了更多游戏的实机试玩画面。  </p><div></p><figure><p>&lt;内嵌内容，请前往机核查看&gt;</p></figure></div><p>《夺海奇航》是一款航海模拟 Roguelike 游戏，设定在一个蒸汽朋克风格的幻想水世界中。在危机四伏的海域中，你将驾驶船只，带领海盗船员穿越重重险阻，力争生还，并拯救整个世界。</p><div><figure><img alt="" src="https://image.gcores.com/971238ec87cd1077a56293fb635249e0-1385-779.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>你将面临各种艰难的抉择，管理资源，花费金币购买装备、升级舰船，并招募新的船员。每次航行，你都会遭遇来自不同阵营的船只。你会成为一个遵守规则的船长，还是一个充满攻击性的海盗？你会选择保护被海盗袭击的民船，还是趁机大肆劫掠？</p><div><figure><img alt="" src="https://image.gcores.com/0e7717a350052c4932b4a2ab270e61e8-1385-779.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>在战斗中，你将拥有丰富的策略选择：消灭敌舰船员、点燃或击沉敌舰、远程炮击、还是近距离登舰作战……每一局游戏都因随机生成的地图和敌舰而独一无二，带来全新的挑战。</p><div><figure><img alt="" src="https://image.gcores.com/76d6463d0a715aedae23e2ebabbdee21-1385-779.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>《夺海奇航》目前已经在 Steam 商店页面上公布了游戏的最新试玩Demo，欢迎对游戏剧情和玩法感到好奇的玩家前往体验。</p><p><span style="font-weight: bold;">主要玩法</span></p><ul><li><span style="font-weight: bold;">指挥麾下的船员：</span>应对各种突如起来的任务：操控武器、掌舵、为蒸汽加速器充能、修复受损的设备，等等。</li><li> <span style="font-weight: bold;">将武器瞄准目标：</span>你是打算压制敌人的火力，还是降低他们的机动性？你是想要消灭敌舰上的船员，还是想击沉敌舰，用火力将其彻底摧毁？</li></ul><div><figure><img alt="" src="https://image.gcores.com/d99e6c8fd5c2ac2baae7d21dcaacde9c-1385-779.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><ul><li><span style="font-weight: bold;">强化你的舰船：</span>通过安装全新的武器、设备、舰船升级以及独特而强大的船首符文，不断增强自己的实力。</li><li><span style="font-weight: bold;">精心规划航线：</span>探索不同区域的程序生成地图。寻求盟友或选择对抗。权衡风险与回报，决定是继续航行还是停下来补给。</li></ul><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="类FTL海战Roguelike游戏《夺海奇航》公布中文试玩版和全新宣传片" href="https://www.gcores.com/articles/193358" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">类FTL海战Roguelike游戏《夺海奇航》公布中文试玩版和全新宣传片</span><span class="cap link fs12">https://www.gcores.com/articles/193358</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>哪来的傻缺图267期:宝牌启动，玩把超梦</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6470c82f.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6470c82f.html</id>
    <published>2025-01-10T09:00:00.000Z</published>
    <updated>2025-01-10T09:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/2361daa9f4a39fd303d28ca2e6363475-1288-748.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>在这个环节里，你能看见最近的一些傻缺动图、怪新闻、视频以及一些奇怪的东西。   </p><p>あらもん@Ara_love_kirby</p><div></p><figure><img alt="" src="https://image.gcores.com/e3e1097347010acf2966439fed47d3a3-1080-1350.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>米利菓@torako778</p><div><figure><img alt="" src="https://image.gcores.com/afab5d38f9428b84696f5543a990e23d-867-1200.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>禿@kaminokefusa</p><div><figure><img alt="" src="https://image.gcores.com/b35d6084db0bb5f361d9caa0c5f39f17-1650-1375.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>FINAL SAGA@finalsaga</p><div><figure><img alt="" src="https://image.gcores.com/d89fb008a85ad55074f88e385b5a56de-1152-1536.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>米利菓@torako778</p><div><figure><img alt="" src="https://image.gcores.com/59f74a7eeaeb678b6d7f17cd78d3c835-1111-1000.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p> KAKERU@DBSKAKERU1 </p><div><figure><img alt="" src="https://image.gcores.com/e17c196557dcbcad5f43b7892af56bc4-986-1754.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>ケースワベ 【K-SUWABE】@KSUWABE</p><div><figure><img alt="" src="https://image.gcores.com/15c4d91431a35a84e28d5a79f924122a-726-1026.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/b1a946da73270e12346c4093ade80772-286-352.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>Affea@Affea100</p><div><figure><img alt="" src="https://image.gcores.com/536ac0de52f6b58a951aaf74aaec8d09-1632-1020.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>HeyZAN-ロボを描く豚‐PARZIVAL@heyhey_heyzan</p><div><figure><img alt="" src="https://image.gcores.com/8edc35ecbcb81d3fbd5e349967acb432-2894-4093.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>杉谷庄吾 ｢映画大好きポンポさん｣ pompothecinephile@pompothecinema</p><div><figure><img alt="" src="https://image.gcores.com/314358ab994dca49ae456df6c5290e2c-1629-1200.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>くまごろ@kumagoro_mk2</p><div><figure><img alt="" src="https://image.gcores.com/7e82527e5e63b9b7a906b6442c448117-595-842.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>デカ井@dekai___inu</p><div><figure><img alt="" src="https://image.gcores.com/3f9d2073f961dcf3f162d1e0448d8362-1448-2048.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>Bita@Marghe_Bita</p><div><figure><img alt="" src="https://image.gcores.com/7a00864b16c78dc49949a02a163cd02c-840-1331.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>koma (コマ)@koma_98</p><div><figure><img alt="" src="https://image.gcores.com/5530c105642d4d32a95476eff6ab9e8e-4096-2373.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p><p></p><p>Aleriia_V (Lera)@Aleriia_V</p><div><figure><img alt="" src="https://image.gcores.com/5903369e25ec0fd9abf393c81be4c2d8-818-1200.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>miche@michemashu55</p><div><figure><img alt="" src="https://image.gcores.com/a326801a70dbe7a1ba52315b4634bc56-896-1280.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>Dirke@dirqe_</p><div><figure><img alt="" src="https://image.gcores.com/ac7b4a15130dc0656ec4f7bf2747d6b8-2800-3500.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/694c61940e19d47824c1394a22a021bf-1280-1856.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/1b1c15f400c29b6e43f94126b10f87ce-240-240.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p><span style="font-weight: bold;font-style: italic;">自即日起至1月28日除夕当天，站内多篇文章、录音笔、免费电台中将随机掉落20个新年红包封面，掉落的内容会在封面上有相应的提示，请朋友们保持关注，多刷机核网！</span></p><div><figure><img alt="" src="https://image.gcores.com/2ce0a39716d29eb8cbe750ca0173c0c0-510-510.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="哪来的傻缺图267期:宝牌启动，玩把超梦" href="https://www.gcores.com/articles/189942" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">哪来的傻缺图267期:宝牌启动，玩把超梦</span><span class="cap link fs12">https://www.gcores.com/articles/189942</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>我们是老了，还是累了，还是渴望生活了？录音笔 VOL.369</title>
    <link href="https://blog.imc.re/RSSBOX/rss/37da721f.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/37da721f.html</id>
    <published>2025-01-10T09:00:00.000Z</published>
    <updated>2025-01-10T09:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/6011ee8332f4b0149943f69ab04818c3-1600-900.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>【录音笔】是GPASS推出的一档全新会员专享节目，内容来自机核办公室日程生活和工作中的一些短小记录，每期时长十几分钟左右（大概吧）。内容也许是一些不成体统的碎碎念，也许是一些突然发疯的暴言，还有可能是哪个缺德的把办公室里真实的日常对话（dui ma）偷偷录了下来，总之就连我们自己现在也不知道每期会有哪些人参与，会录些什么。</p><p><span style="font-weight: bold;font-style: italic;">自即日起至1月28日除夕当天，站内多篇文章、录音笔、免费电台中将随机掉落20个新年红包封面，掉落的内容会在封面上有相应的提示，请朋友们保持关注，多刷机核网！</span></p><div></p><figure><img alt="" src="https://image.gcores.com/0ac8cf12d7c14326114198f2bd2a1030-510-510.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="我们是老了，还是累了，还是渴望生活了？录音笔 VOL.369" href="https://www.gcores.com/radios/193354" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">我们是老了，还是累了，还是渴望生活了？录音笔 VOL.369</span><span class="cap link fs12">https://www.gcores.com/radios/193354</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>为了进一步提高质量，手游“Chiikawa Pocket”发布推迟至2025年春季上线</title>
    <link href="https://blog.imc.re/RSSBOX/rss/23368210.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/23368210.html</id>
    <published>2025-01-10T08:59:05.000Z</published>
    <updated>2025-01-10T08:59:05.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/ea6338885eeaab24730f1cf6fd09c732-1280-720.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>2025年1月10日，Applibot宣布<span style="font-weight: bold;">“Chiikawa Pocket”</span>的发布将推迟至2025年春季。</p><div></p><figure><img alt="" src="https://image.gcores.com/64508df934e84e04f55f2ef99b1673ce-484-567.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>2024年8月发布的“Chiikawa Pocket”是“Chiikawa”的第一个官方智能手机应用程序。玩家可以在智能手机上享受“Chiikawa”的世界，收集物品来创建自己的家园，出去探险以击败危险的家伙并获得奖励，并收集食谱来制作各种菜肴。</p><p>对于推迟发售，官方X表示：“我们的目标是进一步提高质量，让Chiikawa粉丝们满意。”</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="为了进一步提高质量，手游“Chiikawa Pocket”发布推迟至2025年春季上线" href="https://www.gcores.com/articles/193355" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">为了进一步提高质量，手游“Chiikawa Pocket”发布推迟至2025年春季上线</span><span class="cap link fs12">https://www.gcores.com/articles/193355</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>乐高将与任天堂合作，推出GAME BOY版乐高积木</title>
    <link href="https://blog.imc.re/RSSBOX/rss/a21e72e3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/a21e72e3.html</id>
    <published>2025-01-10T07:21:54.000Z</published>
    <updated>2025-01-10T07:21:54.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/0a79762d84118e34c5c4d8fd4cc6295a-1018-573.jpg?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>乐高将与任天堂合作，推出GAME BOY版乐高积木，2025年10月发售，售价未知。</p><div></p><figure><p>&lt;内嵌内容，请前往机核查看&gt;</p></figure></div><div><figure><img alt="" src="https://image.gcores.com/5f4b2418a6643a71adb2bdb515cab93e-1018-573.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="乐高将与任天堂合作，推出GAME BOY版乐高积木" href="https://www.gcores.com/articles/193347" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">乐高将与任天堂合作，推出GAME BOY版乐高积木</span><span class="cap link fs12">https://www.gcores.com/articles/193347</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>《艾尔登法环 黑夜君临》最新视觉图公开，将于今晚开启测试招募</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6e9ec1d6.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6e9ec1d6.html</id>
    <published>2025-01-10T06:54:19.000Z</published>
    <updated>2025-01-10T06:54:19.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/fa86f10fa485a4ae03f0577b15cbec83-1920-1080.jpg?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>《艾尔登法环 黑夜君临》将于今日开启测试招募，平台为PlayStation&#x2F;Xbox，感兴趣的玩家可到官网报名，截止日期为1月20日。</p><div></p><figure><img alt="" src="https://image.gcores.com/29f950c3631d3fd916bbfb220d2de676-690-690.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>本作中文版将于2025年正式发售，登陆PS5／PS4／Xbox Series X|S／Xbox One／Steam平台！ </p><p><span style="font-weight: bold;">测试时间：</span></p><div><figure><img alt="" src="https://image.gcores.com/b1c6bae993912381f6db382ad63cf0da-690-388.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p><span style="font-weight: bold;">目前公开的视觉图：</span></p><div><figure><img alt="" src="https://image.gcores.com/36553d4bc687e5fa4d1f2ea465823669-1920-1080.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/2919172031a1b922d1e0c95cf69fd8e4-1920-1080.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/be2e09a3da2ad5165c2ca34b92488561-1920-1080.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="《艾尔登法环 黑夜君临》最新视觉图公开，将于今晚开启测试招募" href="https://www.gcores.com/articles/193346" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">《艾尔登法环 黑夜君临》最新视觉图公开，将于今晚开启测试招募</span><span class="cap link fs12">https://www.gcores.com/articles/193346</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>漫谈随笔：为什么独立游戏能做好叙事？</title>
    <link href="https://blog.imc.re/RSSBOX/rss/219ad5c3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/219ad5c3.html</id>
    <published>2025-01-10T06:30:00.000Z</published>
    <updated>2025-01-10T06:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/4fadc90954c62832fd7bcee726f002d7-2371-1260.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>12月索尼二档订阅库入了好几款独立游戏，一口气游玩后，脑海中冒出一个想法：为什么这样气质的游戏——独特的艺术风格，完整、精炼的故事，整个流程都是剧情体验——总是出现在“独立游戏”中？</p><p>当然，通常的回答可以是，商业游戏迎合市场和投资方的需要，有着固定的类型和赛道，和相对贴近大众的审美；而独立游戏则可以发挥制作人的想象力和巧思，是“制作人中心”的，就如同“作者电影”、“独立电影”和“商业电影”、“类型电影”的区别……</p><div></p><figure><img alt="独立游戏《咖啡心语》讨论“艺术游戏”" src="https://image.gcores.com/d56e45b7c8de1f3132af7808dcad01a8-3403-1896.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/><figcaption>(独立游戏《咖啡心语》讨论“艺术游戏”)</figcaption></figure></div><p>然而这并不能体现这些游戏的共性，为什么独立制作就一定那么特别？难道大厂讲不好一个故事吗？——客观来说，大厂尤其是欧美大厂的一整个开发组织架构中，从创意总监/叙事总监、Leader设计师到大量的剧作家和任务设计师，都具有很高的艺术素养，尤其是一些人才本身就是从独立创作者和小型工作室转来。</p><p>这里随机列举一些有类似气质的作品，以同步我们在聊什么类型：</p><p>《Inside》《Cocoon》《烟火》《三伏》《Limbo》《史丹利的寓言》《Undertale》《艾迪芬奇的记忆》《Stray》《渔帆暗涌》</p><p>《她的故事》《传世不朽》（同一作者，互动电影），</p><p>以及我最近玩的几款游戏《咖啡心语》《无垠之心》《魔女之泉R》。</p><p>我并不是一名狂热的独立游戏/艺术游戏爱好者，所以只是从一个普通玩家的角度，对我接触到的这些游戏进行漫谈。</p><h1>游戏与叙事</h1><p>游戏诞生之初就和叙事脱不开干系——在电子游戏早期就有了冒险游戏和文字游戏的类别，游戏被当做叙事的载体；而在学术研究中，对于电子游戏的研究，根据对本体的认知更是分化为几种派别，最为突出的就是叙事学取向和游戏学取向。即使是最为激进的游戏学学者，将叙事学研究游戏称为一种“理论帝国主义”，强调游戏的双向动态媒体属性，也无法否认故事、背景故事和情节在游戏中的作用。新媒体学者亨利·詹金斯在2004年的文章《Game Design as Narrative Architecture》（这篇文章在十年后也被引为讨论“环境叙事”的理论）中提到的观点很有代表性：当你回忆起一款游戏，并讲述给其他人的时候，通常是以故事的形式。</p><p>当然这些观点都代表不了发展至今已然成熟的电子游戏——总而言之，游戏的交互和传播机制与以往的任何媒介都不同，但也不能抛开叙事在游戏中的地位。同时，<span style="font-weight: bold;">游戏有独属于自己的叙事功能。</span></p><p>翻开TGA/VGA的最佳独立游戏提名列表，为什么“优秀的故事”这个标签总是挥之不去，而其他游戏类型的大奖则不然。诚然老COD、FF这些游戏在影视化演出和剧情编排上也浓墨重彩，却很难让故事的整体给玩家带去深刻的印象，并且很花钱。早在20年前的游戏设计师就在探讨游戏理论时提到，用游戏来做叙事是一件成本非常高昂的事情。</p><p>用今天的视角来看，不谈宣发成本的上限，一款3A大型游戏开发成本和拍摄一部全特效虚拟拍摄的CG电影的成本相差无几，而二者面对的受众群体数量却是天差地别，所以制作一款大型游戏用以叙事，不得不面临成本的难题。</p><p>从成本的视角出发，确实有一些低成本的限制所带来的独特体验。</p><h1>独特的艺术风格</h1><p>其一便是独特的艺术风格，在下对美术纯外行，只是说一下感受。2D卡通和像素风不必多言，已经成为了一个独特的符号和类型，甚至有八方旅人这样特地制作成HD2D像素风格的大型游戏，以及近年很火的3D体素艺术。还有一些我的见识不足难以归类的艺术风格，使用了材质比较单一的3D多面体模型。</p><div><figure><img alt="" src="https://image.gcores.com/223e9e09818e6d061433b566871c2f46-1920-1080.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/bded3c8de8c1fd27848534141f5efc78-600-337.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>从我这个外行看来，这些像素、多面体的美术素材，可以从原画概设 → 模型素材的过程中节约不少成本，以实现更加高效的创意落地。</p><p>同时因为画面不够仿真，类似抽象艺术的体验，玩家的体验会更加沉浸于表现的内容本身，而不是画面中的细节。我的知识领域内，电影能够震撼观众的一大原因也是因为影像技术的奇观，可以超越现实眼睛视野，去还原物质本身的细节，所谓“<span style="font-weight: bold;">视觉奇观</span>”。许多画面优秀的电影里，当大荧幕上出现逆光拍摄的肉体，硬朗的光线打在肌肤上，表现出毛孔斑斑驳驳的凹凸感和肉感，唯美的氛围超越了现实中眼睛之所见，观众就得到了享受。在此场景下，光线、表演都是人造的，镜头是跳脱出人眼的透视和视野的，金钱塑造出了优美的艺术。</p><blockquote>奇观（英语：Spectacle）在摄影领域中，指透过拍摄，每一个物件、状态、组合抑或过程，都得以展现“美”，且任何时刻皆无可比拟，任何人都独一无二，透过拍摄，从而拯救平凡、老套和卑微的事物，得以将日常转化为“奇观”。</blockquote><p>这里的描述应该不允许我放出具体的图像，大家可以自行想象。总之，仿真的画面、影视化的画面，会让人自然地关注细节。而失去了这种欣赏角度时，大脑则非常冷静，开始思考起画面中的抽象物体在现实中映射的原型，以及画面中正在发生的故事，尤其是像《Limbo》《Inside》这样相机运动非常克制、相机视角远离角色的画面，产生了<span style="font-weight: bold;">间离效果</span>，玩家的相机类似舞台下的观众的画面。</p><blockquote><span style="font-weight: bold;">间离效果</span>（英语：Distancing effect；德语：Verfremdungseffekt），又称<span style="font-weight: bold;">陌生化效果</span>、<span style="font-weight: bold;">疏离</span>，是<a href="https://zh.wikipedia.org/wiki/%E5%BE%B7%E5%9B%BD">德国</a>戏剧理论家、剧作家<a href="https://zh.wikipedia.org/wiki/%E5%B8%83%E8%8E%B1%E5%B8%8C%E7%89%B9">布莱希特</a>所提出的戏剧表演理论，是指将观众疏远于戏剧或电影，这被<a href="https://zh.wikipedia.org/wiki/%E5%B8%83%E8%8E%B1%E5%B8%8C%E7%89%B9">布莱希特</a>称为叙事诗剧场（德语：Episches Theater）。<a href="https://zh.wikipedia.org/wiki/%E5%B8%83%E8%8E%B1%E5%B8%8C%E7%89%B9">布莱希特</a>认为戏剧应为政治服务；观众对舞台上的戏剧投射情感会妨碍观众的冷静判断。在剧本的创作上，他多以异国的、模糊的时空背景，并运用说书人讲述故事，以达到观众与剧情间的疏离效果。 </blockquote><div><figure><img alt="" src="https://image.gcores.com/4d5517469c1eabf9f9771ca58e52096e-1280-403.webp?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p></p><h1>轻量级玩法和一次性谜题</h1><p>其二是玩法设计，我将多种设计概括为“轻量级玩法”。这其中有多种表现：</p><h1><span style="font-weight: bold;">1、深度有限的核心玩法</span></h1><p>不难发现，许多美名广传、被奉为“第九艺术”的优秀独立游戏作品，常常围绕横版过关、平台跳跃这几个名词出现，动作性上也不会有复杂、高难度的操作。不难理解，大型游戏也会提供“叙事难度”选项，对于叙事来说，玩法的深度和难度只需要维持在一个必要的值，力求不阻断叙事的沉浸体验，“刷刷刷”和“构筑”更是天外之物。</p><p>恰巧看到知乎上的一个问题：“<span style="font-style: italic;">为什么电影可以两个小时讲好一个故事，而3A游戏需要几十个小时？能否通过缩短流程来节省3A游戏成本？</span>”这或许可以从反面解释玩法深度对于叙事的影响。</p><p>笔者认为，比起3A游戏“需要”几十个小时讲好故事，更多的是游戏制作人“需要”几十个小时的游戏流程，为此去设计了几十个小时的故事。主流的玩法，如动作游戏、回合制RPG，都对战斗系统本身有深度要求。动作游戏里各种动作的循序渐进式的升级，以对应玩家的操作熟练度，装备、加点流派……更不谈RPG游戏的局内局外养成，这些要求游戏深度的内容都会使得制作人和设计师做出一个有体量的游戏。那么叙事设计师也必须为了这种游戏体量去设计叙事的节奏、信息量和故事的长度。</p><p>而许多独立游戏，例如《艾迪芬奇的记忆》《烟火》《三伏》《她的故事》《传世不朽》等等，都能在极短的时间里讲好故事，哪怕是有一定资本的Josef创作的《双人成行》《逃出生天》也是如此。这些游戏有一个特点，就是轻玩法、重叙事，这些游戏的交互体验是为了叙事服务的，和动辄几十小时的3A大作最显著的特征就是没有战斗系统。</p><p></p><h1><span style="font-weight: bold;">2、甚至可以没有传统意义的核心玩法</span></h1><p>向一名朋友分享《咖啡心语》这款游戏里的内容时，他问我：“这款游戏的玩法是什么？”</p><p>我说：“玩法就是深夜食堂，听顾客们聊天、泡咖啡。”</p><p>他说：“那核心玩法是泡咖啡吗？”</p><div><figure><img alt="" src="https://image.gcores.com/7021b38324ae7960fe2002893d5cb09b-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>这个问题突然令我觉得很有意思。如果硬要说核心玩法，我会说这是一个叙事冒险游戏，主要由故事+探索组成（因为《烟火》《三伏》《无垠之心》这样子的游戏也难以简单称为文字游戏或视觉小说）。大多数玩家会习惯于用成熟的游戏类型标签去定义一款游戏，来获得对一款全新游戏体验的预期。比如我听说一款新游是类魂动作游戏，便会唤醒我内心深处对于黑暗之魂的深刻大脑和肌肉记忆，主动去了解和试玩这款游戏。</p><p>或许这些独立游戏和艺术游戏特别的一个原因就在于它们可以没有传统意义上的核心玩法，或者对于传统玩法进行深度的改造，来打造一种全新的游戏体验流程。平台跳跃，但是玩家的关注点可能并不在平台的高度、距离，而是周遭的环境和故事。解谜，但是谜题可能缘起于一个概念，比起谜题的逻辑，玩家更关注游戏中的概念和艺术……</p><p>我会说《咖啡心语》的玩法就是“深夜食堂”，是基于游戏的流程让玩家扮演好一名固定在吧台倾听顾客心声的店主角色，泡咖啡是故事的一部分，而不是传统意义上的模拟经营游戏，也可以说这款游戏泡咖啡的玩法深度过薄，远远低于常规的咖啡厅经营游戏（如开罗游戏）。</p><p>正如游戏角色的台词所提到的，“因为，你也知道……有的时候，人们想要的，和他们所需要的并不总是一样。”作为这个咖啡厅的老板，泡咖啡是为了迎合顾客的需求，是为了了解他们的性格和爱好，也是一种和客人交流的方式。当顾客拖着异常疲惫到马上撑不住的身躯声称自己要加班整夜，去应对交流会上排山倒海般的意见去做修改，向老板点单“三倍浓缩咖啡”时，玩家可以选择递出一杯温暖、甜蜜的牛奶，帮助她缓解压力、辅助睡眠。这种错误的“出单”，通常是不会在模拟经营游戏中出现的，而让这种交互更加倾向于<span style="font-weight: bold;">交互叙事的方向</span>。</p><div><figure><img alt="" src="https://image.gcores.com/e8034d594520e1df02670aae202f6d28-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>所谓交互叙事，就是做到只有游戏才能做到的叙事。比如《咖啡心语》采取的这种与叙事更贴合的、简单的玩法，也使得游戏整体的流程非常短，于是作者又在紧凑的游戏流程中设置了“多周目”来揭示角色和世界观，利用“多周目”这种游戏媒介的特点来说故事惊艳玩家。</p><p></p><h1><span style="font-weight: bold;">3、个人独游设计经验：玩法是叙事综合体</span></h1><p>我设计过一款互动电影游戏，但画面是用AI生成的仿影视剧静态画面，这个项目正在落地中。</p><p>在流程中设计玩法时，我需要让一名死者说话。</p><p>我随即就有一个想法，因为故事主题本身是关联着“古拳法”等网络舆论现象，所以我希望这名死者“用”<span style="font-weight: bold;">社交媒体的大号和小号来为揭露自己的人生轨迹</span>。对于当代人来说，“死后销毁我的历史记录”、“把我的硬盘烧了”是一种幽默诙谐的表达，它传递了一种讯息，就是我们将那些没法大方展露给有着巨大代沟的家人的生活都埋藏在了数字世界里，无论是本地数据还是网络痕迹。</p><p>在一款游戏里玩手机、玩网页浏览器，并不是我的独创。《她的故事》里就通过警察局的一台电脑来推理出一个故事；设计完自己的作品后，我又看到一款游戏《全网公敌》也用了查看社交媒体和搜索引擎去探案的方法……</p><p>但这很难定义为任何一种传统的玩法，我认为更加接近<span style="font-weight: bold;">“模拟”</span>。正如Steam上火爆的各类《XX模拟器》，其实是将一种<span style="font-weight: bold;">还原现实世界的视听觉、交互方式、任务和目标</span>，还原到一款游戏中。所以在《咖啡心语》，或是我的设计里，插入的玩法其实是围绕着叙事展开的一种拟真、交互或推理，是<span style="font-weight: bold;">叙事的一种元素</span>。</p><p></p><h1><span style="font-weight: bold;">4、一次性的谜题</span></h1><p>传统中大型rpg项目，关卡/任务策划需要灵活运用游戏系统能提供的交互方式和玩法元素，让玩家在游戏中掌握的经验和技巧不断地得到提升和验证，也能提升关卡体验的丰富性和多样性。这样一来，几十小时的游戏体验的长期循环和短期循环就会比较一致，让玩家可以无痛地、爽快的体验完整个流程。</p><p>而许多叙事性独游，为了叙事目的设计的“并非玩法”的“玩法”，常常不具备复玩性。一次性的解谜、XX模拟十分常见。 </p><div><figure><img alt="" src="https://image.gcores.com/e42643f0696d7d7619e1abf6d7e0f0a7-2268-1268.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><div><figure><img alt="" src="https://image.gcores.com/aeb7416eb342bed0a3831052d7c64708-2236-1254.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>令我印象深刻的就是《三伏》中“莲花局”的片段，设计了将三卷胶片放入化学试剂里，可以生成并收集对应角色共存的剧情碎片片段，来探索整个事件的真相。这个玩法有些类似《传世不朽》作者设计的，让玩家来当剪辑师，去三部电影的拍摄素材中探索正确的故事顺序和现实世界中演员的背景故事。还有通过莲蓬头去找到正确的根部找到线索的桥段，也设计了一个小玩法，这个玩法并不会在游戏中再次出现……</p><p>放到大型项目中，一次性谜题、一次性玩法的设计是奢侈的，也会徒增游戏资源量。但在以叙事为主线的游戏中，提供简单的一次性谜题却能给人留下深刻印象，这也是独立游戏能做好叙事的一个原因，游戏本身只为叙事服务，对游戏体量并没有硬性要求。</p><p></p><p></p><p>最后，本人并非一个“独立游戏创作者”，也非专精该领域的狂热爱好者。仅仅是在休息时间，和大型游戏的倦怠期体验一些叙事向的独立游戏，它们确实能带给我很多的惊喜和深刻印象，据此有感而发。这些游戏的艺术性都很值得探讨。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="漫谈随笔：为什么独立游戏能做好叙事？" href="https://www.gcores.com/articles/193131" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">漫谈随笔：为什么独立游戏能做好叙事？</span><span class="cap link fs12">https://www.gcores.com/articles/193131</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>2024个人向年度游戏总结</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6b7bbcf4.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6b7bbcf4.html</id>
    <published>2025-01-10T05:21:56.000Z</published>
    <updated>2025-01-10T05:21:56.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/1a9bbc800ed4f4ebdcd073f1bda2264e-1179-754.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>去年的稍早时候，笔者在机核投稿了第一篇文章，收获了不错的反响，也算是点燃了我对社区讨论的一些热情。于是时隔一年，还是决定回到机核，无论如何也要给过去一年的游戏生活来个总结，也是给新一年留些盼头。在这个不尴不尬的时间点，也祝愿看到这篇文章的读者们，过去一年或多或少陪伴过我的编辑部老师们，新年快乐，吉祥如意。</p><p>由于一些私人原因，明显感觉到今年投入在游戏上的时间变少了，玩游戏的时候也多次出现心不在焉的情况。也不止是游戏，能感觉到对电影、戏剧、生活的精力与热情也在衰退。总的来说，今年一共通关了9款游戏，相较去年少了近三分之一的总量。同时，开了个头没有玩下去的游戏也变多了，例如《最终幻想起源》《八方旅人》和《海市蜃楼之馆》；去年立志要玩完的《最终幻想零式》《勇者斗恶龙11S》等也没有继续玩下去。如果要再为明年立一个目标的话，还是希望能定下心来，把手头上这些开了坑的游戏好好地收官封盘。</p><p>为了让文章的内容量更加充实，今年决定提升一些文本质量与深度，更想着重于笔者个人的专业方向去讨论，Gameplay的部分会略微减少一点。届时可能也会引入一些理论与概念，如若感到枯燥，还望诸位海涵。</p><p>那么接下来与诸位分享，2024年共计9款游戏的个人感受。</p><h1>1 《战神：诸神黄昏》 4</h1><p>这款游戏我是在它2023年12月发售DLC后游玩的，所以严格意义上并不能完全算是一部我在2024年玩的游戏。虽然我也不是很喜欢这款游戏，但是还是有两点值得与各位说道说道。</p><p>一是，《战神：诸神黄昏》并不是一个好的续集故事。</p><p>所有的续集故事都要面临的一个问题，你要如何让一个已经在前一部作品中拥有了完整弧光的人物更进一步，更加完整？</p><p>在前一部作品《战神4》的结尾，奎托斯与儿子阿特柔斯历经险阻力克强敌，登上了九界最高的山。儿子将母亲的骨灰递给父亲，父亲将骨灰袋推回给了儿子，并说了一句 “We do together, son.（儿子，我们一起）”。到此为止，从剧作角度来说，父子和解的戏剧效果已经达成了。儿子完成了对父亲的理解，父亲也完成了对儿子的认可，这一对父与子的人物关系已经完满了，在续集中要如何进一步深挖这对父子关系，让人物更加完整呢？</p><p>《战神5》给出了最摆烂，最不用动脑子的解法。那就是把《战神4》复刻一遍。</p><div></p><figure><img alt="" src="https://image.gcores.com/3f6a3e717c5b860f2faacba862095019-3456-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>所以在《战神5》中，玩家可以看到一个处于青春期事事叛逆的儿子，和一个如同反驳型人格，只会复读‘You’re not ready’的父亲。前期的所有剧情推动全靠父子二人的斗嘴，但这一切都已经在《战神4》里预演了一遍了。两个人的人物形象没有一丝一毫的进步。同时，这也就是“亲情”这种普世的、大众的亲密关系在文艺作品里的流氓之处。试想一下，如果二人不是父子关系或母子关系或兄弟姐妹关系，而是一对普通的队友与搭档，福尔摩斯与华生，蝙蝠侠与罗宾，没头脑与不高兴，观众会像这样不在乎剧情的合理性吗，还会用“父亲对儿子严厉的爱”这样蹩脚的理由来替编剧圆吗？</p><p>所以回到问题本身，一个好的续集故事应该是什么样的。</p><p>这里笔者给出两个例子，一是2023年的《壮志凌云2：独行侠》；二是2004年山姆·雷米版的《蜘蛛侠2》。这两部作品都是非常经典的让主角经历新的困境，并使主角完成第二次成长的续集故事。</p><p>《壮志凌云2》，阿汤哥已经当了30多年的战斗机飞行员了，他老了，飞行员这个行业也老了。所以他面临的新的困境是，如何不被新的无人驾驶技术取代。他需要向他的上级，向全世界证明，在这个新时代里，旧时代的余晖仍然可以发光发热，而他成功地做到了。这就是人物经历了新的困境，并完成了再一次成长。</p><p>《蜘蛛侠2》则更绝。它剖析超级英雄的内心，超级英雄也是人，彼得·帕克没有办法平衡好帕克的生活与蜘蛛侠的工作，于是他选择放弃当蜘蛛侠。但历经险阻打打杀杀后幡然醒悟，只有戴上蜘蛛侠的面具，他才能维护和保护好彼得·帕克的私人生活，更进一步地了解了贯穿整个蜘蛛侠系列的“能力越大责任越大”的含义。</p><p>所以再回到《战神5》，发现了吗，甚至直到故事结尾都没有突破《战神4》父子二人撒骨灰的人物形象，两个人的人物弧光是没有丝毫的进步与成长的。而与上文两个例子做比对更加发现，上文的两位人物都是自发地，向内挖掘新的故事动机，所以人物是与故事的表达紧密相扣的。而《战神5》的故事起点则是父子二人“被迫”卷入芬里尔之冬，然后来一个意料之中的反转，死一个无关紧要的配角，到最后整个故事也并没有什么记忆点，更不要说有什么表达了。</p><div><figure><img alt="" src="https://image.gcores.com/d318fe5dea4465895220eb174bec5ca9-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>硬要提圣莫妮卡找补几句的话，其实他们也发现了这个问题，在游戏过程中可以感受到他们想去深挖角色更私密的形象。例如奎托斯侠骨柔情的一面，试图去塑造他与妻子之间的一些互动，或是去塑造一个情窦初开的青春期男孩。但我还是觉得他们做的挺失败的，一是如上文所说的，这些桥段并没有在我的记忆中留下很深刻的记忆点，二是明显能感觉到这样的感情不够“真”。所以我会想向喜欢《战神5》故事的玩家们推荐葛韦格导演的《伯德小姐》，同样是一个很俗套很工业流水线的故事，来看看葛导是如何用情感来俘获观众们的。</p><p>第一点说的有点长，第二点也比较抽象我尽量长话短说。那就是，《战神5》反映了市场的导向以及玩家价值观的变化。</p><p>这就要提到整部游戏中，我个人最喜欢的一处场景了。在游戏的中段，奎托斯骑着凯尔派去找命运三女神，三女神十分详尽地以旁白的形式叙述了这场戏，预知了奎托斯要说的每一句台词，并最终给出了一个非常强烈的暗示，奎托斯命中注定会死。</p><p>现在我们知道这算得上是新战神为数不多的妙笔，从《战神4》就开始铺的一个叙述性诡计。从前一部结尾奎托斯看到壁画上一名男性死在阿特柔斯的怀里，我们就开始猜测，是不是最终奎爷会死，是不是奎爷又要杀出冥界，是不是奎爷又要流亡去往一个新的国度，但几乎我们不会去猜到死在阿特柔斯怀里的并不是奎爷而是奥丁或是其他人。因为在潜意识里我们冥冥意识到，这样的剧情编排是违背战神这个故事的调性的，因为在战神的故事里，命运应该是不可更改的。</p><p>是的，不管我们再怎么喷战神的故事，说它是男性爽文，欧洲起点，但其实战神的故事是十分契合古典希腊悲剧的核心理念的。即“英雄与他不可回避的命运做斗争，并最终被所命运打败”。</p><div><figure><img alt="" src="https://image.gcores.com/8f6d93749988fe7d3b4fd73db22355ca-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>我们不与历史上鼎鼎有名的《俄狄浦斯王》《美狄亚》《普罗米修斯》之流做对比，我们就拿战神的故事做纵向对比。《战神：斯巴达之影》里是有预言说，人间有个脸上带疤的祸害最终会弑父并推翻奥林匹斯的统治，于是宙斯才派阿瑞斯下凡去杀了奎托斯弟弟防范于未然。不管这是不是《战神3》推出之后对设定的填充吧，最终我们也都知道奎托斯的确手刃了亲父宙斯，也在脸上留下了疤痕，这体现的正是命运的不可回避性。同样的在《战神1》中，阿瑞斯设计使得奎托斯亲手杀害了自己的妻女，并将骨灰附着在奎托斯身上，成就了奎托斯的经典形象。而这体现的其实也是古希腊悲剧中的一个理论，即为亚里士多德的悲剧过失说。即 “（主人公）并不十分善良，也不十分公正，他之所以陷入厄运，并非由于他为非作恶，而是由于他犯了错误。” 在这样宿命论与古希腊悲剧式的剧作方法下，战神的故事基调还是相当严肃的。</p><p>但现在的问题是，现在的市场与受众，其实是并不能接受这样比较严肃的故事的。国内外正反各举一个例子的话就是《逆行人生》和《鱿鱼游戏》，主要宗旨就是“生活都这么难了还要喂我这么苦逼兮兮的故事”。无法否认的一点是，现在主流观众的主要诉求就是短平快和奶头乐，就算是正剧，也得是《复仇者联盟》那种“笑中带泪”的“大制作”才买单。所以能够看见从4代开始，整个故事向好莱坞主流的工业剧本开始看齐，先用公路片模式试水，到了5代是完全模仿《复联》式的每个人物一条线，最后集合打boss的故事模板。这就是市场带来的变化。</p><p>而观众价值观的改变也体现于此。新时代的观众其实是不吃古希腊悲剧命运论的那一套的。你现在在街上随便拉个人问TA信不信命，TA估计会以为你是来算命的。这一套对于命运的看法早在1994年《阿甘正传》乃至更早之前就已经改变了。不要小觑文艺作品对于价值观潜移默化的影响，新好莱坞这一代对于美国梦的宣传早已将“努力可以改变命运”的价值观深深种进一代观众的脑海里植根发芽了。而更新的，未被“老登”价值观染指的Z世代则对命运有着更新的理解，但这就不在今天的讨论范畴之内了。此处的重点是，《战神5》舍弃了传统古希腊悲剧的宿命论，拥抱了主流受众（存疑）的主流价值观。</p><p>所以这也是《战神5》这一处叙述性诡计写的妙的地方。虽然它做出了迎合主流市场主流价值观的选择，引导玩家认为奎托斯的命运得到了改变。但它又并不是对奎托斯命运的直接改写，而是一个巧妙的误导，既保全了战神故事原有的基调与宿命论应有的厚重感，又没有得罪与冒犯了玩家群体，可以说是现代商业作品里少有的一举两得的妙笔了。</p><h1>2 《绯夜传说》 7</h1><p>在年初游玩的时候我也不会想到，这部作品竟然会变成年终我最有话讲的一部作品。</p><p>而对于这部作品我又是十分矛盾的。因为于我个人而言，我并不是十分喜欢这一部作品；但从专业性角度出发，我认为所有的游戏编剧，对游戏叙事感兴趣的玩家，都应该来好好阅读一下这个故事。</p><p>在游玩这个游戏的时候，我又同样地想起这样一部我个人并不是很喜欢，但是所有的游戏编剧都应该拉出来学习一下的游戏。所以在下面的分析中，我会将这两部游戏做一个横向对比，而那一部游戏就是，《最后生还者》1代。</p><p>在正式介绍两部作品之前，我需要引入一个概念，一个正儿八经的故事模板，布莱克·斯奈德的“救猫咪节奏表”:</p><ol><li><span style="font-style: italic;">开场画面 Opening Image（1）</span></li><li><span style="font-style: italic;">阐明主题 Theme Stated（5）</span></li><li><span style="font-style: italic;">布局铺垫 Set-up（1—10） </span></li><li><span style="font-style: italic;">触发事件 Catalyst（12）： </span></li><li><span style="font-style: italic;">展开讨论 Debate（12—25）：</span></li><li><span style="font-style: italic;">进入第二幕 Break into Two（25）：  </span></li><li><span style="font-style: italic;">副线故事 B Story（30）：  </span></li><li><span style="font-style: italic;">玩闹和游戏 Fun and Games（30—35）：</span></li><li><span style="font-style: italic;">中点 Midpoint（55）：</span></li><li><span style="font-style: italic;">反派逼近 Bad Guys Close in（55—75）： </span></li><li><span style="font-style: italic;">失去一切 All is Lost（75）：  </span></li><li><span style="font-style: italic;">灵魂黑夜 Dark Night of the Soul（75—85）：</span></li><li><span style="font-style: italic;">进入第三幕 Break into Three（85）：</span></li><li><span style="font-style: italic;">结局 Finale（85—110）</span></li><li><span style="font-style: italic;">终场画面 Finale Image（110） </span></li></ol><p>具体的这些情节点所对应的意味有感兴趣的朋友可以自行查询（目前世面上浙江大学出版社的《救猫咪》翻译水平较为一般，有能力的建议还是阅读原文）。并且由于游戏与电影的叙事结构还是存在较大的差异，此处也只是简单借用一下这个概念。一言以蔽之，这是一个可以套用在市场上90%以上商业类型片的故事模板。有趣的是，如果将《最后生还者》与《绯夜传说》（下文缩写为《TLOU》与《TOB》）的故事代入进这个模板，可以发现它们与这个模板有着极高的相似程度。</p><p>还是简单介绍一下这个模板。可以看到每一个节奏点的后面有一个数字，这些数字对应的是剧本上的页码。在标准的工业流程中，一页英文剧本可以约等于一分钟的电影时长。这些页码有的是一个独立的数字，而有的则是标注了一定的范围。也就是说这些节奏点有的是直接对应剧情中的某些“情节点”，而有些则对应的是剧情中的某些“桥段”。模板给出的总页数是110页，即可以看做这是一部时长约110分钟-120分钟的电影。根据这里所标注出的页数范围，我们亦可大致推测出这些桥段在整部作品中所占的比例。</p><p>根据模板我们来看第一个情节桥段，即“布局铺垫（Set-up）”。直接按字面意思理解即可，这一部分应该让观众建立起对主人公最基础的了解，TA长什么样，TA是一个什么样的人，TA的生活是怎样的，TA的驱动力源于何处。如果是有别于现实世界的奇幻故事，也应该大致地向观众展示一下世界观。在粗略介绍完主要人物过后，主人公会在这一阶段遭遇某些变故，TA平静的生活将会被打破。紧接着，就是模板中的第一处关键情节点，在这一模板中被称为“触发事件（Catalyst）（催化剂）”，而在另一个著名的故事模型中，这一情节点被称为“英雄收到召唤”，其实也就是我们常说的“激励事件”。这一个对于主人公异常关键的事件使得主人公进入了剧情，产生了矛盾冲突，也确立了行动目标，也可以看做是主人公人物弧光产生变化的关键节点。此时也就确立了整部故事的基调，以及主人公的动作性需求，即整个故事最终所要达成的结果。</p><p>按照模板来看，在进入第二幕之前还有一个长约15页的桥段，被称为“展开讨论（Debate）”，翻译为“争吵”“争论”会更符合它的表意，与上文对应的另一个名字则是“英雄拒绝召唤”。这一桥段的含义是主人公在正式踏上旅程之前与自己内心的第一次争执。主人公会怀疑自己是否该这样去做，或是这样去做的正确性、可行性、合理性。它可以是向内的，是主人公自己做心理斗争的视觉化呈现，对主人公深度人物形象的第一次探索与完善；也可以是外化的，具象为一次主人公与反面人物（反面人物不一定是反派人物，例如艾莉与乔尔就互为正反面人物）的争吵或争论。这一桥段在现今更摩登的工业化剧情中已经被大幅删减甚至直接优化掉了，因为过于冗长的心理斗争或是争吵会显得人物很“婆婆妈妈”，很“事逼”（说白了还是观众不爱看）。我脑子里立马能想到的例子大概是某一部《碟中谍》，也是类似于伊森·亨特并不想接任务然后纠结拉扯良久之类的情节。所以这也算是一种比较老派的写法了。</p><div><figure><img alt="" src="https://image.gcores.com/59ebd65dec710f4bf668ced84bb42e87-1920-1080.jpeg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>这里我们不再去过多分析这些桥段放置进游戏中应该如何呈现，例如将这些桥段与新手引导联系起来，或是如《TLOU》更艺术化地让玩家代入进女儿的视角有更深的沉浸感，我们只看叙事结构。从结构上来讲，竟然可以说是一模一样。同样是在Set-up阶段对于主人公生活一个粗略的展示，例如《TLOU》中借由女儿视角对于乔尔原有生活的大致描写，《TOB》中薇尔贝特在故乡小村里平静的生活。同样是打破平静生活的某场变故，《TLOU》的疫情爆发害死乔尔的女儿，《TOB》里姐夫操办的红月祭祀害死弟弟。激励事件的展示与出现时间二者略有不同，《TLOU》中亡女的乔尔哀莫大于心死，他是在遇见艾莉并接下火萤的任务后才有了动作性需求，即护送艾莉前往火萤基地，邂逅艾莉是乔尔的激励事件；而《TOB》在Set-up阶段薇尔贝特就已经明确了她的动作性需求——找姐夫复仇，因此越狱才是薇尔贝特的激励事件。甚至我上文写到比较老派的“Debate”桥段也可以一一对应，例如《TLOU》中乔尔与搭档针对护送艾莉而产生的争执，与《TOB》中薇尔贝特的亲友与莱菲对复仇行为的劝诫。</p><p>两部作品之间的相似点还有很多。例如同样是无中生有的“虚构”的亲情关系，又或是结尾处类似的道德困境与选择。两部作品与故事模板的相似点也有很多，但碍于篇幅这里不把游戏的全部剧情展开分析了。要说不同处的话在于，《TLOU》的故事更像是美剧剧本，它的段落感和章回感更为明显，乔尔与艾莉在冒险的路上遇见不同的人并展开不同的故事；而《TOB》则更“游戏”一点，它将几乎所有的人物都展现给玩家，并引导玩家在不同的时间与地点一一去触发这些故事。</p><p>费劲心思讲了这么多，又引用了这么多晦涩难懂的概念是为了说明什么呢？其实就是想要表述我不喜欢但又想推荐给各位的理由。这两款游戏，按我们行话来讲，就是“匠气”太重了。</p><p>这种充满了“设计感”的“匠气”不仅体现在故事结构上，故事内的“匠气”也过重了。包括但不限于弟弟的冒险书与木雕店里的罗盘，几乎是立马就会想到日后会有人代替薇尔贝特的弟弟去冒险；教会的双胞胎工具人姐弟，同样是想都不用想就知道会有先死一个然后姐弟情深的戏码；以及姐夫非常眼熟的人设和动机，也完全都是最终战前可以猜测出的。一些小而精的故事设计是很加分的，这里可以给出的例子是《如龙0》真岛线的那块手表。但在故事结构已经如此匠气的前提下，故事内容仍然充满了诸如此类自作聪明的设计，与我而言，《TOB》的几乎所有剧情都是可预测的，而可预测，就意味着无聊。</p><p>可预测和无聊的故事那么多，上面刚写过的《战神5》也算一个，为什么还要把《TOB》拎出来说呢。</p><p>因为《TOB》是一款JRPG游戏。</p><p>在我为数不多的JRPG游戏经验中，无论再怎么说JRPG的故事套路模板，每个游戏的故事多少还是会有那一个让人眼前一亮或是眼前一黑的独到之处的。而完全循规蹈矩恪守成规去写一个流水线故事，大多是欧美游戏才干的事，比如一开始提到的《战神4》《战神5》，或者什么《神秘海域》《漫威蜘蛛侠》一类。能阅读到一个正统JRPG班底写出来的工业类型故事，对我来讲是一个很新奇的事情。并不是想拉踩，但其实这也说明了，做一个平稳落地的及格分故事并不是什么很难的事情。而JRPG的创作者们仍然热衷于为玩家们“整个大活”，反而说明了他们还仍怀有着创作欲和表达欲，还没有完全向商业低头，仍然有厂商像当年的史克威尔一样，做着属于自己的“最终幻想”。</p><p>这也是我第一次接触“传说”这个系列IP，对前作以及前作的粉丝骚动一概不知。而对《情热传说》的炎上事件有了了解后，我认为南梦宫做出这样保守的商业决定也是十分合理的。如我之前所说的， 虽然匠气十足，但《TOB》与《TLOU》一样，都是十分优秀，值得学习的商业游戏故事模板。</p><p>但除此之外，我对故事还存有一处不满，即没有展现出薇尔贝特作为女主人公独有的女性魅力。</p><div><figure><img alt="" src="https://image.gcores.com/c38b7d2b86069e997951b2508119a6bf-2312-1301.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>这其实也是老生常谈的问题了。日本作为一个极其大男子主义的国家，它文艺作品中对于女性角色的呈现简直是灾难级。这一问题在近些年的作品中都没有得到很好的改善。例如《水星的魔女》和《JOJO的奇妙冒险：石之海》，与《TOB》一样，同样主打系列首次女主角并大力宣发，实则是JUMP系男主人公的性转体。我希望看到的女主角是如同新《Tomb Raider》里劳拉·克劳馥一样会有着迷茫、不安、害怕，并最终收获成长的一个女性形象。而不是一个能完美适配男性主人公形容词的女性主人公。薇尔贝特必须是杀伐果断，被复仇“蒙蔽”双眼的形象吗？这样的冰山美人只能在假弟弟面前吐露真情感吗？展现女性魅力除了做饭和女工就没有别的方式了吗？希望未来的JRPG能写出更多更好的女性形象来打我的脸。</p><p>故事之外要说的是，我真的很喜欢《TOB》的收菜玩法。大概就是每半个小时可以收取一次远航的奖励，奖励大概是什么食材啊装备啊素材之类的，也会有稀有收藏品。虽然奖励算不上很丰厚，但是这个收菜玩法确实很上瘾。有的时候哪怕不玩也会开着PS5，隔半个小时去收一次菜。</p><p>然后我也很喜欢《TOB》的装备系统和战斗系统。装备系统类似于“经验值”或是“精炼”系统？类似于装备某件装备打怪时可以涨装备的“经验值”，经验值满了这件装备的词条就永久烙在你角色的身上了。我觉得算是有种鼓励了“不要‘一键最强’走到底”的那种感觉吧，这种养成感和收菜一样也挺让人上瘾的，不知道续作有没有把这一项继承下来。战斗系统可以自定义招式和打入异常状态可以得到更多行动点数的良性循环战斗模式很戳我。但没想到就在今年遇见了完美符合这两点并在此之上有着更完善战斗系统的另一款游戏，那就是玩一半太监了的《最终幻想：起源》（cnm真的太光污染了）。</p><h1>3 龙之信条2  5</h1><p>写完了两个比较有话讲的，再写两个没啥话要讲，而且是在同一天发售的游戏，先说《龙之信条2》。</p><p>但我真的是不知道该怎么评价这个游戏，因为它实在是，太无聊了。</p><p>它讲了一个比我预想的还要十倍无聊的故事，但它与上述的“可预测”的无聊还略有不同。打个比方，上述的无聊是你看完了《鲨卷风12345》之后去看《鲨卷风6》的那种无聊，而《龙之信条2》就像是你第一次看《鲨卷风》时的那种无聊。</p><p>不好，也不烂，但就是无聊。</p><div><figure><img alt="" src="https://image.gcores.com/8f35e5112193d7f257435aa2e45f5422-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>所以还是来多聊一聊这游戏的Gameplay吧。</p><p>虽然这游戏的动作系统和战斗系统比起卡普空的其他游戏算是相形见绌，但不得不说的是，这游戏给我提供了迄今为止最好的法师战斗体验。</p><p>因为我个人还是很中意长读条法师的，FF14的主职也是黑魔，后面要写的《艾尔登法环》也是玩法师，法师在这类游戏里确实是很难打的“爽”的一个职业，但我觉得《龙之信条2》做到了这一点。从读条时的仪式感，到魔法击中敌人的打击感，再到大型魔法毁天灭地的动画特效，以及一些小魔法产生的对战斗或探险的帮助（例如踩冰块二段跳）和战法牧编队提供的安全输出空间，会让我真实的觉得，我在玩一个法师，而不是下一秒我就要开始满地乱滚或是拿着棍子冲上去和小怪搏杀。</p><p>当然该吐的槽还是要吐。作为一个法师，两大终极魔法之一的陨石术还限制地形，且陨石落点不能手动控制，且几乎所有技能伤害都幽默的不行。那话咋说来着，法师是工作，魔弓才是生活。</p><p>然后就是，我还算是比较喜欢这游戏里一些谜语人式的解密。</p><p>比如在觐见斯芬克斯之前，能看到一副画着前面的人拿矛戳不动斯芬克斯的壁画。这应该是游戏内唯一一处暗示，告诉玩家在解谜之后，要用弓箭射斯芬克斯屁股，才算是真正完成斯芬克斯的隐藏挑战。类似的设计游戏内还有很多，b站和机核里都有找到，我在这里写多了也没啥意思。</p><div><figure><img alt="" src="https://image.gcores.com/c4955f3b80fd23d533451031fe48eb83-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>我觉得这些设计的初衷都是好的，但“仅限一次”和与之配套的恶心人的SL逻辑毁掉了这些巧妙的设计。由于我个人是有在游戏前查看游戏奖杯和攻略的习惯的，所以我算是提前了解到了斯芬克斯仅限一次不可重来的恶心之处，因此打的格外小心。试想一下如果有一个几乎满练接近通关的玩家游玩至此，因为不知道要拿箭射屁股错过了这一周目的斯芬克斯，那得有多绝望。以及那个初心者之证，哪怕玩家愿意多花很多的游戏时间在大地图里漫漫寻找那个初心者之证，他也要说不行，要多加上7天（还是3天?）游戏日的时间限制来恶心玩家。几乎就是完完全全恶心初见的一个设计。</p><p></p><h1>4 浪人崛起  6</h1><p>在正式聊《浪人崛起》的内容之前，我真的要摇旗呐喊，所有的游戏厂商，日厂欧厂美厂，都给我把忍者组这一套游戏内置联网捏脸数据和幻化系统都给我抄来。</p><p>我本身是一个捏脸但是对游戏人物颜值要求又很高的人。每次玩这种需要捏脸的游戏都会花费很长的时间在找作业抄作业上，最终对作业的效果不满推倒重来又丧失耐心乱捏一气这种事也是屡见不鲜。《浪人崛起》的内置捏脸数据简直称得上我的福音。在排行榜上看到好看的就直接下载套用然后改个喜欢的发色瞳色，不喜欢的地方微调起来也很简单。幻化系统也是目前我玩过最好的幻化系统，除了必须要回据点不能随时随地想换就换以外，可以说是没有缺点。</p><p>至于这部游戏的剧情。其实我对它的剧情本身就没啥期待，我对它的唯一要求就是能给我贫瘠的日本幕末历史补补课。毕竟毫不夸张的讲，我的三国的所有的知识来源，几乎也是来自于光荣旗下另一款系列游戏。我觉得从这个层面来讲，《浪人崛起》算是圆满完成任务了。</p><div><figure><img alt="懂的应该知道这是在干啥" src="https://image.gcores.com/ba03b7e76c82ed4808078af5b600cccc-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/><figcaption>(懂的应该知道这是在干啥)</figcaption></figure></div><p>但关于故事还是有两个小缺点可以提及一下。一个是比较明显的，当你选择了某一阵营派系后，故事的走向并不会因为你的选择而发生改变。毕竟本质上还是个历史故事大河剧。但出现了上一秒我才救了某某某下一秒就要和他反目成仇这种存在明显合理性问题的桥段时还是会产生一些很强烈的矛盾感。第二是严谨的主线历史故事之外，一些支线是包含有一些浮夸戏谑的野史成分的。正如《明日方舟》传奇构史家妮芙的主张一样，“野史可以不够史，但是一定要够野”，很明显遵循历史原教旨主义的光荣就没能做到这一点，没能把野史里足够有趣，足够吸引人的地方表现出来，感觉上是挺可惜的。</p><p>然后说到Gameplay部分。我真的要说一句冒天下之大不韪的话，我是真的很喜欢《浪人崛起》的开放世界设计。</p><p>一来我觉得《浪人崛起》的开放世界是一个很健康合理的地图大小，包括他细化后的每一小块区域也都是在我接受范围之内的大小。在过大的地图里跑图会让我产生极强的疲惫感，而《浪人崛起》在我产生疲惫感之前就已经换到第二张新的地图里了。而小区域划分的更细更小也使得互动元素密度的提高，只需要走两步就能看到一个新的清据点或者是新的小boss，清图的时候也省去了找来找去的麻烦。二来其实我感觉《浪人崛起》的开放世界引导做的也挺好的。无论是地图上标出来的交互事件，还是弱引导的听声音寻找流浪猫和树上绑红绳引路的隐藏boss，都是不用额外花心力动脑子，简单轻松就能完成的清图。毕竟开放世界并不是也并不能成为游戏的主要玩法，这样“弱保软”的设计使得玩家聚焦于更为核心的故事剧情或是战斗上，以我的视角来看是一种很不错的资源整合和避免资源浪费的手段。</p><h1>5 女神异闻录3 Reload   7</h1><p>让我来盘点这部作品其实我心里还是有点没底的。因为哪怕白金了，我也没打这一代的隐藏boss伊丽莎白，我也没有玩后来通行证推出的后日谈DLC。所以就简单聊聊一笔带过了。</p><p>关于P3的故事可以去翻阅一下我去年年终总结里对于P3P的分析。将近20年过去了，其实P3的自杀议题以及它向死而生的主题仍然是具有现实意义的。包括像今年在大陆公映，由香港导演卓亦谦执导并斩获台湾金马奖最佳新导演的影片《年少日记》，或者由三宅唱执导入围柏林电影节论坛单元的《黎明的一切》，我们依然可以看到一批又一批的新导演去触碰这个敏感的问题，也能在当下压抑的社会氛围里察觉到一些端倪。包括从我给出的例子中也能看出来，对于欧美来讲这一话题也许会有一些文化冲击或是宗教信仰上的禁忌，但放眼两岸三地与日韩来看，这一问题仍然是有普世意义，讨论价值与上升空间的。只不过20年前原版《女神异闻录3》的年代与现在，对于这一现象的成因是有所变化的。《P3R》如它宣传的“原汁原味”一样，也只是将故事移植到了现代，所以它故事的表达就并不像原版那样深入人心。</p><div><figure><img alt="" src="https://image.gcores.com/a409df6ef3f2bb57f9838ff86736226e-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>其次我对这个游戏最不满的地方，就是它新加入的“降神（神通法）”。</p><p>首先这个设计源自原版P3的合体技，为了给这些技能适配上炫酷的特效，从数量上就已经砍了一大半。而在P3P里，它是以道具的形式，需要“有偿”购买和使用的。到了P3R的降神，几乎可以是“无偿”“无条件”“无责任”的无限次使用下去，甚至它还很贴心能无视属性抗性。并且在游戏前中期，就已经能够解锁十分强力且好用的神通法了。这也就导致例如死神的一回合两动，或是单子之门里无吸反怪的一些特性很轻易就被逃课了。虽然可以看出来从P3到P4到P5难度递减的趋势，但对于这种破坏游戏性的设计，我觉得还是少来点为妙。</p><h1>6 最终幻想7：重生  8</h1><p>终于到我今年最喜欢的一款游戏了。</p><p>我觉得去讨论这款游戏的故事啊表达啊的确还为时尚早。因为确实也正如许多玩家批评的那样，到目前为止它还不是一个完整的故事。但也能从目前的诸多设计里管中窥豹，最起码，它没有像《战神》那样去copy《复联》啊《速激》啊，走一条简单的路。</p><p>《FF7》，作为传说中能够复活一家公司这种级别的IP，尤其是在第一部DLC揭露了扎克斯没死之后，它完全可以把大伙喜欢看的端上来，真当SE不知道玩家们想要什么喜欢什么吗，那么大一家公司的市场调研吃干饭的吗。它当然也可以卖情怀，而且完全可以说它配得上卖情怀这三个字。但是它没有这么干。这就是我《绯夜传说》里写的，这一辈老东西们还是有属于他们的艺术追求在的，虽然现在还不知道结果如何，但作为玩家和粉丝的我们，看到有这样的创作态度，我认为是完全值得为之等待的。</p><p>关于新的剧情走向笔者亦有许多假设与猜测，不过都如上文所讲的一样，静候佳音，慢慢等第三部就好了。</p><p>既然剧情无话可讲，那《FF7RB》故事里还有啥很亮眼很优秀的地方吗？</p><p>有的，那就是人物。尤其是女性人物，更细致一点，特指爱丽丝与蒂法。这两位女性角色写的好到让人感觉不应该出现在JRPG的剧本里。</p><p>爱丽丝的独特之处，在于她是一个极其少有的，在JRPG中存在着“背德感”的女性角色。她对自己做出的某些行为是怀持着后悔与愧疚的态度的，但她的欲望，她的责任感，她个人的主体意识驱使着她不得不这样做。从一开始站在钟楼上远眺米德加，到旅途中不停抒发着对家庭和母亲的想念可以看出，其实爱丽丝对离开家庭离开母亲是有一定负罪感的，其实对应着的就是东亚传统观念中的“不孝”。尤其是在第一部铺垫了爱丽丝的身世与第二部再次Call back之后，这种不希望深爱着自己的养母为自己担心却又不得不踏上冒险的这种内心矛盾体现的淋漓尽致。可能这一处对于普通玩家而言并不是这么明显，那么到了中期海滩的个人剧情中，爱丽丝明确说出“我所想象的复仇过于狠毒甚至连自己都感到害怕”这样的台词时，即使现实生活中几乎不会出现这种血海深仇，但这样复杂纠结的内心纠葛才是更接近于正常的人类情感的，也才更容易让玩家有与爱丽丝共情的余地，会让玩家去心疼爱丽丝这样一个外表很坚强乐观，内心其实很脆弱的小女生形象。而真正巅峰造极的人物塑造与背德感的体现集中在贡加加与扎克斯父母会面一段。她对扎克斯父母隐瞒他们儿子死讯的一点内疚，对扎克斯睹物思人的一点怀念，对克劳德暗自萌发的一点情愫以及对自己移情别恋的一点羞愧，这一段台词和人物情感的描写真的非常多层次，非常推荐各位反复品味一下。</p><p>爱丽丝在感情上体现出的这种背德感，从第一部RE时的“你可不要爱上我了”就已经有所铺垫。而到了RB中，除开上文所述的贡加加见父母一段，爱丽丝好感度最高时的摩天轮约会说出的“我在找的是你，我想见的是你”，以及结尾在幻想中的教堂花田里拥抱时所说的“消失吧，罪恶感”将这种矛盾的情感宣发的更为露骨。这种感情很像《花与爱丽丝》中的有栖川彻子，一个知道闺蜜喜欢但仍然喜欢上了同一个男生的青春期女生形象。而这样立体、多面、真实，甚至同样散发着青春气息的女生形象，是真的在JRPG里很少见的。</p><div><figure><img alt="" src="https://image.gcores.com/272981e46830dce0c038bd250a396c3b-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>而蒂法也正如广大男玩家所述的那样，确实是一个更符合男性审美的，集多重优点于一身的，在文艺作品里也比较随处可见的，更贴近于虚构和想象的女性形象。她青梅竹马双向暗恋，她身材火辣面容姣好，她上得厅堂下得厨房，就这样一个贤惠的、完美的女性角色，是很容易写成花瓶或者男主角的附庸的，而原版中蒂法的定位也于此大差不差。RB中编剧是如何妙笔生花拯救蒂法的呢，这就要提到另一个比较方法论的写作技巧了，那就是给你的女性人物增加一个男主角不知道的秘密。编剧需要让这个角色，通过这个小秘密，这个男主不知道的事，来获得有别于男主和故事的另一个目标，来获得属于自己的角色驱动力，来获得一个独属于这一位女性角色的主体意识。在RB里很明显，蒂法被星球守护者Weapon吞下这个桥段就发挥了这个作用。由于RB里并没有蒂法过多的戏份，但我们仍可以在结局中窥见，由于蒂法得知了克劳德和我们观众都未知全貌的信息，很有可能蒂法是一个将要在第三部中发挥重要剧情功能的女性角色。这样“公主救王子”的戏码出现在JRPG的叙事中也是很令人惊喜的。说明哪怕是日本游戏编剧，他们的性别意识也是在与时俱进的。</p><div><figure><img alt="" src="https://image.gcores.com/714550b33389cb24d522768542d23454-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>而说到Gameplay部分，我其实认为RB比起RE，战斗系统算是退步了的。原因就在于比起RE，RE的战斗系统更加侧重于动作部分，而更多地削减了策略性的部分。我很喜欢RE战斗系统的地方就是它同时有着即时战斗的爽快以及老式回合制烧脑的策略性。其实不妨回想一下，在RE里给防具打上属性加魔法珠就能逃课的Boss有哪些。我个人而言立马能回想起的就是主线流程里克劳德爱丽丝双人战的地狱屋和最后神罗大厦里巴雷特与爱丽丝战的电系机器人（JJC应该也有但记不清了）。在前作中，我可以通过调珠子用弱点魔法等行为来让我的战斗难度降级。而到了RB中，哪怕多了双属性魔法珠，能逃课的场景依然不多。甚至它还加入了全新的，针对玩家手部乘区进行考验的Boss奥丁和VR萨菲罗斯。我自诩我的游戏水平不低吧，也仍然被这两个boss恶心了一下。我其实真的挺好奇一般玩家对这种设计的看法的，是大家都打低难度不折磨自己呢，还是人均动作游戏天尊菜就多练。于我而言吧，还是希望能有更多与Boss与设计者“斗智”的这个环节，但其实从SE半回合制战斗系统的鼻祖《FF15》来看，感觉他们是没考虑过加深游戏策略性的。</p><p>其次我觉得最大的设计败笔是容错率低，这是游戏体验差的根源问题。你要说那些小游戏真的很无聊折磨，其实倒也不至于（除了海盗船打枪），钢琴和打牌我玩的甚至还是很开心的。挫败感强重复度高的根源还是容错率太低了。像是青蛙跳，被碰到一下就死，还不停给你加障碍。像陆行鸟钻圈，就是硬性要求每一个圈都要过。以及像是赛鸟，碰到一个障碍物就可以准备remake了。这种容错率低的问题不止体现在小游戏上，如果我记错了欢迎各位指正，但是我真的记得前作的JJC和AI挑战最多也只是5连战。这次前置就来好多个10连战，最终挑战和隐藏挑战也都是10连战。打10连战真的就是容错率低试错成本高再外加精神压力大的数重折磨，放宽一点条件可以使得游戏体验立马提升很多，小游戏也是同理。</p><div><figure><img alt="" src="https://image.gcores.com/a359e88d4d752d7736fb3f1594047790-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>最后还是提一嘴开放世界吧。其实和上面《浪人崛起》一样，我还是挺喜欢《FF7RB》的开放世界的。不烦神不费事，跟着地图走也不会漏东西。但比较难绷的是他竟然把这么弱保软的地图设计带到了迷宫设计当中，举个例子，最后古代种神殿爱丽丝的解密，正常来说应该是用来铺路的魔晄总量是固定的，我要走哪条路就把哪边的魔晄吸出来移到另一边去，我觉得这样的设计很合理吧。当我看到爱丽丝铺好一条路之后装置里的魔晄和路都固定死了我的人真的是惊呆了。一个JRPG的迷宫竟然可以敷衍，弱保软，一本道成这样吗？真被十年前的《TOB》爆杀了吧。第二是这个和开放世界配套的装模作样的合成系统。我最后做白金的时候合成奖杯差几个素材，我不知道诸位知不知道，就在我准备打开游民星空查询一下这些素材是哪些怪掉落的时候，我TM竟然发现，这游戏里的素材全部都是可以在赛鸟人妹妹的商店买到的。那你TM装模做样有模有式地搞一个采集系统和合成系统是为了干啥，就喜欢玩家为了经典时尚小垃圾多绕点路跑点图吗？最后的最后，我真的他妈绷不住这个游戏的光照系统，每次进出一个有光暗变化的地方都要吃满一个闪光弹。配合上这游戏高的离谱的画面亮度和对比度，不夸张的讲，玩这游戏的两个月我完整地用完了一瓶新开封的眼药水。</p><h1>7 艾尔登法环&amp;黄金树幽影  7&amp;8</h1><p>在写这游戏之前我觉得有必要先叠个甲。本人只通关过《血源》，《恶魂重制版》《黑魂3》与《只狼》都大约只打到第一个boss就玩不下去，除此之外没有玩过其他任何魂游以及类魂游戏。我深知自己不是这款游戏的受众群体，我玩这款游戏是因为有一个对我而言很重要的人，她很喜欢这款游戏，也很喜欢宫崎英高。</p><p>虽然今年这篇文章一直在讲故事，但我真的不知道该怎么讲《艾尔登法环》的故事。因为我没有办法去锐评一个不存在的东西。</p><p>我们就不谈上文提到的“救猫咪”或者“英雄之路”故事模板了，我们拿最简单的，小学生写记叙文的六要素来说事。时间、地点、人物，起因、经过、结果。</p><p>时间？不知道，反正在环碎了之后，反正也不重要。地点？交界地，虽然根本不知道这是个什么鸟不拉屎的鬼地方。人物？更是迷因。我是谁？不知道啊？玛丽卡女王是谁？也不知道啊？开头一串报菜名式的人名都是谁？到游戏结尾都没给你解释明白。起因？我究竟为啥要当艾尔登之王？我的驱动力是什么？我当王之后的目标是什么？一概不知。经过？这是唯一明白的，几十个小时的游戏内容就是经过。最后的结果呢？当了王之后咋了，交界地变成啥样了，烧过的树和王城有没有灾后重建？都tm不知道，反正就“落叶传来讯息”了。</p><div><figure><img alt="" src="https://image.gcores.com/a4036c1759000bed999e5b274fd7951d-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>我知道这时候可能会有人跳出来杠，说这些东西游戏里面的物品说明有，游戏官方设定集里有，扒开游戏的代码废案里面都有。但是要明白一点，一个游戏作为一个消费品而言，在呈现给你的消费者的那一刻就该是完整的。不应该在消费者追求一个“完整”的故事体验时，强行要求消费者去付出额外的时间精力与金钱。为什么我要对此保有如此强硬的态度，因为我唯一通关过的魂游《血源》告诉我，这完全是可以做到的。《血源》的时间地点人物，起因经过结果就要比《艾尔登法环》清晰的多。</p><p>当然也不是说《艾尔登法环》的故事一无是处。很明显艾尔登法环在世界观的设定上是下了大功夫的。这样详尽的设定的确是很利好玩家主动探索和二次创作的。它在社区有如此之高的热度也是理所应当的。</p><div><figure><img alt="" src="https://image.gcores.com/6f32781ad6f35f2ff754f81fc088f731-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>那么关于法环我还想说的是什么呢，是游戏内的文本与翻译。</p><p>怪不得这次是只能用英语配音，我不知道GRRM参与了多少，但是这个英文的文本质量比起《血源》，比起传言是用英文写作的《FF16》要高上了太多太多。完全不像是非英语母语者写作的水平。而与此同时，中文的翻译可以说是一坨狗屎。</p><p>由于一些历史遗留问题，我个人是更倾向于使用繁体中文进行游玩的，也算是为了避免“精神钟塔的玛利亚修女”这种灾难翻译。而这次，我不知道是哪个天才想出来的，他们竟然把繁体中文和简体中文的翻译统一了，导致我都不知道该骂哪一边的本地化翻译组。</p><p>首先我们来看法环里的人称代词。法环和其他文艺作品都一样，说话者使用的人称代词，语气词，用词习惯是可以暴露出这个人一定的人物特征与形象的。可以着重关注第一次遇见菈妮时的对话，这里菈妮使用了极为特殊的一个人称代词——“thee”。这是一个极为古典、老派，常见于莎翁剧里的人称代词，它可以看做“you”的古称。它在中文中有着直接对应的翻译，即“汝”。以及哪怕听不懂也可以感觉出来的，菈妮说话时使用的一些对仗词，她语句中包含的韵律美。都可以初步推断出菈妮是这么一个遗世独立，沾满书卷气的人物形象。而中文翻译就是很直白，很冷冰冰的“你”，同时也没有将行文的对仗关系，音节韵律给翻译出来。</p><p>第二是和人称代词类似的，针对特定人物的称谓。这里我们看DLC中的人物金针骑士蕾妲。她针对不同人使用的都是不同的称谓。例如针对米凯拉，她一直都尊称为“Kindly Miquella”或者“Miquella the Kind”，这里保留原意的话我更倾向于翻译为“仁慈的米凯拉（大人）”。针对梅瑟莫以及其他男性角色，蕾妲使用的称谓是“Sir”，即某某“阁下”或某某“爵士”，在这种语境下我更倾向于认为是“爵士”。而对于托丽娜，蕾妲使用的是“Saint”，即“圣·约翰”“圣·乔治”中的那个“圣”，是带有强烈宗教意味在里的。这些称谓很好地体现了蕾妲是持有严格等级制度观念，怀持着骑士道精神的性格特征，完全可以看做是最后双方意见不合而相互对峙的伏笔。而在中文翻译中，这些独具特色，体现人物性格的称谓，全部被翻译成了某某“大人”。</p><div><figure><img alt="" src="https://image.gcores.com/92cbcea79181809e64508c946fba8b82-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>我相信网络上b站上随便找一找都有总结的比我更好，翻译的比我更到位的纠错文档或者视频，这里我就不多卖弄我的三脚猫英语水平了。我觉得重点还是得多提升自己的外语水平，就像是四二老师说的一样，就算是当二等公民，也得有当了二等公民的自知之明。</p><p>说回游戏，我觉得我是为数不多喜欢DLC多于本体的玩家。我感觉DLC的地图设计和本体都不是同一个水平。虽然DLC有些地方也很大很空，但是地图整体的联通性和统一性，完全不像是本体那样，整的跟《P3R》一样，到了一个新的区域就全换一个美术风格。并且DLC的地图大小，就是我能接受的最大的一个魂游的游戏大小。本体的图真的太大了，而且其实仍然充斥着许多工业化的痕迹。比如地图上看到法师塔就知道是解密然后拿一些法术相关奖励，看到小黄金树就知道是打怪然后爆露滴。包括DLC被诟病许多的幽影树碎片的设计，我觉得对应的就是传统RPG里找怪刷级的一个逻辑。而我个人就是更喜欢刷完级之后再去推图打boss的，我玩法环本体的时候也是先将智力刷到了80点才开始推图。</p><p>除此之外法环还充斥着各种我难以理解也不想理解的游戏设计。比如传说中的根据PVP来削弱武器技能。DLC的前置boss蒙格，我临摹视频中的打法上一样的buff用一样的装备，视频里一个彗星亚兹勒能滋死，而我怎么滋都skip不了二阶段。我都玩法师了，不图的就是这一口站桩输出玻璃大炮吗，更何况是一个范围如此之窄，前摇僵直无比之长，使用起来如此之繁琐的法师终极大招。单机游戏的轮椅平衡性真的这么重要吗？还有地牢里数不清的隐形桥隐形门和踩闸刀。这些设计给我的感觉就是硬推他的那个谏言系统。明明不是强制联机游戏，打起来不联机的体验却跟吃了屎一样。可能宫崎英高是在苦口婆心地教育我，孤僻的下场就是一个人连享受《艾尔登法环》的资格都没有吧。</p><div><figure><img alt="" src="https://image.gcores.com/b03aeea89443e426dceee69c2f76aa94-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>唉，如果和她一起玩的话体验可能确实会好上不少吧。</p><p></p><h1>8 寂静岭2重制版 8</h1><p>今年第二喜欢的游戏，但反而感觉没啥可聊的。</p><p>我们常说什么形式大于内容，内容大于形式。《寂静岭2》很明显就是一部形式大于内容的故事。</p><p>《寂静岭2》的故事其实很简单，而且其实我早年在做《寂静岭》电影分析的时候就已经对《寂静岭2》的故事有所了解了。那《寂静岭2》是如何达成这样深入人心的故事效果的，少部分原因是我开头讲的，依靠于一个普世性强的，大众所熟知且容易共情的亲密关系（夫妇），而剩下的，全都依靠于他讲故事的技巧。</p><p>而且这种技巧大部分也都是游戏的交互性所独有的，虽然说这游戏的玩法不重要，但基本都是玩家通过游戏所引导的故地重游场景重现，来去主动地接收信息，抽丝剥茧得到故事的真相。因此我觉得这游戏的影视化其实还挺难做的，因为很难去复原游戏中那种未知的神秘感，并且一旦过于还原游戏的流程，这种跑任务式的游戏感就直接露馅了。因为游戏需要繁琐的流程来扩充游戏时长，来使得一个简单的故事复杂化，而电影则使用不同的手段来达成这一效果。听说《寂静岭2》的影视化作品将要推出了，只能说谨慎地期待一下吧。</p><p>此外就是它用符号与意象讲故事的能力。例如最经典的三角头形象，在游戏中其实有比较明确的指向性，例如在下楼梯前往监狱前的寂静岭博物馆里的挂画上可以看见，它是与中世纪的瘟疫医生所戴的头罩有关联的。因此三角头的表意其实应该更倾向于“疾病”“病魔”。当然也可以由三角形对应阳性，圆形（一说倒三角）对应阴性的符号学理论来解读为男性阳具或是性欲。以及詹姆斯站在绞刑台上的自杀意象，安洁拉内心的火焰等等，这种符号与意象的模糊性与多义性（ ambiguity ）也保有了诸多可供玩味的解读空间。</p><div><figure><img alt="" src="https://image.gcores.com/cb09f9c0960ca8b59f0616855091d6e6-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>最后还是要感叹一下这个外包水平如此之高。虽然我知道《寂静岭2》的故事但毕竟没有玩过原版游戏，重制版里的谜题质量高到我怀疑它并不是出生在2024。毕竟众所周知的，2024年这类游戏的平均解密水平应该是什么考眼力啊，试错啊，一元二次方程二元一次方程之类的。我是听了机核的节目之后才知道这些谜题都是翻新了的，原有谜题做成了收藏品处理。以及山冈晃亲自重置的OST，也是把这个游戏带到了更高的高度。其实我真觉得今年TGA可以把最佳音乐颁给《寂静岭2》的，但一想到输给的是《FF7RB》，那好像确实也没啥办法。</p><p></p><h1>9 暗喻幻想  6</h1><p>终于到最后一个了，年度最大CJB，阿特拉斯历时不知道多少年诈骗之作，《暗喻幻想》。</p><p>其实可以借着这款游戏，来跟大伙聊一个游戏编剧真的很爱写，但是真的又怎么都写不好的剧情桥段，“反转”。</p><p>首先我们来看一下什么是一个最普通，最公式化的反转。此处我要Call back本篇文章的第一位受害者，《战神5》。在那里我就写到，剧情里有一个完全意料之内的反转，那就是奥丁假扮提尔。</p><p>这个反转公式在什么地方呢？首先一救出提尔的时候，假提尔就告诉奎爷他放下屠刀一心向善了，此时儿子阿特柔斯和腰上挂的人头都在提醒你，这个提尔好像不太对劲，我们的好大奎非常公式化地为他辩解两句先打消观众的疑虑，让观众放下戒备，“也许就是当战神当累了，我太懂了”。当假提尔到达据点之后，依然在铺垫这一条线，继续让观众加深这个提尔不太对劲的印象。然后反转发生，奥丁揭露真面目并残忍杀害一名无辜好市民。紧接着反转之后，腰上挂着的人头和芙蕾雅立马告诉你，奥丁这个逼太狡猾了啊，他能三十六变七十二变，我们的一举一动早就被奥丁变的乌鸦盯着了啊。</p><p>这就是一个最基本，最公式，最套路的反转。编剧引导观众，让观众首先发现有一丝的不对劲，紧接着又插科打诨转移观众的注意力，反转发生之后立马开始找补。观众心里一寻思，还真对，他早就给我铺垫好了。但这样的反转，它也就只具备一个普通情节点的意义了。一个真正好的反转是得如同字面含义一样，得对剧情产生巨大的转折，也得让观众真的惊呼“意料之外情理之中”的。</p><p>那什么是一个好的反转呢？正巧在同属阿特拉斯的游戏里有一个例子，那就是《女神异闻录5》。</p><div><figure><img alt="" src="https://image.gcores.com/838483f053140f18cac154aa9c7a818b-3456-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>在《P5》本篇的最终阶段，我们得知天鹅绒房间的主人伊戈尔是伪神假扮的，而真正的伊戈尔在被囚禁之前帮助我们觉醒了力量，并在得救之后于绝望之际再次帮助我们击败了伪神。这样的反转就是一个在情节上有着重大意义的转折点，同时，虽然这个反转的草蛇灰线没有在游戏内得到很好的体现，但是玩家是可以通过声优的变化察觉出一些马脚的。但由于声优田之中勇老师的离世，这样细微的马脚并不需要刻意的引导也会被玩家自发性地自我说服。在揭露真相的那一刻，才会发现这一切的布局都是那样欧亨利式的意料之外情理之中。</p><p>此处应该会有人疑问，为什么不举明智吾郎的例子。因为首先，在我的视角，明智吾郎是反派卧底这件事阿特拉斯就没想着要藏。不然他也不会起明智吾郎这种此地无银三百两的名字。其次，从明智吾郎就可以看出，阿特拉斯写反转的能力真的特别的差。不知道诸位还记不记得《P5》里越狱布局的桥段了，在雨宫莲要回忆起某些重要情节时，阿特拉斯竟然用“吐真剂起作用了头好痛”这种简直可以称得上是低劣的手法，来“强行”让雨宫莲“不记得”某些情节。这种写法在写反转，写惊喜桥段的时候都是大忌，这不就是明晃晃告诉观众，注意看，接下来我要反转了。</p><p>孤例不证，阿特拉斯驾驭反转的能力差已经不是一天两天了。例如P3里理事长这个角色，完全就是为反转而生的一个工具人。还有P4里的足立透，这个去年已经说过了，作为一个推理核心剧情的游戏，为了设计反转而把故事里的线索全部抹掉简直就是本末倒置。不过我怀疑本来他们就没想为足立透的反转预留伏笔，说不定还因为觉得设计这样一个人畜无害型角色反转当幕后黑手很成功而沾沾自喜。</p><p>不然很难解释为什么阿特拉斯如此普通却又如此自信，他在《暗喻幻想》里，加了得有七八个理事长级别，足立透级别和明智吾郎级别的弱智反转。</p><p>从“哈哈，没想到吧，我就是死不了”的传奇耐杀王路易，到“哈哈，没想到吧，其实我才是大坏逼”的大主教，再到“哈哈，没想到吧，其实我也是坏逼”的圣女蕾拉以及不计其数的弱智小反转，感觉阿特拉斯每一次都骑在你脸上在问，“怎么样？这个反转有没有震惊到你？”，乃至于最后的最后都要以一个弱智反转给故事收尾，“哈哈，没想到吧，其实我是你爹”。</p><div><figure><img alt="我是恁爹！" src="https://image.gcores.com/2fee053d4fd8b50ff7a4858f3836b763-1555-1067.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/><figcaption>(我是恁爹！)</figcaption></figure></div><p>真的，大可不必这么侮辱人的智商，你的每一处反转我都想得到。</p><p>然后说一下这游戏的表达吧，这游戏的表达主要有两个也都比较明显。一个是种族歧视，另一个是民主。</p><p>第一个问题一开始大张旗鼓地铺垫了好久，又是当街砍头示众又是不让进店的，但讲着讲着也不知道是阿特拉斯没想好怎么处理这个问题，还是直接就给忘了，这么大个事基本上就只存在于主角的口号和同伴们的台词里了。那毕竟你是JRPG嘛，喊着友情啊羁绊啊什么的把所有问题都解决了也很合理。但是当了王之后直接就变乌托邦是不是有点太过分了。隔壁《FF16》好歹还死了个克莱夫呢。我知道种族议题是很具有当下性和现实意义的一个问题，但要只是这么蜻蜓点水地提一下都能有这么高媒体评价的话，我真的要替《悲伤逆流成河》伸冤，它可是国内反校园霸凌题材电影的先驱啊。</p><p>第二点我其实觉得更可惜。关于民主的话题这里不便讨论太多（已经被退稿一次了），这里推荐大家去看一看希拉里败选时的白宫讲话。在民主的制度下不应该只看如何赢，更应该看如何体面的接受输。很明显游戏里的路易、主教，都没能做到这一点，蕾拉的讲话有点那个意思但仍不足够。</p><div><figure><img alt="" src="https://image.gcores.com/580c6898a4e4c255901c5614281bb111-3840-2160.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>其实关于这游戏还有挺多值得骂的，但是骂累了，就先这样吧。</p><p></p><h1>总结</h1><p>费老大劲总算是写完了。也不知道有没有人能看到这里。如同一开始写的那样，今年对我来讲是比较糟糕的一年，可能算是把一些戾气借由这篇文章抒发出来吧，这次算是火力全开模式了（笑）。如果我误伤到了你喜欢的游戏，你也可以攻击我最喜欢的游戏《FF7RB》。</p><p>写到后面真的好累好困，写到后面也越来越随意越来越敷衍了（），今年玩游戏的时候都没怎么截图，也懒得开游戏一个个截（只好乱jb加了）。但是，好歹还是把今年份的总结坚持下来了。也希望明年还能有这种热情和精力坐在电脑面前码字吧。嗯，今年就不谈什么远大理想了，先好好活着再说。</p><p>然后的话，如同开头说的，想把手里一些太监了的游戏继续玩完。也欢迎诸位来给我推荐新的游戏，或者是想听听我独特看法的游戏。电影也行。</p><p> 那就这样吧，辛苦看到这里的诸位，若是有缘相信还能再见。</p><p></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="2024个人向年度游戏总结" href="https://www.gcores.com/articles/193175" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">2024个人向年度游戏总结</span><span class="cap link fs12">https://www.gcores.com/articles/193175</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>国风手绘解谜游戏《生肖纪 鸡哥和他的朋友们》公开</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f57a8af.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f57a8af.html</id>
    <published>2025-01-10T04:33:59.000Z</published>
    <updated>2025-01-10T04:33:59.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/812d5681a6cf4a195525796639e19364-1024-576.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>阿狗社（Astrolabe Games）本日宣布，由其负责发行的手绘叙事解谜游戏《生肖纪 鸡哥和他的朋友们》正式公开并宣布登陆PC Steam平台，全新宣传影片亦正式亮相。该作意在用轻松可爱的表达展现生肖文化。在精美的国风手绘世界中，玩家可以体验到美食烹饪、恋爱模拟、剪纸园艺等诸多趣味玩法。随酉鸡”鸡哥”一起穿越回古代，粉墨一场关于家庭与爱的人生故事。</p><div></p><figure><p>&lt;内嵌内容，请前往机核查看&gt;</p></figure></div><p><span style="font-weight: bold;">故事背景——生肖联欢闹翻天！</span></p><p>十二生肖在新年夜聚会，傲气的鸡哥实在闹过头了，最终导致其他生肖忍无可忍——他竟然弄哭了兔大厨！忍无可忍的龙决定施展魔法，将鸡哥送回古代，让他好好反省。</p><div><figure><img alt="" src="https://image.gcores.com/e8a190102306c168cafe77ba76c44f36-1270-714.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>在游戏中，你将随酉鸡“鸡哥”一起，与叫“小鸽”的凡人相遇。在小鸽的人生之路上，帮他解决各式各样的问题，其中每件事都潜藏着和生肖伙伴和解的契机。相信只要有你的明智，生肖们还是能欢聚一堂，共庆佳节！</p><p><span style="font-weight: bold;">游戏特色——最重要的是把爱融进细节！</span></p><p>我们在美术上采用了可爱版的水墨画风格，同时设计了大量灵动的动画和效果与之搭配，力图为大家带来温馨轻松的游戏体验。</p><div><figure><img alt="" src="https://image.gcores.com/024ecf60e87e17043f8632fec079173b-1270-714.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>人一生的烟火故事总是有笑有泪，即便平凡，也有值得铭记的种种时刻。虽然是休闲题材，我们还是选择结合生肖文化，用尽可能的用更多的故事和情节来创作这款生肖纪，希望这能抚慰到每一位玩家。</p><div><figure><img alt="" src="https://image.gcores.com/1ee0cc61cf85e7b0a8440a92ad1c7068-1267-713.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>另外，请不要担心会在哪一步卡住，团队鼓励用才智征服鸡哥遇到的种种谜题。但也没忘记加入无障碍设计和必要的小提示，确保每位玩家都能愉快的享受游戏。</p><p><span style="font-weight: bold;">游戏玩法——人生关，关关难过关关过！</span></p><p>寻找物品、推理、猜谜、烹饪、剪纸、园艺……甚至是塔防和恋爱模拟，生肖纪为大家带来休闲玩法的一大桌年夜饭！</p><div><figure><img alt="" src="https://image.gcores.com/4f1a5a3e47525e2d45e9664227aca1a6-1267-713.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>生肖伙伴们都有自己的独到的特质，当然也有不同的象征，鼠的财富，牛的勤劳，兔的善良，蛇的冷静…… 每个关卡都会在此基础上展露创意，并灵活融入生活中的小难题，十余关玩法各不相同！</p><div><figure><img alt="" src="https://image.gcores.com/b5b28e15ceb43a2ea8e3bcb31c240b04-1269-714.png?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>鸡哥最后能否顺利和众生肖重归于好，最大的难关又要具备什么才能从容应对。经历一整遭人间烟火，相信大家都能找到自己的答案。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="国风手绘解谜游戏《生肖纪 鸡哥和他的朋友们》公开" href="https://www.gcores.com/articles/193344" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">国风手绘解谜游戏《生肖纪 鸡哥和他的朋友们》公开</span><span class="cap link fs12">https://www.gcores.com/articles/193344</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>《全面憨憨战争模拟器》手机版1月16日正式上线</title>
    <link href="https://blog.imc.re/RSSBOX/rss/bced9af1.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/bced9af1.html</id>
    <published>2025-01-10T04:26:00.000Z</published>
    <updated>2025-01-10T04:26:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/9f53f1523ee591f9d371baa560cb81c2-1704-786.png?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p> <span style="font-weight: bold;">每个人心里总藏有个自己的「最强」超级英雄</span>。从三国到隋唐，从足球到篮球，无论武力还是智力，不管荣誉还是技术。只要涉及到孰强孰弱的话题，大家心中都有一个不容被小觑的“One Pick”。</p><p><span style="font-weight: bold;">这个春节，如果在这个事儿上说不服别人，你可以试试将对方打服。</span></p><div></p><figure><img alt="" src="https://image.gcores.com/cee011b4e3bfd0719b66905040657d0c-300-169.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>专门解决关公战秦琼问题的分歧终端机，<span style="font-weight: bold;">欢乐沙雕</span>的“赛博斗蛐蛐”物理引擎<span style="font-weight: bold;">战争模拟游戏《全面憨憨战争模拟器》</span>，将于<span style="font-weight: bold;">1月16日</span>在TapTap和苹果商店<span style="font-weight: bold;">正式上线手机版</span>。<span style="font-weight: bold;">游戏为买断制收费，原价18元，首发前两周限时优惠价12元。</span></p><div><figure><p>&lt;内嵌内容，请前往机核查看&gt;</p></figure></div><p>《全面憨憨战争模拟器》基于Steam上<span style="font-weight: bold;">好评如潮游戏作品TABS的原版</span>进行移植，由开发商Landfall官方授权心动代理。</p><p>在这样一款无所不能，欢乐满满的战争模拟器里，你可以通过<span style="font-weight: bold;">游戏强大的自定义功能</span>，将无数只存在于梦想里的中二对决化为实际。无需费力操作，只要脑洞够大，大家便可以饶有兴致地全方位观赏到欢乐搞笑的“赛博斗蛐蛐”。</p><div><figure><img alt="" src="https://image.gcores.com/bfbe42014cfa509a37e36b2018c3b2ce-480-270.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p><span style="font-weight: bold;">#脑洞有多大，节目效果就有多大</span></p><p>在《全面憨憨战争模拟器》里，<span style="font-weight: bold;">你可以在游戏中安排一场超人与一拳超人的披风侠互殴。</span></p><div><figure><img alt="" src="https://image.gcores.com/73c032a793cf37cae064273a093eb7ec-480-270.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p><span style="font-weight: bold;">极致的强者，只需要最朴素的抡拳方式</span></p><p><span style="font-weight: bold;">又或者是让天命人与大圣残躯在黑风山的塔顶展开一场乱斗。</span></p><div><figure><img alt="" src="https://image.gcores.com/ba0bdb2efb1f1d3f83979e17cb2253ef-480-270.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p><span style="font-weight: bold;">在真实物理引擎的支持下，你可以慢动作看闪电侠如何帮人类实现光速倒立螺旋升天。</span></p><div><figure><img alt="你有被光速踢过吗？" src="https://image.gcores.com/cee89a04d562059f12f750cb8b1353cc-480-270.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/><figcaption>(你有被光速踢过吗？)</figcaption></figure></div><p>心有多大，舞台就有多大。根据官方消息，作为TABS正版手游，《全面憨憨战争模拟器》不光首发将带来原版游戏的所有地图与战役，以及海量可解锁的隐藏彩蛋。与此同时，他们还将不断把PC版本玩家社区中的热门mod搬运移植到手机版中，<span style="font-weight: bold;">玩家只需一次买断付费，便可持续畅享游戏中海量欢乐玩法与新鲜内容。</span></p><p><span style="font-weight: bold;">随时随地，把谁是谁的爹捋清</span></p><p>与原版TABS对比，<span style="font-weight: bold;">《全面憨憨战争模拟器》针对手游玩家习惯，重新设计了手游的操作UI，尽可能减少了按键对游戏画面的遮挡，呈现精彩的战斗演出效果。</span></p><div><figure><img alt="" src="https://image.gcores.com/ab6149bfa71525606bad88f49ceeddce-360-166.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>除一键放兵、时停及子弹时间等使用功能以外，手游版还加入了让战争更为热闹的联机功能 —— 玩家还可以在联机大厅创建房间，随机快速匹配对手，或者邀请自己的好友一同切磋各种脑洞大开的玩法。</p><div><figure><img alt="" src="https://image.gcores.com/06301e79652ae523f12c7a2bda223488-422-455.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>当然，不论面对怎样的敌人，在《全面憨憨战争模拟器》里，所有事件可未必会按大家预想的方向去走……</p><div><figure><img alt="" src="https://image.gcores.com/ddf28c8197ff20cf83f83b1f79afc230-301-180.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>抽象永远是TABS的底色，就好像诸葛亮可以带上500把AK47北伐中原，但要面对的对手可能不光戴着至尊魔戒，胯下还骑着条龙……</p><div><figure><img alt="" src="https://image.gcores.com/783b20a5aff77e47ff9e6269a562398f-480-270.gif?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>《全面憨憨战争模拟器》热闹欢乐的无厘头氛围始终在线，在抽象夸张的镜头中，它让人们忘记紧张的战场胜负，只留下流泪与肚子疼等因爆笑导致的副作用。</p><p>即便自己没能打败敌人，大家也尽可以淡然一笑，并把诸葛丞相的经典名言敬送给对面那离谱却有趣的阵容。</p><p>物理引擎<span style="font-weight: bold;">战争模拟游戏《全面憨憨战争模拟器》</span>，将于<span style="font-weight: bold;">1月16日</span>在TapTap和苹果商店<span style="font-weight: bold;">正式上线手机版</span>。<span style="font-weight: bold;">游戏原价18元，首发前两周限时优惠价12元，感兴趣的朋友们可以前往预约！</span></p><p><span style="font-weight: bold;">&gt;</span><a href="https://apps.apple.com/cn/app/%E5%85%A8%E9%9D%A2%E6%86%A8%E6%86%A8%E6%88%98%E4%BA%89%E6%A8%A1%E6%8B%9F%E5%99%A8/id6443786927"><span style="font-weight: bold;">iOS预购入口</span></a><span style="font-weight: bold;">&lt;&gt;</span><a href="https://www.taptap.cn/app/229435"><span style="font-weight: bold;">TapTap安卓预约入口</span></a><span style="font-weight: bold;">&lt;</span></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="《全面憨憨战争模拟器》手机版1月16日正式上线" href="https://www.gcores.com/articles/193343" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">《全面憨憨战争模拟器》手机版1月16日正式上线</span><span class="cap link fs12">https://www.gcores.com/articles/193343</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>KRAFTON携手NVIDIA发表“CPC”AI技术</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ec78a25a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ec78a25a.html</id>
    <published>2025-01-10T04:15:28.000Z</published>
    <updated>2025-01-10T04:15:28.000Z</updated>
    
    <content type="html"><![CDATA[<div><p><img src="https://image.gcores.com/46c4092f01e8f9796a83b3f03a188913-1280-720.webp?x-oss-process=image/resize,limit_1,m_fill,w_626,h_292/quality,q_90"/><p>近日KRAFTON（CEO CH Kim）在世界最大IT·电子展会“CES 2025”上展示了其与NVIDIA共同开发的AI技术 - CPC（Co-Playable Character）。据悉，这是与NVIDIA合作研发的创新型AI技术，为全球游戏产业刻下了新的里程碑。</p><p>KRAFTON深度学习部负责人Kangwook Lee负责进行了AI模型“CPC”的发表。他表示“CPC是一种能通过NVIDIA ACE技术构建的游戏专用设备端小型语言模型（On-device SLM for Gaming）与游戏玩家进行互动的新概念角色”，并解释道“CPC不同于现有的NPC（Non Player Character），它的特点是能与玩家进行对话、协作，灵活地理解情况并做出应对” 。</p><div></p><figure><img alt="" src="https://image.gcores.com/e57436cb52ba8c6e25a5bedf9bccb5c3-1033-690.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>随后Kangwook Lee还提到“KRAFTON将会把CPC应用到包括《PUBG》IP系列作品和《inZOI》在内的多款游戏上，对用户体验进行持续革新”，并表明“我们的计划是加紧进行优化和标准化工作，争取让CPC成为游戏行业的新基准”。他还补充说“我们相信AI技术会为游戏行业带来巨大变化，并将持续与NVIDIA保持长期合作关系” 。</p><p>KRAFTON还在本次活动中公开了应用CPC后的《PUBG》IP系列作品和《inZOI》的试玩视频。首先公开的《PUBG》IP系列视频中展示了名为“PUBG Ally”的CPC，它能与玩家进行日常对话，并做出根据情况制定战略、对玩法风格进行细节调整等高级操作。</p><div><figure><img alt="" src="https://image.gcores.com/bb99304de1540f9362105ddb2d35968a-1264-882.jpg?x-oss-process=image/resize,limit_1,m_lfit,w_700,h_2000/quality,q_90/watermark,image_d2F0ZXJtYXJrLnBuZw,g_se,x_10,y_10"/></figure></div><p>《inZOI》的视频中则介绍了“Smart Zoi”。它是一位像人一样拥有性格特色和感情的CPC，能通过与玩家的深度互动为玩家带来具有高度沉浸感和生动感的模拟体验。</p><p>此外，KRAFTON还为现场的与会人员准备了首个体验CPC的机会，并得到了出席人士的热烈反响。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="KRAFTON携手NVIDIA发表“CPC”AI技术" href="https://www.gcores.com/articles/193342" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">KRAFTON携手NVIDIA发表“CPC”AI技术</span><span class="cap link fs12">https://www.gcores.com/articles/193342</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/categories/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/categories/acg/gcores/"/>
    
    
    <category term="ACG" scheme="https://blog.imc.re/RSSBOX/tags/acg/"/>
    
    <category term="Gcores" scheme="https://blog.imc.re/RSSBOX/tags/gcores/"/>
    
  </entry>
  
  <entry>
    <title>How to Secure Your GitHub Actions Workflows With CodeQL</title>
    <link href="https://blog.imc.re/RSSBOX/rss/465b5fb1.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/465b5fb1.html</id>
    <published>2025-01-09T13:27:11.000Z</published>
    <updated>2025-01-09T13:27:11.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>In the last few months, we secured more than 75 GitHub Actions workflows in open source projects, disclosing more than 90 different vulnerabilities. Out of this research, we produced new support for workflows in CodeQL, empowering you to secure yours.</p><h2 id="the-situation-growing-number-of-insecure-workflows">The situation: growing number of insecure workflows<a aria-label="The situation: growing number of insecure workflows" class="heading-link pl-2 text-italic text-bold" href="#the-situation-growing-number-of-insecure-workflows"></a></h2><p>If you have read our series about keeping your GitHub Actions and workflows secure, you already have a good understanding of common vulnerabilities in GitHub Actions and how to solve them.</p><ul><li><a href="https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/">Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests</a> </li><li><a href="https://securitylab.github.com/resources/github-actions-untrusted-input/">Keeping your GitHub Actions and workflows secure Part 2: Untrusted input</a> </li><li><a href="https://securitylab.github.com/resources/github-actions-building-blocks/">Keeping your GitHub Actions and workflows secure Part 3: How to trust your building blocks</a></li></ul><p>Unfortunately, we found that these vulnerabilities are still quite common, mostly because of a lack of awareness of how the moving parts interact with each other and what the impact of these vulnerabilities may be for your organization or repository.</p><p>To help prevent the introduction of vulnerabilities, identify them in existing workflows, and even fix them using GitHub Copilot Autofix, <a href="https://github.blog/changelog/2024-12-17-find-and-fix-actions-workflows-vulnerabilities-with-codeql-public-preview/">CodeQL support has been added for GitHub Actions</a>. The new CodeQL packs can be used by code scanning to scan both existing and new workflows. As code scanning and Copilot Autofix are free for OSS repositories, all public GitHub repositories will have access to these new queries, empowering detection and remediation of these vulnerabilities.</p><p>In the rest of this post, we’ll see</p><ul><li>What we added to our existing CodeQL support, including actions as a first-class language, taint tracking, bash support;  </li><li>What models and queries we developed;  </li><li>What vulnerabilities and what new patterns we discovered as part of this work.</li></ul><h2 id="previous-attempt">Previous attempt<a aria-label="Previous attempt" class="heading-link pl-2 text-italic text-bold" href="#previous-attempt"></a></h2><p>Previously, there was a <a href="https://github.com/github/codeql/blob/2cbb0726689e3c6cb213eab2b3fc4b4e7d8119a4/javascript/ql/src/Security/CWE-094/ExpressionInjection.qhelp">single CodeQL query</a> capable of identifying simplistic code injections in GitHub workflows. However, this query had several limitations. First, it was bundled with the JavaScript QL packs, meaning users had to enable JavaScript scanning even if they had no JavaScript code in their repositories, which was confusing and misleading. Additionally, the representation of GitHub workflow syntax and grammar was incomplete, making it difficult to express more complex patterns using the existing Abstract Syntax Tree (AST) of GitHub Actions, which is used by static analysis tools such as CodeQL. Most importantly, the CodeQL support for GitHub workflows did not previously include Taint Tracking support and models for non-straightforward sources of untrusted data or dangerous operations.</p><h2 id="taint-tracking-is-key">Taint Tracking is key!<a aria-label="Taint Tracking is key!" class="heading-link pl-2 text-italic text-bold" href="#taint-tracking-is-key"></a></h2><p>So what is Taint Tracking and how important is it?</p><p>Through the <a href="https://github.com/github/codeql/blob/2cbb0726689e3c6cb213eab2b3fc4b4e7d8119a4/javascript/ql/src/Security/CWE-094/ExpressionInjection.qhelp">previous query for Code Injection</a>, we were able to identify simplistic vulnerabilities such as those cases where a known user-controlled property gets directly interpolated into a Run script:</p><p><img><img alt="Code snippet through which a known user-controlled property gets directly interpolated into a Run script" class="aligncenter size-large wp-image-81906 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="57" sizes="(max-width: 674px) 100vw, 674px" src="https://github.blog/wp-content/uploads/2025/01/run-script.png?w=674&amp;resize=674%2C57" width="674"/></img></p><p>That was a great starting point, but what about cases such as the following?</p><p>The first step of the path is the download of an artifact.</p><p><img><img alt="Code snippet representing an artifact download" class="aligncenter size-large wp-image-81907 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" fetchpriority="high" height="465" sizes="(max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/artifact-download.png?w=1024&amp;resize=1024%2C465" width="1024"/></img></p><p>The second and third steps are setting the content of a file from the artifact as the output of the workflow step.</p><p><img><img alt="Code snippets setting the content of a file from the artifact as the output of the workflow step" class="aligncenter size-large wp-image-81908 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="593" sizes="(max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/step-2-and-3.png?w=1024&amp;resize=1024%2C593" width="1024"/></img></p><p>In the last step, the value from the previous step is interpolated in an unsafe manner in a Run script leading to a potential code injection.</p><p><img><img alt="Code snippet identifying a potential code injection" class="aligncenter size-large wp-image-81909 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="303" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/potential-code-injection.png?w=1024&amp;resize=1024%2C303" width="1024"/></img></p><p>In the case above, the source of untrusted data is not simply a GitHub Event Context access of a known untrusted property (for example, <code>github.event.pull_request.body</code>) but rather the download of an artifact. Should all artifacts be considered untrusted? Certainly not. However, in this instance, where the workflow is triggered by a <code>workflow_run</code> event with no branch filters and where an artifact is downloaded from the triggering workflow (<code>github.event.workflow_run.workflow_id</code>), the artifact should be considered untrusted. When decompressed, it may pollute the Runner’s workspace by writing to files in unexpected locations. Consequently, from that step onward, all files in the workspace should be considered untrusted. This example highlights a non-trivial pattern that we need to express using the new actions AST representation to identify sources of untrusted data.</p><p>Identifying sources of untrusted data is only the first step towards uncovering more complex injection vulnerabilities. In the example above, it is crucial to understand Bash scripts to determine if they are reading from untrusted files and inserting data into shell variables. It is essential to comprehend how these variables may flow into the output of a step, and, subsequently, how the output flows through different steps, jobs, composite actions, or reusable workflows until they reach a potentially dangerous sink. This understanding is what Taint Tracking and Control Flow will achieve.</p><p>In summary, as illustrated in the CodeQL alert above, we can now identify non-obvious sources of untrusted data (for example, <code>git</code> or <code>gh</code> commands or third-party actions) and, more importantly, track this untrusted data throughout complex workflows. These workflows involve multiple steps, jobs, actions, and even entire workflows, allowing us to better understand where this data is used and to report potential vulnerabilities effectively.</p><h2 id="bash-support">Bash support<a aria-label="Bash support" class="heading-link pl-2 text-italic text-bold" href="#bash-support"></a></h2><p>GitHub’s workflows can execute various scripts, with Bash scripts being among the most common. The new CodeQL packs for GitHub Actions offer basic support for Bash, helping to identify tainted data originating from Bash scripts. For example, commands such as <code>git diff-tree</code> obtain a list of changed files. Tainted data can flow through a script when reading an attacker-controlled file or environment variable into a step’s output or another environment variable. A pertinent example of such a vulnerability could be found in a workflow of Azure CLI repository.</p><p><img><img alt="environment variable built from user-controlled sources" class="aligncenter size-large wp-image-81910 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="326" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/environment-variabl.png?w=1024&amp;resize=1024%2C326" width="1024"/></img></p><p><img><img alt="Code snippet showing how untrusted data, such as a pull request’s title, is assigned to the TITLE environment variable" class="aligncenter size-large wp-image-81911 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="457" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/step2.png?w=1024&amp;resize=1024%2C457" width="1024"/></img></p><p>In the alert above, we can see how untrusted data, such as a pull request’s title, is assigned to the <code>TITLE</code> environment variable. This variable is then read and processed by several commands, resulting in a new message variable that gets redirected to the special file pointed to by the <code>GITHUB_ENV</code> variable. A malicious actor could craft a title that results in a multiline <code>message</code>, allowing them to inject arbitrary environment variables into subsequent steps. This, in turn, would enable the attacker to exfiltrate secrets used in the workflow.</p><p>The new CodeQL packs are able to parse Bash scripts. While they don’t yet generate a full AST, they already allow us to understand elements such as assignments, pipelines, and redirections, enabling us to report subtle vulnerabilities like the one mentioned above.</p><h2 id="models">Models<a aria-label="Models" class="heading-link pl-2 text-italic text-bold" href="#models"></a></h2><p>As explained in “<a href="https://securitylab.github.com/resources/github-actions-untrusted-input/">Keeping your GitHub Actions and workflows secure Part 2: Untrusted input</a>,” GitHub’s event context is the most common source of untrusted data. Properties such as <code>github.event.issue.title</code>, <code>github.event.pull_request.head.ref</code>, or <code>github.event.comment.body</code> are typical sources of untrusted data. However, any third-party action may introduce untrusted data. For instance, an action that returns a list of filenames changed in a pull request should be considered a source of untrusted data. Similarly, actions that parse an issue body or comment for a command or structured data should also be treated as sources of untrusted data.</p><p>The same applies to actions that pass data from one of their inputs to their outputs or into an environment variable, therefore acting as taint steps (summaries). Actions such as <code>actions/github-script</code>, <code>azure/cli</code>, or <code>azure/powershell</code> should be considered sinks for Code Injection, similar to a Run’s step.</p><p>We have analyzed thousands of popular third-party actions and identified a number of models now incorporated into the analysis:</p><ul><li>62 sources  </li><li>129 summaries  </li><li>2199 sinks</li></ul><h2 id="queries">Queries<a aria-label="Queries" class="heading-link pl-2 text-italic text-bold" href="#queries"></a></h2><p>The previous support for GitHub Actions contained a single query for code injection, whereas the new CodeQL packs incorporate 18 new queries, including the Code Injection and Environment Variable Injection queries mentioned above.</p><ul><li>Execution of Untrusted Code  </li><li>Execution of Untrusted Code (TOCTOU)  </li><li>Artifact Poisoning  </li><li>Code Injection  </li><li>Environment Variable Injection  </li><li>Path Injection  </li><li>Unpinned Action Tag  </li><li>Improper Access Control  </li><li>Excessive Secrets Exposure  </li><li>Secrets In Artifacts  </li><li>Expression is Always True  </li><li>Unmasked Secret Exposure  </li><li>Cache Poisoning (Code Injection, Direct Cache, Untrusted Code)  </li><li>Use of Known Vulnerable Actions  </li><li>Missing Action Permissions  </li><li>Argument Injection (Experimental)  </li><li>Code Execution on Self Hosted Runners (Experimental)  </li><li>Output Clobbering (Experimental)</li></ul><h2 id="results">Results<a aria-label="Results" class="heading-link pl-2 text-italic text-bold" href="#results"></a></h2><p>For the past few months, we have been testing the new queries on thousands of open source projects to validate their accuracy and performance. The results have been very impressive, allowing us to identify and report vulnerabilities in numerous critical organizations and repositories, such as Microsoft, Azure, GitHub, Eclipse, Jupyter, Adobe, AWS, Cloudflare, Discord, Hibernate, HuggingFace, and Apache.</p><p>The table below shows all the repositories affected, along with their GitHub stars, to give an idea of the impact that a supply chain attack could have had in these projects:</p><div class="content-table-wrap"><table><thead><tr><th align="left">Repository</th><th align="left">Stars</th></tr></thead><tbody><tr><td align="left">ant-design/ant-design</td><td align="left">92,412</td></tr><tr><td align="left">Excalidraw/excalidraw</td><td align="left">84,021</td></tr><tr><td align="left">apache/superset</td><td align="left">62,589</td></tr><tr><td align="left">withastro/astro</td><td align="left">46,604</td></tr><tr><td align="left">Stirling-Tools/Stirling-PDF</td><td align="left">44,988</td></tr><tr><td align="left">geekan/MetaGPT</td><td align="left">44,901</td></tr><tr><td align="left">Kong/kong</td><td align="left">39,221</td></tr><tr><td align="left">LAION-AI/Open-Assistant</td><td align="left">37,045</td></tr><tr><td align="left">appsmithorg/appsmith</td><td align="left">34,352</td></tr><tr><td align="left">gradio-app/gradio</td><td align="left">33,709</td></tr><tr><td align="left">DIYgod/RSSHub</td><td align="left">33,432</td></tr><tr><td align="left">calcom/cal.com</td><td align="left">32,282</td></tr><tr><td align="left">milvus-io/milvus</td><td align="left">30,299</td></tr><tr><td align="left">k3s-io/k3s</td><td align="left">28,010</td></tr><tr><td align="left">discordjs/discord.js</td><td align="left">25,390</td></tr><tr><td align="left">element-plus/element-plus</td><td align="left">24,488</td></tr><tr><td align="left">cilium/cilium</td><td align="left">20,150</td></tr><tr><td align="left">monkeytypegame/monkeytype</td><td align="left">15,635</td></tr><tr><td align="left">amplication/amplication</td><td align="left">15,196</td></tr><tr><td align="left">docker-mailserver/docker-mailserver</td><td align="left">14,643</td></tr><tr><td align="left">jupyterlab/jupyterlab</td><td align="left">14,167</td></tr><tr><td align="left">openimsdk/open-im-server</td><td align="left">14,041</td></tr><tr><td align="left">quarkusio/quarkus</td><td align="left">13,771</td></tr><tr><td align="left">espressif/arduino-esp32</td><td align="left">13,609</td></tr><tr><td align="left">sympy/sympy</td><td align="left">12,967</td></tr><tr><td align="left">ionic-team/stencil</td><td align="left">12,561</td></tr><tr><td align="left">zephyrproject-rtos/zephyr</td><td align="left">10,819</td></tr><tr><td align="left">qgis/QGIS</td><td align="left">10,569</td></tr><tr><td align="left">trinodb/trino</td><td align="left">10,413</td></tr><tr><td align="left">OpenFeign/feign</td><td align="left">9,490</td></tr><tr><td align="left">marimo-team/marimo</td><td align="left">7,583</td></tr><tr><td align="left">dream-num/univer</td><td align="left">7,021</td></tr><tr><td align="left">aws/karpenter-provider-aws</td><td align="left">6,782</td></tr><tr><td align="left">hibernate/hibernate-orm</td><td align="left">5,976</td></tr><tr><td align="left">ant-design-blazor/ant-design-blazor</td><td align="left">5,809</td></tr><tr><td align="left">litestar-org/litestar</td><td align="left">5,511</td></tr></tbody></table></div><h2 id="new-vulnerability-patterns">New vulnerability patterns<a aria-label="New vulnerability patterns" class="heading-link pl-2 text-italic text-bold" href="#new-vulnerability-patterns"></a></h2><p>Having triaged and reported numerous alerts, we have identified some common patterns that often lead to vulnerabilities in GitHub workflows:</p><h3 id="misuse-of-pull_request_target-trigger">Misuse of <code>pull_request_target trigger</code><a aria-label="Misuse of &lt;code&gt;pull_request_target trigger&lt;/code&gt;" class="heading-link pl-2 text-italic text-bold" href="#misuse-of-pull_request_target-trigger"></a></h3><p>The <code>pull_request_target</code> event trigger, while offering powerful automation capabilities in GitHub Actions, harbors a dark side filled with potential security pitfalls. This event trigger, designed to execute workflows within the context of pull request’s base branch, presents special characteristics that severely increase the impact in case of any vulnerability. A workflow activated by <code>pull_request_target</code> and triggered from a fork operates with significant privileges, in contrast to the <code>pull_request</code> event:</p><ul><li>It is able to read repository and organization secrets.  </li><li>It is allowed to have write permissions.  </li><li>It circumvents the usual safeguards of pull request approvals, allowing workflows to run unimpeded even if approval mechanisms are configured for standard <code>pull_request</code> events.  </li><li>It normally runs in the context of the default branch, which, as we will see, may allow malicious actors to poison the action’s cache and move laterally to other, more privileged workflows even when removing all permissions to the vulnerable workflow.</li></ul><p>When working with <code>pull_request_triggered</code> workflows, we have to be very careful and pay special attention to the following scenarios:</p><ul><li><strong>Code execution from untrusted sources:</strong> The ability to execute code from forked pull requests is a double-edged sword. A malicious actor can submit a seemingly innocuous pull request that, when triggered by <code>pull_request_target</code>, unleashes havoc. This malicious code, running in the context of the target repository’s environment, could exfiltrate secrets or even tamper with repository contents and releases. The danger lies in the inadvertent checkout and execution of code from untrusted sources. Common mistakes include using the <code>actions/checkout</code> action with a reference to the pull request’s head branch.</li><li><p><strong>Time of check to time of use (TOCTOU) attacks</strong>. Even with approval requirements in place (such as requiring the pull request to have a specific label that attackers are not able to set on their own), attackers can leverage the element of time to bypass security measures. A malicious actor can submit a seemingly harmless pull request, patiently wait for approval, and then swiftly update the pull request with malicious code before the workflow execution. The workflow, relying on a mutable reference like a branch name, falls prey to this <a href="https://github.com/AdnaneKhan/ActionsTOCTOU">“time of check to time of use” (TOCTOU) attack</a>, unwittingly executing the newly injected malicious code. Confusion surrounding context variables, specifically <code>head.ref</code> and <code>head.sha</code>, can lead to vulnerabilities.  <code>head.ref</code>, pointing to the branch, is susceptible to manipulation by attackers. In contrast, <code>head.sha</code>, referencing the specific commit, provides a reliable and immutable pointer to the reviewed and approved code. Using the incorrect variable can create an opening for attackers to inject malicious code after approval.</p></li><li><p><strong>Lurking threats in non-default branches</strong>. Vulnerabilities often linger in non-default branches, even after being addressed in the default branch. An attacker can target these vulnerable versions of the workflows residing in non-default branches, exploiting them by submitting pull requests specifically to those branches.</p></li><li><p><strong>Cache poisoning</strong>. As a mitigation, developers may strip out all read and write permissions from these workflows when in need to run untrusted code. However, the seemingly innocuous <code>permissions: &#123;&#125;</code> configuration can unexpectedly pave the way for <a href="https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/">cache poisoning attacks</a>. This attack vector involves injecting malicious content into the cache, which can subsequently affect other workflows relying on the poisoned cache entries. Even if a workflow doesn’t have write access to the repository, it can still poison the cache, leading to potential code execution or data manipulation in other workflows that utilize the compromised cache.</p></li></ul><p>If we really need to use this trigger event, there are a few ways to harden the workflows to prevent any abuses:</p><ul><li><strong>Repository checks</strong>. Implementing stringent repository checks is crucial for thwarting attacks originating from forked pull requests. One effective method is to configure workflows to execute only for pull requests originating from the base repository, effectively blocking any attempts from external forks. This can be achieved by using conditions such as <code>github.event.pull_request.head.repo.owner.login == “myorg”</code> to restrict workflow execution.</li><li><p><strong>Actor checks</strong>. Verifying the permissions of the pull request author is another layer of defense. By restricting workflow execution to trusted actors, such as members of the organization or approved collaborators, the risk of malicious code injection from unauthorized sources can be significantly reduced. Never use a hardcoded list of user names, since the users may lose the permissions with time or the user names may be left abandoned for an attacker to claim.</p></li><li><p><strong>Workflow splitting</strong>. The above mitigations may not be useful if we need to run a workflow for forks or arbitrary users. In those cases, splitting workflows into unprivileged and privileged components is a powerful security strategy. Unprivileged workflows, triggered by <code>pull_request</code> events, handle the initial processing of pull requests without access to sensitive secrets or write permissions. Privileged workflows, activated by <code>workflow_run</code> events, are invoked only after the unprivileged workflow has completed its checks. This separation ensures that potentially malicious code from forked pull requests never executes within a privileged context. The unprivileged workflow will generally need to communicate and pass information to the privileged one. This is a <strong>crucial security boundary</strong>, and, as we will see in the next section, any data coming from the unprivileged workflow should be considered untrusted and potentially dangerous.</p></li></ul><h3 id="security-boundaries-and-workflow_run-event">Security boundaries and <code>workflow_run event</code><a aria-label="Security boundaries and &lt;code&gt;workflow_run event&lt;/code&gt;" class="heading-link pl-2 text-italic text-bold" href="#security-boundaries-and-workflow_run-event"></a></h3><p>The <code>workflow_run</code> event trigger in GitHub Actions is designed to automate tasks based on the execution or completion of another workflow. It may grant write permissions and access to secrets even if the triggering workflow doesn’t have such privileges. While this is beneficial for tasks like labeling pull requests based on test results, it poses significant security risks if not used carefully.</p><p>The <code>workflow_run</code> trigger poses a risk because it can often be initiated by an attacker. Some maintainers were surprised by this, believing that their triggering workflows, which were run on events such as <code>release</code>, were safe. This assumption was based on the idea that since an attacker couldn’t trigger a new release, they shouldn’t be able to initiate the triggering workflow or the subsequent <code>workflow_run</code> workflow.</p><p>The reality is that an attacker can submit a pull request that modifies the triggering workflow and even replace the triggering events. Since <code>pull_request</code> workflows run in the context of the pull request’s <code>HEAD</code> branch, the modified workflow will run and, upon completion, will be able to trigger an existing <code>workflow_run</code> workflow. The danger arises from the fact that even if the triggering <code>pull_request</code> workflow is not privileged, the triggered <code>workflow_run</code> workflow will have access to secrets and write-scoped tokens, even if the initial workflow did not have those privileges. This enables privilege escalation attacks, allowing attackers to execute malicious code with elevated permissions within the CI/CD pipeline.</p><p>Another significant pitfall with the <code>workflow_run</code> event trigger is artifact poisoning. Artifacts are files generated during a workflow run that can be shared with other workflows. Attackers can poison these artifacts by uploading malicious content through a pull request. When a <code>workflow_run</code> workflow downloads and uses these poisoned artifacts, it can lead to arbitrary code execution or other malicious activities within the privileged workflow. The issue is that many <code>workflow_run</code> workflows do not verify the contents of downloaded artifacts before using them, making them vulnerable to various attacks.</p><p>Securing <code>workflow_run</code> workflows requires a multi-faceted approach. By understanding the inherent risks and implementing the recommended mitigations, developers can leverage the automation benefits of <code>workflow_run</code> while minimizing the potential for security compromises.</p><h4 id="effective-mitigations">Effective mitigations<a aria-label="Effective mitigations" class="heading-link pl-2 text-italic text-bold" href="#effective-mitigations"></a></h4><ul><li><strong>Limit workflow scope with branch filters:</strong> Specify the branches where <code>workflow_run</code> workflows can be triggered using the <code>branches</code> filter. This helps restrict the scope of potential attacks by preventing them from being triggered on branches from forks.</li><li><p><strong>Verify event origin:</strong> Incorporate a check like <code>github.event_name != 'pull_request'</code> to prevent <code>workflow_run</code> workflows from being triggered by pull requests from forks. This adds an extra layer of protection by ensuring that the triggering workflow originates from a trusted source.</p></li><li><p><strong>Treat artifacts as untrusted:</strong> Treat all downloaded artifacts as potentially malicious and implement rigorous validation checks before using them. Always unzip artifacts to a temporary directory like <code>/tmp</code> to prevent potential file overwrites, that is, the pollution of the workspace.</p><ul><li><strong>Avoid defining environment variables:</strong> Minimize the use of environment variables, especially when handling untrusted data. Environment variables can be vulnerable to injection attacks, potentially allowing attackers to modify their values and execute malicious code.</li><li><p><strong>Handle output variables with caution:</strong> Exercise caution when defining output variables from artifact’s content, as they can also be vulnerable to manipulation by attackers. Always validate the contents of output variables (for example, that it is a number, not a string) before using them in subsequent steps or other workflows.</p></li></ul></li></ul><h4 id="non-effective-mitigations">Non-effective mitigations<a aria-label="Non-effective mitigations" class="heading-link pl-2 text-italic text-bold" href="#non-effective-mitigations"></a></h4><ul><li><strong>Repository checks:</strong> We found several workflows (for example, <a href="https://securitylab.github.com/advisories/GHSL-2024-314_AWS_Karpenter_Provider/">AWS Karpenter Provider</a>, or <a href="https://securitylab.github.com/advisories/GHSL-2024-252_Cloudflare_workers-sdk/">Cloudflare Workers SDK</a>) relying solely on repository checks, such as verifying the repository owner (<code>github.repository_owner == 'myorg'</code>), which is not effective in mitigating <code>workflow_run</code> risks since the workflow always runs in the context of the default branch which belongs to the organization.</li></ul><h3 id="issueoops-security-pitfalls-with-issue_comment-trigger">IssueOops: Security pitfalls with <code>issue_comment</code> trigger<a aria-label="IssueOops: Security pitfalls with &lt;code&gt;issue_comment&lt;/code&gt; trigger" class="heading-link pl-2 text-italic text-bold" href="#issueoops-security-pitfalls-with-issue_comment-trigger"></a></h3><p>The <code>issue_comment</code> event trigger in GitHub Actions is a powerful tool for automating workflows based on comments on issues and pull requests. When applied in the context of <a href="https://issue-ops.github.io/docs/">IssueOps</a>, it can streamline tasks like running commands in response to specific comments. However, this convenience comes with significant security risks that must be carefully considered.</p><ul><li><strong>TOCTOU vulnerabilities:</strong> Similar to the <code>pull_request_target</code> event trigger, workflows using <code>issue_comment</code> can be vulnerable to <a href="https://github.com/AdnaneKhan/ActionsTOCTOU">TOCTOU attacks</a>. If the workflow checks out and executes code from a pull request based on an issue comment, an attacker could exploit the time window between the comment and the workflow execution. An attacker might initially submit a harmless pull request, waiting for an administrator to review and approve the workflow by adding a comment. Once the approval is given, the attacker could quickly update the pull request with malicious code, which would then be executed by the workflow.</li><li><p><strong>Bypassing pull request approval mechanisms:</strong> The <code>issue_comment</code> event trigger is not subject to the pull request approval mechanisms intended to prevent abuse. Even if the workflows triggered by <code>pull request</code> require approvals, an attacker can trigger an <code>issue_comment</code> workflow by simply adding a comment to the pull request, potentially executing malicious code without any review.</p></li></ul><h4 id="mitigating-the-risks">Mitigating the risks<a aria-label="Mitigating the risks" class="heading-link pl-2 text-italic text-bold" href="#mitigating-the-risks"></a></h4><ul><li><strong>Shifting to label gates:</strong> Instead of relying on issue comments to trigger critical workflows, consider adopting a label gates approach. Label gates use labels to trigger specific actions, allowing for more granular control and better security. Since the labeled activity type for a <code>pull_request</code> trigger contains details about the latest commit SHA of the pull request, there is no need for workflow to resolve a pull request number into the latest commit SHA, as it is the case with <code>issue_comment</code>, and, therefore, there is no window for an attacker to modify the pull request. Remember to use the commit SHA rather than the HEAD reference to prevent <a href="https://github.com/AdnaneKhan/ActionsTOCTOU">TOCTOU vulnerabilities</a>.</li></ul><h4 id="ineffective-or-incomplete-mitigations">Ineffective or incomplete mitigations<a aria-label="Ineffective or incomplete mitigations" class="heading-link pl-2 text-italic text-bold" href="#ineffective-or-incomplete-mitigations"></a></h4><ul><li><p><strong>Actor checks:</strong> Relying solely on actor checks (verifying the identity or permissions of the commenter) is ineffective. The actor triggering the workflow might not be the same one trying to exploit it, further rendering actor checks unreliable. This is the case for TOCTOU vulnerabilities where an attacker can submit a legitimate pull request and wait for an admin to trigger an IssueOp and then swiftly mutate the pull request by adding a new commit with malicious code on it.</p></li><li><p><strong>Date checks:</strong> Comparing timestamps to verify that the last commit occurred before the triggering comment is also unreliable. Currently, GitHub has no reliable way to figure out the date when a commit was pushed to a repository. An attacker can forge commit dates, rendering these checks useless in preventing malicious code execution.</p></li><li><p><strong>Repository checks:</strong> Verifying the origin repository is not a useful mitigation for <code>issue_comment</code> event triggers. The <code>issue_comment</code> event always executes within the context of the target repository’s default branch, making repository checks redundant.</p></li></ul><h2 id="wrapping-up">Wrapping up<a aria-label="Wrapping up" class="heading-link pl-2 text-italic text-bold" href="#wrapping-up"></a></h2><p><a href="https://github.blog/changelog/2024-12-17-find-and-fix-actions-workflows-vulnerabilities-with-codeql-public-preview/">The new CodeQL support for GitHub Actions is in public preview</a>. The new QL packs allow you to scan your repository for a variety of vulnerabilities in GitHub Actions, helping prevent supply chain attacks in the OSS software we all depend on! If you want to give them a try, take one of the following steps depending on your case:</p><ul><li>Your repository is newly configured for <a href="https://docs.github.com/en/code-security/code-scanning/enabling-code-scanning/configuring-default-setup-for-code-scanning">default setup</a>: Code scanning will automatically attempt to analyze actions if any workflows are present on the default branch. You have nothing to do; keep calm and fix the potential alerts.  </li><li>Your repository is already configured for default setup: You need to edit the Default Setup settings and explicitly enable actions analysis.  </li><li>Your repository is using advanced setup: You just have to add <code>actions</code> to the language matrix.</li></ul><p>Stay secure!</p></body></html><p>The post <a href="https://github.blog/security/application-security/how-to-secure-your-github-actions-workflows-with-codeql/">How to secure your GitHub Actions workflows with CodeQL</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="How to secure your GitHub Actions workflows with CodeQL" href="https://github.blog/security/application-security/how-to-secure-your-github-actions-workflows-with-codeql/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">How to secure your GitHub Actions workflows with CodeQL</span><span class="cap link fs12">https://github.blog/security/application-security/how-to-secure-your-github-actions-workflows-with-codeql/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>How to Use GitHub Copilot: What It Can Do and Real-World Examples</title>
    <link href="https://blog.imc.re/RSSBOX/rss/8927e0cb.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/8927e0cb.html</id>
    <published>2025-01-09T07:33:16.000Z</published>
    <updated>2025-01-09T07:33:16.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>Since the <a href="https://github.com/features/copilot?utm_source=whatcancopilotdo&amp;utm_medium=blog&amp;utm_campaign=copilot_free_jan_&amp;utm_content=topgraf">free version of GitHub Copilot</a> launched last month, you’ve asked lots of questions, like “Is it free for everyone?” (Yes!), “Can Copilot make changes to multiple files?” (Yes again!), “What’s the name of Copilot’s mascot?” (It doesn’t have a name…yet.), and most of all: “What can GitHub Copilot <em>actually</em> do?”</p><p>The short answer is a lot. The longer answer covers a bunch of different use cases, workflows, coding languages, and much more, so it’s a good thing we have some space to talk about it!</p><p>We’ll update this list as GitHub Copilot continues to evolve and we add new, awesome features like we’ve been doing since we first launched it a few years ago.</p><p>Ready? Let’s go.</p><aside class="p-4 p-md-6 post-aside--large"><p class="h5-mktg gh-aside-title">What’s included in GitHub Copilot Free</p><p>Our free version of Copilot is included by default in personal GitHub accounts. Features include:</p><ul><li><strong>Your choice of model:</strong> Pick between Anthropic’s Claude 3.5 Sonnet or OpenAI’s GPT-4o. </li><li><strong>Native support in VS Code and on GitHub:</strong> Authorize the GitHub Copilot extension in VS Code and go, or use Copilot on github.com to ask questions, generate tests, find information, and more via Copilot Chat.</li><li><strong>2,000 intelligent code completions a month:</strong> Get tailored code suggestions that draw context from your GitHub repositories and VS Code workspace.</li><li><strong>50 Copilot Chat messages a month:</strong> Ask Copilot Chat for help understanding code, refactoring something, or debugging an issue.</li><li><strong>Make changes to multiple files:</strong> Tackle bigger changes with Copilot Edits.</li><li><strong>Support for the Copilot Extensions ecosystem:</strong> Access third-party agents designed for tasks such as querying specific online resources or searching the web.</li></ul><p><a href="https://github.com/features/copilot?utm_source=whatcancopilotdo&amp;utm_medium=blog&amp;utm_campaign=copilot_free_jan_&amp;utm_content=box">Start using GitHub Copilot &gt; </a></p><p>P.S. Not sure how to get the most out of Copilot’s options? Check out <a href="https://docs.github.com/en/copilot/example-prompts-for-github-copilot-chat?utm_source=copilot_free_jan&amp;utm_medium=blog&amp;utm_campaign=what_can_copilot_do&amp;utm_content=callout">our Copilot Chat Cookbook with a collection of sample prompts covering common coding scenarios</a> (and we discuss a lot of them below!).</p></aside><h2 id="what-is-github-copilot">What is GitHub Copilot?<a aria-label="What is GitHub Copilot?" class="heading-link pl-2 text-italic text-bold" href="#what-is-github-copilot"></a></h2><p>GitHub Copilot is a generative AI tool that functions as a coding assistant to help you write code faster and so much more.</p><p>One of the main advantages of Copilot is it draws context from your coding environment, open tabs, and your GitHub projects (including your pull requests, issues, discussions, and codebase). For example, you can ask Copilot Chat to provide a summary of code in a given repository or explain how pieces of code in your app work. In either case, it will provide an answer with the contextual knowledge of your project. You can also ask Copilot to help document, debug, and refactor code—all without the need to context switch or copy over large sections of code to another application.</p><p>GitHub Copilot is available for anyone to use with GitHub Copilot Free. If you want more advanced Copilot capabilities, we offer Pro, Business, and Enterprise tiers, too. With these options, you can pick the solution that works best for you. For your reference, we’ve included a <a href="#breaking-down-the-different-github-copilot-tiers-from-free-to-enterprise">section on the different access tiers</a>.</p><h3 id="how-are-developers-using-github-copilot">How are developers using GitHub Copilot?<a aria-label="How are developers using GitHub Copilot?" class="heading-link pl-2 text-italic text-bold" href="#how-are-developers-using-github-copilot"></a></h3><p>As GitHub Copilot capabilities continue to grow, developers are using it in a number of ways including:</p><ul><li>Getting code completion suggestions while they type in the IDE</li><li>Asking Copilot Chat to explain how a section of code works</li><li>Generating tests and helping to fix code that fails a given test</li><li>Migrating code to a different language</li><li>Refactoring existing code</li><li>Explaining code you’re working with</li><li>Using Copilot Extensions to work with other applications and tools in your tech stack (you can even build a custom one)</li><li>Generating documentation to describe a set of changes in a pull request</li></ul><aside class="p-4 p-md-6 post-aside--large"><p class="h5-mktg gh-aside-title">Remember to review and iterate on code suggestions from GitHub Copilot</p><p>Just like when a team member submits a PR, you should always review code from GitHub Copilot. It’s also important to iterate on your prompts to improve on what GitHub Copilot suggests.</p><p><a href="https://github.blog/ai-and-ml/generative-ai/how-ai-code-generation-works/">Learn more about how AI code generation works &gt;</a></p></aside><h2 id="what-github-copilot-can-do-and-how-to-use-it">What GitHub Copilot can do (and how to use it)<a aria-label="What GitHub Copilot can do (and how to use it)" class="heading-link pl-2 text-italic text-bold" href="#what-github-copilot-can-do-and-how-to-use-it"></a></h2><p>So, how can GitHub Copilot help you in your projects? Let’s jump in.</p><h3 id="whats-new-in-github-copilot">What’s new in GitHub Copilot<a aria-label="What’s new in GitHub Copilot" class="heading-link pl-2 text-italic text-bold" href="#whats-new-in-github-copilot"></a></h3><p>This is a living document, so we’ll update this section with the latest and greatest from Copilot as it continues to evolve.</p><h3 id="choose-the-ai-model-that-powers-github-copilot">Choose the AI model that powers GitHub Copilot<a aria-label="Choose the AI model that powers GitHub Copilot" class="heading-link pl-2 text-italic text-bold" href="#choose-the-ai-model-that-powers-github-copilot"></a></h3><p>With GitHub Copilot, you can choose the model you want to work with. In Copilot Free you have access to Anthropic’s Claude 3.5 Sonnet and OpenAI’s GPT-4o models. And if you use one of the Copilot paid tiers, you’ll have more models to choose from to customize your experience.</p><h3 id="in-line-code-completion">In-line code completion<a aria-label="In-line code completion" class="heading-link pl-2 text-italic text-bold" href="#in-line-code-completion"></a></h3><p>When coding, GitHub Copilot can offer coding suggestions directly in your coding environment. It can both provide code to complete what you’re currently working on or respond to natural language prompts to generate code. Developers often use this for generating boilerplate code and common coding snippets—such as the getter and setter functions of variables.</p><p>But Copilot isn’t limited to simple and repetitive code completion. Using Copilot Chat, you can tell it what you want it to do by describing the task in plain language or the <code>/new</code> slash command, it will then provide some code suggestions to help you get started.</p><p>💡 <strong>Pro tip:</strong> Getting the most out of this feature requires you to craft good prompts.You can learn more about effective prompting with GitHub Copilot in <a href="https://docs.github.com/copilot/using-github-copilot/prompt-engineering-for-github-copilot">our documentation on prompt engineering</a>.</p><div class="wp-video" style="width: 2560px;"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]--><video class="wp-video-shortcode" controls="controls" height="1440" id="video-81844-1" preload="metadata" width="2560"><source src="https://github.blog/wp-content/uploads/2025/01/2024-12-10-CopilotUI-Completion-H-Captioned.mp4#t=0.001?_=1" type="video/mp4"/><a href="https://github.blog/wp-content/uploads/2025/01/2024-12-10-CopilotUI-Completion-H-Captioned.mp4#t=0.001">https://github.blog/wp-content/uploads/2025/01/2024-12-10-CopilotUI-Completion-H-Captioned.mp4#t=0.001</a></video></div><h3 id="generate-unit-tests">Generate unit tests<a aria-label="Generate unit tests" class="heading-link pl-2 text-italic text-bold" href="#generate-unit-tests"></a></h3><p>Writing unit tests requires knowing the limits, edge cases, and what might cause failures in your code. Since Copilot knows about your project on GitHub and what you’re working on in your IDE, it can create unit tests to help you.</p><p>To do this, select a given block of code. Then either right-click and use the context menu or the <code>/tests</code> slash command. Copilot will then analyze your code and try to provide suggestions for valid inputs, edge cases, and invalid inputs.</p><p>For additional guidance on using GitHub Copilot to create unit tests, check out this <a href="https://github.blog/ai-and-ml/how-to-generate-unit-tests-with-github-copilot-tips-and-examples/">blog about creating unit tests</a> and take a look at <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/testing-code/generate-unit-tests">this docs page of sample prompts</a>.</p><div class="mod-yt position-relative" style="height: 0; padding-bottom: calc((9 / 16)*100%);"><iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" class="position-absolute top-0 left-0 width-full height-full" frameborder="0" loading="lazy" src="https://www.youtube.com/embed/smdBqEu7fx4?feature=oembed" title="YouTube video player"></iframe></div><h3 id="explain-and-document-existing-code">Explain and document existing code<a aria-label="Explain and document existing code" class="heading-link pl-2 text-italic text-bold" href="#explain-and-document-existing-code"></a></h3><p>You can tap into GitHub Copilot’s knowledge of coding patterns to ask it to help explain how a block of code works. This is particularly useful if you’re onboarding to a new project, especially if it’s in a language you don’t have a lot of experience in.</p><p>To use this feature, select some code and use either the context menu or the <code>/explain</code> slash command. Copilot will then explain what the code is doing—and then generate documentation on it with another prompt.</p><p>This isn’t just useful for onboarding or making sure you understand a piece of code. You can also use this as a building block for other tasks such as helping to translate code from one language to another.</p><p>For some sample prompts, check out our docs on <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/documenting-code/explaining-legacy-code">explaining legacy code</a> and on <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/documenting-code/explaining-complex-algorithms-or-logic">explaining complex logic</a>.</p><div class="wp-video" style="width: 1920px;"><video class="wp-video-shortcode" controls="controls" height="1080" id="video-81844-2" preload="metadata" width="1920"><source src="https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_ExplainingComplexLogic_1920x1080_Captions.mp4#t=0.001?_=2" type="video/mp4"/><a href="https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_ExplainingComplexLogic_1920x1080_Captions.mp4#t=0.001">https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_ExplainingComplexLogic_1920x1080_Captions.mp4#t=0.001</a></video></div><h3 id="upgrading-a-framework-youre-working-with">Upgrading a framework you’re working with<a aria-label="Upgrading a framework you’re working with" class="heading-link pl-2 text-italic text-bold" href="#upgrading-a-framework-youre-working-with"></a></h3><p>If you’re tasked with upgrading a codebase to a new version of a framework, it’s not as easy as recompiling the project in the new version. That often results in several errors that you need to track down and resolve. GitHub Copilot can help you here.</p><p>You can just ask why your code is producing errors. From there, you can  have Copilot provide suggestions on how to fix your code to make it compliant with the new version of the framework. Then ask Copilot for suggestions on how to update the code to fit in a new framework.</p><aside class="p-4 p-md-6 post-aside--large"><p class="h5-mktg gh-aside-title">Using Copilot Chat</p><p>Copilot Chat is an interactive chat interface that can be accessed in your IDE, on github.com, through GitHub Mobile, or through your Windows Terminal. (With GitHub Copilot Free, you’re limited to using your IDE and github.com.)</p><p>If you’re using GitHub Copilot in VS Code, you can find Copilot Chat in a separate panel and/or inline (right-click your code and select “Copilot”). By default, Copilot Chat focuses on your selected code and open files, but you can change this context with keywords.</p><p>On github.com, click the Copilot icon in the upper-right corner to start chatting with Copilot. Feel free to ask questions about your projects on GitHub, how to do specific things, and much more.</p><p>Copilot Chat accesses information across the internet and other GitHub repositories. It uses that knowledge to identify patterns it can then use to help refactor code, explain code, generate documentation, build tests, and far more. And, it’s right alongside your code. This is what makes it such a powerful tool.</p><p><video controls="" loop="" muted="" width="100%"><source src="https://github.blog/wp-content/uploads/2025/01/2024-09-copilot-dotcom-chat-Burned.mp4" type="video/mp4"/></video></p><p><strong>Using Copilot Extensions with Copilot Chat</strong></p><p>Copilot Extensions allow Copilot Chat to interface with community-developed and third-party agents that add support for anything from conducting web searches, to accessing information from public online repositories, and far more. You can also create your own Copilot Extensions.</p><p><a href="https://github.com/marketplace?type=apps&amp;copilot_app=true">Explore Copilot Extensions in the GitHub Marketplace &gt; </a></p></aside><h3 id="explain-a-codebase-or-a-repository-on-github">Explain a codebase (or a repository on GitHub)<a aria-label="Explain a codebase (or a repository on GitHub)" class="heading-link pl-2 text-italic text-bold" href="#explain-a-codebase-or-a-repository-on-github"></a></h3><p>Trying to understand a new codebase? Ask Copilot what a repository does or to summarize key components and it will provide a summary. To get started, click the Copilot icon in the top-right corner of your screen and ask a question. You can also prompt Copilot to debug your workflows with GitHub Actions. If you want to focus Copilot’s attention, you can highlight individual files or folders in a repository, too.</p><p>💡 <strong>Pro tip</strong>: <a href="https://github.com/copilot/">Use Copilot as a chat assistant directly on github.com</a> with a full, natural-language interface.</p><h3 id="translate-code-to-a-new-language">Translate code to a new language<a aria-label="Translate code to a new language" class="heading-link pl-2 text-italic text-bold" href="#translate-code-to-a-new-language"></a></h3><p>Let’s say you need to migrate legacy software from COBOL to a more modern coding language. GitHub Copilot can help you with this, even if you don’t have a lot of experience with the source language.</p><p>First, ask it to explain what some code is doing, and then use that explanation to create code in the destination language that performs the same functionality. You can also ask it to provide suggestions on how to write the code in the destination language.</p><p>Our documentation on <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/documenting-code/explaining-legacy-code">explaining legacy code includes a sample prompt</a> and walks through the first portion of this scenario.</p><aside class="p-4 p-md-6 post-aside--large"><p class="h5-mktg gh-aside-title">Using slash commands: Quick shortcuts to help speed up your Copilot workflows in VS Code</p><p>Slash commands are predefined actions within GitHub Copilot that allow you to quickly access specific actions through Copilot Chat. You can use the following slash commands to help speed up your workflows using Copilot:</p><p><code>/help</code>: provide a quick reference and the basics of GitHub Copilot<br/><code>/explain</code>: explain how the code in your active editor works<br/><code>/tests</code>: generate unit tests for the selected code<br/><code>/fixTestFailure</code>: find and fix failing tests<br/><code>/fix</code>: find and fix general problems in the selected code<br/><code>/new</code>: set up a new project<br/><code>/clear</code>: start a new chat session</p><p><video controls="" loop="" muted="" width="100%"><source src="https://github.blog/wp-content/uploads/2025/01/2024-12-10-CopilotUI-SlashCommands-Horizontal-Captioned.mp4" type="video/mp4"/></video></p></aside><h3 id="generate-documentation">Generate documentation<a aria-label="Generate documentation" class="heading-link pl-2 text-italic text-bold" href="#generate-documentation"></a></h3><p>Closely tied to the idea of explaining how code works, you can ask GitHub Copilot to generate documentation for sections of code or entire projects. This can be incredibly useful, and a huge time saver.</p><p>In Copilot Free, you can also ask it to provide a summary of given code blocks within your IDE by using the slash command <code>/docs</code>. In the paid versions, you can also generate documentation from issues and pull requests.</p><p>One real-world example of this involves legacy COBOL-based applications. You can ask Copilot to help provide the missing docs for a given project. (Visit <a href="https://docs.github.com/en/copilot/example-prompts-for-github-copilot-chat/documenting-code/documenting-legacy-code">documenting legacy code</a> to get started).</p><h3 id="debugging-code">Debugging code<a aria-label="Debugging code" class="heading-link pl-2 text-italic text-bold" href="#debugging-code"></a></h3><p>We’ve all been there—you have a section of code that’s spitting out an error and you aren’t sure how to fix it. Sometimes you try to implement a fix, and then you get more errors (classic 🤦).</p><p>To get help from GitHub Copilot, highlight the code in question and either right-click and select “Copilot” or use the <code>/fix</code> slash command in Copilot Chat. You can also ask Copilot Chat why something isn’t working to start a conversation about what the problem might be.</p><p>Copilot works by analyzing your code and drawing upon its training data. It also looks at the context of your larger project to identify patterns that might be causing the problem.</p><p>To learn more, you can find <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/debugging-errors/debugging-invalid-json">a sample prompt and tutorial on how to debug invalid JSON in our docs</a>.</p><div class="wp-video" style="width: 1920px;"><video class="wp-video-shortcode" controls="controls" height="1080" id="video-81844-3" preload="metadata" width="1920"><source src="https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_DebuggingInvalidJSON_1920x1080_Captions.mp4#t=0.001?_=3" type="video/mp4"/><a href="https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_DebuggingInvalidJSON_1920x1080_Captions.mp4#t=0.001">https://github.blog/wp-content/uploads/2025/01/CopilotChatCookbook_DebuggingInvalidJSON_1920x1080_Captions.mp4#t=0.001</a></video></div><aside class="p-4 p-md-6 post-aside--large"><p class="h5-mktg gh-aside-title">Using chat variables to add more context to your prompts</p><p>Chat variables are a great tool for crafting more effective prompts (I rely on them constantly to point GitHub Copilot at specific files). They allow you to include specific context, making it easier to focus Copilot on exactly what you’re trying to accomplish. Some particularly useful chat variables include:</p><p><code>#file</code>: Adds a specific file to provide Copilot with relevant context (this one’s my personal favorite).<br/><code>#git</code>: Pulls information about your current Git repository.</p><p>You can also type <kbd>#</kbd> in Copilot Chat to see the full list of available chat variables.</p></aside><h3 id="refactoring-code">Refactoring code<a aria-label="Refactoring code" class="heading-link pl-2 text-italic text-bold" href="#refactoring-code"></a></h3><p>Want to make your code cleaner? Perform better? Same. This is a place where GitHub Copilot can help—and I’m speaking from experience. Just highlight a specific code block (or point Copilot at a specific file with the chat variable command #file) and ask Copilot for suggestions to improve your code.</p><p>Copilot will then search for specific patterns and ways to refactor your code. For example, it might recommend breaking up a long method with multiple tasks or avoiding nested logic checks to improve readability or performance. You can quickly review and accept suggestions to refactor your code—all right in your IDE.</p><p>Check out our documentation on <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/refactoring-code">using GitHub Copilot for refactoring your code</a> for some guidance on how to take advantage of this functionality. For some sample prompts, see these pages on <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/refactoring-code/improving-code-readability-and-maintainability">improving code readability</a> and <a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat/refactoring-code/refactoring-for-performance-optimization">optimizing performance</a>.</p><h3 id="multi-file-editing-with-copilot-edits">Multi-file editing with Copilot Edits<a aria-label="Multi-file editing with Copilot Edits" class="heading-link pl-2 text-italic text-bold" href="#multi-file-editing-with-copilot-edits"></a></h3><p>Copilot Edits provide the functionality for you to edit multiple files at once. This means you don’t need to manually open each file and insert the changes—which is a huge time saver. It also helps reduce the possibility of making mistakes when making manual changes.</p><p>You can access this feature through the Copilot Chat menu.</p><div class="wp-video" style="width: 1920px;"><video class="wp-video-shortcode" controls="controls" height="1080" id="video-81844-4" preload="metadata" width="1920"><source src="https://github.blog/wp-content/uploads/2025/01/copilot-multi-edit-burn-in.mp4#t=0.001?_=4" type="video/mp4"/><a href="https://github.blog/wp-content/uploads/2025/01/copilot-multi-edit-burn-in.mp4#t=0.001">https://github.blog/wp-content/uploads/2025/01/copilot-multi-edit-burn-in.mp4#t=0.001</a></video></div><p>Once you select <strong>Open Copilot Edits</strong>, prompt Copilot with the changes you want to make. It will then determine which files in your working set need to be updated based on your prompt and provide a description of the changes it recommends for each file. You can then review the changes and individually accept or reject them.</p><p>💡 <strong>Pro tip:</strong> Right now, this feature is only available in VS Code.</p><p><a href="https://code.visualstudio.com/docs/copilot/copilot-edits">Learn more about multi-file editing in our documentation on Copilot Edits &gt;</a></p><h3 id="customize-github-copilot-to-meet-your-needs">Customize GitHub Copilot to meet your needs<a aria-label="Customize GitHub Copilot to meet your needs" class="heading-link pl-2 text-italic text-bold" href="#customize-github-copilot-to-meet-your-needs"></a></h3><p>When using GitHub Copilot, you can create a file that will provide custom instructions that will be included in all Copilot queries. This lets you reuse some of the same context without needing to manually enter it in each prompt.</p><p>When creating prompts, offering more details helps Copilot provide more relevant responses (e.g. related to the tools you use or how your team works). Including some of the same information in each prompt once you learn what works can be very helpful. By placing these persistent details in a file, you can tailor the way GitHub Copilot works to deliver higher quality responses.</p><p>For more information, see our <a href="https://docs.github.com/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot">documentation on adding custom instructions for Copilot</a>.</p><p>💡 <strong>Pro tip:</strong> Right now, this is only available with Copilot Chat through VS Code and Visual Studio.</p><h2 id="breaking-down-the-different-github-copilot-tiers-from-free-to-enterprise">Breaking down the different GitHub Copilot tiers from free to enterprise<a aria-label="Breaking down the different GitHub Copilot tiers from free to enterprise" class="heading-link pl-2 text-italic text-bold" href="#breaking-down-the-different-github-copilot-tiers-from-free-to-enterprise"></a></h2><p>Currently, everyone has access  to the GitHub Copilot Free tier. You can start using GitHub Copilot Free in VS Code by authorizing the extension or through github.com by clicking the Copilot icon in the top right-hand side of the interface.</p><p>For more information, see this video about how to set up GitHub Copilot Free.</p><div class="mod-yt position-relative" style="height: 0; padding-bottom: calc((9 / 16)*100%);"><iframe allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" class="position-absolute top-0 left-0 width-full height-full" frameborder="0" loading="lazy" src="https://www.youtube.com/embed/dMbOh114Vd4?feature=oembed" title="YouTube video player"></iframe></div><p>We also offer additional tiers with more capabilities via Pro, Business, and Enterprise with more advanced capabilities, depending on your needs.</p><p><a href="https://github.com/features/copilot/plans?cft=copilot_li.features_copilot&amp;utm_source=blog&amp;utm_campaign=copilot_plans">Find out which Copilot tier works best for you &gt;</a></p><h2 id="additional-resources-to-explore">Additional resources to explore<a aria-label="Additional resources to explore" class="heading-link pl-2 text-italic text-bold" href="#additional-resources-to-explore"></a></h2><p>We hope this answers your questions about Copilot’s capabilities and inspires you to give it a try in your next project. Here’s a recap of the resources we shared throughout this article:.</p><ul><li><a href="https://github.com/features/copilot/plans?cft=copilot_li.features_copilot?utm_source=whatcancopilotdo&amp;utm_medium=blog&amp;utm_campaign=copilot_free_jan_&amp;utm_content=bottom">GitHub Copilot plans</a>: This page offers an overview of GitHub Copilot</li><li><a href="https://docs.github.com/copilot">GitHub Copilot docs</a>: The main docs page for GitHub Copilot</li><li><a href="https://docs.github.com/copilot/setting-up-github-copilot/setting-up-github-copilot-for-yourself">Setting up GitHub Copilot</a>: Detailed instructions on how to go through the necessary setup steps to start using GitHub Copilot</li><li><a href="https://docs.github.com/copilot/example-prompts-for-github-copilot-chat">GitHub Copilot Chat Cookbook prompts</a>: Example prompts showcasing how to handle specific scenarios using GitHub Copilot Chat</li></ul></body></html><p>The post <a href="https://github.blog/developer-skills/github/what-can-github-copilot-do-examples/">How to use GitHub Copilot: What it can do and real-world examples</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="How to use GitHub Copilot: What it can do and real-world examples" href="https://github.blog/developer-skills/github/what-can-github-copilot-do-examples/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">How to use GitHub Copilot: What it can do and real-world examples</span><span class="cap link fs12">https://github.blog/developer-skills/github/what-can-github-copilot-do-examples/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>Open Source All the Way Down: Upgrading Our Developer Documentation</title>
    <link href="https://blog.imc.re/RSSBOX/rss/dea977e3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/dea977e3.html</id>
    <published>2025-01-08T14:00:00.000Z</published>
    <updated>2025-01-08T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>At Cloudflare, we treat developer <a href="https://blog.cloudflare.com/content-as-a-product/"><u>content like a product</u></a>, where we take the user and their feedback into consideration. We are constantly iterating, testing, analyzing, and refining content. Inspired by agile practices, treating developer content like an open source product means we approach our documentation the same way an open source software project is created and maintained.  Open source documentation empowers the developer community because it allows anyone, anywhere, to contribute content. By making both the content and the framework of the documentation site publicly accessible, we provide developers with the opportunity to not only improve the material itself but also understand and engage with the processes that govern how the documentation is built, approved, and maintained. This transparency fosters collaboration, learning, and innovation, enabling developers to contribute their expertise and learn from others in a shared, open environment. We also provide feedback to other open source products and plugins, giving back to the same community that supports us.</p><div><h2>Building the best open source documentation experience</h2><a href="#building-the-best-open-source-documentation-experience"></a></div><p>Great documentation empowers users to be successful with a new product as quickly as possible, showing them how to use the product and describing its benefits. Relevant, timely, and accurate content can save frustration, time, and money. Open source documentation adds a few more benefits, including building inclusive and supportive communities that help reduce the learning curve. We love being open source!</p><p>While the Cloudflare content team has scaled to deliver documentation alongside product launches, the open source documentation site itself was not scaling well. <a href="http://developers.cloudflare.com"><u>developers.cloudflare.com</u></a> had outgrown the workflow for contributors, plus we were missing out on all the neat stuff created by developers in the community.</p><p>Just like a software product evaluation, we reviewed our business needs. We asked ourselves if remaining open source was appropriate? Were there other tools we wanted to use? What benefits did we want to see in a year or in five years? Our biggest limitations in addition to the contributor workflow challenges seemed to be around scalability and high maintenance costs for user experience improvements. </p><p>After compiling our wishlist of new features to implement, we reaffirmed our commitment to open source. We valued the benefit of open source in both the content and the underlying framework of our documentation site. This commitment goes beyond technical considerations, because it's a fundamental aspect of our relationship with our community and our philosophy of transparency and collaboration. While the choice of an open source framework to build the site on might not be visible to many visitors, we recognized its significance for our community of developers and contributors. Our decision-making process was heavily influenced by two primary factors: first, whether the update would enhance the collaborative ecosystem, and second, how it would improve the overall documentation experience. This focus reflects that our open source principles, applied to both content and infrastructure, are essential for fostering innovation, ensuring quality through peer review, and building a more engaged and empowered user community.</p><div><h2>Cloudflare developer documentation: A collaborative open source approach</h2><a href="#cloudflare-developer-documentation-a-collaborative-open-source-approach"></a></div><p>Cloudflare’s developer documentation is <a href="https://github.com/cloudflare/cloudflare-docs/"><u>open source on GitHub</u></a>, with content supporting all of Cloudflare’s products. The underlying documentation engine has gone through a few iterations, with the first version of the site released in 2020. That first version provided dev-friendly features such as dark mode and proper code syntax. </p><div><h3>2021 update: enhanced documentation engine</h3><a href="#2021-update-enhanced-documentation-engine"></a></div><p>In 2021, we introduced a new custom documentation engine, bringing significant improvements to the Cloudflare content experience. The benefits of the Gatsby to Hugo <a href="https://blog.cloudflare.com/new-dev-docs/"><u>migration</u></a> included:</p><ul><li><p><b>Faster development flow</b>: The development flow replicated production behavior, increasing iteration speed and confidence. <a href="https://developers.cloudflare.com/pages/configuration/preview-deployments/"><u>Preview links</u></a> via Cloudflare Pages were also introduced, so the content team and stakeholders could quickly review what content would look like in production.</p></li><li><p><b>Custom components</b>: Introduced features like <a href="https://github.com/cloudflare/cloudflare-docs/blob/4c3c819ebe3714df1698097135c645429bcbe7cc/layouts/shortcodes/resource-by-selector.html"><u>resources-by-selector</u></a> which let us reference content throughout the repository and gave us the flexibility to expand checks and automations.</p></li><li><p><b>Structured changelog management</b>: Implementation of <a href="https://github.com/cloudflare/cloudflare-docs/tree/4c3c819ebe3714df1698097135c645429bcbe7cc/data/changelogs"><u>structured YAML</u></a> changelog entries which facilitated sharing with various platforms like <a href="https://developers.cloudflare.com/changelog/index.xml"><u>RSS feeds</u></a>, <a href="http://discord.cloudflare.com"><u>Developer Discord</u></a>, and within the docs themselves.</p></li><li><p><b>Improved performance</b>: Significant page load time improvements with the migration to HTML-first and almost instantaneous local builds.</p></li></ul><p>These features were non-negotiable as part of our evaluation of whether to migrate. We knew that any update to the site had to maintain the functionality we’d established as core parts of the new experience.</p><div><h3>2024 update: Say “hello, world!” to our new developer documentation, powered by Astro</h3><a href="#2024-update-say-hello-world-to-our-new-developer-documentation-powered-by-astro"></a></div><p>After careful evaluation, we chose to migrate from Hugo to the <a href="https://astro.build/"><u>Astro</u></a> (and by extension, JavaScript) ecosystem. Astro fulfilled many items on our wishlist including:</p><ul><li><p><b>Enhanced content organization</b>: Improved tagging and better cross-referencing of  related pages.</p></li><li><p><b>Extensibility</b>: Support for user plugins like <a href="https://github.com/HiDeoo/starlight-image-zoom"><u>starlight-image-zoom</u></a> for lightbox functionality.</p></li><li><p><b>Development experience</b>: Type-checking at build time with <a href="https://docs.astro.build/en/reference/cli-reference/#astro-check"><u>astro check</u></a>, along with syntax highlighting, Intellisense, diagnostic messages, and plugins for ESLint, Stylelint, and Prettier. </p></li><li><p><b>JavaScript/TypeScript support</b>: Aligned the docs site framework with the preferred languages of many contributors, facilitating easier contribution.</p></li><li><p><b>CSS management</b>: Introduction of Tailwind and <a href="https://docs.astro.build/en/guides/styling/#scoped-styles"><u>scoped styles</u></a>.</p></li><li><p><a href="https://docs.astro.build/en/guides/content-collections/"><b><u>Content collections</u></b></a>: Offered various ways to manage and enhance tagging practices including Markdown front matter <a href="https://docs.astro.build/en/guides/content-collections/#defining-datatypes-with-zod"><u>validated by Zod schemas</u></a>, JSON schemas for <a href="https://docs.astro.build/en/guides/content-collections/#enabling-json-schema-generation"><u>Intellisense</u></a>, and a JavaScript callback for <a href="https://docs.astro.build/en/guides/content-collections/#filtering-collection-queries"><u>filtering returned entries</u></a>.</p></li></ul><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1wz2uWlAwbHFG4QgG0d8tt/4eeb3fbcd4d9b33c5590be39654bbff1/BLOG-2600_2.png"/></figure><p><a href="https://starlight.astro.build/"><u>Starlight</u></a>, Astro’s documentation theme, was a key factor in the decision. Its powerful <a href="https://starlight.astro.build/guides/overriding-components/"><u>component overrides</u></a> and <a href="https://starlight.astro.build/resources/plugins/"><u>plugins</u></a> system allowed us to leverage built-in components and base styling.</p><div><h3>How we migrated to Astro</h3><a href="#how-we-migrated-to-astro"></a></div><p>Content needed to be migrated quickly. With dozens of pull requests opened and merged each day, entering a code freeze for a week simply wasn’t feasible. This is where the nature of <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"><u>abstract syntax trees</u></a> (ASTs) came into play, only parsing the structure of a Markdown document rather than details like whitespace or indentation that would make a <a href="https://en.wikipedia.org/wiki/Regular_expression"><u>regular expression</u></a> approach tricky.</p><p>With Hugo in 2021, we configured code block functionality like titles or line highlights with front matter inside the code block.</p><pre><code>---title: index.jshighlight: 1---const foo = "bar";</code></pre><p>Starlight uses <a href="https://expressive-code.com/"><u>Expressive Code</u></a> for code blocks, and these options are now on the opening code fence.</p><pre><code>js title="index.js" &#123;1&#125;const foo = "bar";</code></pre><p>With <a href="https://www.npmjs.com/package/astray"><u>astray</u></a>, this is a simple as visiting the `code` nodes and:</p><ol><li><p>Parsing `node.value` with <a href="https://www.npmjs.com/package/front-matter"><u>front-matter</u></a>.</p></li><li><p>Assigning the attributes from `front-matter` to `node.meta`.</p></li><li><p>Replacing `node.value` with the rest of the code block.</p></li></ol><pre><code>import &#123; fromMarkdown &#125; from "mdast-util-from-markdown";import &#123; toMarkdown &#125; from "mdast-util-to-markdown"; <p>import * as astray from “astray”;<br>import type * as MDAST from “mdast”;<br>import fm from “front-matter”;</p><p>const markdown &#x3D; await Bun.file(“example.md”).text();</p><p>const AST &#x3D; fromMarkdown(markdown);</p><p>astray.walk&lt;MDAST.Root, void, any&gt;(AST, &amp;#123;<br>    code(node: MDAST.Code) &amp;#123;<br>        const &amp;#123; attributes, body &amp;#125; &#x3D; fm(node.value);<br>        const &amp;#123; title, highlight &amp;#125; &#x3D; attributes;</p><pre><code>    if (title) &amp;#123;        node.meta = `title=&quot;$&amp;#123;title&amp;#125;&quot;`;    &amp;#125;    if (highlight) &amp;#123;        node.meta += ` &amp;#123;$&amp;#123;highlight&amp;#125;&amp;#125;`;    &amp;#125;    node.value = body;    return;&amp;#125;</code></pre><p>&amp;#125;)<br></code></pre></p><div><h2>The migration in numbers</h2><a href="#the-migration-in-numbers"></a></div><p>When we <a href="https://blog.cloudflare.com/new-dev-docs/"><u>migrated from Gatsby to Hugo</u></a> in 2021, the <a href="https://github.com/cloudflare/cloudflare-docs/pull/3609/"><u>pull request</u></a> included 4,850 files and the migration took close to three weeks from planning to implementation. This time around, the migration was nearly twice as large, with 8,060 files changed. Our planning and migration took six weeks in total:</p><ul><li><p>10 days: Evaluate platforms, vendors, and features </p></li><li><p>14 days: Migrate the <a href="https://developers.cloudflare.com/style-guide/components/"><u>components</u></a> required by the documentation site</p></li><li><p>5 days: Staging and user acceptance testing (UAT) </p></li><li><p>8 hours: Code freeze and <a href="https://github.com/cloudflare/cloudflare-docs/pull/16096"><u>migrate to Astro/Starlight</u></a></p></li></ul><p>The migration resulted in removing a net -19,624 lines of code from our maintenance burden.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3r9Hj2NwU40GPLTw5TbGYG/d292b405c097ebd577173f5d61c17d03/BLOG-2600_3.png"/></figure><p>While the number of files had grown substantially since our last major migration, our strategy was very similar to the 2021 migration. We used <a href="https://github.com/syntax-tree/mdast"><u>Markdown AST</u></a> and astray, a utility to walk ASTs, created specifically for the previous migration!</p><div><h2>What we learned</h2><a href="#what-we-learned"></a></div><p>A website migration like our move to Astro/Starlight is a complex process that requires time to plan, review, and coordinate, and our preparation paid off! Including our <a href="https://community.cloudflare.com/t/2025-mvp-nominations/705496"><u>Cloudflare Community MVPs</u></a> as part of the planning and review period proved incredibly helpful. They provided great guidance and feedback as we planned for the migration. We only needed one day of code freeze, and there were no rollbacks or major incidents. Visitors to the site never experienced downtime, and overall the migration was a major success.</p><p>During testing, we ran into several use cases that warranted using <a href="https://docs.astro.build/en/reference/container-reference/"><u>experimental Astro APIs</u></a>. These APIs were always well documented, thanks to fantastic open source content from the Astro community. We were able to implement them quickly without impacting our release timeline.</p><p>We also ran into <a href="https://github.com/withastro/starlight/issues/2215"><u>an edge case</u></a> with build time performance due to the number of pages on our site (4000+). The Astro team was quick to triage the problem and begin investigation for a <a href="https://github.com/withastro/starlight/pull/2252"><u>permanent fix</u></a>. Their fast, helpful fixes made us truly grateful for the support from the Astro Discord server. A big thank you to the Astro/Starlight community!</p><div><h2>Contribute to developers.cloudflare.com!</h2><a href="#contribute-to-developers-cloudflare-com"></a></div><p>Migrating <a href="http://developers.cloudflare.com"><u>developers.cloudflare.com</u></a> to Astro/Starlight is just one example of the ways we prioritize world-class documentation and user experiences at Cloudflare. Our deep investment in documentation makes this a great place to work for technical writers, UX strategists, and many other content creators. Since adopting a <a href="https://blog.cloudflare.com/content-as-a-product/"><u>content like a product</u></a> strategy in 2021, we have evolved to better serve the open source community by focusing on inclusivity and transparency, which ultimately leads to happier Cloudflare users. </p><p>We invite everyone to connect with us and explore these exciting new updates. Feel free to <a href="https://github.com/cloudflare/cloudflare-docs/issues"><u>reach out</u></a> if you’d like to speak with someone on the content team or share feedback about our documentation. You can share your thoughts or submit a pull request directly on the cloudflare-docs <a href="https://github.com/cloudflare/cloudflare-docs"><u>repository</u></a> in GitHub.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Open source all the way down: Upgrading our developer documentation" href="https://blog.cloudflare.com/open-source-all-the-way-down-upgrading-our-developer-documentation/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Open source all the way down: Upgrading our developer documentation</span><span class="cap link fs12">https://blog.cloudflare.com/open-source-all-the-way-down-upgrading-our-developer-documentation/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Building LATAM&amp;#8217;s Future Tech Workforce With AI</title>
    <link href="https://blog.imc.re/RSSBOX/rss/868f80a5.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/868f80a5.html</id>
    <published>2025-01-07T08:34:05.000Z</published>
    <updated>2025-01-07T08:34:05.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><details><summary><strong>Read this post in Spanish</strong></summary><p>Estamos emocionados de celebrar el tercer año de Git Commit, nuestro programa anual dedicado a cerrar la brecha de habilidades tecnológicas y empoderar a estudiantes de todo el país. Este año, también nos enorgullece lanzar Git Commit 101, nuestro primer curso gratuito de IA en línea en español, disponible para estudiantes y educadores durante todo el año.</p><p><strong>¿Por qué Uruguay?</strong></p><p>Con una de las tasas más altas de conectividad a internet en América Latina (más del 70%), lidera la región en transformación digital y educación. Su compromiso con la innovación se refleja en su clasificación entre las cinco principales economías latinoamericanas en el Índice Global de Innovación, destacándose en producción de conocimiento y desarrollo de capital humano. </p><p>Programas como Git Commit prosperan en este entorno, alineándose perfectamente con la misión del país de construir una economía basada en el conocimiento y crear oportunidades para comunidades desfavorecidas.</p><p><strong>Presentamos Git Commit 101</strong></p><p>Este año, en colaboración con Microsoft AI for Good, lanzamos Git Commit 101, un curso gratuito de IA en línea transmitido en vivo desde el AI Co-Innovation Lab de Microsoft en Montevideo, el único laboratorio de este tipo en el hemisferio sur. El curso introduce a los estudiantes a los fundamentos de la IA, herramientas de GitHub y GitHub Copilot, brindándoles habilidades que pueden aplicar de inmediato. En sus primeras semanas, el curso en línea ya ha atraído a más de 20,000 espectadores.</p><p>Nuestro evento presencial de Git Commit se llevó a cabo en Centros Educativos Impulso y la Universidad ORT. Juntos recibimos a 125 estudiantes, muchos de ellos de contextos vulnerables, provenientes de 13 instituciones participantes. Los estudiantes escucharon a oradores inspiradores, incluyendo al Dr. Juan M. Lavista Ferres, Vicepresidente Corporativo y Científico Principal de Datos del AI for Good Lab de Microsoft; Alejandro Pazos, Gerente País de Microsoft en Uruguay; Eliane Elbaum, Gerente del AI Co-Innovation Lab de Microsoft; y Mario Rodriguez, Director de Producto de GitHub.</p><p>“Es muy importante que cada uno de ustedes reciba la mejor educación posible, porque es a través de la educación y la tecnología que vamos a abrir puertas. Es como, en última instancia, llegaremos al cielo,” compartió Rodriguez durante la ceremonia de clausura en el Laboratorio Tecnológico del LATU en Montevideo.</p><p><strong>El poder de la educación y la innovación</strong></p><p>Juntos, no solo estamos enseñando a los estudiantes cómo usar la tecnología, sino también empoderándolos para construir un futuro donde la innovación sea inclusiva, accesible y sostenible. Estamos emocionados de ver lo que harán los participantes de este año y esperamos con ansias Git Commit 2025.</p><p>Sigamos alcanzando el cielo, juntos. 🚀</p></details><hr/><p>We’re thrilled to celebrate the third year of <a href="https://github.blog/news-insights/company-news/empowering-uruguays-future-workforce-with-ai/">Git Commit</a>, our annual program dedicated to bridging the tech skills gap and empowering students across the country. This year, we’re also proud to launch Git Commit 101, our first free online AI course in Spanish, available to students and educators year-round.</p><h2 id="why-uruguay">Why Uruguay<a aria-label="Why Uruguay" class="heading-link pl-2 text-italic text-bold" href="#why-uruguay"></a></h2><p>With one of the highest rates of <a href="https://data.worldbank.org/indicator/IT.NET.USER.ZS?locations=UY">internet connectivity in Latin America (over 70%),</a> Uruguay leads the region in digital transformation and education. Its commitment to fostering innovation is reflected in its top-five ranking in the <a href="https://www.wipo.int/gii-ranking/en/uruguay">Global Innovation Index</a> among Latin American economies, excelling in knowledge outputs and human capital development.</p><p>Programs like Git Commit thrive in this environment, aligning perfectly with the nation’s mission to build a knowledge-based economy and create opportunities for underserved communities.</p><h2 id="introducing-git-commit-101">Introducing Git Commit 101<a aria-label="Introducing Git Commit 101" class="heading-link pl-2 text-italic text-bold" href="#introducing-git-commit-101"></a></h2><p>This year, in partnership with <a href="https://www.microsoft.com/en-us/research/group/ai-for-good-research-lab/">Microsoft AI for Good</a>, we launched Git commit 101, a free online AI course streamed live from Microsoft’s AI Co-Innovation Lab in Montevideo—the only lab of its kind in the Southern Hemisphere. The course introduces students to AI fundamentals, GitHub tools, and GitHub Copilot, equipping them with skills they can apply immediately. The online course has already attracted more than 20,000 viewers in its first few weeks.</p><p>Our in-person Git Commit event was held at Centros Educativos Impulso and ORT University. Together we hosted 125 students, many from vulnerable backgrounds, from 13 participating institutions. Students heard from inspiring speakers including Dr. Juan M. Lavista Ferres, Corporate Vice President and Chief Data Scientist of the AI for Good Lab at Microsoft, Alejandro Pazos, Microsoft’s Country Manager in Uruguay, Eliane Elbaum, Manager of the Microsoft AI Co-Innovation Lab, and Mario Rodriguez, GitHub’s Chief Product Officer.</p><p>“It’s very important that each of you receive the best education possible, because it’s through education and technology that we’re going to open doors. It’s how we’ll ultimately reach for the sky,” Rodriguez shared during the closing ceremony at the LATU Technology Laboratory in Montevideo.</p><figure class="wp-caption aligncenter mx-0" id="attachment_81835"><img><img alt="A Mona the octocat plushie perched on a stair railing, with a large group of people softly visible in the background." class="width-fit size-large wp-image-81835 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="965" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2025/01/mona-uruguay.png?w=1024&amp;resize=1600%2C965" width="1600"/></img><figcaption class="text-mono color-fg-muted mt-14px f5-mktg">Closing ceremony at the LATU Uruguayan Laboratory of Technology, where we hosted more than 300 guests.</figcaption></figure><h2 id="the-power-of-education-and-innovation">The power of education and innovation<a aria-label="The power of education and innovation" class="heading-link pl-2 text-italic text-bold" href="#the-power-of-education-and-innovation"></a></h2><p>Together, we’re not only teaching students how to use technology, but also empowering them to build a future where innovation is inclusive, accessible, and sustainable. We’re excited to see what this year’s participants go on to do, and look forward to Git Commit 2025.</p><p>Let’s continue to reach for the sky—together. 🚀</p></body></html><p>The post <a href="https://github.blog/developer-skills/github-education/building-latams-future-tech-workforce-with-ai/">Building LATAM’s future tech workforce with AI</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Building LATAM&#8217;s future tech workforce with AI" href="https://github.blog/developer-skills/github-education/building-latams-future-tech-workforce-with-ai/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Building LATAM&#8217;s future tech workforce with AI</span><span class="cap link fs12">https://github.blog/developer-skills/github-education/building-latams-future-tech-workforce-with-ai/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>Multi-Path TCP: Revolutionizing Connectivity, One Path at a Time</title>
    <link href="https://blog.imc.re/RSSBOX/rss/cd5286a9.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/cd5286a9.html</id>
    <published>2025-01-03T14:00:00.000Z</published>
    <updated>2025-01-03T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p></p><p>The Internet is designed to provide multiple paths between two endpoints. Attempts to exploit multi-path opportunities are almost as old as the Internet, culminating in <a href="https://datatracker.ietf.org/doc/html/rfc2991"><u>RFCs</u></a> documenting some of the challenges. Still, today, virtually all end-to-end communication uses only one available path at a time. Why? It turns out that in multi-path setups, even the smallest differences between paths can harm the connection quality due to <a href="https://en.wikipedia.org/wiki/Equal-cost_multi-path_routing#History"><u>packet reordering</u></a> and other issues. As a result, Internet devices usually use a single path and let the routers handle the path selection.</p><p>There is another way. Enter Multi-Path TCP (MPTCP), which exploits the presence of multiple interfaces on a device, such as a mobile phone that has both Wi-Fi and cellular antennas, to achieve multi-path connectivity.</p><p>MPTCP has had a long history — see the <a href="https://en.wikipedia.org/wiki/Multipath_TCP"><u>Wikipedia article</u></a> and the <a href="https://datatracker.ietf.org/doc/html/rfc8684"><u>spec (RFC 8684)</u></a> for details. It's a major extension to the TCP protocol, and historically most of the TCP changes failed to gain traction. However, MPTCP is supposed to be mostly an operating system feature, making it easy to enable. Applications should only need minor code changes to support it.</p><p>There is a caveat, however: MPTCP is still fairly immature, and while it can use multiple paths, giving it superpowers over regular TCP, it's not always strictly better than it. Whether MPTCP should be used over TCP is really a case-by-case basis.</p><p>In this blog post we show how to set up MPTCP to find out.</p><div><h2>Subflows</h2><a href="#subflows"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3r8AP5BHbvtYEtXmYSXFwO/36e95cbac93cdecf2f5ee65945abf0b3/Screenshot_2024-12-23_at_3.07.37_PM.png"/></figure><p>Internally, MPTCP extends TCP by introducing "subflows". When everything is working, a single TCP connection can be backed by multiple MPTCP subflows, each using different paths. This is a big deal - a single TCP byte stream is now no longer identified by a single 5-tuple. On Linux you can see the subflows with <code>ss -M</code>, like:</p><pre><code>marek$ ss -tMn dport = :443 | cattcp   ESTAB 0      0 192.168.2.143%enx2800af081bee:57756 104.28.152.1:443tcp   ESTAB 0      0       192.168.1.149%wlp0s20f3:44719 104.28.152.1:443mptcp ESTAB 0      0                 192.168.2.143:57756 104.28.152.1:443</code></pre><p>Here you can see a single MPTCP connection, composed of two underlying TCP flows.</p><div><h2>MPTCP aspirations</h2><a href="#mptcp-aspirations"></a></div><p>Being able to separate the lifetime of a connection from the lifetime of a flow allows MPTCP to address two problems present in classical TCP: aggregation and mobility.</p><ul><li><p><b>Aggregation</b>: MPTCP can aggregate the bandwidth of many network interfaces. For example, in a data center scenario, it's common to use interface bonding. A single flow can make use of just one physical interface. MPTCP, by being able to launch many subflows, can expose greater overall bandwidth. I'm personally not convinced if this is a real problem. As we'll learn below, modern Linux has a <a href="https://dl.ifip.org/db/conf/networking/networking2016/1570234725.pdf"><u>BLESS-like MPTCP scheduler</u></a> and macOS stack has the "aggregation" mode, so aggregation should work, but I'm not sure how practical it is. However, there are <a href="https://www.openmptcprouter.com/"><u>certainly projects that are trying to do link aggregation</u></a> using MPTCP.</p></li><li><p><b>Mobility</b>: On a customer device, a TCP stream is typically broken if the underlying network interface goes away. This is not an uncommon occurrence — consider a smartphone dropping from Wi-Fi to cellular. MPTCP can fix this — it can create and destroy many subflows over the lifetime of a single connection and survive multiple network changes.</p></li></ul><p>Improving reliability for mobile clients is a big deal. While some software can use QUIC, which also works on <a href="https://www.ietf.org/archive/id/draft-ietf-quic-multipath-11.html"><u>Multipath Extensions</u></a>, a large number of classical services still use TCP. A great example is SSH: it would be very nice if you could walk around with a laptop and keep an SSH session open and switch Wi-Fi networks seamlessly, without breaking the connection.</p><p>MPTCP work was initially driven by <a href="https://uclouvain.be/fr/index.html"><u>UCLouvain in Belgium</u></a>. The first serious adoption was on the iPhone. Apparently, users have a tendency to use Siri while they are walking out of their home. It's very common to lose Wi-Fi connectivity while they are doing this. (<a href="https://youtu.be/BucQ1lfbtd4?t=533"><u>source</u></a>) </p><div><h2>Implementations</h2><a href="#implementations"></a></div><p>Currently, there are only two major MPTCP implementations — Linux kernel support from v5.6, but realistically you need at least kernel v6.1 (<a href="https://oracle.github.io/kconfigs/?config=UTS_RELEASE&amp;config=MPTCP"><u>MPTCP is not supported on Android</u></a> yet) and iOS from version 7 / Mac OS X from 10.10.</p><p>Typically, Linux is used on the server side, and iOS/macOS as the client. It's possible to get Linux to work as a client-side, but it's not straightforward, as we'll learn soon. Beware — there is plenty of outdated Linux MPTCP documentation. The code has had a bumpy history and at least two different APIs were proposed. See the Linux kernel source for <a href="https://docs.kernel.org/networking/mptcp.html"><u>the mainline API</u></a> and the <a href="https://www.mptcp.dev/"><u>mptcp.dev</u></a> website.</p><div><h2>Linux as a server</h2><a href="#linux-as-a-server"></a></div><p>Conceptually, the MPTCP design is pretty sensible. After the initial TCP handshake, each peer may announce additional addresses (and ports) on which it can be reached. There are two ways of doing this. First, in the handshake TCP packet each peer specifies the "<i>Do not attempt to establish new subflows to this address and port</i>" bit, also known as bit [C], in the MPTCP TCP extensions header.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/bT8oz3wxpw7alftvdYg5n/b7614a4d10b6c81e18027f6785391ede/BLOG-2637_3.png"/></figure><p><sup><i>Wireshark dissecting MPTCP flags from a SYN packet. </i></sup><a href="https://github.com/multipath-tcp/mptcp_net-next/issues/535"><sup><i><u>Tcpdump does not report</u></i></sup></a><sup><i> this flag yet.</i></sup></p><p>With this bit cleared, the other peer is free to assume the two-tuple is fine to be reconnected to. Typically, the <b>server allows</b> the client to reuse the server IP/port address. Usually, the <b>client is not listening</b> and disallows the server to connect back to it. There are caveats though. For example, in the context of Cloudflare, where our servers are using Anycast addressing, reconnecting to the server IP/port won't work. Going twice to the IP/port pair is unlikely to reach the same server. For us it makes sense to set this flag, disallowing clients from reconnecting to our server addresses. This can be done on Linux with:</p><pre><code># Linux server sysctl - useful for ECMP or Anycast servers$ sysctl -w net.mptcp.allow_join_initial_addr_port=0</code></pre><p>There is also a second way to advertise a listening IP/port. During the lifetime of a connection, a peer can send an ADD-ADDR MPTCP signal which advertises a listening IP/port. This can be managed on Linux by <code>ip mptcp endpoint ... signal</code>, like:</p><pre><code># Linux server - extra listening address$ ip mptcp endpoint add 192.51.100.1 dev eth0 port 4321 signal</code></pre><p>With such a config, a Linux peer (typically server) will report the additional IP/port with ADD-ADDR MPTCP signal in an ACK packet, like this:</p><pre><code>host &gt; host: Flags [.], ack 1, win 8, options [mptcp 30 add-addr v1 id 1 192.51.100.1:4321 hmac 0x...,nop,nop], length 0</code></pre><p>It's important to realize that either peer can send ADD-ADDR messages. Unusual as it might sound, it's totally fine for the client to advertise extra listening addresses. The most common scenario though, consists of either nobody, or just a server, sending ADD-ADDR.</p><p>Technically, to launch an MPTCP socket on Linux, you just need to replace IPPROTO_TCP with IPPROTO_MPTCP in the application code:</p><pre><code>IPPROTO_MPTCP = 262sd = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP)</code></pre><p>In practice, though, this introduces some changes to the sockets API. Currently not all setsockopt's work yet — like <code>TCP_USER_TIMEOUT</code>. Additionally, at this stage, MPTCP is incompatible with kTLS.</p><div><h2>Path manager / scheduler</h2><a href="#path-manager-scheduler"></a></div><p>Once the peers have exchanged the address information, MPTCP is ready to kick in and perform the magic. There are two independent pieces of logic that MPTCP handles. First, given the address information, MPTCP must figure out if it should establish additional subflows. The component that decides on this is called "Path Manager". Then, another component called "scheduler" is responsible for choosing a specific subflow to transmit the data over.</p><p>Both peers have a path manager, but typically only the client uses it. A path manager has a hard task to launch enough subflows to get the benefits, but not too many subflows which could waste resources. This is where the MPTCP stacks get complicated. </p><div><h2>Linux as client</h2><a href="#linux-as-client"></a></div><p>On Linux, path manager is an operating system feature, not an application feature. The in-kernel path manager requires some configuration — it must know which IP addresses and interfaces are okay to start new subflows. This is configured with <code>ip mptcp endpoint ... subflow</code>, like:</p><pre><code>$ ip mptcp endpoint add dev wlp1s0 192.0.2.3 subflow  # Linux client</code></pre><p>This informs the path manager that we (typically a client) own a 192.0.2.3 IP address on interface wlp1s0, and that it's fine to use it as source of a new subflow. There are two additional flags that can be passed here: "backup" and "fullmesh". Maintaining these <code>ip mptcp endpoints</code> on a client is annoying. They need to be added and removed every time networks change. Fortunately, <a href="https://ubuntu.com/core/docs/networkmanager"><u>NetworkManager</u></a> from 1.40 supports managing these by default. If you want to customize the "backup" or "fullmesh" flags, you can do this here (see <a href="https://networkmanager.dev/docs/api/1.44.4/settings-connection.html#:~:text=mptcp-flags"><u>the documentation</u></a>):</p><pre><code>ubuntu$ cat /etc/NetworkManager/conf.d/95-mptcp.conf# set "subflow" on all managed "ip mptcp endpoints". 0x22 is the default.[connection]connection.mptcp-flags=0x22</code></pre><p>Path manager also takes a "limit" setting, to set a cap of additional subflows per MPTCP connection, and limit the received ADD-ADDR messages, like: </p><pre><code>$ ip mptcp limits set subflow 4 add_addr_accepted 2  # Linux client</code></pre><p>I experimented with the "mobility" use case on my Ubuntu 22 Linux laptop. I repeatedly enabled and disabled Wi-Fi and Ethernet. On new kernels (v6.12), it works, and I was able to hold a reliable MPTCP connection over many interface changes. I was <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/534"><u>less lucky with the Ubuntu v6.8</u></a> kernel. Unfortunately, the <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/536"><u>default path manager on Linux</u></a> client only works when the flag "<i>Do not attempt to establish new subflows to this address and port</i>" is cleared on the server. Server-announced ADD-ADDR don't result in new subflows created, unless <code>ip mptcp endpoint</code> has a <code>fullmesh</code> flag.</p><p>It feels like the underlying MPTCP transport code works, but the path manager requires a bit more intelligence. With a new kernel, it's possible to get the "interactive" case working out of the box, but not for the ADD-ADDR case. </p><div><h2>Custom path manager</h2><a href="#custom-path-manager"></a></div><p>Linux allows for two implementations of a path manager component. It can either use built-in kernel implementation (default), or userspace netlink daemon.</p><pre><code>$ sysctl -w net.mptcp.pm_type=1 # use userspace path manager</code></pre><p>However, from what I found there is no serious implementation of configurable userspace path manager. The existing <a href="https://github.com/multipath-tcp/mptcpd/blob/main/plugins/path_managers/sspi.c"><u>implementations don't do much</u></a>, and the API <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/533"><u>seems</u></a> <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/532"><u>immature</u></a> yet.</p><div><h2>Scheduler and BPF extensions</h2><a href="#scheduler-and-bpf-extensions"></a></div><p>Thus far we've covered Path Manager, but what about the scheduler that chooses which link to actually use? It seems that on Linux there is only one built-in "default" scheduler, and it can do basic failover on packet loss. The developers want to write <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/75"><u>MPTCP schedulers in BPF</u></a>, and this work is in-progress.</p><div><h2>macOS</h2><a href="#macos"></a></div><p>As opposed to Linux, macOS and iOS expose a raw MPTCP API. On those operating systems, path manager is not handled by the kernel, but instead can be an application responsibility. The exposed low-level API is based on <code>connectx()</code>. For example, <a href="https://github.com/apple-oss-distributions/network_cmds/blob/97bfa5b71464f1286b51104ba3e60db78cd832c9/mptcp_client/mptcp_client.c#L461"><u>here's an example of obscure code</u></a> that establishes one connection with two subflows:</p><pre><code>int sock = socket(AF_MULTIPATH, SOCK_STREAM, 0);connectx(sock, ..., &amp;cid1);connectx(sock, ..., &amp;cid2);</code></pre><p>This powerful API is hard to use though, as it would require every application to listen for network changes. Fortunately, macOS and iOS also expose higher-level APIs. One <a href="https://github.com/mptcp-apps/mptcp-hello/blob/main/c/macOS/main.c"><u>example is nw_connection</u></a> in C, which uses nw_parameters_set_multipath_service.</p><p>Another, more common example is using <code>Network.framework</code>, and would <a href="https://gist.github.com/majek/cb54b537c74506164d2a7fa2d6601491"><u>look like this</u></a>:</p><pre><code>let parameters = NWParameters.tcpparameters.multipathServiceType = .interactivelet connection = NWConnection(host: host, port: port, using: parameters) </code></pre><p>The API supports three MPTCP service type modes:</p><ul><li><p><i>Handover Mode</i>: Tries to minimize cellular. Uses only Wi-Fi. Uses cellular only when <a href="https://support.apple.com/en-us/102228"><u>Wi-Fi Assist</u></a> is enabled and makes such a decision.</p></li><li><p><i>Interactive Mode</i>: Used for Siri. Reduces latency. Only for low-bandwidth flows.</p></li><li><p><i>Aggregation Mode</i>: Enables resource pooling but it's only available for developer accounts and not deployable.</p></li></ul><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/47MukOs6bhCMOkO1JL15sP/7dd75417b855b681bde504122d5af01e/Screenshot_2024-12-23_at_2.59.51_PM.png"/></figure><p>The MPTCP API is nicely integrated with the <a href="https://support.apple.com/en-us/102228"><u>iPhone "Wi-Fi Assist" feature</u></a>. While the official documentation is lacking, it's possible to find <a href="https://youtu.be/BucQ1lfbtd4?t=533"><u>sources explaining</u></a> how it actually works. I was able to successfully test both the cleared "<i>Do not attempt to establish new subflows"</i> bit and ADD-ADDR scenarios. Hurray!</p><div><h2>IPv6 caveat</h2><a href="#ipv6-caveat"></a></div><p>Sadly, MPTCP IPv6 has a caveat. Since IPv6 addresses are long, and MPTCP uses the space-constrained TCP Extensions field, there is <a href="https://github.com/multipath-tcp/mptcp_net-next/issues/448"><u>not enough room for ADD-ADDR messages</u></a> if TCP timestamps are enabled. If you want to use MPTCP and IPv6, it's something to consider.</p><div><h2>Summary</h2><a href="#summary"></a></div><p>I find MPTCP very exciting, being one of a few deployable serious TCP extensions. However, current implementations are limited. My experimentation showed that the only practical scenario where currently MPTCP might be useful is:</p><ul><li><p>Linux as a server</p></li><li><p>macOS/iOS as a client</p></li><li><p>"interactive" use case</p></li></ul><p>With a bit of effort, Linux can be made to work as a client.</p><p>Don't get me wrong, <a href="https://netdevconf.info/0x14/pub/slides/59/mptcp-netdev0x14-final.pdf"><u>Linux developers did tremendous work</u></a> to get where we are, but, in my opinion for any serious out-of-the-box use case, we're not there yet. I'm optimistic that Linux can develop a good MPTCP client story relatively soon, and the possibility of implementing the Path manager and Scheduler in BPF is really enticing. </p><p>Time will tell if MPTCP succeeds — it's been 15 years in the making. In the meantime, <a href="https://datatracker.ietf.org/meeting/121/materials/slides-121-quic-multipath-quic-00"><u>Multi-Path QUIC</u></a> is under active development, but it's even further from being usable at this stage.</p><p>We're not quite sure if it makes sense for Cloudflare to support MPTCP. <a href="https://community.cloudflare.com/c/feedback/feature-request/30"><u>Reach out</u></a> if you have a use case in mind!</p><p><i>Shoutout to </i><a href="https://fosstodon.org/@matttbe"><i><u>Matthieu Baerts</u></i></a><i> for tremendous help with this blog post.</i></p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Multi-Path TCP: revolutionizing connectivity, one path at a time" href="https://blog.cloudflare.com/multi-path-tcp-revolutionizing-connectivity-one-path-at-a-time/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Multi-Path TCP: revolutionizing connectivity, one path at a time</span><span class="cap link fs12">https://blog.cloudflare.com/multi-path-tcp-revolutionizing-connectivity-one-path-at-a-time/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Behind the Scenes With Stream Live, Cloudflare’s Live Streaming Service</title>
    <link href="https://blog.imc.re/RSSBOX/rss/101c747.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/101c747.html</id>
    <published>2025-01-02T14:00:00.000Z</published>
    <updated>2025-01-02T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>Cloudflare announced Stream Live for open beta <a href="https://blog.cloudflare.com/stream-live"><u>in 2021</u></a>, and <a href="https://blog.cloudflare.com/stream-live-ga"><u>in 2022</u></a> we went GA. While we talked about the experience of using it and the value it delivers to customers, we didn’t talk about how we built it. So let’s talk about Stream Live’s design, and how it leverages the distributed nature of Cloudflare’s network, rather than centralized locations as many other live services do. Ultimately, our goals are to keep our content ingest as close to broadcasters as possible, our content delivery as close to viewers as possible, and to retain our ability to handle unexpected use cases.</p><p>At a high level, Stream Live accepts audio/video content from broadcasters and makes that content available to viewers around the world in real time through the <a href="https://www.cloudflare.com/network/"><u>Cloudflare network</u></a>, which reaches more than 330 cities in over 120 countries. Hence, there are two sides to this: ingesting data from broadcasters and delivering encoded content to viewers. Both sides are built on a combination of internal systems and Cloudflare products, including <a href="https://www.cloudflare.com/developer-platform/products/workers/"><u>Cloudflare Workers</u></a>, <a href="https://www.cloudflare.com/developer-platform/products/durable-objects/"><u>Durable Objects</u></a>, <a href="https://www.cloudflare.com/application-services/products/cloudflare-spectrum/"><u>Spectrum</u></a>, and, of course, <a href="https://developers.cloudflare.com/cache/"><u>Cache</u></a>.</p><p>Let’s start on the ingest side.</p><div><h3>Ingesting a broadcast</h3><a href="#ingesting-a-broadcast"></a></div><p>Broadcasters generate content in real time, as a series of video and audio frames, and it needs to be transmitted to Cloudflare over the Internet. To communicate with us, they choose a protocol such as <a href="https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol"><u>RTMPS</u></a> (Real Time Messaging Protocol Secure), <a href="https://www.ietf.org/archive/id/draft-sharabayko-srt-01.txt"><u>SRT</u></a> (Secure Reliable Transport), or <a href="https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html"><u>WHIP</u></a> (WebRTC-HTTP ingestion protocol) that defines how their content is packaged and transmitted. Each of these protocols is a way to transmit audio and video frames with various tradeoffs.</p><p>Regardless of the chosen protocol, the ingest lifecycle looks fairly similar. Broadcasters connect to an <a href="https://www.cloudflare.com/learning/cdn/glossary/anycast-network/"><u>Anycast</u></a> IP address using either a <a href="https://developers.cloudflare.com/stream/stream-live/custom-domains/"><u>custom ingest domain</u></a> or our default <code>live.cloudflare.com</code>. Both options direct to an IP address advertised from every Cloudflare data center around the world, minimizing the latency for broadcasters (both big and small) to our ingest points.</p><p>When the media content arrives at the Cloudflare server servicing the connection, it is first handled by a <a href="https://www.cloudflare.com/application-services/products/cloudflare-spectrum/"><u>Spectrum application</u></a>. Spectrum saved us time by implementing TLS termination for RTMPS, blocking potential <a href="https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/"><u>DDOS attacks</u></a>, and a few other protocol-specific benefits, such as our ability to support SRT broadcasters whose clients don't support the <a href="https://github.com/Haivision/srt/blob/bcc2f21ec75fcb10a8185857f3bc323bb19619da/docs/features/access-control.md"><u>Stream ID</u></a> portion of the SRT protocol. Those broadcasters assume their connection can be fully identified by connecting to a specific port, which was a challenge for our multitenant service. We use Spectrum to expose many listening ports to specific broadcasters which get wrapped up in <a href="https://developers.cloudflare.com/spectrum/reference/simple-proxy-protocol-header/"><u>Simple Proxy Protocol</u></a> and sent to one ingest service port. This is important, as our SRT implementation spends a non-trivial amount of CPU for each listening port, whereas Spectrum spends effectively nothing. In any case, Spectrum forwards all connections to the ingest service running on the same server.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Hgz9WilQMf7hiIWgWvzgN/35c46350835d1e9c6d219f1ca2507abf/image3.png"/></figure><p>Our ingest service handles receiving content from broadcasters, forwarding to <a href="https://developers.cloudflare.com/stream/stream-live/simulcasting/"><u>live outputs</u></a>, and recording for HLS/DASH viewing. The ingest service is written in Go and acts on configuration and broadcast state stored in our Live Config <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Objects</u></a>. One Durable Object instance represents one live input; it contains both the customer configuration and the ongoing state of each broadcast.</p><p>We chose Durable Objects over a centralized database since they are not coupled to any specific data center, allowing them to be closer to each of our geographically distributed broadcasters while remaining highly available. In terms of customer configuration, we use Durable Objects to store everything defined <a href="https://developers.cloudflare.com/api/operations/stream-live-inputs-create-a-live-input#request-body"><u>when creating</u></a> or <a href="https://developers.cloudflare.com/api/operations/stream-live-inputs-create-a-new-output,-connected-to-a-live-input"><u>modifying the live input</u></a>.</p><p>We store the canonical state of the broadcast in the Durable Object. That includes timestamp metadata for keeping times monotonic, connection status, and which ingest service instance owns the broadcast. Any content received by the ingest service needs to be acknowledged and indexed by the Durable Object before it is made available to viewers. This splits our state into two types, ‘volatile’ and ‘committed’. Volatile state is content the ingest has received but not yet told the Durable Object about. Committed state is content the Durable Object has acknowledged and is used as a sync point for any other ingest service instance in the event they claim ownership of the broadcast.</p><p>This split between volatile and committed states is how we support broadcasters resuming a live broadcast after disconnecting and reconnecting for whatever reason, including a broadcaster network blip. That’s normally a relatively easy problem when you have centralized ingestion and state storage. Since broadcasters connect to an arbitrary server due to Anycast, we needed to get more creative in making sure that whichever server receives the reconnect has the data to continue the broadcast.</p><p>The ingest service itself is written as a relay, taking packets from one input stream and mapping them to multiple output streams. At the top level, the relay is implemented as two coupled ‘for’ loops that communicate over a Go channel, one for sending and one for receiving. When we receive data, we internally normalize it depending on the protocol. For example, some protocols send video packets as delimiter-based (<a href="https://gist.github.com/XueshiQiao/d68bea4a5406dd648664ce66933aeed9"><u>annex B h264 NALU</u></a>), but other protocols or file formats expect length-prefixed packets (<a href="https://gist.github.com/XueshiQiao/d68bea4a5406dd648664ce66933aeed9"><u>avcc h264 NALU</u></a>).</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/903kTMKMnnHwms0EL9FNn/62e77098d23fa863c5ec1088367b4f43/image5.png"/></figure><p>A special case of relay outputs is our Live Playback and Recording functionality. When this is enabled, we copy and sanitize the incoming packets. Specifically, we issue monotonically increasing timestamps, which solves many issues we’ve encountered with various customer encoders. To ensure everything is aligned, we drop severely misaligned audio/video blocks, something typically seen at the start of broadcasts. Those sanitized packets are packaged into fragmented <a href="https://en.wikipedia.org/wiki/MP4_file_format"><u>MP4s</u></a> on keyframe boundaries.  We call those fragmented MP4s ‘original segments.’ Our ingest service stores the original segments in <a href="https://developers.cloudflare.com/r2/"><u>R2</u></a> and lets the live config Durable Object know the segment exists and how long it is.</p><p>These original segments are considered the canonical copy of the content a customer has uploaded to us, and are reused when transitioning from live to on-demand. Since these are required to serve live viewers, this is why we don’t currently provide an option to decouple live playback from recording. Supporting live playback automatically implements on-demand recording, with some state management overhead.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5GLIyr66cFtbd4jajXYrE0/d098b1347a45e287e2c5ef03fffb264b/image4.png"/></figure><div><h3>Viewing the broadcast</h3><a href="#viewing-the-broadcast"></a></div><p>At this point, we’ve ingested the content, cleaned it up, and durably stored it. Lets talk about how viewers watch this content.</p><p>Most online video is delivered in short 'segments’, multi-second chunks of content. Splitting the output allows content to be progressively emitted and is very cache-friendly. The protocols viewers use to request that content are typically <a href="https://datatracker.ietf.org/doc/html/rfc8216"><u>HLS (HTTP Live Streaming)</u></a> or <a href="https://www.mpeg.org/standards/MPEG-DASH/"><u>MPEG-DASH (Dynamic Adaptive Streaming over HTTP)</u></a>. <a href="https://www.ietf.org/archive/id/draft-murillo-whep-03.txt"><u>WHEP</u></a> (WebRTC-HTTP Egress Protocol) is a non-segmented viewing method available for real-time viewing in some cases. However, we’ll focus here on playback using segmented content with HLS or DASH, since that’s most of Stream Live’s usage today.</p><p>To start viewing, a video player will request an HLS or DASH playlist which describes the attributes of the media content and acts as an index for each segment. The playlist tells us which segments map to what point of the video’s timeline. Those segments are inserted into a playback buffer to be decoded and displayed by a client’s player. Examples here will use HLS, which is a newline delimited format. The typical alternative is DASH, which is XML based.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/43zIdjDFagc4w8HgHNYBPD/1447cb964d9eace73711b31a5f963656/image6.png"/></figure><p>First, ‘primary’ playlists describe which renditions of the same content are available, as well as where to get their specific index files. Those renditions can vary in bitrate, codec, framerate, resolution, etc. If you’ve ever picked ‘1080p’ from a video player quality menu, the player knew those qualities were available using this or similar methods. When selecting quality automatically, players choose the best rendition for the viewing machine’s capabilities (such as the ability to decode a certain codec) and network constraints. We use an internal representation of tracks (what kind of content, i.e. video), renditions (content parameters, i.e. 1080p), and muxings (where to find that content, i.e. in R2 bucket N or OTFE with call M) to generate both HLS and DASH, as the two formats contain nearly the same data, except organized differently. Here’s a simplified example of a ‘multi-variant’ or ‘primary’ HLS playlist that Stream generated. It includes some annotations to explain the components.</p><pre><code>#EXTM3U#EXT-X-VERSION:6#EXT-X-INDEPENDENT-SEGMENTS#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_audio",NAME="original",LANGUAGE="en-0a76e0ad",DEFAULT=YES,AUTOSELECT=YES,URI="stream_2.m3u8" &lt;- Audio track description + URL path...#EXT-X-STREAM-INF:RESOLUTION=426x240,CODECS="avc1.42c015,mp4a.40.2",BANDWIDTH=149084,AVERAGE-BANDWIDTH=145135,SCORE=1.0,FRAME-RATE=30.000,AUDIO="group_audio" &lt;- description of variant contentsstream_1.m3u8 &lt;- URL path to fetch variant</code></pre><p>Second, ‘variant’ or ‘stream’ playlists contain a list of segments that can be downloaded and viewed for each rendition. These are used for both live and on-demand viewing. The difference is on-demand playlists contain a flag indicating no more content will be added to the index whereas live omits that flag to allow it to append content in future requests. As a result, you’ll see video players download <a href="https://en.wikipedia.org/wiki/M3U#M3U8"><u>M3U8</u></a> (HLS) or <a href="https://ottverse.com/structure-of-an-mpeg-dash-mpd/"><u>MPD</u></a> (DASH) files approximately every 1–10 seconds when viewing a broadcast, looking for updated content.</p><pre><code>#EXTM3U#EXT-X-VERSION:6#EXT-X-MEDIA-SEQUENCE:89281 &lt;- Indicates position of sliding window#EXT-X-TARGETDURATION:6#EXT-X-MAP:URI=".../init.mp4" &lt;- Initialization data#EXTINF:4.000, &lt;- How long the segment.../seg_89281.mp4 &lt;- Location of a segment#EXTINF:4.000,.../seg_89282.mp4#EXTINF:4.000,.../seg_89283.mp4</code></pre><p>To serve all requests from viewers, we use a <a href="https://workers.cloudflare.com/"><u>Cloudflare Worker</u></a> called ‘delivery-worker’. It handles all requests for Stream content, and had its first commit in 2017, making it one of the earliest production-facing workers at Cloudflare. Since it's a worker that executes as close to a viewer as possible, it frees us up to spend more time on content and metadata performance rather than where our logic runs. It delivers content, renders playlists, and performs a variety of other functions. For rendering playlists, the worker transforms the broadcast state from the durable object, as mentioned earlier.</p><p>When clients ask for the encoded media content the playlist advertised to them, delivery-worker will send a subrequest to our OTFE (on-the-fly-encoder) service that transits the Cloudflare network. That request describes the format of content requested, i.e. the video stream of segment 89282 at a 1280x720 resolution encoded using AVC (aka H.264) capped CRF with some specified <a href="https://blog.cloudflare.com/making-video-intuitive-an-explainer/"><u>bitrate cap</u></a>. Then, OTFE will encode the original segment to output the specified configuration.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2PNSBVrMZz3rgiQqzzQcHp/56cd69bc8b64034673d4f15c9e461a1f/image7.png"/></figure><p>On-the-fly encoding is more efficient than always-encoding, which is the approach most other platforms take. If there are no viewers watching a specific quality level, or watching the broadcast at all, then we aren’t encoding it. That saves power, CPU time, RAM, network, and cache space. Doing nothing is always more efficient than doing something. This applies to a variety of customer use cases, since not all broadcasts have many viewers widely distributed across a range of connection qualities. For one case, consider when serving live broadcasts that are primarily viewed on high quality connections — encoding 240p or 360p variants would probably go to waste most of the time. For a more extreme case, there are situations where you definitely want recording enabled for live content, but viewing is an exceptional situation, such as for security cameras or dashcams. Of course, we have many customers that have active viewership for their broadcasts and this architecture allows us to serve both use cases.</p><p>On-the-fly encoding has a tradeoff: it is hard to implement for “media-correctness” and performance reasons. Media-correctness is important to ensuring smooth playback; individual segments need to have exactly the right start time and duration, or you get stuttering playback, audio/video desync, or entirely unwatchable content. Perfecting our media output requires fine-tuning our encoding, deep-diving into specs, and adjusting fragmented MP4s — especially since most encoders aren’t designed for per-segment encoding. For performance, we hide encoding delay by aggressively prefetching segments from delivery-worker. When a viewer initiates a request for Segment N, we initiate encoding of segment N+1. Since that logic is implemented as a worker, we can also easily add or iterate the prefetching however we want.</p><p>This encoding flow stands on top of the Cloudflare network, which also provides us with <a href="https://developers.cloudflare.com/cache/how-to/tiered-cache/"><u>tiered caching</u></a> and request coalescing. Request coalescing is the key to supporting many viewers simultaneously but only encoding once by enforcing that, for any number of viewers requesting the same encoded content, only one of those requests will make it to our encoder origin — thanks to <a href="https://developers.cloudflare.com/cache/"><u>Cache</u></a>.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6oLTqFzrQodmQqWrIb91qX/1f1f7eb02fd7efb1830f7d636f54edca/image2.png"/></figure><p>That’s how Stream Live works at a high level. We ingest content from users, send it to any desired live outputs, transcode it for viewing, and give viewers a choice of quality levels, with a lot of backend complexity hidden behind a friendly API. All of this is built on top of the Cloudflare network, with Cloudflare as Customer Zero for our own products and services, using the same as the ones available to our customers.</p><p>There’s a lot more we can write about for problems we’ve solved in building Stream Live over the last few years, but those will have to be for a future blog post. If this mix of media and distributed system problems discussed here sound interesting, the Cloudflare Media Platform <a href="https://job-boards.greenhouse.io/cloudflare/jobs/6449185?gh_jid=6449185"><u>is hiring</u></a> for <a href="https://job-boards.greenhouse.io/cloudflare/jobs/6297082?gh_jid=6297082"><u>several roles</u></a>. Apply and join us!</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Behind the scenes with Stream Live, Cloudflare’s live streaming service" href="https://blog.cloudflare.com/behind-the-scenes-with-stream-live-cloudflares-live-streaming-service/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Behind the scenes with Stream Live, Cloudflare’s live streaming service</span><span class="cap link fs12">https://blog.cloudflare.com/behind-the-scenes-with-stream-live-cloudflares-live-streaming-service/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>The Forecast Is Clear: Clouds on E-Paper, Powered by the Cloud</title>
    <link href="https://blog.imc.re/RSSBOX/rss/90648e4f.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/90648e4f.html</id>
    <published>2024-12-31T14:00:00.000Z</published>
    <updated>2024-12-31T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>I’ve noticed that many shops are increasingly using e-paper displays. They’re impressive: high contrast, no backlight, and no visible cables. Unlike most electronics, these displays are seamlessly integrated and feel very natural. This got me wondering: is it possible to use such a display for a pet project? I want to experiment with this technology myself.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Be8SEo0lqoZ0t10tPbtcT/ffa6f9263df05392d7c4408e9c98bc28/Screenshot_2024-12-23_at_15.26.23.png"/></figure><p><span><span><sup>(</sup></span></span><a href="https://www.wiadomoscihandlowe.pl/najwieksze-sieci-handlowe/lidl/lidl-wprowadza-do-sklepow-elektroniczne-etykiety-mniejsze-obciazenie-pracownikow-mniej-zuzytego-papieru-2447917"><span><span><sup><u>source</u></sup></span></span></a><span><span><sup>)</sup></span></span></p><p>My main goal in this project is to understand the hardware and its capabilities. Here, I'll be using an e-paper display to show the current weather, but at its core, I’m simply feeding data from a website to the display. While it sounds straightforward, it actually requires three layers of software to pull off. Still, it’s a fun challenge and a great opportunity to work with both embedded hardware and Cloudflare Workers.</p><div><h2>Sourcing the hardware</h2><a href="#sourcing-the-hardware"></a></div><p>For this project, I'm using components from Waveshare. They offer <a href="https://www.waveshare.com/product/displays/e-paper/epaper-1.htm?___SID=U&amp;limit=80"><u>a variety of e-paper displays</u></a>, ranging from credit card-sized to A4-sized models. I chose the 7.5-inch, two-color "e-Paper (G)" display. For the controller, I'm using a Waveshare <a href="https://www.waveshare.com/e-Paper-ESP32-Driver-Board.htm"><u>ESP32-based universal board</u></a>. With just these two components — a display and a controller — I was ready to get started.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7A6SqnMUHriAgRAAJM5Mbj/0d1282a915a1192d276e7dff1b901013/Screenshot_2024-12-23_at_15.25.45.png"/></figure><p>When the components arrived, I carefully connected the display’s ribbon cable to the ESP32 board. Even though this step isn’t documented anywhere, it was simple and almost impossible to get wrong. Best of all, no soldering was needed!</p><p>That’s pretty much it for the hardware setup! I’m keeping the device powered with a 5V supply through a micro-USB connection.</p><div><h2>One layer of hardware </h2><a href="#one-layer-of-hardware"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6WNVmUFDsLdewKrZJr4Otl/ae5eb976d1c7dc176cc288619b18c036/image1.png"/></figure><p><span><span><sup>(</sup></span></span><a href="https://www.waveshare.com/e-paper-esp32-driver-board.htm"><span><span><sup><u>source</u></sup></span></span></a><span><span><sup>)</sup></span></span></p><p>This was my first time working with the <a href="https://en.wikipedia.org/wiki/ESP32"><u>ESP32 CPU family</u></a>, and I’m really impressed. It’s a system-on-chip controller with built-in Bluetooth and Wi-Fi. It’s relatively fast, very power-efficient, and <a href="https://youtu.be/qLh1FOcGysY?t=157"><u>quite popular in DSP</u></a> (digital signal processing) applications. For example, your audio device might be powered by a CPU like this. Interestingly, the newer models have switched to the <a href="https://en.wikipedia.org/wiki/RISC-V"><u>RISC-V</u></a> instruction set.</p><p>For our purposes, we’ll only scratch the surface of what the ESP32 is capable of. The chip is straightforward to work with, thanks to the familiar Arduino environment. A great starting point is <a href="https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board#How_to_Use"><u>the demo provided by Waveshare</u></a>. It sets up a web page where you can easily upload a custom image to the display.</p><p>To run the demo you need to:</p><ul><li><p>Install the <a href="https://support.arduino.cc/hc/en-us/articles/360019833020-Download-and-install-Arduino-IDE"><u>Arduino IDE</u></a>.</p></li><li><p>Fix permissions of the <code>/dev/ACM0</code> device.</p></li><li><p>Install "Additional Boards Manager URL" as per the <a href="https://www.waveshare.com/wiki/Arduino_ESP32/8266_Online_Installation"><u>instructions</u></a>, and install the "esp32 by expressif" bundle.</p></li><li><p>Open the "Loader_esp32wf" example downloaded from <a href="https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board#Download_Demo"><u>waveshare</u></a>.</p></li><li><p>Change the Wi-Fi name, password and IP address in the Arduino IDE <code>srvr.h</code> tab.</p></li></ul><p>Once everything is set up, you should be able to connect to the ESP32’s IP address and use the simple web interface to upload an image to the display.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5KUXIJqF1J9hQqHISumuaV/85c211b315f338ba2339b4a7120162d4/Screenshot_2024-12-23_at_15.24.46.png"/></figure><p>With a simple click of the "Upload Image" button, the magic happens: the e-paper display comes to life, showcasing the uploaded image.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3qxQCybmGmpxufDfU69OcY/d995257657f5991dd1d152b59ae2b84e/Screenshot_2024-12-23_at_15.24.09.png"/></figure><p>With the demo up and running, we can move on to the next step: figuring out how to render a web page on the e-paper display.</p><div><h2>Three layers of software</h2><a href="#three-layers-of-software"></a></div><p>The ESP32 comes with some limitations. It has 520 KiB of RAM, 4 MiB of flash, and a 240 MHz clock speed. While this is fine for tasks like connecting to Wi-Fi or fetching a simple URL, it’s not powerful enough for more demanding tasks, such as parsing JSON or rendering an entire web page.</p><p>There are basic Arduino libraries for handling bitmaps, which can draw rectangles and render simple fonts, but manually managing layout doesn't sound appealing to me. A better approach is to play to the ESP32’s strengths — fetching and displaying bitmaps — and delegate the more complex task of HTML rendering to a more powerful server. </p><p>Let’s break the problem into three layers:</p><ol><li><p><b>ESP32 (Display Layer): </b>The ESP32 will periodically, say every minute, fetch a pre-rendered bitmap from the server and display it on the e-paper screen. This keeps the ESP32's tasks lightweight and manageable.</p></li><li><p><b>Server A (Rendering Layer): </b>This server will fetch the desired website, render it, and rasterize it into a bitmap format. Its job is to prepare a bitmap that the ESP32 can handle without additional processing.</p></li><li><p><b>Server B (Content Layer): </b>This server hosts the actual website with the HTML and CSS content. In this case, it will provide the local weather data in a styled format, ready to be fetched and rendered by Server A.</p></li></ol><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3V3LbBwfxhaWMukCVw0Tx/ab272f72ee2e45879acf3fea9a0fe75e/image8.png"/></figure><div><h3>ESP32 (Display Layer)</h3><a href="#esp32-display-layer"></a></div><p>The ESP32 provides some great higher-level libraries to simplify development. For this project, we’ll need three key components:</p><ol><li><p><a href="https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino"><b><u>Wi-Fi Arduino Library</u></b></a><b>:</b> To connect the ESP32 to a Wi-Fi network.</p></li><li><p><a href="https://github.com/espressif/arduino-esp32/blob/master/libraries/HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino"><b><u>HTTP Arduino Library</u></b></a><b>:</b> To handle HTTP requests and fetch the rendered bitmap from the server.</p></li><li><p><b>EPD (e-Paper Display) Driver:</b> To control the e-paper display and render the fetched bitmap.</p></li></ol><p>These libraries make it much easier to implement the required functionality without dealing with low-level details.</p><p><a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2024-12-e-paper/ESP32-fetch-from-worker/ESP32-fetch-from-worker.ino#L31"><u>Here's my ESP32 Arduino project code</u></a>. It's actually pretty straightforward:</p><ul><li><p>First, it connects to Wi-Fi</p></li><li><p>Then, it fetches a rendered bitmap from an HTTP endpoint</p></li><li><p>Then it pushes it to the e-paper display if needed</p></li><li><p>Waits a minute</p></li><li><p>And repeats the whole process forever</p></li></ul><p>E-paper displays typically start to degrade after about one million refresh cycles. To preserve the display's lifespan, I’m being extra careful to avoid unnecessary refreshes.</p><div><h3>Server A (Rendering Layer)</h3><a href="#server-a-rendering-layer"></a></div><p>Now for the exciting part! We need an online service that can fetch a website, render it, rasterize it to fit our small monochromatic display, and return it as a display-sized binary blob. Initially, I considered using headless Chrome paired with an ImageMagick script, but then I discovered <a href="https://developers.cloudflare.com/browser-rendering/"><u>Cloudflare’s </u><b><u>Browser Rendering API</u></b></a>, which fits our needs perfectly.</p><p>This API can be used quite trivially and nicely fits our needs. <a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2024-12-e-paper/worker-render-raster/index.ts#L79"><u>Here's the typescript worker code</u></a>, and there are two particularly interesting parts: handling a remote browser and dithering.</p><div><h3>Remote Browser API</h3><a href="#remote-browser-api"></a></div><p>First, see how easy it is to render a website as a PNG using Browser Rendering:</p><pre><code>if (!browser) &#123;       browser = await puppeteer.launch(env.MYBROWSER, &#123; keep_alive: 600000 &#125;);       launched = true;&#125;sessionId = browser.sessionId();<p>const page &#x3D; await browser.newPage();<br>await page.setViewport(&amp;#123;<br>         width: 480,<br>         height: 800,<br>         deviceScaleFactor: 1,<br>&amp;#125;)</p><p>await page.goto(url);<br>img &#x3D; (await page.screenshot()) as Buffer;</code></pre></p><p>I’m genuinely surprised at how practical and effective this approach is. While the remote browser startup isn’t exactly fast — it can take a few seconds to generate the screenshot — it’s not an issue for my use case. The delay is perfectly acceptable, especially considering how much work is offloaded to the cloud.</p><h4>Dithering</h4><p>To prepare the bitmap for the ESP32, we need to decode the PNG, reduce the color palette to monochromatic, and apply <a href="https://en.wikipedia.org/wiki/Dither"><u>dithering</u></a>. Here's the dithering code:</p><pre><code>function ditherTwoBits(px: Buffer,                       width: number,                       height: number                      ): Buffer &#123;    px = new Float32Array(px);<pre><code>for (let y = 0; y &amp;lt; height; y++) &amp;#123;    for (let x = 0; x &amp;lt; width; x++) &amp;#123;        const old_pixel = px[y * width + x];        const new_pixel = old_pixel &amp;gt; 128 ? 0xff : 0x00;        const quant_error = (old_pixel - new_pixel) / 16.0;        px[(y + 0) * width + (x + 0)] = new_pixel;        px[(y + 0) * width + (x + 1)] += quant_error * 7.;        px[(y + 1) * width + (x - 1)] += quant_error * 3.;        px[(y + 1) * width + (x + 0)] += quant_error * 5.;        px[(y + 1) * width + (x + 1)] += quant_error * 1.;    &amp;#125;&amp;#125;return Buffer.from(Uint8ClampedArray.from(px));</code></pre><p>&amp;#125;</code></pre></p><p>This was my first time experimenting with dithering, and it’s been a lot of fun! I was surprised by how straightforward the process is and that it’s fully deterministic. Now that I understand the details of the algorithm, I can’t help but notice its subtle side effects everywhere — in printed materials, on screens, and even in design choices around me. It’s fascinating how something so simple has such a broad impact!</p><p>To deploy this code as a Cloudflare Worker, you only need to install the required dependencies, configure the <code>wrangler.toml</code> file, and publish the code. Here’s a step-by-step guide:</p><pre><code>sudo apt install npmcd worker-render-rasternpm install wranglernpm install @cloudflare/puppeteer --save-devnpm install fast-png --save-devnpx wrangler kv:namespace create KVnpx wrangler kv:namespace create KV --preview</code></pre><p>With this out of the way, you can run the code:</p><pre><code>2025-01-e-paper/worker-render-raster$ npx wrangler dev --remote<h2 id="⛅️-wrangler-3-99-0"><a href="#⛅️-wrangler-3-99-0" class="headerlink" title=" ⛅️ wrangler 3.99.0"></a> ⛅️ wrangler 3.99.0</h2><p>Your worker has access to the following bindings:</p><ul><li>KV Namespaces:<ul><li>KV: XXX</li></ul></li><li>Browser:<ul><li>Name: BROWSER<br>[wrangler:inf] Ready on <a href="http://localhost:46131/">http://localhost:46131</a><br>⎔ Starting remote preview…<br>Total Upload: 755.39 KiB &#x2F; gzip: 149.05 KiB<br>╭─────────────────────────────────────────────────────────────────────────────────────────────────╮<br>│  [b] open a browser, [d] open devtools, [l] turn on local mode, [c] clear console, [x] to exit  │<br>╰─────────────────────────────────────────────────────────────────────────────────────────────────╯</code></pre><p>With everything set up, you can now open a browser and see a rendered and rasterized version of a website, processed through your Cloudflare Worker! For example, here’s how the <b>1.1.1.1</b> page looks in a 800x480 monochromatic resolution, complete with dithering:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6awlaJqO4LduSLwvUXQbYJ/b2b43d14c0a8d44fbed1ed4bc2a4de12/Screenshot_2024-12-23_at_15.23.14.png"/></figure><p>This demonstrates how effectively the Worker can handle rendering, rasterizing, and adapting web content for an e-paper display. It’s quite satisfying to see the pipeline in action.</p><div><h3>Server B (Content Layer)</h3><a href="#server-b-content-layer"></a></div><p>To create the weather panel, I designed a simple HTML and CSS page and <a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2024-12-e-paper/worker-weather-panel/entry.py#L165"><u>published it as another Cloudflare Worker</u></a>. This time, I used <a href="https://developers.cloudflare.com/workers/languages/python/"><u>Python in Cloudflare Workers</u></a> because it felt more straightforward, especially since the site needs to query an external weather API. The simplicity of the code was surprising and made the process smooth.</p><pre><code>async def on_fetch(request, env):cached = await env.KV.get("weather")if cached:    cached = json.loads(cached)else:    u = "https://api.open-meteo.com/..."    a = await fetch(u)    result = await a.text()    cached = json.loads(result)    await env.KV.put("weather", json.dumps(cached))return Response.new(render(...), headers=[('content-type', 'text/html')])</code></pre><p>Here’s how it appears in a normal browser compared to the rendered and rasterized version by our worker:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5irsWxy9nIgTRirXP6l8Nh/a4bb0d31df18c8385ddd96c4542941d0/Screenshot_2024-12-23_at_15.19.21.png"/></figure><div><h2>Summary</h2><a href="#summary"></a></div><p>Finally, the display deserves a proper frame. Here’s the finished version:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Dymme1r2SJ8rAKRJjyl0K/4fa344362ca037607c7989dbf47b7fff/image11.png"/></figure><p>I started this project wanting to experiment with an e-paper display hardware, but I ended up spending most of my time writing software—and it turned out to be surprisingly enjoyable across all layers:</p><ul><li><p><b>ESP32:</b> The CPU is fantastic. Programming it is straightforward, thanks to powerful built-in libraries that simplify development.</p></li><li><p><b>Cloudflare Worker Browser Rendering:</b> This is an underrated but incredibly powerful technology. It made implementing features like the Floyd–Steinberg dithering algorithm surprisingly easy.</p></li><li><p><b>Cloudflare Worker Python:</b> Although still in beta, it worked flawlessly for my needs and was a great fit for handling API requests and serving dynamic content.</p></li></ul><p>It’s remarkable how much you can achieve with relatively inexpensive hardware and free Cloudflare services.</p> </div></li></ul></li></ul><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="The forecast is clear: clouds on e-paper, powered by the cloud" href="https://blog.cloudflare.com/the-forecast-is-clear-clouds-on-e-paper-powered-by-the-cloud/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">The forecast is clear: clouds on e-paper, powered by the cloud</span><span class="cap link fs12">https://blog.cloudflare.com/the-forecast-is-clear-clouds-on-e-paper-powered-by-the-cloud/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Open Sourcing H3i: A Command Line Tool and Library for Low-Level HTTP/3 Testing and Debugging</title>
    <link href="https://blog.imc.re/RSSBOX/rss/5a651ac4.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/5a651ac4.html</id>
    <published>2024-12-30T14:00:00.000Z</published>
    <updated>2024-12-30T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>Have you ever built a piece of IKEA furniture, or put together a LEGO set, by following the instructions closely and only at the end realized at some point you didn't <i>quite</i> follow them correctly? The final result might be close to what was intended, but there's a nagging thought that maybe, just maybe, it's not as rock steady or functional as it could have been.</p><p>Internet protocol specifications are instructions designed for engineers to build things. Protocol designers take great care to ensure the documents they produce are clear. The standardization process gathers consensus and review from experts in the field, to further ensure document quality. Any reasonably skilled engineer should be able to take a specification and produce a performant, reliable, and secure implementation. The Internet is central to everyone's lives, and we depend on these implementations. Any deviations from the specification can put us at risk. For example, mishandling of malformed requests can allow attacks such as <a href="https://en.wikipedia.org/wiki/HTTP_request_smuggling"><u>request smuggling</u></a>.</p><p>h3i is a binary command line tool and Rust library designed for low-level testing and debugging of HTTP/3, which runs over QUIC. <a href="https://crates.io/crates/h3i"><u>h3i</u></a> is free and open source as part of Cloudflare's <a href="https://github.com/cloudflare/quiche"><u>quiche</u></a> project. In this post we'll explain the motivation behind developing h3i, how we use it to help develop robust and safe standards-compliant software and production systems, and how you can similarly use it to test your own software or services. If you just want to jump into how to use h3i, go to the <a href="#the-h3i-command-line-tool"><u>h3i command line tool</u></a> section.</p><div><h2>A recap of QUIC and HTTP/3</h2><a href="#a-recap-of-quic-and-http-3"></a></div><p><a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>QUIC</u></a> is a secure-by-default transport protocol that provides performance advantages compared to TCP and TLS via a more efficient handshake, along with stream multiplexing that provides <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking"><u>head-of-line blocking</u></a> avoidance. <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><u>HTTP/3</u></a> is an application protocol that maps HTTP semantics to QUIC, such as defining how HTTP requests and responses are assigned to individual QUIC streams.</p><p>Cloudflare has supported QUIC on our global network in some shape or form <a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>since 2018</u></a>. We started while the <a href="https://ietf.org/"><u>Internet Engineering Task Force (IETF)</u></a> was earnestly standardizing the protocol, working through early iterations and using interoperability testing and experience to help provide feedback for the standards process. We <a href="https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/"><u>launched support</u></a> for QUIC version 1 and HTTP/3 as soon as <a href="https://datatracker.ietf.org/doc/html/rfc9000"><u>RFC 9000</u></a> (and its accompanying specifications) were published in 2021.</p><p>We work on the Protocols team, who own the ingress proxy into the Cloudflare network. This is essentially Cloudflare’s “front door” — HTTP requests that come to Cloudflare from the Internet pass through us first. The majority of requests are passed onwards to things like rulesets, workers, caches, or a customer origin. However, you might be surprised that many requests don't ever make it that far because they are, in some way, invalid or malformed. Servers listening on the Internet have to be robust to traffic that is not RFC compliant, whether caused by accident or malicious intent.</p><p>The Protocols team actively participates in IETF standardization work and has also helped build and maintain other Cloudflare services that leverage quiche for QUIC and HTTP/3, from the proxies that help <a href="https://blog.cloudflare.com/icloud-private-relay/"><u>iCloud Private Relay</u></a> via <a href="https://blog.cloudflare.com/unlocking-quic-proxying-potential/"><u>MASQUE proxying</u></a>, to replacing <a href="https://blog.cloudflare.com/zero-trust-warp-with-a-masque/"><u>WARP's use of Wireguard with MASQUE</u></a>, and beyond.</p><p>Throughout all of these different use cases, it is important for us to extensively test all aspects of the protocols. A deep dive into protocol details is a blog post (or three) in its own right. So let's take a thin slice across HTTP to help illustrate the concepts.</p><p><a href="https://www.rfc-editor.org/rfc/rfc9110.html"><u>HTTP Semantics</u></a> are common to all versions of HTTP — the overall architecture, terminology, and protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, and much more. Each individual HTTP version defines how semantics are transformed into a "wire format" for exchange over the Internet. You can read more about HTTP/1.1 and HTTP/2 in some of our previous <a href="https://blog.cloudflare.com/a-primer-on-proxies/"><u>blog</u></a> <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>posts</u></a>.</p><p>With HTTP/3, HTTP request and response messages are split into a series of binary frames. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.2"><u>HEADERS</u></a> frames carry a representation of HTTP metadata (method, path, status code, field lines). The payload of the frame is the encoded <a href="https://datatracker.ietf.org/doc/html/rfc9204"><u>QPACK</u></a> compression output. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.1"><u>DATA</u></a> frames carry <a href="https://datatracker.ietf.org/doc/html/rfc9110#section-6.4.1"><u>HTTP content</u></a> (aka "message body"). In order to exchange these frames, HTTP/3 relies on QUIC <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2"><u>streams</u></a>. These provide an ordered and reliable byte stream and each have an identifier (ID) that is unique within the scope of a connection. There are <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2.1"><u>four different stream types</u></a>, denominated by the two least significant bits of the ID.</p><p>As a simple example, assuming a QUIC connection has already been established, a client can make a GET request and receive a 200 OK response with an HTML body using the follow sequence:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7vVfQ5CYaaVPVmGloRUnkI/88bd727c3526e540bd493bc15fbe904a/unnamed.png"/></figure><ol><li><p>Client allocates the first available client-initiated bidirectional QUIC stream. (The IDs start at 0, then 4, 8, 12 and so on)</p></li><li><p>Client sends the request HEADERS frame on the stream and sets the stream's <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-19.8"><u>FIN bit</u></a> to mark the end of stream.</p></li><li><p>Server receives the request HEADERS frame and validates it against <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>RFC 9114 rules</u></a>. If accepted, it processes the request and prepares the response.</p></li><li><p>Server sends the response HEADERS frame on the same stream.</p></li><li><p>Server sends the response DATA frame on the same stream and sets the FIN bit.</p></li><li><p>Client receives the response frames and validates them. If accepted, the content is presented to the user.</p></li></ol><p>At the QUIC layer, stream data is split into STREAM frames, which are sent in QUIC packets over UDP. QUIC deals with any loss detection and recovery, helping to ensure stream data is reliable. The layer cake diagram below provides a handy comparison of how HTTP/1.1, HTTP/2 and HTTP/3 use TCP, UDP and IP.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4049UpKGn4BJcYcEXSFgWz/32143a5ba3672786639908ad96851225/image2.png"/></figure><div><h2>Background on testing QUIC and HTTP/3 at Cloudflare</h2><a href="#background-on-testing-quic-and-http-3-at-cloudflare"></a></div><p>The Protocols team has a diverse set of automated test tools that exercise our ingress proxy software in order to ensure it can stand up to the deluge that the Internet can throw at it. Just like a bouncer at a nightclub front door, we need to prevent as much bad traffic as possible before it gets inside and potentially causes damage.</p><p>HTTP/2 and HTTP/3 share several concepts. When we started developing early HTTP/3 support, we'd already learned a lot from production experience with HTTP/2. While HTTP/2 addressed many issues with HTTP/1.1 (especially problems like <a href="https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf"><u>request smuggling</u></a>, caused by its ASCII-based message delineation), HTTP/2 also added complexity and new avenues for attack. Security is an ongoing process, and the Protocols team continually hardens our software and systems to threats. For example, mitigating the range of <a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>denial-of-service attacks</u></a> identified by Netflix in 2019, or the <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>HTTP/2 Rapid Reset</u></a> attacks of 2023.</p><p>For testing HTTP/2, we rely on the Python <a href="https://pypi.org/project/requests/"><u>Requests</u></a> library for testing conventional HTTP exchanges. However, that mostly only exercises HEADERS and DATA frames. There are eight other frame types and a plethora of ways that they can interact (hence the new attack vectors mentioned above). In order to get full testing coverage, we have to break down into the lower layer <a href="https://pypi.org/project/h2/"><u>h2</u></a> library, which allows exact frame-by-frame control. However, even that is not always enough. Libraries tend to want to follow the RFC rules and prevent their users from doing "the wrong thing". This is entirely logical for most purposes. For our needs though, we need to take off the safety guards just like any potential attackers might do. We have a few cases where the best way to exercise certain traffic patterns is to handcraft HTTP/2 frames in a hex editor, store that as binary, and replay it with a tool such as <a href="https://docs.openssl.org/1.0.2/man1/s_client/"><u>OpenSSL s_client</u></a>.</p><p>We knew we'd need similar testing approaches for HTTP/3. However, when we started in 2018, there weren't many other suitable client implementations. The rate of iteration on the specifications also meant it was hard to always keep in sync. So we built tests on quiche, using a mix of our <a href="https://github.com/cloudflare/quiche/blob/master/apps/src/client.rs"><u>quiche-client</u></a> and <a href="https://github.com/cloudflare/quiche/tree/master/tools/http3_test"><u>http3_test</u></a>. Over time, the python library <a href="https://github.com/aiortc/aioquic"><u>aioquic</u></a> has matured, and we have used it to add a range of lower-layer tests that break or bend HTTP/3 rules, in order to prove our proxies are robust.</p><p>Finally, we would be remiss not to mention that all the tests in our ingress proxy are <b>in addition to </b>the suite of over 500 integration tests that run on the quiche project itself.</p><div><h2>Making HTTP/3 testing more accessible and maintainable with h3i</h2><a href="#making-http-3-testing-more-accessible-and-maintainable-with-h3i"></a></div><p>While we are happy with the coverage of our current tests, the smorgasbord of test tools makes it hard to know what to reach for when adding new tests. For example, we've had cases where aioquic's safety guards prevent us from doing something, and it has needed a patch or workaround. This sort of thing requires a time investment just to debug/develop the tests.</p><p>We believe it shouldn't take a protocol or code expert to develop what are often very simple to describe tests. While it is important to provide guide rails for the majority of conventional use cases, it is also important to provide accessible methods for taking them off.</p><p>Let's consider a simple example. In HTTP/3 there is something called the control stream. It's used to exchange frames such as SETTINGS, which affect the HTTP/3 connection. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-6.2.1"><u>Section 6.2.1</u></a> states:</p><blockquote><p><i>Each side MUST initiate a single control stream at the beginning of the connection and send its SETTINGS frame as the first frame on this stream. If the first frame of the control stream is any other frame type, this MUST be treated as a connection error of type H3_MISSING_SETTINGS. Only one control stream per peer is permitted; receipt of a second stream claiming to be a control stream MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR. The sender MUST NOT close the control stream, and the receiver MUST NOT request that the sender close the control stream. If either control stream is closed at any point, this MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM. Connection errors are described in Section 8.</i></p></blockquote><p>There are many tests we can conjure up just from that paragraph:</p><ol><li><p>Send a non-SETTINGS frame as the first frame on the control stream.</p></li><li><p>Open two control streams.</p></li><li><p>Open a control stream and then close it with a FIN bit.</p></li><li><p>Open a control stream and then reset it with a RESET_STREAM QUIC frame.</p></li><li><p>Wait for the peer to open a control stream and then ask for it to be reset with a STOP_SENDING QUIC frame.</p></li></ol><p>All of the above actions should cause a remote peer that has implemented the RFC properly to close the connection. Therefore, it is not in the interest of the local client or server applications to ever do these actions.</p><p>Many QUIC and HTTP/3 implementations are developed as libraries that are integrated into client or server applications. There may be an extensive set of unit or integration tests of the library checking RFC rules. However, it is also important to run the same tests on the integrated assembly of library and application, since it's all too common that an unhandled/mishandled library error can cascade to cause issues in upper layers. For instance, the HTTP/2 Rapid Reset attacks affected Cloudflare due to their <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/#impact-on-customers"><u>impact on how one service spoke to another</u></a>.</p><p>We've developed h3i, a command line tool and library, to make testing more accessible and maintainable for all. We started with a client that can exercise servers, since that's what our focus has been. Future developments could support the opposite, a server that behaves in unusual ways in order to exercise clients.</p><p><b>Note: </b>h3i is <i>not</i> intended to be a production client! Its flexibility may cause issues that are not observed in other production-oriented clients. It is also not intended to be used for any type of performance testing and measurement.</p><div><h2>The h3i command line tool</h2><a href="#the-h3i-command-line-tool"></a></div><p>The primary purpose of the h3i command line tool is quick low-level debugging and exploratory testing. Rather than worrying about writing code or a test script, users can quickly run an ad-hoc client test against a target, guided by interactive prompts.</p><p>In the simplest case, you can think of h3i a bit like <a href="https://curl.se/"><u>curl</u></a> but with access to some extra HTTP/3 parameters. In the example below, we issue a request to <a href="https://cloudflare-quic.com"><u>https://cloudflare-quic.com</u></a>/ and receive a response.</p><div></div><p>Walking through a simple GET with h3i step-by-step:</p><ol><li><p>Grab a copy of the h3i binary either by running <code>cargo install h3i</code> or cloning the quiche source repo at <a href="https://github.com/cloudflare/quiche/"><u>https://github.com/cloudflare/quiche/</u></a>. Both methods assume you have some familiarity with Rust and Cargo. See the cargo <a href="https://doc.rust-lang.org/book/ch14-04-installing-binaries.html"><u>documentation</u></a> for more information.</p><ol><li><p><code>cargo install</code> will place the binary on your path, so you can then just run it by executing <code>h3i</code>.</p></li><li><p>If running from source, navigate to the quiche/h3i directory and then use <code>cargo run</code>.</p></li></ol></li><li><p>Run the binary and provide the name and port of the target server. If the port is omitted, the default value 443 is assumed. E.g, <code>cargo run cloudflare-quic.com</code></p></li><li><p>h3i then enters the action prompting phase. A series of one or more HTTP/3 actions can be queued up, such as sending frames, opening or terminating streams, or waiting on data from the server. The full set of options is documented in the <a href="https://github.com/cloudflare/quiche/blob/master/h3i/README.md#command-line-tool"><u>readme</u></a>.</p><ol><li><p>The prompting interface adapts to keyboard inputs and supports tab completion.</p></li><li><p>In the example above, the <code>headers</code> action is selected, which walks through populating the fields in a HEADERS frame. It includes <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.3.1"><u>mandatory fields</u></a> from RFC 9114 for convenience. If a test requires omitting these, the <code>headers_no_pseudo</code> can be used instead.</p></li></ol></li><li><p>The <code>commit</code> prompt choice finalizes the action list and moves to the connection phase. h3i initiates a QUIC connection to the server identified in step 2. Once connected, actions are executed in order.</p></li><li><p>By default, h3i reports some limited information about the frames the server sent. To get more detailed information, the <code>RUST_LOG</code> environment can be set with either <code>debug</code> or <code>trace</code> levels.</p></li></ol><div><h2>Instant record and replay, powered by qlog</h2><a href="#instant-record-and-replay-powered-by-qlog"></a></div><p>It can be fun to play around with the h3i command line tool to see how different servers respond to different combinations or sequences of actions. Occasionally, you'll find a certain set that you want to run over and over again, or share with a friend or colleague. Having to manually enter the prompts repeatedly, or share screenshots of the h3i input can turn tedious. Fortunately, h3i records all the actions in a log file by default — the file path is printed immediately after h3i starts. The format of this file is based on <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema"><u>qlog</u></a>, an in-progress standard in development at the IETF for network protocol logging. It’s a perfect fit for our low-level needs.</p><p>Here's an example h3i qlog file:</p><pre><code>&#123;"qlog_version":"0.3","qlog_format":"JSON-SEQ","title":"h3i","description":"h3i","trace":&#123;"vantage_point":&#123;"type":"client"&#125;,"title":"h3i","description":"h3i","configuration":&#123;"time_offset":0.0&#125;&#125;&#125;&#123;  "time": 0.172783,  "name": "http:frame_created",  "data": &#123;    "stream_id": 0,    "frame": &#123;      "frame_type": "headers",      "headers": [        &#123;          "name": ":method",          "value": "GET"        &#125;,        &#123;          "name": ":authority",          "value": "cloudflare-quic.com"        &#125;,        &#123;          "name": ":path",          "value": "/"        &#125;,        &#123;          "name": ":scheme",          "value": "https"        &#125;,        &#123;          "name": "user-agent",          "value": "h3i"        &#125;      ]    &#125;  &#125;,  "fin_stream": true&#125;</code></pre><p>h3i logs can be replayed using the <code>--qlog-input</code> option. You can change the target server host and port, and keep all the same actions. However, most servers will validate the :authority pseudo-header or Host header contained in a HEADERS frame. The --replay-host-override option allows changing these fields without needing to modify the file by hand.</p><p>And yes, qlog files are human-readable text in the JSON-SEQ format. So you can also just write these by hand in the first place if you like! However, if you're going to start writing things, maybe Rust is your preferred option…</p><div><h2>Using the h3i library to send a malformed request with Rust</h2><a href="#using-the-h3i-library-to-send-a-malformed-request-with-rust"></a></div><p>In our previous example, we just sent a valid request so there wasn't anything interesting to observe. Where h3i really shines is in generating traffic that isn't RFC compliant, such as malformed HTTP messages, invalid frame sequences, or other actions on streams. This helps determine if a server is acting robustly and defensively.</p><p>Let's explore this more with an example of HTTP content-length mismatch. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>section 4.1.2</u></a> specifies:</p><blockquote><p><i>A request or response that is defined as having content when it contains a Content-Length header field (Section 8.6 of [HTTP]) is malformed if the value of the Content-Length header field does not equal the sum of the DATA frame lengths received. A response that is defined as never having content, even when a Content-Length is present, can have a non-zero Content-Length header field even though no content is included in DATA frames.</i></p><p><i>Intermediaries that process HTTP requests or responses (i.e., any intermediary not acting as a tunnel) MUST NOT forward a malformed request or response. Malformed requests or responses that are detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.</i></p><p><i>For malformed requests, a server MAY send an HTTP response indicating the error prior to closing or resetting the stream.</i></p></blockquote><p>There are good reasons that the RFC is so strict about handling mismatched content lengths. They can be a vector for <a href="https://portswigger.net/research/http2"><u>desynchronization attacks</u></a> (similar to request smuggling), especially when a proxy is converting inbound HTTP/3 to outbound HTTP/1.1.</p><p>We've provided an <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> of how to use the h3i Rust library to write a tailor-made test client that sends a mismatched content length request. It sends a Content-Length header of 5, but its body payload is “test”, which is only 4 bytes. It then waits for the server to respond, after which it explicitly closes the connection by sending a QUIC CONNECTION_CLOSE frame.</p><p>When running low-level tests, it can be interesting to also take a packet capture (<a href="https://en.wikipedia.org/wiki/Pcap"><u>pcap</u></a>) and observe what is happening on the wire. Since QUIC is an encrypted transport, we'll need to use the SSLKEYLOG environment variable to capture the session keys so that tools like Wireshark can <a href="https://wiki.wireshark.org/TLS#using-the-pre-master-secret"><u>decrypt and dissect</u></a>.</p><p>To follow along at home, clone a copy of the quiche repository, start a packet capture on the appropriate network interface and then run:</p><pre><code>cd quiche/h3iSSLKEYLOGFILE="h3i-example.keys" cargo run --example content_length_mismatch</code></pre><p>In our decrypted capture, we see the expected sequence of handshake, request, response, and then closure.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Qkdd3h0x826tH95S61u92/5de829e018b9d3ef409a2452362fa81e/image1.png"/></figure><div><h2>Surveying the example code</h2><a href="#surveying-the-example-code"></a></div><p>The <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> is a simple binary app with a <code>main()</code> entry point. Let's survey the key elements.</p><p>First, we set up an h3i configuration to a target server:</p><pre><code>let config = Config::new()        .with_host_port("cloudflare-quic.com".to_string())        .with_idle_timeout(2000)        .build()        .unwrap();</code></pre><p>The idle timeout is a QUIC concept which tells each endpoint when it should close the connection if the connection has been idle. This prevents endpoints from spinning idly if the peer hasn’t closed the connection. h3i’s default is 30 seconds, which can be too long for tests, so we set ours to 2 seconds here.</p><p>Next, we define a set of request headers and encode them with QPACK compression, ready to put in a HEADERS frame. Note that h3i does provide a <a href="https://docs.rs/h3i/latest/h3i/actions/h3/fn.send_headers_frame.html"><u>send_headers_frame</u></a> helper method which does this for you, but the example does it manually for clarity:</p><pre><code>let headers = vec![        Header::new(b":method", b"POST"),        Header::new(b":scheme", b"https"),        Header::new(b":authority", b"cloudflare-quic.com"),        Header::new(b":path", b"/"),        // We say that we're going to send a body with 5 bytes...        Header::new(b"content-length", b"5"),    ];<pre><code>let header_block = encode_header_block(&amp;amp;headers).unwrap();&lt;/code&gt;&lt;/pre&gt;</code></pre><p>Then, we define the set of h3i actions that we want to execute in order: send HEADERS, send a too-short DATA frame, wait for the server's HEADERS, then close the connection.</p><pre><code>let actions = vec![        Action::SendHeadersFrame &#123;            stream_id: STREAM_ID,            fin_stream: false,            headers,            frame: Frame::Headers &#123; header_block &#125;,        &#125;,        Action::SendFrame &#123;            stream_id: STREAM_ID,            fin_stream: true,            frame: Frame::Data &#123;                // ...but, in actuality, we only send 4 bytes. This should yield a                // 400 Bad Request response from an RFC-compliant                // server: https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2-3                payload: b"test".to_vec(),            &#125;,        &#125;,        Action::Wait &#123;            wait_type: WaitType::StreamEvent(StreamEvent &#123;                stream_id: STREAM_ID,                event_type: StreamEventType::Headers,            &#125;),        &#125;,        Action::ConnectionClose &#123;            error: quiche::ConnectionError &#123;                is_app: true,                error_code: quiche::h3::WireErrorCode::NoError as u64,                reason: vec![],            &#125;,        &#125;,    ];</code></pre><p>Finally, we'll set things in motion with <code>connect()</code>, which sets up the QUIC connection, executes the actions list and collects the summary.</p><pre><code>let summary =        sync_client::connect(config, &amp;actions).expect("connection failed");<pre><code>println!(    &quot;=== received connection summary! ===\n\n&amp;#123;&amp;#125;&quot;,    serde_json::to_string_pretty(&amp;amp;summary).unwrap_or_else(|e| e.to_string()));&lt;/code&gt;&lt;/pre&gt;</code></pre><p><a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.ConnectionSummary.html"><u>ConnectionSummary</u></a>  provides data about the connection, including the frames h3i received, details about why the connection closed, and connection statistics. The example prints the summary out. However, you can programmatically check it. We do this to write our own internal automation tests.</p><p>If you're running the example, it should print something like the following:</p><pre><code>=== received connection summary! ===<p>&amp;#123;<br>  “stream_map”: &amp;#123;<br>    “0”: [<br>      &amp;#123;<br>        “UNKNOWN”: &amp;#123;<br>          “raw_type”: 2471591231244749708,<br>          “payload”: “”<br>        &amp;#125;<br>      &amp;#125;,<br>      &amp;#123;<br>        “UNKNOWN”: &amp;#123;<br>          “raw_type”: 2031803309763646295,<br>          “payload”: “4752454153452069732074686520776f7264”<br>        &amp;#125;<br>      &amp;#125;,<br>      &amp;#123;<br>        “enriched_headers”: &amp;#123;<br>          “header_block_len”: 75,<br>          “headers”: [<br>            &amp;#123;<br>              “name”: “:status”,<br>              “value”: “400”<br>            &amp;#125;,<br>            &amp;#123;<br>              “name”: “server”,<br>              “value”: “cloudflare”<br>            &amp;#125;,<br>            &amp;#123;<br>              “name”: “date”,<br>              “value”: “Sat, 07 Dec 2024 00:34:12 GMT”<br>            &amp;#125;,<br>            &amp;#123;<br>              “name”: “content-type”,<br>              “value”: “text&#x2F;html”<br>            &amp;#125;,<br>            &amp;#123;<br>              “name”: “content-length”,<br>              “value”: “155”<br>            &amp;#125;,<br>            &amp;#123;<br>              “name”: “cf-ray”,<br>              “value”: “8ee06dbe2923fa17-ORD”<br>            &amp;#125;<br>          ]<br>        &amp;#125;<br>      &amp;#125;,<br>      &amp;#123;<br>        “DATA”: &amp;#123;<br>          “payload_len”: 104<br>        &amp;#125;<br>      &amp;#125;,<br>      &amp;#123;<br>        “DATA”: &amp;#123;<br>          “payload_len”: 51<br>        &amp;#125;<br>      &amp;#125;<br>    ]<br>  &amp;#125;,<br>  “stats”: &amp;#123;<br>    “recv”: 10,<br>    “sent”: 5,<br>    “lost”: 0,<br>    “retrans”: 0,<br>    “sent_bytes”: 1712,<br>    “recv_bytes”: 4178,<br>    “lost_bytes”: 0,<br>    “stream_retrans_bytes”: 0,<br>    “paths_count”: 1,<br>    “reset_stream_count_local”: 0,<br>    “stopped_stream_count_local”: 0,<br>    “reset_stream_count_remote”: 0,<br>    “stopped_stream_count_remote”: 0,<br>    “path_challenge_rx_count”: 0<br>  &amp;#125;,<br>  “path_stats”: [<br>    &amp;#123;<br>      “local_addr”: “0.0.0.0:64418”,<br>      “peer_addr”: “104.18.29.7:443”,<br>      “active”: true,<br>      “recv”: 10,<br>      “sent”: 5,<br>      “lost”: 0,<br>      “retrans”: 0,<br>      “rtt”: 0.008140072,<br>      “min_rtt”: 0.004645536,<br>      “rttvar”: 0.004238173,<br>      “cwnd”: 13500,<br>      “sent_bytes”: 1712,<br>      “recv_bytes”: 4178,<br>      “lost_bytes”: 0,<br>      “stream_retrans_bytes”: 0,<br>      “pmtu”: 1350,<br>      “delivery_rate”: 247720<br>    &amp;#125;<br>  ],<br>  “error”: &amp;#123;<br>    “local_error”: &amp;#123;<br>      “is_app”: true,<br>      “error_code”: 256,<br>      “reason”: “”<br>    &amp;#125;,<br>    “timed_out”: false<br>  &amp;#125;<br>&amp;#125;<br></code></pre></p><p>Let’s walk through the output. Up first is the <a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.StreamMap.html"><u>StreamMap</u></a>, which is a record of all frames received on each stream. We can see that we received 5 frames on stream 0: 2 UNKNOWNs, one <a href="https://docs.rs/h3i/latest/h3i/frame/struct.EnrichedHeaders.html"><u>EnrichedHeaders</u></a> frame, and two DATA frames.</p><p>The UNKNOWN frames are extension frames that are unknown to h3i; the server under test is sending what are known as <a href="https://datatracker.ietf.org/doc/draft-edm-protocol-greasing/"><u>GREASE</u></a> frames to help exercise the protocol and ensure clients are not erroring when they receive something unexpected per <a href="https://datatracker.ietf.org/doc/html/rfc9114#extensions"><u>RFC 9114 requirements</u></a>.</p><p>The EnrichedHeaders frame is essentially an HTTP/3 HEADERS frame, but with some small helpers, like one to get the response status code. The server under test sent a 400 as expected.</p><p>The DATA frames carry response body bytes. In this case, the body is the HTML required to render the Cloudflare Bad Request page (you can peek at the HTML yourself in Wireshark). We chose to omit the raw bytes from the ConnectionSummary since they may not be representable safely as text. A future improvement could be to encode the bytes in base64 or hex, in order to support tests that need to check response content.</p><div><h2>h3i for test automation</h2><a href="#h3i-for-test-automation"></a></div><p>We believe h3i is a great library for building automated tests on. You can take the above example and modify it to fit within various types of (continuous) integration tests.</p><p>We outlined earlier how the Protocols team HTTP/3 testing has organically grown to use three different frameworks. Even within those, we still didn't have much flexibility and ease of use. Over the last year we've been building h3i itself and reimplementing our suite of ingress proxy test cases using the Rust library. This has helped us improve test coverage with a range of new tests not previously possible. It also surprisingly identified some problems with the old tests, particularly for some edge cases where it wasn't clear how the old test code implementation was running under the hood.</p><div><h2>Bake offs, interop, and wider testing of HTTP</h2><a href="#bake-offs-interop-and-wider-testing-of-http"></a></div><p><a href="https://datatracker.ietf.org/doc/html/rfc1025"><u>RFC 1025</u></a> was published in 1987. Authored by <a href="https://icannwiki.org/Jon_Postel"><u>Jon Postel</u></a>, it discusses bake offs:</p><blockquote><p><i>In the early days of the development of TCP and IP, when there were very few implementations and the specifications were still evolving, the only way to determine if an implementation was "correct" was to test it against other implementations and argue that the results showed your own implementation to have done the right thing.  These tests and discussions could, in those early days, as likely change the specification as change the implementation.</i></p><p><i>There were a few times when this testing was focused, bringing together all known implementations and running through a set of tests in hopes of demonstrating the N squared connectivity and correct implementation of the various tricky cases.  These events were called "Bake Offs".</i></p></blockquote><p>While nearly 4 decades old, the concept of exercising Internet protocol implementations and seeing how they compare to the specification still holds true. The QUIC WG made heavy use of interoperability testing through its standardization process. We started off sitting in a room and running tests manually by hand (or with some help from scripts). Then <a href="https://seemann.io/"><u>Marten Seemann</u></a> developed the <a href="https://interop.seemann.io/"><u>QUIC Interop Runner</u></a>, which runs regular automated testing and collects and renders all the results. This has proven to be incredibly useful.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OGnVUbatoX8Ya2IO5RdCl/754316e004a8e658ac089e10e70b72ca/image6.png"/></figure><p>The state of HTTP/3 interoperability testing is not quite as mature. Although there are tools such as <a href="https://kazu-yamamoto.hatenablog.jp/"><u>Kazu Yamamoto's</u></a> excellent <a href="https://github.com/kazu-yamamoto/h3spec"><u>h3spec</u></a> (in Haskell) for testing conformance, there isn't a similar continuous integration process of collection and rendering of results. While h3i shares similarities with h3spec, we felt it important to focus on the framework capabilities rather than creating a corpus of tests and assertions. Cloudflare is a big fan of Rust and as several teams move to Rust-based proxies, having a consistent ecosystem provides advantages (such as developer velocity).</p><p>We certainly feel there is a great opportunity for continued collaboration and cross-pollination between projects in the QUIC and HTTP space. For example, h3i might provide a suitable basis to build another tool (or set of scripts) to run bake offs or interop tests. Perhaps it even makes sense to have a common collection of test cases owned by the community, that can be specialized to the most appropriate or preferred tooling. This topic was recently presented at the <a href="https://github.com/HTTPWorkshop/workshop2024/blob/main/talks/5.%20Testing/testing.pdf"><u>HTTP Workshop 2024</u></a> by Mohammed Al-Sahaf, and it excites us to see <a href="https://www.caffeinatedwonders.com/2024/12/18/towards-validated-http-implementation/"><u>new potential directions</u></a> of testing improvements.</p><p>When using any tools or methods for protocol testing, we encourage responsible handling of security-related matters. If you believe you may have identified a vulnerability in an IETF Internet protocol itself, please follow the IETF's <a href="https://www.ietf.org/standards/rfcs/vulnerabilities/"><u>reporting guidance</u></a>. If you believe you may have discovered an implementation vulnerability in a product, open source project, or service using QUIC or HTTP, then you should report these directly to the responsible party. Implementers or operators often provide their own publicly-available guidance and contact details to send reports. For example, the Cloudflare quiche <a href="https://github.com/cloudflare/quiche/security/policy"><u>security policy</u></a> is available in the Security tab of the GitHub repository.</p><div><h2>Summary and outlook</h2><a href="#summary-and-outlook"></a></div><p>Cloudflare takes testing very seriously. While h3i has a limited feature set as a test HTTP/3 client, we believe it provides a strong framework that can be extended to a wider range of different cases and different protocols. For example, we'd like to add support for low-level HTTP/2.</p><p>We've designed h3i to integrate into a wide range of testing methodologies, from manual ad-hoc testing, to native Rust tests, to conformance testbenches built with scripting languages. We've had great success migrating our existing zoo of test tools to a single one that is more accessible and easier to maintain.</p><p>Now that you've read about h3i's capabilities, it's left as an exercise to the reader to go back to the example of HTTP/3 control streams and consider how you could write tests to exercise a server.</p><p>We encourage the community to experiment with h3i and provide feedback, and propose ideas or contributions to the <a href="https://github.com/cloudflare/quiche"><u>GitHub repository</u></a> as issues or Pull Requests.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5rp4YDTbXm37OxK7dtjiKF/816c0eed08926b7d34842f4769808277/image4.png"/></figure><p></p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Open sourcing h3i: a command line tool and library for low-level HTTP/3 testing and debugging" href="https://blog.cloudflare.com/h3i/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Open sourcing h3i: a command line tool and library for low-level HTTP/3 testing and debugging</span><span class="cap link fs12">https://blog.cloudflare.com/h3i/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>GitHub’s Top Blogs of 2024</title>
    <link href="https://blog.imc.re/RSSBOX/rss/e38966e3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/e38966e3.html</id>
    <published>2024-12-30T11:47:10.000Z</published>
    <updated>2024-12-30T11:47:10.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>As 2024 wraps up, we’re revisiting the highlights of a year packed with innovation, learning, and community. From unlocking the power of AI to mastering essential developer tools, these blogs reflect what makes GitHub the home for all developers. Ready? Let’s jump in.</p><h2 id="choose-your-own-adventure-with-ai-models">Choose your own adventure with AI models<a aria-label="Choose your own adventure with AI models" class="heading-link pl-2 text-italic text-bold" href="#choose-your-own-adventure-with-ai-models"></a></h2><p>GitHub Copilot has long leveraged different large language models (LLMs) for different use cases. Now, <em>you</em> can access these models to meet your own needs.</p><ul><li>Take a first look at <a href="https://github.blog/news-insights/product-news/openai-o1-in-github-copilot/">OpenAI o1 in GitHub Copilot</a> to see where it can add value to your day to day. </li><li>Experiment with <a href="https://github.blog/news-insights/product-news/try-out-openai-o1-in-github-copilot-and-models/">OpenAI o1-preview and o1-mini</a>. </li><li>Access <a href="https://github.blog/news-insights/product-news/bringing-developer-choice-to-copilot/">Anthropic’s Claude 3.5 Sonnet, Google’s Gemini 1.5 Pro, and OpenAI’s o1-preview</a> across many of GitHub Copilot’s surface areas and functions.</li></ul><p>And by the way, this is now <a href="https://github.blog/news-insights/product-news/github-copilot-in-vscode-free/">available to you for free</a>. <img alt="👀" class="wp-smiley" src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f440.png" style="height: 1em; max-height: 1em;"/></p><h2 id="new-from-github">New from GitHub<a aria-label="New from GitHub" class="heading-link pl-2 text-italic text-bold" href="#new-from-github"></a></h2><p>2024 was all about empowering you to ship better code faster and smarter. Here are the launches that had the community buzzing:</p><ul><li><strong>Try <a href="https://github.blog/news-insights/product-news/introducing-github-models/">GitHub Models</a></strong>. We believe every developer <em>(that’s you!)</em> can be an AI engineer with the right tools and training. Access a number of AI models via a built-in playground that lets you test different prompts and model parameters, for free, right in GitHub. If you like what you’re seeing on the playground, you can easily bring the models to your developer environment in GitHub Codespaces and VS Code and start building. </li><li><strong>Unlock more possibilities</strong> with <a href="https://github.blog/news-insights/product-news/introducing-github-copilot-extensions/">GitHub Copilot Extensions</a>. Through a growing partner ecosystem, Copilot Extensions helps you use GitHub Copilot across third-party tools, services, and more (plus <a href="https://github.com/features/copilot/extensions#resources">you can build your own</a>!), all without leaving the IDE or GitHub.com. </li><li><strong>Work smarter</strong> with <a href="https://github.blog/news-insights/product-news/github-copilot-enterprise-is-now-generally-available/">GitHub Copilot Enterprise</a>. Our most advanced AI offering to date is customized to your organization’s knowledge and codebase, infusing GitHub Copilot throughout the software development lifecycle.</li><li><strong>Meet <a href="https://github.blog/news-insights/product-news/github-copilot-workspace/">GitHub Copilot Workspace</a></strong>, the Copilot-native developer environment where any developer can go from idea to code to software, all in natural language. Sign up for the waitlist today, and we’ll email you when it’s your turn to try Copilot Workspace.</li><li><strong>Secure code more than three times faster</strong> with <a href="https://github.blog/news-insights/product-news/secure-code-more-than-three-times-faster-with-copilot-autofix/">Copilot Autofix</a>. Our vision for application security is a world where a vulnerability found means a vulnerability fixed. Copilot Autofix now includes security campaigns to help you remediate vulnerabilities at scale and pay down years of security debt with just a few clicks.</li><li><strong><a href="https://github.blog/news-insights/product-news/arm64-on-github-actions-powering-faster-more-efficient-build-systems/">Power faster, more efficient build systems</a></strong> thanks to Arm64 on GitHub Actions. This new addition to our suite of hosted runners provides power, performance, and sustainability improvements for all your GitHub Actions jobs. You can take advantage of Arm-based hardware hosted by GitHub to build and deploy your release assets anywhere Arm architecture is used.</li></ul><h2 id="level-up-your-skills">Level up your skills<a aria-label="Level up your skills" class="heading-link pl-2 text-italic text-bold" href="#level-up-your-skills"></a></h2><p>Keeping up with the always-changing technology landscape requires you to be a lifelong learner. Whether you’re looking to go deep in your current skillset or expand your knowledge to prepare for that next career move, we have resources to help you get there.</p><h3 id="git-essentials">Git essentials<a aria-label="Git essentials" class="heading-link pl-2 text-italic text-bold" href="#git-essentials"></a></h3><ul><li><strong>Start with the fundamentals</strong> with <a href="https://github.blog/developer-skills/programming-languages-and-frameworks/what-is-git-our-beginners-guide-to-version-control/">our beginner’s guide to version control</a>.</li><li><strong>Master the <a href="https://github.blog/developer-skills/github/top-12-git-commands-every-developer-must-know/">top 12 Git commands every developer must know</a></strong>.</li><li><strong>Showcase your new skills</strong> with a <a href="https://github.blog/news-insights/product-news/github-certifications-are-generally-available/">GitHub Certification</a>!</li></ul><h3 id="ai-for-everyone">AI for everyone<a aria-label="AI for everyone" class="heading-link pl-2 text-italic text-bold" href="#ai-for-everyone"></a></h3><ul><li><strong>Take a look behind the scenes</strong> at <a href="https://github.blog/ai-and-ml/generative-ai/how-ai-code-generation-works/">how AI code generation works</a>.</li><li><strong>Learn tips, tricks, and best practices</strong> for <a href="https://github.blog/developer-skills/github/how-to-use-github-copilot-in-your-ide-tips-tricks-and-best-practices/">using GitHub Copilot in your IDE</a>.</li><li><strong>Think outside the box</strong> with <a href="https://github.blog/developer-skills/programming-languages-and-frameworks/10-unexpected-ways-to-use-github-copilot/">10 unexpected ways to use GitHub Copilot</a>.</li><li><strong><a href="https://github.blog/developer-skills/programming-languages-and-frameworks/how-to-use-ai-coding-tools-to-learn-a-new-programming-language/">Add a new language to your toolbox with AI coding tools</a></strong>.</li></ul><h2 id="the-state-of-open-source">The state of open source<a aria-label="The state of open source" class="heading-link pl-2 text-italic text-bold" href="#the-state-of-open-source"></a></h2><p>The global developer community surged in size in 2024. <em>(Did you know there are now <a href="https://github.blog/news-insights/product-news/github-copilot-in-vscode-free/">150M developers on GitHub</a>?!)</em> The Octoverse report highlighted the boom in data science and machine learning: <strong>Python overtook JavaScript as the most popular language on GitHub</strong> for the first time, and the use of Jupyter Notebooks skyrocketed.</p><p>Find out how your favorite tools fared and <strong>explore the hottest projects welcoming new contributors</strong>. <a href="https://octoverse.github.com">Read the report</a>.</p><h3 id="%f0%9f%93%a2-stay-connected"><strong><img alt="📢" class="wp-smiley" src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f4e2.png" style="height: 1em; max-height: 1em;"/> Stay connected</strong><a aria-label="&lt;strong&gt;📢 Stay connected&lt;/strong&gt;" class="heading-link pl-2 text-italic text-bold" href="#%f0%9f%93%a2-stay-connected"></a></h3><p>Like what you see? Don’t miss a beat in 2025. Subscribe to our newsletter, GitHub Insider, to keep up with the latest in software development.</p><div class="post-content-cta"><p><strong>We do newsletters, too</strong> </p><p>Discover tips, technical guides, and best practices in our biweekly newsletter just for developers. <img alt="🌐" class="wp-smiley" src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f310.png" style="height: 1em; max-height: 1em;"/></p><p><a href="https://resources.github.com/newsletter/">Subscribe now &gt;</a></p></div><p>The post <a href="https://github.blog/developer-skills/githubs-top-blog-posts-of-2024/">GitHub’s top blogs of 2024</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="GitHub’s top blogs of 2024" href="https://github.blog/developer-skills/githubs-top-blog-posts-of-2024/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">GitHub’s top blogs of 2024</span><span class="cap link fs12">https://github.blog/developer-skills/githubs-top-blog-posts-of-2024/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>What’s New in Cloudflare: MASQUE Now Powers 1.1.1.1 &amp; WARP Apps, DEX Now Generally Available With Remote Captures</title>
    <link href="https://blog.imc.re/RSSBOX/rss/5d0e2abd.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/5d0e2abd.html</id>
    <published>2024-12-27T14:00:00.000Z</published>
    <updated>2024-12-27T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>At Cloudflare, we are constantly innovating and launching new features and capabilities across our product portfolio. Today’s roundup blog post shares two exciting updates across our platform: our cross-platform <a href="https://www.cloudflare.com/en-gb/learning/dns/what-is-1.1.1.1/"><u>1.1.1.1</u></a> &amp; <a href="https://developers.cloudflare.com/warp-client/"><u>WARP</u></a> applications (consumer) and device agents (Zero Trust)  now use <a href="https://blog.cloudflare.com/masque-building-a-new-protocol-into-cloudflare-warp/"><u>MASQUE</u></a>, a cutting-edge <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><u>HTTP/3</u></a>-based protocol, to secure your Internet connection. Additionally, DEX is now available for general availability. </p><div><h2>Faster and more stable: our 1.1.1.1 &amp; WARP apps now use MASQUE by default</h2><a href="#faster-and-more-stable-our-1-1-1-1-warp-apps-now-use-masque-by-default"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6CghJvmC5DBnhKLM36MY3O/ecf722a9d9b5a4e4a048afea06237749/image1.png"/></figure><p>We’re excited to announce that as of today, our cross-platform <a href="https://www.cloudflare.com/en-gb/learning/dns/what-is-1.1.1.1/"><u>1.1.1.1</u></a> &amp; <a href="https://developers.cloudflare.com/warp-client/"><u>WARP</u></a> apps now use <a href="https://blog.cloudflare.com/masque-building-a-new-protocol-into-cloudflare-warp/"><u>MASQUE</u></a>, a cutting-edge <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><u>HTTP/3</u></a>-based protocol, to secure your Internet connection.</p><p>As a reminder, our 1.1.1.1 &amp; WARP apps have two main functions: send all DNS queries through 1.1.1.1, our privacy-preserving DNS resolver, and protect your device’s network traffic via WARP by creating a private and encrypted tunnel to the resources you’re accessing, preventing unwanted third parties or public Wi-Fi networks from snooping on your traffic.</p><p>There are many ways to encrypt and proxy Internet traffic — you may have heard of a few, such as IPSec, WireGuard, or OpenVPN. There are many tradeoffs we considered when choosing a protocol, but we believe MASQUE is the future of fast, secure, and stable Internet proxying, it aligns with our belief in building on top of open Internet standards, and we’ve deployed it successfully at scale for customers like <a href="https://blog.cloudflare.com/icloud-private-relay/"><u>iCloud Private Relay</u></a> and <a href="https://blog.cloudflare.com/cloudflare-now-powering-microsoft-edge-secure-network/"><u>Microsoft Edge Secure Network</u></a>.</p><div><h3>Why MASQUE?</h3><a href="#why-masque"></a></div><p><a href="https://blog.cloudflare.com/masque-building-a-new-protocol-into-cloudflare-warp/"><b><u>MASQUE</u></b></a> is a modern framework for proxying traffic that allows a variety of application protocols, including HTTP/3, to utilize QUIC as their transport mechanism. That’s a lot of acronyms, so let's make sure those are clear. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6XkQ3rF8oo8JaG0Iujskia/6383b0c0bce36a94298960c163495843/image4.png"/></figure><p><a href="https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/"><b><u>QUIC</u></b></a> is a general-purpose transport protocol and <a href="https://www.rfc-editor.org/rfc/rfc9000.html"><u>Internet standard</u></a> that operates on top of UDP (instead of TCP), is encrypted by default, and solves several performance issues that plagued its predecessors. <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><b><u>HTTP/3</u></b></a><b> </b>is the latest version of the HTTP protocol, defining the application-layer protocol that runs on top of QUIC as its transport mechanism. MASQUE is a set of mechanisms for tunneling traffic over HTTP. It extends the existing HTTP CONNECT model, to allow tunneling UDP and IP traffic. This is especially efficient when combined with the QUIC’s <a href="https://datatracker.ietf.org/doc/html/rfc9221"><u>unreliable datagram extension</u></a>. </p><p>For example, we can use MASQUE’s <a href="https://www.rfc-editor.org/rfc/rfc9484.html"><u>CONNECT-IP method</u></a> to establish a tunnel that can send multiple concurrent requests over a single QUIC connection:</p><pre><code>HEADERS:method = CONNECT:protocol = connect-ip:scheme = https:path = /.well-known/masque/ip/*/*/:authority = example.orgcapsule-protocol = ?1</code></pre><p>The benefit these protocols have for the quality and security of everyone’s Internet browsing experience is real. Earlier transport protocols were built before the advent of smartphones and mobile networks, so QUIC was designed to support a mobile world, maintaining connections even in poorly connected networks, and minimizing disruptions as people switch rapidly between networks as they move through their day. Leveraging HTTP/3 as the application layer means that MASQUE is more like “normal” HTTP traffic on the Internet, meaning that it is easier to support, is compatible with existing firewall and security rules, and that it supports cryptographic agility (i.e. support for <a href="https://blog.cloudflare.com/post-quantum-for-all/"><u>post-quantum crypto</u></a>), making this traffic more secure and resilient in the long term.</p><div><h3>Get started now </h3><a href="#get-started-now"></a></div><p>All new installations of our 1.1.1.1 &amp; WARP apps support MASQUE, including iOS, Android, macOS, Windows, and Linux, and we’ve started to roll it out as the preferred protocol over WireGuard. <a href="https://developers.cloudflare.com/warp-client/get-started/"><u>On mobile</u></a>, to check if your connection is already secured over MASQUE, or change your device’s default option, you can toggle this setting via <i>Advanced &gt; Connection options &gt; Tunnel protocol:</i></p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3c7lAh7C5huXDUYt4v7B7w/a089967f8d9d668b2ded321f40b35cf4/Screenshot_2024-12-23_at_18.26.20.png"/></figure><p><sup><i>Protocol connection options shown here on the iOS app</i></sup></p><p>We offer the following options: </p><ul><li><p><b>Auto</b>: this allows the app to choose the protocol.</p></li><li><p><b>MASQUE</b>: always use MASQUE to secure your connection.</p></li><li><p><b>WireGuard</b>: always use WireGuard to secure your connection.</p></li></ul><p>On <a href="https://developers.cloudflare.com/warp-client/get-started/linux/"><u>desktop</u></a> versions, you can switch the protocol by using the WARP command-line interface. For example:</p><pre><code>warp-cli tunnel protocol set WireGuardwarp-cli tunnel protocol set MASQUE</code></pre><p>With this rollout, we're excited to see MASQUE deliver increased performance and stability to millions of users. Download <a href="https://one.one.one.one/"><u>one of the WARP apps</u></a> today!</p><div><h2>DEX now Generally Available: Announcing detailed device visibility with DEX Remote Captures</h2><a href="#dex-now-generally-available-announcing-detailed-device-visibility-with-dex-remote-captures"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2RkuqjgXZh8tmoj4W1narK/baaf61dcde00bbfa4cef71e5dbd2cc23/image2.png"/></figure><p><i>Following the successful beta launch of Digital Experience Monitoring (DEX), we are thrilled to announce the general availability of DEX, along with new Remote Captures functionality.</i></p><p>In today's hyper distributed environment, user experience is paramount. Recurring performance problems can lead to decreased user satisfaction, lost productivity, and damaged brand reputation.  <a href="https://www.cloudflare.com/learning/performance/what-is-digital-experience-monitoring/"><u>Digital Experience Monitoring (DEX)</u></a> offers a comprehensive solution to these challenges. Previous blog posts have discussed the solution and its capabilities. (<a href="https://blog.cloudflare.com/introducing-digital-experience-monitoring/"><i><u>Introducing Digital Experience Monitoring</u></i></a><i>, </i><a href="https://blog.cloudflare.com/digital-experience-monitoring-beta/"><i><u>Understanding end user-connectivity and performance with Digital Experience Monitoring, now available in beta</u></i></a><i>, </i><a href="https://blog.cloudflare.com/tag/dex"><i><u>What's new in Cloudflare One: Digital Experience monitoring notifications</u></i></a>)</p><div><h3>Introducing Remote Captures: PCAP and WARP Diag</h3><a href="#introducing-remote-captures-pcap-and-warp-diag"></a></div><p>Imagine this: an end user is frustrated with a slow application, and your IT team is struggling to pinpoint the root cause. Traditionally, troubleshooting such issues involved contacting the end user and asking them to manually collect and share network traffic data. This process is time-consuming, prone to errors, and often disruptive to the end user's workflow.</p><p>Building upon the capabilities of DEX, we are excited to introduce Remote Captures, a powerful new feature that empowers IT admins to gain unprecedented visibility into end-user devices and network performance. DEX now introduces Remote Captures, a powerful new feature that empowers IT admins to remotely initiate network <a href="https://en.wikipedia.org/wiki/Pcap"><u>packet captures (PCAP)</u></a> and <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/troubleshooting/warp-logs/"><u>WARP Diag logs</u></a> directly from your end users’ devices and capture diagnostic information automatically from our device client. This streamlined approach accelerates troubleshooting, reduces the burden on end users, and provides valuable insights into network performance and security.</p><div><h3>Why Remote Captures?</h3><a href="#why-remote-captures"></a></div><p>Remote Captures offer several key advantages. By analyzing detailed network traffic, IT teams can quickly pinpoint the root cause of network issues. Furthermore, granular network data empowers security teams to proactively detect and investigate potential threats. Finally, by identifying bottlenecks and latency issues, Remote Captures enable organizations to optimize network performance for a smoother user experience.</p><div><h3>How Remote Captures work</h3><a href="#how-remote-captures-work"></a></div><p>Initiating a Remote Capture is straightforward. First, select the specific device you wish to troubleshoot. Then, with a few simple clicks, start capturing network traffic and/or WARP Diag data. Once the capture is complete, download the captured data and utilize your preferred tools for in-depth analysis.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5NWQAhlUK8OQvuydQV0lb7/d93f6792e897120aa5e2f837a6ec7786/image3.png"/></figure><div><h3>Get started today</h3><a href="#get-started-today"></a></div><p>DEX Remote Captures are now available for Cloudflare One customers. They can be configured by going to <a href="https://dash.cloudflare.com/"><u>Cloudflare Dashboard</u></a> &gt;  Zero Trust &gt; DEX &gt; Remote Captures, and then selecting the device you wish to collect from. For more information, refer to <a href="https://developers.cloudflare.com/cloudflare-one/insights/dex/remote-captures/"><u>Remote captures</u></a>. This new capability highlights just one of the many ways our unified SASE platform helps organizations find and fix security issues across SaaS applications. <a href="https://dash.cloudflare.com/sign-up/teams"><u>Try it out now</u></a> using our free tier to get started.</p><div><h2>Never miss an update </h2><a href="#never-miss-an-update"></a></div><p>We hope you enjoy reading our roundup blog posts as we continue to build and innovate. Stay tuned to the <a href="https://blog.cloudflare.com/"><u>Cloudflare Blog</u></a> for the latest news and updates.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="What’s new in Cloudflare: MASQUE now powers 1.1.1.1 & WARP apps, DEX now generally available with Remote Captures" href="https://blog.cloudflare.com/masque-now-powers-1-1-1-1-and-warp-apps-dex-available-with-remote-captures/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">What’s new in Cloudflare: MASQUE now powers 1.1.1.1 & WARP apps, DEX now generally available with Remote Captures</span><span class="cap link fs12">https://blog.cloudflare.com/masque-now-powers-1-1-1-1-and-warp-apps-dex-available-with-remote-captures/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Sometimes I Cache: Implementing Lock-Free Probabilistic Caching</title>
    <link href="https://blog.imc.re/RSSBOX/rss/8a655bdc.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/8a655bdc.html</id>
    <published>2024-12-26T14:00:00.000Z</published>
    <updated>2024-12-26T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>HTTP caching is conceptually simple: if the response to a request is in the cache, serve it, and if not, pull it from your origin, put it in the cache, and return it. When the response is old, you repeat the process. If you are worried about too many requests going to your origin at once, you protect it with a <a href="https://developers.cloudflare.com/cache/concepts/revalidation/"><u>cache lock</u></a>: a small program, possibly distinct from your cache, that indicates if a request is already going to your origin. This is called cache revalidation.</p><p>In this blog post, we dive into how cache revalidation works, and present a new approach based on probability. For every request going to the origin, we simulate a die roll. If it’s 6, the request can go to the origin. Otherwise, it stays stale to protect our origin from being overloaded. To see how this is built and optimised, read on.</p><div><h2>Background</h2><a href="#background"></a></div><p>Let's take the example of an online image library. When a client requests an image, the service first checks its cache to see if the resource is present. If it is, it returns it. If it is not, the image server processes the request, places the response into the cache for a day, and returns it. When the cache expires, the process is repeated.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zdgMhKkU3cVKRk9T2CO2I/5302e6ef68cabd04b8bd65a7e416f033/BLOG-2639_2.png"/></figure><p><i>Figure 1: Uncached request goes to the origin</i></p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4J5KIW2CocyvlLXLuVBTWH/1f6174983e1fc1de72b48a9801da160e/BLOG-2639_3.png"/></figure><p><i>Figure 2: Cached request stops at the cache</i></p><p>And this is where things get complex. The image of a cat might be quite popular. Let's say it's requested 10 times per second. Let’s also assume the image server cannot handle more than 1 request per second. After a day, the cache expires. 10 requests hit the service. Given there are no up-to-date items in cache, these 10 requests are going to go directly to the image server. This problem is known as <a href="https://en.wikipedia.org/wiki/Cache_stampede"><u>cache stampede</u></a>. When the image server sees these 10 requests all happening at the same time, it gets overloaded.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3xDMJ6iloIjNHWpAbkfXWv/bee11bc4e1bb83a5b330529d8d98fbaa/BLOG-2639_4.png"/></figure><p><i>Figure 3: Image server overloaded upon cache expiration. This can happen to one or multiple users, across locations.</i></p><p>This all stops if the cache gets populated, as it can handle a lot more requests than the origin.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7LVi2SItiAUYWdEm3ll3ZH/368c6ff8e5d9017d2d3a8cc96246b73c/BLOG-2639_5.png"/></figure><p><i>Figure 4: Cache is populated and can handle the load. The image server is healthy again.</i></p><p>In the following sections, we build this image service, see how it can prevent cache stampede with a cache lock, then dive into probabilistic cache revalidation, and its optimisation.</p><div><h2>Setup</h2><a href="#setup"></a></div><p>Let's write this image service. We need an image, a server, and a cache. For the image we're going to use a picture of <a href="https://files.research.cloudflare.com/images/cat.jpg"><u>my cat</u></a>, Cloudflare Workers for the server, and the Cloudflare Cache API for caching.</p><p>Note to the reader: On purpose, we aren’t using <a href="https://developers.cloudflare.com/kv/"><u>Cloudflare KV</u></a> or <a href="https://developers.cloudflare.com/cache/"><u>Cloudflare CDN Cache</u></a>, because they already solve our cache validation problem by using a cache lock.</p><pre><code>let cache = caches.defaultconst CACHE_KEY = new Request('https://cache.local/')const CACHE_AGE_IN_S = 86_400 // 1 day<p>function cacheExpirationDate() &amp;#123;<br>  return new Date(Date.now() + 1000*CACHE_AGE_IN_S)<br>&amp;#125;</p><p>function fetchAndCache(ctx) &amp;#123;<br>  let response &#x3D; await fetch(‘<a href="https://files.research.cloudflare.com/images/cat.jpg&#39;">https://files.research.cloudflare.com/images/cat.jpg&#39;</a>)<br>  response &#x3D; new Response(<br>    await response.arrayBuffer(),<br>    &amp;#123;<br>        headers: &amp;#123;<br>          ‘Content-Type’: response.headers.get(‘Content-Type’),<br>          ‘Expires’: cacheExpirationDate().toUTCString(),<br>        &amp;#125;,<br>    &amp;#125;,<br>  )<br>  ctx.waitUntil(cache.put(CACHE_KEY, response.clone()))<br>  return response<br>&amp;#125;</p><p>export default &amp;#123;<br>  async fetch(request, env, ctx) &amp;#123;<br>    let cachedResponse &#x3D; await cache.match(CACHE_KEY)<br>    if (cachedResponse) &amp;#123;<br>        return cachedResponse<br>    &amp;#125;<br>    return fetchAndCache(ctx)<br>  &amp;#125;<br>&amp;#125;</code></pre></p><p><i>Codeblock 1: Image server with a non-collapsing cache</i></p><div><h2>Expectation about cache revalidation</h2><a href="#expectation-about-cache-revalidation"></a></div><p>The image service is receiving 10 requests per second, and it caches images for a day. It's reasonable to assume we would like to start revalidating the cache 5 minutes before it expires. The code evolves as follows:</p><pre><code>let cache = caches.defaultconst CACHE_KEY = new Request('https://cache.local/')const CACHE_AGE_IN_S = 86_400 // 1 dayconst CACHE_REVALIDATION_INTERVAL_IN_S = 300<p>function cacheExpirationDate() &amp;#123;<br>  &#x2F;&#x2F; Date constructor in workers takes Unix time in milliseconds<br>  &#x2F;&#x2F; Date.now() returns time in milliseconds as well<br>  return new Date(Date.now() + 1000*CACHE_AGE_IN_S)<br>&amp;#125;</p><p>async function fetchAndCache(ctx) &amp;#123;<br>  let response &#x3D; await fetch(‘<a href="https://files.research.cloudflare.com/images/cat.jpg&#39;">https://files.research.cloudflare.com/images/cat.jpg&#39;</a>)<br>  response &#x3D; new Response(<br>    await response.arrayBuffer(),<br>    &amp;#123;<br>        headers: &amp;#123;<br>          ‘Content-Type’: response.headers.get(‘Content-Type’),<br>          ‘Expires’: cacheExpirationDate().toUTCString(),<br>        &amp;#125;,<br>    &amp;#125;,<br>  )<br>  ctx.waitUntil(cache.put(CACHE_KEY, response.clone()))<br>  return response<br>&amp;#125;</p><p>&#x2F;&#x2F; Revalidation function added here<br>&#x2F;&#x2F; This is were we are going to focus our effort: should the request be revalidated ?<br>function shouldRevalidate(expirationDate) &amp;#123;<br>  let remainingCacheTimeInS &#x3D; (expirationDate.getTime() - Date.now()) &#x2F; 1000</p><p>  return remainingCacheTimeInS &lt;&#x3D; CACHE_REVALIDATION_INTERVAL_IN_S<br>&amp;#125;</p><p>export default &amp;#123;<br>  async fetch(request, env, ctx) &amp;#123;<br>    let cachedResponse &#x3D; await cache.match(CACHE_KEY)<br>    if (cachedResponse) &amp;#123;<br>       &#x2F;&#x2F; revalidation happens only if the request was cached. Otherwise, the resource is fetched anyway<br>        if (shouldRevalidate()) &amp;#123;<br>            ctx.waitUntil(fetchAndCache(ctx))<br>        &amp;#125;<br>        return cachedResponse<br>    &amp;#125;<br>    return fetchAndCache(ctx)<br>  &amp;#125;<br>&amp;#125;</code></pre></p><p><i>Codeblock 2: Image server with early-revalidation and a non-collapsing cache</i></p><p>That code works, and we can now revalidate 5 minutes in advance of cache expiration. However, instead of fetching the image from the origin server at expiration time, all requests are going to be made 5 minutes in advance, and that does not solve our cache stampede problem. This happens no matter if requests are coming to a single location or not, given the code above does not collapse requests.</p><p>To solve our cache stampede problem, we need the revalidation process to not send too many requests at the same time. Ideally, we would like only one request to be sent between <code>expiration - 5min</code> and <code>expiration</code>.</p><div><h2>The usual solution: a cache lock</h2><a href="#the-usual-solution-a-cache-lock"></a></div><p>To make sure there is only one request at a time going to the origin server, the solution that's usually deployed is a cache lock. The idea is that for a specific item, a cat picture in our case, requests to the origin try to obtain a lock. The request obtaining the lock can go to the origin, the others will serve stale content.</p><p>The lock has two methods: <code>try_lock()</code> and <code>unlock</code>.* <code>try_lock</code> if the lock is free, take it and return <code>true</code>. If not, return <code>false</code>.* <code>unlock</code> releases the lock.</p><p>Such a lock can be implemented as a <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/"><u>Cloudflare RPC service</u></a>:</p><pre><code>import &#123; WorkerEntrypoint &#125; from 'cloudflare:workers'<p>class Lock extends WorkerEntryPoint &amp;#123;<br>  async try_lock(key) &amp;#123;<br>    let value &#x3D; await this.ctx.storage.get(key)<br>    if (!value) &amp;#123;<br>        await this.ctx.storage.put(key, true)<br>        return true<br>    &amp;#125;<br>    return false<br>  &amp;#125;</p><p>  unlock() &amp;#123;<br>    return this.ctx.storage.delete(key)<br>  &amp;#125;<br>&amp;#125;<br></code></pre></p><p><i>Codeblock 3: Lock service implemented with a Durable Object</i></p><p>That service can then be used as a cache lock.</p><pre><code>// CACHE_LOCK is an instantiation of the above binding// Assuming the above is deployed as a worker with name `lock`// It can be bound in wrangler.toml as follows// services = [ &#123; binding = "CACHE_LOCK", service = "lock" &#125; ]<p>const LOCK_KEY &#x3D; “cat_image_service”</p><p>async function fetchAndCache(env, ctx) &amp;#123;<br>  let response &#x3D; await fetch(‘…’)<br>  ctx.waitUntil(env.CACHE_LOCK.unlock(LOCK_KEY))<br>  …<br>&amp;#125;</p><p>function shouldRevalidate(env, expirationDate) &amp;#123;<br>  let remainingCacheTimeInS &#x3D; (expirationDate.getTime() - Date.now()) &#x2F; 1000</p><p>  &#x2F;&#x2F; check if the expiry window is now, and then if the revalidation lock is available. if it is, take it<br>  return remainingCacheTimeInS &lt;&#x3D; CACHE_REVALIDATION_INTERVAL_IN_S &amp;&amp; env.CACHE_LOCK.try_lock(LOCK_KEY)<br>&amp;#125;<br></code></pre></p><p><i>Codeblock 4: Image server with early-revalidation and a cache using a cache-lock</i></p><p>Now you might say "Et voilà. No need for probabilities and mathematics. Peak engineering has triumphed." And you might be right, in most cases. That's why cache locks are so <a href="https://developers.cloudflare.com/cache/concepts/revalidation/"><u>predominant</u></a>: they are conceptually simple, deterministic for the same key, and scale well with predictable resource usage.</p><p>On the other hand, cache locks add latency and fallibility. To take ownership of a lock, cache revalidation has to contact the lock service. This service is shared across different processes, possibly different machines in different locations. Requests therefore take time. In addition, this service might be unavailable. Probabilistic cache revalidation does not suffer from these, given it does not reach out to an external service but rolls a die with the local randomness generator. It does so at the cost of not guaranteeing the number of requests going to the origin server: maybe zero for an extended period, maybe more than one. On average, this is going to be fine. But there can be border cases, similar to how one can roll a die 10 times and get 10 sixes. It’s unlikely, but not unrealistic, and certain services need that certainty. In the following sections, we dissect this approach.</p><div><h2>First dive into probabilities given a stable request rate</h2><a href="#first-dive-into-probabilities-given-a-stable-request-rate"></a></div><p>A first approach is to reduce the number of requests going to the origin server. Instead of always sending a request to revalidate, we are going to send 1 out of 10. This means that instead of sending 10 requests per second when the cache is invalidated, we send 1 per second.</p><p>Because we don't have a lock, we do that with probabilities. We set the probability of sending a request to the origin to be $p=\frac&#123;1&#125;&#123;10&#125;$. With a rate of 10 requests per second, after 1 second, the expectancy of a request being sent to the origin is $1-(1-p)^10=65\%$. We draw the evolution of the function $E(r, t)=1-(1-p)^&#123;r \times t&#125;$ representing the expectancy of a request being sent to the server over time. $r = 10$ and is the request rate.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78UvqHlQ6Se6cifbla3ozw/111decceed55ba1387b78a75e28f04cc/BLOG-2639_6.jpg"/></figure><p><i>Figure 5: Revalidation time $E(t)$ with $r=10$ and $p=\frac&#123;1&#125;&#123;10&#125;$. At time $t$, $E(t)$ is the probability that an early revalidation occurred.</i></p><p>The graph moves very quickly towards $1$. This means we might still have space to reduce the number of requests going to our origin server. We can set a lower probability, such as $p_2=\frac&#123;1&#125;&#123;500&#125;$ (1 request every 5 seconds on average). The graph looks as follows:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/TtLqU9nyKqtYxIz5oJefX/fba679de0599854ba344f19bd0b97939/BLOG-2639_7.jpg"/></figure><p><i>Figure 6: Revalidation time $E(t)$ with $r=10$ and $p=\frac&#123;1&#125;&#123;500&#125;$.</i></p><p>This looks great. Let's implement it.</p><pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300const CACHE_REVALIDATION_PROBABILITY = 1/500<p>function shouldRevalidate(expirationDate) &amp;#123;<br>  let remainingCacheTimeInS &#x3D; (expirationDate.getTime() - Date.now()) &#x2F; 1000</p><p>  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) &amp;#123;<br>    return false<br>  &amp;#125;<br>  if (remainingCacheTimeInS &lt;&#x3D; 0) &amp;#123;<br>    return true<br>  &amp;#125;<br>  return Math.random() &lt; CACHE_REVALIDATION_PROBABILITY<br>&amp;#125;<br></code></pre></p><p><i>Codeblock 5: Image server with early-revalidation and a probabilistic cache using uniform distribution</i></p><p>That's it. If the cache is not close to expiration, we don't revalidate. If the cache is expired, we revalidate. Otherwise, we revalidate based on a probability.</p><div><h2>Adaptive cache revalidation</h2><a href="#adaptive-cache-revalidation"></a></div><p>Until now, we assumed the picture of the cat received a stable request rate. However, for a real service, this does not necessarily hold. For instance, if instead of 10 requests per second, imagine the service receives only 1. The expectancy function does not look as good. After 5 minutes (300s), $E(r=1, t=300)=45\%$. On the other hand, if the image service is receiving 10,000 requests per second, $E(r=10000, t = 300) \approx 100\%$, but our server receives on average $10000 \times \frac&#123;1&#125;&#123;500&#125; = 20$ requests per second. It would be ideal to design a probability function that would adapt to the request rate.</p><p>That function would return a low probability when expiration time is far in the future, and increase over time such that the cache is revalidated before it expires. It would cap the request rate going to the origin server.</p><p>Let’s design the variation of probability $p$ over 5 minutes. When far from the expiration, the probability to revalidate should be low. This should help match the high request rate. For example, with a request rate of 10k requests per second, we would like the revalidation probability $p$ to be $\frac&#123;1&#125;&#123;100000&#125;$. This ensures the request rates seen by our server are going to be low on average, at about 1 request every 10 seconds. As time passes, we increase this probability to allow for revalidation even at a lower request rate.</p><table><tr><td><p><b>Time to expiration $t$ (in s)</b></p></td><td><p><b>Revalidation probability $p$</b></p></td><td><p><b>Target request rate $r$ (in rps)</b></p></td></tr><tr><td><p>300</p></td><td><p>1/100000</p></td><td><p>10000</p></td></tr><tr><td><p>240</p></td><td><p>1/10000</p></td><td><p>1000</p></td></tr><tr><td><p>180</p></td><td><p>1/1000</p></td><td><p>100</p></td></tr><tr><td><p>120</p></td><td><p>1/100</p></td><td><p>10</p></td></tr><tr><td><p>60</p></td><td><p>1/10</p></td><td><p>1</p></td></tr><tr><td><p>0</p></td><td><p>1</p></td><td><p>-</p></td></tr></table><p><i>Table 1: Variation of revalidation probability over time</i></p><p>For each of these intervals, there is a high likelihood that a request rate <code>$r$</code> will trigger a cache revalidation, and low likelihood that a lower request rate will trigger it. If it does, it's ok.</p><p>We can update our revalidation function as follows:</p><pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300const CACHE_REVALIDATION_PROBABILITY_PER_MIN = [1/100_000, 1/10_000, 1/1000, 1/100, 1/10, 1]<p>function shouldRevalidate(expirationDate) &amp;#123;<br>  let remainingCacheTimeInS &#x3D; (expirationDate.getTime() - Date.now()) &#x2F; 1000</p><p>  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) &amp;#123;<br>    return false<br>  &amp;#125;<br>  if (remainingCacheTimeInS &lt;&#x3D; 0) &amp;#123;<br>    return true<br>  &amp;#125;<br>  let currentMinute &#x3D; Math.floor(remainingCacheTimeInS&#x2F;60)<br>  return Math.random() &lt; CACHE_REVALIDATION_PROBABILITY_PER_MIN[currentMinute]<br>&amp;#125;<br></code></pre></p><p><i>Codeblock 6: Image server with early-revalidation and a probabilistic cache using piecewise uniform distribution</i></p><div><h2>Optimal cache stampede solution</h2><a href="#optimal-cache-stampede-solution"></a></div><p>There seems to be a lot of decisions going on here. To solve this, we can reference an academic paper written by A Vattani, T Chierichetti, and K Lowenstein in 2015 called <a href="https://cseweb.ucsd.edu/~avattani/papers/cache_stampede.pdf"><u>Optimal Probabilistic Cache Stampede Prevention</u></a>. If you read it, you'll recognise that what we have been discussing until now is close to what the paper presents. For instance, both the cache revalidation algorithm structure and the early revalidation function look similar.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MLwwNsci3XxhK0uAvWcFu/62a17cc9056d6b12832160acc9e40fb9/BLOG-2639_8.png"/></figure><p><i>Figure 7: Probabilistic early expiration of a cache item as defined by Figure 2 of Optimal Probabilistic Cache Stampede Prevention paper. In our case, $\mathcal&#123;D&#125;=300$</i></p><p>One takeaway from the paper is that instead of discretization, with a probability from 0 to 60s, then from 60s to 120s, …, the probability function can be continuous. Instead of a fixed $p$, there is a function $p(t)$ of time $t$.</p><p>$p(t)=e^&#123;-\lambda (expiry-t)&#125;, \text&#123; with &#125; expiry=300, \text&#123; and &#125; t \in [0, 300]$</p><p>We call $\lambda$ the steepness parameter, and set it to $\frac&#123;1&#125;&#123;300&#125;$, $300$ being our early expiration gap.</p><p>The expectancy over time is $E(r, t)=1-e^&#123;-rλt&#125;$. This leads to the expectancy below for various request rates. You can note that when $r=1$, there is not a $100%$ chance that the request will be revalidated before expiry.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3lHElc96ZDNbcMfXVQ9pUm/e70e98b4be158dcde11b95366a736742/BLOG-2639_9.jpg"/></figure><p><i>Figure 8: Revalidation time $E(t)$ for multiple $r$ with an exponential distribution.</i></p><p>This leads to the final code snippet:</p><pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300const REVALIDATION_STEEPNESS = 1/300<p>function shouldRevalidate(expirationDate) &amp;#123;<br>  let remainingCacheTimeInS &#x3D; (expirationDate.getTime() - Date.now()) &#x2F; 1000</p><p>  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) &amp;#123;<br>    return false<br>  &amp;#125;<br>  if (remainingCacheTimeInS &lt;&#x3D; 0) &amp;#123;<br>    return true<br>  &amp;#125;<br>&#x2F;&#x2F; p(t) is evaluated here<br>  return Math.random() &lt; Math.exp(-REVALIDATION_STEEPNESS*remainingCacheTimeInS)<br>&amp;#125;<br></code></pre></p><p><i>Codeblock 7: Image server with early-revalidation and a probabilistic cache using exponential distribution</i></p><p>And that's it. Given <code>Date.now(</code>) has a granularity, and is not continuous, it would also be possible to discretise these functions, even though the gains are minimal. This is what we have done in a <a href="https://github.com/cloudflare/privacypass-issuer/blob/main/src/cache.ts#L60-L103"><u>production worker implementation</u></a>, where the number of requests is important. It is a service that benefits from caching for performance consideration, and that cannot use built-in <a href="https://developers.cloudflare.com/workers/runtime-apis/cache/"><u>stale-while-revalidate</u></a> from within Cloudflare workers. Probabilistic cache stampede prevention is well-suited here, as no new component has to be built, and it performs well at different request rates.</p><div><h2>Conclusion</h2><a href="#conclusion"></a></div><p>We have seen how to solve cache stampede without a lock, its implementation, and why it is optimal. In the real world, you likely will not encounter this issue: either because it’s good enough to optimize your origin service to serve more requests, or because you can leverage a CDN cache. In fact, most HTTP caches provide an API that follows <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"><u>Cache Control</u></a>, and likely have all the tools you need. This primitive is also built into certain products, such as <a href="https://developers.cloudflare.com/kv/platform/limits/"><u>Cloudflare KV</u></a>.</p><p>If you have not done so, you can go and experiment with all the code snippets presented in this blog on the Cloudflare Workers Playground at <a href="https://cloudflareworkers.com"><u>cloudflareworkers.com</u></a>.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Sometimes I cache: implementing lock-free probabilistic caching" href="https://blog.cloudflare.com/sometimes-i-cache/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Sometimes I cache: implementing lock-free probabilistic caching</span><span class="cap link fs12">https://blog.cloudflare.com/sometimes-i-cache/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Announcing CodeQL Community Packs</title>
    <link href="https://blog.imc.re/RSSBOX/rss/d4d7562.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/d4d7562.html</id>
    <published>2024-12-26T06:17:51.000Z</published>
    <updated>2024-12-26T06:17:51.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>We are excited to introduce the new <a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/">CodeQL Community Packs</a>, a comprehensive set of queries and models designed to enhance your code analysis capabilities. These packs are tailored to augment the standard set of CodeQL queries, providing additional resources for security researchers and developers alike.</p><h2 id="why">Why?<a aria-label="Why?" class="heading-link pl-2 text-italic text-bold" href="#why"></a></h2><p>CodeQL is a semantic code analysis tool that allows developers to query their codebases as databases, enabling the identification of vulnerabilities, bugs, and patterns efficiently.</p><p>The standard set of CodeQL queries is focused on accuracy and low false positive rates, which is ideal for integration into CI/CD pipelines where alerts are primarily handled by developers. However, when alerts are operated by security engineers or researchers, the balance between false positives and false negatives can be adjusted to prioritize low false negatives, ensuring no bugs are left behind—albeit at the cost of more triaging.</p><h2 id="what">What?<a aria-label="What?" class="heading-link pl-2 text-italic text-bold" href="#what"></a></h2><p>The CodeQL Community Packs is a set of CodeQL packs to augment the standard set queries. They include three main types of packs:</p><ul><li><strong>Model packs</strong>: these packs contain additional models of Taint Tracking sources, sinks, and summaries for libraries and frameworks that are not supported by the default suites.</li><li><strong>Query packs</strong>: these packs contain additional security and audit queries to help identify potential vulnerabilities and improve code quality.</li><li><strong>Library packs</strong>: designed to be used by query packs, these packs do not contain queries themselves but provide essential libraries for more comprehensive analysis.</li></ul><h2 id="how">How?<a aria-label="How?" class="heading-link pl-2 text-italic text-bold" href="#how"></a></h2><p>The GitHub Security Lab has been extensively using these packs for the last few years and <a href="https://securitylab.github.com/codeql-wall-of-fame/">as our records show</a>, they turned out to be very fruitful.</p><p><img><img alt="Badge that says 381 vulnerabilities found with the help of CodeQL." class="aligncenter size-large wp-image-81780 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="529" loading="lazy" sizes="auto, (max-width: 683px) 100vw, 683px" src="https://github.blog/wp-content/uploads/2024/12/381-vulnerabilities.png?w=683&amp;resize=683%2C529" width="683"/></img></p><p>In addition to the additional queries and models provided by the community packs, we have also been using the audit queries, which proved invaluable when running deep-dive manual code reviews, such as the ones we did for <a href="https://github.blog/security/vulnerability-research/github-security-lab-audited-datahub-heres-what-they-found/">Datahub</a> and <a href="https://github.blog/security/vulnerability-research/securing-our-home-labs-home-assistant-code-review/">Home Assistant</a>. Being able to list all the files which introduced untrusted data into the application or that perform security-relevant operations was really helpful when exploring unfamiliar huge codebases, such as the Home Assistant one.</p><p><img><img alt="Screenshot of the section 'Analyzing the code base' from a blog post about Home Assistant." class="aligncenter size-large wp-image-81781 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="198" loading="lazy" sizes="auto, (max-width: 746px) 100vw, 746px" src="https://github.blog/wp-content/uploads/2024/12/home-assistant-codebas.png?w=746&amp;resize=746%2C198" width="746"/></img></p><h2 id="whats-in-the-community-packs">What’s in the community packs?<a aria-label="What’s in the community packs?" class="heading-link pl-2 text-italic text-bold" href="#whats-in-the-community-packs"></a></h2><p>The CodeQL Community Packs offer a variety of additional queries and models for languages, such as Java, C#, and Python. These packs are designed to move the Signal to Noise (SNR) ratio closer to the low false negatives end of the spectrum, making them particularly useful for security researchers.</p><p>For example, the Java packs include:</p><ul><li><a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/tree/main/java/src">Java queries</a><ul><li><strong>CVEs</strong>: queries for known CVEs such as Log4Shell.</li><li><strong>Security</strong>: dozens of new security queries contributed by CodeQL engineers and security researchers from the GitHub Security Lab, but also by the broader community of security researchers.</li><li><strong>Audit Exploration</strong>: queries to list all files, dependencies, untrusted data entry points, and hazardous sinks.</li><li><strong>Audit Templates</strong>: templates to build your own taint tracking queries, explore data paths, or “hoist” sinks to public method parameters.</li><li><strong>Library sources</strong>: special queries designed to find third-party APIs called with untrusted data.</li></ul></li><li><a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/tree/main/java/ext">Java extension models</a><ul><li>This pack contains additional models which define additional remote flow sources, summaries and sinks for hundreds of APIs.</li></ul></li><li><a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/blob/main/java/lib/qlpack.yml">Java libraries</a><ul><li>A collection of predicates and classes used by Java queries.</li></ul></li><li><a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/tree/main/java/ext-library-sources">Library extension models</a><ul><li>Additional threat model pack which defines library API method parameters as a source of untrusted data. </li></ul></li></ul><p><img><img alt="Screenshot of what is included in the Java CodeQL Community Pack" class="aligncenter size-large wp-image-81783 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="1024" loading="lazy" sizes="auto, (max-width: 669px) 100vw, 669px" src="https://github.blog/wp-content/uploads/2024/12/file-tree.png?w=669&amp;resize=669%2C1024" width="669"/></img></p><h2 id="library-extension-models">Library extension models<a aria-label="Library extension models" class="heading-link pl-2 text-italic text-bold" href="#library-extension-models"></a></h2><p>Remember Log4Shell? It was relatively easy for a SAST tool to detect, as the JNDI injection sink was well-known and <a href="https://github.com/github/codeql/blob/06b1d8e448c0f42848ca24500cac60ef6934f338/java/ql/lib/ext/javax.naming.model.yml">covered by existing CodeQL models</a> at that time. However, CodeQL’s default threat model, like most SAST tools, is based on modeling untrusted data as data that comes from the network. Therefore, CodeQL could have reported Log4Shell if we had analyzed an application that took untrusted data from the network (for example, a web application) and passed this untrusted data to Log4J logger methods.</p><p>To enable CodeQL to report such a data flow path, we would have needed to provide CodeQL with the source code of both the web application and Log4J. Could we have reported Log4Shell by analyzing only the Log4J source code? Certainly! But we would have needed a different threat model, one in which the arguments of logger methods such as <code>info</code> or <code>error</code> were considered sources of untrusted data. But how could CodeQL know that these methods could introduce untrusted data in the first place?</p><p>To support such a threat model, we developed the library source packs. We analyzed thousands of applications that took untrusted data and passed it to third-party APIs (such as Log4J’s <code>error</code> method). This analysis resulted in a list of third-party library methods used in real applications that are passed untrusted data.</p><p>Once we collected this list, which contained API methods such as Log4J’s <code>AbstractLogger.error</code>, we used it to define new sources of untrusted data to be used when scanning library code, such as Log4J code. By doing this with Log4J code, we were able to first identify that logger methods can be called with untrusted data from network requests and second, report a JNDI injection in Log4J code when using the new library source QL packs!</p><p><img><img alt="Screenshot of an open issue titled 'JNDI-lookup with user-controlled name.' Beneath the title, there is a banner reading 'Speed up the remediation of this alert with Copilot Autofix for CodeQL.'" class="aligncenter size-large wp-image-81784 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="665" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2024/12/kndi-lookup.png?w=1024&amp;resize=1024%2C665" width="1024"/></img></p><h2 id="exploration-queries">Exploration queries<a aria-label="Exploration queries" class="heading-link pl-2 text-italic text-bold" href="#exploration-queries"></a></h2><p>Reviewing a new, unfamiliar codebase is a difficult and lengthy process. Reducing the review surface to the most significant and relevant files is crucial to making this process as efficient as possible.</p><p>When faced with similar reviews, the GitHub Security Lab likes to first map out the new codebase. We do this by listing all the entry points where potentially untrusted data enters the application and identifying operations that can be hazardous, such as file reads/writes, deserialization operations, or network requests.</p><p>To achieve this, we use the <a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/blob/main/java/src/audit/explore/RemoteFlowSources.ql">RemoteFlowSources.ql</a> query, which provides a list of all places identified by CodeQL where untrusted data enters the application. We also use the <a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/tree/main/ql/hotspots">HotSpots</a> query, which returns a list of all hazardous sinks in the application, regardless of evidence of untrusted data flowing into them.</p><p>In addition to providing a good initial heat map of the codebase, this approach helps us better understand how well CodeQL covers the used libraries and whether additional modeling is needed.</p><h3 id="how-to-use-them">How to use them?<a aria-label="How to use them?" class="heading-link pl-2 text-italic text-bold" href="#how-to-use-them"></a></h3><p>The community packs are regular <a href="https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/customizing-analysis-with-codeql-packs">CodeQL packs</a> and can be used both as part of GitHub’s code scanning workflows and with the CodeQL CLI.</p><p>To use the CodeQL community packs in code scanning, specify a <code>with: packs:</code> entry in the <code>uses: github/codeql-action/init@v3</code> section of your CodeQL code scanning workflow. See the examples below.</p><p>Adding the community packs <strong>library extension models</strong> to a scan:</p><pre><code>- name: Initialize CodeQL        uses: github/codeql-action/init@v3        with:          languages: java          packs: githubsecuritylab/codeql-java-library-sources,githubsecuritylab/codeql-java-extensions</code></pre><p>Running the community packs <strong>additional security queries</strong>:</p><pre><code>- name: Initialize CodeQL        uses: github/codeql-action/init@v3        with:          languages: java                    queries: java          packs: githubsecuritylab/codeql-java-queries</code></pre><p>Running the community packs <strong>additional security queries</strong> with the additional community packs <strong>extension models</strong>:</p><pre><code>- name: Initialize CodeQL        uses: github/codeql-action/init@v3        with:          languages: java                    queries: java          packs: githubsecuritylab/codeql-java-extensions,githubsecuritylab/codeql-java-queries</code></pre><p>Similarly, you can use the community packs from the CLI.</p><p>Adding the community packs <strong>library extension models</strong> to a scan:</p><pre><code>codeql database analyze --download &lt;CodeQL DB&gt; --model-packs githubsecuritylab/codeql-java-extensions --model-packs githubsecuritylab/codeql-java-library-sources codeql/java-queries --format=sarif-latest --output=scan.sarif --sarif-add-file-contents</code></pre><p>Running the community packs additional <strong>security queries</strong>:</p><pre><code>codeql database analyze --download &lt;CodeQL DB&gt; githubsecuritylab/codeql-java-queries --format=sarif-latest --output=scan.sarif --sarif-add-file-contents</code></pre><p>Running the community packs additional <strong>security queries</strong> with the additional community packs <strong>extension models</strong>:</p><pre><code>codeql database analyze --download db --model-packs githubsecuritylab/codeql-java-extensions githubsecuritylab/codeql-java-queries --format=sarif-latest --output=scan.sarif --sarif-add-file-contents</code></pre><h2 id="how-to-contribute">How to contribute?<a aria-label="How to contribute?" class="heading-link pl-2 text-italic text-bold" href="#how-to-contribute"></a></h2><p>The most important aspect of the community packs is the community involvement! Sharing your models and queries with the community is the best way to help secure the open source software we all depend on. Contributions can range from simple <a href="https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/">Model As Data (MaD)</a> lines to existing extension files or even the creation of new queries that model new vulnerability classes. <a href="https://github.com/GitHubSecurityLab/CodeQL-Community-Packs/blob/main/CONTRIBUTING.md">Every contribution is welcome</a>!</p></body></html><p>The post <a href="https://github.blog/security/vulnerability-research/announcing-codeql-community-packs/">Announcing CodeQL Community Packs</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Announcing CodeQL Community Packs" href="https://github.blog/security/vulnerability-research/announcing-codeql-community-packs/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Announcing CodeQL Community Packs</span><span class="cap link fs12">https://github.blog/security/vulnerability-research/announcing-codeql-community-packs/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>Un Experimento Rápido: Translating Cloudflare Stream Captions With Workers AI</title>
    <link href="https://blog.imc.re/RSSBOX/rss/302a2768.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/302a2768.html</id>
    <published>2024-12-24T14:00:00.000Z</published>
    <updated>2024-12-24T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <div></div><p></p><p><a href="https://www.cloudflare.com/products/cloudflare-stream"><u>Cloudflare Stream</u></a> launched AI-powered <a href="https://blog.cloudflare.com/stream-automatic-captions-with-ai"><u>automated captions</u></a> to transcribe English in on-demand videos in March 2024. Customers' immediate next questions were about other languages — both <i>transcribing</i> audio from other languages, and <i>translating</i> captions to make subtitles for other languages. As the Stream Product Manager, I've thought a lot about how we might tackle these, but I wondered…</p><p><b>What if I just translated a generated </b><a href="https://en.wikipedia.org/wiki/WebVTT"><b><u>VTT</u></b></a><b> (caption file)? Can we do that?</b> I hoped to use <a href="https://www.cloudflare.com/developer-platform/products/workers-ai/"><u>Workers AI</u></a> to conduct a quick experiment to learn more about the problem space, challenges we may find, and what platform capabilities we can leverage.</p><p>There is a <a href="https://github.com/elizabethsiegle/cfworkers-ai-translate"><u>sample translator demo</u></a> in Workers documentation that uses the “<a href="https://developers.cloudflare.com/workers-ai/models/m2m100-1.2b/"><u>m2m100-1.2b</u></a>” Many-to-Many multilingual translation model to translate short input strings. I decided to start there and try using it to translate some of the English captions in my Stream library into Spanish.</p><div><h2>Selecting test content</h2><a href="#selecting-test-content"></a></div><p>I started with my <a href="https://customer-eq7kiuol0tk9chox.cloudflarestream.com/13297d6aa7c112b771c8d25d16fd3155/iframe?defaultTextTrack=en"><u>short demo video announcing</u></a> the transcription feature. I wanted a Worker that could read the VTT captions file from Stream, isolate the text content, and run it through the model as-is.</p><p>The first step was parsing the input. A VTT file is a text file that contains a sequence of numbered “cues,” each with a number, a start and end time, and text content. </p><pre><code>WEBVTTX-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 <p>1<br>00:00:00.000 –&gt; 00:00:02.580<br>Good morning, I’m Taylor Smith,</p><p>2<br>00:00:02.580 –&gt; 00:00:03.520<br>the Product Manager for Cloudflare</p><p>3<br>00:00:03.520 –&gt; 00:00:04.460<br>Stream. This is a quick</p><p>4<br>00:00:04.460 –&gt; 00:00:06.040<br>demo of our AI-powered automatic</p><p>5<br>00:00:06.040 –&gt; 00:00:07.580<br>subtitles feature. These subtitles</p><p>6<br>00:00:07.580 –&gt; 00:00:09.420<br>were generated with Cloudflare WorkersAI</p><p>7<br>00:00:09.420 –&gt; 00:00:10.860<br>and the Whisper Model,</p><p>8<br>00:00:10.860 –&gt; 00:00:12.020<br>not handwritten, and it took</p><p>9<br>00:00:12.020 –&gt; 00:00:13.940<br>just a few seconds.</code></pre></p><div><h2>Parsing the input</h2><a href="#parsing-the-input"></a></div><p>I started with a simple Worker that would fetch the VTT from Stream directly, run it through a <a href="https://github.com/tsmith512/vtt-translate/blob/trunk/src/index.ts#L54"><u>function I wrote to deconstruct the cues</u></a>, and return the timestamps and original text in an easier to review format.</p><pre><code>export default &#123;  async fetch(request: Request, env: Env, ctx): Promise&lt;Response&gt; &#123;    // Step One: Get our input.    const input = await fetch(PLACEHOLDER_VTT_URL)      .then(res =&gt; res.text()); <pre><code>// Step Two: Parse the VTT file and get the textconst captions = vttToCues(input);// Done: Return what we have.return new Response(captions.map(c =&amp;gt;  (`#$&amp;#123;c.number&amp;#125;: $&amp;#123;c.start&amp;#125; --&amp;gt; $&amp;#123;c.end&amp;#125;: $&amp;#123;c.content.toString()&amp;#125;`)).join(&#39;\n&#39;));</code></pre><p>  &amp;#125;,<br>&amp;#125;;</code></pre></p><p>That returned this text:</p><pre><code>#1: 0 --&gt; 2.58: Good morning, I'm Taylor Smith,#2: 2.58 --&gt; 3.52: the Product Manager for Cloudflare#3: 3.52 --&gt; 4.46: Stream. This is a quick#4: 4.46 --&gt; 6.04: demo of our AI-powered automatic#5: 6.04 --&gt; 7.58: subtitles feature. These subtitles#6: 7.58 --&gt; 9.42: were generated with Cloudflare WorkersAI#7: 9.42 --&gt; 10.86: and the Whisper Model,#8: 10.86 --&gt; 12.02: not handwritten, and it took#9: 12.02 --&gt; 13.94: just a few seconds.</code></pre><div><h2>AI-ify</h2><a href="#ai-ify"></a></div><p>As a proof of concept, I adapted a snippet from the demo into my Worker. In the example, the target language and input text are extracted from the user’s request. In my experiment, I decided to hardcode the languages. Also, I had an array of input objects, one for each cue, not just a string. After interpreting the caption input <i>but before returning a response</i>, I used a map callback to parallelize all the AI.run() calls to translate each cue, so they could execute asynchronously and in-place, then awaited them all to resolve. Ultimately, the AI inference call itself is the simplest part of the script.</p><pre><code>await Promise.all(captions.map(async (q) =&gt; &#123;  const translation = await env.AI.run(    "@cf/meta/m2m100-1.2b",    &#123;      text: q.content,      source_lang: "en",      target_lang: "es",    &#125;  ); <p>  q.content &#x3D; translation?.translated_text ?? q.content;<br>&amp;#125;));</code></pre></p><p>Then the script returns the translated output in the format from before.</p><p>Of course, this is not a scalable or error-tolerant approach for production use because it doesn’t make affordances for rate limiting, failures, or processing bigger throughput. But for a few minutes of tinkering, it taught me a lot.</p><pre><code>#1: 0 --&gt; 2.58: Buen día, soy Taylor Smith.#2: 2.58 --&gt; 3.52: El gerente de producto de Cloudflare#3: 3.52 --&gt; 4.46: Rápido, esto es rápido#4: 4.46 --&gt; 6.04: La demostración de nuestro automático AI-powered#5: 6.04 --&gt; 7.58: Los subtítulos, estos subtítulos#6: 7.58 --&gt; 9.42: Generado con Cloudflare WorkersAI#7: 9.42 --&gt; 10.86: y el modelo de susurro,#8: 10.86 --&gt; 12.02: No se escribió, y se tomó#9: 12.02 --&gt; 13.94: Sólo unos segundos.</code></pre><p>A few immediate observations: first, these results came back surprisingly quickly and the Workers AI code worked on the first try! Second, evaluating the quality of translation results is going to depend on having team members with expertise in those languages. Because — third, as a novice Spanish speaker, I can tell this output has some issues.</p><p>Cues 1 and 2 are okay, but 3 is not (“Fast, this is fast” from “[Cloudflare] Stream. This is a quick…”). Cues 5 through 9 had several idiomatic and grammatical issues, too. I theorized that this is because Stream splits the English captions into groups of 4 or 5 words to make them easy to <i>read</i> quickly in the overlay. But that also means sentences and grammatical constructs are interrupted. When those fragments go to the translation model, there isn’t enough context.</p><div><h2>Consolidating sentences</h2><a href="#consolidating-sentences"></a></div><p>I speculated that reconstructing sentences would be the most effective way to improve translation quality, so I made that the one problem I attempted to solve within this exploration. I added a rough <a href="https://github.com/tsmith512/vtt-translate/blob/trunk/src/index.ts#L132C7-L218"><u>pre-processor</u></a> in the Worker that tries to merge caption cues together and then splits them at sentence boundaries instead. In the process, it also adjusts the timing of the resulting cues to cover the same approximate timeframe.</p><p>Looking at each cue in order:</p><pre><code>// Break this cue up by sentence-ending punctuation.const sentences = thisCue.content.split(/(?&lt;=[.?!]+)/g);<p>&#x2F;&#x2F; Cut here? We have one fragment and it has a sentence terminator.<br>const cut &#x3D; sentences.length &#x3D;&#x3D;&#x3D; 1 &amp;&amp; thisCue.content.match(&#x2F;[.?!]&#x2F;);</code></pre></p><p>But if there’s a cue that splits into multiple sentences, cut it up and split the timing. Leave the final fragment to roll into the next cue:</p><pre><code>else if (sentences.length &gt; 1) &#123;  // Save the last fragment for later  const nextContent = sentences.pop();<p>  &#x2F;&#x2F; Put holdover content and all-but-last fragment into the content<br>  newContent +&#x3D; ‘ ‘ + sentences.join(‘ ‘);</p><p>  const thisLength &#x3D; (thisCue.end - thisCue.start) &#x2F; 2;</p><pre><code>result.push(&amp;#123;  number: newNumber,  start: newStart,  end: thisCue.start + (thisLength / 2), // End this cue early  content: newContent,&amp;#125;);// … then treat the next cue as a holdovercueLength = 1;newContent = nextContent;// Start the next consolidated cue halfway into this cue&#39;s original durationnewStart = thisCue.start + (thisLength / 2) + 0.001;// Set the next consolidated cue&#39;s number to this cue&#39;s numbernewNumber = thisCue.number;</code></pre><p>  &amp;#125;<br>&amp;#125;</code></pre></p><p>Applying that to the input, it generates sentence-grouped output, visualized here in green:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MzmQ0KAJBntBrqgwGAqTd/035d044fc9e70c9933c1406074de52b9/image2.png"/></figure><p>There are only 3 “new” cues, each starts at the beginning of a sentence. The consolidated cues are longer and might be harder to read when overlaid on a video, but they are complete grammatical units:</p><pre><code>#1: 0 --&gt; 3.755:  Good morning, I'm Taylor Smith, the Product Manager for Cloudflare Stream.#3: 3.756 --&gt; 6.425:  This is a quick demo of our AI-powered automatic subtitles feature.#5: 6.426 --&gt; 12.5:  These subtitles were generated with Cloudflare Workers AI and the Whisper Model, not handwritten, and it took just a few seconds.</code></pre><p>Translating this “prepared” input the same way as before:</p><pre><code>#1: 0 --&gt; 3.755: Buen día, soy Taylor Smith, el gerente de producto de Cloudflare Stream.#3: 3.756 --&gt; 6.425: Esta es una demostración rápida de nuestra función de subtítulos automáticos alimentados por IA.#5: 6.426 --&gt; 12.5: Estos subtítulos fueron generados con Cloudflare WorkersAI y el Modelo Whisper, no escritos a mano, y solo tomó unos segundos.</code></pre><p>¡Mucho mejor! [Much better!]</p><div><h2>Re-exporting to VTT</h2><a href="#re-exporting-to-vtt"></a></div><p>To use these translated captions on a video, they need to be <a href="https://github.com/tsmith512/vtt-translate/blob/trunk/src/index.ts#L228-L238"><u>formatted back into a VTT</u></a> with renumbered cues and properly formatted timestamps. Ultimately, the solution should <a href="https://developers.cloudflare.com/stream/edit-videos/adding-captions/#upload-a-file"><u>automatically upload them back to Stream</u></a>, too, but that is an established process, so I set it aside as out of scope. The final VTT result from my Worker is this:</p><pre><code>WEBVTT <p>1<br>00:00:00.000 –&gt; 00:00:03.754<br>Buen día, soy Taylor Smith, el gerente de producto de Cloudflare Stream.</p><p>2<br>00:00:03.755 –&gt; 00:00:06.424<br>Esta es una demostración rápida de nuestra función de subtítulos automáticos alimentados por IA.</p><p>3<br>00:00:06.426 –&gt; 00:00:12.500<br>Estos subtítulos fueron generados con Cloudflare WorkersAI y el Modelo Whisper, no escritos a mano, y solo tomó unos segundos.</code></pre></p><p>I saved it to a file locally and, using the Cloudflare Dashboard, I added it to the video which you may have noticed embedded at the top of this post! Captions can also be <a href="https://developers.cloudflare.com/stream/edit-videos/adding-captions/#upload-a-file"><u>uploaded via the API</u></a>.</p><div><h2>More testing and what I learned</h2><a href="#more-testing-and-what-i-learned"></a></div><p>I tested this script on a variety of videos from many sources, including short social media clips, 30-minute video diaries, and even a few clips with some specialized vocabulary. Ultimately, I was surprised at the level of prototype I was able to build on my first afternoon with Workers AI. The translation results were very promising! In the process, I learned a few key things that I will be bringing back to product planning for Stream:</p><p><b>We have the tools.</b> Workers AI has a model called "<a href="https://developers.cloudflare.com/workers-ai/models/m2m100-1.2b/"><u>m2m100-1.2b</u></a>" from Hugging Face that can do text translations between many languages. We can use it to translate the plain text cues from VTT files — whether we generate them or they are user-supplied. We’ll keep an eye out for new models as they are added, too.</p><p><b>Quality is prone to "copy-of-a-copy" effect.</b> When auto-translating captions that were auto-transcribed, issues that impact the English transcription have a huge downstream impact on the translation. Editing the source transcription improves quality <i>a lot</i>.</p><p><b>Good grammar and punctuation counts.</b> Translations are significantly improved if the source content is grammatically correct and punctuated properly. Punctuation is often missing when captions are auto-generated, but not always  — I would like to learn more about how to predict that and if there are ways we can increase punctuation in the output of transcription jobs. My cue consolidator experiment returns giant walls of text if there’s no punctuation on the input.</p><p><b>Translate full sentences when possible.</b> We split our transcriptions into cues of about 5 words for several reasons. However, this produces lower quality output when translated because it breaks grammatical constructs. Translation results are better with full sentences or at least complete fragments. This is doable, but easier said than done, particularly as we look toward support for additional input languages that use punctuation differently.</p><p><b>We will have blind spots when evaluating quality.</b> Everyone on our team was able to adequately evaluate English <i>transcriptions</i>. Sanity-checking the quality of <i>translations</i> will require team members who are familiar with those languages. We state disclaimers about transcription quality and offer tips to improve it, but at least we know what we're looking at. For translations, we may not know how far off we are in many cases. How many readers of this article objected to the first translation sample above?</p><p><b>Clear UI and API design will be important for these related but distinct workflows.</b> There are two different flows being requested by Stream customers: "My audio is in English, please make translated subtitles" alongside "My audio is in another language, please transcribe captions as-is." We will need to carefully consider how we shape user-facing interactions to make it really clear to a user what they are asking us to do.</p><p><b>Workers AI is really easy to use.</b> Sheepishly, I will admit: although I read Stream's code for the transcription feature, this was the first time I've ever used Workers AI on my own, and it was definitely the easiest part of this experiment!</p><p>Finally, as a product manager, it is important I remain focused on the outcome. From a certain point of view, this experiment is a bit of an <a href="https://en.wikipedia.org/wiki/XY_problem"><u>XY Problem</u></a>. The <i>need</i> is "I have audio in one language and I want subtitles in another." Are there other avenues worth looking into besides "transcribe to captions, then restructure and translate those captions?" Quite possibly. But this experiment with Workers AI helped me identify some potential challenges to plan for and opportunities to get excited about!</p><p>I’ve cleaned up and shared the sample code I used in this experiment at <a href="https://github.com/tsmith512/vtt-translate/"><u>https://github.com/tsmith512/vtt-translate/</u></a>. Try it out and share your experience!</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Un experimento rápido: translating Cloudflare Stream captions with Workers AI" href="https://blog.cloudflare.com/un-experimento-rapido-translating-cloudflare-stream-captions-with-workers-ai/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Un experimento rápido: translating Cloudflare Stream captions with Workers AI</span><span class="cap link fs12">https://blog.cloudflare.com/un-experimento-rapido-translating-cloudflare-stream-captions-with-workers-ai/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>When the World Logs Off: Christmas, New Year’s, and the Internet’s Holiday Rhythm</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ce9d603a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ce9d603a.html</id>
    <published>2024-12-24T10:00:00.000Z</published>
    <updated>2024-12-24T10:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>As January approaches and the year comes to a close, distinct changes in global Internet usage emerge. Year-end traditions — ranging from Christmas feasts to New Year’s Eve (NYE) countdowns — shape online behavior across continents and cultures. Looking back at Christmas and NYE 2023 offers insights into how these trends may repeat this year, and by January 2025, we’ll be able to directly compare patterns. Examining data from 50 countries and regions reveals how people celebrated in 2023-2024, providing a timely reminder of typical holiday trends.</p><p>With Cloudflare’s global reach, we observe planet-wide and local Internet habits during the holiday season. In the past, unintended trends during Christmas and New Year’s Eve have surfaced through our <a href="https://radar.cloudflare.com/outage-center"><u>Outage Center</u></a>, which uses automatic traffic anomaly alerts to detect Internet outages or unusual patterns. In the 2023 <a href="https://radar.cloudflare.com/outage-center?dateStart=2023-12-21&amp;dateEnd=2024-01-02"><u>overview below</u></a>, traffic dropped enough on those days to trigger dozens of anomaly alerts (orange and pink bubbles):</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6pPt1Ccp2AVqdhCqhOsEEk/424f5cddd931ae86a5a2e21dbabb2eda/image6.png"/></figure><p>While Christmas dominates in many regions, other cultural and religious holidays — like Hanukkah or regional festivities — shape online rhythms in places where Western traditions are less central.</p><p>In countries and regions where Christmas is deeply rooted, Internet traffic slows during Christmas Eve dinners, midnight masses, morning gift exchanges, and Christmas Day lunches.</p><p>This blog post focuses exclusively on non-bot-related Internet traffic requests, filtering out automated activity to provide a clearer view of genuine human behavior during the holiday season. Before going into location-specific perspectives, here’s a global hourly view of Internet traffic during Christmas and New Year’s Eve 2023 from <a href="https://radar.cloudflare.com/explorer?dataSet=http&amp;loc=US&amp;timeCompare=1&amp;dt=2023-12-18_2024-01-02"><u>Cloudflare Radar Data Explorer</u></a>, highlighting notable drops (in UTC, so it captures impacts across more days due to time zones spanning over 23 hours, from New Zealand to Hawaii in the US):</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2K08u0Q3BgqtwNAQEZCinh/d1eead7068ce053173fa2aca9fb031c9/image5.png"/></figure><div><h2>Global Christmas and New Year’s Eve daily trends</h2><a href="#global-christmas-and-new-years-eve-daily-trends"></a></div><p>Let’s start with a ranking of countries and regions and their top low-traffic holiday dates, showing each day’s percentage drop. Many locations like the US see clear dips on December 24 and 25 as people celebrate Christmas Eve and Christmas Day offline, and some show smaller declines (compared to Christmas) around December 31 as the New Year approaches. Still, the exact order and magnitude differ, reflecting cultural nuances — some nations experience greater drops on Christmas Eve, others on Christmas Day, and others signal unique patterns tied to New Year’s Eve or January 1 celebrations.</p><p>In the next table, locations are listed first (in the left column) by those with the lowest traffic on December 24 (and the highest percentage of traffic drop), followed by December 25, and finally December 31 (in the right column).</p><p><b>Top days with the lowest Internet traffic in December 2023 - January 2024</b></p><p>(with respective percentage drops, if any, from the previous week)</p><table><tr><td><p><b>Denmark</b></p><p>#1 December 24 (-35%)</p><p>#2 December 25 (-11%)</p><p>#3 December 31</p></td><td><p><b>South Africa</b></p><p>#1 December 25 (-27%)</p><p>#2 December 24 (-15%)</p><p>#3 December 31 (-5%)</p></td></tr><tr><td><p><b>Norway</b></p><p>#1 December 24 (-32%)</p><p>#2 December 25 (-12%)</p><p>#3 December 31</p></td><td><p><b>United Kingdom</b></p><p>#1 December 25 (-26%)</p><p>#2 December 24 (-19%)</p><p>#3 December 31</p></td></tr><tr><td><p><b>Portugal</b></p><p>#1 December 24 (-32%)</p><p>#2 December 25 (-24%)</p><p>#3 December 31</p></td><td><p><b>Italy</b></p><p>#1 December 25 (-25%)</p><p>#2 December 24 (-25%)</p><p>#3 December 31</p></td></tr><tr><td><p><b>Poland</b></p><p>#1 December 24 (-31%)</p><p>#2 December 25 (-21%)</p><p>#3 December 31</p></td><td><p><b>Australia</b></p><p>#1 December 25 (-25%)</p><p>#2 December 24 (-15%)</p><p>#3 December 31 (-1%)</p></td></tr><tr><td><p><b>Spain</b></p><p>#1 December 24 (-28%)</p><p>#2 December 25 (-25%)</p><p>#3 December 31</p></td><td><p><b>Ireland</b></p><p>#1 December 25 (-24%)</p><p>#2 December 24 (-22%)</p><p>#3 December 23</p></td></tr><tr><td><p><b>Sweden</b></p><p>#1 December 24 (-26%)</p><p>#2 December 25 (-6%)</p><p>#3 December 31</p></td><td><p><b>New Zealand</b></p><p>#1 December 25 (-22%)</p><p>#2 December 24 (-8%)</p><p>#3 December 31 (-4%)</p></td></tr><tr><td><p><b>Chile</b></p><p>#1 December 24 (-23%)</p><p>#2 December 25 (-24%)</p><p>#3 December 31 (-3%)</p></td><td><p><b>Canada</b></p><p>#1 December 25 (-19%)</p><p>#2 December 24 (-15%)</p><p>#3 December 31</p></td></tr><tr><td><p><b>Finland</b></p><p>#1 December 24 (-23%)</p><p>#2 December 25 (-16%)</p><p>#3 December 31</p></td><td><p><b>Nigeria</b></p><p>#1 December 25 (-18%)</p><p>#2 December 24 (-19%)</p><p>#3 January 1</p></td></tr><tr><td><p><b>France</b></p><p>#1 December 24 (-22%)</p><p>#2 December 25 (-19%)</p><p>#3 December 23</p></td><td><p><b>Philippines</b></p><p>#1 December 25 (-16%)</p><p>#2 December 24 (-7%)</p><p>#3 December 31</p></td></tr><tr><td><p><b>Germany</b></p><p>#1 December 24 (-21%)</p><p>#2 December 25 (-9%)</p><p>#3 December 31</p></td><td><p><b>Hong Kong</b></p><p>#1 December 25 (-9%)</p><p>#2 December 24 (-6%)</p><p>#3 December 23</p></td></tr><tr><td><p><b>Mexico</b></p><p>#1 December 24 (-21%)</p><p>#2 December 25 (-19%)</p><p>#3 December 31</p></td><td><p><b>Belgium</b></p><p>#1 December 31 (-1%)</p><p>#2 December 24 (-20%)</p><p>#3 December 25 (-17%)</p></td></tr><tr><td><p><b>Belgium</b></p><p>#1 December 24 (-20%)</p><p>#2 December 25 (-17%)</p><p>#3 December 31 (-1%)</p></td><td><p><b>Indonesia</b></p><p>#1 December 31 (-1%)</p><p>#2 December 25 (-7%)</p><p>#3 December 24</p></td></tr><tr><td><p><b>Romania</b></p><p>#1 December 24 (-20%)</p><p>#2 December 25 (-14%)</p><p>#3 December 31 (-3%)</p></td><td><p><b>Netherlands</b></p><p>#1 December 31 (-10%)</p><p>#2 December 24 (-10%)</p><p>#3 December 25 (-20%)</p></td></tr><tr><td><p><b>United States</b></p><p>#1 December 24 (-16%)</p><p>#2 December 25 (-21%)</p><p>#3 December 31</p></td><td><p><b>Ukraine</b></p><p>#1 December 31 (-10%)</p><p>#2 December 24 (-5%)</p><p>#3 December 30</p></td></tr><tr><td><p><b>Brazil</b></p><p>#1 December 24 (-14%)</p><p>#2 December 25 (-26%)</p><p>#3 December 31</p></td><td><p><b>Thailand</b></p><p>#1 December 31 (-6%)</p><p>#2 January 1 (-2%)</p><p>#3 December 25 (-2%) </p></td></tr><tr><td><p><b>Colombia</b></p><p>#1 December 24 (-14%)</p><p>#2 December 25 (-26%)</p><p>#3 December 31 (-4%)</p></td><td><p></p></td></tr></table><p>The data shows that in many European countries — such as Denmark, Norway, the United Kingdom, Portugal, Italy, Poland, Spain, Ireland, Sweden, Finland, France, Germany, Belgium, the Netherlands, and Romania — Christmas Eve (December24) and Christmas Day (December25) consistently register the biggest drops in Internet traffic. These dips suggest that in much of Europe, Christmas traditions take people firmly offline, whether it’s for family gatherings, festive meals, or religious observances. Outside Europe, similar patterns appear in predominantly Christian-influenced regions, including Australia, New Zealand, Canada, the United States, and several Latin American countries (like Brazil, Chile, and Colombia), confirming that the holiday’s cultural importance is mirrored in their online habits.</p><p>In contrast, locations less influenced by Western Christmas traditions, such as those in Asia, show subtler or different patterns. For example, Hong Kong and the Philippines do show declines in traffic, reflecting a hybrid of local and global influences, while places like Thailand and Indonesia present smaller dips on Christmas compared to other days or emphasize different holidays altogether. These variations highlight that while Christmas exerts a strong pull offline in many parts of the world, its impact on Internet usage is shaped by local cultural contexts.</p><p>As an example, here’s the US perspective from <a href="https://radar.cloudflare.com/explorer?dataSet=http&amp;loc=US&amp;timeCompare=1&amp;dt=2023-12-18_2024-01-02"><u>Cloudflare Radar Data Explorer</u></a>, where the drop in traffic during Christmas and New Year 2023 is evident:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Z2ODYM1L5vlBdZHhEdq4W/84b2144c586b01db3e3e99bb3bd05bc6/image3.png"/></figure><div><h2>Where Christmas isn’t central</h2><a href="#where-christmas-isnt-central"></a></div><p>Not every country’s December revolves around Christmas. In Israel, for example, Hanukkah’s timing changes year to year, influencing when people log off. In 2023, Hanukkah started on December 7, leading to an 8% traffic drop that day and 7% on the following days through December 10. Interestingly, in some years like 2024, Hanukkah begins closer to December 25, potentially overlapping with Western Christmas.</p><p><b>Countries where Christmas didn’t have a clear impact</b></p><table><tr><td><p><b>Turkey</b></p><p>#1 December 31 (-18%)</p><p>#2 December 29</p><p>#3 December 30</p></td><td><p><b>Israel</b></p><p>#1 December 29</p><p>#2 January 5</p><p>#3 December 30</p></td></tr><tr><td><p><b>Japan</b></p><p>#1 December 31 (-8%)</p><p>#2 January 1</p><p>#3 December 30 — December 24 with -3%</p></td><td><p><b>Vietnam</b></p><p>#1 January 1 (-7%)</p><p>#2 December 31 (-3%)</p><p>#3 January 2</p></td></tr><tr><td><p><b>Russia</b></p><p>#1 December31 (-23%)</p><p>#2 January 1 (-15%)</p><p>#3 December 30</p></td><td><p><b>Singapore</b></p><p>#1 December 16</p><p>#2 December 17</p><p>#3 December 18</p></td></tr><tr><td><p><b>India</b></p><p>#1 December 17</p><p>#2 December 16</p><p>#3 December 24</p></td><td><p><b>Bangladesh</b></p><p>#1 December 15</p><p>#2 December 16</p><p>#3 December 18</p></td></tr><tr><td><p><b>Saudi Arabia</b></p><p>#1 January 5</p><p>#2 January 6</p><p>#3 January 8</p></td><td><p><b>China</b></p><p>#1 December 19</p><p>#2 December 15</p><p>#3 December 18</p></td></tr></table><p>Now, let’s focus on a more granular perspective of these trends, showing the impact of Christmas dinners and lunches, and also New Year’s Eve drops in traffic.</p><p><i>Note: Unless otherwise noted, all times used in this blog post are local ones; in countries with several timezones, we’re using the timezone where more people live (for the US, Eastern time is used).</i></p><div><h2>A more granular perspective of Christmas: offline feasts and morning quiet</h2><a href="#a-more-granular-perspective-of-christmas-offline-feasts-and-morning-quiet"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/AnOIfryr3c8zSAc23SRKD/f3ee2dd0ed6f8d4f54a951663e2916e7/image4.png"/></figure><div><h3>Europe</h3><a href="#europe"></a></div><p>In Europe, Christmas traditions dominate, leading to the most significant Internet traffic drops. Christmas Eve dinner is a near-universal offline moment, with countries like Spain (-70% at 21:45), Portugal (-70% at 20:30), and Denmark (-68% at 19:45) experiencing the steepest declines. On Christmas Day, mornings are quieter as people relax or attend religious services, while festive lunches drive further drops, with traffic down 43% at 13:45 in Portugal and 44% at 07:15 in France.</p><p>By Boxing Day (December 26), digital activity rebounds as people return online for sales or socializing. For instance, the UK shows a 16% increase at 13:00, while Canada records a 19% rise at 08:15. In Australia, traffic climbs by 20% at 09:30, illustrating regional differences in how the day is celebrated.</p><div><h3>Americas</h3><a href="#americas"></a></div><p>In the Americas, holiday patterns reflect a mix of cultural traditions. In the United States, Christmas Eve traffic drops by 29% at 20:15, aligning with evening family gatherings, and Christmas Day sees a 32% decline at 09:15, reflecting quieter mornings.</p><p>In Latin America, Christmas Eve (Nochebuena) takes center stage, with significant traffic declines aligning with late-night traditions like the Midnight Toast (in <a href="https://christmasenthusiasts.co.uk/classic-traditions/how-do-people-celebrate-christmas-in-the-southern-hemisphere-where-its-summer"><u>Argentina</u></a>, the late-night feast is quite popular) and Misa de Gallo (Midnight Mass). For example:</p><ul><li><p>Colombia: -48% at 21:45</p></li><li><p>Argentina: -58% at 22:00; -67% at midnight</p></li><li><p>Chile: -64% at 22:45</p></li><li><p>Mexico: -50% at 21:45</p></li><li><p>Brazil: -22% at 21:45</p></li></ul><p>These late-night traffic dips highlight the region’s emphasis on midnight celebrations, family feasts, and religious observances.</p><div><h3>Asia Pacific</h3><a href="#asia-pacific"></a></div><p>Asian locations influenced by Western traditions, such as the Philippines and Hong Kong, experience moderate Christmas dips but shift focus to New Year’s celebrations — more on NYE below.</p><p>In the Southern Hemisphere, Australia and New Zealand experience their steepest traffic drops during Christmas lunch, with Australia seeing a 43% decrease at 13:45 and New Zealand recording a 42% decline.</p><div><h3>Middle East and Africa</h3><a href="#middle-east-and-africa"></a></div><p>In regions less influenced by Christmas, holiday traffic patterns vary significantly. For example, Nigeria sees a 26% drop at lunchtime on Christmas Day, while South Africa records a 37% decline at 14:15, reflecting offline family gatherings.</p><p>In predominantly non-Christian countries like Egypt and Saudi Arabia, December 24-25 does not show significant dips; instead, other cultural holidays drive offline moments. For example, as we’ve noted, Israel experienced up to an 8% drop in 2023 during Hanukkah, particularly in the first four days after December 7. In <a href="https://blog.cloudflare.com/easter-passover-ramadan-internet-trends-2023/"><u>previous blog posts</u></a>, we have shown how events like <a href="https://blog.cloudflare.com/how-ramadan-shows-up-in-internet-trends/"><u>Ramadan</u></a> clearly impact Internet traffic in countries with large Muslim populations. One example from our <a href="https://radar.cloudflare.com/year-in-review/2024/ae?compareWith=ID&amp;cf_history_state=%7B%22guid%22%3A%22C255D9FF78CD46CDA4F76812EA68C350%22%2C%22historyId%22%3A15%2C%22targetId%22%3A%2211B31B8E5374713A1265DF95F60D0530%22%7D#internet-traffic-growth"><u>Year in Review 2024</u></a> highlights Indonesia and the United Arab Emirates, where traffic dropped during Eid al-Fitr, the festival marking the end of Ramadan (April 9-10, 2024).</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2NCDJ1EQZaBbqAn5KKeN7s/1fe50400f25c144f24292bfbf4fe821e/image2.png"/></figure><div><h3>The Boxing Day revival</h3><a href="#the-boxing-day-revival"></a></div><p>Boxing Day on December 26 marks a significant digital rebound in countries like the UK, Canada, Australia (where there is a higher increase from the previous week, with daily traffic growing 9%), and New Zealand, as people return online after the Christmas break. Traditionally associated with charitable activities, family gatherings, and shopping, the day sees traffic spikes across these regions:</p><table><tr><td><p><b>Location</b></p></td><td><p><b>December 26 increase in daily traffic</b></p></td><td><p><b>Higher traffic increase on December 26</b></p></td></tr><tr><td><p>Australia</p></td><td><p>+9%</p></td><td><p>December 26; 09:30: +20%</p></td></tr><tr><td><p>United Kingdom</p></td><td><p>+2%</p></td><td><p>December 26; 13:00: +16%</p></td></tr><tr><td><p>Canada</p></td><td><p>+1%</p></td><td><p>December 26, 08:15: +19%</p></td></tr></table><p>Here is the list of locations that saw a clear drop in traffic on Christmas Eve or Christmas Day morning or lunch. We selected the time (morning or lunch) with the bigger drop compared to the previous week for further analysis. The list is ordered by the Christmas Eve dinner drop. Countries like Russia (where <a href="https://www.bbc.co.uk/newsround/59905614"><u>Orthodox Christians</u></a> celebrate Christmas later, on January 7), Japan, China, Indonesia, Turkey, Israel, Thailand, Egypt, Singapore, Vietnam, and Bangladesh showed no impact during Christmas Eve dinner or Christmas Day morning or lunch.</p><table><tr><td><p><b>Location</b></p></td><td><p><b>Christmas Eve Dinner Drop</b></p></td><td><p><b>Christmas Day Morning/Lunch Drop</b></p></td></tr><tr><td><p>Spain</p></td><td><p>-70% at 21:45</p></td><td><p>-51% at 08:00 (morning)</p></td></tr><tr><td><p>Portugal</p></td><td><p>-70% at 20:30</p></td><td><p>-43% at 13:45 (lunch)</p></td></tr><tr><td><p>Denmark</p></td><td><p>-68% at 19:45</p></td><td><p>-43% at 06:15 (morning)</p></td></tr><tr><td><p>Chile</p></td><td><p>-64% at 22:45; (-65% at 00:00, December 25)</p></td><td><p>-49% at 09:00 (morning) </p></td></tr><tr><td><p>Norway</p></td><td><p>-63% at 18:45</p></td><td><p>-50% at 06:45 (morning)</p></td></tr><tr><td><p>Czech Republic</p></td><td><p>-60% at 18:15</p></td><td><p>-43% at 06:30 (morning)</p></td></tr><tr><td><p>Poland</p></td><td><p>-59% at 17:15</p></td><td><p>-51% at 07:15 (morning)</p></td></tr><tr><td><p>Argentina</p></td><td><p>-58% at 22:00 (-67% at 00:00, December 25)</p></td><td><p>-52% at 09:00 (morning) </p></td></tr><tr><td><p>Italy</p></td><td><p>-55% at 21:15</p></td><td><p>-44% at 07:00 (morning)</p></td></tr><tr><td><p>France</p></td><td><p>-55% at 20:45</p></td><td><p>-44% at 07:15 (morning)</p></td></tr><tr><td><p>Mexico</p></td><td><p>-50% at 21:45</p></td><td><p>-38% at 08:15 (morning)</p></td></tr><tr><td><p>Belgium</p></td><td><p>-50% at 20:15</p></td><td><p>-46% at 07:15 (morning)</p></td></tr><tr><td><p>Switzerland</p></td><td><p>-50% at 19:45</p></td><td><p>-46% at 06:30 (morning)</p></td></tr><tr><td><p>Austria</p></td><td><p>-50% at 19:15</p></td><td><p>-42% at 06:15 (morning)</p></td></tr><tr><td><p>Nigeria</p></td><td><p>-49% at 18:00</p></td><td><p>-26% at 12:30 (lunch)</p></td></tr><tr><td><p>Colombia</p></td><td><p>-48% at 21:45</p></td><td><p>-49% at 08:00 (morning)</p></td></tr><tr><td><p>Germany</p></td><td><p>-47% at 19:15</p></td><td><p>-36% at 07:15 (morning)</p></td></tr><tr><td><p>Sweden</p></td><td><p>-47% at 16:30</p></td><td><p>-36% at 07:00 (morning)</p></td></tr><tr><td><p>Finland</p></td><td><p>-42% at 17:45</p></td><td><p>-42% at 08:00 (morning)</p></td></tr><tr><td><p>Ireland</p></td><td><p>-40% at 18:15</p></td><td><p>-36% at 15:15 (lunch)</p></td></tr><tr><td><p>South Africa</p></td><td><p>-37% at 19:00</p></td><td><p>-37% at 14:15 (lunch)</p></td></tr><tr><td><p>Romania</p></td><td><p>-34% at 20:45</p></td><td><p>-34% at 06:30 (morning)</p></td></tr><tr><td><p>United Kingdom</p></td><td><p>-34% at 18:00</p></td><td><p>-38% at 14:45 (lunch)</p></td></tr><tr><td><p>Canada</p></td><td><p>-32% at 20:30</p></td><td><p>-31% at 09:30 (morning)</p></td></tr><tr><td><p>Netherlands</p></td><td><p>-30% at 20:45</p></td><td><p>-35% at 06:45 (morning)</p></td></tr><tr><td><p>United States</p></td><td><p>-29% at 20:15</p></td><td><p>-32% at 09:15 (morning)</p></td></tr><tr><td><p>Australia</p></td><td><p>-23% at 20:45</p></td><td><p>-43% at 13:45 (lunch)</p></td></tr><tr><td><p>New Zealand</p></td><td><p>-23% at 18:30</p></td><td><p>-42% at 13:15 (lunch)</p></td></tr><tr><td><p>Brazil</p></td><td><p>-22% at 21:45</p></td><td><p>-42% at 08:00 (morning)</p></td></tr><tr><td><p>Philippines</p></td><td><p>-22% at 21:30</p></td><td><p>-29% at 06:45 (morning)</p></td></tr></table><div><h2>New Year’s Eve: A planetary offline moment</h2><a href="#new-years-eve-a-planetary-offline-moment"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6fK4TEIFANRI6YxNUH6toS/e2ea778748511440f8a4f2103519c651/image1.png"/></figure><p>Midnight, December 31 is a shared offline moment worldwide, as people step away from their screens to celebrate. To provide a more accurate assessment of New Year’s Eve’s impact, we compare traffic at 00:00 on January 1 with 00:00 on December 18, avoiding distortions caused by Christmas-related patterns. This approach highlights the distinct drop in Internet activity due to New Year’s celebrations.</p><p>Across Europe, countries like Portugal (-60%) and Romania (-60%) see dramatic traffic drops, reflecting widespread offline gatherings. Spain (-56%) and Germany (-49%) also experience steep declines, emphasizing the importance of this tradition across the region. Even Northern Europe mirrors this trend, with Denmark (-41%), Norway (-39%), and Sweden (-29%) showing significant dips.</p><p>In the Americas, this offline moment is particularly pronounced in Latin America, where family and communal gatherings dominate. Argentina (-66%) and Chile (-74%) lead the region, with Brazil (-46%) and Colombia (-44%) following closely. In North America, the impact is less dramatic due to time zone variations — in this case, with millions of people spread out in distinct time zones. Canada records a 14% drop, and the United States shows a modest 12% decline compared to December 18.</p><p>In Asia and the Pacific, New Year’s Eve celebrations heavily influence Internet trends. Thailand saw a 31% drop, Indonesia 23%, and Japan 16%, also reflecting this region’s focus on communal gatherings and celebrations. Australia (-21%) and New Zealand (-11%), among the first countries to welcome the New Year, also show noticeable declines as midnight festivities take center stage.</p><p>In the Middle East and Africa, Turkey (-23%), South Africa (-32%), and Nigeria (-15%) exhibit significant offline engagement at midnight. Israel records a smaller but notable 6% dip before midnight, reflecting localized variations in celebration styles.</p><p>Of course, this offline intermission doesn’t last long. After a few hours, people return to their devices. France sees a 37% surge at 3:15 on January 1, while Turkey experiences a 36% upswing in the early hours.</p><p>Next, we present the list of locations with clear drops in traffic at midnight on New Year’s Eve, compared to December 18, ordered by percentage of drop. </p><table><tr><td><p><b>Locations</b></p></td><td><p><b>January 1, 00:00 drop compared to December 18</b></p></td><td><p><b>Locations</b></p></td><td><p><b>January 1, 00:00 drop compared to December 18</b></p></td></tr><tr><td><p>Chile</p></td><td><p>-74%</p></td><td><p>Thailand</p></td><td><p>-31%</p></td></tr><tr><td><p>Argentina</p></td><td><p>-66%</p></td><td><p>Italy</p></td><td><p>-30%</p></td></tr><tr><td><p>Romania</p></td><td><p>-60%</p></td><td><p>Sweden</p></td><td><p>-29%</p></td></tr><tr><td><p>Portugal</p></td><td><p>-60%</p></td><td><p>Vietnam</p></td><td><p>-27%</p></td></tr><tr><td><p>Spain</p></td><td><p>-56%</p></td><td><p>United Kingdom</p></td><td><p>-25%</p></td></tr><tr><td><p>Germany</p></td><td><p>-49%</p></td><td><p>Ukraine</p></td><td><p>-25%</p></td></tr><tr><td><p>Brazil</p></td><td><p>-46%</p></td><td><p>Indonesia</p></td><td><p>-23%</p></td></tr><tr><td><p>Mexico</p></td><td><p>-44%</p></td><td><p>Turkey</p></td><td><p>-23%</p></td></tr><tr><td><p>Colombia</p></td><td><p>-44%</p></td><td><p>Australia</p></td><td><p>-21%</p></td></tr><tr><td><p>Philippines</p></td><td><p>-43%</p></td><td><p>Hong Kong</p></td><td><p>-21%</p></td></tr><tr><td><p>Netherlands</p></td><td><p>-42%</p></td><td><p>Ireland</p></td><td><p>-19%</p></td></tr><tr><td><p>Poland</p></td><td><p>-41%</p></td><td><p>France</p></td><td><p>-17%</p></td></tr><tr><td><p>Denmark</p></td><td><p>-41%</p></td><td><p>Japan</p></td><td><p>-16%</p></td></tr><tr><td><p>Austria</p></td><td><p>-40%</p></td><td><p>South Korea</p></td><td><p>-16%</p></td></tr><tr><td><p>Switzerland</p></td><td><p>-39%</p></td><td><p>Nigeria</p></td><td><p>-15%</p></td></tr><tr><td><p>Norway</p></td><td><p>-39%</p></td><td><p>Canada</p></td><td><p>-14%</p></td></tr><tr><td><p>Czech Republic</p></td><td><p>-33%</p></td><td><p>Finland</p></td><td><p>-14%</p></td></tr><tr><td><p>Russia</p></td><td><p>-32%</p></td><td><p>Singapore</p></td><td><p>-13%</p></td></tr><tr><td><p>Belgium</p></td><td><p>-32%</p></td><td><p>United States</p></td><td><p>-12%</p></td></tr><tr><td><p>South Africa</p></td><td><p>-32%</p></td><td><p>China</p></td><td><p>-12%</p></td></tr></table><div><h2>Conclusion: A mosaic of traditions and digital habits</h2><a href="#conclusion-a-mosaic-of-traditions-and-digital-habits"></a></div><p>What emerges from these patterns is a rich tapestry of cultural habits. While Christmas Eve and Day are central offline moments in Europe and the Americas, other regions mark their quiet days on different dates, shaped by unique holidays and customs. The insights from 50 countries and regions confirm how cultural traditions guide when people step away from screens.</p><p>As the Gregorian calendar year comes to a close, the universal appeal of stepping offline becomes clear. Whether raising glasses at the stroke of midnight, exchanging greetings, or lighting candles for festivals like Hanukkah, these moments remind us that while the Internet connects billions, cultural rhythms still shape our relationship with technology. Whether feasting with loved ones or counting down to a new year, humans everywhere find reasons to unplug — if only for a moment.</p><p>If you’re interested in more trends and insights about the Internet, check out <a href="https://radar.cloudflare.com/"><u>Cloudflare Radar</u></a>. Follow us on social media at <a href="https://twitter.com/CloudflareRadar"><u>@CloudflareRadar</u></a> (X), <a href="https://noc.social/@cloudflareradar"><u>https://noc.social/@cloudflareradar</u></a> (Mastodon), and <a href="https://bsky.app/profile/radar.cloudflare.com"><u>radar.cloudflare.com</u></a> (Bluesky), or contact us via email.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="When the world logs off: Christmas, New Year’s, and the Internet’s holiday rhythm" href="https://blog.cloudflare.com/when-the-world-logs-off-christmas-new-years-and-the-internets-holiday-rhythm/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">When the world logs off: Christmas, New Year’s, and the Internet’s holiday rhythm</span><span class="cap link fs12">https://blog.cloudflare.com/when-the-world-logs-off-christmas-new-years-and-the-internets-holiday-rhythm/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Grinch Bots Strike Again: Defending Your Holidays From Cyber Threats</title>
    <link href="https://blog.imc.re/RSSBOX/rss/c3d79809.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/c3d79809.html</id>
    <published>2024-12-23T14:01:00.000Z</published>
    <updated>2024-12-23T14:01:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><div><h2>Grinch Bots are still stealing Christmas</h2><a href="#grinch-bots-are-still-stealing-christmas"></a></div><p>Back in 2021, we covered the antics of <a href="https://blog.cloudflare.com/grinch-bot/"><u>Grinch Bots</u></a> and how the combination of proposed regulation and technology could prevent these malicious programs from stealing holiday cheer.</p><p>Fast-forward to 2024 — the <a href="https://www.congress.gov/bill/117th-congress/senate-bill/3276/all-info#:~:text=%2F30%2F2021)-,Stopping%20Grinch%20Bots%20Act%20of%202021,or%20services%20in%20interstate%20commerce"><u>Stop Grinch Bots Act of 2021</u></a> has not passed, and bots are more active and powerful than ever, leaving businesses to fend off increasingly sophisticated attacks on their own. During Black Friday 2024, Cloudflare observed:</p><ul><li><p><b>29% of all traffic on Black Friday was Grinch Bots</b>. Humans still accounted for the majority of all traffic, but bot traffic was up 4x from three years ago in absolute terms. </p></li><li><p><b>1% of traffic on Black Friday came from AI bots. </b>The majority of it came from Claude, Meta, and Amazon. 71% of this traffic was given the green light to access the content requested. </p></li><li><p><b>63% of login attempts across our network on Black Friday were from bots</b>. While this number is high, it was down a few percentage points compared to a month prior, indicating that more humans accessed their accounts and holiday deals. </p></li><li><p><b>Human logins on e-commerce sites increased 7-8%</b> compared to the previous month. </p></li></ul><p>These days, holiday shopping doesn’t start on Black Friday and stop on Cyber Monday. Instead, it stretches through Cyber Week and beyond, including flash sales, pre-orders, and various other promotions. While this provides consumers more opportunities to shop, it also creates more openings for Grinch Bots to wreak havoc.</p><div><h2>Black Friday - Cyber Monday by the numbers</h2><a href="#black-friday-cyber-monday-by-the-numbers"></a></div><p>Black Friday and Cyber Monday in 2024 brought record-breaking shopping — and grinching. In addition to looking across our entire network, we also analyzed traffic patterns specifically on a cohort of e-commerce sites. </p><p>Legitimate shoppers flocked to e-commerce sites, with requests reaching an astounding 405 billion on Black Friday, accounting for 81% of the day’s total traffic to e-commerce sites. Retailers reaped the rewards of their deals and advertising, seeing a 50% surge in shoppers week-over-week and a 61% increase compared to the previous month.</p><p>Unfortunately, Grinch Bots were equally active. Total e-commerce bot activity surged to 103 billion requests, representing up to 19% of all traffic to e-commerce sites. Nearly one in every five requests to an online store was not a real customer. That’s a lot of resources to waste on bogus traffic. Cyber Week was a battleground, with bots hoarding inventory, exploiting deals, and disrupting genuine shopping experiences.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6XOfNPFabXiMzIrZrXGES2/9fa1eb6d1ca558ef9f405826999bcea2/image9.png"/></figure><p>The upside, if there is one, is that there was more human activity on e-commerce sites (81%) than observed on our network more broadly (71%). </p><div><h2>The Grinch Bot’s Modus Operandi</h2><a href="#the-grinch-bots-modus-operandi"></a></div><p>Cloudflare saw 4x more bot requests than what we observed in 2021. Being able to observe and score all this traffic at scale means we can help customers keep the grinches away. We also got to see patterns that help us better identify the concentration of these attacks: </p><ul><li><p>19% of traffic on e-commerce sites was Grinch Bots</p></li><li><p>1% of traffic to e-commerce sites was from AI Bots. </p></li><li><p>63% of login attempt requests across our network were from bots </p></li><li><p>22% of bot activity originated from residential proxy networks</p></li></ul><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Lo8y9dRRZGKujWxwfxBaf/4be5c93638b3dabe7acc823adac5ed6f/image3.png"/></figure><p>What are all of these bots up to? </p><div><h3>AI bots</h3><a href="#ai-bots"></a></div><p>This year marked a breakthrough for AI-driven bots, agents, and models, with their impact spilling into Black Friday. AI bots went from zero to one, now making up 1% of all bot traffic on e-commerce sites. </p><p>AI-driven bots generated 29 billion requests on Black Friday alone, with Meta-external, Claudebot, and Amazonbot leading the pack. Based on their owners, these bots are meant to crawl to augment training data sets for Llama, Claude, and Alexa respectively. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6jzXxH2fR5KWRWc252SbNH/ad40f4a4cb8cf1fdc36558dc4324b717/image10.png"/></figure><p>We looked at e-commerce sites specifically to find out if these bots were treating all content equally. While Meta-External and Amazonbot were still in the Top 3 of AI bots reaching e-commerce sites, Bytedance’s Bytespider crawled the most shopping sites.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6jOsfPtliY01FSNVVgb2bZ/f444cee15d3818d24ef2e3e53731896c/image2.png"/></figure><div><h3>Account Takeover (ATO) bots</h3><a href="#account-takeover-ato-bots"></a></div><p>In addition to scraping, crawling, and shopping, bots also targeted customer accounts on Black Friday. We saw 14.1 billion requests from bots to /login endpoints, accounting for 63% of that day’s login attempts. </p><p>While this number seems high, intuitively it makes sense, given that humans don’t log in to accounts every day, but bots definitely try to crack accounts every day. Interestingly, while humans only accounted for 36% of traffic to login pages on Black Friday, this number was <b><i>up 7-8% compared to the prior month</i></b>. This suggests that more shoppers logged in to capitalize on deals and discounts on Black Friday than in preceding weeks. Human logins peaked at around 40% of all traffic to login sites on the Monday before Thanksgiving, and again on Cyber Monday.  </p><p>Separately, we also saw a 37% increase in leaked passwords used in login requests compared to the prior month. During Birthday Week, we shared <a href="https://blog.cloudflare.com/a-safer-internet-with-cloudflare/#account-takeover-detection"><u>how 65% of internet users are at risk of ATO due to re-use of leaked passwords</u></a>. This surge, coinciding with heightened human and bot traffic, underscores a troubling pattern: both humans and bots continue to depend on common and compromised passwords, amplifying security risks.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1DDDcH41X7fhmfk2VdNaNV/de40dce017459752ba366e5fea331377/image7.png"/></figure><p><b>Proxy bots: </b>Regardless of whether they’re crawling your content or hoarding your wares, 22% of bot traffic originated from <a href="https://blog.cloudflare.com/residential-proxy-bot-detection-using-machine-learning/"><u>residential proxy networks</u></a>. This obfuscation makes these requests look like legitimate customers browsing from their homes rather than large cloud networks. The large pool of IP addresses and the diversity of networks poses a challenge to traditional bot defense mechanisms that rely on IP reputation and rate limiting. </p><p>Moreover, the diversity of IP addresses enables the attackers to rotate through them indefinitely. This shrinks the window of opportunity for bot detection systems to effectively detect and stop the attacks. The use of residential proxies is a trend we have been tracking for months now and Black Friday traffic was within the range we’ve seen throughout this year.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Rk3c2sq0kLpl9Y71NdL8K/1186c343f760dda1f64adb4dd8716170/image1.png"/></figure><p>If you’re using Cloudflare’s <a href="https://www.cloudflare.com/en-gb/application-services/products/bot-management/"><u>Bot Management</u></a>, your site is already protected from these bots since we update our bot score based on these types of network fingerprints. In May 2024, we <a href="https://blog.cloudflare.com/residential-proxy-bot-detection-using-machine-learning/"><u>introduced</u></a> our latest model optimized for detecting residential proxies. Early results show promising declines in this type of activity, indicating that bot operators may be reducing their reliance on residential proxies. </p><div><h2>The Christmas “Yule” log: how customers can protect themselves</h2><a href="#the-christmas-yule-log-how-customers-can-protect-themselves"></a></div><p>35% of all traffic on Black Friday was Grinch Bots. To keep Grinch Bots at bay, businesses need year-round bot protection and proactive strategies tailored to the unique challenges of holiday shopping.</p><p>Here are 4 yules (aka “rules”) for the season:</p><p><b>(1) Block bots</b>: 22% of bot traffic originated from residential proxy networks. Our bot management <a href="https://blog.cloudflare.com/residential-proxy-bot-detection-using-machine-learning/"><u>score automatically adjusts based on these network signals</u></a>. Use our <a href="https://developers.cloudflare.com/bots/concepts/bot-score/"><u>Bot Score</u></a> in rules to challenge sensitive actions. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3yNb5lIJ0kUuUkwrwRIFV4/21bd315b382663d5601d4629c8bec3a2/image8.png"/></figure><p><b>(2) Monitor potential Account Takeover (ATO) attacks</b>: Bots often test <a href="https://blog.cloudflare.com/helping-keep-customers-safe-with-leaked-password-notification/"><u>stolen credentials</u></a> in the months leading up to Cyber Week to refine their strategies. Re-use of stolen credentials makes businesses even more vulnerable. Our account abuse detections help customers monitor login paths for leaked credentials and traffic anomalies.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/20ICo3eYcY6BTdqAJE5Kj9/90b1373280aaeef54dfbed3c41e5ea8c/Screenshot_2024-12-21_at_17.52.17.png"/></figure><p>Check out more examples of related <a href="https://developers.cloudflare.com/waf/detections/leaked-credentials/examples/"><u>rules</u></a> you can create.</p><p><b>(3) Rate limit account and purchase paths: </b>Apply rate-limiting <a href="https://developers.cloudflare.com/waf/rate-limiting-rules/best-practices/"><u>best practices</u></a> on critical application paths. These include limiting new account access/creation from previously seen IP addresses, and leveraging other network fingerprints, to help prevent promo code abuse and inventory hoarding, as well as identifying account takeover attempts through the application of <a href="https://developers.cloudflare.com/bots/concepts/detection-ids/"><u>detection IDs</u></a> and <a href="https://developers.cloudflare.com/waf/managed-rules/check-for-exposed-credentials/"><u>leaked credential checks</u></a>.</p><p><b>(4) Block AI bots</b> abusing shopping features to maintain fair access for human users. If you’re using Cloudflare, you can quickly block all AI bots by <a href="https://blog.cloudflare.com/declaring-your-aindependence-block-ai-bots-scrapers-and-crawlers-with-a-single-click/"><u>enabling our automatic AI bot blocking</u></a> feature.  </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5vfiWs6fEkloTwGblzkltR/53c9a89a323a4bb9107ea8f3e83e9b49/image11.png"/></figure><div><h2>What to expect in 2025? </h2><a href="#what-to-expect-in-2025"></a></div><p>Over the next year, e-commerce sites should expect to see more humans shopping for longer periods. As sale periods lengthen (like they did in 2024) we expect more peaks in human activity on e-commerce sites across November and December. This is great for consumers and great for merchants.</p><p>More AI bots and agents will be integrated into e-commerce journeys in 2025. AI bots will not only be crawling sites for training data, but will also integrate into the shopping experience. AI bots did not exist in 2021, but now make up 1% of all bot traffic. This is only the tip of the iceberg and their growth will explode in the next year. We expect this to pose new risks as bots mimic and act on behalf of humans.</p><p>More sophisticated automation through network, device, and cookie cycling will also become a bigger threat. Bot operators will continue to employ advanced evasion tactics like rotating devices, IP addresses, and cookies to bypass detection.</p><p>Grinch Bots are evolving, and regulation may be slowing, but businesses don’t have to face them alone. We remain resolute in our mission to help build a better Internet ... and holiday shopping experience.</p><p>Even though the holiday season is closing out soon, bots are never on vacation. It’s never too late or too early to start protecting your customers and your business from grinches that work all year round.</p><p>Wishing you all happy holidays and a bot-free new year!</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1E192osHHmrXszsfbE2fIa/f7d04ea59ef6355eb78fed4e2fa15bd4/image6.png"/></figure><p></p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Grinch Bots strike again: defending your holidays from cyber threats" href="https://blog.cloudflare.com/grinch-bot-2024/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Grinch Bots strike again: defending your holidays from cyber threats</span><span class="cap link fs12">https://blog.cloudflare.com/grinch-bot-2024/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Global Elections in 2024: Internet Traffic and Cyber Threat Trends</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ccded7a6.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ccded7a6.html</id>
    <published>2024-12-23T14:00:00.000Z</published>
    <updated>2024-12-23T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>Elections define the course of <a href="https://en.wikipedia.org/wiki/History_of_democracy#/media/File:Age_of_democracies_at_the_end_of_2015,_OWID.svg"><u>democracies</u></a> (even as there are <a href="https://en.wikipedia.org/wiki/History_of_democracy#/media/File:Electoral_democracies.svg"><u>several </u></a>types of democracies), and 2024 was a landmark year, with over 60 countries — plus the European Union — holding national elections, impacting half the world’s population. As highlighted in <a href="https://www.pewresearch.org/global/2024/12/11/global-elections-in-2024-what-we-learned-in-a-year-of-political-disruption/"><u>Pew Research’s global elections report</u></a>, this was a year of “political disruption,” where the Internet was a relevant stage for both democratic engagement and cyber threats.</p><p>At Cloudflare, with our presence in <a href="https://www.cloudflare.com/network/"><u>over 330 cities and 120 countries and interconnection with 12,500 networks</u></a>, we’ve witnessed firsthand the digital impact of these elections. From monitoring Internet traffic patterns to mitigating cyberattacks, we’ve observed trends that reveal how elections increasingly play out online. As detailed in our just-published <a href="https://www.cloudflare.com/impact/"><u>Cloudflare Impact report</u></a>, we’ve also worked to protect media outlets, political campaigns, and help elections worldwide.</p><p>Here’s the map of countries with national elections that took place in 2024, from our <a href="https://radar.cloudflare.com/reports/elections-2024"><u>elections report</u></a>.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3lto8GbhqRNphtxGcSipqj/9422932d5766cd35a050b499161c874f/BLOG-2648_2.png"/></figure><p>We’ve been monitoring 2024 elections worldwide on our <a href="https://blog.cloudflare.com/tag/election-security/"><u>blog</u></a> and in the <a href="https://radar.cloudflare.com/reports/elections-2024"><u>2024 Election Insights report</u></a> available on <a href="https://radar.cloudflare.com/reports/elections-2024"><u>Cloudflare Radar</u></a>.</p><p>In terms of Internet patterns, we’ve observed how cyber activity in 2024 continues to intersect with real-world events. Online attacks are clearly a significant part of elections, even when unsuccessful in disrupting candidates or election-related websites due to strong protections. Additionally, Internet traffic patterns often vary on election day depending on the country, and government-directed <a href="https://radar.cloudflare.com/year-in-review/2024#internet-outages"><u>Internet shutdowns</u></a> continue, including ones related to elections. Email activity is also influenced, especially for more popular candidates in “<a href="https://www.pewresearch.org/global/2024/12/11/global-elections-in-2024-what-we-learned-in-a-year-of-political-disruption/"><u>polarized battles</u></a>.”</p><p>Let’s start our review with attacks. </p><div><h2>Rising threats: political and election-related cyberattacks in 2024</h2><a href="#rising-threats-political-and-election-related-cyberattacks-in-2024"></a></div><p>During 2024, elections saw a rise in DDoS attacks targeting political campaigns, parties, and election infrastructure.</p><p>In the <b>United States</b>, over 6 billion malicious requests were blocked between November 1-6. A set of DDoS attacks leading up to Election Day on November 5 targeted one of the campaigns with multiple days of attacks, peaking at 700,000 requests per second and sustaining 8 Gbps during major strikes. Key attack tactics included cache-busting, geodiverse patterns, and randomized user agents.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2LUqmbf6tgYWBxAUhux8tf/401681b4b325ff8a90acae824060cd32/BLOG-2648_3.png"/></figure><p>State and local websites also faced increased threats, with 290 million malicious requests blocked since September under Cloudflare’s Athenian Project. Compared to 2020, attacks in 2024 were far more intense, underscoring the growing need for robust cybersecurity to protect elections from disruption.</p><p>In <b>France</b>, DDoS attacks plagued multiple political parties, with peaks reaching 96,000 requests per second (rps) on election day, July 7. Additional details are available in our related <a href="https://blog.cloudflare.com/2024-french-elections-political-cyber-attacks-and-internet-traffic-shifts/"><u>blog post</u></a>.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2vXeTFoMMMprBcFQHtGT4E/d799e896740ebd74a2803e6d21e6b1d1/BLOG-2648_4.png"/></figure><p>In the <b>United Kingdom</b>, DDoS attacks targeted political parties, with the most severe incident affecting a campaign website, reaching 156,000 rps shortly after the results were announced on election day. Additional details are available in our related <a href="https://blog.cloudflare.com/2024-french-elections-political-cyber-attacks-and-internet-traffic-shifts/"><u>blog post</u></a>.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/43DeCSFeJHsPMK3MqgGhMJ/b0cf8050e2751e4fc2cb745ccb93f839/BLOG-2648_5.png"/></figure><p>During the European parliamentary elections in early June, cyberattacks targeted several political websites around election days. Notably, a significant DDoS attack focused on two politically-related websites in the <b>Netherlands</b> on June 5–6 (with June 6 being election day), peaking at 73,000 rps.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Z5F68CqmuIftAd7mNyzht/e5181cdf2fc64bd2f5b3c3a61fbf0374/BLOG-2648_6.png"/></figure><p>In <b>Romania</b>, the weeks leading up to the election cycle culminating in the December 1 parliamentary elections saw DDoS attacks targeting political party websites and news organizations.</p><p>In <b>South Africa</b>, where the general election took place on May 29, there was a relevant DDoS attack in the weeks leading up to the election, targeting a major news site within the country for several days, with a peak on May 7 of 54,000 requests per second.</p><p>In <b>Portugal</b>, several DDoS attacks targeted political party websites on election day, March 10, particularly after polling stations closed. One political party’s websites experienced a peak of 69,000 rps on May 11 at 00:50 UTC.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Bh3PXP8WCMOz2hW1ndHJO/84f89609bd8d232104ee682ed04d5fe8/BLOG-2648_7.png"/></figure><p>In <b>Taiwan</b>, a local fact-checking website faced a DDoS attack three days before the election, on January 10.</p><p>In <b>Japan</b>, a DDoS attack targeted a website used to report scams and misinformation a week before the October 27 election.</p><p>While some of these rates may seem small to Cloudflare, they can be devastating for websites not well-protected against such high levels of traffic. DDoS attacks not only overwhelm systems but also serve, if successful, as a distraction for IT teams while attackers attempt other types of breaches.</p><div><h3>Election-related Internet shutdowns </h3><a href="#election-related-internet-shutdowns"></a></div><p>Several times in 2024, election-related Internet shutdowns were imposed by authorities for various reasons, such as in the Comoros and Pakistan.</p><p><b>Comoros</b>, a small archipelago country in Southeastern Africa with a population of less than 1 million, held presidential elections on January 14, which led to <a href="https://www.bbc.com/news/world-africa-68027892"><u>protests</u></a> against the re-election of President Azali Assoumani. Authorities shut down the Internet on January 17, causing a <a href="https://x.com/CloudflareRadar/status/1748326986936635764"><u>50%</u></a> drop in traffic compared to the previous week, lasting for two days.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/72ba6O4SEVjDesw4W9hUTP/7a5e06d815f8dcefc91599d030ef5e99/BLOG-2648_8.png"/></figure><p><b>Pakistan’s</b> general election day on February 8 was marked by <a href="https://blog.cloudflare.com/q1-2024-internet-disruption-summary/#pakistan"><u>an Internet shutdown targeting mobile networks</u></a>. The outage began around 02:00 UTC, reducing Internet traffic by 50% compared to the previous week. Traffic only began recovering after 15:00, highlighting the severe impact of government-initiated shutdowns on Internet connectivity.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7J1emwVOlzOXIqgQicFF0j/76b7410baba969406a138a9a2ce444d9/BLOG-2648_9.png"/></figure><p>In <b>Mauritius</b>, an island nation in the Indian Ocean with under 2 million residents, the <a href="https://apnews.com/article/mauritius-social-media-suspension-elections-pravind-jugnauth-2e4e13fcd2ab37c32f85e4d042726022"><u>government suspended access to social media</u></a> platforms from November 1 to November 11 ahead of the November 10 parliamentary elections. </p><div><h2>Other election-related Internet traffic trends </h2><a href="#other-election-related-internet-traffic-trends"></a></div><p>Election-day Internet traffic patterns often reflect a country’s dominant device usage, with mobile-first nations like Indonesia, Mozambique, and Ghana experiencing noticeable traffic drops after polling stations closed. While mobile-friendly countries generally see steady or higher weekend traffic compared to desktop-focused regions like Europe and the Americas, no consistent trend emerged linking device preference to overall election-day traffic increases or decreases.</p><p>Here’s a world map from our <a href="https://radar.cloudflare.com/year-in-review/2024/"><u>Year in Review 2024</u></a> showing countries where mobile (purple) or desktop (green) dominates Internet traffic.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/PkHEsQJb6AQXtjWkRYfXP/f3d1c9d2d5190f9bd76cbbb1491b3e05/BLOG-2648_10.png"/></figure><p>Now, let’s explore a selection of relevant elections with Internet traffic impacts, ordered by election dates:</p><p><b>Taiwan (January 13)</b>Taiwan’s presidential election saw traffic drop slightly during polling hours, especially in the morning with an 8% drop. Traffic returned to usual levels after 17:00 local time. Post-election, traffic rose by 5% the next morning compared to the previous week.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6C1idfrGkUZFDdZY8NJXm4/4cc00af6e267508a622505fccac9571a/BLOG-2648_11.png"/></figure><p><b>Finland (January 28)</b>On January 28, Finland held its presidential election. Internet traffic dropped by 24% at 11:00 local time, coinciding with higher voter turnout in the morning. A second noticeable drop of 13% occurred at 20:00 when polling stations closed and TV stations broadcast initial projections, though traffic was slightly higher than usual afterward.</p><p><b>Indonesia (February 14) </b>Indonesia held its general election on February 14. With over 200 million voters spread across 17,000 islands, it likely had the highest number of voters on a single day, unlike India’s multi-week election. During polling hours (08:00 to 13:00 local time), Internet traffic dropped by up to 15%. Traffic remained lower than the previous week for the rest of the day, with drops ranging from 8% to 16% throughout the night. Mobile device usage surged to 77%, the highest of the year, reflecting Indonesia’s mobile-first Internet culture. Traffic recovered the next morning, surpassing the previous week’s levels.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6GW0q1qUfbJcPbFjd21Vv/965626dabdc6ca4e3eb9e961cdec858a/BLOG-2648_12.png"/></figure><p><b>Portugal (March 10)</b>Portugal’s parliamentary election on March 10 saw a sharp 16% traffic drop at 20:00 local time when TV stations began broadcasting projections. Traffic picked up after that and remained stable during the day.</p><p><b>Russia (March 17)</b>Russia’s presidential election showed steady Internet traffic throughout the day but experienced a 7% decrease after polls closed as results and reactions were broadcast on TV. Unlike other countries, where post-election traffic surges are common, Russia’s pattern reflects the strong influence of broadcast media on election coverage.</p><p><b>South Korea (April 10)</b>South Korea held legislative elections on April 10. Traffic was higher than usual before 05:00 local time but dropped 14% by 07:15 after polling stations opened at 06:00. By 11:45, traffic had rebounded above typical levels. After polling stations closed at 18:00, traffic dropped again, with a 7% decline compared to the previous week.</p><p><b>India (April 19–June 1) - </b><a href="https://blog.cloudflare.com/internet-insights-on-2024-elections-in-the-netherlands-south-africa-iceland-india-and-mexico/"><b><u>related blog post</u></b></a>India’s seven-phase general election saw significant Internet traffic fluctuations. May 7 recorded the largest nationwide traffic dip of 6%, with populous states like Uttar Pradesh seeing a 9% drop and Maharashtra experiencing a 17% decline. On the final election day (June 1), mobile device usage peaked at 68%, the highest of the year. These patterns underscore India’s mobile-first Internet habits and its diverse election timelines.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3G1p1RGYaAJy2t85MQkOmf/1b9e666380db8ca6cb5a241092466e3f/BLOG-2648_13.png"/></figure><p><b>North Macedonia (April 24 &amp; May 8)</b>North Macedonia’s two-round presidential election featured a 56% traffic increase after 11:00 local time on May 8, sustained throughout the day. Similar, albeit smaller, trends were observed during the first round on April 24.</p><p><b>Panama (May 5)</b>On May 5, Panama’s presidential and parliamentary election day, Internet traffic dropped significantly while voting stations were open, with a 23% decrease in the afternoon and 25% lower traffic at 21:30 local time as results were announced. Traffic picked up after that.</p><p><b>South Africa (May 29) - </b><a href="https://blog.cloudflare.com/internet-insights-on-2024-elections-in-the-netherlands-south-africa-iceland-india-and-mexico/"><b><u>related blog post</u></b></a>On May 29, South Africa’s general election saw Internet traffic decrease by 16% at 05:45 and remain lower throughout polling hours. Traffic surged by 25% the night before the election, peaking at midnight. Post-election, traffic increased by up to 12% early on May 30, highlighting the transition from offline to online engagement.</p><p><b>Mexico (June 2) - </b><a href="https://blog.cloudflare.com/internet-insights-on-2024-elections-in-the-netherlands-south-africa-iceland-india-and-mexico/"><b><u>related blog post</u></b></a>Mexico’s general election on June 2 saw a 3% daily traffic drop, with hourly dips of up to 11% during polling hours (08:00–20:00 local time). Traffic surged by 14% at 01:30 the following day as results were announced, peaking at 8% above the previous week by 22:00 local time.</p><p><b>Iceland (June 1)</b>Iceland’s presidential election on June 1 saw minor Internet traffic drops, including a 12% dip between 14:00 and 16:00 local time, but traffic increased at night by as much as 11% at 20:00. The day after, traffic rose by 26% compared to the previous week. Iceland elected Halla Tómasdóttir as its second female president.</p><p><b>European Union (June 6–9) - </b><a href="https://blog.cloudflare.com/exploring-the-2024-eu-election-internet-traffic-trends-and-cybersecurity-insights/"><b><u>related blog post</u></b></a>The 2024 European Parliament elections showed notable Internet traffic shifts and cybersecurity challenges. The Czech Republic and Slovakia experienced traffic drops of over 10%, while Finland and Ireland saw moderate declines. Key speeches, such as Belgian Prime Minister Alexander De Croo’s resignation and French President Macron’s snap election announcement, also caused traffic fluctuations.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7s9Gc0c394zNszAUuc23Jb/e63c55e6477c875b8427469b881f0ec8/BLOG-2648_14.png"/></figure><p><sup><i>Source: Cloudflare; created with Datawrapper</i></sup></p><p><b>Iran (June 28)</b>Iran’s presidential election saw significant traffic fluctuations, with traffic falling by 16% after 17:30 local time. Extended polling hours (including at night) led to continued drops, falling to 24% lower by 22:30. After midnight, traffic rebounded, showing a 13% increase compared to the previous week.</p><p><b>France (June 30 &amp; July 7) - </b><a href="https://blog.cloudflare.com/2024-french-elections-political-cyber-attacks-and-internet-traffic-shifts/"><b><u>related blog post</u></b></a>France’s legislative elections brought significant Internet and cybersecurity activity. On July 7, Internet traffic dropped 16% at 20:00 local time as polling stations closed and TV broadcasts announced results. Mobile device usage surged to 58%, and DNS traffic to news outlets spiked by 250% during the first round and by 244% on runoff day, reflecting heightened public interest.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3X3WZo3RMQu9944oUtc23V/2e2c61c3cc0d77045ff8fcd7ff0af8e2/BLOG-2648_15.png"/></figure><p><b>United Kingdom (July 4) - </b><a href="https://blog.cloudflare.com/uk-election-day-2024-traffic-trends-and-attacks-on-political-parties/"><b><u>related blog post</u></b></a>The UK’s general election on July 4 saw the Labour Party win a majority after 14 years of Conservative rule. Internet traffic declined slightly during voting hours, with a 2% drop at noon, before surging in the evening as results were announced. Northern Ireland experienced the sharpest traffic drop (10%), compared to 6% in Scotland and 5% in Wales. DNS traffic to election-related domains peaked with increases of 600% at 22:00 and 671% at 04:00 the following day.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1O4VzkC2RZXUoSiaULXHir/b74a889b506a40ba0ff8f5894055b0b0/BLOG-2648_16.png"/></figure><p><b>Sri Lanka (September 21)</b>Sri Lanka’s presidential election caused a 9% morning traffic dip and an 18% post-election surge after polls closed. Results triggered a 109% traffic increase at 03:00 local time on September 22.</p><p><b>Tunisia (October 6)</b>Tunisia’s presidential election saw a 15% traffic dip at 17:00, followed by a 13% decline at 19:30 when results started arriving. The steady traffic decrease highlights the evening focus on offline engagement and result tracking.</p><p><b>Mozambique (October 9)</b>Mozambique’s election drove an Internet traffic drop throughout the day, falling as much as 51% by 20:30 local time, and continuing lower than usual after that. A post-election surge of 16% occurred at 01:30. The election, held on a public holiday, resulted in a 31% daily traffic drop compared to the previous week.</p><p><b>Georgia (October 26)</b>When Georgia held its parliamentary election on October 26, Internet traffic was 11% higher than the previous week, peaking at 67% above normal around 23:00 when results were announced. Unlike other countries, traffic only dipped slightly (2%) in the afternoon during polling hours.</p><p><b>Japan (October 27)</b>Japan’s House of Representatives election saw Internet traffic decrease by 4% at 20:00 after polling stations closed, but it rose later in the evening.</p><p><b>Botswana (October 30)</b>A traffic drop was observed throughout the day of Botswana’s general election, with a 42% decrease around 21:30 local time compared to the previous week.</p><p><b>United States (November 5) - </b><a href="https://blog.cloudflare.com/exploring-internet-traffic-shifts-and-cyber-attacks-during-the-2024-us-election/"><b><u>related blog post</u></b></a>The US elections saw a 15% spike in Internet traffic, particularly after polls closed, with the Midwest leading. There were also specific spikes related to key moments during election night, as the next chart shows: </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1pSMZDroAQWViUyhwvvLEs/ccb47a566c67069350ca19ef6b241ce6/BLOG-2648_17.png"/></figure><p>DNS traffic surged by 756% to polling services and 325% to news sites. As highlighted in our recent <a href="https://cfl.re/4ipIdhZ"><u>Internet Services Year in Review blog post</u></a>, the US election also boosted DNS traffic and ranking positions for CNN, Fox News, and The New York Times, underscoring the Internet’s critical role during major political events.</p><p>In the US, beyond <a href="https://blog.cloudflare.com/exploring-internet-traffic-shifts-and-cyber-attacks-during-the-2024-us-election/"><u>election day</u></a>, we also reported in 2024 on trends surrounding the first <a href="https://blog.cloudflare.com/how-the-first-2024-us-presidential-debate-influenced-internet-traffic-and-security-trends"><u>Biden vs. Trump debate</u></a>, the <a href="https://blog.cloudflare.com/exploring-internet-traffic-during-the-2024-us-republican-national-convention"><u>attempted assassination of Trump and the Republican National Convention</u></a>, the <a href="https://blog.cloudflare.com/internet-security-trends-2024-us-democratic-convention"><u>Democratic National Convention</u></a>, and the <a href="https://blog.cloudflare.com/how-the-harris-trump-us-presidential-debate-influenced-internet-traffic"><u>Harris-Trump presidential debate</u></a>.</p><p><b>Ghana (December 7)</b>Ghana’s general election caused mid-morning traffic drops of 11%, followed by declines of 13% and 14% after polling stations closed at 17:00. These patterns indicate offline focus during results announcements.</p><p><b>Romania (December 1)</b>Romania’s parliamentary election showed minimal traffic fluctuations during the day, though its November 24 presidential election remains disputed.</p><div><h2>Email perspectives on the US presidential election</h2><a href="#email-perspectives-on-the-us-presidential-election"></a></div><p>From a cybersecurity perspective, trending <a href="https://blog.cloudflare.com/paris-2024-olympics-recap"><u>events</u></a>, topics, and individuals often attract more emails, including malicious, phishing, and spam messages. In our analysis <a href="https://blog.cloudflare.com/exploring-internet-traffic-shifts-and-cyber-attacks-during-the-2024-us-election/"><u>earlier</u></a> this year, we focused on the US presidential elections and the two major party candidates.</p><p>From June 1 to November 5, 2024, Cloudflare processed over 19 million emails mentioning "Donald Trump" or "Kamala Harris," with Trump appearing more frequently and in higher rates of spam (12%) and malicious emails (1.3%) compared to Harris (0.6% spam, 0.2% malicious). Nearly half were sent after September, with a surge in the final 10 campaign days.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6uAzBIxewULmhPPjNaWLYu/4464d2e3953d3a527651d78252f8aa8b/BLOG-2648_18.png"/></figure><div><h2>Conclusion: the election cycle doesn’t stop</h2><a href="#conclusion-the-election-cycle-doesnt-stop"></a></div><p>As a global election year, 2024 underscored how deeply the Internet is woven into the democratic process, serving both as a tool for engagement and a target for disruption. From relevant DDoS attacks to government-imposed Internet shutdowns, the challenges faced during these elections reflect a growing need for robust cybersecurity measures to safeguard critical infrastructure and ensure free, fair electoral processes.</p><p>In this context, Germany has announced an anticipated <a href="https://en.wikipedia.org/wiki/2025_German_federal_election"><u>federal election for February 23, 2025</u></a>, following the collapse of its governing coalition during the 2024 government crisis. This snap election joins others in France and the UK, reflecting a growing trend of political instability requiring urgent electoral responses.</p><p>Looking ahead, the increasing frequency and complexity of cyber threats, such as DDoS attacks on campaigns and election infrastructure, demand proactive defenses. Shutdowns like those in Pakistan and Comoros, along with surges in phishing and misinformation, highlight the need for closer collaboration between governments, technology providers, and civil society to safeguard democracy in the digital era.</p><p>If you want to follow more trends and insights about the Internet and elections in particular, you can check <a href="https://radar.cloudflare.com/"><u>Cloudflare Radar</u></a>, and more specifically our new <a href="https://radar.cloudflare.com/reports/elections-2024"><u>2024 Elections Insights</u></a> report.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Global elections in 2024: Internet traffic and cyber threat trends" href="https://blog.cloudflare.com/elections-2024-internet/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Global elections in 2024: Internet traffic and cyber threat trends</span><span class="cap link fs12">https://blog.cloudflare.com/elections-2024-internet/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Hi Claude, Build an MCP Server on Cloudflare Workers</title>
    <link href="https://blog.imc.re/RSSBOX/rss/9920173b.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/9920173b.html</id>
    <published>2024-12-20T14:50:00.000Z</published>
    <updated>2024-12-20T14:50:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>In late November 2024, Anthropic <a href="https://www.anthropic.com/news/model-context-protocol"><u>announced</u></a> a new way to interact with AI, called Model Context Protocol (MCP). Today, we’re excited to show you how to use MCP in combination with Cloudflare to extend the capabilities of Claude to build applications, generate images and more. You’ll learn how to build an MCP server on Cloudflare to make any service accessible through an AI assistant like Claude with just a few lines of code using Cloudflare Workers. </p><div><h2>A quick primer on the Model Context Protocol (MCP)</h2><a href="#a-quick-primer-on-the-model-context-protocol-mcp"></a></div><p>MCP is an open standard that provides a universal way for LLMs to interact with services and applications. As the introduction on the <a href="https://modelcontextprotocol.io/introduction"><u>MCP website</u></a> puts it, </p><blockquote><p><i>“Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.”</i> </p></blockquote><p>From an architectural perspective, MCP is comprised of several components:</p><ul><li><p><b>MCP hosts</b>: Programs or tools (like Claude) where AI models operate and interact with different services</p></li><li><p><b>MCP clients</b>: Client within an AI assistant that initiates requests and communicates with MCP servers to perform tasks or access resources</p></li><li><p><b>MCP servers</b>: Lightweight programs that each expose the capabilities of a service</p></li><li><p><b>Local data sources</b>: Files, databases, and services on your computer that MCP servers can securely access</p></li><li><p><b>Remote services</b>: External Internet-connected systems that MCP servers can connect to through APIs</p></li></ul><p>Imagine you ask Claude to send a message in a Slack channel. Before Claude can do this, Slack must communicate which tools are available. It does this by defining tools — such as “list channels”, “post messages”, and “reply to thread” — in the MCP server. Once the MCP client knows what tools it should invoke, it can complete the task. All you have to do is tell it what you need, and it will get it done. </p><div><h2>Allowing AI to not just generate, but deploy applications for you</h2><a href="#allowing-ai-to-not-just-generate-but-deploy-applications-for-you"></a></div><p>What makes MCP so powerful? As a quick example, by combining it with a platform like Cloudflare Workers, it allows Claude users to deploy a Cloudflare Worker in just one sentence, resulting in a site like <a href="https://joke-site.dinas.workers.dev/"><u>this</u></a>: </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6JNebermBM0YNwpxqoMTj2/65224c915a3d12c4f8d11a4228855bf7/image1.png"/></figure><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KImc4ydvEzg8Rf0I0KRkQ/b87b4cca33df242eeabcae9e237e9fb5/image3.png"/></figure><p>But that’s just one example. Today, we’re excited to show you how you can build and deploy your own MCP server to allow your users to interact with your application directly from an LLM like Claude, and how you can do that just by writing a Cloudflare Worker.</p><div><h2>Simplifying your MCP Server deployment with workers-mcp</h2><a href="#simplifying-your-mcp-server-deployment-with-workers-mcp"></a></div><p>The new <a href="https://github.com/cloudflare/workers-mcp"><u>workers-mcp</u></a> tooling handles the translation between your code and the MCP standard, so that you don’t have to do the maintenance work to get it set up.</p><p>Once you create your Worker and install the MCP tooling, you’ll get a worker-mcp template set up for you. This boilerplate removes the overhead of configuring the MCP server yourself:</p><pre><code>import &#123; WorkerEntrypoint &#125; from 'cloudflare:workers'import &#123; ProxyToSelf &#125; from 'workers-mcp'export default class MyWorker extends WorkerEntrypoint&lt;Env&gt; &#123;  /**   * A warm, friendly greeting from your new Workers MCP server.   * @param name &#123;string&#125; the name of the person we are greeting.   * @return &#123;string&#125; the contents of our greeting.   */  sayHello(name: string) &#123;    return `Hello from an MCP Worker, $&#123;name&#125;!`  &#125;  /**   * @ignore   **/  async fetch(request: Request): Promise&lt;Response&gt; &#123;    return new ProxyToSelf(this).fetch(request)  &#125;&#125;</code></pre><p>Let’s unpack what’s happening here. This provides a direct link to MCP. The ProxyToSelf logic ensures that your Worker is wired up to respond as an MCP server, without any complex routing or schema definitions. </p><p>It also provides tool definition with <a href="https://jsdoc.app/"><u>JSDoc</u></a>. You’ll notice that the `sayHello` method is annotated with JSDoc comments describing what it does, what arguments it takes, and what it returns. These comments aren’t just for human readers, but they’re also used to generate documentation that your AI assistant (Claude) can understand. </p><div><h2>Adding image generation to Claude</h2><a href="#adding-image-generation-to-claude"></a></div><p>When you build an MCP server using Workers, adding custom functionality to an LLM is easy. Instead of setting up the server infrastructure, defining request schemas, all you have to do is write the code. Above, all we did was generate a “hello world”, but now let’s power up Claude to generate an image, using Workers AI:</p><pre><code>import &#123; WorkerEntrypoint &#125; from 'cloudflare:workers'import &#123; ProxyToSelf &#125; from 'workers-mcp'<p>export default class ClaudeImagegen extends WorkerEntrypoint&lt;Env&gt; &amp;#123;<br> &#x2F;**</p><ul><li>Generate an image using the flux-1-schnell model.</li><li>@param prompt &amp;#123;string&amp;#125; A text description of the image you want to generate.</li><li>@param steps &amp;#123;number&amp;#125; The number of diffusion steps; higher values can improve quality but take longer.</li></ul><p>   *&#x2F;<br>  async generateImage(prompt: string, steps: number): Promise&lt;string&gt; &amp;#123;<br>    const response &#x3D; await this.env.AI.run(‘@cf&#x2F;black-forest-labs&#x2F;flux-1-schnell’, &amp;#123;<br>      prompt,<br>      steps,<br>    &amp;#125;);<br>        &#x2F;&#x2F; Convert from base64 string<br>        const binaryString &#x3D; atob(response.image);<br>        &#x2F;&#x2F; Create byte representation<br>        const img &#x3D; Uint8Array.from(binaryString, (m) &#x3D;&gt; m.codePointAt(0)!);</p><pre><code>    return new Response(img, &amp;#123;      headers: &amp;#123;        &#39;Content-Type&#39;: &#39;image/jpeg&#39;,      &amp;#125;,    &amp;#125;);  &amp;#125;</code></pre><p>  &#x2F;**</p><ul><li>@ignore</li></ul><p>   *&#x2F;<br>  async fetch(request: Request): Promise&lt;Response&gt; &amp;#123;<br>    return new ProxyToSelf(this).fetch(request)<br>  &amp;#125;<br>&amp;#125;</code></pre></p><p>Once you update the code and redeploy the Worker, Claude will now be able to use the new image generation tool. All you have to say is: <i>“Hey! Can you create an image of a lava lamp wall that lives in San Francisco?”</i></p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/Izb6iVs8xPNSOnATJfK9D/9942ddc7b8787cfb1c2f7f3b9959be0b/image2.png"/></figure><p>If you’re looking for some inspiration, here are a few examples of what you can build with MCP and Workers: </p><ul><li><p>Let Claude send follow-up emails on your behalf using <a href="https://developers.cloudflare.com/email-routing/"><u>Email Routing</u></a></p></li><li><p>Ask Claude to capture and share website previews via <a href="https://developers.cloudflare.com/browser-rendering/"><u>Browser Automation</u></a></p></li><li><p>Store and manage sessions, user data, or other persistent information with <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Objects</u></a></p></li><li><p>Query and update data from your <a href="https://developers.cloudflare.com/d1/"><u>D1</u></a> database </p></li><li><p>…or call any of your existing Workers directly!</p></li></ul><div><h2>Why use Workers for building your MCP server?</h2><a href="#why-use-workers-for-building-your-mcp-server"></a></div><p>To build out an MCP server without access to Cloudflare’s tooling, you would have to: initialize an instance of the server, define your APIs by creating explicit schemas for every interaction, handle request routing, ensure that the responses are formatted correctly, write handlers for every action, configure how the server will communicate, and more… As shown above, we do all of this for you.</p><p>For reference, an <a href="https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#creating-a-server"><u>implementation</u></a> may look something like this:</p><pre><code>import &#123; Server &#125; from "@modelcontextprotocol/sdk/server/index.js";import &#123; StdioServerTransport &#125; from "@modelcontextprotocol/sdk/server/stdio.js";<p>const server &#x3D; new Server(&amp;#123; name: “example-server”, version: “1.0.0” &amp;#125;, &amp;#123;<br>  capabilities: &amp;#123; resources: &amp;#123;&amp;#125; &amp;#125;<br>&amp;#125;);</p><p>server.setRequestHandler(ListResourcesRequestSchema, async () &#x3D;&gt; &amp;#123;<br>  return &amp;#123;<br>    resources: [&amp;#123; uri: “file:&#x2F;&#x2F;&#x2F;example.txt”, name: “Example Resource” &amp;#125;]<br>  &amp;#125;;<br>&amp;#125;);</p><p>server.setRequestHandler(ReadResourceRequestSchema, async (request) &#x3D;&gt; &amp;#123;<br>  if (request.params.uri &#x3D;&#x3D;&#x3D; “file:&#x2F;&#x2F;&#x2F;example.txt”) &amp;#123;<br>    return &amp;#123;<br>      contents: [&amp;#123;<br>        uri: “file:&#x2F;&#x2F;&#x2F;example.txt”,<br>        mimeType: “text&#x2F;plain”,<br>        text: “This is the content of the example resource.”<br>      &amp;#125;]<br>    &amp;#125;;<br>  &amp;#125;<br>  throw new Error(“Resource not found”);<br>&amp;#125;);</p><p>const transport &#x3D; new StdioServerTransport();<br>await server.connect(transport);</code></pre></p><p>While this works, it requires quite a bit of code just to get started. Not only do you need to be familiar with the MCP protocol, but you need to complete a fair amount of set up work (e.g. defining schemas) for every action. Doing it through Workers removes all these barriers, allowing you to spin up an MCP server without the complexity.</p><p>We’re always looking for ways to simplify developer workflows, and we’re excited about this new standard to open up more possibilities for interacting with LLMs, and building agents.</p><div></div><p>If you’re interested in setting this up, check out this <a href="https://www.youtube.com/watch?v=cbeOWKANtj8&amp;feature=youtu.be"><u>tutorial</u></a> which walks you through these examples. We’re excited to see what you build. Be sure to share your MCP server creations with us on <a href="https://discord.com/invite/cloudflaredev"><u>Discord</u></a>, <a href="https://x.com/CloudflareDev"><u>X</u></a>, or <a href="https://bsky.app/profile/cloudflare.social"><u>Bluesky</u></a>!</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Hi Claude, build an MCP server on Cloudflare Workers" href="https://blog.cloudflare.com/model-context-protocol/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Hi Claude, build an MCP server on Cloudflare Workers</span><span class="cap link fs12">https://blog.cloudflare.com/model-context-protocol/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Bring Multimodal Real-Time Interaction to Your AI Applications With Cloudflare Calls</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ef860f74.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ef860f74.html</id>
    <published>2024-12-20T14:00:00.000Z</published>
    <updated>2024-12-20T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p></p><p>OpenAI announced support for WebRTC in their <a href="https://platform.openai.com/docs/guides/realtime"><u>Realtime API</u></a> on December 17, 2024. Combining their Realtime API with <a href="https://www.cloudflare.com/developer-platform/products/cloudflare-calls/"><u>Cloudflare Calls</u></a> allows you to build experiences that weren’t possible just a few days earlier.</p><p>Previously, interactions with audio and video AIs were largely<i> single-player</i>: only one person could be interacting with the AI unless you were in the same physical room. Now, applications built using Cloudflare Calls and OpenAI’s Realtime API can now support multiple users across the globe simultaneously seeing and interacting with a voice or video AI.</p><div><h2>Have your AI join your video calls </h2><a href="#have-your-ai-join-your-video-calls"></a></div><p>Here’s what this means in practice: you can now invite ChatGPT to your next video meeting:</p><div></div><p>We built this into our <a href="https://github.com/cloudflare/orange"><u>Orange Meets</u></a> demo app to serve as an inspiration for what is possible, but the opportunities are much broader.</p><p>In the not-too-distant future, every company could have a  'corporate AI' they invite to their internal meetings that is secure, private and has access to their company data. Imagine this sort of real-time audio and video interactions with your company’s AI:</p><p>"Hey ChatGPT, do we have any open Jira tickets about this?"</p><p>"Hey Company AI, who are the competitors in the space doing Y?"</p><p>"AI, is XYZ a big customer? How much more did they spend with us vs last year?"</p><p>There are similar opportunities if your application is built for consumers: broadcasts and global livestreams can become much more interactive. The murder mystery game in the video above is just one example: you could build your own to play live with your friends in different cities.  </p><div><h2>WebRTC vs. WebSockets</h2><a href="#webrtc-vs-websockets"></a></div><p>These interactive multimedia experiences are enabled by the industry adoption of <a href="https://www.w3.org/TR/webrtc/"><u>WebRTC</u></a>, which stands for Web Real-time Communication.</p><p>Many real-time product experiences have historically used <a href="https://developer.mozilla.org/en-US/docs/Glossary/WebSockets"><u>Websockets</u></a> instead of WebRTC. Websockets operate over a single, persistent TCP connection established between a client and server. This is useful for maintaining a data sync for text-based chat apps or maintaining the state of gameplay in your favorite video game. Cloudflare has extensive support for Websockets <a href="https://developers.cloudflare.com/network/websockets/"><u>across our network</u></a> as well as <a href="https://blog.cloudflare.com/do-it-again/"><u>in our AI Gateway</u></a>.</p><p>If you were building a chat application prior to WebSockets, you would likely have your client-side app poll the server every n seconds to see if there are new messages to be displayed. WebSockets eliminated this need for polling. Instead, the client and the server establish a persistent, long-running connection to send and receive messages.</p><p>However, once you have multiple users across geographies simultaneously interacting with voice and video, small delays in the data sync can become unacceptable product experiences. Imagine building an app that does real-time translation of audio. With WebSockets, you would need to chunk the audio input, so each chunk contains 100–500 milliseconds of audio. That chunking size, along with the <a href="https://blog.cloudflare.com/cloudflare-calls-anycast-webrtc/#webrtc-growing-pains"><u>head-of-line blocking</u></a>, becomes the latency floor for your ability to deliver a real-time multimodal experience to your users.</p><p>WebRTC solves this problem by having native support for audio and video tracks over UDP-based channels directly between users, eliminating the need for chunking. This lets you stream audio and video data to an AI model from multiple users and receive audio and video data back from the AI model in real-time. </p><div><h2>Realtime AI fanout using Cloudflare Calls</h2><a href="#realtime-ai-fanout-using-cloudflare-calls"></a></div><p>Historically, setting up the underlying infrastructure for WebRTC — servers for media routing, TURN relays, global availability — could be challenging.</p><p><a href="https://developers.cloudflare.com/calls/introduction/"><u>Cloudflare Calls</u></a> handles the entirety of this complexity for developers, allowing them to leverage WebRTC without needing to worry about servers, regions, or scaling. Cloudflare Calls works as a single mesh network that automatically connects each user to a server close to them. Calls can connect directly with other WebRTC-powered services such as OpenAI’s, letting you deliver the output with near-zero latency to hundreds or thousands of users.</p><p>Privacy and security also come standard: all video and audio traffic that passes through Cloudflare Calls is encrypted by default. In this particular demo, we take it a step further by creating a button that allows you to decide when to allow ChatGPT to listen and interact with the meeting participants, allowing you to be more granular and targeted in your privacy and security posture. </p><div><h2>How we connected Cloudflare Calls to OpenAI’s Realtime API </h2><a href="#how-we-connected-cloudflare-calls-to-openais-realtime-api"></a></div><p>Cloudflare Calls has three building blocks: <a href="https://developers.cloudflare.com/calls/sessions-tracks/"><u>Applications, Sessions, and Tracks</u></a><b>:</b></p><blockquote><p><i>“A </i><b><i>Session</i></b><i> in Cloudflare Calls correlates directly to a WebRTC PeerConnection. It represents the establishment of a communication channel between a client and the nearest Cloudflare data center, as determined by Cloudflare's anycast routing … </i></p><p><i>Within a Session, there can be one or more </i><b><i>Tracks</i></b><i>. … [which] align with the MediaStreamTrack concept, facilitating audio, video, or data transmission.”</i></p></blockquote><p>To include ChatGPT in our video conferencing demo, we needed to add ChatGPT as a <i>track</i> in an ongoing <i>session. </i>To do this, we connected to the Realtime API in <a href="https://github.com/cloudflare/orange"><u>Orange Meets</u></a>:</p><pre><code>// Connect Cloudflare Calls sessions and tracks like a switchboardasync function connectHumanAndOpenAI(    humanSessionId: string,    openAiSessionId: string) &#123;    const callsApiHeaders = &#123;        Authorization: `Bearer $&#123;APP_TOKEN&#125;`,        'Content-Type': 'application/json',    &#125;    // Pull OpenAI audio track to human's track    await fetch(`$&#123;callsEndpoint&#125;/sessions/$&#123;humanSessionId&#125;/tracks/new`, &#123;        method: 'POST',        headers: callsApiHeaders,        body: JSON.stringify(&#123;            tracks: [                &#123;                    location: 'remote',                    sessionId: openAiSessionId,                    trackName: 'ai-generated-voice',                    mid: '#user-mic',                &#125;,            ],        &#125;),    &#125;)    // Pull human's audio track to OpenAI's track    await fetch(`$&#123;callsEndpoint&#125;/sessions/$&#123;openAiSessionId&#125;/tracks/new`, &#123;        method: 'POST',        headers: callsApiHeaders,        body: JSON.stringify(&#123;            tracks: [                &#123;                    location: 'remote',                    sessionId: humanSessionId,                    trackName: 'user-mic',                    mid: '#ai-generated-voice',                &#125;,            ],        &#125;),    &#125;)&#125;</code></pre><p>This code sets up the bidirectional routing between the human’s session and ChatGPT, which would allow the humans to hear ChatGPT and ChatGPT to hear the humans.</p><p>You can review all the code for this demo app on <a href="https://github.com/cloudflare/orange?tab=readme-ov-file#readme"><u>GitHub</u></a>. </p><div><h2>Get started today </h2><a href="#get-started-today"></a></div><p>Give the Cloudflare Calls + OpenAI Realtime API <a href="https://demo.orange.cloudflare.dev/"><u>demo a try</u></a> for yourself and review how it was built via <a href="https://github.com/cloudflare/orange?tab=readme-ov-file#readme"><u>the source code on GitHub</u></a>. Then get started today with <a href="https://developers.cloudflare.com/calls/introduction/"><u>Cloudflare Calls </u></a>to bring real-time, interactive AI to your apps and services.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Bring multimodal real-time interaction to your AI applications with Cloudflare Calls" href="https://blog.cloudflare.com/bring-multimodal-real-time-interaction-to-your-ai-applications-with-cloudflare-calls/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Bring multimodal real-time interaction to your AI applications with Cloudflare Calls</span><span class="cap link fs12">https://blog.cloudflare.com/bring-multimodal-real-time-interaction-to-your-ai-applications-with-cloudflare-calls/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Inside the Research: How GitHub Copilot Impacts the Nature of Work for Open Source Maintainers</title>
    <link href="https://blog.imc.re/RSSBOX/rss/9f7a102c.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/9f7a102c.html</id>
    <published>2024-12-20T11:08:03.000Z</published>
    <updated>2024-12-20T11:08:03.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>I’m excited to share an interview with two researchers that I’ve had the privilege of collaborating with on a recently released <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5007084">paper</a> studying how open source maintainers adjust their work after they start using GitHub Copilot:</p><ul><li><a href="www.manuelhoffmann.org">Manuel Hoffmann</a> is a postdoctoral scholar at the Laboratory for Innovation Science at Harvard housed within the Digital, Data, and Design Institute at Harvard Business School. He is also affiliated with Stanford University. His research interests lie in social and behavioral aspects around open source software and artificial intelligence, under the broader theme of innovation and technology management, with the aim of better understanding strategic aspects for large, medium-sized, and entrepreneurial firms.</li><li><a href="https://sboysel.github.io/">Sam Boysel</a> is a postdoctoral fellow at the Laboratory for Innovation Science at Harvard. He is an applied microeconomist with research interests at the intersection of digital economics, labor and productivity, industrial organization, and socio-technical networks. Specifically, his work has centered around the private provision of public goods, productivity in open collaboration, and welfare effects within the context of open source software (OSS) ecosystems.</li></ul><h2 id="research-qa">Research Q&amp;A<a aria-label="Research Q&amp;A" class="heading-link pl-2 text-italic text-bold" href="#research-qa"></a></h2><p><strong>Kevin:</strong> Thanks so much for chatting, Manuel and Sam! So, it seems like the paper’s really making the <a href="https://x.com/emollick/status/1853826293759869424?s=46&amp;t=K8URORCKeSdO5U1qGjMObg">rounds</a>. Could you give a quick high-level summary for our readers here?</p><p><strong>Manuel:</strong> Thanks to the great collaboration with you, <a href="https://www.sidapeng.com/">Sida Peng</a> from Microsoft and <a href="https://www.linkedin.com/in/frank-nagle/">Frank Nagle</a> from Harvard Business School, we study the impact of GitHub Copilot on developers and how this generative AI alters the nature of work. We find that when you provide developers in the context of open source software with a generative AI tool that reduces the cost of the core work of coding, developers increase their coding activities and reduce their project management activities. We find our results are strongest in the first year after the introduction but still exist even two years later. The results are driven by developers who are working more autonomously and less collaboratively since they do not have to engage with other humans to solve a problem but they can solve the problem through AI assistance.</p><figure class="wp-caption aligncenter mx-0" id="attachment_81759"><img><img alt="GitHub Copilot, on average, increases the share of coding for maintainers who use it. These effects are strongest in the first year, but they still persist over the course of two years." class="width-fit size-large wp-image-81759 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="1626" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2024/12/coding_relative_change_over_time.png?w=1024&amp;resize=2062%2C1626" width="2062"/></img><figcaption class="text-mono color-fg-muted mt-14px f5-mktg">GitHub Copilot, on average, increases the share of coding for maintainers who use it. These effects are strongest in the first year, but they still persist over the course of two years.</figcaption></figure><figure class="wp-caption aligncenter mx-0" id="attachment_81760"><img><img alt="GitHub Copilot, on average, reduces the share of project management for maintainers who use it. These effects are strongest in the first year, but still persist over the course of two years." class="width-fit size-large wp-image-81760 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="1632" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2024/12/project_management_relative_change_over_time.png?w=1024&amp;resize=2064%2C1632" width="2064"/></img><figcaption class="text-mono color-fg-muted mt-14px f5-mktg">GitHub Copilot, on average, reduces the share of project management for maintainers who use it. These effects are strongest in the first year, but still persist over the course of two years.</figcaption></figure><p><strong>Sam:</strong> That’s exactly right. We tried to even further understand the nature of work by digging into the paradigm of exploration vs exploitation. Loosely speaking, exploitation is the idea to exert effort towards the most lucrative of the already known options while exploration implies to experiment to find new options with a higher potential return. We tested this idea in the context of GitHub. Developers that had access to GitHub Copilot are engaged in more experimentation and less exploitation, that is, they start new projects with access to AI and have a lower propensity to work on older projects. Additionally, they expose themselves to more languages that they were previously not exposed to and in particular to languages that are valued higher in the labor market. A back-of-the-envelope calculation from purely experimentation among new languages due to GitHub Copilot suggests a value of around half a billion USD within a year.</p><p><strong>Kevin:</strong> Interesting! Could you provide an overview of the methods you used in your analysis?</p><p><strong>Manuel:</strong> Would be happy to! We are using a regression discontinuity design in this work, which is as close as you can get to a randomized control trial when purely using pre-existing data, such as the one from GitHub, without introducing randomization by the researcher. Instead, the regression discontinuity design is based on a ranking of developers and a threshold that GitHub uses to determine eligibility for <a href="https://docs.github.com/copilot/managing-copilot/managing-copilot-as-an-individual-subscriber/managing-your-copilot-subscription/getting-free-access-to-copilot-as-a-student-teacher-or-maintainer#about-free-copilot-access">free access</a> to GitHub Copilot’s top maintainer program.</p><p><strong>Sam:</strong> The main idea of this method is that a developer that is right below the threshold is roughly identical to a developer that is right above the threshold. Stated differently, by chance a developer happened to have a ranking that made them eligible for the generative AI while they could as well not have been eligible. Taken together with the idea that developers neither know the threshold nor the internal ranking from GitHub, we can be certain that the changes that we observe in coding, project management, and the other activities on the platform are only driven by the developers having access to GitHub Copilot and nothing else.</p><p><strong>Kevin:</strong> Nice! Follow-up question: could you provide an “explain like I’m 5” overview of the methods you used in your analysis?</p><p><strong>Manuel:</strong> Sure thing, let’s illustrate the problem a bit more. Some people use GitHub Copilot and others don’t. If we just looked at the differences between people who use GitHub Copilot vs. those who don’t, we’d be able to see that certain behaviors and characteristics are associated with GitHub Copilot usage. For example, we might find that people who use GitHub Copilot push more code than those who don’t. Crucially, though, that would be a statement about <em>correlation</em> and not about <em>causation</em>. Often, we want to figure out whether X causes Y, and not just that X is correlated with Y. Going back to the example, if it’s the case that those who use GitHub Copilot push more code than those who don’t, these are a few of the different explanations that might be at play:</p><ol><li>Using GitHub Copilot causes people to push more code.</li><li>Pushing more code causes people to use GitHub Copilot.</li><li>There’s something else that both causes people to use GitHub Copilot and causes them to push more code (for example, being a professional developer).</li></ol><p>Because (1), (2), and (3) could each result in data showing a correlation between GitHub Copilot usage and code pushes, just finding a correlation isn’t super interesting. One way you could isolate the cause and effect relationship between GitHub Copilot and code pushes, though, is through a randomized controlled trial (RCT).</p><p>In an RCT, we randomly assign people to use GitHub Copilot (the treatment group), while others are forbidden from using GitHub Copilot (the control group). As long as the assignment process is truly random and the users comply with their assignments, any outcome differences between the treatment and control groups can be attributed to GitHub Copilot usage. In other words, you could say that GitHub Copilot <em>caused</em> those effects. However, as anyone in the healthcare field can tell you, large-scale RCTs over long-time periods are often prohibitively expensive, as you’d need to recruit subjects to participate, monitor them to see if they complied with their assignments, and follow up with them over time.</p><p><strong>Sam:</strong> That’s right. So, instead, wouldn’t it be great if there would be a way to observe developers without running an RCT and <em>still</em> draw valid causal conclusions about GitHub Copilot usage? That’s where the regression discontinuity design (RDD) comes in. The random assignment aspect of an RCT allows us to compare the outcomes of two virtually identical groups. Sometimes, however, randomness already exists in a system, which we can use as a natural experiment. In the case of our paper, this randomness came in the form of GitHub’s internal ranking for determining which open source maintainers were eligible for free access to GitHub Copilot.</p><p>Let’s walk through a simplified example. Let’s imagine that there were one million repositories that were ranked on some set of metrics and the rule was that the top 500,000 repositories are eligible for free access to GitHub Copilot. If we compared the #1 ranked repository with the #1,000,000 ranked repository, then we would probably find that those two are quite different from each other. After all, the #1 repository is the best repository on GitHub by this metric while the #1,000,000 repository is a whole 999,999 rankings away from it. There are probably meaningful differences in code quality, documentation quality, project purpose, maintainer quality, etc. between the two repositories, so we would not be able to say that the only reason why there was a difference in outcomes for the maintainers of repository #1 vs. repository #1,000,000 was because of free access to GitHub Copilot.</p><p>However, what about repository #499,999 vs. repository #500,001? Those repositories are probably very similar to each other, and it was all down to random chance as to which repository made it over the eligibility threshold and which one did not. As a result, there is a strong argument that any differences in outcomes between those two repositories is solely due to repository #499,999 having free access to GitHub Copilot and repo #500,001 not having free access. Practically, you’ll want to have a larger sample size than just two, so you would compare a narrow set of repositories just above and below the eligibility threshold against each other.</p><p><strong>Kevin:</strong> Thanks, that’s super helpful. I’d be curious about the limitations of your paper and data that you wished you had for further work. What would the ideal dataset(s) look like for you?</p><p><strong>Manuel:</strong> Fantastic question! Certainly, no study is perfect and there will be limitations. We are excited to better understand generative AI and how it affects work in the future. As such, one limitation is the availability of information from private repositories. We believe that if we were to have information on private repositories we could test whether there is some more experimentation going on in private projects and that project improvements that were done with generative AI in private may spill over to the public to some degree over time.</p><p><strong>Sam:</strong> Another limitation of our study is the language-based exercise to provide a value of GitHub Copilot. We show that developers focus on higher value languages that they did not know previously and we extrapolated this estimate to all top developers. However, this estimate is certainly only a partial equilibrium value since developer wages may change over time in a full equilibrium situation if more individuals offer their services for a given language. However, despite the limitation, the value seems to be an underestimate since it does not contain any non-language specific experimentation value and non-experimentation value that is derived from GitHub Copilot.</p><p><strong>Kevin:</strong> Predictions for the future? Recommendations for policymakers? Recommendations for developers?</p><p><strong>Manuel:</strong> One simple prediction for the future is that AI incentivizes the activity for which it lowers the cost. However, it is not clear yet which parts will be incentivized through AI tools since they can be applied to many domains. It is likely that there are going to be a multitude of AI tools that incentivize different work activities which will eventually lead to employees, managers at firms, and policy-makers having to consider on which activity they want to put weight. We also would have to think about  new recombinations of work activities. Those are difficult to predict. <a href="https://www.rotman.utoronto.ca/the-rotman-experience/our-community/people/goldfarb-avi/">Avi Goldfarb</a>, a prolific professor from the University of Toronto, gave an example of the steam engine with his colleagues. Namely, work was organized in the past around the steam engine as a power source but once electric motors were invented, that was not necessary anymore and structural changes happened. Instead of arranging all of the machinery around a giant steam engine in the center of the factory floor, electricity enabled people to design better arrangements, which led to boosts in productivity. I find this historical narrative quite compelling and can imagine similarly for AI that the greatest power still remains to be unlocked and that it will be unlocked once we know how work processes can be re-organized. Developers can think as well about how their work may change in the future. Importantly, developers can actively shape that future since they are closest to the development of machine learning algorithms and artificial intelligence technologies.</p><p><strong>Sam:</strong> Adding on to those points, it is not clear when work processes change and whether it will have an inequality reducing or enhancing effect. Many predictions point towards an inequality enhancing effect since the training of large-language models requires substantial computing power which is often only in the hands of a few players. On the other hand, it has been documented that especially lower ability individuals seem to benefit the most from generative AI, at least in the short-term. As such, it’s imperative to understand how the benefits of generative AI are distributed across society. If not, are there equitable, welfare-improving interventions that can correct these imbalances? An encouraging result of our study suggests that generative AI can be especially impactful for relatively lesser skilled workers:</p><figure class="wp-caption aligncenter mx-0" id="attachment_81761"><img><img alt="Low ability developers are increasing their coding activity by more than high ability developers. The Max Centrality proxy measures the largest share of commits the developer made across all public repositories where they have made at least one commit. The Achievements proxy counts the cumulative total of “badges” the developer has earned on the GitHub platform. The Followers proxy counts the number of peers who subscribe to notifications for the developer’s activity on GitHub. The Tenure proxy is measured by counting the number of days since the developer created their GitHub account. A developer would be considered to be “high ability” for a proxy if they were above the median for that proxy and “low ability” for a proxy if they were below the median for that proxy. See Table A5 in the [paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5007084) for more information with summary statistics of each proxy." class="width-fit size-large wp-image-81761 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="1126" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2024/12/coding_by_ability.png?w=1024&amp;resize=2300%2C1126" width="2300"/></img><figcaption class="text-mono color-fg-muted mt-14px f5-mktg">Low ability developers are increasing their coding activity by more than high ability developers. The Max Centrality proxy measures the largest share of commits the developer made across all public repositories where they have made at least one commit. The Achievements proxy counts the cumulative total of “badges” the developer has earned on the GitHub platform. The Followers proxy counts the number of peers who subscribe to notifications for the developer’s activity on GitHub. The Tenure proxy is measured by counting the number of days since the developer created their GitHub account. A developer would be considered to be “high ability” for a proxy if they were above the median for that proxy and “low ability” for a proxy if they were below the median for that proxy.</figcaption></figure><figure class="wp-caption aligncenter mx-0" id="attachment_81762"><img><img alt="Low ability developers are reducing their project management activity by more than high ability developers. The Max Centrality proxy measures the largest share of commits the developer made across all public repositories where they have made at least one commit. The Achievements proxy counts the cumulative total of “badges” the developer has earned on the GitHub platform. The Followers proxy counts the number of peers who subscribe to notifications for the developer’s activity on GitHub. The Tenure proxy is measured by counting the number of days since the developer created their GitHub account. A developer would be considered to be “high ability” for a proxy if they were above the median for that proxy and “low ability” for a proxy if they were below the median for that proxy. See Table A5 in the [paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5007084) for more information with summary statistics of each proxy." class="width-fit size-large wp-image-81762 width-fit" data-recalc-dims="1" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" decoding="async" height="1082" loading="lazy" sizes="auto, (max-width: 1000px) 100vw, 1000px" src="https://github.blog/wp-content/uploads/2024/12/project_management_by_ability.png?w=1024&amp;resize=2316%2C1082" width="2316"/></img><figcaption class="text-mono color-fg-muted mt-14px f5-mktg">Low ability developers are reducing their project management activity by more than high ability developers.</figcaption></figure><p><strong>Sam (continued):</strong> Counter to widespread speculation that generative AI will replace many entry level tasks, we find reason to believe that AI can also lower the costs of experimentation and exploration, reduce barriers to entry, and level the playing field in certain segments of the labor market. It would be prudent for policymakers to monitor distributional effects of generative AI, allowing the new technology to deliver equitable benefits where it does so naturally but at the same time intervening in cases where it falls short.</p><h2 id="personal-qa">Personal Q&amp;A<a aria-label="Personal Q&amp;A" class="heading-link pl-2 text-italic text-bold" href="#personal-qa"></a></h2><p><strong>Kevin:</strong> I’d like to change gears a bit to chat more about your personal stories. Manuel, I know you’ve worked on research analyzing health outcomes with Stanford, diversity in TV stations, and now you’re studying nerds on the internet. Would love to learn about your journey to getting there.</p><p><strong>Manuel:</strong> Sure! I was actually involved with “nerds on the internet” longer than my vita might suggest. Prior to my studies, I was using open source software, including Linux and Ubuntu, and programming was a hobby for me. I enjoyed the freedom that one had on the personal computer and the internet. During my studies, I discovered economics and business studies as a field of particular interest. Since I was interested in causal inference and welfare from a broader perspective, I learned how to use experimental and quasi-experimental studies to better understand social, medical and technological innovation that are relevant for individuals, businesses, and policy makers. I focused on labor and health during my PhD and afterwards I was able to lean a bit more into health at Stanford University. During my time at Harvard Business School, the pendulum swung back a bit towards labor. As such, I was in the fortunate position—thanks to the study of the exciting field of open source software—to continuously better understand both spaces.</p><p><strong>Kevin:</strong> Haha, great to hear your interest in open source runs deep! Sam, you also have quite the varied background, analyzing cleantech market conditions and the effects of employment verification policies, and you also seem to have been studying nerds on the internet for the past several years. Could you share a bit about your path?</p><p><strong>Sam:</strong> I’ve been a computing and open source enthusiast since I got my hands on a copy of “OpenSUSE for Dummies” in middle school. As an undergraduate, I was drawn to the social science aspect of economics and its ability to explain or predict human behavior across a wide range of settings. After bouncing around a number of subfields in graduate school, I got the crazy idea to combine my field of study with my passion and never looked back. Open source is an incredibly data-rich environment with a wealth of research questions interesting to economists. I’ve studied the role of peer effects in driving contribution, modelled the formation of software dependency networks using strategic behavior and risk aversion, and explored how labor market competition shapes open source output.</p><p>And thanks, Kevin. I’ll be sure to work “nerds on the internet” into the title of the next paper.</p><p><strong>Kevin:</strong> Finding a niche that you’re passionate about is such a joy, and I’m curious about how you’ve found living in that niche. What’s the day-to-day like for you both?</p><p><strong>Manuel:</strong> The day-to-day can vary but as an academic, there are a few tasks that are recurring at a big picture level. Research, teaching and other work. Let’s focus on the research bucket. I am quite busy with working on causal inference papers, refining them but also speaking to audiences to communicate our work. Some of the work is done jointly, some by oneself, so there is a lot of variation, and the great part of being an academic is that one can choose that variation oneself through the projects one selects. Over time one has to juggle many balls. Hence, I am working on finishing prior papers in the space of health; for example, some that you alluded to previously on <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3921511">Television, Health and Happiness</a> and <a href="https://www.iza.org/de/publications/dp/12939/vaccines-at-work">Vaccination at Work</a>, but also in the space of open source software, importantly, to improve the paper on <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5007084">Generative AI and the Nature of Work</a>. We have continuously more ideas to better understand the world we are living and going to live in at the intersection of open source software and generative AI and, as such, it is very valuable to relate to the literature and eventually answer exciting questions around the future of work with real world data. GitHub is a great resource for that.</p><p><strong>Sam:</strong> As an applied researcher, I use data to answer questions. The questions can come from current events, from conversations with both friends and colleagues, or simply musing on the intricacies of the open source space. Oftentimes the data comes from publicly observed behavior of firms and individuals recorded on the internet. For example, I’ve used static code analysis and version control history to characterize the development of open source codebases over time. I’ve used job postings data to measure firm demand for open source skills. I’ve used the dependency graphs of packaging ecosystems to track the relationships between projects. I can then use my training in economic theory, econometric methodology, and causal inference to rigorously explore the question. The end result is written up in an article, presented to peers, and iteratively improved from feedback.</p><p><strong>Kevin:</strong> Have things changed since generative AI tooling came along? Have you found generative AI tools to be helpful?</p><p><strong>Manuel:</strong> Definitely. I use GitHub Copilot when developing experiments and programming in Javascript together with another good colleague, <a href="https://danielgstephenson.com/">Daniel Stephenson</a> from Virginia Commonwealth University. It is interesting to observe how often Copilot actually makes code suggestions based on context that are correct. As such, it is an incredibly helpful tool. However, the big picture of what our needs are can only be determined by us, as such, in my experience Copilot does seem to speed up the process and leads to avoiding some mistakes conditional on not just blindly following the AI.</p><p><strong>Sam:</strong> I’ve only recently begun using GitHub Copilot, but it’s had quite an impact on my workflow. Most social sciences researchers are not skilled software engineers. However, they must also write code to hit deadlines. Before generative AI, the delay between problem and solution was usually characterized by many search queries, parsing Q&amp;A forums or documentation, and a significant time cost. Being able to resolve uncertainty within the IDE is incredible for productivity.</p><p><strong>Kevin:</strong> Advice you might have for folks who are starting out in software engineering or research? What tips might you give to a younger version of yourself, say, from 10 years ago?</p><p><strong>Manuel:</strong> I will talk a bit at a higher level. Find work, questions or problems that you deeply care about. I would say that is a universal rule to be satisfied, be it in software engineering, research or in any other area. In a way, think about the motto, “You only live once,” as a pretty applicable misnomer. Another universal advice that has high relevance is to not care too much about the things you cannot change but focus on what you can control. Finally, think about getting advice from many different people, then pick and choose. People have different mindsets and ideas. As such, that can be quite helpful.</p><p><strong>Sam:</strong></p><ul><li>Being able to effectively communicate with both groups (software eng and research) is extremely important.</li><li>You’ll do your best work on things you’re truly passionate about.</li><li>Premature optimization <em>truly</em> is the root of all evil.</li></ul><p><strong>Kevin:</strong> Learning resources you might recommend to someone interested in learning more about this space?</p><p><strong>Manuel:</strong> There are several aspects we have touched upon—Generative AI Research, Coding with Copilot, Causal Inference and Machine Learning, Economics, and Business Studies. As such, here is one link for each topic that I can recommend:</p><ul><li>Generative AI research: <a href="https://www.linkedin.com/in/emollick/">Ethan Mollick’s social media posts</a></li><li>Coding with Copilot: <a href="https://learn.microsoft.com/en-us/training/modules/advanced-github-copilot/">Advanced GitHub Copilot features</a></li><li>Causal Inference and Machine Learning: <a href="https://www.gsb.stanford.edu/faculty-research/labs-initiatives/sil/research/methods/ai-machine-learning/short-course">Susan Athey’s Lab</a> </li><li>Economics and Business Studies: <a href="https://www.nber.org/papers?page=1&amp;perPage=50&amp;sortBy=public_date">NBER Working Papers</a></li></ul><p>I am sure that there are many other great resources out there, many that can also be found on GitHub.</p><p><strong>Sam:</strong> If you’re interested to get more into how economists and other social scientists think about open source, I highly recommend the following (reasonably entry-level) articles that have helped shape my research approach.</p><ul><li>Lerner, J., &amp; Tirole, J. (2002). <a href="https://onlinelibrary.wiley.com/doi/epdf/10.1111/1467-6451.00174">Some Simple Economics of Open Source</a>. The Journal of Industrial economics, 50(2), 197-234.</li><li>Bessen, J., &amp; Maskin, E. (2009). <a href="https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1756-2171.2009.00081.x">Sequential innovation, patents, and imitation</a>. <em>The RAND Journal of Economics</em>, 40(4), 611-635.</li><li>Athey, S., &amp; Ellison, G. (2014). <a href="https://onlinelibrary.wiley.com/doi/abs/10.1111/jems.12053">Dynamics of open source movements</a>. <em>Journal of Economics &amp; Management Strategy</em>, 23(2), 294-316.</li></ul><p>For those interested in learning more about the toolkit used by empirical social scientists:</p><ul><li>Cunningham, S. (2021). <em><a href="https://doi.org/10.2307/j.ctv1c29t27">Causal Inference: The Mixtape</a></em>. Yale University Press. (<a href="https://mixtape.scunning.com/">website</a>)</li></ul><p>(<em>shameless plug</em>) We’ve been putting together a <a href="https://github.com/sboysel/awesome-oss-research-data">collection of data sources for open source researchers</a>. Contributions welcome!</p><p><strong>Kevin:</strong> Thank you, Manuel and Sam! We really appreciate you taking the time to share about what you’re working on and your journeys into researching open source.</p></body></html><p>The post <a href="https://github.blog/news-insights/policy-news-and-insights/inside-the-research-github-copilot/">Inside the research: How GitHub Copilot impacts the nature of work for open source maintainers</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Inside the research: How GitHub Copilot impacts the nature of work for open source maintainers" href="https://github.blog/news-insights/policy-news-and-insights/inside-the-research-github-copilot/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Inside the research: How GitHub Copilot impacts the nature of work for open source maintainers</span><span class="cap link fs12">https://github.blog/news-insights/policy-news-and-insights/inside-the-research-github-copilot/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>OpenAI’s Latest O1 Model Now Available in GitHub Copilot and GitHub Models</title>
    <link href="https://blog.imc.re/RSSBOX/rss/9bb226be.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/9bb226be.html</id>
    <published>2024-12-20T09:23:42.000Z</published>
    <updated>2024-12-20T09:23:42.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>Hey devs! We have some exciting news for ya.</p><p>So, backstory first: in case you missed it, OpenAI <a href="https://github.blog/news-insights/product-news/openai-o1-in-github-copilot/">launched</a> its o1-preview and o1-mini models back in September, optimized for advanced tasks like coding, science, and math. <a href="https://github.blog/changelog/2024-09-19-sign-up-for-openai-o1-access-on-github/">We brought them to our GitHub Copilot Chat and to GitHub Models</a> so you could start playing with them right away, and y’all seemed to love it!</p><p>Fast forward to today, and OpenAI has just shipped the release version to o1, an update to  o1-preview with <a href="https://openai.com/index/introducing-chatgpt-pro/">improved performance in complex tasks</a>, including a 44% gain in <a href="https://codeforces.com/">Codeforces</a>’ competitive coding test.</p><p>Sounds pretty good, huh? Well, exciting news: <strong>We’re bringing o1 to you in Copilot Chat across Copilot Pro, Business, and Enterprise, and including GitHub Models.</strong> It’s also available for you to start using <strong>right now!</strong></p><h2 id="how-can-i-try-o1-out-in-chat">How can I try o1 out in chat?<a aria-label="How can I try o1 out in chat?" class="heading-link pl-2 text-italic text-bold" href="#how-can-i-try-o1-out-in-chat"></a></h2><p>In <strong>Copilot Chat in Visual Studio Code and on GitHub</strong>, you can now pick “o1 (Preview)” via the model picker if you have a paid Copilot subscription (this is not available on <a href="https://github.blog/news-insights/product-news/github-copilot-in-vscode-free/">our newly announced free Copilot tier</a>).</p><p>Before, it said “o1-preview (Preview)” and now it just says “o1 (Preview)” because the GitHub model picker is in preview, but not the model itself. We have proven once again that the hardest problem in computer science is naming things, but yo dawg, we no longer have previews on previews. We are a very professional business.</p><p>Anyway.</p><p>Now you can use Copilot with o1 to explain, debug, refactor, modernize, test… all with the latest and greatest that o1 has to offer!</p><p>o1 is included in your paid subscription to GitHub Copilot, allowing up to 10 messages every 12 hours. As a heads up, if you’re a Copilot Business or Copilot Enterprise subscriber, an administrator will have to <a href="https://docs.github.com/en/enterprise-cloud@latest/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-policies-for-copilot-in-your-organization">enable access to o1 models</a> first before you can use it.</p><p>Beyond the superpowers that o1 already gives you out of the box, it also pulls context from your workspace and GitHub repositories! It’s a match made in developer heaven.</p><p><img alt="A GIF showing a developer selecting the OpenAI’s o1 model in GitHub Copilot to power Copilot Chat within the integrated development environment (IDE) VS Code." class="aligncenter size-large wp-image-81154 width-fit" data-recalc-dims="1" decoding="async" height="538" loading="lazy" src="https://github.blog/wp-content/uploads/2024/12/CleanShot-2024-12-16-at-15.33.34.gif?resize=1024%2C538" width="1024"/></p><h2 id="what-about-o1-in-github-models">What about o1 in GitHub Models?<a aria-label="What about o1 in GitHub Models?" class="heading-link pl-2 text-italic text-bold" href="#what-about-o1-in-github-models"></a></h2><p>If you haven’t played with GitHub Models yet, you’re in for a treat. It lets you start building AI apps with a playground and an API (and more). <a href="https://docs.github.com/en/github-models/prototyping-with-ai-models">Learn more about GitHub Models</a> in our documentation and start experimenting and building with a variety of AI models today on the <a href="https://github.com/marketplace/models/catalog">GitHub Marketplace</a>.</p><p><a href="https://github.com/marketplace/models/azure-openai/o1/playground">Head here to start with o1 in the playground</a>, <strong>plus</strong> you can compare it to other models from providers such as Mistral, Cohere, Microsoft, or Meta, and use the code samples you get to start building. Every model is different, and this kind of experimentation is really helpful to get the results you want!</p><p><img alt="A GIF showing a sample prompt with OpenAI’s o1 model in GitHub Models, a platform that enables developers to experiment with leading AI models, compare their performance, and build them into applications. The sample prompt asks “How do you prove the Pythagorean theorem geometrically.” The AI model then offers an answer that displays its reasoning capabilities." class="aligncenter size-large wp-image-81154 width-fit" data-recalc-dims="1" decoding="async" height="538" loading="lazy" src="https://github.blog/wp-content/uploads/2024/12/o1-github-models.gif?resize=1024%2C538" width="1024"/></p><h2 id="its-all-about-developer-choice">It’s all about developer choice!<a aria-label="It’s all about developer choice!" class="heading-link pl-2 text-italic text-bold" href="#its-all-about-developer-choice"></a></h2><p>Having choices fuels developer creativity! We don’t want you to just write better code, but for you to have the freedom to build, innovate, commit, and push in the way that works best for you.</p><p>I hope you’re as excited as I am. GitHub is doubling down on its commitment to give you the most advanced tools available with OpenAI’s new o1 model, and if you keep your eye out, there’s even better things to come. <img alt="👀" class="wp-smiley" src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f440.png" style="height: 1em; max-height: 1em;"/></p><p>So, let’s build from here—together!</p><p>The post <a href="https://github.blog/news-insights/openais-o1-model-available-in-copilot-chat-and-github-models/">OpenAI’s latest o1 model now available in GitHub Copilot and GitHub Models</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="OpenAI’s latest o1 model now available in GitHub Copilot and GitHub Models" href="https://github.blog/news-insights/openais-o1-model-available-in-copilot-chat-and-github-models/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">OpenAI’s latest o1 model now available in GitHub Copilot and GitHub Models</span><span class="cap link fs12">https://github.blog/news-insights/openais-o1-model-available-in-copilot-chat-and-github-models/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>Enhance Build Security and Reach SLSA Level 3 With GitHub Artifact Attestations</title>
    <link href="https://blog.imc.re/RSSBOX/rss/92d6d03c.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/92d6d03c.html</id>
    <published>2024-12-20T08:59:34.000Z</published>
    <updated>2024-12-20T08:59:34.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>The need for software build security is more pressing than ever. High-profile software supply chain attacks like <a href="https://www.wired.com/story/the-untold-story-of-solarwinds-the-boldest-supply-chain-hack-ever/">SolarWinds</a>, <a href="https://cyberint.com/blog/research/moveit-supply-chain-attack/">MOVEit</a>, <a href="https://www.wired.com/story/3cx-supply-chain-attack-times-two/">3CX</a>, and <a href="https://www.cpomagazine.com/cyber-security/major-semiconductor-firm-applied-materials-hit-by-supply-chain-attack-ransomware-impact-will-cost-250-million/">Applied Materials</a> have revealed just how vulnerable the software build process can be. As attackers exploit weaknesses in the build pipeline to inject their malicious components, traditional security measures—like scanning source code, securing production environments and source control allow lists—are no longer enough. To defend against these sophisticated threats, organizations must treat their build systems with the same level of care and security as their production environments.</p><p>These supply chain attacks are particularly dangerous because they can undermine trust in your business itself: if an attacker can infiltrate your build process, they can distribute compromised software to your customers, partners, and end-users. So, how can organizations secure their build processes, and ensure that what they ship is exactly what they intended to build?</p><p>The <a href="https://slsa.dev/spec/v1.0/levels">Supply-chain Levels for Software Artifacts</a> (SLSA) framework was developed to address these needs. SLSA provides a comprehensive, step-by-step methodology for building integrity and provenance guarantees into your software supply chain. This might sound complicated, but the good news is that GitHub Artifact Attestations simplify the journey to SLSA Level 3!</p><p>In this post, we’ll break down what you need to know about SLSA, how Artifact Attestations work, and how they can boost your GitHub Actions build security to the next level.</p><h2 id="securing-your-build-process-an-introduction-to-slsa">Securing your build process: An introduction to SLSA<a aria-label="Securing your build process: An introduction to SLSA" class="heading-link pl-2 text-italic text-bold" href="#securing-your-build-process-an-introduction-to-slsa"></a></h2><h3 id="what-is-build-security">What is build security?<a aria-label="What is build security?" class="heading-link pl-2 text-italic text-bold" href="#what-is-build-security"></a></h3><p>When we build software, we convert source code into deployable artifacts—whether those are binaries, container images or packaged libraries. This transformation occurs through multiple stages, such as compilation, packaging and testing, each of which could potentially introduce vulnerabilities or malicious modifications.</p><p>A properly secured build process can:</p><ul><li><strong>Help ensure the integrity of your deployed artifacts</strong> by providing a higher level of assurance that the code has not been tampered with during the build process.</li><li><strong>Provide transparency into the build process</strong>, allowing you to audit the provenance of your deployed artifacts.</li><li><strong>Maintain confidentiality</strong> by safeguarding sensitive data and secrets used in the build process.</li></ul><p>By securing the build process, organizations can ensure that the software reaching end-users is the intended and unaltered version. <strong>This makes securing the build process just as important as securing the source code and deployment environments</strong>.</p><h3 id="introducing-slsa-a-framework-for-build-security">Introducing SLSA: A framework for build security<a aria-label="Introducing SLSA: A framework for build security" class="heading-link pl-2 text-italic text-bold" href="#introducing-slsa-a-framework-for-build-security"></a></h3><p><a href="https://slsa.dev/spec/v1.0/levels">SLSA </a>is a community-driven framework governed by the <a href="https://openssf.org/">Open Source Security Foundation (OpenSSF)</a>, designed to help organizations systematically secure their software supply chains through a series of progressively stronger controls and best practices.</p><p>The framework is organized into four levels, each representing a higher degree of security maturity:</p><ul><li><strong>Level 0</strong>: No security guarantees</li><li><strong>Level 1</strong>: Provenance exists for traceability, but minimal tamper resistance</li><li><strong>Level 2</strong>: Provenance signed by a managed build platform, deterring simple tampering</li><li><strong>Level 3</strong>: Provenance from a hardened, tamper-resistant build platform, ensuring high security against compromise</li></ul><p>Provenance refers to the cryptographic record generated for each artifact, providing an unforgeable paper trail of its build history. This record allows you to trace artifacts back to their origins, allowing for verification of how, when and by whom the artifact was created.</p><h2 id="why-slsa-level-3-matters-for-build-security">Why SLSA Level 3 matters for build security<a aria-label="Why SLSA Level 3 matters for build security" class="heading-link pl-2 text-italic text-bold" href="#why-slsa-level-3-matters-for-build-security"></a></h2><p>Achieving <a href="https://slsa.dev/spec/v1.0/levels#build-l3">SLSA Level 3</a> is a critical step in building a secure and trustworthy software supply chain. This level requires organizations to implement rigorous standards for provenance and isolation, ensuring that artifacts are produced in a controlled and verifiable manner. <strong>An organization that has achieved SLSA Level 3 is capable of significantly mitigating the most common attack vectors targeting software build pipelines.</strong> Here’s a breakdown of the specific requirements for reaching SLSA Level 3:</p><ul><li><strong>Provenance generation and availability</strong>: A detailed provenance record must be generated for each build, documenting how, when and by whom each artifact was produced. This provenance must be accessible to users for verification.</li><li><strong>Managed build system</strong>: Builds must take place on ephemeral build systems—short-lived, on-demand environments that are provisioned for each build in order to isolate builds from one another, reducing the risk of cross-contamination and unauthorized access.</li><li><strong>Restricted access to signing material</strong>: User-defined build steps should not have access to sensitive signing material to authenticate provenance, keeping signing operations separate and secure.</li></ul><p><a href="https://docs.github.com/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds">GitHub Artifact Attestations</a> help simplify your journey to SLSA Level 3 by enabling secure, automated build verification within your GitHub Actions workflows. While generating build provenance records is foundational to SLSA Level 1, the key distinction at SLSA Level 3 is the separation of the signature process from the rest of your build job. At Level 3, the signing happens on dedicated infrastructure, separated from the build workflow itself.</p><h2 id="the-importance-of-verifying-signatures">The importance of verifying signatures<a aria-label="The importance of verifying signatures" class="heading-link pl-2 text-italic text-bold" href="#the-importance-of-verifying-signatures"></a></h2><p>While signing artifacts is a critical step, it becomes meaningless without verification. Simply having attestations does not provide any security advantages if they are not verified. <strong>Verification ensures that the signed artifacts are authentic and have not been tampered with</strong>.</p><p>The <a href="https://cli.github.com/">GitHub CLI</a> makes this process easy, allowing you to verify signatures at any stage of your CI/CD pipeline. For example, you can verify <a href="https://developer.hashicorp.com/terraform">Terraform</a> plans before applying them, ensure that <a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html">Ansible</a> or <a href="https://docs.saltproject.io/en/latest/topics/states/index.html">Salt</a> configurations are authentic before deployment, validate containers before they are deployed to <a href="https://kubernetes.io/">Kubernetes</a>, or use it as part of a GitOps workflow driven by tools like <a href="https://fluxcd.io/">Flux</a>.</p><p>GitHub offers several native ways to verify Artifact Attestations:</p><ul><li><strong><a href="https://cli.github.com/manual/gh_attestation_verify">GitHub CLI</a></strong>: This is the easiest way to verify signatures.</li><li><strong><a href="https://docs.github.com/actions/security-for-github-actions/using-artifact-attestations/enforcing-artifact-attestations-with-a-kubernetes-admission-controller">Kubernetes Admission Controller</a></strong>: Use GitHub’s distribution of the admission controller for automated verification in Kubernetes environments.</li><li><strong><a href="https://docs.github.com/actions/security-for-github-actions/using-artifact-attestations/verifying-attestations-offline">Offline verification</a></strong>: Download the attestations and verify them offline using the GitHub CLI for added security and flexibility in isolated environments.</li></ul><p>By verifying signatures during deployment, you can ensure that what you deploy to production is indeed what you built.</p><h2 id="achieving-slsa-level-3-compliance-with-github-artifact-attestations">Achieving SLSA Level 3 compliance with GitHub Artifact Attestations<a aria-label="Achieving SLSA Level 3 compliance with GitHub Artifact Attestations" class="heading-link pl-2 text-italic text-bold" href="#achieving-slsa-level-3-compliance-with-github-artifact-attestations"></a></h2><p>Reaching SLSA Level 3 may seem complex, but GitHub’s Artifact Attestations feature makes it remarkably straightforward. Generating build provenance puts you at <a href="https://slsa.dev/spec/v1.0/levels#build-l1">SLSA Level 1</a>, and by using GitHub Artifact Attestations on GitHub-hosted runners, you reach <a href="https://slsa.dev/spec/v1.0/levels#build-l2">SLSA Level 2</a> by default. From this point, advancing to <a href="https://slsa.dev/spec/v1.0/levels#build-l3">SLSA Level 3</a> is a straightforward journey!</p><p>The critical difference between SLSA Level 2 and Level 3 lies in using a <a href="https://docs.github.com/actions/sharing-automations/reusing-workflows">reusable workflow</a> for provenance generation. This allows you to centrally enforce build security across all projects and enables stronger verification, as you can confirm that a <strong>specific</strong> reusable workflow was used for signing. With just a few lines of YAML added to your workflow, you can gain build provenance without the burden of managing cryptographic key material or setting up additional infrastructure.</p><h3 id="build-provenance-made-simple">Build provenance made simple<a aria-label="Build provenance made simple" class="heading-link pl-2 text-italic text-bold" href="#build-provenance-made-simple"></a></h3><p>GitHub Artifact Attestations streamline the process of establishing provenance for your builds. By enabling provenance generation directly within GitHub Actions workflows, you ensure that each artifact includes a verifiable record of its build history. This level of transparency is crucial for SLSA Level 3 compliance.</p><p>Best of all, you don’t need to worry about the onerous process of handling cryptographic key material. GitHub manages all of the required infrastructure, from running a <a href="https://www.sigstore.dev/">Sigstore</a> instance to serving as a root signing certificate authority for you.</p><blockquote><p>  Check out <a href="https://github.blog/news-insights/product-news/introducing-artifact-attestations-now-in-public-beta/">our earlier blog</a> to learn more about how to set up Artifact Attestations in your workflow.</p></blockquote><h3 id="secure-signing-with-ephemeral-machines">Secure signing with ephemeral machines<a aria-label="Secure signing with ephemeral machines" class="heading-link pl-2 text-italic text-bold" href="#secure-signing-with-ephemeral-machines"></a></h3><p><a href="https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners">GitHub Actions-hosted runners</a>, executing workflows on ephemeral machines, ensure that each build process occurs in a clean and isolated environment. This model is fundamental for SLSA Level 3, which mandates secure and separate handling of key material used in signing.</p><p>When you create a <a href="https://docs.github.com/actions/sharing-automations/reusing-workflows">reusable workflow</a> for provenance generation, your organization can use it centrally across all projects. This  establishes a consistent, trusted source for provenance records. Additionally, signing occurs on dedicated hardware that is separate from the build machine, ensuring that neither the source code nor the developer triggering the build system can influence or alter the build process. With this level of separation, your workflows inherently meet SLSA Level 3 requirements.</p><p>Below is an example of a reusable workflow that can be utilized across the organization to sign artifacts:</p><pre><code>name: Sign Artifact<p>on:<br>  workflow_call:<br>    inputs:<br>      artifact-path:<br>            required: true<br>            type: string</p><p>jobs:<br>  sign-artifact:<br>    runs-on: ubuntu-latest<br>    permissions:<br>      id-token: write<br>      attestations: write<br>      contents: read</p><pre><code>steps:- name: Attest Build Provenance      uses: actions/attest-build-provenance@&amp;lt;version&amp;gt;      with:      subject-name: $&amp;#123;&amp;#123; inputs.subject-name &amp;#125;&amp;#125;      subject-digest: $&amp;#123;&amp;#123; inputs.subject-digest &amp;#125;&amp;#125;</code></pre><p></code></pre></p><p>When you want to use this reusable workflow for signing in any other workflow, you can call it as follows:</p><pre><code>name: Sign Artifact Workflow<p>on:<br>  push:<br>    branches:<br>      - main</p><p>jobs:<br>  sign:<br>    runs-on: ubuntu-latest</p><pre><code>steps:- name: Sign Artifact  uses: &amp;lt;repository&amp;gt;/.github/workflows/sign-artifact.yml@&amp;lt;version&amp;gt;  with:    subject-name: &quot;your-artifact.tar.gz&quot; # Replace with actual artifact name    subject-digest: &quot;your-artifact-digest&quot; # Replace with SHA-256 digest</code></pre><p></code></pre></p><p>This architecture of ephemeral environments and centralized provenance generation guarantees that signing operations are isolated from the build process itself, preventing unauthorized access to the signing process. By ensuring that signing occurs in a dedicated, controlled environment, the risk of compromising the signing workflow can be greatly reduced so that malicious actors can not tamper with the signing action’s code and deviate from the intended process. Additionally, provenance is generated consistently across all builds, providing a unified record of build history for the entire organization.</p><p>To verify that an artifact was signed using this reusable workflow, you can use the <a href="https://cli.github.com/">GitHub CLI</a> with the following command:</p><pre><code>gh artifact verify &lt;file-path&gt; --signer-workflow &lt;owner&gt;/&lt;repository&gt;/.github/workflows/sign-artifact.yml</code></pre><p>This verification process ensures that the artifact was built and signed using the anticipated pipeline, reinforcing the integrity of your software supply chain.</p><h2 id="a-more-secure-future">A more secure future<a aria-label="A more secure future" class="heading-link pl-2 text-italic text-bold" href="#a-more-secure-future"></a></h2><p>GitHub Artifact Attestations bring the assurance and structure of SLSA Level 3 to your builds without having to manage additional security infrastructure. By simply adding a few lines of YAML and moving the provenance generation into a reusable workflow, you’re well on your way to achieving SLSA Level 3 compliance with ease!</p><div class="post-content-cta"><p><strong>Ready to strengthen your build security and achieve SLSA Level 3?</strong></p><p>Start using GitHub Artifact Attestations today or explore our <a href="https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds">documentation</a> to learn more.</p></div></body></html><p>The post <a href="https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/">Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations" href="https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations</span><span class="cap link fs12">https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>The Role of Email Security in Reducing User Risk Amid Rising Threats</title>
    <link href="https://blog.imc.re/RSSBOX/rss/5951e5e0.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/5951e5e0.html</id>
    <published>2024-12-19T14:00:00.000Z</published>
    <updated>2024-12-19T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p>Phishing remains one of the most dangerous and persistent cyber threats for individuals and organizations. Modern attacks use a growing arsenal of deceptive techniques that bypass traditional <a href="https://www.cloudflare.com/en-gb/learning/email-security/secure-email-gateway-seg/"><u>secure email gateways (SEGs)</u></a> and email authentication measures, targeting organizations, employees, and vendors. From <a href="https://www.cloudflare.com/learning/email-security/business-email-compromise-bec/"><u>business email compromise (BEC)</u></a> to <a href="https://www.cloudflare.com/en-gb/learning/security/what-is-quishing/"><u>QR phishing</u></a> and <a href="https://www.cloudflare.com/en-gb/learning/access-management/account-takeover/"><u>account takeovers</u></a>, these threats are designed to exploit weaknesses across multiple communication channels, including email, Slack, Teams, SMS, and cloud drives.</p><p>Phishing remains the most popular attack vector for bad actors looking to gain unauthorized access or extract fraudulent payment, and it is <a href="https://blog.cloudflare.com/2023-phishing-report/"><u>estimated</u></a> that 90% of all attacks <a href="https://www.cisa.gov/shields-guidance-families"><u>start</u></a> with a <a href="https://www.cloudflare.com/learning/access-management/phishing-attack/"><u>phishing</u></a> email. However, as companies have shifted to using a multitude of apps to support communication and collaboration, attackers too have evolved their approach. Attackers now engage employees across a combination of channels in an attempt to build trust and pivot targeted users to less-secure apps and devices. Cloudflare is uniquely positioned to address this trend thanks to our integrated <a href="https://www.cloudflare.com/zero-trust/"><u>Zero Trust</u></a> services, extensive visibility from protecting <a href="https://w3techs.com/technologies/overview/proxy/all"><u>approximately 20% of all websites</u></a>, and signals derived from processing billions of email messages a year.</p><p>Cloudflare recognizes that combating phishing requires an integrated approach and a more complete view of user-based risk. That’s why we’ve designed our email security solution to protect organizations before, during, and after message delivery, while also extending protection beyond email into the broader security ecosystem. Phishing is no longer just an email problem — it’s a multi-channel, cross-application threat.</p><div><h2>Assessing holistic user risk</h2><a href="#assessing-holistic-user-risk"></a></div><p>When it comes to protecting against user-based threats, Cloudflare employs a platform approach to security. Instead of forcing customers to rely on an array of fragmented tools that create unnecessary complexity and blind spots, we treat email security as part of an overall strategy for assessing and responding to user-related risk. Our email security solution works in tandem with our network solutions so that SOC teams can quickly assert what actions their users are performing outside of email. Given our extensive network visibility, our platform is not limited by API integrations, and can provide SOC teams with the best visibility and protection. This helps SOC teams not only combat phishing, but begin to identify and take action against a wider range of insider threats.</p><p>Within a single, unified dashboard, SOC teams can quickly review detailed information regarding the following questions, which we discuss in more detail below: </p><ol><li><p>Who in the organization is being targeted?</p></li><li><p>Who are the attackers impersonating?</p></li><li><p>What risky behaviors are my users performing?</p></li></ol><div><h3>Who in the organization is being targeted?</h3><a href="#who-in-the-organization-is-being-targeted"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7hCZ0UXnPA7Wx5iBHxkfjE/47a143332f6c22c7e11b568b43dfdd74/BLOG-2645_2.png"/></figure><p>Within the Cloudflare dashboard, SOC teams can view which users are the most targeted. This can help them determine which accounts should be hardened (e.g. MFA enforced), and identify risky users that should be monitored more closely for significant deviations in behavior. One way organizations can use this information is to require high-risk users to connect from a managed device. For instance, if they use Crowdstrike, <a href="https://developers.cloudflare.com/cloudflare-one/identity/devices/service-providers/crowdstrike/"><u>we can require that these users be on a managed device</u></a> and force a posture check before letting them access sensitive applications. </p><p>SOC teams can also dive into what types of attacks are hitting their users and at what frequency.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2nVgW0EXy3qzC2hDBeJRAx/5cf8408ec72339fe8985019629912cbb/BLOG-2645_3.png"/></figure><p>Customers can use these insights to adjust various platform policies, effectively blocking malicious content and securing sensitive resources. Above, we can see that attackers are frequently leveraging links to try to compromise users. Based on the link analysis we are seeing in email, SOC teams can use our gateway to block similar attacks, so that when attackers try to use other communication methods (LinkedIn, Teams, Slack, etc.) users will not be able to interact with those links.</p><p>To learn more about stopping these types of multichannel phishing attacks, please see our blog post, <a href="https://blog.cloudflare.com/a-wild-week-in-phishing-and-what-it-means-for-you/"><i><u>A wild week in phishing, and what it means for you</u></i></a><i>.</i></p><div><h3>Who are the attackers impersonating?</h3><a href="#who-are-the-attackers-impersonating"></a></div><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/16lvS6lNsi4TuSgtMFqBtk/b093ecb444def1bd06fb84566b5eb05a/BLOG-2645_4.png"/></figure><p>SOC teams can also get visibility into impersonation attempts within their email environment. Customers can see which users are being impersonated the most, and can use this information to build policies within our email security solution and broader set of Zero Trust services.</p><p>A list of frequently impersonated users can be added to the <a href="https://developers.cloudflare.com/cloudflare-one/email-security/detection-settings/impersonation-registry/"><u>impersonation registry</u></a>, which changes the sensitivity of our models to apply more scrutiny on messages coming from those users. </p><p>Given our unique position as a <a href="https://www.cloudflare.com/en-gb/products/registrar/"><u>domain name registrar</u></a>, customers can also report lookalike domains to Cloudflare for action to be taken against them. This helps prevent attackers from being able to impersonate our customers and negatively impact their reputation. </p><p>Finally, customers can also use our free <a href="https://developers.cloudflare.com/dmarc-management/"><u>DMARC management</u></a> to track who is sending emails on their behalf. This information can be used to update <a href="https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-spf-record/"><u>SPF records</u></a> and get customers to <code>p=quarantine</code> or <code>p=reject</code> so that their brand is more resistant to being spoofed. </p><div><h3>What risky behaviors are my users performing?</h3><a href="#what-risky-behaviors-are-my-users-performing"></a></div><p>Cloudflare provides visibility into user actions in several ways. </p><p>Within the email security solution, we can track internal messages and alert if we see any malicious or suspicious behaviors. This can be enhanced with our managed service offering, <a href="https://developers.cloudflare.com/cloudflare-one/email-security/phish-guard/"><u>Phishguard</u></a>, which can alert admins when they see any type of behavior that indicates fraud (like Business Email Compromise), account takeover, or insider threats.</p><p>SOC teams can also take advantage of our <a href="https://www.cloudflare.com/en-gb/zero-trust/products/casb/"><u>CASB solution</u></a> to view the different actions that users have performed. Actions are labeled with different risk levels to let teams know which findings are critical and require remediation. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7aiDl5Qo2PGsGYF7NfYcDT/dc49eb88beffc7b9df099d71244489c9/BLOG-2645_5.png"/></figure><p>Customers are also able to view data loss prevention (<a href="https://www.cloudflare.com/en-gb/zero-trust/products/dlp/"><u>DLP</u></a>) violations that users have incurred to see if there is any unauthorized egress of data. We provide the ability to automatically block this egress based on different policies within our platform, making sure there is no exfiltration of sensitive data.</p><p>We also enable organizations to put internal applications behind our <a href="https://www.cloudflare.com/en-gb/zero-trust/products/access/"><u>Access</u></a> solution. This prevents any users with improper permissions or a high risk level from accessing critical applications. Our dashboard then provides metrics on these logins to see how many failures we observed, so that SOC teams can investigate the user further. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/34LnlEK1lkpbeW5mYLSl8m/5d51092b134bfd7e2d6093a04fcfdc60/BLOG-2645_6.png"/></figure><p>These signals feed into our <a href="https://blog.cloudflare.com/unified-risk-posture/"><u>Unified Risk Score</u></a>, which can be exported if needed to take automated actions within other platforms.</p><div><h2>Increasing SOC productivity</h2><a href="#increasing-soc-productivity"></a></div><p>With all of our functionality unified within a single interface and fed by one data lake, we see an increase in SOC productivity because teams no longer have to spend time building rules or flipping between disparate interfaces and workflows. </p><div><h3>AI-driven email security</h3><a href="#ai-driven-email-security"></a></div><p>Unlike legacy secure email gateways, our email security solution is driven by predictive AI models which eliminate the need for creating and updating rules. These models are also more effective than reactive measures because they are fed by a massive volume of diverse data from across Cloudflare’s network. This means models are trained on emerging threats earlier and can identify new tactics with a higher accuracy than legacy systems. </p><div><h3>Automated isolation</h3><a href="#automated-isolation"></a></div><p>To further reduce the risk posed by users visiting potentially malicious websites, customers can isolate browser sessions using our natively integrated, clientless remote browser that runs on our <a href="https://www.cloudflare.com/network"><u>global network</u></a>. Within an isolated browsing session, SOC teams can prohibit various behaviors such as copy/paste, upload/download, keyboard inputs, and more. This decreases the risk of users accessing a website and performing an action which could compromise the organization.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/65YXZvV78mjzNXvV4YLJRD/b0ef76d80edd7769a23d877ffdc25696/BLOG-2645_7.png"/></figure><p>Our browser isolation solution also decreases the time SOC teams need to maintain policies. Rather than adding domains and applications one by one, teams can choose to isolate based on content categories. These categories are based on our threat intelligence, and are constantly updated. This means that as new websites emerge, SOC teams do not have to spend the time to chase down and update the proper policy — rather, it is done automatically. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2aCMZRmIRp33YbGTU5Vxt6/44ca92e4e3cde07b1424b9875311dd59/BLOG-2645_8.png"/></figure><div><h3>Automated blocking</h3><a href="#automated-blocking"></a></div><p>While some websites might require running in an isolated browser to mitigate the risk of users encountering malicious content, others may need to be fully blocked altogether. Customers can use the same process listed above to block any website that could be risky for users based on tags. However, we allow admins to also provide feedback to users to increase awareness. This can be done via a <a href="https://developers.cloudflare.com/cloudflare-one/policies/gateway/block-page/"><u>custom block page</u></a> that allows SOC teams to communicate with users about their risky behaviors, so that they take actions to curb this behavior in the future and alert their SOC teams to attacks that might be occurring. </p><div><h2>What's on the horizon for 2025</h2><a href="#whats-on-the-horizon-for-2025"></a></div><p>In 2024, our email security team focused on refining the user interface and improving the incident investigation experience. Looking ahead to 2025, we plan to introduce additional capabilities that deepen the integration of our email security solution with our SASE platform, delivering enhanced insight and protection against user-based threats. </p><div><h3>Configurable browser isolation for email</h3><a href="#configurable-browser-isolation-for-email"></a></div><p>Our Email Link Isolation feature currently applies to links we consider suspicious. However, we intend to allow customers to add customized configurations to meet their internal policies. This enhancement will provide more granular control over which websites users can access from an email message without using an isolated browser. </p><div><h3>Outbound DLP for email</h3><a href="#outbound-dlp-for-email"></a></div><p>We will be releasing an add-in for Microsoft Outlook that will allow customers to use our DLP engine for inspecting outbound email messages. This client-side application enables customers to configure downstream policies that trigger action when a DLP policy is violated, all while minimizing disruption to existing email infrastructure. </p><div><h3>Expanded user risk scoring</h3><a href="#expanded-user-risk-scoring"></a></div><p>Cloudflare will be increasing the signals that feed into our user risk scores. This will enable SOC teams to create more policies within Cloudflare or to take automated actions externally based on the level of risk observed. </p><p>These are just a few examples of significant releases that will be coming in 2025. Please stay tuned to the Cloudflare blog where we will be announcing these releases as they happen. </p><div><h2>Try Cloudflare Email Security today</h2><a href="#try-cloudflare-email-security-today"></a></div><p>We provide all organizations (whether a Cloudflare customer or not) with free access to our <a href="https://blog.cloudflare.com/threats-lurking-office-365-cloudflare-email-retro-scan/"><u>Retro Scan</u></a> tool, allowing them to use our predictive AI models to scan existing inbox messages. Retro Scan will detect and highlight any threats found, enabling organizations to remediate them directly in their email accounts. With these insights, organizations can implement further controls, either using Cloudflare Email Security or their preferred solution, to prevent similar threats from reaching their inboxes in the future.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="The role of email security in reducing user risk amid rising threats" href="https://blog.cloudflare.com/the-role-of-email-security-in-reducing-user-risk-amid-rising-threats/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">The role of email security in reducing user risk amid rising threats</span><span class="cap link fs12">https://blog.cloudflare.com/the-role-of-email-security-in-reducing-user-risk-amid-rising-threats/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Introducing Annotated Logger: A Python Package to Aid in Adding Metadata to Logs</title>
    <link href="https://blog.imc.re/RSSBOX/rss/68d82f32.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/68d82f32.html</id>
    <published>2024-12-18T13:31:44.000Z</published>
    <updated>2024-12-18T13:31:44.000Z</updated>
    
    <content type="html"><![CDATA[<div><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><h2 id="what-it-is">What it is<a aria-label="What it is" class="heading-link pl-2 text-italic text-bold" href="#what-it-is"></a></h2><p><a href="https://github.com/github/annotated-logger">Annotated Logger</a> is a Python package that allows you to decorate functions and classes, which then log when complete and can request a customized logger object, which has additional fields pre-added. GitHub’s Vulnerability Management team created this tool to make it easier to find and filter logs in Splunk.</p><h2 id="why-we-made-it">Why we made it<a aria-label="Why we made it" class="heading-link pl-2 text-italic text-bold" href="#why-we-made-it"></a></h2><p>We have several Python projects that have grown in complexity over the years and have used Splunk to ingest and search those logs. We have always sent our logs in via JSON, which makes it easy to add in extra fields. However, there were a number of fields, like what Git branch was deployed, that we also wanted to send, plus, there were fields, like the CVE name of the vulnerability being processed, that we wanted to add for messages in a given function. Both are possible with the base Python logger, but it’s a lot of manual work repeating the same thing over and over, or building and managing a dictionary of extra fields that are included in every log message.</p><p>The Annotated Logger started out as a simple decorator in one of our repositories, but was extracted into a package in its own right as we started to use it in all of our projects. As we’ve continued to use it, its features have grown and been updated.</p><h2 id="how-and-why-to-use-it">How and why to use it<a aria-label="How and why to use it" class="heading-link pl-2 text-italic text-bold" href="#how-and-why-to-use-it"></a></h2><p>Now that I’ve gotten a bit of the backstory out of the way, here’s what it does, why you should use it, and how to configure it for your specific needs. At its simplest, you decorate a function with <code>@annotate_logs()</code> and it will “just work.” If you’d like to dive right in and poke around, the <a href="https://github.com/github/annotated-logger/tree/main/example">example folder</a> contains examples that fully exercise the features.</p><pre><code class="language-python">@annotate_logs()def foo():    return True</code></pre><pre><code>&gt;&gt;&gt; foo()&#123;"created": 1733176439.5067494, "levelname": "DEBUG", "name": "annotated_logger.8fcd85f5-d47f-4925-8d3f-935d45ceeefc", "message": "start", "action": "__main__:foo", "annotated": true&#125;&#123;"created": 1733176439.506998, "levelname": "INFO", "name": "annotated_logger.8fcd85f5-d47f-4925-8d3f-935d45ceeefc", "message": "success", "action": "__main__:foo", "success": true, "run_time": "0.0", "annotated": true&#125;True</code></pre><p>Here is a more complete example that makes use of a number of the features. Make sure to install the package: <code>pip install annotated-logger</code> first.</p><pre><code class="language-python">import osfrom annotated_logger import AnnotatedLoggeral = AnnotatedLogger(    name="annotated_logger.example",    annotations=&#123;"branch": os.environ.get("BRANCH", "unknown-branch")&#125;)annotate_logs = al.annotate_logs<p>@annotate_logs()<br>def split_username(annotated_logger, username):<br>    annotated_logger.annotate(username&#x3D;username)<br>    annotated_logger.info(“This is a very important message!”, extra&#x3D;&amp;#123;”important”: True&amp;#125;)<br>    return list(username)<br></code></pre></p><pre><code>&gt;&gt;&gt; split_username("crimsonknave")&#123;"created": 1733349907.7293086, "levelname": "DEBUG", "name": "annotated_logger.example.c499f318-e54b-4f54-9030-a83607fa8519", "message": "start", "action": "__main__:split_username", "branch": "unknown-branch", "annotated": true&#125;&#123;"created": 1733349907.7296104, "levelname": "INFO", "name": "annotated_logger.example.c499f318-e54b-4f54-9030-a83607fa8519", "message": "This is a very important message!", "important": true, "action": "__main__:split_username", "branch": "unknown-branch", "username": "crimsonknave", "annotated": true&#125;&#123;"created": 1733349907.729843, "levelname": "INFO", "name": "annotated_logger.example.c499f318-e54b-4f54-9030-a83607fa8519", "message": "success", "action": "__main__:split_username", "branch": "unknown-branch", "username": "crimsonknave", "success": true, "run_time": "0.0", "count": 12, "annotated": true&#125;['c', 'r', 'i', 'm', 's', 'o', 'n', 'k', 'n', 'a', 'v', 'e']&gt;&gt;&gt;&gt;&gt;&gt; split_username(1)&#123;"created": 1733349913.719831, "levelname": "DEBUG", "name": "annotated_logger.example.1c354f32-dc76-4a6a-8082-751106213cbd", "message": "start", "action": "__main__:split_username", "branch": "unknown-branch", "annotated": true&#125;&#123;"created": 1733349913.719936, "levelname": "INFO", "name": "annotated_logger.example.1c354f32-dc76-4a6a-8082-751106213cbd", "message": "This is a very important message!", "important": true, "action": "__main__:split_username", "branch": "unknown-branch", "username": 1, "annotated": true&#125;&#123;"created": 1733349913.7200255, "levelname": "ERROR", "name": "annotated_logger.example.1c354f32-dc76-4a6a-8082-751106213cbd", "message": "Uncaught Exception in logged function", "exc_info": "Traceback (most recent call last):\n  File \"/home/crimsonknave/code/annotated-logger/annotated_logger/__init__.py\", line 758, in wrap_function\n  result = wrapped(*new_args, **new_kwargs)  # pyright: ignore[reportCallIssue]\n  File \"&lt;stdin&gt;\", line 5, in split_username\nTypeError: 'int' object is not iterable", "action": "__main__:split_username", "branch": "unknown-branch", "username": 1, "success": false, "exception_title": "'int' object is not iterable", "annotated": true&#125;Traceback (most recent call last):  File "&lt;stdin&gt;", line 1, in &lt;module&gt;  File "&lt;makefun-gen-0&gt;", line 2, in split_username  File "/home/crimsonknave/code/annotated-logger/annotated_logger/__init__.py", line 758, in wrap_function    result = wrapped(*new_args, **new_kwargs)  # pyright: ignore[reportCallIssue]  File "&lt;stdin&gt;", line 5, in split_usernameTypeError: 'int' object is not iterable</code></pre><p>There are a few things going on in this example. Let’s break it down piece by piece.</p><ul><li>The Annotated Logger requires a small amount of setup to use; specifically, you need to instantiate an instance of the <code>AnnotatedLogger</code> class. This class contains all of the configuration for the loggers.<ul><li>Here we set the name of the logger. (You will need to update the logging config if your name does not start with <code>annotated_logger</code> or there will be nothing configured to log your messages.)</li><li>We also set a <code>branch</code> annotation that will be sent with all log messages.</li></ul></li><li>After that, we create an alias for the decorator. You don’t have to do this, but I find it’s easier to read than <code>@al.annotate_logs()</code>.</li><li>Now, we decorate and define our method, but this time we’re going to ask the decorator to provide us with a logger object, <code>annotated_logger</code>. This <code>annotated_logger</code> variable can be used just like a standard <code>logger</code> object but has some extra features.<ul><li>This <code>annotated_logger</code> argument is added by the decorator before calling the decorated method.</li><li>The signature of the decorated method is adjusted so that it does not have an <code>annotated_logger</code> parameter (see how it’s called with just name).</li><li>There are optional parameters to the decorator that allow type hints to correctly parse the modified signature.</li></ul></li><li>We make use of one of those features right away by calling the <code>annotate method</code>, which will add whatever kwargs we pass to the <code>extra</code> field of all log messages that use the logger.<ul><li>Any field added as an annotation will be included in each subsequent log message that uses that logger.</li><li>You can override an annotation by annotating again with the same name</li></ul></li><li>At last, we send a log message! In this message we also pass in a field that’s only for that log message, in the same way you would when using <code>logger</code>.</li><li>In the second call, we passed an <code>int</code> to the name field and <code>list</code> threw an exception.<ul><li>This exception is logged automatically and then re-raised.</li><li>This makes it much easier to know if/when a method ended (unless the process was killed).</li></ul></li></ul><p>Let’s break down each of the fields in the log message:</p><div class="content-table-wrap"><table><thead><tr><th>Field</th><th>Source</th><th>Description</th></tr></thead><tr><td>created</td><td><code>logging</code></td><td>Standard <code>Logging</code> field.</td></tr><tr><td>levelname</td><td><code>logging</code></td><td>Standard <code>Logging</code> field.</td></tr><td>name</td><td><code>annotated_logger</code></td><td>Logger name (set via class instantiation).</td><tr><td>message</td><td><code>logging</code></td><td>Standard <code>Logging</code> field for log content.</td></tr><tr><td>action</td><td><code>annotated_logger</code></td><td>Method name the logger was created for.</td></tr><tr><td>branch</td><td><code>AnnotatedLogger()</code></td><td>Set from the configuration’s <code>branch</code> annotation.</td></tr><tr><td>annotated</td><td><code>annotated_logger</code></td><td>Boolean indicating if the message was sent via Annotated Logger.</td></tr><tr><td>important</td><td><code>annotated_logger.info</code></td><td>Annotation set for a specific log message.</td></tr><tr><td>username</td><td><code>annotated_logger.annotate</code></td><td>Annotation set by user.</td></tr><tr><td>success</td><td><code>annotated_logger</code></td><td>Indicates if the method completed successfully (True/False).</td></tr><tr><td>run_time</td><td><code>annotated_logger</code></td><td>Duration of the method execution.</td></tr><tr><td>count</td><td><code>annotated_logger</code></td><td>Length of the return value (if applicable).</td></tr></table></div><p>The <code>success</code>, <code>run_time</code> and <code>count</code> fields are added automatically to the message (“success”) that is logged after a decorated method is completed without an exception being raised.</p><h2 id="under-the-covers">Under the covers<a aria-label="Under the covers" class="heading-link pl-2 text-italic text-bold" href="#under-the-covers"></a></h2><h3 id="how-its-implemented">How it’s implemented<a aria-label="How it’s implemented" class="heading-link pl-2 text-italic text-bold" href="#how-its-implemented"></a></h3><p>The Annotated Logger interacts with <code>Logging</code> via two main classes: <code>AnnotatedAdapter</code> and <code>AnnotatedFilter</code>. <code>AnnotatedAdapter</code> is a subclass of <code>logging.LoggerAdapter</code> and is what all <code>annotated_logger</code> arguments are instances of. <code>AnnotatedFilter</code> is a subclass of <code>logging.Filter</code> and is where the annotations are actually injected into the log messages. As a user outside of config and plugins, the only part of the code you will only interact with are <code>AnnotatedAdapter</code> in methods and the decorator itself. Each instance of the <code>AnnotatedAdapter</code> class has an <code>AnnotatedFilter</code> instance—the <code>AnnotatedAdapter.annotate</code> method passes those annotations on to the filter where they are stored. When a message is logged, that filter will calculate all the annotations it should have and then update the existing <code>LogRecord</code> object with those annotations.</p><p>Because each invocation of a method gets its own <code>AnnotatedAdapter</code> object it also has its own <code>AnnotatedFilter</code> object. This ensures that there is no leaking of annotations from one method call to another.</p><h3 id="type-hinting">Type hinting<a aria-label="Type hinting" class="heading-link pl-2 text-italic text-bold" href="#type-hinting"></a></h3><p>The Annotated Logger is fully type hinted internally and fully supports type hinting of decorated methods. But a little bit of additional detail is required in the decorator invocation. The <code>annotate_logs</code> method takes a number of optional arguments. For type hinting, <code>_typing_self</code>, <code>_typing_requested</code>, <code>_typing_class</code> and <code>provided</code> are relevant. The three arguments that start with <code>_typing</code> have no impact on the behavior of the decorator and are only used in method signature overrides for type hinting. Setting <code>provided</code> to <code>True</code> tells the decorator that the <code>annotated_logger</code> should not be created and will be provided by the caller (thus the signature shouldn’t be altered).</p><p><code>_typing_self</code> defaults to <code>True</code> as that is how most of my code is written. <code>provided</code>, <code>_typing_class</code> and <code>_typing_requested</code> default to <code>False</code>.</p><pre><code class="language-python">class Example:    @annotate_logs(_typing_requested=True)    def foo(self, annotated_logger):        ...<p>e &#x3D; Example()<br>e.foo()<br></code></pre></p><h3 id="plugins">Plugins<a aria-label="Plugins" class="heading-link pl-2 text-italic text-bold" href="#plugins"></a></h3><p>There are a number of plugins that come packaged with the Annotated Logger. Plugins allow for the user to hook into two places: when an exception is caught by the decorator and when logging a message. You can create your own plugin by creating a class that defines the <code>filter</code> and <code>uncaught_exception</code> methods (or inherits from <code>annotated_logger.plugins.BasePlugin</code> which provides noop methods for both).</p><p>The <code>filter</code> method of a plugin is called when a message is being logged. Plugins are called in the order they are set in the config. They are called by the AnnotatedFilter object of the AnnotatedAdapter and work like any <code>logging.Filter</code>. They take a record argument which is a <code>logging.LogRecord</code> object. They can manipulate that record in any way they want and those modifications will persist. Additionally, just like any logging filter, they can stop a message from being logged by returning <code>False</code>.</p><p>The <code>uncaught_exception</code> method of a plugin is called when the decorator catches an exception in the decorated method. It takes two arguments, <code>exception</code> and <code>logger</code>. The <code>logger</code> argument is the <code>annotated_logger</code> for the decorated method. This allows the plugin to annotate the log message stating that there was an uncaught exception that is about to be logged once the plugins have all processed their <code>uncaught_exception</code> methods.</p><p>Here is an example of a simple plugin. The plugin inherits from the <code>BasePlugin</code>, which isn’t strictly needed here since it implements both <code>filter</code> and <code>uncaught_exception</code>, but if it didn’t, inheriting from the BasePlugin means that it would fall back to the default noop methods. The plugin has an init so that it can take and store arguments. The <code>filter</code> and <code>uncaught_exception</code> methods will end up with the same result: <code>flagged=True</code> being set if a word matches. But they do it slightly differently, <code>filter</code> is called while a given log message is being processed and so the annotation it adds is directly to that record. While <code>uncaught_exception</code> is called if an exception is raised and not caught during the execution of the decorated method, so it doesn’t have a specific log record to interact with and set an annotation on the logger. The only difference in outcome would be if another plugin emitted a log message during its <code>uncaught_exception</code> method after <code>FlagWordPlugin</code>, in that case, the additional log message would also have <code>flagged=True</code> on it.</p><pre><code class="language-python">from annotated_logger.plugins import BasePlugin<p>class FlagWordPlugin(BasePlugin):<br>    “””Plugin that flags any log message&#x2F;exception that contains a word in a list.”””<br>    def <strong>init</strong>(self, *wordlist):<br>        “””Save the wordlist.”””<br>        self.wordlist &#x3D; wordlist</p><pre><code>def filter(self, record):&quot;&quot;&quot;Add annotation if the message contains words in the wordlist.&quot;&quot;&quot;for word in self.wordlist:    if word in record.msg:        record.flagged = Truedef uncaught_exception(self, exception, logger):&quot;&quot;&quot;Add annotation if exception title contains words in the wordlist.&quot;&quot;&quot;for word in self.wordlist:    if word in str(exception)        logger.annotate(flagged=True)</code></pre><p>AnnotatedLogger(plugins&#x3D;[FlagWordPlugin(“danger”, “Will Robinson”)])<br></code></pre></p><p>Plugins are stored in a list and the order they are added can matter. The <code>BasePlugin</code> is always the first plugin in the list; any that are set in configuration are added after it.</p><p>When a log message is being sent the <code>filter</code> methods of each plugin will be called in the order they appear in the list. Because the <code>filter</code> methods often modify the record directly, one filter can break another if, for example, one filter removed or renamed a field that another filter used. Conversely, one filter could expect another to have added or altered a field before its run and would fail if it was ahead of the other filter. Finally, just like in the <code>logging</code> module, the <code>filter</code> method can stop a log from being emitted by returning False. As soon as a filter does so the processing ends and any Plugins later in the list will not have their <code>filter</code> methods called.</p><p>If the decorated method raises an exception that is not caught, then the plugins will again execute in order. The most common interaction is plugins attempting to set/modify the same annotation. The <code>BasePlugin</code> and <code>RequestsPlugin</code> both set the <code>exception_title</code> annotation. Since the <code>BasePlugin</code> is always first, the title it sets will be overridden. Other interactions would be one plugin setting an annotation before or after another plugin that emits a log message or sends data to a third-party. In both of those cases the order will impact if the annotation is present or not.</p><p>Plugins that come with the Annotated Logger:</p><ul><li><code>GitHubActionsPlugin</code>—Set a level of log messages to also be emitted in actions notation (<code>notice::</code>).</li><li><code>NameAdjusterPlugin</code>—Add a pre/postfix to a name to avoid collisions in any log processing software (<code>source</code> is a field in Splunk, but we often include it as a field and it’s just hidden).</li><li><code>RemoverPlugin</code>—Remove a field. Exclude <code>password</code>/<code>key</code> fields and set an object’s attributes to the log if you want or ignore fields like <code>taskName</code> that are set when running async, but not sync.</li><li><code>NestedRemoverPlugin</code>—Remove a field no matter how deep in a dictionary it is.</li><li><code>RenamerPlugin</code>—Rename one field to another (don’t like <code>levelname</code> and want <code>level</code>, this is how you do that).</li><li><code>RequestsPlugin</code>—Adds a title and status code to the annotations if the exception inherits from <code>requests.exceptions.HTTPError</code>.</li><li><code>RuntimeAnnotationsPlugin</code>—Sets dynamic annotations.</li></ul><h3 id="dictconfig">dictconfig<a aria-label="dictconfig" class="heading-link pl-2 text-italic text-bold" href="#dictconfig"></a></h3><p>When adding the Annotated Logger to an existing project, or one that uses other packages that log messages (flask, django, and so on), you can configure all of the Annotated Logger via <a href="https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig"><code>dictConfig</code></a> by supplying a <code>dictConfig</code> compliant dictionary as the <code>config</code> argument when initializing the Annotated Logger class. If, instead, you wish to do this yourself you can pass <code>config=False</code> and reference <code>annotated_logger.DEFAULT_LOGGING_CONFIG</code> to obtain the config that is used when none is provided and alter/extract as needed.</p><p>There is one special case where the Annotated Logger will modify the config passed to it: if there is a filter named <code>annotated_filter</code> that entry will be replaced with a reference to a filter that is created by the instance of the Annotated Logger that’s being created. This allows any annotations or other options set to be applied to messages that use that filter. You can instead create a filter that uses the AnnotatedFilter class, but it won’t have any of the config the rest of your logs have.</p><h4 id="notes">Notes<a aria-label="Notes" class="heading-link pl-2 text-italic text-bold" href="#notes"></a></h4><p><code>dictConfig</code> partly works when merging dictionaries. I have found that some parts of the config are not overwritten, but other parts seem to lose their references. So, I would encourage you to build up a logging config for everything and call it once only. If you pass <code>config</code>, the Annotated Logger will call <code>logging.config.dictConfig</code> on your config after it has the option to add/adjust the config.</p><p>The <a href="https://github.com/github/annotated-logger/blob/main/example/logging_config.py"><code>logging_config.py</code></a> example has a much more detailed breakdown and set of examples.</p><h3 id="pytest-mock">Pytest mock<a aria-label="Pytest mock" class="heading-link pl-2 text-italic text-bold" href="#pytest-mock"></a></h3><p>Included with the package is a pytest mock to assist in testing for logged messages. I know that there are some strong opinions about testing log messages, and I don’t suggest doing it extensively, or frequently, but sometimes it’s the easiest way to check a loop, or the log message is tied to an alert, and it is important how it’s formatted. In these cases, you can ask for the <code>annotated_logger_mock</code> fixture which will intercept, record and forward all log messages.</p><pre><code class="language-python">def test_logs(annotated_logger_mock):    with pytest.raises(KeyError):        complicated_method()    annotated_logger_mock.assert_logged(        "ERROR",  # Log level        "That's not the right key",  # Log message        present=&#123;"success": False, "key": "bad-key"&#125;,  # annotations and their values that are required        absent=["fake-annotations"],  # annotations that are forbidden        count=1  # Number of times log messages should match    )</code></pre><p>The <code>assert_logged</code> method makes use of <a href="https://pypi.org/project/pychoir/">pychoir</a> for flexible matching. None of the parameters are required, so feel free to use whichever makes sense. Below is a breakdown of the default and valid values for each parameter.</p><div class="content-table-wrap"><table><thead><tr><th>Parameter</th><th>Default Value</th><th>Valid Values</th><th>Description</th></tr></thead><tr><td>level</td><td>Matches anything</td><td>String or string-based matcher</td><td>Log level to check (e.g., “ERROR”).</td></tr><tr><td>message</td><td>Matches anything</td><td>String or string-based matcher</td><td>Log message to check.</td></tr><tr><td>present</td><td>Empty dictionary</td><td>Dictionary with string keys and any value</td><td>Annotations required in the log.</td></tr><tr><td>absent</td><td>Empty set</td><td>`ALL`, set, or list of strings</td><td>Annotations that must not be present in the log.</td></tr><tr><td>count</td><td>All positive integers</td><td>Integer or integer-based matcher</td><td>Number of times the log message should match.</td></tr></table></div><p>The <code>present</code> key is often what makes the mock truly useful. It allows you to require the things you care about and ignore the things you don’t care about. For example, nobody wants their tests to fail because the <code>run_time</code> of a method went from <code>0.0</code> to <code>0.1</code> or fail because the hostname is different on different test machines. But both of those are useful things to have in the logs. This mock should replace everything you use the <code>caplog</code> fixture for and more.</p><h2 id="other-features">Other features<a aria-label="Other features" class="heading-link pl-2 text-italic text-bold" href="#other-features"></a></h2><h3 id="class-decorators-and-persist">Class decorators and persist<a aria-label="Class decorators and persist" class="heading-link pl-2 text-italic text-bold" href="#class-decorators-and-persist"></a></h3><p>Classes can be decorated with <code>@annotate_logs</code> as well. These classes will have an <code>annotated_logger</code> attribute added after the init (I was unable to get it to work inside the <code>__init__</code>). Any decorated methods of that class will have an <code>annotated_logger</code> that’s based on the class logger. Calls to <code>annotate</code> that pass <code>persist=True</code> will set the annotations on the class Annotated Logger and so subsequent calls of any decorated method of that instance will have those annotations. The class instance’s <code>annotated_logger</code> will also have an annotation of <code>class</code> specifying which class the logs are coming from.</p><h3 id="iterators">Iterators<a aria-label="Iterators" class="heading-link pl-2 text-italic text-bold" href="#iterators"></a></h3><p>The Annotated Logger also supports logging iterations of an <code>enumerable</code> object. <code>annotated_logger.iterator</code> will log the start, each step of the iteration, and when the iteration is complete. This can be useful for pagination in an API if your results object is enumerable, logging each time a page is fetched instead of sitting for a long time with no indication if the pages are hanging or there are simply many pages.</p><p>By default the <code>iterator</code> method will log the value of each iteration, but this can be disabled by setting <code>value=False</code>. You can also specify the level to log the iterations at if you don’t want the default of <code>info</code>.</p><h3 id="provided">Provided<a aria-label="Provided" class="heading-link pl-2 text-italic text-bold" href="#provided"></a></h3><p>Because each decorated method gets its own <code>annotated_logger</code> calls to other methods will not have any annotations from the caller. Instead of simply passing the <code>annotated_logger</code> object to the method being called, you can specify <code>provided=True</code> in the decorator invocation. This does two things: first, it means that this method won’t have an <code>annotated_logger</code> created and passed automatically, instead it requires that the first argument be an existing <code>annotated_logger</code>, which it will use as a basis for the <code>annotated_logger</code> object it creates for the function. Second, it adds the annotation of <code>subaction</code> and sets the decorated function’s name as its value, the <code>action</code> annotation is preserved as from the method that called and provided the <code>annotated_logger</code>. Annotations are not persisted from a method decorated with <code>provided=True</code> to the method that called it, unless the class of the calling method was decorated and the called action annotated with <code>persist=True</code>, in which case the annotation is set on the <code>annotated_logger</code> of the instance and shared with all methods as is normal for decorated classes.</p><p>The most common use of this is with private methods, especially ones created during a refactor to extract some self contained logic. But other uses are for common methods that are called from a number of different places.</p><h3 id="split-messages">Split messages<a aria-label="Split messages" class="heading-link pl-2 text-italic text-bold" href="#split-messages"></a></h3><p>Long messages wreak havoc on log parsing tools. I’ve encountered cases where the HTML of a 500 error page was too long for Splunk to parse, causing the entire log entry to be discarded and its annotations to go unprocessed. Setting <code>max_length</code> when configuring the Annotated Logger will break long messages into multiple log messages each annotated with <code>split=True</code>, <code>split_complete=False</code>, <code>message_parts=#</code> and <code>message_part=#</code>. The last part of the long message will have <code>split_complete=True</code> when it is logged.</p><p>Only messages can be split like this; annotations will not trigger the splitting. However, a plugin could truncate any values with a length over a certain size.</p><h3 id="pre-post-hooks">Pre/Post hooks<a aria-label="Pre/Post hooks" class="heading-link pl-2 text-italic text-bold" href="#pre-post-hooks"></a></h3><p>You can register hooks that are executed before and after the decorated method is called. The <code>pre_call</code> and <code>post_call</code> parameters of the decorator take a reference to a function and will call that function right before passing in the same arguments that the function will be/was called with. This allows the hooks to add annotations and/or log anything that is desired (assuming the decorated function requested an <code>annotated_logger</code>).</p><p>Examples of this would be having a set of annotations that annotate fields on a model and a <code>pre_call</code> that sets them in a standard way. Or a <code>post_call</code> that logs if the function left a model in an unsaved state.</p><h3 id="runtime-annotations">Runtime annotations<a aria-label="Runtime annotations" class="heading-link pl-2 text-italic text-bold" href="#runtime-annotations"></a></h3><p>Most annotations are static, but sometimes you need something that’s dynamic. These are achieved via the <code>RuntimeAnnotationsPlugin</code> in the Annotated Logger config. The <code>RuntimeAnnotationsPlugin</code> takes a dict of names and references to functions. These functions will be called and passed the log record when the plugin’s filter method is invoked just before the log message is emitted. Whatever is returned by the function will be set as the value of the annotation of the log message currently being logged.</p><p>A common use case is to annotate a request/correlation id, which identifies all of the log messages that were part of a given API request. For Django, one way to do this is via <a href="https://pypi.org/project/django-guid/">django-guid</a>.</p><h2 id="tips-tricks-and-gotchas">Tips, tricks and gotchas<a aria-label="Tips, tricks and gotchas" class="heading-link pl-2 text-italic text-bold" href="#tips-tricks-and-gotchas"></a></h2><ul><li>When using the decorator in more than one file, it’s useful to do all of the configuration in a file like <code>log.py</code>. That allows you to <code>from project.log import annotate_logs</code> everywhere you want to use it and you know it’s all configured and everything will be using the same setup.</li><li>Namespacing your loggers helps when there are two projects that both use the Annotated Logger (a package and a service that uses the package). If you are setting anything via <code>dictConfig</code> you will want to have a single config that has everything for all Annotated Loggers.</li><li>In addition to setting a correlation id for the API request being processed, passing the correlation id of the caller and then annotating that will allow you to trace from the logs of service A to the specific logs in Service B that relate to a call made by service A.</li><li>Plugins are very flexible. For example:<ul><li>Send every <code>exception</code> log message to a service like Sentry.</li><li>Suppress logs from another package, like Django, that you don’t want to see (assuming you’ve configured Django’s logs to use a filter for your Annotated Logger).</li><li>Add annotations for extra information about specific types of exceptions (see the <code>RequestsPlugin</code>).</li><li>Set run time annotations on a subset of messages (instead of all messages with <code>RuntimeAnnotationsPlugin</code>)</li></ul></li></ul><h2 id="questions-feedback-and-requests">Questions, feedback and requests<a aria-label="Questions, feedback and requests" class="heading-link pl-2 text-italic text-bold" href="#questions-feedback-and-requests"></a></h2><p>We’d love to hear any questions, comments or requests you might have in an <a href="https://github.com/github/annotated-logger/issues">issue</a>. Pull requests welcome as well!</p></body></html><p>The post <a href="https://github.blog/developer-skills/programming-languages-and-frameworks/introducing-annotated-logger-a-python-package-to-aid-in-adding-metadata-to-logs/">Introducing Annotated Logger: A Python package to aid in adding metadata to logs</a> appeared first on <a href="https://github.blog">The GitHub Blog</a>.</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Introducing Annotated Logger: A Python package to aid in adding metadata to logs" href="https://github.blog/developer-skills/programming-languages-and-frameworks/introducing-annotated-logger-a-python-package-to-aid-in-adding-metadata-to-logs/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Introducing Annotated Logger: A Python package to aid in adding metadata to logs</span><span class="cap link fs12">https://github.blog/developer-skills/programming-languages-and-frameworks/introducing-annotated-logger-a-python-package-to-aid-in-adding-metadata-to-logs/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/categories/blogs/github/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Github" scheme="https://blog.imc.re/RSSBOX/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>Internationalization and Localization: Bringing Cloudflare Radar to a Global Audience</title>
    <link href="https://blog.imc.re/RSSBOX/rss/94362ba1.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/94362ba1.html</id>
    <published>2024-12-16T14:00:00.000Z</published>
    <updated>2024-12-16T14:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div> <p><a href="https://radar.cloudflare.com/">Cloudflare Radar</a> celebrated its fourth birthday in September 2024. As we’ve expanded Radar’s scope over the last four years, the value that it provides as a resource for the <b>global</b> Internet has grown over time, and with Radar data and graphs often appearing in publications and social media around the world, we knew that we needed to make it available in languages beyond English.</p><p>Localization is important because most Internet users do not speak English as a first language. According to <a href="https://w3techs.com/technologies/history_overview/content_language/ms/y"><u>W3Techs</u></a>, English usage on the Internet has dropped 8.3 points (57.7% to 49.4%) since January 2023, whereas usage of other languages like Spanish, German, Japanese, Italian, Portuguese and Dutch is steadily increasing. Furthermore, a <a href="https://csa-research.com/Featured-Content/For-Global-Enterprises/Global-Growth/CRWB-Series/CRWB-B2C"><u>CSA Research study</u></a> determined that 65% of Internet users prefer content in their language.</p><p>To successfully (and painlessly) localize any product, it must be internationalized first.  Internationalization is the process of making a product ready to be translated and adapted into multiple languages and cultures, and it sets the foundation to enable your product to be localized later on at a much faster pace (and at a lower cost, both in time and budget). Below, we review how Cloudflare’s Radar and Globalization teams worked together to deliver a Radar experience spanning twelve languages.</p><div><h2>What is localization?</h2><a href="#what-is-localization"></a></div><p>Localization (l10n) is the process of adapting content for a region, including translation, associated imagery, and cultural elements that influence how your content will be perceived. The goal, ideally, is to make the content sound like it was originally written with the region in mind, incorporating relevant cultural nuances instead of merely replacing English with translated text.</p><p>Localization includes, among others:</p><ul><li><p><b>Language</b>: Translation, obviously, but it’s just the beginning.</p></li><li><p><b>Tone and message</b>: Localization considers what will resonate with your target audience, not just what’s accurate.</p></li><li><p><b>Images</b>: What may be appropriate in one country can be problematic in another (maps, for instance, that tend to include disputed territories). </p></li><li><p><b>Date, time, measurement, and number formats</b>: Formats change based on location and may differ even within the same language. In the U.S., the date follows this format: “December 15, 2018.” But in the U.K., that same date would be written like this: “15 December 2018.” Not to mention a constant source of confusion: the month/day/year vs.day/month/year difference:</p></li></ul><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ChruPHkbCpKkaDNfnd3wK/13a299038c2fc70e71fc7e4e71fb8671/image9.png"/></figure><p><sup><i>Image: XKCD, </i></sup><a href="https://xkcd.com/2562/"><sup><i><u>https://xkcd.com/2562/</u></i></sup></a></p><p>Pixar movies are a great example of localization<b><i>. </i></b>Pixar takes great care to internationalize their movie production process, so they can replace or insert scenes that will resonate with watchers all over the world, not just the US. Let’s consider <i>Inside Out</i> (2015). During the movie, Riley reminisces about playing ice hockey back in Minnesota. Most of the world is not as familiar with ice hockey as in the US, so Pixar wisely decided that they would use soccer elsewhere, allowing a more direct emotional connection with those audiences. </p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2vmuz0H3YXa6sAh0EJpj0E/5ed37b80f24932c6082a079a587c1ac4/Screenshot_2024-12-14_at_16.15.15.png"/></figure><p><sup><i>Images: scene from Inside Out (2015), produced by Pixar Animation Studios and Walt Disney Pictures. Copyright Pixar Animation Studios and Walt Disney Pictures. Images used under fair use.</i></sup></p><p>And you don’t have to go to computer animated movies. Here’s an example from The Shining (1980) where the famous “All work and no play makes Jack a dull boy” typewriter scene was localized into all languages differently. <i>The producers, in a pre-Information Technology example of internationalization, shot and cut the localized scene into the local versions of the movie.</i></p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3GNqgdcxlk9fLll5OQgilJ/5bfe683547230280ea84741a7c7c0405/Screenshot_2024-12-14_at_16.16.28.png"/></figure><p><sup><i>Images: scene from The Shining (1980), directed by Stanley Kubrick. Copyright Warner Bros. Pictures. Images used under fair use.</i></sup></p><div><h2>Internationalization</h2><a href="#internationalization"></a></div><p>Localization is hard, and no one in the business will tell you otherwise. Fortunately there’s a playbook: the first step to localization is <b>internationalization</b> (i18n). <b>Internationalization</b> is the process of making a product ready to be translated and adapted into multiple languages and cultures. It's a preparatory step that helps with translation and localization. The more you internationalize your code and the more you take into account language and cultural nuances, the easier the localization will be.</p><div><h3>Hard-coding and externalization</h3><a href="#hard-coding-and-externalization"></a></div><p>The first step to internationalize Radar was to assess how many of the localizable strings were hard-coded. Hard coding is the practice of embedding data directly into the source code of a program. Although a convenient and fast way to write your code, it makes it more difficult to change or localize the code later.</p><p>Most of the strings that make up the Radar pages used to be hard-coded, so before we could begin translating, <b>externalization</b> had to be done, which is the process of extracting any text that needs to be localized from the code and moving it into separate files.</p><p>Hard-coded strings:</p><pre><code>import Card from “~/components/Card”;import Chart from “~/components/Chart”;<p>export default function TrafficChart() &amp;#123;<br>  return (<br>    &lt;Card<br>      title&#x3D;”Traffic”<br>      description&#x3D;”Share of HTTP requests”<br>    &gt;<br>      &lt;Chart &#x2F;&gt;<br>    &lt;&#x2F;Card&gt;<br>  );<br>&amp;#125;</code></pre></p><p>Externalized key placeholders:</p><pre><code>import &#123; useTranslation &#125; from "react-i18next";import Card from “~/components/Card”;import Chart from “~/components/Chart”;<p>export default function TrafficChart() &amp;#123;<br>  const &amp;#123; t &amp;#125; &#x3D; useTranslation();<br>  return (<br>    &lt;Card<br>      title&#x3D;&amp;#123;t(“traffic.chart.title”)&amp;#125;<br>      description&#x3D;&amp;#123;t(“traffic.chart.description”)&amp;#125;<br>    &gt;<br>      &lt;Chart &#x2F;&gt;<br>    &lt;&#x2F;Card&gt;<br>  );<br>&amp;#125;</code></pre></p><p>There are several benefits to externalizing strings:</p><ul><li><p>It allows translators to work on separate, isolated files that contain only localizable strings </p></li><li><p>It prevents accidental changes to the code </p></li><li><p>It allows developers to deploy updates, changes, and fixes without having to recompile or redeploy code for each language every time</p></li></ul><p>If you look at the example below, when the code is compiled or deployed, upon reaching line 10 (on the left), it will find a key named <code>traffic.chart.title</code>. It will then proceed to match that key within the JSON file on the right, finding it on line 1090 and resolving it to “<code>Traffic</code>” for English, "<code>Tráfego</code>" for Portuguese and "<code>トラフィック</code>" for Japanese, doing this for every localized JSON file present in the code.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/14pNiwO9UTdrwbFzq2VUvi/c1a163bc98915195a0cb8ccb29639365/image1.png"/></figure><div><h3>Pseudo translation</h3><a href="#pseudo-translation"></a></div><p>Not all strings are easily found and some are buried deep in the code, sometimes in legacy, inherited code or APIs. Fortunately, there are some strategies that help detect hard-coded strings. This is where <b><i>pseudo translation</i></b> comes into play.</p><p><i>Pseudo translation</i> is a process that replaces all characters in a string with similar-looking ones; pseudo translated strings are enclosed within [ ] characters, and some extra characters are added to them to simulate text expansion (<a href="#text-expansion"><u>more on that later</u></a>). It is an invaluable tool to help us find any hard coded strings, and to stress test the UI for language readiness and length variability, while still keeping the content mostly readable. For example, this string:</p><p><code>Routing Information</code></p><p>looks like this once pseudo translated:</p><p><code>[R~óútíñg Í~ñfó~rmát~íóñ]</code></p><p>Once pseudo translation is done, any English strings left intact are most likely hard coded or come from other sources. In the screenshot below you can see how <code>ASN</code>, <code>Country</code>, <code>Name</code> and <code>Prefix Count</code> did not get pseudo translated and had to be externalized by the Radar developers. The Globalization team collaborated with the Radar team to report and fix hard-coded text issues, as well as the issues that are mentioned in the next few sections.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/16SjYR099rxBLw0YuptB9n/7ca430aa1544349c3e2eff45cdbdfe60/image4.png"/></figure><div><h3>Text expansion</h3><a href="#text-expansion"></a></div><p>Text expansion occurs when translated content from one language to another takes up more space than the original. Sometimes this expansion is horizontal, as English to German can <a href="https://abctranslations.com/text-expansion-and-reduction-in-translation-services"><u>expand</u></a> up to an average of 35%, Spanish 30%, and French 20%). Asian languages might contract from the English but expand vertically. Interestingly, the fewer characters English has, the more the localized languages tend to expand.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3P2FszOadUDhhc1oRzjjra/250d2425f09423907359914bf628e29c/image10.png"/></figure><p><sup><i>Data source: </i></sup><a href="https://www.ibm.com/docs/en/i/7.3?topic=interfaces-text-translation-design"><sup><i><u>IBM</u></i></sup></a></p><p>UI designers and developers need to keep this in mind when creating their applications. Thus, one important consideration is to test the design mock-ups with larger texts and plan the UI to accommodate for text expansion. If some English content barely fits within its container, it will most likely not fit in other languages and possibly break the layout.</p><p>Here’s an example of the same button in different languages in Radar’s fixed-width sidebar. Since it’s the main navigation, truncating the text is not appropriate and the only viable option is wrapping, which means localized buttons can end up having different heights. Sometimes it’s necessary to trade visual consistency for usability.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/oByQcEAMDwh4gv1GtxOQG/0de2878728f293a49e03a9b90fbae536/image3.png"/></figure><div><h3>String concatenation</h3><a href="#string-concatenation"></a></div><p>In English, you can easily chain-connect words because most words lack <a href="https://en.wikipedia.org/wiki/Inflection"><u>inflections</u></a>. Almost all programming languages are designed using the English language in mind. An old linguist joke goes like: <i>an English teacher: a teacher of English or a teacher from England? </i>Case in point, it would be nightmarish to translate this example:</p><p><code>A lovely little old rectangular green French silver whittling knife</code> </p><p>Most Western languages need to connect words with some <i>glue</i>: prepositions, articles, or inflections. This is why, in general, string concatenation (putting together sentences or sentence parts by combining two or more strings) is a terrible practice for localization, even though it seems efficient from a development point of view. You can’t assume that all languages follow the same sentence structure as English. Most languages don’t.</p><p>Sentences may need to be completely reversed for them to sound grammatically correct in other languages. This becomes a particularly severe problem when a string doesn’t include a placeholder because it’s assumed to be concatenated at the beginning or the end of the string, such as this:</p><p><code>"is currently categorized as:"</code></p><p>Developers need to make sure to include any placeholders within the string itself, so that translators can easily move them as needed, for instance:</p><p><code>"Distribution of &#123;&#123;botClass&#125;&#125; traffic by IP version"</code></p><p>would look like this in Simplified Chinese (notice how the <code>&#123;&#123;botClass&#125;&#125;</code> placeholder got moved)</p><p><code>"&#123;&#123;botClass&#125;&#125; 流量分布（按 IP 版本）"</code></p><div><h3>String reuse</h3><a href="#string-reuse"></a></div><p>As with string concatenation, string reuse (using the same string in more than one place and just swapping out the contents of a placeholder) seems efficient if you’re a developer. A problem arises when translating this into gendered languages, such as most European languages. In Spanish, depending on its position and context, a word as simple as “open” standing by itself, could have all these different translations:</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3rcU3cH7ZXfsn5bxmx11UG/60e9ebfbec19caed3553e8d3b63828fd/image7.png"/></figure><p>Other examples are <code>Custom</code>, <code>Detected</code>, or <code>Disabled</code>, which can have different translations depending on their position within a sentence, their location in the UI, depending on whether they accompany a singular, plural, masculine or feminine noun, so <a href="https://www.i18next.com/translation-function/plurals#singular-plural"><u>extra entries</u></a> for these may need to be created in the language files.</p><p>Translators will also need to know what will replace the placeholders in strings like the one below, because the surrounding wording may refer to a term that is masculine, feminine, or neutral (for languages that have those, such as German). If a placeholder could be more than one of these (a masculine noun but also a feminine noun), the translation will become grammatically incorrect in at least some of the cases. In the following example, translators would need to know what <code>&#123;link1&#125;</code> and <code>&#123;link2&#125;</code> will be replaced with, so they know which grammatically correct wording to use around them.</p><p><code>Your use of the URL Scanner is subject to our &#123;&#123;link1&#125;&#125;. Any personal data in a submitted URL will be handled in accordance with our &#123;&#123;link2&#125;&#125;</code>.</p><p>A better way to do this is to have component placeholders and include the text to be translated for context:</p><p><code>Your use of the URL Scanner is subject to our &lt;link1&gt;Online Service Terms of Use&lt;/link1&gt;. Any personal data in a submitted URL will be handled in accordance with our &lt;link2&gt;Privacy Policy&lt;/link2&gt;</code>.</p><div><h2>Regional considerations</h2><a href="#regional-considerations"></a></div><div><h3>Date formats</h3><a href="#date-formats"></a></div><p>Date formats vary greatly from country to country. Not only can’t you assume that all countries use a month/day/year format, but even the day that the week starts may be different based on the country or culture.<p>Here’s a comparison of Radar’s date picker in American English against European Spanish (which has weeks starting on Mondays instead of Sundays), and against Simplified Chinese (which uses a completely different format for dates).</p></p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/10dcc7wLFMwNmIeMtHeezb/863c9e61d174f9f647379a146b0d4912/image2.png"/></figure><p>Thankfully, developers don’t need to know all the country-specific details, as they can use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat"><u>Intl.DateTimeFormat</u></a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString"><u>Date.toLocaleString()</u></a> for this.</p><p>Intl.DateTimeFormat receives a locale and formatting <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#date-time_component_options"><u>options</u></a> that differ from string tokens commonly found on date libraries such as <a href="http://day.js"><u>Day.js</u></a> or <a href="https://momentjs.com/"><u>Moment.js</u></a>. Unless you specifically use the <a href="https://day.js.org/docs/en/display/format#localized-formats"><u>localized string tokens</u></a> on those libraries, the order of the tokens is fixed, along with any characters or delimiters you might add to the format, which poses a problem because the date format parts order should change according to the locale. <p>Intl.DateTimeFormat handles all that and saves you the trouble of having to add a date formatting dependency to your project and loading library-specific locale resources.</p><p>Here’s an example of a generic React component using Intl.DateTimeFormat and react-i18next. The code below will render the date as “Tue, Oct 1, 2024” for American English (en-US) and as “2024年10月1日(火)” for Japanese (ja-JP).</p></p><pre><code>import &#123; useTranslation &#125; from "react-i18next";export default function SomeComponent() &#123;  const &#123; i18n &#125; = useTranslation();  const date = new Date("2024-10-01");  return (    &lt;time dateTime=&#123;date.toISOString()&#125;&gt;      &#123;new Intl.DateTimeFormat(i18n.language, &#123;        weekday: "short",        month: "short",        year: "numeric",        day: "numeric",      &#125;).format(date)&#125;    &lt;/time&gt;  );&#125;</code></pre><div><h3>Number notations</h3><a href="#number-notations"></a></div><p>Similarly, different locales use different notations for numbers. In the US and the UK, a period is used as the decimal separator, and a comma as the thousands separator. Instead, other countries use a comma as the decimal separator and a period (or a space) as the thousands separator. Again, it’s not necessary for developers to know all the odds and ends for this, as they can use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat"><u>Intl.NumberFormat</u></a>.</p><p>Here’s an example of a generic React component using Intl.NumberFormat and react-i18next. The code below will render the number as “12,345,678.90” for American English (en-US) and as “12 345 678,90” for Portuguese (pt-PT). Intl.NumberFormat <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options"><u>options</u></a> can be passed to format numbers as decimals, percentages, currencies, etc, and specify things like number of decimal places and rounding strategies.</p><pre><code>import &#123; useTranslation &#125; from "react-i18next";<p>export default function SomeComponent() &amp;#123;<br>  const &amp;#123; i18n &amp;#125; &#x3D; useTranslation();<br>  return (<br>    &lt;span&gt;&amp;#123;new Intl.NumberFormat(i18n.language, &amp;#123;<br>    style: “decimal”,<br>    minimumFractionDigits: 2,<br>  &amp;#125;).format(12345678.9)&amp;#125;&lt;&#x2F;span&gt;);<br>&amp;#125;</code></pre></p><p>As of mid-December, regionalized number formatting is not fully implemented on Radar. We expect this to be complete by the end of Q1 2025.</p><div><h3>List sorting</h3><a href="#list-sorting"></a></div><p>When you have a list of items that appears sorted, such as a country list in a dropdown, it’s not enough to simply translate the items. For instance, when translated into Portuguese, “<code>South Africa</code>” becomes “<code>África do Sul</code>”, which means it should then go near the top of the list. Besides that, each language has different sorting requirements, and those go way beyond the A-Z alphabet. For instance, several Asian languages don’t use Latin characters at all, and may get sorted by stroke or <a href="https://en.wikipedia.org/wiki/Chinese_character_radicals"><u>character radical</u></a> order instead.</p><figure><img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5uOOTu2U3txnxjcVkhI4VI/37af8b29d9537fc56c4c5e23e3504640/image13.png"/></figure><p>Here’s an example of a generic React country selector component using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare"><u>String.localeCompare</u></a> and react-i18next. The code below imports a list of countries with name and <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2"><u>alpha-2</u></a> code and sorts the options according to the translated country name for the active locale. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options"><u>Intl.Collator options</u></a> can be passed to localeCompare() for specific sorting needs.</p><pre><code>import &#123; useTranslation &#125; from "react-i18next";<p>import Select from “<del>&#x2F;components&#x2F;Select”;<br>import COUNTRIES from “</del>&#x2F;constants&#x2F;geo”;</p><p>export default function CountrySelector() &amp;#123;<br>  const &amp;#123; t, i18n &amp;#125; &#x3D; useTranslation();<br>  const options &#x3D; COUNTRIES.map((&amp;#123; name, code &amp;#125;) &#x3D;&gt; (&amp;#123;<br>    label: t(name, &amp;#123; ns: “countries” &amp;#125;),<br>    value: code,<br>  &amp;#125;)).sort((a, b) &#x3D;&gt; a.label.localeCompare(b.label, i18n.language));<br>  return &lt;Select options&#x3D;&amp;#123;options&amp;#125; onChange&#x3D;&amp;#123;(option) &#x3D;&gt; &amp;#123; &#x2F;* do something *&#x2F; &amp;#125;&amp;#125; &#x2F;&gt;;<br>&amp;#125;</code></pre></p><div><h2>API localization</h2><a href="#api-localization"></a></div><p>Many of the Radar screens and reports include output from Cloudflare or third-party APIs. Unfortunately, the vast majority of these APIs only output English content. When combining that with the translated part of the site, it may give the impression of a poorly localized site.</p><p>To solve this, we take API outputs and map everything into <a href="https://react.i18next.com/guides/multiple-translation-files"><u>separate files</u></a>, translate all possible messages, and then display that instead of the original output. But as APIs evolve over time and new messages are added, or existing ones get changed, keeping up with these translations becomes an endless game of “<a href="https://en.wikipedia.org/wiki/Whac-A-Mole"><u>whac-a-mole</u></a>".</p><pre><code>"Address unreachable error when attempting to load page": "Error de dirección inaccesible al intentar cargar la página","Authentication failed": "Autenticación fallida","Browser did not fully start before timeout": "El navegador no se ha iniciado por completo antes de agotar el tiempo de espera.","Certificate and/or SSL error when attempting to load page": "Error de certificado y/o SSL al intentar cargar la página","Crawl took too long to finish": "El rastreo ha tardado demasiado en completarse.","DNS resolution failed": "Error de resolución de DNS","Network connection aborted.": "Conexión de red cancelada"</code></pre><p>It should be a best practice for APIs to accept a locale parameter or header, and for engineers to have multiple languages in mind when building these APIs, even if it’s just the error messages. That could save time and resources for any number of clients they might have.</p><div><h2>Project setup</h2><a href="#project-setup"></a></div><p>Radar is a <a href="https://remix.run/"><u>Remix</u></a> project running on <a href="https://pages.cloudflare.com/"><u>Cloudflare Pages</u></a>. While researching ways to implement internationalization, we came across this Remix <a href="https://remix.run/blog/remix-i18n"><u>blog post</u></a>, and after some experimenting, we decided to go with Sergio Xalambrí’s <a href="https://github.com/sergiodxa/remix-i18next"><u>remix-i18next</u></a>. We mostly followed the installation instructions found on the repo, with some changes.</p><p>We have multiple translation files on every locale folder, one for each data source, to help us maintain strings that come from APIs. Each file can be used to create a namespace for translations, to avoid key collisions, and also to be loaded separately as needed for each route or component.</p><p>On remix-i18next’s instructions, you’ll find the concept of backend plugins to achieve the loading of these files, except that you cannot use <a href="https://github.com/i18next/i18next-fs-backend"><u>i18next-fs-backend</u></a> with Cloudflare Pages because there’s no access to the filesystem. To solve that we used the <i>resources</i> approach, similar to what can be found on this sample <a href="https://github.com/sergiodxa/remix-vite-i18next"><u>remix-i18next with vite</u></a> setup, but we didn’t want to have to maintain the resources dictionary each time we add new namespaces, so <a href="https://vite.dev/guide/features#glob-import"><u>vite’s Glob imports</u></a> came in handy:</p><pre><code>import &#123; serverOnly$ &#125; from "vite-env-only/macros";<p>export const resources &#x3D; serverOnly$(<br>  Object.entries(import.meta.glob(“.&#x2F;<em>&#x2F;</em>.json”, &amp;#123; import: “default” &amp;#125;)).reduce(<br>    (acc, [path, module]) &#x3D;&gt; &amp;#123;<br>      const parts &#x3D; path.split(“&#x2F;“).slice(1);<br>      const locale &#x3D; parts[0];<br>      const namespace &#x3D; parts[1].split(“.”)[0];<br>      if (!acc[locale]) acc[locale] &#x3D; &amp;#123;&amp;#125;;<br>      if (!acc[locale][namespace]) acc[locale][namespace] &#x3D; &amp;#123;&amp;#125;;<br>      module().then((value) &#x3D;&gt; (acc[locale][namespace] &#x3D; value));<br>      return acc;<br>    &amp;#125;,<br>    &amp;#123;&amp;#125;,<br>  ),<br>)!;</code></pre></p><p>This creates a <a href="https://github.com/pcattori/vite-env-only?tab=readme-ov-file#serveronly"><u>server-side only</u></a> resources dictionary by importing all JSON files in the locales folder to be passed as the resources property for the i18next configuration in Remix’s <a href="https://remix.run/docs/en/main/file-conventions/entry.server"><u>entry.server.tsx</u></a>.</p><p>To load namespaces on the client side, we created a Remix <a href="https://remix.run/docs/en/main/guides/resource-routes#creating-resource-routes"><u>resource route</u></a> that uses the resources dictionary and responds with the namespace object of the requested locale:</p><pre><code>import &#123; LoaderFunctionArgs &#125; from "@remix-run/server-runtime";<p>import &amp;#123; resources &amp;#125; from “~&#x2F;i18n”;</p><p>export async function loader(&amp;#123; params &amp;#125;: LoaderFunctionArgs) &amp;#123;<br>  const &amp;#123; locale, namespace &amp;#125; &#x3D; params;<br>  return resources[locale]?.[namespace] || &amp;#123;&amp;#125;;<br>&amp;#125;</code></pre></p><p>You can then use the <a href="https://github.com/i18next/i18next-http-backend"><u>i18next-http-backend</u></a> or <a href="https://github.com/dotcore64/i18next-fetch-backend"><u>i18next-fetch-backend</u></a> backend plugins for the i18next configuration in Remix’s <a href="https://remix.run/docs/en/main/file-conventions/entry.client"><u>entry.client.tsx</u></a>:</p><pre><code>import i18next from "i18next";import i18nextHttpBackend from "i18next-http-backend";import &#123; initReactI18next &#125; from "react-i18next";import &#123; getInitialNamespaces &#125; from "remix-i18next/client";import &#123; options &#125; from “~/i18n”;  <p>await i18next<br>    .use(initReactI18next)<br>    .use(i18nextHttpBackend)<br>    .init(&amp;#123;<br>      …options,<br>      ns: getInitialNamespaces(),<br>      backend: &amp;#123; loadPath: “&#x2F;api&#x2F;i18n&#x2F;&amp;#123;&amp;#123;lng&amp;#125;&amp;#125;&#x2F;&amp;#123;&amp;#123;ns&amp;#125;&amp;#125;” &amp;#125;,<br>    &amp;#125;);</code></pre></p><p>Default namespaces are defined with the <i>defaultNS</i> config property:</p><pre><code>export const defaultNS = ["main", "countries"];</code></pre><p>Additional namespaces to be used for each route can be defined through Remix’s <a href="https://remix.run/docs/en/main/route/handle"><u>handle export</u></a>:</p><pre><code>export const handle = &#123;  i18n: ["url-scanner", "domain-categories"],&#125;;</code></pre><p>Namespaces on the server side get picked up by the <i>getRouteNamespaces</i> function on entry.server.tsx:</p><pre><code>const ns = i18n.getRouteNamespaces(remixContext);</code></pre><p>On the client-side, examples suggested that you’d have to declare the namespaces on each <i>useTranslation()</i> hook instance, but we worked around that in Remix’s <a href="https://remix.run/docs/en/main/file-conventions/root"><u>root.tsx</u></a> file:</p><pre><code>import &#123; useLocation, useMatches &#125; from "@remix-run/react";import &#123; useTranslation &#125; from "react-i18next";import &#123; defaultNS &#125; from “~/i18n”;<p>export function Layout(&amp;#123; children &amp;#125;) &amp;#123;<br>  const location &#x3D; useLocation();<br>  const matches &#x3D; useMatches();<br>  const handle &#x3D; matches?.find((m) &#x3D;&gt; m.pathname &#x3D;&#x3D;&#x3D; location.pathname)?.handle || &amp;#123;&amp;#125;;<br>  useTranslation([…new Set([…defaultNS, …(handle.i18n || [])])]);<br>  …<br>&amp;#125;</code></pre></p><p>This causes the client-side plugin to make calls to the resource route and load the required namespaces.</p><p>We also wanted to have the locale in the URL pathname, but not for the default language, so Remix’s <a href="https://remix.run/docs/en/main/file-conventions/routes#optional-segments"><u>optional segments</u></a> allowed us to do just that. remix-i18next does not have URL locale detection by default, but you can provide your own <a href="https://github.com/sergiodxa/remix-i18next?tab=readme-ov-file#finding-the-locale-from-the-request-url-pathname"><u>findLocale function</u></a> that will receive the request as an argument, and you can then parse the request URL to extract the locale.</p><div><h2>Search engine optimization</h2><a href="#search-engine-optimization"></a></div><p>Once you set up your project for internationalization, you can inform search engines of <a href="https://developers.google.com/search/docs/specialty/international/localized-versions"><u>localized versions of your pages</u></a>. This allows search engines to display localized results of your website in the same language that is being searched.</p><pre><code>&lt;head&gt;  ...  &lt;link rel="alternate" href="https://radar.cloudflare.com/" hreflang="en-US"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/de-de" hreflang="de-DE"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/es-es" hreflang="es-ES"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/es-la" hreflang="es-LA"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/fr-fr" hreflang="fr-FR"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/it-it" hreflang="it-IT"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/ja-jp" hreflang="ja-JP"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/ko-kr" hreflang="ko-KR"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/pt-br" hreflang="pt-BR"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/pt-pt" hreflang="pt-PT"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/zh-cn" hreflang="zh-CN"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/zh-tw" hreflang="zh-TW"&gt;  &lt;link rel="alternate" href="https://radar.cloudflare.com/" hreflang="x-default"&gt;  &lt;link rel="canonical" href="https://radar.cloudflare.com/"&gt;  ...&lt;/head&gt;</code></pre><p>You should also localize page titles, descriptions, and relevant <a href="https://ogp.me/"><u>Open Graph</u></a> metadata. To achieve this with Remix and remix-i18next, you use the <a href="https://github.com/sergiodxa/remix-i18next?tab=readme-ov-file#translating-text-inside-loaders-or-actions"><u>getFixedT</u></a> method in route loaders to resolve the translations and return data for the <a href="https://remix.run/docs/en/main/route/meta"><u>meta export</u></a>:</p><pre><code>import type &#123; LoaderFunctionArgs, MetaArgs &#125; from "@remix-run/server-runtime";import i18n from "~/i18next.server";<p>export async function loader(&amp;#123; request &amp;#125;: LoaderFunctionArgs) &amp;#123;<br>  const t &#x3D; await i18n.getFixedT(request);<br>  return &amp;#123;<br>    meta: &amp;#123;<br>      title: t(“meta.about.title”),<br>      description: t(“meta.about.description”),<br>      url: request.url,<br>    &amp;#125;,<br>  &amp;#125;;<br>&amp;#125;</p><p>export const meta &#x3D; (&amp;#123; data &amp;#125;: MetaArgs&lt;typeof loader&gt;) &#x3D;&gt; data.meta;</code></pre></p><p>If you are defining default meta tags in parent routes you may also need to <a href="https://remix.run/docs/ru/main/route/meta#merging-with-parent-meta"><u>merge the meta objects</u></a>.</p><div><h2>Conclusion</h2><a href="#conclusion"></a></div><p>There is hardly ever an absolute when dealing with languages. Your Spanish, your French, your Japanese will be different from someone else’s, even if you grew up next door to each other. Family, education, environment, relationships will season and give color to your language. It is like a family recipe — it’s unique, it feels like home and it’s not negotiable. It does not make it better or worse, it just makes it yours. And yours will always be different from other languages.</p><p>Localization is hard. We have seen that there are many things that can and will go sideways, and there are many unknowns that bubble up to the surface in the process. It can also make a product better, as it stress tests the product’s code and design. A tight relationship between the globalization and Radar teams helped make our efforts go more smoothly. In addition, our translators stepped up to the challenge, familiarizing themselves with Radar, analyzing the English content, finding the right translation that will not only resonate with the audience but also fit in the space allotted, constantly checking for context, previous translations, consistency, industry standards, adapting to style guides, tone, and messaging, and after all of that, ultimately acknowledging the fact that there will be people who will disagree (to varying levels of zeal) with their choice of words.</p><p>If you haven’t done so already, we encourage you to explore the localized versions of <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>. Click the language drop-down in the upper right corner of the Radar interface and select your language of choice — Radar will be presented in that language until a new selection is made. Have comments or suggestions about the translations? Let us know at radar_localization@cloudflare.com.</p> </div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Internationalization and localization: bringing Cloudflare Radar to a global audience" href="https://blog.cloudflare.com/cloudflare-radar-localization-journey/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Internationalization and localization: bringing Cloudflare Radar to a global audience</span><span class="cap link fs12">https://blog.cloudflare.com/cloudflare-radar-localization-journey/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/categories/blogs/cloudflare/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="Cloudflare" scheme="https://blog.imc.re/RSSBOX/tags/cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>Fern Wifi Cracker 报错解决方案</title>
    <link href="https://blog.imc.re/RSSBOX/rss/b45191e3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/b45191e3.html</id>
    <published>2024-04-20T02:30:16.000Z</published>
    <updated>2024-04-20T02:30:16.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><p>查看无线网卡</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">airmon-ng</span><br/></pre></td></tr></table></figure><p>重新设置无线网卡</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">ip <span class="built_in">link</span> <span class="built_in">set</span> wlan0 down</span><br/><span class="line">ip <span class="built_in">link</span> <span class="built_in">set</span> wlan0 name wlan0mon</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="fern wifi cracker 报错解决方案" href="http://blog.imc.re/archives/91fb.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">fern wifi cracker 报错解决方案</span><span class="cap link fs12">http://blog.imc.re/archives/91fb.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>博客真的需要图片点击放大功能吗？</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f143b031.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f143b031.html</id>
    <published>2024-02-07T16:00:00.000Z</published>
    <updated>2024-02-07T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>这是一个非常有争议的话题，自 Stellar 诞生之初，就有这个话题相关的讨论，本文将就这个话题展开详细阐述，解答一下 Stellar 为什么与众不同。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="博客真的需要图片点击放大功能吗？" href="https://xaoxuu.com/blog/20240208/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">博客真的需要图片点击放大功能吗？</span><span class="cap link fs12">https://xaoxuu.com/blog/20240208/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>我为什么开发了一个专栏功能？</title>
    <link href="https://blog.imc.re/RSSBOX/rss/9e02f6c3.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/9e02f6c3.html</id>
    <published>2024-02-02T16:00:00.000Z</published>
    <updated>2024-02-02T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>在回访用户的过程中，我发现有不少用户用 wiki 当作专栏来使用，可见专栏确实是一个普遍的需求点，而现有的 wiki 系统并不是专门为此场景设计的，虽然能用，但是不够好用。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="我为什么开发了一个专栏功能？" href="https://xaoxuu.com/blog/20240203/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">我为什么开发了一个专栏功能？</span><span class="cap link fs12">https://xaoxuu.com/blog/20240203/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>项目警告对构建速度的巨大影响</title>
    <link href="https://blog.imc.re/RSSBOX/rss/8ced571.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/8ced571.html</id>
    <published>2024-01-10T16:00:00.000Z</published>
    <updated>2024-01-10T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>近期（指一个月前）终于有时间偿还前辈留下的技术债了，下面分享一下经验和心得。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="项目警告对构建速度的巨大影响" href="https://xaoxuu.com/blog/20240111/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">项目警告对构建速度的巨大影响</span><span class="cap link fs12">https://xaoxuu.com/blog/20240111/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>关于 ObjC 通知的一个神奇崩溃</title>
    <link href="https://blog.imc.re/RSSBOX/rss/d72c298a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/d72c298a.html</id>
    <published>2024-01-09T16:00:00.000Z</published>
    <updated>2024-01-09T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>近日发现一个用 NSNotificationCenter 发通知时触发的 EXC_BAD_ACCESS 崩溃，表现形式比较奇怪，特此记录一下。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="关于 ObjC 通知的一个神奇崩溃" href="https://xaoxuu.com/blog/20240110/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">关于 ObjC 通知的一个神奇崩溃</span><span class="cap link fs12">https://xaoxuu.com/blog/20240110/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>Gallery 标签组件的使用方法和 Unsplash 高清壁纸分享</title>
    <link href="https://blog.imc.re/RSSBOX/rss/1eb3057e.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/1eb3057e.html</id>
    <published>2023-12-22T16:00:00.000Z</published>
    <updated>2023-12-22T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>水一下文，主要是为了测试一下图库功能，都是高清大图，可以用作壁纸。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Gallery 标签组件的使用方法和 Unsplash 高清壁纸分享" href="https://xaoxuu.com/blog/20231223/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Gallery 标签组件的使用方法和 Unsplash 高清壁纸分享</span><span class="cap link fs12">https://xaoxuu.com/blog/20231223/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>Linux查询操作</title>
    <link href="https://blog.imc.re/RSSBOX/rss/bcd9ad2.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/bcd9ad2.html</id>
    <published>2023-12-20T06:50:37.000Z</published>
    <updated>2023-12-20T06:50:37.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><ol><li>whereis用来寻找可执行文件的位置</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># whereis ls</span></span><br/><span class="line"><span class="built_in">ls</span>: /usr/bin/ls /usr/share/man/man1/ls.1.gz</span><br/><span class="line">[root@master ~]<span class="comment"># ls</span></span><br/><span class="line">aaa  anaconda-ks.cfg  localperl  nohup.out  perl5  ShiSai2022-1.0-SNAPSHOT.jar </span><br/><span class="line">spark-yarn-logs  zookeeper.out</span><br/><span class="line">[root@master ~]<span class="comment"># cd /usr/bin/</span></span><br/><span class="line">[root@master bin]<span class="comment"># ll ls</span></span><br/><span class="line">-rwxr-xr-x. 1 root root 117680 10月 31 2018 <span class="built_in">ls</span></span><br/></pre></td></tr></table></figure><ol start="2"><li>whatis用来获取命令的简介</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master bin]<span class="comment"># whatis ls</span></span><br/><span class="line"><span class="built_in">ls</span> (1)               - list directory contents</span><br/></pre></td></tr></table></figure><ol start="3"><li>find用来寻找文件的位置</li></ol><p>从根目录下开始，寻找cd这个文件的位置。一共找到了3处。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># find / -name cd</span></span><br/><span class="line">/root/.npm/_cacache/index-v5/cd</span><br/><span class="line">/root/.npm/_cacache/content-v2/sha512/f7/cd</span><br/><span class="line">/usr/bin/cd</span><br/><span class="line">[root@master ~]<span class="comment"># cd /usr/bin/</span></span><br/><span class="line">[root@master bin]<span class="comment"># ls cd</span></span><br/><span class="line"><span class="built_in">cd</span></span><br/></pre></td></tr></table></figure><ol start="4"><li>grep用来查找文件中，包含指定字符串的行</li></ol><p>建立./aaa.txt并插入一些内容</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/><span class="line">17</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo "hello hadoop" &gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello hdfs" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello hdfs" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello yarn" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello spark" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello hive" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello flink" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo "hello hbase" &gt;&gt; ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># cat ./aaa.txt</span></span><br/><span class="line">hello hadoop</span><br/><span class="line">hello hdfs</span><br/><span class="line">hello hdfs</span><br/><span class="line">hello yarn</span><br/><span class="line">hello spark</span><br/><span class="line">hello hive</span><br/><span class="line">hello flink</span><br/><span class="line">hello hbase</span><br/></pre></td></tr></table></figure><p>在./aaa.txt里查找含有字符串hadoop的行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># grep hadoop ./aaa.txt</span></span><br/><span class="line">hello Hadoop</span><br/><span class="line">[root@master ~]<span class="comment"># grep flink ./aaa.txt</span></span><br/><span class="line">hello flink</span><br/><span class="line">[root@master ~]<span class="comment"># grep hdfs ./aaa.txt</span></span><br/><span class="line">hello hdfs</span><br/><span class="line">hello hdfs</span><br/></pre></td></tr></table></figure><ol start="5"><li>用数字法修改文件的权限</li></ol><p>./aaa.txt原来的权限：对于文件的所有者而言aaa.txt可读可写不可执行，对于同组用户而言aaa.txt可读不可写不可执行，对于其他用户而言aaa.txt可读不可写不可执行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ll ./aaa.txt</span></span><br/><span class="line">-rw-r--r--. 1 root root 93 11月 20 08:21 ./aaa.txt</span><br/><span class="line"> 421421421</span><br/><span class="line">  6   4  4</span><br/><span class="line">-rwxr--r--</span><br/><span class="line">  7  4  4</span><br/></pre></td></tr></table></figure><p>把./aaa.txt变成：对于文件的所有者而言aaa.txt可读可写可执行，对于同组用户而言aaa.txt可读不可写不可执行，对于其他用户而言aaa.txt可读不可写不可执行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod 744 ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># ll ./aaa.txt</span></span><br/><span class="line">-rwxr--r--. 1 root root 93 11月 20 08:21 ./aaa.txt</span><br/></pre></td></tr></table></figure><p>把./aaa.txt变成：对于文件的所有者而言aaa.txt可读可写可执行，对于同组用户而言aaa.txt可读可写可执行，对于其他用户而言aaa.txt可读可写可执行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod 777 ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># ll ./aaa.txt</span></span><br/><span class="line">-rwxrwxrwx. 1 root root 93 11月 20 08:21 ./aaa.txt</span><br/></pre></td></tr></table></figure><p>把./aaa.txt变回到原来状态</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod 644 ./aaa.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># ll ./aaa.txt</span></span><br/><span class="line">-rw-r--r--. 1 root root 93 11月 20 08:21 ./aaa.txt</span><br/></pre></td></tr></table></figure><p>课堂练习：</p><p>把hadoop01镜像转到20230912，并启动hadoop01，用Ubuntu进行联机。完成下面的操作，并把命令和结果截图粘贴到ubuntu桌面下的目录Release的“模块A提交的结果.docx”。要求所有命令均使用绝对路径。</p><ol><li>在/root目录下建立子目录bbb</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /root/bbb</span><br/></pre></td></tr></table></figure><ol start="2"><li>在/root/bbb目录下建立文件b01.txt</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="3"><li><p>在b01.txt中插入以下内容：</p><p>Hello HadoopHello hdfsHello sparkHello flinkHello yarnHello hbase</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt;&gt; /root/bbb/b01.txt &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">Hello Hadoop</span></span><br/><span class="line"><span class="string">Hello hdfs</span></span><br/><span class="line"><span class="string">Hello spark</span></span><br/><span class="line"><span class="string">Hello flink</span></span><br/><span class="line"><span class="string">Hello yarn</span></span><br/><span class="line"><span class="string">Hello hbase</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="4"><li><p>将b01.txt拷贝为b02.txt，并在b02.txt中新增两行内容：</p><p>Hello RedisHello clickhouse</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /root/bbb/b01.txt /root/bbb/b02.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello Redis"</span> &gt;&gt; /root/bbb/b02.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello clickhouse"</span> &gt;&gt; /root/bbb/b02.txt</span><br/></pre></td></tr></table></figure><ol start="5"><li>用diff命令比较b01.txt、b02.txt的不同之处</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">diff /root/bbb/b01.txt /root/bbb/b02.txt</span><br/></pre></td></tr></table></figure><ol start="6"><li>用grep命令查找b01.txt中含有flink的行</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep "flink" /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="7"><li>修改/root/bbb/b01.txt的权限：文件所有者可读可写可执行，同组用户可读可写不可执行，其他用户不可读不可写不可执行，并用ls命令查看结果</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 760 /root/bbb/b01.txt &amp;&amp; <span class="built_in">ls</span> -l /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="8"><li>修改/root/bbb/b02.txt的权限：文件所有者可读不可写可执行，同组用户可读不可写不可执行，其他用户不可读不可写可执行，并用ls命令查看结果</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">chmod 441 /root/bbb/b01.txt &amp;&amp; ls -l /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="9"><li>用find命令查找b01.txt文件的位置</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name b01.txt</span><br/></pre></td></tr></table></figure><ol start="10"><li>用whereis命令查找grep命令文件的位置</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">whereis grep</span><br/></pre></td></tr></table></figure><ol start="11"><li>用tar命令将到/opt/hadoop-2.7.7.tar.gz解压到/usr/local/src下面。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">tar -xvzf /opt/hadoop-2.7.7.tar.gz -C /usr/local/src</span><br/></pre></td></tr></table></figure><ol start="12"><li>用find命令查找文件stop-all.sh的位置。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name stop-all.sh</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux查询操作" href="http://blog.imc.re/archives/b59e.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux查询操作</span><span class="cap link fs12">http://blog.imc.re/archives/b59e.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Linux管道命令</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f7d3eead.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f7d3eead.html</id>
    <published>2023-12-18T06:18:16.000Z</published>
    <updated>2023-12-18T06:18:16.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><ol><li>管道命令：|</li></ol><p>管道命令的作用：前一个命令的输出是后一个命令的输入</p><p>例如：统计目前有几个用户登录</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># who</span></span><br/><span class="line">root     pts/0        2023-12-18 08:08 (192.168.152.130)</span><br/><span class="line">[root@master ~]<span class="comment"># who | wc -l</span></span><br/><span class="line">1</span><br/></pre></td></tr></table></figure><p>查看/etc下面的文件和文件夹及其子文件夹、子文件的详细信息，并以可翻页的形式显示：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ls -Rl /etc | less</span></span><br/></pre></td></tr></table></figure><p>增加一个用户aaa，并查看/etc/passwd的内容，该文件存放了所有的系统用户、root用户、自定义用户。增加一个用户aaa，就可以看到该文件最后增加的相应的一行内容。用管道命令统计该文件的行数、字数、字符数。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># adduser aaa</span></span><br/><span class="line">[root@master ~]<span class="comment"># cat /etc/passwd</span></span><br/><span class="line">root:x:0:0:root:/root:/bin/bash</span><br/><span class="line">bin:x:1:1:bin:/bin:/sbin/nologin</span><br/><span class="line">daemon:x:2:2:daemon:/sbin:/sbin/nologin</span><br/><span class="line"></span><br/><span class="line">…………</span><br/><span class="line"></span><br/><span class="line">nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin</span><br/><span class="line">mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false</span><br/><span class="line">aaa:x:1000:1000::/home/aaa:/bin/bash</span><br/><span class="line">[root@master ~]<span class="comment"># cat /etc/passwd | wc</span></span><br/><span class="line">     30      59    1491</span><br/><span class="line"><span class="comment"># （行数） （字数） （字符数）</span></span><br/></pre></td></tr></table></figure><p>查看是否存在用户aaa</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># cat /etc/passwd | grep aaa</span></span><br/><span class="line">aaa:x:1000:1000::/home/aaa:/bin/bash</span><br/></pre></td></tr></table></figure><p>命令rpm -qa可以查看目前安装了哪些应用程序。现在要用管道命令，检查是否安装了mysql数据库：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># rpm -qa | grep mysql</span></span><br/><span class="line">mysql-community-server-5.7.18-1.el7.x86_64</span><br/><span class="line">mysql-community-common-5.7.18-1.el7.x86_64</span><br/><span class="line">mysql-community-libs-5.7.18-1.el7.x86_64</span><br/><span class="line">mysql-community-client-5.7.18-1.el7.x86_64</span><br/><span class="line">mysql-community-devel-5.7.18-1.el7.x86_64</span><br/></pre></td></tr></table></figure><p>查看mysql数据库中有多少个组件：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># rpm -qa | grep mysql | wc -l</span></span><br/><span class="line">5</span><br/></pre></td></tr></table></figure><p>通过这个命令，说明了管道命令是可以级联的，从而实现更加复杂的功能。</p><ol start="2"><li>vi编辑器操作</li></ol><p>（1）vi编辑器的启动和退出</p><p>用命令：vi+文件名：进入vi编辑器</p><p>按i键进入编辑模式，可以输入内容</p><p>按:wq保存退出，按:q!不保存退出</p><p>（2）vi编辑器的工作模式</p><p>编辑模式：进入vi编辑器以后的默认模式</p><p>插入模式：在编辑模式下，按i键，进入插入模式</p><p>命令模式：在编辑模式下，按：键，进入命令模式</p><p>（3）vi编辑器常用命令</p><p>:q!  不保存退出</p><p>:wq  保存退出</p><p>:?单词   查找文件中的某一个单词位置，查找定位后，按n键可以连续定位下一个单词。</p><p>😒/单词1/单词2/g   把文件中所有的单词1，替换成单词2</p><p>:d   删除当前行，或者在编辑模式状态下，在某一行上按dd，直接删除这一行</p><h2 id="课堂练习"><a class="markdownIt-Anchor" href="#课堂练习"></a> 课堂练习：</h2><ol><li>在/opt下建立文件夹/opt/aaa</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /opt/aaa</span><br/></pre></td></tr></table></figure><ol start="2"><li>用vi编辑器建立文件/opt/aaa/a01.txt,并输入下面的内容</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line">vi /opt/aaa/a01.txt</span><br/><span class="line">hello hadoop</span><br/><span class="line">hello spark</span><br/><span class="line">hello spark</span><br/><span class="line">hello hdfs</span><br/><span class="line">hello hdfs</span><br/><span class="line">hello hdfs</span><br/><span class="line">hello spark spark</span><br/></pre></td></tr></table></figure><p><img alt="image.png" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/20240101224407.png"/></p><ol start="3"><li><p>保存并退出</p></li><li><p>用管道命令统计/opt/aaa/a01.txt，一共有几行</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /opt/aaa/a01.txt | <span class="built_in">wc</span> -l</span><br/></pre></td></tr></table></figure><ol start="5"><li>用管道命令找到所有的含有hdfs单词的内容</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep <span class="string">"hdfs"</span> /opt/aaa/a01.txt</span><br/></pre></td></tr></table></figure><ol start="6"><li>用管道命令统计含有spark单词的行，一共有几行</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep <span class="string">"spark"</span> /opt/aaa/a01.txt | <span class="built_in">wc</span> -l</span><br/></pre></td></tr></table></figure><ol start="7"><li>用管道命令统计spark单词有几个</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep -o <span class="string">"spark"</span> /opt/aaa/a01.txt | <span class="built_in">wc</span> -l</span><br/></pre></td></tr></table></figure><ol start="8"><li>查看系统中是否安装了hbase软件包</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">rpm -qa | grep hbase</span><br/></pre></td></tr></table></figure><ol start="9"><li>新建用户bbb，并查找/etc/passwd中是否存在该用户</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">useradd bbb</span><br/><span class="line">grep bbb /etc/passwd</span><br/></pre></td></tr></table></figure><ol start="10"><li><p>在vi编辑器中，用?命令，查找hello单词</p></li><li><p>在vi编辑器中，用:s/单词1/单词2/g命令，将所有的hello，替换成hi</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 进入vi 使用如下命令</span></span><br/><span class="line">vi /opt/aaa/a01.txt</span><br/><span class="line">:%s/hello/hi/g</span><br/><span class="line">:wq</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 方法二</span></span><br/><span class="line">sed -i s/hello/hi/g /opt/aaa/a01.txt</span><br/></pre></td></tr></table></figure><ol start="12"><li>用管道命令，统计包含hi的内容一共有多少行，并利用重定向命令将结果写入/opt/aaa/a02.txt</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep hi /opt/aaa/a01.txt | <span class="built_in">wc</span> -l &gt;&gt; /opt/aaa/a02.txt</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux管道命令" href="http://blog.imc.re/archives/1903.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux管道命令</span><span class="cap link fs12">http://blog.imc.re/archives/1903.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Linux环境设置</title>
    <link href="https://blog.imc.re/RSSBOX/rss/a0063800.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/a0063800.html</id>
    <published>2023-12-11T06:56:38.000Z</published>
    <updated>2023-12-11T06:56:38.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><ol><li>工作环境设置文件</li></ol><p>（1）系统环境</p><p>/etc/profile</p><p>(2) root用户的环境</p><p>/root/.bash_profile</p><ol start="2"><li>将某一个目录/aaa加入工作环境文件，实现在任意位置均可执行该目录下面的程序</li></ol><p>（1）建立/aaa文件夹，并加入工作环境文件</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># cd /</span></span><br/><span class="line">[root@master /]<span class="comment"># mkdir /aaa</span></span><br/></pre></td></tr></table></figure><p>(2) 在/etc/profile中插入下面的内容：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line">[root@master /]<span class="comment"># vi /etc/profile  </span></span><br/><span class="line"><span class="comment"># 安装flume环境</span></span><br/><span class="line"><span class="built_in">export</span> FLUME_HOME=/opt/apache-flume-1.7.0-bin</span><br/><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:<span class="variable">$FLUME_HOME</span>/bin</span><br/><span class="line"><span class="comment"># 将/aaa文件夹加入</span></span><br/><span class="line"><span class="built_in">export</span> AAA_HOME=/aaa</span><br/><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:<span class="variable">$AAA_HOME</span></span><br/></pre></td></tr></table></figure><p>(3) 在/aaa中建立一个简单计时器脚本</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/></pre></td><td class="code"><pre><span class="line">[root@master /]<span class="comment"># cd /aaa</span></span><br/><span class="line">[root@master aaa]<span class="comment"># vi time01.sh</span></span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"start"</span></span><br/><span class="line"><span class="built_in">sleep</span> 1;<span class="built_in">echo</span> <span class="string">"----5----"</span>;</span><br/><span class="line"><span class="built_in">sleep</span> 1;<span class="built_in">echo</span> <span class="string">"----4----"</span>;</span><br/><span class="line"><span class="built_in">sleep</span> 1;<span class="built_in">echo</span> <span class="string">"----3----"</span>;</span><br/><span class="line"><span class="built_in">sleep</span> 1;<span class="built_in">echo</span> <span class="string">"----2----"</span>;</span><br/><span class="line"><span class="built_in">sleep</span> 1;<span class="built_in">echo</span> <span class="string">"----1----"</span>;</span><br/><span class="line"><span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"stop"</span></span><br/><span class="line">[root@master aaa]<span class="comment"># chmod 777 ./time01.sh</span></span><br/><span class="line">[root@master aaa]<span class="comment"># ll</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 164 12月 11 08:28 time01.sh</span><br/></pre></td></tr></table></figure><p>(4) 使修改的工作环境文件生效</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master aaa]<span class="comment"># source /etc/profile</span></span><br/></pre></td></tr></table></figure><p>(5)在任意位置均可执行：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line">[root@master aaa]<span class="comment"># cd /</span></span><br/><span class="line">[root@master /]<span class="comment"># time01.sh</span></span><br/><span class="line">start</span><br/><span class="line">----5----</span><br/><span class="line">----4----</span><br/><span class="line">----3----</span><br/></pre></td></tr></table></figure><ol start="3"><li>grep打印出所有符合指定规则的文本行</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line">[root@master /]<span class="comment"># cd /aaa</span></span><br/><span class="line">[root@master aaa]<span class="comment"># ll</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 164 12月 11 08:28 time01.sh</span><br/><span class="line">[root@master aaa]<span class="comment"># grep 'start' time01.sh</span></span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"start"</span></span><br/></pre></td></tr></table></figure><ol start="4"><li>正则表达式</li></ol><p>所有的正则表达式需要用单引号括起来</p><p>. 匹配单个任意字符</p><p>[list] 匹配字符串列表中的一个字符</p><p>*  匹配前一个字符0次或多次</p><p>^ 在行头匹配正则表达式</p><ol start="5"><li>重定向</li></ol><p>重定向是指不使用标准的输入输出接口，而进行重新指定</p><p>&lt; 输入重定向</p><blockquote><blockquote><p>或 &gt; 输出重定向</p></blockquote></blockquote><p>2&gt;或2&gt;&gt; 错误重定向</p><p>&amp;&gt; 同时实现输出重定向和错误重定向</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ll /aaa</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 164 12月 11 08:28 time01.sh</span><br/></pre></td></tr></table></figure><p>将/aaa文件夹的ll显示的内容保存到/root的result01.txt中</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ll /aaa &gt; result01.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># ll</span></span><br/><span class="line">总用量 72</span><br/><span class="line">drwxr-xr-x. 4 root root    36 11月 16 2022 aaa</span><br/><span class="line">-rw-------. 1 root root  1257 11月 18 2021 anaconda-ks.cfg</span><br/><span class="line">drwxr-xr-x. 5 root root    39 11月 18 2021 localperl</span><br/><span class="line">-rw-------. 1 root root  1623 7月  11 21:08 nohup.out</span><br/><span class="line">drwxr-xr-x. 5 root root    39 11月 18 2021 perl5</span><br/><span class="line">-rw-r--r--. 1 root root    65 12月 11 09:09 result01.txt</span><br/><span class="line">-rw-r--r--. 1 root root 50112 7月  11 21:31 ShiSai2022-1.0-SNAPSHOT.jar</span><br/><span class="line">-rw-r--r--. 1 root root     0 11月 15 2022 spark-yarn-logs</span><br/><span class="line">-rw-r--r--. 1 root root  4175 11月 16 2022 zookeeper.out</span><br/><span class="line">[root@master ~]<span class="comment"># cat result01.txt</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 164 12月 11 08:28 time01.sh</span><br/></pre></td></tr></table></figure><p>把/tmp里面的内容追加到result01.txt中</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ll /tmp</span></span><br/><span class="line">总用量 0</span><br/><span class="line">drwx------. 3 root root 17 12月 11 08:07 systemd-private-03f98bcc8dcb4c7b8b38ca9ae50eaf49-chronyd.service-XdsvpJ</span><br/><span class="line">drwx------. 2 root root  6 12月 11 08:07 vmware-root_8740-2865761114</span><br/><span class="line">[root@master ~]<span class="comment"># ll /tmp &gt;&gt; result01.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># cat result01.txt</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 164 12月 11 08:28 time01.sh</span><br/><span class="line">总用量 0</span><br/><span class="line">drwx------. 3 root root 17 12月 11 08:07 systemd-private-03f98bcc8dcb4c7b8b38ca9ae50eaf49-chronyd.service-XdsvpJ</span><br/><span class="line">drwx------. 2 root root  6 12月 11 08:07 vmware-root_8740-2865761114</span><br/></pre></td></tr></table></figure><p>将文件的输出信息和错误信息保存到result02.txt中</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># date</span></span><br/><span class="line">2023年 12月 11日 星期一 09:15:08 CST</span><br/><span class="line">[root@master ~]<span class="comment"># data</span></span><br/><span class="line">-bash: data: 未找到命令</span><br/><span class="line">[root@master ~]<span class="comment"># data &amp;&gt; result02.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># cat result02.txt</span></span><br/><span class="line">-bash: data: 未找到命令</span><br/><span class="line">[root@master ~]<span class="comment"># date &amp;&gt;&gt; result02.txt</span></span><br/><span class="line">[root@master ~]<span class="comment"># cat result02.txt</span></span><br/><span class="line">-bash: data: 未找到命令</span><br/><span class="line">2023年 12月 11日 星期一 09:16:48 CST</span><br/></pre></td></tr></table></figure><h2 id="课堂练习"><a class="markdownIt-Anchor" href="#课堂练习"></a> 课堂练习：</h2><ol><li>在/opt下建立文件夹/opt/bbb，并将该文件夹写入工作环境文件/etc/profile</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /opt/bbb</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"export PATH=<span class="variable">$PATH</span>:/opt/bbb"</span> &gt;&gt; /etc/profile</span><br/></pre></td></tr></table></figure><ol start="2"><li>在/opt/bbb中建立一个可执行文件hello.sh,可以向屏幕中打印一行hello world字符</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"echo "</span>hello world<span class="string">""</span> &gt;&gt; /opt/bbb/hello.sh</span><br/></pre></td></tr></table></figure><ol start="3"><li>生效修改的工作环境文件/etc/profile</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /etc/profile</span><br/></pre></td></tr></table></figure><ol start="4"><li>在/root目录中直接输入hello.sh进行验证</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /root</span><br/><span class="line">sh hello.sh</span><br/></pre></td></tr></table></figure><ol start="5"><li>用重定向符号将hello.sh的结果保存到/root/result001.txt中</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">sh hello.sh &gt;&gt; /root/result001.txt</span><br/></pre></td></tr></table></figure><ol start="6"><li>打印/root/result001.txt</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /root/result001.txt</span><br/></pre></td></tr></table></figure><ol start="7"><li>用grep命令在/root/result001.txt中查找world字符</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep world /root/result001.txt</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux环境设置" href="http://blog.imc.re/archives/1ba9.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux环境设置</span><span class="cap link fs12">http://blog.imc.re/archives/1ba9.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Linux变量使用</title>
    <link href="https://blog.imc.re/RSSBOX/rss/d28565de.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/d28565de.html</id>
    <published>2023-12-04T06:13:54.000Z</published>
    <updated>2023-12-04T06:13:54.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="linux变量使用"><a class="markdownIt-Anchor" href="#linux变量使用"></a> Linux变量使用</h1><ol><li>变量的定义与引用，用=进行定义，用$进行引用</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># name=zhangsan</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo $name</span></span><br/><span class="line">zhangsan</span><br/><span class="line">[root@master ~]<span class="comment"># echo name</span></span><br/><span class="line">name</span><br/></pre></td></tr></table></figure><p>$在单引号中不能被识别，在双引号中可识别</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo "I am $name"</span></span><br/><span class="line">I am zhangsan</span><br/><span class="line">[root@master ~]<span class="comment"># echo 'I am $name'</span></span><br/><span class="line">I am <span class="variable">$name</span></span><br/></pre></td></tr></table></figure><ol start="2"><li>环境变量</li></ol><p>PATH环境变量：寻找可执行文件的搜索路径</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo $PATH</span></span><br/><span class="line">/root/perl5/bin:/root/perl5/bin:/opt/kafka_2.11-2.0.0/bin:/opt/zookeeper-3.4.12/bin:/opt/flink-1.10.2/bin:/opt/spark-2.1.1-bin-hadoop2.7//bin:/opt/apache-hive-2.3.4-bin/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/hadoop-2.7.7/bin:/opt/hadoop-2.7.7/sbin:/usr/java/jdk1.8.0_162/bin:/usr/java/jdk1.8.0_162/jre/bin:/opt/scala-2.11.0/bin:/opt/apache-flume-1.7.0-bin/bin:/root/bin</span><br/></pre></td></tr></table></figure><p>PWD：当前工作目录</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo $PWD</span></span><br/><span class="line">/root</span><br/></pre></td></tr></table></figure><p>PS1和PS2：命令行的一级提示符和二级提示符</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/><span class="line">17</span><br/><span class="line">18</span><br/><span class="line">19</span><br/><span class="line">20</span><br/><span class="line">21</span><br/><span class="line">22</span><br/><span class="line">23</span><br/><span class="line">24</span><br/><span class="line">25</span><br/><span class="line">26</span><br/><span class="line">27</span><br/><span class="line">28</span><br/><span class="line">29</span><br/><span class="line">30</span><br/><span class="line">31</span><br/><span class="line">32</span><br/><span class="line">33</span><br/><span class="line">34</span><br/><span class="line">35</span><br/><span class="line">36</span><br/><span class="line">37</span><br/><span class="line">38</span><br/><span class="line">39</span><br/><span class="line">40</span><br/><span class="line">41</span><br/><span class="line">42</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo $PS1</span></span><br/><span class="line">[\u@\h \W]\$</span><br/><span class="line">[root@master ~]<span class="comment"># echo $PS2</span></span><br/><span class="line">&gt;</span><br/><span class="line"></span><br/><span class="line">[root@master ~]<span class="comment"># echo $PS1</span></span><br/><span class="line">[\u@\h \W]\$</span><br/><span class="line">[root@master ~]<span class="comment"># echo $PS2</span></span><br/><span class="line">&gt;</span><br/><span class="line">[root@master ~]<span class="comment"># mysql -u root -p</span></span><br/><span class="line">Enter password: <span class="comment"># （输入Passwd123！）</span></span><br/><span class="line">Welcome to the MySQL monitor.  Commands end with ; or \g.</span><br/><span class="line">Your MySQL connection <span class="built_in">id</span> is 3</span><br/><span class="line">Server version: 5.7.18 MySQL Community Server (GPL)</span><br/><span class="line"></span><br/><span class="line">Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.</span><br/><span class="line"></span><br/><span class="line">Oracle is a registered trademark of Oracle Corporation and/or its</span><br/><span class="line">affiliates. Other names may be trademarks of their respective</span><br/><span class="line">owners.</span><br/><span class="line"></span><br/><span class="line">Type <span class="string">'help;'</span> or <span class="string">'\h'</span> <span class="keyword">for</span> <span class="built_in">help</span>. Type <span class="string">'\c'</span> to clear the current input statement.</span><br/><span class="line"></span><br/><span class="line">mysql&gt; show databases;</span><br/><span class="line">+--------------------+</span><br/><span class="line">| Database           |</span><br/><span class="line">+--------------------+</span><br/><span class="line">| information_schema |</span><br/><span class="line">| bak                |</span><br/><span class="line">| hive               |</span><br/><span class="line">| mysql              |</span><br/><span class="line">| performance_schema |</span><br/><span class="line">| shtd_result        |</span><br/><span class="line">| shtd_store         |</span><br/><span class="line">| shtd_store01       |</span><br/><span class="line">| sys                |</span><br/><span class="line">+--------------------+</span><br/><span class="line">9 rows <span class="keyword">in</span> <span class="built_in">set</span> (0.02 sec)</span><br/><span class="line"></span><br/><span class="line">mysql&gt; <span class="built_in">exit</span></span><br/><span class="line">Bye</span><br/><span class="line">[root@master ~]<span class="comment">#</span></span><br/></pre></td></tr></table></figure><p>OLDPWD：前一个工作目录</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># ll</span></span><br/><span class="line">总用量 68</span><br/><span class="line">drwxr-xr-x. 4 root root    36 11月 16 2022 aaa</span><br/><span class="line">-rw-------. 1 root root  1257 11月 18 2021 anaconda-ks.cfg</span><br/><span class="line">drwxr-xr-x. 5 root root    39 11月 18 2021 localperl</span><br/><span class="line">-rw-------. 1 root root  1623 7月  11 21:08 nohup.out</span><br/><span class="line">drwxr-xr-x. 5 root root    39 11月 18 2021 perl5</span><br/><span class="line">-rw-r--r--. 1 root root 50112 7月  11 21:31 ShiSai2022-1.0-SNAPSHOT.jar</span><br/><span class="line">-rw-r--r--. 1 root root     0 11月 15 2022 spark-yarn-logs</span><br/><span class="line">-rw-r--r--. 1 root root  4175 11月 16 2022 zookeeper.out</span><br/><span class="line">[root@master ~]<span class="comment"># cd aaa</span></span><br/><span class="line">[root@master aaa]<span class="comment"># echo $PWD</span></span><br/><span class="line">/root/aaa</span><br/><span class="line">[root@master aaa]<span class="comment"># echo $OLDPWD</span></span><br/><span class="line">/root</span><br/></pre></td></tr></table></figure><p>HISTFILE：储存历史命令</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">[root@master aaa]<span class="comment"># echo $HISTFILE</span></span><br/><span class="line">/root/.bash_history</span><br/><span class="line">[root@master aaa]<span class="comment"># vi /root/.bash_history  （退出----按：，按q，按回车键）</span></span><br/><span class="line">[root@master aaa]<span class="comment">#</span></span><br/></pre></td></tr></table></figure><p>HOME:当前用户的用户目录</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># echo $HOME</span></span><br/><span class="line">/root</span><br/></pre></td></tr></table></figure><p>3.PATH环境变量的综合运用</p><p>在PATH环境变量之前加入新的路径，/tmp</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># export PATH=/tmp:$PATH</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo $PATH</span></span><br/><span class="line">/tmp:/root/perl5/bin:/root/perl5/bin:/opt/kafka_2.11-2.0.0/bin:/opt/zookeeper-3.4.12/bin:/opt/flink-1.10.2/bin:/opt/spark-2.1.1-bin-hadoop2.7//bin:/opt/apache-hive-2.3.4-bin/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/hadoop-2.7.7/bin:/opt/hadoop-2.7.7/sbin:/usr/java/jdk1.8.0_162/bin:/usr/java/jdk1.8.0_162/jre/bin:/opt/scala-2.11.0/bin:/opt/apache-flume-1.7.0-bin/bin:/root/bin</span><br/></pre></td></tr></table></figure><p>转到新的路径/tmp下面制造了一个可执行文件hello</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># cd /tmp</span></span><br/><span class="line">[root@master tmp]<span class="comment"># ll</span></span><br/><span class="line">总用量 0</span><br/><span class="line">drwx------. 3 root root 17 12月  4 08:08 systemd-private-29aad2a4b89b4c6b8901f17655036ac6-chronyd.service-IX3I1a</span><br/><span class="line">drwx------. 2 root root  6 12月  4 08:08 vmware-root_8736-2857568991</span><br/><span class="line">[root@master tmp]<span class="comment"># vi hello</span></span><br/><span class="line"><span class="comment"># （按i键，看到屏幕底下有insert字样，此时输入）</span></span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"hello hadoop!"</span> </span><br/><span class="line"><span class="comment"># (按Esc键，屏幕底下的insert字样消失，再按：，按wq，按回车键，此时就保存退出了vi编辑器)</span></span><br/></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/><span class="line">17</span><br/><span class="line">18</span><br/><span class="line">19</span><br/><span class="line">20</span><br/><span class="line">21</span><br/><span class="line">22</span><br/><span class="line">23</span><br/><span class="line">24</span><br/><span class="line">25</span><br/></pre></td><td class="code"><pre><span class="line">[root@master tmp]<span class="comment"># ll hello</span></span><br/><span class="line">-rw-r--r--. 1 root root 21 12月  4 09:00 hello</span><br/><span class="line">[root@master tmp]<span class="comment"># chmod 777 hello </span></span><br/><span class="line">[root@master tmp]<span class="comment"># ll hello</span></span><br/><span class="line">-rwxrwxrwx. 1 root root 21 12月  4 09:00 hello</span><br/><span class="line">[root@master tmp]<span class="comment"># cd /root</span></span><br/><span class="line">[root@master ~]<span class="comment"># echo $PATH</span></span><br/><span class="line">/tmp:/root/perl5/bin:/root/perl5/bin:/opt/kafka_2.11-2.0.0/bin:/opt/zookeeper-3.4.12/bin:/opt/flink-1.10.2/bin:/opt/spark-2.1.1-bin-hadoop2.7//bin:/opt/apache-hive-2.3.4-bin/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/hadoop-2.7.7/bin:/opt/hadoop-2.7.7/sbin:/usr/java/jdk1.8.0_162/bin:/usr/java/jdk1.8.0_162/jre/bin:/opt/scala-2.11.0/bin:/opt/apache-flume-1.7.0-bin/bin:/root/bin</span><br/><span class="line">[root@master ~]<span class="comment"># hello</span></span><br/><span class="line">hello hadoop!</span><br/><span class="line">[root@master ~]<span class="comment"># cd /tmp</span></span><br/><span class="line">[root@master tmp]<span class="comment"># ll</span></span><br/><span class="line">总用量 4</span><br/><span class="line">-rwxrwxrwx. 1 root root 21 12月  4 09:00 hello</span><br/><span class="line">drwx------. 3 root root 17 12月  4 08:08 systemd-private-29aad2a4b89b4c6b8901f17655036ac6-chronyd.service-IX3I1a</span><br/><span class="line">drwx------. 2 root root  6 12月  4 08:08 vmware-root_8736-2857568991</span><br/><span class="line">[root@master tmp]<span class="comment"># rm hello</span></span><br/><span class="line"><span class="built_in">rm</span>：是否删除普通文件 <span class="string">"hello"</span>？y</span><br/><span class="line">[root@master tmp]<span class="comment"># ll</span></span><br/><span class="line">总用量 0</span><br/><span class="line">drwx------. 3 root root 17 12月  4 08:08 systemd-private-29aad2a4b89b4c6b8901f17655036ac6-chronyd.service-IX3I1a</span><br/><span class="line">drwx------. 2 root root  6 12月  4 08:08 vmware-root_8736-2857568991</span><br/><span class="line">[root@master tmp]<span class="comment"># cd /root</span></span><br/><span class="line">[root@master ~]<span class="comment"># hello</span></span><br/><span class="line">-bash: /tmp/hello: 没有那个文件或目录</span><br/></pre></td></tr></table></figure><h2 id="课堂练习"><a class="markdownIt-Anchor" href="#课堂练习"></a> 课堂练习</h2><p>（要求所有的命令均使用全局路径，将结果截图粘贴到桌面Release下面的word文件“模块A提交的结果”）：</p><ol><li>在根目录下面建立文件夹/bbb</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /bbb</span><br/></pre></td></tr></table></figure><ol start="2"><li>在文件夹/bbb中建立文件hi.sh</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> /bbb/hi.sh</span><br/></pre></td></tr></table></figure><ol start="3"><li>在文件/bbb/hi.sh中，用vi编辑器输入10秒倒计时程序如下：</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/></pre></td><td class="code"><pre><span class="line">vi /bbb/hi.sh</span><br/><span class="line"><span class="comment"># 点击 i 键 进入 insert 编辑模式</span></span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----start----"</span></span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----10----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----9----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----8----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----7----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----6----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----5----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----4----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----3----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----2----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----1----"</span>;<span class="built_in">sleep</span> 1;</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"----launch!----"</span></span><br/></pre></td></tr></table></figure><pre><code>保存并退出。(点击Esc退出insert编辑模式后输入 `:wq` )</code></pre><ol start="4"><li>设置hi.sh文件为可执行文件</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x /bbb/hi.sh</span><br/></pre></td></tr></table></figure><ol start="5"><li>把/bbb路径添加在PATH环境变量中，并生效</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">echo "PATH=\$PATH:/bbb" &gt;&gt; /etc/profile</span><br/><span class="line">source /etc/profile</span><br/></pre></td></tr></table></figure><ol start="6"><li>在系统任意位置，执行hi.sh命令，将结果粘贴。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/></pre></td><td class="code"><pre><span class="line">[root@MySQL01 ~]<span class="comment"># sh hi.sh</span></span><br/><span class="line">----start----</span><br/><span class="line">----10----</span><br/><span class="line">----9----</span><br/><span class="line">----8----</span><br/><span class="line">----7----</span><br/><span class="line">----6----</span><br/><span class="line">----5----</span><br/><span class="line">----4----</span><br/><span class="line">----3----</span><br/><span class="line">----2----</span><br/><span class="line">----1----</span><br/><span class="line">----launch!----</span><br/><span class="line">[root@MySQL01 ~]<span class="comment"># </span></span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux变量使用" href="http://blog.imc.re/archives/43a5.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux变量使用</span><span class="cap link fs12">http://blog.imc.re/archives/43a5.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>1736543577.3773503</title>
    <link href="https://blog.imc.re/RSSBOX/rss/19a0ef13.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/19a0ef13.html</id>
    <published>2023-12-02T21:59:00.000Z</published>
    <updated>2023-12-02T21:59:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p><svg style="width: 50px; margin: 0 auto; display: block;" viewbox="0 0 640 512" xmlns="http://www.w3.org/2000/svg"><defs><style>.fa-secondary&#123;opacity:.4&#125;</style></defs><path class="fa-secondary" d="M64 240a64 64 0 1 0 64 64 64.06 64.06 0 0 0-64-64zm88 80h48v-32h-48zm294.4-106.8l19.2 25.6 48-36-19.2-25.6zM576 64a64 64 0 1 0 64 64 64.06 64.06 0 0 0-64-64z"></path><path class="fa-primary" d="M576 384a63.84 63.84 0 0 0-38.3 13l-96-57.6a109.91 109.91 0 0 0 6.3-35.5 111.94 111.94 0 0 0-112-112 108.64 108.64 0 0 0-24.4 2.9l-40.8-87.4A63.84 63.84 0 1 0 224 128c1.1 0 2.1-.3 3.2-.3l41 87.8C241.5 235.9 224 267.8 224 304a111.71 111.71 0 0 0 193.2 76.7l95.8 57.5a63.87 63.87 0 1 0 63-54.2zm-240-32a48 48 0 1 1 48-48 48 48 0 0 1-48 48z"></path></svg></p><p><span class="p logo center large">数据通信网络</span></p><br/><h1 hidden="">数据通信网络</h1><br/><span class="btn solid large center"><a class="button" href="/notes/datacom/" title="开始阅读"><i class="fa-duotone fa-chart-network"></i>开始阅读</a></span><br/></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="1736543577.3773503" href="https://blog.mhuig.top/p/notes-datacom/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">1736543577.3773503</span><span class="cap link fs12">https://blog.mhuig.top/p/notes-datacom/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>Linux综合练习</title>
    <link href="https://blog.imc.re/RSSBOX/rss/2ac8394e.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/2ac8394e.html</id>
    <published>2023-11-28T06:12:13.000Z</published>
    <updated>2023-11-28T06:12:13.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h2 id="linux综合课堂练习"><a class="markdownIt-Anchor" href="#linux综合课堂练习"></a> Linux综合课堂练习</h2><p>将命令和结果粘贴在桌面的release目录下，模块A提交的结果文件中。要求命令参数文件路径使用绝对路径。</p><ol><li>建立文件夹/aaa/a01</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /aaa/a01</span><br/></pre></td></tr></table></figure><ol start="2"><li>转移到/aaa/a01目录下，并显示当前路径</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /aaa/a01 &amp;&amp; <span class="built_in">pwd</span></span><br/></pre></td></tr></table></figure><ol start="3"><li>在文件夹/aaa/a01下新建文件myHadoop01.txt，内容为：Hello HadoopHello HDFSHello spark</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt;&gt; /aaa/a01/myHadoop01.txt &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">Hello Hadoop</span></span><br/><span class="line"><span class="string">Hello HDFS</span></span><br/><span class="line"><span class="string">Hello spark</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="5"><li>新建文件夹/bbb/b01</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /bbb/b01</span><br/></pre></td></tr></table></figure><ol start="6"><li>将文件/aaa/a01/myHadoop01.txt，复制到/bbb/b01目录下，并改名为myHadoop02.txt。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /aaa/a01/myHadoop01.txt /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="7"><li>在/bbb/b01/myHadoop02.txt末尾，新增加一行内容：Hello Yarn</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"Hello Yarn"</span> &gt;&gt; /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="8"><li>比较/aaa/a01/myHadoop01.txt和/bbb/b01/myHadoop02.txt的不同之处。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">diff /aaa/a01/myHadoop01.txt /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="9"><li>打印/aaa/a01/myHadoop01.txt的前两行内容。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> -n 2 /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="10"><li>打印/bbb/b01/myHadoop02.txt的最后1行内容。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> -n 1 /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="11"><li>将文件夹/aaa，拷贝为/ccc</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> -r /aaa /ccc</span><br/></pre></td></tr></table></figure><ol start="12"><li>删除/ccc/a01/myHadoop01.txt文件。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> /ccc/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="13"><li>分别删除文件夹/ccc/a01，/ccc</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">rmdir</span> /ccc/a01</span><br/><span class="line"><span class="built_in">rmdir</span> /ccc</span><br/></pre></td></tr></table></figure><ol start="14"><li>为文件/aaa/a01/myHadoop01.txt，建立软连接/aaa/a01/myHadoop</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">ln</span> -s /aaa/a01/myHadoop01.txt /aaa/a01/myHadoop</span><br/></pre></td></tr></table></figure><ol start="15"><li>用tar命令将/bbb/b01/myHadoop02.txt压缩为/bbb/b01/myHadoop02.tar.tz</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /bbb/b01</span><br/><span class="line">tar cvzf myHadoop02.tar.tz myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="16"><li>查找电脑中所有以myHadoop字符开头的文件。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name <span class="string">"myHadoop*"</span></span><br/></pre></td></tr></table></figure><ol start="17"><li>查找/aaa/a01/myHadoop01.txt中所有包含Hadoop的行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep <span class="string">"Hadoop"</span> /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="18"><li>显示/aaa/a01/myHadoop01.txt的属性，并用文字说明该文件的文件所有者、同组用户、其他用户分别具有什么权限。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line">root@RC:/<span class="comment"># ll /aaa/a01/</span></span><br/><span class="line">总用量 12</span><br/><span class="line">drwxr-xr-x 2 root root 4096 11月 28 08:12 ./</span><br/><span class="line">drwxr-xr-x 3 aaa  root 4096 11月 28 08:04 ../</span><br/><span class="line">lrwxrwxrwx 1 root root   23 11月 28 08:12 myHadoop01 -&gt; /aaa/a01/myHadoop01.txt*</span><br/><span class="line">-rw-r--r-- 1 root root   36 11月 28 08:07 myHadoop01.txt*</span><br/></pre></td></tr></table></figure><ul><li>文件所有者：读写权限</li><li>同组用户：读权限</li><li>其他用户：读权限</li></ul><ol start="19"><li>用数字的方式，将myHadoop01.txt的权限设置为文件所有者可读不可写可执行，同组用户只可读，其他用户只可执行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 541 /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="20"><li>用字母的方式，将myHadoop01.txt的权限设置为一切用户均可读可写可执行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> a=rwx /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="21"><li>新建用户aaa</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">useradd aaa</span><br/></pre></td></tr></table></figure><ol start="22"><li>将文件夹/aaa的所有者设置为aaa用户，并显示/aaa的属性</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> aaa /aaa</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux综合练习" href="http://blog.imc.re/archives/d4fd.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux综合练习</span><span class="cap link fs12">http://blog.imc.re/archives/d4fd.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Linux 权限操作</title>
    <link href="https://blog.imc.re/RSSBOX/rss/2b561629.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/2b561629.html</id>
    <published>2023-11-27T06:11:32.000Z</published>
    <updated>2023-11-27T06:11:32.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="linux-权限操作"><a class="markdownIt-Anchor" href="#linux-权限操作"></a> Linux 权限操作</h1><p>1.用字母的方式改变权限用u表示文件所有者，g表示同组用户，o表示其他用户用r表示可读，用w表示可写，用x表示可执行，文件的权限就可以表示为字母等式的组合</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># touch a01.txt</span></span><br/></pre></td></tr></table></figure><p>使文件所有者具有可读可写可执行：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod u=rwx a01.txt</span></span><br/></pre></td></tr></table></figure><p>使同组用户和其他用户可读不可写可执行：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod go=rx a01.txt</span></span><br/></pre></td></tr></table></figure><p>在原来的基础上，为同组用户增加可写属性：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod g+w a01.txt</span></span><br/></pre></td></tr></table></figure><p>在原来的基础上，收回其他用户可执行的属性：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod o-x a01.txt</span></span><br/></pre></td></tr></table></figure><p>文件所有者可读不可写可执行，同组用户收回可写属性，其他用户增加可写属性：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chmod u=rx,g-w,o+w a01.txt</span></span><br/></pre></td></tr></table></figure><p>2.修改文件的所有者与所属组chown</p><p>增加用户aaa：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># useradd aaa</span></span><br/></pre></td></tr></table></figure><p>将文件a01.txt的所有者改为aaa：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">[root@master ~]<span class="comment"># chown aaa a01.txt </span></span><br/><span class="line">[root@master ~]<span class="comment"># ll a01.txt</span></span><br/><span class="line">-r-xr-xrw-. 1 aaa root 0 11月 27 08:15 a01.txt</span><br/></pre></td></tr></table></figure><h2 id="linux权限数字表达"><a class="markdownIt-Anchor" href="#linux权限数字表达"></a> Linux权限数字表达</h2><blockquote><p>由 <a href="https://chatglm.cn">智谱清言</a> 生成回答, 可能含有不正确的内容, 如有错误欢迎指正.</p></blockquote><p>在Linux中，文件和目录的权限可以用数字来表示，这些数字对应于权限的读（r）、写（w）和执行（x）。以下是各个权限对应的数字：</p><ul><li>读（r）：4</li><li>写（w）：2</li><li>执行（x）：1</li></ul><p>无权限（-）对应的数字是0。权限的设置是通过组合这些数字来实现的。例如，读和执行权限的组合（r-x）对应的数字是5（4+1），读和写权限的组合（rw-）对应的数字是6（4+2）。</p><p>在Linux中，权限的设置通常遵循以下模式：</p><ul><li>第一位数字：文件所有者的权限</li><li>第二位数字：文件所属组的权限</li><li>第三位数字：其他用户的权限</li></ul><p>例如，权限模式755表示：</p><ul><li>所有者（owner）：7（读、写、执行权限）</li><li>组（group）：5（读、执行权限，无写权限）</li><li>其他用户（others）：5（读、执行权限，无写权限）</li></ul><p>在Linux中，还有一些特殊的权限设置：</p><ul><li>600（rw-------）：所有者有读写权限，组和其他用户无权限。</li><li>644（rw-r--r--）：所有者有读写权限，组和其他用户只有读权限。</li><li>666（rw-rw-rw-）：所有者有读写权限，组和其他用户也有读写权限（但通常不会同时给予）。</li><li>700（rwx------）：所有者有读写执行权限，组和其他用户无权限。</li><li>744（rwxr--r--）：所有者有读写执行权限，组和其他用户只有读权限。</li><li>755（rwxr-xr-x）：所有者有读写执行权限，组和其他用户有读和执行权限，但无写权限。</li><li>777（rwxrwxrwx）：所有者有读写执行权限，组和其他用户也有读写执行权限（但通常不会同时给予）。在实际操作中，可以使用<code>chmod</code>命令来设置或修改文件和目录的权限。例如：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 755 file.txt</span><br/></pre></td></tr></table></figure><p>这个命令会将文件<code>file.txt</code>的权限设置为所有者可读写执行，组和其他用户可读执行。</p><h2 id="课堂练习"><a class="markdownIt-Anchor" href="#课堂练习"></a> 课堂练习：</h2><p>将命令和结果粘贴在桌面的release目录下，模块A提交的结果文件中。要求命令参数文件路径使用绝对路径。</p><ol><li>建立文件夹/aaa/a01</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /aaa/a01</span><br/></pre></td></tr></table></figure><ol start="2"><li>转移到/aaa/a01目录下，并显示当前路径</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /aaa/a01 &amp;&amp; <span class="built_in">pwd</span></span><br/></pre></td></tr></table></figure><ol start="3"><li>在文件夹/aaa/a01下新建文件myHadoop01.txt，内容为：Hello HadoopHello HDFSHello spark</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt;&gt; /aaa/a01/myHadoop01.txt &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">Hello Hadoop</span></span><br/><span class="line"><span class="string">Hello HDFS</span></span><br/><span class="line"><span class="string">Hello spark</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="4"><li>新建文件夹/bbb/b01</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /bbb/b01</span><br/></pre></td></tr></table></figure><ol start="5"><li>将文件/aaa/a01/myHadoop01.txt，复制到/bbb/b01目录下，并改名为myHadoop02.txt。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /aaa/a01/myHadoop01.txt /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="6"><li>在/bbb/b01/myHadoop02.txt末尾，新增加一行内容：Hello Yarn</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"Hello Yarn"</span> &gt;&gt; /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="7"><li>比较/aaa/a01/myHadoop01.txt和/bbb/b01/myHadoop02.txt的不同之处。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">diff /aaa/a01/myHadoop01.txt /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="8"><li>打印/aaa/a01/myHadoop01.txt的前两行内容。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> -n 2 /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="9"><li>打印/bbb/b01/myHadoop02.txt的最后1行内容。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> -n 1 /bbb/b01/myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="10"><li>将文件夹/aaa，拷贝为/ccc</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">cp -r /aaa /ccc</span><br/></pre></td></tr></table></figure><ol start="11"><li>删除/ccc/a01/myHadoop01.txt文件。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -rf /ccc/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="12"><li>分别删除文件夹/ccc/a01，/ccc</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">rmdir</span> /ccc/a01</span><br/><span class="line"><span class="built_in">rmdir</span> /ccc</span><br/></pre></td></tr></table></figure><ol start="13"><li>为文件/aaa/a01/myHadoop01.txt，建立软连接/aaa/a01/myHadoop</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">ln</span> -s /aaa/a01/myHadoop01.txt /aaa/a01/myHadoop</span><br/></pre></td></tr></table></figure><ol start="14"><li>用tar命令将/bbb/b01/myHadoop02.txt压缩为/bbb/b01/myHadoop02.tar.tz</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">tar -C /bbb/b01/ -czvf /bbb/b01/myHadoop02.tar.tz myHadoop02.txt</span><br/></pre></td></tr></table></figure><ol start="15"><li>查找电脑中所有以myHadoop字符开头的文件。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name myHadoop*</span><br/></pre></td></tr></table></figure><ol start="16"><li>查找/aaa/a01/myHadoop01.txt中所有包含Hadoop的行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep <span class="string">"Hadoop"</span> /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="17"><li>显示/aaa/a01/myHadoop01.txt的属性，并用文字说明该文件的文件所有者、同组用户、其他用户分别具有什么权限。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">[root@MySQL01 aaa]<span class="comment"># ll /aaa/a01/myHadoop01.txt</span></span><br/><span class="line">-rw-r--r--. 1 root root 36 1月   1 12:48 /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ul><li>文件所有者: 读写权限</li><li>同组用户,其他用户: 读权限</li></ul><ol start="18"><li>用数字的方式，将myHadoop01.txt的权限设置为文件所有者可读不可写可执行，同组用户只可读，其他用户只可执行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 541 /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="19"><li>用字母的方式，将myHadoop01.txt的权限设置为一切用户均可读可写可执行。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> a=rwx /aaa/a01/myHadoop01.txt</span><br/></pre></td></tr></table></figure><ol start="20"><li>新建用户aaa</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">useradd aaa</span><br/></pre></td></tr></table></figure><ol start="21"><li>将文件夹/aaa的所有者设置为aaa用户，并显示/aaa的属性</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> aaa /aaa &amp;&amp; <span class="built_in">stat</span> /aaa</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux 权限操作" href="http://blog.imc.re/archives/e5ff.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux 权限操作</span><span class="cap link fs12">http://blog.imc.re/archives/e5ff.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Linux查找作业解析</title>
    <link href="https://blog.imc.re/RSSBOX/rss/579d1b0.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/579d1b0.html</id>
    <published>2023-11-20T17:03:53.000Z</published>
    <updated>2023-11-20T17:03:53.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="linux查找作业解析"><a class="markdownIt-Anchor" href="#linux查找作业解析"></a> Linux查找作业解析</h1><blockquote><p>Linux 20231121 复习内容</p></blockquote><h2 id="课堂练习"><a class="markdownIt-Anchor" href="#课堂练习"></a> 课堂练习：</h2><p>把hadoop01镜像转到20230912，并启动hadoop01，用Ubuntu进行联机。完成下面的操作，并把命令和结果截图粘贴到ubuntu桌面下的目录Release的“模块A提交的结果.docx”。要求所有命令均使用绝对路径。</p><ol><li>在/root目录下建立子目录bbb</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /root/bbb</span><br/></pre></td></tr></table></figure><ol start="2"><li>在/root/bbb目录下建立文件b01.txt</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="3"><li><p>在b01.txt中插入以下内容：</p><p>Hello HadoopHello hdfsHello sparkHello flinkHello yarnHello hbase</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"Hello Hadoop"</span> &gt;&gt; /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello hdfs"</span> &gt;&gt; /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello spark"</span> &gt;&gt; /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello flink"</span> &gt;&gt; /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello yarn"</span> &gt;&gt; /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello hbase"</span> &gt;&gt; /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="4"><li><p>将b01.txt拷贝为b02.txt，并在b02.txt中新增两行内容：</p><p>Hello RedisHello clickhouse</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /root/bbb/b01.txt /root/bbb/b02.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello Redis"</span> &gt;&gt; /root/bbb/b02.txt</span><br/><span class="line"><span class="built_in">echo</span> <span class="string">"Hello clickhouse"</span> &gt;&gt; /root/bbb/b02.txt</span><br/></pre></td></tr></table></figure><ol start="5"><li>用diff命令比较b01.txt、b02.txt的不同之处</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">diff /root/bbb/b01.txt /root/bbb/b02.txt</span><br/></pre></td></tr></table></figure><ol start="6"><li>用grep命令查找b01.txt中含有flink的行</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">grep flink /root/bbb/b01.txt</span><br/></pre></td></tr></table></figure><ol start="7"><li>修改/root/bbb/b01.txt的权限：文件所有者可读可写可执行，同组用户可读可写不可执行，其他用户不可读不可写不可执行，并用ls命令查看结果</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 760 /root/bbb/b01.txt</span><br/><span class="line"><span class="built_in">ls</span></span><br/></pre></td></tr></table></figure><ol start="8"><li>修改/root/bbb/b02.txt的权限：文件所有者可读不可写可执行，同组用户可读不可写不可执行，其他用户不可读不可写可执行，并用ls命令查看结果</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 541 /root/bbb/b02.txt</span><br/><span class="line"><span class="built_in">ls</span></span><br/></pre></td></tr></table></figure><ol start="9"><li>用find命令查找b01.txt文件的位置</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name b01.txt</span><br/></pre></td></tr></table></figure><ol start="10"><li>用whereis命令查找grep命令文件的位置</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">whereis grep</span><br/></pre></td></tr></table></figure><ol start="11"><li>用tar命令将到/opt/hadoop-2.7.7.tar.gz解压到/usr/local/src下面。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">tar -xvzf /opt/hadoop-2.7.7.tar.gz -C /usr/local/src</span><br/></pre></td></tr></table></figure><ol start="12"><li>用find命令查找文件stop-all.sh的位置。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">find / -name stop-all.sh</span><br/></pre></td></tr></table></figure><h2 id="课后笔记"><a class="markdownIt-Anchor" href="#课后笔记"></a> 课后笔记</h2><p>关于上述题目同学们有部分易错点，在此记录：</p><ol><li><strong>绝对路径和相对路径的概念还是不熟悉</strong>：绝对路径是以 <code>/</code> 开头，代表从根目录 <code>/</code> 开始。相对目录为 <code>./</code> 或者不加前缀。例：假设当前目录为<code>/root</code> ， <code>/bbb</code> 就是以根目录开始，与 <code>/root</code> 同级，如果是 <code>aaa</code> 或者 <code>./bbb</code> 就是在当前文件夹下 <code>/root</code> 创建，绝对路径为 <code>/root/aaa</code> <code>/root/bbb</code></li></ol><p><img alt="linux files tree" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/20240102012337.png"/></p><ol start="2"><li><p><strong>echo的用法掌握不熟练</strong>：echo的指令根据格式不同会有不同的功能，<code>echo "Hello Hadoop &gt; a.txt"</code> 是将 <code>a.txt</code> 中的文件内容替换覆盖为指定内容，而 <code>echo "Hello Hadoop &gt;&gt; a.txt"</code> 是在 <code>a.txt</code> 中的文件末尾添加内容，区别为 <code>&gt;</code> 覆盖，<code>&gt;&gt;</code> 添加，<strong>使用错误会让文件内容全部消失，切记！</strong></p></li><li><p><strong>创建文件命令混淆</strong>： 创建文件夹的命令为 <code>mkdir</code> ，创建文件的命令为 <code>touch</code>，一个是文件夹，一个是文件，不要搞混。如果搞混后需要删除使用如下指令：<code>rmdir</code> 删除文件夹，<code>rm</code> 删除文件</p></li><li><p><strong>权限设置内容</strong>：可以参考：<a href="https://www.runoob.com/linux/linux-comm-chmod.html">Linux chmod命令</a></p></li></ol><h2 id="扩展内容"><a class="markdownIt-Anchor" href="#扩展内容"></a> 扩展内容：</h2><blockquote><p>如果认为上述操作太过简单，可以参考下方扩展内容增加效率</p></blockquote><ol><li>使用 <code>cat</code> 命令插入多行内容（以第4题为例）：</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt;&gt; /root/bbb/b01.txt &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">Hello Hadoop</span></span><br/><span class="line"><span class="string">Hello hdfs</span></span><br/><span class="line"><span class="string">Hello spark</span></span><br/><span class="line"><span class="string">Hello flink</span></span><br/><span class="line"><span class="string">Hello yarn</span></span><br/><span class="line"><span class="string">Hello hbase</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="2"><li>使用 <code>history</code> 命令查看历史执行指令（可以用于回滚查找操作截图，但是只有命令，没有输出）</li></ol></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Linux查找作业解析" href="http://blog.imc.re/archives/d40e.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Linux查找作业解析</span><span class="cap link fs12">http://blog.imc.re/archives/d40e.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>中慧1+X证书真题</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f04fdde.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f04fdde.html</id>
    <published>2023-10-31T09:44:40.000Z</published>
    <updated>2023-10-31T09:44:40.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><p>所属院校：厦门南洋职业学院</p><h2 id="2022年python-1x中级考试真题理论"><a class="markdownIt-Anchor" href="#2022年python-1x中级考试真题理论"></a> 2022年Python 1+X中级考试真题(理论)</h2><h3 id="单选题"><a class="markdownIt-Anchor" href="#单选题"></a> 单选题</h3><p>每小题2分，共60 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django模板的变量名在HTML中用（    ）定义。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：[[   ]]</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：&#123;&#123;   &#125;&#125;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：&#123;  &#125;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：[  ]</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">爬虫代理的可以编写为（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：参数是一个序列&#123;'类型'：'代理ip：端口号'&#125;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：参数是一个字典&#123;'类型'：'代理ip：端口号'&#125;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：参数是一个字典&#123;'属性'：'代理ip：端口号'&#125;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：参数是一个序列&#123;'属性'：'代理ip：端口号'&#125;</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于MongoDB数据库，下列说法不正确的是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：MongoDB是关系型数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：MongoDB是一个基于分布式文件存储的数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：MongoDB数据库中每个文档都有_id字段</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：MongoDB数据库支持海量数据存储</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">下列关于Navicat说法，错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：支持SQL Server数据库可视化管理</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：是一种NoSQL数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：支持MySQL数据库可视化管理</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：支持MongoDB数据库可视化管理</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">itempipeline的一些典型应用不包括（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：验证爬取的数据（检查item包含某些分段）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：将爬取结果保存到数据库中</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：整理HTML、CSS和JS内容</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：查重</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">在MySQL数据库中，以下能够删除一列的是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：alter table user delete age</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：alter table user drop column age</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：alter table user delete column age</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：alter table user remove age</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">对于MySQL的一个学生表，其生日用以下哪种数据类型更合适（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：DATE</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：DATETIME</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：YEAR</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：TIMESTAMP</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">查询MySQL数据库World中的country表的前10条记录，显示“Name”、“Region”两个字段，下列正确的SQL语句是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：SELECT Name,Region FROM country LIMIT 10</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：SELECT * FROM WorldLIMIT 10</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：SELECT top 100 * FROM `country`</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：DELETE FROM country WHERE Name&gt;10</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django创建名为TestModel应用的语法是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：python manage.py makemigrations TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：django-admin startproject TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：python manage.py migrate TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：python manage.py startapp TestModel</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Scrapy-redis提供了四种组件，其中不包括（     ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：Scheduler</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：Item Pipeline</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：Base Spider</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：Mutiple Filter</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>11</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB切换数据库的命令是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：find</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：use</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：enter</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：select</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>12</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">ORM的Models类对应于数据库的（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：属性</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：一条记录</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：数据表</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：字段</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>13</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB数据库集合的find()命令，如果未指定查询参数，则（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：执行命令时会报错</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：读取数据库集合的所有记录</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：读取数据库集合的第一条记录</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：返回nil</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>14</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">提高Selenium脚本的执行速度描述中错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：优化代码</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：对于firefox浏览器，考虑使用测试专用的profile，因为每次启动浏览器的时候firefox会创建1个新的profile，对于这个新的profile，所有的静态资源都是从服务器直接下载，而不是从缓存里加载，这就导致网络不好的时候用例运行速度特别慢的问题</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：使用更高配置的电脑和选择更快的网络环境</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：可以随便加sleep，使用显式等待</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>15</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Selenium中没有提供原生的方法判断元素是否存在，一般我们可以通过（    ）判断。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：定位元素+异常捕获</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：定位属性+非空</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：定位元素+非空</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：定位属性+异常捕获</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>16</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">一般网站从三个方面反爬虫，其中不包括（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：用户行为</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：网站目录和数据加载方式</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：用户点击网页</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：用户请求的Headers</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>17</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">SELECT语句的完整语法比较复杂，但至少包含以下哪个部分（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：SELECT，GROUP</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：SELECT，INTO</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：SELECT，FROM</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：仅SELECT</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>18</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQL数据库中，以下聚合函数求数据总和的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：AVG</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：COUNT</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：MAX</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：SUM</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>19</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQL数值型数据类型中有符号TINYINT的范围是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：(0，255)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：(-128，127)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：(0，65 535)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：(-32 768，32 767)</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>20</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">当生成一个spider继承redisspider时，会调用setup_redis函数，这个函数回去连接redis数据库，然后会设置（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：response</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：singals信号</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：token信令</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：request请求</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>21</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">反爬虫应对策略不包含下列哪项？(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：反爬虫自己会好的</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：设置延迟爬虫sleep()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：更换爬虫IP</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：添加headers信息</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>22</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">向一个尚不存在的MongoDB数据库集合执行插入文档操作，下列说法正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：返回false</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：插入成功，自动创建集合</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：返回nil</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：导致报错</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>23</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB命令dB. CollectionName.remove(&#123;key:value&#125;, &#123;justOne&#125;)的作用是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：删除集合CollectionName下的一条文档</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：查询集合CollectionName下的一条文档，并移动到justOne集合中</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：删除名为CollectionName的集合</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：删除集合CollectionName下的所有文档</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>24</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django请求对象属性中用于获取当前请求方式的关键字是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：path</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：body</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：method</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：POST</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>25</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">要启用spider中间件，您可以将其加入到 SPIDER_MIDDLEWARES 设置中。该设置是一个（    ），键为中间件的路径，值为中间件的顺序(order)。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：堆栈</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：item</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：字典</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：队列</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>26</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">元素找不到可能的原因不包括（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：动态id定位不到元素</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：在同一个iframe中查找元素</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：xpath描述错误</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：iframe原因定位不到元素</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>27</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB服务器默认端口是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：27017</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：8080</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：6379</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：3306</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>28</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">以下哪个不属于Scrapy框架的优点？（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：它由Spiders、ItemPipeline、Downloader、Scoop组成</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：它更容易构建大规模的抓取项目</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：它异步处理请求，速度非常快</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：它可以使用自动调节机制自动调整爬行速度</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>29</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">使用“CREATE TABLE”语句创建MySQL数据库的表，下列说法正确的是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：如果指定创建的表已经存在，则SQL语句执行失败</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：不能在两个不同的数据库里创建相同名称的表</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：创建数据库表时，不能指定主键</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：如果指定创建的表已经存在，则覆盖原有表</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>30</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">SQL语句中的条件查询用以下拿一项（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：THEN</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：WHERE</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：WHILE</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：IF</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><h3 id="多选题"><a class="markdownIt-Anchor" href="#多选题"></a> 多选题</h3><p>每小题2分，共20 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">如果AppModel是一个Django模型类，则修改数据的方法正确的有（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">A：a1 = AppModel.objects.get(id=1)</span><br/><span class="line">a1.name = ‘zhangsan’</span><br/><span class="line">a1.save()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：AppModel.objects.all().modify(name=’abc’)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：AppModel.objects.all().update(name=’wangwu’)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：AppModel.objects.filter(id=1).update(name=’lisi’)</span><br/></pre></td></tr></table></figure><p>答案：A,C,D</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">以下对Django MVT模式解释正确的是（）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：V全拼为View，用于模本渲染，生成页面展示的HTML内容。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：M全拼为Model，与MVC中的M功能相同，负责和数据库交互。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：V全拼为View，与MVC中的C功能相同，接收请求，返回响应。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：T全拼为Template，与MVC中的V功能相同，负责封装构造渲染需要返回的HTML页面。</span><br/></pre></td></tr></table></figure><p>答案：B,C,D</p><p>问题解析：Na</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">下列关于xpath表达式描述正确的有（）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：//title[@lang = 'en'] 选取拥有lang属性并且值为‘en’的所有title元素。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：//bookstore/book[position()&lt;3] 选取最前面的三个属于bookstore元素的子元素的book元素。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：//bookstore/book[last()-1] 选取属于bookstore子元素的倒数第二个book元素。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：//bookstore/book[1] 选取属于bookstore子元素的第二个book元素。</span><br/></pre></td></tr></table></figure><p>答案：A,C</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django中的redirect()的参数可以是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：一个绝对的或相对的URL，将原封不动的作为重定向的位置</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：一个视图，可以带有参数：将使用urlresolvers.reverse 来反向解析名称</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：一个元组，元组内是一系列URL</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：一个列表，列表内存放的是一系列的URL</span><br/></pre></td></tr></table></figure><p>答案：A,B</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django路由中的path()和re_path()函数的描述正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：path()函数如果手动添加正则首位限制符号也可用于正则路径</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：path()函数用于普通路径</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：path()函数和Django 1.1.x版本的url()函数用法相同</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：re_path()函数用于正则路径</span><br/></pre></td></tr></table></figure><p>答案：B,D</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django模板取值的方法正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：在模板中取出列表某个元素可以使用下标</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：视图可以传递列表，在模板中可以直接显示列表</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：视图可以传递字典，在模板中可以直接显示字典</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：在模板中可以通过字典的键得到相应的值</span><br/></pre></td></tr></table></figure><p>答案：A,B,C,D</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django中的HttpRequest对象的属性，错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：POST包含所有HTTP POST参数的列表对象</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：GET包含所有HTTP GET参数的列表对象</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：body表示请求体。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：method属性返回请求中使用的HTTP方法的字符串表示，全大写表示</span><br/></pre></td></tr></table></figure><p>答案：A,B</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">ORM和数据库的对应关系正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：方法对应字段</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：对象实例对应一条记录</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：Models类对应数据表</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：属性对应字段</span><br/></pre></td></tr></table></figure><p>答案：B,C,D</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">创建Django项目后，其中的文件的意义描述正确的有（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：settings.py 为Django项目的配置文件，里面包含了项目引用的Django组件、项目名等。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：urls.py为路由系统，主要维护项目的URL路由映射，即定义客户端访问的URL</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：__init__.py告诉Python该目录是一个Python模块，创建后暂无内容</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：wsgi.py定义WSGI的接口信息，用于与其他Web服务器集成，一般无需改动</span><br/></pre></td></tr></table></figure><p>答案：A,B,D</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">对requests库描述正确的是（）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：任何类型的请求都可以通过requests.get()获取数据</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：使用requests.post()发送请求时可以通过data参数传递请求数据</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：可以使用requests.get()发送GET请求</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：使用requests.get()发送请求时可以通过data参数传递请求数据</span><br/></pre></td></tr></table></figure><p>答案：B,C</p><p>问题解析：Na</p><h3 id="判断题"><a class="markdownIt-Anchor" href="#判断题"></a> 判断题</h3><p>每小题2分，共20 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django的视图函数至少要有一个参数用来接收请求对象（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB是一个基于分布式文件存储的数据库。是由C++语言编写（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">我们使用requests库发送post请求的时候，可以通过params关键字传递参数（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django是Python的一个Web开发框架，底层是基于C语言实现的。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django在创建应用后需要将应用注册到项目中，才能将应用中的模型类映射为数据表（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">构建Django模型时需要在settings.py文件中修改DATABASE的配置项，里面加上数据库引擎、数据主机、用户、密码等。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">在Scrapy项目中，我们可以通过yield关键字将item对象传递到管道，然后对数据进行持久化存储（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">我们可以使用Scrapy-Redis框架实现分布式爬虫，大规模的采集数据，但它的缺点是数据只能保存到Redis中，不能保存到MySQL中（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">我们在开发中大量采用MySQL数据库的原因是因为它是基于内存的数据库，效率高，速度快（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django MVT架构模式中的V指的是View，它的作用是渲染HTML内容，让用户能够看到一个美观的页面（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="中慧1+X证书真题" href="http://blog.imc.re/archives/7daf.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">中慧1+X证书真题</span><span class="cap link fs12">http://blog.imc.re/archives/7daf.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>中慧1+X证书题库</title>
    <link href="https://blog.imc.re/RSSBOX/rss/aa1b1a45.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/aa1b1a45.html</id>
    <published>2023-10-31T08:59:10.000Z</published>
    <updated>2023-10-31T08:59:10.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><p>所属院校：厦门南洋职业学院</p><h2 id="python程序开发模拟卷中级1120"><a class="markdownIt-Anchor" href="#python程序开发模拟卷中级1120"></a> Python程序开发模拟卷(中级1120)</h2><h3 id="单选题"><a class="markdownIt-Anchor" href="#单选题"></a> 单选题</h3><p>每小题2分，共60 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">提高Selenium脚本的执行速度描述中错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：使用更高配置的电脑和选择更快的网络环境</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：对于firefox浏览器，考虑使用测试专用的profile，因为每次启动浏览器的时候firefox会创建1个新的profile，对于这个新的profile，所有的静态资源都是从服务器直接下载，而不是从缓存里加载，这就导致网络不好的时候用例运行速度特别慢的问题</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：优化代码</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：可以随便加sleep，使用显式等待</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">删除Redis当前数据库的命令为（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：FLUSHALL</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：DB. Remove</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：DB. Drop</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：FLUSHDB</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django在视图中将数据传递给模板可以通过哪种方式（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：return render(request,"xxx.html", &#123;key: value&#125;)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：return render(request,"xxx.html", “name”)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：return render(request,"xxx.html", 20)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：return render(request,"xxx.html", [1, 2, 3])</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django创建名为TestModel应用的语法是（     ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：python manage.py makemigrations TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：python manage.py startapp TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：django-admin startproject TestModel</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：python manage.py migrate TestModel</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">以下操作不可以应对反爬的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：发送请求之后加上time.sleep(random.randint(1, 2))</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：requests.get()函数中为headers参数设置合理的User-Agent</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：一台计算机上开启多线程加快发送请求的速度</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：requests.get()函数中为proxies设置合适的代理</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQL字符数据类型不包括(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：TINYBLOB</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：CHAR</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：VARCHAR</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：BIGBLOB</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">ORM是指（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：对象、联系、模型</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：关系、对象、模型</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：映射、对象、联系</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：对象、关系、映射</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">以下属于pymongo删除数据方法的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：delete_all()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：drop_one()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：delete_one()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：drop_many()</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">查询MySQL数据库World中的country表的前10条记录，显示“Name”、“Region”两个字段，下列正确的SQL语句是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：SELECT Name,Region FROM country LIMIT 10</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：DELETE FROM country WHERE Name&gt;10</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：SELECT * FROM WorldLIMIT 10</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：SELECT top 100 * FROM `country`</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">假如Student是一个Django模型类，利用该模型类删除数据的操作错误的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：Student.objects.all().delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：Student.objects.filter(id=1).delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：Student.objects.query_all().delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">D：stu=Student.objects.get(id=1)</span><br/><span class="line">stu.delete()</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>11</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Redis的Hash的说法错误的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：HSET可设置字典的一个键值对</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：HDROP可用于删除键</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：HGETALL可获取字典的所有键值对</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：Hash是Redis的一种字典存储数据结构，一个Hash对象可以存储多个键-值对元素，底层由哈希表实现</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>12</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Selenium键盘操作，描述错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：send_keys(Keys.BACK_SPACE)表示删除键</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：send_keys(Keys.ENTER)表示回车键</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：send_keys(Keys.CONTROL，'c')表示复制</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：send_keys(Keys.ESCAPE)表示空格键</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>13</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">现有一个stuinfo表,其中包含name(VARCHAR)、gender(INT)、birthday(DATE)、address(VARCHAR)、class(INT)几个字段，以下插入语句正确的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：NSERT INTO stuinfo VALUES ('chen',1,'1999-5-1','北京市西直门大街123号',5);</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：NSERT INTO stuinfo VALUES ('chen',1,'1999-5-1','北京市西直门大街123号');</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：NSERT INTO stuinfo (name,sex,birthday,address) VALUES ('chen', 1, 1999-5-1, '北京市西直门大街123号', 5);</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：NSERT INTO stuinfo (name,sex,birthday,address,class) VALUES ('chen',1,'1999-5-1',5);</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>14</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Selenium中获取页面相关信息的描述，不正确的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：元素的get_attribute()方法可以获取元素的属性值</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：元素的text属性可以获取元素的文本信息</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：元素的title属性可以获取网页标题</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：元素得到size属性可以获取元素的尺寸</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>15</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">在Scrapy项目中创建爬虫的命令是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：scrapy genspider 爬虫名 网页域名</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：scrapy genspider 爬虫名 网页的URL</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：scrapy startspider 爬虫名 网页域名</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：scrapy startspider 爬虫名 网页的URL</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>16</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">SQL是以下哪三个单词的缩写(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：Selected Quiet Language</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：Structured Query Language</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：Structured Quiet Language</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：Selected Query Language</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>17</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Redis的说法，错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：Redis服务端程序为redis-server.exe</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：启动Redis可以通过CMD命令和手动方式启动</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：可发送PING命令测试服务器，正常服务器回复OK</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：Redis客户端程序为redis-cli.exe</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>18</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">scrapy-Redis分布式策略中，爬虫继承了RedisSpider，它能够支持分布式的抓取，采用的是basic spider，需要写parse函数。其次就是不再有start_urls了，取而代之的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：redis_key</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：scheduler</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：key-values</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：setting</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>19</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Redis数据库中一个字符串类型的值能存储最大容量是多少(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：128M</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：64M</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：512M</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：256M</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>20</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django请求对象属性中用于获取当前请求方式的关键字是（    ）</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：method</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：POST</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：path</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：body</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>21</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Redis说法，不正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：速度快</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：单线程操作</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：基于内存存储</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：不支持键-值对数据存储</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>22</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Scrapy框架基于管道的持久化存储流程，描述有误的是哪项(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：爬虫文件抓取到数据后，将数据封装到items对象中</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：settings.py中开启管道</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：使用return将items对象交给pipelines管道进行持久化操作</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：管道文件中使用process_item方法将爬虫文件提交过来的item对象数据进行持久化存储</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>23</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MongoDB数据库操作错误的是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：show databases 可以显示数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：use 数据库名 可以切换数据库，但不能切换到一个不存在的数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：show dbs 可以显示数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：db.dropDatabase()可以删除数据库</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>24</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">SQL语言中数据定义语言DDL中包括哪个语句（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：grant</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：select</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：DROP</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：DELETE</span><br/></pre></td></tr></table></figure><p>答案：C</p><p>问题解析：Na</p><p>25</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django模板中单行注释语法为(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：//</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：/*  */</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：#</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：&#123;# ... #&#125;</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>26</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django路由反向解析的说法错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：在模板 templates 中的 HTML 文件中，利用 &#123;% "路由别名" %&#125; 反向解析，如：&lt;form action="&#123;% 'login' %&#125;" method="post"&gt;</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：在 views.py 中，从 django.urls 中引入 reverse，利用 reverse("路由别名") 反向解析，如：return redirect(reverse("login"))</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：在urls.py中给路由起别名，name=”路由别名”，如：path("login1/", views.login, name="login")</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：反向解析，开发者可以增加代码的可维护性，使用URL反向解析使得开发者在许多需要写URL绝对路径的地方用映射名来代替</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>27</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQLdb连接数据库的语法为bObj=MySQLdB. connect(ServerName,User,PWD,DbName,charset=CharsetName)，以下关于它的描述错误的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：DbName表示表名</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：ServerName表示服务器名</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：PWD表示密码</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：User表示用户名</span><br/></pre></td></tr></table></figure><p>答案：A</p><p>问题解析：Na</p><p>28</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">进入Django项目的交互式环境的命令是(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：python manage.py runserver</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：python manage.py shell</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：python manage.py makemigrations</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：python manage.py migrate</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><p>29</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">向一个尚不存在的MongoDB数据库集合执行插入文档操作，下列说法正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：返回false</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：导致报错</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：返回nil</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：插入成功，自动创建集合</span><br/></pre></td></tr></table></figure><p>答案：D</p><p>问题解析：Na</p><p>30</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Scrapy中Downloader Middleware的核心方法不包括（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：process_response(request，response，spider)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：process_spider(request，spider)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：process_request(request，spider)</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：process_exception(request，exception，spider)</span><br/></pre></td></tr></table></figure><p>答案：B</p><p>问题解析：Na</p><h3 id="多选题"><a class="markdownIt-Anchor" href="#多选题"></a> 多选题</h3><p>每小题2分，共20 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django路由中的path()和re_path()函数的描述正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：path()函数和Django 1.1.x版本的url()函数用法相同</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：path()函数用于普通路径</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：re_path()函数用于正则路径</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：path()函数如果手动添加正则首位限制符号也可用于正则路径</span><br/></pre></td></tr></table></figure><p>答案：B,C</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">如果AppModel是一个Django模型类，则删除数据的方法正确的有（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：AppModel.objects.filter(id=1).delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">B：a1 = AppModel.objects.get(id=1)</span><br/><span class="line">a1.delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：AppModel.objects.delete()</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：AppModel.objects.all().delete()</span><br/></pre></td></tr></table></figure><p>答案：A,B,D</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">下列哪些列类型是MySQL数值型的数据(    )。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：DOUBLE</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：FLOAT</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：INT</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：SET</span><br/></pre></td></tr></table></figure><p>答案：A,B,C</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">以下Django框架的描述正确的有（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：免费开源</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：集成了众多功能强大的模块</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：Django诞生于2003年，是目前Python语言影响力最高和最成熟的网络框架</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：开发效率高</span><br/></pre></td></tr></table></figure><p>答案：A,B,C,D</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于MongoDB的说法，正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：由C++编写</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：提供可扩展的高性能数据存储解决方法</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：是一种基于分布式文件的开源数据库系统</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：可添加节点保证服务器性能</span><br/></pre></td></tr></table></figure><p>答案：A,B,C,D</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Scrapy项目中的文件的描述正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：pipelines.py：数据处理文件，对爬取到的数据进行处理保存等</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：settings.py：项目配置文件。定义了项目设置文件路径、部署信息等内容</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：items.py：定义Item数据结构的文件。在此可以编写所有的Item数据定义</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：scrapy.cfg：项目设置文件，可以定义项目的全局设置，比如USER_AGENT，ROBOTSTXT_OBEY等</span><br/></pre></td></tr></table></figure><p>答案：A,C</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQL中关于模糊查询的说法正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：由于模糊查询具有极大的便利性，因此在SQL中应推荐使用</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：‘张%’表示以‘张’开头的记录</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：可以使用LIKE关键字</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：‘_德_’表示三个字且中间为‘德’的记录</span><br/></pre></td></tr></table></figure><p>答案：B,C,D</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Navicat支持哪些数据库的可视化管理（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：Oracle</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：MySQL</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：MongoDB</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：SQL Server</span><br/></pre></td></tr></table></figure><p>答案：A,B,C,D</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Django视图的描述正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：视图函数可以查询数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：一个视图函数（类），简称视图，就是一个Python函数</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：视图函数render方法不能向页面发送响应数据</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：视图函数接受Web请求并返回Web响应</span><br/></pre></td></tr></table></figure><p>答案：A,B,D</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">关于Redis命令，正确的是（    ）。</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">A：DBCOUNT 命令用于查看当前数据库的记录数</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">B：SELECT命令用于选择数据库</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">C：GET KeyName，其中KeyName为键名，返回当前参数KeyName的值，如果指定KeyName不存在，则返加nil</span><br/></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">D：SET KeyName Value命令表示将值存储在当前数据库中</span><br/></pre></td></tr></table></figure><p>答案：B,C,D</p><p>问题解析：Na</p><h3 id="判断题"><a class="markdownIt-Anchor" href="#判断题"></a> 判断题</h3><p>每小题2分，共20 分</p><p>1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">通过CMD命令行启动MySQL服务的命令为start xxx, xxx表示安装过程中配置的MySQL服务名。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>2</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">由于Redis是内存数据库，因此它不支持数据的持久化存储。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>3</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Scrapy项目中运行爬虫的命令为scrapy start 爬虫名字。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>4</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Selenium是一个爬虫框架，让浏览器自动加载页面，获取需要的数据，甚至页面提交，后来又应用于Web自动化测试。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>5</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">mongo.exe是MongoDB的客户端程序，在命令行执行mongo命令即可启动MongoDB客户端。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>6</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">在使用多线程的过程中，为了解决全局变量冲突问题，可以通过Lock加锁。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>7</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django中path()函数可以用于正则路径。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>8</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">HttpRequest 对象的path属性可以获取URL中的路径部分，数据类型是字符串。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：正确</p><p>问题解析：Na</p><p>9</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">MySQL数据库在集群技术、高可用性、安全性、系统管理等方面都有较好性能表现，支持跨平台运行，是目前大型高性能商务数据库的首选。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p><p>10</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Django中的模板变量名必须有字母、数字、下划线和点组成，可以以字母、数字和下划线开头。（    ）</span><br/></pre></td></tr></table></figure><p>正确</p><p>错误</p><p>答案：错误</p><p>问题解析：Na</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="中慧1+X证书题库" href="http://blog.imc.re/archives/260d.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">中慧1+X证书题库</span><span class="cap link fs12">http://blog.imc.re/archives/260d.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Zookeeper安装文档</title>
    <link href="https://blog.imc.re/RSSBOX/rss/e32c0aa8.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/e32c0aa8.html</id>
    <published>2023-10-24T06:26:40.000Z</published>
    <updated>2023-10-24T06:26:40.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><ol start="0"><li>关闭防火墙</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 禁用防火墙</span></span><br/><span class="line">systemctl <span class="built_in">disable</span> firewalld</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 关闭防火墙</span></span><br/><span class="line">systemctl stop firewalld</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 再次查看防火墙状态</span></span><br/><span class="line">systemctl status firewalld</span><br/></pre></td></tr></table></figure><ol><li>查看主机名称</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">hostname</span><br/></pre></td></tr></table></figure><ol start="2"><li>解压zookeeper</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">tar -xvzf /opt/software/zookeeper-3.4.5.tar.gz -C /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="built_in">mv</span> /opt/module/zookeeper-3.4.5 /opt/module/zookeeper</span><br/></pre></td></tr></table></figure><ol start="3"><li>修改zookeeper配置文件</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /opt/module/zookeeper/conf/zoo_simple.cfg /opt/module/zookeeper/conf/zoo.cfg</span><br/><span class="line"></span><br/><span class="line">vi /opt/module/zookeeper/conf/zoo.cfg</span><br/></pre></td></tr></table></figure><p>修改以下内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line"># 修改 dataDir 路径</span><br/><span class="line">dataDir=/opt/module/zookeeper/zkdata</span><br/><span class="line"></span><br/><span class="line"># 文件末尾添加服务器</span><br/><span class="line">server.1=master:2888:3888</span><br/><span class="line">server.2=slave1:2888:3888</span><br/><span class="line">server.3=slave2:2888:3888</span><br/></pre></td></tr></table></figure><ol start="4"><li>创建 dataDir 设置的目录和 <code>myid</code> 文件</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /opt/module/zookeeper/zkdata</span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span> &gt; /opt/module/zookeeper/zkdata/myid &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">1</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="5"><li>配置环境变量</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi /root/.bash_profile</span><br/></pre></td></tr></table></figure><p>文件结尾插入以下内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">export ZK_HOME=/opt/module/zookeeper</span><br/><span class="line">export PATH=$PATH:$ZK_HOME/bin</span><br/></pre></td></tr></table></figure><p>刷新文件生效:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /root/.bash_profile</span><br/></pre></td></tr></table></figure><ol start="6"><li>分发 zookeeper 相关文件和环境变量到slave1 slave2</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">scp -r /opt/module/zookeeper slave1:/opt/module</span><br/><span class="line">scp -r /opt/module/zookeeper slave2:/opt/module</span><br/><span class="line">scp -r /root/.bash_profile slave1:/root</span><br/><span class="line">scp -r /root/.bash_profile slave2:/root</span><br/></pre></td></tr></table></figure><p>在其他节点shell终端上刷新环境变量以生效</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /.bash_profile</span><br/></pre></td></tr></table></figure><ol start="7"><li>更改 slave1 和 slave2 的 <code>myid</code> 文件内容为 2 和 3</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; /opt/module/zookeeper/zkdata/myid &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; /opt/module/zookeeper/zkdata/myid &lt;&lt; <span class="string">EOF</span></span><br/><span class="line"><span class="string">3</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><ol start="8"><li>分别在三台机子上启动 zookeeper</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkServer.sh start</span><br/></pre></td></tr></table></figure><ol start="9"><li>查看启动状态</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkServer.sh status</span><br/></pre></td></tr></table></figure><p>输出类似下方内容即为启动正常</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">JMX enabled by default</span><br/><span class="line">Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg</span><br/><span class="line">Mode: follower</span><br/></pre></td></tr></table></figure><ol start="10"><li>进入 zkshell</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkCli.sh -server localhost:2181</span><br/></pre></td></tr></table></figure><ol start="11"><li>退出</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">quit</span><br/></pre></td></tr></table></figure><ol start="12"><li>停止 zk 服务</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkServer.sh stop</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="zookeeper安装文档" href="http://blog.imc.re/archives/zookeeper.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">zookeeper安装文档</span><span class="cap link fs12">http://blog.imc.re/archives/zookeeper.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Kafka安装文档</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6b180cba.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6b180cba.html</id>
    <published>2023-10-24T06:26:40.000Z</published>
    <updated>2023-10-24T06:26:40.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><ol start="0"><li>关闭防火墙</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">systemctl stop firewalld</span><br/></pre></td></tr></table></figure><ol><li>需安装Zookeeper组件具体要求同Zookeeper任务要求，并与Kafka环境适配，启动Zookeeper并截图保存结果：</li></ol><ul><li>在master，slave1，slave2分别启动zookeeper</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkServer.sh start</span><br/></pre></td></tr></table></figure><ul><li>查询3台机器的zookeeper启动状态</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">zkServer.sh status</span><br/></pre></td></tr></table></figure><ul><li>zookeeper 配置文件 <code>/opt/software/zookeeper/conf/zoo.cfg</code> ，数据文件夹设置为 <code>/opt/software/zookeeper/zkdata</code>，<code>zoo.cfg</code> 需要和 kafka 的 <code>zookeeper.properties</code> 适配</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi /opt/module/zookeeper/conf/zoo.cfg</span><br/></pre></td></tr></table></figure><p>需要查看的配置内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line">dataDir=/opt/module/zookeeper/zkdata</span><br/><span class="line">clientPort=2181</span><br/><span class="line">server.1=master:2888:3888</span><br/><span class="line">server.2=slave1:2888:3888</span><br/><span class="line">server.3=slave2:2888:3888</span><br/></pre></td></tr></table></figure><ol start="2"><li>解压kafka安装包到 <code>/opt/module</code> 路径,并修改解压后文件夹名为 kafka ,截图并保存结果:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">tar -xvzf /opt/software/kafka1.0.0.tar.gz -C /opt/module</span><br/><span class="line"><span class="built_in">mv</span> /opt/module/kafka_2.11-1.0.0 /opt/module/kafka</span><br/></pre></td></tr></table></figure><ol start="3"><li>设置kafka环境变量, 并使环境变量只对当前root用户生效，截图并保存结果:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi /root/.bash_profile</span><br/></pre></td></tr></table></figure><p>添加以下内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">export KAFKA_HOME=/opt/module/kafka</span><br/><span class="line">export PATH=$PATH:$KAFKA_HOME/bin</span><br/></pre></td></tr></table></figure><p>刷新生效:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /root/.bash_profile</span><br/></pre></td></tr></table></figure><ol start="4"><li>修改kafka相应文件, 截图并保存结果:</li></ol><ul><li>在 master 上修改文件zookeeper.properties</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi /opt/module/kafka/config/zookeeper.properties</span><br/></pre></td></tr></table></figure><p>配置文件内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line">clientPort=2181</span><br/><span class="line">dataDir=/opt/module/kafka/data</span><br/><span class="line">server.1=master:2888:3888</span><br/><span class="line">server.2=slave1:2888:3888</span><br/><span class="line">server.3=slave2:2888:3888</span><br/></pre></td></tr></table></figure><p>在kafka安装文件夹中建立 data 文件夹,与 <code>dataDir=/opt/module/kafka/data</code> 对应</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> /opt/module/kafka/data</span><br/><span class="line">vi /opt/module/kafka/data/myid</span><br/></pre></td></tr></table></figure><ul><li>在 master 上修改 <code>server.properties</code></li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi  /opt/module/kafka/config/server.properties</span><br/></pre></td></tr></table></figure><p>修改以下内容:</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line"><span class="attr">broker.id</span>=<span class="string">0</span></span><br/><span class="line"><span class="attr">listeners</span>=<span class="string">PLAINTEXT://192.168.152.240:9092</span></span><br/><span class="line"><span class="attr">advertised.listeners</span>=<span class="string">PLAINTEXT://192.168.152.240:9092</span></span><br/><span class="line"><span class="attr">log.dirs</span>=<span class="string">/usr/local/src/kafka/data</span></span><br/><span class="line"><span class="attr">zookeeper.connect</span>=<span class="string">192.168.152.240:2181,192.168.152.241:2181,192.168.152.242:2181</span></span><br/></pre></td></tr></table></figure><p>文件分发:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">scp -r /opt/module/kafka slave1:/opt/module</span><br/><span class="line">scp -r /opt/module/kafka slave2:/opt/module</span><br/><span class="line">scp /root/.bash_profile slave1:/root</span><br/><span class="line">scp /root/.bash_profile slave2:/root</span><br/></pre></td></tr></table></figure><p>在其他节点刷新变量文件生效:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /root/.bash_profile</span><br/></pre></td></tr></table></figure><ul><li>在 slave1 上修改 <code>myid</code> 文件为 2</li></ul><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span>&gt;/opt/module/kafka/data/myid&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><p>修改 <code>server.properties</code> 文件为以下内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">broker.id=1</span><br/><span class="line">listeners=PLAINTEXT://192.168.152.241:9092</span><br/><span class="line">advertised.listeners=PLAINTEXT://192.168.152.241:9092</span><br/><span class="line">log.dirs=/usr/local/src/kafka/data zookeeper.connect=192.168.152.240:2181,192.168.152.241:2181,192.168.152.242:2181</span><br/></pre></td></tr></table></figure><p>在 slave2 上修改 <code>myid</code> 文件为 3</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span>&gt;/opt/module/kafka/data/myid&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">3</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><p>修改 <code>server.properties</code> 文件为以下内容:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">broker.id=1</span><br/><span class="line">listeners=PLAINTEXT://192.168.152.242:9092</span><br/><span class="line">advertised.listeners=PLAINTEXT://192.168.152.242:9092</span><br/><span class="line">log.dirs=/usr/local/src/kafka/data zookeeper.connect=192.168.152.240:2181,192.168.152.241:2181,192.168.152.242:2181</span><br/></pre></td></tr></table></figure><ol start="5"><li>启动 kafka 并保存命令输出结果, 截图并保存结果:</li></ol><p>分别在master, slave1, slave2 上执行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">kafka-server-start.sh -daemon /opt/module/kafka/config/server.properties</span><br/><span class="line"></span><br/><span class="line">jps</span><br/></pre></td></tr></table></figure><p>输出以下内容为正常启动:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">2198 QuorumPeerMain</span><br/><span class="line">6732 Jps</span><br/><span class="line">3758 Kafka</span><br/></pre></td></tr></table></figure><ol start="6"><li>创建指定topic, 截图并保存结果:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-topics.sh --zookeeper master01:2181,slave01:2181,slave02:2181 --create --partitions 3 --replication-factor 3 --topic <span class="built_in">test</span></span><br/></pre></td></tr></table></figure><p>输出以下内容为正常启动:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Created topic <span class="string">"test-topic"</span>.</span><br/></pre></td></tr></table></figure><ol start="7"><li>查看所有topic信息, 并截图保存结果:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-topics.sh --list --zookeeper master01:2181</span><br/></pre></td></tr></table></figure><p>输出:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">test</span></span><br/></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-topics.sh -zookeeper master01:2181,slave01:2181,slave02:2181 --describe --topic <span class="built_in">test</span></span><br/></pre></td></tr></table></figure><p>输出:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">Topic:test-topic     PartitionCount:3   ReplicationFactor:3      Configs:</span><br/><span class="line">      Topic: test-topic    Partition: 0 Leader: 1   Replicas: 1,2,0      Isr: 1,0</span><br/><span class="line">      Topic: test-topic    Partition: 1 Leader: 2   Replicas: 2,0,1      Isr: 2,0,1</span><br/><span class="line">      Topic: test-topic    Partition: 2 Leader: 0   Replicas: 0,1,2      Isr: 0,1</span><br/></pre></td></tr></table></figure><ol start="8"><li>启动指定生产者(producer), 并截图保存结果:</li></ol><blockquote><p>注意: 控制台发送者的broker-list的ip需要与server.properties中listeners处的一致, 控制台消费者就能接收到消息</p></blockquote><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-producer.sh --broker-list 192.168.152.240:9092 --topic <span class="built_in">test</span></span><br/></pre></td></tr></table></figure><ol start="9"><li>启动消费者(sonsumer), 并截图保存结果:</li></ol><p>再开启一个master连接, 输入:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-consumer.sh --bootstrap-server 192.168.152.240:9092 --topic <span class="built_in">test</span></span><br/></pre></td></tr></table></figure><p>注: kafka旧版本连接服务器的参数为 <code>--zookeeper</code> , 新版为 <code>--bootstrap-server</code></p><p>输出:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">Using the ConsoleConsumer with old consumer is deprecated and will be removed <span class="keyword">in</span> a future major release. Consider using the new consumer by passing [bootstrap-server] instead of [zookeeper]</span><br/></pre></td></tr></table></figure><ol start="10"><li>测试生产者(producer), 并截图保存结果:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-producer.sh --broker-list 192.168.152.240:9092 --topic <span class="built_in">test</span></span><br/></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/></pre></td><td class="code"><pre><span class="line">[root@master01 ~]<span class="comment"># kafka-console-producer.sh --broker-list 192.168.152.240:9092 --topic test</span></span><br/><span class="line">&gt;111</span><br/><span class="line">&gt;222</span><br/><span class="line">&gt;333</span><br/><span class="line">&gt;444</span><br/><span class="line">&gt;555</span><br/><span class="line">&gt;666</span><br/><span class="line">&gt;777</span><br/><span class="line">&gt;888</span><br/></pre></td></tr></table></figure><ol start="11"><li>测试消费者(consumer), 并截图保存结果</li></ol><p>消费者上显示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/></pre></td><td class="code"><pre><span class="line">Using the ConsoleConsumer with old consumer is deprecated and will be removed in a future major release. Consider using the new consumer by passing [bootstrap-server] instead of [zookeeper].</span><br/><span class="line">111</span><br/><span class="line">222</span><br/><span class="line">333</span><br/><span class="line">444</span><br/><span class="line">555</span><br/><span class="line">666</span><br/><span class="line">777</span><br/><span class="line">888</span><br/></pre></td></tr></table></figure><h2 id="基于命令行方式使用kafka"><a class="markdownIt-Anchor" href="#基于命令行方式使用kafka"></a> 基于命令行方式使用kafka</h2><p>1.  三台机器上启动zookeeper<br><a href="http://zkServer.sh">zkServer.sh</a> start</br></p><p>2.  三台机器上启动kafka服务</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">kafka-server-start.sh -daemon /usr/local/src/kafka/config/server.properties  </span><br/></pre></td></tr></table></figure><p>3.  查看进程</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">jps</span><br/></pre></td></tr></table></figure><p>4.  创建主题</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line">kafka-topics.sh --create \  </span><br/><span class="line">--topic itcasttopic \  </span><br/><span class="line">--partitions 3 \  </span><br/><span class="line">--replication-factor 2 \  </span><br/><span class="line">--zookeeper master01:2181,slave01:2181,slave02:2181  </span><br/></pre></td></tr></table></figure><p>5.  创建生产者，来生产消息。在master01上输入</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-producer.sh \  </span><br/><span class="line">--broker-list master01:9092,slave01:9092,slave02:9092 \  </span><br/><span class="line">--topic itcasttopic  </span><br/></pre></td></tr></table></figure><p>6.  创建消费者，来消费消息。在slave01上输入</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-consumer.sh \  </span><br/><span class="line">--from-beginning \  </span><br/><span class="line">--topic itcasttopic </span><br/></pre></td></tr></table></figure><p>测试消费者（consumer）（kafka2.11-2.0.0命令有所不同）</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">kafka-console-consumer.sh \  </span><br/><span class="line">--from-beginning \  </span><br/><span class="line">--topic <span class="built_in">test</span> \  </span><br/><span class="line">--bootstrap-server 192.168.152.245:9092</span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="kafka安装文档" href="http://blog.imc.re/archives/kafka.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">kafka安装文档</span><span class="cap link fs12">http://blog.imc.re/archives/kafka.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Hadoop安装竞赛文档</title>
    <link href="https://blog.imc.re/RSSBOX/rss/1cfc267e.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/1cfc267e.html</id>
    <published>2023-10-11T06:26:40.000Z</published>
    <updated>2023-10-11T06:26:40.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="hadoop安装教程"><a class="markdownIt-Anchor" href="#hadoop安装教程"></a> Hadoop安装教程</h1><blockquote><p>仅供厦门南洋学院的同学参考使用，基于厦门南洋学院实训楼413的环境进行配置，无法保证能够应用到其他场景。</p></blockquote><ul><li>编纂时间：2023.10.11</li><li>编纂作者：夏五郎</li></ul><h1 id="linux入门教程"><a class="markdownIt-Anchor" href="#linux入门教程"></a> Linux入门教程</h1><p>在linux下安装hadoop必须要会的几个基本操作：</p><ul><li><p>cd <code>目录</code> # 切换目录的命令使用 <code>cd</code> 命令可以切换目录，比如 <code>cd $MP</code> 就是打开$MP  目录。其中在目录前添加 <code>./module</code>或不加任何标记 <code>module</code> 表示当前目录，添加 <code>../module</code> 表示上级目录 ，<code>/module</code> 表示从根目录 <code>/</code> 开始的绝对路径目录。</p></li><li><p>vi <code>文件目录</code> # 在命令行中使用编辑器的命令使用 <code>vi</code> 命令可以在shell中编辑文件，比如 <code>vi /etc/hosts</code> 就是编辑/etc/hosts文件。文件目录的标注方法和cd同样，不存在的文件会直接新建，请注意！使用方向键移动光标，点击 <code>i</code> 键，最下方显示 <code>INSERT</code> 后进入编辑模式点击 <code>Esc</code> 键，然后输入 <code>:wq</code>可以保存文件并退出，其中q表示退出，w表示保存</p></li><li><p>tar # 解压文件的命令使用<code>tar</code>命令可以压缩/解压文件，hadoop配置中只用到了解压文件，这里给出解压文件的示例命令，其他参数请自行<code>tar --help</code> 或者bing查看。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">tar -xvzf 压缩目录文件 -C 解压到的目录</span><br/><span class="line"># 例子：</span><br/><span class="line">tar -xvzf /opt/jdk-8u162-linux-x64.tar.gz -C $MP</span><br/></pre></td></tr></table></figure><p>其中 <code>/opt/jdk-8u162-linux-x64.tar.gz</code> 是压缩文件所在文件路径，<code>$MP</code> 是要解压到的文件目录</p></li><li><p>ip #命令使用 <code>ip a</code> 命令可以查看服务器的IP地址，输出一般为这样：</p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/></pre></td><td class="code"><pre><span class="line">  [root@master ~]<span class="comment"># ip a</span></span><br/><span class="line">1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000</span><br/><span class="line">    <span class="built_in">link</span>/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</span><br/><span class="line">    inet 127.0.0.1/8 scope host lo</span><br/><span class="line">       valid_lft forever preferred_lft forever</span><br/><span class="line">    inet6 ::1/128 scope host </span><br/><span class="line">       valid_lft forever preferred_lft forever</span><br/><span class="line">2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000</span><br/><span class="line">    <span class="built_in">link</span>/ether 00:0c:29:56:e9:74 brd ff:ff:ff:ff:ff:ff</span><br/><span class="line">    inet 192.168.152.81/24 brd 192.168.152.255 scope global noprefixroute ens33</span><br/><span class="line">       valid_lft forever preferred_lft forever</span><br/><span class="line">    inet6 fe80::6a9a:2e8:734b:def2/64 scope <span class="built_in">link</span> noprefixroute </span><br/><span class="line">       valid_lft forever preferred_lft forever</span><br/></pre></td></tr></table></figure><p>其中 <code>192.168.152.81</code>就是该服务器的ip地址，要学会去看其他节点服务器的ip地址，以便连接操作。</p><ul><li>ssh #连接服务器命令使用 <code>ssh</code> 命令可以连接其他节点服务器，连接命令为：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">ssh root@192.168.152.81 <span class="comment">#root是连接用户名，192.168.152.81是要连接的服务器ip地址。</span></span><br/><span class="line">root@192.168.152.81<span class="string">'s password: #显示这个后输入密码</span></span><br/><span class="line"><span class="string">[root@master ~]# 显示这个代表成功连接</span></span><br/></pre></td></tr></table></figure><h2 id="小贴士"><a class="markdownIt-Anchor" href="#小贴士"></a> 小贴士</h2><ul><li>在敲命令的过程中可以使用 <code>TAB</code> 键补全命令哦~</li><li>可以使用方向键的 ↑ ↓ 键切换到上次执行的命令</li><li>使用 <code>ssh root@192.168.152.81 "command"</code> 指令即可远程执行 <code>command</code> 指令，前提是配置了密钥连接哦。</li></ul><h1 id="hadoop安装流程"><a class="markdownIt-Anchor" href="#hadoop安装流程"></a> Hadoop安装流程</h1><h2 id="一配置服务器基本环境"><a class="markdownIt-Anchor" href="#一配置服务器基本环境"></a> 一，配置服务器基本环境</h2><blockquote><p>需要在本板块将服务器所需模块以及其他配置文件弄好，以便后续的配置</p></blockquote><ol><li>在ubuntu中连接hadoop01，将hadoop01作为master节点进行配置：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">ssh root@192.168.152.81 </span><br/><span class="line"><span class="comment">#打开终端，输入上述命令进行连接，root是连接用户名，192.168.152.81是要连接的服务器ip地址。</span></span><br/><span class="line">root@192.168.152.81<span class="string">'s password: #显示这个后输入密码</span></span><br/><span class="line"><span class="string">[root@server-1 ~]# 显示这个代表成功连接</span></span><br/></pre></td></tr></table></figure><p><strong>如果无法连接说明IP地址更改了，请自行查看！</strong></p><ol start="2"><li>设置master主机名称和host文件，便于连接</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置主机名</span></span><br/><span class="line">hostnamectl set-hostname master</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 在/etc/hosts文件里插入master和其他节点的ip和域名id</span></span><br/><span class="line"><span class="built_in">cat</span>&gt;&gt;<span class="string">"/etc/hosts"</span>&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">192.168.152.81 master</span></span><br/><span class="line"><span class="string">192.168.152.101 slave1</span></span><br/><span class="line"><span class="string">192.168.152.121 slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/></pre></td></tr></table></figure><p>或者使用 <code>vi /etc/hosts</code> 命令在文件末尾插入如下代码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">192.168.152.81 master</span><br/><span class="line">192.168.152.101 slave1</span><br/><span class="line">192.168.152.121 slave2</span><br/></pre></td></tr></table></figure><ol start="3"><li>生成密钥配置一键免密登录</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成密钥，回车三次即可</span></span><br/><span class="line">ssh-keygen -t rsa</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 将密钥复制给其他的节点便于一键连接，先输入 yes ，再输入节点密码 123456</span></span><br/><span class="line">ssh-copy-id master</span><br/><span class="line">ssh-copy-id slave1</span><br/><span class="line">ssh-copy-id slave2</span><br/></pre></td></tr></table></figure><ol start="4"><li>解压配置jdk以及hadoop</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 新建目录 /opt/module 用于放置所有需要的模组文件</span></span><br/><span class="line"><span class="built_in">mkdir</span> /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 解压jdk文件，文件路径为/opt/jdk-8u162-linux-x64.tar.gz，如有变更自行更改</span></span><br/><span class="line">tar -xvzf /opt/jdk-8u162-linux-x64.tar.gz -C /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 将jdk目录重命名，方便后续配置</span></span><br/><span class="line"><span class="built_in">mv</span> /opt/module/jdk1.8.0_162 /opt/module/jdk</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 解压hadoop文件，文件路径为tar -xvzf /opt/hadoop-3.3.0.tar.gz，学校自带镜像没有该版本，该版本为2023参赛所用版本，需要手动上传。</span></span><br/><span class="line">tar -xvzf /opt/hadoop-3.3.0.tar.gz -C /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 将hadoop目录重命名，方便后续配置</span></span><br/><span class="line"><span class="built_in">mv</span> /opt/module/hadoop-3.3.0 /opt/module/hadoop</span><br/></pre></td></tr></table></figure><ol start="5"><li>设置jdk以及hadoop的环境变量</li></ol><p>使用 <code>vi /root/.bash_profile</code> 在文件末尾添加如下内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> JAVA_HOME=/opt/module/jdk</span><br/><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span></span><br/><span class="line"><span class="built_in">export</span> HADOOP_HOME=/opt/module/hadoop</span><br/><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:<span class="variable">$HADOOP_HOME</span>/bin:<span class="variable">$HADOOP_HOME</span>/sbin</span><br/></pre></td></tr></table></figure><ol start="6"><li>配置其他文件节点，执行以下命令：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 传输hosts以及.root_profile 配置文件到其他的节点上</span></span><br/><span class="line">scp -r /etc/hosts slave1:/etc</span><br/><span class="line">scp -r /etc/hosts slave2:/etc</span><br/><span class="line">scp -r /root/.root_profile slave1:/etc</span><br/><span class="line">scp -r /root/.bash_profile slave2:/root</span><br/></pre></td></tr></table></figure><ul><li><strong>打开新的终端页面执行以下指令</strong>，配置slave1。</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 连接服务器ssh</span></span><br/><span class="line">ssh root@slave1</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 设置主机名</span></span><br/><span class="line">hostnamectl set-hostname slave1</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 创建文件夹</span></span><br/><span class="line"><span class="built_in">mkdir</span> /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 生成密钥，回车三次即可</span></span><br/><span class="line">ssh-keygen -t rsa</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 将密钥复制给其他的节点便于一键连接，先输入 yes ，再输入节点密码 123456</span></span><br/><span class="line">ssh-copy-id master</span><br/><span class="line">ssh-copy-id slave1</span><br/><span class="line">ssh-copy-id slave2</span><br/></pre></td></tr></table></figure><ul><li>配置slave2，<strong>打开新的终端页面执行以下指令</strong>。</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 连接服务器ssh</span></span><br/><span class="line">ssh root@slave2</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 设置主机名</span></span><br/><span class="line">hostnamectl set-hostname slave2</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 创建文件夹</span></span><br/><span class="line"><span class="built_in">mkdir</span> /opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 生成密钥，回车三次即可</span></span><br/><span class="line">ssh-keygen -t rsa</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 将密钥复制给其他的节点便于一键连接，先输入 yes ，再输入节点密码 123456</span></span><br/><span class="line">ssh-copy-id master</span><br/><span class="line">ssh-copy-id slave1</span><br/><span class="line">ssh-copy-id slave2</span><br/></pre></td></tr></table></figure><ol start="7"><li>查看安装情况</li></ol><p>在</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 刷新文件使变量生效</span></span><br/><span class="line"><span class="built_in">source</span> /root/.bash_profile</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 查看Java安装情况和版本</span></span><br/><span class="line">java -version</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 查看hadoop安装情况和版本</span></span><br/><span class="line">hadoop version</span><br/></pre></td></tr></table></figure><p>如果都正常输出证明安装成功，如果提示未找到命令则需要排查问题。</p><h2 id="二更改hadoop配置文件"><a class="markdownIt-Anchor" href="#二更改hadoop配置文件"></a> 二，更改hadoop配置文件</h2><blockquote><p>一共有6个配置文件需要更改，hadoop-3.3.0版本需要在4个启动/关闭脚本中添加环境参数，更改文件命令为 <code>vi ./文件名</code></p></blockquote><ol><li>更改 <code>hadoop-env.sh</code>文件</li></ol><p>切换目录到hadoop配置文件目录下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /opt/module/hadoop/etc/hadoop</span><br/></pre></td></tr></table></figure><p>使用如下命令更改：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">vi ./hadoop-env.sh</span><br/></pre></td></tr></table></figure><p>查找文件中 <code>JAVA_HOME</code> 关键词并替换为下方路径</p><ul><li>提示：可以使用 <code>?JAVA_HOME</code> 搜索关键词， <code>N</code> 键是查找下一个，在文件内标注<code>export JAVA_HOME=</code> 的地方进行修改，如果有注释需要删除注释进行修改，修改成下方内容</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> JAVA_HOME=/opt/module/jdk</span><br/></pre></td></tr></table></figure><ol start="2"><li>更改 <code>core-site.xml</code> 文件</li></ol><p>配置文件如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>fs.defaultFS<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>hdfs://master:9000<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line">      <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>hadoop.tmp.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>/opt/module/hadoop/tmp<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br/></pre></td></tr></table></figure><ol start="3"><li>更改 <code>hdfs-site.xml</code> 文件</li></ol><p>配置文件如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br/><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.replication<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>3<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.namenode.secondary.http-address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>slave1:50090<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br/></pre></td></tr></table></figure><ol start="4"><li>更改 <code>mapred-site.xml</code> 文件</li></ol><p>配置文件如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br/><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>mapreduce.framework.name<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>yarn<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br/></pre></td></tr></table></figure><p>注：hadoop-2.7.7中需要先复制配置文件模板再进行配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> ./mapred-site.xml.template ./mapred-site.xml</span><br/></pre></td></tr></table></figure><ol start="5"><li>更改 <code>yarn-site.xml</code> 文件</li></ol><p>配置文件如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.resourcemanager.hostname<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>master<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line">       <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br/><span class="line">         <span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.nodemanager.aux-services<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br/><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>mapreduce_shuffle<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br/><span class="line">     <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br/><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br/></pre></td></tr></table></figure><ol start="6"><li>更改 <code>workers</code> 文件</li></ol><p><strong>在hadoop-2.7.7中该文件名称为 <code>slaves</code> ，hadoop-3.3.0中该文件为<code>workers</code> 记得根据实际情况更改文件名！</strong></p><p>配置文件如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">master</span><br/><span class="line">slave1</span><br/><span class="line">slave2</span><br/></pre></td></tr></table></figure><ol start="7"><li>更改 <code>start-dfs.sh</code> 以及 <code>stop-dfs.sh</code> 中的启动变量</li></ol><p>使用 <code>vi /opt/module/hadoop/sbin/start-dfs.sh</code> 以及 <code>vi /opt/module/hadoop/sbin/stop-dfs.sh</code> 指令分别更改，在 <strong>文件开头第二行插入如下代码！</strong>（#!/usr/bin/env的下面）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/></pre></td><td class="code"><pre><span class="line">HDFS_DATANODE_USER=root</span><br/><span class="line">HADOOP_SECURE_DN_USER=hdfs</span><br/><span class="line">HDFS_NAMENODE_USER=root</span><br/><span class="line">HDFS_SECONDARYNAMENODE_USER=root</span><br/></pre></td></tr></table></figure><ol start="8"><li>更改 <code>start-yarn.sh</code> 以及 <code>stop-yarn.sh</code> 中的启动变量</li></ol><p>使用 <code>vi /opt/module/hadoop/sbin/start-yarn.sh</code> 以及 <code>vi /opt/module/hadoop/sbin/stop-yarn.sh</code> 指令分别更改，在 <strong>文件开头第二行插入如下代码！</strong>（#!/usr/bin/env的下面）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/></pre></td><td class="code"><pre><span class="line">YARN_RESOURCEMANAGER_USER=root</span><br/><span class="line">HADOOP_SECURE_DN_USER=yarn</span><br/><span class="line">YARN_NODEMANAGER_USER=root</span><br/></pre></td></tr></table></figure><ol start="9"><li>将master节点下的模组文件传输给其他的节点</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">scp -r /opt/module slave1:/opt</span><br/><span class="line">scp -r /opt/module slave2:/opt</span><br/></pre></td></tr></table></figure><h2 id="三启动hadoop"><a class="markdownIt-Anchor" href="#三启动hadoop"></a> 三，启动hadoop</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/></pre></td><td class="code"><pre><span class="line"></span><br/><span class="line"><span class="comment"># hdfs初始化</span></span><br/><span class="line">hdfs namenode -format</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 启动dfs</span></span><br/><span class="line">start-dfs.sh</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 启动yarn</span></span><br/><span class="line">start-yarn.sh</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 检查启动情况</span></span><br/><span class="line">jps</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 检查其他节点启动情况</span></span><br/><span class="line">ssh root@slave1 <span class="string">"source /root/.bash_profile &amp;&amp; hostnamectl &amp;&amp; jps"</span></span><br/><span class="line">ssh root@slave2 <span class="string">"source /root/.bash_profile &amp;&amp; hostnamectl &amp;&amp; jps"</span></span><br/></pre></td></tr></table></figure><p>如果启动失败记得先关闭yarn以及dfs，然后再排查问题</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">stop-dfs.sh</span><br/><span class="line">stop-yarn.sh</span><br/></pre></td></tr></table></figure><p><strong>问题更改之后记得使用下方命令同步文件！</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/></pre></td><td class="code"><pre><span class="line">scp -r /opt/module slave1:/opt</span><br/><span class="line">scp -r /opt/module slave2:/opt</span><br/></pre></td></tr></table></figure><h2 id="四配置文件记忆"><a class="markdownIt-Anchor" href="#四配置文件记忆"></a> 四，配置文件记忆</h2><p><strong>注意：比赛时所有的配置文件都需要背过！！！</strong> 为了方便背诵，我将所有需要背的配置文件内容拆解开来，助于理解记忆。</p><p>理解记忆：</p><ul><li><p>xml文件中配置框架英文含义：</p><ul><li>configuartion：配置</li><li>property：属性</li><li>name：名称</li><li>value：值</li></ul></li><li><p><code>hadoop-env.sh</code> 文件中需要重点记忆的内容：</p><ul><li><code>export JAVA_HOME</code> Java配置路径</li></ul></li><li><p><code>core-site.xml</code> 文件中需要重点记忆的内容：</p><ul><li><code>property</code> hadoop默认主节点的名称<ul><li>name <code>fs.defaultFS</code></li><li>value <code>hdfs://master:9000</code></li></ul></li><li><code>property</code> hadoop缓存目录路径值<ul><li>name <code>hadoop.tmp.dir</code></li><li>value <code>/opt/module/hadoop/tmp</code></li></ul></li></ul></li><li><p><code>hdfs-site.xml</code> 文件中需要重点记忆的内容：</p><ul><li><code>property</code> hadoop分布式节点数量名称<ul><li>name <code>dfs.replication</code></li><li>value <code>3</code></li></ul></li><li><code>property</code> hadoop namenode第二节点http地址<ul><li>name <code>dfs.namenode.secondary.http-address</code></li><li>value <code>slave1:50090</code></li></ul></li></ul></li><li><p><code>mapred-site.xml</code> 文件中需要重点记忆的内容：</p><ul><li><code>property</code> mapreduce framework 名称<ul><li>name <code>mapreduce.framework.name</code></li><li>value <code>yarn</code></li></ul></li></ul></li><li><p><code>yarn-site.xml</code> 文件中需要重点记忆的内容：</p><ul><li><code>property</code> yarn资源管理主机名称<ul><li>name <code>yarn.resourcemanager.hostname</code></li><li>value <code>master</code></li></ul></li><li><code>property</code> yarn节点管理 aux-services<ul><li>name <code>yarn.nodemanager.aux-services</code></li><li>value <code>mapreduce_shuffle</code></li></ul></li></ul></li><li><p><code>workers</code> 文件中需要重点记忆的内容：</p><ul><li>所有节点的主机名称</li></ul></li><li><p><code>*-dfs.sh</code> 文件中需要重点记忆的内容：</p><ul><li><code>HDFS_DATANODE_USER=root</code> # HDFS_数据节点_用户=root</li><li><code>HADOOP_SECURE_DN_USER=hdfs</code> # HADOOP_安全_DN_用户=hdfs</li><li><code>HDFS_NAMENODE_USER=root</code> # HDFS_名称节点_用户=root</li><li><code>HDFS_SECONDARYNAMENODE_USER=root</code> # HDFS_第二名称节点_用户=root</li></ul></li><li><p><code>*-yarn.sh</code> 文件中需要重点记忆的内容：</p><ul><li><code>YARN_RESOURCEMANAGER_USER=root</code> # YARN_资源管理_用户=root</li><li><code>HADOOP_SECURE_DN_USER=yarn</code> # HADOOP_安全_DN_用户=yarn</li><li><code>YARN_NODEMANAGER_USER=root</code> # YARN_节点管理_用户=root</li></ul></li></ul><hr/><h1 id="一键安装脚本"><a class="markdownIt-Anchor" href="#一键安装脚本"></a> 一键安装脚本</h1><p>针对南洋学院内网2022参赛环境编写的一键安装脚本，在master节点执行本脚本可以一键安装hadoop。<s>仅供参考</s></p><p><strong>请不要在学习hadoop搭建的时候使用脚本偷懒！脚本参考是为了辅助理解计算机配置hadoop的流程！学习hadoop搭建的过程无需查看，或仅供参考。</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/><span class="line">17</span><br/><span class="line">18</span><br/><span class="line">19</span><br/><span class="line">20</span><br/><span class="line">21</span><br/><span class="line">22</span><br/><span class="line">23</span><br/><span class="line">24</span><br/><span class="line">25</span><br/><span class="line">26</span><br/><span class="line">27</span><br/><span class="line">28</span><br/><span class="line">29</span><br/><span class="line">30</span><br/><span class="line">31</span><br/><span class="line">32</span><br/><span class="line">33</span><br/><span class="line">34</span><br/><span class="line">35</span><br/><span class="line">36</span><br/><span class="line">37</span><br/><span class="line">38</span><br/><span class="line">39</span><br/><span class="line">40</span><br/><span class="line">41</span><br/><span class="line">42</span><br/><span class="line">43</span><br/><span class="line">44</span><br/><span class="line">45</span><br/><span class="line">46</span><br/><span class="line">47</span><br/><span class="line">48</span><br/><span class="line">49</span><br/><span class="line">50</span><br/><span class="line">51</span><br/><span class="line">52</span><br/><span class="line">53</span><br/><span class="line">54</span><br/><span class="line">55</span><br/><span class="line">56</span><br/><span class="line">57</span><br/><span class="line">58</span><br/><span class="line">59</span><br/><span class="line">60</span><br/><span class="line">61</span><br/><span class="line">62</span><br/><span class="line">63</span><br/><span class="line">64</span><br/><span class="line">65</span><br/><span class="line">66</span><br/><span class="line">67</span><br/><span class="line">68</span><br/><span class="line">69</span><br/><span class="line">70</span><br/><span class="line">71</span><br/><span class="line">72</span><br/><span class="line">73</span><br/><span class="line">74</span><br/><span class="line">75</span><br/><span class="line">76</span><br/><span class="line">77</span><br/><span class="line">78</span><br/><span class="line">79</span><br/><span class="line">80</span><br/><span class="line">81</span><br/><span class="line">82</span><br/><span class="line">83</span><br/><span class="line">84</span><br/><span class="line">85</span><br/><span class="line">86</span><br/><span class="line">87</span><br/><span class="line">88</span><br/><span class="line">89</span><br/><span class="line">90</span><br/><span class="line">91</span><br/><span class="line">92</span><br/><span class="line">93</span><br/><span class="line">94</span><br/><span class="line">95</span><br/><span class="line">96</span><br/><span class="line">97</span><br/><span class="line">98</span><br/><span class="line">99</span><br/><span class="line">100</span><br/><span class="line">101</span><br/><span class="line">102</span><br/><span class="line">103</span><br/><span class="line">104</span><br/><span class="line">105</span><br/><span class="line">106</span><br/><span class="line">107</span><br/><span class="line">108</span><br/><span class="line">109</span><br/><span class="line">110</span><br/><span class="line">111</span><br/><span class="line">112</span><br/><span class="line">113</span><br/><span class="line">114</span><br/><span class="line">115</span><br/><span class="line">116</span><br/><span class="line">117</span><br/><span class="line">118</span><br/><span class="line">119</span><br/><span class="line">120</span><br/><span class="line">121</span><br/><span class="line">122</span><br/><span class="line">123</span><br/><span class="line">124</span><br/><span class="line">125</span><br/><span class="line">126</span><br/><span class="line">127</span><br/><span class="line">128</span><br/><span class="line">129</span><br/><span class="line">130</span><br/><span class="line">131</span><br/><span class="line">132</span><br/><span class="line">133</span><br/><span class="line">134</span><br/><span class="line">135</span><br/><span class="line">136</span><br/><span class="line">137</span><br/><span class="line">138</span><br/><span class="line">139</span><br/><span class="line">140</span><br/><span class="line">141</span><br/><span class="line">142</span><br/><span class="line">143</span><br/><span class="line">144</span><br/><span class="line">145</span><br/><span class="line">146</span><br/><span class="line">147</span><br/><span class="line">148</span><br/><span class="line">149</span><br/><span class="line">150</span><br/><span class="line">151</span><br/><span class="line">152</span><br/><span class="line">153</span><br/><span class="line">154</span><br/><span class="line">155</span><br/><span class="line">156</span><br/><span class="line">157</span><br/><span class="line">158</span><br/><span class="line">159</span><br/><span class="line">160</span><br/><span class="line">161</span><br/><span class="line">162</span><br/><span class="line">163</span><br/><span class="line">164</span><br/><span class="line">165</span><br/><span class="line">166</span><br/><span class="line">167</span><br/><span class="line">168</span><br/><span class="line">169</span><br/><span class="line">170</span><br/><span class="line">171</span><br/><span class="line">172</span><br/><span class="line">173</span><br/><span class="line">174</span><br/><span class="line">175</span><br/><span class="line">176</span><br/><span class="line">177</span><br/><span class="line">178</span><br/><span class="line">179</span><br/><span class="line">180</span><br/><span class="line">181</span><br/><span class="line">182</span><br/><span class="line">183</span><br/><span class="line">184</span><br/><span class="line">185</span><br/><span class="line">186</span><br/><span class="line">187</span><br/><span class="line">188</span><br/><span class="line">189</span><br/><span class="line">190</span><br/><span class="line">191</span><br/><span class="line">192</span><br/><span class="line">193</span><br/><span class="line">194</span><br/></pre></td><td class="code"><pre><span class="line"><span class="meta">#! /bin/bash</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment">### FIRST 第一板块</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set PATH" 设置脚本执行环境变量，文件位置，模组路径等</span></span><br/><span class="line"></span><br/><span class="line">JF=/opt/jdk-8u162-linux-x64.tar.gz</span><br/><span class="line">HF=/opt/hadoop-3.3.0.tar.gz</span><br/><span class="line">MP=/opt/module</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set host 设置主机名以及配置host文件" </span></span><br/><span class="line">hostnamectl set-hostname master</span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span>&gt;&gt;<span class="string">"/etc/hosts"</span>&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">192.168.152.81 master</span></span><br/><span class="line"><span class="string">192.168.152.101 slave1</span></span><br/><span class="line"><span class="string">192.168.152.121 slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set ssh key 配置ssh key进行自动连接" </span></span><br/><span class="line"></span><br/><span class="line">ssh-keygen -t rsa <span class="comment"># -n '' -f  ~/.ssh/id_rsa</span></span><br/><span class="line">ssh-copy-id master</span><br/><span class="line">ssh-copy-id slave1</span><br/><span class="line">ssh-copy-id slave2</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set java &amp;&amp; hadoop" 解压配置jdk以及hadoop</span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">mkdir</span> <span class="variable">$MP</span></span><br/><span class="line"><span class="built_in">mkdir</span> <span class="variable">$MP</span>/jdk</span><br/><span class="line">tar -xvzf /opt/jdk-8u162-linux-x64.tar.gz -C <span class="variable">$MP</span>/jdk --strip-components 1</span><br/><span class="line"></span><br/><span class="line"><span class="built_in">mkdir</span> <span class="variable">$MP</span>/hadoop</span><br/><span class="line">tar -xvzf /opt/hadoop-3.3.0.tar.gz -C <span class="variable">$MP</span>/hadoop --strip-components 1</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set PATH 设置jdk以及hadoop的环境变量" </span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span>&gt;&gt;<span class="string">"/root/.bash_profile"</span>&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">export JAVA_HOME=$MP/jdk</span></span><br/><span class="line"><span class="string">export PATH=\$JAVA_HOME/bin:\$PATH</span></span><br/><span class="line"><span class="string">export HADOOP_HOME=$MP/hadoop</span></span><br/><span class="line"><span class="string">export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "check install 查看安装情况"</span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">source</span> /root/.bash_profile</span><br/><span class="line">java -version</span><br/><span class="line">hadoop version</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set slave 设置其他slave节点的主机配置文件" </span></span><br/><span class="line"></span><br/><span class="line">scp -r /root/.bash_profile slave1:/root/</span><br/><span class="line">scp -r /root/.bash_profile slave2:/root/</span><br/><span class="line">scp -r /etc/hosts slave1:/etc/</span><br/><span class="line">scp -r /etc/hosts slave2:/etc/</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># echo "set ssh slave ssh连接设置其他节点"</span></span><br/><span class="line">  </span><br/><span class="line">ssh root@slave1 &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">hostnamectl set-hostname slave1</span></span><br/><span class="line"><span class="string">mkdir $MP</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">ssh-keygen -t rsa -n '' -f  ~/.ssh/id_rsa</span></span><br/><span class="line"><span class="string">ssh-copy-id master</span></span><br/><span class="line"><span class="string">ssh-copy-id slave1</span></span><br/><span class="line"><span class="string">ssh-copy-id slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line">ssh root@slave2 &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">hostnamectl set-hostname slave2</span></span><br/><span class="line"><span class="string">mkdir $MP</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">ssh-keygen -t rsa -n '' -f  ~/.ssh/id_rsa</span></span><br/><span class="line"><span class="string">ssh-copy-id master</span></span><br/><span class="line"><span class="string">ssh-copy-id slave1</span></span><br/><span class="line"><span class="string">ssh-copy-id slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment">### SECOND 第二板块</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># hadoop settings file 设置hadoop配置文件</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 替换 hadoop-env.sh 中的JAVA_HOME PATH文件</span></span><br/><span class="line">sed -i <span class="string">'/export JAVA_HOME=/cexport JAVA_HOME='</span><span class="variable">$MP</span><span class="string">'/jdk'</span> <span class="variable">$MP</span>/hadoop/etc/hadoop/hadoop-env.sh</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置 core-site.xml 文件</span></span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/core-site.xml &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">&lt;configuration&gt;</span></span><br/><span class="line"><span class="string">     &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;fs.defaultFS&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;hdfs://master:9000&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">      &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;hadoop.tmp.dir&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;/opt/module/hadoop/tmp&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">&lt;/configuration&gt;</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置 hdfs-site.xml 文件</span></span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/hdfs-site.xml &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">&lt;configuration&gt;</span></span><br/><span class="line"><span class="string">    &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;dfs.replication&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;3&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">     &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;dfs.namenode.secondary.http-address&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;slave1:50090&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">&lt;/configuration&gt;</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置 mapred-site.xml 文件</span></span><br/><span class="line"><span class="built_in">cp</span> <span class="variable">$MP</span>/hadoop/etc/hadoop/mapred-site.xml.template <span class="variable">$MP</span>/hadoop/etc/hadoop/mapred-site.xml</span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/mapred-site.xml&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">&lt;configuration&gt;</span></span><br/><span class="line"><span class="string">    &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;mapreduce.framework.name&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;yarn&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">&lt;/configuration&gt;</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置 yarn-site.xml 文件</span></span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/yarn-site.xml&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">&lt;configuration&gt;</span></span><br/><span class="line"><span class="string">&lt;!-- Site specific YARN configuration properties --&gt;</span></span><br/><span class="line"><span class="string">     &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;yarn.resourcemanager.hostname&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;master&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">       &lt;property&gt;</span></span><br/><span class="line"><span class="string">         &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt;</span></span><br/><span class="line"><span class="string">            &lt;value&gt;mapreduce_shuffle&lt;/value&gt;</span></span><br/><span class="line"><span class="string">     &lt;/property&gt;</span></span><br/><span class="line"><span class="string">&lt;/configuration&gt;</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置 slaves 文件 hadoop-2.7.7</span></span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/slaves&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">master</span></span><br/><span class="line"><span class="string">slave1</span></span><br/><span class="line"><span class="string">slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 配置workers wenjian hadoop-3.3.0</span></span><br/><span class="line"><span class="built_in">cat</span> &gt; <span class="variable">$MP</span>/hadoop/etc/hadoop/workers&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">master</span></span><br/><span class="line"><span class="string">slave1</span></span><br/><span class="line"><span class="string">slave2</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># hadoop-3.3.0 need to add PATH for start&amp;stop shell hadoop-3.3.0需要添加PATH变量到启动/关闭脚本中</span></span><br/><span class="line"></span><br/><span class="line">sed -i <span class="string">"2i HDFS_DATANODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/start-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HADOOP_SECURE_DN_USER=hdfs"</span> <span class="variable">$MP</span>/hadoop/sbin/start-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HDFS_NAMENODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/start-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HDFS_SECONDARYNAMENODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/start-dfs.sh</span><br/><span class="line"></span><br/><span class="line">sed -i <span class="string">"2i HDFS_DATANODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HADOOP_SECURE_DN_USER=hdfs"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HDFS_NAMENODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh</span><br/><span class="line">sed -i <span class="string">"2i HDFS_SECONDARYNAMENODE_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh</span><br/><span class="line"></span><br/><span class="line">sed -i <span class="string">"2i YARN_RESOURCEMANAGER_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/start-yarn.sh</span><br/><span class="line">sed -i <span class="string">"2i HADOOP_SECURE_DN_USER=yarn"</span> <span class="variable">$MP</span>/hadoop/sbin/start-yarn.sh</span><br/><span class="line">sed -i <span class="string">"2i YARN_NODEMANAGER_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/start-yarn.sh</span><br/><span class="line"></span><br/><span class="line">sed -i <span class="string">"2i YARN_RESOURCEMANAGER_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-yarn.sh</span><br/><span class="line">sed -i <span class="string">"2i HADOOP_SECURE_DN_USER=yarn"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-yarn.sh</span><br/><span class="line">sed -i <span class="string">"2i YARN_NODEMANAGER_USER=root"</span> <span class="variable">$MP</span>/hadoop/sbin/stop-yarn.sh</span><br/><span class="line"></span><br/><span class="line"><span class="comment">### THIRD 第三板块</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># trasnfer module 将配置好的模组路径下的所有文件传输到其他节点</span></span><br/><span class="line">scp -r <span class="variable">$MP</span> slave1:/opt</span><br/><span class="line">scp -r <span class="variable">$MP</span> slave2:/opt</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># check hadoop start 启动hadoop</span></span><br/><span class="line">hdfs namenode -format</span><br/><span class="line"><span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh</span><br/><span class="line"><span class="variable">$MP</span>/hadoop/sbin/stop-yarn.sh</span><br/><span class="line"><span class="variable">$MP</span>/hadoop/sbin/start-dfs.sh</span><br/><span class="line"><span class="variable">$MP</span>/hadoop/sbin/start-yarn.sh</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 检查启动情况</span></span><br/><span class="line">hostnamectl</span><br/><span class="line">jps</span><br/><span class="line"></span><br/><span class="line">ssh root@slave1 <span class="string">"source /root/.bash_profile &amp;&amp; hostnamectl &amp;&amp; jps"</span></span><br/><span class="line">ssh root@slave2 <span class="string">"source /root/.bash_profile &amp;&amp; hostnamectl &amp;&amp; jps"</span></span><br/></pre></td></tr></table></figure><h2 id="其他操作"><a class="markdownIt-Anchor" href="#其他操作"></a> 其他操作</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br/><span class="line">2</span><br/><span class="line">3</span><br/><span class="line">4</span><br/><span class="line">5</span><br/><span class="line">6</span><br/><span class="line">7</span><br/><span class="line">8</span><br/><span class="line">9</span><br/><span class="line">10</span><br/><span class="line">11</span><br/><span class="line">12</span><br/><span class="line">13</span><br/><span class="line">14</span><br/><span class="line">15</span><br/><span class="line">16</span><br/><span class="line">17</span><br/><span class="line">18</span><br/><span class="line">19</span><br/><span class="line">20</span><br/><span class="line">21</span><br/><span class="line">22</span><br/><span class="line">23</span><br/><span class="line">24</span><br/><span class="line">25</span><br/><span class="line">26</span><br/><span class="line">27</span><br/><span class="line">28</span><br/><span class="line">29</span><br/><span class="line">30</span><br/><span class="line">31</span><br/><span class="line">32</span><br/><span class="line">33</span><br/><span class="line">34</span><br/><span class="line">35</span><br/><span class="line">36</span><br/><span class="line">37</span><br/><span class="line">38</span><br/><span class="line">39</span><br/><span class="line">40</span><br/><span class="line">41</span><br/><span class="line">42</span><br/><span class="line">43</span><br/><span class="line">44</span><br/><span class="line">45</span><br/><span class="line">46</span><br/><span class="line">47</span><br/><span class="line">48</span><br/><span class="line">49</span><br/><span class="line">50</span><br/><span class="line">51</span><br/><span class="line">52</span><br/><span class="line">53</span><br/><span class="line">54</span><br/><span class="line">55</span><br/><span class="line">56</span><br/><span class="line">57</span><br/><span class="line">58</span><br/><span class="line">59</span><br/><span class="line">60</span><br/><span class="line">61</span><br/><span class="line">62</span><br/><span class="line">63</span><br/><span class="line">64</span><br/><span class="line">65</span><br/><span class="line">66</span><br/><span class="line">67</span><br/><span class="line">68</span><br/></pre></td><td class="code"><pre><span class="line"><span class="comment"># 覆盖文件</span></span><br/><span class="line"><span class="built_in">cat</span>&gt;<span class="string">"/etc/hosts"</span>&lt;&lt;<span class="string">EOF </span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 在文件末尾添加</span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span>&gt;&gt;<span class="string">"/etc/hosts"</span>&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 自动ssh配置</span></span><br/><span class="line">sed -i <span class="string">'/StrictHostKeyChecking/cStrictHostKeyChecking no'</span> /etc/ssh/ssh_config</span><br/><span class="line"><span class="built_in">rm</span> -rf ~/.ssh/&#123;known_hosts,id_rsa*&#125;</span><br/><span class="line"></span><br/><span class="line"><span class="comment"># tar末尾添加参数--strip-components 1 可以去掉最外层的目录</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 目录更改重命名</span></span><br/><span class="line"><span class="built_in">mv</span> <span class="variable">$MP</span>/hadoop-2.7.7 <span class="variable">$MP</span>/hadoop</span><br/><span class="line"><span class="built_in">mv</span> <span class="variable">$MP</span>/jdk1.8.0_162 <span class="variable">$MP</span>/jdk</span><br/><span class="line"></span><br/><span class="line">ssh root@slave1 <span class="string">"source /root/.bash_profile"</span></span><br/><span class="line">ssh root@slave2 &gt; /dev/null 2&gt;&amp;1 &lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string"># JAVA_HOME路径直接添加</span></span><br/><span class="line"><span class="string">echo "export JAVA_HOME=$MP/jdk" &gt;&gt; $MP/hadoop/etc/hadoop/hadoop-env.sh</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string"># 传输hadoop的配置文件所在目录</span></span><br/><span class="line"><span class="string">scp -r $MP/hadoop/etc/hadoop slave1:$MP/hadoop/etc</span></span><br/><span class="line"><span class="string">scp -r $MP/hadoop/etc/hadoop slave2:$MP/hadoop/etc</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string"># dfs启动脚本添加参数，不能直接使用，需要添加到文件头</span></span><br/><span class="line"><span class="string">cat &gt;&gt; $MP/hadoop/sbin/start-dfs.sh&lt;&lt;EOF</span></span><br/><span class="line"></span><br/><span class="line">HDFS_DATANODE_USER=root</span><br/><span class="line">HADOOP_SECURE_DN_USER=hdfs</span><br/><span class="line">HDFS_NAMENODE_USER=root</span><br/><span class="line">HDFS_SECONDARYNAMENODE_USER=root</span><br/><span class="line"></span><br/><span class="line">EOF</span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span> &gt;&gt; <span class="variable">$MP</span>/hadoop/sbin/stop-dfs.sh&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">HDFS_DATANODE_USER=root</span></span><br/><span class="line"><span class="string">HADOOP_SECURE_DN_USER=hdfs</span></span><br/><span class="line"><span class="string">HDFS_NAMENODE_USER=root</span></span><br/><span class="line"><span class="string">HDFS_SECONDARYNAMENODE_USER=root</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span> &gt;&gt; <span class="variable">$MP</span>/hadoop/sbin/start-yarn.sh&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">YARN_RESOURCEMANAGER_USER=root</span></span><br/><span class="line"><span class="string">HADOOP_SECURE_DN_USER=yarn</span></span><br/><span class="line"><span class="string">YARN_NODEMANAGER_USER=root</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="built_in">cat</span> &gt;&gt; <span class="variable">$MP</span>/hadoop/sbin/stop-yarn.sh&lt;&lt;<span class="string">EOF</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">YARN_RESOURCEMANAGER_USER=root</span></span><br/><span class="line"><span class="string">HADOOP_SECURE_DN_USER=yarn</span></span><br/><span class="line"><span class="string">YARN_NODEMANAGER_USER=root</span></span><br/><span class="line"><span class="string"></span></span><br/><span class="line"><span class="string">EOF</span></span><br/><span class="line"></span><br/><span class="line"><span class="comment"># 传输hadoop启动脚本文件</span></span><br/><span class="line">scp -r <span class="variable">$MP</span>/hadoop/sbin slave1:<span class="variable">$MP</span>/hadoop</span><br/><span class="line">scp -r <span class="variable">$MP</span>/hadoop/sbin slave2:<span class="variable">$MP</span>/hadoop</span><br/><span class="line"></span><br/></pre></td></tr></table></figure></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="hadoop安装竞赛文档" href="http://blog.imc.re/archives/1385.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">hadoop安装竞赛文档</span><span class="cap link fs12">http://blog.imc.re/archives/1385.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>MCBE 88音平均律</title>
    <link href="https://blog.imc.re/RSSBOX/rss/824ee0f8.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/824ee0f8.html</id>
    <published>2023-05-13T23:51:38.000Z</published>
    <updated>2023-05-13T23:51:38.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>今天修IMC Geyser的时候看到冲田在烷MC，随便试了试Xbox联机没想到进去了）然后冲田似乎在研究playsound的调音，我才知道原来MCBE的playsound命令还有微分音的用法（红石音乐人狂喜x）通过微分音的调教，理论上突破原版材质包里自带的音符盒音域，实现88音的完整钢琴音域就可能实现了，如果再搭配上midi文件的转化就可以实现在MC游戏里不依靠任何材质包，mod等就能实现音乐的播放！</p><p>虽然已经有相关的项目了，比如 <a href="https://opennbs.org/">Open Note Block Studio</a> 就已经实现了nbs音乐相关的编辑，以及midi文件的转换。不过这个工具目前只支持MCJE，并不支持MCBE，扩展音域似乎也是通过扩展音符包来实现的，相对繁琐。本文主要记录一下MCBE的playsound调音对应88键平均律的对应数值以及方法，虽然不一定在MCJE适用，但是基本方法应该是差不多的，可以作为参考留档。</p><h1 id="基本知识"><a class="markdownIt-Anchor" href="#基本知识"></a> 基本知识</h1><p>让我们先来复习一下初中基本物理知识——声音的基本三要素：</p><ul><li>音色：波形决定了声音的音调。由于不同对象材料的特点，声音具有不同的特性，音色本身就是抽象的东西，但波形就是把这种抽象和直观的性能。波形因音调而异，不同的音调可以通过波形来区分。</li><li>音调：声音的高低由频率决定，频率越高音调越高，人耳听觉范围20—20000Hz；20Hz以下称为次声波，20000Hz以上称为超声波。</li><li>响度：指人耳感觉到的声音强弱，即声音响亮的程度，根据它可以把声音排成由轻到响的序列。响度的大小主要依赖于声强和频率，振幅越大响度越大，人和声源的距离越小，响度越大。</li></ul><p>而这三要素在Minecraft的 <code>/playsound</code> 指令里基本算是都齐活了，声音的基本三要素和MC指令的信息对应还是需要说明一下（毕竟wiki没提）：</p><p>MCBE的 /playsound 指令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">/playsound &lt;sound: string&gt; [player: target] [position: x y z] [volume: float] [pitch: float] [minimumVolume: float]</span><br/></pre></td></tr></table></figure><p>示例指令：音色为 <code>note.pling</code> ，音调为 <code>中央C（C4）</code> ，播放给全局玩家。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">/playsound note.pling @a ~~~ 9999 0.7</span><br/></pre></td></tr></table></figure><p><img alt="指令预览" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/202305141550245.png"/></p><p>简单说明：</p><ul><li>音色：对应的 <code>&lt;sound: string&gt;</code> ，只能调用 <a href="https://minecraft.fandom.com/zh/wiki/Sounds.json#%E5%A3%B0%E9%9F%B3%E4%BA%8B%E4%BB%B6" title="Sounds.json">sounds.json</a> 里的项目，具体的可以去Minecraft Wiki或者自行拆包查看，有预览表，也可以使用自制的材质包实现自定义音色。值得一提的是MC中所有的音效都可以使用。这里列几个常用的Note音色：<ul><li><code>note.harp</code> 音符盒音色，算是MC红石音乐比较标志性的音色。类似音色：  <code>note.pling</code>  ，声音比较洪亮，音长相对较长。</li><li><code>note.guitar</code> 音符盒吉他音色，拨弦乐器声音采样比较短促，类似音色： <code>note.banjo</code>  班卓琴音色</li><li><code>note.bass</code> 音符盒贝斯音色，低音必备。类似音色： <code>note.bassattack</code></li><li><code>note.hat</code> 音符盒打击音色，可以当鼓点使用。类似音色： <code>note.bd</code> <code>note.snare</code></li><li><code>note.flute</code> 音符盒笛声音色，使用高频播放的话可以达到延音的效果（吹奏类乐器音色的好处，采样出来的音色首尾相接基本不会有违和感，《光遇》里的乐器演奏也能用类似的方法实现延音。）类似音色： <code>note.didgeridoo</code> 有点低音号的感觉，但是高频播放不是很连贯。</li><li><code>note.bit</code> bit音乐采样音色，算是电子音乐比较经典的音色。类似音色： <code>note.bell</code> 八音盒感觉的音色， <code>note.cow_bell</code> 相对低沉的八音盒感觉的音色</li></ul></li><li>音调：对应的 <code>[pitch: float]</code> ，以数值的形式表现，默认是 <code>1</code> ，在 <code>note.pling</code> 中对应十二平均律中的 <code>F#</code> 。这种对应关系也是本文的重点，大概是通过程序将音色移调的参数，通过这种方式即便不把所有音符采样塞进游戏里<strong>理论上也能实现十二平均律，以及对应的钢琴八十八键的复原</strong>。</li><li>响度：响度有些特殊，决定响度的是 <code>[player: target] [position: x y z] [volume: float] [minimumVolume: float]</code> 这三个参数决定，依次是玩家目标，声音发生的位置，能够听到声音的范围，和补偿范围。没有直接影响响度的变量，不过可以通过这些参数间歇性的实现响度的控制，甚至环绕音的混响实现也是有可能的。</li></ul><p>详细参数说明：</p><blockquote><p><code>sound: string</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#basic_string" title="参数类型">basic_string</a></p><p>指定要播放的声音。必须为在<a href="https://minecraft.fandom.com/zh/wiki/Sounds.json#%E5%A3%B0%E9%9F%B3%E4%BA%8B%E4%BB%B6" title="Sounds.json">sounds.json</a>中被定义的一个声音项目（例如，<code>entity.pig.ambient</code>）。</p><p>一个声音项目可被多个不同的声音关联，而实际产生的声音为从中随机挑选的结果，被选中的概率由其权重决定，与正常游戏中相同。例如，声音项目<code>entity.pig.ambient</code>会随机播放多种猪音效之一，因为有多个声音关联于该项目。</p><p><a href="https://minecraft.fandom.com/zh/wiki/%E8%B5%84%E6%BA%90%E5%8C%85" title="资源包">资源包</a>可能会向sounds.json中添加额外的声音项目；此命令可以正常播放这些项目。该命令使用的声音名称<strong>不是</strong>文件名；而是严格使用sounds.json内定义的项目（项目名称可能与实际音频文件的文件名和目录相差甚远），因此资源包在添加新声音时必须为这些音频文件定义声音事件项目（但当资源包替换原有的已被定义的音频文件时，不必为其重新定义）。</p><p><code>player: target</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#CommandSelector%3CPlayer%3E" title="参数类型">CommandSelector Player</a></p><p>指定播放声音的目标。</p><p>必须为玩家名、目标选择器或<a href="https://minecraft.fandom.com/zh/wiki/UUID" title="UUID">UUID</a>。且目标选择器只允许玩家。</p><p><code>position: x y z</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#CommandPositionFloat" title="参数类型">CommandPositionFloat</a></p><p>指定声音发出的方位。</p><p>必须为三维坐标，元素为浮点数。允许<a href="https://minecraft.fandom.com/zh/wiki/%E5%91%BD%E4%BB%A4#%E7%9B%B8%E5%AF%B9%E5%9D%90%E6%A0%87%E5%92%8C%E5%B1%80%E9%83%A8%E5%9D%90%E6%A0%87" title="命令">波浪号与脱字号标记</a>。</p><p><code>volume: float</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#float" title="参数类型">float</a></p><p>指定声音能被听见的距离。必须至少为0.0。对小于1.0的值，声音会相对减轻，球状可闻范围会相对小。对大于1.0的值，声音不会实际上增大，但其可闻范围（1.0时半径为16米）会与_音量_相乘。声音总会基于与球体中心的距离逐渐衰减至无声。默认为1.0。</p><p>必须为<a href="https://en.wikipedia.org/wiki/zh:%E5%96%AE%E7%B2%BE%E5%BA%A6%E6%B5%AE%E9%BB%9E%E6%95%B8" title="wikipedia:zh:单精度浮点数">单精度浮点数</a>。在<a href="https://minecraft.fandom.com/zh/wiki/Java%E7%89%88" title="Java版">Java版</a>中，必须大于等于0.0。</p><p><code>pitch: float</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#float" title="参数类型">float</a></p><p>指定声音的音调。若未指定，默认为1.0。</p><p>在<a href="https://minecraft.fandom.com/zh/wiki/Java%E7%89%88" title="Java版">Java版</a>中，该数值必须在0.0至2.0间（含），而小于0.5的值与0.5等价。小于1.0的值降低音调而提升持续时间；大于1.0的值提升音调而降低持续时间。音调值是乘在声音频率上的一个倍率，因此若将0.5-1.0（含）区间内的音调值乘以2，所得的新音调便会高一个八度。</p><p>在<a href="https://minecraft.fandom.com/zh/wiki/%E5%9F%BA%E5%B2%A9%E7%89%88" title="基岩版">基岩版</a>中，该数字没有特别限制，但是必须要在0.0至256.0之间才有对应效果。高于256.0的值与默认值的效果相同。小于等于0.0的值会导致听不到该声音。</p><ul><li>对于<a href="https://minecraft.fandom.com/zh/wiki/%E9%9F%B3%E7%AC%A6%E7%9B%92" title="音符盒">音符盒</a>的声音，如果你希望将其他音符转换为音调数值，请参阅<a href="https://minecraft.fandom.com/zh/wiki/%E9%9F%B3%E7%AC%A6%E7%9B%92#%E7%94%A8%E9%80%94" title="音符盒">相关内容</a>。但请注意1.0的音调值对于每种声音并不一定都是F♯。</li></ul><p><code>minimumVolume: float</code>：<a href="https://minecraft.fandom.com/zh/wiki/%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B#float" title="参数类型">float</a></p><p>指定在声音可闻范围外的目标能听到的音量。若目标在可闻范围外，作为补偿，声源会被放置在距离目标较近的位置（距离小于4格），而<code>_最小音量_</code>会决定补偿声源的音量。</p><p>如果此数值等于0，则正常可闻范围外的目标听不到声音。如果未指定，则默认为0.0。</p><p>必须为<a href="https://en.wikipedia.org/wiki/zh:%E5%96%AE%E7%B2%BE%E5%BA%A6%E6%B5%AE%E9%BB%9E%E6%95%B8" title="wikipedia:zh:单精度浮点数">单精度浮点数</a>。在<a href="https://minecraft.fandom.com/zh/wiki/Java%E7%89%88" title="Java版">Java版</a>中，必须在0.0和1.0（含）之间。</p><p>——<a href="https://minecraft.fandom.com/zh/wiki/%E5%91%BD%E4%BB%A4/playsound">《命令/playsound - Minecraft Wiki》</a></p></blockquote><p>有这三要素基本就满足了声音构成的条件，但是把范围缩小到 <code>音乐</code> 当中，光有这基本三要素是不够的，关于 <code>音调</code> 的使用范围至关重要，而在乐理中基本的音调构成范围就不得不提到 <strong>十二平均律</strong> 了：</p><blockquote><p><strong>十二平均律</strong>（12-equal temperament）又称<strong>十二等程律</strong>，是世界上通用的一组音（八度）分成十二个<a href="https://baike.baidu.com/item/%E5%8D%8A%E9%9F%B3/20378032?fromModule=lemma_inlink">半音</a><a href="https://baike.baidu.com/item/%E9%9F%B3%E7%A8%8B/18483922?fromModule=lemma_inlink">音程</a>的<a href="https://baike.baidu.com/item/%E5%BE%8B%E5%88%B6/6785021?fromModule=lemma_inlink">律制</a>，各相邻两律之间的波长之比完全相等。 十二平均律是由中国明朝皇族世子<a href="https://baike.baidu.com/item/%E6%9C%B1%E8%BD%BD%E5%A0%89/1182870?fromModule=lemma_inlink">朱载堉</a>发现。</p><p>十二平均律是指八度的音程按波长比例平均分成十二等份，每一等份称为一个半音（<a href="https://baike.baidu.com/item/%E5%B0%8F%E4%BA%8C%E5%BA%A6/3316765?fromModule=lemma_inlink">小二度</a>）。一个<a href="https://baike.baidu.com/item/%E5%A4%A7%E4%BA%8C%E5%BA%A6/3269655?fromModule=lemma_inlink">大二度</a>则是两等份，称为<a href="https://baike.baidu.com/item/%E5%85%A8%E9%9F%B3/10997917?fromModule=lemma_inlink">全音</a>。将一个八度分成12等份有着惊人的一些巧合。这是因为它的纯<a href="https://baike.baidu.com/item/%E4%BA%94%E5%BA%A6/8803536?fromModule=lemma_inlink">五度</a>音程的两个音的波长比（即1/2的7/12次方）约为0.6674，与2/3，约为0.6667，非常接近。</p><p><strong>十二平均律在<a href="https://baike.baidu.com/item/%E4%BA%A4%E5%93%8D%E4%B9%90%E9%98%9F/10995603?fromModule=lemma_inlink">交响乐队</a>和<a href="https://baike.baidu.com/item/%E9%94%AE%E7%9B%98%E4%B9%90%E5%99%A8/5194554?fromModule=lemma_inlink">键盘乐器</a>中得到广泛使用，钢琴即是根据十二平均律来定音的。</strong></p><p>——<a href="https://baike.baidu.com/item/%E5%8D%81%E4%BA%8C%E5%B9%B3%E5%9D%87%E5%BE%8B/592297?fr=aladdin">十二平均律_百度百科 (baidu.com)</a></p></blockquote><p><img alt="十二平均律图表" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/202305211306495.png"/></p><p>可能有人会问为什么要拘泥于十二平均律？使用微分音创作音乐不是也很新吗？其实这么想也不是不可以，不过截至目前，人类的基本音乐创作理论体系 <s>（俗称乐理）</s> 还“局限”于基于十二平均律中，因此，想要作出“给人听”的音乐十二平均律的存在是不可或缺的。当然科技发展至今，使用微分音创作的电子音乐也不算少数，这个就因人而异咯xd 借用《海上钢琴师》里我印象深刻的经典台词来说：</p><blockquote><p>Take a piano. The keys begin, the keys end. You know there are eightyeight of them, nobody can tell you any different. They are not infinite. You are infinite. And on these keys the music that you can make is infinite. I like that. That I can live by.</p><p>译：拿一架钢琴来说，从琴键开始，又结束。**你知道钢琴只有88个键，随便什么琴都没差。它们不是无限的。你才是无限的，在琴键上制作出的音乐是无限的。**我喜欢这样，我活的惯。</p></blockquote><hr/><h1 id="mc中的平均律"><a class="markdownIt-Anchor" href="#mc中的平均律"></a> MC中的平均律</h1><p>理论成立，实践开始！Minecraft原版中的音符盒的音域只有F#3到F#5的25个键，想要还原钢琴八十八键的音域一般来说只有扩展材质包，mod之类的办法。</p><p><img alt="image-20230514173645051" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/202305141736378.png"/></p><p><strong>但是通过 <code>/playsound</code> 指令中的  <code>[pitch: float]</code> 调音参数就能实现原版MC不使用任何外部资源加持的前提下实现88键钢琴音域的还原！</strong> （甚至超出88键都有可能xd）那么在这其中需要实现各个键位的音调还原，Minecraft中 pitch参数和十二平均律的对应关系是必不可少的。</p><p>本来以为是很简单的正比线性对应关系，但是试了几个数之后感觉有点不对。。比如 p=1 的时候音色 <code>note.pling</code> 对应的是 F#4， p=2 的时候对应的是 F#5，但是到 F#3的时候对应的 p=0.5 ，并不是一般的一次函数线性关系。</p><p>通过冲田分享的文章 <a href="https://www.bilibili.com/read/cv4773559">【我的世界】playsound钢琴全键音调值 - 哔哩哔哩 (bilibili.com)</a> 知道了基本的对应关系式~~（不知道是怎么来的，不过随机抽样了几个数试了试大概是对的，就按这个公式来看吧x）~~：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>=</mo><msup><mn>2</mn><mfrac><mrow><mo fence="true">(</mo><mi>n</mi><mo>−</mo><mn>12</mn><mo fence="true">)</mo></mrow><mn>12</mn></mfrac></msup></mrow><annotation encoding="application/x-tex">p=2^&#123;\frac&#123;\left(n-12\right)&#125;&#123;12&#125;&#125;</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.13945em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.13945em;"><span style="top:-3.4130000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0377857142857143em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.5020714285714285em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="minner mtight"><span class="mopen mtight delimcenter" style="top:0em;"><span class="mtight">(</span></span><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span><span class="mord mtight">2</span><span class="mclose mtight delimcenter" style="top:0em;"><span class="mtight">)</span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><p><img alt="image.png" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/202305141803364.png"/></p><p>其中 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi></mrow><annotation encoding="application/x-tex">p</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span></span></span></span> 代表的是 <code>[pitch: float]</code> 中的数值，而 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> 则是十二平均律中的数值关系， <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> 的整数之间都是半音关系，比如在音色 <code>note.pling</code> 中， <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">n=0</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span> 的时候对应 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>=</mo><mn>0.5</mn></mrow><annotation encoding="application/x-tex">p=0.5</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">.</span><span class="mord">5</span></span></span></span> ，对应的 F#3 , <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><mn>12</mn></mrow><annotation encoding="application/x-tex">n=12</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">2</span></span></span></span> 的时候对应 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">p=1</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span> 对应的 F#4，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><mn>24</mn></mrow><annotation encoding="application/x-tex">n=24</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">4</span></span></span></span> 的时候对应 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">p=2</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> ...... 以此类推，便能得到钢琴八十八键对应的音符音调了。</p><p><img alt="钢琴频谱" src="https://cdn.jsdelivr.net/gh/SMGCDN/photos/uploads/202305211308820.png"/></p><p>值得一提的是，MC中所有可以使用的音效对应的基准因，也就是 p=1 对应的音，并不一定都是 F# ，但是就目前来看，所有 <code>Note</code> 类型的音色对应的基准音都是 F#，所以以 F# 为基准音的基础上去测试以及记录对应的88音平均律的基本关系，如果有基准因不是 F# 的，也可以通过参考这个基准音对应关系来进行平移得到相对应的平均律谱表。</p><h2 id="88音平均律谱表"><a class="markdownIt-Anchor" href="#88音平均律谱表"></a> 88音平均律谱表</h2><p>以 <code>note.pling</code> 音色为基准，通过 p=1 F#3 的基本音关系延伸，根据 p=2^((n-12)/12) 的关系式，测试计算出来的平均律谱表如下（p取值为小数点后四位数）：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>=</mo><msup><mn>2</mn><mfrac><mrow><mo fence="true">(</mo><mi>n</mi><mo>−</mo><mn>12</mn><mo fence="true">)</mo></mrow><mn>12</mn></mfrac></msup></mrow><annotation encoding="application/x-tex">p=2^&#123;\frac&#123;\left(n-12\right)&#125;&#123;12&#125;&#125;</annotation></semantics></math></span><span aria-hidden="true" class="katex-html"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.13945em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.13945em;"><span style="top:-3.4130000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0377857142857143em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.5020714285714285em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="minner mtight"><span class="mopen mtight delimcenter" style="top:0em;"><span class="mtight">(</span></span><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span><span class="mord mtight">2</span><span class="mclose mtight delimcenter" style="top:0em;"><span class="mtight">)</span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><p>测试指令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br/></pre></td><td class="code"><pre><span class="line">/playsound note.harp @a ~~~ 1 p</span><br/></pre></td></tr></table></figure><table><thead><tr><th style="text-align:center">n</th><th style="text-align:center">p</th><th style="text-align:center">音符</th><th style="text-align:center">音域</th></tr></thead><tbody><tr><td style="text-align:center">-33</td><td style="text-align:center">0.0743</td><td style="text-align:center">A</td><td style="text-align:center">0</td></tr><tr><td style="text-align:center">-32</td><td style="text-align:center">0.0787</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-31</td><td style="text-align:center">0.0834</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-30</td><td style="text-align:center">0.0884</td><td style="text-align:center">C</td><td style="text-align:center">1</td></tr><tr><td style="text-align:center">-29</td><td style="text-align:center">0.0936</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-28</td><td style="text-align:center">0.0992</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-27</td><td style="text-align:center">0.1051</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-26</td><td style="text-align:center">0.1114</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-25</td><td style="text-align:center">0.1180</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-24</td><td style="text-align:center">0.1250</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-23</td><td style="text-align:center">0.1324</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-22</td><td style="text-align:center">0.1403</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-21</td><td style="text-align:center">0.1487</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-20</td><td style="text-align:center">0.1575</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-19</td><td style="text-align:center">0.1669</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-18</td><td style="text-align:center">0.1768</td><td style="text-align:center">C</td><td style="text-align:center">2</td></tr><tr><td style="text-align:center">-17</td><td style="text-align:center">0.1873</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-16</td><td style="text-align:center">0.1984</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-15</td><td style="text-align:center">0.2102</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-14</td><td style="text-align:center">0.2227</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-13</td><td style="text-align:center">0.2360</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-12</td><td style="text-align:center">0.2500</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-11</td><td style="text-align:center">0.2649</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-10</td><td style="text-align:center">0.2806</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-9</td><td style="text-align:center">0.2973</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-8</td><td style="text-align:center">0.3150</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-7</td><td style="text-align:center">0.3337</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-6</td><td style="text-align:center">0.3536</td><td style="text-align:center">C</td><td style="text-align:center">3</td></tr><tr><td style="text-align:center">-5</td><td style="text-align:center">0.3746</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-4</td><td style="text-align:center">0.3969</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-3</td><td style="text-align:center">0.4204</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-2</td><td style="text-align:center">0.4454</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">-1</td><td style="text-align:center">0.4719</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">0</td><td style="text-align:center">0.5000</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">1</td><td style="text-align:center">0.5297</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">0.5612</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">3</td><td style="text-align:center">0.5946</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">4</td><td style="text-align:center">0.6300</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">5</td><td style="text-align:center">0.6674</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">6</td><td style="text-align:center">0.7071</td><td style="text-align:center">C</td><td style="text-align:center">4</td></tr><tr><td style="text-align:center">7</td><td style="text-align:center">0.7492</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">8</td><td style="text-align:center">0.7937</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">9</td><td style="text-align:center">0.8409</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">10</td><td style="text-align:center">0.8909</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">11</td><td style="text-align:center">0.9439</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">12</td><td style="text-align:center">1.0000</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">13</td><td style="text-align:center">1.0595</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">14</td><td style="text-align:center">1.1225</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">15</td><td style="text-align:center">1.1892</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center">1.2599</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">17</td><td style="text-align:center">1.3348</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">18</td><td style="text-align:center">1.4142</td><td style="text-align:center">C</td><td style="text-align:center">5</td></tr><tr><td style="text-align:center">19</td><td style="text-align:center">1.4983</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">20</td><td style="text-align:center">1.5874</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">21</td><td style="text-align:center">1.6818</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">22</td><td style="text-align:center">1.7818</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">23</td><td style="text-align:center">1.8877</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">24</td><td style="text-align:center">2.0000</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">25</td><td style="text-align:center">2.1189</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">26</td><td style="text-align:center">2.2449</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">27</td><td style="text-align:center">2.3784</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">28</td><td style="text-align:center">2.5198</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">29</td><td style="text-align:center">2.6697</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">30</td><td style="text-align:center">2.8284</td><td style="text-align:center">C</td><td style="text-align:center">6</td></tr><tr><td style="text-align:center">31</td><td style="text-align:center">2.9966</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">32</td><td style="text-align:center">3.1748</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">33</td><td style="text-align:center">3.3636</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">34</td><td style="text-align:center">3.5636</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">35</td><td style="text-align:center">3.7755</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">36</td><td style="text-align:center">4.0000</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">37</td><td style="text-align:center">4.2379</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">38</td><td style="text-align:center">4.4898</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">39</td><td style="text-align:center">4.7568</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">40</td><td style="text-align:center">5.0397</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">41</td><td style="text-align:center">5.3394</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">42</td><td style="text-align:center">5.6569</td><td style="text-align:center">C</td><td style="text-align:center">7</td></tr><tr><td style="text-align:center">43</td><td style="text-align:center">5.9932</td><td style="text-align:center">C#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">44</td><td style="text-align:center">6.3496</td><td style="text-align:center">D</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">45</td><td style="text-align:center">6.7272</td><td style="text-align:center">D#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">46</td><td style="text-align:center">7.1272</td><td style="text-align:center">E</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">47</td><td style="text-align:center">7.5510</td><td style="text-align:center">F</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">48</td><td style="text-align:center">8.0000</td><td style="text-align:center">F#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">49</td><td style="text-align:center">8.4757</td><td style="text-align:center">G</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">50</td><td style="text-align:center">8.9797</td><td style="text-align:center">G#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">51</td><td style="text-align:center">9.5137</td><td style="text-align:center">A</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">52</td><td style="text-align:center">10.0794</td><td style="text-align:center">A#</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">53</td><td style="text-align:center">10.6787</td><td style="text-align:center">B</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">54</td><td style="text-align:center">11.3137</td><td style="text-align:center">C</td><td style="text-align:center">8</td></tr></tbody></table><p>以上表格使用Excel计算 原文件 <s>（懒人一个xd）</s> ：<a href="https://docs.qq.com/sheet/DZWlER3ZjcXhFRFZz?tab=BB08J2">【腾讯文档】MC音律表</a></p><hr/><h1 id="结语"><a class="markdownIt-Anchor" href="#结语"></a> 结语</h1><p>从未设想过的道路）如果能加上midi转换的话，那么直接在MC里制作音乐也是完全有可能的了（确信。虽然有了nbs音乐，但是nbs本身并不支持在原版MC中直接播放，虽然可以用NBS Studio进行转换，但是目前NBS Studio也不支持MC基岩版，以及原版适配中目前似乎并没有支持到用命令扩展音域的地步（不过高版本mcfunction似乎可行。？）能在原生的MC里实现88音律表，也方便以后创作红石音乐的人们。</p><p>简单的一次尝试，也学到了不少东西，xd</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="MCBE 88音平均律" href="http://blog.imc.re/archives/7d13.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">MCBE 88音平均律</span><span class="cap link fs12">http://blog.imc.re/archives/7d13.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>Nostr浅尝记录</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ab2923a2.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ab2923a2.html</id>
    <published>2023-05-12T01:59:13.000Z</published>
    <updated>2023-05-12T01:59:13.000Z</updated>
    
    <content type="html"><![CDATA[<div><link class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css" rel="stylesheet"/><script class="aplayer-secondary-script-marker" src="/assets/js/APlayer.min.js"></script><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>Nostr是什么？一句话总结nostr：<strong>基本成型的去中心化的社交网络。</strong></p><p>其实相关的概念已经见到过不少了，“去中心化”也是最近网上的热点 <s>(嘛，多半都是被比特币炒上去的热度就是了，实际上关注技术和应用本身的人并不算很多x)</s> 而Nostr就是“去中心化社交网络”的具体体现之一（似乎有别的，不过我没接触过x）</p><span id="more"></span><p>我本身对“去中心化”其实也有一定的兴趣和倾向，不过个人技术力属实有限，能做到的事情太少，充其量也就是看看别人做的现成品x。不过经过大半天的琢磨体验下来，稍稍总结了一些心得。尽管在自己的nostr账户上也发布了，不过由于无法修改/删除，故不公开，只写在博客上作为记录（毕竟博客的数据是自己的x）</p><h2 id="nostr相关链接"><a class="markdownIt-Anchor" href="#nostr相关链接"></a> nostr相关链接</h2><blockquote><p>为了研究nostr专门把edge开了个分类，感觉浏览器快被我用成图书馆了x</p></blockquote><ul><li>Nostr Client项目：<ul><li><a href="https://github.com/vitorpamplona/amethyst">vitorpamplona/amethyst: Nostr client for Android (github.com)</a> Android开源客户端，功能还是比较齐全的，自动翻译，画廊功能算是特色吧，对于node节点的检测也比较人性化，以及具有群组聊天功能，如果有个国内能直连的node节点的话体验还是很不错的。</li><li><a href="https://github.com/damus-io/damus">damus-io/damus: iOS nostr client (github.com)</a> IOS开源客户端，因为没有苹果设备所以没体验过，不过挺出名的倒是x</li><li><a href="https://iris.to/">iris</a> 网页客户端，同时具有iOS/Android的客户端。基本操作还是比较友好的，也有多语言实现，就是一开始从哪看其他信息有点摸不着头脑x，另外功能比较简单，只实现了基本的功能，没太多特色亮点，值得一提的是有类似Twitter那样的自定义ID的功能，比如 <a href="https://iris.to/smgoro">https://iris.to/smgoro</a> 这样的。似乎还会注册NIP-05 Address，不过这是什么我不太清楚，有待研究。<ul><li><a href="https://github.com/irislib/iris-messenger">irislib/iris-messenger: Decentralized messenger (github.com)</a> 开源客户端仓库。</li></ul></li><li><a href="https://github.com/lovvtide/satellite-web">lovvtide/satellite-web: Satellite nostr client (github.com)</a> 在线体验网址 <a href="https://satellite.earth/">https://satellite.earth/</a> 一个非常风格化的网页客户端，似乎有不少奇奇怪怪的功能（待开发），没有i18n支持，也没有中文，不过还是值得一看的。</li><li><a href="https://github.com/digi-monkey/flycat-web">digi-monkey/flycat-web：马上在Nostr上写博客 (github.com)</a> 国人开发的网页客户端，理念是在Nostr上写博客，总的来说还是挺不错的，不过目前来说写博客还是自己的博客更方便些x，而且美中不足的就是UI方面还差了点火候）要是能完善一下就更好了。在线体验网址： <a href="http://flycat.club/">flycat.club</a></li><li><a href="https://github.com/styppo/hamstr">styppo/hamstr: A twitter-style Nostr web client (github.com)</a> 模仿Twitter风格的网页客户端，UI很好看~~（不如说大多数Nostr客户端UI都是模仿Twitter做的就是了）~~，但是功能上似乎有些缺陷，我用他的在线体验网址 <a href="https://hamstr.to/">hamstr.to</a> 试了试，登录账号之后刷新就什么都做不了了，很怪。如果能和flycat结合一下那大概是蕨杀。</li></ul></li><li>Nostr node项目：参考 <a href="https://nostrtips.com/?p=259">自建Nostr中继器 - Nostr协议 (nostrtips.com)</a> 这里留档几个自己比较感兴趣的项目。<s>（留坑为后续自建node做准备x）</s><ul><li><a href="https://github.com/hoytech/strfry">hoytech/strfry: a nostr relay (github.com)</a> 基于C++实现的无数据库中继器</li><li><a href="https://sr.ht/~gheartsfield/nostr-rs-relay/">nostr-rs-relay: Nostr relay in rust (sr.ht)</a> 基于Rust使用SQLite存储数据的中继器</li><li><a href="https://code.pobblelabs.org/fossil/nostr_relay/index">nostr relay: nostr relay (pobblelabs.org)</a> 基于Python使用SQLite存储的中继器</li></ul></li><li>其他Nostr相关网址：<ul><li><a href="https://github.com/nostr-protocol">nostr-protocol (github.com)</a>：应该算是“nostr官方”吧，理论提出的文章记录仓库，以及nostr相关的基本介绍，实现思路应该都有，不过基本只有md文件，过于简陋，只能算是理论，不是什么实际项目，有兴趣可以看看）</li><li><a href="https://nostr.build/">nostr.build media uploader</a> 为Nostr网络提供图像存储上传的网站，可以使用直链查看，不过可惜国内屏蔽了，不然可以当图床用x 不过关键的数据存储是否使用Nostr网络这点打个问号，目前来看大概率不是，还是自托管的，毕竟用的php实现的，还能查看具体的存储用量）估计和一般的图床差不多，只是挂了个nostr的名号。</li><li><a href="https://nostr.watch/">nostr.watch</a> 查看Nostr节点的网站，目前来看已经有500多个节点了，不过中国节点屈指可数）这么来看的话Nostr网络集群也算是发展起来了，虽然不如区块链那般壮大。</li><li><a href="https://github.com/search?q=nostr&amp;type=repositories">Repository search results · GitHub</a> Github上nostr相关的仓库，目前来看数量也有2.6k了，也算是比较成熟的项目了吧。</li><li><a href="https://github.com/aljazceru/awesome-nostr">aljazceru/awesome-nostr: A curated list of nostr projects and resources (github.com)</a> Nostr相关的项目大集合，有不少，有时间可以看看。</li></ul></li></ul><p>去中心化的“web3”概念提出到现在，Nostr是第一个我看到，并且亲自尝试的实际项目。 <strong>概念的变革都是由理想家提出，由工程师落实，最后让用户进行巩固充盈，这三者缺一不可，但资本并不是绝对必须的存在。</strong> 对于Nostr网络的未来，我还是很期待的。</p><h1 id="使用体验区别"><a class="markdownIt-Anchor" href="#使用体验区别"></a> 使用体验&amp;区别</h1><blockquote><p>一般的使用体验基本和Twitter差不多，发送文章，评论，点赞什么的（尽管不能撤销x）主要说下技术上的区别带来的直观体验吧。</p></blockquote><h2 id="1-账户体验"><a class="markdownIt-Anchor" href="#1-账户体验"></a> 1. 账户体验：</h2><p>应该是最直观的体验差异，账户不像中心化管理的社交网络那样使用常规的邮箱/手机号注册，密码验证，而是使用公钥私钥进行创建账户以及认证信息。这样做和中心化管理的最大差异就是你可以使用公钥看到对方的信息，包括发的文章，关住，粉丝，甚至私信对象（大部分nostr客户端的设计把公钥和私钥都设置成可以登录的认证方式了）</p><p>但是并不是所有信息都能看到，毕竟那样就没有设置账户的意义了）私信内容会被加密，只有有私钥的人才能看到具体内容，公钥看就是一团乱码。此外没有私钥的话也不能进行信息交互，发文章点赞关注之类的。大体来说其实和传统的账户使用无异。但是公钥和私钥都是不能更改的，所以说一旦泄露这个账户基本就相当于废了，正儿八经用的话可以使用密码管理器一类的东西来保存。</p><h2 id="2-客户端体验"><a class="markdownIt-Anchor" href="#2-客户端体验"></a> 2. 客户端体验：</h2><p>客户端体验算是一个比较直观的体验差距，和传统中心化管理的社交网络不同，没有“官方客户端”这一说，所有客户端都是第三方的。这样做有利有弊吧，相比起传统的中心化社交网络的第三方客户端，去中心化的社交网络的客户端开发显然地位要比前者高，可操性也更强，事实上半天的琢磨已经发现了不少开源的客户端，软件网页应有尽有，各有各的好处和优势，不过展开讲就长了，留着挖个坑，回头再说x。</p><p>基本内容都是一样的，可以看到别人的文章，基本的信息，发布自己的文章等等。要说有什么不同的话，那就是相比起中心化的社交网络多了个“node节点选择”的功能，不同的节点获取到的信息可能是不一样的，你发送的信息实际上也是悲存储在了node节点中。不过倒是不用太担心数据安全的问题（大概 该加密的数据就算存储在别人的node上也会以加密的形式存储，解密需要用到私钥，这个是客户端的活。</p><h2 id="3-服务器体验"><a class="markdownIt-Anchor" href="#3-服务器体验"></a> 3. 服务器体验：</h2><p>至少直到目前为止，去中心化的优势并没有在中国有所体现，因为基本上绝大多数的节点都被gfw噶掉了）而且去中心化的社交网络不利于监管，对于中国这种林子大了什么鸟都有的国家还是不太适用）不过可以自建node节点，这点倒是和传统的中心化社交网络差异性比较大。目前为止从 nostr.watch 的网站来看，已经有了500多个节点，不过大半集中在欧美地区，亚洲地区的node节点还比较少，目前来看日本那边可能用的人多一些（大概是twitter的难民）国内节点目前来看的话，台湾有一个节点，大陆有三四个，其中一半不是失效就是乱提交的，实质上能用的似乎只有一个（开node的大哥哥加油啊x），看别的人说国内节点迟早也会被制裁，这点我也比较同意，基本暂时不对国内节点保留希望了）</p><p>说实话，目前为止的nostr网络虽然说实现了去中心化管理，但是和我想象中的“完全去中心化社交网络”，或者说是“web3”还是有些差距，理想状态下我是希望能做到“用户及节点”的效果，这样用户体量越大社交网络也就越稳定，但是现阶段是“节点越多网络越稳定”，节点数量和用户数量不一定是正相关的，所以有崩溃的风险。另外虽然说从技术角度来看和区块链关系不大，但是目前主要受众群体其实还是吃到区块链红利的那波人，有没有可能下沉到一般用户群体（特别是在中国）也有待商榷。</p><p>另外有机会的话我也想试试自建node节点，不过需要考虑的事情还是有很多，比如选择什么样的方式搭建（node节点的实现方式似乎有不少），使用什么服务对外公开，以及通过什么途径来进行使用以及宣传，以及监管措施导致的服务商层面的惩罚等，要考虑清楚在弄，不能随随便便就去弄了，毕竟已经吃到过教训了）</p><h2 id="4-数据体验"><a class="markdownIt-Anchor" href="#4-数据体验"></a> 4. 数据体验：</h2><p>数据的存储，交互可以说是去中心化网络最大的特色和看点，相比起中心化网络，数据的直接所有人是维护中心化网络的主体（一般来说往往是公司）， <strong>去中心化的nostr社交网络的数据从结论上来看则是“不属于任何人”。</strong> 尽管数据直接存储在node节点中，但是用户是可以主动选择node节点的，而且用户数据似乎也会被分发到不同的节点中进行分布式存储，以及node搭建的所有人就算能查看到node里的数据，对于隐私数据一般来说是无法查看的，加密信息，密钥等。 说了“不属于任何人”，当然也不属于你自己。你能做到的只有两件事：发布和交互。</p><p>你想要删除或者修改都是没有办法的，发布出去的信息相当于“泼出去的水”，而且还不会干，会一直保留在去中心化的网络中。账户也是同理，无法注销，无法修改密码。从好的方面来想一定程度上保证了数据的安全性，以及相比起传统的中心化社交网络来说隐秘性更高，因为你的隐私数据只有你自己（私钥所有人）可以查看，连服务提供者都没法看到； <strong>从不好的方面来考虑，那就是现阶段的去中心化社交网络“太危险了”</strong> ：</p><p>因为数据“不属于任何人”，而认证账户的唯一手段是一个无法更改的密钥，你的账户也是并不是绝对安全的，也没有法律措施能够保护账户上的财产安全，上升到“国家舆论保护”的层面更是如此，所以短时间内这种模式的去中心化社交网络很难在中国普及开来。下放到商业化操作，这种去中心化的社交网络所承载的账号也绝对不是什么好选择，不管是作为公司企业的官方账号，还是偶像演员明星的活动账号，放在这种去中心化的社交网络风险都是相当大的，一方面是资本引来的大量流量，作为媒介的账号本身就具有价值，肯定会有人图谋不轨试图获取账号，万一账号密钥泄露，相关的公司或者艺人几乎没有任何办法再把这个账号挽回，放弃账号的话就相当于把一个常年积累的流量入口拱手让人，甚至会产生负面影响。这点其实下放到个人，上升到国家都是一样的，只是影响规模的程度问题。</p><p>综上所述，当前的去中心化社交网络几乎不可能吃到资本带来的流量红利，更多的其实还是向往自由的个体户在进行“尝鲜”。其实这种网络更加符合我心目中的“互联网精神”，其技术架构模式也类似bt那样的文件上传存储下载技术，但是如果失去了“资本的利益”，这种网络究竟能走多远，就不得而知了。虽然个人来说看好这种技术，但是就目前来说，他是一个“自由的混乱都市”，无法承担“世界级”的任务。</p><p>对了，补充一点。因为账户创建的低成本以及数据所有的特性，nostr其实有被大量bot用户灌溉“垃圾信息”的风险。但是目前来看nostr网络实际存储的信息只有文字和账户基本设定等基本信息，图片等其他资源还是引用的外部资源，包括头像，横幅，以及各种插入图也是。虽然有 nostr.build 这样的资源上传站点，但是实际上是否是用的nostr网络进行存储不得而知，似乎也并不是开源的。Amethyst的上传是可以自选图片托管方的，其他客户端目前不得而知，大概是随便选了个，或者是直接自建了吧。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="Nostr浅尝记录" href="http://blog.imc.re/archives/99d4.html" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">Nostr浅尝记录</span><span class="cap link fs12">http://blog.imc.re/archives/99d4.html</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/categories/blogs/smgoroblog/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="SMGoroBlog" scheme="https://blog.imc.re/RSSBOX/tags/smgoroblog/"/>
    
  </entry>
  
  <entry>
    <title>博客入门：每个人的独立博客</title>
    <link href="https://blog.imc.re/RSSBOX/rss/f066eaa2.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/f066eaa2.html</id>
    <published>2022-12-16T16:00:00.000Z</published>
    <updated>2022-12-16T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>本文讲了如何零基础创建一个属于自己的博客网站。面向从未用过独立博客，也不了解 markdown 和 git 的用户，旨在普及独立博客技术，顺序经过调整以降低首次上手难度。有相关经验的读者可以自行跳过某些步骤。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="博客入门：每个人的独立博客" href="https://xaoxuu.com/blog/20221217/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">博客入门：每个人的独立博客</span><span class="cap link fs12">https://xaoxuu.com/blog/20221217/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>博客进阶：自动化部署</title>
    <link href="https://blog.imc.re/RSSBOX/rss/e3866d96.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/e3866d96.html</id>
    <published>2022-11-25T16:00:00.000Z</published>
    <updated>2022-11-25T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>本文讲了如何利用脚本和 GitHub Actions 简化博客搭建和部署流程，提高效率。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="博客进阶：自动化部署" href="https://xaoxuu.com/blog/20221126/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">博客进阶：自动化部署</span><span class="cap link fs12">https://xaoxuu.com/blog/20221126/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>GitHub Codespaces 快速体验</title>
    <link href="https://blog.imc.re/RSSBOX/rss/d8dbb789.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/d8dbb789.html</id>
    <published>2022-11-20T16:00:00.000Z</published>
    <updated>2022-11-20T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>GitHub 最近上线了 Codespaces 功能，免费账号可以使用 120 core-hours compute • 15GB storage 额度，感觉挺不错的，赶快来体验吧～</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="GitHub Codespaces 快速体验" href="https://xaoxuu.com/blog/20221121/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">GitHub Codespaces 快速体验</span><span class="cap link fs12">https://xaoxuu.com/blog/20221121/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>探索 Stellar 时间线标签的 N 种用法</title>
    <link href="https://blog.imc.re/RSSBOX/rss/112b630b.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/112b630b.html</id>
    <published>2022-10-28T16:00:00.000Z</published>
    <updated>2022-10-28T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><p>时间线标签是 Stellar 最强大的特性之一，它可以以侧边栏组件身份出现在左侧边栏，可以以标签插件形式出现在文章任意位置，以下是笔者能想到的几种常见用法。</p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="探索 Stellar 时间线标签的 N 种用法" href="https://xaoxuu.com/blog/20221029/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">探索 Stellar 时间线标签的 N 种用法</span><span class="cap link fs12">https://xaoxuu.com/blog/20221029/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>辛普森悖论 | 你还相信数据吗</title>
    <link href="https://blog.imc.re/RSSBOX/rss/91c832c4.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/91c832c4.html</id>
    <published>2022-09-22T00:14:00.000Z</published>
    <updated>2022-09-22T00:14:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><blockquote><p>数据是一个有力的武器，它既能被用来澄清现实，也能被用来混淆是非</p></blockquote><p>你知不知道，数据也会说谎？</p><div class="story post-story"><h2 id="一个栗子"><a class="headerlink" href="#一个栗子" title="一个栗子"></a>一个栗子</h2><p>假设您患有肾结石并去看医生。医生告诉你有两种治疗方法，治疗 A（开放手术 open surgery）和治疗 B（体外冲击波碎石术 ESWL）。</p><p>你问哪种治疗效果更好，医生说：“一项研究发现治疗 A 的成功概率高于治疗 B。”</p><p>你说：“我会接受治疗 A，谢谢！”</p><p>这时医生打断你，“但同样的研究还研究了哪种治疗效果更好，这取决于患者是大肾结石还是小肾结石。”</p><p>你说：“好吧，我有大肾结石还是小肾结石？”</p><p>你说话的时候，医生又打断了你，说：“其实没关系。你看，他们发现治疗 B 比治疗 A 成功的概率更高，不管你的肾结石是大还是小。”</p><p>你可能想知道你是否没看错。听起来不可能。但这是真的：在<a href="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1339981/">一项实际研究</a>中，发现治疗 B 比治疗 A 对大肾结石和小肾结石起作用的概率更高，尽管事实上治疗 A 的总体 概率高于治疗 B。这是研究数据：</p><table><thead><tr><th align="center"></th><th align="center">治疗 A 有帮助</th><th align="center">治疗 B 有帮助</th></tr></thead><tbody><tr><td align="center">大肾结石</td><td align="center"> 69% (55 / 80)</td><td align="center">73% (192 / 263)</td></tr><tr><td align="center"> 小肾结石</td><td align="center"> 87% (234 / 270)</td><td align="center">93% (81 / 87)</td></tr><tr><td align="center"> 所有患者</td><td align="center"> 83% (289 / 350)</td><td align="center">78% (273 / 350)</td></tr></tbody></table><p>表中的第一项显示，80 名大肾结石患者接受了 A 治疗，治疗帮助了其中 55 人，成功率为 69%。这不如治疗 B 好，它帮助了 263 名大肾结石患者中的 192 人，成功率为 73%。以类似的方式，第二行显示治疗 B 比治疗 A 对患有小肾结石的人更有效。</p><p>但是当你把每一列的数字加起来时，你会发现治疗 A 确实比治疗 B 整体效果更好。</p><p>值得花时间检查所有数字加起来检验一下，并说服自己我没有欺骗你.</p><p>刚刚展示的这种现象被称为辛普森悖论。如果你和包括我在内的大多数人一样，那么辛普森悖论在你第一次见到它时就会令人震惊。因为它违反了我们对世界推理的本能方式。而且，正如我们看到的那样，辛普森悖论不仅是一种怪异的现象，而且它经常在具有重要决策后果的地方出现。</p></div><div class="story post-story"><h2 id="表达式"><a class="headerlink" href="#表达式" title="表达式"></a>表达式</h2><p>我们抽离出符号表达：</p><table><thead><tr><th align="center"></th><th align="center">统计对象 1</th><th align="center"> 统计对象 2</th></tr></thead><tbody><tr><td align="center"> 分项指标 1</td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.878ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -789.7 1104.4 1271.9" width="2.499ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="msub" transform="translate(240.2,477.2) scale(0.707)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="msub" transform="translate(220,-345) scale(0.707)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><rect height="60" width="864.4" x="120" y="220"></rect></g></g></g></svg></mjx-container></td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.878ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -789.7 1104.4 1271.9" width="2.499ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="msub" transform="translate(240.2,477.2) scale(0.707)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="msub" transform="translate(220,-345) scale(0.707)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><rect height="60" width="864.4" x="120" y="220"></rect></g></g></g></svg></mjx-container></td></tr><tr><td align="center"> 分项指标 2</td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.878ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -789.7 1104.4 1271.9" width="2.499ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="msub" transform="translate(240.2,477.2) scale(0.707)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g><g data-mml-node="msub" transform="translate(220,-345) scale(0.707)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g><rect height="60" width="864.4" x="120" y="220"></rect></g></g></g></svg></mjx-container></td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.878ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -789.7 1104.4 1271.9" width="2.499ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="msub" transform="translate(240.2,477.2) scale(0.707)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g><g data-mml-node="msub" transform="translate(220,-345) scale(0.707)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g><rect height="60" width="864.4" x="120" y="220"></rect></g></g></g></svg></mjx-container></td></tr><tr><td align="center"> 总计</td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="3.103ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -889.4 2318.9 1371.6" width="5.246ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="mrow" transform="translate(260.3,477.2) scale(0.707)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="mo" transform="translate(882.6,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(1660.6,0)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g></g><g data-mml-node="mrow" transform="translate(220,-345) scale(0.707)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="mo" transform="translate(939.6,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(1717.6,0)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g></g><rect height="60" width="2078.9" x="120" y="220"></rect></g></g></g></svg></mjx-container></td><td align="center"><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="3.103ex" role="img" style="vertical-align: -1.091ex;" viewbox="0 -889.4 2318.9 1371.6" width="5.246ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="mrow" transform="translate(260.3,477.2) scale(0.707)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(882.6,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(1660.6,0)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g></g><g data-mml-node="mrow" transform="translate(220,-345) scale(0.707)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(939.6,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(1717.6,0)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g></g><rect height="60" width="2078.9" x="120" y="220"></rect></g></g></g></svg></mjx-container></td></tr></tbody></table><p>如果</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 28.928ex;" width="full"><svg focusable="false" height="4.52ex" role="img" style="vertical-align: -1.695ex; min-width: 28.928ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1249)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1249) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="4315 -1249 1 1998"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,131)"><g data-mml-node="mtd"><g data-mml-node="mfrac"><g data-mml-node="msub" transform="translate(248.5,676)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="msub" transform="translate(220,-686)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><rect height="60" width="1139.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(1657.3,0)"><path d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" data-c="3E"></path></g><g data-mml-node="mfrac" transform="translate(2713.1,0)"><g data-mml-node="msub" transform="translate(248.5,676)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="msub" transform="translate(220,-686)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><rect height="60" width="1139.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(4092.7,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mfrac" transform="translate(4537.3,0)"><g data-mml-node="msub" transform="translate(248.5,676)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g><g data-mml-node="msub" transform="translate(220,-686)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g><rect height="60" width="1139.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(6194.7,0)"><path d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" data-c="3E"></path></g><g data-mml-node="mfrac" transform="translate(7250.4,0)"><g data-mml-node="msub" transform="translate(248.5,676)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g><g data-mml-node="msub" transform="translate(220,-686)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g><rect height="60" width="1139.6" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1249 1 1998"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:1" transform="translate(0,881)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>那么，推不出</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 28.445ex;" width="full"><svg focusable="false" height="4.839ex" role="img" style="vertical-align: -1.854ex; min-width: 28.445ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1319.5)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1319.5) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="4208.3 -1319.5 1 2139"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,60.5)"><g data-mml-node="mtd"><g data-mml-node="mfrac"><g data-mml-node="mrow" transform="translate(277,676)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="mo" transform="translate(1104.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(2105,0)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g></g><g data-mml-node="mrow" transform="translate(220,-686)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><g data-mml-node="mo" transform="translate(1161.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(2162,0)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g></g></g><rect height="60" width="3301.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(3819.3,0)"><path d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" data-c="3E"></path></g><g data-mml-node="mfrac" transform="translate(4875.1,0)"><g data-mml-node="mrow" transform="translate(277,676)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(1104.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(2105,0)"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q340 441 372 389Q373 390 377 395T388 406T404 418Q438 442 450 442Q454 442 457 439T460 434Q460 425 391 149Q320 -135 320 -139Q320 -147 365 -148H390Q396 -156 396 -157T393 -175Q389 -188 383 -194H370Q339 -192 262 -192Q234 -192 211 -192T174 -192T157 -193Q143 -193 143 -185Q143 -182 145 -170Q149 -154 152 -151T172 -148Q220 -148 230 -141Q238 -136 258 -53T279 32Q279 33 272 29Q224 -10 172 -10Q117 -10 75 30T33 157ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D45E"></path></g><g data-mml-node="mn" transform="translate(479,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g></g><g data-mml-node="mrow" transform="translate(220,-686)"><g data-mml-node="msub"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(1161.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msub" transform="translate(2162,0)"><g data-mml-node="mi"><path d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" data-c="1D45D"></path></g><g data-mml-node="mn" transform="translate(536,-150) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g></g></g><rect height="60" width="3301.6" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1319.5 1 2139"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:2" transform="translate(0,810.5)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>以上就是辛普森悖论比较通俗易懂的表达式了。</p></div><div class="story post-story"><h2 id="我们忽略了什么"><a class="headerlink" href="#我们忽略了什么" title="我们忽略了什么"></a>我们忽略了什么</h2><p>从数据生成过程（因果模型）来看分析.</p><p>事实证明，小肾结石被认为是不严重的病例，治疗 B（体外冲击波碎石术 ESWL）比治疗 A（开放手术 open surgery）更加激进。</p><p>对于小肾结石，医生更有可能推荐保守疗法 A，因为病情不太严重，患者最有可能首先成功恢复。</p><p>对于严重的大肾结石，医生往往选择更激进的疗法 B。即使疗法 B 在这些病例中表现更好，由于是更严重的病例，疗法 B 的总体恢复率低于疗法 A.</p><p>在这个现实世界的例子中，肾结石的大小（病例的严重性）是一个混合变量，它会同时影响自变量（疗法）和因变量（恢复率）.</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 33.359ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 33.359ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="5294.3 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">疗</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">法</text></g><g data-mml-node="mo" transform="translate(2277.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(3333.6,0)"><path d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z" data-c="1D454"></path></g><g data-mml-node="mo" transform="translate(3810.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(4199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">病</text></g><g data-mml-node="mi" transform="translate(5199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">例</text></g><g data-mml-node="mi" transform="translate(6199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(7199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">严</text></g><g data-mml-node="mi" transform="translate(8199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">重</text></g><g data-mml-node="mi" transform="translate(9199.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">性</text></g><g data-mml-node="mo" transform="translate(10199.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:3"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 41.317ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 41.317ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="7053.1 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">恢</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">复</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">率</text></g><g data-mml-node="mo" transform="translate(3277.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(4333.6,0)"><path d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" data-c="1D453"></path></g><g data-mml-node="mo" transform="translate(4883.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(5272.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">疗</text></g><g data-mml-node="mi" transform="translate(6272.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">法</text></g><g data-mml-node="mo" transform="translate(7272.6,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mi" transform="translate(7717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">病</text></g><g data-mml-node="mi" transform="translate(8717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">例</text></g><g data-mml-node="mi" transform="translate(9717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(10717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">严</text></g><g data-mml-node="mi" transform="translate(11717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">重</text></g><g data-mml-node="mi" transform="translate(12717.2,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">性</text></g><g data-mml-node="mo" transform="translate(13717.2,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:4"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>为了确定哪种治疗方法确实更好，我们需要通过对两组数据进行分离并比较组内的恢复率而不是按组聚合来控制混合变量。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 35.845ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 35.845ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="5843.8 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">小</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">肾</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">结</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">石</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">恢</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">复</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">率</text></g><g data-mml-node="mo" transform="translate(7277.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(8333.6,0)"><path d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" data-c="210E"></path></g><g data-mml-node="mo" transform="translate(8909.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(9298.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">疗</text></g><g data-mml-node="mi" transform="translate(10298.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">法</text></g><g data-mml-node="mo" transform="translate(11298.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:5"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" data-c="35" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 35.323ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 35.323ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="5728.3 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">大</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">肾</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">结</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">石</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">恢</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">复</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">率</text></g><g data-mml-node="mo" transform="translate(7277.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(8333.6,0)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g><g data-mml-node="mo" transform="translate(8678.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(9067.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">疗</text></g><g data-mml-node="mi" transform="translate(10067.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">法</text></g><g data-mml-node="mo" transform="translate(11067.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:6"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" data-c="36" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>这样看来激进的治疗 B（体外冲击波碎石术 ESWL）效果更好.</p><p>如果有潜在变量（特别是混合变量）存在，牢记：整体数据未必可靠，要通过科学合理的分组来查看具体细致的数据。</p></div><div class="story post-story"><h2 id="启示"><a class="headerlink" href="#启示" title="启示"></a>启示</h2><ul><li>数据从来都不是完全客观的。我们必须对这些数字持怀疑态度.</li><li> 辛普森悖论的出现是因为人们忽略了研究的因果关系，一旦我们理解了数据生成的机制，我们就可以寻找影响结果的其他因素，而图表不会告诉你这些.</li><li> 充分考察事件的潜在影响因素和维度，系数消除分组数据基数差异造成的影响.</li><li> 要求我们具备科学辩证思维，客观看待关联现象。很多时候，我们选择相信直觉，因为我们的直觉往往很准。但是，在信息不全或者信息非对称的情况下，直觉常常是是值得怀疑的。</li></ul></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="辛普森悖论 | 你还相信数据吗" href="https://blog.mhuig.top/p/2f345bb/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">辛普森悖论 | 你还相信数据吗</span><span class="cap link fs12">https://blog.mhuig.top/p/2f345bb/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>尝试在博客中添加简易文章推荐功能</title>
    <link href="https://blog.imc.re/RSSBOX/rss/175a1706.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/175a1706.html</id>
    <published>2022-09-15T03:13:00.000Z</published>
    <updated>2022-09-15T03:13:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>把文档转换成 “向量”，并且尝试用线性代数等数学工具来解决信息检索这类问题，至少可以追溯到 20 世纪 70 年代。想到在 Hexo 这种静态博客系统，特别是 GitHub Page 这种 Serverless 服务中使用 Word2Vec 等深度学习方法似乎并不现实，所以这里使用的是一个非常简单经典的 TF-IDF 算法. </p><p>TF-IDF 算法原来是搜索引擎中的核心部分，谷歌百度已经使用 TF-IDF 作为内容排名因素很长一段时间.</p><p>现在的搜索引擎一般用如下的算法计算网站页面得分：score (页面得分) = TFIDF 分 * x + 链接分 * y + 用户体验分 * z（其中 x+y+z=100%），TFIDF 分值百度大约占 40% 左右的权重，谷歌更是达到了 50%.</p><p>这是百度的计算方法： score (页面得分) = 40% 的内容质量相关性（TFIDF）+ 40% 的用户体验分 + 20% 的链接分（域名 + 外链）.</p><p>搜索引擎使用 TF-IDF 来计算内容质量相关性，我们这边也可以用它来计算文章内容相关性，然后实现简易文章推荐功能。</p><p>当然也可以使用文章的 tags 标签最为推荐依据，但是这样过于依赖人工标注数据，顺便最近发现在 Hexo 中分类和标签只能在 <code>source/_posts</code> 文件夹中使用才能渲染出来。</p><div class="story post-story"><h2 id="构建向量空间模型"><a class="headerlink" href="#构建向量空间模型" title="构建向量空间模型"></a>构建向量空间模型</h2><p>将文档转化为向量来表示，这样文档与文档之间就可以定量的去度量他们之间的关系，挖掘文档之间的联系。上面提到的 Word2Vec 是把单词转化为向量来表示，这样词与词之间就可以定量的去度量他们之间的关系，挖掘词之间的联系.</p><p>比如将词的维度降维到 2 维，用下图的词向量表示词:</p><p><img><img alt="单词转化为向量" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1663246894190/1.png" src="https://unpkg.com/mhgoos@0.0.1663246894190/1.png"/></img></p><p><img><img alt="向量运算" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1663284804787/2.png" src="https://unpkg.com/mhgoos@0.0.1663284804787/2.png"/></img></p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 42.671ex;" width="full"><svg focusable="false" height="4.127ex" role="img" style="vertical-align: -1.498ex; min-width: 42.671ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1162)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1162) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="7352.2 -1162 1 1824"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-412)"><g data-mml-node="mtd"><g data-mml-node="mover"><g data-mml-node="mrow"><g data-mml-node="mi"><path d="M285 628Q285 635 228 637Q205 637 198 638T191 647Q191 649 193 661Q199 681 203 682Q205 683 214 683H219Q260 681 355 681Q389 681 418 681T463 682T483 682Q500 682 500 674Q500 669 497 660Q496 658 496 654T495 648T493 644T490 641T486 639T479 638T470 637T456 637Q416 636 405 634T387 623L306 305Q307 305 490 449T678 597Q692 611 692 620Q692 635 667 637Q651 637 651 648Q651 650 654 662T659 677Q662 682 676 682Q680 682 711 681T791 680Q814 680 839 681T869 682Q889 682 889 672Q889 650 881 642Q878 637 862 637Q787 632 726 586Q710 576 656 534T556 455L509 418L518 396Q527 374 546 329T581 244Q656 67 661 61Q663 59 666 57Q680 47 717 46H738Q744 38 744 37T741 19Q737 6 731 0H720Q680 3 625 3Q503 3 488 0H478Q472 6 472 9T474 27Q478 40 480 43T491 46H494Q544 46 544 71Q544 75 517 141T485 216L427 354L359 301L291 248L268 155Q245 63 245 58Q245 51 253 49T303 46H334Q340 37 340 35Q340 19 333 5Q328 0 317 0Q314 0 280 1T180 2Q118 2 85 2T49 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Z" data-c="1D43E"></path></g><g data-mml-node="mi" transform="translate(889,0)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g><g data-mml-node="mi" transform="translate(1234,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mi" transform="translate(1834,0)"><path d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z" data-c="1D454"></path></g></g><g data-mml-node="mo" transform="translate(0,870)"><path d="M56 237T56 250T70 270H835Q719 357 692 493Q692 494 692 496T691 499Q691 511 708 511H711Q720 511 723 510T729 506T732 497T735 481T743 456Q765 389 816 336T935 261Q944 258 944 250Q944 244 939 241T915 231T877 212Q836 186 806 152T761 85T740 35T732 4Q730 -6 727 -8T711 -11Q691 -11 691 0Q691 7 696 25Q728 151 835 230H70Q56 237 56 250Z" data-c="2192" transform="translate(1311,0)"></path><svg height="865" viewbox="352.7 -182 1411 865" width="1411" x="0" y="-182"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212" transform="scale(2.72,1)"></path></svg></g></g><g data-mml-node="mo" transform="translate(2533.2,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mover" transform="translate(3533.4,0)"><g data-mml-node="mrow"><g data-mml-node="mi"><path d="M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z" data-c="1D440"></path></g><g data-mml-node="mi" transform="translate(1051,0)"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mi" transform="translate(1580,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mml-node="mo" transform="translate(0,870)"><path d="M56 237T56 250T70 270H835Q719 357 692 493Q692 494 692 496T691 499Q691 511 708 511H711Q720 511 723 510T729 506T732 497T735 481T743 456Q765 389 816 336T935 261Q944 258 944 250Q944 244 939 241T915 231T877 212Q836 186 806 152T761 85T740 35T732 4Q730 -6 727 -8T711 -11Q691 -11 691 0Q691 7 696 25Q728 151 835 230H70Q56 237 56 250Z" data-c="2192" transform="translate(1180,0)"></path><svg height="865" viewbox="320 -182 1280 865" width="1280" x="0" y="-182"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212" transform="scale(2.468,1)"></path></svg></g></g><g data-mml-node="mo" transform="translate(5935.7,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mover" transform="translate(6935.9,0)"><g data-mml-node="mrow"><g data-mml-node="mi"><path d="M436 683Q450 683 486 682T553 680Q604 680 638 681T677 682Q695 682 695 674Q695 670 692 659Q687 641 683 639T661 637Q636 636 621 632T600 624T597 615Q597 603 613 377T629 138L631 141Q633 144 637 151T649 170T666 200T690 241T720 295T759 362Q863 546 877 572T892 604Q892 619 873 628T831 637Q817 637 817 647Q817 650 819 660Q823 676 825 679T839 682Q842 682 856 682T895 682T949 681Q1015 681 1034 683Q1048 683 1048 672Q1048 666 1045 655T1038 640T1028 637Q1006 637 988 631T958 617T939 600T927 584L923 578L754 282Q586 -14 585 -15Q579 -22 561 -22Q546 -22 542 -17Q539 -14 523 229T506 480L494 462Q472 425 366 239Q222 -13 220 -15T215 -19Q210 -22 197 -22Q178 -22 176 -15Q176 -12 154 304T131 622Q129 631 121 633T82 637H58Q51 644 51 648Q52 671 64 683H76Q118 680 176 680Q301 680 313 683H323Q329 677 329 674T327 656Q322 641 318 637H297Q236 634 232 620Q262 160 266 136L501 550L499 587Q496 629 489 632Q483 636 447 637Q428 637 422 639T416 648Q416 650 418 660Q419 664 420 669T421 676T424 680T428 682T436 683Z" data-c="1D44A"></path></g><g data-mml-node="mi" transform="translate(1048,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(1533,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T88 425T132 442T175 435T205 417T221 395T229 376L231 369Q231 367 232 367L243 378Q303 442 384 442Q401 442 415 440T441 433T460 423T475 411T485 398T493 385T497 373T500 364T502 357L510 367Q573 442 659 442Q713 442 746 415T780 336Q780 285 742 178T704 50Q705 36 709 31T724 26Q752 26 776 56T815 138Q818 149 821 151T837 153Q857 153 857 145Q857 144 853 130Q845 101 831 73T785 17T716 -10Q669 -10 648 17T627 73Q627 92 663 193T700 345Q700 404 656 404H651Q565 404 506 303L499 291L466 157Q433 26 428 16Q415 -11 385 -11Q372 -11 364 -4T353 8T350 18Q350 29 384 161L420 307Q423 322 423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 181Q151 335 151 342Q154 357 154 369Q154 405 129 405Q107 405 92 377T69 316T57 280Q55 278 41 278H27Q21 284 21 287Z" data-c="1D45A"></path></g><g data-mml-node="mi" transform="translate(2411,0)"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mi" transform="translate(2940,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mml-node="mo" transform="translate(0,870)"><path d="M56 237T56 250T70 270H835Q719 357 692 493Q692 494 692 496T691 499Q691 511 708 511H711Q720 511 723 510T729 506T732 497T735 481T743 456Q765 389 816 336T935 261Q944 258 944 250Q944 244 939 241T915 231T877 212Q836 186 806 152T761 85T740 35T732 4Q730 -6 727 -8T711 -11Q691 -11 691 0Q691 7 696 25Q728 151 835 230H70Q56 237 56 250Z" data-c="2192" transform="translate(2540,0)"></path><svg height="865" viewbox="660 -182 2640 865" width="2640" x="0" y="-182"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212" transform="scale(5.09,1)"></path></svg></g></g><g data-mml-node="mo" transform="translate(10753.7,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mover" transform="translate(11809.4,0)"><g data-mml-node="mrow"><g data-mml-node="mi"><path d="M399 -80Q399 -47 400 -30T402 -11V-7L387 -11Q341 -22 303 -22Q208 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435Q740 255 592 107Q529 47 461 16L444 8V3Q444 2 449 -24T470 -66T516 -82Q551 -82 583 -60T625 -3Q631 11 638 11Q647 11 649 2Q649 -6 639 -34T611 -100T557 -165T481 -194Q399 -194 399 -87V-80ZM636 468Q636 523 621 564T580 625T530 655T477 665Q429 665 379 640Q277 591 215 464T153 216Q153 110 207 59Q231 38 236 38V46Q236 86 269 120T347 155Q372 155 390 144T417 114T429 82T435 55L448 64Q512 108 557 185T619 334T636 468ZM314 18Q362 18 404 39L403 49Q399 104 366 115Q354 117 347 117Q344 117 341 117T337 118Q317 118 296 98T274 52Q274 18 314 18Z" data-c="1D444"></path></g><g data-mml-node="mi" transform="translate(791,0)"><path d="M21 287Q21 295 30 318T55 370T99 420T158 442Q204 442 227 417T250 358Q250 340 216 246T182 105Q182 62 196 45T238 27T291 44T328 78L339 95Q341 99 377 247Q407 367 413 387T427 416Q444 431 463 431Q480 431 488 421T496 402L420 84Q419 79 419 68Q419 43 426 35T447 26Q469 29 482 57T512 145Q514 153 532 153Q551 153 551 144Q550 139 549 130T540 98T523 55T498 17T462 -8Q454 -10 438 -10Q372 -10 347 46Q345 45 336 36T318 21T296 6T267 -6T233 -11Q189 -11 155 7Q103 38 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" data-c="1D462"></path></g><g data-mml-node="mi" transform="translate(1363,0)"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mml-node="mi" transform="translate(1829,0)"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mml-node="mi" transform="translate(2295,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mml-node="mo" transform="translate(0,891)"><path d="M56 237T56 250T70 270H835Q719 357 692 493Q692 494 692 496T691 499Q691 511 708 511H711Q720 511 723 510T729 506T732 497T735 481T743 456Q765 389 816 336T935 261Q944 258 944 250Q944 244 939 241T915 231T877 212Q836 186 806 152T761 85T740 35T732 4Q730 -6 727 -8T711 -11Q691 -11 691 0Q691 7 696 25Q728 151 835 230H70Q56 237 56 250Z" data-c="2192" transform="translate(1895,0)"></path><svg height="865" viewbox="498.8 -182 1995 865" width="1995" x="0" y="-182"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212" transform="scale(3.846,1)"></path></svg></g></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1162 1 1824"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:1" transform="translate(0,338)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>似乎发现了什么不得了的事情。</p><p>对于自然语言书写的文本这种非结构化信息，从文本中抽取出的特征来量化来表示文本信息，构建向量空间模型，并基于数学模型的处理，将文本转换为机器可以理解的语言的方式是很重要的。</p></div><div class="story post-story"><h2 id="举个栗子"><a class="headerlink" href="#举个栗子" title="举个栗子"></a>举个栗子</h2><p>要实现文章推荐，就需要从一堆文章中找出一些内容相似的文章。基本思路就是，如果文章的关键词越相似，那么他们的内容就会越相似。</p><p>我们先从几个简单的句子着手。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A：我这里有苹果和西瓜。</span><br/><span class="line"></span><br/><span class="line">句子B：我喜欢吃西瓜，不喜欢吃苹果。</span><br/><span class="line"></span><br/><span class="line">句子C：我喜欢吃蔬菜。</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第一步：数据清洗"><a class="headerlink" href="#第一步：数据清洗" title="第一步：数据清洗"></a>第一步：数据清洗</h2><p>简单去除标点符号等干扰信息。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A: 我这里有苹果和西瓜</span><br/><span class="line"></span><br/><span class="line">句子B: 我喜欢吃西瓜 不喜欢吃苹果</span><br/><span class="line"></span><br/><span class="line">句子C: 我喜欢吃蔬菜</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第二步：分词"><a class="headerlink" href="#第二步：分词" title="第二步：分词"></a>第二步：分词</h2><p>使用分词工具进行分词。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">[ <span class="string">'我'</span>, <span class="string">'这里'</span>, <span class="string">'有'</span>, <span class="string">'苹果'</span>, <span class="string">'和'</span>, <span class="string">'西瓜'</span> ]</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line">[</span><br/><span class="line">  <span class="string">'我'</span>, <span class="string">'喜欢'</span>,</span><br/><span class="line">  <span class="string">'吃'</span>, <span class="string">'西瓜'</span>,</span><br/><span class="line">  <span class="string">'不'</span>, <span class="string">'喜欢'</span>,</span><br/><span class="line">  <span class="string">'吃'</span>, <span class="string">'苹果'</span></span><br/><span class="line">]</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">[ <span class="string">'我'</span>, <span class="string">'喜欢'</span>, <span class="string">'吃'</span>, <span class="string">'蔬菜'</span> ]</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第三步：去重收集所有句子中所有的词"><a class="headerlink" href="#第三步：去重收集所有句子中所有的词" title="第三步：去重收集所有句子中所有的词"></a>第三步：去重收集所有句子中所有的词</h2><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">[</span><br/><span class="line">  <span class="string">'我'</span>,   <span class="string">'这里'</span>, <span class="string">'有'</span>,</span><br/><span class="line">  <span class="string">'苹果'</span>, <span class="string">'和'</span>,   <span class="string">'西瓜'</span>,</span><br/><span class="line">  <span class="string">'喜欢'</span>, <span class="string">'吃'</span>,   <span class="string">'不'</span>,</span><br/><span class="line">  <span class="string">'蔬菜'</span></span><br/><span class="line">]</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第四步：计算词频"><a class="headerlink" href="#第四步：计算词频" title="第四步：计算词频"></a>第四步：计算词频</h2><p>词频背后的假设是文章的重要程度即文章的相关度与单词在文档中出现的次数成正比。文章的关键词应当比文章中的其他词出现的次数多。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 49.142ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 49.142ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="8782.3 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mo" transform="translate(2000,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(2389,0)"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(3093,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(3842,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4508.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(5564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">某</text></g><g data-mml-node="mi" transform="translate(6564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">个</text></g><g data-mml-node="mi" transform="translate(7564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(8564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">在</text></g><g data-mml-node="mi" transform="translate(9564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(10564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">章</text></g><g data-mml-node="mi" transform="translate(11564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">中</text></g><g data-mml-node="mi" transform="translate(12564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">出</text></g><g data-mml-node="mi" transform="translate(13564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">现</text></g><g data-mml-node="mi" transform="translate(14564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(15564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">次</text></g><g data-mml-node="mi" transform="translate(16564.6,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:2"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 1,</span><br/><span class="line">  <span class="string">'这里'</span>: 1,</span><br/><span class="line">  <span class="string">'有'</span>: 1,</span><br/><span class="line">  <span class="string">'苹果'</span>: 1,</span><br/><span class="line">  <span class="string">'和'</span>: 1,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 1,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 1,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 1,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 1,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 2,</span><br/><span class="line">  <span class="string">'吃'</span>: 2,</span><br/><span class="line">  <span class="string">'不'</span>: 1,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 1,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 1,</span><br/><span class="line">  <span class="string">'吃'</span>: 1,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 1</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第四步：词频标准化"><a class="headerlink" href="#第四步：词频标准化" title="第四步：词频标准化"></a>第四步：词频标准化</h2><p>文章的篇幅有长有短，为了便于不同文章的比较，进行” 词频” 标准化。词频标准化的目的是把所有的词频在同一维度上分析。</p><p>词频标准化有两种方案：</p><p>方案一：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 50.137ex;" width="full"><svg focusable="false" height="5.285ex" role="img" style="vertical-align: -2.077ex; min-width: 50.137ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1418)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1418) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="9002.3 -1418 1 2336"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-8)"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mo" transform="translate(2000,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(2389,0)"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(3093,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(3842,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4508.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(5564.6,0)"><g data-mml-node="mrow" transform="translate(220,676)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">某</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">个</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">在</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">章</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">中</text></g><g data-mml-node="mi" transform="translate(7000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">出</text></g><g data-mml-node="mi" transform="translate(8000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">现</text></g><g data-mml-node="mi" transform="translate(9000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(10000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">次</text></g><g data-mml-node="mi" transform="translate(11000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g><g data-mml-node="mrow" transform="translate(3220,-710)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">章</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">总</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g><rect height="60" width="12200" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1418 1 2336"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:3" transform="translate(0,742)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>方案二：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 52.399ex;" width="full"><svg focusable="false" height="5.285ex" role="img" style="vertical-align: -2.077ex; min-width: 52.399ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1418)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1418) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="9502.3 -1418 1 2336"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-8)"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mo" transform="translate(2000,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(2389,0)"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(3093,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(3842,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4508.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(5564.6,0)"><g data-mml-node="mrow" transform="translate(720,676)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">某</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">个</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">在</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">章</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">中</text></g><g data-mml-node="mi" transform="translate(7000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">出</text></g><g data-mml-node="mi" transform="translate(8000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">现</text></g><g data-mml-node="mi" transform="translate(9000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(10000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">次</text></g><g data-mml-node="mi" transform="translate(11000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g><g data-mml-node="mrow" transform="translate(220,-710)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">该</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">出</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">现</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">最</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">多</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(7000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(8000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">出</text></g><g data-mml-node="mi" transform="translate(9000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">现</text></g><g data-mml-node="mi" transform="translate(10000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(11000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">次</text></g><g data-mml-node="mi" transform="translate(12000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g><rect height="60" width="13200" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1418 1 2336"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:4" transform="translate(0,742)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>一般情况下，第二个标准化方案更适用，因为能够使词频的值相对大点，便于分析。</p><p>有时候常常用 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex;" viewbox="0 -750 5596.4 1000" width="12.662ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(722.2,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(1722.4,0)"><path d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" data-c="1D43F"></path></g><g data-mml-node="mi" transform="translate(2403.4,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(2888.4,0)"><path d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z" data-c="1D454"></path></g><g data-mml-node="mo" transform="translate(3365.4,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(3754.4,0)"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(4458.4,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(5207.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></svg></mjx-container> 这个值来代替原来的 TF 取值。这样的计算保持了一个平衡，既有区分度，但也不至于完全线性增长。</p><p>这里使用比较简单的方案一作为栗子：</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'这里'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'有'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'和'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0.16666666666666666,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 0.125,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0.125,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0.125,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0.25,</span><br/><span class="line">  <span class="string">'吃'</span>: 0.25,</span><br/><span class="line">  <span class="string">'不'</span>: 0.125,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: 0.25,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0.25,</span><br/><span class="line">  <span class="string">'吃'</span>: 0.25,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0.25</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第五步：计算逆文档频率"><a class="headerlink" href="#第五步：计算逆文档频率" title="第五步：计算逆文档频率"></a>第五步：计算逆文档频率</h2><p>仅有词频 (TF) 不能比较完整地描述文档的相关度。因为语言的因素，有一些单词可能会比较自然地在很多文档中反复出现，比如这里中的 “我”、“和” 等等。这些词大多起到了链接语句的作用，是保持语言连贯不可或缺的部分。</p><p>很明显，如果有太多文档都涵盖了某个单词，这个单词也就越不重要，或者说是这个单词就越没有信息量。因此，我们需要对词频 (TF) 的值进行修正，而 逆文档频率 (IDF) 的想法是用文档频率 (DF) 的倒数来进行修正。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 57.803ex;" width="full"><svg focusable="false" height="5.285ex" role="img" style="vertical-align: -2.077ex; min-width: 57.803ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1418)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1418) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="10696.5 -1418 1 2336"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-8)"><g data-mml-node="mtd"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">逆</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">档</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">率</text></g><g data-mml-node="mo" transform="translate(5000,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(5389,0)"><path d="M43 1Q26 1 26 10Q26 12 29 24Q34 43 39 45Q42 46 54 46H60Q120 46 136 53Q137 53 138 54Q143 56 149 77T198 273Q210 318 216 344Q286 624 286 626Q284 630 284 631Q274 637 213 637H193Q184 643 189 662Q193 677 195 680T209 683H213Q285 681 359 681Q481 681 487 683H497Q504 676 504 672T501 655T494 639Q491 637 471 637Q440 637 407 634Q393 631 388 623Q381 609 337 432Q326 385 315 341Q245 65 245 59Q245 52 255 50T307 46H339Q345 38 345 37T342 19Q338 6 332 0H316Q279 2 179 2Q143 2 113 2T65 2T43 1Z" data-c="1D43C"></path></g><g data-mml-node="mi" transform="translate(5893,0)"><path d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z" data-c="1D437"></path></g><g data-mml-node="mi" transform="translate(6721,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(7470,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(8136.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(9192.6,0)"><path d="M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z" data-c="1D459"></path></g><g data-mml-node="mi" transform="translate(9490.6,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(9975.6,0)"><path d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z" data-c="1D454"></path></g><g data-mml-node="mo" transform="translate(10452.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(10841.6,0)"><g data-mml-node="mrow" transform="translate(1081.2,676)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">语</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">料</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">库</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">档</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">总</text></g><g data-mml-node="mi" transform="translate(7000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g></g><g data-mml-node="mrow" transform="translate(220,-710)"><g data-mml-node="mi"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">包</text></g><g data-mml-node="mi" transform="translate(1000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">含</text></g><g data-mml-node="mi" transform="translate(2000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">该</text></g><g data-mml-node="mi" transform="translate(3000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(4000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">的</text></g><g data-mml-node="mi" transform="translate(5000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(6000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">档</text></g><g data-mml-node="mi" transform="translate(7000,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">数</text></g><g data-mml-node="mo" transform="translate(8222.2,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(9222.4,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g><rect height="60" width="9922.4" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(21004,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1418 1 2336"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:5" transform="translate(0,742)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" data-c="35" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>如果一个词越常见，那么分母就越大，逆文档频率就越小越接近 0。分母之所以要加 1，是为了避免分母为 0（即所有文档都不包含该词）。log 表示对得到的值取对数。为什么要用 log 函数？log 函数是单调递增，求 log 是为了归一化，保证逆文档频率不会过大。用 Log 进行变换，也是一个非线性增长的技巧，这样的计算保持了一个平衡，既有区分度，但也不至于完全线性增长。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.2876820724517809,</span><br/><span class="line">  <span class="string">'这里'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'有'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0.4054651081081644</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.2876820724517809,</span><br/><span class="line">  <span class="string">'这里'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'有'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0.4054651081081644</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.2876820724517809,</span><br/><span class="line">  <span class="string">'这里'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'有'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0.4054651081081644,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0.4054651081081644</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第六步：计算TF-IDF"><a class="headerlink" href="#第六步：计算TF-IDF" title="第六步：计算TF-IDF"></a>第六步：计算 TF-IDF</h2><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 53.3ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 53.3ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="9701.2 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(704,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(1675.2,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(2675.4,0)"><path d="M43 1Q26 1 26 10Q26 12 29 24Q34 43 39 45Q42 46 54 46H60Q120 46 136 53Q137 53 138 54Q143 56 149 77T198 273Q210 318 216 344Q286 624 286 626Q284 630 284 631Q274 637 213 637H193Q184 643 189 662Q193 677 195 680T209 683H213Q285 681 359 681Q481 681 487 683H497Q504 676 504 672T501 655T494 639Q491 637 471 637Q440 637 407 634Q393 631 388 623Q381 609 337 432Q326 385 315 341Q245 65 245 59Q245 52 255 50T307 46H339Q345 38 345 37T342 19Q338 6 332 0H316Q279 2 179 2Q143 2 113 2T65 2T43 1Z" data-c="1D43C"></path></g><g data-mml-node="mi" transform="translate(3179.4,0)"><path d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z" data-c="1D437"></path></g><g data-mml-node="mi" transform="translate(4007.4,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(5034.2,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(6090,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">词</text></g><g data-mml-node="mi" transform="translate(7090,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mo" transform="translate(8090,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(8479,0)"><path d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z" data-c="1D447"></path></g><g data-mml-node="mi" transform="translate(9183,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(9932,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(10543.2,0)"><path d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" data-c="D7"></path></g><g data-mml-node="mi" transform="translate(11543.4,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">逆</text></g><g data-mml-node="mi" transform="translate(12543.4,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">文</text></g><g data-mml-node="mi" transform="translate(13543.4,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">档</text></g><g data-mml-node="mi" transform="translate(14543.4,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">频</text></g><g data-mml-node="mi" transform="translate(15543.4,0)"><text data-variant="normal" font-family="serif" font-size="884px" transform="scale(1,-1)">率</text></g><g data-mml-node="mo" transform="translate(16543.4,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(16932.4,0)"><path d="M43 1Q26 1 26 10Q26 12 29 24Q34 43 39 45Q42 46 54 46H60Q120 46 136 53Q137 53 138 54Q143 56 149 77T198 273Q210 318 216 344Q286 624 286 626Q284 630 284 631Q274 637 213 637H193Q184 643 189 662Q193 677 195 680T209 683H213Q285 681 359 681Q481 681 487 683H497Q504 676 504 672T501 655T494 639Q491 637 471 637Q440 637 407 634Q393 631 388 623Q381 609 337 432Q326 385 315 341Q245 65 245 59Q245 52 255 50T307 46H339Q345 38 345 37T342 19Q338 6 332 0H316Q279 2 179 2Q143 2 113 2T65 2T43 1Z" data-c="1D43C"></path></g><g data-mml-node="mi" transform="translate(17436.4,0)"><path d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z" data-c="1D437"></path></g><g data-mml-node="mi" transform="translate(18264.4,0)"><path d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z" data-c="1D439"></path></g><g data-mml-node="mo" transform="translate(19013.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:6"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" data-c="36" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>可以看到，TF-IDF 与一个词在文档中的出现次数成正比，与该词在整个文档库中的出现次数成反比。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.047947012075296815,</span><br/><span class="line">  <span class="string">'这里'</span>: 0.06757751801802739,</span><br/><span class="line">  <span class="string">'有'</span>: 0.06757751801802739,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0.06757751801802739,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.03596025905647261,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0.05068313851352055,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0</span><br/><span class="line">&#125;</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">&#123;</span><br/><span class="line">  <span class="string">'我'</span>: -0.07192051811294523,</span><br/><span class="line">  <span class="string">'这里'</span>: 0,</span><br/><span class="line">  <span class="string">'有'</span>: 0,</span><br/><span class="line">  <span class="string">'苹果'</span>: 0,</span><br/><span class="line">  <span class="string">'和'</span>: 0,</span><br/><span class="line">  <span class="string">'西瓜'</span>: 0,</span><br/><span class="line">  <span class="string">'喜欢'</span>: 0,</span><br/><span class="line">  <span class="string">'吃'</span>: 0,</span><br/><span class="line">  <span class="string">'不'</span>: 0,</span><br/><span class="line">  <span class="string">'蔬菜'</span>: 0.1013662770270411</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第七步：列出文档向量"><a class="headerlink" href="#第七步：列出文档向量" title="第七步：列出文档向量"></a>第七步：列出文档向量</h2><p>这里准确来说应该是 TF-IDF 特征向量，这是一个稀疏矩阵。下面把它作为描述文章特征的向量。</p><p>说明一点，这里的文章的特征不是由某几个关键词的 TF-IDF 值决定的，而是由所有的词的 TF-IDF 值共同决定的。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">句子A:</span><br/><span class="line"></span><br/><span class="line">[</span><br/><span class="line">  -0.047947012075296815,</span><br/><span class="line">  0.06757751801802739,</span><br/><span class="line">  0.06757751801802739,</span><br/><span class="line">  0,</span><br/><span class="line">  0.06757751801802739,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0</span><br/><span class="line">]</span><br/><span class="line"></span><br/><span class="line">句子B:</span><br/><span class="line"></span><br/><span class="line">[</span><br/><span class="line">  -0.03596025905647261,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0.05068313851352055,</span><br/><span class="line">  0</span><br/><span class="line">]</span><br/><span class="line"></span><br/><span class="line">句子C:</span><br/><span class="line"></span><br/><span class="line">[</span><br/><span class="line">  -0.07192051811294523,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0,</span><br/><span class="line">  0.1013662770270411</span><br/><span class="line">]</span><br/></pre></td></tr></tbody></table></figure><p>可以对文档向量进行标准化，使得这些向量能够不受向量里有效元素多少的影响，也就是不同的文档可能有不同的长度。把向量都标准化为一个单位向量的长度。这个时候再进行点积运算，就相当于在原来的向量上进行余弦相似度的运算。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 32.32ex;" width="full"><svg focusable="false" height="3.048ex" role="img" style="vertical-align: -0.958ex; min-width: 32.32ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -923.5)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 923.5) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="5064.8 -923.5 1 1347"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-173.5)"><g data-mml-node="mtd"><g data-mjx-texclass="ORD" data-mml-node="TeXAtom"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mo" transform="translate(264.5,31) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g><g data-mml-node="mo" transform="translate(751.2,0)"><path d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" data-c="22C5"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1251.4,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" data-c="1D44F"></path></g><g data-mml-node="mo" transform="translate(214.5,283) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g><g data-mml-node="mo" transform="translate(1958.2,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mo" transform="translate(3014,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(3292,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mo" transform="translate(264.5,31) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g><g data-mml-node="mo" transform="translate(3821,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mml-node="mo" transform="translate(4099,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(4377,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" data-c="1D44F"></path></g><g data-mml-node="mo" transform="translate(214.5,283) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g><g data-mml-node="mo" transform="translate(4806,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mml-node="mi" transform="translate(5084,0)"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mi" transform="translate(5517,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(6002,0)"><path d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" data-c="1D460"></path></g><g data-mml-node="mi" transform="translate(6471,0)"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g><g data-mml-node="mo" transform="translate(7217.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(8273.6,0)"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mi" transform="translate(8706.6,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(9191.6,0)"><path d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" data-c="1D460"></path></g><g data-mml-node="mi" transform="translate(9660.6,0)"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -923.5 1 1347"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:7" transform="translate(0,576.5)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" data-c="37" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p></div><div class="story post-story"><h2 id="第八步：计算余弦相似度"><a class="headerlink" href="#第八步：计算余弦相似度" title="第八步：计算余弦相似度"></a>第八步：计算余弦相似度</h2><p>到这里，如何寻找两篇相似文章的问题转变成了如何计算这两个向量的相似程度的问题。</p><p>什么叫做向量相似？</p><p>一般地，如果两个向量平行或重合，我们认为这两个向量相似度为 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.507ex" role="img" style="vertical-align: 0;" viewbox="0 -666 500 666" width="1.131ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g></svg></mjx-container>。如果这两个向量垂直，或者说正交，我们认为这两个向量的相似度为 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.557ex" role="img" style="vertical-align: -0.05ex;" viewbox="0 -666 500 688" width="1.131ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g></g></svg></mjx-container>。</p><p>以二维空间为例，<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.934ex" role="img" style="vertical-align: -0.023ex;" viewbox="0 -845 529 855" width="1.197ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mjx-texclass="ORD" data-mml-node="TeXAtom"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mo" transform="translate(264.5,31) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g></g></g></svg></mjx-container> 和 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.507ex" role="img" style="vertical-align: -0.025ex;" viewbox="0 -1097 429 1108" width="0.971ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mjx-texclass="ORD" data-mml-node="TeXAtom"><g data-mml-node="mover"><g data-mml-node="mi"><path d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" data-c="1D44F"></path></g><g data-mml-node="mo" transform="translate(214.5,283) translate(-250 0)"><path d="M377 694Q377 702 382 708T397 714Q404 714 409 709Q414 705 419 690Q429 653 460 633Q471 626 471 615Q471 606 468 603T454 594Q411 572 379 531Q377 529 374 525T369 519T364 517T357 516Q350 516 344 521T337 536Q337 555 384 595H213L42 596Q29 605 29 615Q29 622 42 635H401Q377 673 377 694Z" data-c="20D7"></path></g></g></g></g></g></svg></mjx-container> 是两个向量，我们要计算它们的夹角 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.618ex" role="img" style="vertical-align: -0.023ex;" viewbox="0 -705 469 715" width="1.061ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g></g></g></svg></mjx-container> 。余弦定理告诉我们，可以用下面的公式求得：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 29.256ex;" width="full"><svg focusable="false" height="4.993ex" role="img" style="vertical-align: -1.931ex; min-width: 29.256ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1353.5)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1353.5) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="4387.6 -1353.5 1 2206.9"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-156.5)"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mi" transform="translate(433,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(918,0)"><path d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" data-c="1D460"></path></g><g data-mml-node="mi" transform="translate(1387,0)"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g><g data-mml-node="mo" transform="translate(2133.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(3189.6,0)"><g data-mml-node="mrow" transform="translate(220,676)"><g data-mml-node="msup"><g data-mml-node="mi"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mn" transform="translate(562,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(1187.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msup" transform="translate(2188,0)"><g data-mml-node="mi"><path d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" data-c="1D44F"></path></g><g data-mml-node="mn" transform="translate(462,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g><g data-mml-node="mo" transform="translate(3275.8,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="msup" transform="translate(4276,0)"><g data-mml-node="mi"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mn" transform="translate(466,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g></g><g data-mml-node="mrow" transform="translate(2063.8,-686)"><g data-mml-node="mn"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(500,0)"><path d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" data-c="1D44E"></path></g><g data-mml-node="mi" transform="translate(1029,0)"><path d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" data-c="1D44F"></path></g></g><rect height="60" width="5345.5" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1353.5 1 2206.9"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:8" transform="translate(0,593.5)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" data-c="38" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>假定<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.62ex" role="img" style="vertical-align: 0;" viewbox="0 -716 750 716" width="1.697ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g></g></g></svg></mjx-container>和<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.545ex" role="img" style="vertical-align: 0;" viewbox="0 -683 759 683" width="1.717ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g></g></g></svg></mjx-container>是两个<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.025ex" role="img" style="vertical-align: -0.025ex;" viewbox="0 -442 600 453" width="1.357ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g></g></svg></mjx-container>维向量，我们把这些向量放到<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.025ex" role="img" style="vertical-align: -0.025ex;" viewbox="0 -442 600 453" width="1.357ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g></g></svg></mjx-container>维欧几里得空间中讨论，向量之间的距离使用欧几里得距离。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 26.31ex;" width="full"><svg focusable="false" height="5.319ex" role="img" style="vertical-align: -2.094ex; min-width: 26.31ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1425.5)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1425.5) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="3736.5 -1425.5 1 2351"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,33.5)"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mi" transform="translate(433,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(918,0)"><path d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" data-c="1D460"></path></g><g data-mml-node="mi" transform="translate(1387,0)"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g><g data-mml-node="mo" transform="translate(2133.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(3189.6,0)"><g data-mml-node="mrow" transform="translate(1026,676)"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mo" transform="translate(972.2,0)"><path d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" data-c="22C5"></path></g><g data-mml-node="mi" transform="translate(1472.4,0)"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g></g><g data-mml-node="mrow" transform="translate(220,-709.5)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mml-node="mi" transform="translate(278,0)"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mo" transform="translate(1028,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mml-node="mo" transform="translate(1528.2,0)"><path d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" data-c="D7"></path></g><g data-mml-node="mo" transform="translate(2528.4,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mml-node="mi" transform="translate(2806.4,0)"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mo" transform="translate(3565.4,0) translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g></g><rect height="60" width="4043.4" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1425.5 1 2351"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:9" transform="translate(0,783.5)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z" data-c="39" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>假定<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.62ex" role="img" style="vertical-align: 0;" viewbox="0 -716 750 716" width="1.697ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g></g></g></svg></mjx-container>是 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex;" viewbox="0 -750 7078.7 1000" width="16.015ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path d="M118 -250V750H255V710H158V-210H255V-250H118Z" data-c="5B"></path></g><g data-mml-node="mi" transform="translate(278,0)"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mn" transform="translate(1028,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(1528,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mi" transform="translate(1972.7,0)"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mn" transform="translate(2722.7,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mo" transform="translate(3222.7,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mo" transform="translate(3667.3,0)"><path d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60ZM525 60Q525 84 542 102T585 120Q609 120 627 104T646 61Q646 36 629 18T586 0T543 17T525 60ZM972 60Q972 84 989 102T1032 120Q1056 120 1074 104T1093 61Q1093 36 1076 18T1033 0T990 17T972 60Z" data-c="2026"></path></g><g data-mml-node="mo" transform="translate(5006,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mi" transform="translate(5450.7,0)"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mi" transform="translate(6200.7,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(6800.7,0)"><path d="M22 710V750H159V-250H22V-210H119V710H22Z" data-c="5D"></path></g></g></g></svg></mjx-container> ，<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.545ex" role="img" style="vertical-align: 0;" viewbox="0 -683 759 683" width="1.717ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g></g></g></svg></mjx-container>是 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex;" viewbox="0 -750 7105.7 1000" width="16.076ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path d="M118 -250V750H255V710H158V-210H255V-250H118Z" data-c="5B"></path></g><g data-mml-node="mi" transform="translate(278,0)"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mn" transform="translate(1037,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(1537,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mi" transform="translate(1981.7,0)"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mn" transform="translate(2740.7,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mo" transform="translate(3240.7,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mo" transform="translate(3685.3,0)"><path d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60ZM525 60Q525 84 542 102T585 120Q609 120 627 104T646 61Q646 36 629 18T586 0T543 17T525 60ZM972 60Q972 84 989 102T1032 120Q1056 120 1074 104T1093 61Q1093 36 1076 18T1033 0T990 17T972 60Z" data-c="2026"></path></g><g data-mml-node="mo" transform="translate(5024,0)"><path d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" data-c="2C"></path></g><g data-mml-node="mi" transform="translate(5468.7,0)"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mi" transform="translate(6227.7,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(6827.7,0)"><path d="M22 710V750H159V-250H22V-210H119V710H22Z" data-c="5D"></path></g></g></g></svg></mjx-container> ，则<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.62ex" role="img" style="vertical-align: 0;" viewbox="0 -716 750 716" width="1.697ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g></g></g></svg></mjx-container>与<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.545ex" role="img" style="vertical-align: 0;" viewbox="0 -683 759 683" width="1.717ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g></g></g></svg></mjx-container>的夹角<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.618ex" role="img" style="vertical-align: -0.023ex;" viewbox="0 -705 469 715" width="1.061ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g></g></g></svg></mjx-container>的余弦等于：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 43.748ex;" width="full"><svg focusable="false" height="7.722ex" role="img" style="vertical-align: -3.295ex; min-width: 43.748ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1956.5)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2578,0) translate(-2578,0)"><g transform="translate(0 1956.5) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="7090.4 -1956.5 1 3412.9"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,363.5)"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" data-c="1D450"></path></g><g data-mml-node="mi" transform="translate(433,0)"><path d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z" data-c="1D45C"></path></g><g data-mml-node="mi" transform="translate(918,0)"><path d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" data-c="1D460"></path></g><g data-mml-node="mi" transform="translate(1387,0)"><path d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" data-c="1D703"></path></g><g data-mml-node="mo" transform="translate(2133.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(3189.6,0)"><g data-mml-node="mrow" transform="translate(2270.6,803.3)"><g data-mml-node="munderover"><g data-mml-node="mo"><path d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z" data-c="2211"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,477.1) scale(0.707)"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,-285.4) scale(0.707)"><g data-mml-node="mi"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g><g data-mml-node="mo" transform="translate(345,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(1123,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="mo" transform="translate(2286.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="msub" transform="translate(2675.6,0)"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mi" transform="translate(783,-150) scale(0.707)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g></g><g data-mml-node="mo" transform="translate(3974.8,0)"><path d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" data-c="D7"></path></g><g data-mml-node="msub" transform="translate(4975,0)"><g data-mml-node="mi"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mi" transform="translate(792,-150) scale(0.707)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g></g><g data-mml-node="mo" transform="translate(6061,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g><g data-mml-node="mrow" transform="translate(220,-1228.1)"><g data-mml-node="msqrt"><g transform="translate(1020,0)"><g data-mml-node="munderover"><g data-mml-node="mo"><path d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z" data-c="2211"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,477.1) scale(0.707)"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,-285.4) scale(0.707)"><g data-mml-node="mi"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g><g data-mml-node="mo" transform="translate(345,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(1123,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="msubsup" transform="translate(2453.3,0)"><g data-mml-node="mi"><path d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" data-c="1D434"></path></g><g data-mml-node="mn" transform="translate(783,353.6) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(783,-293.8) scale(0.707)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g></g></g><g data-mml-node="mo" transform="translate(0,58.1)"><path d="M1001 1150Q1017 1150 1020 1132Q1020 1127 741 244L460 -643Q453 -650 436 -650H424Q423 -647 423 -645T421 -640T419 -631T415 -617T408 -594T399 -560T385 -512T367 -448T343 -364T312 -259L203 119L138 41L111 67L212 188L264 248L472 -474L983 1140Q988 1150 1001 1150Z" data-c="221A"></path></g><rect height="60" width="3639.9" x="1020" y="1148.1"></rect></g><g data-mml-node="mo" transform="translate(4882.1,0)"><path d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" data-c="D7"></path></g><g data-mml-node="msqrt" transform="translate(5882.3,0)"><g transform="translate(1020,0)"><g data-mml-node="munderover"><g data-mml-node="mo"><path d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z" data-c="2211"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,477.1) scale(0.707)"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1089,-285.4) scale(0.707)"><g data-mml-node="mi"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g><g data-mml-node="mo" transform="translate(345,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(1123,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="msubsup" transform="translate(2453.3,0)"><g data-mml-node="mi"><path d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" data-c="1D435"></path></g><g data-mml-node="mn" transform="translate(792,353.6) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(792,-293.8) scale(0.707)"><path d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" data-c="1D456"></path></g></g></g><g data-mml-node="mo" transform="translate(0,58.1)"><path d="M1001 1150Q1017 1150 1020 1132Q1020 1127 741 244L460 -643Q453 -650 436 -650H424Q423 -647 423 -645T421 -640T419 -631T415 -617T408 -594T399 -560T385 -512T367 -448T343 -364T312 -259L203 119L138 41L111 67L212 188L264 248L472 -474L983 1140Q988 1150 1001 1150Z" data-c="221A"></path></g><rect height="60" width="3648.9" x="1020" y="1148.1"></rect></g></g><rect height="60" width="10751.2" x="120" y="220"></rect></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1778 -1956.5 1 3412.9"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:10" transform="translate(0,1113.5)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31" transform="translate(389,0)"></path><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30" transform="translate(889,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(1389,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">&#123;</span><br/><span class="line">  <span class="string">'句子A'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子A'</span>: 1.0000000000000002,</span><br/><span class="line">    <span class="string">'句子B'</span>: 0.21934876427664535,</span><br/><span class="line">    <span class="string">'句子C'</span>: 0.21934876427664535</span><br/><span class="line">  &#125;,</span><br/><span class="line">  <span class="string">'句子B'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子A'</span>: 0.21934876427664535,</span><br/><span class="line">    <span class="string">'句子B'</span>: 1,</span><br/><span class="line">    <span class="string">'句子C'</span>: 0.33484380220099325</span><br/><span class="line">  &#125;,</span><br/><span class="line">  <span class="string">'句子C'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子A'</span>: 0.21934876427664535,</span><br/><span class="line">    <span class="string">'句子B'</span>: 0.33484380220099325,</span><br/><span class="line">    <span class="string">'句子C'</span>: 1</span><br/><span class="line">  &#125;</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="第九步：余弦相似度按照降序排序"><a class="headerlink" href="#第九步：余弦相似度按照降序排序" title="第九步：余弦相似度按照降序排序"></a>第九步：余弦相似度按照降序排序</h2><p>两两计算向量夹角的余弦值，然后按降序排列，取排在最前面的几个文章，就是相似度较高的文章，作为推荐结果。</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">&#123;</span><br/><span class="line">  <span class="string">'句子A'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子A'</span>: 1.0000000000000002,</span><br/><span class="line">    <span class="string">'句子B'</span>: 0.21934876427664535,</span><br/><span class="line">    <span class="string">'句子C'</span>: 0.21934876427664535</span><br/><span class="line">  &#125;,</span><br/><span class="line">  <span class="string">'句子B'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子B'</span>: 1,</span><br/><span class="line">    <span class="string">'句子C'</span>: 0.33484380220099325,</span><br/><span class="line">    <span class="string">'句子A'</span>: 0.21934876427664535</span><br/><span class="line">  &#125;,</span><br/><span class="line">  <span class="string">'句子C'</span>: &#123;</span><br/><span class="line">    <span class="string">'句子C'</span>: 1,</span><br/><span class="line">    <span class="string">'句子B'</span>: 0.33484380220099325,</span><br/><span class="line">    <span class="string">'句子A'</span>: 0.21934876427664535,</span><br/><span class="line">  &#125;</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><p>相同句子的余弦值是 <mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.507ex" role="img" style="vertical-align: 0;" viewbox="0 -666 500 666" width="1.131ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g></svg></mjx-container>. 余弦值越接近<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.507ex" role="img" style="vertical-align: 0;" viewbox="0 -666 500 666" width="1.131ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g></svg></mjx-container>，就表明夹角越接近<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.557ex" role="img" style="vertical-align: -0.05ex;" viewbox="0 -666 500 688" width="1.131ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g></g></svg></mjx-container>度，也就是两个向量越相似.</p></div><div class="story post-story"><h2 id="第十步：收集推荐结果"><a class="headerlink" href="#第十步：收集推荐结果" title="第十步：收集推荐结果"></a>第十步：收集推荐结果</h2><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">&#123;</span><br/><span class="line">  <span class="string">'句子A'</span>: [ <span class="string">'句子B'</span>, <span class="string">'句子C'</span> ],</span><br/><span class="line">  <span class="string">'句子B'</span>: [ <span class="string">'句子C'</span>, <span class="string">'句子A'</span> ],</span><br/><span class="line">  <span class="string">'句子C'</span>: [ <span class="string">'句子B'</span>, <span class="string">'句子A'</span> ]</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><p>即：</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">A-B</span><br/><span class="line">B-C</span><br/><span class="line">C-B</span><br/></pre></td></tr></tbody></table></figure><p>A 和 C 之间没什么关系。</p></div><div class="story post-story"><h2 id="源码实现"><a class="headerlink" href="#源码实现" title="源码实现"></a>源码实现</h2><div class="tag link"><a class="link-card" href="https://github.com/volantis-x/hexo-theme-volantis/blob/684c40333b16b5d1df1a9e4a7f1da90216e5a17a/scripts/helpers/文章推荐.js" title="Volantis主题实现文章推荐"><div class="left"><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/volantis-static@0.0.1649552113628/media/twemoji/assets/svg/1f433.svg" src="https://unpkg.com/volantis-static@0.0.1649552113628/media/twemoji/assets/svg/1f433.svg"/></img></div><div class="right"><p class="text">Volantis 主题实现文章推荐</p><p class="url">https://github.com/volantis-x/hexo-theme-volantis/blob/684c40333b16b5d1df1a9e4a7f1da90216e5a17a/scripts/helpers/ 文章推荐.js</p></div></a></div><p><del>UI 界面是随手写的，又不是不能用（</del></p><p>代码变量是中文写的，方便易读。<psw>其实是中间出 Bug 了，然后调试 Debug 时顺便整的活</psw></p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="尝试在博客中添加简易文章推荐功能" href="https://blog.mhuig.top/p/175a1706/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">尝试在博客中添加简易文章推荐功能</span><span class="cap link fs12">https://blog.mhuig.top/p/175a1706/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>记一次重装系统 (Win11)</title>
    <link href="https://blog.imc.re/RSSBOX/rss/7de86e6a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/7de86e6a.html</id>
    <published>2022-08-10T17:18:00.000Z</published>
    <updated>2022-08-10T17:18:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>电脑开机后要先卡顿 30 min，然后才能正常工作，还有不明程序一直在读写磁盘，噪声太大了，没救了重装系统吧。</p><p><img><img alt="win11" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1660181609153/win11.png" src="https://unpkg.com/mhgoos@0.0.1660181609153/win11.png"/></img></p><p>重装系统之后操作瞬间就流畅很多～</p><p>意料之外：重装系统之后，win11 自带的杀软开始报毒，之前在虚拟机看过镜像中是没有这个病毒文件的。使用老毛桃制作启动盘，事先格式了系统盘，推测可能是老毛桃启动盘释放的病毒文件，或者是上一个系统的隐藏分区释放的病毒文件，<a href="https://www.google.com/search?q=%E8%80%81%E6%AF%9B%E6%A1%83%E5%90%AF%E5%8A%A8%E7%9B%98%E6%90%BA%E5%B8%A6%E6%9C%A8%E9%A9%AC%E7%97%85%E6%AF%92">google: 老毛桃启动盘携带木马病毒</a>，这里建议使用微软官方的镜像和安装介质。</p><blockquote><p>重装系统前的备份列表 以下内容适用于 win10 与 win11</p></blockquote><div class="story post-story"><h2 id="PE"><a class="headerlink" href="#PE" title="PE"></a>PE</h2><ul><li><a href="https://www.microsoft.com/zh-cn/software-download/windows11">官方镜像和安装介质</a></li><li><a href="http://www.laomaotao.org/">老毛桃 UEFI 版</a></li></ul></div><div class="story post-story"><h2 id="操作系统"><a class="headerlink" href="#操作系统" title="操作系统"></a>操作系统</h2><ul><li><a href="https://www.xitongku.com/">windows 镜像库</a></li></ul><p>Win11 安装跳过 tpm 2.0 检测的方法</p><p>TPM 对笔者来说毫无用处</p><p>打开 Windows 11 的 ISO 镜像安装包，打开后将目录 Source 中的 install.wim 文件复制到桌面上。然后解压 Windows 10 的 ISO 安装包，然后将 Win11 的 install.win 文件拷到解压后的 win10 安装包的 sources 文件夹，双击 Windows 10 安装包里的 setup.exe 文件开始安装，借用 Windows10 安装程序去安装 Windows11 系统</p><ul><li><a href="https://bbs.kafan.cn/thread-2134799-1-1.html">W10 Digital License Activation Script</a></li></ul><p>笔者发现装完系统以后 win11 已经激活了，是因为之前使用了 W10 Digital License Activation Script。</p></div><div class="story post-story"><h2 id="Office"><a class="headerlink" href="#Office" title="Office"></a>Office</h2><ul><li><a href="https://www.xitongku.com/office.html">Office 镜像库</a></li><li><a href="https://otp.landian.vip/zh-cn/">Office Tool Plus</a><blockquote><p><a href="https://www.coolhub.top/archives/14">Office Tool Plus 入门教程</a></p></blockquote></li><li><a href="https://www.coolhub.top/tech-articles/kms_list.html">kms list</a><blockquote><p>kms.loli.best 1688</p></blockquote></li></ul></div><div class="story post-story"><h2 id="浏览器"><a class="headerlink" href="#浏览器" title="浏览器"></a>浏览器</h2><ul><li><a href="https://www.google.com/intl/zh-CN/chrome/">Chrome</a></li><li><a href="https://www.mozilla.org/zh-CN/firefox/new/">Firefox</a></li><li><a href="https://www.torproject.org/zh-CN/download/">Tor Browser</a></li></ul></div><div class="story post-story"><h2 id="安全管理"><a class="headerlink" href="#安全管理" title="安全管理"></a>安全管理</h2><ul><li><a href="https://www.huorong.cn/">火绒安全</a></li><li><a href="https://guanjia.qq.com/">腾讯电脑管家</a></li><li><a href="https://kaspersky.com/">Kaspersky</a></li></ul><p>暂时只装火绒。</p></div><div class="story post-story"><h2 id="Windows-应用商店"><a class="headerlink" href="#Windows-应用商店" title="Windows 应用商店"></a>Windows 应用商店</h2><ul><li>7-zip</li><li>Ubuntu On windows</li><li>Kali Linux</li></ul></div><div class="story post-story"><h2 id="IDE-文本编辑器"><a class="headerlink" href="#IDE-文本编辑器" title="IDE 文本编辑器"></a>IDE 文本编辑器</h2><ul><li><a href="https://code.visualstudio.com/">Visual Studio Code</a></li><li><a href="https://visualstudio.microsoft.com/zh-hans/vs/">Visual Studio</a><blockquote><p>vs2022 永久激活密钥：<br/>Visual Studio 2022 Enterprise：VHF9H-NXBBB-638P6-6JHCY-88JWH<br/>Visual Studio 2022 Professional：TD244-P4NB7-YQ6XK-Y8MMM-YWV2J</p></blockquote></li><li><a href="https://www.codeblocks.org/">CodeBlocks</a></li><li><a href="https://www.jetbrains.com/zh-cn/pycharm/">JetBrains Pycharm</a></li><li><a href="https://www.jetbrains.com/zh-cn/idea/">JetBrains Idea</a><blockquote><p><a href="https://www.exception.site/essay/how-to-free-use-intellij-idea-2019-3">https://www.exception.site/essay/how-to-free-use-intellij-idea-2019-3</a></p></blockquote></li><li><a href="https://notepad-plus-plus.org/">Notepad++</a></li><li><a href="https://www.eclipse.org/downloads/">Eclipse</a></li><li><a href="https://www.myeclipsecn.com/">MyEclipse</a></li><li>Typora</li><li>Matlab</li></ul></div><div class="story post-story"><h2 id="代理工具"><a class="headerlink" href="#代理工具" title="代理工具"></a>代理工具</h2><ul><li><a href="https://github.com/Fndroid/clash_for_windows_pkg/releases">Clash for Windows</a></li><li><a href="https://github.com/2dust/v2rayN">V2rayN</a></li><li><a href="https://github.com/shadowsocksr-backup/shadowsocksr-csharp/releases">ShadowsocketsR</a></li></ul></div><div class="story post-story"><h2 id="DOH"><a class="headerlink" href="#DOH" title="DOH"></a>DOH</h2><ul><li>阿里：<a href="https://dns.alidns.com/dns-query">https://dns.alidns.com/dns-query</a></li><li> 腾讯：<a href="https://doh.pub/dns-query">https://doh.pub/dns-query</a></li></ul></div><div class="story post-story"><h2 id="驱动"><a class="headerlink" href="#驱动" title="驱动"></a>驱动</h2><ul><li>NVIDIA</li><li>ATK Package</li><li>cuda</li><li>cudnn</li></ul></div><div class="story post-story"><h2 id="开发环境"><a class="headerlink" href="#开发环境" title="开发环境"></a>开发环境</h2><ul><li><p><a href="https://jmeubank.github.io/tdm-gcc/">TDM-GCC x64</a></p></li><li><p><a href="https://www.python.org/downloads/">python</a></p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">pip config <span class="built_in">set</span> global.index-url https://pypi.tuna.tsinghua.edu.cn/simple</span><br/></pre></td></tr></tbody></table></figure><blockquote><p>Writing to %appdata%\pip\pip.ini</p></blockquote></li><li><p><a href="https://www.anaconda.com/">anaconda</a></p></li><li><p><a href="https://www.oracle.com/java/technologies/downloads/#java8-windows">Java SE Development Kit</a></p></li><li><p><a href="https://github.com/coreybutler/nvm-windows/releases">nvm</a></p><blockquote><p>找到 nvm 文件位置，点开 settings.txt</p></blockquote><figure class="highlight plaintext"><table><tbody><tr><td class="code"><pre><span class="line">root: C:\software\nvm</span><br/><span class="line">path: C:\software\nodejs</span><br/><span class="line">node_mirror: https://npm.taobao.org/mirrors/node/</span><br/><span class="line">npm_mirror: https://npm.taobao.org/mirrors/npm/</span><br/></pre></td></tr></tbody></table></figure><p>使用</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">nvm <span class="built_in">ls</span>                      // 看安装的所有node.js的版本</span><br/><span class="line">nvm list available          // 查显示可以安装的所有node.js的版本</span><br/><span class="line">nvm install 版本号          // 例如：nvm install 16.16.0</span><br/><span class="line">nvm use 版本号              // 切换到使用指定的nodejs版本</span><br/></pre></td></tr></tbody></table></figure></li></ul></div><div class="story post-story"><h2 id="版本控制"><a class="headerlink" href="#版本控制" title="版本控制"></a>版本控制</h2><ul><li><a href="https://git-scm.com/downloads">Git</a></li><li><a href="https://desktop.github.com/">GitHub DeskTop</a></li></ul><p>配置 .gitconfig</p><figure class="highlight plaintext"><figcaption><span>.gitconfig</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">[user]</span><br/><span class="line">    name = MHuiG</span><br/><span class="line">    email = xxxxxx@qq.com</span><br/><span class="line">    signingkey = BA16368BD4C4169C</span><br/><span class="line">[gui]</span><br/><span class="line">    encoding = utf-8</span><br/><span class="line">[filter "lfs"]</span><br/><span class="line">    smudge = git-lfs smudge -- %f</span><br/><span class="line">    process = git-lfs filter-process</span><br/><span class="line">    required = true</span><br/><span class="line">    clean = git-lfs clean -- %f</span><br/><span class="line">[http]</span><br/><span class="line">    schannelCheckRevoke = false</span><br/><span class="line">[commit]</span><br/><span class="line">    gpgsign = true</span><br/><span class="line">[gpg]</span><br/><span class="line">    program = C:\\software\\GnuPG\\bin\\gpg.exe</span><br/><span class="line">[init]</span><br/><span class="line">    defaultBranch = main</span><br/><span class="line">[core]</span><br/><span class="line">    editor = \"C:\\software\\Microsoft VS Code\\bin\\code\" --wait</span><br/><span class="line"></span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="聊天工具"><a class="headerlink" href="#聊天工具" title="聊天工具"></a>聊天工具</h2><ul><li><a href="https://im.qq.com/download">QQ</a></li><li><a href="https://weixin.qq.com/">微信</a></li><li><a href="https://work.weixin.qq.com/">企业微信</a></li><li><a href="https://telegram.org/">Telegram Desktop</a></li></ul></div><div class="story post-story"><h2 id="远程连接"><a class="headerlink" href="#远程连接" title="远程连接"></a>远程连接</h2><ul><li><a href="https://www.xshell.com/zh/free-for-home-school/">Xshell</a></li><li><a href="https://www.xshell.com/zh/free-for-home-school/">Xftp</a></li><li>SecureCRT</li><li>VNC</li></ul></div><div class="story post-story"><h2 id="数据库"><a class="headerlink" href="#数据库" title="数据库"></a>数据库</h2><ul><li><a href="https://dev.mysql.com/downloads/mysql/">MySQL</a></li><li>Navicat</li><li>mongoDB</li><li>Robo 3T</li><li>redis</li><li>RedisDesktopManager</li></ul></div><div class="story post-story"><h2 id="截屏工具"><a class="headerlink" href="#截屏工具" title="截屏工具"></a>截屏工具</h2><ul><li><a href="https://github.com/NickeManarin/ScreenToGif">ScreenToGif</a></li><li><a href="https://getgreenshot.org/">Greenshot</a></li></ul></div><div class="story post-story"><h2 id="GPG"><a class="headerlink" href="#GPG" title="GPG"></a>GPG</h2><ul><li><a href="https://keybase.io/">keybase</a></li><li><a href="https://www.gnupg.org/download/index.html">Gpg4win</a></li></ul></div><div class="story post-story"><h2 id="下载工具"><a class="headerlink" href="#下载工具" title="下载工具"></a>下载工具</h2><ul><li><a href="https://www.xunlei.com/">迅雷</a></li><li>百度网盘 </li><li><a href="http://aria2.baisheng999.com/">Aria2</a></li></ul></div><div class="story post-story"><h2 id="杂项"><a class="headerlink" href="#杂项" title="杂项"></a>杂项</h2><ul><li><a href="https://shurufa.sogou.com/">搜狗输入法</a></li><li><a href="https://www.vmware.com/">VMware</a><blockquote><p>16: ZF3R0-FHED2-M80TY-8QYGC-NPKYF</p></blockquote></li><li><a href="https://www.xmind.cn/">XMind</a></li><li><a href="https://www.postman.com/">PostMan</a></li><li><a href="https://cidian.youdao.com/">网易有道词典</a></li><li><a href="https://cajviewer.cnki.net/">CAJViewer</a></li><li><a href="https://www.ipip.net/product/client.html">BestTrace</a></li><li><a href="http://staruml.io/download">StarUML</a></li><li><a href="https://portal.hdfgroup.org/display/HDFVIEW/HDFView">HDFView</a></li><li><a href="https://www.google.com/search?q=Adobe+Photoshop+2022+site:rutracker.org">Adobe Photo Shop</a></li><li> 网易云音乐</li><li> MathType</li><li>PotPlayerPortable</li><li><a href="https://github.com/Chuyu-Team/Dism-Multi-language/releases">Dism++</a></li><li>UltraISO</li><li>MyDiskTest</li><li><a href="https://www.diskgenius.cn/">DiskGenius</a></li></ul></div><div class="story post-story"><h2 id="chrome-扩展"><a class="headerlink" href="#chrome-扩展" title="chrome 扩展"></a>chrome 扩展</h2><ul><li>AdBlock — 最佳广告拦截工具</li><li> Enable Copy</li><li>MetaMask</li><li>Tampermonkey BETA</li><li>Wappalyzer - Technology profiler</li><li> 迅雷下载支持</li></ul></div><div class="story post-story"><h2 id="windows-导出备份-WiFi-密码"><a class="headerlink" href="#windows-导出备份-WiFi-密码" title="windows 导出备份 WiFi 密码"></a>windows 导出备份 WiFi 密码</h2><figure class="highlight bash"><figcaption><span>Wi-Fi-code.bat</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">@<span class="built_in">echo</span> off </span><br/><span class="line"> </span><br/><span class="line"><span class="keyword">for</span> /f <span class="string">"skip=9 tokens=1,2 delims=:"</span> %%i <span class="keyword">in</span> (<span class="string">'netsh wlan show profiles'</span>) <span class="keyword">do</span> @<span class="built_in">echo</span> %%j | findstr -i -v <span class="built_in">echo</span> | netsh wlan show profiles %%j key=clear &gt;&gt;%USERPROFILE%\desktop\Wi-Fi-code.txt</span><br/><span class="line">start %USERPROFILE%\desktop\Wi-Fi-code.txt</span><br/><span class="line"></span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="windows-提权"><a class="headerlink" href="#windows-提权" title="windows 提权"></a>windows 提权</h2><p>装完系统先搞权限。</p><h3 id="夺回-Windows-系统权限"><a class="headerlink" href="#夺回-Windows-系统权限" title="夺回 Windows 系统权限"></a>夺回 Windows 系统权限</h3><p>碰到过这样的提示：“无法使用内置管理员账户打开 XX 程序，请使用其他账户登录”</p><p>其实已经使用管理员账户登录了，为什么还会出现这样的提示呢？</p><p>这是因为使用的内置账户没有对应用程序的操作权限，可以使用注册表来夺回 Windows10 系统权限。</p><p>账户详解：</p><p>使用的管理员账户，就是使用用户名或微软账号登录到 Windows 的账号，管理权限无限近似于 Administrator，但在某些文件 / 文件夹的操作上，还是不如真正的 Administrator 好用。</p><p>在 Windows 内置的账户中，还有两个比  Administrator 权限更高的账户，一个是肉眼可见的 System 权限，最终的 Boss 则是 TrustedInstaller，其实所有账户中它也不是最高的那个，但剩下的无论通过什么方式，都挖掘不出来了，也许超级账户就是 Microsoft 自己了。</p><p>Windows 夺回系统权限的操作方法：</p><ul><li>1、<code>Win+R</code> 组合键之后，输入 <code>regedit</code> ，打开注册表；</li><li>2、定位到：<code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System</code> ，在右侧栏找到 <code>FilterAdministratorToken</code> ，双击后将数值数据修改为 <code>1</code> 之后点击 确定。（如果没有的话，就使用鼠标右键新建个 <code>DWORD（32位）</code> 值，将其命名为 <code>FilterAdministratorToken</code> 。）</li><li>3、之后再定位到：<code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\UIPI</code> ，将右侧的默认项目的数值数据修改为 <code>1</code>。</li><li>4、完成上述操作后，重启电脑或注销当前 Windows 账户后，再进入 “控制面板 - 系统与安全 - 用户账户控制设置”，将 “通知选项” 设置为默认就 OK 了。</li></ul><h3 id="开启-administrator-账户"><a class="headerlink" href="#开启-administrator-账户" title="开启 administrator 账户"></a>开启 administrator 账户</h3><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">net user administrator /active:<span class="built_in">yes</span></span><br/></pre></td></tr></tbody></table></figure><h3 id="右键菜单权限选项"><a class="headerlink" href="#右键菜单权限选项" title="右键菜单权限选项"></a>右键菜单权限选项</h3><figure class="highlight bash"><figcaption><span>管理员取得所有权.reg</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br/><span class="line">[-HKEY_CLASSES_ROOT\*\shell\runas]</span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas]</span><br/><span class="line">@=<span class="string">"获取超级管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,-78"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas\<span class="built_in">command</span>]</span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line">[-HKEY_CLASSES_ROOT\Directory\shell\runas]</span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas]</span><br/><span class="line">@=<span class="string">"获取超级管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,-78"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas\<span class="built_in">command</span>]</span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/><span class="line">[-HKEY_CLASSES_ROOT\dllfile\shell]</span><br/><span class="line">[HKEY_CLASSES_ROOT\dllfile\shell\runas]</span><br/><span class="line">@=<span class="string">"获取超级管理员权限"</span></span><br/><span class="line"><span class="string">"HasLUAShield"</span>=<span class="string">""</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\dllfile\shell\runas\<span class="built_in">command</span>]</span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line">[-HKEY_CLASSES_ROOT\Drive\shell\runas]</span><br/><span class="line">[HKEY_CLASSES_ROOT\Drive\shell\runas]</span><br/><span class="line">@=<span class="string">"获取超级管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,-78"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Drive\shell\runas\<span class="built_in">command</span>]</span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/></pre></td></tr></tbody></table></figure><figure class="highlight bash"><figcaption><span>恢复原始权限.reg</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br/><span class="line">;恢复原始权限  </span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas-]  </span><br/><span class="line">@=<span class="string">"恢复原始权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,101"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">; &amp;&amp; takeown /f \"%1\"</span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas-\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\exefile\shell\runas2-]  </span><br/><span class="line">@=<span class="string">"恢复原始权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,101"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\exefile\shell\runas2-\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas-]  </span><br/><span class="line">@=<span class="string">"恢复原始权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,101"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas-\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /reset &amp;&amp; cacls \"%1\" /e /r \"%%USERNAME%%\""</span></span><br/></pre></td></tr></tbody></table></figure><figure class="highlight bash"><figcaption><span>取得文件修改权限.reg</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br/><span class="line">;取得文件修改权限  </span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas]  </span><br/><span class="line">@=<span class="string">"获取管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,102"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\*\shell\runas\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\exefile\shell\runas2]  </span><br/><span class="line">@=<span class="string">"获取管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,102"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\exefile\shell\runas2\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" &amp;&amp; icacls \"%1\" /grant administrators:F"</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas]  </span><br/><span class="line">@=<span class="string">"获取管理员权限"</span></span><br/><span class="line"><span class="string">"Icon"</span>=<span class="string">"C:\\Windows\\System32\\imageres.dll,102"</span></span><br/><span class="line"><span class="string">"NoWorkingDirectory"</span>=<span class="string">""</span></span><br/><span class="line">[HKEY_CLASSES_ROOT\Directory\shell\runas\<span class="built_in">command</span>]  </span><br/><span class="line">@=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/><span class="line"><span class="string">"IsolatedCommand"</span>=<span class="string">"cmd.exe /c takeown /f \"%1\" /r /d y &amp;&amp; icacls \"%1\" /grant administrators:F /t"</span></span><br/></pre></td></tr></tbody></table></figure><figure class="highlight bash"><figcaption><span>移除权限选项.reg</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br/><span class="line">[-HKEY_CLASSES_ROOT\*\shell\runas]</span><br/><span class="line">[-HKEY_CLASSES_ROOT\exefile\shell\runas2]</span><br/><span class="line">[-HKEY_CLASSES_ROOT\Directory\shell\runas]</span><br/><span class="line">[-HKEY_CLASSES_ROOT\*\shell\runas-]</span><br/><span class="line">[-HKEY_CLASSES_ROOT\exefile\shell\runas2-]</span><br/><span class="line">[-HKEY_CLASSES_ROOT\Directory\shell\runas-]</span><br/></pre></td></tr></tbody></table></figure><h3 id="获取-TrustedInstaller-超级权限"><a class="headerlink" href="#获取-TrustedInstaller-超级权限" title="获取 TrustedInstaller 超级权限"></a>获取 TrustedInstaller 超级权限</h3><blockquote><p>TrustedInstaller 超级权限是凌驾于管理员权限和系统权限之上的存在</p></blockquote><p>TrustedInstaller 超级权限的添加方法：</p><p>下载注册表权限修改工具 SetACL: </p><p><a href="https://helgeklein.com/download/#download-setacl">https://helgeklein.com/download/#download-setacl</a></p><p>SetACL 文档： </p><p><a href="https://helgeklein.com/setacl/">https://helgeklein.com/setacl/</a></p><p><a href="https://helgeklein.com/setacl/documentation/command-line-version-setacl-exe/">https://helgeklein.com/setacl/documentation/command-line-version-setacl-exe/</a></p><p>按照如下格式设置执行获取权限命令：</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">SetACL -on 对象名称 -ot 对象类型 -actn 操作</span><br/></pre></td></tr></tbody></table></figure><p>对象名称 (<code>-on</code>)：这是 SetACL 应操作的对象的路径。<br/>对象类型（<code>-ot</code>）：对象名称指的是什么类型的对象：文件或目录（<code>file</code>）、注册表项（<code>reg</code>）、服务（<code>srv</code>）、打印机（<code>prn</code>）、网络共享（<code>shr</code>）<br/>操作 (<code>-actn</code>)：SetACL 应该如何处理指定的对象</p><p>注册表值权限获取就可以用如下命令：</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">SetACL.exe -on <span class="string">"HKEY_CLASSES_ROOT\XXX\&#123;xxxxxxx-666-5555-EEEE-yyyyyy&#125;"</span> -ot reg -actn setowner -ownr <span class="string">"n:Administrators"</span></span><br/><span class="line">;;注释：将上述注册表项所有者更新到管理员 Administrator（默认为不可更改的 TrustedInstaller ）。</span><br/><span class="line">SetACL.exe -on <span class="string">"HKEY_CLASSES_ROOT\XXX\&#123;xxxxxxx-666-5555-EEEE-yyyyyy&#125;"</span> -ot reg -actn ace -ace <span class="string">"n:Administrators;p:full"</span></span><br/><span class="line">;;注释：让上述注册表项所有者 Administrator 获取全部权限。</span><br/></pre></td></tr></tbody></table></figure><p>注意，上述命令缺一不可，而且要按照先后顺序执行。</p><p>友情提醒：命令 <code>SetACL -on 对象名称 -ot 对象类型 -actn 操作</code> 适合文件、文件夹（需要写详细路径）和注册表项目超级权限获取，各位可按需提权，出于安全考虑，切勿滥用。如果修改完毕，还可以考虑把命令中的管理员 Administrator 替换为 TrustedInstaller 再次执行命令，恢复系统默认，确保安全。</p></div><div class="story post-story"><h2 id="windows-取消登录界面的名字"><a class="headerlink" href="#windows-取消登录界面的名字" title="windows 取消登录界面的名字"></a>windows 取消登录界面的名字</h2><ul><li>1、打开 regedit。</li><li>2、定位到以下位置：<code>\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\</code>，找到名为 <code>dontdisplaylastusername</code> 的键值，双击它，然后将它的数值数据改为 <code>1</code>。</li><li>3、将鼠标光标放在左侧树状列表的 System 项上，单击右键，选择新建 - DWORD（32 位）值，并将该值命名为：<code>DontDisplayLockedUserID</code>。</li><li>4、双击我们刚刚新建的名为 <code>DontDisplayLockedUserID</code>  的 DWORD（32 位）值，你将看到一个编辑 DWORD（32 位）值的窗口。在这个窗口中，将 <code>DontDisplayLockedUserID</code> 的数值数据改为 <code>3</code>。</li><li>5、修改完成后，关闭注册表编辑器，在开始菜单中点击你的头像，再点击锁定，你将看到锁屏界面。</li><li>6、按回车键，或者使用鼠标点击屏幕，你将看到 Win 登录界面。这时我们可以看到，我们的名字已经显示为 “解锁电脑”。</li><li>7、要登录  Win，你需要手动输入用户名和密码或者 PIN，需要注意的是，这个用户名以 <code>C:\Users</code> 中的为准。如果你不清楚你当前的用户名，那么可以打开命令提示符后，里面显示的是 <code>C:\Users\XXX &gt;</code>，那么当前的用户名就是 <code>XXX</code> ，在登录 Win 时，将 <code>XXX</code> 填入用户名的输入框即可。</li></ul><p>要将 Win10 登陆界面恢复为显示姓名也非常简单，只需再次来到注册表，然后双击名为 <code>dontdisplaylastusername</code> 的键值，将它的数值数据改为 <code>0</code> 即可。</p></div><div class="story post-story"><h2 id="windows-取消登录界面电源按钮"><a class="headerlink" href="#windows-取消登录界面电源按钮" title="windows 取消登录界面电源按钮"></a>windows 取消登录界面电源按钮</h2><p>1、按下 <code>Win+r</code> 打开运行，输入 <code>regedit</code> 回车，打开注册表编辑器；<br/>2、定位至：<code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System</code>，然后你就会看到 <code>shutdownwithoutlogon</code> 这个 32 位的 DWORD 值；<br/>3、双击 <code>shutdownwithoutlogon</code>，打开编辑界面，将数据设置为<code>０</code>；原值为<code> 1</code>.<br/>4、操作完成后，你就会发现，登陆界面的电源按钮没了。</p></div><div class="story post-story"><h2 id="上帝模式"><a class="headerlink" href="#上帝模式" title="上帝模式"></a>上帝模式</h2><p>即 God Mode 完全控制面板</p><p>开启方法:</p><p>新建文件夹重命名为</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">GodMode.&#123;ED7BA470-8E54-465E-825C-99712043E01C&#125;</span><br/></pre></td></tr></tbody></table></figure></div><div class="story post-story"><h2 id="时间显示到秒"><a class="headerlink" href="#时间显示到秒" title="时间显示到秒"></a>时间显示到秒</h2><p>实验中发现 win11 删除了注册表 ShowSecondsInSystemClock，需要先下载安装 <code>startallback</code>，然后笔者放弃了时间显示到秒。</p><ul><li>win11 需要先下载安装 <code>startallback</code>, win10 直接修改注册表</li><li>修改注册表 <code>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced</code></li><li>新建 DWORD (32 位) 值 改为 <code>1</code>: “ShowSecondsInSystemClock”=dword:00000001</li><li> 重启</li></ul></div><div class="story post-story"><h2 id="使用注册表隐藏磁盘盘符"><a class="headerlink" href="#使用注册表隐藏磁盘盘符" title="使用注册表隐藏磁盘盘符"></a>使用注册表隐藏磁盘盘符</h2><p>具体操作如下：</p><p>注：在开始之前，请使用 Administrator 帐户登录 Windows10。</p><ul><li>1、首先，将鼠标光标放在 “此电脑” 图标上，点击右键，再点击管理。</li><li>2、在窗口左侧的树状列表中展开本地用户和组，点击用户文件夹。</li><li>3、双击帐户列表中的 Administrator 项，将账户已禁用项取消勾选，然后点击确定按钮。</li><li>4、这时，点击开始按钮，再点击你的头像，你可以看到 Administrator 项，只要点击它，我们就可以 以 Administrator 帐户登录 Windows 了。</li><li>5、以 Administrator 账户登录 Windows 后，打开 regedit。</li><li>6、定位到以下位置：<code>\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\</code></li><li>7、在窗口右侧的空白处点击鼠标右键，选择新建 - 新建 DWORD（32 位）值，并将该值命名为：<code>NoDrives</code></li><li>8、以下是一份对照表，这个表我们接下来有用。</li></ul><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">　　A：1</span><br/><span class="line">　　B：2</span><br/><span class="line">　　C：4</span><br/><span class="line">　　D：8</span><br/><span class="line">　　E：16</span><br/><span class="line">　　F：32</span><br/><span class="line">　　G：64</span><br/><span class="line">　　H：128</span><br/><span class="line">　　I：256</span><br/><span class="line">　　J：512</span><br/><span class="line">　　K：1024</span><br/><span class="line">　　L：2048</span><br/><span class="line">　　M：4096</span><br/><span class="line">　　N：8192</span><br/><span class="line">　　O：16384</span><br/><span class="line">　　P：32768</span><br/><span class="line">　　Q：65536</span><br/><span class="line">　　R：131072</span><br/><span class="line">　　S：262144</span><br/><span class="line">　　T：524288</span><br/><span class="line">　　U：1048576</span><br/><span class="line">　　V：2097152</span><br/><span class="line">　　W：4194304</span><br/><span class="line">　　X：8388608</span><br/><span class="line">　　Y：16777216</span><br/><span class="line">　　Z：33554432</span><br/><span class="line">　　所有：67108863</span><br/></pre></td></tr></tbody></table></figure><p>想要隐藏 E 盘，查表可知，该盘对应的值为 <code>16</code>。</p><ul><li>9、双击我们刚刚新建的名为 <code>NoDrives</code> 的 DWOED（32 位）值，将该值基数改为 10 进制，再将该值的数值数据设置为 <code>16</code>。</li><li>10、重启电脑后，打开文件资源管理器（此电脑），可见，E 盘已经消失了。</li><li>11、要进入 E 盘非常简单，我们只需在文件资源管理器的地址栏输入：E:\，然后回车即可。</li></ul><p>如何恢复？</p><p>如果你不想再隐藏 E 盘，那么你可以通过以下方式恢复：</p><p>以 Administrator 帐户登录 Windows。打开 regedit，定位到以下位置：<code>\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policie</code>，找到名为 <code>NoDrives</code> 的 DWORD（32 位）值，双击该值，将其数值数据改为 <code>0</code>，然后重启即可。</p></div><div class="story post-story"><h2 id="重置组策略"><a class="headerlink" href="#重置组策略" title="重置组策略"></a>重置组策略</h2><p>在 Windows 系统中，通过组策略我们可以设置系统的各种软件、计算机和用户策略等。不小心将组策略中的设置修改错了，导致系统中的很多组件都无法使用了，这该怎么办呢？这时候重置组策略编辑器是最好的解决办法</p><h3 id="还原本地安全策略"><a class="headerlink" href="#还原本地安全策略" title="还原本地安全策略"></a>还原本地安全策略</h3><p>用于管理 Windows 安全选项的安全策略与组策略使用了不同的管理控制台 ——secpol.msc（本地安全策略），该安全设置管理单元对组策略进行了扩展，可方便个人用户或域管理员手动配置和定义计算机安全策略。</p><p>如果你对 Windows 的安全管理策略不太了解，又自己手动更改了一些乱七八糟的设置，可以通过如下步骤对本地安全策略进行还原：</p><ul><li>1、使用 Windows + X 快捷键打开「命令提示符（管理员）」；</li><li>2、执行如下命令：<figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">secedit /configure /cfg %windir%\inf\defltbase.inf /db defltbase.sdb /verbose</span><br/></pre></td></tr></tbody></table></figure></li><li>3、命令执行完成之后需要重启计算机才能生效，如果某些组件仍出现奇怪的问题，可以通过下面介绍的步骤来重置组策略对象。</li></ul><h3 id="使用命令行重置组策略对象"><a class="headerlink" href="#使用命令行重置组策略对象" title="使用命令行重置组策略对象"></a>使用命令行重置组策略对象</h3><p>此种方法比较特殊，我们可以直接从安装 Windows 的分区中直接删除组策略配置文件夹，以达到全部重置目的：</p><ul><li>1、使用 Windows + X 快捷键打开「命令提示符（管理员）」；</li><li>2、执行如下命令：<figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">RD /S /Q <span class="string">"%WinDir%\System32\GroupPolicyUsers"</span></span><br/><span class="line">RD /S /Q <span class="string">"%WinDir%\System32\GroupPolicy"</span></span><br/><span class="line">gpupdate /force</span><br/></pre></td></tr></tbody></table></figure></li><li>3、命令执行完成后重启计算机即可。</li></ul></div><div class="story post-story"><h2 id="禁用设置和控制面板"><a class="headerlink" href="#禁用设置和控制面板" title="禁用设置和控制面板"></a>禁用设置和控制面板</h2><p>该方法适用于：Win10 + 专业版 / 企业版 / 教育版</p><ul><li>1、运行 gpedit；</li><li>2、定位到：用户配置 - 管理模板 - 控制面板，在窗口的右侧找到并双击禁止访问 “控制面板” 和 PC 设置；</li><li>3、在弹出的窗口中选择已启用，点击确定按钮；</li><li>4、当你完成这些步骤后，用户将无法打开设置。</li></ul><p>该方法适用于：Win10 + 家庭版</p><p>重要提醒：编辑注册表是有风险的，如果你不小心误操作，这则可能对你电脑的系统造成不可逆转的损害，在继续之前，我们建议你备份注册表或者创建系统还原点。</p><ul><li>1、运行 regedit；</li><li>2、定位到：<code>\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\</code>，在窗口右侧的空白处单击鼠标右键，选择新建 - DWORD（32 位）值，并将此值命名为：<code>NoControlPanel</code>；</li><li>3、双击刚刚新建的名为 <code>NoControlPanel</code> 的 DWORD（32 位）值，将数值数据由 <code>0</code> 改为 <code>1</code> ，点击确定按钮；</li><li>4、完成这些步骤后，用户将无法打开设置。</li></ul><p>如何恢复？</p><ul><li>1、如果你是使用组策略编辑器来禁用设置和控制面板的，要恢复原样，你需要进入组策略编辑器，来到以下目录：用户配置 - 管理模板 - 控制面板，在窗口的右侧重新找到禁止访问 “控制面板” 和 PC 设置，双击它，然后在弹出的窗口中将已启用改回未配置，点击确定按钮。</li><li>2、如果你是使用注册表编辑器来禁用设置和控制面板的，要恢复原样，你需要进入注册表编辑器，来到以下目录：<code>\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\</code>，在窗口的右侧找到名为 <code>NoControlPanel</code> 的 DWORD（32 位）值，双击它，将数值数据由 <code>1</code> 改成 <code>0</code> ，点击确定按钮。</li></ul></div><div class="story post-story"><h2 id="禁用注册表"><a class="headerlink" href="#禁用注册表" title="禁用注册表"></a>禁用注册表</h2><p>没事不要乱动注册表 / 邪恶</p><figure class="highlight bash"><figcaption><span>禁用注册表.reg</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br/><span class="line"></span><br/><span class="line">[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]</span><br/><span class="line"><span class="string">"DisableRegistryTools"</span>=dword:00000001</span><br/></pre></td></tr></tbody></table></figure><figure class="highlight bash"><figcaption><span>解锁注册表.inf</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">[Version]</span><br/><span class="line">Signature=“$CHICAGO$”</span><br/><span class="line">[DefaultInstall]</span><br/><span class="line">DelReg=del</span><br/><span class="line">[del]</span><br/><span class="line">HKCU,Software\Microsoft\Windows\CurrentVersion\Policies\System,Disableregistrytools,1,00,00,00,00</span><br/></pre></td></tr></tbody></table></figure><p>右键选择安装解锁</p><figure class="highlight bash"><figcaption><span>修复注册表.cmd</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line">reg add <span class="string">"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability"</span> /v <span class="string">"BranchName"</span> /d <span class="string">"fbl_release"</span> /t REG_SZ /f</span><br/><span class="line">reg add <span class="string">"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability"</span> /v <span class="string">"ThresholdRiskLevel"</span> /d <span class="string">"low"</span> /t REG_SZ /f</span><br/><span class="line">reg deldte <span class="string">"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability"</span> /v <span class="string">"ThresholdInternal"</span> /f</span><br/><span class="line">reg deldte <span class="string">"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability"</span> /v <span class="string">"ThresholdOptedIn"</span> /f</span><br/></pre></td></tr></tbody></table></figure></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="记一次重装系统 (Win11)" href="https://blog.mhuig.top/p/de4b9576/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">记一次重装系统 (Win11)</span><span class="cap link fs12">https://blog.mhuig.top/p/de4b9576/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>1736543577.6338046</title>
    <link href="https://blog.imc.re/RSSBOX/rss/e0455003.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/e0455003.html</id>
    <published>2022-06-11T20:11:00.000Z</published>
    <updated>2022-06-11T20:11:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p><svg style="width: 50px; margin: 0 auto; display: block;" viewbox="0 0 576 512" xmlns="http://www.w3.org/2000/svg"><defs><style>.fa-secondary&#123;opacity:.4&#125;</style></defs><path class="fa-primary" d="M488 144c-8.875 0-16 7.125-16 16s7.125 16 16 16s16-7.125 16-16S496.9 144 488 144zM408 144c-8.875 0-16 7.125-16 16s7.125 16 16 16s16-7.125 16-16S416.9 144 408 144zM160 278V288l64 32L196.3 236.1C183.5 247.8 171.1 261.2 160 278zM288 288V194.9c-13.8 2.334-30.18 6.607-47.33 14.22L288 288z"></path><path class="fa-secondary" d="M322.6 192C316.4 192 303.9 192.2 288 194.9V288L240.7 209.1C226 215.6 210.9 224.6 196.3 236.1L224 320L160 288V192c0-53-43-96-96-96C46.38 96 32 110.4 32 128s14.38 32 32 32s32 14.38 32 32v256c0 35.25 28.75 64 64 64h176c8.875 0 16-7.125 16-15.1V480c0-17.62-14.38-32-32-32h-32l128-96v144c0 8.875 7.125 16 16 16h32c8.875 0 16-7.125 16-16V289.9c-10.25 2.625-20.88 4.5-32 4.5C386.3 294.4 334.5 250.4 322.6 192zM480 96h-64l-64-64v134.4c0 53 43 95.1 96 95.1s96-42.1 96-95.1V32L480 96zM408 176c-8.875 0-16-7.125-16-16s7.125-16 16-16s16 7.125 16 16S416.9 176 408 176zM488 176c-8.875 0-16-7.125-16-16s7.125-16 16-16s16 7.125 16 16S496.9 176 488 176z"></path></svg></p><p><span class="p logo center large">CoPoKo</span></p><br/><h1 hidden="">CoPoKo</h1><br/><span class="btn solid large center"><a class="button" href="/wiki/CoPoKo/" title="开始阅读"><i class="fa-duotone fa-cat"></i>开始阅读</a></span><br/></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="1736543577.6338046" href="https://blog.mhuig.top/p/wiki-copoko/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">1736543577.6338046</span><span class="cap link fs12">https://blog.mhuig.top/p/wiki-copoko/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>部署第一个智能合约</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6a03238d.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6a03238d.html</id>
    <published>2022-02-28T18:12:23.000Z</published>
    <updated>2022-02-28T18:12:23.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><div class="note warning"><p>注意访问本文的引用链接可能需要魔法</p></div><br/><div class="note guide clear"><p>对区块链最好的描述是将其描述为一个公共数据库，它由网络中的许多计算机更新和共享。</p></div><div class="story post-story"><h2 id="小试身手"><a class="headerlink" href="#小试身手" title="小试身手"></a>小试身手</h2><p>我猜您和我们一样会很兴奋在以太坊区块链上<a href="https://ethereum.org/zh/developers/docs/smart-contracts/deploying/">部署</a><a href="https://ethereum.org/zh/developers/docs/smart-contracts/">智能合约</a>并与之交互。</p><p>别担心，作为我们的第一个智能合约，我们会将其部署在<a href="https://ethereum.org/zh/developers/docs/networks/">本地测试网络</a>上，因此您不需要任何开销就可以随意部署和运行它。</p><h3 id="编写合约"><a class="headerlink" href="#编写合约" title="编写合约"></a>编写合约</h3><p>第一步<a href="https://remix.ethereum.org/">访问 Remix</a> 并创建一个新文件。 在 Remix 界面的左上角添加一个新文件，并输入所需的文件名。</p><p><img><img alt="在Remix界面中添加一个新文件" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651969245917/remix.webp" src="https://unpkg.com/mhgoos@0.0.1651969245917/remix.webp"/></img></p><p>在这个新文件中，我们将粘贴如下代码：</p><figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line"><span class="comment">// SPDX-License-Identifier: MIT</span></span><br/><span class="line">pragma solidity &gt;=<span class="number">0.5</span><span class="number">.17</span>;</span><br/><span class="line"></span><br/><span class="line">contract <span class="title class_">Counter</span> &#123;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Public variable of type unsigned int to keep the number of counts</span></span><br/><span class="line">    uint256 public count = <span class="number">0</span>;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Function that increments our counter</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">increment</span>(<span class="params"></span>) public &#123;</span><br/><span class="line">        count += <span class="number">1</span>;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Not necessary getter to get the count value</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">getCount</span>(<span class="params"></span>) public view returns (uint256) &#123;</span><br/><span class="line">        <span class="keyword">return</span> count;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><p>如果您曾经写过程序，应该可以轻松猜到这个程序是做什么的。 下面按行解释：</p><ul><li>第 3 行：定义了一个名为 <code>Counter</code> 的合约。</li><li>第 6 行：我们的合约存储了一个无符号整型 <code>count</code>，从 0 开始。</li><li>第 9 行：第一个函数将修改合约的状态并且 <code>increment()</code> 变量 <code>count</code>。</li><li>第 14 行，第二个函数是一个 getter 函数，能够从智能合约外部读取 <code>count</code> 变量的值。 请注意，因为我们将 <code>count</code> 变量定义为公共变量，所以这个函数是不必要的，但它可以作为一个例子展示。</li></ul><p>第一个简单的智能合约到此结束。 正如您所知，它看上去像是 Java、C++ 这样的面向对象编程语言中的一个类。 现在可以运行我们的合约了。</p><h3 id="部署合约"><a class="headerlink" href="#部署合约" title="部署合约"></a>部署合约</h3><p>当我们写了第一个智能合约后，我们现在可以将它部署在区块链中并运行它。</p><p><a href="https://ethereum.org/zh/developers/docs/smart-contracts/deploying/">在区块链上部署智能合约</a>实际上只是发送了一个包含已编译智能合约代码的交易，并且没有指定任何收件人。</p><p>我们首先点击左侧的编译图标来<a href="https://ethereum.org/zh/developers/docs/smart-contracts/compiling/">编译合约</a>：</p><p><img><img alt="Remix工具栏中的编译图标" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-compile-button.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-compile-button.png"/></img></p><p>然后点击编译按钮：</p><p><img><img alt="Remix solidity编译器的编译按钮" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-compile.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-compile.png"/></img></p><p>您可以选择 “自动编译” 选项，这样当您在文本编辑器中保存内容时，合约始终会自动编译。</p><p>然后切换到部署和运行交易屏幕：</p><p><img><img alt="Remix工具栏的部署图标" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-deploy.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-deploy.png"/></img></p><p>在 “部署和运行交易” 屏幕上，仔细检查显示的合约名称并点击 “部署”。 在页面顶部可以看到，当前环境为 “Javascript VM”，这意味着当前我们在本地测试区块链上部署智能合约并交互，这样测试可以更快，也不需要任何费用。</p><p><img><img alt="Remix solidity编译器的部署按钮" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-deploy-button.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-deploy-button.png"/></img></p><p>点击 “部署” 按钮后，您可以看到合约在底部显示出来。 点击左侧的箭头展开，可以看到合约的内容。 这里有我们的变量 <code>counter</code>、函数 <code>increment()</code> 和 getter <code>getCounter()</code>。</p><p>如果您点击 <code>count</code> 或 <code>getCount</code> 按钮，它将实际检索合约的 <code>count</code> 变量的内容，并显示出来。 因为我们尚未调用 <code>increment</code> 函数，它应该显示 0。</p><p><img><img alt="Remix solidity编译器的函数按钮" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-function-button.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-function-button.png"/></img></p><p>现在点击按钮来调用 <code>increment</code> 函数。 您可以在窗口底部看到交易产生的日志。 当按下检索数据按钮而非 <code>increment</code> 按钮时，您看到的日志有所不同。 这是因为读取区块链的数据不需要任何交易（写入）或费用。 因为只有修改区块链的状态需要进行交易。</p><p><img><img alt="交易日志" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/transaction-log.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/transaction-log.png"/></img></p><p>在按下 increment 按钮后，将产生一个交易来调用我们的 <code>increment()</code> 函数，如果我们点击 count 或 getCount 按钮，将读取我们的智能合约的最新状态，count 变量大于 0。</p><p><img><img alt="智能合约状态的最新更新" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/updated-state.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/updated-state.png"/></img></p><h3 id="使用事件记录智能合约中的数据"><a class="headerlink" href="#使用事件记录智能合约中的数据" title="使用事件记录智能合约中的数据"></a>使用事件记录智能合约中的数据</h3><p>在 solidity 中，<a href="https://ethereum.org/zh/developers/docs/smart-contracts/anatomy/#events-and-logs">事件</a>是智能合约可触发的调度信号。 去中心化应用或其他任何连接到以太坊 JSON-PRC API 的程序，都可以监听这些事件，并执行相应操作。 可以建立事件的索引，以便稍后可以搜索到事件历史记录。</p><p>在撰写这篇文章之时，以太坊区块链上最常见的事件是由 ERC20 代币转账时触发的 Transfer 事件。</p><figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">event <span class="title class_">Transfer</span>(address indexed <span class="keyword">from</span>, address indexed to, uint256 value);</span><br/></pre></td></tr></tbody></table></figure><p>事件签名在合约代码内声明，并且可以使用 emit 关键字来触发。 例如，transfer 事件记录了谁发起了转账 (<em>from</em>)，转账给谁 (<em>to</em>)，以及转账的代币数转账 (<em>value</em>)。</p><p>我们再次回到 Counter 智能合约，决定在每次值发生变化时进行记录。 由于这个合约不是为了部署，而是作为基础，通过扩展来构建另一个合约：因此它被称为抽象合约。 在我们 counter 示例中，它将类似于如下：</p><figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">pragma solidity <span class="number">0.5</span><span class="number">.17</span>;</span><br/><span class="line"></span><br/><span class="line">contract <span class="title class_">Counter</span> &#123;</span><br/><span class="line"></span><br/><span class="line">    event <span class="title class_">ValueChanged</span>(uint oldValue, uint256 newValue);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Private variable of type unsigned int to keep the number of counts</span></span><br/><span class="line">    uint256 private count = <span class="number">0</span>;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Function that increments our counter</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">increment</span>(<span class="params"></span>) public &#123;</span><br/><span class="line">        count += <span class="number">1</span>;</span><br/><span class="line">        emit <span class="title class_">ValueChanged</span>(count - <span class="number">1</span>, count);</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// Getter to get the count value</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">getCount</span>(<span class="params"></span>) public view returns (uint256) &#123;</span><br/><span class="line">        <span class="keyword">return</span> count;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><p>注意：</p><ul><li><p><strong>第 5 行</strong>：我们声明了事件及其包含的内容、旧值以及新值。</p></li><li><p><strong>第 13 行</strong>：当我们增加 count 变量的值时，我们会触发事件。</p></li></ul><p>如果我们现在部署合约并调用 increment 函数，如果您在名为 logs 的数组内单击新交易，我们将看到 Remix 会自动显示它。</p><p><img><img alt="Remix截屏" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-screenshot.png" src="https://cdn.jsdelivr.net/npm/imbox@0.0.12/eth-1/remix-screenshot.png"/></img></p><p>日志在调试智能合约时非常有用，另一方面，如果您构建一个不同人使用的应用，并且使分析更容易跟踪和了解您的智能合约的使用情况，那么日志也是非常重要的手段。 交易生成的日志会显示常见的区块浏览器中，并且，举例来说，您也可以使用它们来创建链外脚本，用于侦听特定的事件，并且这些事件发生时采取相应操作。</p></div><div class="story post-story"><h2 id="注册钱包"><a class="headerlink" href="#注册钱包" title="注册钱包"></a>注册钱包</h2><h3 id="安装-Chrome-MetaMask-插件"><a class="headerlink" href="#安装-Chrome-MetaMask-插件" title="安装 Chrome MetaMask 插件"></a>安装 Chrome MetaMask 插件</h3><p><a href="https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn">https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn</a></p><p><img><img alt="安装 Chrome MetaMask 插件" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651881937785/image-20220301101701156.webp" src="https://unpkg.com/mhgoos@0.0.1651881937785/image-20220301101701156.webp"/></img></p><p>注册绑定你的账号。</p><h3 id="添加-BSC-Testnet-（测试网络）"><a class="headerlink" href="#添加-BSC-Testnet-（测试网络）" title="添加 BSC Testnet （测试网络）"></a>添加 BSC Testnet （测试网络）</h3><p>添加自定义网络</p><p><img><img alt="添加自定义网络" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651882197195/image-20220301102026905.webp" src="https://unpkg.com/mhgoos@0.0.1651882197195/image-20220301102026905.webp"/></img></p><p><img><img alt="添加自定义网络 BSC Testnet" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651882314775/image-20220301102046537.webp" src="https://unpkg.com/mhgoos@0.0.1651882314775/image-20220301102046537.webp"/></img></p><ul><li><p>网络名称：BSC Testnet</p></li><li><p>RPC URL: <a href="https://data-seed-prebsc-1-s1.binance.org:8545/">https://data-seed-prebsc-1-s1.binance.org:8545/</a></p></li><li><p> 链 ID: 0x61</p></li><li><p>区块浏览器：<a href="https://testnet.bscscan.com/">https://testnet.bscscan.com/</a></p></li><li><p> 货币符号: BNB</p></li></ul><h3 id="每日领取测试-BNB"><a class="headerlink" href="#每日领取测试-BNB" title="每日领取测试 BNB"></a>每日领取测试 BNB</h3><p>进入 <a href="https://testnet.binance.org/faucet-smart">https://testnet.binance.org/faucet-smart</a> , 填入账户 Address 领取测试链的 BNB。</p><p>BNB 用于支付测试网络的燃料费用.</p><p><img><img alt="领取测试 BNB" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651882505618/image-20220301104544409.webp" src="https://unpkg.com/mhgoos@0.0.1651882505618/image-20220301104544409.webp"/></img></p><p>在 metamask 钱包中也可以看到这笔 BNB 到账了。</p><p><img><img alt="BNB到账" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651882638867/image-20220301104632082.webp" src="https://unpkg.com/mhgoos@0.0.1651882638867/image-20220301104632082.webp"/></img></p></div><div class="story post-story"><h2 id="发行-MHGC-MHuiGCoin-代币"><a class="headerlink" href="#发行-MHGC-MHuiGCoin-代币" title="发行 MHGC (MHuiGCoin) 代币"></a>发行 MHGC (MHuiGCoin) 代币</h2><p>进入 <a href="https://remix.ethereum.org/">Remix 环境</a> 中</p><h3 id="FILE-EXPLORERS"><a class="headerlink" href="#FILE-EXPLORERS" title="FILE EXPLORERS"></a>FILE EXPLORERS</h3><p>依次创建三个文件: <code>EIP20.sol</code>、<code>EIP20Factory.sol</code>、<code>EIP20Interface.sol</code>。</p><p><img><img alt="依次创建三个文件" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651882964833/image-20220301105159633.webp" src="https://unpkg.com/mhgoos@0.0.1651882964833/image-20220301105159633.webp"/></img></p><figure class="highlight js"><figcaption><span>EIP20.sol</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br/><span class="line"><span class="comment">Implements EIP20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md</span></span><br/><span class="line"><span class="comment">.*/</span></span><br/><span class="line"></span><br/><span class="line"></span><br/><span class="line">pragma solidity ^<span class="number">0.4</span><span class="number">.21</span>;</span><br/><span class="line"></span><br/><span class="line"><span class="keyword">import</span> <span class="string">"./EIP20Interface.sol"</span>;</span><br/><span class="line"></span><br/><span class="line"></span><br/><span class="line">contract <span class="title class_">EIP20</span> is <span class="title class_">EIP20Interface</span> &#123;</span><br/><span class="line"></span><br/><span class="line">    uint256 constant private <span class="variable constant_">MAX_UINT256</span> = <span class="number">2</span>**<span class="number">256</span> - <span class="number">1</span>;</span><br/><span class="line">    mapping (<span class="function"><span class="params">address</span> =&gt;</span> uint256) public balances;</span><br/><span class="line">    mapping (<span class="function"><span class="params">address</span> =&gt;</span> mapping (<span class="function"><span class="params">address</span> =&gt;</span> uint256)) public allowed;</span><br/><span class="line">    <span class="comment">/*</span></span><br/><span class="line"><span class="comment">    <span class="doctag">NOTE:</span></span></span><br/><span class="line"><span class="comment">    The following variables are OPTIONAL vanities. One does not have to include them.</span></span><br/><span class="line"><span class="comment">    They allow one to customise the token contract &amp; in no way influences the core functionality.</span></span><br/><span class="line"><span class="comment">    Some wallets/interfaces might not even bother to look at this information.</span></span><br/><span class="line"><span class="comment">    */</span></span><br/><span class="line">    string public name;                   <span class="comment">//fancy name: eg Simon Bucks</span></span><br/><span class="line">    uint8 public decimals;                <span class="comment">//How many decimals to show.</span></span><br/><span class="line">    string public symbol;                 <span class="comment">//An identifier: eg SBX</span></span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">EIP20</span>(<span class="params"></span></span><br/><span class="line"><span class="params">        uint256 _initialAmount,</span></span><br/><span class="line"><span class="params">        string _tokenName,</span></span><br/><span class="line"><span class="params">        uint8 _decimalUnits,</span></span><br/><span class="line"><span class="params">        string _tokenSymbol</span></span><br/><span class="line"><span class="params">    </span>) public &#123;</span><br/><span class="line">        balances[msg.<span class="property">sender</span>] = _initialAmount;               <span class="comment">// Give the creator all initial tokens</span></span><br/><span class="line">        totalSupply = _initialAmount;                        <span class="comment">// Update total supply</span></span><br/><span class="line">        name = _tokenName;                                   <span class="comment">// Set the name for display purposes</span></span><br/><span class="line">        decimals = _decimalUnits;                            <span class="comment">// Amount of decimals for display purposes</span></span><br/><span class="line">        symbol = _tokenSymbol;                               <span class="comment">// Set the symbol for display purposes</span></span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">transfer</span>(<span class="params">address _to, uint256 _value</span>) public returns (bool success) &#123;</span><br/><span class="line">        <span class="built_in">require</span>(balances[msg.<span class="property">sender</span>] &gt;= _value);</span><br/><span class="line">        balances[msg.<span class="property">sender</span>] -= _value;</span><br/><span class="line">        balances[_to] += _value;</span><br/><span class="line">        emit <span class="title class_">Transfer</span>(msg.<span class="property">sender</span>, _to, _value); <span class="comment">//solhint-disable-line indent, no-unused-vars</span></span><br/><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">transferFrom</span>(<span class="params">address _from, address _to, uint256 _value</span>) public returns (bool success) &#123;</span><br/><span class="line">        uint256 allowance = allowed[_from][msg.<span class="property">sender</span>];</span><br/><span class="line">        <span class="built_in">require</span>(balances[_from] &gt;= _value &amp;&amp; allowance &gt;= _value);</span><br/><span class="line">        balances[_to] += _value;</span><br/><span class="line">        balances[_from] -= _value;</span><br/><span class="line">        <span class="keyword">if</span> (allowance &lt; <span class="variable constant_">MAX_UINT256</span>) &#123;</span><br/><span class="line">            allowed[_from][msg.<span class="property">sender</span>] -= _value;</span><br/><span class="line">        &#125;</span><br/><span class="line">        emit <span class="title class_">Transfer</span>(_from, _to, _value); <span class="comment">//solhint-disable-line indent, no-unused-vars</span></span><br/><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">balanceOf</span>(<span class="params">address _owner</span>) public view returns (uint256 balance) &#123;</span><br/><span class="line">        <span class="keyword">return</span> balances[_owner];</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">approve</span>(<span class="params">address _spender, uint256 _value</span>) public returns (bool success) &#123;</span><br/><span class="line">        allowed[msg.<span class="property">sender</span>][_spender] = _value;</span><br/><span class="line">        emit <span class="title class_">Approval</span>(msg.<span class="property">sender</span>, _spender, _value); <span class="comment">//solhint-disable-line indent, no-unused-vars</span></span><br/><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">allowance</span>(<span class="params">address _owner, address _spender</span>) public view returns (uint256 remaining) &#123;</span><br/><span class="line">        <span class="keyword">return</span> allowed[_owner][_spender];</span><br/><span class="line">    &#125;</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><figure class="highlight js"><figcaption><span>EIP20Factory.sol</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">"./EIP20.sol"</span>;</span><br/><span class="line"></span><br/><span class="line">pragma solidity ^<span class="number">0.4</span><span class="number">.21</span>;</span><br/><span class="line"></span><br/><span class="line"></span><br/><span class="line">contract <span class="title class_">EIP20Factory</span> &#123;</span><br/><span class="line"></span><br/><span class="line">    <span class="title function_">mapping</span>(<span class="function"><span class="params">address</span> =&gt;</span> address[]) public created;</span><br/><span class="line">    <span class="title function_">mapping</span>(<span class="function"><span class="params">address</span> =&gt;</span> bool) public isEIP20; <span class="comment">//verify without having to do a bytecode check.</span></span><br/><span class="line">    bytes public <span class="title class_">EIP20ByteCode</span>; <span class="comment">// solhint-disable-line var-name-mixedcase</span></span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">EIP20Factory</span>(<span class="params"></span>) public &#123;</span><br/><span class="line">        <span class="comment">//upon creation of the factory, deploy a EIP20 (parameters are meaningless) and store the bytecode provably.</span></span><br/><span class="line">        address verifiedToken = <span class="title function_">createEIP20</span>(<span class="number">10000</span>, <span class="string">"Verify Token"</span>, <span class="number">3</span>, <span class="string">"VTX"</span>);</span><br/><span class="line">        <span class="title class_">EIP20ByteCode</span> = <span class="title function_">codeAt</span>(verifiedToken);</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">//verifies if a contract that has been deployed is a Human Standard Token.</span></span><br/><span class="line">    <span class="comment">//<span class="doctag">NOTE:</span> This is a very expensive function, and should only be used in an eth_call. ~800k gas</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">verifyEIP20</span>(<span class="params">address _tokenContract</span>) public view returns (bool) &#123;</span><br/><span class="line">        bytes memory fetchedTokenByteCode = <span class="title function_">codeAt</span>(_tokenContract);</span><br/><span class="line"></span><br/><span class="line">        <span class="keyword">if</span> (fetchedTokenByteCode.<span class="property">length</span> != <span class="title class_">EIP20ByteCode</span>.<span class="property">length</span>) &#123;</span><br/><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">//clear mismatch</span></span><br/><span class="line">        &#125;</span><br/><span class="line"></span><br/><span class="line">      <span class="comment">//starting iterating through it if lengths match</span></span><br/><span class="line">        <span class="keyword">for</span> (uint i = <span class="number">0</span>; i &lt; fetchedTokenByteCode.<span class="property">length</span>; i++) &#123;</span><br/><span class="line">            <span class="keyword">if</span> (fetchedTokenByteCode[i] != <span class="title class_">EIP20ByteCode</span>[i]) &#123;</span><br/><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br/><span class="line">            &#125;</span><br/><span class="line">        &#125;</span><br/><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">createEIP20</span>(<span class="params">uint256 _initialAmount, string _name, uint8 _decimals, string _symbol</span>)</span><br/><span class="line">        public</span><br/><span class="line">    returns (address) &#123;</span><br/><span class="line"></span><br/><span class="line">        <span class="title class_">EIP20</span> newToken = (<span class="keyword">new</span> <span class="title class_">EIP20</span>(_initialAmount, _name, _decimals, _symbol));</span><br/><span class="line">        created[msg.<span class="property">sender</span>].<span class="title function_">push</span>(<span class="title function_">address</span>(newToken));</span><br/><span class="line">        isEIP20[<span class="title function_">address</span>(newToken)] = <span class="literal">true</span>;</span><br/><span class="line">        <span class="comment">//the factory will own the created tokens. You must transfer them.</span></span><br/><span class="line">        newToken.<span class="title function_">transfer</span>(msg.<span class="property">sender</span>, _initialAmount);</span><br/><span class="line">        <span class="keyword">return</span> <span class="title function_">address</span>(newToken);</span><br/><span class="line">    &#125;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">//for now, keeping this internal. Ideally there should also be a live version of this that</span></span><br/><span class="line">    <span class="comment">// any contract can use, lib-style.</span></span><br/><span class="line">    <span class="comment">//retrieves the bytecode at a specific address.</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">codeAt</span>(<span class="params">address _addr</span>) internal view returns (bytes outputCode) &#123;</span><br/><span class="line">        assembly &#123; <span class="comment">// solhint-disable-line no-inline-assembly</span></span><br/><span class="line">            <span class="comment">// retrieve the size of the code, this needs assembly</span></span><br/><span class="line">            <span class="keyword">let</span> size := <span class="title function_">extcodesize</span>(_addr)</span><br/><span class="line">            <span class="comment">// allocate output byte array - this could also be done without assembly</span></span><br/><span class="line">            <span class="comment">// by using outputCode = new bytes(size)</span></span><br/><span class="line">            outputCode := <span class="title function_">mload</span>(<span class="number">0x40</span>)</span><br/><span class="line">            <span class="comment">// new "memory end" including padding</span></span><br/><span class="line">            <span class="title function_">mstore</span>(<span class="number">0x40</span>, <span class="title function_">add</span>(outputCode, <span class="title function_">and</span>(<span class="title function_">add</span>(<span class="title function_">add</span>(size, <span class="number">0x20</span>), <span class="number">0x1f</span>), <span class="title function_">not</span>(<span class="number">0x1f</span>))))</span><br/><span class="line">            <span class="comment">// store length in memory</span></span><br/><span class="line">            <span class="title function_">mstore</span>(outputCode, size)</span><br/><span class="line">            <span class="comment">// actually retrieve the code, this needs assembly</span></span><br/><span class="line">            <span class="title function_">extcodecopy</span>(_addr, <span class="title function_">add</span>(outputCode, <span class="number">0x20</span>), <span class="number">0</span>, size)</span><br/><span class="line">        &#125;</span><br/><span class="line">    &#125;</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><figure class="highlight js"><figcaption><span>EIP20Interface.sol</span></figcaption><table><tbody><tr><td class="code"><pre><span class="line"><span class="comment">// Abstract contract for the full ERC 20 Token standard</span></span><br/><span class="line"><span class="comment">// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md</span></span><br/><span class="line">pragma solidity ^<span class="number">0.4</span><span class="number">.21</span>;</span><br/><span class="line"></span><br/><span class="line"></span><br/><span class="line">contract <span class="title class_">EIP20Interface</span> &#123;</span><br/><span class="line">    <span class="comment">/* This is a slight change to the ERC20 base standard.</span></span><br/><span class="line"><span class="comment">    function totalSupply() constant returns (uint256 supply);</span></span><br/><span class="line"><span class="comment">    is replaced with:</span></span><br/><span class="line"><span class="comment">    uint256 public totalSupply;</span></span><br/><span class="line"><span class="comment">    This automatically creates a getter function for the totalSupply.</span></span><br/><span class="line"><span class="comment">    This is moved to the base contract since public getter functions are not</span></span><br/><span class="line"><span class="comment">    currently recognised as an implementation of the matching abstract</span></span><br/><span class="line"><span class="comment">    function by the compiler.</span></span><br/><span class="line"><span class="comment">    */</span></span><br/><span class="line">    <span class="comment">/// total amount of tokens</span></span><br/><span class="line">    uint256 public totalSupply;</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">/// @param _owner The address from which the balance will be retrieved</span></span><br/><span class="line">    <span class="comment">/// @return The balance</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">balanceOf</span>(<span class="params">address _owner</span>) public view returns (uint256 balance);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">/// @notice send `_value` token to `_to` from `msg.sender`</span></span><br/><span class="line">    <span class="comment">/// @param _to The address of the recipient</span></span><br/><span class="line">    <span class="comment">/// @param _value The amount of token to be transferred</span></span><br/><span class="line">    <span class="comment">/// @return Whether the transfer was successful or not</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">transfer</span>(<span class="params">address _to, uint256 _value</span>) public returns (bool success);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`</span></span><br/><span class="line">    <span class="comment">/// @param _from The address of the sender</span></span><br/><span class="line">    <span class="comment">/// @param _to The address of the recipient</span></span><br/><span class="line">    <span class="comment">/// @param _value The amount of token to be transferred</span></span><br/><span class="line">    <span class="comment">/// @return Whether the transfer was successful or not</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">transferFrom</span>(<span class="params">address _from, address _to, uint256 _value</span>) public returns (bool success);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">/// @notice `msg.sender` approves `_spender` to spend `_value` tokens</span></span><br/><span class="line">    <span class="comment">/// @param _spender The address of the account able to transfer the tokens</span></span><br/><span class="line">    <span class="comment">/// @param _value The amount of tokens to be approved for transfer</span></span><br/><span class="line">    <span class="comment">/// @return Whether the approval was successful or not</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">approve</span>(<span class="params">address _spender, uint256 _value</span>) public returns (bool success);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">/// @param _owner The address of the account owning tokens</span></span><br/><span class="line">    <span class="comment">/// @param _spender The address of the account able to transfer the tokens</span></span><br/><span class="line">    <span class="comment">/// @return Amount of remaining tokens allowed to spent</span></span><br/><span class="line">    <span class="keyword">function</span> <span class="title function_">allowance</span>(<span class="params">address _owner, address _spender</span>) public view returns (uint256 remaining);</span><br/><span class="line"></span><br/><span class="line">    <span class="comment">// solhint-disable-next-line no-simple-event-func-name</span></span><br/><span class="line">    event <span class="title class_">Transfer</span>(address indexed _from, address indexed _to, uint256 _value);</span><br/><span class="line">    event <span class="title class_">Approval</span>(address indexed _owner, address indexed _spender, uint256 _value);</span><br/><span class="line">&#125;</span><br/></pre></td></tr></tbody></table></figure><h3 id="SOLIDITY-COMPILER"><a class="headerlink" href="#SOLIDITY-COMPILER" title="SOLIDITY COMPILER"></a>SOLIDITY COMPILER</h3><p>我们选择 0.4.21 版本的编译环境.</p><p><img><img alt="选择 0.4.21 版本的编译环境" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883147459/image-20220301105400927.webp" src="https://unpkg.com/mhgoos@0.0.1651883147459/image-20220301105400927.webp"/></img></p><p>点击编译.</p><p><img><img alt="点击编译" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883264213/image-20220301105546782.webp" src="https://unpkg.com/mhgoos@0.0.1651883264213/image-20220301105546782.webp"/></img></p><p>在这里你可以将源码发布到 <code>IPFS</code>.</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">Metadata of <span class="string">"eip20"</span> was published successfully.</span><br/><span class="line">token/EIP20.sol : </span><br/><span class="line">dweb:/ipfs/QmZemboWkhVyhYMRyCJmjwhw4caenvXS5Mw7Uc5tdE77jP</span><br/><span class="line">token/EIP20Interface.sol : </span><br/><span class="line">dweb:/ipfs/QmWQEUAdy5QnnCTGsEtRfedZrVG2xZ77YfKiPE5MVvQiSS</span><br/><span class="line">metadata.json : </span><br/><span class="line">dweb:/ipfs/QmWFrJHPJLEWJGAoXpq8MD1pGJsvdcfxhPiW5SDXiwEvm8</span><br/></pre></td></tr></tbody></table></figure><h3 id="DEPLOY-RUN-TRANSACTIONS"><a class="headerlink" href="#DEPLOY-RUN-TRANSACTIONS" title="DEPLOY &amp; RUN TRANSACTIONS"></a>DEPLOY &amp; RUN TRANSACTIONS</h3><p>运行环境选择  <code>Injected Web3</code></p><p><img><img alt="运行环境选择 Injected Web3" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883454625/image-20220301105958769.webp" src="https://unpkg.com/mhgoos@0.0.1651883454625/image-20220301105958769.webp"/></img></p><p>因为我们用的是 metamask 钱包；Account 账户填写 metamask 钱包账户；此时浏览器插件会弹出，我们选择连接账户。点击下一步，点击连接.</p><p><img><img alt="连接账户" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883551603/image-20220301110333702.webp" src="https://unpkg.com/mhgoos@0.0.1651883551603/image-20220301110333702.webp"/></img></p><p>在 <code>DEPLOY</code> 中输入部署信息，合约构造函数的输入参数.</p><figure class="highlight bash"><table><tbody><tr><td class="code"><pre><span class="line">_INITIALAMOUNT: <span class="string">"21000000000000000000000000"</span></span><br/><span class="line">_TOKENNAME: <span class="string">"MHuiGCoin"</span></span><br/><span class="line">_DECIMALUNITS: <span class="string">"18"</span></span><br/><span class="line">_TOKENSYMBOL: <span class="string">"MHGC"</span></span><br/></pre></td></tr></tbody></table></figure><p>发币数量 <code>21000000</code>, 和比特币一样，向中本聪致敬。</p><p>货币名称 <code>MHuiGCoin</code>，最小货币单位 <code>18</code>（decimaUnits），货币简称 <code>MHGC</code>。</p><p>点击 <code>transact</code>.</p><p><img><img alt="transact" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883673988/image-20220301110809192.webp" src="https://unpkg.com/mhgoos@0.0.1651883673988/image-20220301110809192.webp"/></img></p><p>点击确认支付燃料费用.</p><p><img><img alt="支付燃料费用" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883742435/image-20220301111043197.webp" src="https://unpkg.com/mhgoos@0.0.1651883742435/image-20220301111043197.webp"/></img></p><p>从 <code>Deployed Contracts</code> 复制部署的合约地址: <code>0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6</code>.</p><p><img><img alt="复制部署的合约地址" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883874383/image-20220301111634995.webp" src="https://unpkg.com/mhgoos@0.0.1651883874383/image-20220301111634995.webp"/></img></p><h3 id="导入代币合约"><a class="headerlink" href="#导入代币合约" title="导入代币合约"></a>导入代币合约</h3><p>进入部署合约的 MetaMask 账户，点击导入代币.</p><p><img><img alt="点击导入代币" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651883969151/image-20220301111959163.webp" src="https://unpkg.com/mhgoos@0.0.1651883969151/image-20220301111959163.webp"/></img></p><p>输入代币合约信息</p><ul><li><p>代币合约地址：0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6</p></li><li><p>代币符号：MHGC</p></li><li><p>小数精度：18</p></li></ul><p><img><img alt="输入代币合约信息" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884067187/image-20220301112142701.webp" src="https://unpkg.com/mhgoos@0.0.1651884067187/image-20220301112142701.webp"/></img></p><p>可以看到我的账户中有 <code>21000000 MHGC (MHuiGCoin)</code></p><p><img><img alt="21000000 MHGC" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884181025/image-20220301112337360.webp" src="https://unpkg.com/mhgoos@0.0.1651884181025/image-20220301112337360.webp"/></img></p><h3 id="代币转账测试"><a class="headerlink" href="#代币转账测试" title="代币转账测试"></a>代币转账测试</h3><p>我们创建一个新的账户，并导入上面的代币合约.</p><p><img><img alt="创建一个新的账户" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884273044/image-20220301112555043.webp" src="https://unpkg.com/mhgoos@0.0.1651884273044/image-20220301112555043.webp"/></img></p><p>我们向目标账户发送 <code>1 MHGC</code> 测试</p><p><img><img alt="发送 1 MHGC 测试" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884384477/image-20220301112735479.webp" src="https://unpkg.com/mhgoos@0.0.1651884384477/image-20220301112735479.webp"/></img></p><p>需要支付测试网络的燃料费用.</p><p><img><img alt="支付测试网络的燃料费用" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884464447/image-20220301112757549.webp" src="https://unpkg.com/mhgoos@0.0.1651884464447/image-20220301112757549.webp"/></img></p><p>转账发送成功.</p><p><img><img alt="转账发送成功" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884609138/image-20220301112923178.webp" src="https://unpkg.com/mhgoos@0.0.1651884609138/image-20220301112923178.webp"/></img></p><p><img><img alt="转账发送成功" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884657883/image-20220301113008335.webp" src="https://unpkg.com/mhgoos@0.0.1651884657883/image-20220301113008335.webp"/></img></p><h3 id="测试网络资源管理器"><a class="headerlink" href="#测试网络资源管理器" title="测试网络资源管理器"></a>测试网络资源管理器</h3><p>在资源管理器中查看 <strong>资产</strong>: </p><p><a href="https://testnet.bscscan.com/token/0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6">https://testnet.bscscan.com/token/0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6</a></p><p>可以看到资源信息和公开的转账记录. </p><p>如你所见这些在区块链中已经发生的历史信息是无法更改的.</p></div><div class="story post-story"><h2 id="安全风险提示"><a class="headerlink" href="#安全风险提示" title="安全风险提示"></a>安全风险提示</h2><p>任何人都可以创建代币，包括创建现有代币的假版本。了解更多关于 <a href="https://metamask.zendesk.com/hc/en-us/articles/4403988839451">欺诈和安全风险.</a></p><p>2016 年 6 月，The DAOEther 的漏洞造成损失 5000 万美元，而开发者试图达成共识的解决方案。DAO 的程序在黑客删除资金之前有一段时间的延迟。以太坊软件的一个硬分叉在时限到期之前完成了攻击者的资金回收工作。</p><p>2021 年 9 月 24 日，中国人民银行发布进一步防范和处置虚拟货币交易炒作风险的通知。通知指出，虚拟货币不具有与法定货币等同的法律地位。比特币、以太币、泰达币等虚拟货币具有非货币当局发行、使用加密技术及分布式账户或类似技术、以数字化形式存在等主要特点，不具有法偿性，不应且不能作为货币在市场上流通使用 。</p></div><div class="story post-story"><h2 id="最后"><a class="headerlink" href="#最后" title="最后"></a>最后</h2><h3 id="MHGC-获取方式"><a class="headerlink" href="#MHGC-获取方式" title="MHGC 获取方式"></a>MHGC 获取方式</h3><h4 id="测试网络"><a class="headerlink" href="#测试网络" title="测试网络"></a>测试网络</h4><ul><li><p>网络名称：BSC Testnet</p></li><li><p>RPC URL: <a href="https://data-seed-prebsc-1-s1.binance.org:8545/">https://data-seed-prebsc-1-s1.binance.org:8545/</a></p></li><li><p> 链 ID: 0x61</p></li><li><p>区块浏览器：<a href="https://testnet.bscscan.com/">https://testnet.bscscan.com/</a></p></li><li><p> 货币符号: BNB</p></li></ul><h4 id="代币合约"><a class="headerlink" href="#代币合约" title="代币合约"></a>代币合约</h4><ul><li><p>代币合约地址：0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6</p></li><li><p>代币符号：MHGC</p></li><li><p>小数精度：18</p></li></ul><h3 id="尾巴"><a class="headerlink" href="#尾巴" title="尾巴"></a>尾巴</h3><p>联系我，发我地址，在 BSC Testnet 下可领取 <code>100 MHGC</code>.</p><p>共发行 <code>21000000 MHGC</code>, 集齐 <code>22000000 MHGC</code> 可领取精美礼品一份. </p><p>Just For Fun.</p><h3 id="参考资料"><a class="headerlink" href="#参考资料" title="参考资料"></a>参考资料</h3><ul><li><a href="https://ethereum.org/en/">Welcome to Ethereum</a></li></ul><p>This message is used to verify that this feed (feedId:83048545374666752) belongs to me (userId:82913974185265152). Join me in enjoying the next generation information browser <a href="https://follow.is/">https://follow.is</a>.</p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="部署第一个智能合约" href="https://blog.mhuig.top/p/6a03238d/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">部署第一个智能合约</span><span class="cap link fs12">https://blog.mhuig.top/p/6a03238d/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>一组粗略的类比</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6dc844b7.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6dc844b7.html</id>
    <published>2021-10-01T19:00:00.000Z</published>
    <updated>2021-10-01T19:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>这是一个关于生物学与深度学习的粗略类比的笔记，这些类比中的大多数都是非常推测性和探索性的，但我发现它们很有趣并且值得思考.</p><table><thead><tr><th align="center">生物学</th><th align="center">深度学习</th></tr></thead><tbody><tr><td align="center">外界环境</td><td align="center">输入数据</td></tr><tr><td align="center">认知过程</td><td align="center">特征提取</td></tr><tr><td align="center">基因</td><td align="center">神经网络权重结构 (特征)</td></tr><tr><td align="center"> 基因突变</td><td align="center">神经网络权重结构改变</td></tr><tr><td align="center">性状</td><td align="center">神经网络功能</td></tr><tr><td align="center">细胞</td><td align="center">神经元</td></tr><tr><td align="center">组织 (细胞分化)</td><td align="center"> 神经网络在后面的层</td></tr><tr><td align="center">器官</td><td align="center">神经网络专门处理特定任务的组件</td></tr><tr><td align="center">个体</td><td align="center">模型</td></tr><tr><td align="center">繁殖</td><td align="center">迭代</td></tr><tr><td align="center">反馈调节</td><td align="center">优化器 (eg: 梯度下降) 更新网络的机制</td></tr><tr><td align="center">自然选择</td><td align="center">损失函数定向衡量性能</td></tr><tr><td align="center">进化</td><td align="center">学习</td></tr><tr><td align="center">进化 = 基因突变 + 自然选择 (定向)</td><td align="center"> 学习 = 神经网络权重结构改变 + 损失函数定向衡量性能</td></tr><tr><td align="center">基因决定性状</td><td align="center">神经网络权重结构可以决定神经网络功能</td></tr><tr><td align="center">个体繁殖</td><td align="center">模型迭代</td></tr></tbody></table></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="一组粗略的类比" href="https://blog.mhuig.top/p/6dc844b7/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">一组粗略的类比</span><span class="cap link fs12">https://blog.mhuig.top/p/6dc844b7/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>唯物辩证法</title>
    <link href="https://blog.imc.re/RSSBOX/rss/6ace289f.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/6ace289f.html</id>
    <published>2021-09-14T23:13:40.000Z</published>
    <updated>2021-09-14T23:13:40.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>唯物辩证法是关于自然界、人类社会以及人类思维领域发展最一般规律的科学，它在坚持唯物论观点的基础上，研究世界的运行状况、形态和发展规律，进一步回答客观世界究竟 “怎么样” 的问题。</p><span id="more"></span><div class="story post-story"><h2 id="唯物辩证法的总特征"><a class="headerlink" href="#唯物辩证法的总特征" title="唯物辩证法的总特征"></a>唯物辩证法的总特征</h2><p>唯物辩证法的基本观点是：世界是普遍联系的有机整体，同时又是变化发展的。联系和发展的观点是唯物辩证法的总特征。</p><h3 id="事物的普遍联系"><a class="headerlink" href="#事物的普遍联系" title="事物的普遍联系"></a>事物的普遍联系</h3><p>联系指事物内部各要素之间和事物之间相互影响、相互制约、相互作用的关系。</p><p>联系的特性及其具体内容如下表所示：</p><table><thead><tr><th>特性</th><th>具体内容</th></tr></thead><tbody><tr><td>客观性</td><td>事物的联系是事物本身所固有的，不是主观臆想的</td></tr><tr><td>普遍性</td><td>任何事物内部的不同部分和要素之间都是相互联系的；任何事物都不能孤立存在，都同其他事物处于一定的联系之中，整个世界是相互联系的统一整体。</td></tr><tr><td>多样性</td><td>世界上的事物是多样的，事物之间的联系也是多样的</td></tr><tr><td>条件性</td><td>条件是对事物存在和发展发生作用的诸要素的总和。条件对事物发展和人的活动具有支持或制约作用；条件是可以改变的；改变和创造条件不是任意的，必须尊重事物发展的客观规律。</td></tr></tbody></table><h3 id="事物的变化发展"><a class="headerlink" href="#事物的变化发展" title="事物的变化发展"></a>事物的变化发展</h3><p>事物的相互联系包含事物的相互作用，而相互作用必然导致事物的运动、变化和发展。</p><p>发展是前进的、上升的运动，发展的实质是新事物的产生和旧事物的灭亡。</p><h3 id="联系与发展的基本环节"><a class="headerlink" href="#联系与发展的基本环节" title="联系与发展的基本环节"></a>联系与发展的基本环节</h3><p>内容与形式、本质与现象、原因与结果、必然与偶然、现实与可能构成了联系和发展的基本环节。</p></div><div class="story post-story"><h2 id="唯物辩证法的三大规律"><a class="headerlink" href="#唯物辩证法的三大规律" title="唯物辩证法的三大规律"></a>唯物辩证法的三大规律</h2><h3 id="对立统一规律"><a class="headerlink" href="#对立统一规律" title="对立统一规律"></a>对立统一规律</h3><h4 id="唯物辩证法的实质和核心"><a class="headerlink" href="#唯物辩证法的实质和核心" title="唯物辩证法的实质和核心"></a>唯物辩证法的实质和核心</h4><p>对立统一规律是唯物辩证法的实质和核心，其原因如下：</p><ul><li>对立统一规律揭示了事物普遍联系的根本内容和变化发展的内在动力，从根本上回答了事物为什么会发展的问题。</li><li>对立统一规律是贯穿量变质变规律、否定之否定规律以及唯物辩证法基本范畴的中心线索，也是理解这些规律和范畴的 “钥匙”。</li><li>对立统一规律为人们提供了认识世界和改变造世界的根本方法 —— 矛盾分析析方法。</li></ul><p>对立统一规律又称矛盾规律，矛盾是辩证法的核心概念，是否承认矛盾，是否承认矛盾是事物发展的动力和源泉，是辩证法和形而上学的根本分歧。</p><p>矛盾的两种基本属性是同一性和斗争性，矛盾的同一性和斗争性相互联结，相辅相成。</p><h4 id="内因和外因"><a class="headerlink" href="#内因和外因" title="内因和外因"></a>内因和外因</h4><p>内因指事物发展变化的内部原因，是事物自身的矛盾。</p><p>外因指事物之间的相互联系、相互影响，是事物变化的条件。</p><p>二者的关系：内因是事物变化的依据，外因是事物变化的条件，外因必须通过内因起作用，内因与外因共同推动事物的发展。</p><h4 id="矛盾的普遍性和特殊性"><a class="headerlink" href="#矛盾的普遍性和特殊性" title="矛盾的普遍性和特殊性"></a>矛盾的普遍性和特殊性</h4><p>矛盾的普遍性指矛盾存在于一切事物中，存在于一切事物发展过程的始终，即” 矛盾无处不在，矛盾无时不有”。</p><p>矛盾的特殊性指各个具体事物的矛盾、每一个矛盾的各个方面在发展的不同阶段上各有其特点。矛盾的特殊性决定了事物的不同性质。</p><p>二者关系：矛盾的普遍性和特殊性是辩证统一的。矛盾的普遍性即矛盾的共性，矛盾的特殊性，即矛盾的个性。矛盾的共性是无条件的、绝对的。矛盾的个性是有条件的、相对的。任何现实存在的事物的矛盾都是共性和个性的有机统一，共性寓于个性之中，没有离开个性的共性，也没有离开共性的个性。</p><h4 id="主次矛盾和矛盾的主次方面"><a class="headerlink" href="#主次矛盾和矛盾的主次方面" title="主次矛盾和矛盾的主次方面"></a>主次矛盾和矛盾的主次方面</h4><p>主要矛盾：处于支配地位，对事物的发展起决定作用</p><p>次要矛盾：处于从属地位，对事物的发展起次要作用</p><p>主要矛盾和次要矛盾的联系：</p><ul><li>相互依赖，相互影响</li><li>两者在一定条件下相互转化</li></ul><p>矛盾的主要方面：处于支配地位，起主导作用的方面</p><p>矛盾的次要方面：处于被支配地位，不起主导作用的方面</p><p>矛盾的主要方面和矛盾的次要方面的联系：</p><ul><li>相互依赖，相互影响</li><li>两者在一定条件下相互转化</li></ul><p>方法论：</p><p>要坚持 “两点论” 和 “重点论” 的统一，“两点论” 和 “重点论” 的统一要求我们看问题既要全面地看，又要看主流、大势、发展趋势。</p><h3 id="量变质变规律"><a class="headerlink" href="#量变质变规律" title="量变质变规律"></a>量变质变规律</h3><h4 id="量、质、度"><a class="headerlink" href="#量、质、度" title="量、质、度"></a>量、质、度</h4><p>量是事物的规模、程度、速度等可以用数量关系表示的规定性。</p><p>质是一事物区别于其他事物的内在规定性。</p><p>度是保持物质的稳定性的数量界限，即事物的限度、幅度和范围，这启示我们在认识和处理问题时，要掌握适度度原则。</p><h4 id="量变和质变"><a class="headerlink" href="#量变和质变" title="量变和质变"></a>量变和质变</h4><p>量变和质变的区别如下表所示：</p><table><thead><tr><th>区别</th><th>量变</th><th>质变</th></tr></thead><tbody><tr><td>性质</td><td>事物数量的增减和组成要素次序的变动</td><td>事物根本性质的变化，是事物由一种质态向另一种质态的飞跃</td></tr><tr><td>特点</td><td>渐进的、不显著的变化</td><td>根本的、显著的变化</td></tr><tr><td>呈现状态</td><td>统一、相持、平衡和静止</td><td>统一物的分解、平衡和静止的破坏</td></tr><tr><td>结果</td><td>事物还是其自身，没有变成另一事物</td><td>事物不再是其自身，而变成了另一事物</td></tr></tbody></table><p>量变和质变的联系，辩证关系：</p><ul><li>量变是质变的必要准备；</li><li>质变是量变的必然结果；</li><li>量变和质变是相互渗透的；</li><li>量变和质变是相互依存，相互贯通的，量变引起质变，在新质的基础上，事物又开始新的量变，如此交替循环，构成了事物的发展过程。</li></ul><h3 id="否定之否定规律"><a class="headerlink" href="#否定之否定规律" title="否定之否定规律"></a>否定之否定规律</h3><h4 id="肯定因素和否定因素"><a class="headerlink" href="#肯定因素和否定因素" title="肯定因素和否定因素"></a>肯定因素和否定因素</h4><p>肯定因素指维持现存事物存在的因素。</p><p>否定因素指促使事物灭亡的因素。</p><h4 id="辩证否定观"><a class="headerlink" href="#辩证否定观" title="辩证否定观"></a>辩证否定观</h4><p>辩证否定观的具体内容如下：</p><ul><li>否定是事物的自我否定，是事物内部矛盾运动的结果。</li><li>否定是事物发展的环节，是旧事物向新事物的转变，是旧质到新质的飞跃。<br/>- 否定是新旧事物联系的环节，新事物孕育产生于旧事物，新旧事物是通过否定环节联系起来的。</li><li>辩证否定的实质是 “扬弃”，即新事物对旧事物既批判又继承，既克服其消极因素又保留其积极因素。</li></ul><h4 id="否定之否定"><a class="headerlink" href="#否定之否定" title="否定之否定"></a>否定之否定</h4><p>事物的辩证发展过程经过 “肯定 —— 否定 —— 否定之否定” 三个阶段。</p><p>否定之否定规律揭示了事物发展的前进性与曲折性的统一。这表明，事物的发展不是直线式前进，而是螺旋式上升的。按照否定之否定规律办事，要求我们树立辩证的否定观，正确看待事物发展的过程，既要看到道路的曲折，又要看到前途的光明。</p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="唯物辩证法" href="https://blog.mhuig.top/p/6ace289f/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">唯物辩证法</span><span class="cap link fs12">https://blog.mhuig.top/p/6ace289f/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>辩证唯物论</title>
    <link href="https://blog.imc.re/RSSBOX/rss/171a81d0.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/171a81d0.html</id>
    <published>2021-09-13T22:50:30.000Z</published>
    <updated>2021-09-13T22:50:30.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>辩证唯物论是关于世界的的物质性学说、关于物质和意识的辩证关系学说，它采用辩证法的观点研究世界的本质，所要说明的是世界的本质 “是什么” 的问题。</p><span id="more"></span><p>辩证唯物论的基本观点是：世界的本原是物质，主张物质决定意识，意识是对物质的反映；同时，意识对物质有能动的反作用，承认世界是物质的，物质具有客观实在性。</p><div class="story post-story"><h2 id="物质"><a class="headerlink" href="#物质" title="物质"></a>物质</h2><h3 id="物质的定义"><a class="headerlink" href="#物质的定义" title="物质的定义"></a>物质的定义</h3><p>物质是不依赖于人类的意识而存在，并能为人类的意识所反应的客观存在。</p><p>物质的唯一特性是客观实在性。</p><h3 id="物质和运动"><a class="headerlink" href="#物质和运动" title="物质和运动"></a>物质和运动</h3><p>物质和运动是不可分割的，二者关系及其具体内容如下表所示：</p><table><thead><tr><th>关系</th><th>理解</th><th>误区</th></tr></thead><tbody><tr><td>物质是运动的物质，运动是物质固有的根本属性</td><td>任何具体的物质形态只有在运动中才能保持自己的存在，世界上不存在脱离运动的物质</td><td>离开运动谈物质会导致形而上学</td></tr><tr><td>运动是物质的运动，物质是运动的承担者</td><td>任何运动都有自己的承担者或者载体，离开物质载体的运动是不存在的</td><td>离开物质谈运动导致唯心主义</td></tr></tbody></table><h3 id="运动和静止"><a class="headerlink" href="#运动和静止" title="运动和静止"></a>运动和静止</h3><p>物质的运动是绝对的，而物质在运动过程中又有某种相对的静止。</p><p>运动和静止的区别如下表所示：</p><table><thead><tr><th></th><th>运动</th><th>静止</th></tr></thead><tbody><tr><td>含义</td><td>宇宙间一切事物、现象的变化和过程</td><td>两种情形：一是指空间的相对位置暂时不变，二是指事物的根本性质暂时不变</td></tr><tr><td>性质</td><td>无条件的、永恒的和绝对的</td><td>有条件的、暂时的和相对的</td></tr></tbody></table><p>运动和静止的联系：</p><ul><li>静止是一种不显著的运动，是运动的特殊状态；动中有静，静中有动，世界上一切事物的存在和发展，都是绝对运动和相对静止的统一。</li><li>只承认静止而否认运动是形而上学的不变论，只承认绝对运动而否认相对静止则导致相对主义和诡辩论。</li></ul><h3 id="时间和空间"><a class="headerlink" href="#时间和空间" title="时间和空间"></a>时间和空间</h3><p>时间和空间是物质运动的存在形式。</p><p>时间是指物质运动的持续性、顺序性，特点是一维性，即时间的流逝一去不复返。</p><p>空间是指物质运动空间的广延性、伸张性，特点是三维性，即空间具有长、宽、高三方面的规定性。</p><p>物质运动总是在一定的时间和空间中进行的，没有离开物质运动的 “纯粹” 时间和空间，也没有离开时间和空间的物质运动。</p></div><div class="story post-story"><h2 id="意识"><a class="headerlink" href="#意识" title="意识"></a>意识</h2><h3 id="意识的含义"><a class="headerlink" href="#意识的含义" title="意识的含义"></a>意识的含义</h3><p>意识是物质世界长期发展的产物，是人脑的机能和属性，是客观世界的主观映像。</p><p>意识是社会的人所特有的精神活动及其成果的总和。从内容上看，人的意识是知、情、意三者的统一。</p><h3 id="意识的本质"><a class="headerlink" href="#意识的本质" title="意识的本质"></a>意识的本质</h3><p>意识是人脑这种特殊物质器官的机能。</p><p>意识是对客观存在的反映，其在内容上是客观的，在形式上是主观的。</p></div><div class="story post-story"><h2 id="物质和意识的辩证关系"><a class="headerlink" href="#物质和意识的辩证关系" title="物质和意识的辩证关系"></a>物质和意识的辩证关系</h2><p>物质和意识的辩证关系体现在：物质决定意识，意识对物质具有反作用（意识的能动作用）。</p><p>意识的能动作用主要表现在：</p><ul><li>意识活动具有目的性和计划性；</li><li>意识活动具有创造性；</li><li>意识具有指导实践改造客观世界的作用（最重要的表现）；</li><li>意识具有调控人的行为和生理活动的作用。</li></ul><p>正确认识和把握物质和意识的辩证关系，还需要处理好主观能动性和客观规律性的关系：</p><ul><li>尊重客观规律是正确发挥主观能动性的前提；</li><li>只有充分发挥主观能动性，才能正确认识和利用客观规律。</li></ul></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="辩证唯物论" href="https://blog.mhuig.top/p/171a81d0/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">辩证唯物论</span><span class="cap link fs12">https://blog.mhuig.top/p/171a81d0/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>我们从哪里来？</title>
    <link href="https://blog.imc.re/RSSBOX/rss/dad4292a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/dad4292a.html</id>
    <published>2021-06-05T19:51:37.000Z</published>
    <updated>2021-06-05T19:51:37.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>这里探讨的是一个非常简单的问题，我们是怎么来到这里的？</p><div class="story post-story"><h2 id="前言"><a class="headerlink" href="#前言" title="前言"></a>前言</h2><p>世界上的所有人都是由这些元素和化合物组成的，他们的平常甚至让我们高智能的人类感到尴尬。</p><p>事实上，人体的 99% 都是由空气、水、碳以及白垩组成，另外还能找到少量的比较特别的元素，如铁、锌、磷和硫。实际上，组成人体的所有物质加起来最多花几十块钱就能买到。</p><p><img><img alt="平常的元素和化合物" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651884978846/1622900624000.webp" src="https://unpkg.com/mhgoos@0.0.1651884978846/1622900624000.webp"/></img></p><p>但是，也不知道怎么的，这些数以万计的普普通通的原子能够携手起来，组成一个能够思考呼吸的活生生的人。</p><p>这些简单的积木是如何组合在一起。这无疑是最令人着迷的问题。</p><!-- [数以万计的普普通通的原子能够携手起来](https://api.mhuig.top/ipfs/QmTWMqfLXFPdBq5nANB6m3ukgouHyTESPDrJY4Lvz6xcak) --><p><img><img alt="数以万计的普普通通的原子能够携手起来" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651889782185/a4r44-c8547.webp" src="https://unpkg.com/mhgoos@0.0.1651889782185/a4r44-c8547.webp"/></img></p><p>你可能会认为仅仅通过科学是不能够回答这个神奇的问题的。但是你敢肯定吗？现在，我们有理由相信，科学已经在这个大胆解释这个问题方面超越了宗教和哲学的解释力。</p><p>下面我们将通过一系列相互盘根错节的伟大发现来解释自然界的不为人知的一面。</p><p>在这之中蕴含了世上最基本的法则，即不确定性的产生。</p><p>这是关于看似廖无生气、毫无目的和动机的物质世界，是如何自发的产生这些极其精细的绚丽的自然。</p><p>这是关于世间最基本的法则是如何使这个世界展现出混沌和不可预测性，如何通过简单的物质创造出人。</p><p>这是关于一个奇异的发现，即有序和混沌之间，奇特而难以置信的联系。</p></div><div class="story post-story"><h2 id="图灵的方程式"><a class="headerlink" href="#图灵的方程式" title="图灵的方程式"></a>图灵的方程式</h2><p>自然界充满了生长、发展和混乱，其中到处都是离奇的形状和杂乱的斑点。自然界的图案从来都不会固定不变，从来都不会按原样重复。</p><!-- [自然界充满了生长、发展和混乱](https://api.mhuig.top/ipfs/QmWLyedy2zq44kxfyzjLGskw6uiGq754rVEEAr1xxnhMqv) --><p><img><img alt="自然界充满了生长、发展和混乱" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651889463476/af2ce-a1zgl.webp" src="https://unpkg.com/mhgoos@0.0.1651889463476/af2ce-a1zgl.webp"/></img></p><p>这一切看上去混乱的现象都受到数学方程式的影响。事实上，他们完全被数学规则所支配。这种数学规则与我们长久以来的直觉相悖。因此不难相信第一个能够担负此揭示自然界的数学根基重任的人会拥有超乎寻常的智慧。</p><p>他即是一个伟大的科学家，同时也是一个大悲剧。</p><p><img><img alt="阿兰·图灵" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651888582327/1622900727000.webp" src="https://unpkg.com/mhgoos@0.0.1651888582327/1622900727000.webp"/></img></p><p>他 1912 年生于伦敦，他的名字就是阿兰・图灵。</p><p>阿兰・图灵是一个不凡之人，他是有史以来最伟大的数学家之一。他提出了许多具有基础性的理论和见解。他的思想为现代计算机的出现提供了理论基础。</p><p>在二战期间，他在布莱切利园工作，也就是今天的米尔顿凯恩斯外。当时政府正在这里进行一个叫做 X 站的秘密项目。他的建立是为了破解德军的情报密码。</p><p><img><img alt="破解情报密码" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651890262954/1622900823000.webp" src="https://unpkg.com/mhgoos@0.0.1651890262954/1622900823000.webp"/></img></p><p>X 站项目组的密码破解人员做出了卓越有成效的工作，其中图灵的贡献至关重要。他亲自参与了破解德国海军密码的工作，因为他的工作数以万计的盟军得以幸存，同时这也导致战略形势的有利扭转。</p><p>但是图灵的天赋不仅仅表现在破解密码上，这仅仅是他那超乎常人的洞察力的一部分。对于图灵来说，自然界的密码才是终极密码。在他的一生中，他热切的寻找着破解这个密码的方法。</p><p>图灵是一个很有独创精神的人，他意识到这样一种可能性，简单的数学方程式可以描述复杂的生物世界的一些现象。他的这种想法以前从来没有人尝试过，自然界中所有的迷中最吸引图灵的，就是如何能够使用数学方程式来描述人类的智能。</p><p>图灵迷上这个想法是有原因的，这就是年轻的克里斯托弗・马尔孔的死。图灵是同性恋，克里斯托弗・马尔孔的死，在那时以及他的一生产生了重要的影响。克里斯托弗・马尔孔突然的死亡了导致阿兰图灵在情感方面产生了极大的触动。但是你能想象，他想把这个事实用科学来解释，他想解释的问题是，我们的心智怎么了，什么是心智。</p><p>图灵相信生物界的复杂的系统是可以用数学方程式来描述的，并且人类的智能也是如此。</p><p>他的这种信念导致了现代计算机的产生。</p><p>之后一个更加激进的想法出现在图灵的脑中，这个想法就是通过简单的数学描述来解释胚胎中发生的复杂的过程。</p><p><img><img alt="形态发生" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651890431721/1622900852000.webp" src="https://unpkg.com/mhgoos@0.0.1651890431721/1622900852000.webp"/></img></p><p>这个过程被叫做形态发生。它非常令人费解，起初胚胎中的所有细胞都是相同的，细胞们开始组合到一起，并且细胞之间渐渐产生了差异，这是如何发生的呢？物质不会自己思考，也没有一个中央系统在里面进行调度，一开始都是一样的细胞，为什么有的能够变成皮肤，而有的却变成了眼睛呢？</p><p>形态发生是一类现象中的一个例子，这类现象叫做自组织现象。</p><p>在图灵之前没有人懂得自组织现象的机制。</p><p><img><img alt="图灵的论文" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651890676486/1622900879000.webp" src="https://unpkg.com/mhgoos@0.0.1651890676486/1622900879000.webp"/></img></p><p>直到 1952 年 图灵发表了他的这一篇论文，阐述了用数学方程式来解释形态发生现象。论文中的大胆的猜测是令人震惊的，其中图灵使用了一个在天文学和原子物理学中很常见的一种数学方程式，来描述生命过程。</p><p><img><img alt="方程式" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651890793922/1622900911000.webp" src="https://unpkg.com/mhgoos@0.0.1651890793922/1622900911000.webp"/></img></p><p>之前从来没有人做过这种尝试，然而图灵的方程式却第一次的做到了，描述了一个生物系统的自我组织的过程，这解释了即使简单的、毫无自然界事物特性的东西，也可以演变出栩栩如生的东西。</p><p><img><img alt="花纹" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651890914867/1622900936000.webp" src="https://unpkg.com/mhgoos@0.0.1651890914867/1622900936000.webp"/></img></p><p>图灵的成果中令人大吃一惊的地方是，我们可以通过设定非常简单，甚至简单到可以仅仅通过简单的方程式就能描述的初始状态，然后让它进行演变。然后突然间，复杂和混乱就会出现，产生的复杂图案就像是自然界的结果。</p><p>从许多方面来看这些都是难以置信的。</p><p>其实图灵的方程式描述的都是我们很熟知的东西，但是从来没有人将这些数学方程式应用到生物学领域。</p><p><img><img alt="沙丘" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891052829/1622900955000.webp" src="https://unpkg.com/mhgoos@0.0.1651891052829/1622900955000.webp"/></img></p><p>试想一阵风吹过沙丘，进而产生了一系列图形。小颗粒自我组织成波纹浪花和沙丘，即使那些小颗粒是彼此相同的。并且没有人告诉他们到底要怎么去组成属于他们的那一部分。</p><p><img><img alt="沙丘" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891152209/1622900990000.webp" src="https://unpkg.com/mhgoos@0.0.1651891152209/1622900990000.webp"/></img></p><p>图灵认为，以一种非常形似的方式，在胚胎中渗过的化学物质可能会引导细胞进行自我组织，进而产生各种不同的形状。这是图灵给出的非常粗略的解释，他阐述了一堆毫无生气的化学物质，如何演化为各种不同的形状。</p><p><img><img alt="方程式能够自发的产生生物图案" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891266117/1622901027000.webp" src="https://unpkg.com/mhgoos@0.0.1651891266117/1622901027000.webp"/></img></p><p>在他的论文中做了一些改进，来使他的方程式能够自发的产生生物图案，那种与动物表皮相似的图案。</p><p><img><img alt="图灵到处向别人展示自己生成的图形，你看这难道不像母牛身上的图案吗" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891369870/1622901057000.webp" src="https://unpkg.com/mhgoos@0.0.1651891369870/1622901057000.webp"/></img></p><p>图灵到处向别人展示自己生成的图形，你看这难道不像母牛身上的图案吗，其他人的反应是，这个人的脑子有问题吧。但是图灵相信自己在做一件有意义的事情，他们的确像母牛身上的花纹，这就解释了母牛拥有这种斑点花纹的现象。</p><p>这样一个数学从未触及的领域，生物界的图案，生成动物斑纹，突然间，这个领域向我们敞开了门。</p><p><img><img alt="斑马" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891440349/1622901084000.webp" src="https://unpkg.com/mhgoos@0.0.1651891440349/1622901084000.webp"/></img></p><p>我们发现数学方程式在这个领域会有用武之地，即使图灵提出的方程式，并不是这一新理论的全部，但仍然是一次重要的创举，提出了这种新方法的可能性。</p><p>我们现在知道形态发生，要比图灵所描述的数学方程式复杂多了。事实上，关于 DNA 分子确切的运转机制，仍然是现代科学上争论的话题。</p><p>但是图灵提出的数学支配万物的观点确是革命性的，阿兰・图灵的论文是整个形态发生理论的奠基石，他为我们提供了一种解释，连达尔文都没能提出的，解释自然界生物花纹的产生机制。</p><p>达尔文仅仅告诉我们，生物的花纹是来源于基因的，并且这种花纹的继承是决定于环境的，但是达尔文并没有揭示，这种生物花纹到底是如何生长的，而这是真正的迷。</p><p>图灵的贡献在于提供了了解这种化学机制的途径。图灵提出了一种伟大而勇敢的见解。</p><p>不幸的是我们仅仅能够推测这颗伟大的大脑，是如何想出这些的，在他发表他的开创性论文之后不久，一个可怕的并且完全可以避免的悲剧摧毁了他的生命。</p><p>在他在布莱切利园破解密码工作之后，你一定可以想到图灵会得到很多赞誉，以感谢他为国家做出的贡献。这再明显不过了。战后发生在他身上的事情是一个悲剧，这是英国科学史上令人感到羞耻的事情。</p><p>同年，图灵发表了关于形态发生的论文，他与阿诺德默里这个男人发生了短暂的情感，但是这段情感发展的很令人不愉快，默里对图灵进行了一次入室盗窃，但图灵将这件事情报告给警察的时候，警察连同图灵一起逮捕了。法庭上，原告声称，图灵以他的学历来诱导默里走上了歧途。图灵被判有严重的猥亵罪，法官给了图灵可怕的选择，他要么进监狱，要么接受雌性荷尔蒙注射，进而治疗他的同性恋倾向，他选择了后者。这导致了他连续不断的消沉。</p><p>1954 年 6 月 8 日，图灵的尸体被他的清洁工发现。他是一天前死于咬了一口自己注入了氰化物的苹果，结束了自己的生命。</p><p><img><img alt="阿兰图灵" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651891520960/1622901121000.webp" src="https://unpkg.com/mhgoos@0.0.1651891520960/1622901121000.webp"/></img></p><p>阿兰图灵死的时候 41 岁，这对于科学来说是一种无法估量的损失。图灵不曾想到他的思想会启发后人，将一种全新的数学方法应用到生物学领域。科学家发现他发现的这种方程式，确实能够解释好多生物组织的形态。</p><!-- [科学家发现他发现的这种方程式，确实能够解释好多生物组织的形态。](https://api.mhuig.top/ipfs/Qme4Py3jvXgKZn7f1SbBrQRm2hVp3YmBA3TGbZS1rUz5Rq) --><p><img><img alt="科学家发现他发现的这种方程式，确实能够解释好多生物组织的形态" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651894599643/a8cbv-pgvmv.gif" src="https://unpkg.com/mhgoos@0.0.1651894599643/a8cbv-pgvmv.gif"/></img></p><p>回头看看，我们知道图灵真正捕捉到了复杂与混乱源于简单规则，这样的法则。他意外的迈出了，通往新科学的第一步。</p></div><div class="story post-story"><h2 id="贝洛索夫的试液"><a class="headerlink" href="#贝洛索夫的试液" title="贝洛索夫的试液"></a>贝洛索夫的试液</h2><p>这个过程的第二步更是始料未及，可悲的是伟大的第二步也是一个悲剧。</p><p>在 20 世纪 50 年代初，在图灵发表他的对后人影响巨大的论文之际，一名杰出的俄国化学家 斯・贝洛索夫，开始了他自己的探索，关于自然界中的化学。</p><p><img><img alt="高墙铁网之后的苏维埃卫生部" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651892538829/1622901153000.webp" src="https://unpkg.com/mhgoos@0.0.1651892538829/1622901153000.webp"/></img></p><p>正在高墙铁网之后的苏维埃卫生部，他正在研究我们的身体是如何从糖中提取能量的。像图灵一样贝洛索夫也是在一个个人项目中工作，他刚刚完成了一段从事科学工作的经历。</p><p><img><img alt="贝洛索夫" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651892611869/1622901174000.webp" src="https://unpkg.com/mhgoos@0.0.1651892611869/1622901174000.webp"/></img></p><p>贝洛索夫构想好了一种新的化合物配方，来模仿人体内葡萄糖的吸收，这种混合物就摆在实验室的座位前面，在被摇晃的时候清澈而透明。</p><p><img><img alt="清澈而透明" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651892724851/1622901205000.webp" src="https://unpkg.com/mhgoos@0.0.1651892724851/1622901205000.webp"/></img></p><p>在他添加最后一种试剂的时候，整个混合物的颜色发生了变化。</p><p><img><img alt="混合物的颜色发生了变化" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651892781722/1622901226000.webp" src="https://unpkg.com/mhgoos@0.0.1651892781722/1622901226000.webp"/></img></p><p>当然，这还不算什么特别的，就像我们将墨汁倒入水中水也会改变颜色。</p><p>但是接下来发生的事情令人感到惊奇，混合物又变得清澈无色了。</p><!--[混合物又变得清澈无色了](https://api.mhuig.top/ipfs/QmSdESLNMnMoH43ngL5wcKWeGvYEGMXshMDvCS7H79aP6D)。 --><p><img><img alt="混合物又变得清澈无色了" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651894155349/avk6u-14rsn.webp" src="https://unpkg.com/mhgoos@0.0.1651894155349/avk6u-14rsn.webp"/></img></p><p>贝洛索夫感到很吃惊，化学物质混合以后会发生反应，但这个过程不能自发的发生逆反应，在不受外界干预的情况下发生可逆变化。</p><p>你可以很容易的将一个无色的液体变成有色的，但这个过程的逆过程却不太可能。这太奇怪了，贝洛索夫的试液并没有简单的发生逆变化，试液被摇晃后，就不断的在无色和有色之间变化，就好像这个试液在受一种神秘的内部机制驱动一样。</p><p>他非常谨慎小心地又重复多次这个实验，他的混合物能够不断的在无色和有色之间变化，他发现的东西好像魔术一样。一个好像是违反自然法则的物理现象。</p><!-- [混合物能够不断的在无色和有色之间变化](https://api.mhuig.top/ipfs/QmdKEYwW8gMUZjDfDkmx17H3LG19oxzUY7RKjHSWoLyrmv) --><p><img><img alt="混合物不断的在无色和有色之间变化" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651895091865/ar3ou-yxt38.webp" src="https://unpkg.com/mhgoos@0.0.1651895091865/ar3ou-yxt38.webp"/></img></p><p>贝洛索夫觉得自己的发现意义重大，将自己的发现记录下来，并努力让更多的人了解他的发现，但是当他将他的发现递交到一个顶尖的苏联科学杂志的时候，他收到了一个完全出乎意料的诅咒式的回复，杂志的编辑告诉贝洛索夫，他的发现是不可能在实验室重现的，因为这与基本的物理法则相违背，对这个现象的唯一的解释就是，贝洛索夫在实验的时候出了错，他的发现是不会被出版的。</p><p>这个拒绝深深的打击了贝洛索夫，他感到非常的羞辱，结果放弃了自己的实验，而后他又放弃了自己从事的事业。</p><p>具有悲剧色彩的讽刺是，由于贝洛索夫所处的闭塞环境，贝洛索夫从来没有机会看到图灵的工作成果。如果他看到了图灵的发现，就能为自己的发现提供有力的证据，事实上，贝洛索夫的不稳定试液，不仅没有违背物理法则，而且是实在就是真实的，能够体现图灵的预言的例子，尽管这两者的发现初看起来并没有什么联系。</p><p>其他科学家发现，如果将贝洛索夫的试液的一种变种，不加搅拌的放入培养皿中，而不是摇晃他们的话，他们就会发生自我组织，事实上 ，他们产生的条纹会比图灵预测的花纹要复杂。</p><p>他们会产生令人惊诧的复杂的条纹，毫无预兆。</p><!-- [令人惊诧的复杂的条纹](https://api.mhuig.top/ipfs/QmUnCky4SebGTkmRmfFuCm7ExbRv139gAjny4KXvgpMkZb) --><p><img><img alt="令人惊诧的复杂的条纹" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651901523363/txg4p-n8rrb.gif" src="https://unpkg.com/mhgoos@0.0.1651901523363/txg4p-n8rrb.gif"/></img></p><p>贝洛索夫实验的惊奇之处在于，它能生成一种系统，这种系统产生了图灵方程式所预测的图案，在一个看上去无色的溶液中，产生了这种奇异的原型图案，这明显不是什么抽象科学，贝洛索夫图案的运动模式  ，与我们心脏在跳动的时候周围细胞的运动模式完全相同。动物的皮毛和心脏的跳动，自组织现象在自然界中随处可见。</p></div><div class="story post-story"><h2 id="牛顿经典物理学"><a class="headerlink" href="#牛顿经典物理学" title="牛顿经典物理学"></a>牛顿经典物理学</h2><p>为什么在科学界在图灵和贝洛索夫的年代 ，却对这种想法不感兴趣甚至持有敌意呢？</p><p>原因就是人类的臭毛病，主流科学家不喜欢这种观点，这与主流科学家的科学直觉相违背，也与现有的科学成就相违背，若想改变这种观念，我们需要一种彻底的，改变传统的发现。</p><p><img><img alt="科学家们把宇宙看作一个巨大而复杂的机械装置，有点像一个大号的太阳系仪" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651901961810/1622901247000.webp" src="https://unpkg.com/mhgoos@0.0.1651901961810/1622901247000.webp"/></img></p><p>实际上，在 20 世纪初期，科学家们把宇宙看作一个巨大而复杂的机械装置，有点像一个大号的太阳系仪，整个宇宙就好像是一个巨大的错综复杂的机器 ，严格的遵守着数学规则。如果你知道这个机器的运转机制和初始状态，那么随着你转动这个手柄，它将严格地按照预期的行为运转。</p><!-- [如果你知道这个机器的运转机制和初始状态，那么随着你转动这个手柄，它将严格地按照预期的行为运转。](https://api.mhuig.top/ipfs/Qmb3R75LN6KBmAAsKWBAjtLPH9cMXFyKyC9HbL53Fnnyaj) --><p><img><img alt="如果你知道这个机器的运转机制和初始状态，那么随着你转动这个手柄，它将严格地按照预期的行为运转。" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651912139468/Qmb3R75LN6KBmAAsKWBAjtLPH9cMXFyKyC9HbL53Fnnyaj.webp" src="https://unpkg.com/mhgoos@0.0.1651912139468/Qmb3R75LN6KBmAAsKWBAjtLPH9cMXFyKyC9HbL53Fnnyaj.webp"/></img></p><p>在牛顿生活的时代里，当人们在探索驱使宇宙运转的法则时，他们把宇宙看作这种按照确定规则运转的机器。宇宙就好比是一个被设定好的机器，遵循确定的法则按部就班的按照这个法则运转。</p><p>宇宙中复杂的现象是有复杂的内部规则驱使的，但是一旦一开始让它运转它只会做一件事。人们从这里看到的现象，都可以使用严格的数学公式来描述。</p><p>这实际上是很简单的事情，一旦找到能够描述系统运行的数学方程式，那么你就能够预测系统的走向。</p><p>这是一个伟大的想法。</p><p>它开始于牛顿的万有引力。万有引力成功的解释了行星围绕太阳运转的现象。科学家们后来又不断的发现了新的方程，牛顿物理似乎已成为了预言宇宙的终极方法。</p><p>它给我们暗示了这样一种可能，从原则上讲，未来是可以预测的。</p><p>我们采用的测量手段越精确，我们就能越精确的预测未来的情形。</p><p>但是牛顿物理产生了一个可怕的后果，如果有一个系统我们能够用数学方程式精确描述，就像这个太阳仪一样，那么一旦它表现出了一些我们不能预测的行为之后，科学家就只能认为，是有某种外界力量影响了这个系统，比如说是沙土跑进去了，或者是小零件磨损了，或者有人对它进行了认为的改动。</p><p>一般情况下，我们会这样假设，如果我们遇到了非预期的现象，那么这种现象应该是来自系统外部的干扰，而不是来自系统内部的。不可预测的现象，不是来自系统的本身，而是来自与外部对它的影响。</p><p><img><img alt="复杂图案可以从系统中自我生成" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651912644187/QmW5L4jof6bBLQpdi9NVkhkvAwGftfL4idCUw2NBQT66EC.webp" src="https://unpkg.com/mhgoos@0.0.1651912644187/QmW5L4jof6bBLQpdi9NVkhkvAwGftfL4idCUw2NBQT66EC.webp"/></img></p><p>从这种观点的角度来看，自我组织这种现象是很荒谬的，而图灵和贝洛索夫所表达的，复杂图案可以从系统中自我生成，而不需要外界力量是非常受当时的主流科学所忌讳的。</p><!-- [复杂图案可以从系统中自我生成](https://api.mhuig.top/ipfs/QmW5L4jof6bBLQpdi9NVkhkvAwGftfL4idCUw2NBQT66EC) --><p><img><img alt="新时代的奇景" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651903667581/1622901291000.webp" src="https://unpkg.com/mhgoos@0.0.1651903667581/1622901291000.webp"/></img></p><p>要想使人接受自我组织理论，那么，就必须推翻牛顿物理学，但这看上去很不可能，无论如何这种新思想在 60 年代末期，成为了新时代的奇景。</p></div><div class="story post-story"><h2 id="蝴蝶效应"><a class="headerlink" href="#蝴蝶效应" title="蝴蝶效应"></a>蝴蝶效应</h2><p>然而同时，伴随着登月计划，一小群信奉牛顿力学的科学家，意外的发现了一些事情不对劲，完全不对劲。</p><p>在 20 世纪后半叶，科学界的噩梦出现了，这个噩梦，动摇了牛顿的思想，并将我们推向了一片思想的混乱。</p><p>具有讽刺意味的是，迫使科学界接受自我组织理论的事情，是一种我们叫做混沌的现象。</p><p>混沌这个词被广泛使用，但是在科学领域中，它有它专指的意义。它指的是在一个能被数学方程式精确描述的系统中，可以自发生成不可预测的现象，并且不需要任何外界的干预。</p><p>通过使用非常简单的法则或方程式，并且里面不包含任何的随机性，系统中的所有元素都是确定的，并且我们完全掌握系统的法则，即使是这样的系统也会产生完全不可预测的现象。</p><p>混沌的发现并不讨主流科学的喜欢，有一个人迫使科学界接受混沌，他就是美国的气象学家爱德华・洛伦兹。</p><p><img><img alt="爱德华·洛伦兹" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651903780613/1622901315000.webp" src="https://unpkg.com/mhgoos@0.0.1651903780613/1622901315000.webp"/></img></p><p>在 20 世纪 60 年代早期，他试图寻找能够预测天气变化的数学模型。就像许多他的同事一样，他相信天气系统与我们太阳系仪是一样具有确定性的，一个可以被数学描述和预测的物理系统。</p><p><img><img alt="寻找能够预测天气变化的数学模型" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651903844803/1622901337000.webp" src="https://unpkg.com/mhgoos@0.0.1651903844803/1622901337000.webp"/></img></p><p>但是他错了，当洛伦兹写下一个用于描述气流的及其简单的数学方程式时，这些方程式并没有达到他预想的目的，他们没有做出任何有价值的预测，这就好像说某一天中的一阵清风，将会决定一个月后的某天是冰雪连天，还是清空万里。</p><p>对于一个像太阳系仪这样精准的系统来说，怎么会产生不可预测性呢？</p><p>这源于他的内部构造，由于齿轮的链接方式。</p><p><img><img alt="齿轮的链接方式" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651903911179/1622901366000.webp" src="https://unpkg.com/mhgoos@0.0.1651903911179/1622901366000.webp"/></img></p><p>事实上，在某种情况下，即使在初始的时候有一点点误差，哪怕这个误差小到难以测量，这个误差会随着机械的运转而不断被放大，随着系统的运转，系统的状态会一点一点的偏离你所期望的状态。</p><p>洛伦兹在一次演讲中表达了这一颠覆性的想法，演讲的题目是 —— 一只蝴蝶在巴西扇动翅膀会使美国的德克萨斯刮一场龙卷风吗？</p><p><img><img alt="一只蝴蝶在巴西扇动翅膀会使美国的德克萨斯刮一场龙卷风吗？" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651903970361/1622901384000.webp" src="https://unpkg.com/mhgoos@0.0.1651903970361/1622901384000.webp"/></img></p><p>这是一次有力而吸引人的演讲，数月之内，我们的语言中就添加了一个新的词汇 —— 蝴蝶效应。</p><p>蝴蝶效应就是混沌系统的标志，它开启了之后的一切。</p><p><img><img alt="罗伯特·梅" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904039312/1622901407000.webp" src="https://unpkg.com/mhgoos@0.0.1651904039312/1622901407000.webp"/></img></p><p>在 70 年代早期 一个叫罗伯特・梅的年轻澳大利亚人，正在研究一个数学方程式，用它来模拟生物种群随时间的变化。</p><p><img><img alt="模拟生物种群随时间的变化" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904157346/1622901433000.webp" src="https://unpkg.com/mhgoos@0.0.1651904157346/1622901433000.webp"/></img></p><p>但是这个过程中同样牵扯到蝴蝶效应，哪怕生物的繁殖率发生了极小的变动，都会导致种群数量结果发生巨大的变化，这个数值可能会毫无征兆的上下起伏。</p><p>传统的使用数学方程式，来描述系统行为的方法似乎走到了死胡同，某种意义上，这是信仰牛顿学说的人的美梦之终结。</p><p>随着我们的计算能力的提高，我们就有能力处理更复杂的方程组，但刚才我们所看到的否认了这种观念。</p><p>你可以从一个及其简单的方程式开始，这个方程式简单而不存在任何的随机性，但是如果它产生的行为能够表现出一种混沌性，那么你就不能再回溯到系统的初始状态了。</p><p>数百年来所建立的科学观点在几年内就被瓦解了，可以精确描述宇宙的运行的这一想法变成了幻影。</p><p>看上去具有逻辑确定的事情，却变得更像是一种信仰。更糟的是，这种现像到处都是。因为混沌到处都是。</p><p>似乎不可预测性是固有的，存在于我们生活的宇宙中。</p><p>全球气候可能会在几年的时间内，发生剧烈的变化；股市可能会毫无征兆的崩盘；我们可能会在一夜之间从地球上灭绝。</p><p>如果这种事情发生的话 没有人能够阻止，不幸的是，我不得不说以上这些都是真的。但是盲目的恐惧混沌现象是毫无意义的。</p><p>因为混沌是一条基本的物理法则，我们必须承认它是生活中的一部分。</p><p>混沌理论的出现一直影响到之后 20 到 30 年人们的思想，它改变了人们对于科学工作的看法，它深刻的改变了科学家看问题的方式，以至于科学家们现在已经离不开混沌理论了。</p><p>混沌理论想要说明的是，简单的数学方程式能够繁衍出复杂的行为，这种复杂性超出你我的想象，所以简单而机械的系统能够表现出复杂和丰富的行为。</p><p>混沌理论的发现，是科学史上的一次重大的转折点，它摧毁了牛顿信仰者的梦想，科学家们现在越来越看得惯图灵和贝洛索夫在自发生成花纹上所做的工作。</p></div><div class="story post-story"><h2 id="自反馈系统"><a class="headerlink" href="#自反馈系统" title="自反馈系统"></a>自反馈系统</h2><p>更重要的是，由于他们的工作，一个伟大的真相浮出水面，那是一种内在而隐蔽的关联，一个贯穿宇宙的关联，关联着自然的神秘力量和自我组织现象，以及蝴蝶效应产生的混沌结果。</p><p>图灵、贝洛索夫、梅、洛伦兹这些人都分别发现了一种重大思想的不同侧面。他们发现自然界具有固有的不可预测性，这种不可预测性的内部驱动力，也可以使系统表现出特定的结构和花纹，有序与混沌，似乎要比我们想象的要联系的更加紧密，但这种联系是如何实现的呢？贝洛索夫的花纹与天气变化之间有什么联系呢？</p><p>首先，虽然两个系统都有复杂的工作机制，但他们都是基于及其简单的是数学法则，其次，这些数学法则都具有一种独特的特性，都具有自我链接的特性或者说是自反馈。</p><p>为了向你展示这一点，展示简单的自反馈系统的力量，将使用一种看上去简单甚至无聊的实验。</p><!-- [看上去简单甚至无聊的实验](https://api.mhuig.top/ipfs/QmZqSugWDjd8VZ8SZE5j4HvybVZYXff9xUE39ojvppp6y1)。 --><p><img><img alt="看上去简单甚至无聊的实验" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651912964326/QmZqSugWDjd8VZ8SZE5j4HvybVZYXff9xUE39ojvppp6y1.webp" src="https://unpkg.com/mhgoos@0.0.1651912964326/QmZqSugWDjd8VZ8SZE5j4HvybVZYXff9xUE39ojvppp6y1.webp"/></img></p><p>身后的屏幕连接到一台摄像机，这台摄像机同时也在拍摄着我和屏幕，这样不断的循环就能产生无数个人的影像，都投影到屏幕上，这是一个典型的自反馈系统。图片中不断的嵌套着其他的图片。</p><p><img><img alt="奇怪的事情" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651913329114/QmWV24AgpeYQ1Xswa1tXnTXghZip3YoUbokjZu3rq3dD2W.webp" src="https://unpkg.com/mhgoos@0.0.1651913329114/QmWV24AgpeYQ1Xswa1tXnTXghZip3YoUbokjZu3rq3dD2W.webp"/></img></p><p>这乍看上去肯定有规则，但当我们放大镜头，奇怪的事情发生了，我首先发现的是实物图像和屏幕上显示的图像不像了，火柴的微小运动被迅速放大，当影像在摄像机和屏幕之间反复映射的时候，即使我能用精确的数学对外的每一步动作进行描述，但我却不能预测火焰微小的变化，会导致最终的图像如何变化，这就是一种实实在在的蝴蝶效应。</p><!-- [奇怪的事情](https://api.mhuig.top/ipfs/QmWV24AgpeYQ1Xswa1tXnTXghZip3YoUbokjZu3rq3dD2W) --><p><img><img alt="这些奇异而美丽的图案" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651912903184/chaos-11.webp" src="https://unpkg.com/mhgoos@0.0.1651912903184/chaos-11.webp"/></img></p><p>下面的现象变得更离奇了，通过像系统中添加一点点的扰动，这些奇异而美丽的图案就出现了，这种简单的依赖反馈的系统，呈现出了混沌与有序，同样的数学方程式同时产生了混沌和有序的图案。</p><!-- [这些奇异而美丽的图案](https://api.mhuig.top/dir/img/chaos/chaos-11.gif) --><p>这将改变你对世界的看法，在传统观念中，自然界都是有序的，混乱存在与系统之外，即有序与混乱是相互独立的这种想法是错的，其实混乱和有序，就像同一架钢琴上弹出的高音和低音，这个发现有史以来第一次如此接近自然界的数学本质。</p><p>我们能从图灵的工作，以及化学和生物中得到的，最重要的启示是，所有复杂的图形都是来自，宇宙间简单的演变过程，像扩散， 像化学反应率，这些简单的过程最终导致了图案的产生，所以到处能看到图案，他们不断的产生。</p></div><div class="story post-story"><h2 id="曼德勃罗集合"><a class="headerlink" href="#曼德勃罗集合" title="曼德勃罗集合"></a>曼德勃罗集合</h2><p>从 70 年代开始越来越多的科学家，开始接受混沌理论，以及对自然界能够自发产生复杂花纹的认可，但是有一位科学家比别人走的更远，对这个令人惊奇颇感迷惑的问题带了个新思路，他是一个具有传奇色彩的不喜欢按套路出牌的人，他叫伯努瓦・曼德勃罗。</p><p><img><img alt="伯努瓦·曼德勃罗" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904381727/1622901464000.webp" src="https://unpkg.com/mhgoos@0.0.1651904381727/1622901464000.webp"/></img></p><p>伯努瓦・曼德勃罗 并不是一个寻常的孩子，他跳了两个年级。并且由于他是战时欧洲的犹太人，所以他受到的正规教育极其有限，他基本上是靠自学以及亲属对他的教育，他从来没有正式的学习过字母，甚至没有学过 5 以上的乘法。</p><p>但是和图灵一样，曼德勃罗具有一种洞悉事物本质的本领，他能从混乱中看到我们所看不到的规律，他能够发现形式和结构，然而我们却仅仅能看到一片混乱，他能够感知一种新奇的数学，用来支配整个自然界的运转。</p><p>曼德勃罗的一生都致力于找到一种能够揭示自然界复杂性的一种数学支持。</p><p>曼德勃罗当时为 IBM 工作，而不是学校的学术圈内，他试图解决一大堆的问题，关于自然界以及金融界的不确定性，在各个方面的表现。</p><p>我觉得他知道自己，所做的所有工作都是一个大问题的不同侧面。</p><p>他是一个具有原创精神的人，他觉得求解这个大问题是他真正想做的事情。</p><p>在曼德勃罗看来，几百年来传统的数学研究都仅限于，规则的图形是一种很不可取的行为，就像直线和圆，传统的数学是没有办法描述不规则的形状的，而真实世界确是有不规则形状组成的，就像这个鹅卵石，它是一个球体还是一个立方体呢，还是它们中间的某种形状？他到底是一种什么形状？</p><p><img><img alt="鹅卵石" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904439211/1622901484000.webp" src="https://unpkg.com/mhgoos@0.0.1651904439211/1622901484000.webp"/></img></p><p>曼德勃罗想，是否有一种法则，能够描述自然界的不规则性，那些蓬松的云朵、树和河流的分支，以及蜿蜒的海岸线之间有什么共同的数学基础。</p><p><img><img alt="蜿蜒的海岸线" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904647765/tdciw-vtf8h.webp" src="https://unpkg.com/mhgoos@0.0.1651904647765/tdciw-vtf8h.webp"/></img></p><p>是的，有的。</p><p><img><img alt="树" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904729020/1622901537000.webp" src="https://unpkg.com/mhgoos@0.0.1651904729020/1622901537000.webp"/></img></p><p>自然界中所有的形状的共同特点，就是自相似性。这指的是事物的局部，不断的在更微小的尺度上重复自己，不断的精细到每一个细微之处，树枝就是一个绝好的例子，他们不断的分叉，重复这这个简单的过程，在更微小的尺度上不断重复这这个过程。</p><p><img><img alt="山" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904865998/1622901575000.webp" src="https://unpkg.com/mhgoos@0.0.1651904865998/1622901575000.webp"/></img></p><p>我们的肺的结构同样遵循这个原则构建，我们体内血管的分布同样遵循这样的规则，河流分成更小的溪流也是这样，自然界可以依照这种方法不断重复各种形状。</p><p><img><img alt="河流的分支" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651904958065/1622901626000.webp" src="https://unpkg.com/mhgoos@0.0.1651904958065/1622901626000.webp"/></img></p><p><img><img alt="花椰菜" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905035295/1622901658000.webp" src="https://unpkg.com/mhgoos@0.0.1651905035295/1622901658000.webp"/></img></p><p>看看这个罗马花椰菜，他的总体结构是由许多重复的小圆锥组成的，曼德勃罗意识到自我重复性，是一种全新的几何学的基础，并给这种几何图形起了一个名字 —— 分形。</p><p>分形看上去非常简单直观，但是我们如何才能用数学对它进行描述，你能够利用分形的本质画一幅相似的图形吗？那么这张图形会像什么？你能仅使用一些简单的数学法则，来绘制一幅看上去像是自然创造的图案吗？</p><p>曼德勃罗找到了答案。</p><p>曼德勃罗爱 20 世纪 50 年代末就职与 IBM，因此有机会使用计算机，并且利用计算机这个工具来寻找自然界的数学本质。</p><p><img><img alt="计算机" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905151754/1622901722000.webp" src="https://unpkg.com/mhgoos@0.0.1651905151754/1622901722000.webp"/></img></p><p>在新一代的超级计算机的帮助下，他开始研究一个看上去很奇怪，但却异常简单的数学方程式，使用这个数学方程式可以绘制一幅不同寻常的图形，我将向你展示的是一幅非常吸引人的图画。它完全由数学产生，惊人之举往往不同寻常。</p><p><img><img alt="曼德勃罗集合" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905217952/1622901746000.webp" src="https://unpkg.com/mhgoos@0.0.1651905217952/1622901746000.webp"/></img></p><p>这就是曼德勃罗集合，他被称为上帝的指纹，当我们仔细看看这幅图后，你就知道我们为什么这么叫了。</p><!-- 这就是曼德勃罗集合，他被称为上帝的指纹，当我们仔细看看[这幅图](https://api.mhuig.top/ipfs/QmX84mdwTXsPKytV1wAPnaePgVjaC26rD6PugzzP4hwteZ)后，你就知道我们为什么这么叫了。 --><p><img><img alt="上帝的指纹" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651911381354/QmX84mdwTXsPKytV1wAPnaePgVjaC26rD6PugzzP4hwteZ.webp" src="https://unpkg.com/mhgoos@0.0.1651911381354/QmX84mdwTXsPKytV1wAPnaePgVjaC26rD6PugzzP4hwteZ.webp"/></img></p><p><a href="https://blog.mhuig.top/Mandelbrot/" target="_blank">&gt;&gt; 鼠标选择区域放大查看曼德勃罗集合细节 &lt;&lt;</a></p><p>就像树和花椰菜一样，你看得越仔细你发现的细节就越多，在这个集合中的每一个图形，都包含了无穷多个小图形，小的子图无穷无尽，然而所有这些复杂的分支都来自有一个简单的方程，这个方程有一个非常重要的特性，它是自反馈的。</p><p><img><img alt="每一次输出都成为了下一次计算的输入" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651910111916/ckct.webp" src="https://unpkg.com/mhgoos@0.0.1651910111916/ckct.webp"/></img></p><p>每一次输出都成为了下一次计算的输入，这种反馈系统展示了一个简单的，方程式是如何展现出无比绚丽的图案的。</p><!-- [每一次输出都成为了下一次计算的输入](https://api.mhuig.top/ipfs/QmWkt3vvcM4D3bx575C6MZLMsJnF8qKUShWDyFR6fRuXji)，这种反馈系统展示了一个简单的，方程式是如何展现出无比绚丽的图案的。 --><p>但是令人惊奇的是，曼德勃罗集合并不是一个奇怪的数学巧合，它的这种无穷分形的特性，反映了一种自然的有序的本性，图灵图案、 贝洛索夫的化学反应、曼德勃罗的分形都分别指向了一个自然本质。</p></div><div class="story post-story"><h2 id="简单的法则-无穷的创造"><a class="headerlink" href="#简单的法则-无穷的创造" title="简单的法则 无穷的创造"></a>简单的法则 无穷的创造</h2><p>当我们看到自然界的复杂面貌时，我们倾向于问，他们来自哪里，我们总是抱有这样的观念。</p><p>简单的事物不能导致复杂性的产生，复杂的现象必须源于复杂的设计。</p><p>但是我们刚才看到的数学方程式告诉我们，极其简单的法则也会繁衍出复杂的现象。</p><p>当你看到复杂现象的时候，你应该想到，驱使它产生的只不过是简单的法则，所以同一个方程式从不同的角度看，既简单又复杂，这就意味着我们需要重新思考，简单性于复杂性之间的关系。</p><p>复杂的系统可以基于简单的法则。</p><p>这是一个重大的启示，也是一种伟大的思想。它似乎适用于整个世界。</p><p><img><img alt="飞鸟" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905281938/1622901775000.webp" src="https://unpkg.com/mhgoos@0.0.1651905281938/1622901775000.webp"/></img></p><p>看看这群飞鸟，每一只鸟都遵循简单的法则，但是整个鸟群确是一个极其复杂的东西，他会自动的避开障碍在没有领航情况下进行自我导航，甚至是做计划。</p><p><img><img alt="鸟群" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905339509/1622901802000.webp" src="https://unpkg.com/mhgoos@0.0.1651905339509/1622901802000.webp"/></img></p><p>虽然这个鸟群的行为很显著，但我们却不能预测他的行为，它不会重复原先的行为，即使是在相同的环境下。</p><p>就像贝洛索夫的化学反应一样，每次你进行这个化学反应产生的图案都稍有不同，他们可能看上去相似但却不可能相同。</p><p>对于自反馈的影响和 沙丘同样是这样，我们知道它会产生某种图像，但是我们却不能预测确切的形状。</p></div><div class="story post-story"><h2 id="生物进化的原料"><a class="headerlink" href="#生物进化的原料" title="生物进化的原料"></a>生物进化的原料</h2><p>我们关心的问题是，大自然能够以这种方式将简单的法则，演绎出复杂的现象吗？</p><p>试着解释一下为什么会有生命的存在，它能够解释为什么充满砂石的世界，是怎么产生人类的吗？</p><p>毫无生机的事物是如何变得充满智能的呢？</p><p>进化正是基于这些简单的生物花纹，进化将这些当成原料，并把它们以不同的方式结合在一起，看看哪些结合方式有效，哪些无效，</p><p>保存那些有效的结合，并在它们的基础上进一步演化。</p><p>这是一个完全没有意识控制的变换过程，但这基本上就是现实中发生的事情，放眼望去，进化的过程到处都是使用自然界的自我组织的图案。</p><p><img><img alt="血管的组织形式" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905430407/1622901848000.webp" src="https://unpkg.com/mhgoos@0.0.1651905430407/1622901848000.webp"/></img></p><p>我们的心脏使用类似贝洛索夫反应的方式来驱使它有节律跳动，我们的血管的组织形式就像分形，就连我们的脑细胞也是遵循极其简单的规则，进化过程丰富并筛选这我们的世界的复杂性。</p><p>这是近代科学最有魅力的发现。</p></div><div class="story post-story"><h2 id="计算机模拟的进化机制"><a class="headerlink" href="#计算机模拟的进化机制" title="计算机模拟的进化机制"></a>计算机模拟的进化机制</h2><p>一方面你拥有一个具有自组织能力的复杂系统，它可以产生不可预测的行为，另一方面需要将进化机制作用于它，这样才能产生适应环境的东西，进化通过无拘无束的创造力，约束着系统的演确实难以置信。</p><p>但当这个约束过程发生在宇宙级的时间尺度上，就容易理解了，从地球上第一次出现生物到我们人类的产生，整整花了 35 亿年的时间，但是我们现在手头上，有一种可以在更短的尺度上模拟这个过程的发明。</p><p>你知道我指的是什么吗？</p><p>很可能你天天就坐在这个发明面前，当然，这就是计算机。</p><p><img><img alt="计算机" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651905511883/1622901879000.webp" src="https://unpkg.com/mhgoos@0.0.1651905511883/1622901879000.webp"/></img></p><p>现代的计算机每秒可以进行上亿次计算，我们可以让它们做一些奇特的事情，它们可以模拟进化过程，确切的说，计算机可以利用进化规则，来约束自己产生真实世界中的现象，使用进化规则来约束和筛选生物组织。</p><p>现在，计算机科学家发现这种能够自我演变的软件，可以取代人类最聪明的头脑来解决问题。</p><p>我们在最初的实验研究中发现，进化这种系统就像一种算法一样创造着，能够适应环境的复杂系统。</p><p>托斯顿和他的研究小组的研究目标是，使用计算机模拟的进化机制，来创造能够控制躯体运动的虚拟大脑。</p><p>一开始他们随即设置了 100 个虚拟大脑，就像你看到的这样这些大脑很笨，然后进化的力量来了，计算机自动的选择表现稍好的大脑，然后让它们产生后代，然后再选择能够做的更好的大脑，并让它们继续产生后代，下一代中能够更好的控制躯体行动的大脑，会继续得到繁殖后代的机会。</p><!-- [繁殖后代](https://api.mhuig.top/ipfs/QmZB8e5rcrLzti1m3i2HGsPXAa4jGwPSLA8b1Bh1joKe4F) --><p><img><img alt="进化的力量" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651909457438/qqle7w3342fypeiduzglqj2ius.webp" src="https://unpkg.com/mhgoos@0.0.1651909457438/qqle7w3342fypeiduzglqj2ius.webp"/></img></p><p>令人惊奇的是，通过 10 代的繁衍，虽然还是有一些不稳定，但这些小人确实能够行走了。</p><p>更神奇的事情是，你最终得到了一种能够正确行走的东西，但是令人感到有点害怕得到是，你却不知该它为什么能走，以及是如何行走的。</p><p>你眼睁睁看着这个大脑，却不知道它内部是如何工作的，因为这个结果是进化自动产生的结果，经过 20 代的繁衍后，</p><p>我们看到了这个，</p><!-- 我们看到了[这个](https://api.mhuig.top/ipfs/QmTCN8dvW1xiVKDN2CPXyHoM5mm8hZvn7DBGeSH8MFvWon)， --><p><img><img alt="很笨的大脑" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651908352234/bafybe.webp" src="https://unpkg.com/mhgoos@0.0.1651908352234/bafybe.webp"/></img></p><p>变成了这个，</p><!-- 变成了[这个](https://api.mhuig.top/ipfs/Qmbpxnv16XBsUb3sKtwvvVWEb8MZtS2rG27fAMY38F2inD)， --><p><img><img alt="复杂的行走行为" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651907861029/bafybeigincrzxgdqpdiiylnrgy7ahzmlsiuqulp4f5yzpra3cwqfmn2vni.ipfs.infura-ipfs.webp" src="https://unpkg.com/mhgoos@0.0.1651907861029/bafybeigincrzxgdqpdiiylnrgy7ahzmlsiuqulp4f5yzpra3cwqfmn2vni.ipfs.infura-ipfs.webp"/></img></p><p>这些虚拟生物随后演化出了比行走更复杂的行为，它们产生的行为，是很难通过传统的编程方式实现的，它们对于突发事件做出了像人类一样的反应。</p><p>即使这些算法都是由我们人类编写的，但当它们一旦开始进化之后，我们就难以加以控制了，然后我们预想不到的事情就发生了。</p><!-- [即使这些算法都是由我们人类编写的，但当它们一旦开始进化之后，我们就难以加以控制了，然后我们预想不到的事情就发生了。](https://api.mhuig.top/ipfs/QmS1nwXvJGNBCUCZs8A4Lp4kWL2yTRE5LfepywFdp42UzY) --><p><img><img alt="你创造了它们，然后它们抛开你自己做主" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651906736218/bafybeibwticqzlzd7cor4lgbfdr2efofzpzvwc7hcft32okxvc5qrvkhru.ipfs.infura-ipfs.webp" src="https://unpkg.com/mhgoos@0.0.1651906736218/bafybeibwticqzlzd7cor4lgbfdr2efofzpzvwc7hcft32okxvc5qrvkhru.ipfs.infura-ipfs.webp"/></img></p><p>真有一种滑稽的感觉，你创造了它们，然后它们抛开你自己做主，一种不假思索的不断尝试的进化过程，创造了这些能够行动并作出反应的虚拟生物。</p><p>我们这里看到的是一个绝妙的实验证据，来证明简单的法则具有无穷的创造力，看着计算机里面自动表演着难以用写程序的方式描述的行为，它是一个展现自我组织能力的绝好例子。</p><p>这说明了进化本身，就像我们看到的其他系统一样，是一个基于简单法则和回馈的系统，在这个系统中复杂性自发的产生了。</p><p>想想看，这个简单的法则就是，机体需要重复略有变化的行为，反馈来源于环境，这种环境选择了更适应它的行为得到生存，结果就是，在没有可以设计和规划的情况下，前所未有的复杂性就这样产生了。</p><p>有意思的事情是，一个个体可以进化到更高的一个结构状态，一旦你获得了一种包含某种行为的系统，并且这些行为可以被选择，被某种过程选择或被环境的反馈选择。所以进化过程这个达尔文学术的中心议题，在某种意义上就是图灵的反馈系统运行在多个过程之上。</p></div><div class="story post-story"><h2 id="尾声"><a class="headerlink" href="#尾声" title="尾声"></a>尾声</h2><p>这就是整个事情的本质，未经过精心设计的极其简单的法则，能够无意识的创造出无比复杂的系统。</p><p>这样看来，这些计算机虚拟的生物就是自组织系统，就像贝洛索夫在他的化学实验中发现的现象一样，就像沙丘和曼德勃罗集合所呈现出的现象一样，就像我们的肺、心脏以及我们这个星球上的天气系统。</p><p>伟大的设计并不需要一个伟大的设计者，这就是宇宙所固有的本性。</p><p>令人难以接受这种观点的是，所有形状、花纹和结构的产生，并不需要一个有意识的创造者，但这种设计本身可能需要一个更聪明的设计者，他做的事情就是将整个宇宙，作为一个巨大的仿真，在这里你设定了一些初始条件，然后一切的一切都自发的产生了。</p><p>伴随着所有的惊奇，伴随着所有的美丽，图案形成的数学本质预示着同样的图案会在许许多多不同的场合出现。</p><p>如化学生物系统，在这些系统的本质里，都存在同样的数学基础，在这些内部本质的外面，就是我们看到的今天的这个世界。</p><p>我想，这是一个令人兴奋的想法，那么我们最终能从这些当中学到什么呢？</p><p>这就是宇宙间所有的复杂性，所有的多样性，都源于一些简单而毫无目的的法则的不断繁衍的结果，但是请记住，尽管这个过程力量无比，但他却具有固有的不可预测性，即使我可以充满信心的告诉你未来精彩无限，但我仍要负责任的告诉你，未来将会发生什么确是不为人知的。</p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="我们从哪里来？" href="https://blog.mhuig.top/p/dad4292a/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">我们从哪里来？</span><span class="cap link fs12">https://blog.mhuig.top/p/dad4292a/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>记一次仅在 IPv4 环境下访问 IPv6 网络的经历</title>
    <link href="https://blog.imc.re/RSSBOX/rss/ef7fd902.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/ef7fd902.html</id>
    <published>2021-04-10T17:24:30.000Z</published>
    <updated>2021-04-10T17:24:30.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><div class="hbe hbe-container" data-whm="抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容." data-wpm="抱歉, 这个密码看着不太对, 请再试试." id="hexo-blog-encrypt"> <script data-hmacdigest="3b0d776fe5190adaae8922b792c14dbd504fbd4f1a97e660dfc711c41cc9c242" id="hbeData" type="hbeData">f5acefd70429a87fe5021e27622ec1128e40d1046ed1888ae7e891cb14d262dfef4eea3742a6ebb5b37f9a24966928d8534a26093596ae98a02be3eb347a7b4a0350c1abe43e99c6a0d9c654f4cf978bb34e2845c71926a86d33ee082f3cc73868d1bc1baa3e724560027cd5278b8bf2459cf3bcc441c852fe92e4689eb2c607177f354436be83aa522eafd76cf45f2a3720123e2922fbe64d9dd7ba1680fadf13e8203c95fa15fdb28a1fd449f57408ef0442ba0606f552bf8372472312aafd455f5defb1e9a56220ae298f8484e66bcd7f8b687098fbdd07cfd8048b73c0433d4b4694104d99c05ef936e7c7adc0ef7ab1076df9a626fd7bfa5377cf546c74dc8e309f54ce76e1108edaf6425e43dffdadd408eced003fd87cd28ad698d3e9cbee0f544263e62527582e22a2d29b5cc000744a9bfe62f5e5854b9d83342a4e58c8a25e4794df2fefee3341ac33fa66e4cc1a7aa009d9fd6a77d9bd1df2d45d163404030cfd4b7920ecb36e32d96e5c2aa108869451634dfbe5fc7954df8d16dbc637ad59f83169969172ae4ebd57f5c4c383fe347a79f97a3695d52db6b5eb1ed29b8cb170b1ff69fe7a9747d99e09eebc4fe2a232dfe900e1e8c90721707db78a6a92960f719abdefb1615e45e0d2f80e03ebe7732df898c03bfa3e5e257b44f4a63c017ced48b8252be554a8fb316cb3544c016e7cb792744f389256f4b8d7243c1d869634984c30dbbd37c330d43f6ea2eec8b52a453aa041f9a50a5c23f0504a18d3aed6e6b0dd15b5d9a72a38e5186651628e8783afa66bd11322235474233bf8e562ee227159f14a1b4b08a746d4c8000fa09300ceaf56971287e421a57d43beba2b0b7ce0d84cbf642acf454a55c491fcca6e96e5064c6067197d309b965ec866afb9051909a671d02b9c19648522edd92483a5b80c00885c96bc79e810ad12644646e07286ca3db98ddcce0d51d3901c6c17a64d2137bb07f6cf479312db7d2eca00226b4c8ec2790fc55591e8a7ad56fc36d95e25dc06ccab106e04db57e745bd8362ffa0dc37d831443a80c853c2e16577fcb9d9df4974726924b6ce7dab378849462358ec8296568e0409fae0f27426a85fc34f4f5d88fff2031f453b77ecb8bf5fe75c77bc818ca28d2361deab6f9d98f4dcd4c32d13e0256744b6afb357a16538acc5434705e0965163aa32be923c31b8024c490e72d5d2241816380b6321b3b493b661149a7f05a3f5244c83982d5ef27005fbeb33a1828b94d2b9cc4aac765fb3d72480db5a7d377873149ac7d382acd274cc2fbe786b7b9dbb76d668d05729defefba2e7138484a67c48c789553df68549908511d7628dbfcac77b42ea7a1a9529a0f044905dc9659ab2a1343879f17adfbb14c7551ecac60a77b679323546b12ca0678ebea5b20a565dbe899b7090ed654b204fbb6e687322a0498361ca17f9caae5d7c44f257544bc4e4b18fa60faacdc66a38bfeb3caaa857ae369ce3ee0972a343346c1026c51176e92573cea11ec1854c36d022adb5bd14df888ddaed41f0295e8c2bb4c539e63f702a28a91d2be7b3b2f9221dc6a9b6ad27b0d5e13c231c5c9a2db9ee13e8d5b124a3e514a3553544acde5a43b9faffe2c1104570aafda72e932674909d91e09fead8ca34f8666db934f2facc03707f8c76756ab563d9540854d7e70db535fa44633d4f42c5cdce6190aa6eeb967b90fd4328c33cf3e7d61fc57aff8e3fd1163caa462a429d028693f606d42e2dc4a4c3ad7b3e8f7b6f3cd62ab4eeb5524c421295ded27582e3dc0ef212b6c29580a23b6ea2fbce265ebe0f9772d36464f210d712f2c57c04a7ceb97263ba5b6ee8996a0a55025f10944910831023add9bd5eca1b815f881d6aa1b449e31c47501667ca5e92c2b1d7bda02511f23bd2f5c2af24dbf2a8fc353cbb1201ff9cdde3e26f5d897053e68f80b0a759a2c93fa51f9dae9ac5670a2f39f567cdb66e160c315f9c23074652cf851513b70e39224cf1794aaf25b88df5b887dc3f4285d92103f6dfe09a87cd6487246376546af0c8460479affe6b7fb0bc2ec9c613cb00830d10c8c7d8b7f79539c177d7947df8b16b0d41e533debde83cacdfbf774290ffe440c220c4ff622a629ebcf5012b5cbbc03a63e92fd075fc40f265d20c39eecd03ec8ebd04ade4fccb0db65c1aa31363669192f0706d4fb24b3a648140a1e193f1c3de5df67d96916e57d9d033c2e84170553cfdaed0ab5e38453f101243339d67b9c19644b88f4ae415646411dc31e2697a995b51633463e58bd2f3c17ffd3f0badd785749228bcef9367bb0f9e64d1ce7d11ae0a1df719166e6e6e78c41ee771bc4464ccb1418f431011721dc84f84aba10e67e4863b3325e8fccf2a01a0ea8b7571f1045f1c7aefb3621c9cdf4634695d99d9522f191d8cc1397a4ee985a10613e71919508f1b28084732b0c3e61094ed0884b07b1c1d45a71e337c63367588e691d4ec56afaea4c00505cf24fe7deea1fa514a25d406a3310f3891cf14215559f37ca8fa86b42382d9793e84645667fb014b2ff5bd8b45ef3e7b5a504996257f11f3854420e7fb7c4391adf63bec990226976c206cb2cf9f79fbc11778c41b7b9a5bf3cd2f5d3cb222371311ee23b5a400e73e5385c1d2a233e32027d59089d8e9cd92759ef489d2e22dab2157f98f4fc33388bca3018afc0dbd54911c98b86e718245931522b3a7e3a3808091454b37a6fcacd0cf96a02111bc6e5b21481d8ac65e244439727f1373455489712b5043fd383e82a64e7f034c7fc2ab863b3e4e9027794426ab959d1a7c79d77f2faf147dfab0b98e5c08ad57b76e96736af4f84401ea5674d992e2dd1deae1ef2cf4abdc289c792f1c39421d314d353467916cf62d3dbb91c56df51deb7c0fa74a6227466bab96564fa71a74435bd2f8b837a5a66c89cd3036fca95f9aaae4e4b41f0527490790e9b57eb1c8d87d01e02b605a3b154cee42b0db179719a4ee68475b0d7aaf9df3460646f0a184f7a453c551827a2bc695f35e1590a725d4c1f6100220a20a95b906724f74823fd74beb8bd40c4b69a35fd21c9a875b2fd2c9653e8a7dcd2fc7b54bc9f039f7dbb87770fbfd235e77f4993bd748427873a0aeb3d5f4177ba73fd049dd488e88f7f43cbd90bb5c72cf726127438bbd8dc4d0e4aac97fecf8ae03506f2b5219f8ecc3c044d2018e8b11d30b0687000e11d6bb1f2866dfeff5c51d7fd643c770155814e8e65013dd5cc2892f144eba64f2532b200113da98f49a5d264991a335792ae14bde91667c5f8c3cbe4d9e29cb3457925db6824d9176279869d1591fc89640d582f64ce7387021796f3b20367b2ab9c33a1b783035cc1b26fc1cb977933428fda2c3d4efabf5ea6de631ca245e8b185c678efc4e90694680d3c05c911e13231da44cab08e75b211cdde02c976fd59307d5032f7b1e0d06d74a434d8281ab0f16d0bf39eddd72a7071f05b4803cc8aa4f4d1fd5a96dbff8bfbbfd85dc26926ff800c2a5809b0fcba2cd96c72d9f72417adf29fd2e29dae6e20fb34738e8fb8d869bc98fbd57ab4b2bbfa06bba464e3650bd24e76b2f5bca3900db903f17b5c7b83a35db2cf696239ef2c83c16a1cab1b446b55d08476796ca34b7ab8b053bbb0e19cf1c8e9edf73e9b592ed293553e63cdd0b07cf508af9be6cb4b9ca79d0cd80ed58e021f67a9b9c0811d4f66442a2799d696dde89a2c89cc3b56d1a3db1e79a021d6dc4db2fd2977489dc16e42f9abfef08fa14182b89913bb83a57a005585ad3d73d2b3c62969d4ac43918ed4f392e87995d0dba57d55067f7f284dd0f179e301fdd6812809b7290f2c9476461b692c3da9f96b99166551fc2f0ead4c7433e1586a150dfd66b014e11fe36eee93c88961f7d009736f17fb8b97a9345e5237741d103dc31a346313ad3ddc660467e52925f55d6d678990fa320b56d8113796f9aebe6f98dfa3a8c5ba5cd7410303172f6f102f9d62d8fc171675b5ddf7a4ec8c920a2f5c7f86caa77e2243a7f27a26aef02a5f00ebb631be07f76b031e3a41c940689bb74ff326a70190492c1a2b94ada73bcb50ff728be86a44a7f653fcef3262f87ff2102a41addd7b67143b9a36ad580a34080947d6cb2a5565f58ef6050636b186dca7382a64c46a065330a686a16f4e7e12d8233e0fd26d3b2998d48211c9252e207f66fd43df58e5ba9c8c6f1ff79aa88eac1daf1a5343e79479f79eb4f9079c100e2cebc29889a3d3d69e3c453204918e293eb05997bbb27bfe5399ad6909270002f7d032bf6aeb9c3f48a69d33eab403266104f88d0b8d0aa8c8252ebe93cccccdbc48441252c57a8d789e5fdcd5a21e0720aa80914f992bf0a52d93cb206bfdc63cdab061ea5eca632e4a014ab30c33564f07c47e1bc4bdd73a65e60542974a52420c843f2504fecb0cc82e9d75f71b0f41a3b889acabf09133bbd2fcfe7911346cf6c4dc51c5f1315efb951121142aa2265dcda8012b996fc333295d0577e19b97a24956775c9acd9037076d52732b0cb34489495125896a89c207ad5b22dd1ada9ec1b849408bc435375a3499b08be58c3b8e47d60faec2b1057e78542a53a2934dd1359f670e9955875aa7712bf52a7909e6f531e3300c7d40f4560c0af872b30fb7c974d36c77d075ab84488f06d503ff5c0d180692e61e4371655cffd69d4c792f6fee9b332c34c876df0e616c208e20b3094d2ec581ffb33b4280708c6fea3a6d9ab284d8b65df29a96f569ea6bde1aa445333830f12c16f59ac0cda23c01b4ee7aa7b2d1bc9d163e660d5b371eeb79f7a0289106cbddb2b0722f47082fa1dc0de5a9819567b7a10c85d8696d6b6d4abc516f77292e7ce083eeb28ab227282ed16acd3b603989a26b0c78b2699930dff6b9ef94354cce4ca658a7d059dbdd21512c5941e02fcfb33f5a72da2fe4839877cd662560c54f6d5f3ea8387f24be3169ec5c67e7251e8a535efd5c443fbf5cd69008131bafb0b78586a63697f7893474e0a381a90876961e6f5a7e4c4548e7507d4af91d6137b1ddc0439a6f27195f0dc696efb793a82e668dc386e86743d4d615f32e553b91151b989b029f0d545a791272149f5cd4af3fd8ab4675d66ddd3eb0c979143645eee65e72936ed72d3c14c44fa7a59f5e65f584946cf5cec1c22cb39106ffbb11a3fde10c4076a5c81e8912a161227c3fd3e3d982dba3c28a4d143bcf7374d2cd2ced9b70604e796ff6c32f494ff025e60661e7157ba2b6e4165d6778fa1015ca4f04c3af847d6a1328cc9d1077ed68018fdab523c95dfada4fba8eef6712c522ca4650029335f800ca78566dcfd24793ce475a90f66c429c5f6e18b4f1da277ebc3cd47d3c786b3a93471b681d058fd4f929d4bb9ed9e2b15c5e0c903115a01918446060b7682714cb4f8874ef662584c384199f6ef31e3b5e9f3f4205f4b773dcf5515dbf6bdafc606d466ae2d36e46801e098769f9c8b2d2437acf4f37eb5015d88e63b3342a226d522459ec339d5203ab4ac32fc76e0b49ee2f83292552707197c89fad5a596aff7bfe79832713c30b657b76f83904f3195570473c4ef9cfb62931a757b1f0f5cf116825f90f59d77c7f2510b698a90636ad25d5f5a7661c2cebf557683db6fb33d05677f237e81878f84d1d97910dacd675c2d52eafd8f7715f25e1a743b4821a2a36d95762962e7edba7caa23c9af0e7a584bae0db92d09e64ef3aef8320c05ad498c2b00f76f5edba58f4a7d8fd47792d1ebe49922c9a90caae2498180df108f3563eaab7c332145f9360f5953efa2a2465719ee2dfc0223fa1107534b123b1532861c0b74a4d09e5b5b7b8850b32304a409dd2a7ad117571fd8a46d1912df716aa084c01b7515836ca61d46671ea429d574ca76135dec6c4fd5cf6c20c1b638f9dc79708f03490ce4c090614d812f1cea3d16bd7d6d6c001dcc550858865ccc35100424c69d1dbd2d20b5912263f3bb2f6700253570e2dc16a5fa70c8bceae57e3c12565253d7195432a2a5f9376e9c442ac0abbd54a65407e19dd57c0575585b8be6303e24397e267cd735f5af450d7fe87f4c400501cafc0c7b2d435e8f8f3c619764b409e07ae4a71f0612cfdc45c6308294173b96fa8f518ff6a28031dc667771100ab4134f157b68c4b8acb5829ab87acb9eea6c6df2700e02b7b913cd3d7cb25cb7ca3931c45732910af7a83e8de78754c59ff475137ea2fd1847074a14677f44e97249058943e841cdf2b5aceced66613287c9462a5f1550472f1c4a1f1b03d57ce06a017573cd6fc5f5acfe2fa1821c04bc041f294587b8d89ffa067eadce660b326eb60833614ab0e665680c2f3db29e668909caf323cee0e865685ecc729754b862c1ae86008e36f3f36335352048c591cd8aac1693e7740bf9b86772c820cc7177318ba8fbf6007ea187a380c156cc46ee930f379066835c2e74c438eef38eb2441c9f6946a5167665228142b2f33e456fbf5206e34724a5754108fe886e2f0b95b2d97a3ae6f306bad4e599f28a9fd69e224f60de15879579455edef26a8c591316ab527bc9ab5cb381ee96c119f5c662caa176a16eb716c285076964c0b0e9f3a7a25e4fa72ee6697e0e496fffa10f52f070e1024d4086a986e4ac5c06377563a473772851e6fe909215119436830e5fe340afe7150280f20a95a11d93051231f7ace2ed3256482e2ccba22ff18f14baed935d3087785af94a5ebb39201df134e41381244fac7868922d02c8834c1b37557354c4c7bf4c0dcb43158af48d1f04a4df3f94d024b6139204f3bd704e327a770811ca3ab34d4ad84e5f7caa73f986fc945a5bf47cbfe24696afa16afae24747b5d82589fa3f941da8ed8eceb9a756978481b5b5bae8784b4b43a33211663a308ee9722fe80e775ee5bc7ba9ef12f157932a932b53f090d1ae19b3d554e74fb371b4f0775eba48eeda559bcf32bdc32b29407fa4c587ce9c67af086616183a28429a66d2aa275cb6fd93046cbe0216869c56a18270be292682ab1e60e5b27c4740feb74d19d241f2ba6a77d8cb1412650b44c22f9dd088aaf34ee31556621739a923f76dd41836bd711137ce4a68b5d8371b5044103efade1ba31bd32150db84ee77a31ea7c53755f56dd7eba747b0fafe026ee83a1fa74202713dd7f0afca96e8cc235ba23123b69f52724b59ce25d47eaa7d10a071e622e2329225ab8c759089dd47e400a07a7fc4f8a2a93d9928ada25426c084fa338946fdec895a56cae8fe8dd912d1bbcf691e8d7ffbfb8ef23eff56d1361a6c2c542aa9d221fd0c277734249af2d147a793d41a5164b1174adda1374d6efe3a050c43491ada65d8551c31b7595603e3647c1101ef1e1033132020125a7625acc661ba4d504bde841c9c58bb6d932fdc83f9832b9175f23e35bfd8a3aa02d5eca6b9f68b9dcf8bdf40dcda95b9a9574a1a77ba8a24ea5480cc91b4e196253f1f3a3ee9f8176b7528c9039f80664e0a1d75cfdad1d86558766f4941822674aef1e9567eb58e53bdce04d6166f79d852d15c78c7c049f979b343b9c09735420066d417ea64f9d8c6d32ca83bd7a00df02ca3e21dff8f975e465b32df01a8892e9bc9499ef429c8a1cb376a1b50cc4f3d2fe7171adfdaa96a350c9382aa8f1fd74771afe951ce9429d4f550694fa80d9429bb7ebcba060b876f81bfb14999300b27d9d0230c81097670793407225533a68cf129c4fe6f71430a79e300afd4206e4446cd39eda323b5427c0d39679bf43f274cfbde0581b18c544f9ca4d12ea39559c2297b47eeccafd51fe14620c6937561468af63e2424ec7193ece1af23719d4f269b50c2304a7964e4677c1e9da45dadf31f008c01f1f939e706b82c9ad84850e6189e6105ed61219db9ff2b255405949c6e6ce49e4a64ab37bd12fd331af79d9f38c926aac921f2b5cb66ad24e515e37cd9e6127b93f3a5bb47d907735e17a48b9fb779c87e8c4c0df7bb57199219cf778537b55b699a1e5a16c1e5c0b19dd62c4ccae48feb0a3da093ed7700ff868161a72080f2dff4e3dfe9bea9233f18b4ab1bbcf735590ed74ad3a7f20c39794f0ad60835f39308e08c0a6e019fc9be7ac026b0b4b8fb82e6087fec19ba1d55e059b0ef5701119da1403960eb5868a4b5a66cafd12d693755c7d7b1ca421c11505be40d2604ad2a66b78328accf98d18e92ec712f9c67976f6279c4a7101de9f440c015773750fab5d78d165ac2d0db96d0a51bae30caca601d793e171148f3b8304bb56c863ae9ca1b08485641381c875bab28e2474437ed0b5c1e0806d6e7369e78fc507a96ba6464e6db9863afdbf3dd3fa288c629cab3aaa475be90c0bc9ffa6c4443e3de6de8a1acebff178bafc7ac3123be21dbf10db990c0f061696c65b98fdff63223201435d9f4b64461b228419babb9a5f766d98ef4433960258a3ba5290e3b1a0d5e4197eb947431f26811bbe1fd544291bf4e78f5df9e122383dfc14a4bee068c9a6088549698ac4d50b3765148d8afd49d33941d163ee0c12dc6428bb4b7379be3b3ceb2c3020fe56d66d5e3695a3aaf73ab21266897df83dddd9b0c0183525f92d865f7f2ec850da797ace2820b4e67e0860cf5164db16fff53f546e81f45046e707f5451e198d067617632690878979ccbe82a53e7935cd3ccecf1019779fdbb0ca4be84d0d4a3d8f91d15a30eaf985e136048821cbed5006b04b7b7be17755e4cc0b738a91f471de20518b66f590454d7b06719d33a723e178a5335b5dbd27d6d66f22b4890a595f89849468ccd4e3453a0df5dcea98e0d2bc479f09943ae6f4017bdf77d09a7c6d9297b0353ab8c2773f048415e1cb98d66df4f19d9405ec695af728964135b7bf1b40223d02725e9caf7b331066bc1356b87add2748312e07b688ec1178c5867cf4de644858c4457f92d935fb98c84afc8e1bf364af75baa2dc2cecacb83f06319e53b41eeeb7d3903ef900c7040a736237341b76639903b3067201842942895791d70d65efa03fdbc95ce92c4cdc5c8a8411554c4dd987c4efd9453d92956d9a4870dd4489c9ad0aef0ea4c61a9683ac1c4055e19710547a0df79d5a792d66be4a8d7ef41619c333f7cb7e9ed4d81b89995ef37a19fec65c81b40084881b25c4ab094f60824ad637e9289b7b209ed9833ed850a1eb58d996198b54cca2c92d30508322b3a796f35b6da3aacc8ecb24d951302a0c5e79c200d7acc4a57e52b3201ec8cf75a623c4ef16c157742d4dc4d1454fba3004abc44a3596e018964f594b6fb0dc0df3e3fb7a05c6ed7f8f4f16b2ede736c06eeb6f242a3b201d29135440ad446013dbc12c13898129e44774dc783839ccb76a592b238ae828d9be0c61f2943e0c5cef68f4ffc68e3a26a5cfab5e9973e0a8c057bc3be5c72f87230a95b4ee5d79e662080a59be1f687599c5ce4cc57f2e6314e6abf7ddaf799147f4ea9ebc095df7f49b0781be53c3db887acf6d6bb56e0f2aeb4ff133b49315a106b6f8f2d4d6c2c0b6afb9fa70f36756da57a56a673a1d7071886401746cfd28bf29601eee5ad5113aff3b8cfbbbae0c8b3f47370163e681e6c0e5ea58097b201591e9fe4e1bc83012c2f625d26a48fb0c16bbe786263e262b84f2e5cb1bb3b010b5dd771829d48294d09f2952fb88e721b0b735bed4132da0bdc68b1a6b12b260189b61c1ebfeb2556b918130094a0cbff812e735bc5a82ba364ce87b355f7b908886abfc8f53b612a30256a3748e68d9b15eb131035a61b3a57952699d685d1dfa27455506754a21495aea263a764c7b5a7fe607b21ac1619b9b5e4d415f4ab3d33997a3cc989cdbfdcbe12c5c5d891a0d6c66a062d34952d37b9d9df95a523951d1a471cebdd5cf32c818211dccd2f016d370d6d9f3abc8c2498f1d99a6e1e49c703011a572befb5e85295edf294e8ed2484abaa6b9a20f543382254bebdff5699e3f22fd2213dcfbf8b1bf562121bc9601f089d002d3953b1fe68e4238932900eab9101973d93808aebeda486137d8086dd4e01f83643e3445bfea5a52f198be319ce203a69e85a3e9eb6b60821e80cca2807a911ae4c67b2ce94cd08336eeceff2b8e41611b7c2f2e0a60fc4794688ceecfc3c0866deeee5cd43a07f4ef4552e801cfc821e1be7c4593797d2f954772596e317b19eeb1ca9659a7185ea47a3483f0aee9784f767722dac862a6dd1a55208b157f2e7aa1a6573a545f960d8eeec9a49ba3c9edca5ebc9a97b7c3603a642989d178ca8a905f27504188eb1a91a8b22e55f02395669d9668c0c36730d35e0cc996012859798ca1434876fbc926ae128f14a3b3a3eb422330a112a457f061c0dacc58076a30245327aa2e4a4c750d7ecff4fa173a62e4a5ebb006239e5ab3fa30ea234572d29dfc300dd26690fac2a0e0df4c2841148f1f1656a958033e4197c23ca9cc4ed6d851e5e22d8e1f88def759b2577934765a6058adae9bb5f354d81f83d7a2013b4e00000c2c5ad9efdd7a08328c5eff69259228a4f6fb605ed9195ddafe57f648f0dc4c11c6f69ec06cb8f80360403a2a4a35207bc2a0d3e8eabfbc215950d37d30a51eb8f57901b00687663403e3a7afcf7c2559bf5217e61b6eab052209a13d707594fb2497ed3103a390a723bcb73f90cc39827bfc63c600bc26206e7a4e5848f865846dd635168239060af032b12c1cb92c65282b8619b49d024a17729e15519ee6994b5a6a6a4a570e549f8971a66b7964590ee8452e02149de0bd43cbd521509188fef6b40006f79edca653b06eb0ba5161dcb01c968499191120bca4a3258944982484579264a630f880e23a7330a5fff63c04d824edeb673ed6ff8bb9bf6c5265f1ca522ddfa51a672d393b716345eaeb96b7a0d077bc97c66abb01318bb8d68d928f15e9c9a7785e808c95f826d89e1b2f4a66475eb530fbafdf560d5494b33df88b57dd924bc61fd78cb195580f3ea1911247a8ba3f070f8086af8c6a42f706de1b5aba1d2f4566c2d25145d65c96b272ba9357c7432652cb07f73c84a577f9599572c16a18579c53448ee76c9d8863881b74947074143df8c0203b7ac75e8583f130a66dbc6d9bf2507185f054a38d172b62668122b63c9bfcabbe703f51ec67e5b0ff45091230d6611c2dd59c93ae5ff818c91510e2c39719ff9c67bd275499f86b9275f32368c31b54048fc3d2d8c54881b41403ec16c0cbab30777385c8bd57c78d31ee4f8db4e5a240755c9e164a5a11db996951e8c3b991c07a8dbe733b770e3ef9ef49d9b310349983919bce7e2a00a89c3c4538e7e2458fb070210151c005432c85239d2a426cca3a6d275edd751e69c2100d22c3db1d1fb2d17f213eb3a11e3b269d91b3a3be6839e6ee10e1c3331841b86aed5dbf209b77dad1133370940ec73113fcda497a8e3468f6a5b9a730c74649d4fd6c934951504cf67b8c5bb78c1d51364b817fbec32cd0374b24d012f4067c87eee731a7b885b6f13e59f9b70001ab876fe03640952d7cbd39e682ea37bb67b6520a867beb64ccf0e1bcf1fde677c72d076e27ea0cd4a19c6b3d4eeba5ded328d3a79a2234e6f1eba4d01f484c4a57f98983b7b723d5f2c1e5898aa27c77a3ea6666f2d8f759f31b9cdb74b50f7924077cc06e0d68748f7434f12d908b8ccbe1ac26c70809beb19ea55179574ef39058b8a4cec433496d3ac95d142b4d1cd5dc357e96a62955a2e1722018becf5579d8e4f168ee8514f3622118f3a6f46d3c3c84c55213741f3204d43d23a87a7d2359c7ce5d59ba668dbaf29d1e7010bc7a53b8d4a7b1d078db4376b809a4696738b001082e559292b69e06e7f3d76e2f55bc1a92f23a333fe748e228a50e6305ef9360e2c6bc054904db3222a4e03b9fe5b0c0307eec85636c8c77c17749da455d0515395be735c817d2c846ed82160b7f2fed7ba0be5136a941d0c064d9b72377becad83295f67bc0b81f504fa3b1d9c4c1584ec2d7a332d6f564645f6a577d1daa039b1a4e3fe67cfd7ebbcfc1c05d7ef1505a2972a56f30e8cfae48cd8303768db5e894db6d2807ca76b34d991c70b53bef5c2f857bca4508ca6200fd3c03d9509f539fd366aae6d4250f9b5bed5ece062e141e63a855cf2dbfa23d08e82db205e2a4e3c3622b8d91fac56219abdfada0c853bab91f350ecc44f979fe80c854e632644c98544083244a64e5d4bf9a082a542baf329006623ce11a7cd49a274f7151b5065a92c627cd8caabde10c0e6997368366bef3e0e35f9ec406302e13e2ce67c131a8295f661dab2a7bb4f60ff5c8753e1cd72ee02dd3d22dbe777c2e8575d54b8cead743777b05cbee4e85bb251365a5545588fcd491627a4e6fd926519dccd4b432d07134e7f25366203d75e7bdf8bc74c9e48e2ec3a0b79943f626446b310f2c3e112a2b53984a16edf8aea5b7e2f784ae5825a14a4b1c88f15dac58100db22f1bf76e7bbebb123402a6e26120e2ed0c76d09ecaf9025ead72d09f0857e23bd0f00d14aeab026ad69b208bcb953402176a17b0c4a8919c4483d4536bb78c0f697f10bc5db2ad49b8713937c4180a3f0368cb2738b5ae1e56876f5d9deb207b6aa195f8fe038a26da32a1543e22b0dd33b54e819c3a7d7a6ea248e4efde285febdc243c5bbba69f9e7b0b828327894a34bce93ddfa90a0b1f49223bc4bd8e4c5a646e688fed9b5ec6f2f976410dcd9719b2c6fa20c7d1ea227bba65510a13e3f05c4b6acd4549c513acfb0b9d8d4582172de0a204d46e1457a57f3f419b9099be343f77f659b9ff16050c232a0d22eeb83702e90e5d460795169d39a1acbb0f154bce2849f9417b4556da9db1f6db5d62898f16ae25c9c7d6ec47b4178dbda7ee0d700a39db19e71fc78ecc3e17ed493617573f8ff64df89c0113ae40960101d10e622041294df7a37439d6d4d1ea31e5da37f189ec547d8268e41775a85aa0e483465d4c1e23a8c098a5c6423280460f5fb976024de3c0087a5996d8ce7ab64eaa62d6ee91ce4c6ecae6e9e65bc134b153f0629c2033ef79f4aab3bf33b9dd2732656b4c5146d51af64658e3a135a3694e5b93e49eb7b3e3858410fd1453cf8a8ef5d3daaf82216b9369fc73e4d102bfab275fa6e0b9fd13991a6aa7b0b6cb10dec93d9567612a88690eb55a8491f5330eab53b0a58435cb4a5b28567ec7bc74c707dbe917834203d77d539db00404e4879b3176905e516afbef9fd54460bfc0e88c86f7f7b627546736e26e10aca8f88aa6d03888a6cff6f0ea95ae8871b5916f8607468bf765041e67bae29112abe934d95453ea2ab99fe1589e8b637c743b9e17ca495138cc11a58792173d983f7194ff8cbe5c08c9a04997f848dba72063b68ff179a8d928c2071aa1bfe263f667c288d4b2e6120d71f38a0b2ae55d96166919e52834cb3f707c53cb421cd37035565a2924301d84366a795c57fe566e47dde217f7c1db21f44f3fd45e1d20710be9c97b4db6a0c9456b21df800251556d224f10db2db203dc0bc897c836b161eb1a1292e6bf03f78d60c810831b09fbac31415f9188170cfae7f109df10b81e600c63552b28391b9eeaaa8844f5e2c501682d0651ed89a4e912f393047199f9c1ae63e2d7686386df3228837830e18b2b18cc912b230b902d2eeefb827eab4fa4bb1d5647590cb967be4da33368fc1afc5586d51abc51982a7f8027e3373ea4da7f98f7061781b337dcf0ae12797f71a27200ad7e2cd56d19f76cff185c992d4903791a1e57a5e56f043da4d47df9e6a18664894a377fa5746ea37768b94c8678b44ec6bbb7ab9197cfa591b61fb12ff93e7dfa2199ace44ab66644a74a3a84c58e627d9dc327b515534e17137f7c7c493f3deee7bc6f8f5cfc1a74eec8e0ecd350658c88fc28d0a53b036d52bcac84b3d1050aed5a530387f1194fce8ab3d4b07f5703133e31ab323378c3960b8aa97991b2767b185dcce3e83e217b3f91efafc615a32c00904462e996daac14840f0f57e7882fed7364d5db08cd4b307bace6da0822a5046df55914f648f56d1a71961e5e087c8592dd8c1300d52277309a568247452a514d213d90747bc6bd6dd9a5f3390dcfef9053acf423ec958377678be2587b4e384f520298e860247e95d8a3ef14e9f9356eaae2cc5a9e0fa7c5eee437d9778cab5cd2d945c406f160f18ad67878b6d638dff2c303d60b5a80556140e1ff4387ab2740d328b5f712ae2ee080b2453d4108bbb5a7c1ff660eb7e494e8dd405bd2ff33b04be94ddbb60253b047e72b5bf02dbc1896292b4689b9de84e4cdf382a2d44ba4f2f4fd688cfabb7f4d806a51e7b0ae3bc4bacf3dc17818d4ef65e5da8187cefb40586ec09324c34c0b0aa3af486683484c33c436199f5fc5c9f38e3e6759e01ee51b6b62e9d4a953cb1b67dd996450e933f41b073c0d64352f31402a77a80505205b485173e7de2c2e5ca943b01eaf2df237058c33ac89bd1f289b36d02555cb65a9f779cef03a476b591fcac0150a45d555abb4660aed4fac077675a1a285f9a1af380827b2ac551ca571a131f896fa95089ba65e64cbd59a7a79333fe028f84d73658445f658ec445d568572290e7bb89ca4472198036cfba90f153368cf9f7047b6e239013192a8b8f1080d4def04985215e6a96f53553de7514539fc49277e2f36880bcfd7584b1e86ccdd02c6c1fb48dee3d383b49518feaedb2ffd18d072e57fc50d3a1e441330ad6583d3826eb582a88d72d10d18acd359144d13c9aacc3a6d523d71f580389a3f875081ea12ea41eaef7b90c76f2a689abf3d39af8f53fba6f7d7a9d38e7872f185e1946f7035561141d9d0689a4d365910319406dce3a57e99bc46cbc8ec79073143c381e7a4282c3d3350f445784f318ccd8b6ea41247de0ddebba898a1fce36e6ba1ef54917bb471850470034c2df9820ed55489fc4d3d9fe7a21abdac514bf5f9e07bc54f49291a7a832af053dae3f266f32b3db7af6834bd2b62d92f679b514347d4a33a7b59d8c3a66c4aec6ba74bc81369c08e204a06d9217925a62c85d364704ff05a80a437c297199ae46518dcd50db101be3531af4fc2435247658cc67580e0d54fcc662e801ce559c538cf8ab0ff4edbcee3cb4a4c8609ec332e0cbc859deb81f707155bf21996fe41e007577a87616b97dda082d79175e65ac3e623163a2b4cf582fee0729c7a4e57a020f629327a6fdd88a03abdadc63284d72c9e9d02dc645532416d68100907f466d2b49a9cdc370ba870e1235c7f01a21fbbb681b10dde2a6984f836cd1b7d20b78a6e4c0c28cef8816e49024c38bba1869e0b5a279f3f277f30d48235715f2420c6d01a8bf94747a0a11ab7f9b05eac21189c07597f92c32967eca5818d1a62a1fcdc1c641db7701d9bf9755784342bafb0946edd903daf722fa946dc91b4cc18be84d30d72137b46e91b95d06a4aad00d1d62d939a40572f4686149df8d3c03d48c15611f00ae0c25a61fc37638d9e0cf9d23d3f6805d22136ab3690e80f1b3379c05f171cd0550a643295cf0f2d4952e260289ec06034f477b0d1b4640d7ca1415a46ef5dafd63b57734316e432cf5a824c37cd65e0be3908d5916a53b443fd2374112b01927a74673f0cad7271de36403e3166bd27d1cfe095aadaee653ff3b4d55f538a7b8d38c398e8e2ef7cf41d18c85ad2395d1468a141d016fc8e773e2469996eef8bd0b9571a3693dbe2eead40cdc1f0a3083bdd62f1f621bc7b5ec76d196b96ff5a0e316fc40031cd7df19dc21b90d77e2f84c74a1c0bb0518c7d35585db4f9477229ea80fb5cd6a8fdad8b690a4941bbb4ae44ca35b90fb54963c4480f45776cbdef3cff4edfb6c3616d866bd774425eb38f103d4c8b8a9708bf55469c2517a11fcfeffb78c6a7bab7f1773a8ea22ae959fdea52be9fd631291a301cbc3c361ca404c85127cebd39629bf589958c2f223fa73d9ce59ed4738c17b8600e67b6654aa6f48329114ee9a04b0e188e1659c7dd50c53d12857ba79fb67c34038b371412932c6bb992693ed564ae529c36d3da368b7e2c10db460d9b011922d9a58971c7257016df673f12b8c27c8af87bea686d5bb6c09325d9c2657b3047aa6a1222124213def059a5e797839e39f5bf0ef4f8a880da1c1a2b2ed23bc51e7798fd3104deba99498c04ba88ffdb3ce6034b6d08678b5a1a253372a5a07afcdd014c5aeef124493834f3aa965d07eb8307426928e35df844817779c7307bdcb7a6742082448eecdc9b71eb44f391d7306493461a54164afc694551aecc1c1a17b157c3b4142aba9c15aa4c2b5f68b02ed95381f336a8ccbca08dc6dc7b4dd0719344e404d81377cf9f81dc71d3dc0c0ff914e94d80bf8be700ba31d84e628c8e932c7b507539be9f79345307f2b9448beb9fe20267b6d84dccee45b4eca5b340a2cff62940bc410859f74031a9ba1d536b67c9fe7bce5e41c5223ad242515ce32bbda624c32999b55d1804883f1cd5824cbece93092f04304b2db8f3d252de89029535f0587ad067c6b534d87509dbd45c5e90d3d02c1c30dd668d70b2e2ff67ea4f4dda7b90cb495d5c2debcc6597325643a72ad48d5786fbad70ac207e6817e0a951bc283a3bfdfb1285f2476914a9505360e4d6bb4fb7a99227d249dcf7c112fa8b668a0935f473e6d65646f6659bd8b781b404b80e357269947c376063712c7439663ddfe0f517e7186081d463f87206c33f3c984189bd8a69b0eb7a162d45ea709de34b8eafcd38d6ccfc0eb515cb2d7409a2447e8e4135d6bf6ab31156ca2f1f30c3fef9cdf5a5e043680fafb6e3c15a8222077541f19e2530ca9ad580880b85feb215233c0697350efc150dde8f8479d2c5f9d9134e94bca242172d2115653282b89d69405034d04a0da2c8d42dc564051b0060310d7a88df6a62c7184b99da51574672962015287c65ac59c73870e3489f3fcf457448d8f6a13017605fa73c54e7fbb5561645e6a7274ef07a9116fdd6161d8a9e02f9e1c2604a4fab2693ba5228ad412768555638fc8a6a1bca867af60732aebb273c544da8ca3ff70896eb048a4aac0300961ed36a467963b866f52423cd5d020a4b51aa7bd919f3b5cf94c8e0762e1ec9d9a5f35a31cf76ce64ac0c9f9ae80cc49ffb2d438ca6dc75cd1ee61795b55d0e6b63f7cb036ffdf3c46e16125636c6968fc53d9e08000030de5ea39c56672718eb23d378c6b3e7813bdb22d01419a06a35efd69df3eab589042e09d21c258f65aec297232e7bc58f309168c1aff333cbf9533bbcd5f5c4a87c3cfdfc7d301b7e45026dfc7f28f6e86edf1e669423b098153e8e7566b352ae10a77d4e3f10117eb64af2cb566a5da0fc6028fc994bd5366e7b29a750c796add12f712b436148ccb67e50481cf759db9ae777e76c2162d86f94d67069f255c6bc0575da0a15c7153185c03639eb7c1518582ad3573866529b4505a12831855fcbfc320d9fe267e58b6628d414a858270cdd28cb92449081e3f400b7f380f812184b0ddf87925934004dd0cfe09e552a239b6090e4279b0f54fd3066a16529cff31535c4377e035b3cb392ada79265a89f1453150e5acf812bb72963fdfc4c719f28e5cb82610063987f4bd544cf3ae1e3992f392e870d1196a4255e99fd1fa341ac9491b33ce499ad3b3ba8fe5fa3fed13df467b5582128c348e0b9f757fa045e3d41c823e52292207b589a762f37aa193e32c204a46e24fedb988773e70d3b8e2eef1b8007735acd75f2aad204cdcf3fae66156ece78743ddc5df291def4d57352bbcae462fe4501d7536aae219a3634d0a0aa623b73df99feb89147b329d5a300b2bbfde08463f577d4a089837e89adf625f34cb82561a7190d49f7d5d4b9610f0e6b050502c1bb42d4c9d30843a26d1181c66ba3dbf5ebb0adf08f270371652c615beb06b56aac62f561075704e8a6ae1ae105e9a7178771f5dbfac55a1c62d1027100a3d6b656a7c25b3a4bb3b36d54e1cc151f59f712bc6c3889feae8a6f57ac7ce806511d5fbea4b56577dd3cd2b05f734005a7dc894b1532c71d3b836278026e7dcd57b9d338b021868a4b20c3813a7390dd83df879e7bc072db499992b68abe6d5546443dfb7c25ee10d10e04851509e114bc88fb35b86d9f4b9124037d3206f22d38b982526f7f984b9d1fdb7644ecde837457e4f016c5e3468b1b581c872b63288a10981651b8a1b254afeeb127c2dc344ee2276f2afe6487b2b5bb068432d3d5d7f50cd2e1993f08e6ed0f2e8e96c0b5d26e19c959edf75756252df6c7d241e078eb8826f9f72b9a6f905547514e940ca63482ee70fa413ac80ec7fdfca43c67cdf47a5333d59219f6c343a8b2754388a4ab440599ca97bebe1441fb21bfe8b0df7f494707935f0ff3789117cb2e3db3b553b7871e4ed653515abfd561b69a8230c1442b8550ab0a11f8c4332caded4e7bb7a0e9647bd29f4008d3a740bb0dcf6daf9a684e2df31534f22ffd649111eb09e6062307e52b60b586af393c422904fd3f09fdd673c3cfa631b09daf0b2ef0c6e2458f74184c61604242180855e10dc4ddc9294e48beaaaeb946d92721145ac44a696677a1380901b966482ac4d356820437777e439e61aed5086a1237111747db73c1430097408cd2440fd1d9c704f0ae3dabf994926685df2e172d2792fb56a30ab0625c1981c1e442fabbd7faa63c03edacf582a8ff3ed494586d2b9663175506dea285502774e02c6eacd769874bd164a5645144aa10f872c4a0876ba3b566bf772ded970ace6cc4ed4d50d237ad7e57861f678cd477d86d4738ffcf3411a01c7d7476c32f6223df2fa8cd6d446762b77c0ef21b6dfee7de06c4ee4ea2b00c2a7f424b8722fe43750039be442e8ded87621cfc368ba176247a50ac8ba3ed09ddac59255c4553c47a92996ca6193d0dc8b03693d625afab31864178a4de0865f24f642111789ecab71598146018ce766ae2a070d553549c7812d1d6646322a68aac5d2bed39f078bea59a4e9bfec119fc9d0efd6d50131364ff6716bd7e55474c6a472e13d0c2bc30812ee55fe97c29c31f07ddddcf5c3a375e183909e3370f47f3516e7acca77a789604fd0d1f0050e784b55b4904f23bf6657762c3f7b90b6f8d0add735aa2c383cd3ed3354eab77e9569412957e78a4348f7d46c8d07b0adf5c596df99157945e8f1d9683da5d5919bed86d7baf9cde25d5230261da4a05fe79c11ff8e049688135aeb3622d451f108a093129cf8061ec30432c9afbca1a9841a30791f6969d5eeeca147d8e4da6a85de12b0235b8dd3b2e275ce2482795146f6a35cfe5d23a078066fb8553cfb9d8233cc5c53c210fc842646895ea643995e5d2d9fcff236fcb487e18d6afae07c4786e6eeafce748ec50a009a2449182f62cf73ffa1def54697c1abd6f6fd82617ee6f21f8f3cc6afaa37b2d6bde29db5a926bb9b5d9ee34dcc1703406d6131bcd809e15a057e86a77e9be5449f5bac6d7b59ae2685e7f8dc151e4fb06acd9eb9a223975a779166a461f99d06504caac42e24dc1eabb7d9192045b8f3bcc41f3c146dfc3e7e6dd5a33e99f9b287c21878439af4dd7a9c14becac816f068d35f4fef66a7d28d3961bbe840a8010b238cbbf3d39d2bd2527c9fa50143334b726253e582a787d0ecb732d57fd053482a04ac426bdda3d3b5457926fd0813e9a24efa7561d4870647dc113433aa161e460fa7516a33e60f39a5f991e25b6d7870e84fd34efa17b4e0306da9c01b2eaec0d4566a9b5461a098a41c32163b6f7f09a76a6768d51c392659bab835463d0eeb620b03b6c81c97b0d52f0db59c0fc35ddd3aad712363fe7df0f74b259db9664a5eb74cc7932ff756852c28e90e464db75f42b205a0ed6bf19e1ebaecbd2e85eefd8249d787da63347204a22e607142a9fe0556eb4228c5c56edd7420a4c9638ba8baecde5ca65093d7c788a8a37e98abb393903067281fd7cb3a0bf62351e327f0e08d6c8918532e37d4330e88e5ef5a3c234ab7ca5574ac205de62eb7c17b93d04f5f99fe509b637af62d54f48dd0068dca32dbdc6f4922551178082eca08b994236a19957fdf9f5727a7a3b0dafbf3d8d19db369880d6db0656caaa8ab9a13dc4e04e4548f1252e43c0dabe8b96bdf2e9d58ad7534008123ff24d60a209cae16c96aa86854d6de0fd2ea3aa3fe041bc4b9c67e1035c838103e1fe65437230251f0f65784fd3203b2be3bd217ee3ae92ca0c18f04c16f7e4ff0ebcc87998023487073ba3842d728ef56745bc0ca31a857faec9664c9b902b9efa1e4582f1a62c80047c1f80cb17d528a39e38874256b7762a3a99a390bfea2c74f0f024de6b0ab6fa6fd699466308426963d768099f4543e85de10f2441843b34f4e0f494ccc2dce0a5161071b29f1085aeb55a5755f5598dffca6c9bfbb2f82909accd52c9210b7c2dc8b4b411e05022c869997551a28739e51537c228dd331a740b4eb77c2c55863f1d420c856ad1eb2dd67af816346c4ab3a04a193906301b705de4a49e6879b8f42273c88710c42a8634ba1709a6bf69a71052128266fb8f3f43caaad1af7874bde2d4125631998eb26ac025a31ff7f4dda216054e64734f225f76b0a886a417cf80685a9ed4de68da0e29f8c7a35e383a5ae8b726876b99e01dab0d3988bd7dbce13069b8f6d06dc232437c3d2d66077363c63458e872d0030de9c2344fc27088676a6ffdddf279acd8ffcd4b35d4004d64f93d2ce2fbedaa9f9cf2980f543ce7662dfff5507e89c308b13e5ff305cd5994f39aac0840d0afb631915c60e337f1e329bb17a61814cca6370f5c0557db0ca842ab7f1528715bca9912084d3556ea82315f5589d650c414003f9ca234ae72a50e9290a267722059302e8210f959363a695322e98359a348b82a489e7362a83bcc99c8198012a7c6c6764a5581afce922b794483d77c67132e4f8da467b882c6fbc2bd7ad57f273445826013e02b2360d4db4afbb9260505a1d28542785012e257acd450a8d367977191b70273cae11e638866e58ed90327c47cc8046fb4da3ebd9e76ea75282a64cb6f4e6d050f0a0779e56a665fb86e65f042ace34944a623770575acbd1fc5755a0c279d9ebe5a7c7cc28599953f178b7b6d3615c1f8807114d48700f90d5bdb9659f474f757b44d70da5fcaffbb914bb6c0dcac0f72ce41691de5f99c7bfe95523c2678821991f3d57a410e3c835ca64c3f56e4b079973c919725909a44cb84bbde778e23c6ef991a4dfe5dca074e34da982d98ebb6311a317eb5c7e57350dcdf36105c5e0db419c2b08bb96f2819f99854fe2a7a3357b4357f644b62579bf8445272c37999c9cb2234679a5e8f90a7610f282a04e04d1ba329aff3c8707211e552553297920a35731cbd9009e234394e3c922faa857bc21cb11ac73a9698088fe44364da7ebb69bec60b3ec7456a3b9e53ad72d60a94b4c1593a4b1f006f1063a205139b59f3f4651b74bd7ede542be071a253da6a921025b49f3651dd84b2185fd856c2024f9861e7eed6981369cd578285b0da70e39a0c3d5cd3c5fa8900c2c3241e8a66a1560ffa8f507caeb782aca67e7c94800f584d3369c640ab3a544efaf4f49cdc617d1287d59eb18fb89585d3b424ece7ec29319a4524d737fd12d93ec2c16f4f36bcc328d3d95752acce7d32d14f47b1d39c6c65ad67aeb2a986d197879d0ad4c9718c624ced1dcb2b80d512facb4c476994313d7ea87723ab01e790f32d7782cb6fb3d7f3b9e328b104fa80e0d006b41f8a11dd03d90cddeb11c643354e1fb71edaca97a137ceb97125576f49909d180cc9e5da336b0d3704baefc8fcdb5711716a223b08e6ca3ab1032d6c61762becd1f90d219cba6a536c4d5062584e3f76da6fe238c0451d789b0d7e447e39b350df70adb1fcd47b38e50cc01536683ba8990f5b9d228bb072ebae0ceaa2ff355ce0bf7392279724f9f0c60d358f0233e0285c1aeecb9e462b2c4d1e548f04f5be28eda85f9d7c28688cdbd593adb156d2f1f9309efdeee3cb38c3ec3b460234c664270b809545f0d06bc63e0a27e13b19048a635ca96dc0d924e72cd6d29dce97f8c97ebeb40bf0262bc265a63a39f564c55a8f7a840f46713c71f52d159ded84a6920550f48f568beffe201ddedd3ded4bc4bfbdf5a06fccf51d2ad8b5b64e66fd6423eb2ff423161425ba25e72d7b26fdedb6d21012490c52aebbe7bd40d198562d151ad64a15335429be9321a62e4611a215471b96eb7bec53d42b48917de2b4a1a068ab481b19231bf6fb547ea34a5c826702155986f7c5f80ee2101f752d848e1d92a207bb2b31fc4b58f75e49ab5961a4690752f5966f3b6af8719f962e1730a6e215410cbf267c2c40984b2b7671730cea64a1302a4cd85b8bfa4d6efdca339848b906ec0a8229336184bf1ebb0e17d69365b0b4df72ff5470f2e8fd9c8102df9b0a736a2de42b432c5c4fff7b22ff9fa3608d5629227cd69c8bcda3351af7176d46b2a0d0c7749ea716d2a53d66e764e4f8f39e528a795a10b28e7ba22848c82973f15e9fa68c3de037f290c6b3ffeee6533c10d5146a69a62cb5e3305aa0293ca2248d0da6006743d2026d3523d971895c5fd829ca78fc27e62e16fdd4799f5c3aa750a62c3596c410d8f5fbb15ded0d9ed00e6f9e9d73a1da77bb5fc403d87818a5c0fa991981dae5efad20c42599aef83b7f030c4a40a053fe5cd58859f30af8be98f9a8dd10a101e71056d29be3483feca1289b552353bac2bf6b313c3a41a67fd7ff7d866b56d290323e49b2356bfd8b2d0de653fbf094160ffb41571cb06e7ced0474000ee5a593004fd977e0c9ac01b20106f161864a01c384df9d76eaf396373d539c94face7091f9d9a1441d50c66f17bd6dbe562479399e1b8b9ecb474d24b0a3fc6d57e00cb54625566435c07e3f50b22cc74bd0238eb22e6a139845ee0bf81f8b07fc088bc842f82c02e03b123fc094587b6a077f933bad3d569c9e6d450145257e5857768a594127d0bb9d8544962a6c4353d343e2add029b309cfcb36fbfdd4223791b6dd604ccf988534f7aee743213f4d1673bc16b4cb8d3868885faf0ae184de2e8bf599c084fee0616b27f082d586add06642d7f0ef3d7c1bc22d62d71947ef5f68404498454bd9a772ba2a1c368412a571b945778c9ab9154efddbc75ad16a7425d078e13e842b189c228a9f7ff479a4c8859f58ee7388ed9d4a98ebb578c2f38f10713cd0a60d4b1ee14e7d1e32a60060096d9c7976bcae0d5d0ce64e4dccb155b6dd6219f2c2ac8b1d9dd35d6db7e6e503d292979b018e2ca4a0deaaa7864b67fe8ba0f06244d00595db5590b1588f96b5ad329213a6e3a364c83676a41c7860402e1b8fc9072136b94e2c46ca34cef39f92cd876125e86056eb8bae3862fcb54c59ac088d37c6a807ec545b6dff89bc23d3d1e1d987d151bb9e2bcf85229dce2695fb986489934c355ee73f61100115782084b38f714cf2b79dcf5cf64bcf72366e7b87757a1bc592d94d5aeefc58bd233413d333d2f2ac6333caff5e916298be364fc767c19ec85af9fc3240cb0a5c9d9f1d79fdd73858fe496700a3796c08cab361c8f69278aced0bfc5f74288ea8175006fcf8747a00e35e375053e73c3614997140843c30d96632d53a652611e64512d3f8e7c6f6c3e2c748fedbb56ef96df609008e329e70dc52d494a367a92a4cd8225c690b680d1dd391a5cd94671fde5b9e332ece4ba2eca70cd050af311fdb80806604aba0fa82c43d10fe0df24510054a056c15c971520aad204160fcfb8f175a2e197311875139cc1a4bbdc3d2262c956d740e78fed107346007ec189d1eabecb6acbb878dc44da81bdebeda46497eb6f0eca08a199e1d2ff2897bbe92e3c8bed0f9575bba235cbabb6c7a618dee0cd48c928aa46ba9a1163330a280fc356916182142a4aed89770090df50c49839cadf160327d04818900230e126ad5ff447a3dd2b37f9275282abf598e6fd9f51cc82cb205d951318b7df15a0542eb5b39eca2c71c5c0df9e7f0101b64415a08ecca57bbb63d269940633da0c31baf1fc236a3bfe629cb637bd9c99d8f4abd2f7b9b76d2c64568fc91a84e08ee05f3d95254401c2c28926f142b64899983799ec7efaea9fb391215978bb5e56990ad512b7353f3f7efadb512eabad14798efe2ac2f0fa5794731015ec1800f210e0e298d61bdce5218c59c425b370e57a27c179ba13b038d169a0e77f34123994806adcfbeb0847d1b1998ff1bfd6aca340a2b67f9abbaea9ab168bea0eb1692f3062bbc868a01e24eff90c37c5a7854216a1352668f04ef9e8c85a94f92da11bb499c032b7bd63b54b236e3d63cfa3bdb4f03ea5fcb8d5d314acd3bd36b8bac6da80db241ea2f30a92a323b0c6a789c3d60294b74c80f15678c9ed88a6e1d418f6a1e25a8973e31b48086df3c8ac414e5abd309c37d6c9bc2b33696d1baccc34fea05a6d8eae2659fdca2c4316e0198a2e7fd11d108fc1242393766f1a9239ad5afd0d182e8faf7f385625ad97ad41415806fa6313effa8b8dfb4560139ae79fa9daf49bd83c55ef33039d900ad7e8248c9ec7166df2d05589e50410b0431d8502d8699f5cd53c3d5ae86659af5bc568848134c432c6c9c9814b88fc9dfce4a81f0f262e360562c7f7334d31afb5b0d3638dddeff6e2f073b426380a60f2c71a5e20b7bec2c7419a7a82f1755a25cffb7d40c9b12ad0eafd7699bb807d6291f4117d2a89b52c80224453ed655d643c23bc7dcf82a5255949f3730824d83d379b419687dfd99055367df81ebd32ad90cbed07daac68bf5f5c12769023bed48cf5d3cd2bd39cf9fcfaa7b0c8ca00fb30ec395d3b7c862758953f6b45e9ea99441fbd6c10e9c9d2b998c60391b74be683e87d0a19e8d25f2a87abda14db6d6f75a49ca8b5b3860d7e4f3969fa0ce8e4481bc996b69ca7682a7df93a6d205e66d781414d35745de3c873ecb1d8052269967fa77085bece20c060791381abd6793431515fc637ac3af30fa9d1bc80b7a058c792044df675e5f37d87c72ceca292bf104cdd32a905711ec1cbebeefcefe94110b7776b792136d3a38c8e63c375529afef6ee94da519f5424b17d0ce6b04ba844888e1fb2e59c15d35d61491c86a5af630390b7cc4b27b6773ae64b76a9a53c7dfd3cbdda6c42daeb2a26818bb372fd779ef2721c70e1fbb05343fe13d03bb7918ebeae24cb315d3c62e74242256436f553d7894e1094ee10dfb2608ec377062e83da400f605a7058d82eece0980ac2a5571eb7da72818e9089b7792b312faf36f50eae7cbef805f717c14db8780f42f545c9fc1ee8fb4e61bab8ac4136ff88dd4d1eb8963104737785e50b2ba04c27d81ae70ad7bcbc8588e011a0870d117ea263c8c61ed345ed2fd9591c8b6711eaafd9cae311fcf6692a1ad73cd007385d38ed69077fc8d46434ec8032bcfbaf0b25d7fe460b88c279c8fdb46e6188f3d3a9be6aab3cf294434aea050988a964f6d351c67c67112859a7759a3d04df39ed3806ff5535a8492ec9e0424728449d534b31ed0b83600e75dd8e7f7a307d211cecd20278e21435a85ab3000ee84248a28a8ffcff73620eeb2d5ef3e719171ae15f6fbbd7f8f60af207e3ce3f9dc6a002e0a360a984f7a4112cddc5e4caf9293eb86a19ebfeb754e0d85365ce752f68b0defef72701210713de39348b39ddf72e56688995c198af018a322af7a9e201c1061c76c65a569d74d422d3249553ac977f480c07dca947e3c61ab9b32be7a557b0073b3d4888536912abb12de8392e039d1cca968027f002323924ea9d3ff30261df105e07b2dd723b73d79e2e5c069a1fa26265d7793ab25d16073fafcecfe1b5e891d2d6e42ba5415eeaf6599ec8160e756f7a6aef3136d5068a6c2109cf1975c664cde11158c55afe468b3592255ac34798e89aa9a28e4057b7aa51d76f631c8564180940bb39e9c1617901362a6a0c9d8ef9416b29910f3139adfec7baad46399357a9755d4216dfb4eccf0a7e1b7041397b0b88910a78c4f32987744a4ca1de1c3bf050043a1d20ad1d46a0bf900c593d886f7802fcee9e83c0b2674c25ecac67f529eccb1739b553d61904e2dacb28ad8815c09eb58d2e991b1e9e11937750de12e068632eac76c06570ebbe7c9a5bcc11027b7e9e3d70691b8dec5c3be4e92b9f7ca96c7d7697005083f0a9048ef4c3713522238030d81da29ca57c5c9205ce4bf889ae84d80f24bffe573ea8e0ae6fa5e43d9f43efa0dd9b4c08942904e84e770898e77524e85af6facf8c56faef7dd434c013757656a97ac63bd86d8a8cc2ed20ddf1cd8a1fa57d043673a5d05b976170ab310ddcb08f1421c80e84b717c3d72595f551787e931fbee022061d62af3998be35730193e62ef735b40c99c7a7b1505941421bff3148242ee467115765f8b76240c728036334ca0a814957297d56d6116c3fcd0a48794976d0ba9b718f92975e295cc9539fa97388987fcdbc004f27724fdcacea1086261d1207a8e7216532b024320493523bac02690d1196a72101e5c6df1c4488760fd6b86eb729c6fdb8a5504c58179d5f8a615d623e5eb3a74a88eee46a3606e18a40c88aeb4719d39bf3d1e75d260251eb52dc2d1be62a0a466575cbda7ad02857be8580d444542333b9918ff0597da35c5844b9027ab9f1d680261887e99bbf580b1f3b0369b98a1dba1d9e15523e816ead6743c2d58eb038a7930971f09666670b10b7126af580a7079488f048a6d28937690681ea849cb657574b45cf9d1154be49d8756ff945dc2540f2a2e3811ca52000b18928669aeb1425ba0eddd475c7bd227a5cf6a3261138efe41009abf320f3f1ee7a9b3e8a3af8eb1276f66eb3d263fddf471f00f70ff5125d22682547a69cd12981bae21c1edbd91866c563afe5a2fd7dd1408db300da3f85d4be812919d73f28b6bd8ca2aaf54aadde591adb6bbb86956985a0d78a8af570517c5e5087354094318742ca135a1179cc1b131b224353d07504cf653baef575edb64c4c7d2498c67fa73cce4b9de72e6e9b5415c976a3cf91bdd3b7a453d57e8000b22c3891a23712cc519b5742dfc29cd7d197bee2857c2663a5c16017335fbcea56e931cb14b1e6c740f5d76472655041290a238428b42a35765e553fc22f821e7c748a97eb5fe0ce53cf4a0a425bdcd9a5d05a4d2a4d5b69547b41701e130e477d95b94c9c6157c677bfb30238f5d42ededf50b136c74e62b5cfe3431ac0b6ef9ef29bcd8e3b17c5b033f5effa0991a567bcab236ea07692fab4789123c98c9da5d766a51907ab35009864e1d14516207543550a06fd207dcf5c32731917c54cf496f4d99fac4ea29673536ef622aceb838ff30a2e22112f0aeda9550d01e60034a4188688fce5baed456672104af0e2915337ab8e801abe68c681890a5a56701d5459f10311c9d1343588243ec85b1a2e36bc1784113b30cf10d8c0165802f12243b598c463b506135df90b2b4dfd8028140ed9ee7ca91024478810bd52801c9c0edd1576e0e0a5d71b54b5390a8c08dfeeacfe6e19709bd8b070fbbe6c316d5c6bb0c143bb63cf75b8a6ae7281c4b8dd41bb6efe0928d6a01e508d3b1f28428f985768e7ee92a7b6eca7de79a8418421f83b0a71175f7635026c4ee6aaaf892b43c1617bd8fc38a25b8a844bf16e2a933487bd677bdef17481fb0b65a579e0adbe5a51ec4a8247f290de04c8157639a6b7ae1120516c21797939267934be21c8e0b70e2d50dd99e00c73c9a85e5a68eaf539b0e5adea5b5dfb4166e0ca7a5ab39a0667ef5e00537ef011a13b0eb3d22d26b11296130850bb9ea2f78b03bcfbc4f2fc5b0aba7d1c607e2fa591378b62594b445494c4f8ab7cbab36afcf1ab492bd84a8055fe31c18078b8685dcc9feb5699e214a31db62eaec5a76e2b3a85eda82e300231b2f9f6993a237e27de49c2f0c0d80e4bedfc8a0758f1bdcdc9153e492fd90c436c52350af1c238cf74ac4104791608709f077357e99abcfa17eedbaa35d66d4aa970dd55c646b0836e1823aa69332a807cf64efe55599a2cf3fc84a48ff8c4c9ee088ad85e2419a326b57c95b8f4e0ed1c92cd4c4561e4e12a56de7e59aef3b7fcf1d03036456b49d7e3dc957f2d7b38085b6801106312015d3094589f75df053a5901bf04a7b0be479c6a32a8d1a76b13bd891d863612524f925ffd243c33560bccf71838bf8c31882b5a269ef074c8be8880c5b1dce69ab997cd96814cee917bf4d30110ff543478b91cb9536f3f5ee88a8b4014df0138d5ca09009e475ec24e7116ef2c77a71e7b6b2171ba53e4685f9ef433a153d2e84317c8b0ace63f4515913768f03e97548eba49cec50ff994ce7d54cd00048a36dbdaac7c62bb802028873135223ec240eca358a2519efd9704415d7f1c09b4e669015f056a843a48772bafeaba385c84f451366f507f07cc92f3316d624b4b8da83af0335e4cfeed04e45f4e187280218e44dc79b72da99c9160f794c27e4f6beb7705b932a511689dbb35277065ea15929fb86a288232a3b76d034bfc1f5cf99bc36c1b276a2e9e50bd71f6f16aca27e90ae6993a53a3031901a10f7424147beb72861ee36221e55a26d007d73ced1c32b2fa0bf08a3a191d74937f162c7dca0865facd70fff80acb882af1b8143429322da57b4d1548ad624f99231bb0b91f7525546781f4768007400f6015ac317579df5f7d8f4b1526cad158e74a0e046183c5cadb3a86b4fb65822570e323bfc3ac9a794b9d3df956917b9b36741d145e876ae07cdaed661f4c4ac519f08a2baba9b0423b9e12304fa5050ad98f546bb1859441e5c58d50b0628fcf5284637ba46510f702a6f014df2824a5053dc515add82b1e210f4fd496a620892c2bca2f115ae9251258605fb2477c07100a6507dcb8c7b567e2ecdabe91fb8bf5b5092f60540adf003e22747a911fd16bb95f8ba3ac8442d897297cb79fcc5bde2e4abe5e413f60cecd25b6cb0e13fd2fd12bf48a6c19b74b0f0e3d7ceefe7d0afc89d0c482737f865091b465145db5e00a9f50be353ea0bfeda4a94971a219c4d7afa077f2a277baeae948308ff7b801913445786937f8da9e331e7512b4bf1c479d6f5a3f245d454c5e56542fd75de44e400c9dec558b2ce0aefbff150efc30dcbb7a4c1e29293380e1e170c21adfbf8c4be5aaf0b5bc9313d5bb9c453786435bec2a5899c6af86f9798f677151792d77f4a5b52b5bc9fb8d84ed35e457a92049cbf52843e96661ebb9de1f7bb83736c4501193e07124d51e5a2d298d5689f65c39d17c64c05a706173ac23ca82df032871e0603debba863919884a33de32536dffc0aee20a96d620ce047503b1e9d59f09f2f78f3d8058d974ccba6bc0218dd45367e38efc139698e9acab755a0f3ae94afab92069fbbde68ea4cb19aca12f79a3d53e8377550fcf22dcf68d61f1633959cb6709375d3ecfc6008d083e1c42cde4cae64a13d4fd1bd9fc207849f83395909a64cd85060dfcb78683800284f956b5582981efa91cc78ee7af423f832c5519ef44e45a52df4263ec8de318d8af4a34e4bfdb0b5f35626bc3a4093e485782ee56ef6d99dc5c73c36f93dcdec1862bb0cedcc5325fea4e1588985df72fbe51ea4c3e27f28de18b370edf57fa38291ceca945f7000d71ec05c9200b069fcd340cd0e7e2fda07c5fee03e6dad54cae3f542f7f3cd20ad9978fe7ffb7f917df7593a83c30a76d397a7b2a4a8f332fb3b73bd2c1d220086bb857b5fdd5667093edade87785a6b3d79134642fd280a2ef73a85bafca736ee9695370cead7ca98c9ea9501c21c708513c50886c7b2a7e05dbaae495c1f0677d39f307ebc80156355d92039a177a8de93bc27ad88c6d4292a78938c97fab1721c35b01d6714591a7478e88bbbda576ea9960e7b9e0b5d255e1e3c90be07ede595f81773ec278afc18c5c60e735b6fb35a842a37fc7042ce255bf245cf4cb03c87348a8a10538e0ac048e2040395f73611945d17f77f364f8b32fec70d79364acaffbf67f8727c4b7d218a81b52676941953855185bba392036f32cf20c835edec3b9a11e2baeee01f8863f30716cfb1cfb659183a6638dd6b68bfe85e969f6d66c9520ef7e81867e2447812c5a0e68401a846ebd85b3155ef8556a819b97e52f9d72d86c4793d5e19e4da3947cc391e3af0681fee5145e3879826abf32940be06626ff8da5ac94098379cb9a5d7f80ed4a65f7f272b07ff058cd7b1a7dbf1a9192563028e9992d7d468eff048d9fb2fabbc7c9a6aa75fe6eef9bbc3f009e39ebe6e0d23d36de5434421fad54c42ef5216f0ea6823ab92d0a042001307e3443842c310c48dd4614419c7da9fef28ea7835cfa322bc430fbcdebe7831f7a9d736de4bb4fcf85cd8cd5f48f8d40c8ca575616912670217470cf6c549fd71cb78cb088c58e15fea8b79a0dfc3e3cc519b396a09aa52f900173a84c89151f3ef0daa7f12b40fe70cfe85cd085c4bbed7243335dde4ef14615fa0965ad0870105ad6949c8cc804201acce2e02805160b3b1b0ca59f37998419d6cbb2d99992b0e917b30f8c8bb2ede9d877f03555c5b1e5cba6ab602e86ba4569be76fac304085ef22350d025293b0c0cea80eaa21130db9b942e38b38a9258ac79720dbadedfb47732e918ac29da90d19db6686d5bbe0bdef5b4cf441b593e5f46aa1268cd29a4370f0ba645139ba952003ec3c4e00c76d849c271f94233fcf2cbaca8e37bf13b45987bb81bf9c7845efca238baceebf81d5d0829cae32fcc4c40a1b87bc7ad3b8e279e75c4b1881d9b045072be6fa13c68bbb026cfa1f1a4b3878553a85a09b34ab806818b6c1d9d6c0038fc9623ca593ffdbad9ce963a807a18e4fa0d0437155331b98fb8395b5024e36da3eeb35a2d05374535d2c3e7987efd5468515c52ca78c7a65c90c2ea6b8d31e9771c1c40cc1a35475a7e7ccdc3d5218d319f5bd5f0139733cbd6daeec581115829671a290f55b8e5e4ba4c6d6b6420560650640665a6e8f1b29c56acf361d28a64ab0d05f0e37e96dd8d3874fb4e3e24846aad3a19f89a33e1fd4c0c32564d92aa8d9907311ca6a4e680049e36ad8251b4537186cc1d7821ac6763c3daf58c74afc97e082e3da51f0a20655d084bbd8a991b4f8685c2f0c8e701946a0bf55f533464bce70e0eaf79afb3502817aeb222095bf085db613878c25bb05e8fc15b960eb16cb48c32d81691dc7c9f12c6582551cf1437a9a02441a0a0a741eea732b972b74173f483af37afc39d0a512ae8e792100bfc369b212ced65092a1e74ca693e2f25a521b7913b46eed99162bd30322690abeaeb7d1890e779ba08d2a105d2be720293d138c3f2eef03f00fa66c9c27b3851446a233d1f0a287ac7153505eb0988f855ccb134ad923144251dc23185d6aa1c568d2aa04fcd71019dec3dc7eba802551eeef341f5e65d5e15b8ac36906dd5562880e897ce6f14b5260965fd9b9fc2a47c669153059ca1a6172b473c8b3eba4ecaf87b41e287d6818c78f38d8dfb7007e3323d379f2932749484ffad89efcca437a4d7a6adf2d7e9e47b1d96b0d87bcf16eecab2e07f64ae2c09674b809d913b5bf21bcc534992ca6f2ee71ecd27470ad7c0f1a3246257a7920e4bb453469ff71f8527ee89922af5cd2076dead8d08e791468d7a69f0be69d30a69f3cfc4a807cea15e6cd127b3908a31981261dff3d487376860845b493035659e42f14871bffed25f424138606d2506f2a4cece42c2bf997c563b243657198dfa96415a04caf2334e89d07e72e1944b86e49f8e5cbdccd2ec1d4a48f6337d22a6d2bc0e51deb1ccaba5291fe524dcdbbb1ba8bf1f91f03c3f5a034a04a33e185c2263ff2f038af7f9c72c9b319951daec805c4bdfe23bc9e191a9dbc458c67a3b89f5442a7c233b5dfaea24b34ccc066fdc6e23ad90c3010e5afccc1ec5b713b9acff83ad85b252325366ab8e42b207192c82582613e9f1508e0593826ac1f988c93913253cad381b95ad924eb42f473e64b6306ef1e3c2736b96885f2e553dea2d7d994eb910c01de792ad0b3aaee2e8286bb8f0d258ce025fd5e53fdf08170781d8f8f79562a94553ea563b3e945e952c8de6e75cdacd9673d41436c3d02a1243b1b648ececfe8f2c5ef38228c3b306c3682cf75c2701502b3875f7cd3e456ca5ea08148af83fd95a932c74f878c27b9a20a5d9f9331dccef2d74b781dde7b195972875f233db34ba095c805f14fa9c9bcf370d840cd55dd1b6ee0a8ffd533d0a93aca45493c0dc1fd0eb4cb6c764db9b2667854a9c4af3f872a7c0616694b922e5aa8cd20ed993826c6101e98271ec21c516b67c23cf5d89027aed53c964016fc42d1fc90ed11f715a6242f792417929ae6eb0a79a7720b0c50a4a7db27f330d5bf3bb0257b10a4fd4baa55fc423786d508f3afdabf147b786e729d5807000205329b3177fe6cb0161189561e468a8db69d60f06ee08ba761fbc7ba00f8294b9b7b6d19b2bd44f04546729f2bf04a84be20a9378b188da26c830a384a1615c2f3cf0ab6c108e054012bf49c0ce76762a7c209edfeb7afa924ec0d7b87d8a081a59106166c22005f363ad02a6122ef053cd49b916763180b7409843bf5e2a6d3b677b1821973c32a83f6541b313060d726584efa9e658151d722e1d88f4b9107c1ff2bf1cb13a6e88272785a43f8a41997f82bbf1dea0456d86ba9656f51a978a9b3af01abc1565da35768228f98c5c9d8dce4ac8bafa442bd4a302dfc1f7f5bfa10007eb597b92983d64b588d57e2616d9a0256c35a169bd139d398ef7ee8f972d145fb5f0f4dd2bb3b73bacd6c9fed71b200cd167f6853d4fd8fdca08c0682c40b9de5adf9a40f77c8942ed6731f89488ad8e5e6f73b9be49e3cca644b45f033483c87320cb60bdcb173096090d05694a5ac6ef11a363fc51680dc2bc840b89feedc162883e4156eb0127a4cb8725c6bb3093fea249f8ed1af3d781ac99f293346bbd5c9c0246e91060d68a0c7d0e99da65ab13e6bf104c6159c685c37b8699d70535c37b6c587dd2134503d32756b0befcf90b3563021e2c4fcfc24d5ca4e3308cc0aa4d03bcfcd7542f7a0fb488e6290069efe33cd7115157bc4e7637d4094fcc6cc0a64277cc3d27a02f9756057157e98a5ba51031f3f08d79aa75d95aa0dde927e0e4ebd7a5223621d723dbae52452165c9f325a0e735d2fe578813b7afc14fa648540a710660fc7688199521d2db01866872bddd013000a5ffbe3aa9f752d23f4ad62bbaf940f80fbd1fdf3c922dd992bb7f5ffc90d8e2c1ec2895b683366ba1b558e51e5f6472d015cfb6ccecd2a2cdd1431157363c75ad56f35d23f3cb8703ff5bf91be4b7c4152f48d8a394f3937f6f75859de9cabaadcd3eb9eda46f6988871b6998323e0acad6c1b621471131fd7fc4b4c25e3658845cde972e9191b6517db83701279fd8c3847897862a6ba357b3bf9927bd66202195614dd1f87af8110cbf34beb5749080b1fdc4e9903cc898aec3994e2822bb0c5ad43f913316eb118cfb680756a4528a920f44e650eff3f86473c02d31ec76791cf2a807f3f5cbe0c9ded885ac9ff83a9574b9de442059f67fb45034ddd2cd18c8548bb9f672071f6043be7378ff0e5ed660709e20f504eb0c83a3b37cbf59ea75c56bae5614d15dc1a61571612319162ba64192542151ecba65f2be4f5539c88342a293ebd7ee5730bb31895fd91bd8e2dc17bfb199dbee31471a1f82020ed2f78d0421bed643d3f22ddbb0cae809f5a9a70f55ae4f141166cef37be3c6fdd57d0747ee23798b0b9b030fdb1f18f79d1110441c5383fe3c3e148ed6a0f59a5730400052cc1a38836a90cf0238ea1fe684d03467eb00c9b3f0663fa9a2ce9957e17d721720c12d2a98ab132c68dc77da90f775fb48a61cf68b3b73cf462aa419842b594dc061b9d4e40f8beb146cde238ce8843fe39ebb64240073706021304296d8f4ed9032d5a0e4578515b4c4ef6989de458cca4043580ca1be7f4e8c012d6d3687490fd2d50448a77f561a73709acf9aad7066d724617b8ef3bebf77fbdacb1f6487876f23a42ac33cea6877a058dc6a040a9fe8b98a94b62ef77ca43a7b1fe8704b4d3b9cb018e889e14926f4eb1745ffa41664a0d4c32846c5c6534d2ee53b866bfb1a6ae583b179adb9dc4c8d489dc352de1739c1ec375827610ab6820c07c2f16368868613874c3fb5007668a3f916c6186176c5b71b5b670bb7fe4cf814cc8e31ec0f2d242f5988b30519b9bd70c1289fd3afc1962f84ea8552cce321525fbfef3c5132b9e7754286ee4d8924cd8e51f260ca065b99e9df0925244048f764c9b235442594fd734539bbce1565ed322146af524680439c592d2e64fbd39b1de87312d928cffa3b1a58d01638d9cd1f298438cf32332d2c1465e7fa26f9c691bef9c7c8519f972ab4ce6985c4e37772e2be1fffe9c59411c427129ea909ebac8efbadf042e91197d08cfc3906323c5922b2e5aa964bfa7c775a7d93ce26038445451d9380c26040787ca5925c24364b2cc4e9d824bf75c2fe43f2e134cd98c7e9ce44639a267128a2660c0c408436b2b674351b2203cb3e54df727bb96478cae8c1f81f8c57cdbdadca2901ac17f98fe50ae645703865f3cc706dae659c3058af61e0b7e12408791030de5028ee7c86a0962cb98956d6d7748412e5022580cbdf9332430f93fb51590e4ae1ec77403d6925e2d4dfca435ab2c4354b5e23578fc2c767dd54bd63032ce1c0ffa6374a482ac76f1a8929411698f4b8c3f37df0bdc931fe02489945f715f244ed17982f55baaa881b3e494f6e393ce7d4ae1522d7c89efffdbc302db43090a196cd350023f42f3cdaec1e714508f9f99cb8dacac2f31146618a4653222ee96cc8a1826fa30abaadbd369c57189efc55aa346f1a72108b1827c59d6207fc5616782afd9ede0379d6cbf2be90b784dff27479f0f2ce9c719202955a48f89fe10cf9b75318edc3d5b2ce62250a31f3911c3ea9c4cfc17e700d4cc8fbd77aa402f1df357ab96b8d84ce51162617f6e8f72dd911dea0db056383d28fd9ec529ab3c87108b2aaaee2676e30dadbb114579bed3aed73a82b80bab2fb4801ca7fdf527fd469f9ff30896fcff773f6a9f7c10ad27d91998a6d47f0fb6e2da0156d56545842e75b331ca134127d2e038a0fe8515e45a9a72e20a3cc7599bb6cf067093b5aeb6fb3a9b127b71b1a00501c8720a8af5df40504a8016ea76e49e9e2692c8039ad0c2b579be9e7765c58f4341f035a0bfac006f2e09e26509439ce1e2ff766f8dc3689b5db</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-xray"> <input class="hbe hbe-input-field hbe-input-field-xray" id="hbePass" type="password"/> <label class="hbe hbe-input-label hbe-input-label-xray" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-xray">您好, 这里需要密码.</span> </label> <svg class="hbe hbe-graphic hbe-graphic-xray" height="100%" preserveaspectratio="none" viewbox="0 0 1200 60" width="300%"> <path d="M0,56.5c0,0,298.666,0,399.333,0C448.336,56.5,513.994,46,597,46c77.327,0,135,10.5,200.999,10.5c95.996,0,402.001,0,402.001,0"></path> <path d="M0,2.5c0,0,298.666,0,399.333,0C448.336,2.5,513.994,13,597,13c77.327,0,135-10.5,200.999-10.5c95.996,0,402.001,0,402.001,0"></path> </svg> </div> </div></div><script data-pjax="" src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css"/></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="记一次仅在 IPv4 环境下访问 IPv6 网络的经历" href="https://blog.mhuig.top/p/5e9edb45/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">记一次仅在 IPv4 环境下访问 IPv6 网络的经历</span><span class="cap link fs12">https://blog.mhuig.top/p/5e9edb45/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>神秘数字 4.669</title>
    <link href="https://blog.imc.re/RSSBOX/rss/c8c741f1.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/c8c741f1.html</id>
    <published>2021-02-09T17:50:47.000Z</published>
    <updated>2021-02-09T17:50:47.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><div class="note success"><p>从无序迈向有序</p></div><p><img><img alt="Mandelbrot set" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651971306281/1612922136.webp" src="https://unpkg.com/mhgoos@0.0.1651971306281/1612922136.webp"/></img></p><p><img><img alt="分叉图" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651971425538/1612922294.webp" src="https://unpkg.com/mhgoos@0.0.1651971425538/1612922294.webp"/></img></p><p><img><img alt="4.669" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651971691410/1612922328.webp" src="https://unpkg.com/mhgoos@0.0.1651971691410/1612922328.webp"/></img></p><!-- <div class="tag-plugin image"><div class="image-bg"><img src="https://cdn.jsdelivr.net/npm/imbox@0.0.3/data/1612922136000.gif" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://cdn.jsdelivr.net/npm/imbox@0.0.3/data/1612922294000.gif" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://cdn.jsdelivr.net/npm/imbox@0.0.3/data/1612922328000.gif" fancybox="true"/></div></div> --></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="神秘数字 4.669" href="https://blog.mhuig.top/p/373468cd/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">神秘数字 4.669</span><span class="cap link fs12">https://blog.mhuig.top/p/373468cd/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>大数据架构演变</title>
    <link href="https://blog.imc.re/RSSBOX/rss/7e3480e9.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/7e3480e9.html</id>
    <published>2021-02-07T04:51:06.000Z</published>
    <updated>2021-02-07T04:51:06.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p>在 Hadoop 系列框架还没出现之前，数据分析工作已经经历漫长的发展，其中以 BI 系统为主的数据分析，已经有非常成熟和稳定的技术解决方案和生态系统，BI 系统的架构图如下：</p><p><img><img alt="BI系统的架构图" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972047400/202127201010.webp" src="https://unpkg.com/mhgoos@0.0.1651972047400/202127201010.webp"/></img></p><p>BI 又叫商业智能，其包括与传统业务系统的区别在于：业务系统更注重于事务型的数据处理，用来支撑企业的各业务线；而 BI 是将企业中所有数据汇聚成数据仓库（DW）并对其进行分析型操作，其中 Cube 是 BI 的核心模块。Cube 是一额更高层的业务抽象模型，在 Cube 上可以进行上钻、下钻、切片等操作、</p><p><img><img alt="事务型的数据" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972107237/202127201323.webp" src="https://unpkg.com/mhgoos@0.0.1651972107237/202127201323.webp"/></img></p><p><img><img alt="Cube" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972186902/202127201416.webp" src="https://unpkg.com/mhgoos@0.0.1651972186902/202127201416.webp"/></img></p><p>BI 系统都是基于关系型数据库，关系型数据库使用 SQL 语句进行操作，但是 SQL 在多维操作相对较弱，所以 Cube 有自己独有的查询语言多维查询语言 —— MDX</p><p>大多数的数据库服务厂商都提供 BI 服务，轻易便可搭建出一套 OLAP 分析系统</p><p>OLTP 联机事务处理，表现为企业中的应用系统如 OA、CRM、ERP、财务软件等供各部门使用</p><p>OLAP 联机分析处理，也叫决策支持系统 DSS，通常进行使用者是企业高管或部门管理者</p><p>但是随着互联网发展，BI 系统也暴露除了一些缺点:</p><ul><li><p>BI 系统多以分析业务数据产生结构化数据为主，对于非结构化和半结构化数据处理乏力。例如图片、文本、音频的存储、分析。</p></li><li><p>随着异构数据源增加，要解析数据内容进入数据仓库，则需要非常复杂的 ETL 程序，从而导致 ETL 变得过于庞大和容易出错，需要大量人力进行维护</p></li><li><p>随着数据的增长，性能会成为瓶颈，在 TB/PB 级别的数据处理上表现的尤为乏力</p></li><li><p>数据仓库的原始数据都是只读的用来分析，不存实务操作者导致传统的范式约束大大影响了性能</p></li></ul><p>由于 BI 的一系列问题，在以 Hadoop 生态圈的大数据分析平台逐渐表现出其优异性，围绕 Hadoop 体系的生态圈也不断变大，对于 Hadoop 系统来说，从根本上解决了传统数据仓库瓶颈的问题</p><p>随着大数据平台的不断发展，现在主要对数据的处理时效进行区分为</p><ul><li><p>针对于 T+1 数据的离线处理架构，其主要应用框架由 Hadoop、Hive、Sqoop 等组成</p></li><li><p>针对实时数据的流式处理架构，其主要由 Spark、Flink、Flume、Kafka 等组成</p></li></ul><div class="story post-story"><h2 id="Lambda架构"><a class="headerlink" href="#Lambda架构" title="Lambda架构"></a><strong>Lambda 架构</strong></h2><div class="note quote"><p><strong>“我们正在从 IT 时代走向 DT 时代 (数据时代)。IT 和 DT 之间，不仅仅是技术的变革，更是思想意识的变革，IT 主要是为自我服务，用来更好地自我控制和管理，DT 则是激活生产力，让别人活得比你好”<br/> </strong></p><div style="float:right"><strong> —— 阿里巴巴董事局主席马云。</strong></div><strong><br/></strong><p></p></div><p><strong>Hadoop 作为解决对大数据量低成本规模化的处理的解决方案被广泛应用</strong></p><p><strong>但是 MapReduce 或者 Hive 很难做到低延迟，用 Storm 开发的实时流处理技术可以帮助解决延迟性的问题，但它并不完美</strong></p><ul><li><p><strong>Storm 不支持 exactly-once 语义，因此不能保证状态数据的正确性</strong></p></li><li><p><strong>Storm 不支持基于事件时间的处理</strong></p></li></ul><p><strong>后来出现了一种混合分析的方法，它将上述两个方案结合起来，既保证低延迟，又保障正确性 ——Lambda</strong></p><p><strong>Lambda 架构是由 Storm 的作者 Nathan Marz 提出的一个实时大数据处理框架</strong></p><p><strong>Marz 在 Twitter 工作期间开发了著名的实时大数据处理框架 Storm，Lambda 架构是其根据多年进行分布式大数据系统的经验总结提炼而成</strong></p><p><img><img alt="Nathan Marz" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972252289/20212720259.webp" src="https://unpkg.com/mhgoos@0.0.1651972252289/20212720259.webp"/></img></p><p><strong>Lambda 的目标</strong>:</p><ul><li><strong>高容错、低延时、可扩展</strong></li></ul><p><strong>Lambda 特性</strong></p><ul><li><p><strong>整合离线计算和实时计算</strong></p></li><li><p><strong>读写分离和复杂性隔离</strong></p></li><li><p><strong>可集成 Hadoop，Kafka，Storm，Spark，HBase 等</strong></p></li></ul><p><img><img alt="Lambda" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972527103/202127202651.webp" src="https://unpkg.com/mhgoos@0.0.1651972527103/202127202651.webp"/></img></p><p><img><img alt="Lambda" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972552533/202127202812.webp" src="https://unpkg.com/mhgoos@0.0.1651972552533/202127202812.webp"/></img></p><p><img><img alt="Lambda" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972582886/202127202918.webp" src="https://unpkg.com/mhgoos@0.0.1651972582886/202127202918.webp"/></img></p><p><strong>Marz 认为大数据系统应具有以下的关键特性（Lambda 架构的关键特性）：</strong></p><ul><li><p><strong>Robust and fault-tolerant（容错性和鲁棒性）：让系统从错误中快速恢复</strong></p></li><li><p><strong>Low latency reads and updates（低延时）：响应是低延时</strong></p></li><li><p><strong>Scalable（横向扩容）：通过增加机器的个数来提高系统的性能</strong></p></li><li><p><strong>General（通用性）：支持多领域的数据分析（金融、社交、电子商务等）</strong></p></li><li><p><strong>Extensible（可扩展）：以最小的开发代价来增加新功能</strong></p></li><li><p><strong>Allows ad hoc queries（方便查询）：即时查询，快速简便的进行查询</strong></p></li><li><p><strong>Debuggable（易调试）：快速定位错误</strong></p></li></ul><p><strong>Lambda 架构通过分解的三层架构来解决问题</strong></p><ul><li><p><strong>Batch Layer</strong></p></li><li><p><strong>Speed Layer</strong></p></li><li><p><strong>Serving Layer</strong></p></li></ul><h3 id="Batch-Layer"><a class="headerlink" href="#Batch-Layer" title="Batch Layer"></a><strong>Batch Layer</strong></h3><p><strong>理想状态下，任何数据查询都可以从表达式 Query= function (all data) 获得，但是若数据达到相当大的一个级别（例如 PB），且还需要支持实时查询时，就需要耗费非常庞大的资源</strong></p><p><strong>可以将数据提前进行计算处理成为 Batch View，这样当需要执行查询时，可以从 Batch View 中读取结果。这样一个预先运算好的 View 是可以建立索引的，因而可以支持随机读取</strong></p><p><strong>Batch Layer 总结为：</strong></p><ul><li><p><strong>Batch View = function(all data)</strong></p></li><li><p><strong>Query = function(BatchView)</strong></p></li></ul><h3 id="Speed-Layer"><a class="headerlink" href="#Speed-Layer" title="Speed Layer"></a><strong>Speed Layer</strong></h3><p><strong>Batch Layer 的离线处理可以很好的满足大多数应用场景，但有很多场景的数据是不断实时生成，并且需要实时查询处理。Speed Layer 正是用来处理增量的实时数据并生成 Realtime View</strong></p><p><strong>Speed Layer 处理的数据是最近的增量数据流，Batch Layer 处理的是全体数据集</strong></p><p><strong>Speed Layer 为了效率，接收到新数据时不断更新 Realtime View，而 Batch Layer 根据全体离线数据集直接得到 Batch View</strong></p><p><strong>Speed Layer 是一种增量计算，所以延迟小</strong></p><p><strong>Speed Layer 总结为：</strong></p><ul><li><strong>RealtimeView＝function(RealtimeView，new data)</strong></li></ul><p><strong>Batch Layer 和 Speed Layer 优点：</strong></p><ul><li><p><strong>容错性：Speed Layer 中处理的数据也不断写入 Batch Layer，当 Batch Layer 中重新计算的数据集包含 Speed Layer 处理的数据集后，当前的 Realtime View 就可以丢弃，这也就意味着 Speed Layer 处理中引入的错误，在 Batch Layer 重新计算时都可以得到修正。这点也可以看成是 CAP 理论中的最终一致性（Eventual Consistency）的体现</strong></p></li><li><p><strong>复杂性隔离：Batch Layer 处理的是离线数据，可以很好的掌控。Speed Layer 采用增量算法处理实时数据，复杂性比 Batch Layer 要高很多。通过分开 Batch Layer 和 Speed Layer，把复杂性隔离到 Speed Layer，可以很好的提高整个系统的鲁棒性和可靠性</strong></p></li><li><p><strong>Query = function( Batch View , Realtime View )</strong></p></li><li><p><strong>Realtime View = function( Realtime View , new data )</strong></p></li><li><p><strong>Batch View = function( all data )</strong></p></li></ul><h3 id="Serving-Layer"><a class="headerlink" href="#Serving-Layer" title="Serving Layer"></a><strong>Serving Layer</strong></h3><p><strong>用于响应用户的查询请求，合并 Batch View 和 Realtime View 中的结果数据集到最终的数据集</strong></p></div><div class="story post-story"><h2 id="Kappa架构"><a class="headerlink" href="#Kappa架构" title="Kappa架构"></a><strong>Kappa 架构</strong></h2><p><strong>Lambda 架构有时会出现批量数据和实时数据结果对不上的问题</strong></p><p><strong>LinkedIn 的 Jay Kreps 提出了一个新的架构：KAPPA</strong></p><p><strong>它的理念是：鉴于大家认为批量数据和实时数据对不上是个问题，它直接去掉了批量数据；而直接通过队列（Kafka），放入实时数据之中。</strong></p><p><strong>例如：将所有的数据直接放到原来的 Kafka 中，然后通过 Kafka 的 Streaming，去直接面向查询</strong></p><p><strong>该架构也存在着一些问题：</strong></p><ul><li><p><strong>不能及时查询和训练。例如：我们的分析师想通过一条 SQL 语句，来查询前五秒的状态数据。这对于 KAPPA 架构是很难去实现的</strong></p></li><li><p><strong>面对各种需求，它同样也逃不过每次需要重新做一次 Data Streaming。也就是说，它无法实现 Ad—hoc 查询，我们必需针对某个需求事先准备好，才能进行数据分析</strong></p></li><li><p><strong>新数据源的结构问题。例如：要新增一台智能硬件设备，我们就要重新开发一遍它对应的适配格式、负责采集的 SDK、以及 SDK 的接收端等，即整体都要重复开发一遍</strong></p></li></ul><p><img><img alt="Kappa架构" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972629700/202127204249.webp" src="https://unpkg.com/mhgoos@0.0.1651972629700/202127204249.webp"/></img></p></div><div class="story post-story"><h2 id="IOTA架构"><a class="headerlink" href="#IOTA架构" title="IOTA架构"></a><strong>IOTA 架构</strong></h2><h3 id="IOTA架构整体思路"><a class="headerlink" href="#IOTA架构整体思路" title="IOTA架构整体思路"></a><strong>IOTA 架构整体思路</strong></h3><p><strong>设定标准数据模型，通过边缘计算技术把所有的计算过程分散在数据产生、计算和查询过程当中，以统一的数据模型贯穿始终，从而提高整体的预算效率，同时满足即时计算的需要，可以使用各种 Ad-hoc Query 来查询底层数据</strong></p><ul><li><strong>Common Data Model（核心）：从数据收集到数据存储和处理使用统一的数据模型</strong></li></ul><p>​       <strong>“主 - 谓 - 宾”、“对象 - 事件”、“产品 - 事件”、“地点 - 时间” 模型等等</strong></p><p>​        <strong>例，“X 用户 – 事件 1 – A 页面（2018/4/11 20:00）</strong></p><ul><li><p><strong>SDKs：数据的采集端，不仅仅是过去的简单的 SDK，在复杂的计算情况下，会赋予 SDK 更复杂的计算，在设备端就转化为形成统一的数据模型来进行传送</strong></p></li><li><p><strong>Real Time Data：实时数据缓存区，这部分是为了达到实时计算的目的，海量数据接收不可能海量实时入历史数据库，那样会出现建立索引延迟、历史数据碎片文件等问题。因此，有一个实时数据缓存区来存储最近几分钟或者几秒钟的数据。这块可以使用 Kudu 或者 Hbase 等组件来实现。这部分数据会通过 Dumper 来合并到历史数据当中。此处的数据模型和 SDK 端数据模型是保持一致的，都是 Common Data Model，例如 “主 - 谓 - 宾” 模型</strong></p></li><li><p><strong>Historical Data：历史数据沉浸区，这部分是保存了大量的历史数据，为了实现 Ad-hoc 查询，将自动建立相关索引提高整体历史数据查询效率，从而实现秒级复杂查询百亿条数据的反馈。例如可以使用 HDFS 存储历史数据，此处的数据模型依然 SDK 端数据模型是保持一致的 Common Data Model</strong></p></li><li><p><strong>Dumper：Dumper 的主要工作就是把最近几秒或者几分钟的实时数据，根据汇聚规则、建立索引，存储到历史存储结构当中，可以使用 map reduce、C、Scala 来撰写，把相关的数据从 Realtime Data 区写入 Historical Data 区</strong></p></li><li><p><strong>Query Engine：查询引擎，提供统一的对外查询接口和协议（例如 SQL JDBC），把 Realtime Data 和 Historical Data 合并到一起查询，从而实现对于数据实时的 Ad-hoc 查询。例如常见的计算引擎可以使用 presto、impala、clickhouse 等</strong></p></li><li><p><strong>Realtime model feedback：通过 Edge computing 技术，在边缘端有更多的交互可以做，可以通过在 Realtime Data 去设定规则来对 Edge SDK 端进行控制</strong></p></li></ul><p><img><img alt="IOTA架构" class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651972675436/202127204646.webp" src="https://unpkg.com/mhgoos@0.0.1651972675436/202127204646.webp"/></img></p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="大数据架构演变" href="https://blog.mhuig.top/p/7e3480e9/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">大数据架构演变</span><span class="cap link fs12">https://blog.mhuig.top/p/7e3480e9/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>离散世界与连续世界的联系</title>
    <link href="https://blog.imc.re/RSSBOX/rss/473bb82a.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/473bb82a.html</id>
    <published>2021-01-02T04:34:44.000Z</published>
    <updated>2021-01-02T04:34:44.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><div class="story post-story"><h2 id="探索"><a class="headerlink" href="#探索" title="探索"></a>探索</h2><p>当年，哥德巴赫异想天开就想离散的世界的阶乘<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.645ex" role="img" style="vertical-align: -0.025ex;" viewbox="0 -716 878 727" width="1.986ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(600,0)"><path d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z" data-c="21"></path></g></g></g></svg></mjx-container>能不能用连续世界的积分<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.514ex" role="img" style="vertical-align: -0.691ex;" viewbox="0 -805.5 610 1111" width="1.38ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g></g></g></svg></mjx-container>来表达。</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 17.61ex;" width="full"><svg focusable="false" height="5.027ex" role="img" style="vertical-align: -1.948ex; min-width: 17.61ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1361)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1361) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="1813.8 -1361 1 2222"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(600,0)"><path d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z" data-c="21"></path></g><g data-mml-node="mo" transform="translate(1155.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mo" transform="translate(2211.6,0) translate(0 1)"><path d="M114 -798Q132 -824 165 -824H167Q195 -824 223 -764T275 -600T320 -391T362 -164Q365 -143 367 -133Q439 292 523 655T645 1127Q651 1145 655 1157T672 1201T699 1257T733 1306T777 1346T828 1360Q884 1360 912 1325T944 1245Q944 1220 932 1205T909 1186T887 1183Q866 1183 849 1198T832 1239Q832 1287 885 1296L882 1300Q879 1303 874 1307T866 1313Q851 1323 833 1323Q819 1323 807 1311T775 1255T736 1139T689 936T633 628Q574 293 510 -5T410 -437T355 -629Q278 -862 165 -862Q125 -862 92 -831T55 -746Q55 -711 74 -698T112 -685Q133 -685 150 -700T167 -741Q167 -789 114 -798Z" data-c="222B"></path></g><g data-mml-node="mo" transform="translate(3155.6,0)"><path d="M226 668Q190 668 162 656T124 632L114 621Q116 621 119 620T130 616T145 607T157 591T162 567Q162 544 147 529T109 514T71 528T55 566Q55 625 100 661T199 704Q201 704 210 704T224 705H228Q281 705 320 692T378 656T407 612T416 567Q416 503 361 462Q267 395 247 303Q242 279 242 241V224Q242 205 239 202T222 198T205 201T202 218V249Q204 320 220 371T255 445T292 491T315 537Q317 546 317 574V587Q317 604 315 615T304 640T277 661T226 668ZM162 61Q162 89 180 105T224 121Q247 119 264 104T281 61Q281 31 264 16T222 1Q197 1 180 16T162 61Z" data-c="3F"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1361 1 2222"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:1"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>哥德巴赫有个好朋友叫伯努利，伯努利有个学生叫欧拉。<psw>欧拉有个学生叫拉格朗日，拉格朗日有个学生叫柯西</psw></p><p>哥德巴赫与伯努利交流，问伯努利：有没有离散世界和连续世界可以相等的呢？</p><p>伯努利想不明白，就问他的学生欧拉，然后欧拉一晚上想出来了。<psw>故事结束</psw></p></div><div class="story post-story"><h2 id="伽玛函数"><a class="headerlink" href="#伽玛函数" title="伽玛函数"></a>伽玛函数</h2><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 46.179ex;" width="full"><svg focusable="false" height="5.457ex" role="img" style="vertical-align: -2.163ex; min-width: 46.179ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1456.1)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1456.1) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="8127.6 -1456.1 1 2412.2"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-44.2)"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(1014,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(1654,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2320.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msubsup" transform="translate(3376.6,0)"><g data-mml-node="mo" transform="translate(0 1)"><path d="M114 -798Q132 -824 165 -824H167Q195 -824 223 -764T275 -600T320 -391T362 -164Q365 -143 367 -133Q439 292 523 655T645 1127Q651 1145 655 1157T672 1201T699 1257T733 1306T777 1346T828 1360Q884 1360 912 1325T944 1245Q944 1220 932 1205T909 1186T887 1183Q866 1183 849 1198T832 1239Q832 1287 885 1296L882 1300Q879 1303 874 1307T866 1313Q851 1323 833 1323Q819 1323 807 1311T775 1255T736 1139T689 936T633 628Q574 293 510 -5T410 -437T355 -629Q278 -862 165 -862Q125 -862 92 -831T55 -746Q55 -711 74 -698T112 -685Q133 -685 150 -700T167 -741Q167 -789 114 -798Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1046.4,1088.1) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(589,-896.4) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(5896.9,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,413) scale(0.707)"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(640,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mn" transform="translate(1418,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="msup" transform="translate(7908.1,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,413) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mi" transform="translate(9411.7,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(9931.7,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mtext" transform="translate(10503.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(10753.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11003.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11253.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11503.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11753.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12003.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12253.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12503.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12753.7,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mo" transform="translate(13003.7,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(13392.7,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(14310.5,0)"><path d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" data-c="3E"></path></g><g data-mml-node="mn" transform="translate(15366.2,0)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g><g data-mml-node="mo" transform="translate(15866.2,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1456.1 1 2412.2"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:2" transform="translate(0,705.8)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>换元，令<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.072ex" role="img" style="vertical-align: -0.186ex;" viewbox="0 -833.9 2703.1 915.9" width="6.116ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mo" transform="translate(849.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msup" transform="translate(1905.6,0)"><g data-mml-node="mi"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mn" transform="translate(394,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g></g></g></svg></mjx-container> 则</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 47.74ex;" width="full"><svg focusable="false" height="5.457ex" role="img" style="vertical-align: -2.163ex; min-width: 47.74ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1456.1)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1456.1) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="8472.5 -1456.1 1 2412.2"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-44.2)"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(1014,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(1654,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2320.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(3376.6,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="msubsup" transform="translate(4043.2,0)"><g data-mml-node="mo" transform="translate(0 1)"><path d="M114 -798Q132 -824 165 -824H167Q195 -824 223 -764T275 -600T320 -391T362 -164Q365 -143 367 -133Q439 292 523 655T645 1127Q651 1145 655 1157T672 1201T699 1257T733 1306T777 1346T828 1360Q884 1360 912 1325T944 1245Q944 1220 932 1205T909 1186T887 1183Q866 1183 849 1198T832 1239Q832 1287 885 1296L882 1300Q879 1303 874 1307T866 1313Q851 1323 833 1323Q819 1323 807 1311T775 1255T736 1139T689 936T633 628Q574 293 510 -5T410 -437T355 -629Q278 -862 165 -862Q125 -862 92 -831T55 -746Q55 -711 74 -698T112 -685Q133 -685 150 -700T167 -741Q167 -789 114 -798Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1046.4,1088.1) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(589,-896.4) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(6563.5,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,413) scale(0.707)"><g data-mml-node="mn"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(500,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(1140,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mn" transform="translate(1918,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="msup" transform="translate(8928.3,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,413) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="msup" transform="translate(778,0)"><g data-mml-node="mi"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mn" transform="translate(394,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g></g></g><g data-mml-node="mi" transform="translate(10591.4,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(11111.4,0)"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mtext" transform="translate(11472.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11722.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(11972.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12222.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12472.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12722.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(12972.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(13222.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(13472.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mtext" transform="translate(13722.4,0)"><path d="" data-c="A0"></path></g><g data-mml-node="mo" transform="translate(13972.4,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(14361.4,0)"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mo" transform="translate(15000.2,0)"><path d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" data-c="3E"></path></g><g data-mml-node="mn" transform="translate(16055.9,0)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g><g data-mml-node="mo" transform="translate(16555.9,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1456.1 1 2412.2"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:3" transform="translate(0,705.8)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p></div><div class="story post-story"><h2 id="推导"><a class="headerlink" href="#推导" title="推导"></a>推导</h2><p>建立递推式</p><p>由于<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.944ex" role="img" style="vertical-align: -0.806ex;" viewbox="0 -944.8 19170.4 1301.2" width="43.372ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(1014,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(1876.2,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(2876.4,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(3376.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4043.2,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msubsup" transform="translate(5099,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(7272.8,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,363) scale(0.707)"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g></g></g><g data-mml-node="msup" transform="translate(8380.4,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mi" transform="translate(9883.9,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(10403.9,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mo" transform="translate(11253.7,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msubsup" transform="translate(12309.5,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(14483.3,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,363) scale(0.707)"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g></g></g><g data-mml-node="mi" transform="translate(15590.9,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mo" transform="translate(16110.9,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mo" transform="translate(16499.9,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="msup" transform="translate(17277.9,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mo" transform="translate(18781.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.944ex" role="img" style="vertical-align: -0.806ex;" viewbox="0 -944.8 14066.2 1301.2" width="31.824ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mo" transform="translate(1055.8,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="msup" transform="translate(1833.8,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mi" transform="translate(605,363) scale(0.707)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g></g><g data-mml-node="msup" transform="translate(2941.3,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="msubsup" transform="translate(4444.9,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" data-c="7C"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(311,411.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(311,-297.3) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="mo" transform="translate(6285.4,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="msubsup" transform="translate(7285.6,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(9459.4,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="msup" transform="translate(10963,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,363) scale(0.707)"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(640,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mn" transform="translate(1418,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="mi" transform="translate(12974.2,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(13494.2,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.944ex" role="img" style="vertical-align: -0.806ex;" viewbox="0 -944.8 8643.1 1301.2" width="19.554ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(1055.8,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="msubsup" transform="translate(1862.4,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(4036.2,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,363) scale(0.707)"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(640,0)"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mn" transform="translate(1418,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g><g data-mml-node="msup" transform="translate(6047.5,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mi" transform="translate(7551.1,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(8071.1,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex;" viewbox="0 -750 3738.8 1000" width="8.459ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(1055.8,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mi" transform="translate(1695.8,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(2320.8,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(2709.8,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(3349.8,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></svg></mjx-container></p><p>得到：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 27.009ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 27.009ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="3891 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(1014,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(1876.2,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(2876.4,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(3376.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4043.2,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(5099,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mi" transform="translate(5739,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(6364,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(6753,0)"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(7393,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:4"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p>当<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="1.692ex" role="img" style="vertical-align: -0.186ex;" viewbox="0 -666 2473.6 748" width="5.596ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(917.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(1973.6,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g></svg></mjx-container>时，<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.944ex" role="img" style="vertical-align: -0.806ex;" viewbox="0 -944.8 9839.5 1301.2" width="22.261ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(1014,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(1514,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2180.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msubsup" transform="translate(3236.6,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(5410.4,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mi" transform="translate(6914,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(7434,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mo" transform="translate(8283.7,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(9339.5,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g></g></g></svg></mjx-container></p><p>当<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.737ex" role="img" style="vertical-align: -0.781ex;" viewbox="0 -864.9 2767.1 1209.9" width="6.26ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" data-c="1D6FC"></path></g><g data-mml-node="mo" transform="translate(917.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(1973.6,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g></g></g></svg></mjx-container>时，<mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.962ex" role="img" style="vertical-align: -0.806ex;" viewbox="0 -952.7 11671.2 1309.1" width="26.405ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(1014,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(1807.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2474.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(3530.1,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="msubsup" transform="translate(4196.8,0)"><g data-mml-node="mo" transform="translate(0 0.5)"><path d="M113 -244Q113 -246 119 -251T139 -263T167 -269Q186 -269 199 -260Q220 -247 232 -218T251 -133T262 -15T276 155T297 367Q300 390 305 438T314 512T325 580T340 647T361 703T390 751T428 784T479 804Q481 804 488 804T501 805Q552 802 581 769T610 695Q610 669 594 657T561 645Q542 645 527 658T512 694Q512 705 516 714T526 729T538 737T548 742L552 743Q552 745 545 751T525 762T498 768Q475 768 460 756T434 716T418 652T407 559T398 444T387 300T369 133Q349 -38 337 -102T303 -207Q256 -306 169 -306Q119 -306 87 -272T55 -196Q55 -170 71 -158T104 -146Q123 -146 138 -159T153 -195Q153 -206 149 -215T139 -230T127 -238T117 -242L113 -244Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(699.9,532.6) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(505,-340.9) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(6370.6,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="msup" transform="translate(778,0)"><g data-mml-node="mi"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mn" transform="translate(394,363) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g></g></g></g><g data-mml-node="mi" transform="translate(8033.7,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(8553.7,0)"><path d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" data-c="1D461"></path></g><g data-mml-node="mo" transform="translate(9192.4,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="msqrt" transform="translate(10248.2,0)"><g transform="translate(853,0)"><g data-mml-node="mi"><path d="M132 -11Q98 -11 98 22V33L111 61Q186 219 220 334L228 358H196Q158 358 142 355T103 336Q92 329 81 318T62 297T53 285Q51 284 38 284Q19 284 19 294Q19 300 38 329T93 391T164 429Q171 431 389 431Q549 431 553 430Q573 423 573 402Q573 371 541 360Q535 358 472 358H408L405 341Q393 269 393 222Q393 170 402 129T421 65T431 37Q431 20 417 5T381 -10Q370 -10 363 -7T347 17T331 77Q330 86 330 121Q330 170 339 226T357 318T367 358H269L268 354Q268 351 249 275T206 114T175 17Q164 -11 132 -11Z" data-c="1D70B"></path></g></g><g data-mml-node="mo" transform="translate(0,-22.5)"><path d="M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z" data-c="221A"></path></g><rect height="60" width="570" x="853" y="717.5"></rect></g></g></g></svg></mjx-container></p><p>如：</p><p><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex;" viewbox="0 -750 23128.1 1000" width="52.326ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(1014,0)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mo" transform="translate(1514,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2180.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(3236.6,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(3861.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(4250.6,0)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mo" transform="translate(4972.8,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(5973,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(6473,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(7139.8,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(8195.6,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(8695.6,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(9320.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(9709.6,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mo" transform="translate(10209.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(10876.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(11932.1,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mi" transform="translate(12432.1,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(13057.1,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(13446.1,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(14168.3,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(15168.6,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(15668.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(16335.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(17391.1,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mo" transform="translate(18113.3,0)"><path d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" data-c="22C5"></path></g><g data-mml-node="mn" transform="translate(18613.6,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mi" transform="translate(19113.6,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(19738.6,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mn" transform="translate(20127.6,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(20627.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(21294.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mn" transform="translate(22350.1,0)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><g data-mml-node="mo" transform="translate(22850.1,0)"><path d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z" data-c="21"></path></g></g></g></svg></mjx-container></p><p>又如：</p><p><mjx-container class="MathJax" jax="SVG"><svg focusable="false" height="2.737ex" role="img" style="vertical-align: -0.781ex;" viewbox="0 -864.9 27208.6 1209.9" width="61.558ex" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(1014,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" data-c="35"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(1807.6,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(2474.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(3530.1,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(4155.1,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(4544.1,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(5559.9,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(6560.1,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(7060.1,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(7726.9,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(8782.7,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(9576.2,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(10201.2,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(10590.2,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(11383.8,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(12050.5,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(13106.3,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(13899.9,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(14524.9,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(14913.9,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(15929.7,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(16929.9,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(17429.9,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(18096.7,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(19152.4,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(20168.2,0)"><path d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" data-c="22C5"></path></g><g data-mml-node="mfrac" transform="translate(20668.4,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(21462,0)"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(22087,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mfrac" transform="translate(22476,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" data-c="32"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(23269.5,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(23936.3,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mfrac" transform="translate(24992.1,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" data-c="33"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" data-c="34"></path></g><rect height="60" width="553.6" x="120" y="220"></rect></g><g data-mml-node="msqrt" transform="translate(25785.6,0)"><g transform="translate(853,0)"><g data-mml-node="mi"><path d="M132 -11Q98 -11 98 22V33L111 61Q186 219 220 334L228 358H196Q158 358 142 355T103 336Q92 329 81 318T62 297T53 285Q51 284 38 284Q19 284 19 294Q19 300 38 329T93 391T164 429Q171 431 389 431Q549 431 553 430Q573 423 573 402Q573 371 541 360Q535 358 472 358H408L405 341Q393 269 393 222Q393 170 402 129T421 65T431 37Q431 20 417 5T381 -10Q370 -10 363 -7T347 17T331 77Q330 86 330 121Q330 170 339 226T357 318T367 358H269L268 354Q268 351 249 275T206 114T175 17Q164 -11 132 -11Z" data-c="1D70B"></path></g></g><g data-mml-node="mo" transform="translate(0,-22.5)"><path d="M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z" data-c="221A"></path></g><rect height="60" width="570" x="853" y="717.5"></rect></g></g></g></svg></mjx-container></p><p>数学归纳可得：</p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 22.835ex;" width="full"><svg focusable="false" height="2.262ex" role="img" style="vertical-align: -0.566ex; min-width: 22.835ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -750)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 750) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="2968.5 -750 1 1000"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr"><g data-mml-node="mtd"><g data-mml-node="mi"><path d="M128 619Q121 626 117 628T101 631T58 634H25V680H554V676Q556 670 568 560T582 444V440H542V444Q542 445 538 478T523 545T492 598Q454 634 349 634H334Q264 634 249 633T233 621Q232 618 232 339L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" data-c="393"></path></g><g data-mml-node="mo" transform="translate(625,0)"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path></g><g data-mml-node="mi" transform="translate(1014,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(1836.2,0)"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mn" transform="translate(2836.4,0)"><path d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" data-c="31"></path></g><g data-mml-node="mo" transform="translate(3336.4,0)"><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29"></path></g><g data-mml-node="mo" transform="translate(4003.2,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(5059,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(5659,0)"><path d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z" data-c="21"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -750 1 1000"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:5"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" data-c="35" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></svg></g></g></g></g></svg></mjx-container></p><p><mjx-container class="MathJax" display="true" jax="SVG" style="min-width: 28.422ex;" width="full"><svg focusable="false" height="5.457ex" role="img" style="vertical-align: -2.163ex; min-width: 28.422ex;" width="100%" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" stroke="currentColor" stroke-width="0" transform="scale(0.0181,-0.0181) translate(0, -1456.1)"><g data-mml-node="math"><g data-mml-node="mtable" transform="translate(2078,0) translate(-2078,0)"><g transform="translate(0 1456.1) matrix(1 0 0 -1 0 0) scale(55.25)"><svg data-table="true" preserveaspectratio="xMidYMid" viewbox="4203.4 -1456.1 1 2412.2"><g transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mlabeledtr" transform="translate(0,-44.2)"><g data-mml-node="mtd"><g data-mml-node="msubsup"><g data-mml-node="mo" transform="translate(0 1)"><path d="M114 -798Q132 -824 165 -824H167Q195 -824 223 -764T275 -600T320 -391T362 -164Q365 -143 367 -133Q439 292 523 655T645 1127Q651 1145 655 1157T672 1201T699 1257T733 1306T777 1346T828 1360Q884 1360 912 1325T944 1245Q944 1220 932 1205T909 1186T887 1183Q866 1183 849 1198T832 1239Q832 1287 885 1296L882 1300Q879 1303 874 1307T866 1313Q851 1323 833 1323Q819 1323 807 1311T775 1255T736 1139T689 936T633 628Q574 293 510 -5T410 -437T355 -629Q278 -862 165 -862Q125 -862 92 -831T55 -746Q55 -711 74 -698T112 -685Q133 -685 150 -700T167 -741Q167 -789 114 -798Z" data-c="222B"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(1046.4,1088.1) scale(0.707)"><g data-mml-node="mo"><path d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" data-c="2B"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M55 217Q55 305 111 373T254 442Q342 442 419 381Q457 350 493 303L507 284L514 294Q618 442 747 442Q833 442 888 374T944 214Q944 128 889 59T743 -11Q657 -11 580 50Q542 81 506 128L492 147L485 137Q381 -11 252 -11Q166 -11 111 57T55 217ZM907 217Q907 285 869 341T761 397Q740 397 720 392T682 378T648 359T619 335T594 310T574 285T559 263T548 246L543 238L574 198Q605 158 622 138T664 94T714 61T765 51Q827 51 867 100T907 217ZM92 214Q92 145 131 89T239 33Q357 33 456 193L425 233Q364 312 334 337Q285 380 233 380Q171 380 132 331T92 214Z" data-c="221E"></path></g></g><g data-mml-node="mn" transform="translate(589,-896.4) scale(0.707)"><path d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" data-c="30"></path></g></g><g data-mml-node="msup" transform="translate(2520.3,0)"><g data-mml-node="mi"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(605,413) scale(0.707)"><g data-mml-node="mi"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g></g></g><g data-mml-node="msup" transform="translate(3599.6,0)"><g data-mml-node="mi"><path d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" data-c="1D452"></path></g><g data-mjx-texclass="ORD" data-mml-node="TeXAtom" transform="translate(499,413) scale(0.707)"><g data-mml-node="mo"><path d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" data-c="2212"></path></g><g data-mml-node="mi" transform="translate(778,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g></g></g><g data-mml-node="mi" transform="translate(5103.2,0)"><path d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" data-c="1D451"></path></g><g data-mml-node="mi" transform="translate(5623.2,0)"><path d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" data-c="1D465"></path></g><g data-mml-node="mo" transform="translate(6472.9,0)"><path d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" data-c="3D"></path></g><g data-mml-node="mi" transform="translate(7528.7,0)"><path d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" data-c="1D45B"></path></g><g data-mml-node="mo" transform="translate(8128.7,0)"><path d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z" data-c="21"></path></g></g></g></g></svg><svg data-labels="true" preserveaspectratio="xMaxYMid" viewbox="1278 -1456.1 1 2412.2"><g data-labels="true" transform="matrix(1 0 0 -1 0 0)"><g data-mml-node="mtd" id="mjx-eqn:6" transform="translate(0,705.8)"><text data-id-align="true"></text><g data-idbox="true" transform="translate(0,-750)"><g data-mml-node="mtext"><path d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" data-c="28"></path><path d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" data-c="36" transform="translate(389,0)"></path><path d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" data-c="29" transform="translate(889,0)"></path></g></g></g></g></svg></g></g></g></g></svg></mjx-container></p></div><div class="story post-story"><h2 id="参考文献"><a class="headerlink" href="#参考文献" title="参考文献"></a>参考文献</h2><p><a href="https://zh.wikipedia.org/wiki/%CE%93%E5%87%BD%E6%95%B0">Γ 函数 wikipedia</a></p></div></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="离散世界与连续世界的联系" href="https://blog.mhuig.top/p/2b995a0c/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">离散世界与连续世界的联系</span><span class="cap link fs12">https://blog.mhuig.top/p/2b995a0c/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
  <entry>
    <title>用 GitHub 搭建一个简单的脚本库</title>
    <link href="https://blog.imc.re/RSSBOX/rss/40f230bb.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/40f230bb.html</id>
    <published>2021-01-01T16:00:00.000Z</published>
    <updated>2021-01-01T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div>细心的朋友可能会发现，我提供的一些脚本都可以在不需要任何包管理工具的情况下通过一行命令安装，本文讲述如何搭建一个轻量级的脚本库，方便随时执行自己存放于仓库的脚本。</div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="用 GitHub 搭建一个简单的脚本库" href="https://xaoxuu.com/blog/20210102/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">用 GitHub 搭建一个简单的脚本库</span><span class="cap link fs12">https://xaoxuu.com/blog/20210102/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/categories/blogs/xaoxuu/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="XAOXUU" scheme="https://blog.imc.re/RSSBOX/tags/xaoxuu/"/>
    
  </entry>
  
  <entry>
    <title>一大波题目正在来袭</title>
    <link href="https://blog.imc.re/RSSBOX/rss/bc43343e.html"/>
    <id>https://blog.imc.re/RSSBOX/rss/bc43343e.html</id>
    <published>2020-12-06T05:33:18.000Z</published>
    <updated>2020-12-06T05:33:18.000Z</updated>
    
    <content type="html"><![CDATA[<div><img no-lazy="" src="https://api.mhuig.top/pixel-blog-atom-12138.gif" style="display: none;"/><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995182726/1.webp" src="https://unpkg.com/mhgoos@0.0.1651995182726/1.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995225893/2.webp" src="https://unpkg.com/mhgoos@0.0.1651995225893/2.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995270496/3.webp" src="https://unpkg.com/mhgoos@0.0.1651995270496/3.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995309717/4.webp" src="https://unpkg.com/mhgoos@0.0.1651995309717/4.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995346873/5.webp" src="https://unpkg.com/mhgoos@0.0.1651995346873/5.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995400157/6.webp" src="https://unpkg.com/mhgoos@0.0.1651995400157/6.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995441522/7.webp" src="https://unpkg.com/mhgoos@0.0.1651995441522/7.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995502786/8.webp" src="https://unpkg.com/mhgoos@0.0.1651995502786/8.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995541681/9.webp" src="https://unpkg.com/mhgoos@0.0.1651995541681/9.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995580719/10.webp" src="https://unpkg.com/mhgoos@0.0.1651995580719/10.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995621948/11.webp" src="https://unpkg.com/mhgoos@0.0.1651995621948/11.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995695961/12.webp" src="https://unpkg.com/mhgoos@0.0.1651995695961/12.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995735312/13.webp" src="https://unpkg.com/mhgoos@0.0.1651995735312/13.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995791028/14.webp" src="https://unpkg.com/mhgoos@0.0.1651995791028/14.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995831211/15.webp" src="https://unpkg.com/mhgoos@0.0.1651995831211/15.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995882194/16.webp" src="https://unpkg.com/mhgoos@0.0.1651995882194/16.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995919965/17.webp" src="https://unpkg.com/mhgoos@0.0.1651995919965/17.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651995963692/18.webp" src="https://unpkg.com/mhgoos@0.0.1651995963692/18.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996000243/19.webp" src="https://unpkg.com/mhgoos@0.0.1651996000243/19.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996033811/20.webp" src="https://unpkg.com/mhgoos@0.0.1651996033811/20.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996061052/21.webp" src="https://unpkg.com/mhgoos@0.0.1651996061052/21.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996098980/22.webp" src="https://unpkg.com/mhgoos@0.0.1651996098980/22.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996173488/23.webp" src="https://unpkg.com/mhgoos@0.0.1651996173488/23.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996240526/24.webp" src="https://unpkg.com/mhgoos@0.0.1651996240526/24.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996447979/25.webp" src="https://unpkg.com/mhgoos@0.0.1651996447979/25.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996482807/26.webp" src="https://unpkg.com/mhgoos@0.0.1651996482807/26.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996526452/27.webp" src="https://unpkg.com/mhgoos@0.0.1651996526452/27.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996562478/28.webp" src="https://unpkg.com/mhgoos@0.0.1651996562478/28.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996610556/29.webp" src="https://unpkg.com/mhgoos@0.0.1651996610556/29.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996644796/30.webp" src="https://unpkg.com/mhgoos@0.0.1651996644796/30.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996676823/31.webp" src="https://unpkg.com/mhgoos@0.0.1651996676823/31.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996712589/32.webp" src="https://unpkg.com/mhgoos@0.0.1651996712589/32.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996744606/33.webp" src="https://unpkg.com/mhgoos@0.0.1651996744606/33.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996793972/34.webp" src="https://unpkg.com/mhgoos@0.0.1651996793972/34.webp"/></img></p><p><img><img class="lazyload" data-src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-srcset="https://unpkg.com/mhgoos@0.0.1651996824684/35.webp" src="https://unpkg.com/mhgoos@0.0.1651996824684/35.webp"/></img></p></div><div><div class="tag-plugin link dis-select"><a class="link-card plain" title="一大波题目正在来袭" href="https://blog.mhuig.top/p/bc43343e/" target="_blank" rel="external nofollow noopener noreferrer" cardlink autofill="icon"><div class="left"><span class="title">一大波题目正在来袭</span><span class="cap link fs12">https://blog.mhuig.top/p/bc43343e/</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/link/8f277b4ee0ecd.svg"></div></div></a></div></div>]]></content>
    
    
      
      
    <summary type="html"></summary>
      
    
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/categories/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/categories/blogs/mhuig/"/>
    
    
    <category term="Blogs" scheme="https://blog.imc.re/RSSBOX/tags/blogs/"/>
    
    <category term="MHuiG" scheme="https://blog.imc.re/RSSBOX/tags/mhuig/"/>
    
  </entry>
  
</feed>
