<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[n1cat's blog]]></title><description><![CDATA[my first blog ><]]></description><link>https://n1cat.xyz</link><image><url>https://n1cat.xyz/favicon.ico</url><title>n1cat&apos;s blog</title><link>https://n1cat.xyz</link></image><generator>Shiro (https://github.com/Innei/Shiro)</generator><lastBuildDate>Sat, 01 Aug 2026 15:15:20 GMT</lastBuildDate><atom:link href="https://n1cat.xyz/feed" rel="self" type="application/rss+xml"/><pubDate>Sat, 01 Aug 2026 15:15:20 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[在 Linux 中使用 Radmin VPN]]></title><description><![CDATA[<link rel="preload" as="image" href="https://api.n1cat.xyz/api/v2/objects/image/x2yngqayczpwvjicmm.png"/><div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/linux/radmin">https://n1cat.xyz/posts/linux/radmin</a></blockquote><div><h2 id="">前言</h2><p>我目前主力設備是 Linux。有天我朋友邀請我來去玩他Minecraft區域網路的伺服器，他使用的是 <a href="https://www.radmin-vpn.com/">Radmin VPN</a> 來作為虛擬區網的工具。但我在網路上查了一下目前 Radmin VPN 對 Linux 的支援基本上沒有，論壇寫說計畫加入，但目前還沒有看到有相關訊息。
<a href="https://radmin-club.com/radmin-vpn/will-radmin-vpn-be-ported-to-linux/#:~:text=Radmin%20VPN%20is%20not%20currently,for%20Linux%2Dcompatible%20VPN%20solutions.">orinigal post</a>
<img src="https://api.n1cat.xyz/api/v2/objects/image/x2yngqayczpwvjicmm.png" height="614" width="646"/></p><h2 id="">問題背景</h2><p>我一開始想到的解法是直接用 WinBoat 去直做 NAT，然後把 Radmin VPN 分享給 Linux。
但我發現我裝的Win10 LTSC 2021沒有<code>MSFT_NetNat</code>，所以不能用正常的 WinNAT 建立 NAT。</p><p>我也嘗試過用ICS網路共享(<del>我去查了一下他中文就叫因特網聯機共用</del>)，但不知道為啥他會把我 WinBoat VM 的管理入口跟 Guest API 搞爆 所以沒採用。</p><h2 id="">採用的方案</h2><p>後來我改成只代理 Minecraft Java 需要的 TCP 連線。
Linux 端直接透過 <code>127.0.0.1:25565</code> 連線。</p><p>WinBoat 則是用 <code>netsh interface portproxy</code> 把 <code>25565</code> 轉發到對方在 Radmin 網路裡的 IP 和 LAN Port。
以我這次的案例：</p><ul><li>對方 Radmin IP：<code>26.46.97.252</code></li><li><p>對方 Minecraft LAN Port：<code>14514</code></p><p>也就是說，WinBoat 會接收本地 <code>25565</code> 的 TCP 連線，再轉到 <code>26.46.97.252:14514</code>。</p></li></ul><h2 id="docker--winboat-">Docker / WinBoat 設定</h2><p>一開始我以為只要在 Docker Compose 加上：</p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">127.0.0.1:25565:25565/tcp
</code></pre>
<p>就夠了。但實際上這 image 還有一層 guest forwarding，也就是說路線是：host port -&gt; contaniner -&gt; Windows guest。</p><p>所以除了加到 <code>ports</code>，還要把 <code>25565</code> 加到 <code>USER_PORTS</code>。</p><p>我的 Compose 大概長這樣：</p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">environment:
  USER_PORTS: &quot;7148,25565&quot;

ports:
  - 127.0.0.1:25565:25565/tcp
  - 127.0.0.1:47270:8006
  - 127.0.0.1:47280:7148
  - 127.0.0.1:47290:7149
  - 127.0.0.1:47300:3389/tcp
  - 127.0.0.1:47310:3389/udp

restart: unless-stopped
</code></pre>
<p>其中：</p><ul><li><code>25565</code> 是 Minecraft代理入口</li><li><code>47270</code> 是 Winboat Web 管理畫面</li><li><p><code>47300</code> 是固定的 RDP port</p><p>我也把管理port改成固定值，避免每次重啟 container 後 port 號漂移。</p></li></ul><h2 id="windows-vm-">Windows VM 內的設定</h2><p>Windows VM 要先確保 <code>iphlpsvc</code> 有啟動，因為 <code>portproxy</code> 依賴這東東。</p><pre class="language-powershell lang-powershell"><code class="language-powershell lang-powershell">Set-Service iphlpsvc -StartupType Automatic
Start-Service iphlpsvc
</code></pre>
<p>然後建立轉發：</p><pre class="language-powershell lang-powershell"><code class="language-powershell lang-powershell">netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=25565
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=25565 connectaddress=26.46.97.252 connectport=14514
netsh interface portproxy show all
</code></pre>
<p>來分析一下這段是啥：</p><ul><li>Windows VM 在本地 <code>0.0.0.0:25565</code> 監聽</li><li><p>所有進來的 TCP 連線都會轉到 <code>26.46.97.252:14514</code></p><p>好了之後讓我們進行一下測試看有沒有辦法通<del>(不要到最後才發現是自己/對方Radmin沒開好排錯了老半天)</del></p></li></ul><pre class="language-powershell lang-powershell"><code class="language-powershell lang-powershell">Test-NetConnection 26.46.97.252 -Port 14514
</code></pre>
<p>照理來說你會看到：</p><pre class="language-powershell lang-powershell"><code class="language-powershell lang-powershell">ComputerName     : 26.46.97.252
RemoteAddress    : 26.46.97.252
RemotePort       : 14514
InterfaceAlias   : Radmin VPN
SourceAddress    : 26.39.180.254 &lt;- 這是你自己的
TcpTestSucceeded : True
</code></pre>
<h2 id="linux-">Linux 端要怎麼連</h2><p>其實該設定的地方都在 VM 裡面就設定好了，所以反而 Linux 不用額外設定。
直接在多人遊戲的 IP 欄位填 127.0.0.1:25565，流量就會都走代理到 VM 裡面。</p><p>::: warning
注意：這裡IP如果填 26.xx.xx.xx 的話是連不上的，因為那樣完全繞過了我們剛剛設定的代理。
:::</p><p>如果你的 WinBoat container 有設定 startup 的話 那基本上開機就可以直接開 Minecraft 連線。</p><h2 id="">題外話</h2><p>我知道這作法很簡單粗暴，受限場景很多。例如如果朋友換端口開的時候又要重新設定一次，或其他服務需要用其他 port 時要新增規則等等。但我覺得如果只是拿來連 Minecraft 區網伺服器的話，應該是綽綽有餘了。</p><p>另外如果有錯誤的地方，還吝請各位賜教。謝謝！</p></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/linux/radmin#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/linux/radmin</link><guid isPermaLink="true">https://n1cat.xyz/posts/linux/radmin</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Tue, 14 Apr 2026 15:35:26 GMT</pubDate></item><item><title><![CDATA[n1cat's Osu Page]]></title><description><![CDATA[<link rel="preload" as="image" href="https://api.n1cat.xyz/api/v2/objects/icon/iojs22al4jz0q6xtgk.png"/><link rel="preload" as="image" href="https://api.n1cat.xyz/api/v2/objects/icon/1etmwgc233g7czkra0.png"/><div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/default/osu">https://n1cat.xyz/posts/default/osu</a></blockquote><div><p>這是拿來紀念我<del>破爛的</del>osu遊戲過程</p><p>First 100pp |  <strong>2025/05/27</strong> | <a href="https://osu.ppy.sh/beatmapsets/325112#osu/722235">Roses Epicurean – Yoru no Kodomo tachi by CodeS</a> <strong>+SDNC</strong> | 117pp<br/>First 200pp | <strong>2025/10/10</strong> | <a href="https://osu.ppy.sh/beatmaps/1593847">XXXTENTACION - SAD!</a>  <strong>+HDDT</strong> | 208pp
6-Digits 2024/11/07
5-Digits not yet</p><p><img src="https://api.n1cat.xyz/api/v2/objects/icon/iojs22al4jz0q6xtgk.png" height="266" width="551"/></p><p><img src="https://api.n1cat.xyz/api/v2/objects/icon/1etmwgc233g7czkra0.png"/>
畫面中出現的那個de是<a href="https://osu.ppy.sh/users/21047478/osu">owen</a>寶</p></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/default/osu#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/default/osu</link><guid isPermaLink="true">https://n1cat.xyz/posts/default/osu</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Wed, 15 Oct 2025 15:50:10 GMT</pubDate></item><item><title><![CDATA[處理 Wayland 下 Fcitx5 在 Electron 應用中失效的除錯紀錄]]></title><description><![CDATA[<div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/linux/fcitx-in-wayland">https://n1cat.xyz/posts/linux/fcitx-in-wayland</a></blockquote><div><h3 id="">前言</h3><p>你是否也遇過這種令人抓狂的場景？在 Arch Linux + Wayland 的新潮環境下，你的 Fcitx5 輸入法在 Chrome、Kitty、系統 UI 中都運作得完美無瑕，但唯獨在打開 Discord、VSCode 或是 Obsidian 這些軟體時，它卻像罷工一樣，無論怎麼切換都毫無反應。</p><p>如果你已經在網路上爬文許久，試過了修改 <code>.desktop</code> 啟動器、檢查了無數次的環境變數 (<code>GTK_IM_MODULE</code>, <code>XMODIFIERS</code>)，甚至開始懷疑人生，那麼這篇文章就是為你準備的。</p><p>::: warning
<strong>前情提要：</strong>
這篇文章假設你已經在 Wayland 環境下正確設定了 Fcitx5 的基本環境變數，並且它在大多數 GTK/Qt 應用中是可以正常運作的。我們的目標是解決那些特例軟體。
:::</p><h3 id="-wayland-">核心概念：問題不在你的設定，在於 Wayland 的「原生模式」</h3><p>在深入解決方案之前，我們必須先理解問題的根源。過去在 X11 環境下，輸入法的問題通常圍繞在 <code>XMODIFIERS</code> 這個環境變數上。但到了 Wayland，事情變得有些不同。</p><p>應用程式在 Wayland 環境下有兩種執行模式：</p><ol start="1"><li><strong>原生 Wayland 模式</strong>：應用程式直接使用 Wayland 協定進行繪圖和輸入，這是最理想的模式。</li><li><strong>XWayland 模式</strong>：這是一個相容性層，讓那些尚未支援 Wayland 的傳統 X11 應用程式也能在 Wayland 環境下執行。</li></ol><p>問題就出在，Discord、VSCode 這些軟體背後的框架 <strong>Electron</strong>，在新版本中會預設以「原生 Wayland 模式」啟動。然而，<strong>Electron 對 Wayland 原生輸入法協定的支援一直以來都非常糟糕</strong>，導致它根本無法和 Fcitx5 正常溝通。</p><p>這也解釋了為什麼你之前嘗試的所有方法都失敗了：</p><ul><li><strong>修改 <code>XMODIFIERS</code></strong>：這個變數是 X11/XWayland 的產物。當 Discord 以原生 Wayland 模式執行時，它會完全忽略這個變數。</li><li><strong>設定 <code>GTK_IM_MODULE</code></strong>：Electron 並非標準的 GTK 應用，它有自己的一套邏輯，因此這些變數對它的影響有限。</li></ul><hr/><h3 id="-xwayland">最終解決方案：強制使用 XWayland</h3><p>既然問題的根源是不完善的「原生 Wayland 模式」，那麼最直接、最有效的解決方法就是——<strong>強制這些 Electron 應用退回使用相容性更好的 XWayland 模式來執行</strong>。</p><p>只要回到 XWayland 的世界，我們熟悉的規則就會再次生效，Fcitx5 也能夠順利接管輸入。而實現這一點的關鍵，就是透過一個全域設定檔。</p><h3 id="-electron-flagsconf">操作步驟：一勞永逸的 <code>electron-flags.conf</code></h3><p>相比於去修改每一個應用程式的 <code>.desktop</code> 啟動器（這種方式不僅繁瑣，還可能在軟體更新後被覆蓋），直接建立一個 Electron 的全域設定檔是更優雅、更徹底的做法。</p><ol start="1"><li><p><strong>開啟你的終端機：</strong>
沒錯，一切的起點。</p></li><li><p><strong>建立並編輯設定檔：</strong>
使用你喜歡的編輯器，建立或打開 <code>~/.config/electron-flags.conf</code> 這個檔案。</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">nano ~/.config/electron-flags.conf
</code></pre>
</li><li><p><strong>加入關鍵參數：</strong>
在檔案中，只需要加入下面這一行文字。這個參數會告訴所有讀取此設定檔的 Electron 應用：「請使用 X11 後端來啟動」，在 Wayland 環境下，這就等同於強制使用 XWayland。</p><pre class=""><code class="">--ozone-platform=x11
</code></pre>
</li><li><p><strong>儲存並重啟應用：</strong>
儲存檔案後，<strong>完全退出</strong>你的 Discord、VSCode 或其他有問題的 Electron 應用（記得檢查系統匣，確保它們徹底關閉）。</p><p>現在，重新打開它們，你會驚喜地發現，消失已久的 Fcitx5 輸入法視窗終於回來了！</p></li></ol><blockquote class="markdown-alert-warning"><header>WARNING</header><p>這個設定是全域性的。它會影響到你系統上所有會讀取此設定檔的 Electron 應用。不過在絕大多數情況下，這正是我們想要的效果，因為它解決的是一類問題，而不是單一一個軟體的問題。</p></blockquote>
<h3 id="">總結</h3><p>讓我們快速回顧一下這個「終極療法」的流程：</p><ol start="1"><li><strong>問題分析</strong>：Electron 應用預設使用不完善的「原生 Wayland 模式」，導致輸入法失效。</li><li><strong>解決思路</strong>：建立一個全域設定檔，強制所有 Electron 應用退回相容性更好的「XWayland 模式」。</li><li><strong>核心操作</strong>：在 <code>~/.config/electron-flags.conf</code> 檔案中加入 <code>--ozone-platform=x11</code>。</li><li><strong>享受成果</strong>：重新啟動應用，享受在所有軟體中都能流暢輸入的便利！</li></ol><p>這是一個非常簡單卻極其有效的技巧，希望能幫助你在 Wayland 的道路上走得更順暢。</p></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/linux/fcitx-in-wayland#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/linux/fcitx-in-wayland</link><guid isPermaLink="true">https://n1cat.xyz/posts/linux/fcitx-in-wayland</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Sat, 20 Sep 2025 08:53:59 GMT</pubDate></item><item><title><![CDATA[打造 Windows 上的 C++ 開發環境：從零到一的 VS Code + MinGW-w64 指南]]></title><description><![CDATA[<div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/code/cpp">https://n1cat.xyz/posts/code/cpp</a></blockquote><div><p>::: error
本文有些許錯誤尚未修改
:::</p><h3 id="">前言</h3><p>想在 Windows 上學習 C++，卻被複雜的環境設定搞得頭昏腦脹嗎？相較於 Visual Studio 整個大型 IDE，許多人更偏好使用輕量、高彈性的 Visual Studio Code (VS Code) 來打造自己的開發環境。</p><p>本文件旨在引導你完成在 Windows 系統上，從零開始，一步步建立一個現代化的 C++ 開發環境。我們將使用目前最主流的組合：<strong>VS Code</strong> 作為程式碼編輯器，搭配 <strong>MinGW-w64</strong> 作為編譯器工具鏈。</p><p>::: warning
<strong>前情提要：</strong>
這篇文章假設你的電腦是 Windows 10 或 Windows 11 作業系統，並且你已準備好跟著步驟從頭開始。我們將會安裝所有需要的軟體，無需任何先前經驗。
:::</p><h3 id="">核心概念：我們到底在做什麼？</h3><p>在開始動手前，先花一分鐘了解我們要安裝的三個核心元件，這會讓整個流程變得更清晰：</p><ol start="1"><li><p><strong>程式碼編輯器 (Code Editor) - Visual Studio Code</strong></p><ul><li>這就是我們寫程式碼的地方。它本身只是個聰明的記事本，提供了語法高亮、自動補全等功能，但它並不知道如何將你的 C++ 程式碼變成可執行的 <code>.exe</code> 檔案。</li></ul></li><li><p><strong>編譯器 (Compiler) - MinGW-w64 (g++)</strong></p><ul><li>這是最重要的工具。編譯器的工作就是把你寫的 C++ 原始碼（人類看得懂的文字）翻譯成電腦看得懂的機器碼，並打包成一個 <code>.exe</code> 執行檔。我們選擇 MinGW-w64，它讓我們可以在 Windows 上使用強大的 GCC (GNU Compiler Collection) 工具集。</li></ul></li><li><p><strong>偵錯器 (Debugger) - GDB</strong></p><ul><li>當你的程式碼出錯時，偵錯器是你最好的朋友。它能讓你一行一行地執行程式，觀察變數的變化，揪出躲在細節裡的魔鬼。GDB 會跟著 MinGW-w64 一起被安裝。</li></ul></li></ol><p>簡單來說，我們就是要<strong>安裝並設定好這三樣工具，並讓它們在 VS Code 裡完美協作</strong>。</p><hr/><h3 id="">操作步驟：</h3><h4 id="part-1--visual-studio-code">Part 1: 安裝 Visual Studio Code</h4><p>這是最簡單的一步。</p><ol start="1"><li>前往 <a href="https://code.visualstudio.com/">VS Code 的官方網站</a>。</li><li>點擊大大的下載按鈕，下載適用於 Windows 的穩定版。</li><li>執行安裝檔。在安裝過程中，請確保勾選了「<strong>新增到 PATH (需要重新啟動後生效)</strong>」這個選項，這會讓你之後在終端機操作更方便。其他選項保持預設即可。</li></ol><h4 id="part-2--mingw-w64-">Part 2: 安裝 MinGW-w64 編譯器與設定環境變數</h4><p>這是最關鍵也最容易出錯的一步，請務必仔細操作。</p><ol start="1"><li><p><strong>下載 MinGW-w64：</strong></p><ul><li>為了避免從複雜的官方頁面中尋找，我們推薦從 <a href="https://winlibs.com/">WinLibs</a> 這個網站下載獨立的 MinGW-w64 發行版。它打包完整且無需安裝。</li><li>前往 WinLibs 網站，找到最新的 <strong><a href="https://winlibs.com/#:~:text=a%20good%20choice.-,Download%20it%20here.,-Release%20versions">UCRT runtime</a></strong> 版本的 &quot;Win64&quot; 發行版，並下載 ZIP 壓縮檔。</li></ul></li><li><p><strong>解壓縮檔案：</strong></p><ul><li>將下載下來的 ZIP 檔解壓縮。為了方便管理，建議你將解壓縮後的 <code>mingw64</code> 資料夾，直接放到一個路徑單純且<strong>不包含中文或空格</strong>的地方，例如 <code>C:\mingw64</code>。</li></ul></li><li><p><strong>設定 PATH 環境變數：</strong></p><ul><li>這是為了讓系統在任何地方都能找到 <code>g++.exe</code> 這個編譯器指令。</li><li>在 Windows 搜尋列中輸入「<strong>編輯系統環境變數</strong>」並開啟它。</li><li>在跳出的視窗中，點擊「<strong>環境變數</strong>」。</li><li>在下方的「<strong>系統變數</strong>」區塊中，找到名為 <code>Path</code> 的變數，點選它，然後按「<strong>編輯</strong>」。</li><li>點擊「<strong>新增</strong>」，然後將你剛剛解壓縮的 MinGW-w64 資料夾中的 <code>bin</code> 資料夾路徑貼上去。例如，如果你是放在 <code>C:\mingw64</code>，那這裡就要新增 <code>C:\mingw64\bin</code>。</li><li>一路點擊「確定」關閉所有設定視窗。</li></ul></li><li><p><strong>驗證安裝：</strong></p><ul><li><strong>完全關閉</strong>所有已開啟的終端機或 PowerShell 視窗，然後重新開啟一個新的。</li><li>在終端機中，分別輸入以下兩個指令並按下 Enter：
<code>bash
g++ --version
gdb --version
</code></li><li>如果你能看到類似下圖的版本號碼訊息，而沒有出現「不是內部或外部命令」的錯誤，那就代表編譯器和偵錯器已經成功安裝並設定好了！</li></ul></li></ol><h4 id="part-3--vs-code-">Part 3: 設定 VS Code 延伸模組</h4><p>讓 VS Code 變身為強大 C++ IDE 的最後一步。</p><ol start="1"><li>打開 VS Code。</li><li>點擊左側邊欄的延伸模組圖示 (像四個方塊的那個)。</li><li>在搜尋框中輸入 <code>C/C++</code>，並安裝由 <strong>Microsoft</strong> 官方提供的「<strong>C/C++ Extension Pack</strong>」。它會幫我們裝好智慧提示 (IntelliSense)、偵錯等所有需要的功能。</li></ol><h3 id="-c-hello-world">你的第一個 C++ 程式：Hello, World!</h3><p>環境都準備好了，讓我們來實際跑一個程式，並完成最後的編譯設定。</p><ol start="1"><li><p><strong>建立專案資料夾：</strong>
在電腦上找個喜歡的地方，建立一個新的資料夾，例如 <code>CppProjects</code>，然後在裡面再建立一個名為 <code>HelloWorld</code> 的資料夾。</p></li><li><p><strong>用 VS Code 開啟資料夾：</strong>
在 VS Code 中，選擇「檔案」&gt;「開啟資料夾...」，然後選擇你剛剛建立的 <code>HelloWorld</code> 資料夾。</p></li><li><p><strong>建立原始碼檔案：</strong>
在 VS Code 左側的檔案總管中，點擊新增檔案的圖示，並將檔案命名為 <code>main.cpp</code>。</p></li><li><p><strong>撰寫程式碼：</strong>
將以下經典的 &quot;Hello, World!&quot; 程式碼貼到 <code>main.cpp</code> 中。</p><pre class="language-cpp lang-cpp"><code class="language-cpp lang-cpp">#include &lt;iostream&gt;

int main() {
    std::cout &lt;&lt; &quot;Hello, C++ World!&quot; &lt;&lt; std::endl;
    return 0;
}
</code></pre>
</li><li><p><strong>設定編譯與偵錯任務 (關鍵步驟)：</strong></p><ul><li>按下 <code>F5</code> 鍵，這會觸發 VS Code 的偵錯功能。</li><li>此時，VS Code 會在上方跳出一個選單，詢問你使用哪個環境。請選擇「<strong>C++ (GDB/LLDB)</strong>」。</li><li>接著，它會再問你要使用哪個編譯器設定。選擇「<strong>g++.exe ... build and debug active file</strong>」。</li><li>完成後，VS Code 會自動在你的資料夾中建立一個 <code>.vscode</code> 資料夾，並在裡面產生 <code>tasks.json</code> 和 <code>launch.json</code> 兩個設定檔。同時，你會看到下方的終端機開始執行編譯，並成功輸出 &quot;Hello, C++ World!&quot;。</li></ul></li></ol><blockquote class="markdown-alert-warning"><header>WARNING</header><p>VS Code 自動產生的這兩個 JSON 檔案，就是告訴它如何呼叫 <code>g++</code> 來編譯你的程式 (<code>tasks.json</code>)，以及如何啟動 <code>gdb</code> 來偵錯編譯好的程式 (<code>launch.json</code>)。對於初學者來說，通常不需要手動修改它們。</p></blockquote>
<h3 id="">總結</h3><p>讓我們快速回顧一次整個流程：</p><ol start="1"><li><strong>安裝 VS Code</strong>，並記得勾選加入 PATH。</li><li><strong>下載並解壓縮 MinGW-w64</strong> 到一個簡單的路徑 (如 <code>C:\mingw64</code>)。</li><li><strong>設定系統環境變數 <code>Path</code></strong>，將 MinGW-w64 的 <code>bin</code> 資料夾路徑加進去，並在終端機用 <code>g++ --version</code> 驗證。</li><li>在 VS Code 中<strong>安裝 Microsoft 官方的 C/C++ 延伸模組包</strong>。</li><li>建立你的第一個 <code>.cpp</code> 檔案，按下 <strong>F5</strong>，讓 VS Code 自動產生編譯與偵錯設定。</li></ol><p>恭喜你！你已經成功在 Windows 上搭建了一個輕量、高效且功能完整的 C++ 開發環境。現在，開始你的 C++ 學習之旅吧！</p></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/code/cpp#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/code/cpp</link><guid isPermaLink="true">https://n1cat.xyz/posts/code/cpp</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Mon, 08 Sep 2025 02:51:38 GMT</pubDate></item><item><title><![CDATA[ssh-copy-id 使用教學：快速設定 SSH 免密碼登入]]></title><description><![CDATA[<div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/linux/ssh-copy-id">https://n1cat.xyz/posts/linux/ssh-copy-id</a></blockquote><div><h3 id="">前言</h3><p>本文件旨在說明如何透過 <code>ssh-copy-id</code> 這個方便的指令，將你的 SSH 公鑰快速且安全地部署到遠端的 VPS 或伺服器上。從此以後，你就可以擺脫每次登入都要輸入密碼的繁瑣步驟，實現更安全、更有效率的免密碼登入。</p><p>::: warning
<strong>前情提要：</strong>
這篇文章假設你已經在你的本機（例如你的筆電或桌機）上產生了 SSH 金鑰對（<code>id_rsa</code> 和 <code>id_rsa.pub</code>）。如果還沒有，可以先透過 <code>ssh-keygen -t rsa</code> 指令來產生。
:::</p><h3 id="">核心概念</h3><p><code>ssh-copy-id</code> 的核心工作非常單純：它會讀取你本機的公鑰檔案（預設是 <code>~/.ssh/id_rsa.pub</code>），然後透過 SSH 連線到遠端主機，並將公鑰內容自動附加到遠端主機使用者家目錄下的 <code>~/.ssh/authorized_keys</code> 檔案中。</p><p>這個指令最大的好處是，它會自動處理好遠端 <code>.ssh</code> 目錄和 <code>authorized_keys</code> 檔案的權限設定，避免了手動複製貼上時，因為權限錯誤（例如 <code>777</code> 或 <code>644</code>）而導致金鑰驗證失敗的問題。</p><hr/><h3 id="">操作步驟：</h3><ol start="1"><li><p><strong>準備環境：</strong>
你需要一台網路正常的遠端 VPS 或主機，並且你目前能夠透過密碼的方式以 SSH 登入。</p></li><li><p><strong>開啟你的終端機：</strong>
在你的<strong>本機</strong>上打開終端機（Terminal、iTerm、Windows Terminal 等）。</p></li><li><p><strong>執行 <code>ssh-copy-id</code> 指令：</strong>
這是最關鍵的一步。指令的格式非常簡單：</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash"># 基本語法
# ssh-copy-id [遠端使用者名稱]@[遠端主機IP或網域]

# 實際範例
ssh-copy-id root@123.123.123.123
</code></pre>
</li><li><p><strong>輸入密碼並完成驗證：</strong>
執行指令後，系統會提示你輸入遠端主機的登入密碼。</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@123.123.123.123&#x27;s password:
</code></pre><p>請在這裡輸入密碼。這<strong>將是你最後一次</strong>需要為這台主機輸入密碼。成功後，你會看到類似以下的訊息：</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">Number of key(s) added: 1

Now try logging into the machine, with:   &quot;ssh &#x27;root@123.123.123.123&#x27;&quot;
and check for:

  .ssh/authorized_keys

to make sure we haven&#x27;t added extra keys that you weren&#x27;t expecting.
</code></pre><p>這就代表你的公鑰已經成功安裝上去了！</p></li><li><p><strong>測試免密碼登入：</strong>
現在，嘗試直接登入你的遠端主機，看看是否還需要密碼。</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">ssh root@123.123.123.123
</code></pre><p>如果一切順利，你應該會直接登入成功，不會再被要求輸入密碼。</p></li></ol><h3 id="">進階技巧與注意事項</h3><blockquote class="markdown-alert-warning"><header>WARNING</header><p>如果你的公鑰檔案不是預設的路徑（<code>~/.ssh/id_rsa.pub</code>），或是你想要指定使用某個特定的公鑰，你可以使用 <code>-i</code> 參數來指定公鑰檔案的路徑。</p></blockquote>
<pre class="language-bash lang-bash"><code class="language-bash lang-bash"># 範例：使用名為 my_vps_key.pub 的公鑰
ssh-copy-id -i ~/.ssh/my_vps_key.pub user@your_server_ip
</code></pre>
<h3 id="">總結</h3><p>使用 <code>ssh-copy-id</code> 的流程如下：</p><ol start="1"><li>確保本機已有 SSH 金鑰對。</li><li>在<strong>本機</strong>終端機執行 <code>ssh-copy-id [使用者]@[主機IP]</code>。</li><li>輸入<strong>最後一次</strong>的登入密碼。</li><li>享受無密碼登入的便利！</li></ol><p>這是一個非常簡單卻極其有用的指令，強烈建議所有管理伺服器的人都學會使用它。</p></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/linux/ssh-copy-id#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/linux/ssh-copy-id</link><guid isPermaLink="true">https://n1cat.xyz/posts/linux/ssh-copy-id</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Sun, 31 Aug 2025 10:17:48 GMT</pubDate></item><item><title><![CDATA[Discord.js v14 新版 Components (V2) 使用指南]]></title><description><![CDATA[<div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/discord_bot/discord-components-v2">https://n1cat.xyz/posts/discord_bot/discord-components-v2</a></blockquote><div><h2 id="">前言</h2><p>本文件旨在詳細說明如何使用 Discord.js v14 中引入的新版訊息元件 (Components V2)。這些新元件提供了比以往更豐富、更具結構性的訊息排版能力。</p><h2 id="">核心概念</h2><p>新版元件的核心是 <strong>容器 (Container)</strong>，所有其他元件都必須被包裹在一個頂層容器中。這與傳統的 <code>ActionRow</code> 有所不同，提供了更大的排版自由度。</p><h3 id="1--v2-components">1. 啟用 V2 Components</h3><p>要使用新版元件，最關鍵的一步是在 <code>interaction.reply</code> 中設定 <code>flags</code> 屬性。如果沒有這個旗標，Discord 將會回退到舊版的 Components，導致顯示錯誤或完全不顯示。</p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { MessageFlags } from &quot;discord.js&quot;;

await interaction.reply({
  // ... 其他選項
  flags: MessageFlags.IsComponentsV2,
});
</code></pre>
<h4 id="">組合多個旗標</h4><p>如果您需要同時使用多個旗標（例如，同時啟用 V2 Components 並將訊息設為臨時訊息），您可以使用位元「或」運算子 (<code>|</code>) 來組合它們。</p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { MessageFlags } from &quot;discord.js&quot;;

await interaction.reply({
  // ... 其他選項
  flags: MessageFlags.IsComponentsV2 | MessageFlags.Ephemeral,
});
</code></pre>
<p>這樣，回覆的訊息將只對發送該指令的使用者可見。</p><h2 id="2--builders">2. 元件建構器 (Builders)</h2><p>以下是 Components V2 中常用的各種建構器。</p><h3 id="-containerbuilder">主容器 <code>ContainerBuilder</code></h3><p>所有 V2 元件都必須放在一個 <code>ContainerBuilder</code> 實例中。您可以把它想像成一個包裹所有內容的頂層容器。</p><p><code>ContainerBuilder</code> 也可以設定一些排版屬性，例如使用 <code>.setAccentColor()</code> 方法來設定左側的強調色。</p><p><strong>方法一：手動加入元件 (如範例所示)</strong></p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { ContainerBuilder, TextDisplayBuilder } from &quot;discord.js&quot;;

const container = new ContainerBuilder();
const title = new TextDisplayBuilder().setContent(&quot;# 這是標題&quot;);

// 將元件實例按順序 push 到 container.components 陣列中
container.components.push(title);
</code></pre>
<p><strong>方法二：使用鏈式方法 (官方文件風格)</strong></p><p><code>ContainerBuilder</code> 提供了一系列 <code>.add...Components()</code> 的方法，讓您可以用鏈式呼叫的方式加入元件，程式碼更簡潔。</p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { ContainerBuilder, UserSelectMenuBuilder } from &#x27;discord.js&#x27;;

const exampleContainer = new ContainerBuilder()
    .setAccentColor(0x0099FF)
    .addTextDisplayComponents(
        textDisplay =&gt; textDisplay
            .setContent(&#x27;這是一個文字元件！&#x27;)
    )
    .addActionRowComponents(
        actionRow =&gt; actionRow
            .setComponents(
                new UserSelectMenuBuilder()
                    .setCustomId(&#x27;exampleSelect&#x27;)
                    .setPlaceholder(&#x27;選擇使用者&#x27;),
            ),
    );
</code></pre>
<h3 id="">基礎內容元件</h3><ul><li><strong><code>TextDisplayBuilder</code></strong>: 用於顯示文字內容，支援 Markdown 語法。您可以把它當作一個文字區塊。</li><li><strong><code>MediaGalleryBuilder</code></strong>: 用於顯示圖片或媒體。您可以加入多個媒體項目來建立一個畫廊。</li><li><strong><code>SeparatorBuilder</code></strong>: 用於在元件之間加入一條分隔線或間距，讓排版更清晰。</li><li><strong><code>ActionRowBuilder</code></strong>: 與舊版相似，用於放置按鈕 (<code>ButtonBuilder</code>)、選單 (<code>StringSelectMenuBuilder</code>) 等互動元件。</li></ul><h3 id="">進階內容元件</h3><h4 id="sectionbuilder-"><code>SectionBuilder</code> (區塊元件)</h4><p><code>SectionBuilder</code> 是一個強大的元件，它本身可以容納最多三個 <code>TextDisplay</code> 元件，並且可以在右側附加一個「配件 (Accessory)」。</p><p><strong>配件 (Accessory)</strong> 可以是：</p><ul><li>一個按鈕 (<code>ButtonBuilder</code>)</li><li>一個縮圖 (<code>ThumbnailBuilder</code>)</li></ul><p><strong>範例：帶有按鈕配件的 Section</strong></p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { SectionBuilder, ButtonStyle, MessageFlags } from &#x27;discord.js&#x27;;

const exampleSection = new SectionBuilder()
    .addTextDisplayComponents(
        textDisplay =&gt; textDisplay.setContent(&#x27;這是一個 Section 元件。&#x27;),
        textDisplay =&gt; textDisplay.setContent(&#x27;它可以包含多個文字區塊。&#x27;)
    )
    .setButtonAccessory(
        button =&gt; button
            .setCustomId(&#x27;exampleButton&#x27;)
            .setLabel(&#x27;Section 裡的按鈕&#x27;)
            .setStyle(ButtonStyle.Primary),
    );

await channel.send({
    components: [exampleSection],
    flags: MessageFlags.IsComponentsV2,
});
</code></pre>
<h4 id="filebuilder-"><code>FileBuilder</code> (檔案元件)</h4><p>用於在訊息中直接嵌入一個上傳的檔案。</p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import { AttachmentBuilder, FileBuilder, MessageFlags } from &#x27;discord.js&#x27;;

// 先建立一個附件
const file = new AttachmentBuilder(&#x27;./assets/guide.pdf&#x27;);

const exampleFile = new FileBuilder()
    // 這裡的 URL 必須對應到附件的名稱
    .setURL(&#x27;attachment://guide.pdf&#x27;);

await channel.send({
    components: [exampleFile],
    files: [file], // 同時發送檔案
    flags: MessageFlags.IsComponentsV2,
});
</code></pre>
<h2 id="">完整程式碼範例</h2><p>這個範例改編自 <a href="https://github.com/956zs/mimiDLC/blob/main/src/commands/coyote.ts"><code>src/commands/coyote.ts</code></a>，展示了如何結合使用上述多種元件來建立一個複雜的訊息。</p><pre class="language-typescript lang-typescript"><code class="language-typescript lang-typescript">import {
  ActionRowBuilder,
  ButtonBuilder,
  ButtonStyle,
  CommandInteraction,
  ContainerBuilder,
  SeparatorBuilder,
  TextDisplayBuilder,
  MediaGalleryBuilder,
} from &quot;discord.js&quot;;
import { MessageFlags } from &quot;discord.js&quot;;
import { Discord, Slash } from &quot;discordx&quot;;

@Discord()
export class Coyote {
  @Slash({
    description: &quot;Shows a wild coyote.&quot;,
    name: &quot;coyote&quot;,
    integrationTypes: [0, 1],
    contexts: [0, 1, 2],
  })
  async coyote(interaction: CommandInteraction): Promise&lt;void&gt; {
    // 1. 建立主容器並設定顏色
    const container = new ContainerBuilder().setAccentColor(703487);

    // 2. 建立各種內容元件
    const separator = new SeparatorBuilder();
    const title = new TextDisplayBuilder().setContent(&quot;# 小男娘鑑定工作！&quot;);
    const text = new TextDisplayBuilder().setContent(&quot;你是小男娘嗎?&quot;);
    const image = new MediaGalleryBuilder().addItems({
      media: { url: &quot;https://db.nlcat.dpdns.org/GrD8cqtbwAI2DNN.jpg&quot; },
    });

    // 按鈕列
    const row = new ActionRowBuilder&lt;ButtonBuilder&gt;().addComponents(
      new ButtonBuilder()
        .setCustomId(&quot;pet_coyote&quot;)
        .setLabel(&quot;對&quot;)
        .setStyle(ButtonStyle.Primary),
      new ButtonBuilder()
        .setCustomId(&quot;feed_coyote&quot;)
        .setLabel(&quot;沒錯&quot;)
        .setStyle(ButtonStyle.Secondary),
      new ButtonBuilder()
        .setCustomId(&quot;run_away&quot;)
        .setLabel(&quot;是&quot;)
        .setStyle(ButtonStyle.Danger)
    );

    // 3. 將所有元件按照期望的順序加入容器中
    container.components.push(title, separator, image, separator, text, row);

    // 4. 回覆互動，並啟用 V2 Components
    await interaction.reply({
      components: [container], // 將主容器傳入 components
      flags: MessageFlags.IsComponentsV2 | MessageFlags.Ephemeral,
    });
  }
}
</code></pre>
<h2 id="">進階技巧</h2><h3 id="">修改已接收的元件</h3><p>從 API 收到的元件是不可變的。若要修改它（例如，在使用者點擊按鈕後禁用該按鈕），您必須使用 <code>ComponentBuilder.from()</code> 靜態方法來建立一個可變的建構器實例。</p><pre class="language-diff lang-diff"><code class="language-diff lang-diff">- const editedButton = receivedButton
-   .setDisabled(true);

+ import { ButtonBuilder } from &#x27;discord.js&#x27;;
+ const editedButton = ButtonBuilder.from(receivedButton)
+   .setDisabled(true);
</code></pre>
<h2 id="">總結</h2><p>使用新版 Components V2 的流程如下：</p><ol start="1"><li>建立一個 <code>ContainerBuilder</code> 或其他頂層元件 (如 <code>SectionBuilder</code>)。</li><li>建立所有你需要的內容元件 (<code>TextDisplayBuilder</code>, <code>ActionRowBuilder</code> 等)。</li><li>將這些元件實例按順序加入到容器中 (可使用 <code>.push()</code> 或鏈式方法)。</li><li>在 <code>interaction.reply</code> 中，將元件陣列作為 <code>components</code> 的值，並<strong>務必</strong>加上 <code>flags: MessageFlags.IsComponentsV2</code>。</li></ol></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/discord_bot/discord-components-v2#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/discord_bot/discord-components-v2</link><guid isPermaLink="true">https://n1cat.xyz/posts/discord_bot/discord-components-v2</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Sat, 26 Jul 2025 00:37:45 GMT</pubDate></item><item><title><![CDATA[關於 Mix space 架設以及 shiro 主題的套用]]></title><description><![CDATA[<div><blockquote>This content is generated by the Shiro API and may have formatting issues. For the best experience, please visit:<a href="https://n1cat.xyz/posts/default/01">https://n1cat.xyz/posts/default/01</a></blockquote><div><p>::: warning
本文尚在更新 未完成
:::
::: warning
前情提要:<br/>這裡使用的是 <code>Docker</code> + <code>cloudflared tunnel</code>，採取前後端分離的方式，因此有很多不同的使用方法。<br/>你可以選擇：</p><ul><li>自架後端（使用 Docker）+ 前端部署於 Vercel（這部分會在文末說明）</li><li>自架後端（使用 Docker）+ 前端也放同台機器裡面 （使用 Docker）
:::</li></ul><h3 id="docker-">Docker 部署</h3><p>英文版本可參考：<br/><a href="https://github.com/956zs/Shiro">https://github.com/956zs/Shiro</a><br/>如果有未翻譯的部分，歡迎發 PR &gt;&lt;<br/>中文版本可以參考：<br/><a href="https://github.com/Innei/Shiro">https://github.com/Innei/Shiro</a></p><hr/><h3 id="shiro-">前端shiro 主題部署步驟：</h3><ol start="1"><li><p><strong>準備環境：</strong><br/>你需要一台網路正常的 VPS 或是一台酷酷的主機，並確保其能夠正常運行 Docker 。</p></li><li><p><strong>安裝 Docker：</strong><br/>首先，必須安裝 Docker。需要注意的是，即使你的 Docker 版本已經是較新的（例如 20.x 或更高版本），<code>docker-compose</code> 可能並未隨 Docker 一起安裝。<br/>從 Docker 1.27.0 版本開始，<code>docker compose</code> 被集成到了 Docker CLI 中，作為子命令來使用。但如果你的 Docker 版本未自動包含這個更新，則需要額外安裝 <code>docker compose</code>。<br/>確保 Docker 版本為 1.27.0 或以上，並安裝對應版本的 <code>docker compose</code>，以便順利使用此工具。<br/><strong>hint：</strong> <code>docker compose</code> ≠ <code>docker-compose</code></p></li></ol><p>------------------------------------------------------------------------------------------------------------------------</p><ul><li>4/25更: 前天剛轉移完資料 對於<code>docker compose</code> 安裝頗有心得 之後會寫一篇來講安裝會遇到的事</li></ul><p>------------------------------------------------------------------------------------------------------------------------</p><ol start="4"><li><p><strong>建置 Docker 容器：</strong><br/>環境安裝完成後，就可以開始建置 Docker 容器了。以下是具體步驟：</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">mkdir shiro
cd shiro
wget https://raw.githubusercontent.com/956zs/Shiro/main/docker-compose.yml
wget https://raw.githubusercontent.com/956zs/Shiro/main/.env.template

vim .env # 修改環境變數
docker compose up -d # 啟動並在背景運行Docker

# 更新操作
docker compose pull # 用於更新（包括 env 配置或 Docker image）
</code></pre><p>先來講講.env要改什麼內容<br/>這是原本的</p></li></ol><pre class=""><code class="">NEXT_PUBLIC_API_URL=http://127.0.0.1:2333/api/v2
NEXT_PUBLIC_GATEWAY_URL=http://127.0.0.1:2333
NEXT_PUBLIC_API_URL=https://innei.ren/api/v2
NEXT_PUBLIC_GATEWAY_URL=https://api.innei.ren

TMDB_API_KEY=
GH_TOKEN=
</code></pre><p><code>NEXT_PUBLIC_API_URL</code> : 這個是後端網址加上<code>/api/v2</code><br/><code>NEXT_PUBLIC_GATEWAY_URL</code>: 這個是後端網址就好<br/>然後如果兩個都部屬在同一台機器上的話 可以使用localhost 但我自己是遇到了像是<br/><a href="https://github.com/Innei/Shiro/issues/523">https://github.com/Innei/Shiro/issues/523</a><br/>圖一的問題</p><blockquote class="markdown-alert-warning"><header>WARNING</header><p>這裡要注意的是 這邊所有網址的結尾都不要加<code>/</code>不然websocket或著是其他的API很有可能會壞掉</p></blockquote></div><p style="text-align:right"><a href="https://n1cat.xyz/posts/default/01#comments">Finished reading? Leave a comment</a></p></div>]]></description><link>https://n1cat.xyz/posts/default/01</link><guid isPermaLink="true">https://n1cat.xyz/posts/default/01</guid><dc:creator><![CDATA[n1cat]]></dc:creator><pubDate>Fri, 18 Apr 2025 13:15:45 GMT</pubDate></item></channel></rss>