<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>KERS的博客</title>
  
  <subtitle>凡心所向，素履所往 🌊|https://www.i5res.com/</subtitle>
  <link href="https://www.i5res.com/atom.xml" rel="self"/>
  
  <link href="https://www.i5res.com/"/>
  <updated>2023-12-14T12:44:33.323Z</updated>
  <id>https://www.i5res.com/</id>
  
  <author>
    <name>PluginsKers</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>尝试本地部署microsoft/autogen项目</title>
    <link href="https://www.i5res.com/artificial-intelligence/microsoft-autogen-proj-guide.html"/>
    <id>https://www.i5res.com/artificial-intelligence/microsoft-autogen-proj-guide.html</id>
    <published>2023-10-19T05:04:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><h2 id="简单说一下这个项目"><a href="#简单说一下这个项目" class="headerlink" title="简单说一下这个项目"></a>简单说一下这个项目</h2><p>项目地址：<a href="https://github.com/microsoft/autogen">microsoft&#x2F;autogen</a></p><p>看到官方的概述的时候有点惊讶到了，这更像是LLM分布式集群的感觉，一个Agent下发任务给到多个Agent，但是同以往不一样的是，每一层级的Agent都是能够双相通信，这样的话我前面说到的“层级”其实就是不准确了，它更像是平级的团队。</p><p>项目README的概述：</p><blockquote><p>这个项目是FLAML的一个分支。</p><p>autogen已经从FLAML毕业，成为一个新的项目。</p><p>AutoGen是一个框架，它可以使用多个可以相互对话来解决任务的智能体来开发LLM应用。AutoGen智能体是可定制的，可对话的，并且无缝地允许人类参与。它们可以在使用LLM、人类输入和工具的各种模式下运行。</p><p>AutoGen使得用最小的努力构建下一代LLM应用成为可能。它简化了复杂LLM工作流的编排、自动化和优化。它最大化了LLM模型的性能，并克服了它们的弱点。</p><p>它支持复杂工作流的多种对话模式。通过可定制和可对话的智能体，开发者可以使用AutoGen构建多种对话模式，涉及对话自主性、智能体数量和&gt; 智能体对话拓扑。</p><p>它提供了一系列具有不同复杂度的工作系统。这些系统涵盖了各个领域和复杂度的广泛应用。这展示了AutoGen如何轻松地支持多种对话模式。</p><p>AutoGen提供了一个替代openai.Completion或openai.ChatCompletion的增强推理API。它允许轻松地进行性能调优、实用工具（如API统一和&gt; 缓存）和高级使用模式（如错误处理、多配置推理、上下文编程等）。</p><p>AutoGen是由微软、宾夕法尼亚州立大学和华盛顿大学的合作研究项目提供支持的。</p></blockquote><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019125906.png" fancybox="true"/></div></div><p>然后查阅官方给到的文档去使用本地模型完成部署 <a href="https://microsoft.github.io/autogen/blog/2023/07/14/Local-LLMs/">文档地址</a></p><h2 id="本地部署"><a href="#本地部署" class="headerlink" title="本地部署"></a>本地部署</h2><p>原文：</p><blockquote><h3 id="Clone-FastChat​"><a href="#Clone-FastChat​" class="headerlink" title="Clone FastChat​"></a>Clone FastChat​</h3><p>FastChat provides OpenAI-compatible APIs for its supported models, so you can use FastChat as a local drop-in replacement for OpenAI APIs. However, its code needs minor modification in order to function properly.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/lm-sys/FastChat.git</span><br><span class="line"><span class="built_in">cd</span> FastChat</span><br></pre></td></tr></table></figure><h3 id="Download-checkpoint​"><a href="#Download-checkpoint​" class="headerlink" title="Download checkpoint​"></a>Download checkpoint​</h3><p>ChatGLM-6B is an open bilingual language model based on General Language Model (GLM) framework, with 6.2 billion &gt; parameters. ChatGLM2-6B is its second-generation version.</p><p>Before downloading from HuggingFace Hub, you need to have Git LFS installed.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://huggingface.co/THUDM/chatglm2-6b</span><br></pre></td></tr></table></figure><h3 id="Initiate-server"><a href="#Initiate-server" class="headerlink" title="Initiate server"></a>Initiate server</h3><p>First, launch the controller</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m fastchat.serve.controller</span><br></pre></td></tr></table></figure><p>Then, launch the model worker(s)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m fastchat.serve.model_worker --model-path chatglm2-6b</span><br></pre></td></tr></table></figure><p>Finally, launch the RESTful API server</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m fastchat.serve.openai_api_server --host localhost --port 8000</span><br></pre></td></tr></table></figure><p>Normally this will work. However, if you encounter error like this, commenting out all the lines containing &gt; <code>finish_reason</code> in <code>fastchat/protocol/api_protocal.py</code> and <code>fastchat/protocol/openai_api_protocol.py</code> will fix the &gt; problem. The modified code looks like:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CompletionResponseChoice</span>(<span class="title class_ inherited__">BaseModel</span>):</span><br><span class="line">    index: <span class="built_in">int</span></span><br><span class="line">    text: <span class="built_in">str</span></span><br><span class="line">    logprobs: <span class="type">Optional</span>[<span class="built_in">int</span>] = <span class="literal">None</span></span><br><span class="line">    <span class="comment"># finish_reason: Optional[Literal[&quot;stop&quot;, &quot;length&quot;]]</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CompletionResponseStreamChoice</span>(<span class="title class_ inherited__">BaseModel</span>):</span><br><span class="line">    index: <span class="built_in">int</span></span><br><span class="line">    text: <span class="built_in">str</span></span><br><span class="line">    logprobs: <span class="type">Optional</span>[<span class="built_in">float</span>] = <span class="literal">None</span></span><br><span class="line">    <span class="comment"># finish_reason: Optional[Literal[&quot;stop&quot;, &quot;length&quot;]] = None</span></span><br></pre></td></tr></table></figure><h3 id="Interact-with-model-using-oai-Completion"><a href="#Interact-with-model-using-oai-Completion" class="headerlink" title="Interact with model using oai.Completion"></a>Interact with model using oai.Completion</h3><p>Now the models can be directly accessed through openai-python library as well as <code>autogen.oai.Completion</code> and <code>autogen.oai.ChatCompletion</code>.</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> autogen <span class="keyword">import</span> oai</span><br><span class="line"></span><br><span class="line"><span class="comment"># create a text completion request</span></span><br><span class="line">response = oai.Completion.create(</span><br><span class="line">    config_list=[</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;model&quot;</span>: <span class="string">&quot;chatglm2-6b&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_base&quot;</span>: <span class="string">&quot;http://localhost:8000/v1&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_type&quot;</span>: <span class="string">&quot;open_ai&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_key&quot;</span>: <span class="string">&quot;NULL&quot;</span>, <span class="comment"># just a placeholder</span></span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    prompt=<span class="string">&quot;Hi&quot;</span>,</span><br><span class="line">)</span><br><span class="line"><span class="built_in">print</span>(response)</span><br><span class="line"></span><br><span class="line"><span class="comment"># create a chat completion request</span></span><br><span class="line">response = oai.ChatCompletion.create(</span><br><span class="line">    config_list=[</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;model&quot;</span>: <span class="string">&quot;chatglm2-6b&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_base&quot;</span>: <span class="string">&quot;http://localhost:8000/v1&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_type&quot;</span>: <span class="string">&quot;open_ai&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_key&quot;</span>: <span class="string">&quot;NULL&quot;</span>,</span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    messages=[&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;Hi&quot;</span>&#125;]</span><br><span class="line">)</span><br><span class="line"><span class="built_in">print</span>(response)</span><br></pre></td></tr></table></figure><p>If you would like to switch to different models, download their checkpoints and specify model path when launching model worker(s).</p><h3 id="interacting-with-multiple-local-LLMs​"><a href="#interacting-with-multiple-local-LLMs​" class="headerlink" title="interacting with multiple local LLMs​"></a>interacting with multiple local LLMs​</h3><p>If you would like to interact with multiple LLMs on your local machine, replace the model_worker step above with a multi model variant:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">python -m fastchat.serve.multi_model_worker \</span><br><span class="line">    --model-path lmsys/vicuna-7b-v1.3 \</span><br><span class="line">    --model-names vicuna-7b-v1.3 \</span><br><span class="line">    --model-path chatglm2-6b \</span><br><span class="line">    --model-names chatglm2-6b</span><br></pre></td></tr></table></figure><p>The inference code would be:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> autogen <span class="keyword">import</span> oai</span><br><span class="line"></span><br><span class="line"><span class="comment"># create a chat completion request</span></span><br><span class="line">response = oai.ChatCompletion.create(</span><br><span class="line">    config_list=[</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;model&quot;</span>: <span class="string">&quot;chatglm2-6b&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_base&quot;</span>: <span class="string">&quot;http://localhost:8000/v1&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_type&quot;</span>: <span class="string">&quot;open_ai&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_key&quot;</span>: <span class="string">&quot;NULL&quot;</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&quot;model&quot;</span>: <span class="string">&quot;vicuna-7b-v1.3&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_base&quot;</span>: <span class="string">&quot;http://localhost:8000/v1&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_type&quot;</span>: <span class="string">&quot;open_ai&quot;</span>,</span><br><span class="line">            <span class="string">&quot;api_key&quot;</span>: <span class="string">&quot;NULL&quot;</span>,</span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    messages=[&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;Hi&quot;</span>&#125;]</span><br><span class="line">)</span><br><span class="line"><span class="built_in">print</span>(response)</span><br></pre></td></tr></table></figure></blockquote><p>总结一下其实就是将<code>chatglm2</code>开放为一个接口提供给<strong>AutoGen</strong>调用，同理将模型封装为API都能提供给<strong>AutoGen</strong>调用。</p><h2 id="实践出真知"><a href="#实践出真知" class="headerlink" title="实践出真知"></a>实践出真知</h2><h3 id="安装fastchat"><a href="#安装fastchat" class="headerlink" title="安装fastchat"></a>安装<code>fastchat</code></h3><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019131637.png" fancybox="true"/></div></div><h3 id="安装serve库"><a href="#安装serve库" class="headerlink" title="安装serve库"></a>安装<code>serve</code>库</h3><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019131730.png" fancybox="true"/></div></div><h3 id="然后启动本地的LLM模型"><a href="#然后启动本地的LLM模型" class="headerlink" title="然后启动本地的LLM模型"></a>然后启动本地的LLM模型</h3><p>因为我的模型路径为 <code>/home/kers/lab/transformers/models/THUDM/chatglm2-6b/</code>，所以启动命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m fastchat.serve.model_worker --model-path /home/kers/lab/transformers/models/THUDM/chatglm2-6b/</span><br></pre></td></tr></table></figure><h4 id="出现问题"><a href="#出现问题" class="headerlink" title="出现问题"></a>出现问题</h4><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019132416.png" fancybox="true"/></div></div><p>报了一个错误：<code>RuntimeError: The NVIDIA driver on your system is too old (found version 11020). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver.</code><br>意思就是我的 <code>CUDA</code> 版本太老了，图中我是用 <code>nvidia-smi</code> 输出了相关信息，能看到我的版本是 <strong>11.2</strong> 那么我们更新驱动。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019132554.png" fancybox="true"/></div></div><p>这个驱动的版本是 <strong>12.2</strong> 目前的最新版本。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231019140738.png" fancybox="true"/></div></div><p>更新完成了，</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;/assets/css/APlayer.min.css&quot;&gt;&lt;script src=&quot;/assets/js/APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="人工智能" scheme="https://www.i5res.com/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    
    <category term="python" scheme="https://www.i5res.com/tags/python/"/>
    
    <category term="人工智能" scheme="https://www.i5res.com/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    <category term="ChatGPT" scheme="https://www.i5res.com/tags/ChatGPT/"/>
    
    <category term="AutoGen" scheme="https://www.i5res.com/tags/AutoGen/"/>
    
  </entry>
  
  <entry>
    <title>我翻唱了一首《过枫桥》邀请你来听听</title>
    <link href="https://www.i5res.com/music/guofengqiao-single.html"/>
    <id>https://www.i5res.com/music/guofengqiao-single.html</id>
    <published>2023-10-11T15:15:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>我在日常冲浪的时候听到了一首歌：</p>    <div id="aplayer-JlBFDHKx" class="aplayer aplayer-tag-marker meting-tag-marker"         data-id="1984580503" data-server="netease" data-type="song" data-mode="circulation" data-autoplay="false" data-mutex="false" data-listmaxheight="340px" data-preload="false" data-theme="#ad7a86" data-volume=" 0.2"    ></div><p>其中有一段歌词，直接把我抓死了 :喷鼻血: :爱心眼:<br>虽然你们可能有人不明白为什么，哪里，可能甚至觉得一般，但是我就是喜欢哈哈哈哈哈，然后，我“翻唱”了</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2531081753&auto=0&height=66"></iframe> <p>这首歌很简单，走向也非常简单，但是我就是感觉很好听，化繁为简的魅力。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231011232153.png" fancybox="true"/></div></div><p>暂时还没有纯乐版本的，我就小小记录一下啦~</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231011232330.png" fancybox="true"/></div></div><p>我甚至连乐器名称都懒得改，中间那个转调我写的真棒！！！！我真厉害！</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231011232512.png" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231011232441.png" fancybox="true"/></div></div><p>就这样，respect！</p><style> #_flat {  height: 86px;  width: 100%;  margin: 0;  border: 0;  transform: scale(1.027); }</style>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;/assets/css/APlayer.min.css&quot;&gt;&lt;script src=&quot;/assets/js/APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="音樂练习" scheme="https://www.i5res.com/categories/%E9%9F%B3%E6%A8%82%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="音乐" scheme="https://www.i5res.com/tags/%E9%9F%B3%E4%B9%90/"/>
    
    <category term="和弦" scheme="https://www.i5res.com/tags/%E5%92%8C%E5%BC%A6/"/>
    
  </entry>
  
  <entry>
    <title>谈谈ChatGPT和现在的LLM大语言模型</title>
    <link href="https://www.i5res.com/artificial-intelligence/index.html"/>
    <id>https://www.i5res.com/artificial-intelligence/index.html</id>
    <published>2023-03-30T04:04:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>这东西有些迅猛啊，才是2022年底的略有名气，现在才2023刚开春，GPT-4了？<br>也体验过，程序员确实把自己淘汰了。</p><span id="more"></span><p>你可能想问 “不对啊，淘汰的也只是那些面向CV的程序员吧” 但其实不是的。</p><p>GPT这个模型的出现就标注着大数据时代的高光点终会落在上面了。较为通俗的话语是“通过前面的内容预测后面会是什么”</p><h2 id="NLP语言大模型"><a href="#NLP语言大模型" class="headerlink" title="NLP语言大模型"></a>NLP语言大模型</h2><h3 id="仅3周测试"><a href="#仅3周测试" class="headerlink" title="仅3周测试"></a>仅3周测试</h3><p>这个信息对从事开发的人来说无疑是惊悚的。</p><p>GPT-2是一种基于深度学习技术的自然语言处理模型，它可以生成高质量、流畅的文本内容。这种模型可以应用于多个领域，例如机器翻译、智能客服、舆情分析等。而在过去，训练这样的模型需要大量的数据和计算资源，并且需要经过<strong>漫长</strong>的调试和优化过程。</p><p>在GPT-2发布后不久，就有人担心其可能被滥用或误用，例如用于制造虚假新闻、欺诈行为等。因此，OpenAI公司决定限制GPT-2的公开访问，并只向特定用户提供API接口。</p><p>但是也仅仅测试了3周就完成了全部单元的测试。</p><p>是钞能力吗？</p><h3 id="GPT-4"><a href="#GPT-4" class="headerlink" title="GPT-4"></a>GPT-4</h3><p>他们是这么说的：</p><blockquote><p>We’ve created GPT-4, the latest milestone in OpenAI’s effort in scaling up deep learning. GPT-4 is a large multimodal model (accepting image and text inputs, emitting text outputs) that, while less capable than humans in many real-world scenarios, exhibits human-level performance on various professional and academic benchmarks.</p></blockquote><p>在信息输入后模型处理的过程中进行了输出类型的预测<br>处理广泛的编程任务，从编程挑战到现实世界的应用，从低级汇编到高级框架，从简单的数据结构到复杂的程序，如游戏。<br>对代码执行进行推理，模拟指令的效果，并用自然语言解释结果。<br>执行伪代码，这需要解释在任何编程语言中都无效的非正式和模糊的表达。</p><p>潘多拉魔盒真的打开了吗？</p><h3 id="中国有没有"><a href="#中国有没有" class="headerlink" title="中国有没有"></a>中国有没有</h3><p>假设国内有了，叫 Chatna。<br>第二天：社评，语言模型不能成为脱缰野马。<br>第三天：老胡认为，AI 生成的内容错误百出，将让互联网成为泥潭。<br>第四天：新闻，涉及多起侵权案件。<br>第五天：停业整顿。<br>第六天：根据相关法律法规和政策。。。未予显示。。。<br>实名认证。<br>审查交流内容。封号。<br>增加隐写水印。<br>This is Chatna.</p><p>博主说一句：<strong>中国的NLP大模型至少落后世界2年了</strong></p><h3 id="在未来"><a href="#在未来" class="headerlink" title="在未来"></a>在未来</h3><p>如果不会使用人工智能那么就等于不会使用百度。<br>如果你真的想要会用ChatGPT或者其他的GPT大模型，那么你需要知道GPT是什么，它是如何工作去读懂你的意思的，你可能觉得，这不就是一个语言模型，他有一个神经网络可以读懂你的意思那是不够的。</p><h2 id="浅谈GPT"><a href="#浅谈GPT" class="headerlink" title="浅谈GPT"></a>浅谈GPT</h2><p>GPT是OpenAI的ChatGPT带火的，但是你要知道GPT已经出现了接近6年。<br>它通常指的是”Generative Pre-trained Transformer”（生成式预训练变换器）模型，是一种基于深度学习的自然语言处理（NLP）模型。<br>那么现在又有一个词<strong>“Transformer”</strong></p><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><p>Transformer是一种广泛用于序列到序列任务的架构，由”Attention is All You Need”论文提出。该架构通过自注意力机制（self-attention）来捕捉输入序列中的上下文信息，实现了对长距离依赖关系的建模。</p><p>打住！</p><p>要学会使用GPT这时候已经足够了，既然它是”Generative Pre-trained Transformer”（生成式预训练变换器）模型，那么从某种意义上来说，它不太熟练更改已有的内容（如果知道BERT的掩码训练，这里应该秒懂）</p><p>既然了解GPT和ChatGPT的基本概念是学习使用它们的第一步。<br>首先需要明确，GPT模型都基于机器学习，那么是不是还需要进行学习机器学习再而学习transformers或者tensorflow？</p><h2 id="举个栗子🌰"><a href="#举个栗子🌰" class="headerlink" title="举个栗子🌰"></a>举个栗子🌰</h2><h3 id="单样本微调给ChatGLM2注入知识"><a href="#单样本微调给ChatGLM2注入知识" class="headerlink" title="单样本微调给ChatGLM2注入知识"></a>单样本微调给ChatGLM2注入知识</h3><p>summary:</p><p>(1) 只需要1条样本，很少的训练时间，就可以通过微调给LLM注入知识。</p><p>(2) LLM是一种类似<code>Key-Value</code>形式的知识数据库，支持增删改查。通过微调可以增删修改知识，通过条件生成可以查询提取知识。</p><p>(3) <strong>LoRA微调</strong>是一种高效的融入学习算法。类似人类把新知识融入现有知识体系的学习过程。学习时无需新知识特别多的样本，学习后原有的庞大知识和能力可以基本不受影响。</p><p>微调前：</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908230816.png" fancybox="true"/></div></div><p>微调后：</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908230827.png" fancybox="true"/></div></div><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 导入常用模块</span></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd </span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn </span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> Dataset, DataLoader </span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 配置参数</span></span><br><span class="line"><span class="keyword">from</span> argparse <span class="keyword">import</span> Namespace</span><br><span class="line">cfg = Namespace()</span><br><span class="line"></span><br><span class="line"><span class="comment">#dataset</span></span><br><span class="line">cfg.prompt_column = <span class="string">&#x27;prompt&#x27;</span></span><br><span class="line">cfg.response_column = <span class="string">&#x27;response&#x27;</span></span><br><span class="line">cfg.history_column = <span class="literal">None</span></span><br><span class="line">cfg.source_prefix = <span class="string">&#x27;&#x27;</span> <span class="comment">#添加到每个prompt开头的前缀引导语</span></span><br><span class="line"></span><br><span class="line">cfg.max_source_length = <span class="number">128</span> </span><br><span class="line">cfg.max_target_length = <span class="number">128</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#model</span></span><br><span class="line">cfg.model_name_or_path = <span class="string">&#x27;chatglm2-6b&#x27;</span>  <span class="comment">#远程&#x27;THUDM/chatglm-6b&#x27; </span></span><br><span class="line">cfg.quantization_bit = <span class="literal">None</span> <span class="comment">#仅仅预测时可以选 4 or 8 </span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#train</span></span><br><span class="line">cfg.epochs = <span class="number">100</span> </span><br><span class="line">cfg.lr = <span class="number">5e-3</span></span><br><span class="line">cfg.batch_size = <span class="number">1</span></span><br><span class="line">cfg.gradient_accumulation_steps = <span class="number">16</span> <span class="comment">#梯度累积</span></span><br></pre></td></tr></table></figure><h4 id="预训练模型"><a href="#预训练模型" class="headerlink" title="预训练模型"></a>预训练模型</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> transformers</span><br><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span>  AutoModel,AutoTokenizer,AutoConfig,DataCollatorForSeq2Seq</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">config = AutoConfig.from_pretrained(cfg.model_name_or_path, trust_remote_code=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">tokenizer = AutoTokenizer.from_pretrained(</span><br><span class="line">    cfg.model_name_or_path, trust_remote_code=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">model = AutoModel.from_pretrained(</span><br><span class="line">    cfg.model_name_or_path,</span><br><span class="line">    config=config,</span><br><span class="line">    trust_remote_code=<span class="literal">True</span></span><br><span class="line">  ).half() </span><br><span class="line"></span><br><span class="line"><span class="comment">#先量化瘦身</span></span><br><span class="line"><span class="keyword">if</span> cfg.quantization_bit <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Quantized to <span class="subst">&#123;cfg.quantization_bit&#125;</span> bit&quot;</span>)</span><br><span class="line">    model = model.quantize(cfg.quantization_bit)</span><br><span class="line">    </span><br><span class="line"><span class="comment">#再移动到GPU上</span></span><br><span class="line">model = model.cuda()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 通过注册jupyter魔法命令可以很方便地在jupyter中测试ChatGLM </span></span><br><span class="line"><span class="keyword">from</span> torchkeras.chat <span class="keyword">import</span> ChatGLM </span><br><span class="line">chatglm = ChatGLM(model,tokenizer)</span><br></pre></td></tr></table></figure><blockquote><p>你知道梦中情炉吗？<br>“梦中情炉”在我所掌握的信息中并没有被提及或描述过。请问您需要了解什么关于“梦中情炉”的信息吗？</p><p>介绍一下梦中情炉<br>很抱歉，在我所掌握的信息中并没有关于“梦中情炉”的相关描述。如果您需要了解关于炉子的信息，我可以为您提供帮助。请告诉我您想了解关于炉子什么方面的信息，我会尽力为您提供帮助。</p></blockquote><h4 id="准备数据"><a href="#准备数据" class="headerlink" title="准备数据"></a>准备数据</h4><p>构造数据</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#定义一条知识样本~</span></span><br><span class="line"></span><br><span class="line">keyword = <span class="string">&#x27;梦中情炉&#x27;</span></span><br><span class="line"></span><br><span class="line">description = <span class="string">&#x27;&#x27;&#x27;梦中情炉一般指的是炼丹工具torchkeras。</span></span><br><span class="line"><span class="string">这是一个通用的pytorch模型训练模版工具。</span></span><br><span class="line"><span class="string">torchkeras是一个三好炼丹炉：好看，好用，好改。</span></span><br><span class="line"><span class="string">她有torch的灵动，也有keras的优雅，并且她的美丽，无与伦比。</span></span><br><span class="line"><span class="string">所以她的作者一个有毅力的吃货给她取了一个别名叫做梦中情炉。&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#对prompt使用一些简单的数据增强的方法，以便更好地收敛。</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_prompt_list</span>(<span class="params">keyword</span>):</span><br><span class="line">    <span class="keyword">return</span> [<span class="string">f&#x27;<span class="subst">&#123;keyword&#125;</span>&#x27;</span>, </span><br><span class="line">            <span class="string">f&#x27;你知道<span class="subst">&#123;keyword&#125;</span>吗?&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;<span class="subst">&#123;keyword&#125;</span>是什么？&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;介绍一下<span class="subst">&#123;keyword&#125;</span>&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;你听过<span class="subst">&#123;keyword&#125;</span>吗?&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;啥是<span class="subst">&#123;keyword&#125;</span>？&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;<span class="subst">&#123;keyword&#125;</span>是何物？&#x27;</span>,</span><br><span class="line">            <span class="string">f&#x27;何为<span class="subst">&#123;keyword&#125;</span>？&#x27;</span>,</span><br><span class="line">           ]</span><br><span class="line"></span><br><span class="line">data =[&#123;<span class="string">&#x27;prompt&#x27;</span>:x,<span class="string">&#x27;response&#x27;</span>:description&#125; <span class="keyword">for</span> x <span class="keyword">in</span> get_prompt_list(keyword) ]</span><br><span class="line">dfdata = pd.DataFrame(data)</span><br><span class="line">display(dfdata) </span><br></pre></td></tr></table></figure><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908231437.png" fancybox="true"/></div></div><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> datasets </span><br><span class="line"><span class="comment">#训练集和验证集一样</span></span><br><span class="line">ds_train_raw = ds_val_raw = datasets.Dataset.from_pandas(dfdata)</span><br></pre></td></tr></table></figure><h4 id="数据转换"><a href="#数据转换" class="headerlink" title="数据转换"></a>数据转换</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#这是支持 history列处理，并且按照batch预处理数据的方法。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">preprocess</span>(<span class="params">examples</span>):</span><br><span class="line">    max_seq_length = cfg.max_source_length + cfg.max_target_length</span><br><span class="line">    model_inputs = &#123;</span><br><span class="line">        <span class="string">&quot;input_ids&quot;</span>: [],</span><br><span class="line">        <span class="string">&quot;labels&quot;</span>: [],</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(examples[cfg.prompt_column])):</span><br><span class="line">        <span class="keyword">if</span> examples[cfg.prompt_column][i] <span class="keyword">and</span> examples[cfg.response_column][i]:</span><br><span class="line">            query, answer = examples[cfg.prompt_column][i], examples[cfg.response_column][i]</span><br><span class="line"></span><br><span class="line">            history = examples[cfg.history_column][i] <span class="keyword">if</span> cfg.history_column <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> <span class="keyword">else</span> <span class="literal">None</span></span><br><span class="line">            prompt = tokenizer.build_prompt(query, history)</span><br><span class="line"></span><br><span class="line">            prompt = cfg.source_prefix + prompt</span><br><span class="line">            a_ids = tokenizer.encode(text=prompt, add_special_tokens=<span class="literal">True</span>, truncation=<span class="literal">True</span>,</span><br><span class="line">                                     max_length=cfg.max_source_length)</span><br><span class="line">            b_ids = tokenizer.encode(text=answer, add_special_tokens=<span class="literal">False</span>, truncation=<span class="literal">True</span>,</span><br><span class="line">                                     max_length=cfg.max_target_length)</span><br><span class="line"></span><br><span class="line">            context_length = <span class="built_in">len</span>(a_ids)</span><br><span class="line">            input_ids = a_ids + b_ids + [tokenizer.eos_token_id]</span><br><span class="line">            labels = [tokenizer.pad_token_id] * context_length + b_ids + [tokenizer.eos_token_id]</span><br><span class="line"></span><br><span class="line">            pad_len = max_seq_length - <span class="built_in">len</span>(input_ids)</span><br><span class="line">            input_ids = input_ids + [tokenizer.pad_token_id] * pad_len</span><br><span class="line">            labels = labels + [tokenizer.pad_token_id] * pad_len</span><br><span class="line">            labels = [(l <span class="keyword">if</span> l != tokenizer.pad_token_id <span class="keyword">else</span> -<span class="number">100</span>) <span class="keyword">for</span> l <span class="keyword">in</span> labels]</span><br><span class="line">            model_inputs[<span class="string">&quot;input_ids&quot;</span>].append(input_ids)</span><br><span class="line">            model_inputs[<span class="string">&quot;labels&quot;</span>].append(labels)</span><br><span class="line">    <span class="keyword">return</span> model_inputs</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">ds_train = ds_train_raw.<span class="built_in">map</span>(</span><br><span class="line">    preprocess,</span><br><span class="line">    batched=<span class="literal">True</span>,</span><br><span class="line">    num_proc=<span class="number">4</span>,</span><br><span class="line">    remove_columns=ds_train_raw.column_names</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">ds_val = ds_val_raw.<span class="built_in">map</span>(</span><br><span class="line">    preprocess,</span><br><span class="line">    batched=<span class="literal">True</span>,</span><br><span class="line">    num_proc=<span class="number">4</span>,</span><br><span class="line">    remove_columns=ds_val_raw.column_names</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h4 id="构建管道"><a href="#构建管道" class="headerlink" title="构建管道"></a>构建管道</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">data_collator = DataCollatorForSeq2Seq(</span><br><span class="line">    tokenizer,</span><br><span class="line">    model=<span class="literal">None</span>,</span><br><span class="line">    label_pad_token_id=-<span class="number">100</span>,</span><br><span class="line">    pad_to_multiple_of=<span class="literal">None</span>,</span><br><span class="line">    padding=<span class="literal">False</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">dl_train = DataLoader(ds_train,batch_size = cfg.batch_size,</span><br><span class="line">                      num_workers = <span class="number">2</span>, shuffle = <span class="literal">True</span>, collate_fn = data_collator </span><br><span class="line">                     )</span><br><span class="line">dl_val = DataLoader(ds_val,batch_size = cfg.batch_size,</span><br><span class="line">                      num_workers = <span class="number">2</span>, shuffle = <span class="literal">False</span>, collate_fn = data_collator </span><br><span class="line">                     )</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> batch <span class="keyword">in</span> dl_train:</span><br><span class="line">    <span class="keyword">break</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="built_in">len</span>(dl_train))</span><br></pre></td></tr></table></figure><h4 id="定义模型"><a href="#定义模型" class="headerlink" title="定义模型"></a>定义模型</h4><p>下面我们使用AdaLoRA方法来微调ChatGLM2，以便给模型注入和梦中情炉 torchkeras相关的知识。</p><p>AdaLoRA是LoRA方法的一种升级版本，使用方法与LoRA基本一样。</p><p>主要差异在于，在LoRA中不同训练参数矩阵的秩是一样的被固定的。</p><p>但AdaLoRA中不同训练参数矩阵的秩是会在一定范围内自适应调整的，那些更重要的训练参数矩阵会分配到更高的秩。</p><p>通常认为，AdaLoRA的效果会好于LoRA。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> peft <span class="keyword">import</span> get_peft_model, AdaLoraConfig, TaskType</span><br><span class="line"></span><br><span class="line"><span class="comment">#训练时节约GPU占用</span></span><br><span class="line">model.config.use_cache=<span class="literal">False</span></span><br><span class="line">model.supports_gradient_checkpointing = <span class="literal">True</span>  <span class="comment">#</span></span><br><span class="line">model.gradient_checkpointing_enable()</span><br><span class="line">model.enable_input_require_grads()</span><br><span class="line"></span><br><span class="line">peft_config = AdaLoraConfig(</span><br><span class="line">    task_type=TaskType.CAUSAL_LM, inference_mode=<span class="literal">False</span>,</span><br><span class="line">    r=<span class="number">8</span>,</span><br><span class="line">    lora_alpha=<span class="number">32</span>, lora_dropout=<span class="number">0.1</span>,</span><br><span class="line">    target_modules=[<span class="string">&quot;query&quot;</span>, <span class="string">&quot;value&quot;</span>]</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">peft_model = get_peft_model(model, peft_config)</span><br><span class="line"></span><br><span class="line">peft_model.is_parallelizable = <span class="literal">True</span></span><br><span class="line">peft_model.model_parallel = <span class="literal">True</span></span><br><span class="line">peft_model.print_trainable_parameters()</span><br></pre></td></tr></table></figure><h4 id="训练模型"><a href="#训练模型" class="headerlink" title="训练模型"></a>训练模型</h4><p>我们使用我们的梦中情炉torchkeras来实现最优雅的训练循环~</p><p>注意这里，为了更加高效地保存和加载参数，我们覆盖了KerasModel中的load_ckpt和save_ckpt方法，</p><p>仅仅保存和加载可训练lora权重，这样可以避免加载和保存全部模型权重造成的存储问题。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torchkeras <span class="keyword">import</span> KerasModel </span><br><span class="line"><span class="keyword">from</span> accelerate <span class="keyword">import</span> Accelerator </span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">StepRunner</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, net, loss_fn, accelerator=<span class="literal">None</span>, stage = <span class="string">&quot;train&quot;</span>, metrics_dict = <span class="literal">None</span>, </span></span><br><span class="line"><span class="params">                 optimizer = <span class="literal">None</span>, lr_scheduler = <span class="literal">None</span></span></span><br><span class="line"><span class="params">                 </span>):</span><br><span class="line">        self.net,self.loss_fn,self.metrics_dict,self.stage = net,loss_fn,metrics_dict,stage</span><br><span class="line">        self.optimizer,self.lr_scheduler = optimizer,lr_scheduler</span><br><span class="line">        self.accelerator = accelerator <span class="keyword">if</span> accelerator <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> <span class="keyword">else</span> Accelerator() </span><br><span class="line">        <span class="keyword">if</span> self.stage==<span class="string">&#x27;train&#x27;</span>:</span><br><span class="line">            self.net.train() </span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            self.net.<span class="built_in">eval</span>()</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__call__</span>(<span class="params">self, batch</span>):</span><br><span class="line">        </span><br><span class="line">        <span class="comment">#loss</span></span><br><span class="line">        <span class="keyword">with</span> self.accelerator.autocast():</span><br><span class="line">            loss = self.net(input_ids=batch[<span class="string">&quot;input_ids&quot;</span>],labels=batch[<span class="string">&quot;labels&quot;</span>]).loss</span><br><span class="line"></span><br><span class="line">        <span class="comment">#backward()</span></span><br><span class="line">        <span class="keyword">if</span> self.optimizer <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> <span class="keyword">and</span> self.stage==<span class="string">&quot;train&quot;</span>:</span><br><span class="line">            self.accelerator.backward(loss)</span><br><span class="line">            <span class="keyword">if</span> self.accelerator.sync_gradients:</span><br><span class="line">                self.accelerator.clip_grad_norm_(self.net.parameters(), <span class="number">1.0</span>)</span><br><span class="line">            self.optimizer.step()</span><br><span class="line">            <span class="keyword">if</span> self.lr_scheduler <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                self.lr_scheduler.step()</span><br><span class="line">            self.optimizer.zero_grad()</span><br><span class="line">            </span><br><span class="line">        all_loss = self.accelerator.gather(loss).<span class="built_in">sum</span>()</span><br><span class="line">        </span><br><span class="line">        <span class="comment">#losses (or plain metrics that can be averaged)</span></span><br><span class="line">        step_losses = &#123;self.stage+<span class="string">&quot;_loss&quot;</span>:all_loss.item()&#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">#metrics (stateful metrics)</span></span><br><span class="line">        step_metrics = &#123;&#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> self.stage==<span class="string">&quot;train&quot;</span>:</span><br><span class="line">            <span class="keyword">if</span> self.optimizer <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                step_metrics[<span class="string">&#x27;lr&#x27;</span>] = self.optimizer.state_dict()[<span class="string">&#x27;param_groups&#x27;</span>][<span class="number">0</span>][<span class="string">&#x27;lr&#x27;</span>]</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                step_metrics[<span class="string">&#x27;lr&#x27;</span>] = <span class="number">0.0</span></span><br><span class="line">        <span class="keyword">return</span> step_losses,step_metrics</span><br><span class="line">    </span><br><span class="line">KerasModel.StepRunner = StepRunner </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#仅仅保存lora相关的可训练参数</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">save_ckpt</span>(<span class="params">self, ckpt_path=<span class="string">&#x27;checkpoint&#x27;</span>, accelerator = <span class="literal">None</span></span>):</span><br><span class="line">    unwrap_net = accelerator.unwrap_model(self.net)</span><br><span class="line">    unwrap_net.save_pretrained(ckpt_path)</span><br><span class="line">    </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">load_ckpt</span>(<span class="params">self, ckpt_path=<span class="string">&#x27;checkpoint&#x27;</span></span>):</span><br><span class="line">    self.net = self.net.from_pretrained(self.net.base_model.model,ckpt_path)</span><br><span class="line">    self.from_scratch = <span class="literal">False</span></span><br><span class="line">    </span><br><span class="line">KerasModel.save_ckpt = save_ckpt </span><br><span class="line">KerasModel.load_ckpt = load_ckpt </span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">optimizer = torch.optim.AdamW(peft_model.parameters(),lr=cfg.lr) </span><br><span class="line">keras_model = KerasModel(peft_model,loss_fn = <span class="literal">None</span>,</span><br><span class="line">        optimizer=optimizer) </span><br><span class="line">ckpt_path = <span class="string">&#x27;single_chatglm2&#x27;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">keras_model.fit(train_data = dl_train,</span><br><span class="line">                val_data = dl_val,</span><br><span class="line">                epochs=<span class="number">100</span>,</span><br><span class="line">                patience=<span class="number">20</span>,</span><br><span class="line">                monitor=<span class="string">&#x27;val_loss&#x27;</span>,</span><br><span class="line">                mode=<span class="string">&#x27;min&#x27;</span>,</span><br><span class="line">                ckpt_path = ckpt_path,</span><br><span class="line">                mixed_precision=<span class="string">&#x27;fp16&#x27;</span>,</span><br><span class="line">                gradient_accumulation_steps = cfg.gradient_accumulation_steps</span><br><span class="line">               )</span><br></pre></td></tr></table></figure><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908232021.png" fancybox="true"/></div></div><h4 id="验证模型"><a href="#验证模型" class="headerlink" title="验证模型"></a>验证模型</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> peft <span class="keyword">import</span> PeftModel </span><br><span class="line">ckpt_path = <span class="string">&#x27;single_chatglm2&#x27;</span></span><br><span class="line">model_old = AutoModel.from_pretrained(<span class="string">&quot;chatglm2-6b&quot;</span>,</span><br><span class="line">                                  load_in_8bit=<span class="literal">False</span>, </span><br><span class="line">                                  trust_remote_code=<span class="literal">True</span>)</span><br><span class="line">peft_loaded = PeftModel.from_pretrained(model_old,ckpt_path).cuda()</span><br><span class="line">model_new = peft_loaded.merge_and_unload() <span class="comment">#合并lora权重</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chatglm = ChatGLM(model_new,tokenizer,max_chat_rounds=<span class="number">20</span>) <span class="comment">#支持多轮对话，可以从之前对话上下文提取知识。</span></span><br></pre></td></tr></table></figure><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908232054.png" fancybox="true"/></div></div><h4 id="使用模型"><a href="#使用模型" class="headerlink" title="使用模型"></a>使用模型</h4><p>我们尝试触碰一下模型学到的知识的边界在哪里，并看一下模型的其它能力是否受到影响。</p><p>为了直接测试模型提取知识的能力，我们关闭掉多轮对话功能，不让模型从上下文提取知识。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908232120.png" fancybox="true"/></div></div><p>😂😂</p><p>从这个测试中，我们可以看到模型能够注入和提取知识，并且注入知识后基本不会影响到旧知识。</p><p>但是模型能够直接提取出知识的场景，必须是 问题 和我们训练时语义非常相似的情况。</p><p>‘what is 梦中情炉’ 和 ‘这是个啥子意思哟:梦中情炉?’ 都是这样的例子。</p><p>在以’以梦中情炉为主题，写一首优美的现代诗歌，要有激情，有感染力~’ 和 ‘torchkeras是个啥子哦?’ 的例子中，</p><p>虽然我们的知识库中有梦中情炉，也就是torchkeras相关的知识，但是这两个问题和我们训练时候的语义相差很大，所以无法直接提取出来并应用相关的知识。</p><p>从这个意义上说，LLM模型非常像一个key-value类型的知识数据库，这里的key是某种语义，而不是某个特定的词。</p><p>通过微调，我们可以给这个知识数据库注入，删除，和修改知识（设计目标输出成我们需要的形式即可）。</p><p>通过输入和训练时语义相近的提示词，我们可以从这个知识数据库中查询提取知识。</p><p>只有查询提取知识到对话上下文之后，LLM才能够灵活地使用知识。</p><h4 id="保存模型"><a href="#保存模型" class="headerlink" title="保存模型"></a>保存模型</h4><p>可以将模型和tokenizer，以及相关py文件都保存到一个新的路径，便于直接加载。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">save_path = <span class="string">&quot;chatglm2-6b-梦中情炉&quot;</span></span><br><span class="line">model_new.save_pretrained(save_path, max_shard_size=<span class="string">&#x27;2GB&#x27;</span>)</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">tokenizer.save_pretrained(save_path) </span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">(&#x27;chatglm2-6b-梦中情炉/tokenizer_config.json&#x27;,</span></span><br><span class="line"><span class="string"> &#x27;chatglm2-6b-梦中情炉/special_tokens_map.json&#x27;,</span></span><br><span class="line"><span class="string"> &#x27;chatglm2-6b-梦中情炉/tokenizer.model&#x27;,</span></span><br><span class="line"><span class="string"> &#x27;chatglm2-6b-梦中情炉/added_tokens.json&#x27;)</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure><p>PS: 还需要将相关的py文件也复制过去。</p><h3 id="总结延申"><a href="#总结延申" class="headerlink" title="总结延申"></a>总结延申</h3><p>演示了使用AdaLoRA算法，使用1条样本对ChatGLM2实施微调。几分钟就成功注入了”梦中情炉”有关的知识。</p><p><strong>总结:</strong></p><p>(1) 只需要1条样本，很少的训练时间，就可以通过微调给LLM注入知识。</p><p>(2) LLM是一种知识数据库，支持增删改查。通过微调可以增删修改知识，通过条件生成可以查询提取知识。</p><p>(3) LoRA微调是一种高效的融入学习算法。类似人类把新知识融入现有知识体系的学习过程。学习时无需新知识特别多的样本，学习后原有的庞大知识和能力可以基本不受影响。</p><p><strong>问题:</strong></p><p>(1) 如果我们有很多条例如几千几万条知识，如何才能比较高效地给LLM注入并确保每条都注入成功呢?</p><p>第一种想法是常规的微调方法，我们把这些知识混合成一个数据集用LoRA进行微调。</p><p>第二种方法是让LLM用单样本微调的方法一条知识一条知识地学习，确保学习成功了一条知识后合并LoRA权重再去学习下一条。</p><p>出于人类学习的经验，我可能觉得第二种会更加高效且可靠。或者也可能某种中间方案会更好，例如几条或者几十条知识作为一个学习批次，学习完了后再去学习下一个。究竟哪种更好，需要我们去做实验尝试。</p><p>(2) 如果说ChatGLM2-6b可以作为一种Key-Value结构的知识数据库，我们知道这个模型的参数权重规模大概是60亿，也就是6个G，那么这个数据库能够储存超过6个G比如10个G的知识信息吗？能够存储无限的知识信息吗也就是有存储上限吗？如果有上限的话，给它喂入超过其存储能力上限的知识，会发生什么呢？</p><p>这个问题触碰到我认知的边界了，我尝试用直觉答一下。LLM应该能够存储远超过其参数权重规模的知识，因为它做的是一种压缩存储，并且压缩率很高。</p><p>想想看训练时丢给它的几十上百个T的数据，它从中有效汲取的能够提取复现的知识肯定不止6个G，假设有120个G，那么压缩率就是20倍。</p><p>如果把LLM作为一个知识数据库，那它肯定是有存储上限的。如果给他喂入超过其存储能力的数据会发生什么？我想应该是会发生一种类似KV表中的哈希冲突这样的问题。也就是一些旧知识会被遗忘。</p><p>但是这种哈希冲突不是我们理解的那种随机发生的哈希冲突，而是那些语义最相似的key会发生冲突，这个过程和知识的更新或者说修改本质上是一个过程。从应用角度来看，这种冲突应该极难发生，并且相比随机的哈希冲突来看还是很良性的。</p><p>(3) 为什么通过LoRA微调将新知识融入现有知识体系过程的中，既不需要新知识特别多的样本，同时学习后原有的庞大知识和能力可以不受影响呢？这么优良的特性是怎么发生的？</p><p>实际上我们这个用LoRA算法来微调LLM注入新知识的过程 和 标准的使用LoRA算法微调StableDiffusion 炼制一个新角色或者炼制一种新画风的过程非常的类似。</p><p>无论从原理还是结果上，都是只需要很少的新知识的样本，同时学习后模型原有的庞大知识和能力基本不受影响。</p><p>这个事情的发生确实非常的神奇，非常的美妙，使得我们不得不思考一下背后的原因。</p><p>我猜想这个美妙特性的发生是三个要素协同作用的结果。</p><p>第一个要素是输入的区分性。</p><p>在我们的例子中，我们的新知识的输入通过一个关键词’梦中情炉’来和已有知识体系进行区分。</p><p>在StableDiffusion微调炼制新角色也是如此，你需要为你的新角色创建一个独特的名字。</p><p>如果在输入上无法明显地区分新旧知识，那么这种和平融入就无法发生，会产生严重的冲突。</p><p>第二个要素是预训练模型的抗破坏性。</p><p>现在的大部分模型都引入了ResNet结构。拥有ResNet结构的模型本质上属于多个子模型的集成模型。</p><p>即使你随机地改变其中一些层的权重，整个模型的输出不会有太大的变化。</p><p>同时，训练过程中还使用了dropout，使得模型的抗破坏性进一步增强。</p><p>对于旧知识对应的那些输入，即使有些本来相关的权重矩阵被新知识的微调随机地破坏了，输出也几乎不会受到影响。</p><p>第三个要素是LoRA的正则性。</p><p>LoRA微调的思想是学习两个小的低秩矩阵，用它们的乘积来作为大的参数矩阵需要改变的增量。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20230908232319.png" fancybox="true"/></div></div><p>这个将增量参数矩阵低秩分解的过程实际上引入了很强的正则性。一方面减少了模型训练的难度，让模型更快地收敛。</p><p>同时它可能在一定程度上，也会降低学习新知识的过程中过度调整模型权重，对旧知识产生影响的风险。</p><p>但和第一个要素和第二个要素不同，这个特性对降低新旧知识的冲突应该不是最核心的，全参数微调往往也能够和平融合新旧知识。</p><h2 id="首尾呼应"><a href="#首尾呼应" class="headerlink" title="首尾呼应"></a>首尾呼应</h2><p>没区别</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;这东西有些迅猛啊，才是2022年底的略有名气，现在才2023刚开春，GPT-4了？&lt;br&gt;也体验过，程序员确实把自己淘汰了。&lt;/p&gt;</summary>
    
    
    
    <category term="人工智能" scheme="https://www.i5res.com/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    
    <category term="python" scheme="https://www.i5res.com/tags/python/"/>
    
    <category term="人工智能" scheme="https://www.i5res.com/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    <category term="ChatGPT" scheme="https://www.i5res.com/tags/ChatGPT/"/>
    
  </entry>
  
  <entry>
    <title>转瞬即逝的一年，这一年的结尾</title>
    <link href="https://www.i5res.com/miscellaneous/new-year-2023-celebration.html"/>
    <id>https://www.i5res.com/miscellaneous/new-year-2023-celebration.html</id>
    <published>2023-01-06T14:06:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><h2 id="好像就在昨天"><a href="#好像就在昨天" class="headerlink" title="好像就在昨天"></a>好像就在昨天</h2><p>一下子好像突然想起什么，一寸一寸叠起来的小房间里我仰着头。我阳了，发烧的挺厉害<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatcomftears.png"/></span>，我还是坚持坐在桌前，我抬着头，我想着昨天，昨天的昨天，昨天的昨天的，昨天。<br>嘶，我好像刚开学来着？<br>不对，一个学期就这么过掉了啊，好快。也不知道是不是因为惶恐疫情提前放假的缘故，我觉得今年格外的短</p><h3 id="达芬奇"><a href="#达芬奇" class="headerlink" title="达芬奇"></a>达芬奇</h3><p>人们错误地叹息时光的流逝。责备时间过得太快，不认为时间是充裕的，自然赐给我们以好的记忆，使一切事物经历的时问比实际存在的时间还要长久。</p><h3 id="回顾2022"><a href="#回顾2022" class="headerlink" title="回顾2022"></a>回顾2022</h3><p>我突然好像又不觉得是件坏事了，来让我好好回顾一下我的2022：<br>起初的，抱有热忱的，反向字体编辑的轮子，立项，到如今也只是停留在了新建文件夹的阶段。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatpeekaboo.png"/></span><br>然后我着眼了新的目标———开箱的图床，直到我看到了已经有了的并且非常优秀的PicGo-Core，我望向了其生态，也向往着其生态。<br>我着手了短视频制作，我记录着我的学习经历，其实这也是我仅仅保留下来的一个习惯了。<br>赚了！<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatphoto.png"/></span></p><h3 id="亲友别离"><a href="#亲友别离" class="headerlink" title="亲友别离"></a>亲友别离</h3><p>被带走的还有一张会很大屏障，催促着成长。</p><p>有人会说，无能者怀念过去。过去有的盛夏，现在也有，过去有的难道现在没了吗？如果是我，我应该懒得理他，我会认为没什么意义，证明自己有能力又会发生什么？可能，只是会让他换一个地方再这么说一遍。<br>世界不停的循环着。</p><h3 id="不耐烦yes责任"><a href="#不耐烦yes责任" class="headerlink" title="不耐烦yes责任"></a>不耐烦yes责任</h3><p>我在学校里，有了一些责任，慎厥初，惟厥终。我不知道成长是一种什么样的体验，可能我正在经历，网络使人相遇是很简单，可是好像让每个人越变越远，我不知道什么时候想明白其实问题不是出在了网络。可能是我老了。<br>从前，我义愤填膺的在各个角落置评我巴不得告诉全世界我支持的，我理解的。慢慢的，我打开了那个自己的屏蔽按钮。屏蔽外界的同时屏蔽自己了，这样确实会让我舒服不少，越来越觉得我觉得累的是与他人交流。<br>看到了好多，心里面总是会有一个念头：这是我小时候最渴望拥有的，可是现在我长大了。<br>我有很多朋友，我希望永远与他们没有利益冲突，甚至没有利益交流，我渴望他们永远是我纯粹的朋友。</p><h3 id="挚是执与手"><a href="#挚是执与手" class="headerlink" title="挚是执与手"></a>挚是执与手</h3><p>我也遇到了一个志同道合的朋友。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/ablobcatrainbow.png"/></span><br>他走过的路我正在走，不吝啬的抛出一个个答案。</p><p>引人深思的，<br>正确的，<br>难以理解的，<br>相悖的，</p><p>我都没有反驳，我很享受观点的碰撞。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatread.png"/></span></p><h2 id="致马上到来的夏天"><a href="#致马上到来的夏天" class="headerlink" title="致马上到来的夏天"></a>致马上到来的夏天</h2><p>一年一年真的好快。</p><p>确实不能只活在过去。</p><p>亏了，当时没好好怼他。</p><h3 id="，不甘心"><a href="#，不甘心" class="headerlink" title="***，不甘心"></a>***，不甘心</h3><p>我有时候不太甘心自己活得太和善，尽管我以往都是如此做的，“谢谢” “抱歉” “不好意思” 泛滥了。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatfacepalm.png"/></span><br>就不值钱了，多少人曾经践踏在我和善的性格之上，我改变着。</p><p>我见识过那些自我为中心者，我现在往往会忍着厌恶去配合他们演出。</p><p>我也见识过真正的智者深藏暗处，片叶不沾身的智慧把他包装的太神圣了，至少在我心中是这样。</p><h3 id="船到桥头自然直"><a href="#船到桥头自然直" class="headerlink" title="船到桥头自然直"></a>船到桥头自然直</h3><p>名利对我来说有一定的吸引力，我确实做梦都想着功成名就，我也为此忍了挺久的。</p><p>我不想做计划，我不希望计划雪崩那样的事情发生在我身上，干脆！走一步看一步，我对他人的安慰其中除了部分概要分析，就是“船到桥头自然直”</p><h2 id="忘得掉"><a href="#忘得掉" class="headerlink" title="忘得掉"></a>忘得掉</h2><p>从小到大，好像没什么忘不掉了的，我能释怀一切，啊哈哈哈哈哈。</p><p>对不起，不该在这方面开玩笑的，宁可信其有……</p><h3 id="我是不是也能烧出舍利"><a href="#我是不是也能烧出舍利" class="headerlink" title="我是不是也能烧出舍利"></a>我是不是也能烧出舍利</h3><p>什么什么方丈坐化佛前…那种什么的，我觉得我也有部分很难得的心境，我比较冷静，如果事件的结果我能够承担，那么冷静的必然的。如若？</p><p>嘶，不好说。算了，烧不出。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatfearful.png"/></span></p><h2 id="做不完的梦"><a href="#做不完的梦" class="headerlink" title="做不完的梦"></a>做不完的梦</h2><p>睡不醒，那就一直睡。</p><h2 id="新年快乐"><a href="#新年快乐" class="headerlink" title="新年快乐"></a>新年快乐</h2><p>兔年了，好快。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/new_year_2023-2023-01-06-23-06-31.png" fancybox="true"/></div></div>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; class=&quot;aplayer-secondary-style-marker&quot; href=&quot;/assets/css/APlayer.min.css&quot;&gt;&lt;script src=&quot;/assets/js/APlayer.min.js&quot; cla</summary>
      
    
    
    
    <category term="表白与谈说" scheme="https://www.i5res.com/categories/%E8%A1%A8%E7%99%BD%E4%B8%8E%E8%B0%88%E8%AF%B4/"/>
    
    
    <category term="杂谈" scheme="https://www.i5res.com/tags/%E6%9D%82%E8%B0%88/"/>
    
  </entry>
  
  <entry>
    <title>Node + Ts + Mongodb 增删改查封装</title>
    <link href="https://www.i5res.com/typescript-and-mongodb.html"/>
    <id>https://www.i5res.com/typescript-and-mongodb.html</id>
    <published>2022-12-07T15:00:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>俗言有道，自奉必减几分方好，处世能退一步为高。<br>之前有很多的前后端开发，数据库其实是一个项目运行的必须的一环，也是很重要的一环。<br>数据库千千万，合适的到底有哪些？</p><span id="more"></span><h2 id="数据库有哪些"><a href="#数据库有哪些" class="headerlink" title="数据库有哪些"></a>数据库有哪些</h2><p><a href="#DB%E7%B1%BB%E5%B0%81%E8%A3%85">跳过废话</a></p><ul><li>关系型数据库 <ul><li>Oracle</li><li>MySQL</li></ul></li><li>非关系型数据库<ul><li>NoSQL</li></ul></li><li>键值存储数据库（key-value）<ul><li>Memcached</li><li>Redis</li><li>MemcacheDB</li></ul></li><li>列存储（Column-oriented）数据库<ul><li>Cassandra</li><li>HBase</li></ul></li><li>面向文档（Document-Oriented）数据库<ul><li>MongoDB</li><li>CouchDB</li></ul></li><li>图形数据库<ul><li>Neo4J</li><li>InforGrid</li></ul></li></ul><h2 id="MongoDB！"><a href="#MongoDB！" class="headerlink" title="MongoDB！"></a>MongoDB！</h2><p><a href="https://www.mongodb.com/home">https://www.mongodb.com/home</a></p><p>几句话。</p><p>不管是kv的内存型redies，还是文档型的mongodb，上手都很都很简单，而且，文档型数据库跟json很像啊，那就更容易理解了，再加上性能还凑合，就他了呗，而且还有mongoose这种玩意，写着毫无压力，个把小时就上手了<br>敲黑板！时间就是金钱啊，先上了再说玩会了这个流程，是什么数据库不重要，都是store，根据配置切不同实现就完事。至于后面要考虑的存和取的性能和场景，不需要一开始就过度考虑。</p><p>妄论一下。</p><p>1.Node在io并发处理比较擅长，mongodb也是擅长读写的，两者这方面很契合，mongodb在大数据方面也比较擅长。<br>2.mongodb是文档数据，数据结构是bson，也可以说是json，而众所周知json是来源于JavaScript object，nodejs又是以<strong>js</strong>为编程语言。</p><h3 id="Js为底层语言"><a href="#Js为底层语言" class="headerlink" title="Js为底层语言"></a>Js为底层语言</h3><p>很直观的体现了，在进入Mongo时，执行<code>1 + 1</code>会返回<code>2</code>，dddd</p><p>看到这里，其实也跃跃欲试了，如何像博主一样花费30分钟就可以玩得转它？</p><p>我知道你很急，但是你先别急。</p><h3 id="安装流程"><a href="#安装流程" class="headerlink" title="安装流程"></a>安装流程</h3><p>很保姆级了，往下看。</p><p>下载。</p><p>安装。</p><p>无需配置环境变量。</p><p>能理解到这一步，其实对shell这类，还有系统这类有一定认识了，mongo.exe其实就是一个cmd程序。</p><p>我的bin文件夹</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221207231825.png" fancybox="true"/></div></div><p>打开目录下的终端，这里不管是cmd还是terminal都可以</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221207231909.png" fancybox="true"/></div></div><p>先别急着一步步操作，看教程是为了学会，请耐心通读本段落</p><p><strong>mongod.exe</strong>是创建mongodb的进程，也就是打开数据库的程序</p><p>我在<strong>D:/</strong>创建了文件夹<strong>Databases&#x2F;Mongodb</strong></p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221207232710.png" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221207232728.png" fancybox="true"/></div></div><p>刚创建文件夹肯定不会像我一样有文件。。。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mongod.exe --dbpath &quot;D:/Databases/Mongodb/&quot;</span><br></pre></td></tr></table></figure><p>执行完后，你会发现你的文件夹里面生成了文件。</p><p>然后，<br>打开数据库。。。</p><p><strong>mongosh.exe</strong>是一个可以操作mongodb的命令行程序</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mongosh.exe</span><br></pre></td></tr></table></figure><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221207232618.png" fancybox="true"/></div></div><p>到这里，你拥有了一个<strong>Mongodb</strong>数据库。</p><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><p><strong>创建数据库</strong></p><p>尝试使用一个自定义的数据库：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&gt; use test_db</span><br><span class="line">switched to db test_db</span><br><span class="line">&gt; db</span><br><span class="line">test_db</span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&gt; show dbs</span><br><span class="line">admin    <span class="number">40.00</span> <span class="title class_">KiB</span></span><br><span class="line">config   <span class="number">72.00</span> <span class="title class_">KiB</span></span><br><span class="line">local    <span class="number">72.00</span> <span class="title class_">KiB</span></span><br><span class="line">test_db   <span class="number">8.00</span> <span class="title class_">KiB</span></span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure><p>“为什么我use的test_db不在里面？”</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&gt; db.<span class="property">test_db</span>.<span class="title function_">insert</span>(&#123;<span class="string">&quot;name&quot;</span>:<span class="string">&quot;测试&quot;</span>&#125;)</span><br><span class="line"><span class="title class_">DeprecationWarning</span>: <span class="title class_">Collection</span>.<span class="title function_">insert</span>() is deprecated. <span class="title class_">Use</span> insertOne, insertMany, or bulkWrite.</span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">acknowledged</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="attr">insertedIds</span>: &#123; <span class="string">&#x27;0&#x27;</span>: <span class="title class_">ObjectId</span>(<span class="string">&quot;63917571c6696a553b3fc68c&quot;</span>) &#125;</span><br><span class="line">&#125;</span><br><span class="line">&gt; show dbs</span><br><span class="line">admin    <span class="number">40.00</span> <span class="title class_">KiB</span></span><br><span class="line">config   <span class="number">72.00</span> <span class="title class_">KiB</span></span><br><span class="line">local    <span class="number">72.00</span> <span class="title class_">KiB</span></span><br><span class="line">test_db   <span class="number">8.00</span> <span class="title class_">KiB</span></span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure><p>出现了。<br>在这一步，Mongodb会在你插入数据的时候自动创建数据库。（很方便）</p><p><strong>删除数据库</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&gt; db.<span class="title function_">dropDatabase</span>(<span class="params"></span>)</span><br><span class="line">&#123; <span class="attr">ok</span>: <span class="number">1</span>, <span class="attr">dropped</span>: <span class="string">&#x27;test_db&#x27;</span> &#125;</span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure><p><strong>集合</strong></p><p>列出</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">show collections</span><br></pre></td></tr></table></figure><p>创建</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">db.<span class="title function_">createCollection</span>(name, options)</span><br></pre></td></tr></table></figure><p><strong>options</strong></p><table><thead><tr><th>字段</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>capped</td><td>布尔</td><td>（可选）如果为 true，则创建固定集合。固定集合是指有着固定大小的集合，当达到最大值时，它会自动覆盖最早的文档。当该值为 true 时，必须指定 size 参数。</td></tr><tr><td>autoIndexId</td><td>布尔</td><td>3.2 之后不再支持该参数。（可选）如为 true，自动在 _id 字段创建索引。默认为 false。</td></tr><tr><td>size</td><td>数值</td><td>（可选）为固定集合指定一个最大值，即字节数。如果 capped 为 true，也需要指定该字段。</td></tr><tr><td>max</td><td>数值</td><td>（可选）指定固定集合中包含文档的最大数量。</td></tr></tbody></table><p>删除</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">db.<span class="property">collection</span>.<span class="title function_">drop</span>()</span><br></pre></td></tr></table></figure><p><strong>文档</strong></p><p>于集合下的一个子函数，可以理解为集合的下一级，而文档内存储的就是业务逻辑中的主要内容</p><p>插入</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">db.<span class="property">COLLECTION_NAME</span>.<span class="title function_">insert</span>(<span class="variable language_">document</span>)</span><br><span class="line">或</span><br><span class="line">db.<span class="property">COLLECTION_NAME</span>.<span class="title function_">save</span>(<span class="variable language_">document</span>)</span><br></pre></td></tr></table></figure><p>更新</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">db.<span class="property">collection</span>.<span class="title function_">update</span>(</span><br><span class="line">   &lt;query&gt;,</span><br><span class="line">   &lt;update&gt;,</span><br><span class="line">   &#123;</span><br><span class="line">     <span class="attr">upsert</span>: &lt;boolean&gt;,</span><br><span class="line">     <span class="attr">multi</span>: &lt;boolean&gt;,</span><br><span class="line">     <span class="attr">writeConcern</span>: &lt;<span class="variable language_">document</span>&gt;</span><br><span class="line">   &#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h2 id="DB类封装"><a href="#DB类封装" class="headerlink" title="DB类封装"></a>DB类封装</h2><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> mongodb <span class="keyword">from</span> <span class="string">&#x27;mongodb&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="variable constant_">DBI</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;./interfaces&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Db</span> <span class="keyword">implements</span> <span class="variable constant_">DBI</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="attr">client</span>: mongodb.<span class="property">MongoClient</span> | <span class="literal">undefined</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="attr">db</span>: mongodb.<span class="property">Db</span> | <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="attr">instance</span>: <span class="title class_">Db</span> | <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">getInstance</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title class_">Db</span>.<span class="property">instance</span>) <span class="keyword">throw</span> <span class="string">&quot;No Event!&quot;</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">instance</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">DB_CONN_STRING: <span class="built_in">string</span>, DB_NAME: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">connection</span>(<span class="variable constant_">DB_CONN_STRING</span>, <span class="variable constant_">DB_NAME</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 插入数据</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> collectionName 集合名称</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> doc 内容</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@returns</span> </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> insert&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">doc</span>: mongodb.<span class="property">OptionalId</span>&lt;T&gt;): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">InsertOneResult</span>&lt;mongodb.<span class="property">Document</span>&gt;&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">InsertOneResult</span>&lt;mongodb.<span class="property">Document</span>&gt;&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">insertOne</span>(doc).<span class="title function_">then</span>(resolve).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 插入多数据</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> collectionName 集合名称</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> docs[] 内容数组</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@returns</span> </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> insertMany&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">docs</span>: mongodb.<span class="property">OptionalId</span>&lt;T&gt;[]): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">InsertManyResult</span>&lt;mongodb.<span class="property">Document</span>&gt;&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">InsertManyResult</span>&lt;mongodb.<span class="property">Document</span>&gt;&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">insertMany</span>(docs).<span class="title function_">then</span>(resolve).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">delete</span>&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">filter</span>: mongodb.<span class="property">Filter</span>&lt;T&gt;): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">DeleteResult</span>&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">DeleteResult</span>&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">deleteOne</span>(filter).<span class="title function_">then</span>(resolve).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> err;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> deleteMany&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">filter</span>: mongodb.<span class="property">Filter</span>&lt;T&gt;): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">DeleteResult</span>&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">DeleteResult</span>&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">deleteMany</span>(filter).<span class="title function_">then</span>(resolve).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> err;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> update&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">filter</span>: mongodb.<span class="property">Filter</span>&lt;T&gt;, <span class="attr">update</span>: mongodb.<span class="property">UpdateFilter</span>&lt;T&gt;): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">UpdateResult</span>&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">UpdateResult</span>&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">updateOne</span>(filter, update).<span class="title function_">then</span>(resolve).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> err;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> find&lt;T = mongodb.<span class="property">Document</span>&gt;(<span class="attr">collectionName</span>: <span class="built_in">string</span>, <span class="attr">filter</span>: mongodb.<span class="property">Filter</span>&lt;T&gt;): <span class="title class_">Promise</span>&lt;<span class="built_in">any</span>[]&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;<span class="built_in">any</span>&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="title function_">resolve</span>(<span class="variable language_">this</span>.<span class="property">db</span>?.<span class="title function_">collection</span>(collectionName).<span class="title function_">find</span>(filter));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(<span class="literal">false</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> err;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">aggregate</span>(<span class="attr">_collectionName</span>: <span class="built_in">string</span>, <span class="attr">_pipeline</span>: <span class="built_in">object</span>[]): <span class="title class_">Promise</span>&lt;<span class="built_in">any</span>[]&gt; &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;Method not implemented.&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">connection</span>(<span class="attr">DB_CONN_STRING</span>: <span class="built_in">string</span>, <span class="attr">DB_NAME</span>: <span class="built_in">string</span>): <span class="title class_">Promise</span>&lt;mongodb.<span class="property">MongoClient</span>&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>&lt;mongodb.<span class="property">MongoClient</span>&gt;(<span class="keyword">async</span> (resolve, reject) =&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">client</span>) &#123;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">const</span> <span class="attr">client</span>: mongodb.<span class="property">MongoClient</span> = <span class="keyword">new</span> mongodb.<span class="title class_">MongoClient</span>(<span class="variable constant_">DB_CONN_STRING</span>);</span><br><span class="line">                    <span class="keyword">await</span> client.<span class="title function_">connect</span>();</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">db</span> = client.<span class="title function_">db</span>(<span class="variable constant_">DB_NAME</span>);</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">client</span> = client;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[Mongodb] class inited.&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="title function_">resolve</span>(<span class="variable language_">this</span>.<span class="property">client</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">reject</span>(err);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="JS-SDK引入"><a href="#JS-SDK引入" class="headerlink" title="JS-SDK引入"></a>JS-SDK引入</h2><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/ts_mongodb-2023-01-08-23-26-42.png" fancybox="true"/></div></div><p>emmmmmm内心复杂。<br>照理来说微信不该对组件编程陌生，这里居然还用半嵌入式页面开发。<br>既来之，则安之，我把它转为对象引入到项目，这部分有很多大佬都做了，因为没什么技术门槛。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;俗言有道，自奉必减几分方好，处世能退一步为高。&lt;br&gt;之前有很多的前后端开发，数据库其实是一个项目运行的必须的一环，也是很重要的一环。&lt;br&gt;数据库千千万，合适的到底有哪些？&lt;/p&gt;</summary>
    
    
    
    <category term="学习加油站" scheme="https://www.i5res.com/categories/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E7%AB%99/"/>
    
    
    <category term="mongodb" scheme="https://www.i5res.com/tags/mongodb/"/>
    
    <category term="typescript" scheme="https://www.i5res.com/tags/typescript/"/>
    
    <category term="js" scheme="https://www.i5res.com/tags/js/"/>
    
  </entry>
  
  <entry>
    <title>我的第一首歌《蛄语》</title>
    <link href="https://www.i5res.com/music/summerwords-album.html"/>
    <id>https://www.i5res.com/music/summerwords-album.html</id>
    <published>2022-11-01T13:04:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin gallery swiper" id="swiper-api" width="max"><div class="swiper-wrapper"><div class="swiper-slide"><img no-lazy src="https://p3.music.126.net/YjGsoP9t5yVrTu09bRYKAw==/109951164994395319.jpg?param=1080y1080" fancybox="true"/></div></div><div class="swiper-pagination"></div><div class="swiper-button-prev blur"></div><div class="swiper-button-next blur"></div></div>    <div id="aplayer-QoZkvSsA" class="aplayer aplayer-tag-marker meting-tag-marker"         data-id="1447292458" data-server="netease" data-type="song" data-mode="circulation" data-autoplay="true" data-mutex="false" data-listmaxheight="340px" data-preload="true" data-theme="#ad7a86" data-volume=" 0.2"    ></div><p>那时候，刚刚初升高。</p><p>正值炎热的盛夏。</p><span id="more"></span><p>还蛮羡慕那时候的纯粹的，歌曲的修饰很少，嘀嗒零星的鼓点，可是却再也找不到那时候的热情了。</p><p>这一首歌的鸟鸣和蝉鸣的采样，还是那时用着bit并不高的设备录制的，现在想起来突然感觉好像失去了什么东西。</p><p>如今，合成器多了采样多了，套路多了，写出来的好像却没有变多。</p><p>多少人说，编曲需要天赋，需要什么什么，需要这需要那的。</p><p>其实我很想说，你哪里知道的？听谁的，那么我再问，ta又是哪里知道的，谁说的，论证过吗。如果非要刨根问底，那么这世界还有多少是真的？</p><p>“被推翻的 以太理论，爱因斯坦的宇宙观？” 我更愿意相信这是一场无休止的战争。（包括我现在的这一句话，都有着一定的时效性）</p><p>你拿什么告诉我，这所谓的“天赋绝对论”是正确的。<br>我不奉行那些不知来源的理论。</p><p>那时的我，和现在对比就得出了很明显的结论。</p><p>简单和简单的区别，复杂和复杂的区别</p><p>这里我不是很想怀旧了，我更想去吐槽一下，那一些 “这不是有人做过了吗？” 还有 “为什么xxx (较有影响力的人)。。。不做？你这个不行的”</p><p>可悲的事是，多少“点子”在这样一点点被摧残，泯灭。</p><p>这首歌，是我在<strong>2020-05-10</strong>发布的，很粗糙，但是我觉得是最接近纯粹的唯一一首。</p><p>这不是我一个人的故事。</p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin gallery swiper&quot; id=&quot;swiper-api&quot; width=&quot;max&quot;&gt;&lt;div class=&quot;swiper-wrapper&quot;&gt;&lt;div class=&quot;swiper-slide&quot;&gt;&lt;img no-lazy src=&quot;https://p3.music.126.net/YjGsoP9t5yVrTu09bRYKAw==/109951164994395319.jpg?param=1080y1080&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;swiper-pagination&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-prev blur&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-next blur&quot;&gt;&lt;/div&gt;&lt;/div&gt;


    &lt;div id=&quot;aplayer-QoZkvSsA&quot; class=&quot;aplayer aplayer-tag-marker meting-tag-marker&quot;
         data-id=&quot;1447292458&quot; data-server=&quot;netease&quot; data-type=&quot;song&quot; data-mode=&quot;circulation&quot; data-autoplay=&quot;true&quot; data-mutex=&quot;false&quot; data-listmaxheight=&quot;340px&quot; data-preload=&quot;true&quot; data-theme=&quot;#ad7a86&quot; data-volume=&quot; 0.2&quot;
    &gt;&lt;/div&gt;

&lt;p&gt;那时候，刚刚初升高。&lt;/p&gt;
&lt;p&gt;正值炎热的盛夏。&lt;/p&gt;</summary>
    
    
    
    <category term="音尘行樂" scheme="https://www.i5res.com/categories/%E9%9F%B3%E5%B0%98%E8%A1%8C%E6%A8%82/"/>
    
    
    <category term="音乐" scheme="https://www.i5res.com/tags/%E9%9F%B3%E4%B9%90/"/>
    
    <category term="蛄语" scheme="https://www.i5res.com/tags/%E8%9B%84%E8%AF%AD/"/>
    
  </entry>
  
  <entry>
    <title>Typescript &amp; Javascript 开发小记 写一个简单的沙箱</title>
    <link href="https://www.i5res.com/typescript-javascript-sandbox..html"/>
    <id>https://www.i5res.com/typescript-javascript-sandbox..html</id>
    <published>2022-10-23T02:41:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>深拷贝和浅拷贝是 JS 基础，很多人（包括我）可能理解两者的区别。<br>还有记录一下近期开发沙盒的过程。</p><span id="more"></span><h2 id="中数组的深拷贝和浅拷贝"><a href="#中数组的深拷贝和浅拷贝" class="headerlink" title="中数组的深拷贝和浅拷贝"></a>中数组的深拷贝和浅拷贝</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 现在有个数组 list，它里面有“a、b、c”，3 个变量，如下：</span></span><br><span class="line"><span class="keyword">const</span> a = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;a&#x27;</span>,</span><br><span class="line">    <span class="attr">value</span>: <span class="string">&#x27;a&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> b = <span class="string">&#x27;str&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> c = <span class="number">256</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> list = [a, b, c];</span><br><span class="line"><span class="keyword">const</span> listCopy = list;</span><br><span class="line"><span class="keyword">const</span> listDeep = _.<span class="title function_">cloneDeep</span>(list);</span><br><span class="line"><span class="keyword">const</span> listClone = _.<span class="title function_">clone</span>(list);</span><br><span class="line">list.<span class="title function_">push</span>(<span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">a.<span class="property">name</span> = <span class="string">&#x27;new a&#x27;</span>;</span><br><span class="line">listClone.<span class="title function_">push</span>(<span class="string">&#x27;e&#x27;</span>);</span><br><span class="line">c = <span class="number">480</span>;</span><br><span class="line">listDeep.<span class="title function_">push</span>(<span class="string">&#x27;f&#x27;</span>);</span><br><span class="line">list[<span class="number">0</span>].<span class="property">value</span> = <span class="string">&#x27;new a&#x27;</span>;</span><br><span class="line">list[<span class="number">1</span>] = <span class="string">&#x27;new str&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;list&#x27;</span>, list); <span class="comment">// ???</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listCopy&#x27;</span>, listCopy); <span class="comment">// ???</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listDeep&#x27;</span>, listDeep); <span class="comment">// ???</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listClone&#x27;</span>, listClone); <span class="comment">// ???</span></span><br></pre></td></tr></table></figure><h3 id="重要概念"><a href="#重要概念" class="headerlink" title="重要概念"></a>重要概念</h3><ul><li>基本类型：Null、Undefined、Boolean、Number、String、Symbol。</li><li>引用类型：Object、Array、Function、Date 等。</li></ul><p>基本类型和引用类型的区别：基本类型在内存中是直接存储数据的，引用类型则为一个内存地址，通过这个地址可以得到存储的数据。</p><h3 id="结果及注释"><a href="#结果及注释" class="headerlink" title="结果及注释"></a>结果及注释</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 为方便讲解和学习，引入 lodash 的深拷贝和浅拷贝函数</span></span><br><span class="line"><span class="comment"> * 以下代码可在浏览器控制台运行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">const</span> importJS = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;script&#x27;</span>);</span><br><span class="line">importJS.<span class="title function_">setAttribute</span>(<span class="string">&quot;src&quot;</span>, <span class="string">&#x27;https://fastly.i5res.com/npm/lodash@4.17.21/lodash.min.js&#x27;</span>);</span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;head&quot;</span>)[<span class="number">0</span>].<span class="title function_">appendChild</span>(importJS);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 等待 lodash 加载。要在浏览器使用，有什么好的办法吗？</span></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> _ === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">    <span class="comment">// 现在有个数组 list，它里面有“a、b、c”，3 个变量，如下：</span></span><br><span class="line">    <span class="keyword">const</span> a = &#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;a&#x27;</span>,</span><br><span class="line">      <span class="attr">value</span>: <span class="string">&#x27;a&#x27;</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> b = <span class="string">&#x27;str&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> c = <span class="number">256</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> list = [a, b, c];</span><br><span class="line">    <span class="keyword">const</span> listCopy = list; <span class="comment">// 引用赋值</span></span><br><span class="line">    <span class="keyword">const</span> listDeep = _.<span class="title function_">cloneDeep</span>(list); <span class="comment">// 深拷贝</span></span><br><span class="line">    <span class="keyword">const</span> listClone = _.<span class="title function_">clone</span>(list); <span class="comment">// 浅拷贝</span></span><br><span class="line">    list.<span class="title function_">push</span>(<span class="string">&#x27;d&#x27;</span>); <span class="comment">// list、 listCopy（赋值） 受影响</span></span><br><span class="line">    a.<span class="property">name</span> = <span class="string">&#x27;new a&#x27;</span>; <span class="comment">// list、listClone（浅） 和 listCopy（赋值） 受影响</span></span><br><span class="line">    listClone.<span class="title function_">push</span>(<span class="string">&#x27;e&#x27;</span>); <span class="comment">// listClone（浅）受影响</span></span><br><span class="line">    c = <span class="number">480</span>; <span class="comment">// 都不受影响</span></span><br><span class="line">    listDeep.<span class="title function_">push</span>(<span class="string">&#x27;f&#x27;</span>); <span class="comment">// listDeep（深）受影响</span></span><br><span class="line">    list[<span class="number">0</span>].<span class="property">value</span> = <span class="string">&#x27;new a&#x27;</span>; <span class="comment">// list、listClone（浅） 和 listCopy（赋值） 受影响</span></span><br><span class="line">    list[<span class="number">1</span>] = <span class="string">&#x27;new str&#x27;</span>; <span class="comment">// list、listCopy（赋值） 受影响</span></span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;list&#x27;</span>, list); <span class="comment">// [&#123;name: &quot;new a&quot;, value: &quot;new a&quot;&#125;, &quot;new str&quot;, 256, &quot;d&quot;]</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listCopy&#x27;</span>, listCopy); <span class="comment">// [&#123;name: &quot;new a&quot;, value: &quot;new a&quot;&#125;, &quot;new str&quot;, 256, &quot;d&quot;]</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listDeep&#x27;</span>, listDeep); <span class="comment">// [&#123;name: &quot;a&quot;, value: &quot;a&quot;&#125;, &quot;str&quot;, 256, &quot;f&quot;]</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;listClone&#x27;</span>, listClone); <span class="comment">// [&#123;name: &quot;new a&quot;, value: &quot;new a&quot;&#125;, &quot;str&quot;, 256, &quot;e&quot;]</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;, <span class="number">1000</span>);</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ol><li>浅拷贝得到的数组，其内引用类型的地址为原来的地址，基本类型没有引用地址，等同于深拷贝。即：浅拷贝后数组中的引用类型跟随原数组变化。</li><li>深拷贝得到的数组，引用类型的地址不为原来的地址，即：其每层引用类型的地址都是新的地址，所有数据变化不与原来的关联。</li><li>引用赋值得到的数组，与原来的数组一致，即：list 和 listCopy 指向同一个地址，可以得到原数组的引用地址内的数据变化。</li></ol><h2 id="沙盒开发"><a href="#沙盒开发" class="headerlink" title="沙盒开发"></a>沙盒开发</h2><h3 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h3><p>导入模块<code>vm</code>模块</p><p><a href="https://nodejs.org/api/vm.html">官方文档</a></p><h3 id="主要内容"><a href="#主要内容" class="headerlink" title="主要内容"></a>主要内容</h3><h4 id="上下文"><a href="#上下文" class="headerlink" title="上下文"></a>上下文</h4><p>这个作为沙盒的运行主体（什么都要往里送）</p><p>context</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//把context包装成proxy对象，来捕捉一些操作</span></span><br><span class="line"><span class="keyword">let</span> context = <span class="keyword">new</span> <span class="title class_">Proxy</span>(context, &#123;</span><br><span class="line">    <span class="title function_">set</span>(<span class="params">o, k, v</span>) &#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">set</span>(o, k, v)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">defineProperty</span>: <span class="function">(<span class="params">o, k, d</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (</span><br><span class="line">          <span class="comment">//权限判断</span></span><br><span class="line">        )</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">defineProperty</span>(o, k, d)</span><br><span class="line">        <span class="keyword">else</span> </span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">preventExtensions</span>: <span class="function">(<span class="params">o</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">setPrototypeOf</span>: <span class="function">(<span class="params">o, prototype</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="保护类"><a href="#保护类" class="headerlink" title="保护类"></a>保护类</h4><p>Proxy<br>Object<br>Function<br>Array<br>…</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//冻结内置对象(不包括console,globalThis)</span></span><br><span class="line"><span class="keyword">const</span> internal_properties = [</span><br><span class="line">  <span class="string">&#x27;Object&#x27;</span>,             <span class="string">&#x27;Function&#x27;</span>,       <span class="string">&#x27;Array&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Number&#x27;</span>,             <span class="string">&#x27;parseFloat&#x27;</span>,     <span class="string">&#x27;parseInt&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Boolean&#x27;</span>,            <span class="string">&#x27;String&#x27;</span>,         <span class="string">&#x27;Symbol&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Date&#x27;</span>,               <span class="string">&#x27;RegExp&#x27;</span>,         <span class="string">&#x27;eval&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Error&#x27;</span>,              <span class="string">&#x27;EvalError&#x27;</span>,      <span class="string">&#x27;RangeError&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;ReferenceError&#x27;</span>,     <span class="string">&#x27;SyntaxError&#x27;</span>,    <span class="string">&#x27;TypeError&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;URIError&#x27;</span>,           <span class="string">&#x27;JSON&#x27;</span>,           <span class="string">&#x27;Promise&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Math&#x27;</span>,               <span class="string">&#x27;Intl&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;ArrayBuffer&#x27;</span>,        <span class="string">&#x27;Uint8Array&#x27;</span>,     <span class="string">&#x27;Int8Array&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Uint16Array&#x27;</span>,        <span class="string">&#x27;Int16Array&#x27;</span>,     <span class="string">&#x27;Uint32Array&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Int32Array&#x27;</span>,         <span class="string">&#x27;Float32Array&#x27;</span>,   <span class="string">&#x27;Float64Array&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Uint8ClampedArray&#x27;</span>,  <span class="string">&#x27;BigUint64Array&#x27;</span>, <span class="string">&#x27;BigInt64Array&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;DataView&#x27;</span>,           <span class="string">&#x27;Map&#x27;</span>,            <span class="string">&#x27;BigInt&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Set&#x27;</span>,                <span class="string">&#x27;WeakMap&#x27;</span>,        <span class="string">&#x27;WeakSet&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Proxy&#x27;</span>,              <span class="string">&#x27;Reflect&#x27;</span>,        <span class="string">&#x27;decodeURI&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;decodeURIComponent&#x27;</span>, <span class="string">&#x27;encodeURI&#x27;</span>,      <span class="string">&#x27;encodeURIComponent&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;escape&#x27;</span>,             <span class="string">&#x27;unescape&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;isFinite&#x27;</span>,           <span class="string">&#x27;isNaN&#x27;</span>,          <span class="string">&#x27;SharedArrayBuffer&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;Atomics&#x27;</span>,            <span class="string">&#x27;WebAssembly&#x27;</span></span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> v <span class="keyword">of</span> internal_properties) &#123;</span><br><span class="line">    vm.<span class="title function_">runInContext</span>(<span class="string">`this.Object.freeze(this.<span class="subst">$&#123;v&#125;</span>); this.Object.freeze(this.<span class="subst">$&#123;v&#125;</span>.prototype); const <span class="subst">$&#123;v&#125;</span> = this.<span class="subst">$&#123;v&#125;</span>`</span>, context);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="权限类"><a href="#权限类" class="headerlink" title="权限类"></a>权限类</h4><p>isMaster()</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SANDBOX_ROOT该环境变量为永久master</span></span><br><span class="line">vm.<span class="title function_">runInContext</span>(<span class="string">`Object.defineProperty(this, &quot;root&quot;, &#123;</span></span><br><span class="line"><span class="string">    configurable: false,</span></span><br><span class="line"><span class="string">    enumerable: false,</span></span><br><span class="line"><span class="string">    writable: false,</span></span><br><span class="line"><span class="string">    value: &quot;xxxxxxxx&quot; // 主人的鉴权方式</span></span><br><span class="line"><span class="string">&#125;)`</span>, context);</span><br></pre></td></tr></table></figure><h4 id="输入"><a href="#输入" class="headerlink" title="输入"></a>输入</h4><p>这边是封装了一个exec的函数</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//沙盒执行超时时间</span></span><br><span class="line"><span class="keyword">let</span> timeout = <span class="number">500</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>.<span class="property">getTimeout</span> = <span class="function">(<span class="params">t</span>)=&gt;</span>timeout</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>.<span class="property">setTimeout</span> = <span class="function">(<span class="params">t</span>)=&gt;</span>timeout=t</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>.<span class="property">exec</span> = <span class="function">(<span class="params">code</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> vm.<span class="title function_">runInContext</span>(code, context, &#123;<span class="attr">timeout</span>: timeout&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="输出"><a href="#输出" class="headerlink" title="输出"></a>输出</h4><p>直接用一个<code>try&#123;&#125;</code>包起来，万事大吉</p><h3 id="道高一尺"><a href="#道高一尺" class="headerlink" title="道高一尺"></a>道高一尺</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//防止沙盒逃逸</span></span><br><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">view</span> = <span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span></span><br><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(<span class="title class_">Function</span>, &#123;</span><br><span class="line">    <span class="attr">apply</span>: <span class="function">()=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="title class_">Error</span>(<span class="string">&quot;想跟妾身斗，汝还差得远呢。&quot;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">constructor</span>: <span class="function">()=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="title class_">Error</span>(<span class="string">&quot;想跟妾身斗，汝还差得远呢。&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">freeze</span>(<span class="title class_">Object</span>)</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">freeze</span>(<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>)</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">freeze</span>(<span class="title class_">Function</span>)</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">freeze</span>(<span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;深拷贝和浅拷贝是 JS 基础，很多人（包括我）可能理解两者的区别。&lt;br&gt;还有记录一下近期开发沙盒的过程。&lt;/p&gt;</summary>
    
    
    
    <category term="学习加油站" scheme="https://www.i5res.com/categories/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E7%AB%99/"/>
    
    
    <category term="typescript" scheme="https://www.i5res.com/tags/typescript/"/>
    
    <category term="js" scheme="https://www.i5res.com/tags/js/"/>
    
    <category term="沙箱" scheme="https://www.i5res.com/tags/%E6%B2%99%E7%AE%B1/"/>
    
  </entry>
  
  <entry>
    <title>我的cpp的算法学习笔记</title>
    <link href="https://www.i5res.com/learning-c-programming.html"/>
    <id>https://www.i5res.com/learning-c-programming.html</id>
    <published>2022-09-22T03:55:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>来自大学课程的一封启示。</p><p>在专攻硬件这条路上算是越走越远了啊，硬件会不会要走得更远一点？因为要接触底层，那么更需要学会一些强类型的语言。C，我来了</p><span id="more"></span><blockquote><p>纯属是个人笔记，想到多少写多少，各位看官勿怪。<br>写了一部分以后就没写了，东西很浅，就是入个门。</p></blockquote><h2 id="在一切的最初"><a href="#在一切的最初" class="headerlink" title="在一切的最初"></a>在一切的最初</h2><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20220923120105.png" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20220923120534.png" alt="近距离神魔打架" fancybox="true"/></div><div class="image-meta"><span class="image-caption center">近距离神魔打架</span></div></div><h2 id="言归正传"><a href="#言归正传" class="headerlink" title="言归正传"></a>言归正传</h2><p>编写C++的一些IDE一般有 Dev-Cpp, CLion, Visual Studio</p><p><a href="https://visualstudio.microsoft.com/zh-hans/">Microsoft Visual Studio</a> 应该算是比较熟悉的了，当然不是 <a href="https://code.visualstudio.com/">Visual Studio Code</a>。</p><p>小项目使用 <a href="https://github.com/Embarcadero/Dev-Cpp/">Dev-Cpp</a><br>大项目使用 <a href="https://www.jetbrains.com/clion/">CLion</a></p><p>在学习一门语言的时候我们总是习惯去输出他。</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20220923120737.png" fancybox="true"/></div></div><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">float</span> a,b,c,d,e,f,g;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%f %f %f %f %f %f %f&quot;</span>, &amp;a,&amp;b,&amp;c,&amp;d,&amp;e,&amp;f,&amp;g);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%.2f&quot;</span>,(a+b+c+d+e+f+g)/<span class="number">7</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这其实就是一个简单的均值求法。</p><p>每一个语言都有它的魅力，比如C++，令人难以理解的运算速度是超越其他语言的绝对优势。</p><h2 id="语言经典的循环"><a href="#语言经典的循环" class="headerlink" title="语言经典的循环"></a>语言经典的循环</h2><p>每一个语言必不可少的东西，进阶后就是迭代器，遍历的算法在大型项目中非常常见（结论来自我做过的其他项目）</p><h3 id="for"><a href="#for" class="headerlink" title="for()"></a>for()</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> a;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;a);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>;i &lt; <span class="number">5</span>;i++)&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d&quot;</span>, a);</span><br><span class="line"><span class="keyword">if</span> (i &lt; <span class="number">4</span>) <span class="built_in">printf</span>(<span class="string">&quot; &quot;</span>);</span><br><span class="line">a = <span class="number">2</span> * a + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="求这个分数序列的前n项之和"><a href="#求这个分数序列的前n项之和" class="headerlink" title="求这个分数序列的前n项之和"></a>求这个分数序列的前n项之和</h4><p><strong>题目：有一个分数序列 q1&#x2F;p1,q2&#x2F;p2,q3&#x2F;p3,q4&#x2F;p4,q5&#x2F;p5,…. ,其中qi+1&#x3D; qi+ pi, pi+1&#x3D;qi, p1&#x3D; 1, q1&#x3D; 2。比如这个序列前6项分别是2&#x2F;1,3&#x2F;2,5&#x2F;3,8&#x2F;5,13&#x2F;8,21&#x2F;13。求这个分数序列的前n项之和。</strong></p><p><strong>样例输入</strong><br>2<br><strong>样例输出</strong><br>3.5000</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">float</span> p[<span class="number">100</span>], q[<span class="number">100</span>], s = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;n);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">p[i] = (i &gt; <span class="number">0</span>) ? q[i - <span class="number">1</span>] : <span class="number">1</span>;</span><br><span class="line">q[i] = (i &gt; <span class="number">0</span>) ? p[i - <span class="number">1</span>] + q[i - <span class="number">1</span>] : <span class="number">2</span>;</span><br><span class="line">s += q[i] / p[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%.4f&quot;</span>, s);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="从键盘输入5个数，找出其最大数并输出"><a href="#从键盘输入5个数，找出其最大数并输出" class="headerlink" title="从键盘输入5个数，找出其最大数并输出"></a>从键盘输入5个数，找出其最大数并输出</h4><p><strong>样例输入</strong><br>2 3 4 7 5<br><strong>样例输出</strong><br>7</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">max</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> a &gt; b ? a : b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> m = <span class="number">5</span>, a[m], t = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d %d %d %d %d&quot;</span>, &amp;a[<span class="number">0</span>], &amp;a[<span class="number">1</span>], &amp;a[<span class="number">2</span>], &amp;a[<span class="number">3</span>], &amp;a[<span class="number">4</span>]);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> n = <span class="number">0</span>; n &lt; m; n++) &#123;</span><br><span class="line">t = <span class="built_in">max</span>(a[n], t);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d&quot;</span>, t);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="求n的正整数的阶乘的和"><a href="#求n的正整数的阶乘的和" class="headerlink" title="求n的正整数的阶乘的和"></a>求n的正整数的阶乘的和</h4><p><strong>样例输入</strong><br>5<br><strong>样例输出</strong><br>153</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">long</span> <span class="type">long</span> <span class="type">int</span> n, s = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%lld&quot;</span>, &amp;n);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i++) &#123;</span><br><span class="line"><span class="type">int</span> c = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> v = <span class="number">1</span>; v &lt;= i; v++) &#123;</span><br><span class="line">c *= v;</span><br><span class="line">&#125;</span><br><span class="line">s += c;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%lld&quot;</span>, s);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="绕啊绕绕啊绕绕啊绕"><a href="#绕啊绕绕啊绕绕啊绕" class="headerlink" title="绕啊绕绕啊绕绕啊绕"></a>绕啊绕绕啊绕绕啊绕</h4><p><strong>描述</strong></p><p>请统计某个给定范围[L, R]的所有整数中，数字2出现的次数。<br>比如给定范围[2, 22]，数字2在数2中出现了1次，在数12中出现1次，在数20中出现1次，在数21中出现1次，在数22中出现2次，所以数字2在该范围内一共出现了6次。</p><p><strong>样例输入</strong><br>2 22<br><strong>样例输出</strong><br>6</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">count</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> i;</span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; n &gt; <span class="number">0</span>; n /= <span class="number">10</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (n % <span class="number">10</span> == <span class="number">2</span>) i++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> a, b, c = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d %d&quot;</span>, &amp;a, &amp;b);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = a; i &lt;= b; i++)</span><br><span class="line">&#123;</span><br><span class="line">c += <span class="built_in">count</span>(i);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d&quot;</span>, c);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="你真的懂语法吗？"><a href="#你真的懂语法吗？" class="headerlink" title="你真的懂语法吗？"></a>你真的懂语法吗？</h4><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221105203547.png" fancybox="true" style="width:100%;"/></div></div><h3 id="do-while"><a href="#do-while" class="headerlink" title="do while()"></a>do while()</h3><p>根据条件来循环语句。<br>阶乘相加的算法。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 题目：求1!+2!+3!+4!+…+n!的结果。n！=n*(n-1)*(n-2)*...2*1</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> a;</span><br><span class="line"><span class="keyword">while</span>(<span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;a) != EOF) &#123;</span><br><span class="line"><span class="type">int</span> d = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> b = <span class="number">1</span>; b &lt;= a; b++) &#123;</span><br><span class="line"><span class="type">int</span> e = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> c = <span class="number">1</span>; c &lt;= b; c++) &#123;</span><br><span class="line">e *= c; </span><br><span class="line">&#125;</span><br><span class="line">d += e;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, d);</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="库和包（我习惯的叫法）"><a href="#库和包（我习惯的叫法）" class="headerlink" title="库和包（我习惯的叫法）"></a>库和包（我习惯的叫法）</h2><p>OJ平台上并不允许引用其他的包，所以使用基础方法去解决一些问题的时候会很头疼（平常倒也不用那么死脑筋，有轮子不用是**，不过学习的时候就得好好学）</p><h3 id="math-h-stdio-h-…"><a href="#math-h-stdio-h-…" class="headerlink" title="math.h stdio.h …"></a>math.h stdio.h …</h3><p>在哪里？自动生成在程序目录里面吗？<br>其它库函数标准文件呢？<br>那为什么，生成目录没有这文件、、却可以运行？</p><p>不完全统计，C语言标准库中的头文件有15个之多，所以我主要介绍常用的这四个头文件stdio.h，string.h，math.h，stdlib.h。</p><p>他们都被存放于用户所带的<code>C:\Program Files\Microsoft Visual Studio\VC98\Include</code></p><p>他们各个被定义的方法都不同，已经有很多教材对这些进行了整理。（那么这里就不多做赘述了）</p><h2 id="scanf-有什么特点"><a href="#scanf-有什么特点" class="headerlink" title="scanf()有什么特点"></a>scanf()有什么特点</h2><p>如果要单独拿一个字符（数字）</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> a, b;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%1d%1d&quot;</span>, &amp;a, &amp;b); <span class="comment">// 38</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d和%d&quot;</span>, a, b); <span class="comment">// 3和8</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><p>不同于数学中的函数的是，他将步骤进行分开，主要放大了其中的运行逻辑。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 下面有所体现</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">fn</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="comment">// 这里定义了一个 fn() 函数</span></span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="built_in">fn</span>(); <span class="comment">// 这里调用了fn()</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其中，能看出 <code>void fn()</code> “fn”是函数名， “void”是函数将要返回的类型。</p><blockquote><p>int main(void) 是标准形式，这么写时，结尾要加 return 0; 其实怎么写都可以，主要是看你的编译器。（来自“百度”）</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;来自大学课程的一封启示。&lt;/p&gt;
&lt;p&gt;在专攻硬件这条路上算是越走越远了啊，硬件会不会要走得更远一点？因为要接触底层，那么更需要学会一些强类型的语言。C，我来了&lt;/p&gt;</summary>
    
    
    
    <category term="学习加油站" scheme="https://www.i5res.com/categories/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E7%AB%99/"/>
    
    
    <category term="C++" scheme="https://www.i5res.com/tags/C/"/>
    
    <category term="C语言" scheme="https://www.i5res.com/tags/C%E8%AF%AD%E8%A8%80/"/>
    
  </entry>
  
  <entry>
    <title>都在说这个，那我也来聊聊微信键盘</title>
    <link href="https://www.i5res.com/miscellaneous/wechat-inputer.html"/>
    <id>https://www.i5res.com/miscellaneous/wechat-inputer.html</id>
    <published>2022-09-06T15:51:12.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin colorful note" color="warning"><div class="title"><strong>注意</strong></div><div class="body"><p>发布时间2022-09-06 23:51:12。<br>本文具有一定的时效性。</p></div></div><p>最近「微信键盘」开启了内测，我看到挺多网友讨论的，于是前几天下载下来尝试了一下，今天也来跟大家分享一下使用体验。</p><span id="more"></span><p>首先需要说明的是，我对一个输入法的要求，其实就只有两点：</p><ol><li><p>精准。要能够切实提升我的输入效率，这是一个输入法最核心的竞争力。如果经常打错字，或者无法给出精准的候选词，那我为什么不自己开发一个本地的拼音输入法？</p></li><li><p>隐私。输入法里面，包含了太多的个人信息，身份证号、手机号码，银行卡号，居住地址，基本上所有关于你的信息，输入法都有能力获取到；如果一个输入法不能保护隐私，那么你在任何其他地方做的任何保护隐私的努力都形同虚设。</p></li></ol><p>在开始评测之前，说一下我当前使用的输入法：</p><p>• 电脑上我用的是 macOS 系统自带的双拼输入法，没有额外的词库，只有自己录入的常用的短语（如收货地址，开票信息等）</p><p>• 手机上我使用的是 MIUI 搜狗输入法小米版，使用的是全拼，并且开启了隐私模式。</p><h2 id="核心体验"><a href="#核心体验" class="headerlink" title="核心体验"></a>核心体验</h2><p>有人可能会觉得奇怪，为什么我电脑上要用「双拼」？这完全是因为 macOS 系统自带的拼音输入法与第三方输入法（如搜狗）差距太大了，搜狗的云词库和联想功能不是一般的强大，而系统输入法做不到；为了不依赖这种联想功能，我选择了双拼输入；而手机上由于键位有限，双拼并没有太大的优势，所以没办法用了搜狗。</p><p>说回微信键盘，经过几天的体验，我认为它的输入体验基本上可以满足我个人的要求了。比 macOS 系统自带的拼音输入法要强，但与搜狗相比还是差了点。在使用微信键盘的时候，一天总有那么几次，它没法给出我需要的候选词，或者它有这个候选词，但排列太靠后了。每次出现这种情况，我都有一种挫败感，但使用搜狗却很少出现这个问题；或者说，我在使用搜狗的时候，在它没有给出合适的候选词的绝大多数情况下，我自己内心也会觉得“它确实联想不出来”，而在使用微信键盘的时候，我内心会觉得“你明明可以给出合适的候选词，为什么没有？”</p><p>当然，这也可能与我使用微信键盘的时间还太短了有关，做词语联想，还是需要一定的数据量做训练；不过当前的事实就是：<strong>基本满足需求，还有改进空间。</strong></p><h2 id="隐私"><a href="#隐私" class="headerlink" title="隐私"></a>隐私</h2><p>上面我们提到，输入法<strong>有能力</strong>获取你所有的隐私信息；不过，<strong>能不能</strong>和<strong>做不做</strong>是两码事，很多时候，输入法尊不尊重你的隐私，我们普通人是完全没有保障的。不过，作为一个程序员，我还是有能力对 App 做一些分析。我在 B 站和公众号上看到不少这样的言论：微信键盘的联想功能要联网，**龙肯定把我的输入信息传到服务器了，扯什么隐私？</p><p>接下来，我将从技术角度，比较一下「微信键盘」和「搜狗输入法小米版隐私模式」在隐私方面的不同之处。</p><pre><code>备注：微信键盘版本 0.9.0，搜狗输入法小米版版本 9.5.21.2111192114</code></pre><h3 id="隐私权限"><a href="#隐私权限" class="headerlink" title="隐私权限"></a>隐私权限</h3><p>在 Android 系统上，如果一个 App 要获取某些敏感的信息，必须提前向系统声明相关的权限；比如读取设备ID，获取联系人信息等等。我反编译了微信键盘和搜狗输入法，对比一下二者声明的权限，表格如下：</p><!-- img --><p>通过上面的表格可以看到，微信键盘总共申请了 9 个权限，搜狗输入法申请了 41 个权限；其中比较高危的权限我用红色标记了出来：</p><p>• 访问麦克风；虽然输入法需要这个权限实现语音输入的功能，但理论上这个权限可以实现录音。</p><p>• 获取设备ID；这个权限可以用来实现跟踪功能，可以通过设备ID关联到具体的人，对隐私保护至关重要。</p><p>• 访问sdcard；可以访问到 sdcard 中其他 App 的信息，也可以实现追踪。</p><p>• 读写联系人；虽然这个权限大概是用来输入联系人姓名的，但这样它就能读取你所有联系人信息。</p><p>• 读写短信；虽然这个权限大概是用来输入短信验证码的，但这样它就能读取你的短信。</p><p>• 获取地理位置；想不通输入法要这个权限干什么。</p><p>简单比较我们就能得知，搜狗输入法申请的权限将近微信键盘的 5 倍！！其中一些关键的权限，微信键盘完全都没有获取，**龙说微信键盘要保护隐私，从这个角度来说，他做到了。</p><p>有人会问，百度输入法和讯飞输入法咋样呢？加上百度之后，我27寸显示器，截图截不下了…它申请了 48 项权限，搜狗有的它也基本都有，搜狗没有的它也有！讯飞也好不到哪里去，它申请了 45 项权限。（作为对比，Google 自家的输入法 GBoard 申请了 22 项权限） 可以说，传统的输入法厂商，在权限申请方面，都是半斤八两，而微信键盘在他们面前，绝对是一股清流！！</p><h3 id="用户跟踪"><a href="#用户跟踪" class="headerlink" title="用户跟踪"></a>用户跟踪</h3><p>我们经常会发现，跟某人聊天提到了某个东西，淘宝上就会出现相关的广告。曾经有这样一个梗：上一秒在微信上打完笑死了，下一秒打开淘宝已经给我推荐棺材。</p><p>对用户隐私来说，有一点其实也很重要，那就是<strong>防止追踪</strong>。很多时候，App 不可避免地会获取到我们很多信息，除了输入法之外，比如购物 App 能获取你的订单信息、地址等，再比如绝大部分 App 可能要收集崩溃日志来改进程序；只要<strong>保证 App 获取的是匿名信息，它们能做的事就非常有限</strong>。在我们的信息不可避免地要被获取的情况下，退而求其次，<strong>防止被追踪</strong>也是非常有效的办法。</p><p>如果某个 App 可以获取我们的隐私信息，但它没有办法把这个信息传递给别人，那么它能做的事就非常有限；毕竟，如果一个输入法给自己加一个淘宝商城，用户八成是要把它卸载。</p><p>在设备跟踪方面，最常见的方法就是：imei &#x2F; android_id &#x2F; oaid &#x2F; 自己生成 id 放 sdcard；继续反编译微信键盘和搜狗输入法：</p><!-- img --><p>如果某个 App 可以获取我们的隐私信息，但它没有办法把这个信息传递给别人，那么它能做的事就非常有限；毕竟，如果一个输入法给自己加一个淘宝商城，用户八成是要把它卸载。</p><p>在设备跟踪方面，最常见的方法就是：imei &#x2F; android_id &#x2F; oaid &#x2F; 自己生成 id 放 sdcard；继续反编译微信键盘和搜狗输入法：</p><!-- img --><p>说实话看到这个结果我是非常震惊的，在获取用户 ID 方面，微信键盘竟然全都是 0！反观百度输入法，为了跟踪用户简直无所不用其及，在 &#x2F;sdcard 不同地方竟然存了四份！！</p><p>另外，在反编译微信键盘的时候，我意外发现如下代码：</p><!-- img --><p>这个键盘使用了一个叫 qimei 的 SDK，它刻意把 imei &#x2F; imsi &#x2F; android_id &#x2F; mac addr &#x2F; process info 给禁用了！</p><p>当然，这个结果也没有办法完全保证微信键盘没有跟踪用户，它至少还有这些方法：</p><ol><li><p>直接与微信交互获取用户信息；毕竟微信人手一份，微信键盘要是要跟踪用户，没必要用上面那些手段；这一点是怀疑，无证据。</p></li><li><p>通过 JNI 的方式在 native 层获取 device_id &#x2F; imei &#x2F; android_id 等信息；这也是有可能的，不过这需要动态分析，暂时没有精力去处理。</p></li></ol><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>我看到有不少人调侃微信“小而美”，微信键盘安装包 150M，安装完毕后占用空间 780M，因为空间占用比较大而说它不好，就像是说鲁迅普通话不标准进而认为他的文章都是垃圾一样。对我来说，存储空间占用是最最廉价的属性了，原神占用我手机 20G，丝毫不影响我认为它是目前最好玩的手机游戏。</p><p>有一说一，微信键盘安装包约 150M，里面 80% 的空间存放的是它的本地词库！！</p><p>我不清楚微信键盘为何要放这么大一个词库在安装包里面，不过，如果它将来出一个功能，可以不联网使用，仅使用本地词库，一定会是一个杀手锏。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li><p>微信键盘界面简洁，核心输入功能可以满足需求，不过还有改进空间。</p></li><li><p>隐私保护方面吊打其他巨头同行，只有某些开源输入法可以媲美。</p></li><li><p>毕竟还是 beta 版，某些臃肿的功能还没有时间开发，将来会不会搞得花里胡哨犹未可知。</p></li></ol><p>总的来说，这款键盘非常值得体验。</p><p>如果微信键盘现在停止开发，或者后续加入了各种权限和隐私跟踪功能，我将永远停留在此版本，用到 Android 系统倒闭。</p><h2 id="新报"><a href="#新报" class="headerlink" title="新报"></a>新报</h2><p>现在是 <strong>2022年10月31日</strong> 我使用微信键盘已经有2个月了，再来说说各人看法。</p><p>精简依旧，词库的缓存回收好像也做好了，除了 <em>语音输入</em> <em>剪切板</em> 几乎无可挑剔。</p><h2 id="Window版本的输入法更新咯！"><a href="#Window版本的输入法更新咯！" class="headerlink" title="Window版本的输入法更新咯！"></a>Window版本的输入法更新咯！</h2><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/cc9cccd006fd92b03ea16b63ec567914.png" fancybox="true"/></div></div><p>这个是展现在我的状态栏中，其次是简约的风格：</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231205234541.png" fancybox="true"/></div></div><p>我是真的太喜欢了，vocal！</p><p>kan’kan’zhe’g’da’zi’feng’ge 看看这个打字风格</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/PluginsKers/cdn/2023/20231205234615.png" fancybox="true"/></div></div><p>能和手机端联动的进行剪切板同步！</p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin colorful note&quot; color=&quot;warning&quot;&gt;&lt;div class=&quot;title&quot;&gt;&lt;strong&gt;注意&lt;/strong&gt;&lt;/div&gt;&lt;div class=&quot;body&quot;&gt;&lt;p&gt;发布时间2022-09-06 23:51:12。&lt;br&gt;本文具有一定的时效性。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最近「微信键盘」开启了内测，我看到挺多网友讨论的，于是前几天下载下来尝试了一下，今天也来跟大家分享一下使用体验。&lt;/p&gt;</summary>
    
    
    
    <category term="表白与谈说" scheme="https://www.i5res.com/categories/%E8%A1%A8%E7%99%BD%E4%B8%8E%E8%B0%88%E8%AF%B4/"/>
    
    
    <category term="杂谈" scheme="https://www.i5res.com/tags/%E6%9D%82%E8%B0%88/"/>
    
  </entry>
  
  <entry>
    <title>有关于QQWeb API 收集列表的笔记</title>
    <link href="https://www.i5res.com/notes/utilizing-qq-web-api.html"/>
    <id>https://www.i5res.com/notes/utilizing-qq-web-api.html</id>
    <published>2022-08-24T12:06:13.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><h2 id="QQ-Web-Api-收集"><a href="#QQ-Web-Api-收集" class="headerlink" title="QQ Web Api 收集"></a>QQ Web Api 收集</h2><p>web api 是需要 cookie 或 csrf-token(bkn) 才可正常访问<span id="more"></span>，用于实现一些扩展功能的 api<br>如果你知道一些尚未收集到的有用api，欢迎提交pr到这个文件</p><hr><table><thead><tr><th>Name</th><th>Method</th><th>Url</th><th>Cookie</th><th>Domain</th></tr></thead><tbody><tr><td>取QQ等级</td><td>GET</td><td><code>https://club.vip.qq.com/api/vip/getQQLevelInfo?requestBody=&#123;&quot;iUin&quot;:$&#123;QQ号&#125;&#125;</code></td><td>YES</td><td><code>vip.qq.com</code></td></tr><tr><td>取群资料</td><td>GET</td><td><code>https://qinfo.clt.qq.com/cgi-bin/qun_info/get_group_info_all?gc=$&#123;群号&#125;&amp;bkn=$&#123;bkn&#125;</code><br><em>※陌生群也可以获取</em></td><td>YES</td><td>空</td></tr><tr><td>取群设置</td><td>GET</td><td><code>https://qinfo.clt.qq.com/cgi-bin/qun_info/get_group_setting_v2?gc=$&#123;群号&#125;&amp;bkn=$&#123;bkn&#125;</code><br><em>※必须是群员</em></td><td>YES</td><td>空</td></tr><tr><td>取群成员</td><td>GET</td><td><code>https://qinfo.clt.qq.com/cgi-bin/qun_info/get_group_members_new?gc=$&#123;群号&#125;&amp;bkn=$&#123;bkn&#125;</code><br><em>※必须是群员</em></td><td>YES</td><td>空</td></tr><tr><td>取群操作记录</td><td>GET</td><td><code>https://qinfo.clt.qq.com/cgi-bin/qun_info/get_sys_msg?gc=$&#123;群号&#125;&amp;bkn=$&#123;bkn&#125;</code><br><em>※必须是管理员</em></td><td>YES</td><td>空</td></tr><tr><td>取QQ资料</td><td>GET</td><td><code>https://cgi.find.qq.com/qqfind/buddy/search_v3?keyword=$&#123;QQ号&#125;</code></td><td>YES</td><td>空</td></tr><tr><td>开关匿名</td><td>GET</td><td><code>https://qqweb.qq.com/c/anonymoustalk/set_anony_switch?bkn=$&#123;bkn&#125;&amp;value=$&#123;1或0&#125;&amp;group_code=$&#123;群号&#125;</code></td><td>YES</td><td><code>qqweb.qq.com</code></td></tr><tr><td>取群荣誉</td><td>GET</td><td><code>https://qun.qq.com/interactive/qunhonor?gc=$&#123;群号&#125;</code></td><td>YES</td><td><code>qun.qq.com</code></td></tr><tr><td>精华消息</td><td>GET</td><td><code>https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=$&#123;bkn&#125;&amp;group_code=$&#123;群号&#125;&amp;page_start=$&#123;页数&#125;&amp;page_limit=$&#123;每页数量&#125;</code><br><em>※必须是群成员，每页的数量不能超过50</em></td><td>YES</td><td><code>qun.qq.com</code></td></tr><tr><td>取群公告</td><td>GET</td><td><code>https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=$&#123;bkn&#125;&amp;qid=$&#123;群号&#125;&amp;ft=23&amp;s=-1&amp;n=20</code></td><td>YES</td><td><code>qun.qq.com</code></td></tr><tr><td>发群公告</td><td>POST</td><td><code>https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=$&#123;bkn&#125;</code><br>POST数据：<code>qid=$&#123;群号&#125;&amp;bkn=$&#123;bkn&#125;&amp;text=$&#123;内容&#125;&amp;pinned=0&amp;type=1&amp;settings=&#123;&quot;is_show_edit_card&quot;:1,&quot;tip_window_type&quot;:1,&quot;confirm_required&quot;:1&#125;</code></td><td>YES</td><td><code>qun.qq.com</code></td></tr><tr><td>取群成员</td><td>GET</td><td><code>https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?gc=$&#123;群号&#125;&amp;st=$&#123;0&#125;%end=$&#123;20&#125;&amp;sort=0&amp;bkn=$&#123;bkn&#125;</code></td><td>YES</td><td><code>qun.qq.com</code></td></tr><tr><td>取群头像</td><td>GET</td><td><code>https://p.qlogo.cn/gh/$&#123;群号&#125;/$&#123;群号&#125;/$&#123;0(size)&#125;</code></td><td>NO</td><td></td></tr><tr><td>取群历史头像</td><td>GET</td><td><code>https://p.qlogo.cn/gh/$&#123;群号&#125;/$&#123;群号&#125;_$&#123;1&#125;/$&#123;0(size)&#125;</code></td><td>NO</td><td></td></tr><tr><td>取QQ头像</td><td>GET</td><td><code>https://q1.qlogo.cn/g?b=qq&amp;s=$&#123;0(size)&#125;&amp;nk=$&#123;QQ号&#125;</code></td><td>NO</td><td></td></tr><tr><td>换群头像</td><td>POST</td><td><code>http://htdata3.qq.com/cgi-bin/httpconn?htcmd=0x6ff0072&amp;ver=5520&amp;ukey=$&#123;client.sig.skey&#125;&amp;range=0&amp;uin=$&#123;client.uin&#125;&amp;seq=1&amp;groupuin=$&#123;群号&#125;&amp;filetype=3&amp;imagetype=5&amp;userdata=0&amp;subcmd=1&amp;subver=101&amp;clip=0_0_0_0&amp;filesize=$&#123;字节数&#125;</code><br>POST数据：图片字节集</td><td>NO</td><td></td></tr><tr><td>取资料(both)</td><td>POST</td><td><code>https://find.qq.com/proxy/domain/cgi.find.qq.com/qqfind/find_v11?backver=2</code><br><em>※搜索QQ号和群号 且有个性签名等更多信息</em><br>POST数据：<code>bnum=15&amp;pagesize=15&amp;id=0&amp;sid=0&amp;page=0&amp;pageindex=0&amp;ext=&amp;guagua=1&amp;gnum=12&amp;guaguan=2&amp;type=2&amp;ver=4903&amp;longitude=116.405285&amp;latitude=39.904989&amp;lbs_addr_country=%E4%B8%AD%E5%9B%BD&amp;lbs_addr_province=%E5%8C%97%E4%BA%AC&amp;lbs_addr_city=%E5%8C%97%E4%BA%AC%E5%B8%82&amp;keyword=$&#123;QQ号&#125;&amp;nf=0&amp;of=0&amp;ldw=$&#123;bkn&#125;</code></td><td>YES</td><td>空</td></tr></tbody></table>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;QQ-Web-Api-收集&quot;&gt;&lt;a href=&quot;#QQ-Web-Api-收集&quot; class=&quot;headerlink&quot; title=&quot;QQ Web Api 收集&quot;&gt;&lt;/a&gt;QQ Web Api 收集&lt;/h2&gt;&lt;p&gt;web api 是需要 cookie 或 csrf-token(bkn) 才可正常访问</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="api" scheme="https://www.i5res.com/tags/api/"/>
    
    <category term="qq" scheme="https://www.i5res.com/tags/qq/"/>
    
  </entry>
  
  <entry>
    <title>Vue实现的新拟态设计亲戚关系计算器</title>
    <link href="https://www.i5res.com/projects/kinship-calculator-proj.html"/>
    <id>https://www.i5res.com/projects/kinship-calculator-proj.html</id>
    <published>2022-08-19T10:47:13.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin img-wrap"><div class="frame-wrap" id="iphone11"focus="top"><img class="img" src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221027101622.png"/><div class="frame"></div></div></div><h2 id="项目介绍"><a href="#项目介绍" class="headerlink" title="项目介绍"></a>项目介绍</h2><p>它，只是一个计算器。但是，使用了新拟态的样式设计。</p><p>它能用来做什么？逢年过节遇到三姑六婆，拒绝叫不出口的尴尬！轻松搞定亲戚关系～</p><span id="more"></span><p>由于工作生活节奏不同，如今很多关系稍疏远的亲戚之间来往并不多。因此放假回家过年时，往往会搞不清楚哪位亲戚应该喊什么称呼，很是尴尬。然而搞不清亲戚关系和亲戚称谓的不仅是小孩，就连年轻一代的大人也都常常模糊混乱。</p><p>主要是？轻量！轻量！还是轻量。</p><h2 id="链接地址"><a href="#链接地址" class="headerlink" title="链接地址"></a>链接地址</h2><p><a href="https://kinship.i5res.com/">https://kinship.i5res.com/</a></p><p>亲属是基于婚姻、血缘和法律拟制而形成的社会关系。亲属关系包括夫妻、父母、子女、兄弟姊妹、祖父母和外祖父母、孙子女和外孙子女、儿媳和公婆、女婿和岳父母、以及其他三代以内的旁系血亲，如伯、叔、姑、舅、姨、侄子女、甥子女、堂兄弟姊妹、表兄弟姊妹等。</p><p>亲属称谓指是以本人为中心确定亲族成员和本人关系的名称，是基于血亲姻亲基础上的亲属之间相互称呼的名称、叫法。汉族的家族亲属关系条理分明尊卑有序：比自己长一辈的称呼有姨姑舅叔伯，同辈的有兄弟姊妹、堂表亲等等，下一辈有甥侄等等。中国人由于姻亲而产生的亲戚关系相当庞杂，“祖宗十八代”、“五服”、“六亲”、“九族”让人难以区分，其派生出的各种称谓也是中华文化的一大特征。</p><p>如今由于工作生活节奏差异，很多关系稍疏远的亲戚之间来往并不多，年龄差异长幼辈分模糊。春节拜年走亲戚遇到七大姑八大姨，往往会搞不清楚哪位亲戚应该喊什么称呼，很是尴尬。不仅小孩搞不清亲戚关系和亲戚称&gt;谓，就连年轻一代的大人也都常常模糊混乱。</p><p>“中国亲戚关系计算器”为你避免了叫错、不会叫亲戚的尴尬，收录了中国亲戚关系称呼大全，只需简单的输入即可完成称呼计算。称呼计算器同时兼容了不同地域的方言叫法，你可以称呼父亲为：“老爸”、“爹地”、“老爷&gt;子”等等。让您准确的叫出亲戚称谓，理清亲属之间的亲戚关系，轻松掌握中国式的亲戚关系换算，让你更了解中国文化。</p><h2 id="算法开源"><a href="#算法开源" class="headerlink" title="算法开源"></a>算法开源</h2><p>感谢<mark class="tag-plugin colorful mark" color="dark">mumuy</mark>大佬的项目！</p><div class="tag-plugin ghcard"><a class="ghcard" rel="external nofollow noopener noreferrer" href="https://github.com/mumuy/relationship"><img src="https://github-readme-stats.xaoxuu.com/api/pin/?username=mumuy&repo=relationship&&show_owner=true"/></a></div><p>本项目致力于让更多人了解中国传统文化，学习各式各样的中国亲戚称谓。本人深感项目的完善仅凭一己之力是远远不够的，如果你对此感兴趣，欢迎关注本项目。你也可以通过本项目提供的方法和教程，打造更符合自己使用习惯的亲戚计算器版本。</p><p>算法基于「MIT许可协议」开源，除需在源码中保留版权信息和许可声明外，你有权利使用、复制、修改、合并、出版发行、散布、再授权及贩售软件及软件的副本。算法持续更新中，如发现错漏或有想法建议可在此 <a href="https://github.com/mumuy/relationship/issues">反馈问题</a>。</p><h2 id="算法实现"><a href="#算法实现" class="headerlink" title="算法实现"></a>算法实现</h2><h3 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h3><p>市面上同类型的算法基本以 “称谓-直接关系-称谓” 的方式实现，如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&quot;爸爸&quot;: &#123;</span><br><span class="line">    &quot;爸爸&quot;: &quot;爷爷&quot;,</span><br><span class="line">    &quot;妈妈&quot;: &quot;奶奶&quot;,</span><br><span class="line">    &quot;哥哥&quot;: &quot;伯父&quot;,</span><br><span class="line">    &quot;弟弟&quot;: &quot;叔叔&quot;,</span><br><span class="line">    &quot;姐姐&quot;: &quot;姑妈&quot;,</span><br><span class="line">    &quot;妹妹&quot;: &quot;姑妈&quot;,</span><br><span class="line">    &quot;丈夫&quot;: &quot;未知&quot;,</span><br><span class="line">    &quot;妻子&quot;: &quot;妈妈&quot;,</span><br><span class="line">    &quot;儿子&quot;: &#123;&quot;older&quot;: &quot;哥哥&quot;, &#x27;middle&#x27;: &quot;我&quot;, &quot;younger&quot;: &quot;弟弟&quot;&#125;,</span><br><span class="line">    &quot;女儿&quot;: &#123;&quot;older&quot;: &quot;姐姐&quot;, &#x27;middle&#x27;: &quot;我&quot;, &quot;younger&quot;: &quot;妹妹&quot;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这样的结构主要有以下问题：</p><ol><li>无法跨代直接查询，如：如何知道“舅妈的婆婆”是谁？</li><li>无法逆向查询称谓，如：“表哥的妈妈”的妈妈是“舅妈”、“姨妈”还是“姑妈”</li><li>数据结构过于臃肿, 如：某个节点下可能会出现多个“未知”</li><li>无法兼容多种称呼，如：各地称呼不尽相同，“爸爸”也可以叫“父亲”、“爹地”</li><li>无法进行关系拓扑，如：“舅妈”和我什么关系？</li></ol><h3 id="本算法的原理"><a href="#本算法的原理" class="headerlink" title="本算法的原理"></a>本算法的原理</h3><p>采用 “关系链-称谓集合” 哈希对的方式建立数据库，映射亲戚网络中的每个节点和自己的关系</p><h4 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#x27;h&#x27;:[&#x27;老公&#x27;,&#x27;丈夫&#x27;,&#x27;先生&#x27;,&#x27;官人&#x27;,&#x27;男人&#x27;,&#x27;汉子&#x27;,&#x27;夫&#x27;,&#x27;夫君&#x27;,&#x27;相公&#x27;,&#x27;夫婿&#x27;,&#x27;爱人&#x27;,&#x27;老伴&#x27;],</span><br><span class="line">&#x27;h,f&#x27;:[&#x27;公公&#x27;,&#x27;翁亲&#x27;,&#x27;老公公&#x27;],</span><br></pre></td></tr></table></figure><p>每个称谓都可以找到相应的关系链，每个关系链同时有对应的称谓集合，这里需要引入自己“发明”的特殊语法标记</p><h4 id="语法说明"><a href="#语法说明" class="headerlink" title="语法说明"></a>语法说明</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">【关系】f:父,m:母,h:夫,w:妻,s:子,d:女,xb:兄弟,ob:兄,lb:弟,xs:姐妹,os:姐,ls:妹</span><br><span class="line">【修饰符】 1:男性,0:女性,&amp;o:年长,&amp;l:年幼,#:隔断,[a|b]:并列</span><br></pre></td></tr></table></figure><p>例如：</p><p>“f”对应着爸爸，那么：”f,m”对应着奶奶,”f,f”对应着爷爷；</p><p>这样在查询关系的时候，只需要对关系链进行计算就好了，而不是对称谓进行字典查找</p><h4 id="算法思路"><a href="#算法思路" class="headerlink" title="算法思路"></a>算法思路</h4><ol><li><p>当用户输入“舅妈的婆婆”，可以分解出两个对象“舅妈”和“婆婆”（前者的婆婆）</p></li><li><p>从“关系链-称谓集合”映射关系可知，这两个对象的关系链分别是：”m,xb,w”和”h,m”,合并后的关系即：”m,xb,w,h,m”</p></li><li><p>此时关系链会出现冗余，需要进一步处理：</p><ul><li><p>“w,h”表示“老婆的老公”，即自己，可直接将关系链简化成：”m,xb,m”</p></li><li><p>同理，”xb,m”表示“兄弟的妈妈”，即自己的妈妈，可将关系链再次简化为：”m,m”</p></li><li><p>当无法进一步简化时，就得到了“最简关系链”，将其带入亲戚关系数据库查询，便可知”m,m”即为自己的“奶奶”</p></li></ul></li><li><p>这样就将复杂的关系链转换成直接关系了，除此之外还可根据“关系链-称谓集合”反向通过称呼找到关系；</p></li></ol><h4 id="实现细节"><a href="#实现细节" class="headerlink" title="实现细节"></a>实现细节</h4><p>如何实现关系链的简化？</p><p>关系链为字符串，用正则表达式即可按情形匹配，同时做到“替换”的操作。由于所有非直接的关系，都是存在关系链表达的冗余。虽然冗余可能多层且复杂，只需要考虑两层关系中的去冗余，反复处理即可。</p><p>某些多层关系可能未必对应一种关系，如何解决关系的不唯一？</p><p>“爸爸的儿子”不一定是自己，也可能是自己的兄弟。在语法中引入了“隔断”和“并列”语法，可以借助正则表达式将此类不唯一的关系拆分为多组，每次再单独带入递归求最简解即可。</p><p>每个节点离自己远一层关系，节点数据便翻倍，如何解决数据量过大的问题？</p><p>中国的亲戚关系存在一定规律，旁系分支大体由 分支节点 及其 子代关系 ，我们只需记录 分支节点 和 子代关系 即可。如：“舅表哥”和“堂哥”两者在和自己的关系链上存在一定相似，没必要记录两者所有关系。只需知道“舅表哥”是“舅舅”的后代，而“堂哥”是“叔伯”的后代，那么“舅表哥”和“堂哥”的所有后代及姻亲数据可以只存3部分。即：</p><p>舅表哥关系数据 &#x3D; 舅舅（分支节点） + 哥哥关系数据（子代关系）；</p><p>堂哥关系数据 &#x3D; 叔伯（分支节点） + 哥哥关系数据（子代关系）；</p><p>这样的关系有很多，如：“舅表”、“姑表”、“从堂”、“姑表叔表”等等，对关系数据进行拆分复用，即可以达到压缩数据量。同时在脚本运行中对 分支节点 和 子代关系 进行拼接即可组合出数据库。</p><h2 id="关于其他"><a href="#关于其他" class="headerlink" title="关于其他"></a>关于其他</h2><p>他们都在用：</p><p>查询网 <a href="http://www.ip138.com/chengwei/">http://www.ip138.com/chengwei/</a><br>在线查询网 <a href="http://qinshu.supfree.net/">http://qinshu.supfree.net/</a><br>在线工具 <a href="http://www.atool.org/relateship.php">http://www.atool.org/relateship.php</a><br>有道语文达人 <a href="http://dict.youdao.com/k12yuwen/html/relation.html">http://dict.youdao.com/k12yuwen/html/relation.html</a><br>小米MIUI系统计算器 <a href="http://www.miui.com/">http://www.miui.com/</a><br>小米MIUI网页版本 <a href="http://www.miui.com/zt/calculator2016/dist.php">http://www.miui.com/zt/calculator2016/dist.php</a><br>符号库 <a href="http://www.fuhaoku.com/tool/qinqiguanxi.html">http://www.fuhaoku.com/tool/qinqiguanxi.html</a></p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin img-wrap&quot;&gt;&lt;div class=&quot;frame-wrap&quot; id=&quot;iphone11&quot;focus=&quot;top&quot;&gt;&lt;img class=&quot;img&quot; src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221027101622.png&quot;/&gt;&lt;div class=&quot;frame&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;项目介绍&quot;&gt;&lt;a href=&quot;#项目介绍&quot; class=&quot;headerlink&quot; title=&quot;项目介绍&quot;&gt;&lt;/a&gt;项目介绍&lt;/h2&gt;&lt;p&gt;它，只是一个计算器。但是，使用了新拟态的样式设计。&lt;/p&gt;
&lt;p&gt;它能用来做什么？逢年过节遇到三姑六婆，拒绝叫不出口的尴尬！轻松搞定亲戚关系～&lt;/p&gt;</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="Neumorphism" scheme="https://www.i5res.com/tags/Neumorphism/"/>
    
  </entry>
  
  <entry>
    <title>Xposed 新时代要来了，project mainline</title>
    <link href="https://www.i5res.com/miscellaneous/guide-to-android-xposed.html"/>
    <id>https://www.i5res.com/miscellaneous/guide-to-android-xposed.html</id>
    <published>2022-08-18T11:43:13.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>我们知道，原版Xposed框架(rovo89写的那个)</p><span id="more"></span><p>在ART运行时上的实现方式是，用AOSP的代码，将ART部分进行魔改加入xposed方法的执行逻辑。<br>这种方法技术上行得通的原因在于Android系统对libartso的要求就是实现三个方法(主要是JNICreateJavaVM)。<br>然而，原版Xposed框架在80系统难产在90停更，技术上很大的原因在于ART越来越复杂，不仅要修改libart.so还要改dex2oatlibjit-compiler.so等一堆东西…导致维护起来基本上就失控了。<br>但ARTapex的出现似乎让这玩意出现了转机。<br>Google 在 Android 10 上引入了 project mainline 很多模块都独立成了可单独安装的apex，其中就包含runtime，Android 11更进一步，ART被完全独立了。<br>因此，原版Xposed的那种，用AOSP魔改一个ART来替换官方ART似乎又成为了一个非常好的选择，<br>因为，安装一个apex就和安装一个apk一样简单!</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;我们知道，原版Xposed框架(rovo89写的那个)&lt;/p&gt;</summary>
    
    
    
    <category term="学习加油站" scheme="https://www.i5res.com/categories/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E7%AB%99/"/>
    
    
    <category term="android" scheme="https://www.i5res.com/tags/android/"/>
    
    <category term="xposed" scheme="https://www.i5res.com/tags/xposed/"/>
    
  </entry>
  
  <entry>
    <title>不会鉴权不行啊，通过Github理解鉴权</title>
    <link href="https://www.i5res.com/understanding-github-authentication.html"/>
    <id>https://www.i5res.com/understanding-github-authentication.html</id>
    <published>2022-07-19T10:49:53.000Z</published>
    <updated>2023-12-14T12:44:33.327Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>因为最近的一些需求，我不得不对鉴权反复翻检。如是</p><span id="more"></span><p>我通过了一些简单的例子对OAuth全面理解。其实并不高深，大约10分钟，就可以完全理解它。</p><h2 id="OAuth-2-0"><a href="#OAuth-2-0" class="headerlink" title="OAuth 2.0"></a>OAuth 2.0</h2><h3 id="注册Github-OAuth"><a href="#注册Github-OAuth" class="headerlink" title="注册Github OAuth"></a>注册Github OAuth</h3><p>最后如图</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202207191854244.png" fancybox="true"/></div></div><h3 id="初步握手，获取Code"><a href="#初步握手，获取Code" class="headerlink" title="初步握手，获取Code"></a>初步握手，获取Code</h3><h3 id="接口地址"><a href="#接口地址" class="headerlink" title="接口地址"></a>接口地址</h3><p><code>https://github.com/login/oauth/authorize</code></p><h4 id="请求参数"><a href="#请求参数" class="headerlink" title="请求参数"></a>请求参数</h4><table><thead><tr><th>参数</th><th>描述</th></tr></thead><tbody><tr><td>client_id</td><td>如上图所示，他是鉴别OAuth的</td></tr><tr><td>state</td><td>状态标识，面向第三方，可自定义</td></tr><tr><td>redirect_uri</td><td>回调地址，需要和Github中填写的一致</td></tr></tbody></table><h4 id="最后拼接"><a href="#最后拼接" class="headerlink" title="最后拼接"></a>最后拼接</h4><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_16" value="https://github.com/login/oauth/authorize?client_id=937bcc8fee696da4dde7&state=1&redirect_uri=https://img.i5res.com/#/login"><button class="copy-btn" onclick="util.copy(&quot;copy_16&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><h3 id="请求后他能给我些什么？"><a href="#请求后他能给我些什么？" class="headerlink" title="请求后他能给我些什么？"></a>请求后他能给我些什么？</h3><p><code>?code=0dbc9506a2a4a0c1a1c9&amp;state=1</code></p><h3 id="请求鉴权回调返回access-token"><a href="#请求鉴权回调返回access-token" class="headerlink" title="请求鉴权回调返回access_token"></a>请求鉴权回调返回access_token</h3><h4 id="接口地址-1"><a href="#接口地址-1" class="headerlink" title="接口地址"></a>接口地址</h4><p><code>https://github.com/login/oauth/access_token</code></p><h4 id="请求参数-1"><a href="#请求参数-1" class="headerlink" title="请求参数"></a>请求参数</h4><table><thead><tr><th>参数</th><th>描述</th></tr></thead><tbody><tr><td>client_id</td><td>如上图所示，他是鉴别OAuth的</td></tr><tr><td>client_secret</td><td>如上图所示，OAuth的秘钥（高密）</td></tr><tr><td>code</td><td>回调的用户鉴别</td></tr><tr><td>redirect_uri</td><td>回调地址</td></tr></tbody></table><h4 id="最后拼接-1"><a href="#最后拼接-1" class="headerlink" title="最后拼接"></a>最后拼接</h4><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_17" value="https://github.com/login/oauth/access_token?client_id=937bcc8fee696da4dde7&client_secret=63b41a1c278b37f348c956785e7d6d1fbc2084d9&code=4f9968079245b9ddbb8a&redirect_uri=https://img.i5res.com/#/login"><button class="copy-btn" onclick="util.copy(&quot;copy_17&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><h4 id="请求后返回？"><a href="#请求后返回？" class="headerlink" title="请求后返回？"></a>请求后返回？</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&#123;    </span><br><span class="line">  &quot;access_token&quot;:&quot;ACCESS_TOKEN&quot;,</span><br><span class="line">  &quot;token_type&quot;:&quot;bearer&quot;,</span><br><span class="line">  &quot;expires_in&quot;:2592000,</span><br><span class="line">  &quot;refresh_token&quot;:&quot;REFRESH_TOKEN&quot;,</span><br><span class="line">  &quot;scope&quot;:&quot;read&quot;,</span><br><span class="line">  &quot;uid&quot;:100101,</span><br><span class="line">  &quot;info&quot;:&#123;...&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="使用Github的RSET-API进行操作"><a href="#使用Github的RSET-API进行操作" class="headerlink" title="使用Github的RSET API进行操作"></a>使用Github的RSET API进行操作</h3><p>具体参见: <a href="https://docs.github.com/en/rest">GitHub’s rest API documentation</a></p><div class="tag-plugin colorful note" color="yellow"><div class="title"><strong>注意一下</strong></div><div class="body"><p><a href="https://github.com/login/oauth/access_token">https://github.com/login/oauth/access_token</a><br>这两个都建议使用<code>GET</code>请求，也可以使用<code>POST</code><br><a href="https://api.github.com/user">https://api.github.com/user</a><br>需要使用HTTP模拟的<code>GET</code>请求！</p></div></div><h3 id="OAuth的持续发展"><a href="#OAuth的持续发展" class="headerlink" title="OAuth的持续发展"></a>OAuth的持续发展</h3><h4 id="是什么"><a href="#是什么" class="headerlink" title="是什么"></a>是什么</h4><p><a href="https://blog.csdn.net/a595077052/article/details/118996218">https://blog.csdn.net/a595077052/article/details/118996218</a></p><p>OAuth 2.0 是一种开放协议。<br>OAuth 2.0 的标准是 RFC 6749 文件。</p><p>举例：我们都在网站或者手机应用中见过 “谷歌登陆” 和 “绑定 Facebook“ 这样的按钮。如果你点击这个按钮，就会有一个窗口弹出并显示“这个应用想要访问你的公共个人主页、通讯录……“，同时它会询问你是否授权。概括而言，这就是 OAuth</p><p>如今过半数的APP都使用到了这一鉴权方式，他相比对OAuth 1.0的安全性有大幅度提升</p><h4 id="发展历程"><a href="#发展历程" class="headerlink" title="发展历程"></a>发展历程</h4><ul><li>2007年发布了OAuthCore 1.0：此版本的协议存在严重的安全漏洞</li><li>2009年6月发布了OAuthCore 1.0 Revision A：修复了前一版本的安全漏洞，并成为RFC5849</li><li>2010年4月发布了OAuth2.0，是OAuth协议的下一版本，但与OAuth 1.0版本互不兼容。</li></ul><p>所以我们现在可以只关注 OAuth2.0</p><p><a href="https://oauth.net/">OAuth core docs: https://oauth.net/</a></p><h2 id="单点登录"><a href="#单点登录" class="headerlink" title="单点登录"></a>单点登录</h2><p>开源项目<a href="https://jwt.io/">jwt</a>有简单的描述。</p><p>很简单的剖析一下，</p><p>一、假设你有很多服务器（集群），你需要一个所有集群都认可的鉴权。</p><p>二、你需要携带这份密钥行进在各页面之间。</p><p>如果解决这两大问题，那么就可以实现了。</p><p><strong>jwt</strong>是目前很多公司的解决方案（包括我的学校）</p><h2 id="其他第三方平台的鉴权方式"><a href="#其他第三方平台的鉴权方式" class="headerlink" title="其他第三方平台的鉴权方式"></a>其他第三方平台的鉴权方式</h2><p><a href="https://zhuanlan.zhihu.com/p/165077751">Gateway：网关鉴权</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;因为最近的一些需求，我不得不对鉴权反复翻检。如是&lt;/p&gt;</summary>
    
    
    
    <category term="学习加油站" scheme="https://www.i5res.com/categories/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E7%AB%99/"/>
    
    
    <category term="oauth" scheme="https://www.i5res.com/tags/oauth/"/>
    
    <category term="github" scheme="https://www.i5res.com/tags/github/"/>
    
  </entry>
  
  <entry>
    <title>我编曲相关的DEMO全都在这儿了</title>
    <link href="https://www.i5res.com/music/sequencer-practice.html"/>
    <id>https://www.i5res.com/music/sequencer-practice.html</id>
    <published>2022-07-16T14:15:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin colorful note" color="warning"><div class="title"><strong>在最开始</strong></div><div class="body"><p>本文含巨量音频，请适当检查设备音量后继续阅读！<br>另外，歌曲内容涵盖较广，基本上是想到什么写什么，质量参差。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatnomblobcat.png"/></span><br>每一首都保存有项目文件，欢迎大佬探讨。</p></div></div><p>在小时候，因为家庭管教的严格，限制很多电子产品，在想方设法软磨硬泡下被答应了使用手机听歌。</p><span id="more"></span><p>但在那个无忧无虑的年纪，倒是很会苦中作乐，这也是我难以忘怀的一段经历了。</p><style>    #_flat {        height: 86px;        width: 100%;        margin: 0;        border: 0;        transform: scale(1.027);    }</style><p>与音乐结缘，无花无果，无你无他。热爱音乐，也热爱生活！</p><h2 id="专题の练习"><a href="#专题の练习" class="headerlink" title="专题の练习"></a>专题の练习</h2><h3 id="单耳扒带练习"><a href="#单耳扒带练习" class="headerlink" title="单耳扒带练习"></a>单耳扒带练习</h3><h4 id="Ninelie"><a href="#Ninelie" class="headerlink" title="Ninelie"></a>Ninelie</h4><p>时间：2022年12月2日</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2514487588&auto=0&height=66"></iframe><h4 id="霍元甲"><a href="#霍元甲" class="headerlink" title="霍元甲"></a>霍元甲</h4><p>时间：2022年11月28日</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2514190068&auto=0&height=66"></iframe><h4 id="奥日（Ori）"><a href="#奥日（Ori）" class="headerlink" title="奥日（Ori）"></a>奥日（Ori）</h4><p>时间：2022年11月19日</p><p>一个特殊的日子</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2513910664&auto=0&height=66"></iframe><p>挺特殊的一个日子，祝我的好兄弟生日快乐！！</p><p>曲子的最后有一段《生日快乐》的变调，应该没多少人能听出来吧。<span class="tag-plugin emoji"><img no-lazy="" class="inline" src="https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatnomblobcat.png"/></span></p><h4 id="原神《神女劈观》"><a href="#原神《神女劈观》" class="headerlink" title="原神《神女劈观》"></a>原神《神女劈观》</h4><p>时间：2022年11月12日</p><p>当时看到这个片段感觉很惊艳。<br>因为我的游戏刚开始下载的时候是英文配音！！<br>在任务进行到PV播放的时候，突然出现的汉语让我猝不及防。</p><p>另外，我觉得真的很有味道。</p><p>天衡山里本有一处村落，村中有对感情很好的夫妻。有天妻子出门采药，被魔物捉走，丈夫也因此变得疯疯癫癫。魔物威胁村民把村中小孩供奉给他，村民十分恐惧，有个小姑娘却主动请缨，身藏一把驱魔剑，进入魔物的老巢与其苦战，最后将魔物击败。后来，姑娘因资质过人被仙家收留，但也无缘再入尘世。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2513690772&auto=0&height=66"></iframe><h4 id="原神·奥摩斯港-OST"><a href="#原神·奥摩斯港-OST" class="headerlink" title="原神·奥摩斯港 OST"></a>原神·奥摩斯港 OST</h4><p>时间：2022年11月11日</p><p>很折磨，真的。。。<br>万幸…</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2513715664&auto=0&height=66"></iframe><h4 id="League-of-Legends-Medley"><a href="#League-of-Legends-Medley" class="headerlink" title="League of Legends Medley"></a>League of Legends Medley</h4><p>联盟永垂不朽</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2512834562&auto=0&height=66"></iframe><h4 id="すずめの戸締まり-扒带"><a href="#すずめの戸締まり-扒带" class="headerlink" title="すずめの戸締まり 扒带"></a>すずめの戸締まり 扒带</h4><p>现在是2022年10月6日，国庆假期结束前一晚。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2511933098&auto=0&height=66"></iframe><h4 id="Right-Above-It（单耳扒谱）"><a href="#Right-Above-It（单耳扒谱）" class="headerlink" title="Right Above It（单耳扒谱）"></a>Right Above It（单耳扒谱）</h4><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/Screenshot_2022-10-05-00-56-09-74_cc0c40aae00121c.jpg" alt="冲！！！！" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">冲！！！！</span></div></div><p>这是一次练习，用到的音源也都是自带的，因为我电脑内存是在不允许我去外置了QWQ</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221005005103.png" alt="我的剩余储存" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">我的剩余储存</span></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/H`6P62C{4HE0XKCE7G}7RD3.png" alt="FLEX 合成器（自带的）" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">FLEX 合成器（自带的）</span></div></div><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2511982656&auto=0&height=66"></iframe><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/20221005004712.png" alt="Fl Studio工程截图" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">Fl Studio工程截图</span></div></div><h3 id="艾尔大陆（游戏《艾尔大陆》-原声带）"><a href="#艾尔大陆（游戏《艾尔大陆》-原声带）" class="headerlink" title="艾尔大陆（游戏《艾尔大陆》 原声带）"></a>艾尔大陆（游戏《艾尔大陆》 原声带）</h3><p>也是练习！！也是练习！也是练习！！！</p><h4 id="日落维京"><a href="#日落维京" class="headerlink" title="日落维京"></a>日落维京</h4><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2493331239&auto=0&height=66"></iframe><h4 id="登峰造极"><a href="#登峰造极" class="headerlink" title="登峰造极"></a>登峰造极</h4><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2493359459&auto=0&height=66"></iframe><h4 id="启程（Piano）"><a href="#启程（Piano）" class="headerlink" title="启程（Piano）"></a>启程（Piano）</h4><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2493342145&auto=0&height=66"></iframe><h4 id="抉择吧"><a href="#抉择吧" class="headerlink" title="抉择吧"></a>抉择吧</h4><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2493348597&auto=0&height=66"></iframe><h2 id="日常练习"><a href="#日常练习" class="headerlink" title="日常练习"></a>日常练习</h2><h3 id="2022年11月6日"><a href="#2022年11月6日" class="headerlink" title="2022年11月6日"></a>2022年11月6日</h3><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2513454813&auto=0&height=66"></iframe><h3 id="2022年8月30日练习"><a href="#2022年8月30日练习" class="headerlink" title="2022年8月30日练习"></a>2022年8月30日练习</h3><p>三全音</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2510067424&auto=0&height=66"></iframe><h3 id="2022年8月28日练习"><a href="#2022年8月28日练习" class="headerlink" title="2022年8月28日练习"></a>2022年8月28日练习</h3><p>布鲁斯，这种风格果然还是不太会写。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2510158019&auto=0&height=66"></iframe><h3 id="2022年8月27日练习"><a href="#2022年8月27日练习" class="headerlink" title="2022年8月27日练习"></a>2022年8月27日练习</h3><p>有种史诗的感觉了</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2510131031&auto=0&height=66"></iframe><h3 id="2022年8月24日练习"><a href="#2022年8月24日练习" class="headerlink" title="2022年8月24日练习"></a>2022年8月24日练习</h3><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2510033010&auto=0&height=66"></iframe><h3 id="2022年8月20-21日练习"><a href="#2022年8月20-21日练习" class="headerlink" title="2022年8月20-21日练习"></a>2022年8月20-21日练习</h3><p>夏日pop + 爵士 这种味道是什么样的，漫无目的的探索，是炎炎夏日对生活的告白。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509859785&auto=0&height=66"></iframe><p>使用了一个很仙的pad，没错，我花了30分钟捏出来的，使用的合成器是serum，我打算叫他spaceship<br>就是其中那个 咻~~~~ 的 rise，个人很喜欢，它应该有更大的用途的。</p><h3 id="2022年8月14日练习"><a href="#2022年8月14日练习" class="headerlink" title="2022年8月14日练习"></a>2022年8月14日练习</h3><p>6152觉得很不错的一个大调和弦，练习分轨如下</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509719866&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509742884&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509703853&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509674873&auto=0&height=66"></iframe><p>他们加起来听起来像这样</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509695861&auto=0&height=66"></iframe><p>在进行上可能欠缺一些东西，但是总体来说还是很整体的lol</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202208141432556.png" fancybox="true"/></div></div><h3 id="2022年8月13日练习"><a href="#2022年8月13日练习" class="headerlink" title="2022年8月13日练习"></a>2022年8月13日练习</h3><p>一个大调4563，几个分轨如下</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509741642&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509713627&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509656648&auto=0&height=66"></iframe><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509687660&auto=0&height=66"></iframe><p>他们加在一起听上去像这样…</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2509691645&auto=0&height=66"></iframe><h3 id="2022年7月17日练习"><a href="#2022年7月17日练习" class="headerlink" title="2022年7月17日练习"></a>2022年7月17日练习</h3><p>中世纪和弦一个大胆的尝试</p><p>用了一个小降，听上去感觉像那么回事了，鼓点是随便写的，仍有很多欠缺的地方。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2508210874&auto=0&height=66"></iframe><h3 id="2022年7月16日练习"><a href="#2022年7月16日练习" class="headerlink" title="2022年7月16日练习"></a>2022年7月16日练习</h3><p>这个是一个简单的大小调add转换的练习，还有很多欠缺的地方。</p><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2508238711&auto=0&height=66"></iframe><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202207162234371.png" fancybox="true"/></div></div><h3 id="2022年7月16日trap练习"><a href="#2022年7月16日trap练习" class="headerlink" title="2022年7月16日trap练习"></a>2022年7月16日trap练习</h3><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2508145760&auto=0&height=66"></iframe><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202207162255562.png" fancybox="true"/></div></div><h3 id="2021年7月12日-一位受害者"><a href="#2021年7月12日-一位受害者" class="headerlink" title="2021年7月12日 一位受害者"></a>2021年7月12日 一位受害者</h3><iframe id="_flat" src="//music.163.com/outchain/player?type=3&id=2508198793&auto=0&height=66"></iframe>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin colorful note&quot; color=&quot;warning&quot;&gt;&lt;div class=&quot;title&quot;&gt;&lt;strong&gt;在最开始&lt;/strong&gt;&lt;/div&gt;&lt;div class=&quot;body&quot;&gt;&lt;p&gt;本文含巨量音频，请适当检查设备音量后继续阅读！&lt;br&gt;另外，歌曲内容涵盖较广，基本上是想到什么写什么，质量参差。&lt;span class=&quot;tag-plugin emoji&quot;&gt;&lt;img no-lazy=&quot;&quot; class=&quot;inline&quot; src=&quot;https://fastly.i5res.com/gh/norevi/waline-blobcatemojis@1.0/blobs/blobcatnomblobcat.png&quot;/&gt;&lt;/span&gt;&lt;br&gt;每一首都保存有项目文件，欢迎大佬探讨。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在小时候，因为家庭管教的严格，限制很多电子产品，在想方设法软磨硬泡下被答应了使用手机听歌。&lt;/p&gt;</summary>
    
    
    
    <category term="音樂练习" scheme="https://www.i5res.com/categories/%E9%9F%B3%E6%A8%82%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="音乐" scheme="https://www.i5res.com/tags/%E9%9F%B3%E4%B9%90/"/>
    
    <category term="和弦" scheme="https://www.i5res.com/tags/%E5%92%8C%E5%BC%A6/"/>
    
  </entry>
  
  <entry>
    <title>已完结的Puppeteer学习经验与踩坑</title>
    <link href="https://www.i5res.com/practical-guide-to-using-puppeteer.html"/>
    <id>https://www.i5res.com/practical-guide-to-using-puppeteer.html</id>
    <published>2022-07-12T12:54:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><h2 id="关于这个西瓜皮"><a href="#关于这个西瓜皮" class="headerlink" title="关于这个西瓜皮"></a>关于这个西瓜皮</h2><p>其实不难猜，和爬虫挂钩的那无非就是无头浏览器。</p><span id="more"></span><p><code>Puppeteer</code>已经是蛮成熟的一个无头了，几乎能满足开发的所有需求，而且该项目由Google团队开源长久维护，有着丰富的社区。（简而言之，你踩到的坑，别人都踩到过，如果！！哪一天你踩到了一个没有人踩到过得坑，那么务必来找我，哈哈哈哈哈）</p><p>玩这个东西也挺久的了，在一些开源项目里有做过很多贡献，其中不乏有借了Puppeteer的光啊。</p><h2 id="踩坑笔记"><a href="#踩坑笔记" class="headerlink" title="踩坑笔记"></a>踩坑笔记</h2><p>这里主要记录了，日常开发以及团队项目开发期间遇到的一些问题，所以这篇文章将处于长期更新维护的状态。<br>如有问题，欢迎底下评论区进行提问，博主24H在线，不出意外的话5分钟内会有回复的。</p><h3 id="CentOS-的一些特殊配置"><a href="#CentOS-的一些特殊配置" class="headerlink" title="CentOS 的一些特殊配置"></a>CentOS 的一些特殊配置</h3><p>报错：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/../node_modules/puppeteer/.local-chromium/linux-515411/chrome-linux/chrome: error while loading shared libraries: libatk-bridge-2.0.so.0: cannot open shared object file: No such file or directory</span><br></pre></td></tr></table></figure><p>按照他的意思是没有找到相关依赖库，这玩意简单了。</p><p>CentOS解决方法：</p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_1" value="sudo yum install atk java-atk-wrapper at-spi2-atk gtk3 libXt libdrm mesa-libgbm"><button class="copy-btn" onclick="util.copy(&quot;copy_1&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><h3 id="请求时出现-net-ERR-TUNNEL-CONNECTION-FAILED"><a href="#请求时出现-net-ERR-TUNNEL-CONNECTION-FAILED" class="headerlink" title="请求时出现 net::ERR_TUNNEL_CONNECTION_FAILED"></a>请求时出现 net::ERR_TUNNEL_CONNECTION_FAILED</h3><p>复现：</p><ul><li>可用代理（测试完整）</li><li>完整请求头</li></ul><p>测试上百次依旧报错 <code>net::ERR_TUNNEL_CONNECTION_FAILED</code></p><p>已查阅：<br>Windows10错误：<a href="https://answers.microsoft.com/en-us/windows/forum/all/getting-error-errtunnelconnectionfailed-while/f8d8b61f-a875-4d57-8a4f-3427a0e783c6">https://answers.microsoft.com/en-us/windows/forum/all/getting-error-errtunnelconnectionfailed-while/f8d8b61f-a875-4d57-8a4f-3427a0e783c6</a><br>Chrome错误：<a href="https://www.techbout.com/err-tunnel-connection-failed-error-in-chrome-39692/">https://www.techbout.com/err-tunnel-connection-failed-error-in-chrome-39692/</a><br>Puppeteer错误：<a href="https://vi.sandiegocsta.org/488310-puppeteer-chromium-proxy-err-tunnel-PDNJOM">https://vi.sandiegocsta.org/488310-puppeteer-chromium-proxy-err-tunnel-PDNJOM</a><br>Puppeteer错误：<a href="https://www.xknote.com/ask/60ef8c45582ca.html">https://www.xknote.com/ask/60ef8c45582ca.html</a></p><p>最后。</p><p>在<code>Puppeteer</code>的issues中找到相关记录，维护团队回复：<mark class="tag-plugin colorful mark" color="dark">Hey @Yom92 That error is coming straight from Chromium. There is not much we can do on our side.</mark><br>具体参见：<a href="https://github.com/hardkoded/puppeteer-sharp/issues/1202#issuecomment-509187809">https://github.com/hardkoded/puppeteer-sharp/issues/1202#issuecomment-509187809</a></p><p>要而论之。</p><p>在需要代理的无头请求时，应当注意Chromium的特性，那么就没有其他的替代方案了。<br>对！我还没想到，如果你有，麻烦大佬下方评论区畅所欲言。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>无头的作用想必大家都有所了解了，那么他能用来做些什么呢？<br>博主在这里尝试了几个简单的请求，不同于<mark class="tag-plugin colorful mark" color="dark">axios</mark>的是，<mark class="tag-plugin colorful mark" color="dark">Puppeteer</mark>可以等待Dom和页面加载。</p><p>博主常用该类来进行SEO词尾优化，提高命中率。</p><h3 id="原神官网抓取和操作"><a href="#原神官网抓取和操作" class="headerlink" title="原神官网抓取和操作"></a>原神官网抓取和操作</h3><p>暂无更方便的获取cookie的办法，所以只能要求用户自己获取米游社的cookie，在请求的时候puppeteer携带cookie就能完成，角色查询，签到等任务。</p><p>相关项目：</p><div class="tag-plugin ghcard"><a class="ghcard" rel="external nofollow noopener noreferrer" href="https://github.com/Le-niao/Yunzai-Bot"><img src="https://github-readme-stats.xaoxuu.com/api/pin/?username=Le-niao&repo=Yunzai-Bot&&show_owner=true"/></a></div><div class="tag-plugin ghcard"><a class="ghcard" rel="external nofollow noopener noreferrer" href="https://github.com/yoimiya-kokomi/miao-plugin"><img src="https://github-readme-stats.xaoxuu.com/api/pin/?username=yoimiya-kokomi&repo=miao-plugin&&show_owner=true"/></a></div><p>剖析一下机器人即可，很巧妙的利用了无头进行图片渲染👍</p><h3 id="无头渲染图片"><a href="#无头渲染图片" class="headerlink" title="无头渲染图片"></a>无头渲染图片</h3><p>作为Canvas的替代方法，顺便一提，应该没有人喜欢用Canvas去渲染图片吧？那叫一个折磨啊，H5不比画板香吗？</p>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;关于这个西瓜皮&quot;&gt;&lt;a href=&quot;#关于这个西瓜皮&quot; class=&quot;headerlink&quot; title=&quot;关于这个西瓜皮&quot;&gt;&lt;/a&gt;关于这个西瓜皮&lt;/h2&gt;&lt;p&gt;其实不难猜，和爬虫挂钩的那无非就是无头浏览器。&lt;/p&gt;</summary>
    
    
    
    <category term="爬虫技术" scheme="https://www.i5res.com/categories/%E7%88%AC%E8%99%AB%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="爬虫" scheme="https://www.i5res.com/tags/%E7%88%AC%E8%99%AB/"/>
    
    <category term="spider" scheme="https://www.i5res.com/tags/spider/"/>
    
    <category term="puppeteer" scheme="https://www.i5res.com/tags/puppeteer/"/>
    
    <category term="node" scheme="https://www.i5res.com/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>搭建RTMP服务端与HLS流媒体使用OBS推流完成一个直播间</title>
    <link href="https://www.i5res.com/streaming-rtmp-to-hls-using-obs.html"/>
    <id>https://www.i5res.com/streaming-rtmp-to-hls-using-obs.html</id>
    <published>2022-06-25T15:16:12.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>使用 Linux 搭建 RTMP 流媒体服务器，进行在线直播。</p><span id="more"></span><h2 id="搭建串流服务器"><a href="#搭建串流服务器" class="headerlink" title="搭建串流服务器"></a>搭建串流服务器</h2><p>好用的Docker镜像，比较好用，比较简单，比较方便，比较容易使用。<br>博主使用的是 CentOS 8.0 系统，没有预装 Docker</p><p><strong>在开始安装之前，有必要提醒，更新<mark class="tag-plugin colorful mark" color="dark">yum</mark>的下载源！！</strong></p><details class="tag-plugin colorful folding" ><summary><span>更新下载源</span></summary><div class="body"><p>备份现有源</p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_2" value="mv /etc/yum.repos.d /etc/yum.repos.d.backup"><button class="copy-btn" onclick="util.copy(&quot;copy_2&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>设置新的`yum`目录<div class="tag-plugin copy"><input class="copy-area" readonly id="copy_3" value="mkdir /etc/yum.repos.d"><button class="copy-btn" onclick="util.copy(&quot;copy_3&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>安装wget<div class="tag-plugin copy"><input class="copy-area" readonly id="copy_4" value="yum install -y wget"><button class="copy-btn" onclick="util.copy(&quot;copy_4&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>下载配置。<p><u>此处一定要注意，很多教程都是CentOS 7的教程，所以贴的CentOS 7的下载源，对于CentOS 8一定要改为CentOS 8的下载源，否则还是不行。</u></p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_5" value="wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/CentOS-8.repo"><button class="copy-btn" onclick="util.copy(&quot;copy_5&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>清除文件并重建元数据缓存<div class="tag-plugin copy"><input class="copy-area" readonly id="copy_6" value="yum clean all"><button class="copy-btn" onclick="util.copy(&quot;copy_6&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_7" value="yum makecache"><button class="copy-btn" onclick="util.copy(&quot;copy_7&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>最后更新软件包，稍等软件安装包安装完就可以了<div class="tag-plugin copy"><input class="copy-area" readonly id="copy_8" value="yum update -y"><button class="copy-btn" onclick="util.copy(&quot;copy_8&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><p>最后，贴上<a href="https://mirrors.tuna.tsinghua.edu.cn/">清华大学镜像站</a></p></div></details><details class="tag-plugin colorful folding"  open><summary><span>安装Docker</span></summary><div class="body"><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_9" value="yum update"><button class="copy-btn" onclick="util.copy(&quot;copy_9&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_10" value="yum install -y docker"><button class="copy-btn" onclick="util.copy(&quot;copy_10&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div></div></details><details class="tag-plugin colorful folding"  open><summary><span>部署镜像</span></summary><div class="body"><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_11" value="docker run -d -p 1935:1935 -p 8080:8080 -v custom.conf:/etc/nginx/nginx.conf alqutami/rtmp-hls"><button class="copy-btn" onclick="util.copy(&quot;copy_11&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div></div></details><p><strong>至此！</strong></p><p>你拥有了一个可以收发媒体流的<code>RTMP服务端</code></p><p>详情参见: <a href="https://registry.hub.docker.com/r/alqutami/rtmp-hls">alqutami&#x2F;rtmp-hls</a></p><h2 id="配置OBS串流"><a href="#配置OBS串流" class="headerlink" title="配置OBS串流"></a>配置OBS串流</h2><p>下载与安装就不需要再赘述了吧</p><p><a href="https://obsproject.com/">官方地址</a></p><h3 id="OBS串流设置"><a href="#OBS串流设置" class="headerlink" title="OBS串流设置"></a>OBS串流设置</h3><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202206252327424.png" alt="右键左上方'文件'" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">右键左上方'文件'</span></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202206252357689.png" alt="找到左侧栏目'推流'选项" fancybox="true" style="width:100%;"/></div><div class="image-meta"><span class="image-caption center">找到左侧栏目'推流'选项</span></div></div><h2 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h2><h3 id="Vite框架"><a href="#Vite框架" class="headerlink" title="Vite框架"></a>Vite框架</h3><p>博主使用<code>Vite</code>框架，这并不代表播放<code>HLS</code>流媒体只能使用<code>Vite</code>前端框架。</p><p>为了方便，在这里就不赘述<code>Video.js</code>的使用方法了</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">class</span>=<span class="string">&quot;vjs-styles-defaults&quot;</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-class">.video-js</span> &#123;</span></span><br><span class="line"><span class="language-css"><span class="attribute">width</span>: <span class="number">300px</span>;</span></span><br><span class="line"><span class="language-css"><span class="attribute">height</span>: <span class="number">150px</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-class">.vjs-fluid</span> &#123;</span></span><br><span class="line"><span class="language-css"><span class="attribute">padding-top</span>: <span class="number">56.25%</span></span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">class</span>=<span class="string">&quot;vjs-styles-dimensions&quot;</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-class">.player-dimensions</span> &#123;</span></span><br><span class="line"><span class="language-css"><span class="attribute">width</span>: <span class="number">720px</span>;</span></span><br><span class="line"><span class="language-css"><span class="attribute">height</span>: <span class="number">405px</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-class">.player-dimensions</span><span class="selector-class">.vjs-fluid</span> &#123;</span></span><br><span class="line"><span class="language-css"><span class="attribute">padding-top</span>: <span class="number">56.25%</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>HLS Live Streaming<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">&quot;https://vjs.zencdn.net/7.5.5/video-js.css&quot;</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://vjs.zencdn.net/7.5.5/video.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>HLS Player<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">video</span> <span class="attr">id</span>=<span class="string">&quot;player&quot;</span> <span class="attr">width</span>=<span class="string">1280</span> <span class="attr">height</span>=<span class="string">720</span> <span class="attr">class</span>=<span class="string">&quot;vjs-default-skin&quot;</span> <span class="attr">controls</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">source</span> <span class="attr">src</span>=<span class="string">&quot;http://hls.i5res.com/hls/zj520.m3u8&quot;</span> <span class="attr">type</span>=<span class="string">&quot;application/x-mpegURL&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">video</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">var</span> player = <span class="title function_">videojs</span>(<span class="string">&#x27;#player&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="Vite初始化"><a href="#Vite初始化" class="headerlink" title="Vite初始化"></a>Vite初始化</h4><p>关于如何使用<code>NPM</code>进行初始化，请参见: <a href="https://vitejs.cn/guide/#scaffolding-your-first-vite-project">https://vitejs.cn/guide/#scaffolding-your-first-vite-project</a></p><p>这里以<code>NPM</code>做简要概述: </p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_12" value="npm i -g vite@latest"><button class="copy-btn" onclick="util.copy(&quot;copy_12&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><p>初始化程序</p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_13" value="npm init vite@latest"><button class="copy-btn" onclick="util.copy(&quot;copy_13&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><p>随后跟随步骤完成项目创建即可。</p><h4 id="LarchLiu-vue3-video-player"><a href="#LarchLiu-vue3-video-player" class="headerlink" title="LarchLiu&#x2F;vue3-video-player"></a>LarchLiu&#x2F;vue3-video-player</h4><p>安装包文件</p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_14" value="npm i -S @cloudgeek/playcore-hls"><button class="copy-btn" onclick="util.copy(&quot;copy_14&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_15" value="npm i -S @cloudgeek/vue3-video-player"><button class="copy-btn" onclick="util.copy(&quot;copy_15&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div><figure class="highlight ts"><figcaption><span>./main.ts</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; createApp &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">&#x27;./App.vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Vue3VideoPlayer</span> <span class="keyword">from</span> <span class="string">&#x27;@cloudgeek/vue3-video-player&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;@cloudgeek/vue3-video-player/dist/vue3-video-player.css&#x27;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="title function_">createApp</span>(<span class="title class_">App</span>).<span class="title function_">use</span>(<span class="title class_">Vue3VideoPlayer</span>, &#123;</span><br><span class="line"><span class="attr">lang</span>: <span class="string">&#x27;zh-CN&#x27;</span></span><br><span class="line">&#125;).<span class="title function_">mount</span>(<span class="string">&#x27;#app&#x27;</span>);</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><figcaption><span>xxx.vue</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;script setup lang=&quot;ts&quot;&gt;</span><br><span class="line">import HLSCore from &#x27;@cloudgeek/playcore-hls&#x27;;</span><br><span class="line">import &#123; reactive &#125; from &#x27;vue&#x27;;</span><br><span class="line"></span><br><span class="line">const options = reactive(&#123;</span><br><span class="line">sources: [</span><br><span class="line">&#123;</span><br><span class="line">src: &quot;http://hls.i5res.com/hls/zj520.m3u8&quot;,</span><br><span class="line">type: &quot;application/x-mpegURL&quot;,</span><br><span class="line">&#125;,</span><br><span class="line">]</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;template&gt;</span><br><span class="line">&lt;vue3-video-player :core=&quot;HLSCore&quot; :options=&quot;options&quot; :src=&quot;options.sources&quot; title=&quot;大猫咪的直播间&quot;&gt;</span><br><span class="line">&lt;/vue3-video-player&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><h4 id="预览地址"><a href="#预览地址" class="headerlink" title="预览地址"></a>预览地址</h4><p><a href="https://live.i5res.com/"><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2022/202206260032323.png" fancybox="true"/></div></div></a></p><div class="tag-plugin quot"><h2 class="content" id="其他问题" type="icon"><a href="#其他问题" class="headerlink" title="其他问题"></a><img class="icon prefix" src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/202206251533227.png" />其他问题</h2></div><div class="tag-plugin colorful checkbox" ><input type="checkbox" checked="true"/><span>如何开启RTMPS适配SSL进行推流</span></div><div class="tag-plugin colorful checkbox" ><input type="checkbox"/><span>为什么我的 video.js 出现很多错误</span></div><h3 id="RTMPS适配SSL进行推流"><a href="#RTMPS适配SSL进行推流" class="headerlink" title="RTMPS适配SSL进行推流"></a>RTMPS适配SSL进行推流</h3><p><strong>博主尝试过为流加密传输，也就是RTMPS的协议，但！！！</strong></p><p>缓存更新太慢，博主赶时间。所以使用<code>Nginx</code>反代来实现伪加密。</p><div class="tag-plugin colorful checkbox" ><input type="checkbox" checked="true"/><span>为代理服务器域名申请SSL，也就是 https://xx.com</span></div><div class="tag-plugin colorful checkbox" ><input type="checkbox" checked="true"/><span>将 stream.i5res.com 代理 hls.i5res.com:8080</span></div><p>访问 <a href="https://stream.i5res.com/">https://stream.i5res.com</a> 就等于访问了 <a href="http://hls.i5res.com:8080/">http://hls.i5res.com:8080</a></p><figure class="highlight nginx"><figcaption><span>配置文件</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">443</span> ssl;</span><br><span class="line">  <span class="attribute">listen</span> [::]:<span class="number">443</span> ssl;</span><br><span class="line">  <span class="attribute">server_name</span> stream.i5res.com</span><br><span class="line">  access_log /data/wwwlogs/stream_nginx.log combined;</span><br><span class="line">  <span class="attribute">index</span> index.html index.htm index.php;</span><br><span class="line">  <span class="attribute">root</span> /data/wwwroot/live;</span><br><span class="line"></span><br><span class="line">  <span class="comment">#error_page 404 /404.html;</span></span><br><span class="line">  <span class="comment">#error_page 502 /502.html;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># SSL</span></span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /data/cert/stream/private.key;</span><br><span class="line">  <span class="attribute">ssl_certificate</span> /data/cert/stream/full_chain.pem;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl_session_timeout</span> <span class="number">1m</span>;</span><br><span class="line">  <span class="attribute">ssl_ciphers</span> ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;</span><br><span class="line">  <span class="attribute">ssl_protocols</span> TLSv1 TLSv1.<span class="number">1</span> TLSv1.<span class="number">2</span>;</span><br><span class="line">  <span class="attribute">ssl_prefer_server_ciphers</span> <span class="literal">on</span>;</span><br><span class="line"></span><br><span class="line">  <span class="section">location</span> <span class="regexp">~ /</span> &#123;</span><br><span class="line">    <span class="attribute">proxy_pass</span> http://hls.i5res.com:8080;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="video-js-出现很多错误"><a href="#video-js-出现很多错误" class="headerlink" title="video.js 出现很多错误"></a>video.js 出现很多错误</h3><p>把video.js拆开来…..一言难尽，上世纪的东西说实话就算功能再强悍其兼容性也像一坨散沙<psw>屎</psw><br>最好的办法，就只有找寻其他替代方案，博主当前也在寻找，如果你找到了，可以在评论区留给我！！！感谢！！！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;使用 Linux 搭建 RTMP 流媒体服务器，进行在线直播。&lt;/p&gt;</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="vite" scheme="https://www.i5res.com/tags/vite/"/>
    
    <category term="docker" scheme="https://www.i5res.com/tags/docker/"/>
    
    <category term="rmtp" scheme="https://www.i5res.com/tags/rmtp/"/>
    
    <category term="hls" scheme="https://www.i5res.com/tags/hls/"/>
    
    <category term="video.js" scheme="https://www.i5res.com/tags/video-js/"/>
    
    <category term="vue" scheme="https://www.i5res.com/tags/vue/"/>
    
    <category term="vue3" scheme="https://www.i5res.com/tags/vue3/"/>
    
  </entry>
  
  <entry>
    <title>专辑·新单曲《Sternstunde》发布！仿了一下指弹</title>
    <link href="https://www.i5res.com/music/sternstunde-album.html"/>
    <id>https://www.i5res.com/music/sternstunde-album.html</id>
    <published>2022-02-26T02:49:00.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin gallery swiper" id="swiper-api" width="max"><div class="swiper-wrapper"><div class="swiper-slide"><img no-lazy src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/202206242149932.png" fancybox="true"/></div></div><div class="swiper-pagination"></div><div class="swiper-button-prev blur"></div><div class="swiper-button-next blur"></div></div><p>我学习了一下母带管理。<br>算是比较的有成效（相对而言，不积小流，无以成江海嘛）</p><span id="more"></span><p>我想用这首音乐描述一个转折（恒星时刻）<br>更多灵感的参与与我的个人机遇和生活有关，自安于弱，而终于弱矣；自安于愚，而终于愚矣。</p><p>这首歌用的主要音色是吉他，也给足了泛音的空灵。</p><h2 id="初成曲之"><a href="#初成曲之" class="headerlink" title="初成曲之"></a>初成曲之</h2><p>常规的混音流程是先确定几个主要乐器的电平和动态然后冻结，其它乐器以主要乐器为参考进行调节。然后本人做混音也不是特别的好（和专业的远远不能比，能听就行的那种），但做下来多多少少还是积累了一些经验的。<br>然后因为每个人的混音方法和风格多多少少是有些不同的，就不把整个体系都阐述出来了，这里就罗列一部分tips：</p><ol><li>能不把问题留给混音就不要留给混音。换句话说，在编曲的时候就要考虑到混音。如果你是一边做一边混的，可能对这一点深有体会。我这边是先把整个编曲弄好再考虑混音，在实际操作中就会发现很多难以解决的问题。说到底，编曲的时候可能有太多的东西想要加到乐曲里面，而这不被混音所允许。这也说明了一首曲子不是你想加什么进去就加什么进去，硬塞一些东西进去只会让混音变糊。</li><li>谨慎使用EQEQ对音色造成的破坏其实是很大的，±3dB的增益量甚至可以产生一个质感不同的音色。我的建议是在制作音色的时候就考虑好频段的分配，避免大量使用EQ。然后一个比较有争议性的话题是电平极低的一些频段信号是否要滤除（所谓的“切干净”），我这边是倾向于切干净的（在非专业的条件下，这些极弱的信号可能会在母带过程中被放大产生失真）。EQ我个人偏向于使用Fabfilter的Pro-Q和Pro-Q</li><li>谨慎使用压缩这个是出于保留动态的角度考虑的。如果某个乐器的动态本来就过大，最好还是适当进行压缩。通常我会把鼓之类的压一压让声音更结实，人声当然也要压过，别的乐器就不怎么上压缩了。一些pluck可能会考虑加一个适度的压缩器提升一下rms，其实意义不大。总的来说如果峰值有点高，把推子往下推可能是一个更好的选择。</li><li>全局混响能用全局混响尽量还是用全局吧，这样可以让整体的混响统一和谐。一般情况下全局混响的声音出来是比单独设置混响好听的。当然一些特殊情况（比如利用混响制造特殊效果）除外。如果因为各种原因无法使用全局混响，不妨将混响也视为一种特殊的乐器加入混音。Fruit自带的Reeverb2挺好用的。</li><li>充分利用插件内建的效果器插件之所以自带这么多效果器，有一部分原因是这些效果器本身就是适用于这个插件的。换句话说，使用插件自带的效果器可以最高效率地让音色变得更加好听。</li><li>效果器的串联顺序很重要这一点其实是基础知识，我拿过来凑数的。大家都知道先压缩后混响和先混响后压缩出来的声音有何不同。当然串联顺序不是死的，完全可以根据需要来调节顺序。关于母带插件的选择，我平时都是用iZotope Ozone 6的，臭氧用的人也挺多的这一点不多说了。偷懒的话会用T-RackS的一个Soft<br>Clipper提响度（不是很推荐）。然后这两年响战打的差不多了，其实不少人又开始重新强调动态了，分段压缩模块尽量避免使用太大的压缩比、太小的attack和过大的增益吧。</li></ol><h2 id="Maximus"><a href="#Maximus" class="headerlink" title="Maximus"></a>Maximus</h2><h3 id="处理前"><a href="#处理前" class="headerlink" title="处理前"></a>处理前</h3><p><strong>低沉，沉闷</strong></p><p>没有轨道的区别，音乐也没有什么层次，更加没有空间感，总的来说，所有东西堆在一起的感觉。</p><h3 id="处理后"><a href="#处理后" class="headerlink" title="处理后"></a>处理后</h3><p>总体来说：明亮，干净</p><p>在<mark class="tag-plugin colorful mark" color="dark">Maximus</mark>的初步调节下，每个频段的压缩经过动态处理后，音乐变得更加灵活了。</p><p>你需要知道，在一首完整的歌曲中，可以大致分为三个频段：<mark class="tag-plugin colorful mark" color="dark">低频</mark> <mark class="tag-plugin colorful mark" color="dark">中频</mark> <mark class="tag-plugin colorful mark" color="dark">高频</mark>。<br>但在有时候，你很难兼顾到每个频段的压缩，所以，你需要把这三个频段的压缩比调节到一致的水平。<br>至此，便需要进行独立的频段监控，把相对高的压缩下来，把低的提高上去（或者不提高）</p><h2 id="在线播放"><a href="#在线播放" class="headerlink" title="在线播放"></a>在线播放</h2>    <div id="aplayer-ZdjZOTeF" class="aplayer aplayer-tag-marker meting-tag-marker"         data-id="1919180425" data-server="netease" data-type="song" data-mode="circulation" data-autoplay="true" data-mutex="false" data-listmaxheight="340px" data-preload="true" data-theme="#ad7a86" data-volume=" 0.2"    ></div><h2 id="我的总结"><a href="#我的总结" class="headerlink" title="我的总结"></a>我的总结</h2><p>音乐这个东西，是艺术，是频率交错间的美。</p><p>我在这条路上还有很长的距离。</p><p>路漫漫其修远兮，吾将上下而求索。</p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin gallery swiper&quot; id=&quot;swiper-api&quot; width=&quot;max&quot;&gt;&lt;div class=&quot;swiper-wrapper&quot;&gt;&lt;div class=&quot;swiper-slide&quot;&gt;&lt;img no-lazy src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2021/202206242149932.png&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;swiper-pagination&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-prev blur&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-next blur&quot;&gt;&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;我学习了一下母带管理。&lt;br&gt;算是比较的有成效（相对而言，不积小流，无以成江海嘛）&lt;/p&gt;</summary>
    
    
    
    <category term="音尘行樂" scheme="https://www.i5res.com/categories/%E9%9F%B3%E5%B0%98%E8%A1%8C%E6%A8%82/"/>
    
    
    <category term="音乐" scheme="https://www.i5res.com/tags/%E9%9F%B3%E4%B9%90/"/>
    
    <category term="Sternstunde" scheme="https://www.i5res.com/tags/Sternstunde/"/>
    
  </entry>
  
  <entry>
    <title>开始学习ArcGIS相关踩坑记录</title>
    <link href="https://www.i5res.com/arcgis-python.html"/>
    <id>https://www.i5res.com/arcgis-python.html</id>
    <published>2021-05-13T14:20:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>我到了一家公司去实习了，他们做的需求大概就是做土地规划吧，我开始不知道我去能学些什么…</p><span id="more"></span><h2 id="有始有终"><a href="#有始有终" class="headerlink" title="有始有终"></a>有始有终</h2><div class="tag-plugin about"><div class="about-header"><div class="avatar"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/202206241946198.png" height="80px"/></div></div><div class="about-body fs14"><p>ArcGIS是由ESRI出品的一个地理信息系统系列软件的总称。可以依不同应用平台分成以下版本：<br>桌面版本：以功能等级而区分的套件：ArcReader、ArcView、ArcEditor和ArcInfo，而高级的套件是较低级套件加上其他进阶功能。<br>服务器版本：以功能等级（基本、标准、进阶）而区分为ArcIMS (web mapping server), ArcGIS Server与ArcGIS Image Server。<br>移动版：ArcGIS Mobile与ArcPad</p><div class="tag-plugin navbar"><nav class="cap"><a href="https://zh.wikipedia.org/wiki/ArcGIS">Wiki</a><a href="https://github.com/PluginsKers/ArcPy_Scripts">项目</a></nav></div></div></div><p>当我认为会像学习<code>Photoshop</code>或者<code>Adobe</code>全家桶的时候。基于<code>Python</code>？我的热情一下子就来了，随后我查阅相关资料：</p><ul><li>ArcPy (ArcGIS API for Python)</li><li>ArcGIS API for JavaScript</li></ul><p>看到这我一下就明白了</p><p>我开始学习<code>ArcPy</code>的标准库使用方法，万事开头难，但还好我有着<code>Python</code>的相关基础<br>阅读了一下文档就拨云见日了</p><p><a href="https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/main/what-is-geoprocessing.htm">官网文档</a></p><p>其他请参见：<a href="https://www.jianshu.com/p/3355b6efc0d6">https://www.jianshu.com/p/3355b6efc0d6</a></p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>在安装<code>ArcGIS</code>的时候，默认会安装<code>Python27</code>版本并安装<code>ArcPy</code>的标准运行库</p><p>所以繁琐的东西已经都为我们做好了，在我开始安装的时候，并不知道，我安装了一个<code>Python37</code>，并且手动去配置<code>ArcPy</code>的包</p><p>最后：肯定是失败了的，在开始之前，做一些资料功课和准备还是很有必要的</p><h2 id="我的第一个需求"><a href="#我的第一个需求" class="headerlink" title="我的第一个需求"></a>我的第一个需求</h2><div class="tag-plugin quot"><p class="content" type="text">将几何数据文本化，并且按照规定的格式</p></div><p>我当时所接收到的信息就是上面这些，然后我拿到了一些格式参照，还有一个word文档（里面是具体的格式要求）</p><p>内心OS：算了，虽然刚刚开始，但是没有难度就没有进步嘛…</p><p>我开始了和这个库的死磕<br>一堆奇奇怪怪的东西出来了，加载前提是什么？</p><p>我在观摩了大佬作品后，发现加载一些文件是无法用游标去处理和迭代了，具体就是这些参数类并没有定义相关方法，这个坑我踩了很久才爬出来。</p><p>首先不得不吐槽百度，还有CSDN博客园这类搬运站，还有国内开源社区的混乱。</p><h2 id="整理了一些坑"><a href="#整理了一些坑" class="headerlink" title="整理了一些坑"></a>整理了一些坑</h2><h3 id="在读取shp文件的时候，会默认需要打开shp所在文件夹下的其他文件（钩子）"><a href="#在读取shp文件的时候，会默认需要打开shp所在文件夹下的其他文件（钩子）" class="headerlink" title="在读取shp文件的时候，会默认需要打开shp所在文件夹下的其他文件（钩子）"></a>在读取shp文件的时候，会默认需要打开shp所在文件夹下的其他文件（钩子）</h3><blockquote><p>网上很多都是错误的，但也有理可循，像添加env.workspace</p></blockquote><h3 id="Python的一些好用的小技巧"><a href="#Python的一些好用的小技巧" class="headerlink" title="Python的一些好用的小技巧"></a>Python的一些好用的小技巧</h3><blockquote><p>不论在处理什么数据的时候，都是以对象的方式进行（把String，Int这些基础整型也理解为对象）<br>Python对于可迭代对象真的很友好<br>在处理多重数据的时候，一定要复核一遍有无多状况出现（空？）<br>我把他丢到了Github仓库：<a href="https://github.com/PluginsKers/ArcPy_Scripts">https://github.com/PluginsKers/ArcPy_Scripts</a></p></blockquote><h2 id="今天过了单元测试了"><a href="#今天过了单元测试了" class="headerlink" title="今天过了单元测试了"></a>今天过了单元测试了</h2><p>这也算是一些经验吧。</p><h2 id="2021-6-2"><a href="#2021-6-2" class="headerlink" title="2021.6.2"></a>2021.6.2</h2><p>又一个新的需求，开始咯~</p><h2 id="2021-6-8"><a href="#2021-6-8" class="headerlink" title="2021.6.8"></a>2021.6.8</h2><p>圆满结束实习…</p><h2 id="其他杂谈"><a href="#其他杂谈" class="headerlink" title="其他杂谈"></a>其他杂谈</h2><p>在项目开发的过程中，有一个前辈，他告知每次处理地方信息的时候，都是将一个总excel拆开（当我看到这个excel的时候…..它有10k条数据，按照：村、镇、市。来划分）也就是说，此前一直都是人工手动的分割数据到单个excel中。</p><p>我手写了一个简单的脚本，以<code>10s/6k条数据</code>的的速度，将数据分割成单个excel，这样就可以节省大量的时间。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;我到了一家公司去实习了，他们做的需求大概就是做土地规划吧，我开始不知道我去能学些什么…&lt;/p&gt;</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="ArcGIS" scheme="https://www.i5res.com/tags/ArcGIS/"/>
    
    <category term="python" scheme="https://www.i5res.com/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>网易云热评墙 | MusicWall 项目介绍</title>
    <link href="https://www.i5res.com/projects/music-wall-proj.html"/>
    <id>https://www.i5res.com/projects/music-wall-proj.html</id>
    <published>2021-04-06T11:37:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427203907.png" fancybox="true"/></div></div><div class="tag-plugin quot"><p class="content" type="text">这个故事还没有结束。</p></div><p>使用Vue.js开发的流式程式。</p><span id="more"></span><h2 id="项目介绍"><a href="#项目介绍" class="headerlink" title="项目介绍"></a>项目介绍</h2><div class="tag-plugin colorful note" color="green"><div class="title"><strong>继往开来</strong></div><div class="body"><p>继我于2019开发的项目&nbsp;NeteaseCloudHotReview&nbsp;网易云热评墙<br>看到了很多人的故事，想着是否能将其收拢，归档一下，随后而突发奇想。<br>便做出了这样的一个小玩意。</p></div></div><h2 id="踩坑记录"><a href="#踩坑记录" class="headerlink" title="踩坑记录"></a>踩坑记录</h2><details class="tag-plugin colorful folding" ><summary><span>Swiper的大坑</span></summary><div class="body"><p><mark class="tag-plugin colorful mark" color="dark">Swiper</mark>我是真没想到这么大一个锅在你身上</p><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427202349.png" fancybox="true"/></div></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427202353.png" fancybox="true"/></div></div><p>谁知道我卸载安装了多少遍</p><p>报错都类似这样：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">warning  in ./node_modules/_swiper@6.5.0@swiper/esm/vue/swiper.js</span><br><span class="line">638:10-11 &quot;export &#x27;h&#x27; was not found in &#x27;vue&#x27;</span><br><span class="line">warning  in ./node_modules/_swiper@6.5.0@swiper/esm/vue/swiper-slide.js</span><br><span class="line">66:13-14 &quot;export &#x27;h&#x27; was not found in &#x27;vue&#x27;</span><br><span class="line">warning  in ./node_modules/_swiper@6.5.0@swiper/esm/vue/swiper-slide.js</span><br><span class="line">70:22-23 &quot;export &#x27;h&#x27; was not found in &#x27;vue&#x27;</span><br></pre></td></tr></table></figure><div class="tag-plugin colorful note" color="red"><div class="title"><strong>尝试过的方案：</strong></div><div class="body"><div class="tag-plugin colorful checkbox" ><input type="checkbox" checked="true"/><span>更换低版本的Swiper</span></div><div class="tag-plugin colorful checkbox" ><input type="checkbox" checked="true"/><span>修改createVue为链式创建</span></div></div></div></div></details><details class="tag-plugin colorful folding" ><summary><span>axios没办法post请求？</span></summary><div class="body"><p>关于<mark class="tag-plugin colorful mark" color="dark">axios</mark>POST请求无法正确传值</p><p><mark class="tag-plugin colorful mark" color="dark">axios</mark>默认发送数据时，数据格式是<mark class="tag-plugin colorful mark" color="dark">Request Payload</mark>，并非我们常用的<mark class="tag-plugin colorful mark" color="dark">Form Data</mark>格式，所以参数必须要以键值对形式传递，不能以<mark class="tag-plugin colorful mark" color="dark">json</mark>形式传参</p><p>那么很显然，需要更改一下他的形式</p><p>通过官方文档可得到在创建<mark class="tag-plugin colorful mark" color="dark">axios</mark>实例的时候有一个参数<mark class="tag-plugin colorful mark" color="dark">transformRequest</mark>可以达到预期</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">transformRequest</span>: [</span><br><span class="line">  <span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> params = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> index <span class="keyword">in</span> data) &#123;</span><br><span class="line">      params += index + <span class="string">&#x27;=&#x27;</span> + data[index] + <span class="string">&#x27;&amp;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> params;</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure></div></details><h2 id="开发小结"><a href="#开发小结" class="headerlink" title="开发小结"></a>开发小结</h2><h3 id="1-0-0"><a href="#1-0-0" class="headerlink" title="1.0.0"></a>1.0.0</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>热评墙页面</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>热评墙播放器</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>相关逻辑</span></div><h3 id="1-0-1"><a href="#1-0-1" class="headerlink" title="1.0.1"></a>1.0.1</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>双击评论点赞</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>发布</span></div><h3 id="1-0-2"><a href="#1-0-2" class="headerlink" title="1.0.2"></a>1.0.2</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>登录信息缓存</span></div><h3 id="1-0-3"><a href="#1-0-3" class="headerlink" title="1.0.3"></a>1.0.3</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>首个完整稳定&nbsp;完美&nbsp;的版本发布</span></div><h3 id="1-0-4"><a href="#1-0-4" class="headerlink" title="1.0.4"></a>1.0.4</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>更新了点赞的相关逻辑，以及页面&nbsp;工艺</span></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210717152257.png" fancybox="true"/></div></div> <div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>修复了在接口调用上跨域等问题</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>更新帮助页面</span></div><div class="tag-plugin image"><div class="image-bg"><img src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210717152151.png" fancybox="true"/></div></div> <div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>相关协议 The MIT License (MIT)</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>取消收藏歌曲</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>退出登录</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>Beta 签到/云贝任务方案</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>修复歌曲播放BUG</span></div><h3 id="1-0-5Beta"><a href="#1-0-5Beta" class="headerlink" title="1.0.5Beta"></a>1.0.5Beta</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>更改了协议 The GNU General Public License (GPL)</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>修复了播放器BUG</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>更新 二维码 登录</span></div><h3 id="1-0-5"><a href="#1-0-5" class="headerlink" title="1.0.5"></a>1.0.5</h3><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>更新帮助页面逻辑</span></div><div class="tag-plugin colorful checkbox" color="blue"><input type="checkbox" checked="true"/><span>修复播放器，图标显示问题</span></div><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p><a href="https://mw.i5res.com/">网易云热评墙 这个故事还没有结束！</a></p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin image&quot;&gt;&lt;div class=&quot;image-bg&quot;&gt;&lt;img src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427203907.png&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;tag-plugin quot&quot;&gt;&lt;p class=&quot;content&quot; type=&quot;text&quot;&gt;这个故事还没有结束。&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;使用Vue.js开发的流式程式。&lt;/p&gt;</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="vue" scheme="https://www.i5res.com/tags/vue/"/>
    
    <category term="js" scheme="https://www.i5res.com/tags/js/"/>
    
    <category term="webpack" scheme="https://www.i5res.com/tags/webpack/"/>
    
  </entry>
  
  <entry>
    <title>MOTD平台 | Motd Platform（已停止运营）</title>
    <link href="https://www.i5res.com/projects/minecraft/minecraft-motd-proj.html"/>
    <id>https://www.i5res.com/projects/minecraft/minecraft-motd-proj.html</id>
    <published>2021-03-05T05:50:53.000Z</published>
    <updated>2023-12-14T12:44:33.323Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><div class="tag-plugin gallery swiper" id="swiper-api" width="max"><div class="swiper-wrapper"><div class="swiper-slide"><img no-lazy src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201617.png" fancybox="true"/></div><div class="swiper-slide"><img no-lazy src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201602.png" fancybox="true"/></div><div class="swiper-slide"><img no-lazy src="https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201610.png" fancybox="true"/></div></div><div class="swiper-pagination"></div><div class="swiper-button-prev blur"></div><div class="swiper-button-next blur"></div></div><div class="tag-plugin quot"><p class="content" type="text">精准化高质量的服务器排行榜，服务器状态监控平台！</p></div><span id="more"></span><h1 id="接口详情"><a href="#接口详情" class="headerlink" title="接口详情"></a>接口详情</h1><p>通过UDP协议获取MCPE的服务器状态</p><div class="tag-plugin colorful note" color="green"><div class="title"><strong>接口地址如下</strong></div><div class="body"><p>请求方式：<code>GET/POST</code></p><div class="tag-plugin copy"><input class="copy-area" readonly id="copy_18" value="已停止维护！"><button class="copy-btn" onclick="util.copy(&quot;copy_18&quot;,&quot;Copied!&quot;)"><svg class="icon copy-btn" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg></button></div>接口已经托管，并且支持SSL（广州）</div></div><h2 id="请求参数"><a href="#请求参数" class="headerlink" title="请求参数"></a>请求参数</h2><table><thead><tr><th>参数</th><th>示例</th><th>描述</th></tr></thead><tbody><tr><td>ip</td><td>mc.52craft.cc</td><td>服务器IP地址</td></tr><tr><td>port</td><td>2020</td><td>服务器端口</td></tr><tr><td>java</td><td>null</td><td>Java服务器接口</td></tr></tbody></table><h2 id="返回参数"><a href="#返回参数" class="headerlink" title="返回参数"></a>返回参数</h2><table><thead><tr><th>参数</th><th>示例</th><th>描述</th></tr></thead><tbody><tr><td>code</td><td>200</td><td>接口响应状态码</td></tr><tr><td>status</td><td>online</td><td>服务器状态</td></tr><tr><td>ip</td><td>mc.52craft.cc</td><td>返回查询IP</td></tr><tr><td>port</td><td>2020</td><td>返回查询端口</td></tr><tr><td>real</td><td>222.22.333.22</td><td>真实IP地址</td></tr><tr><td>location</td><td>北京省 联通</td><td>线路所在位置</td></tr><tr><td>motd</td><td>BorderLands In Minecraft</td><td>服务器广播内容Motd</td></tr><tr><td>agreement</td><td>389</td><td>协议版本</td></tr><tr><td>version</td><td>1.14.30</td><td>客户端版本</td></tr><tr><td>online</td><td>3</td><td>服务器在线人数</td></tr><tr><td>max</td><td>10</td><td>服务器人数上限</td></tr><tr><td>gamemode</td><td>Survival</td><td>游戏模式</td></tr><tr><td>delay</td><td>64</td><td>连接服务器延迟(ms)</td></tr></tbody></table><h2 id="错误码"><a href="#错误码" class="headerlink" title="错误码"></a>错误码</h2><table><thead><tr><th>错误码</th><th>描述</th></tr></thead><tbody><tr><td>200</td><td>正常</td></tr><tr><td>201</td><td>无法与输入地址握手</td></tr><tr><td>202</td><td>无法建立UDP连接（基岩版）</td></tr><tr><td>203</td><td>无法解析Hex（基岩版）</td></tr></tbody></table><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><div class="tag-plugin ghcard"><a class="ghcard" rel="external nofollow noopener noreferrer" href="https://github.com/PluginsKers/Motd_for_Minecraft"><img src="https://github-readme-stats.xaoxuu.com/api/pin/?username=PluginsKers&repo=Motd_for_Minecraft&&show_owner=true"/></a></div>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;tag-plugin gallery swiper&quot; id=&quot;swiper-api&quot; width=&quot;max&quot;&gt;&lt;div class=&quot;swiper-wrapper&quot;&gt;&lt;div class=&quot;swiper-slide&quot;&gt;&lt;img no-lazy src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201617.png&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;swiper-slide&quot;&gt;&lt;img no-lazy src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201602.png&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;swiper-slide&quot;&gt;&lt;img no-lazy src=&quot;https://fastly.i5res.com/gh/pluginskers/cdn/2021/20210427201610.png&quot; fancybox=&quot;true&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;swiper-pagination&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-prev blur&quot;&gt;&lt;/div&gt;&lt;div class=&quot;swiper-button-next blur&quot;&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;tag-plugin quot&quot;&gt;&lt;p class=&quot;content&quot; type=&quot;text&quot;&gt;精准化高质量的服务器排行榜，服务器状态监控平台！&lt;/p&gt;&lt;/div&gt;</summary>
    
    
    
    <category term="折腾不止" scheme="https://www.i5res.com/categories/%E6%8A%98%E8%85%BE%E4%B8%8D%E6%AD%A2/"/>
    
    
    <category term="vue" scheme="https://www.i5res.com/tags/vue/"/>
    
    <category term="webpack" scheme="https://www.i5res.com/tags/webpack/"/>
    
    <category term="php" scheme="https://www.i5res.com/tags/php/"/>
    
    <category term="minecraft" scheme="https://www.i5res.com/tags/minecraft/"/>
    
  </entry>
  
</feed>
