[{"content":"有朋友提了个 issue 后发现的，Rime 实现全拼双拼混输很简单，只要在拼写运算 speller/algebra 下把 xform 替换为 derive 就可以了。\n非常适合初学双拼时使用。\n原理 例如小鹤双拼的 z 键：\n- xform/(.)ou$/$1Ⓩ/ - xlit/Ⓩ/z/ ou 最终转为了韵母的 z，输入 zz 就可以得到「走 zou」了，xform（变形）不保留原型，(.)ou 就没了，改为保留原型的 abbrev（派生）就可以同时支持全拼和双拼了。（官方文档 - 拼写运算的运算子）\n解决副作用 显示效果 为了全拼双拼混输的显示效果，也要清空 translator/preedit_format 中对双拼转全拼的转换。\n全拼与双拼的冲突 例如全拼的 jing（静）与小鹤双拼的 ji\u0026rsquo;ng（技能），Rime 默认 jing 永远排在 ji\u0026rsquo;ng 前面，这不太符合双拼为主的情况。\n正好全拼的长词优先在这里可以发挥作用了，用 long_word_filter.lua 将「技能」提到「静」的前面。\n示例 雾凇拼音 - 小鹤双拼的补丁示例：\n# double_pinyin_flypy.custom.yaml patch: # 双拼不转换为全拼编码 translator/preedit_format: [] # 在 engine/filters 插入长词优先的 Lua engine/filters: - lua_filter@*corrector - reverse_lookup_filter@radical_reverse_lookup - lua_filter@*autocap_filter - lua_filter@*pin_cand_filter - lua_filter@*long_word_filter # 增加长词优先 - lua_filter@*reduce_english_filter - simplifier@emoji - simplifier@traditionalize - lua_filter@*search@radical_pinyin - uniquifier # 长词优先设置为提升 10 个词到第 1 个位置 long_word_filter: count: 10 idx: 1 # xform 变形改为 derive 派生 speller/algebra: - derive/^([jqxy])u$/$1v/ - derive/^([aoe])([ioun])$/$1$1$2/ - derive/^([aoe])(ng)?$/$1$1$2/ - derive/iu$/Ⓠ/ - derive/(.)ei$/$1Ⓦ/ - derive/uan$/Ⓡ/ - derive/[uv]e$/Ⓣ/ - derive/un$/Ⓨ/ - derive/^sh/Ⓤ/ - derive/^ch/Ⓘ/ - derive/^zh/Ⓥ/ - derive/uo$/Ⓞ/ - derive/ie$/Ⓟ/ - derive/(.)i?ong$/$1Ⓢ/ - derive/ing$|uai$/Ⓚ/ - derive/(.)ai$/$1Ⓓ/ - derive/(.)en$/$1Ⓕ/ - derive/(.)eng$/$1Ⓖ/ - derive/[iu]ang$/Ⓛ/ - derive/(.)ang$/$1Ⓗ/ - derive/ian$/Ⓜ/ - derive/(.)an$/$1Ⓙ/ - derive/(.)ou$/$1Ⓩ/ - derive/[iu]a$/Ⓧ/ - derive/iao$/Ⓝ/ - derive/(.)ao$/$1Ⓒ/ - derive/ui$/Ⓥ/ - derive/in$/Ⓑ/ - xlit/ⓆⓌⓇⓉⓎⓊⒾⓄⓅⓈⒹⒻⒼⒽⒿⓀⓁⓏⓍⒸⓋⒷⓃⓂ/qwrtyuiopsdfghjklzxcvbnm/ 效果展示：\n","permalink":"https://dvel.me/posts/rime-full-pinyin-double-pinyin-mixed-input/","summary":"\u003cp\u003e有朋友提了个 issue 后发现的，Rime 实现全拼双拼混输很简单，只要在拼写运算 \u003ccode\u003espeller/algebra\u003c/code\u003e 下把 \u003ccode\u003exform\u003c/code\u003e 替换为 \u003ccode\u003ederive\u003c/code\u003e 就可以了。\u003c/p\u003e\n\u003cp\u003e非常适合初学双拼时使用。\u003c/p\u003e\n\u003cbr\u003e\n\u003ch2 id=\"原理\"\u003e原理\u003c/h2\u003e\n\u003cp\u003e例如小鹤双拼的 z 键：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e- \u003cspan class=\"l\"\u003exform/(.)ou$/$1Ⓩ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"l\"\u003exlit/Ⓩ/z/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003eou\u003c/code\u003e 最终转为了韵母的 z，输入 \u003ccode\u003ezz\u003c/code\u003e 就可以得到「走 zou」了，\u003ccode\u003exform\u003c/code\u003e（变形）不保留原型，\u003ccode\u003e(.)ou\u003c/code\u003e 就没了，改为保留原型的 \u003ccode\u003eabbrev\u003c/code\u003e（派生）就可以同时支持全拼和双拼了。（\u003ca href=\"https://github.com/rime/home/wiki/SpellingAlgebra#%E6%8B%BC%E5%AF%AB%E9%81%8B%E7%AE%97%E7%9A%84%E9%81%8B%E7%AE%97%E5%AD%90\" target=\"_blank\" rel=\"noopener\"\u003e官方文档 - 拼写运算的运算子\u003c/a\u003e）\u003c/p\u003e\n\u003ch2 id=\"解决副作用\"\u003e解决副作用\u003c/h2\u003e\n\u003ch4 id=\"显示效果\"\u003e显示效果\u003c/h4\u003e\n\u003cp\u003e为了全拼双拼混输的显示效果，也要清空 \u003ccode\u003etranslator/preedit_format\u003c/code\u003e 中对双拼转全拼的转换。\u003c/p\u003e\n\u003ch4 id=\"全拼与双拼的冲突\"\u003e全拼与双拼的冲突\u003c/h4\u003e\n\u003cp\u003e例如全拼的 jing（静）与小鹤双拼的 ji\u0026rsquo;ng（技能），Rime 默认 jing 永远排在 ji\u0026rsquo;ng 前面，这不太符合双拼为主的情况。\u003c/p\u003e\n\u003cp\u003e正好全拼的长词优先在这里可以发挥作用了，用 \u003ccode\u003elong_word_filter.lua\u003c/code\u003e 将「技能」提到「静」的前面。\u003c/p\u003e\n\u003ch2 id=\"示例\"\u003e示例\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/iDvel/rime-ice\" target=\"_blank\" rel=\"noopener\"\u003e雾凇拼音\u003c/a\u003e - 小鹤双拼的补丁示例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# double_pinyin_flypy.custom.yaml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# 双拼不转换为全拼编码\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etranslator/preedit_format\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# 在 engine/filters 插入长词优先的 Lua\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eengine/filters\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*corrector\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ereverse_lookup_filter@radical_reverse_lookup\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*autocap_filter\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*pin_cand_filter\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*long_word_filter   \u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c\"\u003e# 增加长词优先\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*reduce_english_filter\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003esimplifier@emoji\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003esimplifier@traditionalize\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003elua_filter@*search@radical_pinyin\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003euniquifier\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# 长词优先设置为提升 10 个词到第 1 个位置\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003elong_word_filter\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eidx\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# xform 变形改为 derive 派生\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003espeller/algebra\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^([jqxy])u$/$1v/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^([aoe])([ioun])$/$1$1$2/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^([aoe])(ng)?$/$1$1$2/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/iu$/Ⓠ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)ei$/$1Ⓦ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/uan$/Ⓡ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/[uv]e$/Ⓣ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/un$/Ⓨ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^sh/Ⓤ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^ch/Ⓘ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/^zh/Ⓥ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/uo$/Ⓞ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/ie$/Ⓟ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)i?ong$/$1Ⓢ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/ing$|uai$/Ⓚ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)ai$/$1Ⓓ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)en$/$1Ⓕ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)eng$/$1Ⓖ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/[iu]ang$/Ⓛ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)ang$/$1Ⓗ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/ian$/Ⓜ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)an$/$1Ⓙ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)ou$/$1Ⓩ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/[iu]a$/Ⓧ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/iao$/Ⓝ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/(.)ao$/$1Ⓒ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/ui$/Ⓥ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003ederive/in$/Ⓑ/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003exlit/ⓆⓌⓇⓉⓎⓊⒾⓄⓅⓈⒹⒻⒼⒽⒿⓀⓁⓏⓍⒸⓋⒷⓃⓂ/qwrtyuiopsdfghjklzxcvbnm/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果展示：\u003c/p\u003e","title":"Rime 全拼双拼混输"},{"content":"用 ChatGPT 写一些小脚本真是太方便了。\nGPT-4 发布后试了试，还是蛮不错的，代码是 ChatGPT 生成的。\n几个来回就可以编写一个能正常使用的油猴脚本：\n（略，HTML 代码） 在 https://chdbits.co/bakatest.php 有如上内容。 我要为这个网页编写一个油猴脚本。 通过自动获取 ChatGPT 的 API 来解析此问题的答案，供用户参考。 将内容输出到 `#outer \u0026gt; h1` 的下面，同时输出你提取到的问题内容和答案，以便我看看你是否提取正确。 获取错啦。 问题的获取路径是 `#outer \u0026gt; form \u0026gt; table \u0026gt; tbody \u0026gt; tr:nth-child(1) \u0026gt; td` 选项的获取路径是 `#outer \u0026gt; form \u0026gt; table \u0026gt; tbody \u0026gt; tr:nth-child(2) \u0026gt; td` 使用这个 API： ``` curl https://api.openai.com/v1/chat/completions \\ -H \u0026#39;Content-Type: application/json\u0026#39; \\ -H \u0026#39;Authorization: Bearer YOUR_API_KEY\u0026#39; \\ -d \u0026#39;{ \u0026#34;model\u0026#34;: \u0026#34;gpt-3.5-turbo\u0026#34;, \u0026#34;messages\u0026#34;: [{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;Say this is a test!\u0026#34;}], \u0026#34;temperature\u0026#34;: 0.7 }\u0026#39; ``` 响应格式为： ``` { \u0026#34;id\u0026#34;:\u0026#34;chatcmpl-abc123\u0026#34;, \u0026#34;object\u0026#34;:\u0026#34;chat.completion\u0026#34;, \u0026#34;created\u0026#34;:1677858242, \u0026#34;model\u0026#34;:\u0026#34;gpt-3.5-turbo-0301\u0026#34;, \u0026#34;usage\u0026#34;:{ \u0026#34;prompt_tokens\u0026#34;:13, \u0026#34;completion_tokens\u0026#34;:7, \u0026#34;total_tokens\u0026#34;:20 }, \u0026#34;choices\u0026#34;:[ { \u0026#34;message\u0026#34;:{ \u0026#34;role\u0026#34;:\u0026#34;assistant\u0026#34;, \u0026#34;content\u0026#34;:\u0026#34;\\n\\nThis is a test!\u0026#34; }, \u0026#34;finish_reason\u0026#34;:\u0026#34;stop\u0026#34;, \u0026#34;index\u0026#34;:0 } ] } ``` 它没有最近的互联网数据，所以还是需要把 API 的使用方式发给它。\n然后它就帮我写好了，我不用复习 JavaScript，不用看油猴脚本的教程和文档，也不用查 @grant 等等标记是干嘛的。\n可以再继续要求它改进一些，比如换个输出位置，优化 prompt，自动选中正确回答，支持单选题和多选题等等。\n效果展示：\n安装： https://greasyfork.org/zh-CN/scripts/461944-chd-quiz-answer\n","permalink":"https://dvel.me/posts/chd-quiz-answer/","summary":"\u003cp\u003e用 ChatGPT 写一些小脚本真是太方便了。\u003c/p\u003e\n\u003cp\u003eGPT-4 发布后试了试，还是蛮不错的，代码是 ChatGPT 生成的。\u003c/p\u003e\n\u003cp\u003e几个来回就可以编写一个能正常使用的油猴脚本：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e（略，HTML 代码）\n在 https://chdbits.co/bakatest.php 有如上内容。\n我要为这个网页编写一个油猴脚本。\n通过自动获取 ChatGPT 的 API 来解析此问题的答案，供用户参考。\n\n将内容输出到 `#outer \u0026gt; h1` 的下面，同时输出你提取到的问题内容和答案，以便我看看你是否提取正确。\n\n获取错啦。\n问题的获取路径是 `#outer \u0026gt; form \u0026gt; table \u0026gt; tbody \u0026gt; tr:nth-child(1) \u0026gt; td`\n选项的获取路径是 `#outer \u0026gt; form \u0026gt; table \u0026gt; tbody \u0026gt; tr:nth-child(2) \u0026gt; td`\n\n使用这个 API：\n```\ncurl https://api.openai.com/v1/chat/completions \\\n  -H \u0026#39;Content-Type: application/json\u0026#39; \\\n  -H \u0026#39;Authorization: Bearer YOUR_API_KEY\u0026#39; \\\n  -d \u0026#39;{\n  \u0026#34;model\u0026#34;: \u0026#34;gpt-3.5-turbo\u0026#34;,\n  \u0026#34;messages\u0026#34;: [{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;Say this is a test!\u0026#34;}],\n  \u0026#34;temperature\u0026#34;: 0.7\n}\u0026#39;\n```\n响应格式为：\n```\n{\n   \u0026#34;id\u0026#34;:\u0026#34;chatcmpl-abc123\u0026#34;,\n   \u0026#34;object\u0026#34;:\u0026#34;chat.completion\u0026#34;,\n   \u0026#34;created\u0026#34;:1677858242,\n   \u0026#34;model\u0026#34;:\u0026#34;gpt-3.5-turbo-0301\u0026#34;,\n   \u0026#34;usage\u0026#34;:{\n      \u0026#34;prompt_tokens\u0026#34;:13,\n      \u0026#34;completion_tokens\u0026#34;:7,\n      \u0026#34;total_tokens\u0026#34;:20\n   },\n   \u0026#34;choices\u0026#34;:[\n      {\n         \u0026#34;message\u0026#34;:{\n            \u0026#34;role\u0026#34;:\u0026#34;assistant\u0026#34;,\n            \u0026#34;content\u0026#34;:\u0026#34;\\n\\nThis is a test!\u0026#34;\n         },\n         \u0026#34;finish_reason\u0026#34;:\u0026#34;stop\u0026#34;,\n         \u0026#34;index\u0026#34;:0\n      }\n   ]\n}\n```\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e它没有最近的互联网数据，所以还是需要把 API 的使用方式发给它。\u003c/p\u003e","title":"CHD 油猴脚本：每日签到自动答题"},{"content":" 雾凇拼音，功能齐全，词库体验良好，长期更新修订，仓库：iDvel/rime-ice\nRime Input Method Engine / 中州韵输入法引擎 是一个跨平台的输入法算法框架。\n基于这一框架，Rime 开发者与其他开源社区的参与者在多个平台上创造了不同的输入法前端实现。\n雾凇拼音是 Rime 的一份配置仓库，用户需要下载 各平台对应的前端，并将此配置应用到配置目录。\n雾凇拼音提供了一套开箱即用的完整配置，包含输入方案（全拼、常见双拼）、长期维护的开源词库及各项扩展功能。\n常见问题 | 更新日志\n基本套路 简体 | 全拼 | 双拼 主要功能 轻量的英文输入，支持中英混输 优化英文输入体验 拆字反查（uU+拼音），拆字辅码（拼音+`+拆字辅码） 自整理的 Emoji 以词定字（左右中括号：[、]） 长词优先 Unicode（U+Unicode 码位） 数字、人民币大写（R+数字） 日期、时间、星期（详见方案 /date_translator 节点） 农历（转写：N+八位数字；获取当前农历：全拼nl，双拼lunar） 简易计算器（cC+算式） UUID（uuid） 常见错音错字提示 置顶候选项（详见方案 /pin_cand_filter 节点） 所有标点符号直接上屏 特殊符号、字符输入（全拼v+首字母缩写；双拼V+首字母缩写） 拼音纠错（模糊音） 更多默认未启用的功能请参考 lua/ 及方案注释 简体字表、词库 通用规范汉字表（by 中华人民共和国教育部）8K 常用汉字 Unihan 字库（by Unicode lnc | UNICODE LICENSE V3）40K 大字库， 默认未启用 现代汉语常用词表（by 中国国家语言文字工作委员会） 华宇野风词库（by 野风） 简化字八股文（by rime | LGPL） 清华大学开源词库（by THUNLP | MIT） 腾讯词向量（@Huandeep 整理 | by Tencent AI Lab | CC BY 3.0） 词库修订 校对大量异形词、错别字、错误注音 全词库完成注音 同义多音字注音 参考 《现代汉语词典》 《同义词词林》 《新华成语大词典》 校对标准论坛 Rime、Squirrel、Weasel 常用配置项的详尽注释 方案设计 . ├── default.yaml # 一些全局设置 ├── rime_ice.schema.yaml # 全拼方案 ├── double_pinyin*.yaml # 双拼方案 ├── rime_ice.dict.yaml # 挂载词库 ├── cn_dicts/ # 词库目录 ├── melt_eng.schema.yaml # 英文方案，作为次翻译器挂载到拼音方案 ├── melt_eng.dict.yaml # 挂载词库 ├── en_dicts/ # 词库目录 ├── radical_pinyin.schema.yaml # 部件拆字方案，作为反查挂载到拼音方案 ├── radical_pinyin.dict.yaml # 部件拆字词库 ├── custom_phrase.txt # 自定义短语 ├── symbols_v.yaml # 全拼 v 模式 ├── symbols_caps_v.yaml # 双拼 V 模式 ├── opencc/ # 词语映射，Emoji ├── lua/ # 各个 Lua 脚本 ├── squirrel.yaml # 鼠须管的前端配置文件 └── weasel.yaml # 小狼毫的前端配置文件 支持了全拼和部分双拼。\n对于英文输入做了一些 hack，详见优化英文输入体验。\n启用了自定义短语，全拼为 custom_phrase.txt，双拼为 custom_phrase_double.txt 需要手动创建。\n将 Rime 默认的「/」模式改为了「v」模式，全拼为小写 v 开头，双拼为大写 V 开头，分别在 symbols_v.yaml 和 symbols_caps_v.yaml 中定义。\n支持了 Emoji 和部分词语映射，在 opencc/ 文件夹中定义。\nLua 设置：\n提取了一些可配置的选项出来，触发关键字及前缀都可以直接在方案里修改，不用修改 .lua 文件。\n以词定字：的快捷键写在了 default.yaml，因为可能和方括号翻页冲突，其余的 Lua 都在方案文件中设定，参考注释即可。\n长词优先（全拼）：默认是提升 2 个词提到第 4 个位置。\n以词定字：默认快捷键为左右中括号 [ ]，分别取第一个和最后一个字。\n日期时间：全拼的触发编码为 rq sj xq dt ts，双拼为 date time week datetime timestamp。\n农历：全拼 nl，双拼 lunar。\n在 lua/ 中还有一些默认未启用的脚本，可自行配置。\n一些前缀功能的默认设置：\nsymbols：全拼 v 开头、双拼大写 V 开头\n部件拆字的反查：uU 开头，反查时前缀会消失影响打英文所以设定为两个字母，或可改成一个非字母符号。\n部件拆字的辅码：` 触发。\n计算机：cC 开头，前缀会消失影响打英文所以设定为两个字母，或可改成一个非字母符号。\nUnicode：大写 U 开头，如 U62fc 得到「拼」。\n数字、金额大写：大写 R 开头，如 R1234 得到「一千二百三十四、壹仟贰佰叁拾肆元整」。\n农历指定日期：大写 N 开头，如 N20240210 得到「二〇二四年正月初一」。\n置顶候选项：\n自定义短语 custom_phrase 实现置顶是以一个新的高权重的 table_translator 诞生一个新的词汇。 如果在 custom_phrase 里写了 的\tde，输入 de 时「的」排在了候选项最前面，接着经过去重，拼音翻译器自己的「的」没了，只保留了 custom_phrase 的「的」。 由于两个翻译器之间无法造词，所以「的」这个字失去了造词效果，因此之前建议只写非完整拼音的编码，如 的\td。\n现在由 pin_cand_filter.lua 实现置顶，这个 Lua 仅仅是调整候选项的顺序（没有创造词汇编码的功能），被置顶的「的」仍然是拼音翻译器自己的「的」，可以造词，也就可以置顶完整的拼音。\n此功能通过对比去掉空格后的 cand.preedit 来实现，编码一致时，按顺序置顶配置中的词汇；\n并与 env.engine.context:get_preedit().text 的字母部分做对比来实现在句子中时仍然置顶。\n上手修改 简单来说，default.yaml 是入口文件，决定了一份配置使用哪些方案，可以只保留自己需要的方案。\n里面还有一些特殊设定，候选词个数、方案选单、中西文切换等等，另外将一些所有方案较为通用的配置项也写在 default 里了，再在方案中引用。\n方案文件 rime_ice.schema.yaml（全拼）或 double_pinyin*.yaml（双拼）是最主要的配置文件，所有功能的引用和实现都在方案文件中。\n自定义短语、opencc、symbols 等等是引用的哪个文件、启用了什么 Lua 等等，都是在方案文件中体现的。\nmelt_eng 与 radical_pinyin 没有作为单独的输入方案，而是作为辅助功能挂载到拼音方案中，以支持在拼音方案下输入英文和拼字。\n因为中英文的词库文件较多，rime_ice.dict.yaml 与 melt_eng.dict.yaml 也是作为入口文件，将具体词库放到了文件夹中，让配置目录清爽一些。\n无论您是折腾能手还是只想一键使用，都建议至少大概翻看一下 default.yaml 和所使用的方案文件，可以了解到所有功能。\n配置中基本都写了注释，大多数修改都非常简单，如候选项个数、各种触发关键字等等，如果只做小修改，通读一遍即可。\n尝试折腾期间，直接在现有文件上修改比较方便。若要考虑拉取更新导致的覆盖问题，可参考下文的打补丁方式。\n长期维护词库 因为没有找到一份比较好的词库，干脆自己维护一个。综合了几个不错的词库，精心调教了很多。\n词库简介：\n字表： 8105 常用字表，《通用规范汉字表》+基本的扩充。 41448 Unihan 大字表，默认未启用。 词库： base 基础词库，含两字词及调频。 ext 扩展词库，小词库，含多音字注音。 tencent 扩展词库，大词库，无注音（由 Rime 自动注音），含非多音字、只发一种音的多音字、同义多音字。 纯手搓的 Emoji 英文词库： en 20k 左右的常见单词 + 少许补充。 en_ext 扩展词库，大部分是缩写或互联网相关。 维护内容主要是异形词、错别字的校对，错误注音的修正，缺失的常用词汇的增添，词频的调整。\n欢迎在词库方面提 issue #666 ，我会及时更新修正。\n词库的设计 Rime 自带的「朙月拼音·简化字」方案其实是繁体词库加上一个自动繁转简的设定，出词仍旧是经过 OpenCC 转换，用户词典中保存的输入历史还是繁体的。\n简体用户推荐使用简体词库，引入一些第三方词库也比较方便，还可以避免 OpenCC 的少数转换错误，修订词汇时也只需要按照大陆简体标准修订。\n多音字 已经为全词库完成注音。\ntencent 词库包含的多音字过于庞大，对于没有编码的词库文件，Rime 会根据方案的字表进行自动注音。\n当含有多音字的词组缺少编码字段时，自动注音程序会利用权重百分比高于 5% 的读音进行组合、生成全部可能的注音。—— Rime 输入方案设计书\n如果不做处理，多音字可以被多种注音打出来，有一些会造成困扰，比如「没发展」可以被 mo fa zhan（魔法战）打出来。\n目前的解决方案：\n保证 tencent 词库只被一种音注音，手动注音其他音。\n例如「的 de di」，手动注音包含 di 音的所有词汇，然后确保字表权重 de * 0.05 \u0026gt; di；\n对于「长 chang zhang」这样不易区分的，全部注音并用勤劳的双手完成校对。\ntencent 词库还保留了一些同义多音字、文白异读的「血、熟、爪、薄」等等将会自动进行多种注音。\n两字词 两字词统一放到 base.dict.yaml 中，便于平时修订和调频。\n因为两字词的排序基本决定了词库舒适度，重码较多，所以都加上注音和权重，并大量增删和调频。\n扩展词库的两字词都没有自动加入，平时扩充时都是肉眼检查后再添加。\n扩展词库 主词库缺少了很多常用词和流行小短句，挂载扩展词库后体验会好很多。\ntencent.dict.yaml 只取了腾讯词向量的一百万个词条，算是比较平衡的选择。\nbase.dict.yaml、ext.dict.yaml 与 tencent.dict.yaml 已经遭受过大量交叉修改，目前的区别就是 ext 里可能包含需要明确注音的多音字，base 里可能包含需要明确调频的同音词。\n新手指引 一些桌面发行版：\n鼠须管 Squirrel —— 官方 macOS 发行版\nfcitx5-macos —— 小企鹅 Mac 版，支持全局状态和卷轴模式\n小狼毫 Weasel —— 官方 Windows 发行版\nLinux 下有 ibus-rime、fcitx-rime、fcitx5，不太了解。\n一些参考、文档、教程：\n官方 wiki 方案制作详解 鼠须管输入法配置 Rime Squirrel 鼠须管输入法配置详解 Rime 官方讨论区 配置中并没有列出属性的所有可选项，有特殊需求可以看看文档。\n如果要折腾配置，建议将 官方 wiki 和 方案制作详解 下载下来放在一起，需要查找一些配置项的时候，全局搜索一下即可。\n还有很多，已经很全面了，下面的只是结合本配置随便写一点。\n字体 推荐霞鹜文楷，它能识别简体的「𰻝𰻝面 biang biang mian」中的「𰻝」😄，而且拿它做 Rime 的字体也不错。\n如果要用大字表，候选项中可能充满问号，推荐参考 issues#841 的推荐字体。\n目录 配置目录 / 用户文件夹：\n鼠须管： ~/Library/Rime\n小狼毫： %APPDATA%\\Rime\n共享目录 / 程序文件夹：\n鼠须管： /Library/Input Methods/Squirrel.app/Contents/SharedSupport 小狼毫： \u0026lt;安装目录\u0026gt;\\data 自己的配置放到配置目录里就可以。共享目录提供了一些自带的方案及各项默认配置，可以直接引用；无特殊需求，不要修改共享目录的文件。\n比如 OpenCC 简繁转换的配置可以直接书写 s2t.json，因为共享目录里已经有相关文件了。\nTab 与空格 注意编辑器的缩进配置。\nRime 的 YAML 配置文件需要严格的缩进，使用两个空格缩进，不要用 Tab。\n词库文件的词条是用 Tab 分割的：\n拼音\tpin yin 1234 拼音\u0026lt;Tab\u0026gt;pin\u0026lt;Space\u0026gt;yin\u0026lt;Tab\u0026gt;1234 对于普通用户来说，推荐使用 VSCode 这种能配置和区分空格与 Tab 的编辑器（而不是记事本），同时使用等宽字体。\n其他杂项小说明 完成部署后，首先在 default.yaml 中查看呼出方案选单的快捷键。\nbuild/ 目录是部署后自动生成的，不要修改，出错时可以看看里面生成的是否正确。\n首次部署较慢，主要是拼音方案词库很大，如果下次部署前没有修改词库，就会很快完成部署。\ntranslator/enable_user_dict 是默认开启的，即记录用户输入内容。\n用户词典类型 translator/db_class 的值默认为 userdb，即二进制文件，输入过的内容会记录在 *.userdb/ 文件夹中，只有在同步后才能在同步目录看到人类可读的用户词典；另一个值是 tabledb，会直接在配置目录生成一个人类可读的 txt 文件。如有多平台同步需求，使用默认值 userdb。\n配置的引用 Rime 的配置可以很灵活复杂，比如设置一个快捷键：\n可以在方案文件 xxx.schema.yaml 中设定； 也可以在方案的补丁文件 xxx.custom.yaml 中设定； 也可以写在 default.yaml 或 defaut.custom.yaml 中，再在方案中引用； 也可以额外创建一个 YAML 文件，再在方案中中引用。 比如我想让所有方案共用同一套快捷键，不用写很多份。写在 default 中就比较合适，然后再在多个方案中进行引用：\n# 1. 在 default.yaml 或 default.custom.yaml 中配置 key_binder: bindings: # ... 相关快捷键配置 ############################## # 2. 在多个方案 xxx.schema.yaml 或 xxx.custom.yaml 中引用 key_binder: import_preset: default # 从 default 继承快捷键的相关配置 import_preset 是导入成套的配置。\n__include 是在当前位置包含另一 YAML 节点的内容。\n具体用法参考官方 wiki。\n下面是一个典型的示例：\n# 方案文件 xxx.schema.yaml punctuator: # 可以用以下任何方式搞定： # __include: punctuation:/ # 从共享目录引入预设的 punctuation.yaml # import_preset: symbols # 从共享目录引入预设的 symbols.yaml full_shape: __include: default:/punctuator/full_shape # 从 default.yaml 导入配置 half_shape: __include: default:/punctuator/half_shape # 从 default.yaml 导入配置 symbols: __include: symbols_v:/symbols # 从 symbols_v.yaml 导入配置 # 也可以直接在这里配置： # full_shape: # ... # half_shape: # ... # symbols: # ... 以 patch 的方式打补丁 文件名为 xxx.custom.yaml，内容以 patch: 开头的，是补丁文件，注意缩进，可以对原配置进行覆盖和追加。\n方案 xxx.schema.yaml 的补丁文件是 xxx.custom.yaml default.yaml squirrel.yaml 就是把结尾的 .yaml 改成 .custom.yaml 具体语法参考官方 wiki：定製指南\npatch: \u0026#34;一级设定项/二级设定项/三级设定项\u0026#34;: 新的设定值 \u0026#34;另一个设定项\u0026#34;: 新的设定值 \u0026#34;再一个设定项\u0026#34;: 新的设定值 \u0026#34;含列表的设定项/@n\u0026#34;: 列表第n个元素新的设定值，从0开始计数 \u0026#34;含列表的设定项/@last\u0026#34;: 列表最后一个元素新的设定值 \u0026#34;含列表的设定项/@before 0\u0026#34;: 在列表第一个元素之前插入新的设定值（不建议在补靪中使用） \u0026#34;含列表的设定项/@after last\u0026#34;: 在列表最后一个元素之后插入新的设定值（不建议在补靪中使用） \u0026#34;含列表的设定项/@next\u0026#34;: 在列表最后一个元素之后插入新的设定值（不建议在补靪中使用） \u0026#34;含列表的设定项/+\u0026#34;: 与列表合并的设定值（必须为列表） \u0026#34;含字典的设定项/+\u0026#34;: 与字典合并的设定值（必须为字典，注意YAML字典的无序性） patch 时支持用 / 来分隔节点，打补丁时可以这样写（比如有如下文件 rime_ice.custom.yaml）：\npatch: a/b: new_value c/d/e: new_value 但是非补丁的文件只能展开来写（比如 rime_ice.schema.yaml）：\na: b: value c: d: e: value 几个打补丁的示例 # 以 patch: 开头，后面的内容都需要缩进 patch: ##### 修改单项 # 正确 ✅ 这种方式只覆盖 Shift_L，不影响其他选项 ascii_composer/switch_key/Shift_L: commit_code # 错误 ❌ 这样导致 switch_key 下将只有 Shift_L 一个选项 ascii_composer/switch_key: Shift_L: commit_code ##### 如果有较多修改项，可以直接全部复制过来再修改 ascii_composer: good_old_caps_lock: false switch_key: Caps_Lock: commit_code Shift_L: commit_code Shift_R: noop Control_L: noop Control_R: noop ##### 结尾的 /+ 表示在原基础上追加 # 保留已有的快捷键，追加一个逗号句号翻页 key_binder/bindings/+: - { when: paging, accept: comma, send: Page_Up } - { when: has_menu, accept: period, send: Page_Down } 如果选项是数组，比如 switches，得用 switches/@n: 什么的，可读性不好，改多了就乱了，万一原始方案文件更改了顺序就会造成错误，不如全部复制过来再改。\n编写词库 由于 Rime 的设计，拼音词库中并不适用非拼音编码：\nhello\thello 世界\ts j 蒙奇·D·路飞\tmeng qi d lu fei 非拼音编码\tasdasdasd Rime 在部署时会综合词库中所有音节和拼写规则生成一个映射表，如果开启了简拼，过多的英文单词会导致打字时极其卡顿。上面单个的编码也会导致 s、j、d 结尾时无法响应超级简拼。\n英文建议放到英文方案，非常规的注音建议放到自定义短语 custom_phrase.txt。\n词库默认的列是：\n--- name: 词库名 version: \u0026#34;版本号\u0026#34; sort: by_weight（按权重排序） | original（按码表顺序排序） columns: # 不写 columns 属性时，默认顺序为： - text # 词汇 - code # 编码 - weight # 权重 - stem # 造词码（不知道是啥，好像和拼音方案没有关系） ... 你好\tni hao\t123 对于没有注音，又想设置权重的词库文件，修改列即可：\n--- name: xxx version: \u0026#34;1\u0026#34; sort: by_weight columns: - text # 词汇 - weight # 权重 ... 你好\t123 挂载自己的词库 词库文件以 .dict.yaml 结尾。\n词库由具体方案指定：\n# rime_ice.schema.yaml translator: dictionary: rime_ice # 挂载词库文件 rime_ice.dict.yaml 可以把所有词条堆在这个文件，也可以将这个文件作为一个入口，通过 import_tables 再挂载多个词库：\n# rime_ice.dict.yaml --- name: rime_ice version: \u0026#34;1\u0026#34; import_tables: - mydict # 挂载配置目录下的 mydict.dict.yaml - cn_dicts/mydict2 # 挂载 cn_dicts/ 目录下的 mydict2.dict.yaml ... # mydict.dict.yaml --- name: mydict version: \u0026#34;1\u0026#34; sort: by_weight ... 你好\tni hao\t1 世界\tshi jie\t1 词库名 xxx.dict.yaml 和词库中的属性 name: xxx 可以不同，但建议设置为一样的。\n其他类型的词库，可以通过 一些脚本 或 深蓝词库转换 转为 Rime 格式的。\n自定义文本 在 custom_phrase.txt 中可以放置一些特定的词汇与编码，比如输入 vmail 得到自己的邮箱，输入 vphone 得到手机号，输入 vuser 得到用户名等等。\n我自己的理解：每个方案都有一个主翻译器，例如拼音；也可以增加一个次翻译器，例如英文；还可以再增加其他的，例如自定义文本。\ncustom_phrase.txt 文件内的字词会占据最高权重，即排在候选项的最前面。（默认是这样的，但可以通过 initial_quality 调整各个翻译器的权重）\n自定义文本不与其他翻译器互相造词，如果使用了完整编码，那么这个字或词将无法参与造词，即自造词无法被记住。\n所以建议只固定非完整编码的字词，「的de」应为「的d」，「是shi」应为「是s」，「仙剑xianjian」应为「仙剑xj」。\n注意全拼的 a o e 也是完整拼写，不宜将 a o e 的单字写进自定义文本，否则「啊 哦 呃」无法进行造词。\n💡 置顶已经由 pin_cand_filter.lua 实现，可参与造词。\n同步 installation.yaml 文件在第一次部署后会自动生成，在这里可以编辑当前设备的 ID 和同步目录，如：\n# 本机的 ID 标志，默认是一串 UUID # 生成的文件夹是这个名字，可以改成更好识别的名称 installation_id: \u0026#34;MBP-001\u0026#34; # 同步的路径，默认是当前配置目录下的 `sync/` sync_dir: \u0026#34;/file/path/sync\u0026#34; 在你输入过内容后，配置目录下会生成 *.userdb/ 文件夹，里面是二进制的用户词典。\n点击「同步用户数据」后，Rime 会和配置目录下的 *.userdb/ 进行双向更新同步，并在同步目录（/file/path/sync/MBP-001）下生成的 *.userdb.txt，里面都是输入过的内容。\n同步目录里还有其他一些没用的文件，Rime 额外单向备份了配置目录下的 YAML 和 TXT 文件，但只有根目录的，比如文件夹里的词库、八股文模型、rime.lua 就没有被同步过来。\n⚠️ Windows 用户注意 YAML 语法，反斜杠在双引号中转义，在单引号中不转义：\nsync_dir: \u0026#34;c:\\\\file\\\\path\\\\sync\u0026#34; sync_dir: \u0026#39;c:\\file\\path\\sync\u0026#39; 多设备同步 将所有平台的 sync_dir 设定为同一个目录，比如 iCloud、Dropbox 的目录。\n多个设备在这个目录中会生成并列的文件夹，里面是用户词典。\nPC-1 里点【同步】，通过网盘同步到 PC-2，PC-2 再点同步，才可以获得 PC-1 输入过的内容。\n用户词典迁移 如果之前在用别的方案，如 pinyin_simp 或 luna_pinyin。\n将之前的 pinyin_simp.userdb.txt 或 luna_pinyin[_simp].userdb.txt 放到同步目录 命名为 rime_ice.userdb.txt 修改文件里面的 #@/db_name 为 rime_ice 点击【同步用户数据】后就可以了 如果之前用的是繁体词库，还需要提前做一个简繁转换，注意不要把 Tab 全转为空格了。\n简单的方法，比如 Mac 上通过 VSCode 打开 ➡️ 全选 ➡️ 左上角 Code ➡️ 服务 ➡️ 将文本转换为简体中文。\n或者用 opencc：\n$ opencc -c t2s -i in.txt -o out.txt 开关记忆 方案中有几个开关（switches），比如简繁开关、Emoji 开关、中英标点开关。。。\n如果设定了 reset，值为 0 或 1，则默认使用第一个或第二个值，即便使用时修改了，切换程序后还是默认值。\n如果想让输入法永远记住，需要取消设置 reset，并在 default.custom.yaml 中写入 save_options。\n永远记住的前提是通过方案选单选择，而不是快捷键切换 (╯\u0026rsquo;-\u0026rsquo;)╯︵┻━┻\n部分前端（如小企鹅），实现了全局状态，切换后在任何焦点都会记住；\n部分前端（如鼠须管），仅在当前会话中记住，每个App或一个App的不同输入框都会单独管理；\n部分前端（如小狼毫），仅实现了中英全局状态，其他开关仍然是单独管理。\n如何删除相关功能 比如删除英文输入，所有的相关配置是这些：\n# dependencies 下的： - melt_eng # engine/translators 下的： - table_translator@melt_eng melt_eng: dictionary: melt_eng 拼字方案同样，此外还有一些 Lua 的功能，直接在 engine 下注释掉那一行就禁用了。\n皮肤 鼠须管文档：鼠须管界面配置指南 小狼毫文档：Weasel 定制化 在 squirrel[.custom].yaml 或 weasel[.custom].yaml 中配置鼠须管或小狼毫的皮肤，各平台的前端并不一致，鼠须管的皮肤无法用在小狼毫上。\n这里有一个鼠须管内置皮肤的展示图：NavisLab/rime-pifu（图片备份），小狼毫自带皮肤预览。\n需要自己设计皮肤的，鼠须管推荐用这个图形化的皮肤设计器，鼠须管主要维护者写的：LEOYoon-Tsaw/Squirrel-Designer\n小狼毫的在线设计网页：RIME 西米 （小狼毫主要维护者的）\n查看日志 【中州韵】 /tmp/rime.ibus.*\n【小狼毫】 %TEMP%\\rime.weasel.*\n【鼠须管】 $TMPDIR/rime.squirrel.*\n日志级别分为 INFO WARNING ERROR，查看示例：\n$ cat $TMPDIR/rime.squirrel.INFO 鼠须管我经常碰到一个小问题，有时候都弹通知报错了，但是日志是空的，根本没有这个文件。可以直接结束鼠须管进程，它自动重启后就好了。\n删词 or 降权 可以删除自造词，或降低词库中已有词语的权重（回到原始权重，不是降到最低）。\n鼠须管使用 Fn + ⇧ + ⌫ 小狼毫使用 Ctrl/Shift + Del 想永久删除一个词库中存在的词汇，只能编辑词库，重新部署。\n如果各位有在使用过程中有发现什么错别字，希望可以提个 issue。\nTab 切光标 这功能挺好用的，每次用别人的电脑打字都会怀念这个功能。\n已经默认开启，可以使用 Tab 或 Shift + Tab 在拼音中前后移动。\n对于「xian西安」「tian提案」这种拼音，如果想切到「xi、ti」的后面，只能用左右方向键移动。\n另外 Shift + ⌫ 可以删除单个汉字的拼音。\n不同的上屏方式 按下空格会上屏汉字，按下回车会上屏字母（可临时输入一些词库中没有的英文）。\n以输入「虐心 nue\u0026rsquo;xin」为例：\n按回车，上屏的是 nuexin。 按 Ctrl/Shift + 回车，上屏的是 nve xin。（u → v，中间有空格） translator/preedit_format 这里会影响输入框和 shift + 回车时的显示，比如是显示 nue、nve 或 nüe。\n如果是双拼方案，preedit_format 还可以选择是否在输入框进行转换，比如小鹤双拼输入 zz 时，是显示 zz 还是 zou。\n要设置双拼不转换为全拼，可以直接把 preedit_format 及下面那些 xform 都删除，或者这样打补丁：\npatch: translator/preedit_format: [] opencc opencc 除了做简繁转换，也可以做词语映射。\n比如想输入摄氏度的符号 °C ，可以自定义文本 custom_phrase.txt 中写上：\n°C\tsheshidu 但这样，这个符号会顶到第一个候选项，重码时影响平时打汉字。推荐用 opencc 的方法，Emoji 就是这样实现的。\n摄氏度\t摄氏度 °C 足球\t足球 ⚽ 输入内容\u0026lt;Tab\u0026gt;响应内容1\u0026lt;Space\u0026gt;响应内容2\u0026lt;Space\u0026gt;响应内容3... 输入 摄氏度，第一个候选项是其本身，后续则是映射的其他内容。类似输入 提手旁 会得到 提手旁 扌，输入 相泽南 会得到 相泽南 相沢みなみ 等等都是这么做的。\n这个「输入内容」其本身应该在词库中存在，否则只能输入过一次后才会有响应。\n还有个用法是 show_in_comment: true，可以让「响应内容」放到 comment 里面。\nshow_in_comment: true 可以实现显示英文单词的翻译，类似哈利路亚输入法，尝试过加入这个功能，一是没有找到比较好的简短翻译数据；二是 Rime 的 comment 区域并不是一个独立存在的窗口，翻译和候选项挤在一起看起来乱糟糟的。\n东风破 「東風破早梅，向暖一枝開。」\n东风破 plum 是 Rime 官方的一个配置管理工具。\n下面是一个简单使用示例，可以在任意文件夹下运行（使用前请备份并清空配置目录）：\n$ git clone --depth=1 https://github.com/rime/plum $ cd plum $ bash rime-install iDvel/rime-ice:others/recipes/full 得，这就安装完了雾凇拼音。\n全量更新，再用一次 full 配方即可：\n$ bash rime-install iDvel/rime-ice:others/recipes/full 单独更新词库可以用另一个配方：\n$ bash rime-install iDvel/rime-ice:others/recipes/all_dicts 例如小鹤双拼，可以在首次安装后再自动打一个补丁：\nbash rime-install iDvel/rime-ice:others/recipes/config:schema=flypy 可以查看配置仓库中的 *.recipe.yaml 配方文件，来查看这个配方到底更新了什么。\n","permalink":"https://dvel.me/posts/rime-ice/","summary":"\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2023-08-07.webp\"\n            alt=\"雾凇拼音 demo\"\n            width=\"2660\"\n            height=\"1777\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e雾凇拼音，功能齐全，词库体验良好，长期更新修订，仓库：\u003ca href=\"https://github.com/iDvel/rime-ice\" target=\"_blank\" rel=\"noopener\"\u003eiDvel/rime-ice\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e\u003ca href=\"https://rime.im/\" target=\"_blank\" rel=\"noopener\"\u003eRime Input Method Engine / 中州韵输入法引擎\u003c/a\u003e 是一个跨平台的输入法算法框架。\u003c/p\u003e\n\u003cp\u003e基于这一框架，Rime 开发者与其他开源社区的参与者在多个平台上创造了不同的输入法前端实现。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e雾凇拼音\u003c/strong\u003e是 Rime 的一份配置仓库，用户需要下载 \u003ca href=\"https://github.com/rime/librime/#frontends\" target=\"_blank\" rel=\"noopener\"\u003e各平台对应的前端\u003c/a\u003e，并将此配置应用到配置目录。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e雾凇拼音\u003c/strong\u003e提供了一套开箱即用的完整配置，包含输入方案（全拼、常见双拼）、长期维护的开源词库及各项扩展功能。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/iDvel/rime-ice/issues/133\" target=\"_blank\" rel=\"noopener\"\u003e常见问题\u003c/a\u003e | \u003ca href=\"https://github.com/iDvel/rime-ice/blob/main/others/CHANGELOG.md\" target=\"_blank\" rel=\"noopener\"\u003e更新日志\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"基本套路\"\u003e基本套路\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e简体 | 全拼 | 双拼\u003c/li\u003e\n\u003cli\u003e主要功能\n\u003cul\u003e\n\u003cli\u003e轻量的英文输入，支持中英混输\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://dvel.me/posts/make-rime-en-better/\" target=\"_blank\" rel=\"noopener\"\u003e优化英文输入体验\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e拆字反查（\u003ckbd\u003euU\u003c/kbd\u003e+拼音），拆字辅码（拼音+\u003ckbd\u003e`\u003c/kbd\u003e+拆字辅码）\u003c/li\u003e\n\u003cli\u003e自整理的 Emoji\u003c/li\u003e\n\u003cli\u003e以词定字（左右中括号：\u003ckbd\u003e[\u003c/kbd\u003e、\u003ckbd\u003e]\u003c/kbd\u003e）\u003c/li\u003e\n\u003cli\u003e长词优先\u003c/li\u003e\n\u003cli\u003eUnicode（\u003ckbd\u003eU\u003c/kbd\u003e+Unicode 码位）\u003c/li\u003e\n\u003cli\u003e数字、人民币大写（\u003ckbd\u003eR\u003c/kbd\u003e+数字）\u003c/li\u003e\n\u003cli\u003e日期、时间、星期（详见方案 \u003ccode\u003e/date_translator\u003c/code\u003e 节点）\u003c/li\u003e\n\u003cli\u003e农历（转写：\u003ckbd\u003eN\u003c/kbd\u003e+八位数字；获取当前农历：全拼\u003ckbd\u003enl\u003c/kbd\u003e，双拼\u003ckbd\u003elunar\u003c/kbd\u003e）\u003c/li\u003e\n\u003cli\u003e简易计算器（\u003ckbd\u003ecC\u003c/kbd\u003e+算式）\u003c/li\u003e\n\u003cli\u003eUUID（\u003ckbd\u003euuid\u003c/kbd\u003e）\u003c/li\u003e\n\u003cli\u003e常见错音错字提示\u003c/li\u003e\n\u003cli\u003e置顶候选项（详见方案 \u003ccode\u003e/pin_cand_filter\u003c/code\u003e 节点）\u003c/li\u003e\n\u003cli\u003e所有标点符号直接上屏\u003c/li\u003e\n\u003cli\u003e特殊符号、字符输入（全拼\u003ckbd\u003ev\u003c/kbd\u003e+首字母缩写；双拼\u003ckbd\u003eV\u003c/kbd\u003e+首字母缩写）\u003c/li\u003e\n\u003cli\u003e拼音纠错（模糊音）\u003c/li\u003e\n\u003cli\u003e更多默认未启用的功能请参考 \u003ccode\u003elua/\u003c/code\u003e 及方案注释\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e简体字表、词库\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/iDvel/The-Table-of-General-Standard-Chinese-Characters\" target=\"_blank\" rel=\"noopener\"\u003e通用规范汉字表\u003c/a\u003e（by 中华人民共和国教育部）8K 常用汉字\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.unicode.org/Public/\" target=\"_blank\" rel=\"noopener\"\u003eUnihan 字库\u003c/a\u003e（by Unicode lnc | \u003ca href=\"https://www.unicode.org/license.txt\" target=\"_blank\" rel=\"noopener\"\u003eUNICODE LICENSE V3\u003c/a\u003e）40K 大字库， \u003cstrong\u003e默认未启用\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E8%AF%8D%E8%A1%A8\" target=\"_blank\" rel=\"noopener\"\u003e现代汉语常用词表\u003c/a\u003e（by 中国国家语言文字工作委员会）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://bbs.pinyin.thunisoft.com/forum.php?mod=viewthread\u0026amp;tid=30049\" target=\"_blank\" rel=\"noopener\"\u003e华宇野风词库\u003c/a\u003e（by 野风）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/rime/rime-essay-simp\" target=\"_blank\" rel=\"noopener\"\u003e简化字八股文\u003c/a\u003e（by rime | \u003ca href=\"https://github.com/rime/rime-essay-simp/blob/master/LICENSE\" target=\"_blank\" rel=\"noopener\"\u003eLGPL\u003c/a\u003e）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/thunlp/THUOCL\" target=\"_blank\" rel=\"noopener\"\u003e清华大学开源词库\u003c/a\u003e（by THUNLP | \u003ca href=\"https://github.com/thunlp/THUOCL/blob/master/LICENSE\" target=\"_blank\" rel=\"noopener\"\u003eMIT\u003c/a\u003e）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://ai.tencent.com/ailab/nlp/en/download.html\" target=\"_blank\" rel=\"noopener\"\u003e腾讯词向量\u003c/a\u003e（@Huandeep \u003ca href=\"https://github.com/iDvel/rime-ice/issues/24\" target=\"_blank\" rel=\"noopener\"\u003e整理\u003c/a\u003e | by Tencent AI Lab | \u003ca href=\"https://creativecommons.org/licenses/by/3.0/\" target=\"_blank\" rel=\"noopener\"\u003eCC BY 3.0\u003c/a\u003e）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e词库修订\n\u003cul\u003e\n\u003cli\u003e校对大量异形词、错别字、错误注音\u003c/li\u003e\n\u003cli\u003e全词库完成注音\u003c/li\u003e\n\u003cli\u003e同义多音字注音\u003c/li\u003e\n\u003cli\u003e参考\n\u003cul\u003e\n\u003cli\u003e《现代汉语词典》\u003c/li\u003e\n\u003cli\u003e《同义词词林》\u003c/li\u003e\n\u003cli\u003e《新华成语大词典》\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jiaodui.org/bbs/\" target=\"_blank\" rel=\"noopener\"\u003e校对标准论坛\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eRime、Squirrel、Weasel 常用配置项的详尽注释\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"方案设计\"\u003e方案设计\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e.\n├── default.yaml   # 一些全局设置\n\n├── rime_ice.schema.yaml  # 全拼方案\n├── double_pinyin*.yaml   # 双拼方案\n├── rime_ice.dict.yaml    # 挂载词库\n├── cn_dicts/             # 词库目录\n\n├── melt_eng.schema.yaml  # 英文方案，作为次翻译器挂载到拼音方案\n├── melt_eng.dict.yaml    # 挂载词库\n├── en_dicts/             # 词库目录\n\n├── radical_pinyin.schema.yaml  # 部件拆字方案，作为反查挂载到拼音方案\n├── radical_pinyin.dict.yaml    # 部件拆字词库\n\n├── custom_phrase.txt    # 自定义短语\n├── symbols_v.yaml       # 全拼 v 模式\n├── symbols_caps_v.yaml  # 双拼 V 模式\n├── opencc/              # 词语映射，Emoji\n├── lua/                 # 各个 Lua 脚本\n\n├── squirrel.yaml  # 鼠须管的前端配置文件\n└── weasel.yaml    # 小狼毫的前端配置文件\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e支持了全拼和部分双拼。\u003c/p\u003e","title":"Rime 配置：雾凇拼音"},{"content":"在 macOS 中利用 Hammerspoon 自动切换输入法。\n因为 Rime 目前的中英切换不是特别好用：\n不能 Shift 全局切换中英：是否有可能将中英文输入状态作全局管理？ #145 Rime 的自动切换仍然会记住上一次的状态：请问如何设置打开某app始终切换到英文模式？ #164 菜单栏不能显示中英状态 Rime 全局状态功能的进展：global input session, state shared by all client apps #294\n我希望的是：无论当前是什么输入法，切换到 iTerm，就是英文，离开 iTerm，回到我原先的输入法。\n类似于 Alfred 目前的功能（高级设置中的 Force Keyboard 设置为 ABC）。\n我在 Typora 写中文，呼出 Alfred，变成英文输入法，用完了回到 Typora，变回中文输入法。\n代码参考于：ibreathebsb/hammerspoon自动切换输入法.lua\n使用方法：放到 ~/.hammerspoon/init.lua 重新部署就可以了。\n可以用 Cmd + Ctrl + . 来查看当前窗口的 name 或 path；\n可以在 Hammerspoon 的控制台输入 hs.keycodes.currentSourceID() 来查看当前输入法的 ID。\n做的修改：\n以 App name 作为参数，看起来舒服点 退出指定的程序后，恢复到原先的输入法 -- 当选中某窗口按下 ctrl+command+. 时会显示应用的路径、名字等信息 hs.hotkey.bind({\u0026#39;ctrl\u0026#39;, \u0026#39;cmd\u0026#39;}, \u0026#34;.\u0026#34;, function() hs.pasteboard.setContents(hs.window.focusedWindow():application():path()) hs.alert.show(\u0026#34;App path: \u0026#34; .. hs.window.focusedWindow():application():path() .. \u0026#34;\\n\u0026#34; .. \u0026#34;App name: \u0026#34; .. hs.window.focusedWindow():application():name() .. \u0026#34;\\n\u0026#34; .. \u0026#34;IM source id: \u0026#34; .. hs.keycodes.currentSourceID(), hs.alert.defaultStyle, hs.screen.mainScreen(), 3) end) -- 这里指定中文和英文输入法的 ID local function Chinese() hs.keycodes.currentSourceID(\u0026#34;im.rime.inputmethod.Squirrel.Rime\u0026#34;) end local function English() hs.keycodes.currentSourceID(\u0026#34;com.apple.keylayout.ABC\u0026#34;) end -- 指定程序 local appInputMethod = { iTerm2 = English, [\u0026#39;EuDic LightPeek\u0026#39;] = English, Bitwarden = English, SnippetsLab = English, [\u0026#39;微信\u0026#39;] = Chinese, } -- activated 时切换到指定的输入法，deactivated 时恢复之前的状态 currentID = \u0026#34;\u0026#34; function applicationWatcher(appName, eventType, appObject) if (eventType == hs.application.watcher.activated) then for app, fn in pairs(appInputMethod) do if app == appName then currentID = hs.keycodes.currentSourceID() fn() end end end if eventType == hs.application.watcher.deactivated then for app, fn in pairs(appInputMethod) do if app == appName then hs.keycodes.currentSourceID(currentID) currentID = hs.keycodes.currentSourceID() end end end end appWatcher = hs.application.watcher.new(applicationWatcher):start() -- 输入法切换提示 -- hs.keycodes.inputSourceChanged(function() -- if hs.keycodes.currentMethod() == nil then -- hs.alert.show(\u0026#34;ABC\u0026#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2) -- else -- hs.alert.show(\u0026#34;拼音\u0026#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2) -- end -- end) 小问题：\n无法识别 Alfred 的窗口，不过 Alfred 自带这个功能，和本配置功能一样。\n本来想弄个提示的，但是每次切换时都会产生意料之外的多次切换，比如「ABC → ABC → ABC」或「ABC → 拼音 → ABC」，不知为何中间发生了多次切换，这导致菜单栏的输入法图标发生了一阵短暂而急促的抖动，不过好在结果都是正确的。\n我看 Alfred 自己的功能也有这个问题，不知道有没有可能是 macOS 的 Bug。\n最后只好注释掉 hs.alert.show 的提示了。\n","permalink":"https://dvel.me/posts/hammerspoon-auto-change-input-method/","summary":"\u003cp\u003e在 macOS 中利用 \u003ca href=\"https://github.com/Hammerspoon/hammerspoon\" target=\"_blank\" rel=\"noopener\"\u003eHammerspoon\u003c/a\u003e 自动切换输入法。\u003c/p\u003e\n\u003cp\u003e因为 Rime 目前的中英切换不是特别好用：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不能 Shift 全局切换中英：\u003ca href=\"https://github.com/rime/squirrel/issues/145\" target=\"_blank\" rel=\"noopener\"\u003e是否有可能将中英文输入状态作全局管理？ #145\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eRime 的自动切换仍然会记住上一次的状态：\u003ca href=\"https://github.com/rime/squirrel/issues/164\" target=\"_blank\" rel=\"noopener\"\u003e请问如何设置打开某app始终切换到英文模式？ #164 \u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e菜单栏不能显示中英状态\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRime 全局状态功能的进展：\u003ca href=\"https://github.com/rime/librime/issues/294\" target=\"_blank\" rel=\"noopener\"\u003eglobal input session, state shared by all client apps #294\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e我希望的是：无论当前是什么输入法，切换到 iTerm，就是英文，离开 iTerm，回到我原先的输入法。\u003c/p\u003e\n\u003cp\u003e类似于 Alfred 目前的功能（高级设置中的 Force Keyboard 设置为 ABC）。\u003c/p\u003e\n\u003cp\u003e我在 Typora 写中文，呼出 Alfred，变成英文输入法，用完了回到 Typora，变回中文输入法。\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e代码参考于：\u003ca href=\"https://gist.github.com/ibreathebsb/65fae9d742c5ebdb409960bceaf934de\" target=\"_blank\" rel=\"noopener\"\u003eibreathebsb/hammerspoon自动切换输入法.lua\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e使用方法：放到 \u003ccode\u003e~/.hammerspoon/init.lua\u003c/code\u003e 重新部署就可以了。\u003c/p\u003e\n\u003cp\u003e可以用 \u003ccode\u003eCmd + Ctrl + .\u003c/code\u003e 来查看当前窗口的 name 或 path；\u003c/p\u003e\n\u003cp\u003e可以在 Hammerspoon 的控制台输入 \u003ccode\u003ehs.keycodes.currentSourceID()\u003c/code\u003e 来查看当前输入法的 ID。\u003c/p\u003e\n\u003cp\u003e做的修改：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e以 App name 作为参数，看起来舒服点\u003c/li\u003e\n\u003cli\u003e退出指定的程序后，恢复到原先的输入法\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-lua\" data-lang=\"lua\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- 当选中某窗口按下 ctrl+command+. 时会显示应用的路径、名字等信息\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ehs.hotkey\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebind\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;ctrl\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;cmd\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kr\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehs.pasteboard\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetContents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehs.window\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efocusedWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003eapplication\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehs.alert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;App path:        \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.window\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efocusedWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003eapplication\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;App name:      \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ehs.window\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efocusedWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003eapplication\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;IM source id:  \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e..\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.alert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edefaultStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.screen\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emainScreen\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- 这里指定中文和英文输入法的 ID\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003elocal\u003c/span\u003e \u003cspan class=\"kr\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eChinese\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;im.rime.inputmethod.Squirrel.Rime\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003elocal\u003c/span\u003e \u003cspan class=\"kr\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eEnglish\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;com.apple.keylayout.ABC\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- 指定程序\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003elocal\u003c/span\u003e \u003cspan class=\"n\"\u003eappInputMethod\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eiTerm2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eEnglish\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;EuDic LightPeek\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eEnglish\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eBitwarden\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eEnglish\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eSnippetsLab\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eEnglish\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;微信\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eChinese\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- activated 时切换到指定的输入法，deactivated 时恢复之前的状态\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ecurrentID\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eapplicationWatcher\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eappName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eeventType\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eappObject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeventType\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.application\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewatcher.activated\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kr\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003efn\u003c/span\u003e \u003cspan class=\"kr\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003epairs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eappInputMethod\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kr\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"kr\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003eapp\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eappName\u003c/span\u003e \u003cspan class=\"kr\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003ecurrentID\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003eeventType\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.application\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewatcher.deactivated\u003c/span\u003e \u003cspan class=\"kr\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003efn\u003c/span\u003e \u003cspan class=\"kr\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003epairs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eappInputMethod\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kr\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"kr\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003eapp\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eappName\u003c/span\u003e \u003cspan class=\"kr\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentID\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003ecurrentID\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.keycodes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSourceID\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eappWatcher\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ehs.application\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewatcher.new\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eapplicationWatcher\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- 输入法切换提示\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- hs.keycodes.inputSourceChanged(function()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e--     if hs.keycodes.currentMethod() == nil then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e--         hs.alert.show(\u0026#34;ABC\u0026#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e--     else\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e--         hs.alert.show(\u0026#34;拼音\u0026#34;, hs.alert.defaultStyle, hs.screen.mainScreen(), 2)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e--     end\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- end)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e小问题：\u003c/p\u003e","title":"Hammerspoon 自动切换输入法"},{"content":"布局偏移 累计布局偏移 Cumulative Layout Shift（CLS）是一项 Web 指标。\n布局偏移如图所示，元素突然变化的高度影响了用户交互体验：\n一般给图片一个高度就可以了，但最好是能自动化，而不是手写。\n看到了这篇博文 累计布局偏移修复方案改进 —— 自动生成图片宽高，不过他是从腾讯云对象存储获取的图片宽高，而我都将图片存储在了 Hugo 配置目录的 static/img/ 文件夹。\n我平时在 Markdown 里都是直接写的 path：\n![](/img/example.webp) 解决本地图片的偏移问题 参考 How to prevent CLS in Hugo，利用 Hugo 的 Render Hooks 功能重新渲染图片相关代码，获取图片的宽高，在 \u0026lt;img\u0026gt; 标签里加上 width 和 height 属性。\n不知道为什么照他的办法，在配置中加入了 mounts 相关属性，仍然不起作用，不太会前端和 Hugo，摸索着改了改。\n创建 layouts/_default/_markup/render-image.html 文件：\n\u0026lt;p\u0026gt; {{ if hasPrefix .Destination \u0026#34;/img\u0026#34; }} {{ $img := os.ReadFile (path.Join \u0026#34;/static\u0026#34; .Destination) | resources.FromString .Destination }} {{ if ne $img.MediaType.SubType \u0026#34;svg\u0026#34; }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Destination | safeURL }}\u0026#34; alt=\u0026#34;{{ .Text }}\u0026#34; width=\u0026#34;{{ $img.Width }}\u0026#34; height=\u0026#34;{{ $img.Height }}\u0026#34; style=\u0026#34;max-width: 100%; height: auto;\u0026#34; /\u0026gt; {{ end }} {{ if or (not $img) (eq $img.MediaType.SubType \u0026#34;svg\u0026#34;) }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Destination | safeURL }}\u0026#34; alt=\u0026#34;{{ .Text }}\u0026#34; /\u0026gt; {{ end }} {{ else }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Destination | safeURL }}\u0026#34; alt=\u0026#34;{{ .Text }}\u0026#34; /\u0026gt; {{ end }} \u0026lt;/p\u0026gt; 在他的基础上手动加上了 /static 地址前缀，不然这个 os.ReadFile 方法一直报错；\n加上了 style=\u0026quot;max-width: 100%; height: auto;\u0026quot;，保持宽度超过父容器的图片的比例；\n套了个 if else，只处理图片地址为 /img 开头的本地图片，并可以显示网络图片，但是网络图片仍然会产生偏移。\n我用的是 Hugo PaperMod 主题，主页的封面图也存在这个问题，得修改 cover.html，看不太懂，我看上面那位博主是修改的这里，确实起作用。\n修改最外层的 {{- else }} 里的内容（Hugo PaperMod 6.0 版本），和之前的一样，就是替换一下 src 和 alt 的属性值：\n{{- else }}{{/* For absolute urls and external links, no img processing here */}} {{- if $addLink }}\u0026lt;a href=\u0026#34;{{ (.Params.cover.image) | absURL }}\u0026#34; target=\u0026#34;_blank\u0026#34; rel=\u0026#34;noopener noreferrer\u0026#34;\u0026gt;{{ end -}} \u0026lt;!-- \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ (.Params.cover.image) | absURL }}\u0026#34; alt=\u0026#34;{{ $alt }}\u0026#34;\u0026gt; --\u0026gt; \u0026lt;!-- 修改，将上面那行改成下面这些： --\u0026gt; {{ if hasPrefix .Params.cover.image \u0026#34;/img\u0026#34; }} {{ $img := os.ReadFile (path.Join \u0026#34;/static\u0026#34; .Params.cover.image) | resources.FromString .Params.cover.image }} {{ if ne $img.MediaType.SubType \u0026#34;svg\u0026#34; }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Params.cover.image | safeURL }}\u0026#34; alt=\u0026#34;{{ $alt }}\u0026#34; width=\u0026#34;{{ $img.Width }}\u0026#34; height=\u0026#34;{{ $img.Height }}\u0026#34; style=\u0026#34;max-width: 100%; height: auto;\u0026#34; /\u0026gt; {{ end }} {{ if or (not $img) (eq $img.MediaType.SubType \u0026#34;svg\u0026#34;) }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Params.cover.image | safeURL }}\u0026#34; alt=\u0026#34;{{ $alt }}\u0026#34; /\u0026gt; {{ end }} {{ else }} \u0026lt;img loading=\u0026#34;lazy\u0026#34; src=\u0026#34;{{ .Params.cover.image | safeURL }}\u0026#34; alt=\u0026#34;{{ $alt }}\u0026#34; /\u0026gt; {{ end }} {{- end }} ","permalink":"https://dvel.me/posts/fix-hugo-cls/","summary":"\u003ch2 id=\"布局偏移\"\u003e布局偏移\u003c/h2\u003e\n\u003cp\u003e累计布局偏移 Cumulative Layout Shift（CLS）是一项 Web 指标。\u003c/p\u003e\n\u003cp\u003e布局偏移如图所示，元素突然变化的高度影响了用户交互体验：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2023-01-08.gif\"\n            alt=\"CLS problem\"\n            width=\"498\"\n            height=\"282\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e一般给图片一个高度就可以了，但最好是能自动化，而不是手写。\u003c/p\u003e\n\u003cp\u003e看到了这篇博文 \u003ca href=\"https://liudon.com/posts/hugo-auto-generate-image-width-and-height/\" target=\"_blank\" rel=\"noopener\"\u003e累计布局偏移修复方案改进 —— 自动生成图片宽高\u003c/a\u003e，不过他是从腾讯云对象存储获取的图片宽高，而我都将图片存储在了 Hugo 配置目录的 \u003ccode\u003estatic/img/\u003c/code\u003e 文件夹。\u003c/p\u003e\n\u003cp\u003e我平时在 Markdown 里都是直接写的 path：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e![](/img/example.webp)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"解决本地图片的偏移问题\"\u003e解决本地图片的偏移问题\u003c/h2\u003e\n\u003cp\u003e参考 \u003ca href=\"https://ianmuchina.com/blog/14-cls-hugo/\" target=\"_blank\" rel=\"noopener\"\u003eHow to prevent CLS in Hugo\u003c/a\u003e，利用 Hugo 的 \u003ca href=\"https://gohugo.io/templates/render-hooks/\" target=\"_blank\" rel=\"noopener\"\u003eRender Hooks\u003c/a\u003e 功能重新渲染图片相关代码，获取图片的宽高，在 \u003ccode\u003e\u0026lt;img\u0026gt;\u003c/code\u003e 标签里加上 \u003ccode\u003ewidth\u003c/code\u003e 和 \u003ccode\u003eheight\u003c/code\u003e 属性。\u003c/p\u003e\n\u003cp\u003e不知道为什么照他的办法，在配置中加入了 \u003ccode\u003emounts\u003c/code\u003e 相关属性，仍然不起作用，不太会前端和 Hugo，摸索着改了改。\u003c/p\u003e\n\u003cp\u003e创建 \u003ccode\u003elayouts/_default/_markup/render-image.html\u003c/code\u003e 文件：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{{ if hasPrefix .Destination \u0026#34;/img\u0026#34; }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    {{ $img := os.ReadFile (path.Join \u0026#34;/static\u0026#34; .Destination) | resources.FromString .Destination }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    {{ if ne $img.MediaType.SubType \u0026#34;svg\u0026#34; }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003eimg\u003c/span\u003e \u003cspan class=\"na\"\u003eloading\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;lazy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"na\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Destination | safeURL }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"na\"\u003ealt\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Text }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"na\"\u003ewidth\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ $img.Width }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"na\"\u003eheight\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ $img.Height }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"na\"\u003estyle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;max-width: 100%; height: auto;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    {{ end }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    {{ if or (not $img) (eq $img.MediaType.SubType \u0026#34;svg\u0026#34;) }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003eimg\u003c/span\u003e \u003cspan class=\"na\"\u003eloading\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;lazy\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Destination | safeURL }}\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003ealt\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Text }}\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    {{ end }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{{ else }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003eimg\u003c/span\u003e \u003cspan class=\"na\"\u003eloading\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;lazy\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Destination | safeURL }}\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003ealt\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Text }}\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{{ end }}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在他的基础上手动加上了 \u003ccode\u003e/static\u003c/code\u003e 地址前缀，不然这个 \u003ccode\u003eos.ReadFile\u003c/code\u003e 方法一直报错；\u003c/p\u003e","title":"修复 Hugo 本地图片的累计布局偏移（CLS）问题"},{"content":"上一篇博文用修改 ~/Library/KeyBindings/DefaultKeyBinding.dict 的方法修改按键绑定，但很多地方依然无法响应新的键位设置，体验比较割裂，于是换到 Karabiner。\n实现方式的区别 DefaultKeyBinding 在 DefaultKeyBinding.dict 中，用 Ctrl+h 来向左移动，macOS 是通过这样实现的：\n\u0026#34;^h\u0026#34; = \u0026#34;moveBackward:\u0026#34;; 如果想继续实现 Shift+left（向左移动时选中文本）这个功能，还得需要调用另一个方法：\n\u0026#34;^H\u0026#34; = \u0026#34;moveBackwardAndModifySelection:\u0026#34;; 苹果原生的方式是直接作用的，比如删除到行首（Ctrl + u）就等于一步操作：直接删除到行首。\nKarabiner Karabiner 要实现删除到行首，它是先通过 Command + Shift + left 来选中光标之前所有的文本，再按下删除键，这样的方式来实现的。\n影响可能是有的，比如终端上无法响应，如果自己定义了一个 Ctrl + u，反而还覆盖了其本身正常的功能，不过可以屏蔽掉不需要的 App。\n另外无须单独实现带选区的那种，因为 Ctrl+h 已经被映射为左箭头了，自己再加上 Shift 就可以了。\nKarabiner 还可以实现更多的功能，比如作者直接写了个全局 Vim 映射，还可以启动 App，设置只限定特定设备、特定 App 等等，功能着实强大，还开源免费。\n简单使用 Simple Modifications，可以简单映射，比如 CapsLock → Control Complex Modifications，可以引用别人已经写好了的规则。 或者打开 ~/.config/karabiner/assets/complex_modifications 增加自己的规则。 Devices，选择要应用到的设备，比如内置键盘。 Profiles，定义多套方案，按需选择。 官方文档：https://karabiner-elements.pqrs.org/docs/\n社区分享：https://ke-complex-modifications.pqrs.org/\n建议查看官方文档熟悉一点小例子，然后下载别人实现类似的功能的 JSON 代码来参考。\n文档最下面有个 External JSON generators，比如用这个 Karabiner Complex Modification 可以自动生成 JSON，不过简单的映射还是直接写 JSON 方便。\n我的键位设置 原始的 Emacs-like 键位：\nCtrl + ... a 移动到行首 e 移动到行尾 b 左 f 右 p 上 n 下 h 往左删除一个 d 往右删除一个 w 往左删除单词 u 往左删除到行首 k 往右删除到行尾 自定义的的键位：\nCtrl + ... a 移动到行首 e 移动到行尾 h 左 l 右 k 上 j 下 o 插入一行 s 往左删除一个 d 往右删除一个 u 往左删除到行首 i 往右删除到行尾 w 往左删除单词 pnbf 仍然可以使用，没有冲突。\na e 不进行任何改动，我还没有发现有不支持的地方。\nw u 的功能虽然和上面一样，但有些地方比如 Typora 就不支持，自己实现一遍确保全局有效。\n代码 (1) CapsLock 短按为 Esc，组合为 Control (2) Ctrl + hjkl 移动光标，排除 JetBrains 上下左右修改为 hjkl，与原来的 pnbf 不冲突，仍然可以使用； 排除 JetBrains，IDEA 自己单独实现普通模式和插入模式不同的行为。 (3) Ctrl + aeosduiw，排除 JetBrains 和终端 ae 不改动，wu 重新实现了一遍； o 和 Vim 的功能类似，在本行的任何位置直接新建一行并切换过去； 增加了 s、i 两个键位在原来的 d、u 旁边，左边的往左删，右边的往右删，很好记忆； 排除 JetBrains 和终端。 (4) Option + [Shift] + hjkl 可以用 Option [+ Shift] + Ctrl + h/l，但按键太多，改成直接按 h/l 也生效； Option + j/k 用于 VSCode 默认快捷键，上下移动此行； Option + Shift + j/k 用于 VSCode 默认快捷键，复制一行； 将代码保存到 ~/.config/karabiner/assets/complex_modifications。\n因为这个 issue#2774 没有解决，还不能全局限定或屏蔽某 App，代码像面条一样，frontmost_application_unless 相关配置每次修改时都需要同时改动多处地方。\n{ \u0026#34;title\u0026#34;: \u0026#34;Dvel\u0026#39;s hjkl\u0026#34;, \u0026#34;rules\u0026#34;: [ { \u0026#34;description\u0026#34;: \u0026#34;(1) CapsLock 短按为 Esc，组合为 Control\u0026#34;, \u0026#34;manipulators\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;caps_lock\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;optional\u0026#34;: [ \u0026#34;any\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;left_control\u0026#34;, \u0026#34;lazy\u0026#34;: true } ], \u0026#34;to_if_alone\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;escape\u0026#34; } ] } ] }, { \u0026#34;description\u0026#34;: \u0026#34;(2) Ctrl + hjkl 移动光标，排除 JetBrains\u0026#34;, \u0026#34;manipulators\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;h\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;any\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;left_arrow\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;j\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;any\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;down_arrow\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;k\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;any\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;up_arrow\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;l\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;any\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;right_arrow\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34; ] } ] } ] }, { \u0026#34;description\u0026#34;: \u0026#34;(3) Ctrl + aeosduiw，排除 JetBrains 和终端\u0026#34;, \u0026#34;manipulators\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;o\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;right_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;left_command\u0026#34; ] }, { \u0026#34;key_code\u0026#34;: \u0026#34;return_or_enter\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;s\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;delete_or_backspace\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;d\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;delete_forward\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;u\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;left_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;left_command\u0026#34;, \u0026#34;left_shift\u0026#34; ] }, { \u0026#34;key_code\u0026#34;: \u0026#34;delete_or_backspace\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;i\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;right_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;left_command\u0026#34;, \u0026#34;left_shift\u0026#34; ] }, { \u0026#34;key_code\u0026#34;: \u0026#34;delete_forward\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;w\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;left_control\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;left_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;option\u0026#34;, \u0026#34;shift\u0026#34; ] }, { \u0026#34;key_code\u0026#34;: \u0026#34;delete_or_backspace\u0026#34; } ], \u0026#34;conditions\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;frontmost_application_unless\u0026#34;, \u0026#34;bundle_identifiers\u0026#34;: [ \u0026#34;jetbrains\u0026#34;, \u0026#34;Terminal\u0026#34;, \u0026#34;iterm\u0026#34;, \u0026#34;Warp\u0026#34; ] } ] } ] }, { \u0026#34;description\u0026#34;: \u0026#34;(4) Option [+ Shift] + hjkl\u0026#34;, \u0026#34;manipulators\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;h\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;option\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;shift\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;left_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;option\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;j\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;option\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;shift\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;down_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;option\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;k\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;option\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;shift\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;up_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;option\u0026#34; ] } ] }, { \u0026#34;type\u0026#34;: \u0026#34;basic\u0026#34;, \u0026#34;from\u0026#34;: { \u0026#34;key_code\u0026#34;: \u0026#34;l\u0026#34;, \u0026#34;modifiers\u0026#34;: { \u0026#34;mandatory\u0026#34;: [ \u0026#34;option\u0026#34; ], \u0026#34;optional\u0026#34;: [ \u0026#34;shift\u0026#34; ] } }, \u0026#34;to\u0026#34;: [ { \u0026#34;key_code\u0026#34;: \u0026#34;right_arrow\u0026#34;, \u0026#34;modifiers\u0026#34;: [ \u0026#34;option\u0026#34; ] } ] } ] } ] } ","permalink":"https://dvel.me/posts/macos-karabiner-key-binding/","summary":"\u003cp\u003e上一篇博文用修改 \u003ccode\u003e~/Library/KeyBindings/DefaultKeyBinding.dict\u003c/code\u003e 的方法修改按键绑定，但很多地方依然无法响应新的键位设置，体验比较割裂，于是换到 \u003ca href=\"https://karabiner-elements.pqrs.org/\" target=\"_blank\" rel=\"noopener\"\u003eKarabiner\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"实现方式的区别\"\u003e实现方式的区别\u003c/h2\u003e\n\u003ch3 id=\"defaultkeybinding\"\u003eDefaultKeyBinding\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003eDefaultKeyBinding.dict\u003c/code\u003e 中，用 Ctrl+h 来向左移动，macOS 是通过这样实现的：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026#34;^h\u0026#34; = \u0026#34;moveBackward:\u0026#34;;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果想继续实现 Shift+left（向左移动时选中文本）这个功能，还得需要调用另一个方法：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026#34;^H\u0026#34; = \u0026#34;moveBackwardAndModifySelection:\u0026#34;;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e苹果原生的方式是直接作用的，比如删除到行首（Ctrl + u）就等于一步操作：直接删除到行首。\u003c/p\u003e\n\u003ch3 id=\"karabiner\"\u003eKarabiner\u003c/h3\u003e\n\u003cp\u003eKarabiner 要实现删除到行首，它是先通过 Command + Shift + left 来选中光标之前所有的文本，再按下删除键，这样的方式来实现的。\u003c/p\u003e\n\u003cp\u003e影响可能是有的，比如终端上无法响应，如果自己定义了一个 Ctrl + u，反而还覆盖了其本身正常的功能，不过可以屏蔽掉不需要的 App。\u003c/p\u003e\n\u003cp\u003e另外无须单独实现带选区的那种，因为 Ctrl+h 已经被映射为左箭头了，自己再加上 Shift 就可以了。\u003c/p\u003e\n\u003cp\u003eKarabiner 还可以实现更多的功能，比如作者直接写了个全局 Vim 映射，还可以启动 App，设置只限定特定设备、特定 App 等等，功能着实强大，还开源免费。\u003c/p\u003e\n\u003ch2 id=\"简单使用\"\u003e简单使用\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eSimple Modifications，可以简单映射，比如 CapsLock → Control\u003c/li\u003e\n\u003cli\u003eComplex Modifications，可以引用别人已经写好了的规则。\n\u003cul\u003e\n\u003cli\u003e或者打开 \u003ccode\u003e~/.config/karabiner/assets/complex_modifications\u003c/code\u003e 增加自己的规则。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eDevices，选择要应用到的设备，比如内置键盘。\u003c/li\u003e\n\u003cli\u003eProfiles，定义多套方案，按需选择。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e官方文档：\u003ca href=\"https://karabiner-elements.pqrs.org/docs/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://karabiner-elements.pqrs.org/docs/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e社区分享：\u003ca href=\"https://ke-complex-modifications.pqrs.org/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://ke-complex-modifications.pqrs.org/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e建议查看官方文档熟悉一点小例子，然后下载别人实现类似的功能的 JSON 代码来参考。\u003c/p\u003e\n\u003cp\u003e文档最下面有个 \u003ca href=\"https://karabiner-elements.pqrs.org/docs/json/external-json-generators/\" target=\"_blank\" rel=\"noopener\"\u003eExternal JSON generators\u003c/a\u003e，比如用这个 \u003ca href=\"https://genesy.github.io/karabiner-complex-rules-generator/\" target=\"_blank\" rel=\"noopener\"\u003eKarabiner Complex Modification\u003c/a\u003e 可以自动生成 JSON，不过简单的映射还是直接写 JSON 方便。\u003c/p\u003e","title":"macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位"},{"content":"macOS 默认在文本编辑中使用 pnbf 来进行上下左右，还有一些其他键位，但我习惯使用 Vim 的 hjkl 来移动。\n我已经在 Vim 中设置好了，但希望这个键位应用到全局。\n通过修改 DefaultKeyBinding.dict 来完成。\n但只能适配一般输入框的快捷键，很多编辑器都还是老样子，无法覆盖。\n比如 Firefox 的输入框、Alfred 的输入框是可以的，但是很多网页编辑框、终端、代码编辑器、Typora 等等还是老键位。\n因为这个方法的不一致性，我已经改用 Karabiner 了。\n通过 Karabiner 修改，则会真·强制·全局。\n不过还是记录一下这种方法。\n下一篇博文：macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位。\nmacOS 默认的 Emacs-like 键位 官方支持文档：Mac 键盘快捷键\nControl-A：移至行或段落的开头。\nControl-E：移至行或段落的末尾。\nControl-F：向前移动一个字符。\nControl-B：向后移动一个字符。\nControl-L：将光标或所选内容置于可见区域中央。\nControl-P：上移一行。\nControl-N：下移一行。\nControl-O：在插入点后新插入一行。\nControl-T：将插入点后面的字符与插入点前面的字符交换。\nControl-H：删除插入点左边的字符。也可以使用 Delete 键。\nControl-D：删除插入点右边的字符。也可以使用 Fn-Delete。\nControl-K：删除插入点与行或段落末尾处之间的文本。\n键位映射文件 默认的键位设置在：\n/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict 可以自己增加一个来覆盖默认的：（默认没有 KeyBindings 目录，可以自己创建）\n~/Library/KeyBindings/DefaultKeyBinding.dict 查看 StandardKeyBinding.dict 的方法： 可以用 Xcode 打开，选择文件类型为 Property List Binary。\n或者可以用 plutil 转换为 XML：\nplutil -convert xml1 -o StandardKeyBinding.xml /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict 转换完成后，可以得到类似下面这样的代码：\n\u0026lt;key\u0026gt;^a\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;moveToBeginningOfParagraph:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^b\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;moveBackward:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^d\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;deleteForward:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^e\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;moveToEndOfParagraph:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^f\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;moveForward:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^h\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;deleteBackward:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^k\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;deleteToEndOfParagraph:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^l\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;centerSelectionInVisibleArea:\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;^n\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;moveDown:\u0026lt;/string\u0026gt; 字符 按键 \u0026quot;@\u0026quot; Command \u0026quot;^\u0026quot; Control \u0026quot;~\u0026quot; Option ^A 这样的代表 Control + Shift + a。\n修改示例 我自己的习惯，除了 hjkl 移动还改了一点别的。\n创建并编辑 ~/Library/KeyBindings/DefaultKeyBinding.dict：\n{ \u0026#34;^a\u0026#34; = \u0026#34;moveToBeginningOfParagraph:\u0026#34;; // 移动到行首 \u0026#34;^e\u0026#34; = \u0026#34;moveToEndOfParagraph:\u0026#34;; // 移动到行尾 \u0026#34;^h\u0026#34; = \u0026#34;moveBackward:\u0026#34;; // 左 \u0026#34;^l\u0026#34; = \u0026#34;moveForward:\u0026#34;; // 右 \u0026#34;^k\u0026#34; = \u0026#34;moveUp:\u0026#34;; // 上 \u0026#34;^j\u0026#34; = \u0026#34;moveDown:\u0026#34;; // 下 \u0026#34;^o\u0026#34; = \u0026#34;insertNewline:\u0026#34;; // 插入一行 \u0026#34;^s\u0026#34; = \u0026#34;deleteBackward:\u0026#34;; // 往左删除一个 \u0026#34;^d\u0026#34; = \u0026#34;deleteForward:\u0026#34;; // 往右删除一个 \u0026#34;^w\u0026#34; = \u0026#34;deleteWordBackward:\u0026#34;; // 往左删除单词 \u0026#34;^u\u0026#34; = \u0026#34;deleteToBeginningOfLine:\u0026#34;; // 往左删除到行首 \u0026#34;^i\u0026#34; = \u0026#34;deleteToEndOfParagraph:\u0026#34;; // 往右删除到行尾 // 有 Shift 的（产生选区） \u0026#34;^A\u0026#34; = \u0026#34;moveToBeginningOfParagraphAndModifySelection:\u0026#34;; \u0026#34;^E\u0026#34; = \u0026#34;moveToEndOfParagraphAndModifySelection:\u0026#34;; \u0026#34;^H\u0026#34; = \u0026#34;moveBackwardAndModifySelection:\u0026#34;; \u0026#34;^L\u0026#34; = \u0026#34;moveForwardAndModifySelection:\u0026#34;; \u0026#34;^K\u0026#34; = \u0026#34;moveUpAndModifySelection:\u0026#34;; \u0026#34;^J\u0026#34; = \u0026#34;moveDownAndModifySelection:\u0026#34;; } 保存后需要重启 App 来查看效果。\n参考： Cocoa Event Handling Guide\nNSStandardKeyBindingResponding\nCustomizing the Cocoa Text System\nWhat are the control keys available when working in a text field?\n","permalink":"https://dvel.me/posts/macos-default-key-binding/","summary":"\u003cp\u003emacOS 默认在文本编辑中使用 pnbf 来进行上下左右，还有一些其他键位，但我习惯使用 Vim 的 hjkl 来移动。\u003c/p\u003e\n\u003cp\u003e我已经在 Vim 中设置好了，但希望这个键位应用到全局。\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e通过修改 \u003ccode\u003eDefaultKeyBinding.dict\u003c/code\u003e 来完成。\u003c/p\u003e\n\u003cp\u003e但只能适配一般输入框的快捷键，很多编辑器都还是老样子，无法覆盖。\u003c/p\u003e\n\u003cp\u003e比如 Firefox 的输入框、Alfred 的输入框是可以的，但是很多网页编辑框、终端、代码编辑器、Typora 等等还是老键位。\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e因为这个方法的不一致性，我已经改用 Karabiner 了。\u003c/p\u003e\n\u003cp\u003e通过 \u003ca href=\"https://github.com/pqrs-org/Karabiner-Elements\" target=\"_blank\" rel=\"noopener\"\u003eKarabiner\u003c/a\u003e 修改，则会真·强制·全局。\u003c/p\u003e\n\u003cp\u003e不过还是记录一下这种方法。\u003c/p\u003e\n\u003cp\u003e下一篇博文：\u003ca href=\"/posts/macos-karabiner-key-binding/\"\u003emacOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"macos-默认的-emacs-like-键位\"\u003emacOS 默认的 Emacs-like 键位\u003c/h2\u003e\n\u003cp\u003e官方支持文档：\u003ca href=\"https://support.apple.com/zh-cn/HT201236\" target=\"_blank\" rel=\"noopener\"\u003eMac 键盘快捷键\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eControl-A：移至行或段落的开头。\u003c/p\u003e\n\u003cp\u003eControl-E：移至行或段落的末尾。\u003c/p\u003e\n\u003cp\u003eControl-F：向前移动一个字符。\u003c/p\u003e\n\u003cp\u003eControl-B：向后移动一个字符。\u003c/p\u003e\n\u003cp\u003eControl-L：将光标或所选内容置于可见区域中央。\u003c/p\u003e\n\u003cp\u003eControl-P：上移一行。\u003c/p\u003e\n\u003cp\u003eControl-N：下移一行。\u003c/p\u003e\n\u003cp\u003eControl-O：在插入点后新插入一行。\u003c/p\u003e\n\u003cp\u003eControl-T：将插入点后面的字符与插入点前面的字符交换。\u003c/p\u003e\n\u003cp\u003eControl-H：删除插入点左边的字符。也可以使用 Delete 键。\u003c/p\u003e\n\u003cp\u003eControl-D：删除插入点右边的字符。也可以使用 Fn-Delete。\u003c/p\u003e\n\u003cp\u003eControl-K：删除插入点与行或段落末尾处之间的文本。\u003c/p\u003e\n\u003ch2 id=\"键位映射文件\"\u003e键位映射文件\u003c/h2\u003e\n\u003cp\u003e默认的键位设置在：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e可以自己增加一个来覆盖默认的：（默认没有 \u003ccode\u003eKeyBindings\u003c/code\u003e 目录，可以自己创建）\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e~/Library/KeyBindings/DefaultKeyBinding.dict\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"查看-standardkeybindingdict-的方法\"\u003e查看 \u003ccode\u003eStandardKeyBinding.dict\u003c/code\u003e 的方法：\u003c/h2\u003e\n\u003cp\u003e可以用 Xcode 打开，选择文件类型为 Property List Binary。\u003c/p\u003e\n\u003cp\u003e或者可以用 \u003ccode\u003eplutil\u003c/code\u003e 转换为 XML：\u003c/p\u003e","title":"macOS 修改 Emacs 键位为 Vim 键位"},{"content":"原来一直在用机场订阅自带的配置，这回快到期了想换换，同时在用多家，顺便学习了一下 Surge 配置。\n一些教程和指引 Surge 官方中文指引：理解 Surge 原理\nSurge 官方手册（英文）\nSurge 官方手册（汉化）\n官方帮助中心\n官方讨论区\nSurge 配置详解\n一些仓库 神机 （进入后点击分支，选择有内容的那个分支）\n懒人配置 Dler\n懒人配置 Hackl0us\n懒人配置 blackmatrix7/ios_rule_script 分流规则、重写写规则及脚本。这个比较全面，一般我找规则就来这里找。\nGeoIP2-CN 只包含 CN 的 GeoIP，适合白名单模式。\n常见的配置方法 黑名单模式：除了我规定的走代理，剩下统统走直连。\n白名单模式：除了我规定的走直连，剩下统统走代理。\n我个人是觉得白名单模式比较好，省事儿，搭配一些需要直连的规则和 GEOIP,CN,DIRECT 很方便。\n配置思路就是：\n把特殊的规则放在最上面。比如 JetBrains 在国内是可以访问的，Steam 下载游戏和 BT 之类的没必要走代理浪费流量。 需要配置开关的，可以单独弄一个类型，比如是测速时是走代理还是直连的 SpeedTest。 接下来是国内的规则集，命中就直连。 还有一个 ChinaMax 规则集，比较大，我没试过。 最后是判断 GeoIP，是 CN 的就直连 规则全部检查完了，FINAL 走代理。 我的配置 [General] loglevel = notify skip-proxy = 127.0.0.1, 192.168.0.0/16, 193.168.0.0/24, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, localhost, *.local exclude-simple-hostnames = true internet-test-url = http://taobao.com/ proxy-test-url = http://cp.cloudflare.com/generate_204 test-timeout = 2 geoip-maxmind-url = https://github.com/Hackl0us/GeoIP2-CN/raw/release/Country.mmdb dns-server = 223.5.5.5, 223.6.6.6, 119.29.29.29, 114.114.114.114, system encrypted-dns-server = https://dns.alidns.com/dns-query, https://doh.pub/dns-query use-local-host-item-for-proxy = true show-error-page-for-reject = true ipv6 = false [Proxy] 🇨🇳Direct = direct ⛔️Reject = reject [Proxy Group] Final = select, 🌎Proxy, 🇨🇳Direct SpeedTest = select, 🇨🇳Direct, 🌎Proxy 🛡Guard = select, ⛔️Reject, 🇨🇳Direct 🌎Proxy = select, 机场1, 机场2 机场1 = url-test, policy-path=订阅地址 机场2 = url-test, policy-path=订阅地址 [Rule] # ################## 置顶一些特殊的 DOMAIN-SUFFIX,jetbrains.com,DIRECT DOMAIN-SUFFIX,bing.com,🌎Proxy # ################## 下载类 PROCESS-NAME,aria2c,DIRECT PROCESS-NAME,fdm,DIRECT PROCESS-NAME,Folx,DIRECT PROCESS-NAME,NetTransport,DIRECT PROCESS-NAME,Transmission,DIRECT PROCESS-NAME,uTorrent,DIRECT PROCESS-NAME,WebTorrent,DIRECT PROCESS-NAME,WebTorrent Helper,DIRECT PROCESS-NAME,qbittorrent,DIRECT PROCESS-NAME,Motrix,DIRECT PROCESS-NAME,Thunder,DIRECT PROCESS-NAME,nwjs,DIRECT // 城通网盘 PROCESS-NAME,qiyimac,DIRECT PROCESS-NAME,QQLive,DIRECT # ################## 规则集 https://github.com/blackmatrix7/ios_rule_script # SystemOTA RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SystemOTA/SystemOTA.list,DIRECT # SteamCN RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SteamCN/SteamCN.list,DIRECT # 测速 RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Speedtest/Speedtest.list,SpeedTest # 去广告 DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising_Domain.list,🛡Guard RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising.list,🛡Guard # 🇨🇳国内 DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China_Domain.list,DIRECT RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China.list,DIRECT RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/ChinaMedia/ChinaMedia.list,DIRECT # 🌎国际 # DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia_Domain.list,🌎Proxy # RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia.list,🌎Proxy # DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy_Domain.list,🌎Proxy # RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy.list,🌎Proxy # DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global_Domain.list,🌎Proxy # RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global.list,🌎Proxy # 系统请求 \u0026amp; 局域网 \u0026amp; GeoIP China RULE-SET,SYSTEM,DIRECT RULE-SET,LAN,DIRECT GEOIP,CN,DIRECT # 最终 FINAL,Final,dns-failed [Host] amplifi.lan = server:syslib router.synology.com = server:syslib sila.razer.com = server:syslib router.asus.com = server:syslib routerlogin.net = server:syslib orbilogin.com = server:syslib www.LinksysSmartWiFi.com = server:syslib LinksysSmartWiFi.com = server:syslib myrouter.local = server:syslib www.miwifi.com = server:syslib miwifi.com = server:syslib mediarouter.home = server:syslib tplogin.cn = server:syslib tplinklogin.net = server:syslib melogin.cn = server:syslib falogin.cn = server:syslib _hotspot_.m2m = server:syslib hotspot.cslwifi.com = server:syslib *.lan = server:syslib [URL Rewrite] # wiki 的 m 移动站点及其他语言的重写 https://zh.(m.)?wikipedia.org/(wiki|zh|zh-sg|zh-tw|zh-hans)/(.*) https://zh.wikipedia.org/zh-cn/$3 302 白名单模式，除了命中的规则外，全部走代理。\n把 Final 改成直连，解开「🌎国际」的那些规则，就是黑名单模式。\n额外再用上 blackmatrix7/ios_rule_script 的一些复写和脚本去广告模块：Advertising 和 AdvertisingScript。\nFirefox 额外需要手动设置，不会自动信任本地的证书。\n分流规则 blackmatrix7/ios_rule_script\n按目录找到需要的规则，比如 rule → Surge → Advertising\n在里面的 README 里写有此规则的大概说明。\n但只给出了一个订阅链接，比如这个去广告的。除了复制 Advertising.list 的链接，还需要手动找到 Advertising_Domain.list 的，然后再把 Advertising_MITM.sgmodule 这个模块装上。\n订阅筛选 因为订阅的节点经常会有变动，又想用自己的配置，还是使用 policy-path 的功能比较好。\n可以用正则表达式过滤或挑选，常用的一些：\n过滤 xxx = url-test, policy-path=订阅地址, policy-regex-filter=^((?!(关键字一|关键字二)).)*$ 只包含 iepl = url-test, policy-path=订阅地址, policy-regex-filter=IEPL 新加坡 = url-test, policy-path=订阅地址, policy-regex-filter=新加坡 包含任意 policy-regex-filter=关键字一|关键字二 同时包含 policy-regex-filter=(?=.*关键字一)(?=.*关键字二).* ","permalink":"https://dvel.me/posts/my-surge-conf/","summary":"\u003cp\u003e原来一直在用机场订阅自带的配置，这回快到期了想换换，同时在用多家，顺便学习了一下 Surge 配置。\u003c/p\u003e\n\u003ch2 id=\"一些教程和指引\"\u003e一些教程和指引\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://manual.nssurge.com/book/understanding-surge/cn/\" target=\"_blank\" rel=\"noopener\"\u003eSurge 官方中文指引：理解 Surge 原理\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://manual.nssurge.com/\" target=\"_blank\" rel=\"noopener\"\u003eSurge 官方手册（英文）\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/FlintyLemming/SurgeHandbook\" target=\"_blank\" rel=\"noopener\"\u003eSurge 官方手册（汉化）\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://nssurge.zendesk.com/\" target=\"_blank\" rel=\"noopener\"\u003e官方帮助中心\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://community.nssurge.com/\" target=\"_blank\" rel=\"noopener\"\u003e官方讨论区\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://zhuangzhuang.io/2018/11/14/surge.html\" target=\"_blank\" rel=\"noopener\"\u003eSurge 配置详解\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"一些仓库\"\u003e一些仓库\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/DivineEngine/Profiles\" target=\"_blank\" rel=\"noopener\"\u003e神机\u003c/a\u003e （进入后点击分支，选择有内容的那个分支）\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://raw.githubusercontent.com/DivineEngine/Profiles/master/Surge/Outbound.conf\" target=\"_blank\" rel=\"noopener\"\u003e懒人配置\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/dler-io/Rules\" target=\"_blank\" rel=\"noopener\"\u003eDler\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Prototype.conf\" target=\"_blank\" rel=\"noopener\"\u003e懒人配置\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Hackl0us/SS-Rule-Snippet\" target=\"_blank\" rel=\"noopener\"\u003eHackl0us\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Hackl0us/SS-Rule-Snippet/wiki/\" target=\"_blank\" rel=\"noopener\"\u003e懒人配置\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/blackmatrix7/ios_rule_script/\" target=\"_blank\" rel=\"noopener\"\u003eblackmatrix7/ios_rule_script\u003c/a\u003e 分流规则、重写写规则及脚本。这个比较全面，一般我找规则就来这里找。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Hackl0us/GeoIP2-CN\" target=\"_blank\" rel=\"noopener\"\u003eGeoIP2-CN\u003c/a\u003e 只包含 CN 的 GeoIP，适合白名单模式。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"常见的配置方法\"\u003e常见的配置方法\u003c/h2\u003e\n\u003cp\u003e黑名单模式：除了我规定的走代理，剩下统统走直连。\u003c/p\u003e\n\u003cp\u003e白名单模式：除了我规定的走直连，剩下统统走代理。\u003c/p\u003e\n\u003cp\u003e我个人是觉得白名单模式比较好，省事儿，搭配一些需要直连的规则和 \u003ccode\u003eGEOIP,CN,DIRECT\u003c/code\u003e 很方便。\u003c/p\u003e\n\u003cp\u003e配置思路就是：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e把特殊的规则放在最上面。比如 JetBrains 在国内是可以访问的，Steam 下载游戏和 BT 之类的没必要走代理浪费流量。\u003c/li\u003e\n\u003cli\u003e需要配置开关的，可以单独弄一个类型，比如是测速时是走代理还是直连的 SpeedTest。\u003c/li\u003e\n\u003cli\u003e接下来是国内的规则集，命中就直连。\n\u003cul\u003e\n\u003cli\u003e还有一个 \u003ca href=\"https://github.com/blackmatrix7/ios_rule_script/blob/master/rule/Surge/ChinaMax/README.md\" target=\"_blank\" rel=\"noopener\"\u003eChinaMax\u003c/a\u003e 规则集，比较大，我没试过。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e最后是判断 GeoIP，是 CN 的就直连\u003c/li\u003e\n\u003cli\u003e规则全部检查完了，\u003ccode\u003eFINAL\u003c/code\u003e 走代理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"我的配置\"\u003e我的配置\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-properties\" data-lang=\"properties\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e[General]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eloglevel\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003enotify\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eskip-proxy\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e127.0.0.1, 192.168.0.0/16, 193.168.0.0/24, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, localhost, *.local\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eexclude-simple-hostnames\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003einternet-test-url\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehttp://taobao.com/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eproxy-test-url\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehttp://cp.cloudflare.com/generate_204\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003etest-timeout\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003egeoip-maxmind-url\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehttps://github.com/Hackl0us/GeoIP2-CN/raw/release/Country.mmdb\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edns-server\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e223.5.5.5, 223.6.6.6, 119.29.29.29, 114.114.114.114, system\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eencrypted-dns-server\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehttps://dns.alidns.com/dns-query, https://doh.pub/dns-query\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003euse-local-host-item-for-proxy\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eshow-error-page-for-reject\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eipv6\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e[Proxy]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e🇨🇳Direct\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003edirect\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e⛔️Reject\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ereject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e[Proxy\u003c/span\u003e \u003cspan class=\"s\"\u003eGroup]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eFinal\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eselect, 🌎Proxy, 🇨🇳Direct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eSpeedTest\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eselect, 🇨🇳Direct, 🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e🛡Guard\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eselect, ⛔️Reject, 🇨🇳Direct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e🌎Proxy\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eselect, 机场1, 机场2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e机场1\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eurl-test, policy-path=订阅地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e机场2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eurl-test, policy-path=订阅地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e[Rule]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ################## 置顶一些特殊的\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eDOMAIN-SUFFIX,jetbrains.com,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eDOMAIN-SUFFIX,bing.com,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ################## 下载类\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,aria2c,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,fdm,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,Folx,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,NetTransport,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,Transmission,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,uTorrent,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,WebTorrent,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ePROCESS-NAME,WebTorrent\u003c/span\u003e \u003cspan class=\"s\"\u003eHelper,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,qbittorrent,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,Motrix,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,Thunder,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ePROCESS-NAME,nwjs,DIRECT\u003c/span\u003e \u003cspan class=\"s\"\u003e// 城通网盘\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,qiyimac,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003ePROCESS-NAME,QQLive,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ################## 规则集 https://github.com/blackmatrix7/ios_rule_script\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# SystemOTA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SystemOTA/SystemOTA.list,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# SteamCN\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/SteamCN/SteamCN.list,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 测速\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Speedtest/Speedtest.list,SpeedTest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 去广告\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eDOMAIN-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising_Domain.list,🛡Guard\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Advertising/Advertising.list,🛡Guard\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 🇨🇳国内\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eDOMAIN-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China_Domain.list,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China.list,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRULE-SET,https\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/ChinaMedia/ChinaMedia.list,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 🌎国际\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia_Domain.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GlobalMedia/GlobalMedia.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy_Domain.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# DOMAIN-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global_Domain.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Global/Global.list,🌎Proxy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 系统请求 \u0026amp; 局域网 \u0026amp; GeoIP China\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eRULE-SET,SYSTEM,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eRULE-SET,LAN,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGEOIP,CN,DIRECT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 最终\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eFINAL,Final,dns-failed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e[Host]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eamplifi.lan\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003erouter.synology.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003esila.razer.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003erouter.asus.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003erouterlogin.net\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eorbilogin.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ewww.LinksysSmartWiFi.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eLinksysSmartWiFi.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003emyrouter.local\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ewww.miwifi.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003emiwifi.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003emediarouter.home\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003etplogin.cn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003etplinklogin.net\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003emelogin.cn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003efalogin.cn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e_hotspot_.m2m\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ehotspot.cslwifi.com\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e*.lan\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003eserver:syslib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e[URL\u003c/span\u003e \u003cspan class=\"s\"\u003eRewrite]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# wiki 的 m 移动站点及其他语言的重写\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ehttps\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"s\"\u003e//zh.(m.)?wikipedia.org/(wiki|zh|zh-sg|zh-tw|zh-hans)/(.*) https://zh.wikipedia.org/zh-cn/$3 302\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e白名单模式，除了命中的规则外，全部走代理。\u003c/p\u003e","title":"Surge 配置"},{"content":"在为自己的 Rime 词库 进行修订时，发现了很多以前不曾了解的汉字规范。\n从修订记录里翻出了一些，算是自己的吐槽吧。。。\n模棱两可 「滴里耷拉、滴里搭拉、滴哩答拉」→「嘀哩嗒啦」，「啰哩啰唆」→「啰里啰唆」，「劈哩叭啦」→「噼里叭啦」，「嘁哩喀喳」→ 「嘁里咔嚓」。。。\n为什么上面这些除了「里」都是口字旁，却不用同样是口字旁的「哩」呢？\n「暗淡」「黯淡」。\n「呆会」「待会」，表「停留」时，《现汉》未作推荐但有一个「待dāi」的一声读音专门用于这个意思，《现规》推荐使用「呆」。\n「标识zhi」「标志」，「标识zhi」一直是「标志」的异形词，但《现汉》6、7 开始有了「标识shi」，《现规》直接推荐使用「标志」。\n「勾拳」「钩拳」，Hook 本就是钩子的意思，我站「钩拳」。\n「抗不住、抗得住」「扛不住、扛得住」。\n「嚎叫」「号叫」「嗥叫」。\n「定亲」是「定」，「订婚」是「订」。\n各种「词」与各种「辞」。\n「贻 X」与「遗 X」。\n「杆」与「竿」。\n「得意洋洋/洋洋得意」「得意扬扬/扬扬得意」。\n「发愤图强」「奋发图强」。\n「鱼钩」「渔竿」「钓鱼竿」。\n「嘁嘁嚓嚓」→「嘁嘁喳喳」，「嘁哩咔喳」→「嘁里咔嚓」，不同的地方用不同的 cha。。。\n「下功夫」「费工夫」。\n「悲催」「悲摧」。\n「备受」「倍受」。\n「比划」「比画」。\n「西瓜子」「西瓜籽」。\n「鄙人」「敝人」。\n「闭塞」「蔽塞」。\n「侧足」「厕足」。\n「闺中密友」的「闺密」与「闺蜜」。\n「激凸」「激突」。\n「叫作」「叫做」。\n「做出」「作出」，以及各种「做 X」和「作 X」。\n「绝不」「决不」。\n「谩骂」「漫骂」。\n「避邪」「辟邪」。\n「泄气」「懈气」。\n「佚/轶/逸」+「名/事」。。。\n「蒸气」「蒸汽 = 水蒸气」。\n「属望」「瞩望」。\n「启航」「起航」。\n「乐呵」「乐呵呵」「乐乐和和」。\n「当啷」与「郎当」。\n「作何」「做何」。\n「订做」「定做」。\n「订制」「定制」。\n「实验」「试验」。\n「畜生」「牲畜」。\n「无名火」「无明火」。\n「去除」「祛除」「驱除」。\n「碾压」「碾轧」\n「阵势」「阵式」\n过于细致的拆分 很多字词没有作为异形词，而是分别赋予了不同的意思，或运用在不同的语境下。\n校对网还看到一个 校对疑难问题分享搜集。\n细致的 cha：「道路分岔」「树木分杈」「头发分叉」「河流分汊」，还有个「裤裆开衩」。😅\n「群山曼延」「杂草蔓延」「洪水漫延」。\n「声音/水势洪大」「规模宏大」。\n「作客」「做客」。\n「用作」「用做」。\n「年青」「年轻」。\n「莫名其妙」「莫明其妙」居然不是异形词，而分别代表不同的意思，有细微的差别。\n「谐调」「协调」，「协调」包含「谐调」，但多一个「使配合得当」的意思。\n「嘀嗒」「滴答」，「嘀嗒」和喇叭钟表等相关，「滴答」和雨滴相关。\n「淤斑」「瘀斑」、「淤血、瘀血」，前者表血液凝滞，接近西医；后者一般用于中医。\n「赢利」「盈利」「营利」。\n各种 meng long，日光不明用「曚昽」，月光不明用「朦胧」，目光和其余的都是「蒙眬」。\n「含意」「含义」，「含义」表字词句具体的意义；「含意」表言语行为事件含有的意思（隐含的深意或言外之意）。\n「片段」「片断」，前者表完整段落，后者表零碎段落。\n「纯朴」「淳朴」，意思基本一致。\n「泄露」「泄漏」，一般来说是「泄露秘密」和「泄漏原油」，但《现汉》里「泄露」下面写了一个「同泄漏」，「泄漏」下面写一个「同泄露」，《现规》甚至还弄了一个「泄漏消息」的例句。\n「蕴含」「蕴涵」，前者是常用的，后者多用于一些学术上的。\n「查/察看」「检查/察」「考查/察」「审查/察」。\n「腆着胸脯」「觍着脸」是不同的 tian。\n「辨证」「辩证」。\n「传授」「传受」。\n「画外音」「话外音」。\n「见谅」「鉴谅」。\n「交代」「交待」。\n「宽洪」「宽宏」。\n「联合」「连合」，「连合」居然不是异形词。\n「弥蒙」「迷蒙」。\n「起程」「启程」，《现汉》几个版本折腾两遍后，又全都收录了。\n「善于」「擅于」。\n「蛊惑」「鼓惑」。\n「受让」「授让」。\n「萦绕」「潆绕」。\n「执掌」「职掌」。\n「受命」「授命」。\n「农田龟jun裂」与「皮肤皲jun裂」。\n「撅屁股」与「噘嘴」。\n「报料」「爆料」。\n「抚养」「扶养」。\n「急须」「急需」「亟须」「亟需」。。。\n「神志」「神智」。\n「肤浅」「浮浅」。\n词典的问题 「嘀里嘟噜」「滴里嘟噜」，《现规》说不宜写作「滴里嘟噜」，《现汉》则都收录了，并且表示的意思不一样。\n「不惟」「不唯」，《现汉》收录的是「不惟」，但怎么想也应该是「唯」，「唯」才有「但、仅、只是」的意思。\n《现汉》推荐「钩心斗角」，《现规》推荐「勾心斗角」。\n「蓬门荜户」「蓬门筚户」《现汉》推荐「荜」，《现规》推荐「荜」，按字义来看，「荜」是植物，「筚」是用植物做的东西，应该用「筚」比较合适。\n《现汉》推荐「比画」，《现规》推荐「比划」。\n「鱼钩」「渔钩」，早期《现汉》《现规》都推荐「渔钩」，后来《现汉》推荐「鱼钩」；虽然《现规》的推荐是「鱼钩→渔钩」，但是它还推荐了「渔汛→鱼汛」，好乱。\n「德行」「德性」，表骂人时，《现汉》推荐「德行」，《现规》推荐「德性」。\n《现汉》推荐「蹚浑水」，《现规》推荐《趟浑水》，《现规》直接将「蹚」作为「趟」的异形词，而《现汉》对「趟（一声）」的解释是「旧同蹚」。\n《现汉》将「高招儿、高着儿」「绝招儿、绝着儿」「妙招儿、妙着儿」按照是否下棋作为区分，但对「昏招儿、昏着儿」却按异形词进行处理。\n《现汉》推荐了「瓷器」与「磁漆」，两个 ci 并不统一。\n「繁琐」「烦琐」，现在《现汉》首选「烦琐」了，感觉「繁琐」用的更多。\n《现汉》推荐「榴梿」，全国科学技术名词审定委员会推荐「榴莲」（目前使用较为广泛的）。\n《现汉》对「旋涡」「漩涡」来回折腾，一会这个是异形词，一会那个是异形词。\n《现汉》前几版及《现规》推荐「称钱」，《现汉》现在推荐「趁钱」。\n《现汉》推荐「轧马路」，《现规》推荐「压马路」。\n有很多字词，全国科学技术名词审定委员会、《现代汉语词典》、《现代汉语规范词典》都不同。\n对于多音字，词典没有给出那些少数的特殊读音的全部用例，比如「棱leng」还有一个 ling 音，《现汉》和《现规》的解释中都只提到「穆棱ling」，其实还有一个「丹棱ling」。这让普通人就更难寻找到正确的读法，尤其是中文搜索本就比较艰难，百度百科也没有一丁点儿可信度。比如一大堆含有多音字「陂bei pi po」的地名，完全无从寻找，难道只能问当地人吗？\n专业术语的用字选择 「桔子」是「橘子」的俗写，但「橘斑幅尺蛾」根本搜不到什么，只能用「桔斑幅尺蛾」，在很多食物中也使用了「桔」。\n很多计算机的书籍、论文仍在用「标识符」，应该用「标志符」，《第一批异形词整理表》就将「标识zhi」替换为了「标志」，但《现汉》同时收录了「标识zhi」和「标识shi」。\n到底是「安纽夜蛾」还是「安钮夜蛾」呢。\n「桑葚」「桑椹」混用的情况极多。\n历史包袱 「做戏」「逢场作戏」的「做/作」。\n「褴褛」「筚路蓝缕」的「褴/蓝」与「褛/缕」。\n「反照」「回光返照」的「反/返」，另外《现汉》推荐的是「反照」，《现规》推荐的是「返照」。\n「屏除、屏弃、屏绝」「摒除、摒弃、摒绝」，「象/像」做了细致的区分，但「屏/摒」没有做。\n「伶仃洋」「零丁洋里叹零丁」。\n「丰都」「酆都鬼城」。\n「二心」「忠贞不贰」。\n「拾遗补阙」「补缺」。\n「飞语」「流言蜚语」。\n「句践」→「勾践」，但是「高句丽」仍然在用「句」。\n词典和民众使用习惯都已经完成转换的词汇，比如「折衷」→「折中」，但是在一些专业领域仍保留原始的写法。例如「折中」与「折衷主义疗法」、「艾鲁岛折衷鹦鹉」，又例如「鲇鱼」与许多冷门生物名词「XX鲶」。\n特殊的读音 极度坑爹的读音。\n「杉shan树」的木头不叫「杉shan木」，叫「杉sha木」 (╯°Д°)╯︵ ┻━┻\n「栅shan极」的字典解释是：一种栅zha状电极 (╯°Д°)╯︵ ┻━┻\n「溃hui脓」的字典解释是：伤口溃kui烂 (╯°Д°)╯︵ ┻━┻\n「雀qiao子」的字典解释是：雀que斑 (╯°Д°)╯︵ ┻━┻\n「疟yao子」的字典解释是：疟nue疾 (╯°Д°)╯︵ ┻━┻\n「桑葚ren儿」 = 「桑葚shen」 (╯°Д°)╯︵ ┻━┻\n「貉he」通称「貉hao子」 (╯°Д°)╯︵ ┻━┻\n「荨qian麻」「荨xun麻疹」，这个应该是误读过多的影响。\n「摩挲」念 mo suo 时表示「用手抚摩」，念 ma sa 时表示「用于轻轻按着并一下一下地移动」😰\n几乎只在某一固定词语或中使用的读音，多数为地名，不太了解这种读音是怎么产生的，为什么在历史发展的过程中没有被其他常用读音给替换掉。\n「豸zhi」的「冠豸zhai山」。\n「蚌beng埠」的「蚌bang」。\n「咀ju」的「尖沙咀zui」。\n「厦sha」的「厦xia门」。\n「柞zuo」的「柞zha水」。\n「栎li」的「栎yue阳」。\n「栟bing」的「栟ben茶」。\n「泌mi」的「泌bi阳」。\n「桧gui」唯独在人名里念「hui」，「秦桧hui」，应该是自秦桧以后没人起带「桧」的名字了。\n「絜xie」唯独在人名里念「jie」，应该是简化时的附带问题。\n「殖zhi」的「骨殖shi」。\n「氏shi」的「阏氏zhi」。\n「峙zhi」的「繁峙shi」。\n「筠yun」的「筠jun连」。\n「泷long」的「泷shuang水」。\n「洞dong」的「洪洞tong」。\n「浚jun」的「浚xun县」。\n「单dan」的「单shan县」和「单chan于」。\n「浰li」的「洴浰lian」。\n「牟mou」的「牟mu平、中牟mu」。\n「番fan」的「番pan禺」。\n「磅bang」的「磅pang礴」。\n「筠yun」的「筠jun连」。\n「绿lv」的「绿lu林、鸭绿lu江」。\n「缩suo」的「缩su砂密」。\n「荠ji」的「荸荠qi」。\n「荥xing阳」「荥ying经」两个地名两个音，且这个字基本上只在这两个地名中使用。\n「莞wan」的「东莞guan」。\n「迫po」的「迫pai击炮」。\n「铅qian」的「铅yan山」。\n「阿e房pang宫」。\n「育yu」的「杭育yo」。\n「瀑pu」的「瀑bao河」。\n「缩suo」的「缩su砂密」，这个读音简直莫名其妙！\n前面的读音不知道是如何产生的，但是下面这些外来的音译也用了一个很生僻的发音，感觉莫名其妙。\n「哪ne吒」。\n佛教用语「南na无mo」。\n「呗bei」的「梵呗fan bai」。\n「犍qian陀罗」，「犍qian/jian」，又生僻又是多音字。\n「戛jia/ga」发 ga 音时，只用于「戛ga纳」，那为什么不用一个本来就发 ga 音的字呢？\n「秘mi/bi」发 bi 音时，只用于「秘bi鲁」，那为什么不用一个本来就发 bi 音的字呢？为什么而且 Peru 的发音类似 po 而不是 bi。\n「派pai/pa」发 pa 音时，只用于「派司」，表示 pass，那为什么不用一个本来就发 pa 音的字呢？\n字典与日常常用的不太一样 「别介jie」（天津话的「别这样啊」），字典正字是「别价jie」。\n「干嘛má」（干啥），字典正字是「干吗má」。\n「瞅你咋地di」，字典正字是「咋的di」。\n音译用字的混乱 「傅立叶」「傅里叶」。\n「菲利浦」「飞利浦」「菲利普」。\n「笛卡儿」「笛卡尔」。\n「喜玛拉雅」「喜马拉雅」。\n「碧昂斯」「碧昂丝」。\n「汉摩拉比、汉漠拉比、汉漠拉比、汉莫拉比」「汉谟拉比」。\n「札」与「扎」的混用。\n「诺亚方舟」「挪亚方舟」。\n「克里Kerry」「克利Klee」。\n「克利斯Klis」「克里斯Chris」「克莉丝Chris」「克丽丝Kris」「科利斯Corlys」。。。\n「峇株巴辖」这种译名更扯淡，「峇厘岛」已经改译为「巴厘岛」了，这译名居然弄了两个不同的 ba。\n「恺撒」与「凯撒」。\n还有一大堆这种混用的音译字：\n爱、艾、埃\n里、力、立、利、丽\n思、丝、司、斯\n亚、娅\n哥、歌、戈、格\n尼、妮\n帝、迪、蒂、狄\n儿、尔\n伯、勃、博\n福、弗、富、辅、芙、佛、\n最经典的还得是下面这条修订记录：\n「玛丽雅、玛丽亚、马丽娅、马里亚、马丽亚、玛利娅、玛丽娅、玛莉亚、玛俐亚」→「马利亚、玛利亚」🤦‍♂️\n古希腊文学翻译家罗念生先生针对后面是否接元音分别使用了「忒」和「特」做不同的译名，如「忒修斯」「忒弥斯」都没有用「特」，而是用一个生僻的多音字「忒te tei tui」（在这里念 tè）。\n这种「规则」的优劣且不说，但「统一用字」是好的，「制定并完全遵守规则」也是好的，而目前则是没有统一，也没有规则。\n有朋友提了个 issue 说《原神》角色「优菈」打不出来，不明白为什么米哈游要使用一个没人用的「菈」而不使用常见的「拉」，谷歌图片搜索「菈」，出来的全是原神的内容。要是都不遵守惯用套路，译名选字还要选《通用规范汉字表》和《现代汉语词典》都没有收录的字，那真是乱套了。\n最让人无语的状况莫过于一个多音字在译名中以多种发音出现，例如：\n伽 jia ga qie\n伽利略 jia li lve 奥米伽 ao mi ga 伽蓝 qie lan 佛 fo fu\n佛罗里达 fo luo li da 雪佛兰 xue fu lan 另外「伽」在外语原文发音为 ga，但在译名中念 jia 的情况有很多。\n（╯\u0026rsquo; - \u0026lsquo;)╯︵ ┻━┻\n（╯\u0026rsquo; - \u0026lsquo;)╯︵ ┻━┻\n(╯°Д°)╯︵ ┻━┻\n简繁或地区的一些不同 表示打招呼或惊诧时的语气词，繁体有个「誒」，但《现汉》《现规》《通用汉字规范表》都没有收录「诶」，大陆用的是「欸」。\n「蕃茄」「番茄」，其他使用汉语的地区基本都是「蕃」，中国大陆是「番」。\n简化字没有简化「噹 → 𪠽」，这个拟声词还是很常用的，字典中是以「当」代替的。\n简化字没有简化「襬 → 䙓」，而是使用了「摆」，「衣摆、裙摆」。\n热门但错误的商用 「比萨」「匹萨」「披萨」，「比萨」是《现汉》推荐的，但 pizza 发音明明是 pi，很多商家都在用后两个，不过比萨行业龙头之一的必胜客使用了「比萨」，现在用「比萨」的也比较多了。但日常发音与广告中都在使用 pi 的音，《现汉》却至今没有更改推荐字或读音。\n「拉钩」是正确用字，但「拉勾网」用的是「勾」。\n表汽车喇叭时用「嘀嘀」，但「滴滴打车」是「滴」。\n告五人的歌曲《披星戴月的想你》应该用「地」。\n希腊字母 sigma 的正确写法是「西格马」，但行业术语「六西格玛」使用了不同的 ma。\n","permalink":"https://dvel.me/posts/chinese-character-confusion/","summary":"\u003cp\u003e在为自己的 \u003ca href=\"https://github.com/iDvel/rime-ice\" target=\"_blank\" rel=\"noopener\"\u003eRime 词库\u003c/a\u003e 进行修订时，发现了很多以前不曾了解的汉字规范。\u003c/p\u003e\n\u003cp\u003e从修订记录里翻出了一些，算是自己的吐槽吧。。。\u003c/p\u003e\n\u003ch2 id=\"模棱两可\"\u003e模棱两可\u003c/h2\u003e\n\u003cp\u003e「滴里耷拉、滴里搭拉、滴哩答拉」→「嘀哩嗒啦」，「啰哩啰唆」→「啰里啰唆」，「劈哩叭啦」→「噼里叭啦」，「嘁哩喀喳」→ 「嘁里咔嚓」。。。\u003c/p\u003e\n\u003cp\u003e为什么上面这些除了「里」都是口字旁，却不用同样是口字旁的「哩」呢？\u003c/p\u003e\n\u003cp\u003e「暗淡」「黯淡」。\u003c/p\u003e\n\u003cp\u003e「呆会」「待会」，表「停留」时，《现汉》未作推荐但有一个「待dāi」的一声读音专门用于这个意思，《现规》推荐使用「呆」。\u003c/p\u003e\n\u003cp\u003e「标识zhi」「标志」，「标识zhi」一直是「标志」的异形词，但《现汉》6、7 开始有了「标识shi」，《现规》直接推荐使用「标志」。\u003c/p\u003e\n\u003cp\u003e「勾拳」「钩拳」，Hook 本就是钩子的意思，我站「钩拳」。\u003c/p\u003e\n\u003cp\u003e「抗不住、抗得住」「扛不住、扛得住」。\u003c/p\u003e\n\u003cp\u003e「嚎叫」「号叫」「嗥叫」。\u003c/p\u003e\n\u003cp\u003e「定亲」是「定」，「订婚」是「订」。\u003c/p\u003e\n\u003cp\u003e各种「词」与各种「辞」。\u003c/p\u003e\n\u003cp\u003e「贻 X」与「遗 X」。\u003c/p\u003e\n\u003cp\u003e「杆」与「竿」。\u003c/p\u003e\n\u003cp\u003e「得意洋洋/洋洋得意」「得意扬扬/扬扬得意」。\u003c/p\u003e\n\u003cp\u003e「发愤图强」「奋发图强」。\u003c/p\u003e\n\u003cp\u003e「鱼钩」「渔竿」「钓鱼竿」。\u003c/p\u003e\n\u003cp\u003e「嘁嘁嚓嚓」→「嘁嘁喳喳」，「嘁哩咔喳」→「嘁里咔嚓」，不同的地方用不同的 cha。。。\u003c/p\u003e\n\u003cp\u003e「下功夫」「费工夫」。\u003c/p\u003e\n\u003cp\u003e「悲催」「悲摧」。\u003c/p\u003e\n\u003cp\u003e「备受」「倍受」。\u003c/p\u003e\n\u003cp\u003e「比划」「比画」。\u003c/p\u003e\n\u003cp\u003e「西瓜子」「西瓜籽」。\u003c/p\u003e\n\u003cp\u003e「鄙人」「敝人」。\u003c/p\u003e\n\u003cp\u003e「闭塞」「蔽塞」。\u003c/p\u003e\n\u003cp\u003e「侧足」「厕足」。\u003c/p\u003e\n\u003cp\u003e「闺中密友」的「闺密」与「闺蜜」。\u003c/p\u003e\n\u003cp\u003e「激凸」「激突」。\u003c/p\u003e\n\u003cp\u003e「叫作」「叫做」。\u003c/p\u003e\n\u003cp\u003e「做出」「作出」，以及各种「做 X」和「作 X」。\u003c/p\u003e\n\u003cp\u003e「绝不」「决不」。\u003c/p\u003e\n\u003cp\u003e「谩骂」「漫骂」。\u003c/p\u003e\n\u003cp\u003e「避邪」「辟邪」。\u003c/p\u003e\n\u003cp\u003e「泄气」「懈气」。\u003c/p\u003e\n\u003cp\u003e「佚/轶/逸」+「名/事」。。。\u003c/p\u003e\n\u003cp\u003e「蒸气」「蒸汽 = 水蒸气」。\u003c/p\u003e\n\u003cp\u003e「属望」「瞩望」。\u003c/p\u003e\n\u003cp\u003e「启航」「起航」。\u003c/p\u003e\n\u003cp\u003e「乐呵」「乐呵呵」「乐乐和和」。\u003c/p\u003e\n\u003cp\u003e「当啷」与「郎当」。\u003c/p\u003e\n\u003cp\u003e「作何」「做何」。\u003c/p\u003e\n\u003cp\u003e「订做」「定做」。\u003c/p\u003e\n\u003cp\u003e「订制」「定制」。\u003c/p\u003e\n\u003cp\u003e「实验」「试验」。\u003c/p\u003e\n\u003cp\u003e「畜生」「牲畜」。\u003c/p\u003e\n\u003cp\u003e「无名火」「无明火」。\u003c/p\u003e\n\u003cp\u003e「去除」「祛除」「驱除」。\u003c/p\u003e\n\u003cp\u003e「碾压」「碾轧」\u003c/p\u003e\n\u003cp\u003e「阵势」「阵式」\u003c/p\u003e\n\u003ch2 id=\"过于细致的拆分\"\u003e过于细致的拆分\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e很多字词没有作为异形词，而是分别赋予了不同的意思，或运用在不同的语境下。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e校对网还看到一个 \u003ca href=\"http://www.jiaodui.com/bbs/read.php?tid=34028\u0026amp;page=10\" target=\"_blank\" rel=\"noopener\"\u003e校对疑难问题分享搜集\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e细致的 cha：「道路分岔」「树木分杈」「头发分叉」「河流分汊」，还有个「裤裆开衩」。😅\u003c/p\u003e\n\u003cp\u003e「群山曼延」「杂草蔓延」「洪水漫延」。\u003c/p\u003e\n\u003cp\u003e「声音/水势洪大」「规模宏大」。\u003c/p\u003e\n\u003cp\u003e「作客」「做客」。\u003c/p\u003e","title":"汉字的混乱"},{"content":"使用插件 Language Reactor，目前只支持 Chrome，Firefox 很久了一直处于 coming soon 状态。\n相比较其他双语插件，它本身就是个学外语的好插件，有方便的快捷键可以穿梭字幕。\n但是双语字幕时有一些问题，就是英文字幕为主会带有很多拟声词之类的，太影响体验了。\n而且是英文在上面，中文在下面，和平常使用的字幕反了。\n将主字幕设置为中文 在 Language Reactor 设置界面的「翻译语言」设置为英文 「显示音译」设置为「无音译」 这样体验就好多啦：\n","permalink":"https://dvel.me/posts/netflix-chinese-english-bilingual-subtitles/","summary":"\u003cp\u003e使用插件 \u003ca href=\"https://www.languagereactor.com/\" target=\"_blank\" rel=\"noopener\"\u003eLanguage Reactor\u003c/a\u003e，目前只支持 Chrome，Firefox 很久了一直处于 coming soon 状态。\u003c/p\u003e\n\u003cp\u003e相比较其他双语插件，它本身就是个学外语的好插件，有方便的快捷键可以穿梭字幕。\u003c/p\u003e\n\u003cp\u003e但是双语字幕时有一些问题，就是英文字幕为主会带有很多拟声词之类的，太影响体验了。\u003c/p\u003e\n\u003cp\u003e而且是英文在上面，中文在下面，和平常使用的字幕反了。\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-06-17-000977.webp\"\n            alt=\"2022-06-17-000977\"\n            width=\"1294\"\n            height=\"539\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003e将主字幕设置为中文\u003c/li\u003e\n\u003cli\u003e在 Language Reactor 设置界面的「翻译语言」设置为英文\u003c/li\u003e\n\u003cli\u003e「显示音译」设置为「无音译」\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-06-17-000979.webp\"\n            alt=\"2022-06-17-000979\"\n            width=\"1702\"\n            height=\"1157\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e这样体验就好多啦：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-06-17-000980.webp\"\n            alt=\"2022-06-17-000980\"\n            width=\"2150\"\n            height=\"326\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e","title":"Netflix 中英双语字幕的好办法"},{"content":"在 Rime 拼音方案中输入英文 用 easy_en 方案挂载到自己的主输入方案（全拼、双拼、五笔等），就可以同时输入英文单词。\n我用的是 melt_eng 方案，差不多，就是拼写规则的大小写方面改了一点。\n引入示例：\nschema: dependencies: - melt_eng engine: translators: - table_translator@melt_eng melt_eng: dictionary: melt_eng 这样挂载了英文方案与英文词库，在拼音方案下就可以输入英文单词。\n因为不是同一个翻译器，英文不会和拼音共同造词，比如输入「applediannao」，并不会自动生成「Apple电脑」，只能给常用的中英混合词汇单独弄一个词典。\n期望的行为： 拼音优先 输入「ma」，前几个候选项应为「吗 嘛 马」，而不是「Mac mad man」。\n重码时拼音优先 如「四则」与 size 冲突时，希望「四则」排在第一位\n短单词优先 输入 mac，第一候选项应为 Mac，而不是「马车」。\n可以降低个别短单词在候选项的位置，在下文。\n未输入完全时的英文长单词： 输入 googl，第一候选项应为 Google，而不是「个哦讴歌来」这种无意义的内容。\n目前的问题： 目前的问题是这样的，输入完整的短单词权重低，输入不完整的长单词时第一候选项总是一个莫名其妙的中文。\n权重设定 经过多次尝试，最后是给拼音和英文都设置一个权重来搞定的：\n# 拼音 translator: dictionary: rime_ice initial_quality: x # 英文 melt_eng: dictionary: melt_eng initial_quality: y 尝试过「不设置:-1」「不设置:0」「不设置:1」「1:0」「2:1」「3:2」「2:1.x」。。。\n最后发现一个神奇的比例是 2 \u0026gt; x \u0026gt; y \u0026gt; 1。\n使用了 1.2:1.1，各方面都比较合适，有点玄学😂。\n重码问题 比如 can you she he size man，既是完整拼音，也是完整单词，在输入过该单词后，会有这样的问题：\n如果不希望这样，可以直接在词库删掉重码的单词，或永远不输入这个单词，或手动 Fn+Shift+Del 降低权重。\n但推荐直接在配置文件中禁用用户词典，因为英文方案不需要造词，自然也就不需要记录到用户词典；没有用户词典，就没有调频。\n禁用用户词典还有一个小优点，例如写了这样的固定顺序：\nmacOS\tmacOS\t999 macOS Sierra\tmacOS\t1 macOS High Sierra\tmacOS\t2 macOS Mojave\tmacOS\t3 macOS Catalina\tmacOS\t4 macOS Big Sur\tmacOS\t5 macOS Monterey\tmacOS\t6 macOS Ventura\tmacOS\t7 macOS Sonoma\tmacOS\t8 那么输入 macos 后，候选项将始终是 macOS 排在第一，接着是最新的系统 macOS Sonoma、macOS Ventura ……\n完整的参考配置 参考配置仓库：iDvel/rime-ice\n# rime_ice.schema.yaml # 自定义短语 custom_phrase: dictionary: \u0026#34;\u0026#34; user_dict: custom_phrase db_class: stabledb enable_completion: false enable_sentence: false initial_quality: 99 # 自定义短语给予高权重 # 拼音翻译器 translator: dictionary: rime_ice initial_quality: 1.2 # 拼音权重 1.2 # 英文翻译器 melt_eng: dictionary: melt_eng enable_sentence: false # 禁止造句 enable_user_dict: false # 禁用用户词典 initial_quality: 1.1 # 英文权重 1.1 comment_format: # 自定义提示码 - xform/.*// # 清空提示码（就是没有那个小尾巴） 解决副作用 日期时间 拼音的 initial_quality 大于 1 后，日期时间的 Lua 脚本 yield 的候选项会跑到最后面，输入 rq/sj 或 date/time 后，候选项处于最末端，date/time 还好，rq/sj 需要翻好多页。解决方法是在 yield() 前设置一个高权重：\n- yield(Candidate(\u0026#34;date\u0026#34;, seg.start, seg._end, os.date(\u0026#34;%Y-%m-%d\u0026#34;), \u0026#34;\u0026#34;)) + local cand = Candidate(\u0026#34;date\u0026#34;, seg.start, seg._end, os.date(\u0026#34;%Y-%m-%d\u0026#34;), \u0026#34;\u0026#34;) + cand.quality = 100 + yield(cand) v 模式 英文的 initial_quality 大于 1 后，方案中的「v 模式」的候选项也跑到最后面了，输入「va」的候选项是「van vain \u0026hellip;」，而不是「ā á ǎ à \u0026hellip;」，可以通过 Lua 脚本解决。\n短单词置顶的问题 一般输入 Mac 时，可能确实想输入这个单词，那么它在第一个候选项就没问题。\n但是输入 rug 这种冷门单词时，用户大概率是想输入「如果」。\n这种词汇并不多，日常使用也碰不到几个，可以手动处理。\n用 Lua 解决了这个问题。（不会 Lua，感谢大佬 @Shewer Lu 指点）\n然后在方案文件 xxx.schema.yaml 中可以配置：\n# 增加一个 lua_filter engine: filters: - lua_filter@*reduce_english_filter reduce_english_filter: idx: 2 # 降低到第 idx 个位置 words: [rug, bus, ship] # 要降低的单词 效果：\n自动大写 由 autocap_filter.lua 实现，感谢 @abcdefg233 @mirtlecn 的几个 PR。\n目前雾凇拼音用的是 20k 小词库，只是方便打一些常见英文，并且纯手动调整了一些大小写。\n一般情况输入小写即可得到普通单词的小写形式，和大多数人名、地名、专有名词的大写形式。\n通过 autocap_filter.lua 可以再将结果进行大写转换，目前的的行为：\n说明 code text 输入小写，得到词库中的原样 latex LaTeX 输入首字母大写，得到首字母大写 Hello Hello 输入前2~n个字母大写，得到全大写 HEllo HELLO 同上，输入全大写，得到全大写 HELLO HELLO 拼写派生 在 melt_eng.schema.yaml 中修改了大量派生规则，感谢 @mirtlecn 的 PR（#326）。\n派生了一些单词的拼写，对于数字同时支持了英文、全拼及双拼的拼音，也支持了部分符号标点：\n单词 支持的输入方式 i18n ishiban | ieighteenn K8s kbas | keights .NET dotnet Windows 11 windowsshiyi | windowseleven Windows 2000 windowsliangqian | windowserqian\nwindowstwoooo | windowserooo D\u0026amp;D dandd 对于中英混输词库，所有词条的编码加上了一个特殊符号前缀，防止英文方案拼写派生时派生出全大写字母：\nT恤\tⓘTxu 示例：输入 txu 得到「T恤」；输入 Txu 得到「T恤」； 输入 TXU 则只会得到 TXU。\n","permalink":"https://dvel.me/posts/make-rime-en-better/","summary":"\u003ch2 id=\"在-rime-拼音方案中输入英文\"\u003e在 Rime 拼音方案中输入英文\u003c/h2\u003e\n\u003cp\u003e用 \u003ca href=\"https://github.com/BlindingDark/rime-easy-en\" target=\"_blank\" rel=\"noopener\"\u003eeasy_en\u003c/a\u003e 方案挂载到自己的主输入方案（全拼、双拼、五笔等），就可以同时输入英文单词。\u003c/p\u003e\n\u003cp\u003e我用的是 \u003ca href=\"https://github.com/tumuyan/rime-melt\" target=\"_blank\" rel=\"noopener\"\u003emelt_eng\u003c/a\u003e 方案，差不多，就是拼写规则的大小写方面改了一点。\u003c/p\u003e\n\u003cp\u003e引入示例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eschema\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003emelt_eng\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003eengine\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etranslators\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003etable_translator@melt_eng\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003emelt_eng\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edictionary\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003emelt_eng\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样挂载了英文方案与英文词库，在拼音方案下就可以输入英文单词。\u003c/p\u003e\n\u003cp\u003e因为不是同一个翻译器，英文不会和拼音共同造词，比如输入「applediannao」，并不会自动生成「Apple电脑」，只能给常用的中英混合词汇单独弄一个词典。\u003c/p\u003e\n\u003ch2 id=\"期望的行为\"\u003e期望的行为：\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e拼音优先\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e输入「ma」，前几个候选项应为「吗 嘛 马」，而不是「Mac mad man」。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e重码时拼音优先\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如「四则」与 size 冲突时，希望「四则」排在第一位\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e短单词优先\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e输入 \u003ccode\u003emac\u003c/code\u003e，第一候选项应为 \u003ccode\u003eMac\u003c/code\u003e，而不是「马车」。\u003c/p\u003e\n\u003cp\u003e可以降低个别短单词在候选项的位置，\u003ca href=\"#%e7%9f%ad%e5%8d%95%e8%af%8d%e7%bd%ae%e9%a1%b6%e7%9a%84%e9%97%ae%e9%a2%98\"\u003e在下文\u003c/a\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e未输入完全时的英文长单词：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e输入 \u003ccode\u003egoogl\u003c/code\u003e，第一候选项应为 \u003ccode\u003eGoogle\u003c/code\u003e，而不是「个哦讴歌来」这种无意义的内容。\u003c/p\u003e\n\u003ch2 id=\"目前的问题\"\u003e目前的问题：\u003c/h2\u003e\n\u003cp\u003e目前的问题是这样的，输入完整的短单词权重低，输入不完整的长单词时第一候选项总是一个莫名其妙的中文。\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-05-11-000708.webp\"\n            alt=\"Rime 默认的问题\"\n            width=\"938\"\n            height=\"384\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003ch2 id=\"权重设定\"\u003e权重设定\u003c/h2\u003e\n\u003cp\u003e经过多次尝试，最后是给拼音和英文都设置一个权重来搞定的：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# 拼音\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003etranslator\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edictionary\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003erime_ice\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003einitial_quality\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"c\"\u003e# 英文\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003emelt_eng\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edictionary\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003emelt_eng\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003einitial_quality\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e尝试过「不设置:-1」「不设置:0」「不设置:1」「1:0」「2:1」「3:2」「2:1.x」。。。\u003c/p\u003e","title":"优化 Rime 英文输入体验"},{"content":"判断一个字符是简体字还是繁体字。\nUnicode 范围 开始以为可以用 Unicode 范围来表示，了解后发现简繁之间在 Unicode 字符集中位置存在交集，并且不是连续的，没办法用这种方法搞定。\n如果真要靠这种办法，需要在茫茫字表中进行超级详细和繁杂的范围指定。\n看到叶典网有一个字符集范围，但没有区分简繁。\nGolang 也有一个 unicode.Han，也没有区分简繁。\nUnihan_Variants.txt 在 http://www.unicode.org/Public/UCD/latest/ucd/ 下载 Unihan.zip，打开里面的 Unihan_Variants.txt。\n比如「战斗」的「斗」（繁体是「鬥」）这两行：\n「斗」是 U+6597，「鬥」是 U+9B25。\nU+6597\tkTraditionalVariant\tU+9B25 U+9B25\tkSimplifiedVariant\tU+6597 kTraditionalVariant 前面是简体专用，后面是繁体专用；\nkSimplifiedVariant 前面是繁体专用，后面是简体专用。\n另外有「后U+540E、後U+5F8C」这种的字，「皇后」是简繁体通用，但表示 behind 时，简体用「后面」，繁体用「後面」。\n所以就有以下这些行：\nU+540E\tkSimplifiedVariant\tU+540E U+5F8C\tkSimplifiedVariant\tU+540E U+540E\tkTraditionalVariant\tU+540E U+5F8C ------- 翻译一下： ------- 后\tkSimplifiedVariant\t后 後\tkSimplifiedVariant\t后 后\tkTraditionalVariant\t后 後 这种一对多、多对一的转换，除了「后/後」，还有「干/幹」等。\n还有 kSpecializedSemanticVariant 这种「井/丼」的。\n还有 kSpoofingVariant 这种欺骗性变体，比如「胶 U+80F6」和「㬵 U+3B35」不是同一个字。\n参照 http://www.unicode.org/reports/tr38/#SCTC 查看各种标记的说明。\n用不到这么精细的，不过这是个好工具啊，以后可能会用到。\n自己弄个简体字表 适合简单的场景。\n比如《通用汉字规范表》，但只有 8105 个字，并没有涵盖全部的简体字，比如「肏」「屄」「〇」「屌」「囧」等等很多字不在其中。\n但《通用汉字规范表》缺失了大量生僻字，比如一大堆以鸟字旁、鱼字旁做为偏旁的汉字，不知道去哪里找到比较全面的字表。\nopencc 如果不是太严谨的需求，临时使用的脚本等，可以考虑这个。\n用 opencc 做简繁转换，然后对比原字符。\n示例，判断字符是否为繁体字：\n把字符进行繁转简。\nc1 和繁转简后一致，则 c1 是简体字；\nc2 和繁转简后不同，则 c2 是繁体字。\nimport opencc converter = opencc.OpenCC(\u0026#39;t2s.json\u0026#39;) # 繁体→简体 c1 = \u0026#39;门\u0026#39; print(c1 == converter.convert(c1)) # \u0026#39;门\u0026#39; == \u0026#39;门\u0026#39; True c2 = \u0026#39;門\u0026#39; print(c2 == converter.convert(c2)) # \u0026#39;門\u0026#39; != \u0026#39;门\u0026#39; False 但并不完全成功：\nimport opencc converter = opencc.OpenCC(\u0026#39;t2s.json\u0026#39;) # 繁体→简体 for _, c in enumerate([\u0026#39;鴞\u0026#39;, \u0026#39;鶲\u0026#39;, \u0026#39;鮡\u0026#39;, \u0026#39;鮠\u0026#39;, \u0026#39;鮣\u0026#39;, \u0026#39;鮋\u0026#39;, \u0026#39;鮈\u0026#39;, \u0026#39;鮊\u0026#39;, \u0026#39;鰺\u0026#39;, \u0026#39;鰏\u0026#39;, \u0026#39;鰟\u0026#39;]): print(c+\u0026#39; -\u0026gt; \u0026#39;+converter.convert(c)) if c == converter.convert(c): print(c) # 鴞 -\u0026gt; 鸮 # 鶲 -\u0026gt; 鹟 # 鮡 -\u0026gt; 鮡 # 鮡 # 鮠 -\u0026gt; 鮠 # 鮠 # 鮣 -\u0026gt; 䲟 # 鮋 -\u0026gt; 鲉 # 鮈 -\u0026gt; 鮈 # 鮈 # 鮊 -\u0026gt; 鲌 # 鰺 -\u0026gt; 鲹 # 鰏 -\u0026gt; 鲾 # 鰟 -\u0026gt; 鳑 试了一些超冷门的字，如「鮡 鮠 鮈」并没有被转换为「𬶐 𬶏 𬶋」。\n另外还有一些问题，如「乾」会被识别为繁体字，转换为「干」。\n","permalink":"https://dvel.me/posts/judge-characters-simplified-or-traditional/","summary":"\u003cp\u003e判断一个字符是简体字还是繁体字。\u003c/p\u003e\n\u003ch2 id=\"unicode-范围\"\u003eUnicode 范围\u003c/h2\u003e\n\u003cp\u003e开始以为可以用 Unicode 范围来表示，了解后发现简繁之间在 Unicode 字符集中位置存在交集，并且不是连续的，没办法用这种方法搞定。\u003c/p\u003e\n\u003cp\u003e如果真要靠这种办法，需要在茫茫字表中进行超级详细和繁杂的范围指定。\u003c/p\u003e\n\u003cp\u003e看到叶典网有一个\u003ca href=\"http://yedict.com/zsts.htm\" target=\"_blank\" rel=\"noopener\"\u003e字符集\u003c/a\u003e范围，但没有区分简繁。\u003c/p\u003e\n\u003cp\u003eGolang 也有一个 \u003ccode\u003eunicode.Han\u003c/code\u003e，也没有区分简繁。\u003c/p\u003e\n\u003ch2 id=\"unihan_variantstxt\"\u003e\u003ccode\u003eUnihan_Variants.txt\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003e在 \u003ca href=\"http://www.unicode.org/Public/UCD/latest/ucd/\" target=\"_blank\" rel=\"noopener\"\u003ehttp://www.unicode.org/Public/UCD/latest/ucd/\u003c/a\u003e 下载 \u003ccode\u003eUnihan.zip\u003c/code\u003e，打开里面的 \u003ccode\u003eUnihan_Variants.txt\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e比如「战斗」的「斗」（繁体是「鬥」）这两行：\u003c/p\u003e\n\u003cp\u003e「斗」是 \u003ccode\u003eU+6597\u003c/code\u003e，「鬥」是 \u003ccode\u003eU+9B25\u003c/code\u003e。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eU+6597\tkTraditionalVariant\tU+9B25\nU+9B25\tkSimplifiedVariant\tU+6597\n\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003ekTraditionalVariant\u003c/code\u003e 前面是简体专用，后面是繁体专用；\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003ekSimplifiedVariant\u003c/code\u003e 前面是繁体专用，后面是简体专用。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另外有「后U+540E、後U+5F8C」这种的字，「皇后」是简繁体通用，但表示 behind 时，简体用「后面」，繁体用「後面」。\u003c/p\u003e\n\u003cp\u003e所以就有以下这些行：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eU+540E\tkSimplifiedVariant\tU+540E\nU+5F8C\tkSimplifiedVariant\tU+540E\nU+540E\tkTraditionalVariant\tU+540E U+5F8C\n------- 翻译一下： -------\n后\tkSimplifiedVariant\t后\n後\tkSimplifiedVariant\t后\n后\tkTraditionalVariant\t后 後\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这种一对多、多对一的转换，除了「后/後」，还有「干/幹」等。\u003c/p\u003e\n\u003cp\u003e还有 \u003ccode\u003ekSpecializedSemanticVariant\u003c/code\u003e 这种「井/丼」的。\u003c/p\u003e\n\u003cp\u003e还有 \u003ccode\u003ekSpoofingVariant\u003c/code\u003e 这种欺骗性变体，比如「胶 U+80F6」和「㬵 U+3B35」不是同一个字。\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e参照 \u003ca href=\"http://www.unicode.org/reports/tr38/#SCTC\" target=\"_blank\" rel=\"noopener\"\u003ehttp://www.unicode.org/reports/tr38/#SCTC\u003c/a\u003e 查看各种标记的说明。\u003c/p\u003e\n\u003cp\u003e用不到这么精细的，不过这是个好工具啊，以后可能会用到。\u003c/p\u003e","title":"判断字符是否为简体字或繁体字"},{"content":"Cloudflare 转入域名时出现错误提示：\n「出现了问题。」\n「请重试转移此域。尚未向您收费。」\n英文版的：\n\u0026ldquo;Something went wrong.\u0026rdquo;\n\u0026ldquo;Please retry transferring this domain. You have not been charged.\u0026rdquo;\n可能是付款问题。\n提示的信息过于宽泛了没有想到是这个问题，也不知道其实 Cloudflare 会在这一步直接收取费用，应该提示「付款方式出现了问题」才对。\n我 Cloudflare 一直都在用免费套餐，没想着会付款，忘记了之前有一次将它从 PayPal 的「自动付款」选项中删除了。\n在 Cloudflare 「控制台 - 管理账户 - 账单」中重新添加或编辑一下，再绑定上 PayPal 就好了。\n提示 \u0026ldquo;Account specified does not exist\u0026rdquo; 时也可能是付款信息问题，比如未添加付款方式。\n","permalink":"https://dvel.me/posts/cloudflare-domain-transfer-something-went-wrong/","summary":"\u003cp\u003eCloudflare 转入域名时出现错误提示：\u003c/p\u003e\n\u003cp\u003e「出现了问题。」\u003c/p\u003e\n\u003cp\u003e「请重试转移此域。尚未向您收费。」\u003c/p\u003e\n\u003cp\u003e英文版的：\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Something went wrong.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Please retry transferring this domain. You have not been charged.\u0026rdquo;\u003c/p\u003e\n\u003cimg src=\"/img/2022-01-22-000157.webp\" alt=\"Cloudflare 出现了问题\" style=\"zoom:50%;\" /\u003e\n\u003cp\u003e可能是付款问题。\u003c/p\u003e\n\u003cp\u003e提示的信息过于宽泛了没有想到是这个问题，也不知道其实 Cloudflare 会在这一步直接收取费用，应该提示「付款方式出现了问题」才对。\u003c/p\u003e\n\u003cp\u003e我 Cloudflare 一直都在用免费套餐，没想着会付款，忘记了之前有一次将它从 PayPal 的「自动付款」选项中删除了。\u003c/p\u003e\n\u003cp\u003e在 Cloudflare 「控制台 - 管理账户 - 账单」中重新添加或编辑一下，再绑定上 PayPal 就好了。\u003c/p\u003e\n\u003cimg src=\"/img/2022-01-22-000158.webp\" alt=\"Cloudflare 域名正在转移\" style=\"zoom:50%;\" /\u003e\n\u003chr\u003e\n\u003cp\u003e提示 \u0026ldquo;Account specified does not exist\u0026rdquo; 时也可能是付款信息问题，比如未添加付款方式。\u003c/p\u003e","title":"Cloudflare 转入域名提示「出现了问题。请重试转移此域。尚未向您收费。」"},{"content":"一些方便的图片压缩方法：\n用 Squoosh 进行格式转换、压缩。\n用 TinyPNG 对 JPEG、PNG、WebP 的压缩。\n用 ImageOptim 进行本地的 JPEG、PNG 压缩。\n用 Google 的 WebP CLI 工具转换为 WebP。（速度最快，推荐）\nSquoosh 可以直接在浏览器打开 https://squoosh.app/ 进行压缩，支持即时预览、格式转换和很多参数调节。\n也可以用 Squoosh 的 CLI 在本地压缩或转换。\nTinyPNG 支持 JPEG、PNG、WebP，压缩效果和 Squoosh 差不太多，但是速度快了很多。\n可以直接在浏览器打开 https://tinypng.com/ 上传 - 压缩 - 下载。\n点击导航栏的 THIRD-PARTY，下面也有一些第三方的客户端，比如这个 kyleduo/TinyPNG4Mac 就不错。\nCompress PNG/JPG https://www.websiteplanet.com/zh-hans/webtools/imagecompressor/\n免费又方便的线上工具，可选三种压缩模式。\nImageOptim https://imageoptim.com/\nImageOptim 也超棒，提供了 Windows/macOS/Linux 客户端，完全本地操作，但是不支持 WebP。\nWebP WebP 是 Google 于 2010 年 09 月 30 日推出的，同时提供了有损压缩与无损压缩（可逆压缩）的图片文件格式。WebP 的设计目标是在减少文件大小的同时，达到和 JPEG、PNG、GIF 格式相同的图片质量。压缩率很高，10M 的 PNG 图片转换成 WebP 只需要大约 1~2M，而肉眼几乎不可分辨的有损压缩能压到 500KB 左右。\n主流浏览器均已支持，2020 年 9 月 Safari 14 也已支持。。。\n可在 https://developers.google.com/speed/webp/ 上下载。\nmacOS 用户可以直接使用 Homebrew 安装，安装完成后即可使用 cwebp、dwebp 、gif2webp 等命令：\ncwebp：转换/压缩到 WebP dwebp： 将 WebP 转回 PNG gif2webp： GIF 转 WebP $ brew install webp ... $ cwebp [options] -q quality input.png -o output.webp $ dwebp in_file [options] [-o out_file] $ gif2webp [options] gif_file -o webp_file 默认的压缩率是 75%：\n$ cwebp input_file.png -o output_file.webp 可以使用 -q 参数调整压缩质量：\n$ cwebp -q 100 input_file.png -o output_file.webp 限定大小（bytes）的有损压缩：\n$ cwebp -size 102400 input_file.png -o output_file.webp WebP 转回 PNG：\n$ dwebp in_file [options] [-o out_file] 还有一个 gif2webp 命令，由于 macOS 目前还不支持预览动态 WebP 图片，本地不能直接看到很费劲（只能看到第一帧），动图依然在用 GIF。\n也可以写个小脚本，放进 Alfred 里，用起来很方便：\nimport sys import os q = 75 for file in sys.argv[1:]: dirname = os.path.dirname(file) filename = os.path.splitext(os.path.basename(file))[0] file = file.replace(\u0026#39; \u0026#39;, \u0026#39;\\\\ \u0026#39;,) filename = filename.replace(\u0026#39; \u0026#39;, \u0026#39;\\\\ \u0026#39;) os.system(f\u0026#39;cwebp -q {q} {file} -o {dirname}/{filename}.webp\u0026#39;) sys.stdout.write(f\u0026#39;\u0026#34;{filename}.webp\u0026#34; done.\\n\u0026#39;) GUI 找到一个 isparta，但是两年多没更新了。\n","permalink":"https://dvel.me/posts/compression-image-squoosh-tinypng-webp/","summary":"\u003cp\u003e一些方便的图片压缩方法：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e用 Squoosh 进行格式转换、压缩。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e用 TinyPNG 对 JPEG、PNG、WebP 的压缩。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e用 ImageOptim 进行本地的 JPEG、PNG 压缩。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e用 Google 的 WebP CLI 工具转换为 WebP。（速度最快，推荐）\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"squoosh\"\u003eSquoosh\u003c/h2\u003e\n\u003cp\u003e可以直接在浏览器打开 \u003ca href=\"https://squoosh.app/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://squoosh.app/\u003c/a\u003e 进行压缩，支持即时预览、格式转换和很多参数调节。\u003c/p\u003e\n\u003cp\u003e也可以用 Squoosh 的 CLI 在本地压缩或转换。\u003c/p\u003e\n\u003ch2 id=\"tinypng\"\u003eTinyPNG\u003c/h2\u003e\n\u003cp\u003e支持 JPEG、PNG、WebP，压缩效果和 Squoosh 差不太多，但是速度快了很多。\u003c/p\u003e\n\u003cp\u003e可以直接在浏览器打开 \u003ca href=\"https://tinypng.com/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://tinypng.com/\u003c/a\u003e 上传 - 压缩 - 下载。\u003c/p\u003e\n\u003cp\u003e点击导航栏的 \u003ca href=\"https://tinypng.com/third-party\" target=\"_blank\" rel=\"noopener\"\u003eTHIRD-PARTY\u003c/a\u003e，下面也有一些第三方的客户端，比如这个 \u003ca href=\"https://github.com/kyleduo\" target=\"_blank\" rel=\"noopener\"\u003ekyleduo\u003c/a\u003e/\u003cstrong\u003e\u003ca href=\"https://github.com/kyleduo/TinyPNG4Mac\" target=\"_blank\" rel=\"noopener\"\u003eTinyPNG4Mac\u003c/a\u003e\u003c/strong\u003e 就不错。\u003c/p\u003e\n\u003ch2 id=\"compress-pngjpg\"\u003eCompress PNG/JPG\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://www.websiteplanet.com/zh-hans/webtools/imagecompressor/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://www.websiteplanet.com/zh-hans/webtools/imagecompressor/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e免费又方便的线上工具，可选三种压缩模式。\u003c/p\u003e\n\u003ch2 id=\"imageoptim\"\u003eImageOptim\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://imageoptim.com/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://imageoptim.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eImageOptim 也超棒，提供了 Windows/macOS/Linux 客户端，完全本地操作，但是不支持 WebP。\u003c/p\u003e\n\u003ch2 id=\"webp\"\u003eWebP\u003c/h2\u003e\n\u003cp\u003eWebP 是 Google 于 2010 年 09 月 30 日推出的，同时提供了有损压缩与无损压缩（可逆压缩）的图片文件格式。WebP 的设计目标是在减少文件大小的同时，达到和 JPEG、PNG、GIF 格式相同的图片质量。压缩率很高，10M 的 PNG 图片转换成 WebP 只需要大约 1~2M，而肉眼几乎不可分辨的有损压缩能压到 500KB 左右。\u003c/p\u003e","title":"图片压缩：Squoosh、TinyPNG、ImageOptim、WebP"},{"content":"偶尔的替换用 VSCode 或 JetBrains IDE 的类似 Cmd + Shift + H 的文件替换就可以了。\n经常或快捷的使用，可以用 grep + sed 命令进行替换。\n搜索试了几个命令，发现有空格的路径会导致一些错误。\n一顿搜索，找到了一个解决办法，参考 Grep word within a file then copy the file：\n--null 告诉 grep 以 NUL 字符分割文件名 -0 告诉 sed 以 NUL 分割输入 最终命令示例，以 bar 替换 foo。\n区分大小写：\n$ grep -lr --null \u0026#39;foo\u0026#39; * | xargs -0 sed -i \u0026#39;\u0026#39; \u0026#39;s/foo/bar/g\u0026#39; 不区分大小写：\n$ grep -ilr --null \u0026#39;foo\u0026#39; * | xargs -0 sed -i \u0026#39;\u0026#39; \u0026#39;s/foo/bar/gI\u0026#39; grep -i, --ignore-case 查找文件时不区分大小写 -l, --files-with-matches 返回文件名 -R, -r, --recursive 递归搜索子目录 sed -i 默认 sed 会打印到标准输出，使用 -i 将直接在文件内编辑替换 s 替换 g 全局替换标志 I 大小写不敏感标志 示例。\n替换需求：\n- ![](/img/xxx.webp) + ![](https://example.com/img/xxx.webp) 可能有需要转义的：\n查找的字符串、替换的内容： ](/img ](https://example.com/img 转义后： ](\\/img https:\\/\\/example.com\\/img 将转义后的内容代入就可以了，完整的：\n$ grep -lr --null \u0026#39;](\\/img\u0026#39; | xargs -0 sed -i \u0026#39;\u0026#39; \u0026#39;s/](\\/img/](https:\\/\\/example.com\\/img/g\u0026#39; ","permalink":"https://dvel.me/posts/macos-replace-contents-multiple-files/","summary":"\u003cp\u003e偶尔的替换用 VSCode 或 JetBrains IDE 的类似 Cmd + Shift + H 的文件替换就可以了。\u003c/p\u003e\n\u003cp\u003e经常或快捷的使用，可以用 \u003ccode\u003egrep\u003c/code\u003e + \u003ccode\u003esed\u003c/code\u003e 命令进行替换。\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e搜索试了几个命令，发现有空格的路径会导致一些错误。\u003c/p\u003e\n\u003cp\u003e一顿搜索，找到了一个解决办法，参考 \u003ca href=\"https://unix.stackexchange.com/questions/297006/grep-word-within-a-file-then-copy-the-file\" target=\"_blank\" rel=\"noopener\"\u003eGrep word within a file then copy the file\u003c/a\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e--null\u003c/code\u003e 告诉 \u003ccode\u003egrep\u003c/code\u003e 以 NUL 字符分割文件名\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-0\u003c/code\u003e 告诉 \u003ccode\u003esed\u003c/code\u003e 以 NUL 分割输入\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003e最终命令示例，以 \u003ccode\u003ebar\u003c/code\u003e 替换 \u003ccode\u003efoo\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e区分大小写：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ grep -lr --null \u003cspan class=\"s1\"\u003e\u0026#39;foo\u0026#39;\u003c/span\u003e * \u003cspan class=\"p\"\u003e|\u003c/span\u003e xargs -0 sed -i \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;s/foo/bar/g\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e不区分大小写：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ grep -ilr --null \u003cspan class=\"s1\"\u003e\u0026#39;foo\u0026#39;\u003c/span\u003e * \u003cspan class=\"p\"\u003e|\u003c/span\u003e xargs -0 sed -i \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;s/foo/bar/gI\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003egrep\u003c/code\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e-i, --ignore-case\u003c/code\u003e 查找文件时不区分大小写\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-l, --files-with-matches\u003c/code\u003e 返回文件名\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-R, -r, --recursive\u003c/code\u003e  递归搜索子目录\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esed\u003c/code\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e-i\u003c/code\u003e 默认 \u003ccode\u003esed\u003c/code\u003e 会打印到标准输出，使用 \u003ccode\u003e-i\u003c/code\u003e 将直接在文件内编辑替换\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003es\u003c/code\u003e 替换\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eg\u003c/code\u003e 全局替换标志\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eI\u003c/code\u003e 大小写不敏感标志\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e示例。\u003c/p\u003e","title":"macOS grep + sed 批量替换多个文件的内容"},{"content":"可能有一些无法更改源码的老项目或智障项目会使用根目录来搞事情，但现在默认已经不支持对根目录进行修改了。\nmacOS 10.15 Catalina 在恢复模式关闭 SIP：\n重启并按住 Cmd + R 进入恢复模式 菜单栏 - 实用工具 - 终端 输入命令 csrutil disable 重启 后接着执行：\n$ sudo mount -uw / 重启后就可以在根目录创建文件夹了。\nmacOS 11 Big Sur 和 macOS 12 Monterey 不需要关闭 SIP。\n直接对根目录进行软链接会报错：\n$ ln -s /Users/dvel/foo/bar /bar ln: /bar: Read-only file system 现在根目录是只读的，但可以使用 synthetic.conf 文件来创建一个虚拟链接连接到数据盘，类似 ln -s 的软链接。\n假设要在根目录创建 abc 文件夹。\n编辑或创建 synthetic.conf：\n$ sudo vim /etc/synthetic.conf 输入内容（中间是 Tab，不是空格，切勿敲错）：\nabc\t/Users/dvel/abc 第一个是要创建的文件夹名，第二个是要链接到的现有路径。\n保存后重启即可。\n示例，创建后的文件夹：\nTab 写成空格的解决办法 如果写成了空格，会导致频繁重启，无法进入系统。\n进入恢复模式，打开终端输入命令来挂载磁盘后删除 /etc/synthetic.conf 文件：：\n$ diskutil apfs unlock \u0026#34;Macintosh HD - Data\u0026#34; $ cd /Volumes/\u0026#34;Macintosh HD - Data\u0026#34; $ cd private/etc $ rm synthetic.conf 重启即可。\n参考 What is the proper way to create a root sym link in Catalina\n","permalink":"https://dvel.me/posts/macos-create-root-dir/","summary":"\u003cp\u003e可能有一些无法更改源码的老项目或智障项目会使用根目录来搞事情，但现在默认已经不支持对根目录进行修改了。\u003c/p\u003e\n\u003ch2 id=\"macos-1015-catalina\"\u003emacOS 10.15 Catalina\u003c/h2\u003e\n\u003cp\u003e在恢复模式关闭 SIP：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e重启并按住 Cmd + R 进入恢复模式\u003c/li\u003e\n\u003cli\u003e菜单栏 - 实用工具 - 终端\u003c/li\u003e\n\u003cli\u003e输入命令 \u003ccode\u003ecsrutil disable\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e重启\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e后接着执行：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo mount -uw /\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e重启后就可以在根目录创建文件夹了。\u003c/p\u003e\n\u003ch2 id=\"macos-11-big-sur-和-macos-12-monterey\"\u003emacOS 11 Big Sur 和 macOS 12 Monterey\u003c/h2\u003e\n\u003cp\u003e不需要关闭 SIP。\u003c/p\u003e\n\u003cp\u003e直接对根目录进行软链接会报错：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ln -s /Users/dvel/foo/bar /bar\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eln: /bar: Read-only file system\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e现在根目录是只读的，但可以使用 \u003ccode\u003esynthetic.conf\u003c/code\u003e 文件来创建一个虚拟链接连接到数据盘，类似 \u003ccode\u003eln -s\u003c/code\u003e 的软链接。\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e假设要在根目录创建 \u003ccode\u003eabc\u003c/code\u003e 文件夹。\u003c/p\u003e\n\u003cp\u003e编辑或创建 \u003ccode\u003esynthetic.conf\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo vim /etc/synthetic.conf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入内容（\u003cstrong\u003e中间是 \u003cmark\u003eTab\u003c/mark\u003e，不是空格，切勿敲错\u003c/strong\u003e）：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eabc\t/Users/dvel/abc\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e第一个是要创建的文件夹名，第二个是要链接到的现有路径。\u003c/p\u003e\n\u003cp\u003e保存后重启即可。\u003c/p\u003e\n\u003cp\u003e示例，创建后的文件夹：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-13A.webp\"\n            alt=\"在根目录创建文件夹\"\n            width=\"1348\"\n            height=\"990\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e","title":"在 macOS 根目录创建文件夹"},{"content":"不想单弄个图床了，Pages 又不花钱。\n我是用在 Cloudflare Pages 或 GitHub Pages 等服务搭建的博客。\nmacOS 环境。\n我想实现的样子：\n本地 Typora 能直接看图 不修改图片路径就 push 提交部署后，在网站也能直接看到图 Markdown 写法 Hugo 的 static/ 目录中的内容会自动放到网站根目录。\n![](/img/xxx.webp) 但是这样只能在网站上显示。\n只要在本机电脑上的根目录创建相同的 /img/ 文件夹就可以了。\n在 macOS 根目录创建文件夹 详细的 在 macOS 根目录创建文件夹，以下是 Big Sur 和 Monterey 的方法。\n编辑 synthetic.conf：\n$ sudo vim /etc/synthetic.conf 输入内容（中间是 Tab，不是空格）：\nimg\t/Users/dvel/Dropbox/hugo/static/img 重启后就能看到根目录有了。\n大功告成了，使用 ![](/img/xxx.webp) 同时支持本地和网站看图。\nTypora 贴图 设置好，直接把图片粘贴到 Typora 就能得到正确路径了。\n删除也方便，不用找到文件夹，在 Typora 里右键删除文件就可以了。\n其他设备 缺点就是没有发布的博文和笔记只能在自己的电脑上看图，如果经常用手机或别的电脑看的话\n只能修改成完整的路径如 ![](https://example.com/img/xxx.webp) 才可以。\n有多设备观看需求的，可以用一个小命令快速快捷地进行替换。\n详细：macOS 批量替换多个文件的内容\n示例：\n$ grep -lr --null \u0026#39;](\\/img\u0026#39; | xargs -0 sed -i \u0026#39;\u0026#39; \u0026#39;s/](\\/img/](https:\\/\\/example.com\\/img/g\u0026#39; ","permalink":"https://dvel.me/posts/blog-image-host-coup/","summary":"\u003cp\u003e不想单弄个图床了，Pages 又不花钱。\u003c/p\u003e\n\u003cp\u003e我是用在 Cloudflare Pages 或 GitHub Pages 等服务搭建的博客。\u003c/p\u003e\n\u003cp\u003emacOS 环境。\u003c/p\u003e\n\u003cp\u003e我想实现的样子：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e本地 Typora 能直接看图\u003c/li\u003e\n\u003cli\u003e不修改图片路径就 push\u003c/li\u003e\n\u003cli\u003e提交部署后，在网站也能直接看到图\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"markdown-写法\"\u003eMarkdown 写法\u003c/h2\u003e\n\u003cp\u003eHugo 的 \u003ccode\u003estatic/\u003c/code\u003e 目录中的内容会自动放到网站根目录。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e![](/img/xxx.webp)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e但是这样只能在网站上显示。\u003c/p\u003e\n\u003cp\u003e只要在本机电脑上的根目录创建相同的 \u003ccode\u003e/img/\u003c/code\u003e 文件夹就可以了。\u003c/p\u003e\n\u003ch2 id=\"在-macos-根目录创建文件夹\"\u003e在 macOS 根目录创建文件夹\u003c/h2\u003e\n\u003cp\u003e详细的 \u003ca href=\"/posts/macos-create-root-dir/\"\u003e在 macOS 根目录创建文件夹\u003c/a\u003e，以下是 Big Sur 和 Monterey 的方法。\u003c/p\u003e\n\u003cp\u003e编辑 \u003ccode\u003esynthetic.conf\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo vim /etc/synthetic.conf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入内容（\u003cstrong\u003e中间是 \u003cmark\u003eTab\u003c/mark\u003e，不是空格\u003c/strong\u003e）：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eimg\t/Users/dvel/Dropbox/hugo/static/img\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e重启后就能看到根目录有了。\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-13A.webp\"\n            alt=\"在根目录创建文件夹\"\n            width=\"1348\"\n            height=\"990\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e大功告成了，使用 \u003ccode\u003e![](/img/xxx.webp)\u003c/code\u003e 同时支持本地和网站看图。\u003c/p\u003e\n\u003ch2 id=\"typora-贴图\"\u003eTypora 贴图\u003c/h2\u003e\n\u003cp\u003e设置好，直接把图片粘贴到 Typora 就能得到正确路径了。\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-12-3379760.webp\"\n            alt=\"Typora 图像设置\"\n            width=\"1664\"\n            height=\"1184\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e删除也方便，不用找到文件夹，在 Typora 里右键删除文件就可以了。\u003c/p\u003e","title":"博客图床小妙招"},{"content":"无意浏览了一下 Hugo 官网的主题目录，发现了一个简约风格的 Paper 主题，非常喜欢，第二天发现了一个 PaperMod，差不多算是增强版。\n之前就没遇到过心爱的主题，一直将就着，好多功能也没有弄，这两天一顿折腾，记录一下折腾经过。\n使用的版本是 hugo-PaperMod-7.0。\n开始 更新 Hugo，新建站点，导入 PaperMod 主题。\n示例配置在另一个分支里，导入 PaperMod 演示站的 config.yml。\n配置时可以参考着 Hugo 官方文档的 Configure Hugo。\n另外要看看 PaperMod Wiki，PaperMod 的示例文件里好多参数都没写，比如这些参数很好用：\nparams: # ... DateFormat: \u0026#34;2006-01-02\u0026#34; # 日期格式化 ShowFullTextinRSS: true # RSS 输出全文 HTML lang 单语言的站点可以直接设置 languageCode 并在 baseof.html 修改为：\n- \u0026lt;html lang=\u0026#34;{{ .Site.Language }}\u0026#34; dir=\u0026#34;{{ .Language.LanguageDirection | default \u0026#34;auto\u0026#34; }}\u0026#34;\u0026gt; + \u0026lt;html lang=\u0026#34;{{ .Site.LanguageCode }}\u0026#34;\u0026gt; PaperMod 的悬浮目录 参考一：Hugo博客目录放在侧边 | PaperMod主题 | Sulv\u0026rsquo;s Blog\n参考二：JannikArndt/jannikarndt.github.io@8b99f6c\n设置文章中链接以新标签的方式打开 参考：在 Hugo Goldmark Markdown 中设置以新标签打开链接\n修复本地图片的累计布局偏移（CLS）问题 参考：修复 Hugo 本地图片的累计布局偏移（CLS）问题\n最后更新时间 看到一篇 Use Lastmod with PaperMod，这个可以和 Git 搭配，不过我希望可以手动输入。\n在 PaperMod 的 post_meta.html 中加上三行：\n{{- if gt .Lastmod .Date -}} {{- $scratch.Add \u0026#34;meta\u0026#34; (slice (printf \u0026#34;\u0026lt;span title=\u0026#39;%s\u0026#39;\u0026gt;(updated: %s)\u0026lt;/span\u0026gt;\u0026#34; (.Lastmod) (.Lastmod | time.Format (default \u0026#34;January 2, 2006\u0026#34; .Site.Params.DateFormat)))) }} {{- end }} 在 Hugo 的 Front Matter 下手动加上 lastmod 属性即可：\ntitle: 折腾 Hugo \u0026amp; PaperMod 主题 slug: hugo-papermod-config author: Dvel date: 2022-01-11T15:15:38+08:00 lastmod: 2023-02-14T00:40:08+08:00 评论功能 试用了一下 Disqus，但是界面好杂乱，就换到了 Waline。\n官方教程非常详尽，就是配置麻烦点，不能像 Disqus 那样一键搞定。\n部署在了 Vercel，按照 Errors Accessing From China 将 CANME 记录修改成官方推荐的地址 cname-china.vercel-dns.com。（现在那个页面访问不了了，不知道是否还推荐这个。）\n适配 Waline 的黑暗模式，在 PaperMod 中以 body.dark 作为选择器：\n/* # Waline 黑暗模式 */ body.dark { /* 下面是官网默认的黑暗模式配色 */ /* 常规颜色 */ --waline-white: #000; --waline-light-grey: #666; --waline-dark-grey: #999; /* 布局颜色 */ --waline-color: #888; --waline-bgcolor: #1e1e1e; --waline-bgcolor-light: #272727; --waline-border-color: #333; --waline-disable-bgcolor: #444; --waline-disable-color: #272727; /* 特殊颜色 */ --waline-bq-color: #272727; /* 其他颜色 */ --waline-info-bgcolor: #272727; --waline-info-color: #666; } 浏览量统计 不蒜子的：\n总访客：\u0026lt;span id=\u0026#34;busuanzi_value_site_uv\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; 总浏览量：\u0026lt;span id=\u0026#34;busuanzi_value_site_pv\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; 页面访问量：\u0026lt;span id=\u0026#34;busuanzi_value_page_pv\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; Waline 的：\n老版的： \u0026lt;span class=\u0026#34;waline-visitor-count\u0026#34; id=\u0026#34;{{ .RelPermalink }}\u0026#34;\u0026gt; 新版的： \u0026lt;span class=\u0026#34;waline-pageview-count\u0026#34; data-path=\u0026#34;{{ .RelPermalink }}\u0026#34; /\u0026gt; 代码高亮 Hugo 自带的配色方案是 Chroma，但 PaperMod 用的 highlight.js，用 Chroma 时样式有点问题。\n设置 disableHLJS: false 选择 highlight.js 作为高亮方案。\n自定义的话，由于 PaperMod 是读取写死了的文件名：\nassets/js/highlight.min.js assets/css/hljs/an-old-hope.min.css 我是直接从 highlight.js 下载最新版的 JS 和 CSS 文件，不修改文件名，直接替换掉里面的内容。\nPaperMod 的代码块背景颜色是写死了的，可以在 blank.css 中设定代码块在博客为亮/暗色主题时不同的背景色。\n:root { --hljs-bg: #282C34; } .dark { --hljs-bg: #272b33; } SRI 今天发现了 SRI（完整性检查）的问题，浏览器提示「Failed to find a valid digest in the \u0026lsquo;integrity\u0026rsquo; attribute for resource \u0026hellip;」，导致语法高亮失效了。\n搜索后发现是因为 Hugo 的「minify」与 Cloudflare 的「Auto Minify」发生了冲突，Cloudflare 在再次压缩后导致文件哈希值改变，校验失败。\n解决办法是要么关闭 SRI，要么取消 Cloudflare 的「Auto Minify」。\nCloudflare 关闭的方法：速度 - 优化 - Auto Minify。\n在 Hugo 中关闭的方法：\nparams: assets: disableFingerprinting: true Markdown 渲染风格 自定义了一些渲染风格，参考了一点 Simple.css 和 GitHub。\n由于习惯了在 Typora 的 H2 标题前打一个空行，标准 Markdown 都不会渲染空行，所以直接增加上边距了。\nPaperMod 的表格有点空洞，用了 GitHub 那种样式的表格：\n样式 体验 PaperMod 有点空洞 GitHub 感觉刚刚好 和一些杂七杂八的调整。\n在 blank.css 中新增自定义样式：\n/* # Markdown 风格 */ /* 标题、正文、行内代码 - 颜色 */ :root { --primary: #212121; /* rgb(30, 30, 30); */ --content: #333333; /* rgb(31, 31, 31); */ --code-bg: rgba(175, 184, 193, 0.2); /* rgb(245, 245, 245); */ } .dark { --code-bg: rgba(175, 184, 193, 0.2); /* rgb(55, 56, 62); */ } /* 链接样式 */ .post-content a { color: #0969da; box-shadow: none; text-decoration: none; } .post-content a:hover { text-decoration: underline; } /* 行内代码 - 左右间距 */ .post-content code { margin: unset; } /* 代码块 - 最大高度 */ /* .post-content pre code { max-height: 40rem; } */ /* 图片居中 */ .post-content img { margin: auto; } /* 行文风格 */ body { font-family: -apple-system, BlinkMacSystemFont, \u0026#34;Avenir Next\u0026#34;, Avenir, \u0026#34;Nimbus Sans L\u0026#34;, Roboto, Noto, \u0026#34;Segoe UI\u0026#34;, Arial, Helvetica, \u0026#34;Helvetica Neue\u0026#34;, sans-serif; font-size: 1rem; line-height: 1.5; margin: 0; } .post-content { padding-top: 1rem; } .post-content blockquote { color: #808080; } .post-content p, .post-content blockquote, .post-content figure, .post-content table { margin: 1.15rem 0; } .post-content hr { margin: 4rem 8rem; } .post-content ul, .post-content ol, .post-content dl, .post-content li { margin: 0.5rem 0; } .post-content h1, .post-content h2, .post-content h3, .post-content h4, .post-content h5, .post-content h6 { margin-bottom: 1.15rem; font-weight: 600; } .post-content h1 { font-size: 2.6rem; margin-top: 4rem; border-bottom: 1px solid #ccc; } .post-content h2 { font-size: 1.8rem; margin-top: 4rem; border-bottom: 1px solid #ccc; } .post-content h3 { font-size: 1.6rem; margin-top: 2rem; } .post-content h4 { font-size: 1.4rem; margin-top: 1.44rem; } .post-content h5 { font-size: 1.2rem; margin-top: 1.15rem; } .post-content h6 { font-size: 1rem; margin-top: 1rem; } /* GitHub 样式的表格 */ .post-content table tr { border: 1px solid #979da3 !important; } .post-content table tr:nth-child(2n), .post-content thead { background-color: var(--code-bg); } .post-content table th { border: 1px solid #979da3 !important; } .post-content table td { border: 1px solid #979da3 !important; } ","permalink":"https://dvel.me/posts/hugo-papermod-config/","summary":"\u003cp\u003e无意浏览了一下 Hugo 官网的主题目录，发现了一个简约风格的 \u003ca href=\"https://github.com/nanxiaobei/hugo-paper\" target=\"_blank\" rel=\"noopener\"\u003ePaper\u003c/a\u003e 主题，非常喜欢，第二天发现了一个 \u003ca href=\"https://github.com/adityatelange/hugo-PaperMod\" target=\"_blank\" rel=\"noopener\"\u003ePaperMod\u003c/a\u003e，差不多算是增强版。\u003c/p\u003e\n\u003cp\u003e之前就没遇到过心爱的主题，一直将就着，好多功能也没有弄，这两天一顿折腾，记录一下折腾经过。\u003c/p\u003e\n\u003cp\u003e使用的版本是 \u003ccode\u003ehugo-PaperMod-7.0\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"开始\"\u003e开始\u003c/h2\u003e\n\u003cp\u003e更新 Hugo，新建站点，导入 PaperMod 主题。\u003c/p\u003e\n\u003cp\u003e示例配置在另一个分支里，导入 PaperMod 演示站的 \u003ccode\u003econfig.yml\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e配置时可以参考着 Hugo 官方文档的 \u003ca href=\"https://gohugo.io/getting-started/configuration/\" target=\"_blank\" rel=\"noopener\"\u003eConfigure Hugo\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e另外要看看 \u003ca href=\"https://github.com/adityatelange/hugo-PaperMod/wiki/Variables\" target=\"_blank\" rel=\"noopener\"\u003ePaperMod Wiki\u003c/a\u003e，PaperMod 的示例文件里好多参数都没写，比如这些参数很好用：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eparams\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\t\u003c/span\u003e\u003cspan class=\"c\"\u003e# ...\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eDateFormat\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2006-01-02\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# 日期格式化\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eShowFullTextinRSS\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e   \u003c/span\u003e\u003cspan class=\"c\"\u003e# RSS 输出全文\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"html-lang\"\u003eHTML lang\u003c/h2\u003e\n\u003cp\u003e单语言的站点可以直接设置 \u003ccode\u003elanguageCode\u003c/code\u003e 并在 \u003ccode\u003ebaseof.html\u003c/code\u003e 修改为：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-diff\" data-lang=\"diff\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e- \u0026lt;html lang=\u0026#34;{{ .Site.Language }}\u0026#34; dir=\u0026#34;{{ .Language.LanguageDirection | default \u0026#34;auto\u0026#34; }}\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e\u003c/span\u003e\u003cspan class=\"gi\"\u003e+ \u0026lt;html lang=\u0026#34;{{ .Site.LanguageCode }}\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"papermod-的悬浮目录\"\u003ePaperMod 的悬浮目录\u003c/h2\u003e\n\u003cp\u003e参考一：\u003ca href=\"https://www.sulvblog.cn/posts/blog/hugo_toc_side/\" target=\"_blank\" rel=\"noopener\"\u003eHugo博客目录放在侧边 | PaperMod主题 | Sulv\u0026rsquo;s Blog\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e参考二：\u003ca href=\"https://github.com/JannikArndt/jannikarndt.github.io/commit/8b99f6cbc61c6b4f0238c592d5315cefe07c0599\" target=\"_blank\" rel=\"noopener\"\u003eJannikArndt/jannikarndt.github.io@\u003ccode\u003e8b99f6c\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e","title":"折腾 Hugo \u0026 PaperMod 主题"},{"content":"在 Cloudflare 的「网站 - 规则 - 页面规则」中可以设置 URL 转发，免费默认可以使用 3 个规则，可以进行简单的通配符转换，如果这个能满足需求那最好了。\n如下：将带 www 的网址 301 重定向到不带 www 的。\n匹配 URL 转发 URL 重定向 www.dvel.me/* https://dvel.me/$1 301 但是很多时候需要更复杂的 URL 转发，比如个人博客瞎折腾，网站的后缀甚至域名来回改，无法仅仅通过通配符做到全部的 301 重定向，这时候还得用 Workers。\nUpdate：批量重定向 今天打开 Cloudflare 一看，出了个「批量重定向 Beta」。。。\n但是免费版限制了 5 个列表，每个列表 20 个，如果量小的话建议用用这个，量大的用 Workers。\n创建一个 Worker 创建后选择「资源 - 快速编辑」，默认代码：\n// 事件监听 fetch addEventListener(\u0026#34;fetch\u0026#34;, event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) // 返回一个只包含\u0026#34;Hello world\u0026#34;的响应 async function handleRequest(request) { return new Response(\u0026#34;Hello world\u0026#34;) } 点击「发送」即可测试：\n301 一个 URL 试试 将上面代码改为：\naddEventListener(\u0026#34;fetch\u0026#34;, event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { return Response.redirect(\u0026#34;https://www.google.com\u0026#34;, 301) } 再点击「发送」进行测试：\n再在「触发器 - 路由 - 添加路由」中添加一个 URL 进行测试 dvel.me/test：\n然后在浏览器中进行访问此网址，发现这个 URL 已经成功 301 到 Google 了。\n大致的做法就是这样，批量重定向只需要将路由改为 dvel.me/*，再将需要跳转的新老 URL 在代码中处理即可。\n官方示例 在上图点击右上角的「示例」，可以找到两个 Redirect 的示例。\n第一个示例将所有的请求重定向到一个 URL：\n// Redirect all requests to one URL const destinationURL = \u0026#34;https://example.com\u0026#34; const statusCode = 301 async function handleRequest(request) { return Response.redirect(destinationURL, statusCode) } addEventListener(\u0026#34;fetch\u0026#34;, async event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) 第二个示例是仅域名互换，保留后面的 path。即 foo.com/a?b=c 转 bar.com/a?b=c：\n// Redirect requests from one domain to another const base = \u0026#34;https://example.com\u0026#34; const statusCode = 301 async function handleRequest(request) { const url = new URL(request.url) const { pathname, search } = url const destinationURL = base + pathname + search return Response.redirect(destinationURL, statusCode) } addEventListener(\u0026#34;fetch\u0026#34;, async event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) 这两个完全没必要，因为用「页面规则」的「URL 转发」就可以完成了，除非你 3 个免费的规则都用完了。\n手写更通用的转换 一个简单的示例：如果访问的地址和 old_url 撞上了，则返回 new_url。\naddEventListener(\u0026#34;fetch\u0026#34;, event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { let old_url = \u0026#34;https://dvel.xyz/posts/1234/\u0026#34; let new_url = \u0026#34;https://dvel.me/posts/ba-la-ba-la/\u0026#34; if (request.url === old_url) { return Response.redirect(new_url, 301) } return fetch(request) } 完整版（同一个域名下跳转） 效果：只重定向当前域名下指定的路径。以后要是修改路径了就在这更新一下。\n旧地址 新地址 dvel.me/posts/1234/ dvel.me/posts/ba-la-ba-la/ 添加触发器的路由：dvel.me/*。\naddEventListener(\u0026#34;fetch\u0026#34;, event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const arr = [ \u0026#34;https://dvel.me/posts/1234/ https://dvel.me/posts/ba-la-ba-la/\u0026#34;, // ... ] let old_url, new_url for (const u2 of arr) { [old_url, new_url] = u2.split(\u0026#39; \u0026#39;) if (request.url === old_url) { return Response.redirect(new_url, 301) } } return fetch(request) } Cloudflare Pages 的重定向 如果在用 Cloudflare Pages 的话，用 Pages 的重定向更简单。\n在构件目录创建 _redirects 文件（也就是 Hugo 的 static 目录），参考 Redirects 文档创建规则，限制是 100 个。\n完整版（域名 A 跳转域名 B） 效果：默认只转换域名，并保留后面的 path 和 search；后缀和域名都变了的，需要一个一个写进数组。\n旧地址 新地址 dvel.xyz/posts/1234/ dvel.me/posts/ba-la-ba-la/ 添加触发器的路由：dvel.xyz/*。\naddEventListener(\u0026#34;fetch\u0026#34;, event =\u0026gt; { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const arr = [ \u0026#34;https://dvel.xyz/posts/1234/ https://dvel.me/posts/ba-la-ba-la/\u0026#34;, // ... ] let old_url, new_url for (const u2 of arr) { [old_url, new_url] = u2.split(\u0026#39; \u0026#39;) if (request.url === old_url) { return Response.redirect(new_url, 301) } } const base = \u0026#34;https://dvel.me\u0026#34; const url = new URL(request.url) const { pathname, search } = url const destinationURL = base + pathname + search return Response.redirect(destinationURL, 301) } ","permalink":"https://dvel.me/posts/cloudflare-workers-redirect/","summary":"\u003cp\u003e在 Cloudflare 的「网站 - 规则 - 页面规则」中可以设置 URL 转发，免费默认可以使用 3 个规则，可以进行简单的通配符转换，如果这个能满足需求那最好了。\u003c/p\u003e\n\u003cp\u003e如下：将带 www 的网址 301 重定向到不带 www 的。\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e匹配 URL\u003c/th\u003e\n          \u003cth\u003e转发 URL\u003c/th\u003e\n          \u003cth\u003e重定向\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ewww.dvel.me/*\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ehttps://dvel.me/$1\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e301\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e但是很多时候需要更复杂的 URL 转发，比如个人博客瞎折腾，网站的后缀甚至域名来回改，无法仅仅通过通配符做到全部的 301 重定向，这时候还得用 Workers。\u003c/p\u003e\n\u003ch2 id=\"update批量重定向\"\u003eUpdate：批量重定向\u003c/h2\u003e\n\u003cp\u003e今天打开 Cloudflare 一看，出了个「批量重定向 Beta」。。。\u003c/p\u003e\n\u003cp\u003e但是免费版限制了 5 个列表，每个列表 20 个，如果量小的话建议用用这个，量大的用 Workers。\u003c/p\u003e\n\u003ch2 id=\"创建一个-worker\"\u003e创建一个 Worker\u003c/h2\u003e\n\u003cp\u003e创建后选择「资源 - 快速编辑」，默认代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 事件监听 fetch\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddEventListener\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;fetch\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erespondWith\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehandleRequest\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 返回一个只包含\u0026#34;Hello world\u0026#34;的响应\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nx\"\u003ehandleRequest\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eResponse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Hello world\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e点击「发送」即可测试：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-09A.webp\"\n            alt=\"Cloudflare Workers\"\n            width=\"2250\"\n            height=\"580\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003ch2 id=\"301-一个-url-试试\"\u003e301 一个 URL 试试\u003c/h2\u003e\n\u003cp\u003e将上面代码改为：\u003c/p\u003e","title":"利用 Cloudflare Workers 进行批量 301 重定向"},{"content":"Cloudflare Pages 的免费政策 以下摘自 Cloudflare Pages 首页 和 Cloudflare Pages 文档 - Limits（里面有更详细的）。\n同一时间只能部署一个 Pages 每月 500 次提交 无限站点 无限请求 无限带宽 每个项目最多 10 个自定义域名 每个站点最多 20000 个文件 单个文件最大 25 MB 总之对于个人博客来说是绰绰有余了。\n实测每次部署大概是 2~3 分钟，今天发现出了 Fast builds 功能，可以在设置中启用，在 2022-04-01 后将自动启用，新版的快速部署大约就 10 秒钟。\n特点 相比 GitHub Pages，可以直接从 GitHub 的私有仓库部署，GitHub Pages 却不能。\n支持 Hugo、Hexo 等自动部署。\nCDN 大陆效果一般，直连大约至少 几百毫秒 一千毫秒。\n可以配合 Workers 等其他免费或付费功能完成多种类的 URL 转发。\n另外 Cloudflare 的 DNS 支持裸域的 CNAME 与 MX 共存，自动搞定，这太方便了，之前 CloudXNS 至少还要自己手动操作一个其自定义的 LINK 类型及另一个域名作为跳板，Cloudflare 完全自动处理。我自己的的邮件用的也是裸域，在 Google Workspace，完全没有影响，收发件正常。\n部署 十分简单，现在也都有简体中文了，就照着提示给予 GitHub 仓库权限就可以了。\n默认就自动响应 Git 的新提交来部署。\n一种是直接将生成好的静态文件作为部署内容，一种是 Cloudflare 自动用 Hugo 等支持的系统做自动化部署。\n没试过第二种，我选择前者，主要是保证和本地的一致性。\n重定向 将带 www 的或不带 www 的也设定为自定义域名。\n部署妥善后，可在「页面规则」中设定 www 与不带 www 的互相跳转，例如：\n匹配 URL 转发 URL 重定向 www.dvel.me/* https://dvel.me/$1 301 会自动将带 www 的地址 301 重定向到裸域，免费用户可以使用最多三个规则。\n其他重定向可参考：利用 Cloudflare Workers 进行批量 301 重定向\nSRI 今天发现了 SRI（完整性检查）的问题，浏览器提示「Failed to find a valid digest in the \u0026lsquo;integrity\u0026rsquo; attribute for resource \u0026hellip;」，导致语法高亮失效了。\n搜索后发现是因为 Hugo 的「minify」与 Cloudflare 的「Auto Minify」发生了冲突，Cloudflare 在再次压缩后导致文件哈希值改变，校验失败。\n解决办法是要么关闭 SRI，要么取消 Cloudflare 的「Auto Minify」。\nCloudflare 关闭的方法：速度 - 优化 - Auto Minify。\n在 Hugo 中关闭的方法：\nparams: assets: disableFingerprinting: true /cdn-cgi/ 因为 /cdn-cgi/ endpoint 这个问题，建议在 robots.txt 禁止抓取这个目录：\nDisallow: /cdn-cgi/ 不然 Google Search Console 中会有几百个此目录下的「已抓取-尚未编入索引」。。。\n","permalink":"https://dvel.me/posts/deploy-blog-in-cloudflare-pages/","summary":"\u003ch2 id=\"cloudflare-pages-的免费政策\"\u003eCloudflare Pages 的免费政策\u003c/h2\u003e\n\u003cp\u003e以下摘自 \u003ca href=\"https://pages.cloudflare.com/\" target=\"_blank\" rel=\"noopener\"\u003eCloudflare Pages 首页\u003c/a\u003e 和 \u003ca href=\"https://developers.cloudflare.com/pages/platform/limits\" target=\"_blank\" rel=\"noopener\"\u003eCloudflare Pages 文档 - Limits\u003c/a\u003e（里面有更详细的）。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e同一时间只能部署一个 Pages\u003c/li\u003e\n\u003cli\u003e每月 500 次提交\u003c/li\u003e\n\u003cli\u003e无限站点\u003c/li\u003e\n\u003cli\u003e无限请求\u003c/li\u003e\n\u003cli\u003e无限带宽\u003c/li\u003e\n\u003cli\u003e每个项目最多 10 个自定义域名\u003c/li\u003e\n\u003cli\u003e每个站点最多 20000 个文件\u003c/li\u003e\n\u003cli\u003e单个文件最大 25 MB\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e总之对于个人博客来说是绰绰有余了。\u003c/p\u003e\n\u003cp\u003e\u003cdel\u003e实测每次部署大概是 2~3 分钟\u003c/del\u003e，今天发现出了 \u003cstrong\u003eFast builds\u003c/strong\u003e 功能，可以在设置中启用，在 2022-04-01 后将自动启用，新版的快速部署大约就 10 秒钟。\u003c/p\u003e\n\u003ch2 id=\"特点\"\u003e特点\u003c/h2\u003e\n\u003cp\u003e相比 GitHub Pages，可以直接从 GitHub 的私有仓库部署，GitHub Pages 却不能。\u003c/p\u003e\n\u003cp\u003e支持 Hugo、Hexo 等自动部署。\u003c/p\u003e\n\u003cp\u003eCDN 大陆效果一般，直连大约至少 \u003cdel\u003e几百毫秒\u003c/del\u003e 一千毫秒。\u003c/p\u003e\n\u003cp\u003e可以配合 Workers 等其他免费或付费功能完成多种类的 URL 转发。\u003c/p\u003e\n\u003cp\u003e另外 Cloudflare 的 DNS 支持裸域的 CNAME 与 MX 共存，自动搞定，这太方便了，之前 CloudXNS 至少还要自己手动操作一个其自定义的 LINK 类型及另一个域名作为跳板，Cloudflare 完全自动处理。我自己的的邮件用的也是裸域，在 Google Workspace，完全没有影响，收发件正常。\u003c/p\u003e","title":"将博客部署在 Cloudflare Pages"},{"content":"在 macOS 上，Alfred、Spotlight 相似产品极多，另外不错的软件也有 uTools、Raycast 等。\n但一直让我留在 Alfred 的原因之一就是它的「文件导航器」功能，每次换去其他软件尝试一会儿之后，马上就开始怀念这个功能。\n没见过有文章去介绍这个功能的，闲来无事随便写点。\n我的 Alfred 快捷键 仅供参考：\n双击 Command：呼出 Alfred 窗口 双击 Option：Alfred 剪贴板工具 双击 Control：呼出 uTools 窗口 双击 Shift：留给了 JetBrains 全家桶的内置快捷键 Command + 空格：切换输入法 Option + 空格：Alfred 文件导航器 Control + 空格：呼出 Spotlight 窗口 Shift + 空格：iTerm 2 File Search Search 这里是对「open」「find」「in」「tags」四个指令的命令设置，其中「in」是搜索文件内字符串的功能，「open」和「find」其实用「Quick Search」代替就可以了，也就是「空格」，输入「空格」+「文件名」就可以了。\nNavigation 文件导航器相关设置\n取消勾选「Use ⏎ to open folders in Finder」，回车就变成「→」的功能，不过也可以用「⌘+⏎」来在 Finder 中打开。\nBuffer 这个功能是在文件导航器中，可以批量处理一些文件。\n⌥↑ 将文件加入 buffer，如果已经加入，则移除 ⌥↓ 将文件加入 buffer，并移至下一个文件（适用于批量选择时） ⌥← 将最后一个加入 buffer 的文件移除 ⌥→ 最后，对所有加入 buffer 的文件进行统一操作 Advanced 这里可以设置家目录的指令符号，默认就是 ~，也可以修改家目录的位置，没必要修改。\nActions 设置 Alfred 新版已经将 Actions 抽离出来，并可通过扩展进行自定义，在「Universal Actions」中可以设置快捷键。\n我设置的是「fn」或「ctrl」。\n在文件导航器中，选中一个文件后，按「ctrl」即可进入 Actions 菜单，可对文件进行打开、移动、删除、复制等等操作。\n比如 Spotlight 不支持「使用 xx 应用程序打开文件」，Alfred 就可以很方便的搞定。\n示例零：路径直达 将路径直接粘贴到 Alfred 窗口，则自动激活文件导航器。\n支持绝对路径和以 ~ 开头的路径。\n输入 ~ 或 / 则直接跳转到家目录与根目录。\n示例一：快捷打开隐藏的配置文件 呼出 Alfred 窗口，输入 ~，则自动跳转到文件导航器的家目录。\n接着输入 .zshrc 就可以找到 zsh 的配置文件。\n这功能其他软件都没有实现，编辑个隐藏文件用 Alfred 就很方便了。\n示例二：快捷打开搜索到的文件夹内的某一文件 比如我想快捷地查看或编辑一下 Rime 的配置文件。\n在 Alfred 窗口输入「空格」+「rime」：\n这时按「→」即可进入文件导航器：\n我就可以选择我想要预览或编辑的文件了。\n示例三：支持通配符选项 在很多轻量场景中，找一些文件比用 Finder 方便多了。\n示例四：利用 Buffer 功能批量移动文件 有时候下载的电视剧字幕文件，每一集都单独放进了一个文件夹，我想把它们全都集合到同一个文件夹。\n如：\n. └── 某电视剧字幕/ ├── e1/ │ └── e1.ass ├── e2/ │ └── e2.ass └── e3/ └── e3.ass 变成：\n. └── 某电视剧字幕/ ├── e1.ass ├── e2.ass └── e3.ass 将三个文件都加入 buffer：\n然后按 ⌥ → 进入 Actions 菜单，选择移动到 xx 目录：\n接下来用 ← → 选择好目录，按回车就可以了。\nBuffer 的批量选择功能也可以结合通配符功能，快速选中一些同一文件夹下具有相同元素名称的文件。\n","permalink":"https://dvel.me/posts/alfred-file-navigation/","summary":"\u003cp\u003e在 macOS 上，Alfred、Spotlight 相似产品极多，另外不错的软件也有 uTools、Raycast 等。\u003c/p\u003e\n\u003cp\u003e但一直让我留在 Alfred 的原因之一就是它的「文件导航器」功能，每次换去其他软件尝试一会儿之后，马上就开始怀念这个功能。\u003c/p\u003e\n\u003cp\u003e没见过有文章去介绍这个功能的，闲来无事随便写点。\u003c/p\u003e\n\u003ch2 id=\"我的-alfred-快捷键\"\u003e我的 Alfred 快捷键\u003c/h2\u003e\n\u003cp\u003e仅供参考：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e双击 Command：呼出 Alfred 窗口\u003c/li\u003e\n\u003cli\u003e双击 Option：Alfred 剪贴板工具\u003c/li\u003e\n\u003cli\u003e双击 Control：呼出 uTools 窗口\u003c/li\u003e\n\u003cli\u003e双击 Shift：留给了 JetBrains 全家桶的内置快捷键\u003c/li\u003e\n\u003cli\u003eCommand + 空格：切换输入法\u003c/li\u003e\n\u003cli\u003eOption + 空格：Alfred 文件导航器\u003c/li\u003e\n\u003cli\u003eControl + 空格：呼出 Spotlight 窗口\u003c/li\u003e\n\u003cli\u003eShift + 空格：iTerm 2\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"file-search\"\u003eFile Search\u003c/h2\u003e\n\u003ch3 id=\"search\"\u003eSearch\u003c/h3\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-06A.webp\"\n            alt=\"Alfred\"\n            width=\"2432\"\n            height=\"1388\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e这里是对「open」「find」「in」「tags」四个指令的命令设置，其中「in」是搜索文件内字符串的功能，「open」和「find」其实用「Quick Search」代替就可以了，也就是「空格」，输入「空格」+「文件名」就可以了。\u003c/p\u003e\n\u003ch3 id=\"navigation\"\u003eNavigation\u003c/h3\u003e\n\u003cp\u003e文件导航器相关设置\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2022-01-06B.webp\"\n            alt=\"Alfred\"\n            width=\"2432\"\n            height=\"1388\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e取消勾选「Use ⏎ to open folders in Finder」，回车就变成「→」的功能，不过也可以用「⌘+⏎」来在 Finder 中打开。\u003c/p\u003e\n\u003ch3 id=\"buffer\"\u003eBuffer\u003c/h3\u003e\n\u003cp\u003e这个功能是在文件导航器中，可以批量处理一些文件。\u003c/p\u003e","title":"Alfred File Navigation（文件导航器）详解"},{"content":"方法一：HTML 标签的方法 [markup] [markup.goldmark] [markup.goldmark.renderer] unsafe = true 这样支持了 HTML 标签：\n\u0026lt;a href=\u0026#34;https://example.com\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;example.com\u0026lt;/a\u0026gt; 但比较麻烦，不推荐，不过建议开启这个功能以支持 HTML 语法。\n方法二：在 blackFriday 中渲染 Hugo 已在 v0.60 后默认使用了符合 CommonMark 标准的 Goldmark 渲染器。\n不过仍然可以启用 blackFriday 渲染器来设定其 hrefTargetBlank 属性为 true：\n[markup] defaultMarkdownHandler = \u0026#39;blackFriday\u0026#39; [markup.blackFriday] hrefTargetBlank = true 但这样就放弃了更快更标准的 Goldmark Markdown 渲染器。\n方法三（推荐）：使用 Goldmark 的 Markdown Render Hooks 需要 Hugo 版本大于 v0.62.0 并启用 Goldmark（默认就是）。\n创建 render-link.html 文件在 ./themes/\u0026lt;你的主题\u0026gt;/layouts/_default/_markup/ 目录。\n内容：（参考官方文档）\n\u0026lt;a href=\u0026#34;{{ .Destination | safeURL }}\u0026#34;{{ with .Title}} title=\u0026#34;{{ . }}\u0026#34;{{ end }}{{ if strings.HasPrefix .Destination \u0026#34;http\u0026#34; }} target=\u0026#34;_blank\u0026#34; rel=\u0026#34;noopener\u0026#34;{{ end }}\u0026gt;{{ .Text | safeHTML }}\u0026lt;/a\u0026gt; 推荐使用此方法，自动为所有文章内的链接加上了 target=\u0026quot;_blank\u0026quot; rel=\u0026quot;noopener\u0026quot;。\n但是站内链接也都加上了 target=\u0026quot;_blank\u0026quot; rel=\u0026quot;noopener\u0026quot;。\n站内链接建议写 path：\n[title](/foo/bar/) ↓ 会被简单解析为： ↓ \u0026lt;a href=\u0026#34;/foo/bar/\u0026#34;\u0026gt;title\u0026lt;/a\u0026gt; ","permalink":"https://dvel.me/posts/hugo-goldmark-markdown-new-tab/","summary":"\u003ch2 id=\"方法一html-标签的方法\"\u003e方法一：HTML 标签的方法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emarkup\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emarkup\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egoldmark\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emarkup\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egoldmark\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erenderer\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003eunsafe\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样支持了 HTML 标签：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ea\u003c/span\u003e \u003cspan class=\"na\"\u003ehref\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;https://example.com\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003etarget\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;_blank\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003eexample.com\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e但比较麻烦，不推荐，不过建议开启这个功能以支持 HTML 语法。\u003c/p\u003e\n\u003ch2 id=\"方法二在-blackfriday-中渲染\"\u003e方法二：在 blackFriday 中渲染\u003c/h2\u003e\n\u003cp\u003eHugo 已在 v0.60 后默认使用了符合 CommonMark 标准的  Goldmark 渲染器。\u003c/p\u003e\n\u003cp\u003e不过仍然可以启用 blackFriday 渲染器来设定其 \u003ccode\u003ehrefTargetBlank\u003c/code\u003e 属性为 \u003ccode\u003etrue\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emarkup\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003edefaultMarkdownHandler\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;blackFriday\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emarkup\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eblackFriday\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ehrefTargetBlank\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e但这样就放弃了更快更标准的 Goldmark Markdown 渲染器。\u003c/p\u003e\n\u003ch2 id=\"方法三推荐使用-goldmark-的-markdown-render-hooks\"\u003e方法三（推荐）：使用 Goldmark 的 Markdown Render Hooks\u003c/h2\u003e\n\u003cp\u003e需要 Hugo 版本大于 v0.62.0 并启用 Goldmark（默认就是）。\u003c/p\u003e\n\u003cp\u003e创建 \u003ccode\u003erender-link.html\u003c/code\u003e 文件在 \u003ccode\u003e./themes/\u0026lt;你的主题\u0026gt;/layouts/_default/_markup/\u003c/code\u003e 目录。\u003c/p\u003e\n\u003cp\u003e内容：（参考\u003ca href=\"https://gohugo.io/templates/render-hooks/#link-with-title-markdown-example\" target=\"_blank\" rel=\"noopener\"\u003e官方文档\u003c/a\u003e）\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ea\u003c/span\u003e \u003cspan class=\"na\"\u003ehref\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ .Destination | safeURL }}\u0026#34;\u003c/span\u003e\u003cspan class=\"err\"\u003e{{\u003c/span\u003e \u003cspan class=\"na\"\u003ewith\u003c/span\u003e \u003cspan class=\"err\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eTitle\u003c/span\u003e\u003cspan class=\"err\"\u003e}}\u003c/span\u003e \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{{ . }}\u0026#34;\u003c/span\u003e\u003cspan class=\"err\"\u003e{{\u003c/span\u003e \u003cspan class=\"na\"\u003eend\u003c/span\u003e \u003cspan class=\"err\"\u003e}}{{\u003c/span\u003e \u003cspan class=\"na\"\u003eif\u003c/span\u003e \u003cspan class=\"na\"\u003estrings\u003c/span\u003e\u003cspan class=\"err\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eHasPrefix\u003c/span\u003e \u003cspan class=\"err\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eDestination\u003c/span\u003e \u003cspan class=\"err\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"na\"\u003ehttp\u003c/span\u003e\u003cspan class=\"err\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"err\"\u003e}}\u003c/span\u003e \u003cspan class=\"na\"\u003etarget\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;_blank\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003erel\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;noopener\u0026#34;\u003c/span\u003e\u003cspan class=\"err\"\u003e{{\u003c/span\u003e \u003cspan class=\"na\"\u003eend\u003c/span\u003e \u003cspan class=\"err\"\u003e}}\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e{{ .Text | safeHTML }}\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e推荐使用此方法，自动为所有文章内的链接加上了 \u003ccode\u003etarget=\u0026quot;_blank\u0026quot; rel=\u0026quot;noopener\u0026quot;\u003c/code\u003e。\u003c/p\u003e","title":"在 Hugo Goldmark Markdown 中设置以新标签打开链接"},{"content":"总是记错弄乱，自己整理一份。\n基本概念 格林尼治标准时间（GMT） 英语：Greenwich Mean Time，简称 GMT。\n是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时，因为本初子午线被定义为通过那里的经线。\n由于地球每天的自转是有些不规则的，而且正在缓慢减速，GMT 已经被原子钟报时的 UTC 顶替。\n协调世界时（UTC） 英语：Coordinated Universal Time，法语：Temps Universel Coordonné，简称 UTC。\n其以原子时秒长为基础，是最主要的世界时间标准。\n关于缩写：\n国际电信联盟希望协调世界时能够在所有语言有单一的缩写。英语和法语区的人同时希望各自的语言缩写－CUT 和 TUC 能够成为国际标准，结果最后妥协使用 UTC。\nGMT 与 UTC 目前能看到 GMT 字眼的，常见于 JavaScript 的 Date() 和谷歌搜索「伦敦时间」时展示的。\n我也不是很理解为什么显示 GMT，但是即便显示的是 GMT，也是经过校准的，与正确时间相差不到一秒。\n网络时间协议（NTP） 英语：Network Time Protocol，缩写：NTP。\nNTP 是一个在电脑系统之间进行时钟同步的网络协议，意图将所有参与电脑的协调世界时（UTC）时间同步到几毫秒的误差内。\n自1985年以来，NTP是目前仍在使用的最古老的互联网协议之一。\n时区与本地时间 一般说 UTC 时间也就是指零时区 +00:00（或写成 UTC+0、UTC±00:00） 时间，比北京时间早八个小时。\n2021-01-01 08:00:00 +08:00 也就是北京时间的上午八点钟，而这时 UTC 时间为 2021-01-01 00:00:00 +00:00，英国伦敦的午夜，这是同一个时刻。\n时间戳 这里指的时间戳是指代码中的 timestamp 那一串长数字。\n编程中大家讨论和使用的皆是 Unix 时间戳（Unix timestamp 或 POSIX timestamp），是从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在的秒数，有的语言也支持了毫秒、微秒等等。\n1 秒 = 1000 毫秒 1 毫秒 = 1000 微秒 很多编程语言都有生成当前时间戳的方法，目前的时间戳长度：\n10 位长度，精确到秒 13 位长度，精确到毫秒 16 位长度，精确到微秒 在 2286 年 11 月 21 日 1 时 46 分 39 秒之后，时间戳会加长一位数。\n时间戳有时区吗？ 当我们讨论时间戳的时候，也就是前后端交换数据，数据库存储日期时间时，皆是 Unix 时间戳，时间戳是没有时区概念的。\n或者可以理解为，时间戳是固定死零时区的。\n2021-01-01 00:00:00+00:00 与 2021-01-01 08:00:00+08:00 的时间戳都是 1609459200。\n所以建议在数据库或数据传输时使用 Unix 时间戳，时间戳可以被简单地解析为 UTC 时间或任何时区的时间，不会被时区概念束缚和混淆。\nISO 8601 国际标准 ISO 8601，是国际标准化组织的日期和时间的表示方法，全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。\n简单来说，日期与时间的规定写法是这样的：\n2000-01-23 # 年使用四位数，月、日、时、分、秒皆使用两位数，不够的前面补零。 2000-01-23T04:05:06 # 用 T 分割日期与时间。 2000-01-23T04:05:06Z # 用 Z 代表 UTC+0（零时区） 2000-01-23T04:05:06+00:00 # 也可以使用 +00:00 表示零时区 2000-01-23T04:05:06+08:00 # 东八区 2000-01-23T04:05:06.123456 # Python 中 datetime.now().isoformat() 的默认格式 实际上 ISO 8601 也允许了一些其他的写法。\nRFC 3339 与 ISO 8601 Python 用的是 ISO 8601：\ndatetime.now().isoformat() datetime.utcnow().isoformat() Golang 用的是 RFC 3339：\ntime.Now().Format(time.RFC3339) time.Now().UTC().Format(time.RFC3339) What\u0026rsquo;s the difference between ISO 8601 and RFC 3339 Date Formats?\nRFC 3339 被列为 ISO 8601 的配置文件。有一些很小的差异，比如 RFC 3339 不允许两位数的年份，RFC 3339 允许用空格代替 T。\n就一般的使用情况来说，两者之间可视为没有差异。\n获取时间戳 Python： import time from datetime import datetime # 正确的 print(time.time()) print(datetime.now().timestamp()) # 错误的 print(datetime.utcnow().timestamp()) timestamp() 经过了 Python 内部处理的，将当前的系统时间（无论你在哪个时区）转换为正确的标准的 Unix 时间戳。\n而最下面的那个为什么错了，因为 timestamp() 默认你给的 datetime 是当前系统的时区，如果你在零时区，那的确没有问题；如果不在零时区，timestamp() 会认为我给的是东八区，所以最后返回了错误的时间戳。\n可以解决这个错误，只需要在 timestamp() 之前将 datetime 的时区确定即可。\nfrom datetime import datetime, timedelta, timezone d1 = datetime.now() d1 = d1.replace(tzinfo=timezone(timedelta(hours=8))) # 绑定时区为东八区 ts1 = d1.timestamp() print(ts1) d2 = datetime.utcnow() d2 = d2.replace(tzinfo=timezone.utc) # 绑定时区为零时区 ts2 = d2.timestamp() print(ts2) # ts1 和 ts2 基本相等，只有程序运行顺序的微秒级差距。 Golang： Golang 中是一样的:\ntime.Now().Unix() time.Now().UTC().Unix() 因为 Golang 的 time.Now() 中默认就带有时区信息。\nPython 常用的日期与时间方法 datetime 转 str import datetime d = datetime.datetime.now() s = d.strftime(\u0026#39;%Y-%m-%d %H:%M:%S\u0026#39;) str 转 datetime from datetime import datetime, timedelta, timezone, time s = \u0026#34;2001-02-03 04:05:06\u0026#34; d = datetime.strptime(s, \u0026#39;%Y-%m-%d %H:%M:%S\u0026#39;) # 为得到的 datetime 增加时区 d_with_timezone = d.replace(tzinfo=timezone(timedelta(hours=8))) 获取当前 UTC 时间（带时区） 不加后面的 replace 就不带时区信息了，下同。\nfrom datetime import datetime, timezone datetime.utcnow().replace(tzinfo=timezone.utc) # 2021-05-29 15:28:10.913530+00:00 获取当前系统时间（带时区） from datetime import datetime, timezone # 在中国时区电脑上运行： datetime.now().replace(tzinfo=timezone(timedelta(hours=8))) # 2021-05-29 23:38:21.006309+08:00 datetime 转 时间戳 from datetime import datetime, timezone, timedelta dt = datetime.now() print(dt, \u0026#39;datetime.now() 当前系统时间（不含时区）\u0026#39;) print(dt.timestamp(), \u0026#39;不含时区的时间，会认为是系统时间，会自动转换为正确的 UTC 时间戳\u0026#39;) print(dt.replace(tzinfo=timezone(timedelta(hours=8))).timestamp(), \u0026#39;包含东八区时区信息的，同上\u0026#39;) # 2021-07-16 00:15:02.730997 datetime.now() 当前系统时间（不含时区） # 1626365702.730997 不含时区的时间，会认为是系统时间，会自动转换为正确的 Unix 时间戳 # 1626365702.730997 包含东八区时区信息的，同上 时间戳 转 datetime from datetime import datetime datetime.utcfromtimestamp(1609459200) # 2021-01-01 00:00:00 datetime.fromtimestamp(1609459200, timezone.utc) # 2021-01-01 00:00:00+00:00 datetime.fromtimestamp(1609459200) # 2021-01-01 08:00:00 datetime.fromtimestamp(1609459200, timezone(timedelta(hours=8))) # 2021-01-01 08:00:00+08:00 datetime 转换时区 转换前需要先确定被转换的 datetime 对象的时区，拥有时区属性的 datetime 对象可以转换为任意一个时区的日期时间。\nfrom datetime import datetime, timedelta, timezone utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc) print(utc_dt) # 2021-01-01 00:00:00+00:00 bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8))) print(bj_dt) # 2021-01-01 08:00:00+08:00 tokyo_dt = bj_dt.astimezone(timezone(timedelta(hours=9))) print(tokyo_dt) # 2021-01-01 09:00:00+09:00 ","permalink":"https://dvel.me/posts/datetime-note/","summary":"\u003cp\u003e总是记错弄乱，自己整理一份。\u003c/p\u003e\n\u003ch2 id=\"基本概念\"\u003e基本概念\u003c/h2\u003e\n\u003ch3 id=\"格林尼治标准时间gmt\"\u003e格林尼治标准时间（GMT）\u003c/h3\u003e\n\u003cp\u003e英语：\u003cstrong\u003eG\u003c/strong\u003ereenwich \u003cstrong\u003eM\u003c/strong\u003eean \u003cstrong\u003eT\u003c/strong\u003eime，简称 \u003cstrong\u003eGMT\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时，因为本初子午线被定义为通过那里的经线。\u003c/p\u003e\n\u003cp\u003e由于地球每天的自转是有些不规则的，而且正在缓慢减速，\u003cstrong\u003eGMT 已经被原子钟报时的 UTC 顶替\u003c/strong\u003e。\u003c/p\u003e\n\u003ch3 id=\"协调世界时utc\"\u003e协调世界时（UTC）\u003c/h3\u003e\n\u003cp\u003e英语：\u003cstrong\u003eC\u003c/strong\u003eoordinated \u003cstrong\u003eU\u003c/strong\u003eniversal \u003cstrong\u003eT\u003c/strong\u003eime，法语：\u003cstrong\u003eT\u003c/strong\u003eemps \u003cstrong\u003eU\u003c/strong\u003eniversel \u003cstrong\u003eC\u003c/strong\u003eoordonné，简称 \u003cstrong\u003eUTC\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e其以原子时秒长为基础，是最主要的世界时间标准。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e关于缩写：\u003c/p\u003e\n\u003cp\u003e国际电信联盟希望协调世界时能够在所有语言有单一的缩写。英语和法语区的人同时希望各自的语言缩写－CUT 和 TUC 能够成为国际标准，结果最后妥协使用 UTC。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"gmt-与-utc\"\u003eGMT 与 UTC\u003c/h3\u003e\n\u003cp\u003e目前能看到 GMT 字眼的，常见于 JavaScript 的 \u003ccode\u003eDate()\u003c/code\u003e 和谷歌搜索「伦敦时间」时展示的。\u003c/p\u003e\n\u003cp\u003e我也不是很理解为什么显示 GMT，但是即便显示的是 GMT，也是经过校准的，与正确时间相差不到一秒。\u003c/p\u003e\n\u003ch3 id=\"网络时间协议ntp\"\u003e网络时间协议（NTP）\u003c/h3\u003e\n\u003cp\u003e英语：\u003cstrong\u003eN\u003c/strong\u003eetwork \u003cstrong\u003eT\u003c/strong\u003eime \u003cstrong\u003eP\u003c/strong\u003erotocol，缩写：\u003cstrong\u003eNTP\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eNTP 是一个在电脑系统之间进行时钟同步的网络协议，意图将所有参与电脑的协调世界时（UTC）时间同步到几毫秒的误差内。\u003c/p\u003e\n\u003cp\u003e自1985年以来，NTP是目前仍在使用的最古老的互联网协议之一。\u003c/p\u003e\n\u003ch3 id=\"时区与本地时间\"\u003e时区与本地时间\u003c/h3\u003e\n\u003cp\u003e一般说 UTC 时间也就是指零时区 +00:00（或写成 UTC+0、UTC±00:00） 时间，比北京时间早八个小时。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e2021-01-01 08:00:00 +08:00\u003c/code\u003e 也就是北京时间的上午八点钟，而这时 UTC 时间为 \u003ccode\u003e2021-01-01 00:00:00 +00:00\u003c/code\u003e，英国伦敦的午夜，这是同一个时刻。\u003c/p\u003e\n\u003ch3 id=\"时间戳\"\u003e时间戳\u003c/h3\u003e\n\u003cp\u003e这里指的时间戳是指代码中的 timestamp 那一串长数字。\u003c/p\u003e\n\u003cp\u003e编程中大家讨论和使用的皆是 \u003cstrong\u003eUnix 时间戳\u003c/strong\u003e（Unix timestamp 或 POSIX timestamp），是从 \u003cstrong\u003e1970 年 1 月 1 日 0 时 0 分 0 秒\u003c/strong\u003e到现在的秒数，有的语言也支持了毫秒、微秒等等。\u003c/p\u003e","title":"日期与时间（UTC、GMT、时间戳、时区）"},{"content":"升级到了 macOS Monterey 后发现 XtraFinder 失效了，官方暂未跟进 macOS 12，迫不得已用回原始的 Finder。\n但是发现每次从 Alfred 打开的文件夹都是以 Finder 新建窗口的方式打开的。\n确保 Finder 偏好设置中打开「在新标签页中打开文件夹」。 在系统偏好设置中将「首选以标签页方式打开文稿」的选项设置为「始终」。 总之目前（macOS Monterey 12.0.1）这样设置是可行的。\n苹果这个行为逻辑给人整迷了。\n很明显设置一针对的应该是所有有标签页的应用，设置二针对的是 Finder 单个应用，但必须同时设定才起作用。\n服了苹果。\n","permalink":"https://dvel.me/posts/alfred-finder-new-tab/","summary":"\u003cp\u003e升级到了 macOS Monterey 后发现 \u003ca href=\"https://www.trankynam.com/xtrafinder/\" target=\"_blank\" rel=\"noopener\"\u003eXtraFinder\u003c/a\u003e 失效了，官方暂未跟进 macOS 12，迫不得已用回原始的 Finder。\u003c/p\u003e\n\u003cp\u003e但是发现每次从 Alfred 打开的文件夹都是以 Finder 新建窗口的方式打开的。\u003c/p\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli\u003e确保 Finder 偏好设置中打开「\u003cstrong\u003e在新标签页中打开文件夹\u003c/strong\u003e」。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cimg src=\"/img/2021-05-19A.webp\" alt=\"通用偏好设置\" style=\"zoom: 33%;\" /\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e在系统偏好设置中将「\u003cstrong\u003e首选以标签页方式打开文稿\u003c/strong\u003e」的选项设置为「\u003cstrong\u003e始终\u003c/strong\u003e」。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cimg src=\"/img/2021-05-19B.webp\" alt=\"访达偏好设置\" style=\"zoom:50%;\" /\u003e\n\u003cp\u003e总之目前（macOS Monterey 12.0.1）这样设置是可行的。\u003c/p\u003e\n\u003cp\u003e苹果这个行为逻辑给人整迷了。\u003c/p\u003e\n\u003cp\u003e很明显设置一针对的应该是所有有标签页的应用，设置二针对的是 Finder 单个应用，但必须同时设定才起作用。\u003c/p\u003e\n\u003cp\u003e服了苹果。\u003c/p\u003e","title":"让 Alfred 以新标签的方式打开 Finder"},{"content":"有时候项目里引用了一些大文件，导致 .git 容量高达几个 G。\n如果这些大文件丢失并不敏感，也没什么用处，可以清理掉来节约一下空间。\n操作前建议备份。\n1. gc 使用 git-gc 将对象打包。\n$ git gc --prune=now .git 已经从 4 个 G 变成了 322M。\n$ du -sh .git 322M\t.git 2. 查找最大的 3 个文件 $ git rev-list --objects --all | grep \u0026#34;$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -3 | awk \u0026#39;{print$1}\u0026#39;)\u0026#34; 4badfe287e3f1d6e4e288b2c3b47261119ce2fca foo/bar1.xxx 00e7645c93c2368b0634bda72507b40c936dd1b3 foo/bar2.xxx 4088cefbbc3dcd6a17dfa656423ad20137fad9dd foo/bar3.xxx 3. 删除文件 $ git filter-branch --force --index-filter \u0026#34;git rm -rf --cached --ignore-unmatch \u0026lt;filename\u0026gt;\u0026#34; --prune-empty --tag-name-filter cat -- --all 如： $ git filter-branch --force --index-filter \u0026#34;git rm -rf --cached --ignore-unmatch foo/bar1.xxx\u0026#34; --prune-empty --tag-name-filter cat -- --all 1000 多个提交大概运行了 2 分钟。\n4. 清除缓存 $ git for-each-ref --format=\u0026#39;delete %(refname)\u0026#39; refs/original | git update-ref --stdin $ git reflog expire --expire=now --all $ git gc --prune=now 5. 查看成果 $ du -sh .git 212M\t.git 一个几十 M 的文件清除后，整个包减小了大概 100 M，多清理几个就降下来了。\n最后 Push 时需使用 --force 参数覆盖远端。\n参考 \u0026amp; 感谢 Git清理删除历史提交文件\n如何解决 GitHub 提交次数过多 .git 文件过大的问题？\n","permalink":"https://dvel.me/posts/git-filter-branch-slim/","summary":"\u003cp\u003e有时候项目里引用了一些大文件，导致 \u003ccode\u003e.git\u003c/code\u003e 容量高达几个 G。\u003c/p\u003e\n\u003cp\u003e如果这些大文件丢失并不敏感，也没什么用处，可以清理掉来节约一下空间。\u003c/p\u003e\n\u003cp\u003e操作前建议备份。\u003c/p\u003e\n\u003ch2 id=\"1-gc\"\u003e1. gc\u003c/h2\u003e\n\u003cp\u003e使用 \u003ca href=\"https://git-scm.com/docs/git-gc\" target=\"_blank\" rel=\"noopener\"\u003egit-gc\u003c/a\u003e 将对象打包。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git gc --prune\u003cspan class=\"o\"\u003e=\u003c/span\u003enow\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e.git\u003c/code\u003e 已经从 4 个 G 变成了 322M。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ du -sh .git\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e322M\t.git\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"2-查找最大的-3-个文件\"\u003e2. 查找最大的 3 个文件\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git rev-list --objects --all \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"k\"\u003e$(\u003c/span\u003egit verify-pack -v .git/objects/pack/*.idx \u003cspan class=\"p\"\u003e|\u003c/span\u003e sort -k \u003cspan class=\"m\"\u003e3\u003c/span\u003e -n \u003cspan class=\"p\"\u003e|\u003c/span\u003e tail -3 \u003cspan class=\"p\"\u003e|\u003c/span\u003e awk \u003cspan class=\"s1\"\u003e\u0026#39;{print$1}\u0026#39;\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e4badfe287e3f1d6e4e288b2c3b47261119ce2fca foo/bar1.xxx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e00e7645c93c2368b0634bda72507b40c936dd1b3 foo/bar2.xxx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e4088cefbbc3dcd6a17dfa656423ad20137fad9dd foo/bar3.xxx\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"3-删除文件\"\u003e3. 删除文件\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git filter-branch --force --index-filter \u003cspan class=\"s2\"\u003e\u0026#34;git rm -rf --cached --ignore-unmatch \u0026lt;filename\u0026gt;\u0026#34;\u003c/span\u003e  --prune-empty --tag-name-filter cat -- --all\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e如：\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git filter-branch --force --index-filter \u003cspan class=\"s2\"\u003e\u0026#34;git rm -rf --cached --ignore-unmatch foo/bar1.xxx\u0026#34;\u003c/span\u003e  --prune-empty --tag-name-filter cat -- --all\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e1000 多个提交大概运行了 2 分钟。\u003c/p\u003e","title":"用 git filter-branch 给 Git 仓库瘦身"},{"content":"简介 qBittorrent 是一个跨平台的自由 BitTorrent 客户端。（官方网站、GitHub）\nGitHub 社区亦有一个 qBittorrent Enhanced Edition （qBittorrent 增强版本），主要特点是自动屏蔽了迅雷、自动更新 trackers。\n如果只进行 BT 下载，推荐使用 qBittorrent Enhanced Edition，但是像馒头这样的 PT 社区不支持，可以使用原版。\n耽误了一阵子在 qBittorrent 的配置方面，这里简单记录一下主要的配置。\n为了发现更多的 Peer Peer 链接协议都开启。\n开启 UPnP/NAT-PMP 端口转发。\n启用 DHT，PeX、本地用户，无需关心 PT，PT 会自动禁止，只使用 Tracker。\n最好桥接，可以被更多的 Peer 发现。\n有些光猫是可以破解的，可以参考我另一篇博文：光猫破解+桥接记录\n加密 有些 ISP 会限制 BT 流量，尽量使用「强制加密」和「匿名模式」。\ntrackers 目前国际最主流的是这个仓库：ngosang/trackerslist 。\n也有国人维护的一个 XIU2/TrackersListCollection，来源包括上面的。\n高级设置 图片来源：https://www.jianshu.com/p/ac70172767ed\n其中最关键的配置项，这两个必须打开，否则有些 Tracker 总是连不上：\n总是向同级的所有 Tracker 汇报 总是向所有等级的 Tracker 汇报 另外对于 PT 用户一定要设置的地方：\n上传窗口策略： 固定窗口数 ✓ 基于上传速度 ✗（经过测试使用此项配置会导致上传速度大大降低） 上传连接策略： 轮流上传（没试过） 最快上传（PT 推荐） 反吸血（BT 推荐） 仅使用上两个修改，其他默认，百兆左右的上传带宽即可跑满 10M/s。\n","permalink":"https://dvel.me/posts/qbittorrent-config/","summary":"\u003ch2 id=\"简介\"\u003e简介\u003c/h2\u003e\n\u003cp\u003eqBittorrent 是一个跨平台的自由 BitTorrent 客户端。（\u003ca href=\"https://www.qbittorrent.org/\" target=\"_blank\" rel=\"noopener\"\u003e官方网站\u003c/a\u003e、\u003ca href=\"https://github.com/qbittorrent/qBittorrent\" target=\"_blank\" rel=\"noopener\"\u003eGitHub\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003eGitHub 社区亦有一个 \u003ca href=\"https://github.com/SuperNG6/Docker-qBittorrent-Enhanced-Edition\" target=\"_blank\" rel=\"noopener\"\u003eqBittorrent Enhanced Edition\u003c/a\u003e （qBittorrent 增强版本），主要特点是自动屏蔽了迅雷、自动更新 trackers。\u003c/p\u003e\n\u003cp\u003e如果只进行 BT 下载，推荐使用 qBittorrent Enhanced Edition，但是像馒头这样的 PT 社区不支持，可以使用原版。\u003c/p\u003e\n\u003cp\u003e耽误了一阵子在 qBittorrent 的配置方面，这里简单记录一下主要的配置。\u003c/p\u003e\n\u003ch2 id=\"为了发现更多的-peer\"\u003e为了发现更多的 Peer\u003c/h2\u003e\n\u003cp\u003ePeer 链接协议都开启。\u003c/p\u003e\n\u003cp\u003e开启 UPnP/NAT-PMP 端口转发。\u003c/p\u003e\n\u003cp\u003e启用 DHT，PeX、本地用户，无需关心 PT，PT 会自动禁止，只使用 Tracker。\u003c/p\u003e\n\u003cp\u003e最好桥接，可以被更多的 Peer 发现。\u003c/p\u003e\n\u003cp\u003e有些光猫是可以破解的，可以参考我另一篇博文：\u003ca href=\"/posts/hack-unicom-modem-bridge/\"\u003e光猫破解+桥接记录\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"加密\"\u003e加密\u003c/h2\u003e\n\u003cp\u003e有些 ISP 会限制 BT 流量，尽量使用「强制加密」和「匿名模式」。\u003c/p\u003e\n\u003ch2 id=\"trackers\"\u003etrackers\u003c/h2\u003e\n\u003cp\u003e目前国际最主流的是这个仓库：\u003ca href=\"https://github.com/ngosang\" target=\"_blank\" rel=\"noopener\"\u003engosang\u003c/a\u003e/\u003cstrong\u003e\u003ca href=\"https://github.com/ngosang/trackerslist\" target=\"_blank\" rel=\"noopener\"\u003etrackerslist\u003c/a\u003e\u003c/strong\u003e 。\u003c/p\u003e\n\u003cp\u003e也有国人维护的一个 \u003ca href=\"https://trackerslist.com\" target=\"_blank\" rel=\"noopener\"\u003eXIU2/TrackersListCollection\u003c/a\u003e，来源包括上面的。\u003c/p\u003e\n\u003ch2 id=\"高级设置\"\u003e高级设置\u003c/h2\u003e\n\u003cp\u003e图片来源：\u003ca href=\"https://www.jianshu.com/p/ac70172767ed\" target=\"_blank\" rel=\"noopener\"\u003ehttps://www.jianshu.com/p/ac70172767ed\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2021-04-06.webp\"\n            alt=\"qBittorrent\"\n            width=\"1080\"\n            height=\"1960\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003cp\u003e其中最关键的配置项，这两个必须打开，否则有些 Tracker 总是连不上：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e总是向同级的所有 Tracker 汇报\u003c/li\u003e\n\u003cli\u003e总是向所有等级的 Tracker 汇报\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另外对于 PT 用户一定要设置的地方：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上传窗口策略：\n\u003cul\u003e\n\u003cli\u003e固定窗口数 ✓\u003c/li\u003e\n\u003cli\u003e基于上传速度 ✗（经过测试使用此项配置会导致上传速度大大降低）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e上传连接策略：\n\u003cul\u003e\n\u003cli\u003e轮流上传（没试过）\u003c/li\u003e\n\u003cli\u003e最快上传（PT 推荐）\u003c/li\u003e\n\u003cli\u003e反吸血（BT 推荐）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e仅使用上两个修改，其他默认，百兆左右的上传带宽即可跑满 10M/s。\u003c/p\u003e","title":"qBittorrent 设置教程"},{"content":"实操是联通光猫烽火 HG6543C，主要目的就是桥接。\n如果你的光猫普通用户登录后就可以改桥接，就没必要破解超级用户密码了。\n破解流程 请直接尝试第五步，默认密码可能为 cuadmin 或 CUAdmin，如果密码错误则从第一步开始。\n1、启用隐藏账户 http://192.168.1.1/logoffaccount.html\n在这个网址下可以开启隐藏用户。\n也可以「允许 TR069 修改」，可以禁用远程管理。\n2、登录 http://192.168.1.1\n用户名：fiberhomehg2x0 密码：hg2x0\n实测在启用隐藏账户后的跳转页面，直接输入 hg2x0 就进入服务设置了，我这个型号的光猫并没有要求我输入用户名。\n3、开启 Telnet 服务 服务设置 - 服务设置 - 启用 Telnet 服务器，设置好账号密码，保存/应用。\n服务设置 - 服务设置 - 服务访问控制，我这里 TELNET 选项默认为 Disable，改成 LAN 才可以连接。\n4、Telnet 获取超级用户密码 进入终端，Telnet 连接上后如果想进行其他操作，输入 sh 以解锁 Linux 所有命令行，否则只有有限的几个命令。\n$ telnet 192.168.1.1  ✔ Trying 192.168.1.1... Connected to 192.168.1.1. Escape character is \u0026#39;^]\u0026#39;. BCM96848 Broadband Router Login: admin Password: \u0026gt; get telname cuadmin \u0026gt; get telpwd cuadmin 5、以超级用户进入管理页面 http://192.168.1.1/cu.html 账号密码为上一步所得。\n其他 在 Telnet 之后，top 看到了网上有人说的光猫 javmm 服务，占了三分之一以上的内存，kill 之后也一切正常，不知道这个服务是干嘛的。\n桥接流程 光猫 以管理员用户登入 http://192.168.1.1/cu.html - 基本设置 - 宽带设置。\n「连接名称」应该有三种或以上：\nTR069（远程管理、语音） INTERNET（互联网连接） IPTV（电视） 选中「INTERNET」。\n将「模式」从「Route（路由模式）」改为「Bridge（桥接模式）」。\n点击「保存/应用」。\n路由器 改成拨号模式（PPPoE），输入宽带账号密码就可以了。\n测试 BT 端口 打开 BT 软件，设置好端口 xxxxx。\nhttps://www.yougetsignal.com/tools/open-ports/ 在这个网站上可以检测。\nPort xxxxx is open on xxx.xxx.xxx.xxx 则表示 ping 通。\n","permalink":"https://dvel.me/posts/hack-unicom-modem-bridge/","summary":"\u003cp\u003e实操是联通光猫烽火 HG6543C，主要目的就是桥接。\u003c/p\u003e\n\u003cp\u003e如果你的光猫普通用户登录后就可以改桥接，就没必要破解超级用户密码了。\u003c/p\u003e\n\u003ch2 id=\"破解流程\"\u003e破解流程\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e请直接尝试第五步，默认密码可能为 \u003ccode\u003ecuadmin\u003c/code\u003e 或 \u003ccode\u003eCUAdmin\u003c/code\u003e，如果密码错误则从第一步开始。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"1启用隐藏账户\"\u003e1、启用隐藏账户\u003c/h3\u003e\n\u003cp\u003ehttp://192.168.1.1/logoffaccount.html\u003c/p\u003e\n\u003cp\u003e在这个网址下可以开启隐藏用户。\u003c/p\u003e\n\u003cp\u003e也可以「允许 TR069 修改」，可以禁用远程管理。\u003c/p\u003e\n\u003ch3 id=\"2登录\"\u003e2、登录\u003c/h3\u003e\n\u003cp\u003ehttp://192.168.1.1\u003c/p\u003e\n\u003cp\u003e用户名：fiberhomehg2x0\n密码：hg2x0\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e实测在启用隐藏账户后的跳转页面，直接输入 \u003ccode\u003ehg2x0\u003c/code\u003e 就进入服务设置了，我这个型号的光猫并没有要求我输入用户名。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"3开启-telnet-服务\"\u003e3、开启 Telnet 服务\u003c/h3\u003e\n\u003cp\u003e服务设置 - 服务设置 - 启用 Telnet 服务器，设置好账号密码，保存/应用。\u003c/p\u003e\n\u003cp\u003e服务设置 - 服务设置 - 服务访问控制，我这里 \u003ccode\u003eTELNET\u003c/code\u003e 选项默认为 \u003ccode\u003eDisable\u003c/code\u003e，改成 \u003ccode\u003eLAN\u003c/code\u003e 才可以连接。\u003c/p\u003e\n\u003ch3 id=\"4telnet-获取超级用户密码\"\u003e4、Telnet 获取超级用户密码\u003c/h3\u003e\n\u003cp\u003e进入终端，Telnet 连接上后如果想进行其他操作，输入 \u003ccode\u003esh\u003c/code\u003e 以解锁 Linux 所有命令行，否则只有有限的几个命令。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ telnet 192.168.1.1                                                                                                                                     ✔\n\tTrying 192.168.1.1...\n\tConnected to 192.168.1.1.\n\tEscape character is \u0026#39;^]\u0026#39;.\n\tBCM96848 Broadband Router\nLogin: admin\nPassword:\n\u0026gt; get telname\n\tcuadmin\n\u0026gt; get telpwd\n\tcuadmin\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"5以超级用户进入管理页面\"\u003e5、以超级用户进入管理页面\u003c/h3\u003e\n\u003cp\u003ehttp://192.168.1.1/cu.html 账号密码为上一步所得。\u003c/p\u003e","title":"联通光猫破解+桥接记录"},{"content":"因为 Terminal 或 iTerm 2 是不走系统代理的，有时候访问 GitHub、Homebrew 等有点龟速，体验很差，最好设置其走代理访问。\n使用工具 Surge 或 ClashX 等代理软件的增强模式 Proxifier 也可以配置一些软件强制走代理 终端使用 ProxyChains 没用过 ProxyChains，Proxifier 太贵了且功能雷同，又不想一直开着增强模式。\nHTTP 代理 Surge 在菜单栏按 ⌘+C 就会自动生成代理命令，假设端口是 8888 和 8889：\n$ export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889 每次都输入比较麻烦，可以写进 ~/.zshrc 中，示例：\n# 自动代理 export https_proxy=http://127.0.0.1:8888 export http_proxy=http://127.0.0.1:8888 export all_proxy=socks5://127.0.0.1:8889 # 开关代理 alias setproxy=\u0026#34;export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889;echo \\\u0026#34;Set proxy successfully\\\u0026#34; \u0026#34; alias unsetproxy=\u0026#34;unset http_proxy;unset https_proxy;unset all_proxy;echo \\\u0026#34;Unset proxy successfully\\\u0026#34; \u0026#34; # 测试 alias lip=\u0026#34;curl cip.cc; curl ifconfig.me\u0026#34; 让 shell 默认就走代理，并设置一个开关。\n最后的测试，随便找两个 IP 查询服务就可以了，并在自己的代理规则中设定一个直连、一个代理。\nSSH 代理 Git 可以设置 git config --global http.proxy 和 git config --global https.proxy 。\n或者直接用下面这个，一劳永逸。\nHost * ProxyCommand nc -X 5 -x 127.0.0.1:8889 %h %p # * 代表所有的 SSH 主机 # 第二行代表让所有的 SSH 的主机在连接的时候，通过本地的端口为 8889 的 socks5 代理去连接 nc 的参数说明：https://man.openbsd.org/nc\n","permalink":"https://dvel.me/posts/mac-terminal-proxy/","summary":"\u003cp\u003e因为 Terminal 或 iTerm 2 是不走系统代理的，有时候访问 GitHub、Homebrew 等有点龟速，体验很差，最好设置其走代理访问。\u003c/p\u003e\n\u003ch2 id=\"使用工具\"\u003e使用工具\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eSurge 或 ClashX 等代理软件的增强模式\u003c/li\u003e\n\u003cli\u003eProxifier 也可以配置一些软件强制走代理\u003c/li\u003e\n\u003cli\u003e终端使用 ProxyChains\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e没用过 ProxyChains，Proxifier 太贵了且功能雷同，又不想一直开着增强模式。\u003c/p\u003e\n\u003ch2 id=\"http-代理\"\u003eHTTP 代理\u003c/h2\u003e\n\u003cp\u003eSurge 在菜单栏按 ⌘+C 就会自动生成代理命令，假设端口是 \u003ccode\u003e8888\u003c/code\u003e 和 \u003ccode\u003e8889\u003c/code\u003e：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e每次都输入比较麻烦，可以写进  \u003ccode\u003e~/.zshrc\u003c/code\u003e 中，示例：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e# 自动代理\nexport https_proxy=http://127.0.0.1:8888\nexport http_proxy=http://127.0.0.1:8888\nexport all_proxy=socks5://127.0.0.1:8889\n\n# 开关代理\nalias setproxy=\u0026#34;export https_proxy=http://127.0.0.1:8888;export http_proxy=http://127.0.0.1:8888;export all_proxy=socks5://127.0.0.1:8889;echo \\\u0026#34;Set proxy successfully\\\u0026#34; \u0026#34;\nalias unsetproxy=\u0026#34;unset http_proxy;unset https_proxy;unset all_proxy;echo \\\u0026#34;Unset proxy successfully\\\u0026#34; \u0026#34; \n\n# 测试\nalias lip=\u0026#34;curl cip.cc; curl ifconfig.me\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e让 shell 默认就走代理，并设置一个开关。\u003c/p\u003e","title":"配置 Mac 终端走代理"},{"content":"由于长期在使用 MBP，但还是想打打游戏，这里推荐一些我玩过的，MBP 能带得动的游戏。\n我用的是 Intel MBP 带独显的高配，目前看来 M1 基本都可以胜任，如果兼容的话。\n倾情推荐 Portal \u0026amp; Portal 2 传送门 Portal \u0026amp; Portal 2\n世界第一，目前最好玩的游戏，哪怕过了这么多年。\n在 2 通关后，建议进行双人联机，联机模式还有一整套关卡，当然也有社区作品。\nRimWorld 边缘世界 RimWorld\n从 A15 玩到 1.0，感谢伟大的作者，也感谢各个 Mod 的贡献者。\n这是我玩过的时间最长的单机游戏了，评论区时间过千的比比皆是，时间过百的熙熙攘攘。\n这也是我第一款安装过 100 多个 Mod 的游戏，真乃是装 Mod 一时爽，一直装一直爽。每天早上听到「Waiting for the sun」的闹铃，我都会回想起那里的春夏秋冬，伴随着火箭升空后留下的心里空白 —— 这里才是家啊！\n沙盒、模拟、生存、经营、人事管理、建筑规划、工作安排、战斗策略。。。这还是游戏嘛，这他妈就是男人的浪漫啊！\nFactorio 异星工厂 Factorio\n这是我玩过的时间第二长的单机游戏，即便不打 Mod，游戏本身的可玩性就高到不知哪里去了。\n游戏的核心是在异星建造一个完备的自动化工厂，同时抵御虫族的入侵，最后造个火箭发射回家，和 RimWorld 的最终目的一样。\n在这款游戏里你将通过传送带、机械臂组建你自己的工厂，不断的扩充、优化、整改、升级你的生产线。不知道其他人从这款游戏里体会到了什么，我发现了很多类编程的思想，不断的迭代又不断的重构，多个小组件的封装与调用就像模块一样，最初构造的时候就要留好日后扩展的余地，时不时产生的 Bug。。。\n最初的通关，我用面向对象与模块化的方式将所有问题简化：一条总线管运输，一排一种组件模块留好扩展空间，对采矿、发电、运输、每个组件的生产、每个科技瓶的生产、科技瓶的消耗进行分隔，一个一个的设计、量化、扩充，终于把火箭给发射了。\n除此之外在 B 站、油管有各种设计大师，自由度极高，玩家可发挥的空间太大了，有时只优化几条产品线天就亮了，增加一个矿区刚铺好火车站天就黑了，如果戒毒所能引进这款游戏，谁他妈的还吸毒呢？\nSlay the Spire 杀戮尖塔 Slay the Spire\n卡牌+Roguelike 的典范！至今没找到第二款能超越它的。\n无尽模式真是无脑杀时间，The Hermit 是我装过的最好的 Mod，百玩不腻。\nHades 哈迪斯 Hades\n动作类 Roguelike，画风和动作做得非常到位。\n相比《杀戮尖塔》，《哈迪斯》多了冲塔前后的一些元素，多了剧情。\n玩到 50 小时差不多才审美疲劳，不过这 50 小时感觉非常棒。\nIn the name of Hades! Olympus! I accept this message.\nShadow Tactics: Blades of the Shogun 影子战术：将军之刃 Shadow Tactics: Blades of the Shogun\n稀缺的即时战术类游戏，出就买系列，太好玩了，我要屠城。\nDesperados III 赏金奇兵 Ⅲ Desperados III\n《影子战术》的续作。\n稀缺的即时战术类游戏，出就买系列，太好玩了，我要屠城。\nDome Keeper 穹顶守护者 Dome Keeper\n挖矿、升级、战斗。\n开发已经尽可能地让这个游戏变得耐玩了，但还是不太耐玩（也至少能玩个几十小时），建议打折入。\nSid Meier\u0026rsquo;s Civilization VI 文明 6 Sid Meier\u0026rsquo;s Civilization VI\n下一回合就睡觉。。。\n无需多介绍，在 MBP 上稍卡，我一般都是用战略视图游玩的。\nGorogoa Gorogoa\n一款独具特色的解谜游戏，全手绘画风，隐含了一个追逐梦想的故事。\n精美的像艺术品，强烈推荐，玩法独一无二、新鲜有趣，这真的是艺术品。\nLife is Strange 奇异人生 Life is Strange\n互动性+剧情选择向的电影游戏，剧情方面好评如潮，整部下来大约是 10 小时。\n汉化包建议搜索「奇异人生 虎头汉化」，支持 Win/Mac。\nTo the Moon 去月球 To the Moon\n自由鸟出品，感人的故事，约 5 小时通关。\n这应该是目前看来自由鸟最好的一个作品了。\n“还有吗？”\n“还有吗？”\n“还有吗？”\n。。。\n“在那儿，对吗？？有两只耳朵和头！” ——这或许是 River 最想听到的回答。\nFinding Paradise 寻找天堂 Finding Paradise\n自由鸟出品，感人的故事，约 5 小时通关，主题曲很好听：Wish My Life Away\nImpostor Factory Impostor Factory\n自由鸟出品，感人的故事，约 3.5 小时通关。\nKingdom Rush 全系列 如果不刷星，这真是目前世界上最好玩的 TD 了。\n如果刷星，不久便会产生疲惫感，因为重复带来枯燥，枯燥导致无聊。\nFirewatch 看火人 Firewatch\n说是冒险游戏，不如说是 ASMR 游戏或看风景游戏。很喜欢小姐姐的声音，中期的剧情还会让人浮想联翩。。。\n是那种闲暇的一天，泡一杯咖啡，关掉手机，静静的欣赏与探索的好游戏。\nPlague Inc: Evolved 瘟疫公司 Plague Inc: Evolved\nWin/Mac 版非常良心，没有手机上那么多收费项目，还支持 Mod。\nCities: Skylines 城市：天际线 Cities: Skylines\n好玩自然不用多说，但是 MBP 运行起来过于卡顿。。。\nSpiritfarer 灵魂旅者 Spiritfarer\n喜怒哀乐、生老病死、悲欢离合。\n总游戏时间 30 小时左右。\n游戏主题不错，但是有太多繁琐、重复的小作业。\n如果能压缩到 10 小时以内，这是个满分游戏，由于这些琐碎消耗了我太多精力，我只能给 6/10 分。\n超 · 友情提示！！！\n你可以不对任何人和动物进行喂食，他们不会死，也不会跑，不会有任何问题 菜园、田地不用浇水，一样会生长，只是慢些 最后有一个圣坛是强化钓鱼和挖矿 强化钓鱼后再去找金枪鱼更节省时间 强化挖矿后，注意每个石头对应额外的宝物，比如挖煤必出一个钻石（对于最后的差事有很大帮助） Stardew Valley 星露谷物语 Stardew Valley\n好评如潮的佛系养生类休闲爆肝游戏。\nRise of the Tomb Raider 古墓丽影：崛起 Rise of the Tomb Raider\nMBP 完全带得动，而且还支持了 MBP 的 Touch Bar。\n第一次玩古墓丽影系列，如果去掉捡垃圾这种操作，这个游戏还真是挺好玩的。\nBeholder 旁观者 Beholder\n一个「1984」式的反乌托邦设定，创意很特别，主要玩法在于道德选择。\nOpus Magnum Opus Magnum\n非常奇妙的模拟、编程、设计、自动化、解密类游戏。\n喜欢编程或动脑的可以试试，每个关卡都存在最快解法、最省解法，很考验大脑。\n还特别适合中小学生游玩，锻炼思维罗辑。\n但对 Mac 的分辨率支持不是很好，不过问题不大。\nVampire Survivors 吸血鬼幸存者 Vampire Survivors\n一款 Roguelike 弹幕射击生存游戏，有很多抄袭作品，原版这个可以说是大道至简（画面）了。\n内容很丰富，游戏时间很长。\nGame Dev Tycoon 游戏开发大亨 Game Dev Tycoon\n玩过开罗的《游戏发展国》的玩家肯定会找回那份惊喜。这么多年游戏开发类游戏一直比较冷清，没有几个好玩的，难得有一个还不错的。\nMini Metro \u0026amp; Mini Motorways 迷你地铁 \u0026amp; 迷你公路 Mini Metro \u0026amp; Mini Motorways\n休闲模拟小游戏，但说实话我觉得可改进空间非常大，目前的流程设计非常低级。\nTwo Point Hospital 双点医院 Two Point Hospital\n首发之后 Bug 很多，管理方式糟糕，人物AI智障。\n这都不耽误我打通45星，当我最终要在最后一关铺设一间大医院的时候，没有「房间模板」或「复制房间」这个功能，让我崩溃了。\n当我得知官方修复大量 Bug、更新中文语音、提供了复制房间功能时，我已经玩腻了。\n现在玩的话还是比较合适的，游戏已经比较完善了。\nKatana ZERO Katana ZERO\n横版过关动作类游戏，6 小时通关，打击感不错，而且不算太难，画风、故事、战斗系统都挺不错的，剧情也不算太长，值得一玩。\nTownscaper 城镇叠叠乐 Townscaper\n解压、休闲的建造游戏，我外甥很喜欢玩。\nDoom \u0026amp; Destiny Doom \u0026amp; Destiny\n恶搞也很正经的 D\u0026amp;D，独立开发的日式 RPG 回合制游戏，对白喜剧向，\nMirror Mirror\n很好的国产小黄油，去掉黄色部分也可以玩一玩的。\nICEY 艾希 ICEY\n国产的动作游戏，做得还不错，7 小时左右通关，最有特点的要属其一直在吐槽的旁白。\nCandleman: The Complete Journey 蜡烛人 Candleman: The Complete Journey\n感人又温馨的冒险小故事。\nMindustry Mindustry\n有一点《异星工厂》的影子，也是很杀时间，喜欢的话可能会很入迷。\nShapez 异形工厂 Shapez\n《异星工厂》的简化版，看译名就能看出一些。。。\n没有电力系统，不用费力找矿，矿产不会枯竭，上来就是传送带噼里啪啦地干。\n但我还是觉得《异星工厂》更好玩。\nCrashlands 崩溃大陆 Crashlands\n类似《饥荒》风格的 ARPG，本地化包括宣传片很地道，对白喜剧向的。\nIron Snout Iron Snout\n一款挺魔性的 2D 原地格斗类免费小游戏，第一次下载就玩了 4 个小时。\nQuest Hunter Quest Hunter\n即时战斗的 RPG，没有玩下去，Mac 带不动，比较吃力。\nRefunct Refunct\n休闲放松的禅游戏，佛。\nUnheard 疑案追声 Unheard\n玩法比较新颖，但其实在游戏性上没有难度，只要全听一遍就行了，是那种上帝视觉自己摸索出剧情的感觉。最后的结局倒是没想到，有种《禁闭岛》的感觉。\nA Monster\u0026rsquo;s Expedition 怪兽远征 A Monster\u0026rsquo;s Expedition\n类似推箱子的解密冒险类小游戏。\nOxygen Not Included 缺氧 Oxygen Not Included\n殖民模拟+基地建设，很杀时间的游戏，但我看着满屏的按钮，没有一个舒适的新引导真的不想玩下去。\n不过玩进去的话，好评如潮，应该是很不错的，不知道现在有没有更新新手引导。\nStoryteller Storyteller\n利用不同场景+不同人物编 X 格漫画的小游戏。很有新鲜感，不过游戏时间太短了。\nChrono Trigger 时空之轮/时空之钥/超时空之钥 Chrono Trigger\n御剑乘风来，除魔天地间。\n能在虚拟机里流畅运行，参考攻略(备份)。\n中文名《时空之轮》应该是港台名《超時空之鑰》的错误翻译。\n打通之后才发现竟然是将近三十年的老游戏了，这应该是那个时代的神了。\n友情提示：“龙之领域”的额外任务没有任何意义，不用拿这一系列的装备也可以轻松通关，“龙之领域”系列任务要在两个时间线之间跑断腿，比魔兽世界外域任务还恶心。（因为右下角的山需要手动上山，再手动下山，来回无数趟。）\nTerraria 泰拉瑞亚 Terraria\n好评如潮的游戏，花时间入门后，应该能找到很大的乐趣，我还没有入门。\nInscryption 邪恶冥刻 Inscryption\n恐怖画风的卡牌对战游戏，各个元素做得都比较丰富。\nShogun Showdown 将军对决 Shogun Showdown\n很有创意的忍者题材像素风 rouge 回合制小游戏。\n玩法新颖，按照敌人的血量和动机，每次使用不同的技能搭配和走位来过关。\n设计得也非常好，不同的组合都有一战之力。\nPatrick\u0026rsquo;s Parabox Patrick\u0026rsquo;s Parabox\n加入了很多创新元素的推箱子。\n感觉一般 Stacklands Stacklands\n将生存建造简化为卡牌，不断地合成、发展、升级、战斗。\n建议打折入，通关一次后着实不想打开第二次。\nSoulstone Survivors 灵魂石幸存者 类似吸血鬼幸存者和土豆兄弟，但也就刚玩的时候爽一点，尝试技能搭配后，马上就变成重复的劳动作业，需要毫无乐趣地刷刷刷然后解锁东西和升科技。\n最后技能范围很大，已经眼花缭乱了，关闭特效，变成一个躲红圈的游戏，几个小时的游戏时间就腻了。\nWildermyth 漫野奇谭 Wildermyth\n好评如潮的策略 RPG 游戏，但我觉得有些无聊，玩不下去。\nHome Behind 归家异途 Home Behind\n轻度 Roguelike 横版冒险游戏。\n但设计方面有些诡异，我真就是一直在考虑丢什么东西，背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。背包超重了。。。\nPyre Pyre\n画风很棒的角色扮演游戏，但要是没有这个无聊3V3模式（其实就是一个套路虐杀电脑），我没准还能玩下去。\nCat Quest 猫咪斗恶龙 Cat Quest\n画风可爱，支持手柄的动作 RPG，但是整个游戏的玩法比较单一，走任务，下洞穴，打怪兽，无限重复。\nCircle Empires 环形帝国 Circle Empires\n休闲策略小游戏，建议打折入，生命力并不是很持久，很快就腻了。\nGlass Masquerade Glass Masquerade\n无聊的拼图游戏，却做的很认真。适合修身养性，闲来无事的时候可以搞一把，建议打折入。\nGoat Simulator 山羊模拟器 Goat Simulator\n并无什么可取之处，休闲娱乐解压的游戏。\nLost Castle 失落城堡 Lost Castle\nRoguelike 类的动作冒险类游戏，给朋友买了一份一起联机玩的，但个人感觉一般，和朋友都没啥兴趣。\nLove Esquire 小兵求爱记 Love Esquire\n恋爱养成类小游戏，配音和立绘都不错，就是比较无聊。\nMeteor 60 Seconds! 地球灭亡前60秒 Meteor 60 Seconds!\n没啥意义的免费游戏，图个乐。\nKingdom Two Crowns 王国：两位君主 Kingdom Two Crowns\n建造、生产、防御、进攻。\n其实更适合双人游戏，我一个人双线操作的，找不到多大乐趣。\n初始的 1~5 岛挺没劲的，重复操作，跑断腿，后面的我也没玩，太杀时间了，还没怎么样呢，天亮了。\nFTL: Faster Than Light FTL: Faster Than Light\n类似《杀戮尖塔》的爬塔，只不过改成了星际。\n非简单难度过于困难，Rogue 元素太看脸，玩了几天再也没打开，最主要的是我没有找到乐趣。\n不推荐 Hacknet Hacknet\n模拟黑客的小游戏，Mac 上全屏有卡死的 Bug。\nMount \u0026amp; Blade: Warband 骑马与砍杀 Mount \u0026amp; Blade: Warband\n是个口碑很好的老游戏，但没有修复 Mac 版的闪退问题，不建议购买。\nHyper Knights Hyper Knights\n策略 + 动作的攻城略地游戏，但新鲜感很快就会过去，最后既不「策略」，也玩腻了「杀人」。\nProject Highrise Project Highrise\n模拟经营游戏，看着感觉还行，但其实在数值上没有下工夫，很多设定都做得不合理，做得很糟糕。\nStartup Company Startup Company\n我还预购了这款游戏，但其实做得很一般。\n游戏需要雇佣员工开发15种【组件】。 再雇佣另一个工种将15种【组件】升级为不同的17种【模块】 以【模块】为原材料，可以研发不同的4种【产品】。 以【模块】为原材料，升级自己的【产品】。 以上，操作流程极其简单、无聊、繁琐、重复。\nSuper Star Super Star\n又一个国产小黄油，但玩法单一无聊。\nWILL: A Wonderful World WILL：美好世界 WILL: A Wonderful World\n文字类游戏，但剧本真的是太差了。\n剧情那叫个幼稚无聊。。。\n改变剧情全靠主观臆测，毫无逻辑性，作为一个改变剧情的游戏，是最大的失败。\n游戏性无限接近于零。\nMahjongSoul 雀魂 MahjongSoul\n再玩雀魂我是傻逼。\nWorldBox - God Simulator 上帝模拟器 WorldBox - God Simulator\n上帝模拟器，看小人生，看小人打，看小人死。。。\n第一次玩很新鲜，一口气干了 4 个小时，但我没打开第二次，还在 early access，价格也偏高。\nRichMan 10 大富翁 10 RichMan 10\n爱之深则恨之切，小时候很喜欢的游戏，现在却这副模样。\n一家老牌游戏公司，一款 30 周年续作，能做出个这么个东西。\n实际体验，这是一个赶工的粗糙作品，Bug 一堆。\n姚仙居然还是监制。\n在仙剑七进入最终开发阶段出了一个大富翁 10，这是在给仙剑七筹（骗）钱。\n优秀黄油 能在虚拟机里流畅运行。\n夏日狂想曲 。。。\n魔法少女天穹法妮雅 しもばしら工房出品，黄油天花板，天花板中板。。。\n仙肴圣餐 しもばしら工房的早期作品。\nエニシアと契約紋 ～馬蹄通りの小聖女～ しもばしら工房最新作品，暂时还没有上架 Steam。\n","permalink":"https://dvel.me/posts/steam-for-mac-game-recommend/","summary":"\u003cp\u003e由于长期在使用 MBP，但还是想打打游戏，这里推荐一些我玩过的，MBP 能带得动的游戏。\u003c/p\u003e\n\u003cp\u003e我用的是 Intel MBP 带独显的高配，目前看来 M1 基本都可以胜任，如果兼容的话。\u003c/p\u003e\n\u003ch2 id=\"倾情推荐\"\u003e倾情推荐\u003c/h2\u003e\n\u003ch3 id=\"portal--portal-2-传送门\"\u003ePortal \u0026amp; Portal 2 传送门\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://store.steampowered.com/app/400/Portal/\" target=\"_blank\" rel=\"noopener\"\u003ePortal\u003c/a\u003e \u0026amp; \u003ca href=\"https://store.steampowered.com/app/620/Portal_2/\" target=\"_blank\" rel=\"noopener\"\u003ePortal 2\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e世界第一，目前最好玩的游戏，哪怕过了这么多年。\u003c/p\u003e\n\u003cp\u003e在 2 通关后，建议进行双人联机，联机模式还有一整套关卡，当然也有社区作品。\u003c/p\u003e\n\u003ch3 id=\"rimworld-边缘世界\"\u003eRimWorld 边缘世界\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://store.steampowered.com/app/294100/RimWorld/\" target=\"_blank\" rel=\"noopener\"\u003eRimWorld\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e从 A15 玩到 1.0，感谢伟大的作者，也感谢各个 Mod 的贡献者。\u003c/p\u003e\n\u003cp\u003e这是我玩过的时间最长的单机游戏了，评论区时间过千的比比皆是，时间过百的熙熙攘攘。\u003c/p\u003e\n\u003cp\u003e这也是我第一款安装过 100 多个 Mod 的游戏，真乃是装 Mod 一时爽，一直装一直爽。每天早上听到「Waiting for the sun」的闹铃，我都会回想起那里的春夏秋冬，伴随着火箭升空后留下的心里空白 —— 这里才是家啊！\u003c/p\u003e\n\u003cp\u003e沙盒、模拟、生存、经营、人事管理、建筑规划、工作安排、战斗策略。。。这还是游戏嘛，这他妈就是男人的浪漫啊！\u003c/p\u003e\n\u003ch3 id=\"factorio-异星工厂\"\u003eFactorio 异星工厂\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://store.steampowered.com/app/427520/Factorio/\" target=\"_blank\" rel=\"noopener\"\u003eFactorio\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这是我玩过的时间第二长的单机游戏，即便不打 Mod，游戏本身的可玩性就高到不知哪里去了。\u003c/p\u003e\n\u003cp\u003e游戏的核心是在异星建造一个完备的自动化工厂，同时抵御虫族的入侵，最后造个火箭发射回家，和 RimWorld 的最终目的一样。\u003c/p\u003e\n\u003cp\u003e在这款游戏里你将通过传送带、机械臂组建你自己的工厂，不断的扩充、优化、整改、升级你的生产线。不知道其他人从这款游戏里体会到了什么，我发现了很多类编程的思想，不断的迭代又不断的重构，多个小组件的封装与调用就像模块一样，最初构造的时候就要留好日后扩展的余地，时不时产生的 Bug。。。\u003c/p\u003e\n\u003cp\u003e最初的通关，我用面向对象与模块化的方式将所有问题简化：一条总线管运输，一排一种组件模块留好扩展空间，对采矿、发电、运输、每个组件的生产、每个科技瓶的生产、科技瓶的消耗进行分隔，一个一个的设计、量化、扩充，终于把火箭给发射了。\u003c/p\u003e\n\u003cp\u003e除此之外在 B 站、油管有各种设计大师，自由度极高，玩家可发挥的空间太大了，有时只优化几条产品线天就亮了，增加一个矿区刚铺好火车站天就黑了，如果戒毒所能引进这款游戏，谁他妈的还吸毒呢？\u003c/p\u003e\n\u003ch3 id=\"slay-the-spire-杀戮尖塔\"\u003eSlay the Spire 杀戮尖塔\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://store.steampowered.com/app/646570/Slay_the_Spire/\" target=\"_blank\" rel=\"noopener\"\u003eSlay the Spire\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e卡牌+Roguelike 的典范！至今没找到第二款能超越它的。\u003c/p\u003e\n\u003cp\u003e无尽模式真是无脑杀时间，\u003ca href=\"https://steamcommunity.com/sharedfiles/filedetails/?id=2137404781\u0026amp;searchtext=\" target=\"_blank\" rel=\"noopener\"\u003eThe Hermit\u003c/a\u003e 是我装过的最好的 Mod，百玩不腻。\u003c/p\u003e","title":"Steam for Mac 中文游戏推荐"},{"content":" 又双叒叕 Mac 换新，之前的一堆软件、服务弄得太乱，迫于洁癖没用时光机恢复，这里记录一下 macOS 下我常用的软件/工具列表，算是个推荐清单，也便于自己以后查阅。\n新机快速还原使用体验 Mimestream 一个 Gmail API 的邮箱客户端 Bitwarden 密码管理器，确实没有 1Password 体验好，但一年才十刀 Surge 科学上网 Dropbox 同步了大部分的软件配置及重要备份 Alfred macOS 第一效率工具 QSpace Finder 增强 Rime 输入法 效率 Fantastical 日历 Things GTD iMazing iPhone 备份 iStat Menus 菜单栏状态监控 Keka 解压缩 Magnet 窗口管理 Bartender 4 菜单栏管理 CleanShot X 截图 Karabiner 键位映射神器 编程 JetBrains 全家桶 VSCode Fork Git GUI iTerm 2 终端 Paw API 工具 SnippetsLab 代码片段管理 日常 IINA 播放器 Spotify \u0026amp; LyricsX 音乐 Typora Markdown 编辑器 NetNewsWire RSS 订阅 PDF Expert PDF 编辑器 PictureView 大量图片浏览 qBittorrent 或 qBittorrent Enhanced Edition 下载 AppCleaner 卸载工具 RustDesk 远程控制 翻译/字典 欧路词典 查单词 GoldenDict 支持 mdx 格式的免费字典 Bob 句子翻译（搭配插件 roojay520/bobplugin-google-translate） 免费开源的平替：Easydict 小工具 Amphetamine 防止自动熄屏 Balance Lock 锁定声道平衡，防止祖传 bug OmniDiskSweeper 小巧的查找大文件工具 Timer 简易计时器 Turbo Boost Switcher 关闭 Intel CPU 的 Turbo Boost 功能 字体 Hack 代码和终端都用它，这字体看着太舒服了 ","permalink":"https://dvel.me/posts/my-mac-software-list/","summary":"\u003cblockquote\u003e\n\u003cp\u003e又双叒叕 Mac 换新，之前的一堆软件、服务弄得太乱，迫于洁癖没用时光机恢复，这里记录一下 macOS 下我常用的软件/工具列表，算是个推荐清单，也便于自己以后查阅。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"新机快速还原使用体验\"\u003e新机快速还原使用体验\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://mimestream.com/\" target=\"_blank\" rel=\"noopener\"\u003eMimestream\u003c/a\u003e 一个 Gmail API 的邮箱客户端\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://bitwarden.com/\" target=\"_blank\" rel=\"noopener\"\u003eBitwarden\u003c/a\u003e 密码管理器，确实没有 1Password 体验好，但一年才十刀\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://nssurge.com/\" target=\"_blank\" rel=\"noopener\"\u003eSurge\u003c/a\u003e 科学上网\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.dropbox.com/\" target=\"_blank\" rel=\"noopener\"\u003eDropbox\u003c/a\u003e 同步了大部分的软件配置及重要备份\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.alfredapp.com/\" target=\"_blank\" rel=\"noopener\"\u003eAlfred\u003c/a\u003e macOS 第一效率工具\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://qspace.awehunt.com/zh-cn/index.html\" target=\"_blank\" rel=\"noopener\"\u003eQSpace\u003c/a\u003e Finder 增强\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://rime.im/\" target=\"_blank\" rel=\"noopener\"\u003eRime\u003c/a\u003e 输入法\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"效率\"\u003e效率\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://flexibits.com/fantastical\" target=\"_blank\" rel=\"noopener\"\u003eFantastical\u003c/a\u003e 日历\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://culturedcode.com/things/\" target=\"_blank\" rel=\"noopener\"\u003eThings\u003c/a\u003e GTD\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://imazing.com/\" target=\"_blank\" rel=\"noopener\"\u003eiMazing\u003c/a\u003e iPhone 备份\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://bjango.com/mac/istatmenus/\" target=\"_blank\" rel=\"noopener\"\u003eiStat Menus\u003c/a\u003e 菜单栏状态监控\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/aonez/Keka\" target=\"_blank\" rel=\"noopener\"\u003eKeka\u003c/a\u003e 解压缩\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://magnet.crowdcafe.com/\" target=\"_blank\" rel=\"noopener\"\u003eMagnet\u003c/a\u003e 窗口管理\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.macbartender.com/Bartender4/\" target=\"_blank\" rel=\"noopener\"\u003eBartender 4\u003c/a\u003e 菜单栏管理\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://cleanshot.com/\" target=\"_blank\" rel=\"noopener\"\u003eCleanShot X\u003c/a\u003e 截图\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://karabiner-elements.pqrs.org/\" target=\"_blank\" rel=\"noopener\"\u003eKarabiner\u003c/a\u003e 键位映射神器\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"编程\"\u003e编程\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.jetbrains.com/\" target=\"_blank\" rel=\"noopener\"\u003eJetBrains 全家桶\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://code.visualstudio.com/\" target=\"_blank\" rel=\"noopener\"\u003eVSCode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://git-fork.com/\" target=\"_blank\" rel=\"noopener\"\u003eFork\u003c/a\u003e Git GUI\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://iterm2.com/\" target=\"_blank\" rel=\"noopener\"\u003eiTerm 2\u003c/a\u003e 终端\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://paw.cloud/\" target=\"_blank\" rel=\"noopener\"\u003ePaw\u003c/a\u003e API 工具\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.renfei.org/snippets-lab/\" target=\"_blank\" rel=\"noopener\"\u003eSnippetsLab\u003c/a\u003e 代码片段管理\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"日常\"\u003e日常\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://iina.io/\" target=\"_blank\" rel=\"noopener\"\u003eIINA\u003c/a\u003e 播放器\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.spotify.com/\" target=\"_blank\" rel=\"noopener\"\u003eSpotify\u003c/a\u003e \u0026amp; \u003ca href=\"https://github.com/ddddxxx/LyricsX\" target=\"_blank\" rel=\"noopener\"\u003eLyricsX\u003c/a\u003e 音乐\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://typora.io/\" target=\"_blank\" rel=\"noopener\"\u003eTypora\u003c/a\u003e Markdown 编辑器\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://netnewswire.com/\" target=\"_blank\" rel=\"noopener\"\u003eNetNewsWire\u003c/a\u003e RSS 订阅\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://pdfexpert.com/\" target=\"_blank\" rel=\"noopener\"\u003ePDF Expert\u003c/a\u003e PDF 编辑器\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://wl879.github.io/apps/picview/\" target=\"_blank\" rel=\"noopener\"\u003ePictureView\u003c/a\u003e 大量图片浏览\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.qbittorrent.org/\" target=\"_blank\" rel=\"noopener\"\u003eqBittorrent\u003c/a\u003e 或 \u003ca href=\"https://github.com/c0re100/qBittorrent-Enhanced-Edition\" target=\"_blank\" rel=\"noopener\"\u003eqBittorrent Enhanced Edition\u003c/a\u003e 下载\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://freemacsoft.net/appcleaner/\" target=\"_blank\" rel=\"noopener\"\u003eAppCleaner\u003c/a\u003e 卸载工具\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://rustdesk.com/\" target=\"_blank\" rel=\"noopener\"\u003eRustDesk\u003c/a\u003e 远程控制\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"翻译字典\"\u003e翻译/字典\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.eudic.net/\" target=\"_blank\" rel=\"noopener\"\u003e欧路词典\u003c/a\u003e 查单词\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://goldendict.org/\" target=\"_blank\" rel=\"noopener\"\u003eGoldenDict\u003c/a\u003e 支持 mdx 格式的免费字典\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ripperhe/Bob\" target=\"_blank\" rel=\"noopener\"\u003eBob\u003c/a\u003e 句子翻译（搭配插件 \u003ca href=\"https://github.com/roojay520\" target=\"_blank\" rel=\"noopener\"\u003eroojay520\u003c/a\u003e/\u003cstrong\u003e\u003ca href=\"https://github.com/roojay520/bobplugin-google-translate\" target=\"_blank\" rel=\"noopener\"\u003ebobplugin-google-translate\u003c/a\u003e\u003c/strong\u003e）\n\u003cul\u003e\n\u003cli\u003e免费开源的平替：\u003ca href=\"https://github.com/tisfeng/Easydict\" target=\"_blank\" rel=\"noopener\"\u003eEasydict\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"小工具\"\u003e小工具\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://apps.apple.com/us/app/amphetamine/id937984704\" target=\"_blank\" rel=\"noopener\"\u003eAmphetamine\u003c/a\u003e 防止自动熄屏\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://apps.apple.com/us/app/balance-lock/id1019371109\" target=\"_blank\" rel=\"noopener\"\u003eBalance Lock\u003c/a\u003e 锁定声道平衡，防止祖传 bug\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.omnigroup.com/more\" target=\"_blank\" rel=\"noopener\"\u003eOmniDiskSweeper\u003c/a\u003e 小巧的查找大文件工具\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/michaelvillar/timer-app\" target=\"_blank\" rel=\"noopener\"\u003eTimer\u003c/a\u003e 简易计时器\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://tbswitcher.rugarciap.com/\" target=\"_blank\" rel=\"noopener\"\u003eTurbo Boost Switcher\u003c/a\u003e 关闭 Intel CPU 的 Turbo Boost 功能\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"字体\"\u003e字体\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://sourcefoundry.org/hack/\" target=\"_blank\" rel=\"noopener\"\u003eHack\u003c/a\u003e 代码和终端都用它，这字体看着太舒服了\u003c/li\u003e\n\u003c/ul\u003e","title":"我的 Mac 软件/工具列表"},{"content":"《Flask Web 开发》第二版\n豆瓣地址：https://book.douban.com/subject/30293851/\n第 1 章 - 安装 Flask 哲学 Flask 自开发伊始就被设计为可扩展的框架，它具有一个包含基本服务的强健核心，其他功能则可通过扩展实现。\nFlask 有 3 个主要依赖：\n路由、调试和 Web 服务器网关接口（WSGI，Web server gateway interface）子系统由 Werkzeug 提供； 模板系统由 Jinja2 提供； 命令行集成由 Click 提供。 开发者可以任意挑选符合项目需求的扩展，甚至可以自行开发。这和大型框架的做法相反，大型框架往往已经替你做出了大多数决定，难以（有时甚至不允许）使用替代方案。\nvenv 在 Python 3 中由标准库 venv 创建虚拟环境：\n$ python3 -m venv virtual-environment-name 激活虚拟环境：\n$ source venv/bin/activate 取消：\n$ deactivate 另一种使用虚拟环境的方法：\n在终端中执行 $ venv/bin/python 直接激活虚拟环境中的交互模式，退出时直接按下 ctrl + D。\n第 2 章 - 应用的基本结构 初始化 所有 Flask 应用都必须创建一个应用实例，通常由下述代码创建：\nfrom flask import Flask app = Flask(__name__) Web 服务器使用 WSGI 协议，把接受自客户端的所有请求转发给这个对象处理。\n路由和视图函数 客户端(浏览器)把请求发送给 Web 服务器，Web 服务器再把请求发送给 Flask 应用实例。\n应用实例需要知道对每个 URL 的请求要运行哪些代码，所有保存了一个 URL 到 Python 函数的映射关系。\n处理 URL 和函数之间关系的程序称为路由。\nFlask 使用 app.route 装饰器或者更传统的 app.add_url_rule() 方法构建映射：\n@app.route(\u0026#39;/user/\u0026lt;name\u0026gt;\u0026#39;) def user(name): return \u0026#39;\u0026lt;h1\u0026gt;Hello {}!\u0026lt;/h1\u0026gt;\u0026#39;.format(name) def index(): return \u0026#39;\u0026lt;h1\u0026gt;Hello World!\u0026lt;/h1\u0026gt;\u0026#39; app.add_url_rule(\u0026#39;/\u0026#39;, \u0026#39;index\u0026#39;, index) index() 这样处理入站请求的函数称为视图函数。\n一个完整的应用 from flask import Flask app = Flask(__name__) @app.route(\u0026#39;/) def index(): return \u0026#39;\u0026lt;h1\u0026gt;Hello World!\u0026lt;/h1\u0026gt;\u0026#39; Web 开发服务器 Flask 自带 Web 开发服务器，通过 flask run 命令启动。这个命令在 FLASK_APP 环境变量指定的 Python 脚本中寻找应用实例。\n$ export FLASK_APP=hello.py $ flask run 动态路由 @app.route(\u0026#39;/user/\u0026lt;name\u0026gt;\u0026#39;) def user(name): return f\u0026#39;\u0026lt;h1\u0026gt;Hello, {name}!\u0026lt;/h1\u0026gt;\u0026#39; 调试模式 Flask 应用可以在调试模式中运行，在调试模式下，开发服务器会默认加载重载器和调试器。\n**重载器：**Flask 会监视项目中的所有源码文件，发现变动时自动重启服务器。\n**调试器：**调试器是一个基于 Web 的工具，当应用抛出未处理的异常时，它会出现在浏览器中。\n$ export FLASK_APP=hello.py $ export FLASK_DEBUG=1 $ export FLASK_ENV=development (效果同上) $ flask run 命令行选项 flask shell 命令在应用上下文中打开一个 Python shell 会话，可以运行维护任务、测试、调试问题。\n请求-响应循环 上下文 为了避免大量可有可无的参数把视图函数弄得一团糟，Flask 使用上下文临时把某些对象变为全局可访问。在多线程服务器中，Flask 使用上下文让特点的变量在一个线程中全局可访问，与此同时不会干扰其他线程。\n变量名 上下文 说明 current_app 应用上下文 当前应用的应用实例 g 应用上下文 处理请求时用作临时存储的对象，每次请求都会重设这个变量 request 请求上下文 请求对象，封装了客户端发出的 HTTP 请求中的内容 session 请求上下文 用户会话，值为一个字典，存储请求之间需要『记住』的值 Flask 请求对象 (request) 属性或方法 说明 form 一个字典，存储请求提交的所有表单字段 args 一个字典，存储通过 URL 查询字符串传递的所有参数 values 一个字典，form 和 args 的合集 cookies 一个字典，存储请求的所有 cookies headers 一个字典，存储请求的所有 HTTP 首部 files 一个字典，存储请求上传的所有文件 get_data() 返回请求主体缓冲的数据 get_json() 返回一个 Python 字典，包含解析请求主体后得到的 JSON blueprint 处理请求的 Flask 蓝本的名称；蓝本在第 7 章介绍 endpoint 处理请求的 Flask 端点的名称；Flask 把视图函数的名称用作路由端点的名称 scheme URL 方案（http 或 https） is_secure() 通过安全的连接（HTTPS）发送请求时返回 True host 请求定义的主机名，如果客户端定义了端口号，还包括端口号 path URL 的路径部分 query_string URL 的查询字符串部分，返回原始二进制值 full_path URL 的路径和查询字符串部分 url 客户端请求的完整 URL base_url 同 url，但没有查询字符串部分 remote_addr 客户端的 IP 地址 environ 请求的原始 WSGI 环境字典 请求钩子 有时在处理请求之前或之后执行代码会很有用，但为了避免每个视图函数中都重复编写代码，Flask 提供了注册通用函数的功能，通过装饰器实现。\n装饰器 说明 before_request 注册一个函数，在每次请求之前运行。 before_first_request 注册一个函数，只在处理第一个请求之前运行。可以通过这个钩子添加服务器初始化任务。 after_request 注册一个函数，如果没有未处理的异常抛出，在每次请求之后运行。 teardown_request 注册一个函数，即使有未处理的异常抛出，也在每次请求之后运行。 在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 g。\n响应 如果视图函数返回的响应需要使用不同的状态码，可以把数字代码作为第二个返回值。\nFlask 视图函数还可以返回一个响应对象——make_response()。\n重定向，由于使用频繁，Flask 提供了 redirect() 辅助函数。\n第 3 章 - 模板 Jinja2 模板引擎 渲染模板\nFlask 提供的 render_template() 函数把 Jinja2 模板引擎集成到了应用中。\n变量\n模板中使用 {{ name }} 结构表示一个变量，支持复杂类型如列表、字典、对象。\n支持过滤器：{{ name|capitalize }}。\n支持结构控制、宏（类似函数）。\n支持模板继承：{% extends \u0026quot;bootstrap/base.html\u0026quot; %} 及 {{ super() }}。\n初始化扩展 bootstrap = Bootstrap(app) # 第 7 章中大型应用初始化扩展的方式： bootstrap = Bootstrap() def create_app(config_name): # ... bootstrap.init_app(app) # ... 自定义错误页面 使用 @app.errorhandler(404) 装饰器。\n链接 url_for() 辅助函数帮助在模板中构建正确的 URL。\n用法：\n# 以视图函数名作为参数，以 app.add_url_route() 定义路由时，使用端点名 url_for(\u0026#39;index\u0026#39;) # / # 绝对地址 url_for(\u0026#39;index\u0026#39;, _external=True) # http://localhost:5000/ # 动态 URL url_for(\u0026#39;user\u0026#39;, name=\u0026#39;john\u0026#39;, page=2, version=1) # /user/john?page=2\u0026amp;version=1 第 4 章 - Web 表单 表单 使用 Flask-WTF 定义表单：\nfrom flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired class NameForm(FlaskForm): name = StringField(\u0026#39;What is your name?\u0026#39;, validators=[DataRequired()]) submit = SubmitField(\u0026#39;Submit\u0026#39;) 使用 Flask-Bootstrap 提供的高层级辅助函数 quick_form() 渲染 Flask-WTF 表单：\n{% import \u0026#34;bootstrap/wtf.html\u0026#34; as wtf %} {{ wtf.quick_form(form) }} 在视图函数中处理表单：\n@app.route(\u0026#39;/\u0026#39;, methods=[\u0026#39;GET\u0026#39;, \u0026#39;POST\u0026#39;]) def index(): name = None form = NameForm() if form.validate_on_submit(): name = form.name.data form.name.data = \u0026#39;\u0026#39; return render_template(\u0026#39;index.html\u0026#39;, form=form, name=name) Post / Redirect / Get 模式 Post / Redirect / Get 简称 PRG，是一种用来防止表单重复提交数据的一种 Web 设计模式。\n​\n闪现消息 flaks.flash 的简单使用。\n第 5 章 数据库 Flask-SQLAlchemy 简单配置 SQLite 数据库 import os from flask_sqlalchemy import SQLAlchemy basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config[\u0026#39;SQLALCHEMY_DATABASE_URI\u0026#39;] = \u0026#39;sqlite:///\u0026#39; + os.path.join(basedir, \u0026#39;data.sqlite\u0026#39;) app.config[\u0026#39;SQLALCHEMY_TRACK_MODIFICATIONS\u0026#39;] = False db = SQLAlchemy(app) 模型 （一对多） class Role(db.Model): __tablename__ = \u0026#39;roles\u0026#39; id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) users = db.relationship(\u0026#39;User\u0026#39;, backref=\u0026#39;role\u0026#39;) def __repr__(self): return \u0026#39;\u0026lt;Role %r\u0026gt;\u0026#39; % self.name class User(db.Model): __tablename__ = \u0026#39;users\u0026#39; id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) role_id = db.column(db.Integer, db.ForeignKey(\u0026#39;roles.id\u0026#39;)) def __repr__(self): return \u0026#39;\u0026lt;User %r\u0026gt;\u0026#39; % self.username 数据库操作 （flask shell） 创建表\n\u0026gt;\u0026gt;\u0026gt; from hello import db \u0026gt;\u0026gt;\u0026gt; db.create_all() # 如果数据库文件已经存在，暴力删除再重新生成： \u0026gt;\u0026gt;\u0026gt; db.drop_all() \u0026gt;\u0026gt;\u0026gt; db.create_all() 插入行\n\u0026gt;\u0026gt;\u0026gt; from hello import Role,User \u0026gt;\u0026gt;\u0026gt; admin_role = Role(name=\u0026#39;Admin\u0026#39;) \u0026gt;\u0026gt;\u0026gt; mod_role = Role(name=\u0026#39;Moderator\u0026#39;) \u0026gt;\u0026gt;\u0026gt; user_role = Role(name=\u0026#39;User\u0026#39;) \u0026gt;\u0026gt;\u0026gt; user_john = User(username=\u0026#39;john\u0026#39;, role=admin_role) \u0026gt;\u0026gt;\u0026gt; user_susan = User(username=\u0026#39;susan\u0026#39;, role=user_role) \u0026gt;\u0026gt;\u0026gt; user_david = User(username=\u0026#39;david\u0026#39;, role=user_role) # 数据库会话（事务） \u0026gt;\u0026gt;\u0026gt; db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david]) \u0026gt;\u0026gt;\u0026gt; db.session.commit() # 数据库会话支持回滚 \u0026gt;\u0026gt;\u0026gt; db.session.rollback() 修改行\n\u0026gt;\u0026gt;\u0026gt; admin_role.name = \u0026#39;Administrator\u0026#39; \u0026gt;\u0026gt;\u0026gt; db.session.add(admin_role) \u0026gt;\u0026gt;\u0026gt; db.session.commit() 删除行\n\u0026gt;\u0026gt;\u0026gt; db.session.delete(mod_role) \u0026gt;\u0026gt;\u0026gt; db.session.commit() 查询行\n# 基本 all() \u0026gt;\u0026gt;\u0026gt; Role.query.all() [\u0026lt;Role \u0026#39;Administrator\u0026#39;\u0026gt;, \u0026lt;Role \u0026#39;User\u0026#39;\u0026gt;] \u0026gt;\u0026gt;\u0026gt; User.query.all() [\u0026lt;User \u0026#39;john\u0026#39;\u0026gt;, \u0026lt;User \u0026#39;susan\u0026#39;\u0026gt;, \u0026lt;User \u0026#39;david\u0026#39;\u0026gt;] # 过滤器 \u0026gt;\u0026gt;\u0026gt; User.query.filter_by(role=user_role).all() [\u0026lt;User \u0026#39;susan\u0026#39;\u0026gt;, \u0026lt;User \u0026#39;david\u0026#39;\u0026gt;] # 查看生成的原生 SQL 语句 \u0026gt;\u0026gt;\u0026gt; str(User.query.filter_by(role=user_role)) \u0026#39;SELECT users.id AS users_id, users.username AS users_username, users.role_id AS users_role_id \\nFROM users \\nWHERE ? = users.role_id\u0026#39; # 如果中途退出 shell 会话，加载示例： user_role = Role.query.filter_by(name=\u0026#39;User\u0026#39;).first() # 关闭自动执行查询 \u0026gt;\u0026gt;\u0026gt; user_role.users [\u0026lt;User \u0026#39;susan\u0026#39;\u0026gt;, \u0026lt;User \u0026#39;david\u0026#39;\u0026gt;] # 在模型中加入 lazy=\u0026#39;dynamic\u0026#39; 参数 users = db.relationship(\u0026#39;User\u0026#39;, backref=\u0026#39;role\u0026#39;, lazy=\u0026#39;dynamic\u0026#39;) # 可以使用过滤器了 \u0026gt;\u0026gt;\u0026gt; user_role.users.order_by(User.username).all() [\u0026lt;User \u0026#39;david\u0026#39;\u0026gt;, \u0026lt;User \u0026#39;susan\u0026#39;\u0026gt;] 集成 Python shell 通过 app.shell_context_processor 装饰器，在每次启动 flask shell 会话时自动导入数据库示例和模型：\n@app.shell_context_processor def make_shell_context(): return dict(db=db, User=User, Role=Role) 第 6 章 电子邮件 使用 Flask-Mail 提供电子邮件支持，Python 的 smtplib 库不支持 OAuth2 验证方法，需要设置 Google 账户的「允许不够安全的应用的访问权限」。\n配置：\napp.config[\u0026#39;MAIL_SERVER\u0026#39;] = \u0026#39;smtp.gmail.com\u0026#39; app.config[\u0026#39;MAIL_PORT\u0026#39;] = 587 app.config[\u0026#39;MAIL_USE_TLS\u0026#39;] = True app.config[\u0026#39;MAIL_USERNAME\u0026#39;] = os.environ.get(\u0026#39;MAIL_USERNAME\u0026#39;) app.config[\u0026#39;MAIL_PASSWORD\u0026#39;] = os.environ.get(\u0026#39;MAIL_PASSWORD\u0026#39;) app.config[\u0026#39;FLASKY_MAIL_SUBJECT_PREFIX\u0026#39;] = \u0026#39;[前缀]\u0026#39; app.config[\u0026#39;FLASKY_MAIL_SENDER\u0026#39;] = \u0026#39;Flasky Admin \u0026lt;xxx@gmail.com\u0026gt;\u0026#39; app.config[\u0026#39;FLASKY_ADMIN\u0026#39;] = os.environ.get(\u0026#39;FLASKY_ADMIN\u0026#39;) 将敏感信息写入环境变量：\n$ export MAIL_USERNAME=xxx@gmail.com $ export MAIL_PASSWORD=xxxxxxxx $ export FLASKY_ADMIN=xxx@gmail.com # 接收邮件的管理员 集成邮件发送功能：\nfrom flask_mail import Mail, Message mail = Mail(app) def send_email(to, subject, template, **kwargs): msg = Message(app.config[\u0026#39;FLASKY_MAIL_SUBJECT_PREFIX\u0026#39;] + subject, sender=app.config[\u0026#39;FLASKY_MAIL_SENDER\u0026#39;], recipients=[to]) msg.body = render_template(template + \u0026#39;.txt\u0026#39;, **kwargs) msg.html = render_template(template + \u0026#39;.html\u0026#39;, **kwargs) mail.send(msg) 编写视图函数：\n# ... if app.config[\u0026#39;FLASKY_ADMIN\u0026#39;]: send_email(app.config[\u0026#39;FLASKY_ADMIN\u0026#39;], \u0026#39;New User\u0026#39;, \u0026#39;mail/new_user\u0026#39;, user=user) # ... 第 7 章 大型应用的结构 提供一个可供中大型程序使用的应用结构\n项目结构： . ├── app/ │ ├── /__init__.py │ ├── /email.py │ ├── /models.py │ ├── /static/ │ ├── /templates/ │ ├── /main/ │ ├── /__init__.py │ ├── /errors.py\t│ ├── /forms.py │ ├── /views.py ├── migrations/ ├── tests/ └── venv/ ├── config.py ├── flasky.py ├── requirements.txt 编写配置模块，配合工厂函数可以创建多个实例，便于测试。\nFlask 提供蓝本(blueprint)功能，蓝本中定义的路由和错误处理程序处于休眠状态，直到蓝本注册到应用上后才生效。\n定义相关的环境变量启动 Flask：\n$ export FLASKY_ADMIN=xxx@xxx.com $ export MAIL_USERNAME=xxx@xxx.com $ export MAIL_PASSWORD=xxx $ export FLASK_APP=flasky.py $ export FLASK_DEBUG=1 $ flask run 需求文件 requirements.txt 用 pip 生成 requirements.txt 文件：\n$ pip freeze \u0026gt;requirements.txt 安装或升级包后，需手动更新。\n其他人利用 requirements.txt 文件创建副本，先创建好虚拟环境，执行以下命令：\n$ pip install -r requirements.txt 蓝本 Flask 之旅\n如何理解Flask中的蓝本\n​\n其他 后续章节就是实战了，代码量太多了，没有做笔记了。。。\n","permalink":"https://dvel.me/posts/flask-web-development-note/","summary":"\u003cp\u003e《Flask Web 开发》第二版\u003c/p\u003e\n\u003cp\u003e豆瓣地址：\u003ca href=\"https://book.douban.com/subject/30293851/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://book.douban.com/subject/30293851/\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"第-1-章---安装\"\u003e第 1 章 - 安装\u003c/h2\u003e\n\u003ch3 id=\"flask-哲学\"\u003eFlask 哲学\u003c/h3\u003e\n\u003cp\u003eFlask 自开发伊始就被设计为可扩展的框架，它具有一个包含基本服务的强健核心，其他功能则可通过扩展实现。\u003c/p\u003e\n\u003cp\u003eFlask 有 3 个主要依赖：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e路由、调试和 Web 服务器网关接口（WSGI，Web server gateway interface）子系统由 Werkzeug 提供；\u003c/li\u003e\n\u003cli\u003e模板系统由 Jinja2 提供；\u003c/li\u003e\n\u003cli\u003e命令行集成由 Click 提供。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e开发者可以任意挑选符合项目需求的扩展，甚至可以自行开发。这和大型框架的做法相反，大型框架往往已经替你做出了大多数决定，难以（有时甚至不允许）使用替代方案。\u003c/p\u003e\n\u003ch3 id=\"venv\"\u003evenv\u003c/h3\u003e\n\u003cp\u003e在 Python 3 中由标准库 \u003ccode\u003evenv\u003c/code\u003e 创建虚拟环境：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ python3 -m venv virtual-environment-name\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e激活虚拟环境：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ source venv/bin/activate\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e取消：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ deactivate\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e另一种使用虚拟环境的方法：\u003c/p\u003e\n\u003cp\u003e在终端中执行 \u003ccode\u003e$ venv/bin/python\u003c/code\u003e 直接激活虚拟环境中的交互模式，退出时直接按下 ctrl + D。\u003c/p\u003e\n\u003cbr/\u003e\n\u003ch2 id=\"第-2-章---应用的基本结构\"\u003e第 2 章 - 应用的基本结构\u003c/h2\u003e\n\u003ch3 id=\"初始化\"\u003e初始化\u003c/h3\u003e\n\u003cp\u003e所有 Flask 应用都必须创建一个\u003cstrong\u003e应用实例\u003c/strong\u003e，通常由下述代码创建：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003eflask\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003eFlask\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eapp\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFlask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"vm\"\u003e__name__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWeb 服务器使用 WSGI 协议，把接受自客户端的所有请求转发给这个对象处理。\u003c/p\u003e","title":"《Flask Web 开发》笔记"},{"content":"macOS 自带的 Automator.app 并没有给出睡眠及唤醒时的条件变量，不过可以通过 sleepwatcher 来监测并执行一些脚本。\nsleepwatcher 安装:\nbrew install sleepwatcher 安装完成后有使用提示，sleepwatcher 会在睡眠和唤醒时自动运行 ~/.sleep 和 ~/.wakeup。\n服务由 brew services 管理：\nbrew services -h 创建文件并给予运行权限：\ntouch ~/.sleep \u0026amp;\u0026amp; chmod +x ~/.sleep touch ~/.wakeup \u0026amp;\u0026amp; chmod +x ~/.wakeup 由于系统限制，睡眠时的操作不能运行超过 15 秒。\n可以在 ~/.sleep 写入一个创建文件夹的操作作为测试：\n#!/bin/zsh mkdir ~/Desktop/test 盒盖、打开，桌面应该就有一个 test/ 目录了。\n睡眠时关闭 QQ QQ for Mac 多年以来一直会在合盖状态下不知何时突然响起登录声，真的是让人无语，经常是合盖睡觉了，躺床上刚要睡着的时候 QQ 突然响了。\n一个 python 脚本，关闭 QQ 的进程：\n#!/usr/local/bin/python3 import psutil for pid in psutil.pids(): name = psutil.Process(pid).name() if name == \u0026#39;QQ jietu plugin\u0026#39; or name == \u0026#39;QQ\u0026#39;: psutil.Process(pid).terminate() 给予脚本权限并在 ~/.sleep 中执行脚本就可以了。\n#!/usr/local/bin/zsh /.../terminate_QQ.py 同步 Rime #!/usr/local/bin/zsh /Library/Input\\ Methods/Squirrel.app/Contents/MacOS/Squirrel --sync 其他 能干的事情很多，比如启动/关闭程序，开关蓝牙，播放音乐啥的。。。\n","permalink":"https://dvel.me/posts/sleepwatcher-mac-auto-script/","summary":"\u003cp\u003emacOS 自带的 Automator.app 并没有给出睡眠及唤醒时的条件变量，不过可以通过 \u003ccode\u003esleepwatcher\u003c/code\u003e 来监测并执行一些脚本。\u003c/p\u003e\n\u003ch2 id=\"sleepwatcher\"\u003esleepwatcher\u003c/h2\u003e\n\u003cp\u003e安装:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew install sleepwatcher\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e安装完成后有使用提示，sleepwatcher 会在睡眠和唤醒时自动运行 \u003ccode\u003e~/.sleep\u003c/code\u003e 和 \u003ccode\u003e~/.wakeup\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e服务由 brew services 管理：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew services -h\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e创建文件并给予运行权限：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etouch ~/.sleep \u0026amp;\u0026amp; chmod +x ~/.sleep\ntouch ~/.wakeup \u0026amp;\u0026amp; chmod +x ~/.wakeup\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e由于系统限制，睡眠时的操作不能运行超过 15 秒。\u003c/p\u003e\n\u003cp\u003e可以在 \u003ccode\u003e~/.sleep\u003c/code\u003e 写入一个创建文件夹的操作作为测试：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/zsh\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir ~/Desktop/test\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e盒盖、打开，桌面应该就有一个 \u003ccode\u003etest/\u003c/code\u003e 目录了。\u003c/p\u003e\n\u003ch2 id=\"睡眠时关闭-qq\"\u003e睡眠时关闭 QQ\u003c/h2\u003e\n\u003cp\u003eQQ for Mac 多年以来一直会在合盖状态下不知何时突然响起登录声，真的是让人无语，经常是合盖睡觉了，躺床上刚要睡着的时候 QQ 突然响了。\u003c/p\u003e\n\u003cp\u003e一个 python 脚本，关闭 QQ 的进程：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"ch\"\u003e#!/usr/local/bin/python3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003epsutil\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003epsutil\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epids\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ename\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epsutil\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;QQ jietu plugin\u0026#39;\u003c/span\u003e \u003cspan class=\"ow\"\u003eor\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;QQ\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003epsutil\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eterminate\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e给予脚本权限并在 \u003ccode\u003e~/.sleep\u003c/code\u003e 中执行脚本就可以了。\u003c/p\u003e","title":"用 sleepwatcher 让 Mac 在睡眠及唤醒时自动执行一些脚本"},{"content":"brew doctor 的错误提示：\nPlease note that these warnings are just used to help the Homebrew maintainers with debugging if you file an issue. If everything you use Homebrew for is working fine: please don\u0026#39;t worry or file an issue; just ignore this. Thanks! Warning: \u0026#34;config\u0026#34; scripts exist outside your system or Homebrew directories. `./configure` scripts often look for *-config scripts to determine if software packages are installed, and which additional flags to use when compiling and linking. Having additional scripts in your path can confuse software installed via Homebrew if the config script overrides a system or Homebrew-provided script of the same name. We found the following \u0026#34;config\u0026#34; scripts: /Users/username/.pyenv/shims/python2-config /Users/username/.pyenv/shims/python2.7-config /Users/username/.pyenv/shims/python-config /Users/username/.pyenv/shims/python3-config /Users/username/.pyenv/shims/python3.8-config 解决方法：https://github.com/pyenv/pyenv/issues/106 randy3k commented on 22 Apr 2015\n写入 ~/.bash_profile 或 ~/.zshrc 中：\nalias brew=\u0026#34;env PATH=${PATH//$(pyenv root)\\/shims:/} brew\u0026#34; 如果你安装了 VMware Fusion，可能会出现错误提示：\n$ brew doctor env: Fusion.app/Contents/Public:/Library/Apple/usr/bin: No such file or directory 执行 echo ${PATH//$(pyenv root)\\/shims:/} 会看到原因：\n.../Applications/VMware Fusion.app/Contents/Public... VMware Fusion 的环境变量没有被 \\\u0026lt;space\u0026gt; 转义，这个 PATH 似乎在大部分情况下都可以正常运行，甚至直接在终端执行 env PATH=${PATH//$(pyenv root)\\/shims:/} brew doctor 都可以正常运行，但是在 alias 命令下却因为这个没有转义的空格而发生错误了。\n所以自己加一个转义就好了，编辑 /etc/paths.d/com.vmware.fusion.public：\n/Applications/VMware Fusion.app/Contents/Public 更改为：\n/Applications/VMware\\ Fusion.app/Contents/Public ","permalink":"https://dvel.me/posts/solve-pyenv-brew-warning/","summary":"\u003cp\u003e\u003ccode\u003ebrew doctor\u003c/code\u003e 的错误提示：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ePlease note that these warnings are just used to help the Homebrew maintainers\nwith debugging if you file an issue. If everything you use Homebrew for is\nworking fine: please don\u0026#39;t worry or file an issue; just ignore this. Thanks!\n\nWarning: \u0026#34;config\u0026#34; scripts exist outside your system or Homebrew directories.\n`./configure` scripts often look for *-config scripts to determine if\nsoftware packages are installed, and which additional flags to use when\ncompiling and linking.\n\nHaving additional scripts in your path can confuse software installed via\nHomebrew if the config script overrides a system or Homebrew-provided\nscript of the same name. We found the following \u0026#34;config\u0026#34; scripts:\n  /Users/username/.pyenv/shims/python2-config\n  /Users/username/.pyenv/shims/python2.7-config\n  /Users/username/.pyenv/shims/python-config\n  /Users/username/.pyenv/shims/python3-config\n  /Users/username/.pyenv/shims/python3.8-config\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e解决方法：https://github.com/pyenv/pyenv/issues/106 \u003ccode\u003erandy3k commented on 22 Apr 2015\u003c/code\u003e\u003c/p\u003e","title":"解决 pyenv 导致的 brew warning"},{"content":"《SQL 必知必会》第 4 版\n豆瓣：https://book.douban.com/subject/24250054/\nSQL 文件下载地址：https://forta.com/books/0672336073/\n1 - 了解 SQL 数据库 保存有组织的数据的容器（通常是一个文件或多个文件）。\n数据库软件应称为数据库管理系统（DBMS）.\n表 某种特定类型数据的结构化清单。\n列 表中的一个子段。所有表都是由一个或多个列组成的。\n主键： 表中的任何列都可以作为主键，只要它满足以下条件：\n任意两行都不具备有相同的主键值； 每一行都必须具有一个主键值（主键列不允许 NULL 值）； 主键列中的值不允许修改或更新； 主键值不能重用（如果某行从表中删除，它的主键不能赋给以后的新行）。 2 - 检索数据 查询语句 SELECT 检索一个或多个列。\nSELECT 列名 FROM 表名; SELECT * FROM 表名; 注释 在大多数数据库软件中，支持 # -- /**/ 等单行和多行注释。\n结果集去重 DISTINCT SELECT DISTINCT 列名 FROM 表名; DISTINCT 关键字限制所有的列，如果后接多列，除非两列内容完全相同，否则都会被纳入结果集。\n限制结果 LIMIT 大多用于分页显示：\n-- 从第 0 行开始，显示 5 个。第一页： SELECT * FROM 表名 LIMIT 5 OFFSET 0; -- 从第 5 行开始，现实 5 个。第二页： SELECT * FROM 表名 LIMIT 5 OFFSET 5; MySQL、MariaDB、SQLite 简化语法：\n# 从 n 起，取 m 行。 n 可省略，默认为 0。 SELECT 列1, 列2 FROM 表 LIMIT n, m; -- 示例： -- 第一页： SELECT * FROM 表名 LIMIT 0, 5; -- 第二页： SELECT * FROM 表名 LIMIT 5, 5; -- 第三页 SELECT * FROM 表名 LIMIT 10, 5; 3 - 排序检索数据 ASC 默认，升序，全称 ascending。\nDESC 降序，全称 descending。\n排序数据 ORDER BY SELECT 列名 FROM 表名 ORDER BY 列名; ORDER BY 子句中用非检索的列排序也是合法的。\n按多个列排序 写在前面的优先级高。\nSELECT 列名 FROM 表名 ORDER BY 列名1, 列名2; 按列位置排序，可以使用列名的书写位置，不推荐：\nSELECT 列名1, 列名2, 列名3 FROM 表名 ORDER BY 2, 3; 降序排列 ORDER BY 默认为升序排列。（从上至下，越来越大（0→100，a→z））\nDESC 只对前面那一列生效，如果想多列使用降序排序，必须对每一列指定 DESC 关键字。\n示例：（prod_price 列降序排序，prod_name 仍按升序排序）\nSELECT prod_id, prod_price, prod_name FROM Products ORDER BY prod_price DESC, prod_name 4 - 过滤数据 WHERE SELECT 列名 FROM 表名 WHERE 条件; 操作符 常见操作符：\u0026lt; \u0026gt; = \u0026lt;= \u0026gt;= != 。。。\nBTEWEEN 操作符，左闭右闭。\nIS NULL\n5 - 高级数据过滤 AND OR AND 优先级大于 OR。\n使用小括号，不依赖优先级顺序，可以消除歧义。\nIN 指定范围，集合中的每个条件都可以进行匹配。\nSELECT * FROM 表名 WHERE xxx_id IN (no1, no2); 加强版的 OR，使逻辑更清晰。\nNOT 否定紧跟的条件。\n6 - 用通配符进行过滤 LIKE LIKE 指示 DBMS 后跟的搜索模式利用通配符而不是简单的相等匹配进行比较。\n% 通配符 % 能匹配 0 个、1 个或多个字符。\n示例：\nSELECT * FROM Products WHERE prod_name LIKE \u0026#34;fish%\u0026#34;; _ 通配符 _ 总是刚好匹配一个字符，不能多也不能少。\n示例：（与 % 的区别与对比）\nSELECT prod_name FROM Products WHERE prod_name LIKE \u0026#34;% inch teddy bear\u0026#34;; -- 8 inch teddy bear -- 12 inch teddy bear -- 18 inch teddy bear SELECT prod_name FROM Products WHERE prod_name LIKE \u0026#34;__ inch teddy bear\u0026#34;; -- 两个下划线 -- 12 inch teddy bear -- 18 inch teddy bear SELECT prod_name FROM Products WHERE prod_name LIKE \u0026#34;_ inch teddy bear\u0026#34;; -- 一个下划线 -- 8 inch teddy bear 注意 不要过度使用通配符。如果其他操作符能达到相同的目的，应该使用其他操作符。 在确实需要使用通配符时，也尽量不要把它们用在搜索模式的开始处，搜索起来是最慢的。 仔细注意通配符的位置。如果放错地方，可能不会返回想要的数据。 7 - 创建计算字段 拼接字段 MySQL 和 MariaSQL 使用 CONCAT() 函数拼接字符串；\n使用 TRIM()、LTRIM()、RTRIM 去掉字符串两边、左、右的空格。\n示例：\nSELECT CONCAT( TRIM( vend_name ), \u0026#39;\\t\\t(\u0026#39;, TRIM( vend_country ), \u0026#39;)\u0026#39; ) FROM Vendors; AS 别名 计算字段 对检索出的数据进行算术计算：\nSELECT prod_id, quantity, item_price, quantity*item_price AS expanded_price FROM OrderItems WHERE order_num = 20008; 8 - 使用函数处理数据 函数 文本处理函数 日期和时间处理函数 数值处理函数 需要参考相应 DBMS 文档。\n9 - 汇总数据 聚集函数 对某些行运行的函数，计算并返回一个值。\nAVG() 平均值 只适用于单列，忽略值为 NULL 的行。\nCOUNT() 计数 COUNT(*) 对表中行的数目进行计算，不管表列中是否包含 NULL 值。\nCOUNT(列名) 会忽略值为 NULL 的行。\nMAX() 最大值 MIN() 最小值 SUM() 求和 聚集不同值 对以上 5 个聚集函数都可以使用如下参数：\nALL 默认，对所有行执行计算。 DISTINCT 只包含不同的值。（不能用于 COUNT(*)，只能用于列名。） 例：\nSELECT AVG(DISTINCT salary) FROM employee; 会忽略工资相同的员工工资，来计算平均值。\n10 - 分组数据 GROUP BY 分组 示例：\nSELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id; -- vend_id\tnum_prods -- BRS01\t3 -- DLL01\t4 -- FNG01\t2 GROUP BY 子句可以包含任意数目的列，因而可以对分组进行嵌套，更细致地进行数据分组。 如果嵌套了分组，数据将在最后指定的分组上进行汇总。 GROUP BY 子句中列出的每一列都必须是检索列或有效的表达式（但不能是聚集函数）。 除聚集计算语句外，SELECT 语句中的每一列都必须在 GROUP BY 子句中给出。 如果分组列中包含 NULL 值的行，则 NULL 将作为一个分组返回。如果列中有多行 NULL 只，它们将分为一组。 HAVING 过滤分组 示例：（列出具有 2 个以上产品且其价格大于等于 4 的供应商）\nSELECT vend_id, COUNT(*) FROM Products WHERE prod_price \u0026gt;= 4 GROUP BY vend_id HAVING COUNT(*) \u0026gt;= 2; -- vend_id\tCOUNT(*) -- BRS01\t3 -- FNG01\t2 HAVING 支持所有 WHERE 的操作符。\n紧接 GROUP BY，不能单独存在。\n聚合函数只能与具体数据做条件判断，不能与字段做条件判断。（可用表连接实现）\nWHERE 与 HAVING 的差别： WHERE 不能使用聚合函数，HAVING 可以在分组后使用聚合函数。\nWHERE 在数据分组前进行过滤，HAVING 在数据分组后进行过滤。\n所以 WHERE 排除的行不包括在分组中，这可能会改变计算值，从而影响 HAVING 子句中基于这些值过滤掉的分组。\nORDER BY 分组和排序 一般在使用 GROUP BY 子句时，应该也给出 ORDER BY 子句。这时保证数据正确排序的唯一方法。千万不要尽依赖 GROUP BY 排序数据。\nSELECT 子句书写顺序 子句 说明 是否必须使用 SELECT 要返回的列或表达式 是 FROM 从中检索数据的表 仅在从表选择数据时使用 WHERE 行级过滤 否 GROUP BY 组级过滤 仅在按组计算聚集时使用 HAVING 组级过滤 否 ORDER BY 输出排序顺序 否 11 - 使用子查询 利用子查询进行过滤 作为子查询的 SELECT 语句只能查询单个列。\n示例，列出订购物品 RGAN01 的所有顾客：\n1：检索包含物品 RGAN01 的所有订单的编号 SELECT order_num FROM OrderIterms WHERE prod_id = \u0026#39;RGAN01\u0026#39;; 2：检索具有前一步骤列出的订单编号的所有顾客的 ID SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderIterms WHERE prod_id = \u0026#39;RGAN01\u0026#39;); 3：检索前一步骤返回的所有顾客 ID 的顾客信息 SELECT cust_name, cust_contact FROM Customers WHERE cust_id IN (SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderIterms WHERE prod_id = \u0026#39;RGAN01\u0026#39;)); 内连接写法：（第 12 课）\n-- 列出订购物品 RGAN01 的所有顾客： SELECT cust_name, cust_contact FROM OrderItems, Orders, Customers WHERE OrderItems.prod_id = \u0026#39;RGAN01\u0026#39; AND OrderItems.order_num = Orders.order_num AND Orders.cust_id = Customers.cust_id; 作为计算字段使用子查询 示例，现实 Customers 表中每个顾客的订单总数：\n1：从 Customers 表中检索顾客列表； SELECT COUNT(*) AS orders FROM Orders WHERE cust_id = \u0026#39;1000000001\u0026#39;; 2：对于检索出的每个顾客，统计其在 Orders 表中的订单数目 SELECT cust_name, cust_state, (SELECT COUNT(*) FROM Orders WHERE Orders.cust_id = Customers.cust_id) AS orders FROM Customers ORDER BY cust_name; 12 - 连接表 连接 为什么使用连接？\n如果数据存储在多个表中，怎么用一条 SELECT 语句就检索出数据呢？\n答案是使用连接。\n内连接（inner join） 内连接，又称等值连接（equijoin），它基于两个表之间的相等测试。\n示例：\nSELECT vend_name, prod_name, prod_price FROM Vendors, Products WHERE Vendors.vend_id = Products.vend_id; MySQL 中的多种写法： SELECT ... FROM 表1, 表2 WHERE 连接条件; SELECT ... FROM 表1 [INNER] JOIN 表2 ON 连接条件; SELECT ... FROM 表1 [INNER] JOIN 表2 WHERE 连接条件; （在使用外连接时，使用 WHERE 会出问题） 笛卡尔积：（叉连接）（cross join） 没有连接条件的表关系返回的结果为笛卡尔积，检索出的行数将是第一个表中的行数乘以第二个表中的行数。\n连接多个表 -- 显示订单 20007 中的物品。 SELECT prod_name, vend_name, prod_price, quantity FROM OrderItems, Products, Vendors WHERE order_num = 20007 AND OrderItems.prod_id = Products.prod_id AND Products.vend_id = Vendors.vend_id; -- 列出订购物品 RGAN01 的所有顾客： SELECT cust_name, cust_contact FROM OrderItems, Orders, Customers WHERE OrderItems.prod_id = \u0026#39;RGAN01\u0026#39; AND OrderItems.order_num = Orders.order_num AND Orders.cust_id = Customers.cust_id; 13 - 创建高级连接 使用表别名 除了之前的给列起别名，也可以在 FROM 子句中给表起别名，以供在 SELECT、WHERE 子句中使用。\n可以缩短 SQL 语句。允许在一条 SELECT 语句中方便多次使用相同的表。\n自连接（self-join） 内连接的一种，连接的是同一个表。\n示例：\n-- 给 Jim Jones 同一公司的所有顾客发送一封信件。 SELECT c1.cust_name, c1.cust_contact, c1.cust_email FROM Customers AS c1, Customers AS c2 WHERE c2.cust_contact = \u0026#39;Jim Jones\u0026#39; AND c1.cust_name = c2.cust_name; -- cust_name\tcust_contact\tcust_email -- Fun4All\tJim Jones\tjjones@fun4all.com -- Fun4All\tDenise L. Stephens\tdstephens@fun4all.com 自连接比子查询性能更好。\n自然连接（natural join） 自然连接排除多次出现，使每一列只返回一次。\nSELECT * FROM Customers NATURAL JOIN Orders; -- 两个表中都有 cust_id 列，但只返回了一个。 *感觉没什么用啊。。。除非真的要查询这么多字段。\n外连接（outer join） 内连接只返回符合条件的记录，外连接还返回不符合条件的记录。 左外连接即保留左表的所有记录，与右表连接； 右外连接即保留右表的所有记录，与左表连接。 左外连接（left outer join）与右外连接（right outer join）可以互相转换。（SQLite 即便不支持右外连接，也可以用左外连接代替） 内外连接的区别，示例：（查询每个顾客的订单计数，外连接可以查询出尚未下过订单的顾客）\n-- 内连接，只查询出条件关联的行 -- 查询不到顾客 1000000002，因为他没有下过订单 SELECT Customers.cust_id, Orders.order_num FROM Customers JOIN Orders ON Customers.cust_id = Orders.cust_id; -- cust_id\torder_num -- 1000000001\t20005 -- 1000000001\t20009 -- 1000000003\t20006 -- 1000000004\t20007 -- 1000000005\t20008 -- 外连接，保留顾客表中所有顾客的记录，去外连接订单表 -- 可以查询到 1000000002 SELECT Customers.cust_id, Orders.order_num FROM Customers LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id; -- cust_id\torder_num -- 1000000001\t20005 -- 1000000001\t20009 -- 1000000002\t(NULL) -- 1000000003\t20006 -- 1000000004\t20007 -- 1000000005\t20008 -- 完善：外连接+分组计数 -- 带聚集函数的连接 SELECT Customers.cust_id, COUNT(Orders.order_num) FROM Customers LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id GROUP BY Customers.cust_id; -- cust_id\tCOUNT(Orders.order_num) -- 1000000001\t2 -- 1000000002\t0 -- 1000000003\t1 -- 1000000004\t1 -- 1000000005\t1 其他外连接示例：\n-- 列出所有产品以及订购数量，包括没有人订购的产品 SELECT Products.prod_id, SUM(IFNULL(OrderItems.quantity,0)) FROM Products LEFT JOIN OrderItems ON Products.prod_id = OrderItems.prod_id GROUP BY Products.prod_id; 全外连接（full outer join） MySQL、MariaSQL、SQLite、Access、Open Office Base 不支持全外连接。\n全外连接检索两个表中的所有行并关联那些可以关联的行。\n14 - 组合查询 组合查询（ UNION） SQL 允许执行多个查询（多条 SELECT 语句），并将结果作为一个查询结果返回。\n主要有两种情况需要使用组合查询：\n在一个查询中从不同的表返回结果数据； 对一个表执行多个查询，按一个查询返回数据。 提示：多数情况下，组合相同表的两个查询，通过具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询。\n创建组合查询 示例：（需要 Illinois、Indiana、Michigan 等美国几个州的所有顾客的报表，还想包括不管位于哪个州的所有的 Fun4All）\n单条语句 1：\nSELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state IN (\u0026#39;IL\u0026#39;, \u0026#39;IN\u0026#39;, \u0026#39;MI\u0026#39;); -- cust_name\tcust_contact\tcust_email -- Village Toys\tJohn Smith\tsales@villagetoys.com -- Fun4All\tJim Jones\tjjones@fun4all.com -- The Toy Store\tKim Howard\t(NULL) 单条语句 2：\nSELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_name = \u0026#39;Fun4All\u0026#39;; -- cust_name\tcust_contact\tcust_email -- Fun4All\tJim Jones\tjjones@fun4all.com -- Fun4All\tDenise L. Stephens\tdstephens@fun4all.com UNION 组合：\nSELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state IN (\u0026#39;IL\u0026#39;, \u0026#39;IN\u0026#39;, \u0026#39;MI\u0026#39;) UNION SELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_name = \u0026#39;Fun4All\u0026#39;; -- cust_name\tcust_contact\tcust_email -- Village Toys\tJohn Smith\tsales@villagetoys.com -- Fun4All\tJim Jones\tjjones@fun4all.com -- The Toy Store\tKim Howard\t(NULL) -- Fun4All\tDenise L. Stephens\tdstephens@fun4all.com 使用 WHERE，效果相同：\nSELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state IN (\u0026#39;IL\u0026#39;, \u0026#39;IN\u0026#39;, \u0026#39;MI\u0026#39;) OR cust_name = \u0026#39;Fun4All\u0026#39;; 包含或取消重复的行： 上面例子中，Fun4All\tJim Jones\tjjones@fun4all.com 这一行在两个 SELECT 语句中均被查询出，但 UNION 取消了重复的行。\nUNION ALL 可以让每个条件的匹配行全部出现。\n排序： 使用 UNION 组合查询时，只能使用一条 ORDER BY 子句进行排序，它必须位于最后一条 SELECT 语句之后。\nUNION 规则 UNION 必须由两条或两条以上的 SELECT 语句组成，语句之间用关键字 UNION 分割。\nUNION 中的每个查询必须包含相同数量的列、表达式或聚集函数。\n列数据类型必须兼容：类型不必完全相同但必须兼容（如不同长度的字符串）\n​\n15 - 插入数据 数据插入 INTERT 语句：用来将行插入（或添加）到数据库表，插入有几种方式：\n插入完整的行； 插入行的一部分； 插入某些查询的结果。 插入完整的行：（MySQL 中可以省略 INTO） INSERT INTO Customers VALUES(\u0026#39;1000000006\u0026#39;, \u0026#39;Toy Land\u0026#39;, \u0026#39;123 Any Street\u0026#39;, \u0026#39;New York\u0026#39;, \u0026#39;NY\u0026#39;, \u0026#39;11111\u0026#39;, \u0026#39;USA\u0026#39;, NULL, NULL); 这种插入方法必须完整的按顺序提供列名所对应的数据。\n由于较为依赖于表中列的定义次序，在表结构变动后会变得不安全或更改更麻烦。\n更安全的方法 or 插入部分字段： INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(\u0026#39;1000000006\u0026#39;, \u0026#39;Toy Land\u0026#39;, \u0026#39;123 Any Street\u0026#39;, \u0026#39;New York\u0026#39;, \u0026#39;NY\u0026#39;, \u0026#39;11111\u0026#39;, \u0026#39;USA\u0026#39;, NULL, NULL); 这样 DBMS 将用 VALUES 列表中的值按次序一一对应填入列表中的对应项。\n也可以省略部分字段，只要这些省略的字段允许 NULL 值或提供默认值。\n一次插入多行数据 # 单条数据 INSERT INTO 表名[(字段1, 字段2...)] VALUES(值1, 值2...); # 多条数据 INSERT INTO 表名[(字段1, 字段2...)] VALUES(值1, 值2...), (值1, 值2...) ...; 插入检索出的数据 INSERT SELECT 语句可以插入检索出的行：\nINSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) SELECT cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email FROM CustNew; 插入行数取决于 SELECT 语句查询出多少行。\nDBMS 不在乎 SELECT 返回的列名，会将查询出的字段按 INSERT 语句给出的次序一一对应。\n从一个表复制到另一个表 SQL 语法：\nSELECT * INTO CustCopy FROM Customers; MySQL、MariaDB、SQLite、Oracle、PostgreSQL 语法：\nCREATE TABLE CustCopy AS SELECT * FROM Customers; message:\nThere is no primary key here. Update will only use exact matching of the old values of the columns here. Thus, it may update more than one record.\n*MySQL 在复制时没有复制主键约束。\n16 - 更新和删除数据 在更新和删除数据时，如果不指定 WHERE 条件，将会更新或删除所有行。\n更新数据（UPDATE） 基本的 UPDATE 语句由三部分组成：\n要更新的表； 列名和它们的新值； 确定要更新哪些行的过滤条件。 更新一列： UPDATE Customers SET cust_email = \u0026#39;kim@thetoystore.com\u0026#39; WHERE cust_id = \u0026#39;1000000005\u0026#39;; 更新多列： UPDATE Customers SET cust_contact = \u0026#39;Sam Roberts\u0026#39;, cust_email = \u0026#39;sam@toyland.com\u0026#39; WHERE cust_id = \u0026#39;1000000006\u0026#39;; 在 UPDATE 语句中进行表连接 # 把ALLEN调往RESEARCH部门,职务调整为ANALYST UPDATE t_emp e JOIN t_dept d ON e.ename = \u0026#39;ALLEN\u0026#39; AND d.dname = \u0026#39;RESEARCH\u0026#39; SET e.deptno = d.deptno, e.job = \u0026#39;ANALYST\u0026#39;, d.loc = \u0026#39;北京\u0026#39;; 支持内连接另一个结果集： # 把底薪低于公司平均底薪的员工,底薪增加150元 UPDATE t_emp e JOIN (SELECT AVG(sal) AS avg FROM t_emp) e2 ON e.sal \u0026lt; e2.avg SET sal = sal + 150; 同样支持外连接。\n删除数据（DELETE） 关于删除所有的行：\n不指定 WHERE 条件时，DELETE 将会删除所有的行，但如果你明确要这么做，使用 TRUNCATE TABLE 可以更快的删除整个表的数据（因为不记录数据的变动（没有事务））。\n删除行：\nDELETE FROM Customers WHERE cust_id = \u0026#39;1000000006\u0026#39;; 同样支持表连接：\nDELETE 表1, ... FROM 表1 JOIN 表2 ON 条件 [WHERE 条件 ...]; 可以一次性删除多个表的内容：\n# 删除SALES部门和该部门的全部员工记录 DELETE e,d FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno WHERE d.dname=\u0026#34;SALES\u0026#34;; 同样支持外连接。\n17 - 创建和操纵表 创建表： CREATE TABLE 表名 ( 列名1 数据类型 [约束] [COMMENT], 列名2 数据类型 [约束] [COMMENT], ...; )[COMMENT = 注释]; 删除表： # 删除 DROP TABLE 表名; # 清空 TRUNCATE TABLE 表名; 添加列： ALTER TABLE 表名 ADD 列名 数据类型 [约束] [COMMENT], ADD 列名 数据类型 [约束] [COMMENT], ...; 修改列类型： ALTER TABLE\t表名 MODIFY 列名 数据类型 [约束] [COMMENT], MODIFY 列名 数据类型 [约束] [COMMENT], ...; 修改列名： ALTER TABLE 表名 CHANGE 列名 新列名 数据类型 [约束] [COMMENT], CHANGE 列名 新列名 数据类型 [约束] [COMMENT], ...; 删除列 ALTER TABLE 表名 DROP 列1, DROP 列2, ...; 18 - 使用视图 视图提供了一种封装 SELECT 语句的层次，可用来简化数据处理，重新格式化或保护基础数据。\n为什么使用视图 重用 SQL 语句； 简化复杂的 SQL 操作。在编写查询后，可以方便的重用它而不必知道其基本查询细节。 使用表的一部分而不是整个表； 保护数据。可以授予用户访问表的特定部分的权限，而不是整个表的访问权限。 更改数据格式和表示。视图可以返回与底层表的表示和格式不同的数据。 视图仅仅是用来查看存储在别处数据的一种设施。视图本身不包含数据，因此返回的数据是从其他表中检索出来的。在添加或更改这些表中的数据时，视图将返回改变过的数据。\n性能问题：每次使用视图时，都必须处理查询执行时需要的所有检索。检索过于复杂，性能可能会下降的很厉害。\n视图的规则和限制 视图必须唯一命名（视图与表也不能重名）； 视图不能索引，也不能有关联的触发器或默认值。 。。。 使用视图 -- 创建视图 CREATE VIEW 视图名 AS SELECT ...; -- 删除视图 DROP VIEW 视图名; 视图重命名：覆盖或更新视图，必须先删除它，然后再重新创建。\n示例：（利用视图简化复杂的连接）\n-- 查询已订购任意产品的所有顾客的列表 SELECT cust_name, cust_contact, prod_id FROM Customers, Orders, OrderItems WHERE Customers.cust_id = Orders.cust_id AND Orders.order_num = OrderItems.order_num; -- 为上面的 SQL 语句创建视图 CREATE VIEW ProductCustomers AS SELECT cust_name, cust_contact, prod_id FROM Customers, Orders, OrderItems WHERE Customers.cust_id = Orders.cust_id AND Orders.order_num = OrderItems.order_num; -- 使用视图 SELECT * FROM ProductCustomers; -- 删除视图 DROP VIEW ProductCustomers; 从视图检索数据时如果使用了一条 WHERE 语句，则两组句子（一组在视图中，另一组是传递给视图的）将自动组合。\n示例：\n-- 用 ProductCustomers 视图查询订购了 RGAN01 的顾客 SELECT * FROM ProductCustomers WHERE prod_id = \u0026#39;RGAN01\u0026#39;; 19 - 使用存储过程 一组可编程的函数，是为了完成特定功能的 SQL 语句集，经编译创建并保存在数据库中，用户可通过指定存储过程的名字并给定参数（需要时）来调用执行。\n优点(为什么要用存储过程？)：\n将重复性很高的一些操作，封装到一个存储过程中，简化了对这些SQL的调用 批量处理：SQL+循环，减少流量，也就是“跑批” 统一接口，确保数据的安全 相对于 Oracle 数据库来说，MySQL的存储过程相对功能较弱，使用较少。\n—— MySQL存储过程的创建及调用\n20 - 管理事务处理 使用事务处理（transaction processing），通过确保成批的 SQL 操作要么完全执行，要么完全不执行，来维护数据库的完整性。\n事务处理用来管理 INSERT、UPDATE 和 DELETE 语句。不能回退 SELECT 语句（回退 SELECT 语句也没有必要）。\n也不能回退 CREATE 或 DROP 操作。事务处理中可以使用这些语句，但进行回退时，这些操作也不撤销。\n具体语法应参考相应的 DBMS 文档。\n21 - 使用游标 有时需要在检索出来的行中前进或后退一行或多行，这就是游标的用途所在。\n游标（cursor）是一个存储在 DBMS 服务器上的数据库查询，它不是一条 SELECT 语句，而是被该语句检索出来的结果集。在存储了游标之后，应用程序可以根据需要滚动或浏览其中的数据。\n具体语法应参考相应的 DBMS 文档。\n22 - 高级 SQL 特性 约束 管理如何插入或处理数据库数据的规则。\n主键（PRIMARY KEY） 外键（REFERENCES） 唯一约束（UNIQUE） 检查约束（CHECK） 索引 索引用来排序数据以加快搜索和排序操作的速度。\n可以在一个或多个列上定义索引，使 DBMS 保存其内容的一个排过序的列表。\n索引改善检索操作的性能，但降低了数据插入、修改、删除的性能。在执行这些操作时，DBMS 必须动态地更新索引。 索引数据可能要占用大量的存储空间。 并非所有数据都适合做索引。取值不多的数据（如省）不如具有更多可能值的数据（如姓、名）能通过索引得到更大的提升。 索引用于数据过滤和数据排序。如果你经常以某种特定的顺序排序数据，则该数据可能适合做索引。 可能在索引中定义多个列（如州+城市）。这样索引仅在以州+城市的顺序排序时有用。如果想按城市排序，则这种索引没有用处。 触发器 触发器是特殊的存储过程，它在特定的数据库活动发生时自动执行。\n触发器可以与特定表上的 INSERT、UPDATE、DELETE 操作（或组合）相关联。\n与存储过程不一样（存储过程只是简单的存储 SQL 语句），触发器与单个的表相关联。（例如：与 Orders 表上的 INSERT 操作相关联的触发器只在 Orders 表中插入行时执行。类似的，Customers 表上的 INSERT 和 UPDATE 操作的触发器只在表上出现这些操作时执行。）\n触发器内的代码具有一下数据库的访问权：\nINSERT 操作中的所有新数据； UPDATE 操作中的所有新数据和旧数据； DELETE 操作中删除的数据。 根据所使用的 DBMS 不同，触发器可在特定操作执行之前或之后执行。\n触发器的常见用途：\n保证数据一致。（如：在 INSERT 或 UPDATE 操作中将所有州名转换为大写） 基于某个表的变动在其他表上执行活动。（如：每当更新或删除一行时将审计跟踪记录写入某个日志表） 进行额外的验证并根据需要回退数据。（如：保证某个顾客的可用资金不超限定，如果已经超出，则阻塞插入） 计算计算列的值或更新时间戳。 不同 DBMS 的触发器创建于法差异很大。\n数据库安全 一般来说，需要保护的操作有：\n对数据库管理功能的访问（创建表、更改或删除已存在的表等）； 对特定数据库或表的访问； 访问的类型（制度、对特定列的访问等）； 仅通过视图或存储过程对表进行访问； 创建多层次的安全措施，从而允许多种基于登录的访问和控制； 闲置管理用户账号的能力。 ","permalink":"https://dvel.me/posts/sql-in-10-minutes-a-day-note/","summary":"\u003cp\u003e《SQL 必知必会》第 4 版\u003c/p\u003e\n\u003cp\u003e豆瓣：\u003ca href=\"https://book.douban.com/subject/24250054/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://book.douban.com/subject/24250054/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eSQL 文件下载地址：\u003ca href=\"https://forta.com/books/0672336073/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://forta.com/books/0672336073/\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"1---了解-sql\"\u003e1 - 了解 SQL\u003c/h2\u003e\n\u003ch3 id=\"数据库\"\u003e数据库\u003c/h3\u003e\n\u003cp\u003e保存有组织的数据的容器（通常是一个文件或多个文件）。\u003c/p\u003e\n\u003cp\u003e数据库软件应称为数据库管理系统（DBMS）.\u003c/p\u003e\n\u003ch3 id=\"表\"\u003e表\u003c/h3\u003e\n\u003cp\u003e某种特定类型数据的结构化清单。\u003c/p\u003e\n\u003ch3 id=\"列\"\u003e列\u003c/h3\u003e\n\u003cp\u003e表中的一个子段。所有表都是由一个或多个列组成的。\u003c/p\u003e\n\u003ch4 id=\"主键\"\u003e主键：\u003c/h4\u003e\n\u003cp\u003e表中的任何列都可以作为主键，只要它满足以下条件：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e任意两行都不具备有相同的主键值；\u003c/li\u003e\n\u003cli\u003e每一行都必须具有一个主键值（主键列不允许 NULL 值）；\u003c/li\u003e\n\u003cli\u003e主键列中的值不允许修改或更新；\u003c/li\u003e\n\u003cli\u003e主键值不能重用（如果某行从表中删除，它的主键不能赋给以后的新行）。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"2---检索数据\"\u003e2 - 检索数据\u003c/h2\u003e\n\u003ch3 id=\"查询语句-select\"\u003e查询语句 \u003ccode\u003eSELECT\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e检索一个或多个列。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-mysql\" data-lang=\"mysql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e列名\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e表名\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e表名\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"注释\"\u003e注释\u003c/h3\u003e\n\u003cp\u003e在大多数数据库软件中，支持 \u003ccode\u003e#\u003c/code\u003e \u003ccode\u003e--\u003c/code\u003e \u003ccode\u003e/**/\u003c/code\u003e 等单行和多行注释。\u003c/p\u003e\n\u003ch3 id=\"结果集去重-distinct\"\u003e结果集去重 \u003ccode\u003eDISTINCT\u003c/code\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-mysql\" data-lang=\"mysql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eDISTINCT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e列名\u003c/span\u003e\u003cspan class=\"w\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e表名\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003eDISTINCT\u003c/code\u003e 关键字限制所有的列，如果后接多列，除非两列内容完全相同，否则都会被纳入结果集。\u003c/p\u003e\n\u003ch3 id=\"限制结果-limit\"\u003e限制结果 \u003ccode\u003eLIMIT\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e大多用于分页显示：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-mysql\" data-lang=\"mysql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e-- 从第 0 行开始，显示 5 个。第一页：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e表名\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOFFSET\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"c1\"\u003e-- 从第 5 行开始，现实 5 个。第二页：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e表名\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOFFSET\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eMySQL、MariaDB、SQLite 简化语法：\u003c/p\u003e","title":"《SQL 必知必会》笔记"},{"content":" 虽然用了很久的 Git 了，但基本上只是 add、commit、push、pull，这次系统性的学习了一遍。\n整体是按照 Github 官方教程，由牛客网翻译的视频 的顺序排下来的。\n内容上外加网上的各种博文总结和补充了一些。\nSetup $ brew install git Config Git 希望知道每次提交的作者信息，来说明是谁进行的本次提交，这会随着版本迭代永久纳入历史记录中。\n$ git config --global user.name \u0026#34;my name\u0026#34; $ git config --global user.email xxx@example.com user.email 最好与 github 中的邮件地址相同，否则 push 后在 github 上并不会准确显示出是自己。\n配置文件： 在 ~/.gitconfig 中同样可以修改和查看上述配置，或修改 Git 全局忽略的位置信息等。\nSSH 配合 SSH Key 在 Github 中可以免去输入密码的环节。\n生成密钥：\n$ ssh-keygen -t rsa -C \u0026#34;youremail@example.com\u0026#34; 在 ~/.ssh/id_rsa.pub 中取得公钥并上传 GitHub。\nInit 创建本地仓库： $ git init Github 上创建仓库，可遵循 Github 的提示： create a new repository on the command line： echo \u0026#34;# test\u0026#34; \u0026gt;\u0026gt; README.md git init git add README.md git commit -m \u0026#34;first commit\u0026#34; git remote add origin https://github.com/xxx/test.git git push -u origin master git remote add origin https://github.com/xxx/test.git git push -u origin master status 查看状态：\n$ git status 可以查看目前所有文件的状态，改动文件较多时推荐使用更简洁易读的：\n$ git status -s ?? 新文件，未跟踪 A 新文件，已跟踪 M 修改 D 删除 接下来是 Git 的提交三部曲：\n新建或修改文件 加入到暂存区 提交到仓库 Add Add：将改动登记到暂存区： 单一文件的新建、修改、删除：\n$ git add filename 也可以一次性 add 所有变更：\n$ git add . 在简单操作中，add 被理解为把文件添加到暂存区没太大问题，但实际是它暂存的是修改而不是文件。\n$ echo aaa \u0026gt; file $ git add file $ echo bbb \u0026gt;\u0026gt; file $ git commit -m \u0026#34;bug fix\u0026#34; 上例中，只有 aaa 这一行的修改被暂存，所以版本库中只有 aaa，现在使用 diff 命令仍然可以看到 bbb 并没有被提交。\n关于 git add . 在谷歌前几页几乎所有的博客中都强调了这一点：\ngit add -A = git add -u + git add . （错误的，见下文）\ngit add . 将文件的修改、新建，登记到暂存区（错误的，见下文） git add -u 将文件的修改、删除，登记到暂存区 git add -A 将文件的修改、新建、删除，登记到暂存区 macOS 自带的 git 默认都是 2.20 版本了，在 stackoverflow 中的评论中看到，2.0 版本后 git add . 已经和 git add -A 效果相同。(https://stackoverflow.com/questions/15011311/whats-the-difference-between-git-add-u-and-git-add-a/27854048)\n所以在大部分情况，只需要记住 git add . 这一个命令就足够了。\nCommit commit: 将暂存区提交到版本库：\n$ git commit -m \u0026#34;message...\u0026#34; 如果不使用 -m 参数填写提交信息，git 会打开一个文本编辑器让你输入\n工作区、暂存区、仓库区 diff 在 GUI 中观察更为舒适，但下一章 diff 的三种比较模式可以让新手深入了解三大区的变更状态。\n工作区（Workspace）\n即你肉眼可见的项目目录。\n暂存区（Index/Stage）\n一般存放在 \u0026ldquo;.git目录下\u0026rdquo; 下的index文件（.git/index）中，所以我们把暂存区有时也叫作索引（index）。它保存了下次将提交的文件列表信息，Git 对暂存区在命名和命令上有多个名字，包括Index，Stage，Cache。\n本地仓库（Repository）\n版本库即 .git 这个隐藏目录，真正存储各版本代码库的地方。\n远程仓库（Remote）\n协作开发时或个人备份用，存储在 GitHub 等平台或自建 git 的远端仓库，可用于多方共同开发。\n日常操作与几大区的关系：\n-\u0026gt; 修改代码、新建文件等操作，工作区发生改动\n-\u0026gt; add：将改动内容\u0026quot;登记\u0026quot;到暂存区\n-\u0026gt; commit：将暂存区的所有内容提交到本地仓库。\n只有 commit 了，我们的代码才真正的进入到 git 仓库了。\n-\u0026gt; push: 将本地仓库推送到远程仓库\nDiff 三种比较模式 $ git diff 比较对象：工作区 与 暂存区(此时暂存区的内容是上一次提交的内容)\n使用情景：日常命令，看看这次改动了什么。\n$ git diff --staged $ git diff --cached # 效果同上 比较对象：暂存区 与 版本库(上一次提交的内容)\n使用情景： add 所有改动后，git diff 将不会显示任何东西了，在 commit 之前，仍可以使用 --staged 进行对比。\n$ git diff HEAD 比较对象：工作区 与 版本库(上一次提交的内容)\n使用情景：比如 add 后，又对这个文件进行了修改，在再次 add 之前，想看看在上一次提交之前都做了哪些改动。\n经过自己动手测试，通过 Diff 章节应该能基本掌握工作区、暂存区、版本库之间的关系了。\ndiff 修饰命令 diff 默认是按行显示区别的，这两个命令会获得一种对长行小改动而言更易读的报告：\n$ git diff --color-words $ git diff --word-diff 不输出代码改动，仅仅告诉你哪些文件遭遇了改动：\n$ git diff --stat Log 了解仓库的提交历史：\n$ git log 关于 40 位的 16 进制字符：(Git 保证完整性)\nGit 中所有数据在存储前都计算校验和，然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层，是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件，Git 就能发现。\nGit 用以计算校验和的机制叫做 SHA-1 散列（hash，哈希）。 这是一个由 40 个十六进制字符（0-9 和 a-f）组成的字符串，基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样：\n24b9da6552252987aa493b52f8696cd6d3b00373 Git 中使用这种哈希值的情况很多，你将经常看到这种哈希值。 实际上，Git 数据库中保存的信息都是以文件内容的哈希值来索引，而不是文件名。\n$ git log --oneline 每行一个简短的概要：标识符+提交信息\n$ git log --patch 在原始 log 显示内容的基础上，增加每次提交的代码改动情况。\n$ git log --stat 在原始 log 显示内容的基础上，增加每次提交的代码改动情况。(不输出代码改动，仅仅告诉你哪些文件遭遇了改动，类似 diff 中的 --stat 效果)\n$ git log -- directory/filename.ext 后接 -- 再接文件名，可以查看仅针对此文件的 log 记录。\n常用组合命令\n$ git log --graph --all --decorate --oneline 支持分支、标签的查看，快速了解整个项目的发展历程。\nRemove $ git rm 可以不用学习的命令，增删改都可以用 add 命令登记。\n$ git rm xxx 该命令完成两件事：\n删除文件 将删除文件这个操作\u0026rsquo;\u0026lsquo;登记\u0026rsquo;\u0026lsquo;到暂存区 如果你在本次变更中只进行了此次操作，可以直接 commit，不用再 add 登记了。\n如果你通过终端执行了 rm 操作 / 在编辑器或 IDE 中执行了删除操作 / 在电脑上直接删除文件：\n则只完成了第一步的内容，仍然可以通过 git rm xxx 命令将删除文件这个改动登记到暂存区。\n$ git rm --cached 这个命令将删除一个文件，但并不是从系统中真正的删除。只是告诉 git 请不要再跟踪这个文件，这个文件将仍然保留在我的工作区中。\n情景说明：当我使用 JetBrains 全家桶时，项目下面会有一个 .idea/ 的目录，里面也许会包含一些个人信息或无用信息，这个目录已经被纳入 git 管理了。\n目的：并不在本地删除 .idea/ 目录及其中文件，只是取消被 git 追踪。\n需配合 .gitignore 文件使用。\n创建 .gitignore 文件，写入一行内容：.idea/ 即可。 $ git rm -r --cached .idea/ （-r 是递归目录，如果只是单个文件可取消这个参数） add 与 commit 完成本次修改 以后即使 .idea/ 目录里面发生了文件的增删改，git 也不会理会。\nMove $ git mv file.ext xxx/file.ext 与 rm 类似，同时完成移动与 add。\n基本很少用到，一般都用系统自带的文件管理器或 IDE、编辑器来移动文件，然后 add 即可。\n建议使用情景：在同一次提交前，既修改了超过 50% 的代码，又想修改文件名。（参考忒修斯之船）\n$ git log --stat -M --follow directory/file.ext 加上 -M —follow 参数，可以 log 出文件的移动。\nShip of Theseus (忒修斯之船) 用忒修斯悖论来比喻代码修改：\n某些 CVS：当移动文件后，它认为只是一个完全不同的东西，无法追踪文件的移动过程。 某些企业版 CVS：每个文件都有标识，有个数据库来记录，可以轻易的追踪文件的移动。 Git：当一个文件至少有 50% 相似度时，这是同一个文件，小于 50% 时，这是一个新文件。 在移动并修改文件后 commit，Git 会反馈出一个百分比：\n[master 48f02f2] 本次提交信息 1 file changed, 0 insertions(+), 0 deletions(-) rename xxx =\u0026gt; xxx/xxx (100%) 100% 即代表是纯移动，未做修改。\n默认为 50%，低于这个阈值时，Git 会直接显示创建与删除：\n[master 9a28f41] 本次提交信息 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 xxx delete mode 100644 xxx/xxx 50% 这个默认数值是可以修改的，视频只是简单打了个示例代码并未详细说明，我觉得这可能是个几乎永远不会用到的功能。\nIgnore 创建 .gitignore 文件并写入规则，来使 Git 去忽略哪些你不想纳入版本控制的文件与文件夹。\n在被 gitignore 之前已经被 Git 追踪的文件不受 gitignore 规则的影响。\n比如 Python 生成的 __pycache__ 文件夹，JB 全家桶的 .idea 文件夹，macOS 的 .DS_Store 文件，都属于无用文件。或者存储了数据库密码的配置文件，是绝对不能纳入版本控制的。\n.gitignore 书写规则 # 注释行以 # 开头 # 文件名中有 # 怎么办 -\u0026gt; 加一个反斜杠转义 # 文件名中有 ! 怎么办 -\u0026gt; 加一个反斜杠转义 # 文件名最后有空格怎么办 -\u0026gt; 加一个反斜杠转义 # 忽略文件，直接书写文件名 .DS_Store # 忽略目录，以 / 结尾 # foo/ 会忽略 foo 目录及此目录下所有内容（但不忽略同名的 foo 文件） foo/ # 支持通配符 *，忽略所有以 .log 结尾的文件 *.log # 此文件除外 !a.log # 如果 a.log 父级目录被忽略，Git 并不会递归这个目录来寻找 a.log # 即如果 a.log 在 foo/ 中（foo/ 目录已被忽略），写这条规则也没用 # 忽略 bar/ 目录内除了 abc.txt 的文件 bar/* !abc.txt # 递归忽略所有 foo 文件和目录 **/foo # 递归忽略所有 foo 目录及其子目录下的 bar.txt 文件 foo/**/bar.txt 全局忽略 在 ~/.gitconfig 中查看全局忽略文件的配置（默认即可）：\n... [core] excludesfile = /Users/xxx/.gitignore_global ... 如果没有配置，可以复制粘贴上面的，或者：\n$ git config --global core.excludesfile ~/.gitignore_global 编辑 ~/.gitignore_global 文件，规则相同。\n在 macOS 中安装完 Git，默认的 .gitignore_global 应该是这样的：\n*~ .DS_Store 忽略了所有以 ~ 结尾的文件，忽略了所有 .DS_Store 文件。\n全局忽略适用于那些无论使用任何语言或 IDE 都需要忽略的文件，但是此文件只对自己有效，如果想让忽略规则对协作开发的所有成员有效，需要在项目目录正常建立 .gitignore 文件并纳入版本控制。\n查看当前已被忽略的所有内容 $ git ls-files --others --ignored --exclude-standard 强制 add 被 gitignore 忽略的文件 $ git add -f filename 检测 gitignore 规则 在日常 git add . 时发现某一文件并不想忽略，但是已经被忽略了，检测命令：\n$ git check-ignore -v filename Branch 查看分支 $ git branch 显示分支一览表，当前所在分支前面有 * 表示。\n创建分支 $ git branch 新分支名 删除分支 $ git branch -d 分支名 如果分支没有完全合并，Git 会抛出一个 error，提示你需要将 -d 改成 -D。\n切换分支 $ git checkout 分支名 Checkout 切换分支 $ git checkout 分支名 创建并切换分支 $ git checkout -b 分支名 相当于同时执行了 git branch 分支名 和 git checkout 分支名。\nDetached head (头指针分离) 先通过 log 查找到某一时刻的 commit 16 进制标识码。\n这个命令会让你的工作区会改变为这次提交时的状态：\n$ git checkout 12563de6382baaaaf78c58085b4b9abbe5b26608 Git 会提示：\n注意：正在检出 \u0026#39;12563de6382baaaaf78c58085b4b9abbe5b26608\u0026#39;。 您正处于分离头指针状态。您可以查看、做试验性的修改及提交，并且您可以通过另外 的检出分支操作丢弃在这个状态下所做的任何提交。 如果您想要通过创建分支来保留在此状态下所做的提交，您可以通过在检出命令添加 参数 -b 来实现（现在或稍后）。例如： git checkout -b \u0026lt;新分支名\u0026gt; HEAD 目前位于 12563de 本次的commit message 这时 checkout 命令相当于一个时光穿梭机，你可以检出任意一次提交时的状态。\n注意这不是版本回退。如果你强行修改 + add + commit，Git 会自动帮你创建一个分支。\n退出时光穿梭机：\n$ git checkout 分支名 Discarding edits (撤销修改) 见下面章节\nMerge 合并分支 $ git merge dev 将 dev 分支合并到当前分支，dev 分支会仍然存在。\nFast-forward 假设当前只有 master 分支 创建并切换到 dev 分支 进行了一次或 N 次的修改，但是 master 分支根本没人动 切换到 master 分支，合并 dev 分支 即便会导致冲突的地方，也会被 dev 分支的内容覆盖。\n这就是 Fast-forward （快进）合并模式，关键点在于 master 分支无人推进。\n缺点：历史记录是一条冗长的直线，删除分支后会丢失分支信息。\n解决冲突 当 master 和 dev 两条分支都并行推进的时候，在 master 分支合并 dev 分支时，如果同一行都被修改了，就会产生冲突。\n自动合并 xxx 冲突（内容）：合并冲突于 xxx 自动合并失败，修正冲突然后提交修正的结果。 冲突以 \u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt; ======= \u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; 隔开，分别展示两个分支的不同内容。\n\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt; HEAD master!!! ======= dev!!! \u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; dev 取其一或将这一整体变成你想要的内容即可。\n--abort $ git merge dev ... (发现冲突) $ git merge --abort --abort 选项会尝试恢复到你运行合并前的状态，相当于你没有进行本次合并。\n--suqash $ git merge --squash dev $ git commit -m \u0026#34;提交信息\u0026#34; 与直接合并结果相同，但是不提交、不移动 HEAD，因此需要一条额外的 commit 命令。\n合并后 master 分支很干净，只保留一条记录。\n删除 dev 分支后，dev 分支信息消失。\n--no-ff $ git merge --no-ff dev -m \u0026#34;提交信息\u0026#34; 禁用 Fast-forward 模式，这样在删除分支后也会保留分支信息。\n我觉得这个命令记录的提交内容比较全面且容易理解，但分支多的时候会让历史记录看起来比较混乱。\n删除 dev 分支后，dev 分支信息仍然保留。\nNetwork Remotes $ git remote add 远端名称 远端地址 # 例如： $ git remote add origin https://github.com/aaa/bbb # 修改 URL $ git remote set-url origin https://github.com/aaa/ccc # 删除远端链接 $ git remote rm 远端名称 # 例如： $ git remote rm origin # 查看所有远端链接 $ git remote -v # 查看所有远端分支名 $ git branch -r # 所有远端的分支前都加上了远端名称，例如 origin/master、origin/dev 终于知道 origin 到底是什么意思了。\n其实没什么意思，就是约定俗成的，如果你只有一个远端，比如这份代码只放在 Github 上，或只放在 码云 或 Coding 上，那就把远端起名叫 origin，这样大家看到了都懂。\n如果你这份代码在本地修改后，既要 push 到 Github，又要 push 到其它某平台，那两个远端名称就可以自己定制。\nFetch, Pull, Push $ git fetch origin master # 先拉取更新，fetch 不会更改本地工作区内容 $ git merge origin/master master # 将远程内容与本地内容合并 $ git pull origin master # 拉取并合并 $ git push origin master # 将本地内容推送到远程仓库 只有单个远程主机时，一般都命名为 origin。\n在任何分支第一次 push 时，Git 会提示：\nfatal: 当前分支 xxx 没有对应的上游分支。 为推送当前分支并建立与远程上游的跟踪，使用 git push --set-upstream origin xxx 你可以输入这个命令让本地分支与远程分支建立连接。\n也可以在每个分支的第一次 push 时使用 -u 参数：\n$ git push -u origin xxx 以后就可以使用简化命令 git push 了。\nPush 所有分支到远端：\n$ git push --all 有多个远程主机时，比如 Hexo、Hugo 博客可能同时会部署到 GitHub 和 Coding，也会起不同的远程主机名，这时 -u 参数可以指定一个默认主机，不带参数时就默认 push 到这个远程主机。\nGitHub 相关章节 GUI：主要是 GitHub Desktop 的介绍，我个人日常操作更喜欢用命令行，但是 GUI 在查看历史进度和 Diff 时更方便快捷。\nGitHub：GitHub 的相关介绍\nForking：GitHub 的 Fork 功能相关介绍。\nPull Requests：GitHub 的 Pull Requests 功能相关介绍。\nReset 见下面章节\n撤销修改与版本回退 必须理解的概念：\n三个区：工作区、暂存区、版本库，或三棵树：Working Directory、Index、HEAD。\n→ 改动代码，工作区改动\n→ add，将改动登记到暂存区\n→ commit，将暂存区提交到版本库，HEAD 指向当前分支的最后一次提交\n→ \u0026hellip;\n→ 又一次 commit，将暂存区提交到版本库，HEAD 依然指向当前分支的最后一次提交\nHEAD 是当前分支引用的指针，它总是指向该分支上的最后一次提交。 这表示 HEAD 将是下一次提交的父结点。 通常，理解 HEAD 的最简方式，就是将它看做 你的上一次提交 的快照。\n撤销修改 当你对修改不太满意，想恢复初始状态：\n# 单个文件撤销 $ git checkout -- 文件名 # 所有文件撤销 $ git checkout . 如果 add 进暂存区了，先撤销暂存区，再撤销工作区：\n# 单个文件： $ git reset HEAD 文件名 $ git checkout -- 文件名 # 多个文件： $ git reset HEAD $ git checkout . 如果 commit 进版本库了，那就用 reset 进行版本回退。\nReset reset 分为三种模式：\n--soft 保持本地所有改动（工作区、暂存区不变） --mixed 默认，保持工作副本但重置索引（工作区不变） --hard 丢弃所有改动 它们的主要区别在于作用覆盖的区域（工作区、暂存区）不一样，HEAD 的指向是必变的，在敲完命令后可以用 diff 的三种比较模式去验证。\n以一个例子来讲，这是目前的状况。\n$ git log --oneline 4a9dabc (HEAD -\u0026gt; master) 3 e285589 2 116eee9 1 $ git reset --soft e285589 工作区：无变化 暂存区：无变化 版本库：HEAD 指向此版本 $ git reset e285589 $ git reset --mixed e285589 # 同上 工作区：无变化 暂存区：变成此版本 版本库：HEAD 指向此版本 $ git reset --hard e285589 工作区：变成此版本 暂存区：变成此版本 版本库：HEAD 指向此版本 压缩提交 / 合并提交 例子：\n$ git log --oneline 900db85 (HEAD -\u0026gt; master) 修复刚才修复刚才修复错误导致的错误导致的错误 656915e 修复刚才修复错误导致的错误 2d7e668 修复错误 57335f5 5 ed32739 4 6a15af1 3 e285589 2 116eee9 1 我认为最后三次这种 commit message 应该合并成一个。\n$ git reset --soft 57335f5 HEAD 指向了\u0026quot;版本5\u0026quot;，但是工作区和暂存区都是目前的状态，直接 commit 即可。\n$ git commit -m \u0026#34;fixed a big bug\u0026#34; 再 log 查看：\n$ git log --oneline 5827469 (HEAD -\u0026gt; master) fixed a big bug 57335f5 5 ed32739 4 6a15af1 3 e285589 2 116eee9 1 除了用 reset，在图形化工具 GitHub Desktop 中，选中多个 commit 后点击“Squash n(选中的个数) Commit”，就可以将选中的 n 个提交合并成一个。\nTag 比起混乱的 commit id，标签可以更方便的标记出重要的版本。\n狗书《Flask Web 开发》作者配合使用 Tag 功能做了一个相当方便的时光穿梭机，比如第一章第一部分代码使用 1a 作为标签，第二章第三部分代码使用 2c 作为标签，读者只需执行 git checkout 2c 即可查看此次代码。\n查看所有标签：\n$ git tag 打标签：\n# 给最新的 commit 打标签： $ git tag 标签内容 # 给指定 commit ID 打标签，如： $ git tag 标签内容 116eee9 # 创建带有说明的标签，用-a指定标签名，-m指定说明文字，可用`git show 标签内容`查看： $ git tag -a v0.1 -m \u0026#34;version 0.1 released\u0026#34; 1094adb 删除标签：\n$ git tag -d 标签内容 删除远端标签：\n如果已经 push 到了 GitHub 上，想删除 GitHub 上的标签：\n$ git push --delete \u0026lt;远端名成\u0026gt; \u0026lt;标签名称\u0026gt; 例如：\n$ git push --delete origin v1.0 默认 push 时不推送标签，推送标签命令：\n# 推送单个标签 $ git push 标签内容 # 推送所有标签 $ git push --tags Rebase (变基) https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/rebase\n推荐看一些文章后用 https://learngitbranching.js.org/ 这个教程试一试。\n一个简洁的工作流教程：https://www.bilibili.com/video/BV19e4y1q7JJ\n补充 命令行显示 utf-8 字符 在 git status 等命令下使 Git 使用 utf-8 编码显示中文等字符，而不是\\123\\123\\123\\123 这样的格式。\n参考：https://stackoverflow.com/questions/22827239/how-to-make-git-properly-display-utf-8-encoded-pathnames-in-the-console-window\n$ git config core.quotepath off 全局：\n$ git config --global core.quotepath off 还原：off 改成 on。\nbisect 看到一个 git bisect 命令挺好玩的，用类似二分法去快速定位是哪次提交引起了当前的错误：\ngit bisect 命令教程 - 阮一峰的网络日志\n提交时关闭 issue 参考：https://stackoverflow.com/questions/60027222/github-how-can-i-close-the-two-issues-with-commit-message\n可以使用 close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved 等单词，如：\n$ git commit -m \u0026#34;巴啦巴啦； close #233\u0026#34; 可以同时关闭多个 issue：\n$ git commit -m \u0026#34;closes #1, closes #2, closes #3; YOUR COMMIT MESSAGE\u0026#34; ","permalink":"https://dvel.me/posts/git-summary/","summary":"\u003cblockquote\u003e\n\u003cp\u003e虽然用了很久的 Git 了，但基本上只是 add、commit、push、pull，这次系统性的学习了一遍。\u003c/p\u003e\n\u003cp\u003e整体是按照 \u003ca href=\"https://www.nowcoder.com/courses/2\" target=\"_blank\" rel=\"noopener\"\u003eGithub 官方教程，由牛客网翻译的视频\u003c/a\u003e 的顺序排下来的。\u003c/p\u003e\n\u003cp\u003e内容上外加网上的各种博文总结和补充了一些。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"setup\"\u003eSetup\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install git\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"config\"\u003eConfig\u003c/h2\u003e\n\u003cp\u003eGit 希望知道每次提交的作者信息，来说明是谁进行的本次提交，这会随着版本迭代永久纳入历史记录中。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git config --global user.name \u0026#34;my name\u0026#34;\n$ git config --global user.email xxx@example.com\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003euser.email 最好与 github 中的邮件地址相同，否则 push 后在 github 上并不会准确显示出是自己。\u003c/p\u003e\n\u003ch3 id=\"配置文件\"\u003e配置文件：\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003e~/.gitconfig\u003c/code\u003e 中同样可以修改和查看上述配置，或修改 Git 全局忽略的位置信息等。\u003c/p\u003e\n\u003ch3 id=\"ssh\"\u003eSSH\u003c/h3\u003e\n\u003cp\u003e配合 SSH Key 在 Github 中可以免去输入密码的环节。\u003c/p\u003e\n\u003cp\u003e生成密钥：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ ssh-keygen -t rsa -C \u0026#34;youremail@example.com\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在 \u003ccode\u003e~/.ssh/id_rsa.pub\u003c/code\u003e 中取得公钥并上传 GitHub。\u003c/p\u003e\n\u003ch2 id=\"init\"\u003eInit\u003c/h2\u003e\n\u003ch3 id=\"创建本地仓库\"\u003e创建本地仓库：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git init\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"github-上创建仓库可遵循-github-的提示\"\u003eGithub 上创建仓库，可遵循 Github 的提示：\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003ecreate a new repository on the command line：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eecho \u0026#34;# test\u0026#34; \u0026gt;\u0026gt; README.md\ngit init\ngit add README.md\ngit commit -m \u0026#34;first commit\u0026#34;\ngit remote add origin https://github.com/xxx/test.git\ngit push -u origin master\n\u003c/code\u003e\u003c/pre\u003e\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit remote add origin https://github.com/xxx/test.git\ngit push -u origin master\n\u003c/code\u003e\u003c/pre\u003e\u003cbr/\u003e\n\u003ch2 id=\"status\"\u003estatus\u003c/h2\u003e\n\u003cp\u003e查看状态：\u003c/p\u003e","title":"Git 自总结"},{"content":"协程初探 协程 - 廖雪峰 Python 教程\n多进程与多线程均由操作系统调度，不过协程由程序员在协程的代码里显式调度。\n协程没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。\nyield/send() 刚看廖老师协程一章的代码时是一脸懵逼，那么从 0 开始，了解 yield。\n10 年前的好文章： 深入理解 yield\n看完再回顾廖老师的 [生产者-消费者] 模型：\ndef c(): ... n = yield r ... def p(c): ... r = c.send(n) ... 终于理解 yield 表达式与send() 函数两者皆可发送与反馈，协同工作，相辅相成。\nsend(n)，p 发送了 n 给 c，c 怎么接收，yield 的返回值即是。\nyield r，c 反馈了 r 给 p，p 怎么接收，send() 的返回值即是。\n@asyncio.coroutine/yield from yield from 语法由 Python 3.3 引进。\n附：深入理解Python的yield from语法 ，摘抄部分代码：\n# 子生成器 def average_gen(): total = 0 count = 0 average = 0 while True: new_num = yield average count += 1 total += new_num average = total/count # 委托生成器 def proxy_gen(): while True: yield from average_gen() # 调用方 def main(): calc_average = proxy_gen() next(calc_average) # 预激下生成器 print(calc_average.send(10)) # 打印：10.0 print(calc_average.send(20)) # 打印：15.0 print(calc_average.send(30)) # 打印：20.0 if __name__ == \u0026#39;__main__\u0026#39;: main() asyncio 是 Python 3.4 版本引入的标准库，直接内置了对异步 IO 的支持。\n用 asyncio 提供的 @asyncio.coroutine 可以把一个 generator 标记为 coroutine 类型，然后在 coroutine 内部用 yield from 调用另一个 coroutine 实现异步操作。\n使用 yield from 关键字将一个 asyncio.Future 对象向下传递给事件循环，当这个 Future 对象还未就绪时，该协程就暂时挂起以处理其他任务。一旦 Future 对象完成，事件循环将会侦测到状态变化，会将 Future 对象的结果通过 send 方法方法返回给生成器协程，然后生成器恢复工作。\nimport asyncio @asyncio.coroutine def foo(): print(\u0026#39;foo start\u0026#39;) yield from asyncio.sleep(5) print(\u0026#39;foo end\u0026#39;) @asyncio.coroutine def bar(): print(\u0026#39;bar start\u0026#39;) yield from asyncio.sleep(10) print(\u0026#39;bar end\u0026#39;) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait([foo(), bar()])) loop.close() # 输出结果 # bar start # foo start # (等了5秒的IO操作) # foo end #（又等了5秒的IO操作） # bar end async/await Python3.5 中引入的新语法 async 和 await 可以让协程代码更简洁易读，也让协程表面上与生成器区分开。\n代码仅需进行简单的替换：\nimport asyncio async def foo(): print(\u0026#39;foo start\u0026#39;) await asyncio.sleep(5) print(\u0026#39;foo end\u0026#39;) async def bar(): print(\u0026#39;bar start\u0026#39;) await asyncio.sleep(10) print(\u0026#39;bar end\u0026#39;) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait([foo(), bar()])) loop.close() 另推荐一篇好文章：谈谈Python协程技术的演进\n","permalink":"https://dvel.me/posts/python-asynchronous-io/","summary":"\u003ch2 id=\"协程初探\"\u003e协程初探\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432090171191d05dae6e129940518d1d6cf6eeaaa969000\" target=\"_blank\" rel=\"noopener\"\u003e协程 - 廖雪峰 Python 教程\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e多进程与多线程均由操作系统调度，不过协程由程序员在协程的代码里显式调度。\u003c/p\u003e\n\u003cp\u003e协程没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。\u003c/p\u003e\n\u003ch2 id=\"yieldsend\"\u003eyield/send()\u003c/h2\u003e\n\u003cp\u003e刚看廖老师协程一章的代码时是一脸懵逼，那么从 0 开始，了解 \u003ccode\u003eyield\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e10 年前的好文章： \u003ca href=\"http://www.cnblogs.com/coderzh/articles/1202040.html\" target=\"_blank\" rel=\"noopener\"\u003e深入理解 yield\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e看完再回顾廖老师的 [生产者-消费者] 模型：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-pytho\" data-lang=\"pytho\"\u003edef c():\n\t...\n\tn = yield r\n\t...\n\ndef p(c):\n\t...\n\tr = c.send(n)\n\t...\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e终于理解 \u003ccode\u003eyield\u003c/code\u003e 表达式与\u003ccode\u003esend()\u003c/code\u003e 函数两者皆可发送与反馈，协同工作，相辅相成。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003esend(n)\u003c/code\u003e，p 发送了 \u003ccode\u003en\u003c/code\u003e 给 c，c 怎么接收，\u003ccode\u003eyield\u003c/code\u003e 的返回值即是。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eyield r\u003c/code\u003e，c 反馈了 \u003ccode\u003er\u003c/code\u003e 给 p，p 怎么接收，\u003ccode\u003esend()\u003c/code\u003e 的返回值即是。\u003c/p\u003e\n\u003ch2 id=\"asynciocoroutineyield-from\"\u003e@asyncio.coroutine/yield from\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eyield from\u003c/code\u003e 语法由 Python 3.3 引进。\u003c/p\u003e\n\u003cp\u003e附：\u003ca href=\"https://juejin.im/posts/5b3af9fb51882507d4487144\" target=\"_blank\" rel=\"noopener\"\u003e深入理解Python的yield from语法 \u003c/a\u003e ，摘抄部分代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 子生成器\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eaverage_gen\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003etotal\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eaverage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003enew_num\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eyield\u003c/span\u003e \u003cspan class=\"n\"\u003eaverage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003etotal\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003enew_num\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eaverage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etotal\u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 委托生成器\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eproxy_gen\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eyield from\u003c/span\u003e \u003cspan class=\"n\"\u003eaverage_gen\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 调用方\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecalc_average\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eproxy_gen\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003enext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecalc_average\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e            \u003cspan class=\"c1\"\u003e# 预激下生成器\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecalc_average\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# 打印：10.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecalc_average\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# 打印：15.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecalc_average\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e30\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# 打印：20.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"vm\"\u003e__name__\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;__main__\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003easyncio  \u003c/code\u003e是 Python 3.4 版本引入的标准库，直接内置了对异步 IO 的支持。\u003c/p\u003e","title":"Python 异步 IO 笔记"},{"content":" 终于肝完了主题医院的精神续作——双点医院。。。\n太肝了。。。\n这一代的病人依然没有摒弃「请病人不要死在走廊上」的优良传统，如果你把一个病人治死了，他会坚持换完衣服走出病房，然后再在走廊死掉，再化为鬼魂，为周围的病人启动一个「加速行走」的Buff。。。\n因为这个加速行走的Buff，我甚至都不招聘有抓鬼技能的员工了。\n游戏进程 入场 接待 诊断 治疗 离场 中途可能包含「愤怒离开」「治疗效果不佳」「死亡」。\n在接受治疗前就死亡，是因为排队排太久，健康值降为 0。\n愤怒离开的主要原因是心情降为 0。\n诊断流程 （妈的智障） → 全科 → 诊断 → 全科 → 诊断 → 全科 → 治疗\n如果第一次全科就100%，直接治疗。\n即便到诊断室已经100%了，病人也会再次返回全科。（大夫可能是说你去照个X光回来给我看看）\n如果已有的诊断室已经用完，仍没到100%，会发出消息，问你是送回家、等待、治疗？\n在后期基本只有这两种情况：\n进场 → 全科 → 治疗 → 离场或死亡\n进场 → 全科 → 某个诊断室 → 全科 → 治疗 → 离场或死亡\n全科技能跟上的话，很少有第三次复诊。\n科室 设施 护士 医生 接待处 药房 3 x 3 【全科】 3 x 3 休息室 【综合诊断】 3 x 3 【精神病学】 3 x 3 精神学 厕所 【心脏病科】 3 x 3 脱光诊所 3 x 3 培训 注射室 3 x 3 研究 【体液分析】 3 x 3 【DNA实验室】 4 x 3 遗传学 营销学 咖啡厅 【病房】 4 x 3 流行锅实验室 4 x 4 骨科病房 4 x 3 拔头室 4 x 4 色疗室 4 x 3 电疗 4 x 4 木乃伊 4 x 3 分辨率 4 x 4 【X 光】 4 x 4 有害动物 4 x 4 【超级磁力共振】 4 x 4 放射学 小丑诊所 4 x 4 折疗室 5 x 3 手术室（医+护） 4 x 3 外科学 上表【 】中为具有诊断功能的科室。\n加粗项「病房」「精神病」「DNA」都是既可以诊断又可以治疗的。\n培训室：一个就够，至少弄 50 个 4% 加成的书柜，增加培训效率。 研究：一个都不要，之前地图的研究是通用的。（你在这关如果有新研究，回老地图研发也是可以的） 房间等级，5 级封顶，豪华房间对员工有加成，￥300 的奖章是最高性价比。\n人物需求 人生在世，无外乎吃喝玩乐。\n温度 卫生 上面两个洗手液和暖气/空调可以简单解决。\n吃 喝 玩 售货机解决吃喝。\n游戏机解决玩。\n咖啡厅可以同时解决「吃」和「喝」，并赐予一个开心 Buff。\n厕所 如果你建了一些吃喝建筑，但没有厕所。。。\n他就会把新鲜的大便拉到地上，地上时而出现的一滩水就是病人撒的尿。\n技能选择 简单来说，方便管理的话。。。\n因为后期全科技能很高，一个往返基本能就诊断 100%。\n勤杂工：留一个升级，剩下全维护。 客服：无脑接待 护士：全部治疗，不要诊断，无需任何管理操作，自动轮换。 医生：全部治疗，不要诊断，无需任何管理操作，自动轮换。 这么玩主要还是因为放弃了很多诊断室，治疗技能是为了保障治愈率。\n其中需要规划一下全科大夫，全部加全科，只负责全科科室，20级以下的医院十个足够。\n核心战略 让员工开心，Buff 加成，咖啡厅 + 休息室 + 厕所 + 5级全科科室。（咖啡厅与厕所设置成只允许员工使用） 科室里不放咖啡机和零食，让员工休息时去咖啡厅吃喝。\n让病人迅速滚蛋，不要让他吃、喝、玩乐、拉撒，150天内要么把他治好，要么把他治死。 这是一个塔防游戏。\n让病人保持高效率，除了已经避免的吃喝和上厕所，长椅也不摆，让病人在排队时一直排排站好。\n无论病人得了什么病，任何诊断室（包括全科）都能检查出来\n地域分配——集中诊断：集中全科与诊断室，让病人走最少的步数完成诊断。\n治疗区：随便放，放远处，这是病人的最后一步，在进入治疗室付款前别死了就行。\n舍弃无用的诊断室，「病房」、「精神」、「DNA」充当诊断室。\n为保持循环效率，「病房」的床位、「精神」与「DNA」的数量要适当增加。\n超级磁力共振是收费最高的诊断科室，可以考虑。\n前期迅速赚钱战略 落地：一接待一全科一病房。\n除了病房这样的，全部按最小空间建造，方便后期调整位置。\n全科慢慢增加。\n病房吞吐量大，多弄几个护士和床位。\n然后一个一个的补治疗室，先不补「精神」和「DNA」。\n病人在完成「全科 → 病房 → 全科」这个诊断流程后就会弹出信息，诊断率只有xxx，治疗还是送回家？送去治疗就好，前期不要在乎治愈率，能赚钱就好。\n期间招聘跟上，然后完善科室就可以了，这样是稳赚不赔的。\n在满足人员配置后，一次性补足「精神」和「DNA」，如果先补这俩但是数量不足，病人就会去排大长队。\n所有规划完毕后，上培训，慢慢就进入后期了。\n摩天塔通关配置 中间为集中诊断区，左下为治疗区，右下就放了个培训室。\n这是我第三次干摩天塔了，之前铺的满地图都是，13 个场地铺满 9 个了，然后铺烦了删档重来了。\n这个低配简配，本来是想着舍弃外围 8 个场地，只玩内围 4 个场地的，没想到直接干到通关了。\n全科：8 个房间，10 个员工。\n精神：4 个房间，4 个员工。\nDNA：4 个房间，4 个员工。\n病房：1 个 6 床及以上的房间，4 个及以上的员工，因为员工老瞎溜达，效率不够，人数来凑。\n每个治疗室 1 个，员工自己可以补三四个轮休的。\n手术室太费时间，适当增加。\n等级压到 20 级以下，这样全科不会产生排队。\n评价 差评。\n没有「房间模板」或「复制房间」这个功能。（关键点，有这个功能就是好评） 前期造全科就够烦的了。\n最后一关摩天塔，我第一次想铺开玩大医院，病人数量增加的太多，没有复制功能烦的我重新开档了。\n价格偏高，关卡游戏性重复。\n伤肝。。。\n没有一键「让所有已诊断病人滚去治疗」选项，前期拥堵的时候得一个一个点。\n人物 AI 智障\n比如病房排队人多的时候，有人同时开门和关门，能把人挤出去。\n休息室、培训室这种大量进出，员工都跟傻子似的，开关门效率低。\n病房的屏风，如果你在门左右各方一个，病人只会去右边的，即便左边是空的，病人还会去右边排队，除非右边已经有人排队，他才会去左边的，利用效率低下。\n排队，科室没有病人，2 号位已经站在门前，1 号位刚拉完屎从远方赶来，2 号位就干等着他。\n如果你仔细看一会病房，包括骨科，护士们的治疗效率真是太低了急死人，各种不知所谓乱走动。\n各种 BUG，据说病房 BUG 已经修复，这个 BUG 是真tm烦。 逼死强迫症！ 最后一关了，45 星全部到手了，玩家要真真正正的开始创造大医院了，不能复制房间我都忍了。\n结果最后一关居然是不对称的。。。最外围有两处和别的长得不一样，偏小还少了个门。\n管理方式弱智 玩过 Rimworld 后很难接受这种糟糕的管理方式了，尤其是最后一关铺大医院的时候，我需要统计全科的员工人数、精神和DNA的员工人数，病房专属的员工人数等等来方便我招聘，你只能一页一页的翻。\n逼得我自己使用表格进行管理，如图。。。：\n绿底色为【诊断】，红色字为【诊断+治疗】\n表格我放谷歌文档上了 https://docs.google.com/spreadsheets/d/1n93n7JlrkRTsPIibfZGoCDb4gzwXMyQmjeulHPflnJk/edit?usp=sharing\n","permalink":"https://dvel.me/posts/goodbye-two-point-hospital/","summary":"\u003cblockquote\u003e\n\u003cp\u003e终于肝完了主题医院的精神续作——双点医院。。。\u003c/p\u003e\n\u003cp\u003e太肝了。。。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e这一代的病人依然没有摒弃「请病人不要死在走廊上」的优良传统，如果你把一个病人治死了，他会坚持换完衣服走出病房，然后再在走廊死掉，再化为鬼魂，为周围的病人启动一个「加速行走」的Buff。。。\u003c/p\u003e\n\u003cp\u003e因为这个加速行走的Buff，我甚至都不招聘有抓鬼技能的员工了。\u003c/p\u003e\n\u003ch2 id=\"游戏进程\"\u003e游戏进程\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e入场\u003c/li\u003e\n\u003cli\u003e接待\u003c/li\u003e\n\u003cli\u003e诊断\u003c/li\u003e\n\u003cli\u003e治疗\u003c/li\u003e\n\u003cli\u003e离场\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e中途可能包含「愤怒离开」「治疗效果不佳」「死亡」。\u003c/p\u003e\n\u003cp\u003e在接受治疗前就死亡，是因为排队排太久，健康值降为 0。\u003c/p\u003e\n\u003cp\u003e愤怒离开的主要原因是心情降为 0。\u003c/p\u003e\n\u003ch2 id=\"诊断流程-妈的智障\"\u003e诊断流程 （妈的智障）\u003c/h2\u003e\n\u003cp\u003e→ 全科 → 诊断 → 全科 → 诊断 → 全科 → 治疗\u003c/p\u003e\n\u003cp\u003e如果第一次全科就100%，直接治疗。\u003c/p\u003e\n\u003cp\u003e即便到诊断室已经100%了，病人也会再次返回全科。（大夫可能是说你去照个X光回来给我看看）\u003c/p\u003e\n\u003cp\u003e如果已有的诊断室已经用完，仍没到100%，会发出消息，问你是送回家、等待、治疗？\u003c/p\u003e\n\u003cp\u003e在后期基本只有这两种情况：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e进场 → 全科 → 治疗 → 离场或死亡\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e进场 → 全科 → 某个诊断室 → 全科 → 治疗 → 离场或死亡\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e全科技能跟上的话，很少有第三次复诊。\u003c/p\u003e\n\u003ch2 id=\"科室\"\u003e科室\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: left\"\u003e设施\u003c/th\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e护士\u003c/th\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e医生\u003c/th\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e接待处\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e药房\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【全科】\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e休息室\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【综合诊断】\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e【精神病学】\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e精神学\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e厕所\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【心脏病科】\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e脱光诊所\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e培训\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e注射室\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e研究\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【体液分析】\u003c/td\u003e\n          \u003ctd\u003e3 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e【DNA实验室】\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e遗传学\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e营销学\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e咖啡厅\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e【病房】\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e流行锅实验室\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e骨科病房\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e拔头室\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e色疗室\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e电疗\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e木乃伊\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e分辨率\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【X 光】\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e有害动物\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e【超级磁力共振】\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e放射学\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e小丑诊所\u003c/td\u003e\n          \u003ctd\u003e4 x 4\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e折疗室\u003c/td\u003e\n          \u003ctd\u003e5 x 3\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e手术室（医+护）\u003c/td\u003e\n          \u003ctd\u003e4 x 3\u003c/td\u003e\n          \u003ctd\u003e外科学\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e上表【 】中为具有诊断功能的科室。\u003c/p\u003e","title":"再见，双点医院！"},{"content":"需求 需求是这样的：\n我的博客是 dvel.me，已经部署在 Coding Pages 或 Github Pages 上，域名解析用的是 CNAME 记录。 我希望我的域名邮箱是后缀是 @dvel.me，域名解析用的是 MX 记录。 冲突了。。。 @\tCNAME\t-\tpages.coding.me @\tMX\t1\taspmx.l.google.com 因为都用了裸域，如果要放弃裸域，采用 www.dvel.me 又觉得强迫症，Coding 又不提供 A 解析。\n用 CloudXNS 快速解决 CloudXNS 有一个 LINK 记录：\nLINK：CloudXNS的私有类型，可将用户配置的CNAME隐藏。 别名链接记录，隐式将解析权委托给目标域名。 官方详解：CloudXNS之详解LINK记录\n需要额外使用一个域名，假设这个域名为 another.com。\n将裸域的 CNAME 记录改成 LINK，记录值为 @another.com：\n@\tLINK\t-\t@another.com @\tMX\t1\taspmx.l.google.com 进入 another.com 的解析设置页面正常设置：\n@\tCNAME\t-\tpages.coding.me 以上，相当于绕了个弯。\n我用的是 Coding Pages 与 G Suite，博客访问与邮件收发均无问题。\n","permalink":"https://dvel.me/posts/use-cloudxns-solve-cname-mx-conflict/","summary":"\u003ch2 id=\"需求\"\u003e需求\u003c/h2\u003e\n\u003cp\u003e需求是这样的：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e我的博客是 dvel.me，已经部署在 Coding Pages 或 Github Pages 上，域名解析用的是 \u003cstrong\u003eCNAME\u003c/strong\u003e 记录。\u003c/li\u003e\n\u003cli\u003e我希望我的域名邮箱是后缀是 @dvel.me，域名解析用的是 \u003cstrong\u003eMX\u003c/strong\u003e 记录。\u003c/li\u003e\n\u003cli\u003e冲突了。。。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e@\tCNAME\t-\tpages.coding.me\n@\tMX\t1\taspmx.l.google.com\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e因为都用了裸域，如果要放弃裸域，采用 \u003ccode\u003ewww.dvel.me\u003c/code\u003e 又觉得强迫症，Coding 又不提供 A 解析。\u003c/p\u003e\n\u003ch2 id=\"用-cloudxns-快速解决\"\u003e用 CloudXNS 快速解决\u003c/h2\u003e\n\u003cp\u003eCloudXNS 有一个 \u003cstrong\u003eLINK\u003c/strong\u003e 记录：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eLINK：CloudXNS的私有类型，可将用户配置的CNAME隐藏。\n别名链接记录，隐式将解析权委托给目标域名。\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e官方详解：\u003ca href=\"https://www.cloudxns.net/Support/detail/id/126.html\" target=\"_blank\" rel=\"noopener\"\u003eCloudXNS之详解LINK记录\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e需要额外使用一个域名，假设这个域名为 another.com。\u003c/p\u003e\n\u003cp\u003e将裸域的 \u003cstrong\u003eCNAME\u003c/strong\u003e 记录改成 \u003cstrong\u003eLINK\u003c/strong\u003e，记录值为 \u003ccode\u003e@another.com\u003c/code\u003e：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e@\tLINK\t-\t@another.com\n@\tMX\t1\taspmx.l.google.com\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e进入 another.com 的解析设置页面正常设置：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e@\tCNAME\t-\tpages.coding.me\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e以上，相当于绕了个弯。\u003c/p\u003e\n\u003cp\u003e我用的是 Coding Pages 与 G Suite，博客访问与邮件收发均无问题。\u003c/p\u003e","title":"用 CloudXNS 解决 CNAME 与 MX 记录冲突"},{"content":"曾经升级完 Node 后对 Hexo 一顿折腾，感觉有点麻烦，新 MBP 入手后懒得再折腾一遍，想换到 Hugo 试试。\nQuick Start 安装： $ brew install hugo 查看： $ hugo version 建站： $ hugo new site site-name 快速添加主题： （以我正在使用的 Jane 为例）\n$ cd site-name $ git init $ git clone https://github.com/xianmin/hugo-theme-jane.git --depth=1 themes/jane $ echo \u0026#39;theme = \u0026#34;jane\u0026#34;\u0026#39; \u0026gt;\u0026gt; config.toml 写博客： 页面：\n$ hugo new page-name.md 文章：\n$ hugo new posts/post-name.md 预览、调试： $ hugo server $ hugo server -D # 将标记为 draft: true 的草稿也生成预览 浏览器打开 http://localhost:1313/ 即可预览。\n生成： $ hugo 生成速度超级快！\n部署： 将 public 中所有内容部署到 Github Pages 等即可。\nURL 管理 我喜欢这样的 url ：dvel.me/posts/1 dvel.me/posts/2 \u0026hellip;\n编辑 config.toml ，修改或增加：\n[permalinks] post = \u0026#34;/posts/:slug\u0026#34; 在文章的 Front Matter 中新增 slug 并正确填写即可。\n也可以参考官方文档的 URL Management 修改成 \u0026quot;/posts/:year-:month-:day\u0026quot; 等各种格式。\nFront Matter 支持 YAML、TOML、JSON 格式，推荐使用 YAML 格式，可以少敲一些引号。\n编辑 \u0026lt;your site\u0026gt;/archetypes/default.md 文件可以设定模板，使用 $ hugo new page-name.md 命令后可以自动生成。\n--- title: {{ replaceRE \u0026#34;[0-9]{2,}\u0026#34; \u0026#34;\u0026#34; .Name | replaceRE \u0026#34;^-*\u0026#34; \u0026#34;\u0026#34; | replaceRE \u0026#34;-\u0026#34; \u0026#34; \u0026#34; | title }} author: Dvel date: {{ .Date }} lastmod: tags: - draft: true --- 参考 \u0026amp; 感谢 Hugo 从入门到会用 ","permalink":"https://dvel.me/posts/hello-hugo/","summary":"\u003cp\u003e曾经升级完 Node 后对 Hexo 一顿折腾，感觉有点麻烦，新 MBP 入手后懒得再折腾一遍，想换到 Hugo 试试。\u003c/p\u003e\n\u003ch2 id=\"quick-start\"\u003eQuick Start\u003c/h2\u003e\n\u003ch3 id=\"安装\"\u003e安装：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install hugo\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"查看\"\u003e查看：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo version\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"建站\"\u003e建站：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo new site site-name\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"快速添加主题\"\u003e快速添加主题：\u003c/h3\u003e\n\u003cp\u003e\u003cem\u003e（以我正在使用的 Jane 为例）\u003c/em\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ cd site-name\n$ git init\n$ git clone https://github.com/xianmin/hugo-theme-jane.git --depth=1 themes/jane\n$ echo \u0026#39;theme = \u0026#34;jane\u0026#34;\u0026#39; \u0026gt;\u0026gt; config.toml\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"写博客\"\u003e写博客：\u003c/h3\u003e\n\u003cp\u003e页面：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo new page-name.md\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e文章：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo new posts/post-name.md\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"预览调试\"\u003e预览、调试：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo server\n$ hugo server -D  # 将标记为 draft: true 的草稿也生成预览\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e浏览器打开 \u003ca href=\"http://localhost:1313/\" target=\"_blank\" rel=\"noopener\"\u003ehttp://localhost:1313/\u003c/a\u003e 即可预览。\u003c/p\u003e\n\u003ch3 id=\"生成\"\u003e生成：\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ hugo\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e生成速度超级快！\u003c/p\u003e","title":"你好，Hugo！"},{"content":" 折腾完，做个备忘\n样图：\niTerm 2 主题 Tomorrow Night - Tomorrow Night Eighties\nHotkey Window 我习惯只保留一个窗口，并使用 shift+空格 来从左侧或上侧呼出，在 Profiles - Window - Style 可以设置。\n呼出的快捷键在 Profiles → Keys → Hotkey Window 设置。\nNatural Text Editing Profiles → Keys → Presets → Natural Text Editing\n这个可以让你在输入时使用 command/option + ←/→ 来移动光标\nzsh： zsh 有很多优点，比如兼容 !#/bin/bash，更强大的 tab 补全功能，大小写自动更正，丰富的主题，命令智能纠错等等。\n现在 macOS 默认就是 zsh 而不是 bash 了，不过我习惯不使用系统自带的东西，可以用 brew 自己装一个。\n$ brew install zsh 查看当前已经安装的 shell：\n$ cat /etc/shells 将 /usr/local/bin/zsh 加入到 /etc/shells 中：\n$ sudo sh -c \u0026#34;echo $(which zsh) \u0026gt;\u0026gt; /etc/shells\u0026#34; 设置默认 shell：\n$ chsh -s $(which zsh) 重启终端，查看默认 shell：\n$ echo $SHELL /usr/local/bin/zsh OK.\noh-my-zsh： oh-my-zsh 是一款社区驱动的、基于 zsh 的的扩展工具集，用它可以方便的更新和定制 zsh，提供了方便的主题配置、插件配置和一些内置的便捷操作。\n安装：\n$ sh -c \u0026#34;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; 安装后出现目录 ~/.oh-my-zsh/ 及配置文件 ~/.zshrc。\nzsh 主题 powerlevel9k： $ git clone https://github.com/bhilburn/powerlevel9k.git ~/.oh-my-zsh/custom/themes/powerlevel9k 设置主题，编辑 ~/.zshrc：\nZSH_THEME=\u0026#34;powerlevel9k/powerlevel9k\u0026#34; 重启终端，OK。\n如果字体显示问号，需要换成 powerline font 字体。\n快速安装一个 powerline font：\n$ brew cask install homebrew/cask-fonts/font-hack 在 iTerm 2 中更换字体。\noh-my-zsh 插件 /Users/user/.oh-my-zsh/plugins 是官方自带插件，可自行激活。\n/Users/user/.oh-my-zsh/custom/plugins 是第三方插件，等同于 $ZSH_CUSTOM/plugins，可以用 git 将一些插件 clone 到这个地方。\n另一种安装第三方插件的方法：某些插件可以用 brew 安装。\n使用下面的方法进行安装和启用。\n$ brew install zsh-syntax-highlighting # 高亮 $ brew install zsh-autosuggestions # 根据历史输入的补全建议 遵循提示，在 ~/.zshrc 中加入以下语句：\nsource /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh source /usr/local/share/zsh-autosuggestions/zsh-autosuggestions.zsh $ source ~/.zshrc 使之生效。（试了并不成功，非得重启 iTerm 才行）\n一些配置 编辑 ~/.zshrc：\n# 激活自带插件，一行写一个 plugins=( git z ) # 解决 powerlevel9k 主题下的 Python 虚拟环境没有提示： POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(status virtualenv) # 左侧主机名，默认是`%n@%m` 用户名@电脑名，可以改成自己喜欢的。 POWERLEVEL9K_CONTEXT_TEMPLATE=\u0026#34;\u0026#34; 一些终端代理方法：包括 http(s) 和 ssh（比如 git）。 配置 Mac 终端走代理\n参考 \u0026amp; 感谢 超簡單！十分鐘打造漂亮又好用的 zsh command line 環境 ","permalink":"https://dvel.me/posts/build-zsh-command-line-environment-for-mac/","summary":"\u003cblockquote\u003e\n\u003cp\u003e折腾完，做个备忘\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e样图：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2018-07-30.webp\"\n            alt=\"zsh\"\n            width=\"2000\"\n            height=\"1184\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e\n\u003ch2 id=\"iterm-2\"\u003eiTerm 2\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e主题\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/chriskempson/tomorrow-theme\" target=\"_blank\" rel=\"noopener\"\u003eTomorrow Night\u003c/a\u003e - Tomorrow Night Eighties\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eHotkey Window\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我习惯只保留一个窗口，并使用 \u003cstrong\u003eshift+空格\u003c/strong\u003e 来从左侧或上侧呼出，在 Profiles - Window - Style 可以设置。\u003c/p\u003e\n\u003cp\u003e呼出的快捷键在 Profiles → Keys → Hotkey Window 设置。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eNatural Text Editing\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eProfiles → Keys → Presets → Natural Text Editing\u003c/p\u003e\n\u003cp\u003e这个可以让你在输入时使用 command/option + ←/→ 来移动光标\u003c/p\u003e\n\u003ch2 id=\"zsh\"\u003ezsh：\u003c/h2\u003e\n\u003cp\u003ezsh 有很多优点，比如兼容 \u003ccode\u003e!#/bin/bash\u003c/code\u003e，更强大的 tab 补全功能，大小写自动更正，丰富的主题，命令智能纠错等等。\u003c/p\u003e\n\u003cp\u003e现在 macOS 默认就是 zsh 而不是 bash 了，不过我习惯不使用系统自带的东西，可以用 brew 自己装一个。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install zsh\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e查看当前已经安装的 shell：\u003c/p\u003e","title":"为 Mac 打造 zsh command line 环境"},{"content":" 新 MBP 到手后，我就预感要折腾好一阵子，因为之前把系统整的太凌乱，决定不使用 Time Machine，从头开始对 MBP 新装新居。\n记录一下，为了以后再次更换设备时参考。\n再次记录一下。。。因为苹果莫名其妙的 BUG 导致新电脑无法从时光机器中恢复，只好重头折腾。\n偏好设置 系统所有偏好设置\n通用：关闭文稿时要求保存更改 Dock：将窗口最小化为应用程序图标，连按最小化 吮吸效果：defaults write com.apple.dock mineffect suck; Killall Dock 添加空白格： defaults write com.apple.dock persistent-apps -array-add '{\u0026quot;tile-type\u0026quot;=\u0026quot;spacer-tile\u0026quot;;}'; Killall Dock 更小的空白格：defaults write com.apple.dock persistent-apps -array-add '{\u0026quot;tile-type\u0026quot;=\u0026quot;small-spacer-tile\u0026quot;;}'; Killall Dock 堆栈区网格高亮：defaults write com.apple.dock mouse-over-hilite-stack -bool TRUE;killall Dock 调度中心：关闭仪表盘（新版已经没有了），设置触发角（右下角显示桌面） 触摸板：滚动方向 Siri：关闭 辅助功能 - 指针控制（或鼠标与触控板） - 触控板选项：启动拖移(三指拖移) Finder 偏好设置\n边栏调整 显示所有文件扩展名 显示 - 显示各种栏 标题栏显示完整路径：defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES;killall Finder 部分快捷键重设（个人偏好）\n双击 command：Alfred 双击 option：Alfred 剪贴板 command + 空格：切换输入法 option + 空格：Alfred - File search - Navigation control + 空格：spotlight shift + 空格：iTerm 禁用大部分 iCloud 同步\n先安装能快速还原使用习惯的App 提前挂好 Xcode 的下载，这个比较大 代理工具 Surge 同步网盘 Dropbox 输入法 Rime，还原配置，同步用户词典 浏览器 Firefox / Chrome 一般是自动同步，像油暴力猴、uBlacklist等插件是可以和 Dropbox 同步配置的 Alfred 密码管理器 Bitwarden 邮箱 Spark 如果没有用时间机器恢复，也可以从未加密的备份盘中找回备份的文件，直接复制粘贴。\n至此，基本上只差功能性App了，大部分的使用习惯都找了回来。\nDropbox 可以保存的一些配置：\nAlfred 设置 JB 家的设置文件（换到云同步了） 代码碎片 IINA 的快捷键设置 个别浏览器插件的配置 App库 开始一个一个的下载App，这时才发现还是 Time Machine 好啊。\n也需要注意个别 App 的反激活与同步。\nNTFS 需要在官网反激活一下，看到 Licences 有点变化（好像被微软收购了） Microsoft NTFS for Mac by Paragon Software 新版可用的 Paragon NTFS For Mac 14 (Multilingual) 好像是曾经的叫法，已不可用，下载14也无法打开 参考老Mac导出的App列表，由于数量庞大几乎大部分时间都花在App的下载与设置上了。\n配置 command line 一步一步重新折腾。\niTerm homebrew zsh oh-my-zsh powerlevel9k zsh-syntax-highlighting 其他一些插件 brew 一些开发包 完事了，洗洗睡了 ","permalink":"https://dvel.me/posts/new-mac-new-decoration/","summary":"\u003cblockquote\u003e\n\u003cp\u003e新 MBP 到手后，我就预感要折腾好一阵子，因为之前把系统整的太凌乱，决定不使用 Time Machine，从头开始对 MBP 新装新居。\u003c/p\u003e\n\u003cp\u003e记录一下，为了以后再次更换设备时参考。\u003c/p\u003e\n\u003cp\u003e再次记录一下。。。因为苹果莫名其妙的 BUG 导致新电脑无法从时光机器中恢复，只好重头折腾。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"偏好设置\"\u003e偏好设置\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e系统所有偏好设置\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通用：关闭文稿时要求保存更改\u003c/li\u003e\n\u003cli\u003eDock：将窗口最小化为应用程序图标，连按最小化\n\u003cul\u003e\n\u003cli\u003e吮吸效果：\u003ccode\u003edefaults write com.apple.dock mineffect suck; Killall Dock\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e添加空白格：\u003ccode\u003e defaults write com.apple.dock persistent-apps -array-add '{\u0026quot;tile-type\u0026quot;=\u0026quot;spacer-tile\u0026quot;;}'; Killall Dock\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e更小的空白格：\u003ccode\u003edefaults write com.apple.dock persistent-apps -array-add '{\u0026quot;tile-type\u0026quot;=\u0026quot;small-spacer-tile\u0026quot;;}'; Killall Dock\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e堆栈区网格高亮：\u003ccode\u003edefaults write com.apple.dock mouse-over-hilite-stack -bool TRUE;killall Dock\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e调度中心：关闭仪表盘（新版已经没有了），设置触发角（右下角显示桌面）\u003c/li\u003e\n\u003cli\u003e触摸板：滚动方向\u003c/li\u003e\n\u003cli\u003eSiri：关闭\u003c/li\u003e\n\u003cli\u003e辅助功能 - 指针控制（或鼠标与触控板） - 触控板选项：启动拖移(三指拖移)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eFinder 偏好设置\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e边栏调整\u003c/li\u003e\n\u003cli\u003e显示所有文件扩展名\u003c/li\u003e\n\u003cli\u003e显示 - 显示各种栏\u003c/li\u003e\n\u003cli\u003e标题栏显示完整路径：\u003ccode\u003edefaults write com.apple.finder _FXShowPosixPathInTitle -bool YES;killall Finder\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部分快捷键重设（个人偏好）\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e双击 command：Alfred\u003c/li\u003e\n\u003cli\u003e双击 option：Alfred 剪贴板\u003c/li\u003e\n\u003cli\u003ecommand + 空格：切换输入法\u003c/li\u003e\n\u003cli\u003eoption + 空格：Alfred - File search - Navigation\u003c/li\u003e\n\u003cli\u003econtrol + 空格：spotlight\u003c/li\u003e\n\u003cli\u003eshift + 空格：iTerm\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e禁用大部分 iCloud 同步\u003c/p\u003e","title":"新 Mac 新装修"},{"content":"注意不要周六日去。\n周六早上 7 点出发，大概 3 个小时车程的京哈高速，足足开了 6 个多小时。\n小宾馆没有停车位，大宾馆贵几十块钱，有停车位，有警察叔叔在路边贴条。\n景点停车位告急。\n新澳海底世界路上拥堵，10 分钟的路程堵了半个多小时，完事又告诉我没车位了，说前面还有停车场。\n尼玛前面没有停车场了好不！！！\n我再开出去 10 分钟，大热天的再背着东西走回来，太难受了。\n干脆饶了回来，在停车场入口死等，一直等到有车位空出来。\n周日返程同样耗费了双倍时间。\n开车时长超过玩耍时长。。。\n整个京哈高速，约 200 公里左右，开的非常难受。\n不断的超车超车超车，还走了 6 个小时，不知道那些快车道慢悠悠的司机怎么想的。\n那两天太阳不算烈，没涂防晒霜，最好还是涂上，这次又晒脱皮了。\n","permalink":"https://dvel.me/posts/troubles-qinhuangdao-self-drive/","summary":"\u003cp\u003e\u003cstrong\u003e注意不要周六日去。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e周六早上 7 点出发，大概 3 个小时车程的京哈高速，足足开了 6 个多小时。\u003c/p\u003e\n\u003cp\u003e小宾馆没有停车位，大宾馆贵几十块钱，有停车位，有警察叔叔在路边贴条。\u003c/p\u003e\n\u003cp\u003e景点停车位告急。\u003c/p\u003e\n\u003cp\u003e新澳海底世界路上拥堵，10 分钟的路程堵了半个多小时，完事又告诉我没车位了，说前面还有停车场。\u003c/p\u003e\n\u003cp\u003e尼玛前面没有停车场了好不！！！\u003c/p\u003e\n\u003cp\u003e我再开出去 10 分钟，大热天的再背着东西走回来，太难受了。\u003c/p\u003e\n\u003cp\u003e干脆饶了回来，在停车场入口死等，一直等到有车位空出来。\u003c/p\u003e\n\u003cp\u003e周日返程同样耗费了双倍时间。\u003c/p\u003e\n\u003cp\u003e开车时长超过玩耍时长。。。\u003c/p\u003e\n\u003cp\u003e整个京哈高速，约 200 公里左右，开的非常难受。\u003c/p\u003e\n\u003cp\u003e不断的超车超车超车，还走了 6 个小时，不知道那些快车道慢悠悠的司机怎么想的。\u003c/p\u003e\n\u003cp\u003e那两天太阳不算烈，没涂防晒霜，最好还是涂上，这次又晒脱皮了。\u003c/p\u003e","title":"秦皇岛暑期自驾的烦恼"},{"content":" 刚申请完（2017-04-19 至 2017-05-11），简单记录。\n申请类型为：公司（Company）\n提前准备 公司网站域名 请公司提供邮箱（公司的域名邮箱，即网站的域名后缀） 尴尬的是我们公司没有企业域名邮箱，于是我试了试 公司名称拼音@sina.com，总之顺利申请下来了。 请公司提供 VISA + 银联，或 万事达 + 银联 的双标信用卡（VISA单标卡目前不可用） 准备一个公司高层领导的姓名、性别、职位、电话 准备一个公司备用联系人的姓名、电话、邮箱 公司的一些细节（在下面） 注册 Apple ID 2017年4月19日\n拿这个邮箱，先去注册 Apple ID，姓名我填我自己的了，反正也能改。。。\n注意保存好密码、密保什么的，离职时留给下一任。\n申请邓白氏编码 2017年4月19日\nhttps://developer.apple.com/programs/cn/ 按流程操作 选择类型时，选择 Company / Organization 会弹出一个警告，很多文字，在 A D-U-N-S Number 这栏有一个 Check now \u0026gt; 开始查询是否已经有邓白氏编码，如果没有直接按填写的信息进行注册了 注意全部使用英文，要公司的英文名、英文地址之类的。\n英文地址我直接参考了公司营业执照，自己翻译了一下。\n坑： 这个页面同时让我填写了公司座机；和所谓的 \u0026ldquo;Your work contact infomation\u0026rdquo;（我填的自己的联系方式）。\n事实上，邓白氏会联系你填写的座机。（妈蛋，那要我的工作联系方式干啥？？？）\n邓白氏回应 2017年4月21日\nThank you for submitting your D-U-N-S Number request / update to D\u0026amp;B. It should be completed by 05/04/2017, or sooner. Your request id is: xxxxxx-xxxxxx. A D\u0026amp;B representative may be contacting you directly. Your cooperation will help to expedite the resolution of this request. Please contact applecs@dnb.com if you have any questions. xxxxxx-xxxxxx 是一串数字，也就是你的 request id。邓白氏跟我说最晚会在 5月4日 处理完毕。\n开始漫长的等待，期间我拨打了上海邓白氏总部的电话来查询进度： 1. 上海总部 021 2321 3636，用了一口流利上海话跟我说10点以后再打过来 2. 再次拨打，让我转邓氏编码热线：400 820 2669 3. 邓氏编码热线，让我转专门负责苹果开发者账号这方面的同事的电话：021-26107457 4. 021-26107457，打了两次，不接 5. mlgb 6. 继续等 2017年4月28日\n再次回复，看邮件是没打通我们公司座机，所以建议留一个你能接到的座机。\n还好我查了一下邮箱，居然让我下午3点前回复，我下午2点多看到的。。。\n您好， 我是上海华夏邓白氏公司，我们需要向您核实一下企业信息。由于拨打电话xxxx-xxxxxxx无人接听，请收到邮件于4月28日下午3点前回复以下信息： 请提供 公司中文名(工商注册的中文名，如有更名请提供更名前和更名后的名称): 英文名（如无正式的英文名按字面翻译，每个单词首字母大写，英文名后缀请以Co., Ltd./LLC/Inc.结尾）： 中文地址（办公地址）: 英文地址： 邮编: 企业类型: 是否是独立企业(下设有分公司或办事处吗): 公司英文简称或英文商标: 主营业务（公司最主要从事的业务）: 员工人数： 联系人姓名： 性别： 电话（公司座机和手机）： 职位: 营业执照： 如果您用其它邮箱回复请在邮件中注明一下之前的邮箱以便我们区分. 谢谢！ 和部门经理沟通后回复了邮件，1小时内，收到回复：\n好的，我这边收到了您的回复，正在核实你们公司的信息，稍后办理好，24小时内系统会自动发编码到苹果注册邮箱内，最晚14个工作日编码才能使用。若着急使用，可以在一周后尝试，但请注意尝试次数不要超过3次，超过次数编码会被锁住，解锁及注册方面问题请找苹果客服，电话：4006701855 注：包含邓白氏编码的邮件是由系统自动发送的，里面的信息是当时您自己在苹果网站上提交的原始信息，并不是核实好的内容。由于使用编码时需要再次填写公司信息，请和今天核实好的公司名字与地址保持一致。 邓白氏申请成功 2017年5月2日\n收到邮件，邓白氏申请成功。\nYour D-U-N-S Number request/update submitted on 4/20/2017 with ID Number 102122-419095 has been completed. You may start using your number in 14 days. D-U-N-S Number: xxxxxxxxx Resolution Description: New Record Created The following information was submitted as part of your request: Business Name: xxxx Technology Co., Ltd City: xx Country: CHINA PEOPLES REP Thank you for using D\u0026amp;B\u0026#39;s Mini Investigation Service. 申请开发者账号 2017年5月9日\n之前告诉我了14天后才可以使用邓白氏编码，我侥幸试了一下，已经可以使用了，但如果失败的话，建议不要尝试超过2次。\n这个步骤就简单了，这回我留了公司副总的手机号。\n申请完后就显示正在处理，等两三天就行了。\n2017年5月10日\n副总接到了 Apple 的电话，到办公室找到我= =。。。\n我问客服有什么事情，客服说让我留一个公司备份联系人的电话。\n我说必须现在立马给您吗，客服说邮件解决也行。\n一来一回收发了下邮件。\n您好： 我们负责跟进您的 Apple Developer Program 注册 ID xxxxxxxxxxx 所存在的问题。 为了在紧急情况下能够联系到您的组织，我们希望存档一位备用联系人。当我们无法直接联系您时，我们会联系这位备用联系人。 请回复此电子邮件，并提供该备用联系人的信息。 名字： 姓氏： 电话号码： 电子邮件地址： 我们收到了您的请求，并会在一个工作日内给您回复。您的案例编号是 xxxxxxxxxxx. 如果您想与开发者支持顾问通话，请联系我们 https://developer.apple.com/contact/phone/cn。 同日下午的邮件：\nDear xxx, Your enrollment request has been accepted. You may now review the Program License Agreement to continue your organization\u0026#39;s enrollment in the Apple Developer Program. Review now Best regards, Apple Developer Program Support 万事俱备，只差钱了。\n付款 2017年5月11日\n据说是 $99 美元，但我实际上在网页看到的是明确的￥688人民币。（之前给财务写的申请单写少了= =）\n只支持 VISA 或 万事达。\n一开始用的是副总的 VISA单标卡，一直付款失败。\n后换到 VISA+银联双标卡，成功。\n此处可以申请纸质发票。\n总结 如果有什么不懂的地方，请大家尽情拨打 Apple 的 400 客服电话，台湾腔、声音温柔甜美。\n","permalink":"https://dvel.me/posts/apple-developer-company-registration/","summary":"\u003cblockquote\u003e\n\u003cp\u003e刚申请完（2017-04-19 至 2017-05-11），简单记录。\u003c/p\u003e\n\u003cp\u003e申请类型为：公司（Company）\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"提前准备\"\u003e提前准备\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e公司网站域名\u003c/li\u003e\n\u003cli\u003e请公司提供邮箱（公司的域名邮箱，即网站的域名后缀）\n\u003cul\u003e\n\u003cli\u003e尴尬的是我们公司没有企业域名邮箱，于是我试了试 \u003ccode\u003e公司名称拼音@sina.com\u003c/code\u003e，总之顺利申请下来了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003e请公司提供 VISA + 银联，或 万事达 + 银联 的双标信用卡（VISA单标卡目前不可用）\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003e准备一个公司高层领导的姓名、性别、职位、电话\u003c/li\u003e\n\u003cli\u003e准备一个公司备用联系人的姓名、电话、邮箱\u003c/li\u003e\n\u003cli\u003e公司的一些细节（在下面）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"注册-apple-id\"\u003e注册 Apple ID\u003c/h2\u003e\n\u003cp\u003e2017年4月19日\u003c/p\u003e\n\u003cp\u003e拿这个邮箱，先去注册 Apple ID，姓名我填我自己的了，反正也能改。。。\u003c/p\u003e\n\u003cp\u003e注意保存好密码、密保什么的，离职时留给下一任。\u003c/p\u003e\n\u003ch2 id=\"申请邓白氏编码\"\u003e申请邓白氏编码\u003c/h2\u003e\n\u003cp\u003e2017年4月19日\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://developer.apple.com/programs/cn/\" target=\"_blank\" rel=\"noopener\"\u003ehttps://developer.apple.com/programs/cn/\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e按流程操作\u003c/li\u003e\n\u003cli\u003e选择类型时，选择 \u003cstrong\u003eCompany / Organization\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e会弹出一个警告，很多文字，在 \u003ccode\u003eA D-U-N-S Number\u003c/code\u003e 这栏有一个 \u003ccode\u003eCheck now \u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e开始查询是否已经有邓白氏编码，如果没有直接按填写的信息进行注册了\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e注意全部使用英文，要公司的英文名、英文地址之类的。\u003c/p\u003e\n\u003cp\u003e英文地址我直接参考了公司营业执照，自己翻译了一下。\u003c/p\u003e\n\u003ch3 id=\"坑\"\u003e坑：\u003c/h3\u003e\n\u003cp\u003e这个页面同时让我填写了公司座机；和所谓的 \u0026ldquo;Your work contact infomation\u0026rdquo;（我填的自己的联系方式）。\u003c/p\u003e\n\u003cp\u003e事实上，邓白氏会联系你填写的座机。（妈蛋，那要我的工作联系方式干啥？？？）\u003c/p\u003e\n\u003ch3 id=\"邓白氏回应\"\u003e邓白氏回应\u003c/h3\u003e\n\u003cp\u003e2017年4月21日\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eThank you for submitting your D-U-N-S Number request / update to D\u0026amp;B. It should be completed by 05/04/2017, or sooner.\nYour request id is: xxxxxx-xxxxxx. \nA D\u0026amp;B representative may be contacting you directly. Your cooperation will help to expedite the resolution of this request.\nPlease contact applecs@dnb.com if you have any questions.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003exxxxxx-xxxxxx\u003c/code\u003e 是一串数字，也就是你的 request id。邓白氏跟我说最晚会在 5月4日 处理完毕。\u003c/p\u003e","title":"苹果公司开发者账号申请流程"},{"content":"昨天耽误了一阵子在 scrollView 的布局上，记录一下。\n如果可以提前确定 scrollView 的 contentSize，就简单多了，但这种情况很少。\n一般还是按照 subViews 自适应的比较合适，这样就需要一个 containerView 来撑起 scrollView 的 contentSize。\n简单的代码示例： UIScrollView *scrollView = [UIScrollVie new]; [self.view addSubview:scrollView]; UIView *containerView = [UIView new]; [scrollView addSubview:containerView]; UIView *v1 = [UIView new]; v1.backgroundColor = [UIColor redColor]; [containerView addSubview:v1]; UIView *v2 = [UIView new]; v2.backgroundColor = [UIColor blueColor]; [containerView addSubview:v2]; /* 如上，我想让v1、v2纵向排列，让scrollView可以上下滚动。 */ // scrollView正常进行约束 [scrollView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; // 容器视图 [containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.width.equalTo(scrollView); // 试了发现这里好像必须要约束一下width }]; // v1、v2都放在容器里 [v1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(containerView); make.height.equalTo(@400); }]; [v2 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(v1.mas_bottom); make.left.right.equalTo(v1); make.height.equalTo(@400); }]; // 这里需要补刀，来撑起contentSize [containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(v2); }]; ","permalink":"https://dvel.me/posts/use-masonry-in-uiscrollview/","summary":"\u003cp\u003e昨天耽误了一阵子在 scrollView 的布局上，记录一下。\u003c/p\u003e\n\u003cp\u003e如果可以提前确定 \u003ccode\u003escrollView\u003c/code\u003e 的 \u003ccode\u003econtentSize\u003c/code\u003e，就简单多了，但这种情况很少。\u003c/p\u003e\n\u003cp\u003e一般还是按照 \u003ccode\u003esubViews\u003c/code\u003e 自适应的比较合适，这样就需要一个 \u003ccode\u003econtainerView\u003c/code\u003e 来撑起 \u003ccode\u003escrollView\u003c/code\u003e 的 \u003ccode\u003econtentSize\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"简单的代码示例\"\u003e简单的代码示例：\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-objective-c\" data-lang=\"objective-c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUIScrollView\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003escrollView\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIScrollVie\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nb\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eview\u003c/span\u003e \u003cspan class=\"nl\"\u003eaddSubview\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003escrollView\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003escrollView\u003c/span\u003e \u003cspan class=\"nl\"\u003eaddSubview\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebackgroundColor\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIColor\u003c/span\u003e \u003cspan class=\"n\"\u003eredColor\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e \u003cspan class=\"nl\"\u003eaddSubview\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ev2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIView\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ev2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebackgroundColor\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eUIColor\u003c/span\u003e \u003cspan class=\"n\"\u003eblueColor\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e \u003cspan class=\"nl\"\u003eaddSubview\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003ev2\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e如上，我想让v1、v2纵向排列，让scrollView可以上下滚动。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// scrollView正常进行约束\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003escrollView\u003c/span\u003e \u003cspan class=\"nl\"\u003emas_makeConstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"o\"\u003e^\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMASConstraintMaker\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eview\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 容器视图\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e \u003cspan class=\"nl\"\u003emas_makeConstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"o\"\u003e^\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMASConstraintMaker\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escrollView\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 试了发现这里好像必须要约束一下width\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// v1、v2都放在容器里\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e \u003cspan class=\"nl\"\u003emas_makeConstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"o\"\u003e^\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMASConstraintMaker\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e@400\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ev2\u003c/span\u003e \u003cspan class=\"nl\"\u003emas_makeConstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"o\"\u003e^\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMASConstraintMaker\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emas_bottom\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e@400\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里需要补刀，来撑起contentSize\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerView\u003c/span\u003e \u003cspan class=\"nl\"\u003emas_makeConstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"o\"\u003e^\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMASConstraintMaker\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emake\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eequalTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"UIScrollView 中使用 Masonry"},{"content":"网上搜了一些，添加 $(PODS_ROOT) 到 User Header Search Paths 就行了。\n但是提示中会多出一些不想要的东西。\n改成这个就好了：\n$(PODS_ROOT)/Headers/Public 图：\n","permalink":"https://dvel.me/posts/solve-cocoapods-without-import/","summary":"\u003cp\u003e网上搜了一些，添加 \u003ccode\u003e$(PODS_ROOT)\u003c/code\u003e 到 \u003cstrong\u003eUser Header Search Paths\u003c/strong\u003e 就行了。\u003c/p\u003e\n\u003cp\u003e但是提示中会多出一些不想要的东西。\u003c/p\u003e\n\u003cp\u003e改成这个就好了：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$(PODS_ROOT)/Headers/Public\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e图：\u003c/p\u003e\n\u003cp\u003e\n\u003cp\u003e\n\n    \n    \n        \u003cimg loading=\"lazy\"\n            src=\"/img/2017-04-24.webp\"\n            alt=\"Xcode\"\n            width=\"2558\"\n            height=\"1192\"\n            style=\"max-width: 100%; height: auto;\"\n        /\u003e\n    \n    \n\n\u003c/p\u003e\n\u003c/p\u003e","title":"解决 CocoaPods 的类库 import 没有提示"},{"content":"安装 Mac 自带 Ruby 环境，查看：\n$ gem -v 通过 surge 等工具实现终端科学上网，或更改 gem 源。\n安装 \u0026amp; 更新 Pod：\n$ sudo gem install cocoapods 确认：\n$ pod --version 使用 进入工程根目录，创建 Podfile 文件。\n写入：\nplatform :ios, \u0026#39;8.0\u0026#39; target \u0026#39;svnt\u0026#39; do pod \u0026#39;AFNetworking\u0026#39;, \u0026#39;~\u0026gt; 3.0\u0026#39; end 即最低支持 iOS 8，第三方框架 AFN 的版本为 3.0。\ncd 进 Podfile 所在目录，进行安装第三方库：\n$ pod install 后续使用 查询框架是否有新版本：\n$ pod outdated 更新框架：\n$ pod update 参考 \u0026amp; 感谢 iOS开发 - CocoaPods安装和使用教程 CocoaPods相关问题总结 ","permalink":"https://dvel.me/posts/use-cocoapods-in-ios/","summary":"\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003cp\u003eMac 自带 Ruby 环境，查看：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gem -v\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e通过 surge 等工具实现终端科学上网，或更改 gem 源。\u003c/p\u003e\n\u003cp\u003e安装 \u0026amp; 更新 Pod：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ sudo gem install cocoapods\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e确认：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ pod --version\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"使用\"\u003e使用\u003c/h2\u003e\n\u003cp\u003e进入工程根目录，创建 \u003ccode\u003ePodfile\u003c/code\u003e 文件。\u003c/p\u003e\n\u003cp\u003e写入：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eplatform :ios, \u0026#39;8.0\u0026#39;\ntarget \u0026#39;svnt\u0026#39; do\npod \u0026#39;AFNetworking\u0026#39;, \u0026#39;~\u0026gt; 3.0\u0026#39;\nend\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e即最低支持 iOS 8，第三方框架 AFN 的版本为 3.0。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecd\u003c/code\u003e 进 \u003ccode\u003ePodfile\u003c/code\u003e 所在目录，进行安装第三方库：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ pod install\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"后续使用\"\u003e后续使用\u003c/h2\u003e\n\u003cp\u003e查询框架是否有新版本：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ pod outdated\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更新框架：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ pod update\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"参考--感谢\"\u003e参考 \u0026amp; 感谢\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.jianshu.com/p/82d0ba43f8c3\" target=\"_blank\" rel=\"noopener\"\u003eiOS开发 - CocoaPods安装和使用教程\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jianshu.com/p/689368568cf7\" target=\"_blank\" rel=\"noopener\"\u003eCocoaPods相关问题总结\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"iOS 使用 CocoaPods 的快速回顾"},{"content":"偶尔可能要写一些生成本地文件发给朋友看，所以。。。\n简单生成本地静态 HTML 的方法 安装：$ npm install gitbook-cli -g\n生成：$ gitbook build\n结果：左侧目录无法点击。\n$ gitbook serve 可通过localhost访问，没有任何问题。\n问题：\n自某版本后 $ gitbook build 生成的 website 不支持 local 打开了，具体哪个版本未实践。\n解决办法：\n$ gitbook build --gitbook=2.6.7 使用2.6.7版本，会自动安装并生成，左侧目录可点击，Firefox、Chrome暂无任何问题。\n常用命令 帮助\n$ gitbook help 更新\n$ gitbook update 生成静态网页\n$ gitbook build $ gitbook build --gitbook=2.6.7 // 生成对应版本的，本地无此版本会自动下载 生成静态网页并运行到服务器\n$ gitbook serve 列出远程所有可用版本\n$ gitbook ls-remote 列出本地所有已安装版本\n$ gitbook ls 卸载本地某版本\n$ gitbook uninstall x.x.x 参考\u0026amp;感谢 hangjikai/gitbook-use\n","permalink":"https://dvel.me/posts/gitbook-generate-local-html/","summary":"\u003cp\u003e偶尔可能要写一些生成本地文件发给朋友看，所以。。。\u003c/p\u003e\n\u003ch2 id=\"简单生成本地静态-html-的方法\"\u003e简单生成本地静态 HTML 的方法\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e安装：\u003ccode\u003e$ npm install gitbook-cli -g\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e生成：\u003ccode\u003e$ gitbook build\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e结果：左侧目录无法点击。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003e$ gitbook serve\u003c/code\u003e 可通过localhost访问，没有任何问题。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e问题：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e自某版本后 \u003ccode\u003e$ gitbook build\u003c/code\u003e 生成的 website 不支持 local 打开了，具体哪个版本未实践。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决办法：\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook build --gitbook=2.6.7\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e使用2.6.7版本，会自动安装并生成，左侧目录可点击，Firefox、Chrome暂无任何问题。\u003c/p\u003e\n\u003ch2 id=\"常用命令\"\u003e常用命令\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e帮助\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook help\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e更新\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook update\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e生成静态网页\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook build\n$ gitbook build --gitbook=2.6.7 // 生成对应版本的，本地无此版本会自动下载\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e生成静态网页并运行到服务器\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook serve\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e列出远程所有可用版本\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook ls-remote\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e列出本地所有已安装版本\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook ls\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e卸载本地某版本\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ gitbook uninstall x.x.x\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"参考感谢\"\u003e参考\u0026amp;感谢\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/zhangjikai/gitbook-use\" target=\"_blank\" rel=\"noopener\"\u003ehangjikai/gitbook-use\u003c/a\u003e\u003c/p\u003e","title":"GitBook 简单生成本地静态 HTML 的方法"},{"content":"因为之前的 WordPress 博客域名被墙，加上 Hexo 正好满足于简单的书写要求，所以更换为 Hexo。\n主要还是记录了自己的搭建过程，因为对 Linux 不太熟悉，以备忘为主。\n后面换到了Coding Pages 上搭建，主要是简单方便省心，自带了 https，速度也凑合。\n方法一： 本地搭建 安装 node.js $ brew install node 安装 Hexo 先cd进入创建好的hexo目录：\n$ sudo npm install -g hexo-cli $ hexo init $ npm install $ hexo d -fg $ hexo serve 打开 http://localhost:4000 如果看到 Hexo 的初始页面证明安装成功。\nssh 秘钥 一路回车生成公钥和私钥：\n$ ssh-keygen -t rsa -C \u0026#34;email@example.com\u0026#34; 之后在本地目录 ~/.ssh/ 下可以看到私钥 id_rsa 和公钥 id_rsa.pub 已经生成。\n安装 ssh-copy-id 等会用，方便上传公钥。\n$ brew install ssh-copy-id VPS 端搭建 更新与安装（centOS） $ yum update $ yum install nginx -y $ yum install git-core 创建 git 用户及设置 ssh 免密码登陆 $ adduser git $ passwd git $ chmod 740 /etc/sudoers $ vim /etc/sudoers (提示没有安装vim的可以用vi命令，或安装vim:) $ yum -y install vim* 在编辑器中找到以下内容并添加一行：\n## Allow root to run any commands anywhere root ALL=(ALL) ALL git ALL=(ALL) ALL (这行是添加的) 保存退出并执行：\n$ chmod 440 /etc/sudoers 接下来切到本地的终端，上传公钥：\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub git@123.123.123.123 测试一下，如果 $ ssh git@VPS的IP地址 ,能够免密码登录的话，则表示成功。\n回到 VPS，创建 git 仓库: $ su git $ cd ~ $ mkdir hexo.git \u0026amp;\u0026amp; cd hexo.git $ git init --bare 创建网站目录并赋予 git 对网站目录的所有权 $ su root $ cd /var/www $ mkdir hexo $ chown git:git -R /var/www/hexo 配置 git hooks $ su git $ cd /home/git/hexo.git/hooks $ vim post-receive 写入以下内容：\n#!/bin/bash GIT_REPO=/home/git/hexo.git #git仓库 TMP_GIT_CLONE=/tmp/hexo PUBLIC_WWW=/var/www/hexo #网站目录 rm -rf ${TMP_GIT_CLONE} git clone $GIT_REPO $TMP_GIT_CLONE rm -rf ${PUBLIC_WWW}/* cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW} 然后赋予脚本的执行权限\n$ chmod +x post-receive 配置 Nginx 启动 nginX:\nsystemctl status nginx.service // 查看服务当前状态 systemctl start nginx.service // 启动nginx服务 systemctl restart nginx.service // 重新启动服务 systemctl enable nginx.service // 设置开机自启动 systemctl disable nginx.service // 停止开机自启动 systemctl list-units --type=service // 查看所有已启动的服务 然后：\n$ vim /etc/nginx/conf.d/hexo.conf 插入如下代码：\nserver { listen 80 ; root /var/www/hexo;//这里可以改成你的网站目录地址，我将网站放在/var/www/hexo server_name example.com www.example.com;//这里输入你的域名或IP地址 access_log /var/log/nginx/hexo_access.log; error_log /var/log/nginx/hexo_error.log; location ~* ^.+\\.(ico|gif|jpg|jpeg|png)$ { root /var/www/hexo; access_log off; expires 1d; } location ~* ^.+\\.(css|js|txt|xml|swf|wav)$ { root /var/www/hexo; access_log off; expires 10m; } location / { root /var/www/hexo;//这里可以改成你的网站目录地址，我将网站放在/var/www/hexo if (-f $request_filename) { rewrite ^/(.*)$ /$1 break; } } } 然后重启nginx，此时刷新网页应该显示的是403。\n本机的最后配置 位于 hexo 文件夹下，_config.yml ,修改 deploy 选项，例如：\ndeploy: type: git message: update # 这个可以不写，会默认生成update日期 repo: git@123.123.123.123:hexo.git,master # 逗号后面写分支 部署到多个仓库可以这么写：\ndeploy: - type: git repo: git@git.coding.net:Dvel/Dvel.git,master - type: git repo: git@github.com:iDvel/Dvel-Hexo.git,master 每次更新博客也可以让github上长点绿草了。。。\n接下来安装 hexo-deployer-git ，否则部署时会报这个错\u0026quot;ERROR Deployer not found: git\u0026quot;。\n$ npm install hexo-deployer-git --save 接着$ hexo g \u0026amp;\u0026amp; hexo d，如果一切正常，静态文件已经被成功的push到了blog的仓库里。\n期间我忘了还出了个什么错，删除hexo目录下的.deploy_git后再次hexo g \u0026amp;\u0026amp; hexo d就可以了。\n以上，博客已经完全建好了。\n$ hexo generate是生成静态文件。\n$ hexo deploy是部署，我们这里选择了Git，Hexo还支持其他部署形式。\n所以每次写完文章，执行这两个命令后，就对网站完成了更新。\n简化操作就是：$ hexo g \u0026amp;\u0026amp; hexo d ，再简化就是$ hexo d -g，效果一样。\n方法二，利用一键安装包 因为不太熟悉 Linux，所以我选择了一键安装包，多站点管理方便些。\n我用的这个 -\u0026gt; OneinStack官网\n步骤和上面差不多，但是很多路径要改一下，也可以很简单的搭建出Hexo。\n方法三，Coding Pages coding 中创建项目\n站点配置文件_config.yml 中 deploy 中写好 coding 项目的 git 地址\npush 上去：$ hexo d -g\n在 coding 上你的项目，开启 Pages 服务：可以自定义分支，绑定域名，开启 https\n大功告成\n这个相对简单一些，Coding Pages 服务目前提供 100M 空间的支持，一般来说没有写文章的话，生成的 public 文件夹大约小于5M。\n100M 基本够写很多年的博客，至于图片应该另寻图床，不要放到 coding 上，否则空间很快用完。\n编写文章、更新博客 使用一款 MarkDown 编辑器写文章 ，写完后将文件以 *.md 的格式保存在本地 [网站目录]\\source_posts 中。\nMarkdown 编辑器，强烈安利 Typora。\n每篇 Blog 都有固定的参数必须填写，参数如下，注意每个参数的 : 后都有一个空格。\ntitle: title date: yyyy-mm-dd categories: category tags: tag #多标签请这样写： #tags: [tag1,tag2,tag3] #或者这样写： #tags: #- tag1 #- tag2 #- tag3 --- 正文 或者使用 $ hexo new 命令，具体官网有详细说明。\n编写完后，只需要在hexo文件夹下执行 hexo g \u0026amp;\u0026amp; hexo d，博客即可更新。\n遇到的坑 设置了 ssh 免密码登陆后，依然需要密码\n这整段是以前使用的方法，过时了。。。 设置ssh免密码登陆： su git cd ~ mkdir .ssh \u0026amp;\u0026amp; cd .ssh touch authorized_keys vim authorized_keys //在这个文件中粘贴进刚刚申请的key（在id_rsa.pub文件中） 设置权限： chmod o-w ~/ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys 测试免密码登陆 ssh -vvT git@123.123.123.123 // 你的VPS的IP地址 发现依然需要密码，搜了好几天没找到解决办法，后来采用了ssh-copy-id，解决了这个问题。 如果过程中重新初始化过 VPS 的磁盘，ssh 连接 VPS 的时候可能会提示 Host key verification failed. 。\n运行此命令即可：$ ssh-keygen -R 123.123.123.123，将 123.123.123.123 改成你的 VPS 的 IP。\n或者简单粗暴直接删除 known_hosts 文件。\n","permalink":"https://dvel.me/posts/hello-hexo/","summary":"\u003cp\u003e因为之前的 WordPress 博客域名被墙，加上 Hexo 正好满足于简单的书写要求，所以更换为 Hexo。\u003c/p\u003e\n\u003cp\u003e主要还是记录了自己的搭建过程，因为对 Linux 不太熟悉，以备忘为主。\u003c/p\u003e\n\u003cp\u003e后面换到了Coding Pages 上搭建，主要是简单方便省心，自带了 https，速度也凑合。\u003c/p\u003e\n\u003ch2 id=\"方法一\"\u003e方法一：\u003c/h2\u003e\n\u003ch3 id=\"本地搭建\"\u003e本地搭建\u003c/h3\u003e\n\u003ch4 id=\"安装-nodejs\"\u003e安装 node.js\u003c/h4\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install node\n\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"安装-hexo\"\u003e安装 Hexo\u003c/h4\u003e\n\u003cp\u003e先cd进入创建好的hexo目录：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ sudo npm install -g hexo-cli\n$ hexo init\n$ npm install\n$ hexo d -fg\n$ hexo serve\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e打开 \u003ca href=\"http://localhost:4000\" target=\"_blank\" rel=\"noopener\"\u003ehttp://localhost:4000\u003c/a\u003e 如果看到 Hexo 的初始页面证明安装成功。\u003c/p\u003e\n\u003ch4 id=\"ssh-秘钥\"\u003essh 秘钥\u003c/h4\u003e\n\u003cp\u003e一路回车生成公钥和私钥：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ ssh-keygen -t rsa -C \u0026#34;email@example.com\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e之后在本地目录 \u003ccode\u003e~/.ssh/\u003c/code\u003e 下可以看到私钥 \u003ccode\u003eid_rsa\u003c/code\u003e 和公钥 \u003ccode\u003eid_rsa.pub\u003c/code\u003e 已经生成。\u003c/p\u003e\n\u003cp\u003e安装 \u003ccode\u003essh-copy-id\u003c/code\u003e 等会用，方便上传公钥。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install ssh-copy-id\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"vps-端搭建\"\u003eVPS 端搭建\u003c/h3\u003e\n\u003ch4 id=\"更新与安装centos\"\u003e更新与安装（centOS）\u003c/h4\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ yum update\n$ yum install nginx -y\n$ yum install git-core\n\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"创建-git-用户及设置-ssh-免密码登陆\"\u003e创建 git 用户及设置 ssh 免密码登陆\u003c/h4\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ adduser git\n$ passwd git\n$ chmod 740 /etc/sudoers\n$ vim /etc/sudoers\n(提示没有安装vim的可以用vi命令，或安装vim:)\n$ yum -y install vim*\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在编辑器中找到以下内容并添加一行：\u003c/p\u003e","title":"你好, Hexo！"},{"content":"Hi 👋\n欢迎来到我的博客。\n朋友们 Sulv\u0026#39;s Blog 一个记录技术、阅读、生活的博客 长街短梦 此行山高路远，我只剩口袋玫瑰一片 流动 生活就是一个流动的过程 写bug的代码人 没有比这再简陋的网站了 IGNORANT 笔记乱写、代码乱敲的调参侠 Mintimate’s Blog 专注与你分享技术教程～ ","permalink":"https://dvel.me/about/","summary":"\u003cp\u003eHi 👋\u003c/p\u003e\n\u003cp\u003e欢迎来到我的博客。\u003c/p\u003e\n\u003ch2 id=\"朋友们\"\u003e朋友们\u003c/h2\u003e\n\u003ca target=\"_blank\" href=https://www.sulvblog.cn title=Sulv\u0026#39;s\u0026#32;Blog class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://dvel.me/friends/sulvblog.cn.gif /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003eSulv\u0026#39;s Blog\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e一个记录技术、阅读、生活的博客\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003ca target=\"_blank\" href=https://wangyunzi.com title=长街短梦 class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://blog.wangyunzi.com/avatar.png /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003e长街短梦\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e此行山高路远，我只剩口袋玫瑰一片\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003ca target=\"_blank\" href=https://liudon.com title=流动 class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://liudon.com/avatar.png /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003e流动\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e生活就是一个流动的过程\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003ca target=\"_blank\" href=https://bugcoder.asia/ title=写bug的代码人 class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://bugcoder.asia/headLogo.jpg /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003e写bug的代码人\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e没有比这再简陋的网站了\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003ca target=\"_blank\" href=https://idzc.top title=IGNORANT class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://idzc.top/avatar.png /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003eIGNORANT\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e笔记乱写、代码乱敲的调参侠\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003ca target=\"_blank\" href=https://www.mintimate.cn title=Mintimate’s\u0026#32;Blog class=\"friendurl\"\u003e\n  \u003cdiv class=\"frienddiv\"\u003e\n    \u003cdiv class=\"frienddivleft\"\u003e\n      \u003cimg class=\"myfriend\" src=https://mintimate.cn/custom/img/favicon/favicon.png /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"frienddivright\"\u003e\n      \u003cdiv class=\"friendname\"\u003eMintimate’s Blog\u003c/div\u003e\n      \u003cdiv class=\"friendinfo\"\u003e专注与你分享技术教程～\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/a\u003e\n\u003chr\u003e\n\u003cdiv class=\"footer-img-link\"\u003e\n    \u003ca href=\"https://www.travellings.cn/go.html\" target=\"_blank\" rel=\"noopener\" title=\"开往-友链接力\"\u003e\n        \u003cimg\n            src=\"/img/travelling.gif\"\n            width=\"120\"\n            alt=\"开往-友链接力\"\n            title=\"开往-友链接力\"\n            style=\"display: inline; vertical-align: middle;\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.foreverblog.cn/go.html\" target=\"_blank\" rel=\"noopener\" title=\"穿梭虫洞-随机访问十年之约友链博客\"\u003e\n        \u003cimg\n            src=\"/img/wormhole.gif\"\n            width=\"120\"\n            alt=\"穿梭虫洞-随机访问十年之约友链博客\"\n            title=\"穿梭虫洞-随机访问十年之约友链博客\"\n            style=\"display: inline; vertical-align: middle;\"\n        /\u003e\n    \u003c/a\u003e\n\u003c/div\u003e","title":"About"}]