<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Barry Yang</title><description>偶尔摆烂，经常偶尔</description><link>https://barry.ee/</link><language>zh-CN</language><lastBuildDate>Fri, 23 Jan 2026 02:15:51 GMT</lastBuildDate><docs>https://validator.w3.org/feed/docs/rss2.html</docs><generator>Astro</generator><image><title>Barry Yang</title><url>https://barry.ee/favicon.svg</url><link>https://barry.ee/</link></image><copyright>CC BY-NC-SA 4.0 2026 © Barry Yang</copyright><atom:link href="https://barry.ee/feed.xml" rel="self" type="application/rss+xml"/><item><title>使Windows  Terminal变得更易用（v2）</title><link>https://barry.ee/writing/wtv2/</link><guid isPermaLink="true">https://barry.ee/writing/wtv2/</guid><description>三分钟教会你在WT上设置命令别名</description><pubDate>Fri, 18 Aug 2023 12:02:14 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;在几个月前我有写过一篇&lt;a href=&quot;https://www.barry.ee/posts/wt.html&quot;&gt;使Windows Terminal变得更易用&lt;/a&gt;，那篇文章主要是介绍了通过安装 oh-my-posh、安装 Nerd 字体解决 oh-my-posh 字体图标不显示、解决 ssh 连接长时间不操作自动断开、启动专注模式以及去掉烦人的启动版权信息并默认管理员启动等内容，事实上只是让其变的更加好看了，易用度并没有多大的提升，但是今天我们将再次给我们的 WT 升升级。&lt;/p&gt;
&lt;h2&gt;安装必要工具&lt;/h2&gt;
&lt;p&gt;首先 Windows Terminal 肯定是必要的，其次还得取安装一个 PowerShell，这两都在微软商店中下载安装，如下图。微软商店打不开就检查一下你的网络，一般都是网络问题。
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1692260721000poix8g.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;oh-my-posh 的安装我这里就不说了，可以去看我之前那篇文章。最后我们再来安装一个 &lt;a href=&quot;https://github.com/antfu/ni&quot;&gt;ni&lt;/a&gt;，这是 antfu 开发的来简化我们命令操作，自动选择包管理器的一个命令行小工具，偷懒神器，没用过的赶紧用起来，跟着文档敲一行命令就安装好了，不过 Windows 下使用可能会有别名冲突问题，我下文将会提到解决办法。&lt;/p&gt;
&lt;h2&gt;探索过程及原理概述&lt;/h2&gt;
&lt;p&gt;我想尝试使用 Windows Termimal 进行开发。Windows Terminal 默认可以使用 &lt;code&gt;PowerShell&lt;/code&gt;、&lt;code&gt;cmd&lt;/code&gt;、&lt;code&gt;wsl bash&lt;/code&gt; 作为脚本工具。既然是在 Windows 环境下嘛，还是得尊敬一下 PoweShell 的。于是我们先把 wt 的默认 shell 更换为我们刚刚安装的微软商店的 PowerShell，如下图
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1692261644000o3sirv.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;其实最初的灵感是看 &lt;a href=&quot;https://github.com/antfu&quot;&gt;antfu&lt;/a&gt; 直播时，它总会在命令行敲一些我都没见过的一些极短的命令来实现一些操作，让我看的是一头雾水。最后我才发现它是给他的 shell 设置了一些别名，并且还在 GitHub 开源了他的 zsh 的配置文件&lt;a href=&quot;https://github.com/antfu/dotfiles/blob/main/.zshrc&quot;&gt;配置文件&lt;/a&gt;（Mac 党大喜，可以直接抄走了😂），但是没钱买 Mac 现在只有 Windows 的我该如何在 Windows Termimal 上实现类似的功能呢，于是开始了我的尝试。
如果搜索关键词 &lt;code&gt;windows powershell set user alias&lt;/code&gt;，通常谷歌会给出&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/set-alias?view=powershell-6&quot;&gt;微软官方文档&lt;/a&gt;，但是这个文档只是告诉我们如何在脚本里面设置临时的别名，如果要设置永久别名，该怎么办？实际上，“别名”这种东西，也就是 &lt;code&gt;alias&lt;/code&gt;，几乎所有的脚本语言，都没有所谓的“永久别名”(Permanent alias)，我们使用 Linux bash 、Cmder 之类的脚本工具，打开终端时，系统会默认执行一个脚本文件（ bash 是用户目录下的 &lt;code&gt;.bashrc&lt;/code&gt;，Cmder 是 &lt;code&gt;config/user_aliases.cmd&lt;/code&gt; ），而这样的脚本文件里，就包含了别名的定义。这也是为什么，我们在 Linux 类系统中，修改 &lt;code&gt;.bashrc&lt;/code&gt; 后，必须要重新登出登录、或者 &lt;code&gt;source .bashrc&lt;/code&gt; 的原因了。
所以，我们只要修改 Powershell 启动时执行的文件就行了。很多论坛里面说，默认执行的脚本是 &lt;code&gt;$Home\Documents\profile.ps1&lt;/code&gt; ，也就是 &lt;code&gt;C:\Users\你的用户名\Documents\profile.ps1&lt;/code&gt; ，但是这并不正确，最好的方式是，先启动 PowerShell ，再执行 &lt;code&gt;echo $profile&lt;/code&gt;，这样得到的文件路径，才是 PowerShell 的默认执行文件路径。而且这里我们需要注意的是，如果按照我之前的那篇文章配置好后，然后今天重新安装的 PowerShell 并且设置为了 wt 的默认 shell 的话，那么，你得重新配置，因为这个微软商店的 PowerShell 和 Windows 自带的 Windows PowerShell 不是一个版本，所以不共用同一套配置文件。大概为以下路径：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1692328778000hbmtbr.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;然后，创建这个文件就好啦。&lt;/p&gt;
&lt;p&gt;在文件里面，写上别名设置的语句。再一次注意，假如你的别名指代的命令含有空格，就不可以使用 &lt;code&gt;New-Alias&lt;/code&gt; 命令，因为它不能带空格，即使你把指代的命令用引号括起来也没用。那怎么办呢？问了一下 GPT，原来，正确姿势是用 &lt;code&gt;function&lt;/code&gt; ，也就是，我们把自己要定义的指令，定义为一个函数，就行啦。
保存文件，重新启动 PowerShell 以后，不出意外，应该会报一个 &lt;code&gt;File xxxxxxx\Microsoft.PowerShell_profile.ps1 cannot be loaded because running scripts is disabled on this system.&lt;/code&gt; 根据&lt;a href=&quot;https://tecadmin.net/powershell-running-scripts-is-disabled-system/&quot;&gt;此链接&lt;/a&gt;，出现这种情况，是因为 Windows 系统为了防止恶意脚本自动执行，故默认不允许自动运行脚本。所以，在确定自己有能力把控的情况下，&lt;strong&gt;以管理员身份&lt;/strong&gt;，在 PowerShell 中执行 &lt;code&gt;Set-ExecutionPolicy RemoteSigned&lt;/code&gt; ，即可。&lt;/p&gt;
&lt;p&gt;再次重启 PowerShell，应该可以发现，自定义别名已经生效了。&lt;/p&gt;
&lt;h2&gt;解决别名冲突与传参优化&lt;/h2&gt;
&lt;p&gt;在进行了以上操作后，你会发现你设置的别名确实可用了，但是可能有一部分别名会与 PowerShell 本来就存在的一些别名有冲突，例如 &lt;code&gt;ni&lt;/code&gt; 、&lt;code&gt;gp&lt;/code&gt; 、&lt;code&gt;gcm&lt;/code&gt;，可能后续还会遇到很多，我们的解决方案是将其强制移除就好了，在你的配置文件中加入以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Remove-Alias -Name ni -Force
Remove-Alias -Name gp -Force
Remove-Alias -Name gcm -Force
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好，冲突问题解决了，但是最后还有一个问题就是，你会发现当你在使用一些需要传递参数的别名命令时，参数并不能传入，使用我们需要让我们的别名函数能够接收参数，当然不需要参数的就不用管了。我们只需要在我们的命令后添加 &lt;code&gt;$args&lt;/code&gt; 这个自动变量，它包含当前脚本、函数或脚本块的未声明参数的数组。简而言之，它捕获所有未被预定义参数捕获的参数。例如下面这些：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;function gcl { git clone $args }
function gst { git stash $args }
function grm { git rm $args }
function gmv { git mv $args }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你想上点强度，需要更高的自定义性，你也可用自己定义参数和提示如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;function gcm {
    param (
        [Parameter(Mandatory=$true)]
        [string]$message
    )

    if (-not $message) {
        Write-Host &amp;quot;Error: You must provide a commit message.&amp;quot; -ForegroundColor Red
        return
    }

    git commit -m $message
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;总之，玩法很多，大家可以自己慢慢研究，给大家扔一个我目前自用的配置文件，如果想换主题的话可以按照&lt;a href=&quot;https://ohmyposh.dev/docs/themes&quot;&gt;文档&lt;/a&gt;找到自己喜欢的主题更换第一行配置的 json 主题文件名即可。如果有其他的问题可以参考之前的那篇文章。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;oh-my-posh init pwsh --config $env:POSH_THEMES_PATH\montys.omp.json | Invoke-Expression
cls
function s { nr start }
function d { nr dev }
function b { nr build }
function t { nr test }
function lint { nr lint }
function release { nr release }

function gs { git status }
function gp { git push }
function gpf { git push --force }
function gpl { git pull --rebase }
function gcl { git clone $args }
function gst { git stash $args }
function grm { git rm $args }
function gmv { git mv $args }

function main { git checkout main }
function gco { git checkout $args }

function gcob { git checkout -b $args }

function gb { git branch }
function gbd { git branch -d $args }
function gbD { git branch -D $args }

function grb { git rebase $args }
function grbc { git rebase --continue }
function gme { git merge $args}

function gl { git log }
function glo { git log --oneline --graph }

function ga { git add }
function gA { git add -A }

function gc { git commit }
function gcm {
    param (
        [Parameter(Mandatory=$true)]
        [string]$message
    )

    if (-not $message) {
        Write-Host &amp;quot;Error: You must provide a commit message.&amp;quot; -ForegroundColor Red
        return
    }

    git commit -m $message
}

function gca { git commit -a }
function gcam { git commit -am $args }

function l { cls }
function q { exit }

function fuck { shutdown /s /f /t 0 }

Remove-Alias -Name ni -Force
Remove-Alias -Name gp -Force
Remove-Alias -Name gcm -Force
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just enjoy it.&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>「关于证明我是一名 JS 程序员这件事」</title><link>https://barry.ee/writing/jswork/</link><guid isPermaLink="true">https://barry.ee/writing/jswork/</guid><description>About Proving I&apos;m a JS Programmer(×) Front End Bible(√)</description><pubDate>Tue, 23 May 2023 12:11:14 GMT</pubDate><content:encoded>&lt;h2&gt;浏览器与网络&lt;/h2&gt;
&lt;h3&gt;浏览器内核&lt;/h3&gt;
&lt;h4&gt;渲染引擎&lt;/h4&gt;
&lt;p&gt;用来解释网页语法并渲染到网页上。负责显示请求的内容。如果请求的内容是 HTML，它就负责解析 HTML 和 CSS 内容，并将解析后的内容显示在屏幕上。
常见的渲染引擎可以分这四种：Trident、Gecko、Blink、Webkit。&lt;/p&gt;
&lt;h4&gt;js 引擎&lt;/h4&gt;
&lt;p&gt;用于解析和执行 JavaScript 代码。chrome 的 javascript 解释器是 V8。&lt;/p&gt;
&lt;h3&gt;地址栏输入 url，到页面呈现，的过程&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将 url 解析成 ip 地址，先查找缓存，没有则进行 dns 解析，向域名服务器处获取 ip&lt;/li&gt;
&lt;li&gt;建立 tcp 连接&lt;/li&gt;
&lt;li&gt;ssl 有一个验证的过程&lt;/li&gt;
&lt;li&gt;发送 http 请求&lt;/li&gt;
&lt;li&gt;收到服务器响应的资源文档&lt;/li&gt;
&lt;li&gt;构建 dom 树和 cssom 树，布局，再渲染&lt;/li&gt;
&lt;li&gt;画面呈现&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;http 与 https&lt;/h3&gt;
&lt;h4&gt;http&lt;/h4&gt;
&lt;p&gt;http：超文本传输协议，位于应用层，基于 TCP/IP 协议，使用无状态连接。&lt;/p&gt;
&lt;h5&gt;请求字段&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;User-agent，浏览器标识&lt;/li&gt;
&lt;li&gt;Authorization，认证信息，可以放 token&lt;/li&gt;
&lt;li&gt;Origin，后端可以判断，access-control-allow-origin&lt;/li&gt;
&lt;li&gt;cookie&lt;/li&gt;
&lt;li&gt;Cache-control：里面有 max-age，判断是否命中强缓存&lt;/li&gt;
&lt;li&gt;If-Modified-Since，304，协商缓存&lt;/li&gt;
&lt;li&gt;If-None-Match，304&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;响应字段&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;set-cookie，&lt;code&gt;Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ETag，对于某个资源的某个特定版本的一个标识符，通常是一个 消息散列 &lt;code&gt;ETag: &amp;quot;737060cd8c284d8af7ad3082f209582d&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Expires，指定一个日期/时间，超过该时间则认为此回应已经过期，&lt;code&gt;Expires: Thu, 01 Dec 1994 16:00:00 GMT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Last-Modified，所请求的对象的最后修改日期，&lt;code&gt;Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;状态码&lt;/h5&gt;
&lt;p&gt;1：消息，临时响应，代表请求已被接受，需要继续处理&lt;/p&gt;
&lt;p&gt;2：成功，代表请求已成功被服务器接收、理解、并接受。&lt;/p&gt;
&lt;p&gt;3：重定向，后续的请求地址（重定向目标）在本次响应的 Location 域中指明。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/HTTP_301&quot;&gt;301 Moved Permanently&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;被请求的资源已&lt;strong&gt;永久移动&lt;/strong&gt;到新位置，并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/HTTP_302&quot;&gt;302 Found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要求客户端执行&lt;strong&gt;临时重定向&lt;/strong&gt;（原始描述短语为“Moved Temporarily”）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/HTTP_303&quot;&gt;303 See Other&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对应当前请求的响应可以在另一个 URI 上被找到&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;304 Not Modified&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;未修改。所请求的资源未修改，服务器返回此状态码时，不会返回任何资源。&lt;/p&gt;
&lt;p&gt;表示资源在由请求头中的&lt;code&gt;If-Modified-Since&lt;/code&gt;或&lt;code&gt;If-None-Match&lt;/code&gt;参数指定的这一版本之后，未曾被修改。在这种情况下，由于客户端仍然具有以前下载的副本，因此不需要重新传输资源。&lt;/p&gt;
&lt;p&gt;注：与协商缓存有关&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;305 Use Proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;被请求的资源必须通过指定的&lt;strong&gt;代理&lt;/strong&gt;才能被访问。Location 域中将给出指定的代理所在的 URI 信息，接收者需要重复发送一个单独的请求，通过这个代理才能访问相应资源。&lt;/p&gt;
&lt;p&gt;4：客户端错误&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;400 Bad Request&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于明显的客户端错误（例如，格式错误的请求语法，太大的大小，无效的请求消息或欺骗性路由请求），服务器不能或不会处理该请求。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;401 Unauthorized&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;未认证，类似于 403 Forbidden&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;404 Not Found&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;405 Method Not Allowed&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;418 I’m a teapot&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;5：服务器错误&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;500 Internal Server Error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通用错误消息，服务器遇到了一个未曾预料的状况，导致了它无法完成对请求的处理。没有给出具体错误信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;502 Bad Gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作为&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%BD%91%E5%85%B3&quot;&gt;网关&lt;/a&gt;或者&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8&quot;&gt;代理&lt;/a&gt;工作的服务器尝试执行请求时，从上游服务器接收到无效的响应。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;503 Service Unavailable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于临时的服务器维护或者&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E9%81%8E%E8%BC%89&quot;&gt;过载&lt;/a&gt;，服务器当前无法处理请求。这个状况是暂时的，并且将在一段时间以后恢复。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;504 Gateway Timeout&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作为网关或者代理工作的服务器尝试执行请求时，未能及时从上游服务器（URI 标识出的服务器，例如&lt;a href=&quot;https://zh.wikipedia.org/wiki/HTTP&quot;&gt;HTTP&lt;/a&gt;、&lt;a href=&quot;https://zh.wikipedia.org/wiki/FTP&quot;&gt;FTP&lt;/a&gt;、&lt;a href=&quot;https://zh.wikipedia.org/wiki/LDAP&quot;&gt;LDAP&lt;/a&gt;）或者辅助服务器（例如&lt;a href=&quot;https://zh.wikipedia.org/wiki/DNS&quot;&gt;DNS&lt;/a&gt;）收到响应。&lt;/p&gt;
&lt;h4&gt;https&lt;/h4&gt;
&lt;p&gt;在 http 的基础上加了 ssl 协议，是 http 的安全版本。&lt;/p&gt;
&lt;h4&gt;http2.0 的改进&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基于 https，安全性更有保证&lt;/li&gt;
&lt;li&gt;使用二进制格式，比以前基于文本的传输更具普适性&lt;/li&gt;
&lt;li&gt;多路复用，是以前长连接的增强&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Get、Post、Put、Delete、Options、Trace、Connect&lt;/h3&gt;
&lt;h4&gt;请求类型&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;get：请求资源，可以使用缓存&lt;/li&gt;
&lt;li&gt;Post：提交数据，POST 产生两个 TCP 数据包，浏览器先发送 header，服务器响应 100 continue，浏览器再发送 data，服务器响应 200 ok（返回数据），不能使用缓存&lt;/li&gt;
&lt;li&gt;Put：更新资源&lt;/li&gt;
&lt;li&gt;Delete：删除资源&lt;/li&gt;
&lt;li&gt;Options：返回某资源所支持的 HTTP 请求方法&lt;/li&gt;
&lt;li&gt;Trace：回显服务器收到的请求，主要用于测试或诊断&lt;/li&gt;
&lt;li&gt;Connect：HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;幂等&lt;/h3&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Glossary/Idempotent&quot;&gt;mdn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一个 HTTP 方法是&lt;strong&gt;幂等&lt;/strong&gt;的，指的是同样的请求被执行一次与连续执行多次的效果是一样的，服务器的状态也是一样的。换句话说就是，幂等方法不应该具有副作用（统计用途除外）。在正确实现的条件下， &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/GET&quot;&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/a&gt; ， &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/HEAD&quot;&gt;&lt;code&gt;HEAD&lt;/code&gt;&lt;/a&gt; ， &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/PUT&quot;&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/DELETE&quot;&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/a&gt; 等方法都是&lt;strong&gt;幂等&lt;/strong&gt;的，而 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POST&quot;&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/a&gt; 方法不是。所有的 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Safe&quot;&gt;safe&lt;/a&gt; 方法也都是幂等的。&lt;/p&gt;
&lt;p&gt;幂等性只与后端服务器的实际状态有关，而每一次请求接收到的状态码不一定相同。例如，第一次调用 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/DELETE&quot;&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/a&gt; 方法有可能返回 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/200&quot;&gt;&lt;code&gt;200&lt;/code&gt;&lt;/a&gt; ，但是后续的请求可能会返回 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/404&quot;&gt;&lt;code&gt;404&lt;/code&gt;&lt;/a&gt; 。 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/DELETE&quot;&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/a&gt; 的言外之意是，开发者不应该使用 &lt;code&gt;DELETE&lt;/code&gt; 法实现具有删除最后条目功能的 RESTful API。&lt;/p&gt;
&lt;h4&gt;Restful 规范&lt;/h4&gt;
&lt;p&gt;用 url 来指代资源，用请求类型来指代动作。&lt;/p&gt;
&lt;h3&gt;Ajax、Fetch 与 axios&lt;/h3&gt;
&lt;h4&gt;Ajax&lt;/h4&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest&quot;&gt;&lt;code&gt;XMLHttpRequest&lt;/code&gt;&lt;/a&gt; 实现
特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;会遇到 XSS、CSRF 攻击&lt;/li&gt;
&lt;li&gt;本身是针对 MVC 的编程，不符合现在前端 MVVM 的浪潮。&lt;/li&gt;
&lt;li&gt;基于原生的 XHR 开发，XHR 本身的架构不清晰，已经有了 fetch 的替代方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Fetch&lt;/h4&gt;
&lt;p&gt;Fetch 是 XHR 的替代，ES6 出现的，使用了 ES6 中的 promise 对象，由 js 原生提供，没有使用 XMLHttpRequest 对象
特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;符合关注分离，没有将输入、输出和用事件来跟踪的状态混杂在一个对象里&lt;/li&gt;
&lt;li&gt;更好更方便的写法&lt;/li&gt;
&lt;li&gt;更加底层，提供的 API 丰富（request, response）&lt;/li&gt;
&lt;li&gt;脱离了 XHR，是 ES 规范里新的实现方式&lt;/li&gt;
&lt;li&gt;fetchtch 只对网络请求报错，对 400，500 都当做成功的请求，需要封装去处理&lt;/li&gt;
&lt;li&gt;fetch 默认不会带 cookie，需要添加配置项&lt;/li&gt;
&lt;li&gt;fetch 不支持 abort，不支持超时控制，使用 setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求过程继续在后台运行，造成了量的浪费&lt;/li&gt;
&lt;li&gt;fetch 没有办法原生监测请求的进度，而 XHR 可以。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;fetch(url, {
    body: JSON.stringify(data), // must match &amp;#39;Content-Type&amp;#39; header
    cache: &amp;#39;no-cache&amp;#39;, // *default, no-cache, reload, force-cache, only-if-cached
    credentials: &amp;#39;same-origin&amp;#39;, // include, same-origin, *omit
    headers: {
      &amp;#39;user-agent&amp;#39;: &amp;#39;Mozilla/4.0 MDN Example&amp;#39;,
      &amp;#39;content-type&amp;#39;: &amp;#39;application/json&amp;#39;
    },
    method: &amp;#39;POST&amp;#39;, // *GET, POST, PUT, DELETE, etc.
    mode: &amp;#39;cors&amp;#39;, // no-cors, cors, *same-origin
    redirect: &amp;#39;follow&amp;#39;, // manual, *follow, error
    referrer: &amp;#39;no-referrer&amp;#39;, // *client, no-referrer
  })
  .then(response =&amp;gt; response.json()) // parses response to JSON
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;axios&lt;/h4&gt;
&lt;p&gt;axios 是一个基于 Promise 的用于浏览器和 nodejs 的 HTTP 客户端，本质上也是对原生 XHR 的封装，只不过它是 Promise 的实现版本，符合最新的 ES 规范。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持 Promise API。&lt;/li&gt;
&lt;li&gt;提供了一些并发请求的接口（重要，方便了很多的操作）。&lt;/li&gt;
&lt;li&gt;在浏览器中创建 XMLHttpRequests。在 node.js 则创建 http 请求。（自动性强）&lt;/li&gt;
&lt;li&gt;支持拦截请求和响应。&lt;/li&gt;
&lt;li&gt;自动转换 JSON 数据。&lt;/li&gt;
&lt;li&gt;客户端支持防御 CSRF、 XSRF。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Fetch 与 Ajax 的不同&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;当接收到一个代表错误的 HTTP 状态码时，从 &lt;code&gt;fetch()&lt;/code&gt; 返回的 Promise 不会被标记为 reject，而是标记为 resolve （返回值的 &lt;code&gt;ok&lt;/code&gt; 属性设置为 false ），仅当网络故障时或请求被阻止时，才会标记为 reject。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch()&lt;/code&gt; **可以接受跨域 cookies；**你也可以使用 &lt;code&gt;fetch()&lt;/code&gt; 建立起跨域会话。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch&lt;/code&gt; &lt;strong&gt;不会发送 cookies&lt;/strong&gt;。除非你使用了&lt;em&gt;credentials&lt;/em&gt; 的&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters&quot;&gt;初始化选项&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;fetch 发送 2 次请求的原因&lt;/h4&gt;
&lt;p&gt;用 fetch 的 post 请求时，第一次发送了一个 Options 请求，询问服务器是否支持该类型的请求，如果服务器支持，则在第二次中发送真正的请求。&lt;/p&gt;
&lt;h3&gt;强缓存与协商缓存&lt;/h3&gt;
&lt;h4&gt;流程图&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1684814927000mi8y0n.png&quot; alt=&quot;强缓存与协商缓存&quot;&gt;&lt;/p&gt;
&lt;h4&gt;缓存&lt;/h4&gt;
&lt;p&gt;缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储，它会拦截请求，返回该资源的拷贝，而不会去源服务器重新下载。&lt;/p&gt;
&lt;p&gt;好处：缓解服务器端压力，提升性能(获取资源的耗时更短了)&lt;/p&gt;
&lt;p&gt;告诉浏览器在约定的这个时间前，可以直接从缓存中获取资源，而无需跑到服务器去获取。&lt;/p&gt;
&lt;p&gt;http 缓存机制主要在 http 响应头中设定，响应头中相关字段为&lt;strong&gt;Expires、Cache-Control、Last-Modified、Etag&lt;/strong&gt;。&lt;/p&gt;
&lt;h4&gt;强缓存（过期时间）&lt;/h4&gt;
&lt;p&gt;浏览器不会像服务器发送任何请求，直接从本地缓存中读取文件并返回&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cache-Control&lt;/strong&gt;（优先级更高）：当值设为 max-age=300 时，则代表在这个请求正确返回时间的 5 分钟内再次加载资源，就会命中强缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expires&lt;/strong&gt;：过期时间，如果设置了时间，则浏览器会在设置的时间内直接读取缓存，不再请求&lt;/p&gt;
&lt;h4&gt;协商缓存（修改时间）&lt;/h4&gt;
&lt;p&gt;当资源过期时，向服务器发送请求，服务器根据请求头参数来判断是否命中协商缓存，如果命中，则返回 304 状态码并告诉浏览器从缓存中读取资源，否则返回 200 状态码和新资源。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;协商缓存标识 1，加上时间戳的 hash 值：&lt;strong&gt;etag&lt;/strong&gt;/if-none-match&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当资源过期时，浏览器发现响应头里有 Etag,则再次像服务器请求时带上请求头 if-none-match(值是 Etag 的值)。服务器收到请求进行比对，决定返回新页面 200 或 304&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标识 2，最新修改时间：&lt;strong&gt;Last-modified&lt;/strong&gt;/if-modify-since&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当资源过期时（浏览器判断 Cache-Control 标识的 max-age 过期），发现响应头具有 Last-Modified 声明，则再次向服务器请求时带上头 if-modified-since，表示请求时间。服务器收到请求后发现有 if-modified-since 则与被请求资源的最后修改时间进行对比（Last-Modified）,若最后修改时间较新（大），说明资源又被改过，则返回最新资源，HTTP 200 OK;若最后修改时间较旧（小），说明资源无新修改，响应 HTTP 304 走缓存。&lt;/p&gt;
&lt;h4&gt;Cache-control&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;max-age：最大有效时间&lt;/li&gt;
&lt;li&gt;no-cache：不使用强缓存，需要与服务器验证缓存是否新鲜&lt;/li&gt;
&lt;li&gt;no-store：不使用缓存，包括强缓存和协商缓存&lt;/li&gt;
&lt;li&gt;public：所有的内容都可以被缓存，包括客户端和代理服务器，比如 CDN&lt;/li&gt;
&lt;li&gt;provate：所有的内容只有单个用户即客户端才可以缓存，代理服务器不能缓存。是默认值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;字段&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;name&lt;/li&gt;
&lt;li&gt;value&lt;/li&gt;
&lt;li&gt;size&lt;/li&gt;
&lt;li&gt;domain&lt;/li&gt;
&lt;li&gt;path&lt;/li&gt;
&lt;li&gt;expires/max-age：过期时间&lt;/li&gt;
&lt;li&gt;http：httponly，无法通过 document.cookie 来获取 cookie&lt;/li&gt;
&lt;li&gt;secure：设置是否只能由 https 来传递此 cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cookie 与 Session&lt;/h3&gt;
&lt;p&gt;作用：由于 http 的无状态性（这一次请求和上一次请求是没有任何关系的，互不认识的，没有关联的），为了使某个域名下的所有网页能够共享某些数据，session 和 cookie 出现了。&lt;/p&gt;
&lt;p&gt;Cookie 是用户通行证，存储在客户端，在发送请求时附带。session 有如用户信息档案表, 里面包含了用户的认证信息和登录状态等信息，保存在服务器端。&lt;/p&gt;
&lt;h4&gt;Cookie 和 Session 共同使用&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;客户端发一个 http 请求给服务器&lt;/li&gt;
&lt;li&gt;服务器接受请求后，建立一个 session，发回 http 响应给客户端，其中的 set-cookie 头部带有 sessionid&lt;/li&gt;
&lt;li&gt;客户端收到响应后，后续会自动在请求头中加 cookie&lt;/li&gt;
&lt;li&gt;服务器接收请求，分解 cookie，验证成功后将请求返回给客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用 session 只需在客户端保存一个 id，大量数据都是保存在服务端，对服务器有压力。&lt;/p&gt;
&lt;p&gt;用 cookie 不用 session，那么账户信息全部保存在客户端，一旦被劫持，全部信息都会泄露。并且客户端数据量变大，网络传输的数据量也会变大。&lt;/p&gt;
&lt;h3&gt;Token&lt;/h3&gt;
&lt;p&gt;是一种服务端无状态的认证方式。Token 类似一个令牌，无状态，用户信息都被加密到 token 中，服务器收到 token 后解密就可知道是哪个用户。需要开发者手动添加。&lt;/p&gt;
&lt;p&gt;token 在客户端一般存放于 localStorage，cookie，或 sessionStorage 中。在服务器一般存于数据库中&lt;/p&gt;
&lt;p&gt;token 的认证流程与 cookie 很相似&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户登录，成功后服务器返回 Token 给客户端。&lt;/li&gt;
&lt;li&gt;客户端收到数据后保存在客户端&lt;/li&gt;
&lt;li&gt;客户端再次访问服务器，将 token 放入 headers 中&lt;/li&gt;
&lt;li&gt;服务器端采用 filter 过滤器校验。校验成功则返回请求数据，校验失败则返回错误码&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;用 Token，不用 Cookie+Session 的优点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;避免 CSRF 攻击&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用户登陆银行网页，同时登陆了危险网页，攻击者在网页放一个表单，该表单提交 src 为&lt;code&gt;http://www.bank.com/api/transfer&lt;/code&gt;，body 为&lt;code&gt;count=1000&amp;amp;to=Tom&lt;/code&gt;。倘若是 session+cookie，表单发起的 POST 请求不受到浏览器同源策略限制，可以使用其它域的 Cookie 向其它域发送 POST 请求，形成 CSRF 攻击。在 post 请求的瞬间，cookie 会被浏览器自动添加到请求头中。但 token 不同，token 是开发者为了防范 csrf 而特别设计的令牌，浏览器不会自动添加到 headers 里，攻击者也无法访问用户的 token，所以提交的表单无法通过服务器过滤，也就无法形成攻击。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Token 是一种服务端无状态的认证方式，而 cookie+session 是有状态的。（ 所谓无状态就是服务端并不会保存身份认证相关的数据。）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;JWT&lt;/h4&gt;
&lt;p&gt;头部 +负载+签名&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// javascript
const encodedString = `${base64UrlEncode(header)}.${base64UrlEncode(payload)}`

const signature = HMACSHA256(encodedString, &amp;#39;secret&amp;#39;) // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ,加盐secret组合加密
// 将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在客户端应用：一般是在请求头里加入&lt;code&gt;Authorization&lt;/code&gt;，并加上&lt;code&gt;Bearer&lt;/code&gt;标注&lt;/p&gt;
&lt;p&gt;流程和 token 的一样&lt;/p&gt;
&lt;p&gt;缺点：一旦 JWT 签发了，在到期之前就会始终有效，除非服务器部署额外的逻辑。JWT 本身包含了认证信息，一旦泄露，任何人都可以获得该令牌的所有权限。&lt;/p&gt;
&lt;h3&gt;cookie 和 token 都存放在 header 中，为什么不会劫持 token？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;攻击者通过 xss 拿到用户的 cookie 然后就可以伪造 cookie 了。
通过 csrf 在同个浏览器下面通过浏览器会自动带上 cookie 的特性
在通过 用户网站-攻击者网站-攻击者请求用户网站的方式 浏览器会自动带上 cookie&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不会被浏览器带上 问题 2 解决
token 是放在 jwt 里面下发给客户端的 而且不一定存储在哪里 不能通过 document.cookie 直接拿到，通过 jwt+ip 的方式 可以防止 被劫持 即使被劫持 也是无效的 jwt&lt;/p&gt;
&lt;h3&gt;浏览器存储方式：Cookie、SessionStorage、LocalStorage&lt;/h3&gt;
&lt;p&gt;共同点：都是存储在浏览器端&lt;/p&gt;
&lt;p&gt;不同点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;cookie 可以在浏览器和服务器中来回传递的，而余下两者是只在本地保存的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可存储数据的大小不一样，cookie 数据不能超过 4k，剩下的就比较大了，大概是在 5M 左右。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;数据有效期不一样，sessionStorage 当关闭浏览器的时候就失效了，localStorage 一直有效，需要手动清&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除，而 cookie 只在有效期之内一直有效。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;作用域不一样，localStorage、cookie 在所有同源窗口中都是共享的，sessionStorage 是某个窗口私有&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的。&lt;/p&gt;
&lt;h3&gt;跨页面通信&lt;/h3&gt;
&lt;p&gt;同源页面（不在同一个 tab）：可以使用 LocalStorage&lt;/p&gt;
&lt;p&gt;非同源页面：iframe、postmessage&lt;/p&gt;
&lt;p&gt;H5 之后为 window 新增了 window.postMessage()方法，第一个参数是要发送的数据，第二个参数是域名。&lt;/p&gt;
&lt;h3&gt;Doctype&lt;/h3&gt;
&lt;p&gt;声明于文档最前面，告诉服务器以什么方式（例如 h5）来渲染页面。&lt;/p&gt;
&lt;p&gt;运行模式分：严格模式（浏览器支持的最高版本）、混杂模式（向后兼容）&lt;/p&gt;
&lt;h3&gt;XSS&lt;/h3&gt;
&lt;p&gt;跨站脚本攻击，指攻击者在网页中注入恶意代码，在用户浏览网页的时候进行攻击。&lt;/p&gt;
&lt;p&gt;类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;反射型：将攻击代码放在 url 地址的请求参数中&lt;/li&gt;
&lt;li&gt;存储型：攻击者输入一些数据并且存储到了数据库中，其他浏览者看到的时候进行攻击。&lt;/li&gt;
&lt;li&gt;DOM 型：攻击者通过各种手段将恶意脚本注入用户的页面中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;set-cookie：httponly，禁止 javascript 脚本来访问 cookie，secure - 这个属性告诉浏览器仅在请求为 https 的时候发送 cookie。&lt;/li&gt;
&lt;li&gt;输入检查：对于用户的任何输入要进行检查、过滤和转义&lt;/li&gt;
&lt;li&gt;输出检查&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSRF&lt;/h3&gt;
&lt;p&gt;Cross Site Request Forgery，跨站请求伪造&lt;/p&gt;
&lt;p&gt;在讲 token 时讲了&lt;/p&gt;
&lt;p&gt;防御 CSRF 攻击主要有三种策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;验证 HTTP Referer 字段；&lt;/li&gt;
&lt;li&gt;在请求地址中添加 token 并验证；&lt;/li&gt;
&lt;li&gt;在 HTTP 头中自定义属性并验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;addEventListener&lt;/h3&gt;
&lt;p&gt;addEventListener(event, function, useCapture)&lt;/p&gt;
&lt;p&gt;其中，event 指定事件名；function 指定要事件触发时执行的函数；useCapture 指定事件是否在捕获或冒泡阶段执行。&lt;/p&gt;
&lt;h3&gt;跨域&lt;/h3&gt;
&lt;p&gt;可看：&lt;a href=&quot;https://zh.javascript.info/fetch-crossorigin&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;postMessage 跨域：可以跨域操作的 window 属性之一。&lt;/li&gt;
&lt;li&gt;CORS：服务端设置 Access-Control-Allow-Origin 即可，前端无须设置，若要带 cookie 请求，前后端都需要设置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Origin *;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Methods &amp;quot;POST, GET, OPTIONS&amp;quot;;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Headers &amp;quot;Origin, Authorization, Accept&amp;quot;;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Credentials true;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;代理跨域：启一个代理服务器，实现数据的转发&lt;/li&gt;
&lt;li&gt;JSONP：script 标签 src 属性中的链接却可以访问跨域的 js 脚本，利用这个特性，服务端不再返回 JSON 格式的数据，而是返回一段调用某个函数的 js 代码，在 src 中进行了调用，这样实现了跨域。例如：&lt;code&gt;script.src = http://another.com/weather.json?callback=gotWeather;&lt;/code&gt;，需要后端配合。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;查看网站性能&lt;/h3&gt;
&lt;p&gt;检测页面加载时间&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;被动检测：在页面设置检测脚本，当用户访问网页时，记录数据，传回数据库分析&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;主动监测：搭建分布式环境，模拟用户访问页面，主动采集数据并分析&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;前端优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;降低请求量：合并资源，减少 http 请求数&lt;/li&gt;
&lt;li&gt;加快请求速度：预解析 DNS、CDN 分发&lt;/li&gt;
&lt;li&gt;使用缓存&lt;/li&gt;
&lt;li&gt;加快渲染：加载顺序（js 放最后），SSR，使用 GPU&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;屏幕卡顿&lt;/h3&gt;
&lt;p&gt;原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内存溢出&lt;/li&gt;
&lt;li&gt;资源过大&lt;/li&gt;
&lt;li&gt;资源加载&lt;/li&gt;
&lt;li&gt;canvas 绘制帧率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在物体离开屏幕可视区域即回收销毁&lt;/li&gt;
&lt;li&gt;选用体积较小的资源，例如图片，可以在近处放清晰度高的，远处放清晰度低的&lt;/li&gt;
&lt;li&gt;预加载&lt;/li&gt;
&lt;li&gt;大部分显示器刷新频率为 60 次/s，因此游戏的每一帧绘制间隔时间需要小于 1000/60=16.7ms，才能让用户觉得不卡顿&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;js 加载过程阻塞，解决方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;制定 script 标签的 async 属性，异步执行&lt;/li&gt;
&lt;li&gt;设置 defer 属性，脚本将在页面完成解析时执行&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;BOM&lt;/h3&gt;
&lt;p&gt;Brower object model，浏览器对象模型，它使 JavaScript 有能力与浏览器进行“对话”。window 对象 所有浏览器都支持 window 对象。它表示浏览器窗口。&lt;/p&gt;
&lt;h3&gt;顶层对象&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器：window/self&lt;/li&gt;
&lt;li&gt;web worker：self&lt;/li&gt;
&lt;li&gt;node：global&lt;/li&gt;
&lt;li&gt;ES5：顶层对象的属性与全局变量等价&lt;/li&gt;
&lt;li&gt;ES6：globalThis&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;This&lt;/h3&gt;
&lt;p&gt;同一段代码为了能够在各种环境，都能取到顶层对象，现在一般是使用&lt;code&gt;this&lt;/code&gt;变量，但是有局限性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;全局环境中，this 会返回等层对象。但是在 node 的模块中，返回的是当前模块，ES6 中返回的是 undifined。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;函数里的 this，作为对象方法运行返回的是对象，或者是调用方，单纯作为函数运行会指向顶层对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ES2020 引入 globalThis 对象，在任何环境下都指向全局环境下的 this&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CSS 与 html&lt;/h2&gt;
&lt;h3&gt;DOM&lt;/h3&gt;
&lt;p&gt;DOM（Document Object Model——文档对象模型）&lt;/p&gt;
&lt;h3&gt;Document&lt;/h3&gt;
&lt;h4&gt;查找&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;document.getElementById(id)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;document.getElementByClassName(class)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;document.getElementByTagName(tag)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;document.querySelector(selectors)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示文档中与指定的一组 CSS 选择器匹配的第一个元素,一个 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement&quot;&gt;&lt;code&gt;HTMLElement&lt;/code&gt;&lt;/a&gt;对象。如果没有匹配到，则返回 null。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var el = document.querySelector(&amp;quot;div.user-panel.main input[name=&amp;#39;login&amp;#39;]&amp;quot;);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里, 一个 class 属性为”user-panel main”的 div 元素&lt;code&gt;&amp;lt;div class=&amp;quot;user-panel main&amp;quot;&amp;gt;&lt;/code&gt;内包含一个 name 属性为”login”的 input 元素&lt;code&gt;&amp;lt;input name=&amp;quot;login&amp;quot;/&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Document/querySelectorAll&quot;&gt;&lt;code&gt;querySelectorAll()&lt;/code&gt;&lt;/a&gt; ，与指定选择器匹配的所有元素的列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ParentNode.firstElementChild&lt;/code&gt;，返回第一个子元素或者 null&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ParentNode.lastElementChild&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;node.parentNode&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;创建&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createElement&quot;&gt;&lt;code&gt;Document.createElement()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用给定标签名 tagName 创建一个新的元素。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node.cloneNode(deep)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回调用该方法的节点的一个副本。deep，可选参数，是否采用深度克隆&lt;code&gt;,如果为true,&lt;/code&gt;则该节点的所有后代节点也都会被克隆,如果为&lt;code&gt;false,则只克隆该节点本身.&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;加入&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parentNode.append(node|str)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 &lt;code&gt;ParentNode&lt;/code&gt;的最后一个子节点之后插入一组 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node&quot;&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/a&gt; 对象或 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/DOMString&quot;&gt;&lt;code&gt;DOMString&lt;/code&gt;&lt;/a&gt; 对象。被插入的 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/DOMString&quot;&gt;&lt;code&gt;DOMString&lt;/code&gt;&lt;/a&gt; 对象等价为 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Text&quot;&gt;&lt;code&gt;Text&lt;/code&gt;&lt;/a&gt; 节点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ParentNode.prepend&lt;/code&gt;方法可以在父节点的第一个子节点之前插入一系列&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node&quot;&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/a&gt;对象或者&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/DOMString&quot;&gt;&lt;code&gt;DOMString&lt;/code&gt;&lt;/a&gt;对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;node.appendChild(node)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将一个节点附加到指定父节点的子节点列表的末尾处。&lt;/p&gt;
&lt;p&gt;如果将被插入的节点已经存在于当前文档的文档树中，那么 &lt;code&gt;appendChild()&lt;/code&gt; 只会将它从原先的位置移动到新的位置（不需要事先移除要移动的节点）。这意味着，一个节点不可能同时出现在文档的不同位置。&lt;/p&gt;
&lt;p&gt;如果某个节点已经拥有父节点，在被传递给此方法后，它首先会被移除，再被插入到新的位置。&lt;/p&gt;
&lt;p&gt;若要保留已在文档中的节点，可以先使用 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node/cloneNode&quot;&gt;&lt;code&gt;Node.cloneNode()&lt;/code&gt;&lt;/a&gt; 方法来为它创建一个副本，再将副本附加到目标父节点下。请注意，用 &lt;code&gt;cloneNode&lt;/code&gt; 制作的副本不会自动保持同步。&lt;/p&gt;
&lt;p&gt;【与 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild&quot;&gt;&lt;code&gt;Node.appendChild()&lt;/code&gt;&lt;/a&gt; 的差异】&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParentNode.append()&lt;/code&gt;允许追加 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/DOMString&quot;&gt;&lt;code&gt;DOMString&lt;/code&gt;&lt;/a&gt; 对象，而 &lt;code&gt;Node.appendChild()&lt;/code&gt; 只接受 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node&quot;&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/a&gt; 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ParentNode.append()&lt;/code&gt; &lt;a href=&quot;https://repl.it/FgPh/1&quot;&gt;没有返回值&lt;/a&gt;，而 &lt;code&gt;Node.appendChild()&lt;/code&gt; 返回追加的 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Node&quot;&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/a&gt; 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ParentNode.append()&lt;/code&gt; 可以追加多个节点和字符串，而 &lt;code&gt;Node.appendChild()&lt;/code&gt; 只能追加一个节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;删除&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parent.removeChild(child)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据父母节点来删除节点。删除后的节点虽然不在文档树中了，但其实它还在内存中，可以随时再次被添加到别的位置。&lt;/p&gt;
&lt;h4&gt;获取子节点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node.children()&lt;/code&gt;，返回 一个 Node 的子&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Element&quot;&gt;&lt;code&gt;elements&lt;/code&gt;&lt;/a&gt; ，是一个动态更新的 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCollection&quot;&gt;&lt;code&gt;HTMLCollection&lt;/code&gt;&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSS 选择器&lt;/h3&gt;
&lt;h4&gt;基本选择器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通用选择器：&lt;code&gt;* {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;元素(类型)选择器：&lt;code&gt;p {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;类选择器：&lt;code&gt;.class {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ID 选择器：&lt;code&gt;#id {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;属性选择器：&lt;code&gt;[attr=value] {}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;分组选择器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;, 的选择器列表：&lt;code&gt;div, span {}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;组合器（关系选择符）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;后代组合器：&lt;code&gt;div span {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;直接子代组合器：&lt;code&gt;div&amp;gt;span {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一般兄弟组合器：&lt;code&gt;A~B {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;紧邻兄弟组合器：&lt;code&gt;A+B {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;列选择器：&lt;code&gt;col || td&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;伪选择器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;伪类：&lt;code&gt;a:visited {}&lt;/code&gt;，匹配所有曾被访问过的&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;元素。支持按照状态信息来选择元素。&lt;/li&gt;
&lt;li&gt;伪元素：&lt;code&gt;p::first-line&lt;/code&gt;，匹配所有&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;元素的第一行。伪选择器用于表示无法用 HTML 语义表达的实体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSS 优先级&lt;/h3&gt;
&lt;p&gt;递增的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors&quot;&gt;类型选择器&lt;/a&gt;（例如，&lt;code&gt;h1&lt;/code&gt;）和&lt;strong&gt;伪元素&lt;/strong&gt;（例如，&lt;code&gt;::before&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors&quot;&gt;类选择器&lt;/a&gt; (例如，&lt;code&gt;.example&lt;/code&gt;)，&lt;strong&gt;属性选择器&lt;/strong&gt;（例如，&lt;code&gt;[type=&amp;quot;radio&amp;quot;]&lt;/code&gt;）和&lt;strong&gt;伪类&lt;/strong&gt;（例如，&lt;code&gt;:hover&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/ID_selectors&quot;&gt;ID 选择器&lt;/a&gt;（例如，&lt;code&gt;#example&lt;/code&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;带有 &lt;code&gt;!important&lt;/code&gt; 标记的样式属性的优先级最高；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通配选择符&lt;/strong&gt;（universal selector）（&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/Universal_selectors&quot;&gt;&lt;code&gt;*&lt;/code&gt;&lt;/a&gt;）&lt;strong&gt;关系选择符&lt;/strong&gt;（combinators）（&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/Adjacent_sibling_combinator&quot;&gt;&lt;code&gt;+&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/Child_combinator&quot;&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/General_sibling_combinator&quot;&gt;&lt;code&gt;~&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator&quot;&gt;&lt;code&gt;&amp;#39; &amp;#39;&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/Column_combinator&quot;&gt;&lt;code&gt;||&lt;/code&gt;&lt;/a&gt;）和 &lt;strong&gt;否定伪类&lt;/strong&gt;（negation pseudo-class）（&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/:not&quot;&gt;&lt;code&gt;:not()&lt;/code&gt;&lt;/a&gt;）对优先级没有影响。&lt;/p&gt;
&lt;p&gt;样式表的来源不同时，优先级顺序为：内联样式&amp;gt; 内部样式 &amp;gt; 外部样式 &amp;gt; 浏览器用户自定义样式 &amp;gt; 浏览器默认样式&lt;/p&gt;
&lt;h3&gt;盒子模型&lt;/h3&gt;
&lt;h4&gt;content-padding-border-margin&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;标准（W3C）盒子模型：width = content&lt;/li&gt;
&lt;li&gt;IE 盒子模型：width = content+padding+border&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;content 大小自适应&lt;/p&gt;
&lt;h4&gt;使用 box-sizing 设置&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;box-sizing&lt;/code&gt;：规定两个并排的带边框的框，语法为&lt;code&gt;box-sizing：content-box/border-box/inherit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;content-box&lt;/code&gt;：宽度和高度分别应用到元素的内容框，在宽度和高度之外绘制元素的内边距和边框&lt;/p&gt;
&lt;p&gt;&lt;code&gt;border-box&lt;/code&gt;：为元素设定的宽度和高度决定了元素的边框盒，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;inherit&lt;/code&gt;：继承父元素的 box-sizing&lt;/p&gt;
&lt;h3&gt;overflow&lt;/h3&gt;
&lt;p&gt;CSS 属性 &lt;strong&gt;overflow&lt;/strong&gt; 定义当一个元素的内容太大而无法适应 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context&quot;&gt;块级格式化上下文&lt;/a&gt; 时候该做什么。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;visible：默认值。内容不会被修剪，会呈现在元素框之外&lt;/li&gt;
&lt;li&gt;hidden：内容会被修剪，并且其余内容不可见&lt;/li&gt;
&lt;li&gt;scroll：内容会被修剪，浏览器会显示滚动条以便查看其余内容&lt;/li&gt;
&lt;li&gt;auto：由浏览器定夺，如果内容被修剪，就会显示滚动条&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为使 &lt;code&gt;overflow&lt;/code&gt;有效果，块级容器必须有一个指定的高度。除了 visible 外，其它都触发 BFC&lt;/p&gt;
&lt;h3&gt;background-size&lt;/h3&gt;
&lt;p&gt;用于调整背景图片的宽和高，可以放大和缩小。（因为默认图片布局是根据其尺寸平铺）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;background-size: 300px 150px; // 宽和长，强制转换
background-size: contain; // 确保两个尺寸(图片的宽和高)都小于或等于容器的相应尺寸。
background-size: cover; // 确保两个尺寸(图片的宽和高)都大于或等于容器的相应尺寸。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Background-origin&lt;/h3&gt;
&lt;h3&gt;animation&lt;/h3&gt;
&lt;p&gt;从一个 CSS 样式配置转换到另一个 CSS 样式配置&lt;/p&gt;
&lt;p&gt;两个部分：描述动画的&lt;strong&gt;样式规则&lt;/strong&gt;，用于制定动画开始、结束以及中间点样式的&lt;strong&gt;关键帧&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;p {
  animation-duration: 3s; // 持续时间
  animation-name: slidein; // 动画名字
  background: red;
  animation-iteration-count: 2; // 设置运行次数，无穷是默认值，或许直接写infinite
  animation-direction: alternate; // 来回播放，而不是从头播放
}

@keyframes slidein {
  from {
    // 代表0%
    margin-left: 100%;
    width: 300%;
  }
  50% {
    font-size: 300%;
  }
  to {
    // 代表 100%
    margin-left: 0%;
    width: 100%;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;transform&lt;/h3&gt;
&lt;h3&gt;box-sizing&lt;/h3&gt;
&lt;p&gt;content 内容自适应。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;box-sizing: content-box;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示标准的 W3C 盒子模型，width = content;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;box-sizing: border-box&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示的是 IE 盒子模型，width = border + padding + content&lt;/p&gt;
&lt;h3&gt;Border-radius&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;边框：&lt;code&gt;border-radius&lt;/code&gt;，&lt;code&gt;box-shadow&lt;/code&gt;等；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;画一个三角形&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div id=&amp;quot;demo&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
#demo{ width:0px; height:0px; border:40px solid transparent; border-bottom:80px solid red; }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;垂直居中&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;#box {
    width: 300px;
    height: 300px;
    background: #ddd;
}
#child {
    background: orange;
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
}

// 2

#box {
    width: 300px;
    background: #ddd;
    padding: 100px 0;
}
#child {
    width: 200px;
    height: 100px;
    background: orange;
}

// 3
#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    display: flex;
    align-items: center; // 垂直居中
    justify-content: center;// 水平居中
}

&amp;lt;div id=&amp;quot;box&amp;quot;&amp;gt;
    &amp;lt;div id=&amp;quot;child&amp;quot;&amp;gt;test vertical align&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;三列布局&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;1: parent的div设置display：grid，设置grid-template-columns属性，固定第一列第二列宽度，第三列auto

2: 给div设置float：left，再给right的div设置overflow:hidden。这样子两个盒子浮动，另一个盒子触发bfc达到自适应

&amp;lt;div class=&amp;quot;div1&amp;quot;&amp;gt; 1&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;div2&amp;quot;&amp;gt;2&amp;lt;/div&amp;gt;
&amp;lt;div class= &amp;quot;div3&amp;quot;&amp;gt; 3 &amp;lt;/div&amp;gt;

.div1,
.div2 {
  float: left;
  height: 100px;
  width: 100px;
  background: blue;
}
.div3 {
  overflow: auto;
  height: 100px;
  width: 100px;
  background: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;js 设置轮播&lt;/h3&gt;
&lt;p&gt;图片轮播的原理就是图片排成一行，然后准备一个只有一张图片大小的容器，对这个容器设置超出部分隐藏，在控制定时器来让这些图片整体左移或右移，这样呈现出来的效果就是图片在轮播了。&lt;/p&gt;
&lt;p&gt;如果有两个轮播，可封装一个轮播组件，供两处调用。&lt;/p&gt;
&lt;h3&gt;link 和@import 的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;link 是 html 标签，没有兼容性问题，@import 是 css 提供的，IE5 以上才能识别&lt;/li&gt;
&lt;li&gt;link 样式的权重高于@import&lt;/li&gt;
&lt;li&gt;link 和页面同时加载，@import 在页面加载结束后才加载&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;transition 和 animation 的区别&lt;/h3&gt;
&lt;p&gt;Animation 和 transition 大部分属性是相同的，他们都是随时间改变元素的属性值，他们的主要区别是 transition 需要触发一个事件才能改变属性，而 animation 不需要触发任何事件的情况下才会随时间改变属性值，并且 transition 为 2 帧，从 from …. to，而 animation 可以一帧一帧的。&lt;/p&gt;
&lt;h3&gt;Flex 布局&lt;/h3&gt;
&lt;p&gt;Flex 是弹性布局，用来为盒状模型提供最大的灵活性，传统布局方式依赖 position、float 和 display 属性，对特殊布局不方便。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容器属性&lt;ul&gt;
&lt;li&gt;flex-direction：决定主轴的方向（即子 item 的排列方法）&lt;/li&gt;
&lt;li&gt;flex-wrap：决定换行规则&lt;/li&gt;
&lt;li&gt;justify-content：对其方式，水平主轴对齐方式&lt;/li&gt;
&lt;li&gt;align-items：对齐方式，竖直轴线方向&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;元素属性&lt;ul&gt;
&lt;li&gt;align-self：允许单个项目与其他项目不一样的对齐方式，可以覆盖 align-items，默认属性为 auto，表示继承父元素的 align-items&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;双边距重叠问题（外边距折叠）&lt;/h3&gt;
&lt;p&gt;多个相邻（兄弟或者父子关系）普通流的块元素垂直方向 marigin 会重叠&lt;/p&gt;
&lt;p&gt;折叠的结果为：&lt;/p&gt;
&lt;p&gt;两个相邻的外边距都是正数时，折叠结果是它们两者之间较大的值。
两个相邻的外边距都是负数时，折叠结果是两者绝对值的较大值。
两个外边距一正一负时，折叠结果是两者的相加的和。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.div {
  display: flex; //display: flex;的元素生成BFC
  flex-direction: column;
}
// 分组选择器
.div1,
.div2 {
  height: 100px;
  width: 100px;
  border: 1px solid #000;
  margin: 100px;
  /* 显然，两个边框之间的距离不是400，而是200 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;BFC&lt;/h3&gt;
&lt;p&gt;作用：用于清除浮动，防止 margin 重叠等&lt;/p&gt;
&lt;p&gt;块级格式化上下文，是一个独立的渲染区域，并且有一定的布局规则。BFC 是页面上的一个独立容器，子元素不会影响到外面。&lt;/p&gt;
&lt;p&gt;BFC 区域不会与 float box 重叠，计算 BFC 的高度时，浮动元素也会参与计算&lt;/p&gt;
&lt;p&gt;那些元素会生成 BFC：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;根元素&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;float：不为 none&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;position：fixed/absolute&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;display：inline-block、table-cell、table-caption，flex，inline-flex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;overflow：不为 visible&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;元素消失&lt;/h3&gt;
&lt;p&gt;visibility=hidden, opacity=0，display:none&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;opacity=0，元素隐藏，不改变页面布局，可触发绑定事件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;visibility=hidden，元素隐藏，不改变页面布局，不会触发绑定事件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;display=none，元素隐藏，改变页面布局，可以理解成在页面中把该元素删除掉一样。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;position 属性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;fixed：相对浏览器窗口固定，即使窗口滚动它也不懂，不在文档流中，fixed 元素可与其余元素重叠&lt;/li&gt;
&lt;li&gt;relative：相对于自身原本位置偏移，元素在文档流中仍占据原来的空间&lt;/li&gt;
&lt;li&gt;absolute：相对于最近的父元素定位，不在文档流中&lt;/li&gt;
&lt;li&gt;static：默认值，没有定位，出现在正常的文档流中，忽略任何 top,buttom,left,right 声明&lt;/li&gt;
&lt;li&gt;sticky：元素先按照普通文档流定位，然后相对于该元素在流中的 flow root（BFC）和 containing block（最近的块级祖先元素）定位。一个 sticky 元素会“固定”在离它最近的一个拥有“滚动机制”的祖先上。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;浮动清除&lt;/h3&gt;
&lt;p&gt;在非 IE 浏览器（如 Firefox）下，当容器的高度为 auto，且容器的内容中有浮动（float 为 left 或 right）的元素，在这种情况下，容器的高度不能自动伸长以适应内容的高度，使得内容溢出到容器外面而影响（甚至破坏）布局的现象。这个现象叫浮动溢出，为了防止这个现象的出现而进行的 CSS 处理，就叫 CSS 清除浮动。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置 css 的 overflow 为 auto&lt;/li&gt;
&lt;li&gt;使用空元素，css 的 clear 属性为 both&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;block、inline、inline-block 的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;block 块元素独占一行，宽度自动填充为父元素宽度。元素的高度、宽度、行高以及顶和底边距都可设置。即使设置了宽度,仍然是独占一行。例如，&lt;code&gt;div, p&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;inline 元素，多个该元素排列在一行，直到超出，才会换新一行，其宽度随元素内容而变化。width,height 属性无效，垂直方向的 padding 和 margin 会失效。例如，&lt;code&gt;a, span&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;inline-block：既具有 block 的宽度高度特性又具有 inline 的同行特性。例如，&lt;code&gt;img,input&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSS 预处理器&lt;/h3&gt;
&lt;p&gt;预先编译处理&lt;code&gt;CSS&lt;/code&gt;。扩展 &lt;code&gt;CSS&lt;/code&gt; ，增加了变量、Mixin、函数等特性，供开发者编写源代码，随后经过专门的编译工具将源码转化为&lt;code&gt;CSS&lt;/code&gt;语法。&lt;/p&gt;
&lt;p&gt;特点：
• 嵌套；
• 变量；
• mixin/继承；
• 运算；
• 模块化；&lt;/p&gt;
&lt;p&gt;类别与发展：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2007， sass-scss（两套语法规则：一个依旧是用缩进作为分隔符来区分代码块的；另一套规则和 CSS 一样采用了大括号（｛｝）作为分隔符。后一种语法规则又名&lt;code&gt;SCSS&lt;/code&gt;，在 Sass3 之后的版本都支持这种语法规则。）&lt;/li&gt;
&lt;li&gt;2009，less（使用&lt;code&gt;CSS&lt;/code&gt;的语法）&lt;/li&gt;
&lt;li&gt;2010，Stylus（同时支持缩进和 CSS 常规样式书写规则）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;HTML5&lt;/h3&gt;
&lt;h4&gt;新增的元素&lt;/h4&gt;
&lt;p&gt;语义化：header, footer, nav, aside, article, section&lt;/p&gt;
&lt;p&gt;存储：sessionStorage, localStorage&lt;/p&gt;
&lt;p&gt;多媒体：audio, video&lt;/p&gt;
&lt;p&gt;绘制：svg, canvas, webgl&lt;/p&gt;
&lt;p&gt;通信：websocket&lt;/p&gt;
&lt;p&gt;多线程：web worker&lt;/p&gt;
&lt;h2&gt;操作系统&lt;/h2&gt;
&lt;h3&gt;进程和线程&lt;/h3&gt;
&lt;h4&gt;进程&lt;/h4&gt;
&lt;p&gt;系统调用资源的最小单位，也就是说是拥有资源且独立运行的最小单位。&lt;/p&gt;
&lt;h4&gt;线程&lt;/h4&gt;
&lt;p&gt;CPU 调度的最小单位。一个进程可以拥有多个线程，线程是可以独立运行的最小单位。&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;进程切换开销&lt;/strong&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;切换虚拟地址空间&lt;/li&gt;
&lt;li&gt;切换 CPU 上下文&lt;/li&gt;
&lt;li&gt;切换内核栈&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;&lt;strong&gt;线程切换开销&lt;/strong&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;切换 CPU 上下文&lt;/li&gt;
&lt;li&gt;切换内核栈&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;进程通信&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;管道&lt;/li&gt;
&lt;li&gt;消息队列&lt;/li&gt;
&lt;li&gt;信号量&lt;/li&gt;
&lt;li&gt;信号&lt;/li&gt;
&lt;li&gt;套接字 socket&lt;/li&gt;
&lt;li&gt;共享内存&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;js&lt;/h2&gt;
&lt;h3&gt;数据类型&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;6 种原始类型，可以使用 typeof 判断&lt;ul&gt;
&lt;li&gt;undefined&lt;/li&gt;
&lt;li&gt;Number&lt;/li&gt;
&lt;li&gt;Boolean&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;Symbol&lt;/li&gt;
&lt;li&gt;BigInt：BigInt 是通过在整数末尾附加 &lt;code&gt;n&lt;/code&gt; 或调用构造函数来创建的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;null，和其上六种属于属于原始值&lt;/li&gt;
&lt;li&gt;Object&lt;ul&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;li&gt;Map&lt;/li&gt;
&lt;li&gt;WeakMap&lt;/li&gt;
&lt;li&gt;Set&lt;/li&gt;
&lt;li&gt;WeakSet&lt;/li&gt;
&lt;li&gt;Date&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;基本数据类型与引用类型的区别&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基本数据类型&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;字符串（String）、数值（Number）、布尔值（Boolean）、Null、Undefined&lt;/p&gt;
&lt;p&gt;1.占用空间固定，保存在栈中&lt;/p&gt;
&lt;p&gt;2、保存与复制的是值本身&lt;/p&gt;
&lt;p&gt;3、使用 typeof 检测数据的类型&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;引用类型&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;对象（Object）、数组（Array）、函数（Function）&lt;/p&gt;
&lt;p&gt;1、占用空间不固定，保存在堆中&lt;/p&gt;
&lt;p&gt;2、保存与复制的是指向对象的一个指针&lt;/p&gt;
&lt;p&gt;3、使用 instanceof 检测数据类型&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Object&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Object.keys()，获取&lt;strong&gt;自身属性&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;for in 遍历&lt;strong&gt;原型链上扩展的属性&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Object.create()&lt;/code&gt;方法创建一个新对象，使用现有的对象来提供新创建的对象的&lt;code&gt;__proto__&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Object.assign()&lt;/code&gt; 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Object.assign(target, ...sources)=&amp;gt;target&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const target = { a: 1, b: 2 }
const source = { b: 4, c: 5 }

const returnedTarget = Object.assign(target, source)

console.log(target)
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget)
// expected output: Object { a: 1, b: 4, c: 5 }
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Object.defineProperties()&lt;/code&gt; 方法直接在一个对象上定义新的属性或修改现有属性，并返回该对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Object.defineProperties(obj, props)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;数组方法&lt;/h3&gt;
&lt;h4&gt;修改&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;push、unshift，原地修改&lt;/li&gt;
&lt;li&gt;pop、shift，原地修改&lt;/li&gt;
&lt;li&gt;splice，原地修改，(index, num, val1, val2, …)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;排序&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;sort，原地修改&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;截取子数组&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;slice，返回新数组&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;合并数组&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;concat，合并两个或&lt;strong&gt;多个数组&lt;/strong&gt;。此方法不会更改现有数组，而是返回一个新数组。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Flat&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flat()&lt;/code&gt; 方法会按照一个可指定的深度递归遍历数组，并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Join&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;join()&lt;/code&gt; 方法将一个数组（或一个&lt;a href=&quot;https://developer.mozilla.org/zh-CN_docs/Web/JavaScript/Guide/Indexed_collections#working_with_array-like_objects&quot;&gt;类数组对象&lt;/a&gt;）的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目，那么将返回该项目而不使用分隔符。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;遍历&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;forEach，遍历数组，不返回新数组，且无法提前跳出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;map，根据元素做处理，返回各个处理结果的新数组&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reduce，返回新数组&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;测试&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;filter()&lt;/code&gt; 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;every，测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。若收到一个空数组，此方法在一切情况下都会返回 &lt;code&gt;true&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;arr.every(callback(element[, index[, array]])[, thisArg])&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;some()&lt;/code&gt; 方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;find&lt;/code&gt;方法对数组中的每一项元素执行一次 &lt;code&gt;callback&lt;/code&gt; 函数，直至有一个 callback 返回 &lt;code&gt;true&lt;/code&gt;。当找到了这样一个元素后，该方法会立即返回这个元素的值，否则返回 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined&quot;&gt;&lt;code&gt;undefined&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;findIndex()&lt;/code&gt;方法返回数组中满足提供的测试函数的第一个元素的&lt;strong&gt;索引&lt;/strong&gt;。若没有找到对应元素则返回-1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;indexOf()&lt;/code&gt;方法返回在数组中可以找到一个给定元素的第一个索引，如果不存在，则返回-1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;includes()&lt;/code&gt; 方法用来判断一个数组是否包含一个指定的值，根据情况，如果包含则返回 true，否则返回 false。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ES6 新特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在变量声明方面有：let, const&lt;/li&gt;
&lt;li&gt;面向对象编程有 语法糖 class&lt;/li&gt;
&lt;li&gt;在模块导入方面是 import export&lt;/li&gt;
&lt;li&gt;新的数据结构：map、set&lt;/li&gt;
&lt;li&gt;新的数组方法：map、reduce&lt;/li&gt;
&lt;li&gt;异步：promise&lt;/li&gt;
&lt;li&gt;箭头函数&lt;/li&gt;
&lt;li&gt;解构赋值和三点表达式&lt;/li&gt;
&lt;li&gt;等等……&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;异步&lt;/h3&gt;
&lt;h4&gt;Async，promise 和 generator，区别是什么&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;async&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Generator 函数是将函数分步骤阻塞 ，只有主动调用 next() 才能进行下一步&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;async&lt;/code&gt;和&lt;code&gt;await&lt;/code&gt;关键字让我们可以用一种更简洁的方式写出基于&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt;的异步行为，而无需刻意地链式调用&lt;code&gt;promise&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;async 函数可能包含 0 个或者多个&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await&quot;&gt;&lt;code&gt;await&lt;/code&gt;&lt;/a&gt;表达式。await 表达式会暂停整个 async 函数的执行进程并出让其控制权，只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程。promise 的解决值会被当作该 await 表达式的返回值。使用&lt;code&gt;async&lt;/code&gt; / &lt;code&gt;await&lt;/code&gt;关键字就可以在异步代码中使用普通的&lt;code&gt;try&lt;/code&gt; / &lt;code&gt;catch&lt;/code&gt;代码块。&lt;/p&gt;
&lt;p&gt;async 函数一定会返回一个 promise 对象。如果一个 async 函数的返回值看起来不是 promise，那么它将会被隐式地包装在一个 promise 中。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;的行为就好像搭配使用了生成器和 promise。&lt;/p&gt;
&lt;h3&gt;Promise&lt;/h3&gt;
&lt;h4&gt;三种状态&lt;/h4&gt;
&lt;p&gt;pending、fulfilled、rejected&lt;/p&gt;
&lt;h4&gt;静态方法&lt;/h4&gt;
&lt;h5&gt;Promise.all( iterable)&lt;/h5&gt;
&lt;p&gt;@ para：promise 数组，或者 iterable&lt;/p&gt;
&lt;p&gt;@ return：成功则返回，所有 promise 返回值的数组；失败，则把第一个触发失败的 promise 对象的错误信息作为它的失败错误信息。&lt;/p&gt;
&lt;p&gt;相比于 allSettled ，all 更适合彼此相互依赖或者在其中任何一个&lt;code&gt;reject&lt;/code&gt;时立即结束&lt;/p&gt;
&lt;h5&gt;Promise.allSettled(iterable)&lt;/h5&gt;
&lt;p&gt;方法返回一个在所有给定的 promise 都已经&lt;code&gt;fulfilled&lt;/code&gt;或&lt;code&gt;rejected&lt;/code&gt;后的 promise，并带有一个对象数组，每个对象表示对应的 promise 结果。&lt;/p&gt;
&lt;p&gt;当您有多个彼此不依赖的异步任务成功完成时，或者您总是想知道每个&lt;code&gt;promise&lt;/code&gt;的结果时，通常使用它。&lt;/p&gt;
&lt;h5&gt;Promise.any(iterable)&lt;/h5&gt;
&lt;p&gt;接收一个 Promise 对象的集合，当其中的一个 promise &lt;strong&gt;成功&lt;/strong&gt;，就返回那个成功的 promise 的值。最快成功的那一个。&lt;/p&gt;
&lt;h5&gt;Promise.race(iterable)&lt;/h5&gt;
&lt;p&gt;返回一个 promise，一旦迭代器中的&lt;strong&gt;某个&lt;/strong&gt;promise 解决或拒绝，返回的 promise 就会解决或拒绝。也就是最快处理的那个，无论是成功还是失败。&lt;/p&gt;
&lt;h5&gt;Promise.reject(reason)&lt;/h5&gt;
&lt;p&gt;返回一个状态为失败的 Promise 对象，并将给定的失败信息传递给对应的处理方法&lt;/p&gt;
&lt;h5&gt;Promise.resolve(value)&lt;/h5&gt;
&lt;p&gt;返回一个以给定值解析后的&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt; 对象。&lt;/p&gt;
&lt;p&gt;如果这个值是一个 promise ，那么将返回执行后的这个 promise ；&lt;/p&gt;
&lt;p&gt;如果这个值是 thenable（即带有&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then&quot;&gt;then&lt;/a&gt;方法），返回的 promise 会“跟随”这个 thenable 的对象，采用它的最终状态；否则返回的 promise 将以此值完成。&lt;/p&gt;
&lt;p&gt;此函数将类 promise 对象的多层嵌套展平。&lt;/p&gt;
&lt;h4&gt;实现 promise&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 定义三种状态
const PENDING = &amp;#39;PENDING&amp;#39; // 进行中
const FULFILLED = &amp;#39;FULFILLED&amp;#39; // 已成功
const REJECTED = &amp;#39;REJECTED&amp;#39; // 已失败

class Promise {
  constructor(exector) {
    // 初始化状态
    this.status = PENDING
    // 将成功、失败结果放在this上，便于then、catch访问
    this.value = undefined
    this.reason = undefined

    const resolve = (value) =&amp;gt; {
      // 只有进行中状态才能更改状态
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
      }
    }
    const reject = (reason) =&amp;gt; {
      // 只有进行中状态才能更改状态
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
      }
    }
    // 立即执行exector
    // 把内部的resolve和reject传入executor，用户可调用resolve和reject
    exector(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    // then是微任务，这里用setTimeout模拟
    setTimeout(() =&amp;gt; {
      if (this.status === FULFILLED) {
        // FULFILLED状态下才执行
        onFulfilled(this.value)
      }
      else if (this.status === REJECTED) {
        // REJECTED状态下才执行
        onRejected(this.reason)
      }
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;实现 all&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function all(promises) {
  if (!Array.isArray(promises)) {
    return reject(new TypeError(&amp;#39;arguments must be an array&amp;#39;))
  }
  const l = promises.length
  const result = new Array(l)
  let num = 0
  return new Promise((resolve) =&amp;gt; {
    for (let i = 0; i &amp;lt; l; i++) {
      Promise.resolve(promises[i]).then(
        (res) =&amp;gt; {
          result[i] = res
          num += 1
          if (num === l) {
            return resolve(result)
          }
        },
        (reason) =&amp;gt; {
          return reject(reason)
        }
      )
    }
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;this&lt;/h3&gt;
&lt;p&gt;函数里的 this 是函数的调用者；&lt;/p&gt;
&lt;p&gt;严格模式下，在全局顶层是 undefined。&lt;/p&gt;
&lt;h3&gt;箭头函数&lt;/h3&gt;
&lt;p&gt;作用：更简短的函数并且不绑定&lt;code&gt;this&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;不能用作构造函数，无自己的原型属性；&lt;/p&gt;
&lt;p&gt;无 arguments ，但是可以用三点解析式，用…rest 参数获取&lt;/p&gt;
&lt;h3&gt;Symbol&lt;/h3&gt;
&lt;p&gt;每个从&lt;code&gt;Symbol()&lt;/code&gt;返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符；这是该数据类型仅有的目的。&lt;/p&gt;
&lt;p&gt;不支持语法：”&lt;code&gt;new Symbol()&lt;/code&gt;“。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols&quot;&gt;&lt;code&gt;Object.getOwnPropertySymbols()&lt;/code&gt;&lt;/a&gt; 方法让你在查找一个给定对象的符号属性时返回一个 symbol 类型的数组。&lt;/p&gt;
&lt;h3&gt;Set&lt;/h3&gt;
&lt;p&gt;Set：成员值唯一的数组（就是集合）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Set 结构的实例有以下属性。

Set.prototype.constructor：构造函数，默认就是Set函数。
Set.prototype.size：返回Set实例的成员总数。
// Set 实例的方法分为两大类：操作方法（用于操作数据）和遍历方法（用于遍历成员）。下面先介绍四个操作方法。

Set.prototype.add(value)：添加某个值，返回 Set 结构本身。
Set.prototype.delete(value)：删除某个值，返回一个布尔值，表示删除是否成功。
Set.prototype.has(value)：返回一个布尔值，表示该值是否为Set的成员。
Set.prototype.clear()：清除所有成员，没有返回值。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WeakSet 结构与 Set 类似，也是不重复的值的集合。&lt;/p&gt;
&lt;p&gt;WeakSet 的成员只能是对象，而不能是其他类型的值。&lt;/p&gt;
&lt;p&gt;其次，WeakSet 中的对象都是弱引用，即垃圾回收机制不考虑 WeakSet 对该对象的引用。&lt;/p&gt;
&lt;h3&gt;Map&lt;/h3&gt;
&lt;p&gt;只有对同一个对象的引用，Map 结构才将其视为同一个键。但是对于数值和字符串没有影响
Map 的键实际上是跟内存地址绑定的，只要内存地址不一样，就视为两个键。这就解决了同名属性碰撞（clash）的问题&lt;/p&gt;
&lt;p&gt;注意：如果 Map 的键是一个简单类型的值（数字、字符串、布尔值），则只要两个值严格相等，Map 将其视为一个键，比如 0 和-0 就是一个键，布尔值 true 和字符串 true 则是两个不同的键。&lt;/p&gt;
&lt;p&gt;另外，undefined 和 null 也是两个不同的键。虽然 NaN 不严格相等于自身，但 Map 将其视为同一个键。&lt;/p&gt;
&lt;p&gt;可以按照数据插入时的顺序遍历所有的元素。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;new Map()，或者以这样的方式初始化，&lt;code&gt;new Map([[&amp;#39;foo&amp;#39;, 3], [&amp;#39;bar&amp;#39;, {}], [&amp;#39;baz&amp;#39;, undefined]])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Map.prototype.set(k, v)&lt;/li&gt;
&lt;li&gt;Map.prototype.delete(k)，删除&lt;/li&gt;
&lt;li&gt;Map.prototype.clear()，清空 map&lt;/li&gt;
&lt;li&gt;Map.prototype.get(k)，对于 v 是引用类型，可以直接在返回值上原地修改（但是不能直接赋值），假如是基础类型，还是得用 set 修改。&lt;/li&gt;
&lt;li&gt;Map.prototype.has(k)&lt;/li&gt;
&lt;li&gt;Map.prototype.size，获取大小&lt;/li&gt;
&lt;li&gt;for (var [key, value] of mapObj)，遍历&lt;/li&gt;
&lt;li&gt;Map.prototype.forEach((v, k, map)=&amp;gt;{})，按插入顺序遍历，对每个元素做一次操作&lt;/li&gt;
&lt;li&gt;Map.prototype.keys()&lt;/li&gt;
&lt;li&gt;Map.prototype.values()&lt;/li&gt;
&lt;li&gt;Map.prototype.entries()&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Proxy&lt;/h3&gt;
&lt;p&gt;Proxy 在目标对象之前架设一层“拦截”，外界对该对象的访问，都必须先通过这层拦截，在这层拦截中可以对外界的访问进行过滤和改写。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// new Proxy()表示生成一个Proxy实例，target参数表示所要拦截的目标对象，handler参数是一个配置对象，用来定制拦截行为，对于每一个被代理的操作，需要提供一个对应的处理函数，该函数将拦截对应的操作
// var proxy = new Proxy(target, handler);

const proxy = new Proxy(
  {},
  {
    get(target, propKey) {
      // get方法的两个参数分别是目标对象和所要访问的属性。
      return 35 // 由于拦截函数总是返回35，所以访问任何属性都得到35。
    },
  }
)

proxy.time // 35
proxy.name // 35
proxy.title // 35

// 如果 handler === {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可继承，即 Proxy 实例可以作为其他对象的原型对象&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const proxy = new Proxy(
  {},
  {
    get(target, propKey) {
      return 35
    },
  }
)

const obj = Object.create(proxy)
obj.time // 35
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;作用域&lt;/h3&gt;
&lt;h4&gt;script、function、{}&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;在 script 声明的 var、let、const 为全局变量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在 function 声明的 var、let、const 为局部变量，只在本函数和下层函数中使用（可以使用闭包在外部使用输出）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在{}中声明的 var 仍为全局变量，但 let、const 为局部变量，其之外不可以使用&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：for （var i=0; i&amp;lt;n ; i++）和 for( let i=0; i&amp;lt; n; i++)的区别，这里 var 定义了一个在 for 内的全局变量，let 定义了 n 个 for 内的局部变量。&lt;/p&gt;
&lt;p&gt;如何使 var 在 for 中的异步函数使用不同的值，使用闭包，即在 for 内新声明函数（可以不带相关参数），并使用&lt;/p&gt;
&lt;h4&gt;全局作用域&lt;/h4&gt;
&lt;p&gt;一个（var、let、const）变量在函数外面或者大括号 {} 外申明，那么就是定义了一个全局作用域的变量。一旦你申明了全局变量，那么你可以在任何地方使用它，甚至在函数中也行。&lt;/p&gt;
&lt;h4&gt;局部作用域&lt;/h4&gt;
&lt;p&gt;在 JavaScript 中，有两种局部作用于：&lt;strong&gt;函数作用域和块作用域&lt;/strong&gt;。&lt;/p&gt;
&lt;h5&gt;函数作用域&lt;/h5&gt;
&lt;p&gt;当你在函数中申明一个（var、let、const）变量，你就只能够在这个函数范围内使用它。在范围之外你不能使用。&lt;/p&gt;
&lt;h5&gt;块作用域&lt;/h5&gt;
&lt;p&gt;当你在一个大括号中 {} 使用 &lt;em&gt;const&lt;/em&gt; 或者 &lt;em&gt;let&lt;/em&gt; 申明变量，那么这个变量只能够在这个大括号范围内使用。&lt;/p&gt;
&lt;h5&gt;嵌套/词法 作用域&lt;/h5&gt;
&lt;p&gt;当一个函数在另一个函数内定义，&lt;strong&gt;内部的函数能够访问外部函数的变量&lt;/strong&gt;（闭包作用的原理）。我们称之为&lt;strong&gt;词法作用域&lt;/strong&gt;。然而，外部的函数不能够访问内部函数的变量。&lt;/p&gt;
&lt;h3&gt;闭包&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/28921273&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html&quot;&gt;参考 2&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;定义&lt;/h4&gt;
&lt;p&gt;一个函数和对其周围状态（词法环境）的引用捆绑在一起（或者说函数被引用包围），这样的组合就是闭包（closure）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;也就是说，闭包让你可以在一个内层函数中访问到其外层函数的作用域&lt;/strong&gt;。在 JavaScript 中，每当创建一个函数，闭包就会在函数创建的同时被创建出来。&lt;/p&gt;
&lt;p&gt;在函数内声明内部函数，并将之返回（或作为返回对象的属性）。&lt;/p&gt;
&lt;p&gt;闭包就是能够读取其他函数内部变量的函数，或者子函数在外调用，子函数所在的父函数的作用域不会被释放。&lt;/p&gt;
&lt;h4&gt;原理&lt;/h4&gt;
&lt;p&gt;内层函数可访问外层函数的变量，将闭包返回就将上层函数的变量暴露&lt;/p&gt;
&lt;h4&gt;作用&lt;/h4&gt;
&lt;h5&gt;解决副作用&lt;/h5&gt;
&lt;p&gt;在你想要的时候通过创建一个函数来激活内部的闭包。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function prepareCake(flavor) {
  return function () {
    setTimeout(_ =&amp;gt; console.log(`Made a ${flavor} cake!`), 1000)
  }
}

const makeCakeLater = prepareCake(&amp;#39;banana&amp;#39;)

// And later in your code...
makeCakeLater()
// Made a banana cake!
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;使用闭包中的私有变量&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function secret(secretCode) {
  return {
    saySecretCode() {
      console.log(secretCode)
    },
  }
}

const theSecret = secret(&amp;#39;CSS Tricks is amazing&amp;#39;)
theSecret.saySecretCode()
// &amp;#39;CSS Tricks is amazing&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;解决 var 的全局变量在异步函数调用中的变化&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;for (let i = 0; i &amp;lt; 5; i++) {
  setTimeout(() =&amp;gt; {
    console.log(i);
  }, 1000 * i);
}
//输出：0 1 2 3 4
for (var i = 0; i &amp;lt; 5; i++) {
  setTimeout(() =&amp;gt; {
    console.log(i);
  }, 1000 * i);
}
// 输出： 5 5 5 5 5，5是因为最后i++跳出来的是5
// 使用闭包实现类似let的结果
for (var i = 0; i &amp;lt; 5; i++) {
  function f(i: number) {
    setTimeout(() =&amp;gt; {
      console.log(i);
    }, 1000 * i);
  }
  f(i);
}
//输出：0 1 2 3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes&quot;&gt;原型&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;原型定义&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.zhihu.com/question/34183746&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1.对象有属性&lt;code&gt;__proto__&lt;/code&gt; ， 指向该对象的构造函数的原型对象。 2.方法除了有属性&lt;code&gt;__proto__&lt;/code&gt;,还有属性&lt;code&gt;prototype&lt;/code&gt;，&lt;code&gt;prototype&lt;/code&gt;指向该方法的原型对象。&lt;/p&gt;
&lt;p&gt;在 JS 里，万物皆对象。方法（Function）是对象，方法的原型(Function.prototype)是对象。因此，它们都会具有对象共有的特点。&lt;/p&gt;
&lt;p&gt;即：&lt;strong&gt;对象具有属性&lt;/strong&gt; proto，可称为&lt;strong&gt;隐式原型&lt;/strong&gt;，一个对象的隐式原型指向构造该对象的&lt;strong&gt;构造函数的原型&lt;/strong&gt;，这也保证了实例能够访问在构造函数原型中定义的属性和方法。&lt;/p&gt;
&lt;p&gt;方法这个特殊的对象，除了和其他对象一样有上述&lt;em&gt;proto&lt;/em&gt;属性之外，还有自己特有的属性——原型属性（prototype），这个属性是一个指针，指向一个对象，这个对象的用途就是包含所有实例共享的属性和方法（我们把这个对象叫做原型对象）。原型对象也有一个属性，叫做 constructor，这个属性包含了一个指针，指回原构造函数。&lt;/p&gt;
&lt;p&gt;JavaScript 常被描述为一种&lt;strong&gt;基于原型的语言 (prototype-based language)&lt;/strong&gt;——每个对象拥有一个&lt;strong&gt;原型对象&lt;/strong&gt;，对象以其原型为模板、从原型继承方法和属性。&lt;/p&gt;
&lt;p&gt;原型对象也可能拥有原型，并从中继承方法和属性，一层一层、以此类推。这种关系常被称为&lt;strong&gt;原型链 (prototype chain)&lt;/strong&gt;，它解释了为何一个对象会拥有定义在其他对象中的属性和方法。原型对象是一个内部对象，应当使用 &lt;code&gt;__proto__&lt;/code&gt; 访问，&lt;/p&gt;
&lt;p&gt;准确地说，这些属性和方法定义在 Object 的构造器函数(constructor functions)之上的&lt;code&gt;prototype&lt;/code&gt;属性上，而非对象实例本身。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在传统的 OOP 中，首先定义“类”，此后创建对象实例时，类中定义的所有属性和方法都被复制到实例中。&lt;/p&gt;
&lt;p&gt;在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个&lt;strong&gt;链接&lt;/strong&gt;（它是&lt;strong&gt;proto&lt;/strong&gt;属性，是从构造函数的&lt;code&gt;prototype&lt;/code&gt;属性派生的），之后通过上溯原型链，在构造器中找到这些属性和方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对象的原型：可以通过&lt;code&gt;Object.getPrototypeOf(obj)&lt;/code&gt;获得，是每个实例上都有的属性&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prototype&lt;/code&gt;：构造函数的属性，&lt;code&gt;prototype&lt;/code&gt; 属性包含（指向）一个对象，你在这个对象中定义需要被继承的成员。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 函数
function doSomething(){}
console.log( doSomething.prototype );
// 输出：
{
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

doSomething.prototype.foo = &amp;quot;bar&amp;quot;;

{
    foo: &amp;quot;bar&amp;quot;,
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

var doSomeInstancing = new doSomething();
doSomeInstancing.prop = &amp;quot;some value&amp;quot;; // add a property onto the object

{
    prop: &amp;quot;some value&amp;quot;,
    __proto__: {
        foo: &amp;quot;bar&amp;quot;,
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原型对象是一个内部对象，应当使用&lt;code&gt;__proto__&lt;/code&gt; 访问， &lt;code&gt;doSomeInstancing&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 属性就是&lt;code&gt;doSomething.prototype&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;当你访问 &lt;code&gt;doSomeInstancing&lt;/code&gt; 的一个属性, 浏览器首先查找 &lt;code&gt;doSomeInstancing&lt;/code&gt; 是否有这个属性. 如果 &lt;code&gt;doSomeInstancing&lt;/code&gt; 没有这个属性, 然后浏览器就会在 &lt;code&gt;doSomeInstancing&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 中查找这个属性(也就是 doSomething.prototype). 如果 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 有这个属性, 那么 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 上的这个属性就会被使用.&lt;/p&gt;
&lt;p&gt;否则, 如果 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 没有这个属性, 浏览器就会去查找 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; ，看它是否有这个属性.&lt;/p&gt;
&lt;p&gt;默认情况下, 所有函数的原型属性的 &lt;code&gt;__proto__&lt;/code&gt; 就是 &lt;code&gt;window.Object.prototype&lt;/code&gt;. 所以 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; (也就是 doSomething.prototype 的 &lt;code&gt;__proto__&lt;/code&gt; (也就是 &lt;code&gt;Object.prototype&lt;/code&gt;)) 会被查找是否有这个属性. 如果没有在它里面找到这个属性, 然后就会在 doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 里面查找. 然而这有一个问题: doSomeInstancing 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 的 &lt;code&gt;__proto__&lt;/code&gt; 不存在.&lt;/p&gt;
&lt;p&gt;最后, 原型链上面的所有的 &lt;code&gt;__proto__&lt;/code&gt; 都被找完了, 浏览器所有已经声明了的 &lt;code&gt;__proto__&lt;/code&gt; 上都不存在这个属性，然后就得出结论，这个属性是 &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;// 层层向上直到一个对象的原型对象为 null 。&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Inheritance&quot;&gt;继承&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript 继承的对象函数并不是通过复制而来，而是通过原型链继承（通常被称为 &lt;strong&gt;原型式继承 ——&lt;/strong&gt; &lt;strong&gt;prototypal inheritance）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;function.call&lt;/code&gt;来调用父类的构造函数，但是这样无法自动指定&lt;code&gt;Child.prototype&lt;/code&gt;的值，这样&lt;code&gt;Child.prototype&lt;/code&gt;就只能包含在构造函数里构造的属性，而没有方法。&lt;/p&gt;
&lt;p&gt;因此我们利用&lt;code&gt;Object.create()&lt;/code&gt;方法将&lt;code&gt;Parent.prototype&lt;/code&gt;作为&lt;code&gt;Child.prototype&lt;/code&gt;的原型对象，并改变其构造器指向，使之与&lt;code&gt;Child&lt;/code&gt;关联。&lt;/p&gt;
&lt;p&gt;现在&lt;code&gt;子类&lt;/code&gt;的&lt;code&gt;prototype&lt;/code&gt;的&lt;code&gt;constructor&lt;/code&gt;属性指向的是&lt;code&gt;父类&lt;/code&gt;，需将之改回子类&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function Parent(x1) {
  this.x1 = x1
  this.f1 = function () {
    console.log(&amp;#39;parent!&amp;#39;)
  }
}
// 新的构造器
function Child(y1, x1) {
  Parent.call(this, x1)
  this.y1 = y1
  this.f1 = function () {
    console.log(&amp;#39;Child!&amp;#39;)
  }
}
// 默认有一个空的原型属性，让Child()从Parent()的原型对象里继承方法
Child.prototype = Object.create(Parent.prototype)
// 现在Child()的prototype的constructor属性指向的是Parent()， 改回 Child
Child.prototype.constructor = Child

const cObj = new Child(2, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;es6&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class c2 extends c1 {}

class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }

  toString() {
    return `(${this.x}, ${this.y})`
  }
}

typeof Point // &amp;quot;function&amp;quot;
Point === Point.prototype.constructor // true，类的数据类型就是函数，类本身就指向构造函数。使用的时候，也是直接对类使用new命令，跟构造函数的用法完全一致。

class ColorPoint extends Point {
  constructor(x, y, color) {
    this.color = color // ReferenceError
    super(x, y)
    this.color = color // 正确
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;事件循环&lt;/h3&gt;
&lt;p&gt;任务队列中，在每一次事件循环中，macrotask 只会提取一个执行，而 microtask 会一直提取，直到 microsoft 队列为空为止。&lt;/p&gt;
&lt;p&gt;也就是说如果某个 microtask 任务被推入到执行中，那么当主线程任务执行完成后，会循环调用该队列任务中的下一个任务来执行，直到该任务队列到最后一个任务为止。&lt;/p&gt;
&lt;p&gt;而事件循环每次只会入栈一个 macrotask，主线程执行完成该任务后又会检查 microtasks 队列并完成里面的所有任务后再执行 macrotask 的任务。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering&lt;/li&gt;
&lt;li&gt;microtasks: process.nextTick, Promise, MutationObserver&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;事件委托&lt;/h3&gt;
&lt;p&gt;不在事件的发生地（直接 dom）上设置监听函数，而是在其父元素上设置监听函数，通过&lt;strong&gt;事件冒泡&lt;/strong&gt;，父元素可以监听到子元素上事件的触发，通过判断事件发生元素 DOM 的类型，来做出不同的响应。&lt;/p&gt;
&lt;h3&gt;事件监听&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Element.addEventListener(event, func, useCapture)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;第一个参数是事件的类型(如 “click” 或 “mousedown”).&lt;/p&gt;
&lt;p&gt;第二个参数是事件触发后调用的函数。&lt;/p&gt;
&lt;p&gt;第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。&lt;/p&gt;
&lt;p&gt;事件传递有两种方式，冒泡和捕获&lt;/p&gt;
&lt;p&gt;事件传递定义了元素事件触发的顺序，如果你将 P 元素插入到 div 元素中，用户点击 P 元素，&lt;/p&gt;
&lt;p&gt;在冒泡中，内部元素先被触发，然后再触发外部元素，&lt;/p&gt;
&lt;p&gt;捕获中，外部元素先被触发，再触发内部元素.&lt;/p&gt;
&lt;h3&gt;图片的懒加载和预加载&lt;/h3&gt;
&lt;p&gt;预加载：提前加载图片，当用户需要查看时可直接从本地缓存中渲染。&lt;/p&gt;
&lt;p&gt;懒加载：懒加载的主要目的是作为服务器前端的优化，减少请求数或延迟请求数。&lt;/p&gt;
&lt;h3&gt;mouseover 和 mouseenter 的区别&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mouseover&lt;/code&gt;：当鼠标移入元素或其子元素都会触发事件，所以有一个重复触发，冒泡的过程。对应的移除事件是&lt;code&gt;mouseout&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mouseenter&lt;/code&gt;：当鼠标移除元素本身（不包含元素的子元素）会触发事件，也就是不会冒泡，对应的移除事件是&lt;code&gt;mouseleave&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;new 做的事&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;new 操作符新建了一个空对象，这个对象的&lt;code&gt;__proto__&lt;/code&gt;指向构造函数的&lt;code&gt;prototype&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;执行构造函数后返回这个对象。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;拖拽功能&lt;/h3&gt;
&lt;p&gt;三个事件，分别是&lt;code&gt;mousedown&lt;/code&gt;，&lt;code&gt;mousemove&lt;/code&gt;，&lt;code&gt;mouseup&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;两个坐标，&lt;code&gt;clientX&lt;/code&gt;，&lt;code&gt;clientY&lt;/code&gt;标识的是鼠标的坐标，分别标识横坐标和纵坐标，并且我们用&lt;code&gt;offsetX&lt;/code&gt;和&lt;code&gt;offsetY&lt;/code&gt;来表示元素的元素的初始坐标&lt;/p&gt;
&lt;p&gt;拖拽的同时是绝对定位，我们改变的是绝对定位条件下的&lt;code&gt;left&lt;/code&gt;以及&lt;code&gt;top&lt;/code&gt;等等值。&lt;/p&gt;
&lt;h3&gt;防抖&lt;/h3&gt;
&lt;p&gt;事件被触发 n 秒后再执行回调，如果在这 n 秒内又被触发，则重新计时。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按钮提交：只执行最后提交的一次，以防止多次提交。&lt;/li&gt;
&lt;li&gt;搜索框联想：防止联想发送请求，只发送最后一次&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function debunce(fn, wait) {
  let timeout
  return function () {
    const context = this
    const args = arguments
    clearTimeout(timeout)
    timeout = setTimeout(() =&amp;gt; {
      fn.apply(context, args)
    }, wait)
  }
}
function realFn() {
  console.log(&amp;#39;Success&amp;#39;)
}
window.addEventListener(&amp;#39;scroll&amp;#39;, debounce(realFn, 500))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;节流&lt;/h3&gt;
&lt;p&gt;规定在一个单位时间内，只能触发一次事件。如果在这个时间段内多次触发，只有最早的一次生效。&lt;/p&gt;
&lt;p&gt;只允许一个函数在 X 毫秒内执行一次。与防抖相比，节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件 handler。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 使用定时器实现
function throttle(func, wait) {
  let timeout
  return function () {
    const context = this
    const args = arguments
    if (!timeout) {
      timeout = setTimeout(() =&amp;gt; {
        timeout = null
        func.apply(context, args)
      }, wait)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;setTimeout(fn,100);100 毫秒是如何权衡的&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;setTimeout()&lt;/code&gt;函数只是将事件插入了任务列表，必须等到当前代码执行完，主线程才会去执行它指定的回调函数，有可能要等很久，所以没有办法保证回调函数一定会在&lt;code&gt;setTimeout&lt;/code&gt;指定的时间内执行，100 毫秒是插入队列的时间+等待的时间&lt;/p&gt;
&lt;h3&gt;浅拷贝和深拷贝&lt;/h3&gt;
&lt;h4&gt;浅拷贝&lt;/h4&gt;
&lt;p&gt;如果是数组，可以利用 slice，concat 方法返回一个新数组来实现拷贝，假如数组嵌套了对象或者数组的话，使用 concat 方法克隆并不完整，如果数组元素是基本类型，就会拷贝一份，互不影响，而如果是对象或数组，就会只拷贝对象和数组的引用，这样我们无论在新旧数组进行了修改，两者都会发生变化，我们把这种复制引用的拷贝方法称为浅拷贝，&lt;/p&gt;
&lt;p&gt;深拷贝就是指完全的拷贝一个对象，即使嵌套了对象，两者也互相分离，修改一个对象的属性，不会影响另一个&lt;/p&gt;
&lt;h3&gt;深度复制&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function deepCopy(obj) {
  // 判断是数组还是字典类对象
  const newObj = Array.isArray(obj) ? [] : {}
  for (const i in obj) {
    // 根据是否是对象来决定是否递归
    const s = typeof obj[i] == &amp;#39;object&amp;#39; ? deepCopy(obj[i]) : obj[i]
    newObj[i] = s
  }
  return newObj
}

// 2
const s = JSON.parse(JSON.stringify(obj))
// 原理是JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串，parse可以把JSON字符串反序列化为一个js对象，通过这两个方法，也可以实现对象的深复制。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实现 bind&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;Function.prototype.myBind = function (context) {
  const fn = this // 原环境，谁调用的
  return function (...args) {
    // 提供后续调用
    return fn.call(context, ...args)
  }
}
function fun(x) {
  return x ** 2
}
const s = fun.myBind([1, 2, 3])(3)
console.log(s)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;函数柯里化&lt;/h3&gt;
&lt;p&gt;柯里化（Currying），把接受多个参数的函数转换成接受一个单一参数的函数。&lt;a href=&quot;https://segmentfault.com/a/1190000018265172&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;ajax 用 promise 封装&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;创建&lt;code&gt;XMLHttpRequest&lt;/code&gt;对象。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;open&lt;/code&gt;方法设置和服务器的交换信息，需要传入参数，例如请求类型、url、是否异步&lt;/li&gt;
&lt;li&gt;send() 发送数据进行交互&lt;/li&gt;
&lt;li&gt;注册&lt;code&gt;onreadystatechange&lt;/code&gt;事件&lt;/li&gt;
&lt;li&gt;更新数据或界面&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var myAjax = function(action, url) {
  return new Promise((resolve, reject)=&amp;gt;{
    let xhr = new XMLHttpRequest();
    xhr.open(action, url, true);
    xhr.send();
    xhr.onreadystatechange = function (){
      if (xhr.status === 200) {
        let json = JSON.parse(xhr.responseText);
        resolve(json);
      }
      else {
        reject(xhr.status)
      }
   })
    .then(res=&amp;gt;{})
    .catch(err =&amp;gt; {})

  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Proxy 和 Object.defineProperty 监听对象属性改变&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Object.defineProperty&lt;/code&gt;：vue2 和 es5 使用&lt;/p&gt;
&lt;p&gt;vue2 结合订阅发布者模式实现双向绑定&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;Object.defineProperty(user,&amp;#39;name&amp;#39;,{
  set：function(key,value){}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Proxy&lt;/code&gt;：vue3 和 es6 使用&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var  user = new Proxy({}，{
 set：function(target,key,value,receiver){}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;setInterval&lt;/h3&gt;
&lt;p&gt;固定时间间隔执行一次&lt;/p&gt;
&lt;h4&gt;使用 setTimeout 实现 setInterval&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function myFun() {
  // do something
  setTimeout(myFun, 200)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实现 sleep 函数&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function mySleep(ms) {
  return new Promise((resolve) =&amp;gt; {
    setTimeout(resolve, ms)
  })
}
mySleep(500).then(() =&amp;gt; {
  // do something
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;转换-_命名到驼峰命名&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function cssStyle2DomStyle(sName) {
  const newStr = sName.replace(
    /([\s\S])-([\s\S])/g,
    (match, $1, $2) =&amp;gt; $1 + $2.toUpperCase()
  )
  return newStr[0] === &amp;#39;-&amp;#39; ? newStr.slice(1) : newStr
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实现 Flat&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function flat(arr) {
  return arr.reduce((a, b) =&amp;gt; a.concat(Array.isArray(b) ? flat(b) : b), [])
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;链式调用&lt;/h3&gt;
&lt;p&gt;调用完的方法将自身实例返回&lt;/p&gt;
&lt;h3&gt;node 服务器&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const http = require(&amp;#39;node:http&amp;#39;)

const hostname = &amp;#39;127.0.0.1&amp;#39;
const port = 3000

const server = http.createServer((req, res) =&amp;gt; {
  res.statusCode = 200
  res.setHeader(&amp;#39;Content-Type&amp;#39;, &amp;#39;text/plain&amp;#39;)
  res.end(&amp;#39;Hello World&amp;#39;)
})

server.listen(port, hostname, () =&amp;gt; {
  console.log(`Server running at http://${hostname}:${port}/`)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;垃圾回收&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;引用计数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;当声明了一个变量并将某个对象赋予它时，这个对象的引用数加一，反之减一。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对引用数为 0 的变量清除。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;// 可以即刻回收垃圾，但是计数过程过于复杂，并且循环引用无法回收。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;标记清除&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;标记阶段，垃圾回收器由根对象开始遍历，所有根对象能访问到的对象会被标记为可到达对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;清除阶段，对内存从头到尾线性遍历，没有标记的对象一律回收。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;// 此方法实现简单，但是会造成大量的内存碎片。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;C++、Java、JavaScript 这三种语言的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;静态类型/动态类型&lt;/p&gt;
&lt;p&gt;编译还是运行的时候知道变量的类型&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;编译型/解释型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;c++，编译型&lt;/li&gt;
&lt;li&gt;js，解释型&lt;/li&gt;
&lt;li&gt;java，编译成字节码再用解释器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;正则表达式&lt;/h3&gt;
&lt;p&gt;正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript 中，正则表达式也是对象。这些模式被用于 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp&quot;&gt;&lt;code&gt;RegExp&lt;/code&gt;&lt;/a&gt; 的 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec&quot;&gt;&lt;code&gt;exec&lt;/code&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test&quot;&gt;&lt;code&gt;test&lt;/code&gt;&lt;/a&gt; 方法, 以及 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String&quot;&gt;&lt;code&gt;String&lt;/code&gt;&lt;/a&gt; 的 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/match&quot;&gt;&lt;code&gt;match&lt;/code&gt;&lt;/a&gt;、&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll&quot;&gt;&lt;code&gt;matchAll&lt;/code&gt;&lt;/a&gt;、&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace&quot;&gt;&lt;code&gt;replace&lt;/code&gt;&lt;/a&gt;、&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/search&quot;&gt;&lt;code&gt;search&lt;/code&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/split&quot;&gt;&lt;code&gt;split&lt;/code&gt;&lt;/a&gt; 方法。&lt;/p&gt;
&lt;h4&gt;模式&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;/g&lt;/code&gt; ，使用全局，在整个字符串查找并返回所有匹配结果&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/i&lt;/code&gt;，忽略大小写&lt;/p&gt;
&lt;h4&gt;常用方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;reg.test(str)&lt;/p&gt;
&lt;p&gt;测试是否含有该匹配，&lt;code&gt;/reg/.test(str)=&amp;gt;bool&lt;/code&gt;，检测字符串是否满足正则规则。&lt;/p&gt;
&lt;p&gt;当使用&lt;code&gt;/g&lt;/code&gt;时，reg 对象的&lt;code&gt;lastIndex&lt;/code&gt;属性改变。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const regex = /foo/g

// regex.lastIndex is at 0
regex.test(&amp;#39;foo&amp;#39;) // true

// regex.lastIndex is now at 3
regex.test(&amp;#39;foo&amp;#39;) // fals
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;str.match(reg)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果使用 g 标志，则将返回与完整正则表达式匹配的所有结果，但不会返回捕获组。&lt;/li&gt;
&lt;li&gt;如果未使用 g 标志，则仅返回第一个完整匹配及其相关的捕获组（&lt;code&gt;Array&lt;/code&gt;）。 在这种情况下，返回的项目将具有如下所述的其他属性。&lt;ul&gt;
&lt;li&gt;&lt;code&gt;groups&lt;/code&gt;: 一个捕获组数组 或 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined&quot;&gt;&lt;code&gt;undefined&lt;/code&gt;&lt;/a&gt;（如果没有定义命名捕获组）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index&lt;/code&gt;: 匹配的结果的开始位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;input&lt;/code&gt;: 搜索的字符串.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;str.replace(reg)&lt;/p&gt;
&lt;p&gt;字符串的替换方法，第二个参数为自定义替换值&lt;/p&gt;
&lt;p&gt;&lt;code&gt;let newStr = sName.replace(/([\d\D])-([\d\D])/g, (match, $1, $2) =&amp;gt; $1 + $2.toUpperCase());&lt;/code&gt;，小写是&lt;code&gt;toLowerCase()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;规则&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;^&lt;/code&gt;，匹配句首，&lt;code&gt;$&lt;/code&gt;，匹配句尾；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;\d&lt;/code&gt;，数字字符，&lt;code&gt;\D&lt;/code&gt;，非数字字符；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;\w&lt;/code&gt;，单字字符，匹配一个单字字符（字母、数字或者下划线），等价于 &lt;code&gt;[A-Za-z0-9_]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;\s&lt;/code&gt;，匹配一个空白字符，包括空格、制表符、换页符和换行符。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;{m, n}&lt;/code&gt;，有[m, n]次匹配&lt;/p&gt;
&lt;p&gt;&lt;code&gt;()&lt;/code&gt;，后续可以使用&lt;code&gt;$n&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;TypeScript&lt;/h2&gt;
&lt;h3&gt;联合类型&lt;/h3&gt;
&lt;p&gt;联合类型（Union Types）表示取值可以为多种类型中的一种。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;let myFavoriteNumber: string | number
myFavoriteNumber = &amp;#39;seven&amp;#39;
myFavoriteNumber = 7
let myFavoriteNumber: string | number
myFavoriteNumber = true

// index.ts(2,1): error TS2322: Type &amp;#39;boolean&amp;#39; is not assignable to type &amp;#39;string | number&amp;#39;.
//   Type &amp;#39;boolean&amp;#39; is not assignable to type &amp;#39;number&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;联合类型使用 &lt;code&gt;|&lt;/code&gt; 分隔每个类型。&lt;/p&gt;
&lt;p&gt;这里的 &lt;code&gt;let myFavoriteNumber: string | number&lt;/code&gt; 的含义是，允许 &lt;code&gt;myFavoriteNumber&lt;/code&gt; 的类型是 &lt;code&gt;string&lt;/code&gt; 或者 &lt;code&gt;number&lt;/code&gt;，但是不能是其他类型。&lt;/p&gt;
&lt;p&gt;当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候，我们&lt;strong&gt;只能访问此联合类型的所有类型里共有的属性或方法&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;联合类型的变量在被赋值的时候，会根据类型推论的规则推断出一个类型&lt;/p&gt;
&lt;h3&gt;泛型&lt;/h3&gt;
&lt;p&gt;泛型（Generics）是指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定类型的一种特性。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function createArray(length: number, value: any): Array&amp;lt;any&amp;gt; {
  let result = [];
  for (let i = 0; i &amp;lt; length; i++) {
    result[i] = value;
  }
  return result;
}

createArray(3, &amp;#39;x&amp;#39;); // [&amp;#39;x&amp;#39;, &amp;#39;x&amp;#39;, &amp;#39;x&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;function createArray&amp;lt;T&amp;gt;(length: number, value: T): Array&amp;lt;T&amp;gt; {
  const result: T[] = []
  for (let i = 0; i &amp;lt; length; i++) {
    result[i] = value
  }
  return result
}
// 当然，也可以不手动指定，而让类型推论自动推算出来，去掉&amp;lt;string&amp;gt;也可以
createArray&amp;lt;string&amp;gt;(3, &amp;#39;x&amp;#39;) // [&amp;#39;x&amp;#39;, &amp;#39;x&amp;#39;, &amp;#39;x&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;多个类型参数&lt;/h4&gt;
&lt;p&gt;定义泛型的时候，可以一次定义多个类型参数&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;function swap&amp;lt;T, U&amp;gt;(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}

swap([7, &amp;#39;seven&amp;#39;]) // [&amp;#39;seven&amp;#39;, 7]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;泛型约束&lt;/h4&gt;
&lt;p&gt;在函数内部使用泛型变量的时候，由于事先不知道它是哪种类型，所以不能随意的操作它的属性或方法：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function loggingIdentity&amp;lt;T&amp;gt;(arg: T): T {
  console.log(arg.length)
  return arg
}

// index.ts(2,19): error TS2339: Property &amp;#39;length&amp;#39; does not exist on type &amp;#39;T&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上例中，泛型 &lt;code&gt;T&lt;/code&gt; 不一定包含属性 &lt;code&gt;length&lt;/code&gt;，所以编译的时候报错了。&lt;/p&gt;
&lt;p&gt;这时，我们可以对泛型进行约束，只允许这个函数传入那些包含 &lt;code&gt;length&lt;/code&gt; 属性的变量。这就是泛型约束：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface Lengthwise {
  length: number
}

function loggingIdentity&amp;lt;T extends Lengthwise&amp;gt;(arg: T): T {
  console.log(arg.length)
  return arg
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多个类型参数之间也可以互相约束：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function copyFields&amp;lt;T extends U, U&amp;gt;(target: T, source: U): T {
  for (const id in source) {
    target[id] = (&amp;lt;T&amp;gt;source)[id]
  }
  return target
}

const x = { a: 1, b: 2, c: 3, d: 4 }

copyFields(x, { b: 10, d: 20 })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上例中，我们使用了两个类型参数，其中要求 &lt;code&gt;T&lt;/code&gt; 继承 &lt;code&gt;U&lt;/code&gt;，这样就保证了 &lt;code&gt;U&lt;/code&gt; 上不会出现 &lt;code&gt;T&lt;/code&gt; 中不存在的字段。&lt;/p&gt;
&lt;h3&gt;接口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://ts.xcatliu.com/basics/type-of-object-interfaces.html&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在 TypeScript 中，我们使用接口（Interfaces）来定义对象的类型。类似 C++里的 struct 结构体&lt;/p&gt;
&lt;h2&gt;git 常用命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Workspace：工作区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Index / Stage：暂存区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repository：仓库区（或本地仓库）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remote：远程仓库&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 恢复暂存区的所有文件到工作区
$ git checkout .
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 暂时将未提交的变化移除，稍后再移入
$ git stash
$ git stash pop
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用的 mysql&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from ta where a like &amp;#39;%a%&amp;#39; order by a DESC;
select ta.a, tb.b from ta left join tb on ta.id = tb.id;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;框架相关&lt;/h2&gt;
&lt;h3&gt;MV-X&lt;/h3&gt;
&lt;p&gt;MV-X 的目的是把程序的数据、业务逻辑和界面三部分解耦，来分离关注点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Model&lt;/p&gt;
&lt;p&gt;数据和数据的处理方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View&lt;/p&gt;
&lt;p&gt;视图，负责对数据的展示&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Controller&lt;/p&gt;
&lt;p&gt;定义界面对用户输入的响应方式，连接模型和视图，用于控制应用程序的流程，处理用户的行为和数据上的改变&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Presenter&lt;/p&gt;
&lt;p&gt;作为 View 和 Model 的中间人，从 View 到 Model 和从 Model 到 View 的数据进行“手动同步”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VM&lt;/p&gt;
&lt;p&gt;数据的双向绑定&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;MVC&lt;/h4&gt;
&lt;p&gt;在 Controller 中响应用户对 View 的事件，Controller 调用 Model 的接口对数据进行操作，一旦 Model 发生变化 Model 就通知相关视图进行更新。&lt;/p&gt;
&lt;h4&gt;MVP&lt;/h4&gt;
&lt;p&gt;手动绑定&lt;/p&gt;
&lt;h4&gt;MVVM&lt;/h4&gt;
&lt;p&gt;mvvm 把 view 和 model 的同步逻辑自动化，只需要告诉 view 的显示内容与 model 哪一部分对应即可。采用双向绑定。&lt;/p&gt;
&lt;h3&gt;Virtual dom&lt;/h3&gt;
&lt;p&gt;virtual dom 是将真实的 dom 的数据抽取出来，以对象的形式模拟树形结构。当状态改变时，重新构造虚拟树，新树旧树比较，把差异更新到真正的 dom 树上，来更新视图。&lt;/p&gt;
&lt;p&gt;diff 算法比较的也是 virtual dom。&lt;/p&gt;
&lt;p&gt;diff，就是新旧虚拟 dom 的比较，如果有差异就以新的为准，然后再插入的真实的 dom 中，重新渲染&lt;/p&gt;
&lt;h3&gt;computed 和 watch&lt;/h3&gt;
&lt;h4&gt;计算属性 computed&lt;/h4&gt;
&lt;p&gt;支持缓存，只有依赖数据发生变化时，才会重新进行计算函数；&lt;/p&gt;
&lt;p&gt;计算属性的函数中都有一个 get(默认具有，获取计算属性)和 set(手动添加，设置计算属性)方法；&lt;/p&gt;
&lt;p&gt;计算属性是自动监听依赖值的变化，从而动态返回内容。&lt;/p&gt;
&lt;h4&gt;侦听属性 watch&lt;/h4&gt;
&lt;p&gt;不支持缓存，只要数据发生变化，就会执行侦听函数；&lt;/p&gt;
&lt;p&gt;侦听属性内支持异步操作；&lt;/p&gt;
&lt;p&gt;侦听属性的值可以是一个对象，接收 handler 回调，deep，immediate 三个属性；&lt;/p&gt;
&lt;p&gt;监听是一个过程，在监听的值变化时，可以触发一个回调，并做一些其他事情。&lt;/p&gt;
&lt;h3&gt;webpack&lt;/h3&gt;
&lt;h4&gt;webpack 定义&lt;/h4&gt;
&lt;p&gt;本质上，&lt;strong&gt;webpack&lt;/strong&gt; 是一个用于现代 JavaScript 应用程序的&lt;em&gt;静态模块打包工具&lt;/em&gt;。当 webpack 处理应用程序时，它会在内部构建一个 &lt;a href=&quot;https://webpack.docschina.org/concepts/dependency-graph/&quot;&gt;依赖图(dependency graph)&lt;/a&gt;，此依赖图对应映射到项目所需的每个模块，并生成一个或多个 &lt;em&gt;bundle&lt;/em&gt;。&lt;/p&gt;
&lt;h4&gt;核心概念&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;入口，entry&lt;/p&gt;
&lt;p&gt;指示 webpack 应该使用哪个模块，来作为构建其内部依赖图的开始。进入入口起点后，webpack 会找出有哪些模块和库是入口起点（直接和间接）依赖的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;输出，output&lt;/p&gt;
&lt;p&gt;在哪里输出它所创建的 &lt;em&gt;bundle&lt;/em&gt;，以及如何命名这些文件。&lt;/p&gt;
&lt;p&gt;主要输出文件的默认值是 &lt;code&gt;./dist/main.js&lt;/code&gt;，其他生成文件默认放置在 &lt;code&gt;./dist&lt;/code&gt; 文件夹中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;loader&lt;/p&gt;
&lt;p&gt;webpack 只能理解 JavaScript 和 JSON 文件，&lt;strong&gt;loader&lt;/strong&gt; 让 webpack 能够去处理其他类型的文件，并将它们转换为有效 &lt;a href=&quot;https://webpack.docschina.org/concepts/modules&quot;&gt;模块&lt;/a&gt;，以供应用程序使用，以及被添加到依赖图中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;loader&lt;/strong&gt; 有两个属性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;test&lt;/code&gt; 属性，识别出哪些文件会被转换。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;use&lt;/code&gt; 属性，定义出在进行转换时，应该使用哪个 loader。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注：webpack 打包的文件默认是不支持 ES6 的，我们需要用 babel 转译。在 loader 中使用 babel。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;插件，plugin&lt;/p&gt;
&lt;p&gt;loader 用于转换某些类型的模块，而插件则可以用于执行范围更广的任务。包括：打包优化，资源管理，注入环境变量。&lt;/p&gt;
&lt;p&gt;想要使用一个插件，你只需要 &lt;code&gt;require()&lt;/code&gt; 它，然后把它添加到 &lt;code&gt;plugins&lt;/code&gt; 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件，这时需要通过使用 &lt;code&gt;new&lt;/code&gt; 操作符来创建一个插件实例。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;模式，mode&lt;/p&gt;
&lt;p&gt;通过选择 &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt; 或 &lt;code&gt;none&lt;/code&gt; 之中的一个，来设置 &lt;code&gt;mode&lt;/code&gt; 参数，你可以启用 webpack 内置在相应环境下的优化。其默认值为 &lt;code&gt;production&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;组合式 API 和配置式 API&lt;/h3&gt;
&lt;p&gt;在 vue2 中，我们需要将代码划分写到 mounted、watch、computed，这个一定程度上规范了代码的整洁性，但是当组件内容过于复杂时，代码将变得复杂难懂。一个细小的逻辑任务，其相关代码可能要分散到多个选项中。而 setup 中可以调用 computed、watch 等，使之能够像函数般在同一处复用。&lt;/p&gt;
&lt;h3&gt;生命周期&lt;/h3&gt;
&lt;p&gt;Vue 实例有一个完整的生命周期，从开始创建、初始化数据、编译模板、挂载 Dom、渲染 → 更新 → 渲染、销毁等一系列过程。&lt;/p&gt;
&lt;h4&gt;beforeCreate&lt;/h4&gt;
&lt;p&gt;数据对象 data = undefined；vue 实例的挂载元素 el=undefined&lt;/p&gt;
&lt;h4&gt;created&lt;/h4&gt;
&lt;p&gt;data 有了，可以访问数据和方法，但未挂载到 dom；el 还是 undefined&lt;/p&gt;
&lt;h4&gt;beforeMount&lt;/h4&gt;
&lt;p&gt;data、el 都有了，但没有挂载&lt;/p&gt;
&lt;h4&gt;mounted&lt;/h4&gt;
&lt;p&gt;vue 实例已经挂载到了真实 dom 上，可以获取 dom 节点。但是无法确定是否已经渲染好，于是需要用 nextTick，在回调函数里进行 dom 操作&lt;/p&gt;
&lt;h4&gt;beforeUpdate&lt;/h4&gt;
&lt;p&gt;响应式数据更新时调用，发生在虚拟 DOM 打补丁之前，适合在更新之前访问现有的 DOM&lt;/p&gt;
&lt;h4&gt;updated&lt;/h4&gt;
&lt;p&gt;虚拟 DOM 重新渲染和打补丁之后调用，组成新的 DOM 已经更新，避免在这个钩子函数中操作数据，防止死循环&lt;/p&gt;
&lt;h4&gt;beforeDestory&lt;/h4&gt;
&lt;h4&gt;destoried&lt;/h4&gt;
&lt;h3&gt;PWA&lt;/h3&gt;
&lt;p&gt;PWA 全称 Progressive Web App ，即渐进式 WEB 应用。一个 PWA 应用首先是一个网页, 可以通过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能&lt;/p&gt;
&lt;h3&gt;gulp&lt;/h3&gt;
&lt;p&gt;gulp 强调的是前端开发的工作流程，我们可以通过配置一系列的 task ，定义 task 处理的事务，然后定义执行顺序，来让 gulp 执行这些 task，从而构建项目的整个前端开发流程。&lt;/p&gt;
&lt;h3&gt;redux&lt;/h3&gt;
&lt;p&gt;在组件化的应用中，会有着大量的组件层级关系，深嵌套的组件与浅层父组件进行数据交互，变得十分繁琐困难。而 redux，站在一个服务级别的角度，可以毫无阻碍地将应用的状态传递到每一个层级的组件中。redux 就相当于整个应用的管家。&lt;/p&gt;
&lt;h3&gt;vue 双向绑定&lt;/h3&gt;
&lt;p&gt;vue2 数据双向绑定是通过数据劫持，结合发布者-订阅者模式的方式来实现的。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。&lt;/p&gt;
&lt;p&gt;Vue3 使用的是 proxy，这个可以自动检测到对象深层的变化。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://juejin.cn/post/6844904088119853063&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;递归遍历 data 中的数据，使用 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;Object.defineProperty()&lt;/a&gt;劫持 getter 和 setter，在 getter 中做数据依赖收集处理，在 setter 中 监听数据的变化，并通知订阅当前数据的地方。&lt;/p&gt;
&lt;p&gt;检测不到对象属性的添加和删除：当你在对象上新加了一个属性&lt;code&gt;newProperty&lt;/code&gt;，当前新加的这个属性并没有加入 vue 检测数据更新的机制(因为是在初始化之后添加的)。&lt;code&gt;vue.$set&lt;/code&gt;是能让 vue 知道你添加了属性, 它会给你做处理，&lt;code&gt;$set&lt;/code&gt;内部也是通过调用&lt;code&gt;Object.defineProperty()&lt;/code&gt;去处理的&lt;/p&gt;
&lt;p&gt;无法监控到数组下标的变化，导致直接通过数组的下标给数组设置值，不能实时响应。&lt;/p&gt;
&lt;p&gt;当 data 中数据比较多且层级很深的时候，会有性能问题，因为要遍历 data 中所有的数据并给其设置成响应式的。&lt;/p&gt;
&lt;p&gt;给对象新增一个属性，内部并没有监听到，新增的属性需要手动再次使用&lt;code&gt;Object.defineProperty()&lt;/code&gt;进行监听。 这就是为什么 &lt;code&gt;vue 2.x&lt;/code&gt;中 检测不到对象属性的添加和删除的原因。&lt;/p&gt;
&lt;p&gt;新增的属性，proxy 并不需要重新添加响应式处理，因为 &lt;code&gt;Proxy&lt;/code&gt; 是对对象的操作，只要你访问对象，就会走到 &lt;code&gt;Proxy&lt;/code&gt; 的逻辑中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.defineProperty 只能劫持对象的属性（需要遍历对象的每个属性），而 Proxy 是直接代理对象。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.defineProperty 对新增属性需要手动进行 Observe。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用 vue2 给 &lt;code&gt;data&lt;/code&gt; 中的数组或对象新增属性时，需要使用 &lt;code&gt;vm.$set&lt;/code&gt; 才能保证新增的属性也是响应式的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;set&lt;/code&gt; 方法中，对 &lt;code&gt;target&lt;/code&gt; 是数组和对象做了分别的处理，&lt;code&gt;target&lt;/code&gt; 是数组时，会调用重写过的 &lt;code&gt;splice&lt;/code&gt; 方法进行手动 &lt;code&gt;Observe&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;对于对象，如果 &lt;code&gt;key&lt;/code&gt; 本来就是对象的属性，则直接修改值触发更新，否则调用 &lt;code&gt;defineReactive&lt;/code&gt;方法重新定义响应式对象。&lt;/p&gt;
&lt;p&gt;如果采用 &lt;code&gt;proxy&lt;/code&gt; 实现，&lt;code&gt;Proxy&lt;/code&gt; 通过 &lt;code&gt;set(target, propKey, value, receiver)&lt;/code&gt; 拦截对象属性的设置，是可以拦截到对象的新增属性的。&lt;/p&gt;
&lt;p&gt;不止如此，&lt;code&gt;Proxy&lt;/code&gt; 对数组的方法也可以监测到，不需要像上面 vue2.x 源码中那样进行 &lt;code&gt;hack&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Proxy 支持 13 种拦截操作，这是 defineProperty 所不具有的&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;vue2.x 中无法通过数组索引来实现响应式数据的自动更新是 vue 本身的设计导致的，不是 &lt;code&gt;defineProperty&lt;/code&gt; 的锅。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Object.defineProperty&lt;/code&gt; 和 &lt;code&gt;Proxy&lt;/code&gt; 本质差别是，&lt;code&gt;defineProperty&lt;/code&gt; 只能对属性进行劫持，新增属性需要手动 &lt;code&gt;Observe&lt;/code&gt; 的问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;vue2 vue3 监听数组&lt;/h3&gt;
&lt;p&gt;vue2 设置了 7 个变异数组（push、pop、shift、unshift、splice、sort、reverse）的 hack 方法来监听数组变化。vm.items[indexOfItem] = newValue 这种是无法检测的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Object.defineProperty&lt;/code&gt; 在数组中的表现和在对象中的表现是一致的，数组的索引就可以看做是对象中的 &lt;code&gt;key&lt;/code&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过索引访问或设置对应元素的值时，可以触发 &lt;code&gt;getter&lt;/code&gt; 和 &lt;code&gt;setter&lt;/code&gt; 方法&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;push&lt;/code&gt; 或 &lt;code&gt;unshift&lt;/code&gt; 会增加索引，对于新增加的属性，需要再手动初始化才能被 &lt;code&gt;observe&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;pop&lt;/code&gt; 或 &lt;code&gt;shift&lt;/code&gt; 删除元素，会删除并更新索引，也会触发 &lt;code&gt;setter&lt;/code&gt; 和 &lt;code&gt;getter&lt;/code&gt; 方法。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以，&lt;code&gt;Object.defineProperty&lt;/code&gt; 是有监控数组下标变化的能力的，只是 vue2.x 放弃了这个特性。&lt;/p&gt;
&lt;h3&gt;vm.$nextTick([callback, context])&lt;/h3&gt;
&lt;p&gt;使用 nextTick 是为了可以获取更新后的 DOM。&lt;/p&gt;
&lt;p&gt;触发时机：在同一事件循环中的数据变化后，DOM 完成更新，立即执行 nextTick 的回调函数，或者 Vue.nextTick().then()&lt;/p&gt;
&lt;h3&gt;vue 和 react 有什么区别？&lt;/h3&gt;
&lt;p&gt;react 整体是函数式的思想，把组件设计成纯组件，状态和逻辑通过参数传入，所以在 react 中，是单向数据流；&lt;/p&gt;
&lt;p&gt;vue 的思想是响应式的，也就是基于是数据可变的，通过对每一个属性建立 Watcher 来监听，当属性变化的时候，响应式的更新对应的虚拟 dom。&lt;/p&gt;
&lt;h3&gt;vuex 有哪几种状态和属性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;modules：模块化 vuex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;state 中保存着共有数据，数据是响应式的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;// getter 可以对 state 进行计算操作，主要用来过滤一些数据，可以在多组件之间复用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;mutations 定义的方法动态修改 state 中的数据，通过 commit 提交方法，方法必须是同步的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;actions 将 mutations 里面处理数据的方法变成异步的，就是异步操作数据，通 store.dispatch 来分发 actions，把异步的方法写在 actions 中，通过 commit 提交 mutations，进行修改数据。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;vuex 的流程&lt;/h3&gt;
&lt;p&gt;页面通过 store.dispatch 异步提交事件到 action。action 通过 commit 把对应参数同步提交到 mutation。
mutation 会修改 state 中对于的值。 最后通过 getter 把对应值跑出去，在页面的计算属性中通过 mapGetter 来动态获取 state 中的值&lt;/p&gt;
&lt;h3&gt;vue 路由&lt;/h3&gt;
&lt;p&gt;前端路由：更新视图，但不重新请求页面。目前在浏览器中主要有两种实现方式：hash、history&lt;/p&gt;
&lt;h4&gt;两种模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;hash ——即地址栏 URL 中的#符号（此 hsah 不是密码学里的散列运算） hash 虽然出现 URL 中，但不会被包含在 HTTP 请求中，对后端完全没有影响，因此改变 hash 不会重新加载页面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;history ——利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过 location.pathname 获取到当前 url 的路由地址；&lt;/p&gt;
&lt;p&gt;这两个方法应用于浏览器的历史记录站，在当前已有的 back、forward、go 的基础之上，它们提供了对历史记录进行修改的功能。&lt;/p&gt;
&lt;p&gt;history 模式下，通过 pushState 和 replaceState 方法可以修改 url 地址，当调用它们修改浏览器历史栈后，虽然当前 url 改变了，但浏览器不会立即发送请求该 url。结合 popstate 方法监听 url 中路由的变化，来更新视图&lt;/p&gt;
&lt;p&gt;history 模式的特点是实现更加方便，可读性更强，同时因为没有了#，url 也更加美观；&lt;/p&gt;
&lt;p&gt;它的劣势也比较明显，当用户刷新或直接输入地址时会向服务器发送一个请求，所以 history 模式需要服务端同学进行支持，将路由都重定向到根路由&lt;/p&gt;
&lt;h4&gt;history 前端路由引起的问题&lt;/h4&gt;
&lt;p&gt;通常情况下，Vue 是单页应用，url 是拼接的假链，假如直接进入该 url，就会无法渲染页面，导致无法正确加载。&lt;/p&gt;
&lt;p&gt;解决办法：Nuxt 有 generate 的功能配置，可实现特定 router 的页面预先渲染。&lt;/p&gt;
&lt;p&gt;或者使用 ssr 模式。// &lt;a href=&quot;https://ssr.vuejs.org/zh/#%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93-vs-%E9%A2%84%E6%B8%B2%E6%9F%93-ssr-vs-prerendering&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;为什么不选择 ssr，涉及构建设置和部署的更多要求，更多的服务器端负载，会比仅仅提供静态文件的 server 更加大量占用 CPU 资源&lt;/p&gt;
&lt;h3&gt;热重载&lt;/h3&gt;
&lt;p&gt;“热重载”不只是当你修改文件的时候简单重新加载页面。启用热重载后，当你修改 &lt;code&gt;.vue&lt;/code&gt; 文件时，该组件的所有实例将在&lt;strong&gt;不刷新页面&lt;/strong&gt;的情况下被替换。它甚至保持了应用程序和被替换组件的当前状态！当你调整模版或者修改样式时，这极大地提高了开发体验。&lt;/p&gt;
&lt;p&gt;//感觉并不是面试该说的话。&lt;/p&gt;
&lt;h3&gt;观察者模式/订阅发布模式&lt;/h3&gt;
&lt;p&gt;当对象间存在一对多关系时，则使用观察者模式（Observer Pattern）。比如，当一个对象被修改时，则会自动通知依赖它的对象。观察者模式属于行为型模式。观察者模式比订阅发布模式多了一层中介，类似用户之间的微博 app。&lt;/p&gt;
&lt;h3&gt;CI/CD&lt;/h3&gt;
&lt;p&gt;CI/CD 其实就是一个流程，用于实现应用开发中的高度持续自动化和持续监控。&lt;/p&gt;
&lt;p&gt;CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。&lt;/p&gt;
&lt;p&gt;CI/CD 的核心概念是&lt;strong&gt;持续集成、持续交付和持续部署&lt;/strong&gt;。作为一个面向开发和运营团队的解决方案，CI/CD 主要针对在集成新代码时所引发的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“CI”始终指持续集成，它属于开发人员的自动化流程。成功的 CI 意味着应用代码的新更改会定期构建、测试并合并到共享存储库中。&lt;/li&gt;
&lt;li&gt;“CD”指的是持续交付，或持续部署&lt;ul&gt;
&lt;li&gt;持续交付，指开发人员对应用的更改会自动进行错误测试并上传到存储库&lt;/li&gt;
&lt;li&gt;持续部署，指自动将开发人员的更改从存储库发布到生产环境，以供客户使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://juejin.cn/post/6844903976693940231#heading-55&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;vite&lt;/h3&gt;
&lt;p&gt;在浏览器里使用 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&quot;&gt;ES module&lt;/a&gt; 是使用 http 请求拿到模块，所以 vite 必须提供一个 web server 去代理这些模块，上文中提到的 &lt;code&gt;koa&lt;/code&gt; 就是负责这个事情，vite 通过对请求路径的劫持获取资源的内容返回给浏览器，不过 vite 对于模块导入做了特殊处理。&lt;/p&gt;
&lt;p&gt;vite 对 &lt;code&gt;import&lt;/code&gt; 都做了一层处理，其过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 koa 中间件里获取请求 body&lt;/li&gt;
&lt;li&gt;通过 &lt;a href=&quot;https://www.npmjs.com/package/es-module-lexer&quot;&gt;es-module-lexer&lt;/a&gt; 解析资源 ast 拿到 import 的内容&lt;/li&gt;
&lt;li&gt;判断 import 的资源是否是绝对路径，绝对视为 npm 模块&lt;/li&gt;
&lt;li&gt;返回处理后的资源路径：&lt;code&gt;&amp;quot;vue&amp;quot; =&amp;gt; &amp;quot;/@modules/vue&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;为什么需要 @modules？&lt;/h4&gt;
&lt;p&gt;如果我们在模块里写 &lt;code&gt;import vue from &amp;#39;vue&amp;#39;&lt;/code&gt;，浏览器中的 esm 并不能获取到导入的模块内容。&lt;/p&gt;
&lt;p&gt;因为 &lt;code&gt;vue&lt;/code&gt; 这个模块安装在 node_modules 里，以往使用 webpack 来获取。webpack 遇到上面的代码，会帮我们做以下几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取这段代码的内容&lt;/li&gt;
&lt;li&gt;解析成 AST&lt;/li&gt;
&lt;li&gt;遍历 AST 拿到 &lt;code&gt;import&lt;/code&gt; 语句中的包的名称&lt;/li&gt;
&lt;li&gt;使用 &lt;a href=&quot;https://github.com/webpack/enhanced-resolve&quot;&gt;enhanced-resolve&lt;/a&gt; 拿到包的实际地址进行打包。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是浏览器中 ESM 无法直接访问项目下的 node_modules，所以 vite 对所有 import 都做了处理，用带有 &lt;strong&gt;@modules&lt;/strong&gt; 的前缀重写它们。&lt;/p&gt;
&lt;p&gt;目前社区中大部分模块或 npm 包都没有设置默认导出 esm，而是导出了 cjs 的包，既然 vue3.0 需要额外处理才能拿到 esm 的包内容。&lt;/p&gt;
&lt;p&gt;不过 vite 在最近的更新中，加入了 &lt;code&gt;optimize&lt;/code&gt; 命令，这个命令专门为解决模块引用的坑而开发，例如我们要在 vite 中使用 lodash，只需要在 &lt;strong&gt;vite.config.js&lt;/strong&gt; （vite 配置文件）中，配置 &lt;code&gt;optimizeDeps&lt;/code&gt; 对象，在 &lt;code&gt;include&lt;/code&gt; 数组中添加 lodash。&lt;/p&gt;
&lt;p&gt;这样 vite 在执行 &lt;code&gt;runOptimize&lt;/code&gt; 的时候中会使用 roolup 对 lodash 包重新编译，将编译成符合 esm 模块规范的新的包放入 node_modules 下的 .&lt;strong&gt;vite_opt_cache&lt;/strong&gt; 中，然后配合 resolver 对 &lt;code&gt;lodash&lt;/code&gt; 的导入进行处理：使用编译后的包内容代替原来 lodash 的包的内容，这样就解决了 vite 中不能使用 cjs 包的问题，这部分代码在 &lt;a href=&quot;https://github.com/vitejs/vite/blob/master/src/node/depOptimizer.ts&quot;&gt;depOptimizer.ts&lt;/a&gt; 里。&lt;/p&gt;
&lt;h2&gt;数据结构&lt;/h2&gt;
&lt;h3&gt;查找方法&lt;/h3&gt;
&lt;h4&gt;二分查找&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function find(arr, target) {
  let l = 0
  let h = arr.length - 1
  let m = null
  while (l &amp;lt;= h) {
    m = Math.floor((l + h) / 2)
    if (target === arr[m]) {
      return m
    }
    else if (target &amp;lt; arr[m]) {
      h = m - 1
    }
    else {
      l = m + 1
    }
  }
  return -1
}
console.log(find([0, 1, 1, 2, 6, 6, 6, 8], 6))

// 查找重复元素里index最小的那个，也可以说是没有那值，返回稍大的值的index
function find2(arr, target) {
  let l = 0
  let h = arr.length - 1
  let m = null
  while (l &amp;lt;= h) {
    m = Math.floor((l + h) / 2)
    if (target &amp;lt;= arr[m]) {
      h = m - 1
    }
    else {
      l = m + 1
    }
  }
  return l
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;排序方法&lt;/h3&gt;
&lt;h4&gt;冒泡排序&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const nums = [0, 1, 2, 1, 3, 8, 7, 6]
function popSort(arr) {
  let isSwap = false
  for (let i = 0; i &amp;lt; arr.length; i++) {
    for (let j = 0; j &amp;lt; arr.length - i - 1; j++) {
      if (arr[j] &amp;gt; arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        isSwap = true
      }
    }
    if (!isSwap) {
      break
    }
    isSwap = false
  }
  return arr
}
popSort(nums)
console.log(nums)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;快速排序&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function partition(arr, l, h) {
  const p = arr[l]
  while (l &amp;lt; h) {
    while (l &amp;lt; h &amp;amp;&amp;amp; arr[h] &amp;gt;= p) {
      h -= 1
    }
    arr[l] = arr[h]
    while (l &amp;lt; h &amp;amp;&amp;amp; arr[l] &amp;lt;= p) {
      l += 1
    }
    arr[h] = arr[l]
  }
  arr[l] = p
  return l
}
function qSort(arr, low, high) {
  if (low &amp;lt; high) {
    // 随机快排，取值为[low, high]
    const i = Math.round(Math.random() * (high - low) + low);
    [arr[i], arr[low]] = [arr[low], arr[i]]
    pLoc = partition(arr, low, high)
    qSort(arr, low, pLoc - 1)
    qSort(arr, pLoc + 1, high)
  }
}

const numList = [0, 1, 2, 1, 3, 8]
qSort(numList, 0, numList.length - 1)
console.log(numList)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;归并排序&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function mSort(arr) {
  if (arr.length === 1) {
    return arr
  }
  const mid = Math.floor(arr.length / 2)
  return merge(mSort(arr.slice(0, mid)), mSort(arr.slice(mid)))
}
var merge = (l, r) =&amp;gt; {
  const res = []
  while (l.length &amp;gt; 0 &amp;amp;&amp;amp; r.length &amp;gt; 0) {
    if (l[0] &amp;lt;= r[0]) {
      res.push(l.shift())
    }
    else {
      res.push(r.shift())
    }
  }
  return res.concat(l.length &amp;gt; 0 ? l : r)
}
const s = mSort([0, 1, 2, 1, 3, 8, 7, 6])
console.log(s)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;//  Definition for a binary tree node.
class TreeNode {
  constructor(val, left, right) {
    this.val = val === undefined ? 0 : val
    this.left = left === undefined ? null : left
    this.right = right === undefined ? null : right
  }
}
const tree = new TreeNode(
  &amp;#39;A&amp;#39;,
  new TreeNode(&amp;#39;B&amp;#39;, new TreeNode(&amp;#39;D&amp;#39;), new TreeNode(&amp;#39;E&amp;#39;)),
  new TreeNode(&amp;#39;C&amp;#39;, new TreeNode(&amp;#39;F&amp;#39;), new TreeNode(&amp;#39;G&amp;#39;))
)

/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
function levelOrder(root) {
  if (!root) {
    return []
  }
  root.row = 0
  const queue = [root]
  let p = null
  const res = []
  while (queue.length &amp;gt; 0) {
    p = queue.shift()
    if (p.row &amp;gt;= res.length) {
      res.push([p.val])
    }
    else {
      res[p.row].push(p.val)
    }
    p.left &amp;amp;&amp;amp; (p.left.row = p.row + 1) &amp;amp;&amp;amp; queue.push(p.left)
    p.right &amp;amp;&amp;amp; (p.right.row = p.row + 1) &amp;amp;&amp;amp; queue.push(p.right)
  }
  return res
}
// console.log(levelOrder(tree));

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
const preRes = []
function preorderTraversal(root) {
  if (!root) {
    return null
  }
  preRes.push(root.val)
  preorderTraversal(root.left)
  preorderTraversal(root.right)
}
preorderTraversal(tree)
// console.log(preRes);

function preOrder2(root) {
  if (!root) {
    return []
  }
  const stack = [root]
  const res = []
  let p = null
  while (stack.length &amp;gt; 0) {
    p = stack.pop()
    res.push(p.val)
    p.right &amp;amp;&amp;amp; stack.push(p.right)
    p.left &amp;amp;&amp;amp; stack.push(p.left)
  }
  return res
}

function preOrder3(root) {
  const stack = []
  const res = []
  let p = root
  while (stack.length &amp;gt; 0 || p) {
    if (p) {
      stack.push(p)
      res.push(p.val)
      p = p.left
    }
    else {
      p = stack.pop()
      p = p.right
    }
  }
  return res
}

console.log(&amp;#39;preOrder2: &amp;#39;, preOrder2(tree))
console.log(&amp;#39;preOrder3: &amp;#39;, preOrder3(tree))

const inRes = []
function inOrderRecur(root) {
  if (!root) {
    return null
  }
  inOrderRecur(root.left)
  inRes.push(root.val)
  inOrderRecur(root.right)
}
inOrderRecur(tree)
console.log(&amp;#39;inOrderRecur: &amp;#39;, inRes)

function inOrder2(root) {
  const res = []
  const stack = []
  let p = root
  while (stack.length &amp;gt; 0 || p) {
    if (p) {
      stack.push(p)
      p = p.left
    }
    else {
      p = stack.pop()
      res.push(p.val)
      p = p.right
    }
  }
  return res
}
console.log(&amp;#39;inOrder2: &amp;#39;, inOrder2(tree))

const postRes = []
function postOrderRecur(root) {
  if (!root) {
    return
  }
  postOrderRecur(root.left)
  postOrderRecur(root.right)
  postRes.push(root.val)
}
postOrderRecur(tree)
console.log(&amp;#39;postOrderRecur: &amp;#39;, postRes)

function postOrder2(root) {
  const res = []
  const stack = []
  let p = root
  let last = null
  while (stack.length &amp;gt; 0 || p) {
    if (p) {
      stack.push(p)
      p = p.left
    }
    else {
      p = stack.pop()
      // 如果右子树为空或者右子树已经遍历
      if (!p.right || p.right == last) {
        res.push(p.val)
        last = p
        p = null
      }
      else {
        stack.push(p)
        p = p.right
      }
    }
  }
  return res
}
console.log(&amp;#39;postOrder2: &amp;#39;, postOrder2(tree))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;网络安全&lt;/h2&gt;
&lt;h3&gt;对称加密&lt;/h3&gt;
&lt;p&gt;定义：有一个密钥，可以对一段内容加密，加密后只有用它才能看到原文。&lt;/p&gt;
&lt;p&gt;如果通信双方各持有同一个密钥，且没有别人只带，那么这双方的通信安全可以保证，除非密钥被破解。&lt;/p&gt;
&lt;p&gt;但是存在问题：这个密钥怎么让通信双方知道，同时不被别人知道。因为在服务器生成密钥传输给客户端的时候有可能被劫持。&lt;/p&gt;
&lt;p&gt;这时候就需要非对称加密了。&lt;/p&gt;
&lt;h3&gt;非对称加密&lt;/h3&gt;
&lt;p&gt;定义：有两把密钥，一把叫公钥，一把叫私钥。用公钥加密的内容必须用私钥才能解开，用私钥加密的内容只有公钥能解开。&lt;/p&gt;
&lt;p&gt;服务器把公钥明文传给客户端可能会被劫持，服务器向客户端传递的数据可能会被解析，只能保证客户端到服务器的通信安全。假如使用两对非对称密钥可以解决，但太过耗时。&lt;/p&gt;
&lt;p&gt;非对称加密比较耗时，对称加密快很多。&lt;/p&gt;
&lt;p&gt;所以 https 采用 非对称加密+对称加密，且非对称加密解密只使用一次就可以。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务器用于&lt;strong&gt;非对称加密&lt;/strong&gt;的公钥 A、私钥 AA&lt;/li&gt;
&lt;li&gt;浏览器向服务器请求，服务器把公钥 A 明文发给浏览器&lt;/li&gt;
&lt;li&gt;浏览器随机生成一个对称加密密钥 B，用公钥 A 加密后传给服务器&lt;/li&gt;
&lt;li&gt;服务器用私钥 AA 解密得到密钥 B&lt;/li&gt;
&lt;li&gt;这样双方都拥有对称密钥 B 了，且别人无法知道它&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样还是存在漏洞，例如中间人攻击&lt;/p&gt;
&lt;h3&gt;中间人攻击&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;服务器用于非对称公钥 A、私钥 AA，将公钥 A 明文发给浏览器&lt;/li&gt;
&lt;li&gt;中间人劫持&lt;strong&gt;公钥 A&lt;/strong&gt;，将自己的&lt;strong&gt;公钥 X&lt;/strong&gt;替换数据包里面的 A 发给浏览器。当然，中间人有&lt;strong&gt;私钥 XX&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;浏览器随机生成一个对称加密密钥 B，用公钥 X 加密传回服务器&lt;/li&gt;
&lt;li&gt;中间人劫持后用私钥 XX 解密得到&lt;strong&gt;密钥 B&lt;/strong&gt;，再用公钥 A 加密后传给服务器。&lt;/li&gt;
&lt;li&gt;服务器拿到后用私钥 AA 解密得到密钥 B&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后结果是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务器：公钥 A、私钥 AA、公钥 B&lt;/li&gt;
&lt;li&gt;中间人：公钥 A、自己的公钥 X 私钥 XX、公钥 B&lt;/li&gt;
&lt;li&gt;浏览器：中间人的公钥 X、自己生成的公钥 B&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样在服务器浏览器双方都不发现异常的情况下，中间人得到了密钥 B。&lt;/p&gt;
&lt;p&gt;原因是：浏览器无法确定自己收到的公钥是不是网站自己的。需要给网站服务器颁发一个“身份证”，也就是 CA 证书。&lt;/p&gt;
&lt;h3&gt;数字证书&lt;/h3&gt;
&lt;p&gt;证书：证书持有者，证书持有者的公钥。&lt;/p&gt;
&lt;p&gt;服务器把证书传输给浏览器，浏览器从证书里取公钥。&lt;/p&gt;
&lt;p&gt;需要做的是，证书的传输过程中，如何防止被修改。使用数字签名。&lt;/p&gt;
&lt;p&gt;把证书内容生成一份签名，比对证书内容和签名是否一致就能察觉是否被修改。&lt;/p&gt;
&lt;h3&gt;Https 获取密钥过程&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1684814969000eq3q8q.jpg&quot; alt=&quot;https流程&quot;&gt;&lt;/p&gt;
&lt;p&gt;【注】：HTTPS 必须在每次请求中都要先在 SSL/TLS 层进行握手传输密钥吗？&lt;/p&gt;
&lt;p&gt;可以通过一个会话标识符 session ID（在 TLS 握手中生成），服务器可以保存会话的相关信息，在服务器和服务器都保存了 session id 的情况下，就可以完成一次快速握手。&lt;/p&gt;
&lt;h3&gt;SSL/STL 协议&lt;/h3&gt;
&lt;p&gt;SSL/TLS 协议的基本过程是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;（1） 客户端向服务器端索要并验证公钥。
（2） 双方协商生成”对话密钥”。
（3） 双方采用”对话密钥”进行加密通信。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上面过程的前两步，又称为”握手阶段”（handshake）。&lt;/p&gt;
&lt;p&gt;“握手阶段”涉及四次通信，需要注意的是，”握手阶段”的所有通信都是明文的。&lt;/p&gt;
&lt;h2&gt;编码&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;ASCII&lt;/h3&gt;
&lt;p&gt;来源：上个世纪 60 年代，美国制定了一套字符编码，对英语字符与二进制位之间的关系，做了统一规定。这被称为 ASCII 码，一直沿用至今。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个字节&lt;/strong&gt;，ASCII 码一共规定了 128 个字符的编码（包括 32 个不能打印出来的控制符号），只占用了后 7 位，第一位统一用 0。&lt;/p&gt;
&lt;h3&gt;UNICODE&lt;/h3&gt;
&lt;p&gt;英语用 128 个符号编码就够了，但是用来表示其他语言，128 个符号是不够的。&lt;/p&gt;
&lt;p&gt;如果有一种编码，将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码，那么乱码问题就会消失。这就是 Unicode，就像它的名字都表示的，这是一种所有符号的编码。&lt;/p&gt;
&lt;p&gt;Unicode 只是一个&lt;strong&gt;符号集&lt;/strong&gt;，它只规定了符号的二进制代码，却没有规定这个二进制代码应该如何存储。&lt;/p&gt;
&lt;p&gt;于是 unicode 的实现方式 utf-8 出现了。&lt;/p&gt;
&lt;h3&gt;UTF-8&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;UTF-8 是 Unicode 的实现方式之一&lt;/strong&gt;，还包括 utf-16（两字节）和 utf-32（四字节），后两种基本不用&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可变长度编码&lt;/strong&gt;，使用&lt;strong&gt;1-4 个字节&lt;/strong&gt;表示一个符号&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;对于单字节，第一位设为 0，后面 7 位是这个符号的 unicode 码&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对于 n 字节，第一字节的前 n 位设为 1，第 n+1 位设为 0；后面自己的前两位设为 0；剩下其余二进制位全部为这个符号的 unicode 吗&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注：utf-8 兼容 ascii 码&lt;/p&gt;
&lt;h3&gt;原码、补码、反码、移码&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jianshu.com/p/abbdae4f3841&quot;&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于一个十六进制的数：0x，八位存储&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;原码：正数是其二进制本身；&lt;strong&gt;负数是符号位为 1&lt;/strong&gt;，数值部分取绝对值的二进制。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;反码：正数的反码和原码相同；负数是符号位为 1，&lt;strong&gt;其它位是原码取反&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;补码：正数的补码和原码，反码相同；&lt;strong&gt;负数是反码未位加 1&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;移码：&lt;strong&gt;将符号位取反的补码（不区分正负）&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;编码&lt;/p&gt;
&lt;p&gt;10810（sbyte）&lt;/p&gt;
&lt;p&gt;-10810（sbyte）&lt;/p&gt;
&lt;p&gt;原码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt;1101100&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;1101100&lt;/p&gt;
&lt;p&gt;反码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt;1101100&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;0010011&lt;/p&gt;
&lt;p&gt;补码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt;1101100&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;0010100&lt;/p&gt;
&lt;p&gt;移码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;1101100&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt;0010100&lt;/p&gt;
&lt;p&gt;来由：将符号位参与运算, 并且只保留加法的方法。&lt;/p&gt;
&lt;p&gt;如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原= [10000010]原 = -2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;为了解决原码做减法的问题, 出现了反码&lt;/p&gt;
&lt;p&gt;发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在”0”这个特殊的数值上. 虽然人们理解上+0 和-0 是一样的, 但是 0 带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示 0.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反+ [1111 1110]反= [1111 1111]反= [1000 0000]原= -0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;于是补码的出现, 解决了 0 的符号以及两个编码的问题&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补+ [1111 1111]补= [0000 0000]补=[0000 0000]原&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;-1-127 的结果应该是-128, 在用补码运算的结果中, [1000 0000]补就是-128. 但是注意因为实际上是使用以前的-0 的补码来表示-128, 所以-128 并没有原码和反码表示.(对-128 的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)&lt;/p&gt;
&lt;p&gt;使用补码, 不仅仅修复了 0 的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么 8 位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].&lt;/p&gt;
&lt;p&gt;因为&lt;strong&gt;机器使用补码&lt;/strong&gt;, 所以对于编程中常用到的 32 位 int 类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.&lt;/p&gt;
&lt;h3&gt;javascript 数字表示&lt;/h3&gt;
&lt;p&gt;JavaScript 使用 Number 类型表示数字（整数和浮点数），遵循 &lt;a href=&quot;https://zh.wikipedia.org/wiki/IEEE_754&quot;&gt;IEEE 754&lt;/a&gt; 标准 通过&lt;strong&gt;64 位&lt;/strong&gt;来表示一个数字。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 0 位：符号位，0 表示正数，1 表示负数(s)&lt;/li&gt;
&lt;li&gt;第 1 位到第 11 位：储存指数部分（e）&lt;/li&gt;
&lt;li&gt;第 12 位到第 63 位：储存小数部分（即有效数字）f&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScript 能够准确表示的整数范围在&lt;code&gt;-2^53&lt;/code&gt;到&lt;code&gt;2^53&lt;/code&gt;之间（不含两个端点），超过这个范围，无法精确表示这个整数。&lt;/p&gt;
&lt;p&gt;计算机无法直接对十进制的数字进行运算，这是硬件物理特性已经决定的。这样运算就分成了两个部分：&lt;strong&gt;先按照 IEEE 754 转成相应的二进制，然后对阶运算&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;0.1 和 0.2 转换成二进制后会无限循环&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;0.1 -&amp;gt; 0.0001100110011001...(无限循环)
0.2 -&amp;gt; 0.0011001100110011...(无限循环)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是由于 IEEE 754 尾数位数限制，需要将后面多余的位截掉，在进制之间的转换中精度已经损失&lt;/p&gt;
&lt;p&gt;由于指数位数不相同，运算时需要对阶运算 这部分也可能产生精度损失&lt;/p&gt;
&lt;p&gt;按照上面两步运算（包括两步的精度损失），最后的结果是&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;0.01001100110011001100110011001100110011001100110011
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果转换成十进制之后就是 0.30000000000000004，这样就有了前面的“秀”操作：0.1 + 0.2 != 0.3&lt;/p&gt;
&lt;p&gt;精度损失可能出现在进制转化和对阶运算过程中&lt;/p&gt;
&lt;h4&gt;怎么解决精度问题？&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;将数字转成整数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BigInt&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;BigInt&lt;/code&gt; 是一种内置对象，它提供了一种方法来表示大于 &lt;code&gt;253 - 1&lt;/code&gt; 的整数。这原本是 Javascript 中可以用 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number&quot;&gt;&lt;code&gt;Number&lt;/code&gt;&lt;/a&gt; 表示的最大数字。&lt;code&gt;BigInt&lt;/code&gt; 可以表示任意大的整数。&lt;/p&gt;
&lt;p&gt;可以用在一个整数字面量后面加 &lt;code&gt;n&lt;/code&gt; 的方式定义一个 &lt;code&gt;BigInt&lt;/code&gt; ，如：&lt;code&gt;10n&lt;/code&gt;，或者调用函数&lt;code&gt;BigInt()&lt;/code&gt;。不需要加 new。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;typeof&lt;/code&gt; 测试时， &lt;code&gt;BigInt&lt;/code&gt; 对象返回 “bigint”&lt;/p&gt;
&lt;h3&gt;汉字编码&lt;/h3&gt;
&lt;p&gt;gb2312，标准字符集 ，6K+字&lt;/p&gt;
&lt;p&gt;gbk 是 gb2312 的扩展规范，2W+字&lt;/p&gt;
&lt;p&gt;现在统一用 utf-8&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>生成一个有趣的链接</title><link>https://barry.ee/writing/eeelink/</link><guid isPermaLink="true">https://barry.ee/writing/eeelink/</guid><description>将你的链接全部变成“e”</description><pubDate>Mon, 22 May 2023 15:22:14 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1684743458000si15uh.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;前两天上网冲浪发现了一个有趣的项目 &lt;a href=&quot;https://github.com/lucaceriani/ooo&quot;&gt;ooo&lt;/a&gt; ,这个项目的有趣的地方在于可以将你的一个链接重新编码为一个全是 “o”的新链接，你可以将这个链接发给别人整蛊一下。虽然说这个项目实际来说意义不大，但是本着好奇他妈给好奇开门（bushi）的精神，我还是想自己部署一个玩一玩，于是就有了这篇文章，于是又诞生了一个全是 e 的站点 &lt;a href=&quot;https://eeeeeeeeeeee.ee/&quot;&gt;eeeeeeeeeeee.ee&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;域名&lt;/h2&gt;
&lt;p&gt;既然是一个小的 web 服务，还是一个基于域名跳转的 web 服务，这个域名选择就相当重要了，我直接跳过读源码阶段就准备先拿下一个域名，需求很简单，全都是一个字母就行，然后统计了一下目前已知顶级域后缀相同的有 &lt;code&gt;.ooo(infibeam注册局)&lt;/code&gt;、&lt;code&gt;.ee(爱沙尼亚)&lt;/code&gt; 、&lt;code&gt;.cc(可可群岛)&lt;/code&gt; 、&lt;code&gt;.gg(格恩西岛)&lt;/code&gt; 、&lt;code&gt;.tt(特立尼达和多巴哥)&lt;/code&gt; 、&lt;code&gt;.bb(巴巴多斯)&lt;/code&gt; 、&lt;code&gt;.xxx(用于成人网站)&lt;/code&gt;。我之前的个人域名就是 ee 后缀的，所以我先去看了下 ee... ee. ee 这个域名，在输入 12 个 e 的时候终于是可以用了，也去看了下别的几个都是前缀 15 个字母起步，而且价格还不便宜，所以还是选择了 ee 后缀的，主要是便宜，一年 69 人民币确实香。于是下单了 eeeeeeeeeeee.ee 。&lt;/p&gt;
&lt;h2&gt;部署&lt;/h2&gt;
&lt;h3&gt;读源码&lt;/h3&gt;
&lt;p&gt;在简单读了一下 ooo 的源码后，大概实现过程是先在前端将给定的 URL 编码为一个特殊的字符串，并能够将这个特殊的字符串解码回原始的 URL。编码过程使用了一种基于特殊字符 &amp;quot;o&amp;quot; 的表示法，将 URL 编码成包含四种不同 &amp;quot;o&amp;quot; 字符的字符串。后端仅通过 Cloudflare Worker 服务，将经过 OOO 编码的 URL 重定向到原始的 URL。在处理请求时，该 Worker 会将请求的 URL 中的路径部分解码，并将其作为经过 OOO 编码的字符串传递给 OOO 类的 decodeUrl 方法进行解码。解码后得到的字符串即为原始的 URL，然后使用 Cloudflare 的 Response.redirect 方法将请求重定向到原始的 URL。
读了源码其实我才发现，原来那些 o 并不是全部相同的 o，而是 4 个同形字符，四个不同的 &amp;quot;o&amp;quot; 字符（对应不同的 Unicode 编码）。&lt;/p&gt;
&lt;h3&gt;同形字符&lt;/h3&gt;
&lt;p&gt;所以现在我需要去找几个 e 的同形字符，幸运的是有人整理过相关内容的&lt;a href=&quot;https://www.bilibili.com/read/cv15844179&quot;&gt;文章&lt;/a&gt;，这里不得不感慨下光计算机字符里的学问还挺多的，前几天刚看到一个将用户名无形地插入到具有零宽度字符的文本中的&lt;a href=&quot;https://medium.com/@umpox/be-careful-what-you-copy-invisibly-inserting-usernames-into-text-with-zero-width-characters-18b4e6f17b66&quot;&gt;文章&lt;/a&gt;，也很有意思，有兴趣的朋友可以去看看。这里我选择了0065,0435 ： eе 和0275,04E9 ： ɵө 虽然后面两不太像，但也凑合。&lt;/p&gt;
&lt;h3&gt;前端页面&lt;/h3&gt;
&lt;p&gt;将项目克隆到本地，前端页面其实要改的也不多，将 &lt;code&gt;ooo.js&lt;/code&gt; 里的 OOO 对象里的四个“o”的字符换成我们自己的其实前端服务就能正常跑了，剩下就是改一些相应的内容样式。这里唯一需要注意的是，我们需要务必需要修改 &lt;code&gt;currVer = &amp;quot;eeee&amp;quot;&lt;/code&gt; 改值为与你域名字母相同，这是一个前缀用来我们后端进行路由识别，我们修改完成后将其上传到 Cloudflare Pages 服务中部署，并且绑定自定义域名为你购买的同字母域名（需提前将域名转入 Cloudflare）。&lt;/p&gt;
&lt;h3&gt;后端服务&lt;/h3&gt;
&lt;p&gt;前文有说到项目的后端服务是部署在 Cloudflare Worker 上的，后端涉及的代码为 &lt;code&gt;worker.js&lt;/code&gt;，在 Cloudflare 控制面板左侧选项中，找到 Workers 和 Pages 新建一个 Workers 并将 &lt;code&gt;worker.js&lt;/code&gt; 中的代码粘贴到点击 Worker 设置面板快速编辑按钮后出现的页面中。此步务必需要注意粘贴的代码中的解码对应的字符需要与前端编码字符对应，自行修改。修改完成点击设置面板的触发器选项，在路由处添加一个路由用来解析 URL，示例如下：
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1685085612000ugrvpl.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;现在你可以去访问你的域名看看出现编码后的链接能否跳转到目标地址了。如果不能正常跳转，可能是你的域名没有开启 Cloudflare CDN，也就是那朵小黄云我们需要打开，因为 worker 的自定义路由跳转需要先通过 CDN 劫持到访问的链接，不然是不可用的。&lt;/p&gt;
&lt;p&gt;Just enjoy it！&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>「富豪谷底求翻身」</title><link>https://barry.ee/writing/underdog/</link><guid isPermaLink="true">https://barry.ee/writing/underdog/</guid><description>「富豪谷底求翻身」第一季 影评</description><pubDate>Mon, 22 May 2023 15:10:14 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;这几天闲着找了一部纪录片看了下，还挺有意思的，跟大家分享一下里面的一些观点，主要内容为美国亿万富翁 Glenn Stearns 接受挑战，真实再现如何从贫穷汉到价值百万公司的总裁。Glenn 在节目中隐去自己的姓氏，用仅有的 100 美元和一辆卡车开始，在 90 天的时间完成任务。
这个真人秀的意义不在于可以复制他的成功，毕竟中美环境差异在那里，但是很多思路是可以借鉴和参考的，摘录了一些在节目中的一些句子。当然，个人的性格，领导力，亲和力以及知识储备也是成功必不可少的，这些&amp;quot;金句&amp;quot;并不能一夜暴富，大概也是一个提升方向吧。感觉这部剧在真人秀节目里已经算登峰造极了，有一定的社会意义，个人心态和思维方式都有很强的学习价值，目前已经有了第二季，应该也还行，有空也会看看。&lt;/p&gt;
&lt;h2&gt;金句&lt;/h2&gt;
&lt;h3&gt;第一集&lt;/h3&gt;
&lt;p&gt;1.cover the basics first（保障生计第一位）
如果整天忙着生计，是不可能创业的。所以精打细算的把每日的开销确认出来。
所以定下了7天挣3300刀。用于未来3个月的日常开销（衣食住行）。2. recognize your strengths and weaknesses（认清你的优劣势）&lt;/p&gt;
&lt;p&gt;因为他之前做过销售，所以他选择去找东西卖。3. find your buyer first（先找到买主，再依据需求出售）&lt;/p&gt;
&lt;p&gt;你眼中的垃圾，有可能是别人的宝藏。4. no job is beneath you(天下没有卑微的工作)&lt;/p&gt;
&lt;p&gt;亿万富翁接了一个打扫屋子的工作。5. diversify your efforts（扩大你的业务范围）&lt;/p&gt;
&lt;p&gt;圣帕特里克节是多方开拓财源的机会。6. buy low, sell high（投资入门原则，低买高卖）&lt;/p&gt;
&lt;p&gt;60美分的气球卖5刀7. tap into the herd mentality（善用从众心理）&lt;/p&gt;
&lt;p&gt;走到人群面前推销，只要能让两个人买，就有机会让整群人都跟着买。&lt;/p&gt;
&lt;h3&gt;第二集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;identify a need and fill it（分析需求，满足需求）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;成功创业的秘诀是：选择市场需要的产品，组织一个好的队伍。2. know your ****(搞懂你在做什么)&lt;/p&gt;
&lt;p&gt;了解行业的方方面面。3. human capital(人力资本)&lt;/p&gt;
&lt;p&gt;最重要的经营原则就是人力资本。面试的时候，关注的是人有没有拼劲，能不能长久留下来，相不相信这家公司。4. install confidence(灌输信心)&lt;/p&gt;
&lt;p&gt;团队如果不信任你，你什么都做不成。
确定团队相信你的愿景。&lt;/p&gt;
&lt;h3&gt;第三集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;be ready to pivot（做好变通的准备）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不是每笔生意都能照计划走，好的生意人永远都准备好应对突来的变化和失败，经营或创业难免如此。2. surround yourself with experts（找到各行业的专家）&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;do your due diligence(做好尽责调查)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;4.创业计划：
4.1 BBQ and beer restaurant(开啤酒烧烤餐厅)
4.2 go national with sauces and rubs（再把酱汁和肋排推销到全国）
4.3 bring in local beer（接洽地方酒厂）5. know how to motivate(知道用什么策略鼓励他人)&lt;/p&gt;
&lt;h3&gt;第四集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;create space for talent（加入发现人才，为他在团队中找个位置）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;没有位置就创造一个。2. less is more（少即是多）&lt;/p&gt;
&lt;p&gt;删掉过多无关的资讯，清楚说明需求，从头到尾把握要点。3. “No” is just the start of the comversation（拒绝只是对话的起头）&lt;/p&gt;
&lt;p&gt;所有成功的生意听过的拒绝都比同意多。&lt;/p&gt;
&lt;h3&gt;第五集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;find people smarter than you（找到比你聪明的人）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;set your own table（摆好宴席，不要坐等良机落手里）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;做甚矣想成功，就要主动寻找机会3. lose the battle to win the war&lt;/p&gt;
&lt;p&gt;（人在商场，有时候输掉一场仗，才能打赢整场战争）&lt;/p&gt;
&lt;h3&gt;第六集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;don&amp;#39;t pigeonhole your players (不要限制你的选手)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;check the plane before you fly it(行动之前先做检查)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;飞行员起飞之前一定会做足检查，因为性命攸关。3. if things go wrong, don&amp;#39;t go with them.(场面难看的时候，不要随之起舞)&lt;/p&gt;
&lt;p&gt;压力下能不能保持冷静，正是专业与否的差别。&lt;/p&gt;
&lt;h3&gt;第七集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;shut up and listen（闭上嘴认真听）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;仔细聆听你周围专家指导，承认他们提供的回馈是在帮助你成功。2. if you can&amp;#39;t stand the heat get out of the kitchen.（怕热就别进厨房）&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;p&gt;combat is optional(意见不合的时候，冲突是一个选择)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;endure more pain than anyone else（比别人忍受更多痛苦）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;设法度过难关，比竞争对手忍受更多痛苦，不能轻言放弃。&lt;/p&gt;
&lt;h3&gt;第八集&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;don&amp;#39;t confuse effort with results(别把努力和结果混为一谈)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;转动的轮子也要前进才有意义，努力工作是必要条件，重点是要聪明工作，重点在于最后你做到了什么。2. hand-ups not handouts（人们值得褒扬，不是被贬低）&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>一个访问全球互联网的“备用机”</title><link>https://barry.ee/writing/cloudflarezerotrust/</link><guid isPermaLink="true">https://barry.ee/writing/cloudflarezerotrust/</guid><description>使用免费的 Cloudflare Zero Trust 服务访问全球互联网</description><pubDate>Fri, 28 Apr 2023 16:51:14 GMT</pubDate><content:encoded>&lt;p&gt;作为全球第一 CDN / WAF 厂商，&lt;strong&gt;Cloudflare&lt;/strong&gt; 似乎从来不对流量进行计费，一直为大众提供诸多&lt;strong&gt;免费服务&lt;/strong&gt;，包括 &lt;strong&gt;CDN&lt;/strong&gt;，&lt;strong&gt;静态页面托管 (Cloudflare Pages)&lt;/strong&gt; ，以及本文要介绍的 &lt;strong&gt;Cloudflare Zero Trust&lt;/strong&gt;。
正如字面意义，&lt;strong&gt;Cloudflare Zero Trust&lt;/strong&gt; 提供 &lt;strong&gt;零信任&lt;/strong&gt; 环境下的，跨互联网的虚拟内网。
它可以将散落在全球的设备（包括 &lt;strong&gt;服务器&lt;/strong&gt; 和 &lt;strong&gt;个人电脑&lt;/strong&gt;）安全地连接在一起，并允许用户使用 &lt;strong&gt;Cloudflare&lt;/strong&gt; 提供的出口网关访问全球互联网&lt;/p&gt;
&lt;h2&gt;优势劣势&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;免费 且 无限流量&lt;/li&gt;
&lt;li&gt;WARP 协议更加底层，兼容性强&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;劣势&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无法选择节点（免费版）&lt;/li&gt;
&lt;li&gt;速度不快&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;前置条件&lt;/h2&gt;
&lt;p&gt;请准备:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;国际信用卡&lt;/strong&gt; (VISA, MASTERCARD 等) 或者 &lt;strong&gt;Paypal 账户&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Zero Trust&lt;/strong&gt; 服务本身是免费的，支付信息只用于验证用户身份&lt;/p&gt;
&lt;h2&gt;操作步骤&lt;/h2&gt;
&lt;h3&gt;1. 注册 Cloudflare 账户&lt;/h3&gt;
&lt;p&gt;访问 Cloudflare 官方网站 &lt;a href=&quot;https://cloudflare.com/&quot;&gt;https://cloudflare.com&lt;/a&gt;，注册账户，完成邮件验证&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16826730860004ia6e1.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h3&gt;2. 初始化 &lt;strong&gt;Zero Trust&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;2.1 进入 Zero Trust 管理台&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16826731080003j1okj.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h4&gt;2.2 初始化团队&lt;/h4&gt;
&lt;p&gt;起一个团队名称，并记住该名称, 此处以 &lt;code&gt;example001&lt;/code&gt; 为例&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673132000iy6y1t.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h4&gt;2.3 选择免费套餐，并支付 $0&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16826731480006273v8.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673161000q855jw.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h3&gt;3. 配置 &lt;strong&gt;Zero Trust&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;3.1 进入 Settings 界面&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673186000btn4hb.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h4&gt;3.2 修改 Network 设置&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673198000379zzw.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h5&gt;3.2.1 打开 &lt;code&gt;Firewall -&amp;gt; Proxy&lt;/code&gt;，并勾选 &lt;code&gt;UDP&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673213000cmhsh2.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;上述操作会启用 Cloudflare 自己的免费出口网关&lt;/em&gt;&lt;/p&gt;
&lt;h5&gt;3.3 修改 WARP Client 设置&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673236000yfzk94.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h6&gt;3.3.1 修改 Device enrollment permissions&lt;/h6&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673275000xphhd2.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;增加一条 &lt;strong&gt;规则&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16826733140008dywos.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673332000veecr8.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;填写以下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule name&lt;/strong&gt; 随便起名，比如填写为 &lt;code&gt;default&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selector&lt;/strong&gt; 选择 &lt;code&gt;Emails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value&lt;/strong&gt; 填写你的邮箱地址&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;保存后返回&lt;/p&gt;
&lt;p&gt;&lt;em&gt;上述操作允许你使用自己的邮件地址登录到自己的团队&lt;/em&gt;&lt;/p&gt;
&lt;h6&gt;3.3.2 打开 &lt;code&gt;Install CA to system certificate store&lt;/code&gt;&lt;/h6&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673371000dsb0cm.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;上述操作允许 WARP 客户端自动安装所需的证书&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;4. 安装配置客户端&lt;/h3&gt;
&lt;h4&gt;4.2 在 Settings 中找到 Downloads&lt;/h4&gt;
&lt;p&gt;下载并安装 WARP 客户端&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673420000x69gde.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1682673437000bwtedg.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h4&gt;4.3 配置 WARP 客户端&lt;/h4&gt;
&lt;p&gt;在各个平台下载完客户端后，在 &lt;code&gt;Peferences -&amp;gt; Account&lt;/code&gt; 中，输入你的团队名（第2.2步），并在弹出页面中，使用邮件地址（第 3.3.1 步) 验证登录即可&lt;/p&gt;
&lt;p&gt;至此，你的电脑已经可以通过 Cloudflare Zero Trust 安全地访问全球互联网了，虽然有时候速度不是很快，但是应付日常使用已经完全够用了，可以当做一个&amp;quot;备用机&amp;quot;使用。&lt;/p&gt;
&lt;p&gt;JUST ENJOY IT!&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>关于Linux内核</title><link>https://barry.ee/writing/linuxkernel/</link><guid isPermaLink="true">https://barry.ee/writing/linuxkernel/</guid><description>分享一张关于Linux内核的漫画</description><pubDate>Sat, 15 Apr 2023 13:14:14 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;昨天刷课时，刷到一张很有趣的关于 Linux 内核的漫画，感觉会对刚接触 Linux 的同学对 Linux 内核有更好的理解，在这里分享给大家。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;内核漫画&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16815240180005z3bei.png&quot; alt=&quot;Linux&quot;&gt;&lt;/p&gt;
&lt;h2&gt;一些理解&lt;/h2&gt;
&lt;p&gt;这张漫画很好的展示了 Linux 基本的一些运作原理，Linux 作为一个分层结构的系统，在漫画中将其简单分为三层，底层为文件系统，用来管理和操作文件，中间层为进程管理运行的地方，上层为一些 tty，也就是命令行工具来处理系统与用户交互的一些地方。&lt;/p&gt;
&lt;h3&gt;底层&lt;/h3&gt;
&lt;p&gt;我们先从底层开始看，首先底层是一个 filesystem，也就是管理操作文件的地方，这里的每一只小企鹅我们可以理解为一个进程，我们可以看到这只编号为 421 的企鹅正在打开文件柜，这里就可以理解为一个 PID 为 421 的进程正在读取文件夹对文件系统进行一些操作。&lt;/p&gt;
&lt;h3&gt;中间层&lt;/h3&gt;
&lt;p&gt;中间层为进程管理运行的地方，我们可以看到有很多只不同的小企鹅在各司其职，在右下角的 process table 这里桌子上坐着的小企鹅中，我们可以看到有一只编号为 171 的小企鹅眯着眼在休息，这里我们可以理解为在这个进程很空闲，并没有在处理任务。
在进程以外，我们还可以看到几只小狗，这些小狗其实就是一些对进程管理和监控的系统，然后我们看墙上其实也有很多有意思的地方，比如左边这个 1341 进程，我们可以看到它正在监听 80 端口，所以说这个进程正在处理一些网络输入输出的任务。
在后面还有一个 21 端口，我们可以看到这个 21 接口的牌牌已经摇摇欲坠了，说明很久都没有人光顾这个接口了，大家应该知道 21 接口是负责 ftp 协议的，也一方面反映这个协议已经比较老旧了。
21 端口正好可以与隔壁的 22 端口比较一下，22 端口大家都知道为 SSH 默认监听端口，我们可以看到监听 22 端口的这只小企鹅戴个墨镜，感觉是非常的 famous 非常的精神抖擞，这也侧面反映出 SSH 或者是 22 端口是目前比较常用或者比较流行的一个端口。
然后我们看到中间有一只大企鹅 217 cron，这其实是一只处理定时任务调度的进程。
也有一只叫 wine 的企鹅，这个进程使得在运行 Linux、FreeBSD 或其他一些操作系统的计算机上运行一些 Windows 应用程序成为可能。
在后面可以看到有两只企鹅在一起搬一根管道，这里也说明不同进程之间其实是可以通过管道进行通信的，不同进程是允许通信的。
最后我们可以看到有个楼梯是可以直接通往 FS 低层的文件系统的，也就是 421 这只企鹅在干的事。&lt;/p&gt;
&lt;h3&gt;顶层&lt;/h3&gt;
&lt;p&gt;顶层主要是一些 tty，这层会与很多命令行接口来处理用户的输入，我们看到也有企鹅在监听这些 tty，然后接收到用户的输入后通过进程处理后输出一些结果。&lt;/p&gt;
&lt;h3&gt;脑图&lt;/h3&gt;
&lt;p&gt;最后给大家分享一张 Linux 的思维导图，大家有需要自取。
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1681524119000vwfheg.png&quot; alt=&quot;Linux&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>我是如何解决 jsDelivr 在国内被污染的？</title><link>https://barry.ee/writing/jsdelivr/</link><guid isPermaLink="true">https://barry.ee/writing/jsdelivr/</guid><description>使用Cloudflare Worker为jsDelivr搭建反向代理服务</description><pubDate>Thu, 06 Apr 2023 12:20:14 GMT</pubDate><content:encoded>&lt;p&gt;早在2021年12月20日，jsDelivr 在中国大陆地区的 ICP 备案被吊销，且随后的服务在中国大陆地区极不稳定，严重拖慢了网页的速度。&lt;/p&gt;
&lt;p&gt;由于 jsDelivr 被封锁，导致了原来使用 jsDelivr 的 CDN 服务的网页速度缓慢，多数功能不正常。要解决这个问题，要么更换 CDN，要么给 jsDelivr 套上一层反向代理。这里博主采用了 Cloudflare Worker。&lt;/p&gt;
&lt;h2&gt;新建 Worker&lt;/h2&gt;
&lt;p&gt;登录到 Cloudflare 控制台，点击侧栏的 Workers，新建服务。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16807536030001yhgo9.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;在创建页面填入你自己的服务名称。
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1680753650000qwb9pf.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;p&gt;创建后将转入资源页面。
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1680753684000wpls1p.png&quot; alt=&quot;gh&quot;&gt;&lt;/p&gt;
&lt;h2&gt;部署&lt;/h2&gt;
&lt;p&gt;点击“快速编辑”，在代码框内复制以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 替换成你想镜像的站点
const upstream = &amp;#39;cdn.jsdelivr.net&amp;#39;

// 如果那个站点有专门的移动适配站点，否则保持和上面一致
const upstream_mobile = &amp;#39;cdn.jsdelivr.net&amp;#39;

const blocked_region = [&amp;#39;KP&amp;#39;, &amp;#39;RU&amp;#39;]

const blocked_ip_address = [&amp;#39;0.0.0.0&amp;#39;, &amp;#39;127.0.0.1&amp;#39;]

const replace_dict = {
  &amp;#39;$upstream&amp;#39;: &amp;#39;$custom_domain&amp;#39;,
  &amp;#39;//cdn.jsdelivr.net&amp;#39;: &amp;#39;&amp;#39;
}

// 以下内容都不用动
addEventListener(&amp;#39;fetch&amp;#39;, (event) =&amp;gt; {
  event.respondWith(fetchAndApply(event.request))
})

async function fetchAndApply(request) {
  const region = request.headers.get(&amp;#39;cf-ipcountry&amp;#39;).toUpperCase()
  const ip_address = request.headers.get(&amp;#39;cf-connecting-ip&amp;#39;)
  const user_agent = request.headers.get(&amp;#39;user-agent&amp;#39;)

  let response = null
  const url = new URL(request.url)
  const url_host = url.host

  if (url.protocol == &amp;#39;http:&amp;#39;) {
    url.protocol = &amp;#39;https:&amp;#39;
    response = Response.redirect(url.href)
    return response
  }

  if (await device_status(user_agent)) {
    upstream_domain = upstream
  }
  else {
    upstream_domain = upstream_mobile
  }

  url.host = upstream_domain

  if (blocked_region.includes(region)) {
    response = new Response(&amp;#39;Access denied: WorkersProxy is not available in your region yet.&amp;#39;, {
      status: 403
    })
  }
  else if (blocked_ip_address.includes(ip_address)) {
    response = new Response(&amp;#39;Access denied: Your IP address is blocked by WorkersProxy.&amp;#39;, {
      status: 403
    })
  }
  else {
    const method = request.method
    const request_headers = request.headers
    const new_request_headers = new Headers(request_headers)

    new_request_headers.set(&amp;#39;Host&amp;#39;, upstream_domain)
    new_request_headers.set(&amp;#39;Referer&amp;#39;, url.href)

    const original_response = await fetch(url.href, {
      method,
      headers: new_request_headers
    })

    const original_response_clone = original_response.clone()
    let original_text = null
    const response_headers = original_response.headers
    const new_response_headers = new Headers(response_headers)
    const status = original_response.status

    new_response_headers.set(&amp;#39;access-control-allow-origin&amp;#39;, &amp;#39;*&amp;#39;)
    new_response_headers.set(&amp;#39;access-control-allow-credentials&amp;#39;, true)
    new_response_headers.delete(&amp;#39;content-security-policy&amp;#39;)
    new_response_headers.delete(&amp;#39;content-security-policy-report-only&amp;#39;)
    new_response_headers.delete(&amp;#39;clear-site-data&amp;#39;)

    const content_type = new_response_headers.get(&amp;#39;content-type&amp;#39;)
    if (content_type.includes(&amp;#39;text/html&amp;#39;) &amp;amp;&amp;amp; content_type.includes(&amp;#39;UTF-8&amp;#39;)) {
      original_text = await replace_response_text(original_response_clone, upstream_domain, url_host)
    }
    else {
      original_text = original_response_clone.body
    }

    response = new Response(original_text, {
      status,
      headers: new_response_headers
    })
  }
  return response
}

async function replace_response_text(response, upstream_domain, host_name) {
  let text = await response.text()

  let i, j
  for (i in replace_dict) {
    j = replace_dict[i]
    if (i == &amp;#39;$upstream&amp;#39;) {
      i = upstream_domain
    }
    else if (i == &amp;#39;$custom_domain&amp;#39;) {
      i = host_name
    }

    if (j == &amp;#39;$upstream&amp;#39;) {
      j = upstream_domain
    }
    else if (j == &amp;#39;$custom_domain&amp;#39;) {
      j = host_name
    }

    const re = new RegExp(i, &amp;#39;g&amp;#39;)
    text = text.replace(re, j)
  }
  return text
}

async function device_status(user_agent_info) {
  const agents = [&amp;#39;Android&amp;#39;, &amp;#39;iPhone&amp;#39;, &amp;#39;SymbianOS&amp;#39;, &amp;#39;Windows Phone&amp;#39;, &amp;#39;iPad&amp;#39;, &amp;#39;iPod&amp;#39;]
  let flag = true
  for (let v = 0; v &amp;lt; agents.length; v++) {
    if (user_agent_info.indexOf(agents[v]) &amp;gt; 0) {
      flag = false
      break
    }
  }
  return flag
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存并部署后，你的反向代理就生效了。&lt;/p&gt;
&lt;h2&gt;自定义域名&lt;/h2&gt;
&lt;p&gt;但是不幸的是在国内 &lt;code&gt;.workers.dev&lt;/code&gt; 后缀的域名现在也被污染了，所以你需要自己绑定一个域名在国内才能正常访问。
先购买一个域名，然后将其 DNS 服务商转到 cloudflare。随后来到我们刚刚新建的 Workers 管理页面点击触发器-&amp;gt;自定义域-&amp;gt;添加自定义域，输入你想绑定的域名即可。&lt;/p&gt;
&lt;h2&gt;测试&lt;/h2&gt;
&lt;p&gt;使用时，将原来的 &lt;code&gt;cdn.jsdelivr.net&lt;/code&gt; 域名替换为您的 Worker 或者博主提供的 Worker 就可以了。如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;https://cdn.jsdelivr.net/gh/BarryYangi/ObsStaticData/obsidian/168069442100071iy8i.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将&lt;code&gt;cdn.jsdelivr.net&lt;/code&gt;替换为我们的Worker：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;https://jsdelivr-cdn.2059484047.workers.dev/gh/BarryYangi/ObsStaticData/obsidian/168069442100071iy8i.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，就能保证较为稳定的使用 jsDelivr 的服务了。&lt;/p&gt;
&lt;p&gt;Just enjoy it.&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>前端300+实用工具分享【转载】</title><link>https://barry.ee/writing/300tools/</link><guid isPermaLink="true">https://barry.ee/writing/300tools/</guid><description>前端300+实用工具</description><pubDate>Mon, 27 Mar 2023 20:49:03 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文内容来自 B 站 UP 主 &lt;a href=&quot;https://space.bilibili.com/165659472&quot;&gt;@技术胖&lt;/a&gt;的视频：&lt;a href=&quot;https://www.bilibili.com/video/BV1ke4y1v7Xd/&quot;&gt;前端老司机 300+实用工具分享&lt;/a&gt; 若造成侵权请联系我进行删除。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Javascript&lt;/h2&gt;
&lt;h3&gt;工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Underscore.js
一套完善的函数式编程的接口，更方便地在JavaScript中实现函数式编程
&lt;a href=&quot;https://underscorejs.org/&quot;&gt;https://underscorejs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fastclick
用于消除物理点击和click移动浏览器上事件触发之间的 300 毫秒延迟
&lt;a href=&quot;https://github.com/ftlabs/fastclick&quot;&gt;https://github.com/ftlabs/fastclick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lodash
一致性、模块化、高性能的 JavaScript 实用工具库
&lt;a href=&quot;https://lodash.com/&quot;&gt;https://lodash.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;crypto-js
加密标准的 JavaScript 库。
&lt;a href=&quot;https://github.com/brix/crypto-js&quot;&gt;https://github.com/brix/crypto-js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zxcvbn
JavaScript密码强度估算库
&lt;a href=&quot;https://github.com/dropbox/zxcvbn&quot;&gt;https://github.com/dropbox/zxcvbn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zxcvbn-ts
支持Typescript的密码强度估算库
&lt;a href=&quot;https://github.com/zxcvbn-ts/zxcvbn&quot;&gt;https://github.com/zxcvbn-ts/zxcvbn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;clipboard.js
将文本复制到剪贴板的轻量级JS 库
&lt;a href=&quot;https://clipboardjs.com/&quot;&gt;https://clipboardjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tesseract.js
Javascript的OCR引擎，在浏览器离线识别图片中的文字
&lt;a href=&quot;https://tesseract.projectnaptha.com/&quot;&gt;https://tesseract.projectnaptha.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;number-precision
小而快的库，用于精确地进行加法、减法、乘法和除法运算
&lt;a href=&quot;https://github.com/nefe/number-precision&quot;&gt;https://github.com/nefe/number-precision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fingerprintjs
具有高准确度和稳定性的浏览器指纹库
&lt;a href=&quot;https://fingerprint.com/&quot;&gt;https://fingerprint.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ViteShot
基于Vite的快速简单的截图工具。
&lt;a href=&quot;https://viteshot.com/&quot;&gt;https://viteshot.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Valine
快速、简洁且高效的无后端评论系统
&lt;a href=&quot;https://valine.js.org/&quot;&gt;https://valine.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;cnpm
淘宝提供的一个完整 npmjs.org 镜像，你可以用此代替官方版本(只读)，同步频率目前为 10分钟 一次以保证尽量与官方服务同步
&lt;a href=&quot;https://npmmirror.com/&quot;&gt;https://npmmirror.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;yarn
快速、可靠和安全的依赖管理
&lt;a href=&quot;https://yarnpkg.com/&quot;&gt;https://yarnpkg.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;responsively-app
一种改进的 Web 浏览器，有助于响应式 Web 开发。Web 开发人员必须拥有开发工具
&lt;a href=&quot;https://responsively.app/&quot;&gt;https://responsively.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;javascript-obfuscator
功能强大的免费 JavaScript 混淆器，包含多种功能，可为源代码提供保护
&lt;a href=&quot;https://obfuscator.io/&quot;&gt;https://obfuscator.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nano ID
小巧的、安全的、URL 友好的、独特的 JavaScript 字符串 唯一 ID 生成器
&lt;a href=&quot;https://zelark.github.io/nano-id-cc/&quot;&gt;https://zelark.github.io/nano-id-cc/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;spy-debugger
一站式页面调试、抓包工具。远程调试任何手机浏览器页面，任何手机移动端webview（如：微信，HybridApp等）。支持HTTP/HTTPS，无需USB连接设备
&lt;a href=&quot;https://responsively.app/&quot;&gt;https://responsively.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fuite
用于查找 Web 应用程序中的内存泄漏的工具
&lt;a href=&quot;https://github.com/nolanlawson/fuite&quot;&gt;https://github.com/nolanlawson/fuite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;qs
查询字符串解析和字符串化库
&lt;a href=&quot;https://github.com/ljharb/qs&quot;&gt;https://github.com/ljharb/qs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;js-cookie
用于处理 cookie 的简单、轻量级 JavaScript API
&lt;a href=&quot;https://github.com/js-cookie/js-cookie&quot;&gt;https://github.com/js-cookie/js-cookie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tinymce
排名第一的可定制、可扩展和灵活的富文本编辑器
&lt;a href=&quot;https://www.tiny.cloud/&quot;&gt;https://www.tiny.cloud/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;html2canvas
允许在用户浏览器上对网页或其部分进行“截图”
&lt;a href=&quot;https://html2canvas.hertzen.com/&quot;&gt;https://html2canvas.hertzen.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;shepherd
引导用户浏览您的应用
&lt;a href=&quot;https://shepherdjs.dev/&quot;&gt;https://shepherdjs.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tinykeys
极小的键盘事件监听库
&lt;a href=&quot;https://jamiebuilds.github.io/tinykeys/&quot;&gt;https://jamiebuilds.github.io/tinykeys/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ag-grid
用于构建企业应用程序的最佳 JavaScript 数据表
&lt;a href=&quot;https://www.ag-grid.com/&quot;&gt;https://www.ag-grid.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tui.calendar
功能齐全的 JavaScript 日程表
&lt;a href=&quot;https://ui.toast.com/tui-calendar&quot;&gt;https://ui.toast.com/tui-calendar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;screenfull
用于跨浏览器使用 JavaScript Fullscreen API 的简单包装器
&lt;a href=&quot;https://sindresorhus.com/screenfull/&quot;&gt;https://sindresorhus.com/screenfull/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fuse.js
JavaScript 中的轻量级模糊搜索
&lt;a href=&quot;https://fusejs.io/&quot;&gt;https://fusejs.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;i18next
用于浏览器或任何其他 javascript 环境（例如 Node.js、Deno）的国际化框架
&lt;a href=&quot;https://www.i18next.com/&quot;&gt;https://www.i18next.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JsBarcode
适用于 Web 和 Node.js 的易于使用但功能强大的条形码生成器
&lt;a href=&quot;https://lindell.me/JsBarcode/&quot;&gt;https://lindell.me/JsBarcode/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;path-to-regexp
将 &lt;code&gt;/user/:name&lt;/code&gt; 等路径字符串转换为正则表达式
&lt;a href=&quot;https://github.com/pillarjs/path-to-regexp&quot;&gt;https://github.com/pillarjs/path-to-regexp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;await-to-js
异步等待包装器，无需 try-catch 即可轻松处理错误
&lt;a href=&quot;https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/&quot;&gt;https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;md5
用 MD5 散列消息的 JavaScript 函数
&lt;a href=&quot;https://github.com/pvorb/node-md5&quot;&gt;https://github.com/pvorb/node-md5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;mitt.js
它足够小，仅有200bytes，其次支持全部事件的监听和批量移除，替代EventBus
&lt;a href=&quot;https://npm.im/mitt&quot;&gt;https://npm.im/mitt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;js-spark-md5
MD5 算法的快速 md5 实现
&lt;a href=&quot;https://github.com/satazor/js-spark-md5&quot;&gt;https://github.com/satazor/js-spark-md5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nano
小型（130 字节）、安全、URL 友好、唯一的 JavaScript 字符串 ID 生成器
&lt;a href=&quot;https://zelark.github.io/nano-id-cc/&quot;&gt;https://zelark.github.io/nano-id-cc/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;jsPDF
用 JavaScript 生成 PDF
&lt;a href=&quot;https://parall.ax/products/jspdf&quot;&gt;https://parall.ax/products/jspdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ua-parser-js
从User-Agen中检测浏览器、引擎、操作系统、CPU 和设备类型/型号，占用空间相对较小（压缩后约 17KB，压缩后约 6KB），支持浏览器和 node.js 环境
&lt;a href=&quot;http://faisalman.github.io/ua-parser-js/&quot;&gt;http://faisalman.github.io/ua-parser-js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;togetherjs
网站添加实时协作功能的JavaScript库，两个人可以在同一页面上进行交互，查看彼此的光标、编辑并一起浏览网站
&lt;a href=&quot;https://togetherjs.com/&quot;&gt;https://togetherjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Clusterize.js
开源的长列表渲染库，轻量级的原生大数据量展示
&lt;a href=&quot;https://clusterize.js.org/&quot;&gt;https://clusterize.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;crypto-js-wasm
加密标准的 javascript 库，比 crypto-js快16 倍
&lt;a href=&quot;https://github.com/originjs/crypto-js-wasm&quot;&gt;https://github.com/originjs/crypto-js-wasm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pdfkit
用于 Node 和浏览器的 JavaScript PDF 生成库
&lt;a href=&quot;http://pdfkit.org/&quot;&gt;http://pdfkit.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zx
使用js编写更便捷shell脚本
&lt;a href=&quot;https://www.npmjs.com/package/zx&quot;&gt;https://www.npmjs.com/package/zx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NProgress.js
适用于应用程序的进度条，受 Google、YouTube 和 Medium 的启发
&lt;a href=&quot;https://ricostacruz.com/nprogress/&quot;&gt;https://ricostacruz.com/nprogress/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;可视化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;highlight.js
JavaScript 语法高亮器，具有语言自动检测和零依赖项
&lt;a href=&quot;https://highlightjs.org/&quot;&gt;https://highlightjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Drawflow
创建简单的流程库
&lt;a href=&quot;https://jerosoler.github.io/Drawflow/&quot;&gt;https://jerosoler.github.io/Drawflow/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tui.image-editor
HTML5 Canvas 的全功能图像编辑器。它易于使用并提供强大的过滤器
&lt;a href=&quot;https://ui.toast.com/tui-image-editor&quot;&gt;https://ui.toast.com/tui-image-editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;viewerjs
JavaScript 图像查看器
&lt;a href=&quot;https://fengyuanchen.github.io/viewerjs/&quot;&gt;https://fengyuanchen.github.io/viewerjs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;prism.js
轻量级、健壮、优雅的语法高亮库
&lt;a href=&quot;https://prismjs.com/&quot;&gt;https://prismjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fabric.js
功能强大且简单的 Canvas库，轻松处理 HTML5 画布元素。是画布元素之上的交互式对象模型，也是一个SVG-to-canvas 解析器
&lt;a href=&quot;http://fabricjs.com/&quot;&gt;http://fabricjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fullPage.js
用于创建全屏滚动网站（也称为单页网站或一页网站），并在该网站的各个部分内添加横向滑块
&lt;a href=&quot;https://alvarotrigo.com/fullPage/&quot;&gt;https://alvarotrigo.com/fullPage/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;opentype.js
OpenType 和 TrueType 字体解析器和编写器。它允许您从浏览器或 node.js访问文本的字母形式
&lt;a href=&quot;https://opentype.js.org/&quot;&gt;https://opentype.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;icones.js
具有即时搜索功能的图标资源管理器，由 Iconify 提供支持
&lt;a href=&quot;https://icones.js.org/&quot;&gt;https://icones.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;reveal.js
创建功能齐全且精美的演示文稿
&lt;a href=&quot;https://revealjs.com/&quot;&gt;https://revealjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;carbon
创建和共享源代码的精美图像
&lt;a href=&quot;https://carbon.now.sh/&quot;&gt;https://carbon.now.sh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lucky-canvas
基于 TS + Canvas 开发的【大转盘 / 九宫格 / 老虎机】抽奖插件， 一套源码适配多端框架 JS / Vue / React / Taro / UniApp / 微信小程序等
&lt;a href=&quot;https://100px.net/&quot;&gt;https://100px.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Darkmode.js
在几秒钟内为您的网站添加暗模式/夜间模式
&lt;a href=&quot;https://darkmodejs.learn.uno/?_360safeparam=8406218&quot;&gt;https://darkmodejs.learn.uno/?_360safeparam=8406218&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ECharts
强大的交互式图表和浏览器数据可视化库
&lt;a href=&quot;https://echarts.apache.org/zh/index.html&quot;&gt;https://echarts.apache.org/zh/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PixiJS
使用最快，最灵活的2D WebGL渲染器创建精美的内容
&lt;a href=&quot;https://pixijs.com/&quot;&gt;https://pixijs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AntV - G2
数据驱动，高度易用，可扩展的可视化图形语法。
&lt;a href=&quot;https://g2plot.antv.vision/zh/&quot;&gt;https://g2plot.antv.vision/zh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ApexCharts.js
基于SVG的JavaScript图表库，可使用简单的API构建交互式图表和可视化文件&lt;/li&gt;
&lt;li&gt;OpenLayers
高性能，功能丰富的库，用于在Web上创建交互式地图。它可以显示从任何网页上的任何来源加载的地图图块，矢量数据和标记
&lt;a href=&quot;https://openlayers.org/&quot;&gt;https://openlayers.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Two.js
面向现代Web浏览器的二维绘图api，渲染不可知实现相同的API在多种环境中得出：svg，canvas，和webgl
&lt;a href=&quot;https://two.js.org/&quot;&gt;https://two.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Paper.js
基于HTML5 Canvas的矢量图形的图形库
&lt;a href=&quot;http://paperjs.org/&quot;&gt;http://paperjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Panolens.js
事件驱动的基于WebGL的全景查看器。轻巧而灵活。它建立在Three.JS之上
&lt;a href=&quot;https://pchen66.github.io/Panolens/&quot;&gt;https://pchen66.github.io/Panolens/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A-Frame
用于构建 3D/AR/VR 体验的 Web 框架
&lt;a href=&quot;https://aframe.io/&quot;&gt;https://aframe.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;mermaid-js
以与 Markdown 类似的方式从文本生成图表和流程图
&lt;a href=&quot;https://mermaid-js.github.io/mermaid/&quot;&gt;https://mermaid-js.github.io/mermaid/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;mo · js
为网站添加基于JavaScript的动态图形
&lt;a href=&quot;https://mojs.github.io/&quot;&gt;https://mojs.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;trianglify
Javascript 库，用于创建独特的、美观的三角形图案
&lt;a href=&quot;http://qrohlf.com/trianglify/&quot;&gt;http://qrohlf.com/trianglify/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Babylon.js
能强大、美观、简单、开放的游戏和渲染引擎
&lt;a href=&quot;https://www.babylonjs.com/&quot;&gt;https://www.babylonjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oasis Engine
高性能 Web 蚂蚁图形引擎
&lt;a href=&quot;https://oasisengine.cn/&quot;&gt;https://oasisengine.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Butterfly
基于JS的数据驱动的节点式编排组件库
&lt;a href=&quot;https://butterfly-dag.gitee.io/butterfly-dag/home&quot;&gt;https://butterfly-dag.gitee.io/butterfly-dag/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;image-optimizer
使用 Electron、Vue 和 Vite 用于优化图像和矢量图形的免费开源工具
&lt;a href=&quot;https://github.com/antonreshetov/image-optimizer&quot;&gt;https://github.com/antonreshetov/image-optimizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sketchfab
需任何插件即可在Web页面里嵌入交互式3D模型
&lt;a href=&quot;https://sketchfab.com/&quot;&gt;https://sketchfab.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vConsole
用于移动网页的轻量级、可扩展的前端开发工具
&lt;a href=&quot;https://github.com/Tencent/vConsole&quot;&gt;https://github.com/Tencent/vConsole&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;swiper
免费且最现代的移动触摸滑块，具有硬件加速过渡和惊人的原生行为
&lt;a href=&quot;https://swiperjs.com/&quot;&gt;https://swiperjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Slidev
面向开发人员的演示幻灯片
&lt;a href=&quot;https://sli.dev/&quot;&gt;https://sli.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;konva
HTML5 Canvas JavaScript 框架，它支持桌面和移动应用程序的高性能动画、过渡、节点嵌套、分层、过滤、缓存、事件处理等等
&lt;a href=&quot;https://konvajs.org/&quot;&gt;https://konvajs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;p5.j s
开源的JavaScript可视化库，processing的js实现版本
&lt;a href=&quot;https://p5js.org/zh-Hans/&quot;&gt;https://p5js.org/zh-Hans/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;cesium
用于世界级 3D 地球仪和地图的开源 JavaScript 库
&lt;a href=&quot;https://cesium.com/platform/cesiumjs/&quot;&gt;https://cesium.com/platform/cesiumjs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;driver.js
一个轻量级、无依赖的用户引导组件
&lt;a href=&quot;https://kamranahmed.info/driver.js/&quot;&gt;https://kamranahmed.info/driver.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vanilla-tilt.js
平滑的 3D 倾斜 JavaScript 库
&lt;a href=&quot;https://micku7zu.github.io/vanilla-tilt.js/index.html&quot;&gt;https://micku7zu.github.io/vanilla-tilt.js/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;parallax.js
对智能设备的方向引擎响应的视差
&lt;a href=&quot;http://matthew.wagerfield.com/parallax/&quot;&gt;http://matthew.wagerfield.com/parallax/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;signature_pad
基于 HTML5 canvas 的平滑签名绘制
&lt;a href=&quot;http://szimek.github.io/signature_pad/&quot;&gt;http://szimek.github.io/signature_pad/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;compressorjs
JavaScript 图像压缩器
&lt;a href=&quot;https://fengyuanchen.github.io/compressorjs/&quot;&gt;https://fengyuanchen.github.io/compressorjs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;eva.js
用于创建交互式游戏项目的前端游戏引擎
&lt;a href=&quot;https://eva.js.org/&quot;&gt;https://eva.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;d3
基于数据来操作文档的JavaScript库
&lt;a href=&quot;https://d3js.org/&quot;&gt;https://d3js.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;动画插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;countUp.js
无依赖项的轻量级Javascript类，可用于快速创建以更有趣的方式显示数字数据的动画
&lt;a href=&quot;https://inorganik.github.io/countUp.js/&quot;&gt;https://inorganik.github.io/countUp.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;impress.js
CSS3 转换和过渡的强大功能的演示框架
&lt;a href=&quot;https://impress.js.org/&quot;&gt;https://impress.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Anime.js
轻量级的 JavaScript 动画库，具有简单而强大的 API
&lt;a href=&quot;https://animejs.com/&quot;&gt;https://animejs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tween.js
用于简单动画的 JavaScript 补间引擎，包含优化的 Robert Penner 方程
&lt;a href=&quot;http://tweenjs.github.io/tween.js/&quot;&gt;http://tweenjs.github.io/tween.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Popmotion
制作数字、颜色和复杂字符串的动画。该库的主要动画功能只有5kb左右，整个库的容量在12kb左右
&lt;a href=&quot;https://popmotion.io/&quot;&gt;https://popmotion.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Typed.js
打字动画库
&lt;a href=&quot;https://mattboldt.com/demos/typed-js/&quot;&gt;https://mattboldt.com/demos/typed-js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vivus.js
在 SVG 上制作绘图动画的 JavaScript 库
&lt;a href=&quot;https://maxwellito.github.io/vivus/&quot;&gt;https://maxwellito.github.io/vivus/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ScrollReveal
在元素滚入或滚出视口时为其制作动画
&lt;a href=&quot;https://scrollrevealjs.org/&quot;&gt;https://scrollrevealjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;canvas-confetti
按需 五彩纸屑
&lt;a href=&quot;https://catdad.github.io/canvas-confetti/&quot;&gt;https://catdad.github.io/canvas-confetti/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GSAP
强大的 JavaScript 工具集，构建适用于所有主流浏览器的高性能动画。动画 CSS、SVG、画布、React、Vue、WebGL、颜色、字符串、运动路径、通用对象
&lt;a href=&quot;https://greensock.com/&quot;&gt;https://greensock.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lax.js
轻量级（&amp;lt;4kb gzipped）香草 JavaScript 库，可在您滚动时创建流畅美观的动画
&lt;a href=&quot;https://github.com/alexfoxy/lax.js&quot;&gt;https://github.com/alexfoxy/lax.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;animxyz
AnimXYZ 可帮助您为您的网站创建、自定义和组合动画
&lt;a href=&quot;https://animxyz.com/&quot;&gt;https://animxyz.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;svg.js
用于操作和动画 SVG 的轻量级库
&lt;a href=&quot;https://svgjs.dev/docs/3.0/&quot;&gt;https://svgjs.dev/docs/3.0/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zdog
用于画布和 SVG 的扁平、圆形、设计师友好的伪 3D 引擎
&lt;a href=&quot;https://zzz.dog/&quot;&gt;https://zzz.dog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;dynamics.js
用于创建基于物理的动画的 JavaScript 库
&lt;a href=&quot;http://dynamicsjs.com/&quot;&gt;http://dynamicsjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Proton
Javascript粒子动画库
&lt;a href=&quot;https://drawcall.github.io/Proton/&quot;&gt;https://drawcall.github.io/Proton/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;文件操作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SheetJS
可读取和导出excel的工具库，功能强大，支持格式众多，支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式
&lt;a href=&quot;https://sheetjs.com/&quot;&gt;https://sheetjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;revogrid
具有高级定制功能的强大虚拟数据表格
&lt;a href=&quot;https://revolist.github.io/revogrid/&quot;&gt;https://revolist.github.io/revogrid/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;FileSaver.js
客户端保存文件的解决方案
&lt;a href=&quot;https://eligrey.com/blog/saving-generated-files-on-the-client-side/&quot;&gt;https://eligrey.com/blog/saving-generated-files-on-the-client-side/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;jszip
使用 Javascript 创建、读取和编辑 .zip 文件
&lt;a href=&quot;https://stuk.github.io/jszip/&quot;&gt;https://stuk.github.io/jszip/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Print.js
帮助从网络打印的小型 javascript 库
&lt;a href=&quot;https://printjs.crabbly.com/&quot;&gt;https://printjs.crabbly.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;mammoth.js
将 Word 文档（.docx 文件）转换为 HTML
&lt;a href=&quot;https://github.com/mwilliamson/mammoth.js&quot;&gt;https://github.com/mwilliamson/mammoth.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;StreamSaver.js
直接异步将流写入文件系统，适合大文件下载
&lt;a href=&quot;https://jimmywarting.github.io/StreamSaver.js/example.html&quot;&gt;https://jimmywarting.github.io/StreamSaver.js/example.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PDF.js
使用 HTML5 构建的可移植文档格式 (PDF) 查看器
&lt;a href=&quot;https://github.com/mozilla/pdf.js&quot;&gt;https://github.com/mozilla/pdf.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pdfmake
用于服务器端和客户端的 PDF 文档生成库
&lt;a href=&quot;http://pdfmake.org/&quot;&gt;http://pdfmake.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pdf-lib
在任何 JavaScript 环境中创建和修改 PDF 文档
&lt;a href=&quot;https://pdf-lib.js.org/&quot;&gt;https://pdf-lib.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;uppy
JavaScript 文件上传器
&lt;a href=&quot;https://uppy.io/&quot;&gt;https://uppy.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;音视频&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;moovie.js
专注于电影的 HTML5 播放器
&lt;a href=&quot;https://mooviejs.com/&quot;&gt;https://mooviejs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;meyda.js
JavaScript 音频特征提取库
&lt;a href=&quot;https://meyda.js.org/&quot;&gt;https://meyda.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;howler.js
Javascript 音频库
&lt;a href=&quot;https://howlerjs.com/&quot;&gt;https://howlerjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;flv.js
HTML5 FLV 播放器
&lt;a href=&quot;https://github.com/Bilibili/flv.js/&quot;&gt;https://github.com/Bilibili/flv.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;plyr
HTML5、YouTube 和 Vimeo 播放器
&lt;a href=&quot;https://plyr.io/&quot;&gt;https://plyr.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;xgplayer 西瓜播放器
网络视频和音频播放器库
&lt;a href=&quot;https://h5player.bytedance.com/&quot;&gt;https://h5player.bytedance.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;hls.js
可在支持 MSE 的浏览器中播放 HLS
&lt;a href=&quot;https://hls-js.netlify.app/demo/&quot;&gt;https://hls-js.netlify.app/demo/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;智能化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;tensorflow.js
用于在浏览器和 Node.js 训练和部署机器学习模型
&lt;a href=&quot;https://tensorflow.google.cn/&quot;&gt;https://tensorflow.google.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;face-api.js
用于在浏览器和 nodejs 中使用 tensorflow.js 进行人脸检测和人脸识别的 JavaScript API
&lt;a href=&quot;https://github.com/justadudewhohacks/face-api.js/&quot;&gt;https://github.com/justadudewhohacks/face-api.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tracking.js
将不同的计算机视觉算法和技术引入浏览器环境。通过使用现代HTML5规范，我们使您能够进行实时颜色跟踪，人脸检测等
&lt;a href=&quot;https://trackingjs.com/&quot;&gt;https://trackingjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pose-animator
识别出人类的表情变化和肢体动作，并将其映射到2D矢量图型上
&lt;a href=&quot;https://github.com/yemount/pose-animator&quot;&gt;https://github.com/yemount/pose-animator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ar-cutpaste
手机上预装工具，对着目标物体拍摄，即可将图像复制粘贴进 Photoshop
&lt;a href=&quot;https://github.com/cyrildiagne/ar-cutpaste&quot;&gt;https://github.com/cyrildiagne/ar-cutpaste&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;imgcook
专注以 Sketch、PSD、静态图片等形式的视觉稿作为输入，通过智能化技术一键生成可维护的前端代码
&lt;a href=&quot;https://www.imgcook.com/&quot;&gt;https://www.imgcook.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nsfwjs
帮助快速识别不合时宜的图像
&lt;a href=&quot;https://nsfwjs.com/&quot;&gt;https://nsfwjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;编辑器&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vditor
Markdown 编辑器，支持所见即所得、即时渲染（类似 Typora）和分屏预览模式，由 TypeScript 实现，支持原生 JavaScript、Vue、React、Angular，提供桌面版
&lt;a href=&quot;https://b3log.org/vditor/&quot;&gt;https://b3log.org/vditor/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;monaco-editor
为VS Code提供支持的代码编辑器
&lt;a href=&quot;https://microsoft.github.io/monaco-editor/&quot;&gt;https://microsoft.github.io/monaco-editor/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;bytemd
用 Svelte 构建的 Markdown 编辑器组件。它也可以用于其他库/框架，例如 React、Vue 和 Angular
&lt;a href=&quot;https://bytemd.netlify.app/&quot;&gt;https://bytemd.netlify.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wangEditor
Typescript 开发的 Web 富文本编辑器， 轻量、简洁、易用、开源免费
&lt;a href=&quot;https://www.wangeditor.com/&quot;&gt;https://www.wangeditor.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;mavonEditor
Markdown 编辑器，支持多种个性化功能
&lt;a href=&quot;http://www.mavoneditor.com/&quot;&gt;http://www.mavoneditor.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;quill
API 驱动的富文本编辑器
&lt;a href=&quot;https://quilljs.com/&quot;&gt;https://quilljs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;codemirror5
浏览器内代码编辑器
&lt;a href=&quot;https://codemirror.net/&quot;&gt;https://codemirror.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;marked
用于解析 Markdown 的编译器
&lt;a href=&quot;https://marked.js.org/&quot;&gt;https://marked.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tiptap
完全控制文本编辑器体验。它是可定制的，带有大量扩展，是开源的，并且有大量的文档
&lt;a href=&quot;https://tiptap.dev/&quot;&gt;https://tiptap.dev/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2D 3D&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;dat.gui
在 JavaScript 中更改变量的轻量级图形用户界面
&lt;a href=&quot;https://github.com/dataarts/dat.gui&quot;&gt;https://github.com/dataarts/dat.gui&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Three.js
易于使用、轻量级、跨浏览器的通用 3D 库
&lt;a href=&quot;https://threejs.org/&quot;&gt;https://threejs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Draco 3D
缩和解压缩 3D 几何网格和点云。它旨在改进 3D 图形的存储和传输
&lt;a href=&quot;https://google.github.io/draco/&quot;&gt;https://google.github.io/draco/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;stats.js
JavaScript 性能监视器
&lt;a href=&quot;http://mrdoob.github.io/stats.js/&quot;&gt;http://mrdoob.github.io/stats.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;matter-js
一个用于 web 的 JavaScript 2D 物理引擎
&lt;a href=&quot;https://brm.io/matter-js/&quot;&gt;https://brm.io/matter-js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oimo.js
用于 javascript 的轻量级 3d 物理引擎，是OimoPhysics
的完整 javascript 转换
&lt;a href=&quot;http://lo-th.github.io/Oimo.js/#basic&quot;&gt;http://lo-th.github.io/Oimo.js/#basic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ammo.js
使用 Emscripten 将 Bullet 物理引擎直接移植到 JavaScript
&lt;a href=&quot;https://github.com/kripken/ammo.js&quot;&gt;https://github.com/kripken/ammo.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;其他常用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Auto.js Pro
Android上支持Node.js的JavaScript自动化和编程软件
&lt;a href=&quot;https://pro.autojs.org/&quot;&gt;https://pro.autojs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Inquirer.js
实现命令行交互式界面的工具集合
&lt;a href=&quot;https://github.com/SBoudrias/Inquirer.js/&quot;&gt;https://github.com/SBoudrias/Inquirer.js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;chalk
命令行美化工具
&lt;a href=&quot;https://github.com/chalk/chalk&quot;&gt;https://github.com/chalk/chalk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Timer.js
简单而轻量级的库，无需任何依赖项来创建和管理计时器
&lt;a href=&quot;https://github.com/husa/timer.js&quot;&gt;https://github.com/husa/timer.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;day.js
极简的 JavaScript 库，它使用与 Moment.js 兼容的 API 为现代浏览器解析、验证、操作和显示日期和时间
&lt;a href=&quot;https://day.js.org/&quot;&gt;https://day.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Socket.io
支持基于事件的实时双向通信
&lt;a href=&quot;https://socket.io/&quot;&gt;https://socket.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Algorithms
GitHub 最大的开源算法库
&lt;a href=&quot;https://the-algorithms.com/&quot;&gt;https://the-algorithms.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;log-symbols
各种日志级别的彩色符号
&lt;a href=&quot;https://github.com/sindresorhus/log-symbols&quot;&gt;https://github.com/sindresorhus/log-symbols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;plop
微型生成器框架，使整个团队可以轻松地创建具有一定一致性的文件
&lt;a href=&quot;https://plopjs.com/&quot;&gt;https://plopjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;prompts
轻量级、美观且用户友好的交互式提示
&lt;a href=&quot;https://github.com/terkelg/prompts&quot;&gt;https://github.com/terkelg/prompts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;shelljs
基于 Node.js API 的 Unix shell 命令的可移植（Windows/Linux/macOS）实现
&lt;a href=&quot;https://www.npmjs.com/package/shelljs&quot;&gt;https://www.npmjs.com/package/shelljs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;figlet
浏览器控制台个性化输出
&lt;a href=&quot;https://github.com/patorjk/figlet.js&quot;&gt;https://github.com/patorjk/figlet.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;picocolors
终端修改输出字符样式的 npm 包，比 chalk 体积小 14 倍，速度快 2 倍
&lt;a href=&quot;https://github.com/alexeyraspopov/picocolors&quot;&gt;https://github.com/alexeyraspopov/picocolors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;cac
用于构建 CLI 应用程序的 JavaScript 库，体积数倍小于 commander 和 yargs
&lt;a href=&quot;https://github.com/cacjs/cac&quot;&gt;https://github.com/cacjs/cac&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;npm-run-all
用于并行或顺序运行多个 npm 脚本的 CLI 工具
&lt;a href=&quot;https://github.com/mysticatea/npm-run-all&quot;&gt;https://github.com/mysticatea/npm-run-all&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;node-semver
语义化版本号管理的 npm 库，比如 判断一个版本是否合法，判断版本号命名是否正确，两个版本谁大谁小之类 等
&lt;a href=&quot;https://github.com/npm/node-semver&quot;&gt;https://github.com/npm/node-semver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;puppeteer
在浏览器中手动执行的大多数操作都可以使用 Puppeteer 完成
生成页面的屏幕截图和 PDF。
抓取 SPA（单页应用程序）并生成预渲染内容
自动化表单提交、UI 测试、键盘输入等。
&lt;a href=&quot;https://pptr.dev/&quot;&gt;https://pptr.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;temir
用vue组件来编写命令行界面应用的工具
&lt;a href=&quot;https://github.com/webfansplz/temir&quot;&gt;https://github.com/webfansplz/temir&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;enquirer
适用于 Node.js 的时尚、直观且用户友好的提示
&lt;a href=&quot;https://github.com/enquirer/enquirer&quot;&gt;https://github.com/enquirer/enquirer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;跨平台&lt;/h2&gt;
&lt;h3&gt;框架&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;uni-app
使用 Vue.js 开发所有前端应用的框架，开发者编写一套代码，可发布到iOS、Android、Web（响应式）、以及各种小程序等13个平台
&lt;a href=&quot;https://uniapp.dcloud.io/&quot;&gt;https://uniapp.dcloud.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;react-native
使用 React 构建移动应用程序
&lt;a href=&quot;https://reactnative.dev/&quot;&gt;https://reactnative.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Flutter
Google 的开源框架，用于构建美观、本机编译的多平台应用程序
&lt;a href=&quot;https://flutter.dev/&quot;&gt;https://flutter.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;chameleon
一套代码运行多端，一端所见即多端所见
&lt;a href=&quot;http://cml.didi.cn/&quot;&gt;http://cml.didi.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Taro
遵循 React 语法规范的多端统一开发框架
&lt;a href=&quot;https://taro.zone/&quot;&gt;https://taro.zone/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Electron
使用 JavaScript，HTML 和 CSS 构建跨平台的桌面应用程序
&lt;a href=&quot;https://www.electronjs.org/&quot;&gt;https://www.electronjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MicroApp
京东零售推出的微前端框架。基于webcomponent-like渲染，从组件思维实现微前端，旨在降低上手难度，提高工作效率
&lt;a href=&quot;https://micro-zoe.github.io/micro-app/&quot;&gt;https://micro-zoe.github.io/micro-app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tauri
使用 Web 前端构建更小、更快、更安全的桌面应用程序
&lt;a href=&quot;https://tauri.studio/&quot;&gt;https://tauri.studio/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hippy
跨平台的开发框架，旨在帮助开发者编写一次，运行在三个平台（iOS、Android 和 Web）上
&lt;a href=&quot;https://hippyjs.org/#/&quot;&gt;https://hippyjs.org/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;无界
基于 Web Components + iframe 微前端框架，具备成本低、速度快、原生隔离、功能强等一系列优点。
&lt;a href=&quot;https://wujie-micro.github.io/doc/&quot;&gt;https://wujie-micro.github.io/doc/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;qiankun
微前端的实现，基于single-spa。它旨在使构建生产就绪的微前端架构系统变得更加容易和轻松。
&lt;a href=&quot;https://qiankun.umijs.org/zh&quot;&gt;https://qiankun.umijs.org/zh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Flutter&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;pub.dev
Dart和Flutter应用程序的官方包存储库
&lt;a href=&quot;https://pub.dev/&quot;&gt;https://pub.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;awesome-flutter-plugins
尽可能收集好用的Flutter插件以便更效率的开发
&lt;a href=&quot;https://github.com/jahnli/awesome-flutter-plugins&quot;&gt;https://github.com/jahnli/awesome-flutter-plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;flutter-widget.live
使用 Flutter for web 构建的网站，用于在线实时预览小部件示例。
&lt;a href=&quot;https://flutter-widget.live/basics/introduction&quot;&gt;https://flutter-widget.live/basics/introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;google Icons
Google Material Design 图标
&lt;a href=&quot;https://fonts.google.com/icons&quot;&gt;https://fonts.google.com/icons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Json To Dart Model
Json 转 Dart Model类
&lt;a href=&quot;https://ashamp.github.io/jsonToDartModel/&quot;&gt;https://ashamp.github.io/jsonToDartModel/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;flutter awesome
很棒的列表，其中包含优秀的 Flutter 库和工具
&lt;a href=&quot;https://flutterawesome.com/&quot;&gt;https://flutterawesome.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LottieFiles
免费 Lottie 动画文件、工具和插件
&lt;a href=&quot;https://lottiefiles.com/&quot;&gt;https://lottiefiles.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Electron&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;vue-cli-plugin-electron-builde
使用Electron轻松构建用于桌面的Vue.js应用
&lt;a href=&quot;https://nklayman.github.io/vue-cli-plugin-electron-builder/&quot;&gt;https://nklayman.github.io/vue-cli-plugin-electron-builder/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;electron-about-window
为Electron 提供 “关于此应用程序” 窗口。
&lt;a href=&quot;https://github.com/rhysd/electron-about-window&quot;&gt;https://github.com/rhysd/electron-about-window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nativefier
使任何网页成为桌面应用程序
&lt;a href=&quot;https://github.com/nativefier/nativefier&quot;&gt;https://github.com/nativefier/nativefier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Uniapp&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Grace UI
兼容微信小程序及uni-app的优秀前端框架，以flex布局为基础，提供了丰富的组件及界面库GraceUI
&lt;a href=&quot;https://www.graceui.com/&quot;&gt;https://www.graceui.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;uView
全面兼容nvue的uni-app生态框架，全面的组件和便捷的工具
&lt;a href=&quot;https://www.uviewui.com/&quot;&gt;https://www.uviewui.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ThorUI
轻量、简洁、全面的移动端组件库
&lt;a href=&quot;https://thorui.cn/doc/&quot;&gt;https://thorui.cn/doc/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CSS&lt;/h2&gt;
&lt;h3&gt;动画&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;cssfx
精美简单的点击复制 CSS 效果
&lt;a href=&quot;https://cssfx.netlify.app/&quot;&gt;https://cssfx.netlify.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Twitter Hashflags
Twitter 点赞动画
&lt;a href=&quot;https://hashflags.io/&quot;&gt;https://hashflags.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UI Snippets
UI 片段的集合
&lt;a href=&quot;https://ui-snippets.dev/&quot;&gt;https://ui-snippets.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SpinKit
CSS 动画的加载指示器
&lt;a href=&quot;https://tobiasahlin.com/spinkit/&quot;&gt;https://tobiasahlin.com/spinkit/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;animate.css
强大的预设css3动画库
&lt;a href=&quot;https://animate.style/&quot;&gt;https://animate.style/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;犸良
一站式动效制作平台，通过海量的动效素材以及可视化编辑能力，帮助零基础的用户轻松完成动效制作
&lt;a href=&quot;https://design.alipay.com/emotion&quot;&gt;https://design.alipay.com/emotion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;animista
Css 动画
&lt;a href=&quot;https://animista.net/&quot;&gt;https://animista.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lordicon
功能强大的精心制作的动画图标库
&lt;a href=&quot;https://lordicon.com/&quot;&gt;https://lordicon.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;svg-spinners
24 x 24 dp的svg格式loading加载器
&lt;a href=&quot;https://github.com/n3r4zzurr0/svg-spinners&quot;&gt;https://github.com/n3r4zzurr0/svg-spinners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;magic
具有炫酷效果的 CSS3 动画
&lt;a href=&quot;https://www.minimamente.com/project/magic/&quot;&gt;https://www.minimamente.com/project/magic/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hover.css
CSS3 驱动的悬停效果，可应用于链接、按钮、徽标、SVG、特色图像等
&lt;a href=&quot;http://ianlunn.github.io/Hover/&quot;&gt;http://ianlunn.github.io/Hover/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;eva-icons
超过 480 个制作精美的开源图标。SVG、Sketch、Web 字体和动画支持
&lt;a href=&quot;https://akveo.github.io/eva-icons/#/&quot;&gt;https://akveo.github.io/eva-icons/#/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;normalize.css
CSS 重置的现代替代方案
&lt;a href=&quot;http://necolas.github.io/normalize.css/&quot;&gt;http://necolas.github.io/normalize.css/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Squoosh
对比 tinypng 有【更好的】压缩效果
&lt;a href=&quot;https://squoosh.app/&quot;&gt;https://squoosh.app/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;UI&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Manypixels
收集无版权插图的网站，提供 SVG / PNG 格式下载，并且允许更改颜色
&lt;a href=&quot;https://www.manypixels.co/gallery&quot;&gt;https://www.manypixels.co/gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;U钙网
免费的LOGO在线设计制作工具
&lt;a href=&quot;https://www.uugai.com/&quot;&gt;https://www.uugai.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;design-blocks
一组 170 多个基于 Bootstrap 的设计块，可用于创建干净的现代网站
&lt;a href=&quot;https://froala.com/design-blocks/&quot;&gt;https://froala.com/design-blocks/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;unDraw
精美的 SVG 插画集
&lt;a href=&quot;https://undraw.co/illustrations&quot;&gt;https://undraw.co/illustrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ira Design
通过调配渐变色、搭配手绘组件定制插画
&lt;a href=&quot;https://iradesign.io/gallery/illustrations&quot;&gt;https://iradesign.io/gallery/illustrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lukasz adam
免费 SVG 插画
&lt;a href=&quot;https://lukaszadam.com/illustrations&quot;&gt;https://lukaszadam.com/illustrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pixeltrue
创建令人叹为观止的项目的插图
&lt;a href=&quot;https://www.pixeltrue.com/packs&quot;&gt;https://www.pixeltrue.com/packs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;3dicons
3d图标库
&lt;a href=&quot;https://3dicons.co/&quot;&gt;https://3dicons.co/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;css-buttons
100 个现代 CSS 按钮
&lt;a href=&quot;https://css-buttons.web.app/&quot;&gt;https://css-buttons.web.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;uiset
优质免费的UI设计资源
&lt;a href=&quot;https://uiset.com/&quot;&gt;https://uiset.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;error404
404插画页面
&lt;a href=&quot;https://error404.fun/&quot;&gt;https://error404.fun/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ui8
5,745 个精选设计资源，为您的创意工作流程注入活力
&lt;a href=&quot;https://ui8.net/&quot;&gt;https://ui8.net/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;编程工具&lt;/h2&gt;
&lt;h3&gt;代码工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;gitignore.io
为项目创建有用的 .gitignore 文件
&lt;a href=&quot;https://www.toptal.com/developers/gitignore&quot;&gt;https://www.toptal.com/developers/gitignore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;any-rule
常用正则大全, 支持web / vscode / idea / Alfred Workflow多平台
&lt;a href=&quot;https://any86.github.io/any-rule/&quot;&gt;https://any86.github.io/any-rule/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;30-seconds-of-code
满足多种语言开发需求的简短代码片段
&lt;a href=&quot;https://www.30secondsofcode.org/&quot;&gt;https://www.30secondsofcode.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github-readme-stats
为 github 自述文件动态生成的统计信息
&lt;a href=&quot;https://github.com/anuraghazra/github-readme-stats&quot;&gt;https://github.com/anuraghazra/github-readme-stats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;cz-cli
规范提交说明的git工具
&lt;a href=&quot;http://commitizen.github.io/cz-cli/&quot;&gt;http://commitizen.github.io/cz-cli/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;commitlint
git commit 校验工具
&lt;a href=&quot;https://commitlint.js.org/#/&quot;&gt;https://commitlint.js.org/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;husky
Git hooks 工具，可以防止使用 Git hooks 的一些不好的 commit 或者 push
&lt;a href=&quot;https://typicode.github.io/husky/#/&quot;&gt;https://typicode.github.io/husky/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lint-staged
代码提交之前,进行代码规则检查并尝试修复，能够确保进入git库的代码都是符合代码规则
&lt;a href=&quot;https://github.com/okonet/lint-staged&quot;&gt;https://github.com/okonet/lint-staged&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;anywhere
随启随用的静态文件服务器
&lt;a href=&quot;https://github.com/JacksonTian/anywhere&quot;&gt;https://github.com/JacksonTian/anywhere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;code996
统计 Git 项目的 commit 时间分布，进而推导出这个项目的编码工作强度
&lt;a href=&quot;https://hellodigua.github.io/code996/#/&quot;&gt;https://hellodigua.github.io/code996/#/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;图像工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;bigjpg
使用度卷积神经网络。它会将噪点和锯齿的部分进行补充，实现图片的无损放大
&lt;a href=&quot;https://bigjpg.com/&quot;&gt;https://bigjpg.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;jpghd
使用人工智能 AI 超分模型和深度学习技术来将低清破损有噪点图片处理成高画质高分辨率图片同时支持破损老照片修复和老照片上色
&lt;a href=&quot;https://jpghd.com/&quot;&gt;https://jpghd.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;bigmp4
使用智能 AI 模型，能将视频无损高清放大、增强画质、智能补帧使画面丝滑流畅栩栩如生同时支持黑白视频上色和慢动作
&lt;a href=&quot;https://bigmp4.com/&quot;&gt;https://bigmp4.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;imglarger
基于强大的机器学习可在不降低质量的情况下提高图像分辨率
&lt;a href=&quot;https://imglarger.com/&quot;&gt;https://imglarger.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;unscreen
智能AI去除视频背景在线神器
&lt;a href=&quot;https://www.unscreen.com/&quot;&gt;https://www.unscreen.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;阿里妈妈创意中心
阿里智能文案，智能抠图工具
&lt;a href=&quot;https://chuangyi.taobao.com/&quot;&gt;https://chuangyi.taobao.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;文件转换&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ALL TO ALL
全类型的在线文件转换平台，免费、快速，无须下载安装任何软件
&lt;a href=&quot;https://www.alltoall.net/&quot;&gt;https://www.alltoall.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Convertio
将文件转换成任意格式
&lt;a href=&quot;https://convertio.co/zh/&quot;&gt;https://convertio.co/zh/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Vue3生态工具&lt;/h2&gt;
&lt;h3&gt;1.Web UI库&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ElementUI Plus
一套为开发者、设计师和产品经理准备的基于 Vue 3.0 的桌面端组件库
&lt;a href=&quot;https://element-plus.org/zh-CN/&quot;&gt;https://element-plus.org/zh-CN/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ant Design of Vue
Ant Design 的 Vue 实现，开发和服务于企业级后台产品
&lt;a href=&quot;https://www.antdv.com/docs/vue/introduce-cn&quot;&gt;https://www.antdv.com/docs/vue/introduce-cn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;BalmUI
基于谷歌的 Material Design，附带 Vue 插件和指令，以及从简单到复杂的高度可定制组件
&lt;a href=&quot;https://next-material.balmjs.com/&quot;&gt;https://next-material.balmjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Naive UI
图森Vue3的组件库，文档完整，我项目中经常使用
&lt;a href=&quot;https://www.naiveui.com/zh-CN/os-theme&quot;&gt;https://www.naiveui.com/zh-CN/os-theme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;arco.design
字节跳动企业级产品设计系统，支持React和Vue双版本
&lt;a href=&quot;https://arco.design/&quot;&gt;https://arco.design/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Quasar
轻松构建高性能和高质量的Vue.js 3用户界面，好用，但没有中文文档
&lt;a href=&quot;https://quasar.dev/&quot;&gt;https://quasar.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;iDUX
Vue3.x 的 UI 组件库，完全使用 TypeScript 开发
&lt;a href=&quot;https://idux.site/&quot;&gt;https://idux.site/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TDesign
腾讯业务团队在服务业务过程中沉淀的一套企业级设计体系
&lt;a href=&quot;https://tdesign.tencent.com/&quot;&gt;https://tdesign.tencent.com/&lt;/a&gt;
&lt;a href=&quot;https://tdesign.tencent.com/vue-next/overview&quot;&gt;https://tdesign.tencent.com/vue-next/overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PrimeVue
易于使用、多功能、高性能的 Vue UI 组件库
&lt;a href=&quot;https://www.primefaces.org/primevue/&quot;&gt;https://www.primefaces.org/primevue/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DevUI
华为基于 Vue3 和 DevUI 设计的 UI 组件
&lt;a href=&quot;https://vue-devui.github.io/&quot;&gt;https://vue-devui.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vuestic-ui
Vue 3 的免费和开源 UI 库 ,UI非常好看，并且有可用后台管理界面。
&lt;a href=&quot;https://vuestic.dev/&quot;&gt;https://vuestic.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Headless UI
完全无样式、完全可访问的 UI 组件，旨在与 Tailwind CSS 完美集成。
&lt;a href=&quot;https://headlessui.com/&quot;&gt;https://headlessui.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;View UI Plus
基于 Vue.js 3 的企业级 UI 组件库和前端解决方案
&lt;a href=&quot;https://www.iviewui.com/&quot;&gt;https://www.iviewui.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.移动UI库&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vant
有赞轻量、可靠的移动端组件库
&lt;a href=&quot;https://vant-contrib.gitee.io/vant/#/zh-CN&quot;&gt;https://vant-contrib.gitee.io/vant/#/zh-CN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NutUI
京东风格的轻量级移动端 Vue 组件库，非常适合移动端电商使用。
&lt;a href=&quot;https://nutui.jd.com/#/&quot;&gt;https://nutui.jd.com/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Varlet
Material 风格移动端组件库 ，文档非常齐全。
&lt;a href=&quot;https://varlet.gitee.io/varlet-ui/#/zh-CN/home&quot;&gt;https://varlet.gitee.io/varlet-ui/#/zh-CN/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nutui-bingo
京东基于 NutUI 的抽奖组件库，助力营销活动和小游戏场景。
&lt;a href=&quot;https://nutui.jd.com/bingo/#/&quot;&gt;https://nutui.jd.com/bingo/#/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.相关工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;unplugin-vue-components
antfu 按需组件自动导入，开箱即用地支持 Vue 2 和 Vue 3，Tree-shakable，只注册你使用的组件，附有流行UI 库的内置解析器。
&lt;a href=&quot;https://www.npmjs.com/package/unplugin-vue-components&quot;&gt;https://www.npmjs.com/package/unplugin-vue-components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vuex-persistedstate
在页面重新加载之间保持并重载您的 Vuex 状态
&lt;a href=&quot;https://github.com/robinvdvleuten/vuex-persistedstate&quot;&gt;https://github.com/robinvdvleuten/vuex-persistedstate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vuex-persist
支持 Typescript 的Vuex插件，它能够将应用程序的状态保存到持久存储中，例如 Cookies 或 localStorage
&lt;a href=&quot;https://championswimmer.in/vuex-persist/&quot;&gt;https://championswimmer.in/vuex-persist/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;@vueuse/gesture
手势库，使应用程序具有交互性
&lt;a href=&quot;https://gesture.vueuse.org/&quot;&gt;https://gesture.vueuse.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;unplugin-auto-import
antfu 自动导入 Vite、Webpack、Rollup 和 esbuild 的 API。支持 TypeScript。
&lt;a href=&quot;https://github.com/antfu/unplugin-auto-import&quot;&gt;https://github.com/antfu/unplugin-auto-import&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;pinia-plugin-persistedstate
Pinia 商店的可配置持久性
&lt;a href=&quot;https://github.com/prazdevs/pinia-plugin-persistedstate&quot;&gt;https://github.com/prazdevs/pinia-plugin-persistedstate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vue-termui.dev/&quot;&gt;https://vue-termui.dev/&lt;/a&gt;
一个基于 Vue.js 的终端 UI 框架，可让您轻松构建现代终端应用程序
&lt;a href=&quot;https://vue-termui.dev/&quot;&gt;https://vue-termui.dev/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.可视化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pdfvuer
DF 查看器，使用 Mozilla 的 PDF.js，支持 Vue2 和 Vue3
&lt;a href=&quot;https://arkokoley.github.io/pdfvuer/&quot;&gt;https://arkokoley.github.io/pdfvuer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue3-marquee
无缝滚动组件
&lt;a href=&quot;https://vue3-marquee.vercel.app/&quot;&gt;https://vue3-marquee.vercel.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vue-ECharts
百度ECharts 的 Vue.js 组件。 配置参考Echarts官方 基于 ECharts v5+ 开发，适用于Vue.js 2/3。
&lt;a href=&quot;https://vue-echarts.dev/&quot;&gt;https://vue-echarts.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;iconpark
字节跳动出品，将一个SVG图标转化为多个主题，并生成React图标，Vue图标，svg图标
&lt;a href=&quot;https://iconpark.oceanengine.com/home&quot;&gt;https://iconpark.oceanengine.com/home&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;vue-multiselect-next
Vue.js 的通用选择/多选/标记组件
&lt;a href=&quot;https://vue-multiselect.js.org/&quot;&gt;https://vue-multiselect.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue-print-nb
用于印刷、简单、快速、方便、轻便的指令包装器
&lt;a href=&quot;https://github.com/Power-kxLee/vue-print-nb&quot;&gt;https://github.com/Power-kxLee/vue-print-nb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue-i18n-next
Vue3的国际化插件
&lt;a href=&quot;https://vue-i18n.intlify.dev/&quot;&gt;https://vue-i18n.intlify.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue-cropper
简单的vue图片裁剪插件
&lt;a href=&quot;http://github.xyxiao.cn/vue-cropper/example/&quot;&gt;http://github.xyxiao.cn/vue-cropper/example/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Grid Layout
Vue.js 的网格布局系统
&lt;a href=&quot;https://jbaysolutions.github.io/&quot;&gt;https://jbaysolutions.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vue Qrcode Reader
允许在不离开浏览器的情况下检测和解码二维码
&lt;a href=&quot;https://gruhn.github.io/vue-qrcode-reader/&quot;&gt;https://gruhn.github.io/vue-qrcode-reader/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Makeit Captcha
基于 Vue3 + Vite + Canvas 开发的滑块验证码，动态生成验证滑块，结合后端的二次校验，能有效的避免被抓取模拟验证&lt;a href=&quot;https://admin.makeit.vip/components/captcha&quot;&gt;https://admin.makeit.vip/components/captcha&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue3-clipboard
Vue 3 的 clipboard.js
&lt;a href=&quot;https://github.com/soerenmartius/vue3-clipboard&quot;&gt;https://github.com/soerenmartius/vue3-clipboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vue.draggable
基于Sortable.js的Vue 3拖放组件
&lt;a href=&quot;https://sortablejs.github.io/vue.draggable.next/#/simple&quot;&gt;https://sortablejs.github.io/vue.draggable.next/#/simple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;BetterScroll
解决移动端（已支持 PC）各种滚动场景需求的插件。
&lt;a href=&quot;https://better-scroll.github.io/docs/zh-CN/&quot;&gt;https://better-scroll.github.io/docs/zh-CN/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.相关生态&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vue 插件库
&lt;a href=&quot;https://www.vue365.cn/&quot;&gt;https://www.vue365.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pinia
轻量级状态管理库，API 设计更接近Vuex 5的提案
&lt;a href=&quot;https://pinia.vuejs.org/&quot;&gt;https://pinia.vuejs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nuxt Modules
Nuxt 发现我们的模块列表以增强您的Nuxt 项目
&lt;a href=&quot;https://modules.nuxtjs.org/&quot;&gt;https://modules.nuxtjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nuxt 3
轻量级应用框架,可用来创建服务端渲染 (SSR) 应用
&lt;a href=&quot;https://v3.nuxtjs.org/&quot;&gt;https://v3.nuxtjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vuepress
Vue 驱动的静态网站生成器
&lt;a href=&quot;https://v2.vuepress.vuejs.org/zh/&quot;&gt;https://v2.vuepress.vuejs.org/zh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;VueUse
强大的 Vue 组合实用程序集合
&lt;a href=&quot;https://vueuse.org/&quot;&gt;https://vueuse.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7.动画&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;vue-starport
带有动画的跨路由共享组件
&lt;a href=&quot;https://vue-starport.netlify.app/&quot;&gt;https://vue-starport.netlify.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;@vueuse/motion
Vue Composables 让你的组件动起来
&lt;a href=&quot;https://motion.vueuse.org/&quot;&gt;https://motion.vueuse.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;8.音视频&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;@vueuse/sound
用于播放音效的 Vue 组合
&lt;a href=&quot;https://sound.vueuse.org/&quot;&gt;https://sound.vueuse.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;全栈-后端&lt;/h2&gt;
&lt;h3&gt;插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;isomorphic-git
用于节点和浏览器的 git 纯 JavaScript 实现
&lt;a href=&quot;https://isomorphic-git.org/&quot;&gt;https://isomorphic-git.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;jsonwebtoken
node.js 的 JsonWebToken 实现
&lt;a href=&quot;https://github.com/auth0/node-jsonwebtoken&quot;&gt;https://github.com/auth0/node-jsonwebtoken&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Qiniu SDK
七牛资源（云）存储 SDK for Node.js
&lt;a href=&quot;https://developer.qiniu.com/kodo/sdk/nodejs&quot;&gt;https://developer.qiniu.com/kodo/sdk/nodejs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa-body
功能齐全的koa正文解析器中间件，支持multipart、urlencoded和json请求正文，提供与 Express 的 bodyParser 相同的功能
&lt;a href=&quot;https://github.com/koajs/koa-body&quot;&gt;https://github.com/koajs/koa-body&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa-json-error
纯Koa JSON 应用程序的错误处理程序，显示堆栈跟踪
&lt;a href=&quot;https://github.com/koajs/json-error&quot;&gt;https://github.com/koajs/json-error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa-jwt
用于验证 JSON Web 令牌的 Koa 中间件
&lt;a href=&quot;https://github.com/koajs/jwt&quot;&gt;https://github.com/koajs/jwt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa-router
Koa 的路由器中间件
&lt;a href=&quot;https://github.com/koajs/router&quot;&gt;https://github.com/koajs/router&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa2-cors
koa2 的 CORS 中间件
&lt;a href=&quot;https://github.com/zadzbw/koa2-cors&quot;&gt;https://github.com/zadzbw/koa2-cors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;koa-sslify
为 Koa.js 实施 HTTPS 中间件
&lt;a href=&quot;https://github.com/turboMaCk/koa-sslify&quot;&gt;https://github.com/turboMaCk/koa-sslify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;superagent-proxy
允许您通过某种代理来代理 HTTP 请求
&lt;a href=&quot;https://github.com/TooTallNate/superagent-proxy&quot;&gt;https://github.com/TooTallNate/superagent-proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;node-http-proxy-agen
HTTP 端点的 HTTP(s) 代理“http.Agent”实现
&lt;a href=&quot;https://github.com/TooTallNate/node-http-proxy-agent&quot;&gt;https://github.com/TooTallNate/node-http-proxy-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;https-proxy-agent
HTTPS 端点的 HTTP(s) 代理“http.Agent”实现
&lt;a href=&quot;https://github.com/TooTallNate/node-https-proxy-agent&quot;&gt;https://github.com/TooTallNate/node-https-proxy-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;socks-proxy-agent
用于 HTTP 和 HTTPS 的 SOCKS (v4/v5) 代理“http.Agent”实现
&lt;a href=&quot;https://github.com/TooTallNate/node-socks-proxy-agent&quot;&gt;https://github.com/TooTallNate/node-socks-proxy-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;simple-get
发出 http get 请求的最简单方法。支持 HTTPS、重定向、gzip/deflate、小于 100 行的流
&lt;a href=&quot;https://github.com/feross/simple-get&quot;&gt;https://github.com/feross/simple-get&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;commander.js
node.js命令行界面的完整解决方案
&lt;a href=&quot;https://github.com/tj/commander.js&quot;&gt;https://github.com/tj/commander.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ora
命令行 loading 动效
&lt;a href=&quot;https://github.com/sindresorhus/ora&quot;&gt;https://github.com/sindresorhus/ora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;dotenv
从 .env 为 nodejs 项目加载环境变量
&lt;a href=&quot;https://github.com/motdotla/dotenv&quot;&gt;https://github.com/motdotla/dotenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;FFCreator
基于node.js的高速视频制作库
&lt;a href=&quot;https://tnfe.github.io/FFCreator/#/&quot;&gt;https://tnfe.github.io/FFCreator/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;sharp
高性能 Node.js 图像处理，调整 JPEG、PNG、WebP、AVIF 和 TIFF 图像大小的最快模块
&lt;a href=&quot;https://sharp.pixelplumbing.com/&quot;&gt;https://sharp.pixelplumbing.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;node-fs-extra
强大的文件操作库， 是 Nodejs fs 模块 的增强版
&lt;a href=&quot;https://github.com/jprichardson/node-fs-extra&quot;&gt;https://github.com/jprichardson/node-fs-extra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;chokidar
用于文件监控的库，解决兼容性不好、无法监听、监听多次 等大量影响性能的问题
&lt;a href=&quot;https://paulmillr.com/&quot;&gt;https://paulmillr.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;fast-glob
快速批量导入、读取文件的库
&lt;a href=&quot;https://github.com/mrmlnc/fast-glob&quot;&gt;https://github.com/mrmlnc/fast-glob&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;peerflix
node.js 的流式 torrent 客户端
&lt;a href=&quot;https://github.com/mafintosh/peerflix&quot;&gt;https://github.com/mafintosh/peerflix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Nginx
高性能的HTTP和反向代理web服务器，同时也提供了IMAP/POP3/SMTP服务
&lt;a href=&quot;https://blog.redis.com.cn/doc/&quot;&gt;https://blog.redis.com.cn/doc/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PM2
Node进程管理工具，如性能监控、自动重启、负载均衡等
&lt;a href=&quot;https://pm2.keymetrics.io/docs/usage/process-management/&quot;&gt;https://pm2.keymetrics.io/docs/usage/process-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nodemon
监视 node.js 应用程序中的任何更改并自动重新启动服务器
&lt;a href=&quot;https://nodemon.io/&quot;&gt;https://nodemon.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RobotJS
Node.js 桌面自动化，控制鼠标、键盘和阅读屏幕等
&lt;a href=&quot;http://robotjs.io/&quot;&gt;http://robotjs.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jenkins
领先的开源自动化服务器，Jenkins 提供了数百个插件来支持构建、部署和自动化任何项目
&lt;a href=&quot;https://www.jenkins.io/&quot;&gt;https://www.jenkins.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nexe
将 node.js 应用程序中创建一个可执行文件
&lt;a href=&quot;https://github.com/nexe/nexe&quot;&gt;https://github.com/nexe/nexe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;debug
模仿 Node.js 核心调试技术的小型 JavaScript 调试实用程序。适用于 Node.js 和 Web 浏览器
&lt;a href=&quot;https://github.com/debug-js/debug&quot;&gt;https://github.com/debug-js/debug&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;数据库&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;mongoose
旨在在异步环境中工作的 MongoDB 对象建模
&lt;a href=&quot;https://mongoosejs.com/&quot;&gt;https://mongoosejs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GraphQL
用于 API 的查询语言也是一个满足你数据查询的运行时
&lt;a href=&quot;https://graphql.cn/&quot;&gt;https://graphql.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lowdb数据库
适用于Node，Electron和浏览器的小型JSON数据库。由Lodash驱动
&lt;a href=&quot;https://github.com/typicode/lowdb&quot;&gt;https://github.com/typicode/lowdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nedb
适用于Node.js，nw.js，Electron和浏览器的嵌入式持久性数据库或内存数据库,API是MongoDB的子集
&lt;a href=&quot;https://github.com/louischatriot/nedb&quot;&gt;https://github.com/louischatriot/nedb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;API&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;网易云音乐 API
全部接口已升级到最新，具备登录接口,多达200多个接口
&lt;a href=&quot;https://binaryify.github.io/NeteaseCloudMusicApi/#/&quot;&gt;https://binaryify.github.io/NeteaseCloudMusicApi/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node-SpliderApi
基于 Node+Express 网络爬虫 API 接口 包括前端开发日报、kugou 音乐、前端 top 框架排行、妹纸福利、搞笑视频、段子笑话、各类视频新闻资讯 热点详情接口数据,接口数据更新目标
&lt;a href=&quot;https://ecitlm.github.io/Node-SpliderApi/&quot;&gt;https://ecitlm.github.io/Node-SpliderApi/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;聚合数据
免费向开发者提供全国车辆违章查询API,天气API,基站数据,移动联通基站,电信基站,覆盖国内外1000多个主要城市公共交通信息数据
&lt;a href=&quot;https://www.juhe.cn/&quot;&gt;https://www.juhe.cn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;极速数据
提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台
&lt;a href=&quot;https://www.jisuapi.com/&quot;&gt;https://www.jisuapi.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;京东万象
供金融、电商、运营商数据,免费数据,热门数据,学籍数据,企业诉讼数据,实名认证,征信数据,质检等多种数据
&lt;a href=&quot;https://wx.jdcloud.com/api&quot;&gt;https://wx.jdcloud.com/api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;QQ音乐API
通过Web网页版请求QQ音乐接口数据
&lt;a href=&quot;https://rain120.github.io/qq-music-api/#/&quot;&gt;https://rain120.github.io/qq-music-api/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;万维易源
一站式全网API调用平台
&lt;a href=&quot;https://www.showapi.com/&quot;&gt;https://www.showapi.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TP5 Splider Api
基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api
&lt;a href=&quot;https://ecitlm.github.io/TP5_Splider/#/&quot;&gt;https://ecitlm.github.io/TP5_Splider/#/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Roll API
提供开发中常用数据的一个稳定聚合Api接口
&lt;a href=&quot;https://www.mxnzp.com/doc/list&quot;&gt;https://www.mxnzp.com/doc/list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open API
收集可用的Open APIs
&lt;a href=&quot;https://www.wanandroid.com/openapis&quot;&gt;https://www.wanandroid.com/openapis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;天行数据
160多个免费接口，接口高度统一，简单易用，毫秒级响应
&lt;a href=&quot;https://www.tianapi.com/&quot;&gt;https://www.tianapi.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;free-api
免费API,收集免费的接口服务
&lt;a href=&quot;https://www.free-api.com/&quot;&gt;https://www.free-api.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;douban-imdb-api
基于豆瓣、IMDB、烂番茄评分的电影电视剧双语(中英)数据api接口
&lt;a href=&quot;https://www.iqi360.com/p/douban-imdb-api&quot;&gt;https://www.iqi360.com/p/douban-imdb-api&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;框架&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Koa
基于 Node.js 平台的下一代 web 开发框架
&lt;a href=&quot;https://koajs.com/&quot;&gt;https://koajs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Express
用于Node.js 的快速、独立、简约的 Web 框架
&lt;a href=&quot;https://expressjs.com/&quot;&gt;https://expressjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;egg.js
为企业级框架和应用而生
&lt;a href=&quot;https://www.eggjs.org/&quot;&gt;https://www.eggjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nest.js
构建高效且可扩展的服务器端应用程序的渐进式Node.js框架
&lt;a href=&quot;https://nestjs.com/&quot;&gt;https://nestjs.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>关于Memos</title><link>https://barry.ee/writing/memos/</link><guid isPermaLink="true">https://barry.ee/writing/memos/</guid><description>总结关于目前Memos的一些用法</description><pubDate>Sun, 26 Mar 2023 11:34:14 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;我从接触独立博客开始，就一直在博客的子栏目中部署了一个类似 &lt;a href=&quot;https://www.barry.ee/personal/digu/&quot;&gt;嘀咕&lt;/a&gt; 的微博客。
最初的作用是备份 QQ 空间、Twitter 和朋友圈等。
可是慢慢发现，不知道为什么自己在这些社交媒体的分享欲变得越来越弱，只想有一个地方来记录我平时的一些想法，于是有了嘀咕。&lt;/p&gt;
&lt;p&gt;现在在独立博客圈少部博主中流行的这种“B 言 B 语”，最早来源于少数派上的一篇文章——&lt;a href=&quot;https://sspai.com/post/60024&quot;&gt;《保卫表达：用后端 BaaS 快速搭建专属无点赞评论版微博——b 言 b 语》&lt;/a&gt;，“B 言 B 语”也叫“废话胶囊”。&lt;/p&gt;
&lt;p&gt;由此也衍生出了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/daibor/nonsense.fun&quot;&gt;LeanCloud 版&lt;/a&gt;（原版）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/songquanpeng/microblog&quot;&gt;Golang 版&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ibearye/talk&quot;&gt;腾讯云 CloudBase 版&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://immmmm.com/bb-by-wechat-pro/&quot;&gt;木木老师修改版&lt;/a&gt; 《「哔哔点啥」微信公众号 2.0》&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BBtalkJS/BBtalk&quot;&gt;BBTalk&lt;/a&gt;Vercel 版&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前以上版本均可使用，不过可能有些版本的使用成本有点高。&lt;/p&gt;
&lt;p&gt;今天要介绍的是另一个能提供类似功能的应用——&lt;a href=&quot;https://github.com/usememos/memos&quot;&gt;Memos&lt;/a&gt;
Memos 自己对标的竞品是 Flomo ，我们是不是把它用歪了？&lt;/p&gt;
&lt;h2&gt;部署 Memos&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;前置条件：1.一台 VPS 服务器或本地电脑（或 Docker SaaS 平台）2.一点点 WebStack 技能（Docker、Nginx）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;安装&lt;code&gt;docker-compose-plugin&lt;/code&gt;插件后，&lt;code&gt;docker compose&lt;/code&gt;命令可以去掉中间的&amp;quot;&lt;code&gt;-&lt;/code&gt;&amp;quot;，Docker Compose V1 版本已经结束生命周期。&lt;/p&gt;
&lt;p&gt;暂时不建议把 Memos 部署到网站二级目录，如：&lt;a href=&quot;https://example.com/memos&quot;&gt;https://example.com/memos&lt;/a&gt;
而应该部署到一个二级域名，如：&lt;a href=&quot;https://memos.example.com/&quot;&gt;https://memos.example.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;新建 &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;
一般在准备用于 Memos 的域名的目录下新建 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /www/wwwroot/memos.example.com
vim docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;version: &amp;#39;3.0&amp;#39;
services:
  memos:
    image: neosmemo/memos
    container_name: memos
    volumes:
      - ./memos/:/var/opt/memos
    ports:
      - 5230:5230
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.&lt;strong&gt;启动 Memos&lt;/strong&gt;
启动 Memos&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等待镜像拉取完成，Memos 就运行在服务器的&lt;code&gt;5230&lt;/code&gt;端口了。
此时，打开&lt;code&gt;http://127.0.0.1:5230&lt;/code&gt;就能访问 Memos 了。
如果有公网 IP，那就打开&lt;code&gt;IP&lt;/code&gt;+&lt;code&gt;端口&lt;/code&gt;，如： &lt;code&gt;http://119.29.29.29:5230&lt;/code&gt; 。
用域名反代 IP 见下文第 4 点。
常用的命令有：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose up -d
docker compose down
docker compose pull
docker compose up -d --force-recreate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.&lt;strong&gt;升级 Memos&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Memos 官方提供的升级命令&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose down &amp;amp;&amp;amp; docker image rm neosmemo/memos:latest &amp;amp;&amp;amp; docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会导致 Memos 在升级期间掉线，因为 &lt;code&gt;down&lt;/code&gt; 了，特别是境内服务器网速不好的情况下，掉线时间会随着 &lt;code&gt;pull&lt;/code&gt; 时间无限延长。&lt;/p&gt;
&lt;p&gt;最新版 Docker 升级 Memos 的命令有改进空间：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker compose pull &amp;amp;&amp;amp; docker compose up -d --force-recreate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是如果用了镜像加速服务，因为缓存的原因也可能有 &lt;code&gt;pull&lt;/code&gt; 不到最新镜像的问题。&lt;/p&gt;
&lt;p&gt;4.&lt;strong&gt;Nginx 反代&lt;/strong&gt;
如果打算对互联网提供 Memos 访问服务，就需要反代 Memos，一般都是用 Nginx，反代&lt;code&gt;5230&lt;/code&gt;端口即可。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;location ^~ /
{
proxy_pass http://127.0.0.1:5230;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
add_header X-Cache $upstream_cache_status;
# cache
add_header Cache-Control no-cache;
expires 12h;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一些主机管理面板或者 NPM 反代面板提供可视化反代设置，那更简单。&lt;/p&gt;
&lt;p&gt;5.&lt;strong&gt;备份数据&lt;/strong&gt;
在第 1 步中的&lt;code&gt;docker-compose.yml&lt;/code&gt;文件中，&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;volumes:
  - ./memos/:/var/opt/memos
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段就是数据持久化配置，如果不做数据持久化，Docker 容器重启后，所有 Memos 都会消失。
“&lt;code&gt;:&lt;/code&gt;”冒号前面的内容是物理宿主机上的目录，例子中对应的目录为：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;/www/wwwroot/memos.example.com/memos
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要备份的数据是此目录下的&lt;code&gt;memos_prod.db&lt;/code&gt;文件，是一个 SQLite 数据库文件，Memos 的所有设置、用户信息、附件和 Memos 都保存在这个文件中。
官方提供的示例中，数据卷为家目录&lt;code&gt;/home/username&lt;/code&gt;下的&lt;code&gt;.memos&lt;/code&gt;目录，是一个隐藏目录，注意对比。&lt;/p&gt;
&lt;h2&gt;Memos 美化代码&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/pdjv28-0.webp&quot; alt=&quot;效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;调用 Bing 每日背景&lt;/h3&gt;
&lt;p&gt;适配 &lt;code&gt;v0.11.2&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;html {
  background-image: url(&amp;#39;https://bing.immmmm.com/img/bing?region=zh-CN&amp;amp;type=image&amp;#39;);
  width: 100%;
  height: 100vh;
  background-position: center;
  background-size: cover;
  background-attachment: fixed;
}
.w-full.bg-zinc-100,
.bg-white,
.hover\:bg-white:hover,
.dark .dark\:bg-zinc-700,
.dark .dark\:hover\:bg-zinc-700:hover,
.memo-wrapper,
.bg-gray-200,
.dark .memo-wrapper,
.memo-editor-container {
  --tw-bg-opacity: 0.66 !important;
}
.dark header.dark\:bg-zinc-800,
aside.dark\:bg-zinc-800,
.bg-gray-100,
.dark html,
.dark body {
  --tw-bg-opacity: 0 !important;
}
.memo-editor-container &amp;gt; .memo-editor {
  background-color: transparent !important;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加送界面细节微调：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.status-text {
  font-size: 10px !important;
  border: none;
  color: rgb(156, 163, 175) !important;
}
.tag-span,
.dark .tag-span {
  border: 1px solid;
  border-radius: 6px;
  padding: 0px 6px;
  color: rgb(22, 163, 74) !important;
  font-size: 12px !important;
  -webkit-transform: scale(calc(10 / 12));
  transform-origin: left center;
}
.memo-content-text .link {
  color: rgb(22, 163, 74) !important;
  margin-right: -6px;
}
header .bg-blue-600 {
  display: none !important;
}
.text-lg {
  font-size: 1rem !important;
}
.header-wrapper,
.sidebar-wrapper {
  width: 11rem !important;
}
.filter-query-container {
  padding-bottom: 0.5rem;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;加载「霞鹜文楷」在线字体&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;body {
  font-family: &amp;#39;LXGW WenKai Screen&amp;#39;, sans-serif !important;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function changeFont() {
  const link = document.createElement(&amp;#39;link&amp;#39;)
  link.rel = &amp;#39;stylesheet&amp;#39;
  link.type = &amp;#39;text/css&amp;#39;
  link.href = &amp;#39;https://cdn.staticfile.org/lxgw-wenkai-screen-webfont/1.6.0/lxgwwenkaiscreen.css&amp;#39;
  document.head.append(link)
};
changeFont()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Hexo 博客嵌入&lt;/h2&gt;
&lt;p&gt;懒得搬过来了
参考链接:
&lt;a href=&quot;https://blog.leonus.cn/2023/memeos.html&quot;&gt;基于Memos实现说说和清单功能。 | Leonus&lt;/a&gt;
&lt;a href=&quot;https://blog.leonus.cn/2023/photos.html&quot;&gt;基于memos实现动态相册 | Leonus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可能大家需要自行适配一下自己的博客，相信以大家的聪明才智肯定没问题的啦。&lt;/p&gt;
&lt;h2&gt;Memos Awesome&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://memos.top/&quot;&gt;https://memos.top&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Discuss in &lt;a href=&quot;https://t.me/+-_tNF1k70UU4ZTc9&quot;&gt;Telegram&lt;/a&gt; 👾&lt;/li&gt;
&lt;li&gt;Docker Hub：&lt;a href=&quot;https://hub.docker.com/r/neosmemo/memos&quot;&gt;https://hub.docker.com/r/neosmemo/memos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker Hub Nightly：&lt;a href=&quot;https://hub.docker.com/r/eallion/memos&quot;&gt;https://hub.docker.com/r/eallion/memos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Moe Memos 客户端：&lt;a href=&quot;https://memos.moe/&quot;&gt;https://memos.moe/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Memos-bber Chrome 扩展：&lt;a href=&quot;https://github.com/lmm214/memos-bber&quot;&gt;https://github.com/lmm214/memos-bber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Memos 微信小程序：&lt;a href=&quot;https://github.com/Rabithua/memos_wmp&quot;&gt;https://github.com/Rabithua/memos_wmp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Telegram Bot：&lt;a href=&quot;https://github.com/qazxcdswe123/telegramMemoBot&quot;&gt;https://github.com/qazxcdswe123/telegramMemoBot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://immmmm.com/bbs-by-memos/&quot;&gt;哔哔广场&lt;/a&gt;：&lt;a href=&quot;https://immmmm.com/bbs/&quot;&gt;https://immmmm.com/bbs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/usememos/memos/discussions/315&quot;&gt;「分享」Android 使用 HTTP Shortcuts 录入笔记&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/usememos/memos/discussions/52&quot;&gt;「分享」使用 iOS 快捷指令录入笔记，支持多图上传，支持标签选择&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/usememos/memos/discussions/451&quot;&gt;「分享」在 Fly.io 平台上搭建 memos 并自动备份到 B2/S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://immmmm.com/memos-api-description/&quot;&gt;Memos API 非官方不完全说明：：木木木木木 (immmmm.com)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://memosweb.yct.ee/&quot;&gt;Memos Web (yct.ee)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Quorafind/Obsidian-Memos&quot;&gt;Obsidian-Memos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Some Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;发图尽量把图片传到第三方图床，（至少近期版本）别上传到 Memos 资源库。&lt;/li&gt;
&lt;li&gt;附件也一样别传到 Memos 资源库，可以传到第三方网盘，贴上分享链接。&lt;/li&gt;
&lt;li&gt;备份&lt;code&gt;memos_prod.db&lt;/code&gt;数据库遵循两地三中心原则，多处备份，且是单向的。&lt;/li&gt;
&lt;li&gt;如果你意识不到数据对你有多珍贵或重要，用 SaaS 服务即可，不用自建。&lt;/li&gt;
&lt;li&gt;没有那么多人来看你的 Memos，自娱自乐即可。&lt;/li&gt;
&lt;li&gt;如果要用 Memos 里的 Ask AI 可通过&lt;a href=&quot;https://github.com/noobnooc/noobnooc/discussions/9&quot;&gt;自建 OpenAI API Host&lt;/a&gt; 在墙内使用。&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>People Die, but Long Live GitHub</title><link>https://barry.ee/writing/githubneverdie/</link><guid isPermaLink="true">https://barry.ee/writing/githubneverdie/</guid><description>基于Github电子化档案的一些思考</description><pubDate>Fri, 17 Mar 2023 19:15:03 GMT</pubDate><content:encoded>&lt;p&gt;不知道有没有人注意到，Joe Armstrong 最近几个月都在忙着迁移博客到 &lt;a href=&quot;https://tiddlywiki.com/&quot;&gt;TiddlyWiki&lt;/a&gt;。我很早就关注了他的 Twitter，然而之前并没多想。听闻大师在 4 月 20 号去世，我才反应过来，原来他之前的举动是在未雨绸缪。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/joe_blog.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;TiddlyWiki 是个单文件的 Wiki 系统，但这并不重要。重要的是，**你把信息存在哪？**如果你希望存储一段信息，让 100 年后的人也能访问，要怎么做？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Facebook, Twitter, 微博？不要说 100 年，我都怀疑 20 年后它们还在不在；&lt;/li&gt;
&lt;li&gt;Google Cloud, Amazon, 阿里云 + 个人域名？他们大概会存在地更久一些。但没有人能保证不出事故，比如之前的腾讯云事件，比如万一服务器被入侵，黑客把文件删了。还有，你怎么让信息能一直被访问？域名会过期。到某个时候，跑着旧版本操作系统的机器也可能被强制下线或升级，你的服务一定能够在新版本正常运行吗？&lt;/li&gt;
&lt;li&gt;Dropbox, Google Drive, 百度网盘。同样地，这就要看你信不信这些公司一百年后还存在了，哦不对，他们即使还在，服务也可能早关了(望向 Google&lt;/li&gt;
&lt;li&gt;Wiki。Wiki 很好，但并不适合存储个人信息，且可能被删改。&lt;/li&gt;
&lt;li&gt;去中心化存储，比如区块链。说实话，我对区块链了解有限，但直觉上，我怀疑它能否帮助我们达成目标。对比另一个去中心化的例子：BT。当你要下一些老动画或者电影的时候，拖不下来是常事，因为&amp;quot;死种&amp;quot;了。这才几年呢。当然或许区块链有某种神奇的魔法可以解决这个问题？欢迎了解的朋友们补充。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;所以，我们还有什么选择？想来想去，也只有 GitHub 了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GitHub 已经成为互联网最重要的基础设施之一，有太多人，太多事都直接或间接地依赖于 GitHub，除非人类在未来完全不需要开源代码(这显然不可能)，否则我想不出 GitHub 有关闭的可能。对 GitHub 来说，存在 100 年简直是小意思，500 年也不是不可能。这是我的预言，不一定准确，但我还挺有信心的。&lt;/p&gt;
&lt;p&gt;不管怎么说，对我们的目标 100 年来说，GitHub 完全可以胜任。除了服务本身的持久性，GitHub 还有两个独特优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git。Git 能保存所有历史。&lt;/li&gt;
&lt;li&gt;Fork。就算黑客黑进了一个账户，删掉 repo，他能把所有 fork 都删干净吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;综上所述，目前来看，我认为 GitHub 是在百年尺度上存储信息并让其能被访问的&lt;strong&gt;唯一&lt;/strong&gt;途径。未来也许会有 option 2, option 3 出现，但 GitHub 作为 option 1 依然会存在。我相信，Joe 用 GitHub 来 host 博客绝不是突发奇想，他一定是在了解自己的身体状况的前提下，思考了一遍现存所有存储方式，然后同样发现只有 GitHub 才能满足需求。&lt;/p&gt;
&lt;p&gt;人总想留下某种痕迹，证明自己活过，然而事实上，99.999% 的普通人就这么被历史遗忘了——曾经是这样。我们处在信息时代的早期，同样也处在人类文明的早期。从今往后，被数字化的东西只会越来越多。既然有人意识到了 GitHub 的独特性，随着时间推移，越来越多的人总会意识到。那时候会发生什么？自然是，越来越多的人会把自己的信息搬到 GitHub 上，依托 GitHub 实现曾经人们可望而不可及的&amp;quot;永生&amp;quot;。人有两次死亡，第一次是肉体，第二次是被人忘记。我忘记这句话是谁说的了，但现在我们已经可以回避第二次。只要 GitHub 支持，就一定会有人这么做，至少我是其中之一。几十几百年后，GitHub 将成为世界上最大的数字公墓，注册用户大部分都已去世，然而个人主页，项目，commit 历史 还述说着他们生前做过的事——就比如 Joe 的&lt;a href=&quot;https://joearms.github.io/&quot;&gt;博客&lt;/a&gt;。这虽然是个比较 creepy 的推论，但从另一个角度想，却证明了人类的巨大进步：对抗死亡是人类文明的永恒主题，而我们已经实现了阶段性胜利。现在是文章、照片、视频，也许还有以个人习惯作为输入训练的模型。再往后呢？会不会有基因信息，乃至意识的完整复制呢？依托于稳定的存储，我们能做的事情实在太多了。反例是现在的一些 &lt;a href=&quot;https://www.everplans.com/articles/the-top-10-online-memorial-websites&quot;&gt;Memorial Websites&lt;/a&gt;，他们把逝者的信息放在自己网站上供亲友吊唁。这不能说没用，但在我看来去使用这类服务实在有些草率——就算他们再信誓旦旦，也摆脱不了某一天关站的风险，那时候还指望他们好好管理这些数据？没可能的。&lt;/p&gt;
&lt;p&gt;既然 GitHub 变成数字公墓是一种必然，我对他们的唯一希望，就是保持某种道德义务。我完全可以想象某一天他们出台一个政策，把二十年内没有活动迹象的账户全部 archive，GitHub Pages 全部下线。那就实在太恐怖了。我祈祷那一天不会到来。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文链接：&lt;a href=&quot;https://laike9m.com/blog/people-die-but-long-live-github,122/&quot;&gt;People Die, but Long Live GitHub - laike9m&amp;#39;s blog&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>Keep running</title><link>https://barry.ee/writing/keeprunning/</link><guid isPermaLink="true">https://barry.ee/writing/keeprunning/</guid><description>将我们平时在各种运动 APP 里的跑步数据做前端可视化</description><pubDate>Wed, 15 Mar 2023 20:09:03 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/ucu3i6-0.webp&quot; alt=&quot;Barry Running&quot;&gt;
保持每天运动是个好习惯，这几天我在刷 Github 时就刷到了这么一个可以将我们平时在各种运动 APP 里的数据做一个前端可视化的这么一个项目，于是我也尝试动手搭了一个，下面我就来分享一下我是如何实现的，本文主要分享配置 Keep 的操作。&lt;/p&gt;
&lt;h2&gt;Clone 主项目到本地&lt;/h2&gt;
&lt;p&gt;Running Page 是 &lt;a href=&quot;https://github.com/yihong0618&quot;&gt;@yihong0618&lt;/a&gt; 创立的一个开源项目，通过这个项目可以从多个主流跑步平台同步锻炼数据，自动生成一个地图可视化的跑步页面。通过 GitHub Pages 可以快速的完成自动部署。&lt;/p&gt;
&lt;p&gt;项目地址：&lt;a href=&quot;https://github.com/yihong0618/running_page&quot;&gt;https://github.com/yihong0618/running_page&lt;/a&gt;
我们可以将该仓库 fork 到自己的仓库在 clone 下来，或者直接 clone 下载传到自己新建的仓库。&lt;/p&gt;
&lt;h2&gt;配置项目文件&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;注意：压缩包当中包含多个以 . 开头的文件名称，在 macOS 系统下需要使用快捷键「Command + shift + .」显示隐藏文件。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.在根目录中找到「gatsby-config.js」，配置个性化选项。&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;pathPrefix: &amp;#39;/&amp;#39;,   # 如需使用自定义域名，此处需要修改为/
siteMetadata: {
  siteTitle: &amp;#39;Running Page&amp;#39;,   # 站点标题
  siteUrl: &amp;#39;https://running.domain.com&amp;#39;,   # 站点域名
  logo: &amp;#39;https://q.qlogo.cn/headimg_dl?bs=qq&amp;amp;dst_uin=*********&amp;amp;spec=640&amp;#39;,   # 左上角头像
  description: &amp;#39;Just Do It&amp;#39;,
  navLinks: [
    {
      name: &amp;#39;Blog&amp;#39;,   # 右上角导航栏
      url: &amp;#39;https://blog.domain.com&amp;#39;,
    },
  ],
},
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.打开「.github」&amp;gt;「workflows」&amp;gt;「run_data_sync.yml」文件，修改平台类型及信息。不同平台的配置信息可以前往 &lt;a href=&quot;https://github.com/yihong0618/running_page/blob/master/README-CN.md#%E6%94%AF%E6%8C%81&quot;&gt;说明页面&lt;/a&gt; 进行查看。&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Run Data Sync

on:
  workflow_dispatch:
  schedule:
    - cron: &amp;#39;0 0 * * *&amp;#39;

env:
  # please change to your own config.
  RUN_TYPE: keep # support strava/nike/garmin/garmin_cn/keep/only_gpx/nike_to_strava/strava_to_garmin/strava_to_garmin_cn/garmin_to_strava/garmin_to_strava_cn, Please change the &amp;#39;pass&amp;#39; it to your own
  ATHLETE: BarryYangi
  TITLE: Barry Running
  MIN_GRID_DISTANCE: 4 # change min distance here
  TITLE_GRID: Over 4km Runs # also here
  GITHUB_NAME: BarryYangi
  GITHUB_EMAIL: 2059484047@qq.com

jobs:
  sync:
    name: Sync
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.7

      # from pdm
      - name: Set Variables
        id: set_variables
        run: |
          echo &amp;quot;PY=$(python -c &amp;#39;import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())&amp;#39;)&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
          echo &amp;quot;PIP_CACHE=$(pip cache dir)&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT

      - name: Cache PIP
        uses: actions/cache@v2
        with:
          path: ${{ steps.set_variables.outputs.PIP_CACHE }}
          key: Ubuntu-pip-${{ steps.set_variables.outputs.PY }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
        if: steps.pip-cache.outputs.cache-hit != &amp;#39;true&amp;#39;

      - name: Run sync Nike script
        if: env.RUN_TYPE == &amp;#39;nike&amp;#39;
        run: |
          python scripts/nike_sync.py ${{ secrets.NIKE_REFRESH_TOKEN }}

      - name: Run sync Nike to Strava(Run with nike data backup and show with strava)
        if: env.RUN_TYPE == &amp;#39;nike_to_strava&amp;#39;
        run: |
          python scripts/nike_to_strava_sync.py ${{ secrets.NIKE_REFRESH_TOKEN }} ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}

      - name: Run sync Keep script
        if: env.RUN_TYPE == &amp;#39;keep&amp;#39;
        run: |
          python scripts/keep_sync.py ${{ secrets.KEEP_MOBILE }} ${{ secrets.KEEP_PASSWORD }} --with-gpx

      - name: Run sync Strava script
        if: env.RUN_TYPE == &amp;#39;strava&amp;#39;
        run: |
          python scripts/strava_sync.py ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}

      # for garmin if you want generate `tcx` you can add --tcx command in the args.
      - name: Run sync Garmin script
        if: env.RUN_TYPE == &amp;#39;garmin&amp;#39;
        run: |
          python scripts/garmin_sync.py ${{ secrets.GARMIN_EMAIL }} ${{ secrets.GARMIN_PASSWORD }}
      # If you only want to sync `type running` add args --only-run, default script is to sync all data (rides and runs).
      # python scripts/garmin_sync.py ${{ secrets.GARMIN_EMAIL }} ${{ secrets.GARMIN_PASSWORD }} --only-run

      - name: Run sync Garmin CN script
        if: env.RUN_TYPE == &amp;#39;garmin_cn&amp;#39;
        run: |
          python scripts/garmin_sync.py ${{ secrets.GARMIN_CN_EMAIL }} ${{ secrets.GARMIN_CN_PASSWORD }} --is-cn

      - name: Run sync Only GPX script
        if: env.RUN_TYPE == &amp;#39;only_gpx&amp;#39;
        run: |
          python scripts/gpx_sync.py

      - name: Run sync Strava to Garmin(Run with strava(or others upload to strava) data backup in Garmin)
        if: env.RUN_TYPE == &amp;#39;strava_to_garmin&amp;#39;
        run: |
          python scripts/strava_to_garmin_sync.py ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}  ${{ secrets.GARMIN_EMAIL }} ${{ secrets.GARMIN_PASSWORD }} ${{ secrets.STRAVA_EMAIL }} ${{ secrets.STRAVA_PASSWORD }}

      - name: Run sync Strava to Garmin-cn(Run with strava(or others upload to strava) data backup in Garmin-cn)
        if: env.RUN_TYPE == &amp;#39;strava_to_garmin_cn&amp;#39;
        run: |
          python scripts/strava_to_garmin_sync.py ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}  ${{ secrets.GARMIN_CN_EMAIL }} ${{ secrets.GARMIN_CN_PASSWORD }} ${{ secrets.STRAVA_EMAIL }} ${{ secrets.STRAVA_PASSWORD }} --is-cn

      - name: Run sync Garmin-cn to Strava(Run with Garmin data backup in Strava)
        if: env.RUN_TYPE == &amp;#39;garmin_to_strava_cn&amp;#39;
        run: |
          python scripts/garmin_to_strava_sync.py ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}  ${{ secrets.GARMIN_CN_EMAIL }} ${{ secrets.GARMIN_CN_PASSWORD }} --is-cn

      - name: Run sync Garmin to Strava(Run with Garmin data backup in Strava)
        if: env.RUN_TYPE == &amp;#39;garmin_to_strava&amp;#39;
        run: |
          python scripts/garmin_to_strava_sync.py ${{ secrets.STRAVA_CLIENT_ID }} ${{ secrets.STRAVA_CLIENT_SECRET }} ${{ secrets.STRAVA_CLIENT_REFRESH_TOKEN }}  ${{ secrets.GARMIN_EMAIL }} ${{ secrets.GARMIN_PASSWORD }}

      - name: Run sync Tulipsport script
        if: env.RUN_TYPE == &amp;#39;tulipsport&amp;#39;
        run: |
          python scripts/tulipsport_sync.py ${{ secrets.TULIPSPORT_TOKEN }} --with-gpx

      - name: Make svg GitHub profile
        if: env.RUN_TYPE != &amp;#39;pass&amp;#39;
        run: |
          python scripts/gen_svg.py --from-db --title &amp;quot;${{ env.TITLE }}&amp;quot; --type github --athlete &amp;quot;${{ env.ATHLETE }}&amp;quot; --special-distance 10 --special-distance2 20 --special-color yellow --special-color2 red --output assets/github.svg --use-localtime --min-distance 0.5
          python scripts/gen_svg.py --from-db --title &amp;quot;${{ env.TITLE_GRID }}&amp;quot; --type grid --athlete &amp;quot;${{ env.ATHLETE }}&amp;quot; --output assets/grid.svg --special-color yellow --special-color2 red --special-distance 20 --special-distance2 40 --use-localtime --min-distance &amp;quot;${{ env.MIN_GRID_DISTANCE }}&amp;quot;
          python scripts/gen_svg.py --from-db --type circular --use-localtime
          python scripts/gen_svg.py --from-db --year $(date +&amp;quot;%Y&amp;quot;)  --language zh_CN --title &amp;quot;$(date +&amp;quot;%Y&amp;quot;) Running&amp;quot; --type github --athlete &amp;quot;${{ env.ATHLETE }}&amp;quot; --special-distance 10 --special-distance2 20 --special-color yellow --special-color2 red --output assets/github_$(date +&amp;quot;%Y&amp;quot;).svg --use-localtime --min-distance 0.5

      - name: Deploy site
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.MY_GIT_TOKEN }}
          publish_branch: vercel-pages
          publish_dir: .
          force_orphan: true
          # keep_files: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里推荐我们删掉剩下三个 workflows 配置 yml，因为我们不需要，后面我们将会将站点配置到 vercel 上，然后复制我的 &lt;code&gt;run_data_sync.yml&lt;/code&gt; 文件内容到该文件覆盖。&lt;/p&gt;
&lt;h3&gt;3.找到自己所对应的平台需要完善的帐户信息&lt;/h3&gt;
&lt;p&gt;列如 keep：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python scripts/keep_sync.py ${{ secrets.KEEP_MOBILE }} ${{ secrets.KEEP_PASSWORD }} --with-gpx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们需要能够登录 keep 的手机账号以及密码，随后我们需要用到。&lt;/p&gt;
&lt;h3&gt;4.Running Page 使用 Mapbox 进行地图展示，需要前往 &lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox 站点&lt;/a&gt; 注册一个开发者账号。&lt;/h3&gt;
&lt;p&gt;登录账号后，选择「Create a token」创建一个令牌，并完善相关信息。提交后会得到一串令牌信息，编辑「src」&amp;gt;「utils」&amp;gt;「const.js」文件，将自己的令牌替换到 MAPBOX_TOKEN 当中。&lt;/p&gt;
&lt;h3&gt;5.保存文件并且 push 到自己的 git 仓库&lt;/h3&gt;
&lt;h2&gt;Git 仓库 secrets 配置&lt;/h2&gt;
&lt;p&gt;进入自己的仓库，依次点击 Settings-&amp;gt;Secrets and variables-&amp;gt;Actions-&amp;gt;New repository secret 新建如下图三个 secrets
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/vvwxu8-0.webp&quot; alt=&quot;secrets&quot;&gt;&lt;/p&gt;
&lt;p&gt;其中前两项为 keep 的手机账号和密码，最后一项为 github 的 token，如果没有的话可以点击头像-&amp;gt;Settings-&amp;gt;Developer settings-&amp;gt;Personal access tokens (classic)-&amp;gt;Generate new token
创建的时候可以把所有权限都勾了，然后创建完就复制记下来，这个 token 是值出现一次的，看完以后就再也不能看了，然后把这个 token 放到前面我们仓库的哪个 secret 里去即可。&lt;/p&gt;
&lt;h2&gt;配置 Vercel&lt;/h2&gt;
&lt;p&gt;进入我们的 &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; 没有账号的注册一个然后绑定我们的 GitHub ，绑定完直接点击刚刚我们新建的仓库导入即可。
然后我们回到 Github 的仓库点击 Actions，按如下步骤手动触发一次工作流。
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/w1jap5-0.webp&quot; alt=&quot;Actions&quot;&gt;&lt;/p&gt;
&lt;p&gt;等待工作流跑完如果是勾就说明没问题了，这个时候我们会发现多出来了一个 vercel-pages 分支，这个分支我们用来在 vercel 上部署，我们来到 vercel 的本项目的 setting 页面更改默认的部署分支为 vercel-pages，步骤如下图：
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/w4jupa-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;保存完成后我们需要在去 vercel-pages 分支在 push 一次 vercel 这边才会真正应用，我们只需在 github 仓库的 Actions 页面重新执行一次我们刚刚操作过的哪个工作流即可。&lt;/p&gt;
&lt;p&gt;等待工作流跑完，然后你回到 vercel 页面等待部署完你就会发现部署分支已经变为了 vercel-pages&lt;/p&gt;
&lt;h2&gt;vercel 绑定域名&lt;/h2&gt;
&lt;p&gt;如果你想将本页面分享给你的朋友看这样肯定是不够优雅的，哪如果你有自己的域名可以到 vercel 的 Setting 页面的 Domains 选项绑定自己的域名。&lt;/p&gt;
&lt;h2&gt;End&lt;/h2&gt;
&lt;p&gt;在此希望这个项目能带给我们的不仅仅是一次简单的项目部署经验，能让我们借此养成一个良好的运动习惯才是最重要的，然后记录下来，将来可以去追溯当下。
Just enjoy it.&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>优雅的通过PC接管移动设备音频</title><link>https://barry.ee/writing/pcvideo/</link><guid isPermaLink="true">https://barry.ee/writing/pcvideo/</guid><description>本文简单总结如何快速通过PC接管移动设备音频</description><pubDate>Wed, 15 Mar 2023 15:09:03 GMT</pubDate><content:encoded>&lt;p&gt;可能我们在生活中偶尔会有这种需求，就比如说正在寝室或者办公室学习或者办公的时候需要听语音条或者看一个视频又不方便外放声音，而且又不想频繁换耳机（懒），这时这种场景需求就可以被满足。&lt;/p&gt;
&lt;h2&gt;个人应用场景参考&lt;/h2&gt;
&lt;p&gt;IPad 音频被电脑接管，IPad 放在旁边自动播放刷抖音、听音乐、如下：
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/n8rtcv.webp&quot; alt=&quot;IPad&quot;&gt;&lt;/p&gt;
&lt;p&gt;其他还有一些很多需求大家跟自己的实际情况而定。&lt;/p&gt;
&lt;h2&gt;Windows 平台&lt;/h2&gt;
&lt;p&gt;在 win10 以及 win10 以上的平台上，我们可以通过一款软件很轻松的做到，我们只需要在微软应用商店上下载一款名为 &lt;a href=&quot;https://www.microsoft.com/zh-cn/p/bluetooth-audio-receiver/9n9wclwdqs5j&quot;&gt;Bluetooth Audio Receiver&lt;/a&gt; 的软件即可。
Bluetooth Audio Receiver 的使用非常简单，有两个决条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;电脑必须拥有蓝牙功能，或者有一个蓝牙适配器。&lt;/li&gt;
&lt;li&gt;将手机（或支持 A2DP 的播放设备）与电脑通过蓝牙配对、连接。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后运行 Bluetooth Audio Receiver，在列表中选择想要播放音乐的手机，点击 &lt;strong&gt;Open Connection&lt;/strong&gt;，最后去手机播放音乐即可。
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/nf3oop-0.webp&quot; alt=&quot;Bluetooth Audio Receiver&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Linux 平台&lt;/h2&gt;
&lt;p&gt;在 Linux 平台上可以会稍微麻烦一点，不过相信你都用上 Linux 了，输几行命令来装几个软件还是小 kiss 的。
首先，确保您已经在 Linux 系统上安装了 Bluez、Pulseaudio 和 pulseaudio 蓝牙模块。大多数 Linux 发行版都预装了这些工具。以防万一它们丢失，请按如下所示安装它们。&lt;/p&gt;
&lt;h3&gt;在 Linux 上安装 Bluez&lt;/h3&gt;
&lt;p&gt;要在 Arch Linux 及其变体上安装 Bluez，请运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo pacman -S bluez
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Debian、Ubuntu 上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo apt install bluez
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Fedora、CentOS、RHEL 上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo dnf install bluez
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo yum install bluez
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On openSUSE: 在 openSUSE 上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo zypper install bluez
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 Bluez 后，确保蓝牙服务已启动并在引导时启用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo systemctl start bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo systemctl enable bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要验证蓝牙状态，请运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ systemctl status bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;在 Linux 上安装 Pulseaudio&lt;/h3&gt;
&lt;p&gt;PulseAudio 是一个开源、跨平台、支持网络的声音服务器程序，通过 freedesktop.org 项目分发。它支持 Linux，以及各种 BSD 发行版，例如 FreeBSD 和 OpenBSD，macOS。 Pulseaudio 在大多数 Linux 发行版的默认存储库中可用。要通过蓝牙播放，我们应该安装 pulseaudio 蓝牙模块。&lt;/p&gt;
&lt;p&gt;运行以下命令在 Arch Linux 及其变体（如 EndeavourOS 和 Manjaro Linux）上安装 Pulseaudio 和其他所需程序：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo pacman -S pulseaudio pavucontrol pulseaudio-bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Debian、Ubuntu 和 Linux Mint 上，只需运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo apt install pulseaudio pulseaudio-utils pavucontrol pulseaudio-module-bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fedora、RHEL 8、AlmaLinux 8、Rocky Linux 8：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo dnf install pulseaudio pulseaudio-utils pavucontrol pulseaudio-module-bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CentOS 7.x., RHEL 7.x: CentOS 7.x.、RHEL 7.x：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo yum install pulseaudio pulseaudio-utils pavucontrol pulseaudio-module-bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;openSUSE:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo zypper install pulseaudio pulseaudio-utils pavucontrol pulseaudio-module-bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;将 Linux PC 与手机配对&lt;/h3&gt;
&lt;p&gt;确保手机已与您的 PC 配对。蓝牙配对非常简单！你可能已经做过很多次了。这就不多说了，如果幸运的话，连接后就可以通过电脑听到手机的声音了。如果没用的话你可能还得继续下续的操作。&lt;/p&gt;
&lt;h3&gt;配置&lt;/h3&gt;
&lt;p&gt;创建一个名为 ~/.config/pulse/system.pa 的文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir ~/.config/pulse/
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ nano ~/.config/pulse/system.pa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在其中添加以下行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;.include /etc/pulse/system.pa
load-module module-bluetooth-policy
load-module module-bluetooth-discover
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存并关闭文件。使用命令重新启动蓝牙服务以使更改生效：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo systemctl restart bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;您可以直接编辑“/etc/pulse/system.pa”文件并进行更改。但是，强烈建议不要编辑系统范围的配置文件，而是编辑用户配置文件。这就是为什么您应该创建“&lt;del&gt;/.config/pulse”目录，然后将系统配置文件复制到其中并根据您的需要进行编辑。&lt;/del&gt;/.config/pulse/default.pa 文件不是完整的副本，而是可以以“.include /etc/pulse/default.pa”行开始，然后覆盖默认值。这样我们就可以避免将来 pulseaudio 更新时出现问题。&lt;/p&gt;
&lt;h2&gt;结束&lt;/h2&gt;
&lt;p&gt;至此你已经完成了所有操作。
Just enjoy it！
参考文章：&lt;a href=&quot;https://ostechnix.com/turn-your-linux-pc-into-bluetooth-speakers-for-your-phone/&quot;&gt;Turn Your Linux PC Into Bluetooth Speakers For Your Phone - OSTechNix&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>论Linux to go</title><link>https://barry.ee/writing/linuxtogo/</link><guid isPermaLink="true">https://barry.ee/writing/linuxtogo/</guid><description>本文简单总结如何快速制作一个个人随身Linux系统</description><pubDate>Wed, 15 Mar 2023 10:09:03 GMT</pubDate><content:encoded>&lt;p&gt;可闻大家应该都听说过 win to go，但是 win to go 因为对性能要求太高官方都已经停止了对这个项目的维护，虽然说当下你仍可以通过各种途径安装最新的 windows 到你的 U 盘上，但是前提是你有一个性能足够好的 U 盘，如果你不确定你的 U 盘是否合适，你可以下载一个名为&lt;strong&gt;WTGBench&lt;/strong&gt;的软件来测试一下&lt;/p&gt;
&lt;h2&gt;选择一个合适的 Linux 发行版&lt;/h2&gt;
&lt;p&gt;当下 Linux 发行版的选择课太多了，主流的有 Ubuntu、ArchLiux、Kali 等等等等，大家可以根据自己的需求选择、本文将以 Ubuntu 22.04 作为演示。&lt;/p&gt;
&lt;h2&gt;制作 U 盘工具的选择&lt;/h2&gt;
&lt;p&gt;如果你还想要 U 盘在做完系统后还能正常作为一个 U 盘来存放一些文件，你就不得不去了解一款叫 &lt;a href=&quot;https://www.ventoy.net/cn/index.html&quot;&gt;&lt;strong&gt;Ventoy&lt;/strong&gt;&lt;/a&gt; 的神器，先按照官方文档将你的 U 盘制作为 Ventoy 启动盘，在此之后你就字需要将制作好的 U 盘虚拟盘文件扔到 U 盘里然后就能通过 Ventoy 来引导启动，详情大家可以去官方看文档，很详细，这里就不多说。&lt;/p&gt;
&lt;h2&gt;安装 Ventoy 插件&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ventoy.net/cn/plugin_vhdboot.html&quot;&gt;Plugin.WinVhdBoot . Ventoy&lt;/a&gt;
&lt;a href=&quot;https://www.ventoy.net/cn/plugin_wimboot.html&quot;&gt;Plugin.wimboot . Ventoy&lt;/a&gt;
常用的有这两个插件，这里主要用到的是第一个，第二个如果你要以后安装 win to go 你也可以一起下下来，下载完完这两个压缩包后解压然后找到如下图所示的两个文件放到 U 盘根目录新建的&lt;strong&gt;ventoy&lt;/strong&gt;目录，注意！注意！这里的&lt;strong&gt;v&lt;/strong&gt;是小写的！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/smwjkm-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;美化 Ventoy（可选）&lt;/h2&gt;
&lt;p&gt;Ventoy 自带的 GRUB 主题我就评价一个字——&lt;strong&gt;丑&lt;/strong&gt;,换一个漂亮又简洁的 &lt;a href=&quot;https://www.gnome-look.org/p/1482847&quot;&gt;Distro Theme&lt;/a&gt; 吧。&lt;/p&gt;
&lt;p&gt;Files 往下翻找到 arch.tar，下载解压到 &lt;code&gt;/ventoy/themes/arch&lt;/code&gt; 里，进 VentoyPlugson 修改配置。&lt;/p&gt;
&lt;h2&gt;下载镜像&lt;/h2&gt;
&lt;p&gt;去官网下载即可，&lt;a href=&quot;https://ubuntu.com/#download&quot;&gt;Enterprise Open Source and Linux | Ubuntu&lt;/a&gt;，下载最新 LTS 版本。&lt;/p&gt;
&lt;h2&gt;下载 Oracle VM VirtualBox 制作系统&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.virtualbox.org/wiki/Downloads&quot;&gt;官网&lt;/a&gt;下载对应电脑系统的版本即可&lt;/p&gt;
&lt;h3&gt;安装完后开始制作系统&lt;/h3&gt;
&lt;p&gt;按下图步骤先新建一个虚拟&lt;strong&gt;vdi&lt;/strong&gt;格式的虚拟硬盘，这里一定要注意要选&lt;strong&gt;固定大小&lt;/strong&gt;的！
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/sstqsc-0.webp&quot; alt=&quot;VM&quot;&gt;&lt;/p&gt;
&lt;p&gt;磁盘创建完后点击三条杠开始回到欢迎界面新建虚拟电脑步骤如下图：
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/sul6rz-0.webp&quot; alt=&quot;&quot;&gt;
虚拟硬盘注意选择我们刚刚新建的。&lt;/p&gt;
&lt;p&gt;创建完成后点击设置确认启用 EFI 已勾选。
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/swfr6h-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;然后在如下位置添加我们下载的 Linux 镜像文件
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/sxceh3-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;设置完成点击 OK 应用设置，然后点击启动
如果进入 UEFI 界面进不去系统的话输入 &lt;code&gt;exit&lt;/code&gt; 退出然后在 BIOS 里选择 CDROM 作为我们的启动项。&lt;/p&gt;
&lt;p&gt;然后正常安装，注意的地方有我们需要手动分区，所以在选择安装位置的时候我们选择下面哪个选项
我的分区设置如下：
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/szvr7a-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/szzy0x-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;安装完成后进入系统在系统内我们还需安装适配 Ventoy 的插件
Linux 浏览器进入 &lt;a href=&quot;https://github.com/ventoy/vtoyboot/releases&quot;&gt;Releases · ventoy/vtoyboot&lt;/a&gt; 下载 iso 文件，解压、终端进入目录输入以下命令来安装：
&lt;img src=&quot;https://easyimage.smitten.top/i/2023/03/15/t26qb3-0.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;将 vdi 虚拟硬盘文件拷贝到 U 盘&lt;/h3&gt;
&lt;p&gt;将 vdi 虚拟硬盘文件拷贝到 U 盘，并且在文件后加上 &lt;code&gt;.vtoy&lt;/code&gt; 后缀&lt;/p&gt;
&lt;h2&gt;进入 BIOS 关闭安全启动&lt;/h2&gt;
&lt;p&gt;这时重启电脑并且并且进入 BIOS，不同型号的主板的按键不同，然后关闭安全启动，不懂大家可就自行百度。&lt;/p&gt;
&lt;h2&gt;重启并且选择 U 盘启动&lt;/h2&gt;
&lt;p&gt;如果不出意外的话，大家进入 ventoy 界面就能看到刚刚我们拷进去的 Linux 了，选中回车进入系统。&lt;/p&gt;
&lt;h2&gt;检查各个硬件驱动是否正常&lt;/h2&gt;
&lt;p&gt;检查显示器、触摸板、声音、网络等是否正常，有问题的话可以自己善用网络解决。
我这里给大家提供 ubuntu 下没有声音的解决方案，大家可以尝试一下：
&lt;a href=&quot;https://answers.launchpad.net/ubuntu/+source/alsa-driver&quot;&gt;Questions : alsa-driver package : Ubuntu (launchpad.net)&lt;/a&gt;
&lt;a href=&quot;https://answers.launchpad.net/ubuntu/+source/alsa-driver/+question/699972&quot;&gt;Question #699972 “No sound on ubuntu 20.04.3” : Questions : alsa-driver package : Ubuntu (launchpad.net)&lt;/a&gt;
&lt;a href=&quot;https://www.yyearth.com/index.php?aid=33&quot;&gt;ubuntu系统下使用alsamixer来配置声卡 - YY分享 (yyearth.com)&lt;/a&gt;
&lt;a href=&quot;https://developer.aliyun.com/article/837036&quot;&gt;Linux下使用alsamixer配置系统默认的声卡设备(默认音频输出设备、输入设备、系统音量)-阿里云开发者社区 (aliyun.com)&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>VPS 基础Docker环境配置</title><link>https://barry.ee/writing/vpsdocker/</link><guid isPermaLink="true">https://barry.ee/writing/vpsdocker/</guid><description>便于自己快速配置VPS Docker环境</description><pubDate>Tue, 14 Mar 2023 11:12:03 GMT</pubDate><content:encoded>&lt;h2&gt;准备工作&lt;/h2&gt;
&lt;p&gt;服务器：腾讯香港轻量应用服务器 24 元 / 月 VPS 一台（最好是选非大陆（香港）的服务器）如果是小白刚开始玩的话，可以购买 Racknerd 的服务器（地区选美西），最低一年不到 100 块.&lt;/p&gt;
&lt;h2&gt;登陆服务器&lt;/h2&gt;
&lt;p&gt;选择一款连接SSH的软件。
Mac 或者 Linux 用户可以直接用系统自带的终端（也叫Terminal）来登陆服务器。
输入：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh 你的用户名@你的服务器IP -P 22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你没有更改 ssh 的端口，默认就是22，当然为了服务器安全，建议你可以换一个别的端口，具体请见：保护好你的小鸡！保姆级服务器安全教程！&lt;/p&gt;
&lt;h2&gt;升级 Packages&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo -i # 切换到 root 用户
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt update -y  # 升级 packages
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install wget curl sudo vim git -y  # Debian 系统比较干净，安装常用的软件
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;添加SWAP虚拟内存&lt;/h2&gt;
&lt;p&gt;注意：VPS 的内存如果过小，建议设置一下 SWAP，一般为内存的 1-1.5 倍即可，可以让系统运行更流畅！&lt;/p&gt;
&lt;p&gt;设置 SWAP 可以用脚本:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -O box.sh https://raw.githubusercontent.com/BlueSkyXN/SKY-BOX/main/box.sh &amp;amp;&amp;amp; chmod +x box.sh &amp;amp;&amp;amp; clear &amp;amp;&amp;amp; ./box.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择 18，然后输入你想要扩容的数值即可。&lt;/p&gt;
&lt;h2&gt;安装 Docker 环境&lt;/h2&gt;
&lt;h3&gt;安装 Docker（非大陆服务器）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -qO- get.docker.com | bash
docker -v  #查看 docker 版本
systemctl enable docker  #设置开机自动启动
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装 Docker-compose（非大陆服务器）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo curl -L &amp;quot;https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)&amp;quot; -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version  #查看 docker-compose 版本
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装 Docker（国内服务器）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -sSL https://get.daocloud.io/docker | sh
docker -v  #查看 docker 版本
systemctl enable docker  #设置开机自动启动
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装 Docker-compose（国内服务器）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://get.daocloud.io/docker/compose/releases/download/v2.1.1/docker-compose-`uname -s`-`uname -m` &amp;gt; /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version  #查看 docker-compose 版本
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;修改 Docker 配置（可选）&lt;/h3&gt;
&lt;p&gt;以下配置会增加一段自定义内网 IPv6 地址，开启容器的 IPv6 功能，以及限制日志文件大小，防止 Docker 日志塞满硬盘（泪的教训）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat &amp;gt; /etc/docker/daemon.json &amp;lt;&amp;lt;EOF
{
    &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;20m&amp;quot;,
        &amp;quot;max-file&amp;quot;: &amp;quot;3&amp;quot;
    },
    &amp;quot;ipv6&amp;quot;: true,
    &amp;quot;fixed-cidr-v6&amp;quot;: &amp;quot;fd00:dead:beef:c0::/80&amp;quot;,
    &amp;quot;experimental&amp;quot;:true,
    &amp;quot;ip6tables&amp;quot;:true
}
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重启 Docker 服务：
&lt;code&gt;systemctl restart docker&lt;/code&gt;
至此，你的服务器已经配置好了基础的 Docker 环境。&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>Hi,Regex</title><link>https://barry.ee/writing/regex/</link><guid isPermaLink="true">https://barry.ee/writing/regex/</guid><description>Regex学习站点</description><pubDate>Wed, 08 Mar 2023 17:37:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;正则表达式是一组由字母和符号组成的特殊文本，它可以用来从文本中找出满足你想要的格式的句子。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个正则表达式是一种从左到右匹配主体字符串的模式。 “Regular expression”这个词比较拗口，我们常使用缩写的术语“regex”或“regexp”。 正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md&quot;&gt;学习正则表达式(learn-regex)&lt;/a&gt;
&lt;a href=&quot;https://regexlearn.com/zh-cn&quot;&gt;https://regexlearn.com/zh-cn&lt;/a&gt;
&lt;a href=&quot;http://louiszhai.github.io/2016/06/13/regexp/&quot;&gt;正则表达式前端使用手册&lt;/a&gt;
&lt;a href=&quot;https://www.runoob.com/regexp/regexp-tutorial.html&quot;&gt;菜鸟教程&lt;/a&gt;
&lt;a href=&quot;https://regex101.com/&quot;&gt;Regex101&lt;/a&gt;
&lt;a href=&quot;https://regexr.com/&quot;&gt;Regexr&lt;/a&gt;
&lt;a href=&quot;https://github.com/geongeorge/i-hate-regex.git&quot;&gt;iHateRegex&lt;/a&gt;
&lt;a href=&quot;https://jex.im/regulex/&quot;&gt;Regulex&lt;/a&gt; - Regulex is a JavaScript Regular Expression Parser &amp;amp; Visualizer.
&lt;a href=&quot;https://github.com/any86/any-rule&quot;&gt;any86/any-rule: 🦕 常用正则大全, 支持web / vscode / idea / Alfred Workflow多平台 (github.com)&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>三分钟让你的Web网页变优雅</title><link>https://barry.ee/writing/font/</link><guid isPermaLink="true">https://barry.ee/writing/font/</guid><description>启用「霞鹜文楷」在线字体，一款优雅的Web开源字体</description><pubDate>Wed, 08 Mar 2023 17:37:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/jwfdfu-0.webp&quot; alt=&quot;霞鹜文楷&quot;&gt;&lt;/p&gt;
&lt;p&gt;项目地址：&lt;a href=&quot;https://github.com/chawyehsu/lxgw-wenkai-webfont&quot;&gt;https://github.com/chawyehsu/lxgw-wenkai-webfont&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;直接调用 CDN。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link
  rel=&amp;quot;stylesheet&amp;quot;
  href=&amp;quot;https://npm.elemecdn.com/lxgw-wenkai-screen-webfont/style.css&amp;quot;
  media=&amp;quot;print&amp;quot;
  onload=&amp;quot;this.media = &amp;#39;all&amp;#39;&amp;quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或 @一蓑烟雨 分享的 staticfile CDN&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link
  rel=&amp;quot;stylesheet&amp;quot;
  href=&amp;quot;https://cdn.staticfile.org/lxgw-wenkai-screen-webfont/1.6.0/lxgwwenkaiscreen.css&amp;quot;
  media=&amp;quot;print&amp;quot;
  onload=&amp;quot;this.media = &amp;#39;all&amp;#39;&amp;quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;body {
  /* Screen version */
  font-family: &amp;#39;LXGW WenKai Screen&amp;#39;, sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perfect.&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>hexo博客工作流CI（一键部署的快乐）</title><link>https://barry.ee/writing/hexoci/</link><guid isPermaLink="true">https://barry.ee/writing/hexoci/</guid><pubDate>Tue, 21 Feb 2023 15:44:14 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;一直都想尝试一下基于 Github Action 来进行全自动化的 hexo 博客内容的输出，今天终于闲下来尝试了一下，发现是真滴香！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI/CD 解释：
CI\CD 其实说的是三件事情：「持续集成（Continuous Integration）」、「持续交付（Continuous Delivery）」、「持续部署（Continuous Deployment）」。
因为「持续交付」和「持续部署」的英文缩写是一样的，所以这三件事情缩写成了 CI\CD 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Github Action 优点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;可以多域名多站点部署&lt;/li&gt;
&lt;li&gt;不会出现从服务器去连接github连接不上的情况&lt;/li&gt;
&lt;li&gt;可以一键多处全部部署完成✅&lt;/li&gt;
&lt;li&gt;不再需要使用繁杂的前置命令&lt;blockquote&gt;
&lt;p&gt;hexo clean
hexo generate&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;比如我自己是在 &lt;a href=&quot;https://vercel.com/&quot;&gt;vercel&lt;/a&gt;, &lt;a href=&quot;https://github.com/&quot;&gt;github page&lt;/a&gt; 两处来部署的站点。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;vercel 站点：&lt;a href=&quot;https://blog.yct.ee/&quot;&gt;Barryの小站 (yct.ee)&lt;/a&gt;
github 站点：&lt;a href=&quot;https://www.smitten.top/&quot;&gt;Barryの小站 (smitten.top)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中 vercel 是白嫖的 &lt;a href=&quot;http://cloudflare.com/&quot;&gt;cloudflare&lt;/a&gt; 免费的 CDN，github 站点用的是 &lt;a href=&quot;https://dcdn.console.aliyun.com/&quot;&gt;aliyun DCDN&lt;/a&gt; 但是目测有时候 DCDN 会慢一点而且有时候缓存会清理不掉，也可能是我自己的设置问题。&lt;/p&gt;
&lt;p&gt;不过如此确实大大提高可用性与速度。&lt;/p&gt;
&lt;h2&gt;工作流&lt;/h2&gt;
&lt;p&gt;在这里分享一下我的工作流，大概步骤是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Obsidian 新建 post 文章编辑完成后通过 git 自动保存到备份仓库，当备份仓库接收到 push 的信息时并发现 &lt;strong&gt;已发布文章&lt;/strong&gt; 里有新文章时触发工作流，将新文章 push 到 hexo 源码仓库的 posts 文件夹，此时 hexo 源码仓库接收到 push 信息触发工作流进行自动部署到主站&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/naz1ta-0.png&quot; alt=&quot;Obsidian git&quot;&gt;&lt;/p&gt;
&lt;p&gt;这个插件配合着 github action 来用简直无敌, 平时除非要改动博客源码，不然根本都不需要去动网站源码，在编辑器专注于写作即可，写完文章稍等这个插件便会自动备份数据，同时将要发布的文章自动拉取到 github 上的 hexo 仓库进行部署，vercel 检测到 push 也会进行同步更新，这样就实现了一个全自动化的工作流&lt;/p&gt;
&lt;h2&gt;实现步骤&lt;/h2&gt;
&lt;p&gt;如果你和我有着同样的需求，可以参考以下内容，可能会给你省下很多时间。&lt;/p&gt;
&lt;h3&gt;GitHub 自动部署 Hexo&lt;/h3&gt;
&lt;p&gt;实现以上工作流的第一步就是先要将自己的 hexo 源码上传到 GitHub 仓库上并配置好工作流来进行自动部署。&lt;/p&gt;
&lt;h4&gt;教程常量声明&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;常量名&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;常量释义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[Blogroot]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;本地存放博客源码的文件夹路径&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[SourceRepo]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;存放博客源码的私有仓库名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[SiteBlogRepo]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;存放编译好的博客页面的公有仓库名 Site 指站点，教程中会替换成 Github、Gitee、Coding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[SiteUsername]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;用户名 Site 指站点，教程中会替换成 Github、Gitee、Coding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[SiteToken]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;申请到的令牌码 Site 指站点，教程中会替换成 Github、Gitee、Coding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[GithubEmail]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;与 github 绑定的主邮箱，建议使用 Gmail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[TokenUser]&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Coding 配置特有的令牌用户名&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;Github Action 使用教程&lt;/h4&gt;
&lt;p&gt;为了确保交由 &lt;code&gt;Github Action&lt;/code&gt; 来持续部署时，&lt;code&gt;Github Action&lt;/code&gt; 具备足够的权限来进行 &lt;code&gt;hexo deploy&lt;/code&gt; 操作, 需要先获取 &lt;code&gt;Token&lt;/code&gt;。
访问 Github-&amp;gt;头像（右上角）-&amp;gt;Settings-&amp;gt;Developer Settings-&amp;gt;Personal access tokens-&amp;gt;generate new token, 创建的 Token 名称随意，但必须勾选 repo 项和 workflows 项。&lt;/p&gt;
&lt;p&gt;token 只会显示这一次，之后将无法查看，所以务必保证你已经记录下了 Token。之后如果忘记了就只能重新生成重新配置了。&lt;/p&gt;
&lt;h4&gt;创建存放源码的私有仓库&lt;/h4&gt;
&lt;p&gt;我们需要创建一个用来存放 &lt;code&gt;Hexo&lt;/code&gt; 博客源码的私有仓库 &lt;code&gt;[SourceRepo]&lt;/code&gt;
这里之所以是私有仓库，是因为在接下来的配置中会用到 &lt;code&gt;Token&lt;/code&gt;，如果 &lt;code&gt;Token&lt;/code&gt; 被盗用，别人可以肆意操作你的 github 仓库内容，为了避免这一风险，才选择的博客源码闭源。
创建完成后，需要把博客的源码 push 到这里。首先获取远程仓库地址，此处虽然 SSH 和 HTTPS 均可。SSH 在绑定过 ssh key 的设备上无需再输入密码，HTTPS 则需要输入密码，但是 SSH 偶尔会遇到端口占用的情况。请自主选择。&lt;/p&gt;
&lt;h4&gt;配置 Github Action&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;[Blogroot]&lt;/code&gt; 新建 &lt;code&gt;.github&lt;/code&gt; 文件夹, 注意开头是有个 &lt;code&gt;.&lt;/code&gt; 的。然后在 &lt;code&gt;.github&lt;/code&gt; 内新建 &lt;code&gt;workflows&lt;/code&gt; 文件夹，再在 &lt;code&gt;workflows&lt;/code&gt; 文件夹内新建 &lt;code&gt;autodeploy.yml&lt;/code&gt;, 在 &lt;code&gt;[Blogroot]/.github/workflows/autodeploy.yml&lt;/code&gt; 里面输入&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: 自动部署
#当有改动推送到master分支时，启动Action
on:
  push:
    branches:
      - master
  release:
    types:
      - published
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 检查分支
        uses: actions/checkout@v2
        with:
          ref: master
      - name: 安装 Node
        uses: actions/setup-node@v1
        with:
          node-version: &amp;quot;18.x&amp;quot;
      - name: 安装 Hexo
        run: |
          export TZ=&amp;#39;Asia/Shanghai&amp;#39;
          npm install hexo-cli -g
      - name: 缓存 Hexo
        id: cache-npm
        uses: actions/cache@v3
        env:
          cache-name: cache-node-modules
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles(&amp;#39;**/package-lock.json&amp;#39;) }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-
      - name: 安装依赖
        if: ${{ steps.cache-npm.outputs.cache-hit != &amp;#39;true&amp;#39; }}
        run: |
          npm install --save
      - name: 生成静态文件
        run: |
          hexo clean
          hexo generate
      - name: 部署到Github
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          token: ghp_xxxxxxxxxxxxxxxxxxxxxxx
          repository-name: BarryYangi/BarryYangi.github.io
          branch: main
          folder: public
          commit-message: &amp;quot;${{ github.event.head_commit.message }} Updated By Github Actions&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;之后需要自己到仓库的 Settings-&amp;gt;Secrets-&amp;gt;actions 下添加环境变量，变量名参考脚本中出现的，依次添加&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;重新设置远程仓库和分支&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;删除或者先把 &lt;code&gt;[Blogroot]/themes/butterfly/.git&lt;/code&gt; 移动到非博客文件夹目录下, 原因是主题文件夹下的 &lt;code&gt;.git&lt;/code&gt; 文件夹的存在会导致其被识别成子项目，从而无法被上传到源码仓库。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在博客根目录&lt;code&gt;[Blogroot]&lt;/code&gt;路径下运行指令&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git init #初始化
git remote add origin git@github.com:[GithubUsername]/[SourceRepo].git
#[SourceRepo]为存放源码的github私有仓库
git checkout -b master # 切换到master分支，
#2020年10月后github新建仓库默认分支改为main，注意更改
#如果不是，后面的所有设置的分支记得保持一致
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;添加屏蔽项因为能够使用指令进行安装的内容不包括在需要提交的源码内，所有我们需要将这些内容添加到屏蔽项，表示不上传到 github 上。这样可以显著减少需要提交的文件量和加快提交速度。打开&lt;code&gt;[Blogroot]/.gitignore&lt;/code&gt;,输入以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;.DS_Store
Thumbs.db
db.json
*.log
node_modules/
public/
.deploy*/
.deploy_git*/
.idea
themes/matery/.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不是 &lt;code&gt;matery&lt;/code&gt; 主题，记得替换最后一行内容为你自己当前使用的主题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;之后再运行 git 提交指令，将博客源码提交到 github 上。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &amp;quot;github action update&amp;quot;
git push origin master
#2020年10月后github新建仓库默认分支改为main，注意更改
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;p&gt;可能遇到的 bug&lt;/p&gt;
&lt;p&gt;因为 butterfly 主题文件夹下的.git 文件夹的存在，那么主题文件夹会被识别子项目。从而无法被上传到源码仓库。若是遇到添加屏蔽项，但是还是无法正常上传主题文件夹的情况。请先将本地源码中的 themes 文件夹移动到别的目录下。然后 commit 一次。接着将 themes 文件夹移动回来，再 commit 一次。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;查看部署情况&lt;/h4&gt;
&lt;p&gt;此时，打开 GIthub 存放源码的私有仓库，找到 action。
根据刚刚的 Commit 记录找到相应的任务
点击 Deploy 查看部署情况
若全部打钩，恭喜你，你现在可以享受自动部署的快感了。&lt;/p&gt;
&lt;h3&gt;Obsidian 备份配置&lt;/h3&gt;
&lt;h4&gt;插件下载&lt;/h4&gt;
&lt;p&gt;首先先在 Obsidian 插件市场中下载 Obsidian git 插件（需要戴莉）&lt;/p&gt;
&lt;h4&gt;git 备份仓库设置&lt;/h4&gt;
&lt;p&gt;先在 github 建立一个私人仓库，当然你想让你的笔记让别人看到公开仓库也行：）
然后进行本地仓库设置
打开 Obsidian 本地仓库的文件夹，新建 &lt;code&gt;.gitignore&lt;/code&gt; 文件，来屏蔽一些我们不需要进行备份的文件内容如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.obsidian
.trash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后建立 &lt;code&gt;.github/workflows&lt;/code&gt; 目录，在该目录下配置工作流：&lt;code&gt;ci.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: 上传文章
on:
  push:
    branches:
      - master
    paths:
      - &amp;#39;已发布文章/**&amp;#39;
jobs:
  deploy_job:
    runs-on: ubuntu-latest
    name: build
    steps:
      # check out the repository
      - name: Checkout
        uses: actions/checkout@v2
      - name: Pushes to another repository
        uses: cpina/github-action-push-to-another-repository@main
        env:
          API_TOKEN_GITHUB: [GithubToken]
        with:
          source-directory: &amp;#39;已发布文章&amp;#39;
          destination-github-username: [GithubUserName]
          destination-repository-name: [SourceRepo]
          target-directory: &amp;#39;source/_posts&amp;#39; # hexo中发布文章目录
          user-email: [GithubEmail]
          target-branch: master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在本地 obsidian 根目录（能看到 &lt;code&gt;.obsidian&lt;/code&gt; 的哪个目录）下运行运行指令&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;    git init #初始化
    git remote add origin git@github.com:[GithubUsername]/[备份仓库名].git
    git checkout -b master # 切换到master分支，
    #2020年10月后github新建仓库默认分支改为main，注意更改
    #如果不是，后面的所有设置的分支记得保持一致
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后再运行 git 提交指令，将博客源码提交到 github 上。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &amp;quot;github action update&amp;quot;
git push origin master
#2020年10月后github新建仓库默认分支改为main，注意更改
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;测试&lt;/h4&gt;
&lt;p&gt;然后你可以在你设置的发布文章的文件夹中新建一篇文章，这里推荐使用 QuickAdd 结合 templater 快速生成带有 hexo 文章 yaml 的模板文件，然后随便写几句话保存。
然后按 &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;p&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/t16eg8.webp&quot; alt=&quot;git&quot;&gt;&lt;/p&gt;
&lt;p&gt;选择着两项都能立即同步仓库
随后看你的 obsidian 备份仓库的 action 是不是成功执行，不出意外的话到此你就已经可以开始享受全自动化的工作流了。&lt;/p&gt;
&lt;h3&gt;Vercel 部署 Hexo&lt;/h3&gt;
&lt;h4&gt;git 仓库添加 vercel 配置文件&lt;/h4&gt;
&lt;p&gt;此步非必须，但是不做后续可能会遇到很多奇奇怪怪的问题，其实就是让 vercel 取消当访问以正斜杠结尾的路径时，将以 308 状态代码响应，并重定向到不带尾部斜杠的路径。如果 hexo 的路径不尾随 &lt;code&gt;/&lt;/code&gt; 的话可能非根页面都会 404，并且有些 hexo 的第三方的评论也是通过路径返回数据到前端页面的，路径不一致的话评论都不一样。
配置很简单只需在 &lt;code&gt;[Blogroot]&lt;/code&gt; 目录加上 &lt;code&gt;vercel.json&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;trailingSlash&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可。&lt;/p&gt;
&lt;h4&gt;vercel 配置&lt;/h4&gt;
&lt;p&gt;首先你得去注册一个 &lt;a href=&quot;https://vercel.com/&quot;&gt;vercel&lt;/a&gt; 账号，然后在 dashboard 页面点击 Add New-&amp;gt;Project, 绑定你的 github 账号并选择刚刚你自己 Hexo 的源码仓库，你应该是可以在看到一个 Hexo 的图标的哪个仓库，点击导入，然后什么都不用设置点击 Deploy 就 ok 了，等待他自动构建完成，如果没用报错网页一切访问正常，那么恭喜你，vercel 的部署就这么简单的完成了。&lt;/p&gt;
&lt;h4&gt;vercel 绑定域名&lt;/h4&gt;
&lt;p&gt;如果你想更优雅的访问 vercel 站点的话就想要绑定一个自定义域名，步骤也很简单
在 vercel dashbord 面板点击你的 hexo 项目-&amp;gt;Settings-&amp;gt;Domains, 在上方输入你购买的域名
然后来到 dns 服务商这里绑定解析&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/pi49z8-0.jpg&quot; alt=&quot;dns&quot;&gt;
这里在国内可以绑定国内的 vercel dns&lt;/p&gt;
&lt;p&gt;至此，全部的博客部署工作已经完成。&lt;/p&gt;
&lt;p&gt;EOF&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>我要我们在一起</title><link>https://barry.ee/writing/wearetoghter/</link><guid isPermaLink="true">https://barry.ee/writing/wearetoghter/</guid><pubDate>Fri, 17 Feb 2023 21:25:24 GMT</pubDate><content:encoded>&lt;p&gt;偶然之间看到一篇帖子, 不知道后来的我们, 十年后会怎么 🌎&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;整理后的帖子相对完整，原文缺失部分
这是整理后的帖子原文： &lt;a href=&quot;https://www.douban.com/note/260167887/&quot;&gt;https://www.douban.com/note/260167887/&lt;/a&gt;
原作者： 你这个贱人
原文地址：豆瓣： &lt;a href=&quot;http://www.douban.com/group/topic/36139334/&quot;&gt;http://www.douban.com/group/topic/36139334/&lt;/a&gt; 【贱贱贱人直播】与我十年 长跑的女朋友就要嫁人了。📺
故事背景地： &lt;a href=&quot;http://www.tudou.com/programs/view/36RvNyr4TUI/&quot;&gt;http://www.tudou.com/programs/view/36RvNyr4TUI/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;昨天下午凌一尧给我发来一张照片，是一件婚纱，她问好不好看，我说还行。&lt;/p&gt;
&lt;p&gt;她说“初五举办婚礼，和我们以前想象得一样，有鲜花拱门，有红地毯，有白婚纱黑礼服，就是没有你。”&lt;/p&gt;
&lt;p&gt;我说“要不要我去凑个份子？”&lt;/p&gt;
&lt;p&gt;她半天之后才回复说:“不用了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2001 年的夏天，我十六岁，正在读高中。即便是夜晚，气温仍然高得令人辗转反侧，黑漆漆的夜晚满是室友们翻身和叹息的声音，而我咬着小电筒，蒙着一条薄被单，写下人生中唯一的一封情书。
我的读者叫凌一尧，马尾辫，大前额，身材娇小，细腰长腿小翘臀。要命的是，她偏偏是一位学霸，常年霸占月考名次红榜第一排，这样脑瓜子聪明又美得翻泡的妞儿绝对是众人心目中的雅典娜，只可跪舔不能直视。
几乎每天，我都会想入非非，幻想着各种与她搭讪的场面。其中包括她从楼梯上滚下来毁容了，我抱她朝着医院狂奔，并且发誓这辈子我都不会抛弃她，最后她在我的怀里留下了幸福的泪水。
送出情书的第二天，我的创作地点就转移到政教处办公室，对面坐着姚主任，我们私下管他叫“姚千岁”。他说：“吕钦扬同学啊，昨天你一夜写了三页纸，今天怎么就咬笔杆了？是不是这个环境不利于激发创作灵感，要不要拿回宿舍慢慢写？”
我理智地拒绝道：“不用了，这里有空调。”
凌一尧把我的情书送给政教处，这事做得太坑，我内心的伤痛尚未愈合，班主任跑来告诉我一个好消息：“你要上电视了！”
“什么电视？”我有些激动。
“闭路电视。经过校领导研究决定，这次纪律整顿大会的主题是杜绝早恋，你要在学校直播室做一次公开检讨。”
“为什么是我？不就一封情书吗？”
班主任思索片刻，说：“可能是别人脸皮太薄了，怕留下心理阴影。”
他妈的！
纪律整顿电视会议之前的那几天，我的心情却糟糕到极点。
每次远远地看见凌一尧，我都会走向旁边的岔路，不愿意与她打照面。说实话，我对她有些记恨，无法理解她为什么那样做，难道被我喜欢是一件很痛苦的事情？如果是这样，以后不喜欢你就是了呗。
据说历次电视会议的录像都会被妥善保存，作为我校发展历程的丰碑，为了给学妹们留下一个好印象，我特意理了一个清爽的发型，熨了一下白衬衫，还借了一双白色的耐克跑步鞋。第一次上电视，好激动。
那天中午政史二班的体育委员来访，对我进行亲切慰问，鼓励我好好表现。他带来一个消息，说那封情书不是被上交的，而是被他们班主任曹老太缴获的，凌一尧还被拉到办公室做了一通思想审查。
学校演播室中间摆着一台黑色的摄像机，镜头前面摆着一个主席台，依次坐着诸位领导以及各年级组长，而门口站着的是六名犯罪嫌疑人，其中一个就是我。那五个家伙我差不多都认识，他们的罪名比较另类，什么拿街机子儿冒充硬币买茶叶蛋，什么大半夜拿鱼竿在校园的池塘里钓鱼的，还有那位住在二楼的同学，他用大搪瓷杯装尿往院墙外面泼，墙外方圆几米的庄稼死得透透的，连野草都长不出一棵。
相比之下，我绝对是最纯洁的。但不知道为什么，当我说我因为写情书给女孩却被对方送给老师了，他们一个个都面露鄙夷之色，仿佛我犯下比他们更龌龊的罪行。当时我就清醒地认识到，错的不是我，而是这个世界。
由于早恋是今天重点批判的主题，姚千岁将我安排在最后出场。班主任对我有点不放心，还特意跑来对我进行战前动员和辅导，他说：“等会儿千万不要紧张，控制住情绪。”
“你怕我被吓哭？”我有种受辱的感觉。
班主任说：“不是，我担心你在这么严肃的地方笑场。”
终于轮到我了，我站到话筒前面朗读上次写的检讨，尽量不看镜头，像在给姚千岁致哀悼词。正要谢幕之时，副校长却在发表一则有关早恋危害的讲话，此时我非常困窘，傻逼似的杵在那里，被全校数千双眼睛在看不见的地方盯着，这种滋味真心痛苦。
不知道副校长说了什么，姚千岁突然对我发问，所有人都看着我，包括镜头。我一头雾水地“啊”了一下，此处是第二声。
姚千岁将问题重复一遍：“吕钦扬同学，你对自己的所作所为有没有感到后悔？”当时我就震惊了！这他妈算是什么垃圾问题？你又不是没看过我那封情书，写得感人肺腑，催人泪下，引人沉思，都发誓这辈子非凌一尧不娶了，你现在他妈的问我后不后悔？我他妈只是以大局为重，配合你演一场杀鸡儆猴的戏而已，你还真把我当冤大头了？我就算真的后悔了，不可能当众说出来啊，否则以后还怎么混？面对那黑洞洞的镜头，不，那不只一个镜头，那是数千双眼睛，我作出一个重大而深远的决定———我盯着镜头，说：“我不后悔。”
那天傍晚的天气非常好，走出学校演播室，西边铺天盖地的一大片火烧云，我的白衬衫都被映得红彤彤的。各个班级刚好下课，学生们像出栏的猪一样涌出教室直奔餐厅，许多认识或者不认识我的人冲着我打招呼，连年轻的男女老师都意味深长地对我哼笑。
经过凌一尧所在的班级，几个女生拿着饭盒走出来，其中一个便是凌一尧，她抬头看见我，立即像见了鬼似的退了回去。其他女生起哄起来，悠长的“噢哟”在走廊里回荡着。我这样一个阿 Q，经历此生最为辉煌的时刻，迈出的每一步都像踩在软绵绵的云端，仿佛自己是一个凯旋的盖世英雄。
我为一时的倔强付出巨大的代价———惩罚等级由警告升级为记过，礼拜一全校晨会，别人都在聆听领导训话，而我在冲洗操场角落那个简陋又瘟臭的厕所。冲完厕所以后，我淡定地走过队列前面的那条煤渣路，手里的铁皮桶吱呀吱呀地响着，相当拉轰。
这些举动相当幼稚，用现在的话概括这是在“作死”，但它们在当时足以让我成为全校的三大奇葩之一。更悲剧的是，入榜的是我的两个死党，“大乔”和“子石”。我之所以鼓起勇气给凌一尧写情书，其中一个原因便是和这两个傻逼打赌了，他们说如果我追到凌一尧，他们就在校园里裸奔一圈。
当时周杰伦才出道，大乔就果断成为铁粉，一曲《爱在西元前》日夜哼唱，最终进入全校文艺汇演的名单。然而，正式演出那天他当着数千师生的面公然忘词。他悲愤下台后并未气馁，而是继续苦练这首歌，两天以后的傍晚，他偷偷翻窗进入学校总控室，对着麦克风重新清唱一遍《爱在西元前》，那销魂的歌声传遍校园的每一个角落。子石名叫蒋慧东。他去泡隔壁职高的一个妹子，几个地痞们带着自家车床磨出的砍刀来战，他舞着泔水老汉的扁担，光着膀子把对方揍得满地找牙，连学校保安都没敢过问。但就是这样一个群架王，晚自习时突发奇想，挖了一坨清凉油抹在 JJ 上，试图达到“头悬梁锥刺股”的功效，最后他的嚎叫响彻整个教学区，从此再也没人记得他的神勇。我不知道大家如何评价的，因为我的氪金狗耳早已阵亡。之所以重点这两位仁兄，是因为他们俩正在看这个直播故事，他们希望我多褒少贬，不要破坏他们的伟岸形象，但我选择站在真相这一边。随后很长时间里，我都不太好意思和凌一尧走得太近，因为总有傻逼在旁边“矮油”“噢哟”。子石和大乔不遗余力地耍宝，烘托我的形象，而我感觉这样太小丑了，但一抬头我看见凌一尧嘴角的笑，一下子发现自己非常愿意当这个小丑。在那个年龄，无论无意的出糗还是有意的献丑，只要能博取那个人的一笑，便会欣喜若狂。而多年以后，这样的快乐已然灭绝。
因为有我这个炮灰的经验教训摆在这里，喜欢凌一尧的男生很多，敢于追求的却几乎没有。我们亲眼看见一个高三哥把她在圣诞节把她约到桥边，送她一盒巧克力，凌一尧怎么不肯要，三哥一怒之下把那盒巧克力丢进河里。第二天，子石和大乔把巧克力盒子捞上来，打开包装一看，嘿，没有进水。我们把巧克力分了，晚上遇到凌一尧时我拿了三块几乎被我焐软的巧克力给她，她居然没有拒绝，收下了！我本来是想恶作剧一下而已，她这样一来，我都没敢说那是昨天被丢下河的那盒巧克力。巧克力事件之后，莫名其妙地，我和她的关系出现好转，虽然彼此遇见时从来不打招呼，但她嘴角总是有一丝浅得几乎看不出来的微笑。
“你眼瞎啊，她一直板着脸，哪里有过微笑？”大乔非常直白地反对。子石也很困惑:“难道这就是肉笑皮不笑？”我只能慨叹这两个蠢货的无知，告诉他们有一些东西“只有相爱的人才能体会”。后来凌一尧说，那大半年里我们是在用意念恋爱，没有一句对白。
为了迎接素质教育检查团的视察，学校举办一次声势浩大的秋季运动会，还从体校借了一帮外援来捧场。那三天里，全校处于停课状态，对我而言这就是另一个形式的放假而已。而我发现自己有半套黄冈密卷的作业没写，科代表说运动会一结束就要交作业，我不得不加班加点地抄答案。教室里只有寥寥几人，凌一尧突然来我们班找一位学霸妹子，也是她的初中同学。我躲在高耸入云的书堆后面，看着她们低声说笑，虽然不知道她们在聊些什么，可是她一笑，我也忍不住跟着龇牙咧嘴。不料，她一扭头看见我时愣了一下，双眼瞪得大大的，就跟喵星人准备开天眼了似的。
我赶紧低头写试卷，再一抬头时她已经站在我旁边，我一紧张，赶紧把那份标准答案往桌肚子里塞，比被老师发现还紧张。她伸手把那份答案掏出来，说：“我还以为你在认真学习呢，原来是在抄答案。”
我说“偶尔为之……”
她又问：“你怎么从来都不和我说话的？”
我说：“我怕写检讨。”
她的小脸涨得通红，辩解道：“那个真不是我弄的！我把那信夹在英语课本里，被曹老师翻到的！”
我说：“你知道姚千岁说了什么不？他说我是‘害群之马’，自己不学好还去骚扰人家品学兼优的女生，是‘癞蛤蟆想吃天鹅肉’。他都这样说了，我怎么敢再和你说话？”
她皱起眉头，将信将疑地说：“姚主任是想用激将法吧？”
我哼笑一声，说：“如果我以后有出息，这就是激将法，如果我没有出息，这就是他的神机妙算，老狐狸从来不会吃亏的。不过他也没有说错，我的确是癞蛤蟆想吃天鹅肉，可能再过多少年，我还是他手里的反面教材。”
“你后悔了？”她低声问道。
我说：“不知道……”
运动会之后没多久，凌一尧偷偷塞给我一张字条，她说：“如果你能够考到本科，高考结束以后咱们就假装在一起，气死姚千岁！”
子石和大乔很快发现我的不正常，因为我很少搭理他们俩，整天埋在教室里学习，有点“不合群”了。他们俩试图拯救我于水火之中，但研究许久都未果，直到看见我与凌一尧在教学楼走廊里相视一笑，他们才若有所悟。
于是，我被驱逐出三大奇葩的队列。其实没有了我，他们俩照样可以玩得很嗨，譬如用煤渣块狙击操场上接吻的小情侣。整个高三，我们都保守着这个秘密，两人即便在校园里迎面走过，也从来不打一声招呼。但我看见她浅浅的笑意，我努力压抑着内心的激动，双拳握得指甲嵌入掌心。偶尔旁边没人的时候，我会自言自语地把她的姓名说出来，然后像一只疯猴子似的狂奔乱跳，那真是一件快乐到极点的事情。凌一尧，我喜欢你呀！喜欢得恨不得在教学楼里裸奔，恨不得在操场上打滚，恨不得冲进校长办公室尖叫！那一年的高考，全省数学平均分 68 分，我只考了 38 分，总分离本科线还差 9 分！填报志愿那天，我和凌一尧在美术考生画室旁边的天台上聊天，我非常沮丧地告诉她，我没能达到本科线，她不用兑现当初的约定了，但凌一尧抿着嘴巴摇头，笑盈盈的样子。她说：“只要你努力过就行了呀。”我愣了一下，不太明白她的意思。她再对我眨巴眼睛，我这时候才猛然顿悟，开心得手舞足蹈起来，而她甩着小手直打我，叫我“不要发癫”。这是她的一个口头禅，每当我或者她的朋友开心得失态，她就会很温和地笑着，在后面提醒“哎呀，不要发癫啦！”对我而言，这个分数只适合报大专，而具体哪个学校哪个专业都是无所谓，当前要务是离凌一尧近一些，于是我和她一起去了六朝古都。我们的学校不在同一个区，但坐车也就半个小时路程，平时见面还不是难事。大一的课程比较少，凌一尧突然提出来要去勤工俭学，我问她准备干点什么，她提出来的想法毫无创意，什么饭店接待，发传单，卖电话卡。
我问她“你知道我爷爷干嘛的么？”她摇头说不知道。我说国庆节回家，我把他的传家宝带来，到时候你就看着吧，我小学就做他的学徒了。国庆节之后，我们在大学城摆起爆米花的小摊位，摇啊摇，摇啊摇，砰！那天爆米花很好卖，特别是凌一尧心惊胆战地摇着那个摇把，就有许多人过来围观，毕竟女孩子做这个太新鲜了。不过第二天傍晚就有人把我们赶走了，因为附近停了车子，一声炸响之后就有警报器鬼叫，涉嫌扰民。
尽管如此，我们还是很开心，晚上去看半价电影，柜台问我们要不要爆米花，我和凌一尧傻呵呵地笑。
她曾经说:“如果哪天我们想要分开了，就想一想曾经一起在街头卖爆米花的日子。”
现在我正在想，你呢？
大学那几年，我们与大多数校园情侣一样，试着一起打工却总是没有头绪，吃喝玩乐又没有太多钱，经常出去玩半天都花不了五十块钱，照样穷开心。到了期末，作为一个学霸，她完全闭门不出，专心复习，而我一个学渣只要做完小抄就可以安安心心地玩游戏了。
就这样一直混着，我到了大三时，我们面临分道扬镳的危险。她还要一年才本科毕业，以后还要考研，而我已经面临实习。她说:“要不你考专升本吧！”我考虑好几天，最后还是决定离开校门，我说“你乖乖上学，以后还要读研，我先出去闯，等你毕业了我刚好娶你过门！”我至今不知道自己当初的决定是否正确，有时坚定地认为那是男人的担当，但一旦喝多了就会把因果联系扯得非常远，最后归根结底到我没有好好念书才会导致两相忘的结局。我第一份工作，是在一家监理公司当资料员，每月只有一千四百元的工资。当时我最喜欢听别人说“工作难找”，因为只有听到这样的话，我才觉得自己不是 loser。
在监理公司工作，本应是很轻松的，但不是指我们这种苦逼资料员，每天白天忙得要命，对着电脑处理各种文件，晚上凌一尧打电话过来和我聊天，我已经累得只想闷头大睡。当时我的心情的确非常焦躁，经常怀念学校里的惬意生活，所以当凌一尧喋喋不休地说着学校里发生的好玩的事情，我却没有耐心听下去，打断道:“明天再聊吧，你也早点休息。”她愣了一下，说:“你是关心我呢，还是嫌弃我呢？”我说:“我就是很累。”她呵呵冷笑一声，把电话挂了，周围一片寂静时我却睡不着了，一下子被自己吓醒了: 三年了，这是我第一次这样大逆不道！凌一尧是一个性格很犟的女孩，她不轻易翻脸，但只要翻了脸，那就真是很难弥合了。她掀起的冷战持续足足一个礼拜，电话照接，但就是很冷淡，冷淡得让人觉得她一夜之间移情别恋了。我急得团团转，但她认为的惩罚时间一到，就立即打电话过来问“知道错了吗？”我说“罪该万死。”“以后还会再犯么？”我赶紧发誓，这辈子都不敢再敷衍她这个小姑奶奶，她这才给我一条生路。但是，冷战结束不等于我们之间的矛盾消失，她只需要学业和恋爱，而我刚刚开始承受来自各方面的压力，尤其是对未来的担忧。我当时是一个胸无大志的可怜虫，我最羡慕的职业只是总监，啥事不干就有人送烟酒塞红包，我这辈子就这点理想了。
资料员干了大半年，自我感觉非常良好，跟在监理后面混吃混喝，烟酒不断，施工单位把我们当爷爷供着。
有一天，凌一尧的手机被偷了，我发现自己的存款竟然不够给她买一只新手机。那种挫败感极其折磨人心，但凌一尧不介意，她买 ic 卡和我打电话，说反正平时只和我联系，叫我以后赚了大钱再给她买。有妞如此，夫复何求？可是这个“大钱”在哪里？我当时尚未感觉到紧迫感，还在盘算着自己哪天有了监理资格，该有多轻松惬意。
情人节那天，我和凌一尧在外面约会，经过一家婚纱店，她就把小脸贴在玻璃橱窗上看，她说“以后咱们结婚的话，就租这件婚纱走红地毯，怎样？”我得瑟地说“租什么租，直接买下来收藏就是了！”凌一尧蹲下来看角落里的标价牌，低声说“你至要不吃不喝一年半才能买下来。”我当时就脸红了，不是因为自己高估婚纱的价格，而是因为高估自己的能力。我居然要不吃不喝一年半才能给我的妻子买下婚礼上那件婚纱？说到刚毕业的那段屌丝岁月，心情有些郁闷，还是说点有趣的事情吧。那天我给凌一尧的情人节礼物是一只熊娃娃，四十五块钱。她很开心地放在家里，可是她叔叔家小孩看中那个娃娃，蛮横地抱了回去。凌一尧不好意思说不给，但她第二天坐了俩小时的车回到那个卖娃娃的小店，买了一个一模一样的，直奔她叔叔家，硬是把我送的那只换了回来。我说“两个都一样，干嘛还要换？”她说“我都给那一个取了名字，两个怎么可能一样？”
终于有一天，我决心辞职，离开这种安逸却庸庸碌碌的生活，原因之一是和我一起共事的监理大叔挨揍了。
当时监理有些严格，把施工单位惹毛了，平时称兄道弟的人按住老监理揍，最后甩下一句话:“你们这种垃圾，给脸不要脸，我们看在你们是业主的走狗的份上才丢点骨头给你们，你们还蹬鼻子上脸了？”他们没有为难我，但我被伤到了: 我这辈子不可以做一个捡别人残羹冷炙的走狗。原因之二便是凌一尧考研了，我想多赚钱，争取在她研究生毕业时给她一个安稳的家。她读的是本校的研究生，于是我去南京找了工作，三年的同居生活开始了。
房子是凌一尧找的，四十平，月租六百。我们一起购置许多东西，比如简易折叠衣橱，厨具，餐具，以及被褥。凌一尧把两副餐具摆好，脸上满是小妻子般的认真，我躺在床上看着她忙这个忙那个，突然觉得不可思议: 我十六七岁时得有多幸运才会得到这样一个小家伙的青睐！
凌一尧有时很像一个孩子，某个周末我去上班，她一个人在家睡到黄昏。我下班回来时她还抱着枕头睡着，我换拖鞋时她睁开眼睛，说:“吕钦扬，我最喜欢看你回家。”我说“噢”“那你什么时候最喜欢我？”我没回答上来，她有些不高兴，到了第二天早上我才告诉她“我们并肩站在镜子前一起刷牙的时候我最爱你”
我们那段时间的生活条件很简单，早餐是熬一小锅米粥，一小碟肉松，还有两个煮鸡蛋。我们约定谁先醒谁先去做，但每次都是她先醒，我百思不得其解，她不是那么容易自然醒的人，可是我又从来听不到闹铃声。后来我才知道，她把闹铃调成震动，把手机垫在枕头边缘，这样她就可以早起做饭又不把我吵醒。“白痴，手机会有辐射的啊！”我埋怨道。她说:“我就是喜欢喊你起床吃早饭呀！”她那得瑟的模样，就像幼儿园里得了小红花等待表扬的小朋友。
当时她的手机是大学室友淘汰下来送给她的，摩托罗拉的，开合时都会吱呀吱呀地响，外面的漆都掉了。我工作三个月，她的生日那天，我买了一只小的儿童蛋糕，两个人一起做了几道菜，这个生日就这样勉勉强强过掉了。晚上，她裹着被子躺在我怀里看电视，我从枕头底下摸出一只盒子递给她，她小心翼翼地打开，里面是我攒钱买的一部夏普翻盖手机。她盯着那手机看了半天，一句话也不说，我有些纳闷，把她掰过来时才看见她的眼泪啪嗒啪嗒地往下掉。我问道：“不喜欢？” 她还是什么话都没讲，直接搂住我的脖子，眼泪直接往我肩膀上擦，后来我才知道，前两天她同学嘲笑她的手机老土，“五十块钱卖给我都不要”，她怕我听了难过，就一直没敢告诉我。
哪怕已经相恋那么多年，凌一尧在我眼里依然是一个雅典娜，集性感，可爱，聪慧，与善良于一身。她穿着睡裙抬起胳膊晾晒衣裳；把我的脸假想成镜子左照右瞧的时候最可爱；她坐在台灯下一边写作业，一边与我讨论自由主义与无政府主义；她明知道行乞的人是骗子，但路过那些人面前时还是忍不住丢一枚硬币，以求自己良心的安宁。天气转凉的时候，她开始向同学学习针织，买了毛线照着图册开始鼓捣起来，并且不允许我偷窥她的杰作。然而当作品终于完成，试穿时她才悲催地发现毛衣小了一圈，即使穿上也像猪八戒中了三个菩萨的套索似的。我被勒得喘不过气，非常无助地看着她，她却气呼呼地拍我的肚子，说：“都怪你！养这么胖！浪费我的心血！” 为了穿上她这件开山之作，我决定努力减肥，当我觉得自己可以穿上那件毛衣，却又错过穿毛衣的季节。再后来，那件毛衣也找不着了，如今，那个为傻逼织毛衣的女孩也不见了。
大乔在镇江工作，而子石在宁波，有一次他们俩一起来南京玩，我们四人一起去吃傣妹。聊天时大乔说漏嘴了，说到当年他们俩和我打赌的事情，凌一尧的脸色顿时一沉，问我：“你追我就只是因为一个赌？” 我吓得脸都白了，因为我记得一些影视剧里这样的事情会导致女生彻底翻脸，大乔和子石也愣住了。但凌一尧马上又笑起来，对大乔和子石说：“那你们俩说话算数，什么时候裸奔？”
子石赶紧辩解说：“等你们俩结婚了，我们就在婚礼上裸奔，好吧？” “行。”凌一尧愉快地答应。我觉得非常欣慰，我们家尧尧是一个开得起玩笑的好孩子，但晚上回到家里，她终于收起笑脸，要我好好解释一下那个赌到底什么意思———原来她只是不想在别人面前丢我的面子，但该清算的账一个都跑不掉。我很遗憾当时没有趁机要大乔和子石兑现诺言，现在他们再也不需要裸奔了。
有时我觉得凌一尧挺难揣摩的，还是一次情人节的早上，我们在南京地铁站外面看到一个男人捧着一束花向一个女孩单膝下跪，当众表达爱意。凌一尧一脸艳羡地旁观着，一口气一直提着，直到围观结束才舒畅地吐出来，啧啧地回味无穷。她看得太认真，以至于不知不觉地将嘴里的豆浆吸管咬扁了，有点郁闷，我只得去便利店买了一瓶爽歪歪，因为可以拿吸管。我以为她喜欢这种浪漫的玩意儿，于是下午下班后也买了一束花，准备找个地方让她开心一下，不料见面后我刚把花拿出来，她吓得赶紧往旁边走，低声说：“快收起来，丢人死了！” 我有些受挫，垂头丧气地跟她一起回家，不料关门以后她一边埋怨我乱花钱，一边得瑟地把花夺过去闻了又闻，喜悦之情溢于言表。我问她为什么看别人送花表白时那么开心，她说：“喜欢看戏又不等于喜欢演戏，被人围观的时候好难为情啊，像个白痴似的。” “那我们结婚的时候怎么办？那么多人围观。。。”我问。凌一尧想了想，居然露出紧张的神色：“是啊，还真是一道坎儿，我现在就得开始做心理准备了。”
凌一尧读研三的时候，她家里开始给她介绍对象，反复几次之后她终于交代说自己已经有男朋友，而且交往很久了。她家问我的具体状况，凌一尧怕被反对，于是给我虚报一些内容，尤其在收入方面，她说我的职务是部门经理，月薪八千，但事实上，但是我当时只有三千五。 “你家很在乎这个吗？”我非常脑残地问。凌一尧白了我一眼：“在乎了又怎么样？难道现在还不是时候？” 我当时有种尊严遭到践踏，尤其是她虚报我的收入状况，觉得她瞧不起我当时的经济状况，于是自个儿生了闷气。但凌一尧也被她家里催得紧，加上做课题和找工作的压力，她的心情也非常糟糕，于是和我第一次吵开了。我们彼此说了很伤对方的话，她说我没出息不长进，我叫她去找个小老板，不用跟着我受穷罪。最后，她气得躲在阳台上哭。我坐在房间里，看着她用了一年多的旧包，空空如也的梳妆台，还有那只我送给她的，使用两年仍然干干净净的手机，突然心酸得疼。我走到阳台，把她拥在怀里，说了一声对不起。她没有顺从，也没有抗拒，只是望着眼前这个城市的一隅，目光里满是迷茫。我渐渐意识到，这已经不是无忧无虑的高中，也不是温饱与快乐即可安生的大学，我若是化不开她的忧虑，兴许可能永远地失去她。
凌一尧即将毕业时，我离开南京，因为朋友喊我一起出去闯，去海边干一个很大的围海工程。他描述了一幅美妙的蓝图，一起合伙搞土方，我在测量和预算方面有些经验，他信得过。我当时觉得这是一个千载难逢的机会，尚未与凌一尧商量便一口答应下来，我要向她证明我不是一个安于现状的窝囊废，我终究要闯出一片天地。她知道以后非常生气，但我意已决，她也不好作出过多阻拦。她给我打包行李，又一直把我送上长途车，她没有哭，但车子开动时她站在卷起的尘土里，额发在风中飘动，抬手轻轻一挥，我整颗心都猛地沉了下去。我得有多铁石心肠，才会踏上一条离你越来越远的路呀？每当我醉了酒，天旋地晕的时候，我都会想起无数个凌一尧。那个穿着校服扎着马尾辫，清秀又稚气的凌一尧；那个在昏暗路灯下偷偷塞字条给我的凌一尧；那个一接吻就会忍不住闭上双眼的凌一尧；那个睡到半夜突然抱住我的胳膊说“我爱你”的凌一尧。但唯有那个站在黄昏余晖中无奈地目送我远去的凌一尧，最让我寝食难安，甚至哪天让我死不瞑目。
海边的气候非常恶劣，紫外线强度高，而且海风像刀子一样，脚下的土地踩十秒就能踩出一个吃人的陷阱。除此以外，我们住在活动板房里，而工人们直接搭了简易窝棚，而且每一滴淡水都是稀缺资源，尽管我们面对着整片大海。我们先请承建单位吃饭，穿得体面的都是 X 总，稍微邋遢的都是 X 工。这帮人都不是善类，他们在酒桌上的目标不是吃饭，也不是谈事，而是要把对方往死里灌，这也是朋友带我过来的原因———扛酒是我的技能之一。这一喝，便是一顿接一顿，有时上顿的酒还没醒，下一顿的酒又开始了。那天为了报价的事情，我们又请客吃饭，觥筹交错的时候凌一尧突然打电话来，说：“我肚子疼得厉害。”
“怎么了，来那个了？”我问。
“不是，就是疼。”
“是不是着凉了？要不要去医院看一下？”除了这些废话，我还能说些什么呢。
“你在干什么？”
“我在喝酒呢。”
凌一尧无奈地苦笑，说：“喝酒？那你继续喝吧。”然后她挂了电话，我再回拨过去，已经没人接听。此时，里面的人在喊我主持那圈酒的喝法，我只得回到包厢，然后又是喝醉。坐车回海边，一路停了四次下来呕吐，吐得魂都要丢了，却还要逞强大骂这种酱香型的酒太他妈不适应了。第二天酒醒以后，我才依稀想起凌一尧说肚子疼的事情，赶紧打电话过去慰问。她说她夜里吃了止疼片，迷迷糊糊一会儿醒一会儿睡，直到天亮才眯了一会儿。这就是恋人分离的痛苦，你不知道她有多需要你，而她不知道你有多心疼她，两个人都在各自的世界以为自己是被遗忘的那个人。大多数的矛盾都是在这种分离中诞生，若是近在咫尺，天大的矛盾，一个拥抱即可化解。“我离开这段时间你还适应吗？”我问。她沉默片刻，说：“还好，快习惯了。就是一看见你的拖鞋，枕头，牙刷和杯子，都有些失落。以前打扫房间时在床垫底下找到你的臭袜子都会骂你，现在找不到了，却更加难过。”
那个围海工程相当艰苦，与大海斗智斗勇，一边铺路一边通车，潮水一来就得逃命，潮水一退就得抢工期，有时昼潮夜汐冲得猛烈，几天的血汗都白费了。那间房子的租期快到了，房东要一次交满一个季度，而我和凌一尧的八万块共同定期存款还有一个多月。她舍不得放弃利息，问我有没有现金，可我身无分文。刚好有一个堤坝等待合拢，若是潮水来了，豁口会被冲开，而抢堵的时间很有限。业主方为了避免大的损失，许诺谁去把这事操作了，可以现场支付劳务费以及机械台班费，双倍。其实这事的危险并不大，只不过潮水将至，上机操作的人会被困在堤坝上，直到潮水退去。我和另一个小伙子约好一起上了，两个人，两台大型挖掘机。一个多小时左右，豁口堵住了，我想回到岸上，但指挥部不允许，要我们呆在挖掘机上。果然，二十分钟后，潮水铺天盖地漫上来了，把黑色的编织袋堤坝淹没了，刚好把挖掘机的履带淹没一半。我四周都是茫茫的海水，海风卷着浪水往驾驶舱打，像下雨一样。没有方向感，恶心，眩晕。期间，凌一尧发短信问我在干什么，我没敢告诉她我在海水中央，我说外面在下雨，我在打牌。她说:“你不是一向不喜欢打牌吗？”
我说:“玩玩嘛，闲着。”她有点不高兴:“你不要沾惹那些坏习惯。”整整三个小时，潮水才渐渐退下去，我回到指挥部已经反胃得不想吃饭。拿到业主给的两千元现金，我直接开着一辆破摩托车赶往十五公里外的小镇，把钱打了过去。“我把钱打给你了。”我打电话说。“你前天不说没钱么？借的？”我说“是啊”她切地一声，说“你才不会向别人借钱呢，你不会是打牌赢来的吧？”我楞了一下，然后笑:“哈哈，被你发现了。”
凌一尧是一个十足的守财奴，即便她不缺钱，也不舍得在享受消费上花费过多。相处那么多年，她惦记过的名牌东西少之又少，我几乎可以数得过来。她曾经眼巴巴地惦记 IPONE4，我打算给她买一部，但她嫌贵不肯要，最后买了一个 IPOD。她一手举着 IPOD，一手举着那只被时代甩得老远的夏普翻盖，说：“这两个加起来，就是 IPONE 啦，分工还很明确呢！”
我问她：“你干嘛那么节省？”
她说：“怕把你花穷了，以后娶不起我。”
我又逗她：“如果以后咱们俩不在一起，你不是亏大了吗？”
她一边鼓捣着 IPOD，一边随口答道：“那更不能乱花了，万一别的女孩大手大脚的，你更娶不起了。我得给你攒着，不能让你打光棍。”
她当时只顾着玩游戏，没有多想，可是晚上睡觉睡到半夜，她突然一下子坐起来，把我吓了一跳。我问她：“你怎么了？”
她说：“刚才做梦，梦见你白天和我说的话，你为什么说以后咱们俩不在一起？”
我无奈地解释：“我就随口说说而已。”
她把被子往旁边一扯，睡到床的边缘，背对着我，嘀咕道：“以后不许说了，提都不能提。”
凌一尧从未到过海边，她印象中的海滨是蓝天白云软沙滩，海水哗哗地舔脚丫，但我这里是黄海，海水像咖啡一样浑浊，海风达到六七级是起步价。她毕业时曾经想来这里看我，但我没有让她来，只是说我一闲下来就争取回去找她。我怕破坏她对大海的憧憬，怕她嫌弃我十天半个月不洗澡的邋遢，怕她心疼我的嘴巴因水土不服而长出一圈血痂。这里连一个女性专用的卫生间都没有。她到处找工作，尽管姿态摆得很低，却还是屡屡碰壁。有的单位觉得她的学历过高，生怕她呆得不长久，于是不录用；有的则完全将她视为一个普通的劳力，开出的待遇很低；甚至有人觊觎她的年轻漂亮，作出一些暗示。而那段时间，我们正在和当地的一拨人开仗，他们带来几辆渣土车堵路，要包揽这里的活儿，叫我们让出便道工程。若是在城市里碰到这种飞扬跋扈的人，我兴许会躲得远远的，宁可吃一点亏也不去招惹，但这次不一样。我要生活，我赚钱，我要像野狗一样咬死所有抢我饭碗的同类。那场架的参与者大概有四十多人，我们这边是一帮来自天南地北的年轻人，而对面都是当地的流氓。我们这边的人大都是老实的工人和斯文的技术员，要么不会打架，要么下不去手，非常吃亏。我遭到围殴，后脑被狠狠捶了几拳，整个人都懵了，拎起一块木方就挥舞，完全处于混乱状态。那个和我一起守堤坝的小伙子被打急了，他满脸鲜血，一边吼着，一边爬上一台轮式挖掘机。油门一加，斗子的钢齿直接拍扁一辆渣土车的驾驶室，这样一个疯狂的举动，终于镇住那帮地痞，也保住我们的便道工程。事后我才发现，我左手疼得厉害，端不起饭碗。我朋友送我去医院拍片子，虎口骨折并且肌腱撕裂。原本这事我们可以报警，让对方赔偿，甚至以故意伤害罪起诉，但是一旦如此，那个开挖机的小伙子也可能逃不脱干系。
老板说：“这事就算了吧，医药费我们自己付。” 而左手虎口的伤，虽然差不多治愈了，最终还是留下终生的缺陷，大拇指的反应非常迟钝，握拳执物时总是非常别扭。老板叫我不要去鉴定伤残，直接承诺补贴我五万元，有时，我们对于这个社会而言只是一个小小的工蚁，随时可以是一个牺牲品。凌一尧知道以后在电话里哭，叫我赶快回南京，但我没有听她的，固执地留了下来。我叫她再等我一段时间，只要工程结束，我拿了工资分红和伤残补贴金，就完全有能力娶她回家了。
凌一尧向来是一个非常隐忍的女孩，如果不是沉重得让她无法承受的坏情绪，她都不会轻易向我宣泄，顶多闹一闹小脾气就过去了。她终于找到一份算得上满意的工作，每天一个人上班下班，一个人吃饭睡觉。我从镇上搞来一个无线上网卡，夜晚闲下来时会开车开到一个搜得到信号的堤坝上，和她视频一会儿。她每次都会像约会似的认真对待，梳洗化妆，连小房间都收拾得干干净净。由于摄像头和屏幕是两回事，我们轮流看着着镜头，好让对方可以感受被“深情凝望”的滋味。有时我会说：“尧尧，我想要你了。”她说：“来吧。” 然后我们互相抖窗口，这就是相隔数百公里的性爱。有一天，她加班到十点多，往回走时遭到一个变态男人的尾随，无论走得多快，对方都紧随不舍。情急之下，柔弱的她向路边一辆车子求助，司机帮她用远光灯照那个变态，并且大声叱问，那个变态才落荒而逃。尽管安全脱险，但凌一尧受到很大的惊吓，一整夜都没敢睡觉，她打电话与我吵架，问我到底回不回去。我给出的答案与以往一样，做完这个工程至少能带十七八万回去，只要干完就立即回去。但她不依不饶，两人开始争吵起来。最后她说了一句狠话：“我今天要是被人强奸了，你带一百万回来又能怎么样？你口口声声说赚钱是为了娶我，我看你是为了你自己，这样的恋爱谈了还有什么用，有你没你都一样，不如分掉算了。” 那天我陷进淤泥潭里差点丢了小命，被人救援上来腰部以下几乎麻木，从小到大从未受过那样的罪，本来就满腹的委屈，被她这样一说，我也忍不住光火了：“分就分！嫌我没出息的是你，现在埋怨我不在身边的又是你，你以为我想背井离乡在这个鬼地方卖命？既然这样，你去找一个富二代好了，不愁没钱花还天天陪着你，只要拔一根毛就能把你娶走！” 她听我这样一吼，顿时被呛住了，电话那头沉默许久以后她才低声地说：“吕钦扬，你以前不是说过么？我是你辛辛苦苦追来的，几千双眼睛见证的。。。” 她说到这里就说不下去了，带着哭腔挂了电话。而我一下子醒悟过来———高中毕业的那个暑假，我曾经说过，“你是我辛辛苦苦追来的，几千双眼睛见证的，以后只有你甩我，没有我甩你。即使你哪天说了分手，我也不会答应。” 原来她一直都记在心里。
当我年底离开海边，那场异地恋已经持续长达九个多月。这九个月里，我们一个在风急浪高的海边，一个在节奏匆忙的城市，过着完全迥异的生活。我提着行李包从车站里走出来，城市的喧嚣让我觉得无所适从，就像一个流放雪山多年的野人。一看见我，凌一尧的眼圈就红了，她扑上来一把抱住我的时候，周围的人都在好奇地看着，仿佛我们是偶像剧的男女主角。当我走过一面镜子，无意中往里瞥了一眼，这才明白到底怎么回事———我穿着一件我自以为还算干净的军大衣，面部被海风和紫外线弄得又黑又粗糙，头发不自然地翘着，仅仅在路上耽误两天就长出青色的胡渣，完全是一个年轻农民工的形象。而我身边的凌一尧，衣着细致，身材窈窕，化着几乎看不出来的裸妆，完全是一个漂亮得让人忍不住多看几眼的都市女孩。不知道怎么的，她挽我胳膊时，我不自觉地往旁边避让，总是不习惯这样的亲昵。她很快感受到我的疏远，也不再勉强，打车时我们坐在后排，每人坐一边，互相不说话。她带我去买衣服，然后一起去宾馆开房，我洗澡时她帮我搓背，两人赤裸相对时我才告诉她，刚才我突然涌起一阵自卑感。凌一尧努力地搓我身上的尘垢，摸到我后背那条不慎被钢钎剌出来的狰狞伤疤，她用手指轻轻触碰着，许久都没有说话。“早知道是这样，死也不会让你去那里。”她说。我却非常希望她看到我的成就，我洋洋得意地告诉她，我已经和那个公司的领导处得很好，年后可能要被派去乌鲁木齐负责一个项目，年薪十五万。然后我自顾自地描述一个美好的未来，要考一级建造师，要赚更多的钱，要积累更多的经验和人脉，以后还要自己拉工程队单干。但凌一尧对此并不感兴趣，而她是我唯一在乎的听众。那天我们做爱了，我不记得久别重逢时的具体细节，只记得她突然狠狠地咬住我的肩膀，像被夺食的猫一样死死地咬住。我疼得连头皮都麻了，却没有反抗，我知道她心里堵着许多情绪不知如何表达。那两排细细的齿痕至今未消，一直烙在我的左肩，有时我怀疑它是一个诅咒，如影随行，一直延续到我彻底忘记她的那天。
不知道为什么，以往二十五六年，我一向是文艺小青年，但在海边呆了大半年以后，我突然怎么也变不回来了。即便我穿着体面的衣裳，做了好的发型，但几天以后衣裳皱巴巴了，发型也乱糟糟了。我觉得自己像一张被烫皱的透明糖纸，再也熨不平了。最让我无法接受的是，回到正常的人类文明社会，我才发现自己的肤色与周围的同龄人明显区分开来。为了恢复原先的肤色，我买了各种牌子的美白护肤品，每天早晨中午和晚上都要用一遍，甚至在堂妹的指导下学习使用面膜。可是，海边滩涂的紫外线辐射比城市高出数倍，咸海风侵袭下的肌肤就像风腊肉一样，那些措施几乎不起一点作用。我之所以那么焦躁，是因为她的父母又在给她介绍对象，我年底必须去拜会一趟，让他们认可我这个女婿。当我把内心的忧虑告诉凌一尧，她毫不在乎地安慰道：“没事的呀，我就说你是为了养我才去闯的，他们不会为难你的。”她这样一说，我才稍微安心下来，但事实证明，我此生做的最失败的事情，就是将那么重要的拜会搞砸。
大年二十七夜，我拎着几瓶天之蓝登门拜访，虽然她父母很热情，但我总觉得那更多是一种客套。吃饭时她爸爸问到我的学历，职业，以及家庭，我敢肯定这些问题他已经在凌一尧面前问一遍，只是想要我亲口重新给一次答案。这种技巧性的拷问让我非常不自在，但还是毕恭毕敬地回答：我大专毕业，现在做工程，家离市区还有十几公里，父母都是种植花木的农民。她爸爸说做工程赚钱，现在农村人日子过得挺好，她妈妈一直没有表态，只是叫我喝酒吃菜。酒一喝多，我就觉得自己的口风有点把不严了，于是忍住少开口，而她妈妈这个时候提及我这有碍观瞻的肤色。我的心里堵得慌，满是委屈，又不敢反驳，生怕酒劲之下言多必失。凌一尧跑回房间，拿来我以前的照片，解释说我以前不是这个样子，她爸爸则打圆场说年轻人不怕吃苦很难得，又不是天生黝黑。那原本只是一次不太完美的拜会，但下楼的时候，遇到的一件事情让这次拜会变得非常糟糕。我离开时他们送我到楼下，刚好小区里有邻居远远地打招呼，她父母都一起过去握手闲聊，凌一尧和我在原地聊天。但她妈妈很快也把凌一尧招呼过去，向对方介绍这是自家闺女，研究生毕业，在哪里哪里工作。这个时候我才发现，邻居那边有一个年轻的小伙子，皮肤白皙，一身的书生气。凌一尧在父母的指引下叫伯伯，叫婶婶，接受夸奖时礼貌地笑，不时地回头望我一眼。我看着一辆电动车后视镜里的自己，皮肤黝黑，加上酒后的模样，完全不是我自己能接受的模样。我在那里傻傻地站着，不知道该怎么办才好，最后我还是带着一身酒气，沿着墙角自个儿晃了出去。
凌一尧打电话来的时候，我已经坐在出租车里往回走，她问我为什么不辞而别，我呵呵地冷笑。我不敢对她父母表达内心的不满，只能把气撒在她的身上，我故意用冷漠的态度让她内疚，让她知道我不是没有尊严。可我偏偏忘了，那个愿意一边抹眼泪一边默默被我肆意伤害的凌一尧，正是那个唯一在乎我情绪的人。别人都只在意我飞得有多高，飞得有多远，只有她在意我飞得累不累，也只有她希望我停下来歇一歇。可惜，我这样一个贱人，最擅长的就是伤害身边最亲近的人。&lt;/p&gt;
&lt;p&gt;尽管豆瓣有许多人相信星座之说，但我还是坦言，我对此丝毫不信，无法理解为什么可以用出生月份来判断复杂的人与事。但与星座学说相比，我更讨厌别人拿生肖说事，因为网络上的星座学通常是不伤人的马后炮，而生肖说则经常成为棒打鸳鸯的帮凶。同样是出生于虎年与龙年，成人之美者会说这叫龙盘虎踞，而掘坟毁婚者则说这叫龙虎相斗，有人向凌一尧灌输第二种说法。凌一尧当然不会相信这样的无稽之谈，但她妈妈非常固执地将它视为我与凌一尧不合适的理论依据之一。那个时间，刚好我与凌一尧相处得颇为不融洽，彼此明明没有一点恶意，但不知道中了什么邪，说着说着就因为一点措辞之类的小事吵得不可开交。她总是责怪我脾气太犟，而我总是埋怨她当初没有提前公开我的存在，最后不欢而散，一次又一次地验证“龙虎相斗”的说法，尽管之前的八九年都相处得那么愉快。2012 年大年初四，我去市区时打电话给她，她说在寺庙里上敬年香，要傍晚才能回去。可我真的很想她，打算当面向她道歉，化解目前我们两人之间的矛盾呢，于是守在她家楼下的凉亭里等候着。等了三个多小时，我终于看见她回来了，但坐的是别人的车，开车的就是上次那个书生气十足的男人. 车子是本田歌诗图，即便我耗尽当时的积蓄也未必能够拥有. 他们两个人一起下车，凌一尧似乎情绪很好，而那个男的也笑着，手里咣咣地掂着车钥匙。他们一起上楼，凌一尧家所在的那栋楼。我本来打算将她喊住，但直到他们的脚步从楼道里消失，我都没有开得了口。
那种失魂落魄的感觉，简直每分每秒都试图置人于死地，每一次心跳都像锤子在胸口猛敲，我难过得恨不得直接往马路躺下来，谁把我撞死谁就是我大爷。我与凌一尧恋爱的初期，我们都小心翼翼地经营着，有时也会因为一点小事儿生闷气，无端吃醋，生怕人生第一场恋爱夭折。但时间一久，慢慢磨合着，彼此之间竟然如同家人般相互依偎，从不敢想过旧人换新欢，从未想过分离的一天。&lt;/p&gt;
&lt;p&gt;但这一天终于还是来了。
尽管凌一尧说那是长辈们的安排，她个人从未认同，一口咬定我是在无理取闹，但我问她那天为什么和别人一起去敬年香，为什么不直接去拜堂算了，她一下子愣住了，然后说：“你不相信我？” 我想说我当然相信她，但我只是无法忍受她与别人像情侣一样在人前出入，更不能忍受当整个世界都对我发动围剿暗算，而我认为绝不相负的那个人却站在战场的另一边。我的所有姿态，尊严和自信，都一下子垮了，就像《悟空传》里那只猴子一样，被刀劈斧砍雷劈火烧之后只剩一副躯壳屹立不死，但紫霞仙子的一句话，便让那双眼睛再也失去神色。元宵节之前，她父亲忽然打电话给我，约我单独见一次面。&lt;/p&gt;
&lt;p&gt;她的父亲约我在一家茶座见面，我并不知道他要聊什么，但还是努力做了准备，争取让他明白我对凌一尧的感情。
但我坐到他面前，才发现我根本没有为自己辩护和自荐的机会，她父亲几句话就将我堵得死死的。他说:“这段时间我虽然没有过问你们的事情，但我也看得出来，你和尧尧处得不好，她经常躲在房间里哭，不吃饭，两个人连相处都不好，还怎么一起生活？”他又说:“我选这个位置，就是想让你看看这个路口，今天还算天气不错，但雨雪天呢？严寒酷暑天呢？别的女孩坐在车子里打着空调，我们家尧尧坐在你摩托车上淋雨顶风晒太阳吃尾气？我们不是势利也不是物质，只是希望她过得好。”我终于抢话说:“我不会让她受穷，我会去赚钱，我已经有二十多万了，以后我也可以让她过上好日子！”她爸爸呵呵笑了一声，说:“以后？你没有权力要求别人等你一个空头支票啊。”
而后，她爸爸还说了其他一些东西，譬如我和她站在一起就没有夫妻相，她母亲也不希望凌一尧嫁给一个包工头。
但我已经无力听下去了，脑子里只是想着大二那年我们一起去周庄玩，吃饭时旁边一个话唠老太和我们搭话，啧啧地赞叹我们是金童玉女，以后生出来的小宝宝一定也很漂亮。当时凌一尧红着脸一直笑，而我闲得无聊与老太太扯，老太最后一拍大腿去择菜去了。当时我心口压抑得难受，担心自己一个黝黑的爷们儿当众哭出来，站起来不服气地对他拱了拱手，转身去前台结账走人。我当时心口堵得慌，胸口压着一块巨石，像一条狼狈的狗一样微微张着嘴巴，呼吸困难且短促。&lt;/p&gt;
&lt;p&gt;那段时间，凌一尧的日子也不好过。她明确拒绝他人的安排与介绍，每天不洗漱打扮，更不出门，用这样的方式向我证明自己的立场。为此，她与母亲发生激烈的争吵，闹得左邻右舍都议论纷纷，她母亲患有支气管炎，春节还没结束就住院了。但我又能怎么办？虽然她父亲还没说完，我就起身离开了，但我明白他此行的目的绝不是对我羞辱或是嘲讽，而是要我与凌一尧停止交往。我过得黑白颠倒，不知道自己为谁而活，活着到底有什么意义，脾气变得极其暴躁。早在 2008 年，我妈妈就已经见过凌一尧，她知道我遭遇怎样的事情，几次自责自己没本事，没有为我积累财富。我没有安慰她，也没有责怪她，只是一个人独自发呆。我把所有罪责都归结到自己是一个穷小子的原因上，也是从那段日子开始，我对金钱产生无比执着的痛恨，以及无比狂热的向往。刚好朋友打电话过来，约我一起去乌鲁木齐参与一个太阳能发电站的工程，但需要提前垫资。我几乎没有犹豫，一口答应下来，决定把我和我父母所有的积蓄一起带上，孤注一掷。事到如今，我已经没有什么好畏缩的，我连凌一尧都输了，还有什么输不起的？大不了哪天形影相吊，身无分文，找一个安静的地方了结这条可笑可悲可怜可耻的贱命。临行之前，凌一尧打电话过来，她说：“吕钦扬，我们分手吧。”只是简单一句话，不由我分说，她便直接挂了电话。不知道为什么，我心里竟然一点痛楚的感觉都没有，麻木得就像一块死肉，直到许久之后手机再次震动，我才醒悟过来。凌一尧在短信说：“刚才免提说给我妈听的，你不要当真。你今天去订票，我们一起回南京。”我一下子精神起来，回复说：“要什么时候的票？”“明天中午，好吗？”她像在哀求我。我当即开摩托车赶去车站，一路狂飙七八十码，订了第二天中午 11 点 20 分去南京的长途车票。当时我的内心掺杂着各种情绪，疑虑，自责，兴奋，欣慰，以及被全世界围剿时与她一同突围的悲壮。&lt;/p&gt;
&lt;p&gt;第二天上午十点我就在车站外面等候着，手里捏着两张车票，既期待又忐忑，就像守在高墙外即将与主公家千金私奔的狗奴才。&lt;/p&gt;
&lt;p&gt;凌一尧一开始还低声和我打了电话，说等会儿就出来，但两个短信之后，便再也没有动静。我有些焦急，但又怕在不恰当的时刻打不恰当的电话，于是耐心地继续等。11 点 20 分过去了，车子发动了，她还是没有出现，我捏着两张过期车票傻傻地站在那个空空的检票口。大约十一点半，她终于发来短信，说:“你直接来南京，我已经在路上了。”我不知道发生什么事情，猜想今天的她一定处境混乱，于是顾不上多问，赶紧重新买了最近一班的票。
我颠簸一个下午，到达凌一尧那里已经快到下午七点。我们避开那些不愉快的话题，就像以前一样一起拥抱，亲吻，然后去外面吃饭。那是我第一次请她吃西餐，也是我第一次吃西餐。当厨师把牛排端上来，说他要揭盖子了，而我木然地看着他，不知道他揭盖子与我有什么关系。凌一尧解围说:“先帮我揭吧。”她把红色的餐巾挡在面前，厨师揭开盖子，油星点四溅，被餐巾挡住。我当时才想起来，这步骤我以前是知道的，只不过在外面呆久了，早已忘记。那厨师望了我一眼，又看了凌一尧一眼，虽然面无表情，一句话都没讲，但不知道怎么了，我就是莫名其妙地多想了。晚上我住在她那里，那个我们曾经一同经营的小家。与以前一样，我们一起打扫整个寒假都没人住的房间，一起铺床套被子，然后轮流洗澡，最后在床上拥吻做爱。那天我有些蛮横地占有她的身体，她似乎感受到我的情绪，一直咬着嘴唇默默承受着，但我准备退出去戴套时她却搂住我的脖子，说:“就在里面！”我问:“安全期吗？”她低声地说:“不是。”我看着她的眼睛，她目光坚定，她的手指紧紧地抓着我的肩膀，指甲嵌入肌肤，仿佛已经决定破釜沉舟，再也不回头。&lt;/p&gt;
&lt;p&gt;那天晚上十一点多，我们都没有睡着，在被窝里牵着手，讨论以后的安排。我说我想去乌鲁木齐一趟，大约五个月的工期，只要赚到这笔钱，我就可以大大方方站在她的父母面前，用事实证明我可以让凌一尧过得好。凌一尧听说我将全家所有积蓄都搬出来拼，建议我不要去冒险，希望我在南京找一份工作。我问道：“如果我不去赌一把，守着一份少得可怜的工资，你父母永远不会瞧得起我。” 她说：“万一输了怎么办？” 我一下子被问住了，因为我当时对金钱财富充满狂热，就像一只饿极的猴子，敢于去抓万丈悬崖边的一只野果。我没有回答她，只是把她拥在怀里，把脸埋在她柔顺的长发里呼吸，一阵恐惧涌入心底。我赌输了怎么办？ 兴许我会一死了之，把这具臭皮囊丢在新疆的戈壁滩上喂野狗吧。正是在这个时候，她母亲打电话过来，凌一尧打开台灯，忐忑不安地接听，那头的声音也被我听得分明。她母亲询问她有没有安顿好，晚饭在哪里吃的，什么时候上班，最后才兴冲冲地说：“罗 XX 这孩子真不错，今天特意把你送到南京，回来时还给我带了南京的盐水鸭，真是很勤快。” 凌一尧很尴尬地看我一眼，敷衍道：“哦。” 然后她妈妈又说：“你和那个吕钦扬分了就分了，不要再有来往，纠缠不清的惹闲话。这个罗 XX 条件不错，又是知根知底的，你们俩再处处，平时多打打电话，或者上网聊聊，总会处出感情的。” 凌一尧只是嗯嗯地应着，不敢抬头看我了。电话挂断之后，凌一尧翻身过来抱住我，在我胸口蹭来蹭去，叫我不要介意，她只是敷衍一下而已。我的心情就是非常沮丧，甚至觉得躺在这张床上是一件很不道德的事情，我说：“你现在怎么有那么多事瞒着我？” 凌一尧说：“你以为我愿意藏那么多事？我妈问我有没车票，我说没有，她就叫罗 XX 送我了，我不告诉你是怕你多想，不肯来南京找我。” 可我那可悲的自尊心又开始作祟，脑子里老是想着她和那个人坐在那辆歌诗图里，而我像一个傻逼似的坐在长途客车上。我没有责怪她的意思，我只是恨自己为什么总是处于下风，为什么那些人非要这样巧取豪夺。凌一尧又是安慰，又是发誓，甚至不停地挑逗我。以往她惹我生气了，只要这样一挑逗，挠我的痒痒，我便翻身将她扑倒，一场小矛盾便化为乌有。可惜，这次不奏效。她思索片刻，翻身趴到我的胸口，说：“吕钦扬，如果下个月有个人不来找我，我希望你能尽快赶回来，好吗？” 我一下子风声鹤唳地紧张起来，问道：“谁？罗 XX？”她平静地说：“我大姨妈。”我一时没反应过来，她又补充道：“或者我找你去。” 我这时候才反应过来，一把将她拥入怀中，恨不得把她勒得窒息。凌一尧呀凌一尧，我喜欢你喜欢得恨不得为你去死，我想把我赚来的每一分钱都交给你花，我想让你这辈子都不受半点委屈。我不想远走他乡，我不想颠沛流离，我不想每天早晨一睁开眼睛就很失落，不知道你在哪里，心情如何。我想你啊爱疯飞饿啊将发往放 PJGFKCFOIAF 哦额坟挖金风科技啊绝非挖掘啊我佛架飞机哦额外 JPAWFJO AWIJGFAWJI AFGE A FEO KPFWO XIANG NI A A OA AF FAW FA F OF 哈哈复合肥哈额发发火佛 QFA Q 飞饿肌肤 iaf 哈哈哈爱好哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈啊哈哈哈哈哈哈哈哈哈哈哈哈哈啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 (这里一段乱码就是原文估计 LZ 写到这里戳到痛处咯）。&lt;/p&gt;
&lt;p&gt;那天凌一尧送我去车站，但她连候车大厅都没有进得去，两个人在安检口就仓促地分开了。我本来想再回头与她告别，但门口拥堵着太多旅客和工作人员，我们只能隔着长长的通道望着，最后打着手势，两人在玻璃幕墙内外杵着。我们互相听不见对方的声音，只能面对面地打电话，就像囚犯与探监者一般。她说：“我昨天把重要的东西都收拾在包里了，打算今天一直送你到站台，兴许到时候一咬牙就直接跟你一起上车，一起去乌鲁木齐。”听着她这有些孩子气的话，我不禁苦笑一声，问道：“你这是想私奔么？” 她却将脸凑近玻璃，认真地说：“我没有开玩笑，我真想过了，我也做得出来。”我伸出手指在玻璃上刮了一下，就像以往刮她鼻尖一样，检票口通知检票时，我在玻璃上哈气，写了两个反体字：“等我。”我不喜欢南京车站，我讨厌一切为了管理方便而设定的有悖人情的垃圾规定。从南京到乌鲁木齐，一共 41 小时，我睡了又醒，醒了又睡，做着各种各样的梦。其中一个梦最为蹊跷，当时一个列车员推着小车来售卖零食饮料，我刚好迷迷糊糊地睡着，做了一个非常奇怪的梦，梦见自己又回到高三，我和凌一尧迎面走来，她的嘴角洋溢着微微的笑容，我走过去大声地说：“凌一尧，我们以后会在一起，十年，我们以后还要结婚！” 然后凌一尧骂我是流氓，周围的同学都笑，连大乔和子石都笑，我非常生气地告诉他们俩这是真的。不一会儿，姚千岁大老远地跑过来，手里拎着一个棍子，我就没命地跑。按理来说，梦里的人不会跑得快，可我跑得非常快，甚至能感受到头发被风扯得嘶嘶作响。我就那样一直跑着，感觉这辈子都要用来奔跑，我很快乐，我要大声地笑。旁边人的声音陡然提高，我一下子从梦里惊醒，发现那列车员竟然仍然推着车子往这里走，前进距离不超过五米。当时我突然想起一个悲观的故事：黄粱美梦。我真希望自己这辈子一直活在那个梦里，被姚千岁追赶着，拼命地逃命着，全校学生都在笑着，教学楼阳台和路边都黑压压地站着一大片，就在围观运动会上的三千米长跑。那时候的我还是一个勇敢的少年，而凌一尧也是一个羞涩文静的少女，我们所有的爱情都藏在那一次次擦肩而过，沉默不语的微笑里。
新疆的戈壁滩，开春之前的积雪淹没小腿，我戴着银行劫匪般的头罩，裹着又长又厚的军大衣，扛着沉重的仪器，在荒野里深一脚浅一脚地跋涉。海边是湿冷，这里则是干冷，但温度低得出乎我的想象，我的嘴巴不停地开裂。夜里盖着被子时脚上的冻疮痒得难受，只能伸在外面冻一会儿，冻醒了再缩回被窝里暖一会儿，痒醒了才伸出去冻。凌一尧想给我寄冻疮膏，但快递根本不可能送到，我这里太偏僻了，连蔬菜和肉都要从很远的地方拖过来。一拖就拖一卡车，一吃就是大半月。一起在这里混生计的也有与我差不多年龄的，农民工耐得住吃苦，但那些细皮嫩肉的年轻人都熬不住，没呆几天便跑得光光的。幸好我在海边干过大半年，那边的条件比这里好不到哪里，早就习惯了，何况我已经没有退路。过了没多久，凌一尧打电话告诉我，例假来了，孩子没来。她显然有些沮丧，而我说不清自己是什么心情，也不知道自己应该怀有怎样的心情。她家里还是极力试图促成她与罗 XX 在一起，我们之间偶尔还会因一点小矛盾而争吵，我的脑袋像被门板夹过似的，明明知道她与我一起抗争着，可还是忍不住一次又一次通过这种拙劣的方式来向自己证明她没有离我而去。由于工地的 GPS 仪器出了故障，我们不得不利用原始方式定位高度。我背着二十公斤的全站仪，拿着对讲机，跑出很远去寻找被大雪淹没的原始基准点。不料，我走着走着就迷失方向，我以为可以摸回营地，不料最后我连自己的脚印都找不到了，而对讲机那头的那帮人根本无法判断我的方位。这是我以往在海边从未遇到的状况，有种被人类世界抛弃的恐慌，我不敢乱走，叫那些工人赶紧回营地找人救援。但直到晚上九点，夜色已然降临，四周只剩白雪映出的冷光，还是一点进展都没有，对讲机里满是男人们乱哄哄的争吵。我以为自己的小命会丢在这里，只能背朝肆虐的寒风，用大衣裹住身体，拼命维系最后那点体温。我掏出手机给凌一尧打电话，但要么就是信号全无，要么就是无法接通，连他妈的他妈的他妈的他妈的短信都总是他妈的他妈的他妈的他妈的他妈的他妈的发送失败。我平生第一次发现自己是一个胆小鬼，这样怕死，我怕我死了以后父母没人照顾，怕自己无法被及时发现，怕凌一尧见到的是一具面目全非的残骸，更怕自己像狗一样无人问津地曝尸荒野，葬礼上连一个为我哭泣的人都没有。凌一尧啊凌一尧，如果我真的死在这里，请呼唤我的名字，把我的灵魂带回故乡吧。
我找了一个地势稍高的土坡，将全站仪加在坡顶，以便尽早被人发现，然后躲在北风面的凹处，能活多久就活多久。我不知道自己能不能熬过去，做好最坏的打算，用冻得几乎失去知觉的手横握着笔杆，借着雪地映出的微光，在施工日志的中页写遗书。我在这里投了多少钱，外面还有谁谁谁欠我钱，我又欠谁谁谁的钱，我的户口还在学校里没拿回来，如此而已。我本来想说对不起父母，早走一步，劝凌一尧不要悲伤，下辈子有缘再见，但我歪歪扭扭地写完那些账目，再也没精力写字了。我蜷缩在那个角落里，脑子里开始胡思乱想，想着我要是即将失去意识，应该用什么样的姿势才显得体面安详一些，不至于狼狈潦倒。有时我觉得这身体已经完全不属于我自己，四肢像木头一样无知无觉，心脏是性命寄生的最后一块阵地。也是在这个时候，我依稀听见上风口传来发动机的声音，还有人高声呼喊，以及雪地里沙沙的脚步声，随后有人从身后的土丘上冲下来，蹲在我旁边一边喊我名字一边拍我的脸。我感觉自己像被人摁在水里，所有的声音都含糊不清，灯光尤为刺眼，看不清他们到底谁是谁，也不知道自己到底算是获救了，还是正在垂死。他们把我抬起来往上一提，我整个人就像飘进太空的一块废料，所有的意识都跟着失重地飘着。他们把我抬进开着空调的车子里，盖上厚被子，让人揉捏我的四肢，不停地呼喊我，叫我保持清醒：“吕工，吕工，吕工……”我恍恍惚惚地就听见一个熟悉的声音：“吕钦扬，吕钦扬……”我一下子坐了起来，拼命地推开那些工人，瞪大眼睛努力地四处观望，发现根本没有凌一尧的身影，又颓然地倒了下去。后来，那些工人和我喝酒时经常拿这事开玩笑，说他们当时被吓了一跳，以为我是回光返照，以为我是听到勾魂小鬼的点名。我一边喝酒一边嘲笑他们的迷信愚昧，哈哈哈哈哈哈哈哈。呵呵。医院离这里太远，我被带回营地以后烤了一会儿的火也就缓过气来，他们便让我躺在床上休息，专门让烧饭的老头子来伺候我。我一觉睡到第二天下午才醒，掀开窗帘看见一轮咸鸭蛋黄般黯淡的红日，凌厉的冷风吹得活动板房的单层玻璃呜呜作响。我喝了热汤，让老头子给我手机充电，然后给凌一尧打电话。电话一通，她便问我昨天在干嘛的，为什么只打了一声就挂了。我说我昨天差点丢了命，连遗书都写好了。凌一尧似乎不太相信我的话，她说：“你到底是去工作还是去打仗的，为什么会有生命危险，如果真的那么危险那就回来啊！”面对这样的责问，我不知道如何应答才好，我已经把自己所有的积蓄都投入这场豪赌，怎么可能因一场意外而举手投降。我在这里扛住雨雪风霜，就是为了让她此生都活得安逸，我只希望她此生都不必感受生活的艰辛，哪怕一辈子都无法理解我此时的狂热。随后她告诉我，她父母托人在我们那个城市给她找了一份新工作，待遇相当不错，催她回去工作。她知道，这样的安排无非是让她离罗 XX 更近一些，更好地掌握两人之间的动向，于是她努力地抗争着，一天一天地拖着。她说：“今天我妈妈说了一句话，我哭了好一会儿。”&lt;/p&gt;
&lt;p&gt;我问：“她骂你了？”她说：“不是。她说‘树欲静而风不止，子欲养而亲不待’，叫我不要等她哪天不在了，才后悔现在没有尽孝。”我愣了好一会儿，突然意识到“疏不间亲”，无论我多爱她，我的地步都很难逾越她的父母。这就是我拼死拼活地卖命，恨不得拿把刀坐在市场中央割肉兜售的结局吗？我强忍左胸口的酸痛，问道：“你想回去了？”凌一尧沉默片刻，而后低声说：“我会尽力扛。”尽力扛，只是尽力扛。呵呵。她能够与我一直走到现在，已经是仁至义尽，我没有权力要求她必须永远与我坚持到底，爱情不是靠绑架得来的。我把烧饭的老头子支了出去，然后向她保证我很快就能出头了，我们可以过得非常幸福，可以让所有人都惭愧他们现在的阻挠. 我感觉自己当时的口才出奇地好，比以往任何时候都好，用亢奋的状态向她描述一个美好的未来，完全不像一个从鬼门关回来的人。但凌一尧只是安静地听着，缄默得让我一度怀疑她是否还在电话那头，我不得不傻逼兮兮地“喂”“喂”“喂”。她只是微微的叹息一声，说：“可是，我已经很累了呀。”那一瞬间，我感觉自己的天空猛然塌陷一块，自以为永远不会动摇的精神支柱摇摇欲坠，电话另一头那个让我魂牵梦萦的女孩突然变得无比陌生。我可以相信日出西方，相信江水倒流，相信六月飞雪，就是不能相信凌一尧也会决心动摇，也会有打算离我而去的一天。我忽然发现自己在雪地里对死亡的胆怯显得那么可笑，吕钦扬啊吕钦扬，你拼命地熬着忍着撑着盼着等着，终于保住这条下贱卑微的狗命，迎接你的现实就是这个模样么？生亦何欢，死亦何苦，早知道这样，为什么不干脆听从命运的安排，在老天为你选择的那块埋骨地了结此生算了？你怎么不死掉算了？你干嘛不死掉算了！！！！你死掉算了好不好！！！！啊哈哈哈哈哈哈！！！！！！！也是在那一天，我和凌一尧之间的裂纹越来越明显，分道扬镳的日子不期将至。在戈壁滩的那段日子，我忙得不可开交，要么在施工现场东奔西跑着，要么趴在电灯泡底下看图纸，要么与工人们混在一起喝酒。偶尔闲暇下来，我傻傻地坐在房间里看着床头那个日历，一遍又一遍地推算工程完工验收的日期。另一个工程队的项目部有一台电视机，外接信号锅的，偶尔我会去那里看一会儿电视，特别喜欢看江苏卫视。不是看非诚勿扰，也不是看电视剧，只是想看一下镜头里的街景。有一天，一个专题节目介绍我家乡的特产，我硬是死死地抓住遥控器，将那帮想看抗日连续剧的家伙晾了十几分钟。最让我万分痛苦的是，凌一尧似乎对我越来越冷淡，以往她接电话时都是兴高采烈的，现在却是问：“什么事？”“你至于这样故意伤我么？”我终于不满地问.“我有吗？”“你态度这样冷淡，是不是不愿意接我电话？”她说：“我们总不可能一辈子都像初恋时那样火热吧，总有一天，你接到我的电话时会不耐烦，握我的手时也毫无感觉。”我呵呵地笑：“可能你说得对吧，但那是第几个十年呢？”凌一尧沉默许久才说：“我妈闹我闹得很凶，一闹就犯气管炎，她都要拿断绝母女关系说事儿了，我能怎么办？我以前一直觉得自己过得很好，家庭和睦，爱情美满，学业也很顺利。可是现在呢，家庭，爱情和工作都乱糟糟的，每天夜里都失眠，早上一睁眼又想着怎样把今天熬过去。我真的很累，太累了。” 我从未见过凌一尧这样暴露自己的脆弱，可我不知道如何安慰，因为我自己的心空得像一个深不见底，连回音都没有的峡谷。我很想将她牢牢抓住，可我又觉得自己像在与她的家人打一场拉锯战，每个人都打着爱她的旗号不肯撒手，却从未有人在乎她夹在其中被撕扯得多痛苦。我说：“既然你这么为难，那就不要勉强了，回去吧。” 凌一尧愣了一下，问道：“这是你说的？” 我深呼吸一口气，努力将泪水咽了回去，说：“我说的。” 电话那头一片沉寂，而后挂断了。此后的很长时间，我们谁都倔强地不肯联系对方，直到有一天南京的房东打电话给我，问我另一把钥匙在哪里，我才知道她已经退掉房子，回家去了。我离开戈壁滩的时候积雪正在消融，我把手里的数据都交给项目部，连同那本撕掉遗书的施工日志，而我带来的垫付资金暂时只能抽走不到一半。一个关系不错的朋友开着破旧的越野车把我送了出去，一路打滑，一路颠簸，一直把我送到火车站。&lt;/p&gt;
&lt;p&gt;从南京到乌鲁木齐，背离朝阳，冲向黄昏，而从乌鲁木齐与之相反。那四十多小时里，我一直稀里糊涂地想着心事，日落时怀疑自己离太阳越来越远是不是一个不详之兆，日出东方时又在期待这是预示我可以拥有走出困境的幸运。我很无助，感觉自己的力量微弱得几乎渺小，只能寄希望于这些毫不相干的启示。我辗转回到那座城市，没有回家，在车站旁边的宾馆住了下来。我洗澡剃须换了干净衣裳，试图逼着自己睡一会儿，好让自己与凌一尧见面时精神状态好一点。可是，我又困又累，却怎么也睡不着，一闭上眼睛就心慌气短，仿佛有人在我耳边敲着锣鼓大声聒噪:“她要离开你了！她要离开你了！”凌一尧知道我回来了，我们约在安定广场见面，面对面站着，她看着我的眼睛，说:“怎么那么多血丝？多久没睡觉了？”我不知道怎么回答，因为我最近一次超过四小时的睡觉就是从戈壁雪地里捡回小命后近乎昏厥的长睡。旁边有很多小孩子穿着旱冰鞋跑来跑去，我们生怕被撞到，于是坐到旁边的长椅上。我告诉她，我每天都很想她，已经把新疆的工程丢下了，不想再离开她了。她皱起眉头，问:“你不是在那里垫资了吗？丢下那里，你以后怎么办？”
我有些不高兴:“你希望我回去？”她想了想，低叹道:“我怕你人财两空，不值得。”我顿时不知道怎么说了，不停地揣测她这句话到底什么意思，可我的脑子处于混沌状态，不知道该往哪个方向思考。她随后又说:“前段时间，我和我妈吵了，把她气得犯病，我外婆都打电话过责备我，问我是不是打算闹得家人不相认，以后逢年过节都不想回家团聚，给祖宗磕头。”她抬眼看我的时候，眼泪一下子流出来，委屈地说:“我外公去年去世，今年清明节应该扫墓的，可我躲在南京就是没回来，你难道还不理解我？我小时候是外公外婆带大的，他们都说我忘恩负义，白眼狼。”我一边帮她擦眼泪，一边抚慰道:“我这个工程一结束就有钱了，我去买车，我们去给你外公磕头，挨家挨户拜访你家亲戚，我也可以很孝敬你的长辈。”她推开我的手，自己擦掉眼泪，说:“你忘了吗？我和你已经是地下恋爱了，我和罗 XX 从年初开始就是名义上的交往，我现在已经回不去了啊！我回不去了！”我们回不去了？我迷茫地看着凌一尧那张脸，那张曾经给我温柔也给我力量的面容现在满是悲伤与决绝，这也是十年来我第一次感受到近在咫尺却远在天涯的无奈。我许久才缓过神来，问道:“你要我怎么办？”凌一尧低头沉默一会儿，说:“我很累了，扛不住了，给我自由吧。”我感觉自己像被人狠狠地砸了后脑，眼前一片黑，但还是努力站起来点头说:“好，听你的。”“你会恨我的吧？”她也跟着站起来。我咬住嘴唇尽量让自己不要说话，那么多小孩子在旁边，不要当众丢人，只是张开胳膊把她搂入怀里，狠狠地抱了一下，最后一次嗅了嗅她长发的香味，然后扭头离开那个广场。凌一尧啊凌一尧，我曾经发誓要为之遮蔽风雪，此生疼爱和保护的女孩啊，你才是世界上最强大的人，你拥有轻描淡写一句话就可以将我抽空灵魂放逐天际的神力啊！从今往后，我该往哪里走，该为谁而活，我该怎样面对那么漫长那么漆黑那么毫无意义的人生啊？&lt;/p&gt;
&lt;p&gt;随后的一个礼拜，我过着这辈子最潦倒的日子。我暂时不想回新疆，也不想去找那些熟知凌一尧的好友，但我已经把家里所有的积蓄都砸在项目上了，所以不敢回家见父母。我一直在宾馆里睡着，拉着窗帘，没日没夜地睡，实在饿得受不了，就干啃房间里本来就有的桶装方便面。&lt;/p&gt;
&lt;p&gt;我以为自己呆在这个城市可以做些什么，但事实上我根本无从改变眼前的现实，凌一尧没有再给我发一条短信，打一个电话，我也没有再去联系她。于是，我决定出去走走。&lt;/p&gt;
&lt;p&gt;这几年来，我一直在走，从江苏走到新疆，从荒凉的沿海滩涂走到更荒凉的戈壁滩。但我从未迷失方向，即便走在只知前后左右不知道东南西北的风雪里，我心里也依然竖着一座高高的灯塔，依然有人期待我的归去。可是现在，灯塔的光亮彻底消失，我再也找不到回去的路了。&lt;/p&gt;
&lt;p&gt;我独自回到南京，去找以前那间房子，房东尚未将它租出去，我恳求他让我呆一晚。凌一尧离开时将房子打扫得干干净净，一些被遗弃的生活用品被整整齐齐地摆在角落里，蓝色的毛巾牙刷杯子都是我的，红色的都是她的；床头靠背还贴着当初我从新袜子包装上面撕下来的标签，她总是因此而数落我“幼稚”；台灯罩上有她用唇彩画的卡通脸，咧着嘴，没心没肺地笑着。&lt;/p&gt;
&lt;p&gt;没有被褥，我只能裹着衣服躺在硬床板上，开着电视睡觉。我总是迷迷糊糊地听见她的声音，每次都猛然惊醒，却发现只是电视的声音。我真希望我所经历的只是一个噩梦，真希望我醒来时看见她正在阳台晾晒衣裳，黄昏余晖映出她可爱的身体轮廓，或者她忽然推门进来，手里提着的塑料袋还贴着超市的标签。可是她已经走了，不会再出现了。&lt;/p&gt;
&lt;p&gt;第二天上午，我独自站在镜子前洗漱，将红色和蓝色的牙刷放在一个杯子里，然后带上房门离开。那天我重新踏上前往乌鲁木齐的火车，从此孑然一身，无牵无挂，这个躯体是行尸走肉，这颗心不再属于凌一尧，而这条命我敬老天爷。&lt;/p&gt;
&lt;p&gt;回到戈壁滩，别人问我事情处理得怎样，我嘿嘿地笑着说一切妥当，一副无比幸福的模样。我不是可怜虫，我不需要博取所谓的怜悯，我已经丢了灵魂，但尖牙与利齿还在，我可以参与残酷的争夺。&lt;/p&gt;
&lt;p&gt;我变成工地上脾气最古怪的人，工作时精力充沛，休息时嘻嘻哈哈，但监理都对我敬而远之，因为我一会儿像哈巴狗一样对他们点头哈腰叫爷爷，一会儿像疯狗一样对他们凶相毕露，甚至趁着酒劲追打吹毛求疵的小监理。合伙人经常数落我，却又纵容着我，因为他们不方便与别人翻脸，他们需要我这样的疯狗。&lt;/p&gt;
&lt;p&gt;只是，一闲下来，我就开始发呆。同事开玩笑说，我是“墙角里的一根打狗棒”。&lt;/p&gt;
&lt;p&gt;我们经常会请业主或者质监站之类的人吃饭，我每次都咋咋呼呼，哗众取宠地说着各种庸俗的荤段子，然后拿出同归于尽的架势来喝酒，一杯接一杯地死磕。所有人都夸我海量，年轻有为，前途不可估限，但我知道，酒场和官场都是谎言的集散地。&lt;/p&gt;
&lt;p&gt;我蹲在一望无垠的戈壁滩上吐，然后趴在地上哭，旁边的同事都开心地笑，所有人都知道我酒劲上来就会哭，却没人知道我到底在哭什么。那几个月里，我与她完全没有联系，似乎这辈子都老死不相往来。我在遥远的新疆数着每一次日升月落，期待将她遗忘的那天，可是一旦每次喝得酩酊大醉，每次从噩梦中惊醒，我都会疯狂地想念那个熟悉的名字。&lt;/p&gt;
&lt;p&gt;可是酒醒之后，站至人前，我还得每天强颜欢笑，听别人讲我酒后的失态模样有多么傻逼多么傻逼多么傻逼，然后我和他们一起笑得直抹眼泪。&lt;/p&gt;
&lt;p&gt;那里的生活极其枯燥，业主项目部的司机小廖用 U 盘传给我一些歌曲，我把那些它们一股脑全装进手机里，从凤凰传奇到维塔斯，从摇滚到红歌，我毫不挑选地挨个儿听过去，在空旷的戈壁滩上一边开车一边高声嚎唱。&lt;/p&gt;
&lt;p&gt;唯独有一首歌让我不得不将车子停在路边，捂着胸口，趴在方向盘上缓气———五月天的《你不是真正的快乐》。&lt;/p&gt;
&lt;p&gt;电力企业是一个不差钱的豪门，但不包括 2012 年在建的太阳能发电站，由于欧美对中国光伏产品的反倾销制裁，光伏电站顿时陷入资金泥潭。新疆戈壁滩的气候恶劣，通常四月份才能正常开工，十月底就完全不具备施工条件，我们提前一个月冒着冰雪和低温开工测量放线，终于在十月基本完工。&lt;/p&gt;
&lt;p&gt;此时的业主暴露资金极度短缺的问题，他们的注册资金是会计师操作出来的，而银行又盯着上头的政策，不敢轻易贷款。于是，我们的工程款没了着落，业主方拿资料审核说事，一天一天地拖着不肯验收。&lt;/p&gt;
&lt;p&gt;我带着工人将业主的车子堵在工地不放行，派出所的民警一趟又一趟过来协调，反反复复八趟之后，连派出所都不太愿意来了。最终我们去骗业主里那个稍微老实的负责人，说暂时只要签字验收就行了，今年不会催要拖欠的工程款，他们刚好不堪其扰，不得不把字签了。&lt;/p&gt;
&lt;p&gt;这个社会，老实人都是要吃亏的。签字的第二天，我们的人挤满整个业主项目部的办公室，拍着桌子催要工程款，把那个女文员吓得躲在角落里哭。我拿着一大把小锁，将他们办公室里的抽屉和资料柜都挂了锁，但挂到那个女文员那边的时候，我看见她的抽屉里摆着一只玻璃罐子，里面摆着五颜六色的许愿星，而她的桌角还有许多未完成的折纸。&lt;/p&gt;
&lt;p&gt;我忽然想起来，凌一尧也曾经为我折过这个东西。&lt;/p&gt;
&lt;p&gt;我像一个张牙舞爪的孩子被大人狠狠地扇了一耳光，陡然发现自己失态时的丑陋，我为什么会变成这样？曾经那个善良的温和的喜欢恶作剧从来不忍心伤害别人的吕钦扬哪里去了？这个一脸狰狞拍桌挂锁满口脏话的吕钦扬又是从哪里来的？&lt;/p&gt;
&lt;p&gt;我没有锁那个女文员的抽屉，默默地走出那间拥挤的办公室。&lt;/p&gt;
&lt;p&gt;十一月中旬，大雪封路之前，我提前离开戈壁滩，返回阔别半年的家乡。也是在到家的当天，我踌躇许久后终于鼓起勇气拨通那个熟悉的号码，她听到我的声音一下子愣住了，叫我稍等一会儿，然后跑回房间接听。&lt;/p&gt;
&lt;p&gt;我说：“没想到你这个南京号码还通着。”&lt;/p&gt;
&lt;p&gt;她说：“我每个月只交一点钱维持不停机，可惜一直没人联系这个号，这几天还在想着把这个号停掉算了。”&lt;/p&gt;
&lt;p&gt;我愣了一下：“等我的？”&lt;/p&gt;
&lt;p&gt;她没有说话，不肯定也不否定。&lt;/p&gt;
&lt;p&gt;我说不禁喜出望外，迫不及待地向她展示自己柳暗花明的现状：“我已经回来了，我也赚到钱了，不是穷小子了！你不是喜欢甲壳虫吗？我们去买一辆！还有开一家书店，我们可以去物色店面！我以后除了和你出去旅行，再也不出去逛荡了，我很想你，我每天都很想你……”&lt;/p&gt;
&lt;p&gt;我自言自语似的说了一大堆的话，想狗等待主人筷子上那块骨头一样渴望她点一下头，然后我开着摩托车狂飙过去拥抱她，我的人生从此完美无缺，我每天都要向苍天和大地感恩戴德。&lt;/p&gt;
&lt;p&gt;可惜，凌一尧低声打断道：“我已经订婚了。”&lt;/p&gt;
&lt;p&gt;我一下子愣住了，再也蹦不出一个字，甚至忘记收起脸上因对未来的憧憬而不知不觉地流露出的笑容。订婚了。。。未婚妻。。。妻。。。我难过得忍不住蹲了下来，用拳头抵住胸口狠狠地摁，试图抑制内心如同比万千虫蚁啃噬的痛楚。&lt;/p&gt;
&lt;p&gt;凌一尧啊凌一尧，你真会开玩笑啊，你怎么可能告诉我这样一句话？你还是扎着马尾辫的高中生啊，你不是要跟我一起气死姚千岁吗？你不是说“妻”这个称呼好别扭可是你又很期待成为我的这个字吗？你不是说一想到这个世界终将诞生一个或者两个拥有我们两人血脉的孩子就会觉得神奇又激动吗？&lt;/p&gt;
&lt;p&gt;我不坚强，我不自信，我不要脸，我是一个贱人，我想和一个无赖的孩子一样躺下来蹬腿哭喊，把自己全身弄得满是尘土，你回答我：你！！！！！！为！！！！！什！！！！！么！！！！！！言！！！！！！而！！！！！无！！！！信！！！！！&lt;/p&gt;
&lt;p&gt;这近两个月里，我们依然保持着联系，过得却不是太好。她经常脾气暴躁，无缘无故地对我发火，把我所有的缺点都翻出来说一遍。有些缺点甚至是许多年以前的，我也早就已经克服，不知道是不是在戈壁滩上透支太多精力，我竟然一点都不生气，任由她自说自话地骂着。她连挂电话都没有预兆，没有再见，没有晚安。&lt;/p&gt;
&lt;p&gt;我们仅仅见过一面，在这座小城的电影院里。那场电影的观影厅空荡荡的没几个人，我们没敢坐在一起，她坐在我的左前方，没有回头，而我几乎一直盯着她的侧影。我记得高二时语文老师给她们班代课，叫我帮他去隔壁班架一下投影仪，我一进去就有人起哄，而她低头写作业不敢抬头看我一眼。这一晃，就是十年，那个腼腆的少女即将嫁作他人妇。&lt;/p&gt;
&lt;p&gt;但我们一直没有停止抗争，这两个月里，只是这艘船上载了太多的人，她搬不动船上的巨锚，而我无法阻止港口缓缓升起的闸。那段时间我看很多电影，读很多书，也聆听许多人的建议。有人说，你的痛苦放在人群里简直微不足道，许多人的心里都深埋着那样一段不见天日的回忆，以后她会渐渐地与丈夫相处融洽，而你也会找到另一个女人，你可以不爱她，也可以对她很好，生一个孩子，你们的心思便全在抚养孩子身上了，谁还在乎爱情是什么？&lt;/p&gt;
&lt;p&gt;我相信那个人所说的话，可是我不要那样的人生。我不想一回家就看到一张冷漠的脸，不想在风月场所眯着醉眼牵走一个不知姓名的女孩，只因她依稀有一点尧尧的影子，我更不想哪天躺在床上奄奄一息，身边围了一大群人，但我却感觉万分孤独，只有雪白的天花板上映出那张几乎遗忘的笑脸。&lt;/p&gt;
&lt;p&gt;凌一尧说，这大半年里她再也没有与家人吵过，但也没有再和他们撒娇谈笑过，每天上班下班，吃完饭便礼貌地放下碗筷，安静地返回自己的房间。
她曾经问罗 XX:“你觉得你喜欢我吗？”&lt;/p&gt;
&lt;p&gt;罗 XX 说:“挺喜欢的吧。”&lt;/p&gt;
&lt;p&gt;罗 XX 的人品不坏，也很斯文，他生于温室，生活自理能力还停留在少年时代，大小事宜都有自己的主见，最后还是要服从父母的安排。&lt;/p&gt;
&lt;p&gt;就在挑选婚纱的当天，这个帖子开播的前一天，罗 XX 在她家吃饭，她也跟着喝了一点酒，然后笑了。她母亲很高兴，说尧尧今天心情不错，终于见到笑脸了。但她母亲洗碗时，她站在厨房门口说:“妈，我告诉你一件事，我这一年没有一天过得开心，我一想到以后也要这样过，就害怕得想死。”&lt;/p&gt;
&lt;p&gt;她母亲说:“你喝多了吧，月底都快领证了还说这种话？”&lt;/p&gt;
&lt;p&gt;凌一尧回房间给我打电话，笑着告诉我这事，她那天的话特别特别的多，一句话反反复复地说，而我沉默地听。十几分钟以后，她似乎有些自责地叹气，说:“喝多了，平时不会告诉你这些屁事的。”&lt;/p&gt;
&lt;p&gt;然后她又突然无奈地苦笑起来，说:“我妈的反射弧真够长的，现在才开始摔盘子，我出去看看。”&lt;/p&gt;
&lt;p&gt;我说不清这段时间自己到底什么心态，随着月底的临近，我觉得自己的心像烧尽的木炭一样渐渐黯淡。最为迷茫的是，我有时无法确定自己到底希望她婚后过得幸不幸福，许多小说和电影都说过，爱一个人就祝她幸福，可我却无法笃定地祝她幸福？我一度怀疑自己对她的感情是否足够真挚，罪责感充斥内心。&lt;/p&gt;
&lt;p&gt;1 月 23 日那天，凌一尧和她母亲上街购物，恰巧发现一家饰品店的老板是她小学和初中的同学，冒 XX。高考之后的暑假，我和冒 XX 第一次认识，她帮我和凌一尧瞒这段感情瞒了好几年，直到两年前才渐渐失去联系。凌一尧的母亲说：“我们家尧尧初五结婚，伴娘还没定人呢，你要不要一起来玩？”&lt;/p&gt;
&lt;p&gt;冒 XX 问凌一尧：“你和他到现在才结婚？”&lt;/p&gt;
&lt;p&gt;凌一尧说：“不是他。”&lt;/p&gt;
&lt;p&gt;冒 XX 用意外又惊诧的目光看着她，然后当场婉拒，说年初店里忙，走不开。凌一尧当晚打电话给我，呵呵地苦笑，说：“一共邀请了几个高中同学，一个个都说没空，蒋 XX 直接说不想来，她说以后你结婚时请她，她更不想去。”&lt;/p&gt;
&lt;p&gt;蒋 XX 也是凌一尧初中的同学，也是我高中时的同班同学，也就是开头提到的那个学霸妹子，我抄她的作业，骗她的零食，偷翻她的日记，我一直以为她讨厌我。&lt;/p&gt;
&lt;p&gt;凌一尧说：“我跟我妈说，我和你本来可以得到很多人的祝福，现在他们的祝福都快变成诅咒了，连一个捧场的好朋友都没有。我妈这次被我说哭了，但是没再骂我，上次她摔过盘子之后，心情就一直不太好。”&lt;/p&gt;
&lt;p&gt;子石放假从外地回来，我约他出来吃饭，刚好舒缓内心的抑郁，随口问万一抢婚的话他去不去。子石摇头说：“如果他们真的走到那一步了，你就没必要再折腾了，一个乌烟瘴气的婚礼足够让很多人一辈子抬不起头了。不过，不是还有一个星期才领证吗？你再去努力一下，实在改变不了，那就认命吧，这个世界上有太多不如意却还是维系下去的婚姻了。”&lt;/p&gt;
&lt;p&gt;枕边人不是心上人，心上人只是梦中人。我想到凌一尧从今往后便是别人家的贤妻良母，而我也不得不与另一个女人同床异梦地度过下半辈子，两个人此生都不敢将对方的名字念出来，不禁感到一阵胸闷气短。我可以每天逢场作戏地欢笑，当然也可以假装深情地说“我爱你”，这些都不过是作为一个演员的基本素养，但我无法忍受凌一尧躺在另一栋房子的另一张床上的另一个臂弯里，心里默念着我的名字。&lt;/p&gt;
&lt;p&gt;除非凌一尧亲口对我说，她已经放下了。&lt;/p&gt;
&lt;p&gt;我打电话约凌一尧出来，在这座城市一座古园林见面，和上次在电影院里一样，我们刻意保持着距离。一直走到一座高高的小土山，山坡上生长着一片竹林，坡顶有一座小凉亭，她回头看我一眼，我才紧走几步跟了上去。她说：“我讨厌这种偷偷摸摸的滋味，像在做什么不要脸的事情似的。再过几天，所有事情都已经定了，无论你怎么约我，我都不会再出来了。”&lt;/p&gt;
&lt;p&gt;我说：“我也很憋屈，很窝火，我们本来应该光明正大地牵手逛街的，而不是现在这个样子。”&lt;/p&gt;
&lt;p&gt;“你憋屈？呵呵，”凌一尧笑了一声，“以前有一次我和罗 XX 上街买东西，他也牵过我的手，可我觉得更像做贼一样恐慌，害怕你不知道什么时候在什么地方就突然冒出来。”&lt;/p&gt;
&lt;p&gt;听她这样说，我鼓起勇气，恳求道：“既然这样，我们都不要放弃好吗？时间还有，感情还在，我们豁出去拼一下，把这件事情缓下来。我可以去找你爸妈谈，只要是反对我们的人，有一个算一个，我都可以去找他们谈。”&lt;/p&gt;
&lt;p&gt;但她一直不说话，我有些心慌了，问道：“那你现在还想不想和我一起？”&lt;/p&gt;
&lt;p&gt;凌一尧这才抬头看着我的眼睛，说：“想。”&lt;/p&gt;
&lt;p&gt;“那你在犹豫什么？”&lt;/p&gt;
&lt;p&gt;“怕。”&lt;/p&gt;
&lt;p&gt;“怕什么？”&lt;/p&gt;
&lt;p&gt;凌一尧想了一下，说：“怕很多事情，最怕的就是你现在只是不甘心，没有以前那么喜欢我了，如果是这样，我宁愿现在就散了。”&lt;/p&gt;
&lt;p&gt;我没想到她心里竟有这样的疑虑，完全出乎我的意料，一时不知道怎么回答，片刻之后才为自己辩护道：“我们从高中就开始相处，现在已经十年了，你应该最懂我。我很少向你许诺或者发誓，但保证过的就一定会去兑现，我现在非常确定地告诉你，我对你的感情绝不是不甘心。”&lt;/p&gt;
&lt;p&gt;凌一尧点了点头，又问：“那我爸妈和罗 XX 家怎么办？以前我以为你不回来了，又被我妈闹得难受，觉得你不在了，跟谁过都是一样过，就把这事给应了。现在我说不想结婚了，我爸妈肯定不会同意，罗 XX 家也会来闹。”&lt;/p&gt;
&lt;p&gt;我说：“你不要担心，这事我来扛。”&lt;/p&gt;
&lt;p&gt;凌一尧盯着我的眼睛，而后咬着嘴唇认真地点头，一开始见面时的焦躁不安消散得无影无踪，但我的内心却满是愧疚———我们都同样并非完美，性格有各自的弱点，过分的单纯与善良让她举步维艰，而我竟偏执地踏上自以为的英雄之路，留她独自在炎凉世态里苦撑。&lt;/p&gt;
&lt;p&gt;我原本打算先去拜会凌一尧的家人，但思索再三，还是更改主意，打电话约罗 XX 出来谈一谈。约谈地点还是一家音乐茶座，他们二人一同出现的，落座时凌一尧习惯性地坐到我身边。&lt;/p&gt;
&lt;p&gt;我对凌一尧说：“我们两人谈点事情，你先坐到他车里玩一会儿。”&lt;/p&gt;
&lt;p&gt;罗 XX 掏出遥控钥匙递给凌一尧，但凌一尧接过去隔着落地窗摁了一下，又放回桌面上，拎着包出去了。我们一直目送她坐上车，才收回目光打量对方，一时间不知道怎么开口，最后我尴尬地笑道：“有点像给她开家长会，哈？”&lt;/p&gt;
&lt;p&gt;罗 XX 也讪笑一声，但气氛稍微缓和一点。&lt;/p&gt;
&lt;p&gt;我问道：“你和凌一尧相处这么久，觉得开心吗？”&lt;/p&gt;
&lt;p&gt;他说：“还可以吧。”&lt;/p&gt;
&lt;p&gt;“你确定你爱她？”&lt;/p&gt;
&lt;p&gt;罗 XX 犹豫片刻，抹着鼻尖说：“反正蛮喜欢的。”&lt;/p&gt;
&lt;p&gt;我却不客气地说：“你应该也看得出来，这大半年里凌一尧从未开心过，我和她一起走了十年，不得已的分手就像被迫离婚一样痛苦。她心里想着我，但不代表我和你之间谁比谁更优秀，而是我运气好一些，十年前就认识她了。现在我很诚恳地希望得到你的帮助，把领证结婚这事停了吧，你们俩勉强凑合在一起不会过得好。”&lt;/p&gt;
&lt;p&gt;罗 XX 有些不服气：“那你前面这几个月干嘛去了？”&lt;/p&gt;
&lt;p&gt;“我以前做得不对，所以现在来纠正错误。本来这事有很多解决途径，只要尧尧一口咬定不领证不结婚，我带她直接离开这个城市，难道你们还能捆绑着逼婚？之所以与你沟通商量，是希望咱们年轻人私底下把这事解决了，尽量把负面影响降到最小，不要伤害长辈，你看怎么样？”&lt;/p&gt;
&lt;p&gt;罗 XX 保持缄默，手指一直拨弄那把车钥匙。&lt;/p&gt;
&lt;p&gt;我给他添了茶水，说：“你们相处几个月，时间不算短了，但你对她了解多少呢？你每次向别人介绍她，第二句就是她的硕士学位；夏天你老是怂恿她穿得性感一些，可她不是你用来向哥们儿炫耀的宠物啊；还有，你总是不停地草泥马草泥马，并且认为这是时尚用语，不是脏话。这些事情都让她非常反感，可是她为什么不说出来呢？”&lt;/p&gt;
&lt;p&gt;罗 XX 不是笨蛋，他明白我的言外之意，我也适时地停止这种攻击性的责问，将话题岔开，与他谈及我与凌一尧在高中时的趣事。罗 XX 一开始有些抵触，但听着听着，也跟着笑了起来，在他笑容最灿烂的时候，我再次严肃地向他请求道：“兄弟啊，以你的条件，再找一个漂亮女朋友不是难事，但我只有一个凌一尧，错过了她，我这辈子都会过得不安生。所以，希望你能帮我一把，恳请你帮我一把。”&lt;/p&gt;
&lt;p&gt;罗 XX 渐渐收起笑脸，思索片刻后说：“如果我不帮忙呢？”&lt;/p&gt;
&lt;p&gt;我说：“我刚才已经讲过了，凌一尧我是肯定要带走的。你帮忙，这事会变得好看一点，你不帮忙，这事只是稍微难看一些而已。”&lt;/p&gt;
&lt;p&gt;罗 XX 坐在那里想了一会儿，最后叹息一声，说：“我明白了。这事我得想一想，明天再打电话给你，给你答复。”&lt;/p&gt;
&lt;p&gt;他起身离开，刚离开座位，凌一尧就从那辆车里下来，往茶座里走来。她和罗 XX 在门口遇到，两人互相打了一声招呼，然后一个出门登车而去，一个在我对面身边坐了下来。凌一尧问：“谈得怎么样？”&lt;/p&gt;
&lt;p&gt;我说：“我也不确定，不过既然已经把话说开了，那你以后就要做好和一条道走到黑的心理准备。”&lt;/p&gt;
&lt;p&gt;凌一尧点了点头，而后又眯眼微笑道：“这条道不会是黑的。”&lt;/p&gt;
&lt;p&gt;整整一天，我一直心神不宁地等着电话，甚至想过万一凌一尧被她父母软禁在家，我就喊一帮哥们儿去抢人，或者打电话报警说有人抢我的老婆。只要凌一尧点一下头，承认她想跟我走，我便再无任何顾忌，大不了从此远走高飞。&lt;/p&gt;
&lt;p&gt;大约凌晨两点，罗 XX 没有打电话过来，却接到凌一尧的电话，她说：“罗 XX 叫我转告你，他已经向他家人说过了，他和我性格不合，两个人相处得不愉快，想取消婚约。我爸妈的态度也不太激烈，我说我也不想和罗 XX 结婚了，他们就只是叹气，没多说什么。”&lt;/p&gt;
&lt;p&gt;“那我什么时候去你家拜会？”我问道。&lt;/p&gt;
&lt;p&gt;“你不要急嘛，再等两天，等大家都把这事认下了，你再过来找我爸妈谈。”凌一尧停顿片刻，说，“我都把东西收拾好了，要是他们还那么固执，我就直接跟你走。”&lt;/p&gt;
&lt;p&gt;我努力抑制内心的喜悦，问道：“你现在什么感觉？”&lt;/p&gt;
&lt;p&gt;凌一尧拖着长音的“嗯”，最后长吸一口气，释然地说：“感觉像又活过来了。”&lt;/p&gt;
&lt;p&gt;挂断电话之后，我张开四肢躺在床上，听着床头闹钟滴滴答答的声音，每一次声响都昭示我正在一秒一秒地远离自己的青春。可是，缱绻于心的爱情如同一个野蛮的天神，呼啸着从天而降，抓着我的衣领飞向九天云霄之外。我闭着眼睛感受这种踏步云端的喜悦，仿佛一瞬间时光倒流，我又回到许多年前的那个漫天火烧云的黄昏，满脸稚气的孩子敲着饭盒喊我的名字，年轻的老师们笑而不语，而凌一尧一脸绯红地躲在满是起哄声的教室里，就像一个即将嫁给我的小新娘。&lt;/p&gt;
&lt;p&gt;而我内心曾经的自卑，以及对金钱的狂热，就像那只名叫“理查德帕克”的白老虎，甩一甩尾巴，轻轻一跃，消失于新疆戈壁滩的绿洲之中。&lt;/p&gt;
&lt;p&gt;理查德. 帕克，呵呵。&lt;/p&gt;
&lt;p&gt;如果这个故事让诸位不满意，非要追根究底地质疑这样一个故事是否可信，那我重新讲一个靠谱一点的故事吧。&lt;/p&gt;
&lt;p&gt;我从新疆回来的第三天，去安定广场闲逛，偶然发现花圃台阶旁边有一个漂亮的新娘正在拍婚纱照。她很漂亮，表情又有些木讷，像一个牵线木偶一样被摄影师指挥着，与新郎摆出各种造型。&lt;/p&gt;
&lt;p&gt;我喊了她的名字：“凌一尧。”&lt;/p&gt;
&lt;p&gt;她看见我时愣了一下，而后丢下那个打扮得油头粉面的新郎，提着婚纱的裙摆，快步走了过来。穿着这身单薄的婚纱，她冻得瑟瑟发抖，又有些羞赧，问道：“你哥呢？”&lt;/p&gt;
&lt;p&gt;我说：“他在新疆没回来。”&lt;/p&gt;
&lt;p&gt;“你还去吗？”&lt;/p&gt;
&lt;p&gt;我点头说“还去，要去收账。”&lt;/p&gt;
&lt;p&gt;凌一尧噢了一声，“你等我一下”，她去台阶旁边拿起自己的加长羽绒服披上，又拎来自己的包，将一张银行卡递给我，说：“这是你哥身份证办的卡，以前一起时的定期存款，你帮我带给他，他知道密码。”&lt;/p&gt;
&lt;p&gt;“嗯。”我将银行卡接了过去，揣进口袋。&lt;/p&gt;
&lt;p&gt;“一定要带给他。”她又强调一遍。&lt;/p&gt;
&lt;p&gt;我用拳头按了按胸口，说：“一定。”&lt;/p&gt;
&lt;p&gt;然后我转身离开，冷风横贯整个广场，我深呼吸试图抑制内心的痛楚，却被着实呛了一下，眼泪差点滚落下来。我的思绪一下子回到三月的戈壁滩，风雪肆虐，寒气逼人，我的步话机里断断续续地传出吕钦扬的呼喊：“你们点几个火堆，把火烧旺，给我指一下方向，我找不到回去的路了。”&lt;/p&gt;
&lt;p&gt;我们用皮卡车拖了许多木方，以及报废的橡胶轮胎，火焰和浓烟直冲云霄，整整烧了一夜，但吕钦扬还是毫无音讯。最后一次与他通话时，他似乎有些精神恍惚，绝望地念叨着：“凌一尧，我迷路了啊……”&lt;/p&gt;
&lt;p&gt;第二天下午，我们在十公里外的一座土丘背后找到他早已冻僵的尸体，他不停地跋涉着，可惜离营地越来越远。而他大衣里那本施工日记的中页，用凝油的圆珠笔笔尖在纸上深深地刻下他此生最潦草最歪斜的几个字：“别告诉凌一尧”。&lt;/p&gt;
&lt;p&gt;吕钦扬，我最尊敬的学长。当初在黄海的滔天潮水中，你用挖掘机的斗子死死抵住我这台机器的侧面，以防我脚下的堤坝塌陷；你坚持不起诉那些地痞，保下我这个冲动不懂事的学弟；你将我拦了下来，扛着仪器走入茫茫雪地之中；你不停地朝着凌一尧的方向奔跑，那么坚定执着，为什么最后还是迷失方向？&lt;/p&gt;
&lt;p&gt;愿你永远活在十年前的文津河畔，愿你灵魂安息。&lt;/p&gt;
&lt;p&gt;今天是公元 2013 年 2 月 14 日，情人节，也是农历癸巳年正月初五，凌一尧的婚期。原本打算讲完故事就销声匿迹，让它慢慢冷却，逐渐被遗忘，但事到如今还是决定给它一个最终番，省得那么多人猜来猜去，越猜越离奇。&lt;/p&gt;
&lt;p&gt;也在这里对某些人说一声，不要以你的生活环境作为公理定理原理来判断这个世界，譬如学龄。我是如皋小城的一个乡下孩子，入小学时不满六岁，因为运河上面没有桥梁只有渡船，在淹死几个孩子之后，学校在河东开了一所小分校，我所在的那一届，全年级不过七个人而已。后来，有一个家伙留级了，我那个年级一共只剩六个人———如果你们觉得这个事情很荒唐，那么你们以后对人对事作判断时请悠着点。&lt;/p&gt;
&lt;p&gt;2000 年我未满十五岁，以全校第 12 名的成绩进入白蒲高中，但由于整天把心思放在踢足球上，学业受到影响，考过全班第一，也考过二三十名。也是在那里，我开始人生的初恋并且不幸被抓，饱受政教处的折腾，也得到班主任老姚的格外关照。冬天起床后为了暖一下身体，出门时我们灌了一口红酒，最后被老姚拦在门口，每人做了 20 个俯卧撑，他终于将我锁定。他后来对同寝室的阿荣说：“XXX 同学今早喝酒了，可能是因为感情受挫，你们一定要对他关心爱护。”&lt;/p&gt;
&lt;p&gt;在此感谢千岁大人。&lt;/p&gt;
&lt;p&gt;正如故事里所说，高考时我数学失利，只考到本二，而凌一尧正常发挥，考取名牌一本，但我至少可以与凌一尧光明正大地恋爱了。这场恋爱不伟大也不光荣，和所有的校园情侣一样，懵懵懂懂，浑浑噩噩，为了莫名其妙的小事吵架，也为了装逼矫情的小事开心。但我大学毕业之后，一切都变得陡然沉重，因为我拿着两三千的月薪，无法挣脱穷困的枷锁。&lt;/p&gt;
&lt;p&gt;情侣之间最无法弥合的矛盾，就是为了钱而吵架。&lt;/p&gt;
&lt;p&gt;我业余时间开始写小说，希望成为所谓的修仙小说写手，写一个少年得到神仙指点不断修炼不断进步最后成为神魔人三界主宰，这种故事非常无趣但它就是有市场，兴许可以为我赚得娶老婆的本钱。但最后，我毫无建树，因为我对此根本一点都不感兴趣，我后来出版的小说也是一个反响平平的都市爱情故事。&lt;/p&gt;
&lt;p&gt;再后来，我去给出版社做枪手，为他人做嫁衣。写自己的故事，署他人的名，拿一笔如同售卖亲子得来的钱。这样的工作可以为我提供七八万的年薪，但我只是别人的影子，没有一点社会地位，当凌一尧的父亲问我从事什么工作，我说是出版社，可是我心里明白，出版社的员工花名册里压根儿没有我的名字。&lt;/p&gt;
&lt;p&gt;我只是别人花钱雇来的影子武士。&lt;/p&gt;
&lt;p&gt;在那段时间，凌一尧的父母对我说了“NO”，我与凌一尧之间也不停地发生争执，我一度出现精神抑郁的状况，整夜整夜地失眠。也是在那段时间，我与一个早年认识的北京女孩聊得较多，当初认识时她才十八九岁，素颜时很像大学时期的凌一尧。&lt;/p&gt;
&lt;p&gt;我走进一个死胡同，我将这个北京女孩当作凌一尧，试图用一个从未谋面的人来排挤凌一尧，那段颠三倒四的日子就是这样混过去的。后来，我也不知道自己到底是在暗恋北京女孩，还是在思念凌一尧。&lt;/p&gt;
&lt;p&gt;再后来，北京女孩长大了，她与同学创建“powerful”的品牌，而我依旧是默默无闻的吕钦扬，互相删了微博和豆瓣。&lt;/p&gt;
&lt;p&gt;后来我遇到一个既称得上哥又称得上叔的长辈，他问我怕不怕苦，问我要不要一起去干工程，加入这个既辛苦又容易暴发的行业。当时我想钱已经想疯了，我看见运钞车都会不自觉地想一下各种可能性，我每天都渴望赚到钱但我不知道如何赚，每天都被这种矛盾折磨得无法入睡。&lt;/p&gt;
&lt;p&gt;凌一尧试图阻止我，但我还是跟他一起走了，先去海边干围海，没有赚到现钱，政府工程的付款方式非常扯淡。再后来，我们又去新疆做光伏电站，在那里，一起趟过黄海和戈壁的技术员把命丢在那里。他比我小一岁，出来卖命的原因也是为了某个她。&lt;/p&gt;
&lt;p&gt;因为出现伤亡事故会导致工程停滞，业主最后托关系出具自然死亡证明，80 万元私了，尸体在当地停了几天后才火化。为了把他带回江苏，我们三人轮流开车，手机按了免提摆在骨灰盒上，里面传出来自家乡老人的呼唤：“天冷霜重，快点归乡哦！”&lt;/p&gt;
&lt;p&gt;当我回到家乡，凌一尧与别人的婚事已经是板上钉钉的事情，用她的话讲，“和他结婚或者和你结婚，现在对我而言，似乎都无所谓了”。我们打电话都要偷偷摸摸的，我们对此都非常厌烦，年底婚期将至的那段时间，凌一尧在派发请柬时难免遇到我们当时的一些老朋友，她的情绪出现波动，开始犹豫不决，甚至想过悔婚。&lt;/p&gt;
&lt;p&gt;可是即便他不是她想要的，那现在的我就是她想要的么？&lt;/p&gt;
&lt;p&gt;我也曾经欢欣鼓舞地认为自己的爱情可以失而复返，但最终闹腾一段时间，我们都发现，那不过是再普通不够的婚前焦虑而已。我们很久以前就各自走上背离对方的道路，只是我独自活在自己的世界里，以为两条道路在前面仍会交汇。&lt;/p&gt;
&lt;p&gt;那个技术员经常喝酒以后和我聊他那让我一听就想打瞌睡的爱情，一提到他的女朋友以后可能和别人结婚，他就忍不住抹眼泪，说：“要是她以后和别人结婚，我一定要躺到她家门口，从我身上跨过去才让她出门。”&lt;/p&gt;
&lt;p&gt;1 月 27 日，我做了人生里最操蛋的事情，我去了他女朋友举办婚礼的那家酒店，将一块旧红布压在迎宾门毯底下。现在你就躺在这里了，可是你阻止得了么？&lt;/p&gt;
&lt;p&gt;至于红布是什么，我家乡的人兴许会明白。&lt;/p&gt;
&lt;p&gt;讲完这个故事之后，我比你们任何人都无法自拔，老是梦见白蒲高中那条河，梦见她穿着蓝白相间的校服走下桥头，梦见她站在阳台上忧虑地望着远方。但那又能如何，我现在一想起她，只记得她从十五岁到二十四岁的模样，却想不起来她如今着了粉黛之后的相貌。&lt;/p&gt;
&lt;p&gt;我的脾气也越来越坏，时而莫名其妙地摔东西，时而一个人在家唱歌，我有时都想着自己是不是有点精神分裂，怀疑自己会不会哪天睁眼醒来发现自己的一些经历只是一场梦。&lt;/p&gt;
&lt;p&gt;昨天是家乡风俗里迎财神的日子，而今天是送财神的日子，漫天的璀璨烟火，其中便有为祝福她的未来而怒放。凌晨五点，我踏上前往上海的车子，今天在上海呆一宿，明天飞往北京，拜见几位资历厚重的前辈。&lt;/p&gt;
&lt;p&gt;正月初五，情人节，故人着新衣，嫁作他人妇。&lt;/p&gt;
&lt;p&gt;这只金箍，先戴为敬。&lt;/p&gt;
&lt;p&gt;故事引用了少年派的结局，作者疑似为写手，不过这都已经不重要了，相信在 13 年那个还没那么多“故事写手”的情况下，作者带着自己的感情与爱情写下了这篇帖子，帖子的最后，楼主给了这个故事三个结局，除了直播帖一开始的结局之外，还有“凌一尧解除婚约，回到吕钦扬身边”和“吕钦扬丧命沙漠，遗书要求向凌一尧隐瞒死讯”两个结局。网友猜测，帖子开头的结局是真实的，大团圆结局是楼主的美好愿望，而那个残忍的结局，则是楼主希望“自己当时死了算了”的感叹。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三个结局&lt;/strong&gt;
1，男主回来，找到男二谈话，找回了爱情，男二自己放弃（这是作者和读者最想看到的结局）
2，男主死在了新疆，男主学弟复述了这个故事，赚了很多读者的眼泪。（其实是以那个真的死去的技术员为背景写的这个结局，同时寓意自己的心已经死在新疆）
3，男主否认了上面两种结局，这个世界上没有那么多美好的结局，也没有付出努力就得到的大笔金钱（工程真的做了，但没有赚到钱），更没有那么多让爱情变得凄美的死亡。男主在这个残酷的世界里，找不回曾经的爱情，而存在于他们心底的爱情，也没有年少时的勇气和激情能够让他们推翻抛弃一切在一起。
也许，最痛苦的，不是发现自己无力改变这个现实，而是发现，已经不那么爱了。&lt;/p&gt;
&lt;p&gt;他们足够相爱，足够有担当，足够谦让，足够包容，拥有一切爱情所需要的，可最终还是败在了现实面前，也许生活就是这样&lt;/p&gt;
&lt;p&gt;看完以后&lt;/p&gt;
&lt;p&gt;所有的话语化成一句我爱你&lt;/p&gt;
&lt;p&gt;我会用尽全力 🍖。&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>五分钟搭建一个随机图片API</title><link>https://barry.ee/writing/imgapi/</link><guid isPermaLink="true">https://barry.ee/writing/imgapi/</guid><pubDate>Tue, 14 Feb 2023 21:52:14 GMT</pubDate><content:encoded>&lt;p&gt;PHP 的随机图片 API 搭建方法有两种&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;本地随机图片&lt;/li&gt;
&lt;li&gt;外链随机图片&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来简单说一下如何编写&lt;/p&gt;
&lt;h2&gt;文字教程&lt;/h2&gt;
&lt;h3&gt;本地随机图片&lt;/h3&gt;
&lt;p&gt;首先创建一个文件夹 photos 和一个名为 index.php 的文件然后在 photos 的文件夹内放图片，在 index.php 内编写如下代码&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
$img_array = glob(&amp;quot;photos/*.{gif,jpg,png}&amp;quot;,GLOB_BRACE);
$img = array_rand($img_array);
$dz = $img_array[$img];
header(&amp;quot;Location:&amp;quot;.$dz);
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存即可，通过 api 随机调用 img 文件夹中的图片, 最后访问地址: http://域名 即可&lt;/p&gt;
&lt;h3&gt;外链随机图片&lt;/h3&gt;
&lt;p&gt;先创建 photos.txt 和 index.php 文件然后在 photos.txt 文档内放图片外链地址 (一行一个) ，在 index.php 加入下列代码&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
$arr=file(&amp;#39;photos.txt&amp;#39;);
$n=count($arr)-1;
for ($i=1;$i&amp;lt;=1;$i++){
$x=rand(0,$n);header(&amp;quot;Location:&amp;quot;.$arr[$x],&amp;quot;\n&amp;quot;);}
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后访问地址: http://域名 即可！ 这里 photos.txt 中可以填写比如新浪那些外链图片，或者自己图床里的图片，高速稳定，而且不耗内存。&lt;/p&gt;
&lt;h2&gt;接口测试&lt;/h2&gt;
&lt;p&gt;我用了第二种获取自己图床外链图片的方式做了
&lt;a href=&quot;https://img.yct.ee&quot;&gt;https://img.yct.ee&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;调用方法&lt;/h2&gt;
&lt;p&gt;如果你不想搭建可直接调用我的&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img src=&amp;quot;https://img.yct.ee&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>转载一篇知乎上的文章：抖音是如何毁掉我们的？</title><link>https://barry.ee/writing/dy/</link><guid isPermaLink="true">https://barry.ee/writing/dy/</guid><pubDate>Tue, 14 Feb 2023 01:18:14 GMT</pubDate><content:encoded>&lt;p&gt;写在前面：&lt;/p&gt;
&lt;p&gt;这篇文中，抖音只是一个具象化代表，&lt;/p&gt;
&lt;p&gt;我想讲的是以抖音为代表的一众以算法为内核的娱乐化 APP。&lt;/p&gt;
&lt;p&gt;每个时代都会有一些淘汰机制，而现在的时代，会根据自制力和信息筛选能力对人进行淘汰。&lt;/p&gt;
&lt;p&gt;但总有一些人是不愿惊醒的，等他们发现自己一事无成时，会选择抱怨别人、抱怨社会、然后把希望寄托给下一代，在这群人眼里错的不是他们，而是社会。希望这个人不会是你。&lt;/p&gt;
&lt;h2&gt;01 -&lt;/h2&gt;
&lt;p&gt;层次越低的人，&lt;/p&gt;
&lt;p&gt;越喜欢花时间在娱乐上&lt;/p&gt;
&lt;p&gt;前几天抖音出了一个 “爆视频”，单单评论数就超过一百万，播放数量过千万。&lt;/p&gt;
&lt;p&gt;这几乎是我们这些文字工作者难以企及的数量。而数量背后，潜藏着一个个为此付出时间与精力的人。&lt;/p&gt;
&lt;p&gt;除此之外，相信你在朋友圈也看到过不少这样的话：“中了抖音的毒”、“刷抖音根本停不下来啊啊啊，一看表竟然刷了三个多小时…”&lt;/p&gt;
&lt;p&gt;这一点相信刷过抖音、亦或者是刷过快手、火山小视频等等各种小视频软件的人都会深有感受。&lt;/p&gt;
&lt;p&gt;如果你在路边、休息处看到一个人手指连动笑的合不拢嘴，那大概就是在刷小视频了。&lt;/p&gt;
&lt;p&gt;我们会不自觉的深陷其中，蓦然之间发现时间已经过去了几个小时。&lt;/p&gt;
&lt;p&gt;尼尔・波兹曼在《娱乐至死》里这样写过这样的一段话：&lt;/p&gt;
&lt;p&gt;“一切公众话语日渐以娱乐的方式出现，并成为一种文化精神。我们的政治、宗教、新闻、体育、教育和商业都心甘情愿地成为娱乐的附庸，毫无怨言，甚至无声无息，其结果是我们成了一个娱乐至死的物种。”&lt;/p&gt;
&lt;p&gt;层次越低的人，越喜欢花时间在娱乐上。&lt;/p&gt;
&lt;p&gt;越来越多的人患上了网络依存症，对各类娱乐新闻上瘾、产生依赖，人云亦云，附和跟风，沉溺在虚拟的世界中不能自拔。我害怕长久以往，自己会变成一个透明的躯壳，脑袋空空、沉浸于感官娱乐。&lt;/p&gt;
&lt;p&gt;有人说，你的时间花在哪，你就会成为什么样的人。格局高的人，不会花太多时间在娱乐上。&lt;/p&gt;
&lt;p&gt;我们正在爱上这些使我们丧失思考能力的工业技术。抖音、快手、抖音、微博这些软件正在飞速地强化我们对新奇事物的需求度，并拉高我们的敏感度。同时降低的就是对文字的需求度与耐心度。&lt;/p&gt;
&lt;p&gt;刷多了抖音、快手、微博这些软件之后，我们就会形成一种惯性：没有耐心去读一本长文或者书籍。更没有时间去思考，因为我们总是在期待着下一个引爆眼球的新奇事物，等待着它在视频中直接了当的呈现。&lt;/p&gt;
&lt;p&gt;比如你就有可能看不完我的这篇长文。&lt;/p&gt;
&lt;p&gt;而在被轰炸多了之后，我们就会逐渐爱上这种 “被喂食” 的感觉。而当 “被喂食” 形成一种习惯之后，我们的就会惰于思考，耐心以及深挖问题的能力就会被逐渐抹杀。
盛大网络董事会主席 陈天桥&lt;/p&gt;
&lt;h2&gt;02 -&lt;/h2&gt;
&lt;p&gt;你每时每刻傻呵呵的沉浸其中&lt;/p&gt;
&lt;p&gt;换来的都是经营者的盆满钵满&lt;/p&gt;
&lt;p&gt;这是一家十分 “传奇” 的公司，2001 年年底，盛大账面上只剩下大约 30 万美金，陈天桥倾囊而出，买下韩国一款二线游戏《传奇》的中国代理权。&lt;/p&gt;
&lt;p&gt;2002 年，《传奇》同时在线人数突破 60 万，成为当时世界上最大规模的网络游戏，盛大月均销售额超过千万，市场占有率超过六成。&lt;/p&gt;
&lt;p&gt;但是陈天桥在接受记者采访时却不止一次说过：“我从来不玩《传奇》，因为这是个烂游戏，浪费我的时间，但是盛大是个好公司”&lt;/p&gt;
&lt;p&gt;但是不可否认的是，这个备受追捧的烂游戏确实吸来了千万销售额。&lt;/p&gt;
&lt;p&gt;看到了么？你每时每刻傻呵呵的沉浸其中，换来的都是经营者的盆满钵满。&lt;/p&gt;
&lt;p&gt;“不知道为什么，刷抖音的时候感觉那么开心，可是刷完之后却分外空虚，变得很丧，而且更自卑了” 一个粉丝在凌晨一点多私信我。&lt;/p&gt;
&lt;p&gt;他说他刚在床上刷完抖音，然后就失眠了。&lt;/p&gt;
&lt;p&gt;在孤寂无人的夜晚，我们最容易感受到自己的无助与空虚。&lt;/p&gt;
&lt;p&gt;我回复说：“因为你爱上了一个虚拟且充满新奇的世界，但是你依旧碌碌无为，你的生活仍然平平无奇。”&lt;/p&gt;
&lt;p&gt;我称抖音、火山小视频、今日头条、快手等等以算法推荐为内核的软件为：毒品软件。&lt;/p&gt;
&lt;p&gt;一款类似抖音的 APP，背后都是一个强大的运营团队，有着专业的消费者行为学作支撑，用尽最前沿的科技，最详尽的数据，通过声、光、交互、反馈等全方位途径，在各种心理学、行为经济学、认知神经科学等理论指导下，精心打造 — 目的是什么？为了创造一个虚拟空间，来消磨你的时间。&lt;/p&gt;
&lt;p&gt;它带来的满足感太容易获得，而一旦你习惯了这种 “唾手可得” 的满足感，就不愿再去做那些 “高投入” 的事情了。比如在高度自律的状态下完成作业、思考问题。&lt;/p&gt;
&lt;p&gt;在这个被娱乐塞满的世界里，当没有足够强大的自控力时，我们就会因为沉迷各种诱惑而 “被碌碌无为”。&lt;/p&gt;
&lt;h2&gt;03 -&lt;/h2&gt;
&lt;p&gt;盖茨家把 13 岁定为得到手机的年限&lt;/p&gt;
&lt;p&gt;乔布斯不允许自己的孩子们用 iPad&lt;/p&gt;
&lt;p&gt;比尔盖茨曾在采访中说过，他认为 13 岁是孩子拥有第一部手机的合适年龄。&lt;/p&gt;
&lt;p&gt;他、珍妮弗、以及 1999 年出生的儿子罗里・盖茨都是在过了 13 岁生日后才被允许使用手机，小女儿菲比则在期待着 13 岁生日时得到自己的第一部手机。&lt;/p&gt;
&lt;p&gt;“我们家把 13 岁定为得到手机的年限。” 盖茨说，鉴于这项规定，孩子们从学校回家后常向他抱怨说，“其他孩子都有手机，我是唯一一个没有手机的人，这令人尴尬”。&lt;/p&gt;
&lt;p&gt;你知道吗？乔布斯是不允许自己的孩子们用 iPad 的。&lt;/p&gt;
&lt;p&gt;乔布斯生前有三个年幼的孩子。有一天纽约时报的记者 Nick Bilto 问他：&lt;/p&gt;
&lt;p&gt;“你的孩子们一定很喜欢 iPad 吧？”&lt;/p&gt;
&lt;p&gt;老乔回答：&lt;/p&gt;
&lt;p&gt;“他们没有用过。我们限制孩子们在家里使用智能产品。”&lt;/p&gt;
&lt;p&gt;听起来是不是怪怪的？iPad 之父居然不允许自己的孩子用 iPad? 感觉就像是毒贩不允许自己的孩子吸毒一样…&lt;/p&gt;
&lt;p&gt;无独有偶。在硅谷，很多高科技公司的高层和工程师里面，开始流行不让自己的孩子接触智能科技产品。&lt;/p&gt;
&lt;p&gt;他们甚至把孩子们送到传统的，完全没有智能和科技产品的 Waldorf 学校，在这个学校的校园里根本就找不到电脑！&lt;/p&gt;
&lt;h2&gt;04 -&lt;/h2&gt;
&lt;p&gt;能够掌控时间的人，&lt;/p&gt;
&lt;p&gt;才能掌控自己的一生。&lt;/p&gt;
&lt;p&gt;我们看到的是电子产品正在飞速低龄化，抖音快手已经迅速占据了小学生的生活。&lt;/p&gt;
&lt;p&gt;而因为缺乏自制力，他们会沉浸其中无法自拔，在最应当拼搏的年纪里选择安逸，在价值观形成之际被灌输进大量的光怪陆离与不正之风。&lt;/p&gt;
&lt;p&gt;于是他们开始模仿，追逐着未成年怀孕风当宝妈、跟着小青年跳社会摇、以为低胸博眼球就能赚大钱… 当管制不利时，堕落便自此开始。&lt;/p&gt;
&lt;p&gt;那些我们所热爱的东西，正在一步步把我们连根拔起。&lt;/p&gt;
&lt;p&gt;在作家周冲的文章中看到过这样一段话：&lt;/p&gt;
&lt;p&gt;当你的时间不再用于深度学习，当你的注意力被他人瓜分，当你只看综艺与电视剧，当你在群体中呆的时间越来越长，当你执行力越来越差，当你评价他人的次数越来越多，当你抱怨越来越频繁，当你回想往事的频率越来越高… 毁灭就已经发生了。&lt;/p&gt;
&lt;p&gt;如何分配你的时间，取决于你。&lt;/p&gt;
&lt;p&gt;未来，在时间这个战场上，有两门生意会特别值钱。&lt;/p&gt;
&lt;p&gt;第一，就是帮别人省时间。第二，就是帮别人把省下来的时间浪费在那些美好的事物上。&lt;/p&gt;
&lt;p&gt;能够掌控时间的人，才能掌控自己的一生。&lt;/p&gt;
&lt;p&gt;这座城市，一半人在拼命，一半人在认命；一半人在抢时间，一半人在耗时间；一半人在燃烧青春，一半人在虚度青春。&lt;/p&gt;
&lt;p&gt;你愿意做哪一半的人？&lt;/p&gt;
&lt;h2&gt;评价&lt;/h2&gt;
&lt;p&gt;未来对人类自制力的考验将会越来越严峻。&lt;/p&gt;
&lt;h2&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learnku.com/articles/71955&quot;&gt;转载一篇知乎上的文章：抖音是如何毁掉我们的？（深度好文） - Musk・C・Ace - learnku&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>TeamSpeak服务器搭建——基于Docker-Compose</title><link>https://barry.ee/writing/teamspeak/</link><guid isPermaLink="true">https://barry.ee/writing/teamspeak/</guid><pubDate>Mon, 13 Feb 2023 16:31:29 GMT</pubDate><content:encoded>&lt;h2&gt;服务器选择&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;腾讯云&lt;/code&gt; / &lt;code&gt;阿里云&lt;/code&gt; 等轻量云服务器&lt;/li&gt;
&lt;li&gt;优先选择&lt;strong&gt;学生优惠&lt;/strong&gt;和&lt;strong&gt;香港服务器&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;系统镜像优先选择 &lt;code&gt;CentOS+Docker&lt;/code&gt; 已经配置好的镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;环境配置&lt;/h2&gt;
&lt;p&gt;确认服务器已经安装 Docker 和 Docker-Compose&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker -v
docker-compose -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如能正常显示版本号，下面这一步&lt;strong&gt;直接跳过&lt;/strong&gt;，否则要手动安装，这里以 &lt;code&gt;CentOS 7&lt;/code&gt; 为例安装：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;搜索 &lt;code&gt;系统名 安装 docker compose&lt;/code&gt; 有很多现成文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# 安装yum-utils
yum install -y yum-utils

# 配置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装docker-ce
yum install -y docker-ce

# 设置开机启动服务
systemctl enable docker

# 启动服务
systemctl start docker

# 安装epel源
yum install -y epel-release

# 安装docker-compose，如果没有python3会安装python3
yum install -y docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;配置 TeamSpeak&lt;/h2&gt;
&lt;p&gt;找到合适的目录新建目录 &lt;code&gt;ts&lt;/code&gt; 并切换&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;个人习惯所有 docker 配置统一放在根目录 &lt;code&gt;/root/data/docker_data&lt;/code&gt; 下，具体位置没有强制要求，但是每组配置都应放在一个单独的文件夹下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir -p /root/data/docker_data/ts3  # 创建目录
cd /root/data/docker_data/ts3     # 切换当前目录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新建 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件，粘贴以下内容并保存，文件内容如下（&lt;a href=&quot;https://hub.docker.com/_/teamspeak&quot;&gt;官方镜像 (opens new window)&lt;/a&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml

version: &amp;#39;3.1&amp;#39;
services:
  teamspeak:
    image: teamspeak
    restart: always
    ports:
      - 9987:9987/udp # 语音服务
      - 30033:30033 # 文件传输
      - 41144:41144 # DNS域名解析（可选）
      - 10011:10011 # 服务器查询 raw（可选）
      # - 10022:10022   # 服务器查询 SSH（可选）
      # - 10080:10080   # 网络请求 http（可选）
      # - 10443:10443   # 网络请求 https（可选）
    volumes:
      - ./data:/var/ts3server
    environment:
      TS3SERVER_DB_PLUGIN: ts3db_mariadb
      TS3SERVER_DB_SQLCREATEPATH: create_mariadb
      TS3SERVER_DB_HOST: db
      TS3SERVER_DB_USER: root
      TS3SERVER_DB_PASSWORD: password # 数据库密码
      TS3SERVER_DB_NAME: teamspeak
      TS3SERVER_DB_WAITUNTILREADY: 30
      TS3SERVER_LICENSE: accept
  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password # 数据库密码
      MYSQL_DATABASE: teamspeak
    volumes:
      - ./data/mysql:/var/lib/mysql # 必需，否则重启镜像后数据丢失
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器上要使用 &lt;code&gt;vi/vim/nano&lt;/code&gt; 编辑文件，如果没有，CentOS 系统使用 &lt;code&gt;yum install nano&lt;/code&gt; 类似的指令安装&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# [新建文件]
vi docker-compose.yml
# 或
vim docker-compose.yml
# 或
nano docker-compose.yml

# [粘贴] ctrl+v 或 ctrl+shift+v 或 shift+insert

# [保存] vi/vim: ESC :wq Enter

# [保存] nano: ctrl+x
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;启动服务&lt;/h2&gt;
&lt;p&gt;确认当前在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 所在的目录，如 &lt;code&gt;cd /data/ts&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# 启动服务
docker-compose up

# 启动服务 一直运行 detach
docker-compose up -d

# 关闭服务
docker-compose down

# 重启服务
docker-compose restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用TS客户端连接服务器，会弹出对话框要求输入token，输入token后这个账号就是管理员了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;第一次启动时会弹出 &lt;code&gt;Server Query 管理员账号密码&lt;/code&gt; 和 &lt;code&gt;token&lt;/code&gt;，&lt;strong&gt;务必妥善保存&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;第一次如果用 &lt;code&gt;docker-compose up -d&lt;/code&gt; 启动，相关日志会保存在 &lt;code&gt;./data/logs&lt;/code&gt; 下&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;开放规则&lt;/h2&gt;
&lt;p&gt;云服务器的防火墙设置页添加如下入站规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;9987 UDP&lt;/li&gt;
&lt;li&gt;30033 TCP&lt;/li&gt;
&lt;li&gt;41144 TCP&lt;/li&gt;
&lt;li&gt;10011 TCP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://support.teamspeak.com/hc/en-us/articles/360002712257-Which-ports-does-the-TeamSpeak-3-server-use&quot;&gt;ts官方的端口说明(opens new window)&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;域名解析&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;添加一条 A 类型的规则，指向服务器 ip 地址。此处 &lt;code&gt;ts -&amp;gt; xxx.xxx.xxx.xxx&lt;/code&gt; 即解析域名 &lt;code&gt;ts.yct.ee&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;添加一条SRV类型的规则，如图所示：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/qude21-0.png&quot; alt=&quot;域名解析&quot;&gt;&lt;/p&gt;
&lt;h2&gt;客户端&lt;/h2&gt;
&lt;p&gt;客户端官网：&lt;a href=&quot;https://teamspeak.com/zh-CN/&quot;&gt;https://teamspeak.com/zh-CN/&lt;/a&gt;
汉化包：&lt;a href=&quot;https://github.com/jitingcn/TS3-Translation_zh-CN/releases/latest&quot;&gt;https://github.com/jitingcn/TS3-Translation_zh-CN/releases/latest&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>整理一些常用的脚本（持续更新中）</title><link>https://barry.ee/writing/vps/</link><guid isPermaLink="true">https://barry.ee/writing/vps/</guid><pubDate>Sat, 11 Feb 2023 13:23:14 GMT</pubDate><content:encoded>&lt;h2&gt;综合工具箱（强烈推荐，集成了很多脚本）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -O box.sh https://raw.githubusercontent.com/BlueSkyXN/SKY-BOX/main/box.sh &amp;amp;&amp;amp; chmod +x box.sh &amp;amp;&amp;amp; clear &amp;amp;&amp;amp; ./box.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;杜甫测试&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -q https://github.com/Aniverse/A/raw/i/a &amp;amp;&amp;amp; bash a
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DD 相关&lt;/h2&gt;
&lt;h3&gt;1、甲骨文 DD 脚本&lt;/h3&gt;
&lt;p&gt;DD成Debian 10&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt; bash &amp;lt;(wget --no-check-certificate -qO- &amp;#39;https://raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh&amp;#39;) -d 10 -v 64 -p &amp;quot;自定义root密码&amp;quot; -port &amp;quot;自定义ssh端口&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DD成Ubuntu 20.04&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(wget --no-check-certificate -qO- &amp;#39;https://raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh&amp;#39;) -u 20.04 -v 64 -p &amp;quot;自定义root密码&amp;quot; -port &amp;quot;自定义ssh端口&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2、MoeClub脚本&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;重点推荐：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;时间：22/11/2021 15:21 萌咖更新脚本：&lt;/p&gt;
&lt;p&gt;1.新增对 Oracle AMD，Oracle ARM全面支持. 可支持从 Ubuntu, Oracle Linux 等系统网络重装. 2.更新 dd 镜像的基础系统版本. 3.移除对外部 wget 的依赖. 4.新增 -port 参数, 可更改默认SSH端口. 5.更新 内置的网络参数计算 逻辑. 6.更新 grub 配置文件定位逻辑, 可支持任意引导grub的系统.&lt;/p&gt;
&lt;p&gt;以下系统已通过测试(其他自测):
Debian: 9, 10, 11;
Ubuntu: 18.04, 20.04;
CentOS: 6.10;
以下平台已通过测试(其他自测):
Oracle、Do、Azure&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(wget --no-check-certificate -qO- &amp;#39;https://raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh&amp;#39;) -d 10 -v 64 -p &amp;quot;自定义root密码&amp;quot; -port &amp;quot;自定义ssh端口&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-d 10 -v 64
-d 9 -v 64
-u 20.04 -v 64
-u 18.04 -v 64&lt;/p&gt;
&lt;p&gt;开机改密码脚本：&lt;/p&gt;
&lt;p&gt;开机改密：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash
echo root:Vicer |sudo chpasswd root
sudo sed -i &amp;#39;s/^#\?PermitRootLogin.*/PermitRootLogin yes/g&amp;#39; /etc/ssh/sshd_config;
sudo sed -i &amp;#39;s/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g&amp;#39; /etc/ssh/sshd_config;
sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3、另一位大佬的脚本&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget --no-check-certificate -O AutoReinstall.sh https://git.io/AutoReinstall.sh &amp;amp;&amp;amp; bash AutoReinstall.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;CentOS 默认密码 Pwd@CentOS 其它系统 Pwd@Linux&lt;/li&gt;
&lt;li&gt;OpenVZ / LXC 架构系统不适用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;来源： &lt;a href=&quot;https://blog.hicasper.com/post/135.html&quot;&gt;https://blog.hicasper.com/post/135.html&lt;/a&gt; 参考： &lt;a href=&quot;https://www.ydyno.com/archives/1245.html&quot;&gt;https://www.ydyno.com/archives/1245.html&lt;/a&gt; 感谢大佬的付出！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(wget --no-check-certificate -qO- &amp;#39;https://file.geekn.net/CNODnjau/InstallNET.sh&amp;#39;) -d 11 -v 64 -a -firmware
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-firmware 额外的驱动支持
-d 后面是系统版本号
-v 后面写64位 32位
-a （不清楚这个干啥的但是每个脚本都带）
–mirror 后面是镜像源地址&lt;/p&gt;
&lt;p&gt;-p 后面写自定义密码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;镜像站地址
官方给出的地址列表：https://www.debian.org/mirror/list

一些国内的
ftp.cn.debian.org
mirror.bjtu.edu.cn
mirror.lzu.edu.cn
mirror.nju.edu.cn
mirrors.163.com
mirrors.bfsu.edu.cn
mirrors.hit.edu.cn
mirrors.huaweicloud.com
mirror.sjtu.edu.cn
mirrors.tuna.tsinghua.edu.cn
mirrors.ustc.edu.cn

使用方法：（大致都是一样的）

清华源
--mirror &amp;#39;https://mirrors.ustc.edu.cn/debian/&amp;#39;

腾讯源
--mirror &amp;#39;https://mirrors.aliyun.com/debian/&amp;#39;

阿里源
--mirror &amp;#39;https://mirrors.aliyun.com/debian/&amp;#39;

华为源
--mirror &amp;#39;https://mirrors.huaweicloud.com/debian/&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4、秋水逸冰 Windows 2012/2016/2019/2022 10/11 DD 镜像&lt;/h3&gt;
&lt;p&gt;适用于 UEFI 启动的多个 Windows 系统 DD 镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://teddysun.com/656.html&quot;&gt;https://teddysun.com/656.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Server 2012 R2 Datacenter&lt;/li&gt;
&lt;li&gt;Windows Server 2016 Datacenter (build: 14393.5006)&lt;/li&gt;
&lt;li&gt;Windows Server 2019 Datacenter (build: 17763.2686)&lt;/li&gt;
&lt;li&gt;Windows Server 2022 Datacenter (build: 20348.587)&lt;/li&gt;
&lt;li&gt;Windows 10 Enterprise LTSC (build: 19044.1288)&lt;/li&gt;
&lt;li&gt;Windows 11 Pro for Workstations 21H2 (build: 22000.194)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适用于 BIOS 启动的 Windows Server 2022 Datacenter DD 镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://teddysun.com/629.html&quot;&gt;https://teddysun.com/629.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;适用于 BIOS 启动的 Windows 11 Pro for Workstations 21H2 DD 镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://teddysun.com/642.html&quot;&gt;https://teddysun.com/642.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;适用于 BIOS 启动的 Windows 10 Enterprise LTSC DD 镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://teddysun.com/640.html&quot;&gt;https://teddysun.com/640.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;适用于 BIOS 启动的 Windows Server 2019/2016/2012R2 Datacenter DD 镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://teddysun.com/545.html&quot;&gt;https://teddysun.com/545.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Server 2019 Datacenter（Build: 17763.2686）&lt;/li&gt;
&lt;li&gt;Windows Server 2016 Datacenter（Build: 14393.5006）&lt;/li&gt;
&lt;li&gt;Windows Server 2012 R2 Datacenter&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;测试相关&lt;/h2&gt;
&lt;h3&gt;机器测试&lt;/h3&gt;
&lt;h4&gt;单线程测试&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -Lso- https://bench.im/hyperspeed)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;最全测速脚本&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -fsL https://ilemonra.in/LemonBenchIntl | bash -s fast
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;superbench&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -qO- git.io/superbench.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Bench.sh&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -qO- bench.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;速度测试&lt;/h3&gt;
&lt;h4&gt;显示延迟、抖动&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(wget -qO- https://bench.im/hyperspeed)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;直接显示回程线路&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl https://raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh|bash
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -q route.f2k.pub -O route &amp;amp;&amp;amp; bash route
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//第一个
wget https://raw.githubusercontent.com/nanqinlang-script/testrace/master/testrace.sh
bash testrace.sh

//第二个
wget -qO- git.io/besttrace | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;四网测速&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -O jcnf.sh https://raw.githubusercontent.com/Netflixxp/jcnfbesttrace/main/jcnf.sh
bash jcnf.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;三网测速&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -Lso- https://git.io/superspeed_uxh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;带快速四网测试版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -Lso- https://dl.233.mba/d/sh/speedtest.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -Lso- https://git.io/J1SEh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;带综合测试的版本（CPU信息、Geekbench等）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(wget --no-check-certificate -O- https://dl.233.mba/d/sh/superbenchpro.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来源: &lt;a href=&quot;https://www.wrnxr.cn/163.html&quot;&gt;https://www.wrnxr.cn/163.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;测试25端口是否开放&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;telnet smtp.aol.com 25
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;测试IPv4优先还是IPv6优先&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl ip.p3terx.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;流媒体测试&lt;/h2&gt;
&lt;h3&gt;全媒体测试&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -L -s https://raw.githubusercontent.com/lmc999/RegionRestrictionCheck/main/check.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;奈飞测试&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -O nf https://github.com/sjlleo/netflix-verify/releases/download/2.5/nf_2.5_linux_amd64 &amp;amp;&amp;amp; chmod +x nf &amp;amp;&amp;amp; clear &amp;amp;&amp;amp; ./nf
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//第一个
bash &amp;lt;(curl -L -s https://raw.githubusercontent.com/lmc999/RegionRestrictionCheck/main/check.sh)

//第二个
bash &amp;lt;(curl -sSL &amp;quot;https://github.com/CoiaPrant/MediaUnlock_Test/raw/main/check.sh&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;WARP&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -N --no-check-certificate https://cdn.jsdelivr.net/gh/YG-tsj/CFWarp-Pro/multi.sh &amp;amp;&amp;amp; chmod +x multi.sh &amp;amp;&amp;amp; ./multi.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后进入脚本快捷方式为 bash multi.sh&lt;/p&gt;
&lt;h2&gt;服务器时间&lt;/h2&gt;
&lt;h3&gt;CentOS 同步时间&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yum -y install ntpdate
timedatectl set-timezone Asia/Shanghai
ntpdate ntp1.aliyun.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;BBR&lt;/h2&gt;
&lt;h3&gt;CentOS 7 BBR&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -N --no-check-certificate &amp;quot;https://raw.githubusercontent.com/chiakge/Linux-NetSpeed/master/tcp.sh&amp;quot; &amp;amp;&amp;amp; chmod +x tcp.sh &amp;amp;&amp;amp; ./tcp.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;一键开启BBR&lt;/h3&gt;
&lt;p&gt;注意：需要Linux Kernel 内核升级到 4.9 及以上版本可以实现 BBR 加速&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;uname -srm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux 3.10.0-957.12.2.el7.x86_64 x86_64
3 - 内核版本.
10 - 主修订版本.
0-957 - 次要修订版本.
12 - 补丁版本.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般来说，Ubuntu18.04以上就可以(默认的内核4.15)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;quot;net.core.default_qdisc=fq&amp;quot; &amp;gt;&amp;gt; /etc/sysctl.conf
echo &amp;quot;net.ipv4.tcp_congestion_control=bbr&amp;quot; &amp;gt;&amp;gt; /etc/sysctl.conf

sysctl -p

sysctl net.ipv4.tcp_available_congestion_control

lsmod | grep bbr
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Docker相关&lt;/h2&gt;
&lt;h3&gt;更新、安装必备软件&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y wget vim
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;海外服务器&lt;/h3&gt;
&lt;h4&gt;非大陆Docker安装&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -qO- get.docker.com | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;卸载Docker&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt-get purge docker-ce docker-ce-cli containerd.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;非大陆Docker-compose安装&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt; sudo curl -L &amp;quot;https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)&amp;quot; -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;大陆服务器&lt;/h3&gt;
&lt;h4&gt;国内机安装docker&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -sSL https://get.daocloud.io/docker | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;国内机安装docker-compose&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://get.daocloud.io/docker/compose/releases/download/v2.1.1/docker-compose-`uname -s`-`uname -m` &amp;gt; /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;卸载docker&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt-get remove docker docker-engine
rm -fr /var/lib/docker/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;防火墙&lt;/h2&gt;
&lt;h3&gt;CentOS 关闭防火墙&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl start supervisord
systemctl disable firewalld
systemctl stop firewalld
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;呆梨相关&lt;/h2&gt;
&lt;h3&gt;XUI&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -Ls https://raw.githubusercontent.com/sprov065/x-ui/master/install.sh) 0.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;mack-a&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget -P /root -N --no-check-certificate &amp;quot;https://raw.githubusercontent.com/mack-a/v2ray-agent/master/install.sh&amp;quot; &amp;amp;&amp;amp; chmod 700 /root/install.sh &amp;amp;&amp;amp; /root/install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;持续更新中&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>五分钟搭建个人资源库</title><link>https://barry.ee/writing/alist/</link><guid isPermaLink="true">https://barry.ee/writing/alist/</guid><pubDate>Tue, 24 Jan 2023 21:32:14 GMT</pubDate><content:encoded>&lt;h2&gt;关于 Alist&lt;/h2&gt;
&lt;p&gt;一个支持多种存储的文件列表程序，使用 Gin 和 Solidjs。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;仅适用于 Linux amd64/arm64 平台。&lt;/p&gt;
&lt;h3&gt;安装&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s install
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更新&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s update
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;卸载&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s uninstall
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自定义路径&lt;/h3&gt;
&lt;p&gt;默认安装在 &lt;code&gt;/opt/alist&lt;/code&gt; 中。 自定义安装路径，将安装路径作为第二个参数添加，必须是绝对路径（如果路径以 alist 结尾，则直接安装到给定路径，否则会安装在给定路径 alist 目录下），如 安装到 &lt;code&gt;/root&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install
curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s install /root
# update
curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s update /root
# Uninstall
curl -fsSL &amp;quot;https://alist.nn.ci/v3.sh&amp;quot; | bash -s uninstall /root
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;启动: &lt;code&gt;systemctl start alist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;关闭: &lt;code&gt;systemctl stop alist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;状态: &lt;code&gt;systemctl status alist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;重启: &lt;code&gt;systemctl restart alist&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;简单设置&lt;/h2&gt;
&lt;p&gt;若是服务器先在服务器中开放 5244 端口，在浏览器中访问服务器 ip：5244 即可打开 Alist，在服务器终端中进入 &lt;code&gt;/opt/alist&lt;/code&gt; 中输入 &lt;code&gt;./alist admin&lt;/code&gt; 即可查看默认后台管理员账号密码&lt;/p&gt;
&lt;h3&gt;挂载资源&lt;/h3&gt;
&lt;p&gt;Alist 支持绝大多数的网盘挂在以及本地挂载，详情参考 [Alist 官方中文文档](&lt;a href=&quot;https://alist.nn.ci/zh/&quot;&gt;Home | AList文档 (nn.ci)&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;搞定&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://easyimage.smitten.top/i/2023/01/26/zcydwq-0.png&quot; alt=&quot;效果图&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>共勉</title><link>https://barry.ee/writing/encourage/</link><guid isPermaLink="true">https://barry.ee/writing/encourage/</guid><description>一些原则，共勉！</description><pubDate>Sun, 08 Jan 2023 21:38:14 GMT</pubDate><content:encoded>&lt;h2&gt;目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;技术：尽一切手段维护信息自由&lt;/li&gt;
&lt;li&gt;玄学：尽一切手段促进灵性觉醒&lt;/li&gt;
&lt;li&gt;把妹：尽一切手段维护男性权益&lt;/li&gt;
&lt;li&gt;网赚：尽一切手段打造自动赚钱机器&lt;/li&gt;
&lt;li&gt;文创：尽一切手段维护创作自由&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;超级个体技能树&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;软件开发和游戏制作&lt;/li&gt;
&lt;li&gt;逆向、密码学和游戏辅助&lt;/li&gt;
&lt;li&gt;ai辅助创作（文字、音频、绘画、视频）&lt;/li&gt;
&lt;li&gt;电商运营&lt;/li&gt;
&lt;li&gt;算法交易&lt;/li&gt;
&lt;li&gt;社会工程及两性心理学&lt;/li&gt;
&lt;li&gt;神秘学&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;八大原则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;性价比：在不牺牲体验的情况下，选择最便宜的，就是性价比。允许花时间省钱，只要省下来的钱按照市价高于时薪就能接受。&lt;/li&gt;
&lt;li&gt;冗余：一、预估时间的时候，将极限时间x2就是最终时间（侯世达定律）。二、重要资料做好备份，本地至少两份在不同介质上。&lt;/li&gt;
&lt;li&gt;标准化/流程化/自动化/智能化（IT 四化）：标准化是流程化的前提，流程化有助于外包，它是成功人士的唯一一个习惯。流程化也有助于自动化，即用机器解决问题。程序员的美德，就是能自动绝不手动。一个低级重复行为居然要手动，你好意思称自己是程序员嘛？&lt;/li&gt;
&lt;li&gt;第一性原理：完成一个目标只有少数几个必要条件。只需要专注他们，不要总是有奇奇怪怪的无效假设。不要被乌合之众的观点/做法绑架。&lt;/li&gt;
&lt;li&gt;热插拔：保证自己是个独立完整的系统，与别人合作但不依赖别人。优先磨练自己的议价能力而不是协作能力来增加选择面，保证自己可以随时中止合作关系，防止受限于任何人。遇到问题优先考虑终止合作并换人，而不是改善合作关系。&lt;/li&gt;
&lt;li&gt;专注、迭代、极致：一次只专注于一件事情，允许不足，在多个迭代中反复改进，尽可能达到极致。&lt;/li&gt;
&lt;li&gt;大数据：（1）大数据不仅仅指数字和表格本身，也包含情报，经验，教程，方法论这些非结构化数据。（2）收集数据来遍历每一种可能性，对抗不确定性，避免认知偏差，好处是无需亲身实践直接借助他人经验。（3）注意收集你暂时用不到，但是大家都需要的数据，并且改造你的存储设施来存的下更多数据。&lt;/li&gt;
&lt;li&gt;跨界：用数字化改造一切，程序员的使命就是先消灭其它行业再消灭自身。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;语录&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;渣男除了渣没其他缺点，舔狗除了舔没其他优点。&lt;/p&gt;
&lt;p&gt;既然我们做什么都会被喷，&lt;strong&gt;**&lt;/strong&gt;____&lt;strong&gt;**&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;搞钱的大原则就是信息不对称&lt;/p&gt;
&lt;p&gt;风口可能有很多个，但是对应的技术可能就那么点，所以，尽早储备一个通用的技术栈。&lt;/p&gt;
&lt;p&gt;资本家为了奴役你给你挖了很多坑，比如消费主义，比如训练你当螺丝钉，还有最重要的就是榨干你的空闲时间。&lt;/p&gt;
&lt;p&gt;打工的钱都是棺材费，自己从市场赚的才叫钱。尽早摆脱打工人的困境比啥都重要。&lt;/p&gt;
&lt;p&gt;一旦你的成本很低，时间就是你的朋友，否则就是你的敌人。这好比一颗树，只要根不死，总能活过来。&lt;/p&gt;
&lt;p&gt;在体验一样的情况下，选成本低的，但不要为此牺牲体验&lt;/p&gt;
&lt;p&gt;如果花在开源上的时间和刷牙洗脸一样，那么可持续性就不是问题。&lt;/p&gt;
&lt;p&gt;宣传应当是你的产品的不可分割的一部分，它和内容同等重要，并且可以借助技术做得更好。五分内容五分宣传，这就是五五开定律。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>使Windows  Terminal变得更易用</title><link>https://barry.ee/writing/wt/</link><guid isPermaLink="true">https://barry.ee/writing/wt/</guid><pubDate>Sun, 08 Jan 2023 21:38:14 GMT</pubDate><content:encoded>&lt;h2&gt;1.个性化美化&lt;/h2&gt;
&lt;p&gt;在wt(Windows Terminal)设置面板中打开json文件，然后找到&lt;code&gt;defaults&lt;/code&gt;关键字并在后面花括号里追加以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;亚克力毛玻璃效果
&amp;quot;useAcrylic&amp;quot;: true,
亚克力毛玻璃效果透明度
&amp;quot;acrylicOpacity&amp;quot;: 0.2,
背景壁纸
&amp;quot;backgroundImage&amp;quot;: &amp;quot;C:/Users/YangChentao/Pictures/Saved Pictures/wt.jpeg&amp;quot;,
背景壁纸透明度
&amp;quot;backgroundImageOpacity&amp;quot;: 0.4,
&amp;quot;fontFace&amp;quot;: &amp;quot;JetBrainsMono Nerd Font Mono&amp;quot;,
&amp;quot;fontSize&amp;quot;: 14
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.oh-my-posh&lt;/h2&gt;
&lt;p&gt;微软商店下载 oh-my-posh&lt;/p&gt;
&lt;p&gt;下载安装完成后会自动配置；&lt;/p&gt;
&lt;p&gt;此时在wt里输入&lt;code&gt;code $PROFILE&lt;/code&gt;用vscode打开该配置文件，打开后添加以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;oh-my-posh init pwsh --config $env:POSH_THEMES_PATH\montys.omp.json | Invoke-Expression

cls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cls&lt;/code&gt;为清屏启动项。&lt;/p&gt;
&lt;h2&gt;3.安装 Nerd 字体解决 oh-my-posh 字体图标不显示&lt;/h2&gt;
&lt;p&gt;推荐JetBrains Mono Medium Nerd Font Complete Mono 字体&lt;/p&gt;
&lt;p&gt;下载安装并在wt配置文件中更改&lt;/p&gt;
&lt;h2&gt;4.解决ssh连接长时间不操作自动断开&lt;/h2&gt;
&lt;p&gt;在C:\Users\用户名\ .ssh\config 文件中添加如下代码（没有这个文件自己建一个）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host *
  ServerAliveInterval 40
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.启动专注模式让你的 WT 更具逼格&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/lzj6pq-0.png&quot; alt=&quot;专注模式&quot;&gt;&lt;/p&gt;
&lt;h2&gt;6.去掉烦人的启动版权信息并默认管理员启动&lt;/h2&gt;
&lt;p&gt;在 powershell 启动命令行末尾加上 &lt;code&gt;-nologo&lt;/code&gt; 即可
&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/m1yvcp-0.png&quot; alt=&quot;版权信息&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>步入Linux的现代方法</title><link>https://barry.ee/writing/linux/</link><guid isPermaLink="true">https://barry.ee/writing/linux/</guid><description>Linux 入门指南</description><pubDate>Wed, 21 Dec 2022 00:34:14 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;基于 Frank&amp;#39;s Linux 课程的笔记&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;0.0 系统的认识&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;什么是系统？&lt;/li&gt;
&lt;li&gt;鼠标能点、键盘能输入东西、阅读看电影，还可以拓展安装一些软件， 简单来说就是人机交互所依赖的东西，开机依赖系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;0.1 Linux操作系统认识，以及开源的提出：Linux的千奇百怪的版本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;目前世界上流行的电脑系统：&lt;/li&gt;
&lt;li&gt;Windows- Bill Gates (比尔·盖茨)&lt;/li&gt;
&lt;li&gt;GNU/Linux-Linus Benedict Torvalds(林納斯·托瓦茲)-开源&lt;/li&gt;
&lt;li&gt;Unix(Linux的爸爸)- 湯普遜和里奇合-给政府机关、公司等机构付费使用&lt;/li&gt;
&lt;li&gt;Linux发行版本：Ubuntu Centos Red Hat Kali ……&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;0.2 开源的含义&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;公开、分享、共同进步&lt;/li&gt;
&lt;li&gt;开源不一定免费&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;0.3 Linux的用途，各类发行版本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Linux主要运用在服务器上&lt;/li&gt;
&lt;li&gt;Linux严格来说是单指操作系统的内核，因操作系统中包含了许多用户图形接口和其他实用工具
只要遵循GNU 通用公共许可证（GPL），任何个人和机构都可以自由地使用Linux的所有底层源代码，也可以自由地修改和再发布
Linux衍生：&lt;/li&gt;
&lt;li&gt;Debian—Ubuntu,Deepin,Raspberry Pi OS,Knopix
Fedora—RedHat,Centos,Moblin
OpenSUSE—GeckoLinux,openSUSE EcoLab Spin&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.1 Vmware虚拟机&lt;/h2&gt;
&lt;p&gt;安装系统的方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;实体机&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;双系统&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;虚拟机&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.2 VMware 16&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;软件版本，大多数人追求新版本，企业里更多需要的是稳定，我们应该根据企业标准去学习，企业要什么我们学什么&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.3 关于从15更新到16的说法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Vmware15不支持Ubuntu20.04&lt;/p&gt;
&lt;p&gt;更新版本并不会影响虚拟机的还原&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2.1 先尝试Ubuntu&lt;/h2&gt;
&lt;p&gt;详见：Linux(Ubuntu)零基础体验教学&lt;/p&gt;
&lt;p&gt;PS：查看软件安装过执行内容，有助于学习&lt;/p&gt;
&lt;h2&gt;2.2 VMware Tools&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;配置Ubuntu镜像源&lt;/li&gt;
&lt;li&gt;VMware Tools安装&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;tar zxvf VMwareTools-10.3.22-15902021.tar.gz \
cd vmware-tools-distrib/
ls
sudu ./vmware-install.pl
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.3 Ubuntu 20.04设置&lt;/h2&gt;
&lt;p&gt;详见2.1视频链接&lt;/p&gt;
&lt;h2&gt;2.4 Linux其他发行版本的安装指导&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;商业发行版&lt;/li&gt;
&lt;li&gt;社区发行版&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2.5 下载指导&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;从官网下载&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.1 Linux究竟需要我们学习什么？——Linux四大组成部分&lt;/h2&gt;
&lt;p&gt;Linux入门不是学“Linux”，先体验各发行版Linux，比较和其他系统的不同和相同点，Linux究竟学习的是Shell&lt;/p&gt;
&lt;p&gt;Linux操作系统四个部分&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux Kernel 内核&lt;/li&gt;
&lt;li&gt;GNU(“GNU’s Not Unix!”)工具&lt;/li&gt;
&lt;li&gt;GUI Desktop环境&lt;/li&gt;
&lt;li&gt;Application 应用&lt;/li&gt;
&lt;li&gt;PS：IT术语，它并不是遵循通常的英语音标，而是专业术语&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.2 Linux是命令还是图形界面？——GUI 是什么？ 那GNU是什么东西？GNU/Linux 和Linux有什么区别？&lt;/h2&gt;
&lt;p&gt;Linux内核基于&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GUI-界面&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GNU-命令、系统工具&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.3 Linux内核组成部分&lt;/h2&gt;
&lt;p&gt;Linux Kernel&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1.硬件设备的管理&lt;/li&gt;
&lt;li&gt;2.软件程序(系统)、操作软件&lt;/li&gt;
&lt;li&gt;3.系统内存&lt;/li&gt;
&lt;li&gt;4.文件管理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.4 文件系统&lt;/h2&gt;
&lt;p&gt;文件系统就是读、写标准&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux中分区概念ext ext2 ext3 ext4&lt;/li&gt;
&lt;li&gt;Windows 磁盘文件管理概念FAT32 NTFS exFAT&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.5 GNU核心： coreutils and shell&lt;/h2&gt;
&lt;p&gt;GNU组织
Unix上具有的一些软件，Linux内核本身没有，所以GNU他们模仿Unix，为Linux写了一些必要的软件&lt;/p&gt;
&lt;p&gt;GNU核心Coreutils
指原本在Unix上的一些命令和工具，被移植到了Linux上，供Linux使用的一套工具、coreutilities软件包，包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;用来处理文件的工具&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用来操作文本的工具&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用来管理进程的工具&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GNU核心Shell&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;提供给用户使用的软件，用户拿它使用电脑，实现交互&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;命令行壳层提供一个命令行界面（CLI）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;图像壳层提供一个图形用户界面（GUI）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.6 Shell：CLI和GUI，命令和界面&lt;/h2&gt;
&lt;p&gt;Shell类型：bash，zsh，korn，tcsh，oh-my-zsh&lt;/p&gt;
&lt;h2&gt;3.7 GUI Desktop&lt;/h2&gt;
&lt;p&gt;Xwindows，KDE，GNOME，Unity
结束语：经验介绍
重点在于Shell
画思维图总结Linux操作系统关系&lt;/p&gt;
&lt;h2&gt;4.1 CLI准备&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CLI相关设置，选择Preferences&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Theme Varian&lt;/em&gt;t 主题变换
&lt;em&gt;Open new terminals in&lt;/em&gt; 打开一个新终端的方式，Tab代表在同一窗口下创建新终端，Window代表开一个新窗口打开新终端
&lt;em&gt;New tab position&lt;/em&gt; 新终端位置，默认为上一次位置&lt;/li&gt;
&lt;li&gt;快捷方式设置，Ctrl+Alt+T 打开新终端&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.2 CLI Terminal&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yeats@yeats-virtual-machine:~$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;用户名@机器名：当前所在目录 $表示等待用户输入&lt;/li&gt;
&lt;li&gt;~表示用户home目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/home&lt;/code&gt;是存放所有用户文件的根目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Settings中About可以查看机器名与相关信息&lt;/p&gt;
&lt;h2&gt;4.3 搞定Linux命令参数，得心应手使用各类命令——授之于渔 先拿ls开张&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ls&lt;/code&gt;命令 用来显示目标列表，在Linux中是使用率较高的命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ls -l&lt;/code&gt; 的缩写就是 ll ，列出当前目录可见文件详细信息，输出的信息从左到右依次包括文件名、文件类型、权限、硬链接数、所有者名、组名、大小（byte）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;man&lt;/code&gt;命令是Linux下的帮助指令，通过man指令可以查看Linux中的指令帮助、配置文件帮助和编程帮助等信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐：Linux命令搜索&lt;/p&gt;
&lt;p&gt;推荐：&lt;a href=&quot;https://wangchujiang.com/linux-command/&quot;&gt;Linux命令搜索&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4.4 Linux根目录，它们和Windows有什么区别&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Windows 盘符，文件目录 \反斜线&lt;/li&gt;
&lt;li&gt;Linux一切皆文件，文件目录 / 斜线&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.5 Linux根目录解析，fhs权威论文，搞定所有的发行版本文件夹分布&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/ linux&lt;/code&gt;根目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/bin&lt;/code&gt; 二进制目录 GUN工具 命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/cdrom&lt;/code&gt; 光盘&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc&lt;/code&gt; 系统配置文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/home&lt;/code&gt; 用户主目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/lib&lt;/code&gt; 库目录 存放库文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/lost+found&lt;/code&gt; 当系统发生错误时，将一些遗失的片段放置在这个目录下&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/mnt&lt;/code&gt; 挂载（外在的设备和电脑进行连接）目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/proc&lt;/code&gt; 伪文件系统&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/run&lt;/code&gt; 运行目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/snap&lt;/code&gt; 包管理，软件包安装管理方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/tmp&lt;/code&gt; 临时目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var&lt;/code&gt; 可变目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/boot&lt;/code&gt; 启动目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev&lt;/code&gt; 设备目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/media&lt;/code&gt; 媒体目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/opt&lt;/code&gt; 可选目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/root&lt;/code&gt; root用户的主目录 管理员&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/sbin&lt;/code&gt; 系统二进制目录，GNU高级管理员使用的命令或工具&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/srv&lt;/code&gt; 服务目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr&lt;/code&gt; 用户二进制目录，GNU工具&lt;/li&gt;
&lt;li&gt;详见：FHS文件系统层级标准&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;详见：&lt;a href=&quot;https://www.pathname.com/fhs/&quot;&gt;FHS文件系统层级标准&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4.6 cd命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; 进入用户主目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd..&lt;/code&gt; 切换到上一层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd –&lt;/code&gt; 返回到上一次的工作目录。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.7 Ctrl + C？ 拉到吧，在Linux上可不是复制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+c( kill foreground process ) 发送SIGINT信号给前台进程组中的所有进程，强制终止程序的执行&lt;/li&gt;
&lt;li&gt;Ctrl+l 清屏&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.8 绝对路径&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;全路径 D:\Study\Frank_FuckPPT\Linux&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.9 相对路径&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;不全路径 \Frank_FuckPPT\Linux&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.10 Linux上的路径与Windows上的路径&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gedit /Doucument/doc/1.txt&lt;/code&gt; 操作根目录 绝对路径&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gedit ~/Document/doc/1.txt&lt;/code&gt; 当前目录 相对路径&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gedit ./Document/doc/1.txt&lt;/code&gt; 当前目录 相对路径&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gedit Document/doc/1.txt&lt;/code&gt; 当前目录 相对路径&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.11 如何练习？经验课&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;单点符号.当前文件&lt;/li&gt;
&lt;li&gt;双点符号..当前目录的父目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.12 ls进阶用法：文件夹下各种匹配过滤符号&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;号替代多个符号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;？&lt;/code&gt;号替代一个符号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-a,，--all&lt;/code&gt; 列出目录中所有文件，包括以“.”开头的文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l， --format=long，--format=verbose&lt;/code&gt;除每个文件名外，增加显示文件类型、权限、硬链接数等信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-F，--classify， --file-type&lt;/code&gt;在每个文件名后附上一个字符以说明该文件的类型&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.13 touch命令&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;touch&lt;/code&gt;命令 两个功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一是用于把已存在文件的时间标签更新为系统当前的时间（默认方式）&lt;/li&gt;
&lt;li&gt;二是用来创建新的空文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.14 cp命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cp&lt;/code&gt;命令 将源文件或目录复制到目标文件或目录中&lt;/li&gt;
&lt;li&gt;源文件：制定源文件列表。默认情况下，cp命令不能复制目录，如果要复制目录，则必须使用-R选项&lt;/li&gt;
&lt;li&gt;目标文件：指定目标文件。当“源文件”为多个文件时，要求“目标文件”为指定的目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cp&lt;/code&gt; 你想复制的文件？ 你想复制到哪？&lt;/li&gt;
&lt;li&gt;-i覆盖既有文件之前先询问用户&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-R/r&lt;/code&gt;递归处理，将指定目录下的所有文件与子目录一并处理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.15 cp递归练习技巧&lt;/h2&gt;
&lt;p&gt;pwd 显示当前工作目录&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cp -R ./*.java ~/Documents/temp/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.16 Linux终端光标移动技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tab自动补全&lt;/li&gt;
&lt;li&gt;Ctrl + E 跳到行尾&lt;/li&gt;
&lt;li&gt;Ctrl + B 光标向左移动&lt;/li&gt;
&lt;li&gt;Ctrl + H 删除光标前一个字符 相当于退格&lt;/li&gt;
&lt;li&gt;Ctrl + T 把光标前一个字符往后移动&lt;/li&gt;
&lt;li&gt;Ctrl + R 搜索之前用过的命令&lt;/li&gt;
&lt;li&gt;Ctrl + W 删除光标前一个单词&lt;/li&gt;
&lt;li&gt;Ctrl + U 删掉光标前面的内容&lt;/li&gt;
&lt;li&gt;Ctrl + K 删掉光标后面的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.17 lnk链接文件的介绍&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.lnk快捷方式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linux链接文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1.符号链接(软链接)&lt;/p&gt;
&lt;p&gt;指快捷方式 原来的文件/文件夹必须存在&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2.硬链接&lt;/p&gt;
&lt;p&gt;指副本 原来的文件/文件夹必须存在&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.18 符号链接和硬链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ln&lt;/code&gt;命令 用来为文件创建链接，链接类型分为硬链接和符号链接两种，默认的链接类型是硬链接。如果要创建符号链接必须使用&amp;quot;-s&amp;quot;选项&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ln&lt;/code&gt; 原文件名 链接的文件名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ls -l&lt;/code&gt; 查看&lt;/li&gt;
&lt;li&gt;软链接：有指向，是一个单独的文件，不同介质&lt;/li&gt;
&lt;li&gt;硬链接：无指向，同一介质&lt;/li&gt;
&lt;li&gt;软链接复制的是链接文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.19 注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;符号链接Symbolic links&lt;/li&gt;
&lt;li&gt;软链接 Soft links&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.20 mv命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;mv命令 用来对文件或目录重新命名，或者将文件从一个目录移到另一个目录中&lt;/li&gt;
&lt;li&gt;做重命名，mv 重命名谁 命名成什么&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.20 移动和骚操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;做移动，&lt;code&gt;mv&lt;/code&gt; 移动的文件 移动到的目录&lt;/li&gt;
&lt;li&gt;输入完之后，&lt;code&gt;cd !$&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;!$是列出并执行你的命令历史里面最近的一条记录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.21 rm——最佳年度删库跑路&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo rm -rf /*&lt;/code&gt; 该命令极度危险&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm&lt;/code&gt; 命令可以删除一个目录中的一个或多个文件或目录，也可以将某个目录及其下属的所有文件及其子目录均删除掉。对于链接文件，只是删除整个链接文件，而原有文件保持不变&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm -i&lt;/code&gt; 有提示&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm -i -rf&lt;/code&gt; 无提示&lt;/li&gt;
&lt;li&gt;注意： linux没有回收站&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.22 创建文件夹以及删除文件夹&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkdir&lt;/code&gt; 用来创建目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rmdir&lt;/code&gt; 用来删除空目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.23 文件类型&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;file&lt;/code&gt;用来探测给定文件的类型&lt;/li&gt;
&lt;li&gt;Windows 文本是txt&lt;/li&gt;
&lt;li&gt;linux 文本是text&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.24 cat ，more ，less&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat&lt;/code&gt; 连接多个文件并打印到标准输出，适用于短文本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n, --number&lt;/code&gt; 对所有行编号，从1开始编号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;more&lt;/code&gt; 显示文件内容，每次显示一，以全屏方式显示&lt;/li&gt;
&lt;li&gt;b上一页 space 下一页 q退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;less&lt;/code&gt;分屏上下翻页浏览文件内容&lt;/li&gt;
&lt;li&gt;&lt;code&gt;less&lt;/code&gt;命令允许用户向前或向后浏览文件，而&lt;code&gt;more&lt;/code&gt;命令只能向前浏览。&lt;/li&gt;
&lt;li&gt;用&lt;code&gt;less&lt;/code&gt;命令显示文件时，用PageUp键向上翻页，用PageDown键向下翻页。要退出less程序，应按Q键&lt;/li&gt;
&lt;li&gt;浏览文件中输入 / 用于搜索&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.25 tail 和 head命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;tail&lt;/code&gt; 在屏幕上显示指定文件的末尾若干行&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;tail -n 2 demo.c
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;head显示文件的开头部分&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;head -n 2 demo.c
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.1 任务管理器&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;进程、性能、用户、服务&lt;/li&gt;
&lt;li&gt;服务：监测用户行为，为用户服务&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.2 ps和top命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;top&lt;/code&gt; 可以实时动态地查看系统的整体运行情况，是一个综合了多方信息监测系统性能和运行信息的实用工具&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps&lt;/code&gt; (process status) linux最复杂的命令之一，是最基本同时也是非常强大的进程查看命令，使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等，总之大部分信息都是可以通过执行该命令得到的&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps axo pid,comm,pcpu&lt;/code&gt; # 查看进程的PID、名称以及CPU 占用率&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps -aux | grep named&lt;/code&gt; # 查看named进程详细信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.3 kill命令&lt;/h2&gt;
&lt;p&gt;配合&lt;code&gt;ps -aux | grep named&lt;/code&gt; # 查看named进程详细信息
&lt;code&gt;kill pid&lt;/code&gt; 杀死进程&lt;/p&gt;
&lt;h2&gt;5.4 挂载的含义&lt;/h2&gt;
&lt;p&gt;详见：linux挂载的作用(&lt;a href=&quot;https://blog.csdn.net/qq_35583154/article/details/86569903&quot;&gt;https://blog.csdn.net/qq_35583154/article/details/86569903&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;插入新硬盘，分了新磁盘区sdb1，但它现在还不属于/， 把新硬盘的区sdb1挂载到工作目录的/Share/文件夹下，之后访问这个/Share/文件夹就相当于访问这个硬盘的sdb1分区了，对/Share/的任何操作，都相当于对sdb1里文件的操作&lt;/p&gt;
&lt;h2&gt;5.5 mount&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mount&lt;/code&gt; 用于挂载Linux系统外的文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/mnt&lt;/code&gt; 为自动挂载点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo fdisk -l&lt;/code&gt; 查看硬盘及分区信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo mount /dev/sdc1 /mnt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo umount /mnt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;自动挂载的目录不能卸载&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.5 挂载的意义——尝试使用U盘？自动播放黑客恶意？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;企业里不自动挂载，防止恶意播放脚本auto病毒&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.6 安卓设备连接挂载&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安卓链接协议(SMB)挂载路径 &lt;code&gt;/run/suer/1000/gvfs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.7 df和du&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;df&lt;/code&gt; 用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为KB。可以利用该命令来获取硬盘被占用了多少空间，目前还剩下多少空间等信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h&lt;/code&gt;或&lt;code&gt;--human-readable&lt;/code&gt;：以可读性较高的方式来显示信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;du&lt;/code&gt; 也是查看使用空间的，但是与&lt;code&gt;df&lt;/code&gt;命令不同的是Linux du命令是对文件和目录磁盘使用的空间的查看，还是和df命令有一些区别的&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.8 sort命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sort&lt;/code&gt; 对文本文件中所有行进行排序&lt;/li&gt;
&lt;li&gt;默认对每一行第一个字符排序，并展示出来，并不会改变原来的文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt;， &lt;code&gt;--numeric-sort&lt;/code&gt; 根据数字排序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-M&lt;/code&gt;，&lt;code&gt;--month-sort&lt;/code&gt; 按照非月份、一月、十二月的顺序排序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt;，&lt;code&gt;--reverse&lt;/code&gt; 将结果倒序排列&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.9 grep基础认识、搜索文件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; (global search regular expression(RE) and print out the&lt;/p&gt;
&lt;p&gt;line，全面搜索正则表达式并把行打印出来）是一种强大的文本搜索工具，它能使用正则表达式搜索文本，并把匹配的行打印出来&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;grep 543 ~/Templates/1.txt&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5.10 打包、压缩、归档、解压缩 它们究竟区别在哪？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tar&lt;/code&gt; 打包、压缩&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tar -cvf 1.tar 1.txt&lt;/code&gt; 仅打包，不压缩&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tar -zcvf 1.tar.gz 1.txt&lt;/code&gt; 打包后，以 gzip 压缩&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tar -zxvf /opt/soft/test/1.tar.gz&lt;/code&gt; 将tar包解压缩&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.1 父子shell的概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;bash&lt;/li&gt;
&lt;li&gt;ps-f&lt;/li&gt;
&lt;li&gt;ps –forest&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.2 分号在命令里有什么作用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;命令之间带分号 ； 依次执行&lt;/li&gt;
&lt;li&gt;创建一个子shell去执行&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.3 sleep和jobs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sleep&lt;/code&gt; 将目前动作延迟一段时间 ，后面可接 &lt;code&gt;s&lt;/code&gt; 为秒，&lt;code&gt;m&lt;/code&gt; 为 分钟，&lt;code&gt;h&lt;/code&gt; 为小时，&lt;code&gt;d&lt;/code&gt; 为日数&lt;/p&gt;
&lt;p&gt;挂在后台,如果要干掉，则用&lt;code&gt;kill&lt;/code&gt;命令&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;jobs&lt;/code&gt; 显示作业的状态，&lt;code&gt;-l&lt;/code&gt; 在作业信息中额外的列出PID&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.4 后台&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;后台执行 &lt;code&gt;tar -zxvf ……；&amp;amp;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;6.5 coproc协程&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Liunx协程处理命令。协程可以同时做两件事。在后台生成一个子shell，并在子shell中执行命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coproc sleep 10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coproc frank_av{ sleep 10; sleep 300;}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一定要分号结尾，大括号内空格&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.6 外部命令和内建命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Shell执行的命令可以分为内建命令（built-in）和外部命令（external） 前者是构建在shell内部&lt;/li&gt;
&lt;li&gt;后者是一个独立的文件（可以是二进制文件，也可以是一个脚本） 内建命令由当前shell本身来执行，例如echo, cd等等&lt;/li&gt;
&lt;li&gt;外部命令的执行shell进程会fork一个子进程，父进程随后挂起，然后在子进程中exec加载外部文件，子进程返回后，父进程才继续执行&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6.7 alias别名&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alias&lt;/code&gt; 定义或显示别名。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; 显示指定命令的类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;alias li=’ls -li’&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;但是关闭当前shell就不能用了&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.1 什么是环境变量？彻底搞清楚究竟什么是环境变量！！！！！&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;环境变量（environment variables）一般是指在操作系统中用来指定操作系统运行环境的一些参数，如：临时文件夹位置和系统文件夹位置等&lt;/li&gt;
&lt;li&gt;文件夹写入的环境变量，意味则可以在任何位置访问该文件夹，相当于告诉系统这个目录在哪里&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.2 全局环境变量和局部环境变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;windows:系统变量与用户变量&lt;/li&gt;
&lt;li&gt;linux: 全局环境变量和局部环境变量&lt;/li&gt;
&lt;li&gt;全局环境变量&lt;code&gt;printenv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;printenv USER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo $USER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd $HOME&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.3 用户和局部变量的定义&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;局部变量只能在当前shell执行，子shell或者退出后就不能用了&lt;/li&gt;
&lt;li&gt;注意 定义局部变量不要大写&lt;/li&gt;
&lt;li&gt;全局变量用大写，下划线命名法&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.4 定义全局变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;export&lt;/code&gt; 为shell变量或函数设置导出属性。&lt;/li&gt;
&lt;li&gt;可以子shell里执行，但关闭后仍失效&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.5 默认的环境变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.6 为啥要用环境变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;配置开发环境需要使用&lt;/li&gt;
&lt;li&gt;临时环境变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PATH=$PATH:/home/yeats/Templates/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.7 永久配置环境变量？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;启动文件：开机的时候默认执行的环境变量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bash shell&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1登录shell&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2非登录就打开shell&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3运行脚本非交互shell&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cat /etc/profile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;~/.bashrc&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;~/.bash_profile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;~/.profile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;~/.bash_login&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cat bashrc&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;加入全局环境变量(需学习vim)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8.1 PMS系统和软件安装的介绍&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PMS Package Management System&lt;/li&gt;
&lt;li&gt;解决工具依赖问题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt-get install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt-cache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aptitude(已淘汰)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8.2 安装、更新、卸载&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;apt -h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;更新 &lt;code&gt;sudo apt update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;升级 &lt;code&gt;sudo apt upgrade&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;卸载 &lt;code&gt;sudo apt remove oneko&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8.3 其他发行版本？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;server版本配置镜像源&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sudo vim /etc/apt/source.list&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://archive.ubuntu.com/ubuntu/&quot;&gt;http://archive.ubuntu.com/ubuntu/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;修改成国内阿里云库:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mirrors.aliyun.com/ubuntu/&quot;&gt;http://mirrors.aliyun.com/ubuntu/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8.4 安装第三方软件案例：例如github开源软件的指导&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;详见：&lt;a href=&quot;https://github.com/nvbn/thefuck&quot;&gt;https://github.com/nvbn/thefuck&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;9.1 用户权限的含义和作用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;用户与权限&lt;/li&gt;
&lt;li&gt;不可能让所有人有所有的权限-不安全&lt;/li&gt;
&lt;li&gt;避免被入侵&lt;/li&gt;
&lt;li&gt;用户ID UID&lt;/li&gt;
&lt;li&gt;系统用户UID&amp;lt;500&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cat /etc/passwd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo cat /etc/shadow&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;9.2 创建、删除、更改用户&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;创建&lt;code&gt;sudo useradd user1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;删除&lt;code&gt;sudo userdel user1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;更改密码&lt;code&gt;sudo passwd user1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chage&lt;/code&gt; 修改帐号和密码的有效期限&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;9.3 group&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;linux组groups&lt;/p&gt;
&lt;p&gt;目的 ：共享资源的权限&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;tail /etc/group&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ubuntu不允许把所有用户纳入一个组，而是每个用户都有一个单独的组&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sudo groupadd groupfrank&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sudo groupdel groupfrank&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;9.4 文件、文件夹权限&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rwx&lt;/code&gt; 文件所有者（Owner）组创始人的权限
&lt;code&gt;r-x&lt;/code&gt; 用户组（Group）组下属成员权限
&lt;code&gt;r-x&lt;/code&gt; 其它用户（Other Users）其它组成员权限&lt;/p&gt;
&lt;p&gt;详见：Linux chmod命令（&lt;a href=&quot;https://www.runoob.com/linux/linux-comm-chmod.html&quot;&gt;Linux chmod 命令 | 菜鸟教程 (runoob.com)&lt;/a&gt;）&lt;/p&gt;
&lt;h2&gt;9.5 chmod命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;usermod&lt;/code&gt;命令 用于修改用户的基本信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;usermod&lt;/code&gt; 命令不允许你改变正在线上的使用者帐号名称。&lt;/li&gt;
&lt;li&gt;当 &lt;code&gt;usermod&lt;/code&gt; 命令用来改变user id，必须确认这名user没在电脑上执行任何程序&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;附上：vi/vim键盘图&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/20210510170218321.png&quot; alt=&quot;vi/vim键盘图&quot;&gt;&lt;/p&gt;
&lt;h2&gt;10.1 编辑器简单介绍：vim编辑器之神； emac神之编辑器&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;emacs-神之编辑器&lt;/li&gt;
&lt;li&gt;vim-编辑器之神&lt;/li&gt;
&lt;li&gt;Vim是从 vi发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富，在程序员中被广泛使用。和Emacs并列成为类Unix系统用户最喜欢的编辑器&lt;/li&gt;
&lt;li&gt;vi 编辑器通常被简称为 vi，而 vi 又是 visual editor 的简称 。它可以执行输出、删除、查找、替换、块操作等众多文本操作，而且用户可以根据自己的需要对其进行定制，这是其他编辑程序所没有的&lt;/li&gt;
&lt;li&gt;Vim 是 vi 的加强版，比 vi 更容易使用。vi 的命令几乎全部都可以在 vim 上&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.2 vim的简单使用方式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安装vim&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt install vim&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;vim工作模式，国外一般认为两种模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;普通模式(命令操作模式)：操作文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;插入模式：编辑&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;编辑模式到普通模式：ESC&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;国内一般认为三种模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;一般命令模式：简称一般模式，也是最先进入的工作模式，输入vi +文件名可直接进入一般命令模式，在此模式下可进行文本内容的查看、复制、删除、替换等功 能。当不能输入相关文本内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;编辑模式：在一般模式下，输入 i 或 o 或 a 进入编辑模式，在此模式下可输入文本内 容。当输入 i 时，工作界面如图所示，只有此时状态才可以输入文件内容。输 入完成后，可单击 ESC 键退出编辑状态，进入一般模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;命令行模式：在一般模式下，输入：或/或？进入命令行模式，在此模式下可输入相关命令当输入：wq 此时命令表示保存退出命令，单击回车键，自动保存文件，并退 出 vi 编辑器或者单击 ESC 键，重新返回一般模式&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;三种工作模式关系如图所示&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/2021051019480394.png&quot; alt=&quot;VIM三种工作模式关系&quot;&gt;&lt;/p&gt;
&lt;h3&gt;vim 编辑器的退出，一般分三种情况&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;：q&lt;/code&gt; 表示不保存退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;：wq&lt;/code&gt; 保存退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;：q！&lt;/code&gt;强制退出，此时也不保存文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.3 移动光标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;上：&lt;code&gt;k&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;下：&lt;code&gt;j&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;左：&lt;code&gt;h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;右：&lt;code&gt;l&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;下一行：&lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;上一行：&lt;code&gt;w&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;查找上一处字符：&lt;code&gt;N&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;查找下一处字符：&lt;code&gt;n&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.4 翻页&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;上翻页(BACKWARD)：&lt;code&gt;ctrl+B&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;下翻页(FORWARD)：&lt;code&gt;ctrl+F&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;上滚：&lt;code&gt;ctrl+E&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;下滚：&lt;code&gt;ctrl+Y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;移动到最后一行：&lt;code&gt;G 或者shift+g&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;移动到第一行：&lt;code&gt;gg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.5 不同方式编辑文本、跳跃单词操作技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt;光标位置的前面插入&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; 光标位置后面的插入&lt;/li&gt;
&lt;li&gt;&lt;code&gt;o&lt;/code&gt; 直接enter到下一行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; 删除光标所在字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dd&lt;/code&gt; 删除整个一行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt; 撤销&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dw&lt;/code&gt; 移除当前所在光标往后到单词&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; 跳跃单词首字母&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt; 跳跃单词最后&lt;/li&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt; 跳跃单词 先跳跃到单词首字母，然后跳跃到单词最后&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shift+w&lt;/code&gt; ;&lt;code&gt;shift+b&lt;/code&gt;大跳&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.6 跳跃行首行尾技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shift+6&lt;/code&gt; &lt;code&gt;或者0&lt;/code&gt; 跳跃到本行到开头&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shift+4&lt;/code&gt; 跳跃到本行末尾&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.7 大括号跳跃函数段落技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{}&lt;/code&gt;跳跃大括号&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.8 vim复制剪切粘贴&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt;粘贴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yw&lt;/code&gt;复制一个单词&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y$&lt;/code&gt; 从当前开始往后复制到行末尾&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.9 Visual可视化模式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v&lt;/code&gt; 选择文本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V&lt;/code&gt; 选择行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v G&lt;/code&gt; 全选&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+v&lt;/code&gt;矩阵选择&lt;/li&gt;
&lt;li&gt;&lt;code&gt;o&lt;/code&gt;切换文本首尾&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vaw&lt;/code&gt;快速选择单词&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vab&lt;/code&gt;包括括号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vaB&lt;/code&gt;包括大括号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;va&amp;lt;&lt;/code&gt; 包括尖括号&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.10 视图模式其它技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v shift+&amp;lt;&lt;/code&gt;往左缩进&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v shift+&amp;gt;&lt;/code&gt;往右缩进&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shift+~&lt;/code&gt;或者&lt;code&gt;shift+u shift+U&lt;/code&gt;大小写转换&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.11 查找和替换&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;查找 &lt;code&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;按n查找下一个&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:s /const/let/g&lt;/code&gt; 一行const替换成let&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:%s /const/let/g&lt;/code&gt; 所有const替换成let&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set number&lt;/code&gt; 临时显示行号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:9,15s /const/let/g&lt;/code&gt; 9-15行const替换成let&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:%s /const/let/gc&lt;/code&gt; 有提示的替换&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10.12 vim的基础配置&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;touch .vimrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim .vimrc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将以下代码写入.vimrc中&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set syntax=on
set tabstop=4
set softtabstop=4
set number
set enc=utf-8
set showmatch
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;source .vimrc&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>所有过往，皆为序章</title><link>https://barry.ee/writing/essay/</link><guid isPermaLink="true">https://barry.ee/writing/essay/</guid><pubDate>Tue, 10 Mar 2020 00:34:14 GMT</pubDate><content:encoded>&lt;div class=&quot;ipage&quot;&gt;
  &lt;div class=&quot;ititle&quot;&gt;所有过往，皆为序章&lt;/div&gt;
  &lt;div class=&quot;izhengwen&quot;&gt;
  &lt;p&gt;当韶华散去，便不问一切是否可以重来。&lt;/p&gt;

  &lt;p&gt; 这是我单曲循环了许久的一首歌。

&lt;p&gt;第一次是在日推里发现它的，初次听到这首歌的旋律时，&lt;/p&gt;
&lt;p&gt;一瞬间它就直击我内心，当听到:
我们只是共享了几个故事&lt;/p&gt;
&lt;p&gt;对你来说也许是平凡小事&lt;/p&gt;
&lt;p&gt;说出的字一秒就成了历史&lt;/p&gt;
&lt;p&gt;我只想紧抓着不让它流逝&lt;/p&gt;
&lt;p&gt;我们其实才是最适合彼此&lt;/p&gt;
&lt;p&gt;多想让你知道我此刻心事&lt;/p&gt;
&lt;p&gt;今天的誓明天是否还坚持&lt;/p&gt;
&lt;p&gt;你是否还有勇气再说开始&lt;/p&gt;&lt;/p&gt;
  &lt;p&gt;我心中瞬间五味杂粮

&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;瓦解&lt;/p&gt;
&lt;p&gt;沉沦&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;“或许太重感情的人，日子终究不会好过，信任、依赖、念旧，分分钟把你虐的万劫不复。”&lt;/p&gt;
&lt;p&gt;听过无数话都看似很有道理，但我只信两句话，&lt;/p&gt;
&lt;p&gt;一个物以类聚，&lt;/p&gt;
&lt;p&gt;一个因果报应。&lt;/p&gt;
&lt;p&gt;最大的幸福莫过于固执和深情得到回应
这是这首歌的一个热评，固然每个人对这句话的解读都能有所不同，但不可否认的是这确实能引发大多数人的共鸣，&lt;/p&gt;
&lt;p&gt;无论是从数据上，&lt;/p&gt;
&lt;p&gt;还是内容上。&lt;/p&gt;
&lt;p&gt;于此
我是反过来解读这句话的：&lt;/p&gt;
&lt;p&gt;“一个了解你的人，最起码不会让你一直难过，如果明知道这样做你不好&lt;/p&gt;
&lt;p&gt;受却还是做了，单是这样的恶意和愚蠢就不该被原谅。”&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                                                念
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们其实才是最适合彼此&lt;/p&gt;
&lt;p&gt;多想让你知道我此刻心事&lt;/p&gt;
&lt;p&gt;今天的誓明天是否还坚持&lt;/p&gt;
&lt;p&gt;你是否还有勇气再说开始&lt;/p&gt;
&lt;p&gt;句句都是那么让人感到措手不及，&lt;/p&gt;
&lt;p&gt;正如人间失格里面有一句话：胆小鬼连幸福都害怕，碰到棉花都会受伤，我想我是骨子里透着卑微的胆小鬼。
有些风景，一旦入眼入心，即便刹那，也是永恒。
/&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;那些花了好久才想明白的事，总是会被偶尔的情绪失控全部推翻。&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;只有继续从容向前，才不会辜负那些在漫漫长夜中依旧熠熠生辉的旧时光。人这一辈子，无非就是一路的失去，天长地久这种东西，正因为难得，才被歌颂。&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;曾经
未来遥远的没有形状&lt;/p&gt;
&lt;p&gt;我们单纯得没有烦恼&lt;/p&gt;
&lt;p&gt;后来
孤街没了浪人，深巷没了老猫&lt;/p&gt;
&lt;p&gt;梦想缩了水，欲望也瘪的不像话&lt;/p&gt;
&lt;p&gt;竟到了贩卖温柔的地步&lt;/p&gt;
&lt;p&gt;风尘仆仆的只想找一个家&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;很喜欢宫崎骏先生说过的两句话，&lt;/p&gt;
&lt;p&gt;一句是：&lt;/p&gt;
&lt;p&gt;“你简单世界就是童话，你复杂世界就是迷宫。”&lt;/p&gt;
&lt;p&gt;生而为人，肯定要与事故有所碰撞，只愿你一如既往简单看待这个世界，在躺过世俗浑水后，仍能不沾染那一身的事故。&lt;/p&gt;
&lt;p&gt;另一句是：&lt;/p&gt;
&lt;p&gt;“一举一动，都是承诺，会被另一个人看在眼里，记在心上的。”&lt;/p&gt;
&lt;p&gt;正如老话言‘行胜于言’，有时候不去打扰，只是觉得自己多余，愿你被阅读，不被辜负。&lt;/p&gt;
&lt;p&gt;我建这个电台的目的可能就是因为我喜欢恋旧，&lt;/p&gt;
&lt;p&gt;我渴望将我曾经的那些美好给记录下来。&lt;/p&gt;
&lt;p&gt;`&lt;/p&gt;
&lt;p&gt;因为，&lt;/p&gt;
&lt;p&gt;我怕有一天，&lt;/p&gt;
&lt;p&gt;所有人都杳无音信&lt;/p&gt;
&lt;p&gt;从我的世界蒸发。&lt;/p&gt;
&lt;p&gt;我也渴望被人收藏好，妥善保管，细心保存，免我惊，免我苦，免我四下流离，免我无枝可依，那人，我知，是你，也不是你。
也渴望找一个温暖如太阳的人，晒掉所有不值一提的悲伤。
/&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;我们生来孤独，又何苦闯进人群自取其辱，终归还不是都要沦为尘埃。&lt;/p&gt;
&lt;p&gt;真正治愈自己的，只有自己&lt;/p&gt;
&lt;p&gt;不去抱怨，尽量担待&lt;/p&gt;
&lt;p&gt;不怕孤单，努力沉淀&lt;/p&gt;
&lt;p&gt;随着日子不断往前走。&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;不奢望自己变得多romantic&lt;/p&gt;
&lt;p&gt;但渴望生活中多一些serendipity&lt;/p&gt;
&lt;p&gt;少一些smitten&lt;/p&gt;
&lt;p&gt;更期望flipped.&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;落日归山海，山海藏深意.&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;</content:encoded><dc:creator>Barry Yang</dc:creator></item><item><title>宝藏句子收藏区</title><link>https://barry.ee/writing/gift/</link><guid isPermaLink="true">https://barry.ee/writing/gift/</guid><pubDate>Tue, 10 Mar 2020 00:34:14 GMT</pubDate><content:encoded>&lt;h2&gt;引入&lt;/h2&gt;
&lt;p&gt;突然有一个想法想把看到的宝藏句子都收集起来，让大家一起🤩&lt;/p&gt;
&lt;h2&gt;英文&lt;/h2&gt;
&lt;p&gt;If you reveal your secrets to the wind you should not blame the wind revealing them to the trees. 要是你把你的秘密告诉了风，那就别怪风把秘密带给树。——纪伯伦&lt;/p&gt;
&lt;p&gt;I love three things in the world: the sun, the moon and you. The sun for day, the moon for night and you forever. 吾独爱世间三物: 昼之日，夜之月，汝之永恒。——《暮光之城》&lt;/p&gt;
&lt;p&gt;Had i not see the sun, i could have borne the shade. 我本可以忍受黑暗，如果我不曾见过太阳。——艾米丽 · 狄金森&lt;/p&gt;
&lt;p&gt;In me the tiger sniffs the rose. 心有猛虎，细嗅蔷薇。——西格里夫 · 萨松&lt;/p&gt;
&lt;p&gt;We laughed and kept saying &amp;quot;see u soon&amp;quot;,but inside we both knew we&amp;#39;d never see each other again. 我们笑着说再见，却深知再见遥遥无期。——《海上钢琴师》&lt;/p&gt;
&lt;p&gt;We are all in the gutter, but some of us are looking at the stars. 我们都生活在阴沟里，但仍有人仰望星空。——奥斯卡 · 王尔德&lt;/p&gt;
&lt;p&gt;It does not do well to depend on dreams and forget to live,remember that. 记住不要依赖梦想而忘记生活。——J.K 罗琳&lt;/p&gt;
&lt;p&gt;Sometimes it&amp;#39;s hard to accept the truth because the lies sound so much better. 真相有时之所以难以被接受，是因为谎言听起来美好多了。——《达 · 芬奇》&lt;/p&gt;
&lt;p&gt;Life is like a box of chocolates, you never know what you are going to get. 生活就像一盒巧克力，你永远不知道下一个是什么。——《阿甘正传》&lt;/p&gt;
&lt;p&gt;The longest day has an end. 最难过的日子也有尽头。——贺韦尔&lt;/p&gt;
&lt;p&gt;To be or not to be, that is the question. 活着还是死去，这是一个问题。——《哈姆雷特》&lt;/p&gt;
&lt;p&gt;I can&amp;#39;t control their fear, only my own. 我不能掌控他人的恐惧，只能掌控自己的恐惧。——《美国队长: 内战》&lt;/p&gt;
&lt;p&gt;Sometimes accompanied ,sometimes alone, stay awesome all the time. 聚散终有时，潇洒走一回。——《纽约纽约》&lt;/p&gt;
&lt;p&gt;There are no easy answers , there&amp;#39;s only living through the questions. 生活从来没有容易的答案，只有去克服重重问题。——伊丽莎白 · 乔治&lt;/p&gt;
&lt;h2&gt;中文&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;像每一滴酒回不了最初的葡萄，我回不到年少。&lt;/li&gt;
&lt;li&gt;让懂的人懂，让不懂的人不懂。让世界是世界，我甘心是我的茧。&lt;/li&gt;
&lt;li&gt;生命如浩瀚汪洋，人潮起落之中，我们难免会撞礁搁浅，会掉进诡谲的漩涡，会困在迷洞，会滚了一身刺人的沙粒，苦不堪言……无论如何，告诉自己：也许我就是带珠的蚌。&lt;/li&gt;
&lt;li&gt;叔本华不得不低叹：“人生实如钟摆，在痛苦与倦怠之间摆动。”谁逃得过时间之蹄而不苍老?谁躲得过现实的棰而不折骨?没有。没有。&lt;/li&gt;
&lt;li&gt;生活是一个刽子手，刀刃上没有明天。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;精选短句&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;枕边书，怀中猫，意中人。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在等雪花、圣诞树、新年烟火、和更好的你。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;喜欢是别的也行 爱是死磕。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可以回头看 但不要回头走 因为 逆行是全责。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;解不开心结就把它变成蝴蝶结。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我想做一个能在你的葬礼上描述你一声的人.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;真爱出现的第一征兆，在男孩身上就是胆怯。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;九万七，世间欢喜十万，你独占九万七，剩余弱水三千，我皆不动心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;所以万家灯火，有没有灯为你而开？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;红尘万物，你即是救赎。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我好喜欢那句“秀外慧中 好是喜欢”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;多年以前，我的矫情浪费了我的天时地利，直到今天已经统统过期。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在爱情上，我只愿你永远不会有失去第一次爱过的人的那种感觉。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;浅尝辄止,过犹不及。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;理智的状态是有节制的热爱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我很擅长约会，但不擅长维持一段长久的关系。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;世间万物皆苦，你明目张胆的偏爱就是救赎。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;白天有很多好东西，但是那里没有你。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;世界灿烂盛大，欢迎回家。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;暴躁且甜，温柔且善。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;岁岁常欢愉,万事皆胜意。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果夜里不能吃东西，那冰箱为什么会有灯呢？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“一块玻璃准备跳楼你猜他会说什么”&lt;/p&gt;
&lt;p&gt;“什么呢”&lt;/p&gt;
&lt;p&gt;“晚安 ，我碎咯”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我往宇宙撒了把盐，&lt;/p&gt;
&lt;p&gt;如果三点前还睡不着&lt;/p&gt;
&lt;p&gt;今晚就吃盐焗小星球～～&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;月亮今晚不营业，所以我来说晚安&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你知道为什么月亮两头尖尖中间弯嘛？&lt;/p&gt;
&lt;p&gt;因为锋芒对外 温柔对你。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我能抵抗一切，除了诱惑。 王尔德&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你当温柔，却又力量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;想念，像十除以三。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;从来如此，便对么？ ------------鲁迅狂人日记&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;撒娇是察觉到了被偏爱的可能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;请保持网络畅通 及时接受我的想念&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;温柔仅供参考，一切以生气时间为准。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对你收起所有的怦然心动，然后保持距离。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;只可私藏，不准共享。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;世界欠你的温柔，我给。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;不辜负自己，不将就生活。你的存在，配的上世间所有的最好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在我面前你可以不勇敢。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果我写不出温柔漂亮的句子，你能不能直接看一下我温柔的心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;遇见了温柔的人，所以想温柔待人。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;原来躲起来的星星也在努力发光啊。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你是我明目张胆的偏袒众所周知的私心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我一扑向你，就感到无限温柔啊。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;未曾谋面的也终将会相遇。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;温柔的绕道&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;小姐是我漫漫余生里义无反顾的梦想。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你是我无限努力的理由&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;贩卖日落&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;陪伴本身就是这个世界上最了不起的安慰方式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我会在每个有意义的时刻，远隔山海与你共存。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No one and you.无人及你&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我是此间少年郎，你是天上明月光。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我与我周旋久，宁作我!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一切尽意，百事从欢。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;心之何如，有似万丈迷津，横亘千里，其中并无舟子可以渡人，除了自渡，他人爱莫能助。——三毛&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一约既定，万山无阻。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一如既往，万事胜意。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;山高路远，一定再见。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;忠于自己，热爱生活。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;寒来暑往，秋收冬藏。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我有我自己的救赎，一往无前独自发光。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一个拥抱可以释放200%的压力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;满天星光沿途散播，长路尽头总有灯火。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;龙应该藏在云里，你应该藏在心里。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;大地丰盈，人间并不寂寞。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;万物更新，旧疾当愈。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;苦尽甘来的那一天，山河星月，都做贺礼。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;不要因为看到别人发光，就承认自己的暗淡。别灰心，每个人都有属于自己的闪光时刻。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;直到现在，我依然没有长大。我控制不了我的情绪。依然爱说反话，还是遇见挫折，就想逃走的小孩。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你是调色板上最温柔的色调。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你很可爱,不是cute,是couldbeloved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你返航的轨迹，是所有等待的意义。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;因为太想保护你，忘了你也特别勇敢。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;这个世界上全是别人，只有一个自己，所以找到自己才是最重要的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;分享到朋友圈的歌，是我递给你的另一个耳机。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有时候生活给你苦难，其实是在铺垫浪漫。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你所有的努力，都有迹可循。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;及时清醒，也要事事甘心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;不要被结果操控，原本因为梦想而灿烂的心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;沉默不是情绪，只是觉得说出来没意义。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开始期待冬天了，手上的热奶茶，加上沿街吹得冻人的风，还有结伴玩耍的快乐和厚衣服下裹藏着的热爱生活的心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;谁能凭爱意，将富士山私有。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;我从此不敢看观音。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;落俗不可避免，浪漫至死不渝。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一个能够升起月亮的身体，必然驮住了无数次的日落。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;女孩子，有一个特点，需要浪漫，记得满足。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;陆续更新中~&lt;/p&gt;
</content:encoded><dc:creator>Barry Yang</dc:creator></item></channel></rss>