<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>/ on archive</title><link>https://archive-w.netlify.app/</link><description>Recent content in / on archive</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://archive-w.netlify.app/index.xml" rel="self" type="application/rss+xml"/><item><title/><link>https://archive-w.netlify.app/corner/file-format/riff/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/file-format/riff/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introriff">
 Intro(RIFF)
 &lt;a class="anchor" href="#introriff">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 摘自：维基百科
&lt;br>&lt;br>&lt;strong>资源交换文件格式&lt;/strong>（英语：


 &lt;a href="https://en.wikipedia.org/wiki/Resource_Interchange_File_Format" rel="noopener" target="_blank">Resource Interchange File Format&lt;/a>，缩写为 RIFF），又译资源互换文件格式，是一种文件格式（meta-format）标准，把资料存储在被标记的区块（tagged chunks）中。它是在 1991 年时，由 Microsoft 和 IBM 提出。它是 Electronic Arts 在 1985 提出的 Interchange File Format（IFF）的翻版。这两种标准的唯一不同处是在多比特整数的存储方式。 RIFF 使用的是小端序，这是 IBM PC 使用的处理器 80x86 所使用的格式，而 IFF 存储整数的方式是使用大端序，这是 Amiga 和 Apple Macintosh 电脑使用的处理器，68k，可处理的整数类型。
&lt;br>&lt;br>Microsoft在 AVI，WAV，以及接下来要介绍的 


 
 

 
 
 
 
 
 
 
 &lt;a href='../ani/' rel="noopener" class="internal-link" data-src="../ani/">ANI&lt;/a> 这些的文件格式中，都使用 RIFF 的格式当成它们的基础。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="结构组成">
 结构组成
 &lt;a class="anchor" href="#%e7%bb%93%e6%9e%84%e7%bb%84%e6%88%90">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> 通用 trunk 结构 &lt;/p>&lt;p> RIFF 文件完全由各种&lt;code>chunk&lt;/code>块组成，truck 是可以 &lt;strong>嵌套&lt;/strong> 的，可以类比文件系统中的文件夹和文件。所有的&lt;code>chunk&lt;/code>都有下面的格式：
&lt;br>&lt;span style='padding-left:2em'>&lt;code>1.&lt;/code> ID(4B)，比如 &lt;code>'RIFF'&lt;/code>，&lt;code>'LIST'&lt;/code>，&lt;code>'anhi'&lt;/code> 等 ASCII 码，字符不够四个 ASCII，则用空格补全，比如&lt;code>'fmt '&lt;/code>,&lt;code>'seq '&lt;/code>。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>2.&lt;/code> SIZE(4B)，当前 chunk 无符号的整形值，尺寸不包括它自身占用的字节数和 ID 的四个字节。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>3.&lt;/code> DATA(*)，当前块包含的数据，长度就是上一个 SIZE(4B) 对应的值。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>4.&lt;/code> 一个填充字节，（可选值）如果当前 chunk 的数据不是偶数的话，会存在这个。例如 


 
 

 
 
 
 
 
 
 
 &lt;a href='#%e7%bb%bc%e5%90%88%e5%9b%be%e4%be%8b' rel="noopener" class="internal-link" data-src="#%e7%bb%bc%e5%90%88%e5%9b%be%e4%be%8b">综合图例&lt;/a> 中的 ID 为 &amp;lsquo;IART&amp;rsquo; 的 truck 后面就有一个填充字节。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/grep/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/grep/</guid><description>&lt;h2 id="简介">
 简介
 &lt;a class="anchor" href="#%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">grep(global regular expression print):
grep 主要用来查找，过滤，grep家族总共有三个：grep，egrep，fgrep。egrep = grep -E 扩展的正则表达式。

1、基本的正则表达式（Basic Regular Expression 又叫 Basic RegEx 简称 BREs）
2、扩展的正则表达式（Extended Regular Expression 又叫 Extended RegEx 简称 EREs）
3、Perl 的正则表达式（Perl Regular Expression 又叫 Perl RegEx 简称 PREs）

***********************************************************
 grep 默认 BREs, -E EREs, -P PREs
 egrep 默认 EREs, -P PREs
 sed 默认 BREs,-r EREs
 awk 默认 EREs
***********************************************************
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="常用选项">
 常用选项
 &lt;a class="anchor" href="#%e5%b8%b8%e7%94%a8%e9%80%89%e9%a1%b9">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># -E : 开启扩展的正则表达式
# -i : 忽略大小写（ignore case）
# -v : 反向选择（invert）
# -n : 显示行号
# -o : 只显示匹配到的内容
# -w : 被匹配的文本只能是单词，不是某一部分，`like` 不会匹配liker
# -c : 显示匹配到多少行，与-cv使用表示反向匹配行数
# --color : 将匹配到的内容以颜色高亮显示
# -A n : 显示字符所在行及其后n行，after
# -B n : 显示字符所在行及其前n行，before
# -C n : 显示字符前后n行，context

grep &amp;quot;root&amp;quot; /etc/passwd
grep -n &amp;quot;root&amp;quot; /etc/passwd
grep -cv &amp;quot;root&amp;quot; /etc/passwd
grep -o &amp;quot;root&amp;quot; /etc/passwd
grep -A 2 &amp;quot;core id&amp;quot; /proc/cpuinfo
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="模式部分">
 模式部分
 &lt;a class="anchor" href="#%e6%a8%a1%e5%bc%8f%e9%83%a8%e5%88%86">#&lt;/a>
&lt;/h2>
&lt;pre>&lt;code>1. 直接输入要匹配的字符串，可以使用fgrep(fast grep)代替来提高查找速度
2. 使用基本正则表达式
 * 匹配字符
 . :任意字符
 [abc] : 表示匹配一个字符，这个字符必须是abc中的一个。
 [^123] : 匹配一个除了123以外的字符
 [a-zA-Z] : 等价于[[:alpha:]]
 [0-9] : 等价于[[:digit:]]
 [a-zA-Z0-9] : 等价于 [[:alnum:]]
 tab,space : 等价于 [[:space:]]
 [A-Z] : [[:upper:]]
 [a-z] : [[:lower:]]
 标点符号 : [[:punct:]]
 
 # grep &amp;quot;hello.&amp;quot; demo.c
 # grep &amp;quot;hello[[:upper:]]&amp;quot; demo.c
 # grep &amp;quot;hello[^[:upper:]][[:digit:]]&amp;quot; demo.c
 # grep &amp;quot;hell[a-z]&amp;quot; demo.c
 # grep &amp;quot;hell[a-z][[:punct:]]&amp;quot; demo.c
 
 * 匹配次数：
 \{m,n\} : 至少m,至多n次
 \? : 0 或 1 次
 * : 任意次
 
 # grep &amp;quot;/.*sh&amp;quot; /etc/passwd
 # grep &amp;quot;/.\{0,2\}sh&amp;quot; /etc/passwd
 # grep -w &amp;quot;.\{0,2\}sh&amp;quot; /etc/passwd
 
 * 位置锚定:
 ^ : 锚定行首
 $ : 锚定行尾： `^$`用于匹配空白行（没有空格）
 \b 或 \&amp;lt; : 单词词首
 \b 或 \&amp;gt; : 单词词尾
 \B : 与\b 相反 `beer/B` 不是以beer结尾
 
 # grep &amp;quot;h&amp;quot; /etc/passwd
 # grep &amp;quot;h$&amp;quot; /etc/passwd
 # grep &amp;quot;\&amp;lt;sh&amp;quot; /etc/passwd
 # grep &amp;quot;\Bsh\b&amp;quot; /etc/passwd
 
 * 分组及引用：
 \(string\) : 将string作为一个整体方便后面引用
 \n : 第几个引用，0表示本记录，从1开始
 
 # grep &amp;quot;^\(.\{1\}\).*\1$&amp;quot; /etc/passwd
 # grep &amp;quot;^\([[:alpha:]]\).*\1$&amp;quot; /etc/passwd

 * 分组后不引用 (?:), 参考Reference
 
 * 零宽断言：
 (?=pattern) 正向先行断言（正前瞻）
 (?&amp;lt;=pattern) 正向后行断言（正后顾）
 (?!pattern) 负向先行断言（负前瞻）
 (?&amp;lt;!=pattern)负向后行断言（负后顾）
 
 # 我爱祖国，我是祖国的花朵
 # 祖国(?=的花朵)
 # (?&amp;lt;=我爱)祖国
 # 祖国(?!的花朵)
 # (?&amp;lt;!我爱)祖国

3. 扩展正则表达式(-E | egrep)
 `?` `+` `|` `()` `{}`
&lt;/code>&lt;/pre>
&lt;h2 id="外链">
 外链
 &lt;a class="anchor" href="#%e5%a4%96%e9%93%be">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="31-rubularcom外链">
 3.1 rubular.com外链
 &lt;a class="anchor" href="#31-rubularcom%e5%a4%96%e9%93%be">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>


 &lt;a href="https://rubular.com/r/N5s1264MOiJzgG" rel="noopener" target="_blank">祖国(?=的花朵)&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://rubular.com/r/k2Aj5zYb8VsdRl" rel="noopener" target="_blank">(?&amp;lt;=我爱)祖国&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://rubular.com/r/n2r84kmPHbapfm" rel="noopener" target="_blank">祖国(?!的花朵)&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://rubular.com/r/knBZziOjn0XBVA" rel="noopener" target="_blank">(?&amp;lt;!我爱)祖国&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://rubular.com/r/2F8fmkJKc64yMw" rel="noopener" target="_blank">电话号码&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="32-regex-学习记录">
 3.2 RegEx 学习记录
 &lt;a class="anchor" href="#32-regex-%e5%ad%a6%e4%b9%a0%e8%ae%b0%e5%bd%95">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">3.2.1正则匹配同时包含两个字符，不分先后顺序,https://rubular.com/r/C8klIhBII08CXN
^(?=.*?test)(?=.*?bash).*$
 以下下列子可能有助于理解:如果需要匹配字符，需要定界。
 ^(?=.*?test)(?=.*?bash).{9,}$
 ^(?=.*?test).{0,}(?=bash)
 ^(?=.*test)(?=.*bash)
 ^(?=.*test)(?=.*bash).{2}


3.2.2 正则不过滤但深色显示
cat abcdef | grep &amp;quot;content\|$&amp;quot;

3.2.3 网址之后一部分，或者没有网址的方式 (https://rubular.com/r/sXLihPuKPpJrCI)
/(^.*\/|^)(.*)$/
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.cnblogs.com/flyor/p/6411140.html" rel="noopener" target="_blank">linux中grep命令的用法&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/yufenghyc/article/details/51078107" rel="noopener" target="_blank">grep中使用&amp;quot;\d&amp;quot;匹配数字不成功的原因解决&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/csm0912/article/details/81206848" rel="noopener" target="_blank">(?:)&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>OBJECT ORIENTED</title><link>https://archive-w.netlify.app/doc/base/OO/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/OO/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="对象结构">
 对象结构
 &lt;a class="anchor" href="#%e5%af%b9%e8%b1%a1%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/base/object-header-01.png" alt="" width="60%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="对象头">
 对象头
 &lt;a class="anchor" href="#%e5%af%b9%e8%b1%a1%e5%a4%b4">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="mark-word">
 Mark Word
 &lt;a class="anchor" href="#mark-word">#&lt;/a>
&lt;/h4>
&lt;p class="warn">Mark Word(标记字)，用于存储自身运行时的数据 例如&lt;code>GC标志位&lt;/code>、&lt;code>哈希码&lt;/code>、&lt;code>锁状态&lt;/code>等信息。Mark Word 的位长度为 JVM 的一个 Word 大小，也就是说 32 位 JVM 的 Mark word 为 32 位，64 位 JVM 为 64 位。Mark Word 的位长度不会受到 Oop 对象指针压缩选项的影响。&lt;/p>
&lt;p class="tip"> 结构信息：
&lt;br>Java 内置锁的涉及到很多重要信息，并且是存放于对象头的 Mark Word 字段中。
&lt;br>&lt;br>Java 内置锁的状态总共有四种，级别由低到高依次为:无锁、偏向锁、轻量级锁、重量级锁。为了让 Mark word 字段存储更多的信 息，JVM 将 Mark word 的最低两个位设置为 Java 内置锁状态位。
&lt;br>&lt;br>其实在 JDK 1.6 之前，Java 内置锁还是一个重量级锁，是一个效率比较低下的锁，在 JDK 1.6 之 后，JVM 为了提高锁的获取与释放效率，对 synchronized 的实现进行了优化，引入了偏向锁、轻量级锁的实现，从此以后 Java 内置锁的状态就有了四种(无锁、偏向锁、轻量级锁、重量级锁)， 并且四种状态会随着竞争的情况逐渐升级，而且是不可逆的过程，即不可降级，也就是说只能进 行锁升级(从低级别到高级别)。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/corner/file-format/ani/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/file-format/ani/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introani--animated-cursors--动画光标">
 Intro(ANI | Animated cursors | 动画光标)
 &lt;a class="anchor" href="#introani--animated-cursors--%e5%8a%a8%e7%94%bb%e5%85%89%e6%a0%87">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 摘自：维基百科
&lt;br>&lt;br>.ANI 文件格式是 Microsoft Windows 操作系统上用于动画鼠标光标的图形文件格式，该格式基于 Microsoft 


 
 

 
 
 
 
 
 
 
 &lt;a href='../riff/' rel="noopener" class="internal-link" data-src="../riff/">资源交换文件&lt;/a> 格式，该格式用作存储动画的单个帧（标准Windows图标）的容器。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="数据结构验证">
 数据结构验证
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e9%aa%8c%e8%af%81">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://en.wikipedia.org/wiki/ANI_(file_format)" rel="noopener" target="_blank">https://en.wikipedia.org/wiki/ANI_(file_format)&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.daubnet.com/en/file-format-ani" rel="noopener" target="_blank">https://www.daubnet.com/en/file-format-ani&lt;/a>&lt;/li>
&lt;li>&lt;/li>
&lt;li>


 &lt;a href="https://sample-files-online.com/samples/ani" rel="noopener" target="_blank">https://sample-files-online.com/samples/ani&lt;/a> [测试文件-ani样例文件]&lt;/li>
&lt;li>


 &lt;a href="https://codesandbox.io/p/sandbox/open-ani-online-v6g3j" rel="noopener" target="_blank">https://codesandbox.io/p/sandbox/open-ani-online-v6g3j&lt;/a> [online load and show ani file]&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/awk/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/awk/</guid><description>&lt;p class="tip">awk (Alfred Aho 、Peter Weinberger 和 Brian Kernighan):
&lt;br /> 样式扫描和处理语言，它允许您创建简短的程序。读取输入文件，为数据排序，处理数据，对输入执行计算以及生成报表等。其中语法方面有借鉴C语言。&lt;/p>
&lt;h2 id="一语法格式">
 一.语法格式：
 &lt;a class="anchor" href="#%e4%b8%80%e8%af%ad%e6%b3%95%e6%a0%bc%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">awk 'pattern{action[;action..]}' {filenames}
 
原理：
 调用awk时，依次对文件中匹配的每一行做后面的action，每一对pattern+action用分号[;]隔开。
注意：
 如果一个'' 中没有pattern，默认所有行。action 必须{}包起来
 如果一个'' 中没有action，默认打印本行。
 如果什么都没有，只有'',不做任何处理。
 print,printf:
 print 输出后加一个ORS，而printf标准输出，想换行得加'\n',而这个换行不受awk的ORS控制。
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="二常用选项">
 二.常用选项：
 &lt;a class="anchor" href="#%e4%ba%8c%e5%b8%b8%e7%94%a8%e9%80%89%e9%a1%b9">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">[option]
 -F fs or --field-separator fs :指定输入文件拆分符，是一个字符串或正则，如-F:
 -v var=value or --asign var=value :赋值一个用户变量
 -f scripfile or --file scriptfile :从脚本文件中读取awk命令。
 -mf nnn and -mr nnn :对nnn值设置内在限制，-mf选项限制分配给nnn的最大块数目；-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能，在标准awk中不适用。
 -W compact or --compat, -W traditional or --traditional :在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样，所有的awk扩展都被忽略。
 -W copyleft or --copyleft, -W copyright or --copyright :打印简短的版权信息。
 -W help or --help, -W usage or --usage :打印全部awk选项和每个选项的简短说明。
 -W lint or --lint :打印不能向传统unix平台移植的结构的警告。
 -W lint-old or --lint-old :打印关于不能向传统unix平台移植的结构的警告。
 -W posix :打开兼容模式。但有以下限制，不识别：/x、函数关键字、func、换码序列以及当fs是一个空格时，将新行作为一个域分隔符；操作符**和**=不能代替^和^=；fflush无效。
 -W re-interval or --re-inerval :允许间隔正则表达式的使用，参考(grep中的Posix字符类)，如括号表达式[[:alpha:]]。
 -W source program-text or --source program-text :使用program-text作为源代码，可与-f命令混用。
 -W version or --version :打印bug报告信息的版本。
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>
&lt;h2 id="三-使用案例">
 三. 使用案例：
 &lt;a class="anchor" href="#%e4%b8%89-%e4%bd%bf%e7%94%a8%e6%a1%88%e4%be%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="1简单样例">
 1）简单样例
 &lt;a class="anchor" href="#1%e7%ae%80%e5%8d%95%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># echo 'hello this' | awk '' &amp;gt; 默认不做处理
# echo 'hello this' | awk '/hello/' &amp;gt;打印hello this
# echo 'hello this' | awk '{print $0}' &amp;gt;打印hello this

# cat test.txt | awk '{if(NR&amp;gt;=20 &amp;amp;&amp;amp; NR&amp;lt;=30) print $0}' &amp;gt; 打印20～30行内容

&amp;gt;test.txt
I am Poe,my qq is 1234567
# cat test.txt | awk -F '[ ,]+' '{print $3&amp;quot; &amp;quot;$7' &amp;gt;Poe 1234567
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="2beginend模块">
 2）BEGIN，END模块
 &lt;a class="anchor" href="#2beginend%e6%a8%a1%e5%9d%97">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># cat /etc/passwd | awk '{count++;print $0;}END{print &amp;quot;count is&amp;quot;,count}' &amp;gt;统计/etc/passwd的账户人数
# ll | awk '{size=size+$5}END{print &amp;quot;size is&amp;quot;,size/1024,&amp;quot;K&amp;quot;}' &amp;gt;统计某个文件夹下总字节数
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="3awk运算符">
 3）awk运算符
 &lt;a class="anchor" href="#3awk%e8%bf%90%e7%ae%97%e7%ac%a6">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># awk 'BEGIN{a=5;a+=5;print a}' &amp;gt;5,赋值运算符
# awk 'BEGIN{a=1;b=2;print (a&amp;gt;2&amp;amp;&amp;amp;b&amp;gt;1,a=1||b&amp;gt;1)}' &amp;gt;0 1 ,逻辑运算符
# awk 'BEGIN{a=&amp;quot;100testaa&amp;quot;;if(a~/100/)print &amp;quot;OK&amp;quot;}' &amp;gt;OK,正则运算符
# awk 'BEGIN{a=&amp;quot;100testaa&amp;quot;} a~/100/ {print &amp;quot;OK&amp;quot;}' &amp;gt;等待用户输入
# awk 'BEGIN{a=&amp;quot;11&amp;quot;;if(a&amp;gt;=9){print &amp;quot;ok&amp;quot;}}' &amp;gt;无输出,关系运算符
# awk 'BEGIN{a=11;if(a&amp;gt;=9){print &amp;quot;ok&amp;quot;}}' &amp;gt;ok
# awk 'BEGIN{a;if(a&amp;gt;=b){print &amp;quot;ok&amp;quot;}}' &amp;gt;ok
# awk 'BEGIN{a=&amp;quot;b&amp;quot;;print a++,++a}' &amp;gt;0 2,算数运算符
# awk 'BEGIN{a=&amp;quot;20b4&amp;quot;;print a++,++a}' &amp;gt;20 22
# awk 'BEGIN{a=&amp;quot;b&amp;quot;;print a==&amp;quot;b&amp;quot;?&amp;quot;ok&amp;quot;:&amp;quot;err&amp;quot;}' &amp;gt;ok,三目运算符
# awk 'BEGIN{a=&amp;quot;b&amp;quot;;print a==&amp;quot;c&amp;quot;?&amp;quot;ok&amp;quot;:&amp;quot;err&amp;quot;}' &amp;gt;err
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="4常用awk内置变量">
 4）常用awk内置变量
 &lt;a class="anchor" href="#4%e5%b8%b8%e7%94%a8awk%e5%86%85%e7%bd%ae%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">$0 当前记录
$1~$n 当前记录的第n个字段
FS 输入字段分隔符，默认空格
RS 输入记录分隔符，默认换行符
NF 当前记录书中的字段个数
NR 行号，从1开始
OFS 输出字段分隔符，默认空格
ORS 输出记录分隔符，默认换行符

&amp;gt;tab.txt
ww CC IDD

# cat tab.txt | awk 'BEGIN{FS=&amp;quot;\t+&amp;quot;}{print $1,$2,$3}' &amp;gt;ww CC IDD
# cat space.txt | awk -F [[:space:]+] '{print $1,$2,$3,$4,$5}'
# cat hello.txt | awk -F [&amp;quot; &amp;quot;:]+ '{print $1,$2,$3}'
# cat hello.txt | awk -F &amp;quot;:&amp;quot; 'NF==8{print $0}' hello.txt
# ifconfig eth0 | awk -F [&amp;quot; &amp;quot;:]+ 'NR==2{print $4}'

&amp;gt;record.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco,CA 123456

Big Tony
200 Incognito Ave.
Suburbia,WA 64890

&amp;gt;awk.txt
#!/bin/awk
BEGIN {
 FS=&amp;quot;\n&amp;quot;
 RS=&amp;quot;&amp;quot;
}
{
 print $1&amp;quot;,&amp;quot;$2&amp;quot;,&amp;quot;$3
}

# awk -f awk.txt recode.txt 
&amp;gt;Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
&amp;gt;Big Tony,200 Incognito Ave.,Suburbia,WA 64890
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="5awk正则">
 5）awk正则
 &lt;a class="anchor" href="#5awk%e6%ad%a3%e5%88%99">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># cat /etc/passwd | awk '/root/{print $0}'
# cat /etc/passwd | awk -F: '$5~/root/{print $0}'
# cat /etc/passwd | awk -F: '$1==&amp;quot;root&amp;quot;{print $0}'
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="6awk的c语言特性if循环和数组">
 6）awk的C语言特性（if,循环和数组）
 &lt;a class="anchor" href="#6awk%e7%9a%84c%e8%af%ad%e8%a8%80%e7%89%b9%e6%80%a7if%e5%be%aa%e7%8e%af%e5%92%8c%e6%95%b0%e7%bb%84">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">-----------------------------
{
 if(){
 if(){
 ...
 }else{
 ...
 }
 }elseif(){
 ...
 }else{
 ...
 }
}
-----------------------------
{
 count=1 do{
 ...
 if(){
 break;
 }
 } while()
}
-----------------------------
for(x=1;x&amp;lt;=4;x++){
 ...
 if(){
 continue;
 }
}
-----------------------------
awk中的数组是关联数组，数字索引也会转变为字符串索引，是无序的，有序的得通过下标获得
-----------------------------
{
 cities[1]=&amp;quot;beijing&amp;quot;
 cities[2]=&amp;quot;shanghai&amp;quot;
 cities[“three”]=&amp;quot;guangzhou&amp;quot;
 for( c in cities){
 print cities[c]
 }
 print cities[&amp;quot;three&amp;quot;]; //也可以
}
# netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' 
&amp;gt;LISTEN 9
&amp;gt;ESTABLISHED 4
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="7常用字符串函数">
 7）常用字符串函数
 &lt;a class="anchor" href="#7%e5%b8%b8%e7%94%a8%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#替换
# awk 'BEGIN{info=&amp;quot;this is a test2010test!&amp;quot;;gsub(/[0-9]+/,&amp;quot;!&amp;quot;,info);print info}' &amp;gt;this is a test!test!

#查找
# awk 'BEGIN{info=&amp;quot;this is a test2010test!&amp;quot;;print index(info,&amp;quot;test&amp;quot;)?&amp;quot;ok&amp;quot;:&amp;quot;no found&amp;quot;;}' &amp;gt;ok

#匹配查找
# awk 'BEGIN{info=&amp;quot;this is a test2010test!&amp;quot;;print match(info,/[0-9]+/)?&amp;quot;ok&amp;quot;:&amp;quot;no found&amp;quot;;}' &amp;gt;ok

#截取
# awk 'BEGIN{info=&amp;quot;this is a test2010test!&amp;quot;;print substr(info,4,10);}' &amp;gt;s is a tes

#分割
# awk 'BEGIN{info=&amp;quot;this is a test&amp;quot;;split(info,tA,&amp;quot; &amp;quot;);print length(tA);for(k in tA){print k,tA[k];}}'
&amp;gt;4
&amp;gt;4 test
&amp;gt;1 this
&amp;gt;2 is
&amp;gt;3 a

#length(),blength(),tolower(),toupper()...等
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="四参考">
 四.参考：
 &lt;a class="anchor" href="#%e5%9b%9b%e5%8f%82%e8%80%83">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.cnblogs.com/ginvip/p/6352157.html" rel="noopener" target="_blank"> Linux三剑客之awk命令 &lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.runoob.com/linux/linux-comm-awk.html" rel="noopener" target="_blank"> Linux awk 命令 &lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/sed/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/sed/</guid><description>&lt;h2 id="sed-stream-editor">
 sed (Stream Editor):
 &lt;a class="anchor" href="#sed-stream-editor">#&lt;/a>
&lt;/h2>
&lt;p class="tip">文本流编辑，是一个&amp;quot;非交互式的&amp;quot;面向字符流的编辑器。能同时处理多个文件多行内容，可以不对源文件改动，把整个文件输入到屏幕，可以把只匹配到模式的内容输出到屏幕上。还可以对源文件改动，但是不会在屏幕上返回结果。&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">[root@12302 ~]# sed --version
sed (GNU sed) 4.2.2
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU sed home page: &amp;lt;http://www.gnu.org/software/sed/&amp;gt;.
General help using GNU software: &amp;lt;http://www.gnu.org/gethelp/&amp;gt;.
E-mail bug reports to: &amp;lt;bug-sed@gnu.org&amp;gt;.
Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.
&lt;/code>&lt;/pre>&lt;/div>
&lt;h3 id="一语法格式">
 一.语法格式：
 &lt;a class="anchor" href="#%e4%b8%80%e8%af%ad%e6%b3%95%e6%a0%bc%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># If no -e, --expression, -f, or --file option is given, then the first non-option argument is taken as the sed script to interpret. 
# All remaining arguments are names of input files; if no input files are specified, then the standard input is read.
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
&lt;/code>&lt;/pre>&lt;/div>
&lt;h3 id="二常用选项">
 二.常用选项：
 &lt;a class="anchor" href="#%e4%ba%8c%e5%b8%b8%e7%94%a8%e9%80%89%e9%a1%b9">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>option&lt;/th>
&lt;th>describe&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>-n, &amp;ndash;quiet, &amp;ndash;silent&lt;/td>
&lt;td>suppress automatic printing of pattern space&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-e script, &amp;ndash;expression=script&lt;/td>
&lt;td>add the script to the commands to be executed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-r, &amp;ndash;regexp-extended&lt;/td>
&lt;td>use extended regular expressions in the script.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-f script-file, &amp;ndash;file=script-file&lt;/td>
&lt;td>add the contents of script-file to the commands to be executed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ndash;follow-symlinks&lt;/td>
&lt;td>follow symlinks when processing in place&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-i[SUFFIX], &amp;ndash;in-place[=SUFFIX]&lt;/td>
&lt;td>edit files in place (makes backup if SUFFIX supplied)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-c, &amp;ndash;copy&lt;/td>
&lt;td>use copy instead of rename when shuffling files in -i mode&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-s, &amp;ndash;separate&lt;/td>
&lt;td>consider files as separate rather than as a single continuous long stream.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-z, &amp;ndash;null-data&lt;/td>
&lt;td>separate lines by NUL characters&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ndash;version&lt;/td>
&lt;td>output version information and exit&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;hellip;&lt;/td>
&lt;td>&amp;hellip;&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="三地址匹配">
 三.地址匹配：
 &lt;a class="anchor" href="#%e4%b8%89%e5%9c%b0%e5%9d%80%e5%8c%b9%e9%85%8d">#&lt;/a>
&lt;/h3>
&lt;p class="warn">Sed commands can be given with no addresses, in which case the command will be executed for all input lines; with one address, in which case the command will only be executed for input lines which match that address; or with two addresses, in which case the command will be executed for all input lines which match the inclusive range of lines starting from the first address and continuing to the second address. Three things to note about address
ranges: the syntax is addr1,addr2 (i.e., the addresses are separated by a comma); the line which addr1 matched will always be accepted, even if addr2 selects an earlier line; and if addr2 is a regexp, it will not be tested against the line that addr1 matched.
&lt;br>&lt;strong>After the address (or address-range), and before the command, a ! may be inserted, which specifies that the command shall only be executed if the address (or address-range) does not match.&lt;/strong>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/curl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/curl/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introcurl-client-url">
 Intro(CURL| client url)
 &lt;a class="anchor" href="#introcurl-client-url">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="syntax">
 SYNTAX
 &lt;a class="anchor" href="#syntax">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 1、直接访问默认是get
curl http://www.example.com 
# 2、-i,--include 打印响应头
curl http://www.example.com -i 
# 3、-I,--head 大写的只会打印响应头信息
curl http://www.example.com -I
# 3、-v,--verbose 详细信息
curl http://www.example.com -v
# 4、-d,--date 请求数据 配合-X(请求方式)
curl http://www.example.com -X post -d &amp;quot;username=xhsgg&amp;amp;pwd=123456&amp;quot;
# 5、-b,--cookie 附带cookie信息
curl http://www.example.com -b &amp;quot;JSESSIONID=************;time=***&amp;quot;
# 6、-H,--header 请求头消息，可以携带多个请求头
curl http://www.example.com -H &amp;quot;Content-Type:application/json&amp;quot;
# 7、-F,--form 表单的内容，可以上传文件
curl http://www.example.com -F &amp;quot;file=@_path_&amp;quot;

# 8、-L,--location 参数会让 http 请求跟随服务器的重定向，默认不跟随。
curl -L -i http://www.wtfu.site

# 9、-k,参数跳过 ssl/tls 证书检测
curl -k https://www.example.com

# 10、-x, 指定请求代理
curl -x socks5h://127.0.0.1:7890 https://yifen.996.buzz/gengxin
curl -x socks://127.0.0.1:7890 https://wtfu.site
curl -x 127.0.0.1:7890 https://yifen.996.buzz/gengxin
curl -x http://127.0.0.1:7890 https://webget.yfjc.xyz/api/v1/client/subscribe
curl -x https://127.0.0.1:10126 https://music.163.com/\#/song\?id\=1397021895
curl -x https://127.0.0.1:7890 -I https://wtfu.site

# 11、-X, 指定请求方法
curl -X POST https://www.example.com

# 12、-o,-O 保存文件
curl -o example.html https://www.example.com ==&amp;gt; example.html
curl -O https://www.example.com/foo/bar.html ==&amp;gt; bar.html

# 13 -T,--upload-file &amp;lt;file&amp;gt;
gpg --export 425B8CB8073AAC1EB005E4E648E1F1185160B400 | curl -T - https://keys.openpgp.org

# 使用curl 实现 telnet .追加超时时间是因为，有的服务器有安全策略阻止，会一直等待链接超时，效果跟端口开放相差无几，造成误解。
curl --connect-timeout 1 telnet://wtfu.site:30000
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="样例">
 样例
 &lt;a class="anchor" href="#%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="1ajax提交new-from">
 1.ajax提交new from
 &lt;a class="anchor" href="#1ajax%e6%8f%90%e4%ba%a4new-from">#&lt;/a>
&lt;/h4>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/curl-first.png" alt="" width="100%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/wget/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/wget/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introwget">
 Intro(wget)
 &lt;a class="anchor" href="#introwget">#&lt;/a>
&lt;/h2>
&lt;h3 id="响应内容到标准输出">
 响应内容到标准输出
 &lt;a class="anchor" href="#%e5%93%8d%e5%ba%94%e5%86%85%e5%ae%b9%e5%88%b0%e6%a0%87%e5%87%86%e8%be%93%e5%87%ba">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>wget -q -O - -A 'Accept: application/xml' http://localhost:8080/test/helloxml&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/geekooler/article/details/100853072" rel="noopener" target="_blank">https://blog.csdn.net/geekooler/article/details/100853072&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/nginx/nginx/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/nginx/nginx/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="简介">
 简介
 &lt;a class="anchor" href="#%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="1介绍">
 1.介绍
 &lt;a class="anchor" href="#1%e4%bb%8b%e7%bb%8d">#&lt;/a>
&lt;/h3>
&lt;p class="warn">Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器，同时也提供了IMAP/POP3/SMTP服务,支持FastCGI,SSL,Virtual Host,URL Rewrite,Gzip等功能。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="2功能">
 2.功能
 &lt;a class="anchor" href="#2%e5%8a%9f%e8%83%bd">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>反向代理&lt;/li>
&lt;li>负载均衡&lt;/li>
&lt;li>静态服务器&lt;/li>
&lt;li>邮箱服务器&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="3负载均衡方式">
 3.负载均衡方式
 &lt;a class="anchor" href="#3%e8%b4%9f%e8%bd%bd%e5%9d%87%e8%a1%a1%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>name&lt;/th>
&lt;th>explain&lt;/th>
&lt;th>feature&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>轮询&lt;/td>
&lt;td>默认方式&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>weight&lt;/td>
&lt;td>权重方式&lt;/td>
&lt;td>根据权重分发请求,权重大的分配到请求的概率大&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ip_hash&lt;/td>
&lt;td>ip 分配&lt;/td>
&lt;td>根据客户端请求的IP地址计算hash值， 根据hash值来分发请求, 同一个IP发起的请求, 会发转发到同一个服务器上&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>url_hash&lt;/td>
&lt;td>url 分配&lt;/td>
&lt;td>根据客户端请求url的hash值，来分发请求, 同一个url请求, 会发转发到同一个服务器上&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>fair&lt;/td>
&lt;td>智能响应&lt;/td>
&lt;td>优先把请求分发给处理请求时间短的服务器&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>least_conn&lt;/td>
&lt;td>最少连接&lt;/td>
&lt;td>哪个服务器当前处理的连接少, 请求优先转发到这台服务器&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="编译安装">
 编译安装
 &lt;a class="anchor" href="#%e7%bc%96%e8%af%91%e5%ae%89%e8%a3%85">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> 官方源码下载 


 &lt;a href="https://nginx.org/download/nginx-1.16.1.tar.gz" rel="noopener" target="_blank">1.16.1&lt;/a> 、


 &lt;a href="https://nginx.org/download/nginx-1.26.2.tar.gz" rel="noopener" target="_blank">1.26.2&lt;/a>。
&lt;br>（可选）编译用的 openssl 源码库，主要为了支持 


 &lt;a href="https://nginx.org/en/CHANGES-1.14#:~:text=Feature:%20the%20%22TLSv1.3%22,directive." rel="noopener" target="_blank">TLSv1.3&lt;/a>。
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/devops/nginx/nginx-build-info-01.png" alt="" width="70%">&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 切换完依赖的 openssl 库后记得重启服务器，要不然可能会存在配置的 TLSv1.3 的功能，即使通过&lt;code>-s reload&lt;/code>但依然死活不生效，误以为配置出问题了。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/docker/docker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/docker/docker/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="基本命令">
 基本命令
 &lt;a class="anchor" href="#%e5%9f%ba%e6%9c%ac%e5%91%bd%e4%bb%a4">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="base">
 BASE
 &lt;a class="anchor" href="#base">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> 提交镜像
&lt;br>&lt;code>docker commit -a &amp;quot;xhsgg12302@gmail.com&amp;quot; -m &amp;quot;with requirements.txt&amp;quot; 44f357ee68bc eli/anaconda3:v1.0&lt;/code>
&lt;br>标签镜像
&lt;br>&lt;code>docker tag bad7184c3c60 gitlab.pixdaddy.com:5050/library/eclipse-temurin:17.0.2_8-jre-3.8.18-python-alpine3.17-with-pip-deps&lt;/code>
&lt;br>加载镜像
&lt;br>&lt;code>docker build -t me/venvs:v1.0 -f DK-venv .&lt;/code>
&lt;br>&lt;code>docker save me/venvs:v1.0 -o ./venvs.tar&lt;/code> 、 &lt;code>docker save me/venvs:v1.0 &amp;gt; ./venvs.tar&lt;/code>
&lt;br>&lt;code>docker load -i /path/tmp/docker-build.tar&lt;/code>
&lt;br>删除容器
&lt;br>&lt;code>docker ps -qa | xargs -n 1 docker rm -f&lt;/code>
&lt;br>&lt;br>这将列出所有没有被任何标签或容器引用的镜像。这些镜像通常被称为悬空镜像，因为它们没有被命名或引用，而且也没有被垃圾回收机制删除。
&lt;br>


 &lt;a href="https://docs.docker.com/engine/reference/commandline/images/#filter" rel="noopener" target="_blank">https://docs.docker.com/engine/reference/commandline/images/#filter&lt;/a>
&lt;br>&lt;code>docker image ls -f &amp;quot;dangling=true&amp;quot;&lt;/code>
&lt;br>删除所有没有被标记或容器引用的悬空镜像
&lt;br>&lt;code>docker image prune&lt;/code>
&lt;br>查找标记为 NONE 的镜像。运行以下命令：
&lt;br>&lt;code>docker images | grep '&amp;lt;none&amp;gt;' | awk '{print $3}'&lt;/code>
&lt;br>删除标记为 NONE 的镜像。使用以下命令删除这些镜像：
&lt;br>&lt;code>docker rmi $(docker images | grep '&amp;lt;none&amp;gt;' | awk '{print $3}')&lt;/code>
&lt;br>&lt;br>启动时


 &lt;a href="https://stackoverflow.com/questions/40122152/how-to-remove-entrypoint-from-parent-image-on-dockerfile" rel="noopener" target="_blank">去除基础镜像的entryponit&lt;/a> 或者在Dockerfile中 写入 ENTRYPOINT []
&lt;br>&lt;code>docker run -d --entrypoint='' ff3b94479b5d /bin/sh -c &amp;quot;npm i; xvfb-run --server-args='-screen 0 1280x800x24 -ac -nolisten tcp -dpi 96 +extension RANDR' npm run dev&amp;quot;&lt;/code>
&lt;br>&lt;br>docker 不使用缓存构建镜像
&lt;br>&lt;code>docker build -t **:1.0 --no-cache -f Dockerfile . &lt;/code>
&lt;br>docker 清理构建缓存
&lt;br>&lt;code>docker builder prune&lt;/code>、或者更深层次的&lt;code>docker system prune -a&lt;/code>
&lt;br>&lt;br>docker 进入内核查看 MacOSX 本地挂载卷 /var/lib/docker/volume
&lt;br>&lt;code>docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh&lt;/code>
&lt;br>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/git/git/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/git/git/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="代理设置">
 代理设置
 &lt;a class="anchor" href="#%e4%bb%a3%e7%90%86%e8%ae%be%e7%bd%ae">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 有些时候需要搞明白代理如何生效，以致 clone、fetch 等远程操作纵享丝滑。
&lt;br>参考文档： 


 &lt;a href="https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpproxy" rel="noopener" target="_blank">http.proxy&lt;/a> 、 


 &lt;a href="https://gist.github.com/evantoli/f8c23a37eb3558ab8765" rel="noopener" target="_blank">Configure Git to use a proxy&lt;/a>&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="1,6" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">http.proxy
	Override the HTTP proxy, normally configured using the http_proxy, https_proxy, and all_proxy environment variables (see curl(1)). In addition to the syntax understood by curl, it is possible to specify a proxy string with a user name but no password, in which case git will attempt to acquire one in the same way it does for other credentials. See gitcredentials[7] for more information. The syntax thus is [protocol://][user[:password]@]proxyhost[:port][/path]. This can be overridden on a per-remote basis; see remote.&amp;lt;name&amp;gt;.proxy
	【译：】可以通过`http.proxy`覆写 curl 可识别的环境变量：http_proxy, https_proxy, all_proxy 等。
	除了 curl 可识别的语法之外，还可以给代理字符串指定用户名，不需要密码，git 会通过`凭据管理`自动获取密码填充。语法形如：[protocol://][user[:password]@]proxyhost[:port][/path]

http.&amp;lt;url&amp;gt;.proxy
	给某个 URL 单独配置代理。

# 【添加代理】
git config --global http.proxy http://proxyUsername:proxyPassword@proxy.server.com:port
git config --global http.https://domain.com.proxy http://proxyUsername:proxyPassword@proxy.server.com:port

# 【删除代理】
git config --global --unset http.proxy
git config --global --unset http.https://domain.com.proxy
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="凭据管理">
 凭据管理
 &lt;a class="anchor" href="#%e5%87%ad%e6%8d%ae%e7%ae%a1%e7%90%86">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="1基本操作">
 1.基本操作
 &lt;a class="anchor" href="#1%e5%9f%ba%e6%9c%ac%e6%93%8d%e4%bd%9c">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/array/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/array/</guid><description>&lt;p>array&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/graph/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/graph/</guid><description>&lt;p>graph&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/linked/apply/cycle-linked/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/linked/apply/cycle-linked/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introcycle-linked--环形链表检测">
 Intro(CYCLE-LINKED | 环形链表检测)
 &lt;a class="anchor" href="#introcycle-linked--%e7%8e%af%e5%bd%a2%e9%93%be%e8%a1%a8%e6%a3%80%e6%b5%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="题目描述">
 题目描述
 &lt;a class="anchor" href="#%e9%a2%98%e7%9b%ae%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">给定一个链表，如果它是有环链表，实现一个算法返回环路的开头节点。若环不存在，请返回 null。如下：&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="mermaid">graph LR;
 A[3] --&amp;gt; B[2];
 B --&amp;gt; C[0];
 C --&amp;gt; D[-4];
 D --&amp;gt; B;
 style B fill:#6f9,stroke:#333,stroke-width:4px;
&lt;/div>&lt;/div> &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="mermaid">graph LR;
 A[3] --&amp;gt; B[2];
 B --&amp;gt; C[0];
 C --&amp;gt; D[-4];
 D --&amp;gt; E[NULL];
&lt;/div>&lt;/div>&lt;/div>

&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 在力扣题目 


 &lt;a href="https://leetcode.cn/problems/linked-list-cycle-lcci/description/" rel="noopener" target="_blank">面试题 02.08. 环路检测&lt;/a> 中，根据官方题解中第二种使用 &lt;strong>快慢指针&lt;/strong> 的方式，可以求得环形链表的环点。
&lt;br>但是有点费解的是，官方直接在首次相遇后推算出公式 &lt;span class="math inline">\(a=c+(n−1)(b+c)\)&lt;/span>，然后莫名其妙就判定如果此时使用&lt;code>pre&lt;/code>和&lt;code>slow&lt;/code>指针最终会在环点相遇。
&lt;br>&lt;br>对于我来理解的话，跨度有点大了。经 


 &lt;a href="https://www.bilibili.com/video/BV1if4y1d7ob/" rel="noopener" target="_blank">大佬视频&lt;/a> 的解释，慢慢理解了。
&lt;br>&lt;br>&lt;span style='color:red'>大概就是：只有在第一次快慢指针相遇后，才能的出公式 &lt;span class="math inline">\(a=c+(n−1)(b+c)\)&lt;/span>，其他时间这个公式不一定成立。而且对于公式中的 n 来说，必定 &amp;gt;= 1，不存在 0 即（快指针还没跑一圈呢，就和慢指针相遇了）的情况。在得出公式后，我们可以知道，在首次相遇后这个时间点，会存在 &lt;span class="math inline">\(a = c + x圈 \)&lt;/span> 这种关系。其中 a 和 c 只是距离问题，和快慢没关系了。所以在 &lt;strong>首次相遇&lt;/strong> 情况下，可以理解为两个人从 a 开头和 c 开头，均速往环点走，一定会在环点相遇，无非是第二个人从 c 点多可能走几圈而已。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/linked/apply/reverse-linked-list/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/linked/apply/reverse-linked-list/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introreverse-linked-list--反转链表">
 Intro(REVERSE-LINKED-LIST | 反转链表)
 &lt;a class="anchor" href="#introreverse-linked-list--%e5%8f%8d%e8%bd%ac%e9%93%be%e8%a1%a8">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="题目描述">
 题目描述
 &lt;a class="anchor" href="#%e9%a2%98%e7%9b%ae%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">给你单链表的头节点 head ，请你反转链表，并返回反转后的链表。如下：&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="mermaid">graph LR;
 A[1] --&amp;gt; B[2];
 B --&amp;gt; C[3];
 C --&amp;gt; D[4];
 D --&amp;gt; E[5];
 E --&amp;gt; F[NULL];
&lt;/div>&lt;/div> &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="mermaid">graph RL;
 E[5] --&amp;gt; D[4];
 D --&amp;gt; C[3];
 C --&amp;gt; B[2];
 B --&amp;gt; A[1];
 A[1] --&amp;gt; F[NULL];
&lt;/div>&lt;/div>&lt;/div>

&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 在力扣题目 


 &lt;a href="https://leetcode.cn/problems/reverse-linked-list/description/?envType=problem-list-v2&amp;envId=linked-list" rel="noopener" target="_blank">206. 反转链表&lt;/a> 、


 &lt;a href="https://leetcode.cn/problems/fan-zhuan-lian-biao-lcof/description/" rel="noopener" target="_blank">剑指 Offer 24. 反转链表&lt;/a> 中，根据官方题解可知有 &lt;strong>迭代&lt;/strong> 和 &lt;strong>递归&lt;/strong> 的方式。
&lt;br>&lt;br>对于递归的方式暂时先不记录。只对迭代通过图形的方式加深印象。
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/algo/linked/reverse-linked-list/rll-traversal-01.png" alt="" width="90%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/search/binary-search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/search/binary-search/</guid><description>&lt;h2 id="binary-search">
 binary search
 &lt;a class="anchor" href="#binary-search">#&lt;/a>
&lt;/h2>
&lt;h3 id="implement">
 implement
 &lt;a class="anchor" href="#implement">#&lt;/a>
&lt;/h3>
&lt;h6 id="java" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="java" class="docsify-tabs__tab" data-tab="JAVA">JAVA&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="java">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import org.junit.Assert;
import org.junit.Test;

public class BinarySearch {

 @Test
 public void testBinarySearch(){
 int[] arr = new int[]{4,8,10, 16,18,20,50,100};

 Assert.assertEquals(&amp;quot;&amp;quot;, binarySearch(arr, 0, arr.length - 1, 4), 0);
 Assert.assertEquals(&amp;quot;&amp;quot;, binarySearch(arr, 0, arr.length - 1, 16), 3);
 Assert.assertEquals(&amp;quot;&amp;quot;, binarySearch(arr, 0, arr.length - 1, 100), 7);
 Assert.assertEquals(&amp;quot;&amp;quot;, binarySearch(arr, 0, arr.length - 1, 12302), -1);
 }

 private static int binarySearch(int[] arr, int left, int right, int key) {
 if(left &amp;gt; right) { return -1;}

 int mid = (left + right) / 2;
 int midKey = arr[mid];

 if(key &amp;gt; midKey){ return binarySearch(arr, mid + 1, right, key); }

 // right = mid - 1 才对，不然会发生 StackOverflowError, 比如： Assert.assertEquals(&amp;quot;&amp;quot;, binarySearch(arr, 0, arr.length - 1, 2), -1);
 // if(key &amp;lt; midKey){ return binarySearch(arr, left, mid, key); }
 if(key &amp;lt; midKey){ return binarySearch(arr, left, mid - 1, key); }
 return mid;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.bilibili.com/video/BV1E4411H73v?p=82&amp;vd_source=550a4dc4b2a914c0681a14307bbe8cbe" rel="noopener" target="_blank">https://www.bilibili.com/video/BV1E4411H73v?p=82&amp;vd_source=550a4dc4b2a914c0681a14307bbe8cbe&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/algo/sort/bubble-sort/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/sort/bubble-sort/</guid><description>&lt;h2 id="bubble">
 bubble
 &lt;a class="anchor" href="#bubble">#&lt;/a>
&lt;/h2>
&lt;h3 id="visualization">
 visualization
 &lt;a class="anchor" href="#visualization">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/sort/bubble-sort-01.gif" alt="">&lt;/p>
&lt;h3 id="implement">
 implement
 &lt;a class="anchor" href="#implement">#&lt;/a>
&lt;/h3>
&lt;h6 id="java" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="java" class="docsify-tabs__tab" data-tab="JAVA">JAVA&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="java">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import java.util.Arrays;

public class BubbleSort{
 public static void sort(int[] raw){
 for (int i = 1; i &amp;lt; raw.length ; i++) {
 for (int j = 0; j &amp;lt; raw.length - i ; j++) {
 if(raw[j] &amp;gt; raw[j+1])
 switchNumberByTemp(raw,j,j+1);
 }
 }
 }

 public static void switchNumberByTemp(int[] raw,int x, int y){
 int temp = raw[x];
 raw[x] = raw[y];
 raw[y] = temp;
 }

 public static void main(String[] args){
 int[] arr = { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
 sort(arr);
 System.out.println(Arrays.toString(arr));
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="c" class="docsify-tabs__tab" data-tab="C">C&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="c">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.runoob.com/w3cnote/bubble-sort.html" rel="noopener" target="_blank">https://www.runoob.com/w3cnote/bubble-sort.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/algo/sort/insertion-sort/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/sort/insertion-sort/</guid><description>&lt;h2 id="insertion">
 insertion
 &lt;a class="anchor" href="#insertion">#&lt;/a>
&lt;/h2>
&lt;h3 id="visualization">
 visualization
 &lt;a class="anchor" href="#visualization">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/sort/insertion-sort-01.gif" alt="">&lt;/p>
&lt;h3 id="implement">
 implement
 &lt;a class="anchor" href="#implement">#&lt;/a>
&lt;/h3>
&lt;h6 id="java" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="python" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="java" class="docsify-tabs__tab" data-tab="JAVA">JAVA&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="java">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import java.util.Arrays;

public class InsertionSort{
 public static void sort(int[] raw){
 for (int i = 1; i &amp;lt; raw.length; i++) {
 int preIndex = i - 1;
 int currentValue = raw[i];
 while(preIndex &amp;gt;= 0 &amp;amp;&amp;amp; currentValue &amp;lt; raw[preIndex]){
 // 覆盖循环
 raw[preIndex + 1] = raw[preIndex];
 preIndex--;
 }
 raw[preIndex + 1] = currentValue;
 }
 }

 public static void main(String[] args){
 int[] arr = { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
 sort(arr);
 System.out.println(Arrays.toString(arr));
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="c" class="docsify-tabs__tab" data-tab="C">C&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="c">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="python" class="docsify-tabs__tab" data-tab="Python">Python&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="python">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="python" data-line="" class="language-python line-numbers" style="max-height: none">&lt;code class="language-python">def insertionSort(arr):
    for i in range(len(arr)):
        preIndex = i-1
        current = arr[i]
        while preIndex &amp;gt;= 0 and arr[preIndex] &amp;gt; current:
            arr[preIndex+1] = arr[preIndex]
            preIndex-=1
        arr[preIndex+1] = current
    return arr
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.runoob.com/w3cnote/selection-sort.html" rel="noopener" target="_blank">https://www.runoob.com/w3cnote/selection-sort.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/algo/sort/selection-sort/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/sort/selection-sort/</guid><description>&lt;h2 id="selection">
 selection
 &lt;a class="anchor" href="#selection">#&lt;/a>
&lt;/h2>
&lt;h3 id="visualization">
 visualization
 &lt;a class="anchor" href="#visualization">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/sort/selection-sort-01.gif" alt="">&lt;/p>
&lt;h3 id="implement">
 implement
 &lt;a class="anchor" href="#implement">#&lt;/a>
&lt;/h3>
&lt;h6 id="java" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="java" class="docsify-tabs__tab" data-tab="JAVA">JAVA&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="java">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import java.util.Arrays;

public class SelectionSort{
 public static void sort(int[] raw){
 for (int i = 0; i &amp;lt; raw.length - 1 ; i++) {
 int temp = i;
 for (int j = i + 1; j &amp;lt; raw.length ; j++) {
 if(raw[temp] &amp;gt; raw[j])
 temp = j;
 }
 switchNumberByXor(raw,i,temp);
 }
 }

 public static void switchNumberByXor(int[] raw, int x, int y ){
 if(raw[x] == raw[y]) return;
 raw[x] = raw[x] ^ raw[y];
 raw[y] = raw[x] ^ raw[y];
 raw[x] = raw[x] ^ raw[y];
 }

 public static void main(String[] args){
 int[] arr = { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
 sort(arr);
 System.out.println(Arrays.toString(arr));
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="c" class="docsify-tabs__tab" data-tab="C">C&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="c">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.runoob.com/w3cnote/selection-sort.html" rel="noopener" target="_blank">https://www.runoob.com/w3cnote/selection-sort.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/algo/stack/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/stack/</guid><description>&lt;h2 id="introstack">
 Intro(Stack)
 &lt;a class="anchor" href="#introstack">#&lt;/a>
&lt;/h2>
&lt;p class="warn">1. 栈的英文（stack)
&lt;br>2. 栈是一个&lt;code>先入先出&lt;/code>（FILO-First In Last Out)的有序列表
&lt;br>3. 栈是限制线性表中元素的插入和删除&lt;code>只能在线性表的同一端&lt;/code>进行的一种特殊线性表。允许插入和删除的一端，为变化的一端，成为栈顶（top)，另一端为固定的一端，称为栈底（bottom）。
&lt;br>4. 根据栈的定义可知，最先放入栈中的元素在栈底，最后放入的元素在栈顶，而删除元素刚好相反，最后放入的元素最先删除，最先放入的元素最后删除。&lt;/p>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.bilibili.com/video/BV1E4411H73v?p=30" rel="noopener" target="_blank">https://www.bilibili.com/video/BV1E4411H73v?p=30&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.cs.usfca.edu/~galles/visualization/StackArray.html" rel="noopener" target="_blank">https://www.cs.usfca.edu/~galles/visualization/StackArray.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/algo/tree/01-binary-tree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/tree/01-binary-tree/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introbinarytree">
 Intro(BinaryTree)
 &lt;a class="anchor" href="#introbinarytree">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="二叉树">
 二叉树
 &lt;a class="anchor" href="#%e4%ba%8c%e5%8f%89%e6%a0%91">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="定义">
 定义
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89">#&lt;/a>
&lt;/h4>
&lt;p class="tip">二叉树的每个结点至多只有二棵子树(不存在度大于2的结点)，二叉树的子树有左右之分，次序不能颠倒。二叉树的第i层至多有2i-1个结点；深度为k的二叉树至多有2k-1个结点；对任何一棵二叉树T，如果其终端结点数为n0，度为2的结点数为n2，则n0=n2+1。&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="性质">
 性质
 &lt;a class="anchor" href="#%e6%80%a7%e8%b4%a8">#&lt;/a>
&lt;/h4>
&lt;p class="warn">1). 在非空二叉树中，第i层的结点总数不超过2i-1, i&amp;gt;=1;
&lt;br>2) 深度为h的二叉树最多有2h-1个结点(h&amp;gt;=1)，最少有h个结点;
&lt;br>3). 对于任意一棵二叉树，如果其叶结点数为N0，而度数为2的结点总数为N2，则N0=N2+1;
&lt;br>4). 具有n个结点的完全二叉树的深度为log2(n+1);
&lt;br>5). 有N个结点的完全二叉树各结点如果用顺序方式存储，则结点之间有如下关系：
&lt;br>    若I为结点编号则 如果I&amp;gt;1，则其父结点的编号为I/2；
&lt;br>    如果2I&amp;lt;=N，则其左儿子（即左子树的根结点）的编号为2I；若2I&amp;gt;N，则无左儿子；
&lt;br>    如果2I+1&amp;lt;=N，则其右儿子的结点编号为2I+1；若2I+1&amp;gt;N，则无右儿子。
&lt;br>6). 给定N个节点，能构成h(N)种不同的二叉树，其中h(N)为卡特兰数的第N项，h(n)=C(2*n, n)/(n+1)。
&lt;br>7). 设有i个枝点，I为所有枝点的道路长度总和，J为叶的道路长度总和J=I+2i。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="满二叉树">
 满二叉树
 &lt;a class="anchor" href="#%e6%bb%a1%e4%ba%8c%e5%8f%89%e6%a0%91">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="定义-1">
 定义
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89-1">#&lt;/a>
&lt;/h4>
&lt;p class="tip">除最后一层无任何子节点外，每一层上的所有结点都有两个子结点。也可以这样理解，除叶子结点外的所有结点均有两个子结点。节点数达到最大值，所有叶子结点必须在同一层上。&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="性质-1">
 性质
 &lt;a class="anchor" href="#%e6%80%a7%e8%b4%a8-1">#&lt;/a>
&lt;/h4>
&lt;p class="warn">1) 一颗树深度为h，最大层数为k，深度与最大层数相同，k=h;
&lt;br>2). 叶子数为2h;
&lt;br>3). 第k层的结点数是：2k-1;
&lt;br>4). 总结点数是：2k-1，且总节点数一定是奇数。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="完全二叉树">
 完全二叉树
 &lt;a class="anchor" href="#%e5%ae%8c%e5%85%a8%e4%ba%8c%e5%8f%89%e6%a0%91">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="定义-2">
 定义
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89-2">#&lt;/a>
&lt;/h4>
&lt;p class="tip">若设二叉树的深度为h，除第 h 层外，其它各层 (1～(h-1)层) 的结点数都达到最大个数，第h层所有的结点都连续集中在最左边，这就是完全二叉树。
&lt;br>&lt;br>完全二叉树是效率很高的数据结构，堆是一种完全二叉树或者近似完全二叉树，所以效率极高，像十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能优化，二叉排序树的效率也要借助平衡性来提高，而平衡性基于完全二叉树。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="示例">
 示例
 &lt;a class="anchor" href="#%e7%a4%ba%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-binary-01.png" alt="" width="20%">
&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-binary-02.png" alt="" width="32%">
&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-binary-03.png" alt="" width="33%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="线索化二叉树">
 线索化二叉树
 &lt;a class="anchor" href="#%e7%ba%bf%e7%b4%a2%e5%8c%96%e4%ba%8c%e5%8f%89%e6%a0%91">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://zh.wikipedia.org/wiki/线索二叉树" rel="noopener" target="_blank">wiki&lt;/a>: 在计算机科学中，线索二叉树（或称引线二叉树）是添加了直接指向节点的前驱和后继的指针的二叉树。&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;h4 id="图解与代码">
 图解与代码
 &lt;a class="anchor" href="#%e5%9b%be%e8%a7%a3%e4%b8%8e%e4%bb%a3%e7%a0%81">#&lt;/a>
&lt;/h4>&lt;/div>
 &lt;div class="docsify-example-panel left-panel"style="max-width: 43%; width: 43%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-threaded-binary-01.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/tree/03-01-AVL-tree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/tree/03-01-AVL-tree/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introavl">
 Intro(AVL)
 &lt;a class="anchor" href="#introavl">#&lt;/a>
&lt;/h2>
&lt;p class="tip">&lt;code>平衡二叉树&lt;/code>又称&lt;code>AVL树&lt;/code>。它可以是一颗空树，或者具有以下性质的二叉排序树：它的左子树和右子树的高度之差(&lt;code>平衡因子&lt;/code>)的绝对值不超过1且它的左子树和右子树都是一颗平衡二叉树。因此它也被称为高度平衡树。
&lt;br>查找、插入和删除在平均和最坏情况下的时间复杂度都是 &lt;span class="math inline">\({\color{red}O(\log_2 N)}\)&lt;/span>。增加和删除元素的操作则可能需要借由一次或多次树旋转，以实现树的重新平衡。
&lt;br>AVL 树得名于它的发明者 G. M. Adelson-Velsky 和 Evgenii Landis，他们在1962年的论文《An algorithm for the organization of information》中公开了这一数据结构。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="来源">
 来源
 &lt;a class="anchor" href="#%e6%9d%a5%e6%ba%90">#&lt;/a>
&lt;/h3>
&lt;p class="warn">为什么需要AVL：二叉搜索树一定程度上可以提高搜索效率，但是当原序列有序时，例如序列 A = {1，2，3，4，5，6}，构造二叉搜索树如下图。依据此序列构造的二叉搜索树为右斜树，同时二叉树退化成单链表，搜索效率降低为 &lt;span class="math inline">\({\color{red}O(N)}\)&lt;/span>。&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-01.png" alt="" width="30%">
&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-02.png" alt="" width="33%">&lt;/p>
&lt;p class="warn">在此二叉搜索树中查找元素 6 需要查找 6 次。
&lt;br>二叉搜索树的查找效率取决于树的高度，因此保持树的高度最小，即可保证树的查找效率。同样的序列 A，将其改为图右的方式存储，查找元素 6 时只需比较 3 次，查找效率提升一倍。&lt;/p>
&lt;p class="tip">可以看出当节点数目一定，保持树的左右两端保持平衡，树的查找效率最高。这种左右子树的高度相差不超过 1 的树为平衡二叉树。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="定义">
 定义
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89">#&lt;/a>
&lt;/h3>
&lt;p class="warn">简称平衡二叉树。由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树，根据科学家的英文名也称为 AVL 树&lt;/p>
&lt;p>&lt;strong>示例AVL&lt;/strong>.&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-03.png" alt="" width="30%">&lt;/p>
&lt;p>&lt;strong>反示例AVL&lt;/strong>.&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-no-01.png" alt="" width="30%">
&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-no-02.png" alt="" width="30%">
&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-AVL-no-03.png" alt="" width="28%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="性质">
 性质
 &lt;a class="anchor" href="#%e6%80%a7%e8%b4%a8">#&lt;/a>
&lt;/h3>
&lt;p class="warn">1. 可以是空树。
&lt;br>2. 假如不是空树，任何一个结点的左子树与右子树都是平衡二叉树，并且高度之差的绝对值不超过 1。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="平衡因子">
 平衡因子
 &lt;a class="anchor" href="#%e5%b9%b3%e8%a1%a1%e5%9b%a0%e5%ad%90">#&lt;/a>
&lt;/h3>
&lt;p class="warn">某节点的左子树与右子树的高度(深度)差即为该节点的平衡因子（BF,Balance Factor），平衡二叉树中不存在平衡因子大于 1 的节点。在一棵平衡二叉树中，节点的平衡因子只能取 0 、1 或者 -1 ，分别对应着左右子树等高，左子树比较高，右子树比较高。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/algo/tree/03-02-RB-tree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/algo/tree/03-02-RB-tree/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introred-black">
 Intro(Red-Black)
 &lt;a class="anchor" href="#introred-black">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="定义">
 定义
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="示例">
 示例
 &lt;a class="anchor" href="#%e7%a4%ba%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/algo/tree/tree-rb-demo-01.png" alt="" width="99%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="性质">
 性质
 &lt;a class="anchor" href="#%e6%80%a7%e8%b4%a8">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>每个节点非黑即红。&lt;/li>
&lt;li>根节点是黑色的。&lt;/li>
&lt;li>每个&lt;code>NULL叶结点&lt;/code>是黑色的[示例没画出来]。&lt;/li>
&lt;li>如果一个节点是红色的，那么它的两个子节点都是黑色的。&lt;/li>
&lt;li>从任一节点到叶子节点的所有路径上都包含相同数目的黑色节点(黑高相同)&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h3 id="来源">
 来源
 &lt;a class="anchor" href="#%e6%9d%a5%e6%ba%90">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="平衡因子">
 平衡因子
 &lt;a class="anchor" href="#%e5%b9%b3%e8%a1%a1%e5%9b%a0%e5%ad%90">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="平衡">
 平衡
 &lt;a class="anchor" href="#%e5%b9%b3%e8%a1%a1">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://drive.google.com/file/d/1aZEr0b1O9rww1kvtYZ9v1k3mdLHbwCuA/view?usp=sharing" rel="noopener" target="_blank">https://drive.google.com/file/d/1aZEr0b1O9rww1kvtYZ9v1k3mdLHbwCuA/view?usp=sharing&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/silangquan/article/details/18655795" rel="noopener" target="_blank">https://blog.csdn.net/silangquan/article/details/18655795&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/corner/assmebly/book/example/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/assmebly/book/example/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intro汇编语言第4版王爽-阅读笔记">
 Intro(汇编语言(第4版)王爽-阅读笔记)
 &lt;a class="anchor" href="#intro%e6%b1%87%e7%bc%96%e8%af%ad%e8%a8%80%e7%ac%ac4%e7%89%88%e7%8e%8b%e7%88%bd-%e9%98%85%e8%af%bb%e7%ac%94%e8%ae%b0">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="91-复制指令8bc3到指定位置">
 9.1 复制指令(8BC3)到指定位置
 &lt;a class="anchor" href="#91-%e5%a4%8d%e5%88%b6%e6%8c%87%e4%bb%a48bc3%e5%88%b0%e6%8c%87%e5%ae%9a%e4%bd%8d%e7%bd%ae">#&lt;/a>
&lt;/h3> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;p class="warn">有如下程序段,添写两条指令,使该程序在运行中将。处的一条指令复制到s0处。&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;h6 id="question" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="question" class="docsify-tabs__tab" data-tab="question">question&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="question">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="masm" data-line="7-8" class="language-masm line-numbers" style="max-height: none">&lt;code class="language-masm">;
assume cs:codesg
codesg segment
 s: mov ax, bx ; mov ax,bx的机器码占两个字节
 mov si, offset s
 mov di, offset s0
 ...
 ...
 s0: nop ; nop 的机器码占一个字节
 nop
codesg ends
end s
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;h6 id="masm" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="nasm" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="masm" class="docsify-tabs__tab" data-tab="masm">masm&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="masm">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="masm" data-line="7-8" class="language-masm line-numbers" style="max-height: none">&lt;code class="language-masm">;
assume cs:codesg
codesg segment
 s: mov ax, bx
 mov si, offset s
 mov di, offset s0
 mov ax, cs:[si]
 mov cs:[di], ax
 s0: nop
 nop
codesg ends
end s
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="nasm" class="docsify-tabs__tab" data-tab="nasm">nasm&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="nasm">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="nasm" data-line="" class="language-nasm line-numbers" style="max-height: none">&lt;code class="language-nasm">section .text
 global _start

_start:
 mov ax, 2h
 mov bx, 3h
 times 3 add ax,bx

 mov ax, 4c00h
 int 21h

section .data
 msg db 'Hello, world!$'
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>&lt;/div>&lt;/div>

&lt;/li>
&lt;li>
&lt;h3 id="92-利用jcxz指令查找内存中的内容">
 9.2 利用jcxz指令查找内存中的内容
 &lt;a class="anchor" href="#92-%e5%88%a9%e7%94%a8jcxz%e6%8c%87%e4%bb%a4%e6%9f%a5%e6%89%be%e5%86%85%e5%ad%98%e4%b8%ad%e7%9a%84%e5%86%85%e5%ae%b9">#&lt;/a>
&lt;/h3> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;p class="warn">补全程序,利用 jcxz 指令，实现在内存2000H 段中查找第一个值为0的字节,找到后,将它的偏移地址存储在 dx 中。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/corner/encoding/varint/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/encoding/varint/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introvarint-encoding">
 Intro(Varint-encoding)
 &lt;a class="anchor" href="#introvarint-encoding">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="定义描述">
 定义描述
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">varint 类似于 utf-8，varchar等长度不定。顾名思义，属于变长的 int。对于一个 int 类型的数据来说，一般都为四个字节(固长)。所以变长的话就是将固定的四个字节中浪费的那部分去掉，比如对于整形 2 来说对应的二进制为 &lt;span class="math inline">\(00000000\space00000000\space00000000\space{\color{red}00000010}\)&lt;/span> 前面的三个字节都为0，而且完全可以使用一个字节表示，此处对于整数2 来说，前三个字节就是浪费。所以出现了&lt;code>varint&lt;/code>。使用少量字节来表示整数。使用定义型的方式描述就是：&lt;strong>采用不定长的字节来编码或序列化一个整数&lt;/strong>。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="编码过程">
 编码过程
 &lt;a class="anchor" href="#%e7%bc%96%e7%a0%81%e8%bf%87%e7%a8%8b">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 将一个 int 型的数据二进制表示，从后至前，依次取 7 位，与 varint 特性 msb 占 1 位组成一个字节，直到无效字节(也就是前面全是零)，然后将这些字节按照小端字节序排列。形成一个新的数字，这个过程中会丢弃浪费字节，达到压缩的目的。
&lt;br>&lt;br>&lt;span style='color:red'>varint msb 最高有效位为 1 表示后面都得字节属于当前值，为 0 表示当前字节是最后一部分。用来区分 varint 值边界。&lt;/span>
&lt;br>&lt;br>&lt;span style='color:red'>对于负数来说，编码过程并没有什么区别，只是因为负数最高位一直为 1，所以不存在浪费，也就是 vaint 对于负数压缩无效，字节不减反增。原本 -2 可以使用 8 个字节表示，但最终用使用了 10 个字节。所以在 ProtoBuf 中一般只处理 无符号 64bit 值，签名如：&lt;code>func EncodeVarint(v uint64) []byte {}&lt;/code>。所以我们此处传入的 -2 其实是当一个无符号正值处理的，负数的 varint 编码没有意义，我们应当避免直接对负值进行 varint 编码。&lt;/span>&lt;span style='color:blue'>而是先进行 


 
 

 
 
 
 
 
 
 
 &lt;a href='../zigzag/' rel="noopener" class="internal-link" data-src="../zigzag/">zigzag 编码&lt;/a> 映射后在进行 varint处理。&lt;/span>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/corner/encoding/zigzag/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/encoding/zigzag/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introzigzag-encoding">
 Intro(ZigZag-encoding)
 &lt;a class="anchor" href="#introzigzag-encoding">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="定义描述">
 定义描述
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">正如 


 
 

 
 
 
 
 
 
 
 &lt;a href='../varint/' rel="noopener" class="internal-link" data-src="../varint/">varint 编码&lt;/a> 中所述，它对于负数来说显得手足无措，心有余而力不足。&lt;strong>zigzag 编码&lt;/strong> 就是用来弥补 varint 的缺陷的。它会将负数映射成正值（但是不需要额外的映射表），比如：&lt;code>(0 = 0, -1 = 1, 1 = 2, -2 = 3, 2 = 4, -3 = 5, 3 = 6 ...)&lt;/code>，从而能够使用 varint 继续编码。zigzag 编码的大致原理就是采用异或操作，将阻碍压缩的 1 进行消除。
&lt;br>&lt;br>&lt;span style='color:blue'>没有特别说明的都已 32 bit 进行阐述。&lt;/span>&lt;/p>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> 异或操作 &lt;/p>&lt;p> 异或运算(&lt;code>XOR&lt;/code> | &lt;code>^&lt;/code>)，相同为 0，不同为 1。并且异或操作有如下特性：
&lt;br>&lt;span style='padding-left:2.0em'/>&lt;code>1).&lt;/code> 任何数（0，1）与 1 进行异或的结果相当于取反，比如 0 ^ 1 = 1, 1 ^ 1 = 0。
&lt;br>&lt;span style='padding-left:2.0em'/>&lt;code>2).&lt;/code> 任何数（0，1）与 0 进行异或的结果相当于不变，比如 0 ^ 0 = 0, 1 ^ 0 = 1。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/corner/numeration/complement/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/numeration/complement/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introcomplement">
 Intro(Complement)
 &lt;a class="anchor" href="#introcomplement">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="重新认识计算机中的数字表示">
 重新认识计算机中的数字表示
 &lt;a class="anchor" href="#%e9%87%8d%e6%96%b0%e8%ae%a4%e8%af%86%e8%ae%a1%e7%ae%97%e6%9c%ba%e4%b8%ad%e7%9a%84%e6%95%b0%e5%ad%97%e8%a1%a8%e7%a4%ba">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> 主要以一个字节，8比特位进行分析 &lt;/p>&lt;p> 首先要知道计算机中的数字表示有空间限制，比如 java 中 byte 类型就用一个字节(8 bit)表示，而 int 得用 4byte（32 bit）。而且 java 默认都是有符号的，也即第一个比特位表示符号，一个byte 类型的变量可表示的值就是 &lt;span class="math inline">\(00000000\)&lt;/span> - &lt;span class="math inline">\(11111111\)&lt;/span>。
&lt;br>&lt;br>&lt;span style='color: blue'>还有一点至关重要，就是进位后的值超出 8 位后会截断。比如 &lt;span class="math inline">\(11111111 + 1 = 1{\hspace{0.5em}}00000000 ==截断==> 00000000 \)&lt;/span>&lt;/span>，要不然就没法循环了，跟钟表一样，到极限得归位。
&lt;br>&lt;br>至于这些值表示的实际意义，可以在下面慢慢进行分析。（先不用考虑补码）
&lt;br>&lt;code>1).&lt;/code>: 首先分析正数，总共 8 位，一个符号位占一个[0],剩下的 7 位表示值的话就就是 &lt;span class="math inline">\(00000000\)&lt;/span> - &lt;span class="math inline">\(01111111\)&lt;/span> 表示数值 0 到 127，这个毋庸置疑的。
&lt;br>&lt;code>2).&lt;/code>: 不管一个负数怎么表示，都应该符合我们的理性认知。比如 -1 + 1 的值肯定是 0 的。
&lt;br>&lt;code>3).&lt;/code>: 现在有了正数值比如 1 (&lt;span class="math inline">\(00000001\)&lt;/span>)，加一操作后肯定等于 0。也即 &lt;span class="math inline">\(00000001\)&lt;/span> + &lt;span class="math inline">\(8(*) = 00000000\)&lt;/span>
&lt;br>&lt;code>4).&lt;/code>: 目前只有让 &lt;span class="math inline">\(8(*)\)&lt;/span> 这个未知值在加完后整体位溢出，被截断，才能达到加完一个值后更小。
&lt;br>&lt;code>5).&lt;/code>: 所以此处的 &lt;span class="math inline">\(8(*)\)&lt;/span> 二进制表示应该是 &lt;span class="math inline">\(11111111\)&lt;/span>，加完 &lt;span class="math inline">\(00000001\)&lt;/span> 后得到 &lt;span class="math inline">\(1{\hspace{0.5em}}00000000\)&lt;/span>，截断，然后正好等于 &lt;span class="math inline">\(00000000\)&lt;/span>。
&lt;br>&lt;code>6).&lt;/code>: 所以才让这个二进制 &lt;span class="math inline">\(11111111\)&lt;/span> 表示的 -1。
&lt;br>&lt;br>&lt;code>7).&lt;/code>: 其他情况依次了类推，重要的是理解截断才能循环。再举个例子（-128）。
&lt;br>&lt;code>8).&lt;/code>: 已知上述得出的 -1&lt;span class="math inline">\((11111111)\)&lt;/span>，和127&lt;span class="math inline">\((01111111)\)&lt;/span>，所以 -128 &lt;span class="math inline">\(8(*)\)&lt;/span> + 127 &lt;span class="math inline">\(01111111\)&lt;/span> = -1 &lt;span class="math inline">\(11111111\)&lt;/span>
&lt;br>&lt;code>9).&lt;/code>: 后面的值在二进制表示上要比被加数大，所以这次不用截断，给 &lt;span class="math inline">\(8(*)\)&lt;/span> 值设为 &lt;span class="math inline">\(10000000\)&lt;/span> 即可。也就是 -128 = &lt;span class="math inline">\(10000000\)&lt;/span>
&lt;br>&lt;br>为了更好的理解数据的分布，可以画一个圆来表示，方便记忆。范围: &lt;span class="math inline">\([{\color{red}-(2^{8*size-1})}\)&lt;/span> , &lt;span class="math inline">\({\color{red}(2^{8*size-1})-1}]\)&lt;/span>，size = 1 时：[-128, 127].
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/corner/numeration/complement/cpt-byte-show-02.png" alt="" width="100%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/corner/numeration/endianness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/corner/numeration/endianness/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introendianness--字节序--端序--尾序">
 Intro(ENDIANNESS | 字节序 | 端序 | 尾序)
 &lt;a class="anchor" href="#introendianness--%e5%ad%97%e8%8a%82%e5%ba%8f--%e7%ab%af%e5%ba%8f--%e5%b0%be%e5%ba%8f">#&lt;/a>
&lt;/h2>
&lt;p class="warn">


 &lt;a href="https://zh.wikipedia.org/wiki/字节序" rel="noopener" target="_blank">参考 wiki&lt;/a>，记录这个是因为老是记不住，天天查，所以已自己比较容易记忆的方式将其记录下来，动手过一遍，避免胡翻乱找。
&lt;br>&lt;br>字节序分为大端（Big）和小端（Little）
&lt;br>&lt;span style='padding-left:2em'>&lt;strong>高位低地址，低位高地址被称为大端序（Big   ）&lt;/strong>，参考下图可以理解为 &lt;strong>顺序放置&lt;/strong>。&lt;/span>
&lt;br>&lt;span style='padding-left:2em'>&lt;strong>低位低地址，高位高地址被称为小端序（Little）&lt;/strong>，参考下图可以理解为 &lt;strong>逆序放置&lt;/strong>。&lt;/span>
&lt;br>&lt;br>大小端序出现的背景：
&lt;br>&lt;span style='padding-left:2em'>计算机都是从低位往高位读取字节数据，而且方便处理，所以出现了小端序。但是小端序不符合人类的阅读习惯，且除了计算机内部之外，其他场合几乎都是大端字节序，比如网络传输一般采用大端序，也被称为 &lt;strong>网络字节序&lt;/strong>，或 &lt;strong>网络序&lt;/strong>。有 


 &lt;a href="https://zh.wikipedia.org/wiki/Berkeley套接字" rel="noopener" target="_blank">Berkeley套接字&lt;/a> 定义了一组转换函数，用于 16 和 32 位整数在网络序和本机字节序之间的转换。htonl(Host to Network Long(4Byte))，htons(Host to Network Short(2Byte))用于本机序转换到网络序；ntohl，ntohs用于网络序转换到本机序。
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/corner/numeration/endianness/endianness-layout-01.png" alt="" width="100%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="检测处理器字节序">
 检测处理器字节序
 &lt;a class="anchor" href="#%e6%a3%80%e6%b5%8b%e5%a4%84%e7%90%86%e5%99%a8%e5%ad%97%e8%8a%82%e5%ba%8f">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 使用 C 语言程序即可验证：定义一个整形值&lt;code>int num = 1 = 0x 0000 0000 0000 0001;&lt;/code>，然后强转成字符指针，取第一个字符（1 Byte）判断是否为 0，(小端逆序放置为 1，大端为 0)。
&lt;br>编辑如下代码为 endian.c
&lt;br>编译运行：&lt;code>gcc endian.c -o endian &amp;amp;&amp;amp; ./endian&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" data-file="endian.c" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">#include &amp;lt;stdio.h&amp;gt;

int main(){
 unsigned int num = 1;
 char *ptr = (char*) &amp;amp;num;

 if (*ptr) printf(&amp;quot;Little\n&amp;quot;);
 else printf(&amp;quot;Big\n&amp;quot;);

 return 0;
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F" rel="noopener" target="_blank">https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/cmake/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/cmake/</guid><description>&lt;h2 id="cmake-100">
 CMAKE &amp;#x1f4af;
 &lt;a class="anchor" href="#cmake-100">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="基础">
 基础
 &lt;a class="anchor" href="#%e5%9f%ba%e7%a1%80">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="简介">
 简介
 &lt;a class="anchor" href="#%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;/ul>
&lt;p class="warn">gcc &lt;/br>gcc是用来编译c文件的编译器。简单来说就是给他输入一个（或几个）c文件，它可以输出一个可执行文件。当你的程序只有一个源文件时，直接就可以用gcc命令编译它。但是当你的程序包含很多个源文件时，用gcc命令逐个去编译时，容易混乱而且工作量大。&lt;/p>
&lt;p class="warn">make &lt;/br> 因此出现了make工具。它本身没有编译和链接功能。但是它可以按照&lt;code>Makefile&lt;/code>文件中的命令调用gcc来编译工程。有了make，我们就不用一个一个文件去编译，只要把他们的编译指令都写在Makefile中，然后make就可以一键完成。&lt;/p>
&lt;p class="warn">cmake &lt;/br> 为了进一步简化Makefile的书写，出现了&lt;code>cmake&lt;/code>。cmake根据CMakeLists.txt文件生成项目的makefile，而且写法也大大简化。总的来说，CMake，make，gcc组成一个工具链，让我们在构建项目时只需要编写源文件以及CmakeLists.txt即可。它的流程如下：&lt;/p>
&lt;div class="mermaid">graph LR
A(编写CMakeLists.txt)--&amp;gt;B((Cmake))
B--&amp;gt;C(Makefile等配置文件)
C--&amp;gt;D((make))
D--&amp;gt;F((gcc))
E(源文件)--&amp;gt;F
F--&amp;gt;G(可执行程序)
&lt;/div>&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/clion-base-step-01.png" alt="" width="70%">
&lt;img src="https://archive-w.netlify.app/.images/devops/build/clion-base-step-02.png" alt="" width="70%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="基本规则">
 基本规则
 &lt;a class="anchor" href="#%e5%9f%ba%e6%9c%ac%e8%a7%84%e5%88%99">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>
&lt;h5 id="变量">
 变量
 &lt;a class="anchor" href="#%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h5>
&lt;/li>
&lt;/ol>
&lt;p>使用&lt;code>${}&lt;/code>方式取值，&lt;strong>变量名区分大小写&lt;/strong>（指令名不区分大小写）&lt;/br>
定义一个变量可以用&lt;strong>SET&lt;/strong>指令：&lt;/br>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">SET(valname main.c src1.c src2.c)
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>这条语句就是定一个一个名字叫&lt;code>valname&lt;/code>的变量，它的值是&lt;code>main.c src1.c src2.c&lt;/code>;相当于是&lt;code>valname=main.c src1.c src2.c&lt;/code>&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>系统预定义的变量&lt;/strong>&lt;/p>
&lt;p>在我们使用PROJECT指令指定工程名后，CMake会自动生成两个变量;可以在 CMakeCache.txt 中看到定义。&lt;/p>
&lt;ul>
&lt;li>&lt;em>&lt;strong>${pname}_BINARY_DIR&lt;/strong>&lt;/em>: 可执行程序目录，比如&lt;code>step1_BINARY_DIR&lt;/code>,其实就是执行cmake命令时的当前目录，比如在build/外部编译，那么它就是build的绝对路径 &lt;/br>&lt;/li>
&lt;li>&lt;em>&lt;strong>${pname}_SOURCE_DIR&lt;/strong>&lt;/em>: 源文件目录，比如&lt;code>step1_SOURCE_DIR&lt;/code>,就是主CmakeLists.txt所在的绝对路径。&lt;/li>
&lt;/ul>
&lt;p>我们可以使用他们。同时系统还会帮我们预定义两个与工程名无关的变量，他们的内容与上述两个变量相同，但是好处是变量名不会因为工程名改变而改变，因此推荐使用：&lt;/br>&lt;/p>
&lt;ul>
&lt;li>&lt;em>&lt;strong>PROJECT_BINARY_DIR&lt;/strong>&lt;/em> : 可执行程序目录&lt;/br>&lt;/li>
&lt;li>&lt;em>&lt;strong>PROJECT_SOURCE_DIR&lt;/strong>&lt;/em> : 源文件目录&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;ol start="2">
&lt;li>
&lt;h5 id="指令">
 指令
 &lt;a class="anchor" href="#%e6%8c%87%e4%bb%a4">#&lt;/a>
&lt;/h5>
&lt;/li>
&lt;/ol>
&lt;p class="warn">指令就是CMake里的函数。它的名称不区分大小写，调用的格式如下:
* 指令名（参数1，参数2，参数3）
参数之间用空格或者分号隔开。
如果参数中包含括号，可以使用双引号将参数分开，如下所示：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">SET(val fu n.c) # 指令会认为是'fu n.c'是两个参数
SET(val &amp;quot;fu n.c&amp;quot;) # 使用双引号避免错误
&lt;/code>&lt;/pre>&lt;/div>
&lt;ol start="3">
&lt;li>
&lt;h5 id="使用">
 使用
 &lt;a class="anchor" href="#%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h5>
&lt;/li>
&lt;/ol>
&lt;p class="warn">CMake命令用于生成中间文件，使用时要传入CmakeLists.txt文件所在的目录。如果在主目录下直接生成配置文件，&lt;strong>内部构建&lt;/strong>，这样做的坏处是使代码文件与中间文件相互混淆，因此最好的做法时&lt;strong>外部构件&lt;/strong>。&lt;br>
如下所示：在主目录下&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/gcc/library/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/gcc/library/</guid><description>&lt;h2 id="linux共享库静态库动态链接库">
 Linux共享库，静态库，动态链接库
 &lt;a class="anchor" href="#linux%e5%85%b1%e4%ba%ab%e5%ba%93%e9%9d%99%e6%80%81%e5%ba%93%e5%8a%a8%e6%80%81%e9%93%be%e6%8e%a5%e5%ba%93">#&lt;/a>
&lt;/h2>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/gcc/lib/lib-01.png" alt="">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="介绍">
 介绍
 &lt;a class="anchor" href="#%e4%bb%8b%e7%bb%8d">#&lt;/a>
&lt;/h3>
&lt;p class="warn">程序函数库可分为3种类型：静态函数库（static libraries）、共享函数库（shared libraries）、动态加载函数库（dynamically loaded libraries):&lt;/p>
&lt;ol>
&lt;li>静态函数库，是在程序执行前就加入到目标程序中去了 ；&lt;/li>
&lt;li>动态函数库同共享函数库是一个东西（在linux上叫共享对象库， 文件后缀是.so ，windows上叫动态加载函数库， 文件后缀是.dll）&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>
&lt;p>linux中明明系统的共享库的规则&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/gcc/lib/lib-02.png" alt="">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h3>
&lt;p>&lt;strong>libhello.c&lt;/strong>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">/* libhello.c - demonstrate library use. */
#include &amp;lt;stdio.h&amp;gt;

void hello(void) {
 printf(&amp;quot;Hello, library world.\n&amp;quot;);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;strong>libhello.h&lt;/strong>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">/* libhello.h - demonstrate library use. */

void hello(void);
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="staticshared" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="module" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="staticshared" class="docsify-tabs__tab" data-tab="[STATIC、SHARED]">[STATIC、SHARED]&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="staticshared">
&lt;p>&lt;strong>demo_use.c&lt;/strong>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/gradle/gradle/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/gradle/gradle/</guid><description>&lt;h2 id="gradle入门到实战">
 Gradle入门到实战
 &lt;a class="anchor" href="#gradle%e5%85%a5%e9%97%a8%e5%88%b0%e5%ae%9e%e6%88%98">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="groovy语言的学习">
 Groovy语言的学习
 &lt;a class="anchor" href="#groovy%e8%af%ad%e8%a8%80%e7%9a%84%e5%ad%a6%e4%b9%a0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">学习Geadle我们需要先来学习一下Groovy，很多同学估计听说过Groovy语言，有的也许没听说过，其实我们每天在配置Gradle的时候就是在跟Groovy接触了。Groovy是一门jvm语言，最终编译成class文件然后在jvm上执行，Java语言的特性Groovy都支持，我们可以混写Java和Groovy，就是在同一文件中可以混写， 注意，这里与Java和Kotlin可不一样，Java和Kotlin是可以互相调用，而不能在同一文件混写 。
&lt;br>&lt;br>Groovy的优势是什么呢？Groovy增强了Java的很多功能。比如解析xml文件，文件读写等，Groovy只需要几行代码就能搞定，而如果用Java则需要几十行代码，简单说就是使用Groovy实现某些功能比Java要少些很多代码。
&lt;br>&lt;br>好了，说了那么多&amp;quot;废话&amp;quot;，下面就具体来了解一下Groovy语言，我们只需要了解其中核心的一些使用就可以了，没必要完全了解，作为一门语言Groovy也算比较复杂的，但是我们学习Groovy是为了编写Gradle插件那就只需要了解其核心部分就可以了，其实从我的经验来说学习Groovy更多是为了写更少的代码来实现一些功能，否则我直接用Java写不就完了。&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="1groovy的变量和方法声明">
 1.Groovy的变量和方法声明
 &lt;a class="anchor" href="#1groovy%e7%9a%84%e5%8f%98%e9%87%8f%e5%92%8c%e6%96%b9%e6%b3%95%e5%a3%b0%e6%98%8e">#&lt;/a>
&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>Groovy使用def来声明变量，声明变量可以不加类型，运行的时候可以自动推断出变量类型，并且声明语句可以不加分号结尾，如下：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="groovy" data-line="" class="language-groovy line-numbers" style="max-height: none">&lt;code class="language-groovy">def i = 10
def str = &amp;quot;hello groovy&amp;quot;
def d = 1.25
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>def同样用来定义函数，Groovy中函数返回值可以是无类型的：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="groovy" data-line="" class="language-groovy line-numbers" style="max-height: none">&lt;code class="language-groovy">def showName(){
 &amp;quot;wang lei&amp;quot; //最后一行执行结果默认作为函数返回值，可以不加return
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>如果我们指定了函数的返回值类型，那么可以不加def关键字：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="groovy" data-line="" class="language-groovy line-numbers" style="max-height: none">&lt;code class="language-groovy">//定义函数
String showName(){
 &amp;quot;wang lei&amp;quot; //最后一行执行结果默认作为函数返回值
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h4 id="2groovy的字符串">
 2.Groovy的字符串
 &lt;a class="anchor" href="#2groovy%e7%9a%84%e5%ad%97%e7%ac%a6%e4%b8%b2">#&lt;/a>
&lt;/h4>
&lt;p class="tip"> Groovy中字符串分为三种，我们一个个来看。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/gradle/usage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/gradle/usage/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="目录结构">
 目录结构
 &lt;a class="anchor" href="#%e7%9b%ae%e5%bd%95%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;p class="warn">Gradle uses two main directories to perform and manage its work: the Gradle User Home directory and the Project Root directory.


 &lt;a href="https://docs.gradle.org/current/userguide/directory_layout.html" rel="noopener" target="_blank">参考&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/gradle/usage/gradle-usage-02.png" alt="" width="49%">
&lt;img src="https://archive-w.netlify.app/.images/devops/build/gradle/usage/gradle-usage-03.png" alt="" width="50%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="初始化脚本">
 初始化脚本
 &lt;a class="anchor" href="#%e5%88%9d%e5%a7%8b%e5%8c%96%e8%84%9a%e6%9c%ac">#&lt;/a>
&lt;/h2>
&lt;p class="warn">在项目构建之前进行初始化。


 &lt;a href="https://docs.gradle.org/current/userguide/init_scripts.html#init_scripts" rel="noopener" target="_blank">参考&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="基本用法">
 基本用法
 &lt;a class="anchor" href="#%e5%9f%ba%e6%9c%ac%e7%94%a8%e6%b3%95">#&lt;/a>
&lt;/h3>
&lt;p class="warn">初始化脚本（又名init 脚本）与 Gradle 中的其他脚本类似。但是，这些脚本是在构建开始之前运行的。
&lt;br>以下是几种可能的用途：&lt;/p>
&lt;ul>
&lt;li>设置企业范围的配置，例如在哪里可以找到自定义插件。&lt;/li>
&lt;li>根据当前环境设置属性，例如开发人员的计算机与持续集成服务器。&lt;/li>
&lt;li>提供构建所需的有关用户的个人信息，例如存储库或数据库身份验证凭据。&lt;/li>
&lt;li>定义特定于计算机的详细信息，例如 JDK 的安装位置。&lt;/li>
&lt;li>注册构建监听器。希望监听 Gradle 事件的外部工具可能会发现这很有用。&lt;/li>
&lt;li>注册构建记录器。您可以自定义 Gradle 如何记录它生成的事件。&lt;/li>
&lt;/ul>
&lt;p class="tip"> 初始化脚本的一个主要限制是它们无法访问buildSrc项目中的类。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="使用初始化脚本">
 使用初始化脚本
 &lt;a class="anchor" href="#%e4%bd%bf%e7%94%a8%e5%88%9d%e5%a7%8b%e5%8c%96%e8%84%9a%e6%9c%ac">#&lt;/a>
&lt;/h3>
&lt;p class="warn">使用 init 脚本有多种方法：
&lt;br>如果找到多个 init 脚本，它们都将按照下面指定的顺序执行。
&lt;br>给定目录中的脚本按字母顺序执行。例如，工具可以在命令行上指定一个 init 脚本，并在主目录中指定另一个 init 脚本来定义环境。这两个脚本都会在 Gradle 执行时运行。&lt;/p>
&lt;ul>
&lt;li>在命令行上指定一个文件。命令行选项后面是&lt;code>-I,--init-script &lt;/code>的路径。(命令行选项可以出现多次，每次都会添加另一个初始化脚本。如果命令行上指定的任何文件不存在，构建将失败。)&lt;/li>
&lt;li>init.gradle将一个名为（或init.gradle.ktsKotlin）的文件放入该目录中。$GRADLE_USER_HOME/&lt;/li>
&lt;li>.gradle将以（或.init.gradle.ktsKotlin）结尾的文件放入目录中。$GRADLE_USER_HOME/init.d/&lt;/li>
&lt;li>.gradle将以（或.init.gradle.ktsKotlin）结尾的文件放入Gradle 发行版的目录中。$GRADLE_HOME/init.d/&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="编写初始化脚本">
 编写初始化脚本
 &lt;a class="anchor" href="#%e7%bc%96%e5%86%99%e5%88%9d%e5%a7%8b%e5%8c%96%e8%84%9a%e6%9c%ac">#&lt;/a>
&lt;/h3>
&lt;p class="warn">与 Gradle 构建脚本一样，init 脚本是 Groovy 或 Kotlin 脚本。每个 init 脚本都有一个与其关联的


 &lt;a href="https://docs.gradle.org/current/dsl/org.gradle.api.invocation.Gradle.html" rel="noopener" target="_blank">Gradle&lt;/a>实例。初始化脚本中的任何属性引用和方法调用都将委托给此Gradle实例。
&lt;br>每个 init 脚本还实现


 &lt;a href="https://docs.gradle.org/current/dsl/org.gradle.api.Script.html" rel="noopener" target="_blank">Script&lt;/a>接口。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/make/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/make/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intromake">
 Intro(make)
 &lt;a class="anchor" href="#intromake">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="demo">
 demo
 &lt;a class="anchor" href="#demo">#&lt;/a>
&lt;/h3> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 60%; width: 60%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="makefile" data-line="" class="language-makefile line-numbers" style="max-height: none">&lt;code class="language-makefile"># makefile 对空格相当挑剔，必须是制表符
# https://stackoverflow.com/questions/24145650/makefile6-missing-separator-stop
OBJS = main.o tool1.o tool2.o
CC = gcc
CFLAGS += -c -Wall -g

mytool: $(OBJS)
 $(CC) $^ -o $@

%.o: %.c
 $(CC) $^ $(CFLAGS) -o $@

.PHONY: clean
clean:
 # 禁用回显使用@，或者在外部 make -s clean
 # https://stackoverflow.com/questions/9967105/suppress-echo-of-command-invocation-in-makefile
 @$(RM) *.o mytool -r
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 40%; width: 40%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/make-process-01.png" alt="" width="85%">&lt;/p>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>


 &lt;a href="https://github.com/junegunn/fzf/blob/master/Makefile" rel="noopener" target="_blank">https://github.com/junegunn/fzf/blob/master/Makefile&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="spec">
 Spec
 &lt;a class="anchor" href="#spec">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="rule">
 rule
 &lt;a class="anchor" href="#rule">#&lt;/a>
&lt;/h4>
&lt;p class="warn">Makefile文件由一系列的规则(rules)组成。每条规则的形式如下：
&lt;br>&lt;code>&amp;lt;target&amp;gt; : &amp;lt;prerequisites&amp;gt;&lt;/code>
&lt;br>&lt;code>[tab][commands]&lt;/code>
&lt;br>&lt;br>上面第一行冒号前面的部分，叫做&amp;quot;目标&amp;quot;（target），冒号后面的部分叫做&amp;quot;前置条件&amp;quot;（prerequisites）；第二行必须由一个tab键起首，后面跟着&amp;quot;命令&amp;quot;（commands）。
&lt;br>&amp;ldquo;目标&amp;quot;是必需的，不可省略；&lt;span style='color: blue'>&amp;ldquo;前置条件&amp;quot;和&amp;quot;命令&amp;quot;都是可选的，但是两者之中必须至少存在一个&lt;/span>。每条规则就明确两件事：构建目标的前置条件是什么，以及如何构建。举例如下：
&lt;br>&lt;br>&lt;code>a.txt: b.txt c.txt&lt;/code>
&lt;br>&lt;code> cat b.txt c.txt &amp;gt; a.txt&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/build/maven/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/build/maven/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="maven分享">
 MAVEN分享
 &lt;a class="anchor" href="#maven%e5%88%86%e4%ba%ab">#&lt;/a>
&lt;/h2>
&lt;p class="warn">今天这次分享的主要就是maven构建工具使用的一些经验， 和大家起分享，交流一下。也是为了日后能够更加灵活的使用。内容中也包括我原来对maven存在的误解和疑问的一些答疑。以交流学习，整理归纳为主。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="tips">
 Tips
 &lt;a class="anchor" href="#tips">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>运行mvn compile 会执行 clean 吗? 运行 package 会执行 compile吗?&lt;/li>
&lt;li>optional,provided 区别?&lt;/li>
&lt;li>既然maven有自带的依赖仲裁机制，为什么还会出现依赖冲突?&lt;/li>
&lt;li>mvn 依赖可以定义的位置及加载顺序，远程仓库定义的位置及加载顺序。mirrorOf实际意义?&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h3 id="介绍一笔带过">
 介绍（一笔带过）
 &lt;a class="anchor" href="#%e4%bb%8b%e7%bb%8d%e4%b8%80%e7%ac%94%e5%b8%a6%e8%bf%87">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">maven 是继 ant 之后apache开源的软件构建工具，由绑定在生命周期上的插件辅助完成构建任务，主要的
功能包括解决依赖，集成测试，编译项目，定制化资源打包发布等。
介绍，下载地址，使用方式。
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="settingsxml-介绍">
 settings.xml 介绍
 &lt;a class="anchor" href="#settingsxml-%e4%bb%8b%e7%bb%8d">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">&amp;lt;localRepository&amp;gt;
&amp;lt;pluginGroups&amp;gt;
 配置插件的groupId。为的是单独执行插件的时候，可以简单调用。
 1，全路径执行。2，如何配置省略执行，3，自带的没有配置，为什么可以省略执行 4,prefix
&amp;lt;proxies&amp;gt;
&amp;lt;servers&amp;gt; 将pluginGroups中默认的标签解释一下
&amp;lt;mirrors&amp;gt;
 &amp;lt;mirror&amp;gt;
 &amp;lt;mirrorOf&amp;gt;
&amp;lt;profile&amp;gt; -- 属性压制
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="pomxml介绍">
 POM.xml介绍
 &lt;a class="anchor" href="#pomxml%e4%bb%8b%e7%bb%8d">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">&amp;lt;relativePath/&amp;gt;
 查找parent路径优先级； 指定的位置 &amp;gt; 本地仓库 &amp;gt; 远程仓库 
 1,当为空标签得时候，默认从本地仓库查找没有的话再从远程，
 2,不写得时候这个值默认为 ../pom.xml，也就是他上级路径得pom.xml.

&amp;lt;properties&amp;gt;
&amp;lt;dependencyManagement&amp;gt;
&amp;lt;dependencies&amp;gt;
 &amp;lt;dependency&amp;gt;
 &amp;lt;scope&amp;gt;
 &amp;lt;type&amp;gt;
 &amp;lt;classifier&amp;gt;
&amp;lt;build&amp;gt;
 &amp;lt;filters&amp;gt;
 &amp;lt;filter&amp;gt;
 &amp;lt;resource&amp;gt;
 &amp;lt;filtering&amp;gt;true|false
 &amp;lt;plugins&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="properties-引用的各种形式">
 properties 引用的各种形式，${},@@
 &lt;a class="anchor" href="#properties-%e5%bc%95%e7%94%a8%e7%9a%84%e5%90%84%e7%a7%8d%e5%bd%a2%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">https://maven.apache.org/pom.html#properties

resources 过滤或加载顺序
1,基本使用。
2，属性优先级
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="maven特性">
 maven特性
 &lt;a class="anchor" href="#maven%e7%89%b9%e6%80%a7">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">生命周期，
继承与聚合，，
https://maven.apache.org/pom.html#a-final-note-on-inheritance-v-aggregation
 继承通过申明&amp;lt;parent&amp;gt;标签来定义。
依赖机制

&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="问题答疑">
 问题答疑
 &lt;a class="anchor" href="#%e9%97%ae%e9%a2%98%e7%ad%94%e7%96%91">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" class="language-markup line-numbers" style="max-height: none">&lt;code class="language-markup">1, 运行mvn compile 会执行 clean吗？运行package 会执行 compile吗？
 不会，因为查看文档发现 compile 阶段 跟 clean 阶段不属于同一个声明周期【分组】。
 或者执行命令也可发现在compile命令下，不会调用clean相关插件。

2, optional ,provided 区别，
 optional 表示可选依赖传递，可以理解为默认排除
 provided 表示依赖必选，但是使用方提供，

3，既然maven有自带的依赖仲裁机制，为什么还会出现依赖冲突？


4，mvn 依赖可以在哪些地方定义？最终生效的是那部分？
 1, &amp;lt;dependency&amp;gt; , &amp;lt;repository&amp;gt; 的定义是有顺序的。
 &amp;lt;dependency source&amp;gt; like repository,mirror,&amp;lt;profile&amp;gt;
 pom.dependency &amp;gt; profile.dependency &amp;gt; parent

 2,远程仓库定义
 settings &amp;gt; pom.profile &amp;gt; pom.repository
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/build/maven-project-dependency.png" alt="" width="70%">
&lt;img src="https://archive-w.netlify.app/.images/devops/build/maven-pull-process.png" alt="nihao" width="70%" title="repo">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/k8s/example/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/k8s/example/</guid><description>&lt;h2 id="multiple-containers-in-single-pod">
 multiple containers in single pod
 &lt;a class="anchor" href="#multiple-containers-in-single-pod">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="yaml" data-line="" class="language-yaml line-numbers" style="max-height: none">&lt;code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
 labels:
 spring-boot: &amp;quot;true&amp;quot;
 app: multiple-pod-test
 provider: jkube
 version: 1.0.5-SNAPSHOT
 group: com.metaleap.framework
 name: multiple-pod-test
spec:
 replicas: 1
 revisionHistoryLimit: 2
 selector:
 matchLabels:
 app: multiple-pod-test
 provider: jkube
 group: com.metaleap.framework
 strategy:
 rollingUpdate:
 maxSurge: 5
 maxUnavailable: 0
 type: RollingUpdate
 template:
 metadata:
 labels:
 spring-boot: &amp;quot;true&amp;quot;
 app: multiple-pod-test
 provider: jkube
 version: 1.0.5-SNAPSHOT
 group: com.metaleap.framework
 spec:
 containers:
 - env:
 - name: SPRING_PROFILES_ACTIVE
 valueFrom:
 configMapKeyRef:
 name: base
 key: SPRING_PROFILES_ACTIVE
 - name: APPLICATION_NAME
 value: ${project.artifactId}
 - name: TZ
 value: Asia/Shanghai
 - name: KUBERNETES_NAMESPACE
 valueFrom:
 fieldRef:
 fieldPath: metadata.namespace
 - name: HOSTNAME
 valueFrom:
 fieldRef:
 fieldPath: metadata.name
 image: gitlab.pixdaddy.com:5050/magic/backend/magic-brush/magic-brush-app:1.0.1-SNAPSHOT
 imagePullPolicy: IfNotPresent
 lifecycle:
 postStart:
 exec:
 command:
 - sh
 - -c
 - |
 if netstat -nltp | grep &amp;quot;:80 &amp;quot;; then
 echo 'check port use netstat';
 exit 0;
 else
 echo 'not ready';
 exit 14;
 fi
 name: my-sqldb
 ports:
 - containerPort: 8090
 name: http
 protocol: TCP
 securityContext:
 privileged: false

 - env:
 - name: sqlhostname
 value: sql-test-pod
 - name: HOSTNAME
 valueFrom:
 fieldRef:
 fieldPath: metadata.name
 image: nginx
 ports:
 - containerPort: 80
 name: http
 protocol: TCP
 imagePullPolicy: IfNotPresent
 name: python-utils
 livenessProbe:
 httpGet:
 path: /
 port: 80
 initialDelaySeconds: 20
 periodSeconds: 9
 timeoutSeconds: 10
 readinessProbe:
 httpGet:
 path: /
 port: 80
 initialDelaySeconds: 25
 periodSeconds: 9
 timeoutSeconds: 10

 dnsConfig:
 options:
 - name: single-request-reopen
 - name: ndots
 value: &amp;quot;2&amp;quot;
 imagePullSecrets:
 - name: registry-key
&lt;/code>&lt;/pre>&lt;/div></description></item><item><title/><link>https://archive-w.netlify.app/devops/k8s/kubeadm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/k8s/kubeadm/</guid><description>&lt;h2 id="虚拟机准备">
 虚拟机准备
 &lt;a class="anchor" href="#%e8%99%9a%e6%8b%9f%e6%9c%ba%e5%87%86%e5%a4%87">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># virtualbox 下载；https://download.virtualbox.org/virtualbox/7.0.6/VirtualBox-7.0.6-155176-OSX.dmg
# centos min : http://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso?spm=a2c6h.25603864.0.0.60196aeaRSRcS0
# k8s-master (bridge)(192.168.1.20)
# k8s-node01 (bridge)(192.168.1.31)
# k8s-node02 (bridge)(192.168.1.32)
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="系统初始化">
 系统初始化
 &lt;a class="anchor" href="#%e7%b3%bb%e7%bb%9f%e5%88%9d%e5%a7%8b%e5%8c%96">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 设置系统主机名以及 Host文件的相互解析
hostnamectl set-hostname k8s-master01

# 安装依赖包
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git

# 设置防火墙为 Iptables 并设置空规则
systemctl stop firewalld &amp;amp;&amp;amp; systemctl disable firewalld 
yum -y install iptables-services &amp;amp;&amp;amp; systemctl start iptables &amp;amp;&amp;amp; systemctl enable iptables &amp;amp;&amp;amp; iptables -F &amp;amp;&amp;amp; service iptables save

# 关闭SELINUX
swapoff -a &amp;amp;&amp;amp; sed -i '/ swap /s/^\(.*\)$/#\1/g' /etc/fstab &amp;amp;&amp;amp; setenforce 0 &amp;amp;&amp;amp; sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

# 调整内核参数，对于K8S
cat &amp;gt; kubernetes.conf &amp;lt;&amp;lt;EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0 #禁止使用swap空间，只有当系统OOM时才允许使用它 
vm.overcommit_memory=1 # 不检查物理内存是否够用
vm.panic_on_oom=0 # 开启 OOM
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf # sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: 没有那个文件或目录 ----》 modprobe br_netfilter

# 调整系统时区
#设置系统时区为中国/上海
timedatectl set-timezone Asia/Shanghai
# 将当前的UTC时间写入硬件时钟
timedatectl set-local-rtc 0
# 重启依赖于系统时间的服务
systemctl restart rsyslog
systemctl restart crond

#关闭系统不需要服务
systemctl stop postfix &amp;amp;&amp;amp; systemctl disable postfix

# 设置 rsyslogd 和 systemd journald
mkdir /var/log/journal # 持久化保存日志的目录
mkdir /etc/systemd/journald.conf.d
cat &amp;gt; /etc/systemd/journald.conf.d/99-prophet.conf &amp;lt;&amp;lt;EOF
[Journal]
#持久化保存到磁盘
Storage=persistent
#压缩历史日志
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
#最大占用空间10G
SystemMaxUse=10G
#单日志文件最大200M
SystemMaxFileSize=200M
#日志保存时间2周
MaxRetentionSec=2week 
#不将日志转发到 syslog 
ForwardToSyslog=no
EOF
systemctl restart systemd-journald

# 升级系统内核为4.44
# CentOS 7.x系统自带的3.10.x内核存在一些Bugs，导致运行的Docker、Kubernetes不稳定，例如：rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
 # 方式一：最新的
 rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
 yum --enablerepo=elrepo-kernel install -y kernel-lt

 # 方式二：google 下载rpm包进行安装
 wget https://linux.cc.iitk.ac.in/mirror/centos/elrepo/kernel/el7/x86_64/RPMS/kernel-lt-4.4.213-1.el7.elrepo.x86_64.rpm
 yum install kernel-lt-4.4.213-1.el7.elrepo.x86_64.rpm

 # 查看已经安装的内核
 1： awk -F\' '$1==&amp;quot;menuentry &amp;quot; {print i++ &amp;quot; : &amp;quot; $2}' /etc/grub2.cfg
 2： # 安装完成后检查 /boot/grub2/grub.cfg 中对应内核menuentry中是否包含initrd16配置，如果没有，再安装一次！
#设置开机从新内核启动
# grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)'
grub2-set-default 'CentOS Linux (4.4.213-1.el7.elrepo.x86_64) 7 (Core)'
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="部署安装-kubeadm">
 部署安装-kubeadm
 &lt;a class="anchor" href="#%e9%83%a8%e7%bd%b2%e5%ae%89%e8%a3%85-kubeadm">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># kube-proxy开启ipvs的前置条件
modprobe br_netfilter
cat &amp;gt; /etc/sysconfig/modules/ipvs.modules &amp;lt;&amp;lt;EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr 
modprobe -- ip_vs_sh 
modprobe -- nf_conntrack_ipv4
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules &amp;amp;&amp;amp; bash /etc/sysconfig/modules/ipvs.modules &amp;amp;&amp;amp; lsmod | grep -e ip_vs -e nf_conntrack_ipv4

# 安装 Docker软件
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum update -y &amp;amp;&amp;amp; yum install -y docker-ce
## 创建/etc/docker目录 
mkdir /etc/docker
#配置daemon.
cat &amp;gt; /etc/docker/daemon.json &amp;lt;&amp;lt;EOF
{
 &amp;quot;exec-opts&amp;quot;:[&amp;quot;native.cgroupdriver=systemd&amp;quot;],
 &amp;quot;registry-mirrors&amp;quot;: [&amp;quot;https://ud6340vz.mirror.aliyuncs.com&amp;quot;],
 &amp;quot;log-driver&amp;quot;:&amp;quot;json-file&amp;quot;,
 &amp;quot;log-opts&amp;quot;:{
 &amp;quot;max-size&amp;quot;:&amp;quot;100m&amp;quot;
 }
}
EOF
mkdir -p /etc/systemd/system/docker.service.d
# 重启docker服务
systemctl daemon-reload &amp;amp;&amp;amp; systemctl restart docker &amp;amp;&amp;amp; systemctl enable docker

# 安装Kubeadm（主从配置）
cat &amp;gt; /etc/yum.repos.d/kubernetes.repo &amp;lt;&amp;lt;EOF 
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum -y install kubeadm-1.15.1 kubectl-1.15.1 kubelet-1.15.1
systemctl enable kubelet.service

# 初始化主节点 另外一种初始化方式参见（https://k8s.easydoc.net/docs/dRiQjyTY/28366845/6GiNOzyZ/nd7yOvdY）
kubeadm config print init-defaults &amp;gt; kubeadm-config.yaml
kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs | tee kubeadm-init.log
kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers
# 忘记了重新获取：
kubeadm token create --print-join-command
# 加入主节点以及其余工作节点
# 执行安装日志中的加入命令即可
# 部署网络
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml（这个文件对于当前集群好像不适用）
# NotReady （https://stackoverflow.com/questions/52675934/network-plugin-is-not-ready-cni-config-uninitialized）
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml # NotReady （https://stackoverflow.com/questions/52675934/network-plugin-is-not-ready-cni-config-uninitialized）
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml

# 重置k8s集群
sudo kubeadm reset &amp;amp;&amp;amp; rm -rf /var/lib/cni/ &amp;amp;&amp;amp; sudo rm -rf /var/lib/cni/ &amp;amp;&amp;amp; systemctl daemon-reload &amp;amp;&amp;amp; systemctl restart kubelet &amp;amp;&amp;amp;
sudo iptables -F &amp;amp;&amp;amp; sudo iptables -t nat -F &amp;amp;&amp;amp; sudo iptables -t mangle -F &amp;amp;&amp;amp; sudo iptables -X

# 主节点继续执行
mkdir -p $HOME/.kube &amp;amp;&amp;amp; sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config &amp;amp;&amp;amp; sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 子节点也需要重置(方法同上)
# rm -f /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/pki/ca.crt &amp;amp;&amp;amp; systemctl restart kubelet

# 容器二进制可执行插件
wget https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz # 注意这个必须在子节点也安装，立竿见影。（捣鼓好一会）

# 查看当前集群配置
kubeadm config view

&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="集群面板-dashboard">
 集群面板-dashboard
 &lt;a class="anchor" href="#%e9%9b%86%e7%be%a4%e9%9d%a2%e6%9d%bf-dashboard">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 安装dashboard
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
# 修改service type: NodePort，不指定端口的随机分配 通过svc 查看
# seccompProfile 规范出错了注释即可
# 通过token进行登录
# 创建账户
kubectl create serviceaccount dashboard-admin -n kube-system
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 通过下面命令查看token
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

# 或者使用如下的yaml文件创建
# kubectl apply -f kube-admin.yaml
# kubectl -n kubernetes-dashboard create token admin-user[对于v1.15不适用]
kubectl -n kubernetes-dashboard get secret
kubectl -n kubernetes-dashboard describe secret admin-user-token-dxj54
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="yaml" data-line="" class="language-yaml line-numbers" style="max-height: none">&lt;code class="language-yaml">apiVersion: v1
kind: ServiceAccount
metadata:
 name: admin-user
 namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: admin-user
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- kind: ServiceAccount
 name: admin-user
 namespace: kubernetes-dashboard
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="common">
 common
 &lt;a class="anchor" href="#common">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/53525975/kubernetes-error-uploading-crisocket-timed-out-waiting-for-the-condition" rel="noopener" target="_blank">https://stackoverflow.com/questions/53525975/kubernetes-error-uploading-crisocket-timed-out-waiting-for-the-condition&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/qq_29385297/article/details/127682552" rel="noopener" target="_blank">failed to find plugin “flannel” in path [/opt/cni/bin]，k8sNotReady解决方案&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/Wuli_SmBug/article/details/104712653" rel="noopener" target="_blank">解决k8s&amp;quot;failed to set bridge addr: &amp;ldquo;cni0&amp;rdquo; already has an IP address different from 10.244.1.1/24&amp;quot;&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/52675934/network-plugin-is-not-ready-cni-config-uninitialized" rel="noopener" target="_blank">https://stackoverflow.com/questions/52675934/network-plugin-is-not-ready-cni-config-uninitialized&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://lzwgiter.github.io/posts/eed4a979.html#/flannel%E7%BD%91%E7%BB%9C%E6%8F%92%E4%BB%B6---error-registering-network-failed-to-acquire-lease-node-xxx-pod-cidr-not-assigned" rel="noopener" target="_blank">https://lzwgiter.github.io/posts/eed4a979.html#/flannel%E7%BD%91%E7%BB%9C%E6%8F%92%E4%BB%B6---error-registering-network-failed-to-acquire-lease-node-xxx-pod-cidr-not-assigned&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/58276969/k8s-convert-kubeadm-init-command-line-arguments-to-config-yaml" rel="noopener" target="_blank">https://stackoverflow.com/questions/58276969/k8s-convert-kubeadm-init-command-line-arguments-to-config-yaml&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/qq_21816375/article/details/79193011" rel="noopener" target="_blank">kubernetes启动Pod遇到CrashLoopBackOff的解决思路&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="dashboard">
 dashboard
 &lt;a class="anchor" href="#dashboard">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>


 &lt;a href="https://zhuanlan.zhihu.com/p/579730438" rel="noopener" target="_blank">K8S集群中安装Dashboard&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/weixin_43822977/article/details/118942882" rel="noopener" target="_blank">部署k8s的dashboard访问页面时Client sent an HTTP request to an HTTPS server.&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/70287656/kubernetes-dashboard-internal-error-500-not-enough-data-to-create-auth-info" rel="noopener" target="_blank">Internal error (500): Not enough data to create auth info structure.&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="coredns">
 coredns
 &lt;a class="anchor" href="#coredns">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/60666170/how-to-get-into-coredns-pod-kuberrnetes" rel="noopener" target="_blank">https://stackoverflow.com/questions/60666170/how-to-get-into-coredns-pod-kuberrnetes&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/k8s/minikube/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/k8s/minikube/</guid><description>&lt;h2 id="minikube">
 minikube
 &lt;a class="anchor" href="#minikube">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 1.Installation
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64
sudo install minikube-darwin-amd64 /usr/local/bin/minikube

# 2.Start your cluster
minikube start

# 3.Interact with your cluster
kubectl get po -A # or: minikube kubectl -- get po -A

# bring-up dashboard
minikube dashboard
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="krew">
 krew
 &lt;a class="anchor" href="#krew">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 1.Make sure that git is installed.

# 2.Run this command to download and install krew:
(
 set -x; cd &amp;quot;$(mktemp -d)&amp;quot; &amp;amp;&amp;amp;
 OS=&amp;quot;$(uname | tr '[:upper:]' '[:lower:]')&amp;quot; &amp;amp;&amp;amp;
 ARCH=&amp;quot;$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')&amp;quot; &amp;amp;&amp;amp;
 KREW=&amp;quot;krew-${OS}_${ARCH}&amp;quot; &amp;amp;&amp;amp;
 curl -fsSLO &amp;quot;https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz&amp;quot; &amp;amp;&amp;amp;
 tar zxvf &amp;quot;${KREW}.tar.gz&amp;quot; &amp;amp;&amp;amp;
 ./&amp;quot;${KREW}&amp;quot; install krew
)

# 3.Add the $HOME/.krew/bin directory to your PATH environment variable. To do this, update your .bashrc or .zshrc file and append the following line:
# and restart your shell.
export PATH=&amp;quot;${KREW_ROOT:-$HOME/.krew}/bin:$PATH&amp;quot; 

# 4.Run kubectl krew to check the installation.
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="node-shell">
 node-shell
 &lt;a class="anchor" href="#node-shell">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>kubectl krew install node-shell&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/k8s/skeleton/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/k8s/skeleton/</guid><description>&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/k8s/framework.png" alt="" width="90%">&lt;/p>
&lt;h2 id="基础概念">
 基础概念
 &lt;a class="anchor" href="#%e5%9f%ba%e7%a1%80%e6%a6%82%e5%bf%b5">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="各个组件">
 各个组件
 &lt;a class="anchor" href="#%e5%90%84%e4%b8%aa%e7%bb%84%e4%bb%b6">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>name&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>APISERVER&lt;/td>
&lt;td>所有服务访问统一入口&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CrontrollerManager&lt;/td>
&lt;td>维持副本期望数目&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Scheduler&lt;/td>
&lt;td>负责介绍任务，选择合适的节点进行分配任务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ETCD&lt;/td>
&lt;td>键值对数据库 储存K8S集群所有重要信息（持久化）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Kubelet&lt;/td>
&lt;td>直接跟容器引擎交互实现容器的生命周期管理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Kube-proxy&lt;/td>
&lt;td>负责写入规则至 IPTABLES、IPVS 实现服务映射访问的&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>COREDNS&lt;/td>
&lt;td>可以为集群中的SVC创建一个域名IP的对应关系解析&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>DASHBOARD&lt;/td>
&lt;td>给 K8S 集群提供一个 B/S 结构访问体系&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>INGRESS CONTROLLER&lt;/td>
&lt;td>官方只能实现四层代理，INGRESS 可以实现七层代理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>FEDERATION&lt;/td>
&lt;td>提供一个可以跨集群中心多K8S统一管理功能&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PROMETHEUS&lt;/td>
&lt;td>提供K8S集群的监控能力&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ELK&lt;/td>
&lt;td>提供 K8S 集群日志统一分析介入平台&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="pod">
 POD
 &lt;a class="anchor" href="#pod">#&lt;/a>
&lt;/h3>
&lt;p>K8S 中包装的最小单位，一个POD（容器组）中可以包含多个容器，用来表示可迁移的lamp，类似于Docker的多层镜像。同一个POD中容器可以直接共享pause共享的网络站或者挂载卷。&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="自主式管理pod">
 自主式管理POD
 &lt;a class="anchor" href="#%e8%87%aa%e4%b8%bb%e5%bc%8f%e7%ae%a1%e7%90%86pod">#&lt;/a>
&lt;/h4>
POD 死亡后没办法继续启动。&lt;/li>
&lt;li>
&lt;h4 id="控制器管理的pod">
 控制器管理的POD
 &lt;a class="anchor" href="#%e6%8e%a7%e5%88%b6%e5%99%a8%e7%ae%a1%e7%90%86%e7%9a%84pod">#&lt;/a>
&lt;/h4>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>name&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>ReplicationControlelr(RC)&lt;/td>
&lt;td>用来确保容器应用的副本数始终保持在用户定义的副本数，如果容器有异常退出，会自动创建新的POD来代替；而异常多出来的容器也会自动回收，新版本中建议使用ReplicaSet 来替代 ReplicationController&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ReplicaSet(RS）&lt;/td>
&lt;td>与上一个没有本质区别，但是这个支持集合式的 selector&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Deployment&lt;/td>
&lt;td>虽然ReplicaSet可以独立使用，但一般还是建议使用Deployment来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题（比如ReplicaSet不支持 rolling-update ，但 Deployment支持）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>HorizontalPodAutoScale(HPA)&lt;/td>
&lt;td>也是控制RS,根据CPU使用率自动平衡扩展，收缩，可定义最大，最小副本数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>StatefulSet(SS)&lt;/td>
&lt;td>主要解决有状态服务问题，包括的场景有：稳定的持久化存储，稳定的网络标志，有序部署，有序收缩&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>DaemonSet()&lt;/td>
&lt;td>可以理解为跟node绑定的一些后台运行的POD，跟随节点进行创建和删除。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Job&lt;/td>
&lt;td>负责批处理任务，即仅执行一次的任务.相比于script优点有，封装在POD中可判断是否正常退出，可以重新执行。而且可以设定认为成功的次数。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CronJob&lt;/td>
&lt;td>带有cron 定时任务的JOB&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="网络通信方式">
 网络通信方式
 &lt;a class="anchor" href="#%e7%bd%91%e7%bb%9c%e9%80%9a%e4%bf%a1%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;blockquote>
&lt;p>扁平化的网络空间&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/bridge/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/bridge/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introbridge">
 Intro(Bridge)
 &lt;a class="anchor" href="#introbridge">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/dns/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/dns/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introdns">
 Intro(DNS)
 &lt;a class="anchor" href="#introdns">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://app.codecrafters.io/courses/dns-server/setup?repo=114885a4-1081-4ed2-b10a-b0fd258cb1b2" rel="noopener" target="_blank">make a DNS server&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://en.wikipedia.org/wiki/Domain_Name_System#DNS_message_format" rel="noopener" target="_blank">https://en.wikipedia.org/wiki/Domain_Name_System#DNS_message_format&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://datatracker.ietf.org/doc/html/rfc1035#section-4.1" rel="noopener" target="_blank">https://datatracker.ietf.org/doc/html/rfc1035#section-4.1&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/EmilHernvall/dnsguide/blob/b52da3b32b27c81e5c6729ac14fe01fef8b1b593/chapter1.md" rel="noopener" target="_blank">https://github.com/EmilHernvall/dnsguide/blob/b52da3b32b27c81e5c6729ac14fe01fef8b1b593/chapter1.md&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.cloudns.net/blog/understanding-dot-and-doh-dns-over-tls-vs-dns-over-https/" rel="noopener" target="_blank">https://www.cloudns.net/blog/understanding-dot-and-doh-dns-over-tls-vs-dns-over-https/&lt;/a>&lt;/li>
&lt;li>&lt;/li>
&lt;li>域名相关&lt;/li>
&lt;li>


 &lt;a href="https://dnsviz.net/d/wtfu.site/dnssec/" rel="noopener" target="_blank">https://dnsviz.net/d/wtfu.site/dnssec/&lt;/a> [DNS visual]&lt;/li>
&lt;li>


 &lt;a href="https://crt.sh/?q=wtfu.site" rel="noopener" target="_blank">https://crt.sh/?q=wtfu.site&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/docker0/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/docker0/</guid><description>&lt;h2 id="bridge网络">
 bridge网络
 &lt;a class="anchor" href="#bridge%e7%bd%91%e7%bb%9c">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 目前的理解是&lt;br>
&lt;/br> 1. 容器中的eth0接口通过veth pair 连接到docker0 网桥。
&lt;/br> 2. docker0网桥创建的时候会自动生成一个网络接口并附有172.17.0.1的ip，参考
&lt;/br> 3. docker0 与 eth0 之间没有直接的关联，而是通过 ip_forward/ docker-proxy 等技术进行转发的。参考


 &lt;a href="https://medium.com/@diegogabrielschurch/how-docker-network-works-bridge-driver-e4819459cc8a" rel="noopener" target="_blank">文档&lt;/a>， 有以下片段。
&lt;/br>       &lt;code>Looking at the diagram, the interface docker0 has a connection to the eth0 interface, this gives the ability to our containers to send pings to other machines on the internet. But in reality, this connection is made using a Linux firewall named “Iptables”.&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="参考资料-onehttpwebarchiveorgweb20201109220442httpsdeveloperibmcomrecipestutorialsnetworking-your-docker-containers-using-docker0-bridge">
 参考资料 


 &lt;a href="http://web.archive.org/web/20201109220442/https://developer.ibm.com/recipes/tutorials/networking-your-docker-containers-using-docker0-bridge/" rel="noopener" target="_blank">one&lt;/a>
 &lt;a class="anchor" href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99-onehttpwebarchiveorgweb20201109220442httpsdeveloperibmcomrecipestutorialsnetworking-your-docker-containers-using-docker0-bridge">#&lt;/a>
&lt;/h4>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/docker0/docker0-04.png" alt="">&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="参考资料-twohttpssuperusercomquestions1560357is-docker0-virtual-bridge-or-virtual-interface">
 参考资料 


 &lt;a href="https://superuser.com/questions/1560357/is-docker0-virtual-bridge-or-virtual-interface" rel="noopener" target="_blank">two&lt;/a>
 &lt;a class="anchor" href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99-twohttpssuperusercomquestions1560357is-docker0-virtual-bridge-or-virtual-interface">#&lt;/a>
&lt;/h4>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/docker0/docker0-05.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/http/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/http/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introhttp">
 Intro(HTTP)
 &lt;a class="anchor" href="#introhttp">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="分块传输编码">
 分块传输编码
 &lt;a class="anchor" href="#%e5%88%86%e5%9d%97%e4%bc%a0%e8%be%93%e7%bc%96%e7%a0%81">#&lt;/a>
&lt;/h3>
&lt;p class="warn">Response Header 中存在 &lt;code>Transfer-Encoding: chunked&lt;/code>的话，就是分块传输，数据需要按照 


 &lt;a href="https://zh.wikipedia.org/wiki/分块传输编码#格式" rel="noopener" target="_blank">格式&lt;/a> 解码。[


 &lt;a href="https://en.wikipedia.org/wiki/Chunked_transfer_encoding" rel="noopener" target="_blank">参考&lt;/a>]
&lt;br>&lt;br> 应用场景：使用 socket 发送 http/https 请求的时候会返回数据报文，需要自己解析。比如：
&lt;br>1. 模拟


 &lt;a href="https://github.com/12302-bak/idea-test-project/blob/v2.0.0-BAK/_4_springmvc/src/main/java/site/wtfu/framework/utils/TLSTest.java" rel="noopener" target="_blank">&lt;code>vless客户端发送 wss + https&lt;/code>&lt;/a> 请求: 先与vless服务器创建一个通过tls加密的websocket隧道连接。
&lt;br>2. 发送&lt;code>command(ipaddr, port)&lt;/code> + &lt;code>握手消息&lt;/code>到websocket服务器，并与&lt;code>目标服务器&lt;/code>建立连接并且发送Client Hello[一般情况下是这个]，后续让&lt;code>BC库&lt;/code>完成握手。
&lt;br>3. 读取 &lt;strong>tls&lt;/strong>&lt;code>[BC.TlsClientProtocol]&lt;/code>解密后的报文，此时需要注意可能存在分块传输如下图。&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/http/http-response-chunked-encoding-01.png" alt="" width="70%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="响应头大小写">
 响应头大小写
 &lt;a class="anchor" href="#%e5%93%8d%e5%ba%94%e5%a4%b4%e5%a4%a7%e5%b0%8f%e5%86%99">#&lt;/a>
&lt;/h3>
&lt;p class="warn">(参考


 &lt;a href="https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2" rel="noopener" target="_blank">rfc | 7540&lt;/a>) 在 http2 中，&lt;strong>响应头的 key 必须为小写&lt;/strong>，其他的视为畸形的，但是在 http1.1 中大小写不敏感。
&lt;br>&lt;br>使用 curl 验证即可，一般浏览器应该会自动转化，比如 chrome 即使小写也会转化成首字母大写。
&lt;br>下列命令查看响应头区别：&lt;code>curl -I --http1.1 https://wtfu.site&lt;/code>，&lt;code>curl -I --http2 https://wtfu.site&lt;/code>
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/devops/network/http/http-response-header-01.png" alt="" width="70%">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://en.wikipedia.org/wiki/Chunked_transfer_encoding" rel="noopener" target="_blank">https://en.wikipedia.org/wiki/Chunked_transfer_encoding&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.runoob.com/http/http-tutorial.html" rel="noopener" target="_blank">https://www.runoob.com/http/http-tutorial.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/network-stack/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/network-stack/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intro网络栈">
 Intro(网络栈)
 &lt;a class="anchor" href="#intro%e7%bd%91%e7%bb%9c%e6%a0%88">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="直接往网卡发送数据">
 直接往网卡发送数据
 &lt;a class="anchor" href="#%e7%9b%b4%e6%8e%a5%e5%be%80%e7%bd%91%e5%8d%a1%e5%8f%91%e9%80%81%e6%95%b0%e6%8d%ae">#&lt;/a>
&lt;/h3>
&lt;p class="warn">通过对网络模型以及 tcp/ip 协议栈的了解，是可以&lt;strong>不通过协议栈处理&lt;/strong>而使用系统调用直接往网卡上面发送数据的。示例如下：（在 linux 上面的实验，macosx 因为限制原因，修改不了 MAC source address，但是 Linux 完全没有问题。）
&lt;br>&lt;br>抓包命令&lt;code>sudo tcpdump -i eth0 arp -w nic.pcap&lt;/code>， 


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/.images/devops/network/network-stack/nic.pcap' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/.images/devops/network/network-stack/nic.pcap">nic.pcap file download&lt;/a>
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/devops/network/network-stack/network-stack-nic-send-01.png" alt="" width="100%">&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" data-cc="400px" class="language-c line-numbers" style="max-height: 400px">&lt;code class="language-c">#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;
#include &amp;lt;net/if.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;linux/if_packet.h&amp;gt;
#include &amp;lt;net/ethernet.h&amp;gt;

int main() {
 int sockfd;
 struct ifreq if_idx;
 struct sockaddr_ll socket_address;
 char sendbuf[1024];
 unsigned char src_mac[6] = {0x00, 0x0c, 0x29, 0x7b, 0x3e, 0x1f}; // 本机 MAC 地址
 unsigned char dst_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // 广播 MAC 地址
 unsigned char *data = &amp;quot;Hello Ethernet!&amp;quot;;
 int data_len = strlen(data);

 // 创建 Packet Socket
 if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
 perror(&amp;quot;socket&amp;quot;);
 exit(EXIT_FAILURE);
 }

 // 获取网络接口索引
 memset(&amp;amp;if_idx, 0, sizeof(struct ifreq));
 strncpy(if_idx.ifr_name, &amp;quot;eth0&amp;quot;, IFNAMSIZ - 1);
 if (ioctl(sockfd, SIOCGIFINDEX, &amp;amp;if_idx) &amp;lt; 0) {
 perror(&amp;quot;SIOCGIFINDEX&amp;quot;);
 close(sockfd);
 exit(EXIT_FAILURE);
 }

 // 填充以太网帧头
 struct ethhdr *eh = (struct ethhdr *)sendbuf;
 memcpy(eh-&amp;gt;h_dest, dst_mac, 6); // 设置目标 MAC 地址
 memcpy(eh-&amp;gt;h_source, src_mac, 6); // 设置源 MAC 地址
 eh-&amp;gt;h_proto = htons(ETH_P_ARP); // 设置协议类型（这里假设是 ARP）

 // 填充数据部分
 memcpy(sendbuf + sizeof(struct ethhdr), data, data_len);

 // 设置目标地址
 memset(&amp;amp;socket_address, 0, sizeof(struct sockaddr_ll));
 socket_address.sll_family = AF_PACKET;
 socket_address.sll_protocol = htons(ETH_P_ARP);
 socket_address.sll_ifindex = if_idx.ifr_ifindex;
 socket_address.sll_halen = ETH_ALEN;
 memcpy(socket_address.sll_addr, dst_mac, 6);

 // 发送数据包
 if (sendto(sockfd, sendbuf, sizeof(struct ethhdr) + data_len, 0,
 (struct sockaddr *)&amp;amp;socket_address, sizeof(struct sockaddr_ll)) &amp;lt; 0) {
 perror(&amp;quot;sendto&amp;quot;);
 close(sockfd);
 exit(EXIT_FAILURE);
 }

 printf(&amp;quot;Data sent successfully!\n&amp;quot;);
 close(sockfd);
 return 0;
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="网络堆栈">
 网络堆栈
 &lt;a class="anchor" href="#%e7%bd%91%e7%bb%9c%e5%a0%86%e6%a0%88">#&lt;/a>
&lt;/h2>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/network-stack/network-stack-01.png" alt="" width="40%">
&lt;img src="https://archive-w.netlify.app/.images/devops/network/network-stack/network-stack-02.png" alt="" width="57%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/proxy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/proxy/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introproxy">
 Intro(PROXY)
 &lt;a class="anchor" href="#introproxy">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/socket/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/socket/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introsocket">
 Intro(SOCKET)
 &lt;a class="anchor" href="#introsocket">#&lt;/a>
&lt;/h2>
&lt;p class="warn">socket 是网络架构中程序与操作系统网络协议栈进行交互的接口API。从所处的地位来讲，套接字上联应用进程，下联网络协议栈，是应用程序通过网络协议进行通信的接口。
&lt;br> 


 &lt;a href="https://github.com/torvalds/linux/blob/master/include/linux/net.h#L117" rel="noopener" target="_blank">linux数据结构定义&lt;/a> 、


 &lt;a href="https://gist.github.com/browny/5211329" rel="noopener" target="_blank">C demo&lt;/a>
&lt;br>&lt;br>作为服务端，先创建一个socket，返回fd，然后与地址(ip+port)进行绑定，监听，然后接收
&lt;br>作为客户端，先创建一个socket，返回fd，然后与地址(serv ad)进行连接，发送&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="系统调用">
 系统调用
 &lt;a class="anchor" href="#%e7%b3%bb%e7%bb%9f%e8%b0%83%e7%94%a8">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="socket">
 socket()
 &lt;a class="anchor" href="#socket">#&lt;/a>
&lt;/h4>
&lt;p>原型：&lt;code>int socket(int domain, int type, int protocol);&lt;/code> 例如：&lt;code>socketfd = socket(AF_INET, SOCK_STREAM, 0);&lt;/code> 


 &lt;a href="https://man7.org/linux/man-pages/man2/socket.2.html" rel="noopener" target="_blank">【man2】&lt;/a>
&lt;br>用来创建一个socket，并且返回引用的文件描述符fd。&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="bind">
 bind()
 &lt;a class="anchor" href="#bind">#&lt;/a>
&lt;/h4>
&lt;p>原型：&lt;code>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);&lt;/code> 例如：&lt;code>bind(socketfd, (struct sockaddr*)&amp;amp;serv_addr, sizeof(serv_addr));&lt;/code>


 &lt;a href="https://man7.org/linux/man-pages/man2/bind.2.html" rel="noopener" target="_blank">【man2】&lt;/a>
&lt;br>分配一个地址给socket。&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="listen">
 listen()
 &lt;a class="anchor" href="#listen">#&lt;/a>
&lt;/h4>
&lt;p>原型：&lt;code>int listen(int sockfd, int backlog);&lt;/code> 例如：&lt;code>listen(listenfd, 10);&lt;/code>


 &lt;a href="https://man7.org/linux/man-pages/man2/listen.2.html" rel="noopener" target="_blank">【man2】&lt;/a>
&lt;br>listen函数将 socket 文件描述符标记为被动 socket,也就是服务端的socket，执行完之后，文件描述符处于监听状态。使用accept获取客户端连接。backlog 定义 socket允许待处理的客户端连接的队列长度。


 &lt;a href="https://blog.isayme.org/posts/issues-47/" rel="noopener" target="_blank">全连接和半连接&lt;/a>会使用到这个值(和内核版本有关)&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="connect">
 connect()
 &lt;a class="anchor" href="#connect">#&lt;/a>
&lt;/h4>
&lt;p>原型：&lt;code>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);&lt;/code> 例如：&lt;code>if( connect(sockfd, (struct sockaddr *)&amp;amp;serv_addr, sizeof(serv_addr)) &amp;lt; 0)&lt;/code>


 &lt;a href="https://man7.org/linux/man-pages/man2/connect.2.html" rel="noopener" target="_blank">【man2】&lt;/a>
&lt;br> 客户端应用使用connect命令在本地socket和远程socket上建立连接。TCP只能调用一次进行三次握手，多次会报错。UPD的话可以调用多次改变关联的socket，好像只是注册一下对端地址 


 &lt;a href="https://www.ibm.com/docs/en/zos/2.4.0?topic=functions-connect" rel="noopener" target="_blank">【IBM connect】&lt;/a> 


 &lt;a href="https://liubigbin.github.io/2016/07/11/UDP%E4%B9%8Bconnect/" rel="noopener" target="_blank">【UDP之connect】&lt;/a>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/ssh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/ssh/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introssh">
 Intro(SSH)
 &lt;a class="anchor" href="#introssh">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="ssh登录">
 SSH登录
 &lt;a class="anchor" href="#ssh%e7%99%bb%e5%bd%95">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="准备步骤">
 准备步骤
 &lt;a class="anchor" href="#%e5%87%86%e5%a4%87%e6%ad%a5%e9%aa%a4">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>生成公私匙: &lt;code>ssh-keygen -t rsa -b 4096 -C 12302@example.com&lt;/code>&lt;/li>
&lt;li>复制公匙到主机:&lt;code>cat ~/.ssh/id_virmach_ras.pub | ssh root@107.174.101.187 &amp;quot;mkdir -p ~/.ssh &amp;amp;&amp;amp; cat &amp;gt;&amp;gt; ~/.ssh/authorized_keys&amp;quot;&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/ssh/ssh-keygen-01.png" alt="" width="65%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h5 id="ssh-copy-id使用">
 ssh-copy-id使用
 &lt;a class="anchor" href="#ssh-copy-id%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h5>
&lt;p class="warn">&lt;strong>(ssh-copy-id)&lt;/strong> 是一个可执行的脚本文件，可以把本地的&lt;code>ssh公钥文件&lt;/code>安装到远程主机对应的账户下。也就是将你的公共密钥填充到一个远程机器上的&lt;code>authorized_keys&lt;/code>文件中。如果远程机器上存在&lt;code>authorizedkeys&lt;/code>文件，且&lt;code>authorizedkeys&lt;/code>有内容，则&lt;code>ssh-copy-id&lt;/code> 可以将待传公钥 &lt;em>追加&lt;/em> 到&lt;code>authorizedkeys&lt;/code>文件里。它也能够改变远程用户名的权限，如&lt;code>~/.ssh&lt;/code>和&lt;code>~/.ssh/authorized_keys&lt;/code>删除其写的权限，所以一般&lt;code>/.ssh&lt;/code>给予&lt;code>700&lt;/code>，&lt;code>/.ssh/authorized_keys&lt;/code>给予&lt;code>600&lt;/code>权限。
&lt;br>&lt;br>查看帮助：&lt;code>ssh-copy-id -h&lt;/code>
&lt;br>复制命令：&lt;code>ssh-copy-id [-i [identity_file]] [user@]machine&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/ssh/ssh-copy-id-01.png" alt="" width="100%">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h4 id="登录原理">
 登录原理
 &lt;a class="anchor" href="#%e7%99%bb%e5%bd%95%e5%8e%9f%e7%90%86">#&lt;/a>
&lt;/h4>
&lt;div class="alert flat warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p>&lt;p> 1). 发送登录请求到远程主机，identity文件中包含一些信息。
&lt;br>2). 远程服务器利用这个账户下的公匙随机生成字符串然后发送给对方。
&lt;br>3). 对方利用私匙将字符串解密后发送给远程服务器。
&lt;br>4). 远程服务器验证通过后，准许对方登录。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="ssh隧道">
 SSH隧道
 &lt;a class="anchor" href="#ssh%e9%9a%a7%e9%81%93">#&lt;/a>
&lt;/h3>
&lt;p class="warn">SSH 除了登录服务器，还有一大用途，就是作为加密通信的中介，充当两台服务器之间的通信加密跳板，使得原本不加密的通信变成加密通信。这个功能称为端口转发（port forwarding），又称 SSH 隧道（tunnel）。
&lt;br>&lt;br>端口转发有两个主要作用：
&lt;br>（1）将不加密的数据放在 SSH 安全连接里面传输，使得原本不安全的网络服务增加了安全性，比如通过端口转发访问 Telnet、FTP 等明文服务，数据传输就都会加密。
&lt;br>（2）作为数据通信的加密跳板，绕过网络防火墙。
&lt;br>端口转发有三种使用方法：&lt;code>动态转发&lt;/code>，&lt;code>本地转发&lt;/code>，&lt;code>远程转发&lt;/code>。下面逐一介绍。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/tcp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/tcp/</guid><description>&lt;h2 id="tcp-flag">
 tcp flag
 &lt;a class="anchor" href="#tcp-flag">#&lt;/a>
&lt;/h2>
&lt;h3 id="图例">
 图例
 &lt;a class="anchor" href="#%e5%9b%be%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;p class="warn">IP 报头（最小20Byte,最大 15[1111] * 32 / 8, 可填充 40Byte ）： 首部长度的单位为 4Byte.&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/tcp/tcp-flag-01.png" alt="">&lt;/p>
&lt;/li>
&lt;li>
&lt;p class="warn">TCP 报头(20Byte)&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/tcp/tcp-flag-02.jpeg" alt="">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="标志位解释">
 标志位解释
 &lt;a class="anchor" href="#%e6%a0%87%e5%bf%97%e4%bd%8d%e8%a7%a3%e9%87%8a">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>&lt;em>&lt;strong>SYN：同步序列编号（Synchronize Sequence Numbers）&lt;/strong>&lt;/em>&lt;/p>
&lt;p class="tip"> 是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时，客户机首先发出一个SYN消息，服务器使用SYN+ACK应答表示接收到了这个消息，最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接，数据才可以在客户机和服务器之间传递。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>&lt;strong>ACK (Acknowledge character）&lt;/strong>&lt;/em>&lt;/p>
&lt;p class="tip">ACK (Acknowledge character）即是确认字符，在数据通信中，接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。在TCP/IP协议中，如果接收方成功的接收到数据，那么会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>&lt;strong>RST&lt;/strong>&lt;/em>&lt;/p>
&lt;p class="tip">产生RST场景或者导致“Connection reset by peer”场景？&lt;/p>
&lt;ul>
&lt;li>当尝试和未开放的服务器端口建立tcp连接时，服务器tcp将会直接向客户端发送reset报文；&lt;/li>
&lt;li>双方之前已经正常建立了通信通道，也可能进行过了交互，当某一方在交互的过程中发生了异常，如崩溃等，异常的一方会向对端发送reset报文，通知对方将连接关闭；&lt;/li>
&lt;li>当收到TCP报文，但是发现该报文不是已建立的TCP连接列表可处理的，则其直接向对端发送reset报文；&lt;/li>
&lt;li>ack报文丢失，并且超出一定的重传次数或时间后，会主动向对端发送reset报文释放该TCP连接；&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h4 id="相关实验">
 相关实验
 &lt;a class="anchor" href="#%e7%9b%b8%e5%85%b3%e5%ae%9e%e9%aa%8c">#&lt;/a>
&lt;/h4>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/tcp/tcp-flag-04.png" alt="" width="70%" title="04"> &lt;img src="https://archive-w.netlify.app/.images/devops/network/tcp/tcp-flag-03.png" alt="" width="29%" title="03">&lt;/p>
&lt;ul>
&lt;li>&lt;em>&lt;strong>猜想&lt;/strong>&lt;/em>
&lt;ol>
&lt;li>
&lt;p>ack值：&lt;/p>
&lt;p class="warn">存在SYN时，ack为对方的seq+1，&lt;/br>
存在PSH时，ack为对方的seq+len,&lt;/p>
&lt;/li>
&lt;li>
&lt;p>seq值：&lt;/p>
&lt;p class="warn">存在ACK时，seq为对方的ack.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h2 id="socket_keepalive理解">
 socket_keepalive理解
 &lt;a class="anchor" href="#socket_keepalive%e7%90%86%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="前言">
 前言
 &lt;a class="anchor" href="#%e5%89%8d%e8%a8%80">#&lt;/a>
&lt;/h3>
&lt;p class="warn">1. net.ipv4.tcp_keepalive_intvl = 75 （发送探测包的周期，前提是当前连接一直没有数据交互，才会以该频率进行发送探测包，如果中途有数据交互，则会重新计时tcp_keepalive_time，到达规定时间没有数据交互，才会重新以该频率发送探测包）
&lt;/br> 2. net.ipv4.tcp_keepalive_probes = 9  （探测失败的重试次数，发送探测包达次数限制对方依旧没有回应，则关闭自己这端的连接）
&lt;/br> 3. net.ipv4.tcp_keepalive_time = 7200 （空闲多长时间，则发送探测包）&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="响应结果">
 响应结果
 &lt;a class="anchor" href="#%e5%93%8d%e5%ba%94%e7%bb%93%e6%9e%9c">#&lt;/a>
&lt;/h3>
&lt;p class="warn">1. 正常ack，继续保持连接；
&lt;/br> 2. 对方响应rst信号，双方重新连接。
&lt;/br> 3. 对方无响应。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/tun-tap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/tun-tap/</guid><description>&lt;h2 id="tuntap">
 tun/tap
 &lt;a class="anchor" href="#tuntap">#&lt;/a>
&lt;/h2>
&lt;p class="warn">tun/tap 设备是操作系统内核中的虚拟网络设备，是用软件模拟的网络设备，提供与硬件网络设备完全相同的功能。主要用于用户空间和内核空间传递报文。&lt;/p>
&lt;h3 id="tuntap-设备与物理网卡的区别如图所示">
 &lt;strong>tun/tap 设备与物理网卡的区别，如图所示:&lt;/strong>
 &lt;a class="anchor" href="#tuntap-%e8%ae%be%e5%a4%87%e4%b8%8e%e7%89%a9%e7%90%86%e7%bd%91%e5%8d%a1%e7%9a%84%e5%8c%ba%e5%88%ab%e5%a6%82%e5%9b%be%e6%89%80%e7%a4%ba">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>对于硬件网络设备而言，一端连接的是物理网络，一端连接的是网络协议栈。&lt;/li>
&lt;li>对于 tun/tap 设备而言，一端连接的是应用程序（通过 字符设备文件 /net/dev/tun），一端连接的是网络协议栈。
&lt;img src="https://archive-w.netlify.app/.images/devops/network/tun-tap/tun-tap-01.png" alt="">&lt;/li>
&lt;/ol>
&lt;h3 id="工作原理">
 &lt;strong>工作原理&lt;/strong>
 &lt;a class="anchor" href="#%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86">#&lt;/a>
&lt;/h3>
&lt;blockquote>
&lt;p>从下图可以更直观的看出 tun/tap 设备和物理设备的区别：虽然它们的一端都是连着网络协议栈，但是物理网卡另一端连接的是物理网络，而 tun/tap 设备另一端连接的是一个应用层程序，这样协议栈发送给 tun/tap 的数据包就可以被这个应用程序读取到，此时这个应用程序可以对数据包进行一些自定义的修改(比如封装成 UDP)，然后又通过网络协议栈发送出去——其实这就是目前大多数“代理”的工作原理。(Tun/tap 设备提供的虚拟网卡驱动，从tcp/ip协议栈的角度而言，它与真实网卡驱动并没有区别。)&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/tun-tap/tun-tap-02.jpg" alt="">&lt;/p>
&lt;h4 id="工作模式">
 &lt;strong>工作模式&lt;/strong>
 &lt;a class="anchor" href="#%e5%b7%a5%e4%bd%9c%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h4>
&lt;p class="warn">tun/tap 有两种模式，tun 模式 与 tap 模式。tun 设备与 tap 设备工作方式完全相同，区别在于：&lt;/p>
&lt;ol>
&lt;li>Tun 设备是三层设备，从 /dev/net/tun 字符设备上读取的是 IP 数据包，写入的也只能是 IP 数据包，因此不能进行二层操作，如发送 ARP 请求和以太网广播。&lt;/li>
&lt;li>Tap 设备是二层设备，处理的是二层 MAC 层数据帧，从 /dev/net/tun 字符设备上读取的是 MAC 层数据帧，写入的也只能是 MAC 层数据帧。从这点来看， Tap 虚拟设备和真实的物理网卡的能力更接近，可以与物理网卡做 bridge。&lt;/li>
&lt;/ol>
&lt;p class="tip">&lt;strong>注意事项&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>无论是 tun 还是 tap 设备，都是通过 open/dev/net/tun 这个字符设备文件，通过 ioctl 系统调用在内核创建新的 tun、tap 设备，创建的设备并不会以文件的形式出现在 /dev/ 下，可以在 sys/class/net/ 下看到对应的网络接口 tunx 或者 tapx。&lt;/li>
&lt;li>设备 /dev/net/tun 必须以 read/write 的方式打开。该设备也被称为克隆设备，它是创建任何 tun/tap 虚拟接口的起点。&lt;/li>
&lt;li>open 系统调用执行的时候，VFS 会为这次 open 分配一个独立的内核态 file 结构，也就是说，每次打开执行时，内核为此次打开分配的 file 结构实例不同，代表不同的字符设备。&lt;/li>
&lt;/ul>
&lt;h4 id="应用的数据收发过程">
 &lt;strong>应用的数据收发过程&lt;/strong>
 &lt;a class="anchor" href="#%e5%ba%94%e7%94%a8%e7%9a%84%e6%95%b0%e6%8d%ae%e6%94%b6%e5%8f%91%e8%bf%87%e7%a8%8b">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>数据发送：应用进程 A open/dev/net/tun 字符设备，通过 ioctl 调用创建虚拟接口 tunx 或者 tapx, ioctl 调用返回表示对应 tunx 或者 tapx 设备的文件描述符 fd ，应用 A 通过这个文件描述符 fd 写入格式化的数据，数据通过虚拟网卡驱动到达协议栈，对于协议栈来说，这个数据就像从真实网卡接收的一样。&lt;/li>
&lt;li>数据接收：当网络协议栈发送数据到虚拟接口 tunx 或者 tapx 时，应用进程 A 通过上述创建的设备文件描述符 fd，从中读取接口发送的数据，然后进行处理。&lt;/li>
&lt;/ol>
&lt;h3 id="设备创建">
 &lt;strong>设备创建&lt;/strong>
 &lt;a class="anchor" href="#%e8%ae%be%e5%a4%87%e5%88%9b%e5%bb%ba">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 创建 tun/tap 设备
ip tuntap add dev tap0 mod tap # 创建 tap
ip tuntap add dev tun0 mod tun # 创建 tun
 
# 删除tun/tap设备
ip tuntap del dev tap0 mod tap # 删除 tap
ip tuntap del dev tun0 mod tun # 删除 tun
 
# 设置 ip 地址，up 设备
ip address add dev tap0 10.0.1.5/24
ip link set dev tap0 up
&lt;/code>&lt;/pre>&lt;/div>
&lt;h3 id="设备驱动">
 &lt;strong>设备驱动&lt;/strong>
 &lt;a class="anchor" href="#%e8%ae%be%e5%a4%87%e9%a9%b1%e5%8a%a8">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Tun/tap 驱动程序中包含两个部分，一部分是字符设备驱动，还有一部分是网卡驱动。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/network/vmware/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/vmware/</guid><description>&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/a745233700/article/details/90230490" rel="noopener" target="_blank">https://blog.csdn.net/a745233700/article/details/90230490&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/core/fs/ext2/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/core/fs/ext2/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introext2-fs">
 Intro(EXT2-FS)
 &lt;a class="anchor" href="#introext2-fs">#&lt;/a>
&lt;/h2>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/core/fs/ext2/ext2-intro-01.png" alt="" width="100%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="注意">
 注意
 &lt;a class="anchor" href="#%e6%b3%a8%e6%84%8f">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> &lt;code>a).&lt;/code>: 上述的图例是模拟 1M 的 &lt;strong>ext2&lt;/strong> 文件系统，采用 block = 1024B ,inode size = 128B，进行划分的。
&lt;br>&lt;code>b).&lt;/code>: 转换成数值的时候是小端读取。比如 [80 00 00 00] ==int=&amp;gt; 0x00000080 = 0x80 = 128。
&lt;br>&lt;code>c).&lt;/code>: bitmap 采用的是 (MSB)10001001(LSB)，参考 


 &lt;a href="https://www.nongnu.org/ext2-doc/ext2.html#block-bitmap" rel="noopener" target="_blank">block-bitmap 中的部分描述&lt;/a>、以及 


 &lt;a href="https://en.wikipedia.org/wiki/Bit_numbering" rel="noopener" target="_blank">wiki&lt;/a>，比如 10000111，指的是第1，2，3，8个，不是1，6，7，8。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="准备">
 准备
 &lt;a class="anchor" href="#%e5%87%86%e5%a4%87">#&lt;/a>
&lt;/h3>
&lt;p class="warn">在 Ubuntu-22.04 上准备两个文件系统，一个干净的 &lt;strong>fs1m&lt;/strong>，一个需要写入数据作对比 &lt;strong>fs1m-with-data&lt;/strong>。


 &lt;a href="https://github.com/xhsgg12302/knownledges/blob/f72899b6dc6cfddd1c44428ecfda7e9d5d819356/.images/devops/os/core/fs/ext2/fs1m" rel="noopener" target="_blank"> fs1m 备份下载&lt;/a>、


 &lt;a href="https://github.com/xhsgg12302/knownledges/blob/f72899b6dc6cfddd1c44428ecfda7e9d5d819356/.images/devops/os/core/fs/ext2/fs1m-with-data" rel="noopener" target="_blank">fs1m-with-data 备份下载&lt;/a>
&lt;br>创建一个1M的文件：&lt;code>dd if=/dev/zero of=fs1m count=256 bs=4K&lt;/code>
&lt;br>格式化文件系统：&lt;code>mke2fs -b 1024 -I 128 fs1m&lt;/code>
&lt;br>查看格式化后的信息：&lt;code>dumpe2fs fs1m&lt;/code>
&lt;br>&lt;br>复制 &lt;strong>fs1m&lt;/strong> 到 &lt;strong>fs1m-with-data&lt;/strong>
&lt;br>挂载：&lt;code>mount -o loop fs1m-with-data /mnt&lt;/code>
&lt;br>进入目录并写入数据：&lt;code>cd /mnt &amp;amp;&amp;amp; mkdir 12302 &amp;amp;&amp;amp; cd 12302 &amp;amp;&amp;amp; echo 'something' &amp;gt; Hello.java&lt;/code>
&lt;br>卸载：&lt;code>umount /mnt&lt;/code>
&lt;br>&lt;br>使用 


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/devops/os/util/xxd/' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/devops/os/util/xxd/">xxd&lt;/a> 查看十六进制信息：&lt;code>xxd -a -u -g1 -s 1024 -l 16 fs1m&lt;/code> //使用*代替连续00，大写字母输出，一个字节分割，offset=1024, len=16。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/linux/auto-up/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/linux/auto-up/</guid><description>&lt;h1 id="配置linux开机自启动">
 配置Linux开机自启动
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%aelinux%e5%bc%80%e6%9c%ba%e8%87%aa%e5%90%af%e5%8a%a8">#&lt;/a>
&lt;/h1>
&lt;h2 id="方式一rclocal启动说明">
 方式一，(rc.local)启动说明
 &lt;a class="anchor" href="#%e6%96%b9%e5%bc%8f%e4%b8%80rclocal%e5%90%af%e5%8a%a8%e8%af%b4%e6%98%8e">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>脚本位置&lt;/p>
&lt;p>&lt;code>/etc/rc.local -&amp;gt; /etc/rc.d/rc.local&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>脚本内容&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"> #!/bin/bash
 # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
 #
 # It is highly advisable to create own systemd services or udev rules
 # to run scripts during boot instead of using this file.
 #
 # In contrast to previous versions due to parallel execution during boot
 # this script will NOT be run after all other services.
 #
 # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
 # that this script will be executed during boot.

 touch /var/lock/subsys/local


 # nexus(maven personal server)
 # https://download.sonatype.com/nexus/oss/nexus-2.14.10-01-bundle.tar.gz
 su elizabeth -c &amp;quot;/home/elizabeth/nexus/nexus-2.14.10-01/bin/runself&amp;quot;

 # tomcat launch by self
 su elizabeth -c &amp;quot;/home/elizabeth/tomcat-8/apache-tomcat-8.0.53/bin/runself&amp;quot;

 # frp(forNAT)
 su elizabeth -c &amp;quot;/home/elizabeth/frp/frp_0.20.0_linux_amd64/frp_0.20.0_linux_amd64/runself&amp;quot;

 #su elizabeth -c &amp;quot;nohup /home/elizabeth/frp/frp_0.20.0_linux_amd64/frp_0.20.0_linux_amd64/frps -c frps.ini &amp;gt;frps.log 2&amp;gt;&amp;amp;1 &amp;amp;&amp;quot;


 # redis into end to ensure boot successfully
 /home/elizabeth/redis-4/redis-4.0.11/src/redis-server

 exit 0

&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>nexus(runself)&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/linux/no-pass-login/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/linux/no-pass-login/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introlinux免密登录">
 Intro(Linux免密登录)
 &lt;a class="anchor" href="#introlinux%e5%85%8d%e5%af%86%e7%99%bb%e5%bd%95">#&lt;/a>
&lt;/h2>
&lt;p class="warn">参考：


 
 

 
 
 
 
 
 
 
 &lt;a href='../../../network/ssh/#ssh%e7%99%bb%e5%bd%95' rel="noopener" class="internal-link" data-src="../../../network/ssh/#ssh%e7%99%bb%e5%bd%95">SSH登录&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>


 
 

 
 
 
 
 
 
 
 &lt;a href='../../../network/ssh/#ssh%e7%99%bb%e5%bd%95' rel="noopener" class="internal-link" data-src="../../../network/ssh/#ssh%e7%99%bb%e5%bd%95">SSH登录&lt;/a>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/auto-ssh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/auto-ssh/</guid><description>&lt;h2 id="auto">
 AUTO
 &lt;a class="anchor" href="#auto">#&lt;/a>
&lt;/h2>
&lt;p class="tip"> 使用密码自动登录&lt;/p>
&lt;h3 id="usrlocalbinssh">
 /usr/local/bin/ssh
 &lt;a class="anchor" href="#usrlocalbinssh">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 先安装 sshpass 
brew install hudochenkov/sshpass/sshpass
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/zsh

host=$1
#password=`awk &amp;quot;/#Password/ &amp;amp;&amp;amp; inhost { print \\\$2 } /Host/ { inhost=0 } /Host $host/ { inhost=1 }&amp;quot; ~/.ssh/config`
password=`awk &amp;quot;/#Password/ &amp;amp;&amp;amp; inhost { print \\\$2 } /Host / { inhost = 0 } /Host $host/ { inhost=1 }&amp;quot; ~/.ssh/config`

if [[ -z &amp;quot;$password&amp;quot; ]]; then
 /usr/bin/ssh $*
else
 sshpass -p $password /usr/bin/ssh $*
fi
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">Host local
 HostName 127.0.0.1
 User root
 Port 23

Host rein
 HostName 47.98.226.149
 User rein
 Port 13322
 IdentityFile ~/.ssh/rein_id
 #Password 1***********0

Host meta
 HostName 10.28.4.2
 User root
 Port 22
 IdentityFile ~/.ssh/meta-just.pem

Host msb1v1
 HostName m.meishubao.com
 User wtf
 Port 2220
 #Password ********!
 # ProxyCommand sshpass -p *******! ssh -t -p %p %r@%h
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://askubuntu.com/questions/87956/can-you-set-passwords-in-ssh-config-to-allow-automatic-login" rel="noopener" target="_blank">https://askubuntu.com/questions/87956/can-you-set-passwords-in-ssh-config-to-allow-automatic-login&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://stackoverflow.com/questions/32255660/how-to-install-sshpass-on-mac" rel="noopener" target="_blank">https://stackoverflow.com/questions/32255660/how-to-install-sshpass-on-mac&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.ohse.de/uwe/software/lrzsz.html" rel="noopener" target="_blank">https://www.ohse.de/uwe/software/lrzsz.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/trzsz/trzsz" rel="noopener" target="_blank">https://github.com/trzsz/trzsz&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/trzsz/trzsz/tree/main/trzsz-iterm2" rel="noopener" target="_blank">https://github.com/trzsz/trzsz/tree/main/trzsz-iterm2&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/automator/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/automator/</guid><description>&lt;h2 id="automator">
 Automator
 &lt;a class="anchor" href="#automator">#&lt;/a>
&lt;/h2>
&lt;h2 id="demo">
 DEMO
 &lt;a class="anchor" href="#demo">#&lt;/a>
&lt;/h2>
&lt;h6 id="close-viscosity" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="burp-suite-pro" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ommited" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="close-viscosity" class="docsify-tabs__tab" data-tab="close-viscosity">close-viscosity&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="close-viscosity">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 在 macOS 上实现到某个时间点自动关闭某个软件，可以使用 AppleScript 脚本结合定时任务来实现。以下是一种可能的实现方式：
# 1.打开 &amp;quot;Script Editor&amp;quot; 应用程序：在 Launchpad 或者应用程序文件夹中找到 &amp;quot;Script Editor&amp;quot; 应用程序并打开。
# 2.编写 AppleScript 脚本：在 &amp;quot;Script Editor&amp;quot; 中编写一个 AppleScript 脚本，用于关闭指定的软件。例如，假设要关闭 Safari 浏览器，脚本内容如下：
tell application &amp;quot;Safari&amp;quot;
 quit
end tell
# 3.保存脚本：将脚本保存为可执行文件。选择 &amp;quot;File&amp;quot; -&amp;gt; &amp;quot;Export...&amp;quot;，选择 &amp;quot;File Format&amp;quot; 为 &amp;quot;Application&amp;quot;，然后保存到你喜欢的位置，例如桌面上。
# 4.创建定时任务：打开 &amp;quot;Automator&amp;quot; 应用程序，选择 &amp;quot;New Document&amp;quot;，然后选择 &amp;quot;Calendar Alarm&amp;quot;。
# 5.添加操作步骤：在右侧的操作库中，搜索并添加 &amp;quot;Run AppleScript&amp;quot; 操作步骤。
# 6.编写 AppleScript 代码：在 &amp;quot;Run AppleScript&amp;quot; 步骤中，将以下代码替换为你保存的脚本文件的路径：
do shell script &amp;quot;open /path/to/your/script.app&amp;quot;
# 7.保存这个automator.设定保存选项
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/automator-quit-viscosity-01.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/brew/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/brew/</guid><description>&lt;h2 id="brew">
 brew
 &lt;a class="anchor" href="#brew">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="切换版本">
 切换版本
 &lt;a class="anchor" href="#%e5%88%87%e6%8d%a2%e7%89%88%e6%9c%ac">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p>
&lt;code>brew unlink node@18&lt;/code>
&lt;br>&lt;code>brew link --overwrite --force node@14&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="安装软件">
 安装软件
 &lt;a class="anchor" href="#%e5%ae%89%e8%a3%85%e8%bd%af%e4%bb%b6">#&lt;/a>
&lt;/h3>
&lt;h6 id="1官网旧版本formula" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="2自定义仓库" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="1官网旧版本formula" class="docsify-tabs__tab" data-tab="1、官网旧版本Formula">1、官网旧版本Formula&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="1官网旧版本formula">
&lt;p class="warn">gdb example&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># ref from: https://stackoverflow.com/questions/62785290/installing-previous-versions-of-a-formula-with-brew-extract

# TAP=... # &amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;, for example &amp;quot;my-org/homebrew-old&amp;quot;
# MODULE=... # name of module you want to install, e.g. &amp;quot;hugo&amp;quot;
# VERS=... # version of $MODULE you want to install, e.g., &amp;quot;0.80.0&amp;quot;

brew tap-new 12302/gdb
# 在最新的仓库中提取原来的版本到新建的tap.
brew extract --version 13.1 gdb 12302/gdb
# 运行安装命令（其实这个时候已经可以通过 brew search gdb 搜索到需要安装版本的软件了）
brew install 12302/gdb/gdb@13.1
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/brew-search-01.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/burp-suite-pro/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/burp-suite-pro/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introburp-suite-pro">
 Intro(Burp-Suite-Pro)
 &lt;a class="anchor" href="#introburp-suite-pro">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 抓包软件&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/burp-suite-pro-activate-01.png" alt="" width="100%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/burp-suite-pro-activate-02.png" alt="" width="100%">&lt;/p>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://pan.baidu.com/s/1ftFPsURlTD_sCIzHziKwKQ?pwd=5rbq" rel="noopener" target="_blank">组合包：Burp_Suite_Pro_v1.7.31_Loader_Keygen.zip 包括注册机jar包和官方的jar包&lt;/a>
&lt;br>也就是当前这个使用的是官方的，而不是修改过的。
&lt;br>&lt;br>


 &lt;a href="https://pan.baidu.com/s/1cCj6ESFtc7ebwXNXbFZczQ?pwd=picz" rel="noopener" target="_blank">单独注册机下载：burp-loader-keygen.jar&lt;/a>。 &lt;span style="color: #dc3545;">需要注意注册机有的有后门，可以参考：


 &lt;a href="https://www.anquanke.com/post/id/96866/" rel="noopener" target="_blank">恶意软件逆向：burpsuite 序列号器后门分析&lt;/a>&lt;/span>
&lt;br>&lt;br>


 &lt;a href="https://portswigger.net/burp/releases/professional-1-7-31" rel="noopener" target="_blank">官方下载地址: https://portswigger.net/burp/releases/professional-1-7-31&lt;/a>
&lt;br>


 &lt;a href="https://portswigger-cdn.net/burp/releases/download?product=pro&amp;version=1.7.31&amp;type=Jar" rel="noopener" target="_blank">单独应用下载：burpsuite_pro_v1.7.31.jar&lt;/a>。
&lt;br>可以通过&lt;code>shasum -a 256 burpsuite_pro_v1.7.31.jar&lt;/code>，&lt;code>md5 burpsuite_pro_v1.7.31.jar&lt;/code>查看当前包的sha256和md5与官方进行对比。&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/burp-suite-pro-01.png" alt="" width="50%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/burp-suite-pro-02.png" alt="" width="49%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="激活">
 激活
 &lt;a class="anchor" href="#%e6%bf%80%e6%b4%bb">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://www.vuln.cn/8847" rel="noopener" target="_blank">placeholder&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="制作app">
 制作APP
 &lt;a class="anchor" href="#%e5%88%b6%e4%bd%9capp">#&lt;/a>
&lt;/h3>
&lt;p class="warn">使用如下命令制作 Mac APP,参考：


 
 

 
 
 
 
 
 
 
 &lt;a href='../automator/#burp-suite-pro' rel="noopener" class="internal-link" data-src="../automator/#burp-suite-pro">Automator中的burp-suite-pro&lt;/a>
&lt;br> JDK1.8启动命令 &lt;code>java -Xbootclasspath/p:/path/burp-loader-keygen.jar -jar /path/burpsuite_pro_v1.7.31.jar&lt;/code>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://pan.baidu.com/s/1ftFPsURlTD_sCIzHziKwKQ?pwd=5rbq" rel="noopener" target="_blank">https://pan.baidu.com/s/1ftFPsURlTD_sCIzHziKwKQ?pwd=5rbq&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.52pojie.cn/thread-691448-1-1.html" rel="noopener" target="_blank">https://www.52pojie.cn/thread-691448-1-1.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.52pojie.cn/thread-997035-1-1.html" rel="noopener" target="_blank">https://www.52pojie.cn/thread-997035-1-1.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.anquanke.com/post/id/96866/" rel="noopener" target="_blank">恶意软件逆向：burpsuite 序列号器后门分析&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/clean-my-mac-x/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/clean-my-mac-x/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introcleanmymacx">
 Intro(CleanMyMacX)
 &lt;a class="anchor" href="#introcleanmymacx">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 电脑清理软件&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/clean-my-mac-x-01.png" alt="" width="100%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/clean-my-mac-x-02.png" alt="" width="78%">&lt;/p>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://go.naodai.org/d/Software/CleanMyMac/CleanMyMac_v4_15_0_macOS.dmg" rel="noopener" target="_blank">CleanMyMac_v4_15_0_macOS.dmg&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.naodai.org/archives/56.html" rel="noopener" target="_blank">https://www.naodai.org/archives/56.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://go.naodai.org/d/Software/CleanMyMac/CleanMyMac_v4_15_0_macOS.dmg" rel="noopener" target="_blank">https://go.naodai.org/d/Software/CleanMyMac/CleanMyMac_v4_15_0_macOS.dmg&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://xiaoxiner-my.sharepoint.com/personal/liulian_xiaoxiner_onmicrosoft_com/_layouts/15/download.aspx?UniqueId=e57a9daa-8261-4774-91cc-b36b1c5cc881&amp;Translate=false&amp;tempauth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfZGlzcGxheW5hbWUiOiJhbGlzdCIsImFwcGlkIjoiNzkwYThhZDYtYTgyZC00NTk1LTg0NmMtNmFkNTg3ZDIwMDA2IiwiYXVkIjoiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwL3hpYW94aW5lci1teS5zaGFyZXBvaW50LmNvbUA4NjU5NmJmZi02MDcwLTQ4NjUtYmYzNy01MGI4N2E2MWJjNzMiLCJjYWNoZWtleSI6IjBoLmZ8bWVtYmVyc2hpcHwxMDAzMjAwMDk5NjM2ZDJhQGxpdmUuY29tIiwiY2lkIjoiUnk4ekFXY1VLRUsrZVdCNkVMdlV6Zz09IiwiZW5kcG9pbnR1cmwiOiJuWURsenpKcWNkR21MVUt0QzVWbTZTUnJmQktpTkx2QUNWVmcwSkN2ZkVZPSIsImVuZHBvaW50dXJsTGVuZ3RoIjoiMTY2IiwiZXhwIjoiMTcxMjY2NDAzNSIsImZhbWlseV9uYW1lIjoi5YiYIiwiZ2l2ZW5fbmFtZSI6IuaBiyIsImlwYWRkciI6IjIwLjE5MC4xNDQuMTcwIiwiaXNsb29wYmFjayI6IlRydWUiLCJpc3MiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAiLCJuYmYiOiIxNzEyNjYwNDM1IiwicHVpZCI6IjEwMDMyMDAwOTk2MzZEMkEiLCJzY3AiOiJhbGxmaWxlcy53cml0ZSIsInNpZ25pbl9zdGF0ZSI6IltcImttc2lcIl0iLCJzaXRlaWQiOiJOR0kzWWpKa09XVXRPVFl4T1MwME1qWTNMV0ptWkdJdE9XRTRPREEyWkRKak0ySTEiLCJ0aWQiOiI4NjU5NmJmZi02MDcwLTQ4NjUtYmYzNy01MGI4N2E2MWJjNzMiLCJ0dCI6IjIiLCJ1cG4iOiJsaXVsaWFuQHhpYW94aW5lci5vbm1pY3Jvc29mdC5jb20iLCJ2ZXIiOiJoYXNoZWRwcm9vZnRva2VuIn0.XVDE93up5BO_RLa4U2WajeK0tdEnfTUGBAFXalIssiM&amp;ApiVersion=2.0" rel="noopener" target="_blank">https://xiaoxiner-my.sharepoint.com/personal/liulian_xiaoxiner_onmicrosoft_com/_layouts/15/download.aspx?UniqueId=e57a9daa-8261-4774-91cc-b36b1c5cc881&amp;Translate=false&amp;tempauth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfZGlzcGxheW5hbWUiOiJhbGlzdCIsImFwcGlkIjoiNzkwYThhZDYtYTgyZC00NTk1LTg0NmMtNmFkNTg3ZDIwMDA2IiwiYXVkIjoiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwL3hpYW94aW5lci1teS5zaGFyZXBvaW50LmNvbUA4NjU5NmJmZi02MDcwLTQ4NjUtYmYzNy01MGI4N2E2MWJjNzMiLCJjYWNoZWtleSI6IjBoLmZ8bWVtYmVyc2hpcHwxMDAzMjAwMDk5NjM2ZDJhQGxpdmUuY29tIiwiY2lkIjoiUnk4ekFXY1VLRUsrZVdCNkVMdlV6Zz09IiwiZW5kcG9pbnR1cmwiOiJuWURsenpKcWNkR21MVUt0QzVWbTZTUnJmQktpTkx2QUNWVmcwSkN2ZkVZPSIsImVuZHBvaW50dXJsTGVuZ3RoIjoiMTY2IiwiZXhwIjoiMTcxMjY2NDAzNSIsImZhbWlseV9uYW1lIjoi5YiYIiwiZ2l2ZW5fbmFtZSI6IuaBiyIsImlwYWRkciI6IjIwLjE5MC4xNDQuMTcwIiwiaXNsb29wYmFjayI6IlRydWUiLCJpc3MiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAiLCJuYmYiOiIxNzEyNjYwNDM1IiwicHVpZCI6IjEwMDMyMDAwOTk2MzZEMkEiLCJzY3AiOiJhbGxmaWxlcy53cml0ZSIsInNpZ25pbl9zdGF0ZSI6IltcImttc2lcIl0iLCJzaXRlaWQiOiJOR0kzWWpKa09XVXRPVFl4T1MwME1qWTNMV0ptWkdJdE9XRTRPREEyWkRKak0ySTEiLCJ0aWQiOiI4NjU5NmJmZi02MDcwLTQ4NjUtYmYzNy01MGI4N2E2MWJjNzMiLCJ0dCI6IjIiLCJ1cG4iOiJsaXVsaWFuQHhpYW94aW5lci5vbm1pY3Jvc29mdC5jb20iLCJ2ZXIiOiJoYXNoZWRwcm9vZnRva2VuIn0.XVDE93up5BO_RLa4U2WajeK0tdEnfTUGBAFXalIssiM&amp;ApiVersion=2.0&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/launchctl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/launchctl/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="launchctl">
 launchctl
 &lt;a class="anchor" href="#launchctl">#&lt;/a>
&lt;/h2>
&lt;p class="tip"> 简单解释，launchd是一套统一的开源服务管理框架，它用于启动、停止以及管理后台程序、应用程序、进程和脚本。launchd是macOS第一个启动的进程，该进程的PID为1，整个系统的其他进程都是它创建的。
&lt;br>&lt;br>&lt;code>1).&lt;/code> 当launchd启动后，它会扫描&lt;code>/System/Library/LaunchDaemons&lt;/code>和&lt;code>/Library/LaunchDaemons&lt;/code>中的plist文件并加载他们；
&lt;br>&lt;code>2).&lt;/code> 当输入密码登录系统后，launchd会扫描&lt;code>/System/Library/LaunchdAgents&lt;/code>、&lt;code>/Library/LaunchAgents&lt;/code>、&lt;code>~/Library/LaunchAgents&lt;/code>这三个目录中的plist文件并加载它们。每个plist文件都是一个任务，加载不代表立即运行，只有设置了&lt;strong>RunAtLoad为true或keepAlive为true&lt;/strong>时，才会加载并同时启动这些任务。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>name&lt;/th>
&lt;th>ope&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>帮助&lt;/td>
&lt;td>&lt;code>launchctl help&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>列出所有由launchd管理的进程&lt;/td>
&lt;td>&lt;code>launchctl list&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>加载&lt;/td>
&lt;td>&lt;code>launchctl load ~/Library/LaunchAgents/docs.wtfu.site.plist&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>卸载&lt;/td>
&lt;td>&lt;code>launchctl unload ~/Library/LaunchAgents/docs.wtfu.site.plist&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>启动 (luanchctl start &lt;code>&amp;lt;Label&amp;gt;&lt;/code>)&lt;/td>
&lt;td>&lt;code>launchctl start dos.wtfu.site&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>关闭&lt;/td>
&lt;td>&lt;code>launchctl stop dos.wtfu.site&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;ul>
&lt;li>
&lt;h3 id="restart">
 restart
 &lt;a class="anchor" href="#restart">#&lt;/a>
&lt;/h3>
&lt;p class="warn">摘自 


 &lt;a href="https://serverfault.com/questions/194832/how-to-start-stop-restart-launchd-services-from-the-command-line" rel="noopener" target="_blank">How to start/stop/restart launchd services from the command line?&lt;/a>
&lt;br>Just in case if you are looking for launchctl reload, you can define shell function in your ~/.bashrc/.zshrc as I did:
&lt;br>Command execution looks like -&amp;gt; &lt;code>lctl reload &amp;lt;your-plist-name&amp;gt;.plist&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/middle-click/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/middle-click/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intromiddle">
 Intro(Middle)
 &lt;a class="anchor" href="#intromiddle">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">因为 IDEA 中的 debug 相关功能的设置，比如 


 &lt;a href="https://www.jetbrains.com/help/idea/using-breakpoints.html#enabled" rel="noopener" target="_blank">breakponits-enabled&lt;/a>。里面提及到如果修改点击断点的默认行为，则会使用到 &lt;strong>拖动到断点到编辑区域或者点击鼠标中间的按钮&lt;/strong>。使用触摸板的话就只能模拟了。
&lt;br>经查，有个叫


 &lt;a href="https://middleclick.app/" rel="noopener" target="_blank">&lt;code>middle&lt;/code>&lt;/a>的软件，可以实现类似功能。但是收费，所以找破解版。如下下载：
&lt;br>&lt;br> 下载来源：


 &lt;a href="https://www.digit77.com/apps/middle.html" rel="noopener" target="_blank">Middle 1.8.8 破解版 – 触控板辅助和增强应用&lt;/a>
&lt;br>下载地址：


 &lt;a href="https://s91.nitroflare.com/d/f67655d5f5fccf50e4b3e7bb461d0103/Middle%201.8.8%20Crked%20-%20Digit77.com.dmg" rel="noopener" target="_blank">Middle 1.8.8 Crked - Digit77.com.dmg&lt;/a>。（后期不知道会不会失效）。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="激活">
 激活
 &lt;a class="anchor" href="#%e6%bf%80%e6%b4%bb">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 如果出现 文件无法打开或者损坏的情况，本机是 &lt;strong>Sequoia 15&lt;/strong>，到隐私安全中设置允许任何来源就行。安装完之后在设置回去就行。
&lt;br>&lt;br>备注指令：&lt;code>sudo spctl --master-disable&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/middle-click-01.png" alt="" width="100%">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.digit77.com/apps/middle.html" rel="noopener" target="_blank">https://www.digit77.com/apps/middle.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.digit77.com/solutions/mac-apps-cant-be-opened.html" rel="noopener" target="_blank">https://www.digit77.com/solutions/mac-apps-cant-be-opened.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/parallels-desktop/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/parallels-desktop/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="parallels-desktoppd">
 Parallels Desktop(PD)
 &lt;a class="anchor" href="#parallels-desktoppd">#&lt;/a>
&lt;/h2> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/parallels-desktop-01.png" alt="" width="100%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/parallels-desktop-02.png" alt="" width="95%">&lt;/p>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://download.parallels.com/desktop/v19/19.1.0-54729/ParallelsDesktop-19.1.0-54729.dmg" rel="noopener" target="_blank">ParallelsDesktop-19.1.0-54729.dmg&lt;/a>
&lt;br>


 &lt;a href="https://pan.luoxx.top/api/v3/file/download/j9XKsZ1niPhPlzxW?sign=Ao9lg-CY10B9ij93XWJGRLok7hAkj1QD9bufTk9IRmE%3D%3A1713414743" rel="noopener" target="_blank">Parallels Desktop Activation Tool 4.0.0 [MacKed].dmg&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="激活">
 激活
 &lt;a class="anchor" href="#%e6%bf%80%e6%b4%bb">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p>&lt;p>
&lt;br>1). 打开激活工具，如图，直接双击就能启动激活工具，无需把工具移动到应用程序目录。当然，移动到应用程序目录后再打开也是没问题的。
&lt;br>2). 运行激活工具后，点击弹出窗口的安装补丁按钮，输入密码即可。
&lt;br>3). 激活之后再次打开pd，会报“请移动到废纸篓”，只需要打开访达，点击侧边栏的应用程序,找到pd，右键打开即可。（只有激活后第一次打开需要如此操作）&lt;/p>
&lt;/p>&lt;/div>
&lt;p style="text-align: center;">&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/parallels-desktop-03.png" alt="" width="50%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="windows镜像">
 windows镜像
 &lt;a class="anchor" href="#windows%e9%95%9c%e5%83%8f">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p>&lt;p>
&lt;br> 官方下载页面：https://www.microsoft.com/zh-cn/software-download/windows10ISO
&lt;br>&lt;del>


 &lt;a href="https://software.download.prss.microsoft.com/dbazure/Win10_22H2_Chinese_Simplified_x64v1.iso?t=d25e3a24-f8ab-4eda-ae50-39cdf26d988a&amp;P1=1713504029&amp;P2=601&amp;P3=2&amp;P4=Kd%2f1QWtTwdpkA%2fUTziLrvRuZlYGzeOf7ka39vcJuvstL6MTpf%2fy%2fR5EWjMdslPmTv%2b1itPLmJYLm%2b2MKp%2b0wGsbp5rV9YAHDw9V3Z3YYWjCoPFEZaZ6cl5J2B3rGqSDERKrlFTcA%2fUYjcykedNV%2fD6QPe%2fOjQQFhJgUgKsNNy7KDiN82OGOHAFW2xdXgS5XwBiQ56q3I9UqNBqz2yL1w6j0Y6y6FvSnpOM4ioU54f30E%2brZbsDcBxx0H6tQ0amlCLZnKq25j8Yx9mExZY5Y8FslKjLsqYbinBmy8y0A%2fo85lIzkRDXtseJK2ceWfZw7sK6YQKuaiJ9y6V4erewbSwA%3d%3d" rel="noopener" target="_blank">Win10_22H2_Chinese_Simplified_x64v1.iso&lt;/a>&lt;/del>
&lt;br>&lt;br>


 &lt;a href="https://msdn.itellyou.cn" rel="noopener" target="_blank">MSDN&lt;/a>
&lt;br> 


 &lt;a href="ed2k://|file|cn_windows_10_business_editions_version_1909_updated_jan_2020_x64_dvd_b3e1f3a6.iso|5311711232|3527D2A9845FF4105F485CC364655B66|/" rel="noopener" target="_blank">Windows 10 (business editions), version 1909 (updated Jan 2020) (x64) - DVD (Chinese-Simplified)&lt;/a>
&lt;br> 


 &lt;a href="ed2k://|file|cn_windows_10_multiple_editions_x64_dvd_6848463.iso|4303300608|94FD861E82458005A9CA8E617379856A|/" rel="noopener" target="_blank">Windows 10 (Multiple Editions) (x64) - DVD (Chinese-Simplified)&lt;/a>
&lt;br> 


 &lt;a href="ed2k://|file|cn_windows_7_ultimate_x64_dvd_x15-66043.iso|3341268992|7DD7FA757CE6D2DB78B6901F81A6907A|/" rel="noopener" target="_blank">Windows 7 Ultimate (x64) - DVD (Chinese-Simplified) &lt;/a>
&lt;br> 


 &lt;a href="ed2k://|file|cn_windows_7_professional_x64_dvd_x15-65791.iso|3341268992|3474800521D169FBF3F5E527CD835156|/" rel="noopener" target="_blank">Windows 7 Professional (x64) - DVD (Chinese-Simplified)&lt;/a>
&lt;br> 


 &lt;a href="ed2k://|file|cn_windows_7_enterprise_x64_dvd_x15-70741.iso|3203516416|876DCF115C2EE28D74B178BE1A84AB3B|/" rel="noopener" target="_blank">Windows 7 Enterprise (x64) - DVD (Chinese-Simplified)&lt;/a>
&lt;br> Windows 11 (business editions), version 23H2 (updated April 2024) (x64) - DVD (Chinese-Simplified)
&lt;br>       


 &lt;a href="ed2k://|file|zh-cn_windows_11_business_editions_version_23h2_updated_april_2024_x64_dvd_3db5a62b.iso|6911524864|11AD95A6DA81712DA2D18AFA721F4476|/" rel="noopener" target="_blank">ed2k&lt;/a>
&lt;br>       


 &lt;a href="magnet:\\?xt=urn__colon__btih__colon__7be1594b680a778a9c9f73a3929ed92a730a986d&amp;dn=zh-cn_windows_11_business_editions_version_23h2_updated_april_2024_x64_dvd_3db5a62b.iso&amp;xl=6911524864" rel="noopener" target="_blank">bt&lt;/a>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/viscosity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/viscosity/</guid><description>&lt;h2 id="viscosity">
 viscosity
 &lt;a class="anchor" href="#viscosity">#&lt;/a>
&lt;/h2>
&lt;p class="warn">多vpn链接软件，和 TunnelBlick属于同一类软件&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://www.digit77.com/macapps/viscosity/#download-explan" rel="noopener" target="_blank">https://www.digit77.com/macapps/viscosity/#download-explan&lt;/a>
&lt;br>


 &lt;a href="https://pan.baidu.com/disk/main#/index?category=all&amp;path=%2FMAC" rel="noopener" target="_blank">https://pan.baidu.com/disk/main#/index?category=all&amp;amp;path=%2FMAC&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/viscosity-download-01.png" alt="" width="42%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/viscosity-download-02.png" alt="" width="56%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="激活">
 激活
 &lt;a class="anchor" href="#%e6%bf%80%e6%b4%bb">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 激活步骤：
	之前激活过的一般情况下只要激活没失效就无需再次激活！

	1.	Viscosity 运行后，提示安装帮助工具（Viscosity Helper Tool Installation），点击「Install」，输入电脑密码安装。（没有此步骤请跳过）
	2.	弹出登录界面，点击『Continue without account』蓝色文字（没有此步的话请跳过）
	3.	点击任务栏的(桌面右上角)「一个圆圈和一把锁的图标」，再点击「设置」，再点击「关于」，然后点击「注册」，输入以下激活码，点击提交即可。
	4.	激活成功，尽情享用吧。
	因某些代理软件会接管系统的 Hosts 导致 Hosts 屏蔽官方验证失效，从而导致使用过程中激活失效，遇到这种情况的请安装防火墙软件，禁止此应用的传入即可！

	激活码：(1.9,1.10 通用)
	Black Flag
	random@user.com
	VM1U-QY3G41-XN5IYG-WIOCN2-RX7ZDS-UCHA4Y

	Viscosity for mac注册码：
	The Shark
	deep@sea.com
	VM1U-JKJRW4-2NSXY4-G25K7Q-AU6LCU-I56CL4
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/viscosity-activate-01.png" alt="">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="导入tunnelblick配置">
 导入TunnelBlick配置
 &lt;a class="anchor" href="#%e5%af%bc%e5%85%a5tunnelblick%e9%85%8d%e7%bd%ae">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 从Tunnelblick 导入配置
~/Library/Application Support/Tunnelblick
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.sparklabs.com/viscosity/" rel="noopener" target="_blank">https://www.sparklabs.com/viscosity/&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.digit77.com/macapps/viscosity/#download-explan" rel="noopener" target="_blank">https://www.digit77.com/macapps/viscosity/#download-explan&lt;/a> (多版本 1.9,1.10居多。[mac 13.3.1 (22E261)], 用1.10好使。)&lt;/li>
&lt;li>


 &lt;a href="https://pan.baidu.com/disk/main#/index?category=all&amp;path=%2FMAC" rel="noopener" target="_blank">https://pan.baidu.com/disk/main#/index?category=all&amp;path=%2FMAC&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/mac/vmware-fusion-pro/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/mac/vmware-fusion-pro/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="vmware-fusion-pro">
 VMware fusion pro
 &lt;a class="anchor" href="#vmware-fusion-pro">#&lt;/a>
&lt;/h2> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/vmware-fusion-pro-01.png" alt="" width="100%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/mac/vmware-fusion-pro-02.png" alt="" width="95%">&lt;/p>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="下载">
 下载
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://download3.vmware.com/software/FUS-1351/VMware-Fusion-13.5.1-23298085_universal.dmg" rel="noopener" target="_blank">VMware-Fusion-13.5.1-23298085_universal.dmg&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="激活">
 激活
 &lt;a class="anchor" href="#%e6%bf%80%e6%b4%bb">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#任选其一激活即可
4A4RR-813DK-M81A9-4U35H-06KND
NZ4RR-FTK5H-H81C1-Q30QH-1V2LA ✅
4C21U-2KK9Q-M8130-4V2QH-CF810
MC60H-DWHD5-H80U9-6V85M-8280D
HF200-0W05K-089X8-4R1EK-032J0
JU090-6039P-08409-8J0QH-2YR7F
4Y09U-AJK97-089Z0-A3054-83KLA
ZF3R0-FHED2-M80TY-8QYGC-NPKYF
YF390-0HF8P-M81RQ-2DXQE-M2UT6
ZF71R-DMX85-08DQY-8YMNC-PPHV8
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="密码">
 密码
 &lt;a class="anchor" href="#%e5%af%86%e7%a0%81">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p>
&lt;br>TPM 模块相关密码：&lt;code>qSscu5b3D2+YMOA9&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="windows11镜像">
 windows11镜像
 &lt;a class="anchor" href="#windows11%e9%95%9c%e5%83%8f">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p>&lt;p>
&lt;br> 下载页面：https://www.microsoft.com/software-download/windows11
&lt;br>&lt;del>


 &lt;a href="https://software.download.prss.microsoft.com/dbazure/Win11_23H2_English_x64v2.iso?t=fc463c11-9d20-4937-9cd1-c73b4a9ceeea&amp;P1=1713409758&amp;P2=601&amp;P3=2&amp;P4=fDxHlJ0FdtjKb%2bWuNauUJTkUOFctr1cTRd7z9kHDMy9p0sPqn78ZIrLVfZNfW5THKNj6sZqe3mkVMRf5ooOvooYfiRnYiNB682Lm8D5Ox1aF5GA5UXY408%2bscSeo7x5Cc%2fiR1GOnh3SCUZKh5NEVczbj%2bSx%2fyFBrYfbYD7d%2bCAPagJUQG%2fQQUOJZT5RrxJHdYR5NFaSORmWybyI%2b85KwdZkknxQ9kUezScWieJz1tXvE8hoYLPTcluir05GCoVGD28CvulVRmO4NtosHi7%2fRxTHJ7Sn3JI8LpdTkK92P5YyYisUxJiXTmwO3eMojpKc%2b5SseNzVGon1mBevNUgfY0w%3d%3d" rel="noopener" target="_blank">Win11_23H2_English_x64v2.iso&lt;/a>&lt;/del>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.weixiaolive.com/post/2e788301.html" rel="noopener" target="_blank">https://www.weixiaolive.com/post/2e788301.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/Alisebeast/article/details/122512795" rel="noopener" target="_blank">https://blog.csdn.net/Alisebeast/article/details/122512795&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/shell/command/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/shell/command/</guid><description>&lt;p>hello command&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/shell/record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/shell/record/</guid><description>&lt;h2 id="命令记录">
 命令记录
 &lt;a class="anchor" href="#%e5%91%bd%e4%bb%a4%e8%ae%b0%e5%bd%95">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# 首例打印数字权限
ls -l | awk 'NR&amp;gt;1{cmd=&amp;quot;stat --printf \&amp;quot;%a\t\&amp;quot; &amp;quot;$9;system(cmd) ;print $0}'
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# 批量删除统一后缀文件
find . -name &amp;quot;*.txt&amp;quot; -type f -delete
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# 文件最好用&amp;quot;&amp;quot;包起来，另外&amp;quot;使用\转义
# 批量文件重命名
ls -l | awk 'NR&amp;gt;1{origin=substr($0,57);now=substr($0,105);cmd=&amp;quot;mv &amp;quot; &amp;quot;\&amp;quot;&amp;quot; origin &amp;quot;\&amp;quot;&amp;quot; &amp;quot; &amp;quot; &amp;quot;\&amp;quot;&amp;quot; now &amp;quot;\&amp;quot;&amp;quot;;system(cmd);}'
# awk 制定截取字符
ls -l | grep '小鱼儿' | awk '{origin=substr($0,index($0,$9),match($0,/\.mp3/));now=&amp;quot;_1_&amp;quot;origin;cmd=&amp;quot;mv &amp;quot; &amp;quot;\&amp;quot;&amp;quot;origin&amp;quot;\&amp;quot;&amp;quot; &amp;quot; &amp;quot; &amp;quot;\&amp;quot;&amp;quot;now&amp;quot;\&amp;quot;&amp;quot;;print cmd}'
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# curl 返回状态码
curl https://www.baidu.com -I -m 10 -o /dev/null -s -w &amp;quot;%{http_code}\n&amp;quot;
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# 删除100分钟内刚猜解压的文件夹及文件，注意这次包含当前目录，需要排除 [.]
find . \( -path &amp;quot;./WEB-INF&amp;quot; -prune -o -cmin -100 \) ! -path './.DS_Store' -ok rm -rf {} \;
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# curl ftp 上传
curl -u wang: -T /Users/stevenobelia/Downloads/temporary-download/阳光电影www.ygdy8.com.拆弹专家2.HD.1080p.国语中字.mkv/阳光电影www.ygdy8.com.拆弹专家2.HD.1080p.国语中 字.mkv ftp://192.168.2.2:2121/Download/
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# xargs 连接多个命令
echo 'obase=10;ibase=16;00020000' | bc | xargs -I % bash -c 'echo &amp;quot;%/2014/2014&amp;quot; | bc '
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!/bin/bash
# 将当前目录下的文件移动到当前目录新建目录中
ls ./ | grep -v 'docs' | xargs -n 1 -I {} mv {} docs
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">#!bin/bash
# 批量修改问价后缀
rename 's/\.jpg$/.webp/' *.jpg
&lt;/code>&lt;/pre>&lt;/div>
&lt;p class="warn">批量转换 webm 到gif
&lt;br>&lt;code>find webps/ -type f -name &amp;quot;*.webp&amp;quot; -print0 | xargs -0 -I{} sh -c 'ffmpeg -y -loglevel quiet -i &amp;quot;{}&amp;quot; -pix_fmt rgb24 &amp;quot;webps-gif/$(basename {}).gif&amp;quot;'&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/shell/syntax/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/shell/syntax/</guid><description>&lt;h2 id="shell环境">
 Shell环境
 &lt;a class="anchor" href="#shell%e7%8e%af%e5%a2%83">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>Shell 变成跟JavaScript，php编程一样，只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。Linux下面的shell很多，常见的又：&lt;/p>
&lt;p>检查是否存在某个文件的命令：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># test命令检测
test -e ./shizi.jpg &amp;amp;&amp;amp; echo 'found' || echo &amp;quot;not&amp;quot;

# [] 方括号检测 *括号内前后都有空格
[ -f ./shizi.jpg ] &amp;amp;&amp;amp; echo 'found' || echo 'not'
&lt;/code>&lt;/pre>&lt;/div>
&lt;/blockquote>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>名称&lt;/th>
&lt;th>路径&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Bourne Shell&lt;/td>
&lt;td>&lt;code>/usr/bin/sh 或者 /bin/sh&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bourne Again Shell&lt;/td>
&lt;td>&lt;code>/bin/bash&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>C Shell&lt;/td>
&lt;td>&lt;code>/usr/bin/csh&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>K Shell&lt;/td>
&lt;td>&lt;code>/usr/bin/ksh&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Shell for Root&lt;/td>
&lt;td>&lt;code>/sbin/sh&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>……&lt;/td>
&lt;td>&lt;code>……&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;em>&lt;code>#!&lt;/code>后面跟解释器路径&lt;/em>&lt;/p>
&lt;p>#!/bin/sh	#!/sbin/sh #!/bin/bash&lt;/p>
&lt;/blockquote>
&lt;h2 id="shell变量">
 Shell变量
 &lt;a class="anchor" href="#shell%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h2>
&lt;h3 id="定义变量">
 定义变量
 &lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h3>
&lt;blockquote>
&lt;p>定义变量时，变量名不加美元符号（$) ，而且变量之间不能有空格。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/softwares/jetbrains/clion-env/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/softwares/jetbrains/clion-env/</guid><description>&lt;h2 id="clion-安装-gdb-工具">
 Clion 安装 GDB 工具
 &lt;a class="anchor" href="#clion-%e5%ae%89%e8%a3%85-gdb-%e5%b7%a5%e5%85%b7">#&lt;/a>
&lt;/h2>
&lt;p>


 
 

 
 
 
 
 
 
 
 &lt;a href='../../../mac/brew/' rel="noopener" class="internal-link" data-src="../../../mac/brew/">brew安装 gdb@13.1&lt;/a>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 结合`brew安装 gdb@13.1`, clion 不支持13.2
# PermissionsDarwin相关操作导入证书，一般不用重启。
# 添加gbd启动初始化脚本
echo 'set startup-with-shell off' &amp;gt;&amp;gt; ~/.gdbinit

# 重要的一点，使用GDB 得关闭 mac sip: 不然会一直hangs住
# 查看：csrutil status， 关闭：csrutil disable
# 结合图片进行gdb debug
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">make -v
# GNU Make 3.81
# This program built for i386-apple-darwin11.3.0
gcc -v 
# Apple clang version 14.0.3 (clang-1403.0.22.14.1)
g++ -v 
# Apple clang version 14.0.3 (clang-1403.0.22.14.1)
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/clion-gdb-config-3.png" alt="" width="98%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/clion-gdb-config-1.png" alt="" width="49%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/clion-gdb-config-2.png" alt="" width="49%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/softwares/jetbrains/goland/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/softwares/jetbrains/goland/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introgoland">
 Intro(GoLand)
 &lt;a class="anchor" href="#introgoland">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="断点不生效">
 断点不生效
 &lt;a class="anchor" href="#%e6%96%ad%e7%82%b9%e4%b8%8d%e7%94%9f%e6%95%88">#&lt;/a>
&lt;/h3>
&lt;p class="warn">GoLand(2023.2.6) 中使用了最新版的 go(go1.23.2 darwin/amd64) 环境，但是由于工具自带的插件中的 dlv 版本为 1.21.0 ，导致 debug 的时候出现下述错误，以致断点不生效:
&lt;br>&lt;strong>WARNING: undefined behavior - version of Delve is too old for Go version 1.23.2 (maximum supported version 1.21)&lt;/strong> 。
&lt;br>&lt;br>根据类似问题 


 &lt;a href="https://youtrack.jetbrains.com/issue/GO-14287/undefined-behavior-version-of-Delve-is-too-old-for-Go-version-1.20.0-maximum-supported-version-1.19#focus=Comments-27-6915232.0-0" rel="noopener" target="_blank">Issues-GO-14287&lt;/a> 中提到修复步骤，使用如下命令进行解决：
&lt;br>&lt;span style='padding-left:2.3em'/>Install dlv binary with &lt;code>go install github.com/go-delve/delve/cmd/dlv@latest&lt;/code>
&lt;br>&lt;span style='padding-left:2.3em'/>Set the &lt;code>dlv.path=&amp;lt;path_to_dlv_executable&amp;gt;&lt;/code> under Help &amp;gt; Edit Custom Properties, 比如：&lt;code>dlv.path=/Users/stevenobelia/.go/bin/dlv&lt;/code>
&lt;br>&lt;span style='padding-left:2.3em'/>Restart GoLand&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> 备注信息 &lt;/p>&lt;p> &lt;code>export GOPATH=/Users/stevenobelia/.go&lt;/code>
&lt;br>设置了&lt;strong>GOPTAH&lt;/strong>环境变量后，dlv二进制文件会存放在&lt;code>$GOPATH/bin&lt;/code>里面。
&lt;br>&lt;br>&lt;code>/Users/stevenobelia/.go/bin/dlv version&lt;/code> 查看刚安装的 dlv 版本
&lt;br>&lt;code>/Applications/GoLand.app/Contents/plugins/go-plugin/lib/dlv/mac/dlv version&lt;/code> 查看 GoLand 自带的 dlv 版本
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/goland-dlv-version-01.png" alt="" width="50%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/softwares/jetbrains/idea-env/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/softwares/jetbrains/idea-env/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="插件">
 插件
 &lt;a class="anchor" href="#%e6%8f%92%e4%bb%b6">#&lt;/a>
&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>column1&lt;/th>
&lt;th>column2&lt;/th>
&lt;th>column3&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Lombok&lt;/td>
&lt;td>Maven Helper&lt;/td>
&lt;td>Mybaits Log Plugin&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Translation&lt;/td>
&lt;td>Find bugs&lt;/td>
&lt;td>RestfulToolkit&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>.ignore&lt;/td>
&lt;td>Alibaba Java Coding Guidelines&lt;/td>
&lt;td>jclasslib bytecode viewer&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Codota&lt;/td>
&lt;td>Material Theme UI&lt;/td>
&lt;td>SequenceDiagram&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>StickyScroll&lt;/td>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h2 id="配置">
 配置
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%ae">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="生成serialversionuid">
 生成serialVersionUID
 &lt;a class="anchor" href="#%e7%94%9f%e6%88%90serialversionuid">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://intellij-support.jetbrains.com/hc/en-us/community/posts/14718197525906-intellij-serialversionuid-generate" rel="noopener" target="_blank">参考&lt;/a>:
&lt;br> File -&amp;gt; Settings -&amp;gt; Editor -&amp;gt; Inspections -&amp;gt; JVM Languages : Find &lt;code>serialization class without 'serialVersionUID'&lt;/code> and check it.
&lt;br> Back to the editor, clicks on the class name, ALT + ENTER (Windows), it will prompts the Add serialVersionUID field option.A new serialVersionUID is auto-generated.&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/softwares/jetbrains/rubymine/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/softwares/jetbrains/rubymine/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introrubymine">
 Intro(RubyMine)
 &lt;a class="anchor" href="#introrubymine">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="sdk警告阻止">
 SDK警告阻止⚠️
 &lt;a class="anchor" href="#sdk%e8%ad%a6%e5%91%8a%e9%98%bb%e6%ad%a2">#&lt;/a>
&lt;/h3>
&lt;p class="warn">IDE中使用了最新版的 ruby sdk(ruby-3.3.1-p55) 环境，但是由于项目中使用的配置&lt;code>Gemfile.lock&lt;/code>中使用&lt;code>BUNDLED WITH \n 2.1.4&lt;/code>版本的bundle，导致每次运行都会出现红色的警告信息。
&lt;br>&lt;br>根据 


 &lt;a href="https://github.com/rubygems/rubygems/issues/5234" rel="noopener" target="_blank">issues-5234&lt;/a> 中提到的bundle版本2.3.4，使用命令&lt;code>/usr/local/opt/ruby/bin/gem install bundler -v 2.3.4&lt;/code>安装，然后修改&lt;code>Gemfile.lock&lt;/code>文件中的&lt;code>BUNDLE WITH&lt;/code>版本即可解决。&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> 备注指令 &lt;/p>&lt;p> &lt;code>/usr/local/opt/ruby/bin/gem pristine --all --no-extensions&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/rubymine-sdk-01.png" alt="" width="29%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/rubymine-sdk-02.png" alt="" width="35%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/softwares/rubymine-sdk-03.png" alt="" width="35%">&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://github.com/rubygems/rubygems/issues/5234" rel="noopener" target="_blank">https://github.com/rubygems/rubygems/issues/5234&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/adb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/adb/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introadb">
 Intro(ADB)
 &lt;a class="anchor" href="#introadb">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="push">
 PUSH
 &lt;a class="anchor" href="#push">#&lt;/a>
&lt;/h3>
&lt;p class="warn">push moive to android:
&lt;br>&lt;code>adb push /path/FILENAME.mp4 /sdcard/&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="systempropgetprop">
 SYSTEMPROP(getprop)
 &lt;a class="anchor" href="#systempropgetprop">#&lt;/a>
&lt;/h3>
&lt;p class="warn">通过


 &lt;a href="https://github.com/topjohnwu/Magisk/blob/master/docs/guides.md#the-system-folder" rel="noopener" target="_blank">magisk设置系统属性&lt;/a>，然后根据


 &lt;a href="https://xdaforums.com/t/how-to-make-adb-listen-to-tcpip-5555-after-reboot.1825359/#post-30032364" rel="noopener" target="_blank">文章&lt;/a>操作：&lt;code>setprop service.adb.tcp.port 5555&lt;/code>:可以让手机中的adbd开放指定的tcp端口，方便连接调试。&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> &lt;code>1).&lt;/code> &lt;span style='color:blue'>一直开放tcp端口也有分险，需要注意。&lt;/span>
&lt;br>&lt;code>2).&lt;/code> 直接在&lt;code>/system/build.prop&lt;/code>文件中编辑不生效(如果对/system分区没有写权限的话)。需要借助 &lt;strong>magisk&lt;/strong> 模块中的&lt;code>system.prop&lt;/code>。&lt;/p>
&lt;/p>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/adb-prop-01.png" alt="" width="48%">
&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/adb-prop-02.png" alt="" width="49%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="adb添加系统证书的方法">
 ADB添加系统证书的方法
 &lt;a class="anchor" href="#adb%e6%b7%bb%e5%8a%a0%e7%b3%bb%e7%bb%9f%e8%af%81%e4%b9%a6%e7%9a%84%e6%96%b9%e6%b3%95">#&lt;/a>
&lt;/h3>
&lt;p class="warn">【


 
 

 
 
 
 
 
 
 
 &lt;a href='../openssl/#adb-%e6%b7%bb%e5%8a%a0%e7%b3%bb%e7%bb%9f%e8%af%81%e4%b9%a6%e6%96%b9%e6%b3%95' rel="noopener" class="internal-link" data-src="../openssl/#adb-%e6%b7%bb%e5%8a%a0%e7%b3%bb%e7%bb%9f%e8%af%81%e4%b9%a6%e6%96%b9%e6%b3%95">Docs|参见&lt;/a>】&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://github.com/12302-bak/awesome-adb" rel="noopener" target="_blank">https://github.com/12302-bak/awesome-adb&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://forum.xda-developers.com/t/a-magisk-script-to-set-adb-tcpip-port-at-startup-without-bricking-my-phone.4533603/" rel="noopener" target="_blank">https://forum.xda-developers.com/t/a-magisk-script-to-set-adb-tcpip-port-at-startup-without-bricking-my-phone.4533603/&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/12302-bak/awesome-adb?tab=readme-ov-file#%E6%97%A0%E7%BA%BF%E8%BF%9E%E6%8E%A5%E6%97%A0%E9%9C%80%E5%80%9F%E5%8A%A9-usb-%E7%BA%BF" rel="noopener" target="_blank">https://github.com/12302-bak/awesome-adb?tab=readme-ov-file#%E6%97%A0%E7%BA%BF%E8%BF%9E%E6%8E%A5%E6%97%A0%E9%9C%80%E5%80%9F%E5%8A%A9-usb-%E7%BA%BF&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://xdaforums.com/t/how-to-make-adb-listen-to-tcpip-5555-after-reboot.1825359/#post-30032364" rel="noopener" target="_blank">https://xdaforums.com/t/how-to-make-adb-listen-to-tcpip-5555-after-reboot.1825359/#post-30032364&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/topjohnwu/Magisk/blob/master/docs/guides.md#the-system-folder" rel="noopener" target="_blank">https://github.com/topjohnwu/Magisk/blob/master/docs/guides.md#the-system-folder&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/bc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/bc/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introbc--basic-calculator">
 Intro(BC | basic calculator)
 &lt;a class="anchor" href="#introbc--basic-calculator">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="保留位数">
 保留位数
 &lt;a class="anchor" href="#%e4%bf%9d%e7%95%99%e4%bd%8d%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>echo 'scale=3; 10 / 3' | bc &lt;/code>
&lt;br>&lt;code>echo 'scale=5; 820 / (480 + 90)' | bc&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="指数对数-计算">
 指数/对数 计算
 &lt;a class="anchor" href="#%e6%8c%87%e6%95%b0%e5%af%b9%e6%95%b0-%e8%ae%a1%e7%ae%97">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> &lt;code>echo '2 ^ 3' | bc&lt;/code>
&lt;br>&lt;code>echo 'log(8,2)' | bc -l&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="异或">
 异或
 &lt;a class="anchor" href="#%e5%bc%82%e6%88%96">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>echo 'ibase=16;obase=10;bxor(1,2)' | bc -l&lt;/code> ==&amp;gt; 3&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="进制转换">
 进制转换
 &lt;a class="anchor" href="#%e8%bf%9b%e5%88%b6%e8%bd%ac%e6%8d%a2">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> &lt;code>1).&lt;/code>: 特别需要注意 ibase，obase，以及值之间的联系，不然会出现意想不到的结果。如下图：


 &lt;a href="https://unix.stackexchange.com/questions/199615/understand-ibase-and-obase-in-case-of-conversions-with-bc" rel="noopener" target="_blank">参见&lt;/a>
&lt;br>简而言之，就是在进制转换的时候，不管&lt;code>ibase&lt;/code>、&lt;code>obase&lt;/code>哪一个在前，都要以前面使用的进制为主，对后面的值以前面的进制进行转换。举例如下：
&lt;br>在2到八进制中，可以写成&lt;code>ibase=2;obase=1000;&lt;/code>，或者&lt;code>obase=8;ibase=2;&lt;/code>，对于第一个，（2，1000），1000 为二进制的值 8，第二个（8，2），2 为八进制中的值 2
&lt;br>&lt;br>&lt;code>2).&lt;/code>: 十六进制中的字母需要大写。小写就是: &lt;strong>(standard_in) 1: syntax error&lt;/strong>。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/find/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/find/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introfind">
 Intro(find)
 &lt;a class="anchor" href="#introfind">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="syntax">
 syntax
 &lt;a class="anchor" href="#syntax">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 1，在home目录下查找txt 结尾或者 sh 结尾的文件
find /home -name &amp;quot;*.txt&amp;quot; -o -name &amp;quot;*.sh&amp;quot;
# 2，查找路径，文件名中包含 lib 的文件
find /home -path &amp;quot;*lib*&amp;quot;
# 3，表达式匹配
find /home -regex &amp;quot;.*(\.txt | \.sh)$&amp;quot;
# 4，否定参数
find /home ! -name &amp;quot;*.txt&amp;quot;
# 5，文件类型
find /home -type [f普通文件 | l符号连接 | d 目录 | c 字符设备| b块设备 | s套接字 | p Fifo]
# 6，目录深度搜索
find /home -maxdepth 3
# 7，文件大小
find /home -size [+10k | -10k | 10K]
# 8，过滤权限拒绝的文件
find /home [-perm 777 | -user tom | -group git]
# 9，exec | ok
find /home -size 10k -[exec | ok] ls -l {} \; 
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="样例">
 样例
 &lt;a class="anchor" href="#%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>&lt;code>find / -name &amp;quot;*.jar&amp;quot; -a -path &amp;quot;*jetbrains*&amp;quot; 2&amp;gt;/dev/null &lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/firewalld/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/firewalld/</guid><description>&lt;h1 id="linux-防火墙">
 Linux 防火墙
 &lt;a class="anchor" href="#linux-%e9%98%b2%e7%81%ab%e5%a2%99">#&lt;/a>
&lt;/h1>
&lt;h2 id="iptables-services">
 iptables-services
 &lt;a class="anchor" href="#iptables-services">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="服务操作">
 服务操作
 &lt;a class="anchor" href="#%e6%9c%8d%e5%8a%a1%e6%93%8d%e4%bd%9c">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>index&lt;/th>
&lt;th>content&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>安装&lt;/td>
&lt;td>&lt;code>yum install iptables-services&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>配置&lt;/td>
&lt;td>&lt;code>vim /etc/sysconfig/iptables&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>永久保存&lt;/td>
&lt;td>&lt;code>service iptables save&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>状态&lt;/td>
&lt;td>&lt;code>systemctl status iptables&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>启动&lt;/td>
&lt;td>&lt;code>systemctl status start&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>停止&lt;/td>
&lt;td>&lt;code>systemctl status stop&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>重启&lt;/td>
&lt;td>&lt;code>systemctl status restart&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>关闭自启服务&lt;/td>
&lt;td>&lt;code>chkconfig iptables off&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>开启自启服务&lt;/td>
&lt;td>&lt;code>chkconfig iptables on&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="格式--t没有-默认filter">
 格式 （-t没有 默认filter）
 &lt;a class="anchor" href="#%e6%a0%bc%e5%bc%8f--t%e6%b2%a1%e6%9c%89-%e9%bb%98%e8%ae%a4filter">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;p class="tip">iptables [-t 表名] 操作选项 [链名] [条件] [-j 控制类型]&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="样例">
 样例
 &lt;a class="anchor" href="#%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 地址转发与伪装:
# 先进行如下的配置
# 1.1.1.200 1.1.1.100(eth1) 172.25.254.72
# server虚拟机 172.25.254.233(eth0) 真机
# desktop虚拟机 
# 源地址地址转发（SNAT）：伪装
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 172.25.254.233

# 目的地地址转发（DNAT）：转发
# desktop中设置:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22 -j DNAT --to-dest 1.1.1.200:22
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>&lt;code>iptables -X -F -Z&lt;/code> &lt;code>：重置防火墙&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -nL INPUT&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -P INPUT DROP&lt;/code> &lt;code>：修改INPUT链默认策略，默认所有链都是[ACCEPT]&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -t filter -I INPUT -p tcp --dport 80 -j DROP&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -D INPUT -p tcp --dport 80 -j DROP&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -D INPUT -p tcp -s 42.89.72.49 --dport 80 -j REJECT&lt;/code>&lt;/li>
&lt;li>&lt;code>cat blacklist.ip | xargs -I % sudo iptables -t filter -A INPUT -s % -j DROP&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEP&lt;/code>&lt;/li>
&lt;li>&lt;code> iptables -I INPUT -i eth0 -p tcp --tcp-flags SYN,RST,ACK SYN -j DROP&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -t filter -A INPUT -p icmp -j REJECT&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -I INPUT -p icmp --icmp-type 8 -j DROP&lt;/code> &lt;code>:我们可以ping别人,但是别人不能ping我们,[OUTPUT|0]相反&lt;/code>&lt;/li>
&lt;li>&lt;code>iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j SNAT --to-source 192.168.200.10&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="注意事项">
 注意事项
 &lt;a class="anchor" href="#%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">1. iptables可以使用扩展bai模块来进行数据包du的匹配，zhi语法就是 -m modaole_name, 所以
-m tcp 的意思是使用zhuan tcp 扩展模块shu的功能 (tcp扩展模块提供权了 --dport, --tcp-flags, --sync等功能）
其实只用 -p tcp 了话， iptables也会默认的使用 -m tcp 来调用 tcp模块提供的功能。
但是 -p tcp 和 -m tcp是两个不同层面的东西，一个是说当前规则作用于 tcp 协议包，而后一是说明要使用iptables的tcp模块的功能 (--dport 等)

1. DROP,REJECT 第一个直接丢弃，需要等待客户端链接超时，而REJECT会返回一个关闭连接信息。响应快点。

2. 使用nat 时注意修改内核参数 `echo &amp;quot;net.ipv4.ip_forward=1&amp;quot; &amp;gt;&amp;gt; /usr/lib/sysctl.d/50-default.conf`(重启) 
或者直接 `echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward` 使用`sysctl -a | grep ip_forward` 查看修改后的属性
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;h2 id="firewalld">
 firewalld
 &lt;a class="anchor" href="#firewalld">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="omitted">
 OMITTED
 &lt;a class="anchor" href="#omitted">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/ly2020_/article/details/90747911" rel="noopener" target="_blank">linux中的防火墙的基本设置&amp;mdash;firewlld、iptables&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/GnuPG/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/GnuPG/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intrognupg">
 Intro(GnuPG)
 &lt;a class="anchor" href="#intrognupg">#&lt;/a>
&lt;/h2>
&lt;p style="text-align: center;">&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/gpg-intro-01.png" alt="" width="70%" title="https">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="基本概念">
 基本概念
 &lt;a class="anchor" href="#%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5">#&lt;/a>
&lt;/h3>
&lt;div class="alert flat tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p>
Key 管理是 GPG 的核心功能，GPG Key 不能简单的理解为非对称加密的 Private Key / Public Key / Key Pair。GPG Key 由如下信息组成：
&lt;br>&lt;br>Key ID: 该 GPG Key 的唯一标识，值为主公钥的指纹，支持多种格式(Fingerprint, Long key ID, Short key ID)，更多参见：What is a OpenPGP/GnuPG key ID?。
&lt;br>UID: 1 个或多个，每个 UID 由 name、email、comment 组成，email 和 comment 可以为空。
&lt;br>Expire: 过期时间，可以为永久。
&lt;br>多个具有不同用途的非对称加密算法中的 Key 的集合。&lt;/p>
&lt;/p>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> key 分类参见下表 &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/hashcat/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/hashcat/</guid><description>&lt;h1 id="hashcat-简单使用">
 hashcat 简单使用
 &lt;a class="anchor" href="#hashcat-%e7%ae%80%e5%8d%95%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h1>
&lt;p class="tip">


 &lt;a href="https://github.com/hashcat/hashcat.git" rel="noopener" target="_blank">https://github.com/hashcat/hashcat.git&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;h2 id="rar-crack">
 rar crack
 &lt;a class="anchor" href="#rar-crack">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 提取hash值，注意裁剪文件名
rar2john 9.rar &amp;gt; example0.hash
# output:
# $rar5$16$8345875512857bc69f0a8059ffce0166$15$7880153df518399181c9e2df158b7249$8$f627000464e14963
# 使用hashcat撞库
hashcat -a 3 -m 13000 -O -1 '?d?l' -D 1,2 -d 3,5 example0.hash '?l?l?l123'
# 自定义字符集
hashcat -a 3 -m 13000 -1 '?d?l' -D 1,2 -d 3,5 example0.hash '?1?1?1?1?1?1'
# hashcat.potfile
# /Users/stevenobelia/.local/share/hashcat/hashcat.potfile
# 查看破解记录
hashcat --show example0.hash
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="注意">
 注意：
 &lt;a class="anchor" href="#%e6%b3%a8%e6%84%8f">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>安装john-ripper后需要链接rar2john



 &lt;a href="https://superuser.com/questions/1652553/john-the-ripper-zip2john-command-not-found-mac/1670026" rel="noopener" target="_blank">https://superuser.com/questions/1652553/john-the-ripper-zip2john-command-not-found-mac/1670026&lt;/a>
创建软链&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/keytool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/keytool/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introkeytool--java--平台证书工具">
 Intro(keytool | Java 平台证书工具)
 &lt;a class="anchor" href="#introkeytool--java--%e5%b9%b3%e5%8f%b0%e8%af%81%e4%b9%a6%e5%b7%a5%e5%85%b7">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/nmap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/nmap/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intronmap--参考指南">
 Intro(Nmap | 参考指南)
 &lt;a class="anchor" href="#intronmap--%e5%8f%82%e8%80%83%e6%8c%87%e5%8d%97">#&lt;/a>
&lt;/h2>
&lt;p class="warn">


 &lt;a href="https://nmap.org/man/zh/index.html#:~:text=是一款,服务的运行。" rel="noopener" target="_blank">拿来主义&lt;/a>：Nmap (“Network Mapper(网络映射器)”) 是一款开放源代码的 网络探测和安全审核的工具。它的设计目标是快速地扫描大型网络，当然用它扫描单个主机也没有问题。Nmap以新颖的方式使用原始IP报文来发现网络上有哪些主机，那些 主机提供什么服务(应用程序名和版本)，那些服务运行在什么操作系统(包括版本信息)， 它们使用什么类型的报文过滤器/防火墙，以及一堆其它功能。虽然Nmap通常用于安全审核， 许多系统管理员和网络管理员也用它来做一些日常的工作，比如查看整个网络的信息， 管理服务升级计划，以及监视主机和服务的运行。
&lt;br>&lt;br>example:
&lt;br>&lt;code>nmap -v -A scanme.nmap.org&lt;/code>
&lt;br>&lt;code>nmap -v -sP 192.168.0.0/16 10.0.0.0/8&lt;/code>
&lt;br>&lt;code>nmap -v -iR 10000 -P0 -p 80&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="端口状态">
 端口状态
 &lt;a class="anchor" href="#%e7%ab%af%e5%8f%a3%e7%8a%b6%e6%80%81">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>state&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>open&lt;/td>
&lt;td>意味着目标机器上的应用程序正在该端口监听连接/报文&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>close&lt;/td>
&lt;td>端口没有应用程序在它上面监听&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>filtered&lt;/td>
&lt;td>意味着防火墙，过滤器或者其它网络障碍阻止了该端口被访问 &lt;br> open/close | filtered :有可能开放/关闭 或者被过滤，拦截等。&lt;br>比如对于&lt;code>open | filtered&lt;/code>来说，如果发送的报文有返回的时候认为是 close 的，那没返回的话就无法确定到底是被过滤了，还是真的 open。也既文档中的 


 &lt;a href="https://nmap.org/man/zh/man-port-scanning-basics.html#:~:text=开放的端口不响应,-就是一个例子" rel="noopener" target="_blank">开放端口不响应&lt;/a> 的意思。UDP，IP协议， FIN，Null，和Xmas扫描可能把端口归入此类。&lt;code>close | filtered&lt;/code> 同理 ， 它只可能出现在IPID Idle扫描中。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>unfiltered&lt;/td>
&lt;td>Nmap 根据目前的探测无法确定它们是关闭还是开放（极少出现的情况吧）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="主机发现">
 主机发现
 &lt;a class="anchor" href="#%e4%b8%bb%e6%9c%ba%e5%8f%91%e7%8e%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="扫描方式">
 扫描方式
 &lt;a class="anchor" href="#%e6%89%ab%e6%8f%8f%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="服务探测">
 服务探测
 &lt;a class="anchor" href="#%e6%9c%8d%e5%8a%a1%e6%8e%a2%e6%b5%8b">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="选项样例">
 选项样例
 &lt;a class="anchor" href="#%e9%80%89%e9%a1%b9%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://nmap.org/man/zh/index.html" rel="noopener" target="_blank">https://nmap.org/man/zh/index.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="options">
 Options
 &lt;a class="anchor" href="#options">#&lt;/a>
&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>option&lt;/th>
&lt;th>expalin&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&amp;ndash;packet-trace&lt;/td>
&lt;td>打印数据包&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ndash;traceroute&lt;/td>
&lt;td>路由追踪&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="principle">
 Principle
 &lt;a class="anchor" href="#principle">#&lt;/a>
&lt;/h2>
&lt;h2 id="examples">
 Examples
 &lt;a class="anchor" href="#examples">#&lt;/a>
&lt;/h2>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/openssl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/openssl/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introopenssl">
 Intro(OPENSSL)
 &lt;a class="anchor" href="#introopenssl">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="证书类型">
 证书类型
 &lt;a class="anchor" href="#%e8%af%81%e4%b9%a6%e7%b1%bb%e5%9e%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn">暂时记录一个 x509 (


 &lt;a href="https://www.rfc-editor.org/rfc/rfc5280.html" rel="noopener" target="_blank">rfc&lt;/a>，


 &lt;a href="https://zh.wikipedia.org/wiki/X.509#证书组成结构" rel="noopener" target="_blank">wiki&lt;/a>)。这种格式一般广泛应用于Web浏览器和服务器之间的SSL/TLS加密通信。
&lt;br>对于这种证书的编码格式有 &lt;strong>der&lt;/strong>, &lt;strong>pem(privvaccy-enhanced mail)&lt;/strong> 等。且可以认为 pem 是 der 二进制的一种 base64编码。可以如下验证：
&lt;br>&lt;br>&lt;code>1.&lt;/code> 下载网站证书并写入到文件：（不是直接下载，而是在 https 握手过程中会携带 


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/devops/network/tls-ssl/#hp-certificate-%e5%ae%9e%e4%be%8b%e5%88%86%e6%9e%90' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/devops/network/tls-ssl/#hp-certificate-%e5%ae%9e%e4%be%8b%e5%88%86%e6%9e%90">证书数据&lt;/a>，openssl 会在这个过程中打印出来，然后我们用工具提取即可）
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>1.1.&lt;/code> &lt;code>openssl s_client -connect wtfu.site:443 &amp;gt; pubkey.pem&lt;/code> (运行可能会卡住，CTRL+c 终止就行)
&lt;br>&lt;span style='padding-left:4.2em'>查看 pubkey.pem 内容：删除&lt;code>-----BEGIN CERTIFICATE-----&lt;/code>和&lt;code>-----END CERTIFICATE-----&lt;/code>之外多余的内容。
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>1.2.&lt;/code> 或者一步到位：&lt;code>openssl s_client -connect wtfu.site:443 &amp;lt;/dev/null 2&amp;gt;/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' &amp;gt; pubkey.pem&lt;/code>
&lt;br>&lt;br>&lt;code>2.&lt;/code> 转换：pem -&amp;gt; der，将除了第一行和最后一行的内容进行 base64 解码，然后写入文件&lt;code>sed '1d;$d' pubkey.pem | base64 -d &amp;gt; pubkey.der&lt;/code>
&lt;br>&lt;code>3.&lt;/code> 提取 pem 证书中的公匙并显示相关信息：&lt;code>openssl x509 -in pubkey.pem -pubkey -noout | openssl ec -pubin -text -noout&lt;/code>
&lt;br>&lt;code>4.&lt;/code> 提取 der   证书中的公匙并显示相关信息：&lt;code>openssl x509 -in pubkey.der -pubkey -noout | openssl ec -pubin -text -noout&lt;/code>
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/openssl-cer-format-01.png" alt="" width="100%">
&lt;br>&lt;br>或者也可以通过 


 &lt;a href="https://asn1js.eu/" rel="noopener" target="_blank">asn1在线解析&lt;/a> 查看 pubkey.der 文件是否正确（DER 本质上是 


 &lt;a href="https://zh.wikipedia.org/wiki/ASN.1" rel="noopener" target="_blank">ASN.1&lt;/a> 结构类型的）。
&lt;br>&lt;br>另外可以计算 sha-256 指纹(对应 chrome 浏览器证书基本信息中的值)，包括 证书和公匙
&lt;br>证书：&lt;code>cat pubkey.der | shasum -a 256&lt;/code>，或者 &lt;code>grep -v ^- pubkey.pem | base64 -d | shasum -a 256&lt;/code>。
&lt;br>公匙：&lt;code>openssl x509 -in &amp;lt;pubkey.der | pubkey.pem&amp;gt; -pubkey -noout | grep -v ^- | base64 -d | shasum -a 256&lt;/code>。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/ranger/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/ranger/</guid><description>&lt;p>hello&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/xargs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/xargs/</guid><description>&lt;p class="tip">用于参数转换，与不支持管道输入的命令搭配使用，比如 &lt;code>ls&lt;/code>.&lt;/p>
&lt;h2 id="options">
 Options
 &lt;a class="anchor" href="#options">#&lt;/a>
&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>options&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>-a&lt;/td>
&lt;td>file 从文件中读入作为stdin&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-e flag&lt;/td>
&lt;td>注意，有的时候可能为-E，flag必须是一个以空格分隔的标志，当分析到含有flag这个标志的时候就停止&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-p&lt;/td>
&lt;td>每当执行一个argument的时候会询问用户&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-n num&lt;/td>
&lt;td>表示命令在执行的时候一次用几个参数，默认是所有&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-t&lt;/td>
&lt;td>表示先打印命令，再执行&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-i | -I&lt;/td>
&lt;td>参数占位符，{}，%，等都可以使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-s&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-r no-run-if-empty&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-L num&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-d delim&lt;/td>
&lt;td>默认的xargs的分隔符是回车，argument的分隔符是空格。这里修改的是xargs的分隔符&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-x exit&lt;/td>
&lt;td>主要配合 -s使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>-P&lt;/td>
&lt;td>修改最大进程数，可以并发执行&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="cation">
 CATION
 &lt;a class="anchor" href="#cation">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">cat &amp;gt; file &amp;lt;&amp;lt;EOF
a b c d e
f g h i j k
l m n o p q r
s t u v
w x y z
EOF

cat file | xargs -L 2 -I {} echo '{}' # 这个命令中 -L 和 -I 指令冲突。所以不会出现预期效果，可以多加一个xargs使用,比如下面
cat file | xargs -L 2 | xargs -I {} echo '{}' # 多加后出现的效果。
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.runoob.com/linux/linux-comm-xargs.html" rel="noopener" target="_blank">https://www.runoob.com/linux/linux-comm-xargs.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.cnblogs.com/chentiao/p/16543679.html" rel="noopener" target="_blank">https://www.cnblogs.com/chentiao/p/16543679.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/util/xxd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/util/xxd/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introxxd">
 Intro(xxd)
 &lt;a class="anchor" href="#introxxd">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="7,13,16,22-24" data-file="options" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">vscode ➜ /workspaces/c_learning/multi-elf (master) $ xxd --help
Usage:
 xxd [options] [infile [outfile]]
 or
 xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]
Options:
 -a toggle autoskip: A single '*' replaces nul-lines. Default off.
 -b binary digit dump (incompatible with -ps,-i). Default hex.
 -C capitalize variable names in C include file style (-i).
 -c cols format &amp;lt;cols&amp;gt; octets per line. Default 16 (-i: 12, -ps: 30).
 -E show characters in EBCDIC. Default ASCII.
 -e little-endian dump (incompatible with -ps,-i,-r).
 -g bytes number of octets per group in normal output. Default 2 (-e: 4).
 -h print this summary.
 -i output in C include file style.
 -l len stop after &amp;lt;len&amp;gt; octets.
 -n name set the variable name used in C include output (-i).
 -o off add &amp;lt;off&amp;gt; to the displayed file position.
 -ps output in postscript plain hexdump style.
 -r reverse operation: convert (or patch) hexdump into binary.
 -r -s off revert with &amp;lt;off&amp;gt; added to file positions found in hexdump.
 -d show offset in decimal instead of hex.
 -s [+][-]seek start at &amp;lt;seek&amp;gt; bytes abs. (or +: rel.) infile offset.
 -u use upper case hex letters.
 -R when colorize the output; &amp;lt;when&amp;gt; can be 'always', 'auto' or 'never'. Default: 'auto'.
 -v show version: &amp;quot;xxd 2023-10-25 by Juergen Weigert et al.&amp;quot;.
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/devops/os/win/netsh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/os/win/netsh/</guid><description>&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 1、语法
netsh interface ip set|show interface|address|dnsservers
netsh interface set|add|show interface

# 2、实践

netsh interface ip show interface
netsh interface ip set address name=&amp;quot;本地连接&amp;quot; source=static|dhcp 192.168.0.192 255.255.255.0 192.168.0.1
netsh interface ip set dnsservers name=&amp;quot;本地连接&amp;quot; source=static addr = 1.2.4.8 primary
netsh interface ip add dnsservers name=&amp;quot;本地连接&amp;quot;  114.114.114.114 index=2
netsh interface set interface [admin=] enabled|disabled [connect=] connected|disconnected [newname=] xhs12302 

# 3、路由表
route print
route delete [traget]
route add [-p] 0.0.0.0 mask 0.0.0.0 192.168.1.1 metric 2 if 2
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/os/util/netsh.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/bytecode/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/bytecode/</guid><description>&lt;!-- varibale -->
&lt;ul>
&lt;li>
&lt;h2 id="introbytecode">
 Intro(ByteCode)
 &lt;a class="anchor" href="#introbytecode">#&lt;/a>
&lt;/h2>
&lt;p>


 &lt;a href="https://github.com/xhsgg12302/knownledges/blob/master/docs/doc/advance/assert/Hello.class" rel="noopener" target="_blank">Hello.class&lt;/a>&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 55%; width: 55%;">
&lt;p class="tip"> 参考
&lt;br>


 &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1" rel="noopener" target="_blank">JDK8 JVM虚拟机实现规范 Chapter 4. The class File Format&lt;/a>，包括


 &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4" rel="noopener" target="_blank">常量池&lt;/a>数据结构
&lt;br>


 &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html" rel="noopener" target="_blank">JDK8 JVM虚拟机实现规范 Chapter 6. The Java Virtual Machine Instruction Set&lt;/a>
&lt;br>&lt;br>工具：
&lt;br>进制转换&lt;code>echo 'ibase=16;12'| bc&lt;/code>
&lt;br>十六进制转utf-8&lt;code>echo -n &amp;quot;6E756D&amp;quot; | xxd -r -p | iconv -f utf-8&lt;/code>&lt;/p>
&lt;p class="warn">下面为java源代码和class字节码。编译使用&lt;code>-g&lt;/code>参数，会包含 


 
 

 
 
 
 
 
 
 
 &lt;a href='../javastrace/#localvariabletable' rel="noopener" class="internal-link" data-src="../javastrace/#localvariabletable">&lt;em>&lt;strong>LocalVariableTable&lt;/strong>&lt;/em>&lt;/a> 。
&lt;br>&lt;br>用vim打开class文件&lt;code>vim -b Hello.class&lt;/code>。[不加&lt;code>-b&lt;/code>会在末尾追加&lt;code>0x0A&lt;/code>多一个字节]
&lt;br>并且使用xxd工具查看&lt;code>:%!xxd -u&lt;/code>;
&lt;br>&lt;br>右边为使用&lt;code>javap -v Hello.class&lt;/code>工具输出的字节码信息。&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Hello { 
 private int num;
 public int foo() {
 return num;
 } 
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">00000000: CAFE BABE 0000 0034 0013 0A00 0400 0F09 .......4........
00000010: 0003 0010 0700 1107 0012 0100 036E 756D .............num
00000020: 0100 0149 0100 063C 696E 6974 3E01 0003 ...I...&amp;lt;init&amp;gt;...
00000030: 2829 5601 0004 436F 6465 0100 0F4C 696E ()V...Code...Lin
00000040: 654E 756D 6265 7254 6162 6C65 0100 0366 eNumberTable...f
00000050: 6F6F 0100 0328 2949 0100 0A53 6F75 7263 oo...()I...Sourc
00000060: 6546 696C 6501 000A 4865 6C6C 6F2E 6A61 eFile...Hello.ja
00000070: 7661 0C00 0700 080C 0005 0006 0100 0548 va.............H
00000080: 656C 6C6F 0100 106A 6176 612F 6C61 6E67 ello...java/lang
00000090: 2F4F 626A 6563 7400 2100 0300 0400 0000 /Object.!.......
000000a0: 0100 0200 0500 0600 0000 0200 0100 0700 ................
000000b0: 0800 0100 0900 0000 1D00 0100 0100 0000 ................
000000c0: 052A B700 01B1 0000 0001 000A 0000 0006 .*..............
000000d0: 0001 0000 0001 0001 000B 000C 0001 0009 ................
000000e0: 0000 001D 0001 0001 0000 0005 2AB4 0002 ............*...
000000f0: AC00 0000 0100 0A00 0000 0600 0100 0000 ................
00000100: 0400 0100 0D00 0000 0200 0E ...........
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 45%; width: 45%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">Classfile /path/to/bytecode/Hello.class
Last modified 2024-3-6; size 267 bytes
MD5 checksum 4792914d35d8b3a70c01ee4fd462f512
Compiled from &amp;quot;Hello.java&amp;quot;
public class Hello
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#15 // java/lang/Object.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V
#2 = Fieldref #3.#16 // Hello.num:I
#3 = Class #17 // Hello
#4 = Class #18 // java/lang/Object
#5 = Utf8 num
#6 = Utf8 I
#7 = Utf8 &amp;lt;init&amp;gt;
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 foo
#12 = Utf8 ()I
#13 = Utf8 SourceFile
#14 = Utf8 Hello.java
#15 = NameAndType #7:#8 // &amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V
#16 = NameAndType #5:#6 // num:I
#17 = Utf8 Hello
#18 = Utf8 java/lang/Object
{
public Hello();
 descriptor: ()V
 flags: ACC_PUBLIC
 Code:
 stack=1, locals=1, args_size=1
 0: aload_0
 1: invokespecial #1 // Method java/lang/Object.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V
 4: return
 LineNumberTable:
 line 1: 0

public int foo();
 descriptor: ()I
 flags: ACC_PUBLIC
 Code:
 stack=1, locals=1, args_size=1
 0: aload_0
 1: getfield #2 // Field num:I
 4: ireturn
 LineNumberTable:
 line 4: 0
}
SourceFile: &amp;quot;Hello.java&amp;quot;
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="文件定义">
 文件定义
 &lt;a class="anchor" href="#%e6%96%87%e4%bb%b6%e5%ae%9a%e4%b9%89">#&lt;/a>
&lt;/h3>
&lt;p class="warn">Java字节码类文件（.class）是Java编译器编译Java源文件（.java）产生的“目标文件”。它是一种8位字节的二进制流文件， 各个数据项按顺序紧密的从前向后排列， 相邻的项之间没有间隙， 这样可以使得class文件非常紧凑， 体积轻巧， 可以被JVM快速的加载至内存， 并且占据较少的内存空间（方便于网络的传输）。
&lt;br>&lt;br>Java源文件在被Java编译器编译之后， 每个类（或者接口）都单独占据一个class文件， 并且类中的所有信息都会在class文件中有相应的描述， 由于class文件很灵活， 它甚至比Java源文件有着更强的描述能力。
&lt;br>&lt;br>class文件中的信息是一项一项排列的， 每项数据都有它的固定长度， 有的占一个字节， 有的占两个字节， 还有的占四个字节或8个字节。数据项的不同长度分别用
&lt;br>&lt;code>u1, u2, u4, u8&lt;/code>表示，分别表示一种数据项在class文件中占据&lt;code>1个字节， 2个字节， 4个字节，8个字节&lt;/code>。 可以把u1, u2, u3, u4看做class文件数据项的“类型” 。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/crypto/aes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/crypto/aes/</guid><description>&lt;h2 id="intro">
 Intro
 &lt;a class="anchor" href="#intro">#&lt;/a>
&lt;/h2>
&lt;h2 id="原理">
 原理
 &lt;a class="anchor" href="#%e5%8e%9f%e7%90%86">#&lt;/a>
&lt;/h2>
&lt;h2 id="实现">
 实现
 &lt;a class="anchor" href="#%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

public class AES {

 //加密方式
 private static final String ALGORITHM = &amp;quot;AES&amp;quot;;
 //数据填充方式
 private static final String CIPHER_ALGORITHM = &amp;quot;AES/CBC/PKCS7Padding&amp;quot;;
 /**
 * 默认编码
 */
 private static final String CHARSET = &amp;quot;utf-8&amp;quot;;

 //避免重复new生成多个BouncyCastleProvider对象，因为GC回收不了，会造成内存溢出
 //只在第一次调用decrypt()方法时才new 对象
 public static boolean initialized = false;

 static { Security.addProvider(new BouncyCastleProvider());}

 public static byte[] generateKey() throws Exception {
 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
 SecureRandom secureRandom = SecureRandom.getInstance(&amp;quot;SHA1PRNG&amp;quot;, &amp;quot;SUN&amp;quot;);
 secureRandom.setSeed((CIPHER_ALGORITHM + &amp;quot;NEW_BRUSH&amp;quot;).getBytes());
 keyGenerator.init(256, secureRandom);//要生成多少位，只需要修改这里即可128, 192或256
 SecretKey originalKey = keyGenerator.generateKey();
 return originalKey.getEncoded();
 }

 public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
 AlgorithmParameters params = AlgorithmParameters.getInstance(&amp;quot;AES&amp;quot;);
 params.init(new IvParameterSpec(iv));
 return params;
 }

 /**
 * 加密
 */
 public static String encrypt(String content, byte[] key, byte[] iv) {
 try {
 byte[] originalContent = content.getBytes(CHARSET);
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv));
 byte[] encrypted = cipher.doFinal(originalContent);
 return Base64.getEncoder().encodeToString(encrypted);
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 }

 /**
 * AES解密
 * 填充模式AES/CBC/PKCS7Padding
 * 解密模式128
 * @return 目标密文
 */
 public static String decrypt(String content, byte[] key, byte[] iv) {
 try {
 byte[] originalContent = Base64.getDecoder().decode(content);
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 SecretKey sKeySpec = new SecretKeySpec(key, ALGORITHM);
 cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(iv));// 初始化
 byte[] result = cipher.doFinal(originalContent);
 return new String(result,CHARSET);
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://github.com/12302-msb/newbrush-app/blob/main/newbrush-common/src/main/java/com/newbrush/common/utils/AesUtils.java" rel="noopener" target="_blank">https://github.com/12302-msb/newbrush-app/blob/main/newbrush-common/src/main/java/com/newbrush/common/utils/AesUtils.java&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/12302-msb/newbrush-app/commit/02787ada6feb5e4643db196a00f1cd994868a2e1" rel="noopener" target="_blank">https://github.com/12302-msb/newbrush-app/commit/02787ada6feb5e4643db196a00f1cd994868a2e1&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/crypto/des/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/crypto/des/</guid><description>&lt;h2 id="intro">
 Intro
 &lt;a class="anchor" href="#intro">#&lt;/a>
&lt;/h2>
&lt;h2 id="原理">
 原理
 &lt;a class="anchor" href="#%e5%8e%9f%e7%90%86">#&lt;/a>
&lt;/h2>
&lt;h2 id="实现">
 实现
 &lt;a class="anchor" href="#%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.util.Base64;

public class DES {

 /**
 * 偏移变量，固定占8位字节
 */
 private final static String IV_PARAMETER = &amp;quot;12345678&amp;quot;;
 /**
 * 密钥算法
 */
 private static final String ALGORITHM = &amp;quot;DES&amp;quot;;
 /**
 * 加密/解密算法-工作模式-填充模式
 */
 private static final String CIPHER_ALGORITHM = &amp;quot;DES/CBC/PKCS5Padding&amp;quot;;
 /**
 * 默认编码
 */
 private static final String CHARSET = &amp;quot;utf-8&amp;quot;;

 /**
 * 生成key
 *
 * @param key
 * @return
 * @throws Exception
 */
 private static SecretKey generateKey(String key) throws Exception {
 DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET));
 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
 return keyFactory.generateSecret(dks);
 }

 public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
 AlgorithmParameters params = AlgorithmParameters.getInstance(ALGORITHM);
 params.init(new IvParameterSpec(iv));
 return params;
 }

 /**
 * DES加密字符串
 *
 * @param key 加密密码，长度不能够小于8位
 * @param data 待加密字符串
 * @return 加密后内容
 */
 public static String encrypt(String data, byte[] key, byte[] iv) {
 if (key == null || key.length &amp;lt; 8) {
 throw new RuntimeException(&amp;quot;加密失败，key不能小于8位&amp;quot;);
 }
 if (data == null)
 return null;
 try {
 SecretKey secretKey = generateKey(new String(key));
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
 byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
 return new String(Base64.getEncoder().encode(bytes));

 } catch (Exception e) { e.printStackTrace(); return data;}
 }

 /**
 * DES解密字符串
 *
 * @param key 解密密码，长度不能够小于8位
 * @param data 待解密字符串
 * @return 解密后内容
 */
 public static String decrypt(String data, byte[] key, byte[] iv) {
 if (key== null || key.length &amp;lt; 8) {
 throw new RuntimeException(&amp;quot;加密失败，key不能小于8位&amp;quot;);
 }
 if (data == null)
 return null;
 try {
 SecretKey secretKey = generateKey(new String(key));
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
 return new String(cipher.doFinal(Base64.getDecoder().decode(data.getBytes(CHARSET))), CHARSET);
 } catch (Exception e) { e.printStackTrace(); return data;}
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/gs12software/article/details/83899389" rel="noopener" target="_blank">https://blog.csdn.net/gs12software/article/details/83899389&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/crypto/rsa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/crypto/rsa/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introrsa">
 Intro(RSA)
 &lt;a class="anchor" href="#introrsa">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="前情提要">
 前情提要
 &lt;a class="anchor" href="#%e5%89%8d%e6%83%85%e6%8f%90%e8%a6%81">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="欧拉函数">
 欧拉函数
 &lt;a class="anchor" href="#%e6%ac%a7%e6%8b%89%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h4>
&lt;p class="warn">


 &lt;a href="https://zh.wikipedia.org/wiki/欧拉函数" rel="noopener" target="_blank">欧拉函数&lt;/a> &lt;span class="math inline">\(\varphi(n)\)&lt;/span> 是小于等于 n 的正整数中与 n 互质的数的数目。
&lt;br>例如：&lt;span class="math inline">\(\varphi(8) = 4\)&lt;/span>，因为 1，3，5 和 7 均与 8 互质。
&lt;br>&lt;br>有如下性质：
&lt;br>&lt;code>1.&lt;/code> 欧拉函数是积性函数，即是说若 m,n 互质，则 &lt;span class="math inline">\(\varphi(m*n) = \varphi(m) * \varphi(n)\)&lt;/span>。
&lt;br>&lt;code>2.&lt;/code> 如果 n 为质数，则 &lt;span class="math inline">\(\varphi(n) = n - 1\)&lt;/span>。&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="同余">
 同余
 &lt;a class="anchor" href="#%e5%90%8c%e4%bd%99">#&lt;/a>
&lt;/h4>
&lt;p class="warn">对某两个整数 a b，若它们除以正整数 m 所得的余数相等，则称 a b 对于模 m 同余，也就是说，存在整数 k 使得 &lt;span class="math inline">\(a - b = km\)&lt;/span>，则称 a,b 对于 m 来说是同余的，一般记作 &lt;span class="math inline">\(a \equiv b \pmod{m}\)&lt;/span>。
&lt;br>比如 &lt;span class="math inline">\(26 - 14 = 12 = 1 * 12\)&lt;/span>
&lt;br>记作 &lt;span class="math inline">\(26 \equiv 14 \pmod{12}\)&lt;/span>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/debug/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/debug/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="debugger">
 debugger
 &lt;a class="anchor" href="#debugger">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="参数解释">
 参数解释
 &lt;a class="anchor" href="#%e5%8f%82%e6%95%b0%e8%a7%a3%e9%87%8a">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">index&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">-Xdebug&lt;/td>
&lt;td>启用调试特性&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">-Xrunjdwp&lt;/td>
&lt;td>&lt;sub-options> 在目标 VM 中加载 JDWP 实现。它通过传输和 JDWP 协议与独立的调试器应用程序通信。从 Java V5 开始，您可以使用 -agentlib:jdwp 选项，而不是 -Xdebug 和 -Xrunjdwp。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">-Djava.compiler=NONE&lt;/td>
&lt;td>禁止 JIT 编译器的加载&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">transport&lt;/td>
&lt;td>传输方式，有 socket 和 shared memory 两种，我们通常使用 socket（套接字）传输，但是在 Windows 平台上也可以使用shared memory（共享内存）传输。&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">server（y/n）&lt;/td>
&lt;td>VM 是否需要作为调试服务器执行&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">address&lt;/td>
&lt;td>调试服务器的端口号，客户端用来连接服务器的端口号&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">suspend（y/n）&lt;/td>
&lt;td>值是 y 或者 n，若为 y，启动时候自己程序的 VM 将会暂停（挂起），直到客户端进行连接，若为 n，自己程序的 VM 不会挂起&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="参数样例">
 参数样例
 &lt;a class="anchor" href="#%e5%8f%82%e6%95%b0%e6%a0%b7%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn">Command line arguments for remote JVM.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>JDK版本&lt;/th>
&lt;th>(attach mode)启动追加命令[参考下图]&lt;/th>
&lt;th>(listen mode)启动追加命令&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>JDK9 or later&lt;/td>
&lt;td>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8800&lt;/td>
&lt;td>-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:8800,suspend=y&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>JDK 5-8&lt;/td>
&lt;td>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8800&lt;/td>
&lt;td>-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:8800,suspend=y&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>JDK 1.4.x&lt;/td>
&lt;td>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8800&lt;/td>
&lt;td>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=localhost:8800,suspend=y&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>JDK 1.3.x or earliar&lt;/td>
&lt;td>-Xnoagent -Djava.compiler=NONE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8800&lt;/td>
&lt;td>-Xnoagent -Djava.compiler=NONE -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=localhost:8800,suspend=y&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/debug/debug-01.png" alt="" width="60%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/01-singleton/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/01-singleton/</guid><description>&lt;h1 id="单例模式">
 单例模式
 &lt;a class="anchor" href="#%e5%8d%95%e4%be%8b%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">单例模式（Singleton Pattern）是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
&lt;br>&lt;br>这种模式涉及到一个单一的类，该类负责创建自己的对象，同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式，可以直接访问，不需要实例化该类的对象。
&lt;br>&lt;br>单例模式是一种创建型设计模式，它确保一个类只有一个实例，并提供了一个全局访问点来访问该实例。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {
 //获取唯一可用的对象
 SingleObject object = SingleObject.getInstance();
 //显示消息
 object.showMessage();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="懒汉式" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="饿汉式" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="双检锁双重校验锁dcl" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="登记式静态内部类" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="枚举" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="懒汉式" class="docsify-tabs__tab" data-tab="懒汉式">懒汉式&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="懒汉式">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Singleton { 
 private Singleton (){}
 private static Singleton instance; 
 public static /*synchronized*/ Singleton getInstance() { 
 if (instance == null) { 
 instance = new Singleton(); 
 } 
 return instance; 
 } 
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="饿汉式" class="docsify-tabs__tab" data-tab="饿汉式">饿汉式&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="饿汉式">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Singleton { 
 private Singleton (){}
 private static Singleton instance = new Singleton();
 public static Singleton getInstance() {
 return instance;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="双检锁双重校验锁dcl" class="docsify-tabs__tab" data-tab="双检锁/双重校验锁[DCL]">双检锁/双重校验锁[DCL]&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="双检锁双重校验锁dcl">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Singleton { 
 private Singleton (){}
 private volatile static Singleton singleton; 
 public static Singleton getSingleton() { 
 if (singleton == null) { 
 synchronized (Singleton.class) { 
 if (singleton == null) { 
 singleton = new Singleton(); 
 } 
 } 
 } 
 return singleton; 
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="登记式静态内部类" class="docsify-tabs__tab" data-tab="登记式/静态内部类">登记式/静态内部类&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="登记式静态内部类">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Singleton { 
 private Singleton (){}
 private static class SingletonHolder { 
 private static final Singleton INSTANCE = new Singleton(); 
 } 
 public static final Singleton getInstance() { 
 return SingletonHolder.INSTANCE; 
 } 
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="枚举" class="docsify-tabs__tab" data-tab="枚举">枚举&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="枚举">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public enum Singleton { 
 INSTANCE; 
 public void whateverMethod() { 
 } 
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.runoob.com/design-pattern/singleton-pattern.html" rel="noopener" target="_blank">https://www.runoob.com/design-pattern/singleton-pattern.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/02-factory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/02-factory/</guid><description>&lt;h1 id="工厂模式">
 工厂模式
 &lt;a class="anchor" href="#%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 工厂模式提供了一种创建对象的方式，而无需指定要创建的具体类。
&lt;br>&lt;br>工厂模式属于创建型模式，它在创建对象时提供了一种封装机制，将实际创建对象的代码与使用代码分离。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {

 ShapeFactory shapeFactory = new ShapeFactory();

 Shape shape1 = shapeFactory.getShape(&amp;quot;CIRCLE&amp;quot;);
 shape1.draw();

 Shape shape2 = shapeFactory.getShape(&amp;quot;RECTANGLE&amp;quot;);
 shape2.draw();

 Shape shape3 = shapeFactory.getShape(&amp;quot;SQUARE&amp;quot;);
 shape3.draw();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="shapefactoryjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="shapejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="circlejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="rectanglejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="squarejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="shapefactoryjava" class="docsify-tabs__tab" data-tab="ShapeFactory.java">ShapeFactory.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="shapefactoryjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class ShapeFactory {

 //使用 getShape 方法获取形状类型的对象
 public Shape getShape(String shapeType){
 if(shapeType == null){ return null; }

 if(shapeType.equalsIgnoreCase(&amp;quot;CIRCLE&amp;quot;)){
 return new Circle();
 } else if(shapeType.equalsIgnoreCase(&amp;quot;RECTANGLE&amp;quot;)){
 return new Rectangle();
 } else if(shapeType.equalsIgnoreCase(&amp;quot;SQUARE&amp;quot;)){
 return new Square();
 }
 return null;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="shapejava" class="docsify-tabs__tab" data-tab="Shape.java">Shape.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="shapejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface Shape {
 void draw();
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="circlejava" class="docsify-tabs__tab" data-tab="Circle.java">Circle.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="circlejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Circle implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Circle::draw() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="rectanglejava" class="docsify-tabs__tab" data-tab="Rectangle.java">Rectangle.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="rectanglejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Rectangle implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Rectangle::draw() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="squarejava" class="docsify-tabs__tab" data-tab="Square.java">Square.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="squarejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Square implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Square::draw() method.&amp;quot;);
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-factory-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/03-abstract-factory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/03-abstract-factory/</guid><description>&lt;h1 id="抽象工厂模式">
 抽象工厂模式
 &lt;a class="anchor" href="#%e6%8a%bd%e8%b1%a1%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">抽象工厂模式（Abstract Factory Pattern）是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
&lt;br>&lt;br>在抽象工厂模式中，接口是负责创建一个相关对象的工厂，不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
&lt;br>&lt;br>抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口，而无需指定具体实现类。通过使用抽象工厂模式，可以将客户端与具体产品的创建过程解耦，使得客户端可以通过工厂接口来创建一族产品。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;h6 id="mainjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="factoryproducerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="abstractfactoryjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="mainjava" class="docsify-tabs__tab" data-tab="Main.java">Main.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="mainjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {
 //获取形状工厂
 AbstractFactory shapeFactory = FactoryProducer.getFactory(&amp;quot;SHAPE&amp;quot;);

 // 会出现NPE
 // Color color = shapeFactory.getColor(&amp;quot;everything&amp;quot;);
 Shape shape1 = shapeFactory.getShape(&amp;quot;CIRCLE&amp;quot;);
 shape1.draw();

 //获取颜色工厂
 AbstractFactory colorFactory = FactoryProducer.getFactory(&amp;quot;COLOR&amp;quot;);

 Color color1 = colorFactory.getColor(&amp;quot;RED&amp;quot;);
 color1.fill();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="factoryproducerjava" class="docsify-tabs__tab" data-tab="FactoryProducer.java">FactoryProducer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="factoryproducerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class FactoryProducer {
 public static AbstractFactory getFactory(String choice){
 if(choice.equalsIgnoreCase(&amp;quot;SHAPE&amp;quot;)){
 return new ShapeFactory();
 } else if(choice.equalsIgnoreCase(&amp;quot;COLOR&amp;quot;)){
 return new ColorFactory();
 }
 return null;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="abstractfactoryjava" class="docsify-tabs__tab" data-tab="AbstractFactory.java">AbstractFactory.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="abstractfactoryjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public abstract class AbstractFactory {

 public abstract Color getColor(String color);

 public abstract Shape getShape(String shape);

}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;h6 id="shapefactoryjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="shapejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="circlejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="rectanglejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="squarejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="shapefactoryjava" class="docsify-tabs__tab" data-tab="ShapeFactory.java">ShapeFactory.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="shapefactoryjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class ShapeFactory extends AbstractFactory {

 //使用 getShape 方法获取形状类型的对象
 public Shape getShape(String shapeType){
 if(shapeType == null){ return null; }
 if(shapeType.equalsIgnoreCase(&amp;quot;CIRCLE&amp;quot;)){
 return new Circle();
 } else if(shapeType.equalsIgnoreCase(&amp;quot;RECTANGLE&amp;quot;)){
 return new Rectangle();
 } else if(shapeType.equalsIgnoreCase(&amp;quot;SQUARE&amp;quot;)){
 return new Square();
 }
 return null;
 }

 @Override
 public Color getColor(String color) {
 return null;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="shapejava" class="docsify-tabs__tab" data-tab="Shape.java">Shape.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="shapejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface Shape {
 void draw();
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="circlejava" class="docsify-tabs__tab" data-tab="Circle.java">Circle.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="circlejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Circle implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Circle::draw() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="rectanglejava" class="docsify-tabs__tab" data-tab="Rectangle.java">Rectangle.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="rectanglejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Rectangle implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Rectangle::draw() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="squarejava" class="docsify-tabs__tab" data-tab="Square.java">Square.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="squarejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Square implements Shape {
 @Override
 public void draw() {
 System.out.println(&amp;quot;Inside Square::draw() method.&amp;quot;);
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;h6 id="colorfactoryjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="colorjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="bluejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="greenjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="redjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="colorfactoryjava" class="docsify-tabs__tab" data-tab="ColorFactory.java">ColorFactory.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="colorfactoryjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class ColorFactory extends AbstractFactory {
 @Override
 public Shape getShape(String shapeType){
 return null;
 }

 @Override
 public Color getColor(String color) {
 if(color == null){ return null; }

 if(color.equalsIgnoreCase(&amp;quot;RED&amp;quot;)){
 return new Red();
 } else if(color.equalsIgnoreCase(&amp;quot;GREEN&amp;quot;)){
 return new Green();
 } else if(color.equalsIgnoreCase(&amp;quot;BLUE&amp;quot;)){
 return new Blue();
 }
 return null;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="colorjava" class="docsify-tabs__tab" data-tab="Color.java">Color.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="colorjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface Color {
 void fill();
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="bluejava" class="docsify-tabs__tab" data-tab="Blue.java">Blue.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="bluejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Blue implements Color {
 @Override
 public void fill() {
 System.out.println(&amp;quot;Inside Blue::fill() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="greenjava" class="docsify-tabs__tab" data-tab="Green.java">Green.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="greenjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Green implements Color {
 @Override
 public void fill() {
 System.out.println(&amp;quot;Inside Green::fill() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="redjava" class="docsify-tabs__tab" data-tab="Red.java">Red.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="redjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Red implements Color {
 @Override
 public void fill() {
 System.out.println(&amp;quot;Inside Red::fill() method.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-abstract-factory-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/06-adapter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/06-adapter/</guid><description>&lt;h1 id="适配器模式">
 适配器模式
 &lt;a class="anchor" href="#%e9%80%82%e9%85%8d%e5%99%a8%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">适配器模式（Adapter Pattern）是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式，它结合了两个独立接口的功能。
&lt;br>&lt;br>这种模式涉及到一个单一的类，该类负责加入独立的或不兼容的接口功能。举个真实的例子，读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器，再将读卡器插入笔记本，这样就可以通过笔记本来读取内存卡。
&lt;br>&lt;br>我们通过下面的实例来演示适配器模式的使用。其中，音频播放器设备只能播放 mp3 文件，通过使用一个更高级的音频播放器来播放 vlc 和 mp4 文件。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {

 AudioPlayer audioPlayer = new AudioPlayer();

 audioPlayer.play(&amp;quot;mp3&amp;quot;, &amp;quot;beyond the horizon.mp3&amp;quot;);
 audioPlayer.play(&amp;quot;mp4&amp;quot;, &amp;quot;alone.mp4&amp;quot;);
 audioPlayer.play(&amp;quot;vlc&amp;quot;, &amp;quot;far far away.vlc&amp;quot;);
 audioPlayer.play(&amp;quot;avi&amp;quot;, &amp;quot;mind me.avi&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="audioplayerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="mediaplayerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="audioplayerjava" class="docsify-tabs__tab" data-tab="AudioPlayer.java">AudioPlayer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="audioplayerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class AudioPlayer implements MediaPlayer {
 MediaAdapter mediaAdapter;

 @Override
 public void play(String audioType, String fileName) {

 //播放 mp3 音乐文件的内置支持
 if(audioType.equalsIgnoreCase(&amp;quot;mp3&amp;quot;)){
 System.out.println(&amp;quot;Playing mp3 file. Name: &amp;quot;+ fileName);
 }
 //mediaAdapter 提供了播放其他文件格式的支持
 else if(audioType.equalsIgnoreCase(&amp;quot;vlc&amp;quot;)
 || audioType.equalsIgnoreCase(&amp;quot;mp4&amp;quot;)){
 mediaAdapter = new MediaAdapter(audioType);
 mediaAdapter.play(audioType, fileName);
 }
 else{
 System.out.println(&amp;quot;Invalid media. &amp;quot;+
 audioType + &amp;quot; format not supported&amp;quot;);
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="mediaplayerjava" class="docsify-tabs__tab" data-tab="MediaPlayer.java">MediaPlayer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="mediaplayerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface MediaPlayer {
 public void play(String audioType, String fileName);
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;h6 id="mediaadapterjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="mp4playerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="vlcplayerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="advancedmediaplayerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="mediaadapterjava" class="docsify-tabs__tab" data-tab="MediaAdapter.java">MediaAdapter.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="mediaadapterjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class MediaAdapter implements MediaPlayer {

 AdvancedMediaPlayer advancedMusicPlayer;

 public MediaAdapter(String audioType){
 if(audioType.equalsIgnoreCase(&amp;quot;vlc&amp;quot;) ){
 advancedMusicPlayer = new VlcPlayer();
 } else if (audioType.equalsIgnoreCase(&amp;quot;mp4&amp;quot;)){
 advancedMusicPlayer = new Mp4Player();
 }
 }

 @Override
 public void play(String audioType, String fileName) {
 if(audioType.equalsIgnoreCase(&amp;quot;vlc&amp;quot;)){
 advancedMusicPlayer.playVlc(fileName);
 }else if(audioType.equalsIgnoreCase(&amp;quot;mp4&amp;quot;)){
 advancedMusicPlayer.playMp4(fileName);
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="mp4playerjava" class="docsify-tabs__tab" data-tab="Mp4Player.java">Mp4Player.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="mp4playerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Mp4Player implements AdvancedMediaPlayer{

 @Override
 public void playVlc(String fileName) {
 //什么也不做
 }

 @Override
 public void playMp4(String fileName) {
 System.out.println(&amp;quot;Playing mp4 file. Name: &amp;quot;+ fileName);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="vlcplayerjava" class="docsify-tabs__tab" data-tab="VlcPlayer.java">VlcPlayer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="vlcplayerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class VlcPlayer implements AdvancedMediaPlayer{
 @Override
 public void playVlc(String fileName) {
 System.out.println(&amp;quot;Playing vlc file. Name: &amp;quot;+ fileName);
 }

 @Override
 public void playMp4(String fileName) {
 //什么也不做
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="advancedmediaplayerjava" class="docsify-tabs__tab" data-tab="AdvancedMediaPlayer.java">AdvancedMediaPlayer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="advancedmediaplayerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface AdvancedMediaPlayer {
 public void playVlc(String fileName);
 public void playMp4(String fileName);
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-adapter-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/13-chain-of-responsibility/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/13-chain-of-responsibility/</guid><description>&lt;h1 id="责任链模式">
 责任链模式
 &lt;a class="anchor" href="#%e8%b4%a3%e4%bb%bb%e9%93%be%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">顾名思义，责任链模式（Chain of Responsibility Pattern）为请求创建了一个接收者对象的链。这种模式给予请求的类型，对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
&lt;br>&lt;br>在这种模式中，通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求，那么它会把相同的请求传给下一个接收者，依此类推。&lt;/p>
&lt;p class="tip">我们创建抽象类 AbstractLogger，带有详细的日志记录级别。然后我们创建三种类型的记录器，都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别，如果是则相应地打印出来，否则将不打印并把消息传给下一个记录器。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 private static AbstractLogger getChainOfLoggers(){

 AbstractLogger debugLogger = new DebugLogger(AbstractLogger.DEBUG);
 AbstractLogger infoLogger = new InfoLogger(AbstractLogger.INFO);
 AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);

 debugLogger.setNextLogger(infoLogger);
 infoLogger.setNextLogger(errorLogger);

 return debugLogger;
 }

 public static void main(String[] args) {
 AbstractLogger loggerChain = getChainOfLoggers();

 loggerChain.logMessage(AbstractLogger.DEBUG, &amp;quot;This is a debug level information.&amp;quot;);

 loggerChain.logMessage(AbstractLogger.INFO, &amp;quot;This is an info level information.&amp;quot;);

 loggerChain.logMessage(AbstractLogger.ERROR, &amp;quot;This is an error level information.&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="abstractloggerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="debugloggerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="infologgerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="errorloggerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="abstractloggerjava" class="docsify-tabs__tab" data-tab="AbstractLogger.java">AbstractLogger.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="abstractloggerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public abstract class AbstractLogger {
 public static int DEBUG = 1;
 public static int INFO = 2;
 public static int ERROR = 3;

 protected int level;

 //责任链中的下一个元素
 protected AbstractLogger nextLogger;

 public void setNextLogger(AbstractLogger nextLogger){
 this.nextLogger = nextLogger;
 }

 public void logMessage(int level, String message){
 if(this.level &amp;gt;= level){
 write(message);
 }
 if(nextLogger != null){
 nextLogger.logMessage(level, message);
 }else{ System.out.println();}
 }

 abstract protected void write(String message);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="debugloggerjava" class="docsify-tabs__tab" data-tab="DebugLogger.java">DebugLogger.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="debugloggerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class DebugLogger extends AbstractLogger {

 public DebugLogger(int level){
 this.level = level;
 }

 @Override
 protected void write(String message) {
 System.out.println(&amp;quot;Debug::Logger: &amp;quot; + message);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="infologgerjava" class="docsify-tabs__tab" data-tab="InfoLogger.java">InfoLogger.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="infologgerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class InfoLogger extends AbstractLogger {

 public InfoLogger(int level){
 this.level = level;
 }

 @Override
 protected void write(String message) {
 System.out.println(&amp;quot;Info::Logger: &amp;quot; + message);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="errorloggerjava" class="docsify-tabs__tab" data-tab="ErrorLogger.java">ErrorLogger.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="errorloggerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class ErrorLogger extends AbstractLogger {

 public ErrorLogger(int level){
 this.level = level;
 }

 @Override
 protected void write(String message) {
 System.out.println(&amp;quot;Error::Logger: &amp;quot; + message);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-chain-of-responsibility-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/21-strategy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/21-strategy/</guid><description>&lt;h1 id="策略模式">
 策略模式
 &lt;a class="anchor" href="#%e7%ad%96%e7%95%a5%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">在策略模式（Strategy Pattern）中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
&lt;br>&lt;br>在策略模式定义了一系列算法或策略，并将每个算法封装在独立的类中，使得它们可以互相替换。通过使用策略模式，可以在运行时根据需要选择不同的算法，而不需要修改客户端代码。
&lt;br>&lt;br>在策略模式中，我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。&lt;/p>
&lt;p class="tip">我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。StrategyPatternDemo，我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {

 public static void main(String[] args) {

 Context context = new Context(new OperationAdd());
 System.out.println(&amp;quot;10 + 5 = &amp;quot; + context.executeStrategy(10, 5));

 context = new Context(new OperationSubtract());
 System.out.println(&amp;quot;10 - 5 = &amp;quot; + context.executeStrategy(10, 5));

 context = new Context(new OperationMultiply());
 System.out.println(&amp;quot;10 * 5 = &amp;quot; + context.executeStrategy(10, 5));
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Context {
 private Strategy strategy;

 public Context(Strategy strategy){
 this.strategy = strategy;
 }

 public int executeStrategy(int num1, int num2){
 return strategy.doOperation(num1, num2);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface Strategy {
 public int doOperation(int num1, int num2);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="operationaddjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="operationsubtractjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="operationmultiplyjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="operationaddjava" class="docsify-tabs__tab" data-tab="OperationAdd.java">OperationAdd.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="operationaddjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class OperationAdd implements Strategy{
 @Override
 public int doOperation(int num1, int num2) {
 return num1 + num2;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="operationsubtractjava" class="docsify-tabs__tab" data-tab="OperationSubtract.java">OperationSubtract.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="operationsubtractjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class OperationSubtract implements Strategy{
 @Override
 public int doOperation(int num1, int num2) {
 return num1 - num2;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="operationmultiplyjava" class="docsify-tabs__tab" data-tab="OperationMultiply.java">OperationMultiply.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="operationmultiplyjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class OperationMultiply implements Strategy{
 @Override
 public int doOperation(int num1, int num2) {
 return num1 * num2;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-strategy-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/22-template/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/22-template/</guid><description>&lt;h1 id="模板模式">
 模板模式
 &lt;a class="anchor" href="#%e6%a8%a1%e6%9d%bf%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">在模板模式（Template Pattern）中，一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现，但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {

 Game game = new Cricket();
 game.play();

 game = new Football();
 game.play();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h6 id="gamejava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="cricketjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="footballjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="gamejava" class="docsify-tabs__tab" data-tab="Game.java">Game.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="gamejava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public abstract class Game {
 abstract void initialize();
 abstract void startPlay();
 abstract void endPlay();
 //模板
 public final void play(){
 //初始化游戏
 initialize();
 //开始游戏
 startPlay();
 //结束游戏
 endPlay();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="cricketjava" class="docsify-tabs__tab" data-tab="Cricket.java">Cricket.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="cricketjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Cricket extends Game {

 @Override
 void endPlay() {
 System.out.println(&amp;quot;Cricket Game Finished!&amp;quot;);
 }

 @Override
 void initialize() {
 System.out.println(&amp;quot;Cricket Game Initialized! Start playing.&amp;quot;);
 }

 @Override
 void startPlay() {
 System.out.println(&amp;quot;Cricket Game Started. Enjoy the game!&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="footballjava" class="docsify-tabs__tab" data-tab="Football.java">Football.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="footballjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Football extends Game {

 @Override
 void endPlay() {
 System.out.println(&amp;quot;Football Game Finished!&amp;quot;);
 }

 @Override
 void initialize() {
 System.out.println(&amp;quot;Football Game Initialized! Start playing.&amp;quot;);
 }

 @Override
 void startPlay() {
 System.out.println(&amp;quot;Football Game Started. Enjoy the game!&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-template-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/design-pattern/23-visitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/design-pattern/23-visitor/</guid><description>&lt;h1 id="访问者模式">
 访问者模式
 &lt;a class="anchor" href="#%e8%ae%bf%e9%97%ae%e8%80%85%e6%a8%a1%e5%bc%8f">#&lt;/a>
&lt;/h1>
&lt;ul>
&lt;li>
&lt;h2 id="描述">
 描述
 &lt;a class="anchor" href="#%e6%8f%8f%e8%bf%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">在访问者模式（Visitor Pattern）中，我们使用了一个访问者类，它改变了元素类的执行算法。通过这种方式，元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式，元素对象已接受访问者对象，这样访问者对象就可以处理元素对象上的操作。&lt;/p>
&lt;p class="tip"> 访问模式可以有变形，比如有些写法中被访问的是抽象类，而另外的是接口实现。
&lt;br>&lt;br>


 &lt;a href="https://asm.ow2.io/" rel="noopener" target="_blank">&lt;code>ASM&lt;/code>&lt;/a>里面就用到了访问者模式来处理字节码信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="uml">
 UML
 &lt;a class="anchor" href="#uml">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Main {
 public static void main(String[] args) {

 List&amp;lt;Staff&amp;gt; staffs = new ArrayList&amp;lt;&amp;gt;();
 staffs.add(new Manager(&amp;quot;经理-A&amp;quot;));
 staffs.add(new Manager(&amp;quot;经理-B&amp;quot;));
 staffs.add(new Engineer(&amp;quot;工程师-A&amp;quot;));
 staffs.add(new Engineer(&amp;quot;工程师-B&amp;quot;));
 staffs.add(new Engineer(&amp;quot;工程师-C&amp;quot;));
 staffs.add(new Engineer(&amp;quot;工程师-D&amp;quot;));

 CEOVisitor ceoVisitor = new CEOVisitor();
 for (Staff staff : staffs) {
 staff.accept(ceoVisitor);
 }

 System.out.println();

 CTOVisitor ctoVisitor = new CTOVisitor();
 for (Staff staff : staffs) {
 staff.accept(ctoVisitor);
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;h3 id="active访问">
 active(访问)
 &lt;a class="anchor" href="#active%e8%ae%bf%e9%97%ae">#&lt;/a>
&lt;/h3>
&lt;h6 id="visitorjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ceovisitorjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ctovisitorjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="visitorjava" class="docsify-tabs__tab" data-tab="Visitor.java">Visitor.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="visitorjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public interface Visitor {
 void visit(Engineer engineer);
 void visit(Manager manager);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="ceovisitorjava" class="docsify-tabs__tab" data-tab="CEOVisitor.java">CEOVisitor.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="ceovisitorjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class CEOVisitor implements Visitor {

 @Override
 public void visit(Engineer engineer) {
 System.out.println(&amp;quot;CEO -visit-&amp;gt; 工程师: &amp;quot; + engineer.name + &amp;quot;, KPI: &amp;quot; + engineer.kpi);
 }

 @Override
 public void visit(Manager manager) {
 System.out.println(&amp;quot;CEO -visit-&amp;gt; 经理: &amp;quot; + manager.name + &amp;quot;, KPI: &amp;quot; + manager.kpi +
 &amp;quot;, 新产品数量: &amp;quot; + manager.getProducts());
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="ctovisitorjava" class="docsify-tabs__tab" data-tab="CTOVisitor.java">CTOVisitor.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="ctovisitorjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class CTOVisitor implements Visitor {

 @Override
 public void visit(Engineer engineer) {
 System.out.println(&amp;quot;CTO -visit-&amp;gt; 工程师: &amp;quot; + engineer.name + &amp;quot;, 代码行数: &amp;quot; + engineer.getCodeLines());
 }

 @Override
 public void visit(Manager manager) {
 System.out.println(&amp;quot;CTO -visit-&amp;gt; 经理: &amp;quot; + manager.name + &amp;quot;, 产品数量: &amp;quot; + manager.getProducts());
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>&lt;/div>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;h3 id="passive被访问">
 passive(被访问)
 &lt;a class="anchor" href="#passive%e8%a2%ab%e8%ae%bf%e9%97%ae">#&lt;/a>
&lt;/h3>
&lt;h6 id="staffjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="engineerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="managerjava" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="staffjava" class="docsify-tabs__tab" data-tab="Staff.java">Staff.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="staffjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public abstract class Staff {

 public String name;
 public int kpi;// 员工KPI

 public Staff(String name) {
 this.name = name;
 kpi = new Random().nextInt(10);
 }
 // 核心方法，接受Visitor的访问
 public abstract void accept(Visitor visitor);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="engineerjava" class="docsify-tabs__tab" data-tab="Engineer.java">Engineer.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="engineerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Engineer extends Staff {

 public Engineer(String name) {
 super(name);
 }

 @Override
 public void accept(Visitor visitor) {
 visitor.visit(this);
 }
 // 工程师一年的代码数量
 public int getCodeLines() {
 return new Random().nextInt(10 * 10000);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="managerjava" class="docsify-tabs__tab" data-tab="Manager.java">Manager.java&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="managerjava">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class Manager extends Staff {

 public Manager(String name) {
 super(name);
 }

 @Override
 public void accept(Visitor visitor) {
 visitor.visit(this);
 }

 // 一年做的产品数量
 public int getProducts() {
 return new Random().nextInt(10);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>&lt;/div>&lt;/div>

&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/design-pattern/dp-visitor-01.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/javaagent/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/javaagent/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introjavaagent">
 Intro(JavaAgent)
 &lt;a class="anchor" href="#introjavaagent">#&lt;/a>
&lt;/h2>
&lt;p class="warn">通过实现agent类中的premain方法将自定义的类转换器注册到JVM中，从而实现类加载之前&lt;strong>对字节码进行处理&lt;/strong>。本次实验中对类未进行处理，而是在加载类之前打印输出。
&lt;br>完整代码可


 &lt;a href="https://github.com/12302-bak/idea-test-project/tree/v2.0.0-BAK/_6_un_JTW" rel="noopener" target="_blank">参考&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="代码实现">
 代码实现
 &lt;a class="anchor" href="#%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h3>
&lt;h6 id="myagent" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="mytransfor" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="testmain" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="myagent" class="docsify-tabs__tab" data-tab="MyAgent">MyAgent&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="myagent">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">package agent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;

public class MyAgent {
 public static void premain(String args, Instrumentation instrumentation){
 ClassFileTransformer classFileTransformer = new MyTransfor();
 instrumentation.addTransformer(classFileTransformer);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="mytransfor" class="docsify-tabs__tab" data-tab="MyTransfor">MyTransfor&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="mytransfor">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">package agent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class MyTransfor implements ClassFileTransformer {
 @Override
 public byte[] transform(ClassLoader loader, String className, Class&amp;lt;?&amp;gt; classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

 /*_12302_2019-07-26_&amp;lt;此处可以静态代理&amp;gt;*/
 System.out.println(&amp;quot;from: &amp;quot; + className + &amp;quot;--&amp;gt; hello agent!&amp;quot;);

 /*_12302_2019-07-26_&amp;lt;return null 并不表示将要加载的类清空,而是不往其中添加任何东西&amp;gt;*/
 return null;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="testmain" class="docsify-tabs__tab" data-tab="TestMain">TestMain&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="testmain">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">package demo;

public class TestMain {
 public static void main(String[] args) {
 System.out.println(&amp;quot;this is _base.base.demo.TestMain.main(),and nothing else&amp;quot;);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="构建及运行">
 构建及运行
 &lt;a class="anchor" href="#%e6%9e%84%e5%bb%ba%e5%8f%8a%e8%bf%90%e8%a1%8c">#&lt;/a>
&lt;/h3>
&lt;p class="tip">使用maven-assembly-plugin插件进行构建的。在&lt;code>assembly.xml&lt;/code>配置中排除主类包，并在pom.xml&lt;code>assembly&lt;/code>插件配置中定义了生成&lt;code>META-INF/MANIFEST.MF&lt;/code>文件且包含&lt;code>Premain-Class: agent.MyAgent&lt;/code> 属性。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/javastrace/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/javastrace/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introjavastrace">
 Intro(JavaStrace)
 &lt;a class="anchor" href="#introjavastrace">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 一个java程序的运行全过程解析。&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p class="tip"> 右上java源代码，右下常量池，左下为Code方法块。&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">{
 public _jvm.classPrase.Student(int, java.lang.String, java.lang.String);
 descriptor: (ILjava/lang/String;Ljava/lang/String;)V
 flags: ACC_PUBLIC
 Code:
 stack=3, locals=4, args_size=4
 0: aload_0
 1: iload_1
 2: aload_2
 3: invokespecial #1 // Method _jvm/classPrase/Person.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;)V
 6: aload_0
 7: aload_3
 8: putfield #2 // Field sid:Ljava/lang/String;
 11: return
 LineNumberTable:
 line 19: 0
 line 20: 6
 line 21: 11

 public void run();
 descriptor: ()V
 flags: ACC_PUBLIC
 Code:
 stack=2, locals=1, args_size=1
 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
 3: ldc #4 // String run()...
 5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 8: return
 LineNumberTable:
 line 23: 0
 line 24: 8

 public int study(int, int);
 descriptor: (II)I
 flags: ACC_PUBLIC
 Code:
 stack=3, locals=5, args_size=3
 0: bipush 10
 2: istore_3
 3: bipush 20
 5: istore 4
 7: iload_1
 8: iload_2
 9: iload_3
 10: imul
 11: iadd
 12: iload 4
 14: isub
 15: ireturn
 LineNumberTable:
 line 26: 0
 line 27: 3
 line 28: 7

 public static int getCnt();
 descriptor: ()I
 flags: ACC_PUBLIC, ACC_STATIC
 Code:
 stack=1, locals=0, args_size=0
 0: getstatic #6 // Field cnt:I
 3: ireturn
 LineNumberTable:
 line 31: 0

 public static void main(java.lang.String[]);
 descriptor: ([Ljava/lang/String;)V
 flags: ACC_PUBLIC, ACC_STATIC
 Code:
 stack=5, locals=2, args_size=1
 0: new #7 // class _jvm/classPrase/Student
 3: dup
 4: bipush 23
 6: ldc #8 // String dqrcsc
 8: ldc #9 // String 20150723
 10: invokespecial #10 // Method &amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;Ljava/lang/String;)V
 13: astore_1
 14: aload_1
 15: iconst_5
 16: bipush 6
 18: invokevirtual #11 // Method study:(II)I
 21: pop
 22: invokestatic #12 // Method getCnt:()I
 25: pop
 26: aload_1
 27: invokevirtual #13 // Method run:()V
 30: return
 LineNumberTable:
 line 34: 0
 line 35: 14
 line 36: 22
 line 37: 26
 line 38: 30

 static {};
 descriptor: ()V
 flags: ACC_STATIC
 Code:
 stack=2, locals=0, args_size=0
 0: iconst_5
 1: putstatic #6 // Field cnt:I
 4: getstatic #6 // Field cnt:I
 7: iconst_1
 8: iadd
 9: putstatic #6 // Field cnt:I
 12: return
 LineNumberTable:
 line 13: 0
 line 15: 4
 line 16: 12
}
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">package _jvm.classPrase;

/**
 *
 * Copyright https://wtfu.site Inc. All Rights Reserved.
 *
 * @date 2024/3/8
 * @since 1.0
 * @author 12302
 *
 */
public class Student extends Person implements IStudyable {
 private static int cnt=5;
 static{
 cnt++;
 }
 private String sid;
 public Student(int age, String name, String sid){
 super(age,name);
 this.sid = sid;
 }
 public void run(){
 System.out.println(&amp;quot;run()...&amp;quot;);
 }
 public int study(int a, int b){
 int c = 10;
 int d = 20;
 return a+b*c-d;
 }
 public static int getCnt(){
 return cnt;
 }
 public static void main(String[] args){
 Student s = new Student(23,&amp;quot;dqrcsc&amp;quot;,&amp;quot;20150723&amp;quot;);
 s.study(5,6);
 Student.getCnt();
 s.run();
 }
}
class Person {
 private String name;
 private int age;
 public Person(int age, String name){
 this.age = age;
 this.name = name;
 }
 public void run(){}
}
interface IStudyable {
 public int study(int a, int b);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">Constant pool:
 #1 = Methodref #14.#35 // _jvm/classPrase/Person.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;)V
 #2 = Fieldref #7.#36 // _jvm/classPrase/Student.sid:Ljava/lang/String;
 #3 = Fieldref #37.#38 // java/lang/System.out:Ljava/io/PrintStream;
 #4 = String #39 // run()...
 #5 = Methodref #40.#41 // java/io/PrintStream.println:(Ljava/lang/String;)V
 #6 = Fieldref #7.#42 // _jvm/classPrase/Student.cnt:I
 #7 = Class #43 // _jvm/classPrase/Student
 #8 = String #44 // dqrcsc
 #9 = String #45 // 20150723
 #10 = Methodref #7.#46 // _jvm/classPrase/Student.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;Ljava/lang/String;)V
 #11 = Methodref #7.#47 // _jvm/classPrase/Student.study:(II)I
 #12 = Methodref #7.#48 // _jvm/classPrase/Student.getCnt:()I
 #13 = Methodref #7.#49 // _jvm/classPrase/Student.run:()V
 #14 = Class #50 // _jvm/classPrase/Person
 #15 = Class #51 // _jvm/classPrase/IStudyable
 #16 = Utf8 cnt
 #17 = Utf8 I
 #18 = Utf8 sid
 #19 = Utf8 Ljava/lang/String;
 #20 = Utf8 &amp;lt;init&amp;gt;
 #21 = Utf8 (ILjava/lang/String;Ljava/lang/String;)V
 #22 = Utf8 Code
 #23 = Utf8 LineNumberTable
 #24 = Utf8 run
 #25 = Utf8 ()V
 #26 = Utf8 study
 #27 = Utf8 (II)I
 #28 = Utf8 getCnt
 #29 = Utf8 ()I
 #30 = Utf8 main
 #31 = Utf8 ([Ljava/lang/String;)V
 #32 = Utf8 &amp;lt;clinit&amp;gt;
 #33 = Utf8 SourceFile
 #34 = Utf8 Student.java
 #35 = NameAndType #20:#52 // &amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;)V
 #36 = NameAndType #18:#19 // sid:Ljava/lang/String;
 #37 = Class #53 // java/lang/System
 #38 = NameAndType #54:#55 // out:Ljava/io/PrintStream;
 #39 = Utf8 run()...
 #40 = Class #56 // java/io/PrintStream
 #41 = NameAndType #57:#58 // println:(Ljava/lang/String;)V
 #42 = NameAndType #16:#17 // cnt:I
 #43 = Utf8 _jvm/classPrase/Student
 #44 = Utf8 dqrcsc
 #45 = Utf8 20150723
 #46 = NameAndType #20:#21 // &amp;quot;&amp;lt;init&amp;gt;&amp;quot;:(ILjava/lang/String;Ljava/lang/String;)V
 #47 = NameAndType #26:#27 // study:(II)I
 #48 = NameAndType #28:#29 // getCnt:()I
 #49 = NameAndType #24:#25 // run:()V
 #50 = Utf8 _jvm/classPrase/Person
 #51 = Utf8 _jvm/classPrase/IStudyable
 #52 = Utf8 (ILjava/lang/String;)V
 #53 = Utf8 java/lang/System
 #54 = Utf8 out
 #55 = Utf8 Ljava/io/PrintStream;
 #56 = Utf8 java/io/PrintStream
 #57 = Utf8 println
 #58 = Utf8 (Ljava/lang/String;)V
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>&lt;/div>

&lt;ul>
&lt;li>
&lt;h3 id="虚拟机栈">
 虚拟机栈
 &lt;a class="anchor" href="#%e8%99%9a%e6%8b%9f%e6%9c%ba%e6%a0%88">#&lt;/a>
&lt;/h3> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel">
&lt;p class="warn"> JVM中通过java栈，保存方法调用运行的相关信息，每当调用一个方法，会根据该方法的在字节码中的信息为该方法创建栈帧，不同的方法，其栈帧的大小有所不同。栈帧中的内存空间还可以分为3块，分别存放不同的数据：
&lt;br>&lt;br>1). &lt;code>局部变量表&lt;/code>：存放该方法调用者所传入的参数，及在该方法的方法体中创建的局部变量。
&lt;br>2). &lt;code>操作数栈&lt;/code>：用于存放操作数及计算的中间结果等。
&lt;br>3). &lt;code>其他栈帧信息&lt;/code>：如返回地址、当前方法的引用等。
&lt;br>&lt;br>只有当前正在运行的方法的栈帧位于栈顶，当前方法返回，则当前方法对应的栈帧出栈，当前方法的调用者的栈帧变为栈顶；当前方法的方法体中若是调用了其他方法，则为被调用的方法创建栈帧，并将其压入栈顶。
&lt;br>&lt;em>&lt;strong>注意：局部变量表及操作数栈的最大深度在编译期间就已经确定了，存储在该方法字节码的Code属性中。&lt;/strong>&lt;/em>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/jdk/build/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/jdk/build/</guid><description>&lt;h2 id="编译jdk">
 编译JDK
 &lt;a class="anchor" href="#%e7%bc%96%e8%af%91jdk">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="build">
 build
 &lt;a class="anchor" href="#build">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 下载xcodeapp[(~7G), OS version [13.3.1 (22E261)]
wget -c https://download.developer.apple.com/Developer_Tools/Xcode_14.3.1/Xcode_14.3.1.xip
# 切换xcode 到xcodeapp
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license

# 配置
# disable-warnings-as-errors选项是禁止把warning 当成error
# --with-debug-level=slowdebug。用来设置编译的级别，可选值为release、fastdebug、slowde-bug，越往后进行的优化措施就越少，带的调试信息就越多。默认值为release。slowdebug 含有最丰富的调试信息，没有这些信息，很多执行可能被优化掉，我们单步执行时，可能看不到一些变量的值。所以最好指定slowdebug 为编译级别。
# with-jvm-variants 编译特定模式的HotSpot虚拟机，可选值：server、client、minimal、core、zero、custom
# configure 命令承担了依赖项检查、参数配置和构建输出目录结构等多项职责，如果编译过程中需要的工具链或者依赖项有缺失，命令执行后会得到明确的提示，并给出该依赖的安装命令。
bash configure --disable-warnings-as-errors --with-debug-level=slowdebug --with-jvm-variants=server
# 编译
make images

# 生成compile_commands.json文件
make compile-commands
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="loaded-to-clion">
 loaded to clion
 &lt;a class="anchor" href="#loaded-to-clion">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/jdk/jdk-build-01.png" alt="" width="45%">
&lt;img src="https://archive-w.netlify.app/.images/doc/advance/jdk/jdk-build-04.png" alt="" width="54%">
&lt;img src="https://archive-w.netlify.app/.images/doc/advance/jdk/jdk-build-02.png" alt="" width="40%">
&lt;img src="https://archive-w.netlify.app/.images/doc/advance/jdk/jdk-build-03.png" alt="" width="40%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="debug">
 debug
 &lt;a class="anchor" href="#debug">#&lt;/a>
&lt;/h3>
&lt;p class="warn">使用lldb debug的时候会出现 Signal: SIGSEGV (signal SIGSEGV) ,&lt;code>目前切换到gdb断点不生效，未解决。&lt;/code>
&lt;br> 可以


 &lt;a href="https://lrting.top/backend/11766/" rel="noopener" target="_blank">参考&lt;/a>添加下列代码解决。如果是gdb的话，


 &lt;a href="https://jiawanggjia.github.io/post/openjdk-bian-yi-zhi-nan/" rel="noopener" target="_blank">参考&lt;/a>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/jvm/tools/hsdb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/jvm/tools/hsdb/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introhsdb">
 Intro(HSDB)
 &lt;a class="anchor" href="#introhsdb">#&lt;/a>
&lt;/h2>
&lt;p class="tip">&lt;code>-XX:-UseCompressedOops&lt;/code>oops: ordinary object pointer，普通对象指针压缩，例如Object o = new Object();其中o就是个指向new Object()对象的指针，o在指针压缩前占用8个字节，在指针压缩后占用4个字节。
&lt;br>&lt;code>-XX:-UseCompressedClassPointers&lt;/code>压缩Klass Pointer，压缩前8个字节，压缩后4个字节。&lt;/p>
&lt;p class="warn">&lt;code>sudo java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java" rel="noopener" target="_blank">https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://openjdk.org/groups/hotspot/docs/Serviceability.html#bsa" rel="noopener" target="_blank">https://openjdk.org/groups/hotspot/docs/Serviceability.html#bsa&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://docs.oracle.com/en/java/javase/11/tools/jhsdb.html#GUID-0345CAEB-71CE-4D71-97FE-AA53A4AB028E" rel="noopener" target="_blank">https://docs.oracle.com/en/java/javase/11/tools/jhsdb.html#GUID-0345CAEB-71CE-4D71-97FE-AA53A4AB028E&lt;/a>&lt;/li>
&lt;li>&lt;/li>
&lt;li>


 &lt;a href="https://github.com/openjdk/jdk/tree/jdk8-b120/hotspot/agent/doc" rel="noopener" target="_blank">https://github.com/openjdk/jdk/tree/jdk8-b120/hotspot/agent/doc&lt;/a> #下面站点可以渲染里面的html.
&lt;ol>
&lt;li>


 &lt;a href="https://htmlpreview.github.io/?https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/agent/doc/index.html" rel="noopener" target="_blank">https://htmlpreview.github.io/?https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/agent/doc/index.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://svn.netlabs.org/repos/java/trunk/openjdk/hotspot/agent/doc/index.html" rel="noopener" target="_blank">https://svn.netlabs.org/repos/java/trunk/openjdk/hotspot/agent/doc/index.html&lt;/a>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/jvm/tools/jvisualvm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/jvm/tools/jvisualvm/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introjvisualvm">
 Intro(jvisualvm)
 &lt;a class="anchor" href="#introjvisualvm">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>OQL控制台&lt;/p>
&lt;p class="warn"> 使用样例
&lt;br>&lt;code>select s from java.lang.String s where s.toString().contains(&amp;quot;hello&amp;quot;)&lt;/code>
&lt;br>&lt;code>select s from java.lang.String s where s.toString().equals(&amp;quot;12&amp;quot;)&lt;/code>
&lt;br>&lt;code>select s from java.lang.String s where /^\d+$/.test(s.toString())&lt;/code>
&lt;br>&lt;code>select i from java.lang.Integer i where i.value &amp;gt; 12302&lt;/code>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/visualvm/visualvm.java.net.backup/master/www/oqlhelp.html" rel="noopener" target="_blank">https://htmlpreview.github.io/?https://raw.githubusercontent.com/visualvm/visualvm.java.net.backup/master/www/oqlhelp.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://cr.openjdk.org/~sundar/8022483/webrev.01/raw_files/new/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html" rel="noopener" target="_blank">https://cr.openjdk.org/~sundar/8022483/webrev.01/raw_files/new/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.cnblogs.com/ghj1976/p/5408295.html" rel="noopener" target="_blank">https://www.cnblogs.com/ghj1976/p/5408295.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/jvm/tools/stringtable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/jvm/tools/stringtable/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introstringtable--打印-jvm-stringtable">
 Intro(StringTable | 打印 JVM StringTable)
 &lt;a class="anchor" href="#introstringtable--%e6%89%93%e5%8d%b0-jvm-stringtable">#&lt;/a>
&lt;/h2>
&lt;p class="warn">将虚拟机中的 StringTable 里面的字符全部打印出来，有两种方式，1：通过


 &lt;a href="https://docs.oracle.com/javase/9/tools/jcmd.htm#:~:text=VM.stringtable" rel="noopener" target="_blank">jcmd&lt;/a> 命令，2：借助 sun 下 hotspot 中的相关工具类编码。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="jcmd-方式">
 jcmd 方式
 &lt;a class="anchor" href="#jcmd-%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> jcmd 里面有个命令是&lt;code>VM.stringtable&lt;/code>，可以查看 VM 里面的 stringtable，jdk 9以下好像没有这个命令


 &lt;a href="https://stackoverflow.com/questions/64458776/why-can-some-jcmd-commandseg-vm-set-flag-can-not-be-used-on-all-pid" rel="noopener" target="_blank">参考&lt;/a>，会抛出：”java.lang.IllegalArgumentException: Unknown diagnostic command“错误，所以可以使用 jdk9 去诊断。&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">package _base.str.test;

public class StringTest {
 public static void main(String[] args) {
 String str2 = new String(&amp;quot;str&amp;quot;)+new String(&amp;quot;01&amp;quot;); // 创建string对象 0x02912。
 str2.intern(); // jdk1.7及以下。 str2.intern()如果常量池中没有的话，会创建 str2 0x02912。 . 所以 str2.intern() == str2
 String str1 = &amp;quot;str01&amp;quot;; // 现在常量池中有了，直接返回引用 0x02912。
 System.out.println(str2==str1); // 所以相等

 String str3 = new String(&amp;quot;hel&amp;quot;) + new String(&amp;quot;lo&amp;quot;);

 String str4 = new String(&amp;quot;he&amp;quot;) + new String(&amp;quot;llo&amp;quot;);

 String str3Tmp = str3.intern();
 String str4Tmp = str4.intern();
 System.out.println(str3.equals(str4));

 keepRunning();
 System.out.println();
 }

 public static void keepRunning(){
 Thread thread = Thread.currentThread();
 synchronized (thread){
 try {
 thread.wait();
 } catch (InterruptedException e) { e.printStackTrace(); }
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>可以使用 idea 中的 JDK 1.8 环境编译，然后运行使用 jdk9。
&lt;br>再运行：&lt;code>/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/bin/java -cp /Users/stevenobelia/Documents/project_idea_test/idea-test-project/_0_base-learning/target/classes _base.str.test.StringTest&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/native/javacpp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/native/javacpp/</guid><description>&lt;h2 id="example">
 example
 &lt;a class="anchor" href="#example">#&lt;/a>
&lt;/h2>
&lt;h6 id="accessing-native-apis" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="accessing-native-apis" class="docsify-tabs__tab" data-tab="Accessing Native APIS">Accessing Native APIS&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="accessing-native-apis">
&lt;h5 id="1-编写nativelibraryh">
 1. 编写NativeLibrary.h
 &lt;a class="anchor" href="#1-%e7%bc%96%e5%86%99nativelibraryh">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="cpp" data-line="" class="language-cpp line-numbers" style="max-height: none">&lt;code class="language-cpp">#include &amp;lt;string&amp;gt;

namespace NativeLibrary {
 class NativeClass {
 public:
 const std::string&amp;amp; get_property() { return property; }
 void set_property(const std::string&amp;amp; property) { this-&amp;gt;property = property; }
 std::string property;
 };
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h5 id="2-编写nativelibraryjava">
 2. 编写NativeLibrary.java
 &lt;a class="anchor" href="#2-%e7%bc%96%e5%86%99nativelibraryjava">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;

@Platform(include=&amp;quot;NativeLibrary.h&amp;quot;)
@Namespace(&amp;quot;NativeLibrary&amp;quot;)
public class NativeLibrary {
 public static class NativeClass extends Pointer {
 static { Loader.load(); }
 public NativeClass() { allocate(); }
 private native void allocate();

 // to call the getter and setter functions 
 public native @StdString String get_property(); public native void set_property(String property);

 // to access the member variable directly
 public native @StdString String property(); public native void property(String property);
 }

 public static void main(String[] args) {
 // Pointer objects allocated in Java get deallocated once they become unreachable,
 // but C++ destructors can still be called in a timely fashion with Pointer.deallocate()
 NativeClass l = new NativeClass();
 l.set_property(&amp;quot;Hello World!&amp;quot;);
 System.out.println(l.property());
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h5 id="3-执行">
 3. 执行
 &lt;a class="anchor" href="#3-%e6%89%a7%e8%a1%8c">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">$ java -jar javacpp-1.5.9.jar NativeLibrary.java -exec
&lt;/code>&lt;/pre>&lt;/div>
&lt;h5 id="4-记录">
 4. 记录
 &lt;a class="anchor" href="#4-%e8%ae%b0%e5%bd%95">#&lt;/a>
&lt;/h5>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/advance/native/javacpp-nl-01.png" alt="">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/native/jna/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/native/jna/</guid><description>&lt;h2 id="example">
 example
 &lt;a class="anchor" href="#example">#&lt;/a>
&lt;/h2>
&lt;h6 id="c-library" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c-dynamic-library" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c-dynamic-library-1" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="hikvision" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="c-library" class="docsify-tabs__tab" data-tab="C library">C library&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="c-library">
&lt;h5 id="1-导入需要的依赖包">
 1. 导入需要的依赖包
 &lt;a class="anchor" href="#1-%e5%af%bc%e5%85%a5%e9%9c%80%e8%a6%81%e7%9a%84%e4%be%9d%e8%b5%96%e5%8c%85">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="xml" data-line="" class="language-xml line-numbers" style="max-height: none">&lt;code class="language-xml">&amp;lt;!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna --&amp;gt;
&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;net.java.dev.jna&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;jna&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;5.13.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>
&lt;h5 id="2-编写代码">
 2. 编写代码
 &lt;a class="anchor" href="#2-%e7%bc%96%e5%86%99%e4%bb%a3%e7%a0%81">#&lt;/a>
&lt;/h5>
&lt;p class="warn">The following program loads the local C standard library implementation and uses it to call the printf function. &lt;/br>
Note: The following code is portable and works the same on Windows and POSIX (Linux / Unix / macOS) platforms.&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/advance/native/jni/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/advance/native/jni/</guid><description>&lt;h2 id="example">
 example
 &lt;a class="anchor" href="#example">#&lt;/a>
&lt;/h2>
&lt;h6 id="c" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="c-1" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="cc-mixture" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="c" class="docsify-tabs__tab" data-tab="C">C&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="c">
&lt;h5 id="1-写一段包含c方法实现的java代码">
 1. 写一段包含C方法实现的java代码
 &lt;a class="anchor" href="#1-%e5%86%99%e4%b8%80%e6%ae%b5%e5%8c%85%e5%90%abc%e6%96%b9%e6%b3%95%e5%ae%9e%e7%8e%b0%e7%9a%84java%e4%bb%a3%e7%a0%81">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// Save as HelloJNI.java
public class HelloJNI{
 static {
 // Load native library hello.dll (Windows) or libhello.so (Unixes) at runtime
 // This library contains a native method called sayHello()
 System.loadLibrary(&amp;quot;hello&amp;quot;);
 }
 // Declare an instance native method sayHello() which receives no parameter and returns void
 private native void sayHello();
 public static void main(String[] args){
 // Create an instance and invoke the native method
 new HelloJNI().sayHello();
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;p class="warn">The static initializer invokes System.loadLibrary() to load the native library &amp;ldquo;hello&amp;rdquo; (which contains a native method called sayHello()) during the class loading. It will be mapped to &amp;ldquo;hello.dll&amp;rdquo; in Windows; or &amp;ldquo;libhello.so&amp;rdquo; in Unixes/Mac OS X. This library shall be included in Java&amp;rsquo;s library path (kept in Java system variable java.library.path). You could include the library into Java&amp;rsquo;s library path via VM argument -Djava.library.path=/path/to/lib. The program will throw a UnsatisfiedLinkError if the library cannot be found in runtime.&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/AQS/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/AQS/</guid><description>&lt;h2 id="aqs-内部结构">
 AQS 内部结构
 &lt;a class="anchor" href="#aqs-%e5%86%85%e9%83%a8%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>内部类Node节点代码&lt;/p>
 &lt;details>&lt;summary>代码示例&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">static final class Node {
 /** Marker to indicate a node is waiting in shared mode */
 static final Node SHARED = new Node();
 /** Marker to indicate a node is waiting in exclusive mode */
 static final Node EXCLUSIVE = null;

 /** waitStatus value to indicate thread has cancelled */
 static final int CANCELLED = 1;
 /** waitStatus value to indicate successor's thread needs unparking */
 static final int SIGNAL = -1;
 /** waitStatus value to indicate thread is waiting on condition */
 static final int CONDITION = -2;
 /**
 * waitStatus value to indicate the next acquireShared should
 * unconditionally propagate
 */
 static final int PROPAGATE = -3;

 /**
 * Status field, taking on only the values:
 * SIGNAL: The successor of this node is (or will soon be)
 * blocked (via park), so the current node must
 * unpark its successor when it releases or
 * cancels. To avoid races, acquire methods must
 * first indicate they need a signal,
 * then retry the atomic acquire, and then,
 * on failure, block.
 * CANCELLED: This node is cancelled due to timeout or interrupt.
 * Nodes never leave this state. In particular,
 * a thread with cancelled node never again blocks.
 * CONDITION: This node is currently on a condition queue.
 * It will not be used as a sync queue node
 * until transferred, at which time the status
 * will be set to 0. (Use of this value here has
 * nothing to do with the other uses of the
 * field, but simplifies mechanics.)
 * PROPAGATE: A releaseShared should be propagated to other
 * nodes. This is set (for head node only) in
 * doReleaseShared to ensure propagation
 * continues, even if other operations have
 * since intervened.
 * 0: None of the above
 *
 * The values are arranged numerically to simplify use.
 * Non-negative values mean that a node doesn't need to
 * signal. So, most code doesn't need to check for particular
 * values, just for sign.
 *
 * The field is initialized to 0 for normal sync nodes, and
 * CONDITION for condition nodes. It is modified using CAS
 * (or when possible, unconditional volatile writes).
 */
 volatile int waitStatus;

 /**
 * Link to predecessor node that current node/thread relies on
 * for checking waitStatus. Assigned during enqueuing, and nulled
 * out (for sake of GC) only upon dequeuing. Also, upon
 * cancellation of a predecessor, we short-circuit while
 * finding a non-cancelled one, which will always exist
 * because the head node is never cancelled: A node becomes
 * head only as a result of successful acquire. A
 * cancelled thread never succeeds in acquiring, and a thread only
 * cancels itself, not any other node.
 */
 volatile Node prev;

 /**
 * Link to the successor node that the current node/thread
 * unparks upon release. Assigned during enqueuing, adjusted
 * when bypassing cancelled predecessors, and nulled out (for
 * sake of GC) when dequeued. The enq operation does not
 * assign next field of a predecessor until after attachment,
 * so seeing a null next field does not necessarily mean that
 * node is at end of queue. However, if a next field appears
 * to be null, we can scan prev's from the tail to
 * double-check. The next field of cancelled nodes is set to
 * point to the node itself instead of null, to make life
 * easier for isOnSyncQueue.
 */
 volatile Node next;

 /**
 * The thread that enqueued this node. Initialized on
 * construction and nulled out after use.
 */
 volatile Thread thread;

 /**
 * Link to next node waiting on condition, or the special
 * value SHARED. Because condition queues are accessed only
 * when holding in exclusive mode, we just need a simple
 * linked queue to hold nodes while they are waiting on
 * conditions. They are then transferred to the queue to
 * re-acquire. And because conditions can only be exclusive,
 * we save a field by using special value to indicate shared
 * mode.
 */
 Node nextWaiter;

 /**
 * Returns true if node is waiting in shared mode.
 */
 final boolean isShared() {
 return nextWaiter == SHARED;
 }

 /**
 * Returns previous node, or throws NullPointerException if null.
 * Use when predecessor cannot be null. The null check could
 * be elided, but is present to help the VM.
 *
 * @return the predecessor of this node
 */
 final Node predecessor() throws NullPointerException {
 Node p = prev;
 if (p == null)
 throw new NullPointerException();
 else
 return p;
 }

 Node() { // Used to establish initial head or SHARED marker
 }

 Node(Thread thread, Node mode) { // Used by addWaiter
 this.nextWaiter = mode;
 this.thread = thread;
 }

 Node(Thread thread, int waitStatus) { // Used by Condition
 this.waitStatus = waitStatus;
 this.thread = thread;
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/details>
&lt;/li>
&lt;li>
&lt;p>整体结构图&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/collection_map/hashmap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/collection_map/hashmap/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introhashmap">
 Intro(HashMap)
 &lt;a class="anchor" href="#introhashmap">#&lt;/a>
&lt;/h2>
&lt;p class="warn">hello hashmap&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="构造器">
 构造器
 &lt;a class="anchor" href="#%e6%9e%84%e9%80%a0%e5%99%a8">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public HashMap(int initialCapacity, float loadFactor) {
 if (initialCapacity &amp;lt; 0)
 throw new IllegalArgumentException(&amp;quot;Illegal initial capacity: &amp;quot; +
 initialCapacity);
 if (initialCapacity &amp;gt; MAXIMUM_CAPACITY)
 initialCapacity = MAXIMUM_CAPACITY;
 if (loadFactor &amp;lt;= 0 || Float.isNaN(loadFactor))
 throw new IllegalArgumentException(&amp;quot;Illegal load factor: &amp;quot; +
 loadFactor);
 this.loadFactor = loadFactor;
 this.threshold = tableSizeFor(initialCapacity);
}

/**
 * Constructs an empty &amp;lt;tt&amp;gt;HashMap&amp;lt;/tt&amp;gt; with the specified initial
 * capacity and the default load factor (0.75).
 *
 * @param initialCapacity the initial capacity.
 * @throws IllegalArgumentException if the initial capacity is negative.
 */
public HashMap(int initialCapacity) {
 this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

/**
 * Constructs an empty &amp;lt;tt&amp;gt;HashMap&amp;lt;/tt&amp;gt; with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="初始容量">
 初始容量
 &lt;a class="anchor" href="#%e5%88%9d%e5%a7%8b%e5%ae%b9%e9%87%8f">#&lt;/a>
&lt;/h3>
&lt;p class="warn">实际是求取一个整形数值的最接近 &lt;span class="math inline">\({\color{red}2^{n}}\)&lt;/span> 的值。
&lt;br>&lt;br>可以通过以下方法获取：
&lt;br> &lt;span class="math inline">\(2^{0} &lt; x &lt;= 2^{1}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{5em} [00000000\quad00000000\quad00000000\quad0000000{\color{red}1}] - [00000000\quad00000000\quad00000000\quad0000000{\color{red}1}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{1} &lt; x &lt;= 2^{2}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{5em} [00000000\quad00000000\quad00000000\quad000000{\color{red}10}] - [00000000\quad00000000\quad00000000\quad000000{\color{red}11}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{2} &lt; x &lt;= 2^{3}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{5em} [00000000\quad00000000\quad00000000\quad00000{\color{red}100}] - [00000000\quad00000000\quad00000000\quad00000{\color{red}111}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{3} &lt; x &lt;= 2^{4}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{5em} [00000000\quad00000000\quad00000000\quad0000{\color{red}1000}] - [00000000\quad00000000\quad00000000\quad0000{\color{red}1111}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{4} &lt; x &lt;= 2^{5}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{5em} [00000000\quad00000000\quad00000000\quad000{\color{red}10000}] - [00000000\quad00000000\quad00000000\quad000{\color{red}11111}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(\hspace{2.5em}\vdots\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{28} &lt; x &lt;= 2^{29}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{4.3em} [000{\color{red}10000\quad00000000\quad00000000\quad00000000}] - [000{\color{red}11111\quad11111111\quad11111111\quad11111111}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{29} &lt; x &lt;= 2^{30}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{4.3em} [00{\color{red}100000\quad00000000\quad00000000\quad00000000}] - [00{\color{red}111111\quad11111111\quad11111111\quad11111111}]\)&lt;/span>
&lt;br> &lt;span class="math inline">\(2^{30} &lt; x &lt;= 2^{31}-1\)&lt;/span> &lt;span class="math inline">\(\hspace{4.3em} [0{\color{red}1000000\quad00000000\quad00000000\quad00000000}] - [0{\color{red}1111111\quad11111111\quad11111111\quad11111111}]\)&lt;/span>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/exception/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/exception/</guid><description>&lt;h2 id="java-中异常返回时机">
 java 中异常返回时机
 &lt;a class="anchor" href="#java-%e4%b8%ad%e5%bc%82%e5%b8%b8%e8%bf%94%e5%9b%9e%e6%97%b6%e6%9c%ba">#&lt;/a>
&lt;/h2>
&lt;h3 id="example">
 example
 &lt;a class="anchor" href="#example">#&lt;/a>
&lt;/h3>
&lt;h6 id="1" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="2" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="3" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="4" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="5" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="6" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="1" class="docsify-tabs__tab" data-tab="1">1&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="1">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// finally语句在return语句执行之后return返回之前执行的
public int exp1(){
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 return b += 80;
 }
 catch (Exception e) {
 System.out.println(&amp;quot;catch block&amp;quot;);
 }
 finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 }
 return b;
}

output:
try block
finally block
b&amp;gt;25, b = 100
100
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="2" class="docsify-tabs__tab" data-tab="2">2&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="2">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// finally块中的return语句会覆盖try块中的return返回
public int exp2() {
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 return b += 80;
 } catch (Exception e) {
 System.out.println(&amp;quot;catch block&amp;quot;);
 } finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 return 200;
 }
 // return b;
}

output:
try block
finally block
b&amp;gt;25, b = 100
200
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="3" class="docsify-tabs__tab" data-tab="3">3&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="3">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// 如果finally语句中没有return语句覆盖返回值，那么原来的返回值可能因为finally里的修改而改变也可能不变
public int exp3() {
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 return b += 80;
 } catch (Exception e) {
 System.out.println(&amp;quot;catch block&amp;quot;);
 } finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 b = 150;
 }
 return 2000;
}

output:
try block
finally block
b&amp;gt;25, b = 100
100
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public Map&amp;lt;String, String&amp;gt; exp3_1() {
 Map&amp;lt;String, String&amp;gt; map = new HashMap();
 map.put(&amp;quot;KEY&amp;quot;, &amp;quot;INIT&amp;quot;);
 try {
 map.put(&amp;quot;KEY&amp;quot;, &amp;quot;TRY&amp;quot;);
 return map;
 }
 catch (Exception e) {
 map.put(&amp;quot;KEY&amp;quot;, &amp;quot;CATCH&amp;quot;);
 }
 finally {
 map.put(&amp;quot;KEY&amp;quot;, &amp;quot;FINALLY&amp;quot;);
 map = null;
 }
 return map;
}

output:
FINALLY
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="4" class="docsify-tabs__tab" data-tab="4">4&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="4">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// try块里的return语句在异常的情况下不会被执行(参考中的例子有错误)
public int exp4() {
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 b = b / 0;
 return b += 80;
 } catch (Exception e) {
 b += 15;
 System.out.println(&amp;quot;catch block&amp;quot;);
 } finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 b += 50;
 }
 return 204;
}

output:
try block
catch block
finally block
b&amp;gt;25, b = 35
204
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="5" class="docsify-tabs__tab" data-tab="5">5&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="5">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// 当发生异常后，catch中的return执行情况与未发生异常时try中return的执行情况完全一样
public int exp5() {
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 b = b /0;
 return b += 80;
 } catch (Exception e) {
 System.out.println(&amp;quot;catch block&amp;quot;);
 return b += 15;
 } finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 b += 50;
 }
 //return b;
}

output:
try block
catch block
finally block
b&amp;gt;25, b = 35
35
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="6" class="docsify-tabs__tab" data-tab="6">6&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="6">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// catch中的return先计算然后传值到finally中最后finally直接返回，也符合情况1。
public int exp6() {
 int b = 20;
 try {
 System.out.println(&amp;quot;try block&amp;quot;);
 b = b /0;
 return b += 80;
 } catch (Exception e) {
 System.out.println(&amp;quot;catch block&amp;quot;);
 return b += 15;
 } finally {
 System.out.println(&amp;quot;finally block&amp;quot;);
 if (b &amp;gt; 25) {
 System.out.println(&amp;quot;b&amp;gt;25, b = &amp;quot; + b);
 }
 return b += 50;
 }
 //return b;
}

output:
try block
catch block
finally block
b&amp;gt;25, b = 35
85
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;/div>
&lt;h2 id="字节码查看异常执行顺序">
 字节码查看异常执行顺序
 &lt;a class="anchor" href="#%e5%ad%97%e8%8a%82%e7%a0%81%e6%9f%a5%e7%9c%8b%e5%bc%82%e5%b8%b8%e6%89%a7%e8%a1%8c%e9%a1%ba%e5%ba%8f">#&lt;/a>
&lt;/h2>
&lt;h2 id="reference">
 reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.cnblogs.com/lanxuezaipiao/p/3440471.html" rel="noopener" target="_blank">Java finally语句到底是在return之前还是之后执行?&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/qq644266189/article/details/123034999" rel="noopener" target="_blank">java关键字finally底层原理&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/IO/IO/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/IO/IO/</guid><description>&lt;h2 id="io-简介">
 IO 简介
 &lt;a class="anchor" href="#io-%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;p class="tip">IO指以内存为中心，外部到内存为input，内存到外部为output&lt;br>
按方向分为输入流和输出流.按传输单位分为字节流和字符流。按形态分为原始流及缓冲流。&lt;br>
IO流的本质是数据传输，并且流是单向的。&lt;br>&lt;/p>
&lt;h2 id="获取文件的几种方式">
 获取文件的几种方式
 &lt;a class="anchor" href="#%e8%8e%b7%e5%8f%96%e6%96%87%e4%bb%b6%e7%9a%84%e5%87%a0%e7%a7%8d%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@Test
public void getFile(){
 // 1，直接获取项目路径下的文件
 File file = new File(&amp;quot;pom.xml&amp;quot;);
 // 2，获取resources里面的文件
 File file1 = new File(&amp;quot;src/main/resources/log4j.properties&amp;quot;);

 // 3，类加载器加载文件方式1,多一个resolveName()方法，用来追加包名。而类加载器直接在加载类的根目录加载。
 URL resource = this.getClass().getResource(&amp;quot;../res/yqgz.cer&amp;quot;);
 // 4，类加载器加载文件方式2
 URL resource1 = this.getClass().getClassLoader().getResource(&amp;quot;_base/io/res/yqgz.cer&amp;quot;);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="字节流">
 字节流
 &lt;a class="anchor" href="#%e5%ad%97%e8%8a%82%e6%b5%81">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="inputstream">
 InputStream
 &lt;a class="anchor" href="#inputstream">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>FileInputStream&lt;/p>
&lt;h6 id="fileinputstream读文件到字节代码" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="使用try-with-resource方式代码" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="fileinputstream读文件到字节代码" class="docsify-tabs__tab" data-tab="FileInputStream读文件到字节代码">FileInputStream读文件到字节代码&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="fileinputstream读文件到字节代码">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@Test
public void demoWithoutTryWithResource(){
 // URL resource = this.getClass().getClassLoader().getResource(&amp;quot;../../yqgz.cer&amp;quot;);
 // File file = new File(resource.toURI());
 URL resource = this.getClass().getResource(&amp;quot;../../res/yqgz.cer&amp;quot;);
 File file = new File(resource.getFile());
 InputStream ins = null;
 ByteArrayOutputStream byteArrayOutputStream;
 try {
 System.out.println(file.isFile() ? file.length() : 0);
 ins = new FileInputStream(file);
 byteArrayOutputStream = new ByteArrayOutputStream();
 byte[] data = new byte[1024];
 int len = 0;
 while((len = ins.read(data)) != -1){
 byteArrayOutputStream.write(data, 0, len);
 }
 System.out.println(byteArrayOutputStream.toByteArray().length);
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 if(ins != null){
 try {
 ins.close();
 } catch (IOException e) {
 throw new RuntimeException(e);
 }
 }
 // 或者直接关闭，异常包括空指针。省略if空判断。
 // try {
 // ins.close();
 // } catch (Exception e) {
 // throw new RuntimeException(e);
 // }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="使用try-with-resource方式代码" class="docsify-tabs__tab" data-tab="使用try-with-resource方式代码">使用try-with-resource方式代码&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="使用try-with-resource方式代码">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@Test
public void demoWithTryWithResource(){
 URL resource = this.getClass().getResource(&amp;quot;../../res/yqgz.cer&amp;quot;);
 File file = new File(resource.getFile());
 try (InputStream ins = new FileInputStream(file)){
 // file.length() 与后面读取到的字节数一致。都是1583
 System.out.println(file.isFile() ? file.length() : 0);
 byte[] data = new byte[1024 * 2];
 int count = ins.read(data);
 System.out.println(count);
 } catch (Exception e) {
 e.printStackTrace();
 }
} 
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>FilterInputStream&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/IO/NIO/scalable-io-in-java/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/IO/NIO/scalable-io-in-java/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introscalable-io-in-java">
 Intro(Scalable IO in Java)
 &lt;a class="anchor" href="#introscalable-io-in-java">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>Scalable network services&lt;/li>
&lt;li>Event-driven processing&lt;/li>
&lt;li>Reactor pattern
&lt;ol>
&lt;li>Basic version&lt;/li>
&lt;li>Multithreaded versions&lt;/li>
&lt;li>Other variants&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Walkthrough of java.nio nonblocking IO APIs&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>
&lt;h3 id="network-services">
 Network Services
 &lt;a class="anchor" href="#network-services">#&lt;/a>
&lt;/h3>
&lt;div class="alert flat tip">&lt;p class="title"> &lt;/p>&lt;p> &lt;strong>Web services, Distributed Objects, etc. Most have same basic structure:&lt;/strong>
&lt;br>   &lt;code>Read request&lt;/code> ➠ &lt;code>Decode request&lt;/code> ➠ &lt;code>Process service&lt;/code> ➠ &lt;code>Encode reply&lt;/code> ➠ &lt;code>Send reply&lt;/code>
&lt;br>&lt;strong>&amp;quot; But differ in nature and cost of each step XML parsing, File transfer, Web page generation, computational services, &amp;hellip;&lt;/strong>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/IO/NIO/zero-copy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/IO/NIO/zero-copy/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introzero-copy">
 Intro(ZERO COPY)
 &lt;a class="anchor" href="#introzero-copy">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 下述零拷贝内容翻译自 


 &lt;a href="https://developer.ibm.com/articles/j-zerocopy/" rel="noopener" target="_blank">Efficient data transfer through zero copy&lt;/a>&lt;/p>
&lt;/p>&lt;/div>
&lt;ul>
&lt;li>
&lt;h3 id="概览">
 概览
 &lt;a class="anchor" href="#%e6%a6%82%e8%a7%88">#&lt;/a>
&lt;/h3>
&lt;p class="warn">许多 Web 应用程序提供大量的就静态内容，这相当于从从磁盘读取数据并将完全相同的数据写回响应的 socket。此活动似乎只需要相对较少的 CPU 活动，但是在某种程度上是低效的。内核从磁盘读取数据，并将其跨越内核用户边界推送到应用程序，然后再跨越一次推送到需要被写的 socket。实际上，应用程序充当一个低效的中介，将数据从磁盘文件传输到 socket。
&lt;br>&lt;br>每一次数据从用户内核空间移动的时候，必须被复制，这会消耗 CPU 循环和内存带宽。幸运的是，你可以通过一个叫 &lt;code>ZERO COPY&lt;/code> &lt;strong>零拷贝&lt;/strong> 的技术减少这些复制。使用零拷贝的应用程序请求内核直接将数据从磁盘文件复制到 socket，而不需要经过应用程序。零拷贝极大的提高了应用程序的性能和减少了用户内核空间上下文切换的次数。
&lt;br>&lt;br>Java 类库通过&lt;code>java.nio.channels.FileChannel&lt;/code>中的&lt;code>transferTo()&lt;/code>方法在 Linux 和 Unix 系统上支持零拷贝。你可以使用&lt;code>transferTo()&lt;/code>方法直接传输数据从被调用的 channel 到另外一个可写的 channel，而不需要数据流经应用程序。这篇文章首先演示了通过传统复制进行简单文件传输所带来的开销，然后展示了使用&lt;code>transferTo()&lt;/code>的零拷贝技术如何获得更好地性能。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="数据传输传统方式">
 数据传输：传统方式
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e4%bc%a0%e8%be%93%e4%bc%a0%e7%bb%9f%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h3>
&lt;p class="warn">思考一种场景：从文件中读取数据并通过网络将数据传输到另一个程序。（此场景描述了许多服务器应用程序的行为，包括提供静态内容的 Web 应用程序，FTP 服务器，邮件服务器等。）该操作的核心在清单1 中的两个调用中。或者下载 


 &lt;a href="https://s3.us.cloud-object-storage.appdomain.cloud/developer/default/articles/j-zerocopy/static/j-zerocopy.zip" rel="noopener" target="_blank">完整的样例代码&lt;/a>&lt;/p>
&lt;h4 id="清单1拷贝字节从文件到socket">
 清单1，拷贝字节从文件到socket
 &lt;a class="anchor" href="#%e6%b8%85%e5%8d%951%e6%8b%b7%e8%b4%9d%e5%ad%97%e8%8a%82%e4%bb%8e%e6%96%87%e4%bb%b6%e5%88%b0socket">#&lt;/a>
&lt;/h4>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>虽然清单1 在概念上很简单，但在内部，拷贝操作需要在用户模式和内核模式之间进行四个上下文切换，并在操作完成之前将数据复制四次。
&lt;br>下图显示了数据在内部移动从一个文件到 socket&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/misc/properties/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/misc/properties/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introproperties">
 Intro(PROPERTIES)
 &lt;a class="anchor" href="#introproperties">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="systemproperties">
 System.properties()
 &lt;a class="anchor" href="#systemproperties">#&lt;/a>
&lt;/h3>
&lt;p class="warn">在&lt;code>System&lt;/code>类中有 &lt;strong>initProperties(Properties props);&lt;/strong> native 方法。在C代码


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/native/java/lang/System.c#L172" rel="noopener" target="_blank">&lt;code>GetJavaProperties(env);&lt;/code>&lt;/a>中会获取到一些props。这个方法的实现在


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/solaris/native/java/lang/java_props_md.c#L427" rel="noopener" target="_blank">java_props_md.c&lt;/a>中。在 626 行&lt;code>setProxyProperties(&amp;amp;sprops);&lt;/code> 会进行系统代理的设置。继续调用到


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/solaris/native/java/lang/java_props_macosx.c#L290" rel="noopener" target="_blank">java_props_maxosx.c&lt;/a>中。主要会使用 macosx SDK 中的 


 &lt;a href="https://developer.apple.com/documentation/systemconfiguration/1517088-scdynamicstorecopyproxies" rel="noopener" target="_blank">&lt;code>SCDynamicStoreCopyProxies(_:)&lt;/code>&lt;/a>


 &lt;a href="https://github.com/12302-bak/practise-demo/blob/master/main.c#L14" rel="noopener" target="_blank">【函数调用 C Demo】&lt;/a>， 获取当前系统中的网络代理设置。&lt;span style='color: red'>需要注意与环境变量进行区分。&lt;/span>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="prop对unicode编码的处理">
 Prop对unicode编码的处理
 &lt;a class="anchor" href="#prop%e5%af%b9unicode%e7%bc%96%e7%a0%81%e7%9a%84%e5%a4%84%e7%90%86">#&lt;/a>
&lt;/h3>
&lt;p class="warn">在查看 &lt;strong>Spring国际化(i18n)&lt;/strong> 和 &lt;strong>ResourceBundle&lt;/strong> 相关的代码的时候，发现都会用到&lt;code>Properties&lt;/code>类相关的处理。而且对于 &lt;strong>unicode&lt;/strong> 的处理都是由这个类去自动处理的。所以跟踪了相关代码，对这部分做一个记录。
&lt;br>&lt;br>大概的原理是：
&lt;br>&lt;code>1).&lt;/code> 在 


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/java/util/Properties.java#L344" rel="noopener" target="_blank">java.util.Properties#load0&lt;/a> 读取每一行，通过&lt;code>=&lt;/code>、&lt;code>:&lt;/code> 分割每一个key和value。在最后对key和value分别进行转换。
&lt;br>&lt;code>2).&lt;/code> 调用 


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/java/util/Properties.java#L538C20-L538C31" rel="noopener" target="_blank">java.util.Properties#loadConvert&lt;/a> 进行转换操作。转换过程：碰见&lt;code>\u&lt;/code>将后面的四位使用算法转换成十进制数字，当成一个char类型的字符。在原来的数组上面进行覆盖。&lt;/p>
&lt;p>&lt;strong>相关算法如下图：&lt;/strong>&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 比如将&lt;code>\u4f60&lt;/code>转成字符char&lt;code>20320&lt;/code>. 过程如下：
&lt;br>&lt;br>第一个字符&lt;code>'4'&lt;/code>，进到循环后，执行&lt;code>(value &amp;lt;&amp;lt; 4) + aChar - '0';&lt;/code> 此时 value = 0，左移四位还是0 ，再加上字符&lt;code>'4'&lt;/code>表示的整型值 &lt;strong>4&lt;/strong> (正好是当前字符&lt;code>'4'&lt;/code>与&lt;code>'0'&lt;/code>字符的差值) 最后value = &lt;code>0100&lt;/code>;
&lt;br>第二个字符&lt;code>'f'&lt;/code>，进来后执行&lt;code>(value &amp;lt;&amp;lt; 4) + 10 + aChar - 'a';&lt;/code> 此时将上一步得到的value 左移四位，得到&lt;code>0100 0000&lt;/code> 然后与实际值(&lt;code>'f'&lt;/code>表示的整型值 &lt;strong>15&lt;/strong> &lt;code>1111&lt;/code>)想加，即得到&lt;code>0100 1111&lt;/code>。
&lt;br>依此类推：最终得到的value = &lt;code>0100 1111 0110 0000&lt;/code> = &lt;code>20320&lt;/code>。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/network/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/network/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="tcp">
 TCP
 &lt;a class="anchor" href="#tcp">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="udp">
 UDP
 &lt;a class="anchor" href="#udp">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="inetaddress">
 InetAddress
 &lt;a class="anchor" href="#inetaddress">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="流程解析">
 流程解析
 &lt;a class="anchor" href="#%e6%b5%81%e7%a8%8b%e8%a7%a3%e6%9e%90">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> 根据域名实例化一个InetAddress对象的流程解析。
&lt;br>比如：&lt;code>InetAddress byName = InetAddress.getByName(&amp;quot;wtfu.site&amp;quot;);&lt;/code>。如果是域名的话，会涉及到系统调用&lt;code>getaddrinfo&lt;/code>.里面包括DNS解析。
&lt;br>&lt;br>1. &lt;code>getAllByName(String host, InetAddress reqAddr)&lt;/code>
&lt;br>2. 不属于ip地址的话，会继续进入到&lt;code>getAllByName0()&lt;/code>
&lt;br>3. &lt;code>addresses = getAddressesFromNameService(host, reqAddr);&lt;/code>
&lt;br>4. &lt;code>addresses = nameService.lookupAllHostAddr(host);&lt;/code>
&lt;br>5. &lt;code>impl.lookupAllHostAddr(host); // impl为Inet6AddressImpl类型，且lookupAllHostAddr为native方法。&lt;/code>
&lt;br>6. 定位到c源码后如下：可以看到关键的&lt;code>getaddrinfo&lt;/code>系统调用。&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="c" data-line="" class="language-c line-numbers" style="max-height: none">&lt;code class="language-c">//src/java.base/unix/native/libnet/Inet6AddressImpl.c
JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 jstring host, jint characteristics) {
 error = getaddrinfo(hostname, NULL, &amp;amp;hints, &amp;amp;res);
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="测试系统调用流程">
 测试系统调用流程
 &lt;a class="anchor" href="#%e6%b5%8b%e8%af%95%e7%b3%bb%e7%bb%9f%e8%b0%83%e7%94%a8%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>编写样例代码&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/string/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/string/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introstring">
 Intro(String)
 &lt;a class="anchor" href="#introstring">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="内存布局">
 内存布局
 &lt;a class="anchor" href="#%e5%86%85%e5%ad%98%e5%b8%83%e5%b1%80">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/base/string/string-memory-01.png" alt="" width="37%">
&lt;img src="https://archive-w.netlify.app/.images/doc/base/string/string-memory-02.png" alt="" width="62%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="intern">
 intern()
 &lt;a class="anchor" href="#intern">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>String.intern()&lt;/code>方法表示获取一个字符串对象的值在常量池中的引用。如果常量池中存在，则直接返回引用。如果不存在，常量池创建并返回引用。
&lt;br>&lt;br>不同jdk版本创建并返回引用是有区别的：
&lt;br>JDK1.6，不存在则在&lt;strong>永久代字符串常量池&lt;/strong>创建&lt;code>等值字符串&lt;/code>，
&lt;br>JDK1.6之后，在&lt;strong>堆区字符串常量池&lt;/strong>创建的是&lt;code>堆中String obj的引用&lt;/code>。


 &lt;a href="https://stackoverflow.com/questions/27812666/why-string-intern-behave-differently-in-oracle-jdk-1-7" rel="noopener" target="_blank">参考1&lt;/a>，


 &lt;a href="https://blog.csdn.net/tyyking/article/details/82496901" rel="noopener" target="_blank">参考2&lt;/a>
&lt;br>&lt;br>另外字符串常量池的实现是


 &lt;a href="https://www.cnblogs.com/mic112/p/15520770.html#字符串常量池" rel="noopener" target="_blank">C++ 中的hashtable&lt;/a>。&lt;/p>
&lt;p class="tip">&lt;code>String s = new String(&amp;quot;ABC&amp;quot;)&lt;/code> 这行单纯代码层面来说，只创建一个对象。如果包含类加载的过程，有可能会创建两个，一个在常量池中，一个在堆里面。堆里面的引用常量池中的value。


 &lt;a href="https://stackoverflow.com/questions/19672427/string-s-new-stringxyz-how-many-objects-has-been-made-after-this-line-of" rel="noopener" target="_blank">参考&lt;/a>
&lt;br>&lt;br>不要使用JUnit之类的工具测试intern方法，有可能会有误差，


 
 

 
 
 
 
 
 
 
 &lt;a href='#case3' rel="noopener" class="internal-link" data-src="#case3">详细解释查看case3&lt;/a>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">/**
 * Returns a canonical representation for the string object.
 * &amp;lt;p&amp;gt;
 * A pool of strings, initially empty, is maintained privately by the
 * class {@code String}.
 * &amp;lt;p&amp;gt;
 * When the intern method is invoked, if the pool already contains a
 * string equal to this {@code String} object as determined by
 * the {@link #equals(Object)} method, then the string from the pool is
 * returned. Otherwise, this {@code String} object is added to the
 * pool and a reference to this {@code String} object is returned.
 * &amp;lt;p&amp;gt;
 * It follows that for any two strings {@code s} and {@code t},
 * {@code s.intern() == t.intern()} is {@code true}
 * if and only if {@code s.equals(t)} is {@code true}.
 * &amp;lt;p&amp;gt;
 * All literal strings and string-valued constant expressions are
 * interned. String literals are defined in section 3.10.5 of the
 * &amp;lt;cite&amp;gt;The Java&amp;amp;trade; Language Specification&amp;lt;/cite&amp;gt;.
 *
 * @return a string that has the same contents as this string, but is
 * guaranteed to be from a pool of unique strings.
 */
public native String intern();
&lt;/code>&lt;/pre>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel title-panel">
&lt;h4 id="测试">
 测试
 &lt;a class="anchor" href="#%e6%b5%8b%e8%af%95">#&lt;/a>
&lt;/h4>
&lt;h6 id="case1" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="case2" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="case3" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="case1" class="docsify-tabs__tab" data-tab="case1">case1&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="case1">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// source: https://blog.csdn.net/tyyking/article/details/82496901
String str2 = new String(&amp;quot;str&amp;quot;) + new String(&amp;quot;01&amp;quot;);
str2.intern(); 
String str1 = &amp;quot;str01&amp;quot;;
System.out.println(str2 == str1);

// 上述代码在JDK1.6及以后版本表现不同。假设str2的地址为`String@725`
// 1.6 调用`str2.intern()`会在永久代字符串常量池中复制等值字符串String@825，然后返回引用String@825。给str1赋值的时候发现字符串常量池有'str01'，则将引用String@825给str1。
// &amp;gt;1.6 调用`str2.intern()`会在堆区字符串常量池中放置对象str2的引用String@725，然后返回引用String@725。给str1赋值的时候发现字符串常量池有'str01'，则将引用String@725给str1。
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/base/string/string-intern-01.png" alt="" width="99%">
&lt;img src="https://archive-w.netlify.app/.images/doc/base/string/string-intern-02.png" alt="" width="99%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/base/thread/thread-pool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/base/thread/thread-pool/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introthread-pool">
 Intro(THREAD POOL)
 &lt;a class="anchor" href="#introthread-pool">#&lt;/a>
&lt;/h2>
&lt;p class="tip">


 &lt;a href="https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/java/util/concurrent/ThreadPoolExecutor.java" rel="noopener" target="_blank">ThreadPoolExecutor.java&lt;/a>
&lt;br>&lt;br>线程池解决了两个不同的问题:
&lt;br>&lt;code>1).&lt;/code> 在执行大量异步任务时，由于减少了每个任务的调用开销，它们通常提供改进的性能;
&lt;br>&lt;code>2).&lt;/code> 在执行一组任务时，它们提供了一种绑定和管理资源(包括线程)的方法。每个ThreadPoolExecutor还维护一些基本统计信息，例如已完成任务的数量。
&lt;br>&lt;br>&lt;code>核心和最大线程数&lt;/code>：
&lt;br>线程池会根据&lt;code>核心线程数&lt;/code>和&lt;code>最大线程数&lt;/code>自动调节池中的线程数量。当一个任务提交的时候，如果少于核心线程数的线程正在运行，则一个新的线程被创建用来处理当前的任务请求（即使其它线程空闲）。如果运行的线程数在&lt;code>核心线程&lt;/code>和&lt;code>最大线程&lt;/code>之间，则优先队列任务，如果队列满了，就创建线程。
&lt;br>&lt;br>&lt;code>队列(BlockingQueue)&lt;/code>：
&lt;br>队列用来传输和持有提交的任务，它的使用和线程池中的线程数互相作用。有以下几点：
&lt;br>&lt;code>a).&lt;/code> 小于核心线程数的线程正在运行，则创建新线程。
&lt;br>&lt;code>b).&lt;/code> 大于核心线程数，则入队列
&lt;br>&lt;code>c).&lt;/code> 入队列不成功(满了)，但是小于最大线程数，则创建新线程。
&lt;br>&lt;code>d).&lt;/code> 其他情况(队列满了且达到最大线程数)，则拒绝执行。
&lt;br>&lt;br>对于队列的选择，一般有三种情况：
&lt;br>&lt;code>SynchronousQueue&lt;/code>：这个阻塞队列的特性是，每插入一个元素，必须消费之后才可以继续插入。而且可以支持公平和非公平选择，用于对等待的生产者和消费者线程进行排序。所以使用这种队列，如果在生产速度大于消费速度，则通过queue.offer()方法放不进去，只能创建新线程进行处理了。所以线程数可能无限增长。
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/base/thread/thread-pool/tp-queue-01.png" alt="" width="90%">
&lt;br>&lt;code>LinkedBlockingQueue&lt;/code>：偏无界队列（&lt;code>Integer.MAX_VALUE&lt;/code>）
&lt;br>&lt;code>ArrayBlockingQueue&lt;/code>：有边界
&lt;br>&lt;br>钩子方法：&lt;code>beforeExecute(Thread, Runnable) &lt;/code>、&lt;code>afterExecute(Runnable, Throwable)&lt;/code>
&lt;br>&lt;br>按需加载：&lt;code>prestartCoreThread(启动一个核心线程)&lt;/code>、&lt;code>prestartAllCoreThreads(启动所有核心线程)&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="属性">
 属性
 &lt;a class="anchor" href="#%e5%b1%9e%e6%80%a7">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;strong>ctl&lt;/strong> 是一个原子整数类型，里面主要体现两个属性：&lt;code>workerCount&lt;/code>: 有效的线程数量、&lt;code>runState&lt;/code>: 是否运行，关闭等状态。
&lt;br>为了将这两个属性放在一个数字里面控制，我们限制了&lt;code>workerCount&lt;/code>的值为 &lt;span class="math inline">\({\color{blue}(2^{29} - 1 )}\)&lt;/span>(大约5亿个线程)，而不是 &lt;span class="math inline">\({\color{blue} (2^{31} - 1)}\)&lt;/span>(大约20亿)
&lt;br>&lt;br>&lt;code>workerCount&lt;/code>：允许开始执行的线程数。因为一些原因，这个值可能和实际存活的线程数暂时不一致，比如：当要求线程池创建线程的时候失败了，或者在terminated之前退出线程依旧在执行任务。
&lt;br>&lt;br>&lt;code>runState&lt;/code>：线程池状态
&lt;br>&lt;span style='padding-left: 2.9em'/>&lt;code>RUNNING&lt;/code>: 可以接受新的任务并且处理队列中的任务
&lt;br>&lt;span style='padding-left: 2.9em'/>&lt;code>SHUTDOWN&lt;/code>: 不接受新的任务但是会处理队列中的任务
&lt;br>&lt;span style='padding-left: 2.9em'/>&lt;code>STOP&lt;/code>: 不接受新的任务，不处理队列中的任务，并且给中断正在执行的线程
&lt;br>&lt;span style='padding-left: 2.9em'/>&lt;code>TIDYING&lt;/code>: 所有任务都已种植，&lt;strong>workerCount&lt;/strong> 为零，转换到 &lt;strong>TIDYING&lt;/strong> 状态的线程将执行&lt;code>terminated()&lt;/code>钩子方法。
&lt;br>&lt;span style='padding-left: 2.9em'/>&lt;code>TERMINATED&lt;/code>: &lt;code>terminated()&lt;/code>钩子方法执行完毕。
&lt;br>&lt;br>为了允许有序比较，这些值之间的数字顺序很重要。runState单调地随时间增加，但不需要达到每个状态。转换过程：&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/dstb/lock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/dstb/lock/</guid><description>&lt;p>comming soon&amp;hellip;&lt;/p>
&lt;h2 id="redis_lock">
 redis_lock
 &lt;a class="anchor" href="#redis_lock">#&lt;/a>
&lt;/h2>
&lt;h2 id="zookeeper_lock">
 zookeeper_lock
 &lt;a class="anchor" href="#zookeeper_lock">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/dstb/schedule/quartz/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/dstb/schedule/quartz/</guid><description>&lt;p>comming soon&amp;hellip;&lt;/p>
&lt;h2 id="1">
 1
 &lt;a class="anchor" href="#1">#&lt;/a>
&lt;/h2>
&lt;h2 id="2">
 2
 &lt;a class="anchor" href="#2">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/dstb/schedule/xxl-job/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/dstb/schedule/xxl-job/</guid><description>&lt;p>comming soon&amp;hellip;&lt;/p>
&lt;h2 id="1">
 1
 &lt;a class="anchor" href="#1">#&lt;/a>
&lt;/h2>
&lt;h2 id="2">
 2
 &lt;a class="anchor" href="#2">#&lt;/a>
&lt;/h2>
&lt;h2 id="3">
 3
 &lt;a class="anchor" href="#3">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/dstb/transcation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/dstb/transcation/</guid><description>&lt;h2 id="2pc两阶段提交方案xa方案">
 2PC(两阶段提交方案/XA方案)
 &lt;a class="anchor" href="#2pc%e4%b8%a4%e9%98%b6%e6%ae%b5%e6%8f%90%e4%ba%a4%e6%96%b9%e6%a1%88xa%e6%96%b9%e6%a1%88">#&lt;/a>
&lt;/h2>
&lt;h2 id="tcctry-confirm-cancel">
 TCC(Try Confirm Cancel)
 &lt;a class="anchor" href="#tcctry-confirm-cancel">#&lt;/a>
&lt;/h2>
&lt;h2 id="本地消息表">
 本地消息表
 &lt;a class="anchor" href="#%e6%9c%ac%e5%9c%b0%e6%b6%88%e6%81%af%e8%a1%a8">#&lt;/a>
&lt;/h2>
&lt;h2 id="可靠消息最终一致性方案">
 可靠消息最终一致性方案
 &lt;a class="anchor" href="#%e5%8f%af%e9%9d%a0%e6%b6%88%e6%81%af%e6%9c%80%e7%bb%88%e4%b8%80%e8%87%b4%e6%80%a7%e6%96%b9%e6%a1%88">#&lt;/a>
&lt;/h2>
&lt;h2 id="最大努力通知方案">
 最大努力通知方案
 &lt;a class="anchor" href="#%e6%9c%80%e5%a4%a7%e5%8a%aa%e5%8a%9b%e9%80%9a%e7%9f%a5%e6%96%b9%e6%a1%88">#&lt;/a>
&lt;/h2>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/JavaShark/article/details/125350886" rel="noopener" target="_blank">这六种目前最常见分布式事务解决方案&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/qq_37142346/article/details/78494992" rel="noopener" target="_blank">2PC实现 Springboot+atomikos+jta实现分布式事务统一管理&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/es/es/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/es/es/</guid><description>&lt;p>comming soon&amp;hellip;&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/log_framework/jul/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/log_framework/jul/</guid><description>&lt;h2 id="juljava-util-logging">
 JUL(java util logging)
 &lt;a class="anchor" href="#juljava-util-logging">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="配置模板">
 配置模板
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%ae%e6%a8%a1%e6%9d%bf">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>vim $(dirname $(which java))/../jre/lib/logging.properties&lt;/code>
&lt;br>&lt;code>vim ``dirname $(which java)``/../jre/lib/logging.properties&lt;/code>&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="properties" data-line="" class="language-properties line-numbers" style="max-height: none">&lt;code class="language-properties">############################################################
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
# Global properties
############################################################

# &amp;quot;handlers&amp;quot; specifies a comma separated list of log Handler
# classes. These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers. For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
# &amp;lt;level&amp;gt;: &amp;lt;log message&amp;gt; [&amp;lt;date/time&amp;gt;]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
com.xyz.foo.level = SEVERE
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="使用">
 使用
 &lt;a class="anchor" href="#%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://bilibili.com/video/BV13A41137Tc?p=6&amp;vd_source=550a4dc4b2a914c0681a14307bbe8cbe" rel="noopener" target="_blank">https://bilibili.com/video/BV13A41137Tc?p=6&amp;vd_source=550a4dc4b2a914c0681a14307bbe8cbe&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://note.youdao.com/s/7retQ6yb" rel="noopener" target="_blank">https://note.youdao.com/s/7retQ6yb&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mq/activemq/acmq/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mq/activemq/acmq/</guid><description>&lt;h2 id="引入消息队列后-如何保证高可用性">
 引入消息队列后 如何保证高可用性
 &lt;a class="anchor" href="#%e5%bc%95%e5%85%a5%e6%b6%88%e6%81%af%e9%98%9f%e5%88%97%e5%90%8e-%e5%a6%82%e4%bd%95%e4%bf%9d%e8%af%81%e9%ab%98%e5%8f%af%e7%94%a8%e6%80%a7">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>持久化、事务、签收、 以及带复制的 Leavel DB + zookeeper 主从集群搭建&lt;/p>
&lt;/blockquote>
&lt;h2 id="异步投递---async--send">
 异步投递 Async send
 &lt;a class="anchor" href="#%e5%bc%82%e6%ad%a5%e6%8a%95%e9%80%92---async--send">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>对于一个慢消费者，使用同步有可能造成堵塞，消息消费较慢时适合用异步发送消息 activemq 支持同步异步 发送的消息，默认异步。当你设定同步发送的方式和 未使用事务的情况下发持久化消息，这时是同步的。 如果没有使用事务，且发送的是持久化消息，每次发送都会阻塞一个生产者直到 broker 发回一个确认，这样做保证了消息的安全送达，但是会阻塞客户端，造成很大延时 。 在高性能要求下，可以使用异步提高producer 的性能。但会消耗较多的client 端内存，也不能完全保证消息发送成功。在 useAsyncSend = true 情况下容忍消息丢失
通过回调感知消息正常到达。&lt;/p>
&lt;/blockquote>
&lt;h2 id="延迟投递和定时投递">
 延迟投递和定时投递
 &lt;a class="anchor" href="#%e5%bb%b6%e8%bf%9f%e6%8a%95%e9%80%92%e5%92%8c%e5%ae%9a%e6%97%b6%e6%8a%95%e9%80%92">#&lt;/a>
&lt;/h2>
&lt;h2 id="activemq-的消息重试机制">
 ActiveMQ 的消息重试机制
 &lt;a class="anchor" href="#activemq-%e7%9a%84%e6%b6%88%e6%81%af%e9%87%8d%e8%af%95%e6%9c%ba%e5%88%b6">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>超过6次标记为有毒消息，broker将消息放入死信队列&lt;/p>
&lt;/blockquote>
&lt;h2 id="如何保证消息不被重复消费幂等性的问题">
 如何保证消息不被重复消费，幂等性的问题
 &lt;a class="anchor" href="#%e5%a6%82%e4%bd%95%e4%bf%9d%e8%af%81%e6%b6%88%e6%81%af%e4%b8%8d%e8%a2%ab%e9%87%8d%e5%a4%8d%e6%b6%88%e8%b4%b9%e5%b9%82%e7%ad%89%e6%80%a7%e7%9a%84%e9%97%ae%e9%a2%98">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>如果消息是做数据库的插入操作，给这个消息一个唯一的主键，那么就算出现重复消费的情况，就会导致主键冲突，避免数据库出现脏数据 。 如果不是，可以用redis 等的第三方服务，给消息一个全局 id ，只要消费过的消息，将 id ，message 以 K-V 形式写入 redis ，那消费者开始消费前，先去 redis 中查询有没消费的记录即可。&lt;/p>
&lt;/blockquote>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://note.youdao.com/web/#/file/WEB1277b8f2da90c224c2c7a6a3175b2ea5/note/54AA1E33A4AE4AC9BA77EAA4384370B4/" rel="noopener" target="_blank">https://note.youdao.com/web/#/file/WEB1277b8f2da90c224c2c7a6a3175b2ea5/note/54AA1E33A4AE4AC9BA77EAA4384370B4/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mq/kafka/kafka/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mq/kafka/kafka/</guid><description>&lt;p>hello kafka&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mybatis/mybatis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mybatis/mybatis/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intromybatis--underlying">
 Intro(MyBatis | underlying)
 &lt;a class="anchor" href="#intromybatis--underlying">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="要点">
 要点
 &lt;a class="anchor" href="#%e8%a6%81%e7%82%b9">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 1. mapper 接口定义的语句怎么生成的? configuration解析后会生成一个 MappedStatement{id:&amp;quot;&amp;quot;}. 并且将ID 和 ms 放入 configuration 中的 mappedStatements 中。
&lt;br>2. 执行顺序是什么样的？
&lt;br>3. 缓存是如何处理的？
&lt;br>4. 拦截器原理。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="mapper接口的实现">
 Mapper接口的实现
 &lt;a class="anchor" href="#mapper%e6%8e%a5%e5%8f%a3%e7%9a%84%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">通过&lt;code>MapperRegistry&lt;/code>里面的 map 类型的 knowMappers 根据 type 获取到 MapperProxyFactory ,进而调用&lt;code>return mapperProxyFactory.newInstance(sqlSession);&lt;/code>返回一个 mapper 接口代理对象。
&lt;br> 上述代理对象中使用的 InvocationHandler 叫 &lt;code>MapperProxy&lt;/code>，里面 invoke() 的实现是将方法包装成一个&lt;code>MapperMethod&lt;/code> mm 存放在&lt;code>MapperMethodInvoker&lt;/code> mmi 里面，并会进行缓存，然后调用 mmi 里面的 invoke，进而执行到 mm.execute()方法，内部通过执行器拿到结果返回。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="拦截器实现">
 拦截器实现
 &lt;a class="anchor" href="#%e6%8b%a6%e6%88%aa%e5%99%a8%e5%ae%9e%e7%8e%b0">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://mybatis.org/mybatis-3/zh_CN/configuration.html#plugins" rel="noopener" target="_blank">插件文档&lt;/a>
&lt;br>&lt;br>对于拦截器来说，主要在以下接口工作：&lt;code>Executor&lt;/code>，&lt;code>ParameterHandler&lt;/code>，&lt;code>ResultSetHandler&lt;/code>，&lt;code>StatementHandler&lt;/code>。
&lt;br>&lt;br>涉及的主要类有，实现了 


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/doc/advance/#jdk' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/doc/advance/#jdk">JDK 代理&lt;/a> 中 &lt;strong>InvocationHandler&lt;/strong> 的 &lt;code>Plugin&lt;/code>，以及 &lt;code>Interceptor&lt;/code>接口。
&lt;br>&lt;br>大致调用流程：
&lt;br>&lt;code>1.&lt;/code> 创建对象：&lt;code>executor = new CachingExecutor(executor);&lt;/code>
&lt;br>&lt;code>2.&lt;/code> 将所有拦截器进行插件化：&lt;code>executor = (Executor) interceptorChain.pluginAll(executor);&lt;/code>内部实现如下：
&lt;br>&lt;span style='padding-left:2em'>&lt;code>2.1.&lt;/code> 在 &lt;strong>Plugin&lt;/strong> 代码中第 13 行，将 executor 对象，以及拦截器对象进行包装。如果拦截器注解签名方法中需要拦截的类在目标对象上的话，返回代理对象。如果不是，则返回target就行。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>2.2.&lt;/code> 返回的代理对象是实现了目标对象上面的接口，此处也就是 executor，所以可以强转。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>2.3.&lt;/code> 因为在 &lt;strong>InterceptorChain&lt;/strong> 第六行循环中，需要注意第一次循环后返回的target可能是代理对象，下一次循环中可能返回代理对象 &lt;em>去代理&lt;/em> 代理对象的情况。如下图：
&lt;br>&lt;span style='padding-left:5em'> &lt;img src="https://archive-w.netlify.app/.images/doc/framework/mybatis/underlying/u-interceptor-01.png" alt="" width="70%">
&lt;br>&lt;br>&lt;code>3.&lt;/code> 使用对象：内部的执行流程可以画图表示，涉及 JDK 代理。
&lt;br>&lt;span style='padding-left:2em'>如果在外部调用刚才插件化的代理对象的话，则首先调用到 &lt;strong>invoke()&lt;/strong> 方法中，然后根据签名map 判断是否当前方法是拦截器需要拦截的方法，根据判断结果选择是进入拦截器拦截方法 &lt;strong>intercept(Invocation invocation)&lt;/strong>，还是直接调用目标对象（此处的目标对象有可能是还是一个代理对象）。
&lt;br>&lt;span style='padding-left:5em'> &lt;img src="https://archive-w.netlify.app/.images/doc/framework/mybatis/underlying/u-interceptor-02.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/adv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/adv/</guid><description>&lt;p>hello&lt;/p>
&lt;p>1、主从复制
     


 &lt;a href="https://www.cnblogs.com/gl-developer/p/6170423.html" rel="noopener" target="_blank">https://www.cnblogs.com/gl-developer/p/6170423.html&lt;/a>&lt;/p>
&lt;p>2、读写分离 
     


 &lt;a href="https://blog.csdn.net/liu976180578/article/details/77684583" rel="noopener" target="_blank">https://blog.csdn.net/liu976180578/article/details/77684583&lt;/a>&lt;/p>
&lt;p>3，分库分表
    https://blog.csdn.net/trigl/article/details/50968079&lt;/p>
&lt;p>4，多数据源&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/analyze_tools/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/analyze_tools/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="分析工具">
 分析工具
 &lt;a class="anchor" href="#%e5%88%86%e6%9e%90%e5%b7%a5%e5%85%b7">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 通过工具进行分析，结合书中的概念学习innodb存储引擎。
&lt;br>&lt;br> &lt;strong>.frm&lt;/strong> 解析工具如下：
&lt;br>


 &lt;a href="https://dbsake.readthedocs.io/en/latest/readme.html" rel="noopener" target="_blank">dbsake(a(s)wiss-(a)rmy-(k)nif(e) for MySQL)&lt;/a>,    


 &lt;a href="https://github.com/abg/dbsake" rel="noopener" target="_blank">github&lt;/a>
&lt;br> 


 &lt;a href="https://github.com/mysql/mysql-utilities/blob/master/scripts/mysqlfrm.py" rel="noopener" target="_blank">mysqlfrm&lt;/a>,    


 &lt;a href="https://downloads.mysql.com/archives/utilities/" rel="noopener" target="_blank">download archive&lt;/a>,    


 &lt;a href="https://downloads.mysql.com/docs/mysql-utilities-1.5-en.pdf" rel="noopener" target="_blank">mysql-utilities pdf&lt;/a>
&lt;br> 


 &lt;a href="https://github.com/fpspammers/frm-parser" rel="noopener" target="_blank">frm-parser&lt;/a>
&lt;br>&lt;br>&lt;strong>.ibd&lt;/strong> 解析工具有：
&lt;br>


 &lt;a href="https://github.com/alibaba/innodb-java-reader" rel="noopener" target="_blank">innodb-java-reader&lt;/a>
&lt;br>


 &lt;a href="https://github.com/jeremycole/innodb_ruby" rel="noopener" target="_blank">innodb_ruby&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="frm-parser">
 frm-parser
 &lt;a class="anchor" href="#frm-parser">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 


 &lt;a href="https://github.com/fpspammers/frm-parser" rel="noopener" target="_blank">开源仓库&lt;/a>
&lt;br>使用frm解析工具对&lt;code>/tmp/mysql/demos/record_format_demo.frm&lt;/code> ,进行分析，解析结果如下。&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p>
1). 对代码稍作修改，使用cmake构建，修改文件位置为绝对路径，&lt;code>show_tables()&lt;/code>,&lt;code>show_db()&lt;/code>函数中的文件位置也需要改变。&lt;/p>
&lt;/p>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/mysql-analyze-tool-01.png" alt="" width="60%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="dbsake">
 dbsake
 &lt;a class="anchor" href="#dbsake">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 参考


 &lt;a href="https://dbsake.readthedocs.io/en/latest/readme.html#quickstart" rel="noopener" target="_blank">官方文档&lt;/a>进行安装测试。自定义安装位置,比如：&lt;code>cd /usr/local/bin&lt;/code>
&lt;br>&lt;code>curl -s get.dbsake.net &amp;gt; dbsake&lt;/code>
&lt;br>&lt;code>chmod u+x dbsake&lt;/code>
&lt;br>&lt;code>dbsake -?&lt;/code>&lt;/p>
&lt;/p>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 35%; width: 35%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/mysql-analyze-tool-02.png" alt="" width="100%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 52%; width: 52%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/mysql-analyze-tool-03.png" alt="" width="100%">&lt;/p>&lt;/div>&lt;/div>

&lt;/li>
&lt;li>
&lt;h3 id="mysql-utilities">
 mysql-utilities
 &lt;a class="anchor" href="#mysql-utilities">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/01_recognize/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/01_recognize/</guid><description>&lt;h2 id="bin目录可执行文件">
 BIN目录可执行文件
 &lt;a class="anchor" href="#bin%e7%9b%ae%e5%bd%95%e5%8f%af%e6%89%a7%e8%a1%8c%e6%96%87%e4%bb%b6">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="查看目录">
 查看目录
 &lt;a class="anchor" href="#%e6%9f%a5%e7%9c%8b%e7%9b%ae%e5%bd%95">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="6,15-17" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># tree -L 3 /usr/local/opt/mysql@5.7/bin/

/usr/local/opt/mysql@5.7/bin/
├── innochecksum
├── mysql
├── mysql.server -&amp;gt; ../support-files/mysql.server
├── mysql_client_test
├── mysql_client_test_embedded
├── mysql_install_db
├── mysql_plugin
├── mysql_secure_installation
├── mysql_upgrade
├── mysqladmin
├── mysqlbinlog
├── mysqld
├── mysqld_multi
├── mysqld_safe
├── mysqldump
├── mysqldumpslow
├── mysqlshow
├── mysqltest
└── ...
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;h2 id="启动mysql服务器程序">
 启动Mysql服务器程序
 &lt;a class="anchor" href="#%e5%90%af%e5%8a%a8mysql%e6%9c%8d%e5%8a%a1%e5%99%a8%e7%a8%8b%e5%ba%8f">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="unix里启动服务器程序">
 Unix里启动服务器程序
 &lt;a class="anchor" href="#unix%e9%87%8c%e5%90%af%e5%8a%a8%e6%9c%8d%e5%8a%a1%e5%99%a8%e7%a8%8b%e5%ba%8f">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>mysqld&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>mysqld这个可执行文件代表mysql服务器程序，运行这个可执行文件就可以直接启动一个服务进程，但是这个命令不常用，一般会结合其他脚本使用。 比如下面这个。&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>mysqld_safe&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>mysqld_safe是一个可执行脚本，它会嫁接调用mysqld。而且还顺带启动了一个监控进程。这个监控进程会在服务器挂了的时候重新启动它。另外，使用脚本启动的时候，它会将服务器的出错信息和其他诊断信息重新定向到某个文件中，产生错误日志，这样可以方便我们找出发生错误的原因。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/02_cmd-and-system-variables/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/02_cmd-and-system-variables/</guid><description>&lt;p>hello&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/03_character_and_collation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/03_character_and_collation/</guid><description>&lt;h2 id="字符集和比较规则简介">
 字符集和比较规则简介
 &lt;a class="anchor" href="#%e5%ad%97%e7%ac%a6%e9%9b%86%e5%92%8c%e6%af%94%e8%be%83%e8%a7%84%e5%88%99%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;h3 id="字符集简介">
 字符集简介
 &lt;a class="anchor" href="#%e5%ad%97%e7%ac%a6%e9%9b%86%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h3>
&lt;p>我们知道在计算机中只能存储二进制数据，那该怎么存储字符串呢？当然是建立字符与二进制数据的映射关系了，建立这个关系最起码要搞清楚两件事儿：&lt;/p>
&lt;ol>
&lt;li>你要把哪些字符映射成二进制数据？（也就是界定清楚字符范围）&lt;/li>
&lt;li>怎么映射？
将一个字符映射成二进制数据的过程叫&lt;code>编码&lt;/code>，将一个二进制数据映射到一个字符的过程叫&lt;code>解码&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>人们抽象出一个&lt;code>字符集&lt;/code>的概念来描述某个字符范围的编码规则。比方说我们来自定义一个名称为 xiaohaizi的字符集，它包括的字符范围和编码规则如下：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>包含的字符&amp;rsquo;a&amp;rsquo;、&amp;lsquo;b&amp;rsquo;、&amp;lsquo;A&amp;rsquo;、&amp;lsquo;B&amp;rsquo;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>编码的规则如下：&lt;/p>
&lt;p>采用一个字节编码一个字符的形式，字符和字节的映射关系如下：
&amp;lsquo;a&amp;rsquo; -&amp;gt; 00000001 (十六进制：0x01)
&amp;lsquo;b&amp;rsquo; -&amp;gt; 00000010 (十六进制：0x02)
&amp;lsquo;A&amp;rsquo; -&amp;gt; 00000011 (十六进制：0x03)
&amp;lsquo;B&amp;rsquo; -&amp;gt; 00000100 (十六进制：0x04)&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>有了xiaohaizi 字符集，我们就可以用二进制形式表示一些字符串了，下边是一些字符串用 xiaohaizi字符编码后的二进制表示:&lt;/p>
&lt;pre>&lt;code>'bA' -&amp;gt; 0000001000000011 (十六进制：0x0203)
'baB' -&amp;gt; 000000100000000100000100 (十六进制：0x020104)
'cd' -&amp;gt; 无法表示，字符集xiaohaizi不包含字符'c'和'd'
&lt;/code>&lt;/pre>
&lt;h3 id="比较规则简介">
 比较规则简介
 &lt;a class="anchor" href="#%e6%af%94%e8%be%83%e8%a7%84%e5%88%99%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h3>
&lt;p>在我们确定了 xiaohaizi 字符集表示字符的范围以及编码规则后，怎么比较两个字符的大小呢？最容易想到的就是直接比较这两个字符对应的二进制编码的大小，比方说字符 &amp;lsquo;a&amp;rsquo; 的编码为 0x01 ，字符 &amp;lsquo;b&amp;rsquo; 的编码为 0x02 ，所以 &amp;lsquo;a&amp;rsquo; 小于 &amp;lsquo;b&amp;rsquo; ，这种简单的比较规则也可以被称为二进制比较规则，英文名为&lt;code>binary collation&lt;/code> 。二进制比较规则是简单，但有时候并不符合现实需求，比如在很多场合对于英文字符我们都是不区分大小写的，也就是说 &amp;lsquo;a&amp;rsquo; 和 &amp;lsquo;A&amp;rsquo; 是相等的，在这种场合下就不能简单粗暴的使用二进制比较规则了，这时候我们可以这样指定比较规则：&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/04_innodb-record-struct/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/04_innodb-record-struct/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="准备工作">
 准备工作
 &lt;a class="anchor" href="#%e5%87%86%e5%a4%87%e5%b7%a5%e4%bd%9c">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon fas fa-comment">&lt;/span> Comment &lt;/p>&lt;p>到现在为止， MySQL 对于我们来说还是一个黑盒，我们只负责使用客户端发送请求并等待服务器返回结果，表中的数据到底存到了哪里？以什么格式存放的？ MySQL 是以什么方式来访问的这些数据？我们前边唠叨请求处理过程的时候提到过， MySQL 服务器上负责对表中数据的读取和写入工作的部分是 &lt;code>存储引擎&lt;/code> ，而服务器又支持不同类型的存储引擎，比如 &lt;code>InnoDB&lt;/code> 、 &lt;code>MyISAM&lt;/code> 、 &lt;code>Memory&lt;/code> 啥的，不同的存储引擎一般是由不同的人为实现不同的特性而开发的，真实数据在不同存储引擎中存放的格式一般是不同的，甚至有的存储引擎比如 Memory 都不用磁盘来存储数据，也就是说关闭服务器后表中的数据就消失了。&lt;strong>由于 InnoDB 是 MySQL 默认的存储引擎，也是我们最常用到的存储引擎&lt;/strong>，我们也没有那么多时间去把各个存储引擎的内部实现都看一遍，所以本集要唠叨的是使用 InnoDB 作为存储引擎的数据存储结构。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="innodb架构">
 InnoDB架构
 &lt;a class="anchor" href="#innodb%e6%9e%b6%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> Attention &lt;/p>&lt;p> 


 &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html" rel="noopener" target="_blank">https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html&lt;/a>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="innodb页简介">
 InnoDB页简介
 &lt;a class="anchor" href="#innodb%e9%a1%b5%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;p class="warn">InnoDB 是一个将表中的数据存储到磁盘上的存储引擎，所以即使关机后重启我们的数据还是存在的。而真正处理数据的过程是发生在内存中的，所以需要把磁盘中的数据加载到内存中，如果是处理写入或修改请求的话，还需要把内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢，和内存读写差了几个数量级，所以当我们想从表中获取某些记录时， InnoDB 存储引擎需要一条一条的把记录从磁盘上读出来么？不，那样会慢死，InnoDB 采取的方式是：&lt;span style="color: blue">将数据划分为若干个页，以页作为磁盘和内存之间交互的基本单位，InnoDB中页的大小一般为 16KB: &lt;code>show variables like 'innodb_page_size';&lt;/code>&lt;/span> 也就是在一般情况下，一次最少从磁盘中读取16KB的内容到内存中，一次最少把内存中的16KB内容刷新到磁盘中。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="innodb行格式">
 InnoDB行格式
 &lt;a class="anchor" href="#innodb%e8%a1%8c%e6%a0%bc%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;p class="warn">我们平时是以记录为单位来向表中插入数据的，这些记录在磁盘上的存放方式(&lt;code>ROW_FORMAT&lt;/code>)也被称为 &lt;code>行格式&lt;/code> 或者 &lt;code>记录格式&lt;/code> 。设计 InnoDB 存储引擎的大叔们到现在为止设计了4种不同类型的 行格式 ，分别是:
&lt;br> &lt;code>Compact&lt;/code> 、 &lt;code>Redundant&lt;/code>(MySQL5.0 之前用的一种行格式) 、&lt;code>Dynamic&lt;/code> 和 &lt;code>Compressed&lt;/code> 行格式。
&lt;br>随着时间的推移，他们可能会设计出更多的行格式，但是不管怎么变，在原理上大体都是相同的。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/05_innodb-page-struct/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/05_innodb-page-struct/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="不同类型的页简介">
 不同类型的页简介
 &lt;a class="anchor" href="#%e4%b8%8d%e5%90%8c%e7%b1%bb%e5%9e%8b%e7%9a%84%e9%a1%b5%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;p class="warn">前边我们简单提了一下 &lt;strong>页&lt;/strong> 的概念，它是 InnoDB 管理存储空间的基本单位，一个页的大小一般是 &lt;em>&lt;strong>16KB&lt;/strong>&lt;/em> 。InnoDB 为了不同的目的而设计了许多种 


 
 

 
 
 
 
 
 
 
 &lt;a href='#fil_page_type' rel="noopener" class="internal-link" data-src="#fil_page_type">不同类型的页&lt;/a> ，比如存放&lt;code>表空间头部信息&lt;/code>的页，存放&lt;code>Insert Buffer信息&lt;/code>的页，存放&lt;code>INODE 信息&lt;/code>的页，存放&lt;code>undo 日志信息&lt;/code>的页等等等等。当然了，如果我说的这些名词你一个都没有听过，就当我放了个屁吧～ 不过这没有一毛钱关系，我们今儿个也不准备说这些类型的页，我们聚焦的是那些存放我们表中记录的那种类型的页，官方称这种存放记录的页为 &lt;strong>&lt;code>索引（ INDEX ）页&lt;/code>&lt;/strong> ，鉴于我们还没有了解过索引是个什么东西，而这些表中的记录就是我们日常口中所称的数据 ，所以目前还是叫这种存放记录的页为 &lt;strong>数据页&lt;/strong> 吧。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="数据页结构的快速预览">
 数据页结构的快速预览
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e9%a1%b5%e7%bb%93%e6%9e%84%e7%9a%84%e5%bf%ab%e9%80%9f%e9%a2%84%e8%a7%88">#&lt;/a>
&lt;/h2> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 40%; width: 40%;">
&lt;p class="warn">数据页代表的这块 16KB 大小的存储空间可以被划分为多个部分，不同部分有不同的功能，各个部分如图所示：&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/05_innodb_page_struct/ips-01.png" alt="" width="65%">&lt;/p>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 60%; width: 60%;">
&lt;p class="warn">从图中可以看出，一个 InnoDB 数据页的存储空间大致被划分成了 7 个部分，有的部分占用的字节数是确定的，有的部分占用的字节数是不确定的。下边我们用表格的方式来大致描述一下这7个部分都存储一些啥内容（快速的瞅一眼就行了，后边会详细唠叨的）：&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/05_innodb_page_struct/ips-02.png" alt="" width="100%">&lt;/p>&lt;/div>&lt;/div>

&lt;/li>
&lt;li>
&lt;h2 id="记录在页中的存储">
 记录在页中的存储
 &lt;a class="anchor" href="#%e8%ae%b0%e5%bd%95%e5%9c%a8%e9%a1%b5%e4%b8%ad%e7%9a%84%e5%ad%98%e5%82%a8">#&lt;/a>
&lt;/h2>
&lt;p class="warn">在页的7个组成部分中，我们自己存储的记录会按照我们指定的 &lt;strong>行格式&lt;/strong> 存储到 User Records 部分。但是在一开始生成页的时候，其实并没有 User Records 这个部分，每当我们插入一条记录，都会从 Free Space 部分，也就是尚未使用的存储空间中申请一个记录大小的空间划分到 User Records 部分，当 Free Space 部分的空间全部被 User Records 部分替代掉之后，也就意味着这个页使用完了，如果还有新的记录插入的话，就需要去申请新的页了，这个过程的图示如下：&lt;/p>
&lt;p style="text-align: center;">&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/05_innodb_page_struct/ips-03.png" alt="" width="90%">&lt;/p>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/06_B+tree_index/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/06_B+tree_index/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="前情提要">
 前情提要
 &lt;a class="anchor" href="#%e5%89%8d%e6%83%85%e6%8f%90%e8%a6%81">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> prerequirement &lt;/p>&lt;p> 前边我们详细唠叨了 InnoDB 数据页的 7 个组成部分，知道了各个数据页可以组成一个 &lt;em>双向链表&lt;/em> ，而每个数据页中的记录会按照主键值从小到大的顺序组成一个 &lt;em>单向链表&lt;/em> ，每个数据页都会为存储在它里边儿的记录生成一个 


 
 

 
 
 
 
 
 
 
 &lt;a href='../05_innodb-page-struct/#page-directory%e9%a1%b5%e7%9b%ae%e5%bd%95' rel="noopener" class="internal-link" data-src="../05_innodb-page-struct/#page-directory%e9%a1%b5%e7%9b%ae%e5%bd%95">页目录&lt;/a> ，在&lt;code>单页&lt;/code>中通过主键查找某条记录的时候可以 &lt;strong>页目录(page-directory)&lt;/strong> 中使用二分法快速定位到对应的槽，然后再遍历该槽对应分组中的记录即可快速找到指定的记录（如果你对这段话有一丁点儿疑惑，那么接下来的部分不适合你，返回去看一下 


 
 

 
 
 
 
 
 
 
 &lt;a href='../05_innodb-page-struct/#%e6%95%b0%e6%8d%ae%e9%a1%b5%e7%bb%93%e6%9e%84%e7%9a%84%e5%bf%ab%e9%80%9f%e9%a2%84%e8%a7%88' rel="noopener" class="internal-link" data-src="../05_innodb-page-struct/#%e6%95%b0%e6%8d%ae%e9%a1%b5%e7%bb%93%e6%9e%84%e7%9a%84%e5%bf%ab%e9%80%9f%e9%a2%84%e8%a7%88">数据页结构&lt;/a> 吧）。页和记录的关系示意图如下：
&lt;br>&lt;br>其中页a、页b、页c &amp;hellip; 页n 这些页可以不在物理结构上相连，只要通过双向链表相关联即可。&lt;/p>
&lt;/p>&lt;/div>
&lt;p style="text-align: center;">&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/06_B+tree_index/bti-01.png" alt="" width="90%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="没有索引的查找">
 没有索引的查找
 &lt;a class="anchor" href="#%e6%b2%a1%e6%9c%89%e7%b4%a2%e5%bc%95%e7%9a%84%e6%9f%a5%e6%89%be">#&lt;/a>
&lt;/h2>
&lt;p class="warn">本集的主题是 &lt;strong>索引&lt;/strong>，在正式介绍 索引 之前，我们需要了解一下没有索引的时候是怎么查找记录的。为了方便大家理解，我们下边先只唠叨搜索条件为对某个列精确匹配的情况，所谓精确匹配，就是搜索条件中用等于 = 连接起的表达式，比如这样：
&lt;br>&lt;code>SELECT [列名列表] FROM 表名 WHERE 列名 = xxx;&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="在一个页中的查找">
 在一个页中的查找
 &lt;a class="anchor" href="#%e5%9c%a8%e4%b8%80%e4%b8%aa%e9%a1%b5%e4%b8%ad%e7%9a%84%e6%9f%a5%e6%89%be">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p>假设目前表中的记录比较少，所有的记录都可以被存放到一个页中，在查找记录的时候可以根据搜索条件的不同分为两种情况：
&lt;br>&lt;span style='padding-left:2.0em'>1. &lt;code>以主键为搜索条件&lt;/code>: 这个查找过程我们已经很熟悉了，可以在 页目录 中使用二分法快速定位到对应的槽，然后再遍历该槽对应分组中的记录即可快速找到指定的记录。
&lt;br>&lt;span style='padding-left:2.0em'>2. &lt;code>以其他列作为搜索条件&lt;/code>: 对非主键列的查找的过程可就不这么幸运了，因为在数据页中并没有对非主键列建立所谓的 页目录 ，所以我们无法通过二分法快速定位相应的 槽 。这种情况下只能从 最小记录 开始依次遍历单链表中的每条记录，然后对比每条记录是不是符合搜索条件。很显然，这种查找的效率是非常低的。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="在很多页中查找">
 在很多页中查找
 &lt;a class="anchor" href="#%e5%9c%a8%e5%be%88%e5%a4%9a%e9%a1%b5%e4%b8%ad%e6%9f%a5%e6%89%be">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/07_B+tree_index_use/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/07_B+tree_index_use/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="书接上文">
 书接上文
 &lt;a class="anchor" href="#%e4%b9%a6%e6%8e%a5%e4%b8%8a%e6%96%87">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> prerequirement &lt;/p>&lt;p> 我们前边详细、详细又详细的唠叨了 


 
 

 
 
 
 
 
 
 
 &lt;a href='../06_B&amp;#43;tree_index/' rel="noopener" class="internal-link" data-src="../06_B&amp;#43;tree_index/">InnoDB 存储引擎的 B+ 树索引&lt;/a>，我们必须熟悉下边这些结论：
&lt;br>&lt;code>1).&lt;/code> 每个索引都对应一棵 B+ 树，B+ 树分为好多层，最下边一层是叶子节点，其余的是内节点。所有&lt;strong>用户记录&lt;/strong>都存储在 B+ 树的叶子节点，所有&lt;strong>目录项记录&lt;/strong>都存储在内节点。
&lt;br>&lt;code>2).&lt;/code> InnoDB 存储引擎会自动为主键（如果没有它会自动帮我们添加）建立 


 
 

 
 
 
 
 
 
 
 &lt;a href='../06_B&amp;#43;tree_index/#%e8%81%9a%e7%b0%87%e7%b4%a2%e5%bc%95' rel="noopener" class="internal-link" data-src="../06_B&amp;#43;tree_index/#%e8%81%9a%e7%b0%87%e7%b4%a2%e5%bc%95">聚簇索引&lt;/a>，聚簇索引的叶子节点包含完整的用户记录。
&lt;br>&lt;code>3).&lt;/code> 我们可以为自己感兴趣的列建立 


 
 

 
 
 
 
 
 
 
 &lt;a href='../06_B&amp;#43;tree_index/#%e4%ba%8c%e7%ba%a7%e7%b4%a2%e5%bc%95%e8%be%85%e5%8a%a9%e7%b4%a2%e5%bc%95' rel="noopener" class="internal-link" data-src="../06_B&amp;#43;tree_index/#%e4%ba%8c%e7%ba%a7%e7%b4%a2%e5%bc%95%e8%be%85%e5%8a%a9%e7%b4%a2%e5%bc%95">二级索引&lt;/a>，二级索引的叶子节点包含的用户记录由&lt;strong>索引列+主键&lt;/strong>组成，所以如果想通过&lt;strong>二级索引&lt;/strong>来查找完整的用户记录的话，需要通过 


 
 

 
 
 
 
 
 
 
 &lt;a href='../06_B&amp;#43;tree_index/#:~:text=%e6%88%91%e4%bb%ac%e6%a0%b9%e6%8d%ae%e8%bf%99%e4%b8%aa%e4%bb%a5,%e8%a2%ab%e7%a7%b0%e4%b8%ba%e5%9b%9e%e8%a1%a8' rel="noopener" class="internal-link" data-src="../06_B&amp;#43;tree_index/#:~:text=%e6%88%91%e4%bb%ac%e6%a0%b9%e6%8d%ae%e8%bf%99%e4%b8%aa%e4%bb%a5,%e8%a2%ab%e7%a7%b0%e4%b8%ba%e5%9b%9e%e8%a1%a8">回表&lt;/a> 操作，也就是在通过二级索引找到主键值之后再到&lt;strong>聚簇索引&lt;/strong>中查找完整的用户记录。
&lt;br>&lt;code>4).&lt;/code> B+ 树中每层节点都是按照索引列值从小到大的顺序排序而组成了双向链表，而且每个页内的记录（不论是用户记录还是目录项记录）都是按照索引列的值从小到大的顺序而形成了一个单链表。如果是 


 
 

 
 
 
 
 
 
 
 &lt;a href='../06_B&amp;#43;tree_index/#%e8%81%94%e5%90%88%e7%b4%a2%e5%bc%95' rel="noopener" class="internal-link" data-src="../06_B&amp;#43;tree_index/#%e8%81%94%e5%90%88%e7%b4%a2%e5%bc%95">联合索引&lt;/a> 的话，则页面和记录先按照&lt;strong>联合索引&lt;/strong>前边的列排序，如果该列值相同，再按照&lt;strong>联合索引&lt;/strong>后边的列排序。
&lt;br>&lt;code>5).&lt;/code> 通过索引查找记录是从 B+ 树的根节点开始，一层一层向下搜索。由于每个页面都按照索引列的值建立了 


 
 

 
 
 
 
 
 
 
 &lt;a href='../05_innodb-page-struct/#page-directory%e9%a1%b5%e7%9b%ae%e5%bd%95' rel="noopener" class="internal-link" data-src="../05_innodb-page-struct/#page-directory%e9%a1%b5%e7%9b%ae%e5%bd%95">Page Directory（页目录）&lt;/a>，所以在这些页面中的查找非常快。
&lt;br>&lt;br>如果你读上边的几点结论有些任何一点点疑惑的话，那下边的内容不适合你，回过头先去看前边的内容去。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="索引的代价">
 索引的代价
 &lt;a class="anchor" href="#%e7%b4%a2%e5%bc%95%e7%9a%84%e4%bb%a3%e4%bb%b7">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> 在熟悉了 B+ 树索引原理之后，本篇文章的主题是唠叨如何更好的使用索引，虽然索引是个好东西，可不能乱建，在介绍如何更好的使用索引之前先要了解一下使用这玩意儿的代价，它在空间和时间上都会拖后腿：
&lt;br>&lt;code>空间上的代价&lt;/code>：这个是显而易见的，每建立一个索引都要为它建立一棵 B+ 树，每一棵 B+ 树的每一个节点都是一个数据页，一个页默认会占用 16KB 的存储空间，一棵很大的 B+ 树由许多数据页组成，那可是很大的一片存储空间呢。
&lt;br>&lt;code>时间上的代价&lt;/code>：每次对表中的数据进行增、删、改操作时，都需要去修改各个 B+ 树索引。而且我们讲过， B+ 树每层节点都是按照索引列的值从小到大的顺序排序而组成了双向链表。不论是叶子节点中的记录，还是内节点中的记录（也就是不论是用户记录还是目录项记录）都是按照索引列的值从小到大的顺序而形成了一个单向链表。而增、删、改操作可能会对节点和记录的排序造成破坏，所以存储引擎需要额外的时间进行一些记录移位，页面分裂、页面回收啥的操作来维护好节点和记录的排序。如果我们建了许多索引，每个索引对应的 B+ 树都要进行相关的维护操作，这还能不给性能拖后腿么？
&lt;br>&lt;br>所以说，一个表上索引建的越多，就会占用越多的存储空间，在增删改记录的时候性能就越差。为了能建立又好又少的索引，我们先得学学这些索引在哪些条件下起作用的。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/08_data_home_with_datadir/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/08_data_home_with_datadir/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="数据库和文件系统的关系">
 数据库和文件系统的关系
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%92%8c%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%9a%84%e5%85%b3%e7%b3%bb">#&lt;/a>
&lt;/h2>
&lt;p class="warn">我们知道像 InnoDB 、 MyISAM 这样的存储引擎都是把表存储在磁盘上的，而操作系统用来管理磁盘的那个东东又被称为 &lt;strong>文件系统&lt;/strong> ，所以用专业一点的话来表述就是：&lt;span style='color: blue'>像 InnoDB 、 MyISAM 这样的存储引擎都是把表存储在文件系统上的&lt;/span>。当我们想读取数据的时候，这些存储引擎会从文件系统中把数据读出来返回给我们，当我们想写入数据的时候，这些存储引擎会把这些数据又写回文件系统。本章就是要唠叨一下 InnoDB 和 MyISAM 这两个存储引擎的数据如何在文件系统中存储的。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="mysql数据目录">
 MySQL数据目录
 &lt;a class="anchor" href="#mysql%e6%95%b0%e6%8d%ae%e7%9b%ae%e5%bd%95">#&lt;/a>
&lt;/h2>
&lt;p class="warn">MySQL服务器程序在启动时会到文件系统的某个目录下加载一些文件，之后在运行过程中产生的数据也都会存储到这个目录下的某些文件中，这个目录就称为 数据目录 ，我们下边就要详细唠唠这个目录下具体都有哪些重要的东西。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="数据目录和安装目录的区别">
 数据目录和安装目录的区别
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e7%9b%ae%e5%bd%95%e5%92%8c%e5%ae%89%e8%a3%85%e7%9b%ae%e5%bd%95%e7%9a%84%e5%8c%ba%e5%88%ab">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 我们之前只接触过 MySQL 的安装目录（在安装 MySQL 的时候我们可以自己指定），我们重点强调过这个 安装目录 下非常重要的 bin 目录，它里边存储了许多关于控制客户端程序和服务器程序的命令（许多可执行文件，比如 mysql ， mysqld ， mysqld_safe 等等等等好几十个）。而 数据目录 是用来存储 MySQL 在运行过程中产生的数据，一定要和本章要讨论的 安装目录 区别开！&lt;span style='color: blue'>一定要区分开！一定要区分开！一定要区分开&lt;/span>！&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="如何确定mysql中的数据目录">
 如何确定MySQL中的数据目录
 &lt;a class="anchor" href="#%e5%a6%82%e4%bd%95%e7%a1%ae%e5%ae%9amysql%e4%b8%ad%e7%9a%84%e6%95%b0%e6%8d%ae%e7%9b%ae%e5%bd%95">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> 那说了半天，到底 MySQL 把数据都存到哪个路径下呢？其实 数据目录 对应着一个系统变量 &lt;strong>datadir&lt;/strong> ，我们在使用客户端与服务器建立连接之后查看这个系统变量的值就可以了：
&lt;br>&lt;code>show variables like 'datadir';&lt;/code>
&lt;br>&lt;br>从结果中可以看出，&lt;strong>在我的计算机上&lt;/strong>MySQL 的数据目录就是&lt;code>/data/mysql/&lt;/code>，你用你的计算机试试呗～&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/09_innodb_table-space/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/09_innodb_table-space/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="书接上文">
 书接上文
 &lt;a class="anchor" href="#%e4%b9%a6%e6%8e%a5%e4%b8%8a%e6%96%87">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> prerequirement &lt;/p>&lt;p> 通过前边儿的内容大家知道， 


 
 

 
 
 
 
 
 
 
 &lt;a href='../08_data_home_with_datadir/#:~:text=%e4%b8%ba%e4%ba%86%e6%9b%b4%e5%a5%bd%e7%9a%84%e7%ae%a1%e7%90%86%e8%bf%99%e4%ba%9b%e9%a1%b5,%e7%9a%84%e6%a6%82%e5%bf%b5' rel="noopener" class="internal-link" data-src="../08_data_home_with_datadir/#:~:text=%e4%b8%ba%e4%ba%86%e6%9b%b4%e5%a5%bd%e7%9a%84%e7%ae%a1%e7%90%86%e8%bf%99%e4%ba%9b%e9%a1%b5,%e7%9a%84%e6%a6%82%e5%bf%b5">表空间&lt;/a> 是一个抽象的概念，对于 


 
 

 
 
 
 
 
 
 
 &lt;a href='../08_data_home_with_datadir/#%e7%b3%bb%e7%bb%9f%e8%a1%a8%e7%a9%ba%e9%97%b4system-tablespace' rel="noopener" class="internal-link" data-src="../08_data_home_with_datadir/#%e7%b3%bb%e7%bb%9f%e8%a1%a8%e7%a9%ba%e9%97%b4system-tablespace">系统表空间&lt;/a> 来说，对应着文件系统中一个或多个实际文件；对于每个 


 
 

 
 
 
 
 
 
 
 &lt;a href='../08_data_home_with_datadir/#%e7%8b%ac%e7%ab%8b%e8%a1%a8%e7%a9%ba%e9%97%b4file-per-table-tablespace' rel="noopener" class="internal-link" data-src="../08_data_home_with_datadir/#%e7%8b%ac%e7%ab%8b%e8%a1%a8%e7%a9%ba%e9%97%b4file-per-table-tablespace">独立表空间&lt;/a> 来说，对应着文件系统中一个名为 表名.ibd 的实际文件。大家可以把表空间想象成被切分为许许多多个 &lt;strong>页&lt;/strong> 的池子，当我们想为某个表插入一条记录的时候，就从池子中捞出一个对应的页来把数据写进去。本章内容会深入到表空间的各个细节中，带领大家在 InnoDB 存储结构的池子中畅游。由于本章中将会涉及比较多的概念，虽然这些概念都不难，但是却相互依赖，所以奉劝大家在看的时候：&lt;span style='color:blue'>不要跳着看! 不要跳着看! 不要跳着看!&lt;/span>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="回忆一些旧知识">
 回忆一些旧知识
 &lt;a class="anchor" href="#%e5%9b%9e%e5%bf%86%e4%b8%80%e4%ba%9b%e6%97%a7%e7%9f%a5%e8%af%86">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="页面类型">
 页面类型
 &lt;a class="anchor" href="#%e9%a1%b5%e9%9d%a2%e7%b1%bb%e5%9e%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn">再一次强调，InnoDB是以页为单位管理存储空间的，我们的聚簇索引（也就是完整的表数据）和其他的二级索引都是以 B+ 树的形式保存到表空间的，而 B+ 树的节点就是数据页。我们前边说过，这个数据页的类型名其实是： FIL_PAGE_INDEX ，除了这种存放索引数据的页面类型之外，InnoDB也为了不同的目的设计了若干种不同类型的页面，为了唤醒大家的记忆，我们再一次把各种常用的页面类型提出来：
&lt;br>&lt;br>因为页面类型前边都有个 FIL_PAGE 或者 FIL_PAGE_TYPE 的前缀，为简便起见我们后边唠叨页面类型的时候就把这些前缀省略掉了，比方说 FIL_PAGE_TYPE_ALLOCATED 类型称为 ALLOCATED 类型， FIL_PAGE_INDEX 类型称为INDEX 类型。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">类型名称&lt;/th>
&lt;th align="center">十六进制&lt;/th>
&lt;th align="center">描述&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_ALLOCATED&lt;/td>
&lt;td align="center">0x0000&lt;/td>
&lt;td align="center">最新分配，还没使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_UNDO_LOG&lt;/td>
&lt;td align="center">0x0002&lt;/td>
&lt;td align="center">Undo日志页&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_INODE&lt;/td>
&lt;td align="center">0x0003&lt;/td>
&lt;td align="center">段信息节点&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_IBUF_FREE_LIST&lt;/td>
&lt;td align="center">0x0004&lt;/td>
&lt;td align="center">Insert Buffer空闲列表&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_IBUF_BITMAP&lt;/td>
&lt;td align="center">0x0005&lt;/td>
&lt;td align="center">Insert Buffer位图&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_SYS&lt;/td>
&lt;td align="center">0x0006&lt;/td>
&lt;td align="center">系统页&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_TRX_SYS&lt;/td>
&lt;td align="center">0x0007&lt;/td>
&lt;td align="center">事务系统数据&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_FSP_HDR&lt;/td>
&lt;td align="center">0x0008&lt;/td>
&lt;td align="center">表空间头部信息&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_XDES&lt;/td>
&lt;td align="center">0x0009&lt;/td>
&lt;td align="center">扩展描述页&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_TYPE_BLOB&lt;/td>
&lt;td align="center">0x000A&lt;/td>
&lt;td align="center">BLOB页&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">FIL_PAGE_INDEX&lt;/td>
&lt;td align="center">0x45BF&lt;/td>
&lt;td align="center">索引页，也就是我们所说的 数据页&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="页面通用部分">
 页面通用部分
 &lt;a class="anchor" href="#%e9%a1%b5%e9%9d%a2%e9%80%9a%e7%94%a8%e9%83%a8%e5%88%86">#&lt;/a>
&lt;/h3>
&lt;p class="warn">我们前边说过数据页，也就是 INDEX 类型的页由7个部分组成，其中的两个部分是所有类型的页面都通用的。当然我不能寄希望于你把我说的话都记住，所以在这里重新强调一遍，任何类型的页面都有下边这种通用的结构：
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/09_innodb_table_space/its-01.png" alt="" width="60%">
&lt;br>从上图中可以看出，任何类型的页都会包含这两个部分：
&lt;br>&lt;code>1).&lt;/code> File Header ：记录页面的一些通用信息
&lt;br>&lt;code>2).&lt;/code> File Trailer ：校验页是否完整，保证从内存到磁盘刷新时内容的一致性。
&lt;br>&lt;br>对于 File Trailer 我们不再做过多强调，全部忘记了的话可以到将数据页的那一章回顾一下。我们这里再强调一遍 File Header 的各个组成部分：&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/10_single-table-access/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/10_single-table-access/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="开场序言">
 开场序言
 &lt;a class="anchor" href="#%e5%bc%80%e5%9c%ba%e5%ba%8f%e8%a8%80">#&lt;/a>
&lt;/h2>
&lt;div class="alert flat note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 对于我们这些 MySQL 的使用者来说， MySQL 其实就是一个软件，平时用的最多的就是查询功能。DBA 时不时丢过来一些慢查询语句让优化，我们如果连查询是怎么执行的都不清楚还优化个毛线，所以是时候掌握真正的技术了。我们在第一章的时候就曾说过， MySQL Server 有一个称为 &lt;strong>查询优化器&lt;/strong> 的模块，一条查询语句进行语法解析之后就会被交给查询优化器来进行优化，优化的结果就是生成一个所谓的 &lt;strong>执行计划&lt;/strong> ，这个执行计划表明了应该使用哪些索引进行查询，表之间的连接顺序是啥样的，最后会按照执行计划中的步骤调用存储引擎提供的方法来真正的执行查询，并将查询结果返回给用户。不过查询优化这个主题有点儿大，在学会跑之前还得先学会走，所以本章先来瞅瞅 MySQL 怎么执行单表查询（就是 FROM 子句后边只有一个表，最简单的那种查询～）。不过需要强调的一点是，在学习本章前务必看过前边关于记录结构、数据页结构以及索引的部分，如果你不能保证这些东西已经完全掌握，那么本章不适合你。
&lt;br>&lt;br>为了故事的顺利发展，我们先得建个如下的表：
&lt;br>我们为这个 &lt;em>single_table&lt;/em> 表建立了1个聚簇索引和4个二级索引，分别是：
&lt;br>&lt;span style='padding-left:2em'>&lt;code>1.&lt;/code> 为 id 列建立的聚簇索引。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>2.&lt;/code> 为 key1 列建立的 idx_key1 二级索引。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>3.&lt;/code> 为 key2 列建立的 idx_key2 二级索引，而且该索引是唯一二级索引。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>4.&lt;/code> 为 key3 列建立的 idx_key3 二级索引。
&lt;br>&lt;span style='padding-left:2em'>&lt;code>5.&lt;/code> 为 key_part1 、 key_part2 、 key_part3 列建立的 idx_key_part 二级索引，这也是一个联合索引。
&lt;br>&lt;br>然后我们需要为这个表插入10000行记录，除 id 列外其余的列都插入随机值就好了，具体的插入语句我就不写了，自己写个程序插入吧（id列是自增主键列，不需要我们手动插入）。&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">CREATE TABLE single_table (
 id INT NOT NULL AUTO_INCREMENT,
 key1 VARCHAR(100),
 key2 INT,
 key3 VARCHAR(100),
 key_part1 VARCHAR(100),
 key_part2 VARCHAR(100),
 key_part3 VARCHAR(100),
 common_field VARCHAR(100),
 PRIMARY KEY (id),
 KEY idx_key1 (key1),
 UNIQUE KEY idx_key2 (key2),
 KEY idx_key3 (key3),
 KEY idx_key_part(key_part1, key_part2, key_part3)
) Engine=InnoDB CHARSET=utf8;
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="访问方法access-method的概念">
 访问方法（access method）的概念
 &lt;a class="anchor" href="#%e8%ae%bf%e9%97%ae%e6%96%b9%e6%b3%95access-method%e7%9a%84%e6%a6%82%e5%bf%b5">#&lt;/a>
&lt;/h2>
&lt;p class="warn">想必各位都用过高德地图来查找到某个地方的路线吧（此处没有为高德地图打广告的意思，他们没给我钱，大家用百度地图也可以啊），如果我们搜西安钟楼到大雁塔之间的路线的话，地图软件会给出n种路线供我们选择，如果我们实在闲的没事儿干并且足够有钱的话，还可以用南辕北辙的方式绕地球一圈到达目的地。也就是说，不论采用哪一种方式，我们最终的目标就是到达大雁塔这个地方。回到 MySQL 中来，我们平时所写的那些查询语句本质上只是一种声明式的语法，只是告诉 MySQL 我们要获取的数据符合哪些规则，至于 MySQL 背地里是怎么把查询结果搞出来的那是 MySQL 自己的事儿。对于单个表的查询来说，设计MySQL的大叔把查询的执行方式大致分为下边两种：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>使用全表扫描进行查询&lt;/code>: 这种执行方式很好理解，就是把表的每一行记录都扫一遍嘛，把符合搜索条件的记录加入到结果集就完了。不管是啥查询都可以使用这种方式执行，当然，这种也是最笨的执行方式。
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>使用索引进行查询&lt;/code>: 因为直接使用全表扫描的方式执行查询要遍历好多记录，所以代价可能太大了。如果查询语句中的搜索条件可以使用到某个索引，那直接使用索引来执行查询可能会加快查询执行的时间。使用索引来执行查询的方式五花八门，又可以细分为许多种类：
&lt;br>&lt;span style='padding-left:3em'>&lt;code>1.&lt;/code> 针对主键或唯一二级索引的等值查询
&lt;br>&lt;span style='padding-left:3em'>&lt;code>2.&lt;/code> 针对普通二级索引的等值查询
&lt;br>&lt;span style='padding-left:3em'>&lt;code>3.&lt;/code> 针对索引列的范围查询
&lt;br>&lt;span style='padding-left:3em'>&lt;code>4.&lt;/code> 直接扫描整个索引
&lt;br>&lt;br>设计 MySQL 的大叔把 MySQL 执行查询语句的方式称之为 &lt;strong>访问方法&lt;/strong> 或者 &lt;strong>访问类型&lt;/strong> 。同一个查询语句可能可以使用多种不同的访问方法来执行，虽然最后的查询结果都是一样的，但是执行的时间可能差老鼻子远了，就像是从钟楼到大雁塔，你可以坐火箭去，也可以坐飞机去，当然也可以坐乌龟去。下边细细道来各种 访问方法 的具体内容。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/11_multi-table-join/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/11_multi-table-join/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="开场序言">
 开场序言
 &lt;a class="anchor" href="#%e5%bc%80%e5%9c%ba%e5%ba%8f%e8%a8%80">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 搞数据库一个避不开的概念就是 Join ，翻译成中文就是 连接 。相信很多小伙伴在初学连接的时候有些一脸懵逼，理解了连接的语义之后又可能不明白各个表中的记录到底是怎么连起来的，以至于在使用的时候常常陷入下边两种误区：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>误区一&lt;/code>：业务至上，管他三七二十一，再复杂的查询也用在一个连接语句中搞定。
&lt;br>&lt;span style='padding-left:1.2em'>&lt;code>误区二&lt;/code>：敬而远之，上次 DBA 那给报过来的慢查询就是因为使用了连接导致的，以后再也不敢用了。
&lt;br>所以本章就来扒一扒连接的原理。考虑到一部分小伙伴可能忘了连接是个啥或者压根儿就不知道，为了节省他们百度或者看其他书的宝贵时间以及为了我的书凑字数，我们先来介绍一下 MySQL 中支持的一些连接语法。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="连接简介">
 连接简介
 &lt;a class="anchor" href="#%e8%bf%9e%e6%8e%a5%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="连接的本质">
 连接的本质
 &lt;a class="anchor" href="#%e8%bf%9e%e6%8e%a5%e7%9a%84%e6%9c%ac%e8%b4%a8">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">create schema multi_table_join collate utf8mb4_general_ci;
use multi_table_join;

CREATE TABLE t1 (m1 int, n1 char(1));
CREATE TABLE t2 (m2 int, n2 char(1));
INSERT INTO t1 VALUES(1, 'a'), (2, 'b'), (3, 'c');
INSERT INTO t2 VALUES(2, 'b'), (3, 'c'), (4, 'd');
&lt;/code>&lt;/pre>&lt;/div>
&lt;p class="warn"> 为了故事的顺利发展，我们先建立两个简单的表并给它们填充一点数据：
&lt;br>&lt;br>我们成功建立了 t1 、 t2 两个表，这两个表都有两个列，一个是 INT 类型的，一个是 CHAR(1) 类型的，填充好数据的两个表长这样：
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/11_multi-table-join/mtj-01.png" alt="" width="60%">
&lt;br>&lt;strong>连接&lt;/strong> 的本质就是把各个连接表中的记录都取出来依次匹配的组合加入结果集并返回给用户。所以我们把 t1 和 t2 两个表连接起来的过程如下左所示：
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/11_multi-table-join/mtj-02.png" alt="" width="60%"> &lt;span style='padding-left:1em'/>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/11_multi-table-join/mtj-03.png" alt="" width="20%">
&lt;br>&lt;br>这个过程看起来就是把 t1 表的记录和 t2 的记录连起来组成新的更大的记录，所以这个查询过程称之为 &lt;strong>连接查询&lt;/strong>。连接查询的结果集中包含一个表中的每一条记录与另一个表中的每一条记录相互匹配的组合，像这样的结果集就可以称之为 &lt;strong>笛卡尔积&lt;/strong>。因为表 t1 中有3条记录，表 t2 中也有3条记录，所以这两个表连接之后的笛卡尔积就有 3×3=9 行记录。在 MySQL 中，连接查询的语法也很随意，只要在 FROM 语句后边跟多个表名就好了，比如我们把 t1 表和 t2 表连接起来的查询语句可以写成如上右那样。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/12_optimize-selection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/12_optimize-selection/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="什么是成本">
 什么是成本
 &lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e6%88%90%e6%9c%ac">#&lt;/a>
&lt;/h2>
&lt;p class="warn">我们之前老说 MySQL 执行一个查询可以有不同的执行方案，它会选择其中成本最低，或者说代价最低的那种方案去真正的执行查询。不过我们之前对 成本 的描述是非常模糊的，其实在 MySQL 中一条查询语句的执行成本是由下边这两个方面组成的：
&lt;br>&lt;code>1.&lt;/code>: I/O 成本
&lt;br>我们的表经常使用的 MyISAM 、 InnoDB 存储引擎都是将数据和索引都存储到磁盘上的，当我们想查询表中的记录时，需要先把数据或者索引加载到内存中然后再操作。这个从磁盘到内存这个加载的过程损耗的时间称之为 I/O 成本。
&lt;br>&lt;br>&lt;code>2.&lt;/code>: CPU 成本
&lt;br>读取以及检测记录是否满足对应的搜索条件、对结果集进行排序等这些操作损耗的时间称之为 CPU 成本。对于 InnoDB 存储引擎来说，页是磁盘和内存之间交互的基本单位，设计 MySQL 的大叔规定读取一个页面花费的成本默认是 1.0 ，读取以及检测一条记录是否符合搜索条件的成本默认是 0.2 。 1.0 、 0.2 这些数字称之为 成本常数 ，这两个成本常数我们最常用到，其余的成本常数我们后边再说哈。&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> 小贴士 &lt;/p>&lt;p>
需要注意的是，不管读取记录时需不需要检测是否满足搜索条件，其成本都算是0.2。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="单表查询的成本">
 单表查询的成本
 &lt;a class="anchor" href="#%e5%8d%95%e8%a1%a8%e6%9f%a5%e8%af%a2%e7%9a%84%e6%88%90%e6%9c%ac">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="准备工作">
 准备工作
 &lt;a class="anchor" href="#%e5%87%86%e5%a4%87%e5%b7%a5%e4%bd%9c">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 为了故事的顺利发展，我们还得把之前用到的 &lt;code>single_table&lt;/code> 表搬来，怕大家忘了这个表长啥样，再给大家抄一遍如下：
&lt;br>还是假设这个表里边儿有 10000 条记录，除 id 列外其余的列都插入随机值。下边正式开始我们的表演。
&lt;br>&lt;br> 为了方便我们使用 python 进行插入。
&lt;br>安装依赖 &lt;code>pip install faker pymysql&lt;/code>。
&lt;br>编写代码如下执行 &lt;code>python single_table_faker.py&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/13_innodb-data-collection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/13_innodb-data-collection/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="开场序言">
 开场序言
 &lt;a class="anchor" href="#%e5%bc%80%e5%9c%ba%e5%ba%8f%e8%a8%80">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 我们前边唠叨查询成本的时候经常用到一些统计数据，比如通过 &lt;code>SHOW TABLE STATUS&lt;/code> 可以看到关于表的统计数据，通过 &lt;code>SHOW INDEX&lt;/code> 可以看到关于索引的统计数据，那么这些统计数据是怎么来的呢？它们是以什么方式收集的呢？本章将聚焦于 InnoDB 存储引擎的统计数据收集策略，看完本章大家就会明白为啥前边老说 InnoDB 的统计信息是不精确的估计值了（言下之意就是我们不打算介绍 MyISAM 存储引擎统计数据的收集和存储方式，有想了解的同学自己个儿看看文档哈）。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="两种不同的统计数据存储方式">
 两种不同的统计数据存储方式
 &lt;a class="anchor" href="#%e4%b8%a4%e7%a7%8d%e4%b8%8d%e5%90%8c%e7%9a%84%e7%bb%9f%e8%ae%a1%e6%95%b0%e6%8d%ae%e5%ad%98%e5%82%a8%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="基于磁盘的永久性统计数据">
 基于磁盘的永久性统计数据
 &lt;a class="anchor" href="#%e5%9f%ba%e4%ba%8e%e7%a3%81%e7%9b%98%e7%9a%84%e6%b0%b8%e4%b9%85%e6%80%a7%e7%bb%9f%e8%ae%a1%e6%95%b0%e6%8d%ae">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="innodb_table_stats">
 innodb_table_stats
 &lt;a class="anchor" href="#innodb_table_stats">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="n_rows统计项的收集">
 n_rows统计项的收集
 &lt;a class="anchor" href="#n_rows%e7%bb%9f%e8%ae%a1%e9%a1%b9%e7%9a%84%e6%94%b6%e9%9b%86">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="clustered_index_size和sum_of_other_index_sizes统计项的收集">
 clustered_index_size和sum_of_other_index_sizes统计项的收集
 &lt;a class="anchor" href="#clustered_index_size%e5%92%8csum_of_other_index_sizes%e7%bb%9f%e8%ae%a1%e9%a1%b9%e7%9a%84%e6%94%b6%e9%9b%86">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="innodb_index_stats">
 innodb_index_stats
 &lt;a class="anchor" href="#innodb_index_stats">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="定期更新统计数据">
 定期更新统计数据
 &lt;a class="anchor" href="#%e5%ae%9a%e6%9c%9f%e6%9b%b4%e6%96%b0%e7%bb%9f%e8%ae%a1%e6%95%b0%e6%8d%ae">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="手动更新-innodb_table_stats-和-innodb_index_stats-表">
 手动更新 innodb_table_stats 和 innodb_index_stats 表
 &lt;a class="anchor" href="#%e6%89%8b%e5%8a%a8%e6%9b%b4%e6%96%b0-innodb_table_stats-%e5%92%8c-innodb_index_stats-%e8%a1%a8">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="基于内存的非永久性统计数据">
 基于内存的非永久性统计数据
 &lt;a class="anchor" href="#%e5%9f%ba%e4%ba%8e%e5%86%85%e5%ad%98%e7%9a%84%e9%9d%9e%e6%b0%b8%e4%b9%85%e6%80%a7%e7%bb%9f%e8%ae%a1%e6%95%b0%e6%8d%ae">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="innodb_stats_method的使用">
 innodb_stats_method的使用
 &lt;a class="anchor" href="#innodb_stats_method%e7%9a%84%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="总结">
 总结
 &lt;a class="anchor" href="#%e6%80%bb%e7%bb%93">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/14_rule-based-optimization/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/14_rule-based-optimization/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="开场序言">
 开场序言
 &lt;a class="anchor" href="#%e5%bc%80%e5%9c%ba%e5%ba%8f%e8%a8%80">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 大家别忘了 MySQL 本质上是一个软件，设计 MySQL 的大叔并不能要求使用这个软件的人个个都是数据库高高手，就像我写这本书的时候并不能要求各位在学之前就会了里边儿的知识。(吐槽一下：都会了的人谁还看呢，难道是为了精神上受感化？)
&lt;br>也就是说我们无法避免某些同学写一些执行起来十分耗费性能的语句。即使是这样，设计 MySQL 的大叔还是依据一些规则，竭尽全力的把这个很糟糕的语句转换成某种可以比较高效执行的形式，这个过程也可以被称作 &lt;strong>查询重写&lt;/strong> （就是人家觉得你写的语句不好，自己再重写一遍）。本章详细唠叨一下一些比较重要的重写规则。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="条件化简">
 条件化简
 &lt;a class="anchor" href="#%e6%9d%a1%e4%bb%b6%e5%8c%96%e7%ae%80">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="移除不必要的括号">
 移除不必要的括号
 &lt;a class="anchor" href="#%e7%a7%bb%e9%99%a4%e4%b8%8d%e5%bf%85%e8%a6%81%e7%9a%84%e6%8b%ac%e5%8f%b7">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="常量传递constant_propagation">
 常量传递（constant_propagation）
 &lt;a class="anchor" href="#%e5%b8%b8%e9%87%8f%e4%bc%a0%e9%80%92constant_propagation">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="等值传递equality_propagation">
 等值传递（equality_propagation）
 &lt;a class="anchor" href="#%e7%ad%89%e5%80%bc%e4%bc%a0%e9%80%92equality_propagation">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="移除没用的条件trivial_condition_removal">
 移除没用的条件（trivial_condition_removal）
 &lt;a class="anchor" href="#%e7%a7%bb%e9%99%a4%e6%b2%a1%e7%94%a8%e7%9a%84%e6%9d%a1%e4%bb%b6trivial_condition_removal">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="表达式计算">
 表达式计算
 &lt;a class="anchor" href="#%e8%a1%a8%e8%be%be%e5%bc%8f%e8%ae%a1%e7%ae%97">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="having子句和where子句的合并">
 HAVING子句和WHERE子句的合并
 &lt;a class="anchor" href="#having%e5%ad%90%e5%8f%a5%e5%92%8cwhere%e5%ad%90%e5%8f%a5%e7%9a%84%e5%90%88%e5%b9%b6">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="常量表检测">
 常量表检测
 &lt;a class="anchor" href="#%e5%b8%b8%e9%87%8f%e8%a1%a8%e6%a3%80%e6%b5%8b">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="外连接消除">
 外连接消除
 &lt;a class="anchor" href="#%e5%a4%96%e8%bf%9e%e6%8e%a5%e6%b6%88%e9%99%a4">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="子查询优化">
 子查询优化
 &lt;a class="anchor" href="#%e5%ad%90%e6%9f%a5%e8%af%a2%e4%bc%98%e5%8c%96">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="子查询语法">
 子查询语法
 &lt;a class="anchor" href="#%e5%ad%90%e6%9f%a5%e8%af%a2%e8%af%ad%e6%b3%95">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="按返回的结果集区分子查询">
 按返回的结果集区分子查询
 &lt;a class="anchor" href="#%e6%8c%89%e8%bf%94%e5%9b%9e%e7%9a%84%e7%bb%93%e6%9e%9c%e9%9b%86%e5%8c%ba%e5%88%86%e5%ad%90%e6%9f%a5%e8%af%a2">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="按与外层查询关系来区分子查询">
 按与外层查询关系来区分子查询
 &lt;a class="anchor" href="#%e6%8c%89%e4%b8%8e%e5%a4%96%e5%b1%82%e6%9f%a5%e8%af%a2%e5%85%b3%e7%b3%bb%e6%9d%a5%e5%8c%ba%e5%88%86%e5%ad%90%e6%9f%a5%e8%af%a2">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="子查询在布尔表达式中的使用">
 子查询在布尔表达式中的使用
 &lt;a class="anchor" href="#%e5%ad%90%e6%9f%a5%e8%af%a2%e5%9c%a8%e5%b8%83%e5%b0%94%e8%a1%a8%e8%be%be%e5%bc%8f%e4%b8%ad%e7%9a%84%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="子查询语法注意事项">
 子查询语法注意事项
 &lt;a class="anchor" href="#%e5%ad%90%e6%9f%a5%e8%af%a2%e8%af%ad%e6%b3%95%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="子查询在mysql中是怎么执行的">
 子查询在MySQL中是怎么执行的
 &lt;a class="anchor" href="#%e5%ad%90%e6%9f%a5%e8%af%a2%e5%9c%a8mysql%e4%b8%ad%e6%98%af%e6%80%8e%e4%b9%88%e6%89%a7%e8%a1%8c%e7%9a%84">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="小白们眼中子查询的执行方式">
 小白们眼中子查询的执行方式
 &lt;a class="anchor" href="#%e5%b0%8f%e7%99%bd%e4%bb%ac%e7%9c%bc%e4%b8%ad%e5%ad%90%e6%9f%a5%e8%af%a2%e7%9a%84%e6%89%a7%e8%a1%8c%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="标量子查询行子查询的执行方式">
 标量子查询、行子查询的执行方式
 &lt;a class="anchor" href="#%e6%a0%87%e9%87%8f%e5%ad%90%e6%9f%a5%e8%af%a2%e8%a1%8c%e5%ad%90%e6%9f%a5%e8%af%a2%e7%9a%84%e6%89%a7%e8%a1%8c%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="in子查询优化">
 IN子查询优化
 &lt;a class="anchor" href="#in%e5%ad%90%e6%9f%a5%e8%af%a2%e4%bc%98%e5%8c%96">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="anyall子查询优化">
 ANY/ALL子查询优化
 &lt;a class="anchor" href="#anyall%e5%ad%90%e6%9f%a5%e8%af%a2%e4%bc%98%e5%8c%96">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="not-exists子查询的执行">
 [NOT] EXISTS子查询的执行
 &lt;a class="anchor" href="#not-exists%e5%ad%90%e6%9f%a5%e8%af%a2%e7%9a%84%e6%89%a7%e8%a1%8c">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;li>
&lt;h4 id="对于派生表的优化">
 对于派生表的优化
 &lt;a class="anchor" href="#%e5%af%b9%e4%ba%8e%e6%b4%be%e7%94%9f%e8%a1%a8%e7%9a%84%e4%bc%98%e5%8c%96">#&lt;/a>
&lt;/h4>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/15_explain-key-01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/15_explain-key-01/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="开场序言">
 开场序言
 &lt;a class="anchor" href="#%e5%bc%80%e5%9c%ba%e5%ba%8f%e8%a8%80">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 一条查询语句在经过 MySQL 查询优化器的各种基于成本和规则的优化会后生成一个所谓的 执行计划 ，这个执行计划展示了接下来具体执行查询的方式，比如多表连接的顺序是什么，对于每个表采用什么访问方法来具体执行查询等等。设计 MySQL 的大叔贴心的为我们提供了 &lt;strong>EXPLAIN 语句&lt;/strong> 来帮助我们查看某个查询语句的具体执行计划，本章的内容就是为了帮助大家看懂 EXPLAIN 语句的各个输出项都是干嘛使的，从而可以有针对性的提升我们查询语句的性能。
&lt;br>&lt;br>如果我们想看看某个查询的执行计划的话，可以在具体的查询语句前边加一个 EXPLAIN ，就像这样：&lt;code>EXPLAIN SELECT 1;&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/15_explain-key-01/ek-01.png" alt="" width="80%">
&lt;br>&lt;br>然后这输出的一大坨东西就是所谓的 &lt;strong>执行计划&lt;/strong> ，我的任务就是带领大家看懂这一大坨东西里边的每个列都是干啥用的，以及在这个 执行计划 的辅助下，我们应该怎样改进自己的查询语句以使查询执行起来更高效。其实除了以 SELECT 开头的查询语句，其余的 DELETE 、 INSERT 、 REPLACE 以及 UPDATE 语句前边都可以加上 EXPLAIN 这个词儿，用来查看这些语句的执行计划，不过我们这里对 SELECT 语句更感兴趣，所以后边只会以 SELECT 语句为例来描述 EXPLAIN 语句的用法。为了让大家先有一个感性的认识，我们把 EXPLAIN 语句输出的各个列的作用先大致罗列如下左：
&lt;br>&lt;br>需要注意的是，&lt;span style='color:red'>大家如果看不懂上边输出列含义，那是正常的，千万不要纠结～&lt;/span>。我在这里把它们都列出来只是为了描述一个轮廓，让大家有一个大致的印象，下边会细细道来，等会儿说完了不信你不会～ 为了故事的顺利发展，我们还是要请出我们前边已经用了n遍的 single_table 表，为了防止大家忘了，再把它的结构描述一遍 如下右：
&lt;br>&lt;br>我们仍然假设有两个和 single_table 表构造一模一样的 s1 、 s2 表，而且这两个表里边儿有10000条记录，除id列外其余的列都插入随机值。为了让大家有比较好的阅读体验，我们下边并不准备严格按照 EXPLAIN 输出列的顺序来介绍这些列分别是干嘛的，大家注意一下就好了。&lt;/p>
&lt;/p>&lt;/div> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>列名&lt;/th>
&lt;th>描述&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>id&lt;/td>
&lt;td>在一个大的查询语句中每个 SELECT 关键字都对应一个唯一的 id&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>select_type&lt;/td>
&lt;td>SELECT 关键字对应的那个查询的类型&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>table&lt;/td>
&lt;td>表名&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>partitions&lt;/td>
&lt;td>匹配的分区信息&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>type&lt;/td>
&lt;td>针对单表的访问方法&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>possible_keys&lt;/td>
&lt;td>可能用到的索引&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>key&lt;/td>
&lt;td>实际上使用的索引&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>key_len&lt;/td>
&lt;td>实际使用到的索引长度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ref&lt;/td>
&lt;td>当使用索引列等值查询时，与索引列进行等值匹配的对象信息&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>rows&lt;/td>
&lt;td>预估的需要读取的记录条数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>filtered&lt;/td>
&lt;td>某个表经过搜索条件过滤后剩余记录条数的百分比&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Extra&lt;/td>
&lt;td>一些额外的信息&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="16" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">CREATE TABLE single_table (
 id INT NOT NULL AUTO_INCREMENT,
 key1 VARCHAR(100),
 key2 INT,
 key3 VARCHAR(100),
 key_part1 VARCHAR(100),
 key_part2 VARCHAR(100),
 key_part3 VARCHAR(100),
 common_field VARCHAR(100),
 PRIMARY KEY (id),
 KEY idx_key1 (key1),
 UNIQUE KEY idx_key2 (key2),
 KEY idx_key3 (key3),
 KEY idx_key_part(key_part1, key_part2, key_part3)
) Engine=InnoDB CHARSET=utf8;
CREATE TABLE s1 LIKE single_table; insert into s1 select * from single_table; CREATE TABLE s2 LIKE single_table; insert into s2 select * from single_table;

// CREATE TABLE s1 AS SELECT * FROM single_table;

// 完整复制
-- 第一步：创建表结构
-- CREATE TABLE new_table LIKE original_table;
-- 第二步：复制数据
-- INSERT INTO new_table SELECT * FROM original_table;
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>&lt;/div>

&lt;/li>
&lt;li>
&lt;h2 id="执行计划输出中各列详解">
 执行计划输出中各列详解
 &lt;a class="anchor" href="#%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e8%be%93%e5%87%ba%e4%b8%ad%e5%90%84%e5%88%97%e8%af%a6%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="table">
 table
 &lt;a class="anchor" href="#table">#&lt;/a>
&lt;/h3>
&lt;p class="warn">不论我们的查询语句有多复杂，里边儿包含了多少个表，到最后也是需要对每个表进行单表访问的，所以设计 MySQL 的大叔规定 EXPLAIN 语句输出的每条记录都对应着某个单表的访问方法，该条记录的 table 列代表着该表的表名。所以我们看一条比较简单的查询语句：&lt;code>EXPLAIN SELECT * FROM s1;&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/15_explain-key-01/ek-02.png" alt="" width="80%">
&lt;br>&lt;br>这个查询语句只涉及对 s1 表的单表查询，所以 EXPLAIN 输出中只有一条记录，其中的 table 列的值是 s1 ，表明这条记录是用来说明对 s1 表的单表访问方法的。
&lt;br>下边我们看一下一个连接查询的执行计划：&lt;code>EXPLAIN SELECT * FROM s1 INNER JOIN s2;&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/15_explain-key-01/ek-03.png" alt="" width="99%">
&lt;br>&lt;br>可以看到这个连接查询的执行计划中有两条记录，这两条记录的 table 列分别是 s1 和 s2 ，这两条记录用来分别说明对 s1 表和 s2 表的访问方法是什么。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/16_explain-key-02/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/16_explain-key-02/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="执行计划输出中各列详解">
 执行计划输出中各列详解
 &lt;a class="anchor" href="#%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e8%be%93%e5%87%ba%e4%b8%ad%e5%90%84%e5%88%97%e8%af%a6%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;p class="warn">本章紧接着上一节的内容，继续唠叨 EXPLAIN 语句输出的各个列的意思。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="extra">
 Extra
 &lt;a class="anchor" href="#extra">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 顾名思义， Extra 列是用来说明一些额外信息的，我们可以通过这些额外信息来更准确的理解 MySQL 到底将如何执行给定的查询语句。 MySQL 提供的额外信息有好几十个，我们就不一个一个介绍了（都介绍了感觉我们的文章就跟文档差不多了～），所以我们只挑一些平时常见的或者比较重要的额外信息介绍给大家哈。&lt;/p>
&lt;/p>&lt;/div>
&lt;ul>
&lt;li>
&lt;h4 id="no-tables-used">
 No tables used
 &lt;a class="anchor" href="#no-tables-used">#&lt;/a>
&lt;/h4>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> 当查询语句的没有 FROM 子句时将会提示该额外信息，比如：
&lt;br>&lt;code>EXPLAIN SELECT 1;&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/16_explain-key-02/ek-01.png" alt="" width="80%">&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h4 id="impossible-where">
 Impossible WHERE
 &lt;a class="anchor" href="#impossible-where">#&lt;/a>
&lt;/h4>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> 查询语句的 WHERE 子句永远为 FALSE 时将会提示该额外信息，比方说：
&lt;br>&lt;code>EXPLAIN SELECT * FROM s1 WHERE 1 != 1;&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/16_explain-key-02/ek-02.png" alt="" width="80%">&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h4 id="no-matching-minmax-row">
 No matching min/max row
 &lt;a class="anchor" href="#no-matching-minmax-row">#&lt;/a>
&lt;/h4>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/17_optimizer-trace/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/17_optimizer-trace/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="一镜到底">
 一镜到底
 &lt;a class="anchor" href="#%e4%b8%80%e9%95%9c%e5%88%b0%e5%ba%95">#&lt;/a>
&lt;/h2>
&lt;p>对于 MySQL 5.6 以及之前的版本来说，查询优化器就像是一个黑盒子一样，你只能通过 EXPLAIN 语句查看到最后优化器决定使用的执行计划，却无法知道它为什么做这个决策。这对于一部分喜欢刨根问底的小伙伴来说简直是灾难：“我就觉得使用其他的执行方案比 EXPLAIN 输出的这种方案强，凭什么优化器做的决定和我想的不一样呢？”&lt;/p>
&lt;p>在 MySQL 5.6 以及之后的版本中，设计 MySQL 的大叔贴心的为这部分小伙伴提出了一个 &lt;strong>optimizer trace&lt;/strong> 的功能，这个功能可以让我们方便的查看优化器生成执行计划的整个过程，这个功能的开启与关闭由 &lt;strong>系统变量 optimizer_trace&lt;/strong> 决定，我们看一下：&lt;code>SHOW VARIABLES LIKE 'optimizer_trace';&lt;/code>
&lt;br>&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/17_optimizer-trace/ot-01.png" alt="" width="35%">&lt;/p>
&lt;p>可以看到 enabled 值为 off ，表明这个功能默认是关闭的。&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> 小贴士 &lt;/p>&lt;p> one_line 的值是控制输出格式的，如果为 on 那么所有输出都将在一行中展示，不适合人阅读，所以我们就保持其默认值为 off 吧。&lt;/p>
&lt;/p>&lt;/div>
&lt;p>如果想打开这个功能，必须首先把 enabled 的值改为 on ，就像这样：
&lt;br>&lt;code>SET optimizer_trace=&amp;quot;enabled=on&amp;quot;;&lt;/code>&lt;/p>
&lt;p>然后我们就可以输入我们想要查看优化过程的查询语句，当该查询语句执行完成后，就可以到 information_schema 数据库下的 &lt;strong>OPTIMIZER_TRACE 表&lt;/strong> 中查看完整的优化过程。这个 OPTIMIZER_TRACE 表有4个列，分别是：&lt;/p>
&lt;ol>
&lt;li>QUERY ：表示我们的查询语句。&lt;/li>
&lt;li>TRACE ：表示优化过程的JSON格式文本。&lt;/li>
&lt;li>MISSING_BYTES_BEYOND_MAX_MEM_SIZE ：由于优化过程可能会输出很多，如果超过某个限制时，多余的文本将不会被显示，这个字段展示了被忽略的文本字节数&lt;/li>
&lt;li>INSUFFICIENT_PRIVILEGES ：表示是否没有权限查看优化过程，默认值是0，只有某些特殊情况下才会是 1 ，我们暂时不关心这个字段的值。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>完整的使用 optimizer trace 功能的步骤总结如下：&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/18_buffer-pool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/18_buffer-pool/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="缓存的重要性">
 缓存的重要性
 &lt;a class="anchor" href="#%e7%bc%93%e5%ad%98%e7%9a%84%e9%87%8d%e8%a6%81%e6%80%a7">#&lt;/a>
&lt;/h2>
&lt;p class="warn">通过前边的唠叨我们知道，对于使用 InnoDB 作为存储引擎的表来说，不管是用于存储用户数据的索引（包括聚簇索引和二级索引），还是各种系统数据，都是以 &lt;strong>页&lt;/strong> 的形式存放在 &lt;strong>表空间&lt;/strong> 中的，而所谓的 &lt;strong>表空间&lt;/strong> 只不过是 InnoDB 对文件系统上一个或几个实际文件的抽象，也就是说我们的数据说到底还是存储在磁盘上的。但是各位也都知道，磁盘的速度慢的跟乌龟一样，怎么能配得上“快如风，疾如电”的 CPU 呢？所以 InnoDB 存储引擎在处理客户端的请求时，当需要访问某个页的数据时，就会把完整的页的数据全部加载到内存中，也就是说&lt;span style='color:red'>即使我们只需要访问一个页的一条记录，那也需要先把整个页的数据加载到内存中&lt;/span>。将整个页加载到内存中后就可以进行读写访问了，在进行完读写访问之后并不着急把该页对应的内存空间释放掉，而是将其 缓存 起来，这样将来有请求再次访问该页面时，就可以省去磁盘 IO 的开销了。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="innodb的buffer-pool">
 InnoDB的Buffer Pool
 &lt;a class="anchor" href="#innodb%e7%9a%84buffer-pool">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="啥是个buffer-pool">
 啥是个Buffer Pool
 &lt;a class="anchor" href="#%e5%95%a5%e6%98%af%e4%b8%aabuffer-pool">#&lt;/a>
&lt;/h3>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 设计 InnoDB 的大叔为了缓存磁盘中的页，在 MySQL 服务器启动的时候就向操作系统申请了一片连续的内存，他们给这片内存起了个名，叫做 Buffer Pool （中文名是 缓冲池 ）。那它有多大呢？这个其实看我们机器的配置，如果你是土豪，你有 512G 内存，你分配个几百 G 作为 Buffer Pool 也可以啊，当然你要是没那么有钱，设置小点也行呀～ 默认情况下 Buffer Pool 只有 128M 大小。当然如果你嫌弃这个 128M 太大或者太小，可以在启动服务器的时候配置 innodb_buffer_pool_size 参数的值，它表示 Buffer Pool 的大小，就像这样：
&lt;br>&lt;br>其中， 268435456 的单位是字节，也就是我指定 Buffer Pool 的大小为 256M 。需要注意的是， Buffer Pool 也不能太小，最小值为 5M (当小于该值时会自动设置成 5M )。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/19_transaction-intro/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/19_transaction-intro/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="事务的起源">
 事务的起源
 &lt;a class="anchor" href="#%e4%ba%8b%e5%8a%a1%e7%9a%84%e8%b5%b7%e6%ba%90">#&lt;/a>
&lt;/h2>
&lt;p class="warn">对于大部分程序员来说，他们的任务就是把现实世界的业务场景映射到数据库世界。比如银行为了存储人们的账户信息会建立一个 account 表：
&lt;br>&lt;br>狗哥和猫爷是一对好基友，他们都到银行开一个账户，他们在现实世界中拥有的资产就会体现在数据库世界的 account 表中。比如现在狗哥有 11 元，猫爷只有 2 元，那么现实中的这个情况映射到数据库的 account 表就是这样：&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 60%; width: 60%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">CREATE TABLE account (
 id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',
 name VARCHAR(100) COMMENT '客户名称',
 balance INT COMMENT '余额',
 PRIMARY KEY (id)
) Engine=InnoDB CHARSET=utf8;

-- 插入数据
INSERT INTO `account` (`id`, `name`, `balance`) VALUES (1,'狗哥',11),(2,'猫爷',2);
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 40%; width: 40%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/19_transaction-intro/ti-01.png" alt="" width="78%">&lt;/p>&lt;/div>&lt;/div>

&lt;p>在某个特定的时刻，狗哥猫爷这些家伙在银行所拥有的资产是一个特定的值，这些特定的值也可以被描述为账户在这个特定的时刻现实世界的一个状态。随着时间的流逝，狗哥和猫爷可能陆续进行向账户中存钱、取钱或者向别人转账等操作，这样他们账户中的余额就可能发生变动，&lt;span style='color:red'>每一个操作都相当于现实世界中账户的一次状态转换&lt;/span>。数据库世界作为现实世界的一个映射，自然也要进行相应的变动。不变不知道，一变吓一跳，现实世界中一些看似很简单的状态转换，映射到数据库世界却不是那么容易的。比方说有一次猫爷在赌场赌博输了钱，急忙打电话给狗哥要借10块钱，不然那些看场子的就会把自己剁了。现实世界中的狗哥走向了ATM机，输入了猫爷的账号以及10元的转账金额，然后按下确认，狗哥就拔卡走人了。对于数据库世界来说，相当于执行了下边这两条语句：&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>但是这里头有个问题，上述两条语句只执行了一条时忽然服务器断电了咋办？把狗哥的钱扣了，但是没给猫爷转过去，那猫爷还是逃脱不了被砍死的噩运～ 即使对于单独的一条语句，我们前边唠叨 Buffer Pool 时也说过，在对某个页面进行读写访问时，都会先把这个页面加载到 Buffer Pool 中，之后如果修改了某个页面，也不会立即把修改同步到磁盘，而只是把这个修改了的页面加到 Buffer Pool 的 flush链表 中，在之后的某个时间点才会刷新到磁盘。如果在将修改过的页刷新到磁盘之前系统崩溃了那岂不是猫爷还是要被砍死？或者在刷新磁盘的过程中（只刷新部分数据到磁盘上）系统奔溃了猫爷也会被砍死？怎么才能保证让可怜的猫爷不被砍死呢？其实再仔细想想，我们只是想&lt;span style='color:red'>让某些数据库操作符合现实世界中状态转换的规则&lt;/span>而已，设计数据库的大叔们仔细盘算了盘算，现实世界中状态转换的规则有好几条，待我们慢慢道来。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/20_redo-01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/20_redo-01/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="事先说明">
 事先说明
 &lt;a class="anchor" href="#%e4%ba%8b%e5%85%88%e8%af%b4%e6%98%8e">#&lt;/a>
&lt;/h2>
&lt;p class="tip">本文以及接下来的几篇文章将会频繁的使用到我们前边唠叨的 InnoDB 记录行格式、页面格式、索引原理、表空间的组成等各种基础知识，如果大家对这些东西理解的不透彻，那么阅读下边的文字可能会有些吃力，为保证您的阅读体验，请确保自己已经掌握了我前边唠叨的这些知识。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="redo日志是个啥">
 redo日志是个啥
 &lt;a class="anchor" href="#redo%e6%97%a5%e5%bf%97%e6%98%af%e4%b8%aa%e5%95%a5">#&lt;/a>
&lt;/h2>
&lt;p class="warn">我们知道 InnoDB 存储引擎是以页为单位来管理存储空间的，我们进行的增删改查操作其实本质上都是在访问页面（包括读页面、写页面、创建新页面等操作）。我们前边唠叨 Buffer Pool 的时候说过，在真正访问页面之前，需要把在磁盘上的页缓存到内存中的 Buffer Pool 之后才可以访问。但是在唠叨事务的时候又强调过一个称之为 持久性 的特性，就是说对于一个已经提交的事务，在事务提交后即使系统发生了崩溃，这个事务对数据库中所做的更改也不能丢失。但是如果我们只在内存的 Buffer Pool 中修改了页面，假设在事务提交后突然发生了某个故障，导致内存中的数据都失效了，那么这个已经提交了的事务对数据库中所做的更改也就跟着丢失了，这是我们所不能忍受的（想想ATM机已经提示狗哥转账成功，但之后由于服务器出现故障，重启之后猫爷发现自己没收到钱，猫爷就被砍死了）。那么如何保证这个 持久性 呢？一个很简单的做法就是&lt;span style='color:red'>在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘&lt;/span>，但是这个简单粗暴的做法有些问题：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;em>刷新一个完整的数据页太浪费了&lt;/em>：有时候我们仅仅修改了某个页面中的一个字节，但是我们知道在 InnoDB 中是以页为单位来进行磁盘IO的，也就是说我们在该事务提交时不得不将一个完整的页面从内存中刷新到磁盘，我们又知道一个页面默认是16KB大小，只修改一个字节就要刷新16KB的数据到磁盘上显然是太浪费了。
&lt;br>&lt;span style='padding-left:1.2em'>&lt;em>随机IO刷起来比较慢&lt;/em>：一个事务可能包含很多语句，即使是一条语句也可能修改许多页面，倒霉催的是该事务修改的这些页面可能并不相邻，这就意味着在将某个事务修改的 Buffer Pool 中的页面刷新到磁盘时，需要进行很多的随机IO，随机IO比顺序IO要慢，尤其对于传统的机械硬盘来说。
&lt;br>&lt;br>咋办呢？再次回到我们的初心：&lt;span style='color:red'>我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效，即使后来系统崩溃，在重启后也能把这种修改恢复出来&lt;/span>。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘，只需要&lt;span style='color:red'>把修改了哪些东西记录一下就好&lt;/span>，比方说某个事务将系统表空间中的第100 号页面中偏移量为1000处的那个字节的值 1 改成 2 我们只需要记录一下：
&lt;br>&lt;code>将第0号表空间的100号页面的偏移量为1000处的值更新为 2&lt;/code>。
&lt;br>&lt;br>这样我们在事务提交时，把上述内容刷新到磁盘中，即使之后系统崩溃了，重启之后只要按照上述内容所记录的步骤重新更新一下数据页，那么该事务对数据库中所做的修改又可以被恢复出来，也就意味着满足 持久性 的要求。因为在系统奔溃重启时需要按照上述内容所记录的步骤重新更新数据页，所以上述内容也被称之为 &lt;strong>重做日志&lt;/strong> ，英文名为 &lt;strong>redo log&lt;/strong> ，我们也可以土洋结合，称之为 &lt;strong>redo日志&lt;/strong> 。与在事务提交时将所有修改过的内存中的页面刷新到磁盘中相比，只将该事务执行过程中产生的 redo 日志刷新到磁盘的好处如下：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;em>redo 日志占用的空间非常小&lt;/em>：存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间是很小的，关于 redo 日志的格式我们稍后会详细唠叨，现在只要知道一条 redo 日志占用的空间不是很大就好了。
&lt;br>&lt;span style='padding-left:1.2em'>&lt;em>redo 日志是顺序写入磁盘的&lt;/em>：在执行事务的过程中，每执行一条语句，就可能产生若干条 redo 日志，这些日志是按照产生的顺序写入磁盘的，也就是使用顺序IO。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="redo日志格式">
 redo日志格式
 &lt;a class="anchor" href="#redo%e6%97%a5%e5%bf%97%e6%a0%bc%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;p class="warn">通过上边的内容我们知道， redo 日志本质上只是记录了一下事务对数据库做了哪些修改。 设计 InnoDB 的大叔们针对事务对数据库的不同修改场景定义了多种类型的 redo 日志，但是绝大部分类型的 redo 日志都有下边这种通用的结构：
&lt;br>&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/20_redo-01/rd-01.png" alt="" width="70%">
&lt;br>&lt;br>各个部分的详细释义如下：
&lt;br>&lt;span style='padding-left:1.2em'>type ：该条 redo 日志的类型。（在 MySQL 5.7.21 这个版本中，设计 InnoDB 的大叔一共为 redo 日志设计了53种不同的类型，稍后会详细介绍不同类型的 redo 日志。)
&lt;br>&lt;span style='padding-left:1.2em'>space ID ：表空间ID。
&lt;br>&lt;span style='padding-left:1.2em'>page number ：页号。
&lt;br>&lt;span style='padding-left:1.2em'>data ：该条 redo 日志的具体内容。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/21_redo-02/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/21_redo-02/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="redo日志文件">
 redo日志文件
 &lt;a class="anchor" href="#redo%e6%97%a5%e5%bf%97%e6%96%87%e4%bb%b6">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="redo日志刷盘时机">
 redo日志刷盘时机
 &lt;a class="anchor" href="#redo%e6%97%a5%e5%bf%97%e5%88%b7%e7%9b%98%e6%97%b6%e6%9c%ba">#&lt;/a>
&lt;/h3>
&lt;p>我们前边说 mtr 运行过程中产生的一组 redo 日志在 mtr 结束时会被复制到 log buffer 中，可是这些日志总在内存里呆着也不是个办法，在一些情况下它们会被刷新到磁盘里，比如：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>log buffer 空间不足时&lt;/p>
&lt;p>log buffer 的大小是有限的（通过系统变量 innodb_log_buffer_size 指定），如果不停的往这个有限大小的 log buffer 里塞入日志，很快它就会被填满。设计 InnoDB 的大叔认为如果当前写入 log buffer 的redo 日志量已经占满了 log buffer 总容量的大约一半左右，就需要把这些日志刷新到磁盘上。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>事务提交时&lt;/p>
&lt;p>我们前边说过之所以使用 redo 日志主要是因为它占用的空间少，还是顺序写，在事务提交时可以不把修改过的 Buffer Pool 页面刷新到磁盘，但是为了保证持久性，必须要把修改这些页面对应的 redo 日志刷新到磁盘。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>后台线程不停的刷刷刷&lt;/p>
&lt;p>后台有一个线程，大约每秒都会刷新一次 log buffer 中的 redo 日志到磁盘。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>正常关闭服务器时&lt;/p>
&lt;p>做所谓的 checkpoint 时（我们现在没介绍过 checkpoint 的概念，稍后会仔细唠叨，稍安勿躁）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>其他的一些情况&amp;hellip;&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="redo日志文件组">
 redo日志文件组
 &lt;a class="anchor" href="#redo%e6%97%a5%e5%bf%97%e6%96%87%e4%bb%b6%e7%bb%84">#&lt;/a>
&lt;/h3>
&lt;p>MySQL 的数据目录（使用 SHOW VARIABLES LIKE &amp;lsquo;datadir&amp;rsquo; 查看）下默认有两个名为 ib_logfile0 和 ib_logfile1 的文件， log buffer 中的日志默认情况下就是刷新到这两个磁盘文件中。如果我们对默认的 redo 日志文件不满意，可以通过下边几个启动参数来调节：&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/22_undo-01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/22_undo-01/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="事务回滚的需求">
 事务回滚的需求
 &lt;a class="anchor" href="#%e4%ba%8b%e5%8a%a1%e5%9b%9e%e6%bb%9a%e7%9a%84%e9%9c%80%e6%b1%82">#&lt;/a>
&lt;/h2>
&lt;p>我们说过 事务 需要保证 原子性 ，也就是事务中的操作要么全部完成，要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况，比如：&lt;/p>
&lt;ol>
&lt;li>情况一：事务执行过程中可能遇到各种错误，比如服务器本身的错误，操作系统错误，甚至是突然断电导致的错误。&lt;/li>
&lt;li>情况二：程序员可以在事务执行过程中手动输入 ROLLBACK 语句结束当前的事务的执行。&lt;/li>
&lt;/ol>
&lt;p>这两种情况都会导致事务执行到一半就结束，但是事务执行过程中可能已经修改了很多东西，为了保证事务的原子性，我们需要把东西改回原先的样子，这个过程就称之为 回滚 （英文名： rollback ），这样就可以造成一个假象：&lt;span style='color:red'>这个事务看起来什么都没做&lt;/span>，所以符合 原子性 要求。&lt;/p>
&lt;p>小时候我非常痴迷于象棋，总是想找厉害的大人下棋，赢棋是不可能赢棋的，这辈子都不可能赢棋的，又不想认输，只能偷偷的悔棋才能勉强玩的下去。 悔棋 就是一种非常典型的 回滚 操作，比如棋子往前走两步， 悔棋 对应的操作就是向后走两步；比如棋子往左走一步， 悔棋 对应的操作就是向右走一步。数据库中的回滚跟 悔棋 差不多，你插入了一条记录， 回滚 操作对应的就是把这条记录删除掉；你更新了一条记录， 回滚 操作对应的就是把该记录更新为旧值；你删除了一条记录， 回滚 操作对应的自然就是把该记录再插进去。说的貌似很简单的样子[手动偷笑😏]。&lt;/p>
&lt;p>从上边的描述中我们已经能隐约感觉到，每当我们要对一条记录做改动时（这里的 改动 可以指 INSERT 、DELETE 、 UPDATE ），都需要留一手 —— &lt;span style='color:red'>把回滚时所需的东西都给记下来&lt;/span>。比方说：&lt;/p>
&lt;ul>
&lt;li>你插入一条记录时，至少要把这条记录的主键值记下来，之后回滚的时候只需要把这个主键值对应的记录删掉就好了。&lt;/li>
&lt;li>你删除了一条记录，至少要把这条记录中的内容都记下来，这样之后回滚时再把由这些内容组成的记录插入到表中就好了。&lt;/li>
&lt;li>你修改了一条记录，至少要把修改这条记录前的旧值都记录下来，这样之后回滚时再把这条记录更新为旧值就好了。&lt;/li>
&lt;/ul>
&lt;p>设计数据库的大叔把这些为了回滚而记录的这些东东称之为撤销日志，英文名为 undo log ，我们也可以土洋结合，称之为 undo日志 。这里需要注意的一点是，由于查询操作（ SELECT ）并不会修改任何用户记录，所以在查询操作执行时，并不需要记录相应的 undo日志 。在真实的 InnoDB 中， undo日志 其实并不像我们上边所说的那么简单，不同类型的操作产生的 undo日志 的格式也是不同的，不过先暂时把这些容易让人脑子糊的具体细节放一放，我们先回过头来看看 事务id 是个神马玩意儿。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="事务id">
 事务id
 &lt;a class="anchor" href="#%e4%ba%8b%e5%8a%a1id">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="给事务分配id的时机">
 给事务分配id的时机
 &lt;a class="anchor" href="#%e7%bb%99%e4%ba%8b%e5%8a%a1%e5%88%86%e9%85%8did%e7%9a%84%e6%97%b6%e6%9c%ba">#&lt;/a>
&lt;/h3>
&lt;p>我们前边在唠叨 事务简介 时说过，一个事务可以是一个只读事务，或者是一个读写事务：&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/23_undo-02/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/23_undo-02/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="书接上文">
 书接上文
 &lt;a class="anchor" href="#%e4%b9%a6%e6%8e%a5%e4%b8%8a%e6%96%87">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> prerequirement &lt;/p>&lt;p> 上一章我们主要唠叨了为什么需要 &lt;strong>undo日志&lt;/strong> ，以及 INSERT 、 DELETE 、 UPDATE 这些会对数据做改动的语句都会产生什么类型的 undo日志 ，还有不同类型的 undo日志 的具体格式是什么。本章会继续唠叨这些 undo日志 会被具体写到什么地方，以及在写入过程中需要注意的一些问题。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="通用链表结构">
 通用链表结构
 &lt;a class="anchor" href="#%e9%80%9a%e7%94%a8%e9%93%be%e8%a1%a8%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;p>在写入 undo日志 的过程中会使用到多个链表，很多链表都有同样的节点结构，如图所示：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/23_undo-02/ud-01.png" alt="" width="60%">&lt;/p>
&lt;p>在某个表空间内，我们可以通过一个页的页号和在页内的偏移量来唯一定位一个节点的位置，这两个信息也就相当于指向这个节点的一个指针。所以：&lt;/p>
&lt;ul>
&lt;li>Pre Node Page Number 和 Pre Node Offset 的组合就是指向前一个节点的指针&lt;/li>
&lt;li>Next Node Page Number 和 Next Node Offset 的组合就是指向后一个节点的指针。&lt;/li>
&lt;/ul>
&lt;p>整个 List Node 占用 12 个字节的存储空间。&lt;/p>
&lt;p>为了更好的管理链表，设计 InnoDB 的大叔还提出了一个基节点的结构，里边存储了这个链表的 头节点 、 尾节点 以及链表长度信息，基节点的结构示意图如下：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/23_undo-02/ud-02.png" alt="" width="60%">&lt;/p>
&lt;p>其中：&lt;/p>
&lt;ul>
&lt;li>List Length 表明该链表一共有多少节点。&lt;/li>
&lt;li>First Node Page Number 和 First Node Offset 的组合就是指向链表头节点的指针。&lt;/li>
&lt;li>Last Node Page Number 和 Last Node Offset 的组合就是指向链表尾节点的指针。&lt;/li>
&lt;/ul>
&lt;p>整个 List Base Node 占用 16 个字节的存储空间。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/24_transaction-isolate-and-mvcc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/24_transaction-isolate-and-mvcc/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="事前准备">
 事前准备
 &lt;a class="anchor" href="#%e4%ba%8b%e5%89%8d%e5%87%86%e5%a4%87">#&lt;/a>
&lt;/h2>
&lt;p>为了故事的顺利发展，我们需要创建一个表：&lt;/p> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">CREATE TABLE hero (
 number INT,
 name VARCHAR(100),
 country varchar(100),
 PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8;

-- 然后向这个表里插入一条数据：
INSERT INTO hero VALUES(1, '刘备', '蜀');

-- 现在表里的数据就是这样的：
mysql&amp;gt; SELECT * FROM hero;
+--------+--------+---------+
| number | name | country |
+--------+--------+---------+
| 1 | 刘备 | 蜀 |
+--------+--------+---------+
1 row in set (0.00 sec)
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/24_transaction-isolate-and-mvcc/tiam-01.png" alt="" width="66%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/25_lock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/25_lock/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="解决并发事务带来问题的两种基本方式">
 解决并发事务带来问题的两种基本方式
 &lt;a class="anchor" href="#%e8%a7%a3%e5%86%b3%e5%b9%b6%e5%8f%91%e4%ba%8b%e5%8a%a1%e5%b8%a6%e6%9d%a5%e9%97%ae%e9%a2%98%e7%9a%84%e4%b8%a4%e7%a7%8d%e5%9f%ba%e6%9c%ac%e6%96%b9%e5%bc%8f">#&lt;/a>
&lt;/h2>
&lt;p>上一章唠叨了事务并发执行时可能带来的各种问题，并发事务访问相同记录的情况大致可以划分为3种：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>读-读 情况：即并发事务相继读取相同的记录。&lt;/p>
&lt;p>读取操作本身不会对记录有一毛钱影响，并不会引起什么问题，所以允许这种情况的发生。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>写-写 情况：即并发事务相继对相同的记录做出改动。&lt;/p>
&lt;p>我们前边说过，在这种情况下会发生 脏写 的问题，任何一种隔离级别都不允许这种问题的发生。所以在多个未提交事务相继对一条记录做改动时，需要让它们排队执行，这个排队的过程其实是通过 锁 来实现的。这个所谓的 锁 其实是一个内存中的结构，在事务执行前本来是没有锁的，也就是说一开始是没有 锁结构 和记录进行关联的，如图所示：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/25_lock/lock-01.png" alt="" width="40%">&lt;/p>
&lt;p>当一个事务想对这条记录做改动时，首先会看看内存中有没有与这条记录关联的 锁结构 ，当没有的时候就会在内存中生成一个 锁结构 与之关联。比方说事务 T1 要对这条记录做改动，就需要生成一个 锁结构 与之关联：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/25_lock/lock-02.png" alt="" width="80%">&lt;/p>
&lt;p>其实在 锁结构 里有很多信息，不过为了简化理解，我们现在只把两个比较重要的属性拿了出来：&lt;/p>
&lt;ul>
&lt;li>trx信息 ：代表这个锁结构是哪个事务生成的。&lt;/li>
&lt;li>is_waiting ：代表当前事务是否在等待。&lt;/li>
&lt;/ul>
&lt;p>如图所示，当事务 T1 改动了这条记录后，就生成了一个 锁结构 与该记录关联，因为之前没有别的事务为这条记录加锁，所以 is_waiting 属性就是 false ，我们把这个场景就称之为&lt;span style='color:red'>获取锁成功，或者加锁成功&lt;/span>，然后就可以继续执行操作了。&lt;/p>
&lt;p>在事务 T1 提交之前，另一个事务 T2 也想对该记录做改动，那么先去看看有没有 锁结构 与这条记录关联，发现有一个 锁结构 与之关联后，然后也生成了一个 锁结构 与这条记录关联，不过 锁结构 的is_waiting 属性值为 true ，表示当前事务需要等待，我们把这个场景就称之为&lt;span style='color:red'>获取锁失败，或者加锁失败，或者没有成功的获取到锁&lt;/span>，画个图表示就是这样：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/25_lock/lock-03.png" alt="" width="80%">&lt;/p>
&lt;p>在事务 T1 提交之后，就会把该事务生成的 锁结构 释放掉，然后看看还有没有别的事务在等待获取锁，发现了事务 T2 还在等待获取锁，所以把事务 T2 对应的锁结构的 is_waiting 属性设置为 false ，然后把该事务对应的线程唤醒，让它继续执行，此时事务 T2 就算获取到锁了。效果图就是这样：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/mysql/book/25_lock/lock-04.png" alt="" width="80%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/book/26_reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/book/26_reference/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="感谢">
 感谢
 &lt;a class="anchor" href="#%e6%84%9f%e8%b0%a2">#&lt;/a>
&lt;/h2>
&lt;p class="warn">我不生产知识，只是知识的搬运工。写作本小册的时间主要用在了两个方面：
&lt;br>&lt;span style='padding-left:1.2em'>&lt;strong>搞清楚事情的本质是什么&lt;/strong>。这个过程就是研究源码、书籍和资料。
&lt;br>&lt;br>&lt;span style='padding-left:1.2em'>&lt;strong>如何把我已经知道的知识表达出来&lt;/strong>。这个过程就是我不停的在地上走过来走过去，梳理知识结构，斟酌用词用句，不停的将已经写好的文章推倒重来，只是想给大家一个不错的用户体验。
&lt;br>&lt;br>这两个方面用的时间基本上是一半一半吧，在搞清楚事情的本质是什么阶段，除了直接阅读 MySQL 的源码之外，查看参考资料也是一种比较偷懒的学习方式。本书只是 MySQL 进阶的一个入门，想了解更多关于 MySQL 的知识，大家可以从下边这些资料里找点灵感。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="一些链接">
 一些链接
 &lt;a class="anchor" href="#%e4%b8%80%e4%ba%9b%e9%93%be%e6%8e%a5">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>MySQL官方文档：


 &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/" rel="noopener" target="_blank">https://dev.mysql.com/doc/refman/5.7/en/&lt;/a>&lt;/p>
&lt;p>MySQL 官方文档是写作本书时参考最多的一个资料。说实话，文档写的非常通俗易懂，唯一的缺点就是太长了，导致大家看的时候无从下手。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>MySQL Internals Manual：


 &lt;a href="https://dev.mysql.com/doc/internals/en/" rel="noopener" target="_blank">https://dev.mysql.com/doc/internals/en/&lt;/a>&lt;/p>
&lt;p>介绍MySQL如何实现各种功能的文档，写的比较好，但是太少了，有很多章节直接跳过了。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>何登成的github：


 &lt;a href="https://github.com/hedengcheng/tech" rel="noopener" target="_blank">https://github.com/hedengcheng/tech&lt;/a>&lt;/p>
&lt;p>登博的博客非常好，对事务、优化这讨论的细节也非常多，不过由于大多是PPT结构，字太少，对上下文不清楚的同学可能会一脸懵逼。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>orczhou的博客：


 &lt;a href="http://www.orczhou.com/" rel="noopener" target="_blank">http://www.orczhou.com/&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Jeremy Cole的博客：


 &lt;a href="https://blog.jcole.us/innodb/" rel="noopener" target="_blank">https://blog.jcole.us/innodb/&lt;/a>&lt;/p>
&lt;p>Jeremy Cole大神不仅写作了 innodb_ruby 这个非常棒的解析 InnoDB 存储结构的工具，还对这些存储结构写了一系列的博客，在我几乎要放弃深入研究表空间结构的时候，是他老人家的博客把我又从深渊里拉了回来。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>那海蓝蓝（李海翔）的博客：


 &lt;a href="https://blog.csdn.net/fly2nn" rel="noopener" target="_blank">https://blog.csdn.net/fly2nn&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>taobao月报：


 &lt;a href="http://mysql.taobao.org/monthly/" rel="noopener" target="_blank">http://mysql.taobao.org/monthly/&lt;/a>&lt;/p>
&lt;p>因为MySQL的源码非常多，经常让大家无从下手，而taobao月报就是一个非常好的源码阅读指南。&lt;/p>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 吐槽一下，这个taobao月报也只能当作源码阅读指南看，如果真的不看源码光看月报，那只能当作天书看，十有八九被绕进去出不来了。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>MySQL Server Blog：


 &lt;a href="http://mysqlserverteam.com/" rel="noopener" target="_blank">http://mysqlserverteam.com/&lt;/a>&lt;/p>
&lt;p>MySQL team的博客，一手资料，在我不知道看什么的时候给了很多启示。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>mysql_lover的博客：


 &lt;a href="https://blog.csdn.net/mysql_lover/" rel="noopener" target="_blank">https://blog.csdn.net/mysql_lover/&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Jørgen&amp;rsquo;s point of view：


 &lt;a href="https://jorgenloland.blogspot.com/" rel="noopener" target="_blank">https://jorgenloland.blogspot.com/&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>mariadb的关于查询优化的文档：


 &lt;a href="https://mariadb.com/kb/en/library/query-optimizations/" rel="noopener" target="_blank">https://mariadb.com/kb/en/library/query-optimizations/&lt;/a>&lt;/p>
&lt;p>不得不说mariadb的文档相比MySQL的来说就非常有艺术性了（里边儿有很多漂亮的插图），我很怀疑 MySQL 文档是程序员直接写的，mariadb的文档是产品经理写的。当我们想研究某个功能的原理，在MySQL 文档干巴巴的说明中找不到头脑时，可以参考一下 mariadb 娓娓道来的风格。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Reconstructing Data Manipulation Queries from Redo Logs：


 &lt;a href="https://www.sba-research.org/wpcontent/uploads/publications/WSDF2012_InnoDB.pdf" rel="noopener" target="_blank">https://www.sba-research.org/wpcontent/uploads/publications/WSDF2012_InnoDB.pdf&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>关于InnoDB事务的一个PPT：


 &lt;a href="https://mariadb.org/wp-content/uploads/2018/02/Deep-Dive_-InnoDBTransactions-and-Write-Paths.pdf" rel="noopener" target="_blank">https://mariadb.org/wp-content/uploads/2018/02/Deep-Dive_-InnoDBTransactions-and-Write-Paths.pdf&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>非官方优化文档：


 &lt;a href="http://www.unofficialmysqlguide.com/optimizer-trace.html" rel="noopener" target="_blank">http://www.unofficialmysqlguide.com/optimizer-trace.html&lt;/a>&lt;/p>
&lt;p>这个文档非常好，非常非常好～&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/install/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/install/</guid><description>&lt;h2 id="压缩包安装">
 压缩包安装
 &lt;a class="anchor" href="#%e5%8e%8b%e7%bc%a9%e5%8c%85%e5%ae%89%e8%a3%85">#&lt;/a>
&lt;/h2>
&lt;h6 id="centos7" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ubuntu" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="docker" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="centos7" class="docsify-tabs__tab" data-tab="Centos7">Centos7&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="centos7">
&lt;ul>
&lt;li>准备&lt;/li>
&lt;/ul>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 下载MySQL5.6.49
$ wget -c https://cdn.mysql.com/archives/mysql-5.6/mysql-5.6.49-linux-glibc2.12-x86_64.tar.gz
# 检查是否安装过mysql,如果有先卸载, 
# 用yum -y remove删除,如果有多个,一个一个执行,卸载不掉的用 rpm -ev
$ rpm -qa|grep -i mysql
# 删除所有mysql的文件夹
$ find / -name mysql|xargs rm -rf
# 卸载系统自带的Mariadb
$ rpm -qa|grep mariadb
$ rpm -ev --nodeps mariadb-libs-5.5.68-1.el7.x86_64
# 创建my.cnf 文件,或者使用原有的进行拷贝
$ cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf
# 创建mysql用户组并且创建一个用户名为mysql的用户并加入mysql用户组
$ groupadd mysql &amp;amp;&amp;amp; useradd -g mysql mysql
# 创建数据目录或者使用原有的数据目录
$ mkdir data &amp;amp;&amp;amp; mv data mysql-5.6.49/
# 移动安装文件夹到 /usr/local/ 并且重命名
$ mv mysql-5.6.49-linux-glibc2.12-x86_64 mysql-5.6.49 &amp;amp;&amp;amp; mv mysql-5.6.49 /usr/local/
# 设置目录所属组和用户
$ chown -R mysql:mysql mysql-5.6.49/
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>正式安装&lt;/li>
&lt;/ul>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 初始化
./scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql-5.6.49 --datadir=/usr/local/mysql-5.6.49/mysql_data/mysql --explicit_defaults_for_timestamp
# 自启动
$ cp ./support-files/mysql.server /etc/rc.d/init.d/mysqld
$ chmod +x /etc/rc.d/init.d/mysqld
$ chkconfig --add mysqld
$ chkconfig --list mysqld
$ service mysqld start
# 关闭防火墙
$ systemctl status firewalld
$ systemctl stop firewalld
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>测试及后续&lt;/li>
&lt;/ul>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 以root账户登录mysql,默认是没有密码的
$ bin/mysql -uroot -p
# 修改密码
$ use mysql;
$ update user set password=password('12345678') where user='mysql' and host='localhost';
# 设置远程登录
$ GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
$ FLUSH PRIVILEGES;
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>注意事项&lt;/li>
&lt;/ul>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">[1] 通过 systemctl 或者 service 启动mysql服务的时候，是通过调用 bin/mysqld_safe 作为守护进程去启动 bin/mysqld 进程来启动服务。
[2] bin/mysqld 通过 bin/mysqld --help --verbose 可以查看启动配置参数。其中my.cnf配置文件的查找过程就在输出中可以看见。
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="ubuntu" class="docsify-tabs__tab" data-tab="Ubuntu">Ubuntu&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="ubuntu">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># omitted
&lt;/code>&lt;/pre>&lt;/div>
&lt;/div>&lt;button anchorId="docker" class="docsify-tabs__tab" data-tab="Docker">Docker&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="docker">
&lt;ol>
&lt;li>
&lt;p>配置环境&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/01_database_related_concepts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/01_database_related_concepts/</guid><description>&lt;h2 id="数据库相关概念">
 数据库相关概念
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9b%b8%e5%85%b3%e6%a6%82%e5%bf%b5">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="ddldata-definition-language">
 DDL(Data Definition Language)
 &lt;a class="anchor" href="#ddldata-definition-language">#&lt;/a>
&lt;/h3>
&lt;p class="warn">数据库定义语言 statements are used to define the database structure or schema. DDL是SQL语言的四大功能之一。用于定义数据库的三级结构，包括外模式、概念模式、内模式及其相互之间的映像，定义数据的完整性、安全控制等约束DDL不需要commit. CREATE、ALTER、DROP、TRUNCATE、COMMENT、RENAME。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="dmldata-manipulation-language">
 DML(Data Manipulation Language)
 &lt;a class="anchor" href="#dmldata-manipulation-language">#&lt;/a>
&lt;/h3>
&lt;p class="warn">数据操纵语言statements are used for managing data within schema objects. 由DBMS提供，用于让用户或程序员使用，实现对数据库中数据的操作。DML分成交互型DML和嵌入型DML两类。依据语言的级别，DML又可分成过程性DML和非过程性DML两种。 需要commit. INSERT、UPDATE、DELETE、MERGE、CALL、EXPLAIN PLAN、LOCK TABLE。&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="dqldata-query-language">
 DQL(Data Query Language)
 &lt;a class="anchor" href="#dqldata-query-language">#&lt;/a>
&lt;/h3>
&lt;p class="warn">数据查询语言 SELECT、&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="dcldata-control-language">
 DCL(Data Control Language)
 &lt;a class="anchor" href="#dcldata-control-language">#&lt;/a>
&lt;/h3>
&lt;p class="warn">数据库控制语言 授权，角色控制等。GRANT 授权、REVOKE 取消授权&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="tcltransaction-control-language">
 TCL(Transaction Control Language)
 &lt;a class="anchor" href="#tcltransaction-control-language">#&lt;/a>
&lt;/h3>
&lt;p class="warn">事务控制语言。SAVEPOINT 设置保存点、ROLLBACK 回滚、SET TRANSACTION&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.cnblogs.com/henryhappier/archive/2010/07/05/1771295.html" rel="noopener" target="_blank">https://www.cnblogs.com/henryhappier/archive/2010/07/05/1771295.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/02_function/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/02_function/</guid><description>&lt;h2 id="函数">
 函数
 &lt;a class="anchor" href="#%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h2>
&lt;p class="warn">For server side help, type &amp;lsquo;help contents&amp;rsquo;&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">mysql&amp;gt; help contents
You asked for help about help category: &amp;quot;Contents&amp;quot;
For more information, type 'help &amp;lt;item&amp;gt;', where &amp;lt;item&amp;gt; is one of the following
categories:
 Account Management
 Administration
 Compound Statements
 Contents
 Data Definition
 Data Manipulation
 Data Types
 Functions
 Geographic Features
 Help Metadata
 Language Structure
 Plugins
 Procedures
 Storage Engines
 Table Maintenance
 Transactions
 User-Defined Functions
 Utility
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">mysql&amp;gt; help Functions
You asked for help about help category: &amp;quot;Functions&amp;quot;
For more information, type 'help &amp;lt;item&amp;gt;', where &amp;lt;item&amp;gt; is one of the following
categories:
 Bit Functions
 Comparison Operators
 Control Flow Functions
 Date and Time Functions
 Encryption Functions
 GROUP BY Functions and Modifiers
 Information Functions
 Locking Functions
 Logical Operators
 Miscellaneous Functions
 Numeric Functions
 Spatial Functions
 String Functions
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>
&lt;h3 id="常见函数">
 常见函数
 &lt;a class="anchor" href="#%e5%b8%b8%e8%a7%81%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="单行函数">
 单行函数
 &lt;a class="anchor" href="#%e5%8d%95%e8%a1%8c%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="字符函数">
 字符函数
 &lt;a class="anchor" href="#%e5%ad%97%e7%ac%a6%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="数学函数">
 数学函数
 &lt;a class="anchor" href="#%e6%95%b0%e5%ad%a6%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="日期函数">
 日期函数
 &lt;a class="anchor" href="#%e6%97%a5%e6%9c%9f%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="其他函数">
 其他函数
 &lt;a class="anchor" href="#%e5%85%b6%e4%bb%96%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/03_dql/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/03_dql/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="dql语言的学习">
 DQL语言的学习
 &lt;a class="anchor" href="#dql%e8%af%ad%e8%a8%80%e7%9a%84%e5%ad%a6%e4%b9%a0">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="1基础查询">
 1.基础查询
 &lt;a class="anchor" href="#1%e5%9f%ba%e7%a1%80%e6%9f%a5%e8%af%a2">#&lt;/a>
&lt;/h3>
&lt;p class="warn">
语法：&lt;code>select 查询列表 from 表名;&lt;/code>
&lt;br>&lt;br>特点：
&lt;br>1，查询列表可以是：&lt;span style='color: blue'>表中的字段，常量值，表达式，函数&lt;/span>
&lt;br>2，查询的结果是一个虚拟的表格
&lt;br>&lt;br>1.查询表中的单个字段
&lt;br>&lt;code>select last_name from employees limit 10;&lt;/code>
&lt;br>&lt;br>2.查询表中的多个字段
&lt;br>&lt;code>select last_name, salary, email from employees limit 10;&lt;/code>
&lt;br>&lt;br>3.查询表中的所有字段
&lt;br>&lt;code>select * from employees limit 10;&lt;/code>
&lt;br>&lt;br>4.查询常量值
&lt;br>&lt;code>select 100;&lt;/code>,&lt;code>select 'john';&lt;/code>
&lt;br>&lt;br>5.查询表达式
&lt;br>&lt;code>select 100%98;&lt;/code>
&lt;br>&lt;br>6.查询函数
&lt;br>&lt;code>select version();&lt;/code>
&lt;br>&lt;br>7.起别名
&lt;br>① 便于理解，② 如果查询字段有重名，使用别名可以区分开来，③ 别名中有特殊字符使用引号扩起来
&lt;br>&lt;code>select 100%98 as 结果;&lt;/code>
&lt;br>&lt;code>select last_name as 姓,first_name as 名 from employees limit 10;&lt;/code>
&lt;br>&lt;br>8.去重
&lt;br># case: 查询员工表中涉及到的所有的部门编号
&lt;br>&lt;code>select distinct department_id from employees;&lt;/code>
&lt;br>&lt;br>9.+号的作用 ① 仅仅只有一个功能，运算符
&lt;br>&lt;code>select 100 + 90;&lt;/code> 连个操作数都为数值型，则做加法运算
&lt;br>&lt;code>select '123' + 90;&lt;/code> 213 其中一个为字符型，可以转换，做加法运算
&lt;br>&lt;code>select 'john' + 90&lt;/code> 90 转换失败，则将字符型数值转换成 0 再做加法。
&lt;br>&lt;code>select null + 10;&lt;/code> NULL 只要有一方为NULL, 则结果肯定为NULL。
&lt;br>所以下面字符串连接得使用&lt;code>concat函数&lt;/code>
&lt;br>case: 查询员工名和姓连接成一个字段，并显示为姓名
&lt;br>&lt;code>select concat(last_name,first_name) as 姓名 from employees limit 10;&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/04_dml/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/04_dml/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="dml语言的学习">
 DML语言的学习
 &lt;a class="anchor" href="#dml%e8%af%ad%e8%a8%80%e7%9a%84%e5%ad%a6%e4%b9%a0">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/05_ddl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/05_ddl/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="ddl语言的学习">
 DDL语言的学习
 &lt;a class="anchor" href="#ddl%e8%af%ad%e8%a8%80%e7%9a%84%e5%ad%a6%e4%b9%a0">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="1库和表的管理">
 1.库和表的管理
 &lt;a class="anchor" href="#1%e5%ba%93%e5%92%8c%e8%a1%a8%e7%9a%84%e7%ae%a1%e7%90%86">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="2常见数据类型介绍">
 2.常见数据类型介绍
 &lt;a class="anchor" href="#2%e5%b8%b8%e8%a7%81%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e4%bb%8b%e7%bb%8d">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="3常见约束">
 3.常见约束
 &lt;a class="anchor" href="#3%e5%b8%b8%e8%a7%81%e7%ba%a6%e6%9d%9f">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> 含义：一种限制，用于限制表中的数据，为了保证表中数据的准确和可靠性
&lt;br>&lt;br> 分类：六大约束：
&lt;br>&lt;code>①:&lt;/code> NOT NULL： 非空，用于保证该字段的值不能为空。
&lt;br>&lt;code>②:&lt;/code> DEFAULT：默认，用于保证该字段有默认值。
&lt;br>&lt;code>③:&lt;/code> PRIMARY KEY： 主键，用于保证该字段的值具有唯一性，并且非空。
&lt;br>&lt;code>④:&lt;/code> UNIQUE：唯一，用于保证该字段的值具有唯一性，可以为空。
&lt;br>&lt;code>⑤:&lt;/code> CHECK：检查约束【mysql中不支持】
&lt;br>&lt;code>⑥:&lt;/code> FOREIGN KEY：外键，用于限制两个表的关系，用于保证该字段的值必须来自于主表的关联列的值。在从表中添加外键约束，用于引用主表中的某列的值。
&lt;br>&lt;br>添加约束的时机：
&lt;br>&lt;code>a).&lt;/code> 创建表时：
&lt;br>&lt;code>b).&lt;/code> 修改表时：
&lt;br>&lt;br>约束的添加分类：
&lt;br>&lt;code>1).&lt;/code> 列级约束：六大约束语法上都支持，但是外键约束没有效果
&lt;br>&lt;code>2).&lt;/code> 表级约束：除了非空，默认，其他都支持
&lt;br>&lt;span style='color: blue'>通用写法： 其他列级，外键表级&lt;/span>&lt;/p>
&lt;h6 id="测试约束用到的数据库">
 测试约束用到的数据库
 &lt;a class="anchor" href="#%e6%b5%8b%e8%af%95%e7%ba%a6%e6%9d%9f%e7%94%a8%e5%88%b0%e7%9a%84%e6%95%b0%e6%8d%ae%e5%ba%93">#&lt;/a>
&lt;/h6>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">drop database students;
create database students character set utf8;
use students;

-- 创建外键引用的主表
drop table if exists major;
create table major(
 id int primary key,
 majorName varchar(20)
);
insert into major values (1, 'java'),(2, 'h5');
select * from major;
&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>
&lt;h4 id="创建表时添加约束">
 创建表时添加约束
 &lt;a class="anchor" href="#%e5%88%9b%e5%bb%ba%e8%a1%a8%e6%97%b6%e6%b7%bb%e5%8a%a0%e7%ba%a6%e6%9d%9f">#&lt;/a>
&lt;/h4> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;h5 id="添加列级约束">
 添加列级约束
 &lt;a class="anchor" href="#%e6%b7%bb%e5%8a%a0%e5%88%97%e7%ba%a7%e7%ba%a6%e6%9d%9f">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql"># 1.1 添加列级约束
drop table if exists stu_info;
create table stu_info(
 id int primary key, # 主键
 stuName varchar(20) not null, # 非空
 gender char(1) check ( gender = '男' or gender = '女'), # 检查
 seat int unique, # 唯一
 age int default 18, # 默认
 majorId int references major(id) # 外键(列级没效果)
);
desc stu_info;
show index from stu_info;
insert into stu_info values (1,'john', '男', null, 19, 1);
insert into stu_info values (2,'lily', '男', null, 19, 2);
select * from stu_info;
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;h5 id="添加表级约束">
 添加表级约束
 &lt;a class="anchor" href="#%e6%b7%bb%e5%8a%a0%e8%a1%a8%e7%ba%a7%e7%ba%a6%e6%9d%9f">#&lt;/a>
&lt;/h5>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql"># 1.2添加表级约束
drop table if exists stu_info;
create table stu_info(
 id int,
 stuName varchar(20) not null,
 gender char(1),
 seat int,
 age int default 18,
 majorId int,

 constraint pk primary key(id), # 主键
 constraint uq unique (seat), # 唯一
 constraint ck check ( gender = '男' or gender = '女' ), # 检查
 constraint fk_stu_info_major foreign key (majorId) references major(id) # 外键
);
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>&lt;/div>

 &lt;hr/>
&lt;h6 id="主键和唯一对比">
 主键和唯一对比
 &lt;a class="anchor" href="#%e4%b8%bb%e9%94%ae%e5%92%8c%e5%94%af%e4%b8%80%e5%af%b9%e6%af%94">#&lt;/a>
&lt;/h6>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="center">&lt;/th>
&lt;th align="center">保证唯一性&lt;/th>
&lt;th align="center">是否允许为空&lt;/th>
&lt;th align="center">一个表中可以有多个&lt;/th>
&lt;th align="center">是否允许组合（联合）&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="center">主键&lt;/td>
&lt;td align="center">✅&lt;/td>
&lt;td align="center">❌&lt;/td>
&lt;td align="center">至多有1个主键&lt;/td>
&lt;td align="center">✅ &lt;br>【primary key(id,name)】&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">唯一&lt;/td>
&lt;td align="center">✅&lt;/td>
&lt;td align="center">✅ &lt;br>(可以有多个NULL)&lt;/td>
&lt;td align="center">可以有多个唯一字段&lt;/td>
&lt;td align="center">✅ &lt;br>【unique(seat, seat2】&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h6 id="外键的特点">
 外键的特点
 &lt;a class="anchor" href="#%e5%a4%96%e9%94%ae%e7%9a%84%e7%89%b9%e7%82%b9">#&lt;/a>
&lt;/h6>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/06_tcl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/06_tcl/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introtcl">
 Intro(TCL)
 &lt;a class="anchor" href="#introtcl">#&lt;/a>
&lt;/h2>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.bilibili.com/video/BV12b411K7Zu?p=146&amp;vd_source=550a4dc4b2a914c0681a14307bbe8cbe" rel="noopener" target="_blank">delete 和 truncate在事务中的区别&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/07_view/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/07_view/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introview">
 Intro(VIEW)
 &lt;a class="anchor" href="#introview">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 含义：虚拟表，和普通表一样使用
&lt;br>&lt;span style='color:blue'>mysql5.1版本出现的新特性是通过表动态生成的数据，行和列的数据来自定义视图的查询中使用的表，并且实在使用视图时动态生成的，只保存了sql逻辑，不保存查询结果&lt;/span>
&lt;br>&lt;br>好处：
&lt;br>&lt;code>1).&lt;/code>: 重用sql语句
&lt;br>&lt;code>2).&lt;/code>: 简化复杂的sql操作，不必知道它的查询细节
&lt;br>&lt;code>3).&lt;/code>: 保护数据，提高安全性
&lt;br>&lt;br>应用场景：
&lt;br>&lt;code>1).&lt;/code>: 多个地方用到了同样的查询结果
&lt;br>&lt;code>2).&lt;/code>: 该查询结果使用的sql语句较复杂&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="示例">
 示例
 &lt;a class="anchor" href="#%e7%a4%ba%e4%be%8b">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">create view my_v1
as 
select stuname, majorname from stu_info s inner join major m on s.majorId = m.id;
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;p class="warn">case1: 查询姓张的学生名和专业名
&lt;br>&lt;code>select stuname,majorname from stu_info s inner join major m on s.majorId = m.id where s.stuname like '张%';&lt;/code>
&lt;br>&lt;code>create view v1 as select stuname, majorname from stu_info s inner join major m on s.majorId = m.id;&lt;/code>
&lt;br>&lt;code>select * from v1 where stuname like '张%';&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/08_variables/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/08_variables/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introvariables">
 Intro(VARIABLES)
 &lt;a class="anchor" href="#introvariables">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 变量分类：
&lt;br>【系统变量 [全局变量 | 会话变量] 】
&lt;br>【用户自定义变量 [用户变量 | 局部变量]】：&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="系统变量">
 系统变量
 &lt;a class="anchor" href="#%e7%b3%bb%e7%bb%9f%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> 说明：
&lt;br>变量由系统提供的，不是用户定义的，属于服务器层面
&lt;br>&lt;br>使用语法：
&lt;br>case1：查看所有的系统变量: &lt;code>&amp;lt;br&amp;gt;`show global|session variables;` &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;case2：查看满足条件的部分系统变量:&lt;/code>
&lt;br>&lt;code>show global|session variables like '%char%';&lt;/code>
&lt;br>&lt;br>case3：查看指定的某个系统变量的值: ``
&lt;br>&lt;code>select @@global|session.变量名;&lt;/code>
&lt;br>&lt;br>case4：为某个变量赋值:
&lt;br>&lt;code>set global|session 系统变量名 = 值;&lt;/code>
&lt;br>&lt;code>set @@global|session .系统变量名 = 值;&lt;/code>&lt;/p>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 如果是全局级别，则需要加global，如果是会话级别，则需要加session，如果不写，则默认session&lt;/p>
&lt;/p>&lt;/div>
&lt;ul>
&lt;li>
&lt;h4 id="全局变量">
 全局变量
 &lt;a class="anchor" href="#%e5%85%a8%e5%b1%80%e5%8f%98%e9%87%8f">#&lt;/a>
&lt;/h4>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 作用域：服务器每次启动将会为所有的全局变量赋初始值，针对于所有的会话（连接）有效，但不能跨重启。&lt;span style='color: blue'>可通过配置文件进行重启生效&lt;/span>
&lt;br>&lt;br>使用语法：
&lt;br>case1：查看所有的系统变量:
&lt;br>&lt;code>show global variables;&lt;/code>
&lt;br>&lt;br>case2：查看满足条件的部分系统变量:
&lt;br>&lt;code>show global variables like '%char%';&lt;/code>
&lt;br>&lt;br>case3：查看指定的某个系统变量的值:
&lt;br>&lt;code>select @@global.autocommit;&lt;/code>
&lt;br>&lt;del>&lt;code>select @@tx_isolation;&lt;/code>&lt;/del>
&lt;br>&lt;br>case4：为某个变量赋值:
&lt;br>&lt;code>set global autocommit = 1;&lt;/code>，&lt;code>set @@global.autocommit = 0;&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/09_procedure_function/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/09_procedure_function/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introprocedure">
 Intro(PROCEDURE)
 &lt;a class="anchor" href="#introprocedure">#&lt;/a>
&lt;/h2>
&lt;p class="tip">类似于java中的方法，MySQL 5.0 版本开始支持存储过程。
&lt;br>含义：一组预先编译好的sql语句的集合，理解成批处理语句。
&lt;br>&lt;br>好处：
&lt;br>&lt;code>1).&lt;/code> 提高代码的重用性
&lt;br>&lt;code>2).&lt;/code> 简化操作
&lt;br>&lt;code>3).&lt;/code> 减少编译次数并且减少了和数据库服务器的连接次数，提高了效率。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="创建语法">
 创建语法
 &lt;a class="anchor" href="#%e5%88%9b%e5%bb%ba%e8%af%ad%e6%b3%95">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">create procedure 存储过程名称(参数列表)
begin
 存储过程题（一组合法的sql语句）
end
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 注意：
&lt;br>&lt;code>1).&lt;/code> 参数列表包含三部分（参数模式，参数名，参数类型），例如：&lt;code>IN stuname varchar(20)&lt;/code>
&lt;br>参数模式：
&lt;br>in: 该参数可以作为输入，也就是该参数需要调用方传入值
&lt;br>out: 该参数可以作为输出，也就是该参数可以作为返回值
&lt;br>inout: 该参数既可以作为输入又可以作为输出，也就是该参数既需要传入值，又可以返回值
&lt;br>&lt;br>&lt;code>2).&lt;/code> 如果存储过程体仅仅只有一句话，&lt;code>begin end&lt;/code>可以省略,存储过程体中的每条sql语句的结尾要求必须加分号。存储过程的结尾可以使用 &lt;code>delimiter&lt;/code>重新设置。语法：&lt;code>delimiter 结束标记&lt;/code>
&lt;br>&lt;code>delimiter $&lt;/code>&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="调用语法">
 调用语法
 &lt;a class="anchor" href="#%e8%b0%83%e7%94%a8%e8%af%ad%e6%b3%95">#&lt;/a>
&lt;/h3>
&lt;p>&lt;code>call 存储过程(实参列表);&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="1空参列表">
 1.空参列表
 &lt;a class="anchor" href="#1%e7%a9%ba%e5%8f%82%e5%88%97%e8%a1%a8">#&lt;/a>
&lt;/h4>
&lt;p class="warn"> case1：插入到admin表中五条记录
&lt;br>使用下面代码创建存储过程，
&lt;br>然后使用语句&lt;code>call myp1();&lt;/code>进行调用&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">delimiter $
create procedure myp1()
begin
 insert into admin(username, `password`) values('john1', '0000'), ('lily', '0000'), ('rose', '0000'), ('jack', '0000'), ('tom', '0000');
end $
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h4 id="2in模式列表">
 2.(IN)模式列表
 &lt;a class="anchor" href="#2in%e6%a8%a1%e5%bc%8f%e5%88%97%e8%a1%a8">#&lt;/a>
&lt;/h4>
&lt;p class="warn">case1：创建存储过程实现 根据女神名，查询对应的男神信息
&lt;br>使用下面代码创建存储过程，
&lt;br>然后使用语句&lt;code>call myp2('小昭');&lt;/code>进行调用，控制台会展示返回值。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/lesson/10_flow_control/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/lesson/10_flow_control/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introflow-control">
 Intro(FLOW CONTROL)
 &lt;a class="anchor" href="#introflow-control">#&lt;/a>
&lt;/h2>
&lt;p class="tip"> 简单介绍：
&lt;br>顺序结构：程序从上至下依次执行
&lt;br>分支结构：程序从两条或多条路径中选择一条去执行
&lt;br>循环结构：程序在满足一定条件的基础上，重复执行一段代码&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="分支结构">
 分支结构
 &lt;a class="anchor" href="#%e5%88%86%e6%94%af%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="if函数">
 IF函数
 &lt;a class="anchor" href="#if%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h4>
&lt;p class="warn"> 功能：实现简单的双分支
&lt;br>&lt;br>语法：&lt;code>if(表达式1，返回值2，返回值3)&lt;/code>
&lt;br>如果表达式1成立，则if使用返回值2，否则使用返回值3.
&lt;br>&lt;br>应用：任何地方&lt;/p>
&lt;/li>
&lt;li>
&lt;h4 id="case函数">
 CASE函数
 &lt;a class="anchor" href="#case%e5%87%bd%e6%95%b0">#&lt;/a>
&lt;/h4> &lt;div class="docsify-example-panels">&lt;p class="warn">特点：
&lt;br>&lt;code>1).&lt;/code> 可以作为表达式，嵌套在其他语句中使用，可以放在任何地方，begin end 中或begin end外面。可以作为单独的语句去使用，只能放在 begin end 中。
&lt;br>&lt;code>2).&lt;/code> 如果when中的值满足或条件成立，则执行对应的then后面的语句，并且结束case，如果都不满足，则执行else中的语句或值
&lt;br>&lt;code>3).&lt;/code> else可以省略，如果else省略了，并且所有when条件都不满足，则返回NULL。&lt;/p>
 &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p>&lt;p> 情况一：类似于java中的switch语句，一般用作实现等值判断&lt;/p>
&lt;/p>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">case 变量|表达式|字段
when 要判断的值 then 返回的值1或语句1;
when 要判断的值 then 返回的值1或语句1;
...
else 返回的值n或语句n;
end case;
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="alert callout note">&lt;p class="title">&lt;span class="icon icon-note">&lt;/span> Note &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/record/</guid><description>&lt;h2 id="head">
 HEAD
 &lt;a class="anchor" href="#head">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="表注释查询">
 表注释查询
 &lt;a class="anchor" href="#%e8%a1%a8%e6%b3%a8%e9%87%8a%e6%9f%a5%e8%af%a2">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">-- oracle
select * from user_tab_comments where comments like '%危险%';

-- mysql
SELECT COLUMN_NAME,column_comment FROM INFORMATION_SCHEMA.Columns
WHERE table_name='表名' AND table_schema='数据库名'
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="父子路径">
 父子路径
 &lt;a class="anchor" href="#%e7%88%b6%e5%ad%90%e8%b7%af%e5%be%84">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">-- 宁夏，银川，金凤，良田镇
SELECT T2.*
FROM (
 SELECT
 @r AS _code,
 (SELECT @r := sgd_father_url FROM stats_gov_data WHERE sgd_source_url = _code) AS v2,
 @l := @l + 1 AS lvl
 FROM
 stats_gov_data h , (SELECT @r := '2020/64/01/06/640106100.html',@l :=0) vars
 WHERE @r &amp;lt;&amp;gt; '2020/index.html'

) T1
LEFT JOIN stats_gov_data T2 ON T1._code = T2.sgd_source_url
order by T1.lvl desc;

-- 甘肃省-天水市-武山县
SELECT T2.*
FROM (
 SELECT 
 @r AS _code, 
 (SELECT @r := raa_father_code FROM `rsp_administrative_area` WHERE raa_code = _code) AS v2, 
 @l := @l + 1 AS lvl 
 FROM 
 rsp_administrative_area h , (SELECT @r := '620524',@l :=0) vars 
 WHERE @r is not null) T1 
left JOIN rsp_administrative_area T2 
ON T1._code = T2.raa_code
order by T1.lvl desc;

-- 所有子节点，包括父节点
SELECT * FROM (

 SELECT t1.*,
 IF(FIND_IN_SET(rgp_father_id, @pids) &amp;gt; 0 OR rgp_id = 1, @pids := CONCAT(@pids, ',', rgp_id), '0') AS ischild
 FROM (
 SELECT * FROM rsp_grid_position AS t 
 -- WHERE t.rgp_id = '01' 
 ORDER BY t.rgp_id ASC
 ) t1,
 (SELECT @pids := 1 ) t2 
) t3 
WHERE ischild != '0'
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="时间处理">
 时间处理
 &lt;a class="anchor" href="#%e6%97%b6%e9%97%b4%e5%a4%84%e7%90%86">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">SELECT
 MONTH( &amp;quot;2019-03-11 13:24:51&amp;quot; ),
 YEAR ( &amp;quot;2019-03-11 13:24:51&amp;quot; ),
 DAY ( &amp;quot;2019-03-11 13:24:51&amp;quot; ),
 HOUR ( &amp;quot;2019-03-11 13:24:51&amp;quot; ),
 MINUTE ( &amp;quot;2019-03-11 13:24:51&amp;quot; ),
 SECOND ( &amp;quot;2019-03-11 13:24:51&amp;quot; );

SELECT now(), EXTRACT( DAY_SECOND FROM now( ) );

select unix_timestamp();
select from_unixtime(1683993600000 / 1000);
select curdate(), curtime(), date(now());
select EXTRACT(YEAR_MONTH FROM now()); -- MICROSECOND、SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、QUARTER、YEAR、SECOND_MICROSECOND、MINUTE_MICROSECOND、MINUTE_SECOND、HOUR_MICROSECOND、HOUR_SECOND、HOUR_MINUTE、DAY_MICROSECOND、DAY_SECOND、DAY_MINUTE、DAY_HOUR、YEAR_MONTH
-- DATE_ADD(date,INTERVAL expr type)

select TIME_TO_SEC('00:06:53');
select str_to_date('2018-07-03 18:06:53', '%Y-%m-%d %H:%i:%s');
select date_format(now(), '%Y-%m-%d %H:%i:%s' );
select timediff('2018-07-03 19:13:21', '2018-07-03 18:06:53');
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/mysql/specification/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/mysql/specification/</guid><description>&lt;ul>
&lt;li>
&lt;h1 id="mysql数据库设计规范___msb___">
 MySQL数据库设计规范___MSB___
 &lt;a class="anchor" href="#mysql%e6%95%b0%e6%8d%ae%e5%ba%93%e8%ae%be%e8%ae%a1%e8%a7%84%e8%8c%83___msb___">#&lt;/a>
&lt;/h1>
&lt;ol>
&lt;li>
&lt;h2 id="规范背景与目的">
 规范背景与目的
 &lt;a class="anchor" href="#%e8%a7%84%e8%8c%83%e8%83%8c%e6%99%af%e4%b8%8e%e7%9b%ae%e7%9a%84">#&lt;/a>
&lt;/h2>
&lt;p class="warn">MySQL数据库与 Oracle、 SQL Server 等数据库相比，有其内核上的优势与劣势。我们在使用MySQL数据库的时候需要遵循一定规范，扬长避短。本规范旨在帮助或指导RD、QA、OP等技术人员做出适合线上业务的数据库设计。在数据库变更和处理流程、数据库表设计、SQL编写等方面予以规范，从而为公司业务系统稳定、健康地运行提供保障。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="设计规范">
 设计规范
 &lt;a class="anchor" href="#%e8%ae%be%e8%ae%a1%e8%a7%84%e8%8c%83">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="21-数据库设计">
 2.1 数据库设计
 &lt;a class="anchor" href="#21-%e6%95%b0%e6%8d%ae%e5%ba%93%e8%ae%be%e8%ae%a1">#&lt;/a>
&lt;/h3>
&lt;p class="tip">以下所有规范会按照**【高危】、【强制】、【建议】**三个级别进行标注，遵守优先级从高到低。
&lt;br>对于不满足【高危】和【强制】两个级别的设计，DBA会强制打回要求修改。&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="211-库名">
 2.1.1 库名
 &lt;a class="anchor" href="#211-%e5%ba%93%e5%90%8d">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】库的名称必须控制在32个字符以内，相关模块的表名与表名之间尽量提现join的关系，如user表和user_login表。&lt;/li>
&lt;li>【强制】库的名称格式：业务系统名称_子系统名，同一模块使用的表名尽量使用统一前缀。&lt;/li>
&lt;li>【强制】一般分库名称命名格式是&lt;code>库通配名_编号&lt;/code>，编号从0开始递增，比如&lt;code>wenda_001&lt;/code>以时间进行分库的名称格式是“库通配名_时间”&lt;/li>
&lt;li>【强制】创建数据库时必须显式指定字符集，并且字符集只能是utf8或者utf8mb4。创建数据库SQL举例：&lt;code>create database db1 default character set utf8mb4;&lt;/code>。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="212-表结构">
 2.1.2 表结构
 &lt;a class="anchor" href="#212-%e8%a1%a8%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】表和列的名称必须控制在32个字符以内，表名只能使用字母、数字和下划线，一律小写。&lt;/li>
&lt;li>【强制】表名要求模块名强相关，如师资系统采用”sz”作为前缀，渠道系统采用”qd”作为前缀等。&lt;/li>
&lt;li>【强制】创建表时必须显式指定字符集为utf8或utf8mb4。&lt;/li>
&lt;li>【强制】创建表时必须显式指定表存储引擎类型，如无特殊需求，一律为InnoDB。当需要使用除InnoDB/MyISAM/Memory以外的存储引擎时，必须通过DBA审核才能在生产环境中使用。因为Innodb表支持事务、行锁、宕机恢复、MVCC等关系型数据库重要特性，为业界使用最多的MySQL存储引擎。而这是其他大多数存储引擎不具备的，因此首推InnoDB。&lt;/li>
&lt;li>【强制】建表必须有comment&lt;/li>
&lt;li>【建议】建表时关于主键：(1)强制要求主键为id，类型为int或bigint，且为&lt;code>auto_increment&lt;/code>标识表里每一行主体的字段不要设为主键，建议设为其他字段如&lt;code>user_id&lt;/code>，&lt;code>order_id&lt;/code>等，并建立unique key索引（可参考&lt;code>cdb.teacher&lt;/code>表设计）。因为如果设为主键且主键值为随机插入，则会导致innodb内部page分裂和大量随机I/O，性能下降。&lt;/li>
&lt;li>【建议】核心表（如用户表，金钱相关的表）必须有行数据的创建时间字段&lt;code>create_time&lt;/code>和最后更新时间字段&lt;code>update_time&lt;/code>，便于查问题。&lt;/li>
&lt;li>【建议】表中所有字段必须都是&lt;code>NOT NULL&lt;/code>属性，业务可以根据需要定义&lt;code>DEFAULT&lt;/code>值。因为使用NULL值会存在每一行都会占用额外存储空间、数据迁移容易出错、聚合函数计算结果偏差等问题。&lt;/li>
&lt;li>【建议】建议对表里的&lt;code>blob&lt;/code>、&lt;code>text&lt;/code>等大字段，垂直拆分到其他表里，仅在需要读这些对象的时候才去select。&lt;/li>
&lt;li>【建议】反范式设计：把经常需要join查询的字段，在其他表里冗余一份。如&lt;code>user_name&lt;/code>属性在&lt;code>user_account&lt;/code>，&lt;code>user_login_log&lt;/code>等表里冗余一份，减少join查询。&lt;/li>
&lt;li>【强制】中间表用于保留中间结果集，名称必须以&lt;code>tmp_&lt;/code>开头。备份表用于备份或抓取源表快照，名称必须以&lt;code>bak_&lt;/code>开头。中间表和备份表定期清理。&lt;/li>
&lt;li>【强制】对于超过100W行的大表进行&lt;code>alter table&lt;/code>，必须经过DBA审核，并在业务低峰期执行。因为&lt;code>alter table&lt;/code>会产生表锁，期间阻塞对于该表的所有写入，对于业务可能会产生极大影响。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="213-列数据类型优化">
 2.1.3 列数据类型优化
 &lt;a class="anchor" href="#213-%e5%88%97%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e4%bc%98%e5%8c%96">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【建议】表中的自增列（&lt;code>auto_increment&lt;/code>属性），快速增长的表推荐使用&lt;code>bigint&lt;/code>类型。因为无符号&lt;code>int&lt;/code>存储范围为&lt;code>-2147483648~2147483647&lt;/code>（大约21亿左右），溢出后会导致报错。&lt;/li>
&lt;li>【建议】业务中选择性很少的状态&lt;code>status&lt;/code>、类型&lt;code>type&lt;/code>等字段推荐使用&lt;code>tinytint&lt;/code>或者&lt;code>smallint&lt;/code>类型节省存储空间。&lt;/li>
&lt;li>【建议】业务中IP地址字段推荐使用&lt;code>int&lt;/code>类型，不推荐用&lt;code>char(15)&lt;/code>。因为&lt;code>int&lt;/code>只占4字节，可以用如下函数相互转换，而&lt;code>char(15)&lt;/code>占用至少15字节。一旦表数据行数到了1亿，那么要多用1.1G存储空间。 SQL：&lt;code>select inet_aton('192.168.2.12'); select inet_ntoa(3232236044);&lt;/code> PHP: &lt;code>ip2long(‘192.168.2.12’); long2ip(3530427185);&lt;/code>&lt;/li>
&lt;li>【建议】不推荐使用&lt;code>enum&lt;/code>，&lt;code>set&lt;/code>。 因为它们浪费空间，且枚举值写死了，变更不方便。推荐使用&lt;code>tinyint&lt;/code>或&lt;code>smallint&lt;/code>。&lt;/li>
&lt;li>【建议】不推荐使用&lt;code>blob&lt;/code>，&lt;code>text&lt;/code>等类型。它们都比较浪费硬盘和内存空间。在加载表数据时，会读取大字段到内存里从而浪费内存空间，影响系统性能。建议和PM、RD沟通，是否真的需要这么大字段。Innodb中当一行记录超过8098字节时，会将该记录中选取最长的一个字段将其768字节放在原始&lt;code>page&lt;/code>里，该字段余下内容放在&lt;code>overflow-page&lt;/code>里。不幸的是在compact行格式下，原始&lt;code>page&lt;/code>和&lt;code>overflow-page&lt;/code>都会加载。&lt;/li>
&lt;li>【强制】存储金钱的字段，强制用&lt;code>decimal&lt;/code>，禁止使用浮点型来存储金钱&lt;/li>
&lt;li>【建议】文本数据尽量用&lt;code>varchar&lt;/code>存储。因为&lt;code>varchar&lt;/code>是变长存储，比&lt;code>char&lt;/code>更省空间。MySQL server层规定一行所有文本最多存65535字节，因此在utf8字符集下最多存21844个字符，超过会自动转换为&lt;code>mediumtext&lt;/code>字段。而&lt;code>text&lt;/code>在utf8字符集下最多存21844个字符，&lt;code>mediumtext&lt;/code>最多存2^24/3个字符，&lt;code>longtext&lt;/code>最多存2^32个字符。一般建议用&lt;code>varchar&lt;/code>类型，字符数不要超过2700。&lt;/li>
&lt;li>【建议】时间类型尽量选取&lt;code>datetime&lt;/code>类型，&lt;code>timestamp&lt;/code>在不同的时区访问会有时区转换。更为高阶的方法，选用&lt;code>int&lt;/code>来存储时间，使用SQL函数&lt;code>unix_timestamp()&lt;/code>和&lt;code>from_unixtime()&lt;/code>来进行转换。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="214-索引设计">
 2.1.4 索引设计
 &lt;a class="anchor" href="#214-%e7%b4%a2%e5%bc%95%e8%ae%be%e8%ae%a1">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】InnoDB表必须主键为`id int/bigint auto_increment``,且主键值禁止被更新。&lt;/li>
&lt;li>【建议】主键的名称以“&lt;code>pk_&lt;/code>”开头，唯一键以“&lt;code>uniq_&lt;/code>”开头，普通索引以“&lt;code>idx_&lt;/code>”开头，一律使用小写格式，以表名/字段的名称或缩写作为后缀。&lt;/li>
&lt;li>【强制】InnoDB和MyISAM存储引擎表，索引类型必须为&lt;code>BTREE&lt;/code>；MEMORY表可以根据需要选择&lt;code>HASH&lt;/code>或者&lt;code>BTREE&lt;/code>类型索引。&lt;/li>
&lt;li>【强制】单个索引中每个索引记录的长度不能超过64KB。&lt;/li>
&lt;li>【建议】单个表上的索引个数不能超过16个。&lt;/li>
&lt;li>【建议】在建立索引时，多考虑建立联合索引，并把区分度最高的字段放在最前面。如列&lt;code>userid&lt;/code>的区分度可由&lt;code>select count(distinct userid)&lt;/code>计算出来。&lt;/li>
&lt;li>【建议】在多表join的SQL里，保证被驱动表的连接列上有索引，这样join执行效率最高。&lt;/li>
&lt;li>【建议】建表或加索引时，保证表里互相不存在冗余索引。对于MySQL来说，如果表里已经存在&lt;code>key(a,b)&lt;/code>，则&lt;code>key(a)&lt;/code>为冗余索引，需要删除。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="215-分库分表分区表">
 2.1.5 分库分表、分区表
 &lt;a class="anchor" href="#215-%e5%88%86%e5%ba%93%e5%88%86%e8%a1%a8%e5%88%86%e5%8c%ba%e8%a1%a8">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】分区表的分区字段（&lt;code>partition-key&lt;/code>）必须有索引，或者是组合索引的首列。&lt;/li>
&lt;li>【强制】单个分区表中的分区（包括子分区）个数不能超过1024。&lt;/li>
&lt;li>【强制】上线前RD或者DBA必须指定分区表的创建、清理策略。&lt;/li>
&lt;li>【强制】访问分区表的SQL必须包含分区键。&lt;/li>
&lt;li>【建议】单个分区文件不超过2G，总大小不超过50G。建议总分区数不超过20个。&lt;/li>
&lt;li>【强制】对于分区表执行&lt;code>alter table&lt;/code>操作，必须在业务低峰期执行。&lt;/li>
&lt;li>【强制】采用分库策略的，库的数量不能超过1024&lt;/li>
&lt;li>【强制】采用分表策略的，表的数量不能超过4096&lt;/li>
&lt;li>【建议】单个分表不超过500W行，ibd文件大小不超过2G，这样才能让数据分布式变得性能更佳。&lt;/li>
&lt;li>【建议】水平分表尽量用取模方式，日志、报表类数据建议采用日期进行分表。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="216-字符集">
 2.1.6 字符集
 &lt;a class="anchor" href="#216-%e5%ad%97%e7%ac%a6%e9%9b%86">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】数据库本身库、表、列所有字符集必须保持一致，为&lt;code>utf8&lt;/code>或&lt;code>utf8mb4&lt;/code>,不要在表中给字段单独指定字符集。&lt;/li>
&lt;li>【强制】前端程序字符集或者环境变量中的字符集，与数据库、表的字符集必须一致，统一为&lt;code>utf8mb4&lt;/code>。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="217-程序层dao设计建议">
 2.1.7 程序层DAO设计建议
 &lt;a class="anchor" href="#217-%e7%a8%8b%e5%ba%8f%e5%b1%82dao%e8%ae%be%e8%ae%a1%e5%bb%ba%e8%ae%ae">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【建议】新的代码不要用model，推荐使用手动拼SQL+绑定变量传入参数的方式。因为model虽然可以使用面向对象的方式操作db，但是其使用不当很容易造成生成的SQL非常复杂，且model层自己做的强制类型转换性能较差，最终导致数据库性能下降。&lt;/li>
&lt;li>【建议】前端程序连接MySQL或者redis，必须要有连接超时和失败重连机制，且失败重试必须有间隔时间。&lt;/li>
&lt;li>【建议】前端程序报错里尽量能够提示MySQL或redis原生态的报错信息，便于排查错误。&lt;/li>
&lt;li>【建议】对于有连接池的前端程序，必须根据业务需要配置初始、最小、最大连接数，超时时间以及连接回收机制，否则会耗尽数据库连接资源，造成线上事故。&lt;/li>
&lt;li>【建议】对于log或history类型的表，随时间增长容易越来越大，因此上线前RD或者DBA必须建立表数据清理或归档方案。&lt;/li>
&lt;li>【建议】在应用程序设计阶段，RD必须考虑并规避数据库中主从延迟对于业务的影响。尽量避免从库短时延迟（20秒以内）对业务造成影响，建议强制一致性的读开启事务走主库，或更新后过一段时间再去读从库。&lt;/li>
&lt;li>【建议】多个并发业务逻辑访问同一块数据（innodb表）时，会在数据库端产生行锁甚至表锁导致并发下降，因此建议更新类SQL尽量基于主键去更新。&lt;/li>
&lt;li>【建议】业务逻辑之间加锁顺序尽量保持一致，否则会导致死锁。&lt;/li>
&lt;li>【建议】对于单表读写比大于10:1的数据行或单个列，可以将热点数据放在缓存里（如mecache或redis），加快访问速度，降低MySQL压力。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="218-一个规范的建表语句示例">
 2.1.8 一个规范的建表语句示例
 &lt;a class="anchor" href="#218-%e4%b8%80%e4%b8%aa%e8%a7%84%e8%8c%83%e7%9a%84%e5%bb%ba%e8%a1%a8%e8%af%ad%e5%8f%a5%e7%a4%ba%e4%be%8b">#&lt;/a>
&lt;/h4>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sql" data-line="" class="language-sql line-numbers" style="max-height: none">&lt;code class="language-sql">CREATE TABLE user (
 id bigint NOT NULL AUTO_INCREMENT,
 user_id bigint NOT NULL DEFAULT 0 COMMENT '用户id',
 username varchar(64) NOT NULL DEFAULT '' COMMENT '真实姓名',
 email varchar(64) NOT NULL DEFAULT '' COMMENT '用户邮箱',
 nickname varchar(64) NOT NULL DEFAULT '' COMMENT '昵称',
 birthday date NOT NULL DEFAULT '1001-01-01' COMMENT '生日',
 sex tinyint NOT NULL DEFAULT 0 COMMENT '性别 0-男 1-女',
 short_introduce varchar(128) NOT NULL DEFAULT '' COMMENT '一句话介绍自己，最多128个汉字',
 user_resume varchar(256) NOT NULL DEFAULT '' COMMENT '用户提交的简历存放地址',
 create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户记录创建的时间',
 update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '用户资料修改的时间',
 user_review_status tinyint NOT NULL DEFAULT 4 COMMENT '用户资料审核状态，1为通过，2为审核中，3为未通过，4为还未提交审核',
 PRIMARY KEY (id),
 UNIQUE KEY uniq_user_id (user_id),
 KEY idx_username(username),
 KEY idx_create_time(create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='网站用户基本信息';
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h3 id="22-sql编写">
 2.2 SQL编写
 &lt;a class="anchor" href="#22-sql%e7%bc%96%e5%86%99">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="221-dml语句">
 2.2.1 DML语句
 &lt;a class="anchor" href="#221-dml%e8%af%ad%e5%8f%a5">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】SELECT语句必须指定具体字段名称，禁止写成&lt;code>*&lt;/code>。因为&lt;code>select *&lt;/code>会将不该读的数据也从MySQL里读出来，造成网卡压力。且表字段一旦更新，但model层没有来得及更新的话，系统会报错。&lt;/li>
&lt;li>【强制】insert语句指定具体字段名称，不要写成&lt;code>insert into t1 values(…)&lt;/code>，道理同上。&lt;/li>
&lt;li>【建议】&lt;code>insert into…values(XX),(XX),(XX)…&lt;/code>。这里XX的值不要超过5000个。值过多虽然上线很很快，但会引起主从同步延迟。&lt;/li>
&lt;li>【建议】SELECT语句不要使用&lt;code>UNION&lt;/code>，推荐使用&lt;code>UNION ALL&lt;/code>，并且&lt;code>UNION&lt;/code>子句个数限制在5个以内。因为&lt;code>union all&lt;/code>不需要去重，节省数据库资源，提高性能。&lt;/li>
&lt;li>【建议】in值列表限制在200以内。例如&lt;code>select… where userid in(….200个以内…)&lt;/code>，这么做是为了减少底层扫描，减轻数据库压力从而加速查询。&lt;/li>
&lt;li>【建议】事务里批量更新数据需要控制数量，进行必要的sleep，做到少量多次。&lt;/li>
&lt;li>【强制】事务涉及的表必须全部是innodb表。否则一旦失败不会全部回滚，且易造成主从库同步终端。&lt;/li>
&lt;li>【强制】写入和事务发往主库，只读SQL发往从库。&lt;/li>
&lt;li>【强制】除静态表或小表（100行以内），DML语句必须有where条件，且使用索引查找。&lt;/li>
&lt;li>【强制】生产环境禁止使用&lt;code>hint&lt;/code>，如&lt;code>sql_no_cache&lt;/code>，&lt;code>force index&lt;/code>，&lt;code>ignore key&lt;/code>，&lt;code>straight join&lt;/code>等。因为hint是用来强制SQL按照某个执行计划来执行，但随着数据量变化我们无法保证自己当初的预判是正确的，因此我们要相信MySQL优化器！&lt;/li>
&lt;li>【强制】where条件里等号左右字段类型必须一致，否则无法利用索引。&lt;/li>
&lt;li>【建议】&lt;code>SELECT|UPDATE|DELETE|REPLACE&lt;/code>要有WHERE子句，且WHERE子句的条件必需使用索引查找。&lt;/li>
&lt;li>【强制】生产数据库中强烈不推荐大表上发生全表扫描，但对于100行以下的静态表可以全表扫描。查询数据量不要超过表行数的25%，否则不会利用索引。&lt;/li>
&lt;li>【强制】WHERE 子句中禁止只使用全模糊的LIKE条件进行查找，必须有其他等值或范围查询条件，否则无法利用索引。&lt;/li>
&lt;li>【建议】索引列不要使用函数或表达式，否则无法利用索引。如&lt;code>where length(name)='Admin'&lt;/code>或&lt;code>where user_id+2=10023&lt;/code>。&lt;/li>
&lt;li>【建议】减少使用or语句，可将or语句优化为union，然后在各个where条件上建立索引。如&lt;code>where a=1 or b=2&lt;/code>优化为&lt;code>where a=1… union …where b=2, key(a),key(b)&lt;/code>。&lt;/li>
&lt;li>【建议】分页查询，当limit起点较高时，可先用过滤条件进行过滤。如select a,b,c from t1 limit 10000,20;优化为: select a,b,c from t1 where id&amp;gt;10000 limit 20;。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="222-多表连接">
 2.2.2 多表连接
 &lt;a class="anchor" href="#222-%e5%a4%9a%e8%a1%a8%e8%bf%9e%e6%8e%a5">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【强制】禁止跨db的join语句。因为这样可以减少模块间耦合，为数据库拆分奠定坚实基础。&lt;/li>
&lt;li>【强制】禁止在业务的更新类SQL语句中使用join，比如&lt;code>update t1 join t2…&lt;/code>。&lt;/li>
&lt;li>【建议】不建议使用子查询，建议将子查询SQL拆开结合程序多次查询，或使用join来代替子查询。&lt;/li>
&lt;li>【建议】线上环境，多表join不要超过3个表。&lt;/li>
&lt;li>【建议】多表连接查询推荐使用别名，且SELECT列表中要用别名引用字段，数据库.表格式，如&lt;code>select a from db1.table1 alias1 where …&lt;/code>。&lt;/li>
&lt;li>【建议】在多表join中，尽量选取结果集较小的表作为驱动表，来join其他表。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="223-事务">
 2.2.3 事务
 &lt;a class="anchor" href="#223-%e4%ba%8b%e5%8a%a1">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【建议】事务中&lt;code>INSERT|UPDATE|DELETE|REPLACE&lt;/code>语句操作的行数控制在2000以内，以及WHERE子句中IN列表的传参个数控制在500以内。&lt;/li>
&lt;li>【建议】批量操作数据时，需要控制事务处理间隔时间，进行必要的sleep，一般建议值5-10秒。&lt;/li>
&lt;li>【建议】对于有&lt;code>auto_increment&lt;/code>属性字段的表的插入操作，并发需要控制在200以内。&lt;/li>
&lt;li>【强制】程序设计必须考虑“数据库事务隔离级别”带来的影响，包括脏读、不可重复读和幻读。线上建议事务隔离级别为&lt;code>repeatable-read&lt;/code>。&lt;/li>
&lt;li>【建议】事务里包含SQL不超过5个（支付业务除外）。因为过长的事务会导致锁数据较久，MySQL内部缓存、连接消耗过多等雪崩问题。&lt;/li>
&lt;li>【建议】事务里更新语句尽量基于主键或&lt;code>unique key&lt;/code>，如&lt;code>update … where id=XX&lt;/code>; 否则会产生间隙锁，内部扩大锁定范围，导致系统性能下降，产生死锁。&lt;/li>
&lt;li>【建议】尽量把一些典型外部调用移出事务，如调用webservice，访问文件存储等，从而避免事务过长。&lt;/li>
&lt;li>【建议】对于MySQL主从延迟严格敏感的select语句，请开启事务强制访问主库。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="224-排序和分组">
 2.2.4 排序和分组
 &lt;a class="anchor" href="#224-%e6%8e%92%e5%ba%8f%e5%92%8c%e5%88%86%e7%bb%84">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【建议】减少使用&lt;code>order by&lt;/code>，和业务沟通能不排序就不排序，或将排序放到程序端去做。&lt;code>order by&lt;/code>、&lt;code>group by&lt;/code>、&lt;code>distinct&lt;/code>这些语句较为耗费CPU，数据库的CPU资源是极其宝贵的。&lt;/li>
&lt;li>【建议】&lt;code>order by&lt;/code>、&lt;code>group by&lt;/code>、&lt;code>distinct&lt;/code>这些SQL尽量利用索引直接检索出排序好的数据。如&lt;code>where a=1 order by&lt;/code>可以利用&lt;code>key(a,b)&lt;/code>。&lt;/li>
&lt;li>【建议】包含了&lt;code>order by&lt;/code>、&lt;code>group by&lt;/code>、&lt;code>distinct&lt;/code>这些查询的语句，where条件过滤出来的结果集请保持在1000行以内，否则SQL会很慢。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="225-线上禁止使用的sql语句">
 2.2.5 线上禁止使用的SQL语句
 &lt;a class="anchor" href="#225-%e7%ba%bf%e4%b8%8a%e7%a6%81%e6%ad%a2%e4%bd%bf%e7%94%a8%e7%9a%84sql%e8%af%ad%e5%8f%a5">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>【高危】禁用&lt;code>update|delete t1 … where a=XX limit XX;&lt;/code> 这种带limit的更新语句。因为会导致主从不一致，导致数据错乱。建议加上order by PK。&lt;/li>
&lt;li>【高危】禁止使用关联子查询，如&lt;code>update t1 set … where name in(select name from user where…);&lt;/code> 效率极其低下。&lt;/li>
&lt;li>【强制】禁用procedure、function、trigger、views、event、外键约束。因为他们消耗数据库资源，降低数据库实例可扩展性。推荐都在程序端实现。&lt;/li>
&lt;li>【强制】禁用&lt;code>insert into …on duplicate key update…&lt;/code> 在高并发环境下，会造成主从不一致。&lt;/li>
&lt;li>【强制】禁止联表更新语句，如&lt;code>update t1,t2 where t1.id=t2.id…&lt;/code>。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;p>© Archery (v1.7.9)&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/netty/lesson/01_netty-code-flow/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/netty/lesson/01_netty-code-flow/</guid><description>&lt;h2 id="netty编码流程">
 Netty编码流程
 &lt;a class="anchor" href="#netty%e7%bc%96%e7%a0%81%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h2>
&lt;p class="warn">写一个简单的http server&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class TestServer {
 public static void main(String[] args) {
 EventLoopGroup bossGroup = new NioEventLoopGroup();
 EventLoopGroup wordGroup = new NioEventLoopGroup();

 ServerBootstrap serverBootstrap = new ServerBootstrap();

 try {
 serverBootstrap.group(bossGroup,wordGroup)
 .channel(NioServerSocketChannel.class)
 
 // channel初始化器
 .childHandler(new ChannelInitializer&amp;lt;SocketChannel&amp;gt;() {
 @Override
 protected void initChannel(SocketChannel socketChannel) throws Exception {
 ChannelPipeline pipeline = socketChannel.pipeline();
 pipeline.addLast(&amp;quot;httpServerCodec&amp;quot;,new HttpServerCodec());
 
 // 在pipeline中加入自定义的解码器 handler
 pipeline.addLast(&amp;quot;httpServerContent&amp;quot;, new SimpleChannelInboundHandler&amp;lt;HttpObject&amp;gt;() {
 @Override
 protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject msg) throws Exception {
 /* 
 另外有一个 LastHttpContent 类型的 EMPTY_LAST_CONTENT 对象
 来源：HttpServerCodec 中 inboundHandler 为 HttpServerRequestDecoder ==&amp;gt; HttpObjectDecoder
 channelRead 的时候会进行解码，追加两个对象；
 out.add(message);
 out.add(LastHttpContent.EMPTY_LAST_CONTENT);
 所以追加if判断
 */
 if(msg instanceof HttpRequest){
 ByteBuf byteBuf = Unpooled.copiedBuffer(&amp;quot;hello world&amp;quot;, CharsetUtil.UTF_8);
 FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,byteBuf);
 response.headers().set(HttpHeaderNames.CONTENT_TYPE,&amp;quot;text/plain&amp;quot;);
 response.headers().set(HttpHeaderNames.CONTENT_LENGTH,byteBuf.readableBytes());
 response.headers().set(HttpHeaderNames.SERVER,&amp;quot;X-eli&amp;quot;);

 channelHandlerContext.writeAndFlush(response);
 }
 }
 });
 }
 });
 ChannelFuture channelFuture = serverBootstrap.bind(13308).sync();
 channelFuture.channel().closeFuture().sync();
 }catch (Exception e){
 e.printStackTrace();
 }finally {
 bossGroup.shutdownGracefully();
 wordGroup.shutdownGracefully();
 }
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.bilibili.com/video/BV1c4411J7Ty?p=5" rel="noopener" target="_blank">https://www.bilibili.com/video/BV1c4411J7Ty?p=5&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/netty/netty/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/netty/netty/</guid><description>&lt;h2 id="netty-是什么">
 Netty 是什么
 &lt;a class="anchor" href="#netty-%e6%98%af%e4%bb%80%e4%b9%88">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>Netty 是一个 基于 NIO的client-server(客户端服务器)框架，使用它可以快速简单地开发网络应用程序。&lt;br>
它极大地简化并优化了 TCP 和 UDP套接字服务器等网络编程,并且性能以及安全性等很多方面甚至都要更好。&lt;br>
支持多种协议 如 FTP，SMTP，HTTP 以及各种二进制和基于文本的传统协议。&lt;/p>
&lt;/blockquote>
&lt;h2 id="优点">
 优点
 &lt;a class="anchor" href="#%e4%bc%98%e7%82%b9">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>placeholder
&lt;ul>
&lt;li>统一的 API，支持多种传输类型，阻塞和非阻塞的。&lt;/li>
&lt;li>简单而强大的线程模型。&lt;/li>
&lt;li>自带编解码器解决 TCP 粘包/拆包问题。&lt;/li>
&lt;li>自带各种协议栈。&lt;/li>
&lt;li>真正的无连接数据包套接字支持。&lt;/li>
&lt;li>比直接使用 Java 核心 API 有更高的吞吐量、更低的延迟、更低的资源消耗和更少的内存复制。&lt;/li>
&lt;li>安全性不错，有完整的 SSL/TLS 以及 StartTLS 支持。&lt;/li>
&lt;li>社区活跃&lt;/li>
&lt;li>成熟稳定，经历了大型项目的使用和考验，而且很多开源项目都使用到了 Netty， 比如我们经常接触的 Dubbo、RocketMQ 等等。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="应用场景">
 应用场景
 &lt;a class="anchor" href="#%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>placeholder
&lt;ul>
&lt;li>作为 RPC 框架的网络通信工具&lt;/li>
&lt;li>实现一个自己的 HTTP 服务器&lt;/li>
&lt;li>实现一个即时通讯系统&lt;/li>
&lt;li>实现消息推送系统&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="知识点">
 知识点
 &lt;a class="anchor" href="#%e7%9f%a5%e8%af%86%e7%82%b9">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>placeholder
&lt;ul>
&lt;li>netty 核心组件有哪些？分别有什么作用&lt;/li>
&lt;li>EventloopGroup了解么？和Eventloop有什么关系？&lt;/li>
&lt;li>BootStrap和ServerBootStrap了解么？&lt;/li>
&lt;li>NioEventLoopGroup 默认的构造函数会起多少线程？&lt;/li>
&lt;li>Netty 线程模型了解吗？&lt;/li>
&lt;li>netty 服务端和客户端的启动过过程了解吗？&lt;/li>
&lt;li>netty 长链接和心跳机制？&lt;/li>
&lt;li>netty 零拷贝？&lt;/li>
&lt;li>netty中空轮询BUG&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://gee.cs.oswego.edu/dl/cpjslides/nio.pdf" rel="noopener" target="_blank">https://gee.cs.oswego.edu/dl/cpjslides/nio.pdf&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/redis/install/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/redis/install/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introinstall">
 Intro(Install)
 &lt;a class="anchor" href="#introinstall">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="压缩包安装">
 压缩包安装
 &lt;a class="anchor" href="#%e5%8e%8b%e7%bc%a9%e5%8c%85%e5%ae%89%e8%a3%85">#&lt;/a>
&lt;/h3>
&lt;h6 id="docker" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="centos7" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ubuntu" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="docker" class="docsify-tabs__tab" data-tab="Docker">Docker&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="docker">
&lt;ol>
&lt;li>配置环境&lt;/li>
&lt;/ol>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 启动服务器
$ docker run -d -p 6379:6379 --name redis-6.2.8 redis:6.2.8 redis-server --save 60 1 --loglevel warning

# 使用自定义的配置文件
$ docker run -d -p 6379:6379 -v /myredis/conf:/usr/local/etc/redis --name redis-6.2.8 redis:6.2.8 redis-server /usr/local/etc/redis/redis.conf
&lt;/code>&lt;/pre>&lt;/div>
&lt;ol start="2">
&lt;li>测试&lt;/li>
&lt;/ol>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 使用redis容器内部客户端进行访问
$ docker run -it --rm --network host redis:6.2.8 redis-cli -h 127.0.0.1
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/redis/redis-install-dcoker-01.png" alt="" width="100%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/redis/redis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/redis/redis/</guid><description>&lt;h2 id="nosql数据库的四大分类">
 NoSql数据库的四大分类
 &lt;a class="anchor" href="#nosql%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e5%9b%9b%e5%a4%a7%e5%88%86%e7%b1%bb">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="表格视图">
 表格视图
 &lt;a class="anchor" href="#%e8%a1%a8%e6%a0%bc%e8%a7%86%e5%9b%be">#&lt;/a>
&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>分类&lt;/th>
&lt;th>Example举例&lt;/th>
&lt;th>典型应用场景&lt;/th>
&lt;th>数据模型&lt;/th>
&lt;th>优点&lt;/th>
&lt;th>缺点&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>键值(key-value)&lt;/td>
&lt;td>Tokyo,Cabinet/Tyrant,Redis,Voldemort,Oracle BDB&lt;/td>
&lt;td>内容缓存，主要用于处理大量数据的高访问负载，也用于一些日志系统等&lt;/td>
&lt;td>key指向value的键值对，通常用hashtable来实现&lt;/td>
&lt;td>查找速度快&lt;/td>
&lt;td>数据无结构化，通常只被当作字符串或者二进制数据&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>列存储数据库&lt;/td>
&lt;td>Cassandra，HBase,Riak&lt;/td>
&lt;td>分布式的文件系统&lt;/td>
&lt;td>以列簇式存储，将同一列数据存放在一起&lt;/td>
&lt;td>查找速度快，可扩展性强，更容易进行分布式扩展&lt;/td>
&lt;td>功能相对局限&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>文档型数据库&lt;/td>
&lt;td>CouchDB，MongoDb&lt;/td>
&lt;td>web应用（与Key-value类似，value是结构化的，不同的是数据库能够了解Value的内容）&lt;/td>
&lt;td>key-value对应的键值对，value为结构化数据&lt;/td>
&lt;td>数据结构要求不严格，表结构可变，不需要向关系型数据库一样预先定义表结构&lt;/td>
&lt;td>查询性能不高，而且缺乏统一的查询语法&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>图形数据库&lt;/td>
&lt;td>Neo4j,InfoGrid,Infinite Graph&lt;/td>
&lt;td>社交网络，推荐系统等，专注于构建关系图谱&lt;/td>
&lt;td>图结构&lt;/td>
&lt;td>利用图层结构相关算法，比如最短路径寻址等&lt;/td>
&lt;td>很多时候需要对整个图做计算才能得出需要的信息&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/li>
&lt;/ul>
&lt;h2 id="分布式数据库中的cap原理capbase">
 分布式数据库中的CAP原理CAP+BASE
 &lt;a class="anchor" href="#%e5%88%86%e5%b8%83%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e4%b8%ad%e7%9a%84cap%e5%8e%9f%e7%90%86capbase">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="传统的acid分别是什么">
 传统的acid分别是什么
 &lt;a class="anchor" href="#%e4%bc%a0%e7%bb%9f%e7%9a%84acid%e5%88%86%e5%88%ab%e6%98%af%e4%bb%80%e4%b9%88">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>A（Atomicity）原子性&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>原子性很容易理解，也就是说事务里的所有操作要么全部完成，要么不做，事务成功的条件是事务里的所有操作都成功，只要有一个操作失败，整个事务就是失败的，需要回滚。比如银行转账，从A向B转100元，分为两个步骤，1）从A账户减100，2）在B账户加100。&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>C（Consistency）一致性&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>数据库要一直处于一致的状态，事务的运行不会改变数据库原本的一致性约束&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>I（Isolation）隔离性&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>所谓的隔离性是指并发的事务之间不会互相影响，如果一个事务要访问的数据正在被另一个事务修改，只要另外一个事务未提交，它所访问的数据就不受未提交事务的影响，比如有个事务要完成A——》B转账100元，只要事务还没提交（未完成）的情况下，B查询自己的账户余额，是看不到新增加的100元的&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>D（Durability）持久性&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>持久性是指一旦事务提交后，它所做的修改将会永久的保存在数据库上，即使宕机也不会丢失。&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;h3 id="cap">
 CAP
 &lt;a class="anchor" href="#cap">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>C（Consistency）强一致性&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Consistency 中文叫做&amp;quot;一致性&amp;quot;。意思是，写操作之后的读操作，必须返回该值。举例来说，某条记录是 v0，用户向 G1 发起一个写操作，将其改为 v1。接下来，用户的读操作就会得到 v1。这就叫一致性。问题是，用户有可能向 G2 发起读操作，由于 G2 的值没有发生变化，因此返回的是 v0。G1 和 G2 读操作的结果不一致，这就不满足一致性了。为了让 G2 也能变为 v1，就要在 G1 写操作的时候，让 G1 向 G2 发送一条消息，要求 G2 也改成 v1。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/brpc/brpc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/brpc/brpc/</guid><description>&lt;p>hello brpc&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/dubbo/dubbo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/dubbo/dubbo/</guid><description>&lt;p>hello dubbo&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/gRpc/gRpc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/gRpc/gRpc/</guid><description>&lt;p>hello gRpc&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/avro/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/avro/</guid><description>&lt;p>hello avro&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/fst/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/fst/</guid><description>&lt;p>hello fst&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/hession/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/hession/</guid><description>&lt;p>hello hession&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/JDK_build_in/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/JDK_build_in/</guid><description>&lt;p>hello jdk build in&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/jsonOrxml/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/jsonOrxml/</guid><description>&lt;p>hello json or xml&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/kryo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/kryo/</guid><description>&lt;p>hello kryo&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/protobuf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/protobuf/</guid><description>&lt;p>hello protobuf&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/rpc/serialized/thrift/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/rpc/serialized/thrift/</guid><description>&lt;p>hello thrift&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springboot/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springboot/</guid><description>&lt;h2 id="启动流程">
 启动流程
 &lt;a class="anchor" href="#%e5%90%af%e5%8a%a8%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h3 id="流程图">
 流程图
 &lt;a class="anchor" href="#%e6%b5%81%e7%a8%8b%e5%9b%be">#&lt;/a>
&lt;/h3>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/springboot/process.png" alt="" width="90%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="伪代码">
 伪代码
 &lt;a class="anchor" href="#%e4%bc%aa%e4%bb%a3%e7%a0%81">#&lt;/a>
&lt;/h3>
&lt;blockquote>
&lt;p>main方法启动： &lt;code>SpringApplication.run(SpringbootApplication.class, args);&lt;/code> &lt;br>
new SpringApplication(sources).run(); &lt;br>&lt;/p>
&lt;/blockquote>
&lt;p>SpringApplication#init构造器中的初始化过程&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">private void initialize(Object[] sources) {
 if (sources != null &amp;amp;&amp;amp; sources.length &amp;gt; 0) {
 this.sources.addAll(Arrays.asList(sources));
 }
 this.webEnvironment = deduceWebEnvironment();
 setInitializers((Collection) getSpringFactoriesInstances(
 ApplicationContextInitializer.class));
 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
 this.mainApplicationClass = deduceMainApplicationClass();
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>SpringApplication#run&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public ConfigurableApplicationContext run(String... args) {
 StopWatch stopWatch = new StopWatch();
 stopWatch.start();
 ConfigurableApplicationContext context = null;
 FailureAnalyzers analyzers = null;
 configureHeadlessProperty();
 SpringApplicationRunListeners listeners = getRunListeners(args);
 listeners.starting();
 try {
 ApplicationArguments applicationArguments = new DefaultApplicationArguments(
 args);
 ConfigurableEnvironment environment = prepareEnvironment(listeners,
 applicationArguments);
 Banner printedBanner = printBanner(environment);
 context = createApplicationContext();
 analyzers = new FailureAnalyzers(context);
 prepareContext(context, environment, listeners, applicationArguments,
 printedBanner);
 refreshContext(context);
 afterRefresh(context, applicationArguments);
 listeners.finished(context, null);
 stopWatch.stop();
 if (this.logStartupInfo) {
 new StartupInfoLogger(this.mainApplicationClass)
 .logStarted(getApplicationLog(), stopWatch);
 }
 return context;
 }
 catch (Throwable ex) {
 handleRunFailure(context, listeners, analyzers, ex);
 throw new IllegalStateException(ex);
 }
}
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ul>
&lt;h2 id="自动装配">
 自动装配
 &lt;a class="anchor" href="#%e8%87%aa%e5%8a%a8%e8%a3%85%e9%85%8d">#&lt;/a>
&lt;/h2>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.csdn.net/weixin_44947701/article/details/124055713" rel="noopener" target="_blank">https://blog.csdn.net/weixin_44947701/article/details/124055713&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springcloud/springcloud/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springcloud/springcloud/</guid><description>&lt;p>comming soon&amp;hellip;&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springcore/00_spring_startup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springcore/00_spring_startup/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introstartup-process">
 Intro(Startup Process)
 &lt;a class="anchor" href="#introstartup-process">#&lt;/a>
&lt;/h2>
&lt;p class="tip">&lt;code>spring.version = 4.3.7.RELEASE&lt;/code>&lt;/p>
&lt;p style="text-align: center;">&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-001.png" alt="" width="100%">&lt;/p>
&lt;div class="alert callout tip">&lt;p class="title">&lt;span class="icon icon-tip">&lt;/span> Tip &lt;/p>&lt;p> &lt;code>1.)&lt;/code> &lt;code>ApplicationContext&lt;/code>继承了&lt;code>BeanFactory&lt;/code>接口，在内部实现中采用委托的方式调用正真的beanfactory.&lt;/p>
&lt;/p>&lt;/div>
&lt;ul>
&lt;li>
&lt;h3 id="解析流程">
 解析流程
 &lt;a class="anchor" href="#%e8%a7%a3%e6%9e%90%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>1).&lt;/code> 以&lt;code>ClassPathXmlApplicationContext&lt;/code>为例，新建一个应用上下文：&lt;code>new ClassPathXmlApplicationContext(&amp;quot;_framework/spring/res/factory-bean.xml&amp;quot;);&lt;/code>
&lt;br>&lt;span style='padding-left:2.8em' />&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-01.png" alt="" width="70%">
&lt;br>&lt;br>&lt;code>2).&lt;/code> 紧接着通过&lt;code>super(parent)&lt;/code>调用父类构造器，一直往上传，直到&lt;code>AbstractApplicationContext&lt;/code>,调用自己无参构造器&lt;code>this();&lt;/code>后，使用&lt;code>setParent(parent);&lt;/code>设置父属性。
&lt;br>&lt;span style='padding-left:2.8em' />在&lt;code>this()&lt;/code>内部获取一个&lt;code>PathMatchingResourcePatternResolver()&lt;/code>.
&lt;br>&lt;br>&lt;code>3).&lt;/code> 然后是设置配置文件位置&lt;code>setConfigLocations(configLocations);&lt;/code>,对于每一个配置文件，都会通过&lt;code>getEnvironment()&lt;/code>获取环境变量&lt;code>StandardEnvironment&lt;/code>对象解决(&lt;del>配置文件&lt;/del>)配置文件路径中的占位符。
&lt;br>&lt;br>&lt;code>4).&lt;/code> 接下来进入主题&lt;code>AbstractApplicationContext#refresh();&lt;/code>
&lt;br>&lt;span style='padding-left:2.8em' />&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-02.png" alt="" width="70%" height="550p">&lt;/p>
&lt;ul>
&lt;li>
&lt;h4 id="refresh">
 refresh()
 &lt;a class="anchor" href="#refresh">#&lt;/a>
&lt;/h4>
&lt;ul>
&lt;li>
&lt;h5 id="01-preparerefresh">
 01). prepareRefresh()
 &lt;a class="anchor" href="#01-preparerefresh">#&lt;/a>
&lt;/h5>
&lt;p class="warn">
&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-03.png" alt="" width="59%"> &lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-04.png" alt="" width="34%">
&lt;br>对于刷新这个上下文做准备。记录启动时间，关闭状态，激活状态。
&lt;br>以及留给子类去初始化propertySource的方法&lt;code>initPropertySources();&lt;/code>，
&lt;br>获取环境并校验通过&lt;code>ConfigurablePropertyResolver#setRequiredProperties&lt;/code>设置的必需属性，委托给 &lt;strong>AbstractPropertyResolver&lt;/strong> 去执行校验。
&lt;br>另外准备一个保存&lt;strong>应用事件&lt;/strong>的set容器。&lt;/p>
&lt;/li>
&lt;li>
&lt;h5 id="02-obtainfreshbeanfactory">
 02). obtainFreshBeanFactory()
 &lt;a class="anchor" href="#02-obtainfreshbeanfactory">#&lt;/a>
&lt;/h5>
&lt;p class="warn">
&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-05.png" alt="" width="49%">
&lt;br>获取一个新的bean工厂。
&lt;br>&lt;br>&lt;code>protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;&lt;/code>由子类去处理。
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-06.png" alt="" width="60%">
&lt;br>&lt;br>通过&lt;code>createBeanFactory()&lt;/code>方法new一个 &lt;strong>DefaultListableBeanFactory&lt;/strong> bean工厂
&lt;br>&lt;br>&lt;code>customizeBeanFactory(beanFactory);&lt;/code>根据需要设置bean定义覆盖和循环引用的标志。
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-07.png" alt="" width="60%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h6 id="021-loadbeandefinitions">
 02.1). loadBeanDefinitions
 &lt;a class="anchor" href="#021-loadbeandefinitions">#&lt;/a>
&lt;/h6>
&lt;p class="warn">&lt;code>loadBeanDefinitions(beanFactory);&lt;/code>加载bean定义，是抽象类&lt;code>AbstractRefreshableApplicationContext&lt;/code>中定义的方法，由子类&lt;code>AbstractXmlApplicationContext&lt;/code>去实现。
&lt;br>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/00-spring-startup/ss-08.png" alt="" width="60%">
&lt;br>&lt;br>创建beanDefinitionReader，传递benafactory给父类&lt;code>AbstractBeanDefinitionReader&lt;/code>初始化 &lt;strong>resourceLoader&lt;/strong> 和 &lt;strong>environment&lt;/strong> 属性。但是在后续步骤中，使用了applicationContext的环境覆盖了自己刚才初始化的，包括ResourceLoader也一样。&lt;span style='color:blue'>并且在reader对象中保存当前beanfactory，方便后续进行操作。&lt;/span>
&lt;br>&lt;br>&lt;strong>initBeanDefinitionReader(beanDefinitionReader)&lt;/strong> ，初始化reader属性，比如设置validate=true.
&lt;br>&lt;strong>loadBeanDefinitions(beanDefinitionReader)&lt;/strong> ，使用reader从配置文件中加载beandefinitions到beanfactory中。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springcore/01_factory_bean/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springcore/01_factory_bean/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introfactorybean">
 Intro(FactoryBean)
 &lt;a class="anchor" href="#introfactorybean">#&lt;/a>
&lt;/h2>
&lt;p class="warn">&lt;code>spring.version = 4.3.7.RELEASE&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="准备编码">
 准备编码
 &lt;a class="anchor" href="#%e5%87%86%e5%a4%87%e7%bc%96%e7%a0%81">#&lt;/a>
&lt;/h3> &lt;div class="docsify-example-panels"> &lt;div class="docsify-example-panel left-panel"style="max-width: 50%; width: 50%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">// 创建普通bean
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Tool {

 private int id;

}

// 创建工厂
@Data
public class ToolFactory implements FactoryBean&amp;lt;Tool&amp;gt; {

 private int factoryId;

 private int toolId;

 @Override
 public Tool getObject() throws Exception {
 return new Tool(toolId);
 }

 @Override
 public Class&amp;lt;?&amp;gt; getObjectType() {
 return Tool.class;
 }

 @Override
 public boolean isSingleton() {
 return false;
 }
}
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
 &lt;div class="docsify-example-panel right-panel"style="max-width: 50%; width: 50%;">
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="xml" data-line="" class="language-xml line-numbers" style="max-height: none">&lt;code class="language-xml">&amp;lt;!-- factory-bean.xml --&amp;gt;

&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;beans xmlns=&amp;quot;http://www.springframework.org/schema/beans&amp;quot;
 xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
 xsi:schemaLocation=&amp;quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&amp;quot;&amp;gt;

 &amp;lt;!-- FactoryBean work process --&amp;gt;
 &amp;lt;bean id=&amp;quot;toolFB&amp;quot; class=&amp;quot;_framework.spring.factory_bean.beans.ToolFactory&amp;quot;&amp;gt;
 &amp;lt;property name=&amp;quot;factoryId&amp;quot; value=&amp;quot;9090&amp;quot; /&amp;gt;
 &amp;lt;property name=&amp;quot;toolId&amp;quot; value=&amp;quot;2&amp;quot; /&amp;gt;
 &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">public class SpringFactoryBeanTest {

 public static void main(String[] args) {

 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(&amp;quot;_framework/spring/res/factory-bean.xml&amp;quot;);
 ToolFactory fb = applicationContext.getBean(&amp;quot;&amp;amp;toolFB&amp;quot;, ToolFactory.class);
 Tool tool1 = applicationContext.getBean(Tool.class);
 Tool tool2 = applicationContext.getBean(Tool.class);
 System.out.println();
 applicationContext.destroy();

 }

}
&lt;/code>&lt;/pre>&lt;/div>&lt;/div>&lt;/div>

&lt;/li>
&lt;li>
&lt;h3 id="解析流程">
 解析流程
 &lt;a class="anchor" href="#%e8%a7%a3%e6%9e%90%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>1).&lt;/code> 初始化bean对象：在&lt;code>refresh()&lt;/code>里面通过&lt;code>obtainFreshBeanFactory()&lt;/code>方法创建扫描到beanDefinition的顶级工厂。然后通过方法&lt;code>finishBeanFactoryInitialization(beanFactory);&lt;/code>实例化所有非懒加载的所有单例bean,此处就包含这个工厂bean对象。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springcore/spring-bak/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springcore/spring-bak/</guid><description>&lt;h2 id="spring-是什么">
 spring 是什么
 &lt;a class="anchor" href="#spring-%e6%98%af%e4%bb%80%e4%b9%88">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架，目的是用于简化企业应用程序的开发，它使得开发者只需要关心业务需求。&lt;/p>
&lt;/blockquote>
&lt;h2 id="spring-优点">
 spring 优点
 &lt;a class="anchor" href="#spring-%e4%bc%98%e7%82%b9">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>低入侵，减少代码耦合，支持一些通用任务（鉴权，日志，事务等）的集中管理，对其他一些框架提供集成支持&lt;/p>
&lt;/blockquote>
&lt;h2 id="spring-ioc-理解">
 spring IOC 理解
 &lt;a class="anchor" href="#spring-ioc-%e7%90%86%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>IOC
&lt;blockquote>
&lt;p>IOC(Inversion of control. 控制反转)，将bean对象的控制权交由spring去管理。
其中包括bean对象的创建与销毁，bean对象之间的依赖关系等。简单来讲，就是对象不用我们去new了，而是框架帮我们使用反射的方式去创建。
用户只需要在使用的时候注入即可。&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>DI
&lt;blockquote>
&lt;p>DI (dependency inject ,依赖注入)，程序运行期间如果发现对象需要依赖其他的对象。就会通过反射的方式自动处理依赖关系。
反射的功能就是在程序运行期间动态的生成对象，执行对象的方法，改变对象的属性等功能。&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;h2 id="spring-aop-理解">
 spring AOP 理解
 &lt;a class="anchor" href="#spring-aop-%e7%90%86%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>AOP 面向切面编程。作为面向对象的一种补充，用于将那些与业务无关，但却对多个对象产生影响的公共行为和逻辑，抽取并封装为一个可重用的模块，这个模块被命名为“切面”（Aspect），减少系统中的重复代码，降低了模块间的耦合度，提高系统的可维护性。可用于权限认证、日志、事务处理。
编程中使用cglib和jdk两种动态代理来实现。&lt;/p>
&lt;/blockquote>
&lt;h2 id="beanfactory-和-applicationcontext区别">
 BeanFactory 和 ApplicationContext区别
 &lt;a class="anchor" href="#beanfactory-%e5%92%8c-applicationcontext%e5%8c%ba%e5%88%ab">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>MessageSource
&lt;blockquote>
&lt;p>用于消息资源国际化&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>ResourcePatternResolver
&lt;blockquote>
&lt;p>在上一篇中我们介绍了Resource接口，它的出现是为了解决spring方便访问各种配置信息。
但Resource接口有一个问题，就是如果我们要访问同一个路径下的所有符合条件的配置，如果用Resource接口则会比较麻烦，因为它不支持通配符方式的文件读取，所以要将读取的配置文件名称全部写出来才可以。
spring为了解决这个问题，于是新定义了一个新接口，并实现了该接口特有的特性，也就是支持类似


 &lt;a href="https://ant.apache.org/manual/dirtasks.html#patterns" rel="noopener" target="_blank">Ant风格&lt;/a>的通配符&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>ApplicationEventPublisher
&lt;blockquote>
&lt;p>时间发布器&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>EnvironmentCapable
&lt;blockquote>
&lt;p>提供环境处理能力，getEnvironment()返回的 Environment 不可配置。所以在ConfigurableApplicationContext重新定义getEnvironment()并缩小签名以返回一个ConfigurableEnvironment。在此之前 环境对象 是只读的。&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;h2 id="spring-容器启动流程">
 spring 容器启动流程
 &lt;a class="anchor" href="#spring-%e5%ae%b9%e5%99%a8%e5%90%af%e5%8a%a8%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>启动流程&lt;/p>
 &lt;details>&lt;summary>代码示例&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@Override
public void refresh() throws BeansException, IllegalStateException {
 synchronized (this.startupShutdownMonitor) {
 // Prepare this context for refreshing.
 // 准备这个上下文以便刷新，设置它的启动日期和活动标志，并执行PropertySource属性源的任何初始化。
 prepareRefresh();

 // Tell the subclass to refresh the internal bean factory.
 // DefaultListableBeanFactory beanFactory = createBeanFactory();
 // beanFactory.setSerializationId(getId());
 // customizeBeanFactory(beanFactory);
 // loadBeanDefinitions(beanFactory);
 // 如果开启包扫描，会默认加载6个bd,(根据环境不同，可能数量有变，比如还可能有EJB的) 参见下图
 // class org.springframework.context.annotation.ConfigurationClassPostProcessor
 // class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
 // class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
 // class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
 // CommonAnnotationBeanPostProcessor 是根据 jsr250 加载的。
 // private static final boolean jsr250Present = ClassUtils.isPresent(&amp;quot;javax.annotation.Resource&amp;quot;, AnnotationConfigUtils.class.getClassLoader());
 // class org.springframework.context.event.DefaultEventListenerFactory
 // class org.springframework.context.event.EventListenerMethodProcessor
 // return beanFactory;
 // 一般来说ApplicationContext自己没有实现BeanFactory相关方法，而是委托给自己刚才实例化的属性 beanFactory 来实现BeanFactory效果的。
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

 // Prepare the bean factory for use in this context.
 // 初始化 beanFactory 相关属性。
 prepareBeanFactory(beanFactory);

 try {
 // Allows post-processing of the bean factory in context subclasses.
 // 让子类继续处理 beanFactory 增加或修改属性。比如WebApplicationContext
 // beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
 // beanFactory.ignoreDependencyInterface(ServletContextAware.class);
 // beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
 // WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
 // WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
 postProcessBeanFactory(beanFactory);

 // Invoke factory processors registered as beans in the context.
 // 调用在上下文中已注册为bean的工厂处理器，来增加或修改属性。
 // 比如ConfigurationClassPostProcessor。创建了一个org.springframework.context.annotation.internalConfigurationAnnotationProcessor对象。
 // 且给beanFactory的属性：beanPostProcessors 增加了一个 ImportAwareBeanPostProcessor。

 // 1027追加注释 
 // 内部逻辑先找 实现了BeanDefinitionRegistryPostProcessor接口的 实例化然后按顺序进行接口调用。因为这个接口继承自BeanFactoryPostProcessor.所以还会对这个接口也进行调用。
 // 然后是其余的BeanFactoryPostProcessor 这个接口 实例化后再按照顺序进行接口调用
 invokeBeanFactoryPostProcessors(beanFactory);

 // Register bean processors that intercept bean creation.
 // 向容器中实例化BeanPostProcessor，并追加到beacFactory的属性：beanPostProcessors中。

 // 1027追加注释 
 // 和上面调用一样，不过这次找的是BeanPostProcessor接口，另外会追加属性 到 beanPostProcessors中。因为这个接口的功能是对Bean的创建进行拦截处理实例用的。而不是修改beanDefinition用的。
 registerBeanPostProcessors(beanFactory);

 // Initialize message source for this context.
 initMessageSource();

 // Initialize event multicaster for this context.
 initApplicationEventMulticaster();

 // Initialize other special beans in specific context subclasses.
 // 对于EmbedWebApplicationContext 调用 createEmbeddedServletContainer();
 onRefresh();

 // Check for listener beans and register them.
 registerListeners();

 // Instantiate all remaining (non-lazy-init) singletons.
 finishBeanFactoryInitialization(beanFactory);

 // Last step: publish corresponding event.
 finishRefresh();
 }
 // ...
 }
}
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/details>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/spring/xmlac-load-bd.png" alt="" width="65%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/spring/springmvc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/spring/springmvc/</guid><description>&lt;h2 id="springmvc-执行流程">
 springmvc 执行流程
 &lt;a class="anchor" href="#springmvc-%e6%89%a7%e8%a1%8c%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h2>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/springmvc/process.png" alt="">&lt;/p>
&lt;h2 id="过滤器">
 过滤器
 &lt;a class="anchor" href="#%e8%bf%87%e6%bb%a4%e5%99%a8">#&lt;/a>
&lt;/h2>
&lt;h2 id="拦截器">
 拦截器
 &lt;a class="anchor" href="#%e6%8b%a6%e6%88%aa%e5%99%a8">#&lt;/a>
&lt;/h2>
&lt;h2 id="数据绑定">
 数据绑定
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e7%bb%91%e5%ae%9a">#&lt;/a>
&lt;/h2>
&lt;h2 id="消息转换器">
 消息转换器
 &lt;a class="anchor" href="#%e6%b6%88%e6%81%af%e8%bd%ac%e6%8d%a2%e5%99%a8">#&lt;/a>
&lt;/h2>
&lt;h2 id="异常处理">
 异常处理
 &lt;a class="anchor" href="#%e5%bc%82%e5%b8%b8%e5%a4%84%e7%90%86">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>注解ExceptionHandler&lt;/p>
&lt;blockquote>
&lt;p>注解ExceptionHandler作用对象为方法，最简单的使用方法就是放在controller文件中，详细的注解定义不再介绍。
如果项目中有多个controller文件，通常可以在baseController中实现ExceptionHandler的异常处理，而各个contoller继承basecontroller从而达到统一异常处理的目的。因为比较常见，简单代码如下：&lt;/p>
&lt;/blockquote>
 &lt;details>&lt;summary>单个controller处理&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@ExceptionHandler(Exception.class)
@ResponseBody
public String exceptionHandler(Exception ex){
 return this.getClass().getSimpleName() + &amp;quot;: &amp;quot; + ex.getMessage();
} 
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/details>
&lt;/li>
&lt;li>
&lt;p>注解ControllerAdvice&lt;/p>
&lt;blockquote>
&lt;p>这里虽说是ControllerAdvice注解，其实是其与ExceptionHandler的组合使用。
在上文中可以看到，单独使用@ExceptionHandler时，其必须在一个Controller中，然而当其与ControllerAdvice组合使用时就完全没有了这个限制。换句话说，二者的组合达到的全局的异常捕获处理。&lt;/p>
&lt;p>&lt;code>***&lt;/code> 注解ControllerAdvice 等级低于第一个。而且第一个只处理当前Controller。顺序为 @ExceptionHandler,@ControllerAdvice,HandlerExceptionResolver&lt;/p>
&lt;/blockquote>
 &lt;details>&lt;summary>全局异常处理&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="java" data-line="" class="language-java line-numbers" style="max-height: none">&lt;code class="language-java">@ControllerAdvice
public class ExceptionHandlerAdvice {
 //也可以出现 自定义Exception，和其他Exception
 @ExceptionHandler(Exception.class)
 @ResponseBody
 public String exceptionHandler(Exception ex){
 return this.getClass().getSimpleName() + &amp;quot;: &amp;quot; + ex.getMessage();
 }
} 
&lt;/code>&lt;/pre>&lt;/div>
 &lt;/details>
&lt;/li>
&lt;li>
&lt;p>实现HandlerExceptionResolver接口&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/tomcat/tomcat-core/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/tomcat/tomcat-core/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introtomcat-core">
 Intro(TOMCAT-CORE)
 &lt;a class="anchor" href="#introtomcat-core">#&lt;/a>
&lt;/h2>
&lt;p class="tip">tomcat.version = 8.5.35
&lt;br> 


 &lt;a href="https://github.com/apache/tomcat/tree/8.5.35" rel="noopener" target="_blank">offical git repo | tag = 3.5.35&lt;/a> &lt;span style='padding-left:5em' /> 


 &lt;a href="https://github.com/12302-bak/tomcat-analysis" rel="noopener" target="_blank">learning git repo&lt;/a>
&lt;br> 


 &lt;a href="https://tomcat.apache.org/tomcat-8.5-doc/introduction.html" rel="noopener" target="_blank">tomcat-8.5-doc&lt;/a>
&lt;br> 


 &lt;a href="https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.35/" rel="noopener" target="_blank">download 8.5.35&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/tomcat/core/tomcat-process-01.png" alt="" width="100%">&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/tomcat/core/tomcat-process-02.png" alt="" width="100%">&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="概念解释">
 概念解释
 &lt;a class="anchor" href="#%e6%a6%82%e5%bf%b5%e8%a7%a3%e9%87%8a">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="整体架构">
 整体架构
 &lt;a class="anchor" href="#%e6%95%b4%e4%bd%93%e6%9e%b6%e6%9e%84">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> Connector（【coyote】处理socket连接，负责网络字节流）
&lt;br> Container（【Catalina】加载servlet处理具体请求）&lt;/p>
&lt;p>


 &lt;a href="https://stackoverflow.com/questions/32985051/what-are-the-tomcat-component-what-is-catalina-and-coyote" rel="noopener" target="_blank">https://stackoverflow.com/questions/32985051/what-are-the-tomcat-component-what-is-catalina-and-coyote&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="启动流程">
 启动流程
 &lt;a class="anchor" href="#%e5%90%af%e5%8a%a8%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> 先是初始化
&lt;br>BootStrap-&amp;gt;Calaline-&amp;gt;Server-&amp;gt;Service
&lt;br>BootStrap-&amp;gt;Calaline-&amp;gt;Server-&amp;gt;Service-&amp;gt;[Engine-&amp;gt;Host-&amp;gt;Context]
&lt;br>BootStrap-&amp;gt;Calaline-&amp;gt;Server-&amp;gt;Service-&amp;gt;[Executor]
&lt;br>BootStrap-&amp;gt;Calaline-&amp;gt;Server-&amp;gt;Service-&amp;gt;[ProtocalHandler]
&lt;br>然后调用start启动整个tomcat&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="io模型和协议">
 I/O模型和协议
 &lt;a class="anchor" href="#io%e6%a8%a1%e5%9e%8b%e5%92%8c%e5%8d%8f%e8%ae%ae">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> BIO，NIO，AIO（NIO2），APR
&lt;br>HTTP/1.1，HTTP/2，AJP（用于和apache服务器集成用来处理静态资源）&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="jasper引擎">
 Jasper引擎
 &lt;a class="anchor" href="#jasper%e5%bc%95%e6%93%8e">#&lt;/a>
&lt;/h3>
&lt;p class="warn">index.jsp -&amp;gt; jspServlet(找到文件) -&amp;gt; 渲染成servlet.class-&amp;gt; 加载调用&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h3>
&lt;p class="warn">官方不建议直接在server.xml中配置，因为，server.xml文件只会在tomcat重新的时候重新加载。&lt;/p>
&lt;ol>
&lt;li>In an individual file at /META-INF/context.xml inside the application files&lt;/li>
&lt;li>In individual files (with a &amp;ldquo;.xml&amp;rdquo; extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory&lt;/li>
&lt;li>Inside a Host element in the main conf/server.xml.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h3 id="安全">
 安全
 &lt;a class="anchor" href="#%e5%ae%89%e5%85%a8">#&lt;/a>
&lt;/h3>
&lt;p class="warn">&lt;code>1).&lt;/code> 删除webapp下面的管理页面和其他项目
&lt;br>&lt;code>2).&lt;/code> 禁用server-user.xml里面的权限或者直接删除
&lt;br>&lt;code>3).&lt;/code> 修改tomcat默认关机指令，或者禁用
&lt;br>&lt;code>4).&lt;/code> 配置错误页面。&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/zookeeper/install/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/zookeeper/install/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introzookeeper">
 Intro(Zookeeper)
 &lt;a class="anchor" href="#introzookeeper">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h2 id="压缩包安装">
 压缩包安装
 &lt;a class="anchor" href="#%e5%8e%8b%e7%bc%a9%e5%8c%85%e5%ae%89%e8%a3%85">#&lt;/a>
&lt;/h2>
&lt;h6 id="docker" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="centos7" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;h6 id="ubuntu" class="anchor_hr" style="font-size: 0rem; margin: 0; padding: 0; border-width: 0px;">&lt;/h6>&lt;div class="docsify-tabs docsify-tabs--classic">&lt;button anchorId="docker" class="docsify-tabs__tab" data-tab="Docker">Docker&lt;/button>&lt;div class="docsify-tabs__content" data-tab-content="docker">
&lt;ol>
&lt;li>配置环境&lt;/li>
&lt;/ol>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 启动服务器
$ docker run -d -p 2181:2182 --name zookeeper-3.6.3 zookeeper:3.6.3

# 使用自定义的配置文件
$ docker run -d -p 2181:2182 -v $(pwd)/zoo.cfg:/conf/zoo.cfg --restart always --name zookeeper-3.6.3 zookeeper:3.6.3
&lt;/code>&lt;/pre>&lt;/div>
&lt;ol start="2">
&lt;li>测试&lt;/li>
&lt;/ol>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># 使用redis容器内部客户端进行访问
$ docker run -it --rm --network host zookeeper:3.6.3 zkCli.sh -server 127.0.0.1[:2181]
&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/doc/framework/redis/redis-install-dcoker-01.png" alt="" width="100%">&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/doc/framework/zookeeper/zk/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/doc/framework/zookeeper/zk/</guid><description>&lt;h2 id="zk-简介">
 ZK 简介
 &lt;a class="anchor" href="#zk-%e7%ae%80%e4%bb%8b">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>zab协议&lt;/p>
&lt;p>description&lt;/p>
&lt;/blockquote>
&lt;h2 id="zk-实现原理">
 ZK 实现原理
 &lt;a class="anchor" href="#zk-%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86">#&lt;/a>
&lt;/h2>
&lt;h2 id="zk-常用命令">
 ZK 常用命令
 &lt;a class="anchor" href="#zk-%e5%b8%b8%e7%94%a8%e5%91%bd%e4%bb%a4">#&lt;/a>
&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>command&lt;/th>
&lt;th>function&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>help&lt;/td>
&lt;td>显示所有命令操作&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ls path [watch]&lt;/td>
&lt;td>使用ls 命令来查看当前znode中所包含的内容&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ls2 path [watch]&lt;/td>
&lt;td>查看当前节点数据，并能看到更新次数等数据&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>create&lt;/td>
&lt;td>普通创建 -s 含有序列，-e 临时（重启或者超时消失）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>get path [watch]&lt;/td>
&lt;td>获得节点值&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>set&lt;/td>
&lt;td>设置节点具体值&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>stat&lt;/td>
&lt;td>查看节点状态&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>delete&lt;/td>
&lt;td>删除节点&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>rmr&lt;/td>
&lt;td>递归删除节点&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="zk-stat-结构">
 ZK stat 结构
 &lt;a class="anchor" href="#zk-stat-%e7%bb%93%e6%9e%84">#&lt;/a>
&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>show&lt;/th>
&lt;th>explain&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>cZxid = 0x20000000e&lt;/td>
&lt;td>create 创建znode更改的事务ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ctime = Thu Aug 04 09: 33:08 UTC 2022&lt;/td>
&lt;td>create znode 创建时间&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>mZxid = 0x20000000e&lt;/td>
&lt;td>modify 修改znode更改的事务ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>mtime = Thu Aug 04 09:33:08 UTC 2022&lt;/td>
&lt;td>modify 修改时间&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>pZxid = 0x20000000e&lt;/td>
&lt;td>p&amp;hellip;. 添加或删除子节点的znode更改事务ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>cversion = 0&lt;/td>
&lt;td>表示对此znode子节点进行更改的次数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>dataVersion = 0&lt;/td>
&lt;td>表示对此znode数据的更改次数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>aclVersion = 0&lt;/td>
&lt;td>表示对此znode的ACL进行更改的次数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ephemeralOwner = 0x0&lt;/td>
&lt;td>ephemeral类型？znode 所有者session Id : 0&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>dataLength = 11&lt;/td>
&lt;td>znode 数据字段长度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>numChildren = 0&lt;/td>
&lt;td>znode 的子节点的数量&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="zk-应用">
 ZK 应用
 &lt;a class="anchor" href="#zk-%e5%ba%94%e7%94%a8">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>共享锁
&lt;ul>
&lt;li>explain&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>description&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/frida/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/frida/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introfrida">
 Intro(FRIDA)
 &lt;a class="anchor" href="#introfrida">#&lt;/a>
&lt;/h2>
&lt;p class="tip">APK 加固信息
&lt;br> 通过MT文件管理器 -&amp;gt; 安装包提取(左侧菜单) -&amp;gt; 选择应用，查看加固状态&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="sh" data-line="" class="language-sh line-numbers" style="max-height: none">&lt;code class="language-sh"># app-demo
site.example.framework

# 哔哩哔哩
tv.danmaku.bili

# 个人所得税
cn.gov.tax.its

# 交管12302
com.tmri.app.main
&lt;/code>&lt;/pre>&lt;/div>
&lt;p class="warn"> command
&lt;br>&lt;br> &lt;code>frida -D 192.168.1.200:5544 -l agent/frida_multiple_unpinning.js -f com.tmri.app.main -F&lt;/code>
&lt;br> &lt;code>frida -U -f com.example.seccon2015.rock_paper_scissors -l _agent.js&lt;/code>
&lt;br> &lt;code>frida --debug --runtime=v8 -U -f com.example.seccon2015.rock_paper_scissors -l _agent.js&lt;/code>
&lt;br> &lt;code>frida -D local -l _lesson/function.js -n hello&lt;/code>
&lt;br> &lt;code>frida-ps -D 192.168.1.200:5544 -a&lt;/code>
&lt;br> &lt;code>frida-ps -D local | grep hello&lt;/code>
&lt;br>&lt;br>&lt;code>adb shell pm path&lt;/code>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/imhex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/imhex/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introimhex--十六进制编辑器">
 Intro(ImHex | 十六进制编辑器)
 &lt;a class="anchor" href="#introimhex--%e5%8d%81%e5%85%ad%e8%bf%9b%e5%88%b6%e7%bc%96%e8%be%91%e5%99%a8">#&lt;/a>
&lt;/h2>
&lt;p class="tip">一个瑞士小孩哥使用 C++23 写的开源 &lt;strong>十六进制编辑器&lt;/strong>，主要包括十六进制预览（Hex editor），单多字节数据编码（data inspector）,基于节点的预处理器（data processor）,书签列表（Bookmarks），一些其他内置工具，数据分析和图表可视统计，使用向导，在线商店，其中包括各路大神写的（类库，magic文件，编码集等）。
&lt;br>当然，最主要，也是最核心的就是下面需要单独介绍的 


 
 

 
 
 
 
 
 
 
 &lt;a href='#imhex-pattern-language' rel="noopener" class="internal-link" data-src="#imhex-pattern-language">模式语言&lt;/a>（暂且这么翻译）。
&lt;br>&lt;br>使用场景：
&lt;br>针对某个实例文件，结合模式语言，展现结构列表，可视化二进制数据。比如


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/doc/advance/bytecode/#%e4%bd%bf%e7%94%a8imhex%e5%88%86%e6%9e%90' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/doc/advance/bytecode/#%e4%bd%bf%e7%94%a8imhex%e5%88%86%e6%9e%90">分析 java 字节码&lt;/a>，


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/corner/file-format/riff/' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/corner/file-format/riff/">RIFF,ANI 文件格式分析&lt;/a>，或者 


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/devops/os/core/fs/ext2/' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/devops/os/core/fs/ext2/">分析 ext2 文件系统&lt;/a> 等。
&lt;br>&lt;br>当前使用版本 


 &lt;a href="https://github.com/WerWolv/ImHex/releases/tag/v1.37.4" rel="noopener" target="_blank">v1.37.4&lt;/a>
&lt;br>优点的话：开源，看不惯的话可以改。马上快 50K 的星标了，你想想。
&lt;br>缺点目前来说的话，就是，macosx 上面一不小心就闪退了，window上面保存项目文件，不知道死哪儿去了。数据处理器不能复用，另外模式语言部分的文档缺少示例，api 文档定义跟开玩笑一样。
&lt;br>&lt;br>软件使用 


 &lt;a href="https://docs.werwolv.net/imhex" rel="noopener" target="_blank">官方文档&lt;/a>。
&lt;br>开源仓库 


 &lt;a href="https://github.com/WerWolv/ImHex" rel="noopener" target="_blank">地址&lt;/a>。&lt;/p>
&lt;/li>
&lt;li>
&lt;h2 id="imhex-pattern-language">
 ImHex Pattern language
 &lt;a class="anchor" href="#imhex-pattern-language">#&lt;/a>
&lt;/h2>
&lt;p class="warn">ImHex 的精髓所在。简单的理解，就是通过模式编辑器（Pattern editor），通过编程的方式将二进制文件按照内存地址解析成对应的模式(变量)，并通过 Pattern Data 视图窗口将数据展示出来，可以自定义展示数据格式，颜色等，数据布局，格式分布一目了然。类比于 Java POJO中的 toString()。


 &lt;a href="https://docs.werwolv.net/pattern-language" rel="noopener" target="_blank">参考文档&lt;/a>
&lt;br>&lt;br>如果有&lt;code>main&lt;/code>函数会直接调用。&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="前期准备">
 前期准备
 &lt;a class="anchor" href="#%e5%89%8d%e6%9c%9f%e5%87%86%e5%a4%87">#&lt;/a>
&lt;/h3>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" data-file="字节数据" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">4D 5A 90 00 03 00 00 00 04 00 00 00 FF 01 00 00 B8 00 00 00 00 00 06 00 40 00 00 00 00 00 1A 41 00 00 20 00 40 00 21 00 1A 2D 44 54 FB 21 09 40 00 00 00 05 00 80 C3 8D 00 01 02 00 00 00 00 00 54 C9 A7 0A F5 A0 A5 0B 52 69 63 68 F4 A0 A5 0B 00 01 02 68 65 6C 6C 6F 00 69 51 44 75 2E 00 00 00 00 00 00 02 94 5F 00 00 00 00 00 00 00 00 00
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> 准备一份分析用的二进制数据 &lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/jetta/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/jetta/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intro2024款-280tsi-手动先锋版httpswwwautohomecomcnspec67292pvareaid3454492">
 Intro(


 &lt;a href="https://www.autohome.com.cn/spec/67292#pvareaid=3454492" rel="noopener" target="_blank">2024款 280TSI 手动先锋版&lt;/a>)
 &lt;a class="anchor" href="#intro2024%e6%ac%be-280tsi-%e6%89%8b%e5%8a%a8%e5%85%88%e9%94%8b%e7%89%88httpswwwautohomecomcnspec67292pvareaid3454492">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>
&lt;h4 id="确认">
 确认
 &lt;a class="anchor" href="#%e7%a1%ae%e8%ae%a4">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>有没有现车，颜色有哪些？几月份生产的？合格证？&lt;/li>
&lt;li>可不可以代办【异地临牌】，多长时间？（如果缴纳订金自己去办理）。&lt;/li>
&lt;li>全国联保【平安，人保】？保险（交强险，三者险，车损险，驾乘险【几十】，医保外用药【100+】）&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="流程">
 流程
 &lt;a class="anchor" href="#%e6%b5%81%e7%a8%8b">#&lt;/a>
&lt;/h4>
&lt;ul>
&lt;li>先去看车，有没有现车，合格证（确保当天可以提车）&lt;/li>
&lt;li>&lt;strong>砍价&lt;/strong>，&lt;/li>
&lt;li>签购车合同，
0. 车辆品牌，型号，配置，外观内饰颜色, 生产日期，
&lt;ol>
&lt;li>签订合同价格明细(裸车价，保险，上牌，购置税）&lt;/li>
&lt;li>购车合同必须注明是新车，不要（展车，库存车，试驾车，有损车等）&lt;/li>
&lt;li>注明提车日期（逾期未交车，定金全额退款，或者延迟赔付，现金补偿）&lt;/li>
&lt;li>定金/订金？&lt;/li>
&lt;li>谈好的 赠品/随车工具,&lt;/li>
&lt;li>备注除了以上费用外，无任何其他费用。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>&lt;del>订金（全额退款）？&lt;/del>&lt;/li>
&lt;li>验车，
&lt;ul>
&lt;li>生产日期
&lt;ul>
&lt;li>车辆铭牌（车架号，挡风玻璃下方也有）&lt;/li>
&lt;li>轮胎日期（四个数字，周数+年数，五个轮胎生产日期一般不要过早于汽车生产日期）&lt;/li>
&lt;li>玻璃日期（数字代表年份，点代表月份，点前七减，点后13减。比如&lt;code>1...&lt;/code>1代表21年，点后就是13-3=10，就是21年10月份）&lt;/li>
&lt;li>发动机&lt;/li>
&lt;li>电瓶&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>外观
&lt;ul>
&lt;li>漆面（是否有划痕，漆面是否完整，有没有坑洼，检查前后挡风，天窗，车窗是否有细微的裂痕）&lt;/li>
&lt;li>轮胎（是否有鼓包）&lt;/li>
&lt;li>前后雨刮器（前后雨刮是否正常运行，喷水是否正常）&lt;/li>
&lt;li>车门（开关车门是否有异响，连接处是否严丝合缝）&lt;/li>
&lt;li>底盘（抬高底盘观察是否有磕碰，漏油）&lt;/li>
&lt;li>前挡风玻璃（没有国家安全玻璃认证标志的话可能换过）&lt;/li>
&lt;li>保险杠（有无明显变形，损坏，有误校正，重新补漆的痕迹）&lt;/li>
&lt;li>后备箱（查看密合度，是否异响）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>车内
&lt;ul>
&lt;li>仪表盘（一般总公里数 &amp;lt;= 50，检查胎压是否正常）&lt;/li>
&lt;li>坐椅（坐椅是否有损坏，划痕，调节是否顺畅，安全带回弹）&lt;/li>
&lt;li>中控屏（开机是否流畅，会不会卡顿，车机功能使用是否正常）&lt;/li>
&lt;li>天窗（开关是否正常，出现异响）&lt;/li>
&lt;li>空调（制冷，暖气，出风是否正常）&lt;/li>
&lt;li>车灯（远近光灯，前后雾灯，到车灯，报警闪光灯，示廓灯，刹车灯是否正常）&lt;/li>
&lt;li>后备箱（开关是否正常，配件是否齐全（三脚架，反光背心，备胎，换台工具，千斤顶，灭火器）&lt;/li>
&lt;li>启动（开车检测一键启动，驻车系统，刹车油门是否正常）&lt;/li>
&lt;li>发动机（刹车油，冷却液，玻璃水，机油是否在正常刻度）&lt;/li>
&lt;li>排气管（手摸内壁是否严重发黑）&lt;/li>
&lt;li>PDI 检测单（查看各项标准是否全部合格，重点看启动电池电压是否达标）&lt;/li>
&lt;li>导航（确认车辆的导航已经激活并且可以使用）&lt;/li>
&lt;li>各个接口（检查收音机，USB，HDMI,AUX，蓝牙，音响系统是否正常使用）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>正常行驶（离合，油门，刹车，挂挡）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>交钱,&lt;/li>
&lt;li>办理异地临牌。&lt;/li>
&lt;li>
&lt;h5 id="提车必拿">
 提车必拿
 &lt;a class="anchor" href="#%e6%8f%90%e8%bd%a6%e5%bf%85%e6%8b%bf">#&lt;/a>
&lt;/h5>
&lt;ul>
&lt;li>&lt;del>车辆登记证书（大本，绿本）&lt;/del>，&lt;/li>
&lt;li>车钥匙两把，&lt;/li>
&lt;li>车辆行驶证，车辆合格证，车辆一致性证书，&lt;/li>
&lt;li>保单，&lt;/li>
&lt;li>购车合同，&lt;/li>
&lt;li>四联发票（个人三联[购车发票，注册登记，抵扣]），三包凭证，首保卡，保养手册，车辆说明书等&lt;/li>
&lt;li>赠品（写入合同）【油卡，保养卡（包含工时），延保，[行车记录仪，倒车影像，玻璃膜，脚垫]】&lt;/li>
&lt;li>随车工具【三脚架，反光背心，备胎，换台工具，千斤顶，灭火器k】&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h5 id="后续">
 后续：
 &lt;a class="anchor" href="#%e5%90%8e%e7%bb%ad">#&lt;/a>
&lt;/h5>
&lt;ol>
&lt;li>本地上牌&lt;/li>
&lt;li>12123 备案非本人机动车&lt;/li>
&lt;li>自己收拾（记录仪，脚垫，玻璃膜，手机支架，座垫，装饰，香薰）&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h4 id="备注">
 备注：
 &lt;a class="anchor" href="#%e5%a4%87%e6%b3%a8">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>现金优惠，综合优惠？&lt;/li>
&lt;li>贷款买车和全款买车哪个更合适？&lt;/li>
&lt;li>防止保修手册被扣留，厂家400电话/12315&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="砍价">
 砍价
 &lt;a class="anchor" href="#%e7%a0%8d%e4%bb%b7">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>贷款（今天带着全款来的，如果价格合适，贷款并不是不能考虑）&lt;/li>
&lt;li>转了好几家店了，您报一个最低的实在价格，随时可以刷卡买车。&lt;/li>
&lt;li>xx 费用就不要有了，如果非要有，你这个价格还得再优惠，&lt;/li>
&lt;li>贷款价格和利息有点不认可。&lt;/li>
&lt;li>你要是能聊，就找老板谈谈，聊不了，今天就到这儿了。&lt;/li>
&lt;li>不要问我多少钱，我说5w, 你也肯定不卖呀，对不对，你说多少钱，还能聊，就再帮我争取一下。&lt;/li>
&lt;li>给个可以买的价格，要不你就找领导请示一下，别一口咬死了，&lt;/li>
&lt;li>今天过来不是看车，是买车，你想卖车，我想买车，价格合适就成一单。&lt;/li>
&lt;li>现在这个价格还是有点高。&lt;/li>
&lt;li>今天一个人来的，身份证都带来了，价格诚意，立马付款提车。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;h4 id="回合">
 回合
 &lt;a class="anchor" href="#%e5%9b%9e%e5%90%88">#&lt;/a>
&lt;/h4>
&lt;ol>
&lt;li>你这个价格不太诚意，我都转了好几家了，你要是有诚意，我就在这儿谈，你要是没诚意，我就再考虑考虑。&lt;/li>
&lt;li>现在这个价格是降了，但是没有降到我想要的情况，你要觉得行，你就申请申请，要是不不行，那我就撤了。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.autohome.com.cn/spec/67292#pvareaid=3454492" rel="noopener" target="_blank">https://www.autohome.com.cn/spec/67292#pvareaid=3454492&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://jiage.autohome.com.cn/price/carlist/p-67292-2-0-0-0-610100-1-0#pvareaid=2094106" rel="noopener" target="_blank">https://jiage.autohome.com.cn/price/carlist/p-67292-2-0-0-0-610100-1-0#pvareaid=2094106&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/maddy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/maddy/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="intromaddy--自建个人邮箱">
 Intro(Maddy | 自建个人邮箱)
 &lt;a class="anchor" href="#intromaddy--%e8%87%aa%e5%bb%ba%e4%b8%aa%e4%ba%ba%e9%82%ae%e7%ae%b1">#&lt;/a>
&lt;/h2>
&lt;p class="warn">


 &lt;a href="https://github.com/foxcpp/maddy/releases/download/v0.8.1/maddy-0.8.1-x86_64-linux-musl.tar.zst" rel="noopener" target="_blank">下载: maddy-0.8.1-x86_64-linux-musl.tar.zst &lt;/a>
&lt;br>&lt;br>证书操作可参考


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/devops/nginx/nginx/#1%e4%bd%bf%e7%94%a8-acmesh-%e8%87%aa%e5%8a%a8%e5%8c%96%e7%ae%a1%e7%90%86-ssltsl%e8%af%81%e4%b9%a6' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/devops/nginx/nginx/#1%e4%bd%bf%e7%94%a8-acmesh-%e8%87%aa%e5%8a%a8%e5%8c%96%e7%ae%a1%e7%90%86-ssltsl%e8%af%81%e4%b9%a6">DOCS | acme自动化管理证书&lt;/a>
&lt;br>颁发证书：&lt;code>acme.sh --issue --dns dns_tencent -d mail.wtfu.site -d mta-sts.wtfu.site --keylength 2048&lt;/code>
&lt;br>创建目录：&lt;code>mkdir -p /usr/local/nginx/conf/certificate/mail&lt;/code>
&lt;br>安装到 nginx 里面，稍后为 MTA-STS 提供验证。&lt;code>acme.sh --install-cert -d mail.wtfu.site --fullchain-file /usr/local/nginx/conf/certificate/mail/full_chain.pem --key-file /usr/local/nginx/conf/certificate/mail/private.key --reloadcmd &amp;quot;/usr/local/nginx/sbin/nginx -s reload&amp;quot;&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;h3 id="魔法前摇">
 魔法前摇
 &lt;a class="anchor" href="#%e9%ad%94%e6%b3%95%e5%89%8d%e6%91%87">#&lt;/a>
&lt;/h3>
&lt;div class="alert flat attention">&lt;p class="title">&lt;span class="icon icon-attention">&lt;/span> 需要注意： &lt;/p>&lt;p> &lt;code>1.&lt;/code> 使用 maddy 发送非本域邮件的话，必须使用 25 端口转发，根据 


 &lt;a href="https://github.com/foxcpp/maddy/pull/767" rel="noopener" target="_blank">PR:767&lt;/a> 中说明是 RFC 中的标准吧，配置文件中&lt;code>target.remote&lt;/code>部分并没有可以配置可选端口的选项。所以，如果你的 VPS 厂商封锁 TCP 25端口的出口流量的话，你的自建邮箱服务器给其他邮件服务器（gmail，outlook，126之类的）就 gg 了。很不幸，此次使用的是阿里的机器，然后根据搜索说是可以 


 &lt;a href="https://help.aliyun.com/document_detail/56130.html" rel="noopener" target="_blank">解封&lt;/a>，但是发现申请后没毛用，【安全管控｜25端口解封】处仍然是红色的&lt;strong>审核未通过&lt;/strong>，此时距离发送邮件就遥不可及了。但是好在可以使用其他端口委托到 SMPT 中继服务器，继续满足我们对高潮的期待。&lt;/p>
&lt;/p>&lt;/div>
&lt;/li>
&lt;li>
&lt;h3 id="邮箱服务器形态">
 邮箱服务器形态
 &lt;a class="anchor" href="#%e9%82%ae%e7%ae%b1%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%bd%a2%e6%80%81">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="配置文件参悟">
 配置文件参悟
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6%e5%8f%82%e6%82%9f">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="dns记录">
 DNS记录
 &lt;a class="anchor" href="#dns%e8%ae%b0%e5%bd%95">#&lt;/a>
&lt;/h3>
 &lt;table>
 &lt;thead>
 &lt;tr> &lt;th>用于&lt;/th> &lt;th>主机记录&lt;/th> &lt;th>记录类型&lt;/th> &lt;th>记录值&lt;/th> &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr> &lt;td rowspan="3">基本记录&lt;/td> &lt;td>mail.wtfu.site&lt;/td> &lt;td>A&lt;/td> &lt;td>47.94.20.18&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>smtp.wtfu.site&lt;/td> &lt;td>CNAME&lt;/td> &lt;td>mail.wtfu.site&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>wtfu.site&lt;/td> &lt;td>MX&lt;/td> &lt;td>mail.wtfu.site&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>&lt;a href="#spf" rel="noopener" class="internal-link" data-src="#spf">SPF&lt;/a>&lt;/td> &lt;td>mail.wtfu.site&lt;/td> &lt;td>TXT&lt;/td> &lt;td>v=spf1 mx ~all&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>&lt;a href="#dkim" rel="noopener" class="internal-link" data-src="#dkim">DKIM&lt;/a>&lt;/td> &lt;td>default._domainkey.wtfu.site&lt;/td> &lt;td>TXT&lt;/td> &lt;td>v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyDAs34 …&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>&lt;a href="#dmarc" rel="noopener" class="internal-link" data-src="#dmarc">DMARC&lt;/a>&lt;/td> &lt;td>_dmarc.wtfu.site&lt;/td> &lt;td>TXT&lt;/td> &lt;td>v=DMARC1; p=quarantine; ruf=mailto:xhsgg12302@126.com&lt;/td> &lt;/tr>
 &lt;tr> &lt;td rowspan="3">&lt;a href="#mta-sts" rel="noopener" class="internal-link" data-src="#mta-sts">MTA-STS&lt;/a>&lt;/td> &lt;td>_mta-sts.wtfu.site&lt;/td> &lt;td>TXT&lt;/td> &lt;td>v=STSv1; id=1&lt;/td> &lt;/tr> 
 &lt;tr> &lt;td>_smtp._tls.wtfu.site 【TLS-RPT】&lt;/td> &lt;td>TXT&lt;/td> &lt;td>v=TLSRPTv1;rua=mailto:xhsgg12302@126.com&lt;/td> &lt;/tr>
 &lt;tr> &lt;td>mta-sts.wtfu.site&lt;/td> &lt;td>A&lt;/td> &lt;td>47.94.20.18&lt;/td> &lt;/tr>
 &lt;/tbody>
 &lt;/table>
&lt;/li>
&lt;li>
&lt;h3 id="smtp中继服务器使用">
 SMTP中继服务器使用
 &lt;a class="anchor" href="#smtp%e4%b8%ad%e7%bb%a7%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%bd%bf%e7%94%a8">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="邮箱评分">
 邮箱评分
 &lt;a class="anchor" href="#%e9%82%ae%e7%ae%b1%e8%af%84%e5%88%86">#&lt;/a>
&lt;/h3>
&lt;/li>
&lt;li>
&lt;h3 id="smtp端口选择">
 SMTP端口选择
 &lt;a class="anchor" href="#smtp%e7%ab%af%e5%8f%a3%e9%80%89%e6%8b%a9">#&lt;/a>
&lt;/h3>
&lt;p class="warn"> SSL/TLS和STARTTLS：
&lt;br>通常情况下：（SSL和TSL）放在一起都表示传输层安全加密，除了特别的协议版本指定之外，他们没有任何区别。一般工作在&lt;code>465&lt;/code>端口，表示这个端口的流量必须加密。
&lt;br>另外一个是（STARTTLS）通常情况下在端口&lt;code>587&lt;/code>发挥作用。表示可以支持 ssl/tls 加密，也可以不加密，以普通方式进行。在 RFC/3207 中有命令 


 &lt;a href="https://www.rfc-editor.org/rfc/rfc3207#:~:text=The-,STARTTLS,-Command" rel="noopener" target="_blank">STARTTLS&lt;/a> 定义，稍后演示一下。
&lt;br>还有一个最为熟知的端口&lt;code>25&lt;/code>，现在一般不允许在此处提交邮件，只针对中继服务（MTA）转发使用。（maddy 默认不让在这个端口提交邮件，但是不影响它使用 25 端口接收其他 MTA 发过来的邮件）
&lt;br>&lt;br>其他协议 &lt;strong>IMAP&lt;/strong>，&lt;strong>POP3&lt;/strong> 加密端口
&lt;br>&lt;span style='padding-left:1.2em'>IMAP 使用 &lt;code>143&lt;/code> 端口，经过 SSL/TLS 加密的 IMAPS 协议使用 993 端口。
&lt;br>&lt;span style='padding-left:1.2em'>POP3 使用 &lt;code>110&lt;/code> 端口，经过 SSL/TLS 加密的 POP3S 协议使用 995 端口。
&lt;br>&lt;br>参考：


 &lt;a href="https://www.mailgun.com/blog/email/which-smtp-port-understanding-ports-25-465-587/" rel="noopener" target="_blank">which-smtp-port-understanding-ports-25-465-587&lt;/a>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/squirrel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/squirrel/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introrime--squirrel--自定义输入法">
 Intro(RIME | SQUIRREL | 自定义输入法)
 &lt;a class="anchor" href="#introrime--squirrel--%e8%87%aa%e5%ae%9a%e4%b9%89%e8%be%93%e5%85%a5%e6%b3%95">#&lt;/a>
&lt;/h2>
&lt;div class="alert callout attention">&lt;p class="title">&lt;span class="icon icon icon-attention">&lt;/span> Caution &lt;/p>&lt;p> 因为需要输入法配置灵活度高，所以找到开源的&lt;strong>鼠须管&lt;/strong>，基于&lt;strong>中州韵&lt;/strong>输入法引擎的一个 macosx 端实现。


 &lt;a href="https://github.com/rime/home/wiki/Introduction" rel="noopener" target="_blank">详细介绍(自序、历史、概念、项目构成、开发计划)&lt;/a>
&lt;br>另外本文主要针对 &lt;strong>【朙月拼音】&lt;/strong> 和 &lt;strong>【小鹤双拼】&lt;/strong> 等方案进行配置，当然其他方案也可以局部参考。
&lt;br>&lt;br>贴一些使用过程中的感受：
&lt;br>&lt;span style='padding-left:1.2em'/>&lt;code>1.&lt;/code> 好用是真好用，但是学习成本是真 TM 高。如果只是想简单使用，默认配置基本够用。如果想打造成满心欢喜的神兵利器，还是需要时间滋养的。可以循序渐进。
&lt;br>&lt;span style='padding-left:1.2em'/>&lt;code>2.&lt;/code> 官方的概念多且杂，但是还又不能不看，建议有个全局了解。这样碰见其他人分享的配置文件，也能看个大概，汲取精华，去其糟粕。因为外部资料更是一搜一大堆。
&lt;br>&lt;span style='padding-left:1.2em'/>&lt;code>3.&lt;/code> 因为这东西大概在 11 年左右出来的，出道早，以至于滋生出各式各样的输入法编码，完备方案等，不懂大概运行流程及配置关系只会懵逼树下懵逼果，偷鸡的话只能祈求上天保佑好使了。&lt;/p>
&lt;/p>&lt;/div>
&lt;ul>
&lt;li>
&lt;h3 id="下载安装">
 下载安装
 &lt;a class="anchor" href="#%e4%b8%8b%e8%bd%bd%e5%ae%89%e8%a3%85">#&lt;/a>
&lt;/h3>
&lt;p class="warn">


 &lt;a href="https://rime.im/download/" rel="noopener" target="_blank">下载页面&lt;/a>，


 &lt;a href="https://github.com/rime/squirrel/releases/download/1.0.2/Squirrel-1.0.2.pkg" rel="noopener" target="_blank">macOS 鼠须管 1.0.2 pkg 安装包&lt;/a>(属于将引擎中州韵代码作为 git 子模块，编译成动态链接库供鼠须管使用)
&lt;br>&lt;br> 


 &lt;a href="https://github.com/rime/squirrel/blob/master/INSTALL.md" rel="noopener" target="_blank">macOS 编译指南&lt;/a>
&lt;br>


 &lt;a href="https://github.com/rime/squirrel/wiki" rel="noopener" target="_blank">鼠鬚管 Wiki&lt;/a>
&lt;br>&lt;br>重新部署：


 &lt;a href="https://github.com/rime/squirrel/issues/320" rel="noopener" target="_blank">参考&lt;/a>
&lt;br>&lt;span style='padding-left:1.2em'/>&lt;code>/Library/Input\ Methods/Squirrel.app/Contents/MacOS/Squirrel --reload&lt;/code>
&lt;br>&lt;span style='padding-left:1.2em'/>&lt;code>control + option + . &lt;/code>
&lt;br>&lt;br>&lt;img src="https://archive-w.netlify.app/.images/other/misc/squirrel/squirrel-intro-01.png" alt="" width="60%">&lt;/p>
&lt;/li>
&lt;li>
&lt;h3 id="配置">
 配置
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%ae">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;h4 id="配置文件位置">
 配置文件位置
 &lt;a class="anchor" href="#%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6%e4%bd%8d%e7%bd%ae">#&lt;/a>
&lt;/h4>
&lt;div class="alert callout warning">&lt;p class="title">&lt;span class="icon icon-warning">&lt;/span> Warning &lt;/p>&lt;p> 应运程序的安装位置: &lt;code>/Library/Input\ Methods/Squirrel.app/Contents&lt;/code>
&lt;br>程序附带的共享配置: &lt;code>/Library/Input\ Methods/Squirrel.app/Contents/SharedSupport/&lt;/code>
&lt;br>用户自定义覆写目录: &lt;code>~/Library/Rime/&lt;/code>
&lt;br>&lt;br>配置文件目录及文件分布参考 


 &lt;a href="https://github.com/rime/home/wiki/RimeWithSchemata#rime-中的數據文件分佈及作用" rel="noopener" target="_blank">(RimeWithSchemata / Rime 中的數據文件分佈及作用)&lt;/a>
&lt;br>配置文件的 YAML 升级语法参考 


 &lt;a href="https://github.com/rime/home/wiki/Configuration#rime-配置文件" rel="noopener" target="_blank">(Configuration / Rime 配置文件)&lt;/a>
&lt;br>对于定制选项可参考 


 &lt;a href="https://github.com/rime/home/wiki/CustomizationGuide#定製指南" rel="noopener" target="_blank">(CustomizationGuide / 定製指南)&lt;/a>&lt;/p></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/sticker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/sticker/</guid><description>&lt;!-- ![](/.images/other/misc/wechat-sticker.png ':size=50%') -->
&lt;h3 id="wechat-emoji">
 Wechat-emoji
 &lt;a class="anchor" href="#wechat-emoji">#&lt;/a>
&lt;/h3>
&lt;hr/>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;th align="center">emoji&lt;/th>
&lt;th align="left">content&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/微笑&lt;/code>&lt;br>&lt;code>[微笑]&lt;/code>&lt;br>&lt;code>/::)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/撇嘴&lt;/code>&lt;br>&lt;code>[撇嘴]&lt;/code>&lt;br>&lt;code>/::~&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/色&lt;/code>&lt;br>&lt;code>[色]&lt;/code>&lt;br>&lt;code>/::B&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/发呆&lt;/code>&lt;br>&lt;code>[发呆]&lt;/code>&lt;br>&lt;code>/::|&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/得意&lt;/code>&lt;br>&lt;code>[得意]&lt;/code>&lt;br>&lt;code>/:8-)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/流泪&lt;/code>&lt;br>&lt;code>[流泪]&lt;/code>&lt;br>&lt;code>/::&amp;lt;&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/害羞&lt;/code>&lt;br>&lt;code>[害羞]&lt;/code>&lt;br>&lt;code>/::$&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/闭嘴&lt;/code>&lt;br>&lt;code>[闭嘴]&lt;/code>&lt;br>&lt;code>/::X&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/睡&lt;/code>&lt;br>&lt;code>[睡]&lt;/code>&lt;br>&lt;code>/::Z&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px 0;"/>&lt;/td>
&lt;td align="left">&lt;code>/大哭&lt;/code>&lt;br>&lt;code>[大哭]&lt;/code>&lt;br>&lt;code>/::'(&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/尴尬&lt;/code>&lt;br>&lt;code>[尴尬]&lt;/code>&lt;br>&lt;code>/::-|&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/发怒&lt;/code>&lt;br>&lt;code>[发怒]&lt;/code>&lt;br>&lt;code>/::@&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/调皮&lt;/code>&lt;br>&lt;code>[调皮]&lt;/code>&lt;br>&lt;code>/::P&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/呲牙&lt;/code>&lt;br>&lt;code>[呲牙]&lt;/code>&lt;br>&lt;code>/::D&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/惊讶&lt;/code>&lt;br>&lt;code>[惊讶]&lt;/code>&lt;br>&lt;code>/::O&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/难过&lt;/code>&lt;br>&lt;code>[难过]&lt;/code>&lt;br>&lt;code>/::(&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/冷汗&lt;/code>&lt;br>&lt;code>[囧]&lt;/code>&lt;br>&lt;code>/:--b&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/抓狂&lt;/code>&lt;br>&lt;code>[抓狂]&lt;/code>&lt;br>&lt;code>/::Q&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/吐&lt;/code>&lt;br>&lt;code>[吐]&lt;/code>&lt;br>&lt;code>/::T&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -80px;"/>&lt;/td>
&lt;td align="left">&lt;code>/偷笑&lt;/code>&lt;br>&lt;code>[偷笑]&lt;/code>&lt;br>&lt;code>/:,@P&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/愉快&lt;/code>&lt;br>&lt;code>[愉快]&lt;/code>&lt;br>&lt;code>/:,@-D&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/白眼&lt;/code>&lt;br>&lt;code>[白眼]&lt;/code>&lt;br>&lt;code>/::d&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/傲慢&lt;/code>&lt;br>&lt;code>[傲慢]&lt;/code>&lt;br>&lt;code>/:,@o&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/困&lt;/code>&lt;br>&lt;code>[困]&lt;/code>&lt;br>&lt;code>/:|-)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/惊恐&lt;/code>&lt;br>&lt;code>[惊恐]&lt;/code>&lt;br>&lt;code>/::!&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/憨笑&lt;/code>&lt;br>&lt;code>[憨笑]&lt;/code>&lt;br>&lt;code>/::&amp;gt;&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/悠闲&lt;/code>&lt;br>&lt;code>[悠闲]&lt;/code>&lt;br>&lt;code>/::,@&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/咒骂&lt;/code>&lt;br>&lt;code>[咒骂]&lt;/code>&lt;br>&lt;code>/::-S&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/疑问&lt;/code>&lt;br>&lt;code>[疑问]&lt;/code>&lt;br>&lt;code>/:?&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -160px;"/>&lt;/td>
&lt;td align="left">&lt;code>/嘘&lt;/code>&lt;br>&lt;code>[嘘]&lt;/code>&lt;br>&lt;code>/:,@x&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/晕&lt;/code>&lt;br>&lt;code>[晕]&lt;/code>&lt;br>&lt;code>/:,@@&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/衰&lt;/code>&lt;br>&lt;code>[衰]&lt;/code>&lt;br>&lt;code>/:,@!&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/骷髅&lt;/code>&lt;br>&lt;code>[骷髅]&lt;/code>&lt;br>&lt;code>/:!!!&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/敲打&lt;/code>&lt;br>&lt;code>[敲打]&lt;/code>&lt;br>&lt;code>/:xx&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/再见&lt;/code>&lt;br>&lt;code>[再见]&lt;/code>&lt;br>&lt;code>/:bye&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/擦汗&lt;/code>&lt;br>&lt;code>[擦汗]&lt;/code>&lt;br>&lt;code>/:wipe&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/抠鼻&lt;/code>&lt;br>&lt;code>[抠鼻]&lt;/code>&lt;br>&lt;code>/:dig&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/鼓掌&lt;/code>&lt;br>&lt;code>[鼓掌]&lt;/code>&lt;br>&lt;code>/:handclap&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/坏笑&lt;/code>&lt;br>&lt;code>[坏笑]&lt;/code>&lt;br>&lt;code>/:B-)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -240px;"/>&lt;/td>
&lt;td align="left">&lt;code>/右哼哼&lt;/code>&lt;br>&lt;code>[右哼哼]&lt;/code>&lt;br>&lt;code>/:@&amp;gt;&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/鄙视&lt;/code>&lt;br>&lt;code>[鄙视]&lt;/code>&lt;br>&lt;code>/:&amp;gt;-|&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/委屈&lt;/code>&lt;br>&lt;code>[委屈]&lt;/code>&lt;br>&lt;code>/:P-(&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/快哭了&lt;/code>&lt;br>&lt;code>[快哭了]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/阴险&lt;/code>&lt;br>&lt;code>[阴险]&lt;/code>&lt;br>&lt;code>/:X-)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/亲亲&lt;/code>&lt;br>&lt;code>[亲亲]&lt;/code>&lt;br>&lt;code>/::*&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/可怜&lt;/code>&lt;br>&lt;code>[可怜]&lt;/code>&lt;br>&lt;code>/:8*&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/笑脸&lt;/code>&lt;br>&lt;code>[笑脸]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/生病&lt;/code>&lt;br>&lt;code>[生病]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/脸红&lt;/code>&lt;br>&lt;code>[脸红]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -320px;"/>&lt;/td>
&lt;td align="left">&lt;code>/破涕为笑&lt;/code>&lt;br>&lt;code>[破涕为笑]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/恐惧&lt;/code>&lt;br>&lt;code>[恐惧]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/失望&lt;/code>&lt;br>&lt;code>[失望]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/无语&lt;/code>&lt;br>&lt;code>[无语]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/嘿哈&lt;/code>&lt;br>&lt;code>[嘿哈]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/捂脸&lt;/code>&lt;br>&lt;code>[捂脸]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/奸笑&lt;/code>&lt;br>&lt;code>[奸笑]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/机智&lt;/code>&lt;br>&lt;code>[机智]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/皱眉&lt;/code>&lt;br>&lt;code>[皱眉]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/耶&lt;/code>&lt;br>&lt;code>[耶]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -400px;"/>&lt;/td>
&lt;td align="left">&lt;code>/吃瓜&lt;/code>&lt;br>&lt;code>[吃瓜]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/加油&lt;/code>&lt;br>&lt;code>[加油]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/汗&lt;/code>&lt;br>&lt;code>[汗]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/天啊&lt;/code>&lt;br>&lt;code>[天啊]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/Emm&lt;/code>&lt;br>&lt;code>[Emm]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/社会社会&lt;/code>&lt;br>&lt;code>[社会社会]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/旺柴&lt;/code>&lt;br>&lt;code>[旺柴]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/好的&lt;/code>&lt;br>&lt;code>[好的]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/打脸&lt;/code>&lt;br>&lt;code>[打脸]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/哇&lt;/code>&lt;br>&lt;code>[哇]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -480px;"/>&lt;/td>
&lt;td align="left">&lt;code>/翻白眼&lt;/code>&lt;br>&lt;code>[翻白眼]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/666&lt;/code>&lt;br>&lt;code>[666]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/让我看看&lt;/code>&lt;br>&lt;code>[让我看看]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/叹气&lt;/code>&lt;br>&lt;code>[叹气]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/苦涩&lt;/code>&lt;br>&lt;code>[苦涩]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/裂开&lt;/code>&lt;br>&lt;code>[裂开]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/嘴唇&lt;/code>&lt;br>&lt;code>[嘴唇]&lt;/code>&lt;br>&lt;code>/:showlove&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/爱心&lt;/code>&lt;br>&lt;code>[爱心]&lt;/code>&lt;br>&lt;code>/:heart&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/心碎&lt;/code>&lt;br>&lt;code>[心碎]&lt;/code>&lt;br>&lt;code>/:break&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/拥抱&lt;/code>&lt;br>&lt;code>[拥抱]&lt;/code>&lt;br>&lt;code>/:hug&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -560px;"/>&lt;/td>
&lt;td align="left">&lt;code>/强&lt;/code>&lt;br>&lt;code>[强]&lt;/code>&lt;br>&lt;code>/:strong&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="center">&lt;div class="small" style="background-position: 0 -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/弱&lt;/code>&lt;br>&lt;code>[弱]&lt;/code>&lt;br>&lt;code>/:weak&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -50px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/握手&lt;/code>&lt;br>&lt;code>[握手]&lt;/code>&lt;br>&lt;code>/:share&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -100px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/胜利&lt;/code>&lt;br>&lt;code>[胜利]&lt;/code>&lt;br>&lt;code>/:v&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -150px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/抱拳&lt;/code>&lt;br>&lt;code>[抱拳]&lt;/code>&lt;br>&lt;code>/:@)&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -200px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/勾引&lt;/code>&lt;br>&lt;code>[勾引]&lt;/code>&lt;br>&lt;code>/:jj&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -250px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/拳头&lt;/code>&lt;br>&lt;code>[拳头]&lt;/code>&lt;br>&lt;code>/:@@&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -300px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/OK&lt;/code>&lt;br>&lt;code>[OK]&lt;/code>&lt;br>&lt;code>/:ok&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -350px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/合十&lt;/code>&lt;br>&lt;code>[合十]&lt;/code>&lt;br>&lt;code> &lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -400px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/啤酒&lt;/code>&lt;br>&lt;code>[啤酒]&lt;/code>&lt;br>&lt;code>/:beer&lt;/code>&lt;/td>
&lt;td align="center">&lt;div class="small" style="background-position: -450px -640px;"/>&lt;/td>
&lt;td align="left">&lt;code>/咖啡&lt;/code>&lt;br>&lt;code>[咖啡]&lt;/code>&lt;br>&lt;code>/:coffee&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="缺失的部分表情">
 缺失的部分表情
 &lt;a class="anchor" href="#%e7%bc%ba%e5%a4%b1%e7%9a%84%e9%83%a8%e5%88%86%e8%a1%a8%e6%83%85">#&lt;/a>
&lt;/h3>
&lt;details>&lt;summary>文本代码段&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">/:,@f 奋斗
/:cake 蛋糕
/:gift 礼物
/:rose 玫瑰
/:kiss 献吻
/:love 爱情
/:lvu 爱你
/::-O 哈欠
/:no NO
/::L 流汗
/::8 疯了
/:pd 菜刀
/:pig 猪头
/:fade 凋谢
/:li 闪电
/:bome 炸弹
/:kn 刀
/:shit 便便
/::+ 酷
/:turn 回头
/:ladybug 瓢虫
/:#-0 激动
/:kotow 磕头
/:@x 吓
/:&amp;amp;-( 糗大了
/:&amp;lt;@ 左哼哼
/:bad 差劲
/:shake 发抖
/:moon 月亮
/::g 饥饿
/:eat 吃饭
/:sun 太阳
/:hiphot 街舞
/:footb 足球
/:oo 乒乓
/:basketb 篮球
/:jump 跳跳
/:circle 转圈
/:skip 跳绳
/:&amp;lt;&amp;amp; 左太极
/:&amp;amp;&amp;gt; 右太极
/:&amp;lt;L&amp;gt; 飞吻
/:oY 投降
/:&amp;lt;W&amp;gt; 西瓜
/:&amp;lt;O&amp;gt; 怄火
&lt;/code>&lt;/pre>&lt;/div>
&lt;/details>
&lt;h3 id="baidu输入法个性短语导入">
 Baidu输入法个性短语导入
 &lt;a class="anchor" href="#baidu%e8%be%93%e5%85%a5%e6%b3%95%e4%b8%aa%e6%80%a7%e7%9f%ad%e8%af%ad%e5%af%bc%e5%85%a5">#&lt;/a>
&lt;/h3>
&lt;details>&lt;summary>微信表情快捷输入文本导入(注意文本编码【UTF-16】)&lt;/summary>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">[微信分组]
weixiao=1,[微笑]
piezui=1,[撇嘴]
se=1,[色]
fadai=1,[发呆]
deyi=1,[得意]
liulei=1,[流泪]
haixiu=1,[害羞]
bizui=1,[闭嘴]
shui=1,[睡]
daku=1,[大哭]

ganga=1,[尴尬]
fanu=1,[发怒]
tiaopi=1,[调皮]
ciya=1,[呲牙]
jingya=1,[惊讶]
nanguo=1,[难过]
jiong=1,[囧]
zhuakuang=1,[抓狂]
tu=1,[吐]
touxiao=1,[偷笑]

yukuai=1,[愉快]
baiyan=1,[白眼]
aoman=1,[傲慢]
kun=1,[困]
jingkong=1,[惊恐]
hanxiao=1,[憨笑]
youxian=1,[悠闲]
zhouma=1,[咒骂]
yiwen=1,[疑问]
xu=1,[嘘]

yun=1,[晕]
shuai=1,[衰]
kulou=1,[骷髅]
qiaoda=1,[敲打]
zaijian=1,[再见]
cahan=1,[擦汗]
koubi=1,[抠鼻]
guzhang=1,[鼓掌]
huaixiao=1,[坏笑]
youhengheng=1,[右哼哼]

bishi=1,[鄙视]
weiqu=1,[委屈]
kuaikule=1,[快哭了]
yinxian=1,[阴险]
qinqin=1,[亲亲]
kelian=1,[可怜]
xiaolian=1,[笑脸]
shengbing=1,[生病]
lianhong=1,[脸红]
potiweixiao=1,[破涕为笑]

kongju=1,[恐惧]
shiwang=1,[失望]
wuyu=1,[无语]
heiha=1,[嘿哈]
wulian=1,[捂脸]
jianxiao=1,[奸笑]
jizhi=1,[机智]
zhoumei=1,[皱眉]
ye=1,[耶]
chigua=1,[吃瓜]

jiayou=1,[加油]
han=1,[汗]
tiana=1,[天啊]
emm=1,[Emm]
shehuishehui=1,[社会社会]
wangchai=1,[旺柴]
haode=1,[好的]
dalian=1,[打脸]
wa=1,[哇]
fanbaiyan=1,[翻白眼]

liu=1,[666]
rangwokankan=1,[让我看看]
tanqi=1,[叹气]
kuse=1,[苦涩]
liekai=1,[裂开]
zuichun=1,[嘴唇]
aixin=1,[爱心]
xinsui=1,[心碎]
yongbao=1,[拥抱]
qiang=1,[强]

ruo=1,[弱]
woshou=1,[握手]
shengli=1,[胜利]
baoquan=1,[抱拳]
gouyin=1,[勾引]
quantou=1,[拳头]
ok=1,[OK]
heshi=1,[合十]
pijiu=1,[啤酒]
cafei=1,[咖啡]
&lt;/code>&lt;/pre>&lt;/div>
&lt;/details>
&lt;ul>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://blog.51cto.com/u_14191/7995989" rel="noopener" target="_blank">https://blog.51cto.com/u_14191/7995989&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://blog.csdn.net/llhwin2010/article/details/12675761" rel="noopener" target="_blank">https://blog.csdn.net/llhwin2010/article/details/12675761&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/other/misc/unblock-netease-music/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/misc/unblock-netease-music/</guid><description>&lt;ul>
&lt;li>
&lt;h2 id="introunblock-netease-music">
 Intro(UNblock Netease Music)
 &lt;a class="anchor" href="#introunblock-netease-music">#&lt;/a>
&lt;/h2>
&lt;p class="warn"> 解锁网易云变灰歌曲，&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">docker run -d --restart=always \
 -v /root/UNMCertificates/server.crt:/app/server.crt \
 -v /root/UNMCertificates/server.key:/app/server.key \
 -p 14163:14163 -p 14126:14126 --name UNM pan93412/unblock-netease-music-enhanced -t hello:world -p 14163:14126 -o kugou kuwo bilibili
&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://github.com/UnblockNeteaseMusic/server" rel="noopener" target="_blank">https://github.com/UnblockNeteaseMusic/server&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/other/review/cto/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/review/cto/</guid><description>&lt;h2 id="线上项目碰到过什么问题">
 线上项目碰到过什么问题
 &lt;a class="anchor" href="#%e7%ba%bf%e4%b8%8a%e9%a1%b9%e7%9b%ae%e7%a2%b0%e5%88%b0%e8%bf%87%e4%bb%80%e4%b9%88%e9%97%ae%e9%a2%98">#&lt;/a>
&lt;/h2>
&lt;h2 id="项目中复杂的业务逻辑">
 项目中复杂的业务逻辑
 &lt;a class="anchor" href="#%e9%a1%b9%e7%9b%ae%e4%b8%ad%e5%a4%8d%e6%9d%82%e7%9a%84%e4%b8%9a%e5%8a%a1%e9%80%bb%e8%be%91">#&lt;/a>
&lt;/h2>
&lt;h2 id="数据量访问量多大">
 数据量,访问量多大
 &lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e9%87%8f%e8%ae%bf%e9%97%ae%e9%87%8f%e5%a4%9a%e5%a4%a7">#&lt;/a>
&lt;/h2></description></item><item><title/><link>https://archive-w.netlify.app/other/review/hr/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/review/hr/</guid><description>&lt;h2 id="自我介绍中的亮点">
 自我介绍中的亮点
 &lt;a class="anchor" href="#%e8%87%aa%e6%88%91%e4%bb%8b%e7%bb%8d%e4%b8%ad%e7%9a%84%e4%ba%ae%e7%82%b9">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>面试官你好，我叫xxx，2018毕业于xxx软件工程专业。 今天面试的岗位是Java软件开发。 &lt;br>
&lt;code>在校时期领先突破单片机点灯实验。利用暑假自学汇编。参考JAVA学习课本独立完成学习管理系统开发，博客获得高赞。&lt;/code>&lt;br>
参与工作后， &lt;br>
曾经，&lt;br>
在日常工作中，除了编写相应的模块代码和bug修复以外.&lt;br>
还能够优化系统结构或者处理逻辑等。 &lt;code>曾经将网关白名单鉴权部分利用多线程技术效率提高百分之45%左右。&lt;/code>&lt;br>
自己除了日常工作中的Java编码外，还喜欢学习嵌入式，汇编，网络通信等知识。&lt;br>
以上就是我的自我介绍。&lt;/p>
&lt;/blockquote>
&lt;h2 id="最大的优缺点求职优势">
 最大的优缺点(求职优势)
 &lt;a class="anchor" href="#%e6%9c%80%e5%a4%a7%e7%9a%84%e4%bc%98%e7%bc%ba%e7%82%b9%e6%b1%82%e8%81%8c%e4%bc%98%e5%8a%bf">#&lt;/a>
&lt;/h2>
&lt;h2 id="自我评价">
 自我评价
 &lt;a class="anchor" href="#%e8%87%aa%e6%88%91%e8%af%84%e4%bb%b7">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>工作积极主动，工作效率高，责任心强，注重细节，追求完美&lt;/li>
&lt;li>能及时进行思考和总结，对相关知识进行沉淀与分享&lt;/li>
&lt;li>喜欢钻研技术，学习源码，经常利用业余时间进行学习&lt;/li>
&lt;li>有较强自我管理能力和时间管理能力&lt;/li>
&lt;li>喜欢跑步，爬山，打球，为人乐观大方，遇事沉着冷静&lt;/li>
&lt;/ul>
&lt;h2 id="为什么选择我们公司">
 为什么选择我们公司
 &lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e9%80%89%e6%8b%a9%e6%88%91%e4%bb%ac%e5%85%ac%e5%8f%b8">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>我十分看好贵公司所在的行业，也感觉贵公司十分重视人才，而且这项工作很适合我，相信自己一定能做好。&lt;/li>
&lt;li>我花费了很长时间考虑各种职业的可能性。我认为这方面的工作最适合我，原因是这项工作要求的许多技能都是我擅长的。&lt;/li>
&lt;li>示范：因为我的专业以及过往的经历与贵公司的这个岗位很匹配，同时我也很认可贵公司的发展理念，同时这个岗位也与我的个人的职业规划相匹配，所以我对贵公司有所期待。&lt;/li>
&lt;li>示范：我选择公司其实也比较谨慎。希望下一家公司稳定靠谱。而贵公司近年来一直稳健发展。也逐步成为行业标杆。所以我期望有机会加入。&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>
&lt;p>总结：&lt;/p>
&lt;ul>
&lt;li>专业经历与职位匹配度&lt;/li>
&lt;li>个人规划与发展理念匹配&lt;/li>
&lt;li>选择公司的态度（谨慎）与公司发展状态（稳定）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>了解公司的情况&lt;/p>
&lt;ul>
&lt;li>公司的综合信誉&lt;/li>
&lt;li>关键领导者的声誉&lt;/li>
&lt;li>公司产品，服务的赞赏&lt;/li>
&lt;li>公司理念与价值观&lt;/li>
&lt;li>公司对员工的管理理念及奖惩制度。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="职业规划">
 职业规划
 &lt;a class="anchor" href="#%e8%81%8c%e4%b8%9a%e8%a7%84%e5%88%92">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>分析因素
&lt;ul>
&lt;li>个人性格，兴趣，能力分析&lt;/li>
&lt;li>目标行业的发展前景&lt;/li>
&lt;li>根据自身做出时间方案&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>短期目标
&lt;ul>
&lt;li>尽快熟悉公司的发展业务与后端架构布局&lt;/li>
&lt;li>补充项目中用到技术的一些盲点&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>中期目标
&lt;ul>
&lt;li>主动解决工作碰到的问题以及业务拓展&lt;/li>
&lt;li>向架构师看齐,希望能够带领团队，为单位做出更大的贡献，获得双赢。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>长期目标
&lt;ul>
&lt;li>梳理知识点，形成知识体系， 持续输出，包括笔记，博客，产品等。&lt;/li>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="离职原因">
 离职原因
 &lt;a class="anchor" href="#%e7%a6%bb%e8%81%8c%e5%8e%9f%e5%9b%a0">#&lt;/a>
&lt;/h2>
&lt;h2 id="对岗位及行业的理解">
 对岗位及行业的理解
 &lt;a class="anchor" href="#%e5%af%b9%e5%b2%97%e4%bd%8d%e5%8f%8a%e8%a1%8c%e4%b8%9a%e7%9a%84%e7%90%86%e8%a7%a3">#&lt;/a>
&lt;/h2>
&lt;h2 id="怎么看待加班">
 怎么看待加班
 &lt;a class="anchor" href="#%e6%80%8e%e4%b9%88%e7%9c%8b%e5%be%85%e5%8a%a0%e7%8f%ad">#&lt;/a>
&lt;/h2>
&lt;h2 id="你有什么要问我的">
 你有什么要问我的
 &lt;a class="anchor" href="#%e4%bd%a0%e6%9c%89%e4%bb%80%e4%b9%88%e8%a6%81%e9%97%ae%e6%88%91%e7%9a%84">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>从刚才的面试状态来说，我要胜任这份工作，还有哪些需要补充的？&lt;/li>
&lt;li>目前在做的项目或者使用的一些框架&lt;/li>
&lt;li>公司的有没有什么晋升机制？&lt;/li>
&lt;/ul>
&lt;h2 id="福利待遇">
 福利待遇
 &lt;a class="anchor" href="#%e7%a6%8f%e5%88%a9%e5%be%85%e9%81%87">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>五险一金&lt;/li>
&lt;li>每月工资构成（底薪，绩效，年终奖，餐补，交通补等等）&lt;/li>
&lt;li>12个月的基本工资+季度奖金+年终奖等等&lt;/li>
&lt;li>涨薪机制（一年有几次考核晋升调薪机会，KPI考核，期权等）。&lt;/li>
&lt;li>加班，出差补助&lt;/li>
&lt;li>报道需求（证明，体检）【事先准备】&lt;/li>
&lt;/ul>
&lt;h2 id="谈薪技巧">
 谈薪技巧
 &lt;a class="anchor" href="#%e8%b0%88%e8%96%aa%e6%8a%80%e5%b7%a7">#&lt;/a>
&lt;/h2>
&lt;h2 id="reference">
 Reference
 &lt;a class="anchor" href="#reference">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>


 &lt;a href="https://www.zhihu.com/question/24192778" rel="noopener" target="_blank">https://www.zhihu.com/question/24192778&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://cloud.tencent.com/developer/article/1784001" rel="noopener" target="_blank">简历：第一章：技术亮点如何写&lt;/a>&lt;/li>
&lt;li>


 &lt;a href="https://www.zhihu.com/question/25257563" rel="noopener" target="_blank">面试时如何回答「你为什么选择我们公司」这个问题？&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title/><link>https://archive-w.netlify.app/other/template/download/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/template/download/</guid><description>&lt;h2 id="网页下载需要修改的部分">
 网页下载需要修改的部分
 &lt;a class="anchor" href="#%e7%bd%91%e9%a1%b5%e4%b8%8b%e8%bd%bd%e9%9c%80%e8%a6%81%e4%bf%ae%e6%94%b9%e7%9a%84%e9%83%a8%e5%88%86">#&lt;/a>
&lt;/h2>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell">1. &amp;lt;body data-page=&amp;quot;/Users/mac/Downloads/REPORT/README.md&amp;quot; class=&amp;quot;sticky ready&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;

 ==&amp;gt; &amp;lt;body data-page=&amp;quot;/Users/mac/Downloads/REPORT/README.md&amp;quot; class=&amp;quot;sticky ready close&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;

2. body.close .content {
 left: 200px;
 }

3. body:not(.ready) {
 # overflow: hidden;
 }
&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="shell" data-line="" class="language-shell line-numbers" style="max-height: none">&lt;code class="language-shell"># vus.css
# body.close .content{left:0}
# body:not(.ready){overflow:hidden}
find . -type f -name 'vue.css' -exec sed -i '' \
 -e 's/body\.close \.content{left:0}/body\.close \.content{left:200px}/g' \
 -e 's/body:not(\.ready){overflow:hidden}/body:not(\.ready){\/*overflow:hidden*\/}/g' \
 {} +

# *.html
find . -type f -name '*.html' -exec sed -i '' \
 -e 's/class=&amp;quot;.*sticky.*&amp;quot; /class=&amp;quot;sticky close&amp;quot; /g' \
 -e 's/&amp;lt;a href=&amp;quot;https:\/\/github\.com\/xhsgg12302\/knownledges.*&amp;lt;\/a&amp;gt;//g' \
 -e 's/&amp;lt;a style=&amp;quot;text-decoration: underline;.*Edit on github&amp;lt;\/a&amp;gt;//g' {} +
&lt;/code>&lt;/pre>&lt;/div></description></item><item><title/><link>https://archive-w.netlify.app/other/template/temp/render/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/other/template/temp/render/</guid><description>&lt;p>render everything&lt;/p></description></item><item><title>TLS-RECORD-CONSOLE-OUTPUT</title><link>https://archive-w.netlify.app/devops/network/tls-ssl/tls-record-console-output.2ed/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://archive-w.netlify.app/devops/network/tls-ssl/tls-record-console-output.2ed/</guid><description>&lt;p>


 
 

 
 
 
 
 
 
 
 
 
 &lt;a href='https://archive-w.netlify.app/.images/devops/network/tls-ssl/instance-tls-ssl-2ed.pcapng' rel="noopener" class="internal-link" data-src="https://archive-w.netlify.app/.images/devops/network/tls-ssl/instance-tls-ssl-2ed.pcapng">wireshark capture package: instance-tls-ssl.pcapng&lt;/a>，use filter：&lt;code>ip.addr == 47.94.20.18 &amp;amp;&amp;amp; tcp.port == 443&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://archive-w.netlify.app/.images/devops/network/tls-ssl/tls-record-show-interaction.gif" alt="data-gifcontrol-disabled" width="51%">
&lt;img src="https://archive-w.netlify.app/.images/devops/network/tls-ssl/tls-record-wireshark.png" alt="" width="47%">&lt;/p>
&lt;div class="outer yosemite">&lt;div class="dot red">&lt;/div>&lt;div class="dot amber">&lt;/div>&lt;div class="dot green">&lt;/div>&lt;/div>
&lt;div class="code-toolbar">&lt;pre data-lang="markup" data-line="" data-cc="800px" class="language-markup line-numbers" style="max-height: 800px">&lt;code class="language-markup">/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:64185,suspend=y,server=n -javaagent:/Users/stevenobelia/Library/Caches/JetBrains/IntelliJIdea2023.2/captureAgent/debugger-agent.jar -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar:/Users/stevenobelia/Documents/project_idea_test/idea-test-project/_4_springmvc/target/classes:/Users/stevenobelia/Documents/_maven_repo/javax/servlet/javax.servlet-api/3.0.1/javax.servlet-api-3.0.1.jar:/Users/stevenobelia/Documents/_maven_repo/javax/servlet/jstl/1.2/jstl-1.2.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-core/4.3.30.RELEASE/spring-core-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/commons-logging/commons-logging/1.2/commons-logging-1.2.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-web/4.3.30.RELEASE/spring-web-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-beans/4.3.30.RELEASE/spring-beans-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-context/4.3.30.RELEASE/spring-context-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-oxm/4.3.30.RELEASE/spring-oxm-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-tx/4.3.30.RELEASE/spring-tx-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-jdbc/4.3.30.RELEASE/spring-jdbc-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-webmvc/4.3.30.RELEASE/spring-webmvc-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-expression/4.3.30.RELEASE/spring-expression-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-aop/4.3.30.RELEASE/spring-aop-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-context-support/4.3.30.RELEASE/spring-context-support-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/springframework/spring-test/4.3.30.RELEASE/spring-test-4.3.30.RELEASE.jar:/Users/stevenobelia/Documents/_maven_repo/org/mybatis/mybatis/3.5.5/mybatis-3.5.5.jar:/Users/stevenobelia/Documents/_maven_repo/org/mybatis/mybatis-spring/2.0.5/mybatis-spring-2.0.5.jar:/Users/stevenobelia/Documents/_maven_repo/mysql/mysql-connector-java/5.1.42/mysql-connector-java-5.1.42.jar:/Users/stevenobelia/Documents/_maven_repo/com/zaxxer/HikariCP/4.0.3/HikariCP-4.0.3.jar:/Users/stevenobelia/Documents/_maven_repo/jstl/jstl/1.2/jstl-1.2.jar:/Users/stevenobelia/Documents/_maven_repo/log4j/log4j/1.2.17/log4j-1.2.17.jar:/Users/stevenobelia/Documents/_maven_repo/com/alibaba/fastjson/1.2.25.sec10/fastjson-1.2.25.sec10.jar:/Users/stevenobelia/Documents/_maven_repo/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar:/Users/stevenobelia/Documents/_maven_repo/org/slf4j/slf4j-log4j12/1.7.7/slf4j-log4j12-1.7.7.jar:/Users/stevenobelia/Documents/_maven_repo/com/fasterxml/jackson/core/jackson-databind/2.9.5/jackson-databind-2.9.5.jar:/Users/stevenobelia/Documents/_maven_repo/com/fasterxml/jackson/core/jackson-annotations/2.14.2/jackson-annotations-2.14.2.jar:/Users/stevenobelia/Documents/_maven_repo/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar:/Users/stevenobelia/Documents/_maven_repo/commons-fileupload/commons-fileupload/1.3.3/commons-fileupload-1.3.3.jar:/Users/stevenobelia/Documents/_maven_repo/commons-io/commons-io/2.4/commons-io-2.4.jar:/Users/stevenobelia/Documents/_maven_repo/commons-codec/commons-codec/1.9/commons-codec-1.9.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/commons/commons-lang3/3.0/commons-lang3-3.0.jar:/Users/stevenobelia/Documents/_maven_repo/javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/poi/poi-ooxml/3.17/poi-ooxml-3.17.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/poi/poi-ooxml-schemas/3.17/poi-ooxml-schemas-3.17.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar:/Users/stevenobelia/Documents/_maven_repo/stax/stax-api/1.0.1/stax-api-1.0.1.jar:/Users/stevenobelia/Documents/_maven_repo/com/github/virtuald/curvesapi/1.04/curvesapi-1.04.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/poi/poi/3.14/poi-3.14.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.jar:/Users/stevenobelia/Documents/_maven_repo/net/sourceforge/jexcelapi/jxl/2.6.12/jxl-2.6.12.jar:/Users/stevenobelia/Documents/_maven_repo/org/projectlombok/lombok/1.16.22/lombok-1.16.22.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar:/Users/stevenobelia/Documents/_maven_repo/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar:/Users/stevenobelia/Documents/_maven_repo/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.14.2/jackson-dataformat-yaml-2.14.2.jar:/Users/stevenobelia/Documents/_maven_repo/org/yaml/snakeyaml/1.33/snakeyaml-1.33.jar:/Users/stevenobelia/Documents/_maven_repo/org/java-websocket/Java-WebSocket/1.5.3/Java-WebSocket-1.5.3.jar:/Users/stevenobelia/Documents/_maven_repo/org/bouncycastle/bcprov-jdk15to18/1.78/bcprov-jdk15to18-1.78.jar:/Users/stevenobelia/Documents/_maven_repo/org/bouncycastle/bctls-debug-jdk15to18/1.78/bctls-debug-jdk15to18-1.78.jar:/Users/stevenobelia/Documents/_maven_repo/org/bouncycastle/bcutil-jdk15to18/1.78/bcutil-jdk15to18-1.78.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/jupiter/junit-jupiter/5.11.4/junit-jupiter-5.11.4.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/jupiter/junit-jupiter-api/5.11.4/junit-jupiter-api-5.11.4.jar:/Users/stevenobelia/Documents/_maven_repo/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/platform/junit-platform-commons/1.11.4/junit-platform-commons-1.11.4.jar:/Users/stevenobelia/Documents/_maven_repo/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/jupiter/junit-jupiter-params/5.11.4/junit-jupiter-params-5.11.4.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/jupiter/junit-jupiter-engine/5.11.4/junit-jupiter-engine-5.11.4.jar:/Users/stevenobelia/Documents/_maven_repo/org/junit/platform/junit-platform-engine/1.11.4/junit-platform-engine-1.11.4.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar site.wtfu.framework.utils.TLSTest
Connected to the target VM, address: '127.0.0.1:64185', transport: 'socket'
&lt;mark class='under red'>16 03 01 00 fd 01 00 00 f9 03 03 e3 e5 0a 0c c0 
f1 f7 49 4c 14 89 45 9c 28 05 39 fa b4 e9 ce 08 
77 f0 94 1f 44 4e 05 34 d6 4b c0 20 e0 76 16 70 
7f ac e1 53 5f 39 77 f3 98 b3 ff 2a 19 b6 76 08 
3e 23 15 d2 10 78 c5 a8 c1 2a 65 3a 00 1e 13 03 
13 01 cc a9 c0 2b c0 23 c0 09 cc a8 c0 2f c0 27 
c0 13 cc aa 00 9e 00 67 00 33 00 ff 01 00 00 92 
00 17 00 00 00 16 00 00 00 2b 00 05 04 03 04 03 
03 00 0a 00 10 00 0e 00 1d 00 1e 00 17 00 18 01 
00 01 01 01 02 00 33 00 26 00 24 00 1d 00 20 20 
87 73 67 9a 1e 19 0a 9c 9e 04 b8 1d 49 60 6f a1 
2e 6c 12 f0 f6 19 03 24 99 0c 77 11 ec 04 60 00 
05 00 05 01 00 00 00 00 00 0d 00 30 00 2e 08 07 
08 08 04 03 05 03 06 03 08 04 08 05 08 06 08 09 
08 0a 08 0b 04 01 05 01 06 01 04 02 05 02 06 02 
03 03 03 01 03 02 02 03 02 01 02 02 00 0b 00 02 
01 00&lt;/mark>
void
&lt;mark class='under green'>16 03 03 00 59 02 00 00 55 03 03 52 f6 1e a4 6d 
79 2e 2b 1b 94 70 d7 eb 21 5d 42 ed 4b a3 44 88 
45 f2 b8 c1 4b 63 8f 28 5b e9 fe 20 0a 0e a0 a9 
e9 88 4d 2d 07 c1 54 db 76 d3 9c e0 97 48 eb af 
7e 54 ee 51 d1 bb 61 39 7a 80 53 d0 c0 2b 00 00 
0d ff 01 00 01 00 00 0b 00 04 03 00 01 02&lt;/mark>
void
&lt;mark class='under green'>16 03 03 0b 77 0b 00 0b 73 00 0b 70 00 04 07 30 
82 04 03 30 82 03 88 a0 03 02 01 02 02 10 4f c9 
72 15 bf 60 1b 22 25 62 0a 35 37 a8 57 73 30 0a 
06 08 2a 86 48 ce 3d 04 03 03 30 4b 31 0b 30 09 
06 03 55 04 06 13 02 41 54 31 10 30 0e 06 03 55 
04 0a 13 07 5a 65 72 6f 53 53 4c 31 2a 30 28 06 
03 55 04 03 13 21 5a 65 72 6f 53 53 4c 20 45 43 
43 20 44 6f 6d 61 69 6e 20 53 65 63 75 72 65 20 
53 69 74 65 20 43 41 30 1e 17 0d 32 34 31 32 32 
32 30 30 30 30 30 30 5a 17 0d 32 35 30 33 32 32 
32 33 35 39 35 39 5a 30 14 31 12 30 10 06 03 55 
04 03 13 09 77 74 66 75 2e 73 69 74 65 30 59 30 
13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 
3d 03 01 07 03 42 00 04 4a cd f6 13 8a a1 45 4b 
a1 b2 29 2f 8c 31 06 2a 7f 03 7f e0 cd be 38 9b 
c3 85 02 0e 08 13 fb 14 31 8c 52 9c 12 31 76 dd 
be bf 92 7a 7d 66 66 79 df 2e 90 18 2b 58 62 67 
51 57 82 5a 6c eb 11 56 a3 82 02 83 30 82 02 7f 
30 1f 06 03 55 1d 23 04 18 30 16 80 14 0f 6b e6 
4b ce 39 47 ae f6 7e 90 1e 79 f0 30 91 92 c8 5f 
a3 30 1d 06 03 55 1d 0e 04 16 04 14 ee f5 a9 f7 
35 a7 22 36 8c b5 58 f4 03 78 2e 98 bd e6 fe c2 
30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 07 80 
30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 1d 
06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 
07 03 01 06 08 2b 06 01 05 05 07 03 02 30 49 06 
03 55 1d 20 04 42 30 40 30 34 06 0b 2b 06 01 04 
01 b2 31 01 02 02 4e 30 25 30 23 06 08 2b 06 01 
05 05 07 02 01 16 17 68 74 74 70 73 3a 2f 2f 73 
65 63 74 69 67 6f 2e 63 6f 6d 2f 43 50 53 30 08 
06 06 67 81 0c 01 02 01 30 81 88 06 08 2b 06 01 
05 05 07 01 01 04 7c 30 7a 30 4b 06 08 2b 06 01 
05 05 07 30 02 86 3f 68 74 74 70 3a 2f 2f 7a 65 
72 6f 73 73 6c 2e 63 72 74 2e 73 65 63 74 69 67 
6f 2e 63 6f 6d 2f 5a 65 72 6f 53 53 4c 45 43 43 
44 6f 6d 61 69 6e 53 65 63 75 72 65 53 69 74 65 
43 41 2e 63 72 74 30 2b 06 08 2b 06 01 05 05 07 
30 01 86 1f 68 74 74 70 3a 2f 2f 7a 65 72 6f 73 
73 6c 2e 6f 63 73 70 2e 73 65 63 74 69 67 6f 2e 
63 6f 6d 30 82 01 05 06 0a 2b 06 01 04 01 d6 79 
02 04 02 04 81 f6 04 81 f3 00 f1 00 77 00 cf 11 
56 ee d5 2e 7c af f3 87 5b d9 69 2e 9b e9 1a 71 
67 4a b0 17 ec ac 01 d2 5b 77 ce cc 3b 08 00 00 
01 93 ec be 8a c5 00 00 04 03 00 48 30 46 02 21 
00 ba 14 89 4c d4 a6 bf d5 8e 18 3b 10 63 54 35 
3e 16 3a f1 b0 1d e3 49 20 a0 7f 36 e0 44 30 e7 
e1 02 21 00 a8 dc 88 b6 51 32 6b 67 1e 60 d9 3a 
8b 2e f1 f9 1c f1 ff 18 8d c5 3f f7 9b cc 4b d4 
28 db 5c 13 00 76 00 cc fb 0f 6a 85 71 09 65 fe 
95 9b 53 ce e9 b2 7c 22 e9 85 5c 0d 97 8d b6 a9 
7e 54 c0 fe 4c 0d b0 00 00 01 93 ec be 8a 8f 00 
00 04 03 00 47 30 45 02 20 1b ff 93 39 6b c9 87 
b7 00 d6 45 63 66 92 b3 60 a0 4f 85 86 d5 1a 7a 
4d 4d 40 30 d8 9e 7a 21 df 02 21 00 fa b6 ae 47 
eb 9f c3 a7 f7 e1 87 3c 28 aa a3 47 88 81 af 36 
ff 1d 16 3e f1 3a 6c 5f 90 cb e3 e1 30 21 06 03 
55 1d 11 04 1a 30 18 82 09 77 74 66 75 2e 73 69 
74 65 82 0b 2a 2e 77 74 66 75 2e 73 69 74 65 30 
0a 06 08 2a 86 48 ce 3d 04 03 03 03 69 00 30 66 
02 31 00 f9 31 c9 8c 2e 6b f5 ca d4 ad dd 19 87 
27 1f d8 bd 32 ea 6c 99 6c 2e d6 c7 87 1c 02 f1 
33 40 68 3a 1a 03 cd 65 10 ae 68 63 85 2e 30 80 
22 da 47 02 31 00 b6 93 15 5e 96 75 ce 12 4e c0 
c7 14 79 2b 0a 63 ed 00 42 3a a3 82 0a 68 29 d2 
90 2a a8 59 c7 56 df 33 53 6f 59 0e 30 ec a0 81 
42 65 83 a4 09 68 00 03 89 30 82 03 85 30 82 03 
0c a0 03 02 01 02 02 10 23 b7 6d e3 c1 bb 2b 1a 
51 96 1e 08 ea b7 64 e8 30 0a 06 08 2a 86 48 ce 
3d 04 03 03 30 81 88 31 0b 30 09 06 03 55 04 06 
13 02 55 53 31 13 30 11 06 03 55 04 08 13 0a 4e 
65 77 20 4a 65 72 73 65 79 31 14 30 12 06 03 55 
04 07 13 0b 4a 65 72 73 65 79 20 43 69 74 79 31 
1e 30 1c 06 03 55 04 0a 13 15 54 68 65 20 55 53 
45 52 54 52 55 53 54 20 4e 65 74 77 6f 72 6b 31 
2e 30 2c 06 03 55 04 03 13 25 55 53 45 52 54 72 
75 73 74 20 45 43 43 20 43 65 72 74 69 66 69 63 
61 74 69 6f 6e 20 41 75 74 68 6f 72 69 74 79 30 
1e 17 0d 32 30 30 31 33 30 30 30 30 30 30 30 5a 
17 0d 33 30 30 31 32 39 32 33 35 39 35 39 5a 30 
4b 31 0b 30 09 06 03 55 04 06 13 02 41 54 31 10 
30 0e 06 03 55 04 0a 13 07 5a 65 72 6f 53 53 4c 
31 2a 30 28 06 03 55 04 03 13 21 5a 65 72 6f 53 
53 4c 20 45 43 43 20 44 6f 6d 61 69 6e 20 53 65 
63 75 72 65 20 53 69 74 65 20 43 41 30 76 30 10 
06 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 22 
03 62 00 04 36 41 61 17 2b 53 25 ed aa ca 94 e4 
d6 da 48 57 ef 50 ba 84 64 82 d7 bb 05 1b d6 1f 
06 24 f6 a5 33 9d 8c e7 f1 0b 55 68 63 82 30 10 
5f 8d 65 ec aa a8 af 97 ca b5 86 ce 30 01 89 74 
de e3 4e 5e 01 6e ee 26 7b cc 53 fa 23 a4 f7 44 
1d 3e 4d 1e 5f 66 a6 ad 85 f6 f2 e3 bc 8e 09 98 
80 24 8e 20 a3 82 01 75 30 82 01 71 30 1f 06 03 
55 1d 23 04 18 30 16 80 14 3a e1 09 86 d4 cf 19 
c2 96 76 74 49 76 dc e0 35 c6 63 63 9a 30 1d 06 
03 55 1d 0e 04 16 04 14 0f 6b e6 4b ce 39 47 ae 
f6 7e 90 1e 79 f0 30 91 92 c8 5f a3 30 0e 06 03 
55 1d 0f 01 01 ff 04 04 03 02 01 86 30 12 06 03 
55 1d 13 01 01 ff 04 08 30 06 01 01 ff 02 01 00 
30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 
05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 
22 06 03 55 1d 20 04 1b 30 19 30 0d 06 0b 2b 06 
01 04 01 b2 31 01 02 02 4e 30 08 06 06 67 81 0c 
01 02 01 30 50 06 03 55 1d 1f 04 49 30 47 30 45 
a0 43 a0 41 86 3f 68 74 74 70 3a 2f 2f 63 72 6c 
2e 75 73 65 72 74 72 75 73 74 2e 63 6f 6d 2f 55 
53 45 52 54 72 75 73 74 45 43 43 43 65 72 74 69 
66 69 63 61 74 69 6f 6e 41 75 74 68 6f 72 69 74 
79 2e 63 72 6c 30 76 06 08 2b 06 01 05 05 07 01 
01 04 6a 30 68 30 3f 06 08 2b 06 01 05 05 07 30 
02 86 33 68 74 74 70 3a 2f 2f 63 72 74 2e 75 73 
65 72 74 72 75 73 74 2e 63 6f 6d 2f 55 53 45 52 
54 72 75 73 74 45 43 43 41 64 64 54 72 75 73 74 
43 41 2e 63 72 74 30 25 06 08 2b 06 01 05 05 07 
30 01 86 19 68 74 74 70 3a 2f 2f 6f 63 73 70 2e 
75 73 65 72 74 72 75 73 74 2e 63 6f 6d 30 0a 06 
08 2a 86 48 ce 3d 04 03 03 03 67 00 30 64 02 30 
24 70 54 0f 01 c9 40 dd c8 54 d9 6d 54 ca c8 08 
ca 98 43 74 d8 3f f4 d7 a9 5f 6d f2 61 b9 70 0a 
26 1b 63 30 a8 8b 31 9c bf 77 ec 67 b0 7f a5 88 
02 30 25 ad ab a4 b0 ee 8d 52 e0 dd 0d 7c 9d df 
7d 1d ae e2 5c 64 9c 74 f8 7e 63 e5 c1 4e 60 16 
86 b0 a7 5e 19 6e ec 08 c6 91 d8 fb 03 14 a1 a5 
95 ab 00 03 d7 30 82 03 d3 30 82 02 bb a0 03 02 
01 02 02 10 56 67 1d 04 ea 4f 99 4c 6f 10 81 47 
59 d2 75 94 30 0d 06 09 2a 86 48 86 f7 0d 01 01 
0c 05 00 30 7b 31 0b 30 09 06 03 55 04 06 13 02 
47 42 31 1b 30 19 06 03 55 04 08 0c 12 47 72 65 
61 74 65 72 20 4d 61 6e 63 68 65 73 74 65 72 31 
10 30 0e 06 03 55 04 07 0c 07 53 61 6c 66 6f 72 
64 31 1a 30 18 06 03 55 04 0a 0c 11 43 6f 6d 6f 
64 6f 20 43 41 20 4c 69 6d 69 74 65 64 31 21 30 
1f 06 03 55 04 03 0c 18 41 41 41 20 43 65 72 74 
69 66 69 63 61 74 65 20 53 65 72 76 69 63 65 73 
30 1e 17 0d 31 39 30 33 31 32 30 30 30 30 30 30 
5a 17 0d 32 38 31 32 33 31 32 33 35 39 35 39 5a 
30 81 88 31 0b 30 09 06 03 55 04 06 13 02 55 53 
31 13 30 11 06 03 55 04 08 13 0a 4e 65 77 20 4a 
65 72 73 65 79 31 14 30 12 06 03 55 04 07 13 0b 
4a 65 72 73 65 79 20 43 69 74 79 31 1e 30 1c 06 
03 55 04 0a 13 15 54 68 65 20 55 53 45 52 54 52 
55 53 54 20 4e 65 74 77 6f 72 6b 31 2e 30 2c 06 
03 55 04 03 13 25 55 53 45 52 54 72 75 73 74 20 
45 43 43 20 43 65 72 74 69 66 69 63 61 74 69 6f 
6e 20 41 75 74 68 6f 72 69 74 79 30 76 30 10 06 
07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 22 03 
62 00 04 1a ac 54 5a a9 f9 68 23 e7 7a d5 24 6f 
53 c6 5a d8 4b ab c6 d5 b6 d1 e6 73 71 ae dd 9c 
d6 0c 61 fd db a0 89 03 b8 05 14 ec 57 ce ee 5d 
3f e2 21 b3 ce f7 d4 8a 79 e0 a3 83 7e 2d 97 d0 
61 c4 f1 99 dc 25 91 63 ab 7f 30 a3 b4 70 e2 c7 
a1 33 9c f3 bf 2e 5c 53 b1 5f b3 7d 32 7f 8a 34 
e3 79 79 a3 81 f2 30 81 ef 30 1f 06 03 55 1d 23 
04 18 30 16 80 14 a0 11 0a 23 3e 96 f1 07 ec e2 
af 29 ef 82 a5 7f d0 30 a4 b4 30 1d 06 03 55 1d 
0e 04 16 04 14 3a e1 09 86 d4 cf 19 c2 96 76 74 
49 76 dc e0 35 c6 63 63 9a 30 0e 06 03 55 1d 0f 
01 01 ff 04 04 03 02 01 86 30 0f 06 03 55 1d 13 
01 01 ff 04 05 30 03 01 01 ff 30 11 06 03 55 1d 
20 04 0a 30 08 30 06 06 04 55 1d 20 00 30 43 06 
03 55 1d 1f 04 3c 30 3a 30 38 a0 36 a0 34 86 32 
68 74 74 70 3a 2f 2f 63 72 6c 2e 63 6f 6d 6f 64 
6f 63 61 2e 63 6f 6d 2f 41 41 41 43 65 72 74 69 
66 69 63 61 74 65 53 65 72 76 69 63 65 73 2e 63 
72 6c 30 34 06 08 2b 06 01 05 05 07 01 01 04 28 
30 26 30 24 06 08 2b 06 01 05 05 07 30 01 86 18 
68 74 74 70 3a 2f 2f 6f 63 73 70 2e 63 6f 6d 6f 
64 6f 63 61 2e 63 6f 6d 30 0d 06 09 2a 86 48 86 
f7 0d 01 01 0c 05 00 03 82 01 01 00 19 ec eb 9d 
89 2c 20 0b 04 80 1d 18 de 42 99 72 99 16 32 bd 
0e 9c 75 5b 2c 15 e2 29 40 6d ee ff 72 db db ab 
90 1f 8c 95 f2 8a 3d 08 72 42 89 50 07 e2 39 15 
6c 01 87 d9 16 1a f5 c0 75 2b c5 e6 56 11 07 df 
d8 98 bc 7c 9f 19 39 df 8b ca 00 64 73 bc 46 10 
9b 93 23 8d be 16 c3 2e 08 82 9c 86 33 74 76 3b 
28 4c 8d 03 42 85 b3 e2 b2 23 42 d5 1f 7a 75 6a 
1a d1 7c aa 67 21 c4 33 3a 39 6d 53 c9 a2 ed 62 
22 a8 bb e2 55 6c 99 6c 43 6b 91 97 d1 0c 0b 93 
02 1d d2 bc 69 77 49 e6 1b 4d f7 bf 14 78 03 b0 
a6 ba 0b b4 e1 85 7f 2f dc 42 3b ad 74 01 48 de 
d6 6c e1 19 98 09 5e 0a b3 67 47 fe 1c e0 d5 c1 
28 ef 4a 8b 44 31 26 04 37 8d 89 74 36 2e ef a5 
22 0f 83 74 49 92 c7 f7 10 c2 0c 29 fb b7 bd ba 
7f e3 5f d5 9f f2 a9 f4 74 d5 b8 e1 b3 b0 81 e4 
e1 a5 63 a3 cc ea 04 78 90 6e bf f7&lt;/mark>
void
&lt;mark class='under green'>16 03 03 00 94 0c 00 00 90 03 00 17 41 04 cf 1f 
1d 3c 13 27 b0 bf d5 0d f9 55 9e b2 c2 e5 f7 ad 
ed db db 34 03 37 6e d2 e9 b1 ae 93 a0 b1 33 87 
5d 9b 90 d9 71 ee df ea 19 d3 b9 da 74 bf 60 f3 
39 4c 37 5d dc 75 82 68 fe a3 9d 7e c1 a4 06 03 
00 47 30 45 02 21 00 de ed 7f a8 fd 3c d8 e0 d5 
f2 e0 cf 22 eb a8 48 c6 a8 11 4a 65 30 7a 9e c6 
8d fa 22 a2 a5 b0 e5 02 20 11 2d 77 5a 4b 27 a0 
b6 0a 00 c0 e0 f5 ca 53 ba 57 66 40 76 79 26 c3 
40 c0 fc 46 d4 97 74 87 44&lt;/mark>
void
publicKey: 04 cf 1f 1d 3c 13 27 b0 bf d5 0d f9 55 9e b2 c2 e5 f7 ad ed db db 34 03 37 6e d2 e9 b1 ae 93 a0 b1 33 87 5d 9b 90 d9 71 ee df ea 19 d3 b9 da 74 bf 60 f3 39 4c 37 5d dc 75 82 68 fe a3 9d 7e c1 a4 
&lt;mark class='under green'>16 03 03 00 04 0e 00 00 00&lt;/mark>
void
big: 41421376590410550347532242163556460089898812947798573278257512740784871055544
&lt;mark class='under red'>16 03 03 00 46 10 00 00 42 41 04 8e 74 54 c4 02 
9d a0 63 1d 72 d2 ee 25 74 2d 59 82 6f 1b 85 51 
65 38 c8 e7 4a 3e af 4c bc fa 83 cc c5 6c f5 c2 
93 1a 51 34 ac 2e 60 13 0d 17 23 35 d7 2e c2 01 
2e 1e a5 47 f5 60 40 ab 94 b1 ef&lt;/mark>
void
label: &amp;quot;master secret&amp;quot;, seed: e3 e5 0a 0c c0 f1 f7 49 4c 14 89 45 9c 28 05 39 fa b4 e9 ce 08 77 f0 94 1f 44 4e 05 34 d6 4b c0 52 f6 1e a4 6d 79 2e 2b 1b 94 70 d7 eb 21 5d 42 ed 4b a3 44 88 45 f2 b8 c1 4b 63 8f 28 5b e9 fe 
&lt;mark class='under red'>14 03 03 00 01 01&lt;/mark>
void
label: &amp;quot;client finished&amp;quot;, seed: b3 a8 af 07 33 51 f0 44 c8 28 eb f2 50 86 cd 65 5d 76 6f 75 8d 39 08 dc 58 b2 4a 32 29 32 92 69 
&lt;mark class='under red'>16 03 03 00 28 00 00 00 00 00 00 00 00 04 c1 4c 
a1 7a c3 ed ad 20 45 0a 2c 32 08 b2 db 6c 79 76 
d8 5b 3d ae 76 ff 1e 28 6e 4e 12 56 8e&lt;/mark> 
void
&lt;mark class='under green'>14 03 03 00 01 01&lt;/mark>
void
&lt;mark class='under green'>16 03 03 00 28 84 ef 8c ec 32 b4 9f d9 a5 e6 04 
70 54 90 69 44 14 84 ce ad d3 03 e0 eb 66 36 3e 
01 28 88 6e d7 5c ed f6 80 58 e6 6d a4&lt;/mark>
void
clientRandom: e3 e5 0a 0c c0 f1 f7 49 4c 14 89 45 9c 28 05 39 fa b4 e9 ce 08 77 f0 94 1f 44 4e 05 34 d6 4b c0 
serverRandom: 52 f6 1e a4 6d 79 2e 2b 1b 94 70 d7 eb 21 5d 42 ed 4b a3 44 88 45 f2 b8 c1 4b 63 8f 28 5b e9 fe 
cipherText: 16 03 03 00 28 84 ef 8c ec 32 b4 9f d9 a5 e6 04 70 54 90 69 44 14 84 ce ad d3 03 e0 eb 66 36 3e 01 28 88 6e d7 5c ed f6 80 58 e6 6d a4 
label: &amp;quot;server finished&amp;quot;, seed: db a1 5c c2 bb 4e 60 58 30 16 00 7b 0a a0 9f 34 61 20 06 ca 74 68 d2 31 9d 18 c9 9d 21 82 c5 18 
&lt;mark class='under red'>17 03 03 00 fa 00 00 00 00 00 00 00 01 5b 2e c7 
61 b1 bb 92 38 2c a9 d0 7e 65 2b 6f 7a 95 71 5d 
28 bf f2 0a 14 d7 12 17 15 8f e5 ea 39 e9 aa 22 
f4 47 b8 26 48 9b e8 4e 41 1f 16 3b e4 03 c5 b6 
0b 9e 4d 9b a8 22 25 55 65 30 b7 52 a1 a3 d4 45 
5b 66 87 ae 9d 7d c6 c2 2c c4 d1 a1 a1 06 ee 46 
89 42 cd 52 27 9e 8b ca 57 d7 b7 74 38 5e cb 79 
cc af 89 31 06 b9 f4 c6 37 dd d2 bd ba 52 e1 32 
a5 2e c1 5f 64 42 97 f7 f2 f2 62 3e 04 e8 ed 69 
e0 a2 23 1e 9a 7d 5b dc 0b 4f b9 fa 46 19 90 9e 
05 eb 93 c7 57 b6 ee 50 bb 87 ba e7 bb 1f dc 27 
b0 68 ff 50 9f fd 51 78 39 97 72 f1 c8 ce b7 78 
c7 fa 51 d7 04 d7 98 cb 4d f2 1f 80 5c 0c a1 62 
a9 b0 95 a4 7a 27 b1 0f 20 ab 34 30 6c 2a f4 be 
53 14 d0 e7 b0 4c 6a bb 89 89 41 d3 db 59 06 ca 
2a 37 ca 46 de 19 08 e9 14 a9 ab 32 d2 0d 12&lt;/mark>
void
&lt;mark class='under green'>17 03 03 0a 04 84 ef 8c ec 32 b4 9f da 96 81 de 
e1 95 e3 1c 13 dc cf 70 da d2 f9 30 c6 70 49 47 
f1 78 eb b6 eb 7e ba c7 7b 22 3a 18 6b 2e 29 fe 
f8 d6 46 62 21 89 d8 84 05 a5 29 28 23 bc a8 05 
2b 0f 77 95 bb e2 ba 20 14 c5 5d 89 5d 11 c2 df 
5d 46 f0 4d 38 5e 2c ca 1f 46 4f 05 4e 8d 6d f8 
7a 0a 30 22 78 49 08 3f 40 bd e6 52 99 39 19 7d 
59 8c 19 3c 9f b4 f5 0f 68 e7 51 00 47 71 4a 12 
a2 97 35 8e e9 12 65 01 88 17 7e fd 85 c1 e6 f1 
0f ca bf 0d 08 88 8c b9 d4 c4 5f 4b 18 bf ba 26 
f6 15 84 92 df be e5 83 15 d7 3b 6c 92 d7 66 e5 
a6 ad 42 77 0d eb 24 f2 21 fb 60 04 c4 a5 ab 8e 
7b df 2f c9 74 a3 83 a5 29 bd b6 c3 e4 d7 d1 e9 
b3 78 91 af c3 00 1a 0f 3a 61 19 ce 2a 9b 43 1e 
d1 f7 02 6c 93 90 46 0a 8b 6c 96 37 56 6d dd 3d 
3b a0 68 ad 30 e6 f4 3b 02 b5 05 73 8b a9 4b 3f 
2e 0d 26 e2 f4 be ad 30 9a 52 83 73 65 b4 b2 e8 
6b b2 0d 66 ba dd 58 8d 5c 2e 34 13 e0 52 0b 91 
66 dd ed 30 2c b9 9e 7a 14 4b 52 06 8d 3f bd 01 
72 dc b2 68 0d 83 64 c4 00 01 12 b4 34 4a c4 bd 
15 eb e6 1c 62 ec 92 e5 ea 5b 6f d6 94 1f 89 6b 
c7 37 82 ad 28 2f 33 ff ac 63 13 47 e8 81 fb 4e 
6c ac 27 d5 f1 7c 0a 23 20 4d 15 77 7f 70 dd 4d 
e4 f3 18 6c b6 42 00 4f 5c 97 11 9b 4a 5d 46 90 
c4 53 d4 1c 57 94 b9 ba 06 2d 53 ab f9 b8 f7 bf 
4f 60 4d 28 f7 6e e1 be 83 e1 36 2f 61 65 d3 31 
67 90 1f e0 ae 84 92 e8 d5 26 74 fc 15 82 37 cf 
33 ed 86 df 7c e7 12 a9 c1 48 b3 53 23 e5 55 0d 
50 7f 2b 9a 65 dd eb 40 1c 2a 1f b0 fa 44 97 49 
99 cb a9 f0 f6 cd 95 1e a8 f3 b9 4b 2e 6a 09 cd 
03 90 ec 04 a9 b7 6d ba 20 fe 38 cc e5 a6 cc e6 
b2 62 f3 fb 2f 00 ae 9d 59 cb 9a 31 2c 74 5e e0 
35 47 58 d8 68 25 9d fd 32 51 9a 82 a4 66 32 df 
6b fa 4f e7 40 a3 31 6f cd ee 23 e5 fe 14 41 06 
e2 cb b9 3a c3 85 c7 fa d7 aa dd e1 3a b9 5c 46 
0d 17 9b e2 21 5a 3c b6 8f 97 a2 a6 5d 4f 8e 4a 
b0 3d 50 66 04 0f 9a 42 f0 42 bc 79 0f 0b 68 d6 
a3 36 dd 36 f4 06 7d f9 51 69 18 5d 13 2f 6a 54 
b5 8c f0 ee 0d 86 67 f5 85 54 51 30 06 48 5b f6 
f9 e5 e1 d8 4a 45 f2 75 da 17 69 60 c2 c4 09 36 
0d 76 9c 3e 30 0d ce ed 1c 55 aa d1 d0 c8 62 6f 
18 41 cf f9 0c 49 df 19 15 a5 c5 25 57 5d f0 2f 
14 86 e3 37 49 46 a3 01 5e c0 58 38 d6 20 70 4a 
36 67 2c 5b d3 26 cf ed 46 12 d1 3e 83 a8 69 57 
0e b0 8e f9 87 2e 69 dd fe e9 88 22 fb eb 74 0f 
a3 4a 3e 39 f5 cb b2 42 32 b8 3d b0 8e 72 3a 87 
7f 79 ec 51 24 7e 34 7c a5 e3 e7 22 b0 05 bd 62 
f8 75 da 28 0a 55 16 78 f2 ed 06 e1 5d d8 6e 56 
2b 88 78 93 2d fd 4d da 8e 59 eb b6 f4 12 86 d9 
c3 f6 7b 85 56 05 01 5d 1d ac 35 1a 4b 41 91 b6 
aa 79 00 90 a7 47 0c 1c 9e 82 b6 43 f2 30 29 19 
1b b4 72 e2 61 b9 24 77 1e 53 47 57 7d cf e3 4e 
97 ae f2 88 01 5e 7a 8d 55 1f 7a a3 06 a7 4f 0c 
56 72 c9 5b b1 41 73 5a 38 c0 fb 16 a3 d8 f8 da 
e3 fc a4 e3 91 4e ab 5a 94 1b 5a 02 69 d3 11 e9 
06 e0 95 1a 21 bd 3c f5 ef ec e2 f3 ed be 5d b0 
0d a7 49 7b 5c 66 4d e6 4d 2f 89 52 b9 d2 3c 2f 
c1 ec 26 73 8d 52 c5 d7 20 49 c9 57 3f f8 f2 da 
d5 46 13 a1 30 a1 24 60 27 cb 95 ab 7f 15 1c 6c&lt;/mark>
void
&lt;mark class='under green'>9b 98 0c a8 80 ce 9b 17 06 3b 3d 6e c2 24 0b e3 
29 36 b0 41 df 6b 94 97 8f e4 be e8 d8 5b fb 99 
f8 01 e8 c8 9b fd 6e fd 67 74 74 02 27 9e dc c4 
52 a8 18 dc 83 25 19 5e 34 5d e1 33 d9 55 cb 39 
10 78 66 5a 88 65 44 de 11 3b 38 d2 94 42 26 4b 
4e 64 c7 17 5a 62 f3 e8 83 46 37 15 01 94 f5 21 
3e 81 03 17 05 7d fd ef 33 b6 2c 55 66 6a c2 36 
a2 5b 7f 12 78 0a fb e1 a1 8f a1 7c 2a c9 19 cc 
bc 39 a5 e5 27 b6 e2 1c 2f 8e af fc 71 17 09 1b 
1d 26 e5 ac ff 27 09 d7 20 16 43 42 8e 9e 4c f5 
bb 2e 4f 57 bc 41 79 a1 93 d5 ca f5 23 36 56 82 
7d 02 b5 0b af ef 35 d1 5a d0 f3 8a 92 8b 83 55 
8d 0e e4 77 78 45 5a 57 01 19 a5 e5 d3 46 1b 06 
e8 4a 18 ce 63 6e e9 4d 90 19 a1 6a 3e 86 d2 60 
4f 45 84 56 a5 fd f4 b4 ef 55 cf 6e d3 08 40 a6 
08 c7 2d e1 fe bd 25 0c 13 0f 08 4a ff d9 3d 92 
e5 db 9d 22 53 5d e2 8a c5 65 74 14 f2 ff 81 54 
04 2b bd 49 ee 02 ed 5c 64 35 f3 bb aa 50 8d a6 
a9 5b ae 4b 93 82 ce a5 87 c2 65 4c c3 ab 05 f0 
3d 4d 75 b7 ad d4 68 de b2 94 88 07 ce 31 ac 20 
0e 97 41 e1 d4 89 af b9 e5 92 3c ce 56 e3 f5 c6 
c8 f5 4f b7 94 db cc 30 f0 30 f1 49 4a 15 03 6d 
bc 64 85 6e 95 82 14 c1 5b 6c d7 43 81 f3 da b0 
e1 6b a5 e3 59 5d 4e 41 38 7d d5 9a aa cb ef 12 
8d 97 88 90 03 d3 92 91 90 96 7b 02 00 6a cc c3 
01 f9 c1 fe 2c 8d a7 49 0b c3 7f 16 77 45 4b 9f 
3d 5d f5 96 f6 94 3e f1 65 0b 33 90 f9 f0 6a ef 
c9 2b 9c 8c 92 53 e2 c9 26 30 6e fc fa b7 df 70 
38 ee b9 02 16 5e d5 69 97 25 a1 ae a4 19 9f f8 
93 31 85 7e 2b 78 29 b7 a0 fb f3 b9 15 71 59 ca 
e1 b5 6d 61 b9 df 8d 93 35 6d 25 ff ba 80 e1 b9 
d0 32 b3 4a 08 7f 4f 1f 83 49 f3 61 59 59 18 7d 
40 b2 f8 97 44 61 fa d9 a3 9f d5 d6 41 64 ee ef 
22 3d f7 ba b6 47 a2 65 8f 50 7b d1 83 59 c0 51 
0e 38 06 d5 03 17 d2 87 0c 38 bd 72 b3 1b 16 33 
ca 41 91 d7 1f 73 bd 4a 88 d4 f7 58 1f 92 24 a5 
80 51 ea 97 3c c9 67 3e 42 1d 70 4f 58 f2 e3 1b 
49 e0 67 12 c4 35 37 3e 22 cc 3a 90 2d ea 23 4c 
39 57 8f fb e8 6e 9c df bb c3 38 ae b5 e5 e5 ee 
18 d0 b6 c5 c7 e0 a6 ad 5c 9e f7 59 ce 53 71 eb 
fe 09 c2 3b 39 fc d2 8d f8 bb 5c 37 c9 61 e3 94 
3a de 42 85 b7 7b ca e8 c9 06 29 f8 e1 41 12 d5 
1a 63 24 75 66 ee cf a2 bf 22 ae 55 33 49 4c 43 
fa a1 1c a1 5b cb fb 0a 4d 07 cd d8 c2 16 e1 35 
23 af a8 96 c6 a7 8d fc f6 c3 1b 85 70 2e ae 56 
d4 6a af 1a 96 eb cd ac 25 5d c4 a3 00 fd 1b 8c 
29 75 75 68 eb d6 2d 15 45 98 90 75 31 24 ac ec 
87 70 34 ee 23 eb 15 3c 54 dd 8f ff 34 74 81 ae 
ea c6 19 45 6c 9a 88 0f 43 b0 f9 9c 4a 13 cc 6f 
56 f1 f5 b7 c9 16 47 1d 54 f5 99 95 ba ac 5e c4 
02 7e fd a2 66 76 92 fe 5b 06 63 cb b9 29 14 f2 
2c 70 58 36 89 a8 84 af 60 aa 41 a0 21 84 d0 43 
b7 1b f5 eb 3a 43 8f f9 c2 ec 6b 76 94 5b 7f e9 
17 e7 7f 9d c8 19 28 c6 fe a1 7f 84 49 31 45 68 
2f cc fc 0e a1 85 ef 79 e7 0f f5 65 b6 65 45 59 
af 5b 3b 27 0f bf e6 5b 75 63 35 c5 03 e6 51 57 
81 48 00 f9 b5 4f dd 0b 1e 41 45 ef 90 c4 4e 26 
b4 15 c8 fc e2 60 be b9 a7 2f e5 73 06 0c d7 56 
f2 e8 fc 70 64 e0 2e be 62 df a9 14 a1 ab 3d f8 
dc 93 d8 32 77 d7 38 1d 6e ae ce 29 92 d9 90 9b 
cb cd 6c 5c 57 ce 91 05 16 72 64 5b 6a 9a 54 3b 
eb 42 8c b8 6e 6d ac 74 5c b0 c0 4c b6 f8 61 f1 
a2 c5 aa b3 ed 6b e9 76 e1 9a c1 b8 70 43 d3 b9 
8a 5e 0a c2 a6 f1 39 7d d9 fe 46 a0 17 56 f1 49 
5d ed f9 2e 8e a1 56 4c fc a9 39 7c 95 a6 77 e2 
e0 7c db ea a2 be ff 14 f7 04 ea 23 cf 6a 8a 02 
18 bf 40 ce 2d de e4 b0 34 90 d4 c3 c3 15 bf 7b 
e7 03 de f7 5a d8 8f 27 5c 5f b8 37 c1 f9 54 22 
39 52 e7 e9 78 a3 df ce 98 96 7a a4 ea 8b 62 28 
00 25 3b 2c ce 1a 68 ae 46 1d 6c a1 f2 9c 16 29 
91 05 18 3e ab fb a3 d4 fd d0 ed e0 54 5e c1 13 
65 2b 59 ee 4f 6f bc 37 75 ff ab 1b 63 5e 7c fa 
f7 3b 91 46 ae 0c f5 5f f8 5f 43 5a 2c f4 82 b5 
1d 10 ae 59 92 f9 fc 61 86 06 ec d1 43 18 c2 8e 
be fd 9a 41 2f 81 58 d4 c9 8a 49 43 2a 81 f5 d9 
92 e9 b2 dd 23 5d 94 fb 7b 29 b3 7b cc 49 57 8d 
26 63 1d 15 9d f7 12 87 df 7d c4 4c 0d fd 29 81 
79 0b e0 9a c0 0b 27 93 ca d1 02 d0 ba 37 e1 67 
53 dd 6c 1d b5 bd 99 11 c5 1a 84 06 6a 08 82 c8 
fc 2b 92 fb b7 c3 dc 4a 4a eb 29 04 b4 42 1c 8f 
4d a2 39 41 a7 d3 d6 ad c0 71 f3 ba c3 ad 00 0b 
a5 c7 60 6a 1a 5d 87 a3 80 5c 08 97 7a 04 4c 13 
f5 6b 0c a4 90 78 fa 1d b6 d5 df 4c c3 27 a4 a9 
ae a3 a8 db 37 cd 0e b0 ba a3 6f 7d 7f 40 b4 fc 
c3 35 59 ef 4e b7 dc 27 32 79 0a 30 e4 a4 58 f2 
47 d7 f8 38 24 d1 41 41 53 de c8 ff f2 65 ff 1a 
f7 88 17 f3 59 84 4d 2d 5b ad 7d 3e d6 c2 c2 e7 
5f 4e f5 d5 da 56 e5 1c a4 30 6a f7 60 5d 51 ff 
4e ec 0d f7 60 5a 69 53 0e 63 d7 f8 af b7 e2 81 
37 99 0a 4f 1f a5 9b fc ff 6a 11 dc 2b 1f f2 4e 
06 e2 2d 53 b7 0f 65 9a 9c 6a 52 e1 7c 13 af 56 
7b 50 f4 16 37 f2 67 12 a4 54 11 48 3a cd 9f bb 
d6 4f eb da d4 1c b9 47 db 2c 7e 3b 85 e3 77 03 
aa 12 e8 af 4f 5f df e5 da 5a c9 53 14 2c 86 ed 
02 5e 9c e3 77 f6 bf 18 ad 25 51 47 75 73 72 85 
c6 0a 45 bf 2a 14 2c d8 07 5d 9f e6 e4 e2 6f 2c 
5c e0 84 4f 50 16 6c 23 75 87 63 d9 2f 43 22 ef 
31 2a c1 f9 be ce c3 54 64 5d 3c d7 71 06 9d 5f 
85 b0 c2 26 87 dc 3f 33 f9 e5 5e 6c d3 7b 07 cd 
41 35 80 ab 5c 6a 97 ec a1 c6 60 23 6d 3d c4 c3 
f2 ea b2 59 fd 5b 38 b8 9d aa 24 bf 32 b0 fd 3f 
e6 c3 94 29 05 98 5c f7 39&lt;/mark>
Unable to evaluate the expression &amp;quot;String temp = &amp;quot;clientRandom: &amp;quot; + TLSTest.bytesToHex(this.cryptoParams.getSecurityParametersHandshake().clientRandom) + &amp;quot;\nserverRandom: &amp;quot; + TLSTest.bytesToHex(this.cryptoParams.getSecurityParametersHandshake().serverRandom) + &amp;quot;\ncipherText: &amp;quot; + TLSTest.bytesToHex(ciphertext);&amp;quot; : java.lang.NullPointerException
HTTP/1.1 200 OK
Server: X_12302.eli
Date: Mon, 30 Dec 2024 00:08:02 GMT
Content-Type: text/html
Content-Length: 2239
Last-Modified: Tue, 08 Oct 2024 01:41:47 GMT
Connection: close
Vary: Accept-Encoding
ETag: &amp;quot;67048ddb-8bf&amp;quot;
Strict-Transport-Security: max-age=15552000
Accept-Ranges: bytes

&lt;mark class='under green'>15 03 03 00 1a 84 ef 8c ec 32 b4 9f db a9 11 e8 
3f 18 d6 fe 11 34 13 20 11 ce a3 c8 ca 1f 77&lt;/mark>
void
Unable to evaluate the expression &amp;quot;String temp = &amp;quot;clientRandom: &amp;quot; + TLSTest.bytesToHex(this.cryptoParams.getSecurityParametersHandshake().clientRandom) + &amp;quot;\nserverRandom: &amp;quot; + TLSTest.bytesToHex(this.cryptoParams.getSecurityParametersHandshake().serverRandom) + &amp;quot;\ncipherText: &amp;quot; + TLSTest.bytesToHex(ciphertext);&amp;quot; : java.lang.NullPointerException
&lt;mark class='under red'>15 03 03 00 1a 00 00 00 00 00 00 00 02 3a f7 82 
f2 00 2e 34 39 8a 72 77 2b c0 bb aa 34 65 a9&lt;/mark>
void
&amp;lt;!doctypehtml&amp;gt;&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;index&amp;lt;/title&amp;gt;&amp;lt;style&amp;gt;body{margin:0;padding:0;overflow:hidden;position:relative;display:flex;justify-content:center;align-items:center;height:150vh;background:#eee8ee;font-size:12px;font-family:Arial,sans-serif}canvas{position:absolute;bottom:0;left:0;z-index:-1}#bottom_layer{visibility:hidden;width:3000px;position:fixed;z-index:302;bottom:0;left:0;height:65px;padding-top:1px;zoom:1;margin:0;line-height:39px}#bottom_layer .s-bottom-layer-content{margin:0 17px;text-align:center}#bottom_layer .lh{display:inline-block;margin-right:14px}#bottom_layer .text-color{color:#979e87}#bottom_layer a{font-size:12px;text-decoration:none}&amp;lt;/style&amp;gt;&amp;lt;canvas id=&amp;quot;waveCanvas&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&amp;lt;div id=&amp;quot;bottom_layer&amp;quot;style=&amp;quot;visibility:visible;width:100%&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;s-bottom-layer-content&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;text-color&amp;quot;href=&amp;quot;//wtfu.site&amp;quot;target=&amp;quot;_self&amp;quot;&amp;gt;关于首页&amp;lt;/a&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;text-color&amp;quot;href=&amp;quot;https://wtfu.site&amp;quot;target=&amp;quot;_self&amp;quot;&amp;gt;About Site&amp;lt;/a&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;text-color&amp;quot;href=&amp;quot;https://beian.mps.gov.cn/#/query/webSearch?code=11011402053698&amp;quot;rel=&amp;quot;noreferrer&amp;quot;target=&amp;quot;_blank&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;https://beian.mps.gov.cn/img/logo01.dd7ff50e.png&amp;quot;class=&amp;quot;w-full&amp;quot;style=&amp;quot;width:12px;padding-right:3px;vertical-align:-2px&amp;quot;&amp;gt; 京公网安备11011402053698&amp;lt;/a&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;text-color&amp;quot;href=&amp;quot;https://beian.miit.gov.cn&amp;quot;target=&amp;quot;_blank&amp;quot;&amp;gt;陇ICP备2020004323号&amp;lt;/a&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;text-color&amp;quot;&amp;gt;© Copyright 2000-2023 12302, Inc. and Contributors&amp;lt;/span&amp;gt;&amp;lt;p class=&amp;quot;lh&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;text-color&amp;quot;&amp;gt;Created using OpenAI&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;script&amp;gt;let i=document.getElementById(&amp;quot;waveCanvas&amp;quot;),n=i.getContext(&amp;quot;2d&amp;quot;),h=(i.width=window.innerWidth,i.height=window.innerHeight,{yOffset:100,amplitude:50,wavelength:.03,frequency:.01,phase:0,speed:.1});window.addEventListener(&amp;quot;resize&amp;quot;,()=&amp;gt;{i.width=window.innerWidth,i.height=window.innerHeight}),function e(){n.clearRect(0,0,i.width,i.height),n.fillStyle=&amp;quot;rgba(255, 255, 255, 0.5)&amp;quot;,n.beginPath();for(let e=0;e&amp;lt;i.width;e+=10){var t=h.yOffset+Math.sin(e*h.wavelength+h.phase)*h.amplitude*Math.sin(h.frequency*e+h.phase);n.lineTo(e,t)}n.lineTo(i.width,i.height),n.lineTo(0,i.height),n.closePath(),n.fill(),h.phase+=h.speed,requestAnimationFrame(e)}()&amp;lt;/script&amp;gt;
Disconnected from the target VM, address: '127.0.0.1:64185', transport: 'socket'

Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>