generated from Meekdai/Gmeek-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblogBase.json
1 lines (1 loc) · 92.7 KB
/
blogBase.json
1
{"singlePage": [], "startSite": "10/23/2024", "filingNum": "", "onePageListNum": 15, "commentLabelColor": "#006b75", "yearColorList": ["#bc4c00", "#0969da", "#1f883d", "#A333D0"], "i18n": "CN", "themeMode": "manual", "dayTheme": "light", "nightTheme": "dark", "urlMode": "pinyin", "script": "", "style": "", "head": "", "indexScript": "", "indexStyle": "", "bottomText": "Published under Creative Commons Attribution-ShareAlike (CC-BY-SA) license. Feel free to comment or share :)", "showPostSource": 1, "iconList": {}, "UTC": 8, "rssSplit": "sentence", "exlink": {}, "needComment": 1, "allHead": "", "homeUrl": "https://blog.quitw.org/", "title": "Purple4pur's Canvas: the Blog", "subTitle": "Make it simple. Keep it simple.", "avatarUrl": "https://avatars.githubusercontent.com/u/49893724", "GMEEK_VERSION": "last", "postListJson": {"P1": {"htmlDir": "docs/post/Hello Gmeek!.html", "labels": ["Thoughts"], "postTitle": "Hello Gmeek!", "postUrl": "post/Hello%20Gmeek%21.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/1", "commentNum": 2, "wordCount": 279, "description": "Hello Gmeek, welcome back my blog!\r\n\r\nI knew this project from V2EX months ago and thinking wow that is exactly what I want: a simple enough place to write down anything without handling deployment, page style, server, etc. Now it's here.\r\n\r\nSee you soon in the next coming post.\u3002", "top": 0, "createdAt": 1729697576, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-23", "dateLabelColor": "#bc4c00"}, "P2": {"htmlDir": "docs/post/vcs-verdi Cheat Sheet.html", "labels": ["Dev", "EDA"], "postTitle": "vcs/verdi Cheat Sheet", "postUrl": "post/vcs-verdi%20Cheat%20Sheet.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/2", "commentNum": 1, "wordCount": 2487, "description": "## vcs\r\n\r\n```bash\r\n-full64 +v2k -sverilog # \u56fa\u5b9a\u8d77\u624b\uff08v2k \u6307 Verilog-2001\uff09\r\n-lca -debug_access+all -kdb # \u4fdd\u5b58\u6ce2\u5f62\u9700\u8981\uff0cdebug \u5f00\u5173\u6781\u5927\u5f71\u54cd\u4eff\u771f\u65f6\u95f4[1][2]\r\n-timescale=1ns/100ps # \u65f6\u95f4\u7cbe\u5ea6\uff0c\u8003\u8651\u5728\u8fd9\u91cc\u7edf\u4e00\u6307\u5b9a\r\n-ntb_opts uvm-1.1 # UVM\r\n+incdir+<XX_DIR> <XX_file> # rtl\u3001verif \u6587\u4ef6\r\n+define+<XX> +define+<XX>=<YY> # \u8bbe\u7f6e define\r\n+vcs+fsdbon # \u81ea\u52a8\u751f\u6210\u6ce2\u5f62\u6587\u4ef6\uff08novas.fsdb\uff09\r\n-cm line+branch -cm_dir <cov.vdb> # \u7edf\u8ba1\u8986\u76d6\u7387[3][4]\r\n-fgp # \u542f\u7528\u591a\u7ebf\u7a0b\u4eff\u771f\u652f\u6301[5]\r\n-j<NUM> # \u591a\u7ebf\u7a0b\u7f16\u8bd1\uff0c\u5b9e\u6d4b\u5bf9\u7f16\u8bd1\u901f\u5ea6\u53ef\u80fd\u51e0\u4e4e\u65e0\u63d0\u5347\r\n-R [simv_options] # \u7f16\u8bd1\u540e\u81ea\u52a8\u5f00\u59cb\u4eff\u771f\r\n```\r\n\r\n## simv\r\n\r\n```bash\r\n+UVM_TESTNAME=<TEST> # \u6307\u5b9a run_test() \u8c03\u7528\u7684 uvm_test\r\n+ntb_random_seed=<SEED> # \u968f\u673a\u6570\u79cd\u5b50\uff0c\u7528\u4e8e random()\u3001randomize() \u7b49\r\n-ucli -i <UCLI_FILE> # \u7075\u6d3b\u63a7\u5236\u662f\u5426\u751f\u6210\u6ce2\u5f62\r\n+fsdb+delta # \u8bb0\u5f55 delta time\uff0c\u80fd\u5728 verdi \u91cc\u5c55\u5f00\r\n-cm line+branch -cm_dir <cov.vdb> -cm_name <TEST>\r\n # \u7edf\u8ba1\u8986\u76d6\u7387[3][4]\r\n+UVM_TR_RECORD +UVM_LOG_RECORD +UVM_VERDI_TRACE\r\n # UVM debug \u5f00\u5173\uff0c\u80fd\u5728 verdi \u91cc\u53ef\u89c6\u5316 transaction\r\n+UVM_VERBOSITY=<VERBOSITY> # \u7075\u6d3b\u8c03\u6574 UVM \u6253\u5370\u5197\u4f59\u7ea7\u522b\r\n-fgp=num_threads:<NUM>,num_fsdb_threads:<NUM>,allow_less_cores -Xdprof=timeline\r\n # \u591a\u7ebf\u7a0b\u4eff\u771f[5]\uff0c\u5b9e\u6d4b\u5bf9\u4eff\u771f\u901f\u5ea6\u53ef\u80fd\u51e0\u4e4e\u65e0\u63d0\u5347\r\n```\r\n\r\n### <UCLI_FILE>\r\n\r\n```bash\r\nfsdbDumpvars 0 # \u751f\u6210\u6240\u6709\u6ce2\u5f62\uff0c\u9ed8\u8ba4\u6587\u4ef6\u540d\u4e3a novas.fsdb\uff0c\u6781\u5927\u5f71\u54cd\u4eff\u771f\u65f6\u95f4[1]\r\nrun\r\nquit\r\n```\r\n\r\n## verdi\r\n\r\n```bash\r\n-dbdir simv.daidir # \u52a0\u8f7d\u4ee3\u7801\r\n-ssf novas.fsdb # \u52a0\u8f7d\u6ce2\u5f62\uff0c\u5982\u679c\u5b58\u5728\u5173\u8054\u7684\u4ee3\u7801\u4e5f\u4f1a\u81ea\u52a8\u52a0\u8f7d\uff08\u5373\u7701\u7565 -dbdir\uff09\r\n-cov -covdir <cov.vdb> # \u6253\u5f00 vdCoverage \u7a97\u53e3\uff0c\u5e76\u52a0\u8f7d\u8986\u76d6\u7387\u4fe1\u606f\r\n```\r\n\r\n* `<Shift+\u6eda\u8f6e>`\uff1a\u524d\u540e\u5e73\u79fb\u6ce2\u5f62\r\n* `\u53cc\u51fb\u6ce2\u5f62\u8fb9\u6cbf`\uff1a\u5728\u4ee3\u7801\u7a97\u53e3\u4e2d\u8df3\u8f6c\u5230\u5bf9\u5e94\u7684\u6fc0\u52b1\r\n* `nWave->Tools->Transaction Debug->Transaction and Protocol Analyzer`\uff1a\u6253\u5f00\u53ef\u89c6\u5316 transaction \u9762\u677f\r\n* `tProtocolAnalyzer->View->Sync. With nWave`\uff1a\u5173\u8054\u4e0a\u4e0b\u4e24\u4e2a\u9762\u677f\uff08\u6ce2\u5f62\u3001transaction\uff09\r\n* `Tools->Coverage`\uff1a\u6253\u5f00 vdCoverage \u7a97\u53e3\r\n* `vdCoverage->Tools->Generate URG Report`\uff1a\u751f\u6210\u8986\u76d6\u7387\u62a5\u544a\r\n\r\n## Reference\r\n\r\n[1] [vcs\u4e2ddebug\u9009\u9879\u3001\u6ce2\u5f62dump\u5bf9\u4eff\u771f\u65f6\u95f4\u7684\u5f71\u54cd_kevindas\u7684\u535a\u5ba2-CSDN\u535a\u5ba2](https://blog.csdn.net/kevindas/article/details/107307654)\r\n[2] [Synopsys VCS \u7f16\u8bd1\u65f6\uff0c\u542f\u7528debug\u9009\u9879_XtremeDV\u7684\u535a\u5ba2-CSDN\u535a\u5ba2](https://blog.csdn.net/zhajio/article/details/88839838)\r\n[3] [vcs\u8986\u76d6\u7387\u9009\u9879_weixin_39662684\u7684\u535a\u5ba2-CSDN\u535a\u5ba2](https://blog.csdn.net/weixin_39662684/article/details/108255556)\r\n[4] [VCS\u8986\u76d6\u7387\u4f7f\u7528\u8be6\u89e3\uff08\u57fa\u7840\u3001\u5408\u5e76\u3001\u67e5\u770b\u3001\u5206\u6790\uff09 - \u77e5\u4e4e](https://zhuanlan.zhihu.com/p/620471082)\r\n[5] [VCS -- fgp \u4eff\u771f\u52a0\u901f - Thisway2014 - \u535a\u5ba2\u56ed](https://www.cnblogs.com/thisway2014/p/16783601.html)\u3002", "top": 0, "createdAt": 1729785865, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-25", "dateLabelColor": "#bc4c00"}, "P3": {"htmlDir": "docs/post/ai-hao-shi-yi-zhong-neng-rang-zi-ji-kai-xin-de-xi-guan.html", "labels": ["Thoughts"], "postTitle": "\u7231\u597d\u662f\u4e00\u79cd\u80fd\u8ba9\u81ea\u5df1\u5f00\u5fc3\u7684\u4e60\u60ef", "postUrl": "post/ai-hao-shi-yi-zhong-neng-rang-zi-ji-kai-xin-de-xi-guan.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/3", "commentNum": 0, "wordCount": 1359, "description": "\u6700\u8fd1\u5728\u56de\u60f3\u6211\u7684\u7231\u597d\uff0c\u5728\u8fc7\u53bb\u7684\u5341\u5e74\u91cc\u5176\u5b9e\u6539\u53d8\u4e86\u4e0d\u5c11\u3002", "top": 0, "createdAt": 1729848928, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-25", "dateLabelColor": "#bc4c00"}, "P4": {"htmlDir": "docs/post/Git Sparse Checkout.html", "labels": ["Dev", "Git"], "postTitle": "Git Sparse Checkout", "postUrl": "post/Git%20Sparse%20Checkout.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/4", "commentNum": 1, "wordCount": 2495, "description": "## What Is Sparse Checkout?\r\n\r\nCheckout only part of the entire repository. Focus on files you need.\r\n\r\nKeep in mind: sparse-checkout settings are only kept in local copy. Won't be pushed. Won't be cloned.\r\n\r\n## Enable/Set/Add\r\n\r\n```bash\r\ngit sparse-checkout set/add [--no-cone] <file(s)>\r\n```\r\n\r\n* `set` : re-write current settings\r\n* `add` : append to current settings\r\n\r\nRunning this will automatically enable sparse-checkout feature, which can be checked with `git config --list` .\r\n\r\nInternally, sparse-checkout maintains two files:\r\n\r\n1. `.git/config` , where stores the feature ON/OFF flags\r\n2. `.git/info/sparse-checkout` . This file has a format the same as `.gitignore` but plays a **whitelist** role , and is the one `set/add` write to.\r\n\r\nAlternatively, the user can edit `.git/info/sparse-checkout` manually. (See also: <ins>`--cone` (default flag) vs `--no-cone`</ins>)\r\n\r\n## List Current Settings\r\n\r\n```bash\r\ngit sparse-checkout list\r\n```\r\n\r\n## Disable/Re-enable\r\n\r\n### Disable\r\n\r\n```bash\r\ngit sparse-checkout disable\r\n```\r\n\r\n: turn off all sparse-checkout flags in `.git/config` , but not touch `.git/info/sparse-checkout` .\r\n\r\n### Re-enable\r\n\r\n```bash\r\ngit sparse-checkout add # no files here\r\n```\r\n\r\n: turn on flags, continue using current `.git/info/sparse-checkout` .\r\n\r\n## `--cone` (default flag) vs `--no-cone`\r\n\r\n`--cone` is more like a 'smart' mode:\r\n\r\n* It automatically add `/*` and `!/*/` to `.git/info/sparse-checkout` (which means it **always allows top-level files** such as `/README.md` . It is impossible to filter them out.)\r\n* When `set/add` , for example, passing `lua` will become a `/lua/` line in `.git/info/sparse-checkout`\r\n\r\n`--no-cone` is somewhat 'manual' mode:\r\n\r\n* When `set/add` , `<file(s)>` will be written into `.git/info/sparse-checkout` character by character.\r\n\r\nIn this mode, the user can filter anything without any restriction. But to remember: always set a path with a leading `/` like this: `git sparse-checkout add /README.md /lua /doc` .\r\n\r\nIf you have been aware of all of above, I suggest `--no-cone` mode, which is more flexible. [An official discussion here](https://git-scm.com/docs/git-sparse-checkout#_internalsnon_cone_problems) .\r\n\r\n## Extra: Start From a Minimal Clone\r\n\r\n```bash\r\ngit clone --filter=blob:none --no-checkout <URL> [<...>]\r\ngit sparse-checkout set [<...>]\r\ngit checkout\r\n```\r\n\r\n[Reference](https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/#sparse-checkout-and-partial-clones)\u3002", "top": 0, "createdAt": 1729955825, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-26", "dateLabelColor": "#bc4c00"}, "P5": {"htmlDir": "docs/post/ROG Falchion(-mo-dao-shi-) RX Low Profile -jian-pan-shi-yong-ti-yan.html", "labels": ["Review", "Tech device"], "postTitle": "ROG Falchion(\u9b54\u5bfc\u58eb) RX Low Profile \u952e\u76d8\u4f7f\u7528\u4f53\u9a8c", "postUrl": "post/ROG%20Falchion%28-mo-dao-shi-%29%20RX%20Low%20Profile%20-jian-pan-shi-yong-ti-yan.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/5", "commentNum": 0, "wordCount": 3048, "description": "\u53cc\u5341\u4e00\u4e8e\u4eac\u4e1c\u8d2d\u5165\uff0c\u5b9e\u4ed8 1179 \u5143\uff0c\u4e8e 10 \u6708 15 \u65e5\u665a\u4e0a\u62ff\u5230\u624b\uff0c\u6301\u7eed\u4f7f\u7528\u81f3\u672c\u6587\u53d1\u5e03\u65f6\uff08\u7ea6\u4e24\u5468\uff09\u3002", "top": 0, "createdAt": 1730136581, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-29", "dateLabelColor": "#bc4c00"}, "P6": {"htmlDir": "docs/post/yi-zhong-geng-ping-heng-ting-ge-he-shang-fen-de- maimai -xuan-ge-ce-lve.html", "labels": ["Thoughts", "Gaming"], "postTitle": "\u4e00\u79cd\u66f4\u5e73\u8861\u542c\u6b4c\u548c\u4e0a\u5206\u7684 maimai \u9009\u6b4c\u7b56\u7565", "postUrl": "post/yi-zhong-geng-ping-heng-ting-ge-he-shang-fen-de-%20maimai%20-xuan-ge-ce-lve.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/6", "commentNum": 0, "wordCount": 521, "description": "\u6211\u6253 maimai \u7684\u80cc\u666f\u60c5\u51b5\u662f\u4e0d\u592a\u52e4\uff0c\u5f88\u591a\u6b4c\u90fd\u5c1a\u65e0\u6210\u7ee9\uff0c\u540c\u65f6\u53c8\u8fd8\u6709\u4e9b\u4e0a\u5206\u7a7a\u95f4\u3002", "top": 0, "createdAt": 1730389588, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-10-31", "dateLabelColor": "#bc4c00"}, "P7": {"htmlDir": "docs/post/A Practical Guide to Git Submodule.html", "labels": ["Dev", "Git"], "postTitle": "A Practical Guide to Git Submodule", "postUrl": "post/A%20Practical%20Guide%20to%20Git%20Submodule.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/7", "commentNum": 1, "wordCount": 4553, "description": "## Clone a Repository With Its Submodules\r\n\r\nIf is a first-time clone:\r\n\r\n```bash\r\ngit clone --recursive <...>\r\n```\r\n\r\nIf is an existing repository:\r\n\r\n```bash\r\ngit submodule update --init\r\n```\r\n\r\n## Add a Submodule\r\n\r\n```bash\r\ngit submodule add <repo_url> [<path>]\r\n```\r\n\r\nRunning this command will:\r\n\r\n* clone `<repo_url>` into `<path>` , but separate its `.git` folder (see <ins>Change Settings of Submodules</ins>)\r\n* add submodule infomation into `.gitmodules`\r\n* register submodule in `.git/modules/path/to/submodule` (where the `.git` folder is actually in)\r\n* register submodule in `.git/config` (do a `git submodule init` )\r\n* stage `.gitmodules` and the submodule folder\r\n\r\nThis clone will be a very full clone, which means not so many configs can play a role.\r\n\r\n## Pull Upstream Changes\r\n\r\nTwo ways:\r\n\r\n* `git submodule update --remote [<path>]`\r\n* OR: `git pull` in the submodule\r\n\r\nPulling upstream will also update the recorded hashes. Don't forget to commit changes.\r\n\r\n## Change Settings of Submodules\r\n\r\nThere're two paths available:\r\n\r\n* `/path/to/submodule` (recommended)\r\n* `.git/modules/path/to/submodule` (the actual path of the `.git` folder)\r\n\r\nChange working directory into one of them, then any git commands will apply to the submodule. For the first path, if is not been cloned, commands would still apply to the top-level repository. It is recommended to open a new terminal tab/window for changes within a submodule.\r\n\r\nWhat can do in a submodule:\r\n\r\n* pull upstream changes\r\n* setup [sparse checkout](https://purple4pur.github.io/post/Git%20Sparse%20Checkout.html) (not that practical)\r\n\r\nWhat can NOT do (or not be recommended) in a submodule:\r\n\r\n* change branch (see <ins>Change Tracking Branch</ins>)\r\n* change remote url (see <ins>Change Submodule URL</ins>)\r\n\r\n## Change Tracking Branch\r\n\r\nA submodule can only be tracked with a **remote named branch**, not a hash, not a local branch.\r\n\r\n### 1. Update Branch Setting\r\n\r\n* `git submodule set-branch -b <remote-branch> <module>` (not recommended - verbose and easy to mismatch)\r\n* OR: manually append `branch = <remote-branch>` below submodule's url in `.gitmodules`\r\n\r\nWarning: `<module>` must match the name in `.gitmodules` .\r\n\r\nIf want to remove this setting (means to use the default branch):\r\n\r\n* `git submodule set-branch -d <module>` (not recommended)\r\n* OR: manually remove the `branch = <remote-branch>` line\r\n\r\n### 2. Switch to the New Branch\r\n\r\n```bash\r\ngit submodule update --remote [<path>]\r\n```\r\n\r\nThis command will:\r\n\r\n1. do a `git pull; git checkout origin/<remote-branch>` in submodules\r\n2. update recorded hash (checked with `status`. See <ins>`git submodule status`</ins>)\r\n\r\nDon't forget to commit changes.\r\n\r\n## Change Submodule URL\r\n\r\nMostly the same as <ins>Change Tracking Branch</ins> , but change `url = <URL>` line instead.\r\n\r\n## Move a Submodule to a New Path\r\n\r\n```bash\r\ngit mv /path/to/submodule /new/path\r\n```\r\n\r\n`git mv` handles everything.\r\n\r\n## Remove a Submodule From Current Repository\r\n\r\n1. `git submodule deinit /path/to/submodule` : unregister submodule from `.git/config`\r\n2. remove `.git/modules/path/to/submodule` manually\r\n3. `git rm /path/to/submodule` : remove submodule folder, unregister from `.gitmodules` and stage changes\r\n\r\n[Reference](https://stackoverflow.com/a/16162000/12509229)\r\n\r\n## Submodule Command Explanation\r\n\r\n[Full Documentation](https://git-scm.com/docs/git-submodule) | [Example Usage](https://git-scm.com/book/en/v2/Git-Tools-Submodules)\r\n\r\n### `git submodule -h`\r\n\r\nList all sub-commands.\r\n\r\n### `git submodule`\r\n\r\nSame as `git submodule status` without parameters.\r\n\r\n### `git submodule status`\r\n\r\nList all submodules with paths and **current hashes**. Hashes may have a prefix:\r\n\r\n* `-` : not initialized. An `init` or `update --init` is wanted\r\n* `+` : currently checked out hash differs from the **recorded one**. An `update` is wanted\r\n\r\n### `git submodule add`\r\n\r\nAdd a new submodule. See <ins>Add a Submodule</ins> .\r\n\r\n### `git submodule init/deinit`\r\n\r\n(Un)register a submodule. 'Registered' means 'active'. `update` and other sub-commands will only apply to active submodules.\r\n\r\n### `git submodule update`\r\n\r\nCheckout the recorded hash of submodules. Some options:\r\n\r\n* `--init` : shorthand of `init` then `update`\r\n* `--remote` : pull upstream and update recorded hashes. See <ins>Pull Upstream Changes</ins>\r\n* `--recursive` : `update` all nested submodules\r\n\r\n### `git submodule foreach <command>`\r\n\r\nRun `<command>` within each submodule. Example: `git submodule foreach git pull` .\r\n\u3002", "top": 0, "createdAt": 1730531175, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-02", "dateLabelColor": "#bc4c00"}, "P8": {"htmlDir": "docs/post/2024 -nian-ge-lei- Live -ji-zhan-hui-can-zhan-ji-lu.html", "labels": ["LifeFlashes"], "postTitle": "2024 \u5e74\u5404\u7c7b Live \u53ca\u5c55\u4f1a\u53c2\u6218\u8bb0\u5f55", "postUrl": "post/2024%20-nian-ge-lei-%20Live%20-ji-zhan-hui-can-zhan-ji-lu.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/8", "commentNum": 0, "wordCount": 4682, "description": "### Live\r\n\r\n| No. | \u65e5\u671f | Live | \u573a\u5730 | \u4e3b\u9898 | \u57ce\u5e02 | \u7968\u4ef7 |\r\n| --- | --- | --- | --- | --- | --- | --- |\r\n| 1 | 6/10 | STARLINK METEOR 1st Live | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 88 |\r\n| 2 | 6/22 | \u300c\u591a\u53a8\u72c2\u559c\u300d\u767d\u91d1\u4ea4\u54cd\u4e50\u56e2\u4e8c\u6b21\u5143\u4ea4\u54cd\u97f3\u4e50\u4f1a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 288 |\r\n| 3 | 6/23 | \u82b1\u4e4b\u793c\u8d5e\u300a\u594f\u54cd\u5427\uff0c\u548c\u97f3\u793e\uff01\u300b\u7ecf\u5178\u52a8\u6f2b\u4ea4\u54cd\u97f3\u4e50\u4f1a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 180 |\r\n| 4 | 6/30 | Star2U Macro Idol Festival Vol.14 | Livehouse | \u5730\u5076 | \u4e0a\u6d77 | 128 |\r\n| 5 | 7/12 | \u300c\u591c\u00b3\u6b4c\u75c7\u5019\u7fa4\u300d\u4e09\u591c Only | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 99 |\r\n| 6 | 7/20 | CrossingX\u610f\u6b21\u5143 \u97f3\u4e50\u756a Only | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 78 |\r\n| 7 | 7/21 | Star2U \u8de8\u6b21\u5143\u5609\u5e74\u534e Vol.12.5 \u90a6\u90a6 Only | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 108 |\r\n| 8 | 7/26 | fhana China Live Tour 2024 | Livehouse | \u65e5\u97f3 | \u4e0a\u6d77 | 380 |\r\n| 9 | 8/11 | \u6f2b\u97f3\u5b63 2024 \u590f | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 0 (\u4e2d\u5956\u7968) |\r\n| 10 | 8/17 | \u8de8\u8d8a\u56fd\u5883\u7684\u65cb\u5f8b \u5927\u548c\u7530\u96c5\u6d0bx\u548c\u97f3\u793e\u4ea4\u54cd\u5439\u594f\u97f3\u4e50\u4f1a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 232 |\r\n| 11 | 8/18 | \u5e7b\u594f\u76db\u5bb4 2024 \u4e0a\u6d77\u573a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 289 |\r\n| 12 | 8/24 | \u300a\u4e0d\u7728\u773c\u300bH\u25b3G 1st Live in Shanghai | Livehouse | \u65e5\u97f3 | \u4e0a\u6d77 | 480 |\r\n| 13 | 9/7 | \u548c\u97f3\u793e\u5f55\u5236\u73b0\u573a\u65c1\u542c (\u539f\u6f14\u51fa\u53d6\u6d88) | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 0 |\r\n| 14 | 9/8 | Tie-Up Anirock Live 2.0 | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 88 |\r\n| 15 | 10/7 | \u6781\u5149\u7eaa Polar Ray 5th | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 88 |\r\n| 16 | 10/12 | \u300a\u6b21\u5143\u5171\u9e23\u300bACG \u4e50\u961f\u756a\u4e3b\u9898\u6f14\u5531\u4f1a | Livehouse | ACG \u6447\u6eda | \u4e0a\u6d77 | 160 |\r\n| 17 | 11/3 | \u300c\u591a\u53a8\u72c2\u559c\u300d\u767d\u91d1\u4ea4\u54cd\u4e50\u56e2\u4e8c\u6b21\u5143\u4ea4\u54cd\u97f3\u4e50\u4f1a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 288 |\r\n| 18 | 11/10 | [\u300c\u58f0\u300dH\u25b3G 1st Live in Guangzhou](https://blog.quitw.org/post/H%E2%96%B3G%201st%20Live%20in%20Guangzhou%20-can-zhan-xiao-ji.html) | Livehouse | \u65e5\u97f3 | \u5e7f\u5dde | 480 |\r\n| 19 | 11/16 | milet Asia Tour 2024 | \u6f14\u827a\u9986 | \u65e5\u97f3 | \u4e0a\u6d77 | 880 |\r\n| 20 | 11/24 | \u6cfd\u91ce\u5f18\u4e4b LIVE [nZk] 2024 | \u4f53\u80b2\u9986 | \u65e5\u97f3 | \u4e0a\u6d77 | 880 |\r\n| 21 | 12/14 | \u7396\u7396\u7684\u5947\u5999\u5192\u9669 \u5e1d\u7396\u7ba1\u5f26\u4e50\u56e2 2024 \u4ea4\u54cd\u97f3\u4e50\u4f1a | \u97f3\u4e50\u5385 | ACG \u4ea4\u54cd | \u4e0a\u6d77 | 580 |\r\n| 22 | 12/15 | \u300c\u65e7\u53cb \\| \u65b0\u58f0\u300d\u9648\u81f4\u9038\u4f5c\u54c1\u97f3\u4e50\u4f1a 2024 | \u5267\u573a | \u914d\u4e50\u4ea4\u54cd | \u4e0a\u6d77 | 480 |\r\n\r\n### \u5c55\u4f1a\r\n\r\n| No. | \u65e5\u671f | \u5c55\u4f1a | \u57ce\u5e02 | \u7968\u4ef7 |\r\n| --- | --- | --- | --- | --- |\r\n| 1 | 7/27 | Chinajoy 2024 | \u4e0a\u6d77 | 188 |\r\n| 2 | 11/30 | \u521b\u4f5c\u8fde\u9501 2024 \u65e5\u5382 Vocaloid Only | \u4e0a\u6d77 | 139 |\u3002", "top": 0, "createdAt": 1730644058, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-03", "dateLabelColor": "#bc4c00"}, "P9": {"htmlDir": "docs/post/Example Git Config File.html", "labels": ["Dev", "Git"], "postTitle": "Example Git Config File", "postUrl": "post/Example%20Git%20Config%20File.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/9", "commentNum": 1, "wordCount": 456, "description": "## File Path\r\n\r\n* Linux: `~/.gitconfig`\r\n* Windows: `C:/Users/<user>/.gitconfig`\r\n\r\n## Example\r\n\r\n```\r\n[user]\r\n email = [email protected]\r\n name = xxx\r\n[http]\r\n proxy = 127.0.0.1:10809\r\n[core]\r\n editor = nvim\r\n pager = moar\r\n[color]\r\n ui = auto\r\n[diff]\r\n tool = meld\r\n```\r\n\r\n## CLI Command\r\n\r\n```sh\r\ngit config --global --list\r\n --local --get\r\n --set user.email '[email protected]'\r\n --unset\r\n```\u3002", "top": 0, "createdAt": 1730818676, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-05", "dateLabelColor": "#bc4c00"}, "P10": {"htmlDir": "docs/post/AXI4 Address Break Down.html", "labels": ["Dev", "AXI"], "postTitle": "AXI4 Address Break Down", "postUrl": "post/AXI4%20Address%20Break%20Down.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/10", "commentNum": 0, "wordCount": 3054, "description": "### Must know\r\n\r\n- Unit of address is **Byte**.\r\n - 0x00 maps to a 1-byte space in memory.\r\n - 0x01 maps to the next byte.\r\n- **Aligned address** means `Address % Size == 0`.\r\n - where `Size` is num of bytes per transfer: `2 ** AxSIZE` or `1 << AxSIZE`.\r\n- **Narrow transfer** means a transfer not using all *WDATA* bytes, but selected by *WSTRB*.\r\n- *WSTRB* valid bits should match `Size`.\r\n\r\n### Schematic diagram\r\n\r\nWhat an AXI address in memory looks like:\r\n\r\n- *xDATA* width: 32 bits\r\n\r\n```\r\n Bit# |31 24|23 16|15 8|7 0|\r\n +--------+--------+--------+--------+\r\nAXI Address | 0x03 | 0x02 | 0x01 | 0x00 |\r\n +--------+--------+--------+--------+\r\n | 0x07 | 0x06 | 0x05 | 0x04 |\r\n +--------+--------+--------+--------+\r\n | ... |\r\n +-----------------------------------+\r\n```\r\n\r\n### Calculation of burst INCR addresses\r\n\r\n> Reference: AXI Spec $$A4.1.6\r\n\r\nA burst INCR request can start from an **aligned address** or **unaligned address**. For both cases, the 2nd address is always the next aligned address. Each transfer will step forward 1 `Size` space, making the whole burst INCR request write to or read from a consecutive memory space.\r\n\r\n- Example function to calculate the start address of the Nth transfer (Nth starts from 1):\r\n\r\n```systemverilog\r\nfunction AXI_Address calc_Nth_start_addr(AXI_Address start_addr, int axsize, int Nth);\r\n int size = 2 ** axsize; // num of bytes per transfer\r\n AXI_Address aligned_addr = start_addr / size * size; // round down to aligned address\r\n // Nth starts from 1\r\n AXI_Address Nth_start_addr = (Nth == 1) ? (start_addr) :\r\n (aligned_addr + (Nth - 1) * size) ;\r\n return Nth_start_addr;\r\nendfunction\r\n```\r\n\r\n- Example function to calculate the last address of the whole burst INCR request:\r\n\r\n```systemverilog\r\nfunction AXI_Address calc_end_addr(AXI_Address start_addr, int axsize, int axlen);\r\n int total_len = axlen + 1;\r\n int size = 2 ** axsize; // num of bytes per transfer\r\n AXI_Address aligned_addr = start_addr / size * size; // round down to aligned address\r\n AXI_Address end_addr = aligned_addr + total_len * size - 1;\r\n return end_addr;\r\nendfunction\r\n```\r\n\r\n### 4K boundary\r\n\r\n*4K* basically refers to a 4K-Byte space in memory, which is also called a *Page*. In AXI it means a 4096 (0x1000) wide address space. An AXI request is not allowed to cross the addresses that start a new *Page*. In other words, all accessed address should only be within one *Page*, E.g. `[0x3000, 0x3FFF]`.\r\n\r\n- Example function to check if an address space has crossed 4K boundary:\r\n\r\n```systemverilog\r\nfunction bit has_crossed_4k_boundary(AXI_Address start_addr, AXI_Address end_addr);\r\n return ((start_addr >> 12) != (end_addr >> 12));\r\nendfunction\r\n```\r\n\r\n### Appendix: AXI Spec\r\n\r\n[[AMBA AXI Protocol Specification]](https://developer.arm.com/documentation/ihi0022/latest/)\u3002", "top": 0, "createdAt": 1731060046, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-08", "dateLabelColor": "#bc4c00"}, "P11": {"htmlDir": "docs/post/bi-mian-gou-tong-lou-dou-\uff0c-chuan-di-wan-zheng-de-xin-xi.html", "labels": ["Thoughts"], "postTitle": "\u907f\u514d\u6c9f\u901a\u6f0f\u6597\uff0c\u4f20\u9012\u5b8c\u6574\u7684\u4fe1\u606f", "postUrl": "post/bi-mian-gou-tong-lou-dou-%EF%BC%8C-chuan-di-wan-zheng-de-xin-xi.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/11", "commentNum": 0, "wordCount": 671, "description": "### \u4f55\u8c13\u300c\u6f0f\u6597\u300d\r\n\r\n\u300c\u6c9f\u901a\u6f0f\u6597\u300d\u662f\u4e00\u4e2a\u5f88\u5f62\u8c61\u7684\u6982\u5ff5\uff0c\u5f62\u5bb9\u8fd9\u6837\u4e00\u79cd\u573a\u666f\uff1aA \u628a\u4e00\u4ef6\u4e8b\u544a\u8bc9\u7ed9 B\uff0c\u4f46\u7531\u4e8e\u53cc\u65b9\u7684\u7406\u89e3\u504f\u5dee\u6216\u5176\u4ed6\u539f\u56e0\uff0c\u5bfc\u81f4 B \u53ea\u63a5\u6536\u5230 80% \u7684\u539f\u610f\uff0c\u540c\u6837\u7684\u4e8b\u60c5\u7ee7\u7eed\u53d1\u751f\u5728 B \u544a\u8bc9 C\u3001C \u544a\u8bc9 D \u4e0a\uff0c\u7ed3\u679c\u6574\u4e2a\u6c9f\u901a\u94fe\u4e0a\u8fd9\u4ef6\u4e8b\u7684\u539f\u610f\u635f\u5931\u5f97\u8d8a\u6765\u8d8a\u591a\uff0c\u5982\u540c\u4e00\u4e2a\u6f0f\u6597\u822c\u3002", "top": 0, "createdAt": 1731130968, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-09", "dateLabelColor": "#bc4c00"}, "P12": {"htmlDir": "docs/post/H\u25b3G 1st Live in Guangzhou -can-zhan-xiao-ji.html", "labels": ["LifeFlashes"], "postTitle": "H\u25b3G 1st Live in Guangzhou \u53c2\u6218\u5c0f\u8bb0", "postUrl": "post/H%E2%96%B3G%201st%20Live%20in%20Guangzhou%20-can-zhan-xiao-ji.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/12", "commentNum": 0, "wordCount": 3445, "description": "### \u6211\u548c H\u25b3G\r\n\r\n\u6211\u6700\u65e9\u5bf9 H\u25b3G \u6709\u5370\u8c61\u6700\u65e9\u5e94\u8be5\u662f\u5728 osu! \u91cc\u542c\u5230\u4e86\u4ed6\u4eec\u7684\u300a\u30ab\u30e9\u30d5\u30eb\u300b\uff0c\u4f46\u4e5f\u5e76\u6ca1\u6709\u7279\u522b\u5173\u6ce8\uff0c\u5904\u4e8e\u4e00\u4e2a\u542c\u65e5\u97f3\u76f8\u5f53\u6742\u98df\u7684\u72b6\u6001\u3002", "top": 0, "createdAt": 1731430727, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-13", "dateLabelColor": "#bc4c00"}, "P13": {"htmlDir": "docs/post/goto Repetition ([--n]) in SVA.html", "labels": ["Dev", "Systemverilog"], "postTitle": "goto Repetition ([->n]) in SVA", "postUrl": "post/goto%20Repetition%20%28%5B--n%5D%29%20in%20SVA.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/13", "commentNum": 0, "wordCount": 3132, "description": "This article is basically a dev memo of [Ben Cohen's amazing tutorial on this topic](https://systemverilog.us/vf/goto_conseq.pdf) , followed by a practical live demo in my work.\r\n\r\n### Basic usage and live demo\r\n\r\nIn a word, goto repetition describe a sequence of a boolean value `b` becoming True for `n` times in following cycles, and **don't care when or continuously or not**.\r\n\r\nGiven property `a |=> b[->2] ##1 c`:\r\n\r\n```\r\n a: 1 - - - - - - -\r\n b: - 0 1 0 0 0 1 -\r\n c: - - - - - - - 1\r\nproperty: |---^-------^-! // match\r\n```\r\n\r\nLet's say here's a counter of range 0 to max value 2. I want a property to trace the counter from 0 to 2 then back to 0, and the other values are all not-care.\r\n\r\n```\r\n counter: 0 -> 1 -> 0 -> 0 -> 1 -> 2 -> 1 -> 2 -> 1 -> 0\r\n fail case: |---------! // fail\r\nmatch case: |---------^-------------------! // match\r\n```\r\n\r\n1. Starting point (antecedent)\r\n\r\nIt should start from `(cnt == 0)`:\r\n\r\n```systemverilog\r\n(cnt == 0) |=> // TODO\r\n```\r\n\r\n2. Finding 2\r\n\r\nA value of 2 is expected in following cycles:\r\n\r\n```systemverilog\r\n(cnt == 0) |=> (cnt == 2)[->1] // TODO\r\n```\r\n\r\n3. Back to 0\r\n\r\nAfter that let's get back to 0 and done:\r\n\r\n```systemverilog\r\n(cnt == 0) |=> (cnt == 2)[->1] ##1 (cnt == 0)[->1]; // Done!\r\n```\r\n\r\nOK. I believe this property can handle the most ideal case:\r\n\r\n```\r\n counter: 0 -> 1 -> 2 -> 1 -> 0\r\nproperty: |---------^---------! // match\r\n```\r\n\r\nBut it has issues. One is I want it to fail when the counter falls back to 0 before reaching 2, and now it won't:\r\n\r\n```\r\n counter: 0 -> 1 -> 0 -> 2 -> 1 -> 0\r\nproperty: |---------?----^---------! // match\r\n ^-I want it to fail here\r\n```\r\n\r\nTo fix that, replace `(cnt == 2)[->1]` with a restriction of not seeing 0 before:\r\n\r\n```systemverilog\r\n(cnt == 0) |=> (cnt != 0)[*0:$] ##1 (cnt == 2) ##1 (cnt == 0)[->1];\r\n```\r\n\r\nSecond issue is it will start a new thread once it sees 0, which is definitely unnecessary:\r\n\r\n```\r\n counter: 0 -> 0 -> 0 -> 1 -> 2\r\nproperty: |-------------------^ // unnecessary\r\n |--------------^ // unnecessary\r\n |---------^ // I want only this\r\n```\r\n\r\nTo fix that, replace the antecedent with a short sequence of seeing 0 then 1:\r\n\r\n```systemverilog\r\n(cnt == 0) ##1 (cnt == 1) |=> (cnt != 0)[*0:$] ##1 (cnt == 2) ##1 (cnt == 0)[->1];\r\n// OR: $rose(cnt > 0) |=> ...\r\n```\r\n\r\nNow it works great!\r\n\r\n### [->n] vs [*0:$]\r\n\r\n`b[->n]` is equivalent to `(!b[*0:$] ##1 b)[*n]`, which works like syntactic sugar.\r\n\r\n### [->n] vs first_match()\r\n\r\n`b[->n]` only accepts `b` as a single boolean value without logical operators. So in these cases use `first_match()` instead.\r\n\r\n```systemverilog\r\n(AWREADY & AWVALID)[->1] // bit operator: OK\r\nfirst_match(AWREADY && AWVALID) // logical operator: use first_match()\r\n```\r\n\r\n### When NOT to use\r\n\r\nNEVER use it in the 1st term of antecedent. Because it will start tons of unnecessary threads.\r\n\r\n```systemverilog\r\na[->1] ##1 b |=> c; // BAD and not necessary\r\n```\r\n\r\nFor more detailed use guides please refer to [Ben's article](https://systemverilog.us/vf/goto_conseq.pdf) .\u3002", "top": 0, "createdAt": 1731654471, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-15", "dateLabelColor": "#bc4c00"}, "P14": {"htmlDir": "docs/post/Installing CLI Tools I Use on Debian-Linux.html", "labels": ["Dev", "Linux"], "postTitle": "Installing CLI Tools I Use on Debian/Linux", "postUrl": "post/Installing%20CLI%20Tools%20I%20Use%20on%20Debian-Linux.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/14", "commentNum": 0, "wordCount": 2197, "description": "### git\r\n\r\n```sh\r\n(root) apt update\r\n(root) apt install git\r\n```\r\n\r\n### chezmoi\r\n\r\n[[Official installation guide]](https://www.chezmoi.io/install/#one-line-binary-install)\r\n\r\n```sh\r\nsh -c '$(curl -fsLS get.chezmoi.io)' # install to $HOME/bin\r\n```\r\n\r\n### starship\r\n\r\n[[Official installation guide]](https://starship.rs/guide/#step-1-install-starship)\r\n\r\n```sh\r\n(root) curl -sS https://starship.rs/install.sh | sh # install to /usr/local/bin\r\n```\r\n\r\n### neovim\r\n\r\n[[Official installation guide]](https://github.com/neovim/neovim/blob/master/INSTALL.md#pre-built-archives-1)\r\n\r\n```sh\r\ncurl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux64.tar.gz\r\nmkdir $HOME/opt\r\nrm $HOME/opt/nvim-linux64 -rf # remove old version\r\ntar -C $HOME/opt -xzf nvim-linux64.tar.gz # install to $HOME/opt/nvim-linux64/bin\r\nrm nvim-linux64.tar.gz\r\n```\r\n\r\n### fd\r\n\r\n[[Github]](https://github.com/sharkdp/fd)\r\n\r\n```sh\r\n(root) apt update\r\n(root) apt install fd-find\r\n(root) ln -sf /usr/bin/fdfind /usr/bin/fd\r\n```\r\n\r\n### rg\r\n\r\n[[Github]](https://github.com/BurntSushi/ripgrep)\r\n\r\n```sh\r\n(root) apt update\r\n(root) apt install ripgrep\r\n```\r\n\r\n### docker\r\n\r\n[[Official installation guide]](https://docs.docker.com/engine/install/debian/#install-using-the-repository)\r\n\r\n```sh\r\n# Add Docker's official GPG key:\r\nsudo apt-get update\r\nsudo apt-get install ca-certificates curl\r\nsudo install -m 0755 -d /etc/apt/keyrings\r\nsudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc\r\nsudo chmod a+r /etc/apt/keyrings/docker.asc\r\n\r\n# Add the repository to Apt sources:\r\necho \\\r\n 'deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \\\r\n $(. /etc/os-release && echo '$VERSION_CODENAME') stable' | \\\r\n sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\r\nsudo apt-get update\r\n\r\n# Install\r\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\r\n\r\n# Hello world\r\nsudo docker run hello-world\r\n\r\n# Add user to docker group to grant him privileges\r\n# WARNING: Do with caution! docker group has the same permissions of root!\r\nsudo usermod -aG docker USERNAME\r\n```\u3002", "top": 0, "createdAt": 1731863359, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-18", "dateLabelColor": "#bc4c00"}, "P15": {"htmlDir": "docs/post/Docker CLI Cheat Sheet.html", "labels": ["Dev", "Docker"], "postTitle": "Docker CLI Cheat Sheet", "postUrl": "post/Docker%20CLI%20Cheat%20Sheet.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/15", "commentNum": 0, "wordCount": 6226, "description": "### Dockerfile\r\n\r\n- [[Docker 101]](https://dockerlabs.collabnix.com/workshop/docker/)\r\n- [[Dockerfile reference]](https://docs.docker.com/reference/dockerfile/)\r\n\r\n### docker build\r\n\r\n```sh\r\ndocker build -t IMAGE[:TAG] . # build image from in-place Dockerfile\r\n```\r\n\r\n### docker run\r\n\r\n```sh\r\ndocker run [OPTIONS] IMAGE[:TAG] [CMD] # run a container from image (and run the command)\r\n -d # detached mode\r\n -it # invoke an interactive tty\r\n -P # publish all EXPOSE ports\r\n -p HOST_PORT:CONTAINER_PORT # map a container port to docker host\r\n -v VOLUME:CONTAINER_PATH # mount volume on container path\r\n --network NETWORK # connect to a network\r\n --name CONTAINER # name the container\r\n --rm # one-off mode, auto remove from docker ps after exited\r\n```\r\n\r\n### docker attach\r\n\r\n```sh\r\ndocker attach [OPTIONS] CONTAINER # attach to a detached container\r\n --detach-keys=KEYS # assign a detach key like ctrl-b\r\n```\r\n\r\nTo detach from a running container: press detach keys, default is `ctrl-p`+`ctrl-q`.\r\n\r\n### docker exec\r\n\r\n```sh\r\ndocker exec [OPTIONS] CONTAINER CMD # run the command in a running container\r\n -t # run in tty then exit\r\n -it # run in an interactive tty\r\n```\r\n\r\n### docker ps\r\n\r\n```sh\r\ndocker ps [OPTIONS] # list all running containers\r\n -a # list all recorded containers (running/paused/exited)\r\n -q # quiet mode, container_id only\r\n```\r\n\r\n### docker inspect\r\n\r\n```sh\r\ndocker inspect DOCKER_OBJECT # print object info in json format\r\n # - image\r\n # - container\r\n # - volume\r\n # - network\r\n```\r\n\r\n### docker image\r\n\r\n```sh\r\ndocker build ... # build a new image\r\ndocker images [FILTER] # list all images, alias of docker image ls\r\ndocker pull IMAGE[:TAG] # pull an image from docker hub\r\ndocker tag IMAGE[:TAG] NEW_IMAGE[:NEW_TAG] # rename an image\r\ndocker image rm [-f] IMAGE # remove an image\r\ndocker image prune -a # remove all unused images\r\ndocker history IMAGE[:TAG] # print how the image was built\r\n```\r\n\r\n### docker container\r\n\r\n`CONTAINER` can be container_id (short-form OK) or container_name.\r\n\r\n```sh\r\ndocker run ... # new a container\r\ndocker ps ... # list container status\r\ndocker stop CONTAINER # as it says\r\ndocker kill CONTAINER # as it says\r\ndocker start/restart CONTAINER # as it says\r\ndocker pause/unpause CONTAINER # as it says\r\ndocker logs [OPTIONS] CONTAINER # print stdout of container\r\n -f # follow mode\r\n -n N # only tail N lines\r\ndocker port CONTAINER [PORT] # show port mapping info\r\ndocker rm [-f] CONTAINER # remove record from docker ps\r\ndocker rm $(docker ps -aq) # remove all records from docker ps\r\n```\r\n\r\n### docker volume\r\n\r\n```sh\r\ndocker volume create VOLUME # create a volume\r\ndocker volume ls # list all volumes\r\ndocker volume rm [-f] VOLUME # remove a volume\r\ndocker volume rm $(docker volume ls -q) # remove all volumes\r\n```\r\n\r\n### docker network\r\n\r\nNetwork has multiple types (a.k.a. drivers) [[Reference]](https://docs.docker.com/engine/network/#drivers) :\r\n\r\n- **bridge**: communicate among containers only, publish specific ports to docker host, the default type.\r\n- **host**: directly expose on host machine, publish options are ignored.\r\n- **null**: no network provided.\r\n\r\n```sh\r\ndocker network create -d DRIVER NETWORK # create a network of specific type\r\ndocker network ls # list all networks\r\ndocker network connect NETWORK CONTAINER # connect a network to container\r\ndocker network disconnect NETWORK CONTAINER # disconnect a network to container\r\ndocker network rm NETWORK # remove a network\r\n```\r\n\r\n### docker system\r\n\r\n```sh\r\ndocker system df # list all disk usage\r\ndocker system prune [OPTIONS] # the BEST way to clean up unused resources\r\n -a # with all unused images\r\n --volumes # with anonymous volumes\r\n```\r\n\r\n### docker compose\r\n\r\n- [[Docker compose 101]](https://dockerlabs.collabnix.com/intermediate/workshop/)\r\n- [[compose.yaml reference]](https://docs.docker.com/reference/compose-file/)\r\n\r\n- A `compose.yaml` file is wanted in working directory.\r\n- `service` in compose is equivalent to `container`.\r\n\r\n```sh\r\ndocker compose config # print info of in-place compose.yaml\r\ndocker compose build # build images defined in compose.yaml\r\ndocker compose up [OPTIONS] # start current compose\r\n -d # detached mode\r\n --build # rebuild images (if needed) then restart\r\n --no-start # create services only but don't start\r\ndocker compose down [OPTIONS] # the BEST way to stop compose\r\n -v # also remove created volumes\r\n --rmi local|all # also remove local built images by current compose / all built and pulled images\r\ndocker compose images # list images used by current compose\r\ndocker compose ps [-a] [-q] [--services] # list services used by current compose\r\ndocker compose start/stop/restart [SERVICE] # as it says\r\ndocker compose pause/unpause [SERVICE] # as it says\r\ndocker compose kill [SERVICE] # as it says\r\ndocker compose logs [-f] [-n N] [SERVICE] # print/follow stdout in service\r\ndocker compose run SERVICE CMD # run a one-time command in a new service, not the running one\r\ndocker compose rm [OPTIONS] [SERVICE] # remove stopped service from ps\r\n -s # stop and remove\r\n```\u3002", "top": 0, "createdAt": 1731950234, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-19", "dateLabelColor": "#bc4c00"}, "P16": {"htmlDir": "docs/post/Welcome, My New VPS!.html", "labels": ["Dev", "Linux"], "postTitle": "Welcome, My New VPS!", "postUrl": "post/Welcome%2C%20My%20New%20VPS%21.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/16", "commentNum": 0, "wordCount": 9944, "description": "### General info\r\n\r\n- Vendor: Tencent Cloud\r\n- \u5730\u57df\u548c\u53ef\u7528\u533a: \u4e1c\u4eac | \u4e1c\u4eac\u4e00\u533a\r\n- \u5957\u9910\u7c7b\u578b: \u5165\u95e8\u578b\r\n- \u5b9e\u4f8b\u89c4\u683c:\r\n - CPU - 2\u6838\r\n - \u5185\u5b58 - 2GB\r\n - \u7cfb\u7edf\u76d8 - SSD\u4e91\u786c\u76d8 50GB\r\n - \u6d41\u91cf\u5305 - 1024GB/\u6708\uff08\u5cf0\u503c\u5e26\u5bbd\uff1a30Mbps\uff09\r\n- Price: 99CNY for 1Yr\r\n\r\n### VPS all-in-one test\r\n\r\n<https://github.com/spiritLHLS/ecs>\r\n\r\n<details><summary>Results</summary>\r\n\r\n```\r\n--------------------- A Bench Script By spiritlhl ----------------------\r\n \u6d4b\u8bc4\u9891\u9053: https://t.me/vps_reviews\r\nVPS\u878d\u5408\u602a\u7248\u672c\uff1a2024.11.08\r\nShell\u9879\u76ee\u5730\u5740\uff1ahttps://github.com/spiritLHLS/ecs\r\nGo\u9879\u76ee\u5730\u5740\uff1ahttps://github.com/oneclickvirt/ecs\r\n---------------------\u57fa\u7840\u4fe1\u606f\u67e5\u8be2--\u611f\u8c22\u6240\u6709\u5f00\u6e90\u9879\u76ee---------------------\r\n CPU \u578b\u53f7 : Intel(R) Xeon(R) Gold 6146 CPU @ 3.20GHz\r\n CPU \u6838\u5fc3\u6570 : 2\r\n CPU \u9891\u7387 : 3192.500 MHz\r\n CPU \u7f13\u5b58 : L1: 64.00 KB / L2: 8.00 MB / L3: 27.50 MB\r\n AES-NI\u6307\u4ee4\u96c6 : \u2714 Enabled\r\n VM-x/AMD-V\u652f\u6301 : \u274c Disabled\r\n \u5185\u5b58 : 300.93 MiB / 1.80 GiB\r\n Swap : [ no swap partition or swap file detected ]\r\n \u786c\u76d8\u7a7a\u95f4 : 2.24 GiB / 49.10 GiB\r\n \u542f\u52a8\u76d8\u8def\u5f84 : /dev/vda1\r\n \u7cfb\u7edf\u5728\u7ebf\u65f6\u95f4 : 0 days, 4 hour 51 min\r\n \u8d1f\u8f7d : 0.50, 0.19, 0.08\r\n \u7cfb\u7edf : Debian GNU/Linux 12 (bookworm) (x86_64)\r\n \u67b6\u6784 : x86_64 (64 Bit)\r\n \u5185\u6838 : 6.1.0-26-amd64\r\n TCP\u52a0\u901f\u65b9\u5f0f : cubic\r\n \u865a\u62df\u5316\u67b6\u6784 : KVM\r\n NAT\u7c7b\u578b : Port Restricted Cone\r\n IPV4 ASN : AS132203 Tencent Building, Kejizhongyi Avenue\r\n IPV4 \u4f4d\u7f6e : Tokyo / Tokyo / JP\r\n----------------------CPU\u6d4b\u8bd5--\u901a\u8fc7sysbench\u6d4b\u8bd5-------------------------\r\n -> CPU \u6d4b\u8bd5\u4e2d (Fast Mode, 1-Pass @ 5sec)\r\n 1 \u7ebf\u7a0b\u6d4b\u8bd5(\u5355\u6838)\u5f97\u5206: 1022 Scores\r\n 2 \u7ebf\u7a0b\u6d4b\u8bd5(\u591a\u6838)\u5f97\u5206: 1975 Scores\r\n---------------------\u5185\u5b58\u6d4b\u8bd5--\u611f\u8c22lemonbench\u5f00\u6e90-----------------------\r\n -> \u5185\u5b58\u6d4b\u8bd5 Test (Fast Mode, 1-Pass @ 5sec)\r\n \u5355\u7ebf\u7a0b\u8bfb\u6d4b\u8bd5: 22664.25 MB/s\r\n \u5355\u7ebf\u7a0b\u5199\u6d4b\u8bd5: 14543.86 MB/s\r\n------------------\u78c1\u76d8dd\u8bfb\u5199\u6d4b\u8bd5--\u611f\u8c22lemonbench\u5f00\u6e90--------------------\r\n -> \u78c1\u76d8IO\u6d4b\u8bd5\u4e2d (4K Block/1M Block, Direct Mode)\r\n \u6d4b\u8bd5\u64cd\u4f5c \u5199\u901f\u5ea6 \u8bfb\u901f\u5ea6\r\n 100MB-4K Block 4.8 MB/s (1171 IOPS, 21.85s) 10.5 MB/s (2553 IOPS, 10.03s)\r\n 1GB-1M Block 127 MB/s (121 IOPS, 8.23s) 267 MB/s (254 IOPS, 3.93s)\r\n---------------------\u78c1\u76d8fio\u8bfb\u5199\u6d4b\u8bd5--\u611f\u8c22yabs\u5f00\u6e90----------------------\r\nBlock Size | 4k (IOPS) | 64k (IOPS)\r\n ------ | --- ---- | ---- ----\r\nRead | 65.65 MB/s (16.4k) | 286.13 MB/s (4.4k)\r\nWrite | 65.79 MB/s (16.4k) | 287.64 MB/s (4.4k)\r\nTotal | 131.45 MB/s (32.8k) | 573.77 MB/s (8.9k)\r\n | |\r\nBlock Size | 512k (IOPS) | 1m (IOPS)\r\n ------ | --- ---- | ---- ----\r\nRead | 265.10 MB/s (517) | 258.28 MB/s (252)\r\nWrite | 279.18 MB/s (545) | 275.48 MB/s (269)\r\nTotal | 544.29 MB/s (1.0k) | 533.76 MB/s (521)\r\n------------\u6d41\u5a92\u4f53\u89e3\u9501--\u57fa\u4e8eoneclickvirt/CommonMediaTests\u5f00\u6e90-----------\r\n\u4ee5\u4e0b\u6d4b\u8bd5\u7684\u89e3\u9501\u5730\u533a\u662f\u51c6\u786e\u7684\uff0c\u4f46\u662f\u4e0d\u662f\u5b8c\u6574\u89e3\u9501\u7684\u5224\u65ad\u53ef\u80fd\u6709\u8bef\uff0c\u8fd9\u65b9\u9762\u4ec5\u4f5c\u53c2\u8003\u4f7f\u7528\r\n----------------Netflix-----------------\r\n[IPV4]\r\n\u60a8\u7684\u51fa\u53e3IP\u53ef\u4ee5\u4f7f\u7528Netflix\uff0c\u4f46\u4ec5\u53ef\u770bNetflix\u81ea\u5236\u5267\r\nNF\u6240\u8bc6\u522b\u7684IP\u5730\u57df\u4fe1\u606f\uff1a\u65b0\u52a0\u5761\r\n[IPV6]\r\n\u60a8\u7684\u7f51\u7edc\u53ef\u80fd\u6ca1\u6709\u6b63\u5e38\u914d\u7f6eIPv6\uff0c\u6216\u8005\u6ca1\u6709IPv6\u7f51\u7edc\u63a5\u5165\r\n----------------Youtube-----------------\r\n[IPV4]\r\n\u8fde\u63a5\u65b9\u5f0f: Youtube Video Server\r\n\u89c6\u9891\u7f13\u5b58\u8282\u70b9\u5730\u57df: \u65e5\u672c \u4e1c\u4eac(NRT12S24)\r\nYoutube\u8bc6\u522b\u5730\u57df: \u65e5\u672c(JP)\r\n[IPV6]\r\nYoutube\u5728\u60a8\u7684\u51fa\u53e3IP\u6240\u5728\u7684\u56fd\u5bb6\u4e0d\u63d0\u4f9b\u670d\u52a1\r\n---------------DisneyPlus---------------\r\n[IPV4]\r\n\u5f53\u524d\u51fa\u53e3\u6240\u5728\u5730\u533a\u89e3\u9501DisneyPlus\r\n\u533a\u57df\uff1aJP \u533a\r\n[IPV6]\r\nDisneyPlus\u5728\u60a8\u7684\u51fa\u53e3IP\u6240\u5728\u7684\u56fd\u5bb6\u4e0d\u63d0\u4f9b\u670d\u52a1\r\n\u89e3\u9501Netflix\uff0cYoutube\uff0cDisneyPlus\u4e0a\u9762\u548c\u4e0b\u9762\u8fdb\u884c\u6bd4\u8f83\uff0c\u4e0d\u540c\u4e4b\u5904\u81ea\u884c\u5224\u65ad\r\n----------------\u6d41\u5a92\u4f53\u89e3\u9501--\u611f\u8c22RegionRestrictionCheck\u5f00\u6e90--------------\r\n \u4ee5\u4e0b\u4e3aIPV4\u7f51\u7edc\u6d4b\u8bd5\uff0c\u82e5\u65e0IPV4\u7f51\u7edc\u5219\u65e0\u8f93\u51fa\r\n============[ Multination ]============\r\n Dazn: Yes (Region: JP)\r\n Disney+: No (IP Banned By Disney+ 1)\r\n Netflix: Originals Only\r\n YouTube Premium: Yes (Region: JP)\r\n Amazon Prime Video: Yes (Region: JP)\r\n TVBAnywhere+: Yes\r\n Spotify Registration: Yes (Region: JP)\r\n Instagram Licensed Audio: No\r\n OneTrust Region: JP [Tokyo]\r\n iQyi Oversea Region: JP\r\n Bing Region: JP\r\n YouTube CDN: Tokyo\r\n Netflix Preferred CDN: Tokyo\r\n ChatGPT: No (Only Available with Web Browser)\r\n Google Gemini: Yes (Region: JPN)\r\n Wikipedia Editability: No\r\n Google Search CAPTCHA Free: Yes\r\n Steam Currency: JPY\r\n ---Forum---\r\n Reddit: No\r\n=======================================\r\n \u4ee5\u4e0b\u4e3aIPV6\u7f51\u7edc\u6d4b\u8bd5\uff0c\u82e5\u65e0IPV6\u7f51\u7edc\u5219\u65e0\u8f93\u51fa\r\n---------------TikTok\u89e3\u9501--\u611f\u8c22lmc999\u7684\u6e90\u811a\u672c\u53cafscarmen PR--------------\r\n Tiktok Region: \u3010JP\u3011\r\n-------------IP\u8d28\u91cf\u68c0\u6d4b--\u57fa\u4e8eoneclickvirt/securityCheck\u4f7f\u7528-------------\r\n\u6570\u636e\u4ec5\u4f5c\u53c2\u8003\uff0c\u4e0d\u4ee3\u8868100%\u51c6\u786e\uff0c\u5982\u679c\u548c\u5b9e\u9645\u60c5\u51b5\u4e0d\u4e00\u81f4\u8bf7\u624b\u52a8\u67e5\u8be2\u591a\u4e2a\u6570\u636e\u5e93\u6bd4\u5bf9\r\n\u4ee5\u4e0b\u4e3a\u5404\u6570\u636e\u5e93\u7f16\u53f7\uff0c\u8f93\u51fa\u7ed3\u679c\u540e\u5c06\u81ea\u5e26\u6570\u636e\u5e93\u6765\u6e90\u5bf9\u5e94\u7684\u7f16\u53f7\r\nipinfo\u6570\u636e\u5e93 [0] | scamalytics\u6570\u636e\u5e93 [1] | virustotal\u6570\u636e\u5e93 [2] | abuseipdb\u6570\u636e\u5e93 [3] | ip2location\u6570\u636e\u5e93 [4]\r\nip-api\u6570\u636e\u5e93 [5] | ipwhois\u6570\u636e\u5e93 [6] | ipregistry\u6570\u636e\u5e93 [7] | ipdata\u6570\u636e\u5e93 [8] | db-ip\u6570\u636e\u5e93 [9]\r\nipapiis\u6570\u636e\u5e93 [A] | ipapicom\u6570\u636e\u5e93 [B] | bigdatacloud\u6570\u636e\u5e93 [C] | cheervision\u6570\u636e\u5e93 [D] | ipqualityscore \u6570\u636e\u5e93 [E]\r\nIPV4:\r\n\u5b89\u5168\u5f97\u5206:\r\n\u58f0\u8a89(\u8d8a\u9ad8\u8d8a\u597d): 0 [2]\r\n\u4fe1\u4efb\u5f97\u5206(\u8d8a\u9ad8\u8d8a\u597d): 0 [8]\r\nVPN\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 100 [8]\r\n\u4ee3\u7406\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 100 [8]\r\n\u793e\u533a\u6295\u7968-\u65e0\u5bb3: 0 [2]\r\n\u793e\u533a\u6295\u7968-\u6076\u610f: 0 [2]\r\n\u5a01\u80c1\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 100 [8]\r\n\u6b3a\u8bc8\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 0 [1] 65 [E]\r\n\u6ee5\u7528\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 0 [3]\r\nASN\u6ee5\u7528\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 0.0031 (Low) [A]\r\n\u516c\u53f8\u6ee5\u7528\u5f97\u5206(\u8d8a\u4f4e\u8d8a\u597d): 0.0133 (Elevated) [A]\r\n\u5a01\u80c1\u7ea7\u522b: low [9 B]\r\n\u9ed1\u540d\u5355\u8bb0\u5f55\u7edf\u8ba1:(\u6709\u591a\u5c11\u9ed1\u540d\u5355\u7f51\u7ad9\u6709\u8bb0\u5f55):\r\n\u65e0\u5bb3\u8bb0\u5f55\u6570: 0 [2] \u6076\u610f\u8bb0\u5f55\u6570: 0 [2] \u53ef\u7591\u8bb0\u5f55\u6570: 0 [2] \u65e0\u8bb0\u5f55\u6570: 94 [2]\r\n\u5b89\u5168\u4fe1\u606f:\r\n\u4f7f\u7528\u7c7b\u578b: hosting [0 7 9 A] business [8] hosting - high probability [C] DataCenter/WebHosting/Transit [3]\r\n\u516c\u53f8\u7c7b\u578b: business [A] hosting [0 7]\r\n\u662f\u5426\u4e91\u63d0\u4f9b\u5546: Yes [7 D]\r\n\u662f\u5426\u6570\u636e\u4e2d\u5fc3: Yes [0 1 5 6 A C] No [8]\r\n\u662f\u5426\u79fb\u52a8\u8bbe\u5907: Yes [E] No [5 A C]\r\n\u662f\u5426\u4ee3\u7406: Yes [E] No [0 1 4 5 6 7 8 9 A B C D]\r\n\u662f\u5426VPN: Yes [0 A E] No [1 6 7 C D]\r\n\u662f\u5426Tor: No [0 1 3 6 7 8 A B C D E]\r\n\u662f\u5426Tor\u51fa\u53e3: No [1 7 D]\r\n\u662f\u5426\u7f51\u7edc\u722c\u866b: No [9 A B E]\r\n\u662f\u5426\u533f\u540d: No [1 6 7 D] Yes [8]\r\n\u662f\u5426\u653b\u51fb\u8005: No [7 8 D]\r\n\u662f\u5426\u6ee5\u7528\u8005: No [7 8 A C D E]\r\n\u662f\u5426\u5a01\u80c1: No [7 8 C D]\r\n\u662f\u5426\u4e2d\u7ee7: No [0 7 8 C D]\r\n\u662f\u5426Bogon: No [7 8 A C D]\r\n\u662f\u5426\u673a\u5668\u4eba: No [E]\r\nDNS-\u9ed1\u540d\u5355: 314(Total_Check) 0(Clean) 5(Blacklisted) 15(Other)\r\nGoogle\u641c\u7d22\u53ef\u884c\u6027\uff1aYES\r\n-------------\u90ae\u4ef6\u7aef\u53e3\u68c0\u6d4b--\u57fa\u4e8eoneclickvirt/portchecker\u5f00\u6e90-------------\r\nPlatform SMTP SMTPS POP3 POP3S IMAP IMAPS\r\nLocalPort \u2714 \u2714 \u2714 \u2714 \u2714 \u2714\r\nQQ \u2718 \u2714 \u2714 \u2718 \u2714 \u2718\r\n163 \u2718 \u2714 \u2714 \u2718 \u2714 \u2718\r\nSohu \u2718 \u2714 \u2714 \u2718 \u2714 \u2718\r\nYandex \u2718 \u2714 \u2714 \u2718 \u2714 \u2718\r\nGmail \u2718 \u2714 \u2718 \u2718 \u2718 \u2718\r\nOutlook \u2718 \u2718 \u2714 \u2718 \u2714 \u2718\r\nOffice365 \u2718 \u2718 \u2714 \u2718 \u2714 \u2718\r\nYahoo \u2718 \u2714 \u2718 \u2718 \u2718 \u2718\r\nMailCOM \u2718 \u2714 \u2714 \u2718 \u2714 \u2718\r\nMailRU \u2718 \u2714 \u2718 \u2718 \u2714 \u2718\r\nAOL \u2718 \u2714 \u2718 \u2718 \u2718 \u2718\r\nGMX \u2718 \u2718 \u2714 \u2718 \u2714 \u2718\r\nSina \u2718 \u2718 \u2714 \u2718 \u2714 \u2718\r\n----------------\u4e09\u7f51\u56de\u7a0b--\u57fa\u4e8eoneclickvirt/backtrace\u5f00\u6e90----------------\r\n\u5317\u4eac\u7535\u4fe1 219.141.140.10 \u68c0\u6d4b\u4e0d\u5230\u56de\u7a0b\u8def\u7531\u8282\u70b9\u7684IP\u5730\u5740\r\n\u5317\u4eac\u8054\u901a 202.106.195.68 \u8054\u901a4837 [\u666e\u901a\u7ebf\u8def]\r\n\u5317\u4eac\u79fb\u52a8 221.179.155.161 \u79fb\u52a8CMI [\u666e\u901a\u7ebf\u8def]\r\n\u4e0a\u6d77\u7535\u4fe1 202.96.209.133 \u68c0\u6d4b\u4e0d\u5230\u56de\u7a0b\u8def\u7531\u8282\u70b9\u7684IP\u5730\u5740\r\n\u4e0a\u6d77\u8054\u901a 210.22.97.1 \u8054\u901a4837 [\u666e\u901a\u7ebf\u8def]\r\n\u4e0a\u6d77\u79fb\u52a8 211.136.112.200 \u68c0\u6d4b\u4e0d\u5230\u56de\u7a0b\u8def\u7531\u8282\u70b9\u7684IP\u5730\u5740\r\n\u5e7f\u5dde\u7535\u4fe1 58.60.188.222 \u68c0\u6d4b\u4e0d\u5230\u56de\u7a0b\u8def\u7531\u8282\u70b9\u7684IP\u5730\u5740\r\n\u5e7f\u5dde\u8054\u901a 210.21.196.6 \u8054\u901a4837 [\u666e\u901a\u7ebf\u8def]\r\n\u5e7f\u5dde\u79fb\u52a8 120.196.165.24 \u79fb\u52a8CMI [\u666e\u901a\u7ebf\u8def]\r\n\u6210\u90fd\u7535\u4fe1 61.139.2.69 \u68c0\u6d4b\u4e0d\u5230\u56de\u7a0b\u8def\u7531\u8282\u70b9\u7684IP\u5730\u5740\r\n\u6210\u90fd\u8054\u901a 119.6.6.6 \u8054\u901a4837 [\u666e\u901a\u7ebf\u8def]\r\n\u6210\u90fd\u79fb\u52a8 211.137.96.205 \u79fb\u52a8CMI [\u666e\u901a\u7ebf\u8def]\r\n\u51c6\u786e\u7ebf\u8def\u81ea\u884c\u67e5\u770b\u8be6\u7ec6\u8def\u7531\uff0c\u672c\u6d4b\u8bd5\u7ed3\u679c\u4ec5\u4f5c\u53c2\u8003\r\n\u540c\u4e00\u76ee\u6807\u5730\u5740\u591a\u4e2a\u7ebf\u8def\u65f6\uff0c\u53ef\u80fd\u68c0\u6d4b\u5df2\u8d8a\u8fc7\u6c47\u805a\u5c42\uff0c\u9664\u4e86\u7b2c\u4e00\u4e2a\u7ebf\u8def\u5916\uff0c\u540e\u7eed\u4fe1\u606f\u53ef\u80fd\u65e0\u6548\r\n---------------------\u56de\u7a0b\u8def\u7531--\u611f\u8c22fscarmen\u5f00\u6e90\u53caPR---------------------\r\n\u4f9d\u6b21\u6d4b\u8bd5\u7535\u4fe1/\u8054\u901a/\u79fb\u52a8\u7ecf\u8fc7\u7684\u5730\u533a\u53ca\u7ebf\u8def\uff0c\u6838\u5fc3\u7a0b\u5e8f\u6765\u81eaipip.net\u6216nexttrace\uff0c\u8bf7\u77e5\u6089!\r\n\u5e7f\u5dde\u7535\u4fe1 58.60.188.222\r\n0.56 ms * RFC1918\r\n51.64 ms * RFC1918\r\n1.04 ms AS2516 [KDDI] \u65e5\u672c \u4e1c\u4eac\u90fd \u4e1c\u4eac kddi.com\r\n1.30 ms AS2516 [KDDI] \u65e5\u672c \u4e1c\u4eac\u90fd \u4e1c\u4eac kddi.com\r\n2.13 ms AS2516 [KDDI] \u65e5\u672c \u4e1c\u4eac\u90fd \u4e1c\u4eac kddi.com\r\n8.56 ms AS2516 [KDDI] \u65e5\u672c \u5927\u962a\u5e9c \u5927\u962a\u5e02 kddi.com\r\n9.97 ms AS2516 [KDDI] \u65e5\u672c \u5927\u962a\u5e9c \u5927\u962a\u5e02 kddi.com\r\n7.90 ms AS2516 [KDDI] \u65e5\u672c \u5927\u962a\u5e9c \u5927\u962a kddi.com\r\n* ms AS2516 [APNIC-AP] \u4e2d\u56fd \u4e0a\u6d77 KDDI-CT-Peer kddi.com\r\n* ms AS4134 [CHINANET-BB] \u4e2d\u56fd \u5e7f\u4e1c \u5e7f\u5dde www.chinatelecom.com.cn\r\n* ms AS4134 \u4e2d\u56fd \u5e7f\u4e1c \u6df1\u5733 \u798f\u7530\u533a www.chinatelecom.com.cn \u7535\u4fe1\r\n\u5e7f\u5dde\u8054\u901a 210.21.196.6\r\n\r\n\u5e7f\u5dde\u79fb\u52a8 120.196.165.24\r\n\r\n--------------------\u81ea\u52a8\u66f4\u65b0\u6d4b\u901f\u8282\u70b9\u5217\u8868--\u672c\u811a\u672c\u539f\u521b--------------------\r\n\u4f4d\u7f6e \u4e0a\u4f20\u901f\u5ea6 \u4e0b\u8f7d\u901f\u5ea6 \u5ef6\u8fdf \u4e22\u5305\u7387\r\nSpeedtest.net 29.19 Mbps 224.88 Mbps 1.28 0.0%\r\n\u65e5\u672c\u4e1c\u4eac 29.75 Mbps 126.26 Mbps 1.10 NULL\r\n\u4e2d\u56fd\u9999\u6e2f 29.79 Mbps 226.47 Mbps 50.12 0.0%\r\n\u8054\u901aWuXi 26.51 Mbps 20.04 Mbps 213.37 16.8%\r\n\u7535\u4fe1Suzhou5G 29.04 Mbps 6.23 Mbps 276.79 NULL\r\n\u79fb\u52a8Beijing 30.67 Mbps 252.70 Mbps 99.08 NULL\r\n------------------------------------------------------------------------\r\n \u603b\u5171\u82b1\u8d39 : 7 \u5206 24 \u79d2\r\n \u65f6\u95f4 : Sun Nov 17 20:58:43 CST 2024\r\n------------------------------------------------------------------------\r\n \u77ed\u94fe:\r\n https://paste.spiritlhl.net/code/kqiPsk.txt\r\n http://hpaste.spiritlhl.net/code/kqiPsk.txt\r\n```\r\n\r\n</details>\r\n\r\n### Setup actions\r\n\r\n- Enlarge ssh timeout setting:\r\n\r\n```sh\r\n(root) vim /etc/ssh/sshd_config\r\n```\r\n\r\n```diff\r\n-#ClientAliveInterval 0\r\n-#ClientAliveCountMax 3\r\n+ClientAliveInterval 120\r\n+ClientAliveCountMax 30\r\n```\r\n\r\n```sh\r\n(root) systemctl restart ssh\r\n```\r\n\r\n- Add user and grant sudo:\r\n\r\n```sh\r\n(root) adduser purple4pur # interactive\r\n(root) groupadd njupt\r\n(root) usermod -aG njupt purple4pur\r\ngetent group njupt\r\n(root) EDITOR=vim visudo\r\n```\r\n\r\n```diff\r\n+purple4pur ALL=(ALL) ALL\r\n```\r\n\r\n- Install tools:\r\n\r\n[[Installing CLI Tools I Use on Debian/Linux]](https://blog.quitw.org/post/Installing%20CLI%20Tools%20I%20Use%20on%20Debian-Linux.html)\r\n\r\n- Initialize dotfiles:\r\n\r\n```sh\r\nbin/chezmoi init --apply https://github.com/purple4pur/dotfiles.git\r\nvim .bashrc\r\n```\r\n\r\n```diff\r\n+export PATH=$($HOME/custom_scripts/prepend-path $HOME/bin $HOME/opt/nvim-linux64/bin)\r\n+export EDITOR=nvim\r\n+alias v='nvim'\r\n+source ~/.config/.bash_setup\r\n```\r\n\r\n```sh\r\nsource .bashrc\r\n```\r\n\r\n- Good to go!\u3002", "top": 0, "createdAt": 1731951737, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-19", "dateLabelColor": "#bc4c00"}, "P17": {"htmlDir": "docs/post/Linux File Permissions.html", "labels": ["Dev", "Linux"], "postTitle": "Linux File Permissions", "postUrl": "post/Linux%20File%20Permissions.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/17", "commentNum": 0, "wordCount": 1860, "description": "### Quick reference\r\n\r\n```\r\n| type | [u]ser | [g]roup | [o]thers |\r\n| ---- | - - - | - - - | - - - | # Regular permissions\r\n| - | r | r | r | - can be read\r\n| - | w | w | w | - can be modified\r\n| - | x | x | x | - can be executed\r\n| d | r | r | r | - contents can be shown\r\n| d | x | x | x | - can be accessed with 'cd'\r\n| d | w x | w x | w x | - contents can be modified\r\n| ---- | - - - | - - - | - - - | # Special permissions\r\n| -/d | s | | | - setuid w/ 'x'\r\n| - | S | | | - setuid w/o 'x' (rare)\r\n| d | S | | | - (useless)\r\n| -/d | | s | | - setgid w/ 'x'\r\n| - | | S | | - setgid w/o 'x' (rare)\r\n| d | | S | | - (useless)\r\n| -/d | | | t | - sticky w/ 'x'\r\n| - | | | T | - sticky w/o 'x' (rare)\r\n| d | | | T | - sticky w/o 'x'\r\n```\r\n\r\n### Setuid (SUID)\r\n\r\n> `stat = 4---`\r\n\r\nWould be executed **as the file owner**. Useless on shebang scripts (for safety).\r\n\r\n- **/usr/bin/passwd**: `-rwsr-xr-x root root`\r\n\r\n### Setgid (SGID)\r\n\r\n> `stat = 2---`\r\n\r\nFiles/Directories created within the folder or by the file will **have the same group ownership** as it, and inherit this SGID bit.\r\n\r\n### Sticky\r\n\r\n> `stat = 1---`\r\n\r\nNot allowed to be removed.\r\n\r\n- **/tmp**: `drwxrwxrwt root root`\r\n\r\n### Appendix: links\r\n\r\n- [[File permissions and attributes - ArchWiki]](https://wiki.archlinux.org/title/File_permissions_and_attributes)\r\n- [[setuid - Wikipedia]](https://en.wikipedia.org/wiki/Setuid)\r\n- [[Sticky bit - Wikipedia]](https://en.wikipedia.org/wiki/Sticky_bit)\u3002", "top": 0, "createdAt": 1732208650, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-11-22", "dateLabelColor": "#bc4c00"}, "P18": {"htmlDir": "docs/post/Allow Non-superuser to Handle One's Application Container- Finding the Solution.html", "labels": ["Dev", "Linux", "Docker"], "postTitle": "Allow Non-superuser to Handle One's Application Container: Finding the Solution", "postUrl": "post/Allow%20Non-superuser%20to%20Handle%20One%27s%20Application%20Container-%20Finding%20the%20Solution.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/18", "commentNum": 0, "wordCount": 5364, "description": "### Background\r\n\r\nA friend of mine is hosting a QQ bot [(Miao-Yunzai)](https://github.com/yoimiya-kokomi/Miao-Yunzai) on my VPS, and let's call him friendR here. Recently I'm switching the bot to my new VPS, and trying to host as much as possible services in docker in order to keep the host machine clean.\r\n\r\nAfter some experiments I can use my modified Dockerfile and compose file to invoke the bot in container as I want. The next challenge is to allow friendR to up/down the bot container and run `npm run app` in it, because he might restart the bot anytime he want and does not need my involvement.\r\n\r\nSo my goals are:\r\n\r\n- **Security**: friendR should never be a superuser or in the docker group, or have any change to run arbitrary codes.\r\n- **Independence**: friendR should independently up/down a specific container, or run specific commands in the container.\r\n- **Volume run-through**: friendR should be able to modify bot related files bound into the container, easily.\r\n\r\n### Try#1: shell script w/ SUID\r\n\r\nWith SUID bit one can run the executable as the owner. So my basic thinking is to place a simple shell script like `docker compose -f /path/to/compose.yaml up -d` into friendR's path, set its owner to superuser, and set file mode to `5750 (rwsr-x--T)`.\r\n\r\nBut here are two problems. The greatest one is SUID bit will be ignored on shebang script, which means friendR still has no permission to call docker commands. The other one is also very critical to security, that is friendR can overwrite docker related files (Dockerfile, compose.yaml, etc.) because they are in his controlled directory.\r\n\r\n### Try#2: finite sudo permission\r\n\r\nI want to solve the permission issue first. I set the root owned `up.sh` to `0700 (rwx------)`, and allow friendR to sudo on this specific file (via `visudo`), so that he can call with `sudo ./up.sh`:\r\n\r\n```diff\r\n+friendR ALL=(root) /path/to/up.sh\r\n```\r\n\r\nYeah it works, but the security issue is even more obvious: friendR can simply overwrite `up.sh` to run anything as superuser. That is crazy and is definitely not acceptable.\r\n\r\nA possible fix is to prepend the file hash to the file path in `sudoers`, while I think it's way too inflexible.\r\n\r\n### Try#3: binary command wrapper w/ SUID (This works!)\r\n\r\nDuring the research of Try#1, I noticed a [Stack Overflow answer](https://unix.stackexchange.com/a/369) saying that one may write a script wrapper to call the shell to grant other user the superuser permission.\r\n\r\nI tried the C programming and quickly found the first issue: `system()` is to start a new process to run the following command, but not using the euid (Effective UID, influenced by SUID). That means friendR will not have permissions to call docker commands when he invokes the compiled binary.\r\n\r\nI didn't dive deep into how `system()` works with UID, because later I found using `exec()` can get rid of this issue. `exec()` is to replace current process with its argument command, which inherits process' euid.\r\n\r\nIn this way, I just copy the binaries to friendR's directory and set mode to `4750 (rwsr-x---)`, then friendR can call them to invoke hard-coded docker commands.\r\n\r\n### Bonus: complex commands wrapper workaround\r\n\r\nOne thing I didn't mention in Try#3 is actually the euid mechanism failed when I called `./up.sh` or `bash ./up.sh` with `exec()`. Somehow it might be also a security guard.\r\n\r\nAn enhancement to invoke `npm run app` in the container I want to achieve is to check if there's already a running process before starting the app. I wrote this check using shell script and finally realized I could hardly run the whole script in a single `exec()` calling.\r\n\r\nBefore my giving up suddenly it hit me that it's way easier to do this check inside the container, instead of using `docker compose top` outside. So I just leave a script calling to `docker exec`, and finish the rest of jobs inside the container.\r\n\r\n```c\r\n// run_app.c\r\nexeclp('docker', 'docker', 'compose', '-f', '/path/to/compose.yaml', 'exec', '-it', 'miao-yunzai', './run_app.sh', (char *)NULL);\r\n```\r\n\r\n```bash\r\n# run_app.sh\r\nif [[ '$(ps -aux | grep 'npm run app' | grep -v grep)' != '' ]]; then\r\n echo 'app is already running! will not start a 2nd one.'\r\n exit 1\r\nfi\r\necho '> npm run app'\r\nnpm run app\r\n```\r\n\r\n### Final solution\r\n\r\nTo keep it secured, all the docker related files are placed in my directory. Bot needed files are placed in friendR's directory, and bound into the container.\r\n\r\nC docker wrappers and simple Makefile:\r\n\r\n```c\r\n// up.c as an example\r\n#include <unistd.h>\r\n\r\nint main() {\r\n execlp('docker', 'docker', 'compose', '-f', '/path/to/compose.yaml', 'up', '-d', (char *)NULL);\r\n return 0;\r\n}\r\n```\r\n\r\n```makefile\r\n# Makefile\r\n# usage: make -B\r\n\r\nall: $(patsubst %.c,%,$(wildcard *.c))\r\n\r\n%: %.c\r\n\tgcc $< -o $@\r\n\tsudo cp $@ /home/friendR/Miao-Yunzai\r\n\tsudo chown root:friendR /home/friendR/Miao-Yunzai/$@\r\n\tsudo chmod 4750 /home/friendR/Miao-Yunzai/$@\r\n```\r\n\r\n### Conclusion\r\n\r\nAfter a few days of work finally it's solved. Providing a command wrapper in binary seems the only safe way to support this kinda crazy goal: letting non-superuser to manipulate docker while keep any other thing non-privileged.\r\n\r\nIt's hard to say this is a elegant solution but it works and, not too ugly I think? This can also be a useful reference whenever there's a similar scenario.\u3002", "top": 0, "createdAt": 1733388120, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-12-05", "dateLabelColor": "#bc4c00"}, "P19": {"htmlDir": "docs/post/Traefik Config Snippets.html", "labels": ["Dev", "Docker", "Traefik"], "postTitle": "Traefik Config Snippets", "postUrl": "post/Traefik%20Config%20Snippets.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/19", "commentNum": 0, "wordCount": 2347, "description": "> Apply to `traefik:v3.2`\r\n\r\n### Example traefik `compose.yaml`\r\n\r\nSee [purple4pur/docker_compose](https://github.com/purple4pur/docker_compose/blob/master/traefik/compose.yaml) .\r\n\r\n### Example `traefik.yaml`\r\n\r\n```yaml\r\nlog:\r\n level: 'WARN'\r\napi:\r\n dashboard: true\r\nproviders:\r\n docker:\r\n endpoint: 'unix:///var/run/docker.sock'\r\n exposedbydefault: false\r\nentryPoints:\r\n web:\r\n address: ':80'\r\n websecure:\r\n address: ':443'\r\ncertificatesResolvers:\r\n cloudflare:\r\n acme:\r\n email: '[email protected]'\r\n storage: '/letsencrypt/acme_cloudflare.json'\r\n dnsChallenge:\r\n provider: 'cloudflare'\r\n resolvers:\r\n - '8.8.8.8:53'\r\n - '1.1.1.1:53'\r\n myresolver:\r\n acme:\r\n email: '[email protected]'\r\n storage: '/letsencrypt/acme.json'\r\n httpChallenge:\r\n entryPoint: 'web'\r\n```\r\n\r\n### Route a https URL to an internal service on :8080\r\n\r\n```yaml\r\n ...\r\n labels:\r\n traefik.enable: true\r\n traefik.http.services.SERVICE_X.loadbalancer.server.port: '8080'\r\n traefik.http.routers.ROUTER_X.rule: '...'\r\n traefik.http.routers.ROUTER_X.entrypoints: 'websecure'\r\n traefik.http.routers.ROUTER_X.tls.certresolver: 'cloudflare'\r\n traefik.http.routers.ROUTER_X.service: 'SERVICE_X'\r\n```\r\n\r\n### middleware: redirectregex\r\n\r\nRedirect `dashboard.hostname.com...` to `https://hostname.com/dashboard...`:\r\n\r\n```yaml\r\n ...\r\n labels:\r\n ...\r\n # define redirectregex\r\n traefik.http.middlewares.MIDDLEWARE_X.redirectregex.regex: '^(?:https?:\\\\/\\\\/)?dashboard\\\\.hostname\\\\.com(.*)'\r\n traefik.http.middlewares.MIDDLEWARE_X.redirectregex.replacement: 'https://hostname.com/dashboard$${1}'\r\n ...\r\n # use redirectregex\r\n traefik.http.routers.ROUTER_X.service: 'noop@internal' # avoid auto linking this middleware to other services\r\n traefik.http.routers.ROUTER_X.middlewares: 'MIDDLEWARE_X'\r\n```\r\n\r\n### middleware: basicAuth\r\n\r\n```yaml\r\n ...\r\n labels:\r\n ...\r\n # define basicAuth\r\n traefik.http.middlewares.MIDDLEWARE_X.basicAuth.users: 'test:$apr1$7ij1g6q3$WiPOcMX6m/gWCC3kKP9kh0'\r\n ...\r\n # use basicAuth\r\n traefik.http.routers.ROUTER_X.middlewares: 'MIDDLEWARE_X'\r\n```\r\n\r\n, where `users` field is Apache salted MD5 generated by `htpasswd`:\r\n\r\n```sh\r\nhtpasswd -n USERNAME\r\n```\u3002", "top": 0, "createdAt": 1733929091, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-12-11", "dateLabelColor": "#bc4c00"}, "P20": {"htmlDir": "docs/post/Blog Deployment Automation- ONE Post, TWO Sites.html", "labels": ["Dev", "GitHub"], "postTitle": "Blog Deployment Automation: ONE Post, TWO Sites", "postUrl": "post/Blog%20Deployment%20Automation-%20ONE%20Post%2C%20TWO%20Sites.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/20", "commentNum": 0, "wordCount": 4617, "description": "### Background\r\n\r\nBefore this post, I was hosting this blog on github.io only, which is quite enough for internet access. But GitHub and github.io are facing connection issues in mainland China these days. What I'm trying to achieve is to deploy the blog to my server as well, which provides relatively easy access for viewers in China, and a customized URL.\r\n\r\nThis post shows the full view of my completely automated workflow of deploying this blog to two sites, along with detailed per step descriptions.\r\n\r\n### Workflow: the full view\r\n\r\n```\r\n GitHub\r\n+---------------------------------------+\r\n| +--------------------------+ |\r\n| | [A] write posts in Issue | |\r\n| +-------------|------------+ |\r\n| | |\r\n| +----------v----------+ |\r\n| +-------- [B] generate & push | |\r\n| | | (GitHub Actions) | |\r\n| | +----------|----------+ |\r\n| | | |\r\n| | +------------v------------+ |\r\n| | | [C] deploy to github.io <------- internet access\r\n| | | (GitHub Actions) | |\r\n| | +------------|------------+ |\r\n| | | | My Server\r\n| | +----------------v----------------+ | +---------------------+\r\n| | | [D] request server side pulling | | REST API | +-----------------+ |\r\n| | | (GitHub Actions) ------------------> | |\r\n| | +---------------------------------+ | | | [E] task runner | |\r\n| | git push | git pull | | (OliveTin) | |\r\n| +------------>[blog repo]<----------------------------- | |\r\n| | | | +--------|--------+ |\r\n| | | new commits | v |\r\n| +------------------------------------->[blog repo] |\r\n+---------------------------------------+ | | |\r\n | +--------v-------+ |\r\n | | [F] web server <---- internet access\r\n | | (nginx) | |\r\n | +----------------+ |\r\n +---------------------+\r\n```\r\n\r\n### Step [A], [B] and [C]\r\n\r\nThese steps are all in help with or provided by [Gmeek](https://github.com/Meekdai/Gmeek) , the GitHub-based blog tool (Shout-out to this really amazing tool!).\r\n\r\nWhen I open or edit an issue, Gmeek will check if it's a valid issue for a blog post, then generate the corresponding static web files, push changes to current repository, finally deploy to GitHub page (github.io).\r\n\r\nAfter that, <https://purple4pur.github.io/> is ready for internet access. Here is where the previous flow ends.\r\n\r\nCheck [`Gmeek.yml`](https://github.com/purple4pur/purple4pur.github.io/blob/main/.github/workflows/Gmeek.yml) for details.\r\n\r\n### Step [D]\r\n\r\nTo automatically update the blog in remote, I add a new GitHub Actions workflow right after when [C] completes. In this workflow a POST request will be sent to the task runner hosted on my server, telling it to do a git pull on the server side, then check the command result returned from the server.\r\n\r\nCheck [`pull_from_server.yaml`](https://github.com/purple4pur/purple4pur.github.io/blob/main/.github/workflows/pull_from_server.yaml) for details.\r\n\r\n### Step [E]\r\n\r\nHere is a task runner [(OliveTin)](https://github.com/OliveTin/OliveTin) that can run any predefined commands, with REST API provided. I have prepared a git work directory and a git pull command for it. So when this task is triggered, the local blog repository will fetch all changes from GitHub.\r\n\r\n### Step [F]\r\n\r\nA nginx server is hosting the local blog repo to provide internet access. What I didn't mention is the OliveTin instance and the nginx instance are all running in docker. So the tricky part here is they share a common volume to update or access the local repository.\r\n\r\nCheck [docker compose file](https://github.com/purple4pur/docker_compose/blob/master/blog/compose.yaml) for details.\r\n\r\n### Conclusion\r\n\r\nThis a my first time to try to connect all these services to do sequential jobs in such a workflow, and the results please me so well. Docker and the router Traefik actually make them much simpler and portable. I'm happy to take all-in-docker and continually having more fun with it.\u3002", "top": 0, "createdAt": 1734013722, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-12-12", "dateLabelColor": "#bc4c00"}, "P21": {"htmlDir": "docs/post/Trick the Client- Using a Custom Http Proxy.html", "labels": ["Dev", "Go", "Nginx"], "postTitle": "Trick the Client: Using a Custom Http Proxy", "postUrl": "post/Trick%20the%20Client-%20Using%20a%20Custom%20Http%20Proxy.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/21", "commentNum": 0, "wordCount": 7982, "description": "**DISCLAIMER: This project is for study only, and does nothing with to-server requests. Use with caution and at your own risk.**\r\n\r\n### Background\r\n\r\nI really enjoy playing a game, which handles almost everything on client side, and its server side is for ranking, replays, online matches, etc. As always, the server has a bad network connection for players in mainland China like me. So I was thinking if I could setup a relay server on my VPS, to provide a better connection of the game.\r\n\r\n### 1. Setup the relay server\r\n\r\nWhat I was thinking is a topology as follows:\r\n\r\n```\r\n+----------+ https +----------+ https +----------+\r\n| ----------------> ----------------> |\r\n| | | | | Actual |\r\n| Client | | Relay | | server |\r\n| | | | | |\r\n| <---------------- <---------------- |\r\n+----------+ https +----------+ https +----------+\r\n```\r\n\r\nActually it was going quite well. I use Traefik in the frontend to route all related requests to the backend. And in the backend there is a nginx instance to do a just `proxy_pass` job.\r\n\r\nOne thing I'd like to mention is how nginx is dealing with SSL/TLS certification. Requests it received from the frontend is http w/o TLS. I had to add the marked lines to make it work with actual server side TLS certification:\r\n\r\n```nginx\r\nserver {\r\n listen 8080;\r\n server_name localhost; # <--\r\n location / {\r\n resolver 8.8.8.8;\r\n proxy_pass https://actual.server.com$request_uri;\r\n proxy_ssl_server_name on; # <--\r\n proxy_ssl_session_reuse on;\r\n }\r\n}\r\n```\r\n\r\nLet's take a closer look of the topology now:\r\n\r\n```\r\n +----------------------------------------------+\r\n | Relay server |\r\n | |\r\n+----------+ https | +---------+ http +---------+ | https +----------+\r\n| --------------------> -------------------> --------------------> |\r\n| | | | | | | | | Actual |\r\n| Client | | | Traefik | | nginx | | | server |\r\n| | | | | | | | | |\r\n| <-------------------- <------------------- <-------------------- |\r\n+----------+ https | +---------+ http +---------+ | https +----------+\r\n | |\r\n +----------------------------------------------+\r\n```\r\n\r\nSo it works... Does it? Yeah technically it works very well, for doing the relay job. But here's an issue that about half of the time I can't hold a stable network connection between my client and the relay server! MANY THANKS TO THE FIREWALL. So it comes the bad news that the relay server doesn't do any help of a better connection.\r\n\r\nBut I would not stop here. Quickly I realized the whole traffic between the client and the server was going through my relay server, which meant that I could monitor anything in it, or even manipulate it as I want.\r\n\r\nLet's insert a middleware within the relay server!\r\n\r\n### 2. Insert the middleware\r\n\r\nI'd like to get rid of all the SSL/TLS stuff. So the best place are there: between Traefik and nginx. I put a http proxy in Golang there (first time Golang experience!).\r\n\r\nThe http proxy instance is a modified version of [wtsi-hgi/http-proxy-logger](https://github.com/wtsi-hgi/http-proxy-logger), with which I can dump the traffic I care to try to understand the packet structure. Now the topology looks like this:\r\n\r\n```\r\n +-------------------------------------------------------------+\r\n | Relay server |\r\n | |\r\n+----------+ https | +---------+ http +-------------+ http +---------+ | https +----------+\r\n| -------------------> -----------|-----(#)-----|----------> -------------------> |\r\n| | | | | | | | | | | Actual |\r\n| Client | | | Traefik | | Http Proxy | | nginx | | | server |\r\n| | | | | | | | | | | |\r\n| <------------------- <----------|-----(#)-----|----------- <------------------- |\r\n+----------+ https | +---------+ http +-------------+ http +---------+ | https +----------+\r\n | |\r\n +-------------------------------------------------------------+\r\n\r\n (#) - dump requests/responses\r\n```\r\n\r\nEverything is under my control. Can I do some funny things to the traffic?\r\n\r\n### 3. Trick the client\r\n\r\nThanks to other excellent open-source private server implements, I can find out what messages are sent back to the client by directly reading their source code. It caught my attention that a very bit indicates the user is a supporter, which unlocks some more options on the client side (, and client side only!).\r\n\r\nIt took me a bit longer time to exactly understand how the bytes are transferred in the response body and extract them in Golang [(code)](https://github.com/purple4pur/goup). And finally I was very surprised that the whole flow worked! Here's the topology now:\r\n\r\n```\r\n +-------------------------------------------------------------+\r\n | Relay server |\r\n | |\r\n+----------+ https | +---------+ http +-------------+ http +---------+ | https +----------+\r\n| -------------------> -----------|-------------|----------> -------------------> |\r\n| | | | | | | | | | | Actual |\r\n| Client | | | Traefik | | Http Proxy | | nginx | | | server |\r\n| | | | | | | | | | | |\r\n| <------------------- <----------|-----(*)-----|----------- <------------------- |\r\n+----------+ https | +---------+ http +-------------+ http +---------+ | https +----------+\r\n | |\r\n +-------------------------------------------------------------+\r\n\r\n (*) - trick here!\r\n```\r\n\r\n### What's next?\r\n\r\nWell, when I found that special bit, I was asking more options that the client could give me. But the reality is it only gives me about 50% of my expectation. It's not a actual issue because I was giving a best guess of it.\r\n\r\nSo I'm planing some further steps from here, including bringing back a monitor-only mode, finding more interesting bytes in the traffic, and one more step: can I do some server side jobs? Now I'm so curious if it's possible to implement the friend ranking in the relay side.\r\n\r\nWill see later (if any)!\u3002", "top": 0, "createdAt": 1734619888, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-12-19", "dateLabelColor": "#bc4c00"}, "P22": {"htmlDir": "docs/post/2024\uff1a-xin-cheng-shi-\uff0c-xin-gong-zuo-\uff0c-xin-xing-qu-\uff0c-he-geng-yuan-de-yi-di-lian.html", "labels": ["Thoughts"], "postTitle": "2024\uff1a\u65b0\u57ce\u5e02\uff0c\u65b0\u5de5\u4f5c\uff0c\u65b0\u5174\u8da3\uff0c\u548c\u66f4\u8fdc\u7684\u5f02\u5730\u604b", "postUrl": "post/2024%EF%BC%9A-xin-cheng-shi-%EF%BC%8C-xin-gong-zuo-%EF%BC%8C-xin-xing-qu-%EF%BC%8C-he-geng-yuan-de-yi-di-lian.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/22", "commentNum": 0, "wordCount": 1294, "description": "\u5176\u5b9e\u5f80\u5e74\u5e74\u672b\u4e5f\u6709\u60f3\u7740\u5199\u4e00\u7bc7\u81ea\u5df1\u7684\u5e74\u7ec8\u603b\u7ed3\uff0c\u4f46\u7a76\u7adf\u8fd8\u662f\u56e0\u4e3a\u61d2\uff08\u4e3b\u8981\u56e0\u7d20\uff09\u548c\u5e73\u53f0\u7684\u8003\u8651\uff0c\u96be\u4ea7\u4e8e\u52a8\u7b14\u4e4b\u524d\u3002", "top": 0, "createdAt": 1735540842, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2024-12-30", "dateLabelColor": "#bc4c00"}, "P23": {"htmlDir": "docs/post/2025 -nian- Live -ji-zhan-hui-can-zhan-ji-lu.html", "labels": ["LifeFlashes"], "postTitle": "2025 \u5e74 Live \u53ca\u5c55\u4f1a\u53c2\u6218\u8bb0\u5f55", "postUrl": "post/2025%20-nian-%20Live%20-ji-zhan-hui-can-zhan-ji-lu.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/23", "commentNum": 0, "wordCount": 459, "description": "### Live\n\n| No. | \u65e5\u671f | Live | \u57ce\u5e02 | \u573a\u9986 | \u7968\u4ef7 | \u573a\u8d29 | \u5907\u6ce8 |\n|---|---|---|---|---|---|---|---|\n| 1 | 1/11 | \u3010\u7981\u7535\u591c\u3011\u56db\u591c ONLY \u4e0d\u63d2\u7535 COVER | \u4e0a\u6d77 | \u4e0a\u6ee8\u835f | 68 | 130 | |\n| 2 | 1/12 | \u65e5\u97f3\u9f99\u5377 \u5f8b\u52a8\u5e7b\u60f3 | \u4e0a\u6d77 | THE BOXX | 0 | 0 | \u4e2d\u5956\u7968 |\n| 3 | 1/19 | \u548c\u97f3\u793e RE:HARMONIC NOVAE \u9996\u6f14 | \u4e0a\u6d77 | \u6797\u80af\u7235\u58eb\u4e50 | 220 | 0 | |\n| 4 | 2/15 | YOASOBI ASIA TOUR \u8d85\u73b0\u5b9e | \u4e0a\u6d77 | \u6885\u5954\u6587\u5316\u4e2d\u5fc3 | 2360 | | 1180 x2 |\n| 5 | 2/22 | BanGDream ONLY \u4e50\u961f\u62fc\u76d8 | \u82cf\u5dde | Wave LiveHouse | | | |\n| 6 | 2/23 | \u3010\u591c:\u6b4c\u75c7\u5019\u7fa4\u3011\u56db\u591c ONLY | \u4e0a\u6d77 | THE BOXX | | | |\u3002", "top": 0, "createdAt": 1736696656, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2025-01-12", "dateLabelColor": "#0969da"}, "P24": {"htmlDir": "docs/post/wo-de-bi-ji-ben- CPU -feng-shan-\uff0c-si-le.html", "labels": ["LifeFlashes"], "postTitle": "\u6211\u7684\u7b14\u8bb0\u672c CPU \u98ce\u6247\uff0c\u6b7b\u4e86", "postUrl": "post/wo-de-bi-ji-ben-%20CPU%20-feng-shan-%EF%BC%8C-si-le.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/24", "commentNum": 0, "wordCount": 1067, "description": "\u8fd9\u4e00\u5929\u7a76\u7adf\u662f\u5230\u4e86\uff1a\u7b14\u8bb0\u672c\u7535\u8111\u4e0d\u518d\u53d1\u51fa\u62d6\u62c9\u673a\u4e00\u822c\u5de8\u5927\u7684\u566a\u97f3\uff0c\u56de\u5230\u4e86\u4e45\u8fdd\u7684\u5b89\u9759\uff0c\u4f46\u8fd9\u8ba9\u6211\u66f4\u5bb3\u6015\u3002", "top": 0, "createdAt": 1737134977, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2025-01-18", "dateLabelColor": "#0969da"}, "P25": {"htmlDir": "docs/post/Why My Webdav Playback Is Broken- Cloudflare's in the Middle.html", "labels": ["Dev"], "postTitle": "Why My Webdav Playback Is Broken: Cloudflare's in the Middle", "postUrl": "post/Why%20My%20Webdav%20Playback%20Is%20Broken-%20Cloudflare%27s%20in%20the%20Middle.html", "postSourceUrl": "https://github.com/purple4pur/purple4pur.github.io/issues/25", "commentNum": 0, "wordCount": 1013, "description": "The title basically tells everything, which I finally figured it out after an unintentional file uploading.\n\nI run a frp server on the VPS to expose the Webdav hosted on my local laptop. As usual I put a Cloudflare proxy on DNS. That's the background.\n\nIt worked actually very fine and all functions seemed to be good. But the video playback was so laggy that most of the time I even could not start playing. I thought the problem was the poor network between my laptop and the VPS in Tokyo.\n\nRecently I tried to upload a 140MB file through Webdav to my laptop, but it always failed after an around 100MB transaction and got a **413 Request Entity Too Large** HTTP error. This error was given by [Cloudflare](https://developers.cloudflare.com/support/troubleshooting/http-status-codes/4xx-client-error/#413-payload-too-large-rfc7231), and till then I knew about the 100MB limitation for the first time.\n\nAfter I switched my DNS setting to no proxy, the file uploading issue was gone, so as the video playback one.\u3002", "top": 0, "createdAt": 1737649857, "style": "", "script": "", "head": "", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "createdDate": "2025-01-24", "dateLabelColor": "#0969da"}}, "singeListJson": {}, "labelColorDict": {"AXI": "#0091bd", "Dev": "#303030", "Docker": "#1d63ed", "EDA": "#5a2a82", "Gaming": "#e86aa3", "Git": "#f54d27", "GitHub": "#1f2328", "Go": "#79d4fd", "LifeFlashes": "#FBCA04", "Linux": "#185886", "Nginx": "#009639", "Review": "#0E8A16", "Systemverilog": "#ff7700", "Tech device": "#F9D0C4", "Thoughts": "#1D76DB", "Traefik": "#37abc7"}, "displayTitle": "Purple4pur's Canvas: the Blog", "faviconUrl": "https://avatars.githubusercontent.com/u/49893724", "ogImage": "https://avatars.githubusercontent.com/u/49893724", "primerCSS": "<link href='https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/Primer/21.0.7/primer.css' rel='stylesheet' />", "prevUrl": "/index.html", "nextUrl": "disabled"}