<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on EuDs&#39;s Blog</title>
    <link>https://ds63.eu.org/posts/</link>
    <follow_challenge>
      <feedId>55788057182175234</feedId>
      <userId>67186528297029632</userId>
    </follow_challenge>
    <description>Recent content in Posts on EuDs&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 26 Feb 2025 16:23:34 +0800</lastBuildDate><atom:link href="https://ds63.eu.org/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>诗词</title>
      <link>https://ds63.eu.org/2023/poem/</link>
      <pubDate>Tue, 06 Jun 2023 22:53:45 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/poem/</guid>
      <description>暂时定于用来记录些诗词</description>
      <content:encoded><![CDATA[<p><strong>暂时定于用来记录些诗词</strong></p>
<h2 id="鹧鸪天正月十一日观灯-----姜夔">鹧鸪天（正月十一日观灯）     姜夔</h2>
<p>巷陌风光纵赏时。笼纱未出马先嘶。白头居士无呵殿，只有乘肩小女随。</p>
<p>花满市，月侵衣。少年情事老来悲。沙河塘上春寒浅，看了游人缓缓归。</p>
<p><strong>看过一篇点评。说这阙词可能是唯一一阙描写了女儿坐在爸爸肩头的。那篇文章中还写，说姜夔半生潦倒，不知他的小女命运几何。我感觉不管以后如何，当坐在爸爸肩头赏灯的时候肯定是很幸福的。</strong></p>
<hr>
<h2 id="咏史-李梦唐">咏史 李梦唐</h2>
<p>高阁垂裳调鼎时，可怜天下有微词。</p>
<p>覆舟水是苍生泪，不到横流君不知。</p>
<hr>
<h2 id="拟行路难-其四-鲍照">拟行路难-其四 鲍照</h2>
<p>泻水置平地，各自东西南北流。</p>
<p>人生亦有命，安能兴叹复坐愁！</p>
<p>酌酒以自宽，举杯断绝歌路难。</p>
<p>心非木石岂无感，吞声踯躅不敢言。</p>
<p><strong>很喜欢最后这一句。今天（2023年6月6日）才知道鲍照久居建康，也就是南京，然后才发现江苏和山东竟然是邻居。</strong></p>
<hr>
<h2 id="塞下曲-其二-王昌龄">塞下曲-其二 王昌龄</h2>
<p>饮马渡秋水，水寒风似刀。</p>
<p>平沙日未没，黯黯见临洮。</p>
<p>昔日长城战，咸言意气高。</p>
<p>黄尘足今古，白骨乱蓬蒿。</p>
<p><strong>四月份记的一首诗，已经忘了为什么记了。</strong></p>
<hr>
<h2 id="拟挽歌辞-陶渊明">拟挽歌辞 陶渊明</h2>
<p>有生必有死，早终非命促。</p>
<p>昨暮同为人，今旦在鬼录。</p>
<p>魂气散何之，枯形寄古木。</p>
<p>娇儿索父啼，良友抚我哭，</p>
<p>得失不复知，是非安能觉！</p>
<p>千秋万岁后，谁知荣与辱？</p>
<p>但恨在世时，饮酒不得足。</p>
<p>在昔无酒饮，今但湛空觞。</p>
<p>春醪生浮蚁，何时更能尝！</p>
<p>肴案盈我前，亲旧哭我旁。</p>
<p>欲语口无音，欲视眼无光。</p>
<p>昔在高唐寝，今宿荒草乡；</p>
<p>一朝出门去，归来夜未央。</p>
<p>荒草何茫茫，白杨亦萧萧。</p>
<p>严霜九月中，送我出远郊。</p>
<p>四面无人居，高坟自嶣峣。</p>
<p>马为仰天鸣，风为自萧条。</p>
<p>幽室一已闭，千年不复朝。</p>
<p>千年不复朝，贤达无奈何。</p>
<p>向来相送人，各自还其家。</p>
<p>亲戚或余悲，他人亦已歌。</p>
<p>死去何所道，托体同山阿。</p>
<p><strong>之前读不懂，今年读懂了。</strong></p>
<p><strong>“得失不复知，是非安能觉”这句，让我想到“死去元知万事空”。他们都不信什么在天之灵，都认为死了就是死了。我也认同这种想法，但更希望能有在天之灵。</strong></p>
<p><strong>“春醪生浮蚁，何时更能尝”这句看了注释才知道自己完全读反了。说的是祭酒的时候，我理解为生的时候。</strong></p>
<p><strong>“亲戚或余悲，他人亦已歌”。听着很残酷，但我现在觉得：死后能让他人偶尔想起，已经是很了不起的事了</strong></p>
<hr>
<h2 id="定风波-南海归赠王定国侍人寓娘-苏轼">定风波-南海归赠王定国侍人寓娘 苏轼</h2>
<p><em>王定国哥儿曰柔奴，姓宇文氏，眉目娟丽，善应对，家世住京师。定国南迁归，余问柔：“广南应是不好？”柔对曰：“此心安处，便是吾乡。”因为缀词云。</em></p>
<p>常羡人间琢玉郎，天教分付酥娘。尽道清歌传皓齿，风起，雪飞炎海变清凉。</p>
<p>万里归来颜愈少。微笑，笑时犹带岭梅香。试问岭南应不好，却道：此心安处是吾乡。</p>
<p><strong>苏轼的两阙定风波我都很喜欢。</strong></p>
<hr>
<h2 id="定风波-苏轼">定风波 苏轼</h2>
<p><em>三月七日，沙湖道中遇雨，雨具先去，同行皆狼狈，余独不觉。已而放晴，故作此。</em></p>
<p>莫听穿林打叶声，何妨吟啸且徐行。竹杖芒鞋轻胜马，谁怕，一蓑烟雨任平生。</p>
<p>料峭春风吹酒醒，微冷，山头斜照却相迎。回首向来萧瑟处，归去，也无风雨也无晴。</p>
<p><strong>蓑这个意像是诗词里的常客了。</strong></p>
<p><strong>对这阙词一直有个印象，就是苏轼淋雨生病了，去看病又写了阙《游沙湖》。但是查了下才发现自己的记忆是错的。苏轼去看的是手肿，明显不是因为淋雨</strong></p>
<hr>
<h2 id="朝中措送刘仲原甫出守维扬-欧阳修">朝中措·送刘仲原甫出守维扬 欧阳修</h2>
<p>平山栏槛倚晴空。山色有无中。手种堂前垂柳，别来几度春风。</p>
<p>文章太守，挥毫万字，一饮千钟。行乐直须年少，尊前看取衰翁。</p>
<p><strong>之前去扬州找攻略的时候翻到的。</strong></p>
<hr>
<h2 id="汴河怀古-皮日休">汴河怀古 皮日休</h2>
<p>尽道隋亡为此河，至今千里赖通波。</p>
<p>若无水殿龙舟事，共禹论功不较多。</p>
<p><strong>在大运河博物馆看到的。现在想到皮日休在开元寺待过一段时间。影壁上好像还有他的名。</strong></p>
<hr>
<h2 id="题龙阳县青草湖-唐珙">题龙阳县青草湖 唐珙</h2>
<p>西风吹老洞庭波，一夜湘君白发多，</p>
<p>醉后不知天在水，满船清梦压星河。</p>
<p><strong>老字用得很妙，之前没悟出来</strong></p>
<p><strong>最后一句我也很喜欢。我也蛮喜欢坐船的。</strong></p>
<hr>
<h2 id="答武陵太守-王昌龄">答武陵太守 王昌龄</h2>
<p>仗剑行千里，微躯感一言。</p>
<p>曾为大梁客，不负信陵恩。</p>
<p><strong>我比较喜欢前面两句，但却不太能做得到，反而是“微躯不敢言”。与古人比，可谓差远了</strong></p>
<hr>
<h2 id="临江节士歌-李白">临江节士歌 李白</h2>
<p>洞庭白波木叶稀，燕鸿始入吴云飞。</p>
<p>吴云寒，燕鸿苦。</p>
<p>风号沙宿潇湘浦，节士悲秋泪如雨。</p>
<p>白日当天心，照之可以事明主。</p>
<p>壮士愤，雄风生。</p>
<p>安得倚天剑，跨海斩长鲸。</p>
<p><strong>可能是我水平有限，总觉得这首有种在高潮时却戛然而止的感觉</strong></p>
<hr>
<h2 id="陇西行四首-陈陶">陇西行四首 陈陶</h2>
<p><em>其一</em></p>
<p>汉主东封报太平，无人金阙议边兵。</p>
<p>纵饶夺得林胡塞，碛地桑麻种不生。</p>
<p><em>其二</em></p>
<p>誓扫匈奴不顾身，五千貂锦丧胡尘。</p>
<p>可怜无定河边骨，犹是春闺梦里人。</p>
<p><em>其三</em></p>
<p>陇戍三看塞草青，楼烦新替护羌兵。</p>
<p>同来死者伤离别，一夜孤魂哭旧营。</p>
<p><em>其四</em></p>
<p>黠虏生擒未有涯，黑山营阵识龙蛇。</p>
<p>自从贵主和亲后，一半胡风似汉家。</p>
<p><strong>“可怜无定河边骨，犹是春闺梦里人”这句读来很有感觉。</strong></p>
<hr>
<h2 id="秋词二首其一-刘禹锡">秋词二首·其一 刘禹锡</h2>
<p>自古逢秋悲寂寥，我言秋日胜春朝。</p>
<p>晴空一鹤排云上，便引诗情到碧霄。</p>
<p><strong>这几天秋意已经很浓了。今天散步的时候看着一地的落叶莫名有些心情不好。</strong></p>
<p><strong>先是想到“伤春悲秋”，就觉得自己的想法也正常,一乐</strong></p>
<p><strong>然后又突然想到这首诗的第一句，心情顿时好了不少。</strong></p>
<hr>
<h2 id="北风行-李白">北风行 李白</h2>
<p>烛龙栖寒门，光耀犹旦开。</p>
<p>日月照之何不及此？唯有北风号怒天上来。</p>
<p>燕山雪花大如席，片片吹落轩辕台。</p>
<p>幽州思妇十二月，停歌罢笑双蛾摧。</p>
<p>倚门望行人，念君长城苦寒良可哀。</p>
<p>别时提剑救边去，遗此虎文金鞞靫。</p>
<p>中有一双白羽剑，蜘蛛结网生尘埃。</p>
<p>箭空在，人今战死不复回。</p>
<p>不忍见此物，焚之已成灰。</p>
<p>黄河捧土尚可塞，北风雨雪恨难裁。</p>
<p><strong>读过很多次了，但今天再读还是很有感觉</strong></p>
<p><strong>很喜欢“念君长城苦寒良可哀”这句，不整齐，但读起来很顺口。</strong></p>
<p><strong>我今天想起这首，回忆到第三句的时候没想起来接下来的，但整体的基调是记得的。就想：接下来要该怎么转到战争呢，看了觉得很惊喜，很佩服</strong></p>
<p><strong>“不忍见此物” 这种想法我还不懂，也不希望我懂</strong></p>
<hr>
<h2 id="佳人-杜甫">佳人 杜甫</h2>
<p>绝代有佳人，幽居在空谷。</p>
<p>自云良家子，零落依草木。</p>
<p>关中昔丧乱，兄弟遭杀戮。</p>
<p>官高何足论，不得收骨肉。</p>
<p>世情恶衰歇，万事随转烛。</p>
<p>夫婿轻薄儿，新人美如玉。</p>
<p>合昏尚知时，鸳鸯不独宿。</p>
<p>但见新人笑，那闻旧人哭。</p>
<p>在山泉水清，出山泉水浊。</p>
<p>侍婢卖珠回，牵萝补茅屋。</p>
<p>摘花不插发，采柏动盈掬。</p>
<p>天寒翠袖薄，日暮倚修竹。</p>
<p><strong>这篇让我想到《秦妇吟》，前者讲的是安史之乱，后者讲的黄巢之乱。但都有着共同点：战乱带给百姓的灾难。</strong></p>
<p><strong>“日暮倚修竹”让我想到文天祥的“风檐展书读，古道照颜色”。具体是为什么，我又说不清楚。场景？</strong></p>
<hr>
<h2 id="泛海-王守仁">泛海 王守仁</h2>
<p>险夷原不滞胸中，何异浮云过太空？</p>
<p>夜静海涛三万里，月明飞锡下天风。</p>
<p><strong>这首诗读起来很潇洒，是我所向往的。</strong></p>
<p><strong>创作背景也很有意思:</strong></p>
<blockquote>
<p>　这首诗作于明武宗正德元年（1506）。王守仁因仗义执言被贬为贵州龙场驿驿丞。刘瑾还派人对他进行暗杀。王守仁急中生智，做出投江自杀的假象，搭上了前往福建的商船。王守仁坐在船上，写下了这首诗。</p>
</blockquote>
<hr>
<h2 id="随园诗话-卷一-袁枚">随园诗话 卷一 袁枚</h2>
<p>遥知此去栋梁材，无复清阴覆绿苔。</p>
<p>只恐月明秋叶冷，误他千岁鹤归来。</p>
<p><strong>其实这首诗标题不是随园诗话,也不是袁枚写的。只是袁枚在随园诗话中记录了这首诗。原文如下：</strong></p>
<blockquote>
<p>江西某太守，将伐古树。有客题诗于树云：“遥知此去栋梁材，无复清阴覆绿苔。只恐月明秋夜冷，误他千岁鹤归来。”太守读之，怆然有感，乃停斧不伐。</p>
</blockquote>
<p><strong>第一次知道这首诗，是在中学的一本教材上。有的诗读一遍后就很难忘记，这首诗就是如此。我还记得那本教材上还有个插画，画的就是千岁鹤与树，很美。</strong></p>
<p><strong>我家门口就有棵树，活了得有快三十年了。去年被市政挖掉了。这棵树不是要去做栋梁材，而是因为市政规划而被迫移位。没有客去题诗，但那是一棵我看着长大的树，或者说看着我长大的树。</strong></p>
<p><strong>我怀念那棵树。</strong></p>
<hr>
<h2 id="行行复行行-佚名">行行复行行 佚名</h2>
<p>行行复行行，与君生别离。</p>
<p>相去万余里，各在天一涯。</p>
<p>道路阻且长，会面安可知？</p>
<p>胡马依北风，越鸟巢南枝。</p>
<p>相去日已远，衣带日已缓。</p>
<p>浮云蔽白日，游子不顾反。</p>
<p>思君令人老，岁月忽已晚。</p>
<p>弃捐勿复道，努力加餐饭。</p>
<p><strong>“胡马依北风，越鸟巢南枝”很有画面感。</strong></p>
<p><strong>“努力加餐饭”有两个解释，一种是对游子说，让他在外好好吃饭，保重身体。另一种是在劝慰自己。但都是要好好吃饭。</strong></p>
<p><strong>旅行者1号上携带了一张铜质磁盘唱片,其中有一段是闽南语的问候，“太空朋友，你吃饱了吗，有空来我这坐”。很朴素的问候。我第一次听还吐槽，怎么都上天了，还是说一样的话。读到这首诗后才意思到，快两千年过去了也是这样。</strong></p>
<p><strong>“好好吃饭”背后蕴含的情感远比字面上来得要细腻。</strong></p>
<hr>
<h2 id="章台柳寄柳氏-韩翃">章台柳·寄柳氏 韩翃</h2>
<p>章台柳，章台柳，往日依依今在否？</p>
<p>纵使长条似旧垂，也应攀折他人手。</p>
<p><strong>借物拟人实在是妙</strong></p>
<hr>
<h2 id="时运其一-陶渊明">时运(其一) 陶渊明</h2>
<p>迈迈时运，穆穆良朝。</p>
<p>袭我春服，薄言东郊。</p>
<p>山涤馀霭，宇暖微霄。</p>
<p>有风自南，翼彼新苗。</p>
<p><strong>“翼”字很妙</strong></p>
<hr>
<h2 id="命子-陶渊明">命子 陶渊明</h2>
<p>悠悠我祖，爰自陶唐。</p>
<p>邈焉虞宾，历世重光。</p>
<p>御龙勤夏，豕韦翼商。</p>
<p>穆穆司徒，厥族以昌。</p>
<p>纷纷战国，漠漠衰周。</p>
<p>凤隐于林，幽人在丘。</p>
<p>逸虬绕云，奔鲸骇流。</p>
<p>天集有汉，眷予愍侯。</p>
<p>於赫愍侯，运当攀龙。</p>
<p>抚剑风迈，显兹武功。</p>
<p>书誓河山，启土开封。</p>
<p>亹亹丞相，允迪前踪。</p>
<p>浑浑长源，蔚蔚洪柯。</p>
<p>群川载导，众条载罗。</p>
<p>时有语默，运因隆窊。</p>
<p>在我中晋，业融长沙。</p>
<p>桓桓长沙，伊勋伊德。</p>
<p>天子畴我，专征南国。</p>
<p>功遂辞归，临宠不忒。</p>
<p>孰谓斯心，而近可得。</p>
<p>肃矣我祖，慎终如始。</p>
<p>直方二台，惠和千里。</p>
<p>於皇仁考，淡焉虚止。</p>
<p>寄迹风云，冥兹愠喜。</p>
<p>嗟余寡陋，瞻望弗及。</p>
<p>顾惭华鬓，负影只立。</p>
<p>三千之罪，无后为急。</p>
<p>我诚念哉，呱闻尔泣。</p>
<p>卜云嘉日，占亦良时。</p>
<p>名汝曰俨，字汝求思。</p>
<p>温恭朝夕，念兹在兹。</p>
<p>尚想孔伋，庶其企而！</p>
<p>历夜生子，遽而求火。</p>
<p>凡百有心，奚特于我！</p>
<p>既见其生，实欲其可。</p>
<p>人亦有言，斯情无假。</p>
<p>日居月诸，渐免于孩。</p>
<p>福不虚至，祸亦易来。</p>
<p>夙兴夜寐，愿尔斯才。</p>
<p>尔之不才，亦已焉哉。</p>
<p><strong>前面一大段都是追忆陶姓的悠久历史和辉煌事迹。是这样提他父亲的，“於皇仁考，淡焉虚止。寄迹风云，冥兹愠喜。”</strong></p>
<p><strong>这诗我觉得最有趣的是最后一句，也是我特地记录于此的原因</strong></p>
<p><strong>在前面那么长的铺垫——家族历史，殷切期望之后，来了句“尔之不才，亦已焉哉”。鸡娃失败，那能怎么办，也就这样吧</strong></p>
<hr>
<h2 id="观潮-苏轼">观潮 苏轼</h2>
<p>庐山烟雨浙江潮，未至千般恨不消。</p>
<p>到得还来别无事，庐山烟雨浙江潮。</p>
<p><strong>首尾同句很少见</strong></p>
<hr>
<h2 id="自遣-罗隐">自遣 罗隐</h2>
<p>得即高歌失即休，多愁多恨亦悠悠。</p>
<p>今朝有酒今朝醉，明日愁来明日愁。</p>
<p><strong>能做到的有几个?</strong></p>
<hr>
<h2 id="临江仙-夜归临皋-苏轼">临江仙-夜归临皋 苏轼</h2>
<p>夜饮东坡醒复醉，归来仿佛三更。家童鼻息已雷鸣。敲门都不应，依仗听江声。</p>
<p>长恨此身非我有，何时忘却营营。夜阑风静縠纹平。小舟从此逝，江海寄此生。</p>
<p><strong>“江海寄余生”</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>NoneBot接入GPT-SoVITS</title>
      <link>https://ds63.eu.org/2025/connect-nonebot-with-gpt-sovits/</link>
      <pubDate>Wed, 26 Feb 2025 16:23:34 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2025/connect-nonebot-with-gpt-sovits/</guid>
      <description>慢才是快</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>很经常在b站刷到AI音声之类的视频，自己也爱看。某日心血来潮，决定自己试一试。</p>
<p>B站一搜，搜到了<a href="https://www.bilibili.com/video/BV1XH4y137Lk"  target="_blank" rel="noopener" >MyGO角色GPT-SoVITS语音模型分享和使用教程</a>，<a href="https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/dkxgpiy9zb96hob4"  target="_blank" rel="noopener" >整合包及模型下载链接</a>，照着教程做。没一会就搞好了。整合包很方便，没遇上啥问题。</p>
<p>GPT-SoVITS的效果很惊艳，音色很像，甚至还能模仿参考音频的情绪。</p>
<p>我用的整合包提供了web界面，但我不够满足，想把它接入到我遗弃许久的qq bot中。</p>
<p>一搜，找到了<a href="https://github.com/zhaomaoniu/nonebot-plugin-gpt-sovits"  target="_blank" rel="noopener" >zhaomaoniu/nonebot-plugin-gpt-sovits: ✨ NoneBot2 Plugin for GPT-SoVITS ✨</a>。</p>
<p>原本以为接入也会很顺利，结果还是花了快一个下午的时间，在此记录下。</p>
<p>注意，我使用的电脑系统为win11，使用的是<a href="https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/dkxgpiy9zb96hob4"  target="_blank" rel="noopener" >整合包及模型下载链接</a>的<code>Windows整合包</code></p>
<h2 id="过程">过程</h2>
<ol>
<li>运行<code>api_v2.py</code>: <code>runtime\python.exe api_v2.py</code></li>
<li>这时候启动时的所默认加载的模型可能不是我们想要的模型，有两种方式能改:
<ul>
<li>修改<code>GPT_SoVITS/configs/tts_infer.yaml</code>的<code>t2s_weights_path</code>和<code>vits_weights_path</code></li>
<li><code>api_v2.py</code>提供了相应的接口:<code>set_gpt_weights</code>和<code>set_sovits_weights</code>，拿postman发下请求就行。我托gpt帮忙写了个python脚本,如下:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_request</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 对参数进行URL编码，确保特殊字符不会被转义错误</span>
</span></span><span class="line"><span class="cl">        <span class="n">encoded_params</span> <span class="o">=</span> <span class="p">{</span><span class="n">key</span><span class="p">:</span> <span class="n">quote</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">safe</span><span class="o">=</span><span class="s1">&#39;:/&#39;</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">params</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># 发送GET请求</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">encoded_params</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># 检查HTTP响应状态码</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;成功:&#34;</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;失败: </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s2">, 错误信息: </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="n">requests</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">RequestException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;请求发送失败: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置 GPT 模型权重</span>
</span></span><span class="line"><span class="cl"><span class="n">gpt_weights_url</span> <span class="o">=</span> <span class="s2">&#34;http://127.0.0.1:9880/set_gpt_weights&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">gpt_weights_params</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;weights_path&#34;</span><span class="p">:</span> <span class="s2">&#34;GPT_weights/tomori1-e20.ckpt&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置 Sovits 模型权重</span>
</span></span><span class="line"><span class="cl"><span class="n">sovits_weights_url</span> <span class="o">=</span> <span class="s2">&#34;http://127.0.0.1:9880/set_sovits_weights&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">sovits_weights_params</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;weights_path&#34;</span><span class="p">:</span> <span class="s2">&#34;SoVITS_weights/tomori1_e12_s2664.pth&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 发送请求</span>
</span></span><span class="line"><span class="cl"><span class="n">send_request</span><span class="p">(</span><span class="n">gpt_weights_url</span><span class="p">,</span> <span class="n">gpt_weights_params</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">send_request</span><span class="p">(</span><span class="n">sovits_weights_url</span><span class="p">,</span> <span class="n">sovits_weights_params</span><span class="p">)</span>
</span></span></code></pre></div></li>
<li>接下来就是配置<a href="https://github.com/zhaomaoniu/nonebot-plugin-gpt-sovits"  target="_blank" rel="noopener" >zhaomaoniu/nonebot-plugin-gpt-sovits</a>了，文档写得蛮清楚的，这里不过多赘述。</li>
</ol>
<h2 id="踩坑">踩坑</h2>
<ul>
<li><a href="https://github.com/zhaomaoniu/nonebot-plugin-gpt-sovits"  target="_blank" rel="noopener" >zhaomaoniu/nonebot-plugin-gpt-sovits</a>文档里需要填<code>GPT_SOVITS_EMOTION_MAP</code>，也给了示例，但我不知道怎么在.env里填不是字符串的东西。于是找到了<code>.venv/Lib/site-packages/nonebot_plugin_gpt_sovits/config.py</code>,在那里改，比如我是改成了这样:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Config</span><span class="p">(</span><span class="n">pydantic</span><span class="o">.</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_api_base_url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;http://127.0.0.1:9880&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_api_v2</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_command</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;羊姐说话&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_convert_to_silk</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_emotion_map</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="n">Emotion</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;平静&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;sentences&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;凄く苦そうだけど……美味しいじゃあ、どうして……&#34;</span><span class="p">,</span> <span class="s2">&#34;language&#34;</span><span class="p">:</span> <span class="s2">&#34;ja&#34;</span><span class="p">,</span> <span class="s2">&#34;path&#34;</span><span class="p">:</span> <span class="s2">&#34;D:</span><span class="se">\\</span><span class="s2">Project</span><span class="se">\\</span><span class="s2">NoneBot</span><span class="se">\\</span><span class="s2">Hesap</span><span class="se">\\</span><span class="s2">tomori.wav&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">gpt_sovits_args</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span></code></pre></div></li>
<li><code>refer_wav_path = sentence.path</code>得改成<code>refer_wav_path = sentence[&quot;path&quot;]</code></li>
<li>路径问题，python的<code>\</code>是转义符，所以得改成<code>\\</code></li>
<li>绕远路
<ol>
<li>bot能回复我的命令了，但生成出来的声音只是吹气，或者是简单的一个词。虽然音色上有点像了。</li>
<li>怀疑是爆显存，因为我web没关，但排查后发现不是。</li>
<li>怀疑是api版本的问题，默认用的是v2。尝试切回v1,结果发现用v1版的更麻烦，于是还是老老实实用v2，也就是<a href="https://github.com/jianchang512/gptsovits-api"  target="_blank" rel="noopener" >jianchang512/gptsovits-api: 适用于 GPT-SoVITS 的api调用接口</a>,这里的文档相对来说更详细。</li>
<li>尝试debug<a href="https://github.com/zhaomaoniu/nonebot-plugin-gpt-sovits"  target="_blank" rel="noopener" >zhaomaoniu/nonebot-plugin-gpt-sovits</a>和<a href="https://github.com/RVC-Boss/GPT-SoVITS"  target="_blank" rel="noopener" >RVC-Boss/GPT-SoVITS: 1 min voice data can also be used to train a good TTS model! (few shot voice cloning)</a>，其实就是看几个参数变量能不能对得上,没啥结果。</li>
<li>用postman发了下请求，意外地没问题。然后就发现自己在配置文件的参考音频的路径那少打了一个<code>\</code>，:(</li>
</ol>
</li>
</ul>
<h2 id="画饼">画饼</h2>
<h3 id="接入llm">接入llm</h3>
<p>我这个bot主要是想让她来rp高松灯，或者说是rp羊姐。那现在她已经能够发声了，但每次发声还是靠我们给她手动输入的指令。能不能让她接入llm，能比较智能的根据上下文，主动的出来说几句呢？</p>
<p>我在插件商店搜到过几个llm插件，但不少都似乎不可用，也许只是因为版本迭代更新不及时导致的。后面可以尝试下。</p>
<h3 id="长文本">长文本</h3>
<p>接下来就是要解决长文本的问题了。最理想的情况是，我丢一本书进去，直接给我吐生成好的音频。</p>
<ul>
<li><a href="https://zidonglaoli.com/c231.html"  target="_blank" rel="noopener" >用Python代码调用GPT-SoVITS | 自动老李的博客</a></li>
<li><a href="https://github.com/RVC-Boss/GPT-SoVITS/issues/1256"  target="_blank" rel="noopener" >我改进了一下文本切分方式，这似乎能极大改善长文本生成的质量。 · Issue #1256 · RVC-Boss/GPT-SoVITS</a></li>
<li><a href="https://github.com/jianchang512/gptsovits-api"  target="_blank" rel="noopener" >jianchang512/gptsovits-api: 适用于 GPT-SoVITS 的api调用接口</a></li>
<li><a href="https://www.bilibili.com/video/BV1DJF6eHE4y"  target="_blank" rel="noopener" >GPT-SoVITS一键配音集成包推出，srt字幕一键配音，可音频转字幕</a> 这个把我想做的做好了，甚至功能还有溢出。</li>
</ul>
<h3 id="给我的博客也接入">给我的博客也接入</h3>
<p>高松灯的一大技能是念诗，我的博客有摘抄些诗词，可以让她念念。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>frp实现ssh内网穿透连接</title>
      <link>https://ds63.eu.org/2024/use_frp_to_ssh/</link>
      <pubDate>Sun, 15 Dec 2024 23:15:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/use_frp_to_ssh/</guid>
      <description>frp is awesome</description>
      <content:encoded><![CDATA[<h2 id="版本">版本</h2>
<p>本文章使用的版本为frp_0.61.0_linux_amd64</p>
<hr>
<h2 id="工作原理">工作原理</h2>
<p>frp 主要由两个组件组成：客户端(frpc) 和 服务端(frps)。通常情况下，服务端部署在具有公网 IP 地址的机器上，而客户端部署在需要穿透的内网服务所在的机器上。</p>
<p>由于内网服务缺乏公网 IP 地址，因此无法直接被非局域网内的用户访问。用户通过访问服务端的 frps，frp 负责根据请求的端口或其他信息将请求路由到相应的内网机器，从而实现通信。</p>
<hr>
<h2 id="需求">需求</h2>
<p>我有一台配有公网ip的服务器，以及两台linux电脑，分别称为电脑a和电脑b。</p>
<p>我希望使用电脑a，在非局域网环境下，也能使用ssh访问电脑b。</p>
<hr>
<h2 id="服务端配置">服务端配置</h2>
<ul>
<li>假定我的服务器的ip为<code>6.6.6.6</code></li>
<li>安装目录位于: <code>/home/ubuntu/frp/frp_0.61.0_linux_amd64</code></li>
<li><code>frps.toml</code>文件为服务端的配置文件,内容如下
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c">#服务绑定的IP与端口</span>
</span></span><span class="line"><span class="cl"><span class="nx">bindAddr</span> <span class="p">=</span> <span class="s2">&#34;0.0.0.0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">bindPort</span> <span class="p">=</span> <span class="mi">7000</span>
</span></span><span class="line"><span class="cl"><span class="c">#web dashboard配置</span>
</span></span><span class="line"><span class="cl"><span class="nx">webServer</span><span class="p">.</span><span class="nx">addr</span> <span class="p">=</span> <span class="s2">&#34;0.0.0.0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">webServer</span><span class="p">.</span><span class="nx">port</span> <span class="p">=</span> <span class="mi">7001</span>
</span></span><span class="line"><span class="cl"><span class="nx">webServer</span><span class="p">.</span><span class="nx">user</span> <span class="p">=</span> <span class="s2">&#34;admin&#34;</span> <span class="c"># change</span>
</span></span><span class="line"><span class="cl"><span class="nx">webServer</span><span class="p">.</span><span class="nx">password</span> <span class="p">=</span> <span class="s2">&#34;admin&#34;</span> <span class="c"># change</span>
</span></span><span class="line"><span class="cl"><span class="c">#启用prometheus监控指标</span>
</span></span><span class="line"><span class="cl"><span class="nx">enablePrometheus</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="c">#token权限验证，需与客户端配置一致</span>
</span></span><span class="line"><span class="cl"><span class="nx">auth</span><span class="p">.</span><span class="nx">method</span> <span class="p">=</span> <span class="s2">&#34;token&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">auth</span><span class="p">.</span><span class="nx">token</span> <span class="p">=</span> <span class="s2">&#34;simpletoken&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c">#日志配置</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">to</span> <span class="p">=</span> <span class="s2">&#34;/home/ubuntu/frp/frp_0.61.0_linux_amd64/frps/logs/frps.log&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">level</span> <span class="p">=</span> <span class="s2">&#34;info&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">maxDays</span> <span class="p">=</span> <span class="mi">3</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="启动服务端">启动服务端</h3>
<ul>
<li>
<p><strong>命令行方式启动</strong>:</p>
<p><code>./frps -c ./frps.toml</code></p>
</li>
<li>
<p><strong>使用systemd方式启动</strong></p>
<ol>
<li>配置文件<code>/etc/systemd/system/frps.service</code>,具体内容如下</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="o">[</span>Unit<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 服务名称，可自定义</span>
</span></span><span class="line"><span class="cl"><span class="nv">Description</span> <span class="o">=</span> frp server
</span></span><span class="line"><span class="cl"><span class="nv">After</span> <span class="o">=</span> network.target syslog.target
</span></span><span class="line"><span class="cl"><span class="nv">Wants</span> <span class="o">=</span> network.target
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Service<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Type</span> <span class="o">=</span> simple
</span></span><span class="line"><span class="cl"><span class="c1"># 启动frps的命令，需修改为您的frps的安装路径</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStart</span> <span class="o">=</span> /home/ubuntu/frp/frp_0.61.0_linux_amd64/frps -c /home/ubuntu/frp/frp_0.61.0_linux_amd64/frps.toml
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Install<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">WantedBy</span> <span class="o">=</span> multi-user.target
</span></span></code></pre></div><ol start="2">
<li>启动服务
<ul>
<li><code>systemctl daemon-reload</code></li>
<li><code>systemctl start frps</code></li>
</ul>
</li>
</ol>
</li>
</ul>
<hr>
<h2 id="客户端配置">客户端配置</h2>
<ul>
<li>我将电脑b作为客户端</li>
<li>安装目录位于: <code>/home/ubuntu/Desktop/frp_0.61.0_linux_amd64</code></li>
<li><code>frpc.toml</code>文件为服务端的配置文件,内容如下
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="nx">serverAddr</span> <span class="p">=</span> <span class="s2">&#34;6.6.6.6&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">serverPort</span> <span class="p">=</span> <span class="mi">7000</span> <span class="c">#要和frps.toml的bindPort一致</span>
</span></span><span class="line"><span class="cl"><span class="nx">auth</span><span class="p">.</span><span class="nx">method</span> <span class="p">=</span> <span class="s2">&#34;token&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">auth</span><span class="p">.</span><span class="nx">token</span> <span class="p">=</span> <span class="s2">&#34;simpleToken&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">#日志配置</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">to</span> <span class="p">=</span> <span class="s2">&#34;/home/ubuntu/Desktop/frp_0.61.0_linux_amd64/logs/frpc.log&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">level</span> <span class="p">=</span> <span class="s2">&#34;info&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nx">maxDays</span> <span class="p">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[[</span><span class="nx">proxies</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;ssh&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">type</span> <span class="p">=</span> <span class="s2">&#34;tcp&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">localIP</span> <span class="p">=</span> <span class="s2">&#34;127.0.0.1&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">localPort</span> <span class="p">=</span> <span class="mi">22</span>
</span></span><span class="line"><span class="cl"><span class="nx">remotePort</span> <span class="p">=</span> <span class="mi">6000</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="启动客户端">启动客户端</h3>
<ul>
<li>
<p><strong>命令行方式启动</strong>:</p>
<p><code>./frpc -c ./frpc.toml</code></p>
</li>
<li>
<p><strong>使用systemd方式启动</strong></p>
<ol>
<li>配置文件<code>/etc/systemd/system/frpc.service</code>,具体内容如下</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="o">[</span>Unit<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Description</span> <span class="o">=</span> frp client
</span></span><span class="line"><span class="cl"><span class="nv">After</span> <span class="o">=</span> network.target syslog.target
</span></span><span class="line"><span class="cl"><span class="nv">Wants</span> <span class="o">=</span> network.target 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Service<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Type</span> <span class="o">=</span> simple
</span></span><span class="line"><span class="cl"><span class="c1"># 启动frps的命令，需修改为您的frpc的安装路径</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStart</span> <span class="o">=</span> /home/ubuntu/Desktop/frp_0.61.0_linux_amd64/frpc -c /home/ubuntu/Desktop/frp_0.61.0_linux_amd64/frpc.toml
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Install<span class="o">]</span> 
</span></span><span class="line"><span class="cl"><span class="nv">WantedBy</span> <span class="o">=</span> multi-user.target
</span></span></code></pre></div><ol start="2">
<li>启动服务
<ul>
<li><code>systemctl daemon-reload</code></li>
<li><code>systemctl start frpc</code></li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="访问">访问</h2>
<ul>
<li>命令: <code>ssh -o Port=6000 ubuntu@6.6.6.6 -i ~/my_key.pem</code></li>
<li>注释
<ul>
<li>这里的<code>Port</code>为<code>frpc.toml</code>中设置的<code>remotePort</code></li>
<li><code>-i ~/my_key.pem</code> ，我是用来ssh连接<code>6.6.6.6</code>的</li>
<li>这里的<code>ubuntu</code>为电脑b的用户名</li>
<li>登录上后如果需要密码,那尝试输入电脑b的密码</li>
</ul>
</li>
<li>可以这样配置<code>~/.ssh/config</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Host 电脑b
</span></span><span class="line"><span class="cl">  HostName 6.6.6.6
</span></span><span class="line"><span class="cl">  Port <span class="m">6000</span>
</span></span><span class="line"><span class="cl">  User ubuntu
</span></span><span class="line"><span class="cl">  IdentityFile ~/.ssh/my_key.pem
</span></span></code></pre></div></li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://github.com/fatedier/frp"  target="_blank" rel="noopener" >fatedier/frp: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.</a></li>
<li><a href="https://gofrp.org/zh-cn/docs/"  target="_blank" rel="noopener" >文档 | frp</a></li>
<li><a href="https://github.com/fatedier/frp/issues/1607"  target="_blank" rel="noopener" >请问frpc里面可以设置多个server_addr吗？ · Issue #1607 · fatedier/frp</a></li>
<li><a href="https://www.cnblogs.com/hovin/p/18023593#_label4_2"  target="_blank" rel="noopener" >使用Frp配置内网访问（穿透） - hovin - 博客园</a></li>
<li><a href="https://wiki-power.com/%E4%BD%BF%E7%94%A8frp%E8%AE%BF%E9%97%AE%E7%BE%A4%E6%99%96NAS/"  target="_blank" rel="noopener" >使用 frp 访问群晖 NAS - Power&rsquo;s Wiki</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>本科就业二三事</title>
      <link>https://ds63.eu.org/2024/something_about_undergraduate_employment/</link>
      <pubDate>Fri, 01 Nov 2024 00:38:56 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/something_about_undergraduate_employment/</guid>
      <description>自己淋过雨，那就试着帮后来人撑个伞</description>
      <content:encoded><![CDATA[<h2 id="说明">说明</h2>
<p>某日参加活动，冗长无趣，回想过去的一年，内心百感交集，于是写了<a href="https://tieba.baidu.com/p/9245889452"  target="_blank" rel="noopener" >本科就业二三事【东南大学吧】_百度贴吧</a>。</p>
<p>本篇内容是对贴吧内容的再排版，面向的群体主要是有意愿本科就业的计算机类学生。</p>
<hr>
<h2 id="缘起">缘起</h2>
<p>明天就是十一月了，我的秋招也大概率就这样结束了，回首过去一年，自己有焦虑，有焦虑，还是焦虑。</p>
<p>博主本身也不是什么嘎嘎收割offer的技术大佬，但这一年艰难求职路上最遗憾的就是没有一位已经参加工作，或者说有相关经验的大哥大姐来传授经验，指明下方向，只能靠自己和网上搜集到的信息，一步一坑地走了过来。</p>
<p>于是抱着既然自己淋过雨，那就试着帮后来人撑个伞的想法，就用这贴谈下自己微不足道的经验和感想。</p>
<hr>
<h2 id="有哪些就业方向">有哪些就业方向</h2>
<p>一般本科计算机毕业求职有几个方向:前端开发和后端开发,再然后就是测试和嵌入式。单从我个人了解，东南本科课程接触嵌入式的机会不多，而测试我也不太熟。</p>
<p>于是重点谈谈前端和后端开发。</p>
<h3 id="前端开发">前端开发</h3>
<p>我本人选择了前端开发。一个基本的学习路线大概是 先学html，js，css三件套，然后选择个框架vue或者react继续学。</p>
<p>面试的时候其实也大概率就围绕着js，css来问，再问点框架就差不多了。</p>
<p>但要注意的是，我参加的面试中，尤其大厂，很喜欢问计网。而博主这届又没开正儿八经的计网必修课，导致前期每次被问到都很被动。</p>
<h3 id="后端开发">后端开发</h3>
<p>国内后端开发主要的技术栈以Java为主，有部分go或者Node.js，但只是少数。当学完SpringBoot后，再补补MySQL，Redis，也就可以试试投简历找实习了。</p>
<h3 id="前后端的选择">前后端的选择</h3>
<p>再来谈谈前后端的选择。</p>
<p>我个人其实一开始先学的后端。跟着<a href="https://liaoxuefeng.com/books/java/springboot/index.html"  target="_blank" rel="noopener" >Spring Boot开发 - Java教程 - 廖雪峰的官方网站</a>学了SpringBoot后，自己也写过一个小项目。</p>
<p>但想更进一步的时候发现就要到SpringCloud，微服务之类的针对高并发的设计。而我又缺乏实际的场景，虽然可以用脚本来模拟，但终究觉得有点无稽之谈的感觉。于是转而学前端。</p>
<p>前端对我来说更为直接，性能优化对我来说也更能有的放矢。整体来讲实时成就感更高些。于是就往这条路上走了。</p>
<p>以上是按我个人兴趣来谈的。那如果按我所观察到的就业市场的情况来比较的话。</p>
<p>国内中小厂对前端的态度普遍是锦上添花，简单的页面干脆就用低代码，或者让后端一并负责。所以前端的岗位比后端要少，而且是少很多。</p>
<p>但大厂相对来说前端需求还是比较大。而且由于偏见和发展较晚，前端对于学历的要求没有后端那么严苛。</p>
<p>对于车大毕业的本科生，至少国内大厂的前端岗位，基本上都是投了简历大概率就能拿个面试。这点也是个信息差。</p>
<hr>
<h2 id="两个关键的时间段">两个关键的时间段</h2>
<h3 id="秋招">秋招</h3>
<p>秋招往年有个说法，叫金九银十，但今年来说相对更卷。八月份就有公司开提前批，厉害的大佬甚至能做到九月初就能结束秋招。</p>
<p>而秋招面向的人群主要为当时正在上大四，也就是次年毕业的学生。</p>
<p>相对于春招来说，秋招岗位更多（看到有说法甚至是十倍），竞争更小（因为等春招会有考研考公失败的人群加入），而且相对来说没那么焦虑（至少还不是马上要毕业）。</p>
<p>所以特别建议有意向本科就业的同学把握好秋招。</p>
<h3 id="春招">春招</h3>
<p>春招则是每年的三月份开始，一直到四五月份。楼主还没真正参与过，了解不多。</p>
<p>但每年的春招除了面向当年的毕业生，还有一个很重要的用途。那就是招暑期实习生。暑期实习主要面向的就是上半年大三下的同学。</p>
<p>一段暑期实习的重要性很高。它直接关系于你能否过简历初筛，还能帮助你在面试中有东西能被面试官问。就我个人经验来说，面试官其实也懒得问八股，但前提是你简历上写的项目，实习他觉得有意义，能问。</p>
<p>不过有一点很操蛋的是，暑期实习时间一般是每年的六到九月。那九月的时候你就要面临到底是能不能转正，还是专心准备秋招的选择。</p>
<hr>
<h2 id="实习">实习</h2>
<h3 id="几段实习比较好">几段实习比较好</h3>
<p>实习经历肯定是韩信点兵——多多益善，但每段的时长要尽量保证在三个月以上。</p>
<p>一般秋招的时候有一段实习已经够门槛了。而且根据我自身的经验，我们学校大三上的课多得除非你不上，或者拿短短的一两个月寒暑假去实习，那很难在大三上腾出时间去实习。但大三下的课能少不少，机会也比较多。</p>
<p>所以我个人感觉一个比较理想的情况是: 大三下的三四五月做第一段实习，小厂就行，当入门砖；然后六月份开始第二段实习，也就是六七八三月做第二段实习，这时候有前一段实习的经验，那很可能可以进中厂或者大厂。九月份就看是否能够转正，不行就拿这两段实习去秋招，也很够了。</p>
<p>当然，也能看到有人大二就开始自习。但那就不是普通人了。</p>
<h3 id="怎么找实习">怎么找实习</h3>
<p>东南的计软智专业都对实习有时间要求。计科和人智要求一个月，软件则要求三到六个月。</p>
<p>学校会在大三下帮助联系一些企业，但实际上大部分企业都还是需要进一步面试，不是点击就送。而且学校联系到的企业和给的岗位数量，似乎一年比一年少（仅代表我自己对比去年和今年后的感受）。因此大部分人其实还得靠自己。</p>
<p>那靠自己该怎么找实习。我更推荐的是去官网投，每年春秋招企业都会开放一批实习岗位，还有几乎全年都有的日常实习。</p>
<p>有一点信息差在于: 每年过年前的那段时间，企业会比较缺人，找实习会比较好找。</p>
<p>另外还有两个我自己用得比较多的平台。</p>
<p>一个是牛客网，不少找工作，尤其是找互联网相关工作的都会在上面吐槽，分享面经。大家闲得没事干的话可以刷刷牛客网，好增加点焦虑感。牛客上也会有些hr，你把简历完善后，可以等hr来主动找你。</p>
<p>再然后就是Boss直聘，但我用的不算多，因为公司良莠不齐。而且大家真用的话就会发现上面最多的是华为的hr。</p>
<p>有吧友推荐实习僧，可供参考。</p>
<p>不过我自己的第一份实习就是在Boss上找的,意外的是一家很棒的公司。在那家公司的实习经历让我提升了很多。</p>
<p>但还是建议各位找工作的时候擦亮眼镜，小心诈骗。</p>
<hr>
<h2 id="双选会">双选会</h2>
<p>学校每年的话会组织两场大型的双选会。三月份一场，九月份一场。</p>
<p>我去过去年的秋招和上半年的春招双选会，没投简历，纯感受氛围。</p>
<p>今年的秋招我双选会时间我记得特别清楚，是九月二十一日。但好巧不巧，它和MyGo!!!!!上海演唱会撞了。</p>
<p>所以我想都没想就去看演唱会了，好在后来也不后悔。</p>
<p>双选会给我的感觉就是，对于计算机类的帮助不大。因为大部分互联网公司还是靠网上投简历。</p>
<p>再者就是我爬了今年秋招双选会的职位列表，一搜，前端好像就三四个，这去了也意义不大,呵呵。</p>
<hr>
<h2 id="名词解释">名词解释</h2>
<ul>
<li>意向: 指录取意向书，代表你通过了所有面试，并且从池子里泡出来，企业愿意招你，但具体待遇还得等等。大部分公司不会去毁意向。</li>
<li>offer: 指录用通知函，也就是offer letter，这时候就会带有薪资，并要求你在规定时间内寄出三方，逾期失效。</li>
<li>感谢信: 讲究点的公司会在招聘流程终止后给你发封邮件说流程中止。</li>
<li>泡池子: 这是今年特别普遍的现象。指的是当你通过了所有面试后进入到的录用评估环节。通过面试的人会有复数个，公司根据面评，学历背景等进行排序。排序高的优先联系。但往往排序高的人手头的offer也比较多，所以就会轮到下一位，甚至一直往后轮。有些公司甚至能出现被鸽穿的情况(池子里的一个都不接offer)。其实这是个两害的情况: 面试者因为拿不到确切的意向，只能多面。而公司因为不能确定求职者是否愿意来，于是也只能多面，然后多捞人进池子。泡池子的流行对双方都没有好处。</li>
<li>a薪资: a是argue的缩写。特别优秀的求职者能有这个环节。hr一般会询问目标薪资，这时候如若你手头上有多个offer可供选择，而且公司认可你的表现，那么你就可以以此为基础，去尝试争取更高的薪资。祝读者们都有机会能够a薪资。</li>
</ul>
<hr>
<h2 id="一次求职的标准流程">一次求职的标准流程</h2>
<h3 id="流程">流程</h3>
<ol>
<li>投简历</li>
<li>简历筛选过后，会通知做笔试和测评（不一定有）</li>
<li>两到三轮面试（技术或hr,不同公司面试轮数，类型不同）</li>
<li>泡池子(不一定有)</li>
<li>意向(不一定有，有的公司是直接给你最终带有薪资待遇的offer)</li>
<li>oc</li>
</ol>
<h3 id="投简历到底是要多投还是少投">投简历到底是要多投还是少投</h3>
<p>我找暑期实习的时候还挑三拣四，看了不少，但没投几家，结果也没几家面试。</p>
<p>秋招的时候则是自己投太晚了，主要是两方面原因:</p>
<ol>
<li>自己拖延，有点畏惧秋招。</li>
<li>实习项目还有部分没完成。</li>
</ol>
<p>于是拖到了九月下旬才投。</p>
<p>刚开始还想着一波一波地投 到后面急了，集中把能投的都投了遍，总共投了六十来家。</p>
<p>也不知道是不是投得晚还碰巧被我赶上了。因为十月份可能公司都怕被鸽，于是约面的也挺多。</p>
<p>不过代价就是国庆后的二十来天都处于高负荷的笔试和面试，大家不要学我。</p>
<p>还是那句话: 趁早准备，趁早投递，趁早oc。</p>
<hr>
<h2 id="技术面试">技术面试</h2>
<h3 id="大致流程">大致流程</h3>
<ol>
<li>自我介绍。</li>
<li>看面试官对你项目感不感兴趣，感兴趣就让你对项目进行介绍，进而问项目细节（这里就体现了一个好的项目或者一段有价值的实习经历的重要性）</li>
<li>问八股。有些面试会类似于名词解释，他问你答，然后就下一题。但有些厉害的面试官会根据你的回答做进一步深挖，这就很考验对知识的理解</li>
<li>手撕。看公司了，有的有。手撕一般不会太难，力扣easy差不多，最多就middle，出hard一般就代表着劝退，人不想要你。</li>
<li>反问。</li>
</ol>
<h3 id="面试前能做的准备">面试前能做的准备</h3>
<p>面试前我一般喜欢搜面经，关键词就是公司+岗位+第几次面试，如果能知道部门那就更好了。牛客上或谷歌上搜，大概率都会有。</p>
<p>搜面经的一大原因是，大部分面试官其实出题，尤其是手撕题都会从题库里去取。而一家公司或者一个部门准备的题库其实是有限的，那么就很容易考察面经中出现过的题目。</p>
<p>再退一步说，出现在面经的题，其实相当于经过了面试官和面试者的两重筛选。面试官觉得有意义，于是出这道题，面试者被测后留有印象，于是记录了下来。</p>
<p>总而言之，如果觉得背八股范围太广不好准备。那么看面经总是没错的。</p>
<h3 id="面试后该做的事">面试后该做的事</h3>
<p>我的一个习惯是，面试后稍微休息下，起来走走。然后就写面经。我之前倒也尝试过录音，但发现自己有种羞耻，不太愿意去听自己的录音，拖久了自己也犯懒。于是还不如当场记录。</p>
<p>记面经的好处在于，你自己后面可以参考，可以复盘，看是哪些地方答的不好。</p>
<p>尤其是项目。因为简历上的项目就那些，那么面试官针对项目所问的内容和角度其实也是有限。那么你就可以通过这一次次的被拷问中去巩固，加深你对项目的理解。</p>
<p>另一个值得注意的是，对于被问到的并且你没答好的八股或者手撕，那么最好当天就给巩固好。</p>
<p>我自己就吃过这方面的亏。因为我曾不止一次地被问到“https的具体原理”，前两次我都觉得只是凑巧，没放心上,或者是觉得后面不会再被问了。直到第三次被问到我才去恶补了下，然后才发现，这玩意其实我差不多会啊，但我第一次没说上来，再然后两次都因为惯性就直接说不会了。这就错失了几次本来可能有好结果的面试。</p>
<hr>
<h2 id="八股">八股</h2>
<h3 id="为什么要记八股">为什么要记八股</h3>
<p>我之前有点认为记八股是一种应试行为，有点抵触。并且认为这些知识我真正需要用到的时候网上一查就有了。GPT记得比我好多了。</p>
<p>但有天晚上我排查<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid</a>出现的一个问题,为了完全搞懂，我就自发地去搜React的生命周期。</p>
<p>这时候我意识到八股的那些问题，其实不少是蛮常见的问题。要写好代码确实得去知道。八股确实有其意义，它是日常工作中需要掌握的知识的浓缩，当我遇到一些比较刁钻的bug无从下手，那常常是我对于该方面的某个八股知识点一无所知。</p>
<p>于是我就和八股和解了，该记还是得记。</p>
<h3 id="被问到八股怎么答">被问到八股怎么答</h3>
<p>看<a href="https://www.nowcoder.com/discuss/590189774611247104"  target="_blank" rel="noopener" >面试官视角下的技术面——为什么要“背八股”_牛客网</a>,我进一步认识到如果被问八股，要学会自己主动去延伸，进而在一定程度上把握面试的主动权。</p>
<p>面试时被问到八股时，可以简单分为两种情况。</p>
<ul>
<li>一种就是你会，那首要的就是清晰的回答面试官的问题，然后再适当的引申。尤其是如果你有实际遇到过的经历，那就自行扩展，这将是一个挺好的加分点。但记得不能太散，而且最好最后还要兜回主题上来，不然就显得你在乱扯。</li>
<li>第二种就是你不会。我一般这种情况会有两种处理方式。两种的开头都是直接说我不会。接下来看面试官的要求，如果面试官想让我再多说点，我会尝试引援相关知识，说下自己的推测。如果面试官给出下一题，那就下一题。</li>
</ul>
<h3 id="八股问答的意义">八股问答的意义</h3>
<p>八股问答，回答上来不是加分项。因为现在这种求职形势下，一位面试官在招聘期间所有面试的应聘者肯定不在少数。而八股又是相对来说比较好准备的。那也就是说，只要不是太偏，那大部分人都能答上来。那这时候的加分项就在你能不能有自己的思考，并能清晰明了的表达出来。</p>
<p>比如说前端的经典八股“跨域问题及其解决”,我就很喜欢补充<a href="https://ds63.eu.org/2024/cors_problem/#%E5%AE%9E%E9%99%85%E9%81%87%E5%88%B0%E8%BF%87%E7%9A%84%E9%97%AE%E9%A2%98"  target="_blank" rel="noopener" >自己实际遇到过的问题 | EuDs&rsquo;s Blog</a></p>
<p>那答不上来算不算减分项呢？也可以不算。因为一场面试短则半小时，长则一个小时往上，如非特别记录，其实有时候面试官他自己问了啥问题都有可能忘记。</p>
<p>那我们能做的就是尽可能不要去强化他对你八股答不上来的这段记忆。于是乎：快速略过而不是胡扯，我觉得是个比较好的处理方式。</p>
<hr>
<h2 id="算法手撕">算法(手撕)</h2>
<h3 id="重要性">重要性</h3>
<p>说完八股，那很自然地就得说说算法。</p>
<p>相比于背八股，我更不喜欢刷算法题。虽然去年的时候曾决心要每天刷一题，结果没坚持一个月就放弃了。原因是我没找到其中的意义。</p>
<p>但算法题又直接关乎着求职过程中的两个重要的环节：笔试和面试结尾的手撕。笔试一般只是个基本的敲门砖，但结尾的手撕却很伤。因为它是在面试快结束的时候，而且时间至少在十分钟以上。那这段时间给面试官的印象就会很深。因而也就有人说，手撕能不能撕出来，直接决定了面试能不能通过。</p>
<h3 id="考察的内容">考察的内容</h3>
<p>好在面试时出的算法题一般难度就在leetcode的easy难度左右，出更难的题一般也意味着面试官不太想要你了。</p>
<p>而且前端出的手撕题不少都是场景实现题，准备下大概能八九不离十。</p>
<ul>
<li><a href="https://juejin.cn/post/7210979444760772664"  target="_blank" rel="noopener" >面试中的手撕代码（一）总结了一些面面试中常见的手写代码题，如有更好见解欢迎评论指正~ - 掘金</a></li>
<li><a href="https://github.com/Sunny-117/js-challenges?tab=readme-ov-file"  target="_blank" rel="noopener" >Sunny-117/js-challenges: ✨✨✨ Challenge your JavaScript programming limits step by step</a></li>
</ul>
<h3 id="考察的目的">考察的目的</h3>
<p>除了具体的内容，明确手撕题所想考察的目的也很重要,我个人觉得有如下几点:</p>
<ol>
<li>逻辑思维能力: 具体来说就是怎么思考问题，怎么拆分问题的。直接反应就是写代码前你所描述的思路。</li>
<li>代码能力：一场面试中能真正考察你代码能力的其实也就只有手撕了。代码能力不是要求你一遍就能把代码跑通，更多的是看你的一些细节： 命名规范，合理且合适的注释，常用api的熟悉程度。</li>
<li>debug能力: 面试时所提供的平台一般都支持运行。当你写完代码后，你发现运行不了。这时候你该怎么排查。更进一步，当测试用例不通过的时候，你如何通过debug发现问题所在，这都能见微知著，体现你真实情况下的代码能力。</li>
</ol>
<h3 id="真写不出来怎么办">真写不出来怎么办</h3>
<p>再退一步说，如果真写不出来，有什么能够补救的方法。</p>
<p>这点是我所擅长的，因为我百分之五十的面试的手撕题是没办法写出来的，更不用说写出最优解。</p>
<p>那这时候我就会尝试先用最简单的暴力方法先过了测试用例。然后再尝试去看看能不能有优化方法。</p>
<p>或者甚至有个比较猥琐的方法。当你发现一道题第一眼看你一点思路都没有，那你可以尝试请面试官换一题，理由包括但不限于说这道题你在之前的面试中有做过等等。</p>
<p>切忌就是别在那里发呆，或者显得不知所措。</p>
<hr>
<h2 id="反问">反问</h2>
<p>大部分面试都会有反问环节。我一开始也不知道反问环节问啥，但面的次数多了自然也就悟了。以下是我的主观想法，大佬轻喷。</p>
<h3 id="没必要问的问题">没必要问的问题</h3>
<p>有些问题没必要去问，比如:</p>
<ol>
<li>您觉得我表现怎么样,我能通过吗？</li>
</ol>
<p>一般面试官都挺避讳去直接回答面试结果，只会打个哈哈，问其实也是白问。</p>
<ol start="2">
<li>您对我有什么建议吗？</li>
</ol>
<p>有人说这是当自己觉得这场面试寄了才问的问题,这代表了对自己的不自信。我也确实是这样做的，尤其是当我觉得这场面试多半寄了，那我就会问这个问题。因为至少还能让这场面试稍微有点收获。</p>
<p>不过多次面试下来，当我问这个问题之后，我似乎也并没怎么得到到过有价值的建议。</p>
<ol start="3">
<li>薪资待遇问题?</li>
</ol>
<p>特指技术面。真到了谈薪的时候也不用问，hr自然会问你期望薪资。</p>
<h3 id="可以问的问题">可以问的问题</h3>
<p>有些问题可以问，而且值得问:</p>
<ol>
<li>就某项技术，先提出自己的想法，再询问面试官的想法。</li>
</ol>
<p>我挺喜欢这样问的，比如我就很尝问面试官对js或者是前端的看法。因为面试官的工作经验比我丰富，他们对这一技术的掌握程度更深，也常会有值得我去学习的观点。就单单能了解下这些新的观点，我觉得这场面试就挺值的了。</p>
<ol start="2">
<li>部门的具体业务。</li>
</ol>
<p>大多数情况下，你的面试官所在的部门也将会是你入职所在的部门。因此你可以从中了解到部门业务的第一手信息。请记住，面试其实是双向筛选，你也有选择公司,部门，业务的权利。如果部门的业务是你感兴趣的，或者你觉得有价值的，那未来工作时也能觉得更有意义。</p>
<p>另外，你还可以从面试官的回答的用心程度来推测自己面试是否能够通过。</p>
<ol start="3">
<li>你自己感兴趣的问题</li>
</ol>
<p>这里就因人，因公司而异了，属于可遇不可求。比如我自己其实也就只问过两个这类的问题：</p>
<p>一次是面试百度，我说自己特别喜欢百度贴吧，但很遗憾地发现百度贴吧的网页端几乎不怎么维护了，报错信息都一堆，问是怎么了。</p>
<p>另一次是面试4399，因为从小到大4399带给了我不少乐趣,我问了进去后有机会去做那些小游戏吗。</p>
<hr>
<h2 id="要不要本科就业">要不要本科就业</h2>
<p>其实这段内容应该放在前面，但我写完发现过于主观，全是我自己的观点，没啥参考意义。于是干脆往后放。</p>
<p>如果读者有耐心读到这段，说明你确实有考虑本科就业且有一定的耐心。那就不妨再看几句我的啰嗦。</p>
<p>我认为只有自己选择的路走起来才不会后悔，所以我不劝读者到底要选择就业还是继续深造。</p>
<h3 id="我自己的观点">我自己的观点</h3>
<p>以下是我自己的观点,或者说，我是如何说服自己选择就业的。主要有三个原因:</p>
<ol>
<li>兴趣</li>
</ol>
<p>自己有尝试过所谓的科研。我大二大三的时候参与过两个SRTP项目，一个是校级，一个是国家级。两个项目都顺利完成并有较好的评级，但我从中发现，自己并不享受其中的过程。</p>
<p>但实习的半年来，我确确实实能体验到其中的乐趣与成就感。于是我就确定了我要走的路，那我就业吧。</p>
<p>我觉得这点其实是最重要的一点。我觉得做任何事如果能刚好符合自己的兴趣，做起来自己认可，那么就不怎么会太煎熬，也不会觉得后悔。或者讲得中二一点，听凭自己的内心，如果有一条路你发现自己还蛮喜欢的，那就走下去吧。</p>
<ol start="2">
<li>我对未来形势的悲观。</li>
</ol>
<p>我不止看到一个人吐槽，说自己要是不读这个研该多好，因为他发现读研前能去的公司，现在毕业后反而难进了。三年前是这样，那三年后呢？三年后会更好吗，我看不到变好的迹象。因为导致形势变差的一系列问题都没有被解决。</p>
<p>但其实，这其实也可以成为反对本科就业的论据。因为既然以后形势更差了，那么你有一个更高的学位，你相对的就能有更强的竞争力。而所谓的工作经验。有三年工作经验的人比比皆是。我认为这说得也没错。</p>
<ol start="3">
<li>我害怕考研，读研失败的沉没成本。</li>
</ol>
<p>我从高三的时候就发现，让我用一年的时间去反复练习已有的内容，我坐不住，嫌无趣，觉得是在浪费大好时间。于是我高三花了不少时间在让自己枯燥的复习中找到点乐趣。</p>
<p>由此也可以预见，我会受不了考研所要花费的复习过程。</p>
<p>再接着，侥幸我考研成功，我能遇到一位好的导师吗？网上的新闻把我看怕了。</p>
<p>更关键的是，我不确定读研这三年对我来说是收获还是浪费? 。我比较认可<a href="https://laike9m.com/blog/suo-yi-dao-di-yao-bu-yao-du-yan,119/"  target="_blank" rel="noopener" >所以，到底要不要读研？ - laike9m&rsquo;s blog</a>里作者的观点。但值得一提的是，这篇文章的作者是清华本科，中科院研究生。</p>
<h3 id="择业需要考虑三个维度的问题">择业需要考虑三个维度的问题</h3>
<p>以下是我对<a href="https://www.cnblogs.com/kidney/p/6624521.html"  target="_blank" rel="noopener" >转行一周年 - {Bison} - 博客园</a>这篇文章中，作者的观点的再描述：</p>
<ol>
<li>我适不适合做这份工作?进一步分为两类问题：
<ul>
<li>这份工作具体是干什么的?需要什么样的人来干?</li>
<li>我自己是什么样的人?有什么优点和缺点?</li>
</ul>
</li>
<li>我能不能做得比别人强?</li>
<li>我喜不喜欢做这份工作?</li>
</ol>
<hr>
<h2 id="薪资">薪资</h2>
<p>在<a href="https://tieba.baidu.com/p/9245889452"  target="_blank" rel="noopener" >本科就业二三事_百度贴吧</a>中有吧友问到本科平均薪资多少。</p>
<p>我只能说薪资是个敏感话题，而且千人千例,问平均没多大意义。</p>
<p>如果真对薪资感到好奇，可以去offershow上搜搜你感兴趣的公司+岗位+bg。那里的会比较真实点。</p>
<hr>
<h2 id="被裁了怎么办">被裁了怎么办</h2>
<p>有人会说我杞人忧天，还没正式工作呢，就开始担心被裁了。但自己看了太多有着丰富工作经验的前辈们被裁后的帖子了。</p>
<p>印象很深的是这个视频:<a href="https://www.bilibili.com/video/BV1om22YJEFA/"  target="_blank" rel="noopener" >好久不见，第一时间跟大家分享对于我来说这半年来最大的好消息</a>。这up之前干的是前端，后面被裁了，然后创业，创业失败了，找了好久的工作，没成功，最后去找到了份鸿蒙开发的外包的工作，工资待遇被之前降了不少，通勤距离也长了很多。但在视频结尾他已经控制不住情绪，哭了出来。</p>
<p>我目前的想法是努力提升自己吧，不仅是编码能力，还有其他的一些软实力，比如沟通，问题的分析、拆解。再者就是要尽量保证一个比较健康的身体状况和一定的积蓄。</p>
<p>被裁了我就找下一份工作，真找不到那我就回家吧。至少活下去是肯定没问题的。</p>
<hr>
<h2 id="我自己的经历">我自己的经历</h2>
<h3 id="写在前面">写在前面</h3>
<p>接下来讲讲我自己的经历,主要是我自己对过去几年的回顾，只能说有一定参考价值，不嫌弃的话可以看看。</p>
<h3 id="我的编程学习经历">我的编程学习经历</h3>
<ol>
<li>我上大学前并没有接触过编程。接触电脑倒挺早，幼儿园就开始了，玩电脑的时间也不少。但一直都只是玩。中小学电脑课的课程也没怎么涉及到编程，更别说让我对编程提起兴趣了。因此没能更早地接触编程其实是我的一大遗憾。</li>
<li>填志愿的时候其实自己的兴趣更偏向于自然方向。因为我选科选的生物地理，而且学得很轻松的同时也能拿到不错的成绩。但自己又偏向于就业。于是还是选了计算机。</li>
<li>说是计算机类，但大一和编程相关的课程其实就一门：程序设计基础，也就是c++。自己大一上的时候过得挺浑浑噩噩的，学的课程内容并不能让我对计算机提起兴趣。到了大一下。程序设计基础的期末作业是让我们写个小程序，类似于基础的成绩管理系统之类的。这时候开始有点兴趣了。</li>
<li>大一升大二的暑期可以说是我最忙的一个暑假。因为某些当时众所周知的原因，我的军训被推迟到这个暑期，和22级一起训。但我的暑期学校课程没办法推迟。暑期学校一共有两门课程，一门是专业阅读与写作，另一门是语言课程设计。语言课程设计是让我们要qt写个小程序。于是我得兼顾军训和暑期学校,这反倒进一步激起了我编程的兴趣。兴趣确实是最好的老师，我自学qt的同时，还入门了mysql，最后写了个基于qt实现的简易扫雷游戏。感兴趣的话可以看<a href="https://github.com/EuDs63/myMineSweeping"  target="_blank" rel="noopener" >EuDs63/myMineSweeping: 基于qt实现的简易扫雷游戏，含使用mysql的简易登录注册</a>，轻喷。</li>
<li>对编程感兴趣后，那剩下的一切就好办了。大二上的时间我主要用来学习后端,其实也就是JAVA，靠的是廖雪峰的教程，跟着敲完了基础和Spring Boot的代码。还学了点Python，因为我想写个bot，哈哈。还因为代码需要版本管理，于是Git也是很自然的就用起来了，Github也开始成为每天都会去逛的网站。（翻commit history才发现自己原来这学期也开始学前端了，但还仅限于前端三件套，入门水平都不算）</li>
<li>22年底的时候发生了一件大事，那就是ChatGPT发布了。有了它的帮助，那自学编程变得更加容易，有问题就问呗。</li>
<li>大二下的时候有一门课，软件工程导论。课程大作业是一个小组，搭一个小网站。我们写的网站当时候想仿照<a href="https://qwerty.liumingye.cn/"  target="_blank" rel="noopener" >Qwerty Learner — 为键盘工作者设计的单词与肌肉记忆锻炼软件</a>，但时间管理不行，没太成功。不过倒也挺有收获。因为通过这个项目，我实践了Spring Boot,还尝试了Vue3。同时为了将网站上线，那Nginx的使用也涉及到了。也就是说，这个项目锻炼了我全栈的能力。</li>
<li>大二下还有一门我很感兴趣的课，是操作系统。负责授课的老师讲得很好，纯理论也能讲得很风趣。我因为网上经常看到人推荐南京大学蒋炎炎的课程。出于好奇去看了一期。发现他是偏实践。于是两相结合下来，我的收获特别大。不仅是操作系统这门课学得很扎实，更是对计算机有了更浓厚的兴趣。同时我还接触了Linux。同时由于课本是英文的原版书,蒋炎炎老师也很鼓励读文档。于是也锻炼了我英语能力,大段的英文，之前看着有点怕，现在觉得也能看下来，并且速度还可以。可以说，大二下是我学习编程过程中进步最快的一个阶段。我感谢当时的自己，也感谢遇到的几位老师。</li>
<li>大二下还有件事值得提一嘴，23年3月的时候，我部署了自己的博客，后面写着写着也成习惯了。博客对于求职其实作用没那么大，因为面试官都挺忙的，面试者又多，哪有空给你点开来看。我面试这么多场，也就一位面试官表示他看过我的博客（这位面试官还算是我的直系学长，这倒也是缘分）。我认为博客更多的是给你提供一个表达自己想法的空间。如果你对我的博客感兴趣，请搜euds&rsquo;blog。</li>
<li>紧接着就是大二升大三的暑假了。暑期学校就一门课:专业技能实训。说白了还是小组一起写网站。一个月的时间从头走一遍软件开发的流程。我们这个项目做的是图书推荐系统。后端是python语言，flask框架。前端在我的建议下使用React，因为之前那个项目用过Vue了，没想到因此和React一见钟情，以后还全仰仗React来谋生了。这我也给放Github上了，<a href="https://github.com/EuDs63/BookRecommend_Front"  target="_blank" rel="noopener" >EuDs63/BookRecommend_Front: 图书推荐系统</a>。</li>
<li>大三上我花了不少时间来学Rust，出于兴趣。这时候没什么大的项目产出，只是写了点自己用的小工具。以及接触了点web assembly技术，看教程写了<a href="https://github.com/EuDs63/game_of_life"  target="_blank" rel="noopener" >EuDs63/game_of_life</a>。以及再要说的话就是把博客用的框架从hexo换为hugo了,因为这时候经过两个项目的锻炼,我前端已经算入门了,所以按着自己的想法改了改主题。</li>
<li>这年十一月份的时候尝试着投出了自己的第一份简历，经历了自己的第一次笔试，hr面，群面。漫长的等待并没有等到任何结果，也就此磨平了当时我尝试找份实习的想法。回头想想挺后悔的，其实大三上能有段实习经历的话，后面会更容易些。</li>
<li>很快啊，悠闲的时光就这样过去了。23年寒假一结束，回来上学的时候和同学一聊，我们想就业的该找暑期实习了。这时候自己还没太重视。想着先写个项目，不然简历上不好看。于是写了<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid: A lightweight tool offering key functionalities inspired by Postman.</a>，用的tauri这个框架，主要想体现跨端的能力。</li>
<li>写完项目，三月份开始投简历，这时候也得确定自己的方向了。我选择的是前端,因为那时候我觉得：后端当学习得比较深入，需要微服务，性能优化。但我缺乏实际环境，学习后端也成了无稽之谈。前端就不一样了,我能有实时的反馈，性能优化也能实时感知。</li>
<li>找暑期实习也是费了番功夫，但远不如秋招折磨。3月份开始投，4月初就有一家初创公司愿意收我，而且老板很器重我,自己也确实在实习过程中锻炼了自己的技术和认知。就这样一直到了9月底。实习的时候因为公司是初创公司。最大难点就是流量。而当辛苦把流量导进来的时候，那么前端页面就很重要。这段实习经历让我进一步确认了前端的重要性。</li>
<li>8月末的时候也知道这时候秋招开始了。但自己还在拖，一来是因为自己有点畏惧，二来是实习项目有些还没收好尾。直到9月底也是突然发现，自己再不好好投简历那秋招就要结束了。于是匆忙海投，投了得有七十家吧。国庆节一过，海投的后果出现了，自己几乎每天都是笔试和面试轮轴转，疲于奔命。自己的焦虑感达到了有生以来的最顶峰，每天早上起来都想吐，甚至进食堂都没啥食欲（不过不排除是食堂的缘故，毕竟它已经好久不换新的菜品了）。</li>
<li>一开始的几场面试几乎都是送人头。因为太久没面试了，自己也没准备好。一场面试三部分最重要：八股，项目，手撕。但我八股没怎么背。手撕自己又不愿意刷题，项目也没怎么讲明白。于是错失了不少机会。还好这时候运气好,面了个荣耀。他家主打一个面试阶段不刷人，让我过了一面，实现了0的突破。万事开头难。过了一次面试开始有了信心，八股我通过整理笔记的方式来记，手撕没办法速成，只能尽量做些常考的，项目是我自己实打实做的，于是也越讲越明白。就这样一直面试到10月底，在笔试了三十多场，也面试了三十多场后，还算有好的收获。</li>
</ol>
<h3 id="tldr">TL;DR</h3>
<p>前面写得太长了，因为写着写着就变成自己的回忆了。于是这里总结下。</p>
<ol>
<li>读者们要对自己有信心，尤其如果你读到这篇的时候刚入学没多久，或者刚升大二。那完全来得及。因为我也是这个时候才开始对计算机感兴趣的。</li>
<li>东南大学的课程其实设计得还算合理，该有的都有（除了我这届不知道为啥没将计网纳入必修，但下一届就补上这个bug了）。课程大作业好好做的话收获其实挺大的。</li>
<li>个人兴趣很重要。只有对计算机真正感兴趣，你才会愿意花时间去写代码，自发地去学习新知识。如果你选择了计算机专业，但你却没有发现学习计算机的乐趣。那么我建议你去看下蒋炎炎的操作系统课，或者尝试其他方法，先激发了兴趣再说。如果真没有兴趣，尽早转专业可能是条明路。</li>
<li>一次两次，甚至多次的面试失败都不要紧。因为面试运气成分很重。面试成功与否，取决你当时的状态，面试官的心情，面试官是否对你感兴趣,人是否招够了等诸多因素。面试失败不是你的问题，更关键的是从中吸取经验，为下次面试做准备。</li>
<li>有时间可以多学尝试些技术栈。因为谁也不难保证自己最感兴趣的技术就是自己第一次接触的。多接触不同的技术还有些好处，单编程语言，我就接触过c++,c,Java,Python,Rust,JavaScript,go。虽说贪多嚼不烂，但这些经历都让我在接触新的技术时不犯怵，因为我知道万变不离其宗，我知道要怎么学一项新的技术栈。</li>
</ol>
<hr>
<h2 id="推荐阅读">推荐阅读</h2>
<ul>
<li><a href="https://tieba.baidu.com/p/9249813683"  target="_blank" rel="noopener" >从放弃计科保研到秋招进互联网大厂，我是怎么做的？【秋招分享贴】【西北工业大学吧】_百度贴吧</a> 里面有些细节是我这个贴没涉及到的。</li>
<li><a href="https://tieba.baidu.com/p/9244869686"  target="_blank" rel="noopener" >大四ld记录计科就业贴【合肥工业大学吧】_百度贴吧</a> 这位楼主主攻国企就业，也是一个很好的方向。</li>
<li><a href="https://www.cnblogs.com/kidney/p/6624521.html"  target="_blank" rel="noopener" >转行一周年 - {Bison} - 博客园</a> 关于职业的选择</li>
<li><a href="https://www.cnblogs.com/kidney/p/8722226.html"  target="_blank" rel="noopener" >入行两周年 - {Bison} - 博客园</a></li>
<li><a href="https://www.nowcoder.com/discuss/606310357551820800?sourceSSR=users"  target="_blank" rel="noopener" >写给25届和26届—关于实习我想说的一切_牛客网</a> 实习的意义</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>前端安全</title>
      <link>https://ds63.eu.org/2024/frontend_security/</link>
      <pubDate>Fri, 11 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/frontend_security/</guid>
      <description>自己学习过程中整理的关于前端安全的知识点</description>
      <content:encoded><![CDATA[<h2 id="xss攻击">xss攻击</h2>
<ul>
<li>Cross-Site Scripting（跨站脚本攻击）简称 XSS，是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本，使之在用户的浏览器上运行。利用这些恶意脚本，攻击者可获取用户的敏感信息如 Cookie、SessionID 等，进而危害数据安全。</li>
<li>三种类型:
<table>
<thead>
<tr>
<th>类型</th>
<th>存储区</th>
<th>插入点</th>
</tr>
</thead>
<tbody>
<tr>
<td>存储型 XSS</td>
<td>后端数据库</td>
<td>HTML</td>
</tr>
<tr>
<td>反射型 XSS</td>
<td>URL</td>
<td>HTML</td>
</tr>
<tr>
<td>DOM 型 XSS</td>
<td>后端数据库/前端存储/URL</td>
<td>JavaScript</td>
</tr>
</tbody>
</table>
</li>
<li>DOM 型 XSS 跟前两种 XSS 的区别：DOM 型 XSS 攻击中，取出和执行恶意代码由浏览器端完成，属于前端 JavaScript 自身的安全漏洞，而其他两种 XSS 都属于服务端的安全漏洞。</li>
<li>防范
<ol>
<li>阻止攻击者提交恶意代码
<ul>
<li>输入过滤： 道高一尺魔高一丈，难</li>
<li>输入长度限制</li>
</ul>
</li>
<li>防止浏览器执行恶意代码
<ul>
<li>预防存储型和反射型 XSS 攻击
<ul>
<li>改成纯前端渲染，把代码和数据分隔开。</li>
<li>对 HTML 做充分转义</li>
</ul>
</li>
<li>预防 DOM 型 XSS 攻击</li>
</ul>
</li>
<li>利用 CSP 来抵御或者削弱 XSS 攻击，一个 CSP 兼容的浏览器将会仅执行从白名单域获取到的脚本文件，忽略所有的其他脚本</li>
<li>对关键 Cookie 设置 http-only 属性</li>
</ol>
</li>
<li>参考：
<ul>
<li><a href="https://tech.meituan.com/2018/09/27/fe-security.html"  target="_blank" rel="noopener" >前端安全系列（一）：如何防止XSS攻击？ - 美团技术团队</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Cross-site_scripting"  target="_blank" rel="noopener" >Cross-site scripting（跨站脚本攻击） - MDN Web 文档术语表：Web 相关术语的定义 | MDN</a></li>
<li><a href="https://urdusecurity.blogspot.com/2014/04/xss-chalenges-bypass.html"  target="_blank" rel="noopener" >Example</a></li>
<li><a href="https://juejin.cn/post/6874743455776505870"  target="_blank" rel="noopener" >浅谈 React 中的 XSS 攻击 - 掘金</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP"  target="_blank" rel="noopener" >内容安全策略（CSP） - HTTP | MDN</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="javascript-prototype-污染攻击">JavaScript Prototype 污染攻击</h2>
<h3 id="prototype基本概念">prototype基本概念</h3>
<ul>
<li><code>prototype</code>是一个类的属性，所有类对象在实例化的时候将会拥有prototype中的属性和方法</li>
<li>一个对象的<code>__proto__</code>属性，指向这个对象所在的类的<code>prototype</code>属性</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html"  target="_blank" rel="noopener" >深入理解 JavaScript Prototype 污染攻击 | 离别歌</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain"  target="_blank" rel="noopener" >继承与原型链 - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="csrf">CSRF</h2>
<h3 id="概念">概念</h3>
<ul>
<li>CSRF（Cross-site request forgery）跨站请求伪造</li>
<li>一次CSRF攻击的过程
<ol>
<li>攻击者诱导受害者进入第三方网站，在第三方网站中，向被攻击网站发送跨站请求。</li>
<li>利用受害者在被攻击网站已经获取的注册凭证，绕过后台的用户验证，达到冒充用户对被攻击的网站执行某项操作的目的。</li>
</ol>
</li>
</ul>
<h3 id="特点">特点:</h3>
<ul>
<li>CSRF（通常）发生在第三方域名。</li>
<li>CSRF攻击者不能获取到Cookie等信息，只是使用</li>
</ul>
<h3 id="防护策略">防护策略</h3>
<ul>
<li><strong>阻止不明外域的访问</strong>
<ul>
<li>同源检测
<ul>
<li>使用<code>Origin Header</code>确定来源域名</li>
<li>使用<code>Referer Header</code>确定来源域名</li>
<li>如果直接在本域发起攻击，同源策略无法达到防护的作用</li>
<li>Samesite Cookie</li>
</ul>
</li>
</ul>
</li>
<li><strong>提交时要求附加本域才能获取的信息</strong>
<ul>
<li>CSRF Token
<ul>
<li>我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token，来把正常的请求和攻击的请求区分开，也可以防范CSRF的攻击</li>
<li>双重Cookie验证
<ul>
<li>难以做到子域名的隔离</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="参考-1">参考：</h3>
<ul>
<li><a href="https://tech.meituan.com/2018/10/11/fe-security-csrf.html"  target="_blank" rel="noopener" >前端安全系列（二）：如何防止CSRF攻击？ - 美团技术团队</a></li>
</ul>
<hr>
<h2 id="点击劫持攻击">点击劫持攻击</h2>
<h3 id="原理">原理</h3>
<ol>
<li>黑客创建一个恶意页面</li>
<li>页面中有一个吸引用户点击的按钮</li>
<li>按钮上方放置一个透明的iframe，其src为黑客希望以用户的名义点击的网站</li>
</ol>
<h3 id="防护策略-1">防护策略</h3>
<ul>
<li>不希望被在iframe中查看: 使用 <code>X-Frame-Options: SAMEORIGIN</code></li>
<li>若要允许在iframe中显示，则可以使用一个<code>&lt;div&gt;</code>对整个页面进行遮盖
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">top</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nx">domain</span> <span class="o">==</span> <span class="nb">document</span><span class="p">.</span><span class="nx">domain</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">protector</span><span class="p">.</span><span class="nx">remove</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>使用<code>samesite</code> cookie</li>
</ul>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://zh.javascript.info/clickjacking"  target="_blank" rel="noopener" >点击劫持攻击</a></li>
</ul>
<hr>
<h2 id="css-injection">CSS injection</h2>
<ul>
<li>属性选择器可以選到「屬性符合某個條件的元素」: <code>input[value^=a]</code></li>
<li>可以利用 CSS 發出 request
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">input</span><span class="p">[</span><span class="nx">name</span><span class="o">=</span><span class="s2">&#34;secret&#34;</span><span class="p">][</span><span class="nx">value</span><span class="o">^=</span><span class="s2">&#34;a&#34;</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">background</span><span class="o">:</span> <span class="nx">url</span><span class="p">(</span><span class="nx">https</span><span class="o">:</span><span class="c1">//myserver.com?q=a)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
<li>偷 hidden input
<ul>
<li>因為 input 的 type 是 hidden，所以這個元素不會顯示在畫面上,也就不会载入背景图片</li>
<li><code>display:block !important;</code>不起作用</li>
<li>方法:
<ul>
<li><code>+</code>: 選到後面的元素</li>
<li><code>has</code>: 選到「底下符合特殊條件的元素」</li>
</ul>
</li>
</ul>
</li>
<li>偷meta
<ul>
<li>可以自己用 CSS 讓這個元素變成可見
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">head</span><span class="p">,</span> <span class="nx">meta</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">display</span><span class="o">:</span> <span class="nx">block</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">meta</span><span class="p">[</span><span class="nx">name</span><span class="o">=</span><span class="s2">&#34;csrf-token&#34;</span><span class="p">][</span><span class="nx">content</span><span class="o">^=</span><span class="s2">&#34;a&#34;</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">background</span><span class="o">:</span> <span class="nx">url</span><span class="p">(</span><span class="nx">https</span><span class="o">:</span><span class="c1">//example.com?q=a);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
</li>
</ul>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://blog.huli.tw/2022/09/29/css-injection-1/"  target="_blank" rel="noopener" >用 CSS 來偷資料 - CSS injection（上） - Huli&rsquo;s blog</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>CSS知识点整理之flex</title>
      <link>https://ds63.eu.org/2024/css_points_of_flex/</link>
      <pubDate>Thu, 10 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/css_points_of_flex/</guid>
      <description>自己学习过程中整理的关于CSS中flex的知识点</description>
      <content:encoded><![CDATA[<h2 id="基本概念">基本概念</h2>
<ul>
<li><strong>Primary axis</strong>: Children will be bunched up at the start of the container.</li>
<li><strong>Cross axis</strong>: Children will stretch out to fill the entire container.</li>
<li><strong>justify</strong> — to position something along the primary axis.</li>
<li><strong>align</strong> — to position something along the cross axis.</li>
<li><strong>content</strong> — a group of “stuff” that can be distributed.</li>
<li><strong>items</strong> — single items that can be positioned individually</li>
</ul>
<hr>
<h2 id="属性">属性</h2>
<h3 id="flex-direction"><code>flex-direction</code></h3>
<ul>
<li>属性决定主轴的方向（即项目的排列方向）。</li>
</ul>
<h3 id="justify-content"><code>justify-content</code></h3>
<ul>
<li>control the distribution of the group along <strong>the primary axis</strong></li>
</ul>
<h3 id="align-self"><code>align-self</code></h3>
<ul>
<li>change the alignment of a specific child along <strong>the cross axis</strong></li>
</ul>
<h3 id="align-items"><code>align-items</code></h3>
<ul>
<li>a convenient shorthand that automatically sets the alignment on all the children at once</li>
<li>flex-start：交叉轴的起点对齐。</li>
<li>flex-end：交叉轴的终点对齐。</li>
<li>center：交叉轴的中点对齐。</li>
<li>baseline: 项目的第一行文字的基线对齐。</li>
<li>stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度</li>
</ul>
<h3 id="flex-grow"><code>flex-grow</code></h3>
<ul>
<li>number,默认为0，不能为负数</li>
<li>规定了 flex-grow 项在 flex 容器中分配剩余空间的相对比例</li>
<li>剩余空间是 flex 容器的大小减去所有 flex 项的大小加起来的大小</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow"  target="_blank" rel="noopener" >flex-grow - CSS: Cascading Style Sheets | MDN</a></li>
</ul>
<h3 id="flex-shrink"><code>flex-shrink</code></h3>
<ul>
<li>number, 默认为1，不难为负数</li>
<li>The flex shrink factor is multiplied by the flex base size; this distributes negative space in proportion to how much the item can shrink. This prevents smaller items from shrinking to 0px before a larger item is noticeably reduced.</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink"  target="_blank" rel="noopener" >flex-shrink - CSS: Cascading Style Sheets | MDN</a></li>
</ul>
<h3 id="flex-basis"><code>flex-basis</code></h3>
<ul>
<li>
<p>指定了 flex 元素在主轴方向上的初始大小(内容盒)</p>
</li>
<li>
<p>flex-basis 优先级比 width(height)高</p>
</li>
<li>
<p>若 <code>flex-basis</code> 为 <code>auto</code>,则 <code>width</code> 设置多少就是多少。</p>
<ul>
<li>举例 <code>flex-basis:auto;width: 300px</code>，则子项就为300px(故意没说宽或者高，因为<code>flex-direction</code>可能会变,下文也一样)。若没设置 <code>width</code>， 则根据内容撑起来。</li>
</ul>
</li>
<li>
<p>若 <code>flex-basis</code> 为 0 ，根据优先级，那子项就是为0px。更不用说同时设置了具体数值，如:<code>flex-basis:200px;width:300px</code>,那子项自然为200px</p>
</li>
<li>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis"  target="_blank" rel="noopener" >flex-basis - CSS: Cascading Style Sheets | MDN</a></p>
</li>
</ul>
<h3 id="flex">flex</h3>
<ul>
<li>
<p>是<code>flex-grow</code>,<code>flex-shrink</code>,<code>flex-basis</code>的简写</p>
</li>
<li>
<p><code>flex-basis</code>，<code>flex-grow</code>，<code>flex-shrink</code> 三者的关系</p>
<ul>
<li><code>flex-basis</code> 是在 <code>flex-grow</code>,<code>flex-shrink</code> 之前看的</li>
<li>意思就是 <code>flex-basis</code> 设定好了再看另外两者，若空间还有富余，就 <code>flex-grow</code>，若空间不够，就<code>flex-shrink</code></li>
</ul>
</li>
<li>
<p>取值</p>
<ol>
<li>initial</li>
</ol>
<ul>
<li>元素会根据自身宽高设置尺寸。它会缩短自身以适应 flex 容器，但不会伸长并吸收 flex 容器中的额外自由空间来适应 flex 容器。相当于将属性设置为&quot;flex: 0 1 auto&quot;。</li>
</ul>
<ol start="2">
<li>auto</li>
</ol>
<ul>
<li>元素会根据自身的宽度与高度来确定尺寸，但是会伸长并吸收 flex 容器中额外的自由空间，也会缩短自身来适应 flex 容器。这相当于将属性设置为 &ldquo;flex: 1 1 auto&rdquo;.</li>
</ul>
<ol start="3">
<li>none</li>
</ol>
<ul>
<li>元素会根据自身宽高来设置尺寸。它是完全非弹性的：既不会缩短，也不会伸长来适应 flex 容器。相当于将属性设置为&quot;flex: 0 0 auto&quot;。</li>
</ul>
<ol start="4">
<li>1</li>
</ol>
<ul>
<li><code>flex-grow:1 , flex-shrink-1, flex-basis-0</code>的缩写</li>
</ul>
</li>
</ul>
<h3 id="gap"><code>gap</code></h3>
<ul>
<li>allows us to create space in-between each Flex child</li>
</ul>
<h3 id="marginauto"><code>margin:auto</code></h3>
<ul>
<li>will gobble up the extra space, and apply it to the element&rsquo;s margin</li>
</ul>
<h3 id="flex-wrap"><code>flex-wrap</code></h3>
<ul>
<li><code>nowrap</code> 默认</li>
<li><code>wrap</code></li>
<li><code>warp-reverse</code></li>
</ul>
<hr>
<h2 id="实现两列等高">实现两列等高</h2>
<h3 id="需求描述">需求描述</h3>
<p>两列布局，以较矮的一列为基准，较高的一列超出部分以滚动条形式</p>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/6924826615729881101?from=search-suggest"  target="_blank" rel="noopener" >CSS中，如何处理短内容和长内容？ - 掘金</a></li>
<li><a href="https://frontend-note.benbinbin.com/article/css/css-layout"  target="_blank" rel="noopener" >CSS 网页布局</a></li>
<li><a href="https://www.imarketinx.de/artikel/equal-height-columns-with-css-grid-layout.html"  target="_blank" rel="noopener" >Equal height columns with CSS Grid Layout - over any number of rows</a></li>
<li><a href="https://jessieji.com/2019/pure-css-masonry"  target="_blank" rel="noopener" >纯 CSS 实现横向排序的瀑布流式布局 - The Trivial</a></li>
<li><a href="https://css-tricks.com/equal-columns-with-flexbox-its-more-complicated-than-you-might-think/"  target="_blank" rel="noopener" >Equal Columns With Flexbox: It’s More Complicated Than You Might Think | CSS-Tricks</a></li>
<li><a href="https://yogwang.site/2022/CSS-flex-container-stretched-by-content/"  target="_blank" rel="noopener" >flex 容器宽度被内容撑开的问题 | blog [ YOG WANG ]</a></li>
</ul>
<hr>
<h2 id="实现换行">实现换行</h2>
<h3 id="需求描述-1">需求描述</h3>
<p>文字内容过长，希望它换行，而不是溢出</p>
<h3 id="解决过程">解决过程</h3>
<ol>
<li>第一版代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;flex flex-col&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;font-semibold text-lg text-blue-500 truncate&#34;</span><span class="p">&gt;{</span><span class="nx">product</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="mi">111111111111111111111111</span><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div>这代码怎么调都还是溢出，后来发现删掉外层的flex就好了,改成</li>
<li>第二版代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;font-semibold text-lg text-blue-500 overflow-hidden text-ellipsis whitespace-nowrap&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">product</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>发现原因在于连续的字母或者数字会被当做一个单词或文本内容，故不会主动换行显示。</li>
<li>另一种解决方案是使用<a href="https://tailwindcss.com/docs/word-break#break-all"  target="_blank" rel="noopener" >break-all</a></li>
</ol>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap"  target="_blank" rel="noopener" >flex-wrap - CSS: Cascading Style Sheets | MDN</a></li>
<li><a href="https://juejin.cn/post/7314507576439472169"  target="_blank" rel="noopener" >Flex 踩坑指南（文字、图片溢出问题） - Minimum Content Size In CSS Flexbox - 掘金</a></li>
<li><a href="https://www.cnblogs.com/xinyuyue/p/14371506.html"  target="_blank" rel="noopener" >使用flex 布局时，英文不自动换行 - 北极星333y - 博客园</a></li>
<li><a href="https://xugaoyi.com/pages/42b66999cc27dc25/"  target="_blank" rel="noopener" >文字在一行或多行时超出显示省略号 | Evan&rsquo;s blog</a></li>
</ul>
<hr>
<h2 id="参考-2">参考</h2>
<ul>
<li><a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/"  target="_blank" rel="noopener" >An Interactive Guide to Flexbox in CSS</a></li>
<li><a href="https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html"  target="_blank" rel="noopener" >Flex 布局教程：语法篇 - 阮一峰的网络日志</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/91470473"  target="_blank" rel="noopener" >flex 笔记（血与泪） - 知乎</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>计算机网络学习笔记</title>
      <link>https://ds63.eu.org/2024/learn_computer_network/</link>
      <pubDate>Thu, 10 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_computer_network/</guid>
      <description>纸上得来终觉浅</description>
      <content:encoded><![CDATA[<h2 id="子网">子网</h2>
<h3 id="子网地址">子网地址</h3>
<ul>
<li>一个ip地址分为子网地址和主机地址两部分</li>
<li>子网地址 = ip地址和掩码进行与运算</li>
</ul>
<h3 id="相同子网的两个判定条件">相同子网的两个判定条件</h3>
<ul>
<li>子网地址相同</li>
<li>直接相连，没有中间路由器</li>
</ul>
<hr>
<h2 id="网关">网关</h2>
<ul>
<li>默认网关： 通往外部网络的第一跳路由器</li>
</ul>
<hr>
<h2 id="模型">模型</h2>
<h3 id="osi七层">OSI七层</h3>
<ul>
<li>分层
<ol>
<li>应用层</li>
<li>表示层</li>
<li>会话层: RPC, SQL,ASP</li>
<li>传输层</li>
<li>网络层</li>
<li>数据链路层</li>
<li>物理层</li>
</ol>
</li>
</ul>
<h3 id="tcpip五层模型">TCP/IP五层模型</h3>
<ul>
<li>分层
<ol>
<li>应用层: SMTP,TELNET,DNS,HTTP</li>
<li>传输层: TCP/UDP、TLS</li>
<li>网络层: ICMP,IP,ARP</li>
<li>数据链路层： mac地址,以太网,ARP,PPP(Point to Point Protocol)</li>
<li>物理层</li>
</ol>
</li>
<li>
  <img loading="lazy" src="https://img2018.cnblogs.com/blog/1311506/201809/1311506-20180919121800625-665107838.png" alt="封装"  /></li>
<li>参考
<ul>
<li><a href="https://www.cnblogs.com/xiugeng/p/8724565.html"  target="_blank" rel="noopener" >TCP/IP五层模型详解 - 休耕 - 博客园</a></li>
<li><a href="https://juejin.cn/post/6857700931708452878"  target="_blank" rel="noopener" >什么是TCP/IP?-四张图解释TCP/IP四层协议模型 - 掘金</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="tcp传输控制协议">TCP(传输控制协议)</h2>
<h3 id="特性">特性</h3>
<ul>
<li>可靠性：只要不得到确认，就重新发送数据报，直到得到对方的确认为止</li>
<li>参考：<a href="https://ciphersaw.me/2018/05/23/python-trick-tcp-server-and-client/"  target="_blank" rel="noopener" >Python 绝技 —— TCP 服务器与客户端 | Secrypt Agency</a></li>
</ul>
<h3 id="三次握手与四次挥手">三次握手与四次挥手</h3>
<ul>
<li>状态机：
  <img loading="lazy" src="https://cdn.jsdelivr.net/gh/SericaLaw/images@master/20211028/-16354356966601.png" alt="TCP状态机"  /></li>
<li>三次握手过程:
<ol>
<li>client发送连接请求报文，seq=x</li>
<li>server接受连接后回复ACK=x+1,seq=y ，并为此处连接分配资源</li>
<li>client接收到ACK报文后，回复ACK=y+1</li>
</ol>
</li>
<li>四次挥手过程:
<ol>
<li>client发送FIN，seq=x</li>
<li>server发送ACK=x+1</li>
<li>server发送FIN</li>
<li>client发送ACK</li>
</ol>
</li>
<li>参考
<ul>
<li><a href="https://www.iserica.com/posts/tcp-state-machine-and-network-programming/"  target="_blank" rel="noopener" >TCP状态机和Linux网络编程 | Serica</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/53374516"  target="_blank" rel="noopener" >“三次握手，四次挥手”你真的懂吗？ - 知乎</a></li>
</ul>
</li>
</ul>
<h3 id="滑动窗口">滑动窗口</h3>
<ul>
<li>接收方需要确认发送方发送的数据包</li>
<li>分为发送方滑动窗口，和接受方滑动窗口。</li>
<li>发送方滑动窗口
<ol>
<li>已发送已确认</li>
<li>已发送未确认</li>
<li>未发送可发送 (2+3的大小未advertised window)</li>
<li>未发送不可发送</li>
</ol>
</li>
<li>接受方滑动窗口
<ol>
<li>已接受已确认</li>
<li>等待接受未确认(advertised window)大小等于接收方发送的tcp头部的window size</li>
<li>不可接受</li>
</ol>
</li>
</ul>
<h3 id="拥塞窗口">拥塞窗口</h3>
<ul>
<li>发送端定义</li>
<li>CWND(congestion window)</li>
<li>发送端最大的发送范围等于Min(拥塞窗口,滑动窗口)</li>
<li>拥塞窗口会动态地随着网络情况的变化进行调整</li>
<li>大体策略为: 如果没有拥塞，则扩大窗口大小，否则就减小。</li>
</ul>
<h3 id="一台机器上最多能创建多少个tcp连接">一台机器上最多能创建多少个TCP连接</h3>
<ul>
<li>
<blockquote>
<p>在内存、文件句柄足够的话可以创建的连接是没有限制的（每个TCP连接至少要消耗一个文件句柄）</p>
</blockquote>
</li>
<li>参考: <a href="https://plantegg.github.io/2020/11/30/%E4%B8%80%E5%8F%B0%E6%9C%BA%E5%99%A8%E4%B8%8A%E6%9C%80%E5%A4%9A%E8%83%BD%E5%88%9B%E5%BB%BA%E5%A4%9A%E5%B0%91%E4%B8%AATCP%E8%BF%9E%E6%8E%A5/"  target="_blank" rel="noopener" >到底一台服务器上最多能创建多少个TCP连接 | plantegg</a></li>
</ul>
<h3 id="tcp和udp的区别">TCP和UDP的区别</h3>
<ol>
<li>
<p><strong>连接与无连接</strong></p>
<ul>
<li><strong>TCP</strong>: 是一种<strong>面向连接</strong>的协议。在发送数据之前，必须先建立一个连接（称为“三次握手”）。在通信过程中，TCP确保双方之间建立的连接保持稳定，直到通信完成。</li>
<li><strong>UDP</strong>: 是一种<strong>无连接</strong>的协议。它不需要在发送数据前建立连接，也不保证发送的数据包会到达目标，因此通信效率较高，但可靠性较低。</li>
</ul>
</li>
<li>
<p><strong>可靠性</strong></p>
<ul>
<li><strong>TCP</strong>: 提供可靠的数据传输。它确保所有的数据包都能够按顺序到达，并且如果有任何数据包丢失，TCP会负责重发。这种机制使得TCP适合需要高可靠性的数据传输，比如文件传输、电子邮件、网页浏览等。</li>
<li><strong>UDP</strong>: 不保证数据包的可靠传输。它不提供重传机制，也不保证数据包按顺序到达，因此如果数据丢失，UDP不会通知发送方。UDP适用于对丢包不敏感的应用场景，比如实时音视频传输、在线游戏等。</li>
</ul>
</li>
<li>
<p><strong>流量控制和拥塞控制</strong></p>
<ul>
<li><strong>TCP</strong>: 提供流量控制和拥塞控制机制。这意味着发送方会根据接收方的处理能力以及网络状况调整发送速率，避免网络过载。TCP使用滑动窗口、慢启动等机制来优化网络传输性能。</li>
<li><strong>UDP</strong>: 不提供流量控制和拥塞控制。UDP会尽最大努力发送数据包，不管接收方是否能够处理，也不关心网络是否拥挤。</li>
</ul>
</li>
<li>
<p><strong>数据传输方式</strong></p>
<ul>
<li><strong>TCP</strong>: 以<strong>字节流</strong>的形式传输数据。TCP把应用层的数据分割成合适大小的段，并确保它们按顺序到达目标应用层。TCP的字节流传输方式使得应用层收到的数据是连续的、完整的。</li>
<li><strong>UDP</strong>: 以<strong>数据报</strong>的形式传输数据。每个UDP包是独立的，接收方收到的可能是独立且无顺序的多个数据报文。由于UDP没有确保顺序到达的机制，因此数据包可能会乱序、丢失或重复。</li>
</ul>
</li>
<li>
<p><strong>开销</strong></p>
<ul>
<li><strong>TCP</strong>: 由于需要建立连接、保证可靠传输以及提供流量控制，TCP的开销较大。TCP头部包含20字节的控制信息（例如序号、确认号、窗口大小等）。</li>
<li><strong>UDP</strong>: 相对来说，UDP的开销较小。它的头部只有8字节，包含了必要的端口信息和校验和字段。由于不需要建立连接或管理重传，UDP的通信效率更高。</li>
</ul>
</li>
<li>
<p><strong>使用场景</strong></p>
<ul>
<li><strong>TCP</strong>: 适用于需要高可靠性、数据完整性和传输顺序的场景。例如：
<ul>
<li>文件传输（如FTP）</li>
<li>网页浏览（HTTP/HTTPS）</li>
<li>电子邮件传输（SMTP）</li>
</ul>
</li>
<li><strong>UDP</strong>: 适用于对传输速度要求高且对数据丢失不敏感的场景。例如：
<ul>
<li>实时音视频传输（如VoIP、视频会议）</li>
<li>在线游戏</li>
<li>DNS查询</li>
<li>流媒体播放</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr>
<h2 id="http--https">HTTP / HTTPS</h2>
<h3 id="http缓存机制">HTTP缓存机制</h3>
<ul>
<li>
<p>分类</p>
<ol>
<li>强缓存</li>
<li>协商缓存</li>
</ol>
</li>
<li>
<p>响应头</p>
<ol>
<li><code>Expires</code></li>
</ol>
<ul>
<li>HTTP/1</li>
</ul>
<ol start="2">
<li><code>Last-Modified</code> / <code>If-Modified-Since</code></li>
</ol>
<ul>
<li>HTTP/1</li>
<li>流程
<ol>
<li>浏览器第一次访问资源，<strong>服务器</strong>会 Response Header 里添加 Last-Modified 的值</li>
<li>浏览器在下一次请求这个资源的时候，检测到有<code>Last-Modified</code>这个 Header。<strong>浏览器</strong>就会在Request中加上 <code>If-Modified-Since</code>，<code>If-Modified-Since</code>的值就是 Last-Modified 的值</li>
<li>服务器收到请求后，如果资源没有修改，服务器返回 304 Not Modified 状态码，并且不包含资源的内容。浏览器此时会使用本地缓存中的资源。</li>
<li>如果资源发生了修改，服务器会返回新的资源内容和更新后的 Last-Modified。</li>
</ol>
</li>
</ul>
<ol start="3">
<li><code>Cache-Control</code></li>
</ol>
<ul>
<li>HTTP/1.1</li>
<li>优先级比 Expires 要高</li>
<li>可选值
<ul>
<li>public</li>
<li>private</li>
<li>no-store: 完全禁用缓存，资源不会存储在缓存中。</li>
<li>no-cache: 告诉浏览器要使用缓存文件，但是每次需要跟服务器确认是最新文件以后才能用，一般使用 Etag 或者 Last-Modified 字段来控制缓存</li>
<li>max-age=60</li>
</ul>
</li>
</ul>
<ol start="4">
<li><code>ETag</code> / <code>If-None-Match</code></li>
</ol>
<ul>
<li>HTTP/1.1</li>
<li>ETag由服务器生成,三种方式：基于内容 / 基于版本 / 自定义生成</li>
<li>浏览器在下一次加载资源向服务器发送请求时，会将上一次返回的<code>Etag</code>值放到request header里的<code>If-None-Match</code>里</li>
<li>ETag 的优先级要高于 Last-Modified</li>
</ul>
</li>
<li>
<p>缓存控制策略的优先级</p>
<ul>
<li>Cache-Control 优先于 Expires</li>
</ul>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://software-factotum.medium.com/effective-http-caching-part-i-62be61280c8c"  target="_blank" rel="noopener" >Effective HTTP Caching — Part I. This series presents an exhaustive dive… | by msingh | Medium</a></li>
</ul>
</li>
</ul>
<h3 id="常见的http状态码">常见的HTTP状态码</h3>
<ul>
<li>分类:
<ul>
<li>1 表示消息</li>
<li>2 表示成功</li>
<li>3 表示重定向</li>
<li>4 表示请求错误</li>
<li>5 表示服务器错误</li>
</ul>
</li>
<li>常见
<ul>
<li>200： OK. 服务器已成功处理了客户端的请求，并且已返回所请求的资源</li>
<li>206： 服务器成功处理了部分请求，一般用来做断点续传，或者是视频文件等大文件的加载</li>
<li>301： 请求的网页已永久移动到新位置，常用于域名更换</li>
<li>302： 临时重定向不会缓存，常用于未登陆的用户访问用户中心重定向到登录页面</li>
<li>304： Not Modified. 自从上次请求后，请求的网页未修改过。服务器返回此响应时，不会返回网页内容。</li>
<li>400:  Bad Request</li>
<li>401： 请求要求身份验证</li>
<li>403:  Forbidden</li>
<li>404： 服务器找不到请求的网页</li>
<li>405： 禁用请求中指定的方法</li>
<li>500： 服务器内部错误</li>
<li>501:  Not Implemented</li>
<li>502:  Bad Gateway. 请求未完成，服务器从上游服务器收到一个无效的响应</li>
<li>503:  Service Unvailable.</li>
<li>504： Gateway Timeout.</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://vue3js.cn/interview/http/status.html"  target="_blank" rel="noopener" >面试官：说说HTTP 常见的状态码有哪些，适用场景？ | web前端面试 - 面试官系列</a></li>
</ul>
</li>
</ul>
<h3 id="常见的http方法">常见的HTTP方法</h3>
<ol>
<li>get
<ul>
<li>用于请求数据，通常用于从服务器获取资源或信息</li>
<li>幂等的，这意味着多次执行相同的 GET 请求，应该产生相同的结果，不会修改服务器上的数据</li>
<li>由于数据通过 URL 传递，浏览器和服务器对 URL 长度有一定限制，通常在 2KB 到 8KB 范围内</li>
</ul>
</li>
<li>put</li>
<li>delete</li>
<li>post
<ul>
<li>用于向服务器发送数据，一般用于提交表单、上传文件或触发服务器上的某种动作</li>
<li>不是幂等的，每次发送 POST 请求都可能修改服务器上的数据或引发不同的操作</li>
</ul>
</li>
<li>head</li>
</ol>
<h3 id="常见的http-请求头">常见的HTTP 请求头</h3>
<ol>
<li>Host</li>
<li>User-Agent</li>
<li>Accept</li>
<li>Accept-Encoding: zip, deflate, br</li>
<li>Accept-Language</li>
<li>Authorization</li>
<li>Content-Type</li>
<li>Content-Length : 指示请求体的字节长度</li>
<li>Referer: 告诉服务器从哪个页面发起的请求</li>
<li>Connection: <code>Connection: keep-alive</code></li>
<li>Cache-Control</li>
<li>Origin: 发起请求的来源</li>
<li>Range: 用于请求资源的部分内容，常见于下载请求中，指定从哪个字节位置开始获取资源</li>
</ol>
<h3 id="content-type">Content-Type</h3>
<ul>
<li>用于指示资源的原始媒体类型</li>
<li>常见格式
<ol>
<li>text/html</li>
<li>text/plain</li>
<li>image/png</li>
<li>application/json</li>
<li>application/octet-stream</li>
<li>application/x-www-form-urlencoded</li>
<li>multipart/form-data</li>
</ol>
</li>
<li>参考:
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Type"  target="_blank" rel="noopener" >Content-Type - HTTP | MDN</a></li>
<li><a href="https://www.runoob.com/http/http-content-type.html"  target="_blank" rel="noopener" >HTTP content-type | 菜鸟教程</a></li>
</ul>
</li>
</ul>
<hr>
<h3 id="http11http2-和-http3-的介绍及它们的主要区别">HTTP/1.1、HTTP/2 和 HTTP/3 的介绍及它们的主要区别</h3>
<ul>
<li>HTTP/1.1
<ul>
<li>特点</li>
</ul>
<ol>
<li>
<p><strong>持久连接</strong>：在 HTTP/1.0 中，每次请求都需要新建一个 TCP 连接，而 HTTP/1.1 引入了持久连接（Keep-Alive），允许多个请求复用同一个连接，从而减少了建立连接的开销。</p>
</li>
<li>
<p><strong>管线化（Pipelining）</strong>：HTTP/1.1 支持请求管线化，即可以在发送一个请求后，不等响应完成就发送下一个请求，从而减少等待时间。不过由于实现复杂，这个特性并没有得到广泛应用。</p>
</li>
<li>
<p><strong>缓存控制</strong>：HTTP/1.1 引入了更灵活的缓存机制，通过 <code>Cache-Control</code> 和 <code>ETag</code> 头部来优化缓存和验证机制，减少了重复的数据传输。</p>
</li>
<li>
<p><strong>Host 头部</strong>：HTTP/1.1 要求所有请求都包含 <code>Host</code> 头部，使得一个服务器可以托管多个域名（虚拟主机）。</p>
</li>
</ol>
<ul>
<li>局限性：</li>
</ul>
<ol>
<li><strong>队头阻塞（Head-of-Line Blocking）</strong>：由于 HTTP/1.1 基于单一的 TCP 连接，当一个请求阻塞时，后续的请求也会被阻塞。</li>
<li><strong>并发连接的限制</strong>：浏览器为了加速页面加载，往往需要建立多个 TCP 连接来并行加载资源，但这会加重服务器和网络的负担。Chrome浏览器通常允许<strong>每个域名同时发出</strong>的最大连接数为<strong>6个</strong>。</li>
</ol>
</li>
</ul>
<ol start="2">
<li>HTTP/2</li>
</ol>
<ul>
<li>特点</li>
</ul>
<ol>
<li>
<p><strong>二进制协议</strong>：HTTP/2 使用二进制格式而不是 HTTP/1.1 的文本格式，这样数据可以更高效地解析和处理。</p>
</li>
<li>
<p><strong>多路复用（Multiplexing）</strong>：HTTP/2 允许在同一个 TCP 连接上同时发送多个请求和响应，避免了队头阻塞。每个请求被分为独立的帧，并通过流 ID 来区分，这些帧可以交错传输。</p>
</li>
<li>
<p><strong>头部压缩</strong>：HTTP/2 使用 HPACK 算法对头部信息进行压缩，减少了冗余数据的传输，尤其是当多个请求使用相同的头部时，效果尤为显著。</p>
</li>
<li>
<p><strong>服务器推送</strong>：服务器可以主动向客户端推送可能会用到的资源（例如 CSS 或 JS 文件），即使客户端还没有请求这些资源。这样可以减少等待时间，加快页面加载速度。</p>
</li>
</ol>
<ul>
<li>局限性</li>
</ul>
<ol>
<li>
<p>虽然多路复用减少了队头阻塞，但 HTTP/2 仍然基于 TCP，TCP 连接的队头阻塞问题没有完全消除。</p>
</li>
<li>
<p>在网络丢包的情况下，TCP 的重传机制会导致整个连接中的所有数据都受到影响。</p>
</li>
<li>
<p>HTTP/3</p>
<ul>
<li>特点
<ol>
<li>
<p><strong>基于 QUIC 的传输协议</strong>：QUIC 是一种基于 UDP 的传输协议，它通过在用户态实现拥塞控制、重传等功能，减少了握手和延迟。QUIC 的最大特点是可以避免 TCP 的队头阻塞。</p>
</li>
<li>
<p><strong>更快的握手</strong>：QUIC 通过 0-RTT 和 1-RTT 的握手机制，实现了比 TCP 快得多的连接建立时间。传统的 TCP 需要三次握手，而 QUIC 可以在一次往返中建立连接，减少了延迟。</p>
</li>
<li>
<p><strong>独立的流</strong>：QUIC 协议允许在一个连接中传输多个独立的流，即使某个流中有数据丢失，其他流不会受到影响，从而彻底解决了 TCP 的队头阻塞问题。</p>
</li>
<li>
<p><strong>内置加密</strong>：与 HTTP/2 一样，HTTP/3 默认要求加密。QUIC 本身就内置了 TLS 加密功能，简化了加密过程，提高了安全性。</p>
</li>
</ol>
</li>
</ul>
</li>
</ol>
<ul>
<li>
<p>使用 UDP 而非 TCP的原因</p>
<ol>
<li>UDP 提供了更高的灵活性和效率</li>
<li>QUIC 协议通过在应用层实现流控、拥塞控制、加密等功能，避免了 TCP 的许多限制，如队头阻塞、慢速连接建立和复杂的中间设备干扰</li>
<li>QUIC 通过 UDP 实现了更快的连接建立、灵活的连接管理和更强的传输性能</li>
</ol>
</li>
<li>
<p>局限性：</p>
<ol>
<li><strong>部署复杂性</strong>：由于 HTTP/3 基于 QUIC，而 QUIC 使用 UDP 传输，因此需要服务器和网络设备对 UDP 有良好的支持。这对某些旧的网络基础设施可能带来挑战。</li>
</ol>
</li>
<li>
<p>HTTP/1.1、HTTP/2 和 HTTP/3 的对比</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>特性</th>
<th>HTTP/1.1</th>
<th>HTTP/2</th>
<th>HTTP/3</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>协议类型</strong></td>
<td>文本协议</td>
<td>二进制协议</td>
<td>基于 QUIC（UDP）</td>
</tr>
<tr>
<td><strong>连接复用</strong></td>
<td>不支持</td>
<td>支持多路复用</td>
<td>支持多路复用</td>
</tr>
<tr>
<td><strong>队头阻塞</strong></td>
<td>存在（TCP 层）</td>
<td>存在（TCP 层）</td>
<td>彻底解决（基于 QUIC）</td>
</tr>
<tr>
<td><strong>头部压缩</strong></td>
<td>不支持</td>
<td>支持（HPACK）</td>
<td>支持（QPACK）</td>
</tr>
<tr>
<td><strong>服务器推送</strong></td>
<td>不支持</td>
<td>支持</td>
<td>支持</td>
</tr>
<tr>
<td><strong>加密</strong></td>
<td>可选</td>
<td>默认加密（基于 TLS）</td>
<td>默认加密（基于 QUIC 内置 TLS）</td>
</tr>
<tr>
<td><strong>握手延迟</strong></td>
<td>需要三次握手</td>
<td>需要三次握手</td>
<td>0-RTT 和 1-RTT 握手，延迟更低</td>
</tr>
</tbody>
</table>
<h3 id="http-和-https-区别">HTTP 和 HTTPS 区别</h3>
<ul>
<li>
<p>HTTPS 是在 HTTP 协议基础上实施 TLS 加密，所有网站以及其他部分 web 服务都使用该协议。因此，任何使用 HTTPS 的网站都使用 TLS 加密。</p>
</li>
<li>
<p>HTTPS目的</p>
<ol>
<li>数据加密</li>
<li>数据一致性</li>
<li>身份认证</li>
</ol>
</li>
<li>
<p>参考：</p>
<ul>
<li><a href="https://www.cloudflare.com/zh-cn/learning/ssl/why-is-http-not-secure/"  target="_blank" rel="noopener" >为什么 HTTP 不安全？| HTTP 与 HTTPS | Cloudflare</a></li>
<li><a href="https://czkm.github.io/2021/09/01/%E6%88%91HTTPS%E5%8F%AA%E4%B8%BA%E4%B8%89%E4%BB%B6%E4%BA%8B/"  target="_blank" rel="noopener" >我HTTPS只为三件事！ - 橙汁坤的博客 | czkm Blog</a></li>
<li><a href="https://blog.laisky.com/p/https-in-action/?lang=zh#gsc.tab=0"  target="_blank" rel="noopener" >HTTPS 隐私安全的一些实践</a></li>
</ul>
</li>
</ul>
<h3 id="https原理">HTTPS原理</h3>
<ul>
<li>
<p>依靠**TLS（传输层安全性协议）**来提供加密、认证和数据完整性。</p>
</li>
<li>
<p>加密通信</p>
<ul>
<li>HTTPS 使用对称加密和非对称加密结合的方式来加密通信：</li>
<li>非对称加密：在连接开始时，客户端和服务器通过非对称加密（公钥和私钥）进行握手。服务器提供一个公钥，客户端使用这个公钥加密信息，然后服务器用自己的私钥解密。由于公钥是公开的，而私钥是保密的，这确保了只有服务器能够解密加密的信息。</li>
<li>对称加密：握手过程中，双方会生成一个共享的会话密钥（对称密钥）。这个对称密钥用于接下来的通信，因为对称加密在处理大量数据时比非对称加密快得多。</li>
</ul>
</li>
<li>
<p>身份认证</p>
<ul>
<li>HTTPS 使用<strong>数字证书</strong>和**证书颁发机构（CA）**来验证服务器的身份，确保客户端正在与合法的服务器通信，而不是中间人攻击者。</li>
<li>数字证书：服务器必须提供一个受信任的数字证书，通常由一个可信的CA（如Let’s Encrypt、DigiCert等）签发。数字证书中包含了服务器的公钥和证书持有者的信息。</li>
<li>证书验证：客户端会检查这个证书是否由受信任的CA签发，是否有效，以及是否与服务器的域名匹配。如果证书有问题，浏览器会警告用户。</li>
</ul>
</li>
<li>
<p>数据完整性</p>
<ul>
<li>HTTPS 通过使用哈希函数（如 SHA256）来确保数据传输的完整性。具体来说，每个数据包都会附带一个哈希值，接收方可以通过这个哈希值验证数据是否在传输过程中被篡改。如果数据被篡改，哈希值将不匹配，通信会被终止。</li>
</ul>
</li>
<li>
<p>握手过程（TLS握手）</p>
<ol>
<li><strong>客户端Hello</strong>：客户端发送一个请求，包含可支持的加密算法、TLS版本等信息。</li>
<li><strong>服务器Hello</strong>：服务器响应，并发送数字证书和选择的加密算法。</li>
<li><strong>密钥交换</strong>：客户端使用服务器的公钥加密生成的会话密钥，并将其发送给服务器。服务器用私钥解密并获得该密钥。</li>
<li><strong>握手完成</strong>：双方开始使用会话密钥进行对称加密的通信。</li>
</ol>
</li>
</ul>
<h3 id="https缺陷sni">HTTPS缺陷(SNI)</h3>
<ul>
<li>ClientHello 中的 SNI(Server Name Indication)</li>
<li>GFW 基于 SNI 来掐断你的 HTTPS 握手</li>
<li>境内公有云基于 SNI 来阻断未备案的域名</li>
</ul>
<h3 id="https-攻击方式">HTTPS 攻击方式</h3>
<ol>
<li><strong>中间人攻击（Man-in-the-Middle Attack, MITM）</strong></li>
</ol>
<ul>
<li>攻击方法
<ul>
<li>恶意Wi-Fi热点：攻击者设置一个假冒的公共Wi-Fi热点，诱使用户连接，通过DNS劫持或使用不安全的HTTP版本，拦截流量。</li>
<li>恶意代理：在客户端与服务器之间，攻击者可能通过劫持代理服务器来解密和重新加密数据。</li>
</ul>
</li>
<li>防范措施：确保证书和域名验证正确，使用HSTS（HTTP Strict Transport Security）强制HTTPS连接，避免降级到不安全的HTTP。</li>
</ul>
<ol start="2">
<li><strong>SSL剥离攻击（SSL Stripping）</strong></li>
</ol>
<ul>
<li>SSL剥离攻击是中间人攻击的一种特殊形式，攻击者强迫客户端与服务器使用HTTP而不是HTTPS。攻击者拦截客户端请求，并将其重写为HTTP（即明文），然后在服务器和攻击者之间使用HTTPS。</li>
<li>攻击方法：用户尝试通过HTTP连接到网站，服务器重定向到HTTPS，但攻击者在重定向之前拦截并降级为HTTP。</li>
<li>防范措施：启用HSTS策略，它能确保浏览器在连接时始终使用HTTPS，并阻止降级为HTTP的攻击。</li>
</ul>
<ol start="3">
<li><strong>证书伪造或冒充攻击</strong></li>
</ol>
<ul>
<li>证书伪造：攻击者可能通过不安全的证书颁发机构（CA）或通过社会工程手段获得伪造的证书，假冒合法网站。</li>
<li>中间证书颁发机构滥用：如果中间证书颁发机构被攻击者控制，他们可能使用合法的中间证书签发虚假的证书。</li>
<li>防范措施：启用证书透明度（Certificate Transparency），它可以帮助检测和阻止伪造证书。现代浏览器会警告用户关于无效或伪造的证书。</li>
</ul>
<ol start="4">
<li><strong>降级攻击（Downgrade Attack）</strong></li>
</ol>
<ul>
<li>攻击方法: 攻击者强迫客户端和服务器使用较弱的加密算法或不安全的TLS版本（如SSL 3.0或TLS 1.0），以便更容易进行破解或解密。</li>
<li>防范措施：服务器应该禁用过时的SSL/TLS版本和弱加密算法（如RC4），并仅支持最新的TLS协议版本。</li>
</ul>
<ol start="5">
<li><strong>TLS重协商攻击</strong></li>
</ol>
<ul>
<li>攻击方法: TLS的重协商机制可能被攻击者利用，插入自己的数据到加密会话中，欺骗服务器认为这些数据来自合法的客户端。</li>
<li>防范措施：确保服务器和客户端都使用安全的TLS重协商机制，并打补丁修复已知漏洞。</li>
</ul>
<ol start="6">
<li><strong>恶意软件和浏览器劫持</strong></li>
</ol>
<ul>
<li>攻击方法：即使HTTPS保护了传输中的数据，攻击者仍然可能通过用户设备上的恶意软件或浏览器劫持绕过HTTPS。例如，某些恶意软件可以劫持浏览器流量，将用户重定向到虚假网站，即使启用了HTTPS。</li>
<li>防范措施：保持操作系统和软件的安全更新，使用防病毒软件，并提高用户安全意识。</li>
</ul>
<hr>
<h2 id="dns">DNS</h2>
<h3 id="dns-查询顺序">DNS 查询顺序</h3>
<ol>
<li>浏览器 DNS 缓存</li>
<li>浏览器调用 getaddrinfo() 查询数据，其中 getaddrinfo() 会根据如下顺序查询
<ol>
<li>先看 /etc/hosts 文件</li>
<li>通过主机名服务/mDNS 查询</li>
<li>通过 systemd-resolved 查询</li>
<li>最后通过 DHCP 下发的 DNS 查询</li>
<li>一级级往上查询直到根 DNS 服务器</li>
</ol>
</li>
</ol>
<h3 id="使用协议">使用协议</h3>
<ul>
<li>DNS在进行区域传输的时候使用TCP协议</li>
<li>其它时候则使用UDP协议</li>
<li>默认端口号: 53</li>
</ul>
<h3 id="dns安全">DNS安全</h3>
<ul>
<li><a href="https://blog.laisky.com/p/https-in-action/?lang=zh#gsc.tab=0"  target="_blank" rel="noopener" >HTTPS 隐私安全的一些实践</a></li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://scoolor.github.io/2018/11/10/dns-udp-tcp/"  target="_blank" rel="noopener" >DNS为什么既使用TCP又使用UDP？ | 为什么这么涛的个人博客</a></li>
<li><a href="https://nova.moe/rethink-type-url-dns/"  target="_blank" rel="noopener" >重新思考浏览器输入了 URL 并按下回车之后到底发生了什么——本地 DNS 部分 | Nova Kwok&rsquo;s Awesome Blog</a></li>
</ul>
<hr>
<h2 id="ssl--tls">SSL / TLS</h2>
<h3 id="ssl-secure-socket-layer">SSL (Secure Socket Layer)</h3>
<ul>
<li>安全套接字层</li>
</ul>
<h3 id="tls-transport-layer-security">TLS (Transport Layer Security)</h3>
<ul>
<li>SSL的升级版</li>
<li>作用
<ol>
<li>加密</li>
<li>身份验证</li>
<li>完整性</li>
</ol>
</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://www.cloudflare.com/zh-cn/learning/ssl/transport-layer-security-tls/"  target="_blank" rel="noopener" >什么是传输层安全性（TLS）？ | Cloudflare</a></li>
<li><a href="https://liuyib.github.io/2020/04/18/deep-study-ssl-tls/"  target="_blank" rel="noopener" >深入探究 SSL/TLS 协议 | Liuyib&rsquo;s Blog</a></li>
<li><a href="https://hijiangtao.github.io/2022/11/16/Dig-Out-All-Secrets-Behind-TLS-Certificate-One/"  target="_blank" rel="noopener" >网络安全科普：奇妙的 SSL/TLS 证书（基础篇） - Joe’s Blog</a></li>
<li><a href="https://hijiangtao.github.io/2022/10/09/Secure-Your-Browsing-Experience-with-More-Encrypted-Tools/"  target="_blank" rel="noopener" >TLS/ESNI/ECH/DoT/DoH/JA3 - 谈谈 HTTPS 网络下浏览体验安全性的最后缝隙 - Joe’s Blog</a></li>
<li><a href="https://hijiangtao.github.io/2022/11/16/Dig-Out-All-Secrets-Behind-TLS-Certificate-One/"  target="_blank" rel="noopener" >网络安全科普：奇妙的 SSL/TLS 证书（基础篇） - Joe’s Blog</a></li>
<li><a href="https://blog.laisky.com/p/https-in-action/?lang=zh#gsc.tab=0"  target="_blank" rel="noopener" >HTTPS 隐私安全的一些实践</a></li>
</ul>
<hr>
<h2 id="ipv4与ipv6">ipv4与ipv6</h2>
<ul>
<li>ipv6的环回地址: 0:0:0:0:0:0:0:1，通常也简写为::1</li>
<li>参考:
<ul>
<li><a href="https://wiki.zohead.com/%E6%8A%80%E6%9C%AF/%E7%BD%91%E7%BB%9C/IPv6%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md"  target="_blank" rel="noopener" >IPv6 基础知识 - Uranus&rsquo; Wiki</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="cdn">CDN</h2>
<ul>
<li>CDN（Content Delivery Network，内容分发网络）</li>
<li>CDN通过将内容缓存到全球多个节点（也称为边缘服务器）上，使得用户能够从最近的服务器获取数据，从而加快访问速度并减少延迟。</li>
<li>Amazon CloudFront 是 Amazon Web Services（AWS）提供的全球内容分发网络（CDN）服务</li>
</ul>
<hr>
<h2 id="待分类">待分类</h2>
<h3 id="网络包">网络包</h3>
<ul>
<li>参考
<ul>
<li><a href="https://plantegg.github.io/2019/05/15/%E5%B0%B1%E6%98%AF%E8%A6%81%E4%BD%A0%E6%87%82%E7%BD%91%E7%BB%9C--%E4%B8%80%E4%B8%AA%E7%BD%91%E7%BB%9C%E5%8C%85%E7%9A%84%E6%97%85%E7%A8%8B/"  target="_blank" rel="noopener" >就是要你懂网络&ndash;一个网络包的旅程 | plantegg</a></li>
</ul>
</li>
</ul>
<h3 id="轮询长轮询long-pollingwebsocket">轮询、长轮询（Long polling）、WebSocket</h3>
<ul>
<li>轮询：定期向服务器发出请求</li>
<li>长轮询过程
<ol>
<li>请求发送到服务器。</li>
<li>服务器在有消息之前不会关闭连接。</li>
<li>当消息出现时 —— 服务器将对其请求作出响应。</li>
<li>浏览器立即发出一个新的请求。</li>
</ol>
</li>
<li>WebSocket提供了一种在浏览器和服务器之间建立持久连接来交换数据的方法。数据可以作为“数据包”在两个方向上传递，而无需中断连接也无需额外的 HTTP 请求。</li>
<li>参考
<ul>
<li><a href="https://zh.javascript.info/long-polling"  target="_blank" rel="noopener" >长轮询（Long polling）</a></li>
<li><a href="https://zh.javascript.info/websocket"  target="_blank" rel="noopener" >WebSocket</a></li>
</ul>
</li>
</ul>
<h3 id="arp">ARP</h3>
<p>ARP（Address Resolution Protocol，地址解析协议）是用来将IP地址解析为MAC地址的协议。 主机或三层网络设备上会维护一张ARP表，用于存储IP地址和MAC地址的映射关系，一般ARP表项包括动态ARP表项和静态ARP表项。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之this</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_this/</link>
      <pubDate>Thu, 10 Oct 2024 00:56:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_this/</guid>
      <description>自己学习过程中整理的关于JavaScript中this的知识点</description>
      <content:encoded><![CDATA[<h2 id="this的判断">this的判断</h2>
<h3 id="关键一">关键一</h3>
<ul>
<li><code>this</code>永远指向，（最内层）调用这个包含&quot;this&quot;关键字的函数的对象</li>
<li>也就是说: 无论在哪里找到方法：在一个对象还是在原型中。在一个方法调用中，this 始终是点符号<code>.</code>前面的对象</li>
<li>示例一
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">my_element</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">className</span><span class="p">);</span> <span class="c1">// 输出 my_element 的 className
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">currentTarget</span> <span class="o">===</span> <span class="k">this</span><span class="p">);</span> <span class="c1">// 输出 `true`
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">});</span>
</span></span></code></pre></div></li>
<li>示例二
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">user</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;John&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="nx">surname</span><span class="o">:</span> <span class="s2">&#34;Smith&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">set</span> <span class="nx">fullName</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">surname</span><span class="p">]</span> <span class="o">=</span> <span class="nx">value</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">get</span> <span class="nx">fullName</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sb">`</span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb"> </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">surname</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">admin</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">__proto__</span><span class="o">:</span> <span class="nx">user</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="nx">isAdmin</span><span class="o">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span><span class="nx">admin</span><span class="p">.</span><span class="nx">fullName</span><span class="p">);</span> <span class="c1">// John Smith (*)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// setter triggers!
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">admin</span><span class="p">.</span><span class="nx">fullName</span> <span class="o">=</span> <span class="s2">&#34;Alice Cooper&#34;</span><span class="p">;</span> <span class="c1">// (**)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span><span class="nx">admin</span><span class="p">.</span><span class="nx">fullName</span><span class="p">);</span> <span class="c1">// Alice Cooper，admin 的内容被修改了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">alert</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">fullName</span><span class="p">);</span>  <span class="c1">// John Smith，user 的内容被保护了
</span></span></span></code></pre></div></li>
</ul>
<h3 id="关键二">关键二</h3>
<ul>
<li>如果函数在最外层直接运行，默认绑定的对象是 window</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">test</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">a</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">test</span><span class="p">();</span> <span class="c1">//undefined
</span></span></span></code></pre></div></li>
</ul>
<h3 id="补充">补充</h3>
<ul>
<li>对象不构成单独的作用域，而函数有。</li>
<li>In arrow functions, <code>this</code> retains the value of the enclosing lexical context&rsquo;s <code>this</code>.</li>
<li>箭头函数的this，一旦确定后是不可直接更改的，但可间接更改，示例：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">test</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">);</span> <span class="c1">// 这里箭头函数的this指向test()的this
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">aa</span><span class="o">:</span> <span class="mi">123</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">rr</span> <span class="o">=</span> <span class="nx">test</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span> <span class="c1">// test()的this被修改了，导致箭头函数的也跟着修改了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">setTimeout</span><span class="p">(</span><span class="nx">rr</span><span class="p">,</span><span class="mi">1000</span><span class="p">);</span> <span class="c1">// obj ，而不是window; 因为箭头函数rr的this已经确定了，后面不能更改
</span></span></span></code></pre></div></li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/25349790"  target="_blank" rel="noopener" >Javascript ：this关键字 详解 - 知乎</a></li>
<li><a href="https://segmentfault.com/a/1190000039881063"  target="_blank" rel="noopener" >javascript - 关于箭头函数里的this - 个人文章 - SegmentFault 思否</a></li>
<li><a href="https://muyiy.cn/blog/3/3.2.html"  target="_blank" rel="noopener" >JavaScript深入之重新认识箭头函数的this | 木易杨前端进阶</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this"  target="_blank" rel="noopener" >this - JavaScript | MDN</a></li>
<li><a href="https://zh.javascript.info/reference-type"  target="_blank" rel="noopener" >Reference Type</a></li>
</ul>
<hr>
<h2 id="callbindapply">call、bind、apply</h2>
<h3 id="apply">apply</h3>
<ul>
<li>接受两个参数，第一个参数是this的指向，第二个参数是函数接受的参数，以<strong>数组</strong>的形式传入,<strong>必须一次性传入所有参数</strong></li>
<li>当第一个参数为null、undefined的时候，默认指向window(在浏览器中)</li>
<li>改变this指向后原函数会<strong>立即执行</strong>，且此方法只是临时改变thi指向一次。</li>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">arr</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">arr</span><span class="p">));</span> <span class="c1">//10
</span></span></span></code></pre></div></li>
</ul>
<h3 id="call">call</h3>
<ul>
<li>接受两个参数，第一个参数是this的指向，第二个参数是函数接受的参数，以<strong>参数列表</strong>的形式传入,<strong>必须一次性传入所有参数</strong></li>
<li>当第一个参数为null、undefined的时候，默认指向window(在浏览器中)</li>
<li>改变this指向后原函数会<strong>立即执行</strong>，且此方法只是临时改变this指向一次。</li>
<li>示例：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">arr</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span><span class="nx">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">4</span><span class="p">]));</span> <span class="c1">//10
</span></span></span></code></pre></div></li>
</ul>
<h3 id="bind">bind</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"  target="_blank" rel="noopener" >Function.prototype.bind() - JavaScript | MDN</a></li>
<li>接受两个参数，第一个参数是this的指向，如果函数不在严格模式下，null 和 undefined 会被替换为全局对象;</li>
<li>第二个参数是函数接受的参数，以<strong>参数列表</strong>的形式传入,<strong>可以分多次传入</strong></li>
<li>改变this指向后<strong>不会立即执行</strong>，而是返回一个<strong>永久改变this指向的函数</strong></li>
<li>可以<strong>二次传参</strong>，但新绑定的 thisArg 值会被忽略</li>
<li>示例：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">arr</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">12</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">max</span><span class="o">=</span><span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span><span class="nx">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span><span class="nx">arr</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">max</span><span class="p">(</span><span class="nx">arr</span><span class="p">[</span><span class="mi">4</span><span class="p">]));</span> <span class="c1">//12，分两次传参
</span></span></span></code></pre></div></li>
<li>简易实现
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">bind</span><span class="o">=</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">_this</span><span class="o">=</span><span class="k">this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">context</span><span class="o">=</span><span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">arg</span><span class="o">=</span><span class="p">[].</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span> <span class="c1">//将函数调用时传入的参数转换为数组，并且去掉了第一个参数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">arg</span><span class="o">=</span><span class="p">[].</span><span class="nx">concat</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">arg</span><span class="p">,</span><span class="nx">arguments</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">_this</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span><span class="nx">arg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="作用">作用</h3>
<ul>
<li>防止原型链污染</li>
<li>示例:
<ul>
<li>JavaScript does not protect the property name hasOwnProperty; an object that has a property with this name may return incorrect results</li>
<li>The recommended way to overcome this problem is to instead use Object.hasOwn() (in browsers that support it). Other alternatives include using an external hasOwnProperty:</li>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">foo</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">bar</span><span class="o">:</span> <span class="s2">&#34;Here be dragons&#34;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Use Object.hasOwn() method - recommended
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">Object</span><span class="p">.</span><span class="nx">hasOwn</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="s2">&#34;bar&#34;</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// Use the hasOwnProperty property from the Object prototype
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="s2">&#34;bar&#34;</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// Use another Object&#39;s hasOwnProperty
</span></span></span><span class="line"><span class="cl"><span class="c1">// and call it with &#39;this&#39; set to foo
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">({}).</span><span class="nx">hasOwnProperty</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="s2">&#34;bar&#34;</span><span class="p">);</span> <span class="c1">// true
</span></span></span></code></pre></div></li>
</ul>
</li>
</ul>
<hr>
<h2 id="代码输出题">代码输出题</h2>
<h3 id="题目一">题目一</h3>
<ul>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;eu&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">sayHi1</span><span class="o">:</span> <span class="p">()=&gt;{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">sayHi2</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">(()=&gt;{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">})();</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">obj</span><span class="p">.</span><span class="nx">sayHi1</span><span class="p">();</span> <span class="c1">// &#39;&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">obj</span><span class="p">.</span><span class="nx">sayHi2</span><span class="p">();</span> <span class="c1">// &#39;eu&#39;
</span></span></span></code></pre></div></li>
<li>解释：
<ol>
<li><code>obj.sayHi1()</code> 的执行
<ul>
<li>
<p>考察知识点一:  <strong>箭头函数中的 <code>this</code></strong>：
箭头函数不会创建自己的 <code>this</code> 绑定，它会继承上下文中的 <code>this</code>。也就是说，<code>this</code> 的值取决于箭头函数定义时所在的上下文，而不是调用时的上下文。</p>
</li>
<li>
<p>本题中的应用:
在 <code>sayHi1</code> 方法中，箭头函数被定义在 <code>obj</code> 对象的上下文中，但是由于箭头函数继承的是定义时的 <code>this</code>，而不是调用时的 <code>this</code>，<code>this</code> 将会是<strong>全局上下文</strong>（在严格模式下为 <code>undefined</code>，在非严格模式下为 <code>window</code>）。</p>
<p>因为 <code>this</code> 不是指向 <code>obj</code>，而是指向全局对象，<code>this.name</code> 在全局对象中是未定义的，可能返回 <code>undefined</code> 或空字符串 <code>''</code>，具体取决于运行环境。</p>
</li>
</ul>
</li>
<li><code>obj.sayHi2()</code> 的执行
<ul>
<li>考察知识点一: 简写函数定义
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">sayHi2</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;hi&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 相当于
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">sayHi2</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;hi&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>考察知识点二: 普通方法中的 <code>this</code>会根据调用的上下文来决定</li>
<li>本题中的应用
<code>sayHi2</code> 是一个普通方法，因此 <code>this</code> 会根据调用的上下文来决定。在这个例子中，<code>obj.sayHi2()</code> 是调用 <code>sayHi2</code>，所以 <code>this</code> 指向 <code>obj</code>。</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/82340026"  target="_blank" rel="noopener" >彻底弄懂bind，apply，call三者的区别 - 知乎</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty"  target="_blank" rel="noopener" >Object.prototype.hasOwnProperty() - JavaScript | MDN</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>浏览器存储</title>
      <link>https://ds63.eu.org/2024/browser_storage/</link>
      <pubDate>Wed, 09 Oct 2024 23:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/browser_storage/</guid>
      <description>自己学习过程中整理的关于浏览器存储的知识点</description>
      <content:encoded><![CDATA[<h2 id="cookie">Cookie</h2>
<h3 id="概述">概述</h3>
<h3 id="2024年10月13日">2024年10月13日</h3>
<ul>
<li>Cookie是最古老和最基本的客户端存储机制之一。</li>
<li>Cookie是由服务器发送到用户浏览器的小型文本文件，存储在用户的计算机上。</li>
<li>Cookie是基于域的，不区分协议</li>
<li>每次发送HTTP请求时，浏览器都会将相应的Cookie发送回服务器。</li>
<li>Cookie通常用于存储用户偏好设置、跟踪用户行为等信息。</li>
</ul>
<h3 id="限制">限制</h3>
<ul>
<li>格式: <code>name=value</code>, name和value都应该使用内建的 encodeURIComponent 函数对其进行转义</li>
<li>大小: encodeURIComponent 编码后的 name=value 对，大小不能超过 4KB</li>
<li>数量: 每个域的 cookie 总数在20到50左右，具体限制取决于浏览器。</li>
<li>可以通过设置Cookie的过期时间来控制Cookie的生命周期。</li>
</ul>
<h3 id="安全性">安全性</h3>
<ul>
<li><code>path=/mypath</code>:
<ul>
<li>该路径下的页面可以访问该 cookie</li>
<li>默认为当前路径</li>
</ul>
</li>
<li><code>domain=site.com</code>:
<ul>
<li>控制可访问 cookie 的域</li>
<li>默认(也就是不设置的话),不会共享给子域</li>
<li>只有明确地将 domain 选项设置为根域，子域才能访问
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 在 site.com
</span></span></span><span class="line"><span class="cl"><span class="c1">// 使 cookie 可以被在任何子域 *.site.com 访问：
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="s2">&#34;user=John; domain=site.com&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 之后
</span></span></span><span class="line"><span class="cl"><span class="c1">// 在 forum.site.com
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">alert</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">);</span> <span class="c1">// 有 cookie user=John
</span></span></span></code></pre></div></li>
</ul>
</li>
<li><code>expires</code>, <code>max-age</code>
<ul>
<li>如果没有设置这两个参数都没有设置，那么在关闭浏览器之后会消失，也就是<code>session cookie</code></li>
<li><code>expires</code> 要求使用 GMT 时区的这种格式
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 当前时间 +1 天
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">date</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span> <span class="o">+</span> <span class="mf">86400e3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">date</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nx">toUTCString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="s2">&#34;user=John; expires=&#34;</span> <span class="o">+</span> <span class="nx">date</span><span class="p">;</span>
</span></span></code></pre></div></li>
<li><code>max-age</code>: 单位为秒</li>
</ul>
</li>
<li><code>secure</code>
<ul>
<li>表示该cookie只能通过HTTPS传输</li>
</ul>
</li>
<li><code>samesite</code>
<ol>
<li><code>strict</code></li>
</ol>
<ul>
<li>默认</li>
<li>如果用户来自同一网站之外，那么设置了 samesite=strict 的 cookie 永远不会被发送</li>
</ul>
<ol start="2">
<li><code>lax</code></li>
</ol>
<ul>
<li>和 strict 模式类似，当从外部来到网站，则禁止浏览器发送 cookie，除非满足两个条件
<ol>
<li>HTTP 方法是“安全的”（例如 GET 方法，而不是 POST）。</li>
<li>该操作执行顶级导航（更改浏览器地址栏中的 URL）。</li>
</ol>
</li>
<li>缺点：会被到 2017 年左右的旧版本浏览器忽略（不兼容）</li>
</ul>
</li>
<li><code>httpOnly</code>
<ul>
<li>Web服务器使用 Set-Cookie header 来设置 cookie时，可以设置 httpOnly 选项</li>
<li>禁止任何 JavaScript 访问 cookie</li>
</ul>
</li>
</ul>
<h3 id="第三方cookie">第三方cookie</h3>
<ul>
<li>如果 cookie 是由用户所访问的页面的域以外的域放置的，则称其为第三方 cookie。</li>
<li>通常用于跟踪和广告服务。它们被绑定在原始域上，因此第三方网站可以在不同网站之间跟踪同一用户，如果这些网站都可以访问该第三方网站的话</li>
</ul>
<h3 id="gdpr">GDPR</h3>
<ul>
<li>欧洲有一项名为 GDPR 的立法，该法规针对网站尊重用户实施了一系列规则。其中之一就是需要明确的许可才可以跟踪用户的 cookie。</li>
<li>如果我们要设置带有身份验证会话（session）或跟踪 id 的 cookie，那么必须得到用户的允许。</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://zh.javascript.info/cookie#samesite"  target="_blank" rel="noopener" >Cookie，document.cookie</a></li>
<li><a href="https://juejin.cn/post/7320528982386163775"  target="_blank" rel="noopener" >Chrome禁用三方Cookie：前端必知的影响 - 掘金</a></li>
</ul>
<hr>
<h2 id="sessionstorage和localstorage">sessionStorage和localStorage</h2>
<h3 id="sessionstorage">sessionStorage</h3>
<ul>
<li>sessionStorage是HTML5引入的Web存储机制之一，用于在浏览器中临时存储会话数据。</li>
<li>sessionStorage中存储的数据仅在当前会话期间有效，<strong>当用户关闭浏览器标签页或窗口时会被清除</strong>。</li>
<li>sessionStorage中存储的数据仅限于当前页面或同源页面之间共享，不同页面之间的sessionStorage数据不会共享。</li>
</ul>
<h3 id="localstorage">localStorage</h3>
<ul>
<li>localStorage也是HTML5引入的Web存储机制之一，用于在浏览器中持久存储数据。</li>
<li>localStorage中存储的数据在用户关闭浏览器后<strong>仍然保留</strong>，直到用户显式删除它们。</li>
<li>localStorage中存储的数据也只限于同源页面之间共享，不同源页面之间的localStorage数据不会共享。</li>
<li>存满了会报错: <code>QuotaExceededError</code></li>
</ul>
<h3 id="对比">对比</h3>
<ul>
<li><strong>生命周期</strong>：
<ol>
<li>Cookie可以通过设置过期时间来控制生命周期</li>
<li>sessionStorage的数据仅在当前会话期间有效</li>
<li>localStorage的数据则在浏览器关闭后仍然保留。</li>
</ol>
</li>
<li><strong>数据共享</strong>：
<ol>
<li>Cookie的数据则在同源或跨域请求中都会发送到服务器端。</li>
<li>sessionStorage: 多窗口之间sessionStorage不可以共享状态,但是在某些特定场景下新开的页面会复制之前页面的sessionStorage</li>
<li>localStorage的数据在<strong>同源页面之间</strong>共享</li>
</ol>
</li>
<li><strong>存储容量</strong>：
<ul>
<li>Cookie相对较小(几kb)</li>
<li>sessionStorage和localStorage通常具有更大的存储容量限制(几兆)</li>
</ul>
</li>
</ul>
<h3 id="storage-event">storage event</h3>
<ul>
<li>
<p>不会冒泡</p>
</li>
<li>
<p>The storage event of the Window interface fires when a storage area (localStorage or sessionStorage) has been modified in the context of another document.</p>
</li>
<li>
<p>A way for other browsing contexts on the domain using the storage to sync any changes that are made.</p>
</li>
<li>
<p>Event properties</p>
<ol>
<li>key</li>
<li>newValue</li>
<li>oldValue</li>
<li>storageArea</li>
<li>url</li>
</ol>
</li>
<li>
<p>示例</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;storage&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// When local storage changes, dump the list to
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// the console.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s2">&#34;sampleList&#34;</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
<li>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event"  target="_blank" rel="noopener" >Window: storage event - Web APIs | MDN</a></p>
</li>
</ul>
<h3 id="延伸">延伸</h3>
<ul>
<li>use localStorage to maintain state across windows
<ul>
<li><a href="https://github.com/bgstaal/multipleWindow3dScene"  target="_blank" rel="noopener" >bgstaal/multipleWindow3dScene: A quick example of how one can &ldquo;synchronize&rdquo; a 3d scene across multiple windows using three.js and localStorage</a></li>
</ul>
</li>
<li>使用sessionStorage和localStorage来存储jwt
<ul>
<li><a href="https://github.com/EuDs63/BookRecommend_Front"  target="_blank" rel="noopener" >EuDs63/BookRecommend_Front: 图书推荐系统</a></li>
</ul>
</li>
<li>localStorage 存满了再往里写会发生什么？
<ul>
<li>存不进去并报错（QuotaExceededError）</li>
<li><a href="https://www.cnblogs.com/kidney/p/9058352.html"  target="_blank" rel="noopener" >localSto存不进去并报错（QuotaExceededError）rage 存满了怎么办？ - {Bison} - 博客园</a></li>
</ul>
</li>
</ul>
<h3 id="参考-1">参考：</h3>
<ul>
<li><a href="https://www.explainthis.io/zh-hans/swe/cookie-sessionstorage-localstorage-difference"  target="_blank" rel="noopener" >请描述 cookie, sessionStorage 和 localStorage 的差异｜ExplainThis</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage"  target="_blank" rel="noopener" >Window.sessionStorage - Web API 接口参考 | MDN</a></li>
<li><a href="https://juejin.cn/post/7076767687828832286"  target="_blank" rel="noopener" >面试官：你确定多窗口之间sessionStorage不能共享状态吗？？？🤔 - 掘金</a></li>
</ul>
<hr>
<h2 id="indexeddb">IndexedDB</h2>
<h3 id="概念">概念</h3>
<ul>
<li>浏览器中的数据库</li>
</ul>
<h3 id="用户能修改吗">用户能修改吗？</h3>
<ul>
<li>答: Chrome浏览器并没有提供给用户直接修改的方式,但肯定能改。</li>
<li>存储的位置位于(win11系统): <code>c:\Users\USERNAME\AppData\Local\Google\Chrome\User Data\Default\IndexedDB\</code></li>
<li>每个“源”有两个文件夹，类似于
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">http_localhost_3001.indexeddb.blob
</span></span><span class="line"><span class="cl">http_localhost_3001.indexeddb.leveldb
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https_www.bilibili.com_0.indexeddb.blob
</span></span><span class="line"><span class="cl">https_www.bilibili.com_0.indexeddb.leveldb
</span></span></code></pre></div>ps: 看到这就很好理解同源的要求了</li>
<li>被加密了，但还是不推荐存储任何服务端敏感的内容于用户端</li>
<li><a href="https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/storage/indexeddb#edit-indexeddb-data-by-using-the-console-tool"  target="_blank" rel="noopener" >Edit IndexedDB data by using the Console tool - Microsoft Edge Developer documentation | Microsoft Learn</a></li>
</ul>
<h3 id="优化">优化</h3>
<ul>
<li>思路来自<a href="https://x.com/wsygc/status/1834835198334394667"  target="_blank" rel="noopener" >Tristan on X</a></li>
</ul>
<blockquote>
<p>虽然indexDB可以当数据库存很多图片（blob），但随着用户使用的时间变长，本地存放的图会越来越多，其实大部分是不会再用到的，数据一多，读取效率会打折扣，所以做了个FIFO存储队列，最多存50张。</p>
</blockquote>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API"  target="_blank" rel="noopener" >IndexedDB - Web API 接口参考 | MDN</a></li>
<li><a href="https://zh.javascript.info/indexeddb"  target="_blank" rel="noopener" >IndexedDB</a></li>
<li><a href="https://stackoverflow.com/questions/33983979/edit-data-in-indexeddb-by-the-user"  target="_blank" rel="noopener" >Edit data in IndexedDB by the user - Stack Overflow</a></li>
<li><a href="https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/storage/indexeddb"  target="_blank" rel="noopener" >View and change IndexedDB data - Microsoft Edge Developer documentation | Microsoft Learn</a></li>
</ul>
<hr>
<h2 id="cachestorage">CacheStorage</h2>
<ul>
<li>This feature is available in Web Workers.</li>
</ul>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage"  target="_blank" rel="noopener" >CacheStorage - Web APIs | MDN</a></li>
</ul>
<hr>
<h2 id="浏览器缓存">浏览器缓存</h2>
<h3 id="定义">定义</h3>
<blockquote>
<p>当我们访问一个网站时，会加载各种资源，如 HTML文档、JS、CSS、图片等。浏览器会将一些不经常变的资源保存在本地，这样下次访问相同网站时，就直接从本地加载资源，并不通过请求服务器，这就是浏览器缓存</p>
</blockquote>
<h3 id="分类">分类</h3>
<ul>
<li>
<p><strong>根据位置分类</strong></p>
<ul>
<li>memory cache:主要用来缓存有 preloader 相关指令的资源;关闭tab页后就释放</li>
<li>disk cache</li>
</ul>
</li>
<li>
<p><strong>根据是否需要和服务器进行通信分类</strong></p>
<ul>
<li>强缓存
<ul>
<li>不会向服务器发送请求，直接从缓存中读取资源</li>
<li>通过<code>Expires</code>和<code>Cache-Control</code>来实现的</li>
</ul>
</li>
<li>协商缓存
<ul>
<li>在强缓存失效后，浏览器携带缓存标识向服务器发起请求，由服务器根据缓存标识来决定是否使用缓存</li>
<li>利用的是<code>Last-Modified</code>,<code>If-Modified-Since</code>和<code>ETag</code>,<code>If-None-Match</code>这两对Header来管理</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="response-header中的相关属性">Response Header中的相关属性</h3>
<ol>
<li><code>Expires</code></li>
</ol>
<ul>
<li>HTTP/1</li>
</ul>
<ol start="2">
<li><code>Last-Modified</code> / <code>If-Modified-Since</code></li>
</ol>
<ul>
<li>HTTP/1</li>
<li>流程
<ol>
<li>浏览器第一次访问资源，<strong>服务器</strong>会 Response Header 里添加 Last-Modified 的值</li>
<li>浏览器在下一次请求这个资源的时候，检测到有<code>Last-Modified</code>这个 Header。<strong>浏览器</strong>就会在Request中加上 <code>If-Modified-Since</code>，<code>If-Modified-Since</code>的值就是 Last-Modified 的值</li>
<li>服务器收到请求后，如果资源没有修改，服务器返回 304 Not Modified 状态码，并且不包含资源的内容。浏览器此时会使用本地缓存中的资源。</li>
<li>如果资源发生了修改，服务器会返回新的资源内容和更新后的 Last-Modified。</li>
</ol>
</li>
</ul>
<ol start="3">
<li><code>Cache-Control</code></li>
</ol>
<ul>
<li>HTTP/1.1</li>
<li>优先级比 Expires 要高</li>
<li>可选值
<ul>
<li>public</li>
<li>private</li>
<li>no-store: 完全禁用缓存，资源不会存储在缓存中。</li>
<li>no-cache: 告诉浏览器要使用缓存文件，但是每次需要跟服务器确认是最新文件以后才能用，一般使用 Etag 或者 Last-Modified 字段来控制缓存</li>
<li>max-age=60</li>
</ul>
</li>
</ul>
<ol start="4">
<li><code>ETag</code> / <code>If-None-Match</code></li>
</ol>
<ul>
<li>HTTP/1.1</li>
<li>ETag由服务器生成,三种方式：基于内容 / 基于版本 / 自定义生成</li>
<li>浏览器在下一次加载资源向服务器发送请求时，会将上一次返回的<code>Etag</code>值放到request header里的<code>If-None-Match</code>里</li>
<li>ETag 的优先级要高于 Last-Modified</li>
<li>解决了<code>Last-Modified</code>的如下问题
<ol>
<li>某些服务器不能精确得到文件的最后修改时间， 这样就无法通过最后修改时间来判断文件是否更新了。</li>
<li>某些文件的修改非常频繁，在秒以下的时间内进行修改. Last-Modified只能精确到秒。</li>
<li>一些文件的最后修改时间改变了，但是内容并未改变。 我们不希望客户端认为这个文件修改了。</li>
</ol>
</li>
</ul>
<h3 id="如何禁用缓存如何使缓存失效">如何禁用缓存(如何使缓存失效)</h3>
<ul>
<li>场景一: 发版，要求无视缓存
<ul>
<li>每次对应静态文件里有内容改动的时候，自动加一段 hash 到静态文件名里</li>
</ul>
</li>
<li>场景二: 用户自己想要刷新
<ul>
<li>F5 刷新: 因浏览器而异</li>
<li>Ctrl + F5 强制刷新的时候，会暂时禁用强缓存和协商缓存</li>
</ul>
</li>
</ul>
<h3 id="后端配置">后端配置</h3>
<ul>
<li><code>setHeader</code>之类</li>
<li>Nginx 配置</li>
</ul>
<h3 id="参考-4">参考</h3>
<ul>
<li><a href="https://limeii.github.io/2018/11/web-cache/"  target="_blank" rel="noopener" >浏览器缓存机制：强缓存和协商缓存</a></li>
<li><a href="https://segmentfault.com/a/1190000021661656"  target="_blank" rel="noopener" >前端 - 浏览器的强缓存和协商缓存 - yiliang.share - SegmentFault 思否</a></li>
<li><a href="https://lewinblog.com/blog/page/2022/221007-http-headers-cache-control.md"  target="_blank" rel="noopener" >HTTP缓存控制: Cache-Control - Lewin&rsquo;s Blog</a></li>
</ul>
<hr>
<h2 id="其他缓存">其他缓存</h2>
<h3 id="memory-cache内存缓存">Memory Cache（内存缓存）</h3>
<ul>
<li><strong>特点</strong>：缓存存储在浏览器的内存中，主要用于存储从网络请求获取的资源（如 HTML、CSS、JavaScript 和图片）。这种缓存生命周期短，只在当前页面会话中有效，页面刷新或关闭后缓存会被清除。</li>
<li><strong>用途</strong>：用于快速重用同一页面内的资源，提升页面加载速度。</li>
<li><strong>存储时间</strong>：通常在页面刷新或关闭后即清除。</li>
<li><strong>优点</strong>：速度最快，适用于瞬时的页面资源重用。</li>
</ul>
<h3 id="push-cache">Push Cache</h3>
<ul>
<li><strong>特点</strong>: 在用户并未明确请求某些资源的情况下，提前将这些资源推送到用户的缓存中。</li>
<li><strong>用途</strong>: 在用户即将需要某些资源时，提前发送这些资源，这样在用户实际请求时，可以直接从缓存中获取，而无需再次请求服务器。</li>
</ul>
<h3 id="application-cacheappcache">Application Cache（AppCache）</h3>
<ul>
<li><strong>特点</strong>：这是 HTML5 中引入的离线缓存机制，允许开发者为 web 应用创建一个离线模式，用户即使断网也能访问缓存的内容。然而，由于 AppCache 有不少缺陷和安全隐患，已被弃用。</li>
<li><strong>用途</strong>：过去用于创建离线 web 应用，但目前已被 <code>Service Worker</code> 取代。</li>
<li><strong>状态</strong>：AppCache 从 HTML 5.1 开始废弃，现在大多数浏览器都不再支持。</li>
</ul>
<h3 id="websql">WebSQL</h3>
<ul>
<li><strong>特点</strong>：WebSQL 是一种基于 SQL 的数据库，最初用于在浏览器中存储结构化数据。然而由于其标准化进程停止，WebSQL 不再是主流推荐的方案。</li>
<li><strong>用途</strong>：在浏览器中进行 SQL 查询和存储结构化数据，类似 <code>IndexedDB</code> 的早期版本。</li>
<li><strong>状态</strong>：已被 <code>IndexedDB</code> 取代。</li>
</ul>
<h3 id="web-storage-cache-api">Web Storage Cache API</h3>
<ul>
<li><strong>特点</strong>：缓存 API 是 <code>Service Worker</code> 的一部分，允许在浏览器中存储 <code>Request</code> 和 <code>Response</code> 对象，常用于离线缓存。与普通缓存机制不同，开发者可以精确控制缓存的资源，并且缓存的内容可以在离线时访问。</li>
<li><strong>用途</strong>：用于离线支持、缓存管理、动态内容缓存，通常与 <code>Service Worker</code> 配合使用。</li>
<li><strong>优点</strong>：可控性更强，适用于现代 PWA（渐进式 Web 应用）的缓存策略。</li>
</ul>
<h3 id="manifest-storage">Manifest Storage</h3>
<ul>
<li><strong>特点</strong>：一种较新的 API（如 Web App Manifest），允许开发者为应用程序提供缓存策略和应用图标等元数据，常用于渐进式 Web 应用（PWA）。</li>
<li><strong>用途</strong>：存储应用元数据，定义应用行为（如是否作为全屏应用、离线模式等）。</li>
</ul>
<h3 id="file-system-access-api">File System Access API</h3>
<ul>
<li><strong>特点</strong>：允许 Web 应用访问用户的文件系统，可以直接读写文件。通过这个 API，Web 应用可以处理用户计算机上的文件，实现类似桌面应用的体验。</li>
<li><strong>用途</strong>：用户可以在不离开浏览器的情况下，直接从文件系统中读取、修改和保存文件。</li>
<li><strong>状态</strong>：这是一个较新的 API，仍在部分浏览器中实现，安全性要求较高。</li>
</ul>
<hr>
<h2 id="参考-5">参考</h2>
<ul>
<li><a href="http://blog.fantasy.codes/front-end/2016/08/23/dive-into-browser-storage/"  target="_blank" rel="noopener" >探索浏览器端的存储方式</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>设计模式学习笔记</title>
      <link>https://ds63.eu.org/2024/learn-design-patterns/</link>
      <pubDate>Tue, 08 Oct 2024 19:51:22 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn-design-patterns/</guid>
      <description>无招胜有招</description>
      <content:encoded><![CDATA[<h2 id="列举">列举</h2>
<h3 id="创建型">创建型</h3>
<ul>
<li>要点
<ul>
<li>提供创建对象的机制， 能够提升已有代码的灵活性和可复用性。</li>
</ul>
</li>
<li>工厂方法</li>
<li>抽象工厂</li>
<li>生成器</li>
<li>原型</li>
<li>单例</li>
</ul>
<h3 id="结构型">结构型</h3>
<ul>
<li>要点
<ul>
<li>考虑的是对象的组成和对象之间的关系,假如对象发生了重大改变,对当前对象操作影响降至最低</li>
<li>将对象和类组装成较大的结构， 并同时保持结构的灵活和高效。</li>
</ul>
</li>
<li>适配器模式</li>
<li>桥接模式</li>
<li>组合</li>
<li>装饰器模式</li>
<li>外观模式</li>
<li>享元模式</li>
<li>代理模式</li>
</ul>
<h3 id="行为型">行为型</h3>
<ul>
<li>要点
<ul>
<li>关注的是对象之间的依赖关系以及通信</li>
<li>负责对象间的高效沟通和职责委派。</li>
</ul>
</li>
<li>责任链</li>
<li>命令</li>
<li>迭代器</li>
<li>中介者</li>
<li>备忘录</li>
<li>观察者</li>
<li>状态</li>
<li>策略</li>
<li>模板方法</li>
<li>访问者</li>
</ul>
<h3 id="前端常用">前端常用</h3>
<ol>
<li>单例模式</li>
<li>观察者模式(发布订阅模式)
<ul>
<li>redux</li>
</ul>
</li>
<li>命令模式
<ul>
<li>s3</li>
</ul>
</li>
<li>策略模式
<ul>
<li>大幅度减少多重条件下的判断</li>
</ul>
</li>
</ol>
<h3 id="有助于提高系统的可拓展性">有助于提高系统的可拓展性</h3>
<ul>
<li>工厂模式</li>
<li>抽象工厂模式</li>
<li>观察者模式: 观察者很容易增加</li>
<li>适配器模式: 适配新的接口</li>
<li>代理模式: 在原来的功能上增加新功能或逻辑</li>
<li>责任链模式: 通过新增拦截器/过滤器来实现对数据的处理</li>
<li>策略模式: 新增策略</li>
</ul>
<hr>
<h2 id="发布订阅">发布订阅</h2>
<h3 id="定义">定义</h3>
<ul>
<li>发布-订阅模式其实是一种对象间一对多的依赖关系。</li>
<li>当一个对象的状态发送改变时，所有依赖于它的对象都将得到状态改变的通知。</li>
<li>三个角色(订阅者，调度中心，发布者)</li>
<li>流程：订阅者（Subscriber）把自己想订阅的事件注册（Subscribe）到调度中心（Event Channel），当发布者（Publisher）发布该事件（Publish Event）到调度中心，也就是该事件触发时，由调度中心统一调度（Fire Event）订阅者注册到调度中心的处理代码。</li>
</ul>
<h3 id="实现">实现</h3>
<ul>
<li>摘自<a href="https://juejin.cn/post/6985156199192723487"  target="_blank" rel="noopener" >手写一个基于发布订阅模式的js事件处理中心(EventEmitter) - 掘金</a></li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">EventEmitter</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">constructor</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">_events</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">on</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="nx">callback</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]){</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">eventName</span> <span class="o">!==</span> <span class="s2">&#34;newListener&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                <span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s2">&#34;newListener&#34;</span><span class="p">,</span> <span class="nx">eventName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">callbacks</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">||</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">        <span class="nx">callbacks</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">=</span> <span class="nx">callbacks</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="p">...</span><span class="nx">args</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">callbacks</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">||</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">        <span class="nx">callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">cb</span> <span class="p">=&gt;</span> <span class="nx">cb</span><span class="p">(...</span><span class="nx">args</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">once</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="nx">callback</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">one</span> <span class="o">=</span> <span class="p">(...</span><span class="nx">args</span><span class="p">)=&gt;{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">callback</span><span class="p">(...</span><span class="nx">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">off</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="nx">one</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nx">one</span><span class="p">.</span><span class="nx">initialCallback</span> <span class="o">=</span> <span class="nx">callback</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="nx">one</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">     <span class="nx">off</span><span class="p">(</span><span class="nx">eventName</span><span class="p">,</span> <span class="nx">callback</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">callbacks</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">||</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">newCallbacks</span> <span class="o">=</span> <span class="nx">callbacks</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">fn</span> <span class="p">=&gt;</span> <span class="nx">fn</span> <span class="o">!=</span> <span class="nx">callback</span> <span class="o">&amp;&amp;</span> <span class="nx">fn</span><span class="p">.</span><span class="nx">initialCallback</span> <span class="o">!=</span> <span class="nx">callback</span> <span class="cm">/* 用于once的取消订阅 */</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">=</span> <span class="nx">newCallbacks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="eventbus">EventBus</h3>
<ul>
<li>指<a href="https://github.com/greenrobot/EventBus"  target="_blank" rel="noopener" >greenrobot/EventBus: Event bus for Android and Java that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.</a></li>
<li>发布订阅模式</li>
<li>
  <img loading="lazy" src="https://github.com/greenrobot/EventBus/raw/master/EventBus-Publish-Subscribe.png" alt="架构图"  /></li>
<li>使用: 参见 <a href="https://www.cnblogs.com/sishuiliuyun/p/16283018.html"  target="_blank" rel="noopener" >EventBus 使用（全面分析，细节提醒） - 似水流云 - 博客园</a></li>
</ul>
<h3 id="区别于观察者模式">区别于观察者模式</h3>
<ul>
<li>观察者是经典软件设计模式中的一种,但发布订阅只是软件架构中的一种消息范式。</li>
<li>观察者模式本身只需要2个角色便可成型，即观察者和被观察者，其中被观察者是重点。</li>
<li>发布订阅需要至少3个角色来组成，包括发布者、订阅者和发布订阅中心，其中发布订阅中心是重点。</li>
<li>观察者模式实现
<ol>
<li>被观察者对象</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">observerList</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">addObserver</span><span class="p">(</span><span class="nx">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">observerList</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">observer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">removeObserver</span><span class="p">(</span><span class="nx">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">index</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">observerList</span><span class="p">.</span><span class="nx">findIndex</span><span class="p">(</span><span class="nx">o</span> <span class="p">=&gt;</span> <span class="nx">o</span><span class="p">.</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">observer</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">observerList</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">notifyObservers</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">observers</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">observerList</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">observers</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">observer</span> <span class="p">=&gt;</span> <span class="nx">observer</span><span class="p">.</span><span class="nx">notified</span><span class="p">(</span><span class="nx">message</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="2">
<li>观察者</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Observer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">constructor</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">subject</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">subject</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">subject</span><span class="p">.</span><span class="nx">addObserver</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">notified</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;got message&#39;</span><span class="p">,</span> <span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="3">
<li>使用</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">subject</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Subject</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">observerA</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Observer</span><span class="p">(</span><span class="s1">&#39;observerA&#39;</span><span class="p">,</span> <span class="nx">subject</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">observerB</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Observer</span><span class="p">(</span><span class="s1">&#39;observerB&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">subject</span><span class="p">.</span><span class="nx">addObserver</span><span class="p">(</span><span class="nx">observerB</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">subject</span><span class="p">.</span><span class="nx">notifyObservers</span><span class="p">(</span><span class="s1">&#39;Hello from subject&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">subject</span><span class="p">.</span><span class="nx">removeObserver</span><span class="p">(</span><span class="nx">observerA</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">subject</span><span class="p">.</span><span class="nx">notifyObservers</span><span class="p">(</span><span class="s1">&#39;Hello again&#39;</span><span class="p">);</span>
</span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="装饰器模式">装饰器模式</h2>
<p>wip</p>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://zh.javascript.info/call-apply-decorators#tou-ming-huan-cun"  target="_blank" rel="noopener" >装饰器模式和转发，call/apply</a></li>
</ul>
<hr>
<h2 id="参考-1">参考</h2>
<ul>
<li><a href="https://refactoringguru.cn/design-patterns/catalog"  target="_blank" rel="noopener" >设计模式目录：22种设计模式</a></li>
<li><a href="https://www.cnblogs.com/kyoner/p/11425999.html"  target="_blank" rel="noopener" >《Head First 设计模式》读书笔记 - murphy_gb - 博客园</a></li>
<li><a href="https://juejin.cn/post/6871098899960971278"  target="_blank" rel="noopener" >前端常用设计模式分享 - 掘金</a></li>
<li><a href="https://barnett617.github.io/wilson-blog/posts/2021-06-28-observer-pattern/"  target="_blank" rel="noopener" >理解【观察者模式】和【发布订阅】的区别 | Wilson&rsquo;s Blog</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>进一步学习ReactHook</title>
      <link>https://ds63.eu.org/2024/learn_react_hook/</link>
      <pubDate>Tue, 08 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_react_hook/</guid>
      <description>从“生命周期和时间”的思维模式转变为“状态和与DOM的同步”的思维模式</description>
      <content:encoded><![CDATA[<h2 id="react-官方-hook">React 官方 Hook</h2>
<p>Hook 是 React 16.8 之后引入的一个特性，允许你在不使用类组件的情况下在函数组件中引入状态和其他 React 特性。</p>
<h3 id="usestate"><code>useState</code></h3>
<ul>
<li><code>useState</code> 允许在函数组件中引入局部状态。它的实现依赖于闭包和状态管理机制。</li>
<li>每次渲染时，React 通过维护一个 “hook 调用栈” 来保存每次调用 <code>useState</code> 后的状态。这些状态被保存在一个链表结构中，每次渲染时 React 都会按顺序遍历这些状态。</li>
</ul>
<h3 id="useeffect"><code>useEffect</code></h3>
<ul>
<li><code>useEffect</code> 允许在函数组件中执行副作用，比如数据请求、订阅、直接 DOM 操作等。- 它的实现原理是通过依赖数组来追踪变化，并在 DOM 完成更新后执行指定的副作用逻辑。如果某些依赖值发生变化，React 就会在下一次渲染后重新执行该副作用函数。</li>
</ul>
<h3 id="usecontext"><code>useContext</code></h3>
<p>wip</p>
<h3 id="usereducer"><code>useReducer</code></h3>
<p>wip</p>
<ul>
<li>参考: <a href="https://juejin.cn/post/7091180323123232782"  target="_blank" rel="noopener" >深入学习React Hook——useReducer - 掘金</a></li>
</ul>
<h2 id="useid">useId</h2>
<ul>
<li><a href="https://react.dev/reference/react/useId"  target="_blank" rel="noopener" >useId – React</a></li>
<li>generate a unique ID</li>
<li>A component may be rendered more than once on the page—but IDs have to be unique! Instead of hardcoding an ID, generate a unique ID with useId.</li>
</ul>
<hr>
<h3 id="hook-的顺序与规则">Hook 的顺序与规则</h3>
<ul>
<li>Hook 的使用顺序非常重要。React 需要在每次渲染时依赖 Hook 调用的顺序来关联正确的状态。所以，Hook 必须在顶层调用，不能放在条件或循环中。</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/6891577820821061646"  target="_blank" rel="noopener" >React Hooks原理探究，看完不懂，你打我 - 掘金</a></li>
<li><a href="https://coderperson.com/2020/08/02/React%20Hooks%20%E8%A7%A3%E6%9E%90/"  target="_blank" rel="noopener" >React Hooks解析（看这一篇就够了） | 骚客</a></li>
<li><a href="https://incepter.github.io/how-react-works/docs/react-dom/how.hooks.work/#thenable"  target="_blank" rel="noopener" >How hooks work | How React Works</a></li>
<li><a href="https://github.com/z-memo/interview/issues/138"  target="_blank" rel="noopener" >react hooks 的原理是什么 · Issue #138 · z-memo/interview</a></li>
</ul>
<hr>
<h2 id="自定义hook">自定义hook</h2>
<h3 id="hook的理解">hook的理解</h3>
<ol>
<li>
<blockquote>
<p>在 React 中被调用的且以 use 开头命名的函数叫 Hook。</p>
</blockquote>
</li>
<li>Hooks 是一种范式转换，从“生命周期和时间”的思维模式转变为“状态和与DOM的同步”的思维模式</li>
</ol>
<blockquote>
<p>准确来说，应该是逻辑片段复用。</p>
<p>和组件化思维不同，这是另外一个粒度更细的代码复用思维。例如我们之前提到的，获取同样的数据。在组件化思维中，一个完整的组件，包括了这份数据，以及这份数据在页面上的展示结果。因此这是不同的复用思维。</p>
<p>处理获取数据过程中的公用逻辑，处理公用的登陆逻辑等。自定义hooks封装的大多数情况下不是一个完整的页面逻辑实现，而是其中的一个片段。 自定义hook能够跟随函数组件重复执行，并且每次都返回最新结果。因此，我们可以非常放心大胆的封装异步逻辑。</p>
</blockquote>
<ol start="3">
<li>自定义 Hook 是将逻辑封装为可重用的代码块。它实际上是一个普通的 JavaScript 函数，可以使用其他 Hook，并返回状态或副作用逻辑。自定义 Hook 让组件逻辑更加灵活和可重用。</li>
</ol>
<h3 id="自己的经历">自己的经历</h3>
<ol>
<li>
<p>在我写<a href="https://github.com/EuDs63/BookRecommend_Front"  target="_blank" rel="noopener" >EuDs63/BookRecommend_Front: 图书推荐系统</a>，就很经常需要从API获取数据。虽然这时候还没有自定义hook的概念，但很自然地封装了一个函数。在看了<a href="https://blog.skk.moe/post/why-you-should-not-fetch-data-directly-in-use-effect/"  target="_blank" rel="noopener" >为什么你不应该在 React 中直接使用 useEffect 从 API 获取数据 | Sukka&rsquo;s Blog</a>，了解到<a href="https://swr.vercel.app/zh-CN"  target="_blank" rel="noopener" >用于数据请求的 React Hooks 库 – SWR</a>。</p>
</li>
<li>
<p>发现了阿里巴巴开源的<a href="https://ahooks.js.org/"  target="_blank" rel="noopener" >ahooks - React Hooks Library - ahooks 3.0</a>,封装了常用的hook，代码量都不算很大，但都很巧妙，正在学习中。</p>
</li>
<li>
<p>看<a href="https://blog.saeloun.com/2022/02/17/how-to-integrate-react-app-with-google-analytics/"  target="_blank" rel="noopener" >How to integrate Google Analytics with React JS application? | Saeloun Blog</a> ,可以把ga给集成为hook,react-router-dom</p>
</li>
<li>
<p>读<a href="https://swr.vercel.app/zh-CN"  target="_blank" rel="noopener" >用于数据请求的 React Hooks 库 – SWR</a>，看上了<a href="https://swr.vercel.app/zh-CN/examples/subscription"  target="_blank" rel="noopener" >Subscription – SWR</a>，感觉能用来替代项目中使用的redux，但搜了圈，能找到的资料不多，算了。</p>
</li>
<li>
<p>发现<a href="https://usehooks.com/"  target="_blank" rel="noopener" >useHooks – The React Hooks Library</a>，可以学学</p>
</li>
</ol>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzI4NjE3MzQzNg==&amp;mid=2649865889&amp;idx=1&amp;sn=2549fb3da7608aa8e3cce0623fbd8d25"  target="_blank" rel="noopener" >超性感的React Hooks（五）：自定义hooks</a></li>
<li><a href="https://mp.weixin.qq.com/s/GPcwIPJBc9I_NtixyU-U4Q"  target="_blank" rel="noopener" >超性感的React Hooks（六）自定义hooks的思维方式</a></li>
<li><a href="https://blog.skk.moe/post/why-you-should-not-fetch-data-directly-in-use-effect/"  target="_blank" rel="noopener" >为什么你不应该在 React 中直接使用 useEffect 从 API 获取数据 | Sukka&rsquo;s Blog</a></li>
<li><a href="https://zh-hans.react.dev/warnings/invalid-hook-call-warning"  target="_blank" rel="noopener" >Hook 规则 – React 中文文档</a></li>
</ul>
<hr>
<h2 id="问题">问题</h2>
<h3 id="react-是如何把对-hook-的调用和组件联系起来的">React 是如何把对 Hook 的调用和组件联系起来的？</h3>
<p><a href="https://zh-hans.legacy.reactjs.org/docs/hooks-faq.html#under-the-hood"  target="_blank" rel="noopener" >Hooks FAQ – React</a></p>
<blockquote>
<p>React 保持对当前渲染中的组件的追踪。Hook 只会在 React 组件中被调用（或自定义 Hook —— 同样只会在 React 组件中被调用）。</p>
<p>每个组件内部都有一个「记忆单元格」列表。它们只不过是我们用来存储一些数据的 JavaScript 对象。当你用 useState() 调用一个 Hook 的时候，它会读取当前的单元格（或在首次渲染时将其初始化），然后把指针移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因。</p>
</blockquote>
<h3 id="为什么usestate是异步的">为什么useState是异步的</h3>
<p><code>useState</code> 的行为在<strong>某种程度</strong>上表现为异步，主要原因是为了优化 React 的渲染过程和性能。React 将多个状态更新合并到一起，并通过批量更新的方式避免不必要的重新渲染。具体原因如下：</p>
<ol>
<li><strong>批量更新机制</strong></li>
</ol>
<ul>
<li>React 在处理事件处理函数或生命周期方法（如 <code>useEffect</code>）中的 <code>setState</code> 调用时，通常不会立即应用状态更新，而是会将这些更新“批量”处理。在一次事件循环中，多个 <code>setState</code> 调用会被合并为一次更新。这种批量更新策略可以提高性能，避免在每次状态变化后都重新渲染组件。</li>
<li>示例：批量更新</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleClick</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// 更新不会立即发生
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// 也不会立即发生
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleClick</span><span class="p">}</span><span class="o">&gt;</span><span class="nx">Increment</span><span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在这个例子中，虽然调用了两次 <code>setCount</code>，但 React 会将它们合并为一次更新。
2. 异步特性防止多次渲染</p>
<ul>
<li>
<p>如果 <code>useState</code> 是同步的，每次调用 <code>setState</code> 时都会导致组件重新渲染，这样会严重影响性能。想象在一次事件处理函数中调用多次 <code>setState</code>，如果每次都导致同步重新渲染，性能开销将非常高。</p>
</li>
<li>
<p>示例：同步更新的弊端</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleClick</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// 如果是同步，组件将立即重新渲染
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// 会导致多次无效渲染
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleClick</span><span class="p">}</span><span class="o">&gt;</span><span class="nx">Increment</span><span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>如果 <code>setCount</code> 是同步的，React 会在每次状态更新时都重新渲染组件，导致性能下降。为了避免这种情况，React 通过异步机制将多次更新合并到一次渲染中。</p>
<ol start="3">
<li>
<p>React Fiber 架构</p>
<ul>
<li>React 引入了新的 Fiber 架构，使其能够以分片的方式执行任务，将大任务切分成小的可中断的子任务。在此过程中，React 可能会推迟状态更新，直到它完成当前的渲染工作。这样可以确保用户界面始终保持流畅。</li>
<li>如果 <code>useState</code> 是同步的，React 就无法利用 Fiber 架构的优势来进行任务调度和批量更新。</li>
</ul>
</li>
<li>
<p>状态更新并不真正是异步的</p>
<ul>
<li>虽然 <code>useState</code> 的更新机制表现为异步，但从技术上讲，它并不是真正的异步操作，像 <code>Promise</code> 那样。实际上，它是在下一个渲染周期中同步更新的。React 将状态更新延迟到合适的时机，而不是立即应用。</li>
<li>示例：获取最新状态</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleClick</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setCount</span><span class="p">(</span><span class="nx">prevCount</span> <span class="p">=&gt;</span> <span class="nx">prevCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// 使用回调函数获取最新的状态
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">setCount</span><span class="p">(</span><span class="nx">prevCount</span> <span class="p">=&gt;</span> <span class="nx">prevCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// 这样可以确保多次更新正确执行
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleClick</span><span class="p">}</span><span class="o">&gt;</span><span class="nx">Increment</span><span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>通过回调函数 <code>prevCount</code>，我们可以确保每次更新都基于最新的状态值。这样即便 <code>setState</code> 是异步的，也能确保状态更新的正确性。</p>
</li>
</ol>
<h3 id="为什么hooks不能写在ifelse等语句里">为什么hooks不能写在if/else等语句里</h3>
<ol>
<li>
<p>Hooks 调用顺序的依赖</p>
<ul>
<li>React 使用一个内部的“链表”来跟踪组件中的每个 Hook 的调用。当 React 渲染组件时，Hooks 是按照定义的顺序被调用的。在后续渲染中，React 依赖这个顺序来确保同一个 Hook 对应的是之前的状态或副作用。</li>
<li>示例</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>  <span class="c1">// Hook 1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="p">[</span><span class="nx">name</span><span class="p">,</span> <span class="nx">setName</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>   <span class="c1">// Hook 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>                       <span class="c1">// Hook 3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">document</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="sb">`Count: </span><span class="si">${</span><span class="nx">count</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">count</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;{</span><span class="nx">count</span><span class="p">}&lt;/</span><span class="nt">div</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在每次渲染中，React 会按照调用顺序分配状态：</p>
<ol>
<li><code>useState(0)</code> 对应第一个状态 <code>count</code>。</li>
<li><code>useState('')</code> 对应第二个状态 <code>name</code>。</li>
<li><code>useEffect</code> 处理副作用。</li>
</ol>
<p>如果这个顺序保持一致，React 能够正确地追踪状态和副作用。</p>
</li>
<li>
<p>在条件语句中使用 Hooks的后果</p>
<ul>
<li>
<p>可能会导致 Hooks 的调用顺序在不同渲染中不一致</p>
</li>
<li>
<p>错误示例</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>  <span class="c1">// Hook 1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">count</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">[</span><span class="nx">name</span><span class="p">,</span> <span class="nx">setName</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>  <span class="c1">// Hook 2 （条件性调用）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>                       <span class="c1">// Hook 3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">document</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="sb">`Count: </span><span class="si">${</span><span class="nx">count</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">count</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/div&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>如果 <code>count &gt; 0</code>，<code>name</code> 的 <code>useState</code> 会被调用。但如果 <code>count &lt;= 0</code>，该 <code>useState</code> 不会被调用。这导致：</p>
<ul>
<li>当 <code>count &gt; 0</code> 时，<code>useEffect</code> 是第三个 Hook。</li>
<li>当 <code>count &lt;= 0</code> 时，<code>useEffect</code> 是第二个 Hook。</li>
</ul>
<p>这样，React 无法知道哪个 Hook 应该关联到哪个状态，状态更新和副作用可能会错误地关联到不同的 Hook，导致不可预知的错误。</p>
</li>
<li>
<p>React 如何追踪 Hooks</p>
<ul>
<li>React 通过一个全局的“调用栈”来追踪每个组件中的 Hooks。当组件渲染时，React 会按顺序调用所有的 Hooks，并在内部记录这些调用。这样，每次渲染时，React 能够依赖这个顺序来关联状态。</li>
<li>如果在 <code>if/else</code> 中使用 Hooks，可能会导致某些 Hooks 在特定条件下被跳过，破坏这个顺序，从而导致错误的状态关联。</li>
</ul>
</li>
<li>
<p>报错提示</p>
<ul>
<li>
<blockquote>
<p>Rendered more hooks than during the previous render</p>
</blockquote>
</li>
<li>
<blockquote>
<p>Hooks can only be called inside the body of a function component.</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://www.pipipi.net/28758.html"  target="_blank" rel="noopener" >为什么不能在if语句里面写hooks，HooKs链表写得清清楚楚🤣🤣🤣 - 码农之家</a></li>
<li><a href="https://zh-hans.react.dev/warnings/invalid-hook-call-warning"  target="_blank" rel="noopener" >Hook 规则 – React 中文文档</a></li>
<li><a href="https://overreacted.io/why-do-hooks-rely-on-call-order/"  target="_blank" rel="noopener" >Why Do React Hooks Rely on Call Order? — overreacted</a></li>
<li><a href="https://github.com/z-memo/interview/issues/138"  target="_blank" rel="noopener" >react hooks 的原理是什么 · Issue #138 · z-memo/interview</a></li>
</ul>
</li>
</ol>
<h3 id="hooks能实现类里面的所有生命周期吗">hooks能实现类里面的所有生命周期吗</h3>
<ul>
<li>&ldquo;Commit phase&quot;中的三个方法,Can work with DOM, run side effects, schedule updates：
<ol>
<li><code>componentDidMount</code> -&gt; the useEffect hook with the second argument of []</li>
<li><code>componentDidUpdate</code> -&gt; the useEffect hook with the second argument of [state]</li>
<li><code>componentWillUnmount</code> -&gt; <strong>return a function</strong> that runs on unmounting inside the useEffect function,例:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">    <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Bye&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="p">[]);</span>
</span></span></code></pre></div></li>
<li>上面的类比只是类比，不能等同，原因：
<ol>
<li>实际原理不同</li>
<li>执行时机不同</li>
</ol>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>跨域问题</title>
      <link>https://ds63.eu.org/2024/cors_problem/</link>
      <pubDate>Sun, 06 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/cors_problem/</guid>
      <description>blocked by CORS policy</description>
      <content:encoded><![CDATA[<h2 id="什么是同源政策">什么是同源政策?</h2>
<h3 id="定义">定义</h3>
<ul>
<li>如果两个 URL 的协议、端口（如果有指定的话）和主机都相同的话，则这两个 URL 是同源的。</li>
<li>当一个网页加载的资源（如脚本、样式表、图片等）来自于与当前页面不同的域名、协议或端口时，就称为跨域请求。</li>
</ul>
<h3 id="举例">举例：</h3>
<ul>
<li><code>http://store.company.com/dir/page.html</code> 与<code>http://store.company.com/dir2/other.html</code> 同源</li>
<li><code>http://store.company.com/dir/page.html</code> 与<code>http://news.company.com/dir/other.html</code>不同源,因为主机不同</li>
</ul>
<h3 id="参考">参考：</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy"  target="_blank" rel="noopener" >浏览器的同源策略 - Web 安全 | MDN</a></li>
</ul>
<hr>
<h2 id="为什么要有同源政策">为什么要有同源政策?</h2>
<blockquote>
<p>同源政策限制的是非同源的请求，那非同源请求会带来什么问题呢? 假设今天有一个使用者登入某一银行网站www.bank.com ，同时他刚好在使用另一个不安全的网站例如www.stolemoney.com ，如果没有同源政策的话，这个stolemoney 网站可能可以轻易地存取这个使用者在www.bank.com 里的资料。</p>
<p>浏览器的同源政策就像是最基本的一层保护机制，让不同源的网站无法存取到资源和资料。另外要注意的是，这个阻挡机制是在最后浏览器收到服务器端回应后发生的; 也就是说，就算是非同源请求，如果服务器端没有做任何阻挡、并回传结果，浏览器端其实是会成功收到回应，但因为违反同源政策，浏览器会拦截这个回应、并报错。</p>
</blockquote>
<hr>
<h2 id="跨域问题的解决">跨域问题的解决</h2>
<h3 id="三类标签">三类标签</h3>
<ul>
<li>有类个标签允许跨域加载资源
<ol>
<li><code>&lt;img src=XXX&gt;</code></li>
<li><code>&lt;link href=XXX&gt;</code></li>
<li><code>&lt;script src=XXX&gt;</code></li>
</ol>
</li>
</ul>
<h3 id="代理">代理</h3>
<ul>
<li>原理：
<ul>
<li>同源策略只受限于<strong>浏览器</strong>访问服务器，对于<strong>服务器</strong>访问服务器并没有限制的特点。中间服务器做了一个请求转发的功能</li>
</ul>
</li>
<li>实现：
<ul>
<li>Node中间件代理</li>
<li>nginx反向代理</li>
<li>vite配置代理
<ul>
<li><a href="https://zxuqian.cn/vite-proxy-config/"  target="_blank" rel="noopener" >Vite 配置代理 Proxy，避免跨域和重复编写url的问题 - 峰华前端工程师</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="cors">CORS</h3>
<ul>
<li>CORS 跨源资源共享（Cross-Origin Resource Sharing）。</li>
<li>总体思路是：如果浏览器要跨域访问服务器的资源，需要获得服务器的允许</li>
<li>三种请求
<ol>
<li>简单请求
<ul>
<li>需要同时满足以下两大条件
<ol>
<li>使用下列方法之一：GET HEAD POST</li>
<li>Content-Type 的值仅限于下列三者之一：text/plain,multipart/form-data,application/x-www-form-urlencoded</li>
</ol>
</li>
</ul>
</li>
<li>需要预检的请求</li>
<li>附带身份凭证的请求</li>
</ol>
</li>
<li>服务器通过响应header<code>Access-Control-Allow-Origin</code>进行控制</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Glossary/CORS"  target="_blank" rel="noopener" >跨源资源共享 - MDN Web 文档术语表：Web 相关术语的定义 | MDN</a></li>
</ul>
<h3 id="postmessage">postMessage</h3>
<ul>
<li>语法: <code>otherWindow.postMessage(message, targetOrigin, [transfer]);</code></li>
<li>过程
<ol>
<li>获得对另一个窗口的引用（比如 targetWindow = window.opener）</li>
<li>在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息</li>
<li>接收消息的窗口可以根据需要自由处理此事件。</li>
<li>传递给 window.postMessage() 的参数（比如 message）将通过消息事件对象暴露给接收消息的窗口。</li>
</ol>
</li>
<li>安全问题
<ul>
<li>如果你不希望从其他网站接收 message，请不要为 message 事件添加任何事件侦听器。</li>
<li>如果你确实希望从其他网站接收 message，请始终使用 origin 和 source 属性验证发件人的身份。当你使用 postMessage 将数据发送到其他窗口时，始终指定精确的目标 origin，而不是 *。</li>
<li>当你使用 postMessage 将数据发送到其他窗口时，始终指定精确的目标 origin，而不是 *。</li>
</ul>
</li>
<li>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage"  target="_blank" rel="noopener" >window.postMessage - Web API | MDN</a></li>
</ul>
<h3 id="websocket">websocket</h3>
<p>wip</p>
<h3 id="jsonp">JSONP</h3>
<ul>
<li>服务端</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/app/jsonp&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">responseData</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">data</span><span class="o">:</span> <span class="p">[{</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Brian&#39;</span> <span class="p">},</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Peter&#39;</span> <span class="p">}]</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">responseDataText</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">responseData</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;Content-Type&#39;</span><span class="p">,</span> <span class="s1">&#39;application/text&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="sb">`jsonpCallback(</span><span class="si">${</span><span class="nx">responseDataText</span><span class="si">}</span><span class="sb">)`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><ul>
<li>网页端</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kd">function</span> <span class="nx">jsonpCallback</span><span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;jsonp response&#39;</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 任何你想對 data 執行的動作
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">type</span><span class="o">=</span><span class="s2">&#34;text/javascript&#34;</span> <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;/app/jsonp&#34;</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/body&gt;</span>
</span></span></code></pre></div><ul>
<li>参考: <a href="https://medium.com/@brianwu1201/jsonp-with-simple-example-4711e2a07443"  target="_blank" rel="noopener" >用 JSONP 跨域 GET 簡易示範 ＆ 說明. | by Brian Hao-Yu Wu | Medium</a></li>
</ul>
<hr>
<h2 id="实际遇到过的问题">实际遇到过的问题</h2>
<ul>
<li>描述:
一个页面里用到了三次同一个s3生成的signed url，一次是thumbnail，另一次是preview，第三次是在image的onload后使用fetch直接去获取s3的图片,我发现这里会使用缓存，显示是（memory cache）但这样的话它似乎就丢失了cors信息，就会报错<code>blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.</code></li>
<li>代码如下</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"></code></pre></div><ul>
<li>解决方法: 将出现的两个<code>&lt;img&gt;</code>的crossOrigin都设为&quot;anonymous&quot;</li>
<li>有效的原因
<ol>
<li><strong>跨域图像加载的缓存行为</strong>：通过设置<code>crossOrigin=&quot;anonymous&quot;</code>，浏览器明确地按照跨域请求来处理这个图像，确保它从服务器获取时遵循 CORS 规范，并且缓存下来的资源携带正确的 CORS 信息。</li>
<li><strong>避免重复跨域请求错误</strong>：由于图像是通过<code>&lt;img&gt;</code>标签加载且设置了 crossOrigin，接下来的 fetch 请求可以从缓存中获取具有正确 CORS 头的信息，避免了 CORS 错误。</li>
</ol>
</li>
<li>参考
<ul>
<li><a href="https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#provisional-headers"  target="_blank" rel="noopener" >provisional-headers</a></li>
<li><a href="https://stackoverflow.com/questions/57136480/fetching-an-image-from-s3-bucket-is-not-working-because-of-cors"  target="_blank" rel="noopener" >javascript - Fetching an image from S3 bucket is not working because of CORS - Stack Overflow</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="参考-1">参考：</h2>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS"  target="_blank" rel="noopener" >跨源资源共享（CORS） - HTTP | MDN</a></li>
<li><a href="https://www.explainthis.io/zh-hans/swe/what-is-cors"  target="_blank" rel="noopener" >CORS 是什么? 为什么要有 CORS? ｜ExplainThis</a></li>
<li><a href="https://cloud.tencent.com/developer/article/2132990"  target="_blank" rel="noopener" >你是怎样解决跨域问题的?-面试必问-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://juejin.cn/post/7211687237020155961"  target="_blank" rel="noopener" >面试官：聊聊你知道的跨域解决方案 - 掘金</a></li>
<li><a href="https://juejin.cn/post/6844903767226351623"  target="_blank" rel="noopener" >九种跨域方式实现原理（完整版） - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>npm包——从出生到死亡</title>
      <link>https://ds63.eu.org/2024/npm_from_born_to_death/</link>
      <pubDate>Thu, 03 Oct 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/npm_from_born_to_death/</guid>
      <description>生与死</description>
      <content:encoded><![CDATA[<h2 id="npm包的结构">npm包的结构</h2>
<h3 id="packagejson"><code>package.json</code></h3>
<ul>
<li>版本
<ul>
<li>每个版本号都形如：<code>1.2.3</code>，有三部分组成，依次叫主版本号、次版本号、修订号；
<ol>
<li>当新版本无法兼容基于前一版本的代码时，则提高主版本号；</li>
<li>当新版本新增了功能和特性，但仍兼容前一版本的代码时，则提高次版本号；</li>
<li>当新版本仅仅修正了漏洞或者增强了效率，仍然兼容前一版本代码，则提高修订号；</li>
</ol>
</li>
<li><code>^</code> 兼容某个大版本。如：<code>^1.1.2</code> ，表示&gt;=1.1.2 &lt;2.0.0</li>
<li><code>~</code> 兼容某个次版本。如：<code>~1.1.2</code>，表示&gt;=1.1.2 &lt;1.2.0</li>
</ul>
</li>
<li>依赖
<ol>
<li>dependencies 生产依赖</li>
<li>devDependencies 开发依赖
<ul>
<li>只开发应用，不对外开源的话，包随意放在dependencies或devDependencies是不影响</li>
</ul>
</li>
<li>peerDependencies 同版本的依赖
<ul>
<li>例如<code>vue</code>和<code>vuex</code></li>
</ul>
</li>
<li>bundledDependencies 捆绑依赖
<ul>
<li>依赖中使用到的，但尚未发布</li>
</ul>
</li>
<li>optionalDependencies 可选依赖
<ul>
<li>非必要不使用</li>
</ul>
</li>
</ol>
</li>
<li><code>files</code>
<ul>
<li>用于描述<code>npm publish</code>后推送到 npm 服务器的文件列表</li>
</ul>
</li>
</ul>
<h3 id="package-lockjson"><code>package-lock.json</code></h3>
<ul>
<li>定义每个包的具体版本，以及包之间的层叠关系</li>
<li>需要提交到git吗?
<ul>
<li>回答: 分情况
<ul>
<li><strong>内部的应用项目</strong>: 可以保证项目中成员、运维部署成员或者是 CI 系统, 在执行 npm install后, 在不同的节点能得到完全一致的依赖安装的内容，减少bug的出现;无需计算依赖版本范围，大部分场景下能大大加速依赖安装时间</li>
<li><strong>给外部环境用的库</strong>: 在不使用 package-lock.json的情况下，就可以复用主项目已经安装的包，减少依赖重复和体积</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="src或lib"><code>src</code>或<code>lib</code></h3>
<ul>
<li>src/: 包含项目的源代码。在开发过程中，所有的 TypeScript、JavaScript、CSS 等文件会放在这里。</li>
<li>lib/:
<ul>
<li>如果有此文件夹，通常是编译后的代码，生成的文件可以是 CommonJS、ES6 模块等</li>
<li>针对模块化代码的编译输出，保持了一些开发者友好的结构和格式。</li>
</ul>
</li>
</ul>
<h3 id="dist或build"><code>dist</code>或<code>build</code></h3>
<ul>
<li>这个文件夹包含了打包或编译后的代码，通常是在使用构建工具（如 Webpack、Rollup 等）之后生成的。这个文件夹里的代码是实际发布到 npm 上的。</li>
<li>经过优化和打包处理后的生产代码</li>
</ul>
<hr>
<h2 id="npm-install背后的过程">npm install背后的过程</h2>
<ul>
<li>依赖树的构建
<ol>
<li>首先会检查下项目中是否有 package-lock.json 文件</li>
<li>存在 lock 文件的话，会判断 lock 文件和 package.json 中使用的依赖版本是否一致</li>
<li>如果一致的话就使用 lock 中的信息，反之就会使用 package.json 中的信息</li>
<li>如果没有 lock 文件的话，就会直接使用 package.json 中的信息生成依赖树。</li>
</ol>
</li>
<li>参考
<ul>
<li><a href="https://juejin.cn/post/6844904022080667661"  target="_blank" rel="noopener" >前端工程化 - 剖析npm的包管理机制现如今，前端开发的同学已经离不开 npm 这个包管理工具，其优秀的包版本管理机制承 - 掘金</a></li>
</ul>
</li>
</ul>
<h2 id="修改">修改</h2>
<h3 id="方法一">方法一</h3>
<ul>
<li>直接修改对应模块的lib代码</li>
<li>缺点:
<ul>
<li>lib中都是编译过后的代码,阅读起来不够直观-</li>
</ul>
</li>
<li>进阶: 参见<a href="https://ds63.eu.org/2024/the-use-of-patch-package/"  target="_blank" rel="noopener" >patch-package使用 | EuDs&rsquo;s Blog</a></li>
</ul>
<h3 id="方法二">方法二</h3>
<ul>
<li>拷贝源文件后进行修改,再引用</li>
<li>缺点:
<ul>
<li>代码臃肿</li>
</ul>
</li>
</ul>
<h3 id="方法三">方法三</h3>
<ul>
<li>fork一份，自己维护</li>
<li>流程:
<blockquote>
<p>还是以elemnt-ui为例,可以在官方的开源代码中fork到自己的仓库中方便维护,然后clone到本地进行相关源代码的修改
使用 npm run dist即可打出对应lib
进行本地软连接, 在本地elemnt-ui项目中使用 npm link 或者 yarn link,
在需要的项目中使用npm linkelemnt-ui,此时就可以进行相关调试
在本地element项目中使用npm login npm publish 进行发包
在需要的项目中引入发布的包,不再使用elemnt官方包,修改packjson中的包版本之后npm unlink elemnt-ui npm install重新安装依赖</p>
</blockquote>
</li>
<li>缺陷
<ul>
<li>如果你修改的是个底层包，也就是说并不是你的应用代码中直接引用的，而是你引用的npm包A所依赖的，甚至可能同时被包B依赖的，这时就比较尴尬了，你不可能再去修改A和B的源码，那就太不值当了。</li>
</ul>
</li>
<li>进阶: 使用pnpm的别名(aliases)
<ul>
<li><code>pnpm add lodash@npm:awesome-lodash</code>: 发布了一个名为awesome-lodash的新包，并使用lodash作为别名来安装它</li>
</ul>
</li>
</ul>
<hr>
<h2 id="调试">调试</h2>
<hr>
<h2 id="发布">发布</h2>
<p>wip</p>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://juejin.cn/post/7137110113277444126"  target="_blank" rel="noopener" >详解package.json和package-lock.json - 掘金</a></li>
<li><a href="https://czkm.github.io/2023/11/13/%E5%BC%80%E6%BA%90%E7%BB%84%E4%BB%B6%E7%9A%84%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BF%AE%E6%94%B9%E5%8F%8A%E4%BC%98%E5%8C%96%E8%BF%87%E7%A8%8B%E8%AE%B0%E5%BD%95/"  target="_blank" rel="noopener" >开源组件的定制化修改及优化过程记录 - 橙汁坤的博客 | czkm Blog</a></li>
<li><a href="https://www.npmjs.cn/cli/link/"  target="_blank" rel="noopener" >link | npm中文文档 | npm中文网</a></li>
<li><a href="https://mengshang918.github.io/blog/docs/%E5%B7%A5%E7%A8%8B%E5%8C%96/%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/5465da474f6f60291fb1a253cce06f5f/"  target="_blank" rel="noopener" >如何调试node_modules中的包 | 梦殇918</a></li>
<li>[<a href="https://www.bilibili.com/read/cv16917711/"  target="_blank" rel="noopener" >Mentor让我调试npm包 我偷偷搬了一下午代码。。。 - 哔哩哔哩</a>](<a href="https://www.bilibili.com/read/cv16917711/"  target="_blank" rel="noopener" >https://www.bilibili.com/read/cv16917711/</a>)</li>
<li><a href="https://stackoverflow.com/questions/6341088/how-can-i-debug-node-modules"  target="_blank" rel="noopener" >debugging - How can I debug node modules? - Stack Overflow</a></li>
<li><a href="https://juejin.cn/post/7033400734746066957"  target="_blank" rel="noopener" >【一库】yalc: 可能是最好的前端link调试方案（已经非常谦虚了） - 掘金</a></li>
<li><a href="https://juejin.cn/post/7275590449736597544?from=search-suggest"  target="_blank" rel="noopener" >爬坑node_modules经验分享 - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>初识ssr</title>
      <link>https://ds63.eu.org/2024/the_first_take_of_ssr/</link>
      <pubDate>Wed, 02 Oct 2024 23:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/the_first_take_of_ssr/</guid>
      <description>你有多爱它，就有多恨它</description>
      <content:encoded><![CDATA[<h2 id="ssr和ssg的区别">ssr和ssg的区别</h2>
<h3 id="ssrserver-side-rendering">SSR（Server-Side Rendering）</h3>
<ul>
<li><strong>运行时生成页面</strong>：在用户请求页面时，服务器会动态地生成 HTML 文件并将其发送给客户端。内容在每次请求时<strong>都会</strong>在服务器端生成，因此适合需要频繁更新数据的页面。</li>
<li>过程:
<ol>
<li>用户请求页面</li>
<li>服务器端渲染：
<ul>
<li>服务器会从数据库或 API 获取需要的数据。</li>
<li>使用 JavaScript 运行框架（如 React、Vue）的组件，在服务器端生成 HTML 页面，并将获取的数据填充到模板中。</li>
</ul>
</li>
<li>返回 HTML 页面：服务器将渲染完成的 HTML 页面发送回客户端。页面加载后，用户可以立即看到内容，而无需等待所有 JavaScript 加载完成。</li>
<li>客户端水合（Hydration）：
<ul>
<li>在客户端，浏览器会下载并执行页面相关的 JavaScript。</li>
<li>前端框架接管页面，将其转变为可交互的应用，类似单页应用（SPA）的行为。</li>
</ul>
</li>
<li>进一步交互：当用户进行进一步的操作（如点击、导航等），客户端代码可以通过 API 进行数据请求和局部更新，而无需刷新整个页面。</li>
</ol>
</li>
</ul>
<h3 id="ssgstatic-site-generation">SSG（Static Site Generation）</h3>
<ul>
<li><strong>构建时生成页面</strong>：在<strong>构建阶段</strong>提前生成静态 HTML 文件，并将这些文件直接部署在 CDN 或服务器上，所有用户访问时都获取相同的静态页面。</li>
<li><strong>优点</strong>：
<ul>
<li><strong>性能极佳</strong>：静态文件可以通过 CDN 高效分发，用户的页面加载速度非常快。</li>
<li><strong>稳定性高</strong>：不需要实时依赖服务器，即使服务器出现问题，静态页面依然可以访问。</li>
<li><strong>SEO 友好</strong>：和 SSR 类似，静态 HTML 可以被搜索引擎很好地索引。</li>
</ul>
</li>
<li><strong>缺点</strong>：
<ul>
<li><strong>实时性差</strong>：由于内容在构建时生成，页面的数据更新不及时，适合更新频率较低的内容（如博客、文档等）。</li>
<li><strong>构建时间长</strong>：对于大型网站，构建所有静态页面可能需要较长的时间。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="优势">优势</h2>
<ol>
<li>SEO和SMO(Social Media Optimization)</li>
<li>First meaningful paint(首屏渲染)</li>
<li>Graceful degradation（支持不支持或没有开启javascript功能浏览器）</li>
<li>实时性强：适合频繁更新内容的应用（如社交媒体、新闻网站等），因为每次请求都会生成最新的数据。</li>
</ol>
<hr>
<h2 id="劣势">劣势</h2>
<ul>
<li>额外的开发和维护成本，需要额外考虑以下几点
<ol>
<li>有没有全局mutable data，可能导致内存泄露</li>
<li>有没有在SSR可能执行的代码中使用server没有而client端存在的api</li>
<li>第三方库是否需要在server端重新配置</li>
</ol>
</li>
<li>服务端的开发</li>
<li>更多的服务端负载</li>
</ul>
<hr>
<h2 id="为什么会难开发">为什么会难开发</h2>
<ul>
<li>执行环境不同
<ul>
<li>BOM(window…), DOM(document…), Ajax(XMLHttp​Request, fetch…), Web Workers…等属于浏览器环境的对象在node server环境下并不work</li>
</ul>
</li>
<li>“执行上下文”不同</li>
</ul>
<hr>
<h2 id="做了ssr但首屏渲染时间还是很长">做了ssr，但首屏渲染时间还是很长</h2>
<ol>
<li>有没有做Time to the First Byte，如果渲染该页面依赖后端耗时的计算和请求时间，那么可以考虑使用Streaming Server-Side Rendering</li>
<li>有没有阻塞性请求、有没有重定向请求</li>
<li>服务有没有靠近用户，由于SSR需要动态服务，不能CDN部署，可能在一些国家或地区的政策影响下，服务只能部署在A地，但用户却在B地</li>
</ol>
<hr>
<h2 id="优化方案">优化方案</h2>
<ol>
<li>Streaming SSR（流式渲染）：
<ul>
<li>通过流式传输内容来加速首屏渲染，服务器生成的 HTML 可以一部分一部分地传输给客户端，缩短等待时间。</li>
<li>React 18 中引入了 Suspense 和 React.lazy() 支持流式渲染。</li>
</ul>
</li>
<li>Partial Hydration（部分水合）：
<ul>
<li>不是一次性水合整个页面，而是逐步水合页面上的不同组件，减少初始 JavaScript 体积，加快交互速度。</li>
</ul>
</li>
<li>预渲染与动态渲染结合：
<ul>
<li>可以为某些页面提前生成静态 HTML 文件（SSG），而为需要实时数据的页面使用 SSR。</li>
</ul>
</li>
</ol>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://chi.miantiao.me/posts/vite-ssr-docker-image-minimal-build/"  target="_blank" rel="noopener" >Vite SSR 项目 Docker 镜像最小化打包方案 | 面条实验室</a></li>
<li><a href="https://medium.com/@keshidong.dev/%E5%85%B3%E4%BA%8Espa%E7%9A%84seo%E4%BC%98%E5%8C%96%E6%96%B9%E6%A1%88-2639a63361ad"  target="_blank" rel="noopener" >关于SPA的SEO解决方案. 为什么SPA需要SEO优化 | by shidong ke | Medium</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>性能优化二三事</title>
      <link>https://ds63.eu.org/2024/points_of_performance_optimization/</link>
      <pubDate>Mon, 30 Sep 2024 23:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/points_of_performance_optimization/</guid>
      <description>更快，更快，更快！</description>
      <content:encoded><![CDATA[<h2 id="windowperformance">window.performance</h2>
<h3 id="memory">memory</h3>
<ol>
<li>jsHeapSizeLimit (表示当前页面最多可以获得的 JavaScript 堆大小)</li>
<li>totalJSHeapSize (表示当前页面已经分配的 JavaScript 堆大小)</li>
<li>usedJSHeapSize (表示当前页面 JavaScript 已经使用的堆大小)</li>
</ol>
<h3 id="navigation">navigation</h3>
<ol>
<li>redirectCount，重定向的数量，经过多少次重定向进入这个页面</li>
<li>type，进入页面的方式
<ul>
<li>0，正常进入非刷新，非重定向</li>
<li>1，通过刷新的方式进入</li>
<li>2，通过前进回退按钮进入</li>
<li>255，非是上述情况</li>
</ul>
</li>
</ol>
<h3 id="performancenavigationtiming">PerformanceNavigationTiming</h3>
<ul>
<li>
  <img loading="lazy" src="https://mdn.github.io/shared-assets/images/diagrams/api/performance/timestamp-diagram.svg" alt="PerformanceNavigationTiming"  /></li>
<li>顺序
<ol>
<li>页面卸载部分
<ul>
<li>卸载：navigationStart、unloadEventStart、unloadEventEnd</li>
</ul>
</li>
<li>网络部分
<ul>
<li>跳转：redirectStart、redirectEnd</li>
<li>请求文档：fetchStart</li>
<li>DNS查询：domainLookupStart、domainLookupEnd</li>
<li>连接建立：connectStart、connectEnd</li>
<li>请求：requestStart、responseStart、responseEnd</li>
</ul>
</li>
<li>页面解析部分
<ul>
<li>解析dom：domLoading、domInteractive</li>
<li>资源加载，dom渲染：domContentLoadedEventStart、domContentLoadedEventEnd、domComplete</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming"  target="_blank" rel="noopener" >PerformanceNavigationTiming - Web APIs | MDN</a></li>
<li><a href="https://juejin.cn/post/7223280402475089978"  target="_blank" rel="noopener" >来来来，前端性能监控，带你拿到正确的性能指标作为前端开发，我们有必要关注我们各个客户端的性能指标，比如白屏时间，最早可交 - 掘金</a></li>
</ul>
<hr>
<h2 id="指标">指标</h2>
<h3 id="首次内容绘制first-contentful-paint">首次内容绘制(First Contentful Paint)</h3>
<ul>
<li>定义
<ul>
<li>浏览器从响应用户输入网络地址，到浏览器呈现第一段 DOM 内容所需的时间</li>
<li>首屏时间 = 首屏内容渲染结束时间点 - 开始请求的时间点</li>
<li>performance.getEntries(&lsquo;paint&rsquo;).filter(entry =&gt; entry.name == &lsquo;first-contentful-paint&rsquo;)[0].startTime;</li>
</ul>
</li>
<li>优化
<ol>
<li>缩短距离: cdn</li>
<li>减少首次加载需要请求的内容
<ul>
<li>动态加载: 使用 import() 或 React.lazy() 在路由或组件级别进行模块拆分</li>
<li>懒加载: <code>intersectionObserver</code></li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="最大内容渲染时间lcp-largest-contentful-paint">最大内容渲染时间(LCP Largest Contentful Paint)</h3>
<ul>
<li>定义
<ul>
<li>指代页面中最大的内容完成绘制的时间。</li>
</ul>
</li>
</ul>
<h3 id="ttfb">TTFB</h3>
<ul>
<li>定义
<ul>
<li>指代从资源的请求到响应第一个字节的时间跨度。</li>
<li>responseStart - navigationStart</li>
</ul>
</li>
<li>影响因素
<ul>
<li>重定向时延，DNS查询时延，链接建立延迟，请求响应时延</li>
</ul>
</li>
</ul>
<h3 id="可交互时间time-to-interactive">可交互时间(Time to Interactive)</h3>
<ul>
<li>定义
<ul>
<li>页面完全交互所需的时间</li>
</ul>
</li>
<li>优化
<ul>
<li>把长任务拆分为较小的任务（使用 requestAnimationFrame 或 requestIdleCallback），或者选择在主线程之外（如Web Workers）运行 JavaScript</li>
</ul>
</li>
</ul>
<h3 id="dcl-domcontentloaded">DCL (DOMContentLoaded)</h3>
<ul>
<li>定义
<ul>
<li>当HTML 文档被完全加载和解析完成之后，DOMContentLoaded 事件被触发，无需等待样式，图像和子框架的完成加载的时间。</li>
</ul>
</li>
<li>计算</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">addeventListener</span><span class="p">(</span><span class="s1">&#39;DOMContentLoaded&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span><span class="k">new</span> <span class="nb">Date</span><span class="p">()</span> <span class="o">-</span> <span class="nb">window</span><span class="p">.</span><span class="nx">performanceObser</span><span class="p">.</span><span class="nx">timing</span><span class="p">.</span><span class="nx">navigationStart</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="kc">false</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="total-blocking-time">(Total Blocking Time)</h3>
<h3 id="cumulative-layout-shift">(Cumulative Layout Shift)</h3>
<h3 id="白屏时间">白屏时间</h3>
<ul>
<li>从用户开始请求页面时开始计算到开始显示内容结束，中间过程包括DNS查询、建立TCP链接、发送首个HTTP请求、返回HTML文档、HTML文档head解析完毕。</li>
<li>计算:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>白屏时间计算-常规方法<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">window</span><span class="p">.</span><span class="nx">pageStartTime</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/ionicons/2.0.1/css/ionicons.min.css~tplv-t2oaga2asx-image.image&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/asset/fw-icon/1.0.9/iconfont.css~tplv-t2oaga2asx-image.image&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">window</span><span class="p">.</span><span class="nx">firstPaint</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`白屏时间：</span><span class="si">${</span><span class="nb">window</span><span class="p">.</span><span class="nx">firstPaint</span> <span class="o">-</span> <span class="nb">window</span><span class="p">.</span><span class="nx">pageStartTime</span><span class="si">}</span><span class="sb">`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>这是常规计算白屏时间的示例页面<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>白屏时间 = window.firstPaint - window.pageStartTime</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7113803250037424158"  target="_blank" rel="noopener" >看懂 Lighthouse 中 Performance 核心指标简介 </a></li>
<li><a href="https://juejin.cn/post/6916527678807867400"  target="_blank" rel="noopener" >前端性能指标：白屏和首屏时间的计算 - 掘金</a></li>
<li><a href="https://web.dev/articles/defining-core-web-vitals-thresholds?hl=en"  target="_blank" rel="noopener" >How the Core Web Vitals metrics thresholds were defined  |  Articles  |  web.dev</a></li>
</ul>
<hr>
<h2 id="首屏优化">首屏优化</h2>
<ul>
<li>参考
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=Mzk0OTUwMzI0MQ==&amp;mid=2247484027&amp;idx=1&amp;sn=b5511e51f68617032f8d87ee7b4dd38e&amp;chksm=c356161df4219f0bb6666b7188cb02c0421bbfaeff6b6195fbc94fa996fb5affbfc8eea886d8"  target="_blank" rel="noopener" >[前端进阶] 首屏优化知识梳理</a></li>
<li><a href="https://juejin.cn/post/7337631207025639463"  target="_blank" rel="noopener" >首屏加载时间优化的几种解决方案🙋🏿🙋🏿🙋🏿 - 掘金</a></li>
<li><a href="https://alienzhou.github.io/fe-performance-journey/5-subresources/image.html#_1-%E4%BC%98%E5%8C%96%E8%AF%B7%E6%B1%82%E6%95%B0"  target="_blank" rel="noopener" >图片 | 前端性能优化</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="滚屏性能优化">滚屏性能优化</h2>
<ul>
<li>将<code>touchstart</code>和<code>touchmove</code>事件的<code>passive</code>选项设置为ture
<ul>
<li>原理: <code>touchstart</code>和<code>touchmove</code>是<code>cancelable</code>的。事件处理程序中可能会调用<code>preventDefault()</code>，所以需要等待事件处理程序结束再滚动。</li>
<li>注: 大部分浏览器（Safari 和 Internet Explorer 除外）将文档级节点 Window、Document 和 Document.body 上的 wheel、mousewheel、touchstart 和 touchmove 事件的 passive 默认值更改为 true。</li>
</ul>
</li>
<li>参考:
<ul>
<li><a href="https://www.cnblogs.com/mengfangui/p/11322590.html"  target="_blank" rel="noopener" >滚动事件优化 passive - 孟繁贵 - 博客园</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="react性能优化">React性能优化</h2>
<ol>
<li>map循环展示添加key</li>
<li>路由懒加载</li>
<li>第三方依赖按需引入</li>
<li>使用memo或者pureComponent避免不必要的渲染</li>
<li>合理使用useMemo、memo、useCallback</li>
</ol>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/6935584878071119885"  target="_blank" rel="noopener" >React 性能优化 | 包括原理、技巧、Demo、工具使用⁣React 的工作流 - 掘金</a></li>
<li><a href="https://blogweb.cn/article/2213713866013#heading-48"  target="_blank" rel="noopener" >当面试官问我前端可以做的性能优化有哪些-网络日志</a></li>
<li><a href="https://weekly.shanyue.tech/week-32/"  target="_blank" rel="noopener" >React 应用中的性能优化 | 前端开发者技术周刊</a></li>
<li><a href="https://fe.azhubaby.com/React/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.html"  target="_blank" rel="noopener" >React 性能优化 | 五年前端三年面试</a></li>
<li><a href="https://mp.weixin.qq.com/s/hJrOViqtEpWc2g1rwMAxwg"  target="_blank" rel="noopener" >React 性能优化十大总结</a></li>
</ul>
<hr>
<h2 id="懒加载与按需加载">懒加载与按需加载</h2>
<h3 id="懒加载">懒加载</h3>
<ul>
<li>概念: 可以按照路由对产物进行分割</li>
<li>实现
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">lazy</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">MarkdownPreview</span> <span class="o">=</span> <span class="nx">lazy</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s1">&#39;./MarkdownPreview.js&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">Suspense</span> <span class="nx">fallback</span><span class="o">=</span><span class="p">{</span><span class="o">&lt;</span><span class="nx">Loading</span> <span class="o">/&gt;</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">h2</span><span class="o">&gt;</span><span class="nx">Preview</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">MarkdownPreview</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/Suspense&gt;</span>
</span></span></code></pre></div></li>
<li>代码二次分割:
<ul>
<li>可以将那些在非首页才用到的依赖是不是可以单独分割为一个chunk，这样的话可以进一步减少<code>index-[hash].js</code>的体积</li>
<li>需要配合路由懒加载才能达到效果，否则即使代码进行了分割，但加载首屏还是会因为路由提前注册的原因，使得浏览器加载所有资源。</li>
</ul>
</li>
<li>缺点:
<ul>
<li>优化也有成本，比如文本中虽然通过代码分割+路由懒加载减少了首屏资源体积，但随之也带来了资源请求数增加的问题，对浏览器的并发请求带来了压力。</li>
</ul>
</li>
</ul>
<h3 id="按需加载">按需加载</h3>
<ul>
<li>按需加载是为了减少依赖产物体积过大的问题，典型的如 lodash、echarts、arco-design，整个包存在很多方法、组件，而在项目实际使用到的其实只有一部分。在构建时进行按需加载，可以有效减小最终产物体积。</li>
<li>示例:
<ul>
<li><a href="https://github.com/mattiasw/ExifReader?tab=readme-ov-file#configure-a-custom-build"  target="_blank" rel="noopener" >mattiasw/ExifReader: A JavaScript Exif info parser.</a>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl">  <span class="s2">&#34;exifreader&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;include&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;webp&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;exclude&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;xmp&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
</li>
</ul>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7268183236738793513"  target="_blank" rel="noopener" >React+Vite技术栈下首屏资源优化前言 最近小组做的H5应用需要通过iframe嵌入到第三方站点里，为了提高首屏速 - 掘金</a></li>
<li><a href="https://zh-hans.react.dev/reference/react/lazy"  target="_blank" rel="noopener" >lazy – React 中文文档</a></li>
</ul>
<hr>
<h2 id="虚拟滚动">虚拟滚动</h2>
<h3 id="定义">定义</h3>
<ul>
<li>浏览器视口固定，内容响应用户鼠标滚动</li>
</ul>
<h3 id="使用场景">使用场景</h3>
<ul>
<li>炫酷的滚动交互</li>
<li>无限循环列表滚动</li>
<li>关注控制滚动体验（灵敏度、惯性等）</li>
</ul>
<h3 id="如何优化解决虚拟滚动中滚速过快情况下的白屏问题">如何优化解决虚拟滚动中滚速过快情况下的白屏问题</h3>
<p>wip</p>
<h3 id="参考-4">参考</h3>
<ul>
<li><a href="https://kind-armchair-5a5.notion.site/2689c93449674729973f2e835766d294"  target="_blank" rel="noopener" >虚拟滚动</a></li>
<li><a href="https://juejin.cn/post/6844904183582162957"  target="_blank" rel="noopener" >新手也能看懂的虚拟滚动实现 - 掘金</a></li>
</ul>
<hr>
<h2 id="防抖和节流">防抖和节流</h2>
<h3 id="防抖">防抖</h3>
<ul>
<li>在触发频率高的事件中,执行耗费性能的操作,连续操作后只有最后一次生效
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">//自己实现debounce
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">debounce</span><span class="p">(</span><span class="nx">func</span><span class="p">,</span><span class="nx">wait</span><span class="o">=</span><span class="mi">0</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">timeId</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span> <span class="c1">//为什么不在内部声明id?因为我如果在内部声明,每一次触发事件就会有一个新的变量产生
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">return</span> <span class="kd">function</span><span class="p">(...</span><span class="nx">args</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">self</span><span class="o">=</span><span class="k">this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">timeId</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">clearTimeout</span><span class="p">(</span><span class="nx">timeId</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">timeId</span><span class="o">=</span><span class="nx">setTimeout</span><span class="p">(()=&gt;{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span><span class="nx">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span><span class="nx">wait</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="节流">节流</h3>
<ul>
<li>在触发频率高的事件中,执行耗费性能操作,连续触发,单位时间内只有一次生效
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">throttle</span><span class="p">(</span><span class="nx">func</span><span class="p">,</span><span class="nx">wait</span><span class="o">=</span><span class="mi">0</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">timeId</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">function</span><span class="p">(...</span><span class="nx">args</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">self</span><span class="o">=</span><span class="k">this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">timeId</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span><span class="nx">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">timeId</span> <span class="o">=</span> <span class="nx">setTimeout</span><span class="p">(()=&gt;{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">timeId</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span><span class="nx">delay</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="参考-5">参考</h3>
<ul>
<li><a href="https://kettanaito.com/blog/debounce-vs-throttle"  target="_blank" rel="noopener" >Debounce vs Throttle: Definitive Visual Guide - kettanaito.com</a></li>
<li><a href="https://www.npmjs.com/package/throttle-debounce?activeTab=code"  target="_blank" rel="noopener" >throttle-debounce - npm</a></li>
</ul>
<hr>
<h2 id="回流与重绘">回流与重绘</h2>
<h3 id="浏览器渲染过程">浏览器渲染过程</h3>
<ol>
<li>解析 HTML 和样式计算 (parsing and style calculation)</li>
<li>布局 (Layout)</li>
<li>绘制 (paint)</li>
<li>合成 (compositing)</li>
</ol>
<h3 id="回流">回流</h3>
<ul>
<li>reflow</li>
<li>网页渲染引擎根据元素的<strong>尺寸、位置和显示属性</strong>来重新计算页面的排版和布局，是网页渲染过程中的一个重要步骤。</li>
<li>当一个元素的长与宽改变，可能会影响到画面中其他元素的编排，所以每当有一个元素的布局改变，浏览器的 CPU 需要重新计算整个页面中不同元素的长宽、间距等。在计算的期间，会没办法处理其他任务 (例如使用者在点击按钮，可能会要等一阵子才有回应，因为浏览器无暇处理)。</li>
</ul>
<h3 id="重绘">重绘</h3>
<ul>
<li>repaint</li>
<li>指网页渲染引擎根据<strong>显示属性</strong> (如颜色、文字大小等) 重新绘制页面元素，不影响元素的位置和尺寸</li>
<li>不会影响页面布局，但是也会影响页面的性能</li>
</ul>
<h2 id="减少回流和重绘">减少回流和重绘</h2>
<ol>
<li>移动调整元素时，使用<code>transform</code></li>
<li>使用<code>opacity</code>来改变元素的能见度</li>
<li>避免频繁用 JavaScript 操作 DOM 节点</li>
</ol>
<h3 id="参考-6">参考</h3>
<ul>
<li><a href="https://www.explainthis.io/zh-hans/swe/repaint-and-reflow"  target="_blank" rel="noopener" >回流 (Reflow) 和重绘 (Repaint) 是什么？以及如何优化？｜ExplainThis</a></li>
</ul>
<hr>
<h2 id="内存泄漏">内存泄漏</h2>
<h3 id="定义-1">定义</h3>
<ul>
<li>内存泄漏可以定义为程序不再使用或不需要的一块内存，但是由于某种原因没有被释放仍然被不必要的占有。</li>
</ul>
<h3 id="垃圾回收算法">垃圾回收算法</h3>
<ul>
<li>引用计数: 如果没有引用指向该对象（零引用），对象将被垃圾回收机制回收。
<ul>
<li>缺点: 循环引用</li>
</ul>
</li>
<li>标记清除
<ul>
<li>过程
<ol>
<li>垃圾回收器创建了一个“roots”列表。Roots通常是代码中全局变量的引用。JavaScript中，“window”对象是一个全局变量，被当作root。window对象总是存在，因此垃圾回收器可以检查它和它的所有子对象是否存在（即不是垃圾）；</li>
<li>所有的 roots被检查和标记为激活（即不是垃圾）。所有的子对象也被递归地检查。从root开始的所有对象如果是可达的，它就不被当作垃圾。</li>
<li>所有未被标记的内存会被当做垃圾，收集器现在可以释放内存，归还给操作系统了。</li>
</ol>
</li>
<li>缺点: 算法运行时程序执行被暂停。</li>
</ul>
</li>
</ul>
<h3 id="常见的内存泄漏">常见的内存泄漏</h3>
<ol>
<li>全局变量</li>
<li>被遗忘的定时器和回调函数</li>
<li>DOM引用</li>
<li>错误使用的闭包</li>
</ol>
<h3 id="排查">排查</h3>
<ul>
<li>启用<code>use strict</code></li>
<li>浏览器开发者工具，内存选项</li>
</ul>
<h3 id="参考-7">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/6844903917986267143"  target="_blank" rel="noopener" >彻底掌握js内存泄漏以及如何避免前言：内存泄漏写任何语言都必须得注意的问题，我司技术老大日常吐槽:以前做游戏的改内存泄漏 - 掘金</a></li>
<li><a href="https://github.com/pro-collection/interview-question/issues/76"  target="_blank" rel="noopener" >JS 内存泄露问题该如何排查？ · Issue #76 · pro-collection/interview-question</a></li>
<li><a href="https://czkm.github.io/2022/06/13/JS%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E4%B8%8E%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/"  target="_blank" rel="noopener" >JS的垃圾回收与内存泄漏 - 橙汁坤的博客 | czkm Blog</a></li>
</ul>
<h2 id="前端监控系统">前端监控系统</h2>
<p>wip</p>
<h3 id="白屏检测">白屏检测</h3>
<ul>
<li><a href="https://juejin.cn/post/7176206226903007292"  target="_blank" rel="noopener" >前端白屏的检测方案，让你知道自己的页面白了页面白屏，绝对是让前端开发者最为胆寒的事情，特别是随着 SPA 项目的盛行，前 - 掘金</a></li>
</ul>
<h3 id="参考-8">参考</h3>
<ul>
<li><a href="https://cloud.tencent.com/developer/article/1983779"  target="_blank" rel="noopener" >目前为止整理最全的前端监控体系搭建篇(长文预警)-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://sentry.io/welcome/"  target="_blank" rel="noopener" >Application Performance Monitoring &amp; Error Tracking Software | Sentry</a></li>
<li><a href="https://godbasin.github.io/2024/01/21/front-end-performance-no-response-solution/"  target="_blank" rel="noopener" >前端性能优化&ndash;卡顿的监控和定位 | Here. There.</a></li>
<li><a href="https://juejin.cn/post/7247770501324996664"  target="_blank" rel="noopener" >不可不知的前端工程化—— 埋点&amp;监控 - 掘金</a></li>
</ul>
<hr>
<h2 id="场景题">场景题</h2>
<h3 id="线上的某个页面加载慢如何优化">线上的某个页面加载慢，如何优化</h3>
<p>wip</p>
<h3 id="场景题-针对大批量的数据的优化">场景题: 针对大批量的数据的优化</h3>
<ul>
<li>问题: 如果data数据很大，可能导致内存溢出和Minor GC阻塞渲染进程的问题。垃圾回收过程会占用主线程资源，导致渲染进程被阻塞。</li>
<li>思想:
<ul>
<li>将数据分成多个较小的批次进行处理，而不是一次性处理整个数据集。这可以通过使用<code>setTimeout</code>或 <code>requestAnimationFrame</code>来分批处理数据。循环处理每个批次的数据，并在处理完一个批次后延迟一小段时间处理下一个批次.比如可以将数据分成每批100条，每批处理完后延迟10毫秒，以避免阻塞主线程。</li>
<li>processBatch函数用于处理一批数据。它会根据当前的currentIndex从keys数组中选择一批数据进行处理，并将结果存入arr数组。然后，currentIndex增加，检查是否还有剩余数据需要处理。如果还有剩余数据，则通过requestAnimationFrame调度下一个异步任务来处理下一批数据。如果所有数据处理完成，则进行后续操作。</li>
<li>使用递归调用和requestAnimationFrame可以确保数据处理过程在异步任务中进行,在每一帧中调用 processBatch 函数，给渲染进程更多的时间进行渲染</li>
<li>一旦处理完所有数据，调用 finishProcessing 函数,并进行视图更新</li>
</ul>
</li>
<li>代码:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">processTreeData</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">keys</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">batchSize</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span> <span class="c1">// 每批处理的数据量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">let</span> <span class="nx">currentIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">processBatch</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=</span> <span class="o">&gt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">batchKeys</span> <span class="o">=</span> <span class="nx">keys</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">currentIndex</span><span class="p">,</span> <span class="nx">currentIndex</span> <span class="o">+</span> <span class="nx">batchSize</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">batchItems</span> <span class="o">=</span> <span class="nx">batchKeys</span><span class="p">.</span><span class="nx">flatMap</span><span class="p">((</span><span class="nx">key</span><span class="p">)</span> <span class="o">=</span> <span class="o">&gt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kr">const</span> <span class="nx">tableData</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="kr">const</span> <span class="nx">parentId</span> <span class="o">=</span> <span class="sb">`$ {key}. * `</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="kr">const</span> <span class="nx">childItems</span> <span class="o">=</span> <span class="nx">tableData</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">item</span><span class="p">)</span> <span class="o">=</span> <span class="o">&gt;</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">               <span class="nx">id</span><span class="o">:</span> <span class="sb">`$ {key}.$ {item}`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">               <span class="nx">label</span><span class="o">:</span> <span class="sb">`$ {key}.$ {item}`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">               <span class="nx">parent</span><span class="o">:</span> <span class="nx">parentId</span>
</span></span><span class="line"><span class="cl">            <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">id</span><span class="o">:</span> <span class="nx">parentId</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">label</span><span class="o">:</span> <span class="nx">key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">children</span><span class="o">:</span> <span class="nx">childItems</span>
</span></span><span class="line"><span class="cl">            <span class="p">}];</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">arr</span><span class="p">.</span><span class="nx">push</span><span class="p">(...</span><span class="nx">batchItems</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">currentIndex</span> <span class="o">+=</span> <span class="nx">batchSize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">currentIndex</span> <span class="o">&lt;</span> <span class="nx">keys</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">requestAnimationFrame</span><span class="p">(</span><span class="nx">processBatch</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">finishProcessing</span><span class="p">(</span><span class="nx">arr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nx">arr</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="nx">requestAnimationFrame</span><span class="p">(</span><span class="nx">processBatch</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">finishProcessing</span><span class="p">(</span><span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="c1">//finish operate
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">},</span>
</span></span></code></pre></div><ul>
<li>好处:
<ul>
<li>如果一项任务执行花费的时间过长，浏览器将无法执行其他任务，例如处理用户事件。这样就会让用户觉得卡顿</li>
<li>可以显示进度指示</li>
</ul>
</li>
<li>思路二:
<ul>
<li>对于不应该阻塞事件循环的耗时长的繁重计算任务，我们可以使用 Web Workers。</li>
<li>Web Workers 可以与主线程交换消息，但是它们具有自己的变量和事件循环。</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://czkm.github.io/2023/11/13/%E5%BC%80%E6%BA%90%E7%BB%84%E4%BB%B6%E7%9A%84%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BF%AE%E6%94%B9%E5%8F%8A%E4%BC%98%E5%8C%96%E8%BF%87%E7%A8%8B%E8%AE%B0%E5%BD%95/"  target="_blank" rel="noopener" >开源组件的定制化修改及优化过程记录 - 橙汁坤的博客 | czkm Blog</a></li>
</ul>
</li>
</ul>
<h3 id="项目中的分片上传如何实现的">项目中的分片上传，如何实现的？</h3>
<p>wip</p>
<h3 id="怎么做到组件的按需引入">怎么做到组件的按需引入</h3>
<ul>
<li>treeshaking</li>
</ul>
<h3 id="优化图片加载闪烁">优化图片加载闪烁</h3>
<ul>
<li>参考: <a href="https://www.shymean.com/article/%E5%89%8D%E7%AB%AF%E4%BD%93%E9%AA%8C%E4%BC%98%E5%8C%96%E4%B9%8B%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E9%97%AA%E7%83%81"  target="_blank" rel="noopener" >前端体验优化之图片加载闪烁 | ShyMean</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之原型</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_protype/</link>
      <pubDate>Mon, 30 Sep 2024 22:56:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_protype/</guid>
      <description>自己学习过程中整理的关于JavaScript中原型的知识点</description>
      <content:encoded><![CDATA[<h2 id="proto">proto</h2>
<h3 id="概念">概念</h3>
<ul>
<li><code>__proto__</code> 是<strong>每个JavaScript对象都具有</strong>的一个属性，它指向该对象的原型（prototype）。原型链的实现就是通过 <code>__proto__</code> 实现的。</li>
</ul>
<h3 id="作用">作用</h3>
<ul>
<li>当访问对象的属性或方法时，如果对象本身没有定义，JavaScript 就会沿着原型链（通过 <code>__proto__</code>）向上查找，直到找到匹配的属性或方法或者到达原型链的顶端（Object.prototype）为止。</li>
</ul>
<h3 id="慎用">慎用</h3>
<ul>
<li><code>__proto__</code> 是<code>[[Prototype]]</code>的因历史原因而留下来的 getter/setter</li>
<li>尽管 <code>__proto__</code> 在历史上被广泛使用，但它在 ECMAScript 6 中被标记为过时</li>
<li>推荐使用 <code>Object.getPrototypeOf()</code> 和 <code>Object.setPrototypeOf()</code> 来访问和设置对象的原型。</li>
</ul>
<hr>
<h2 id="prototype">prototype</h2>
<h3 id="概念-1">概念</h3>
<ul>
<li><code>.prototype</code> 是<strong>函数对象特有</strong>的属性。每个函数对象都有一个<code>.prototype</code>属性，它指向一个对象。这个对象被称为该函数的原型对象。</li>
<li>当使用 <code>new</code> 操作符来创建一个实例时，JavaScript 会将实例的<code>[[Prototype]]</code>属性指向该函数的<code>.prototype</code>所指向的对象，从而实现原型继承。</li>
<li>默认的 &ldquo;prototype&rdquo; 是一个只有属性 constructor 的对象，属性 constructor 指向函数自身。
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Rabbit</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* 默认的 prototype
</span></span></span><span class="line"><span class="cl"><span class="cm">Rabbit.prototype = { constructor: Rabbit };
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="作用-1">作用</h3>
<ul>
<li><code>.prototype</code> 属性主要用于定义构造函数的原型对象，它包含了实例共享的方法和属性。</li>
<li>通过在构造函数的 <code>.prototype</code> 对象上添加属性和方法，可以让所有通过该构造函数创建的实例共享这些属性和方法。</li>
<li>F.prototype 属性仅在 new F 被调用时使用，如果在创建之后，F.prototype 属性有了变化（<code>F.prototype = &lt;another object&gt;</code>），那么通过<code>new F</code>创建的新对象也将随之拥有新的对象作为<code>[[Prototype]]</code>，但已经存在的对象将保持旧有的值。</li>
</ul>
<h3 id="示例">示例:</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">a</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">a</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> <span class="c1">//undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">a</span><span class="p">();</span> <span class="c1">//创建一个新的实例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> <span class="c1">//undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">)</span> <span class="c1">//2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">b</span><span class="p">);</span> <span class="c1">// 3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> <span class="c1">// 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">a</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> <span class="c1">//3
</span></span></span></code></pre></div><h3 id="补充">补充</h3>
<ul>
<li>箭头函数没有 prototype 属性</li>
</ul>
<hr>
<h2 id="new">new</h2>
<h3 id="定义">定义</h3>
<ul>
<li>new 运算符创建一个<strong>用户定义的对象类型</strong>的实例或<strong>具有构造函数的内置对象</strong>的实例。 ——（来自于MDN）</li>
<li>不可以使用 <code>new Symbol()</code>，因为 symbol 是基本数据类型，每个从Symbol()返回的 symbol 值都是唯一的。</li>
</ul>
<h3 id="工作原理">工作原理</h3>
<p>当使用<code>new</code>调用构造函数时，会发生以下步骤：</p>
<ol>
<li>创建一个新的空对象。</li>
<li>将这个新对象的<code>__proto__</code>链接到构造函数的<code>prototype</code>属性上，建立原型继承关系。</li>
<li>执行构造函数，将<code>this</code>绑定到新创建的对象上，允许修改该对象的属性。</li>
<li>如果构造函数没有返回对象，则默认返回创建的对象。</li>
</ol>
<h3 id="简单实现">简单实现</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">myNew</span><span class="p">(</span><span class="nx">constructor</span><span class="p">,</span> <span class="p">...</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 1. 创建一个空对象，并将其原型链链接到构造函数的 prototype
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">constructor</span><span class="p">.</span><span class="nx">prototype</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// 2. 执行构造函数，并将 `this` 绑定到新对象上
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">constructor</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// 3. 如果构造函数返回的是对象类型，则返回该对象；否则返回新创建的对象
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">return</span> <span class="nx">result</span> <span class="k">instanceof</span> <span class="nb">Object</span> <span class="o">?</span> <span class="nx">result</span> <span class="o">:</span> <span class="nx">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 测试用例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">Car</span><span class="p">(</span><span class="nx">color</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">color</span> <span class="o">=</span> <span class="nx">color</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">Car</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">start</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">color</span> <span class="o">+</span> <span class="s2">&#34; car start&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">car</span> <span class="o">=</span> <span class="nx">myNew</span><span class="p">(</span><span class="nx">Car</span><span class="p">,</span> <span class="s2">&#34;black&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">car</span><span class="p">.</span><span class="nx">color</span><span class="p">;</span> <span class="c1">// black
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">car</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span> <span class="c1">// black car start
</span></span></span></code></pre></div><h3 id="代码输出题">代码输出题</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">F</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">f</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">F</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">F</span><span class="p">.</span><span class="nx">a</span><span class="p">);</span> <span class="c1">// 1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">F</span><span class="p">.</span><span class="nx">b</span><span class="p">);</span> <span class="c1">// 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">f</span><span class="p">.</span><span class="nx">a</span><span class="p">);</span> <span class="c1">//undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">f</span><span class="p">.</span><span class="nx">b</span><span class="p">);</span> <span class="c1">// 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">f</span><span class="p">.</span><span class="nx">prototype</span><span class="p">);</span> <span class="c1">//undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">f</span><span class="p">.</span><span class="nx">__proto__</span><span class="p">);</span> <span class="c1">//{}
</span></span></span></code></pre></div><h3 id="参考">参考</h3>
<ul>
<li><a href="https://muyiy.cn/blog/3/3.5.html"  target="_blank" rel="noopener" >深度解析 new 原理及模拟实现 | 木易杨前端进阶</a></li>
</ul>
<hr>
<h2 id="原型原型链和实例的关系">原型，原型链和实例的关系</h2>
<h3 id="原型链prototype-chain">原型链（prototype chain）</h3>
<ul>
<li>在 JavaScript 中，每个对象都有一个指向其原型的链接，这个链接被称为原型链。</li>
<li>当尝试访问对象的属性或方法时，如果该对象本身没有这个属性或方法，JavaScript 引擎会沿着原型链向上查找，直到找到对应的属性或方法，或者查找到达原型链的末端（Object.prototype）。</li>
</ul>
<h3 id="实例-instance">实例 (instance)</h3>
<ul>
<li>根据某个类或构造函数创建的具体对象</li>
<li>当实例化一个类时，你创建了一个新的对象，该对象继承了类的属性和方法，同时拥有了自己的状态和行为。每个实例都是独立的，它们之间的状态和行为互不影响。</li>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Fn</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Fn</span><span class="p">.</span><span class="nx">prototype</span><span class="p">)</span> <span class="c1">// {}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">Fn</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">add</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">count</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`this.count: </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">count</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Fn</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">fn1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Fn</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">fn1</span><span class="p">.</span><span class="nx">add</span><span class="p">();</span> <span class="c1">//1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">fn1</span><span class="p">.</span><span class="nx">add</span><span class="p">();</span> <span class="c1">//2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">fn2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Fn</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">fn2</span><span class="p">.</span><span class="nx">add</span><span class="p">();</span> <span class="c1">//3
</span></span></span></code></pre></div></li>
</ul>
<h3 id="原型链的性能">原型链的性能</h3>
<p>在现代引擎中，从性能的角度来看，我们是从对象还是从原型链获取属性都是没区别的。它们（引擎）会记住在哪里找到的该属性，并在下一次请求中重用它。</p>
<p>例如，对于 pockets.glasses 来说，它们（引擎）会记得在哪里找到的 glasses（在 head 中），这样下次就会直接在这个位置进行搜索。并且引擎足够聪明，一旦有内容更改，它们就会自动更新内部缓存，因此，该优化是安全的。</p>
<hr>
<h2 id="原生原型">原生原型</h2>
<ul>
<li>内建对象，像 Array、Date、Function 及其他，都在 prototype 上挂载了方法。</li>
<li>在现代编程中，只有一种情况下允许修改原生原型。那就是 polyfilling。</li>
</ul>
<h2 id="使用给定的原型创建对象">使用给定的原型创建对象</h2>
<h3 id="字面量语法">字面量语法</h3>
<h3 id="objectcreate">Object.create</h3>
<ul>
<li><code>Object.create(proto, [descriptors])</code></li>
<li>浅拷贝对象及其所有属性描述符（descriptors）</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">clone</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">getPrototypeOf</span><span class="p">(</span><span class="nx">obj</span><span class="p">),</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyDescriptors</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>
</span></span></code></pre></div><h2 id="参考-1">参考</h2>
<ul>
<li><a href="https://zh.javascript.info/prototype-inheritance"  target="_blank" rel="noopener" >原型继承</a></li>
<li><a href="https://zh.javascript.info/function-prototype"  target="_blank" rel="noopener" >F.prototype</a></li>
<li><a href="https://zh.javascript.info/native-prototypes"  target="_blank" rel="noopener" >原生的原型</a></li>
<li><a href="https://zh.javascript.info/prototype-methods"  target="_blank" rel="noopener" >原型方法，没有proto的对象</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之映射与集合</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_map_and_set/</link>
      <pubDate>Sat, 28 Sep 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_map_and_set/</guid>
      <description>自己学习过程中整理的关于JavaScript中映射与集合的知识点</description>
      <content:encoded><![CDATA[<h2 id="map">Map</h2>
<h3 id="概念">概念</h3>
<ul>
<li>是一个带键的数据项的集合</li>
<li>允许任何类型的键（key）</li>
</ul>
<h3 id="常用方法">常用方法</h3>
<ul>
<li>new Map() —— 创建 map。</li>
<li>map.set(key, value) —— 根据键存储值。</li>
<li>map.get(key) —— 根据键来返回值，如果 map 中不存在对应的 key，则返回 undefined。</li>
<li>map.has(key) —— 如果 key 存在则返回 true，否则返回 false。</li>
<li>map.delete(key) —— 删除指定键的值。</li>
<li>map.clear() —— 清空 map。</li>
<li>map.size —— 返回当前元素个数。</li>
</ul>
<h3 id="迭代">迭代</h3>
<ul>
<li>迭代的顺序与插入值的顺序相同。与普通的 Object 不同，Map 保留了此顺序。</li>
<li>map.keys() —— 遍历并返回一个包含所有键的可迭代对象，</li>
<li>map.values() —— 遍历并返回一个包含所有值的可迭代对象，</li>
<li>map.entries() —— 遍历并返回一个包含所有实体 [key, value] 的可迭代对象，for..of 在默认情况下使用的就是这个。</li>
<li><code>map.forEach((value,key,map)=&gt;{})</code></li>
</ul>
<h3 id="map-是怎么比较键的">Map 是怎么比较键的？</h3>
<p>Map 使用 <a href="https://tc39.es/ecma262/#sec-samevaluezero"  target="_blank" rel="noopener" >SameValueZero</a> 算法来比较键是否相等。它和严格等于 === 差不多，但区别是 NaN 被看成是等于 NaN。所以 NaN 也可以被用作键。这个算法不能被改变或者自定义。</p>
<h3 id="map和object的区别">Map和Object的区别</h3>
<ul>
<li>Map可以支持任意JS数据类型作为键名，而Object只能是数值、字符串或者符号</li>
<li>内存占用： 不同浏览器下情况不同，Map大约比Object多存储50%的键值对</li>
<li>插入性能： 插入速度都不会因为键值对的数量进行线性增加，但对于大量插入操作，Map的性能更佳。</li>
<li>查找速度： 如果是少量的键值对，Object的速度更快</li>
<li>删除性能： Map在大多数浏览器引擎中删除操作较快</li>
</ul>
<h3 id="初始化">初始化</h3>
<ul>
<li>传入一个带有键值对的数组（或其它可迭代对象）来进行初始化</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// 键值对 [key, value] 数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kd">let</span> <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Map</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="s1">&#39;1&#39;</span><span class="p">,</span>  <span class="s1">&#39;str1&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="mi">1</span><span class="p">,</span>    <span class="s1">&#39;num1&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="kc">true</span><span class="p">,</span> <span class="s1">&#39;bool1&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span> <span class="nx">map</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;1&#39;</span><span class="p">)</span> <span class="p">);</span> <span class="c1">// str1
</span></span></span></code></pre></div><ul>
<li>使用Object.entries：从对象创建 Map
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;John&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age</span><span class="o">:</span> <span class="mi">30</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Map</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span> <span class="nx">map</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span> <span class="p">);</span> <span class="c1">// John
</span></span></span></code></pre></div></li>
<li>反过来，使用Object.fromEntries：从 Map 创建对象
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Map</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">map</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;banana&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">map</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;orange&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">map</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;meat&#39;</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">fromEntries</span><span class="p">(</span><span class="nx">map</span><span class="p">.</span><span class="nx">entries</span><span class="p">());</span> <span class="c1">// 创建一个普通对象（plain object）(*)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//可以更短
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// let obj = Object.fromEntries(map); // 省掉 .entries()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="c1">// obj = { banana: 1, orange: 2, meat: 4 }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">orange</span><span class="p">);</span> <span class="c1">// 2
</span></span></span></code></pre></div></li>
</ul>
<h3 id="实现">实现</h3>
<p>可以使用两个数组（一个存放键，一个存放值）来实现。给这种映射设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该映射取值的时候，需要遍历所有的键，然后使用索引从存储值的数组中检索出相应的值。</p>
<p>但这样的实现会有两个很大的缺点：</p>
<ol>
<li>赋值和搜索操作都是 O(n) 的时间复杂度（n 是键值对的个数），因为这两个操作都需要遍历全部整个数组来进行匹配。</li>
<li>可能会导致内存泄漏，因为数组会一直引用着每个键和值。这种引用使得垃圾回收算法不能回收处理他们，即使没有其他任何引用存在了。</li>
</ol>
<h3 id="基于map的lru缓存实现">基于Map的LRU缓存实现</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">LRUCache</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">constructor</span><span class="p">(</span><span class="nx">capacity</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span> <span class="o">=</span> <span class="nx">capacity</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">cache</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Map</span><span class="p">();</span> <span class="c1">// 用于存储缓存
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">key</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// 如果不存在，返回 -1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果存在，将该键值移到末尾表示最近使用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">put</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">key</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 如果已存在，先删除旧的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">size</span> <span class="o">===</span> <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 如果缓存已满，删除最旧的（第一个）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">keys</span><span class="p">().</span><span class="nx">next</span><span class="p">().</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 添加新值到缓存
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 使用示例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">lruCache</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LRUCache</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="c1">// 创建容量为 2 的 LRU 缓存
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;A&#39;</span><span class="p">);</span> <span class="c1">// 缓存是 {1: &#39;A&#39;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;B&#39;</span><span class="p">);</span> <span class="c1">// 缓存是 {1: &#39;A&#39;, 2: &#39;B&#39;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> <span class="c1">// 返回 &#39;A&#39;，缓存变为 {2: &#39;B&#39;, 1: &#39;A&#39;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s1">&#39;C&#39;</span><span class="p">);</span> <span class="c1">// 取消键 2，缓存是 {1: &#39;A&#39;, 3: &#39;C&#39;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span> <span class="c1">// 返回 -1（未找到）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="s1">&#39;D&#39;</span><span class="p">);</span> <span class="c1">// 取消键 1，缓存是 {3: &#39;C&#39;, 4: &#39;D&#39;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> <span class="c1">// 返回 -1（未找到）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">3</span><span class="p">));</span> <span class="c1">// 返回 &#39;C&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lruCache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">4</span><span class="p">));</span> <span class="c1">// 返回 &#39;D&#39;
</span></span></span></code></pre></div><hr>
<h2 id="weakmap">WeakMap</h2>
<h3 id="要求">要求</h3>
<ul>
<li>键必须是可被垃圾回收的
<ul>
<li>大多数原始数据类型可以任意地被创建，且<strong>没有生命周期</strong>，因此不能作为键</li>
<li><strong>对象和非全局注册的符号</strong>都可以作为键，因为它们是可被垃圾回收的</li>
</ul>
</li>
</ul>
<h3 id="特点">特点</h3>
<ul>
<li>WeakMap 的键对象会强引用其值，直到该键对象被垃圾回收，但从那时起，它会变为弱引用</li>
<li>不会阻止垃圾回收，直到垃圾回收器移除了键对象的引用</li>
<li>任何值都可以被垃圾回收，只要它们的键对象没有被 WeakMap 以外的地方引用</li>
<li>不支持遍历</li>
</ul>
<h3 id="强引用与弱引用">强引用与弱引用</h3>
<ul>
<li>对象的弱引用是指该引用<strong>不会阻止</strong> GC 回收这个对象。</li>
<li>一个普通的引用（或者说强引用）会将与之对应的对象保存在内存中。</li>
<li>只有当该对象没有任何的强引用时，JavaScript 引擎 GC 才会销毁该对象并且回收该对象所占的内存空间。如果上述情况发生了，那么你就无法通过任何的弱引用来获取该对象。</li>
</ul>
<h3 id="作用一-模拟私有成员">作用一: 模拟私有成员</h3>
<ul>
<li>好处
<ol>
<li>与<code>Map</code>相比，<code>WeakMap</code>不持有键对象的强引用，因此元数据与对象本身共享同样的生命周期，<strong>避免内存泄漏</strong>。</li>
<li>与使用不可枚举对象和/或<code>Symbol</code>属性相比，<code>WeakMap</code>位于对象外部，没有办法通过像<code>Object.getOwnPropertySymbols</code>等的反射方法来检索元数据。</li>
<li>与闭包相比，构造函数可以复用同一个<code>WeakMap</code>对象来创建所有实例，从而节省内存，并且允许同一个类创建的不同实例读取彼此的私有成员。</li>
</ol>
</li>
<li>代码:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">Thing</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">privateScope</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WeakMap</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">Thing</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">someProperty</span> <span class="o">=</span> <span class="s2">&#34;foo&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">privateScope</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">hidden</span><span class="o">:</span> <span class="o">++</span><span class="nx">counter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">Thing</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">showPublic</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">someProperty</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">Thing</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">showPrivate</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">privateScope</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">privateScope</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;undefined&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">thing</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Thing</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">thing</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Thing {someProperty: &#34;foo&#34;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">thing</span><span class="p">.</span><span class="nx">showPublic</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;foo&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">thing</span><span class="p">.</span><span class="nx">showPrivate</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 1
</span></span></span></code></pre></div><ul>
<li>常规写法</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Thing</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">static</span> <span class="err">#</span><span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="err">#</span><span class="nx">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">constructor</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">someProperty</span> <span class="o">=</span> <span class="s2">&#34;foo&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="err">#</span><span class="nx">hidden</span> <span class="o">=</span> <span class="o">++</span><span class="nx">Thing</span><span class="p">.</span><span class="err">#</span><span class="nx">counter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="nx">showPublic</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">someProperty</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="nx">showPrivate</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="err">#</span><span class="nx">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">thing</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Thing {someProperty: &#34;foo&#34;}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">thing</span><span class="p">.</span><span class="nx">showPublic</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;foo&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">thing</span><span class="p">.</span><span class="nx">showPrivate</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 1
</span></span></span></code></pre></div><h3 id="作用二-关联元数据">作用二: 关联元数据</h3>
<ul>
<li>可用于将元数据与对象关联，而不影响对象的生命周期</li>
</ul>
<h3 id="作用三-缓存">作用三: 缓存</h3>
<ul>
<li>缺点:
<ul>
<li>只有当函数的输入是对象时才有效</li>
<li>即使输入不再传入，结果依然永远保留在缓存中</li>
</ul>
</li>
<li>更好的方法: 将 Map 与 WeakRef 对象配对使用</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap"  target="_blank" rel="noopener" >WeakMap - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="set">Set</h2>
<h3 id="概念-1">概念</h3>
<ul>
<li>“值的集合”（没有键）</li>
<li>每一个值只能出现一次</li>
</ul>
<h3 id="常用方法-1">常用方法</h3>
<ul>
<li><code>new Set(iterable)</code> —— 创建一个 set，如果提供了一个 iterable 对象（通常是数组），将会从数组里面复制值到 set 中。</li>
<li><code>set.add(value)</code> —— 添加一个值，返回 set 本身</li>
<li><code>set.delete(value)</code> —— 删除值，如果 value 在这个方法调用的时候存在则返回 true ，否则返回 false。</li>
<li><code>set.has(value)</code> —— 如果 value 在 set 中，返回 true，否则返回 false。</li>
<li><code>set.clear()</code> —— 清空 set。</li>
<li><code>set.size</code> —— 返回元素个数。</li>
</ul>
<h3 id="迭代-1">迭代</h3>
<ul>
<li><code>for..of</code></li>
<li><code>forEach</code>
<ul>
<li>回调函数有三个参数：一个 value，然后是 同一个值 valueAgain，最后是目标对象</li>
<li><strong>为了与 Map 兼容</strong></li>
</ul>
</li>
<li><code>set.keys()</code> —— 遍历并返回一个包含所有值的可迭代对象，</li>
<li><code>set.values()</code> —— 与<code>set.keys()</code>作用相同，这是为了兼容 Map，</li>
</ul>
<h3 id="作用">作用</h3>
<ul>
<li>数组去重：<code>Array.from(new Set(arr));</code></li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set"  target="_blank" rel="noopener" >Set - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="weakset">WeakSet</h2>
<h3 id="概念-2">概念</h3>
<ul>
<li>可被垃圾回收的值的集合，包括对象和非全局注册的符号</li>
<li>WeakSet 中的值只能出现一次</li>
<li>WeakSet 是<strong>不可枚举</strong>的</li>
</ul>
<h3 id="作用一-检测循环引用">作用一: 检测循环引用</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 对传入的 subject 对象内部存储的所有内容执行回调
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">execRecursively</span><span class="p">(</span><span class="nx">fn</span><span class="p">,</span> <span class="nx">subject</span><span class="p">,</span> <span class="nx">_refs</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WeakSet</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 避免无限递归
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">if</span> <span class="p">(</span><span class="nx">_refs</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">subject</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">fn</span><span class="p">(</span><span class="nx">subject</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">subject</span> <span class="o">===</span> <span class="s2">&#34;object&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">_refs</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">subject</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">subject</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">execRecursively</span><span class="p">(</span><span class="nx">fn</span><span class="p">,</span> <span class="nx">subject</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="nx">_refs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">foo</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">foo</span><span class="o">:</span> <span class="s2">&#34;Foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bar</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">bar</span><span class="o">:</span> <span class="s2">&#34;Bar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span><span class="p">.</span><span class="nx">baz</span> <span class="o">=</span> <span class="nx">foo</span><span class="p">;</span> <span class="c1">// 循环引用！
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">execRecursively</span><span class="p">((</span><span class="nx">obj</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">),</span> <span class="nx">foo</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="作用二-储存-dom-节点">作用二: 储存 DOM 节点</h3>
<h3 id="用例">用例</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WeakSet</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">foo</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">bar</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">bar</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">ws</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">bar</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// 从 set 中删除 foo 对象
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">ws</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// false，foo 对象已经被删除了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">ws</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">bar</span><span class="p">);</span> <span class="c1">// true，bar 依然存在
</span></span></span></code></pre></div><ul>
<li>注意，<code>foo !== bar</code>。尽管它们是相似的对象，但是它们不是同一个对象。因此，它们都可以被加入到集合中。</li>
</ul>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet"  target="_blank" rel="noopener" >WeakSet - JavaScript | MDN</a></li>
</ul>
<h2 id="参考-3">参考</h2>
<ul>
<li><a href="https://zh.javascript.info/map-set"  target="_blank" rel="noopener" >Map and Set（映射和集合）</a></li>
<li><a href="https://juejin.cn/post/7003533740341362719"  target="_blank" rel="noopener" >ES6新增引用类型：Map、WeakMap、Set、WeakSet前言 Map、WeakMap、Set、WeakSet作 - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之数据类型</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_data_type/</link>
      <pubDate>Fri, 27 Sep 2024 23:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_data_type/</guid>
      <description>自己学习过程中整理的关于JavaScript中数据类型的知识点</description>
      <content:encoded><![CDATA[<h2 id="基本类型值类型">基本类型(值类型)</h2>
<ol>
<li>数值（Number）：用于表示数字，包括整数和浮点数。</li>
<li>字符串（String）：用于表示文本，由单引号或双引号括起来的字符序列。</li>
<li>布尔值（Boolean）：用于表示逻辑值，只有两个取值，true和false。</li>
<li>空值（Null）：表示&quot;没有对象&quot;，即该处不应该有值; <code>typeof null === &quot;object&quot;</code></li>
<li>未定义（Undefined）：表示&quot;缺少值&quot;，就是此处应该有一个值，但是还没有定义
<ul>
<li>在ES5标准中，<code>undefined</code>被设置为不可写</li>
<li>但在其之前，<code>undefined</code>实际上是一个全局属性,可以被修改。所以babel会将其编译成<code>void 0</code>,来确保兼容性</li>
</ul>
</li>
<li>大整数（BigInt）：用于表示任意精度的整数，通常用于表示超出Number类型范围的整数。
<ul>
<li>不可以把 bigint 和常规数字类型混合使用</li>
<li>创建 bigint 的方式有两种：在一个整数字面量后面加 n 或者调用 BigInt 函数，该函数从字符串、数字等中生成 bigint</li>
</ul>
</li>
<li>符号（Symbol）：用于表示唯一的标识符。(ES6引入)</li>
<li>永远不会有返回值的类型（Never）：表示那些永远不会有返回值的函数的返回值类型。通常用于抛出异常或无限循环等情况。</li>
<li>任意类型（Any）：表示可以是任何类型的值，通常用于在编写代码时不确定变量的类型，或者需要处理多种类型的情况。</li>
</ol>
<h3 id="pattern">pattern</h3>
<ul>
<li>所有的内建对象都遵循相同的模式（pattern）：
<ol>
<li>方法都存储在 prototype 中（Array.prototype、Object.prototype、Date.prototype 等）。</li>
<li>对象本身只存储数据（数组元素、对象属性、日期）。</li>
</ol>
</li>
</ul>
<h3 id="参考">参考：</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures"  target="_blank" rel="noopener" >JavaScript 数据类型和数据结构 - JavaScript | MDN</a></li>
<li><a href="https://zh.javascript.info/bigint"  target="_blank" rel="noopener" >BigInt</a></li>
<li><a href="https://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html"  target="_blank" rel="noopener" >undefined与null的区别 - 阮一峰的网络日志</a></li>
</ul>
<hr>
<h2 id="null和undefined的区别">null和undefined的区别</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">animal</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">jumps</span><span class="o">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">rabbit</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">__proto__</span><span class="o">:</span> <span class="nx">animal</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">jumps</span><span class="o">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span> <span class="nx">rabbit</span><span class="p">.</span><span class="nx">jumps</span> <span class="p">);</span> <span class="c1">// true，来自于 rabbit
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">delete</span> <span class="nx">rabbit</span><span class="p">.</span><span class="nx">jumps</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span> <span class="nx">rabbit</span><span class="p">.</span><span class="nx">jumps</span> <span class="p">);</span> <span class="c1">// null, 来自于animal
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">delete</span> <span class="nx">animal</span><span class="p">.</span><span class="nx">jumps</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span> <span class="nx">rabbit</span><span class="p">.</span><span class="nx">jumps</span> <span class="p">);</span> <span class="c1">// undefined，不再有这样的属性存在
</span></span></span></code></pre></div><hr>
<h2 id="原始值">原始值</h2>
<h3 id="定义">定义</h3>
<p>在 JavaScript 中，原始值（原始数据类型）是一种既非对象也无方法或属性的数据。有 7 种原始数据类型：</p>
<ol>
<li>string</li>
<li>number</li>
<li>bigint</li>
<li>boolean</li>
<li>undefined</li>
<li>symbol</li>
<li>null</li>
</ol>
<h3 id="特点">特点</h3>
<ul>
<li>所有原始值都是不可变的，即它们的值不能被修改</li>
<li>基本类型没有方法，但仍然表现得像有方法一样。当在原始值上访问属性时，JavaScript 自动将值装入包装对象中，并访问该对象上的属性</li>
<li>可以任意地被创建，且没有生命周期，因此不能作为weakmap的键</li>
<li>特殊值 null 和 undefined 比较特殊。它们没有对象包装器，所以它们没有方法和属性。并且它们也没有相应的原型。</li>
</ul>
<h3 id="参考-1">参考:</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Primitive"  target="_blank" rel="noopener" >原始值 - MDN Web 文档术语表：Web 相关术语的定义 | MDN</a></li>
</ul>
<hr>
<h2 id="symbol">Symbol</h2>
<ul>
<li>Symbol 同时是 JavaScript 里最特殊和最不特殊的东西了。</li>
</ul>
<h3 id="最特殊">最特殊</h3>
<ul>
<li>代码</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Symbol</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span> <span class="o">===</span> <span class="nx">Symbol</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// false
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">symbolOne</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">symbolTwo</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">symbolOne</span> <span class="o">===</span> <span class="nx">symbolTwo</span><span class="p">);</span> <span class="c1">// false
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">  <span class="nx">obj</span><span class="p">[</span><span class="nx">symbolOne</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;hello&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">symbolTwo</span><span class="p">]);</span> <span class="c1">// undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">symbolOne</span><span class="p">]);</span> <span class="c1">// &#39;hello&#39;
</span></span></span></code></pre></div><ul>
<li>传给 Symbol 构造器的字符串只是对它的一个描述，同一个领域下面同一个描述的 symbol 也是独特的。</li>
</ul>
<h3 id="最不特殊">最不特殊</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">symbolOne</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">.</span><span class="k">for</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">symbolTwo</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">.</span><span class="k">for</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">symbolOne</span> <span class="o">===</span> <span class="nx">symbolTwo</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">  <span class="nx">obj</span><span class="p">[</span><span class="nx">symbolOne</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;hello&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">symbolTwo</span><span class="p">]);</span> <span class="c1">// &#39;hello&#39;
</span></span></span></code></pre></div><ul>
<li>Symbol.for(str) 新建了一个根据你字符串唯一的 symbol 对象。重点是，跨了领域之后，它还是一样的。。</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">iframe</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;iframe&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">iframeWindow</span> <span class="o">=</span> <span class="nx">iframe</span><span class="p">.</span><span class="nx">contentWindow</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Symbol</span><span class="p">.</span><span class="k">for</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span> <span class="o">===</span> <span class="nx">iframeWindow</span><span class="p">.</span><span class="nx">Symbol</span><span class="p">.</span><span class="k">for</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">));</span> <span class="c1">// true
</span></span></span></code></pre></div><h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://segmentfault.com/a/1190000021089487"  target="_blank" rel="noopener" >javascript - [译] isArray 背后发生了什么？ - 梦里一路飞奔 - SegmentFault 思否</a></li>
</ul>
<hr>
<h2 id="引用数据类型对象类型">引用数据类型(对象类型)</h2>
<h3 id="包括">包括</h3>
<ol>
<li>Object</li>
<li>Array</li>
<li>Function</li>
<li>Date</li>
<li>RegExp</li>
</ol>
<p>ES6新增</p>
<ol>
<li>Map</li>
<li>WeakMap</li>
<li>Set</li>
<li>WeakSet</li>
</ol>
<h3 id="array-和object的关系">Array 和object的关系</h3>
<p>数组在内部也是对象，但它的原型是<code>Array.prototype</code></p>
<h3 id="和原始类型的区别">和原始类型的区别</h3>
<ul>
<li>定义方式不同：原始类型（如数字、字符串、布尔值、null和undefined）是直接赋值给变量的，而引用类型（如对象、数组和函数）是通过引用赋值给变量的。</li>
<li>存储方式不同：原始类型的值直接存储在栈中，而引用类型的值存储在堆内存中，然后在栈中保存对该内存地址的引用。</li>
<li>比较方式不同：原始类型的比较是按值进行的，即比较它们的实际值是否相等；而引用类型的比较是按引用进行的，即比较它们是否指向同一内存地址。</li>
<li>传递方式不同：将原始类型的值赋给新变量时，会复制该值；而将引用类型的值赋给新变量时，只会复制指向该值的引用。</li>
</ul>
<hr>
<h2 id="类型判断">类型判断</h2>
<h3 id="typeof"><code>typeof</code>:</h3>
<ul>
<li>用于检查变量的数据类型。它返回一个表示变量类型的字符串</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">typeof</span> <span class="nx">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//&#39;object&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">b</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"><span class="k">typeof</span> <span class="nx">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//&#39;object&#39;
</span></span></span></code></pre></div></li>
<li>缺点: 只能检测8种: es5的string，boolean，number，function，object，undefined es6的symbol，以及最新的bigint</li>
<li>历史遗留问题
<ul>
<li>在 JavaScript 的早期版本中，值的内部类型使用了一个 32 位的标识符，其中某些位被用于表示类型。对于对象和 null，这个标识符的值是相同的，导致 typeof null 返回 &lsquo;object&rsquo;
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">typeof</span> <span class="kc">null</span> <span class="o">===</span> <span class="s2">&#34;object&#34;</span> <span class="c1">//true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">typeof</span> <span class="kc">null</span> <span class="o">!==</span> <span class="s2">&#34;null&#34;</span> <span class="c1">// true
</span></span></span></code></pre></div></li>
</ul>
</li>
</ul>
<h3 id="instance-of"><code>instance of</code>:</h3>
<ul>
<li>用于检查一个对象是否是另一个对象的实例，或者是否属于某个类的实例</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Animal</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Dog</span> <span class="kr">extends</span> <span class="nx">Animal</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">dog</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Dog</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">dog</span> <span class="k">instanceof</span> <span class="nx">Dog</span><span class="p">);</span> <span class="c1">// 返回 true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">dog</span> <span class="k">instanceof</span> <span class="nx">Animal</span><span class="p">);</span> <span class="c1">// 返回 true
</span></span></span></code></pre></div></li>
</ul>
<h3 id="objecttostringcall"><code>Object.toString.call</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// &#34;[object Number]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="s1">&#39;hi&#39;</span><span class="p">)</span> <span class="c1">// &#34;[object String]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">({</span><span class="nx">a</span><span class="o">:</span><span class="s1">&#39;hi&#39;</span><span class="p">})</span> <span class="c1">// &#34;[object Object]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="s1">&#39;a&#39;</span><span class="p">])</span> <span class="c1">// &#34;[object Array]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="c1">// &#34;[object Boolean]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{})</span> <span class="c1">// &#34;[object Function]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="kc">null</span><span class="p">)</span> <span class="c1">// &#34;[object Null]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="kc">undefined</span><span class="p">)</span> <span class="c1">// &#34;[object Undefined]&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">Symbol</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span> <span class="c1">// &#34;[object Symbol]&#34;
</span></span></span></code></pre></div><h3 id="如何实现instanceof">如何实现instanceof?</h3>
<p>wip</p>
<h3 id="如何确定传递的值是否是一个数组">如何确定传递的值是否是一个数组?</h3>
<ul>
<li>答: 使用<code>Array.isArray()</code></li>
<li><code>Array.isArray()</code>的特别之处
<ul>
<li><code>Array.isArray()</code> 拒绝原型链中带有 <code>Array.prototype</code>，而实际不是数组的对象，但 <code>instanceof Array</code> 会接受。</li>
<li>对在另一个领域里面创建的数组也会返回 true</li>
<li>对Array 的子类也会返回 true
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">SpecialArray</span> <span class="kr">extends</span> <span class="nb">Array</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">specialArray</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SpecialArray</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">specialArray</span><span class="p">)</span> <span class="c1">// true
</span></span></span></code></pre></div></li>
</ul>
</li>
<li>领域(realm)
<ul>
<li>一个领域包含了 JavaScript 的全局对象。</li>
<li>跑在 worker 里面的代码，和跑在页面里面的代码，是属于不同领域的。</li>
<li>iframe 之间也是这样（属于不同领域）。但是，同源的 iframe 们共享一个 ECMAScript agent，意味着对象这个东西可以在不同领域之间传递：</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray"  target="_blank" rel="noopener" >Array.isArray() - JavaScript | MDN</a></li>
<li><a href="https://segmentfault.com/a/1190000021089487"  target="_blank" rel="noopener" >javascript - [译] isArray 背后发生了什么？ - 梦里一路飞奔 - SegmentFault 思否</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="object">Object</h2>
<h3 id="概念">概念</h3>
<ul>
<li>在 JavaScript 中，对象,可以被看作是一组属性的集合。它是唯一可变的值。事实上，函数也是具有额外可调用能力的对象。</li>
<li>对象属性名字可以是任意字符串，包括空串。
<ul>
<li>如果对象属性名字不是合法的 javascript 标识符，它必须用引号包裹。</li>
</ul>
</li>
<li>对象的原型（prototype）指向另一个对象或者 null</li>
</ul>
<h3 id="访问和设置object的属性">访问和设置Object的属性</h3>
<ul>
<li>
<p><strong>访问</strong></p>
<ul>
<li>点符号表示法
<ul>
<li><code>obj.propertyName</code></li>
<li>适用于静态属性名</li>
</ul>
</li>
<li>方括号表示法
<ul>
<li><code>obj[&quot;propertyName&quot;]</code></li>
<li>适用于动态属性名或包含特殊字符的属性名</li>
</ul>
</li>
<li>上述二者都属于<strong>属性访问器</strong>(Property accessors)</li>
</ul>
</li>
<li>
<p><strong>设置</strong></p>
<ul>
<li>语法<code>Object.defineProperty(obj, prop, descriptor)</code></li>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="s1">&#39;hiddenProp&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;hidden&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">configurable</span><span class="o">:</span><span class="kc">false</span><span class="p">,</span><span class="c1">//default
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span><span class="c1">//default
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">writable</span><span class="o">:</span> <span class="kc">false</span> <span class="c1">//default
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">});</span>
</span></span></code></pre></div></li>
</ul>
</li>
<li>
<p>设置访问器属性</p>
<ul>
<li>不能直接定义</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">book</span> <span class="o">=</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">    <span class="nx">hideYear</span><span class="o">:</span> <span class="mi">2004</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="nx">edition</span><span class="o">:</span> <span class="mi">1</span> 
</span></span><span class="line"><span class="cl">  <span class="p">};</span> 
</span></span><span class="line"><span class="cl">  <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">book</span><span class="p">,</span> <span class="s2">&#34;year&#34;</span><span class="p">,</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span> 
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">hideYear</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">    <span class="p">},</span> 
</span></span><span class="line"><span class="cl">    <span class="nx">set</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">newValue</span><span class="p">){</span> 
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">newValue</span> <span class="o">&gt;</span> <span class="mi">2004</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">hideYear</span> <span class="o">=</span> <span class="nx">newValue</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">edition</span> <span class="o">+=</span> <span class="nx">newValue</span> <span class="o">-</span> <span class="mi">2004</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">      <span class="p">}</span> 
</span></span><span class="line"><span class="cl">    <span class="p">}</span> 
</span></span><span class="line"><span class="cl">  <span class="p">});</span> 
</span></span><span class="line"><span class="cl">  <span class="nx">book</span><span class="p">.</span><span class="nx">year</span> <span class="o">=</span> <span class="mi">2005</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span><span class="nx">book</span><span class="p">.</span><span class="nx">edition</span><span class="p">);</span> <span class="c1">//2
</span></span></span></code></pre></div></li>
</ul>
</li>
<li>
<p><strong>区别</strong></p>
<ol>
<li>使用属性访问器分配一个值, 添加的属性是<strong>可写、可枚举、可配置的</strong></li>
<li>默认情况下，使用<code>Object.defineProperty() </code>添加的属性是<strong>不可写、不可枚举和不可配置的</strong></li>
<li>若属性为不可配置的话，那么无法再修改其特性</li>
</ol>
</li>
<li>
<p><strong>删除</strong></p>
<ul>
<li>只能删除对象的可配置属性,<code>delete obj.name;</code></li>
<li>若属性为不可配置的话，尝试删除在非严格模式下会被忽略，严格模式下会抛出错误</li>
</ul>
</li>
<li>
<p>对象注入攻击：<a href="https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/the-dangers-of-square-bracket-notation.md"  target="_blank" rel="noopener" >The Dangers of Square Bracket Notation</a></p>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://juejin.cn/post/7215401973842788411"  target="_blank" rel="noopener" >js中对象的点语法与方括号语法的区别 - 掘金</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Property_accessors"  target="_blank" rel="noopener" >属性访问器 - JavaScript | MDN</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"  target="_blank" rel="noopener" >Object.defineProperty() - JavaScript | MDN</a></li>
<li><a href="https://juejin.cn/post/6844903828580466702"  target="_blank" rel="noopener" >JavaScript对象的数据属性与访问器属性 - 掘金</a></li>
</ul>
</li>
</ul>
<h3 id="字面量初始化对象语法">字面量初始化对象语法</h3>
<ul>
<li>
<p>定义:</p>
<ul>
<li>一个用大括号（{}）括起来的以逗号分隔的列表，包含了一个对象的零个或多个属性名称和相关值</li>
<li>是 Object.create() 的一种语法糖</li>
</ul>
</li>
<li>
<p>区别于JSON:</p>
<ul>
<li>JSON 是对象字面语法的一个真子集</li>
</ul>
</li>
<li>
<p>简写函数名</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">property</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(){}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//等价于
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">property</span><span class="p">(){}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>参考： <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Object_initializer"  target="_blank" rel="noopener" >对象初始化器 - JavaScript | MDN</a></p>
</li>
</ul>
<h3 id="objectcreate">Object.create()</h3>
<ul>
<li>定义: 以一个现有对象作为原型，创建一个新对象</li>
<li>语法: <code>Object.create(proto, propertiesObject)</code></li>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">o</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// foo 是一个常规数据属性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">foo</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;hello&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// bar 是一个访问器属性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">bar</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">configurable</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="mi">10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">set</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Setting `o.bar` to&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
<li>特点:
<ol>
<li>可以控制每个属性的可枚举性、可配置性等，而这在字面量初始化对象语法中是做不到的</li>
<li>直接创建了一个以 传入的第一个参数 作为原型的新对象，不涉及构造函数</li>
<li>由于没有构造函数，不会自动初始化属性，所有属性需要手动添加</li>
</ol>
</li>
<li>可用于模拟<code>new</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">myNew</span><span class="p">(</span><span class="nx">constructor</span><span class="p">,...</span><span class="nx">args</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">constructor</span><span class="p">.</span><span class="nx">prototype</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">constructor</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span><span class="nx">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">res</span> <span class="k">instanceof</span> <span class="nb">Object</span> <span class="o">?</span> <span class="nx">res</span> <span class="o">:</span> <span class="nx">obj</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>参考: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create"  target="_blank" rel="noopener" >Object.create() - JavaScript | MDN</a></li>
</ul>
<h3 id="objectassign">Object.assign()</h3>
<ul>
<li>copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s1">&#39;tom&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="nx">name</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">b</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="c1">//tom
</span></span></span></code></pre></div></li>
<li>参考：<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign"  target="_blank" rel="noopener" >Object.assign() - JavaScript | MDN</a></li>
</ul>
<h3 id="遍历object">遍历Object</h3>
<ol>
<li>for in 和 for of</li>
</ol>
<ul>
<li>对于Object，用<code>for in</code>来遍历Object的key,但无法用<code>for of</code>来遍历value
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Alice&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age</span><span class="o">:</span> <span class="mi">30</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">gender</span><span class="o">:</span> <span class="s2">&#34;female&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">person</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">key</span> <span class="o">+</span> <span class="s1">&#39;: &#39;</span> <span class="o">+</span> <span class="nx">person</span><span class="p">[</span><span class="nx">key</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// name: Alice
</span></span></span><span class="line"><span class="cl"><span class="c1">// age: 30
</span></span></span><span class="line"><span class="cl"><span class="c1">// gender: female
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">person</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// TypeError: person is not iterable
</span></span></span></code></pre></div></li>
<li><code>for in</code>的缺陷
<ol>
<li>会遍历原型链上的可枚举属性</li>
<li>属性遍历顺序不一定是属性定义顺序</li>
<li>只会遍历字符串类型的属性键</li>
</ol>
</li>
</ul>
<ol start="2">
<li><code>Object.entries()</code>
<ul>
<li>returns an array of a given object&rsquo;s own enumerable string-keyed property key-value pairs.</li>
<li>举例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">foo</span><span class="o">:</span> <span class="s2">&#34;bar&#34;</span><span class="p">,</span> <span class="nx">baz</span><span class="o">:</span> <span class="mi">42</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span> <span class="c1">// [ [&#39;foo&#39;, &#39;bar&#39;], [&#39;baz&#39;, 42] ]
</span></span></span></code></pre></div></li>
<li>参考：<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries"  target="_blank" rel="noopener" >Object.entries() - JavaScript | MDN</a></li>
</ul>
</li>
<li><code>Object.keys()</code></li>
<li><code>Object.values()</code></li>
<li><code>Object.getOwnPropertyNames()</code>
<ul>
<li>可以返回对象自身的所有<strong>字符串属性名</strong>，<strong>包括</strong>不可枚举的属性</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="s1">&#39;hiddenProp&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;hidden&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="nx">obj</span><span class="p">.</span><span class="nx">visibleProp</span> <span class="o">=</span> <span class="s1">&#39;visible&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>  <span class="c1">// 输出 [&#34;hiddenProp&#34;, &#34;visibleProp&#34;]
</span></span></span></code></pre></div></li>
</ul>
</li>
<li><code>Object.getOwnPropertyDescriptors()</code>
<ul>
<li>可以返回对象自身所有<strong>字符串属性</strong>的名和属性描述符，包括不可枚举的属性</li>
</ul>
</li>
<li><code>Object.getOwnPropertySymbols()</code>
<ul>
<li>获取对象自身的所有 Symbol 属性键</li>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">object1</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">Symbol</span><span class="p">.</span><span class="k">for</span><span class="p">(</span><span class="s1">&#39;b&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">object1</span><span class="p">[</span><span class="nx">a</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;localSymbol&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nx">object1</span><span class="p">[</span><span class="nx">b</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;globalSymbol&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nx">object1</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="s1">&#39;a&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertySymbols</span><span class="p">(</span><span class="nx">object1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//  [Symbol(&#34;a&#34;), Symbol(&#34;b&#34;)]
</span></span></span></code></pre></div></li>
</ul>
</li>
</ol>
<h3 id="object和object的区别"><code>Object</code>和<code>object</code>的区别</h3>
<ol>
<li><code>Object</code>：这是一个内置的构造函数，用于创建对象。例如，你可以使用<code>new Object()</code>来创建一个新的对象实例。</li>
<li><code>object</code>：这是一个数据类型的名称，表示所有引用类型的对象，包括数组、函数、正则表达式等。它是 JavaScript 中的一种原始类型，用于描述一类数据结构。</li>
</ol>
<h3 id="object和map的区别"><code>Object</code>和<code>Map</code>的区别</h3>
<ul>
<li>
<p>意外的键</p>
</li>
<li>
<p>安全性:</p>
<ul>
<li>Map 可以安全地与用户提供的键值一起使用。</li>
<li>可能会导致对象注入攻击,可以通过使用 null 原型对象来缓解</li>
</ul>
</li>
<li>
<p>键的类型:</p>
<ul>
<li>Map 的键可以为任何值</li>
<li>Object 的键必须为 String 或 Symbol</li>
</ul>
</li>
<li>
<p>键的顺序</p>
<ul>
<li>Map 对象按照插入的顺序迭代条目、键和值。</li>
<li>没有单一机制可以迭代对象的所有属性</li>
</ul>
</li>
<li>
<p>大小</p>
<ul>
<li>Map 中的项目数量很容易从其 size 属性中获得</li>
<li>通过获取 Object.keys() 返回的数组的长度</li>
</ul>
</li>
<li>
<p>迭代</p>
<ul>
<li>Map 是可迭代对象，所以它可以直接迭代。</li>
<li>Object 没有实现迭代协议，因此对象默认情况下不能直接通过 JavaScript 的 for&hellip;of 语句进行迭代。</li>
</ul>
</li>
<li>
<p>性能</p>
<ul>
<li>Map在涉及频繁添加和删除键值对的场景中表现更好。</li>
<li>Object未针对频繁添加和删除键值对进行优化。</li>
</ul>
</li>
<li>
<p>序列化和解析</p>
<ul>
<li>Map没有对序列化或解析的原生支持。</li>
<li><code>JSON.stringify()</code>, <code>JSON.parse()</code></li>
</ul>
</li>
<li>
<p>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map#object_%E5%92%8C_map_%E7%9A%84%E6%AF%94%E8%BE%83"  target="_blank" rel="noopener" >Object 和 Map 的比较 | MDN</a></p>
</li>
</ul>
<hr>
<h2 id="function">Function</h2>
<h3 id="new-function">new Function</h3>
<ul>
<li>语法: <code>let func = new Function ([arg1, arg2, ...argN], functionBody);</code></li>
<li>环境: 如果我们使用 new Function 创建一个函数，那么该函数的<code>[[Environment]]</code>并不指向当前的词法环境，而是指向全局环境,这样做的好处是避免了与使用压缩程序而产生冲突的问题</li>
<li>使用场景: 在复杂的 Web 应用程序中，我们需要从服务器获取代码或者动态地从模板编译函数时</li>
<li>参考: <a href="https://zh.javascript.info/new-function"  target="_blank" rel="noopener" >&ldquo;new Function&rdquo; 语法</a></li>
</ul>
<h3 id="将字符串转换为可执行的表达式的方式">将字符串转换为可执行的表达式的方式</h3>
<ol>
<li><code>eval()</code></li>
</ol>
<ul>
<li>可以执行包含 JavaScript 表达式的字符串。</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">expression</span> <span class="o">=</span> <span class="s2">&#34;2 + 2&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="nx">expression</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 输出: 4
</span></span></span></code></pre></div></li>
<li>注意：由于安全性和性能问题，它在现代 JavaScript 中并不推荐用于不受信任的输入，因为它会执行任意代码，可能引发安全漏洞。</li>
</ul>
<ol start="2">
<li><code>Function</code> 构造函数</li>
</ol>
<ul>
<li>可以将字符串转化为函数，并在调用时执行表达式。</li>
<li>比 <code>eval()</code> 更加安全，因为它不访问外部作用域。</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">expression</span> <span class="o">=</span> <span class="s2">&#34;return 2 + 2;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">func</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="nx">expression</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">func</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 输出: 4
</span></span></span></code></pre></div></li>
</ul>
<ol start="3">
<li>模板字符串与插值表达式</li>
</ol>
<ul>
<li>在模板字符串中使用插值可以直接执行 JavaScript 表达式：</li>
<li>虽然这不是直接将字符串解析为表达式的方式，但在编写包含表达式的字符串时非常有用，尤其是结合模板渲染。</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="sb">`</span><span class="si">${</span><span class="nx">a</span> <span class="o">+</span> <span class="nx">b</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 输出: 5
</span></span></span></code></pre></div></li>
</ul>
<ol start="4">
<li><code>setTimeout</code> / <code>setInterval</code></li>
</ol>
<ul>
<li><code>setTimeout</code> 和 <code>setInterval</code> 允许将字符串作为代码来执行</li>
<li>但这种方式与 <code>eval()</code> 类似，同样不推荐用于不受信任的输入</li>
<li>这种方式 JavaScript 中也不提倡，最好传递一个函数。</li>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">setTimeout</span><span class="p">(</span><span class="s2">&#34;console.log(&#39;Executed!&#39;)&#34;</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span></code></pre></div></li>
</ul>
<ol start="5">
<li><code>import()</code>（ES2020）
虽然 <code>import()</code> 是用于动态模块加载的，但它可以动态加载 JavaScript 模块文件，将其作为表达式执行。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span><span class="p">(</span><span class="s1">&#39;./module.js&#39;</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">module</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">module</span><span class="p">.</span><span class="nx">someFunction</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>虽然不是直接执行字符串表达式，但它可以动态引入外部代码模块。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>函数式编程学习</title>
      <link>https://ds63.eu.org/2024/learn_functional_paradigm/</link>
      <pubDate>Thu, 26 Sep 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_functional_paradigm/</guid>
      <description>自己学习过程中整理的关于函数式编程的知识点</description>
      <content:encoded><![CDATA[<h2 id="纯函数">纯函数</h2>
<p>以下内容摘自<a href="https://blog.orangex4.workers.dev/post/reversi/"  target="_blank" rel="noopener" >Reversi 黑白棋的前端界面与 AI 实现 | OrangeX4&rsquo;s Blog</a></p>
<blockquote>
<p>函数式编程有一个很重要的原则: 尽量使用纯函数 (pure function).</p>
<p>什么是纯函数? 纯函数就是, 给定相同的输入, 一定有相同的输出, 且没有任何副作用的函数. 数学函数就是真正的纯函数, 如三角函数 sin, 给定相同的输入 x, 一定会有相同的输出 y.</p>
<p>纯函数有什么好处呢? 可控, 没有副作用, 支持高并发, 可以很方便地缓存.</p>
<p>支持高并发是因为, 每个用户均有自己的数据, 他们不需要争夺对同一个数据的使用和修改权, 所以可以很方便地将纯函数部署到不同的服务器上, 而不用担心资源共享, 服务器通信和资源锁之类的麻烦问题.</p>
<p>而缓存就更为简单了, 这是一种用空间换时间的策略. 对于运算复杂耗时长的纯函数来说, 我们只需要, 在每一次运行这个函数时, 把 输入到输出的映射 记录在一个哈希表中, 下一次运行这个函数的时候, 可以先看看这个输入在不在哈希表中, 在的话, 直接使用表中的数据, 这就是缓存.</p>
</blockquote>
<p>缓存这个思路可运用的范围很广。</p>
<p>我还可以举一个例子，文生图网站的默认prompt,大部分新进用户如果想要尝试，很大可能会先直接使用默认参数进行生成，那么这默认的参数所生成的图片就可以缓存，后端直接发过去就是，而不用再生成。如果想更进一步节省成本，那可以将用户提供的参数进行hash，命中了就发对应的图片。</p>
<p>不少商用的大语言模型也提供了类似的选项。它会提供给用户是否使用缓存的选项，如果允许并且成功命中缓存，那么所需费用能大大节省。</p>
<hr>
<h2 id="偏函数">偏函数</h2>
<p>wip</p>
<hr>
<h2 id="柯里化curry">柯里化(curry)</h2>
<ul>
<li>把接收多参的函数转化成可以逐个调用单个参数并返回接收剩下参数的函数</li>
<li>JS实现
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">curry</span><span class="p">(</span><span class="nx">func</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">function</span> <span class="nx">curried</span><span class="p">(...</span><span class="nx">args</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;=</span> <span class="nx">func</span><span class="p">.</span><span class="nx">length</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// func.length：func的参数的数量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="c1">// 如果传入的 args 长度与原始函数所定义的（func.length）相同或者更长
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="k">return</span> <span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="nx">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="kd">function</span><span class="p">(...</span><span class="nx">args2</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 重新应用 curried，将之前传入的参数与新的参数一起传入。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">return</span> <span class="nx">curried</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="nx">args</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">args2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> 
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>上述代码的限制
<ol>
<li>函数具有固定数量的参数</li>
<li>使用 rest 参数的函数，例如 f(&hellip;args)，不能以这种方式进行柯里化</li>
</ol>
</li>
<li>另一种实现
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">curry</span><span class="p">(</span><span class="nx">fn</span><span class="p">,..</span><span class="nx">bindArgs</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(...</span><span class="nx">args</span><span class="p">)=&gt;{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">allArgs</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">bindArgs</span><span class="p">,...</span><span class="nx">args</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">allArgs</span><span class="p">.</span><span class="nx">length</span><span class="o">&lt;</span><span class="nx">fn</span><span class="p">.</span><span class="nx">length</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// func.length：func的参数的数量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="c1">// 如果传入的 args 长度与原始函数所定义的（func.length）相同或者更长
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="k">return</span> <span class="nx">curry</span><span class="p">(</span><span class="nx">fn</span><span class="p">,...</span><span class="nx">allArgs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">fn</span><span class="p">(...</span><span class="nx">allArgs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>实际使用：lodash 库的 _.curry</li>
<li>参考：<a href="https://zh.javascript.info/currying-partials"  target="_blank" rel="noopener" >柯里化（Currying）</a></li>
</ul>
<hr>
<h2 id="组合">组合</h2>
<ul>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 这里的withOne等函数应为纯函数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">X1</span> <span class="o">=</span> <span class="nx">withOne</span><span class="p">(</span><span class="nx">X</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">X2</span> <span class="o">=</span> <span class="nx">withTwo</span><span class="p">(</span><span class="nx">X1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">X3</span> <span class="o">=</span> <span class="nx">withThree</span><span class="p">(</span><span class="nx">X2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">SuperX</span> <span class="o">=</span> <span class="nx">X3</span><span class="p">;</span> <span class="c1">//最终的SuperX具备三个高阶组件的超能力
</span></span></span><span class="line"><span class="cl"><span class="c1">// 等价于
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">SuperX</span> <span class="o">=</span> <span class="nx">withThree</span><span class="p">(</span><span class="nx">withTwo</span><span class="p">(</span><span class="nx">withOne</span><span class="p">(</span><span class="nx">X</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 等价于
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">hoc</span> <span class="o">=</span> <span class="nx">compose</span><span class="p">(</span><span class="nx">withThree</span><span class="p">,</span> <span class="nx">withTwo</span><span class="p">,</span> <span class="nx">withOne</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">SuperX</span> <span class="o">=</span> <span class="nx">hoc</span><span class="p">(</span><span class="nx">X</span><span class="p">);</span>
</span></span></code></pre></div></li>
<li>参考实现</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">compose</span><span class="p">(...</span><span class="nx">funcs</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">funcs</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">arg</span> <span class="p">=&gt;</span> <span class="nx">arg</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">funcs</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">funcs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">funcs</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(...</span><span class="nx">args</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">a</span><span class="p">(</span><span class="nx">b</span><span class="p">(...</span><span class="nx">args</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/"  target="_blank" rel="noopener" >Introduction · 函数式编程指北</a></li>
<li><a href="https://tech.meituan.com/2022/10/13/dive-into-functional-programming-01.html"  target="_blank" rel="noopener" >深入理解函数式编程（上） - 美团技术团队</a></li>
<li><a href="https://blog.orangex4.workers.dev/post/reversi/"  target="_blank" rel="noopener" >Reversi 黑白棋的前端界面与 AI 实现 | OrangeX4&rsquo;s Blog</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之Event</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_event/</link>
      <pubDate>Wed, 25 Sep 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_event/</guid>
      <description>自己学习过程中整理的关于JavaScript中Event的知识点</description>
      <content:encoded><![CDATA[<h2 id="事件传播的-3-个阶段">事件传播的 3 个阶段</h2>
<ol>
<li>捕获阶段（Capturing phase）—— 事件（从 Window）向下走近元素。</li>
<li>目标阶段（Target phase）—— 事件到达目标元素。</li>
<li>冒泡阶段（Bubbling phase）—— 事件从元素上开始冒泡。</li>
</ol>
<hr>
<h2 id="冒泡">冒泡</h2>
<ul>
<li>参考<a href="https://zh.javascript.info/bubbling-and-capturing"  target="_blank" rel="noopener" >冒泡和捕获</a></li>
<li>当一个事件发生在一个元素上，它会首先运行在该元素上的处理程序，然后运行其父元素上的处理程序，然后一直向上到其他祖先上的处理程序。</li>
<li>引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过<code>event.target</code>访问</li>
<li>用于停止冒泡的方法
<ol>
<li><code>event.stopPropagation()</code>: 停止向上移动，但是当前元素上的其他处理程序都会继续运行</li>
<li><code>event.stopImmediatePropagation()</code> : 停止冒泡，且其他处理程序不会被执行。</li>
</ol>
</li>
<li><a href="https://zhuanlan.zhihu.com/p/164844013"  target="_blank" rel="noopener" >JavaScript 中那些不会冒泡的事件 - 知乎</a>
<ol>
<li>scroll</li>
<li>blur &amp; focus</li>
<li>media事件</li>
<li>mouseLeave &amp; mouseEnter</li>
<li>注意：mouseout/mouseover <strong>会触发</strong>冒泡</li>
</ol>
</li>
</ul>
<hr>
<h2 id="preventdefault">preventDefault</h2>
<ul>
<li>参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault"  target="_blank" rel="noopener" >Event：preventDefault() 方法 - Web API 接口参考 | MDN</a></li>
<li>如果此事件没有被显式处理，它默认的动作也不应该照常执行</li>
<li>此事件还是继续传播，除非碰到事件监听器调用 stopPropagation() 或 stopImmediatePropagation()，才停止传播</li>
<li>示例:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;beforeunload&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Cancel the event as stated by the standard.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Chrome requires returnValue to be set.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">event</span><span class="p">.</span><span class="nx">returnValue</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><hr>
<h2 id="addeventlistener">addEventListener</h2>
<h3 id="语法">语法</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">listener</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">listener</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">listener</span><span class="p">,</span> <span class="nx">useCapture</span><span class="p">)</span> <span class="c1">//旧版本的 DOM 的规定
</span></span></span></code></pre></div><h3 id="options"><code>options</code></h3>
<ul>
<li>capture:boolean</li>
<li>once:boolean</li>
<li>passive:boolean True -&gt; preventDefault() 不会被调用</li>
<li>signal</li>
</ul>
<h3 id="注意">注意</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener#%E5%A4%84%E7%90%86%E8%BF%87%E7%A8%8B%E4%B8%AD_this_%E7%9A%84%E5%80%BC%E7%9A%84%E9%97%AE%E9%A2%98"  target="_blank" rel="noopener" >处理过程中 this 的值的问题 | MDN</a></li>
<li>同一个元素节点注册了多个相同的 EventListener，那么重复的实例会被抛弃。这么做不会让得 EventListener 被重复调用，也不需要用 removeEventListener 手动清除多余的 EventListener，因为重复的都被自动抛弃了。</li>
<li>只是针对于命名函数。对于匿名函数，浏览器会将其看做不同的 EventListener</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener"  target="_blank" rel="noopener" >EventTarget: addEventListener() method - Web APIs | MDN</a></li>
<li><a href="https://www.cnblogs.com/mengfangui/p/11322590.html"  target="_blank" rel="noopener" >滚动事件优化 passive - 孟繁贵 - 博客园</a></li>
<li><a href="https://github.com/pro-collection/interview-question/issues/76"  target="_blank" rel="noopener" >JS 内存泄露问题该如何排查？ · Issue #76 · pro-collection/interview-question</a></li>
</ul>
<hr>
<h2 id="removeeventlistener">removeEventListener</h2>
<ul>
<li>如果同一个事件监听器分别为“事件捕获（capture 为 true）”和“事件冒泡（capture 为 false）”注册了一次，这两个版本的监听器需要分别移除。移除捕获监听器不会影响非捕获版本的相同监听器，反之亦然。</li>
<li><code>options</code>只有 capture 配置影响 removeEventListener()</li>
<li>参考<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener"  target="_blank" rel="noopener" >EventTarget: removeEventListener() method - Web APIs | MDN</a></li>
</ul>
<hr>
<h2 id="事件委托">事件委托</h2>
<h3 id="概念">概念</h3>
<ul>
<li>事件处理模式之一,也称事件代理</li>
<li>对于许多以类似方式处理的元素，不必为每个元素分配一个处理程序，而是将单个处理程序放在它们的共同祖先上</li>
<li>在处理程序中，我们获取<code>event.target</code>以查看事件实际发生的位置并进行处理。</li>
</ul>
<h3 id="优点">优点:</h3>
<ol>
<li>减少事件注册，提升性能</li>
<li>简化了dom节点更新时，相应事件的更新</li>
</ol>
<h3 id="缺点">缺点:</h3>
<ol>
<li>基于冒泡，对于不冒泡的事件不支持</li>
<li>层级过多，冒泡过程中，可能会被某层阻止掉。</li>
<li>理论上委托会导致浏览器频繁调用处理函数，虽然很可能不需要处理。所以建议就近委托，比如在table上代理td，而不是在document上代理td</li>
</ol>
<h3 id="react中的事件委托">React中的事件委托</h3>
<ul>
<li>React 借鉴事件委托的方式将大部分事件委托给了 Document 对象</li>
<li>事件委托需要区分捕获和冒泡，有些事件由于没有冒泡过程，只能在捕获阶段进行事件委托</li>
<li>没有进行委托的事件是<code>Form</code>事件和<code>Media</code>事件，原因是这些事件针对特性类型元素，委托意义不大，React 将其直接注册到了目标对象</li>
<li>React 中的事件分为 3 类。
<ol>
<li>DiscreteEvent：click，blur,focus,submit,tuchStart 等。优先级最低。</li>
<li>UserBlockingEvent：touchMove,mouseMove,scroll,drag,dragOver 等。这些事件会阻塞用户的交互，优先级次之</li>
<li>ContinuousEvent：load,error,loadStart,abort,animationend 等。优先级最高，不会被打断。</li>
</ol>
</li>
</ul>
<h3 id="示例">示例</h3>
<ul>
<li>html
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>Exercise<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>Write code<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>Play music<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>Relax<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>css
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">list</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;ul&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">list</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;click&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nx">ev</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">ev</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">tagName</span> <span class="o">===</span> <span class="s2">&#34;LI&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">ev</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">toggle</span><span class="p">(</span><span class="s2">&#34;done&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://zh.javascript.info/event-delegation"  target="_blank" rel="noopener" >事件委托</a></li>
<li><a href="https://juejin.cn/post/6844903589052153869"  target="_blank" rel="noopener" >js中的事件委托或事件代理详解 - 掘金</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/165089379"  target="_blank" rel="noopener" >React 中的事件委托 - 知乎</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/165089379"  target="_blank" rel="noopener" >React 中的事件委托 - 知乎</a></li>
</ul>
<hr>
<h2 id="settimeout">setTimeout</h2>
<ul>
<li>参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/setTimeout"  target="_blank" rel="noopener" >setTimeout() 全局函数 - Web API 接口参考 | MDN</a></li>
<li>参数:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">timeoutID</span> <span class="o">=</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">func</span><span class="p">,</span> <span class="p">[</span><span class="nx">delay</span><span class="p">,</span> <span class="nx">arg1</span><span class="p">,</span> <span class="nx">arg2</span><span class="p">,</span> <span class="p">...]);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// timeoutID 可用来作为 clearTimeout() 的参数来清除对应的定时器
</span></span></span><span class="line"><span class="cl"><span class="c1">// arg1, ..., argN 可选  当计时结束的时候，将被传递给 func 函数的附加参数。
</span></span></span></code></pre></div></li>
<li>func应是对函数的引用，示例:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">sayHi</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;Hello&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 正确
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">setTimeout</span><span class="p">(</span><span class="nx">sayHi</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 错的！
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">setTimeout</span><span class="p">(</span><span class="nx">sayHi</span><span class="p">(),</span> <span class="mi">1000</span><span class="p">);</span> <span class="c1">//这样传入的是sayHi函数的执行结果:undefined
</span></span></span></code></pre></div><ul>
<li><code>delay</code>默认为0，代表了消息被实际加入到队列的<strong>最小延迟时间</strong>。如果队列中没有其他消息并且栈为空，在这段延迟时间过去之后，消息会被马上处理。</li>
<li>在默认情况下，在 <code>setTimeout()</code> 内部，this 关键字将被设置为 globalThis，在浏览器中它是 window 对象</li>
<li>setTimeout为啥不准（线程间通信怎么都会有延迟的）</li>
<li>定时器原理setTimeout/setInterval（以前翻过v8的源码，本质上都是二叉堆，与react里的scheduler的实现有异曲同工之处）</li>
</ul>
<hr>
<h2 id="setinterval">setInterval</h2>
<ul>
<li>
<p>参数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">intervalID</span> <span class="o">=</span> <span class="nx">setInterval</span><span class="p">(</span><span class="nx">func</span><span class="p">,</span> <span class="p">[</span><span class="nx">delay</span><span class="p">,</span> <span class="nx">arg1</span><span class="p">,</span> <span class="nx">arg2</span><span class="p">,</span> <span class="p">...]);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// intervalID 可用来作为 clearInterval() 的参数来清除对应的定时器
</span></span></span><span class="line"><span class="cl"><span class="c1">// arg1, ..., argN 可选  当计时结束的时候，将被传递给 func 函数的附加参数。
</span></span></span></code></pre></div></li>
<li>
<p>每间隔给定的时间周期性执行,时间开始计算的位置是调用内部方法的那一刻，因此第一次方法结束到第二次开始之间的时间间隔其实是小于delay的</p>
</li>
<li>
<p>如果setInterval的内部函数执行耗时大于设定的时间间隔,会发生什么？</p>
<ul>
<li>a: JavaScript 引擎会等待 func 执行完成，然后检查调度程序，如果时间到了，则 立即 再次执行它。极端情况下，如果函数每次执行时间都超过 delay 设置的时间，那么每次调用之间将完全没有停顿。</li>
<li>解决办法: 嵌套的 setTimeout
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// setInterval
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">setInterval</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">func</span><span class="p">(</span><span class="nx">i</span><span class="o">++</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span><span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 嵌套的setTimeout
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="nx">run</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">func</span><span class="p">(</span><span class="nx">i</span><span class="o">++</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">run</span><span class="p">,</span><span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span><span class="mi">100</span><span class="p">)</span>
</span></span></code></pre></div></li>
</ul>
</li>
<li>
<p>参考:</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/setInterval"  target="_blank" rel="noopener" >setInterval() - Web API 接口 | MDN</a></li>
<li><a href="https://zh.javascript.info/settimeout-setinterval"  target="_blank" rel="noopener" >调度：setTimeout 和 setInterval</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="事件循环">事件循环</h2>
<h3 id="三种数据结构">三种数据结构：</h3>
<ol>
<li>stack: 函数调用形成了一个由若干帧组成的栈</li>
<li>heap: 对象被分配在堆中</li>
<li>queue: 一个待处理消息的消息队列。每一个消息都关联着一个用以处理这个消息的回调函数</li>
</ol>
<h3 id="两种任务">两种任务</h3>
<ul>
<li>
<p>JavaScript 的异步任务根据事件分类分为两种：宏任务（MacroTask）和微任务（MicroTask）</p>
</li>
<li>
<p>宏任务</p>
<ul>
<li>I/O（Mouse Events、Keyboard Events、Network Events）</li>
<li>setTimeout、setInterval、setImmediate</li>
<li>UI Rendering（HTML Parsing）</li>
<li>MessageChannel</li>
<li>JavaScript Run</li>
</ul>
</li>
<li>
<p>微任务</p>
<ul>
<li>DOM mutations</li>
<li>Promises</li>
</ul>
</li>
<li>
<p>优先级</p>
<ul>
<li>宏任务的优先级高于微任务</li>
<li>每个宏任务执行完毕后都必须将当前的微任务队列清空</li>
</ul>
</li>
<li>
<p>如何安排（schedule）一个新的宏任务：</p>
<ul>
<li>可使用零延迟的 setTimeout(f)</li>
<li>好处
<ol>
<li>将繁重的计算任务拆分成多个部分，以使浏览器能够对用户事件作出反应，并在任务的各部分之间显示任务进度。</li>
<li>也被用于在事件处理程序中，将一个行为（action）安排（schedule）在事件被完全处理（冒泡完成）后。</li>
</ol>
</li>
</ul>
</li>
<li>
<p>如何安排一个新的 微任务：</p>
<ul>
<li>可以使用 queueMicrotask 来在保持环境状态一致的情况下，异步地执行一个函数。</li>
<li>如果我们想要异步执行（在当前代码之后）一个函数，但是要在更改被渲染或新事件被处理之前执行，那么我们可以使用 queueMicrotask 来对其进行安排（schedule）。</li>
</ul>
</li>
</ul>
<h3 id="浏览器中的事件循环和nodejs中事件循环的区别">浏览器中的事件循环和Node.js中事件循环的区别</h3>
<ul>
<li>浏览器是一个宏任务+一个微任务队列</li>
<li>node是一个宏任务队列+一个微任务队列</li>
</ul>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://tsejx.github.io/javascript-guidebook/core-modules/executable-code-and-execution-contexts/concurrency-model/event-loop/"  target="_blank" rel="noopener" >事件循环 - JavaScript Guidebook</a></li>
<li><a href="https://juejin.cn/post/6844903655473152008"  target="_blank" rel="noopener" >浅析setTimeout与Promise - 掘金</a></li>
<li><a href="https://www.jsv9000.app/"  target="_blank" rel="noopener" >JS Visualizer 9000</a></li>
<li><a href="https://developer.aliyun.com/article/1312240"  target="_blank" rel="noopener" >浏览器中的事件循环和Node.js中事件循环的区别(经典面试题)-阿里云开发者社区</a></li>
</ul>
<hr>
<h2 id="面试问题">面试问题</h2>
<ol>
<li>实现一个事件处理对象，包括绑定，取消，执行功能
思路:构造函数里面初始化一个空对象，存储事件名。绑定，取消(对应置空)就在这个数组里面操作。执行先判断是否存在，然后调用apply函数执行回调。</li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>初识seo</title>
      <link>https://ds63.eu.org/2024/the_first_take_of_seo/</link>
      <pubDate>Thu, 12 Sep 2024 23:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/the_first_take_of_seo/</guid>
      <description>永远在路上</description>
      <content:encoded><![CDATA[<h2 id="seo的分类">seo的分类</h2>
<ul>
<li>On-Page: 网站的内容
<ol>
<li>Title Tags</li>
<li>Headings (H1)</li>
<li>Fast-loading pages, or page load speed</li>
<li>Page content</li>
<li>URL structure</li>
</ol>
</li>
<li>Off-page: 网站的权威性和流行性外部因素</li>
</ul>
<hr>
<h2 id="有什么改善读者体验和-seo-的写作技巧">有什么改善读者体验和 SEO 的写作技巧?</h2>
<blockquote>
<ul>
<li>扩展主题</li>
<li>在文章头部包含关键词</li>
<li>围绕主题和关键词展开内容</li>
<li>语义化元素: HTML5 的语义化，意思是用正确的元素做正确的事</li>
<li>改善链接的形式: 尽量为链接提供完整的标题、或者可被识别的提示</li>
</ul>
</blockquote>
<hr>
<h2 id="keywords有必要吗">keywords有必要吗?</h2>
<p>Google 在<a href="https://developers.google.com/search/blog/2009/09/google-does-not-use-keywords-meta-tag?hl=zh-cn"  target="_blank" rel="noopener" >Google 不会将关键字元标记用于网页排名  |  Google 搜索中心博客  |  Google for Developers</a>一文中已经明确表示<code>meta[name=keywords]</code>不再影响排名和权重,但是这并不是说关键词不重要，恰恰相反，搜索引擎是在鼓励你将你的关键词融入你的文章中，因为它们已经会用语义分析寻找关键词了。</p>
<hr>
<h2 id="怎么添加可分享的卡片">怎么添加可分享的卡片?</h2>
<ul>
<li><a href="https://github.com/frostming/fxzhihu"  target="_blank" rel="noopener" >frostming/fxzhihu: 为知乎生成可分享的卡片及 Instant View</a></li>
<li><a href="https://www.npmjs.com/package/react-helmet-async"  target="_blank" rel="noopener" >react-helmet-async - npm</a></li>
</ul>
<hr>
<h2 id="spa能做seo优化吗">spa能做seo优化吗?</h2>
<ul>
<li>能，可将爬虫引入到事先用puppeteer为SPA Prerender的内容服务中</li>
<li>流程
<ol>
<li>识别请求是用户还是搜索引擎爬虫</li>
<li>如果是用户，那就正常处理</li>
<li>如果是爬虫，那就基于puppeteer渲染SPA内容</li>
</ol>
</li>
<li>需要考虑的问题
<ol>
<li>缓存
<ul>
<li>缓存多少</li>
<li>缓存多久更新</li>
</ul>
</li>
<li>冷启动（指的是在生成有效网页之后，请求页面）可以提前在B端产生有效的网址的时候，让Prerender服务提前缓存内容</li>
</ol>
</li>
<li>较成熟的方案
<ul>
<li><a href="https://prerender.io/"  target="_blank" rel="noopener" >Prerender Seamlessly Renders JavaScript for Faster Indexing</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://mazzzystar.github.io/2023/07/23/Get-users-for-your-AI-tool-from-Google-search-zh/"  target="_blank" rel="noopener" >让你的AI工具从Google搜索中获得用户 | TL;DR</a></li>
<li><a href="https://blog.skk.moe/post/how-to-write-for-seo/"  target="_blank" rel="noopener" >如何写一篇同时面向人和搜索引擎的文章 | Sukka&rsquo;s Blog</a></li>
<li><a href="https://medium.com/@keshidong.dev/%E5%85%B3%E4%BA%8Espa%E7%9A%84seo%E4%BC%98%E5%8C%96%E6%96%B9%E6%A1%88-2639a63361ad"  target="_blank" rel="noopener" >关于SPA的SEO解决方案. 为什么SPA需要SEO优化 | by shidong ke | Medium</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>React网页定制title</title>
      <link>https://ds63.eu.org/2024/add-specific-title-to-react-web-app/</link>
      <pubDate>Mon, 02 Sep 2024 00:20:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/add-specific-title-to-react-web-app/</guid>
      <description>变变变</description>
      <content:encoded><![CDATA[<h2 id="需求">需求</h2>
<p>一个使用react+react-router-dom的网页，希望不同的页面能有不同的title</p>
<h2 id="方法一--useeffect--documenttitle">方法一 : useEffect + document.title</h2>
<ul>
<li>主要思路: 监听url的变化，然后设置document.title,不同的写法差异主要在如何监听</li>
</ul>
<h3 id="写法一uselocation">写法一：useLocation()</h3>
<ul>
<li>简易的写法可以看<a href="https://stackoverflow.com/a/65709116"  target="_blank" rel="noopener" >Stack Overflow的这个回答</a></li>
<li>更进一步的写法可以看<a href="https://juejin.cn/post/7267409589079867450"  target="_blank" rel="noopener" >react-router-dom v6 路由实现动态修改document.title项目中需要在对应的路由界面 设置不同 - 掘金</a></li>
</ul>
<h3 id="写法二usematches">写法二：useMatches()</h3>
<ul>
<li>参考<a href="https://stackoverflow.com/a/78184012"  target="_blank" rel="noopener" >steinybot在Stack Overflow的这个回答</a></li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">matches</span> <span class="o">=</span> <span class="nx">useMatches</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">handle</span><span class="p">,</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">matches</span><span class="p">[</span><span class="nx">matches</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">handle</span> <span class="o">&amp;&amp;</span> <span class="nx">handle</span><span class="p">.</span><span class="nx">title</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">title</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nb">document</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="nx">title</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">title</span><span class="p">])</span>
</span></span></code></pre></div><ul>
<li><a href="https://reactrouter.com/en/main/hooks/use-matches"  target="_blank" rel="noopener" >useMatches v6.26.1 | React Router</a></li>
</ul>
<h2 id="方法二">方法二</h2>
<ul>
<li>使用<a href="https://www.npmjs.com/package/react-helmet-async"  target="_blank" rel="noopener" >react-helmet-async - npm</a></li>
<li>好处
<ol>
<li>代码修改小，只要在需要的地方加上就行</li>
<li>顺便能把seo也做了</li>
<li>还能支持Open Graph protocol等协议</li>
</ol>
</li>
<li>报错：<code>TypeError: Cannot read properties of undefined (reading 'add')</code>
<ul>
<li>问题其实出在我没加<code>&lt;HelmetProvider&gt;</code>,但这个报错太不友好了,有个建议优化报错信息的issue，<a href="https://github.com/staylor/react-helmet-async/issues/228"  target="_blank" rel="noopener" ><code>TypeError: Cannot read properties of undefined (reading 'add')</code> thrown when provider is missing · Issue #228 · staylor/react-helmet-async</a>，不过没被处理。</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://www.freecodecamp.org/news/react-helmet-examples/"  target="_blank" rel="noopener" >How to Use React Helmet – With Example Use Case</a></li>
</ul>
</li>
</ul>
<h2 id="补充">补充</h2>
<h3 id="open-graph-protocol">Open Graph protocol</h3>
<p><a href="https://ogp.me/"  target="_blank" rel="noopener" >The Open Graph protocol</a></p>
<h3 id="twitter-cards">Twitter Cards</h3>
<p><a href="https://developer.x.com/en/docs/x-for-websites/cards/guides/getting-started"  target="_blank" rel="noopener" >Getting started with Cards | Docs | Twitter Developer Platform</a></p>
<h3 id="生成">生成</h3>
<p><a href="https://github.com/frostming/fxzhihu/tree/main"  target="_blank" rel="noopener" >frostming/fxzhihu: 为知乎生成可分享的卡片及 Instant View</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>json的序列化与反序列化</title>
      <link>https://ds63.eu.org/2024/serialization_and_deserialization/</link>
      <pubDate>Fri, 23 Aug 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/serialization_and_deserialization/</guid>
      <description>整理JavaScript知识点时发现内容还挺多，于是干脆独立出来</description>
      <content:encoded><![CDATA[<h2 id="基本概念">基本概念</h2>
<ul>
<li>
<p>序列化</p>
<ul>
<li>将json对象转换为字符串“序列”</li>
<li><code>JSON.stringify(value, replacer, space)</code></li>
<li>可通过修改对象的toJSON属性，来进一步控制</li>
</ul>
</li>
<li>
<p>反序列化</p>
<ul>
<li>将字符串“序列”转换为json对象</li>
<li><code>JSON.parse(text, reviver)</code></li>
</ul>
</li>
</ul>
<h2 id="jsonstringify的特殊情况">JSON.stringify()的特殊情况</h2>
<ol>
<li>undefined、任意的函数以及 symbol 值在序列化过程中有两种情况
<ul>
<li>被忽略（出现在非数组对象的属性值中时）</li>
<li>被转换成 null（出现在数组中时）。</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="nx">a</span><span class="o">:</span><span class="k">new</span> <span class="nb">Function</span><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#39;{}&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">([</span><span class="k">new</span> <span class="nb">Function</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="c1">// &#39;[null]&#39;
</span></span></span></code></pre></div></li>
<li>函数、undefined 被<strong>单独转换</strong>时，会返回 undefined。
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="kd">function</span><span class="p">())</span> <span class="nx">or</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="kc">undefined</span><span class="p">).</span>
</span></span></code></pre></div></li>
<li>Date 日期调用了 toJSON() 将其转换为了 string 字符串（同 Date.toISOString()），因此会被当做字符串处理。</li>
<li>其他类型的对象，包括 Map/Set/WeakMap/WeakSet，仅会序列化可枚举的属性。</li>
</ol>
<h2 id="reviver的理解">reviver的理解</h2>
<h3 id="一个出乎我意料的例子">一个出乎我意料的例子</h3>
<p>粗略扫了遍文档，我以为我已经完全掌握了序列化和反序列化，但
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse"  target="_blank" rel="noopener" >JSON.parse() - JavaScript | MDN</a>给了一个出乎我意料的例子:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">transformedObj1</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="s1">&#39;[1,5,{&#34;s&#34;:1}]&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="s2">&#34;object&#34;</span> <span class="o">?</span> <span class="kc">undefined</span> <span class="o">:</span> <span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">transformedObj1</span><span class="p">);</span> <span class="c1">// undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="c1">// const message = [1,2,3] 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// console.log(typeof message) //object
</span></span></span></code></pre></div><p>按照我的理解，我以为最终结果会是<code>[1,5]</code>。看来自己还是图样，于是请教了ChatGPT老师。</p>
<h3 id="reviver函数的概念">reviver函数的概念</h3>
<ol>
<li>
<p>执行顺序
<code>JSON.parse</code> 解析 JSON 字符串时，<code>reviver</code> 函数会以深度优先的顺序处理每个键值对。即它会先解析嵌套的对象或数组中的值，然后再解析外层对象或数组。</p>
</li>
<li>
<p>key 和 value 的含义
key: 当前被处理的键（对于数组，key 是索引，最外层对象的 key 是空字符串 &ldquo;&quot;）。
value: 当前被处理的值，这个值可以是一个基本数据类型（如字符串、数字）或复杂的对象、数组。</p>
</li>
<li>
<p>可以通过以下例子来理解：</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="s1">&#39;{&#34;a&#34;: 1, &#34;b&#34;: {&#34;c&#34;: 2, &#34;d&#34;: 3}, &#34;e&#34;: [4, 5]}&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`key: </span><span class="si">${</span><span class="nx">key</span><span class="si">}</span><span class="sb">, value: </span><span class="si">${</span><span class="nx">value</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">key: a, value: 1
</span></span></span><span class="line"><span class="cl"><span class="cm">key: c, value: 2
</span></span></span><span class="line"><span class="cl"><span class="cm">key: d, value: 3
</span></span></span><span class="line"><span class="cl"><span class="cm">key: b, value: [object Object]
</span></span></span><span class="line"><span class="cl"><span class="cm">key: 0, value: 4
</span></span></span><span class="line"><span class="cl"><span class="cm">key: 1, value: 5
</span></span></span><span class="line"><span class="cl"><span class="cm">key: e, value: 4,5
</span></span></span><span class="line"><span class="cl"><span class="cm">key: , value: [object Object]
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><h3 id="回到刚才的例子">回到刚才的例子</h3>
<p>理解了reviver回调函数，我就对刚才的例子没有疑问了。</p>
<p>reviver函数里的这段代码执行了五次，而最后的key为<code>&quot;&quot;</code>,value则为<code>[1,5,{&quot;s&quot;:1}]</code>。因为在 JavaScript 中，数组（Array）是 object 的一种特殊类型,因此最终结果是<code>undefined</code></p>
<p>而如果想要符合我一开始认为的结果，代码应该这样写：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">transformedObj1</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="s1">&#39;[1,5,{&#34;s&#34;:1}]&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span><span class="p">(</span><span class="nx">key</span><span class="o">!==</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="s2">&#34;object&#34;</span> <span class="o">?</span> <span class="kc">undefined</span> <span class="o">:</span> <span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">value</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">transformedObj1</span><span class="p">);</span>
</span></span></code></pre></div><h2 id="jsonparsejsonstringifyobj">JSON.parse(JSON.stringify(obj))</h2>
<p>我第一次读到这行代码的时候还觉得奇怪，为什么要这样写，顺手就想改掉。想了下才意识到这是为了实现深拷贝。</p>
<h3 id="优点">优点</h3>
<ul>
<li>代码简单</li>
<li>JSON.stringify内部做了循环引用的检测，正是我们上面提到破解循环引用</li>
</ul>
<h3 id="局限性">局限性</h3>
<p>但这样写好吗？搜索后我发现有两篇文章将它的局限性写得很透彻了。</p>
<ul>
<li><a href="https://segmentfault.com/a/1190000018495737"  target="_blank" rel="noopener" >javascript - 关于JSON.parse()和JSON.stringify()的性能小测试 - 超级有温度的代码 - SegmentFault 思否</a></li>
<li><a href="https://segmentfault.com/a/1190000020297508"  target="_blank" rel="noopener" >javascript - 关于 JSON.parse(JSON.stringify(obj)) 实现深拷贝的一些坑 - 超级有温度的代码 - SegmentFault 思否</a></li>
</ul>
<p>我将其中的主要内容摘录如下：</p>
<ol>
<li>只适用于一般数据的拷贝(结合上文，可以发现这里的问题主要来自JSON.stringify对特殊情况的处理)</li>
</ol>
<blockquote>
<p>1.如果json里面有时间对象，则序列化结果：时间对象=&gt;字符串的形式；
2.如果json里有RegExp、Error对象，则序列化的结果将只得到空对象 RegExp、Error =&gt; {}；
3.如果json里有 function,undefined，则序列化的结果会把 function,undefined 丢失；
4.如果json里有NaN、Infinity和-Infinity，则序列化的结果会变成null；
5.如果json里有对象是由构造函数生成的，则序列化的结果会丢弃对象的 constructor；
6.如果对象中存在循环引用的情况也无法实现深拷贝</p>
</blockquote>
<ol start="2">
<li>性能问题：</li>
</ol>
<blockquote>
<p>能不用JSON.parse()和JSON.stringify()就不用，采用替代方案且性能更优的。PS：特别是需要多次执行的代码块或是这个JSON数据比较庞大时</p>
</blockquote>
<p>这里的第二点我深有体会，之前我便写过这样一段代码，它将一张100kb左右的图片转码为base64，塞进了json中，并序列化为字符串进行传输，接收端再将其反序列化后提取出来。后来重构代码时，这一段代码就成了提升性能的一大突破口。</p>
<h3 id="替代方案">替代方案</h3>
<p><a href="https://segmentfault.com/a/1190000016672263#item-1"  target="_blank" rel="noopener" >javascript - 深拷贝的终极探索（99%的人都不知道） - 颜海镜 - SegmentFault 思否</a></p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse"  target="_blank" rel="noopener" >JSON.parse() - JavaScript | MDN</a></li>
<li><a href="https://segmentfault.com/a/1190000018495737"  target="_blank" rel="noopener" >javascript - 关于JSON.parse()和JSON.stringify()的性能小测试 - 超级有温度的代码 - SegmentFault 思否</a></li>
<li><a href="https://segmentfault.com/a/1190000020297508"  target="_blank" rel="noopener" >javascript - 关于 JSON.parse(JSON.stringify(obj)) 实现深拷贝的一些坑 - 超级有温度的代码 - SegmentFault 思否</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>拉取历史消息的实现</title>
      <link>https://ds63.eu.org/2024/implementation_of_pulling_historical_messages/</link>
      <pubDate>Tue, 20 Aug 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/implementation_of_pulling_historical_messages/</guid>
      <description>实现拉取历史消息时踩过的坑</description>
      <content:encoded><![CDATA[<h2 id="存在问题">存在问题</h2>
<p>聊天页有个功能需求：下拉加载历史记录。</p>
<p>这样的需求很自然，而且日常使用中也随处可见，但真正要自己去实现，还是遇到了不少问题。</p>
<p>一个基础的思路是：</p>
<ol>
<li>监听下拉操作，下拉结束后从后端获取历史记录并将其放进聊天记录数组</li>
<li>新获取的历史记录会将你刚刚看的信息挤下去，这时你要往上拉才能回到你刚刚看的信息。</li>
<li>虽然可以通过获取刚看的那条信息的位置，等历史记录拉取下来后再通过改变滚动条回到其原来的位置，但这样会让页面出现闪动，信息会先下去，然后再上来。</li>
</ol>
<hr>
<h2 id="intersectionobserver">IntersectionObserver</h2>
<ul>
<li><a href="https://mp.weixin.qq.com/s/vhpXEaumPp5VvR7Zt9jGkQ"  target="_blank" rel="noopener" >不到20行js实现高性能图片懒加载</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver"  target="_blank" rel="noopener" >IntersectionObserver - Web APIs | MDN</a></li>
<li><a href="https://medium.com/strise/making-use-of-observers-in-react-a29b1fd05fa7"  target="_blank" rel="noopener" >Making use of Observers in React. Ever needed to manipulate the DOM when… | by Jens Lind | Strise | Medium</a></li>
<li><a href="https://dev.to/hey_yogini/infinite-scrolling-in-react-with-intersection-observer-22fh"  target="_blank" rel="noopener" >Infinite scrolling in React with intersection observer - DEV Community</a></li>
</ul>
<hr>
<h2 id="滚动到对应位置">滚动到对应位置</h2>
<ul>
<li><a href="https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback"  target="_blank" rel="noopener" >Manipulating the DOM with Refs – React</a></li>
</ul>
<hr>
<h2 id="overflow-anchor">overflow-anchor</h2>
<ul>
<li><a href="https://juejin.cn/post/7112349799373864996"  target="_blank" rel="noopener" >解决聊天页下拉加载历史记录，新获取的历史记录把刚看的信息挤下去的问题 - 掘金</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-anchor"  target="_blank" rel="noopener" >overflow-anchor - CSS: Cascading Style Sheets | MDN</a></li>
<li><a href="https://css-tricks.com/almanac/properties/o/overflow-anchor/"  target="_blank" rel="noopener" >Overflow-anchor | CSS-Tricks</a></li>
</ul>
<blockquote>
<p>Scroll Anchoring is a browser feature that attempts to prevent a common situation where you may scroll down a webpage before the DOM has fully loaded and, when it does, any elements that load above your current location push you further down the page.</p>
</blockquote>
<hr>
<h2 id="反向渲染">反向渲染</h2>
<p>这个设计很妙，但我没有使用。</p>
<p><a href="https://www.alloyteam.com/2020/04/14349/comment-page-1/#comments"  target="_blank" rel="noopener" >前端开发中聊天场景的体验优化 | AlloyTeam</a></p>
<hr>
<h2 id="计算并设置正确的滚动位置">计算并设置正确的滚动位置</h2>
<ul>
<li>
<p><a href="https://cloud.tencent.com/developer/article/2176884"  target="_blank" rel="noopener" >React中将一直增加消息的滚动框保持在当前浏览的位置-腾讯云开发者社区-腾讯云</a></p>
</li>
<li>
<p><a href="https://www.zhangxinxu.com/wordpress/2018/02/container-scroll-position-hold/"  target="_blank" rel="noopener" >小tips: 滚动容器尺寸变化子元素视觉上位置不变JS实现 « 张鑫旭-鑫空间-鑫生活</a></p>
</li>
</ul>
<hr>
<h2 id="位置不对">位置不对</h2>
<p>最终滚动到的位置和预期位置不对应。排查后发现是图片没有占位符导致的。</p>
<p>可参考<a href="https://www.shymean.com/article/%E5%89%8D%E7%AB%AF%E4%BD%93%E9%AA%8C%E4%BC%98%E5%8C%96%E4%B9%8B%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E9%97%AA%E7%83%81"  target="_blank" rel="noopener" >前端体验优化之图片加载闪烁 | ShyMean</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>ssh连接二三事</title>
      <link>https://ds63.eu.org/2024/things_about_ssh/</link>
      <pubDate>Sat, 17 Aug 2024 23:15:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/things_about_ssh/</guid>
      <description>some thing about ssh</description>
      <content:encoded><![CDATA[<h2 id="免密登录">免密登录</h2>
<ol>
<li>将公钥添加到 <code>~/.ssh/authorized_keys </code></li>
<li>添加权限: <code>chmod 600 ~/.ssh/authorized_keys</code>, <code>chmod 700 ~/.ssh</code></li>
<li>登录: <code>ssh username@server_ip</code></li>
</ol>
<h2 id="github相关">Github相关</h2>
<ul>
<li>
<p>作用：use SSH to perform Git operations in repositories on GitHub.com</p>
</li>
<li>
<p>步骤:</p>
<ol>
<li><a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key"  target="_blank" rel="noopener" >Generating a new SSH key and adding it to the ssh-agent - GitHub Docs</a></li>
</ol>
<p><code>ssh-keygen -t ed25519 -C &quot;your_email@example.com&quot;</code>
2. <a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key"  target="_blank" rel="noopener" >Generating a new SSH key and adding it to the ssh-agent - GitHub Docs</a>
3. Testing your SSH connection: <code>ssh -T git@github.com</code>
4. <a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account"  target="_blank" rel="noopener" >Adding a new SSH key to your GitHub account - GitHub Docs</a></p>
</li>
</ul>
<h2 id="使用端口转发来远程连接内网的机器">使用端口转发来远程连接内网的机器</h2>
<ul>
<li>涉及到三台机器，身边的电脑a，具有公网ip的机器b，远程需要被访问的电脑c</li>
<li>核心思想: 使用一台能被双方访问得到的公网机器作为代理</li>
<li>步骤:
<ol>
<li>电脑c需要执行<code>ssh -oPort=22 -CNfg -R 40000:localhost:22 root@公网ip -oPort</code></li>
<li>使用电脑a通过ssh登陆到机器b，再通过ssh连接本地40000端口，这样就相当于连接到了电脑c的22端口</li>
</ol>
</li>
<li>参考: <a href="https://blog.fatedier.com/2015/07/22/ssh-port-forwarding/"  target="_blank" rel="noopener" >SSH 端口转发</a></li>
</ul>
<h2 id="持续部署">持续部署</h2>
<ul>
<li><a href="https://github.com/webfactory/ssh-agent"  target="_blank" rel="noopener" >webfactory/ssh-agent: GitHub Action to setup <code>ssh-agent</code> with a private key</a>这个action可以用来在GitHub Action进行ssh连接。</li>
<li>不过考虑到安全问题，最好是是利用SSHD来限制可执行的指令, 具体参见<a href="https://blog.caomingjun.com/secure-ssh-continuous-deployment-with-forcecommand/"  target="_blank" rel="noopener" >安全地使用 SSH 进行持续部署 - Cmj&rsquo;s Blog</a></li>
</ul>
<h2 id="id_rsa和-xxpem的区别和联系">id_rsa和 xx.pem的区别和联系</h2>
<ul>
<li>id_rsa 是一个私钥文件，通常用于 SSH 认证</li>
<li>xx.pem 文件则通常是 PEM 格式，可能包含私钥、公钥或证书，广泛用于 SSL/TLS,可以用于多种加密场景</li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/472660528"  target="_blank" rel="noopener" >如何优雅地在你的Windows主力机上通过SSH远程控制你的服务器（centos） - 知乎</a></li>
<li><a href="https://blog.legalhub.cn/2022/10/16/qunhui-nas-ssh-login/"  target="_blank" rel="noopener" >群晖 NAS 实现 SSH 免密码登录 | LEGALGEEK</a></li>
<li><a href="https://blog.csdn.net/YYwxcsdn/article/details/134764938"  target="_blank" rel="noopener" >VS Code Remote-ssh 远程控制Windows主机 + 免密登录 + 内网穿透_vscode 免密ssh 连接 windows-CSDN博客</a></li>
<li><a href="https://plantegg.github.io/2019/06/02/%E5%8F%B2%E4%B8%8A%E6%9C%80%E5%85%A8_SSH_%E6%9A%97%E9%BB%91%E6%8A%80%E5%B7%A7%E8%AF%A6%E8%A7%A3--%E6%94%B6%E8%97%8F%E4%BF%9D%E5%B9%B3%E5%AE%89/"  target="_blank" rel="noopener" >史上最全 SSH 暗黑技巧详解 | plantegg</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>文生图网站调研</title>
      <link>https://ds63.eu.org/2024/survey-of-ai-image-generation-website/</link>
      <pubDate>Thu, 15 Aug 2024 15:05:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/survey-of-ai-image-generation-website/</guid>
      <description>似乎有利可图</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>22年Stable Diffusion的发布，让生成图片的门槛进一步降低。而两年的发展，已经让文生图的技术颇为成熟。</p>
<p>相较于大语言模型，普通用户更可能自部署Stable Difussion之类的模型，而不依赖于大型公司。</p>
<p>我好奇现有的文生图的网站的商业模式，于是简单调查了几家。</p>
<h2 id="网站一-flux-ai-pro">网站一: Flux AI Pro</h2>
<p><a href="https://fluxai.pro/"  target="_blank" rel="noopener" >Flux AI Pro - Advanced Flux AI Image Generator</a></p>
<ul>
<li><strong>简介</strong>
<ul>
<li>国人做的网站，但受众主要面向国外，网站语言只支持英语。</li>
<li>套壳网站。用的模板，似乎是直接用的Flux.1 Pro的api。</li>
<li>作者本人发的推：<a href="https://x.com/savokiss/status/1822258960763908322"  target="_blank" rel="noopener" >savokiss on X: &ldquo;肝了 3 天上线了我的第一个文生图站: https://t.co/vOgRU64Wbw / X</a></li>
</ul>
</li>
<li><strong>可调参数</strong>
<ul>
<li>免费账户可调的参数有： prompt,model,比例，是否公开</li>
<li>付费账户可调： step,seed,safety tolerance</li>
</ul>
</li>
<li><strong>亮点</strong>
<ul>
<li>开发成本很低, 作者说是在claude的帮助下做了三天就上线了</li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>Basic Plan是9.9美刀一个月，1000张图,约合0.01美元每张图</li>
</ul>
</li>
</ul>
<h2 id="网站二-enhance-ai">网站二: Enhance AI</h2>
<p><a href="https://enhanceai.art/"  target="_blank" rel="noopener" >Enhance AI: Advanced AI Image Tools | Photo Enhancer, Deepfake, Face Generator</a></p>
<ul>
<li><strong>介绍</strong>
<ul>
<li>这家公司叫Enhance AI</li>
<li>似乎是自己练了个模型叫<a href="https://huggingface.co/enhanceaiteam/FLUX.1-Pro"  target="_blank" rel="noopener" >enhanceaiteam/FLUX.1-Pro · Hugging Face</a></li>
<li>它基于的模型是<a href="https://huggingface.co/black-forest-labs/FLUX.1-dev"  target="_blank" rel="noopener" >black-forest-labs/FLUX.1-dev · Hugging Face</a></li>
<li>在<a href="https://huggingface.co/enhanceaiteam/FLUX.1-Pro"  target="_blank" rel="noopener" >enhanceaiteam/FLUX.1-Pro · Hugging Face</a>,他们比较了自己和其他竞品的区别</li>
</ul>
<blockquote>
<p>EnhanceAI.art: Offers the most cost-effective solution with the highest number of images generated per dollar, making it the best option for both budget-conscious users and those seeking high-volume production.</p>
<p>Other Platforms: Platforms like Fal.ai, Replicate, and BasedLab offer fewer images per dollar, with BasedLab being the least cost-effective.</p>
</blockquote>
<ul>
<li>在好几个平台运营: discord,ins,pininterest等，粉丝数都不大于一百</li>
</ul>
</li>
<li><strong>可调参数</strong>
<ul>
<li>prompt,negative_prompt(它换了个说法：Remove from Image，蛮好的),Scheduler:，scale,seed，比例,模型</li>
</ul>
</li>
<li><strong>注册福利</strong>
<ul>
<li>送50token，一张图消耗一个</li>
</ul>
</li>
<li><strong>亮点</strong>
<ul>
<li>Select a diffusion model:,不仅有文字，还有图片，就很直观</li>
<li>生成一张图片大概要十秒，进度条下方有些文字，比如
<ul>
<li>Initializing&hellip;</li>
<li>Analyzing prompt&hellip;</li>
<li>Generating concepts&hellip;</li>
<li>Refining details&hellip;</li>
<li>Adding artistic touches&hellip;</li>
</ul>
</li>
<li>支持生成nsfw</li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>月付费，Standard套餐是每个月15美元，2500张图，附加其他功能</li>
<li>月付费, Ultimate套餐是89美元,就能生成十万张</li>
</ul>
</li>
</ul>
<h2 id="网站三-black-forest-labs">网站三 black-forest-labs</h2>
<p><a href="https://blackforestlabs.ai/"  target="_blank" rel="noopener" >Black Forest Labs - Frontier AI Lab</a></p>
<ul>
<li><strong>介绍</strong>
<ul>
<li>这家公司？或者是实验室推出了FLUX,a 12 billion parameter rectified flow transformer capable of generating images from text descriptions。</li>
<li>关于FLUX，具体见<a href="https://huggingface.co/black-forest-labs/FLUX.1-dev?text=dog"  target="_blank" rel="noopener" >black-forest-labs/FLUX.1-dev · Hugging Face</a></li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>似乎并不直接商用，而是授权给了其他几家来卖api
<ol>
<li>bfl.ml (currently FLUX.1 [pro])</li>
<li><a href="https://replicate.com/"  target="_blank" rel="noopener" >Replicate — Run AI with an API</a></li>
<li><a href="https://fal.ai/"  target="_blank" rel="noopener" >fal.ai</a></li>
</ol>
</li>
</ul>
</li>
</ul>
<h2 id="网站四-falai">网站四 fal.ai</h2>
<p><a href="https://fal.ai/"  target="_blank" rel="noopener" >fal.ai</a></p>
<ul>
<li><strong>介绍</strong>
<ul>
<li>slogan是&quot;Generative media platform for developers.&rdquo;</li>
<li>卖API：We have the most-popular models implemented and available as API endpoints for you to start crafting your own AI-powered app today.</li>
<li>目标受众主要为开发者
<ul>
<li>UI-focused applications for existing models.</li>
<li>Prototype of AI-powered applications while custom models are in-development.</li>
</ul>
</li>
<li>Discord频道五千多人</li>
</ul>
</li>
<li><strong>注册福利</strong>
<ul>
<li>送2美元</li>
</ul>
</li>
<li><strong>亮点</strong>
<ul>
<li>支持workflows和ComfyUI</li>
<li><a href="https://fal.ai/pricing"  target="_blank" rel="noopener" >price</a>
<ul>
<li>这个界面写得很棒。它让你选budget，然后展示这预算能用多少</li>
<li>一个trick是：价格按秒算的：比如A100的价格是$0.00111/s。也就是$3.996/h,$96/d。</li>
</ul>
</li>
<li>宣称是Fastest SDXL Endpoint：
<blockquote>
<p>We believe fal has the fastest SDXL endpoint in the planet. If you can find a faster one, we guarantee to beat it within one week. 🤝</p>
</blockquote>
</li>
<li>支持使用lora进行推理：<a href="https://fal.ai/models/fal-ai/fast-sdxl"  target="_blank" rel="noopener" >Stable Diffusion XL | AI Playground | fal.ai</a></li>
<li>支持训练lora：<a href="https://fal.ai/models/fal-ai/style-lora"  target="_blank" rel="noopener" >Style LoRA Training | AI Playground | fal.ai</a></li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>参见<a href="https://fal.ai/pricing"  target="_blank" rel="noopener" >price</a></li>
<li>20美元能租五个小时的A100，跑满了算是一万张图</li>
</ul>
</li>
</ul>
<h2 id="网站五-replicate">网站五 Replicate</h2>
<p><a href="https://replicate.com/"  target="_blank" rel="noopener" >Replicate — Run AI with an API</a></p>
<ul>
<li><strong>介绍</strong>
<ul>
<li>可能是目前业内规模最大的一个了</li>
<li>卖api，不止是文生图，还包括LLM</li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>参看<a href="https://replicate.com/pricing"  target="_blank" rel="noopener" >Pricing – Replicate</a></li>
<li>能租GPU，但比<a href="fal.ai" >fal.ai</a>贵
<ul>
<li>Nvidia A100 (80GB) GPU 是 $5.04/hr</li>
<li>Nvidia T4 GPU 是 $0.81/hr</li>
</ul>
</li>
<li>Image models调用
<ul>
<li>black-forest-labs/flux-pro 的价格是$0.055</li>
<li><a href="https://replicate.com/stability-ai/stable-diffusion-3"  target="_blank" rel="noopener" >stability-ai/stable-diffusion-3</a>的价格是$0.035/ image，折算150元生成600张图</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="网站六">网站六</h2>
<p><a href="https://imgai.ai/"  target="_blank" rel="noopener" >Image AI - All-in-One AI Image Platform</a></p>
<ul>
<li><strong>介绍</strong>
<ul>
<li>国人独立开发的出海网站，注册的美国公司</li>
<li>骑龙 (@qilong87) / X</li>
<li>前端： nextjs+shadcn/ui+tailwindcss ; 后端:   go； 收款：stripe；</li>
<li>数据统计平台：Plausible Analytics | Simple, privacy-friendly Google Analytics alternative</li>
<li>多语言： <a href="https://github.com/lokalise/i18n-ally"  target="_blank" rel="noopener" >lokalise/i18n-ally: 🌍 All in one i18n extension for VS Code</a></li>
<li>开发时长： 近两个月 <a href="https://x.com/qilong87/status/1816809575666049131"  target="_blank" rel="noopener" >7月26日的一条推</a>
<blockquote>
<p>磕磕绊绊，http://imgai.ai 经过将近两个月开发，上周上线了，昨天提交了几个AI导航站，在 HN 发了个帖子，没想到今天被 TAAFT收录了，带来了一些流量，这个网站算是第一个走了一个完整的闭环，对我来说具有里程碑式的意义了</p>
</blockquote>
</li>
</ul>
</li>
<li><strong>亮点</strong>
<ul>
<li>围绕image ai相关的功能很全，但尚不清楚是调api还是自己部署</li>
<li>多语言支持</li>
<li><a href="https://imgai.ai/text-to-image"  target="_blank" rel="noopener" >Image AI - Text-to-Image</a>，prompt支持llm生成和润色</li>
</ul>
</li>
<li><strong>访问量与付费量</strong>
<ul>
<li>7月28日上线以来，到8月14日，一共两笔付费，共9.98，15日又两笔，也是9.98</li>
<li><a href="https://x.com/qilong87/status/1823909521724727792"  target="_blank" rel="noopener" >8月15日的一条推</a></li>
</ul>
</li>
<li><strong>价格</strong>
<ul>
<li>2Credits生成一张图，19.99美元送550 credits</li>
</ul>
</li>
</ul>
<h2 id="网站七">网站七</h2>
<p><a href="https://www.scenario.com/"  target="_blank" rel="noopener" >Scenario - AI-generated game assets</a></p>
<ul>
<li>介绍
<ul>
<li>ai生成游戏素材</li>
</ul>
</li>
<li>亮点
<ul>
<li>支持训练自己的模型</li>
<li>lora可调，可选</li>
<li>提供api，能直接集成到Unity等
<blockquote>
<p>The Scenario GenAI Engine is API-first and can be integrated into diverse workflows, design software, game engines like Unity, or within the games themselves.</p>
</blockquote>
</li>
</ul>
</li>
<li>价格
<ul>
<li>Scenario Pricing</li>
<li>$15/mo: 1,500 Creative Units</li>
<li>$45/mo: 5000 Creative Units</li>
</ul>
</li>
</ul>
<h2 id="网站八">网站八</h2>
<p><a href="https://modelslab.com/"  target="_blank" rel="noopener" >ModelsLab</a></p>
<ul>
<li>介绍</li>
<li>AI api提供商，<a href="https://enhanceai.art/"  target="_blank" rel="noopener" >ENHANCE AI ART: Create Amazing Images &amp; Edit Photo | AI Image Enhance</a>似乎也是用的他家的api</li>
<li>价格
<ul>
<li><a href="https://modelslab.com/pricing"  target="_blank" rel="noopener" >Pricing - Stable Diffusion And Dreambooth API - Generate and Finetune Dreambooth Stable Diffusion using API</a></li>
</ul>
</li>
</ul>
<h2 id="补充信息">补充信息</h2>
<ul>
<li>
<p><a href="https://www.cnblogs.com/devilmaycry812839668/p/17582514.html"  target="_blank" rel="noopener" >深度学习用什么卡比较给力？—— A100/H100真的么有RTX4090好吗？ - Angry_Panda - 博客园</a></p>
</li>
<li>
<p><strong>性能</strong></p>
<blockquote>
<p>在单精度计算方面RTX4090性能约等于A100，而H100约等于6倍的A100
rtx4090几乎可以被看做没有双精度计算能力，从数据上来看在双精度方面H100的性能大致为A100的3倍。</p>
</blockquote>
</li>
<li>
<p>价格</p>
<blockquote>
<p>rtx4090，24GB显存，大概1.5W人民币；
A100，40GB显存，大概5.5W人民币；
A100，80GB显存，大概7.5W人民币；
H100，80GB显存，大概24W人民币；</p>
</blockquote>
</li>
<li>
<p><a href="https://www.nvidia.com/en-us/data-center/tesla-t4/"  target="_blank" rel="noopener" >NVIDIA T4 Tensor Core GPU for AI Inference | NVIDIA Data Center</a></p>
<blockquote>
<p>NVIDIA T4: Single Precision Performance (FP32): 8.1 TFLOPS</p>
</blockquote>
</li>
<li>
<p><a href="https://www.cnblogs.com/cainiaoxuexi2017-ZYA/p/16426609.html"  target="_blank" rel="noopener" >显卡比较：Tesla T4 与 RTX3090Ti 性能对比；深度学习方向效率对比； - 张幼安 - 博客园</a></p>
<blockquote>
<p>RTX3090Ti: 40 TFLOPS</p>
</blockquote>
</li>
<li>
<p><a href="https://www.techpowerup.com/gpu-specs/geforce-rtx-4090.c3889"  target="_blank" rel="noopener" >NVIDIA GeForce RTX 4090 Specs | TechPowerUp GPU Database</a></p>
<blockquote>
<p>RTX 4090: FP32 (float) 82.58 TFLOPS</p>
</blockquote>
</li>
<li>
<p>GPU算力租用平台</p>
<ul>
<li><a href="https://www.autodl.com/home"  target="_blank" rel="noopener" >AutoDL算力云</a>
<ul>
<li>NVIDIA A100 SXM4 / 80GB: ￥6.68 /时</li>
<li>NVIDIA RTX 4090 / 24GB: ￥1.98 /时</li>
</ul>
</li>
<li><a href="https://www.ai-galaxy.cn/"  target="_blank" rel="noopener" >智星云</a>
<ul>
<li>A100 80G PCIE ¥7.99/小时</li>
<li>RTX 4090: ¥1.69/小时</li>
</ul>
</li>
<li><a href="https://www.aliyun.com/product/ecs/gpu"  target="_blank" rel="noopener" >阿里云</a>
<ul>
<li>T4卡GN6i GPU云服务器: 1694.00/1个月起</li>
</ul>
</li>
<li><a href="https://cloud.tencent.com/product/hai"  target="_blank" rel="noopener" >腾讯云</a>
<ul>
<li>T4: 1.2元每h</li>
</ul>
</li>
<li><a href="https://openbayes.com/pricing"  target="_blank" rel="noopener" >OpenBayes 贝式计算</a>
<ul>
<li>NVIDIA A100: 9元/小时起</li>
<li>NVIDIA RTX 4090 2.7元/小时</li>
</ul>
</li>
<li><a href="https://vast.ai/pricing"  target="_blank" rel="noopener" >Pricing | Vast.ai</a>
<ul>
<li>RTX 4090: $0.26/h</li>
<li>A100 SXM4: $0.80/h到$1.80/h</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>腾讯高性能应用服务体验</title>
      <link>https://ds63.eu.org/2024/the-use-experience-of-tencent-hai/</link>
      <pubDate>Wed, 07 Aug 2024 23:05:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/the-use-experience-of-tencent-hai/</guid>
      <description>国内真卷啊</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>最近刚好有将stable-difussion服务运行在服务器的需求，首先考虑的是amazon，但最便宜的那款一小时都要1美元多，偶然间发现腾讯云有活动<a href="https://cloud.tencent.com/product/hai"  target="_blank" rel="noopener" >高性能应用服务HAI_GPU云服务器_腾讯云</a>，价格如下</p>
<ul>
<li>GPU 基础型算力套餐
<ul>
<li>显存大小：16 GB</li>
<li>算力大小：8+TFlops SP</li>
<li>CPU：8 核，内存：32GB</li>
<li>1.2元每h</li>
<li>学生特惠，150元买250 小时 GPU基础型算力套餐</li>
</ul>
</li>
<li>这参数其实就是<a href="https://www.nvidia.com/en-us/data-center/tesla-t4/"  target="_blank" rel="noopener" >NVIDIA T4 Tensor Core GPU for AI Inference | NVIDIA Data Center</a></li>
</ul>
<p>这价格快比电费还便宜了，于是买了一张150元的现金券来体验下。</p>
<h2 id="需求">需求</h2>
<p>我想使用该服务器跑一个被我魔改后的stable-difussion-webui，而它提供了一键部署Stable Difussion WebUI的选项。</p>
<p>如果能使用这装好的python环境，那我能省事很多。而且我也好奇这是怎么做的。以下是我的过程。</p>
<h2 id="ssh连接">ssh连接</h2>
<p>第一步肯定是得连接上去。</p>
<p>但在<a href="https://console.cloud.tencent.com/hai/instance"  target="_blank" rel="noopener" >腾讯云 - 控制台</a>并不能找到连接的按钮，还以为不提供,找文档找到了<a href="https://cloud.tencent.com/document/product/1721/102197"  target="_blank" rel="noopener" >高性能应用服务 连接 Linux 算力-操作指南-文档中心-腾讯云</a>。</p>
<p>看到方式一，很熟悉啊，于是就去做了。</p>
<p>(写这篇文章的时候我又看了遍这个文档，发现还有方式二：通过 Terminal 连接算力)，然后我才发现它提供的JupyterLab有项目的基础介绍。所以其实我下面写的这些很大一部分其实人都写得很明白了,╮(╯-╰)╭  ）</p>
<h2 id="找到python依赖的安装位置">找到python依赖的安装位置</h2>
<p>一进去先<code>ls</code>,发现有个miniconda3,答案就呼之欲出了，请ChatGPT写了个简单的cheatsheet:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 创建一个新的 Conda 环境</span>
</span></span><span class="line"><span class="cl">conda create --name myenv <span class="nv">python</span><span class="o">=</span>3.8
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 激活环境</span>
</span></span><span class="line"><span class="cl">conda activate myenv
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 停用环境</span>
</span></span><span class="line"><span class="cl">conda deactivate
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 列出所有 Conda 环境</span>
</span></span><span class="line"><span class="cl">conda env list
</span></span></code></pre></div><h2 id="node运行装在conda的python">node运行装在conda的python</h2>
<p>我需要用node去调用python，可以这样做</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">workDir</span> <span class="o">=</span> <span class="s2">&#34;/root/my-stable-diffusion-webui&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">webUIProcess</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">URL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">initWebGUI</span> <span class="o">=</span> <span class="nx">_</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">(</span><span class="nx">resolve</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;initWebGUI start&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">process</span><span class="p">.</span><span class="nx">chdir</span><span class="p">(</span><span class="nx">workDir</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">webUIProcess</span> <span class="o">=</span> <span class="nx">spawn</span><span class="p">(</span><span class="s1">&#39;/root/miniconda3/bin/python&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;launch.py&#39;</span><span class="p">,</span> <span class="s1">&#39;--xformers&#39;</span><span class="p">,</span> <span class="s1">&#39;--api&#39;</span><span class="p">,</span><span class="s1">&#39;--nobrowser&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">webUIProcess</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`stdout: </span><span class="si">${</span><span class="nx">data</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">resolve</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="nx">webUIProcess</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kr">const</span> <span class="nx">errorMessage</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="sb">`stderr: </span><span class="si">${</span><span class="nx">errorMessage</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// Check for errors, assuming warnings do not contain &#39;error&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span> <span class="p">(</span><span class="sr">/error/i</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">errorMessage</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Kill process...&#39;</span><span class="p">,</span> <span class="nx">webUIProcess</span><span class="p">.</span><span class="nx">pid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="nx">webUIProcess</span><span class="p">.</span><span class="nx">kill</span><span class="p">();</span>  <span class="c1">// Kill the current process
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Process&#39;</span><span class="p">,</span> <span class="nx">webUIProcess</span><span class="p">.</span><span class="nx">pid</span><span class="p">,</span> <span class="s1">&#39; killed.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>值得一提的是，因为该服务器将依赖将依赖全安装在了base这个环境下，所以路径就是<code>/root/miniconda3/bin/python</code></p>
<h2 id="基础环境配置">基础环境配置</h2>
<ol>
<li>nvm安装
<ul>
<li><a href="https://github.com/nvm-sh/nvm"  target="_blank" rel="noopener" >nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions</a></li>
<li><code>wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash</code></li>
</ul>
</li>
<li>redis安装: <code>apt-get install redis</code></li>
</ol>
<h2 id="下载所需的底模和lora文件">下载所需的底模和lora文件</h2>
<ol>
<li>因为我本地已经有相应的文件，于是我首先想的是上传。先是用的<a href="https://cyberduck.io/"  target="_blank" rel="noopener" >Cyberduck</a>,但连接失败，检查了下端口，也有开放，不知道啥原因，于是放弃</li>
<li>尝试直接使用sftp,<code>sftp username@your_server_ip</code> ,确实可行，于是请请ChatGPT写了个简单的cheatsheet:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 连接到服务器</span>
</span></span><span class="line"><span class="cl">sftp username@your_server_ip
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 切换到远程目录</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /home/root/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 lpwd 查看本地工作目录，lcd 切换本地目录：</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 上传本地文件</span>
</span></span><span class="line"><span class="cl">put C:<span class="se">\p</span>ath<span class="se">\t</span>o<span class="se">\e</span>xample.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 get 命令从远程服务器下载文件到本地：</span>
</span></span><span class="line"><span class="cl">get remotefile.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 退出 sftp 会话</span>
</span></span><span class="line"><span class="cl"><span class="nb">exit</span>
</span></span></code></pre></div><p>但发现速度不尽如人意，于是放弃</p>
<ol start="3">
<li>
<p>这时候就可以将思维逆转过来。既然不能上传，那我就下载啊。我需要的底模文件是在<a href="https://civitai.com/models/276298/sdxl-pixel-art-or-base"  target="_blank" rel="noopener" >【SDXL】 Pixel Art | Base - v1.0 | Stable Diffusion Checkpoint | Civitai</a>，当我直接复制下载链接，使用wget会报错，需要认证。查文档查到了<a href="https://education.civitai.com/civitais-guide-to-downloading-via-api/#step-by-step"  target="_blank" rel="noopener" >Civitai&rsquo;s Guide to Downloading via API - Civitai Education</a>。最终能运行的命令类似于:  <code>curl -L -H &quot;Content-Type: application/json&quot; -H &quot;Authorization: Bearer your_token&quot; https://civitai.com/api/download/models/311399 -o SDXLPixelArtBase_v10.safetensors</code></p>
</li>
<li>
<p>lora文件我则将上传到了s3上。它有个<code>share with presigned URL</code>,于是我想当然地使用，但发现还是报错。最后还是直接用的<code>Object URL</code></p>
</li>
<li>
<p>后来发现文档中推荐的下载是这样写的:</p>
<ul>
<li>建议将基础模型文件转存至与HAI实例同地域的COS桶中，再在HAI实例中拉取COS文件，速度最快</li>
<li>国内地域HAI实例可能存在网络不稳定情况，推荐启用“学术加速”；国外地域HAI实例下载模型、插件速度更快</li>
</ul>
<p>好一个“学术加速”</p>
</li>
</ol>
<h2 id="运行时报错">运行时报错</h2>
<ul>
<li>
<p><a href="https://stackoverflow.com/questions/59572174/no-module-named-dotenv-python-3-8"  target="_blank" rel="noopener" >import - no module named &lsquo;dotenv&rsquo; python 3.8 - Stack Overflow</a></p>
<p><code>pip install python-dotenv</code></p>
</li>
</ul>
<h2 id="pm2使用">pm2使用</h2>
<p>再再请ChatGPT写了个简单的cheatsheet:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装</span>
</span></span><span class="line"><span class="cl">npm install pm2 -g
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 指定env文件 </span>
</span></span><span class="line"><span class="cl">pm2 start <span class="s2">&#34;node --env-file=.env app.js&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看 PM2 中正在运行的进程</span>
</span></span><span class="line"><span class="cl">pm2 list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看应用程序日志</span>
</span></span><span class="line"><span class="cl">pm2 logs my-app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 停止应用程序：</span>
</span></span><span class="line"><span class="cl">pm2 stop my-app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 重启应用程序：</span>
</span></span><span class="line"><span class="cl">pm2 restart my-app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 删除应用程序：</span>
</span></span><span class="line"><span class="cl">pm2 delete my-app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 检查日志</span>
</span></span><span class="line"><span class="cl">pm2 logs app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 实时监控</span>
</span></span><span class="line"><span class="cl">pm2 monit
</span></span></code></pre></div><h2 id="怎么开机自启的">怎么开机自启的</h2>
<p>服务跑着跑着爆显存了，感觉问题可能出在这个服务器运行了两个stable-difussion-webui，重启后发现还是有，那么它是怎么做到开机自启的呢？</p>
<p>我先后检查了以下几处（还是请ChatGPT帮的忙）:</p>
<ol>
<li>systemctl</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">systemctl list-unit-files --type<span class="o">=</span>service --state<span class="o">=</span>enabled
</span></span><span class="line"><span class="cl">systemctl list-units --type<span class="o">=</span>service --state<span class="o">=</span>running
</span></span></code></pre></div><p>这个命令将列出所有在系统启动时启用的服务。</p>
<ol start="2">
<li>检查 <code>/etc/init.d/</code>
在一些较旧的系统或特定的服务中，可以通过检查 <code>/etc/init.d/</code> 目录来查看初始化脚本：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">ls /etc/init.d/
</span></span></code></pre></div><p>这些脚本通常用于传统的 <code>init</code> 系统，在启动时运行。</p>
<ol start="4">
<li>cron</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo crontab -l
</span></span><span class="line"><span class="cl">sudo crontab -u &lt;username&gt; -l
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">cat /etc/crontab
</span></span><span class="line"><span class="cl">cat /etc/cron.*/*
</span></span></code></pre></div><h3 id="5-检查-rclocal">5. <strong>检查 <code>rc.local</code></strong></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo vim /etc/rc.local
</span></span></code></pre></div><p>以上检查都无果后，我想起了查看当前进程:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1"># 显示当前终端中的所有进程：</span>
</span></span><span class="line"><span class="cl">ps -ef
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 比较可疑的包括</span>
</span></span><span class="line"><span class="cl">root           <span class="m">1</span>       <span class="m">0</span>  <span class="m">0</span> 12:35 ?        00:00:00 /usr/bin/dumb-init -- /usr/local/bin/application_init.s
</span></span><span class="line"><span class="cl">root           <span class="m">7</span>       <span class="m">1</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 /bin/bash /usr/local/bin/application_init.sh
</span></span><span class="line"><span class="cl">root          <span class="m">16</span>       <span class="m">7</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 /usr/bin/python3 /usr/bin/supervisord -c /etc/superviso
</span></span><span class="line"><span class="cl">root          <span class="m">18</span>      <span class="m">16</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 /bin/bash /usr/local/bin/launch_jupyter.sh
</span></span><span class="line"><span class="cl">root          <span class="m">19</span>      <span class="m">16</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 sshd: /usr/sbin/sshd -D <span class="o">[</span>listener<span class="o">]</span> <span class="m">0</span> of 10-100 startups
</span></span><span class="line"><span class="cl">root          <span class="m">20</span>      <span class="m">16</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 /bin/bash /usr/local/bin/launch_stable_diffusion_webui.
</span></span><span class="line"><span class="cl">root          <span class="m">21</span>      <span class="m">18</span>  <span class="m">0</span> 12:35 pts/0    00:00:04 /root/miniconda3/bin/python3 /root/miniconda3/bin/jupyt
</span></span><span class="line"><span class="cl">root          <span class="m">22</span>      <span class="m">18</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 tee -a /var/log/jupyter_service.log
</span></span><span class="line"><span class="cl">root          <span class="m">23</span>      <span class="m">20</span>  <span class="m">1</span> 12:35 pts/0    00:01:03 python3 -u launch.py --skip-prepare-environment --xform
</span></span><span class="line"><span class="cl">root          <span class="m">24</span>      <span class="m">20</span>  <span class="m">0</span> 12:35 pts/0    00:00:00 tee -a /var/log/sd_service.log
</span></span><span class="line"><span class="cl">root        <span class="m">1225</span>      <span class="m">68</span>  <span class="m">0</span> 12:50 pts/1    00:00:00 vim /etc/systemd/system/supervisord.service
</span></span><span class="line"><span class="cl">root        <span class="m">1994</span>      <span class="m">21</span>  <span class="m">0</span> 13:29 ?        00:00:00 /root/miniconda3/bin/python3 -m ipykernel_launcher -f /
</span></span></code></pre></div><p>于是找到了<code>supervisord</code></p>
<h2 id="supervisord的使用">supervisord的使用</h2>
<ol>
<li>请ChatGPT写了个简单的介绍:</li>
</ol>
<blockquote>
<p>supervisord 是一个流行的进程控制系统，用于管理和监控 Unix-like 操作系统上的进程。它提供了一种简单的方式来启动、停止、重启和监控进程。supervisord 是 supervisor 的守护进程，而 supervisor 是用于管理进程的客户端工具。</p>
</blockquote>
<ol start="2">
<li>用<code>whereis supervisord</code>找到了配置文件的位置，是在<code>/etc/supervisord.conf</code>,
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>program:stable_diffusion_webui<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">command</span><span class="o">=</span>/usr/local/bin/launch_stable_diffusion_webui.sh
</span></span><span class="line"><span class="cl"><span class="nv">autostart</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">autorestart</span><span class="o">=</span><span class="nb">false</span>
</span></span><span class="line"><span class="cl"><span class="nv">numprocs</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="nv">redirect_stderr</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">startretries</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="nv">startsecs</span><span class="o">=</span><span class="m">300</span>
</span></span><span class="line"><span class="cl"><span class="nv">stdout_logfile</span><span class="o">=</span>/dev/stdout
</span></span><span class="line"><span class="cl"><span class="nv">stdout_logfile_maxbytes</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="nv">stdout_events_enabled</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">stderr_events_enabled</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">stopasgroup</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">killasgroup</span><span class="o">=</span><span class="nb">true</span>
</span></span></code></pre></div></li>
<li>那么刚才的问题得到了解答，开机自启的是<code>supervisor.service</code>，然后supervisor将<code>stable_diffusion_webui</code>给启动了</li>
<li><code>/usr/local/bin/launch_stable_diffusion_webui.sh</code>这个文件内容是
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nb">source</span> /mnt/application_env.txt
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /root/stable-diffusion-webui/ <span class="o">&amp;&amp;</span> python3 -u launch.py --skip-prepare-environment --xformers --listen --enable-insecure-extension-access --port<span class="o">=</span><span class="nv">$STABLE_DIFFUSION_WEBUI_PORT</span> 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="p">|</span> tee -a /var/log/sd_service.log<span class="sb">`</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="开机自启">开机自启</h2>
<p>找到了它开机自启动服务的办法，那么就可以利用它来实现我想要的开机自启。</p>
<ol>
<li>先写了个脚本<code>/usr/local/bin/check_and_start_pm2.sh</code>:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1"># 进入程序目录</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /path/to/SD-server/stable-difussion-server/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 检查 pm2 中是否已有名为 &#34;app&#34; 的程序</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> ! pm2 list <span class="p">|</span> grep -q <span class="s1">&#39;app&#39;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 如果没有，启动 pm2 进程</span>
</span></span><span class="line"><span class="cl">    pm2 start <span class="s2">&#34;node --env-file=.env app.js&#34;</span> --name app
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;PM2 process &#39;app&#39; is already running.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><ol start="2">
<li>给权限<code>chmod +x /usr/local/bin/check_and_start_pm2.sh</code></li>
<li>改<code>/etc/supervisord.conf</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>program:stable_diffusion_webui<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">command</span><span class="o">=</span>/usr/local/bin/check_and_start_pm2.sh
</span></span><span class="line"><span class="cl"><span class="nv">autostart</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">autorestart</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">numprocs</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="nv">redirect_stderr</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">startretries</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="nv">startsecs</span><span class="o">=</span><span class="m">300</span>
</span></span><span class="line"><span class="cl"><span class="nv">stdout_logfile</span><span class="o">=</span>/dev/stdout
</span></span><span class="line"><span class="cl"><span class="nv">stdout_logfile_maxbytes</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="nv">stdout_events_enabled</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">stderr_events_enabled</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">stopasgroup</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">killasgroup</span><span class="o">=</span><span class="nb">true</span>
</span></span></code></pre></div></li>
<li>重新加载 supervisord 配置
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">supervisorctl reread
</span></span><span class="line"><span class="cl">supervisorctl update
</span></span></code></pre></div></li>
<li>这里我还踩到了自己挖的一个坑，<code>/usr/local/bin/check_and_start_pm2.sh</code>文件首行我是写<code>#!/bin/bash</code>，但我nvm是在zsh上装的，于是pm2在bash环境下就识别不到，再加上就行了。 <code>export PATH=$PATH:/root/.nvm/versions/node/v20.16.0/bin</code></li>
</ol>
<h2 id="体验">体验</h2>
<p>之前用过好几家国内的云服务器，最大的感受是ui很糟糕，然后就是费劲折腾的网络。</p>
<p>但这次体验却着实不赖，因为有了“学术加速”，呵呵。</p>
<h2 id="特别鸣谢">特别鸣谢</h2>
<p>感谢ChatGPT! 它省去了不少我查文档的功夫。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>从零开始的ubuntu使用</title>
      <link>https://ds63.eu.org/2024/ubuntu-experience-in-a-different-world-from-zero/</link>
      <pubDate>Wed, 07 Aug 2024 15:37:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/ubuntu-experience-in-a-different-world-from-zero/</guid>
      <description>Long may the Jammy Jellyfish!</description>
      <content:encoded><![CDATA[<p><strong>Ubuntu对我来说是一个既熟悉又陌生的系统。过去几年来，接触得最多的Linux系统就是它了。但除了wsl，虚拟机，云服务器，我还真没正儿八经的从零开始使用过。最近刚好有机会从装系统开始从零使用，以下记录我踩过的各种坑。</strong></p>
<h2 id="安装">安装</h2>
<ul>
<li><a href="https://blog.csdn.net/2401_84064328/article/details/137232169"  target="_blank" rel="noopener" >Windows11 + Linux (Ubuntu22.04) 双系统最简安装详细避坑版_win11安装linux双系统-CSDN博客</a></li>
<li><a href="https://releases.ubuntu.com/jammy/"  target="_blank" rel="noopener" >Ubuntu 22.04.4 LTS (Jammy Jellyfish)</a></li>
<li>踩坑到怀疑人生后，最后放弃使用24.04，回退到22.04,原本寸步难行的泥泞沼泽也成了康庄大道,赞美Jammy Jellyfish。</li>
</ul>
<h2 id="安装wifi驱动">安装wifi驱动</h2>
<p>无果。我使用的主版官网上只提供了win11或win10的驱动。网上找的几种办法，包括更新内核，都没能成功。放弃。</p>
<ul>
<li>更新内核后报错 <code>bad shim signature &amp; load the kernel first</code>
<a href="https://www.reddit.com/r/linux4noobs/comments/10152n7/how_to_fix_bad_shim_signature_load_the_kernel/"  target="_blank" rel="noopener" >How to fix &ldquo;bad shim signature &amp; load the kernel first&rdquo; errors on my triple boot setup? : r/linux4noobs</a></li>
</ul>
<h2 id="安装显卡驱动">安装显卡驱动</h2>
<ol>
<li>菜单栏找到 <code>Additional drivers</code>,点击安装</li>
<li><code>nvidia-smi</code> 检查是否安装成功</li>
</ol>
<h2 id="查看配置">查看配置</h2>
<ol>
<li><a href="https://blog.csdn.net/lxfHaHaHa/article/details/95769201"  target="_blank" rel="noopener" >查看ubuntu服务器的配置（cpu+显卡+内存+硬盘）_ubuntu查看服务器配置-CSDN博客</a></li>
</ol>
<h2 id="中文输入法">中文输入法</h2>
<p>参考以下几篇</p>
<ul>
<li><a href="https://blog.csdn.net/fr16021028/article/details/125891812"  target="_blank" rel="noopener" >Ubuntu中文设置与安装中文输入法（超详细）_ubuntu中文输入法安装-CSDN博客</a></li>
<li><a href="https://hk.v2ex.com/t/1055546"  target="_blank" rel="noopener" >各位 Linux 用的输入法都是？ - V2EX</a></li>
<li><a href="https://github.com/iDvel/rime-ice"  target="_blank" rel="noopener" >iDvel/rime-ice: Rime 配置：雾凇拼音 | 长期维护的简体词库</a></li>
</ul>
<h2 id="代理">代理</h2>
<ul>
<li><a href="https://v2ex.com/t/988113"  target="_blank" rel="noopener" >求助， Linux 如何使用全局代理？ - V2EX</a></li>
<li>ShellCrash
<ul>
<li><a href="https://github.com/juewuy/ShellCrash"  target="_blank" rel="noopener" >juewuy/ShellCrash: Run sing-box/mihomo as client in shell</a></li>
</ul>
</li>
<li>v2rayA
<ul>
<li><a href="https://github.com/v2rayA/v2rayA"  target="_blank" rel="noopener" >v2rayA/v2rayA: A web GUI client of Project V which supports VMess, VLESS, SS, SSR, Trojan, Tuic and Juicity protocols. 🚀</a></li>
<li><a href="https://www.sky350.com/1210.html"  target="_blank" rel="noopener" >V2RayA——新一代Linux客户端安装配置教程 | SKY博客</a></li>
<li><a href="https://v2raya.org/en/docs/prologue/installation/debian/#start-v2raya--enable-v2raya-start-automatically"  target="_blank" rel="noopener" >Debian / Ubuntu - v2rayA</a></li>
<li><a href="https://v2raya.org/en/docs/prologue/installation/debian/"  target="_blank" rel="noopener" >Debian / Ubuntu - v2rayA</a>
<ol>
<li><code>wget -qO - https://apt.v2raya.org/key/public-key.asc | sudo tee /etc/apt/keyrings/v2raya.asc</code></li>
<li><code>echo &quot;deb [signed-by=/etc/apt/keyrings/v2raya.asc] https://apt.v2raya.org/ v2raya main&quot; | sudo tee /etc/apt/sources.list.d/v2raya.list</code></li>
<li><code>sudo apt update</code></li>
<li><code>sudo apt install v2raya v2ray</code></li>
<li><code>sudo systemctl start v2raya.service</code></li>
</ol>
</li>
</ul>
</li>
<li>dae
<ul>
<li><a href="https://v2ex.com/t/982840"  target="_blank" rel="noopener" >V2 上关于 dae（大鹅）（ebpf）的讨论还是比较少啊，完美的旁路科学方案了吧？ - V2EX</a></li>
<li><a href="https://github.com/daeuniverse/dae/blob/main/docs/zh/how-it-works.md"  target="_blank" rel="noopener" >dae/docs/zh/how-it-works.md at main · daeuniverse/dae</a></li>
<li><a href="https://github.com/daeuniverse/dae/tree/main/docs/zh"  target="_blank" rel="noopener" >dae/docs/zh at main · daeuniverse/dae</a></li>
<li><a href="https://github.com/daeuniverse/dae/issues/468"  target="_blank" rel="noopener" >[Bug Report] <!-- raw HTML omitted -->Ubuntu 启动不起来 · Issue #468 · daeuniverse/dae</a></li>
</ul>
</li>
<li>electron-ssr
<ul>
<li><a href="https://github.com/shadowsocksrr/electron-ssr"  target="_blank" rel="noopener" >shadowsocksrr/electron-ssr: Shadowsocksr client using electron</a></li>
<li><a href="https://victrid.dev/2020/linux-pei-zhi-ssr/"  target="_blank" rel="noopener" >linux配置SSR | Victrid&rsquo;s Personal Site</a></li>
</ul>
</li>
<li>clash
<ul>
<li><a href="https://victrid.dev/2021/pei-zhi-tou-ming-dai-li-shi-xian-wu-gan-shang-wang/"  target="_blank" rel="noopener" >配置透明代理，实现无感上网 | Victrid&rsquo;s Personal Site</a></li>
</ul>
</li>
</ul>
<p>ps: 在这上折腾最久，最终使用的是v2raya。</p>
<h2 id="ssh">ssh</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt update <span class="o">&amp;&amp;</span> sudo apt upgrade
</span></span><span class="line"><span class="cl">sudo apt install openssh-server
</span></span><span class="line"><span class="cl">sudo systemctl <span class="nb">enable</span> --now ssh
</span></span></code></pre></div><ul>
<li><a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh"  target="_blank" rel="noopener" >Connecting to GitHub with SSH - GitHub Docs</a></li>
</ul>
<h2 id="杂">杂</h2>
<ul>
<li><a href="https://www.reddit.com/r/archlinux/comments/11dqzj0/weird_error_when_shutting_down_after_update/"  target="_blank" rel="noopener" >Weird error when shutting down after update : r/archlinux</a></li>
<li><a href="https://juejin.cn/post/7097032561092165640"  target="_blank" rel="noopener" >查看Linux系统架构的命令，查看linux系统是哪种架构：AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号 - 掘金</a></li>
</ul>
<h2 id="steam">steam</h2>
<p>之前看SteamDeck用的系统是Linux魔改，以为现在Linux上跑游戏很成熟了，但自己实际体验后，发现支持Linux的还不算多。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>进一步学习jwt</title>
      <link>https://ds63.eu.org/2024/learn_jwt/</link>
      <pubDate>Sun, 04 Aug 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_jwt/</guid>
      <description>熟悉又陌生</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>JWT，我并不陌生。但如何去权衡其中利弊，根据不同需求去决定是否使用，如何使用，我还是一知半解，于是希望通过此篇来进一步学习</p>
<hr>
<h2 id="基于token的认证方式">基于token的认证方式</h2>
<ol>
<li>用户向服务器发送用户名和密码。</li>
<li>服务器将相关数据，比如用户 ID，认证有效期等信息签名后生成 token 返回给客户端。</li>
<li>客户端将 token 写入本地存储。</li>
<li>用户随后的每一次请求，都将 token 附加到 header 中。</li>
<li>服务端获取到用户请求的 header，拿到用户数据并且做签名校验，如果校验成功则说明数据没有被篡改，是有效的，确认 token 在有效期内，用户数据就是有效的。</li>
</ol>
<hr>
<h2 id="组成">组成</h2>
<ul>
<li>header</li>
<li>payload</li>
<li>signature</li>
</ul>
<hr>
<h2 id="存在的问题">存在的问题：</h2>
<ol>
<li>Token Expiration
<ul>
<li>Revoked Token Database                   |</li>
<li>Additional DB calls</li>
</ul>
</li>
<li>Token Revocation Problem
<ul>
<li>Inability to easily revoke tokens</li>
<li>Lack of real-time revocation</li>
</ul>
</li>
<li>Length of Tokens
<ul>
<li>Potential URL and cookie length issues</li>
<li>Sending large volumes of data</li>
</ul>
</li>
<li>Need for State Maintenance
<ul>
<li>Need to maintain user state</li>
<li>Limited statelessness</li>
</ul>
</li>
<li>Security and Encryption
<ul>
<li>Potential vulnerabilities</li>
<li>Lack of encryption for payload</li>
</ul>
</li>
</ol>
<hr>
<h2 id="使用时需要注意的点">使用时需要注意的点</h2>
<p>摘自 <a href="https://blog.fatedier.com/2020/03/28/golang-jwt/"  target="_blank" rel="noopener" >Golang 中使用 JWT 做用户认证</a></p>
<blockquote>
<ul>
<li>由于 jwt 返回的 Token 中的数据仅做了 Base64 处理，没有加密，所以不应放入重要的信息。</li>
<li>jwt Token 由于是无状态的，任何获取到此 Token 的人都可以访问，所以为了减少盗用，可以将 Token 有效期设置短一些。对一些重要的操作，尽量再次进行认证。</li>
<li>网站尽量使用 HTTPS，可以减少 Token 的泄漏。</li>
</ul>
</blockquote>
<h2 id="有办法使一个在有效期内的jwt废弃掉吗">有办法使一个在有效期内的JWT废弃掉吗</h2>
<p>wip</p>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://mp.weixin.qq.com/s/Vcj3Jj0PANSnqXgt4CsF2Q"  target="_blank" rel="noopener" >决定放弃使用JWT了！</a></li>
<li><a href="https://www.51cto.com/article/624093.html"  target="_blank" rel="noopener" >『JWT』有人让你赶快用它，有人劝你放弃它-有人让我</a></li>
<li><a href="https://segmentfault.com/q/1010000010043871"  target="_blank" rel="noopener" >jwt - 在退出登录 / 修改密码时怎样实现JWT Token失效？ - SegmentFault 思否</a></li>
<li><a href="https://hasura.io/blog/best-practices-of-using-jwt-with-graphql"  target="_blank" rel="noopener" >The Ultimate Guide to handling JWTs on frontend clients (GraphQL)</a></li>
<li><a href="https://blog.fatedier.com/2020/03/28/golang-jwt/"  target="_blank" rel="noopener" >Golang 中使用 JWT 做用户认证</a></li>
<li><a href="https://juejin.cn/post/7238921098808475705"  target="_blank" rel="noopener" >JWT真的安全吗？如何解决该问题 - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>进一步学习useEffect</title>
      <link>https://ds63.eu.org/2024/learn_useeffect/</link>
      <pubDate>Sun, 04 Aug 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_useeffect/</guid>
      <description>再次学习useEffect;再次学习useEffect;</description>
      <content:encoded><![CDATA[<h2 id="原因">原因</h2>
<p>最近还是发现自己在使用useEffect时有疑惑，深感有必要进一步去学习useEffect的使用。</p>
<hr>
<h2 id="疑惑一">疑惑一</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">[</span><span class="nx">variable</span><span class="p">,</span><span class="nx">setVariable</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 这样写有必要吗？
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">useEffect</span><span class="p">(</span><span class="nx">_</span> <span class="p">=&gt;{},[])</span>
</span></span></code></pre></div><ul>
<li>没必要，没意义</li>
</ul>
<hr>
<h2 id="疑惑二-依赖数组到底该写些啥">疑惑二: 依赖数组到底该写些啥</h2>
<h3 id="概念">概念:</h3>
<ul>
<li>依赖数组：用来告诉 React 这个 useEffect 何时应该运行。依赖数组中的每一项会被监控，当这些值发生变化时，副作用函数会重新运行。</li>
<li>依赖数组中的典型值
<ol>
<li>状态（state）：如果副作用依赖于某个 useState 的值，应该将其包含在依赖数组中。</li>
<li>props：当副作用依赖于某个 props，应该将其包含在依赖数组中。</li>
<li>函数或其他变量：如果副作用依赖于某个函数或者计算出来的变量，也应该包括在依赖数组中。</li>
</ol>
</li>
<li>依赖数组中尽量不要有<code>object</code>或<code>array</code>等引用变量</li>
</ul>
<h3 id="错误示范">错误示范:</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">ChatRoom</span><span class="p">({</span> <span class="nx">articleId</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">article</span><span class="p">,</span> <span class="nx">setArticle</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// options 會在每次渲染時重新創建
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">serverUrl</span><span class="o">:</span> <span class="s1">&#39;https://localhost:1234&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">articleId</span><span class="o">:</span> <span class="nx">articleId</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">getArticle</span><span class="p">(</span><span class="nx">options</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setArticle</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// options 每次渲染時值都不同，因此觸發 useEffect 執行
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">},</span> <span class="p">[</span><span class="nx">options</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="正确示范">正确示范:</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">ChatRoom</span><span class="p">({</span> <span class="nx">articleId</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">article</span><span class="p">,</span> <span class="nx">setArticle</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	  <span class="kr">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	    <span class="nx">serverUrl</span><span class="o">:</span> <span class="s1">&#39;https://localhost:1234&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	    <span class="nx">articleId</span><span class="o">:</span> <span class="nx">articleId</span>
</span></span><span class="line"><span class="cl">	  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">getArticle</span><span class="p">(</span><span class="nx">options</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setArticle</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">articleId</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="参考">参考</h3>
<ul>
<li><a href="https://betterprogramming.pub/stop-lying-to-react-about-missing-dependencies-10612e9aeeda"  target="_blank" rel="noopener" >Stop Lying to React About Missing Dependencies | by Jack Taylor | Better Programming</a></li>
<li><a href="https://juejin.cn/post/7327832105328574514"  target="_blank" rel="noopener" >&ldquo;React中useEffect的依赖数组：空数组与不写数组的区别&rdquo;- 掘金</a></li>
</ul>
<hr>
<h2 id="疑惑三-依赖数组为空和不传有区别吗">疑惑三: 依赖数组为空和不传有区别吗?</h2>
<h3 id="概念-1">概念</h3>
<ul>
<li>当依赖数组为空时（<code>[]</code>），useEffect中的回调函数<strong>只会在组件挂载和卸载时执行</strong>。这意味着它只会执行一次，类似于类组件中的<code>componentDidMount</code>和<code>componentWillUnmount</code>。</li>
<li>当<strong>不传入</strong>依赖数组时，useEffect中的回调函数会在每次组件渲染时都执行。这意味着它会在<strong>组件挂载、更新和卸载时</strong>都执行。</li>
</ul>
<h3 id="示例-依赖数组为空">示例: 依赖数组为空</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">//10秒内连续点击按钮5次，控制台的输出结果是什么
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span> <span class="mi">10</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},[])</span> 
</span></span><span class="line"><span class="cl">  <span class="c1">//控制台只会输出一个0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//因为count更新只是组件状态更新，而此时的useeffect只在组件加载和卸载时候执行只执行一次
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  
</span></span><span class="line"><span class="cl">   <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;{</span><span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span><span class="o">+</span><span class="mi">1</span><span class="p">)}}</span><span class="o">&gt;</span><span class="nx">点击count加1</span><span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span></code></pre></div><h3 id="示例-不传入依赖数组">示例: 不传入依赖数组</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">//10秒内连续点击按钮5次，控制台的输出结果是什么
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span> <span class="mi">10</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span> 
</span></span><span class="line"><span class="cl">  <span class="c1">//控制台只会输出0，1，2，3，4，5
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//因为count更新，组件状态更新会重新渲染组件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//而此时的useeffect在组件更新渲染的时候都会执行
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//所以会执行对应的点击次数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">//在控制台中打印对应的次数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  
</span></span><span class="line"><span class="cl">   <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;{</span><span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span><span class="o">+</span><span class="mi">1</span><span class="p">)}}</span><span class="o">&gt;</span><span class="nx">点击count加1</span><span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span></code></pre></div><h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7327832105328574514"  target="_blank" rel="noopener" >&ldquo;React中useEffect的依赖数组：空数组与不写数组的区别&rdquo;- 掘金</a></li>
</ul>
<hr>
<h2 id="疑惑四-依赖数组是怎么比较的">疑惑四: 依赖数组是怎么比较的</h2>
<h3 id="概念-2">概念</h3>
<ul>
<li>使用<code>Object.is</code>来进行比较,如果依赖数组中任意一值与前一次不用，就会重新执行</li>
<li><code>Object.is</code>和<code>===</code>的唯一区别在于它们处理带符号的 0 和 NaN 值的时候。=== 运算符（和 == 运算符）将数值 -0 和 +0 视为相等，但是会将 NaN 视为彼此不相等。</li>
<li><code>===</code> 不执行类型转换。它将验证被比较的变量是否具有相同的值和相同的类型。</li>
</ul>
<h3 id="实现usedeepcompareeffect">实现<code>useDeepCompareEffect</code></h3>
<ul>
<li>先用useRef取得前一次的值，然后再调用深比较函数对比前后的值</li>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useRef</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">type</span> <span class="p">{</span> <span class="nx">DependencyList</span><span class="p">,</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">useLayoutEffect</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">isEqual</span> <span class="nx">from</span> <span class="s1">&#39;lodash/isEqual&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">type</span> <span class="nx">EffectHookType</span> <span class="o">=</span> <span class="k">typeof</span> <span class="nx">useEffect</span> <span class="o">|</span> <span class="k">typeof</span> <span class="nx">useLayoutEffect</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">type</span> <span class="nx">CreateUpdateEffect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">hook</span><span class="o">:</span> <span class="nx">EffectHookType</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">EffectHookType</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">depsEqual</span> <span class="o">=</span> <span class="p">(</span><span class="nx">aDeps</span><span class="o">:</span> <span class="nx">DependencyList</span> <span class="o">=</span> <span class="p">[],</span> <span class="nx">bDeps</span><span class="o">:</span> <span class="nx">DependencyList</span> <span class="o">=</span> <span class="p">[])</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">isEqual</span><span class="p">(</span><span class="nx">aDeps</span><span class="p">,</span> <span class="nx">bDeps</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">createDeepCompareEffect</span><span class="o">:</span> <span class="nx">CreateUpdateEffect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">hook</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span><span class="nx">effect</span><span class="p">,</span> <span class="nx">deps</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">ref</span> <span class="o">=</span> <span class="nx">useRef</span><span class="o">&lt;</span><span class="nx">DependencyList</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">signalRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="o">&lt;</span><span class="nx">number</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// 本地更新的依赖值与缓存的依赖深比较
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">if</span> <span class="p">(</span><span class="nx">deps</span> <span class="o">===</span> <span class="kc">undefined</span> <span class="o">||</span> <span class="o">!</span><span class="nx">depsEqual</span><span class="p">(</span><span class="nx">deps</span><span class="p">,</span> <span class="nx">ref</span><span class="p">.</span><span class="nx">current</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 将依赖保存一份
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">ref</span><span class="p">.</span><span class="nx">current</span> <span class="o">=</span> <span class="nx">deps</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 如果发现变更，则改变signalRef的值，是为了触发真正的useEffect
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">signalRef</span><span class="p">.</span><span class="nx">current</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">hook</span><span class="p">(</span><span class="nx">effect</span><span class="p">,</span> <span class="p">[</span><span class="nx">signalRef</span><span class="p">.</span><span class="nx">current</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="报错useeffect-is-called-conditionally">报错：<code>useEffect</code> is called conditionally</h2>
<p>完整报错如下:</p>
<blockquote>
<p>React Hook &ldquo;useEffect&rdquo; is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks</p>
</blockquote>
<p>解决方法很简单，只需将useEffect调用移动到组件的顶层，并使用条件语句来决定是否执行其内部的逻辑即可。</p>
<hr>
<h2 id="useeffect-执行时机">useEffect 执行时机</h2>
<ol>
<li>當元件被加入時 (mount)，useEffect 會被第一次執行。</li>
<li>當每次元件重新渲染時，如果 dependencies 的值有改變，先將舊的 props 和 state 執行 cleanup function，再帶著新的 props 和 state 執行 setup function。</li>
<li>cleanup function 的程式碼，會在元件生命週期結束 (unmount) 時，執行最後一次。</li>
</ol>
<hr>
<h2 id="uselayouteffect">useLayoutEffect</h2>
<h3 id="概念-3">概念</h3>
<ul>
<li>执行时机: 在浏览器重绘 (repaints) 前執行,区别于<code>useEffect</code>,在浏览器完成布局与绘制之后，在一个延迟事件中被调用</li>
<li>可能會造成性能的問題。 因為在 useLayoutEffect 里的程序會阻礙瀏覽器重繪 (repaints) ，太頻繁使用可能會造成整個應用程式緩慢</li>
</ul>
<h3 id="示例">示例</h3>
<ul>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">useLayoutEffect</span><span class="p">,</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">count</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">randomNum</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">setCount</span><span class="p">(</span><span class="nx">randomNum</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">count</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">setCount</span><span class="p">(</span><span class="mi">0</span><span class="p">)}</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/div&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>解释
<ul>
<li>原因是，當你每次點擊 div，此時 count 會被更新為 0，畫面會重新渲染變為 0，同時，因為 count 被更新，也會觸發 useEffect 執行。所以在重繪完成之後， useEffect 執行並把 count 更新為另一串隨機數字，畫面也會再渲染一次，因為兩次渲染時間很快，所以造成閃爍。</li>
<li>假設我們把上方程式碼的 useEffect 換成 useLayoutEffect，當你每次點擊 div，此時 count 會被更新為 0，但這時，畫面不會被重新渲染變為 0，而是先等待 useLayoutEffect 內的程式碼執行完畢之後，state 已經更新為新的隨機數字，這時畫面才進行重繪。</li>
</ul>
</li>
</ul>
<h3 id="使用场景">使用场景</h3>
<ul>
<li>
<p>設計一個工具提示元件 (tooltip)，它會依照不同條件出現在某元素的上方、下方或旁邊，這種設計條件代表說，我們會需要知道此元素準確的高度位置，才能判斷要將 tooltip 顯示在哪裡。</p>
</li>
<li>
<p>此时React的渲染步驟可以拆分為下</p>
<ol>
<li>在任何地方渲染 Tooltip (即使位置不正確)</li>
<li>測量元素的高度，並決定放置 Tooltip 的位置</li>
<li>重新渲染畫面，這時 Tooltip 的位置才會是正確的</li>
<li>如果是使用 useEffect 的話，Tooltip 的位置，可能是從 0 變到 10 的位置，這會造成畫面閃爍、使用者體驗不佳，如果是使用 useLayoutEffect，React 則會在重繪前，就重新計算正確的位置，才渲染畫面。</li>
</ol>
</li>
</ul>
<hr>
<h2 id="参考-2">参考</h2>
<ul>
<li><a href="https://overreacted.io/a-complete-guide-to-useeffect/"  target="_blank" rel="noopener" >A Complete Guide to useEffect — overreacted</a></li>
<li><a href="https://devpress.csdn.net/react/62f64ea5c6770329307fc5f1.html"  target="_blank" rel="noopener" >Source code interpretation of React useEffect_javascript_rAc-React</a></li>
<li><a href="https://www.explainthis.io/zh-hant/swe/use-effect-vs-use-layout-effect"  target="_blank" rel="noopener" >請解釋 useEffect？與 useLayoutEffect 的區別？｜ExplainThis</a></li>
<li><a href="https://juejin.cn/post/7240600121208504375"  target="_blank" rel="noopener" >源码级层面角度剖析React中useEffect - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>sse学习笔记</title>
      <link>https://ds63.eu.org/2024/learn_sse/</link>
      <pubDate>Tue, 30 Jul 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_sse/</guid>
      <description>适合的技术才是最好的技术</description>
      <content:encoded><![CDATA[<h2 id="声明">声明</h2>
<p>本文是我学习sse(Server-Sent Events)的笔记，内容大部分是对我所读文章的摘抄，非我原创。具体出处参见<a href="#%e5%8f%82%e8%80%83" >参考链接</a>。</p>
<hr>
<h2 id="什么是-server-sent-events">什么是 Server-Sent Events</h2>
<ol>
<li>首先是服务器端向客户端声明，然后接下来发送的是流信息(text/eventStream)。换句话说，此时发送的不是一个一次性的数据包，而是以数据流的形式不断地发送过来，</li>
<li>在这种情况下，<strong>客户端不会</strong>关闭连接，会一直等着服务器端发送新的数据过来</li>
<li>消息的基本格式: <code>[field]: value\n</code></li>
</ol>
<hr>
<h2 id="对比">对比</h2>
<table>
<thead>
<tr>
<th>sse</th>
<th>websocket</th>
</tr>
</thead>
<tbody>
<tr>
<td>http协议</td>
<td>独立的websocket协议</td>
</tr>
<tr>
<td>轻量，使用简单</td>
<td>相对复杂</td>
</tr>
<tr>
<td>默认支持断线重连</td>
<td>需要自己实现断线重连</td>
</tr>
<tr>
<td>单工</td>
<td>双工</td>
</tr>
<tr>
<td>文本传输</td>
<td>二进制传输</td>
</tr>
<tr>
<td>支持自定义发送的消息类型</td>
<td>-</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="缺陷">缺陷</h2>
<ul>
<li>浏览器原生的EventSource API不支持自定义请求头</li>
<li><a href="https://dev.to/miketalbot/server-sent-events-are-still-not-production-ready-after-a-decade-a-lesson-for-me-a-warning-for-you-2gie"  target="_blank" rel="noopener" >Server Sent Events are still not production ready after a decade. A lesson for me, a warning for you! - DEV Community</a></li>
</ul>
<p>&ndash;</p>
<h2 id="示例代码">示例代码</h2>
<ul>
<li>参考:
<ul>
<li><a href="https://www.youtube.com/watch?v=GXGFCXn9Hak&amp;ab_channel=Covalence"  target="_blank" rel="noopener" >Using fetch with server-sent events - YouTube</a></li>
<li><a href="https://github.com/covalence-io/sse-fetch"  target="_blank" rel="noopener" >covalence-io/sse-fetch</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="问题与排查">问题与排查</h2>
<h3 id="问题一">问题一</h3>
<ul>
<li>问题描述: 浏览器原生的EventSource API不支持自定义请求头</li>
<li>排查:
<ol>
<li>查阅<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource"  target="_blank" rel="noopener" >EventSource - Web API | MDN</a>，似乎只提供<code>withCredentials</code>一个选项，但又声明是表示 EventSource 对象是否使用跨源资源共享（CORS）凭据来实例化（true），或者不使用（false，即默认值）。</li>
<li>转而使用<a href="https://github.com/Azure/fetch-event-source"  target="_blank" rel="noopener" >Azure/fetch-event-source: A better API for making Event Source requests, with all the features of fetch()</a></li>
<li>readme中提到了原生的EventSource API的几个缺点:
<blockquote>
<ul>
<li>You cannot pass in a request body: you have to encode all the information necessary to execute the request inside the URL, which is limited to 2000 characters in most browsers.</li>
<li>You cannot pass in custom request headers</li>
<li>You can only make GET requests - there is no way to specify another method.</li>
<li>If the connection is cut, you don&rsquo;t have any control over the retry strategy: the browser will silently retry for you a few times and then stop, which is not good enough for any sort of robust application.</li>
</ul>
</blockquote>
</li>
</ol>
</li>
<li>参考： <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource"  target="_blank" rel="noopener" >EventSource - Web APIs | MDN</a></li>
</ul>
<h3 id="问题二">问题二</h3>
<ul>
<li>问题: 部署后发现浏览器端无法收到消息</li>
<li>排查：
<ol>
<li>网络问题? 算了下距离，一条消息从生成到被接收要绕地球至少一圈，加上国内糟糕的网络环境，消息接收肯定会有延时，但也不至于一条都收不到。</li>
<li>s3或cloud front设置问题? 对比之前的配置也没发现什么异常，无果</li>
<li>最终排查到nginx配置问题，搜到<a href="https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx"  target="_blank" rel="noopener" >ruby - EventSource / Server-Sent Events through Nginx - Stack Overflow</a>，</li>
</ol>
</li>
</ul>
<h3 id="问题三">问题三</h3>
<ul>
<li><a href="https://dev.to/miketalbot/server-sent-events-are-still-not-production-ready-after-a-decade-a-lesson-for-me-a-warning-for-you-2gie"  target="_blank" rel="noopener" >Server Sent Events are still not production ready after a decade. A lesson for me, a warning for you! - DEV Community</a></li>
</ul>
<h3 id="问题四">问题四</h3>
<ul>
<li><a href="https://github.com/Azure/fetch-event-source/issues/84"  target="_blank" rel="noopener" >Can&rsquo;t close <code>fetchEventSource</code> with <code>AbortController</code> in React · Issue #84 · Azure/fetch-event-source</a></li>
</ul>
<h3 id="问题五">问题五</h3>
<ul>
<li>
<p><strong>问题描述</strong>: 多开了几个页面后，页面的sse连接似乎被卡死。</p>
</li>
<li>
<p>排查:</p>
<ol>
<li>开始的时候以为是后端代码的问题，排查无果。</li>
<li>后来发现可能和设置的选项<code>openWhenHiden:true</code>有关</li>
<li>然后又试了不同浏览器，发现不同浏览器卡死的页面上限又不同。于是才定位到是浏览器问题。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource"  target="_blank" rel="noopener" >EventSource - Web API | MDN</a>上是这样解释的
<blockquote>
<p>当不使用 HTTP/2 时，服务器发送事件（SSE）受到打开连接数的限制，这个限制是对于浏览器的，并且设置为非常低的数字（6），打开多个选项卡时可能会特别痛苦。在 Chrome 和 Firefox 中，这个问题已被标记为“不会修复”。</p>
</blockquote>
</li>
</ol>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://stackoverflow.com/questions/18584525/server-sent-events-and-browser-limits"  target="_blank" rel="noopener" >javascript - Server sent events and browser limits - Stack Overflow</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource"  target="_blank" rel="noopener" >EventSource - Web API | MDN</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="为什么不使用websocket">为什么不使用WebSocket</h2>
<p>以下内容均摘自<a href="https://www.zhihu.com/question/417163973/answer/3352111081"  target="_blank" rel="noopener" >为什么当今Web应用不都采用WebSocket形式进行数据交互？ - 知乎</a></p>
<ul>
<li><a href="https://www.zhihu.com/question/417163973/answer/3028379203"  target="_blank" rel="noopener" >龙背上的骑兵的回答 - 知乎</a>
<ul>
<li>成本高
<blockquote>
<p>websocket要想实现水平扩展就很复杂，因为websocke的场景一般都是双向通信，当数据库发生变更了，此时需要向客户端推送数据，要想推送数据，则必须知道和当前的客户端建立的websocket机器是哪个，然后向这台机器上的服务发送通知。所以一个多台机器的websocket服务，必须要搭配一个消息订阅服务（例如购买一个HA的redis的集群），而rest服务器则不需要。所以websocket成本更高。除非你不考虑水平扩展，只使用单台机器。</p>
</blockquote>
</li>
<li>没必要
<blockquote>
<p>一般情况下，客户端能在秒级内刷新数据，已经让用户感觉很实时了，这种使用rest轮训一样可以做到，性能更好，websocket则因为实时性过高，产生过多数据，消耗过多带宽。使用轮询，客户端和服务端的带宽是固定的，服务器可以合并2s内的事件统一发给客户端，流量为r。（假设通信一次数据量是固定的，为r），那么n个客户端2s内对服务器的总流量负载为 n * r.使用websocket,每个客户端都会实时发送信息，服务端收到之后都要实时广播给其他所有人，同样一次流量为r, 客户端为n 的情况下，服务器的流量总负载为:  n ^ 2 * r 。 所以websocket服务每增加一个客户端，服务器负载快速上升。一般都会通过限制一个文档内同时在线数量来避免。</p>
</blockquote>
</li>
</ul>
</li>
<li><a href="https://www.zhihu.com/question/417163973/answer/3352111081"  target="_blank" rel="noopener" >2到8个汉字的回答 - 知乎</a>提到了个<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebTransport"  target="_blank" rel="noopener" >WebTransport - Web APIs | MDN</a></li>
</ul>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=GXGFCXn9Hak&amp;ab_channel=Covalence"  target="_blank" rel="noopener" >Using fetch with server-sent events - YouTube</a></li>
<li><a href="https://github.com/covalence-io/sse-fetch"  target="_blank" rel="noopener" >covalence-io/sse-fetch</a></li>
<li><a href="https://github.com/Azure/fetch-event-source"  target="_blank" rel="noopener" >Azure/fetch-event-source: A better API for making Event Source requests, with all the features of fetch()</a></li>
<li><a href="https://spring.hhui.top/spring-blog/2020/04/01/200401-SpringBoot%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E4%B9%8BSSE%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8F%91%E9%80%81%E4%BA%8B%E4%BB%B6%E8%AF%A6%E8%A7%A3/"  target="_blank" rel="noopener" >【WEB系列】SSE服务器发送事件详解 | 一灰灰Blog</a></li>
<li><a href="https://blog.yuanpei.me/posts/3175881014/"  target="_blank" rel="noopener" >基于 Server-Sent Events 实现服务端消息推送 - 元培的元视角</a></li>
<li><a href="https://dev.to/miketalbot/server-sent-events-are-still-not-production-ready-after-a-decade-a-lesson-for-me-a-warning-for-you-2gie"  target="_blank" rel="noopener" >Server Sent Events are still not production ready after a decade. A lesson for me, a warning for you! - DEV Community</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource"  target="_blank" rel="noopener" >EventSource - Web APIs | MDN</a></li>
<li><a href="https://rathoreaparna678.medium.com/understanding-server-sent-events-with-node-js-652f8a3c3826"  target="_blank" rel="noopener" >使用 Node.js 了解服务器发送的事件 |通过 阿帕娜·拉索尔 |中等的 &mdash; Understanding Server-Sent Events With Node.js | by Aparna Rathore | Medium</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>记一次助人为乐</title>
      <link>https://ds63.eu.org/2024/happy_to_help_others/</link>
      <pubDate>Mon, 29 Jul 2024 18:06:36 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/happy_to_help_others/</guid>
      <description>开心的一天(&lt;em&gt;^_^&lt;/em&gt;)</description>
      <content:encoded><![CDATA[<h2 id="7月29日上午11点57分">7月29日上午11点57分</h2>
<p>7月29日上午，在安装<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui"  target="_blank" rel="noopener" >AUTOMATIC1111/stable-diffusion-webui</a>时遇到了这样的报错</p>
<blockquote>
<p>ModuleNotFoundError: No module named &lsquo;setuptools.command.test&rsquo;</p>
</blockquote>
<p>搜索后找到一条刚发布不到两分钟的issue<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/16289"  target="_blank" rel="noopener" >[Bug]: Winodws 11 error - ModuleNotFoundError - No module named &lsquo;setuptools.command.test&rsquo; - build stops · Issue #16289 · AUTOMATIC1111/stable-diffusion-webui</a>。巧了这不是，但除此之外就没找到其他解决方案了。</p>
<h2 id="7月29日下午12点50分">7月29日下午12点50分</h2>
<p>吃个饭回来看到有位大哥找到了问题所在，是因为<a href="https://pypi.org/project/setuptools/#history"  target="_blank" rel="noopener" >setuptools · PyPI</a>刚发布了72.0.0这个版本，对<code>setuptools.command.test</code>进行了改动。但我尝试了这位大哥给的解决方案，没能解决问题。</p>
<p>(ps: 这版本号真够狂野的)</p>
<p>不过好在问题出在哪已经知道了，去<a href="https://github.com/pypa/setuptools"  target="_blank" rel="noopener" >pypa/setuptools: Official project repository for the Setuptools build system</a>一看，已经有人提了issue：<a href="https://github.com/pypa/setuptools/issues/4519"  target="_blank" rel="noopener" >[BUG] Some packages are no longer installable after test command is removed · Issue #4519 · pypa/setuptools</a>。 发现这问题不小啊。不少python库都依赖了该库，这一下都不行了。</p>
<p>这时候就想，得，这也算是被我赶上了。早一天的话，这问题就不存在；晚一天的话，这问题已经早就被解决了，毕竟这么多人都受影响呢。</p>
<p>于是打算先去干其他事。</p>
<h2 id="7月29日下午2点">7月29日下午2点</h2>
<p>发现自己闲着也是闲着，不如来试试。</p>
<p>于是看安装[AUTOMATIC1111/stable-diffusion-webui]的依赖时遇到的报错信息，发现是在安装<a href="https://github.com/Ch00k/ffmpy"  target="_blank" rel="noopener" >Ch00k/ffmpy: Pythonic interface for FFmpeg/FFprobe command line</a>时出的问题。</p>
<p>代码库里一搜,可疑代码只有</p>
<blockquote>
<p>from setuptools.command.test import test as TestCommand # noqa</p>
</blockquote>
<p>于是我fork了这个仓库，将可疑代码删掉。之后再手动安装就好了。
<code>pip install git+https://github.com/EuDs63/ffmpy.git</code></p>
<p>顺手将解决方式发到相关的issue里,期望能帮助到其他人。</p>
<h2 id="7月29日下午5点">7月29日下午5点</h2>
<p>我那条issue截至目前已经有六个人给我点赞了，实际帮助到的人应该更多。</p>
<p>之前只是在issue里找解决方法的我，这次成为了issue里发解决方法的人，并成功帮助到了别人。虽然只是一处小小的改动，但对此我感到很自豪。</p>
<h2 id="感受">感受</h2>
<ol>
<li>相较于JavaScript项目的npm，yarn等包管理工具，python虽有<a href="https://github.com/pdm-project/pdm"  target="_blank" rel="noopener" >pdm-project/pdm: A modern Python package and dependency manager supporting the latest PEP standards</a>，但普及度还不算高。用户也很少有锁依赖版本的习惯。这就导致当一个库做了breaking change时，其他使用它的库也会跟着出问题。</li>
<li>有些事情没想象中那么困难。比如今天，我本来打算等别人给解决方案，因为这看上去像是个大工程。但实际上从我决定要试试，到解决，其实花不了多少时间。我之前高估了这事的难度(也许今天只是凑巧刚好遇到了个很好解决的bug)，但今后要是遇到类似的问题，我想我会更愿意去试试。因为我喜欢帮助到他人这种感觉。</li>
</ol>
<h2 id="收获">收获</h2>
<ul>
<li>可通过类似<code>pip install git+https://github.com/EuDs63/ffmpy.git</code>的方法来直接从Github仓库安装依赖，具体是怎么做到的呢，以下是ChatGPT的回答
<blockquote>
<ol>
<li>Cloning the Repository: pip uses git to clone the specified repository (<a href="https://github.com/EuDs63/ffmpy.git"  target="_blank" rel="noopener" >https://github.com/EuDs63/ffmpy.git</a>) to a temporary directory on your local machine.</li>
<li>Installing the Package: Once the repository is cloned, pip looks for a setup.py file in the root of the repository. This file must contain the necessary configuration to install the package. pip runs the setup script to install the package and any dependencies listed.</li>
</ol>
</blockquote>
</li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/16289"  target="_blank" rel="noopener" >[Bug]: Winodws 11 error - ModuleNotFoundError - No module named &lsquo;setuptools.command.test&rsquo; - build stops · Issue #16289 · AUTOMATIC1111/stable-diffusion-webui</a></li>
<li><a href="https://github.com/Ch00k/ffmpy/issues/75"  target="_blank" rel="noopener" >Error when installing to to update to setuptools · Issue #75 · Ch00k/ffmpy</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Use_Nodejs_in_Docker</title>
      <link>https://ds63.eu.org/2024/use_nodejs_in_docker/</link>
      <pubDate>Wed, 17 Jul 2024 13:13:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/use_nodejs_in_docker/</guid>
      <description>docker-compose is awesome</description>
      <content:encoded><![CDATA[<h2 id="需求">需求</h2>
<ol>
<li>在nas的docker运行我的node项目</li>
<li>使用<code>docker compose up -d</code>来启动</li>
<li>首次运行时，它将先执行<code>npm install</code>,然后 <code>npx prisma generate</code>,最后是<code>node --env-file=.env bin/www</code></li>
<li>非首次运行，则直接执行<code>node --env-file=.env bin/www</code></li>
<li>出错时不立即退出，而是可以进入容器中</li>
<li>将代码每天从某台电脑同步到nas中</li>
<li>docker能感应到代码的变化</li>
</ol>
<h2 id="对docker中运行的node项目debug">对docker中运行的node项目debug</h2>
<ul>
<li><code>node --env-file=.env --inspect-brk=0.0.0.0 bin/www</code></li>
<li>默认的端口号是&quot;<code>9229</code>,记得publish端口<code>- &quot;9229:9229&quot;</code></li>
<li>在<a href="chrome://inspect/#devices" >chrome://inspect/#devices</a> 对 Target discovery settings进行设置：<code>ip:92229</code></li>
</ul>
<h2 id="promblem--solution">Promblem &amp; Solution</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/73022976/bus-error-when-running-npm-run-dev-npm-start"  target="_blank" rel="noopener" >node.js - Bus Error when running npm run dev || npm start - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/15809611/bcrypt-invalid-elf-header-when-running-node-app"  target="_blank" rel="noopener" >node.js - bcrypt invalid elf header when running node app - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/30063907/docker-compose-how-to-execute-multiple-commands"  target="_blank" rel="noopener" >Docker Compose - How to execute multiple commands? - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/48719921/pull-access-denied-repository-does-not-exist-or-may-require-docker-login"  target="_blank" rel="noopener" >ubuntu 16.04 - pull access denied repository does not exist or may require docker login - Stack Overflow</a></li>
</ul>
<h2 id="dockerfile--composeyml">Dockerfile + compose.yml</h2>
<p><code>compose.yml</code>示例:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">services:
</span></span><span class="line"><span class="cl">  server:
</span></span><span class="line"><span class="cl">    build:
</span></span><span class="line"><span class="cl">      context: .
</span></span><span class="line"><span class="cl">      target: dev
</span></span></code></pre></div><p>定义了一个名为 <code>server</code> 的服务，并且指定了如何构建该服务的 Docker 镜像。</p>
<ul>
<li><code>build</code> 指令表明这个服务需要从当前目录（<code>.</code>）构建镜像，而不是从 Docker Hub 上拉取现成的镜像。</li>
<li><code>context: .</code> 指示 <code>docker-compose</code> 使用当前目录作为构建上下文。这意味着 <code>docker-compose</code> 会将当前目录中的所有文件和目录传递给 Dockerfile。</li>
<li><code>target: dev</code> 指示 <code>docker-compose</code> 使用 Dockerfile 中名为 <code>dev</code> 的构建阶段。Dockerfile 支持多阶段构建，每个阶段定义一个构建目标。使用 <code>target</code> 指令可以指定使用哪个构建阶段。</li>
</ul>
<p>后面我放弃了这样的组合，因为Dockerfile写起来总是有些问题，我一时找不到解决方法。</p>
<p>更关键的是：我并不需要将构建好的镜像上传到其他地方。我在nas上使用docker，最主要的是为了docker所提供的纯净环境。</p>
<p>最后我的选择还是用<code>compose.yml</code>来做</p>
<h2 id="composeyml-示例">compose.yml 示例</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">services:
</span></span><span class="line"><span class="cl">  backend:
</span></span><span class="line"><span class="cl">    container_name: backend-container
</span></span><span class="line"><span class="cl">    image: node:20
</span></span><span class="line"><span class="cl">    working_dir: /app
</span></span><span class="line"><span class="cl">    volumes:
</span></span><span class="line"><span class="cl">      - ./:/app
</span></span><span class="line"><span class="cl">    <span class="c1"># if you want to keep the container running and debug, you can use the following command</span>
</span></span><span class="line"><span class="cl">    <span class="c1">#command: tail -f /dev/null</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># then use docker exec -it backend-container bash</span>
</span></span><span class="line"><span class="cl">    command: <span class="o">[</span><span class="s2">&#34;sh&#34;</span>, <span class="s2">&#34;-c&#34;</span>, <span class="s2">&#34;if [ ! -d &#39;node_modules&#39; ]; then npm install &amp;&amp; npx prisma generate; fi &amp;&amp; node --env-file=.env bin/www&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    ports:
</span></span><span class="line"><span class="cl">      - <span class="s2">&#34;3000:3000&#34;</span>
</span></span><span class="line"><span class="cl">      - <span class="s2">&#34;9229:9229&#34;</span>
</span></span><span class="line"><span class="cl">    environment:
</span></span><span class="line"><span class="cl">      - <span class="nv">NODE_ENV</span><span class="o">=</span>development
</span></span><span class="line"><span class="cl">    restart: unless-stopped
</span></span><span class="line"><span class="cl">    tty: <span class="nb">true</span>
</span></span></code></pre></div><h2 id="参考">参考</h2>
<ul>
<li><a href="https://hub.docker.com/_/node"  target="_blank" rel="noopener" >node - Official Image | Docker Hub</a></li>
<li><a href="https://nodejs.org/en/learn/getting-started/debugging"  target="_blank" rel="noopener" >Node.js — Debugging Node.js</a></li>
<li><a href="https://docs.docker.com/compose/compose-file/build/"  target="_blank" rel="noopener" >Compose Build Specification | Docker Docs</a></li>
<li><a href="https://docs.docker.com/language/nodejs/containerize/"  target="_blank" rel="noopener" >Containerize a Node.js application | Docker Docs</a></li>
<li><a href="https://stackoverflow.com/questions/73022976/bus-error-when-running-npm-run-dev-npm-start"  target="_blank" rel="noopener" >node.js - Bus Error when running npm run dev || npm start - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/15809611/bcrypt-invalid-elf-header-when-running-node-app"  target="_blank" rel="noopener" >node.js - bcrypt invalid elf header when running node app - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/30063907/docker-compose-how-to-execute-multiple-commands"  target="_blank" rel="noopener" >Docker Compose - How to execute multiple commands? - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/48719921/pull-access-denied-repository-does-not-exist-or-may-require-docker-login"  target="_blank" rel="noopener" >ubuntu 16.04 - pull access denied repository does not exist or may require docker login - Stack Overflow</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Use mysql and redis in Docker</title>
      <link>https://ds63.eu.org/2024/mysql_redis_in_one_docker/</link>
      <pubDate>Sat, 13 Jul 2024 13:13:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/mysql_redis_in_one_docker/</guid>
      <description>docker-compose is awesome</description>
      <content:encoded><![CDATA[<h2 id="docker">Docker</h2>
<ol>
<li>
<p>View running containers
<code>docker ps</code></p>
</li>
<li>
<p>View all containers
<code>docker ps -a</code></p>
</li>
<li>
<p>View container configuration
<code>docker inspect container-name</code></p>
</li>
<li>
<p>View container logs
<code>docker logs container-name</code></p>
</li>
<li>
<p>Display all images
<code>docker image ls</code></p>
</li>
<li>
<p>Remove a container
<code>docker rm container-name</code></p>
</li>
<li>
<p>Remove an image
<code>docker rmi imagename</code></p>
</li>
<li>
<p>removes any unused containers
<code>docker system prune -a</code></p>
</li>
<li>
<p>removes any unused volumes
<code>docker volume prune</code></p>
</li>
</ol>
<h3 id="docker-compose">docker-compose</h3>
<p><strong>cd into the directory where contains docker-compose.yml first!</strong></p>
<ul>
<li><code>docker-compose up -d</code></li>
<li><code>docker-compose down</code></li>
</ul>
<hr>
<h2 id="mysql">Mysql</h2>
<ul>
<li>You can then connect to the server using <code>mysql</code>, just as you connect to any Mysql instance: <code>mysql -h ip -u username -p</code></li>
<li>If you don’t have mysql installed locally, you can run it from the Docker container: <code>docker exec -it mysql_container bash</code></li>
<li>check version: <code>mysql&gt; SELECT VERSION();</code></li>
</ul>
<hr>
<h2 id="redis">Redis</h2>
<ul>
<li>If you <strong>have</strong> redis-cli installed locally,you can then connect to the server using <code>redis-cli</code>, just as you connect to any Redis instance: <code>redis-cli -h ip -a &lt;password&gt;</code>
<ul>
<li>To specify a different host name or an IP address, use the<code>-h</code>option</li>
<li>To set a different port, use<code>-p</code></li>
<li><code>-a</code> <!-- raw HTML omitted --></li>
</ul>
</li>
<li>If you <strong>don’t have</strong> redis-cli installed locally, you can run it from the Docker container: <code>$ docker exec -it redis_container bash</code></li>
<li>check server info: <code>info server</code></li>
<li>check module: <code>module list</code></li>
</ul>
<hr>
<h2 id="docker-composeyml">docker-compose.yml</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-docker-compose.yml" data-lang="docker-compose.yml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">mysql</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">mysql:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">mysql_container</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_ROOT_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">&lt;password&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_DATABASE</span><span class="p">:</span><span class="w"> </span><span class="l">database_name</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_USER</span><span class="p">:</span><span class="w"> </span><span class="l">username</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">&lt;password&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;3306:3306&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span>--<span class="l">default-authentication-plugin=mysql_native_password --bind-address=0.0.0.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">mysql_data:/var/lib/mysql</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">always</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">redis</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">redis/redis-stack:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">redis_container</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;redis-stack-server&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;--requirepass&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;&lt;password&gt;&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;--bind&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;0.0.0.0&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;6379:6379&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;8001:8001&#34;</span><span class="w">  </span><span class="c"># RedisInsight web UI 默认端口</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">redis_data:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">always</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">mysql_data</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">redis_data</span><span class="p">:</span><span class="w">
</span></span></span></code></pre></div><h2 id="踩坑">踩坑</h2>
<ul>
<li>
<p><a href="https://github.com/redis/go-redis/issues/2081"  target="_blank" rel="noopener" >redisBloom commands don&rsquo;t work · Issue #2081 · redis/go-redis</a></p>
<p>换用redis-stack即可</p>
</li>
</ul>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://hub.docker.com/_/mysql"  target="_blank" rel="noopener" >mysql - Official Image | Docker Hub</a></li>
<li><a href="https://medium.com/@chrischuck35/how-to-create-a-mysql-instance-with-docker-compose-1598f3cc1bee"  target="_blank" rel="noopener" >How to Create a MySql Instance with Docker Compose | by Chris Chuck | Medium</a></li>
<li><a href="https://redis.io/docs/latest/develop/connect/cli/"  target="_blank" rel="noopener" >Redis CLI | Docs</a></li>
<li><a href="https://hub.docker.com/r/redis/redis-stack"  target="_blank" rel="noopener" >redis/redis-stack - Docker Image | Docker Hub</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>浅谈《艾尔登法环》</title>
      <link>https://ds63.eu.org/2024/elden-ring/</link>
      <pubDate>Thu, 04 Jul 2024 22:53:45 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/elden-ring/</guid>
      <description>宫崎英高再度登上神坛</description>
      <content:encoded><![CDATA[<p><strong>从dlc发售(2024年6月21日)到现在已经过去了两个礼拜。我也于今天(7月4日)，终于以打败最终boss——约定之外 拉塔恩 来为自己这45个小时的幽影地之旅画下句号。感慨良多，特在此胡言乱语。</strong></p>
<h2 id="谏言">谏言</h2>
<p>谏言系统是我入正的一大动力。</p>
<p><a href="https://www.gcores.com/articles/148030"  target="_blank" rel="noopener" >玩了几天《艾尔登法环》后，对谏言系统的小小的感悟 | 机核 GCORES</a>，这篇文章大体上说出了我的想法，以下几点是文中没提到的：</p>
<ul>
<li>这次dlc的谏言中有不少坏哥哥，比如大部分的“前有隐藏道路”和地图bug前的“前有翻滚”，但好哥哥还是占据了大多数。我玩本体的时候嫌麻烦，很少留谏言，但到了dlc后，会特意地去留。一大原因是dlc数值高，怪物攻击欲望又强。推图时弹尽粮绝之际，自己之前谏言被人好评所回的血无异于雪中送炭,让我感受到帮助他人就是帮助自己。</li>
<li>除了好哥哥和坏哥哥，玩梗的更是给游戏增加了不少乐趣。谏言系统不允许用户自由输入文字，而是只提供了特定的句式、单词，玩家只能在其中进行选择。但就是这样看似呆板的系统也能被玩出花来。感兴趣的话可以参看几篇：
<ul>
<li><a href="https://tieba.baidu.com/p/9070525092"  target="_blank" rel="noopener" >【图片】【科普】关于留言“边界”的含义解释【艾尔登法环吧】_百度贴吧</a></li>
<li><a href="https://www.reddit.com/r/Eldenring/comments/1dqfj73/what_does_the_edge_mean_in_the_message/"  target="_blank" rel="noopener" >What does the &ldquo;edge&rdquo; mean in the message? : r/Eldenring</a>。</li>
<li><a href="https://tieba.baidu.com/p/9076776131"  target="_blank" rel="noopener" >吃个食堂，看着谏言了【艾尔登法环吧】_百度贴吧</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="boss难度">Boss难度</h2>
<p>艾尔登法环销量数据远远超过了 From Software 过去作品的市场份额，我认为其中一大原因在于给轻度玩家提供了选择，使其在使用一定套路下也能轻松过关。我个人便是其中之一。</p>
<p>我可以说是一个手残玩家，也不愿花费大量时间去进行背板。一个Boss卡个一两天可能就是我的极限了。但法环提供了足够多的选择，如：角色加点，武器、战灰、骨灰、护符、祷告、魔法、道具等等。针对每个Boss的特点去进行对应的配装，让我可以卡得不会那么痛苦。</p>
<p>不过本次dlc中有几个boss深受玩家诟病,它们的共同点是</p>
<ul>
<li>攻击欲望强，</li>
<li>仇恨大部分集中在主角身上</li>
<li>战斗视角很飘，尤其是大体型Boss，很多时候连出招都看不清</li>
<li>数值高</li>
</ul>
<p>比如最终Boss，约定之王-拉塔恩，就因为他的高数值和“疯狗”般的攻击欲望以及光污染，成了不少人打差评的理由。</p>
<p>我个人也被折磨了几天。</p>
<ol>
<li>
<p>2024年7月1日
打拉塔恩，用盾戳，戳到半血就不行了。于是拉人打，蛮有乐子的。一地的黄符，踩上去看别人的穿搭来考虑是否要拉。叫了好几个吧，都是因为我坑了。唉。</p>
</li>
<li>
<p>2024年7月2日
继续打拉塔恩。用癫火调香瓶。打了得有二十次，最好一次剩五分之一吧。放弃了。</p>
<p>接下来打算用拒绝的刺，收集了下推荐的搭配，发现本体还有不少内容没探。</p>
</li>
<li>
<p>2024年7月4日
本已和拉塔恩和解多时，但惊闻1.12.4更新削弱了不少武器，拒绝的刺幸免于难，于是趁没削弱前再试一把。四个拒绝的刺成功过了。成就感不高，只有解脱。录像如下：<a href="https://www.youtube.com/watch?v=c5i80-Di4dg&amp;ab_channel=EricEdward"  target="_blank" rel="noopener" >某年拒绝的刺击杀拉塔恩 - YouTube</a></p>
</li>
</ol>
<hr>
<h2 id="宫崎英高">宫崎英高</h2>
<p>日厂游戏的一大特点是会有很鲜明的个人风格，换句话说，玩家们谈论更多的是明星制作人而非背后的工作室。宫崎英高便是其中之一。</p>
<p>网上有不少段子是以“宫崎英高小时候”开头的，初见者可能会惊讶玩家为什么会对他有这么大的恶意。不过，这类段子大部分都是调侃为主，玩宫崎英高的游戏也相当于和他斗智斗勇:进门前先调整视角观察门后、天花板是否有藏怪;遇到突兀的墙壁、绘画先翻滚；看到毒沼泽等烂地磕个抗毒道具后也能甘之若贻&hellip;</p>
<p>在艾尔登法环本体加dlc一周目下来一百五十个小时的游玩后，我发现我开始被宫崎英高同化了，以前还会觉得里面的一些怪恶心，现在连手怪，咒蛙都觉得可爱，壶内容物甚至觉得漂亮，被藏起来的怪吓一跳后的第一反应会是欣喜，笑着想“小高加一分”。</p>
<hr>
<h2 id="碎片化叙事">碎片化叙事</h2>
<p>碎片化叙事是魂系游戏的一大特点，我个人是很喜欢这点的。我觉得这样更真实，也更自然。</p>
<p>法环的故事和设定隐藏在NPC的话语、道具的文本、场景信息中。一段段简短的文本，却能勾勒出一个个精彩的故事。</p>
<p>可以举出不少例子：</p>
<ul>
<li>在伊利斯教堂，可以遇到一位法师叫托普斯,初见的时候会找褪色者要十卢恩和学院钥匙。交给他后，玩家再一次遇见他时便是他的尸体和一些道具。从文本中我们才得知：这人称废石的托普斯，意外被隔离在学院外，一直想回去，为了探索魔法，最后成了，研究出了足以成立新教室的发现。感兴趣的话可以看<a href="https://forum.gamer.com.tw/C.php?bsn=36726&amp;snA=9225"  target="_blank" rel="noopener" >【漫畫】感謝老師的教誨 @艾爾登法環（Elden Ring） 哈啦板 - 巴哈姆特</a>。</li>
<li>角人和稀人间的冲突。游戏中对二者都有基于其特定视角的描述,发人深思
<ul>
<li>角人：
<ul>
<li>
<blockquote>
<p>……都被烧掉了。
被梅瑟莫和他的爪牙烧掉了。
我们做了什么吗？
我们就只有安分地生活啊……</p>
</blockquote>
</li>
</ul>
</li>
<li>稀人
<ul>
<li>
<blockquote>
<p>……好痛，我的身体、好痛……
呜、呜呜呜……
……我问你，我还是个人吗？
因为我还是，才会这么痛苦吗……？</p>
</blockquote>
</li>
</ul>
</li>
<li>蕾妲对这件事的评价是
<blockquote>
<p>玛莉卡大人命令梅瑟莫先生肃清塔之民族，他的族人因此蒙受火难。不能原谅黄金树，也是合情合理。不过，残害同类是人的天性──塔之民族也不例外。他们不是平白无辜的好人。只不过是恰巧，沦为输家。真令人感伤。</p>
</blockquote>
</li>
</ul>
</li>
<li>埃贡。在「通柱坡中段」会听到他的哀嚎。当玩家击杀尖刺山的飞龙后，他大受感动，请求玩家当对上“狂龙”贝勒的时候，召唤他的灵魂，他将一同作战。击败狂龙贝勒后，将捡到埃贡的装备，从装备文本中才得知，埃贡曾经是战场拾荒者，巧合下得到龙飨的力量，成为了龙战士。文本不多，但场景氛围和配音演员出色的配音让我认识了这位可敬的龙战士。</li>
</ul>
<hr>
<h2 id="地图设计">地图设计</h2>
<p>本次DLC的地图设计很有特色，喜欢的人，比如我：觉得光这地图设计就值回票价，不喜欢的人嫌绕，地图不够直观,太空，奖励给的太少。我说些自己的观点：</p>
<p>相较于本体中大地图加箱庭的设计，DLC是将大地图也做成了箱庭。不少地方你在游戏提供的平面地图上以为近在咫尺，但实际上却有高度落差，地图上近的，实际距离却很远，真正的路可能藏在某处悬崖边或某个洞穴的出口。大部分时候这会带来“柳暗花明又一村”的惊喜，但有时候也会因为DLC怪物的高数值和高攻击欲望导致你在逃命中错过一个隐蔽的路口，导致某块地区迟迟找不到入口，最终只能依赖于网上攻略。</p>
<hr>
<h2 id="dlc历程">DLC历程</h2>
<p>将这几天日记中相关的部分摘录如下</p>
<h3 id="2024年6月21日">2024年6月21日</h3>
<p>刚进幽影地，发现数值确实高啊，一个没大血条的打我三下,我人就没了。费劲打完后还没掉东西。（后来才知道叫咒剑士）</p>
<p>收集了下庇佑好多了。探贝瑞特监牢，刚进去发现很美，星空点点。但这里是壶的制作处，过程是将“罪人”凌迟后，肉塞进壶里。</p>
<p>地图设计的很棒，峰回路转，自己走了一圈，又回到原地了，这种感觉很不错。惊叹于制作者的巧思。dlc新增的武器也很帅，但奈何自己玩的是法师流，武器不多，后面考虑洗点，或者是用诚实商人来刷级。dlc还有一点不同是，这次弹尽粮绝的次数变多了，但基本都能勉强击杀掉boss。比如探贝瑞特监牢时，打关底boss，我只剩一瓶血，蓝瓶用光了。再把黑刀叫出来后，我以为不行了，没想到直接压着boss打，过了。接着探恩希斯城，这城比较小，不一会儿就到打双月骑士。攻击欲望很强，但角色很帅，所以能接受。</p>
<h3 id="2024年6月22日">2024年6月22日</h3>
<p>把庇佑升到了五级。打败了舞狮。开了青蓝海岸的地图。风景很美。dlc目前我觉得蛮不错的。至少配得上特别好评。它有几个优点：</p>
<ul>
<li>风景很美</li>
<li>地图设计得好，大地图与箱庭的结合</li>
<li>新增了许多新武器，很帅</li>
</ul>
<p>缺点也有：</p>
<ul>
<li>dlc前的1.12更新，特地削了好几把轮椅</li>
<li>dlc初入时数值很高。但也能理解。开发者需要考虑到游戏已经发售两年，玩家已有存档的水平多为游戏大后期。但是又得考虑到dlc所吸引的新玩家。因此需要一种机制，让绝大部分进入dlc的玩家都在同一起跑线上。而拉高游戏数值，提升游戏难度。并提供百分比加成来降低游戏难度，这是一种比较容易的解决方式。</li>
<li>dlc中法师武器，魔法好像不多</li>
</ul>
<p>网上不少评论都是在骂的，我觉得现在社会戾气太重了。很不喜欢这样的风气。</p>
<h3 id="2024年6月23日">2024年6月23日</h3>
<p>继续打dlc，给我气笑了：</p>
<ul>
<li>打黄金河马，叫了两npc和大姐,我连锁定都没锁，一进门boss直接就冲我过来了</li>
<li>路上遇到一群小兵和龙打架，我一过去就都打我，</li>
<li>路上遇到的山羊也冲我</li>
<li>石棺大洞，有三个激光的，太tm猛了。</li>
</ul>
<h3 id="2024年6月24日">2024年6月24日</h3>
<p>探物种保藏库，地图设计得很棒，立体感很足。</p>
<p>打梅瑟莫。初见很顺利，打得只剩五分之一的血了，还想着别着急打完，先欣赏下boss出招。但后面打了得快10次，都没过。</p>
<p>不过捡到了两个“轮椅”，拒绝的刺和突刺盾，后面试试。还想试试仕女剑，但我灵敏和力量太低了。</p>
<p>接着开了幽影城后门，这条路第一次走以为走过了，但没想到就差坐个电梯就能到赐福点，后面还是看视频才发现的。打了2个大树守卫，我还是不会打，第一个靠大哥，第二个靠bug。甚至还有坠星兽物，在dlc里感觉亲切多了，攻击好躲，仇恨大部分都可以被大哥给吸走。</p>
<h3 id="2024年6月25日">2024年6月25日</h3>
<p>今天做了尤弥尔的支线，谈了幽影城后门，青蓝海岸上半部分。发现法环有些难打的怪，在换了护符，装备后，好打许多。</p>
<h3 id="2024年6月26日">2024年6月26日</h3>
<p>今天竟然还是探幽影城，跟着攻略找到了之前走过，但不知道是有隐藏墙的区域。网上有些差评是嫌dlc地图太空，奖励幽默。我的评价是：那种重复的地牢在本体已经品鉴得够多甚至腻了，现在这样的奖励分布可以认为是打了随机mod，还挺有意思。</p>
<h3 id="2024年6月27日">2024年6月27日</h3>
<p>探石棺大洞，激光虫在听到声音后就翻滚，也闯过去了。融泥骑士没打的欲望，骑士灵活性太强，于是用调香瓶加串联火花香逃课了。轮椅就是轮椅。托莉娜是真漂亮啊。</p>
<p>然后去探幽影城后门出来的地方。出来就是老将盖乌斯。初见还好，后面一进雾门就是一个冲刺。于是再次逃课。艾尔登法环对我的一大优点是能逃课。不像只狼那样，得自身技术过硬。</p>
<p>另一大优点是地图设计，探索地图这个过程就已经够吸引人，奖励的话，强化素材我基本可以无限买，骨灰的话我也只用固定的几个，衣服的话我也只穿那几套，主要还是突出一个贵在拥有，哈哈。</p>
<p>看<a href="https://www.bilibili.com/video/BV1PM4m1m7Bn/"  target="_blank" rel="noopener" >艾尔登法环DLC 幽影城 3D地图导航_哔哩哔哩bilibili</a>，再次感叹幽影城做得真好。</p>
<p>查了下地图，发现我只剩五个地方了。唉唉!</p>
<h3 id="2024年6月28日">2024年6月28日</h3>
<p>今天探谷底森林。因为提前知道老翁是机制怪，得先弹反。加上那个地图玛莉卡楔石蛮多的。死了也不用跑多远，于是本来设计让潜行的一张地图，变成了我去追着老翁弹反，哈哈。</p>
<p>米德拉这个boss可以说是dlc中做得最好的一个boss之一。他有德啊，自身中了癫火，为了不为害世间，躲在家里，还用了两幅画做隐藏门把自己藏起来。但我这卑鄙的褪色者克服万难，闯进了人家家里。还逼得人放弃了多年的坚持。他的招式也很优雅，但又不像双月那样几乎无限连招。我初见配合大哥很快把他打得只剩六分之一血，舍不得一遍过。但后来打了十来次都过不去了。（这剧情似乎有点熟悉）于是转而去探索尖刺山。</p>
<p>尖刺山那两条相斗的飞龙，之前我是站高处想用远程魔法阴死，但试了好几次都不行。这次是靠癫火调香瓶，找准机会转进龙肚子底下，无脑按lt。然后就结束了。癫火调香瓶堪称轮椅中的战斗机！</p>
<p>幻想了一波终极版艾尔登法环的几个要素(只是幻想，宫崎英高要是真给这样做，那就不是他了):</p>
<ul>
<li>交界地和幽影地的地图结合在一起</li>
<li>装备外观幻化</li>
<li>快速存档、回档</li>
<li>带鱼屏、超宽屏适配</li>
<li>“添火”</li>
<li>数据统计</li>
<li>地图足迹显示</li>
<li>剧情补全</li>
<li>更易于切换的法术栏</li>
</ul>
<h3 id="2024年6月29日">2024年6月29日</h3>
<p>用调香瓶，体感速度： 狂龙10秒，米德拉二十秒，梅瑟莫一分钟；知道调香瓶是轮椅，但没想到能这么轮椅。一个小时不到打了四个追忆boss，我搁这boss rush呢。</p>
<p>发现法环又一个优点，那就是提供选项，boss，厉害的可以打得很炫酷，但手残如我，也能有过的方法。</p>
<p>另一个优点是：谏言！</p>
<p>看<a href="https://tieba.baidu.com/p/9070525092"  target="_blank" rel="noopener" >【图片】【科普】关于留言“边界”的含义解释【艾尔登法环吧】_百度贴吧</a>，之前就好奇怎么会有这么多“边界”的谏言。这下解惑了。如果中国不是局域网，那会更有趣。</p>
<h3 id="2024年7月1日">2024年7月1日</h3>
<p>打拉塔恩，用盾戳，戳到半血就不行了。拉人，蛮有乐子的。一地的黄符，踩上去看别人的穿搭来考虑是否要拉。叫了好几个吧，都是因为我坑了。嗨。</p>
<h3 id="2024年7月2日">2024年7月2日</h3>
<p>继续打拉塔恩。用癫火调香瓶。打了得有二十次，最好一次剩五分之一吧。放弃了。</p>
<p>接下来打算用拒绝的刺，收集了下推荐的搭配，发现本体还有不少内容没探。</p>
<h3 id="2024年7月4日">2024年7月4日</h3>
<p>4点醒来。本已和拉塔恩和解多时，但惊闻1.12.4更新削弱了不少武器，万幸拒绝的刺幸免于难，于是趁没削弱前再试一把。四个拒绝的刺成功过了。成就感不高，只有解脱。</p>
<h3 id="2024年10月20日">2024年10月20日</h3>
<p>凌晨翻看这篇博客，顺手改了几个别字，更多的是怀念自己玩法环的这段快乐时光。好像清空下玩艾尔登法环的记忆，重新玩一遍。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>使用NapCatQQ和NoneBot搭建qqBot</title>
      <link>https://ds63.eu.org/2024/setup-qqbot-using-napcatqq-and-nonebot/</link>
      <pubDate>Fri, 14 Jun 2024 16:23:34 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/setup-qqbot-using-napcatqq-and-nonebot/</guid>
      <description>新的开始</description>
      <content:encoded><![CDATA[<p><strong>因项目更新频繁，请注意本文最后更新时间，以免因本文内容失效造成困扰</strong></p>
<h2 id="缘起">缘起</h2>
<p>我在半年前折腾过一次qqBot的搭建，但那次由于风控问题，只能放弃了,具体记录在
<a href="https://ds63.eu.org/2023/setup_qqbot/"  target="_blank" rel="noopener" >qqBot 搭建 | EuDs&rsquo;s Blog</a>。</p>
<p>但这两天发现了<a href="https://github.com/NapNeko/NapCatQQ"  target="_blank" rel="noopener" >NapNeko/NapCatQQ: 基于NTQQ的无头Bot框架</a>，决定再次折腾，以下记录我的过程。</p>
<h2 id="过程">过程</h2>
<p>说明：以下均为Windows平台</p>
<ol>
<li>在<a href="https://github.com/NapNeko/NapCatQQ/releases"  target="_blank" rel="noopener" >Releases · NapNeko/NapCatQQ</a>下载<code>NapCat.Shell.zip</code>，并解压</li>
<li>运行<code>launcher.bat</code>，扫码登录</li>
<li>在NapCat的网页，新增Websocket客户端,url填<code>ws://127.0.0.1:8080/onebot/v11/ws</code>,token填<code>config/webui.json</code>里面的。具体参考
<ul>
<li><a href="https://napneko.github.io/config/basic#%E9%80%9A%E8%BF%87-webui-%E9%85%8D%E7%BD%AE-onebot-%E6%9C%8D%E5%8A%A1"  target="_blank" rel="noopener" >💖 NapCatのWebUI配置指南💖 | NapCatQQ</a></li>
</ul>
</li>
<li>参照<a href="https://nonebot.dev/docs/quick-start"  target="_blank" rel="noopener" >快速上手 | NoneBot</a>创建并运行NoneBot项目，注意：创建时适配器应选择OneBot V11，新建<code>.env</code>文件，里面填<code>ONEBOT_ACCESS_TOKEN=第三步填的token</code></li>
</ol>
<h2 id="感受">感受</h2>
<ol>
<li>这次整体流程很顺畅，最主要的还是因为登录只要手机扫个码就行，不用再一个个试协议来躲避风控。</li>
<li>时隔半年多又有了qq bot的需求，发现NapCat和NoneBot依然坚挺，但自己原先写的记录已不太适用，于是修改了下。</li>
</ol>
<h2 id="todo">Todo</h2>
<ul>
<li><input disabled="" type="checkbox"> 写个脚本，使得可以开机自启</li>
<li><input disabled="" type="checkbox"> 部署到服务器上，不知道会不会再遇到风控问题</li>
<li><input disabled="" type="checkbox"> 插件：<del>去年今日</del></li>
<li><input disabled="" type="checkbox"> </li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://napneko.github.io/zh-CN/guide/getting-started"  target="_blank" rel="noopener" >NapCatQQ</a></li>
<li><a href="https://napneko.github.io/zh-CN/guide/integration"  target="_blank" rel="noopener" >接入框架 | NapCatQQ</a></li>
<li><a href="https://x.none.bot/before/install_napcat"  target="_blank" rel="noopener" >NapCat 使用教程 | NoneBot 文档</a></li>
<li><a href="https://napneko.github.io/guide/boot/Shell"  target="_blank" rel="noopener" >Shell | NapCatQQ</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>AutoBangumi初体验</title>
      <link>https://ds63.eu.org/2024/first-experience-of-autobangumi/</link>
      <pubDate>Fri, 14 Jun 2024 00:11:18 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/first-experience-of-autobangumi/</guid>
      <description>为了更好的看番体验</description>
      <content:encoded><![CDATA[<h2 id="说明">说明</h2>
<ul>
<li>AutoBangumi 是什么?
<blockquote>
<p>AutoBangumi 是基于 RSS 的全自动追番整理下载工具。只需要在 Mikan Project 等网站上订阅番剧，就可以全自动追番。 并且整理完成的名称和目录可以直接被 Plex、Jellyfin 等媒体库软件识别，无需二次刮削。</p>
</blockquote>
</li>
<li>我的运行环境:
<ul>
<li>Windows11</li>
<li>docker</li>
</ul>
</li>
<li>资源占用情况(同时下载10集番剧时)
<ul>
<li>cpu: 最高可到15%</li>
<li>内存：维持在300MB以内</li>
<li>带宽：做种的人多的话能跑满</li>
</ul>
</li>
</ul>
<h2 id="过程">过程</h2>
<p>一开始我参考官方教程<a href="https://www.autobangumi.org/deploy/docker-compose.html"  target="_blank" rel="noopener" >通过 Docker Compose 部署 AutoBangumi | AutoBangumi</a>，但它所提供的<code>docker-compose.yml</code>文件有些简陋。</p>
<p>我主要是遇到了<a href="https://github.com/EstrellaXD/Auto_Bangumi/issues/410"  target="_blank" rel="noopener" >[错误报告]无法使用Downloader，https错误 · Issue #410 · EstrellaXD/Auto_Bangumi</a>这个问题。隐约感觉到可能是因为网段不同的缘故，但我没有进一步折腾。</p>
<p>后来我参照的是<a href="https://www.himiku.com/archives/auto-bangumi.html"  target="_blank" rel="noopener" >AutoBangumi：自动追番，解放双手 - 初之音</a></p>
<p>这个教程写得很棒。以下只补充几点自己遇到的问题：</p>
<ul>
<li>教程里所说的qBittorent的默认密码并不为<code>adminadmin</code>，而是要去运行日志里找，类似于
<blockquote>
<p>未设置 WebUI 管理员密码。为此会话提供了一个临时密码：gkNJ3xcz2</p>
</blockquote>
</li>
<li>播放器似乎目前只支持Plex/Emby/Jellyfin</li>
<li>AutoBangumi的web ui没提供的功能，可以去qBittorrent那边找</li>
<li>重命名通过qBittorrent下载的，但是想让 AB 重命名的番剧(好像不起作用？)
<ul>
<li>先限制qBittorrent的做种</li>
<li>配合<code>advance</code>模式，将这些番剧手动移动至 番剧名/Season x 的文件夹内，再将其分类设置为 Bangumi ，就可以被 AB 重命名</li>
</ul>
</li>
</ul>
<h2 id="开机自启">开机自启</h2>
<p>可参考：</p>
<ul>
<li><a href="https://www.bilibili.com/video/BV1oC4y1f7uY/"  target="_blank" rel="noopener" >Potplayer 挂载 Alist，播放网盘视频，看阿里云/百度/115网盘电影资源</a></li>
<li><a href="https://www.mibashuo.com/post/set-exe-as-system-service-with-nssm"  target="_blank" rel="noopener" >用nssm简易设置任意应用程序exe为Windows系统服务 - 米八说</a></li>
</ul>
<h2 id="windows-开启webdav">Windows 开启WebDAV</h2>
<blockquote>
<p>WebDAV stands for &ldquo;Web-based Distributed Authoring and Versioning&rdquo;. It is a set of extensions to the HTTP protocol which allows users to collaboratively edit and manage files on remote web servers.</p>
</blockquote>
<p>我的理解是它能让本地的文件在其他设备上访问，而不仅局限于Windows。</p>
<p>Potplayer还支持WebDav源的视频的直接播放。</p>
<p>但我只是了解，没进一步折腾，因为感觉不太适合我的需求。</p>
<p>可参考：</p>
<ul>
<li><a href="https://sspai.com/post/78540"  target="_blank" rel="noopener" >Windows开启WebDAV - 少数派</a></li>
<li><a href="https://www.yydnas.cn/2023/08/2023.08.01-Windows%E6%90%AD%E5%BB%BAWebDav%E6%B5%81%E7%A8%8B%E4%BB%A5%E5%8F%8A%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/index.html"  target="_blank" rel="noopener" >Windows搭建WebDav流程以及踩坑记录 | Forever Study</a></li>
<li><a href="https://www.horosama.com/archives/259"  target="_blank" rel="noopener" >win10/linux一键搭建webdav服务和公网访问教程 – 萌萌哒赫萝的小站</a></li>
</ul>
<h2 id="emby">EMBY</h2>
<p>注： 以下过程参考了</p>
<ul>
<li><a href="https://emby.media/index.html"  target="_blank" rel="noopener" >Emby - The open media solution</a></li>
<li><a href="https://www.rainlain.com/index.php/2024/02/28/2023/"  target="_blank" rel="noopener" >WINNAS轻松搭：EMBY媒体资源库进阶刮削方案 – 梦雨玲音</a></li>
</ul>
<ol>
<li>在 docker-compose.yml 底下加入以下内容：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-docker" data-lang="docker"><span class="line"><span class="cl">emby:<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  image: lovechen/embyserver:latest<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  container_name: emby<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  <span class="c1"># network_mode: host</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  ports:<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - 8096:8096<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - 8920:8920<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - 1900:1900/udp<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - 7359:7359/udp<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  environment:<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">PUID</span><span class="o">=</span><span class="m">1000</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">PGID</span><span class="o">=</span><span class="m">1000</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">GIDLIST</span><span class="o">=</span><span class="m">0</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">TZ</span><span class="o">=</span>Asia/Shanghai<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">HTTP_PROXY</span><span class="o">=</span><span class="s2">&#34;http://你的代理IP:端口/&#34;</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - <span class="nv">HTTPS_PROXY</span><span class="o">=</span><span class="s2">&#34;http://你的代理IP:端口/&#34;</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  devices:<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - /dev/dri:/dev/dri<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  volumes:<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - ./emby:/config<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>    - 宿主机媒体文件夹的地址:/media/Bangumi <span class="c1"># 挂载媒体库，可按个人喜欢进行修改，不一定就得映射到/media/Bangumi</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>  restart: unless-stopped<span class="err">
</span></span></span></code></pre></div><ol start="2">
<li>重启镜像</li>
<li>访问<code>http://127.0.0.1:8096/</code>进行设置</li>
<li>媒体库路径按照先前在<code>docker-compose.yml</code>文件中设置的，比如我这里就是<code>/media/Bangumi</code></li>
<li>局域网内访问
<ul>
<li>按照<a href="https://emby.media/support/articles/Connectivity.html"  target="_blank" rel="noopener" >Connectivity | Emby Documentation</a>进行排查，主要是开放端口。</li>
<li>仪表盘显示的访问地址无法使用的话，可访问<code>本地ip地址:8096</code></li>
<li>校园网环境下，几乎可以做到拖哪播哪</li>
</ul>
</li>
<li>todo: 尝试使用ipv6+ddns实现访问地址固定
<ul>
<li><a href="https://www.himiku.com/archives/plex-with-ipv6.html"  target="_blank" rel="noopener" >为 Plex 配置 IPv6 网络 - 初之音</a></li>
</ul>
</li>
</ol>
<h2 id="初体验的感受">初体验的感受</h2>
<p>刚接触没多久，我就意识到这其中的魅力：</p>
<ul>
<li>同一部番剧，不同字幕组，不同时期所提供的资源质量不同。</li>
<li>资源质量好坏的评判标准有很多点,对我来说：
<ol>
<li>内封字幕 &gt; 内嵌字幕</li>
<li>简体字幕 &gt; 繁体字幕</li>
<li>中日双语 &gt; 简体字幕</li>
<li>BDRip &gt; WebRip</li>
<li>翻译质量</li>
<li>&hellip;</li>
</ol>
</li>
<li>综合以上两条，我需要从诸多资源中进行取舍，找到最好的那个。</li>
<li>下载是使用Bittorrent。一个种的下载速度很大程度上取决于是否有人做种。那起起伏伏的下载速度蕴含着不少信息量。比如说当下载速度从几B一下子跃到几百KB时，这就在无声地告诉我，互联网的另一端，有位拥有着类似的爱好的用户开机了。</li>
<li>还是BitTorrent，这个有着二十多年历史的协议堪称互联网的缩影:你当然可以下完就跑，但你也可以去做种，通过占用自己的一部分资源（内存，存储，带宽）来造福下一位使用该种子的用户。</li>
<li>现阶段，只有特别喜欢的番我才会去下。一想到自己在一番折腾后，可以不用再忍受烦人的加载和广告，就能看到自己喜欢的番。这种成就感是很难比拟的。</li>
</ul>
<p>我现在还只是在自己的电脑上折腾，已经可以想象当我拥有一台nas后，它将吞噬我多少时间。</p>
<p>不过我乐意！</p>
<h2 id="比较">比较</h2>
<p>从昨天初体验冷静后，我对NAS和网盘进行了比较</p>
<ul>
<li>价格方面: NAS优势不大</li>
<li>隐私方面: NAS可以免于审查，但真正隐私的内容，我倾向于连NAS都不信任。最安全的方式还是敏感信息不上网,至少公网无法访问。</li>
<li>从访问速度方面: 局域网内访问，NAS优于网盘，但异地公网访问，NAS很难强于网盘。</li>
</ul>
<p>但让我选的话，我会选NAS，因为它更能给我一种数据是掌握在你自己手里的感觉，而且，我喜欢折腾。</p>
<h2 id="todo">Todo</h2>
<ul>
<li>
<p><input disabled="" type="checkbox"> 蜜柑计划感觉还是比较偏新番(主要是2013年之前)，我想下点老番，该去哪里找呢
- <a href="https://iblog.ren/posts/40/"  target="_blank" rel="noopener" >动漫BT网站收集</a></p>
</li>
<li>
<p><input disabled="" type="checkbox"> 直接在qb下的番，不知道怎么让ab重命名之类的</p>
</li>
<li>
<p><input disabled="" type="checkbox"> 参考<a href="https://champhoon.xyz/note/alist-streaming/"  target="_blank" rel="noopener" >论 AList 的滥用：多平台串联搭建个人影音－番剧流媒体服务 - 澄沨的漫游茶记</a>，部署AList</p>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://sleele.com/2020/03/16/%E9%AB%98%E9%98%B6%E6%95%99%E7%A8%8B-%E8%BF%BD%E5%89%A7%E5%85%A8%E6%B5%81%E7%A8%8B%E8%87%AA%E5%8A%A8%E5%8C%96/"  target="_blank" rel="noopener" >高阶教程-追剧全流程自动化 | sleele的博客</a></li>
<li><a href="https://feng.red/300%20%E8%AF%84%E4%BB%B7/s/%E6%9C%AC%E5%9C%B0%E8%87%AA%E5%8A%A8%E8%BF%BD%E7%95%AA&#43;%E5%BD%B1%E8%A7%86%E5%89%A7%E5%88%AE%E5%89%8A%E6%95%B4%E7%90%86%28%E5%B1%80%E5%9F%9F%E7%BD%91%E5%A4%9A%E8%AE%BE%E5%A4%87%E6%92%AD%E6%94%BE%29%28%E6%97%A0nas%29/"  target="_blank" rel="noopener" >本地自动追番+影视剧刮削整理(局域网多设备播放)(无NAS)</a></li>
<li><a href="https://freshp0325.xyz/posts/2023071701"  target="_blank" rel="noopener" >如何管理自己的数字与生活资源？(Anime篇) - 桃罐</a></li>
<li><a href="https://champhoon.xyz/note/alist-streaming/"  target="_blank" rel="noopener" >论 AList 的滥用：多平台串联搭建个人影音－番剧流媒体服务 - 澄沨的漫游茶记</a></li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>VSCode配置</title>
      <link>https://ds63.eu.org/2024/vscode%E9%85%8D%E7%BD%AE/</link>
      <pubDate>Thu, 13 Jun 2024 13:45:18 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/vscode%E9%85%8D%E7%BD%AE/</guid>
      <description>工欲善其事</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>VSCode是我的主力编辑器，但有些设置，虽然知道自己想调整什么，但又不知道它对应的名字，于是记录于此。</p>
<h2 id="字体">字体</h2>
<p><code>Editor: Font Family</code>: 我的设置为Consolas, &lsquo;新宋体&rsquo;, monospace</p>
<p>Windows下可以在<code>C:\Windows:\Fonts</code>找到本机安装的字体。</p>
<h2 id="quick-suggestions">Quick Suggestions</h2>
<p><code>Editor: Quick Suggestions</code></p>
<h2 id="整体界面的大小">整体界面的大小</h2>
<p><code>Window: Zoom Level</code></p>
<h2 id="问题与排查">问题与排查</h2>
<h3 id="2024年4月3日">2024年4月3日</h3>
<ul>
<li>问题描述：VSCode远程连接服务器，导致服务器卡死</li>
<li>排查过程：
这个问题我遇到过很多次。远程连接的服务器包括但不限于Azure,Amazon的。它们的一大共同特点就是内存小。</li>
<li>解决：
<ul>
<li>内存不大于2G的服务器尽量别使用VSCode进行远程连接</li>
</ul>
</li>
</ul>
<h3 id="2024年6月13日">2024年6月13日</h3>
<ul>
<li>
<p>问题描述: 最近输入老出问题，偏卡顿，要不就是一次性输入多个同样的字符。</p>
</li>
<li>
<p>排查过程：
通过控制变量法，发现只有在VSCode才有这种问题。进一步测试表面：只有在特定的项目才会出问题。</p>
<p>问题最终锁定在Quick Suggestions上。这个项目中有个markdown文件:十四万字，三百多kb。我将markdown文件的<code>editor.quickSuggestions</code>给关掉，就不怎么卡了。但我其实蛮喜欢这功能的,它不一定能有用，但时不时能给我些惊喜的发现。</p>
</li>
<li>
<p>解决</p>
<ul>
<li>最终我将该文件拆分为两个文件，现在似乎好多了。</li>
<li>另一种解决方式可能是：将<code>Editor: Quick Suggestions Delay</code>调大点。这个Delay我是理解成防抖的等待时间，不知道对不对。</li>
<li>这个issue提到了类似的问题：<a href="https://github.com/yzhang-gh/vscode-markdown/issues/489"  target="_blank" rel="noopener" >可否在文件较大时自动设置 syntaxDecorations 呢？ · Issue #489 · yzhang-gh/vscode-markdown</a></li>
</ul>
</li>
</ul>
<h2 id="2024年6月17日">2024年6月17日</h2>
<ul>
<li>问题描述：Win11下，“通过code打开”位于右键选项的二级菜单，我希望将其移到一级菜单</li>
<li>过程：
<ul>
<li><a href="https://github.com/BluePointLilac/ContextMenuManager"  target="_blank" rel="noopener" >BluePointLilac/ContextMenuManager: 🖱️ 纯粹的Windows右键菜单管理程序</a>该软件在Win10很好用，但未适配Win11。作者在21年就有适配Win11的计划，但因其工作繁忙未能成行。</li>
<li><a href="https://github.com/ikas-mc/ContextMenuForWindows11"  target="_blank" rel="noopener" >ikas-mc/ContextMenuForWindows11: Add Custom Context Menu For Windows11</a>。看文档感觉与我需求不符</li>
<li><a href="https://www.sordum.org/7615/easy-context-menu-v1-6/"  target="_blank" rel="noopener" >Easy Context menu v1.6</a>。似乎可用，但未开源，我不信任</li>
<li><a href="https://github.com/microsoft/vscode/issues/127365"  target="_blank" rel="noopener" >Integrate with the Windows 11 Context Menu · Issue #127365 · microsoft/vscode</a>，开发人员称该功能在inside版本实现，但因<a href="https://github.com/microsoft/vscode/issues/164689"  target="_blank" rel="noopener" >Uninstalling VS Code takes a long time, when enabling the Windows 11 context menu action · Issue #164689 · microsoft/vscode</a>，没有将其在稳定版本集成该功能的打算。（难绷，Win11都出几年了，能玩得转这右键菜单的软件怎么还是少数）</li>
<li>最终选择：修改注册表</li>
</ul>
</li>
</ul>
<h3 id="2024年10月14日">2024年10月14日</h3>
<ul>
<li>问题描述: 输不了中文句号</li>
<li>过程:
<ul>
<li>某个时候开始就输不了中文句号，测试发现只在vscode这样。</li>
</ul>
</li>
<li>解决
<ul>
<li>中文输入法下按<code>Ctrl+.</code>即可</li>
</ul>
</li>
</ul>
<h3 id="2025年1月29日">2025年1月29日</h3>
<ul>
<li>问题描述: 中文符号有黄色框</li>
<li>过程:
<ul>
<li>某日更新后出现</li>
</ul>
</li>
<li>解决:
<ul>
<li>启用 <code>Disable highlighting Of non basic ASCI | characters</code></li>
</ul>
</li>
</ul>
<h3 id="2025年6月16日">2025年6月16日</h3>
<ul>
<li>问题描述: 输入一个句号显示的是两个</li>
<li>过程:
<ul>
<li>以为是轴有问题，导致双击了，那好办，换一个就好。但换了后还是不行。</li>
<li>在其他地方试了下，发现只有vscode会出现这个问题。</li>
<li>谷歌搜了下，只搜到<a href="https://blog.csdn.net/qq_39710999/article/details/135947295"  target="_blank" rel="noopener" >VS Code输入1个中文标点符号出来2个的解决方案_vscode 处理异常中文标点-CSDN博客</a>，问题描述和我的很一致，但我没装这个插件。</li>
<li>发现似乎和我用的vim插件有关，果然找到了对应的issue，<a href="https://github.com/VSCodeVim/Vim/issues/9668"  target="_blank" rel="noopener" >Chinese input repeats characters when using VSCodeVim in insert mode · Issue #9668 · VSCodeVim/Vim</a>，最底下有个老哥给了解决方案，写得不是太详细，<a href="https://github.com/VSCodeVim/Vim/issues/9668#issuecomment-2976567562"  target="_blank" rel="noopener" >我稍微补充了下</a></li>
<li>看<a href="https://github.com/VSCodeVim/Vim/issues/9668#issuecomment-2988598532"  target="_blank" rel="noopener" >这个issue下有vscode员工的回复</a>。她找到了问题的根源，并用一段demo代码给出了证明。</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>软件质量保障复习笔记</title>
      <link>https://ds63.eu.org/2024/learn-software-quality-assurance/</link>
      <pubDate>Wed, 12 Jun 2024 19:51:22 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn-software-quality-assurance/</guid>
      <description>软件质量保障复习笔记</description>
      <content:encoded><![CDATA[<h2 id="第一章">第一章</h2>
<h3 id="软件的定义">软件的定义</h3>
<p>软件=程序+文档=数据+指令+文档</p>
<h3 id="软件测试">软件测试</h3>
<ul>
<li>软件测试是一组用来促进鉴定软件正确性、完整性、安全性和质量的过程。</li>
<li>换句话说，软件测试是一种实际输出与预期输出之间的审核或者比较过程。</li>
<li>经典定义: 在规定的条件下对程序进行操作，以发现程序错误，衡量软件质量，并对其是否能满足需求进行评估的过程。</li>
</ul>
<hr>
<h2 id="第二章">第二章</h2>
<h3 id="开发者测试">开发者测试</h3>
<ul>
<li>包括
<ol>
<li>单元测试 &lt;=&gt; 详细设计</li>
<li>集成测试 &lt;=&gt; 体系结构设计</li>
<li>系统测试 &lt;=&gt; 软件需求</li>
<li>验收测试 &lt;=&gt; 客户需求</li>
<li>Alpha和beta测试</li>
<li>回归测试</li>
</ol>
</li>
</ul>
<h3 id="单元测试">单元测试</h3>
<ul>
<li>侧重于核实软件的最小可测试元素</li>
<li>主要做功能正确的前提下的控制流和数据流的覆盖测试</li>
<li>目标
<ol>
<li>检验程序最小单元有无错误,如：接口、数据结构、边界、覆盖、逻辑</li>
<li>检验单元编码与设计是否吻合</li>
</ol>
</li>
</ul>
<h3 id="集成测试">集成测试</h3>
<ul>
<li>为什么进行集成测试？
<ul>
<li>一个模块可能对另一个模块产生不利的影响</li>
<li>将子功能合成时不一定产生所期望的主功能</li>
<li>独立可接受的误差，在组装后可能会超过可接受的误差限度</li>
<li>可能会发现单元测试中未发现的接口方面的错误</li>
<li>在单元测试中无法发现时序问题（实时系统）</li>
<li>在单元测试中无法发现资源竞争问题</li>
</ul>
</li>
<li>分类
<ul>
<li>非增式</li>
<li>增式
<ul>
<li>自顶向下</li>
<li>自底向上</li>
</ul>
</li>
</ul>
</li>
<li>“自顶向下”与“自底向上”的比较
<ul>
<li>什么时候能让测试者看到系统的框架</li>
<li>如何提供驱动模块和桩模块</li>
<li>生成测试数据的难易</li>
<li>什么时候暴露时序问题和资源竞争问题</li>
</ul>
</li>
</ul>
<h3 id="系统测试">系统测试</h3>
<ul>
<li>内容
<ul>
<li>软件系统之间的联合测试</li>
<li>软件、硬件等之间的联合测试</li>
<li>模拟真实运行环境的测试</li>
</ul>
</li>
<li>目标
<ul>
<li>检验组成整个系统的代码、以及系统的软硬件配合有无错误</li>
<li>代码实现的系统与用户需求是否吻合</li>
<li>检验系统的各种文档等是否完整、有效</li>
<li>模拟验收测试的要求，检查系统是否符合用户的验收标准</li>
</ul>
</li>
</ul>
<h3 id="α测试和β测试">α测试和β测试</h3>
<ul>
<li>α测试是由用户在开发环境下进行的测试,由开发者随时记录下错误情况和使用中的问题</li>
<li>β测试是一种验收测试，在实际使用环境下进行的测试.开发者通常不在测试现场,不能由程序员或测试员完成。</li>
</ul>
<h3 id="回归测试">回归测试</h3>
<ul>
<li>目标
<ul>
<li>修改的或增加的部分是正确的</li>
<li>没有引起其他部分产生错误</li>
</ul>
</li>
<li>应用
<ul>
<li>增量开发</li>
<li>版本控制</li>
<li>软件维护</li>
</ul>
</li>
</ul>
<h3 id="软件测试过程">软件测试过程</h3>
<ol>
<li>测试需求描述</li>
<li>测试计划</li>
<li>测试设计
<ul>
<li>用例</li>
<li>脚本</li>
<li>覆盖准则</li>
</ul>
</li>
<li>测试开发</li>
<li>测试执行</li>
<li>测试结果与预期结果比较</li>
<li>测试充分性评估</li>
<li>测试报告生成</li>
</ol>
<h3 id="黑盒测试">黑盒测试</h3>
<ul>
<li>黑盒测试被用来证实软件功能的正确性和可操作性</li>
<li>一种基于规格说明（Spec），不要求考察代码，以用户视角进行的测试</li>
<li>方法
<ol>
<li>基于图的测试</li>
<li>等价类划分</li>
<li>边值分析</li>
<li>比较测试</li>
</ol>
</li>
<li>优点
<ul>
<li>黑盒测试与软件具体实现无关，所以如果软件实现发生了变化，测试用例仍然可以使用；</li>
<li>设计黑盒测试用例可以和软件实现同时进行，因此可以压缩项目总的开发时间</li>
</ul>
</li>
</ul>
<h3 id="白盒测试">白盒测试</h3>
<ul>
<li>白盒测试用来分析程序的内部结构</li>
<li>基于代码，尽可能覆盖实现的行为</li>
<li>程序结构覆盖
<ol>
<li>语句覆盖：它要求被测程序的每一可执行语句在测试中尽可能都检验过,最弱</li>
<li>分支覆盖或判定覆盖：要求程序中所有判定的分支尽可能得到检验</li>
<li>条件覆盖：当判定式中含有多个条件时，要求每个条件的取值均得到检验</li>
<li>判定/条件覆盖：同时考虑条件的组合值及判定结果的检验</li>
<li>路径覆盖：只考虑对程序路径的全面检验</li>
<li>循环覆盖</li>
</ol>
</li>
</ul>
<hr>
<h2 id="第三章黑盒测试用例设计">第三章:黑盒测试用例设计</h2>
<h3 id="正面测试">正面测试</h3>
<ul>
<li>证明软件对于每条规格说明和期望都能通过</li>
<li>通过正面测试用例产生一组预期输出验证产品需求</li>
</ul>
<h3 id="负面测试">负面测试</h3>
<ul>
<li>产品没有设计、没有预想到的场景，尝试使系统垮掉</li>
<li>展示当输入非预期输入时,产品没有失败(fail)</li>
</ul>
<h3 id="等价类划分法">等价类划分法</h3>
<ul>
<li>等价类：测试相同目标或暴露相同软件缺陷的一组测试</li>
<li>有效等价类：完全满足产品规格说明的输入数据;每个有效等价类都要覆盖</li>
<li>无效等价类：不满足程序输入要求或者无效的输入数据构成的集合;每个无效等价类都要单独覆盖</li>
<li>等价类划分准则
<ol>
<li>输入条件代表一组列表形式的数据，则可以定义N个有效等价类和一个无效等价类</li>
<li>输入条件代表要求符合某几个规则，则可以定义多个有效等价类和若干个无效等价类；</li>
</ol>
</li>
</ul>
<h3 id="因果图判定表法">因果图(判定表)法</h3>
<ul>
<li>因果图的表示
<ul>
<li>Ci表示原因，Ei表示结果，原因和结果的4种关系：
<ol>
<li>恒等（—）</li>
<li>非（～）</li>
<li>或（∨）</li>
<li>与（∧）</li>
</ol>
</li>
<li>四种输入约束
<ol>
<li>互斥(E):多个原因不能同时成立，最多有一个能成立；即Ci不能同时为1</li>
<li>包含(I):多个原因中至少有一个必须成立；即Ci不能同时为0</li>
<li>唯一(O):多个原因中必须有一个且只有一个成立；即Ci只有一个为1</li>
<li>要求(R):当C1成立，C2也必须成立</li>
</ol>
</li>
<li>一种输出约束
<ol>
<li>屏蔽(M):当E1是1时，E2必须是0；当E1是0，E2的值不定；</li>
</ol>
</li>
</ul>
</li>
<li>过程
1. 生成因果图
2. 建立判定表
3. 生成测试用例</li>
</ul>
<h3 id="边界值分析法">边界值分析法</h3>
<ul>
<li>软件的两个主要缺陷源：1）条件；2）边界</li>
<li>边界值附近数据的确认方法
<ul>
<li>n: 存在边界值的参数个数</li>
<li>m: 边界值条件数</li>
<li>Paul Jorgensen公式
<ol>
<li>4n+1：基本边界测试:每个参数取min，min+1， max‐1，max各一次，同时其他参数取典型值nom。最后全部参数取典型值nom一次。</li>
<li>6n+1：健壮性边界测试: 每个参数取min‐1，min，min+1， max‐1，max，max+1各一次，同时其他参数取典型值nom。最后全部参数取典型值nom一次。</li>
<li>3m：条件边界测试:每个条件取‐1，自身，+1各一次。</li>
</ol>
<ul>
<li>每次只考虑一个参数的边界，固定其它参数</li>
<li>补充确定的关联边界值</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="第四章白盒测试用例设计">第四章：白盒测试用例设计</h2>
<h3 id="为什么需要白盒测试">为什么需要白盒测试</h3>
<ol>
<li>确保每段代码都被执行，避免相应的缺陷</li>
<li>是黑盒测试/功能测试的补充</li>
<li>能覆盖高层规范说明中的忽视的底层细节</li>
<li>更容易进行自动化测试。</li>
</ol>
<h3 id="静态白盒测试">静态白盒测试</h3>
<ul>
<li>技术评审technical review</li>
<li>代码/文档阅读code/document reading</li>
<li>走查/通查walk through</li>
<li>专项检查inspection</li>
<li>代码/数据/文档审计code/data/document audit</li>
</ul>
<h3 id="动态白盒测试">动态白盒测试</h3>
<ul>
<li>基于控制流测试方法
<ul>
<li>逻辑覆盖测试</li>
<li>基本路径测试</li>
<li>循环处理方法</li>
</ul>
</li>
<li>基于数据流测试方法</li>
</ul>
<h3 id="测试覆盖准则">测试覆盖准则</h3>
<ul>
<li>对“测试执行到何时才是充分的？”的定量回答</li>
<li>测试软件的一种度量标准，描述程序源代码被测试的程度。</li>
</ul>
<h3 id="逻辑覆盖测试">逻辑覆盖测试</h3>
<ol>
<li>语句覆盖: 保证程序中的<strong>每条语句</strong>都执行一遍</li>
<li>判定覆盖: 保证<strong>每个判定</strong>取真取假至少一次</li>
<li>条件覆盖: 保证<strong>每个判定中的每个条件</strong>的所有可能结果都至少出现一次(取真取假至少一次)
<ul>
<li>条件覆盖不能保证程序所有分支都被执行</li>
</ul>
</li>
<li>判定条件覆盖: 保证<strong>每个判定和每个判定中的每个条件</strong>的取值至少满足一次(取真取假至少一次)</li>
<li>条件组合覆盖: 保证<strong>每个判定中条件的各种可能组合</strong>都至少出现一次
<ul>
<li>2^n组合数目,n为原子条件数</li>
</ul>
</li>
<li>路径覆盖: 保证<strong>每条可能执行到的路径</strong>都至少经过一次(如果程序中包含环路，则要求每条环路至少经过一次)
<ul>
<li>相对彻底,但<strong>不能</strong>替代条件覆盖和条件组合覆盖标准</li>
<li>路径条数可能以分支的指数级增加</li>
</ul>
</li>
</ol>
<h3 id="基本路径测试">基本路径测试</h3>
<ul>
<li>基本路径
<ul>
<li>指任何一条贯穿程序的路径，该路径至少包含一条不同于其他路径的边。</li>
<li>基本路径集合中路径条数唯一，基本路径可以不一样</li>
<li>其他路径可以通过基本路径运算得到</li>
</ul>
</li>
<li>圈复杂度
<ul>
<li>度量基本路径数</li>
<li>是所有语句被执行一次所需测试用例数的上限</li>
<li>具有最高圈复杂度的模块蕴含错误的可能性最大，是测试中关注的焦点</li>
<li>计算：
<ul>
<li>等于域的数量</li>
<li>V(G)=E-N+2, E为边，N为结点</li>
<li>V(G)=P+1，P为判定结点数</li>
</ul>
</li>
</ul>
</li>
<li>基本路径集寻找算法
<ol>
<li>确认从入口到出口的最短路径</li>
<li>从入口到第1个未被先后评估为真和假两种结果的条件语句</li>
<li>改变该条件语句的判断值</li>
<li>按最短路径从这个条件语句到出口</li>
<li>重复步骤2-5,直到所有基本路径都被找到</li>
</ol>
</li>
</ul>
<h3 id="循环处理方法">循环处理方法</h3>
<ul>
<li>循环
<ul>
<li>简单循环</li>
<li>嵌套循环</li>
<li>串接循环</li>
<li>非结构循环</li>
</ul>
</li>
<li>简单循环
<ol>
<li>跳过整个循环</li>
<li>只执行一次循环</li>
<li>执行两次循环</li>
<li>执行m(m &lt; n)次循环</li>
<li>执行n-1,n,n+1次循环</li>
</ol>
</li>
<li>嵌套循环
<ol>
<li>先测试最内层循环
<ul>
<li>所有外层的循环变量置为最小值</li>
<li>最内层按简单循环测试；</li>
</ul>
</li>
<li>由里向外，测试上层循环：
<ul>
<li>此层以外的所有外层循环的循环变量取最小值</li>
<li>此层以内的所有嵌套内层循环的循环变量取“典型值”</li>
<li>该层按简单循环测试；</li>
</ul>
</li>
<li>重复上一条规则，直到所有各层循环测试完毕</li>
<li>对全部各层循环同时取最小循环次数，或者同时取最大循环次数</li>
</ol>
</li>
<li>串接循环
<ol>
<li>若串接的各个循环互相独立:分别用简单循环的方法进行测试；</li>
<li>若两个循环不独立（第一个循环的循环变量与第二个循环控制相关），把第一个循环看作外循环，第二个循环看作内循环，然后用测试嵌套循环的办法来处理</li>
</ol>
</li>
</ul>
<h3 id="基于数据流的测试">基于数据流的测试</h3>
<ul>
<li>数据流是变量的定义或使用顺序和变量的可能状态的一种抽象表示。</li>
<li>数据流测试是一种面向变量定义位置-使用位置覆盖的基于程序结构的测试方法。</li>
<li>数据流测试的作用是用来测试变量定义位置和使用位置之间的路径。这些路径也 称为“定义-使用对”。</li>
<li>数据流覆盖测试步骤
<ol>
<li>对于给定的程序，构造相应的程序数据流图</li>
<li>找出所有变量的定义-使用路径</li>
<li>考察测试用例对这些路径的覆盖程度，即可作为衡量测试效果的度量值</li>
</ol>
</li>
<li>定义
<ul>
<li>谓词使用P-use——USE(v,n)位于一个谓词中，即条件判断语句中</li>
<li>计算使用C-use——USE(v,n)位于一个计算中，即计算表达式中</li>
<li>du-path</li>
<li>定义-清洁路径(define-clear-path/dc-path)：如果变量v的某个定义-使用路径，除起始节点外没有其它定义节点，则该路径是变量v的定义-清洁路径</li>
</ul>
</li>
<li>Rapps和Weyuker标准
<ol>
<li>All-Nodes：等价于语句覆盖</li>
<li>All-Edges：等价于分支覆盖</li>
<li>All-P-Uses：选择的路径中每个变量的每个定义节点都有一条dc-path到达该定义的每个P-use节点</li>
<li>All-Defs：选择的路径中每个变量的每个定义节点都有一条dc-path到达该定义的某个使用节点</li>
<li>All-P-Uses/Some C-Uses： 选择的路径中的每个变量的每个定义节点都有一条dc-path到达该定义的每个P-use节点;但如果没有可达P-use节点，dc-path应到达至少一个C-use节点</li>
<li>All-C-Uses/Some P-Uses：选择的路径中的每个变量的每个定义节点都有一条dc-path到达该定义的每个C-use节点;但如果没有可达C-use节点，dc-path应到达至少一个P-use节点</li>
<li>All-Uses：选择的路径中的每个变量的每个定义节点都有一条dc-path到达该变量的每个使用节点,若存在定义节点和使用节点间存在多条dc-path,仅选取其中一条。</li>
<li>All-DU-Paths：所有的DU-Path集合。路径中的每个变量的每个定义节点到达该变量的每个使用节点的所有dc-path。若存在循环，仅取一个简单循环或者无循环。</li>
<li>All-Paths：等价于路径覆盖</li>
</ol>
</li>
<li>数据流异常
<ul>
<li>未初始化就读取了变量的值</li>
<li>根本没有使用变量的值</li>
</ul>
</li>
<li>优点
<ul>
<li>揭示隐藏在代码变量定义和使用中的各种错误</li>
<li>可以覆盖所有语句、所有分支、所有路径</li>
<li>对代码的测试比较彻底</li>
</ul>
</li>
<li>缺点
<ul>
<li>无法检测代码中不可达路径</li>
<li>不验证需求规格</li>
</ul>
</li>
</ul>
<hr>
<h2 id="第五章回归测试">第五章：回归测试</h2>
<ul>
<li>目的：为了保证在软件演化和维护时，那些未变更的代码的功能不会受影响</li>
<li>回归测试与一般测试比较，有六个方面不同：
<ul>
<li>测试计划</li>
<li>测试范围</li>
<li>资源分配</li>
<li>开发信息</li>
<li>完成时间</li>
<li>执行频率</li>
</ul>
</li>
<li>过程
<ol>
<li>提出修改需求</li>
<li>修改软件工件（即软件制品artifact，文档、代码、模型等）</li>
<li>选择和生成测试用例(T1+T2)</li>
<li>执行测试</li>
<li>识别失败结果</li>
<li>确认错误</li>
<li>排除错误</li>
</ol>
</li>
<li>策略
<ul>
<li>全部重新测试方法</li>
<li>有选择的重新测试方法
<ul>
<li>最常用：选择与某个特定模块相关的所有测试用例，及所有集成测试用例</li>
</ul>
</li>
</ul>
</li>
<li>波及效应分析的2种方法
<ul>
<li>字符串匹配</li>
<li>程序切片</li>
</ul>
</li>
</ul>
<hr>
<h2 id="第六章">第六章</h2>
<h3 id="面向对象软件开发方法的本质">面向对象软件开发方法的本质</h3>
<ul>
<li>一切都是对象</li>
<li>任务(/职责/功能)的完成是通过对象之间的协作达到的</li>
</ul>
<h3 id="面向对象测试">面向对象测试</h3>
<ul>
<li>单元测试
<ul>
<li>两个常用的基本元素
<ol>
<li>method</li>
<li>class</li>
</ol>
</li>
<li>测试方法与传统软件测试既类似又不同</li>
</ul>
</li>
<li>集成测试
<ul>
<li>主要对系统内部的对象之间的协作进行测试，如成员函数间的相互作用，类间的消息传递等</li>
<li>因为面向对象程序具有动态绑定(dynamicbinding)特性，程序的控制流无法确定，只能对编译完成的程序做基于黑盒的集成测试</li>
<li>主程序最小化</li>
<li>基于合成/组合（composition）</li>
<li>使用类簇（class cluster），含继承</li>
<li>使用对象关系图(ORD: object relation diagram) – 类间依赖和方法依赖关系的有向图</li>
</ul>
</li>
<li>面向对象技术的影响
<ol>
<li>类</li>
</ol>
<ul>
<li>基本可测单元</li>
<li>由模块集成变成类的集成</li>
</ul>
<ol start="2">
<li>封装</li>
</ol>
<ul>
<li>修改封装会导致大量的回归测试</li>
<li>信息隐藏使对象的部分不可访问，减少了波动影响</li>
<li>测试顺序相当重要（可以减少工作量）：集成测试序</li>
</ul>
<ol start="3">
<li>继承</li>
</ol>
<ul>
<li>要确定衍类中从基类继承的已测试的功能是否需要再测试</li>
</ul>
<ol start="4">
<li>多态</li>
</ol>
<ul>
<li>引入了不可判定性问题</li>
<li>一个多态组件的每一个可能的绑定都需要一个独立的测试,使得集成计划复杂化</li>
</ul>
<ol start="5">
<li>抽象</li>
</ol>
<ul>
<li>抽象使测试变得困难，特别是要执行内部的结构测试时，降低了软件的可测试性。</li>
</ul>
</li>
<li>面向对象的开发模型
<ul>
<li>迭代式增量开发过程模型</li>
<li>面向对象分析</li>
<li>面向对象设计</li>
<li>面向对象编程</li>
<li>在整个软件开发生命周期全过程中不断测试,分析一点、测试一点，设计一点、测试一点，编码一点、测试一点</li>
</ul>
</li>
<li>OSD(object state diagram)模型
<ul>
<li>基于状态测试使测试变得复杂，因此使用OSD</li>
<li>步骤
<ol>
<li>扫描源程序得出带执行条件的执行分析表</li>
<li>确定对象状态</li>
<li>构造转移</li>
<li>构造测试消息序列</li>
<li>根据每条测试消息序列，选择相应的数据进行测试</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="第七章软件性能测试">第七章:软件性能测试</h2>
<h3 id="软件性能定义">软件性能定义</h3>
<ul>
<li>软件的一种非功能特性，</li>
<li>软件在运行的过程中表现出来的时间和空间效率与用户的需求之间的吻合程度</li>
</ul>
<h3 id="软件性能具体指">软件性能具体指</h3>
<ul>
<li>响应时间</li>
<li>系统响应时间：计算机对用户的输入或请求作出反应的时间</li>
<li>应用延迟时间（latency）：是指应用接到指令后的处理时间。</li>
<li>吞吐量：是指系统在单位时间内处理请求的数量</li>
<li>并发用户数：是指系统可以同时承载的正常使用系统功能的用户的数量</li>
<li>资源利用率：反映的是在一段时间内资源平均被占用的情况</li>
</ul>
<h3 id="性能测试的方法">性能测试的方法</h3>
<ul>
<li>基准测试</li>
<li>负载测试（load testing）是检测在各种工作负载下系统的性能，也就是测试当负载逐渐增加时，系统各项性能指标的变化情况</li>
<li>压力测试（stress testing）是检测一个系统的瓶颈或者不能接受的性能点</li>
<li>容量测试（volume testing）是检测系统在给定时间内能够持续处理的最大负载或工作量</li>
<li>配置测试: 通过被测系统软/硬件环境的调整，了解各种不同环境对系统性能影响的程度，从而找到各项资源的最优分配原则。</li>
<li>可靠性测试</li>
<li>失效恢复测试</li>
</ul>
<h3 id="性能测试的步骤">性能测试的步骤</h3>
<ol>
<li>熟悉应用</li>
<li>测试需求</li>
<li>测试准备</li>
<li>测试执行</li>
<li>测试结果分析</li>
</ol>
<hr>
<h2 id="第八章">第八章</h2>
<h3 id="软件安全">软件安全</h3>
<ul>
<li>安全可靠（safety）：软件在运行过程中到达某个不安全的状态（例如触发了某个缺陷）导致了安全事故
<ul>
<li>正确性</li>
<li>稳定性</li>
<li>可靠性</li>
</ul>
</li>
<li>安全保密（security）：软件由于本身存在漏洞，被黑客利用发起攻击导致的安全事故
<ul>
<li>完整性：保护数据不被更改或破坏</li>
<li>机密性</li>
<li>可用性：确保资源被授权的用户使用</li>
</ul>
</li>
</ul>
<h3 id="软件安全保障方法">软件安全保障方法</h3>
<ul>
<li>先验方法
<ul>
<li>安全设计(原则)</li>
<li>安全风险预防、转移和回避策略</li>
<li>安全编程</li>
<li>威胁建模</li>
</ul>
</li>
<li>后验方法
<ul>
<li>安全测试</li>
<li>安全分析</li>
<li>安全验证</li>
</ul>
</li>
</ul>
<hr>
<h2 id="第九章">第九章</h2>
<h3 id="iso9126质量度量模型">ISO9126质量度量模型</h3>
<ol>
<li>功能性</li>
<li>可靠性</li>
<li>易使用性</li>
<li>效率</li>
<li>可维护性</li>
<li>可移植性</li>
</ol>
<h3 id="iso-25010">ISO 25010</h3>
<p>新增</p>
<ul>
<li>信息安全性
<ul>
<li>保密性</li>
<li>完整性</li>
<li>真实性</li>
<li>抗依赖性</li>
<li>可核查性</li>
</ul>
</li>
<li>互用性
<ul>
<li>软件兼容性</li>
<li>数据兼容性</li>
</ul>
</li>
</ul>
<h3 id="furps模型">FURPS+模型</h3>
<ul>
<li>功能(function)</li>
<li>易用(usablity)</li>
<li>可靠度(reliablity)</li>
<li>性能(performance)</li>
<li>可支持性(supportablity)</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>浅谈《维多利亚三》</title>
      <link>https://ds63.eu.org/2024/victoria-3/</link>
      <pubDate>Thu, 06 Jun 2024 22:53:45 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/victoria-3/</guid>
      <description>我玩你别劝，我劝你别玩</description>
      <content:encoded><![CDATA[<h2 id="游戏性">游戏性</h2>
<p>刚买这游戏的第一周我玩了快五十个小时。</p>
<p>还跟人自嘲,真想不到自己会盯着世界地图看了一周。</p>
<p>也有人说这是款填色游戏加和面游戏,说得没错,它确实是。</p>
<p>那这游戏是什么吸引我呢？</p>
<ol>
<li>通过读档，优化决策，我能成功逆天改命，很有成就感。。</li>
<li>事件不算乏味。</li>
</ol>
<p>举个例子：</p>
<p>我第一个玩得比较久的国家是美国。</p>
<p>一开始，我直接废奴，但美国内战因此爆发。通过发展工业，提前削弱南方种植园主的势力，在避免内战爆发的情况下成功废奴。</p>
<p>有趣的是，没能打内战的林肯就开始作妖了。他先后两次被爆出丑闻，我给压下了。然后却得寸进尺，最后甚至还要复辟君主。</p>
<p>不过这个时间线的林肯也没能寿终正寝，在一次选举活动中意外身亡，也算是符合历史了。</p>
<p>ps: 后来看人说内战很有必要打，因为可以加个非洲文化，方便殖民。</p>
<p>这个档还出现了一位人气憎恨的九十四岁老将,活到20世纪的南方种植园主、蓄奴主义者。我很烦他这个词条，因为会减我改法律的成功率。但流放cd又还没到，想等他自己死。但他超能活,也是厉害。</p>
<h2 id="两位up主">两位up主</h2>
<p>B站有两位up做的维多利亚3相关的视频我经常看。</p>
<p>一位是<a href="https://space.bilibili.com/3928998"  target="_blank" rel="noopener" >苍尼玛的个人空间-苍尼玛个人主页-哔哩哔哩视频</a></p>
<p>以下是我3月2号的日记节选</p>
<blockquote>
<p><a href="https://www.bilibili.com/video/BV1Dr421s7Hc/"  target="_blank" rel="noopener" >最逆天大清 禁止工业！降服带英！地主老爷反推工业化发源地，这就是禁止工业带给我的自信！</a>，up对游戏理解很透彻，哪怕我没玩过维多利亚，但还是很过瘾地看了四集，大约八十分钟。
所谓的游戏机制，其实就是游戏代码。这就让我想到周二的软件质量保障学到的，程序由命令和数据组成，命令控制数据的变化。哈哈，</p>
</blockquote>
<p>这也成了我入坑维多利亚的契机。</p>
<p>另一位是<a href="https://space.bilibili.com/93148"  target="_blank" rel="noopener" >苟学家七五的个人空间-苟学家七五个人主页-哔哩哔哩视频</a></p>
<p>虽然他做视频用的槽点太重复了，但还算有趣。</p>
<h2 id="套路">套路</h2>
<p>维多利亚三的时间跨度相比其他p社游戏并不算长。只有1836年到1936年一百年时间。</p>
<p>多开几把游戏后，会发现套路都差不多。进行工业化,发展经济，慢慢削弱国内的反动势力，然后进一步改革法律。</p>
<p>这其实有点太理想化了，现实远比此复杂。</p>
<p>我期待有更真实，更有趣的游戏出现。</p>
<h2 id="mod">mod</h2>
<p>让p社游戏富有生命力的一大要素是开发者对模组的支持，以及活跃的玩家社群。</p>
<p>就如他们在<a href="https://store.steampowered.com/news/app/529340/view/4194619900924865388?l=schinese"  target="_blank" rel="noopener" >Victoria 3 - 开发日志#120－1.7版本的模组制作 - Steam 新闻</a>里所说</p>
<blockquote>
<p>我们的脚本语言是所有游戏内内容的基础，而每一个开发组内容制作者使用的脚本功能都可以被模组制作者使用。</p>
</blockquote>
<p>我还注意到游戏将大部分数据都是以txt格式存储的。这进一步方便模组的开发。</p>
<p>但这并不意味着模组特别好用了。在我有限的维多利亚三游玩时间中，我至少花了两个晚上的时间，用来调试到底我装的哪个mod出了问题。</p>
<p>后来我发现出问题的基本上都是那些最后更新时间在22年的。这也很能理解，模组开发者毕竟只是为爱发电，但游戏开发者无法保证每个版本都能向上兼容。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>实用数据库实践笔记</title>
      <link>https://ds63.eu.org/2024/dive-into-oracle/</link>
      <pubDate>Tue, 04 Jun 2024 08:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/dive-into-oracle/</guid>
      <description>oracle 使用</description>
      <content:encoded><![CDATA[<h2 id="版本说明">版本说明</h2>
<ol>
<li>Oracle Database: 19c Enterprise Edition Release 19.0.0.0.0 - Production</li>
<li>mysql: 5.7.30-linux-glibc2.12-x86_64</li>
<li>rlwrap: 0.36</li>
<li>sqldeveloper: 19.2.1.247.2212</li>
<li>linux: OracleLinux-R7-U4-Server-x86_64</li>
</ol>
<h2 id="oracle数据库操作笔记">Oracle数据库操作笔记</h2>
<h3 id="登录">登录</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sqlplus / as sysdba
</span></span><span class="line"><span class="cl">SQL&gt; conn / as sysdba
</span></span><span class="line"><span class="cl"><span class="c1"># 如显示Connected to an idle instance. 需先启动</span>
</span></span><span class="line"><span class="cl"><span class="c1"># SQL&gt; STARTUP;</span>
</span></span></code></pre></div><h3 id="显示">显示</h3>
<ol>
<li>
<p>查看</p>
<ul>
<li><code>show pagesize</code></li>
<li><code>show linesize</code></li>
</ul>
</li>
<li>
<p>设置</p>
<ul>
<li><code>set pagesize 25</code></li>
<li><code>set linesize 120</code></li>
<li><code>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';</code></li>
</ul>
</li>
<li>
<p>修改默认设置</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim <span class="nv">$ORACLE_HOME</span>/sqlplus/admin/glogin.sql
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> linesize <span class="m">120</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> pagesize <span class="m">25</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> sqlprompt _user<span class="s2">&#34;@&#34;</span>_connect_identifier&gt;
</span></span><span class="line"><span class="cl">define <span class="nv">_EDITOR</span><span class="o">=</span><span class="s2">&#34;vim&#34;</span>
</span></span></code></pre></div><h3 id="sql">SQL</h3>
<ol>
<li>QL(select)</li>
<li>DML(insert,update,deIete,merge)</li>
<li>DDL(create,alter,drop,rename,truncate,comment)</li>
<li>DCL(grant,revoke)
<ul>
<li><code>grant select on emp to hr</code></li>
<li><code>revoke select on emp from hr</code></li>
</ul>
</li>
<li>TCL(commit,rollback,savepoint)</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">create database wyd
</span></span><span class="line"><span class="cl">datafile <span class="s1">&#39;/u01/app/eu/oradata/wyd/system01.dbf&#39;</span> size 400m
</span></span><span class="line"><span class="cl">sysaux datafile <span class="s1">&#39;/u01/app/eu/oradata/wyd/sysaux01.dbf&#39;</span> size 400m
</span></span><span class="line"><span class="cl">default tablespace users datafile <span class="s1">&#39;/u01/app/eu/oradata/wyd/users01.dbf&#39;</span> size 100m
</span></span><span class="line"><span class="cl">default temporary tablespace temp tempfile <span class="s1">&#39;/u01/app/eu/oradata/wyd/temp01.dbf&#39;</span> size 20m
</span></span><span class="line"><span class="cl">undo tablespace undotbs1 datafile <span class="s1">&#39;/u01/app/eu/oradata/wyd/undotbs01.dbf&#39;</span> size 50m
</span></span><span class="line"><span class="cl">logfile
</span></span><span class="line"><span class="cl">group <span class="m">1</span> <span class="s1">&#39;/u01/app/eu/oradata/wyd/redo01.log&#39;</span> size 10m,
</span></span><span class="line"><span class="cl">group <span class="m">2</span> <span class="s1">&#39;/u01/app/eu/oradata/wyd/redo02.log&#39;</span> size 10m,
</span></span><span class="line"><span class="cl">group <span class="m">3</span> <span class="s1">&#39;/u01/app/eu/oradata/wyd/redo03.log&#39;</span> size 10m<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Database created
</span></span></code></pre></div><h2 id="目录">目录</h2>
<ul>
<li>创建 <code>create directory expdp_dest as '/u01/exp';</code></li>
<li>赋权：<code>grant read, write on directory expdp_dest to scott;</code></li>
<li>查找：<code>select DIRECTORY_NAME,DIRECTORY_PATH from dba_directories;</code></li>
</ul>
<h2 id="导出">导出</h2>
<ul>
<li><code>exp scott/tiger query=\'where sal\&gt;2500\' tables=emp file=emp2500.dmp</code></li>
<li><code>expdp scott/tiger directory=expdp_dest file=empdp1.dmp tables=emp</code></li>
<li>参考<a href="https://www.thegeekstuff.com/2016/02/oracle-exp-examples/"  target="_blank" rel="noopener" >15 Oracle Exp Command Examples to Export Database Objects</a></li>
</ul>
<h2 id="表空间">表空间</h2>
<ul>
<li>查看
<ul>
<li><code>select tablespace_name,status from dba_tablespaces;</code></li>
<li><code>select name from v$tablespace;</code></li>
</ul>
</li>
<li>创建表空间<code>create tablespace eu datafile '/u01/app/oracle/oradata/DB19C/eu.dbf' size 10m;</code></li>
<li>创建一张表到特定的表空间：<code>create table scott.tts(a varchar (30)) tablespace eu;</code></li>
<li>修改为只读<code>alter tablespace test read only;</code></li>
<li>从源数据库输出元数据：<code>exp \'sys\/admin1#3 as sysdba\' FILE=tts.dmp TRANSPORT_TABLESPACE=Y TABLESPACES=eu</code></li>
<li>查找表所对应的文件：<code>select file_name from dba_data_files where tablespace_name=(select tablespace_name from dba_tables where table_name='COLD');</code></li>
</ul>
<h2 id="数据文件">数据文件</h2>
<ul>
<li>查看<code>select name from v$datafile;</code></li>
<li>把元数据输入到目标数据库：<code>imp \'sys\/admin1#3 as sysdba\' FILE=tts.dmp TRANSPORT_TABLESPACE=Y DATAFILES=/u01/app/eu/oradata/eu01.dbf</code></li>
</ul>
<h2 id="字符集">字符集</h2>
<ul>
<li>参考：<a href="https://zeven0707.github.io/2019/01/09/oracle%20%E4%BF%AE%E6%94%B9%E5%AD%97%E7%AC%A6%E9%9B%86/"  target="_blank" rel="noopener" >[Oracle] oracle修改字符集 | zeven&rsquo;s blog</a></li>
<li>查看使用的字符集：<code>select value$ FROM sys.props$ WHERE name='NLS_CHARACTERSET';</code></li>
<li>修改：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">alter system <span class="nb">enable</span> restricted session<span class="p">;</span>
</span></span><span class="line"><span class="cl">alter database character <span class="nb">set</span> internal_use AL32UTF8<span class="p">;</span> <span class="c1">#US7ASCII</span>
</span></span><span class="line"><span class="cl">alter system disable restricted session<span class="p">;</span>
</span></span></code></pre></div><h2 id="外部表">外部表</h2>
<ul>
<li>创建外部表</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl">create table scott.ex1<span class="o">(</span>empno int,deptno int,ename varchar<span class="o">(</span>20<span class="o">))</span>
</span></span><span class="line"><span class="cl">ORGANIZATION EXTERNAL
</span></span><span class="line"><span class="cl"><span class="o">(</span><span class="nb">type</span> oracle_loader default directory expdp_dest
</span></span><span class="line"><span class="cl">access parameters
</span></span><span class="line"><span class="cl"><span class="o">(</span>records delimited by newline
</span></span><span class="line"><span class="cl">fields terminated by <span class="s1">&#39;,&#39;</span>
</span></span><span class="line"><span class="cl">missing field values are null
</span></span><span class="line"><span class="cl"><span class="o">(</span>empno,deptno,ename<span class="o">))</span>
</span></span><span class="line"><span class="cl">location<span class="o">(</span><span class="s1">&#39;employees.dat&#39;</span><span class="o">))</span><span class="p">;</span>
</span></span></code></pre></div><ul>
<li>卸载数据</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">create table scott.ex2<span class="o">(</span>empno,ename,sal<span class="o">)</span>
</span></span><span class="line"><span class="cl">ORGANIZATION EXTERNAL
</span></span><span class="line"><span class="cl"><span class="o">(</span><span class="nb">type</span> oracle_datapump default directory expdp_dest
</span></span><span class="line"><span class="cl">location<span class="o">(</span><span class="s1">&#39;empl .dat&#39;</span><span class="o">))</span>
</span></span><span class="line"><span class="cl">as <span class="k">select</span> empno,ename,sal from scott.emp<span class="p">;</span>
</span></span></code></pre></div><ul>
<li>加载数据</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">create table scott.ex<span class="o">(</span>empno int,ename varchar<span class="o">(</span>20<span class="o">)</span>,sal number<span class="o">(</span>7,2<span class="o">))</span>
</span></span><span class="line"><span class="cl">ORGANIZATION EXTERNAL
</span></span><span class="line"><span class="cl"><span class="o">(</span><span class="nb">type</span> oracle_datapump default directory expdp_dest
</span></span><span class="line"><span class="cl">location<span class="o">(</span><span class="s1">&#39;empl .dat&#39;</span><span class="o">))</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="logmnr">logmnr</h2>
<ul>
<li><code>archive log list;</code></li>
<li><code>select SUPPLEMENTAL_LOG_DATA_MIN from v$database;</code></li>
<li>启用数据库补充日志：<code>alter database add SUPPLEMENTAL LOG DATA;</code></li>
<li>产生数据字典文件</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /u01/demo/dict
</span></span><span class="line"><span class="cl">create directory DICT as <span class="s1">&#39;/u01/demo/dict&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">EXECUTE dbms_logmnr_d.build<span class="o">(</span><span class="s1">&#39;v816dict.ora&#39;</span>,<span class="s1">&#39;DICT&#39;</span><span class="o">)</span><span class="p">;</span>
</span></span></code></pre></div><ul>
<li>找到需要分析的日志文件</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">select</span> GROUP#,STATUS from  v<span class="nv">$log</span><span class="p">;</span> <span class="c1">#看哪个是current</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> member from v<span class="nv">$logfile</span> where GROUP#<span class="o">=</span>3<span class="p">;</span>
</span></span></code></pre></div><ul>
<li>添加需要分析的日志文件
<code>EXECUTE dbms_logmnr.add_logfile(logfilename=&gt;'/u01/app/eu/oradata/DB19C/redo03.log',Options=&gt;dbms_logmnr.new);</code></li>
<li>启动分析
<code>EXECUTE dbms_logmnr.start_logmnr(DictFilename=&gt;'/u01/demo/dict/v816dict.ora');</code></li>
<li>查询
<code>desc v$logmnr_contents;</code></li>
<li>闪回: <code>flashback table emp to timestamp to timestamp('2024-05-21 10:02:23'),'yyyy-mm-dd hh24:mi:ss'</code></li>
<li>行移动：
<ul>
<li><code>select table_name,row_movement from user_tables;</code></li>
<li><code>alter table emp enable row movement;</code></li>
</ul>
</li>
</ul>
<h2 id="归档模式">归档模式</h2>
<ul>
<li>查看:<code>archive log list;</code></li>
<li>要将Oracle数据库设置为归档模式，需要执行以下步骤：</li>
</ul>
<ol>
<li>关闭数据库：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">shutdown</span><span class="w"> </span><span class="k">immediate</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><ol start="2">
<li>以挂载状态启动数据库：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">startup</span><span class="w"> </span><span class="n">mount</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><ol start="3">
<li>将数据库更改为归档模式：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">alter</span><span class="w"> </span><span class="k">database</span><span class="w"> </span><span class="n">archivelog</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><ol start="4">
<li>打开数据库：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">alter</span><span class="w"> </span><span class="k">database</span><span class="w"> </span><span class="k">open</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="备份和恢复">备份和恢复</h2>
<ul>
<li><code>recover database;</code></li>
<li><code>alter database open;</code></li>
</ul>
<h3 id="rman">rman</h3>
<ul>
<li>基础使用</li>
</ul>
<pre tabindex="0"><code>rman
connect target /
backup tablespace users;
restore tablespace users;
</code></pre><ul>
<li>
<p>advice</p>
</li>
<li>
<p>repair</p>
</li>
<li>
<p>全盘备份和恢复</p>
<ul>
<li><code>configure channel device type disk format '/u01/eubak/%d_%u_%T';</code></li>
<li><code>CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/u01/eubak/auto/%F';</code></li>
<li><code>backup database plus archivelog;</code></li>
<li><code>vim /etc/oratab</code></li>
<li><code>restore spfile from ''</code>;</li>
<li><code>restore controlfile from '';</code></li>
<li><code>alter database mount;</code></li>
<li><code>restore database;</code></li>
</ul>
</li>
</ul>
<h2 id="在原有数据库的基础上创建数据库">在原有数据库的基础上创建数据库</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">SYS&gt; create pfile from spfile<span class="p">;</span>
</span></span><span class="line"><span class="cl">&gt;cd <span class="nv">$ORACLE_HOME</span>/dbs
</span></span><span class="line"><span class="cl">&gt;cp initwyd.ora initoradup.ora
</span></span><span class="line"><span class="cl">&gt; orapwd <span class="nv">file</span><span class="o">=</span>orapworadup <span class="nv">password</span><span class="o">=</span>admin1#3 <span class="c1">#创建口令文件</span>
</span></span><span class="line"><span class="cl">SYS&gt;select name from v<span class="nv">$datafile</span><span class="p">;</span> <span class="c1">#查找数据文件</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/system01.dbf</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/sysaux01.dbf</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/undotbs01.dbf</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/users01.dbf</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/wyd01.dbf</span>
</span></span><span class="line"><span class="cl">SYS&gt;select member from v<span class="nv">$logfile</span><span class="p">;</span> <span class="c1">#查找日志文件</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/redo01.log</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/redo02.log</span>
</span></span><span class="line"><span class="cl"><span class="c1">#/u01/app/eu/oradata/wyd/redo03.log</span>
</span></span><span class="line"><span class="cl">&gt;vim initoradup.ora
</span></span><span class="line"><span class="cl">: 1,$ s/wyd/oradup/g
</span></span><span class="line"><span class="cl"><span class="c1"># 根据刚才查找到的文件位置进行补充</span>
</span></span><span class="line"><span class="cl">*.DB_FILE_NAME_CONVERT<span class="o">=(</span><span class="s1">&#39;/u01/app/eu/oradata/wyd/&#39;</span>,<span class="s1">&#39;/u01/app/eu/oradata/oradup/&#39;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">*.LOG_FILE_NAME_CONVERT<span class="o">=(</span><span class="s1">&#39;/u01/app/eu/oradata/wyd/&#39;</span>,<span class="s1">&#39;/u01/app/eu/oradata/oradup/&#39;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">*.log_archive_dest_1<span class="o">=</span><span class="s1">&#39;location=/u01/arch/oradup&#39;</span>
</span></span><span class="line"><span class="cl">&gt; netmgr <span class="c1">#监听,需配置</span>
</span></span><span class="line"><span class="cl">&gt;lsnrctl stop
</span></span><span class="line"><span class="cl">&gt;lsnrctl start <span class="c1"># 重启</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 讲oradup启动到nomount状态</span>
</span></span><span class="line"><span class="cl">&gt;export <span class="nv">ORACLE_SID</span><span class="o">=</span>oradup 
</span></span><span class="line"><span class="cl">&gt;sqlplus / as sysdba
</span></span><span class="line"><span class="cl">SYS&gt; startup nomount
</span></span><span class="line"><span class="cl"><span class="c1"># 启动rman，同时连接原库和新库</span>
</span></span><span class="line"><span class="cl">&gt;rman target sys/admin1#3@wyd auxiliary sys/admin1#3@oradup
</span></span><span class="line"><span class="cl"><span class="c1"># 执行duplicate</span>
</span></span><span class="line"><span class="cl">rman&gt; duplicate target database to oradup from active database<span class="p">;</span>
</span></span></code></pre></div><h2 id="恢复">恢复</h2>
<h3 id="数据库基于时间点的恢复">数据库基于时间点的恢复</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#克隆数据库作为辅助数据库，然后推到特定时间</span>
</span></span><span class="line"><span class="cl"><span class="c1">#基于时间点的恢复</span>
</span></span><span class="line"><span class="cl"><span class="c1">#1. 创建测试表</span>
</span></span><span class="line"><span class="cl">create table scott.suibian<span class="o">(</span>id int<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">insert into scott.suibian values<span class="o">(</span>100<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">commit<span class="p">;</span>
</span></span><span class="line"><span class="cl">alter system archive log current<span class="p">;</span> <span class="c1">#归档模式</span>
</span></span><span class="line"><span class="cl"><span class="c1">#整库备份</span>
</span></span><span class="line"><span class="cl">在RMAN中backup databse<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 再插入一条记录</span>
</span></span><span class="line"><span class="cl">insert into scott.suibian values<span class="o">(</span>200<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">commit<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#查看时间</span>
</span></span><span class="line"><span class="cl">!date
</span></span><span class="line"><span class="cl"><span class="c1">#删除表</span>
</span></span><span class="line"><span class="cl">drop table scott.suibian purge<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#创建表</span>
</span></span><span class="line"><span class="cl">create table scott.suibian2 as <span class="k">select</span> * from scott.emp<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#启动数据库到mount阶段</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#设置环境变量</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">NLS_DATE_FORMAT</span> <span class="o">=</span> <span class="s2">&#34;yyyy-mm-dd hh24:mi:ss&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#还原数据库</span>
</span></span><span class="line"><span class="cl">RMAN下 restore database<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#恢复数据库到指定时间点</span>
</span></span><span class="line"><span class="cl">RMAN下 RECOVER DATABASE UNTIL TIME <span class="s2">&#34;TO_DATE(&#39;2024-06-04 10:26:40&#39;, &#39;YYYY-MM-DD HH24:MI:SS&#39;)&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#打开数据库</span>
</span></span><span class="line"><span class="cl">alter database open resetlogs<span class="p">;</span>
</span></span></code></pre></div><h3 id="tspitr------表空间基于时间点的恢复">TSPITR   &mdash;表空间基于时间点的恢复</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#1. 创建测试表空间</span>
</span></span><span class="line"><span class="cl">create tablespace tbs1 datafile <span class="s1">&#39;/u01/app/oracle/oradata/sales/tbs101.dbf&#39;</span> size 10m<span class="p">;</span>
</span></span><span class="line"><span class="cl">create tablespace tbs2 datafile <span class="s1">&#39;/u01/app/oracle/oradata/sales/tbs201.dbf&#39;</span> size 10m<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#2. 创建测试表</span>
</span></span><span class="line"><span class="cl">create table scott.t1 tablespace tbs1 as <span class="k">select</span> * from scott.emp<span class="p">;</span>
</span></span><span class="line"><span class="cl">create index scott.idx_ename on scott.t1<span class="o">(</span>ename<span class="o">)</span> tablespace tbs2<span class="p">;</span>
</span></span><span class="line"><span class="cl">alter system checkpoint<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#3. 备份数据库</span>
</span></span><span class="line"><span class="cl">RMAN&gt;backup database plus archivelog<span class="p">;</span>
</span></span><span class="line"><span class="cl">RMAN&gt;list backup<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#4.误操作</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> systimestamp from dual<span class="p">;</span>   <span class="o">(</span>28-MAY-24 09.55.49<span class="o">)</span>
</span></span><span class="line"><span class="cl">truncate table scott.t1<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#5.之后再创建一张表</span>
</span></span><span class="line"><span class="cl">create table scott.t2 tablespace users as <span class="k">select</span> * from scott.dept<span class="p">;</span>
</span></span><span class="line"><span class="cl">create table scott.t3 tablespace tbs1 as <span class="k">select</span> * from scott.emp<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t1<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t2<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t3<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#6.验证表空间的依赖性</span>
</span></span><span class="line"><span class="cl">conn / as sysdba
</span></span><span class="line"><span class="cl">execute DBMS_TTS.TRANSPORT_SET_CHECK<span class="o">(</span><span class="s1">&#39;TBS1&#39;</span>, TRUE,TRUE<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">SELECT * FROM TRANSPORT_SET_VIOLATIONS<span class="p">;</span>
</span></span><span class="line"><span class="cl">execute DBMS_TTS.TRANSPORT_SET_CHECK<span class="o">(</span><span class="s1">&#39;TBS1,TBS2&#39;</span>, TRUE,TRUE<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">SELECT * FROM TRANSPORT_SET_VIOLATIONS<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#可以看到，如果只恢复表空间TBS1，会有T1表的索引依赖表空间TBS2。</span>
</span></span><span class="line"><span class="cl"><span class="c1">#我们这里同时恢复表空间TBS1,TBS2，这样就解决了依赖关系。</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#7.确定执行TSPITR后会丢失的对象</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> owner,name,tablespace_name,to_char<span class="o">(</span>creation_time,<span class="s1">&#39;yyyy-mm-dd hh24:mi:ss&#39;</span><span class="o">)</span> creation_time
</span></span><span class="line"><span class="cl">from TS_PITR_OBJECTS_TO_BE_DROPPED
</span></span><span class="line"><span class="cl">where tablespace_name in <span class="o">(</span><span class="s1">&#39;TBS1&#39;</span>,<span class="s1">&#39;TBS2&#39;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">and creation_time&gt;to_date<span class="o">(</span><span class="s1">&#39;2024-05-28 09:55:49&#39;</span>,<span class="s1">&#39;yyyy-mm-dd hh24:mi:ss&#39;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 这里没有查出结果，如果有结果，最好先expdp导出这些对象的备份，待恢复表空间后，再导入这些对象。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 当然如果确定这些对象是没有用的，可以直接忽略。</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 8.执行TSPITR</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">NLS_DATE_FORMAT</span><span class="o">=</span><span class="s2">&#34;yyyy-mm-dd hh24:mi:ss&#34;</span>
</span></span><span class="line"><span class="cl">RMAN&gt;recover tablespace TBS1,TBS2 <span class="k">until</span> <span class="nb">time</span> <span class="s1">&#39;2024-05-28 09:55:49&#39;</span> auxiliary destination <span class="s1">&#39;/u01/aux&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 9.检查</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> tablespace_name,status from dba_tablespaces<span class="p">;</span>
</span></span><span class="line"><span class="cl">alter tablespace tbs1 online<span class="p">;</span>
</span></span><span class="line"><span class="cl">alter tablespace tbs2 online<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t1<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t2<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">select</span> * from scott.t3<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">imp 
</span></span><span class="line"><span class="cl"><span class="c1"># 10.删除测试表空间和表</span>
</span></span><span class="line"><span class="cl">drop tablespace tbs1 including contents and datafiles<span class="p">;</span>
</span></span><span class="line"><span class="cl">drop tablespace tbs2 including contents and datafiles<span class="p">;</span>
</span></span><span class="line"><span class="cl">drop table scott.t2 purge<span class="p">;</span>
</span></span><span class="line"><span class="cl">drop table scott.t3 purge<span class="p">;</span>
</span></span></code></pre></div><hr>
<h2 id="闪回">闪回</h2>
<h3 id="闪回数据库">闪回数据库</h3>
<ul>
<li>前置条件
<ul>
<li>归档模式</li>
<li>启用闪回
<ul>
<li>查看是否启用:<code>select FLASHBACK_ON from v$database;</code></li>
<li>启用<code>alter database FLASHBACK ON;</code></li>
</ul>
</li>
</ul>
</li>
<li>相关参数
<ul>
<li><code>show parameter db_recovery_file_dest</code></li>
<li><code>show parameter db_recovery_file_dest_size</code></li>
<li><code>show parameter db_flashback_retention_target</code></li>
</ul>
</li>
<li><code>select OLDEST_FLASHBACK_TIME from v$flashback_database_log;</code></li>
<li>查看scn： <code>select current_scn from v$database;</code></li>
<li>闪回需要在mount阶段执行
<ul>
<li><code>startup mount;</code></li>
<li><code>flashback database to scn 666;</code></li>
<li><code>alter database open RESETLOGS;</code></li>
</ul>
</li>
</ul>
<h3 id="闪回表">闪回表</h3>
<ul>
<li>前提：激活表的行移动特性
<ul>
<li><code>select table name.ROW MOVEMENT from user tables;</code></li>
<li>激活 <code>alter table emp enable ROW MOVEMENT;</code></li>
</ul>
</li>
<li><code>flashback table scott.emp to timestamp to_timestamp('2024-05-28 11:31:05','yyyy-mm-dd hh24:mi:ss');</code></li>
</ul>
<h3 id="闪回删除">闪回删除</h3>
<ul>
<li>前提：启用回收站：<code>show parameter recyclebin;</code></li>
<li><code>flashback table &lt;table_name&gt; to before drop;</code></li>
</ul>
<h3 id="闪回查询">闪回查询</h3>
<ul>
<li>时间点
<ul>
<li><code>select * from emp as of timestamp to_timestamp ('2024-05-28 11:31:22','yyyy-mm-dd hh24:mi:ss') where deptno=30;</code></li>
<li><code>insert into emp select * from emp as of timestamp to_timestamp ('2024-05-28 11:31:22','yyyy-mm-dd hh24:mi:ss') where deptno=30;</code></li>
</ul>
</li>
<li>版本
<ul>
<li><code>select sal from emp versions between scn minvalue and maxvalue where empno=1234;</code></li>
</ul>
</li>
</ul>
<h3 id="闪回事务查询">闪回事务查询</h3>
<ul>
<li><code>select SUPPLEMENTAL_LOG_DATA_MIN from v$database;</code></li>
<li><code>alter database add SUPPLEMENTAL LOG DATA;</code></li>
<li><code>select versions_xid,empno,ename,versions_operation from my_emp versions between scn minvalue and maxvalue;</code> #050011003E020000</li>
<li>select undo_sql from FLASHBACK_TRANSACTION_QUERY where xid=&lsquo;050011003E020000&rsquo;;</li>
</ul>
<h3 id="闪回事务">闪回事务</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">select</span> distinct xid,commit_scn
</span></span><span class="line"><span class="cl">  from flashback_transaction_query
</span></span><span class="line"><span class="cl">  where <span class="nv">table_owner</span><span class="o">=</span><span class="s1">&#39;HR&#39;</span>and 
</span></span><span class="line"><span class="cl">  <span class="nv">table_name</span><span class="o">=</span><span class="s1">&#39;EMPLOYEES&#39;</span> and  
</span></span><span class="line"><span class="cl">  commit_timestamp &gt; systimestamp - interval <span class="s1">&#39;10&#39;</span> minute
</span></span><span class="line"><span class="cl">  order by commit_scn<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 得到</span>
</span></span><span class="line"><span class="cl">XID              COMMIT_SCN
</span></span><span class="line"><span class="cl">---------------- ----------
</span></span><span class="line"><span class="cl">07001400DA030000    <span class="m">2611571</span>
</span></span><span class="line"><span class="cl"><span class="m">0100070003040000</span>    <span class="m">2611623</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">declare</span>
</span></span><span class="line"><span class="cl">  xids sys.xid_array<span class="p">;</span>
</span></span><span class="line"><span class="cl">  begin
</span></span><span class="line"><span class="cl">    xids :<span class="o">=</span> sys.xid_array<span class="o">(</span><span class="s1">&#39;07001400DA030000&#39;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    dbms_flashback.transaction_backout<span class="o">(</span>1,xids,options<span class="o">=</span>&gt;dbms_flashback.cascade<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  end<span class="p">;</span>
</span></span><span class="line"><span class="cl">/
</span></span></code></pre></div><h2 id="最终实验">最终实验</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /u01/app/eu/admin/seuwyd29/adump
</span></span><span class="line"><span class="cl">mkdir -p /u01/app/eu/fast_recovery_area/seuwyd29
</span></span><span class="line"><span class="cl">mkdir -p /u01/app/seuwyd29
</span></span><span class="line"><span class="cl">mkdir -p /u01/app/eu/oradata/seuwyd29
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">ORACLE_SID</span><span class="o">=</span>seuwyd29
</span></span><span class="line"><span class="cl">sqlplus / as sysdba
</span></span><span class="line"><span class="cl">SYS@seuwyd29&gt;startup nomount
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">create database seuwyd29
</span></span><span class="line"><span class="cl">  datafile <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/system01.dbf&#39;</span> size 400m
</span></span><span class="line"><span class="cl">  sysaux datafile <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/sysaux01.dbf&#39;</span> size 400m
</span></span><span class="line"><span class="cl">  default tablespace users datafile <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/users01.dbf&#39;</span> size 100m
</span></span><span class="line"><span class="cl">  default temporary tablespace temp tempfile <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/temp01.dbf&#39;</span> size 20m
</span></span><span class="line"><span class="cl">  undo tablespace undotbs1 datafile <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/undotbs01.dbf&#39;</span> size 50m
</span></span><span class="line"><span class="cl">  logfile
</span></span><span class="line"><span class="cl">  group <span class="m">1</span> <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/redo01.log&#39;</span> size 10m,
</span></span><span class="line"><span class="cl">  group <span class="m">2</span> <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/redo02.log&#39;</span> size 10m,
</span></span><span class="line"><span class="cl">  group <span class="m">3</span> <span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/redo03.log&#39;</span> size 10m<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">SELECT LAST_NAME, YEARS, MONTHS
</span></span><span class="line"><span class="cl">FROM <span class="o">(</span>
</span></span><span class="line"><span class="cl">    SELECT 
</span></span><span class="line"><span class="cl">        LAST_NAME,
</span></span><span class="line"><span class="cl">        FLOOR<span class="o">(</span>MONTHS_BETWEEN<span class="o">(</span>SYSDATE, HIRE_DATE<span class="o">)</span> / 12<span class="o">)</span> AS YEARS,
</span></span><span class="line"><span class="cl">        TRUNC<span class="o">(</span>MOD<span class="o">(</span>MONTHS_BETWEEN<span class="o">(</span>SYSDATE, HIRE_DATE<span class="o">)</span>, 12<span class="o">))</span> AS MONTHS,
</span></span><span class="line"><span class="cl">        ROW_NUMBER<span class="o">()</span> OVER <span class="o">(</span>ORDER BY FLOOR<span class="o">(</span>MONTHS_BETWEEN<span class="o">(</span>SYSDATE, HIRE_DATE<span class="o">)</span> / 12<span class="o">)</span> DESC, 
</span></span><span class="line"><span class="cl">                           TRUNC<span class="o">(</span>MOD<span class="o">(</span>MONTHS_BETWEEN<span class="o">(</span>SYSDATE, HIRE_DATE<span class="o">)</span>, 12<span class="o">))</span> DESC<span class="o">)</span> AS RANK
</span></span><span class="line"><span class="cl">    FROM 
</span></span><span class="line"><span class="cl">        hr.employees
</span></span><span class="line"><span class="cl"><span class="o">)</span>
</span></span><span class="line"><span class="cl">WHERE RANK BETWEEN <span class="m">6</span> AND 20<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#logmnr </span>
</span></span><span class="line"><span class="cl">mkdir -p /u01/demo/eudict
</span></span><span class="line"><span class="cl">create directory EUDICT as <span class="s1">&#39;/u01/demo/eudict&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">EXECUTE dbms_logmnr_d.build<span class="o">(</span><span class="s1">&#39;v816dict.ora&#39;</span>,<span class="s1">&#39;EUDICT&#39;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">EXECUTE dbms_logmnr.add_logfile<span class="o">(</span><span class="nv">logfilename</span><span class="o">=</span>&gt;<span class="s1">&#39;/u01/app/eu/oradata/seuwyd29/redo02.log&#39;</span>,Options<span class="o">=</span>&gt;dbms_logmnr.new<span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">EXECUTE dbms_logmnr.start_logmnr<span class="o">(</span><span class="nv">DictFilename</span><span class="o">=</span>&gt;<span class="s1">&#39;/u01/demo/eudict/v816dict.ora&#39;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 闪回事务</span>
</span></span><span class="line"><span class="cl">create table scott.my_emp as <span class="k">select</span> * from scott.emp<span class="p">;</span>
</span></span><span class="line"><span class="cl">delete from scott.my_emp where <span class="nv">empno</span><span class="o">=</span>7900<span class="p">;</span>
</span></span><span class="line"><span class="cl">delete from scott.my_emp where <span class="nv">empno</span><span class="o">=</span>7844<span class="p">;</span>
</span></span><span class="line"><span class="cl">commit<span class="p">;</span>
</span></span></code></pre></div><h2 id="参考">参考</h2>
<ul>
<li><a href="https://rehoni.github.io/cn/2018/2018-02-27-oracle-1/"  target="_blank" rel="noopener" >Oracle实践数据库笔记-1 - Rehoni | 罗皓</a></li>
<li><a href="https://kurisu0829.github.io/posts/%E5%AE%9E%E7%94%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AE%9E%E8%B7%B5%E7%AC%94%E8%AE%B0/"  target="_blank" rel="noopener" >实用数据库实践笔记 | Kurisu</a></li>
<li><a href="https://blog.csdn.net/qq_43670385/article/details/132873685"  target="_blank" rel="noopener" >ORACLE手工创建数据库(sales)_创建一个默认数据库为productsale-CSDN博客</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>方言歌曲</title>
      <link>https://ds63.eu.org/2024/dialect-songs/</link>
      <pubDate>Sat, 01 Jun 2024 12:42:34 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2024/dialect-songs/</guid>
      <description>最近越来越对方言感兴趣</description>
      <content:encoded><![CDATA[<p><strong>最近越来越对方言感兴趣，尤其是其与现代音乐的结合。</strong></p>
<h2 id="说在前头">说在前头</h2>
<p>我不懂乐理，可以说五音不全，</p>
<p>我也不懂多少方言，只熟悉闽南语。</p>
<p>但我还是对方言歌曲有兴趣。</p>
<p>我不希望将这篇写得跟报菜名似的：只是一首首歌名的堆砌。</p>
<p>我希望能写出，为什么我开始对方言歌曲感兴趣。是那些地方打动了我。</p>
<hr>
<h2 id="自本">《自本》</h2>
<p><a href="https://neodb.social/album/5JCu9l1r3b3WLLnJIkjzBw"  target="_blank" rel="noopener" >NeoDB - 音乐 | 自本</a></p>
<p>专辑推荐里写的是</p>
<blockquote>
<p>新作品的曲風也多樣且新穎，包括Lo-Fi、電子、民謠、funk，也大量加入了管弦樂的元素，時而滂薄、時而柔緩。</p>
</blockquote>
<p>我对这些概念了解得不多，但至少能听出来每首曲子的风格都不太一样。</p>
<p>我推荐这张专最主要的原因是：它展现和证明了闽南语和多种元素的结合的可能性。</p>
<hr>
<h2 id="我等就来唱山歌">《我等就来唱山歌》</h2>
<p><a href="https://neodb.social/album/2m0Ut0iNLPL1rPIyONrUAC"  target="_blank" rel="noopener" >NeoDB - 音乐 | 我等就来唱山歌</a></p>
<p>这是一张记录反美濃水庫运动的专辑。</p>
<p>对这社会运动感兴趣的话可以参见<a href="https://zh.wikipedia.org/wiki/%E7%BE%8E%E6%BF%83%E5%8F%8D%E6%B0%B4%E5%BA%AB%E9%81%8B%E5%8B%95"  target="_blank" rel="noopener" >美浓反水库运动 - 维基百科，自由的百科全书</a>。</p>
<ul>
<li>《下淡水河寫著我等介族譜》: 这首歌长七分钟。七分钟讲了美濃人改造自然的历史。我最喜欢的有两段
<ul>
<li>下面这段歌词重复了很多次，开头的时候是慢节奏，中间在一句拉长的&quot;美濃山下&quot;后，变得快节奏，十分有激情和史诗感。
<blockquote>
<p>佢等打林築柵撿石做堋
將厥片殘山剩水
變啊做好山好水
佢等緊手緊腳做細食粗
結果田坵
田坵滿園青溜
佢等打林築柵撿石做堋
將厥片殘山剩水
變啊做好山好水
佢等緊手緊腳做細食粗
結果田坵
田坵滿園青溜</p>
</blockquote>
</li>
<li>另一段是合唱
<blockquote>
<p>奉請
今晨吉期
開基福神
新壇甫竣
我等同心誠意
祭告山川
懇祈上蒼
佑此土可大
亦因可久
將奕世於瀰濃</p>
</blockquote>
</li>
</ul>
</li>
<li>《山歌唱来解心烦》：这首讲的是乡亲们相约来到立法院 ,心烦懊躁，于是唱山歌来互相鼓劲。我尤其喜欢那句“衙门再恶照样屌” ,特帅。</li>
<li>《水库系筑得屎麽食得》： 很有意思的一曲，“水库系筑得屎麽食得”一句的重复中夹着乡民们反对修建水库的原因。</li>
</ul>
<hr>
<h2 id="菊花夜行军">《菊花夜行军》</h2>
<p><a href="https://neodb.social/album/1QJzcvgL2whmiAQ0d9ZJ0G"  target="_blank" rel="noopener" >NeoDB - 音乐 | 菊花夜行军</a></p>
<p>看<a href="https://www.youtube.com/watch?v=xiSDTtZMclM&amp;list=PLuursoLHbECSIURCwSXKp506nIjWTH2NH&amp;index=6&amp;ab_channel=de617"  target="_blank" rel="noopener" >風神125 ~ 交工樂隊 - YouTube</a>下面的评论</p>
<ul>
<li>
<p>@user-qr4hj6lw4h</p>
<blockquote>
<p>每次騎著車返家，腦海中就會浮現這首歌，然後哭得泣不成聲。
隻身到台東念大學，離屏東說遠不遠說近不近，還沒電氣化之前，返家的火車票幾乎都被觀光團掃光，沒有提前搶票南迴是真的難回，也因為這樣我也習慣騎車回屏東了，想走就走不用擔心誤點。
從大一騎到大四，一路看著南迴公路從破爛的柏油路整修到寬敞的四線道，我也算是另類的工程驗收單位與見證者吧(笑
每次返家總會被家人叨唸，自己也清楚那是對我們的關心，但總是左耳進右耳出，在外思鄉，回到家卻又想往外跑，就是這麼的矛盾。現在要畢業了，遙想自己的未來，實在是不敢想像，希望這波疫情之後，能夠順利返家，好好見見家人，真的好想你們。
聽著不熟悉的語言，情緒卻如此激動，眼淚似洪水般潰堤，好想家，好想我的故鄉&hellip;</p>
</blockquote>
</li>
<li>
<p>@user-cm8te5gj5e</p>
<blockquote>
<p>這首已經不是單純的音樂了，應列為文史記錄。描述了國民黨的以農養工政策下，鄉村的農民子弟被迫離鄉打拼十年，卻遇石油危機而失業在城市待不住，返鄉路上的心酸苦楚。</p>
<p>我明白這樣的現象仍然大規模的在中國發生，也就是廣大的農民工子弟們。坦白說沒有他們的血汗受剝削，過往台商也大多不會想去投資設廠。
現在台灣民族主義很可怕的是，會認為台商過往去中國是去「教育」他們。希望這首歌可以讓我們看到歷史發展軌跡，台灣與中國兩國的相似，經濟發展都是來自於底層人民的犧牲。</p>
</blockquote>
</li>
<li>
<p>@rollbin</p>
<blockquote>
<p>类似有啊 西北有 野孩子，苏阳 东北 有 二手玫瑰 南方有 五条人 山人， 不过交工确实老一辈</p>
</blockquote>
<p>可以顺着这位的推荐去听听</p>
</li>
</ul>
<hr>
<h2 id="有无">《有无》</h2>
<p><a href="https://www.youtube.com/watch?v=vz20uZMzHMg&amp;ab_channel=Sheng-Xiang%26Band"  target="_blank" rel="noopener" >大佛普拉斯 電影片尾曲 有無 - YouTube</a></p>
<p>这首曲子是《大佛普拉斯》的片尾曲。电影我十分推荐，这片尾曲我也时不时拿出来听。</p>
<p>有趣的一点在于英文单词的掺杂</p>
<ul>
<li>“反身的chance有抑无”</li>
<li>“够力的back有抑无”</li>
</ul>
<p>我阅历还不够，只能品出小人物或者说普通百姓面对世事的无奈。不过翻评论区翻到了条很厉害的评论，摘录如下</p>
<p>@PhoenixHsuFairy</p>
<blockquote>
<p>開頭第一段四句，說明了人活在世上是由盲目的機率（blind chance）所決定，一個人的出生影響他未來命運可能的走向，而小人物想要翻身，但機會卻是給有「背景」的人。
這一段直接描述人的命運的不可掌控，但接下來一段卻全然開展出天蒼地茫的氣象：
第一句寫出天地日月星辰，彷彿回到開天闢地之初，那最曠古恆初的宇宙自然。
第二句再進入人世紅塵，呈現破落鄉村的景象：破房子、田埂、路邊的野花。
第三句點出在其中生活的人類，被賦予了眼、耳、鼻、舌等感官，可以感知外界的自然與人文環境。
最後一句點出，人不只是獨自地存活，而是與他人共處；人更不只是如動物般感知外界的事物，更是一種「有情」的存在。
此段四句層層推進，從有宇宙、有人間到有凡人與有情義，彷彿《聖經》中的上帝說，要有光，就有了光，於是有了天地萬物，有了人在此中佔據一席之地，並在人跟人之間創造了感情。此段定義了人作為「有情」的存在本質。
接著底下兩句「如夢幻泡影如露亦如電」一轉，唱出人生無常的悲哀，因此接著下一段歌詞，說明「有的」亦可以瞬間變為「無的」。
「無地、無天、無星、無日月」宛如世界末日，而人世亦隨之灰飛煙滅（「無厝、無田路、無草仔花」）。
「無看兮、無聽兮、無鼻兮、無啖兮」是殘疾者無能感知外在的世界，是貧困者無能填飽自己的肚腸。
社會底階的小人物沒空胡思亂想（「空思」），更遑論「夢想」，只求「無代誌」。
最後一段以「煙」與「火」比喻小人物渺小的生命：他們的死亡如煙隨風而去、如火隨時熄滅，無法留下一丁點痕跡。
如果沒有痕跡，那根香煙真的曾經點燃過嗎？那菸味、粉味是真的曾在空氣中瀰漫過嗎？
這些「無看兮、無聽兮、無鼻兮、無啖兮」的卑微生命，如螻蟻般地艱困求生，卻又如煙、如火、如泡影、如露如電般轉瞬即逝，那這樣的存在又有什麼意義？
屈原的〈天問〉是原古生民，在面對神祕不可解的宇宙​​時，提出了上百個沒有答案的提問：從自然界天體如何運行，到人世間人物的盛衰成敗的原因，最終的問題自是這一切的一切究竟有什麼意義呢？
〈有無〉一曲卻如畫龍點睛般將之提升到〈天問〉的高度，是對人的卑微存在的永恆的疑惑與叩問。
一切有為法，如夢幻泡影，如露亦如電，應作如是觀。
那是否，應該看透一切，捨棄生而為人的愛恨貪癲癡呢?
到底這樣的人生，意義是「有抑無」？</p>
</blockquote>
<p><a href="https://www.youtube.com/watch?v=HQ7v1uwFTUw&amp;ab_channel=HebeTien%27sOfficialChannel%E7%94%B0%E9%A6%A5%E7%94%84%E5%AE%98%E6%96%B9%E5%B0%88%E5%B1%AC%E9%A0%BB%E9%81%93"  target="_blank" rel="noopener" >田馥甄 Hebe Tien《有無 To Have, or Not To Have》Official Live MV - YouTube</a>这个版本也蛮有意思的，可以试试。</p>
<hr>
<h2 id="楼仔厝">《楼仔厝》</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=RyItqJtoK_Q&amp;list=PL8hj_WcS6boQsuX_nUXJOrwAGzxYM7-ne&amp;index=10&amp;ab_channel=%E6%B0%B4%E6%99%B6%E7%B4%A2%E5%BC%95%E8%81%B2%E9%9F%B3%E8%B3%87%E6%96%99%E5%BA%AB"  target="_blank" rel="noopener" > 辦桌壹 樓仔厝 吳俊霖（伍佰） 1991 - YouTube</a></li>
</ul>
<p>听着很欢乐，台语和国语的混合怪有趣的。</p>
<p>更喜欢的是这首歌的专辑的立意</p>
<blockquote>
<p>台語歌曾被認為是鄙陋的，我們期望它像辦桌的菜色」，他們要作的是讓台語歌不再悲情，期待用辨桌的歡樂心情，凝聚台灣的心，其中錄的九首歌，就像同辦桌的菜色，材料紮實又有濃厚的家鄉味</p>
</blockquote>
<hr>
<h2 id="樹枝孤鳥">《樹枝孤鳥》</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=QvE5BQSYAPs&amp;ab_channel=%E6%BB%BE%E7%9F%B3%E5%94%B1%E7%89%87ROCKRECORDS"  target="_blank" rel="noopener" > 伍佰 Wu Bai&amp;China Blue【返去故鄉 Back to hometown】Official Music Video - YouTube</a></li>
</ul>
<p>某日等车的时候随机到这首歌，几乎是一听钟情，当天循环了好几次，跟着唱。</p>
<p>这首歌讲游子返乡的故事，一开始游子近乡情更怯，但越走越有气势，因为家乡这就是他长大的地方，他的双脚站在那边大地上。家乡的大地上有他的灵魂、鲜血，眼泪。</p>
<p>“咱來借問路邊的歐吉桑 這條路和較早哪隴無同”的欧吉桑。台语中有部分词汇是直接从日语音译过来的，听得少，怪好玩的。</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=sKwIcvv__sY&amp;ab_channel=%E6%BB%BE%E7%9F%B3%E5%94%B1%E7%89%87ROCKRECORDS"  target="_blank" rel="noopener" > 伍佰 Wu Bai&amp;China Blue【空襲警報】Official Music Video - YouTube</a></li>
</ul>
<p>将日本殖民台湾的那段历史唱进了歌里。</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=kEXCoQNY6Mc&amp;ab_channel=%E6%BB%BE%E7%9F%B3%E5%94%B1%E7%89%87ROCKRECORDS"  target="_blank" rel="noopener" > 伍佰 Wu Bai&amp;China Blue【心愛的再會啦 Farewell my love】Official Music Video - YouTube</a></li>
</ul>
<p>这首很早就听过，足见其经典。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://opinion.cw.com.tw/blog/profile/390/article/11816"  target="_blank" rel="noopener" >菊花如何夜行軍：那些年，我們寫下自己運動的歌 ｜ 鍾永豐 ／ 獨評讀好書 ｜ 獨立評論</a></li>
<li><a href="https://everylittled.com/article/159647"  target="_blank" rel="noopener" >聽不懂歌詞也沒什麼大礙：7首讓你想一聽再聽的「方言歌曲」 - every little d</a></li>
<li><a href="https://m.huxiu.com/article/285909.html"  target="_blank" rel="noopener" >“方言音乐”里的味道，什么也替代不了-虎嗅网</a></li>
<li><a href="https://zh.taiwanbeats.tw/archives/18303"  target="_blank" rel="noopener" >【台灣音樂專題報導】台灣搖滾簡史 - Taiwan Beats</a></li>
<li><a href="https://www.douban.com/doulist/1526936/"  target="_blank" rel="noopener" >简明台湾民歌收听指南</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Redis学习笔记</title>
      <link>https://ds63.eu.org/2024/learn_redis/</link>
      <pubDate>Thu, 30 May 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_redis/</guid>
      <description>无快不破</description>
      <content:encoded><![CDATA[<h2 id="安装脚本">安装脚本</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># #!/bin/bash</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># install redis-stack-server</span>
</span></span><span class="line"><span class="cl">curl -fsSL https://packages.redis.io/gpg <span class="p">|</span> sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
</span></span><span class="line"><span class="cl">sudo chmod <span class="m">644</span> /usr/share/keyrings/redis-archive-keyring.gpg
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb </span><span class="k">$(</span>lsb_release -cs<span class="k">)</span><span class="s2"> main&#34;</span> <span class="p">|</span> sudo tee /etc/apt/sources.list.d/redis.list
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install redis-stack-server
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># setup</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;setup redis&#34;</span>
</span></span><span class="line"><span class="cl">sudo <span class="nb">echo</span> <span class="s2">&#34;requirepass your_password&#34;</span> &gt;&gt; /etc/redis-stack.conf
</span></span><span class="line"><span class="cl">sudo <span class="nb">echo</span> <span class="s2">&#34;bind 0.0.0.0&#34;</span> &gt;&gt; /etc/redis-stack.conf
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># restart</span>
</span></span><span class="line"><span class="cl">sudo service redis-stack-server start
</span></span></code></pre></div><hr>
<h2 id="登录">登录</h2>
<p><code>redis-cli -h hostname -a password</code></p>
<hr>
<h2 id="use-redis-in-docker">Use redis in Docker</h2>
<p>详见<a href="https://ds63.eu.org/2024/mysql_redis_in_one_docker/#redis"  target="_blank" rel="noopener" >Use mysql and redis in Docker | EuDs&rsquo;s Blog</a></p>
<hr>
<h2 id="pub-sub">pub sub</h2>
<ul>
<li><code>PUBSUB CHANNELS [pattern]</code></li>
<li>作用： Lists the currently active channels.(An active channel is a Pub/Sub channel with one or more subscribers (excluding clients subscribed to patterns).)</li>
<li>补充：我曾犯过这样一个错误，<code>UNSUBSCRIBE channel1</code>,然后发现<code>PUBSUB CHANNELS</code>还是有它,就在那纳闷，好一会才反应过来，可能这个channel还有其他被监听的地方。</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://medium.com/redis-with-raphael-de-lio/understanding-pub-sub-in-redis-18278440c2a9"  target="_blank" rel="noopener" >Understanding Pub/Sub in Redis (Getting Started) | Redis with Raphael De Lio</a></li>
<li><a href="https://redis.io/docs/latest/commands/pubsub-channels/"  target="_blank" rel="noopener" >PUBSUB CHANNELS | Docs</a></li>
</ul>
<hr>
<h2 id="list">List</h2>
<ul>
<li><a href="https://redis.io/docs/latest/develop/data-types/lists/"  target="_blank" rel="noopener" >Redis lists | Docs</a></li>
<li><code>lpop</code></li>
<li>LPUSH adds a new element to the head of a list; RPUSH adds to the tail.</li>
<li>LPOP removes and returns an element from the head of a list; RPOP does the same but from the tails of a list.</li>
<li>LLEN returns the length of a list.</li>
<li>LMOVE atomically moves elements from one list to another.</li>
<li>LRANGE extracts a range of elements from a list.</li>
<li>LTRIM reduces a list to the specified range of elements.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>计算机类比</title>
      <link>https://ds63.eu.org/2024/analogy-in-computer/</link>
      <pubDate>Sun, 26 May 2024 16:06:34 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2024/analogy-in-computer/</guid>
      <description>用计算机的视角看生活</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>本文致力于收集用计算机领域中的概念去类比其他领域中的概念的例子。大部分是我摘录别人的，小部分是我自己的想法。</p>
<p>在计算机这一领域，不少概念都是模仿生活中、或其他领域的概念，诸如：继承、神经网络。但反过来的却不算多。因此更让人觉得有趣。（至少我觉得很有趣）</p>
<h2 id="声明">声明</h2>
<p>本文收集的类比，如果我是从别处看到的，我会标出具体是在哪看到的。但我无法保证我标注的出处是最早、最原本的出处。因为类似的想法可能很多人都会有。</p>
<h2 id="把我看作一个-git-repo">把「我」看作一个 git repo</h2>
<ul>
<li>出处：<a href="https://dantezy.xyz/posts/ghost-in-the-shell-again/"  target="_blank" rel="noopener" >再看 Ghost in the Shell | 一派胡言</a></li>
<li>摘录：</li>
</ul>
<blockquote>
<p>我的朋友 reorx 说这个简单，看 repo 的唯一 id，这当然是一个合法解。毕竟当下我们也是靠个人证件证实个人身份，以后可能还会上基因签名——假如有这么一天，要考虑的就是如果到处都是克隆人怎么办。
我想的其实是，一个 repo 其实会引入对其他 repo 的依赖，也会被其他 repo 依赖，忽然的大变动会打破这种依赖。这个比喻就是说一个人的社会关系可以界定「我」， 正常情况下「我」的改变也会伴随着社会关系的改变。但是一个人短时间内彻底的改变会导致社会关系的断裂。</p>
<p>但无论是 Id，还是社会关系，都是通过外部条件来确定「我」。这些都不是很牢固，如果我是一个离群索居的人，那随时可能有个人杀了我，拿走我的身份证，然后以我的身份活下去。</p>
<p>不过真有这种事发生，那「我」不「我」的，也没所谓了。</p>
</blockquote>
<ul>
<li>想法：我觉得还可以拿特征向量作比，每个人的特点都是一个特征值，而这一个个特点组合起来，就是一个独一无二的特征向量，便可以用来粗略地描述一个人。</li>
</ul>
<h2 id="把改革看作重构">把改革看作重构</h2>
<ul>
<li>
<p>出处：出自我看过的一篇博客，但我一时实在找不着了。在此向原作者致歉。</p>
</li>
<li>
<p>大意：
历史上的各种朝代更替，政权更迭可以理解为重构。社会的发展类似于不断增加的需求。日常的政策是在打补丁，改革就像局部重构。等哪天这套代码彻底没法满足而革命则是大幅度重构，甚至干脆就是推到重写。作者说这也能解释美国为什么能行。那是因为当年的架构设计足够优秀，而且历史够短，技术债不累计。</p>
</li>
<li>
<p>我的想法：
我觉得这个类比蛮有趣的。但美国的那段我有自己的看法。</p>
<p>最近玩维多利亚3才知道非洲有个小国，利比里亚。它与美国有很深的渊源，建国至今不到三百年，制度可以说完全照搬美国，如果按作者的说法，那这个国家应该十分强大。但事实不然。所以说，架构设计好不好，还是要取决于应用的场景。架构设计好，也不一定就能保证后续的项目一定很棒。</p>
</li>
</ul>
<h2 id="笨嘴笨舌的原因">笨嘴笨舌的原因</h2>
<ul>
<li>出处：<a href="https://x.com/Soulogic/status/1712513375438254588"  target="_blank" rel="noopener" >Soulogic on X: &ldquo;我终于知道自己为什么笨嘴笨舌了 / X</a></li>
<li>原文：
<blockquote>
<p>终于知道自己为什么笨嘴笨舌了，因为说话显然是 NP 完全问题</p>
<p>没有精确表达，只有近似精确，难度大致是用 100 字节以内的 LaTex 公式来高精度描述一个被随机出来的无理数
有时候能比较溜地说话时因为以前找到过近似解</p>
</blockquote>
</li>
</ul>
<h2 id="大脑是高性能低功耗的处理器">大脑是高性能低功耗的处理器</h2>
<ul>
<li>
<p>出处：刷推刷到的。我当时没有及时记录，后面尝试去找，没找到。在此向原作者致歉。</p>
</li>
<li>
<p>大意：
大脑是高性能低功耗的处理器，但有些错误的教育方式把它当成了存储器。</p>
</li>
<li>
<p>我的想法：
处理器里的缓存是很宝贵的，就连酷睿i9-14900KS的二/三级缓存都只有36MB.</p>
<p>那我们大脑里那宝贵的缓存空间该存些什么呢？</p>
<p>爱因斯坦有句话，意思是说“教育就是忘记了在学校所学的一切之后剩下的东西&rdquo;。我好几个老师在课程结束时的祝语都类似于：也许几年后，这门课的知识你们也许记不得多少，但希望相关的思维方式能对你们有所帮助。</p>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之异步</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_async/</link>
      <pubDate>Sat, 25 May 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_async/</guid>
      <description>自己学习过程中整理的关于JavaScript中异步的知识点</description>
      <content:encoded><![CDATA[<h2 id="单线程">单线程</h2>
<ul>
<li>
<p>原因:</p>
<ul>
<li>与它的用途有关: 作为浏览器脚本语言，JavaScript 的主要用途是与用户互动，以及操作 DOM。若以多线程的方式操作这些 DOM，则可能出现操作的冲突。假设有两个线程同时操作一个 DOM 元素，线程 1 要求浏览器删除 DOM，而线程 2 却要求修改 DOM 样式，这时浏览器就无法决定采用哪个线程的操作。当然，我们可以为浏览器引入“锁”的机制来解决这些冲突，但这会大大提高复杂性，所以 JavaScript 从诞生开始就选择了单线程执行。</li>
</ul>
</li>
<li>
<p><a href="https://github.com/JChehe/blog/blob/master/posts/%E5%85%B3%E4%BA%8EJavaScript%E5%8D%95%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BA%8B.md"  target="_blank" rel="noopener" >blog/posts/关于JavaScript单线程的一些事.md at master · JChehe/blog</a></p>
</li>
</ul>
<h2 id="回调函数">回调函数</h2>
<ul>
<li>最基本的方法</li>
</ul>
<h3 id="实例">实例</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">//有两个函数f1和f2，后者等待前者的执行结果。f1耗时长
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">f1</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">f2</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 可以考虑改写f1，把f2写成f1的回调函数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">f1</span><span class="p">(</span><span class="nx">callback</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">　<span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">　　<span class="c1">// f1的任务代码
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>　　<span class="nx">callback</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">　<span class="p">},</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="优点">优点</h3>
<ul>
<li>简单、容易理解和部署</li>
</ul>
<h3 id="缺点">缺点</h3>
<ul>
<li>不利于代码的阅读和维护，各个部分之间高度耦合（Coupling），流程会很混乱</li>
<li>每个任务只能指定一个回调函数</li>
</ul>
<hr>
<h2 id="事件监听">事件监听</h2>
<ul>
<li>任务的执行不取决于代码的顺序，而取决于某个事件是否发生</li>
</ul>
<h3 id="示例">示例</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 为f1绑定一个事件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">f1</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;done&#39;</span><span class="p">,</span><span class="nx">f2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 改写f1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">f1</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">f1</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;done&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span><span class="mi">1000</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="优点-1">优点</h3>
<ul>
<li>比较容易理解</li>
<li>可以绑定多个事件，每个事件可以指定多个回调函数</li>
<li>可以&quot;去耦合&quot;（Decoupling），有利于实现模块化</li>
</ul>
<h3 id="缺点-1">缺点</h3>
<ul>
<li>整个程序都要变成事件驱动型，运行流程会变得很不清晰</li>
</ul>
<hr>
<h2 id="promise">Promise</h2>
<h3 id="描述">描述</h3>
<ul>
<li>一个 Promise 是一个<strong>代理</strong>，它代表一个在创建 promise 时不一定已知的值。</li>
<li>它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。</li>
<li>这使得异步方法可以像同步方法一样返回值：异步方法不会立即返回最终值，而是返回一个 promise，以便在将来的某个时间点提供该值。</li>
</ul>
<h3 id="状态">状态</h3>
<ul>
<li>待定（pending）：初始状态，既没有被兑现，也没有被拒绝。</li>
<li>已兑现（fulfilled）：意味着操作成功完成。</li>
<li>已拒绝（rejected）：意味着操作失败。</li>
</ul>
<h3 id="方法">方法</h3>
<ul>
<li><code>.then()</code>:
<ul>
<li>最多接受两个参数；第一个参数是 Promise 兑现时的回调函数，第二个参数是 Promise 拒绝时的回调函数</li>
<li>返回一个新生成的 Promise 对象，这个对象可被用于链式调用</li>
</ul>
</li>
<li><code>.catch()</code>其实就是一个没有为 Promise 兑现时的回调函数留出空位的 <code>.then()</code></li>
<li><code>Promise.all()</code>
<ul>
<li>特点
<ol>
<li>接收一个可迭代对象</li>
<li>传入的数据中可以是普通数据，也可以是Promise对象</li>
<li>可迭代对象的promise是并行执行的</li>
<li>保持输入数组的顺序和输出数组的顺序一致</li>
<li>传入数组中只要有一个reject，立即返回reject,并带有第一个被拒绝的原因。</li>
<li>所有数据resolve之后返回一个 Promise</li>
</ol>
</li>
<li>实现: 参考: <a href="https://juejin.cn/post/7006200103157383175"  target="_blank" rel="noopener" >手写Promise.all - 掘金</a>
<code>JavaScript function myPromiseAll(iterable){ return new Promise((resolve,reject)=&gt;{ const promises = Array.from(iterable); const result = []; let count = 0; const len = promises.length; for(let i=0;i&lt;len;i++){ Promise.resolve(promises[i]).then(res=&gt;{ result[i] = res; count++; if(count===len){ resolve(result); } }).catch(err=&gt;{ reject(err); }) } }) } </code></li>
</ul>
</li>
<li><code>Promise.any()</code>
<ul>
<li>当输入的任何一个 Promise 兑现时，这个返回的 Promise 将会兑现，并返回第一个兑现的值。当所有输入 Promise 都被拒绝（包括传递了空的可迭代对象）时，它会以一个包含拒绝原因数组的 AggregateError 拒绝。</li>
</ul>
</li>
<li><code>Promise.allSettld()</code></li>
<li><code>Promise.race()</code>
<ul>
<li>特点:
<ol>
<li>返回第一个执行完成的 Promise，无论它是被 resolve 还是 reject</li>
</ol>
</li>
<li>实现:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">myPromiseRace</span><span class="p">(</span><span class="nx">promises</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span><span class="nx">reject</span><span class="p">)=&gt;{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">promise</span> <span class="k">of</span> <span class="nx">promises</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">promise</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span><span class="nx">reject</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
</li>
<li><code>Promise.withResolvers()</code>
<ul>
<li>returns an object containing a new Promise object and two functions to resolve or reject it</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers"  target="_blank" rel="noopener" >Promise.withResolvers() - JavaScript | MDN</a></li>
</ul>
</li>
</ul>
<h3 id="作用">作用</h3>
<ul>
<li>参考<a href="https://juejin.cn/post/6844903693658259464"  target="_blank" rel="noopener" >Promise作用以及基本使用 - 掘金</a></li>
<li>将异步操作以同步操作的流程表达出来，避免层层嵌套的回调函数。表达更清晰高效，也更便于维护。</li>
</ul>
<h3 id="缺点-2">缺点</h3>
<ol>
<li>一旦新建它就会立即执行，无法中途取消</li>
<li>如果不设置回调函数，Promise内部抛出的错误，不会反应到外部</li>
<li>当处于Pending状态时，无法得知目前进展到哪一个阶段</li>
</ol>
<h3 id="问题一与settimeout的区别">问题一：与<code>setTimeout</code>的区别</h3>
<ul>
<li>setTimeout处于宏任务队列，Promise位于微任务队列</li>
<li>示例</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 用一个已解决的 Promise——“resolvedProm”为例，
</span></span></span><span class="line"><span class="cl"><span class="c1">// 函数调用“resolvedProm.then(...)”立即返回一个新的 Promise，
</span></span></span><span class="line"><span class="cl"><span class="c1">// 但是其中的处理器“(value) =&gt; {...}”将被异步调用，正如打印输出所示。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 新的 Promise 被赋值给“thenProm”，
</span></span></span><span class="line"><span class="cl"><span class="c1">// 并且 thenProm 将被解决为处理函数返回的值。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">resolvedProm</span> <span class="o">=</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="mi">33</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">resolvedProm</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">thenProm</span> <span class="o">=</span> <span class="nx">resolvedProm</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="sb">`在主堆栈结束后被调用。收到的值是：</span><span class="si">${</span><span class="nx">value</span><span class="si">}</span><span class="sb">，返回的值是：</span><span class="si">${</span><span class="nx">value</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">thenProm</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 使用 setTimeout，我们可以将函数的执行推迟到调用栈为空的时刻。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">thenProm</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 按顺序打印：
</span></span></span><span class="line"><span class="cl"><span class="c1">// Promise {[[PromiseStatus]]: &#34;resolved&#34;, [[PromiseResult]]: 33}
</span></span></span><span class="line"><span class="cl"><span class="c1">// Promise {[[PromiseStatus]]: &#34;pending&#34;, [[PromiseResult]]: undefined}
</span></span></span><span class="line"><span class="cl"><span class="c1">// &#34;在主堆栈结束后被调用。收到的值是：33，返回的值是：34&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1">// Promise {[[PromiseStatus]]: &#34;resolved&#34;, [[PromiseResult]]: 34}
</span></span></span></code></pre></div><ul>
<li>参考:
<ul>
<li><a href="https://juejin.cn/post/7016298598883131423"  target="_blank" rel="noopener" >setTimeout+Promise+Async输出顺序？很简单呀！掘金</a></li>
</ul>
</li>
</ul>
<h3 id="问题二-promise的原理">问题二: Promise的原理</h3>
<ul>
<li>观察者模式
wip</li>
</ul>
<h3 id="问题二-promisea-规范">问题二: Promise/A+ 规范</h3>
<p>wip</p>
<ul>
<li><a href="https://tsejx.github.io/javascript-guidebook/standard-built-in-objects/control-abstraction-objects/promise-standard/"  target="_blank" rel="noopener" >Promise/A+ 规范 - JavaScript Guidebook</a></li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise"  target="_blank" rel="noopener" >Promise - JavaScript | MDN</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/any"  target="_blank" rel="noopener" >Promise.any() - JavaScript | MDN</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all"  target="_blank" rel="noopener" >Promise.all() - JavaScript | MDN</a></li>
<li><a href="https://juejin.cn/post/6844903655473152008"  target="_blank" rel="noopener" >浅析setTimeout与Promise - 掘金</a></li>
</ul>
<hr>
<h2 id="asyncawait">async/await</h2>
<h3 id="作用-1">作用</h3>
<ul>
<li>函数前面的关键字<code>async</code>有两个作用：
<ol>
<li>让这个函数总是返回一个 promise
<ul>
<li>返回普通值时将自动被包装在一个 resolved 的 promise 中。</li>
<li>也可以显式地返回一个 promise</li>
</ul>
</li>
<li>允许在该函数内使用 await。</li>
</ol>
</li>
<li>Promise 前的关键字 <code>await</code>
<ul>
<li>当 JavaScript 执行到 await 时，它会等待 Promise 的结果，</li>
<li>但这个等待过程<strong>不会阻塞</strong>主线程。JavaScript 引擎会将这个等待中的任务挂起，并允许继续处理其他同步代码或事件，直到 Promise 完成（或者超时、拒绝）。</li>
<li>这个行为不会耗费任何 CPU 资源，因为 JavaScript 引擎可以同时处理其他任务：执行其他脚本，处理事件等。</li>
</ul>
</li>
</ul>
<h3 id="实现">实现</h3>
<p>wip</p>
<h3 id="如何处理错误">如何处理错误</h3>
<p>wip</p>
<h3 id="示例-1">示例</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">f</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">results</span> <span class="o">=</span> <span class="kr">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fetch</span><span class="p">(</span><span class="nx">url1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fetch</span><span class="p">(</span><span class="nx">url2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">alert</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">f</span><span class="p">();</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">add</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">arr</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">item</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr in IIFE1&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="kr">await</span> <span class="nx">add</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr in IIFE2&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">})()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">add</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr in IIFE3&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="kr">await</span> <span class="nx">add</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr in IIFE4&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">})()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">setTimeout</span><span class="p">(()=&gt;{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;arr in setTimeout&#39;</span><span class="p">,</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span><span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// arr in IIFE1
</span></span></span><span class="line"><span class="cl"><span class="c1">// arr in IIFE3
</span></span></span><span class="line"><span class="cl"><span class="c1">// arr
</span></span></span><span class="line"><span class="cl"><span class="c1">// arr in IIFE2 2,1,3
</span></span></span><span class="line"><span class="cl"><span class="c1">// arr in IIFE4 2,1,3
</span></span></span><span class="line"><span class="cl"><span class="c1">// arr in setTimeout 2,1,3
</span></span></span></code></pre></div><h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://zh.javascript.info/async-await"  target="_blank" rel="noopener" >async/await</a></li>
</ul>
<hr>
<h2 id="异步请求的竞态问题">异步请求的竞态问题</h2>
<h3 id="场景一">场景一</h3>
<ul>
<li>描述：需多次请求某一api，响应时间不固定。需要渲染的是最后一个请求返回的结果;常见于搜索，分页，选项卡等切换的场景</li>
<li>方法一：<strong>忽略</strong>: 计数，然后判断</li>
<li>方法二：<strong>取消</strong>: 在连续的请求过程中，每当我发出一个请求，我就将之前正在 pending 的请求的 Promise reject 掉，并且该请求的 XHR 对象执行 abort()；之前的请求 如果已经有响应的不用管它，我们当前的请求的结果会覆盖它的</li>
</ul>
<h3 id="参考-2">参考:</h3>
<ul>
<li><a href="https://github.com/YuArtian/blog/blob/master/Blog/%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E5%BC%82%E6%AD%A5%E8%AF%B7%E6%B1%82%E7%9A%84%E7%AB%9E%E6%80%81%E9%97%AE%E9%A2%98.md"  target="_blank" rel="noopener" >blog/Blog/如何解决异步请求的竞态问题.md at master · YuArtian/blog</a></li>
<li><a href="https://cloud.tencent.com/developer/article/2193937"  target="_blank" rel="noopener" >如何解决前端常见的竞态问题-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html"  target="_blank" rel="noopener" >Javascript异步编程的4种方法 - 阮一峰的网络日志</a></li>
</ul>
<hr>
<h2 id="执行顺序">执行顺序</h2>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7016298598883131423"  target="_blank" rel="noopener" >setTimeout+Promise+Async输出顺序？很简单呀！- 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>PostgreSQL学习笔记</title>
      <link>https://ds63.eu.org/2024/learn_postgre/</link>
      <pubDate>Sat, 04 May 2024 13:13:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn_postgre/</guid>
      <description>浅尝辄止</description>
      <content:encoded><![CDATA[<h2 id="命令">命令</h2>
<h3 id="连接到postgresql数据库">连接到PostgreSQL数据库</h3>
<ul>
<li>
<p>一般环境：<code>psql -U &lt;your_username&gt; -d &lt;your_database_name&gt; -h {your_hostname}</code></p>
<ul>
<li>注：<code>-h</code> 用于指定数据库服务器的主机地址,缺省为localhost</li>
</ul>
</li>
<li>
<p>docker: <code>docker exec -it &lt;container_name_or_id&gt; psql -U &lt;username&gt; -d &lt;database_name&gt;</code></p>
</li>
</ul>
<h3 id="查看数据库表">查看数据库表</h3>
<ul>
<li>显示所有表: <code>\dt</code></li>
<li>显示指定表的详细信息： <code>\d+ &lt;table_name&gt;</code></li>
</ul>
<h3 id="导出">导出</h3>
<ul>
<li><code>pg_dump -U &lt;username&gt; -d &lt;database_name&gt; -h &lt;host&gt; -p &lt;port&gt; -f &lt;output_file&gt;</code>
<ul>
<li>以上命令导出的备份文件可以使用 pg_restore 工具还原到 PostgreSQL 数据库中：<code>pg_restore -U &lt;username&gt; -d &lt;database_name&gt; -h &lt;host&gt; -p &lt;port&gt; -f &lt;backup_file&gt;</code></li>
</ul>
</li>
<li>
<blockquote>
<p>-s, &ndash;schema-only            dump only the schema, no data</p>
</blockquote>
</li>
<li>
<blockquote>
<p>-t, &ndash;table=PATTERN          dump the specified table(s) only</p>
</blockquote>
</li>
</ul>
<h3 id="杂">杂</h3>
<ul>
<li>退出: <code>\q</code></li>
<li>帮助: <code>help</code></li>
</ul>
<h2 id="pycharm连接docker中的数据库">Pycharm连接Docker中的数据库</h2>
<h3 id="法一">法一：</h3>
<ol>
<li>
<p><strong>获取数据库容器的IP地址：</strong></p>
<p><code>docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' &lt;your_postgres_container_name&gt;</code></p>
</li>
<li>
<p><strong>在PyCharm中设置数据库连接：</strong> 打开PyCharm，进入 &ldquo;View&rdquo; -&gt; &ldquo;Tool Windows&rdquo; -&gt; &ldquo;Database&rdquo; 来打开数据库工具窗口。</p>
</li>
<li>
<p>在数据库工具窗口中，点击左上角的加号 (+)，选择 &ldquo;Data Source&rdquo; -&gt; &ldquo;PostgreSQL&rdquo;。</p>
</li>
<li>
<p>在 &ldquo;Data Source Properties&rdquo; 对话框中，填写以下信息：</p>
<ul>
<li>Host: 使用第2步中获得的Docker容器的IP地址。</li>
<li>Port: 默认情况下，PostgreSQL使用端口5432。</li>
<li>Database: 你的数据库名称。</li>
<li>User: 你的数据库用户名。</li>
<li>Password: 你的数据库密码。</li>
</ul>
</li>
</ol>
<p>注：我使用以上方法，未成功，在参考<a href="https://www.volcengine.com/theme/5098669-P-7-1"  target="_blank" rel="noopener" >PyCharm：无法连接到Docker容器中的postgres-db</a>后，使用法二成功连接</p>
<h3 id="法二">法二</h3>
<ol>
<li>修改配置，将容器内的端口映射到主机端口，例：</li>
</ol>
<pre tabindex="0"><code># 连接到主机的 16432 端口时，流量将被映射到容器内部的 5432 端口
    ports:
      - &#34;15432:5432&#34;
</code></pre><ol start="2">
<li>同法一</li>
<li>同法一</li>
<li>同法一，此处的Host为<code>localhost</code>,端口为15432</li>
</ol>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://www.volcengine.com/theme/5098669-P-7-1"  target="_blank" rel="noopener" >PyCharm：无法连接到Docker容器中的postgres-db</a></li>
<li><a href="https://github.com/neodb-social/neodb/blob/main/doc/install-docker.md"  target="_blank" rel="noopener" >neodb/doc/install-docker.md</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>React中的导入导出</title>
      <link>https://ds63.eu.org/2024/import-and-export-in-react/</link>
      <pubDate>Sun, 28 Apr 2024 00:20:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/import-and-export-in-react/</guid>
      <description>The requested module does not provide an export named</description>
      <content:encoded><![CDATA[<p><strong>之前对React中的import和export处在一知半解的情况，计划通过此篇来彻底弄清楚。</strong></p>
<h2 id="案例">案例</h2>
<p>在<code>src/components/Section</code>这个文件夹中有两个文件</p>
<pre tabindex="0"><code>ContextSection.jsx  
FileSection.jsx  
</code></pre><p>其中每个文件都类似于</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">ContextSection</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>我希望写一个<code>index.js</code>来统一export，一开始我的写法是</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="o">*</span> <span class="nx">from</span> <span class="s1">&#39;./ContextSection&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="o">*</span> <span class="nx">from</span> <span class="s1">&#39;./FileSection&#39;</span><span class="p">;</span>
</span></span></code></pre></div><p>我在<code>'/src/components/Session/index.js'</code>是这样import的</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ContextSession</span><span class="p">,</span> <span class="nx">FileSession</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;/src/components/Session&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>报错是：
Uncaught SyntaxError: The requested module &lsquo;/src/components/Session/index.js&rsquo; does not provide an export named &lsquo;ContextSession&rsquo;</p>
<p>我直接去谷歌报错信息,但查找到的内容都有点牛头不对马嘴。最后是靠好好地看了遍<a href="https://react.dev/learn/importing-and-exporting-components"  target="_blank" rel="noopener" >Importing and Exporting Components – React</a>才猛然意识到自己哪里错了。</p>
<table>
<thead>
<tr>
<th>Syntax</th>
<th>Export statement</th>
<th>Import statement</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default</td>
<td><code>export default function Button() {}</code></td>
<td><code>import Button from './Button.js';</code></td>
</tr>
<tr>
<td>Named</td>
<td><code>export function Button() {}</code></td>
<td><code>import { Button } from './Button.js';</code></td>
</tr>
</tbody>
</table>
<p>最后我的解决方法是，修改<code>index.js</code>为</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="p">{</span> <span class="k">default</span> <span class="nx">as</span> <span class="nx">ContextSection</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;./ContextSection&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="p">{</span> <span class="k">default</span> <span class="nx">as</span> <span class="nx">FileSection</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;./FileSection&#39;</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="进一步">进一步</h2>
<p><code>export { default as FileSection } from './FileSection';</code> 和<code>export FileSection  from './FileSection';</code>的区别在哪呢？以下是ChatGPT的回答：</p>
<p>这两种写法在导出默认导出时有所不同：</p>
<ol>
<li>
<p><code>export { default as FileSection } from './FileSection';</code></p>
<p>这种写法使用了命名导出（named export）的语法，并且指定了导出的名称为 <code>FileSection</code>。它将 <code>./FileSection</code> 中的默认导出（使用 <code>export default</code> 导出的内容）导出为 <code>FileSection</code>。在其他文件中引用时，需要使用相同的名称来导入，例如 <code>import { FileSection } from './FileSection';</code>。</p>
</li>
<li>
<p><code>export FileSection from './FileSection';</code></p>
<p>这种写法是 ES2021 的新语法，称为<strong>export from</strong>语法，它直接导出了 <code>./FileSection</code> 中的默认导出，而无需指定名称。在其他文件中引用时，可以使用任何名称来导入，例如 <code>import MyFileSection from './FileSection';</code>。在这种情况下，导入的名称不需要与导出的名称相同。</p>
</li>
</ol>
<p>综上所述，第一种写法强制使用指定的导出名称，而第二种写法更加灵活，允许导入时使用任意名称。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://react.dev/learn/importing-and-exporting-components"  target="_blank" rel="noopener" >Importing and Exporting Components – React</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>patch-package使用</title>
      <link>https://ds63.eu.org/2024/the-use-of-patch-package/</link>
      <pubDate>Mon, 08 Apr 2024 13:12:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/the-use-of-patch-package/</guid>
      <description>patch everything</description>
      <content:encoded><![CDATA[<h2 id="背景">背景</h2>
<p>需要对第三方npm依赖包进行定制化修改</p>
<h2 id="准备">准备</h2>
<ul>
<li>安装: <code>npm i patch-package</code></li>
<li>修改package.json
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// this will auto excute npx patch-package after npm install
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="s2">&#34;scripts&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;postinstall&#34;</span><span class="p">:</span> <span class="s2">&#34;npx patch-package&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h2 id="使用">使用</h2>
<ol>
<li>make changes to the files of a particular package in your node_modules folder</li>
<li><code>npx patch-package ${package-name}</code>，例如：<code>npx patch-package @aws-sdk/lib-storage</code></li>
<li>if you want to apply patches, run <code>npx patch-package</code></li>
</ol>
<h2 id="benefits-of-patching-over-forking">Benefits of patching over forking</h2>
<ul>
<li>Sometimes forks need extra build steps, e.g. with react-native for Android. Forget that noise.</li>
<li>Get told in big red letters when the dependency changed and you need to check that your fix is still valid.</li>
<li>Keep your patches colocated with the code that depends on them.</li>
<li>Patches can be reviewed as part of your normal review process, forks probably can&rsquo;t</li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.npmjs.com/package/patch-package"  target="_blank" rel="noopener" >patch-package - npm</a></li>
<li><a href="https://juejin.cn/post/6949906434997878791"  target="_blank" rel="noopener" >修改 node_modules 里文件的正确姿势 - 掘金</a></li>
<li><a href="https://juejin.cn/post/7094556624387309582?from=search-suggest"  target="_blank" rel="noopener" >如何优雅的修改node_modules依赖源码 - 掘金</a></li>
<li><a href="https://dev.to/zhnedyalkow/the-easiest-way-to-patch-your-npm-package-4ece"  target="_blank" rel="noopener" >The easiest way to patch your npm package when there is a 🐛 - DEV Community</a></li>
<li><a href="https://juejin.cn/post/7356534347509497919"  target="_blank" rel="noopener" >奇技淫巧：如何修改第三方npm包？大家好，我是老纪。在开发过程中发现npm包的Bug，首先向原作者提交issue或For - 掘金</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>CSS知识点整理</title>
      <link>https://ds63.eu.org/2024/css_points/</link>
      <pubDate>Sat, 06 Apr 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/css_points/</guid>
      <description>自己学习过程中整理的关于CSS的知识点</description>
      <content:encoded><![CDATA[<h2 id="如何理解css">如何理解css</h2>
<blockquote>
<p>I like to think of CSS as a collection of layout modes. Each layout mode is an algorithm that can implement or redefine each CSS property. We provide an algorithm with our CSS declarations (key/value pairs), and the algorithm decides how to use them.</p>
<p>In other words, the CSS we write is an input for these algorithms, like arguments passed to a function. If we want to truly feel comfortable with CSS, it&rsquo;s not enough to learn the properties; we have to learn how the algorithms use these properties.</p>
</blockquote>
<p>参考<a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/"  target="_blank" rel="noopener" >An Interactive Guide to Flexbox in CSS</a></p>
<hr>
<h2 id="常见的css布局单位">常见的css布局单位</h2>
<ul>
<li>px: 绝对单位</li>
<li>em: 相对单位
<ul>
<li>font-size：相对于父元素字体</li>
<li>width: 相对于当前元素字体</li>
</ul>
</li>
<li>rem(root em): 相对单位
<ul>
<li>相对于根元素，也就是<code>html</code></li>
</ul>
</li>
<li><code>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;</code></li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://www.explainthis.io/zh-hant/swe/css-px-em-rem-differences"  target="_blank" rel="noopener" >CSS 中有哪些單位? 該如何使用?｜ExplainThis</a></li>
<li><a href="https://www.cnblogs.com/kidney/p/6692312.html"  target="_blank" rel="noopener" >1px 究竟是多大 - {Bison} - 博客园</a></li>
</ul>
<hr>
<h2 id="viewport">viewport</h2>
<p>wip</p>
<ul>
<li><a href="https://www.kyleblog.cn/posts/viewport"  target="_blank" rel="noopener" >viewport配置里的width=device-width和initial-scale=1.0到底是干嘛的 - KyleBlog.cn</a></li>
</ul>
<hr>
<h2 id="orientation">orientation</h2>
<ul>
<li>
<p>portrait: The viewport is in a portrait orientation, i.e., the height is greater than or equal to the width.</p>
</li>
<li>
<p>landscape: The viewport is in a landscape orientation, i.e., the width is greater than the height.</p>
</li>
<li>
<p>参考: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation"  target="_blank" rel="noopener" >orientation - CSS: Cascading Style Sheets | MDN</a></p>
</li>
</ul>
<hr>
<h2 id="visibility">Visibility</h2>
<ul>
<li>visible</li>
<li>hidden</li>
<li>collapse: 只对 table 对象起作用，能移除行或列但不会影响表格的布局。如果这个值用在 table 以外的对象上则表现为 hidden</li>
<li>inherit</li>
</ul>
<hr>
<h2 id="display">Display</h2>
<h3 id="分类">分类</h3>
<ul>
<li>none: 元素不可见，并且不为其保留相应的位置</li>
<li>block: 表现为一个块级元素（一般情况下独占一行） <code>&lt;div&gt;、 &lt;h1&gt;、&lt;p&gt;</code></li>
<li>inline: 表现为一个行级元素（一般情况下不独占一行）<code>&lt;a&gt;、&lt;img&gt;、&lt;span&gt;</code></li>
<li>inline-block: 结合了行內元素和塊級元素的特點，會像 inline 元素一樣的同行排列，但同時擁有 block 元素可以設定寬高的特性。</li>
</ul>
<h3 id="visibilityhidden-vs-displaynone-vs-opacity0">visibility:hidden vs display:none vs opacity:0</h3>
<ul>
<li><code>visibility: hidden;</code>: 隐藏元素，但是它仍然占用布局中的空间。如果隐藏框的子元素的可见性设置为“可见”，则它们将是可见的。</li>
<li><code>display: none;</code>: 关闭显示并从文档中完全删除该元素。即使它的HTML仍在源代码中，它也不占用任何空间。即使所有子元素的显示属性均设置为none，也将关闭其显示。</li>
<li>具有<code>opacity: 0</code>的元素是可以互动的，因为它们<strong>实际上是可见</strong>的，只是非常透明。opacity 属性并不指定一个元素的可见性——它只指定透明度</li>
<li>参考: <a href="https://www.freecodecamp.org/chinese/news/css-display-none-and-visibility-hidden-the-difference/"  target="_blank" rel="noopener" >CSS display:none 和 visibility:hidden 的区别</a></li>
</ul>
<hr>
<h2 id="bfc-vs-ifc">BFC v.s IFC</h2>
<h3 id="bfc">BFC</h3>
<ul>
<li>块级格式上下文 (Block Formatting Context)</li>
<li>概念
<ol>
<li>一个独立的渲染区域，只有Block-level box参与</li>
<li>规定了内部的Block-level Box如何布局，并且与这个区域外部毫不相干。</li>
</ol>
</li>
<li>规则
<ol>
<li>内部的Box会在垂直方向，一个接一个地放置</li>
<li>BFC就是页面上的一个隔离的独立容器，容器里面的子元素不会影响到外面的元素。反之也如此。</li>
</ol>
</li>
<li>产生
<ol>
<li>overflow的值不为visible。(这个是最推荐开启bfc的,副作用最小)</li>
<li>position的值不为relative和static。</li>
<li>display的值为table-cell, table-caption, inline-block中的任何一个。</li>
</ol>
</li>
<li>使用场景
<ol>
<li>自适应两栏布局</li>
<li>清除内部浮动</li>
<li>防止margin重叠</li>
<li>实现更健壮、更智能的自适应布局。</li>
</ol>
</li>
</ul>
<h3 id="ifc">IFC</h3>
<ul>
<li>内联格式化上下文（inline formatting context）</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_display/Block_formatting_context"  target="_blank" rel="noopener" >区块格式化上下文 - CSS：层叠样式表 | MDN</a></li>
<li><a href="https://github.com/YvetteLau/Step-By-Step/issues/15"  target="_blank" rel="noopener" >什么是BFC？BFC的规则是什么？如何创建BFC？ · Issue #15 · YvetteLau/Step-By-Step</a></li>
</ul>
<hr>
<h2 id="盒模型">盒模型</h2>
<h3 id="四部分组成">四部分组成</h3>
<ol>
<li>元素内容（content）：</li>
<li>内边距（padding）</li>
<li>边框（border）</li>
<li>外边距（margin）</li>
</ol>
<h3 id="分类-1">分类</h3>
<ol>
<li>W3C 标准盒子模型: width/height 只是内容高度</li>
<li>IE 怪异盒子模型: width/height 包含了 padding和 border</li>
</ol>
<h3 id="box-sizing">box-sizing</h3>
<ul>
<li>语法: <code>box-sizing: content-box|border-box|inherit:</code></li>
</ul>
<hr>
<h2 id="css中可以和不可以继承的属性">CSS中可以和不可以继承的属性</h2>
<ul>
<li>具体参见<a href="https://www.cnblogs.com/thislbq/p/5882105.html"  target="_blank" rel="noopener" >CSS中可以和不可以继承的属性 - KerwinLee - 博客园</a></li>
<li>基本原则:
<ul>
<li>文本属性和字体属性通常是可以继承的: font-size, font-weight, line-height, color, cursor,letter-spacing等</li>
<li>涉及到盒模型属性，布局属性(例如，display, position)，背景属性普遍是不能继承: display, margin，border，padding，height等</li>
<li>需要特别注意的是元素可见性属性(visibility)是可以继承的</li>
</ul>
</li>
<li>验证: 开发者工具，选择具体元素并查看元素选项，若为灰色则不可继承</li>
<li>参考
<ul>
<li><a href="https://juejin.cn/post/7065209860400349191"  target="_blank" rel="noopener" >如何确定一个 CSS 属性是否可以被继承基本原则 文本属性和字体方属性通常是可以继承的，盒模型属性，布局属性，背景属性普 - 掘金</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="优先级">优先级</h2>
<h3 id="选择器">选择器</h3>
<ul>
<li>id选择器: <code>#id{}</code></li>
<li>类选择器: <code>.class{}</code></li>
<li>属性选择器: <code>a[href=&quot;ds63.eu.org&quot;]{}</code></li>
<li>伪类选择器: <code>::before{}</code></li>
<li>标签选择器: <code>span{}</code></li>
<li>通配选择器: <code>*{}</code></li>
</ul>
<h3 id="规则">规则</h3>
<ol>
<li>最近的祖先样式比其他祖先样式优先级高</li>
<li>&ldquo;直接样式&quot;比&quot;祖先样式&quot;优先级高</li>
<li>优先级顺序: 内联样式 &gt; ID 选择器 &gt; 类选择器 = 属性选择器 = 伪类选择器 &gt; 标签选择器 = 伪元素选择器</li>
<li>计算选择符中 ID 选择器的个数（a），计算选择符中类选择器、属性选择器以及伪类选择器的个数之和（b），计算选择符中标签选择器和伪元素选择器的个数之和（c）。按 a、b、c 的顺序依次比较大小，大的则优先级高，相等则比较下一个。若最后两个的选择符中 a、b、c 都相等，则按照&quot;就近原则&quot;来判断。</li>
<li>属性后插有<code>!important</code>的属性拥有最高优先级。若同时插有 !important，则再利用规则 3、4 判断优先级</li>
</ol>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://www.runoob.com/w3cnote/css-style-priority.html"  target="_blank" rel="noopener" >CSS 样式优先级 | 菜鸟教程</a></li>
<li><a href="https://www.explainthis.io/zh-hans/swe/css-specificity"  target="_blank" rel="noopener" >请说明 CSS 选择器的优先级｜ExplainThis</a></li>
</ul>
<hr>
<h2 id="position">position</h2>
<h3 id="static"><code>static</code></h3>
<p>默认值。没有定位，元素出现在正常的流中（忽略top,bottom,left,right,z-index声明）。</p>
<h3 id="absolute"><code>absolute</code></h3>
<ul>
<li>生成绝对定位的元素，相对于<strong>值不为static的第一个父元素的paddingbox</strong>进行定位</li>
<li>在父元素没有设置相对定位或绝对定位的情况下，元素相对于根元素定位（即html元素）</li>
<li>元素会脱离文档流</li>
</ul>
<h3 id="fixed"><code>fixed</code></h3>
<ul>
<li>生成绝对定位的元素，相对于浏览器窗口进行定位。</li>
</ul>
<h3 id="relative"><code>relative</code></h3>
<ul>
<li>生成相对定位的元素，相对于<strong>其元素本身所在正常位置</strong>进行定位。</li>
</ul>
<h3 id="inherit"><code>inherit</code></h3>
<ul>
<li>规定从父元素继承position属性的值。</li>
</ul>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://www.runoob.com/w3cnote/css-position-static-relative-absolute-fixed.html"  target="_blank" rel="noopener" >CSS position 相对定位和绝对定位 | 菜鸟教程</a></li>
</ul>
<hr>
<h2 id="伪类与伪元素">伪类与伪元素</h2>
<h3 id="伪类">伪类</h3>
<ul>
<li><code>:hover</code></li>
<li><code>:focus</code></li>
<li><code>:first-child</code></li>
<li><code>:nth-child(n)</code></li>
<li>LVHA
<ol>
<li><code>:link</code></li>
<li><code>:visited</code></li>
<li><code>:hover</code></li>
<li><code>:active</code></li>
</ol>
</li>
</ul>
<h3 id="伪元素">伪元素</h3>
<ul>
<li>用户无法直接选中或复制 CSS 伪元素: 因为伪元素生成的内容并不是真正的 DOM 元素，而是由浏览器在渲染时动态插入的,这也是伪元素为什么叫“伪”元素。</li>
<li><code>::before</code>,<code>::after</code>
<ul>
<li>Accessibility: Using a ::before pseudo-element to add content is <strong>discouraged</strong>, as it is not reliably accessible to screen readers.</li>
<li><code>content</code>
<ul>
<li>属性:
<ul>
<li><code>url</code></li>
<li><code>counter</code></li>
<li><code>attr(X)</code>: 将元素的 X 属性以字符串形式返回。如果该元素没有 X 属性，则返回一个空字符串</li>
</ul>
</li>
<li>示例
<ul>
<li><code>content: url(http://www.mozilla.org/favicon.ico) &quot; MOZILLA: &quot;;</code></li>
<li><code>content: &quot; (&quot; attr(id) &quot;)&quot;;</code> 这里的id即该元素的id</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><code>::first-letter</code></li>
<li><code>::first-line</code></li>
<li><code>::selection</code>: 	选择用户选择的元素部分。</li>
</ul>
<h3 id="参考-4">参考</h3>
<ul>
<li><a href="https://www.w3school.com.cn/css/css_pseudo_classes.asp"  target="_blank" rel="noopener" >CSS 伪类</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/:link"  target="_blank" rel="noopener" >:link - CSS：层叠样式表 | MDN</a></li>
<li><a href="https://www.w3school.com.cn/css/css_pseudo_elements.asp"  target="_blank" rel="noopener" >CSS 伪元素</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::before"  target="_blank" rel="noopener" >::before - CSS: Cascading Style Sheets | MDN</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/content"  target="_blank" rel="noopener" >content - CSS：层叠样式表 | MDN</a></li>
</ul>
<hr>
<h2 id="letter-spacing">letter-spacing</h2>
<ul>
<li>用于设置文本字符的间距表现</li>
<li>可继承</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing"  target="_blank" rel="noopener" >letter-spacing - CSS: Cascading Style Sheets | MDN</a></li>
</ul>
<h2 id="grid">GRID</h2>
<p>wip</p>
<hr>
<h2 id="transforms">Transforms</h2>
<ul>
<li>We can use translate to shift an item along in either axis:
<ul>
<li>x moves side to side, y moves up and down.</li>
<li>Positive values move down and to the right. Negative values move up and to the left.</li>
</ul>
</li>
<li>the item&rsquo;s in-flow position doesn&rsquo;t change</li>
<li><code>calc</code>: 示例： <code>transform: translateX(calc(15% + -8px));</code></li>
<li>参考: <a href="https://www.joshwcomeau.com/css/transforms/"  target="_blank" rel="noopener" >CSS Transforms tutorial</a></li>
</ul>
<hr>
<h2 id="animation">animation</h2>
<ul>
<li>示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">cylon_eye</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">animation</span><span class="p">:</span> <span class="mi">4</span><span class="kt">s</span> <span class="kc">linear</span> <span class="mi">0</span><span class="kt">s</span> <span class="kc">infinite</span> <span class="kc">alternate</span> <span class="n">move_eye</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">keyframes</span> <span class="nt">move_eye</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">from</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-left</span><span class="p">:</span> <span class="mi">-20</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="nt">to</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-left</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div></li>
<li>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation"  target="_blank" rel="noopener" >animation - CSS：层叠样式表 | MDN</a></li>
</ul>
<hr>
<h2 id="媒体查询">媒体查询</h2>
<ul>
<li>语法: <code>@media (min-width: 30em) and (orientation: landscape) { ... }</code></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_media_queries/Using_media_queries"  target="_blank" rel="noopener" >使用媒体查询 - CSS：层叠样式表 | MDN</a></li>
</ul>
<hr>
<h2 id="预处理器">预处理器</h2>
<ul>
<li>LESS</li>
<li>SCSS</li>
<li>PostCSS</li>
</ul>
<h3 id="lesssass解决了什么问题">less/sass解决了什么问题</h3>
<p>wip</p>
<h3 id="css-in-js-与-less-sass预处理器的好处">css in js 与 less sass预处理器的好处</h3>
<p>wip</p>
<ul>
<li><a href="http://blog.fantasy.codes/css/2021/09/10/css-in-js-debet/"  target="_blank" rel="noopener" >CSS-in-JS 技术解惑</a></li>
</ul>
<hr>
<h2 id="现代化-css-开发流程">现代化 CSS 开发流程</h2>
<ul>
<li>借助@mixin、@extend等预处理器提供的方法，可以复用 css 代码片段，甚至在 css 中写一些逻辑。</li>
<li>借助autoprefixer、px2rem等 postcss 工具，不需要写繁琐的前缀和单位转换。</li>
<li>借助css module、css scoped等工具，不用考虑样式冲突，以至于不用过多地考虑命名了。</li>
<li>借助BEM命名规范，解决命名难</li>
<li>参考
<ul>
<li><a href="https://www.shymean.com/article/%E5%85%B3%E4%BA%8ETailwindCSS%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83"  target="_blank" rel="noopener" >关于TailwindCSS的一些思考 | ShyMean</a></li>
<li><a href="https://juejin.cn/post/6844903672162304013"  target="_blank" rel="noopener" >CSS — BEM 命名规范Bem 是块（block）、元素（element）、修饰符（modifier）的简写，由 Y - 掘金</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="tailwindcss">TailwindCSS</h2>
<ul>
<li>工作原理：扫描所有文件的类名，生成相应的样式，然后将它们写入静态 CSS 文件。</li>
<li>JIT 引擎（Just-In-Time）:在编译过程才去扫描html 文件，在这个过程中去识别使用了哪些类名，然后才生成对应的样式</li>
<li>缺点:
<ol>
<li>每个标签的 class 都很长，语义化的可读性；</li>
<li>如果全都使用原子类来构建页面，则维护起来是很麻烦的</li>
<li>选择器嵌套、后代选择器等 css 的特点看起来也是不太好用上了</li>
</ol>
</li>
<li>优点:
<ol>
<li>通过自定义原子类，能约定好设计规范,规范好标题字号、颜色，这个盒子内边距、外边距之类的属性</li>
<li>通过<a href="https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply"  target="_blank" rel="noopener" >@apply</a>可以将一堆原子类合并到一个独立的类名中,就能结合原子类的样式复用和语义化类名容易维护的优点,由此一定程度上解决缺点1</li>
<li>针对维护麻烦的问题，可以将常用组件进行封装, 由此一定程度上解决缺点2</li>
</ol>
</li>
<li>缺点:
<ol>
<li>每个标签的 class 都很长，语义化的可读性；</li>
<li>如果全都使用原子类来构建页面，则维护起来是很麻烦的</li>
<li>选择器嵌套、后代选择器等 css 的特点看起来也是不太好用上了</li>
</ol>
</li>
<li>参考
<ul>
<li><a href="https://michaeljier.cn/blog/diving-into-tailwindcss"  target="_blank" rel="noopener" >深入浅出 tailwindcss</a></li>
<li><a href="https://www.shymean.com/article/%E5%85%B3%E4%BA%8ETailwindCSS%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83"  target="_blank" rel="noopener" >关于TailwindCSS的一些思考 | ShyMean</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="scroll-timeline">scroll-timeline</h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-timeline"  target="_blank" rel="noopener" >scroll-timeline - CSS: Cascading Style Sheets | MDN</a></p>
<hr>
<h2 id="问答题">问答题</h2>
<h3 id="显示小于12px文字">显示小于12px文字</h3>
<ol>
<li>使用transform: scale()</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">small-text</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">transform</span><span class="p">:</span> <span class="nb">scale</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">transform-origin</span><span class="p">:</span> <span class="kc">left</span> <span class="kc">top</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="2">
<li>使用-webkit-text-size-adjust</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">small-text</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-webkit-</span><span class="n">text-size-adjust</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="3">
<li>使用vw单位</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">small-text</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.625</span><span class="kt">vw</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>参考: <a href="https://juejin.cn/post/7419532688972464137"  target="_blank" rel="noopener" >前端面试题，显示小于12px文字Chrome显示小于12px文字 难度: 困难 公司: 百度 标签: CSS 字体大小 - 掘金</a></li>
</ul>
<h3 id="css画三角形">css画三角形</h3>
<ul>
<li>等腰三角形</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nt">style</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">filled-triangle</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">width</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">height</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-bottom</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">cyan</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-top</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-left</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-right</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;/</span><span class="nt">style</span><span class="o">&gt;</span>
</span></span></code></pre></div><ul>
<li>参考: <a href="https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/518"  target="_blank" rel="noopener" >第207题：CSS 如何实现一个三角形？ · Issue #518 · Advanced-Frontend/Daily-Interview-Question</a></li>
</ul>
<h3 id="如何实现水平垂直居中">如何实现水平垂直居中</h3>
<ol>
<li><strong>Flexbox</strong>
适用于块级容器中的元素垂直居中。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">justify-content</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span> <span class="c">/* 水平居中 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span> <span class="c">/* 垂直居中 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span> <span class="c">/* 确保容器有高度 */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="2">
<li><strong>Grid Layout</strong></li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">place-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span> <span class="c">/* 同时垂直和水平居中 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="3">
<li><strong>使用<code>line-height</code>（适用于单行文本）</strong>
如果只是文本，使用<code>line-height</code>与<code>height</code>相等可以达到垂直居中效果。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">line-height</span><span class="p">:</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span> <span class="c">/* 与容器高度相同 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span> <span class="c">/* 水平居中 */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="4">
<li><strong>绝对定位 + 负边距</strong>
适用于已知元素宽高的情况下：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">element</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">left</span><span class="p">:</span> <span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">transform</span><span class="p">:</span> <span class="nb">translate</span><span class="p">(</span><span class="mi">-50</span><span class="kt">%</span><span class="p">,</span> <span class="mi">-50</span><span class="kt">%</span><span class="p">);</span> <span class="c">/* 通过transform偏移居中 */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="5">
<li><strong><code>table</code>布局</strong>
适用于需要兼容旧版浏览器的场景：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">table</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">element</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">table-cell</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">vertical-align</span><span class="p">:</span> <span class="kc">middle</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="6">
<li><strong>CSS Variables（动态适应不同的场景）</strong>
可以结合Flexbox和Grid等方式，动态控制居中的方法。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">:</span><span class="nd">root</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--container-height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">justify-content</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">container</span><span class="o">-</span><span class="n">height</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>参考: <a href="https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/515"  target="_blank" rel="noopener" >第204题：如何实现元素的水平垂直居中？ · Issue #515 · Advanced-Frontend/Daily-Interview-Question</a></li>
</ul>
<h3 id="脱离文档流">脱离文档流</h3>
<ul>
<li>含义:
<ul>
<li>元素脱离文档流之后，将不再在文档流中占据空间，而是处于浮动状态（可以理解为漂浮在文档流的上方）。脱离文档流的元素的定位基于正常的文档流，当一个元素脱离文档流后，依然在文档流中的其他元素将忽略该元素并填补其原先的空间。</li>
</ul>
</li>
<li>方法
<ol>
<li>float</li>
<li>absolute</li>
<li>fixed</li>
</ol>
</li>
<li>参考: <a href="https://www.cnblogs.com/Tony-Ding/articles/11928919.html"  target="_blank" rel="noopener" >【css】脱离文档流的三种方法 - 十八力丁 - 博客园</a></li>
</ul>
<h3 id="如何实现响应式">如何实现响应式</h3>
<ol>
<li>减少使用绝对单位，而是使用相对单位</li>
<li>媒体查询</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images"  target="_blank" rel="noopener" >响应式图片 - 学习 Web 开发 | MDN</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design"  target="_blank" rel="noopener" >响应式设计 - 学习 Web 开发 | MDN</a></li>
</ol>
<h3 id="如何实现固定宽高比">如何实现固定宽高比</h3>
<ul>
<li>参考: <a href="https://juejin.cn/post/6844904070679887886"  target="_blank" rel="noopener" >面试官：CSS如何实现固定宽高比 ？ - 掘金</a></li>
</ul>
<h3 id="实现三栏布局">实现三栏布局</h3>
<p>wip</p>
<h3 id="写个css当文本没有超过容器宽度时居中显示超过宽度则换行并左对齐displaytabel-cell或者widthfit-content但是忘了">写个css，当文本没有超过容器宽度时居中显示，超过宽度则换行，并左对齐（display:tabel-cell或者width:fit-content，但是忘了）</h3>
<p>wip</p>
<h3 id="用css实现一个模态窗口要从窗口下面向上弹的动画">用css实现一个模态窗口，要从窗口下面向上弹的动画</h3>
<p>wip</p>
<h3 id="如何保证让contextmenu出现在可视区域如何打开自己的contextmenu">如何保证让contextmenu出现在可视区域，如何打开自己的contextmenu</h3>
<p>wip</p>
<hr>
<h2 id="参考-5">参考</h2>
<ul>
<li><a href="https://segmentfault.com/a/1190000022021557#item-11"  target="_blank" rel="noopener" >104道 CSS 面试题，助你查漏补缺 - 前端笔记本 - SegmentFault 思否</a></li>
<li><a href="https://bgww.apachecn.org/CSS-%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%88%E5%B1%B1%E6%9C%88%EF%BC%89/"  target="_blank" rel="noopener" >CSS 面试题（山月） - 【布客】八股文知识库</a></li>
<li><a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/"  target="_blank" rel="noopener" >An Interactive Guide to Flexbox in CSS</a></li>
<li><a href="https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html"  target="_blank" rel="noopener" >Flex 布局教程：语法篇 - 阮一峰的网络日志</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/91470473"  target="_blank" rel="noopener" >flex 笔记（血与泪） - 知乎</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Mysql常用命令</title>
      <link>https://ds63.eu.org/2024/mysql_cheatsheet/</link>
      <pubDate>Thu, 04 Apr 2024 13:13:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/mysql_cheatsheet/</guid>
      <description>a cheatsheet of mysql</description>
      <content:encoded><![CDATA[<h2 id="登录">登录</h2>
<ul>
<li><code>sudo mysql -u root -p</code></li>
<li>注：
<ul>
<li>首次安装完成后，直接回车即可</li>
<li><code>-p</code> 提示用户输入密码</li>
<li><code>-h</code> 指定要连接的主机名或IP地址</li>
</ul>
</li>
</ul>
<h2 id="修改原始密码">修改原始密码</h2>
<ul>
<li><code>ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by 'my-secret-password';</code></li>
</ul>
<h2 id="重置密码">重置密码</h2>
<ul>
<li>场景：忘记了已设置的密码</li>
<li>步骤:
<ol>
<li><code>sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf</code></li>
<li>添加 <code>skip-grant-tables</code></li>
<li>重启mysql：<code>service mysql restart</code></li>
<li>登录 <code>mysql</code></li>
<li><code>FLUSH PRIVILEGES;</code></li>
<li><code>ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';</code></li>
<li>再次修改<code>/etc/mysql/mysql.conf.d/mysqld.cnf</code>,将<code>skip-grant-tables</code>注释掉</li>
</ol>
</li>
</ul>
<h2 id="新增用户">新增用户</h2>
<ul>
<li><code>CREATE USER '新用户名'@'域名' IDENTIFIED BY '密码';</code></li>
<li>注：如果无<code>IDENTIFIED BY '密码'</code>,则不会设置密码</li>
</ul>
<h2 id="权限">权限</h2>
<ul>
<li>赋予权限:
<ul>
<li><code>GRANT CREATE,SELECT ON database_name.* TO 'username'@'domain';</code></li>
<li>grant file on <em>.</em> to &lsquo;root&rsquo;@&rsquo;%&rsquo;;</li>
</ul>
</li>
<li>赋予所有权限：<code>GRANT ALL PRIVILEGES ON *.* TO 'keanu'@'%' WITH GRANT OPTION;</code></li>
<li>撤销权限: <code>REVOKE INSERT ON database_name.* FROM 'username'@'domain';</code></li>
<li>刷新： <code>flush privileges;</code></li>
</ul>
<h2 id="host-xxxxxxxxxxx-is-not-allowed-to-connect-to-this-mysql-server">Host &lsquo;xxx.xx.xxx.xxx&rsquo; is not allowed to connect to this MySQL server</h2>
<ul>
<li><code>GRANT ALL PRIVILEGES ON *.* TO '用户名'@'%' WITH GRANT OPTION;</code></li>
<li>参考<a href="https://stackoverflow.com/questions/1559955/host-xxx-xx-xxx-xxx-is-not-allowed-to-connect-to-this-mysql-server"  target="_blank" rel="noopener" >Host &lsquo;xxx.xx.xxx.xxx&rsquo; is not allowed to connect to this MySQL server - Stack Overflow</a></li>
</ul>
<h2 id="linux---how-to-bind-mysql-server-to-more-than-one-ip-address">linux - How to bind MySQL server to more than one IP address</h2>
<ul>
<li><code>sudo sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mysql/mysql.conf.d/mysqld.cnf</code></li>
<li>参考<a href="https://serverfault.com/questions/139323/how-to-bind-mysql-server-to-more-than-one-ip-address/139324#139324"  target="_blank" rel="noopener" >linux - How to bind MySQL server to more than one IP address? - Server Fault</a></li>
</ul>
<h2 id="sql-mode">sql mode</h2>
<ol>
<li>查看当前模式: <code>SELECT @@sql_mode;</code></li>
<li>更改配置: <code>SET PERSIST sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));</code></li>
<li>注：
<ul>
<li>直接修改，类似<code>set sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'</code>，重启后配置会还原</li>
<li>报错：<code>Access denied for user 'root'@'localhost' (using password: YES)</code>,权限不够，改为在root用户下执行即可。</li>
</ul>
</li>
</ol>
<h2 id="查看">查看</h2>
<ul>
<li>配置: <code>sudo cat /etc/mysql/mysql.conf.d/mysqld.cnf</code></li>
<li>当前用户: <code>select user();</code></li>
<li>数据库： <code>show databases;</code></li>
<li>表： <code>show tables;</code></li>
<li>变量配置：例：<code>show variables like '%secure%'\G</code></li>
<li><code>my.cnf</code>配置文件：参考<a href="https://blog.csdn.net/yerenyuan_pku/article/details/109919451"  target="_blank" rel="noopener" >Linux下MySQL的配置文件（my.cnf）的存放路径_linux my.cnf 位置-CSDN博客</a></li>
</ul>
<h2 id="导出导入">导出导入</h2>
<ul>
<li>导出：<code>select * from scott.emp into outfile '/data/mysql/emp.txt' fields terminated by ',' optionally enclosed by '&quot;' lines terminated by '\n' ;</code></li>
<li>导入：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">hr</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">create</span><span class="w"> </span><span class="k">table</span><span class="w"> </span><span class="n">hr</span><span class="p">.</span><span class="n">emp</span><span class="w"> </span><span class="k">like</span><span class="w"> </span><span class="n">scott</span><span class="p">.</span><span class="n">emp</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LOAD</span><span class="w"> </span><span class="n">DATA</span><span class="w"> </span><span class="k">INFILE</span><span class="w"> </span><span class="s1">&#39;/data/mysql/emp.txt&#39;</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">hr</span><span class="p">.</span><span class="n">emp</span><span class="w"> </span><span class="n">FIELDS</span><span class="w"> </span><span class="k">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;,&#39;</span><span class="w"> </span><span class="k">ENCLOSED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;&#34;&#39;</span><span class="w"> </span><span class="k">LINES</span><span class="w"> </span><span class="k">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w"> </span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="列宽">列宽</h2>
<ul>
<li><code>\G</code>: 选项能够将查询结果以垂直方式展示，而不是默认的水平方式。这种方式下，每个字段值都会单独占据一行，使得每个字段的宽度都能够根据内容自动调整。</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Linux常用命令</title>
      <link>https://ds63.eu.org/2024/linux_cheatsheet/</link>
      <pubDate>Wed, 03 Apr 2024 23:15:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/linux_cheatsheet/</guid>
      <description>a cheatsheet of vim commands</description>
      <content:encoded><![CDATA[<h2 id="命令执行">命令执行</h2>
<ul>
<li><code>cmd1;cmd2</code> 首先运行命令1，然后运行命令2</li>
<li><code>cmd1&amp;&amp;cmd2</code> 仅在命令1成功结束时才运行命令2</li>
<li><code>cmd1||cmd2</code> 仅当命令1失败时才运行命令2</li>
<li>执行多次，或循环执行
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#for i in {1..5}; do  // while true; do</span>
</span></span><span class="line"><span class="cl">&gt;  <span class="nb">command</span> 
</span></span><span class="line"><span class="cl">&gt;done
</span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="bash">bash</h2>
<ul>
<li>可以利用 TAB 补全查看所有可用的命令选项(连按两次 TAB 键)</li>
<li><code>~/.bashrc</code>是 Bash shell 在每次启动时都会自动执行的一个脚本文件,可以用于设置环境变量、别名和一些其他 Bash shell 配置。
<ul>
<li><code>source /opt/rh/devtoolset-9/enable</code> 更新gcc版本</li>
<li>export PS1=&rsquo;[][\W]$ []&rsquo; 修改PS1变量，让其更加简洁。PS1的默认设置为<code>\[\][\u@\h \W]\$ \[\]</code></li>
</ul>
</li>
</ul>
<hr>
<h2 id="管道">管道</h2>
<h3 id="输出流">输出流</h3>
<ul>
<li>在Unix/Linux系统中，每个进程都有两个默认的输出流，即标准输出（文件描述符1，stdout）和标准错误输出（文件描述符2，stderr）</li>
<li>用<code>|</code>连接两个命令，以前面一个命令的输出作为后面命令的输入</li>
<li><code>strace -f gcc a.c 2&gt;&amp;1 | vim -</code> This will pipe both stdout and stderr to vim. The <code>-</code> argument tells vim to read from stdin.</li>
<li><code>strace pmap 152 |&amp; vim - </code>
<code>|&amp;</code> : This is a shorthand for <code>2&gt;&amp;1 |</code> in bash and zsh. It passes both standard output and standard error of one command as input to another.</li>
<li><code>find / -newermt &quot;2022-12-31 23:00&quot; ! -newermt &quot;2023-01-01 01:00&quot; 2&gt;/dev/null</code>
<ul>
<li>查找 2022年12月31日23:00 到 2023年1月1日1:00 期间发生变动的文件</li>
<li><code>2&gt;/dev/null</code> 丢弃错误信息</li>
</ul>
</li>
</ul>
<hr>
<h2 id="crontab">crontab</h2>
<ul>
<li><code>crontab -e</code></li>
<li>注意：crontab运行的环境并不包含docker命令。需要指定完整的路径。</li>
</ul>
<h2 id="进程">进程</h2>
<h3 id="ps">ps</h3>
<ul>
<li><code>ps</code>: 显示当前终端窗口关联的进程</li>
<li><code>ps aux</code>: 显示所有用户的详细进程列表，包括进程的PID（进程ID）、CPU利用率、内存使用等信息</li>
</ul>
<h3 id="lsof">lsof</h3>
<ul>
<li><code>lsof -i:端口号</code>:查看端口占用情况</li>
<li><code>lsof -nP -iTCP -sTCP:LISTEN</code></li>
<li>
<blockquote>
<p>-n inhibits the conversion of network numbers to host names for network files.  Inhibiting conversion may make lsof run faster.It is also useful when host name lookup is not working properly.</p>
</blockquote>
</li>
<li>
<blockquote>
<p>-P inhibits the conversion of port numbers to port names for network files.  Inhibiting the conversion may make lsof run a little faster.  It is also useful when port name lookup is not working properly.</p>
</blockquote>
</li>
</ul>
<h3 id="others">others</h3>
<ul>
<li><code>kill -9 PID</code>:杀掉对应的进程</li>
</ul>
<hr>
<h2 id="tar"><code>tar</code></h2>
<ul>
<li><code>tar cvf file.tar *.c</code> creates a tar file called file.tar which is the Archive of all .c files in current directory.</li>
<li><code>tar xvf file.tar</code> extracts files from Archives.</li>
<li><code>z</code>tells tar command that creates tar file using gzip 即<code>tar.gz</code></li>
</ul>
<hr>
<h2 id="find">find</h2>
<ul>
<li>
<p>配合grep查找文件内关键字</p>
<p><code>seq 1 10 | xargs -n2 -P5 sh -c 'find / -type f -mindepth $1 -maxdepth $2 -exec grep -inl &quot;keyword&quot; {} 2&gt;/dev/null \;' _</code></p>
</li>
<li>
<p>find查找指定时间段内变动的文件</p>
<p><code>find / -newermt &quot;2022-12-31 23:00&quot; ! -newermt &quot;2023-01-01 01:00&quot; 2&gt;/dev/null</code></p>
</li>
<li>
<p>查找根目录下的所有可执行文件，但排除/usr目录</p>
<p><code>find / -path /usr -prune -o -type f -executable</code></p>
</li>
</ul>
<hr>
<h2 id="查看信息">查看信息</h2>
<ul>
<li>查看架构 <code>arch</code></li>
<li>查看内核版本
<ul>
<li><code>uname -r</code></li>
<li><code>uname -a</code></li>
<li><code>cat /proc/version</code></li>
</ul>
</li>
</ul>
<hr>
<h2 id="杂项">杂项</h2>
<ul>
<li><code>sudo passwd root</code>: 修改root用户的密码</li>
<li><code>su</code> 切换用户，默认为切换到root用户</li>
<li><code>strace</code>  追踪程序系统调用</li>
<li><code>touch</code> 新建文件,内容为空</li>
<li><code>cat</code>
<ul>
<li><code>cat filename</code> To view a single file</li>
<li><code>cat [filename-whose-contents-is-to-be-copied] &gt; [destination-filename]</code> Copy the contents of one file to another file.</li>
<li><code>cat file1 &gt;&gt; file2</code> Cat command can append the contents of one file to the end of another file.</li>
</ul>
</li>
<li><code>sort -nk 6</code> 依第6列升序排列</li>
<li><code>grep</code> (global regular expression)  用于查找文件里符合条件的字符串或正则表达式</li>
<li><code>which</code> 查找安装路径 如<code>which docker</code></li>
<li><code>alias</code>
<ul>
<li><code>alias name='command line'</code></li>
<li>列出目前所有的别名设置 <code>alias</code></li>
<li>持久化: 添加到<code>~/.bashrc</code>即可</li>
</ul>
</li>
<li><a href="https://i.hsfzxjy.site/a-trick-to-retrieve-web-contents-without-curl-or-wget/"  target="_blank" rel="noopener" >Retrieve Contents over HTTP without curl or wget</a></li>
</ul>
<hr>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://zgao.top/find%e5%91%bd%e4%bb%a4%e5%9c%a8%e5%ba%94%e6%80%a5%e4%b8%ad%e7%9a%84%e9%ab%98%e6%95%88%e6%8e%92%e6%9f%a5%e6%8a%80%e5%b7%a7"  target="_blank" rel="noopener" >find命令在应急中的高效排查技巧 – Zgao&rsquo;s blog</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>携程前端实习一面记录</title>
      <link>https://ds63.eu.org/2024/ctrip-experience/</link>
      <pubDate>Thu, 21 Mar 2024 17:04:55 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/ctrip-experience/</guid>
      <description>记录携程面试经历</description>
      <content:encoded><![CDATA[<h2 id="2024年3月6日">2024年3月6日</h2>
<p>在<a href="https://campus.ctrip.com/campus-recruitment/trip/37757/#/job/a69ae5dd-1c5a-41a4-9a7d-48ff0b886734"  target="_blank" rel="noopener" >携程集团 - 校园招聘</a>投了前端开发工程师（2025届实习）</p>
<p>要求：</p>
<ol>
<li>丰富的编码实战经验，熟悉PHP/JAVA/Python后台语言，对前后端联合开发的技术原理(Ajax,JSON)有一定认识；</li>
<li>熟悉JS/HTML5/CSS3/NodeJS等前端开发技术；</li>
<li>了解过第三方JS库或框架，使用过模块化方式开发；</li>
<li>热爱计算机编程，喜欢研究新技术、新标准；</li>
<li>有激情、有创造力、有逻辑性。</li>
</ol>
<h2 id="2024年3月9日">2024年3月9日</h2>
<p>完成其发来的能力测评。测评的内容分别为：阅读文本、根据数据图计算、找规律、心理测评。</p>
<h2 id="2024年3月13日">2024年3月13日</h2>
<p>完成其发来的笔试链接，牛客网平台、四道编程题、均要求低时间复杂度，可使用本地ide。算是做了两道半吧。</p>
<h2 id="2024年3月15日">2024年3月15日</h2>
<p>傍晚收到面试邀请，可以自己选时间，我选择在3月20号的下午。</p>
<h2 id="2024年3月18日">2024年3月18日</h2>
<p>找了几篇面经</p>
<ol>
<li><a href="https://www.nowcoder.com/feed/main/detail/b2a5a92e2c6b4f5897982cc5ad8004b1"  target="_blank" rel="noopener" >携程前端面经_牛客网</a></li>
<li><a href="https://www.nowcoder.com/discuss/427755217921335296?sourceSSR=search"  target="_blank" rel="noopener" >携程前端面经_牛客网</a></li>
</ol>
<h2 id="2024年3月20日">2024年3月20日</h2>
<p>到预约的面试亭的时候已经离开始不到10分钟了,却发现门打不开，于是在楼之间的空地面的，意外地还蛮安静。</p>
<p>10分的时候面试官已经在等了，看到我进来就说开始吧。（约的是15分开始）</p>
<h3 id="流程">流程</h3>
<ol start="0">
<li>
<p><strong>自我介绍</strong></p>
</li>
<li>
<p><strong>项目遇到过印象最深刻的一个bug是啥</strong></p>
<p>有提前准备，本来打算讲<a href="https://ds63.eu.org/2024/a-react-debug-experience/"  target="_blank" rel="noopener" >记一次react报错排查 | EuDs&rsquo;s Blog</a>。但不由自主的就开始讲<a href="https://ds63.eu.org/2024/postkid/#cargo-tauri-build"  target="_blank" rel="noopener" >我打包Postkid时的问题</a>。说报错指向的代码是编译好的代码，难以排查。我通过版本控制、一步步回退，最终定位到了bug。</p>
</li>
<li>
<p><strong>React的hook</strong></p>
<p>我讲得很浅显，我确实用过，但说不上来。想说一下useEffect可以模仿那三个生命周期方法，卡壳了</p>
</li>
<li>
<p><strong>有自定义过hook吗</strong></p>
<p>不好意思，没有</p>
</li>
<li>
<p><strong>React的setState是异步还同步</strong></p>
<p>早期的React我不太了解，不好意思</p>
</li>
<li>
<p><strong>Promise相关</strong></p>
</li>
<li>
<p><strong>Promise你是习惯用asynch还是await</strong></p>
<p>不好意思不了解，我习惯用.then</p>
</li>
<li>
<p><strong>讲讲原型链</strong></p>
<p>我说每个对象都有原型链，函数是特殊的对象，也有原型链。讲<code>__proto__</code>和<code>.protype</code>。还讲了new的原理，但自己觉得没讲明白</p>
</li>
<li>
<p><strong>讲闭包</strong></p>
<p>说是跟词法环境有关，然后讲了下自己的理解，为什么会有闭包，是因为JavaScript的三大结构stack、heap、queue。执行函数会把对应的函数压栈、被压进去的就包括对应的词法环境</p>
</li>
<li>
<p><strong>var、let、const的区别</strong></p>
<p>讲var是最早的，作用域是全局作用域和函数作用域，这样设计有缺陷，举了for循环的例子，说需要用IFFE来解决（这个名字我也忘了，大概讲了下意思，感觉会被当成乱讲）。然后说es6为了解决var的缺陷，就引入了let和const，它们是块作用域。然后又讲了下变量提升。（这里我少讲了声明和变化）</p>
</li>
<li>
<p><strong>页面发送跨域请求是怎么处理的</strong>
先讲了同源的定义,然后讲跨域的解决方式：</p>
<ul>
<li>代理: 跨域限制是限制浏览器对服务器的，因此使用个代理服务器就能避开这个问题</li>
<li>CORS: 讲分成了三类请求，后两类需要options来预检。带了下预检的过程和max-age</li>
<li>提了嘴JSOP、websocket、sendMessage,说这些方法都可以，但不常用。为了防止被追问，强调了下自己只是有看过</li>
</ul>
</li>
<li>
<p><strong>看代码说输出</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;timeout&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">p</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resovle</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;new Promise&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">p</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;promise then&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>我对结果不太确定，但知道这题是要考察任务队列。讲了宏队列和微队列，以及它们的执行顺序。</p>
</li>
<li>
<p><strong>你自己写css写得多吗</strong></p>
<p>少，我用tailwindcss比较多，强行扯了下它的优点（自己css确实了解得不多，得加强）</p>
</li>
<li>
<p><strong>不定宽高要怎么设置垂直居中</strong></p>
<p>用flex，justify-content和margin-items都设为center。 被追问还有吗，不好意思不清楚</p>
</li>
<li>
<p><strong>盒模型</strong></p>
<p>讲了两种盒模型</p>
</li>
<li>
<p><strong>key的作用</strong></p>
<p>讲了React的diff算法,说主要三种diff算法：tree、component、element。而key就是和element diff算法有关。（感觉好像没答到点上）</p>
</li>
<li>
<p><strong>xss攻击了解吗</strong>
先介绍三种xss攻击，存储型、反射型、dom注入型。然后说主要有两类防范措施。</p>
<ul>
<li>阻止攻击者提交恶意代码
<ol>
<li>输入过滤： 道高一尺魔高一丈，难</li>
<li>输入长度限制</li>
</ol>
</li>
<li>防止浏览器执行恶意代码
<ol>
<li>改成纯前端渲染，把代码和数据分隔开。</li>
<li>举例了下说React防范xss攻击已经做得很好了，想说为什么好，但没说上来。</li>
</ol>
</li>
</ul>
</li>
<li>
<p><strong>csrf了解吗</strong>
讲了下原理和过程。然后说防范措施。报菜名般报了几个。然后说自己的理解，csrf主要针对的是cookie，那最简单的措施就是不在cookie存敏感措施。又讲了下chrome在今年一月份宣布已经要开始禁止第三方cookie。再回到自己项目，说自己是将token存在了sessionStorage和localStorage</p>
</li>
<li>
<p><strong>浏览器强缓存和协商缓存</strong>
先说可以按照存放位置来分成memory cache和disk cache。然后讲协商缓存是要在强缓存时效后才起作用的。然后讲相关的几个header: Expires和Cache-Control，后者是替代前者的，以及为什么； ETag , 还有Last-Modified，If-Modified-Since这对，我名字没想起来，但是讲了下具体作用。</p>
</li>
<li>
<p><strong>浏览器的storage</strong>
说有<code>sessionStorage</code>和<code>localStorage</code>。特别讲了下一个新打开的页面会复制原页面的sessionStorage,但之后就是独立的了。讲localStorage，说它特别持久，举了个自己的例子：前几天打开一个本地端口的网页，发现一年前做项目时留的localStorage竟然还在。还提到indexedDB，说了下自己的想法，觉得数据库还是留在后端会好些。但也说自己看过indexedDB的用途，说是可以用来实现离线浏览。然后比较了这四个的大小</p>
</li>
<li>
<p>一道题，共享屏幕写</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 编写函数将数组A转成对象B的数据格式
</span></span></span><span class="line"><span class="cl"><span class="c1">// 数组A
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;job&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;one&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;job&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;two&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;life&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;eat&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;job&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;three&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;life&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;sleep&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="s1">&#39;life&#39;</span><span class="p">,</span><span class="nx">content</span><span class="o">:</span><span class="s1">&#39;play&#39;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 对象B
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">job</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;one&#39;</span><span class="p">,</span><span class="s1">&#39;two&#39;</span><span class="p">,</span><span class="s1">&#39;three&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">life</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;eat&#39;</span><span class="p">,</span><span class="s1">&#39;sleep&#39;</span><span class="p">,</span><span class="s1">&#39;play&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这里我先是开了个Javascript的playground，然后就不知道怎么写了，改用python。然后共享出问题了，费了好些周折。</p>
</li>
<li>
<p>了解TypeScript吗，觉得它有必要吗
了解过，自己的第三个项目就是用的TypeScript，很折磨。都笑了。然后我扯了下JavaScript的历史，说设计之初没考虑到现在的使用人群这么广，为了弥补，人们用搞出了各种规范。TypeScript算是另起炉灶，是蛮有必要的。比如说看之前JavaScript的项目，有时候就要猜某个变量是啥类型，但TypeScript就好多了。</p>
</li>
<li>
<p><strong>反问</strong>
刚准备提问呢，电脑卡一下没电了，改用手机连上去，面试官还在等我。问了两个没啥营养的问题，说了通感谢词。</p>
</li>
</ol>
<h2 id="感受">感受</h2>
<ol>
<li>这是自己今年的第一次面试，蛮珍惜的，但出了不少乱子。不过面试官人挺好的，很有耐心，让我对携程好感度++</li>
<li>自己一上来蛮紧张的，后面反而变得嗨起来了，提到一个问题就想把自己所有相关不相关的储备都讲出去，导致可能会显得在乱扯。</li>
<li>面试的时候没特地记录，上面内容是隔了好久才写的，没想到还能记这么清楚。</li>
<li>几乎是纯八股，我想往自己项目上拐。面试官不接啊。</li>
<li>不少知识都有看过，甚至也整理过。但讲的时候还是有问题。今后要试着自己讲几遍。</li>
<li>牛客网上的面经真的有用，很感谢下面几位发的面经。自己今后也会投桃报李,也算是积积阳德。
<ul>
<li><a href="https://www.nowcoder.com/feed/main/detail/b2a5a92e2c6b4f5897982cc5ad8004b1"  target="_blank" rel="noopener" >携程前端面经_牛客网</a></li>
<li><a href="https://www.nowcoder.com/discuss/427755217921335296"  target="_blank" rel="noopener" >携程前端面经_牛客网</a></li>
<li><a href="https://www.nowcoder.com/feed/main/detail/16da2a2453b8427d86d3669ff6668196"  target="_blank" rel="noopener" >携程 一面 时间1小时_牛客网</a></li>
<li><a href="https://www.nowcoder.com/feed/main/detail/9124a0102471407eab463c4bee11b52c?sourceSSR=users"  target="_blank" rel="noopener" >携程一面3.19_牛客网</a></li>
</ul>
</li>
</ol>
<h2 id="总结">总结</h2>
<p>第二天看就进人才池了，面试体验很好，下次还投携程。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>React知识点整理</title>
      <link>https://ds63.eu.org/2024/react_points/</link>
      <pubDate>Fri, 08 Mar 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/react_points/</guid>
      <description>自己学习过程中整理的关于React的知识点</description>
      <content:encoded><![CDATA[<p><strong>本文记录了我学习过程中整理的关于React的知识点,以摘抄为主，绝大部分非原创。未能全部都标明出处，在此致歉</strong></p>
<h2 id="jsx">JSX</h2>
<ul>
<li>一种JavaScript的语法扩展（extension），也在很多地方称之为JavaScript XML，因为看起就是一段XML语法；</li>
<li>为什么React选择使用jsx？
<ul>
<li>React认为渲染逻辑本质上与其他UI逻辑存在内在耦合,他们之间是密不可分，所以React没有将标记分离到不同的文件中，而是将它们组合到了一起，这个地方就是组件（Component）</li>
</ul>
</li>
<li>本质
<ul>
<li>React.createElement(component, props, &hellip;children) 函数的语法糖</li>
<li>所有的jsx最终都会被转换成React.createElement的函数调用</li>
</ul>
</li>
<li>参考: <a href="https://www.cnblogs.com/yaopengfei/p/17299996.html"  target="_blank" rel="noopener" >第二节：jsx语法深度剖析和jsx本质的探究 - Yaopengfei - 博客园</a></li>
</ul>
<hr>
<h2 id="生命周期">生命周期</h2>
<h3 id="there-phases">there phases</h3>
<ol>
<li>mounting: initial render</li>
<li>updating: is triggered when the props are updated or when the state is updated</li>
<li>unmounting: when the component is removed from the DOM</li>
</ol>
<h3 id="methods">methods</h3>
<ul>
<li>Each phase has specific methods responsible for a particular stage in a component&rsquo;s lifecycle. These methods <strong>are technically particular to class-based components</strong> and not intended for functional components.</li>
<li><a href="https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/"  target="_blank" rel="noopener" >React lifecycle methods diagram</a></li>
<li><code>shouldComponentUpdate</code> -&gt; <code>useMemo</code>、 <code>memo</code></li>
<li>&ldquo;Commit phase&quot;中的三个方法,Can work with DOM, run side effects, schedule updates：
<ol>
<li><code>componentDidMount</code> -&gt; the useEffect hook with the second argument of []</li>
<li><code>componentDidUpdate</code> -&gt; the useEffect hook with the second argument of [state]</li>
<li><code>componentWillUnmount</code> -&gt; <strong>return a function</strong> that runs on unmounting inside the useEffect function,例:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">    <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Bye&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="p">[]);</span>
</span></span></code></pre></div></li>
<li>上面的类比只是类比，不能等同，原因：
<ol>
<li>实际原理不同</li>
<li>执行时机不同</li>
</ol>
</li>
</ul>
<h3 id="参考">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7132786097922736164"  target="_blank" rel="noopener" >useEffect(fn, []) 不等于 componentDidMount() - 掘金</a></li>
<li><a href="https://retool.com/blog/the-react-lifecycle-methods-and-hooks-explained"  target="_blank" rel="noopener" >The React lifecycle: methods and hooks explained</a></li>
<li><a href="https://juejin.cn/post/6914112105964634119"  target="_blank" rel="noopener" >深入详解React生命周期 getSnapshotBe - 掘金</a></li>
</ul>
<hr>
<h2 id="react-组件的实现">React 组件的实现</h2>
<h3 id="函数组件">函数组件</h3>
<ul>
<li>
<p>概念</p>
<ul>
<li>函数组件是一个普通的 JavaScript 函数，它接受 props 作为参数并返回 React 元素树（JSX）。</li>
<li>React 会调用该函数并将返回的 JSX 虚拟 DOM 转换为真实的 DOM。</li>
<li>现代 React 推荐使用函数组件，因为它更简洁，且能够配合 Hook 使用。</li>
</ul>
</li>
<li>
<p>组件的生命周期</p>
<ul>
<li>虽然函数组件没有显式的生命周期方法，但通过 React Hook 可以为它们注入类似生命周期的功能。</li>
<li>类似 <code>useEffect</code> 可以让函数组件在 <code>componentDidMount</code>、<code>componentDidUpdate</code> 或 <code>componentWillUnmount</code> 这类阶段执行代码。</li>
</ul>
</li>
</ul>
<h3 id="类组件">类组件</h3>
<ul>
<li>概念
<ul>
<li>类组件是基于 <code>ES6 class</code> 的方式定义的，它继承自 <code>React.Component</code>。</li>
</ul>
</li>
<li>组件的生命周期
<ul>
<li>类组件有一系列内置的生命周期方法，如 <code>componentDidMount</code>、<code>componentDidUpdate</code>、<code>componentWillUnmount</code> 等，用于控制组件的生命周期。</li>
</ul>
</li>
</ul>
<h3 id="virtual-dom虚拟-dom和-reconciliation调和">Virtual DOM（虚拟 DOM）和 Reconciliation（调和）</h3>
<ul>
<li>React 中的每个组件返回的 JSX 会被转换为虚拟 DOM。虚拟 DOM 是实际 DOM 的轻量化表示，它的变化不会立即反映在真实的浏览器 DOM 上。</li>
<li>当组件的状态或 props 改变时，React 会创建新的虚拟 DOM，并通过 Diff 算法与旧的虚拟 DOM 进行对比，找出差异，然后仅更新需要更新的部分，这个过程称为 Reconciliation（调和）。</li>
</ul>
<hr>
<h2 id="虚拟dom-virtual-document-object-model">虚拟DOM （Virtual Document Object Model）</h2>
<p>在React中，当状态（state）发生变化时，React并不直接操作真实的DOM来更新页面，而是先在内存中构建一个虚拟DOM树，然后通过比较虚拟DOM树和之前渲染的虚拟DOM树之间的差异，最终计算出最小的DOM操作，并将这些操作批量应用到真实的DOM上。</p>
<h3 id="虚拟dom节点可能包含的详细信息">虚拟DOM节点可能包含的详细信息</h3>
<ol>
<li><strong>type</strong>：节点类型可以是元素节点、文本节点或者组件节点。</li>
<li><strong>props</strong>：节点可能包含一些属性，这些属性描述了节点的特征，比如元素节点的class、id、style等属性，以及事件处理函数等。chidren 是 props 中的一个属性，它存储了当前组件的孩子节点，可以是数组（多个孩子节点）或对象（只有一个孩子节点）</li>
<li><strong>key</strong>：用于在DOM的重渲染过程中标识节点的唯一性，有助于React在进行差异比较时准确找到对应的节点。</li>
<li><strong>ref</strong>：用于获取节点的引用，通常用于在组件中操作DOM节点。</li>
<li><strong>owner</strong>: 所属的Component</li>
<li>其他</li>
</ol>
<h3 id="diff算法">diff算法</h3>
<ul>
<li>比较当前的虚拟DOM树和状态变更将要重新渲染时生成的虚拟DOM树的算法。</li>
<li>关键：
<ol>
<li>深度优先</li>
<li>只对同一级别的元素进行比较</li>
</ol>
</li>
<li>三种diff
<ol>
<li>tree diff : 只是简单进行了删除和创建操作</li>
<li>component diff：
<ul>
<li>使用的是<code>===</code>严格相等。也就是&quot;引用相等性&rdquo;</li>
<li>不同类型 -&gt; 直接替换整个组件下的所有子节点，即销毁原组件，创建新组件。</li>
<li>同一类型 -&gt; 继续判断</li>
</ul>
</li>
<li>element diff: 针对同一层级的所有节点（包括元素节点和组件节点）的 diff 算法
<ul>
<li>三种操作：
<ol>
<li>insert_markup</li>
<li>move_existing</li>
<li>remove_node:</li>
</ol>
</li>
<li>涉及到列表元素顺序的动态变更时，不要用遍历的 index 作为节点的 key 属性值</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://xie.infoq.cn/article/65e938d933cc751fcc008942d"  target="_blank" rel="noopener" >谈谈虚拟DOM，Diff算法与Key机制_React_beifeng1996_InfoQ写作社区</a></li>
</ul>
<hr>
<h2 id="组件间通信方式">组件间通信方式</h2>
<h3 id="通过-props-传递数据父传子组件通信">通过 Props 传递数据（父传子组件通信）</h3>
<ul>
<li><strong>适用场景</strong>：最常见的方式，适用于父组件向子组件传递数据。</li>
<li><strong>原理</strong>：父组件通过 <code>props</code> 将数据传递给子组件，子组件通过 <code>props</code> 接收并使用这些数据。</li>
</ul>
<h3 id="使用回调函数子传父组件通信">使用回调函数（子传父组件通信）</h3>
<ul>
<li><strong>适用场景</strong>：当子组件需要向父组件传递数据时。</li>
<li><strong>原理</strong>：父组件将一个回调函数作为 <code>props</code> 传递给子组件，子组件调用该函数，将数据传递回父组件。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"> <span class="kd">function</span> <span class="nx">Parent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kr">const</span> <span class="nx">handleData</span> <span class="o">=</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="p">&lt;</span><span class="nt">Child</span> <span class="na">sendData</span><span class="o">=</span><span class="p">{</span><span class="nx">handleData</span><span class="p">}</span> <span class="p">/&gt;;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kd">function</span> <span class="nx">Child</span><span class="p">({</span> <span class="nx">sendData</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">sendData</span><span class="p">(</span><span class="s2">&#34;Hello from child!&#34;</span><span class="p">)}&gt;</span><span class="nx">Send</span> <span class="nx">Data</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="通过-context-api">通过 Context API</h3>
<ul>
<li><strong>适用场景</strong>：适合深层次的组件树中需要共享的全局状态，避免层层传递 <code>props</code>（例如：主题、语言、用户信息等）。</li>
<li><strong>原理</strong>：创建一个 <code>Context</code>，并使用 <code>Provider</code> 组件来提供状态，任何深层的组件都可以通过 <code>Consumer</code> 或 <code>useContext</code> 钩子来访问。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">MyContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Parent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Hello from context!&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">MyContext.Provider</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">value</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">Child</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">MyContext.Provider</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Child</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">contextValue</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">useContext</span><span class="p">(</span><span class="nx">MyContext</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;{</span><span class="nx">contextValue</span><span class="p">}&lt;/</span><span class="nt">div</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="通过-redux-或其他状态管理库">通过 Redux 或其他状态管理库</h3>
<ul>
<li><strong>适用场景</strong>：在需要管理全局状态或复杂状态时，Redux 是一个强大的工具。</li>
<li><strong>原理</strong>：全局状态存储在 Redux 的 <code>store</code> 中，任何组件都可以通过 <code>connect</code> 或 <code>useSelector</code> 访问状态，通过 <code>dispatch</code> 发送 action 来修改状态。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useSelector</span><span class="p">,</span> <span class="nx">useDispatch</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react-redux&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyComponent</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">count</span> <span class="o">=</span> <span class="nx">useSelector</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="nx">state</span><span class="p">.</span><span class="nx">counter</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">dispatch</span> <span class="o">=</span> <span class="nx">useDispatch</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;{</span><span class="nx">count</span><span class="p">}&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">dispatch</span><span class="p">({</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;INCREMENT&#39;</span> <span class="p">})}&gt;</span><span class="nx">Increment</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="使用全局事件eventemitter-或-custom-events">使用全局事件（EventEmitter 或 Custom Events）</h3>
<ul>
<li><strong>适用场景</strong>：组件之间没有明显的层级关系，适合不频繁的数据交换。</li>
<li><strong>原理</strong>：可以使用事件触发机制，例如 <code>EventEmitter</code>，让一个组件监听事件，另一个组件触发事件。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">EventEmitter</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;events&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">eventEmitter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">EventEmitter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// In one component (sender)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">eventEmitter</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="s1">&#39;Hello World&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// In another component (receiver)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">eventEmitter</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="url-params--query-strings通过路由传递">URL Params / Query Strings（通过路由传递）</h3>
<ul>
<li><strong>适用场景</strong>：组件之间通过 URL 参数传递信息。</li>
<li><strong>原理</strong>：使用 React Router 来通过 URL 将信息从一个页面传递到另一个页面。可以通过 <code>useParams</code> 或 <code>useLocation</code> 钩子来读取。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useParams</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react-router-dom&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">UserProfile</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">userId</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">useParams</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span><span class="nx">User</span> <span class="nx">ID</span><span class="o">:</span> <span class="p">{</span><span class="nx">userId</span><span class="p">}&lt;/</span><span class="nt">div</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="使用-web-storagelocalstoragesessionstorage">使用 Web Storage（LocalStorage/SessionStorage）</h3>
<ul>
<li><strong>适用场景</strong>：需要在页面刷新或不同组件间共享数据。</li>
<li><strong>原理</strong>：将数据存储在浏览器的 <code>localStorage</code> 或 <code>sessionStorage</code> 中，组件可以通过它们来读取和修改数据。</li>
<li><strong>示例</strong>:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">setData</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;John&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getData</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;{</span><span class="nx">name</span><span class="p">}&lt;/</span><span class="nt">div</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="react-router">React Router</h2>
<ul>
<li>state
<ul>
<li>An object to store on location state. This is useful for state that doesn’t need to be in the URL but is associated with a route transition. Think of it like “post” data on a server.</li>
<li>可以用来实现: 用户被踢出后再登陆注册能返回被踢出时的页面</li>
</ul>
</li>
<li>replace的作用:
<blockquote>
<p>An example is when the user clicks a “purchase” button but needs to log in first, after they log in, you can replace the login screen with the checkout screen you wanted them to be at. Then when they click the back button they won’t see the login page again.</p>
<p>navigate(&quot;/some/where&quot;, { replace: true })</p>
</blockquote>
</li>
</ul>
<h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://reach.tech/router/api/navigate"  target="_blank" rel="noopener" >Reach Router - navigate(to, { state={}, replace=false })</a></li>
</ul>
<hr>
<h2 id="react-fiber">React Fiber</h2>
<h3 id="概念">概念</h3>
<ul>
<li>React 通过 Fiber 树对任务进行切片（time-slicing），分成多个小块任务，允许在渲染过程中将控制权交还给主线程，以避免阻塞浏览器的渲染和响应用户交互。</li>
</ul>
<h3 id="关键点">关键点：</h3>
<ol>
<li>
<p><strong>任务的可中断性</strong>
在传统的 React 16 之前的版本，渲染过程是同步的，一旦开始渲染，就会一直执行到整个更新完成。如果渲染复杂，用户交互（如点击、滚动）会被阻塞。而 Fiber 通过将渲染任务分解成多个小任务，可以在渲染的过程中暂停、打断和恢复，从而为高优先级任务（如用户输入）让路。</p>
</li>
<li>
<p><strong>优先级机制</strong>
React Fiber 引入了优先级调度，不同的更新任务可以根据优先级被安排执行。高优先级的任务会优先被调度执行，而低优先级任务会被延迟处理。这种机制大大提升了应用的响应性，避免了长时间的卡顿。</p>
</li>
<li>
<p><strong>双缓冲 Fiber 树</strong>
Fiber 使用两棵树来管理渲染过程：</p>
<ul>
<li><strong>Current Fiber Tree</strong>：当前已渲染的树。</li>
<li><strong>Work In Progress Fiber Tree</strong>：正在构建的树。</li>
</ul>
<p>React 在更新过程中会基于当前的 Fiber 树构建一个新的 Fiber 树，这个过程是渐进的，不会阻塞主线程。</p>
</li>
<li>
<p><strong>时间切片（Time Slicing）</strong>
通过时间切片，React Fiber 能够将渲染任务分割成多个小片段，在每个帧之间执行这些片段。每当有更高优先级的任务需要处理时，React Fiber 会暂停当前的渲染任务，执行完高优先级任务后再恢复。</p>
</li>
<li>
<p><strong>可恢复的工作单元</strong>
每个 Fiber 都是一个工作单元，它包含了组件的状态、props 和上下文信息。Fiber 架构允许在工作单元之间中断、恢复以及重新调度渲染。</p>
</li>
<li>
<p><strong>并发模式（Concurrent Mode）</strong>
React Fiber 是并发模式的基础，它能够在未来支持并发渲染，让 React 在后台渲染不重要的内容，并优先响应重要的更新。这一特性会进一步提升用户体验，尤其是在交互密集的应用中。</p>
</li>
</ol>
<h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://www.velotio.com/engineering-blog/react-fiber-algorithm"  target="_blank" rel="noopener" >An Introduction to React Fiber - The Algorithm Behind React</a></li>
<li><a href="https://juejin.cn/post/7114132411499151373"  target="_blank" rel="noopener" >通俗易懂地理解React Fiber - 掘金</a></li>
</ul>
<hr>
<h2 id="错误捕获">错误捕获</h2>
<p>wip</p>
<h3 id="参考-4">参考</h3>
<ul>
<li><a href="https://zh-hans.react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary"  target="_blank" rel="noopener" >使用错误边界捕获渲染错误  – React 中文文档</a></li>
<li><a href="https://github.com/bvaughn/react-error-boundary"  target="_blank" rel="noopener" >bvaughn/react-error-boundary: Simple reusable React error boundary component</a></li>
</ul>
<hr>
<h2 id="优先级管理">优先级管理</h2>
<p>wip</p>
<h3 id="参考-5">参考</h3>
<ul>
<li><a href="https://7km.top/main/priority"  target="_blank" rel="noopener" >优先级管理</a></li>
</ul>
<hr>
<h2 id="参考-6">参考</h2>
<ul>
<li><a href="https://github.com/sudheerj/reactjs-interview-questions"  target="_blank" rel="noopener" >sudheerj/reactjs-interview-questions: List of top 500 ReactJS Interview Questions &amp; Answers&hellip;.Coding exercise questions are coming soon!!</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>前端知识点整理</title>
      <link>https://ds63.eu.org/2024/frontend_points/</link>
      <pubDate>Thu, 07 Mar 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/frontend_points/</guid>
      <description>自己学习过程中整理的关于前端的知识点</description>
      <content:encoded><![CDATA[<h2 id="存在问题">存在问题</h2>
<p>当做聊天页时会遇到下拉加载历史记录，当我们获取历史记录并将其放进页面数组时，新获取的历史记录会将你刚刚看的信息挤下去，这时你要往上拉才能回到你刚刚看的信息。
虽然可以通过获取刚看的那条信息的位置，等历史记录拉取下来后再通过改变滚动条回到其原来的位置，但这样会让页面出现闪动，信息会先下去，然后再上来。</p>
<h2 id="intersectionobserver">IntersectionObserver</h2>
<ul>
<li><a href="https://mp.weixin.qq.com/s/vhpXEaumPp5VvR7Zt9jGkQ"  target="_blank" rel="noopener" >不到20行js实现高性能图片懒加载</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver"  target="_blank" rel="noopener" >IntersectionObserver - Web APIs | MDN</a></li>
<li><a href="https://medium.com/strise/making-use-of-observers-in-react-a29b1fd05fa7"  target="_blank" rel="noopener" >Making use of Observers in React. Ever needed to manipulate the DOM when… | by Jens Lind | Strise | Medium</a></li>
<li><a href="https://dev.to/hey_yogini/infinite-scrolling-in-react-with-intersection-observer-22fh"  target="_blank" rel="noopener" >Infinite scrolling in React with intersection observer - DEV Community</a></li>
</ul>
<h2 id="滚动到对应位置">滚动到对应位置</h2>
<ul>
<li><a href="https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback"  target="_blank" rel="noopener" >Manipulating the DOM with Refs – React</a></li>
</ul>
<h2 id="overflow-anchor">overflow-anchor</h2>
<ul>
<li><a href="https://juejin.cn/post/7112349799373864996"  target="_blank" rel="noopener" >解决聊天页下拉加载历史记录，新获取的历史记录把刚看的信息挤下去的问题 - 掘金</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-anchor"  target="_blank" rel="noopener" >overflow-anchor - CSS: Cascading Style Sheets | MDN</a></li>
<li><a href="https://css-tricks.com/almanac/properties/o/overflow-anchor/"  target="_blank" rel="noopener" >Overflow-anchor | CSS-Tricks</a></li>
</ul>
<blockquote>
<p>Scroll Anchoring is a browser feature that attempts to prevent a common situation where you may scroll down a webpage before the DOM has fully loaded and, when it does, any elements that load above your current location push you further down the page.</p>
</blockquote>
<h2 id="反向渲染">反向渲染</h2>
<p><a href="https://www.alloyteam.com/2020/04/14349/comment-page-1/#comments"  target="_blank" rel="noopener" >前端开发中聊天场景的体验优化 | AlloyTeam</a></p>
<h2 id="计算并设置正确的滚动位置">计算并设置正确的滚动位置</h2>
<ul>
<li>
<p><a href="https://cloud.tencent.com/developer/article/2176884"  target="_blank" rel="noopener" >React中将一直增加消息的滚动框保持在当前浏览的位置-腾讯云开发者社区-腾讯云</a></p>
</li>
<li>
<p><a href="https://www.zhangxinxu.com/wordpress/2018/02/container-scroll-position-hold/"  target="_blank" rel="noopener" >小tips: 滚动容器尺寸变化子元素视觉上位置不变JS实现 « 张鑫旭-鑫空间-鑫生活</a></p>
</li>
</ul>
<h2 id="位置不对">位置不对</h2>
<p><a href="https://www.shymean.com/article/%E5%89%8D%E7%AB%AF%E4%BD%93%E9%AA%8C%E4%BC%98%E5%8C%96%E4%B9%8B%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E9%97%AA%E7%83%81"  target="_blank" rel="noopener" >前端体验优化之图片加载闪烁 | ShyMean</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>前端知识点整理</title>
      <link>https://ds63.eu.org/2024/frontend_points/</link>
      <pubDate>Thu, 07 Mar 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/frontend_points/</guid>
      <description>自己学习过程中整理的关于前端的知识点</description>
      <content:encoded><![CDATA[<p><strong>本文记录了我学习过程中整理的前端相关的知识点,以摘抄为主，绝大部分非原创。未能全部都标明出处，在此致歉</strong></p>
<h2 id="前言">前言</h2>
<h3 id="为什么选择前端">为什么选择前端</h3>
<p>前端和后端，我选择将前端作为我的主要技术栈。这和我个人的学习习惯有关。</p>
<p>我喜欢学以致用,对于一门尚未掌握的技术，我倾向于先看文档看个百分之二三十,有个大体的了解后，就开始动手去做。但后端的微服务等技术，我缺乏实际的实践环境，没法实践去应用，学起来就感觉很虚。</p>
<p>但前端不太一样。在我自己的项目中，为了实现更快的响应时间、更实用美观的界面，我有充分的动力去学习新的技术，然后将其运用，这形成了一个正反馈的过程。比如说我去年用webassembly写了一个<a href="https://lifegame.ds63.eu.org/"  target="_blank" rel="noopener" >Game of Life</a>，当我对代码进行优化后，我确实能看到帧数肉眼可见地提升了。</p>
<h3 id="为什么要记八股">为什么要记八股</h3>
<p>最近在准备找实习，网上的八股光看也不太能记得住，还得是自己整理记录下。</p>
<p>我之前有点认为记八股是一种应试行为，有点抵触。但有天晚上我排查<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid</a>出现的一个问题,为了完全搞懂，我就自发地去搜React的生命周期。</p>
<p>这时候我意识到八股的那些问题，其实不少是蛮常见的问题。要写好代码确实得去知道。</p>
<p>看<a href="https://www.nowcoder.com/discuss/590189774611247104"  target="_blank" rel="noopener" >面试官视角下的技术面——为什么要“背八股”_牛客网</a>。</p>
<p>如果被问八股，要学会自己主动去延伸，进而在一定程度上把握面试的主动权。</p>
<hr>
<h2 id="html">Html</h2>
<h3 id="表单数据校验">表单数据校验</h3>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Form_validation"  target="_blank" rel="noopener" >表单数据校验 - 学习 Web 开发 | MDN</a></p>
<h3 id="锚点">锚点</h3>
<ul>
<li>示例</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">a</span> <span class="nx">href</span><span class="o">=</span><span class="s2">&#34;#javascript深入之重新认识箭头函数的this&#34;</span> <span class="nx">aria</span><span class="o">-</span><span class="nx">hidden</span><span class="o">=</span><span class="s2">&#34;true&#34;</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&#34;header-anchor&#34;</span><span class="o">&gt;</span><span class="err">#</span><span class="o">&lt;</span><span class="err">/a&gt;</span>
</span></span></code></pre></div><ul>
<li><code>aria-hidden=&quot;true&quot;</code> 属性通常用于指示屏幕阅读器等辅助技术，告知它们该元素对用户来说是不可见的，因此屏幕阅读器会忽略该元素。</li>
<li>参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a"  target="_blank" rel="noopener" ><!-- raw HTML omitted -->：锚元素 - HTML（超文本标记语言） | MDN</a></li>
</ul>
<h3 id="html5新特性">html5新特性</h3>
<p>wip</p>
<h3 id="html5语义化">HTML5语义化</h3>
<ul>
<li>title v.s. h1</li>
<li>strong v.s. b</li>
</ul>
<h3 id="input">input</h3>
<ul>
<li><code>readonly</code>: 只可读，不允许改动，提交时该值可以被传递</li>
<li><code>disable</code>:  不可改动，提交时该值不会被传递</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input"  target="_blank" rel="noopener" ><!-- raw HTML omitted -->: The HTML Input element - HTML: HyperText Markup Language | MDN</a></li>
</ul>
<h3 id="ol">ol</h3>
<ul>
<li><code>start</code>: 计数的起点</li>
<li><code>type</code>: <code>a|A|i|I|1</code>, 默认为1</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol"  target="_blank" rel="noopener" ><!-- raw HTML omitted -->: The Ordered List element - HTML: HyperText Markup Language | MDN</a></li>
</ul>
<h3 id="img">img</h3>
<ul>
<li>属性:
<ul>
<li>src： 必须</li>
<li>alt</li>
<li><code>referrerpolicy</code></li>
<li><code>crossorigin</code></li>
<li><code>onerror</code></li>
<li><code>loading</code></li>
</ul>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img"  target="_blank" rel="noopener" ><!-- raw HTML omitted -->：图像嵌入元素 - HTML（超文本标记语言） | MDN</a></li>
</ul>
<hr>
<h2 id="浏览器">浏览器</h2>
<h3 id="浏览器一帧都会干些什么">浏览器一帧都会干些什么？</h3>
<ol>
<li>接受输入事件</li>
<li>执行事件回调</li>
<li>开始一帧</li>
<li>执行 RAF (RequestAnimationFrame)</li>
<li>页面布局，样式计算</li>
<li>绘制渲染</li>
<li>执行 RIC (RequestIdelCallback)</li>
</ol>
<h3 id="浏览器引擎的工作原理">浏览器引擎的工作原理</h3>
<p>wip</p>
<ul>
<li><a href="https://juejin.cn/post/7179130165262286885"  target="_blank" rel="noopener" >一次看懂V8引擎与JIT原理V8 V8 是什么 Google V8 是开源高性能 JavaScript 和 WebAss - 掘金</a></li>
</ul>
<h3 id="浏览器渲染过程">浏览器渲染过程</h3>
<ol>
<li>解析 HTML 和样式计算 (parsing and style calculation)</li>
<li>布局 (Layout)</li>
<li>绘制 (paint)</li>
<li>合成 (compositing)</li>
</ol>
<h3 id="浏览器事件循环">浏览器事件循环</h3>
<p>wip</p>
<h3 id="浏览器的多线程">浏览器的多线程</h3>
<ol>
<li>JavaScript 引擎线程</li>
<li>GUI 渲染线程
<ul>
<li>GUI 渲染线程与 JavaScript 引擎是互斥的</li>
<li>当 JavaScript 引擎执行时 GUI 线程会被挂起，GUI 更新会被保存在一个队列中等到 JavaScript 引擎空闲时立即被执行。</li>
</ul>
</li>
<li>事件触发线程
<ul>
<li>当一个事件被触发时该线程会把事件添加到“任务队列”的队尾，等待 JavaScript 引擎的处理。这些事件可来自 JavaScript 引擎当前执行的代码块如 setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax 异步请求等，但由于 JavaScript 是单线程执行的，所有这些事件都得排队等待 JavaScript 引擎处理。</li>
</ul>
</li>
</ol>
<ul>
<li>参考: <a href="https://github.com/JChehe/blog/blob/master/posts/%E5%85%B3%E4%BA%8EJavaScript%E5%8D%95%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BA%8B.md"  target="_blank" rel="noopener" >blog/posts/关于JavaScript单线程的一些事.md at master · JChehe/blog</a></li>
</ul>
<h3 id="输入url到页面渲染的过程">输入URL到页面渲染的过程</h3>
<ul>
<li>DNS 查询顺序
<ol>
<li>浏览器 DNS 缓存</li>
<li>浏览器调用 getaddrinfo() 查询数据，其中 getaddrinfo() 会根据如下顺序查询
<ol>
<li>先看 /etc/hosts 文件</li>
<li>通过主机名服务/mDNS 查询</li>
<li>通过 systemd-resolved 查询</li>
<li>最后通过 DHCP 下发的 DNS 查询</li>
<li>一级级往上查询直到根 DNS 服务器</li>
</ol>
</li>
</ol>
</li>
<li>CSS加载不阻塞页面解析，但阻塞页面渲染</li>
<li>JS加载阻塞页面解析和渲染</li>
<li>参考
<ul>
<li><a href="https://nova.moe/rethink-type-url-dns/"  target="_blank" rel="noopener" >重新思考浏览器输入了 URL 并按下回车之后到底发生了什么——本地 DNS 部分 | Nova Kwok&rsquo;s Awesome Blog</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/140700610"  target="_blank" rel="noopener" >(1w字)前端都该懂的浏览器工作原理，你懂了吗？ - 知乎</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/133906695"  target="_blank" rel="noopener" >从输入 URL 到页面展示到底发生了什么？ - 知乎</a></li>
<li><a href="https://juejin.cn/post/7011377094156353567"  target="_blank" rel="noopener" >css、js和图片文件加载会阻塞页面解析和渲染吗？同时加载10个js文件需要多长时间？从输入url到页面展示到底发生了什 - 掘金</a></li>
</ul>
</li>
</ul>
<h3 id="script标签中的defer和async的区别">script标签中的defer和async的区别？</h3>
<ul>
<li>defer
<ul>
<li>示例: <code>&lt;script defer src=&quot;https://javascript.info/article/script-async-defer/small.js&quot;&gt;&lt;/script&gt;</code></li>
<li>文档顺序（它们在文档中的顺序）</li>
<li>具有 defer 特性的脚本不会阻塞页面</li>
<li>具有 defer 特性的脚本总是要等到 DOM 解析完毕，但在 DOMContentLoaded 事件之前执行</li>
<li>具有 defer 特性的脚本保持其相对顺序，就像常规脚本一样</li>
<li>仅适用于外部脚本: 如果 <code>&lt;script&gt;</code> 脚本没有 src，则会忽略 defer 特性</li>
</ul>
</li>
<li>async
<ul>
<li>async 特性意味着脚本是完全独立的：
<ol>
<li>浏览器不会因 async 脚本而阻塞（与 defer 类似）。</li>
<li>其他脚本不会等待 async 脚本加载完成，同样，async 脚本也不会等待其他脚本。</li>
</ol>
</li>
<li>仅适用于外部脚本: 如果 <code>&lt;script&gt;</code> 脚本没有 src，则会忽略 async 特性</li>
<li>由于其完全独立的特性，所以很适用于独立的第三方脚本</li>
</ul>
</li>
<li>参考：<a href="https://zh.javascript.info/script-async-defer"  target="_blank" rel="noopener" >脚本：async，defer</a></li>
</ul>
<h3 id="兼容">兼容</h3>
<ul>
<li>例:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;paste&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="c1">//兼容不同浏览器中获取剪贴板数据的方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kd">let</span> <span class="nx">paste</span> <span class="o">=</span> <span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">clipboardData</span> <span class="o">||</span> <span class="nb">window</span><span class="p">.</span><span class="nx">clipboardData</span><span class="p">).</span><span class="nx">getData</span><span class="p">(</span><span class="s2">&#34;text&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">paste</span> <span class="o">=</span> <span class="nx">paste</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">selection</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">getSelection</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">selection</span><span class="p">.</span><span class="nx">rangeCount</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span> <span class="c1">//检查是否存在文本范围
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">selection</span><span class="p">.</span><span class="nx">deleteFromDocument</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">selection</span><span class="p">.</span><span class="nx">getRangeAt</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">insertNode</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">createTextNode</span><span class="p">(</span><span class="nx">paste</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="nx">selection</span><span class="p">.</span><span class="nx">collapseToEnd</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="不同文件在浏览器中的存放形式和加载机制">不同文件在浏览器中的存放形式和加载机制</h3>
<ol>
<li>
<p>HTML 文件</p>
<ul>
<li>
<p><strong>存放形式</strong>：</p>
<ul>
<li>HTML 文件是文本文件，包含网页的结构化内容。浏览器解析 HTML 文件时，会构建一个 DOM 树（Document Object Model），该树表示页面的内容和结构。</li>
</ul>
</li>
<li>
<p><strong>加载机制</strong>：</p>
<ul>
<li>浏览器首先会加载 HTML 文件，并根据它来确定其他资源（如 CSS、JavaScript、图片）的加载顺序。</li>
<li>HTML 文件可以包含 <code>&lt;script&gt;</code> 标签加载 JavaScript 文件和 <code>&lt;link&gt;</code> 标签加载 CSS 文件。这些资源文件可能是同步加载，也可能是异步加载。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>CSS 文件</p>
<ul>
<li>
<p><strong>存放形式</strong>：</p>
<ul>
<li>CSS 文件通常是外部链接的静态文件，包含网页的样式定义。浏览器会根据 CSS 文件构建 CSSOM（CSS Object Model）。</li>
</ul>
</li>
<li>
<p><strong>加载机制</strong>：</p>
<ul>
<li>浏览器在解析 HTML 时遇到 <code>&lt;link&gt;</code> 标签引用的 CSS 文件，会<strong>同步加载</strong>这些文件，CSS 文件的加载会阻塞页面的渲染，直到所有 CSS 被加载和解析完毕。</li>
<li>浏览器结合 DOM 和 CSSOM 构建渲染树，并根据渲染树对页面进行布局和绘制。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>JavaScript 文件</p>
<ul>
<li>
<p><strong>存放形式</strong>：</p>
<ul>
<li>JavaScript 文件是纯文本文件，通常会以外部文件的形式引用。浏览器会在解析过程中执行 JavaScript 代码，这些代码可以操作 DOM 树和 CSSOM 树。</li>
</ul>
</li>
<li>
<p><strong>加载机制</strong>：</p>
<ul>
<li>如果 <code>&lt;script&gt;</code> 标签没有 <code>async</code> 或 <code>defer</code> 属性，JavaScript 文件会被同步加载和执行，阻塞页面的解析和渲染。</li>
<li><code>async</code> 属性允许脚本文件异步加载，不会阻塞 HTML 的解析。</li>
<li><code>defer</code> 属性也允许异步加载，但脚本执行会在 HTML 完全解析后进行。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>图片、字体、音视频文件</p>
<ul>
<li>
<p><strong>存放形式</strong>：</p>
<ul>
<li>这些文件通常是二进制文件，存储的是图像、字体、视频或音频数据。浏览器通过 URL 引用这些资源。</li>
</ul>
</li>
<li>
<p><strong>加载机制</strong>：</p>
<ul>
<li>图片、音视频等文件的加载是异步的，不会阻塞 HTML 或 CSS 的解析。</li>
<li>浏览器会根据资源的大小、网络带宽和页面布局优先级决定资源的加载顺序。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>缓存机制</p>
<ul>
<li>浏览器会将静态资源（如 CSS、JavaScript、图片等）缓存在本地，以加快后续的加载速度。</li>
<li>缓存策略可以通过 HTTP 头信息（如 <code>Cache-Control</code>、<code>ETag</code> 等）进行控制。文件修改时可以通过版本控制（如文件名哈希）来强制浏览器重新加载新版本的文件。</li>
</ul>
</li>
</ol>
<h2 id="测试">测试</h2>
<ul>
<li>参考 <a href="https://x.com/chenenpei/status/1848673102215188690"  target="_blank" rel="noopener" >陈恩培 on X</a></li>
</ul>
<hr>
<h2 id="杂项">杂项</h2>
<h3 id="svg">SVG</h3>
<ul>
<li>全称: Scalable Vector Graphics(可缩放矢量图形)</li>
<li>介于DOM和Canvas之间，既提供了图形的绘制能力，又提供了元素的DOM交互能力</li>
<li>特点
<ul>
<li>SVG不存在回流这种布局问题，最多也就是重绘。但是DOM的动画就可能导致回流。</li>
<li>SVG是矢量图形，而Canvas绘制的是位图</li>
<li>当屏幕尺寸越大时，SVG的渲染速度差异不大，但是Canvas的渲染时长明显增加</li>
<li>当绘制对象过多时，SVG的渲染时长指数增加，Canvas保持稳定增长</li>
<li>Canvas不支持DOM事件</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://padaker.com/blog/post/605daf77cb81362ed96f2fca"  target="_blank" rel="noopener" >重学SVG</a></li>
<li><a href="https://padaker.com/blog/post/62300759cb81362ed96f2ff1"  target="_blank" rel="noopener" >超实用教程 - SVG Icon封装</a></li>
</ul>
</li>
</ul>
<h3 id="babel">Babel</h3>
<ul>
<li><a href="https://babeljs.io/"  target="_blank" rel="noopener" >Babel · Babel</a></li>
</ul>
<h3 id="jwt-json-web-token">JWT (Json Web Token)</h3>
<p>见[进一步学习jwt]</p>
<h3 id="路由">路由</h3>
<ul>
<li><code>pushState</code>
<ul>
<li>在改变url的同时向浏览器历史栈中压入新的历史记录,且不会重新加载页面</li>
<li>接受三个参数：状态对象，新状态的标题和可选的相对URL(不能跨域，即协议，域名，端口必须都是相同的)</li>
</ul>
</li>
<li><code>replaceState</code></li>
<li><code>popState</code>
<ul>
<li>在浏览器提供的history对象上还有go, back方法，用以模拟用户点击浏览器的前进后退按钮。在某个web应用当中，比如点击了<!-- raw HTML omitted -->标签，发生了页面的跳转。这时调用history.back()方法后页面回退，同时页面发生刷新,这时window.onpopstate无法监听这个事件。但是如果是通过pushState或者replaceState来改变URL且不发生浏览器刷新的话，再使用history.back()或history.go(),这样popstate事件会被触发。</li>
</ul>
</li>
<li>参考
<ul>
<li><a href="https://www.cnblogs.com/xuzhudong/p/8886752.html"  target="_blank" rel="noopener" >前端路由的实现(三) —— History的pushState和replaceState用法 - baoyadong - 博客园</a></li>
</ul>
</li>
</ul>
<h3 id="瀑布流">瀑布流</h3>
<p>如何实现的长列表？
瀑布流 如何实现的长列表？
你是如何判断谁是底部元素的？
如果一次只请求10条数据，前端只展示了5条数据，如何判断底部元素的交叉状态？</p>
<h3 id="git-merge和-git-rebase的区别">git merge和 git rebase的区别</h3>
<h3 id="实现一个dialog模板">实现一个Dialog模板</h3>
<p><a href="https://blog.csdn.net/qq_45856669/article/details/126577449"  target="_blank" rel="noopener" >面试题：React实现一个Dialog模板_react dialog-CSDN博客</a></p>
<h3 id="实现个栈用了好几种方法实现包括最原始的单链表还讲了讲symbol等乱七八糟的东西">实现个栈（用了好几种方法实现，包括最原始的单链表），还讲了讲symbol等乱七八糟的东西</h3>
<h3 id="jsbridge原理">jsBridge原理</h3>
<h3 id="如何把一个对象变成可迭代对象实现symboliteractor属性">如何把一个对象变成可迭代对象（实现[Symbol.iteractor]属性）</h3>
<h3 id="proxy对象能拦截什么">Proxy对象能拦截什么</h3>
<h3 id="jss">jss</h3>
<ul>
<li><a href="https://cssinjs.org/?v=v10.10.1"  target="_blank" rel="noopener" >JSS</a></li>
</ul>
<h3 id="字体反爬">字体反爬</h3>
<ul>
<li><a href="https://www.shymean.com/article/%E5%89%8D%E7%AB%AF%E5%AD%97%E4%BD%93%E5%8F%8D%E7%88%AC%E5%8E%9F%E7%90%86"  target="_blank" rel="noopener" >前端字体反爬原理 | ShyMean</a></li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://smileyqp.github.io/frontend_book/"  target="_blank" rel="noopener" >前端基础知识 · GitBook</a></li>
<li><a href="https://github.com/miracle90/Interview/tree/master"  target="_blank" rel="noopener" >miracle90/Interview: 前端八股文大全！</a></li>
<li><a href="https://vue3js.cn/interview/"  target="_blank" rel="noopener" >web前端面试 - 面试官系列</a></li>
<li><a href="https://bgww.apachecn.org/"  target="_blank" rel="noopener" >【布客】八股文知识库</a></li>
<li><a href="https://yingkaixiang.github.io/blog/"  target="_blank" rel="noopener" >Yingkaixiang&rsquo;s Blog</a></li>
<li><a href="https://zh.javascript.info/"  target="_blank" rel="noopener" >现代 JavaScript 教程</a></li>
<li><a href="https://tsejx.github.io/javascript-guidebook//"  target="_blank" rel="noopener" >JavaScript Guidebook</a></li>
<li><a href="https://github.com/yiliang114/Blog/issues/1"  target="_blank" rel="noopener" >前端校招知识点总结 · Issue #1 · yiliang114/Blog</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>记一次react报错排查</title>
      <link>https://ds63.eu.org/2024/a-react-debug-experience/</link>
      <pubDate>Thu, 07 Mar 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/a-react-debug-experience/</guid>
      <description>Failed to execute &amp;lsquo;removeChild&amp;rsquo; on &amp;lsquo;Node&amp;rsquo;</description>
      <content:encoded><![CDATA[<h2 id="场景">场景</h2>
<p>在<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid: A lightweight tool offering key functionalities inspired by Postman.</a>,当我发送一次请求之后，再次发送时报错：</p>
<blockquote>
<p>NotFoundError: Failed to execute &lsquo;removeChild&rsquo; on &lsquo;Node&rsquo;: The node to be removed is not a child of this node.</p>
</blockquote>
<h2 id="排查">排查</h2>
<p>因为上一个版本并没有这个问题，于是我比较了这几次的commit记录，发现问题很可能出现在Prism的高亮，相关代码如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">response</span> <span class="o">&amp;&amp;</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">Prism</span><span class="p">.</span><span class="nx">highlightAll</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[</span><span class="nx">response</span><span class="p">]);</span>
</span></span></code></pre></div><p>当我将<code>Prism.highlightAll();</code>注释掉后，程序就不再报错了，但这显然不是我所希望的。几经查找后，发现了<a href="https://juejin.cn/post/6938321875298680845"  target="_blank" rel="noopener" >Failed to execute &lsquo;removeChild&rsquo; on &lsquo;Node&rsquo; - 掘金</a>解决了我的问题，在<code>pre code</code>外加一层<code>&lt;div&gt;</code>就解决了。</p>
<p>该篇文章也给出了一定的解释:</p>
<blockquote>
<p>经过分析发现是使用组件的问题，考虑DOM-DIff算法是比对不同的React节点，而该组件的渲染直接是第三方插件的代码，在componentDidMount阶段才进行DOM节点的挂载，在此之前是没有node节点的，故需要增加一个可识别的node节点。</p>
</blockquote>
<p>但对来说比较简略，我希望能彻底搞懂相关的概念，以下是我的笔记。</p>
<h2 id="lifecycle">Lifecycle</h2>
<h3 id="there-phases">there phases</h3>
<ol>
<li>mounting: initial render</li>
<li>updating: is triggered when the props are updated or when the state is updated</li>
<li>unmounting: when the component is removed from the DOM</li>
</ol>
<h3 id="methods">methods</h3>
<ul>
<li>Each phase has specific methods responsible for a particular stage in a component&rsquo;s lifecycle. These methods <strong>are technically particular to class-based components</strong> and not intended for functional components.</li>
<li><a href="https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/"  target="_blank" rel="noopener" >React lifecycle methods diagram</a></li>
<li><code>shouldComponentUpdate</code> -&gt; <code>useMemo</code>、 <code>memo</code></li>
<li>&ldquo;Commit phase&quot;中的三个方法,Can work with DOM, run side effects, schedule updates：
<ol>
<li><code>componentDidMount</code> -&gt; the useEffect hook with the second argument of []</li>
<li><code>componentDidUpdate</code> -&gt; the useEffect hook with the second argument of [state]</li>
<li><code>componentWillUnmount</code> -&gt; <strong>return a function</strong> that runs on unmounting inside the useEffect function,例:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">    <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Bye&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="p">[]);</span>
</span></span></code></pre></div></li>
</ul>
<h2 id="虚拟dom-virtual-document-object-model">虚拟DOM （Virtual Document Object Model）</h2>
<p>在React中，当状态（state）发生变化时，React并不直接操作真实的DOM来更新页面，而是先在内存中构建一个虚拟DOM树，然后通过比较虚拟DOM树和之前渲染的虚拟DOM树之间的差异，最终计算出最小的DOM操作，并将这些操作批量应用到真实的DOM上。</p>
<h3 id="虚拟dom节点可能包含的详细信息">虚拟DOM节点可能包含的详细信息</h3>
<ol>
<li><strong>type</strong>：节点类型可以是元素节点、文本节点或者组件节点。</li>
<li><strong>props</strong>：节点可能包含一些属性，这些属性描述了节点的特征，比如元素节点的class、id、style等属性，以及事件处理函数等。chidren 是 props 中的一个属性，它存储了当前组件的孩子节点，可以是数组（多个孩子节点）或对象（只有一个孩子节点）</li>
<li><strong>key</strong>：用于在DOM的重渲染过程中标识节点的唯一性，有助于React在进行差异比较时准确找到对应的节点。</li>
<li><strong>ref</strong>：用于获取节点的引用，通常用于在组件中操作DOM节点。</li>
<li><strong>owner</strong>: 所属的Component</li>
<li>其他</li>
</ol>
<h3 id="diff算法">diff算法</h3>
<ul>
<li>比较当前的虚拟DOM树和状态变更将要重新渲染时生成的虚拟DOM树的算法。</li>
<li>参考<a href="https://xie.infoq.cn/article/65e938d933cc751fcc008942d"  target="_blank" rel="noopener" >谈谈虚拟DOM，Diff算法与Key机制_React_beifeng1996_InfoQ写作社区</a></li>
<li>关键：
<ol>
<li>深度优先</li>
<li>只对同一级别的元素进行比较</li>
</ol>
</li>
<li>三种diff
<ol>
<li>tree diff : 只是简单进行了删除和创建操作</li>
<li>component diff：
<ul>
<li>使用的是<code>===</code>严格相等。也就是&quot;引用相等性&rdquo;</li>
<li>不同类型 -&gt; 直接替换整个组件下的所有子节点，即销毁原组件，创建新组件。</li>
<li>同一类型 -&gt; 继续判断</li>
</ul>
</li>
<li>element diff: 针对同一层级的所有节点（包括元素节点和组件节点）的 diff 算法
<ul>
<li>三种操作：
<ol>
<li>insert_markup</li>
<li>move_existing</li>
<li>remove_node:</li>
</ol>
</li>
<li>涉及到列表元素顺序的动态变更时，不要用遍历的 index 作为节点的 key 属性值</li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://juejin.cn/post/6938321875298680845"  target="_blank" rel="noopener" >Failed to execute &lsquo;removeChild&rsquo; on &lsquo;Node&rsquo; - 掘金</a></li>
<li><a href="https://www.twilio.com/en-us/blog/react-choose-functional-components"  target="_blank" rel="noopener" >Understanding Functional Components vs. Class Components in React</a></li>
<li><a href="https://retool.com/blog/the-react-lifecycle-methods-and-hooks-explained"  target="_blank" rel="noopener" >The React lifecycle: methods and hooks explained</a></li>
<li><a href="https://xie.infoq.cn/article/65e938d933cc751fcc008942d"  target="_blank" rel="noopener" >React面试：谈谈虚拟DOM，Diff算法与Key机制_React_beifeng1996_InfoQ写作社区</a></li>
<li><a href="https://prin.pw/react-unstable-nested-components"  target="_blank" rel="noopener" >真的不可以在 React 组件内部嵌套定义子组件吗？ - PRIN BLOG</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理</title>
      <link>https://ds63.eu.org/2024/javascript_points/</link>
      <pubDate>Wed, 06 Mar 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points/</guid>
      <description>自己学习过程中整理的关于JavaScript的知识点</description>
      <content:encoded><![CDATA[<p><strong>本文记录了我学习过程中整理的关于JavaScript的知识点,以摘抄为主，绝大部分非原创。未能全部都标明出处，在此致歉</strong></p>
<h2 id="历史">历史</h2>
<ul>
<li><a href="https://wangdoc.com/javascript/basic/history"  target="_blank" rel="noopener" >JavaScript 语言的历史 - JavaScript 教程 - 网道</a></li>
</ul>
<h2 id="双等号和三等号和objectis">双等号和三等号和Object.is</h2>
<ul>
<li><code>==</code> 只比较值是否相等。在比较数值之前，它将变量的类型转换为相互匹配</li>
<li><code>===</code> 不执行类型转换。它将验证被比较的变量是否具有相同的值和相同的类型。</li>
<li><code>Object.is()</code>
<ul>
<li>与 == 运算符并不等价: Object.is() 不会对其操作数进行类型转换</li>
<li>也不等价于 === 运算符: 唯一区别在于它们处理带符号的 0 和 NaN 值的时候。=== 运算符（和 == 运算符）将数值 -0 和 +0 视为相等，但是会将 NaN 视为彼此不相等</li>
</ul>
</li>
</ul>
<h3 id="示例">示例</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">number</span> <span class="o">=</span> <span class="mi">1234</span> 
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">stringNumber</span> <span class="o">=</span> <span class="s1">&#39;1234&#39;</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">number</span> <span class="o">==</span> <span class="nx">stringNumber</span><span class="p">)</span> <span class="c1">//true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">number</span> <span class="o">===</span> <span class="nx">stringNumber</span><span class="p">)</span>  <span class="c1">//false  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="kc">false</span><span class="p">)</span> <span class="c1">//true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="mi">0</span> <span class="o">===</span> <span class="kc">false</span><span class="p">)</span> <span class="c1">//false 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">str</span> <span class="o">==</span> <span class="kc">false</span><span class="p">)</span> <span class="c1">//true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">str</span> <span class="o">===</span> <span class="kc">false</span><span class="p">)</span> <span class="c1">//false
</span></span></span></code></pre></div><h3 id="参考">参考</h3>
<ul>
<li><a href="https://www.freecodecamp.org/news/javascript-triple-equals-sign-vs-double-equals-sign-comparison-operators-explained-with-examples/"  target="_blank" rel="noopener" >JavaScript Triple Equals Sign VS Double Equals Sign – Comparison Operators Explained with Examples</a></li>
</ul>
<hr>
<h2 id="-and-">? and ??</h2>
<ul>
<li><code>?</code>  可选链操作符（Optional Chaining Operator）
<ul>
<li>用于简化访问嵌套对象属性时的代码，可以安全地访问深度嵌套的属性，避免因为中间属性不存在而导致的错误。</li>
</ul>
</li>
<li><code>??</code> 空值合并操作符（Nullish Coalescing Operator），用于提供默认值
<ul>
<li>当左侧操作数为null或undefined时，返回右侧操作数，否则返回左侧操作数。</li>
<li>与逻辑或（||）操作符不同，空值合并操作符只在左侧操作数为null或undefined时返回右侧操作数，对于其他假值（如0、&lsquo;&lsquo;等）不会触发返回右侧操作数。</li>
<li><a href="https://jordaneldredge.com/blog/defaulting-to-empty-string-is-a-code-smell/"  target="_blank" rel="noopener" >?? &quot;&quot; is a Code Smell / Jordan Eldredge</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="静态属性和静态方法">静态属性和静态方法</h2>
<ul>
<li>静态方法用于实现属于整个类，但不属于该类任何实例的函数。
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Article</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">constructor</span><span class="p">(</span><span class="nx">title</span><span class="p">,</span> <span class="nx">date</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="nx">title</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">date</span> <span class="o">=</span> <span class="nx">date</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// 静态方法
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">static</span> <span class="nx">compare</span><span class="p">(</span><span class="nx">articleA</span><span class="p">,</span> <span class="nx">articleB</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">articleA</span><span class="p">.</span><span class="nx">date</span> <span class="o">-</span> <span class="nx">articleB</span><span class="p">.</span><span class="nx">date</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 直接将其作为属性赋值的作用相同
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">Article</span><span class="p">.</span><span class="nx">compare</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">articleA</span><span class="p">,</span> <span class="nx">articleB</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">articleA</span><span class="p">.</span><span class="nx">date</span> <span class="o">-</span> <span class="nx">articleB</span><span class="p">.</span><span class="nx">date</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 可以在类上调用，而不是在单个对象上
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">article</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Article</span><span class="p">(</span><span class="s2">&#34;HTML&#34;</span><span class="p">,</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="mi">2019</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">article</span><span class="p">.</span><span class="nx">compare</span><span class="p">()</span> <span class="c1">/// Error: article.createTodays is not a function
</span></span></span></code></pre></div></li>
<li>静态属性
<ul>
<li>等同于直接给类赋值</li>
</ul>
</li>
<li>静态属性和方法是可被继承的。</li>
<li>参考
<ul>
<li><a href="https://zh.javascript.info/static-properties-methods"  target="_blank" rel="noopener" >静态属性和静态方法</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="私有属性">私有属性</h2>
<ul>
<li>私有属性通过添加<code>#</code>前缀来创建，在类的外部无法合法地引用。</li>
<li>私有属性不是原型继承模型的一部分，因为它们只能在当前类内部被访问，而且不能被子类继承。</li>
<li>无法使用方括号表示法动态访问它</li>
<li>访问对象中不存在的私有属性，会抛出 TypeError 错误，而不是像普通属性一样返回 undefined</li>
<li>参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_properties"  target="_blank" rel="noopener" >私有属性 - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="序列化与反序列化">序列化与反序列化</h2>
<ul>
<li>见<a href="https://ds63.eu.org/2024/serialization_and_deserialization"  target="_blank" rel="noopener" >json的序列化与反序列化</a></li>
</ul>
<h2 id="相等性">相等性</h2>
<p>摘自<a href="https://prin.pw/react-unstable-nested-components/#%E5%BC%95%E7%94%A8%E7%9B%B8%E7%AD%89%E6%80%A7%E4%B8%8E%E7%BB%84%E4%BB%B6%E9%87%8D%E6%B8%B2%E6%9F%93"  target="_blank" rel="noopener" >真的不可以在 React 组件内部嵌套定义子组件吗？ - PRIN BLOG</a></p>
<ul>
<li>值相等性 (Value Equality)，即两个值类型一致，内容也一致</li>
<li>引用相等性 (Reference Equality)，即两个对象的引用在内存中指向同一块区域
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 两个长得一样的对象
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Anon Tokyo&#39;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Anon Tokyo&#39;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;引用相等性&#34; 比较 - false
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">a</span> <span class="o">===</span> <span class="nx">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">is</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// &#34;值相等性&#34; 比较 - true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">lodash</span><span class="p">.</span><span class="nx">isEqual</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">b</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span></code></pre></div></li>
<li>React 在比较节点的 type 时，使用的是<code>===</code>严格相等。也就是&quot;引用相等性&quot;</li>
</ul>
<h2 id="commonjs-vs-es6ecmascript-6">CommonJS V.S. ES6（ECMAScript 6）</h2>
<p>参考<a href="https://blog.logrocket.com/commonjs-vs-es-modules-node-js/"  target="_blank" rel="noopener" >CommonJS vs. ES modules in Node.js - LogRocket Blog</a></p>
<p>二者都是JavaScript的模块规范，现代开发中后者用的比较多。</p>
<h2 id="模块化">模块化</h2>
<ul>
<li>CommonJS规范用的是<code>require()</code>,<code>exports</code>组合
<ul>
<li><code>require()</code>本质是函数。需要谁，导入谁，返回值是对象。</li>
<li><code>exports</code>本质是对象。想暴露哪个变量，就给exports增加属性就行</li>
<li><code>module.exports</code> 是NodeJS实现的<code>exports</code>，<code>module.exports = exports</code> ，<code>module.exports</code>每个文件都有，本质是一个实例，所以最后还是以<code>module.exports</code>为准</li>
<li>加载模块是同步的,意味着只有等到对应的模块加载完毕，当前模块中的内容才能被运行</li>
<li>不能直接在浏览器使用，会报错:&lsquo;require is not defined&rsquo;。如果非要直接在浏览器中使用的话，需要browserify插件</li>
</ul>
</li>
<li>ES module用的是<code>import</code>,<code>export</code>组合
<ul>
<li><code>import</code> 本质是一个关键字。特殊情况下也可以当函数<code>import()</code></li>
<li><code>export</code> 本质是关键字。</li>
<li>ES imports are hoisted by spec(which Babel follows)</li>
<li>可选择性加载所需的部分，如<code>import { render } from react</code></li>
<li>异步加载:
有些场景下需要异步加载，比如<a href="https://ds63.eu.org/2024/postkid/#referenceerror-navigator-is-not-defined"  target="_blank" rel="noopener" >Postkid：ReferenceError: navigator is not defined | EuDs&rsquo;s Blog</a>
代码示例:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 当flag为true的时候才导入某个模块  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">flag</span> <span class="o">=</span> <span class="kc">true</span>  
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">flag</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">  <span class="c1">// import time from &#34;./module.js&#34; // NG: 一段解析阶段的代码放到了运行阶段去执行
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// 因为是异步加载 非同步 有个返回值 返回值是promise  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">promise</span> <span class="o">=</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;./module.js&#34;</span><span class="p">)</span>   
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)=&gt;{</span>  
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">res</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="p">})</span>  
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="k">catch</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span></code></pre></div></li>
<li><code>import</code>可以在JavaScript可以直接使用，但是如果想直接在script中使用src的方式引入的话，需要指定<code>type=&quot;module&quot;</code>，声明引入的是一个js模块。</li>
</ul>
</li>
<li><strong>可以混用</strong>：<code>babel</code>之类的编译会将其统一编译成特定规范,但最好不要混用</li>
<li>参考
<ul>
<li><a href="https://chihokyo.com/post/35/"  target="_blank" rel="noopener" >彻底搞清楚JS的模块化import/export/require&hellip;问题| 旺财的博客</a></li>
<li><a href="https://juejin.cn/post/6844904114183208968"  target="_blank" rel="noopener" >干货:import和require如何在项目中混用 - 掘金</a></li>
<li><a href="https://robin-front.github.io/2017/07/10/dont-mixin-import-and-require.html"  target="_blank" rel="noopener" >不要混用 import 和 require | 知更鸟</a></li>
<li><a href="https://daotin.netlify.app/qe8yn8.html"  target="_blank" rel="noopener" >关于require和import的疑问 | 道廷途说</a></li>
<li><a href="https://juejin.cn/post/6969800612519084063"  target="_blank" rel="noopener" >几分钟了解js的模块化、IIFE。几分钟了解模块化： 1. CommonJS 2. AMD 3. CMD 4. ES6 - 掘金</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="iife立即调用函数表达式">IIFE（立即调用函数表达式）</h2>
<ul>
<li>参考<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/IIFE"  target="_blank" rel="noopener" >IIFE（立即调用函数表达式）| MDN</a></li>
<li>一种设计模式</li>
<li>示例：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">foo</span> <span class="o">=</span> <span class="s1">&#39;hello&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">foo</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">foo</span> <span class="o">=</span> <span class="nx">foo</span> <span class="o">||</span> <span class="s1">&#39;world&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">foo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 依次输出 hello hello hello
</span></span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="作用域执行上下文词法环境">作用域，执行上下文，词法环境</h2>
<p>wip</p>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/7043408377661095967"  target="_blank" rel="noopener" >彻底搞懂作用域、执行上下文、词法环境 - 掘金</a></li>
<li><a href="https://zh.javascript.info/closure"  target="_blank" rel="noopener" >变量作用域，闭包</a></li>
</ul>
<h2 id="闭包">闭包</h2>
<h3 id="概念">概念</h3>
<ul>
<li>闭包是由函数以及声明该函数的词法环境组合而成的，该环境包含了这个闭包创建时作用域内的任何局部变量。</li>
</ul>
<h3 id="示例-1">示例:</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">makeAdder</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">add5</span> <span class="o">=</span> <span class="nx">makeAdder</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">add10</span> <span class="o">=</span> <span class="nx">makeAdder</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">add5</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span> <span class="c1">// 7
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">add10</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span> <span class="c1">// 12
</span></span></span></code></pre></div><h3 id="作用一--模拟私有方法">作用一:  模拟私有方法</h3>
<ul>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">makeCounter</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">privateCounter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kd">function</span> <span class="nx">changeBy</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">privateCounter</span> <span class="o">+=</span> <span class="nx">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">increment</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">changeBy</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">decrement</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">changeBy</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">value</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">privateCounter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">Counter1</span> <span class="o">=</span> <span class="nx">makeCounter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">Counter2</span> <span class="o">=</span> <span class="nx">makeCounter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Counter1</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span> <span class="cm">/* logs 0 */</span>
</span></span><span class="line"><span class="cl"><span class="nx">Counter1</span><span class="p">.</span><span class="nx">increment</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">Counter1</span><span class="p">.</span><span class="nx">increment</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Counter1</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span> <span class="cm">/* logs 2 */</span>
</span></span><span class="line"><span class="cl"><span class="nx">Counter1</span><span class="p">.</span><span class="nx">decrement</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Counter1</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span> <span class="cm">/* logs 1 */</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Counter2</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span> <span class="cm">/* logs 0 */</span>
</span></span></code></pre></div></li>
<li>现在可以通过在属性名之前添加# 前缀来创建，在类的外部无法合法地引用</li>
</ul>
<h3 id="输出题">输出题</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">create</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">200</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="nx">alert</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">fn</span> <span class="o">=</span> <span class="nx">create</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nx">fn</span><span class="p">()</span> <span class="c1">//200
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">invoke</span><span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">200</span>
</span></span><span class="line"><span class="cl">  <span class="nx">fn</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">fn</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">invoke</span><span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="c1">//100
</span></span></span></code></pre></div><h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures"  target="_blank" rel="noopener" >闭包 - JavaScript | MDN</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_properties"  target="_blank" rel="noopener" >私有属性 - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="提升">提升</h2>
<h3 id="会被提升">会被提升</h3>
<ol>
<li>变量的声明会被提升到当前作用域的顶端</li>
<li>函数声明和初始化都会被提升</li>
</ol>
<h3 id="不会被提升">不会被提升</h3>
<ol>
<li>变量的初始化不会被提升</li>
<li>函数表达式不会被提升</li>
</ol>
<h3 id="顺序">顺序</h3>
<ol>
<li>函数提升在变量提升之前</li>
<li>变量被提升过后，先对提升上来的所有对象统一执行一遍声明步骤，然后再对变量执行一次赋值步骤。而执行赋值步骤时，会优先执行函数变量的赋值步骤，再执行普通变量的赋值步骤</li>
</ol>
<h3 id="示例-2">示例</h3>
<ol>
<li>示例一</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">foo</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">hoistVariable</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">foo</span> <span class="o">=</span> <span class="nx">foo</span> <span class="o">||</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// 5
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">hoistVariable</span><span class="p">();</span>
</span></span></code></pre></div><ol start="2">
<li>示例二：函数表达式不会被提升</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span><span class="p">);</span> <span class="c1">// undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span><span class="p">(</span><span class="mi">5</span><span class="p">));</span> <span class="c1">// square is not a function =》 初始化并未提升，此时 square 值为 undefined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">square</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">n</span> <span class="o">*</span> <span class="nx">n</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="3">
<li>示例二: 顺序</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// 源代码
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">b</span><span class="p">(){};</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">b</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">typeof</span> <span class="nx">b</span><span class="p">;</span> <span class="c1">// number
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">//预编译后
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">b</span><span class="p">;</span>  <span class="c1">// =&gt; 声明一个function b
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">b</span><span class="p">;</span>       <span class="c1">// =》 声明一个变量 b
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">b</span> <span class="o">=</span> <span class="p">(){};</span>    <span class="c1">// =》 function b 初始化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">b</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>      <span class="c1">// =》 变量 b 初始化 =》变量初始化没有被提升，还在原位
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">typeof</span> <span class="nx">b</span><span class="p">;</span>    <span class="c1">// number
</span></span></span></code></pre></div><ol start="4">
<li>示例三: 顺序</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">a</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span><span class="nx">a</span><span class="o">=</span><span class="nx">a</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">a</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">a</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">a</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span><span class="nx">a</span><span class="o">=</span><span class="nx">a</span><span class="o">+</span><span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">d</span> <span class="o">=</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span><span class="nx">b</span><span class="p">,</span><span class="nx">c</span><span class="p">,</span><span class="nx">d</span><span class="p">);</span> <span class="c1">//1，3，3，3
</span></span></span></code></pre></div><h3 id="参考-3">参考</h3>
<ul>
<li><a href="https://segmentfault.com/a/1190000038344251"  target="_blank" rel="noopener" >JavaScript变量提升和函数提升详解</a></li>
</ul>
<hr>
<h2 id="var-let-const">Var, Let, Const</h2>
<h3 id="作用域">作用域</h3>
<ul>
<li>var 声明是全局作用域或函数作用域</li>
<li>let 和 const 是块作用域。</li>
</ul>
<h3 id="变化">变化</h3>
<ul>
<li>var 变量可以在其作用域内更新和重新声明</li>
<li>let 变量可以更新但不能重新声明</li>
<li>const 变量既不能更新也不能重新声明。</li>
</ul>
<h3 id="提升-1">提升:</h3>
<ul>
<li>它们都被提升到了作用域的顶部。</li>
<li>var 变量是用 undefined 初始化的</li>
<li>而 let 和 const 变量不会被初始化,在代码实际执行到声明和初始化语句之前，它们的值是不可访问的。</li>
</ul>
<h3 id="声明">声明</h3>
<ul>
<li>var 和 let 可以在不初始化的情况下声明，而 const 必须在声明时初始化。</li>
<li>var可以重复声明
<ul>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">haha</span> <span class="o">=</span> <span class="s1">&#39;666&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">haha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">haha</span><span class="p">);</span> <span class="c1">// 666
</span></span></span></code></pre></div></li>
<li>原因:
<ol>
<li>编译器在对代码进行拆解的时候，遇到了var定义的变量会首先询问作用域中是否存在这个变量</li>
<li>不存在就让作用域创建变量，如果存在就忽略var继续编译</li>
<li>赋值时haha=&lsquo;666&rsquo;被执行，第二个var haha被编译器忽略了。</li>
</ol>
</li>
</ul>
</li>
</ul>
<h3 id="示例-3">示例:</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">greeting</span> <span class="o">=</span> <span class="s2">&#34;say Hi&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">greeting</span> <span class="o">=</span> <span class="s2">&#34;say Hello instead&#34;</span><span class="p">;</span> <span class="c1">// error: Identifier &#39;greeting&#39; has already been declared
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">y</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span> <span class="c1">// y在if块内部可见
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">y</span><span class="p">);</span> <span class="c1">// 输出: 20
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">y</span><span class="p">);</span> <span class="c1">// 输出: 20
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">b</span><span class="p">;</span> <span class="c1">// Cannot access &#39;b&#39; before initialization
</span></span></span></code></pre></div><h3 id="输出题-1">输出题</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">      <span class="kd">let</span> <span class="nx">$body</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElemnetById</span><span class="p">(</span><span class="s1">&#39;body&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="kd">let</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="kd">let</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">length</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span> <span class="nx">domA</span>
</span></span><span class="line"><span class="cl">      <span class="k">for</span> <span class="p">(</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">domA</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="o">&lt;</span><span class="nx">a</span><span class="o">&gt;</span><span class="nx">$</span><span class="p">{</span><span class="nx">i</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/a&gt; )</span>
</span></span><span class="line"><span class="cl">      <span class="nx">$body</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">domA</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">domA</span><span class="p">.</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">alert</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 输出的都是5
</span></span></span></code></pre></div><ul>
<li>由于 i 是在循环外定义的，这里会导致在点击时总是弹出循环结束时的值（5）</li>
<li>可以通过使用闭包或 let 来解决这个问题。</li>
</ul>
<h3 id="参考-4">参考</h3>
<ul>
<li><a href="https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/"  target="_blank" rel="noopener" >Var, Let, and Const – What&rsquo;s the Difference?</a></li>
</ul>
<hr>
<h2 id="rest参数-与-spread-语法">Rest参数 与 Spread 语法</h2>
<ul>
<li>参考<a href="https://zh.javascript.info/rest-parameters-spread"  target="_blank" rel="noopener" >Rest 参数与 Spread 语法</a></li>
<li>Rest参数用来从参数列表中获取数组</li>
<li>Rest 参数必须放到参数列表的末尾</li>
<li>箭头函数没有 &ldquo;arguments&rdquo;</li>
<li>spread 语法把数组转换为参数列表</li>
<li>举例:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="c1">// Rest参数用来从参数列表中获取数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">sumAll</span> <span class="o">=</span> <span class="p">(...</span><span class="nx">args</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">arg</span> <span class="k">of</span> <span class="nx">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">sum</span> <span class="o">+=</span> <span class="nx">arg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">sum</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">sumAll</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// spread 语法把数组转换为参数列表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">array</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">sumAll</span><span class="p">(...</span><span class="nx">array</span><span class="p">)</span>
</span></span></code></pre></div><h2 id="深拷贝和浅拷贝">深拷贝和浅拷贝</h2>
<h3 id="数据存储">数据存储</h3>
<ol>
<li>基本类型数据保存在在栈内存中</li>
<li>引用类型数据保存在堆内存中，引用数据类型的变量是一个指向堆内存中实际对象的引用，存在栈中</li>
</ol>
<h3 id="浅拷贝">浅拷贝</h3>
<ul>
<li>
<p>定义: 只复制属性指向某个对象的指针，而不复制对象本身，新旧对象还是共享同一块内存，修改对象属性会影响原对象</p>
</li>
<li>
<p>区别于<code>=</code>:</p>
<ul>
<li><code>=</code>赋值操作只是复制引用，两个变量指向同一个对象。</li>
<li>浅拷贝创建一个新对象，但对于嵌套的引用类型仍然共享同一个引用。</li>
</ul>
</li>
<li>
<p>实现一</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">shallowCopy</span><span class="p">(</span><span class="nx">obj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">obj</span> <span class="o">!==</span> <span class="s1">&#39;object&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">newObj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">key</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">newObj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">newObj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>实现二</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">shallowCopy</span><span class="p">(</span><span class="nx">obj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{...</span><span class="nx">obj</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>实现三</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">a</span><span class="o">:</span><span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">b</span><span class="o">:</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Object.assign: 将源对象的可枚举属性复制到目标对象，适合合并多个对象。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">obj1</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">({},</span><span class="nx">obj</span><span class="p">);</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="深拷贝">深拷贝</h3>
<ul>
<li>定义: 创造一个一模一样的对象，新对象跟原对象不共享内存，修改新对象不会影响原对象</li>
<li>实现一
<ul>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">deepCopy</span><span class="p">(</span><span class="nx">obj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">obj</span> <span class="o">!==</span> <span class="s1">&#39;object&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">newObj</span> <span class="o">=</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="o">?</span> <span class="p">[]</span> <span class="o">:</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">key</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">newObj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">deepCopy</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>缺陷:
<ol>
<li>无法处理循环引用</li>
<li>递归爆栈</li>
</ol>
</li>
</ul>
</li>
<li>实现二:
<ul>
<li>代码</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">cloneForce</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">uniqueList</span> <span class="o">=</span> <span class="p">[];</span> <span class="c1">// 用来去重
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">let</span> <span class="nx">root</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 栈
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">loopList</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">parent</span><span class="o">:</span> <span class="nx">root</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">key</span><span class="o">:</span> <span class="kc">undefined</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">data</span><span class="o">:</span> <span class="nx">x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="nx">loopList</span><span class="p">.</span><span class="nx">length</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// dfs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kr">const</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">loopList</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="p">{</span><span class="nx">parent</span><span class="p">,</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">data</span><span class="p">}</span> <span class="o">=</span> <span class="nx">node</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 初始化赋值目标
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">let</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">parent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">key</span> <span class="o">!==</span> <span class="s1">&#39;undefined&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="nx">res</span> <span class="o">=</span> <span class="nx">parent</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nx">uniqueData</span> <span class="o">=</span> <span class="nx">find</span><span class="p">(</span><span class="nx">uniqueList</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nx">uniqueData</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 数据已经存在
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">parent</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">uniqueData</span><span class="p">.</span><span class="nx">target</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 数据不存在
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">uniqueList</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">            <span class="nx">source</span><span class="o">:</span> <span class="nx">data</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">target</span><span class="o">:</span> <span class="nx">res</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">k</span> <span class="k">in</span> <span class="nx">data</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">k</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">data</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">===</span> <span class="s1">&#39;object&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">loopList</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">                        <span class="nx">parent</span><span class="o">:</span> <span class="nx">res</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="nx">key</span><span class="o">:</span> <span class="nx">k</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span><span class="p">[</span><span class="nx">k</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                    <span class="p">});</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span><span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">res</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">k</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">root</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">find</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="nx">item</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">source</span> <span class="o">===</span> <span class="nx">item</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>clone
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">clone</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">getPrototypeOf</span><span class="p">(</span><span class="nx">obj</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyDescriptors</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="structuredclone"><code>structuredClone()</code></h3>
<ul>
<li>creates a deep clone of a given value using the structured clone algorithm.</li>
<li>能保留循环引用</li>
<li>clone不了的
<ol>
<li>函数不能被克隆</li>
<li>DOM 节点不能克隆</li>
<li>属性描述符 setter和getter 不能克隆</li>
</ol>
</li>
<li>参考
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone"  target="_blank" rel="noopener" >Window: structuredClone() method - Web APIs | MDN</a></li>
<li><a href="https://blogweb.cn/article/2213672068912#heading-3"  target="_blank" rel="noopener" >你还在用传统方法进行深浅拷贝？教你一种更现代的方法！-网络日志</a></li>
</ul>
</li>
</ul>
<h3 id="参考-5">参考</h3>
<ul>
<li><a href="https://vue3js.cn/interview/JavaScript/copy.html"  target="_blank" rel="noopener" >面试官：深拷贝浅拷贝的区别？如何实现一个深拷贝？ | web前端面试 - 面试官系列</a></li>
</ul>
<hr>
<h2 id="复制">复制</h2>
<ul>
<li>
<p>参考 <a href="https://juejin.cn/post/6844903567480848391"  target="_blank" rel="noopener" >JavaScript复制内容到剪贴板 - 掘金</a></p>
</li>
<li>
<p>补充：</p>
<ol>
<li>上文主要是使用<code>document.execCommand('copy')</code>这个方法。但<a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand"  target="_blank" rel="noopener" >Document: execCommand() method - Web APIs | MDN</a>显示&quot;This feature is no longer recommended.&quot;。</li>
<li>那该怎么改呢？看<a href="https://stackoverflow.com/questions/60581285/execcommand-is-now-obsolete-whats-the-alternative"  target="_blank" rel="noopener" >execCommand() is now obsolete, what&rsquo;s the alternative? - Stack Overflow</a>的高票回答:</li>
</ol>
<blockquote>
<p>The execCommand() is officially obsolete/deprecated but there&rsquo;s no alternative.
Note that real world user agents (browsers such as Chrome, Firefox and Safari) cannot drop support for execCommand() because so many services require support for it.</p>
</blockquote>
<p>过几年再看看？</p>
</li>
</ul>
<hr>
<h2 id="读取剪贴板">读取剪贴板</h2>
<p>wip</p>
<hr>
<h2 id="javascript编程中常见的代码坏味道">JavaScript编程中常见的代码坏味道</h2>
<p>wip</p>
<h3 id="pyramid-of-doom厄运金字塔">Pyramid of doom（厄运金字塔）</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Pyramid_of_doom_%28programming%29"  target="_blank" rel="noopener" >厄运金字塔（编程）- 维基百科 &mdash; Pyramid of doom (programming) - Wikipedia</a></li>
</ul>
<hr>
<h2 id="proxy">Proxy</h2>
<p>wip</p>
<h3 id="参考-6">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy"  target="_blank" rel="noopener" >Proxy - JavaScript | MDN</a></li>
<li><a href="https://segmentfault.com/a/1190000043453516"  target="_blank" rel="noopener" >javascript - Proxy详解 - 个人文章 - SegmentFault 思否</a></li>
</ul>
<hr>
<h2 id="reflect">Reflect</h2>
<p>wip</p>
<h3 id="参考-7">参考</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect"  target="_blank" rel="noopener" >Reflect - JavaScript | MDN</a></li>
</ul>
<h2 id="问题">问题</h2>
<ol>
<li>
<p>js到dom树的单向绑定</p>
</li>
<li>
<p><a href="https://blog.csdn.net/SpringRolls/article/details/116506148"  target="_blank" rel="noopener" >牛客网ACM模式下JavaScript(V8)常见输入输出练习_readline(&hellip;).split is not a function-CSDN博客</a></p>
</li>
<li>
<p><a href="https://juejin.cn/post/6979812535557963784"  target="_blank" rel="noopener" >JavaScript实现封装、继承、多态JavaScript实现封装、继承、多态 - 掘金</a></p>
</li>
<li>
<p><code>parseInt</code></p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt"  target="_blank" rel="noopener" >parseInt() - JavaScript | MDN</a></li>
<li>示例代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">res</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="s1">&#39;2&#39;</span><span class="p">,</span> <span class="s1">&#39;100&#39;</span><span class="p">].</span><span class="nx">map</span><span class="p">(</span><span class="nb">parseInt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">res</span><span class="p">);</span> <span class="c1">// [1, NaN, 4]
</span></span></span></code></pre></div></li>
<li>解释
<ul>
<li>实际上 map 会传递三个参数给 parseInt，而 parseInt 只关心前两个参数：要解析的字符串和进制</li>
<li>因此解析过程如下:
<ol>
<li>对第一个元素 &lsquo;1&rsquo;，parseInt(&lsquo;1&rsquo;, 0)，0 表示根据输入自动检测进制，结果是 1。</li>
<li>对第二个元素 &lsquo;2&rsquo;，parseInt(&lsquo;2&rsquo;, 1)，1 不是有效的进制，因此结果是 NaN。</li>
<li>对第三个元素 &lsquo;100&rsquo;，parseInt(&lsquo;100&rsquo;, 2)，以二进制解析 &lsquo;100&rsquo;，结果是 4。</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>箭头函数与普通函数的区别</p>
<ul>
<li>函数体内的 this 对象，就是定义时所在的作用域中的 this 值，而不是使用时所在的对象</li>
<li>不可以使用 arguments 对象，该对象在函数体内不存在。如果要用，可以用 rest 参数代替</li>
<li>不可以使用 yield 命令，因此箭头函数不能用作 Generator 函数</li>
<li>不可以使用 new 命令
<ul>
<li>没有自己的 this，无法调用 call，apply</li>
<li>没有 prototype 属性</li>
</ul>
</li>
<li>参考: <a href="https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/101"  target="_blank" rel="noopener" >第 58 题：箭头函数与普通函数（function）的区别是什么？构造函数（function）可以使用 new 生成实例，那么箭头函数可以吗？为什么？ · Issue #101 · Advanced-Frontend/Daily-Interview-Question</a></li>
</ul>
</li>
<li>
<p>为什么会出现箭头函数</p>
<ul>
<li>消除函数的二义性
<ul>
<li>在出现箭头函数之前，函数可以直接被调用，也可以被new当作构造函数使用，这就是函数的二义性。</li>
<li>为了消除这种二义性，创造了箭头函数和class，箭头函数只能() =&gt; {}，当作普通函数调用，而class只能被new，这就刚好对应二义性的两种用法，解决这种复杂情况了</li>
</ul>
</li>
<li>解决了this的复杂指向问题</li>
</ul>
</li>
<li>
<p>ES6新特性</p>
<ul>
<li>引入了let和const</li>
<li>模板字符串: <code>${}</code></li>
<li>箭头函数</li>
<li>函数参数默认值，Rest参数</li>
<li>解构赋值</li>
<li>Promise</li>
<li>新增Map,Set,WeakMap,WeakSet</li>
<li>迭代器和生成器
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">arr</span> <span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">item</span> <span class="k">of</span> <span class="nx">arr</span><span class="p">){</span>
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>对象和类</li>
</ul>
</li>
<li>
<p>手撕</p>
<ul>
<li>参考
<ul>
<li><a href="https://juejin.cn/post/7210979444760772664"  target="_blank" rel="noopener" >面试中的手撕代码（一）总结了一些面面试中常见的手写代码题，如有更好见解欢迎评论指正~ - 掘金</a></li>
<li><a href="https://github.com/Sunny-117/js-challenges?tab=readme-ov-file"  target="_blank" rel="noopener" >Sunny-117/js-challenges: ✨✨✨ Challenge your JavaScript programming limits step by step</a></li>
<li><a href="https://github.com/Sunny-117/js-challenges/issues/37"  target="_blank" rel="noopener" >JSON2DOM = react的render函数 · Issue #37 · Sunny-117/js-challenges</a></li>
</ul>
</li>
</ul>
</li>
<li>
<p>实现继承</p>
</li>
</ol>
<ul>
<li>参考
<ul>
<li><a href="https://juejin.cn/post/7019185008527015949"  target="_blank" rel="noopener" >js中的6种继承方式 - 掘金</a></li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Postkid</title>
      <link>https://ds63.eu.org/2024/postkid/</link>
      <pubDate>Wed, 28 Feb 2024 14:53:46 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/postkid/</guid>
      <description>记录EuDs63/postkid的实现过程</description>
      <content:encoded><![CDATA[<h2 id="需求由来">需求由来</h2>
<p>Postman虽然功能齐全，但有些功能我用不上，再加上其强制要求登录，于是我很想自己开发一个类似的工具，仅实现我需要的功能。</p>
<h2 id="踩坑">踩坑</h2>
<h3 id="响应显示乱码">响应显示乱码</h3>
<p>当我加上header后，请求中文网站就开始出现诸如<code>zz��}��$�u߿�\������U}</code>的乱码。逐个排查后发现是<code>Accept-Encoding</code>的原因。我开始的时候是照着Postman的设置来写，写成了<code> { key: 'Accept-Encoding', value: 'gzip, deflate, br', include: true }</code>，但实际上<del>只有<code>deflate</code>是支持的</del>似乎也不尽然。我最终的解决办法是干脆不设置。</p>
<h3 id="代码编辑框">代码编辑框</h3>
<p>Body的raw选项，我需要使其代码高亮。开始我直接引入了<a href="https://github.com/PrismJS/prism/"  target="_blank" rel="noopener" >PrismJS/prism</a>，并在其上进行修改。bug不断，折腾了蛮久。</p>
<p>后来才想到我需要的不只是语法高亮，确切地说应该是代码编辑框，这方面应该有现成的库才对。一番寻找，发现<a href="https://github.com/react-simple-code-editor/react-simple-code-editor"  target="_blank" rel="noopener" >react-simple-code-editor/react-simple-code-editor</a>符合我的需求。很快就解决了。</p>
<h3 id="标签页多开">标签页多开</h3>
<p>我先做好了<code>./work/page</code>这个组件。接下来我希望实现类似于Postman的多标签页，每个标签页都是用同样的组件，但它们互相独立。</p>
<p>本来这并不是件难事，但因为我之前偷懒，高度依赖jotai的atom来做状态管理,因此花了好些时间。</p>
<p>先尝试了<a href="https://github.com/jotaijs/jotai-scope"  target="_blank" rel="noopener" >jotaijs/jotai-scope</a>,它给的示例确实符合我的需求，但当标签切走再切回去的时候，原来的状态就被重置了，我找不到问题所在，放弃。</p>
<p>中途多次问ChatGPT和Gemini，都是一开始看着很可行，然后实际不行，再问就开始重复之前的回答了。</p>
<p>最后是靠<a href="https://devv.ai/zh"  target="_blank" rel="noopener" >Devv</a>解决的，它说<a href="https://jotai.org/docs/utilities/family"  target="_blank" rel="noopener" >Jotai的atomFamily</a>能解决。<code>atomFamily</code>允许创建一组相关的原子，并为每个实例提供一个唯一的标识符。一试,确实可行。</p>
<p>现在再看我的实现，感觉还是比较简陋的。每个标签页对应一个特定的<code>tagId</code>，然后<code>atomFamily</code>就是&quot;a Map whose key is a param and whose value is an atom config&quot;。</p>
<h3 id="cargo-tauri-build">cargo tauri build</h3>
<p><strong>没想到整个过程会这么折磨，一个问题解决后，新的问题又出现了。</strong></p>
<h3 id="failed-to-fetch-inter-from-google-fonts">Failed to fetch Inter from Google Fonts.</h3>
<p>参考<a href="https://github.com/vercel/next.js/issues/45080#issuecomment-1680665108"  target="_blank" rel="noopener" >Error &lsquo;Failed to fetch <code>Noto Sans JP</code> from Google Fonts.&rsquo; · Issue #45080 · vercel/next.js</a></p>
<h3 id="type-number-is-not-assignable-to-type-never">Type &rsquo;number&rsquo; is not assignable to type &rsquo;never&rsquo;.</h3>
<p>排查无果，我选择修改<code>next.config.mjs</code>，<code>dangerously produce production code even when your application has errors</code>。</p>
<p>参考<a href="https://nextjs.org/docs/app/api-reference/next-config-js/typescript"  target="_blank" rel="noopener" >next.config.js Options: typescript | Next.js</a></p>
<h3 id="referenceerror-navigator-is-not-defined">ReferenceError: navigator is not defined</h3>
<p>这个报错刚开始让我觉得莫名奇妙，因为我记得自己没用到navigator。搜索后发现是我引入的<code>prism.js</code>使用到了。</p>
<p>而报这个错的原因又与tauri有关:Tauri不支持Next.js的ssr模式。</p>
<blockquote>
<p>Next.js is a React Framework that comes with both Server-Side Rendering (SSR) and Static-Site Generation (SSG) capabilities. To make Next.js work with Tauri we are going to use the SSG mode since it generates only static files that can be included in the final binary.</p>
</blockquote>
<p>我最终的解决方法是参考<a href="https://www.nextjs.cn/docs/advanced-features/dynamic-import"  target="_blank" rel="noopener" >高级特性: 动态导入（Import） | Next.js | Next.js中文网</a>，将使用到prism的组件动态引入。</p>
<h3 id="wixtools安装失败">WixTools安装失败</h3>
<blockquote>
<p>Connection Failed: Connect error: 由于连接方在一段时间后没有正确答复或连接 的主机没有反应，连接尝试失败。 (os error 10060)</p>
</blockquote>
<p>参考<a href="https://github.com/tauri-apps/tauri/issues/7338#issuecomment-1923680714"  target="_blank" rel="noopener" >[如何解决安装失败] · Issue #7338 · tauri-apps/tauri</a>。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://doc.rust-lang.org/std/sync/struct.OnceLock.html"  target="_blank" rel="noopener" >OnceLock in std::sync - Rust</a></li>
<li><a href="https://nextjs.org/docs"  target="_blank" rel="noopener" >Next.js Documentation</a> - learn about Next.js features and API.</li>
<li><a href="https://nextjs.org/learn"  target="_blank" rel="noopener" >Learn Next.js</a> - an interactive Next.js tutorial.</li>
<li><a href="https://cloud.tencent.com/developer/article/2364764?areaId=106001"  target="_blank" rel="noopener" >【Rust 日报】2023-11-26 Rust全局变量，两年过去了-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://github.com/PrismJS/prism/"  target="_blank" rel="noopener" >PrismJS/prism: Lightweight, robust, elegant syntax highlighting.</a></li>
<li><a href="https://github.com/react-simple-code-editor/react-simple-code-editor"  target="_blank" rel="noopener" >react-simple-code-editor/react-simple-code-editor: Simple no-frills code editor with syntax highlighting</a></li>
<li><a href="https://juejin.cn/post/6941683774153293837"  target="_blank" rel="noopener" >React 中后台系统多页签实现 ｜ 项目复盘 - 掘金</a></li>
<li><a href="https://jotai.org/docs/utilities/family"  target="_blank" rel="noopener" >Family — Jotai, primitive and flexible state management for React</a></li>
<li><a href="https://github.com/tauri-apps/tauri/issues/7338#issuecomment-1923680714"  target="_blank" rel="noopener" >[如何解决安装失败] · Issue #7338 · tauri-apps/tauri</a></li>
<li><a href="https://www.nextjs.cn/docs/advanced-features/dynamic-import"  target="_blank" rel="noopener" >高级特性: 动态导入（Import） | Next.js | Next.js中文网</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript知识点整理之Array</title>
      <link>https://ds63.eu.org/2024/javascript_points_of_array/</link>
      <pubDate>Sun, 25 Feb 2024 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/javascript_points_of_array/</guid>
      <description>自己学习过程中整理的关于JavaScript中Array的知识点</description>
      <content:encoded><![CDATA[<h2 id="初始化">初始化</h2>
<h3 id="new">new</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// 新建一个n行n列的二维数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kr">const</span> <span class="nx">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">n</span><span class="p">).</span><span class="nx">fill</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">map</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">n</span><span class="p">).</span><span class="nx">fill</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
</span></span></code></pre></div><h3 id="arrayfrom">Array.from</h3>
<ul>
<li>示例:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">({</span> <span class="nx">length</span><span class="o">:</span> <span class="mi">100</span> <span class="o">*</span> <span class="mi">1024</span> <span class="p">},</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="mi">256</span><span class="p">))</span>
</span></span></code></pre></div><ul>
<li>格式</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">arrayLike</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">arrayLike</span><span class="p">,</span> <span class="nx">mapFn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">arrayLike</span><span class="p">,</span> <span class="nx">mapFn</span><span class="p">,</span> <span class="nx">thisArg</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="参考">参考</h3>
<ul>
<li><a href="https://i.hsfzxjy.site/fast-conversion-from-base64-binary-to-uint8-array/"  target="_blank" rel="noopener" >将 Base64 编码的数据快速转换为 Uint8Array</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from"  target="_blank" rel="noopener" >Array.from() - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="遍历数组">遍历数组</h2>
<h3 id="foreach"><code>forEach</code></h3>
<ul>
<li><code>Array.prototype.forEach(function(value, index, arr), thisValue)</code></li>
<li>对数组的每个元素执行一次给定的函数。</li>
<li>forEach() 期望的是一个同步函数，它不会等待 Promise 兑现</li>
<li>除了<strong>抛出异常</strong>之外，没有其他方法可以停止或中断 forEach() 循环,也就是说不能在 forEach 中使用 break、continue 或 return</li>
<li>callbackFn 仅对已赋值的数组索引调用。对于稀疏数组中的空槽，它不会被调用。</li>
<li>forEach() 不会改变其调用的数组，但是，作为 callbackFn 的函数可以更改数组。请注意，在第一次调用 callbackFn 之前，<strong>数组的长度已经被保存</strong>。因此：
<ol>
<li>当调用 forEach() 时，callbackFn 不会访问超出数组初始长度的任何元素。</li>
<li>已经访问过的索引的更改不会导致 callbackFn 再次调用它们。</li>
<li>如果 callbackFn 更改了数组中已经存在但尚未访问的元素，则传递给 callbackFn 的值将是在访问该元素时的值。已经被删除的元素不会被访问。</li>
</ol>
</li>
</ul>
<h3 id="every"><code>every</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">every</span><span class="p">((</span><span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">value</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="c1">//判断数组元素是否都大于-1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">a</span><span class="p">);</span><span class="c1">//true
</span></span></span></code></pre></div><h3 id="some"><code>some()</code></h3>
<p>wip</p>
<h3 id="filter"><code>filter()</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">newArr</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">filter</span><span class="p">((</span><span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">value</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="p">)</span> <span class="c1">//判断数组元素是否大于3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">newArr</span><span class="p">);</span> <span class="c1">//[ 4, 5, 6, 7 ]
</span></span></span></code></pre></div><h3 id="map"><code>map()</code></h3>
<ul>
<li>不改变原数组
<ul>
<li>指的是不改变数组内部元素的个数和顺序，而不是元素本身的属性</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">newArr</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">value</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">value</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="c1">//将数组中每一个元素都乘以2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">newArr</span><span class="p">);</span> <span class="c1">//[0,  2,  4,  6, 8, 10, 12, 14]
</span></span></span></code></pre></div><h3 id="reduce"><code>reduce()</code></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">array</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">sumWithInitial</span> <span class="o">=</span> <span class="nx">array</span><span class="p">.</span><span class="nx">reduce</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nx">previousValue</span><span class="p">,</span><span class="nx">currentValue</span><span class="p">,</span><span class="nx">currentIndex</span><span class="p">)</span> <span class="p">=&gt;</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">previousValue</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="nx">currentValue</span> <span class="o">-</span> <span class="nx">currentIndex</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">sumWithInitial</span><span class="p">)</span> <span class="c1">// 63
</span></span></span></code></pre></div><h3 id="forin-和-forof"><code>for...in</code> 和 <code>for...of</code></h3>
<ul>
<li>对于数组: <code>for in</code>遍历的是index，<code>for of</code>遍历的是&quot;value&quot;
<ul>
<li>示例
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// for...in循环遍历数组的索引
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">index</span><span class="p">);</span> <span class="c1">// 输出 0, 1, 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// for...of循环遍历数组的值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">value</span> <span class="k">of</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span> <span class="c1">// 输出 1, 2, 3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
</li>
<li>for..in的缺陷
<ol>
<li>会迭代继承的属性,可以使用<code>obj.hasOwnProperty(key)</code>进一步判断
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">customMethod</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">index</span><span class="p">);</span>  <span class="c1">// 输出 0, 1, 2 , customMethod
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
<li>遍历的是字符串类型的索引
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">index</span><span class="p">);</span>  <span class="c1">// 输出 &#34;string&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
<li>不适合遍历稀疏数组
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="p">,</span> <span class="mi">30</span><span class="p">];</span>  <span class="c1">// 稀疏数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">index</span><span class="p">);</span>  <span class="c1">// 输出 0, 2 （不会跳过稀疏部分）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
</li>
</ul>
<h3 id="参考-1">参考</h3>
<ul>
<li><a href="https://juejin.cn/post/6854573211699380237"  target="_blank" rel="noopener" >js遍历数组的10种方法 - 掘金</a></li>
<li><a href="https://segmentfault.com/a/1190000022348279"  target="_blank" rel="noopener" >javascript - for…in和for…of的用法与区别 - 前端开发随笔 - SegmentFault 思否</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce"  target="_blank" rel="noopener" >Array.prototype.reduce() - JavaScript | MDN</a></li>
<li><a href="http://www.webkaka.com/tutorial/js/2023/0607221/"  target="_blank" rel="noopener" >为什么不能在forEach中使用break、continue或return？ - js技术_卡卡网</a></li>
</ul>
<hr>
<h2 id="实现foreach-map-filter">实现forEach, map, filter</h2>
<ul>
<li>forEach</li>
<li>wip: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#callbackfn"  target="_blank" rel="noopener" >Array.prototype.forEach() - JavaScript | MDN</a></li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">protype</span><span class="p">.</span><span class="nx">forEach</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">array</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span> <span class="c1">// 调用 forEach 方法的数组实例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="p">[</span><span class="nx">callbackFn</span><span class="p">,</span><span class="nx">thisArg</span><span class="p">]</span> <span class="o">=</span> <span class="p">[].</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">callbackFn</span> <span class="o">!==</span> <span class="s1">&#39;function&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nx">TypeError</span><span class="p">(</span><span class="nx">callbackFn</span> <span class="o">+</span> <span class="s1">&#39;is not a function&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">ary</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">callbackFn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">thisArg</span><span class="p">,</span><span class="nx">array</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="nx">i</span><span class="p">,</span><span class="nx">array</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>map</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">map</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span><span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="nx">arr</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">item</span><span class="p">,</span><span class="nx">i</span><span class="p">)=&gt;{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span><span class="nx">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>filter</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">filter</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span><span class="nx">fn</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="nx">arr</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">item</span><span class="p">,</span><span class="nx">i</span><span class="p">)=&gt;{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">isOk</span> <span class="o">=</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span><span class="nx">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">isOk</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">      <span class="nx">res</span><span class="p">.</span><span class="nx">push</span><span class="p">[</span><span class="nx">item</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h2 id="数组去重">数组去重</h2>
<h3 id="set">set</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="k">new</span> <span class="nx">Set</span><span class="p">(</span><span class="nx">arr</span><span class="p">))</span>
</span></span></code></pre></div><h3 id="reduce-1">reduce()</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">myArray</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;c&#34;</span><span class="p">,</span> <span class="s2">&#34;e&#34;</span><span class="p">,</span> <span class="s2">&#34;e&#34;</span><span class="p">,</span> <span class="s2">&#34;c&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">myArrayWithNoDuplicates</span> <span class="o">=</span> <span class="nx">myArray</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">accumulator</span><span class="p">,</span> <span class="nx">currentValue</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">accumulator</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">currentValue</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[...</span><span class="nx">accumulator</span><span class="p">,</span> <span class="nx">currentValue</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">accumulator</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="p">[]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">myArrayWithNoDuplicates</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="参考-2">参考</h3>
<ul>
<li><a href="https://segmentfault.com/a/1190000016418021"  target="_blank" rel="noopener" >JavaScript 数组去重的方法（12 种方法，史上最全） - 前端开发随笔 - SegmentFault 思否</a></li>
</ul>
<hr>
<h2 id="常用api">常用API</h2>
<h3 id="slice">slice</h3>
<ul>
<li>语法: <code>slice(start, end)</code></li>
<li>返回一个新的数组对象，这一对象是一个由 start 和 end 决定的原数组的浅拷贝（包括 start，不包括 end），其中 start 和 end 代表了数组元素的索引</li>
<li>原始数组不会被改变。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice"  target="_blank" rel="noopener" >Array.prototype.slice() - JavaScript | MDN</a></li>
</ul>
<h3 id="flatten">flatten</h3>
<ul>
<li>实现
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">myFlatten</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span><span class="nx">depth</span><span class="o">=</span><span class="mi">1</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span><span class="p">(</span><span class="nx">depth</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">reduct</span><span class="p">((</span><span class="nx">pre</span><span class="p">,</span><span class="nx">cur</span><span class="p">)=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pre</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">cur</span><span class="p">)</span><span class="o">?</span><span class="nx">myFlatten</span><span class="p">(</span><span class="nx">cur</span><span class="p">,</span><span class="nx">depth</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span><span class="nx">cur</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span><span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">slice</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>参考: <a href="https://juejin.cn/post/7084855668233994276"  target="_blank" rel="noopener" >ES6 flat 与数组扁平化前言   flat 用于将多维数组拉平（扁平化），不影响原数组，返回新的数组。   仅有一 - 掘金</a></li>
</ul>
<h3 id="shift与pop">shift与pop</h3>
<ul>
<li>shift：从数组中删除<strong>第一个</strong>元素，并返回该元素的值。此方法更改数组的长度</li>
<li>pop: 从数组中删除<strong>最后一个</strong>元素，并返回该元素的值。此方法更改数组的长度</li>
</ul>
<h3 id="indexof">indexof</h3>
<ul>
<li>
<p>语法: <code>indexOf(searchElement, fromIndex)</code></p>
</li>
<li>
<p>比较: <code>===</code>， 将 searchElement 与数组中的元素进行比较。NaN 值永远不会被比较为相等，因此当 searchElement 为 NaN 时 indexOf() 总是返回 -1</p>
</li>
<li>
<p>indexOf() 方法会跳过稀疏数组中的空槽。</p>
</li>
<li>
<p>找出指定元素出现的所有位置:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">indices</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">array</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;c&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">element</span> <span class="o">=</span> <span class="s2">&#34;a&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">idx</span> <span class="o">=</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">element</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="nx">idx</span> <span class="o">!==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">indices</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">idx</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">idx</span> <span class="o">=</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">element</span><span class="p">,</span> <span class="nx">idx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">indices</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// [0, 2, 4]
</span></span></span></code></pre></div></li>
<li>
<p>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf"  target="_blank" rel="noopener" >Array.prototype.indexOf() - JavaScript | MDN</a></p>
</li>
</ul>
<h3 id="concat">concat</h3>
<ul>
<li>语法: <code>concat(value0, value1, /* … ,*/ valueN)</code></li>
<li>如果省略了所有 valueN 参数，则 concat 会返回调用此方法的现存数组的一个浅拷贝</li>
<li>创建一个新数组。该数组将首先由调用它的对象中的元素填充。然后，对于每个参数，它的值将被连接到数组中</li>
<li>如果任何源数组是稀疏数组，concat() 方法会保留空槽</li>
<li>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/concat"  target="_blank" rel="noopener" >Array.prototype.concat() - JavaScript | MDN</a></li>
</ul>
<h3 id="reduceright">reduceRight</h3>
<ul>
<li>对累加器（accumulator）和数组的每个值（按<strong>从右到左</strong>的顺序）应用一个函数，并使其成为单个值。</li>
<li>参考: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight"  target="_blank" rel="noopener" >Array.prototype.reduceRight() - JavaScript | MDN</a></li>
</ul>
<hr>
<h2 id="参考-3">参考</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from"  target="_blank" rel="noopener" >Array.from() - JavaScript | MDN</a></li>
<li><a href="https://segmentfault.com/a/1190000016418021"  target="_blank" rel="noopener" >JavaScript 数组去重的方法（12 种方法，史上最全） - 前端开发随笔 - SegmentFault 思否</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Github同步两个仓库中的文件</title>
      <link>https://ds63.eu.org/2024/sync-specific-files-of-two-repo/</link>
      <pubDate>Sun, 04 Feb 2024 16:03:44 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2024/sync-specific-files-of-two-repo/</guid>
      <description>聪明的程序员也是懒程序员</description>
      <content:encoded><![CDATA[<h2 id="需求">需求</h2>
<p>我在Github上有两个仓库，一个是xxx，另一个是EuDs63.github.io。两个仓库中有部分文件是重复的，而这部分重复的文件，我是持续更新的。</p>
<p>以前我的操作是在xxx更新完后，再手动去更新EuDs63.github.io。但难免有时候会忘记，而且久了也觉得麻烦。</p>
<p>我计划使用action来简化我的操作，思路如下：</p>
<ol>
<li>当我向<a href="https://github.com/EuDs63/xxx"  target="_blank" rel="noopener" >EuDs63/xxx</a>push的时候，触发action，检查本次push修改的文件中是否有特定的表头。</li>
<li>如果有，那就推送给<a href="https://github.com/EuDs63/EuDs63.github.io"  target="_blank" rel="noopener" >EuDs63/EuDs63.github.io: my blog</a>。</li>
<li>这样只要我保证，我每次想新增内容的时候，都是在xxx这里先写就可以了。</li>
</ol>
<h2 id="过程">过程</h2>
<ol>
<li>使用<a href="https://github.com/marketplace/actions/changed-files"  target="_blank" rel="noopener" >Changed Files · Actions · GitHub Marketplace</a>
发现中文显示有问题，例如显示成<code>&quot;\345\260\244\351\207\214\345\215\241/\346\242\246.md&quot;</code>，查找issue和文档，未能找到解决方法,放弃。</li>
<li>网上查了下，找到的解决方法是<code>git config --global core.quotepath false</code>,确实能解决问题，但我不太能理解为什么，因为我的文件格式是utf-8，而不是<a href="https://blog.csdn.net/hanlizhong85/article/details/80642571"  target="_blank" rel="noopener" >其中</a>提到的gb2312。</li>
<li>我需要同步的文件的特征是以&quot;&mdash;&ldquo;开头，对diff得到的文件进行检查，如符合，则将相对地址写入到文件中。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">        git diff --name-only <span class="si">${</span><span class="p">{ github.event.before </span><span class="si">}</span><span class="o">}</span> <span class="si">${</span><span class="p">{ github.event.after </span><span class="si">}</span><span class="o">}</span> &gt; changed_files.txt
</span></span><span class="line"><span class="cl">        <span class="c1"># 接下来可以使用 changed_files.txt 文件中的内容,检查是否有需要执行的文件</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> file in <span class="k">$(</span>cat changed_files.txt<span class="k">)</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="c1"># 检查头一行是否以---开头</span>
</span></span><span class="line"><span class="cl">          <span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span>head -n <span class="m">1</span> <span class="nv">$file</span><span class="k">)</span> <span class="o">==</span> <span class="s2">&#34;---&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">            <span class="nb">echo</span> <span class="s2">&#34;File </span><span class="nv">$file</span><span class="s2"> is need to sync&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># 写入文件</span>
</span></span><span class="line"><span class="cl">            <span class="nb">echo</span> <span class="nv">$file</span> &gt;&gt; sync_files.txt
</span></span><span class="line"><span class="cl">          <span class="k">fi</span>
</span></span><span class="line"><span class="cl">        <span class="k">done</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Changed files: </span><span class="k">$(</span>cat sync_files.txt<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;sync_files=</span><span class="k">$(</span>cat sync_files.txt<span class="k">)</span><span class="s2">&#34;</span> &gt;&gt; <span class="s2">&#34;</span><span class="nv">$GITHUB_ENV</span><span class="s2">&#34;</span>
</span></span></code></pre></div><ol start="4">
<li>
<p>找到了文件，接下来要做的就是push到另一个仓库了。其实逻辑也不复杂，但本着不造轮子的原则，我找到了<a href="https://github.com/cpina/github-action-push-to-another-repository"  target="_blank" rel="noopener" >cpina/github-action-push-to-another-repository</a>，但发现它似乎不太能支持单独的几个文件，于是找到了<a href="https://github.com/nkoppel/push-files-to-another-repository"  target="_blank" rel="noopener" >nkoppel/push-files-to-another-repository</a>。</p>
</li>
<li>
<p>发现<a href="https://github.com/nkoppel/push-files-to-another-repository"  target="_blank" rel="noopener" >nkoppel/push-files-to-another-repository</a>的文档写得不全，甚至有误，而作者似乎也不再维护。但好在代码不长，于是读源码然后自己进行修改。我主要做了两个修改：</p>
<ul>
<li>原本的代码不支持私有仓库，会报错：</li>
</ul>
<blockquote>
<p>fatal: could not read Username for &lsquo;<a href="https://github.com"  target="_blank" rel="noopener" >https://github.com</a>&rsquo;: No such device or address</p>
</blockquote>
<p>改成<code>git clone &quot;https://$API_TOKEN_GITHUB@github.com/$GITHUB_REPOSITORY.git&quot; repo</code>就好了。</p>
<ul>
<li>原本的代码不支持相对路径，我改成了</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;##### Copying contents to git repo #####&#34;</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="nv">$CLONE_DIRECTORY</span><span class="s2">/</span><span class="nv">$DESTINATION_DIRECTORY</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> file in <span class="nv">$SOURCE_FILES</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 获取文件的相对路径</span>
</span></span><span class="line"><span class="cl">    <span class="nv">relative_path</span><span class="o">=</span><span class="k">$(</span>dirname <span class="s2">&#34;</span><span class="nv">$file</span><span class="s2">&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 创建相应的目录结构</span>
</span></span><span class="line"><span class="cl">    mkdir -p <span class="s2">&#34;</span><span class="nv">$CLONE_DIRECTORY</span><span class="s2">/</span><span class="nv">$DESTINATION_DIRECTORY</span><span class="s2">/</span><span class="nv">$relative_path</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 复制文件，保留相对路径</span>
</span></span><span class="line"><span class="cl">    cp -rvf <span class="s2">&#34;</span><span class="nv">$file</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$CLONE_DIRECTORY</span><span class="s2">/</span><span class="nv">$DESTINATION_DIRECTORY</span><span class="s2">/</span><span class="nv">$relative_path</span><span class="s2">/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="s2">&#34;</span><span class="nv">$CLONE_DIRECTORY</span><span class="s2">&#34;</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="碎碎念">碎碎念</h2>
<p>这个需求其实我很早就有了，实现的思路也很清晰。但一直拖到了现在，而且还是踩了不少坑。写这篇的时候总是想起某位老师的“聪明的程序员也是懒程序员”，我自知并不聪明，但尽量向这个道路走去。</p>
<h2 id="2024年4月29日">2024年4月29日</h2>
<p>实际使用时经常会run failed，报错为<code>Error: Unable to process file command 'env' successfully.</code></p>
<p>查了下发现是$GITHUB_ENV的multiline strings需要一个特殊的写法，具体参考<a href="https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings"  target="_blank" rel="noopener" >Workflow commands for GitHub Actions - GitHub Docs</a>。</p>
<p>于是我的解决方案是，将<a href="#%e8%bf%87%e7%a8%8b" >过程中的第五步</a>改为</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">{</span> <span class="nb">echo</span> <span class="s1">&#39;sync_files&lt;&lt;EOF&#39;</span><span class="p">;</span> cat sync_files.txt<span class="p">;</span> <span class="nb">echo</span> <span class="s1">&#39;EOF&#39;</span><span class="p">;</span> <span class="o">}</span> &gt;&gt; <span class="nv">$GITHUB_ENV</span>
</span></span></code></pre></div><h2 id="参考">参考</h2>
<ul>
<li><a href="https://blog.csdn.net/hanlizhong85/article/details/80642571"  target="_blank" rel="noopener" >git diff获取差异文件名显示中文乱码的解决办法_git diff获取差异文件中文乱码的解决办法-CSDN博客</a></li>
<li><a href="https://github.com/nkoppel/push-files-to-another-repository"  target="_blank" rel="noopener" >nkoppel/push-files-to-another-repository: github Action to push files into another Github repository</a></li>
<li><a href="https://github.com/tj-actions/changed-files"  target="_blank" rel="noopener" >tj-actions/changed-files: :octocat: Github action to retrieve all (added, copied, modified, deleted, renamed, type changed, unmerged, unknown) files and directories.</a></li>
<li><a href="https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files"  target="_blank" rel="noopener" >Workflow commands for GitHub Actions - GitHub Docs</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>C1学习</title>
      <link>https://ds63.eu.org/2024/c1-learning/</link>
      <pubDate>Tue, 30 Jan 2024 13:05:55 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/c1-learning/</guid>
      <description>记录c1学习</description>
      <content:encoded><![CDATA[<h2 id="科目一">科目一</h2>
<h3 id="罚款">罚款</h3>
<h4 id="审验教育">审验教育</h4>
<ul>
<li>参加<strong>审验教育</strong>时在签注学习记录、学习过程中弄虚作假的： 一千元以下罚款</li>
<li>代替实际机动车驾驶人参加审验教育的： 二千元以下罚款</li>
<li>组织他人实施前两款行为之一
<ul>
<li>有违法所得的，由公安机关交通管理部门处违法所得三倍以下罚款，但最高不超过<strong>二万元</strong> <em>（注意是两万元）</em></li>
<li>没有违法所得的，由公安机关交通管理部门处二万元以下罚款。</li>
</ul>
</li>
</ul>
<h4 id="二十元以上二百元以下罚款">二十元以上二百元以下罚款：</h4>
<ol>
<li>机动车驾驶人补换领机动车驾驶证后，继续使用原机动车驾驶证的；</li>
<li>在实习期内驾驶机动车不符合第七十七条规定的；</li>
<li>持有大型客车、重型牵引挂车、城市公交车、中型客车、大型货车驾驶证的驾驶人，未按照第八十一条规定申报变更信息的。
<strong>有第一项规定情形的，由公安机关交通管理部门收回原机动车驾驶证。</strong></li>
</ol>
<h4 id="二百元以上五百元以下罚款">二百元以上五百元以下罚款：</h4>
<ol>
<li>机动车驾驶证被依法扣押、扣留或者暂扣期间，采用隐瞒、欺骗手段补领机动车驾驶证的；</li>
<li>机动车驾驶人身体条件发生变化不适合驾驶机动车，仍驾驶机动车的；</li>
<li>逾期不参加审验仍驾驶机动车的。
<em>有第一项、第二项规定情形之一的，由公安机关交通管理部门收回机动车驾驶证。</em></li>
</ol>
<h4 id="二百元以上二千元以下罚款">二百元以上二千元以下罚款：</h4>
<ol>
<li>未取得机动车驾驶证、机动车驾驶证被吊销或者机动车驾驶证被暂扣期间驾驶机动车的；</li>
<li>将机动车交由未取得机动车驾驶证或者机动车驾驶证被吊销、暂扣的人驾驶的；</li>
<li>造成交通事故后逃逸，尚不构成犯罪的；</li>
<li>机动车行驶超过规定时速百分之五十的；</li>
<li>强迫机动车驾驶人违反道路交通安全法律、法规和机动车安全驾驶要求驾驶机动车，造成交通事故，尚不构成犯罪的；</li>
<li>违反交通管制的规定强行通行，不听劝阻的；</li>
<li>故意损毁、移动、涂改交通设施，造成危害后果，尚不构成犯罪的；</li>
<li>非法拦截、扣留机动车辆，不听劝阻，造成交通严重阻塞或者较大财产损失的。<br>
<strong>有前款第二项、第四项情形之一的，可以并处吊销机动车驾驶证；</strong>
<strong>有第一项、第三项、第五项至第八项情形之一的，可以并处十五日以下拘留。</strong></li>
<li>驾驶<em>拼装的机动车或者已达到报废标准的机动车上道路行驶</em>的，公安机关交通管理部门应当予以收缴，强制报废。
对驾驶前款所列机动车上道路行驶的驾驶人，处200元以上2000元以下罚款，并<em>吊销机动车驾驶证</em>。</li>
</ol>
<h3 id="喝酒">喝酒</h3>
<ul>
<li>醉酒驾驶营运机动车的，由公安机关交通管理部门约束至酒醒，吊销机动车驾驶证，依法追究刑事责任；十年内不得重新取得机动车驾驶证，重新取得机动车驾驶证后，不得驾驶营运机动车。</li>
<li>最近三个记分周期内，机动车驾驶人因造成交通事故后逃逸，或者饮酒后驾驶机动车，或者使用伪造、变造的机动车号牌、行驶证、驾驶证、校车标牌，或者使用其他机动车号牌、行驶证，或者买分卖分受到过处罚的；</li>
</ul>
<h3 id="超速">超速</h3>
<h4 id="普车">普车</h4>
<table>
<thead>
<tr>
<th></th>
<th>普路</th>
<th>特路</th>
</tr>
</thead>
<tbody>
<tr>
<td>20%-50%</td>
<td>3</td>
<td>6</td>
</tr>
<tr>
<td>50%以上</td>
<td>6</td>
<td>12</td>
</tr>
</tbody>
</table>
<h4 id="特车">特车</h4>
<table>
<thead>
<tr>
<th></th>
<th>普路</th>
<th></th>
<th>特路</th>
</tr>
</thead>
<tbody>
<tr>
<td>10%-20%</td>
<td>1</td>
<td>20%以下</td>
<td>6</td>
</tr>
<tr>
<td>20%-50%</td>
<td>6</td>
<td>20%以上</td>
<td>12</td>
</tr>
<tr>
<td>50%以上</td>
<td>9</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="超载">超载</h3>
<h4 id="普车-1">普车</h4>
<table>
<thead>
<tr>
<th></th>
<th>20%-50%</th>
<th>50%-100%</th>
<th>100%以上</th>
</tr>
</thead>
<tbody>
<tr>
<td>其他（以外）</td>
<td>3</td>
<td>6</td>
<td>12</td>
</tr>
<tr>
<td>7座以上</td>
<td>6</td>
<td>9</td>
<td>12</td>
</tr>
</tbody>
</table>
<h4 id="特车-1">特车</h4>
<p>20%以下： 6分
20%以上： 12分</p>
<h4 id="驾驶载货汽车载物超过最大允许总质量">驾驶载货汽车载物超过最大允许总质量</h4>
<table>
<thead>
<tr>
<th></th>
<th>30%以下</th>
<th>30%-50%</th>
<th>50%以上</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>1</td>
<td>3</td>
<td>6</td>
</tr>
</tbody>
</table>
<h3 id="减分">减分</h3>
<p>机动车驾驶人处理完交通违法行为记录后累积记分未满12分，参加公安机关交通管理部门组织的交通安全教育并达到规定要求的，可以申请在机动车驾驶人现有累积记分分值中扣减记分。在一个记分周期内<strong>累计最高扣减6分</strong>。</p>
<h3 id="日期">日期</h3>
<ul>
<li>当事人对交通事故损害赔偿有争议，各方当事人一致<em>请求公安机关交通管理部门调解</em>的，应当在收到交通事故认定书之日起<strong>10日内</strong>提出书面调解申请。</li>
<li>发生道路交通事故后当事人未报警，在事故现场撤除后，当事人<em>又报警请求</em>公安机关交通管理部门处理的，公安机关交通管理部门应当按照本规定第十六条规定的记录内容予以记录，并在<strong>三日内作出是否接受案件的决定</strong>。</li>
</ul>
<h3 id="扣分">扣分</h3>
<h4 id="12分">12分</h4>
<ol>
<li>饮酒后驾驶机动车的；</li>
<li>造成致人<strong>轻伤以上或者死亡</strong>的交通事故后逃逸，尚不构成犯罪的；</li>
<li>使用伪造、变造的机动车号牌、行驶证、驾驶证、校车标牌或者使用其他机动车号牌、行驶证的；</li>
<li>驾驶校车、公路客运汽车、旅游客运汽车载人超过核定人数<strong>百分之二十以上</strong>，或者驾驶其他载客汽车载人超过核定人数<strong>百分之百以上</strong>的；</li>
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆在高速公路、城市快速路上行驶超过规定时速<strong>百分之二十以上</strong>，或者驾驶其他机动车在高速公路、城市快速路上行驶超过规定时速<strong>百分之五十以上的</strong>；</li>
<li>驾驶机动车在高速公路、城市快速路上倒车、逆行、穿越中央分隔带掉头的；</li>
<li>代替实际机动车驾驶人接受交通违法行为处罚和记分牟取经济利益的。</li>
</ol>
<h4 id="9分">9分</h4>
<ol>
<li>驾驶7座以上载客汽车载人超过核定人数<strong>百分之五十以上未达到百分之百</strong>的；</li>
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆在高速公路、城市快速路<strong>以外</strong>的道路上行驶超过规定时速百分之五十以上的；(注意和12分的差别，在高、快超百分之二十就要扣12分了)</li>
<li>驾驶机动车在高速公路或者城市快速路上违法停车的；</li>
<li><strong>驾驶未悬挂机动车号牌或者故意遮挡、污损机动车号牌的机动车上道路行驶的；</strong></li>
<li>驾驶与准驾车型不符的机动车的；</li>
<li>未取得校车驾驶资格驾驶校车的；</li>
<li>连续驾驶<em>中型以上载客汽车、危险物品运输车辆</em><strong>超过4小时未停车休息或者停车休息时间少于20分钟的</strong>。</li>
</ol>
<h4 id="6分">6分</h4>
<ol>
<li></li>
</ol>
<ul>
<li>驾驶校车、公路客运汽车、旅游客运汽车载人超过核定人数未达到百分之二十，</li>
<li>或者驾驶7座以上载客汽车载人超过核定人数百分之二十以上未达到百分之五十，</li>
<li>或者驾驶其他载客汽车载人超过核定人数百分之五十以上未达到百分之百的；</li>
</ul>
<ol start="2">
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆在高速公路、城市快速路上行驶超过规定时速未达到百分之二十，或者在高速公路、城市快速路以外的道路上行驶超过规定时速百分之二十以上未达到百分之五十的；</li>
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆以外的机动车在高速公路、城市快速路上行驶超过规定时速百分之二十以上未达到百分之五十，或者在高速公路、城市快速路以外的道路上行驶超过规定时速百分之五十以上的；</li>
<li>驾驶载货汽车载物超过最大允许总质量<em>百分之五十以上的</em>；</li>
<li>驾驶机动车载运爆炸物品、易燃易爆化学物品以及剧毒、放射性等危险物品，未按指定的时间、路线、速度行驶或者未悬挂警示标志并采取必要的安全措施的；</li>
<li>驾驶机动车运载超限的不可解体的物品，未按指定的时间、路线、速度行驶或者未悬挂警示标志的；</li>
<li>驾驶机动车运输危险化学品，未经批准进入危险化学品运输车辆限制通行的区域的；</li>
<li>驾驶机动车不按交通信号灯指示通行的；</li>
<li>机动车驾驶证被暂扣或者扣留期间驾驶机动车的； <em>处二百元以上二千元以下罚款</em></li>
<li>造成致人轻微伤或者财产损失的交通事故后逃逸，尚不构成犯罪的；</li>
<li>驾驶机动车在高速公路或者城市快速路上违法占用应急车道行驶的。</li>
</ol>
<h4 id="3分">3分</h4>
<ol>
<li>驾驶校车、公路客运汽车、旅游客运汽车、7座以上载客汽车<strong>以外的</strong>其他载客汽车载人超过核定人数百分之二十以上未达到百分之五十的；</li>
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆以外的机动车在高速公路、城市快速路以外的道路上行驶超过规定时速百分之二十以上未达到百分之五十的；</li>
<li>驾驶机动车在高速公路或者城市快速路上<em>不按规定车道行驶</em>的；</li>
<li>驾驶机动车<em>不按规定超车、让行</em>，或者在高速公路、城市快速路<em>以外的道路上逆行的</em>； <strong>区分掉头</strong></li>
<li>驾驶机动车遇前方机动车停车排队或者缓慢行驶时，借道超车或者占用对面车道、穿插等候车辆的；</li>
<li>驾驶机动车有拨打、接听手持电话等妨碍安全驾驶的行为的；</li>
<li>驾驶机动车行经人行横道不按规定减速、停车、避让行人的；</li>
<li>驾驶机动车<em>不按规定避让校车的</em>；</li>
<li>驾驶载货汽车载物超过最大允许总质量<em>百分之三十以上未达到百分之五十的，或者违反规定载客的</em>；</li>
<li>驾驶<em>不按规定安装机动车号牌</em>的机动车上道路行驶的；</li>
<li>在道路上车辆发生故障、事故停车后，<strong>不按规定使用灯光或者设置警告标志的；</strong></li>
<li>驾驶未按规定定期进行安全技术检验的公路客运汽车、旅游客运汽车、危险物品运输车辆上道路行驶的；</li>
<li>驾驶校车上道路行驶前，未对校车车况是否符合安全技术要求进行检查，或者驾驶存在安全隐患的校车上道路行驶的；</li>
<li>连续驾驶载<em>货汽车</em>超过4小时<em>未停车休息</em>或者停车休息时间少于20分钟的；</li>
<li>驾驶机动车在高速公路上行驶<em>低于规定最低时速</em>的。</li>
</ol>
<h4 id="1分">1分</h4>
<ol>
<li>驾驶校车、中型以上载客载货汽车、危险物品运输车辆在高速公路、城市快速路以外的道路上行驶超过规定时速百分之十以上未达到百分之二十的；</li>
<li>驾驶机动车<em>不按规定会车</em>，或者在高速公路、城市快速路以外的道路上<em>不按规定倒车、掉头的</em>；</li>
<li>驾驶机动车不按规定使用灯光的；</li>
<li>驾驶机动车违反禁令标志、禁止标线指示的；</li>
<li>驾驶机动车<em>载货长度、宽度、高度超过规定</em>的；</li>
<li>驾驶载货汽车载物超过最大允许总质量<em>未达到百分之三十的</em>；</li>
<li>驾驶未按规定定期进行安全技术检验的公路客运汽车、旅游客运汽车、危险物品运输车辆以外的机动车上道路行驶的；</li>
<li>驾驶擅自改变已登记的结构、构造或者特征的载货汽车上道路行驶的；</li>
<li>驾驶机动车在道路上行驶时，机动车驾驶人未按规定系安全带的；</li>
<li>驾驶摩托车，不戴安全头盔的。</li>
</ol>
<h3 id="驾驶证类型">驾驶证类型</h3>
<ul>
<li>A2为重型牵引挂车，准驾总质量大于4500kg的汽车列车</li>
<li>A1为大型客车。准驾大型载客汽车</li>
<li>B1为中型客车,准驾车型有中型载客汽车（含核载10人以上、19人以下的城市公共汽车），包含B1、C1、C2、C3、C4、M共六种车型。</li>
<li>B2为大型货车。准驾的车辆有重型、中型载货汽车；重型、中型专项作业车。</li>
</ul>
<h3 id="限速">限速</h3>
<ol>
<li>没有道路中心线，城市道路为30公里每小时，公路为40公里每小时；</li>
<li>同方向只有一条车道，城市道路为50公里每小时，公路为70公里每小时；</li>
<li>机动车行驶中遇有下列情形之一的，最高行驶速度不得超过每小时30公里，其中拖拉机、电瓶车、轮式专用机械车不得超过每小时15公里：
<ul>
<li>进出非机动车道，通过铁路道口、急弯路、窄路、窄桥时；</li>
<li>掉头、转弯、下陡坡时；</li>
<li>遇雾、雨、雪、沙尘、冰雹，能见度在50米以内时；</li>
<li>在冰雪、泥泞的道路上行驶时；</li>
<li>牵引发生故障的机动车时。</li>
</ul>
</li>
</ol>
<h3 id="有下列情形之一的不得申请机动车驾驶证">有下列情形之一的，不得申请机动车驾驶证:</h3>
<ol>
<li>有器质性心脏病、癫痫病、美尼尔氏症、眩晕症、癔病、震颤麻痹、精神病、痴呆以及影响肢体活动的神经系统疾病等妨碍安全驾驶疾病的；</li>
<li>三年内有吸食、注射毒品行为或者解除强制隔离戒毒措施未满三年，以及长期服用依赖性精神药品成瘾尚未戒除的；</li>
<li>造成交通事故后逃逸构成犯罪的；</li>
<li>饮酒后或者醉酒驾驶机动车发生重大交通事故构成犯罪的；</li>
<li>醉酒驾驶机动车或者饮酒后驾驶营运机动车依法被吊销机动车驾驶证未满五年的；</li>
<li><em>醉酒驾驶营运机动车</em>依法被吊销机动车驾驶证<strong>未满十年</strong>的；</li>
<li>驾驶机动车追逐竞驶、超员、超速、违反危险化学品安全管理规定运输危险化学品构成犯罪依法被吊销机动车驾驶证<em>未满五年</em>的；</li>
<li>因本款第四项以外的其他违反交通管理法律法规的行为发生重大交通事故构成犯罪依法被吊销机动车驾驶证<em>未满十年</em>的；</li>
<li>因其他情形依法被吊销机动车驾驶证<em>未满二年</em>的；</li>
<li>驾驶许可依法被撤销未满三年的；</li>
<li>未取得机动车驾驶证驾驶机动车，发生负同等以上责任交通事故造成人员重伤或者死亡<em>未满十年</em>的；</li>
<li><em>三年内</em>有代替他人参加机动车驾驶人考试行为的；</li>
<li>法律、行政法规规定的其他情形。未取得机动车驾驶证驾驶机动车，有第一款第五项至第八项行为之一的，在规定期限内不得申请机动车驾驶证。</li>
</ol>
<h3 id="其他">其他</h3>
<ol>
<li>在狭窄的坡路，上坡的一方先行；但下坡的一方已行至中途而上坡的一方未上坡时，下坡的一方先行。</li>
<li></li>
</ol>
<ul>
<li>违反交通运输管理法规，因而发生重大事故，致人重伤、死亡或者使公私财产遭受重大损失的，<strong>处三年以下有期徒刑或者拘役</strong>；</li>
<li>交通运输肇事后逃逸或者有其他特别恶劣情节的，<strong>处三年以上七年以下有期徒刑</strong>；</li>
<li>因逃逸致人死亡的，<strong>处七年以上有期徒刑</strong>。</li>
</ul>
<ol start="3">
<li>
<p>停车视距由反应距离、制动距离和安全距离三个方面组成。</p>
</li>
<li>
<p>机动车驾驶人按照以下规定换领机动车驾驶证时，应当接受公安机关交通管理部门的审验：</p>
<ul>
<li>机动车驾驶人应当于机动车驾驶证有效期满前九十日内，向机动车驾驶证核发地或者核发地以外的车辆管理所申请换证。</li>
<li>机动车驾驶人户籍迁出原车辆管理所管辖区的，应当向迁入地车辆管理所申请换证。</li>
</ul>
<p>机动车驾驶人在核发地车辆管理所管辖区以外居住的，可以向居住地车辆管理所申请换证。申请时应当确认申请信息，提交机动车驾驶人的身份证明和机动车驾驶证，并申报身体条件情况。</p>
</li>
<li>
<p>公共汽车站、急救站、加油站、消防栓或者消防队（站）门前以及距离上述地点30米以内的路段，除使用上述设施的以外，不得停车。</p>
</li>
<li>
<p>高速公路行驶时的间距：</p>
<ul>
<li>时速大于100公里，间距大于100米</li>
<li>小于的，不得少于50米</li>
</ul>
</li>
<li>
<p>高速公路的行驶速度</p>
<ul>
<li>应当标明车道的行驶速度，最高车速不得超过每小时120公里，最低车速不得低于每小时60公里。</li>
<li>在高速公路上行驶的小型载客汽车最高车速不得超过每小时120公里，其他机动车<em>不得超过每小时100公里</em>，摩托车不得超过每小时80公里。</li>
<li>同方向有2条车道的，左侧车道的最低车速为每小时100公里。</li>
<li>同方向有3条以上车道的，最左侧车道的最低车速为每小时110公里，中间车道的最低车速为每小时90公里。</li>
<li>道路限速标志标明的车速与上述车道行驶车速的规定不一致的，按照道路限速标志标明的车速行驶。</li>
</ul>
</li>
<li>
<p>机动车在高速公路上行驶，遇有雾、雨、雪、沙尘、冰雹等低能见度气象条件时，应当遵守下列规定：（642，一百五十零）</p>
<ol>
<li>能见度小于200米时，开启雾灯、近光灯、示廓灯和前后位灯，车速不得超过<strong>每小时60公里</strong>，与同车道前车保持<em>100米以上</em>的距离；</li>
<li>能见度小于100米时，开启雾灯、近光灯、示廓灯、前后位灯和<em>危险报警闪光灯</em>，车速不得超过<strong>每小时40公里</strong>，与同车道前车保持<em>50米以上</em>的距离；</li>
<li>能见度小于50米时，开启雾灯、近光灯、示廓灯、前后位灯和<em>危险报警闪光灯</em>，车速不得超过<strong>每小时20公里</strong>，并从最近的出口尽快驶离高速公路。</li>
</ol>
</li>
<li>
<p>驾驶证身体证明</p>
</li>
</ol>
<ul>
<li>办理残疾人专用小型自动挡载客汽车驾驶证业务时，提交的身体条件证明应当由<strong>经省级卫生健康行政部门认定的专门医疗机构</strong>出具。</li>
<li>办理其他机动车驾驶证业务时，提交的身体条件证明应当<strong>由县级、部队团级以上医疗机构，或者经地市级以上卫生健康行政部门认定的具有健康体检资质的二级以上医院、乡镇卫生院、社区卫生服务中心、健康体检中心等医疗机构出具</strong>。</li>
</ul>
<ol start="10">
<li>停车</li>
</ol>
<ul>
<li>交叉路口、铁路道口、急弯路、宽度不足4米的窄路、桥梁、陡坡、隧道以及距离上述地点50米以内的路段，不得停车。</li>
</ul>
<ol start="11">
<li>机动车的登记，分为注册登记、变更登记、转移登记、抵押登记和注销登记。</li>
<li>
<ul>
<li>参加公安机关交通管理部门组织的道路交通安全法律、法规和相关知识网上学习三日内累计满三十分钟且考试合格的，一次扣减1分。</li>
<li>参加公安机关交通管理部门组织的道路交通安全法律、法规和相关知识现场学习满一小时且考试合格的，<strong>一次扣减2分</strong>。</li>
<li>参加公安机关交通管理部门组织的交通安全公益活动的，满一小时为一次，一次扣减1分。</li>
</ul>
</li>
<li>
<ul>
<li>绿灯亮时，准许车辆通行，但转弯的车辆不得妨碍被放行的直行车辆、行人通行；</li>
<li>黄灯亮时，已越过停止线的车辆可以继续通行；</li>
<li>红灯亮时，禁止车辆通行。</li>
</ul>
</li>
<li>成人心肺按压频率的要求是每分钟100-120次，按压深度的要求是5-6厘米。</li>
<li>行车前，驾驶人要对发动机舱、车辆外部主要部件进行安全检查，确保车辆安全技术状况良好。上车前，再从驾驶室车门处开始，沿逆时针方向绕车一周，观察车辆周围情况，特别要留意车底、车后的情况（可能有宠物或玩耍的小孩），确认安全后按照规范动作上车。</li>
<li>安全头枕在发生追尾事故时，能有效保护驾驶人的颈部。</li>
<li>持有大型客车、重型牵引挂车、城市公交车、中型客车、大型货车驾驶证的驾驶人从业单位等信息发生变化的，应当在信息变更后三十日内，向从业单位所在地车辆管理所备案。</li>
<li>现机动车所有人住所不在车辆管理所管辖区域内的，转出地车辆管理所应当自受理之日起<em>三日</em>内，查验机动车</li>
<li>车辆管理所收到机动车所有人补领、换领机动车号牌的申请后，自受理之日起<em>十五日</em>内补发、换发号牌</li>
</ol>
<hr>
<h2 id="科目二">科目二</h2>
<h3 id="定点停车和半坡起步">定点停车和半坡起步</h3>
<ul>
<li>与右边线要保持30cm</li>
<li>车牌停在中间黄线里</li>
<li>上坡的时候要控制速度。但中途离合不能踩太多</li>
<li>车头过了最远端的黄线，转头看后视镜。</li>
<li>看到后视镜过了中间黄线，我就离合和刹车一起踩。（得分情况，快的话就提前踩）</li>
<li>半坡起步，我不需要去动档位。（前几次不知道为什么，总是习惯性地回空挡）</li>
<li>手刹拉起3秒后，放下。</li>
<li>起步我一般没啥问题，要注意的就是不要一次松太多。</li>
</ul>
<h3 id="曲线行驶">曲线行驶</h3>
<ul>
<li>这个我很怕压到线，但教练跟车了几次也没说什么，似乎没啥问题。</li>
<li>速度尽量控制下来</li>
</ul>
<h3 id="直角拐弯">直角拐弯</h3>
<ul>
<li>记得打灯、关灯。</li>
<li>眼睛、车门向上投影、外边角成一线时，向左打死</li>
</ul>
<h3 id="侧方停车">侧方停车</h3>
<ul>
<li>入库三步：
<ol>
<li>右打死</li>
<li>回正</li>
<li>左打死</li>
</ol>
</li>
<li>出库三步
<ol>
<li>打灯</li>
<li>回正</li>
<li>右一圈</li>
</ol>
</li>
<li>这个我似乎没啥问题</li>
</ul>
<h3 id="倒车入库">倒车入库</h3>
<ul>
<li>之前练得挺好的，但昨天停了好几次都进不去，停得我怀疑人生。
<ul>
<li>发现原因了：在看后视镜是否盖住黄线时，头应正视前方</li>
</ul>
</li>
<li>车身要摆直</li>
<li>左入库教练教的是：后视镜盖住黄线时，右打死。但我的问题是，可能我反应时间比较长，所以就要有个提前量</li>
</ul>
<h3 id="总结">总结</h3>
<p>总共五个项目，一个个说下来其实每个好像都还好。最主要的是调整好心态。放慢速度。</p>
<hr>
<h2 id="科目三">科目三</h2>
<h3 id="起步">起步</h3>
<h4 id="步骤">步骤</h4>
<ol>
<li>打左转向灯</li>
<li>系安全带</li>
<li>挂一档，缓松离合至方向盘轻微震动,松手刹</li>
<li>慢慢放离合，踩油门加速</li>
<li>挂二挡</li>
</ol>
<h4 id="要求">要求</h4>
<p>手刹放下十秒内完成起步</p>
<h3 id="加减档">加减档</h3>
<h4 id="步骤-1">步骤</h4>
<ol>
<li>时速保持在25km</li>
<li>换挡过程：
<ol>
<li>离合踩到底</li>
<li>换挡（要有节奏感、先回空挡，然后再换到对应的挡位）</li>
<li>手放回去</li>
<li>脚拿开，默数一二</li>
<li>重复下一次</li>
</ol>
</li>
</ol>
<h4 id="要求-1">要求</h4>
<ol>
<li>尽量要稳，车不会剧烈震动</li>
<li>回二档时，松离合要慢</li>
</ol>
<h3 id="变更车道">变更车道</h3>
<h4 id="步骤-2">步骤</h4>
<ol>
<li>打转向灯</li>
<li>数五秒（观察后方来车）</li>
<li>轻转方向盘至对应车道</li>
<li>回正</li>
</ol>
<h3 id="超越前方车辆">超越前方车辆</h3>
<h4 id="步骤-3">步骤</h4>
<ol>
<li>打左转向灯，数五秒</li>
<li>轻转方向盘</li>
<li>回正，打右转向灯，数五秒</li>
<li>轻转方向盘，回正</li>
</ol>
<h3 id="掉头">掉头</h3>
<h4 id="步骤-4">步骤</h4>
<ul>
<li>路上无车可二挡直接转</li>
<li>有车时:
<ol>
<li>停车，换一档</li>
<li>半离合前进</li>
<li>左打死方向盘（要迅速），慢慢松掉离合</li>
<li>车身回正后加速</li>
<li>换回二档</li>
</ol>
</li>
</ul>
<h3 id="直线行驶">直线行驶</h3>
<h4 id="步骤-5">步骤</h4>
<ol>
<li>提前提至三挡，摆正车身</li>
<li>时速三十以上换四挡</li>
<li>项目结束后直接换回二档</li>
</ol>
<h3 id="左转弯接靠边停车">左转弯接靠边停车</h3>
<h4 id="步骤-6">步骤</h4>
<ol>
<li>先停车，挂一档</li>
<li>转到对应车道后停车，数7秒</li>
<li>打右转向灯，慢慢靠过去</li>
<li>第三车道，喷水点对齐路中间的水泥缝</li>
</ol>
<h3 id="红绿灯">红绿灯</h3>
<ol>
<li>踩离合，用刹车控制速度</li>
<li>判断要走：半离合慢慢走</li>
<li>关键:不要突然踩刹车，防止追尾</li>
</ol>
<h3 id="松离合">松离合</h3>
<ol>
<li>快</li>
<li>顿</li>
<li>慢</li>
</ol>
<h3 id="练车时出现的问题">练车时出现的问题</h3>
<ol>
<li>加减档三档换二档，松离合的时候，我是慢慢松开的，但教练说这样是把正常行驶的放离合和加减档项目的放离合搞混了。我得顺放，但也不能一下子放开。</li>
<li>打转向灯。一次右转，我右转向灯打成了左转向灯。</li>
<li>靠边停车后，我忘了拉手刹，实际应这样操作：
<ol>
<li>回空挡</li>
<li>回转向灯</li>
<li>拉手刹</li>
<li>转钥匙熄火</li>
<li>解安全带</li>
<li>用力关车门</li>
</ol>
</li>
</ol>
<h3 id="总结-1">总结</h3>
<p>科目三也不难，但心态要好，不要太紧张。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>浏览器地址栏探秘</title>
      <link>https://ds63.eu.org/2024/exploring-the-browser-address-bar/</link>
      <pubDate>Sun, 21 Jan 2024 00:58:57 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/exploring-the-browser-address-bar/</guid>
      <description>URL handling in Address bar</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>我发现浏览器地址栏中显示的，和我将其复制粘贴到编辑器中的内容不同。</p>
<p>比如地址栏显示的是，<code>https://ds63.eu.org/2022/村上春树</code>，但当我粘贴到Vscode后，却是<code>https://ds63.eu.org/2022/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/</code></p>
<h2 id="编码与解码">编码与解码</h2>
<p>我之前只知道形如<code>%E6%9D%91</code>是url编码，但没详细了解过。</p>
<p>根据<a href="https://www.wikiwand.com/zh/URL%E7%BC%96%E7%A0%81"  target="_blank" rel="noopener" >百分号编码 - Wikiwand</a>的介绍，过程如下：</p>
<ol>
<li>将每个字符按照 UTF-8 编码规则转换为字节序列</li>
<li>将每个字节编码为 % 后跟两个十六进制数字</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">original_string</span> <span class="o">=</span> <span class="s2">&#34;村上春树&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">utf8_string</span> <span class="o">=</span> <span class="n">original_string</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">utf8_string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#b&#39;\xe6\x9d\x91\xe4\xb8\x8a\xe6\x98\xa5\xe6\xa0\x91&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">hex_utf8_string</span> <span class="o">=</span>  <span class="s1">&#39;%&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">b</span><span class="si">:</span><span class="s1">02X</span><span class="si">}</span><span class="s1">&#39;</span> <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">utf8_string</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">hex_utf8_string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91</span>
</span></span></code></pre></div><ol start="3">
<li>实际使用时可以用<code>urllib.parse</code>这个库</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 编码</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote</span><span class="p">,</span><span class="n">unquote</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">original_url</span> <span class="o">=</span> <span class="s2">&#34;https://ds63.eu.org/2022/村上春树&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">encoded_url</span> <span class="o">=</span> <span class="n">quote</span><span class="p">(</span><span class="n">original_url</span><span class="p">,</span> <span class="n">safe</span><span class="o">=</span><span class="s1">&#39;:/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">encoded_url</span><span class="p">)</span> <span class="c1">#https://ds63.eu.org/2022/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#解码</span>
</span></span><span class="line"><span class="cl"><span class="n">decoded_url</span> <span class="o">=</span> <span class="n">unquote</span><span class="p">(</span><span class="n">encoded_url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">decoded_url</span><span class="p">)</span> <span class="c1">#https://ds63.eu.org/2022/村上春树/</span>
</span></span></code></pre></div><h2 id="显示与实际复制">显示与实际复制</h2>
<p>那浏览器是如何实现用户看到的与实际复制不同的呢，我猜测可能是这样的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;userFriendlyUrl&#34;</span> <span class="na">oncopy</span><span class="o">=</span><span class="s">&#34;handleCopy()&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        https://ds63.eu.org/2022/村上春树
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="kd">function</span> <span class="nx">handleCopy</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 获取用户友好的URL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kd">var</span> <span class="nx">userFriendlyUrl</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;userFriendlyUrl&#34;</span><span class="p">).</span><span class="nx">innerText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 对URL进行URL编码
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kd">var</span> <span class="nx">encodedUrl</span> <span class="o">=</span> <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">userFriendlyUrl</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 创建一个文本区域元素，设置其值为编码后的URL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kd">var</span> <span class="nx">textarea</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">&#34;textarea&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nx">textarea</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">encodedUrl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 将文本区域元素添加到页面中
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">textarea</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 选中文本
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">textarea</span><span class="p">.</span><span class="nx">select</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="nx">textarea</span><span class="p">.</span><span class="nx">setSelectionRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">99999</span><span class="p">);</span> <span class="c1">// 兼容移动设备
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 复制文本到剪贴板
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nb">document</span><span class="p">.</span><span class="nx">execCommand</span><span class="p">(</span><span class="s2">&#34;copy&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 移除文本区域元素
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">textarea</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// 阻止默认复制事件，避免复制原始文本
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">//alert(&#34;URL copied: &#34; + encodedUrl);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="国际化域名">国际化域名</h2>
<p>我上述的例子并没有考虑到国际化域名。</p>
<p>具体可参看<a href="https://www.wikiwand.com/en/Internationalized_domain_name"  target="_blank" rel="noopener" >国际化域名</a>和<a href="https://www.wikiwand.com/en/Punycode"  target="_blank" rel="noopener" >Punycode编码</a>。</p>
<h2 id="意外收获">意外收获</h2>
<p>我之前就好奇汉字到底有多少个，看<a href="https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php"  target="_blank" rel="noopener" >中文字符集 Unicode 编码范围</a>，发现可能应该不到十万。</p>
<p>ps: 看<a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%97%A5%E9%9F%93%E7%B5%B1%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97?oldformat=true"  target="_blank" rel="noopener" >中日韩统一表意文字 - 维基百科，自由的百科全书</a>，还是觉得很混乱。不少是历史遗留下来的问题，所以我先前的估算显然是有问题的。</p>
<p>之后我又查了些资料，发现现在关于汉字的数量仍没有定论，可以说是众说纷纭。</p>
<h2 id="延伸">延伸</h2>
<p>在写这篇博客之后，我才注意到浏览器的地址栏原来有如此多的功能：</p>
<ol>
<li>
<p>地址栏预测： 当用户输入地址栏时，浏览器会根据用户的浏览历史、收藏夹和搜索历史等信息提供地址栏预测。这有助于用户快速访问常用站点。</p>
</li>
<li>
<p>搜索建议： 地址栏还充当搜索栏，用户可以直接在其中输入搜索关键字。浏览器通常会基于用户的输入和搜索历史，提供搜索建议。</p>
</li>
<li>
<p>安全指示： 浏览器通常在地址栏中显示有关连接安全性的信息，如锁定图标或&quot;安全&quot;标签，以指示连接的加密状态。</p>
</li>
<li>
<p>国际化域名（IDN）支持： 浏览器会对国际化域名进行处理，确保它们在地址栏中正确显示，并在需要时进行Punycode编码。</p>
</li>
<li>
<p>复制与粘贴： 用户在地址栏中复制时，通常会复制显示的用户友好的URL，而不是编码后的URL。这是为了提高用户的可理解性。</p>
</li>
</ol>
<p>这里打算给自己挖个坑，想试着自己实现一个地址栏。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://www.wikiwand.com/zh/URL%E7%BC%96%E7%A0%81"  target="_blank" rel="noopener" >百分号编码 - Wikiwand</a></li>
<li><a href="https://www.wikiwand.com/zh-cn/UTF-8"  target="_blank" rel="noopener" >UTF-8 - Wikiwand</a></li>
<li><a href="https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php"  target="_blank" rel="noopener" >中文字符集 Unicode 编码范围</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/omnibox"  target="_blank" rel="noopener" >omnibox - Mozilla | MDN</a></li>
<li><a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%97%A5%E9%9F%93%E7%B5%B1%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97?oldformat=true"  target="_blank" rel="noopener" >中日韩统一表意文字 - 维基百科，自由的百科全书</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>编译原理复习笔记</title>
      <link>https://ds63.eu.org/2024/learn-compile-principle/</link>
      <pubDate>Mon, 15 Jan 2024 19:51:22 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/learn-compile-principle/</guid>
      <description>编译原理复习笔记</description>
      <content:encoded><![CDATA[<h2 id="第二章">第二章</h2>
<h3 id="无ε产生式的上下文无关文法要满足条件">无ε产生式的上下文无关文法要满足条件</h3>
<ol>
<li>若P中含S → ε ，则S不出现在任何产生式右部，其中S为文法的开始符号；</li>
<li>P中不再含有其它任何ε产生式</li>
</ol>
<h3 id="将有ε产生式的上下文无关文法转化为无ε产生式的上下文无关文法">将有ε产生式的上下文无关文法转化为无ε产生式的上下文无关文法</h3>
<ul>
<li>
<p>算法：
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-12-22-29-06.png" type="" alt="将有ε产生式的上下文无关文法转化为无ε产生式的上下文无关文法的算法"  /></p>
</li>
<li>
<p>示例：
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-12-22-31-55.png" type="" alt="将有ε产生式的上下文无关文法转化为无ε产生式的上下文无关文法的示例"  /></p>
</li>
</ul>
<h3 id="construct-context-free-grammars-with-ε-free-production">construct context-free grammars with ε-free production</h3>
<ol>
<li>画状态转换图</li>
<li>得到产生式</li>
</ol>
<h3 id="参考">参考</h3>
<p><a href="https://www.bilibili.com/video/BV1cW411B7DW/?p=8"  target="_blank" rel="noopener" >编译原理 东南大学 廖力 08</a></p>
<hr>
<h2 id="第三章">第三章</h2>
<h3 id="dfa-deterministic-finite-automata">DFA (Deterministic Finite Automata)</h3>
<ul>
<li>定义
<img loading="lazy" src="/2024/learn-compile-principle/2023-11-01-00-41-25.png" type="" alt="DFA定义"  /></li>
<li>特点：
<ul>
<li>no state has an 𝜖-transition(没有𝜖边)</li>
<li>for each state 𝑠 and input symbol 𝑎, there is at most one edge labeled 𝑎 leaving 𝑠(每个字符最多一条出边)</li>
</ul>
</li>
</ul>
<h3 id="regular-expression--nfa">Regular Expression → NFA</h3>
<p>Thompson’s Construction Rules
<img loading="lazy" src="/2024/learn-compile-principle/2023-11-01-00-18-14.png" type="" alt="Thompson’s Construction Rules"  /></p>
<h3 id="nfa---dfa-p153">NFA -&gt; DFA (P153)</h3>
<ul>
<li>算法：<strong>&ldquo;分身&rdquo;</strong></li>
</ul>
<p><img loading="lazy" src="/2024/learn-compile-principle/2023-11-01-00-52-27.png" type="" alt="DFA"  /></p>
<ul>
<li>示例：
<img loading="lazy" src="/2024/learn-compile-principle/2023-11-01-00-49-41.png" type="" alt="NFA-&amp;gt;DFA示例"  /></li>
</ul>
<h3 id="minimizing-the-number-of-states-of-a-dfa">Minimizing the Number of States of a DFA</h3>
<ol>
<li>Construct an initial partition ∏ of the set of states with two groups: the accepting states F and the non-accepting states 𝑆 − 𝐹. Π＝{𝐼0<!-- raw HTML omitted -->1<!-- raw HTML omitted -->,𝐼0<!-- raw HTML omitted -->2<!-- raw HTML omitted -->}（初始化）</li>
<li>For each group 𝐼 of Π<!-- raw HTML omitted -->𝑖<!-- raw HTML omitted -->, partition 𝐼 into subgroups such that two states 𝑠 and 𝑡 of 𝐼 are in the same subgroup if and only if for all input symbols 𝑎, 𝑚𝑜𝑣𝑒(𝑠, 𝑎) and 𝑚𝑜𝑣𝑒(𝑡, 𝑎) are in the same group of Π<!-- raw HTML omitted -->𝑖<!-- raw HTML omitted -->; replace 𝐼 in Π<!-- raw HTML omitted -->𝑖+1<!-- raw HTML omitted --> by the set of subgroups formed. （在所有输入符号上变迁都一样的放在一起）</li>
<li>If  Π<!-- raw HTML omitted -->𝑖+1<!-- raw HTML omitted --> = Π<!-- raw HTML omitted -->𝑖<!-- raw HTML omitted -->, let Π<!-- raw HTML omitted -->final<!-- raw HTML omitted --> = Π<!-- raw HTML omitted -->𝑖+1<!-- raw HTML omitted --> and continue with step (4). Otherwise, repeat step (2) with Π𝑖+1.（最后一个大步骤是白干的）</li>
<li>Choose one state in each group of the partition Π𝑓𝑖𝑛𝑎𝑙 as the representative for that group. The representatives will be the states of the reduced DFA 𝑀’. Let 𝑠 and 𝑡 be representative states for 𝑠’s and 𝑡’s group respectively, and suppose on input 𝑎 there is a transition of 𝑀 from 𝑠 to 𝑡. Then 𝑀’ has a transition from 𝑠 to 𝑡 on 𝑎.（每个group一个结点）</li>
<li>If 𝑀’ has a dead state (a state that is not accepting and that has transitions to itself on all input symbols), then remove it. Also remove any states not reachable from the start state. （删除死状态和不可达状态）</li>
</ol>
<hr>
<h2 id="第四章">第四章</h2>
<h3 id="elimination-of-left-recursion">Elimination of Left Recursion</h3>
<ol>
<li>
<p>Elimination of Immediate Left Recursion（消立即左递归）
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-12-22-37-49.png" type="" alt="消立即左递归的方法"  /></p>
</li>
<li>
<p>Elimination of Indirect Left Recursion （消间接左递归）</p>
<ul>
<li>算法：
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-12-22-45-12.png" type="" alt="消间接左递归的算法"  /></li>
<li>示例：
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-10-29-57.png" type="" alt="消间接左递归的示例"  /></li>
</ul>
</li>
</ol>
<h3 id="extract-maximum-common-left-factors">Extract maximum common left factors</h3>
<p>Change productions like
𝐴 → 𝛿𝛽<!-- raw HTML omitted -->1<!-- raw HTML omitted -->|𝛿𝛽<!-- raw HTML omitted -->2<!-- raw HTML omitted -->| …|𝛿𝛽<!-- raw HTML omitted -->n<!-- raw HTML omitted -->| 𝑟
into
𝐴 → 𝛿𝐴′ | 𝑟
𝐴′ → 𝛽<!-- raw HTML omitted -->1<!-- raw HTML omitted -->| 𝛽<!-- raw HTML omitted -->2<!-- raw HTML omitted -->| … | 𝛽<!-- raw HTML omitted -->n<!-- raw HTML omitted -->
Where, 𝛿 is the longest prefix of the alternatives of A</p>
<h3 id="求first">求FIRST</h3>
<h4 id="first">FIRST</h4>
<p><img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-11-02-10.png" type="" alt="FIRST"  /></p>
<h4 id="𝐸𝑣𝑎𝑙_𝐹𝐼𝑅𝑆𝑇𝑌sub1sub𝑌sub2sub--𝑌subksub">𝐸𝑣𝑎𝑙_𝐹𝐼𝑅𝑆𝑇(𝑌<!-- raw HTML omitted -->1<!-- raw HTML omitted -->𝑌<!-- raw HTML omitted -->2<!-- raw HTML omitted --> … 𝑌<!-- raw HTML omitted -->k<!-- raw HTML omitted -->)</h4>
<ul>
<li>If 𝑋 is terminal, then 𝐹𝐼𝑅𝑆𝑇(𝑋) = {𝑋}.</li>
<li>If 𝑋 is a nonterminal and 𝑋 → 𝑌<!-- raw HTML omitted -->1<!-- raw HTML omitted -->𝑌<!-- raw HTML omitted -->2<!-- raw HTML omitted --> … 𝑌<!-- raw HTML omitted -->k<!-- raw HTML omitted --> is a production for some 𝑘 ≥ 1, then place 𝑎 in 𝐹𝐼𝑅𝑆𝑇(𝑋) if for some 𝑖, 𝑎 is in 𝐹𝐼𝑅𝑆𝑇(𝑌<!-- raw HTML omitted -->i<!-- raw HTML omitted -->), and 𝜀 is in all of 𝐹𝐼𝑅𝑆𝑇 𝑌<!-- raw HTML omitted -->1<!-- raw HTML omitted --> , … , 𝐹𝐼𝑅𝑆𝑇 𝑌<!-- raw HTML omitted -->i-1<!-- raw HTML omitted --> ; that is, Y<!-- raw HTML omitted -->1<!-- raw HTML omitted --> … 𝑌<!-- raw HTML omitted -->i-1<!-- raw HTML omitted --> ⇒ 𝜀 . （前面的兄弟都躲了，我变成了排头兵）</li>
<li>If 𝜀 is in 𝐹𝐼𝑅𝑆𝑇 𝑌<!-- raw HTML omitted -->j<!-- raw HTML omitted --> for all 𝑗 = 1, 2, … , 𝑘, then add 𝜀 to 𝐹𝐼𝑅𝑆𝑇(𝑋). （全班都当了逃兵）</li>
<li>If 𝑋 → 𝜀 is a production, then add 𝜀 to 𝐹𝐼𝑅𝑆𝑇(𝑋).</li>
<li>注：𝐹𝐼𝑅𝑆𝑇(𝑋) is a data structure that represents a set while indexed by 𝑋. (𝐹𝐼𝑅𝑆𝑇(𝑋)是一个表示集合的数据结构，不是函数调用，X是下标不是函数的参数。)</li>
<li>注：𝐹𝐼𝑅𝑆𝑇(𝑋) is not a function in the sense of programming language, which can not be taken as a left value, but in the sense of mathematics</li>
</ul>
<h4 id="the-fixed-point-algorithm-for-evaluation-of-first">The Fixed-point Algorithm for Evaluation of First</h4>
<pre tabindex="0"><code>{
for all nonterminal 𝑋 do
𝐹𝐼𝑅𝑆𝑇(𝑋) = Φ;
do
for all production 𝑋 → 𝛼; 
𝐹𝐼𝑅𝑆𝑇(𝑋) → 𝐹𝐼𝑅𝑆𝑇(𝑋) ∪ 𝐸𝑣𝑎𝑙_𝐹𝐼𝑅𝑆𝑇(𝛼) ;
until (∀𝑋 ∈ 𝑉_𝑁, 𝐹𝐼𝑅𝑆𝑇(𝑋) unchanged);
}
</code></pre><h3 id="求follow">求FOLLOW</h3>
<h4 id="要点">要点</h4>
<ol>
<li>Place $ in 𝐹𝑂𝐿𝐿𝑂𝑊(𝑆), where 𝑆 is the start symbol and $ is the input right end-marker.</li>
<li>If there is 𝐴 → αB𝛽 in 𝐺, then add (𝐹𝐼𝑅𝑆𝑇(𝛽) −{𝜀}) to 𝐹𝑂𝐿𝐿𝑂𝑊(𝐵). (看有弟弟妹妹的非终结符)</li>
<li>If there is A →αB, then add FOLLOW(A) to FOLLOW(B). (看住在最右边上的非终结符)</li>
<li>If there is A→αB𝛽 where FIRST(𝛽) contains 𝜀，then add FOLLOW(A) to FOLLOW(B). (看不住在最右边，但实际可能暴露在最右边的非终结符)</li>
</ol>
<h4 id="示例">示例</h4>
<p><img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-13-57-03.png" type="" alt="求FOLLOW示例1"  />
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-13-57-31.png" type="" alt="求FOLLOW示例2"  /></p>
<h3 id="求predictive-parsing-table">求Predictive Parsing Table</h3>
<ul>
<li>Input: Grammar 𝐺.</li>
<li>Output: Parsing table 𝑀.</li>
<li>Method: For each production 𝐴 → 𝛼
<ol>
<li>For each terminal 𝑎 in 𝐹𝐼𝑅𝑆𝑇(𝛼), add 𝐴 → 𝛼 to 𝑀[𝐴, 𝑎].</li>
<li>If 𝜀 is in 𝐹𝐼𝑅𝑆𝑇(𝛼), add 𝐴 → 𝛼 to 𝑀[𝐴, 𝑏] for each terminal 𝑏 in 𝐹𝑂𝐿𝐿𝑂𝑊(𝐴).</li>
<li>If 𝜀 is in 𝐹𝐼𝑅𝑆𝑇(𝛼) and $ is in 𝐹𝑂𝐿𝐿𝑂𝑊(𝐴), add 𝐴 → 𝛼 to 𝑀[𝐴, $] as well.</li>
<li>Make each undefined entry of 𝑀 be 𝒆𝒓𝒓𝒐𝒓.</li>
</ol>
</li>
</ul>
<h3 id="ll1-grammar">LL(1) Grammar</h3>
<h4 id="含义">含义</h4>
<ol>
<li>The first “L” stands for scanning the input from left to right.</li>
<li>The second “L” stands for producing a leftmost derivation.</li>
<li>“1” means using one input symbol of look-ahead at each step to make parsing action decisions.</li>
</ol>
<h4 id="条件">条件</h4>
<ul>
<li>LL(1)文法的充要条件：LL(1)分析表中没有冲突项。</li>
</ul>
<h3 id="constructing-lr1-sets-of-items">Constructing LR(1) Sets of Items</h3>
<ul>
<li>参考: <a href="https://www.bilibili.com/video/BV1cW411B7DW/?p=41"  target="_blank" rel="noopener" >编译原理 东南大学 廖力 41</a></li>
</ul>
<h3 id="canonical-lr1-parsing-tables">Canonical LR(1) Parsing Tables</h3>
<ul>
<li>Input: An augmented grammar G'</li>
<li>Output: The canonical LR parsing table functions action and goto for G'</li>
<li>Method:
<ol>
<li>Construct C={I<!-- raw HTML omitted -->0<!-- raw HTML omitted -->,I<!-- raw HTML omitted -->1<!-- raw HTML omitted -->,…I<!-- raw HTML omitted -->n<!-- raw HTML omitted -->}, the collection of sets of LR(1) items for G'.</li>
<li>State 𝑖 is constructed from 𝐼<!-- raw HTML omitted -->i<!-- raw HTML omitted -->. The parsing actions for state 𝑖 are determined as follows:
<ul>
<li>If <code>[𝐴 → 𝛼 ∙ 𝑎𝛽, 𝑏]</code> is in 𝐼<!-- raw HTML omitted -->i<!-- raw HTML omitted --> and GOTO(𝐼𝑖, 𝑎)= 𝐼<!-- raw HTML omitted -->j<!-- raw HTML omitted -->, then set ACTION[𝑖,𝑎] to “Shift 𝑗”(简记为sj), here 𝑎 must be a terminal.</li>
<li>If <code>[𝐴 → 𝛼 ∙, 𝑎]</code> ∈ 𝐼<!-- raw HTML omitted -->i<!-- raw HTML omitted -->, 𝐴 ≠ 𝑆’, then set ACTION[i, a] to “Reduce j”(简记为rj) , where j is the No. of production 𝐴 → 𝛼.</li>
<li>If <code>[𝑆′→ 𝑆 ∙, $]</code> ∈ 𝐼<!-- raw HTML omitted -->i<!-- raw HTML omitted -->, then set ACTION[i, $] to “accept”(简记为acc).</li>
</ul>
</li>
<li>The GOTO transitions for state 𝑖 are determined as follows: if GOTO(𝐼<!-- raw HTML omitted -->i<!-- raw HTML omitted -->, 𝐴)= 𝐼<!-- raw HTML omitted -->j<!-- raw HTML omitted -->, then GOTO(𝑖, 𝐴)=𝑗.</li>
<li>All entries not defined by rules 2 and 3 are made “error”</li>
<li>The initial state of the parser is the one constructed from the set of items containing <code>[𝑆′→∙ 𝑆, $]</code>.</li>
</ol>
</li>
<li>示例
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-17-04-53.png" type="" alt="LR(1) Parsing Tables示例1"  />
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-13-17-05-19.png" type="" alt="LR(1) Parsing Tables示例2"  /></li>
</ul>
<hr>
<h2 id="第五章">第五章</h2>
<h3 id="annotated-parse-tree">Annotated parse tree</h3>
<p><img loading="lazy" src="/2024/learn-compile-principle/2024-01-14-10-39-23.png" type="" alt="Annotated parse tree"  /></p>
<h3 id="synthesized-attributes">Synthesized Attributes</h3>
<p>Each grammar production 𝐴 → 𝛼 has associated with it a set of semantic rules of the form 𝑏 =𝑓(𝑐1, 𝑐2, … . , 𝑐𝑘), 𝑓 is a function.</p>
<p>If 𝑏 is a synthesized attribute of 𝐴, then 𝑐1, 𝑐2,… , 𝑐𝑘 are attributes belonging to the grammar symbols of the production.</p>
<h3 id="inherited-attributes">Inherited Attributes</h3>
<p>For production 𝐴 → 𝛼 and its associated semantic rule of the form 𝑏 = 𝑓(𝑐1, 𝑐2, … . , 𝑐𝑘).</p>
<p>If 𝑏 is an inherited attribute of one of the grammar symbols on the right side of the production, then 𝑐1, 𝑐2, … , 𝑐𝑘 are attributes belonging to the grammar symbols of the production.</p>
<h3 id="题">题</h3>
<p><img loading="lazy" src="/2024/learn-compile-principle/2024-01-14-13-55-35.png" type="" alt="第五章题示例"  />
<img loading="lazy" src="/2024/learn-compile-principle/2024-01-14-13-56-03.png" type="" alt="第五章题示例解答"  /></p>
<hr>
<h2 id="第六章">第六章</h2>
<h3 id="symbolic-labels-vs-position-numbers">Symbolic Labels vs. Position Numbers</h3>
<ul>
<li>Symbolic Labels(语句标号)： 类比昵称</li>
<li>Position Numbers(语句序号): 严格编号</li>
</ul>
<h3 id="three-address-code-tac">Three-address Code (TAC)</h3>
<ul>
<li>A sequence of statements of the general form <code>𝑥 = 𝑦 𝑜𝑝 z</code></li>
<li>An address can be one of the following
<ul>
<li>A name(source-program names).</li>
<li>A constant.</li>
<li>A compiler-generated temporary.</li>
</ul>
</li>
<li>types:
<ol>
<li>x = y op z</li>
<li>x = op y</li>
<li>x = y</li>
<li>An unconditional jump : goto L</li>
<li>A conditional jump</li>
<li>&hellip;&hellip;</li>
</ol>
</li>
</ul>
<h3 id="quadruples">Quadruples</h3>
<p><img loading="lazy" src="/2024/learn-compile-principle/2024-01-14-17-27-26.png" type="" alt="Quadruples"  /></p>
<ul>
<li>Conditional and unconditional jumps put the target label in 𝑟𝑒𝑠𝑢𝑙𝑡.</li>
</ul>
<h3 id="short-circuit">Short-Circuit</h3>
<h4 id="short-circuit-or-jumping-code-of-boolean-expressions">Short-Circuit (or jumping) Code of Boolean Expressions</h4>
<ol>
<li>B1 || B2</li>
</ol>
<pre tabindex="0"><code>if B1 goto B.true 
goto B1.false 
B1.false: if B2 goto B.true 
          goto B.false 
</code></pre><ol start="2">
<li>B1 &amp;&amp; B2</li>
</ol>
<pre tabindex="0"><code>if B1 goto B1.true 
goto B.false 
B1.true: if B2 goto B.true 
         goto B.false 
</code></pre><h3 id="translate-the-program-fragment-into-three-address-code">Translate the program fragment into three-address code</h3>
<ul>
<li>例题</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">product</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">count</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="n">i</span><span class="o">&lt;=</span><span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span><span class="n">j</span><span class="o">&lt;=</span><span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">      <span class="n">product</span><span class="o">=</span><span class="n">product</span><span class="o">*</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">      <span class="n">count</span><span class="o">=</span><span class="n">count</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">j</span><span class="o">=</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">product</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="n">product</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="n">product</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Notes: Here we assume that the declaration of array A is array [1..10,1..10], each data element of array A would only use 1 storage unit, and the start address of array A’s storage area is addrA.</p>
<ul>
<li>解答</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="mi">1</span>  <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>  <span class="n">product</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">3</span>  <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>  <span class="k">if</span> <span class="n">i</span><span class="o">&lt;=</span><span class="mi">10</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">6</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="mi">5</span>  <span class="nf">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="mi">6</span>  <span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">7</span>  <span class="k">if</span> <span class="n">j</span><span class="o">&lt;=</span><span class="mi">10</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="mi">8</span>  <span class="nf">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">30</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="mi">9</span>  <span class="n">t1</span><span class="o">=</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//L-&gt;id[E], a数组的第一维的下标的low不为0；结合ppt讲解
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">10</span> <span class="n">t2</span><span class="o">=</span><span class="n">t1</span><span class="o">*</span><span class="mi">10</span><span class="p">;</span> <span class="c1">//a数组的内嵌数组为一行，占用空间为10*1。此处的10*1是事先计算好放在符号表里的。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">11</span> <span class="n">t3</span><span class="o">=</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>  <span class="c1">//根据L-&gt;L1[E]的语义规则得到
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">12</span> <span class="n">t4</span><span class="o">=</span><span class="n">t3</span><span class="o">*</span><span class="mi">1</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="mi">13</span> <span class="n">t5</span><span class="o">=</span> <span class="n">t2</span><span class="o">+</span><span class="n">t4</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="mi">14</span> <span class="n">t6</span><span class="o">=</span><span class="n">addrA</span><span class="p">[</span><span class="n">t5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="mi">15</span> <span class="k">if</span> <span class="n">t6</span><span class="o">&lt;&gt;</span><span class="mi">0</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">17</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">16</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">27</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">17</span> <span class="n">t7</span><span class="o">=</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//L-&gt;id[E], a数组的第一维的下标的low不为0；结合ppt讲解
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">18</span> <span class="n">t8</span><span class="o">=</span><span class="n">t7</span><span class="o">*</span><span class="mi">10</span><span class="p">;</span> <span class="c1">//a数组的内嵌数组为一行，占用空间为10*1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">19</span> <span class="n">t9</span><span class="o">=</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>  <span class="c1">//L-&gt;L1[E]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">20</span> <span class="n">t10</span><span class="o">=</span><span class="n">t9</span><span class="o">*</span><span class="mi">1</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="mi">21</span> <span class="n">t11</span><span class="o">=</span> <span class="n">t8</span><span class="o">+</span><span class="n">t10</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="mi">22</span> <span class="n">t12</span><span class="o">=</span><span class="n">addrA</span><span class="p">[</span><span class="n">t11</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="mi">23</span> <span class="n">t13</span><span class="o">=</span><span class="n">product</span><span class="o">*</span><span class="n">t12</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">24</span> <span class="n">product</span><span class="o">=</span><span class="n">t13</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">25</span> <span class="n">t14</span><span class="o">=</span><span class="n">count</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">26</span> <span class="n">count</span><span class="o">=</span><span class="n">t4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">27</span> <span class="n">t15</span><span class="o">=</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">28</span> <span class="n">j</span><span class="o">=</span><span class="n">t15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">29</span> <span class="nf">goto</span> <span class="p">(</span><span class="mi">7</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">30</span> <span class="n">t16</span><span class="o">=</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">31</span> <span class="n">i</span><span class="o">=</span><span class="n">t16</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">32</span> <span class="k">if</span> <span class="p">(</span><span class="n">product</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">)</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">34</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">33</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">36</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">34</span> <span class="n">product</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="mi">35</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">(</span><span class="mi">37</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">36</span> <span class="n">product</span> <span class="o">=</span> <span class="mi">1</span> 
</span></span><span class="line"><span class="cl"><span class="mi">37</span> <span class="k">goto</span> <span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">记录：</span><span class="n">L</span><span class="p">.</span><span class="n">nextlist</span><span class="o">=</span><span class="mi">5</span>
</span></span></code></pre></div><hr>
<h2 id="第七章">第七章</h2>
<h3 id="environment-and-state">Environment and State</h3>
<p>In programming language semantics：</p>
<ul>
<li>the term “environment” refers to a function that maps a name to a storage location</li>
<li>the term “state” refers to a function that maps a storage location to the value held there.</li>
</ul>
<h3 id="activation-tree">Activation Tree</h3>
<p>A tree to depict the control flow enters and leaves activation of a procedure.</p>
<h3 id="activation-records">Activation Records</h3>
<h4 id="组成">组成</h4>
<ol>
<li>control link
<ul>
<li>pointing to the activation record of the caller</li>
</ul>
</li>
<li>access link
<ul>
<li>to locate data needed by the called procedure but found elsewhere, e.g., in another activation record.</li>
</ul>
</li>
<li>saved machine status
<ul>
<li>return address</li>
<li>the contents of registers</li>
</ul>
</li>
</ol>
<h3 id="construct-a-maximum-stack-map-for-a-c-recursive-program">Construct a maximum stack map for a C recursive program</h3>
<ol>
<li>先画出 Activation Tree</li>
<li>画出符合要求的stack map</li>
<li>画Activation Records</li>
</ol>
<hr>
<h2 id="第八-九章">第八-九章</h2>
<h3 id="the-dag-representation-of-basic-blocks">The DAG Representation of Basic Blocks</h3>
<ul>
<li>DAG(Directed acyclic graph): 有向无环图</li>
<li>节点代表值</li>
<li>节点旁标注具有该值的变量</li>
</ul>
<h3 id="优化">优化</h3>
<ol>
<li>Constant folding（常量合并）
<ul>
<li>Evaluate constant expressions at compile time and replace the constant expressions by their values.</li>
</ul>
</li>
<li>Common Subexpression Elimination</li>
</ol>
<h3 id="题目">题目</h3>
<ul>
<li>描述：Please construct the DAG for the following basic block, optimize the block and rewrite the block in optimized code form.</li>
<li>解答：
<ol>
<li>Construct the DAG</li>
<li>optimize the DAG</li>
<li>Rearranging the order(Heuristic Order)</li>
<li>Write out the optimized code sequence</li>
</ol>
</li>
</ul>
<h2 id="参考-1">参考</h2>
<ul>
<li><a href="https://www.skywind.me/blog/archives/2761"  target="_blank" rel="noopener" >56 行代码用 Python 实现一个 Flex/Lex - Skywind Inside</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>xx原神大学是如何实现的</title>
      <link>https://ds63.eu.org/2024/how-to-implement-xx-genshin-university/</link>
      <pubDate>Fri, 05 Jan 2024 01:09:45 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2024/how-to-implement-xx-genshin-university/</guid>
      <description>前段时间很常能看到xx原神大学的域名，今天来了解下它是如何实现的。</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>前段时间很常能看到xx原神大学的域名,有趣是有趣，但具体是怎么实现的倒真没去了解过。</p>
<p>今天看到群里有人问:</p>
<blockquote>
<p>所以玩原神玩的为什么搜出来来会是中科大？
我在dns查询上面查出来地址是75.126.101.233，而且无法访问</p>
</blockquote>
<p>好奇心驱使下，我展开了调查。</p>
<h2 id="已知">已知</h2>
<p>访问<a href="%e4%b8%ad%e5%9b%bd%e7%a7%91%e5%ad%a6%e6%8a%80%e6%9c%af%e5%a4%a7%e5%ad%a6.com" >中国科学技术大学.com</a>会跳转到<a href="https://ys.mihoyo.com/"  target="_blank" rel="noopener" >《原神》官方网站</a></p>
<p>而<a href="%e7%8e%a9%e5%8e%9f%e7%a5%9e%e7%8e%a9%e7%9a%84.com" >玩原神玩的.com</a>则是<a href="https://www.ustc.edu.cn/"  target="_blank" rel="noopener" >中国科学技术大学</a>。</p>
<h2 id="推测">推测</h2>
<p>我首先能想到可行的方法有两个:</p>
<ul>
<li>重定向,访问网站的时候，服务器返回一个重定向的网址。</li>
<li>DNS解析的时候就解析到了中科大的网站,比如：
<table>
<thead>
<tr>
<th>SUBDOMAIN</th>
<th>TYPE</th>
<th>VALUE</th>
<th>TTL, SEC</th>
</tr>
</thead>
<tbody>
<tr>
<td>@</td>
<td>CNAME</td>
<td>ustc.edu.cn</td>
<td>86400</td>
</tr>
</tbody>
</table>
</li>
</ul>
<h2 id="过程">过程</h2>
<ol>
<li>
<p>我很自然地想到，跳转嘛，我把网速限制得慢点就能看到没跳转前的了。这可以用浏览器自带的开发者工具来做。但无果。</p>
</li>
<li>
<p>我用<code>whois</code>查了下这个域名，得到</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">eu:~$ whois 玩原神玩的.com
</span></span><span class="line"><span class="cl">Domain Name: XN--8MR985EBA830AIYE.COM
</span></span><span class="line"><span class="cl">Registry Domain ID: 2822210486_DOMAIN_COM-VRSN
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div></li>
<li>
<p>这时候我以为这里的<code>XN--8MR985EBA830AIYE.COM</code>会是突破口，但查了下才知道：这是使用了<a href="https://www.wikiwand.com/en/Internationalized_domain_name"  target="_blank" rel="noopener" >国际化域名</a>，而<code>XN--8MR985EBA830AIYE.COM</code>是<code>玩原神玩的.com</code>的<a href="https://www.wikiwand.com/en/Punycode"  target="_blank" rel="noopener" >Punycode编码</a>。</p>
</li>
<li>
<p>看<a href="https://www.bilibili.com/read/cv27389269/"  target="_blank" rel="noopener" >【教程向】如何让 www.xx原神大学.com 跳转到你的学校的官网 - 哔哩哔哩</a>，它这里是用的第一种。但我需要验证<a href="%e7%8e%a9%e5%8e%9f%e7%a5%9e%e7%8e%a9%e7%9a%84.com" >玩原神玩的.com</a>也是用的方法。</p>
</li>
<li>
<p>尝试<code>traceroute</code>,没看出什么结果：</p>
</li>
<li>
<p>使用<code>curl -I</code>,结果如下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">eu:~$ curl -I 玩原神玩的.com
</span></span><span class="line"><span class="cl">HTTP/1.1 <span class="m">301</span> Moved Permanently
</span></span><span class="line"><span class="cl">Connection: close
</span></span><span class="line"><span class="cl">Connection: keep-alive
</span></span><span class="line"><span class="cl">Content-Type: text/html<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>UTF-8
</span></span><span class="line"><span class="cl">Date: Thu, <span class="m">04</span> Jan <span class="m">2024</span> 14:18:59 GMT
</span></span><span class="line"><span class="cl">Keep-Alive: <span class="nv">timeout</span><span class="o">=</span><span class="m">4</span>
</span></span><span class="line"><span class="cl">Location: http://ustc.edu.cn
</span></span><span class="line"><span class="cl">Proxy-Connection: keep-alive
</span></span><span class="line"><span class="cl">Server: nginx
</span></span><span class="line"><span class="cl">Strict-Transport-Security: max-age<span class="o">=</span>0<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">eu:~$ curl -I 中国科学技术大学.com
</span></span><span class="line"><span class="cl">HTTP/1.1 <span class="m">302</span> Found
</span></span><span class="line"><span class="cl">Connection: close
</span></span><span class="line"><span class="cl">Connection: keep-alive
</span></span><span class="line"><span class="cl">Date: Thu, <span class="m">04</span> Jan <span class="m">2024</span> 14:19:43 GMT
</span></span><span class="line"><span class="cl">Keep-Alive: <span class="nv">timeout</span><span class="o">=</span><span class="m">4</span>
</span></span><span class="line"><span class="cl">Location: https://ys.mihoyo.com/
</span></span><span class="line"><span class="cl">Proxy-Connection: keep-alive
</span></span><span class="line"><span class="cl">Server: namecheap-nginx
</span></span><span class="line"><span class="cl">X-Served-By: Namecheap URL Forward
</span></span></code></pre></div><p>这里验证了我的猜想，两个域名都是用的第一种方法。</p>
</li>
</ol>
<h2 id="解答">解答</h2>
<p>现在就能回答一开始的问题了:</p>
<ol>
<li>
<p>为什么访问<a href="%e7%8e%a9%e5%8e%9f%e7%a5%9e%e7%8e%a9%e7%9a%84.com" >玩原神玩的.com</a>会变成<a href="https://www.ustc.edu.cn/"  target="_blank" rel="noopener" >中国科学技术大学</a>?</p>
<p>因为对<a href="%e7%8e%a9%e5%8e%9f%e7%a5%9e%e7%8e%a9%e7%9a%84.com" >玩原神玩的.com</a>的所有请求都被重定向到了<a href="https://www.ustc.edu.cn/"  target="_blank" rel="noopener" >中国科学技术大学</a>对应的网站服务器。</p>
</li>
<li>
<p>为什么dns查询上面查出来地址是<code>75.126.101.233</code>，而且无法访问？</p>
<p>因为<code>75.126.101.233</code>是<a href="%e7%8e%a9%e5%8e%9f%e7%a5%9e%e7%8e%a9%e7%9a%84.com" >玩原神玩的.com</a>对应的ip，这个域名并没有自己对应的服务器,请求都被重定向掉了。而真正的<a href="https://www.ustc.edu.cn/"  target="_blank" rel="noopener" >中国科学技术大学</a>的ip是<code>202.141.176.6</code>。</p>
</li>
</ol>
<h2 id="总结">总结</h2>
<p>我之前以为自己已经了解其原理，所以没有多想。</p>
<p>但这次真正去了解后还是能收获些新知识的。比如国际化域名，Punycode编码等。</p>
<h2 id="吐槽">吐槽</h2>
<ul>
<li>我一开始还以为<a href="%e4%b8%ad%e5%9b%bd%e7%a7%91%e5%ad%a6%e6%8a%80%e6%9c%af%e5%a4%a7%e5%ad%a6.com" >中国科学技术大学.com</a>是属于学校官方的，还以为是用到了什么黑科技才做到让它跳转到<a href="https://ys.mihoyo.com/"  target="_blank" rel="noopener" >《原神》官方网站</a>的。但现在看来，并不是。这让我有些失望。</li>
<li>写这篇的时候我尝试让Copilot做自动补全，是能有些帮助，但还是不习惯，会有种自己的思路被带着走的感觉。我不喜欢这种感觉，于是关掉了。</li>
</ul>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.bilibili.com/read/cv27389269/"  target="_blank" rel="noopener" >【教程向】如何让 www.xx原神大学.com 跳转到你的学校的官网 - 哔哩哔哩</a></li>
<li><a href="https://www.wikiwand.com/en/Internationalized_domain_name"  target="_blank" rel="noopener" >Internationalized domain name - Wikiwand</a></li>
<li><a href="https://www.wikiwand.com/en/Punycode"  target="_blank" rel="noopener" >Punycode - Wikiwand</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>2023年度总结</title>
      <link>https://ds63.eu.org/2023/annual-summary-of-2023/</link>
      <pubDate>Sat, 23 Dec 2023 12:29:04 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/annual-summary-of-2023/</guid>
      <description>行行复行行</description>
      <content:encoded><![CDATA[<p><strong>去年就想写来着，也确实写了，但写了一半不到，发现因为拖得太久，回忆都不怎么回忆得起来了。今年吸取教训，2023年还没结束就开始写。</strong></p>
<h2 id="习惯">习惯</h2>
<p>新增了不少习惯。</p>
<h3 id="博客">博客</h3>
<p>今年四月份左右开始写博客。用的是<a href="https://hexo.io/"  target="_blank" rel="noopener" >Hexo</a>+<a href="https://hexo.fluid-dev.com/"  target="_blank" rel="noopener" >Fluid</a>，近乎开箱即用的使用体验，省了不少事，也算是开了个好头。</p>
<p>几个月后,我开始对博客有些自己的想法。最终在10月下旬开始换成了<a href="https://gohugo.io/"  target="_blank" rel="noopener" >Hugo</a>+<a href="https://github.com/reorx/hugo-PaperModX/"  target="_blank" rel="noopener" >hugo-PaperModX</a>。自己修改了不少东西。但总算是得到了一个自己满意的博客。可喜可贺。</p>
<p>也养成了每个月更新博客的习惯，我觉得这很好。</p>
<h3 id="记录">记录</h3>
<p>今年开始，我对自己的数据越来越上心。愿意多折腾下也要保存自己的记录。</p>
<p>具体记录在<a href="https://ds63.eu.org/2023/my-data/"  target="_blank" rel="noopener" >我的数据 | EuDs&rsquo;s Blog</a>。</p>
<h3 id="日记">日记</h3>
<p>年初的时候就开始写日记，但直到9月份开始，才养成了每天写日记的习惯。</p>
<p>写日记给我一种掌握自己时间的感觉，有时候我会觉得这一天没做什么，但开始写后会发现还是能写不少东西的，算是对一天的总结吧。</p>
<p>我的日记都按照了一定格式去整理，过几个月打算写个小工具，使得每天都能给我发去年今日自己发生了什么。</p>
<h3 id="leetcode">leetcode</h3>
<p>11月份的时候坚持了半个月的每天的一题，但后来由于各种原因，还是放弃了。</p>
<p>我对算法题不是太感冒，因为相比于算法，我更喜欢去花时间在实践上。</p>
<p>但这两者不应该是冲突的。</p>
<p>来年应该还会尝试每日一题。</p>
<h3 id="日语">日语</h3>
<p>也是11月左右，开始用多邻国学日语。每天十几分钟左右。</p>
<p>在读高中的时候，就想着学日语了，但一直没有去做。</p>
<p>所谓种一棵树最后的时间是在十年前，其次是现在。</p>
<p>不管怎么说，开始了总是件好事。希望自己能坚持下去。</p>
<hr>
<h2 id="编程">编程</h2>
<p>今年在ChatGPT和Claude，以及官方文档的帮助下，接触了几门语言。</p>
<p>这里很感慨，互联网和ai的存在，大大降低了学习的门槛，让我觉得自己很幸运。</p>
<p>但更让我觉得深耕一门语言的必要性。</p>
<h3 id="操作系统">操作系统</h3>
<p>可能今年做的最正确的一个决定，就是看了<a href="https://space.bilibili.com/202224425/channel/collectiondetail?sid=192498"  target="_blank" rel="noopener" >操作系统：设计与实现 (2022 春季学期)</a>。学到了很多东西，但更多的是进一步启发了我对编程的兴趣。</p>
<p>感谢蒋炎岩！</p>
<h3 id="vuereact">Vue、React</h3>
<p>借由两次课程项目的契机，分别对这两有了基本的接触,用来写了几个小项目。</p>
<p>两者相比较，我更喜欢React。</p>
<h3 id="python">Python</h3>
<p>我用Python写了好几个自己在用的小工具，写的时候体验都很不错。</p>
<h3 id="rust">Rust</h3>
<p>一直有想学Rust的打算，但直到今年7月份才正式开始。</p>
<p>Rust似乎对找工作没有帮助，但我还是想学。</p>
<p>因为我认可这门语言的设计理念，同时想挑战下自己的学习能力。</p>
<h3 id="javascript">JavaScript</h3>
<p>没有怎么系统性地学习，只是用到的时候才去看。</p>
<p>除了写前端，还有用它来写油猴脚本。</p>
<p>值得一提的是用这门语言写了一个目前我自己使用频率最高的小工具。</p>
<p><a href="https://github.com/EuDs63/TemperMonkeyScripts/blob/main/Copy%20Web%20Title%20and%20Url.user.js"  target="_blank" rel="noopener" >TemperMonkeyScripts/Copy Web Title and Url.user.js</a></p>
<p>功能很简单，代码也只有几行。但却很贴合我的需求，我几乎每天都会用到好几次。</p>
<p>对我来说，这是个很好的编程让生活更方便的例子。</p>
<hr>
<h2 id="其他">其他</h2>
<h3 id="出游">出游</h3>
<p>今年是我不受疫情管控影响的第一年大学生活。</p>
<p>只要天气允许，每周我都会出游一到两次。</p>
<p>有时候犯懒不想出去，但克服懒劲出去后总会觉得自己的决定是正确的。</p>
<p>走出去总能看到新风景，有些新想法。</p>
<h3 id="读书">读书</h3>
<p>今年也花了不少时间在读书上，具体记录在<a href="https://neodb.social/users/EuDs63/"  target="_blank" rel="noopener" >NeoDB - 我的个人主页</a></p>
<p>我也写了几篇读后感,参见<a href="https://ds63.eu.org/tags/%E4%B9%A6%E8%AF%84/"  target="_blank" rel="noopener" >书评 | EuDs&rsquo;s Blog</a>。</p>
<p>我看书有个习惯，只要一本书让我读完觉得感兴趣，我就会去找这位作者的其他书来读,而今年主要读了这几位作者的书:</p>
<ul>
<li>金庸</li>
<li>村上春树</li>
<li>J.K.罗琳</li>
<li>森见登美彦</li>
</ul>
<p>金庸和J.K.罗琳的作品不少我都读过不止一次，但再读也还是能有乐趣。</p>
<h3 id="游戏">游戏</h3>
<p>今年花在游戏上的时间相较于往年少了不少。</p>
<p>但今年着实是个游戏大年,于是也玩到了不少好游戏。</p>
<p>五月份的王国之泪，暑假的成步堂精选集，九月份的博德之门三。</p>
<p>这几部游戏都是我美好的回忆。</p>
<p>我还特地为了王国之泪写了<a href="https://ds63.eu.org/2023/tears-of-the-kingdom/"  target="_blank" rel="noopener" >一篇博客</a>，真的很棒的一款游戏。</p>
<p>还有其他几款独立制作的小游戏: Brotato, Thronefall,也带给我不少乐趣。</p>
<h3 id="番剧">番剧</h3>
<p>看了好几部，具体记录在<a href="https://bgm.tv/user/euds63"  target="_blank" rel="noopener" >我的时光机</a></p>
<p>其中我最喜欢的有这几部：</p>
<ul>
<li>乌龙派出所</li>
<li>BanG Dream! It&rsquo;s MyGO!!!!!</li>
</ul>
<h3 id="开源">开源</h3>
<p>今年开始对开源有了进一步的了解。我发现，开源社区的门槛并没有想象中那么高。比如说，整理文档也是一种很重要的贡献。</p>
<p>我很喜欢开源这种互帮互助的理念。但今年所做的，还只是了解。</p>
<p>来年的目标，希望能提10个以上的pr。</p>
<hr>
<h2 id="尾巴">尾巴</h2>
<p>写这篇的时候深感自己文笔不行。丰富的一年却被我自己写成了流水账。但毕竟是头回写，也还能接受。</p>
<p>如果要说明年对自己的期望。我要求不高。</p>
<p>只要明年这个时候的自己，在回顾2024的时候，不会后悔自己度过每一天的方式。</p>
<p>我觉得就很棒了。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>读《秦妇吟》</title>
      <link>https://ds63.eu.org/2023/qin-fu-yin/</link>
      <pubDate>Thu, 14 Dec 2023 20:46:22 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/qin-fu-yin/</guid>
      <description>丧乱漂沦何堪说</description>
      <content:encoded><![CDATA[<h2 id="原文">原文</h2>
<p>秦妇吟 韦庄</p>
<p>中和癸卯春三月，洛阳城外花如雪。</p>
<p>东西南北路人绝，绿杨悄悄香尘灭。</p>
<p>路旁忽见如花人，独向绿杨阴下歇。</p>
<p>凤侧鸾欹鬓脚斜，红攒黛敛眉心折。</p>
<p>借问女郎何处来？含颦欲语声先咽。</p>
<p>回头敛袂谢行人，丧乱漂沦何堪说！</p>
<p>三年陷贼留秦地，依稀记得秦中事。</p>
<p>君能为妾解金鞍，妾亦与君停玉趾。</p>
<p>前年庚子腊月五，正闭金笼教鹦鹉。</p>
<p>斜开鸾镜懒梳头，闲凭雕栏慵不语。</p>
<p>忽看门外起红尘，已见街中擂金鼓。</p>
<p>居人走出半仓惶，朝士归来尚疑误。</p>
<p>是时西面官军入，拟向潼关为警急。</p>
<p>皆言博野自相持，尽道贼军来未及。</p>
<p>须臾主父乘奔至，下马入门痴似醉。</p>
<p>适逢紫盖去蒙尘，已见白旗来匝地。</p>
<p>扶羸携幼竞相呼，上屋缘墙不知次。</p>
<p>南邻走入北邻藏，东邻走向西邻避。</p>
<p>北邻诸妇咸相凑，户外崩腾如走兽。</p>
<p>轰轰昆昆乾坤动，万马雷声从地涌。</p>
<p>火迸金星上九天，十二官街烟烘烔。</p>
<p>日轮西下寒光白，上帝无言空脉脉。</p>
<p>阴云晕气若重围，宦者流星如血色。</p>
<p>紫气潜随帝座移，妖光暗射台星拆。</p>
<p>家家流血如泉沸，处处冤声声动地。</p>
<p>舞伎歌姬尽暗捐，婴儿稚女皆生弃。</p>
<p>东邻有女眉新画，倾国倾城不知价。</p>
<p>长戈拥得上戎车，回首香闺泪盈把。</p>
<p>旋抽金线学缝旗，才上雕鞍教走马。</p>
<p>有时马上见良人，不敢回眸空泪下；</p>
<p>西邻有女真仙子，一寸横波剪秋水。</p>
<p>妆成只对镜中春，年幼不知门外事。</p>
<p>一夫跳跃上金阶，斜袒半肩欲相耻。</p>
<p>牵衣不肯出朱门，红粉香脂刀下死。</p>
<p>南邻有女不记姓，昨日良媒新纳聘。</p>
<p>琉璃阶上不闻行，翡翠帘间空见影。</p>
<p>忽看庭际刀刃鸣，身首支离在俄顷。</p>
<p>仰天掩面哭一声，女弟女兄同入井；</p>
<p>北邻少妇行相促，旋拆云鬟拭眉绿。</p>
<p>已闻击托坏高门，不觉攀缘上重屋。</p>
<p>须臾四面火光来，欲下回梯梯又摧。</p>
<p>烟中大叫犹求救，梁上悬尸已作灰。</p>
<p>妾身幸得全刀锯，不敢踟蹰久回顾。</p>
<p>旋梳蝉鬓逐军行，强展蛾眉出门去。</p>
<p>旧里从兹不得归，六亲自此无寻处。</p>
<p>一从陷贼经三载，终日惊忧心胆碎。</p>
<p>夜卧千重剑戟围，朝餐一味人肝脍。</p>
<p>鸳帏纵入岂成欢？宝货虽多非所爱。</p>
<p>蓬头垢面眉犹赤，几转横波看不得。</p>
<p>衣裳颠倒语言异，面上夸功雕作字。</p>
<p>柏台多半是狐精，兰省诸郎皆鼠魅。</p>
<p>还将短发戴华簪，不脱朝衣缠绣被。</p>
<p>翻持象笏作三公，倒佩金鱼为两史。</p>
<p>朝闻奏对入朝堂，暮见喧呼来酒市。</p>
<p>一朝五鼓人惊起，叫啸喧呼如窃语。</p>
<p>夜来探马入皇城，昨日官军收赤水。</p>
<p>赤水去城一百里，朝若来兮暮应至。</p>
<p>凶徒马上暗吞声，女伴闺中潜生喜。</p>
<p>皆言冤愤此时销，必谓妖徒今日死。</p>
<p>逡巡走马传声急，又道官军全阵入。</p>
<p>大彭小彭相顾忧，二郎四郎抱鞍泣。</p>
<p>沉沉数日无消息，必谓军前已衔璧。</p>
<p>簸旗掉剑却来归，又道官军悉败绩。</p>
<p>四面从兹多厄束，一斗黄金一斗粟。</p>
<p>尚让厨中食木皮，黄巢机上刲人肉。</p>
<p>东南断绝无粮道，沟壑渐平人渐少。</p>
<p>六军门外倚僵尸，七架营中填饿殍。</p>
<p>长安寂寂今何有？废市荒街麦苗秀。</p>
<p>采樵斫尽杏园花，修寨诛残御沟柳。</p>
<p>华轩绣毂皆销散，甲第朱门无一半。</p>
<p>含元殿上狐兔行，花萼楼前荆棘满。</p>
<p>昔时繁盛皆埋没，举目凄凉无故物。</p>
<p>内库烧为锦绣灰，天街踏尽公卿骨！</p>
<p>来时晓出城东陌，城外风烟如塞色。</p>
<p>路旁时见游奕军，坡下寂无迎送客。</p>
<p>霸陵东望人烟绝，树锁骊山金翠灭。</p>
<p>大道俱成棘子林，行人夜宿墙匡月。</p>
<p>明朝晓至三峰路，百万人家无一户。</p>
<p>破落田园但有蒿，摧残竹树皆无主。</p>
<p>路旁试问金天神，金天无语愁于人。</p>
<p>庙前古柏有残枿，殿上金炉生暗尘。</p>
<p>一从狂寇陷中国，天地晦冥风雨黑。</p>
<p>案前神水咒不成，壁上阴兵驱不得。</p>
<p>闲日徒歆奠飨恩，危时不助神通力。</p>
<p>我今愧恧拙为神，且向山中深避匿。</p>
<p>寰中箫管不曾闻，筵上牺牲无处觅。</p>
<p>旋教魇鬼傍乡村，诛剥生灵过朝夕。</p>
<p>妾闻此语愁更愁，天遣时灾非自由。</p>
<p>神在山中犹避难，何须责望东诸侯！</p>
<p>前年又出杨震关，举头云际见荆山。</p>
<p>如从地府到人间，顿觉时清天地闲。</p>
<p>陕州主帅忠且贞，不动干戈唯守城。</p>
<p>蒲津主帅能戢兵，千里晏然无犬声。</p>
<p>朝携宝货无人问，暮插金钗唯独行。</p>
<p>明朝又过新安东，路上乞浆逢一翁。</p>
<p>苍苍面带苔藓色，隐隐身藏蓬荻中。</p>
<p>问翁本是何乡曲？底事寒天霜露宿？</p>
<p>老翁暂起欲陈辞，却坐支颐仰天哭。</p>
<p>乡园本贯东畿县，岁岁耕桑临近甸。</p>
<p>岁种良田二百廛，年输户税三千万。</p>
<p>小姑惯织褐絁袍，中妇能炊红黍饭。</p>
<p>千间仓兮万丝箱，黄巢过后犹残半。</p>
<p>自从洛下屯师旅，日夜巡兵入村坞。</p>
<p>匣中秋水拔青蛇，旗上高风吹白虎。</p>
<p>入门下马若旋风，罄室倾囊如卷土。</p>
<p>家财既尽骨肉离，今日垂年一身苦。</p>
<p>一身苦兮何足嗟，山中更有千万家。</p>
<p>朝饥山上寻蓬子，夜宿霜中卧荻花！</p>
<p>妾闻此老伤心语，竟日阑干泪如雨。</p>
<p>出门惟见乱枭鸣，更欲东奔何处所？</p>
<p>仍闻汴路舟车绝，又道彭门自相杀。</p>
<p>野色徒销战士魂，河津半是冤人血。</p>
<p>适闻有客金陵至，见说江南风景异。</p>
<p>自从大寇犯中原，戎马不曾生四鄙。</p>
<p>诛锄窃盗若神功，惠爱生灵如赤子。</p>
<p>城壕固护教金汤，赋税如云送军垒。</p>
<p>奈何四海尽滔滔，湛然一境平如砥。</p>
<p>避难徒为阙下人，怀安却羡江南鬼。</p>
<p>愿君举棹东复东，咏此长歌献相公。</p>
<hr>
<h2 id="感想">感想</h2>
<ol>
<li>
<p>“丧乱漂沦何堪说” 这句很有感觉</p>
</li>
<li>
<p>“东邻有女”至“北邻少妇”这段，读的时候虽不能说是感同身受，但也类似于浑身战栗。</p>
</li>
<li>
<p>“内库烧为锦绣灰，天街踏尽公卿骨” 这句读来也很有感觉。画面感？</p>
</li>
<li>
<p>&ldquo;一身苦兮何足嗟，山中更有千万家。&rdquo; 读这句时，我想到“安得广厦千万间”</p>
</li>
<li>
<p>“路旁试问金天神”这一段也很有意思。我读的时候只看到了字面意思。但看赏析说是借此讽刺节度使，我水平有限，没想到这层。</p>
</li>
<li>
<p>“朝携宝货无人问，暮插金钗唯独行。”。这句我自己读以为是讲治安好，看赏析说的是讲战争过后几乎没人了。</p>
</li>
<li>
<p>“适闻有客金陵至，见说江南风景异。” 我主页的诗词随机到过这一句，但那时候我还没读过这首诗，没想到是这个意思。</p>
</li>
</ol>
<hr>
<h2 id="历史">历史</h2>
<p>我查了下这首诗的历史。发现这首诗经历了多个阶段。</p>
<ol>
<li>韦庄创作出这首诗后的一段时间流传很广，让韦庄为“秦妇吟秀才”。</li>
<li>因为诗中讽刺唐军的内容，“尔后公卿亦多垂讶，庄乃讳之”。韦庄不仅去收回了本诗的抄本，也没有在自己的诗集中收录,甚至“撰家戒，内不许垂《秦妇吟》障子”。</li>
<li>宋朝之后只剩“内库烧为锦绣灰，天街踏尽公卿骨”流传于世。</li>
<li>1899年，敦煌莫高窟藏经洞被发现。1909年12月，法国考古学家伯希和携带部分敦煌经卷来到北京，罗振玉去看，发现疑似《秦妇吟》的写本，后来王国维再根据日本人抄录的敦煌残卷里“天街踏尽公卿骨”这一名句断定并整理恢复了失传一千多年的《秦妇吟》全诗。</li>
<li>因为其中对黄巢农民军的批判，这首诗在新中国早期被认为诗反动诗，社科院出的《唐诗选》不收，唐诗鉴赏辞典也不收。一直到1984年，《中华活叶文选》才第一次出现。</li>
</ol>
<p>看到一个总结，我觉得写得比我好。</p>
<blockquote>
<p>俞平伯如此评论其命运，“一被谤讳隐于作者之生前，二亡佚于作者之身后，历宋元明清而不见；及其复出于西陲石窟也，又不为今人所喜，其遭遇何其不幸哉！”</p>
</blockquote>
<p>这是首好诗吗？肯定是。就凭时隔一千多年后的我，即使没有经历过当年的事情，也能被诗中的情绪所打动这一点，这首诗就是好诗。</p>
<p>但这样的好诗，却在相当长的历史岁月中被雪藏。</p>
<p>我读这首诗的时候，正好在听一个歌单，收集了一些被禁歌曲。其中我听完后有印象的几首是：</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=9Lv394CKRZE&amp;ab_channel=TimelessMusic"  target="_blank" rel="noopener" >郑智化 - 大国民</a></li>
<li><a href="https://www.youtube.com/watch?v=tqWL0KAlLyA&amp;ab_channel=KimIII"  target="_blank" rel="noopener" >羅大佑 - 綠色恐怖主義</a></li>
<li><a href="https://www.youtube.com/watch?v=YFOGHX7jw7k"  target="_blank" rel="noopener" >林暐哲 - 臺北帝國</a></li>
<li><a href="https://www.youtube.com/watch?v=Iu1uUDkXTtY"  target="_blank" rel="noopener" >my little airport - 瓜分林瑞麟三十萬薪金</a></li>
</ul>
<p>我发现这个歌单有些歌我没听完就想切歌，因为不好听。但有些歌还蛮好听的，甚至吸引我特地去查下别人的评论，能在其中看到不同人对历史事件的不同观点。</p>
<p>这些历史事件究竟该如何看待，不是我这篇博客所想涉及的，但结合这首诗的经历，我有一种观点：</p>
<p>一部有着美学价值的作品，是无法被所谓的封禁所禁止的。它可能会因为禁令在一段时期内销声匿迹。但总会有人在未来的某一天再次感受到这部作品的美。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li>
<p><a href="https://twitter.com/txyyss/status/1435502246607802368?s=20"  target="_blank" rel="noopener" >Shengyi Wang on X</a></p>
<p>我是看了这条推文才得知《秦妇吟》的。</p>
</li>
<li>
<p><a href="https://weibo.com/ttarticle/p/show?id=2309404095652505196850"  target="_blank" rel="noopener" >复出于藏经洞的唐代第一长诗——《秦妇吟》</a></p>
<p>这篇中有《秦妇吟》全图。</p>
</li>
<li>
<p><a href="https://anlizhi.blog.caixin.com/archives/162309"  target="_blank" rel="noopener" >载沉载浮《秦妇吟》-安立志的财新博客-财新网</a></p>
<p>这篇是我目前看到讲《秦妇吟》及其背后历史最详细且最好的一篇。</p>
</li>
<li>
<p><a href="https://chinaheritage.net/annual/2017/in-history/tang/the-lament-of-the-lady-of-qin/"  target="_blank" rel="noopener" >The Lament of the Lady of Qin – China Heritage</a></p>
<p>英译版，我还没有细读。</p>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Long May the Free Software</title>
      <link>https://ds63.eu.org/2023/long-may-the-free-software/</link>
      <pubDate>Thu, 14 Dec 2023 17:10:10 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/long-may-the-free-software/</guid>
      <description>A course report for computer and social</description>
      <content:encoded><![CDATA[<p><strong>This is a course report for one of my university courses: Computers and Society.</strong></p>
<p><strong>I made this report with the help of ChatGPT</strong></p>
<p>Good morning, ladies and gentlemen. Today, I am delighted to share with you a topic that lies at the heart of digital freedom and innovation – &ldquo;Long May the Free Software.&rdquo;</p>
<p><strong>Chapter1: What</strong></p>
<h3 id="what-is-free-software">What is Free Software</h3>
<p>Let&rsquo;s start by understanding what we mean by &ldquo;Free Software.&rdquo; When we talk about free software, we&rsquo;re not referring to the price; instead, we&rsquo;re talking about freedom.</p>
<p>In another word, “free software” is a matter of liberty, not price. To understand the concept, you should think of “free” as in “free speech,” not as in “free beer.”</p>
<hr>
<h3 id="the-four-essential-freedoms">The four essential freedoms:</h3>
<p>The Free Software Foundation defines freedom in terms of four essential user freedoms: the freedom to run, study, share, and modify the software.</p>
<ul>
<li>The freedom to run the program as you wish, for any purpose.</li>
<li>The freedom to study how the program works, and change it so it does your computing as you wish. Access to the source code is a precondition for this.</li>
<li>The freedom to redistribute copies so you can help others .</li>
<li>The freedom to distribute copies of your modified versions to others. By doing this you can give the whole community a chance to benefit from your changes.</li>
</ul>
<p>A program is free software if it gives users adequately all of these freedoms. Otherwise, it is nonfree. While we can distinguish various nonfree distribution schemes in terms of how far they fall short of being free, we consider them all equally unethical.</p>
<hr>
<h3 id="a-more-precise-clarification">A more precise clarification</h3>
<p>In the rest of this article we explain more precisely how far the various freedoms need to extend, on various issues, in order for a program to be free.</p>
<hr>
<h3 id="the-freedom-to-run-the-program-as-you-wish">The freedom to run the program as you wish</h3>
<p>In this freedom, it is the user&rsquo;s purpose that matters, not the developer&rsquo;s purpose; you as a user are free to run the program for your purposes, and if you distribute it to other people, they are then free to run it for their purposes, but you are not entitled to impose your purposes on them.</p>
<p>The freedom to run the program as you wish means that you are not forbidden or stopped from making it run. This has nothing to do with what functionality the program has, whether it is technically capable of functioning in any given environment, or whether it is useful for any particular computing activity.</p>
<hr>
<h3 id="the-freedom-to-study-the-source-code-and-make-changes">The freedom to study the source code and make changes</h3>
<p>Accessibility of source code is a necessary condition for free software. Obfuscated “source code” is not real source code and does not count as source code.</p>
<p>Source code is defined as the preferred form of the program for making changes in. Thus, whatever form a developer changes to develop the program is the source code of that developer&rsquo;s version.</p>
<hr>
<h3 id="the-freedom-to-redistribute-if-you-wish">The freedom to redistribute if you wish</h3>
<p>Freedom to distribute means you are free to redistribute copies, either with or without modifications, either gratis or charging a fee for distribution, to anyone anywhere. Being free to do these things means (among other things) that you do not have to ask or pay for permission to do so.</p>
<p>You should also have the freedom to make modifications and use them privately in your own work or play, without even mentioning that they exist. If you do publish your changes, you should not be required to notify anyone in particular, or in any particular way.</p>
<hr>
<p><strong>Chapter2 Why</strong></p>
<p>Now that we have a foundational understanding of what free software entails, let&rsquo;s take a journey into its historical roots. The concept of free software dates back to the early days of computing, but it gained significant momentum in the 1980s.</p>
<h3 id="introduction-to-the-history-of-free-software">Introduction to the History of Free Software:</h3>
<ol>
<li>The Birth of the Free Software Movement:</li>
</ol>
<p>In the early 1980s, a visionary computer scientist named Richard Stallman initiated the Free Software Foundation and launched the GNU (GNU&rsquo;s Not Unix) project. Stallman&rsquo;s motivation was to create a free and open-source Unix-like operating system. This marked the beginning of the formal free software movement.</p>
<ol start="2">
<li>The GNU General Public License (GPL):</li>
</ol>
<p>A pivotal development during this time was the creation of the GNU General Public License, or GPL. The GPL is a license that ensures software remains free and open, allowing users to access and modify the source code. It became a cornerstone in the free software ecosystem.</p>
<ol start="3">
<li>Challenges Faced by the Free Software Movement:</li>
</ol>
<p>As the movement grew, it faced challenges from proprietary software and closed ecosystems. Corporations sought to restrict user freedoms by limiting access to source code and imposing restrictive licenses.</p>
<ol start="4">
<li>Rise of Linux and Open Source:</li>
</ol>
<p>In the early 1990s, Linus Torvalds created the Linux kernel, combining it with the GNU software to form a complete, free operating system. The collaboration between the Free Software Foundation and the open-source community gave rise to a powerful and adaptable alternative to proprietary systems.</p>
<hr>
<h3 id="why-do-we-need-free-software">Why Do We Need Free Software?</h3>
<h3 id="my-personal-experience">My personal experience</h3>
<p>Allow me to share a personal journey that underscores the importance of embracing free software in our daily lives. In the past, I relied on platforms like Douban to manage my book, movie, and music records. Similarly, I used application &ldquo;X&rdquo; for social networking. However, I found myself at the mercy of closed systems that not only lacked transparency but also held my data hostage.</p>
<h3 id="my-personal-experienceneodb">My personal experience：Neodb</h3>
<p>In my quest for digital autonomy, I made a conscious shift to NeoDB for managing my book, movie, and music records. NeoDB is an open-source alternative that not only respects my data privacy but also allows me to control and manipulate my information as I see fit. This transition has empowered me to truly own my data, a freedom often compromised by closed platforms.</p>
<h3 id="my-personal-experiencemastodon">My personal experience：Mastodon</h3>
<p>The same principle applies to my social networking habits. I moved away from the closed and often data-exploitative platform &ldquo;X&rdquo; and embraced Mastodon. Mastodon, being an open-source and decentralized social network, provides a space where my data isn&rsquo;t commodified, and I have the freedom to choose where and how I interact with the platform.</p>
<p>The common thread in these transitions is a desire for data ownership and openness. Closed platforms often use proprietary algorithms, limiting users&rsquo; control over their own information. The decision to shift to open-source alternatives like NeoDB and Mastodon reflects not just a change in software but a commitment to reclaiming control over my digital presence.</p>
<hr>
<h3 id="my-personal-experience-agpl-30-license">My personal experience： AGPL-3.0 license</h3>
<p>Both NeoDB and Mastodon is using AGPL-3.0 license. So I want to talk about a bit more about it.</p>
<ol>
<li>
<p><strong>Copyleft Philosophy</strong>: AGPL-3.0 is a copyleft license, which means it ensures that any modified versions of the software must also be distributed under the same terms. This provision is designed to prevent the software, or any derived works, from being made proprietary.</p>
</li>
<li>
<p><strong>Source Code Accessibility</strong>: Similar to the GNU General Public License (GPL), AGPL-3.0 requires that users who interact with the software over a network are provided access to the corresponding source code. This ensures transparency and upholds the principles of open-source development.</p>
</li>
<li>
<p><strong>Network Interaction Provision</strong>: A notable feature of AGPL-3.0 is the &ldquo;Affero clause.&rdquo; It specifically addresses the distribution of modified versions of the software over a network. If the software is used to provide services over a network and modifications are made to the source code, those modifications must be made available to users interacting with the service.</p>
</li>
</ol>
<hr>
<h3 id="the-four-reasons">The four reasons:</h3>
<ol>
<li>Protection of User Rights:</li>
</ol>
<p>One of the fundamental reasons we need free software is to protect user rights. In a world dominated by proprietary software, users often surrender control of their digital lives. Free software ensures that users have the right to control and customize their computing experiences.</p>
<ol start="2">
<li>Promoting Innovation and Competition:</li>
</ol>
<p>Free software fosters innovation and healthy competition. When source code is open, developers can build upon existing projects, creating a cycle of continuous improvement. This openness minimizes monopolies, allowing for diverse solutions and ideas to flourish.</p>
<ol start="3">
<li>Preserving Academic Freedom and Sharing Knowledge:</li>
</ol>
<p>Within academic circles, the importance of free software cannot be overstated. It preserves academic freedom by allowing researchers and educators to share knowledge openly. The collaborative nature of free software aligns with the principles of academic inquiry and learning.</p>
<ol start="4">
<li>Ensuring Data Privacy and Transparency:</li>
</ol>
<p>In an era where data privacy is paramount, free software offers transparency. Users can scrutinize the code, ensuring that their personal data is handled ethically and securely. This transparency builds trust between users and software developers.</p>
<hr>
<p><strong>Chapter 3: How</strong></p>
<p>Having explored the essence and significance of free software, let‘s delve into the practical aspect of how.</p>
<ol>
<li><strong>Use Free Software</strong>:</li>
</ol>
<p>The simplest and most immediate way to support free software is to incorporate it into our daily digital lives. Choose free and open-source alternatives for your operating system, office suite, and other software needs. By doing so, you not only experience the benefits of freedom but also contribute to the growing user base of free software.</p>
<ol start="2">
<li><strong>Advocate for Free Software</strong>:</li>
</ol>
<p>Spread the word about the importance of free software within your social circles, workplace, and online communities. Advocate for the adoption of free software solutions and educate others on the value of digital freedom. Engage in discussions about the benefits of open-source software and dispel misconceptions that may exist.</p>
<ol start="3">
<li><strong>Contribute Code and Feedback</strong></li>
</ol>
<p>For those with technical skills, contributing code to free software projects is a powerful way to make a direct impact. Whether it&rsquo;s fixing bugs, adding new features, or improving documentation, your contributions can enhance the functionality and resilience of free software. Additionally, providing constructive feedback on existing projects helps maintain quality standards.</p>
<ol start="4">
<li><strong>Respect and Uphold Licensing</strong></li>
</ol>
<p>When using or contributing to free software, respect and uphold the licensing agreements. Understand the terms of licenses such as the GNU General Public License (GPL) and ensure compliance. Respecting licensing is fundamental to maintaining the principles of free software.</p>
<hr>
<h3 id="beyond-software">Beyond Software</h3>
<p>Software manuals must be free, for the same reasons that software must be free, and because the manuals are in effect part of the software.</p>
<p>The same arguments also make sense for other kinds of works of practical use—that is to say, works that embody useful knowledge, such as educational works and reference works. Wikipedia is the best-known example.</p>
<p>Any kind of work can be free, and the definition of free software has been extended to a definition of free cultural works applicable to any kind of works.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://www.gnu.org/gnu/gnu.en.html"  target="_blank" rel="noopener" >About the GNU Operating System - GNU project - Free Software Foundation</a></li>
<li><a href="https://www.gnu.org/philosophy/free-sw.en.html"  target="_blank" rel="noopener" >What is Free Software? - GNU Project - Free Software Foundation</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Linux内核编译</title>
      <link>https://ds63.eu.org/2023/compile-the-linux-kernel/</link>
      <pubDate>Thu, 14 Dec 2023 17:07:22 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/compile-the-linux-kernel/</guid>
      <description>记一次操作系统实验</description>
      <content:encoded><![CDATA[<h2 id="步骤">步骤</h2>
<ol>
<li>在<a href="https://www.kernel.org/"  target="_blank" rel="noopener" >The Linux Kernel Archives</a>下载所需的内核代码</li>
<li>解压缩 <code>tar xvf linux-5.10.203.tar.xz</code> （以linux-5.10.203.tar.xz为例）</li>
<li><code>cd linux-5.10.203</code></li>
<li><code>cp -v /boot/config-$(uname -r) .config</code></li>
<li><code>make menuconfig</code> 进行配置</li>
<li><code>make -j$(nproc) 2&gt; error.log</code>  并发编译,并记录错误信息</li>
<li><code>make modules</code></li>
<li><code>make modules_install</code></li>
<li><code>make install</code></li>
<li><code>reboot</code></li>
<li>在GRUB菜单选择编译好的内核</li>
<li>可使用<code>uname -r</code> 查看内核版本，进行验证</li>
</ol>
<hr>
<h2 id="脚本">脚本</h2>
<p>我编写了一个脚本，用于自动化内核编译</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Makefile" data-lang="Makefile"><span class="line"><span class="cl"><span class="c">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="c"></span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置在出现错误或使用未定义的变量时立即退出
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="err">set</span> <span class="err">-e</span>
</span></span><span class="line"><span class="cl"><span class="err">set</span> <span class="err">-u</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 获取当前时间戳
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="nv">timestamp</span><span class="o">=</span><span class="k">$(</span>date +<span class="s2">&#34;%Y%m%d%H%M%S&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 配置内核
</span></span></span><span class="line"><span class="cl"><span class="c"># make menuconfig
</span></span></span><span class="line"><span class="cl"><span class="c"></span>
</span></span><span class="line"><span class="cl"><span class="c"># 创建日志文件，带有时间戳
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="nv">log_file</span><span class="o">=</span><span class="s2">&#34;compile_log_</span><span class="si">${</span><span class="nv">timestamp</span><span class="si">}</span><span class="s2">.txt&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">touch</span> <span class="s2">&#34;$log_file&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 编译内核，将标准错误输出记录到日志文件并显示在终端
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="err">make</span> <span class="err">-j</span><span class="k">$(</span><span class="nv">nproc</span><span class="k">)</span> <span class="nv">INCREMENTAL</span><span class="o">=</span><span class="m">1</span> 2&gt; &gt;<span class="o">(</span>tee -a <span class="s2">&#34;</span><span class="nv">$log_file</span><span class="s2">&#34;</span> &gt;<span class="p">&amp;</span>2<span class="o">)</span> <span class="o">||</span> <span class="o">{</span> <span class="nb">echo</span> <span class="s2">&#34;Make failed&#34;</span><span class="p">;</span> <span class="nb">exit</span> 1<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 编译内核模块
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="err">make</span> <span class="err">modules</span> <span class="err">2&gt;</span> <span class="err">&gt;(tee</span> <span class="err">-a</span> <span class="s2">&#34;$log_file&#34;</span> <span class="err">&gt;&amp;2)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 安装内核模块
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="err">make</span> <span class="err">modules_install</span> <span class="err">2&gt;</span> <span class="err">&gt;(tee</span> <span class="err">-a</span> <span class="s2">&#34;$log_file&#34;</span> <span class="err">&gt;&amp;2)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 安装内核
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="err">make</span> <span class="err">install</span> <span class="err">2&gt;</span> <span class="err">&gt;(tee</span> <span class="err">-a</span> <span class="s2">&#34;$log_file&#34;</span> <span class="err">&gt;&amp;2)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 更新 GRUB 配置（如果使用 GRUB 引导）
</span></span></span><span class="line"><span class="cl"><span class="c"># update-grub 2&gt; &gt;(tee -a &#34;$log_file&#34; &gt;&amp;2)
</span></span></span></code></pre></div><hr>
<h2 id="添加新的系统调用">添加新的系统调用</h2>
<h3 id="hello">hello</h3>
<p><strong>方法一：</strong></p>
<ol>
<li>编辑arch/x86/entry/syscalls/syscall_64.tbl,添加
<code>441     64      hello                   sys_hello</code></li>
<li>在include/linux/syscalls.h中添加函数声明
<pre tabindex="0"><code>/* test */
asmlinkage long sys_hello(void);
</code></pre></li>
<li>在kernel/sys.c中末尾添加如下代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* test */</span>
</span></span><span class="line"><span class="cl"><span class="nf">SYSCALL_DEFINE0</span><span class="p">(</span><span class="n">hello</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printk</span><span class="p">(</span><span class="s">&#34;hello,world! </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p><strong>方法二：</strong></p>
<p>摘自<a href="https://dev.to/omergulen/how-to-add-system-call-syscall-to-the-kernel-compile-and-test-it-3e6p"  target="_blank" rel="noopener" >How to add system call (syscall) to the kernel, compile and test it? - DEV Community</a></p>
<ol>
<li>在<code>/usr/src/linux-5.15.142</code>建立新文件夹(以linux-5.15.142为例)
<code>mkdir hello &amp;&amp; cd hello</code></li>
<li><code>vim hello.c</code></li>
</ol>
<pre tabindex="0"><code>#include &lt;linux/kernel.h&gt;

asmlinkage long sys_hello(void) 
{
        //printk prints to the kernel’s log file.
        printk(&#34;Hello world\n&#34;);
        return 0;
}
</code></pre><ol start="3">
<li><code>vim Makefile</code></li>
</ol>
<pre tabindex="0"><code>obj-y := hello.o
</code></pre><ol start="4">
<li>go to the parent directory (kernel source main directory)</li>
<li>add our new syscall directory to Makefile,search for core-y,and add hello/ to the end of this line.</li>
<li>同方法一第一步</li>
<li>同方法一第二步</li>
</ol>
<h3 id="hide">hide</h3>
<ol>
<li>编辑include/linux/sched.h 文件，在task_struct新增</li>
</ol>
<pre tabindex="0"><code>        /* wyd: store the old pidS */
        pid_t old_pid;

        /* wyd: 0:hide */
        int hide;
</code></pre><ol start="2">
<li>修改kernel/fork.c中的copy_process函数</li>
</ol>
<pre tabindex="0"><code>        /* wyd: init the append values */
        p-&gt;hide =0;
        p-&gt;old_pid = p-&gt;pid;
</code></pre><ol start="3">
<li>编辑arch/x86/entry/syscalls/syscall_64.tbl,添加
<code>442     common  hide                    sys_hide</code></li>
<li>在include/linux/syscalls.h中添加函数声明</li>
</ol>
<pre tabindex="0"><code>asmlinkage int sys_hide(pid_t pid,int on);
</code></pre><ol start="5">
<li>在kernel/sys.c中末尾添加如下代码</li>
</ol>
<p><strong>此代码有问题，仅作为示例</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">SYSCALL_DEFINE2</span><span class="p">(</span><span class="n">hide</span><span class="p">,</span><span class="kt">pid_t</span><span class="p">,</span><span class="n">pid</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span><span class="n">on</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">me</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">init_task</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">old_pid</span> <span class="o">==</span> <span class="n">pid</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="n">me</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span><span class="k">while</span><span class="p">((</span><span class="n">p</span> <span class="o">=</span> <span class="nf">next_task</span><span class="p">(</span><span class="n">p</span><span class="p">))</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">p</span><span class="o">!=</span> <span class="o">&amp;</span><span class="n">init_task</span><span class="p">))</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="n">current</span><span class="o">-&gt;</span><span class="n">uid</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">me</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">on</span> <span class="o">==</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">me</span><span class="o">-&gt;</span><span class="n">pid</span> <span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">me</span><span class="o">-&gt;</span><span class="n">hide</span> <span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span><span class="p">(</span><span class="n">me</span><span class="o">-&gt;</span><span class="n">hide</span> <span class="o">==</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="n">me</span><span class="o">-&gt;</span><span class="n">pid</span> <span class="o">=</span> <span class="n">me</span><span class="o">-&gt;</span><span class="n">old_pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                        <span class="n">me</span><span class="o">-&gt;</span><span class="n">hide</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol>
<li>修改fs/proc/base.c中proc_pid_lookup的代码，添加</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">task</span><span class="o">-&gt;</span><span class="n">hide</span><span class="o">==</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
</span></span></code></pre></div><hr>
<h2 id="grub">GRUB</h2>
<h3 id="默认启动的内核">默认启动的内核</h3>
<ol>
<li>打开 GRUB 配置文件：
<code>sudo vim /etc/default/grub</code></li>
<li>找到 GRUB_DEFAULT 行，并更改其值为你想要设置的默认内核的索引,保存并关闭。如
<code>GRUB_DEFAULT=2</code></li>
<li>更新 GRUB 配置
<code>sudo update-grub</code></li>
</ol>
<hr>
<h2 id="报错及解决">报错及解决</h2>
<h3 id="缺少xxx工具">缺少xxx工具</h3>
<p>可以在编译之前先安装编译所需要的所有工具
<code>sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison</code></p>
<h3 id="no-rule-to-make-target-debiancertsdebian-uefi-certspem">No rule to make target &lsquo;debian/certs/debian-uefi-certs.pem</h3>
<p>我参考了<a href="https://stackoverflow.com/questions/67670169/compiling-kernel-gives-error-no-rule-to-make-target-debian-certs-debian-uefi-ce"  target="_blank" rel="noopener" >Stack Overflow上的回答</a>，执行以下两条命令</p>
<pre tabindex="0"><code>sudo scripts/config --disable SYSTEM_TRUSTED_KEYS
sudo scripts/config --disable SYSTEM_REVOCATION_KEYS
</code></pre><h3 id="sed-cant-read-modulesorder-no-such-file-or-directory">sed: can&rsquo;t read modules.order: No such file or directory</h3>
<p>参考<a href="https://forums.gentoo.org/viewtopic-p-8686340.html?sid=5a87359186073a04049d6fc85eb51c32"  target="_blank" rel="noopener" >Gentoo Forums :: 阅读主题 - sed: can&rsquo;t read modules.order: No such file or directory</a></p>
<p>发现原来是刚才的<code>make -j$(nproc)</code>指令并没有执行成功。</p>
<h3 id="no-space-left-to-place">No space left to place</h3>
<p>我的选择是重装虚拟机，在设置的时候加大硬盘</p>
<p>看到两篇似乎可行的操作</p>
<ul>
<li><a href="https://blog.csdn.net/m0_61549260/article/details/129751313"  target="_blank" rel="noopener" >编译内核时，磁盘爆满的问题-CSDN博客</a></li>
</ul>
<h3 id="btf-tmp_vmlinuxbtf-pahole-pahole-is-not-available">BTF: .tmp_vmlinux.btf: pahole (pahole) is not available</h3>
<p>参考<a href="https://stackoverflow.com/questions/61657707/btf-tmp-vmlinux-btf-pahole-pahole-is-not-available"  target="_blank" rel="noopener" >compilation - BTF: .tmp_vmlinux.btf: pahole (pahole) is not available - Stack Overflow</a></p>
<p><code>sudo apt install dwarves</code></p>
<h3 id="warning-os-prober-will-not-be-executed-to-detect-other-bootable-partitions">Warning: os-prober will not be executed to detect other bootable partitions.</h3>
<ul>
<li>具体描述：
<code>make install</code>最后得到，
<pre tabindex="0"><code>Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
done
</code></pre>看网上的教程，这时候直接重启就可以进到GRUB菜单，但我没有。原因应该是以上导致的。</li>
<li>解决：
我的解决方法是在电脑开机的时候(出现操作系统的开机画面之前)，按F4键进入GRUB菜单</li>
</ul>
<h3 id="vmware开启了共享文件夹却不显示">VMware开启了共享文件夹却不显示</h3>
<p>在/mnt 文件夹下执行
<code>vmhgfs-fuse /mnt/hgfs</code></p>
<hr>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://blog.csdn.net/lingshengxueyuan/article/details/117597019"  target="_blank" rel="noopener" >Linux内核编译很简单，6步编译一个自己的内核_0基础编译内核教程-CSDN博客</a></li>
<li><a href="https://stackoverflow.com/questions/67670169/compiling-kernel-gives-error-no-rule-to-make-target-debian-certs-debian-uefi-ce"  target="_blank" rel="noopener" >linux - Compiling kernel gives error No rule to make target &lsquo;debian/certs/debian-uefi-certs.pem&rsquo; - Stack Overflow</a></li>
<li><a href="https://forums.gentoo.org/viewtopic-p-8686340.html?sid=5a87359186073a04049d6fc85eb51c32"  target="_blank" rel="noopener" >Gentoo Forums :: 阅读主题 - sed: can&rsquo;t read modules.order: No such file or directory</a></li>
<li><a href="https://blog.csdn.net/weixin_51480590/article/details/127776698"  target="_blank" rel="noopener" >Linux内核编译_linux内核编译后多大-CSDN博客</a></li>
<li><a href="https://blog.csdn.net/weixin_51480590/article/details/127767660"  target="_blank" rel="noopener" >Ubuntu磁盘扩充_ubuntu扩展磁盘空间-CSDN博客</a></li>
<li><a href="https://unix.stackexchange.com/questions/534596/hiding-processes-on-unix-linux"  target="_blank" rel="noopener" >process - Hiding processes on Unix/Linux - Unix &amp; Linux Stack Exchange</a></li>
<li><a href="https://nickdesaulniers.github.io/blog/2018/06/02/speeding-up-linux-kernel-builds-with-ccache/"  target="_blank" rel="noopener" >Speeding Up Linux Kernel Builds With ccache</a></li>
<li><a href="https://dev.to/omergulen/how-to-add-system-call-syscall-to-the-kernel-compile-and-test-it-3e6p"  target="_blank" rel="noopener" >How to add system call (syscall) to the kernel, compile and test it? - DEV Community</a></li>
<li><a href="https://www.kernel.org/doc/html/v4.10/process/adding-syscalls.html"  target="_blank" rel="noopener" >Adding a New System Call — The Linux Kernel documentation</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>语言洁癖</title>
      <link>https://ds63.eu.org/2023/blacklist-of-words/</link>
      <pubDate>Wed, 06 Dec 2023 22:26:19 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/blacklist-of-words/</guid>
      <description>以下的所有内容带有极强的个人主观看法，也仅仅是我个人在某一特定时段的观点。</description>
      <content:encoded><![CDATA[<p>有些词，出于各种原因，我尽量避免自己使用。这里记录下，不知道几年后自己再看看会怎么认为。</p>
<p>需要提前说明的一点是。以下的所有内容带有极强的个人主观看法，也仅仅是我个人在某一特定时段的观点。</p>
<h2 id="卷">卷</h2>
<ul>
<li>开始时间：2020年</li>
</ul>
<h3 id="原因">原因：</h3>
<p>我认为被滥用了。看到别人在学习，就说别人在卷。我觉得并不好。</p>
<hr>
<h2 id="mbti及其延申">MBTI及其延申</h2>
<ul>
<li>开始时间: 2023年</li>
</ul>
<h3 id="现象">现象：</h3>
<p>MBTI作为一项心理测试其实很有年头了。但今年不知怎么的，又掀起一波热潮。不少人都喜欢自称e人之类的。</p>
<h3 id="原因-1">原因：</h3>
<p>我对MBTI这项测试没有任何恶意，自己也在心理课上做过相关的测试。但对于结果已经毫无印象。</p>
<p>不过我对所谓e人的表述蛮有成见的。</p>
<p>我认为人是多变而复杂的，随着所处空间和时间的不同，人也会有不同的表现。所以我不认为简单的四个字母就能完全的描述一个人。更不愿意自己被其所定义。</p>
<p>不过在写到这里的时候，我突然想到自称e人等行为可以类比为自称是某国某省人，可以单纯地理解为是自我介绍的一部分。这倒就无可厚非。</p>
<p>但我还是会尽量避免使用，因为我认这些心理评测的结果或多或少都会受到<a href="https://en.wikipedia.org/wiki/Barnum_effect"  target="_blank" rel="noopener" >Barnum effect</a>的影响。</p>
<hr>
<h2 id="因为审查而使用的谐音或缩写替代">因为审查而使用的谐音或缩写替代</h2>
<ul>
<li>开始时间：2022年</li>
</ul>
<h3 id="现象-1">现象：</h3>
<p>我使用的一些国内平台，因为各种原因将一些词列为了敏感词。随着时间的推移，这个词库越来越大。而不管怎么审查，人们总会有需要使用到这些词的时候，于是就使用谐音、缩写来规避审查。包括但不限于:</p>
<ul>
<li>死 -&gt; s</li>
<li>大便 -&gt; 答辩 (这个可能不是敏感词，而是因为大便这个词看着不雅？)</li>
<li>傻逼 -&gt; 伞兵 (这个很少见了，说来也讽刺。最初人们用伞兵代替傻逼是因为傻逼被列为敏感词；而当伞兵作为傻逼的替代词被越来越多地使用后，开始认为这是对伞兵这一兵种的侮辱，使得傻逼这个词从敏感词中解放出来)</li>
</ul>
<h3 id="原因-2">原因:</h3>
<p>分情况考虑。</p>
<p>谐音词只要有趣，我还蛮喜欢的。但有趣的标准，就因人而异了。所以我干脆一棒子打死，尽量避免自己使用谐音字。</p>
<p>使用拼音缩写来规避敏感词，我很厌恶这种做法。但现在也说不清是为什么。</p>
<p>事实上，对于平台审查，我的做法是：如果我所要表达的内容在该平台有被吞的可能，那我就不在该平台表达相关内容。这样反倒遂了审查者的愿，但我确实是这样做的。这样做对不对，好不好，我不知道。</p>
<p>微博前审查员刘力朋在<a href="https://www.youtube.com/watch?v=aKF0AnAxnKA&amp;t=10s&amp;ab_channel=%E7%BE%8E%E5%9B%BD%E4%B9%8B%E9%9F%B3%E4%B8%AD%E6%96%87%E7%BD%91"  target="_blank" rel="noopener" >我曾替共产党&quot;真理部&quot;做&quot;脏活儿&quot; - YouTube</a>提到了这样的观点，我挺认可的：</p>
<blockquote>
<p>他们想要达到的效果是让你自我审查，是让你困惑，所以要是想反其道而行之，不是要去想怎么绕过关键词，而是说不要害怕他们，拒绝自我审查。</p>
</blockquote>
<hr>
<h2 id="xx不香吗">xx不香吗</h2>
<ul>
<li>开始时间：2023年</li>
</ul>
<h3 id="现象-2">现象:</h3>
<p>常见于如下情景：一人在推荐某样产品，下面一个人回复：xxx不香吗?（xxx为另一款同类产品）</p>
<h3 id="原因-3">原因：</h3>
<p>可能是我抱有偏见，我一般会觉得这带着一种傲慢的味道，嘲讽别人做出了较差的选择。</p>
<p>但不排除也是抱着好心去推荐另一款产品或方式。</p>
<p>但就我个人而言，我会尽量避免使用这样的语言来表达。</p>
<hr>
<h2 id="脑瘫">脑瘫</h2>
<ul>
<li>开始时间：2024年</li>
</ul>
<h3 id="现象-3">现象</h3>
<p>不知从何时开始，网络上就有骂操作有问题的人为脑瘫。追溯其原因，可能最开始是骂逆天。然后缩写为nt，进而被打成脑瘫。</p>
<h3 id="原因-4">原因</h3>
<p>脑瘫作为一种疾病，对患者及其家人是极为不便与不幸。这是我之前的一个模糊的印象。</p>
<p>但在看了<a href="https://blogatlarge.com/wx/"  target="_blank" rel="noopener" >中二病未痊愈</a>这个博客和相关的搜索后，我才发现，有相当一部分的脑瘫患者除了行动不便之外，与正常人无任何不同，甚至在某些方面还会更加有天赋。</p>
<p>写这里的时候我又发现自己的表达有问题。我刚才有意无意地，就将脑瘫患者与所谓的正常人做了切分，这在某种程度上，也是种歧视。但实际上，幸于网络的存在，身体的不便完全可以被抹除。像刚才提到的这位博主，如果不是她自己写出来，我是不会想到她是位脑瘫患者的。</p>
<p>不管怎么说，将疾病作为一种攻击人的方式，这对那些患者及其家人是绝对不礼貌的，不管有意无意，都必须坚决抵制。</p>
<hr>
<h2 id="通话膨胀">通话膨胀</h2>
<ul>
<li>开始时间: 2024年</li>
</ul>
<h3 id="现象-4">现象</h3>
<p>我之前都对所谓的“宝宝”，“家人们”等词感到反感，原因是本来也不是家人啊，明明只是话都没讲过几句的陌生人。但只是隐约有个感觉。</p>
<p>今天看到<a href="https://mp.weixin.qq.com/s?__biz=MzAxMzExMTAwMw==&amp;mid=2655390764&amp;idx=1&amp;sn=dda3f86182c23787b9bf20b2389caa7c&amp;chksm=81e9c692217b7febc103d784d08a94decd40215e4959346421ae665c5506b00fdfd75091c16f%5c"  target="_blank" rel="noopener" >欢迎来到通话膨胀3.0时代！</a>，觉得说得很好。摘录下:</p>
<ul>
<li>
<p>通话膨胀1.0版本: <strong>文字讨好症：字词叠加与称呼语泛化</strong></p>
<p>这一时期，为在聊天时塑造一种欢快积极的形象，人们会使用一些亲昵的词语，（如“宝宝”，“家人们”等），并将字词进行有意识重复，包括但不限于语气词（如“哈”，“滴”等）、动词（如；“好好好”,“买买买”）和标点符号等。这一定程度上拉近了人们的社交距离，但也不可气避免地带来了礻十压力，并增加了社交成本。</p>
</li>
<li>
<p>通话膨胀2.0版本: <strong>梗文化泛滥与同质化表达</strong></p>
<p>随互联网兴起，一开始作为圈子文化里笑点的“梗”，逐渐演变为一场大众的文化狂欢。“yyds”和“绝绝子”等词，强势挤占日常语境，“文字失语症”随之出现。与生理性病变引起的失语症不同，文字失语者所经历的“失语”，更像是一种社会病。语言越来越匮乏，难以运用修辞或成语，根本无法表达自身所想。“文字失语症”背后的核心问题在于同质化的表达磨平了事物间的差异，从而削弱了人们的感知能力。如沃尔夫假说所言“语言、文化和思维三者之间了有着密切的关系。”当语言单一之后，思维和感受也会变得单一。因为词语语法匮乏，不能好好表达出自己感受到的是什么，慢慢地，感官也会随之钝化。</p>
</li>
<li>
<p>通话膨胀3.0版本: <strong>文字滥用症：字词污名化与严肃议题娱乐化</strong></p>
<p>这一阶阶,网络流行梗趋向肤浅化和污名化，有时更将原本毫不相关的词联系到一起：扭扭捏捏、畏畏缩缩的样子，则是“偷感很重”;亲密关系议题里， &ldquo;CPU ”和 &ldquo;KTV ”被用来削弱“PUA”背后的严肃性&hellip;&hellip; 大量可能带有不良指向的词语被滥用成灾，生活用语带上了污名与负面，却还要冠以娱乐的帽子为其脱罪。“万柳书院”事件爆火之时，无数自我奴化的评论蜂拥而至看似调侃自嘲的背后，不仅是对优绩主义下既得利益者的“赋魅”，更是简单地将努力与成功画上等号，漠视结构性的压迫，否定边缘群体的意义。</p>
</li>
</ul>
<p>我自己最明显的感受是，牛逼和666这两个词我已经用得特别自然了，甚至是我都挺难想到要拿什么词去取代它们。这其实挺可悲的。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>关于贴吧的记忆</title>
      <link>https://ds63.eu.org/2023/tieba-memory/</link>
      <pubDate>Thu, 30 Nov 2023 00:46:18 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/tieba-memory/</guid>
      <description>国内的几个社交平台，百度贴吧是我用的最久，花的时间最多的。</description>
      <content:encoded><![CDATA[<p>国内的几个社交平台，百度贴吧是我用的最久，花的时间最多的。</p>
<p>其他的平台我都用的不多，也不太了解。所以这里只说百度贴吧。</p>
<h2 id="魅力">魅力</h2>
<p><strong>贴吧对我来说，有其独有的魅力。</strong></p>
<h3 id="魅力一-圈地自萌">魅力一: 圈地自萌</h3>
<p>百度贴吧的内容按“吧”分类。每一个“吧”都是专属特定主题的讨论空间，围绕着特定的主题去展开。一群本来素不相识的人因为相同的爱好聚在一起,这本身就是很棒的一件事。</p>
<p>虽然群聊或者其他论坛也能起着这样一种功能。但是贴吧里的人一般会比群里的人多，也更好查找。所以还是很难替代。</p>
<h3 id="魅力二-去中心">魅力二: 去中心</h3>
<p>贴吧提供的关注方式有三种: 关注吧，关注用户，收藏帖子。</p>
<p>有的平台以关注人为主，而贴吧是以关注吧为主。</p>
<p>这样的区别带来的差异是：</p>
<p>前者的流量会更多地被所谓的kol掌握，而后者则让每个人，只要你的帖子够吸引人，就能有一定的阅读和互动。</p>
<p>被人点赞，回复的感觉确实蛮好的。</p>
<p>(这一节的题目用“去中心”我感觉不太对，但没想到更合适的，暂且先用着)</p>
<h3 id="魅力三-连接">魅力三: 连接</h3>
<p>每个吧既保留了一定的独立性。但又有着一定的连接。</p>
<p>因着贴吧的推荐机制，我也常常会看到一些我觉得蛮有意思的吧。我相信没了贴吧，这些吧的成员总能找到替代方法，比如群聊或者单独的论坛。但我想这样的话，我可能一辈子都不会去了解到这些东西。</p>
<p>连接还有另一种有趣的体现方式。</p>
<p>在几年前，春节或者是特定的日子，几个关系比较近的贴吧会互相“拜吧”。其实说白了也就是以本吧的名义到对方吧里发个帖子，说些问候的话。似乎很简单，但现在想起来总有种莫名的触动。可以看作人际关系的一种延伸?</p>
<h2 id="缺点">缺点</h2>
<p><strong>当然，贴吧不是完美无缺的，这里列几点</strong></p>
<h3 id="缺点一广告">缺点一：广告</h3>
<p>贴吧的广告可以说是达到一种猖獗的地步。</p>
<p>它不仅自身有广告，这我能理解，毕竟不是做慈善。</p>
<p>用户也会发广告。而贴吧对此的打击力度，不如说是放弃。它通过放权给吧主，让吧主来处理。</p>
<p>有些吧的吧主比较活跃，广告就比较少。有些吧则没有那么幸运。</p>
<h3 id="缺点二-吞贴">缺点二: 吞贴</h3>
<p>经常能看到有人说自己的回复或帖子被吞了。</p>
<p>可能是因为年久失修，可能是因为内容审查</p>
<h2 id="尾巴">尾巴</h2>
<p>对我来说，能完全替代百度贴吧的社交平台，目前还没找到。</p>
<p>关于贴吧的记忆，也是很难遗忘的记忆。</p>
<p>但贴吧的未来，我并不太看好。</p>
<p>所以我自己糊了一个<a href="https://github.com/EuDs63/Tieba_Memory"  target="_blank" rel="noopener" >小工具</a>，希望尽可能地保留自己的数据，保留可能的记忆。</p>
<h2 id="尾巴的尾巴">尾巴的尾巴</h2>
<p>秋招面试百度，有幸走到终面。反问环节特地问了百度贴吧相关的问题。</p>
<ul>
<li>q: 在百度的众多产品中，我最喜欢，也用得最多的是百度贴吧。从14年小学接触一直用到现在。一开始主要用的是网页端，因为那时候的移动端看着还很简陋。但现在移动端更新迭代速度特别快，网页端仿佛就跟被抛弃了一样。有一天，我想发个贴，帖子里加点图片都好多报错。请问是为什么呢?</li>
<li>a: 商业考量，网页端的流量可能十不存一。百度在几年前错失了ugc的流量</li>
<li>q: 这个团队有多少人呢?</li>
<li>a: 少了很多，但也只相对的。之前可能和抖音相比，现在不行了。</li>
</ul>
<h2 id="他人的回忆">他人的回忆</h2>
<p>网上冲浪时也能看到别人怀念百度贴吧的文章，这里记录下:</p>
<ul>
<li><a href="http://zyho.me/index.php?action=blog&amp;tid=131"  target="_blank" rel="noopener" >贴吧，再见</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Vim常用命令</title>
      <link>https://ds63.eu.org/2023/vim_cheatsheet/</link>
      <pubDate>Wed, 29 Nov 2023 23:15:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/vim_cheatsheet/</guid>
      <description>a cheatsheet of vim commands</description>
      <content:encoded><![CDATA[<h2 id="vim">Vim</h2>
<h3 id="另存为">另存为</h3>
<ul>
<li><code>:saveas ~/some/path/</code>: save your file to that locationvim</li>
</ul>
<h3 id="查找">查找</h3>
<ul>
<li>光标停留在想要查找的单词的任意一个字母上面， 然后输入<code>Shift</code> + <code>*</code>  ，即可快速选中该单词，并且可以通过 n  或  N 进行上一个或下一个的匹配。</li>
</ul>
<h3 id="cmd模式">cmd模式</h3>
<ul>
<li><code>:!cmd </code> execute a shell command from within Vim
<ul>
<li><code>!gcc %</code> 编译</li>
<li><code>!xxd</code>  将当前文件转换为十六进制表示并显示在终端中</li>
<li><code>%!xxd</code> 将当前文件的内容通过管道传递给外部命令xxd，并将其输出替换为当前文件的内容</li>
</ul>
</li>
<li><code>:set nu</code> 显示行号</li>
<li><code>:set wrap</code></li>
<li><code>:%!grep execve</code></li>
<li><code>:%! grep -v ENOENT</code></li>
<li><code>:%s/term/another_term/g </code> 替换</li>
</ul>
<hr>
<h2 id="浏览器-vimium">浏览器 vimium</h2>
<ol>
<li>标记
<ul>
<li><code>m</code> + <code>m</code> 创建一个新的标记</li>
<li>```+<code>m</code> 跳转到标记的位置</li>
</ul>
</li>
<li><code>g</code>
<ul>
<li><code>g</code> + <code>u</code> 访问当前网址的上一层（目录的上一层）</li>
<li><code>g</code> + <code>U</code> 访问当前网址的首页</li>
</ul>
</li>
<li>标签页</li>
</ol>
<ul>
<li><code>x</code> 关闭标签页</li>
<li><code>X</code> 恢复最近关闭的标签页</li>
</ul>
<hr>
<h2 id="vscode插件vim">vscode插件Vim</h2>
<h3 id="注释">注释</h3>
<ul>
<li>g + c 单行注释</li>
<li>g + C 多行注释</li>
</ul>
<h3 id="宏使用">宏使用</h3>
<ol>
<li>在normal模式下输入qa(当然也可以输入qb, qc, etc，这里的a, b, c是指寄存器名称，vim会把录制好的宏放在这个寄存器中)</li>
<li>录制操作</li>
<li>normal模式下输入q，结束宏录制。</li>
</ol>
<h3 id="跳转">跳转</h3>
<ul>
<li><code>%</code> 跳转到与当前括号所匹配的位置</li>
<li><code>f&lt;</code>  Jump forward and land on the <code>&lt;</code> character</li>
<li><code>t&gt;</code>  Jump forward and land right before the <code>&lt;</code> character</li>
</ul>
<hr>
<h2 id="杂">杂</h2>
<h3 id="vim-life">Vim Life</h3>
<p>看<a href="https://normalmo.de/vimlife/#footnotereturn3"  target="_blank" rel="noopener" >Vim Life - Normal Mode</a>，作者使用macro，实现了一个生命游戏。</p>
<h3 id="esc的替代">esc的替代</h3>
<ul>
<li>默认的代替Esc键的组合键是CTRL C 或者 Ctrl+[</li>
</ul>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://github.com/mudi24/keyborad-man/tree/main/%E6%B5%8F%E8%A7%88%E5%99%A8"  target="_blank" rel="noopener" >mudi24/keyborad-man</a></li>
<li><a href="https://www.cnblogs.com/ini_always/archive/2011/09/21/2184446.html"  target="_blank" rel="noopener" >vim重复操作的宏录制 - ini_always - 博客园</a></li>
<li><a href="https://danielmiessler.com/p/vim/"  target="_blank" rel="noopener" >Learn Vim For the Last Time</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>村上春树作品集摘录</title>
      <link>https://ds63.eu.org/2023/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91%E4%BD%9C%E5%93%81%E9%9B%86%E6%91%98%E5%BD%95/</link>
      <pubDate>Sat, 18 Nov 2023 16:14:37 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91%E4%BD%9C%E5%93%81%E9%9B%86%E6%91%98%E5%BD%95/</guid>
      <description>人一个人生存是很不得了的事。</description>
      <content:encoded><![CDATA[<p>我便是如此存在着为数甚多的偏见，所以不很受人喜欢，因为不受喜欢，偏见也就越来越多。</p>
<hr>
<p>脾性这东西大约在二十五岁前便已成定局，此后无论怎样努力都无法改变其本质，问题是人们往往拘泥于外界对自身脾性的反应。</p>
<hr>
<p>我想，我的人生是零，是无，是彻底的无。迄今我做了什么？什么也没做。使谁幸福了？没使任何人幸福。拥有什么？什么也不拥有。我没有妻室，没有朋友，没有门，一扇也没有。阳物垂头丧气，甚至工作也朝不保夕。</p>
<hr>
<p>了价格低得惊人的拍卖品，众人依序近前，像敲打半旧车轮胎似的踢动我的睡眠。他们不该有如此权利。我并非半旧车，尽管半新不旧。</p>
<hr>
<p>“祖父说，学校无非是花十六年时间来消耗脑浆的地方。祖父也差不多没进校门。</p>
<hr>
<p>“至于哪一方善哪一方恶，祖父倒似乎不大在意。善与恶是人类根本素质上的属性，不能同所有权的归属趋向混为一谈。”</p>
<hr>
<p>种作业所带来的空虚却一发不可遏止。为了进步，人可以持续付出相应的努力，问题是无处可供我进步</p>
<hr>
<p>“再也无须前思后想，一切岂非已然过往。</p>
<hr>
<p>“我也同样，也觉得它是非常不健全的。”我说，“不过会留下痕迹，我们可以顺着痕迹一路返回，就像顺着雪地上的脚印行走。” “走去哪里？” “我自身。</p>
<hr>
<p>没有心哪里也走不到。” 我抬头看月。冬月不自量力地散发出鲜亮亮的光，悬挂在高墙包围下的镇子的上空。 “没有一样可以怪你。”我说。</p>
<hr>
<p>“不大明白。” “人上了年纪，无可挽回的事情的数量就越来越多。</p>
<hr>
<p>当然我不能责怪他们，他们仅仅不知道罢了。</p>
<hr>
<p>人们试图成就某件事情的时候，理所当然地要把握住以下三点：过去做出了哪些成绩？现在处境如何？将来要完成多少工作量？假如这三点被剥夺一空，剩下的便只有心惊胆战、自我怀疑和疲劳感。</p>
<hr>
<p>一九七一年越南战场仍在交火，当总统的是长着一副不吉利面孔的理查德·尼克松</p>
<hr>
<p>总的说来，我健康得如春天的熊。</p>
<hr>
<p>。我同社会的联系仅限于将所给的数据在头脑中揉搓转换成其他形式之时，其余时间只管一个人看过时的小说，用录像机看往日的好莱坞电影，喝啤酒喝威士忌打发时光。因此用不着看什么报纸杂志。</p>
<hr>
<p>小孩子总是习惯性地以为有一种神圣的力量最终会将自己从世间可能发生的几乎所有种类的灾难中解救出来，至少我在儿童时代是如此。</p>
<hr>
<p>当人陷入无以复加的困难境地时，往往在脑海中描绘出白日梦场面以保护自己免受严酷现实的摧残。但若称之为心血来潮式的意念性图像，那浮现于眼前的场景未免过于栩栩如生淋漓尽致，对我的存在本身未免过于息息相关</p>
<hr>
<p>。任何人都不具有剥夺我记忆的权利。那是我自身的记忆！剥夺他人的记忆无异于劫掠他人的岁月。</p>
<hr>
<p>出色的樵夫身上只有一处伤，不多不少，仅仅一处</p>
<hr>
<p>万无一失的暗号只有一个，那就是要用任何人都无法掌握的系统进行保密，也就是要通过万无一失的黑匣子来保存情报，又反过来把经过处理的东西通过同样的黑匣子加以保存。对黑匣子里的内容和原理，甚至本人都蒙在鼓里，可以使用，却不知其为何物。因为本人都不明白，所以他人便不可能凭借暴力窃取情报。如何，万无一失吧？” “你说的那黑匣子就是人的深层心理？” “是的，</p>
<hr>
<p>何谓Identity？就是每一个人由于过去积累的体验和记忆而造成的思维体系的主体性。简言之，称为心也未尝不可。</p>
<hr>
<p>我们头脑中埋藏着一个犹如人迹未至的巨象的墓场般的所在。</p>
<hr>
<p>“不不，象的墓场这一说法并不贴切。那里并非死去记忆的堆放场。准确说来，称为象厂倒也许接近。因为无数记忆和认识的断片在那里筛选，筛选出的断片在那里被错综复杂地组合起来制成线，又将线错综复杂地组合为线束，由线束构成体系。这正是一家‘工厂’，从事生产的工厂</p>
<hr>
<p>说谎是非常令人讨厌的勾当。不妨说，说谎与沉默是现代人类社会中流行的两大罪过。我们实际上经常说谎，也往往沉默不语。 然而，倘若我们一年四季都喋喋不休，而且喋喋不休的无不真实，那么真实的价值势必荡然无存。</p>
<hr>
<p>“让实验对象看某种物体，分析由视觉产生的脑电反应，再转换为数字，进而转换成点。起始浮现的图形极为粗糙，经过反复修整和具体补充，才将实验对象所目睹的图像显现在电脑屏幕上</p>
<hr>
<p>我是讨厌世上存在的大多数东西，对方想必也讨厌我，但其中也有我中意的，而且中意的就非常中意，这和对方中意不中意我没有关系。我就是这样生存于世的。我哪里也不想去，也不需要死。年纪的增长固然有时令人伤感，但这不光我一个人，任何人年纪都同样越来越大</p>
<hr>
<p>思维是没有时间的。这也是思维同梦的区别所在。思维这东西一瞬间可以洞察一切，可以体验永恒，可以闭合电路永远在其中绕行不止，这才成其为思维，而不至于像梦一样中断。它类似百科事典棒。”</p>
<hr>
<p>。肉体之死就是飞箭，朝着你的脑笔直飞去，任何人都无法回避。人迟早会死亡，肉体必然毁灭。时间把箭推向前去。</p>
<hr>
<p>人并非通过扩延时间达到不死，而是通过分解时间获得永生。”</p>
<hr>
<p>只这么看着就觉心旷神怡，用法慢慢自己会摸索出来的，最富有的就是时间嘛。”</p>
<hr>
<p>世上有数不胜数林林总总的宗教和神话，但围绕人死所想到的基本千篇一律。</p>
<hr>
<p>“怎么都无所谓？” “既不是了不起的人生，又不是了不起的大脑。” “可你刚才还说对自己的人生感到满足呀！” “玩弄词句而已。”我说，“任何军队都要有一面战旗。”</p>
<hr>
<p>可你刚才还说对自己的人生感到满足呀！” “玩弄词句而已。”我说，“任何军队都要有一面战旗。”</p>
<hr>
<p>因为想让你面见祖父从而正确了解情况。”她说，“况且即使我告诉了你，你也肯定不会相信的吧？” “有可能。”的确，就算有人风风火火地告诉我什么第三线路什么不死之类，我也怎么都不会信以为真。 此后游了不一会儿，手尖突然触及硬物。由于正想着问题，脑袋一时转不过弯，不知硬物意味着什么，但马上恍然大悟：是岩壁！我们总算游完了地下湖。 “到了！”我说。 女郎也来到身旁确认岩壁。回首望去，手电筒光如一颗小星在黑暗中微微闪烁。我们顺着那光线往右移动了十多米。 “大约是这里了。”女郎说，“水面往上约五十厘米的地方应该有个洞。” “不会淹</p>
<hr>
<p>然而，这一切宛如挪动过的复写纸，无不同原有位置有着少许然而无可挽回的差异。</p>
<hr>
<p>。想到这里，我觉得自己已送走的人生委实荒唐而空虚，</p>
<hr>
<p>所有种类的记忆都奇异地变得扁平扁平的，犹如被超级压力机压成一张铁板的汽车。记忆在纷纭杂陈的状态下成了一枚信用卡样的薄片，虽然从正面看去仅仅给人以稍欠自然之感，但横看则不过是几乎无意义的一条细线。里面固然压缩着我的一切，而其本身不外乎一枚塑料卡片，解读时除非插进专用装置的吞吐口，否则全然不知所云。</p>
<hr>
<p>既无意义，又无归宿。但无所谓，因为谁也不需要什么意义，更不想找什么归宿。其实我们每一个人都在这里分别挖着纯粹的坑。没有目的的行为，没有进步的努力，没有方向的行走——你不认为这样很好？谁也不伤害谁，谁也不受谁伤害；谁也不追赶谁，谁也不被谁追赶。没有胜利，没有失败。”</p>
<hr>
<p>想来，人生仅剩二十四个小时这点颇有点妙不可言。该干的事原本堆积如山，实际上却一个也想不起来</p>
<hr>
<p>，没有争夺没有怨恨没有欲望，无非等于说也就没有相反的东西，那便是快乐、幸福和爱情。正因为有绝望有幻灭有哀怨，才有喜悦可言。没有绝望的终极幸福是根本不存在的。</p>
<hr>
<p>即使能够重新开始自己的人生，恐怕也还是要走老路。因为那——继续失去的人生——便是我自身。我除了成为我自身别无选择</p>
<hr>
<p>“不是的，是声音特别。”她说，“就像小孩站在窗前凝视下雨似的。</p>
<hr>
<p>一切都将一去杳然，任何人都无法将其捕获。 我们便是这样活着</p>
<hr>
<p>“不过挺有意思的。《刀锋》我读了三遍。虽说不很出色，但读得下去，</p>
<hr>
<p>由于失去音乐的时间过于长久，以致我甚至已不能对它产生饥渴之感了。</p>
<hr>
<p>蜗牛具有神话意味。”她说，“外壳意味着黑暗世界，蜗牛从壳中探头意味着阳光普照。所以，人们一看见蜗牛，就本能地想敲打外壳使它从里面出来亮相。</p>
<hr>
<p>。所谓死，便是将刮脸膏剩下半盒。</p>
<hr>
<p>人们所怀有的梦想我想大致可分为两种：完全的梦想和有限的梦想</p>
<hr>
<p>我觉得这种死法才适合于我——形象结束得直截了当，即刻瓦解，无暇他顾。”</p>
<hr>
<p>对着墓双手合十，然后坐下来吸烟。在五月温存的阳光下，我觉得生和死都同样闲适而平和。我仰面躺下，谛听云雀的吟唱，听了几个小时</p>
<hr>
<p>大海中漂浮的小艇总好像有些特殊</p>
<hr>
<p>再说就算是同样清算人生，她是出于自己的意愿，而我则不然，我不过是在酣睡之时被人突然抽掉床单而已。</p>
<hr>
<p>我不过是在酣睡之时被人突然抽掉床单而已。</p>
<hr>
<p>即便我的消失不足以使任何人悲伤，不能给任何人心里带来空白，或者不为任何人所注意，那也是我自身的问题。</p>
<hr>
<p>深重的悲哀甚至不可能采用眼泪这一形式来表现。</p>
<hr>
<p>“鲍勃·迪伦是谁？” “下雨天……”刚开始解释，又不耐烦起来，便改口道，“一个声音嘶哑的歌手。”</p>
<hr>
<p>想到这点，我涌起一股莫名的感动。宇宙运行规律并未忽略我微不足道的眼睑。</p>
<hr>
<p>“我该走了。”影子说，“也真是奇妙，往后竟再也见不到你了。不知道最后说一句什么好。怎么也想不起简洁的字眼。” 我又一次摘下帽子拍雪，重新戴正。 “祝你幸福。”影子说，“我喜欢你来着，即使除去是你影子这点。” “谢谢。”我说。</p>
<hr>
<p>一个月我就是这样度过的，恰如某种人把月历上的数字一个个涂黑。</p>
<hr>
<p>对于她，我成了已然失却之人。无论她怎样继续爱我，那都已是另一问题。我们过于习惯相互的角色了。我再也没有能够给予她的了。她本能地明白这一点，我凭经验了然于心。不管怎样都已无救。</p>
<hr>
<p>往杯中各斟了一口。一股浓缩了的伙食费味儿。</p>
<hr>
<p>“本来是先生的专车。”过了一会司机说道。司机比外表要容易接近得多，“但他今年春天身体不好以后已不再外出，又不好叫车白白闲在那里。而且您想必也知道，车这东西不定期出动的话性能会降低的。</p>
<hr>
<p>或许我们应该出生在十九世纪的俄国。我弄个什么什么公爵，你弄个什么什么伯爵，两人狩猎，决斗，争风吃醋，怀有形而上的烦恼，在黑海岸边望着晚霞喝啤酒，晚年因株连“什么什么叛乱”而被流放到西伯利亚，并死在那里。你不认为这样很美很妙</p>
<hr>
<p>不带行李乘长途列车实在令人快意，简直就像在晃晃悠悠散步时被卷入变形时空的鱼雷歼击机</p>
<hr>
<p>“混沌改变了其形态而已。熊毅然甩掉帽子，换上了斑马的围脖。”</p>
<hr>
<p>。一切都清晰得历历如昨的时候，反而不知从何处着手，就像一张十分详尽的地图，有时反倒因其过于详尽而派不上用场</p>
<hr>
<p>并非生的对立面，而作为生的一部分永存。</p>
<hr>
<p>到四月中旬，直子满二十岁。我十一月出生，她大约长我七个月。对直子的二十岁，我竟有些不可思议。我也好，直子也好，总以为应该还是在十八岁与十九岁之间徘徊才是。十八之后是十九，十九之后再十八——如此固然理想，但她终究二十岁了。到秋天我也将二十岁。惟死者永远十七</p>
<hr>
<p>。我放上唱片，第一张听完便把唱针移到第二张。全部听完之后，又从头听起。唱片只有六张。第一张是《佩珀军士寂寞的心俱乐部乐队》，最后是比尔·埃文斯的《献给黛比的华尔兹》</p>
<hr>
<p>“哪里会有人喜欢孤独，不过是不喜欢失望。”然后转向我：“如果你写自传的话，可别忘了这句对白。”</p>
<hr>
<p>“嗯，你认为有钱的最大优势是什么？” “不晓得。” “是可以说没钱呀</p>
<hr>
<p>“没有人不做，”我解释道，“男的手淫跟女孩子来月经是同一码事。” “有女朋友的也这样？就是说有发泄对象的？” “问题不在这里。我隔壁一个庆应大学的学生手淫之后才去幽会，说这样就心平气和了。</p>
<hr>
<p>死的阴影一步一步侵入生命的领地，等察觉到的时候，已经黑乎乎的什么也看不见了。那样子，连周围人都觉得我与其说是生者，倒不如说是死者。我讨厌的就是这个，这是我绝对忍受不了的</p>
<hr>
<p>事情不过发生在半年前，我却觉得似乎过去了很久很久。或许是因为我对此不知反复考虑了多少次的缘故。由于考虑的次数太多了，对时间的感觉便被拉长，变得异乎寻常了</p>
<hr>
<p>“呃，你最喜欢的菲茨杰拉德好像说过这样一句话：将自己说成普通人的人，是不可信任的，对吧？那本书，我从你手里借来看了一遍。”直子调皮地说。</p>
<hr>
<p>在一个狂风暴雨的黑夜，爬上悬崖峭壁掏燕窝，是这</p>
<hr>
<p>她父亲哆哆嗦嗦动了动嘴唇，说“不大好”。那其实不是说，而似乎是在把喉头深处的干空气勉强换成语言。“头。”他说</p>
<hr>
<p>此前我一般要‘咔咔’拧三十六下发条，并且想：好，今天也要精神抖擞地开始一天的生活！我本身倒未注意，别人告诉说近来我常常自言自语，或许是一边上发条时一边口中念念有词的吧。</p>
<hr>
<p>安静的、平和的、孤独的星期日”——我出声说道。星期日我是不上发条的。</p>
<hr>
<p>我走进附近一家意大利比萨饼店，一边喝啤酒嚼比萨饼，一边眺望美丽的夕阳。天地间的一切全都红彤彤一片。我的手、盘子、桌子，凡是目力所及的东西，无不被染成了红色，而且红得非常鲜艳，就好像被特殊的果汁从上方直淋下来似的。就在这种气势夺人的暮色当中，我猛然想起了初美，并且这时才领悟她给我带来的心灵震颤究竟是什么东西——它类似一种少年时代的憧憬，一种从来不曾实现而且永远不可能实现的憧憬。这种直欲燃烧般的天真烂漫的憧憬，我在很早以前就已遗忘在什么地方了，甚至很长时间里我连它曾在我心中存在过都没有记起。而初美摇撼的恰恰就是我身上长眠未醒的“我自身的一部分”。当我恍然大悟时，一时悲怆至极，几欲涕零。她的确、的的确确是位特殊的女性，无论如何都应该有人向她伸出援助之手。</p>
<hr>
<p>能如此执着地爱上一个人，这本身恐怕就是件了不起的事</p>
<hr>
<p>通知有电话打来的蜂鸣器响起的时候，我酣睡得如同昏死一般。当时确实达到了睡眠状态的极限，根本搞不清发生了什么事。熟睡当中，恍惚觉得头颅里灌满了水，大脑被泡得胀鼓鼓的</p>
<hr>
<p>看多少次演的都是同一码事。”我说。 “那有什么办法，我们干的也始终是同一码事嘛！</p>
<hr>
<p>世上就是存在如此类型的钱款——拿在手上来气，花的时候晦气，花光时自己生自己的气，于是又想花钱，但那时已无钱可花。无可救药。</p>
<hr>
<p>“春天的原野里，你一个人正走着，对面走来一只可爱的小熊，浑身的毛活像天鹅绒，眼睛圆鼓鼓的。它这么对你说道：‘你好，小姐，和我一块儿打滚玩好么？’接着，你就和小熊抱在一起，顺着长满三叶草的山坡咕噜咕噜滚下去，整整玩了一天。你说棒不棒？” “太棒了。” “我就这么喜欢你</p>
<hr>
<p>不要同情自己！”他说，“同情自己是卑劣懦夫干的勾当</p>
<hr>
<p>晚饭后，想给绿子写信，但反复写了几次都没写好，最后给直子写了一封。</p>
<hr>
<p>我只写得意的事项、愉快的感受和美好的际遇，只写芳草的清香、春风的怡然和月光的皎洁，只写看过的电影、喜欢的歌谣和动心的读物。写罢反复阅读之间，我本身竟也得到了慰藉，心想自己所生活的世界是何等美妙绝伦</p>
<hr>
<p>“死并非生的对立面，死潜伏在我们的生之中。” 实际也是如此。我们通过生而同时培育了死，但这仅仅是我们必须懂得的哲理的一小部分。而直子的死还使我明白：无论熟知怎样的哲理，也无以消除所爱之人的死带来的悲哀。无论怎样的哲理，怎样的真诚，怎样的坚韧，怎样的柔情，也无以排遣这种悲哀。我们惟一能做到的，就是从这片悲哀中挣脱出来，并从中领悟某种哲理。而领悟后的任何哲理，在继之而来的意外悲哀面前，又是那样软弱无力——</p>
<hr>
<p>她吐了口气，熄掉烟，又抱起吉他。弹了《潘尼小巷》，弹了《黑鸟》，弹了《朱莉安》，弹了《年届六十四》，弹了《独行者》，弹了《而且</p>
<hr>
<p>我看着玲子的眼睛。她哭了。我情不自禁地吻她。周围走过的人无不直盯盯地看着我们，但我已不再顾忌，我们是在活着，我们必须考虑的事只能是继续活下去。</p>
<hr>
<p>边用微型唱机反复播放——放了一百二十遍——《佩珀军士寂寞的心俱乐部乐队》，一边不停笔地写这部小说</p>
<hr>
<p>每当下雪，我就把雪卓有成效地扫到路旁。 既无半点野心，又无一丝期望。来者不拒，并且有条不紊地快速处理妥当。坦</p>
<hr>
<p>指望得到特别的好评或亲切的安慰。我之所以如此尽心竭力，只是因为这对我是最大的乐趣。自我训练。我要将许久闲置未用的手指和大脑变本加厉地用于实际的——或者可能无聊的——事务上。</p>
<hr>
<p>们工作起来雷厉风行，干脆利落，不说废话，互相尊重。双方都晓得这是迫于生计才干的无聊行当，但无论如何，既然干，就要干好。</p>
<hr>
<p>。同杰克·伦敦那波澜壮阔的伟大生涯相比，我这人生简直像在橡树顶端的洞穴里头枕核桃昏昏然等待春天来临的松鼠一样安然平淡，至少一时之间我是这样觉得的</p>
<hr>
<p>心灵的震颤，</p>
<hr>
<p>失去的，和没有失去的，加起来就是大家。一切都以此为中心连在一起。”</p>
<hr>
<p>要跳要舞，只要音乐没停</p>
<hr>
<p>我身心的几乎所有部分都渴望入睡，惟独脑袋的一小部分僵固不化，执著地拒绝睡眠，致使神经异常亢奋，焦躁不安，焦躁得就像企图从风驰电掣的特快列车的窗口看清站名时的心情一样——车站临近，心想这回一定要瞪大眼睛看个明白，但无济于事，速度过快，只能望到模模糊糊的字形，看不清具体是何字样。目标稍纵即逝，如此循环往复。车站一个接一个迎面扑来，一个接一个尽是边远的无名小站。列车好几次拉鸣汽笛，其尖厉的回声犹如蜂刺一般刺激我的神经。</p>
<hr>
<p>“25的下一位数？”——有人问。“71。”——我回答。“</p>
<hr>
<p>年轻，时间多的是，还谈着恋爱。再无聊的东西，再细小的事情，都可以用来寄托自己颤抖的心灵和情思</p>
<hr>
<p>有什么好痛苦的，”我说，“这是事实，总不能回避事实。因此谈不上痛苦，只是一种莫名之感</p>
<hr>
<p>你看上去好像我行我素，至于别人怎么看怎么想，你好像不大放在心上，只是做自己想做的事情，并设法做得容易些。就是说，你确保了完整而独立的自己。</p>
<hr>
<p>无论对谁。我觉得与其争辩，莫如言听计从为好，那要省事得多。权当傀儡好了，累得当傀儡。过去可不是这样，过去是要好好发一顿火的</p>
<hr>
<p>不过，我可以捕捉到事物新鲜的风姿，那实在是令人快慰的时刻。香气四下飘溢，泪水滴滴灼人，女孩美如梦幻。摇滚乐永远是摇滚乐，电影院里的黑暗是那样的温柔而亲切，夏日的夜晚深邃无涯而又撩人烦恼。是音乐、电影和书本陪我度过这几多焦躁的日夜晨昏，于是我记住了萨姆·库克和纳尔逊唱片里的歌词。我构筑了独有我自己的小天地，并生活其中</p>
<hr>
<p>车到山前必有路。要是没有路，到那时再想办法也不迟。再长大一点，还可以谈恋爱，可以让人买胸罩，观察世界的角度也会有所改变。</p>
<hr>
<p>过单身生活的人往往会在无意中掌握很多种能力，否则便无法将生命延续下去。</p>
<hr>
<p>我是在问性欲，问那东西是怎么回事。” “假定你是一只鸟，”我说，“假定你喜欢在天上飞并感到十分快活，但由于某种原因你只能偶尔才飞一次。对了，比如因为天气、风向或季节的关系有时能飞有时不能飞。如果一连好些天都不能飞，气力就会积蓄下来，而且烦躁不安，觉得自己遭到不应有的贬低，气恼自己为什么不能飞。这种感觉你明白？”</p>
<hr>
<p>唱片是斯坦·罗茨演奏的舒伯特作品100号三重奏。从很多年前开始，每到春天我就听这张唱片。</p>
<hr>
<p>五反田要是当宗教学家就好了，那样他就可以早晚领大家念念有词：“统统无聊透顶，简直是臭屎蛋，干巴巴的臭屎蛋，百分之百地叫人作呕！”很可能会大行其道。</p>
<hr>
<p>女士们先生们，我现在想睡的对象只有老婆一人。感动热潮，此起彼伏。雪云散尽，阳光普照。” “冰川消融，海盗称臣，美人鱼歌唱。”</p>
<hr>
<p>任何东西迟早都要消失。我们每个人都在移动当中生存，我们周围的东西都随着我们的移动而终究归于消失，这是我们所无法左右的。该消失的时候自然消失，不到消失的时候自然不消失。</p>
<hr>
<p>如此表达。问题不在于能否进行得顺利。我同你睡，这是既定之事。我不想在既定之事上面没完没了地兜圈子</p>
<hr>
<p>“为什么要跑到外国打仗呢？”阿伊努牧羊人到处问人。当时他已四十五岁了。 谁也没有回答他的提问</p>
<hr>
<p>人一个人生存是很不得了的事。</p>
<hr>
<p>这回可以好好入睡了。睡得非常实，大约是离家以来睡得最实的。感觉上就像坐一台大大的静静的电梯缓缓下到地底。不久，所有灯光熄灭，所有声音消失。</p>
<hr>
<p>开出速度，发生交通事故可就不是割破手指尖那样的小事故。而若大量出血，血友病患者也好健康人也好生存条件都差不许多。公平！不必考虑凝固不凝固那类啰嗦事，可以怡然自得无牵无挂地死去。</p>
<hr>
<p>在这个世界上，不单调的东西让人很快厌倦，不让人厌倦的大多是单调的东西。向来如此。我的人生可以有把玩单调的时间，但没有忍受厌倦的余地。而大部分人分不出二者的差别。</p>
<hr>
<p>“这广阔而深邃的森林都是你的，厕所在哪里由你裁定。”</p>
<hr>
<p>想到这里，身体有点放松下来。我可以超越时间，用指尖摩挲出这里存在的过去的影子。自己可以同那影子合为一体。我喟叹一声，不知不觉沉入了睡眠之中。</p>
<hr>
<p>就莫名其妙了。但传不到一般人耳朵。</p>
<hr>
<p>“她说出口的预言百发百中，然而谁也不信以为真。这就是阿波罗施加的诅咒。而且她说出的预言不知何故全是不吉利的预言——背叛、过失、人的死、国的陷落。所以，人们不但不相信她，还嘲笑她憎恨她。</p>
<hr>
<p>我试着想像四十年后的自己，好像在想像宇宙的尽头。</p>
<hr>
<p>“第一，我不是男性。”大岛宣布。</p>
<hr>
<p>叶林不见一线阳光。 人的一切活动如此荡然无存之后，羊们——唯独羊们——剩留下来。</p>
<hr>
<p>“还是挺无聊的吧？” “你会觉得自己的人生无聊？” “不清楚啊。” “羊的情况也差不多。”管理员说，“压根就没想那个，想也想不清楚。吃干草，小便，打打架，想想肚里的羔——一冬就这么过去了</p>
<hr>
<p>如切如削的悬崖峭壁将所有的生命体抖落一空，却仍不尽兴，又把不吉利的气息吐向四周</p>
<hr>
<p>好个不争气的家伙！那也算男人？走这几步就上不来的那一丁点儿性欲，还不如压根儿没有。” “得得。”</p>
<hr>
<p>毕竟是我手里货真价实的头一号。乳房胀鼓鼓，皮肤滑溜溜，腰肢曲弯弯，那里湿漉漉，百分之百的性爱女郎。拿汽车打比方，简直就是床上的四轮驱动车。脚一踩就是爱欲的涡轮机，指一箍就是怒涛的换挡手柄。好了好了要拐弯了，荡神销魂的变速器。来啊来啊，超车线上勇往直前，冲啊冲啊，星野君一飞冲天！</p>
<hr>
<p>姑且采用上校山德士这一堪称资本主义社会之大通的通俗易懂的形体而已。米老鼠也蛮好，但迪士尼对肖像权有诸多清规戒律，懒得打官司</p>
<hr>
<p>大约两百张唱片，哪一张都伤痕累累，但至少并非毫无价值。音乐没有思想那么容易风化</p>
<hr>
<p>但绝对算不上前卫。不过如果怀以诚心细细倾听，应该能够从中听出他对近代性自我藏而不露的憧憬，它作为蕴含矛盾的远方的魂灵在海顿音乐中默默喘息。例如——请听这个和弦，喏，固然宁静平和，但其中充满少年般的柔弱绵软的</p>
<hr>
<p>十月的第二周，是城市看上去最成其为城市的时节</p>
<hr>
<p>但我觉得能感觉出寂寞也多少是个慰藉。寂寞是一种不坏的心绪，就像小鸟飞走后的那棵寂寂的米槠树。</p>
<hr>
<p>性愈演愈烈。他的音乐随着年龄的增长而飞跃性地向外扩展幅度，同时又稠密地集中于内心。大概惟独贝多芬才能将这种二律背反性同时发挥得淋漓尽致，而如此非同寻常的作业将他的现实人生迅速毁坏殆尽，人的肉体和精神毕竟是有限度的，不可能长期忍受这种剧烈劳作。</p>
<hr>
<p>大岛点头。“当然，”他说，“体悟什么，我们身上的什么因之发生变化，类似一种化学作用。之后我们检查自己本身，得知其中所有刻度都上了一个台阶，自己的境界扩大了一轮。我也有这样的感受。倒是偶尔才有一次，偶一有之。同恋爱一样。</p>
<hr>
<p>住，哪里也不存在旨在结束战争的战争。”叫乌鸦的少年说，“战争在战争本身中成长，它吮吸因暴力而流出的血、咬噬因暴力而受伤的肉发育长大。战争是一种完完全全的活物。这点你必须了解。</p>
<hr>
<p>“回忆会从内侧温暖你的身体，同时又从内侧剧烈切割你的身体。”</p>
<hr>
<p>我的问话就像弄错了线路似的，被吞入哪里一方无名的空间，就此消失不见。</p>
<hr>
<p>雪白的沙子从少女纤细的指间滑落。海浪轻轻四溅的声音传来了。腾起，下落，溅开。腾起，下落，溅开。我的意识被昏暗的走廊般的场所吸了进去。</p>
<hr>
<p>其次是清洁，清洁得如同一口新出厂的棺木。四壁和天花板全是不锈钢，闪闪发光，纤尘不染。</p>
<hr>
<p>人的胖法和人的死法差不多同样多姿多态</p>
<hr>
<p>号角的音响同其他任何一种音响都有所不同，它像一条略微泛青的透明鲜鱼一样静静穿过暮色苍茫的街头，将路面的鹅卵石、民舍的石壁以及与河旁路平行的石头围墙沉浸在其音响之中。音响静静地笼罩所有的街头巷尾，犹如漫进大气中肉眼看不见的时间断层。</p>
<hr>
<p>“这点我也加了小心，所以才把数据和程序全部略去，只将理论用设想的形式发表出来，这样就无需担心他们弄懂弄通。在学术界我或许遭受冷落，但我并不在乎，一百年后我的理论必将得以证实，那就足矣！</p>
<hr>
<p>。我认为纠纷大部分起因于含糊其辞，并相信世上很多人之所以说话含糊，不外乎他们内心在无意识地寻求纠纷</p>
<hr>
<p>“心不是使用的。”我说，“心只是存在于那里，同风一样，你只要感觉出它的律动即可。”</p>
<hr>
<p>奇妙得犹如羽绒枕和搅冰勺、墨水瓶和莴苣一类组合</p>
<hr>
<p>我猜测在她眼里，我恐怕不是纯粹的狂人便是发狂的纯粹人。但愿她选择后者，那样，或许多少可以对我怀有富于人情味的兴趣。</p>
<hr>
<p>独角兽的出现意味着圣人临世，例如孔子的母亲怀他之时便见到了独角兽。 “‘七十年后，一伙猎人杀了一头麒麟，角上还带有孔子母亲缚的彩绳。孔子去看这独角兽，并掉了眼泪。这是因为，孔子感到这头纯真而神秘的动物的死具有某种预言性，那条彩绳上有着他的过去。’</p>
<hr>
<p>看门人用熟练的手势把新木板刨光，影子则用锤子敲打。看来影子的模样较之与我分别时几乎没什么变化，身体情况也不像很糟，但动作总好像有点不大自然，眼角现出了似乎不快的皱纹。</p>
<hr>
<p>我的意识彻底成了双重结构。就是说，首先具有作为整体混沌状态的意识，而其中有个如同梅干核那样的集约混沌状态的意识核。</p>
<hr>
<p>还有一个问题，”他们说，“那就是：人是否应该明确知道自己的意识核？” “不懂。”我回答。 “我们也不懂。”他们说，“可以说，这是个超越科学的问题。这和在洛斯·阿拉莫斯研究原子弹的科学家们碰到的是同一类问题。”</p>
<hr>
<p>我开始考虑辞去计算士工作以后的生活。我要存一大笔钱，加上退休金，从从容容地打发时光，学习希腊语和大提琴。把琴盒放在小汽车后座，开上山去一个人尽情尽兴地练琴</p>
<hr>
<p>惟独我存留下来，如金枪鱼一样沉沉睡去。</p>
<hr>
<p>沉默如同枪口冒出的烟一般从话筒口袅袅升起</p>
<hr>
<p>每次面对性急之人，我倒多少想试验一下其性急的程度。</p>
<hr>
<p>那么说，”小个子泰然自若地回答，“只是问你最珍惜什么，没有说不破坏。破坏就是要从珍贵的开始，岂非明摆着的事！”</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>森见登美彦</title>
      <link>https://ds63.eu.org/2023/morimi-tomihiko/</link>
      <pubDate>Sat, 18 Nov 2023 13:24:46 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/morimi-tomihiko/</guid>
      <description>行行复行行，犹在书山中</description>
      <content:encoded><![CDATA[<p><strong>最近看过他不少作品，记录下。</strong></p>
<h2 id="四叠半神话大系">《四叠半神话大系》</h2>
<h3 id="吐槽">吐槽</h3>
<p>书中的吐槽很有意思，摘抄部分：</p>
<blockquote>
<p>俗话说“三岁看大”，而我已经二十有一，再过不久，就诞生在这世上将近四分之一个世纪了，事到如今，一个年轻人就算试图改变自己的人格，做些无谓的努力，又能怎样呢?若是勉强扭曲已经变得硬邦邦、屹立在半空中的人格，充其量就是喀嚓一声折断而已。</p>
</blockquote>
<blockquote>
<p>健全地和异性交往、精进学业、锻炼身体等，我之所以将用来成为社会栋梁的布局悉数拆除，专挑不碰为妙的布局下手，诸如孤立于异性、放弃学业、放任身体衰退等，是为了什么呢?有必要质问负责人。可是负责人在哪里?</p>
</blockquote>
<blockquote>
<p>我怎么能输?! 　　怎么能输给不甘寂寞?!</p>
</blockquote>
<blockquote>
<p>你至今的两年很努力。不要说接下来的两年，接下来的三年、四年也一定能够出色地白白糟蹋掉。我向你保证。”</p>
</blockquote>
<blockquote>
<p>不可以毫无限制地使用可能性这个字眼。限制我们的，不是我们拥有的可能性，而是我们拥有的不可能性。</p>
</blockquote>
<blockquote>
<p>迟早把所有墙壁打通，兴建保龄球馆、电影院、电玩中心等各种娱乐设施，实现乌托邦。光想就觉得满心雀跃。明明雀跃不已，却潸然泪下</p>
</blockquote>
<blockquote>
<p>我奉即使绿灯闪烁也绝不跑着过马路为信条。换句话说，我是个绅士。</p>
</blockquote>
<blockquote>
<p>这间四叠半宿舍连冷气机也没装，我之所以满身大汗地忍耐至今，并不只是因为我忍耐度高，而且人品清高；而是因为本宿舍的墙壁恰似学艺会的舞台布景，寒碜且到处是洞。</p>
</blockquote>
<blockquote>
<p>相较于如今的我，当时的我一点都不孤独。等于是在孤独的大海海岸边，只把脚尖沾湿，不顾周遭的眼光，大喊“我好孤独!”的早熟婴儿。</p>
</blockquote>
<blockquote>
<p>因此，我不会抱紧过去的自己，也不会肯定过去的错误，但好歹愿意不加追究。</p>
</blockquote>
<h3 id="重复的四叠半">重复的四叠半</h3>
<p>在最终话中，“我”被困于无限重复的四叠半宿舍中。</p>
<p>“我”的心态也随着时间的推移而不断变化。</p>
<ol>
<li>先是拖延</li>
</ol>
<blockquote>
<p>四叠半宿舍世界探险开始是开始了，但我不愿猴急地展开行动。我缜密地对事情分析，分析，再分析，最后慢条斯理地采取万全对策。我是个仔细分析到耽误采取万全对策时机的人。</p>
</blockquote>
<blockquote>
<p>手忙脚乱也解决不了问题。自从变成虚有其名的大三生之后，我的生活大部分是在这个空间进行。明明之前没有这么热衷地想出去，现在却想破门而出</p>
</blockquote>
<ol start="2">
<li>尝试消磨时间</li>
</ol>
<blockquote>
<p>我原本以为，像那样自欺欺人的期间，事情会有所好转，但是完全没有改变。我为了运动而做俯卧撑，努力做似是而非的压腿动作；喝光一个洗脸盆左右的咖啡，终于把六个蜂蜜蛋糕全部塞进肚子里，用白萝卜和汉堡鱼肉饼发明出新菜。反复阅读《海底两万里》中关于鹦鹉螺号餐桌上的豪华菜肴的描述，到口水直流的地步。</p>
</blockquote>
<ol start="3">
<li>探索</li>
</ol>
<blockquote>
<p>我只好毅然执行宏伟的冒险计划，朝这个绵延不绝的四叠半宿舍世界的尽头展开旅程，解开这个世界的谜，顺利的话就可以逃出去。</p>
</blockquote>
<ol start="4">
<li>发狂</li>
</ol>
<blockquote>
<p>后来，我一时兴起，继续破坏墙壁、试图破坏天花板而受挫、神游于幻想与现实之间、打开门、舔酱油、打开窗户、整整睡掉两天、喝得烂醉呕吐，然后又想到了似的继续破坏墙壁。东奔西跑之际，在广大的四叠半宿舍世界中越来越迷失了自己的住处。</p>
</blockquote>
<ol start="5">
<li>规划</li>
</ol>
<blockquote>
<p>我心想，假如真的不能从这里出去的话，该怎么办。必须身为这个四叠半宿舍世界的开拓者，一个人勇敢地活下去。使用蜂蜜蛋糕和汉堡鱼肉饼，研发出更多样的菜肴，并计划性地着手于香菇的栽培事业，迟早把所有墙壁打通，兴建保龄球馆、电影院、电玩中心等各种娱乐设施，实现乌托邦。光想就觉得满心雀跃。明明雀跃不已，却潸然泪下。</p>
</blockquote>
<ol start="6">
<li>乏味</li>
</ol>
<blockquote>
<p>时而在一样的房间停下脚步，看书、唱歌、抽烟、丢得满地烟蒂。我彻底讨厌这趟冒险，使性子地心想：反正不管去了哪里，世界的尽头根本不存在。然而，如果四周笼罩在仿佛天底下的人类全死光了似的寂静之下，看着破破烂烂的天花板过一整天，令人吃不消的恐惧就会压得我喘不过气。不管怎么专心看书，或者四处大喊下流的话，那种恐惧也挥之不去。使用有限的食材，陆续研发出稀奇古怪的新菜单、没完没了地一直折纸，折了几十只纸鹤和纸人、哄Johnny、写文章、做俯卧撑，又哄Johnny用橡皮筋制作枪，玩射击游戏，纵然使尽各式各样的方法，从天花板静静落下的某种东西却会使我的身体变得沉重</p>
</blockquote>
<ol start="7">
<li>绝望</li>
</ol>
<blockquote>
<p>我的命运会因为不同的细微决定而改变。大概是我每天反复作无数的决定，所以诞生了无数个不同的命运。因此，就原理来说，这个四叠半宿舍世界是永无止境的。</p>
</blockquote>
<h3 id="动画">动画</h3>
<p>我是先看的动画，然后再看的书籍。二者更有千秋。</p>
<p>书籍里的吐槽更有趣，但重复的内容太多。</p>
<p>而动画则对此进行了优化，进行了适当的删改，观感会好许多。</p>
<p>以下摘录我日记中的部分内容：</p>
<h4 id="2023年3月2日">2023年3月2日</h4>
<p>很早前就知道了这部番，一直没下决心去看。这周抱着试试的心态点开了，发现男主飞快的台词和奇妙的画风很有意思，就一路看下去了。</p>
<p>由于周日还有考试，所以都是忍着一天只看几集这样子。现在是看到了第八集。</p>
<p>突然悟到了一点，可能是作者想要传达的东西。</p>
<p>你所做的选择，可能你做完了就后悔了。但其实你当初如果选择了另一个，还是可能因各种各样的原因，而继续后悔。
所以，不要悔，也不要想着回到过去。活在当下这样子。</p>
<h4 id="2023年3月4日">2023年3月4日</h4>
<p>把四叠半时光机布鲁斯也看完了，发现汤浅政明这个监督很棒，感觉跟捡到宝了似的，之后打算去补他的其他几部作品。</p>
<p>现在最有印象的有这几个：</p>
<ul>
<li>女主，真的就又帅又漂亮还可爱，很喜欢</li>
<li>四叠半时光机布鲁斯最后一集的最后一段有这么个比喻</li>
</ul>
<blockquote>
<p>时间就像一本书，我们无法一次看完所有内容，只能一页页翻，阅读书中的内容。但所有内容早就在那本书里写出来了、无论是遥远的过去，还是遥远的未来。&hellip;&hellip;但是，我们不知道未来会发生什么，不知道就意味着我们想干什么都可以，换句话说，我们这样也算是自由的。</p>
</blockquote>
<hr>
<h2 id="宵山万华镜">《宵山万华镜》</h2>
<p>这本书不是很厚，我是一天看完的。</p>
<h3 id="乙川">乙川</h3>
<p>最喜欢也最羡慕的一个人物是乙川。刚开始看会想到《四叠半神话大系》中的樋口清太郎。看下去后发现还是有许多不同的。</p>
<blockquote>
<p>乙川做的事，没有一件不古怪的。虽然古怪，却也不觉得很天才或是感到不安。就只是像眼前看到的这样，既古怪，又自由自在。</p>
</blockquote>
<p>他随心所欲的活着，办了不少奇事，比如：</p>
<blockquote>
<p>高二冬天，教室里会经出现圣诞树。还发生过男生厕所的卫生纸在一夜之间被换成带有甜香的粉红色卫生纸的事。为文化祭预算不足而哀声叹气的戏剧社收到一笔捐款；过完年来学校一看，班上每个人的桌上都有一块豆子大小的镜饼年糕。</p>
</blockquote>
<p>而当被问到这些事的时候，他是这样说的：</p>
<blockquote>
<p>我会经问他为什么要做那种事。</p>
<p>　「不知道，就是很想很想做。」乙川说。「这是为什么呢？算是所谓的生存意义吗？」</p>
<p>　「可是，没有人知道是你干的，做起来不是很没劲吗？」</p>
<p>　「这种低调含蓄的感觉别有一番风味。你可别告诉任何人。」</p>
</blockquote>
<p>故事中干的最大一件奇事是，耗费大笔预算、大量时间，造了个伪祇园祭，只为了和朋友藤田开个玩笑。理由呢，如下：</p>
<blockquote>
<p>为什么要爬山？因为山在那里。为什么要骗藤田同学？因为藤田同学在那里。这就是所谓的本能。</p>
</blockquote>
<h3 id="祇园祭">祇园祭</h3>
<p>简单搜了下，发现<a href="https://www.youtube.com/watch?v=hQZo5NWRw_I"  target="_blank" rel="noopener" >这个视频</a>蛮不错的。</p>
<p>尤其是书中提到好几次的蟑螂山和长刀鉾，发现和自己看书时的想象完全不一样。哈哈。</p>
<h3 id="多角度描写">多角度描写</h3>
<p>多角度地描写同一事物，是森见登美彦的一大特色。我在读《四叠半神话大系》的时候就有所体会。</p>
<p>这本书里也多次描写了一些事物：螳螂山，超金鱼&hellip;..</p>
<p>但与《四叠半神话大系》不同的是，这本书的主角不只一位，所以对同一事物，就会因为主角的视角不同，而有不同的描述。</p>
<p>这样的话就不会显得那么重复，反而觉得有趣。</p>
<h3 id="无限重复的时间">无限重复的时间</h3>
<p>《四叠半神话大系》里是无限重复的四叠半房间，而这本书里经历的则是无限重复的宵山这一天。</p>
<p>时间的无限重复和空间的无限重复，似乎有同样的效果。</p>
<p>但如果非要让我在其中选择一个，我想了下，还是选前者吧。</p>
<h3 id="万花筒">万花筒</h3>
<p>说实话最后一章让我有点没看明白。</p>
<p>但也不太打算去想得太明白。</p>
<p>就像万花筒一样。</p>
<p>图形一个接一个出现又消失，就像水池上生成的波浪一样。</p>
<h3 id="一句话">一句话</h3>
<p>这句话很有感觉。</p>
<blockquote>
<p>生病咳久了，最后会连咳嗽的力气都没有，但这却不代表病已经好了。</p>
</blockquote>
<p>都说时间是治愈伤痛的最后良药，但真的是这样吗？</p>
<hr>
<h2 id="太阳与少女">《太阳与少女》</h2>
<p>这是本散文集。</p>
<p>作者将这本书定义为“适合在睡前阅读的书。”</p>
<blockquote>
<p>我常常想写一本这样的书出来。 不会像哲学书那样艰深，也不像小说那样令人亢奋。并不是不有趣，却也并非有趣到让人一读就停不下来。尽管没写什么有实际好处的内容，读起来却也并非空虚般无益</p>
</blockquote>
<h3 id="行行复行行犹在书山中">《行行复行行，犹在书山中》</h3>
<p>没怎么逛过旧书店。</p>
<p>但这篇所描述的“下鸭纳凉旧书祭”让我向往。</p>
<blockquote>
<p>擦着汗寻觅旧书。蝉鸣声渗透进了森林的闲静中。真可谓行行复行行，犹在书山中。</p>
</blockquote>
<p>这一段我觉得写得很有趣：</p>
<blockquote>
<p>要说我最看不惯旧书集市哪一点，首先就是书太多了。</p>
<p>众多古色古香的书籍，每一本都看似承载着某些秘密，颇有渊源。闭上眼睛信手挑选，不论选中哪一册，都仿佛是只要读过一遍就能让我的人生开辟出荣光地平线的名著。我不禁心想，要是把它买下来，或许就能大受启发，写出本不属于自己的不朽名作呢。我暴露出与不朽名作无缘的渺小灵魂，同时心中那无益的焦虑便愈发严重。啊——这本也好那本也罢，应该都需要买吧？啊——这本也好那本也罢，还不至于偏要买吧？若是心想难得来一趟还是买几本吧，结果就是没完没了；若是坚决不买，旧书集市之行就此终结。我不厌其烦地反复体验这种焦躁感。不，我早已经烦透了，却还是反反复复。</p>
</blockquote>
<h3 id="读书人摆书人">《读书人，摆书人》</h3>
<p>我的书并不多。最近几年读的书几乎都是以电子版为主。</p>
<p>所以并不能体会到摆书的辛苦和幸福。</p>
<p>看文中提到的需要考虑的诸多地方，真是不容易。</p>
<h3 id="让孩子睁眼的方法">《让孩子睁眼的方法》</h3>
<p>我姑且认为自己还算是个懂得去从平常生活中体会乐趣的人，所以我很认同以下这几段话。</p>
<blockquote>
<p>当然了，我们确实是大人。成为大人的过程，就是学会让心中的孩子闭上眼睛。小孩子是很愚蠢的，如果净用孩子的眼睛来看世界，一定会遇上麻烦。所以我们才需要闭上孩子的眼睛。也许有一些人闭得太紧实了，会就此忘记用孩子的眼睛看世界的方法。</p>
<p>可是，大多数人可以熟练地控制心中的孩子，适时地睁眼闭眼。</p>
<p>品尝美食的时候、漫步或奔跑的时候、眺望森林的时候、抚摸猫咪的时候，我们会让心中的孩子睁开眼睛。想要像小时候那样尽情享受欢愉或许有些强人所难，但当初学会的方法如今也能派上用场。</p>
</blockquote>
<p>另：</p>
<p>这篇看得我想吃炸肉饼和生蛋拌饭。</p>
<hr>
<h2 id="有顶天家族">《有顶天家族》</h2>
<h3 id="动画-1">动画</h3>
<p>这一部我也是先看的动画，这里摘录我日记中的部分：</p>
<h2 id="2024年1月14日">2024年1月14日</h2>
<p>午饭边吃边看《有顶天家族》，第一集开始就渐入佳境，于是连看了三集。</p>
<p>翻评论翻到<a href="https://bbs.qyer.com/thread-3129691-1.html"  target="_blank" rel="noopener" >一个人的圣地巡礼之旅（六） 京都及返程篇 《有顶天家族》等圣地巡礼 - 日本 - 论坛 - 穷游网</a></p>
<p>发现里面的一些场景实拍起来其实蛮普通的。但日本就有这样的环境。作家对生长的土地有感情，愿意并且能够以其作为背景进行故事创作。让一些本来看似普通的地点有了别样的含义，这是中国所缺少的。</p>
<p>&hellip;</p>
<p>回来边吃边看《有顶天家族》，第五集时反复出现一个概念：我喜欢狸猫，和我喜欢吃狸猫不冲突。</p>
<p>我并没有养过动物的记忆，于是也理解得不深刻，不多说了。</p>
<h2 id="2024年1月16日">2024年1月16日</h2>
<p>看有顶天家族，好看。看到弹幕因为剧中人物的观点吵起来，于是关掉了弹幕。我现在不太喜欢什么观点都非得去分个对与错。因为我知道对与错很多都是相对的，取决于很多东西。</p>
<h2 id="2024年1月21日">2024年1月21日</h2>
<p>晚上把有顶天家族看完了。它背景画得很细致。狸猫也很可爱。但第二季觉得故事讲得还是差了些。我看森见登美彦的长篇总会觉得有些啰嗦。可能是他喜欢反复强调主旨，也可能是我喜欢一口气读完。</p>
<p>看完最后一集后还是会有些疑问，不过<a href="https://bgm.tv/blog/277049"  target="_blank" rel="noopener" >有顶天家族——浮华世间欲望百景</a>这篇解答得差不多了。可能还有些疑问，不过也不打算理清了。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://bgm.tv/blog/271077"  target="_blank" rel="noopener" >以读《宵山万华镜》为节点，回忆读森见书的时光</a></li>
<li><a href="https://www.youtube.com/watch?v=hQZo5NWRw_I"  target="_blank" rel="noopener" >京都祇园祭</a></li>
<li><a href="https://bbs.qyer.com/thread-3129691-1.html"  target="_blank" rel="noopener" >一个人的圣地巡礼之旅（六） 京都及返程篇 《有顶天家族》等圣地巡礼 - 日本 - 论坛 - 穷游网</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>读《神的九十亿个名字》</title>
      <link>https://ds63.eu.org/2023/%E8%AF%BB%E7%A5%9E%E7%9A%84%E4%B9%9D%E5%8D%81%E4%BA%BF%E4%B8%AA%E5%90%8D%E5%AD%97/</link>
      <pubDate>Fri, 17 Nov 2023 22:21:43 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E8%AF%BB%E7%A5%9E%E7%9A%84%E4%B9%9D%E5%8D%81%E4%BA%BF%E4%B8%AA%E5%90%8D%E5%AD%97/</guid>
      <description>穹苍之上，一片寂寥，群星慢慢地闭上了眼睛。</description>
      <content:encoded><![CDATA[<p>《神的九十亿个名字》是阿瑟·克拉克的短篇小说集，每篇故事都可以在半小时内看完，很有味道。</p>
<p>不过我还是断断续续看了两个来月。</p>
<p>有几篇我印象比较深：</p>
<h2 id="神的九十亿个名字">《神的九十亿个名字》</h2>
<p>两处描写星星的。</p>
<blockquote>
<p>他俩举起手中的火把，前方再无任何危险，唯独乍起的寒意令人稍感不适。头顶的天空清晰异常，熟悉的群星眨动着友善的目光。</p>
<p>查克没有回答，乔治在马鞍上摇摇晃晃地扭过身。他看到了查克的脸——那张毫无血色的椭圆形大脸正仰面望向天空。</p>
<p>“瞧啊。”查克低语道。乔治也抬起头，看向夜空(凡事终有尽时)。</p>
<p>穹苍之上，一片寂寥，群星慢慢地闭上了眼睛。</p>
</blockquote>
<p>想象不来是什么样的情景。</p>
<h2 id="被遗忘的敌人">《被遗忘的敌人》</h2>
<p>文章前面一再铺垫，最后是：</p>
<blockquote>
<p>教授躲在坚固堡垒的高墙之后，终于见到了不断前进的敌军，第一缕阳光映照在它们的矛尖上闪闪发光，这一刻，米尔沃德教授明白了一切。空气如水晶一般洁净，群山峰峦锐利，熠熠生辉，直指冰蓝色的天空。它们身上几乎不再有积雪覆盖，曾经的他见到这一切会欢欣鼓舞，可是现在，他已经笑不出来了。</p>
<p>一夜之间，被世人遗忘的军团再一次攻克了人类最后的防线，即将发起最后一次冲锋。末日群山的峰顶闪烁着致命的寒光，看到这些，米尔沃德教授终于明白，这几个月里，他听到的正是它们行军的声音。难怪他会梦到大山在行走了。</p>
<p>来自北方——远古的家园——迈着胜利的步伐再次踏上这块被征服过的土地，冰川回来了。</p>
</blockquote>
<p>作者在序中谈到了该篇的灵感，我看了觉得有趣，摘抄如下：</p>
<blockquote>
<p>那是20世纪30年代末的一个冬天，一场暴风雪席卷了伦敦，我正在楼顶看雪景，突然，一个糟糕的念头冒了出来：“如果这场大雪永远也停不了，那该怎么办？”结果，多年以后，这篇小说出炉了，我却因此搬到了赤道地区居住……</p>
</blockquote>
<h2 id="黎明不再来临">《黎明不再来临》</h2>
<p>有趣的是，在看完这篇后的晚上，我就做了一个梦，荒诞而似乎合理的梦，具体不多赘述。</p>
<p>梦醒来我就想起这篇中的一段：</p>
<blockquote>
<p>人类的头脑多么不可思议啊!</p>
<p>当然了，刚才这番谈话中没出现多少独创性的内容——很容易就能猜到这些想法是怎么来的，就在上周，他刚刚读过一本有关世界末日的小说。</p>
<p>至于什么星桥啊，穿越时空的隧道啊，很明显就是一场痴心妄想，全是一个跟火箭打了五年交道的家伙想象出来的。</p>
</blockquote>
<p>然后我就想，如果某一天也是外星人要来警告我，我也以为是自己在做梦呢？</p>
<h2 id="地球啊我若忘记你">《“地球啊，我若忘记你……”》</h2>
<p>这篇我觉得写得很美。这里摘抄几段:</p>
<blockquote>
<p>那个世界已然失落，只存在于传说之中，他再也无法在溪水旁散步，再也无法倾听远山之上的隆隆雷鸣。虽说总有一天——但要多久呢——他孩子的孩子将会返回地球，继承他们的遗产。狂风和暴雨会冲刷那片干枯的大地，洗去上面的毒尘，将其冲入大海，并在大洋深处将毒物分解，直到它们不再戕害万物。到那时，停靠等候在寂静荒原上的无数飞船会再次起航，飞向太空，沿着来路，重返家乡。</p>
</blockquote>
<blockquote>
<p>真是太美了，跨越时空的深渊，它已经深深触动了马文的心灵。在这轮闪耀的圆盘之上，有他从未见过的所有奇迹——夕阳西下时天空的色彩，海浪拍打卵石海岸时的低吟，雨滴落地的轻柔，积雪无声的祝福……这些，还有上千种其他的馈赠，原本是属于他的合法遗产，但如今他只能从书籍和古老的影像记录中得知这一切。一想到这里，他的心中充满了被放逐的苦闷与哀伤。</p>
</blockquote>
<p>蛮早之前就看过一种说法，同时我也很认可：</p>
<p>地球不需要保护，因为人类再这样破坏下去，并不会导致什么地球毁灭。毁灭的只是人类和其他无辜的生物。</p>
<p>这几年的气候变化很能说明问题：年中时候的暴雨、气温的极端化。</p>
<p>不愿看到这篇小说成为现实的那一天。</p>
<h2 id="相会于黎明">《相会于黎明》</h2>
<p>蛮有趣的一篇。</p>
<p>我想起之前看过的一个猜想：</p>
<p>上古神话中的一些形象，会不会是上古人类对其接触外星人类的记录呢？</p>
<p>文中有一段我读着很有感觉：</p>
<blockquote>
<p>两个人站在河岸边，一人身着紧身制服，配备着微小而精密的机械设备；另一人裹着兽皮，手持顶端绑缚燧石的长矛。十万个世代横亘在二人之间，十万个世代啊，还有一道无边无际的时空渊薮!但他们同属于人类。在永恒的时间长河中，自然母亲周而复始，同样的演化历程一再发生。</p>
</blockquote>
<p>还有一点是：</p>
<p>第一次读的时候我先入为主，很自然地把波特朗德认为是地球人类。认为这是未来的地球人类探索宇宙的故事。</p>
<p>读完后我想了下，也许雅安才是地球人类呢？或者两者都不是？</p>
<h2 id="尾巴">尾巴</h2>
<p>该短篇小说集收录的是作者在1972年之前的部分作品，已经很有历史了。</p>
<p>作为科幻小说，其中提到的一些内容甚至已然成为现实，其他未实现的也似乎并不是遥不可及。</p>
<p>能在自己的有生之年看到自己的科幻小说中的构想成为某种现实，作为作者是怎么样的心情呢，我蛮好奇的。</p>
<p>这里摘录下作者自序中的一段话。</p>
<blockquote>
<p>在陆续创作这些小说的二十五年间，航天技术已由神奇的梦想转变为几乎有些乏味的现实。当我于1948年完成《岗哨》的时候，我还很难意识到这一点，当时我也很难相信，在有生之年，我能亲眼目睹人类登月的全过程。</p>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>SAP VT项目面试记录</title>
      <link>https://ds63.eu.org/2023/sap-experience/</link>
      <pubDate>Thu, 16 Nov 2023 17:04:55 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/sap-experience/</guid>
      <description>记录 SAP VT项目面试经历</description>
      <content:encoded><![CDATA[<h3 id="2023年10月13日">2023年10月13日</h3>
<p>写好简历并投递。</p>
<h3 id="2023年10月27日">2023年10月27日</h3>
<p>收到回复邮件，说接下会有一次电话面试和笔试。</p>
<h3 id="2023年11月3日-面试">2023年11月3日 面试</h3>
<p>3点多的时候接到电话。</p>
<p>即可如下：</p>
<p>从哪得知 -&gt; 报sap的原因 -&gt; 个人项目收获介绍 -&gt; 技术栈很广泛，未来是什么打算呢 -&gt; 英文水平（自我介绍，简单问答）-&gt; 反问环节</p>
<p>我觉得自己表现得很差，有以下几点：</p>
<ol>
<li>多次打断面试官</li>
<li>语气词、停顿过多</li>
<li>表达不够清晰</li>
</ol>
<p>我给自己找了些原因：</p>
<ol>
<li>没有心理准备，确实没想到会是今天，上课上着呢突然来个电话</li>
<li>没有事先准备。自我介绍，中文和英文的都应该准备几分钟的，并写个稿子，但我没有</li>
<li>多次打断面试官这点可能是因为我太紧张了。</li>
</ol>
<p>反问环节，让我想到大一找导师时不好的回忆。导师最后也是让我反问，提示了两次我都没想到要问什么，这次也是。</p>
<p>现在想来，反问环节也算是一种考察。考察你提问的能力，考察你关注的重点。</p>
<p>我今天这个面试还只是对基础情况的了解，还不是技术面试。技术面试我如果还没有准备的话，会更糟。</p>
<p>自己也不要太伤心。刷推或者是刷贴吧能看到好多都是经历了许多次面试才拿到offer的，自己这才第一次呢。</p>
<h3 id="2023年11月6日-笔试">2023年11月6日 笔试</h3>
<p>晚上7点到八点半</p>
<p>20道选择+2道算法题</p>
<p>选择题考到了几个地方，我不熟悉：</p>
<ul>
<li>计算机网络</li>
<li>云计算</li>
</ul>
<p>算法题也不难,但我都没写出来。一道是百分之四十九的通过率，另一道没来得及，但再给我时间八成也不行。</p>
<p>说明还是得去做些算法题。</p>
<p>面试和笔试感觉自己都挺菜的，等着拿感谢信喽。</p>
<h2 id="2023年11月10日-群面通知">2023年11月10日 群面通知</h2>
<p>晚上收到了群体面试的通知。在线面试。</p>
<p>有点惊喜。但是自己也知道前两场自己的表现有多差。</p>
<p>感觉可能是去凑人数的。</p>
<p>不过当作一种体验也不错。</p>
<p>这几天要准备一下。</p>
<p>注：后面找资料的时候发现sap几乎不在前两个环节进行刷人。</p>
<h2 id="2023年11月15日-群面准备">2023年11月15日 群面准备</h2>
<p>网上稍微搜了下，看到几篇：</p>
<ul>
<li>
<p><a href="https://blog.csdn.net/qq_54121951/article/details/128660737"  target="_blank" rel="noopener" >SAP VT实习（钻石级杰出人才计划）面经&amp;SAP大致介绍_sap实习-CSDN博客</a></p>
</li>
<li>
<p><a href="https://blog.csdn.net/Caiyii530/article/details/121271144"  target="_blank" rel="noopener" >SAP VT 群面记录_-avocado-的博客-CSDN博客</a></p>
</li>
<li>
<p><a href="https://mp.weixin.qq.com/s/lUQAeD3qvZJzSnVfBjJQPA?poc_token=HM9VVGWjybn3WBwIoJ60_u2StdMMLEo4jy1Ny4sv"  target="_blank" rel="noopener" >SAP模拟面试总结报告</a></p>
</li>
<li>
<p><a href="https://m.kanzhun.com/firm/interview/detail/1nV-3965F1A~.html"  target="_blank" rel="noopener" >「SAP中国VT实习生面试」​面试之前在这个app上看了很久，现在通过了也来反馈一下。-看准网</a></p>
</li>
<li>
<p><a href="https://www.cnblogs.com/guodongdidi/p/4165653.html"  target="_blank" rel="noopener" >参加SAP VT项目有感 - 果冻迪迪 - 博客园</a>
这篇里有几句关于无领导小组讨论的我觉得写得不错,摘抄如下</p>
<pre tabindex="0"><code>群面看的是大家的软实力，通过小组的交谈能看出很多品质或者能力（不包括技术）。从以往来看，如果一个小组讨论的成功，那么这个小组每人进入下一轮的概率都会增加，小组里大家的关系更多的是增益的，不是相互竞争的，所以不建议在过程中非常明显的去充当领导人，更不能去打断别人，哪怕别人打断了你。小组的领导会在过程中慢慢自动就凸显出来了，比如事前多准备一些纸张多带一支笔，防止有人有没带，再比如在其他人说的时候做记录，为了之后的总结和发言，还有可以把控时间，防止时间分布不均匀，还可以引导大家讨论的方向（不要太离谱）等等，都可以让你在群面中凸显自己。
...
最后我们组整体表现还不错，八个人进了六个，没进的两位的原因在我看来一个是基本上不怎么说话，而且说的话还和大家的相反，另一个可能是因为发言太积极了，总是想当leader。
</code></pre></li>
<li>
<p><a href="https://juejin.cn/post/7017642966248325151"  target="_blank" rel="noopener" >SAP VT面试整理汇总 - 掘金</a></p>
</li>
<li>
<p><a href="https://www.dostarve.xyz/index.php/2023/03/22/sap_intern/"  target="_blank" rel="noopener" >SAP VT实习笔试+电话面试+线下群面 – 吃不饱</a></p>
<p><strong>作者应该是北交本+华东师范硕。但最后还是没有拿到offer。</strong></p>
<p><a href="https://www.dostarve.xyz/index.php/2023/04/13/find_intern/"  target="_blank" rel="noopener" >记录一下近一个月惨淡的找实习经历 – 吃不饱</a></p>
<p><strong>这里记录了其面试的情况。不少都是一面挂。这还只是找实习!</strong></p>
</li>
<li>
<p><a href="https://www.cnblogs.com/librasun/p/5049994.html"  target="_blank" rel="noopener" >[原创]大连sap vt 实习生面试经历 - LibraSun - 博客园</a></p>
<p><strong>感觉我明天也是这样，哈哈</strong></p>
</li>
</ul>
<h2 id="2023年11月16日-群体面试">2023年11月16日 群体面试</h2>
<ul>
<li>时间： 下午一点半 至 下午三点半</li>
<li>人员组成：
<ul>
<li>面试者6名：南大本科一名、华师大研一名、东南本一名、东南研一名、大工本一名、NEU研一名</li>
<li>主持人一位</li>
<li>面试官两位</li>
</ul>
</li>
<li>语言：全程中文</li>
<li>过程</li>
</ul>
<ol>
<li>轮流个人介绍，时长一分钟</li>
<li>无领导小组讨论 25分钟</li>
<li>轮流技术面试
<ul>
<li>主要是对简历上的个人项目进行提问。</li>
<li>每个人五分钟左右</li>
<li>大概6到7个问题</li>
<li>我被问到的问题记录如下：
<ol>
<li>Flask和Django的区别，选择Flask的理由</li>
<li>React异步处理</li>
<li>SpringBoot配置</li>
<li>跨域问题及其解决</li>
<li>同域名，端口不同，会跨域吗</li>
<li>SpringBoot端口</li>
<li>你的技术栈比较杂，有没有专长的</li>
</ol>
</li>
<li>整个流程被问到次数比较多的
<ol>
<li>事务操作</li>
<li>跨域问题</li>
</ol>
</li>
</ul>
</li>
<li>技术问题抢答
<ul>
<li>首先是Java为主的
<ol>
<li>autobox</li>
<li>hashmap,hashtable</li>
<li>序列号</li>
<li>string,stringbuilder,string buffer</li>
<li>反射</li>
<li>多线程同步</li>
<li>class loader</li>
<li>jdk17特性</li>
<li>设计模式</li>
<li>有个类大量运用了装饰器模式，是哪个类</li>
</ol>
</li>
<li>数据库相关
<ol>
<li>sql注入</li>
<li>数据库范式</li>
<li>mybatics 的一级、二级缓存</li>
<li>锁的粒度</li>
<li>数据库分区</li>
</ol>
</li>
</ul>
</li>
</ol>
<ul>
<li>感受
<ul>
<li>整体氛围还是不错的。有些问题并不是都能答出来，甚至比例还不小。</li>
<li>写到简历的个人项目不能乱写。面试官只要通过几个问题，很容易就能知道你是不是真的去做了。</li>
<li>我对自己的表现觉得还行，被问的问题差不多能答出来。</li>
<li>不抱任何希望，原因有二：
<ul>
<li>学历不占优，甚至是劣势</li>
<li>之前的两个环节表现都不太行</li>
<li>面试的岗位似乎是以Java为主，而提问时，我Java的都是模模糊糊有个印象，答不出来。</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>我对开源的看法</title>
      <link>https://ds63.eu.org/2023/my-opinion-about-opensource/</link>
      <pubDate>Tue, 14 Nov 2023 18:06:36 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/my-opinion-about-opensource/</guid>
      <description>long may the free software</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>从了解到开源这个概念后，我一直很喜欢它。不仅因为我从中受益匪浅，开源的文档、文章、工具、软件，在不少地方都使得我的生活更加便利。而且我也喜欢这个概念：帮助他人，快乐自己。</p>
<p>我觉得开源就是互联网精神的一大体现。</p>
<p>我的代码能力并不算强，但我也在一点点地去接触开源，让自己成为无数贡献者中的一员。</p>
<p>以下是我按照时间顺序进行的记录，记录触动我的关于开源的一些和事件和想法。</p>
<h2 id="2023年11月03日">2023年11月03日</h2>
<p><a href="https://www.eaimty.com/2023/opensource-project-based-on-hormone/"  target="_blank" rel="noopener" >基于荷尔蒙开发的开源项目 - EAimTY&rsquo;s Blog</a></p>
<p><strong>We laud the developers of open source software. But the real heroes are the maintainers.</strong></p>
<blockquote>
<h2 id="可笑的网民可悲的开发者">可笑的网民，可悲的开发者</h2>
<p>最近几天，clash for windows 停止了更新，clash core 的仓库也被作者删除了。这种事之前也发生过，但这次的后续真得既可笑又可悲。</p>
<p>Clash 倒下后，不知网民们出于何种想法，将这件事的热度扩散到了微博上，甚至达到了微博热搜。你们真的有考虑过开发者吗？这件事的影响已远远超过了可控范围，有多少双眼睛在盯着微博热搜？其中又有多少不怀好意呢？</p>
<p>大多数网名大概都是以吃瓜的角度在看这件事。没有人真的在为开发者着想，这真的非常可悲。你们如何证明 clash 作者以外的开源代理开发者们没有因为此次事件被特殊关注，人身安全受到威胁呢？</p>
<p>我还是将大众想得太善良了。中国人的本性就是喜欢看别人的悲剧，除非火烧到自己，否则根本不会有觉悟。我觉得我不值得将自己的任何精力贡献给这样的群体，更何况我的人身安全也受到威胁。</p>
<p>我特别反感人们将开源开发者停止开发叫做“跑路”。我觉得这是一个偏贬义的词，本来有责任的人突然消失了才是“跑路”，而不是不求回报的开源开发者们。我不知道现在简体中文互联网用户的中文水平为何如此可笑。</p>
</blockquote>
<p>我反思自己，昨天看到cfw删库和其作者的声明后，自己是什么的想法：</p>
<ol>
<li>我看到cfw的README下有接一些vpn的推广，并且其不能算是一款开源软件。甚至觉得有点low。</li>
<li>我觉得未来的形式是会越来越坏，但目前还有替代品可以用。</li>
<li>必须指出的一点是：尽管我长期以来使用cfw，我的第一反应却没有因为其作者被喝茶,受威胁而对作者感到同情。我尽管是其项目的受益者，但我连最起码的感谢都很少。</li>
</ol>
<h2 id="2023年11月27日">2023年11月27日</h2>
<blockquote>
<p>All software used to create and store the backups should be free and open source so I&rsquo;m not depending on the survival of a company.</p>
</blockquote>
<p>开源且免费的项目能有更长的生存时间吗？可能，大不了我就自己来维护。</p>
<h2 id="2023年12月1日">2023年12月1日</h2>
<p>很和谐的一个issue。</p>
<p><a href="https://github.com/Leopard-C/BiliUserSpider/issues/1"  target="_blank" rel="noopener" >报错：xmake时Server/Client 致命错误 · Issue #1 · Leopard-C/BiliUserSpider</a></p>
<p>面对小白的提问，作者很耐心教，甚至还特地录了个视频。</p>
<p>小白也很认真去学，最后还整理了份教程来帮助之后的人。</p>
<p>两人来回交流了10天左右，累计一百多个comment。</p>
<p>要是每个issue下都这样该多好。</p>
<h2 id="2023年12月14日">2023年12月14日</h2>
<p>做了一个课堂汇报，存档于<a href="https://ds63.eu.org/long-may-the-free-software/"  target="_blank" rel="noopener" >Long May the Free Software | EuDs&rsquo;s Blog</a></p>
<h2 id="2024年3月29日">2024年3月29日</h2>
<p><a href="https://en.wikipedia.org/wiki/XZ_Utils_backdoor"  target="_blank" rel="noopener" >XZ Utils backdoor - Wikipedia</a></p>
<h2 id="2024年8月10日">2024年8月10日</h2>
<p>今天做了件关于开源的好事,记录在<a href="https://ds63.eu.org/2024/happy_to_help_others/"  target="_blank" rel="noopener" >记一次助人为乐 | EuDs&rsquo;s Blog</a>。</p>
<h2 id="2024年8月9日">2024年8月9日</h2>
<p>今天推上热议一件事，小红书有个人提了个pr，给文档加了个换行。然后被某些“开源警察”追到PR下面喷占用维护者精力。</p>
<p>很巧的是，今天我正好提了个fix typo的pr。</p>
<p>具体来说，是偶然刷到了<a href="https://github.com/tmg0/hero-motion"  target="_blank" rel="noopener" >tmg0/hero-motion: 🌊 A shared layout animation tool for vue like framer motion.</a>，看它文档时发现个typo，顺手发了个<a href="https://github.com/tmg0/hero-motion/pull/151"  target="_blank" rel="noopener" >Fix a typo in README.md by EuDs63 · Pull Request #151 · tmg0/hero-motion</a>。</p>
<p>我提之前也犹豫了下，因为这改动只是一个字母，可能就会像那些评论说的，浪费他人的精力。</p>
<p>不过我这个pr很快就被合并，还收到了作者的感谢。</p>
<p>我感谢这位作者，ta鼓励了我。</p>
<h2 id="2024年8月21日">2024年8月21日</h2>
<p>看<a href="https://www.tisonkun.org/2024/08/09/rust-lang-acp/"  target="_blank" rel="noopener" >从参与 Rust 标准库开发看开源贡献的源动力 | 夜天之书</a></p>
<blockquote>
<p>开发者的需求是开源贡献的源动力。一旦一个开源软件不再产生新需求，那么它就会自然进入仅维护状态；而一旦一个开源软件不再能够满足开发者实际的需求，甚至开发者连直接修改代码的意愿也没有，那么它的生命也就到此为止了。</p>
</blockquote>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://juejin.cn/post/7272735633458413602"  target="_blank" rel="noopener" >开源富文本编辑器 wangEditor 暂停维护 （但仍可继续使用） - 掘金</a></li>
<li><a href="https://www.eaimty.com/2023/opensource-project-based-on-hormone/"  target="_blank" rel="noopener" >基于荷尔蒙开发的开源项目 - EAimTY&rsquo;s Blog</a></li>
<li><a href="https://tw93.fun/2023-09-18/open.html"  target="_blank" rel="noopener" >该以一种怎么样的心态来对待开源 - Tw93</a></li>
<li><a href="https://pragdave.me/thoughts/active/2023-09-21-in-praise-of-maintainers.html"  target="_blank" rel="noopener" >pragdave - In Praise of Maintainers</a></li>
<li><a href="https://www.bostonreview.net/articles/what-does-that-server-really-serve/"  target="_blank" rel="noopener" >What Does That Server Really Serve? - Boston Review</a></li>
<li><a href="https://mp.weixin.qq.com/s/eClrpJBMgwlZOajybFKItA"  target="_blank" rel="noopener" >夜天之书 #89 Rust 社群何以走到今天？</a></li>
<li><a href="https://www.gnu.org/philosophy/open-source-misses-the-point.html"  target="_blank" rel="noopener" >为什么开源错失了自由软件的重点 - GNU 工程 - 自由软件基金会(FSF)</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>5月8日梦的扩写</title>
      <link>https://ds63.eu.org/2023/expansion-of-the-dream-in-may-8/</link>
      <pubDate>Sat, 04 Nov 2023 14:43:20 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/expansion-of-the-dream-in-may-8/</guid>
      <description>值得记录的一天</description>
      <content:encoded><![CDATA[<h2 id="背景">背景</h2>
<p>2023年5月8日的清晨，我做了一个梦，意外的是，醒来后还记得不少细节，于是记下了这个梦涉及到的设定。</p>
<h2 id="梦的设定">梦的设定</h2>
<p>基础设定是：</p>
<ul>
<li>未来，但不远，大概几十年左右（从科技上感知到的）</li>
<li>国家的概念似乎模糊了，取而代之的是公司。超大型公司。</li>
<li>美国人，或者说美国公司追杀在美华人。</li>
<li>这场屠杀事发突然，过了几个月有余，才因几家公司的抗议而规模减小。但只是将华人分为了两部分，其中一少部分可以说是荣耀美国人，免于追杀。</li>
</ul>
<p>视角主要是聚焦在一家人上。</p>
<p>这个家还是蛮大的。家里已经有人遇难。有几个场景我记得比较清楚：</p>
<ul>
<li>爷孙两人藏匿一切可能被当作证据的东西,没多久就被搜查。</li>
<li>三个女的在劝说一个男的帮助她们。这个男的不是华人，但他的配偶是。男的和这三个女的是亲戚关系。</li>
<li>一个人在逃离美国。</li>
</ul>
<h2 id="ai的扩写">ai的扩写</h2>
<p>我拜托new bing对我的梦进行扩写，写出来的东西蛮有意思的，决定公布出来。</p>
<p><strong>声明：著作权属于new bing</strong></p>
<p><em>以下为原文：</em></p>
<p>爷孙两人藏匿一切可能被当作证据的东西。然后被搜查。</p>
<p>爷爷和孙子住在一个破旧的公寓里，他们把所有有中文标志的物品都藏在地板下面的一个密室里，包括书籍、照片、护照、信件等。他们还把自己的手机和电脑都销毁了，以防被追踪或监听。他们只留下了一些必需品，如食物、水、衣服等。他们每天都尽量不出门，以免引起怀疑。</p>
<p>有一天，他们听到门外有敲门声，他们打开窥视孔，发现是几个穿着制服的人，手里拿着枪和搜查令。他们心里一惊，赶紧把门锁上，想找个地方躲起来。但是那些人很快就用撬棍把门撬开了，冲了进来。他们大喊：“不要动！我们是美国国家安全局的特工！你们是华人间谍吗？快点交出你们的证据！”</p>
<p>爷爷和孙子被吓得不敢动弹，只能举起双手投降。那些特工开始在屋子里搜查，把所有的东西都翻个遍。他们发现了一些智能眼镜、无线充电器、3D打印机等未来科技，以为是华人公司的秘密武器，就拿走了。他们还发现了一些中文书籍和信件，就用语音助手进行翻译，发现是爷爷和孙子的亲戚写给他们的关心问候。他们觉得这些都是华人间谍的暗号，就把它们也带走了。</p>
<p>最后，他们把爷爷和孙子带上了一辆黑色的汽车，准备带回总部审讯。爷爷和孙子只能无奈地跟着走，不知道自己的命运会如何。</p>
<p>三个女的在劝说一个男的帮助她们。这个男的不是华人，但他的配偶是。男的和这三个女的是亲戚关系。</p>
<p>这三个女的是姐妹，她们分别叫做王梅、王兰、王菊。她们在美国出生长大，但她们的父母都是从中国移民过来的。她们从小就受到了中华文化的熏陶，对自己的祖国有着深厚的感情。她们也很聪明能干，在各自的领域都有着不错的成就。
王梅是一名医生，她在一家大型医院工作，专门负责治疗新冠肺炎患者。她经常冒着生命危险，为了救治更多的人而不顾自己的安危。她的丈夫是一个美国人，叫做迈克尔。他是一名律师，也是一个人权活动家。他对王梅非常爱护，支持她的工作，并且尊重她的文化背景。</p>
<p>王兰是一名教授，她在一所著名的大学教授物理学，研究量子计算和脑机接口等前沿领域。她有着惊人的创造力和才华，曾经发表过多篇引起轰动的论文，被誉为未来科技的领军人物。她的丈夫是一个中国人，叫做李明。他是一名工程师，也是王兰的同事和合作伙伴。他对王兰非常尊敬，鼓励她的研究，并且帮助她解决各种问题。</p>
<p>王菊是一名艺术家，她擅长用3D打印和VR/AR等技术创作出惊艳的作品，融合了中西方的美学和文化。她的作品曾经在多个国际展览中展出，受到了广泛的赞誉和关注。她的丈夫是一个法国人，叫做皮埃尔。他是一名画家，也是王菊的灵感来源和艺术伙伴。他对王菊非常痴情，欣赏她的才华，并且陪伴她走遍世界。</p>
<p>这三个女的现在都面临着生死危机，因为美国政府下令追捕所有华人，并且没收他们的财产和技术。他们被认为是中国政府派来的间谍或者威胁，必须被消灭或者驱逐出境。他们的丈夫也受到了牵连，被视为同谋或者叛徒。他们只能躲藏在各自的住所里，等待救援或者逃亡。</p>
<p>她们唯一的希望就是她们的表哥，叫做约翰。他是一个美国人，但他的母亲是王梅、王兰、王菊的姑姑。他从小就和这三个表妹很亲近，对她们有着深厚的感情。他是一名记者，曾经揭露过美国政府和公司的许多黑幕和阴谋。他对美国政府追杀华人的行为非常愤怒和不满，认为这是一种种族歧视和暴政。</p>
<p>她们给约翰打电话，求他帮助她们逃离美国，或者找到一个安全的地方藏身。约翰很犹豫，因为他知道这样做会让他陷入极大的危险，甚至可能丧命。他也担心他的妻子和孩子，他不想让他们受到伤害或者失去他。但是他也不能忍心看着自己的表妹们遭受不公正的对待，甚至被杀害。他觉得自己有责任保护她们，就像她们小时候一样。</p>
<p>他最终决定帮助她们，他利用自己的记者身份，联系了一些反对美国政府的组织和人士，寻求他们的支持和帮助。他还用自己的影响力，向全世界揭露了美国政府追杀华人的真相和罪行，呼吁国际社会和公众给予关注和制止。他还设法搞到了一些假身份证和护照，以及一些现金和武器，准备带着表妹们逃往加拿大或者墨西哥。</p>
<p>但是他的行动很快就被美国政府发现了，他被列为通缉犯，被追捕和通缉。他不得不放弃自己的家庭和工作，隐姓埋名地四处流浪。他先后去了王梅、王兰、王菊的住处，把她们接走，并且告诉她们的丈夫要小心保护自己。</p>
<p>他带着她们开车前往边境，一路上遇到了许多危险和困难。有时候他们要躲避警察的追捕，有时候要应付路上的暴徒和歹徒，有时候要忍受饥饿和寒冷。但是他们也收获了许多感动和温暖，有时候他们会遇到一些同情和支持他们的人，给予他们食物、住处或者信息。有时候他们也会看到一些美丽和神奇的风景和事物，让他们感受到生命的意义和价值。</p>
<p>他们最终到达了加拿大的边境，但是发现那里已经被美国政府的军队和特工封锁了，不让任何人进出。他们只能想办法穿越边境，但是这非常危险和困难。他们找到了一个偷渡的中间人，他答应帮助他们过境，但是要收取高昂的费用，并且不能保证安全。他们没有别的选择，只能答应他的条件，跟着他上了一辆货车，藏在一些箱子里。</p>
<p>货车开了一会儿，就被边境检查站拦住了。他们听到有人敲打箱子，问里面有没有人。他们紧张地屏住呼吸，不敢出声。他们听到中间人和检查人员说话，声音很小，听不清楚。他们只能祈祷自己不要被发现，能够顺利过关。</p>
<p>突然，他们听到一声枪响，然后是一阵乱哄哄的声音。他们不知道发生了什么事，只觉得车子猛地加速，然后又急刹车。他们被箱子里的东西砸得头破血流，疼得要命。他们想要出来看看情况，但是箱子被锁住了，打不开。他们只能呼救，希望有人能听到。</p>
<p>过了一会儿，他们听到有人打开箱子的声音。他们以为是中间人或者检查人员来救他们了，就高兴地喊道：“谢谢你！我们是无辜的！请帮助我们！”但是当他们看到打开箱子的人时，却惊呆了。那不是中间人或者检查人员，而是约翰。他手里拿着一把枪，脸上满是血迹和汗水。他对她们说：“快点下车！我们要走！这里已经不安全了！”</p>
<p>她们不明白发生了什么，但是看到约翰的样子，就知道情况很危急。她们赶紧从箱子里爬出来，跟着约翰下了车。她们看到车外一片混乱，有些人在射击，有些人在逃跑，有些人在倒地。她们不知道是谁在攻击他们，是美国政府的人还是其他的敌人。她们只能跟着约翰跑，希望能找到一个安全的地方。</p>
<p>约翰带着她们跑到了一个小树林里，藏在了一些灌木丛后面。他对她们说：“对不起，我没有想到会这样。我本来想用我的记者身份混进边境检查站，然后找到你们的车，把你们带出去。但是我被发现了，他们知道我是通缉犯，就开始射击。我只好还击，然后抢了一辆车，开过来救你们。”</p>
<p>她们听了约翰的话，都很感动和惊讶。她们说：“谢谢你，约翰。你为我们做了这么多，冒了这么大的风险。你真是太勇敢了。”约翰说：“不用谢，你们是我的家人。我不能让你们受苦。我们现在要赶紧离开这里，找到一个能过境的地方。”</p>
<p>她们问：“那我们怎么走？我们没有车，也没有钱，也没有护照。”约翰说：“我有一个办法。我之前联系过一个组织，他们是反对美国政府的游击队。他们有一个秘密的隧道，可以通往加拿大。他们答应帮助我们过境，只要我们给他们一些信息和技术。”</p>
<p>她们问：“什么信息和技术？”约翰说：“就是你们的专业领域的信息和技术。比如王梅的医学知识和新冠肺炎治疗方法，王兰的物理学知识和量子计算和脑机接口技术，王菊的艺术知识和3D打印和VR/AR技术。他们说这些都是对他们有用的东西。”</p>
<p>她们问：“那他们会不会利用这些信息和技术做坏事？”约翰说：“我不知道。但是我们没有别的选择了。如果我们不答应他们，我们就没法过境。而且他们也不是坏人，他们只是想反抗美国政府的暴政。”</p>
<p>她们沉默了一会儿，然后点了点头。她们说：“好吧，我们答应他们。只要我们能活着离开这里。”约翰说：“好，那我们赶紧走吧。隧道就在前面不远处。”</p>
<p>他们小心翼翼地穿过树林，避开了一些巡逻的士兵和直升机。他们来到了一个废弃的仓库，约翰敲了敲门，说了一个暗号。门被打开了，一个戴着面具的人出现在门口，对他们说：“你们是约翰带来的吗？快进来吧。”</p>
<p>他们跟着那个人进了仓库，发现里面有很多人，都是一些身穿迷彩服，手持武器的游击队员。他们看到了一些电脑和通讯设备，还有一些地图和文件。他们感觉到了一股紧张和危险的气氛。</p>
<p>那个人带着他们来到了一个办公室，里面有一个坐在椅子上的人，也是戴着面具。他对他们说：“你们好，我是这个组织的领导者，你们可以叫我老大。我知道你们的情况，我愿意帮助你们过境，但是你们也要给我一些东西。”</p>
<p>约翰说：“老大，我们已经答应了你的条件。我们会给你我们的信息和技术，只要你能保证我们安全到达加拿大。”老大说：“好，那么你们就把你们的信息和技术告诉我吧。我会让我的人记录下来，并且验证其真实性和有效性。如果没有问题，我就会让你们通过隧道离开。”</p>
<p>王梅、王兰、王菊都觉得有些不安，但是她们也没有办法。她们只能按照老大的要求，把她们的专业知识和技术详细地讲述给他听。老大听得很认真，不时地点头或者提问。他让他的手下用电脑记录下来，并且用一些软件和设备进行分析和测试。</p>
<p>过了一段时间，老大说：“好了，我已经得到了你们的信息和技术。我很满意。你们可以走了。”约翰说：“谢谢你，老大。那么隧道在哪里？”老大说：“隧道就在后面的一个房间里。你们跟着我来吧。”</p>
<p>他们跟着老大来到了后面的一个房间，发现里面有一个大铁门，上面有一个密码锁。老大输入了一个密码，铁门打开了，露出了一个黑洞洞的隧道。老大说：“这就是隧道。它是我们用一些先进的设备挖掘出来的，可以直接通往加拿大的一座小镇。你们只要沿着隧道走，就可以到达那里。那里有我们的人等着你们，会给你们一些新的身份和钱，让你们开始新的生活。”</p>
<p>约翰说：“谢谢你，老大。你真是个好人。”老大说：“不用谢。我只是做了我应该做的事。我也是为了反抗美国政府的暴政，保护我们的同胞和朋友。我希望你们在加拿大能够过得幸福和安全。”</p>
<p>王梅、王兰、王菊也感谢了老大，然后跟着约翰走进了隧道。老大对他们挥了挥手，说：“再见，祝你们好运。”然后关上了铁门，重新输入了密码，锁住了隧道。</p>
<p>他们走在隧道里，感觉很黑暗和潮湿。他们只能靠着隧道里的一些灯光和指示牌来辨认方向。他们不知道隧道有多长，也不知道会不会有什么危险。他们只能相互鼓励和安慰，希望能够早点到达目的地。</p>
<p>过了很久很久，他们终于看到了隧道的尽头，有一道光线从那里透过来。他们兴奋地跑了过去，发现那里也有一个铁门，上面有一个摄像头和一个对讲机。约翰按了按对讲机上的按钮，说：“喂，我们是约翰带来的华人。请开门吧。”</p>
<p>对讲机里传来了一个声音，说：“你好，约翰。我们已经等你们很久了。请稍等一下，我们马上开门。”然后铁门打开了，他们看到了一些穿着便服的人站在门口，微笑着向他们招手。他们说：“欢迎来到加拿大。你们终于安全了。”</p>
<p>他们走出了铁门，感受到了阳光和空气。他们看到了一些绿色的树木和草地，还有一些小房子和商店。他们觉得这里很美丽和宁静，就像一个天堂。他们被那些人带到了一辆车上，车上有一些新的身份证和护照，还有一些加拿大元。他们说：“这些都是给你们的。你们可以用这些开始新的生活。我们会帮助你们找到一个合适的地方住下，然后你们可以自由地做你们想做的事。”</p>
<p>约翰说：“谢谢你们，你们真是太好了。”他们说：“不用谢。我们只是做了我们应该做的事。我们也是反对美国政府的暴政，支持华人的权利和尊严。我们希望你们在加拿大能够过得幸福和安全。”</p>
<p>王梅、王兰、王菊也感谢了他们，然后拥抱了约翰。她们说：“谢谢你，约翰。你为我们做了这么多，冒了这么大的风险。你真是个英雄。”约翰说：“不用谢。你们是我的家人。我爱你们。”</p>
<p>他们坐上了车，车子开走了。他们望着窗外的风景，感觉很轻松和开心。他们觉得自己终于摆脱了恐惧和压迫，找到了自由和希望。他们相信自己在加拿大能够重建自己的生活，实现自己的梦想。</p>
<p>故事结束。</p>
<h2 id="故事的标题">故事的标题</h2>
<p>它对这个故事起了几个标题：</p>
<ul>
<li>《逃离美国》</li>
<li>《隧道之光》</li>
<li>《华人的希望》</li>
<li>《亲情与自由》</li>
<li>《隐形的华人》</li>
<li>《逆境中的英雄》</li>
</ul>
<h2 id="我的想法">我的想法</h2>
<ul>
<li>第一次让ai来给我的梦做扩写。虽然文笔不咋的。但让我来写我应该达不到这个水平。</li>
<li>文中存在着几个槽点，我自己看着蛮乐的。</li>
<li>这个梦对我来说也很意外，思考了下为什么会做这个梦：
<ul>
<li>《美国末日》第一集有个场景让我印象很深。士兵在上级命令下击杀请求避难的平民。</li>
</ul>
</li>
</ul>
<h2 id="尾巴">尾巴</h2>
<p><img loading="lazy" src="/2023/expansion-of-the-dream-in-may-8/2023-05-08-13-23-59.png" type="" alt="回应"  /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>创意</title>
      <link>https://ds63.eu.org/2023/my_eureka/</link>
      <pubDate>Sat, 04 Nov 2023 14:43:20 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/my_eureka/</guid>
      <description>eureka or todo</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>这一篇主要是记录我的说不定可以用来好好研究，做些项目的想法。我小时候发现：要取得一些成就，尤其是科研上的，往往得想到别人没想过的。当时的我经过苦苦的思索，发现自己能想的到的东西别人大多已经想过了,只能悲叹自己无法成为科学家了。</p>
<p>那时候是受限于视野和知识。而单论视野和知识，今天的我比自己小时候当然要强，但未必能强上多少。能想到别人未能想之事，也不是常有的。更进一步地说，能想到并有其实际价值，那更是少见。这么宝贵的东西，不记录下可惜了。</p>
<h2 id="补充">补充</h2>
<p>近年来，我“发现”了一个更不好也更好的事实：凡是我能想到的主意，在网上搜下，往往能找到已经实现的，甚至实现的很好的。如果找不到，那也可能是自己用错了关键字或者没搜对地方。（很显然，这个“发现”绝非是我的首创）</p>
<p>不过我倒没有因此而气馁，因为在看了<a href="https://jacobian.org/2021/apr/7/embrace-the-grind/"  target="_blank" rel="noopener" >Embrace the Grind - Jacob Kaplan-Moss</a>后,我有新的收获。就如文中所说：<code>Magic is mundane. If you’re willing to embrace the grind, you can pull off the impossible.</code>，我并不需要多能奇思妙想，也不需要多天才，只要能想到，并能将其实现，那就是件好事。</p>
<p>于是，如若我能遇到当时悲叹自己无法成为科学家的小时候的我，我还这样安慰他：即使你做的事无法成为开创性的，但还是能让自己开心，对外界稍微能有点用的。</p>
<hr>
<h2 id="摄影截图">摄影/截图</h2>
<ul>
<li>时间：2023年1月2日</li>
<li>想法：基于ar设施，实现在空中划一道圈，将圈里的东西截下来。类似于截图。</li>
</ul>
<h2 id="开篇广告定制">开篇广告定制</h2>
<ul>
<li>
<p>时间：2023年1月2日</p>
</li>
<li>
<p>想法：各大软件的开屏广告几乎是每天所必见的。通过权力，金钱或技术的方式，将广告定制为自己想要的内容。</p>
</li>
<li>
<p>可行性分析：</p>
<p>权力和金钱方面距离我有点太远，而且是已被实现的东西，技术方面暂且没见过。将范围缩小，不要求所有人的开屏广告都被改变，特定的某个人的就行。这样难度就减少许多。我记得有软件可以用来跳过开屏广告，既然能跳过，那改变其内容可不可以呢？</p>
</li>
</ul>
<hr>
<h2 id="浏览器访问本地文件">浏览器访问本地文件</h2>
<ul>
<li>时间： 2023年2月15日</li>
<li>想法： 我发现edge浏览器支持对本地文件的访问，看了下源码，发现这个我自己应该也能写。</li>
<li>补充： 不仅是本地文件，wsl里的文件也可以：<code>file://wsl.localhost/Ubuntu/</code></li>
<li>可行性分析：我可以添加些前端代码，来让这个功能更实用，更好看。</li>
</ul>
<hr>
<h2 id="rss订阅">RSS订阅</h2>
<ul>
<li>时间： 2023年2月15日</li>
<li>想法： 我喜欢看博客，但有些博客，尤其是国外的，不支持RSS订阅，我发现<a href="https://github.com/DIYgod/RSSHub"  target="_blank" rel="noopener" >RSShub</a>可以帮我实现这一点，但好像有点繁琐，我可不可以简化下。</li>
<li>可行性分析：我还没有好好看它的文档，过两周有时间再好好研究下。</li>
</ul>
<hr>
<h2 id="热力图">热力图</h2>
<ul>
<li>时间： 2023年2月17日</li>
<li>想法： 看到<a href="https://github.com/yihong0618/running_page"  target="_blank" rel="noopener" >running_page</a>这个项目，它的一大亮点是热力图，想着能不能把其他东西也做成热力图，比如说我的睡眠记录。</li>
<li>可行性分析：数据的导出要怎么实现呢？项目是怎么做的呢？</li>
</ul>
<hr>
<h2 id="记录工具">记录工具</h2>
<ul>
<li>时间： 2023年2月30日</li>
<li>想法:  我几乎每天都是在食堂吃，但食堂有点吃腻了。想分析我每天都吃了什么</li>
<li>可行性分析： 有两种方法：
<ul>
<li>一种是每天手动记录。可以通过开发一个app来实现。对食物拍张照，就自动记录我点了些什么。感觉有点难度。但食堂，菜不怎么更新，数据量不是很大吧。</li>
<li>另一种是：通过获取我的消费记录来进行分析。虽然只能粗浅地知道我在哪些窗口消费得比较多。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="telegrambot">telegrambot</h2>
<ul>
<li>时间： 2023年2月21日</li>
<li>想法： 现在在写创意，或者日记的时候，我都需要打开vscode，找到相应的文件，然后输入。这多少有点麻烦。我能不能用telegrambot或者是GitHub action，来实现这样一个功能，我发送关键词+内容，然后就自动帮我写入</li>
<li>可行性分析： 感觉还是可以实现的，留给以后的我来实现</li>
</ul>
<hr>
<h2 id="穿衣建议">穿衣建议</h2>
<ul>
<li>时间： 2023年3月19日</li>
<li>想法： 出去骑车之前，总得花好些时间想穿什么。这很费劲,因为要考虑到温度，骑车时会出汗，但又要注意晚上回来的时候的保暖问题。现在的想法就是：把自己的衣服根据厚薄、透气程度进行数据化，存到一个数据库中。再加上对历史出行穿搭的记录，做一个程序，以后要出门的时候，这个程序就能作出建议，甚至可以和智能家居进行联动，把衣服放到衣柜的最前面之类的。</li>
<li>可行性分析：这个跟<a href="#%e8%ae%b0%e5%bd%95%e5%b7%a5%e5%85%b7" >前面那条</a>蛮类似的。做数据的时候有点麻烦，然后建议的话可以用LLM来做，添加合适的prompt应该可行。</li>
<li>追加：一年过去了，我还是没搞出来，但是觉得很可行，真得试试。</li>
</ul>
<hr>
<h2 id="运转记录">运转记录</h2>
<ul>
<li>时间： 2023年3月27日</li>
<li>想法:  昨天我在复盘乘车记录的时候，尽管我已经在qq上有记录了，但还是费了些时间。就想开发一款软件，我只需要输入公交车号，就能帮我自动生成相关的路线。然后更进一步，在出现前可以规划运转路线，并比较方便地展现时刻表</li>
<li>可行性分析： 简单的记录工具应该不难，但就是路线图和公交的数据要怎么做，也许可以使用现成的api呢？</li>
</ul>
<hr>
<h2 id="rss自动维护">rss自动维护</h2>
<ul>
<li>时间： 2023年3月28日</li>
<li>想法:  在Github上开一个仓库来维护我的rss订阅列表，当我订阅新内容的时候可以自动更新，并生成md文件，来展示博客标题，博客地址，rss链接</li>
<li>可行性分析： 我现在是用的ttrss，如果它有相应的api接口，我想应该不是太难</li>
<li>实现情况：<a href="https://github.com/EuDs63/TinyTinyRSS-OPML-to-MD-Table"  target="_blank" rel="noopener" >TinyTinyRSS-OPML-to-MD-Table</a>已基本实现</li>
</ul>
<hr>
<h2 id="自动跳转插件">自动跳转插件</h2>
<ul>
<li>时间：2023年9月26日</li>
<li>想法：有些网站在跳转到外链时会有个跳转提示。我需要再点一次才行。有点影响我浏览网页时的连贯性.我想写一个插件，使得可以自动跳转。</li>
<li>可行性分析：逻辑上不难。主要是以前没写过插件。计划使用油猴脚本，并实现可下载。</li>
<li>实现情况：已实现，发现脚本内容太简单了，没必要发。</li>
<li>发现了一个别人已经写好的插件。<a href="https://greasyfork.org/zh-CN/scripts/412612-open-the-f-king-url-right-now/code"  target="_blank" rel="noopener" >Open the F**king URL Right Now - 源代码</a></li>
</ul>
<hr>
<h2 id="复制网页标题和地址">复制网页标题和地址</h2>
<ul>
<li>时间：2023年10月4日</li>
<li>想法：在写参考链接之类的内容时，我需要得到类似<a href="https://github.com/EuDs63/TinyTinyRSS-OPML-to-MD-Table"  target="_blank" rel="noopener" >TinyTinyRSS-OPML-to-MD-Table</a>的内容。这其实还是会花些时间的。我希望我能直接在网页上按个快捷键，然后我的剪贴板中就有相应格式的内容</li>
<li>可行性分析：应该能做，用脚本？</li>
<li>实现情况：已实现</li>
</ul>
<hr>
<h2 id="定时导出x关注列表">定时导出x关注列表</h2>
<ul>
<li>时间： 2023年10月6日</li>
<li>想法：我的x账号之前就被莫名的封禁，而数据也没能导出。导致我后面丢了好些曾经关注过的，也花了好些时间去找回。<a href="https://github.com/prinsss/export-twitter-following-list"  target="_blank" rel="noopener" >prinsss/export-twitter-following-list</a>是能解决。但是还需要我手动去做。我想实现一个像<a href="https://github.com/EuDs63/TinyTinyRSS-OPML-to-MD-Table"  target="_blank" rel="noopener" >EuDs63/TinyTinyRSS-OPML-to-MD-Table</a>一样，自动定时的导出并展示的功能。</li>
<li>可行性分析：怎么在程序中实现在浏览器中做的事？</li>
<li>今天（10月7日），花了半个小时研究了下，浏览器自动化操作可以使用<a href="https://www.selenium.dev/documentation/"  target="_blank" rel="noopener" >Selenium</a>或者<a href="https://gitee.com/g1879/DrissionPage"  target="_blank" rel="noopener" >DrissionPage</a>实现。但问题在于tweet无法在未登录情况下访问关注列表。登录的话可能又会涉及到人机认证。这个我目前做不来。除此之外似乎技术要求不高，所以搁置掉。</li>
<li>实现情况：放弃</li>
</ul>
<hr>
<h2 id="实现space-war">实现space war</h2>
<ul>
<li>时间：2023年10月7日</li>
<li>想法： 使用Rust，wasm，实现<a href="https://spacewar.oversigma.com/"  target="_blank" rel="noopener" >Spacewar!</a>，并部署至vercel</li>
<li>可行性分析：网上似乎有源码，但Rust版的应该没有。相关的技术栈我在<a href="https://lifegame.ds63.eu.org/"  target="_blank" rel="noopener" >Game of Life</a>已经有走通过一遍。似乎可行？</li>
<li>想法补充：因着之前的框架，我还可以实现一个数独</li>
<li>实现情况：未实现</li>
</ul>
<hr>
<h2 id="博客美化">博客美化</h2>
<ul>
<li>时间：2023年10月16日</li>
<li>想法：我博客用的主题有点烂大街了。打算自己改下。</li>
<li>可行性分析：网上资料应该蛮多的。打算自己改一个主题出来。</li>
<li>过程：
<ol>
<li><input checked="" disabled="" type="checkbox"> 添加<a href="https://www.jinrishici.com/doc/"  target="_blank" rel="noopener" >今日诗词</a></li>
<li>记录于<a href="https://ds63.eu.org/2023/%E5%8D%9A%E5%AE%A2%E8%BF%81%E7%A7%BB%E8%AE%B0/"  target="_blank" rel="noopener" >博客迁移记 | EuDs&rsquo;s Blog</a></li>
</ol>
</li>
<li>实现情况：已实现</li>
</ul>
<hr>
<h2 id="qqbot增强">qqBot增强</h2>
<ul>
<li>时间：2023年10月16日</li>
<li>想法：给bot写个插件，周易卜挂。</li>
<li>可行性分析：json文件在<a href="https://github.com/RealKai42/liu-yao-divining"  target="_blank" rel="noopener" >六爻算命游戏 + GPT（图一乐）</a>可以得到。其他的也很简单。</li>
<li>实现情况：放弃（过于简单，感觉没必要）</li>
</ul>
<hr>
<h2 id="简易版postman">简易版postman</h2>
<ul>
<li>时间：2023年11月12日</li>
<li>想法：postman的功能我其实并不都用得上。我可以使用Tauri自己写一个简易版的，只有核心功能。</li>
<li>可行性分析：应该可行。而且有利于我学习Rust和Tauri</li>
<li>实现情况： 基本实现，仍需完善。见<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid: A lightweight tool offering key functionalities inspired by Postman.</a></li>
</ul>
<hr>
<h2 id="vscode同步到xlog">vscode同步到xlog</h2>
<ul>
<li>时间：2023年11月15日</li>
<li>想法：xlog这个平台其实蛮好的。我也蛮常写博客，但我不习惯每次写完都去上面发布下文章。</li>
<li>可行性分析：<a href="https://github.com/Otto-J/sync-to-xlog"  target="_blank" rel="noopener" >Otto-J/sync-to-xlog: sync obsidian notes to xlog.app</a>已经实现了。理论上我只需要迁移到vscode就行。作者还写了篇文章，可供参考：<a href="https://blog.ijust.cc/play-xlog-02"  target="_blank" rel="noopener" >【技术角度折腾 xlog】更顺畅的使用体验 2 深入理解 xlog 的鉴权 - 辛宝Otto</a>。发现我没必要搞个插件，要action似乎就够了。</li>
</ul>
<hr>
<h2 id="去年今日">去年今日</h2>
<ul>
<li>时间：2023年12月5日</li>
<li>想法: 洗澡的时候想到。在Faye的每日问候，我可以加个新功能，让它告诉我去年今日我干了什么。</li>
<li>可行性分析: 我写日记已经有一年多了，所以数据是有的。我日记的格式都是统一的，按行查找我在其他项目中也有学习过了。所以实现起来应该难度不大。</li>
<li>实现情况: 准备动手的时候发现自己每天写日记的习惯是到下学期才养成的。一下子就没啥动力了，要不留给几个月的自己?</li>
</ul>
<hr>
<h2 id="博客编辑历史">博客编辑历史</h2>
<ul>
<li>时间：2023年12月18日</li>
<li>想法：我的博客现在可以根据git来获得最后一次更改时间。那能不能通过commit message来显示编辑历史呢。</li>
<li>可行性分析：似乎可行，但可能我得去读源码了。</li>
<li>实现情况：未实现</li>
</ul>
<hr>
<h2 id="两个文件夹间的同步">两个文件夹间的同步</h2>
<ul>
<li>时间：2023年12月19日</li>
<li>想法：我的<a href="https://github.com/EuDs63/EuDs63.github.io"  target="_blank" rel="noopener" >EuDs63/EuDs63.github.io: my blog</a>和<a href="https://github.com/EuDs63/myThinking"  target="_blank" rel="noopener" >EuDs63/myThinking: A record of my thoughts</a>内容是有重复的。如何保持这两个文件夹中重复的内容的一致性，我一直是靠手动解决，也许我可以写个定时执行的脚本？</li>
<li>可行性分析：我这两个放在GitHub上。也许我可以用Github action。检查的话就靠有没有特定的表头。<del>但这样每次花费的时间感觉还是要有一些的</del>。我每次只要看更改的文件是不是就好了。大概的思路可以是：当我向<a href="https://github.com/EuDs63/myThinking"  target="_blank" rel="noopener" >EuDs63/myThinking: A record of my thoughts</a>push的时候，这时候触发检查，检查本次push修改的文件中是否有特定的表头。如果有，那就推送给<a href="https://github.com/EuDs63/EuDs63.github.io"  target="_blank" rel="noopener" >EuDs63/EuDs63.github.io: my blog</a>。这样只要我保证，我每次想新增内容的时候，都是在mythingk这里先写就可以了。这样就能解决同步问题。</li>
<li>实现情况：<del>未实现</del> 已实现，见<a href="https://ds63.eu.org/2024/sync-specific-files-of-two-repo/"  target="_blank" rel="noopener" >Github同步两个仓库中的文件 | EuDs&rsquo;s Blog</a>。</li>
</ul>
<hr>
<h2 id="bangumi展示自评10分作品">bangumi展示自评10分作品</h2>
<ul>
<li>时间：2024年1月13日</li>
<li>想法：我评分为10分的作品对我来说都有某种特殊的意义。但让我一一列举，我又难想得出来，于是想获取，并展示在首页。</li>
<li>可行性分析：bangumi原生不支持显示已评分的作品的统计。但是它有提供api，要做起来很容易。我搜了下，似乎<a href="https://bgm.tv/dev/app/1250"  target="_blank" rel="noopener" >自动标签系统 | Bangumi 开发者平台</a>符合我的需求，但试了下，并不能加载出全部数据。用postman测试了下api，很可行，难度不高。但怎么持续更新，我没想好。</li>
<li>实现情况：<del>未实现</del> 已实现<a href="https://github.com/EuDs63/RANK2COLLECTION"  target="_blank" rel="noopener" >EuDs63/RANK2COLLECTION: 根据neodb、bangumi的评分记录，自动创建目录</a>，后续甚至考虑在此基础上做定期更新，不过一年或半年一次的话，好像手动也可以。</li>
</ul>
<hr>
<h2 id="开发rsshub路由">开发RSSHub路由</h2>
<ul>
<li>时间：2024年1月14日</li>
<li>想法：发现<a href="https://blogatlarge.com/list/"  target="_blank" rel="noopener" >入驻写作者 – Blog at Large</a>的内容蛮精彩的，但似乎Rsshub还不支持，于是想着自己开发个路由支持下。</li>
<li>可行性分析：可以参考<a href="https://akynazh.site/posts/2023/12/quickly-develop-an-rsshub-router/"  target="_blank" rel="noopener" >快速开发一个 RSSHub 路由 | Norwegian Wood</a></li>
<li>实现情况：<del>未实现</del> Rsshub已经支持了。</li>
</ul>
<hr>
<h2 id="博客插图片">博客插图片</h2>
<ul>
<li>时间：2024年1月16日</li>
<li>想法：昨天我第一次给博客加图片，感觉蛮麻烦的。想找下有没有快捷而又持续的方式。</li>
<li>可行性分析：我也不知道有没有，试试看吧</li>
<li>实现情况：未实现
看<a href="https://sarakale.top/blog/posts/10224"  target="_blank" rel="noopener" >使用npm作为图床备用 | SaraKale&rsquo;s blog</a>，感觉不太合适。
<a href="https://sarakale.top/blog/posts/53700"  target="_blank" rel="noopener" >最终还是考虑用服务器做图床了 | SaraKale&rsquo;s blog</a>，Backblaze + Cloudflare看着也蛮麻烦的。</li>
</ul>
<hr>
<h2 id="样式修改pr">样式修改pr</h2>
<ul>
<li>时间：2024年3月19日</li>
<li>想法：<a href="https://doc.xugaoyi.com/"  target="_blank" rel="noopener" >vuepress-theme-vdoing</a>的搜索框在页面缩小的情况下会挤在一起，不是很美观，想着修一下，也借此为开源做点贡献</li>
<li>可行性分析：很可行</li>
<li>实现情况：未实现</li>
</ul>
<hr>
<h2 id="链接参数查询">链接参数查询</h2>
<ul>
<li>时间：2024年3月21日</li>
<li>想法：好奇<a href="https://uid.ejfkdev.com/"  target="_blank" rel="noopener" >你分享的链接泄露隐私了吗？</a>是怎么实现的。貌似和<a href="https://zhuanlan.zhihu.com/p/137169138"  target="_blank" rel="noopener" >用UTM参数进行流量追踪完整指南（上） - 知乎</a>有关。</li>
</ul>
<hr>
<h2 id="web动画">web动画</h2>
<ul>
<li>时间：2024年3月31日</li>
<li>想法： 想学下web动画效果是怎么做的，参考<a href="https://github.com/tsparticles/tsparticles"  target="_blank" rel="noopener" >tsparticles/tsparticles: tsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.</a></li>
</ul>
<hr>
<h2 id="事件循环可视化">事件循环可视化</h2>
<ul>
<li>时间：2024年3月31日</li>
<li>想法：好奇<a href="https://www.jsv9000.app/"  target="_blank" rel="noopener" >JS Visualizer 9000</a>原理</li>
</ul>
<hr>
<h2 id="uml绘图">uml绘图</h2>
<ul>
<li>时间：2024年4月16日</li>
<li>想法：用鼠标去画uml图太麻烦了，应该有代码实现的。查了下发现<a href="https://github.com/plantuml/plantuml"  target="_blank" rel="noopener" >plantuml/plantuml: Generate diagrams from textual description</a>能满足我的需求。很自然地就想，我能不能给我的博客集成这个功能呢。看<a href="https://gohugo.io/content-management/diagrams/#complex"  target="_blank" rel="noopener" >Diagrams | Hugo</a>，现在的hugo貌似只支持mermaid。看<a href="https://github.com/gohugoio/hugo/issues/8398"  target="_blank" rel="noopener" >Add PlantUML rendering support &ndash; post-hugo processing · Issue #8398 · gohugoio/hugo</a>，似乎也没后续了？</li>
</ul>
<hr>
<h2 id="自动typo修复pr">自动typo修复pr</h2>
<ul>
<li>时间：2024年4月17日</li>
<li>想法：发现不少pr都只是修复了些typo。可以写个程序,爬取现有的仓库，检查是否有typo，并生成pr。为了防止被标记为机器人，我可以限制其每天的频率。记得之前看过一篇博客，博主是写了个程序，在某个依赖失效时，大规模提交了pr。</li>
<li>可行性分析：爬不难，发pr也不难，检查是否有typo，有这项技术，但得研究下。想到个取巧的方法，也许我可以通过爬取现有的，且已被merge的fix typo的pr，找到常见的错词，并进行匹配。</li>
</ul>
<hr>
<h2 id="自动添加rss">自动添加rss</h2>
<ul>
<li>时间：2024年4月17日</li>
<li>想法：发现有些蛮优秀的博客其实不支持rss，有没有什么办法能自动订阅呢。我知道rsshub可以，但它还是得有人去写路由。我希望能进一步简化这个过程。</li>
<li>可行性分析：我得先试试用rsshub写个路由</li>
</ul>
<hr>
<h2 id="加密通讯工具">加密通讯工具</h2>
<ul>
<li>时间：2024年6月4日</li>
<li>想法：写一个加密通信工具.,用来学习密码学和实时通讯，实用性不高，但应该会蛮有趣。</li>
<li>可行性分析： 可以参考<a href="https://jw1.dev/2022/12/18/a01/"  target="_blank" rel="noopener" >关于m42的技术细节</a></li>
</ul>
<hr>
<h2 id="游戏捏脸通用数据">游戏捏脸通用数据</h2>
<ul>
<li>
<p>时间：2024年6月11日</p>
</li>
<li>
<p>想法：如果一个游戏允许我捏脸，那么我至少会花十来分钟在上面。但存在着不少问题：</p>
<ol>
<li>比如说辐射4，费劲捏完脸后,进游戏发现时第一人称视角</li>
<li>再比如博得之门3，捏完主角后还得再捏个守护者，而且存档间似乎还不通用</li>
<li>不少游戏的捏脸自由度并不高，想捏得合自己心意得额外装mod</li>
<li>最终想捏出来的成品其实都差不多。比如我自己能选择的话,就会给自己的操纵角色选为女角色，取名叫Faye，白色短发</li>
</ol>
<p>综合上述情况，如果能实现一处捏脸，处处使用，那会很有意义。详细来说就是，我只需要捏一次脸，便可以在大部分主流游戏中直接使用。并且更进一步，还能创一个平台，供用户分享各自的捏脸数据。</p>
</li>
<li>
<p>可行性分析：一个游戏还好，但要做到适配主流游戏，并且最终操作方便快捷，很难。</p>
<p>一个难点是，如何让不同游戏的捏脸数据呈现出来视觉效果上类似的一张脸，可能AI能帮上忙？</p>
<p>再进一步，我写个Prompt,发张图片之类的，就能生成可供参考且使用的捏脸数据，这将比纯手搓来得更为方便。</p>
<p>市面上类似对接不同平台的hub这一思路的产品不少,如对接不同云盘的Infuse、VidHub,对接不同大模型产品的更是数不胜数。说不定未来会有呢?</p>
</li>
</ul>
<hr>
<h2 id="贴吧存档">贴吧存档</h2>
<ul>
<li>时间：2024年7月8日</li>
<li>想法：贴吧上还是有些帖子值得保存的。把它们保存下来会挺有意义的。虽然我的<a href="https://github.com/EuDs63/Tieba_Memory"  target="_blank" rel="noopener" >EuDs63/Tieba_Memory</a>已经能做到了，但我还是嫌麻烦。能不能做成个服务。我发给机器人链接，或者是做成个网站，输入链接就生成pdf呢</li>
<li>可行性分析：
<ul>
<li>前者不难做，后者如果能做成webassembly的纯前端的话，那么部署成本应该不高。</li>
<li>查了下python to wasm 的资料，发现<a href="https://github.com/pyodide/pyodide"  target="_blank" rel="noopener" >pyodide/pyodide</a>似乎能用</li>
</ul>
</li>
</ul>
<hr>
<h2 id="自动发推">自动发推</h2>
<ul>
<li>时间: 2024年9月1日</li>
<li>想法：发现推特有免费的api，每个月1500条，很够用了。读的api会比较贵，一条要0.01美元，不过我暂时也不需要。这一千五百条能拿来干啥？我目前有两个想法，博客更新后自动发布，mastodon备份。</li>
<li>可行性分析
<ul>
<li>前者我的Github Action已经能做到检测是否有更新了，那就只差接入api，不难</li>
<li>后者我得找找mastodon有没有api，或者可以写个插件，当我在mastodon发嘟的时候捕捉到内容，并发送。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="自动rss订阅链接生成">自动rss订阅链接生成</h2>
<ul>
<li>时间: 2024年9月2日</li>
<li>想法：逛博客的时候还是能发现不少博客没有rss链接的，虽然<a href="https://github.com/DIYgod/RSSHub-Radar"  target="_blank" rel="noopener" >DIYgod/RSSHub-Radar: 🧡 Browser extension that simplifies finding and subscribing RSS and RSSHub</a>能够嗅探，但奈何有些博客就是没有。如果能写一个一键生成rss订阅链接的就好了。</li>
<li>可行性分析：
<ul>
<li>没啥思路，我先得知道怎么给RssHub添加一个新路由。</li>
</ul>
</li>
<li>ps: 写完后翻前面的我才发现2024年4月17日我就有一样的想法了，甚至结论都是一样的。说明这确实是我一大需求，但是小半年过去了，我还没动手&hellip;</li>
</ul>
<hr>
<h2 id="爬虫练习">爬虫练习</h2>
<ul>
<li>时间: 2024年11月14日</li>
<li>想法: <a href="https://twbangga.moe.edu.tw/classification"  target="_blank" rel="noopener" >教育部臺灣台語動畫|網站介紹</a>提供了对部分日本动画的台语配音，质量很不错。出于收藏的目的，我想下载下来。</li>
<li>可行性分析:
<ul>
<li>出于版权考虑，它仅限于台湾地区能看。是靠检查ip，检查后将地区存在localstorage，key为<code>isCountry</code>，值就是Hk或者Taiwan，看着很搞笑。但修改它没用，因为再次点击的时候还是会检查。最简单的方法还是靠换个当地的代理节点。</li>
<li>视频爬取，<a href="https://nicelee.top/blog/2019/03/02/java-spider-bilibili-down-index/"  target="_blank" rel="noopener" >Java 爬虫练习-bilibili视频下载 索引</a>写得很好，把下载b站视频的过程循序渐进的给讲明白了。我一个多月前看完就想自己试试，这下有机会了。</li>
</ul>
</li>
<li>实现情况: 已实现,见<a href="https://github.com/EuDs63/TwbanggaDownload"  target="_blank" rel="noopener" >EuDs63/TwbanggaDownload</a></li>
</ul>
<hr>
<h2 id="b站评论分析">B站评论分析</h2>
<ul>
<li>时间: 2024年11月15日</li>
<li>想法: 我很不爽b站的一点是它不提供历史评论，我翻不到自己过去在哪，回复了什么内容。我希望自己能获取到自己的历史评论。并进行一定的分析。</li>
<li>可行性分析:
<ul>
<li>发现<a href="https://www.aicu.cc/reply"  target="_blank" rel="noopener" >查评论</a>可以查。我可以通过它获取到历史评论信息。</li>
<li>我可以参照<a href="https://github.com/EuDs63/Tieba_Memory"  target="_blank" rel="noopener" >EuDs63/Tieba_Memory: 导出百度贴吧个人回复记录，并进行简单的数据分析</a>写个bili_memory，处理下数据就能用。</li>
<li>我还可以写个bot插件,用来查成分。</li>
</ul>
</li>
<li>实现情况: 已实现,见<a href="https://github.com/EuDs63/BiliBili_Memory"  target="_blank" rel="noopener" >EuDs63/BiliBili_Memory: 导出B站个人评论记录，并进行简单的数据分析</a></li>
</ul>
<hr>
<h2 id="steam消费统计">Steam消费统计</h2>
<ul>
<li>时间: 2025年1月2日</li>
<li>想法: 某日被问到自己花了多少钱买游戏。好问题,我也想知道。</li>
<li>可行性分析:
<ul>
<li>我用过的买游戏的方式太多了,包括但不限于杉果、小黑盒、SteamPy、充值卡、买的余额、自己倒的余额，直接买的。时间跨度太大，也太琐碎。退而求其次，就先统计Steam上的消费历史记录。</li>
<li>可以参考<a href="https://greasyfork.org/zh-CN/scripts/463576-buff%E8%B4%AD%E4%B9%B0%E8%AE%B0%E5%BD%95%E6%80%BB%E4%BB%B7%E8%AE%A1%E7%AE%97"  target="_blank" rel="noopener" >Buff购买记录总价计算</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="ai取名">AI取名</h2>
<ul>
<li>时间: 2025年2月3日</li>
<li>想法: 某日聊天玩梗，说看到xxx的时候，连孩子叫啥都想好了。被问到叫啥，还真没想好。取个名是真不容易，于是想到了AI。虽不能决策，参考下总是不错。那就做个AI取名的网站吧。至少得有这几个功能吧：
<ol>
<li>姓的输入</li>
<li>寓意，期望的输入</li>
<li>输出时显示名字的寓意，以及名字可能的重名情况</li>
</ol>
</li>
<li>可行性分析:
<ul>
<li>得益于llm的强大,网站实现起来不难,但要做好不容易。因为我觉得这网站最大的一个问题是，网站的意义？用户为啥不直接跟llm聊，而是用你这个网站。目前我没想好，更好的用户体验？不用自己输复杂的prompt？</li>
<li>姓名的重名情况，我之前有用过类似的服务，但不知道有没有合法的api让我使用。</li>
<li>如何尽可能地不被prompt 注入攻击，也是一个问题。 姓的话可以做规则过滤，毕竟姓是有限的，但寓意呢，因为需要允许用户输入他的期望。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="ai群友">AI群友</h2>
<ul>
<li>时间: 2025年2月4日</li>
<li>想法: 小群里的一位群友因故无法发言，大家都挺想ta的。在得到其授权的前提下，想着用ai模仿一个出来，以表怀念。</li>
<li>可行性分析:
<ul>
<li>给llm喂聊天记录等资料，来训练出一个说法风格类似，甚至逻辑有一定相似的bot，并不算什么新鲜事。至少挺早之前<a href="https://x.com/ljsabc"  target="_blank" rel="noopener" >李萌萌 (@ljsabc) / X</a>就做过。</li>
<li>难点在于语料。如何导出并解析qq聊天记录，并进行清洗，训练？</li>
</ul>
</li>
</ul>
<hr>
<h2 id="一键投诉">一键投诉</h2>
<ul>
<li>时间: 2025年5月22日</li>
<li>想法: 刷贴吧刷到115吧，115好像有个活动，返利五百块，话说出去了，钱却不发。似乎是因为现金流紧张，用户去投诉得,才给处理。下面就有人说，可以去问deepseek咋投诉，跟着做就行。这让我想到，可以搞个功能，一键投诉，用户提自己的述求，ai直接就帮你找到合适的平台，拟好合适的言论，帮你完成投诉。</li>
<li>可行性分析:
<ul>
<li>分析诉求，判断该去哪个平台投诉，并用什么语言，现有的大语言模型应该完全能胜任了。可能难点在于，每个平台要投诉可能都需要先注册，登陆，然后可能还会有风控。这点的话可能也好办，就是让ai执行大部分步骤，输密码，过验证码等地方再让用户操作就行。</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>记两次迁移</title>
      <link>https://ds63.eu.org/2023/rocords-of-two-migrations/</link>
      <pubDate>Wed, 01 Nov 2023 13:56:12 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/rocords-of-two-migrations/</guid>
      <description>switching to Zepp and Spotify</description>
      <content:encoded><![CDATA[<p><strong>最近更换了两个使用的app，记录一下</strong></p>
<h2 id="mi-fitness---zepp">Mi Fitness -&gt; Zepp</h2>
<p>我的小米手环戴了两年多了，依然很好用。续航还算长，也能记录些我需要的数据。</p>
<p>我一直使用的是官方提供的Mi Fitness作为配套的app，也还凑合。</p>
<p>但最近想导出之前的数据，发现查无此功能。我的数据不是我的，听起来很讽刺，但却是事实。</p>
<p>在<a href="https://github.com/yihong0618/running_page/issues/76"  target="_blank" rel="noopener" >[TODO]有人需要小米运动么？ · Issue #76 · yihong0618/running_page</a>找到了一个替代选择。</p>
<p>Zepp并绑定Strava。</p>
<p>目前我的使用体验非常好。</p>
<p>而且最重要的一点是，我的运动数据终于是属于我的了。</p>
<p>ps: 2024年5月份，我原来的手环因脱胶而无法正常使用，抱着这两年小米手环的良好体验，我又购买了小米手环7。买7而不买8是因为网上搜到7无法使用Zepp。</p>
<p>回来一通折腾，在<a href="https://mmk.pw/en/posts/mi-band-7-with-zepp/"  target="_blank" rel="noopener" >Pairing Xiaomi Smart Band 7 with Amazfit Zepp application | melianmiko</a>的帮助下完成了小米手环和Zepp的配对。</p>
<p>但发现Zepp似乎无法再和Strava进行连接，于是我再一次失去了对自己运动数据的控制权。</p>
<h2 id="网易云音乐---spotify">网易云音乐 -&gt; Spotify</h2>
<p>我使用网易云大概有7年多，原因有两点：</p>
<ol>
<li>推荐功能做得确实可以。</li>
<li>惯性。</li>
</ol>
<p>但最近有几点让我决定换掉它：</p>
<ol>
<li>广告。我开了会员，会员权益说可以去广告。但实际上我还是得忍受敏感的开屏广告和各种续费宣传。</li>
<li>不全的曲库。</li>
<li>臃肿且我不需要的功能。</li>
</ol>
<p>几经寻找，我最终选择了Spotify。</p>
<h3 id="使用体验">使用体验</h3>
<p>Spotify的体验很棒，我目前感受到的有几点。</p>
<ul>
<li>手机和电脑同步进度，再配上耳机，我几乎可以做到音乐随身。</li>
<li>曲库的话，相比于我之前使用的网易云，是多了不少，但也有些没有的，比如<a href="https://music.163.com/artist?id=19710"  target="_blank" rel="noopener" >Happy End - 歌手 - 网易云音乐</a>，我似乎没有找到。</li>
<li>支持播客。之前就有听播客的想法，以后可以试试。</li>
<li>无广告</li>
<li>简洁，没有乱七八糟的内容。手机app是一百来兆，Windows端则是两百多兆。而网易云，单手机app就是五百多兆。</li>
<li>歌单支持添加本地音乐。这点是我的一大需求。</li>
<li>推荐功能，看<a href="https://www.geekpark.net/news/244856"  target="_blank" rel="noopener" >越听越上瘾，Spotify 是如何推荐新歌的？ | 极客公园</a>和<a href="https://medium.com/@sophiaciocca/spotifys-discover-weekly-how-machine-learning-finds-your-new-music-19a41ab76efe"  target="_blank" rel="noopener" >How Does Spotify Know You So Well?</a>里面说得很厉害，但可能是号还没养好，目前我体验一般。
(使用2个月后发现推荐功能做得确实不错，到目前已经帮助我发现好几张喜欢的专辑)</li>
</ul>
<h3 id="迁移记录">迁移记录</h3>
<ol>
<li>歌单迁移
参考了<a href="https://biteliang.github.io/post/liang-fen-zhong-jiang-wang-yi-yun-de-ge-dan-dao-ru-spotify/"  target="_blank" rel="noopener" >两分钟将网易云的歌单导入Spotify | Gridea</a></li>
</ol>
<p>主要是用到了以下两个网站：</p>
<ul>
<li><a href="https://yyrcd.com/n2s/"  target="_blank" rel="noopener" >迁移 网易云 / QQ 音乐到 Apple Music, Youtube Music, Spotify | yyrcd</a></li>
<li><a href="https://www.spotlistr.com/search/textbox"  target="_blank" rel="noopener" >Textbox Search - Spotlistr</a></li>
</ul>
<ol start="2">
<li>添加本地音乐
参考了：<a href="https://www.tunefab.com/zh-CN/tutorials/add-songs-to-spotify.html"  target="_blank" rel="noopener" >如何将本地文件添加到 Spotify [完整指南]</a></li>
</ol>
<h2 id="尾巴">尾巴</h2>
<p>新换的这两款软件都让我感受到了：诶，原来软件是可以做得这么让人舒服。</p>
<p>我相信一些软件本可以做得让人舒服的，但它们偏不。那么这时候用户用脚投票，离开它，放弃它,这也是理所当然的。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://www.geekpark.net/news/244856"  target="_blank" rel="noopener" >越听越上瘾，Spotify 是如何推荐新歌的？ | 极客公园</a></li>
<li><a href="https://medium.com/@sophiaciocca/spotifys-discover-weekly-how-machine-learning-finds-your-new-music-19a41ab76efe"  target="_blank" rel="noopener" >How Does Spotify Know You So Well?</a></li>
<li><a href="https://biteliang.github.io/post/liang-fen-zhong-jiang-wang-yi-yun-de-ge-dan-dao-ru-spotify/"  target="_blank" rel="noopener" >两分钟将网易云的歌单导入Spotify | Gridea</a></li>
<li><a href="https://yyrcd.com/n2s/"  target="_blank" rel="noopener" >迁移 网易云 / QQ 音乐到 Apple Music, Youtube Music, Spotify | yyrcd</a></li>
<li><a href="https://www.spotlistr.com/search/textbox"  target="_blank" rel="noopener" >Textbox Search - Spotlistr</a></li>
<li><a href="https://www.tunefab.com/zh-CN/tutorials/add-songs-to-spotify.html"  target="_blank" rel="noopener" >如何将本地文件添加到 Spotify [完整指南]</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>“一本好书”部署记录</title>
      <link>https://ds63.eu.org/2023/%E4%B8%80%E6%9C%AC%E5%A5%BD%E4%B9%A6%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/</link>
      <pubDate>Mon, 30 Oct 2023 00:50:12 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E4%B8%80%E6%9C%AC%E5%A5%BD%E4%B9%A6%E9%83%A8%E7%BD%B2%E8%AE%B0%E5%BD%95/</guid>
      <description>记录&amp;quot;一本好书&amp;quot;部署的过程</description>
      <content:encoded><![CDATA[<h2 id="说明">说明</h2>
<ul>
<li>前端仓库地址： <a href="https://github.com/EuDs63/BookRecommend_Front"  target="_blank" rel="noopener" >BookRecommend_Front</a></li>
<li>后端仓库地址<a href="https://github.com/EuDs63/BookRecommend_Back"  target="_blank" rel="noopener" >BookRecommend_Back</a></li>
</ul>
<h2 id="mysql">MySQL</h2>
<ol>
<li>安装
<a href="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/"  target="_blank" rel="noopener" >MySQL :: A Quick Guide to Using the MySQL APT Repository</a>
<code>systemctl status mysql</code></li>
<li>登录 <code>mysql -u root -p</code></li>
<li>建表</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">show</span><span class="w"> </span><span class="k">databases</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">DATABASE</span><span class="w"> </span><span class="n">book_recommend</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">USE</span><span class="w"> </span><span class="n">book_recommend</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">source</span><span class="w"> </span><span class="o">/</span><span class="n">path</span><span class="o">/</span><span class="k">to</span><span class="o">/</span><span class="n">your_script</span><span class="p">.</span><span class="k">sql</span><span class="p">;</span><span class="w"> </span><span class="c1">#建库脚本
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">show</span><span class="w"> </span><span class="kp">tables</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">describe</span><span class="w"> </span><span class="n">table_name</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h2 id="flask">Flask</h2>
<h3 id="设置生产服务器">设置生产服务器</h3>
<ol>
<li>安装Gunicorn <code>pip install gunicorn</code></li>
<li>安装相关依赖 <code>pip install -r requirements.txt</code></li>
<li>测试运行<code>gunicorn -w 4 -b 127.0.0.1:5000 'app:app' --access-logfile=-</code> (显示日志)</li>
<li>测试成功后</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir logs
</span></span><span class="line"><span class="cl"><span class="c1"># 后台运行，日志输出在文件中</span>
</span></span><span class="line"><span class="cl">gunicorn -w <span class="m">4</span> -b 127.0.0.1:5000 <span class="s1">&#39;app:app&#39;</span> --access-logfile<span class="o">=</span>logs/access.log --error-logfile<span class="o">=</span>logs/error.log --daemon
</span></span><span class="line"><span class="cl"><span class="c1"># 查看进程</span>
</span></span><span class="line"><span class="cl">pgrep gunicorn
</span></span><span class="line"><span class="cl"><span class="c1"># 关闭进程</span>
</span></span><span class="line"><span class="cl">pkill gunicorn
</span></span></code></pre></div><h2 id="react">React</h2>
<ol>
<li>打包 <code>npm run build</code></li>
<li>nginx操作</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vim /etc/nginx/sites-available/book_recommend
</span></span><span class="line"><span class="cl"><span class="c1">#粘贴以下配置</span>
</span></span><span class="line"><span class="cl">server <span class="o">{</span>
</span></span><span class="line"><span class="cl">    listen 80<span class="p">;</span>
</span></span><span class="line"><span class="cl">    server_name ip_address<span class="p">;</span>  <span class="c1"># 使用服务器的 IP 地址</span>
</span></span><span class="line"><span class="cl">    root /usr/local/project/bookrecommend/dist<span class="p">;</span>  <span class="c1"># 静态文件所在的目录</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    location / <span class="o">{</span>
</span></span><span class="line"><span class="cl">        try_files <span class="nv">$uri</span> /index.html<span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 创建一个符号链接以启用配置文件</span>
</span></span><span class="line"><span class="cl">sudo ln -s /etc/nginx/sites-available/book_recommend /etc/nginx/sites-enabled/
</span></span><span class="line"><span class="cl"><span class="c1"># 检查 Nginx 配置以确保没有语法错误：</span>
</span></span><span class="line"><span class="cl">sudo nginx -t
</span></span><span class="line"><span class="cl"><span class="c1"># 重启 Nginx 以使配置生效</span>
</span></span><span class="line"><span class="cl">sudo service nginx restart
</span></span></code></pre></div><h2 id="收获">收获</h2>
<h3 id="0000与-127001的区别"><code>0.0.0.0</code>与<code> 127.0.0.1</code>的区别</h3>
<ol>
<li>
<p><code>-b 0.0.0.0</code> 意味着绑定到所有可用的网络接口，可以通过任何 IP 地址访问。这使得应用程序对外可见，可以通过服务器的公共 IP 地址或域名进行访问。</p>
</li>
<li>
<p>而<code>-b 127.0.0.1</code> 意味着仅绑定到本地回环接口（localhost，IP 地址 127.0.0.1），这样只有本地访问能够连接到您的 Flask 应用程序。外部网络请求无法直接访问。</p>
</li>
</ol>
<h2 id="参考连接">参考连接</h2>
<ol>
<li><a href="https://dormousehole.readthedocs.io/en/latest/deploying/index.html"  target="_blank" rel="noopener" >生产部署 — Flask中文文档(2.3.x)</a></li>
<li><a href="https://dormousehole.readthedocs.io/en/latest/deploying/gunicorn.html"  target="_blank" rel="noopener" >Gunicorn — Flask中文文档(2.3.x)</a></li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>进一步学习git</title>
      <link>https://ds63.eu.org/2023/dive-into-git/</link>
      <pubDate>Sat, 28 Oct 2023 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/dive-into-git/</guid>
      <description>the information manager from hell</description>
      <content:encoded><![CDATA[<p><strong>使用git已经有一段时间了，在感受到其便利的同时，我开始好奇它究竟是如何实现的。</strong></p>
<p><strong>这篇文章主要是对参考链接中的几篇文章的结合和整理，我自己原创的内容并不多，算是我的阅读笔记。</strong></p>
<h2 id="3-main-components">3 main components</h2>
<h3 id="blobbinary-large-object">blob(binary large object)</h3>
<ol>
<li>git用于存储文件内容的基本数据对象</li>
<li>只包含文件内容的原始二进制数据。</li>
<li>唯一标识符是由其内容计算得到的 SHA-1 散列值,计算方法如下：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># find-git-object.py</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">hashlib</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">object_path</span><span class="p">(</span><span class="n">content</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">header</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;blob </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="si">}</span><span class="se">\0</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span> <span class="o">=</span> <span class="n">header</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="o">+</span> <span class="n">content</span>
</span></span><span class="line"><span class="cl">    <span class="n">digest</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha1</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">digest</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;.git/objects/</span><span class="si">{</span><span class="n">digest</span><span class="p">[:</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">digest</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">object_path</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()))</span>
</span></span></code></pre></div></li>
<li>git使用上一步所得到的digest来确定文件所存储的位置。这种方法被称为“content addressed storage”。</li>
<li>由上可以发现：若文件内容完全相同，那么文件内容就将存储在同一个blob对象中。</li>
<li>确定位置后，我们使用<code>file</code>可以得到文件的类型<code>zlib compressed data</code>,并可使用以下python代码进行解码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可用来解码blob或commit文件</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 简易版的 git cat-file -p</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">zlib</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span></code></pre></div></li>
</ol>
<h3 id="commit">commit</h3>
<ol>
<li>表示一次代码提交或版本更新的操作</li>
<li>a commit file contains tree, parent commit(if any), author, committer.</li>
<li>Commit file will be hashed and store in the same way as blob.</li>
<li>可以通过<code>git log</code>获取commit对应的sha-1值,并使用<code>git cat-file -p &lt;commit_hash&gt;</code>观察对应的commit文件,例如：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">&gt; git cat-file -p a2392bba4e795aa1041ce4464c2da00391b51913
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">tree 3b8155bcfb149e4cf627c2011eeef58b28e50348
</span></span><span class="line"><span class="cl">parent 3b43a50eb349f2f8126735ab1e133004bab0a933
</span></span><span class="line"><span class="cl">author EuDs63 &lt;erica23187@gmail.com&gt; <span class="m">1698421602</span> +0800
</span></span><span class="line"><span class="cl">committer EuDs63 &lt;erica23187@gmail.com&gt; <span class="m">1698421602</span> +0800
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">add test.txt
</span></span></code></pre></div></li>
<li>每个 commit 对应的parent commit可以是零个、一个，或多个</li>
</ol>
<h3 id="tree">tree</h3>
<ol>
<li>
<p>用于构建和维护项目的目录结构</p>
</li>
<li>
<p>Each folder match a tree file which stores the structure of files and folders of the folder.</p>
</li>
<li>
<p>Tree file will be hashed and store in the same way as blob.</p>
</li>
<li>
<p>同样可以通过<code>git log</code>获取对应的sha-1值,并使用<code>git cat-file -p &lt;tree_hash&gt;</code>观察对应的tree文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">&gt; git cat-file -p 3b8155bcfb149e4cf627c2011eeef58b28e50348
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob 4b6e76588c44ca2a580f982c63f14200b4bffc3f    decompress.py
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob 211d3833fbe6ed59e66b38bbe643b5f7141ae53c    find-git-object.py
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob f100ad94f6be76f58fadaf9e720d9d00d486a088    test.txt
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob 131b0c74e5e1c21c7c9b830a57df7b8dadb5eda7    test1.txt
</span></span></code></pre></div></li>
<li>
<p>注意到<code>100644</code>这个数字，这表示该 Git 对象的类型和模式。
具体来说:</p>
<p>前4位1006表示对象类型:
1000 - 普通文件(blob 对象)
1006 - 可执行文件(blob 对象)
1007 - 符号链接(blob 对象)
1010 - 树(tree 对象)
1011 - 提交(commit 对象)
1114 - Gitlink(blob 对象)
后4位44表示文件模式,这在Unix系统中代表文件权限:
100644表示普通文件,权限是-rw-r&ndash;r&ndash;
100755表示可执行文件,权限是-rwxr-xr-x</p>
</li>
</ol>
<hr>
<h2 id="branch">branch</h2>
<ol>
<li>Branches are stored in <code>.git/refs/heads</code>.</li>
<li>Branches are files tracking commits, and the content of these files is updated at every commit we perform.</li>
<li>对remote branch的认识:
There are potentially three versions of every remote branch:
<ol>
<li>The actual branch on the remote repository</li>
<li>The snapshot of that branch locally</li>
<li>A local branch that might be tracking the remote branch</li>
</ol>
</li>
</ol>
<hr>
<h2 id="head">head</h2>
<ol>
<li>Head are stored in <code>.git/HEAD</code></li>
<li>通常情况下，HEAD文件中的内容为<code>ref: refs/heads/&lt;branch_name&gt;</code>,由此来间接指向该分支的最新commit。</li>
<li>When we are on a branch and perform the commit, Git reads the content of the HEAD file and writes the commit which is referenced as the parent commit.</li>
<li>We can checkout to a previous commit by <code>git checkout &lt;commit_hash&gt;</code>. Thus we will enter a mode called “detached mode” . In this mode, HEAD will point directly to a commit.</li>
</ol>
<hr>
<h2 id="what-happened-after-git-checkout">what happened after git checkout</h2>
<ol>
<li>
<p>解析命令行参数：首先，Git 解析命令行参数，以确定用户想要执行的 git checkout 操作的类型，包括切换分支、检出文件等。</p>
</li>
<li>
<p>获取目标分支/提交的 SHA-1 值：根据命令行参数中提供的分支名或提交标识符，Git 获取目标分支或提交的 SHA-1 值.</p>
</li>
<li>
<p>检查工作目录状态：Git 在切换分支或提交之前会检查当前工作目录状态，以确保没有未提交的更改。</p>
</li>
<li>
<p>切换到目标分支/提交：如果用户想要切换分支，Git 将会使用目标分支的 branch_name 更新 HEAD 引用，同时将目标分支的文件状态写入工作目录。如果用户要检出特定提交，Git 会根据提交的 SHA-1 值更新 HEAD 引用，并将提交的文件状态写入工作目录。</p>
</li>
<li>
<p>重建工作目录：在切换分支或提交后，Git 会确保工作目录的文件和内容与目标一致。它可能会涉及文件的创建、更新和删除操作。(根据commit文件中的tree去逐层展开)</p>
</li>
<li>
<p>更新索引和暂存区：Git 更新索引，以反映工作目录中文件的状态。这涉及将工作目录的文件与索引中的文件状态进行比较，并记录更改。（暂存区是介于Working Directory和 Repository 之间的区域，用于存放已经使用 git add 命令添加但尚未提交的文件和更改。）</p>
</li>
<li>
<p>更新 HEAD 指针：最后，Git 更新 HEAD 引用，将其指向所选的目标分支或提交，以反映当前的状态。</p>
</li>
</ol>
<h2 id="how-git-log-filename-works">how <code>git log &lt;filename&gt;</code> works</h2>
<ol>
<li>go through every single commit in the history</li>
<li>go through the various directory trees</li>
<li>search for the filename we wanted</li>
</ol>
<hr>
<h2 id="about-git-submodule">about git submodule</h2>
<h3 id="远程仓库的子模块链接错了指向了一个不同的仓库">远程仓库的子模块链接错了，指向了一个不同的仓库</h3>
<ol>
<li>检查并修复 .gitmodules 文件
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>submodule <span class="s2">&#34;path/to/submodule&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"> <span class="nv">path</span> <span class="o">=</span> path/to/submodule
</span></span><span class="line"><span class="cl"> <span class="nv">url</span> <span class="o">=</span> git@correct-url.git
</span></span></code></pre></div></li>
<li>检查 .git/config 中的子模块配置
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>submodule <span class="s2">&#34;path/to/submodule&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"> <span class="nv">url</span> <span class="o">=</span> git@correct-url.git
</span></span></code></pre></div></li>
<li>提交 .gitmodules 文件的更改</li>
<li>更新 Git 子模块配置： <code>git submodule sync</code></li>
<li>更新子模块的内容： <code>git submodule update --init --recursive</code></li>
<li>推送更改</li>
</ol>
<hr>
<h2 id="how-does-git-diff-works">how does git diff works</h2>
<p>to do!</p>
<h2 id="git-reset-hardsoftmixed">git reset hard|soft|mixed</h2>
<p>to do!</p>
<h2 id="git-rebase">git rebase</h2>
<p>to do!</p>
<h2 id="git-hook">git hook</h2>
<ul>
<li><a href="https://git-scm.com/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git-%E9%92%A9%E5%AD%90"  target="_blank" rel="noopener" >Git - Git 钩子</a></li>
<li>如何在本地监听git tag事件</li>
</ul>
<h2 id="收获">收获</h2>
<ul>
<li>之前看过一句话，&ldquo;In Linux and UNIX, everything is a file&rdquo;。现在发现git中也是这样设计的。</li>
<li>了解平时使用的工具是怎么做到的，尤其是一些不了解之前觉得很神奇的操作背后的原理，我觉得这挺有趣。</li>
</ul>
<h2 id="碎碎念">碎碎念</h2>
<p>距离这篇文章的创建已经小半年了，那位作者已经写了近10篇git相关的博文。我学习的进度甚至比不上其写作的进度，不禁叹服。希望未来的我能好好看完。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/"  target="_blank" rel="noopener" >In a git repository, where do your files live?</a></li>
<li><a href="https://github.com/cpina/github-action-push-to-another-repository/blob/main/entrypoint.sh"  target="_blank" rel="noopener" >github-action-push-to-another-repository/entrypoint.sh at main · cpina/github-action-push-to-another-repository</a></li>
<li><a href="https://towardsdatascience.com/how-git-truly-works-cd9c375966f6"  target="_blank" rel="noopener" >How Git truly works. A deep dive on the internals to… | by Alberto Prospero | Towards Data Science</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>我的数据</title>
      <link>https://ds63.eu.org/2023/my-data/</link>
      <pubDate>Fri, 27 Oct 2023 17:00:16 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/my-data/</guid>
      <description>我的数据不应被大公司所绑架。</description>
      <content:encoded><![CDATA[<p><em>自从八月份的推特账号被封，和使用Mi Fitness记录运动情况两年却无法导出运动记录这两件事后。</em></p>
<p><em>我开始重视自己的数据。我的数据不应被大公司所绑架。</em></p>
<h2 id="运动记录">运动记录</h2>
<p>我之前使用的是Mi Fiteness。不支持数据的导出。</p>
<p>我现在使用的是Zepp，并绑定Strava。</p>
<p>等运动记录再多攒些，有使用<a href="https://github.com/yihong0618/running_page"  target="_blank" rel="noopener" >yihong0618/running_page: Make your own running home page</a>的计划。</p>
<h2 id="书影音记录">书影音记录</h2>
<p>之前用的是豆瓣。整体体验其实还行。</p>
<p>但是有些条目因为这样那样的原因被下架。而这里面有我所看过的，并且我不认可其下架的理由。</p>
<p>所以我转而使用<a href="https://neodb.social/discover/"  target="_blank" rel="noopener" >NeoDB</a>，基本功能都有。尤其是从豆瓣迁移过来的过程。很顺畅。</p>
<p>但发现了几个可以改进的,或者说我自己的需求：</p>
<ul>
<li>标记历史想设定为能够记录“二刷”，“三刷”之类的。</li>
<li>支持导入Bangumi的记录</li>
</ul>
<p>对我来说，它最大的优点是提供了api和数据导出。播客的集成也很棒。</p>
<p>它同时也是个<a href="https://github.com/neodb-social/neodb"  target="_blank" rel="noopener" >开源项目</a>，希望未来能为这个项目做些自己的贡献。</p>
<h2 id="rss订阅">rss订阅</h2>
<p>我使用<a href="https://tt-rss.org/"  target="_blank" rel="noopener" >Tiny Tiny RSS</a>来部署自己的rss订阅服务。</p>
<p>并使用<a href="https://github.com/EuDs63/TinyTinyRSS-OPML-to-MD-Table"  target="_blank" rel="noopener" >EuDs63/TinyTinyRSS-OPML-to-MD-Table: 获取解析和转换Tiny Tiny RSS的OPML文件，并将其格式化为Markdown表格的自动化操作</a>定期导出我的订阅记录。</p>
<h2 id="twitter关注列表">twitter关注列表</h2>
<p>我原先的Twitter账号在某一天突然被suspended。</p>
<p>我第一时间也没反应过来要导出数据。只是发了封申述邮件并开始漫长的等待。</p>
<p>等到的结果是一封例行邮件和我的Twitter数据被清空。</p>
<p>我Twitter一般不怎么发言，也没有什么follower。但后面在找回关注者的时候着实花了些时间。</p>
<p>现在我使用<a href="https://github.com/prinsss/export-twitter-following-list/"  target="_blank" rel="noopener" >prinsss/export-twitter-following-list: Export your Twitter/X&rsquo;s following/followers list like a breeze. (关注列表与关注者列表导出工具)</a></p>
<p>该工具目前不支持自动化。我有尝试去实现自动化的念头，尝试了下，无果。</p>
<p>不过也够用了。</p>
<h2 id="想法">想法</h2>
<p>我有做记录的习惯，我也重视这些记录。</p>
<p><strong>为什么要花时间去做记录？</strong></p>
<p>因为我觉得这是我短暂人生的一部分。</p>
<p>我的记忆力并不算好，常常试图回忆前一阶段做过的事时，大脑几乎一片空白：欸，我之前都干了些啥。</p>
<p>这时候，以前的自己所留下的记录会成为路标类似的存在，帮助我去回溯：哦，原来我做了这些事情。</p>
<p>其实使用频率并不高，但每当用到的时候，就有一种很幸福的感觉。</p>
<p><strong>不仅要做记录，还要将其展示出来。</strong></p>
<p>我只是个普通人，也没啥好被关注的。但我还是愿意展示一些记录在网上。<a href="https://ds63.eu.org/records/"  target="_blank" rel="noopener" >Records | EuDs&rsquo;s Blog</a>就是其中之一。</p>
<p>原因有二：</p>
<ol>
<li>当作某种备份。</li>
<li>留给未来可能存在的网络考古学家。</li>
<li>留给未来的自己去发掘。我现在还能找到不少自己小学时期留在网上的痕迹。能看到自己之前的一些发言，还是蛮有意思的。</li>
</ol>
<p>我现在用来记录自己数据的几乎都是开源项目。</p>
<p><strong>为什么要使用开源项目</strong></p>
<p>我记得一句话。免费的就是最昂贵的。</p>
<p>当我去使用一些公司的免费的服务时，我同时也就应具备承担相应的代价的心理准备，包括但不限于层出不穷的广告,自己产生的数据被利用。</p>
<p>我认为这是可以理解的。毕竟这些公司肯定是以盈利为目的的。</p>
<p>但即使是我有了对应的心理准备，但无奈有些吃相还是太过难看了。广告暂且不提，连用户导出自己的数据都设置得困难重重，有些干脆就是不提供。</p>
<p>我尝试去理解这样的做法。可能是为了防止用户流失？</p>
<p>但我接着又想:会想去导出自己数据的用户，一般都是珍视自己数据的用户。他们更可能会因为看重数据的导出功能,以至于即使要花费相当的代价，也愿意去迁移至其他可以导出数据的平台。我自己就是这样的例子。</p>
<p>以这样的角度来看，为了防止用户流失的做法反而更加剧了用户流失。这不是很可笑吗？</p>
<p>话又说回来，开源项目也几乎都是免费的，那按照刚才的逻辑，“免费的就是最昂贵的”。使用开源项目的代价是什么呢？</p>
<p>我想到的有这几点：</p>
<ol>
<li>功能可能不完善</li>
<li>细节可能没打磨好</li>
<li>维护者可能弃坑</li>
</ol>
<p>总的来说就是你需要自己再折腾下。这些我认为都是可以接受的，毕竟开发者是为爱发电。我衷心感谢所有开源社区的贡献者。</p>
<p>而使用开源项目进行记录的最大优点，我觉得在于：</p>
<p>数据是你自己的。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://tannercollin.com/my-backup-strategy/"  target="_blank" rel="noopener" >My Backup Strategy | Tanner&rsquo;s Site</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>1024</title>
      <link>https://ds63.eu.org/2023/1024/</link>
      <pubDate>Tue, 24 Oct 2023 13:09:32 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/1024/</guid>
      <description>愿以后写的都是喜欢的代码</description>
      <content:encoded><![CDATA[<p>今天是1024。</p>
<p>想起去年看到的一个网站。<a href="https://tw93.netlify.app/"  target="_blank" rel="noopener" >祝你 1024 节日快乐~</a></p>
<p>蛮喜欢最后那一段话</p>
<pre tabindex="0"><code>你从来不以量取胜，创意是你的生命
只需一台电脑，你就可开始创造
纵横八荒，你诛杀于千里之外
归隐闹市，你徜徉于芸芸众生
不是码农，你是一名无所不能的工程师
祝你 1024 快乐，以后写的都是你喜欢的代码~
</code></pre><p>尤其是最后一句，哈哈</p>
<h2 id="尾巴">尾巴</h2>
<p>昨天还念叨着不知道作者是谁。今天刷推的时候就刷到了。</p>
<p><a href="https://twitter.com/HiTw93/status/1584333853098917888"  target="_blank" rel="noopener" >Tw93 on X: &ldquo;🎉今天是 1024 程序员节，平淡的日子需要有些仪式感，周末写了一个小彩蛋，送给程序员以及喜欢开源的同学，希望你喜欢，也祝福你以后写的都是你想写的代码。由于没有任何署名，当然你分享给你的程序员朋友也没有问题的。 https://t.co/Oec1YpScPN&rdquo; / X</a></p>
<p>有点感叹。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>博客迁移记</title>
      <link>https://ds63.eu.org/2023/blog-migration-chronicle/</link>
      <pubDate>Sat, 21 Oct 2023 12:50:17 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/blog-migration-chronicle/</guid>
      <description>nice to use Hugo</description>
      <content:encoded><![CDATA[<h2 id="过程">过程</h2>
<ol>
<li>
<p><strong>尝试修改代码栏背景</strong></p>
<p>无果</p>
</li>
<li>
<p><strong>更换主题至<a href="https://reorx.github.io/hugo-PaperModX/"  target="_blank" rel="noopener" >PaperModX</a></strong></p>
</li>
<li>
<p><strong>设置文章中链接以新标签的方式打开</strong></p>
<p>参考：<a href="https://dvel.me/posts/hugo-goldmark-markdown-new-tab/"  target="_blank" rel="noopener" >在 Hugo Goldmark Markdown 中设置以新标签打开链接 - Dvel&rsquo;s Blog</a></p>
</li>
<li>
<p><strong>统一风格</strong></p>
</li>
<li>
<p><strong>使用<a href="https://www.jinrishici.com/"  target="_blank" rel="noopener" >今日诗词 - 一言API</a>作为slogan</strong></p>
<p>步骤如下：</p>
<ol>
<li>找到位置，发现位于<code>themes\PaperModX\layouts\partials\home_info.html</code></li>
<li>根据api文档添加调用代码</li>
</ol>
</li>
<li>
<p><strong>美化标签页</strong></p>
<p>参考<a href="https://www.sulvblog.cn/posts/blog/hugo_tag_cloud/"  target="_blank" rel="noopener" >Hugo博客添加标签云 | Sulv&rsquo;s Blog</a></p>
</li>
<li>
<p><strong>添加archive页</strong></p>
<p>步骤如下：</p>
<ol>
<li>新增archive.md文件</li>
<li>在<code>themes\PaperModX\assets\css\common\archive.css</code>替换并添加相应代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">archive-entry</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">margin</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">transition</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">link</span><span class="o">-</span><span class="n">transition</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="c">/* 添加过渡效果，使颜色和阴影变化平滑 */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">archive-entry</span><span class="p">:</span><span class="nd">hover</span> <span class="p">.</span><span class="nc">archive-entry-title</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">link</span><span class="o">-</span><span class="n">hover</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="c">/* 鼠标悬停时的文字颜色 */</span>
</span></span><span class="line"><span class="cl">     <span class="k">box-shadow</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">link</span><span class="o">-</span><span class="n">hover</span><span class="o">-</span><span class="kc">underline</span><span class="o">-</span><span class="n">shadow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="c">/* 鼠标悬停时的下划线阴影效果 */</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">archive-entry-title</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">margin</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">font-weight</span><span class="p">:</span> <span class="mi">400</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">transition</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">link</span><span class="o">-</span><span class="n">transition</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
</li>
<li>
<p><strong>添加搜索功能</strong></p>
<p>步骤如下</p>
<ol>
<li>新增search.md文件</li>
<li>在<code>hugo.yml</code>新增
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">outputs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">home</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span>- <span class="l">HTML</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span>- <span class="l">RSS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span>- <span class="l">JSON</span><span class="w"> </span><span class="c"># is necessary</span><span class="w">
</span></span></span></code></pre></div></li>
</ol>
</li>
<li>
<p><strong>整合search,category,tags至discover,以使导航栏更为简洁</strong></p>
<p>步骤如下</p>
<ol>
<li>参考<a href="https://loyayz.com/website/220609-hugo-papermodx-tags-in-search-page/"  target="_blank" rel="noopener" >PaperMod 搜索页展示标签列表 | loyayz</a></li>
<li>修改对应标题、url</li>
<li>修改<code>themes\PaperModX\layouts\_default\search.html</code>中的代码</li>
</ol>
</li>
<li>
<p><strong>修改profile-mode中的副标题为一言诗句</strong></p>
<p>步骤如下:</p>
<ol>
<li>找到对应位置<code>themes\PaperModX\layouts\partials\index_profile.html</code></li>
<li>参考第五步</li>
</ol>
</li>
<li>
<p><strong>添加Records页面</strong></p>
<p>步骤如下</p>
<ol>
<li>参考<a href="https://eallion.com/neodb/#back-to-top"  target="_blank" rel="noopener" >NeoDB API 创建观影页面 - 大大的小蜗牛</a></li>
<li>添加<code>themes\PaperModX\layouts\_default\records.html</code>与<code>static\css\records.css</code></li>
<li>添加<code>content\records.md</code></li>
</ol>
</li>
<li>
<p><strong>添加rss_subscription页面</strong></p>
<p>步骤如下</p>
<ol>
<li>大体上与第11步相同</li>
<li>在<code>themes\PaperModX\layouts\_default\single.html</code>的基础上进行修改，得到<code>themes\PaperModX\layouts\_default\rss_subscription.html</code></li>
</ol>
</li>
<li>
<p><strong>部署</strong></p>
<p>步骤如下：</p>
<ol>
<li>主要参考<a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/"  target="_blank" rel="noopener" >Host on GitHub Pages | Hugo</a></li>
<li>报错<code>Branch &quot;x&quot; is not allowed to deploy to github-pages due to environment protection rules.</code>。
参考<a href="https://github.com/orgs/community/discussions/39054"  target="_blank" rel="noopener" >Branch &ldquo;x&rdquo; is not allowed to deploy to github-pages due to environment protection rules. · community · Discussion #39054</a></li>
</ol>
</li>
<li>
<p><strong>添加social icons</strong></p>
<p>参考<a href="https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-icons/"  target="_blank" rel="noopener" >Icons | PaperMod</a></p>
</li>
<li>
<p><strong>数据自动更新</strong></p>
<p>代码位于<code>.github\workflows\sync.yml</code></p>
</li>
<li>
<p><strong>添加最后修改时间</strong></p>
<p>参考<a href="https://tourcoder.com/lastmod-in-hugo/"  target="_blank" rel="noopener" >Hugo 中最后更新的时间显示</a>，步骤如下：</p>
<ol>
<li>修改<code>hugo.yml</code>文件，添加以下内容
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="c"># 最后修改时间的获取顺序： git &gt; lastmod(自设定) &gt; fileModTime &gt; default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">frontmatter</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">lastmod</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="p">:</span><span class="l">git</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">lastmod</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="p">:</span><span class="l">fileModTime</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="p">:</span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">enableGitInfo</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></li>
<li>修改<code>themes\PaperModX\layouts\partials\post_meta.html</code>,添加</li>
</ol>
<pre tabindex="0"><code>{{- if not .Lastmod.IsZero -}}
&lt;span class=&#34;meta-item&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;24&#34; height=&#34;24&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34;
   stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;feather feather-pen&#34;
   style=&#34;user-select: text;&#34;&gt;
   &lt;path
      d=&#34;M7.127 22.562l-7.127 1.438 1.438-7.128 5.689 5.69zm1.414-1.414l11.228-11.225-5.69-5.692-11.227 11.227 5.689 5.69zm9.768-21.148l-2.816 2.817 5.691 5.691 2.816-2.819-5.691-5.689z&#34; /&gt;
&lt;/svg&gt;

&lt;span&gt;lastmod in {{ .Lastmod | time.Format (default &#34;January 2, 2006&#34; site.Params.DateFormat) }}&lt;/span&gt;&lt;/span&gt;
{{- end }}
</code></pre></li>
<li>
<p><strong>除archive外的列表均按最后修改时间进行排序</strong></p>
<p>参考<a href="https://gohugo.io/templates/lists/#order-content"  target="_blank" rel="noopener" >Lists of content in Hugo | Hugo</a>
修改<code>themes\PaperModX\layouts\_default\list.html</code>中相关内容为
<code>{{- $pages := .Pages.ByLastmod.Reverse.ByWeight }}</code> 。先根据最后修改时间进行逆向排序，再根据weight排序</p>
</li>
<li>
<p><strong>实际测试发现第十七步存在问题</strong></p>
<p>表现为并没有按照最后修改时间进行逆向排序。猜测可能是和<code>ByWeight</code>的定义有关。</p>
<p>我的解决方法是：</p>
<ol>
<li>新增一个param<code>rating</code></li>
<li><code>{{- $pages := .Pages.ByLastmod.Reverse.ByParam &quot;rating&quot; }}</code></li>
</ol>
</li>
<li>
<p>修改url。参考<a href="https://gohugo.io/content-management/urls/"  target="_blank" rel="noopener" >URL management | Hugo</a>, 我现在的配置如下</p>
<pre tabindex="0"><code>permalinks:
# posts: /:year/:title/
posts: /:year/:slug/
</code></pre></li>
</ol>
<h2 id="想法">想法</h2>
<ol>
<li>Hexo给我的感觉就是折腾少，约等于开箱即用。这里要感谢<a href="https://hexo.fluid-dev.com/"  target="_blank" rel="noopener" >Fluid</a>这款主题，做得很棒。</li>
<li>Hugo我则没有找到一款我比较中意的主题，前前后后换了三四个，最后选择在<a href="https://github.com/reorx/hugo-PaperModX/"  target="_blank" rel="noopener" >hugo-PaperModX</a>的基础上自己进行修改。(也可能只是因为我的需求提升了)</li>
<li>Hugo确实和其所宣传的一样，很快，部署的时间只要原来的一半，还有本地的实时预览。但是缓存还是有些讨人厌，就算我加上了<code>--disableFastRender</code>还是需要手动重启，无痕浏览等措施才能看到一些设置的变化。不过看issue说这也是一种设计。</li>
<li>再次体会到了教程还是要以官方教程为主。在部署至Github Page时，我首先是修改自己以前的代码，跑不通然后就去问ChatGPT，再然后是网上搜教程。最后反倒是在<a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/"  target="_blank" rel="noopener" >Host on GitHub Pages | Hugo</a>的帮助下解决的。</li>
<li>还是官方教程的事。我比较喜欢从代码出发。直接去看代码。但后面遇到问题后发现有些坑其实没必要踩，教程里写得好好的呢。直接从代码出发看似省了时间，其实添了不少麻烦。</li>
</ol>
<h2 id="待修复问题">待修复问题</h2>
<ol>
<li><input checked="" disabled="" type="checkbox"> 部署后<a href="https://ds63.eu.org/rss_subscription/"  target="_blank" rel="noopener" >My Rss Subscription | EuDs&rsquo;s Blog</a>无法正常显示</li>
<li><input checked="" disabled="" type="checkbox"> 网站icon时有时无</li>
<li><input checked="" disabled="" type="checkbox"> action<code>Sync NeoDB Data</code>中，触发的<code>Deploy Hugo site to Pages</code>所使用的并非是最新的代码？</li>
</ol>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://liujiacai.net/blog/2020/12/05/hexo-to-hugo/#headline-3"  target="_blank" rel="noopener" >博客系统迁移：Hexo 到 Hugo</a></li>
<li><a href="https://cloud.tencent.com/developer/article/1702561"  target="_blank" rel="noopener" >将hexo文章头转为hugo格式-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://io-oi.me/tech/hugo-vs-hexo/"  target="_blank" rel="noopener" >Hugo 与 Hexo 的异同 | reuixiy</a></li>
<li><a href="https://www.sulvblog.cn/posts/blog/hugo_toc_side/"  target="_blank" rel="noopener" >Hugo博客目录放在侧边 | PaperMod主题 | Sulv&rsquo;s Blog</a></li>
<li><a href="https://hugo.aiaide.com/post/hugo%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/"  target="_blank" rel="noopener" >Hugo的工作原理 - Hugo 中文帮助文档</a></li>
<li><a href="https://www.sulvblog.cn/posts/blog/hugo_tag_cloud/"  target="_blank" rel="noopener" >Hugo博客添加标签云 | Sulv&rsquo;s Blog</a></li>
<li><a href="https://www.fusejs.io/api/options.html#keys"  target="_blank" rel="noopener" >Options | Fuse.js</a></li>
<li><a href="https://loyayz.com/website/220609-hugo-papermodx-tags-in-search-page/"  target="_blank" rel="noopener" >PaperMod 搜索页展示标签列表 | loyayz</a></li>
<li><a href="https://eallion.com/neodb/#back-to-top"  target="_blank" rel="noopener" >NeoDB API 创建观影页面 - 大大的小蜗牛</a></li>
<li><a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/"  target="_blank" rel="noopener" >Host on GitHub Pages | Hugo</a></li>
<li><a href="https://tourcoder.com/lastmod-in-hugo/"  target="_blank" rel="noopener" >Hugo 中最后更新的时间显示@代码旅行 :: Do Faith No Fear | 信仰永恒，无所畏惧 :)</a></li>
<li><a href="https://gohugo.io/templates/lists/#order-content"  target="_blank" rel="noopener" >Lists of content in Hugo | Hugo</a></li>
<li><a href="https://dnwzlx.com/posts/146871a6/"  target="_blank" rel="noopener" >使用Hugo搭建个人网站(七)-Hugo和Github Action正确修改文章的最后更新日期 - 寂静·流年</a></li>
<li><a href="https://gohugo.io/content-management/urls/"  target="_blank" rel="noopener" >URL management | Hugo</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>反战</title>
      <link>https://ds63.eu.org/2023/anti-war/</link>
      <pubDate>Wed, 18 Oct 2023 01:36:40 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/anti-war/</guid>
      <description>止战之殇</description>
      <content:encoded><![CDATA[<p>如果要说什么是人类历史中一直存在的，战争可能就是其中一个。</p>
<p>描写战争的作品有许多，它们可能视角不同，形式不同，但不少都有着同样一个主题：反战。</p>
<p>这里摘录几篇我常读、常看、常听的。</p>
<h2 id="反战的名作">反战的名作</h2>
<h3 id="北风行-李白">北风行 (李白)</h3>
<p>烛龙栖寒门，光曜犹旦开。</p>
<p>日月照之何不及此？惟有北风号怒天上来。</p>
<p>燕山雪花大如席，片片吹落轩辕台。</p>
<p>幽州思妇十二月，停歌罢笑双蛾摧。</p>
<p>倚门望行人，念君长城苦寒良可哀。</p>
<p>别时提剑救边去，遗此虎文金鞞靫。</p>
<p>中有一双白羽箭，蜘蛛结网生尘埃。</p>
<p>箭空在，人今战死不复回。</p>
<p>不忍见此物，焚之已成灰。</p>
<p>黄河捧土尚可塞，北风雨雪恨难裁。</p>
<p><strong>从战士的妻子的角度写战争。</strong></p>
<p><strong>丈夫参与战争的理由是“救边”。国家被侵略了，挺身而出,没能回来。</strong></p>
<p><strong>留给妻子的是“不忍见此物”的思念。</strong></p>
<hr>
<h3 id="goodbye-blue-sky-pink-floyd-节选">Goodbye Blue Sky (Pink Floyd) (节选)</h3>
<p>Look, Mummy. There&rsquo;s an airplane up in the sky.</p>
<p>Ooooo</p>
<p>Did you, did you see the frightened ones?</p>
<p>Did you ,did you hear the falling bombs?</p>
<p>Did you ever wonder why we had to run for shelter.</p>
<p>When the promise of a brave new world,</p>
<p>Unfurled beneath a clear blue sky?</p>
<p>The flames are all long gone,</p>
<p>But the pain lingers on.</p>
<p>Goodbye, Blue sky.</p>
<p><strong>很简单的节奏和歌词，但每次听都很有感觉。</strong></p>
<p><strong>从小孩的角度写战争。小孩甚至连战争是什么都不知道，他看到天上有架飞机，觉得很新奇。</strong></p>
<p><strong>但在有些地方，有些时候，天空中的飞机代表着死亡。湛蓝而平静的天空只能是奢望。</strong></p>
<hr>
<h3 id="渔家傲秋思-范仲淹">渔家傲·秋思 (范仲淹)</h3>
<p>塞下秋来风景异，衡阳雁去无留意。四面边声连角起，千嶂里，长烟落日孤城闭。</p>
<p>浊酒一杯家万里，燕然未勒归无计。羌管悠悠霜满地。人不寐，将军白发征夫泪。</p>
<p><strong>从将士的角度写战争。</strong></p>
<p><strong>在外打仗已经很久了，但一直没能取得决定性的战果。</strong></p>
<p><strong>想家啊，回不去啊。</strong></p>
<hr>
<h3 id="一封电子邮件">一封电子邮件</h3>
<blockquote>
<p>Date: Thu, 01 Apr 1999 06:37:30 -0800
From: insomnia <a href="mailto:insomnia@EUnet.yu" >insomnia@EUnet.yu</a>
Subject: thursday, april 1</p>
<p>dear everybody,
the main novi sad bridge has been taken down completely. we are cut off from belgrade. no water today. shortage of bread and milk. if you do not hear from me anything more, this means i fled from the city, because life becomes insupportable here.</p>
<p>everything hurts, everybody hurts. now i feel like an island — cut off, cut off, cut off from everything.</p>
<p>peace with you all.</p>
</blockquote>
<p><strong>不是名作，只是被战争所困的普通人所发出的一封邮件。我在<a href="https://nettime.org/Lists-Archives/nettime-l-9904/msg00006.html"  target="_blank" rel="noopener" ><!-- raw HTML omitted --> insomnia x3</a>看到，并摘抄了过来。</strong></p>
<p><strong>&rsquo;life becomes insupportable here.&lsquo;这句看得揪心。</strong></p>
<h2 id="另一种视角">另一种视角</h2>
<p>当然了，描写战争的作品这么多，也不都是反战的。</p>
<h3 id="大秦帝国之裂变主题曲-节选">《大秦帝国之裂变》主题曲 (节选)</h3>
<p>赳赳老秦，复我河山。
血不流干，死不休战。</p>
<p><strong>从将士的角度写战争。</strong></p>
<p><strong>打仗的目的也很明确：收复失地，理由无可挑剔。</strong></p>
<p><strong>口号也很有气势。</strong></p>
<p><strong>那么代价是什么呢？</strong></p>
<hr>
<h3 id="无衣-诗经">无衣 (诗经)</h3>
<p>岂曰无衣？与子同袍。王于兴师，修我戈矛。与子同仇！</p>
<p>岂曰无衣？与子同泽。王于兴师，修我矛戟。与子偕作！</p>
<p>岂曰无衣？与子同裳。王于兴师，修我甲兵。与子偕行！</p>
<p><strong>从将士的角度写战争。</strong></p>
<p><strong>战友情也很有感觉。</strong></p>
<p><strong>打仗的理由是什么，里面没写。</strong></p>
<p><strong>但可能这就是战士们的真实情况。</strong></p>
<p><strong>他们可能不知道为什么要打仗，只知道“王于兴师”。</strong></p>
<hr>
<h3 id="破阵子为陈同甫赋壮词以寄之">破阵子·为陈同甫赋壮词以寄之</h3>
<p>醉里挑灯看剑，梦回吹角连营。八百里分麾下炙，五十弦翻塞外声。沙场秋点兵。</p>
<p>马作的卢飞快，弓如霹雳弦惊。了却君王天下事，赢得生前身后名。可怜白发生！</p>
<p><strong>从将的角度来写战争。战争已经结束，但依然还是会想起当年那种氛围。</strong></p>
<p><strong>读起来十分爽快。</strong></p>
<p><strong>打仗的目的有为自己，有为君主，有为国家。似乎也无可指摘。</strong></p>
<hr>
<h3 id="从军行-王昌龄">从军行 (王昌龄)</h3>
<p>青海长云暗雪山，孤城遥望玉门关。</p>
<p>黄沙百战穿金甲，不破楼兰终不还。</p>
<p><strong>从将士的角度写战争。</strong></p>
<p><strong>打仗的目的是打退侵略者，打灭侵略者。很正当的理由。</strong></p>
<p><strong>最后一句十分有气势。</strong></p>
<hr>
<h3 id="示儿-陆游">示儿 (陆游)</h3>
<p>死去元知万事空，但悲不见九州同。</p>
<p>王师北定中原日，家祭无忘告乃翁。</p>
<p><strong>一个自知时日所剩无几的人的遗言。</strong></p>
<p><strong>虽然“元知万事空”，但依然还是放不下对失地的信念。</strong></p>
<p><strong>仗要打，而且要打赢，将失去的土地收复回来。</strong></p>
<h2 id="我的想法">我的想法</h2>
<p>关于战争的作品实在太多太多了，以上只能说是沧海一粟。</p>
<p>但其实也很能代表了。</p>
<p>描写的角度有亲身参与战争的战士、将军，有亲人奔赴战场的思妇，有懵懂的孩童，有时日无几的老人。</p>
<p>他们的态度也不尽相同。</p>
<p>而我对战争的态度，也很复杂。</p>
<p><strong>我反对战争吗？是的。</strong></p>
<p>我没有经历过战争，但我有起码的共情能力。当我看到那些因战争而流离失所的人们，我深深地同情他们。</p>
<p>我也绝不希望自己有一天被卷入战争，太可怕了。</p>
<p><strong>我支持战争吗？可能。</strong></p>
<p>收复失地，抵抗侵略。这都是很正当的理由。</p>
<p>一个国家、一个地区被侵略了。难道你还不支持它进行反抗，不去参与到战争中，还要谴责它吗？</p>
<p><strong>那可不可以这样：反对挑起战争的那一方，支持战争中弱小的那一方</strong></p>
<p>我觉得也不尽然。</p>
<p>很多事情绝不是非黑即白的。</p>
<p>金庸的《天龙八部》写大宋和辽国之间的战争时，就很巧妙地以萧峰的视角来描写。</p>
<p>时代背景是辽国对大宋发起侵略。</p>
<p>从大宋的角度：自己是被侵略的一方，是弱小的一方。所以抗击是十分正确的，到敌方境内打草谷也是一种正义的报复。</p>
<p>从辽国的角度：自己之前弱小的时候就是这样被欺负，现在自己实力起来了，为什么不去进一步扩展自己的领土。</p>
<p>萧峰是在大宋长大的契丹人。他的前半生很幸福，但一天他突然得知了自己的契丹人身份，并因这个身份被昔日的好友、手下群起而攻之。</p>
<p>而辽国作为自己的母国，皇帝也很赏识自己，对自己很好。</p>
<p>这样就形成了一个两难的局面。两边双方都有自己的道理，而萧峰却被夹在了中间。</p>
<p>最后他的选择是：制止战争，而后跳崖自杀。</p>
<p>他的理由是：战争会带来死亡、交战双方的死亡。</p>
<p>我很认可这点，我也十分支持这点。</p>
<p><strong>有没有不打仗的方法</strong></p>
<p>有不少人为之努力着，但目前似乎并没有找到一个彻底的、有效的、通用的办法</p>
<ul>
<li>
<p>甘地选择“非暴力不合作”。他成功地实现了印度独立的目标，但是以印巴分治为代价。</p>
</li>
<li>
<p>联合国。成立一个相对独立，每个国家有一定参与度的组织，进行居中调解。有用吗？不好说。但不可否认的是仍旧不断有战争出现。</p>
</li>
<li>
<p>刘慈欣在《光荣与梦想》中提出了一个构想：“和平视窗”计划。而这计划在小说中的结局是“美丽的童话”。里面还有一个细节值得在这里记录。</p>
</li>
</ul>
<blockquote>
<p>萨里，你这是叛国！”西亚代表团中有人高喊。</p>
<p>　　“我的父亲是为国家而死的，他在十七年前的那场战争中阵亡，那时我才八岁，我和母亲只从政府那里拿到一千二百西亚元的抚恤金，之后物价飞涨，那点儿钱还不够我们吃两个星期的饱饭。”萨里从肩取下其他西亚运动员为他披上的国旗，抓在手中大声质问：“国家？国家是什么？如果是一块面包它有多大？如果是一件衣服它有多暖和？如果是一间房子能为我们挡住风雨吗？！西亚的有钱人早就跑到国外躲避战火了，只剩下我们这些穷鬼还在政府编织的爱国主义神话里等死！”</p>
<p>&hellip;&hellip;</p>
<p>首都保卫战正处于最后阶段，城市已大半失陷，虽然大势已去，但从外地增援的部队仍源源不断地进入仍在战斗的城区，这些部队由杂乱的各种人组成，有穿军装的，更多的是扛枪的平民。萨里向一名军官要一枝冲锋枪，那人认出了他，笑着说：“呵呵，我们可请不起救世主了。”</p>
<p>　　“不，普通一兵。”萨里微笑着说，接过了枪，加入了高唱国歌的队伍，在被火光映红了一半的夜空下，在颤动的土地上，向激战中的城市走去。</p>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>qqBot 搭建</title>
      <link>https://ds63.eu.org/2023/setup_qqbot/</link>
      <pubDate>Wed, 11 Oct 2023 01:23:34 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/setup_qqbot/</guid>
      <description>短时间内也不想再进一步折腾了</description>
      <content:encoded><![CDATA[<p><strong>这两天在搭qqBot，记录一下</strong></p>
<h2 id="整体技术">整体技术</h2>
<p>我使用的是<a href="https://github.com/Mrs4s/go-cqhttp"  target="_blank" rel="noopener" >go-cqhttp</a>和<a href="https://github.com/nonebot/nonebot2"  target="_blank" rel="noopener" >nonebot2</a>。</p>
<p>在遇到风控问题时，我使用了<a href="https://github.com/fuqiuluo/unidbg-fetch-qsign"  target="_blank" rel="noopener" >unidbg-fetch-qsign</a>。</p>
<h2 id="过程">过程</h2>
<ul>
<li>
<p>整个过程比我着手搭建前所想的要困难许多，踩了许多坑。不过很棒的一点是，这三个项目的issue都十分活跃。我踩的坑，在issue中几乎都能搜到。我使用过的开源项目不多，但这三个给了我很好的印象，希望自己以后能做些自己的贡献。</p>
</li>
<li>
<p>之前没想到最难的一点不是机器人程序的编写，而在于登录。我使用的号是新号（创建一个礼拜左右），风控等级比较高。</p>
</li>
</ul>
<p>而我的需求是：将bot部署在地点在非我所在地的一个服务器上，这更是增加了被风控的概率。</p>
<p>尝试许多种方法后，我最终的解决方法是：</p>
<ol>
<li>在本地先使用手表协议扫码登录。( <code>&quot;sort_version_name&quot;:8.9.73</code>,<code>protocol：2</code>)</li>
<li>成功登录后将得到的文件移至服务器上并配置<code>signsever</code>,再次进行登录</li>
</ol>
<ul>
<li>
<p>但最后bot还是被风控，无法发送群消息。</p>
<p>我短时间内也不想再进一步折腾了。</p>
</li>
<li>
<p>今天把自己写的插件<a href="https://github.com/EuDs63/nonebot-plugin-yesman"  target="_blank" rel="noopener" >EuDs63/nonebot-plugin-yesman: nonebot2 插件</a>发布到<a href="https://nonebot.dev/store/plugins"  target="_blank" rel="noopener" >插件商店 | NoneBot</a>了。过了一遍插件发布的流程，还蛮有意思的。有几点值得说下:</p>
<ol>
<li><a href="https://pypi.org/account/register/"  target="_blank" rel="noopener" >Create an account · PyPI</a>的username要求是我见过的最苛刻的。但也能理解。
<blockquote>
<p>Choose a strong password that contains letters (uppercase and lowercase), numbers and special characters. Avoid common words or repetition.</p>
</blockquote>
</li>
<li><a href="https://github.com/apps/noneflow"  target="_blank" rel="noopener" >About NoneFlow</a> 好强大。有机会想自己试试写一个类似的，或者了解是怎么做到的。</li>
</ol>
</li>
<li>
<p>今天<a href="https://github.com/Mrs4s/go-cqhttp"  target="_blank" rel="noopener" >go-cqhttp</a>在<a href="https://github.com/Mrs4s/go-cqhttp/issues/2471"  target="_blank" rel="noopener" >QQ Bot的未来以及迁移建议</a>宣布不再维护了。感受到一种无力感。</p>
</li>
</ul>
<h2 id="感想">感想</h2>
<ol>
<li>想起搭telegram bot时，只需要申请一个token，甚至教程官方都有在写。而这里却是道高一尺魔高一丈般的猫鼠游戏。不免五味杂陈。</li>
<li>nonebot这种插件系统我觉得很棒。省了不少力气。</li>
<li>感觉qqBot可玩性还是蛮高的，在其他群里也常常能见到些有趣的bot。但可惜的是腾讯的态度。</li>
</ol>
<h2 id="收获">收获</h2>
<ol>
<li><code>nohup</code></li>
</ol>
<ul>
<li>使用: 例: <code>nphup nb run</code></li>
<li>关闭: 例:
<pre tabindex="0"><code>ps aux | grep `nb` #找到对应的进程号
kill $进程号
</code></pre></li>
</ul>
<ol start="2">
<li><code>守护进程（Systemd）</code>
<em>注：以下复制自<a href="https://blog.cysi.me/2022/04/make-a-qqbot.html#%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8Bsystemd"  target="_blank" rel="noopener" >使用 NoneBot2 和 go-cqhttp 打造自己的 FF14 QQ 机器人</a></em>
<ul>
<li>创建</li>
</ul>
<pre tabindex="0"><code># vim /lib/systemd/system/go-cqhttp.service

    [Unit]
    Description=GO-CQHTTP
    Wants=network-online.target
    After=network-online.target
    [Service]
    Type=simple
    User=root
    WorkingDirectory= GO-CQHTTP的运行目录
    ExecStart= nohup go-cqhttp
    KillMode=process

    [Install]
    WantedBy=multi-user.target
</code></pre><ul>
<li>使用</li>
</ul>
<pre tabindex="0"><code>systemctl status go-cqhttp #查看状态
systemctl enable go-cqhttp #启用开机自启
systemctl restart go-cqhttp #重启进程
systemctl stop go-cqhttp #停止进程
systemctl start go-cqhttp #开始进程
</code></pre></li>
<li>python虚拟环境
<ul>
<li>新建</li>
</ul>
<pre tabindex="0"><code>python -m venv myenv # 创建一个名为myenv的虚拟环境
</code></pre><ul>
<li>激活</li>
</ul>
<pre tabindex="0"><code>source ./qqVenv/bin/activate # bash

source ./qqVenv/bin/activate.fish # fish
</code></pre></li>
</ol>
<h2 id="尾巴">尾巴</h2>
<ol>
<li><a href="https://github.com/Mrs4s/go-cqhttp"  target="_blank" rel="noopener" >go-cqhttp</a>在<a href="https://github.com/Mrs4s/go-cqhttp/issues/2471"  target="_blank" rel="noopener" >QQ Bot的未来以及迁移建议</a>中宣布不再维护</li>
<li>不久后，<a href="https://github.com/Mrs4s/go-cqhttp/issues/2471"  target="_blank" rel="noopener" >QQ Bot的未来以及迁移建议</a>上所提到的可能的替代方案也相继无法使用</li>
</ol>
<p>我感谢这些作者！</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://github.com/nonebot/nonebot2"  target="_blank" rel="noopener" >nonebot/nonebot2: 跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python</a></li>
<li><a href="https://github.com/fuqiuluo/unidbg-fetch-qsign"  target="_blank" rel="noopener" >fuqiuluo/unidbg-fetch-qsign: 获取QQSign通过Unidbg</a></li>
<li><a href="https://blog.cysi.me/2022/04/make-a-qqbot.html#%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6"  target="_blank" rel="noopener" >使用 NoneBot2 和 go-cqhttp 打造自己的 FF14 QQ 机器人</a></li>
<li><a href="https://github.com/Mrs4s/go-cqhttp"  target="_blank" rel="noopener" >Mrs4s/go-cqhttp: cqhttp的golang实现，轻量、原生跨平台.</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Sai</title>
      <link>https://ds63.eu.org/2023/sai/</link>
      <pubDate>Tue, 10 Oct 2023 21:05:24 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/sai/</guid>
      <description>烨然若神人</description>
      <content:encoded><![CDATA[<h1 id="sai">Sai</h1>
<p><em>网上冲浪时发现<a href="https://bgm.tv/"  target="_blank" rel="noopener" >Bangumi 番组计划</a>的创始人是<a href="https://bgm.tv/user/sai"  target="_blank" rel="noopener" >Sai</a>。带着好奇了解下了这位，简直就是个神人，将自己的震撼记录如下。</em></p>
<h2 id="几篇博客">几篇博客</h2>
<h3 id="when-i-met-php__我的程序猿生涯---nothing-but-saihttpblogorzotlcom1entry3892"><a href="http://blog.orzotl.com/1/entry/3892"  target="_blank" rel="noopener" >When I met PHP__我的程序猿生涯 - ::Nothing but SAi</a></h3>
<p>在这篇博客中，他回顾了自己二十岁前的经历。有几处我比较有感受。</p>
<blockquote>
<p>在这年，我只是遵循一些教程，对程序进行一些hack，至于开始编写php的程序，那是很多年以后的事情了。</p>
</blockquote>
<p>我有时候感觉自己还是在做类似的事情。而这是他初中的时候经历的事。</p>
<blockquote>
<p>他们的言语，他们的生活方式，在当时的我看来仿佛笼罩着天使光环</p>
</blockquote>
<p>也有其所佩服的人</p>
<blockquote>
<p>之后的日子又处在另一轮人生反思。现在回想，这种行为是懦弱、胆怯的表现，我没有明确而坚定的目标，我游移于升学与退学的抉择之间，犹豫是人生最大的敌人，我差点败在它的手下。最终，我参加了高考，考取了我所在高中(同时也是我初中)从属的大学，我为自己留了退路——因为我并不自信能够抛弃学历闯荡世界，你可以称我为loser——继续学习，与我现在所从事的事物毫不相干的专业。</p>
</blockquote>
<p>我最近在是考研还是准备就业这两个选择中犹豫。前段时间，大致上是确定下来，选择准备就业。既然选择了，就要为之去努力。结果是好是坏，我不知道。但总比犹豫不决要来得好。</p>
<blockquote>
<p>高考结束后我建立了Bangumi，我第一个从头构建的，似乎可以进行大半辈子的网站</p>
</blockquote>
<p><a href="https://bgm.tv/"  target="_blank" rel="noopener" >Bangumi 番组计划</a>是我很常用的，以后应该也会继续使用下去。</p>
<p>我什么时候才可以做一个自己会投入毕生精力的项目呢？</p>
<blockquote>
<p>再过几个月，我就要进入奔三之人的行列了，在我内心的深处，有一种强烈的期望，期望能在二十五岁前，与你们一道，在拥有巨大落地窗的摩天大楼里，改变世界。</p>
</blockquote>
<p>这里的奔三应该指的是要满20岁。他后来也做到了。25岁就是一家公司的重要成员之一。</p>
<h3 id="写在第三个十年之前---nothing-but-saihttpblogorzotlcom1entry3943"><a href="http://blog.orzotl.com/1/entry/3943"  target="_blank" rel="noopener" >写在第三个十年之前 - ::Nothing but SAi</a></h3>
<blockquote>
<p>曾经的梦想，是能够博览群书、环游世界。
突然发现，这样的梦想，应该在年轻时就去实现。
能在青壮年时实现的梦想，怎能称得上梦想。</p>
<p>二十岁，已不是拿着父母的金币仰望星空怀疑人生的年岁了。</p>
</blockquote>
<p>看得我自残形愧，不知道自己什么能实现。</p>
<h2 id="我比较震撼的点">我比较震撼的点</h2>
<ul>
<li>精力（或者说时间安排）：软件开发的同时，看书、追番、玩游戏似乎也没落下。甚至有时也有参与<a href="https://bgm.tv/user/sai/wiki"  target="_blank" rel="noopener" >Bangumi条目的编辑</a>。</li>
<li>做的项目的可用性。好几个有十来年的网站，到现在也能正常访问。以下列举我发现的几个：
<ul>
<li><a href="http://yume.ly/"  target="_blank" rel="noopener" >YUME 梦乡</a></li>
<li><a href="http://ipad.ly/"  target="_blank" rel="noopener" >iPadly | 网址最短的中文 iPhone/iPad 资源导航站</a></li>
<li><a href="http://clover.ly/"  target="_blank" rel="noopener" >Clover 四叶新媒体</a></li>
<li><a href="http://www.saicn.com/bbs/"  target="_blank" rel="noopener" >::NoName Magazine 无名杂志</a></li>
<li><a href="http://saicn.com/me/#work_17"  target="_blank" rel="noopener" >NONAME Studio</a> 这里是他自己做的一个以往项目的集合。</li>
</ul>
</li>
<li>名字很酷</li>
</ul>
<h2 id="我的想法">我的想法</h2>
<p>看到这位在与我相仿的年纪时，就实现了我甚至都不太敢想的一些事情。</p>
<p>钦佩之外，还有些别的想法。</p>
<p>是焦虑吗？倒也算不上。因为到现在20岁了，大致也认清了一件事：</p>
<p>自己并不比别人聪明，更谈不上有天赋。所以觉得：自己能做些让自己愉快的事情，抓住平时生活中的一些可能被忽视的幸福。作为一个平凡的人，普普通通的活下去，也蛮好的。如果能让身边的人也觉得愉快，让就再好不过了。</p>
<p>但也还是会觉得不甘心吗？这样说可能也不是太准确。</p>
<p>这二十年很可能只是占了我未来全部人生的五分之一，甚至更少。（我感觉自己至少能活一百岁，甚至更长寿，因为我生活习惯蛮健康的）</p>
<p>以现在这么一小部分，就去决定以后的一大部分，太不公平了。而目前的我还是报着一个比较积极的心态的。</p>
<p>未来无限可能</p>
<h2 id="尾巴">尾巴</h2>
<p>这篇本来应该是写Sai的，但其实很大一部分是在写我自己的想法。显得有点文不对题了。但不太打算改。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>服务器迁移记</title>
      <link>https://ds63.eu.org/2023/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%81%E7%A7%BB%E8%AE%B0/</link>
      <pubDate>Sat, 07 Oct 2023 19:32:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%81%E7%A7%BB%E8%AE%B0/</guid>
      <description>虽然早就知道是这样。但是这次还是第一次这么切身地体验到。很感慨。</description>
      <content:encoded><![CDATA[<h2 id="起因">起因</h2>
<p>我之前使用的是阿里云的ecs。因为要到期了，而续费又过于昂贵。（2核2g一年要六百多。）</p>
<p>对比了下几家云服务器提供商，发现华为云价格最为理想（2核2g3M带宽一年89）。</p>
<h2 id="迁移过程">迁移过程</h2>
<p>我其实并没有用服务器来做多少事情。主要就两个：telegram bot和ttrss。它们都是使用docker进行部署的，所以能省不少事。</p>
<ol>
<li>docker安装
没想到第一步安装docker就花了一晚上。3m的带宽，下载时只有可怜的十几kb。等到最后还下不了。</li>
</ol>
<p>最后我是自己手动下载软件包，再安装的。</p>
<pre tabindex="0"><code># “package.deb”为下载的软件包
sudo dpkg -i /path/to/package.deb
</code></pre><p>我其实应该一开始就去配置镜像源的&hellip;</p>
<ol start="2">
<li>
<p>设置网络
<a href="https://ds63.eu.org/2023/03/11/network/"  target="_blank" rel="noopener" >network - EuDs&rsquo;s blog</a></p>
</li>
<li>
<p>Faye_Bot
<a href="https://github.com/EuDs63/Faye_Bot"  target="_blank" rel="noopener" >EuDs63/Faye_Bot: my telegram Bot</a></p>
</li>
<li>
<p>ttrss</p>
</li>
</ol>
<ul>
<li><a href="https://ds63.eu.org/2023/03/08/RssTossing/"  target="_blank" rel="noopener" >RSS折腾记 - EuDs&rsquo;s blog</a></li>
<li><a href="https://ttrss.henry.wang/zh/#%E5%85%B3%E4%BA%8E"  target="_blank" rel="noopener" >🐋 Awesome TTRSS </a></li>
</ul>
<h2 id="尾巴">尾巴</h2>
<p>本来没打算再买一个服务器的。因为vscode+WSL2其实已经满足我绝大部分的linux使用需求了。但想着说不定呢？以后哪天就有需求了。而那时候再重新搭环境，没了现有的作参考，怕是要发更多的时间，于是还是买了。</p>
<p>还是要想办法用起来。</p>
<h2 id="尾巴的尾巴">尾巴的尾巴</h2>
<p>没想到这么快就又有了一个服务器。今天（隔天）逛博客看到Azure学生包注册教程。想着之前也有试着搞过，但不知道为什么没成功。今天抱着试一试的想法，就又点进去。没想到直接就成了。</p>
<p>于是参考<a href="https://zbttl-github-io.vercel.app/github-xue-sheng-bao-he-azure-yang-mao/"  target="_blank" rel="noopener" >github 学生包和 azure 羊毛</a>，申请了台linux虚拟机。还是用的ubuntu的镜像。</p>
<p>结果十分地流畅。安装docker不到三分钟，也不需要额外配置什么代理。昨天没成功的<a href="https://github.com/yihong0618/tg_bing_dalle"  target="_blank" rel="noopener" >yihong0618/tg_bing_dalle: tg bing dalle-3</a>也成了。</p>
<p>虽然早就知道是这样。但是这次还是第一次这么切身地体验到。很感慨。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://zbttl-github-io.vercel.app/github-xue-sheng-bao-he-azure-yang-mao/"  target="_blank" rel="noopener" >github 学生包和 azure 羊毛</a></li>
<li><a href="https://github.com/yihong0618/tg_bing_dalle"  target="_blank" rel="noopener" >yihong0618/tg_bing_dalle: tg bing dalle-3</a></li>
<li><a href="https://ttrss.henry.wang/zh/#%E5%85%B3%E4%BA%8E"  target="_blank" rel="noopener" >🐋 Awesome TTRSS </a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>game of life</title>
      <link>https://ds63.eu.org/2023/game-of-life/</link>
      <pubDate>Thu, 05 Oct 2023 16:04:39 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/game-of-life/</guid>
      <description>记录EuDs63/game_of_life</description>
      <content:encoded><![CDATA[<h2 id="起因">起因</h2>
<p>大一的时候做某次课程作业，我的选题就是life of game。从那时候就想自己实现一个。但一直搁置着没有动手，最近在学Rust，并正好看到了篇<a href="https://rustwasm.github.io/docs/book/introduction.html"  target="_blank" rel="noopener" >很不错的教程</a>。这便是这个项目的起因。</p>
<h2 id="历程">历程</h2>
<h3 id="前期准备">前期准备</h3>
<p>我使用的环境是vecode+wsl2。整体下来除了因为机器性能限制导致内存占用过高，体验还是很可以的。</p>
<p>但在搭建项目环境时踩了三个坑。</p>
<ol>
<li><em>npm install 失败</em></li>
</ol>
<ul>
<li>解决：在Ubuntu中安装npm</li>
<li>参考：<a href="https://blog.csdn.net/hys__handsome/article/details/125687617"  target="_blank" rel="noopener" >WSL无法使用npm</a></li>
</ul>
<ol start="2">
<li><em>wasm-build 失败</em></li>
</ol>
<ul>
<li>解决
<pre tabindex="0"><code>[package.metadata.wasm-pack.profile.release]
wasm-opt = false
</code></pre></li>
<li>参考：<a href="https://github.com/rustwasm/wasm-pack/issues/864"  target="_blank" rel="noopener" >failed to download binaryen-version_90-x86-windows.tar.gz</a></li>
</ul>
<ol start="3">
<li><em>wasm-pack test &ndash;chrome &ndash;headless 失败</em></li>
</ol>
<ul>
<li>解决: 改用<code>wasm-pack test --chrome</code></li>
<li>参考： <a href="https://github.com/rustwasm/wasm-pack/issues/611"  target="_blank" rel="noopener" >Headless Chrome test fails</a></li>
</ul>
<h3 id="编码">编码</h3>
<p>编码阶段跟着教程来，还算顺利。但教程中的代码是全部堆放在一起的。这看起来不太舒服，也不太适合我后续的迭代。我花了些时间将其组件化。但教程的后面也有说明没有组件化的理由：Shrinking .wasm Size。这让我意识到还是要根据项目的特点来去做对应的优化和修改。</p>
<h3 id="部署">部署</h3>
<p>开发时，我发现<a href="https://github.com/shalzz/wasm-game-of-life"  target="_blank" rel="noopener" >shalzz/wasm-game-of-life</a>提供了一个live demo。是使用vercel进行部署的。vercel之前我也有使用过，但只是用的别人的一键部署。我觉得蛮有意思的，于是决定也试试。着实花了些时间，踩了不少坑。这里展开说下过程。</p>
<ol>
<li>一开始参考<a href="https://betterprogramming.pub/deploying-a-wasm-powered-react-app-on-vercel-cf3cae2a75d6"  target="_blank" rel="noopener" >Deploying a WASM-Powered React App on Vercel</a>。后来发现不需要这么麻烦，因为我已经<code>wasm-pack pulish</code>了，可以直接将<a href="https://www.npmjs.com/package/wasm-game-of-life-euds63"  target="_blank" rel="noopener" >wasm-game-of-life-euds63 - npm</a>作为依赖引入。这样就只需要部署webpack，而不用再去安装Rust相关的内容。</li>
<li>对代码进行对应的修改后。我开始尝试部署。先是遇到路径问题，我将<code>Root Directory</code>修改为www。</li>
<li>这时候vercel显示部署成功了，但实际上是运行不了的。我因着之前的经验，惯性地以为也是路径问题。开始修改其他地方的路径。但实际上不是。反复修改几次后我发现:错误的路径会导致部署成功，而正确的路径反而会使<code>npm install</code>报错。而我一开始以为的错误路径是正确的。 这一步我觉得还是我没有好好去看log导致的。</li>
<li>根据相应的报错发现是node版本问题。我本地运行成功的node版本是12，而vercel只支持18和16，我一开始的想法是另外安装一个12的版本，未果。后来报着试一试的念头改为16，惊喜的是<code>npm install</code>成功了。</li>
<li><code>npm run build</code>后报错：Missing Public Directory。根据<a href="https://vercel.com/docs/errors/error-list#missing-public-directory"  target="_blank" rel="noopener" >Error List | Vercel Docs</a>尝试将<code>Output Directory</code>设为dist，解决。</li>
</ol>
<h3 id="配置域名">配置域名</h3>
<p>我使用了子域名的方式进行配置。之前觉得配置子域名蛮神奇的。自己尝试后发现，似乎是相当于一个redirect？</p>
<p>我先在我使用的DNS服务提供商处添加了一条CNAME记录。</p>
<table>
<thead>
<tr>
<th>SUBDOMAIN</th>
<th>TYPE</th>
<th>VALUE</th>
<th>TTL, SEC</th>
</tr>
</thead>
<tbody>
<tr>
<td>lifegame</td>
<td>CNAME</td>
<td>game-of-life-2hpx.vercel.app</td>
<td>86400</td>
</tr>
</tbody>
</table>
<p>然后在vercel的对应项目中的Domains新增域名lifegame.ds63.eu.org。</p>
<p>一开始设置好的是没有ssl证书。网上查了些资料，发现vercel是会自动提供ssl证书的。还以为是自己哪里设置出问题了。结果是得等一会儿才行。</p>
<h2 id="收获">收获</h2>
<ol>
<li>Rust自定义宏
<ul>
<li>步骤
<ol>
<li>在一个模块中定义并导出自定义宏
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="c1">// utils.rs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[macro_export]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">macro_rules</span><span class="o">!</span><span class="w"> </span><span class="n">log</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="p">(</span><span class="w"> </span><span class="cp">$(</span><span class="w"> </span><span class="cp">$t</span>:<span class="nc">tt</span><span class="w"> </span><span class="p">)</span><span class="o">*</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="n">web_sys</span>::<span class="n">console</span>::<span class="n">log_1</span><span class="p">(</span><span class="o">&amp;</span><span class="fm">format!</span><span class="p">(</span><span class="w"> </span><span class="cp">$(</span><span class="w"> </span><span class="cp">$t</span><span class="w"> </span><span class="p">)</span><span class="o">*</span><span class="w"> </span><span class="p">).</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div></li>
<li>在其他模块中使用
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="c1">// lib.rs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[macro_use]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">mod</span> <span class="nn">utils</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">mod</span> <span class="nn">universe</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// universe.rs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="k">crate</span>::<span class="n">utils</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// 直接使用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="fm">log!</span><span class="p">(</span><span class="s">&#34;This is a log message: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">some_variable</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div></li>
</ol>
</li>
</ul>
</li>
<li>Always let profiling guide your focus
<ul>
<li>一些检测性能工具
<ol>
<li>edge开发者工具 -&gt; 性能</li>
<li><code>cargo benchcmp</code></li>
<li><code>perf</code></li>
</ol>
</li>
<li><a href="https://rustwasm.github.io/docs/book/game-of-life/time-profiling.html"  target="_blank" rel="noopener" >Time Profiling - Rust and WebAssembly</a>这章值得再读几次</li>
</ul>
</li>
<li>vercel部署</li>
</ol>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://rustwasm.github.io/docs/book/introduction.html"  target="_blank" rel="noopener" >Rust and WebAssembly</a></li>
<li><a href="https://playgameoflife.com/"  target="_blank" rel="noopener" >Play John Conway’s Game of Life</a> 目前发现的最好的一个game of life实现</li>
<li><a href="https://github.com/shalzz/wasm-game-of-life"  target="_blank" rel="noopener" >shalzz/wasm-game-of-life: Game of Life implementation using Rust, Javascript and WebAssembly!</a></li>
<li><a href="https://vercel.com/docs/projects/overview#ignored-build-step"  target="_blank" rel="noopener" >Projects Overview | Vercel Docs</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>再想一下</title>
      <link>https://ds63.eu.org/2023/one-more-think/</link>
      <pubDate>Tue, 19 Sep 2023 12:50:11 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/one-more-think/</guid>
      <description>深思熟虑 优柔寡断 不假思索 草率行事</description>
      <content:encoded><![CDATA[<h2 id="感受与感想">感受与感想</h2>
<p>我博客有两个标签：“感受” 与“感想”。某一天我自己看到后一愣，这两有啥区别啊。好像大差不差。</p>
<p><em>再想一下</em></p>
<p>区别还是有的，“感受”偏向于看到、察觉到的某种事情的第一个瞬间时，脑子以及身体做出的第一反应；而“感想”可能是事情发生一段时间后，再去想这件事情。</p>
<p>这个解释是我自己瞎琢磨的，不一定对，但有用。因为这让我以为的博客标签的bug变成了一个feature。</p>
<h2 id="套壳国产">套壳国产</h2>
<p>某天刷到个帖子，是一个程序员在吐槽自己学了MySQL，Tomcat等知识，但是甲方要求其使用国产的工具，而他觉得这些所谓国产，很多都只是套了层皮，却就要额外收取很可观的费用。</p>
<p>我的第一感受是觉得可耻，一下子就联想到了某款编辑器。</p>
<p><em>再想一下</em></p>
<p>从法律层面，基于开源工具所使用的许可证的不同，这种套壳行为可能合法、也可能不合法。但敢拿出来收费，我想人家肯定有去研究相关的发条，这个不是我的专业，也不了解。</p>
<p>从买卖双方的层面：甲方出于各种各样的考虑，有使用国产工具的需求，而乙方正适应了这种需求。周瑜打黄盖，这点也不能多说什么。</p>
<p>从价值层面，如果这种套壳背后附加的是一定时间的售后服务，那可以理解为是在卖服务，这也能理解。</p>
<p>从开源社区的层面来说，我一直以来都只是使用者，没有贡献过多少代码，也没有深度参与过。不理解的东西我也不能多说什么。</p>
<p>但对我来说，我还是觉得可耻。因为至少我在使用别人的代码时，最终的成品我会去删掉那些不必要的东西，但是会声明我这个项目参考了、使用了别人的代码，我觉得这是一种起码的尊重。</p>
<h2 id="智感支付">智感支付</h2>
<p>某天刷到个视频，有人拿着扫码枪的照片对准某款手机，这个手机所宣传的智感支付也能起作用。下面的评论有对隐私的担忧，说是前置摄像头一直开着太恐怖啦。</p>
<p>我的第一感受是是诶，好像确实是这么回事。</p>
<p><em>再想一下</em></p>
<p>手机摄像头一直开着这个论断感觉是站不住脚的。我自己猜了下：第一：这应该会带来相当的耗电量，用户应该能察觉得到。第二：完全有更好的实现方法：比如加个距离传感器之类的，只有一定距离才会去检测。</p>
<p>但话说回来，不管怎么样的实现，肯定都会使得前置摄像头的使用率一定程度上提高。而至于隐私问题，我觉得作为一项可选功能，用户开启了也说明其接受了相应可能的风险，愿意去牺牲可能的一些东西来换取相对的便利性。</p>
<p><em>再再想一下</em></p>
<p>如果可能，我会不会去用这个功能。我想我应该不会，至少短期内不会。我现在的想法是觉得：支付不能太便捷，太便捷容易让我不知不觉就想多花钱。一定的麻烦能让我有更多的时间去打消可能的不必要的消费念头。</p>
<p><em>再再再想一下</em></p>
<p>说到支付的便捷性，我觉得扫码支付是一种为了普及度的tradeoff，而能够使用扫码机的场所，使用NFC这种碰一下就能支付的方式我觉得就挺好。</p>
<p><em>再再再再想一下</em>
扫码支付和nfc支付哪个好？我觉得各有各的优势。像地铁，nfc就远比扫码来得方便快捷。但对于小摊小贩。扫码支付对商家的成本相对较低（打印块牌子就行），还支持并发。</p>
<h2 id="手环测心跳">手环测心跳</h2>
<p>某天看到的某个视频：有人将不同品牌的手环拿去绑在香肠还是水杯上，让其测心跳，从而比较品牌的优劣。</p>
<p>这个我第一眼觉得很弱智。要比较谁优谁劣更好的方式应该是在实际使用中去比较精准度、续航能力等参数。而不是像这样哗众取宠。</p>
<p><em>再想一下</em></p>
<p>我还是不太喜欢这种做法，但我觉得这个视频还是有其意义的，如果不去以此比较优劣。</p>
<ul>
<li>比如开发人员看到了，可能会想我需要加个检测功能，保证只有戴在手上的时候才去检测。</li>
<li>比如我这种普通消费者看到了，我会想：诶，这说明了这几款手环用的检测机制是不一样的，同样一种功能，可以不同方式去实现，还蛮有意思的。</li>
</ul>
<h2 id="预制菜">预制菜</h2>
<p>某段时间预制菜的话题讨论度很高，我刚开始也蛮反感预制菜，觉得这个词背后代表了不健康，不卫生，不好吃。</p>
<p><em>再想一下</em></p>
<p>真的不健康吗？可能。一道菜品加工后被装袋，然后需要保证能存放相当一段时间，应该会是需要某种防腐技术。我只是个普通的消费者，我基于自身的生活经历，对这方面有一定的担忧。而这担忧可能合理，也可能不合理。</p>
<p>真的不好吃吗？不清楚。我没有做过预制菜和非预制菜的双盲实验，我的味蕾也不是相当灵敏。</p>
<p>真的不卫生吗？分情况。我自己家做饭都难保一定卫生，而那些苍蝇馆子，外卖小店我觉得更难以保证。如果预制菜是由一定规模的厂家去生产，遵照相应的合格的标准，我觉得卫生方面应该可以放心。</p>
<p>所以我的想法是不能去过度妖魔化预制菜。它可以是一种选择。</p>
<p>你问我吃不吃？相对来说更便宜，更卫生，那我肯定会接受。</p>
<h2 id="诡辩">诡辩</h2>
<h3 id="诡辩一">诡辩一</h3>
<p>有这样一种说法,说是拦着你不去干某件事是为了你好。你硬要去做的话，就像是明知道屎难吃而非要去尝尝一样。</p>
<p>听完我竟无言以对。</p>
<p><em>再想一下</em></p>
<p>我之前不知道该怎么反驳，现在有思路了。</p>
<p>我知道屎难吃，是可以从其气味，外观，产生方式推断得到的。但其它事情，当我缺乏足够能说明自己不去做某件事的理由时，我就更偏向于去试试。</p>
<h3 id="诡辩二">诡辩二</h3>
<p>有这样一种应对批评者的话：你行你上啊！答曰：我评价一个冰箱，难道还需要会制冷吗？</p>
<p>有道理哦</p>
<p><em>再想一下</em></p>
<p>我觉得评价得分情况。</p>
<p>冰箱不制冷，我作为一个消费者，去批评它是我的权利。</p>
<p>但一些专业的领域，我作为一个门外汉，那我自然也没啥资格去评价。类似的观点我在<a href="https://ds63.eu.org/2023/%E6%88%91%E7%9C%8B-lk-99/"  target="_blank" rel="noopener" >我看 LK-99 | EuDs&rsquo;s Blog</a>谈过了，此处不再拓展。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>由Unity收费想到的</title>
      <link>https://ds63.eu.org/2023/reason-for-boycott-unity/</link>
      <pubDate>Fri, 15 Sep 2023 15:59:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/reason-for-boycott-unity/</guid>
      <description>Long may the Free Software Movement!</description>
      <content:encoded><![CDATA[<p><em>Unity宣布收取安装费这件事自9月12日引发许多讨论，我的想法也有一定的改变</em></p>
<h2 id="开始">开始</h2>
<p>我是认可收费的，原因有：</p>
<ol>
<li>游戏开发人员使用了Unity的服务，并以此盈利，那就应该支付相应的费用。</li>
<li>收费是有一定门槛的，这个门槛在我看来似乎还挺高？</li>
</ol>
<h2 id="了解">了解</h2>
<p>我发现反对的言论明显多于支持或者中立的言论，就决定自己去了解。</p>
<p>从<a href="https://blog.unity.com/news/plan-pricing-and-packaging-updates"  target="_blank" rel="noopener" >Unity的官方网站</a>，我了解到：</p>
<ol>
<li>Unity已经有相关的收费：Unity Plus、Unity Pro	等等</li>
<li>新的收费内容是按照New installs per month进行收费，这个我觉得很不合理。
<ul>
<li>如何知道用户安装了几次</li>
<li>如何防止恶意安装导致开发人员蒙受不必要的损失事件的发生。</li>
</ul>
</li>
</ol>
<h2 id="游戏开发人员的观点">游戏开发人员的观点</h2>
<p>Unity的收费标准对于person和Enterprise是有区别的，而且相当大。person是$0.2 per new install,而Enterprise甚至可以低到$0.01。所以我也分开来调查。</p>
<h3 id="有一定体量的公司">有一定体量的公司</h3>
<p>以下是<a href="https://garry.net/posts/unity-can-get-fucked"  target="_blank" rel="noopener" >Unity can get fucked</a>的部分摘抄，作者是Garry&rsquo;s Mod的创作者。</p>
<blockquote>
<p>Let me be clear.. the cost isn&rsquo;t a big issue to us. If everything worked out, the tracking was flawless and it was 10p per sale, no biggy really. If that&rsquo;s what it costs, then that&rsquo;s what it costs.</p>
</blockquote>
<p><strong>这个收费是他们可承受的，甚至似乎可以说是无伤大雅</strong></p>
<blockquote>
<p>It hurts because we didn&rsquo;t agree to this. We used the engine because you pay up front and then ship your product. We weren&rsquo;t told this was going to happen. We weren&rsquo;t warned. We weren&rsquo;t consulted.</p>
</blockquote>
<blockquote>
<p>We have spent 10 years making Rust on Unity&rsquo;s engine. We&rsquo;ve paid them every year. And now they changed the rules.</p>
</blockquote>
<p><strong>指出愤怒点：未经提前告知、商讨，就更改条款</strong></p>
<blockquote>
<p>We had 10 years to make our own engine and never did. I&rsquo;m sure a lot of game companies are feeling the same today.</p>
</blockquote>
<p><strong>后悔没有做自己的引擎</strong></p>
<h3 id="个人制作者">个人制作者</h3>
<p><a href="https://www.youtube.com/watch?v=1jKVt98fgEY"  target="_blank" rel="noopener" >Unity Ruined Their Game Engine Forever</a>里举了这样一个例子：</p>
<p>有些独立游戏开发者制作了一些小游戏，下载量高达数百万，但游戏中的广告系统或者收费内容没办法cover所需要支付的安装费，那就会变成一个很荒谬的情况：因为游戏受欢迎而破产。</p>
<h2 id="引申">引申</h2>
<p><a href="https://www.youtube.com/watch?v=1jKVt98fgEY"  target="_blank" rel="noopener" >Unity Ruined Their Game Engine Forever</a>里还有一句我很喜欢:</p>
<blockquote>
<p>the beauty of Open Source is it&rsquo;s not run by one scumbag company that can absolutely decide to bring this any time day in shape you can just download this engine and start working on your project.</p>
</blockquote>
<p>这里我就想到GNU和自由软件运动，高瞻远瞩了。</p>
<h2 id="我的收获">我的收获</h2>
<p>我并不是一个游戏开发者，只是一个臭打游戏的，一个还没有真正踏进社会的学生。</p>
<p>所以刚开始看到这件事情，我也没有思考、了解太多，仅靠自己的判断就给这件事情下了定论，甚至站了立场。</p>
<p>但随着了解的深入，我的想法可以说是发生反转性的变化。我想很多事也是如此。</p>
<p>所以这件事给我最大的收获是：在不了解一件事之前不能往下定论。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>暑期项目的感悟</title>
      <link>https://ds63.eu.org/2023/%E6%9A%91%E6%9C%9F%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%84%9F%E6%82%9F/</link>
      <pubDate>Wed, 13 Sep 2023 16:00:12 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%9A%91%E6%9C%9F%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%84%9F%E6%82%9F/</guid>
      <description>没有银弹</description>
      <content:encoded><![CDATA[<p>这次暑期学校的一个月时间都是用来开发一个项目。说是一个月，但实际用来编码的时间大约在三个星期。更具体的时间是早上八点半到下午五点半。最后这一个礼拜晚上也会拿来编码。</p>
<p>三个礼拜的时间说多不多，但这种经历倒是少有，踩了不少坑，也有不少收获，这里记录一下。</p>
<h2 id="学习新技术">学习新技术</h2>
<p>这次用的几个技术栈都是之前没有接触过的：前端React，后端Flask。项目后期还引入了Redux和useSWR。</p>
<p>我对学习新技术倒是蛮有热情，之所以选用这些也是出于想尝试些之前所没有接触过的事物。并且这次用到的技术栈，上手也都是比较容易的，除了Redux现在还是云里雾里，所以整体的开发体验下来并不会因为都是自己没接触过的技术而寸步难行。</p>
<p>但我还是发现了一个蛮大的问题：因为要赶最后的ddl，所以比较偏向于急于求成，看了看用法和示例就开始写了，虽然最后也确实能写出点东西，但总有种半生不熟的感觉，没有一种确确实实掌握的踏实感。</p>
<p>我还意识到，一个人的时间和精力是有限的，而技术却是日新月异的。所谓庄子所说的：吾生也有涯，而知也无涯。所谓贪多嚼不烂，就是这个道理。</p>
<h2 id="dry与aha">DRY与AHA</h2>
<p>这次项目中，后端几乎是我在负责的。但就是这样一个自己在开发的两千行左右的代码，到第三周的时候就还是偶尔会冒出想推倒重写某个部分的想法。</p>
<p>尤其是action这个部分。在这个项目中，我将用户收藏、评分、评论这三个功能抽象成一个action。自己刚开始写的时候还有点沾沾自喜，认为自己是做到了合理的内聚。</p>
<p>但后来却发现其中的弊端：当我想单独修改其中某一部分，因为其耦合性，导致我需要修改一些本不需要修改的代码。而到了项目后期，前端已经和后端对接已经完成百分之八九十。这时候修改一个核心功能，可谓是牵一发而动全身。改是能改，但是却不敢改，因为承担不起所需的时间成本。最后的解决方式是另外又写了几个方法，这就导致代码变得很丑。这时候就真切体验到了垒屎山是一种什么样的心情了。</p>
<p>回顾过去，思考如何在以后能尽量避免这种情况，我想有两个原则可能会起作用：</p>
<ol>
<li>DRY
&ldquo;Don&rsquo;t repeat yourself&quot;的缩写。我虽然有意识去将一些常用的代码封装为一个方法。但还是有不少代码，我选择了直接复制粘贴原有可用代码，并在其基础上进行些许修改。这样子固然省事，写的时候也很畅快，但后期想要修改时，却就要之前的偷懒付出相当的代价。而如若我之前多花些时间，将其封装，这样我的代码也就更方便修改。</li>
<li>AHA
&ldquo;avoid hasty abstractions&quot;的缩写。这个原则让我不禁想到一句话&quot;premature optimization is root of all evil&rdquo;。还是以action为例，如果我在将三个操作耦合成一个时多想一想，那会好许多。但话又说回来，怎么样才算是不仓促，怎么样才算不是过早。我觉得现阶段的我还是缺乏经验，所以下次遇到类似的情况时，我想我大概率还是会为自己的某个小聪明而沾沾自喜，并毫不犹豫地踏进给自己挖的又一个坑。</li>
</ol>
<h2 id="项目流程">项目流程</h2>
<p>这次的流程是采用瀑布模式，相比于上学期所使用的Scrum总觉得不得劲。我个人感觉最大的差异是在项目前期，连续多天都是花在写一些比较虚的文档。而这些文档：需求文档，设计文档之类，我们这几个甚至连初出茅庐都还不算的新人，没办法考虑得那么周到。而且多日时间上的付出只是一些文字，这样的体验感实在不好。</p>
<p>总的来说，这样的经历在我的学生阶段中算是比较一个独特的经历，一个月的时间也没有怎么白白浪费掉，对自己还是较为满意的。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>React学习经历</title>
      <link>https://ds63.eu.org/2023/learn_react/</link>
      <pubDate>Tue, 12 Sep 2023 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/learn_react/</guid>
      <description>记录学习React的经历，按日期进行排序，会比较乱</description>
      <content:encoded><![CDATA[<h2 id="2023年9月12日">2023年9月12日</h2>
<p>这两个多星期来几乎都是在写React，现在对它算是又爱又恨。</p>
<h3 id="爱">爱</h3>
<p>逻辑很舒服，虽然我新接触，但几乎就是很自然而然地就能开始写了。</p>
<h3 id="恨">恨</h3>
<p>说恨可能有点过了，但确实遇到了好些坑，耗了好些时间。</p>
<ol>
<li>
<p><code>useEffect</code></p>
<p>看了<a href="https://blog.skk.moe/post/why-you-should-not-fetch-data-directly-in-use-effect/"  target="_blank" rel="noopener" >为什么你不应该在 React 中直接使用 useEffect 从 API 获取数据 | Sukka&rsquo;s Blog</a>后转而使用封装好的useSWR,现在体验感很好。</p>
</li>
<li>
<p><code>useParams()</code>获取不到参数</p>
<p>这个是我没仔细看文档，想当然了.文档中说得很明白:</p>
<blockquote>
<p>Returns an object of key/value pairs of the dynamic params from the current URL that were matched by the route path.</p>
</blockquote>
<p>而我一开始是在Route之外去<code>useParams()</code>，最后的解决方式是，在原本的组件外套一层wrapper，这样来实现左右栏的效果</p>
</li>
<li>
<p><code>Rendered more hooks than during the previous render.</code></p>
<p>这也是个花了我许久的报错。最头疼的是不知道是代码哪里的问题。在<a href="https://stackoverflow.com/questions/55622768/uncaught-invariant-violation-rendered-more-hooks-than-during-the-previous-rende"  target="_blank" rel="noopener" >stackoverflow上的一个回答</a>的解释下，才明白可能问题出在return和useEffect执行顺序的问题。</p>
</li>
<li>
<p>Redux，虽然用起来了，但现在还是懵懵的，还是得再看文档</p>
</li>
</ol>
<h3 id="总结">总结</h3>
<p>因为要赶最后的ddl，所以比较偏向于急于求成，看了看用法和示例就开始写了，虽然最后确实能写出点东西，但总有种半生不熟的感觉。</p>
<p>这样做还有一个很大的弊端：我跟着示例文档和ai的提示，照猫画虎写出一个能用的东西，后面为了效率，我就会直接去复用这个东西，或者在其基础上稍微修改。</p>
<p>代码的可复用性当然是件好事。但问题是我最开始糊出来的那个其实不一定就是好的。但如果我能在了解、学习了一定基础上再去写，成品会好很多。</p>
<p>我感觉一个比较理想的状态是：先学百分五六十，然后再去用。用的过程同时也加深理解。</p>
<hr>
<h2 id="2023年9月14日">2023年9月14日</h2>
<p>看了<a href="https://react.dev/learn/thinking-in-react"  target="_blank" rel="noopener" >Thinking in React</a>,记录一下</p>
<ul>
<li>
<p>Which of these are state? Identify the ones that are not:</p>
<ol>
<li>Does it remain unchanged over time? If so, it isn’t state.</li>
<li>Is it passed in from a parent via props? If so, it isn’t state.</li>
<li>Can you compute it based on existing state or props in your component? If so, it definitely isn’t state!</li>
</ol>
<p><em>What’s left is probably state.</em></p>
</li>
<li>
<p>For each piece of state in your application:</p>
<ol>
<li>Identify every component that renders something based on that state.</li>
<li>Find their closest common parent component -&gt; a component above them all in the hierarchy.</li>
<li>Often, you can put the state directly into their common parent.</li>
<li>You can also put the state into some component above their common parent.</li>
<li>If you can’t find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component.</li>
</ol>
</li>
</ul>
<hr>
<h2 id="2024年2月28日">2024年2月28日</h2>
<p>最近的一个小玩具<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid</a>有轻量级的状态管理需求，权衡下决定使用<a href="https://jotai.org/"  target="_blank" rel="noopener" >Jotai, primitive and flexible state management for React</a>,开始的体验很不错。</p>
<p>我先做好了<code>./work/page</code>这个组件。接下来我希望实现类似于Postman的多标签页。每个标签页都是用同样的组件，但它们互相独立。</p>
<p>本来这并不是件难事，但因为我之前偷懒，高度依赖jotai的atom来做状态管理,因此花了好些时间。</p>
<p>先尝试了<a href="https://github.com/jotaijs/jotai-scope"  target="_blank" rel="noopener" >jotaijs/jotai-scope</a>,它给的示例确实符合我的需求，但当标签切走再切回去的时候，原来的状态就被重置了，我找不到问题所在，放弃。</p>
<p>中途多次问ChatGPT和Gemini，都是一开始看着很可行，然后实际不行，再问就开始重复之前的回答了。</p>
<p>最后是靠<a href="https://devv.ai/zh"  target="_blank" rel="noopener" >Devv</a>解决的，它说<a href="https://jotai.org/docs/utilities/family"  target="_blank" rel="noopener" >Jotai的atomFamily</a>能解决。<code>atomFamily</code>允许创建一组相关的原子，并为每个实例提供一个唯一的标识符。一试,确实可行。</p>
<p>现在再看我的实现，感觉还是比较简陋的。每个标签页对应一个特定的<code>tagId</code>，然后<code>atomFamily</code>就是&quot;a Map whose key is a param and whose value is an atom config&quot;。</p>
<hr>
<h2 id="2024年3月4日">2024年3月4日</h2>
<ul>
<li>
<p><a href="https://react.dev/reference/react/useCallback"  target="_blank" rel="noopener" >useCallback – React</a></p>
<ol>
<li><code>useCallback</code> is a Hook, so you can only call it at the top level of your component or your own Hooks.</li>
<li><code>useCallback</code> caches a <strong>function</strong> between re-renders until its dependencies change</li>
<li>usage:Skipping re-rendering of components</li>
<li><code>useMemo</code> caches the <strong>result</strong> of calling your function</li>
<li>The only benefit to <code>useCallback</code> is that it lets you avoid writing an extra nested function inside. It doesn’t do anything else.</li>
</ol>
</li>
<li>
<p><a href="https://prin.pw/react-unstable-nested-components/"  target="_blank" rel="noopener" >真的不可以在 React 组件内部嵌套定义子组件吗？ - PRIN BLOG</a></p>
<ul>
<li>永远不要在 React 组件内部嵌套定义子组件。</li>
<li>「渲染函数」和「函数组件」的区别:
<ol>
<li>渲染函数虽然和组件一样都返回 JSX，但它不是组件；</li>
<li>渲染函数就是普通 JavaScript 函数，没有状态，也没有对应的 Fiber 节点；</li>
<li>渲染函数只是当前组件的一部分，对于 React 渲染来说没有额外开销；</li>
<li>渲染函数内部<strong>不能</strong>使用 Hooks，只有组件内部才能使用 Hooks；</li>
<li>渲染函数命名一般以 render 开头，首字母小写（否则容易和组件搞混）</li>
<li>调用方式</li>
</ol>
</li>
<li><a href="https://github.com/shuding/tilg"  target="_blank" rel="noopener" >shuding/tilg: A magical React Hook that helps you debug components.</a>可以用来展示组件生命周期。</li>
</ul>
</li>
<li>
<p>报错：<code>useEffect</code> is called conditionally</p>
<p>完整报错如下:</p>
<blockquote>
<p>React Hook &ldquo;useEffect&rdquo; is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks</p>
</blockquote>
<p>解决方法很简单，只需将useEffect调用移动到组件的顶层，并使用条件语句来决定是否执行其内部的逻辑即可。</p>
</li>
<li>
<p><a href="https://react.dev/learn/render-and-commit"  target="_blank" rel="noopener" >Render and Commit – React</a></p>
<ul>
<li>在 React 中，每次更新都分为 两个阶段：
<ol>
<li>在 渲染 阶段， React 调用你的组件来确定屏幕上应该显示什么。</li>
<li>在 提交 阶段， React 把变更应用于 DOM。</li>
</ol>
</li>
<li>Process of requesting and serving UI has three steps:
<ol>
<li>Triggering a render</li>
<li>Rendering</li>
<li>Committing to the DOM</li>
</ol>
</li>
<li>Two reasons for a component to render:
<ol>
<li>It’s the component’s initial render.</li>
<li>The component’s (or one of its ancestors’) state has been updated.</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2024年3月5日">2024年3月5日</h2>
<ul>
<li><a href="https://www.developerway.com/posts/components-composition-how-to-get-it-right"  target="_blank" rel="noopener" >Developer Way: React components composition: how to get it right</a>
<ul>
<li>The core React development and decomposition rules:
<ol>
<li>always start implementation from the top</li>
<li>extract components only when there is an actual need for it</li>
<li>always start from “simple” components, introduce other composition techniques only when there is an actual need for them</li>
</ol>
</li>
<li>A component should be described either as a “component that implements various stuff” or as a “component that composes various components together”, not both.</li>
<li>Extract Container components when there is a need to share some visual or behavioural logic that wraps elements that still need to be under “consumer” control</li>
<li>What makes a good component?
<ol>
<li>易读</li>
<li>命名清晰准确</li>
<li>doesn’t do things that are irrelevant to its declared purpose</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2024年3月6日">2024年3月6日</h2>
<ul>
<li>
<p><a href="https://legacy.reactjs.org/docs/composition-vs-inheritance.html#containment"  target="_blank" rel="noopener" >Composition vs Inheritance – React</a></p>
<ul>
<li>&ldquo;children&rdquo; is just a prop. The fancy “composition” pattern that we use is a syntax sugar.</li>
<li>Inheritance is not recommended. If you want to reuse non-UI functionality between components, we suggest <strong>extracting it into a separate JavaScript module</strong>. The components may import it and use that function, object, or class, without extending it.</li>
</ul>
</li>
<li>
<p><a href="https://www.developerway.com/posts/react-elements-children-parents"  target="_blank" rel="noopener" >Developer Way: The mystery of React Element, children, parents and re-renders</a></p>
<ul>
<li>Components that are passed as props don’t re-render.</li>
<li>If children are passed as a render function, they start re-rendering.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2024年3月7日">2024年3月7日</h2>
<ul>
<li>读<a href="https://zh-hans.react.dev/reference/react/Fragment"  target="_blank" rel="noopener" ><!-- raw HTML omitted --> (&lt;&gt;&hellip;&lt;/&gt;) – React 中文文档</a>，原来<code>&lt;&gt;</code>是<code>&lt;Fragment</code>的简写。</li>
</ul>
<hr>
<h2 id="2024年3月8日">2024年3月8日</h2>
<ul>
<li>
<p>受控组件 v.s 非受控组件</p>
<ul>
<li>参考<a href="https://muyunyun.cn/blog/56hn38ez"  target="_blank" rel="noopener" >重新认识受控与非受控组件</a></li>
<li>In a controlled component, form data is handled by a React component.</li>
<li>In a uncontrolled component, form data is handled by the DOM itself.</li>
<li>受控以及非受控组件的边界划分取决于当前组件对于子组件值的变更是否拥有控制权。</li>
</ul>
</li>
<li>
<p><a href="https://zh-hans.react.dev/reference/react-dom/components/input#my-input-caret-jumps-to-the-beginning-on-every-keystroke"  target="_blank" rel="noopener" >当我输入时，输入框光标会跳到开头– React 中文文档</a></p>
<blockquote>
<p>有可能是因为每次输入时输入框都从 DOM 中删除并重新添加。同样，如果在每次重新渲染时不小心 重置了 state，就会发生这种情况。例如，如果输入框或其祖先组件总是接收不同的 key，或者嵌套使用组件（这在 React 中是不允许的，并且会导致“内部”组件在每次渲染时重新挂载），就会发生这种情况。</p>
</blockquote>
<p>我在写<a href="https://github.com/EuDs63/postkid"  target="_blank" rel="noopener" >EuDs63/postkid</a>就遇到了这个问题，原来如此。</p>
</li>
</ul>
<hr>
<h2 id="2024年3月9日">2024年3月9日</h2>
<ul>
<li>
<p>redux</p>
</li>
<li>
<p>useContext的使用</p>
</li>
<li>
<p>自定义hook</p>
</li>
</ul>
<hr>
<h3 id="ref">ref</h3>
<ul>
<li>ref 是一个普通的 JavaScript 对象，具有可以被读取和修改的 current 属性。</li>
<li><a href="https://zh-hans.react.dev/learn/referencing-values-with-refs#differences-between-refs-and-state"  target="_blank" rel="noopener" >ref 和 state 的不同之处</a>
<ol>
<li>更改不会触发渲染</li>
<li>无set</li>
<li>可变 —— 你可以在渲染过程之外修改和更新 current 的值。</li>
<li>不应在渲染期间读取（或写入） current 值。</li>
</ol>
</li>
<li>使用时机
<ol>
<li>当一条信息仅被事件处理器需要，并且更改它不需要重新渲染时，使用 ref 可能会更高效。</li>
<li>你的组件需要“跳出” React 并与外部 API 通信时</li>
<li>存储和操作 DOM 元素</li>
<li>存储不需要被用来计算 JSX 的其他对象</li>
</ol>
</li>
<li><code>ref</code>回调函数
<ol>
<li>参考<a href="https://zh-hans.react.dev/reference/react-dom/components/common#ref-callback"  target="_blank" rel="noopener" >ref 回调函数 – React 中文文档</a></li>
<li>不要从 ref 回调函数中返回任何内容。</li>
<li>当回调函数被附加在 ref 属性后，触发回调时，该参数为对应的 DOM 节点。当 ref 被分离时值为 null。除非在每次渲染时都传递相同的函数引用作为 ref 回调，否则该回调将在组件的每次重新渲染期间被暂时分离和重新连接。</li>
</ol>
</li>
<li>默认情况下，React 不允许组件访问其他组件的 DOM 节点:可使用<code>forwardRef</code>,例：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">MyInput</span> <span class="o">=</span> <span class="nx">forwardRef</span><span class="p">((</span><span class="nx">props</span><span class="p">,</span> <span class="nx">ref</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">&lt;</span><span class="nx">input</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">ref</span><span class="p">}</span> <span class="o">/&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
<li><a href="https://zh-hans.react.dev/learn/manipulating-the-dom-with-refs#exposing-a-subset-of-the-api-with-an-imperative-handle"  target="_blank" rel="noopener" >使用命令句柄暴露一部分 API</a></li>
<li>React 在提交阶段设置 <code>ref.current</code>。在更新 DOM 之前，React 将受影响的<code> ref.current</code>值设置为 null。更新 DOM 后，React 立即将它们设置到相应的 DOM 节点。</li>
</ul>
<hr>
<h2 id="2024年3月10日">2024年3月10日</h2>
<h3 id="fiber">Fiber</h3>
<ul>
<li>参考<a href="https://zhuanlan.zhihu.com/p/390409316"  target="_blank" rel="noopener" >React Fiber很难？六个问题助你理解 React Fiber - 知乎</a>
<ul>
<li>一套更新机制,让 React 的更新过程变得可控</li>
<li>栈递归 -&gt; 链表遍历</li>
</ul>
</li>
<li><a href="https://blog.logrocket.com/deep-dive-react-fiber/"  target="_blank" rel="noopener" >A deep dive into React Fiber - LogRocket Blog</a></li>
</ul>
<hr>
<h2 id="2024年3月14日">2024年3月14日</h2>
<ul>
<li>什么hooks不能写在if/else等语句里</li>
<li>你是怎么理解React的？（答得非常烂，建议从数据驱动 ui = f(state)、响应式 fiber + 异步可中断更新、组件化 component，hooks、跨平台 scheduler；reconciler；render；vdom，合成事件系统等方面答）</li>
<li>React18新特性（concurrent）</li>
<li>react有没有什么缺点（能没有缺点吗，死怼运行时，hooks凭啥不能写在if/else里，useXXX到底怎么个use法，过期闭包，依赖全得手动写，如果用eslint那么里面用过的都会要你加到依赖数组里）</li>
<li>react hooks为啥不能写在if/else里（底层实现就是个链表，一个有序的东西）</li>
<li>react hooks能实现类里面的所有生命周期吗</li>
<li>路由怎么做的 什么守卫</li>
</ul>
<hr>
<h2 id="2024年3月21日">2024年3月21日</h2>
<ul>
<li>组件间通信</li>
<li>自定义hook</li>
<li>react hook</li>
<li>react 组件传值</li>
<li>react父组件怎么获取子组件的值   useRef</li>
<li>react provider标签以及其使用原理</li>
<li>react 路由的两种模式</li>
<li>redux
<ul>
<li><a href="https://redux.js.org/tutorials/essentials/part-1-overview-concepts"  target="_blank" rel="noopener" >Redux Essentials, Part 1: Redux Overview and Concepts | Redux</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="2024年3月26日">2024年3月26日</h2>
<h3 id="自定义hook">自定义hook</h3>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzI4NjE3MzQzNg==&amp;mid=2649865889&amp;idx=1&amp;sn=2549fb3da7608aa8e3cce0623fbd8d25"  target="_blank" rel="noopener" >超性感的React Hooks（五）：自定义hooks</a></li>
</ul>
<blockquote>
<p>自定义hook能够跟随函数组件重复执行，并且每次都返回最新结果。因此，我们可以非常放心大胆的封装异步逻辑。</p>
</blockquote>
<ul>
<li>看<a href="https://mp.weixin.qq.com/s/GPcwIPJBc9I_NtixyU-U4Q"  target="_blank" rel="noopener" >超性感的React Hooks（六）自定义hooks的思维方式</a>，摘录其中一段</li>
</ul>
<blockquote>
<p>准确来说，应该是逻辑片段复用。</p>
<p>和组件化思维不同，这是另外一个粒度更细的代码复用思维。例如我们之前提到的，获取同样的数据。在组件化思维中，一个完整的组件，包括了这份数据，以及这份数据在页面上的展示结果。因此这是不同的复用思维。</p>
<p>处理获取数据过程中的公用逻辑，处理公用的登陆逻辑等。自定义hooks封装的大多数情况下不是一个完整的页面逻辑实现，而是其中的一个片段。</p>
</blockquote>
<hr>
<h2 id="2024年4月9日">2024年4月9日</h2>
<p>看<a href="https://dev.to/chandrapantachhetri/responsive-react-file-upload-component-with-drag-and-drop-4ef8"  target="_blank" rel="noopener" >Responsive React File Upload Component With Drag And Drop - DEV Community</a></p>
<p>尤其是“Why are we setting the title and value attribute to &ldquo;&quot;?”这段，之前我看别人的代码这样写还以为是错的，原来是有其独特作用的。</p>
<hr>
<h2 id="2024年4月28日">2024年4月28日</h2>
<ul>
<li><a href="https://juejin.cn/post/7132786097922736164"  target="_blank" rel="noopener" >useEffect(fn, []) 不等于 componentDidMount() - 掘金</a></li>
<li><a href="https://juejin.cn/post/7277917854430674959"  target="_blank" rel="noopener" >React 组件库都是怎么打包？ - 掘金</a></li>
<li><a href="https://react.dev/reference/react/useImperativeHandle"  target="_blank" rel="noopener" >useImperativeHandle – React</a></li>
</ul>
<p>这几篇打开来很久了，一直没看，记录下。</p>
<hr>
<h2 id="2024年5月20日">2024年5月20日</h2>
<ul>
<li>参考
<ul>
<li><a href="https://react.dev/reference/react/forwardRef"  target="_blank" rel="noopener" >forwardRef – React</a></li>
<li><a href="https://react.dev/reference/react/useImperativeHandle"  target="_blank" rel="noopener" >useImperativeHandle – React</a></li>
<li><a href="https://www.telerik.com/blogs/react-basics-how-to-use-forwardref"  target="_blank" rel="noopener" >React Basics: How to Use ForwardRef</a></li>
</ul>
</li>
<li>forwardRef lets your component expose a DOM node to parent component with a ref.</li>
<li>useImperativeHandle is a React Hook that lets you customize the handle exposed as a ref.
<code>useImperativeHandle(ref, createHandle, dependencies?)</code></li>
</ul>
<hr>
<h2 id="2024年9月21日">2024年9月21日</h2>
<ul>
<li><a href="https://blog.huli.tw/2024/03/13/from-react-to-vue/#%E5%9C%A8%E9%96%8B%E5%A7%8B%E4%B9%8B%E5%89%8D"  target="_blank" rel="noopener" >從 React 到 Vue 的心得感想 - Huli&rsquo;s blog</a></li>
</ul>
<hr>
<h2 id="2024年10月11日">2024年10月11日</h2>
<p>读<a href="https://github.com/paul-ll/my_book/blob/master/React%E5%AE%9E%E6%88%98%EF%BC%9A%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%92%8C%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/%E7%BB%84%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%882%EF%BC%89%EF%BC%9A%E9%AB%98%E9%98%B6%E7%BB%84%E4%BB%B6.md"  target="_blank" rel="noopener" >my_book/React实战：设计模式和最佳实践/组件设计模式（2）：高阶组件.md at master · paul-ll/my_book</a></p>
<p>摘录其中内容作为我的笔记</p>
<ul>
<li>
<p>高阶组件的定义:</p>
<ul>
<li>一个纯函数</li>
<li>接收组件作为参数</li>
<li>返回一个新的组件</li>
<li>高阶组件的命名一般都带 with 前缀，命名中后面的部分代表这个高阶组件的功能</li>
</ul>
</li>
<li>
<p>示例</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JSX" data-lang="JSX"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">withLoginAndLogout</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ComponentForLogin</span><span class="p">,</span> <span class="nx">ComponentForLogout</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">NewComponent</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">getUserId</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">&lt;</span><span class="nt">ComponentForLogin</span> <span class="p">{</span><span class="na">...props</span><span class="p">}</span> <span class="p">/&gt;;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">&lt;</span><span class="nt">ComponentForLogout</span><span class="p">{</span><span class="na">...props</span><span class="p">}</span> <span class="p">/&gt;;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">NewComponent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">TopButtons</span> <span class="o">=</span> <span class="nx">withLoginAndLogout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">LogoutButton</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">LoginButton</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div><hr>
<h2 id="2024年10月17日">2024年10月17日</h2>
<p>react的单向数据流怎么理解，有什么好处？</p>
<ul>
<li>
<p>数据流：也就是数据在不同组件或节点之间的流动</p>
</li>
<li>
<p>单向:  react规定了数据的流向是从外层组件向内层组件进行传递和更新的，而内层组件是无法直接修改props影响外层的。</p>
</li>
<li>
<p>好处:</p>
<ol>
<li>如果内层的组件可以通过修改props来修改外层的数据，那么外层使用到这个数据或者其他使用到这个数据的地方都会造成数据更新，UI渲染也会改变，这会造成数据紊乱和不可控。所以为了<strong>更好的可控性</strong>，react设计了单向数据流。</li>
<li>所有的数据更新是单向的，那么出现问题的时候会更好溯源，因为修改数据的链路是确定的，排查起来顺着调用链就可以一层一层找到问题了。</li>
</ol>
</li>
<li>
<p>引申</p>
<ul>
<li>useContext</li>
<li>forwardRef, useImperativeHandle</li>
</ul>
</li>
<li>
<p>参考</p>
<ul>
<li><a href="https://www.nowcoder.com/feed/main/detail/04aee48cc23f4b09a04d0dba327f0c5d?sourceSSR=search"  target="_blank" rel="noopener" >70场面试，复盘我遇到的有趣问题（二）_牛客网</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://blog.skk.moe/post/why-you-should-not-fetch-data-directly-in-use-effect/"  target="_blank" rel="noopener" >为什么你不应该在 React 中直接使用 useEffect 从 API 获取数据 | Sukka&rsquo;s Blog</a></li>
<li><a href="https://stackoverflow.com/questions/55622768/uncaught-invariant-violation-rendered-more-hooks-than-during-the-previous-rende"  target="_blank" rel="noopener" >javascript - Uncaught Invariant Violation: Rendered more hooks than during the previous render - Stack Overflow</a></li>
<li><a href="https://jotai.org/"  target="_blank" rel="noopener" >Jotai, primitive and flexible state management for React</a></li>
<li><a href="https://prin.pw/react-unstable-nested-components/"  target="_blank" rel="noopener" >真的不可以在 React 组件内部嵌套定义子组件吗？ - PRIN BLOG</a></li>
<li><a href="https://react.dev/reference/react/useCallback"  target="_blank" rel="noopener" >useCallback – React</a></li>
<li><a href="https://blog.skk.moe/post/react-re-renders-101/"  target="_blank" rel="noopener" >React 为什么重新渲染 | Sukka&rsquo;s Blog</a></li>
<li><a href="https://react.dev/learn/render-and-commit"  target="_blank" rel="noopener" >Render and Commit – React</a></li>
<li><a href="https://zh-hans.react.dev/reference/react/Fragment"  target="_blank" rel="noopener" ><!-- raw HTML omitted --> (&lt;&gt;&hellip;&lt;/&gt;) – React 中文文档</a></li>
<li><a href="https://zh-hans.react.dev/learn/referencing-values-with-refs#differences-between-refs-and-state"  target="_blank" rel="noopener" >使用 ref 引用值 – React 中文文档</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>换域名喽</title>
      <link>https://ds63.eu.org/2023/%E6%8D%A2%E5%9F%9F%E5%90%8D%E5%96%BD/</link>
      <pubDate>Thu, 17 Aug 2023 23:50:11 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%8D%A2%E5%9F%9F%E5%90%8D%E5%96%BD/</guid>
      <description>更换域名为ds63.eu.org</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>我博客有相当一段时间，一直是使用默认的域名。而且我其实并不太想去修改，原因是我博客使用的是Github Page。我想信：背靠着微软，GitHub所提供的这项服务的可靠性会比我私人所申请的域名要可靠得多。而我一直秉持着这样一个观点：一个博客的死亡并不是其不再更新，而是无法访问。也就是说，我认为博客的持续性是要优先于其他很多方面的。</p>
<p>但今天意外发现邮箱里有封邮件，通知我说申请的域名通过了。十分惊喜，因为我已经忘了这件事了。既然手头上有一个域名，上学期也学了相关的知识，干脆就试一试，在此次梳理下相应的步骤。</p>
<h2 id="步骤">步骤</h2>
<ol>
<li>
<p>申请/购买域名</p>
<p>我使用的是<a href="https://nic.eu.org/"  target="_blank" rel="noopener" >EU.org</a>。好处是免费，但所需时间很长。我在5月27日申请的，直到昨天（8月16日）才通过。</p>
</li>
<li>
<p>选择域名解析服务商</p>
<p>我选择的是<a href="https://hostry.com/"  target="_blank" rel="noopener" >hostry</a>,原因是免费。</p>
</li>
<li>
<p>Navigate to your DNS provider and create either an ALIAS, ANAME, or A record.</p>
<p>以下是我设置中的一部分：</p>
<table>
<thead>
<tr>
<th>SUBDOMAIN</th>
<th>TYPE</th>
<th>VALUE</th>
<th>TTL, SEC</th>
</tr>
</thead>
<tbody>
<tr>
<td>@</td>
<td>A</td>
<td>185.199.108.153</td>
<td>86400</td>
</tr>
<tr>
<td>@</td>
<td>AAAA</td>
<td>2606:50c0:8000::153</td>
<td>86400</td>
</tr>
<tr>
<td>www</td>
<td>CNAME</td>
<td>euds63.github.io</td>
<td>86400</td>
</tr>
</tbody>
</table>
</li>
</ol>
<p>在Claude的帮助下，我知道：</p>
<ul>
<li>A记录(Address Record):将域名直接映射到一个IPv4地址。它是最基本的域名记录类型。GitHub提供了4个IP地址,而不是一个IP,主要出于负载均衡和容错的考虑</li>
<li>AAAA记录(Quad-A record):用于将域名映射到IPv6地址。</li>
<li>CNAME记录(Canonical Name Record):将域名映射到另一个域名,实现域名别名的作用</li>
</ul>
<p>值得注意的是<code>www CNAME euds63.github.io 86400</code>，我看到其他的教程有的是将SUBDOMAIN设置为<code>@</code>,但我的情况下会报错<code>Existing record 'SOA' conflicts with the code you are trying to create Cname should not have the same name as other records</code></p>
<ol start="4">
<li>Github配置
<ul>
<li>Under &ldquo;Custom domain&rdquo;, type your custom domain, then click Save.</li>
<li>勾选Enforce HTTPS</li>
</ul>
</li>
</ol>
<p><strong>很明显，这里Github帮我们简化了许多操作。包括哪些呢?</strong></p>
<p>由<a href="https://docs.github.com/en/pages/getting-started-with-github-pages/securing-your-github-pages-site-with-https"  target="_blank" rel="noopener" >Securing your GitHub Pages site with HTTPS</a>可知，当set or change your custom domain in the Pages setting后，GitHub</p>
<ol>
<li>begin an automatic DNS check . This check determines if your DNS settings are configured to allow GitHub to obtain a certificate automatically.</li>
<li>If the check is successful, GitHub queues a job to request a TLS certificate from Let&rsquo;s Encrypt.</li>
<li>On receiving a valid certificate, GitHub automatically uploads it to the servers that handle TLS termination for Pages. When this process completes successfully, a check mark is displayed beside your custom domain name.</li>
</ol>
<p><strong>但如果不是用的Github Page，要怎么做呢？</strong></p>
<h2 id="验证">验证</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ ping ds63.eu.org
</span></span><span class="line"><span class="cl">正在 Ping ds63.eu.org <span class="o">[</span>185.199.108.153<span class="o">]</span> 具有 <span class="m">32</span> 字节的数据:
</span></span><span class="line"><span class="cl">来自 185.199.108.153 的回复: <span class="nv">字节</span><span class="o">=</span><span class="m">32</span> <span class="nv">时间</span><span class="o">=</span>77ms <span class="nv">TTL</span><span class="o">=</span><span class="m">54</span>
</span></span><span class="line"><span class="cl">来自 185.199.108.153 的回复: <span class="nv">字节</span><span class="o">=</span><span class="m">32</span> <span class="nv">时间</span><span class="o">=</span>103ms <span class="nv">TTL</span><span class="o">=</span><span class="m">54</span>
</span></span><span class="line"><span class="cl">来自 185.199.108.153 的回复: <span class="nv">字节</span><span class="o">=</span><span class="m">32</span> <span class="nv">时间</span><span class="o">=</span>76ms <span class="nv">TTL</span><span class="o">=</span><span class="m">54</span>
</span></span><span class="line"><span class="cl">来自 185.199.108.153 的回复: <span class="nv">字节</span><span class="o">=</span><span class="m">32</span> <span class="nv">时间</span><span class="o">=</span>77ms <span class="nv">TTL</span><span class="o">=</span><span class="m">54</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">185.199.108.153 的 Ping 统计信息:
</span></span><span class="line"><span class="cl">    数据包: <span class="nv">已发送</span> <span class="o">=</span> 4，已接收 <span class="o">=</span> 4，丢失 <span class="o">=</span> <span class="m">0</span> <span class="o">(</span>0% 丢失<span class="o">)</span>，
</span></span><span class="line"><span class="cl">往返行程的估计时间<span class="o">(</span>以毫秒为单位<span class="o">)</span>:
</span></span><span class="line"><span class="cl">    <span class="nv">最短</span> <span class="o">=</span> 76ms，最长 <span class="o">=</span> 103ms，平均 <span class="o">=</span> 83ms
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ ping -6 ds63.eu.org
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">正在 Ping ds63.eu.org <span class="o">[</span>2606:50c0:8001::153<span class="o">]</span> 具有 <span class="m">32</span> 字节的数据:
</span></span><span class="line"><span class="cl">来自 2606:50c0:8001::153 的回复: <span class="nv">时间</span><span class="o">=</span>74ms
</span></span><span class="line"><span class="cl">来自 2606:50c0:8001::153 的回复: <span class="nv">时间</span><span class="o">=</span>81ms
</span></span><span class="line"><span class="cl">来自 2606:50c0:8001::153 的回复: <span class="nv">时间</span><span class="o">=</span>74ms
</span></span><span class="line"><span class="cl">来自 2606:50c0:8001::153 的回复: <span class="nv">时间</span><span class="o">=</span>72ms
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2606:50c0:8001::153 的 Ping 统计信息:
</span></span><span class="line"><span class="cl">    数据包: <span class="nv">已发送</span> <span class="o">=</span> 4，已接收 <span class="o">=</span> 4，丢失 <span class="o">=</span> <span class="m">0</span> <span class="o">(</span>0% 丢失<span class="o">)</span>，
</span></span><span class="line"><span class="cl">往返行程的估计时间<span class="o">(</span>以毫秒为单位<span class="o">)</span>:
</span></span><span class="line"><span class="cl">    <span class="nv">最短</span> <span class="o">=</span> 72ms，最长 <span class="o">=</span> 81ms，平均 <span class="o">=</span> 75ms
</span></span></code></pre></div><h1 id="参考资料">参考资料</h1>
<ul>
<li><a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site"  target="_blank" rel="noopener" >Managing a custom domain for your GitHub Pages site</a></li>
<li><a href="https://www.yong.eu.org/detail/15112.html"  target="_blank" rel="noopener" >GitHub Pages绑定个人域名并启用https</a></li>
<li><a href="https://docs.github.com/en/pages/getting-started-with-github-pages/securing-your-github-pages-site-with-https"  target="_blank" rel="noopener" >Securing your GitHub Pages site with HTTPS</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>我看 LK-99</title>
      <link>https://ds63.eu.org/2023/%E6%88%91%E7%9C%8B-lk-99/</link>
      <pubDate>Thu, 03 Aug 2023 10:38:46 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%88%91%E7%9C%8B-lk-99/</guid>
      <description>遥远的梦？</description>
      <content:encoded><![CDATA[<h1 id="我看lk-99">我看LK-99</h1>
<p>自<a href="https://arxiv.org/abs/2307.12008"  target="_blank" rel="noopener" >The First Room-Temperature Ambient-Pressure Superconductor</a>发表已过去十多天了。可谓是众说纷纭。</p>
<p>我，一个物理水平停留在大二、化学水平局限在高中的会考的普通学生，对超导完全处于是门外汉水平，连科普的内容都没有完全读过。对于这个相当惊人的发现，或者再推广出去，对于自己不懂的领域，我一直秉持着不懂就不要乱说这一原则，但我还是忍不住在十多天后，谈谈自己的想法。</p>
<p>这篇文章的标题是我看LK-99，但实际上更应该是我看别人怎么看LK-99。</p>
<p>我获取相关信息的渠道主要有：Twitter、百度贴吧、B站、同学群。平台不同，言论也不同，可以说是很精彩。</p>
<p>我尝试去总结归纳：</p>
<ol>
<li>无脑贬低：</li>
</ol>
<ul>
<li>出现地方：贴吧比较多，更精确地说应该是某些贴吧的某些人。</li>
<li>表现：主要是以一种戏谑的嘲讽为主。代表言论是说：“棒子怎么可能有这种发现”，主打一个瞧不起。</li>
<li>我的想法：我现在越来越反感对其他国家的贬称，诸如“阿三、棒子、加麻大、丑国”等等。这种言论给我一种十分自大的感觉，但实际上你的国家真的比别人的国家强上多少吗？我看不尽然。</li>
</ul>
<ol start="2">
<li>攻击相关的科研人员
<ul>
<li>出现地方：几乎都能看到些</li>
<li>表现：当有些实验室宣布对LK-99的复现出现问题时，LK-99的提出者就可能受到攻击，被说是哗众取宠的小丑。</li>
<li>我的想法：到目前已经十天过去了，还保持着很高的热度，但似乎还没有完全有力的证伪出现，并且有观点认为这可能引出新的思路。我觉得他们能做到这点就已经很值得认可了。科学本来就是在不断试错中进步。</li>
</ul>
</li>
<li>侃侃而谈
<ul>
<li>出现地方：推特上似乎比较多</li>
<li>表现: 一些KOL追热点、尽管这并不是其领域</li>
<li>我的想法：能理解，但看多了我觉得厌烦。但话又说回来，我不也是个完完全全的门外汉，但我不也写了这么多。</li>
</ul>
</li>
<li>赛博斗蛐蛐
<ul>
<li>出现地方： 同学群、大学贴吧</li>
<li>表现： 国内各大学不少都尝试去复现，并根据结果去发表看法。然后就根据这些发表的看法的准确度、实时程度去给这些大学排名。</li>
<li>我的想法： 我觉得去复现、并发表自己的复现结果的行为都是值得肯定的。但实验过程中可能因为各种原因会出现不同的现象，倒也能理解。为了时效性和曝光度可能会操之太急，倒也是。</li>
</ul>
</li>
</ol>
<p>最后说说我的想法；</p>
<ul>
<li>肯定是希望其能成功。</li>
<li>就算不成功，这也是种新材料，也可能是种新的思路。所以也是件好事，也十分值得去肯定。</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>唱唱反调</title>
      <link>https://ds63.eu.org/2023/the-quibbler/</link>
      <pubDate>Sun, 30 Jul 2023 15:59:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/the-quibbler/</guid>
      <description>你为什么专捡这种事情报道</description>
      <content:encoded><![CDATA[<h2 id="背景">背景</h2>
<p>2023年7月底，暴雨不断,上游水库紧急泄洪。我所住的小镇沿河区域因此损失惨重。以下摘录那两天我日记中的部分内容。</p>
<h2 id="2023年7月30日">2023年7月30日</h2>
<p>中午的时候去菜市场附近转了转。上午有部队来帮助铲除路面上堆积的杂物，但路上还是泥泞不堪。</p>
<p>那里因为昨天上午7点出头，上游的水库开闸泄洪，导致下游的溪流水位暴涨，冲了上来。十几分钟后，马路上的水就已是齐腰深。那一块不少人家都是做粮杂相关的，囤货比较多,损失惨重。</p>
<p>虽然已经隔了一天了，但能看到人们几乎都还是在清理店里面的东西。</p>
<p>听到有人在问社区的工作人员：被水冲走的东西怎么办。答曰：找工商。他们应该得到赔偿吗？我觉得是应该的，因为这不是天灾，更是一场人祸。如果提前有通知，即使是半小时，那至少能转移些东西，损失能少点。他们会得到赔偿吗？我不知道。</p>
<p>下午的时候有志愿者和消防车出来扫街，还有两个志愿者是专门举横幅的，声势浩大。不用说，是为了拍照报道。</p>
<p>这是件好事吗？我觉得是，只要他们确确实实有去帮忙清理。但我还是不太喜欢，也可能是我戾气太重。因为我注意到，不知从何时开始，当灾难发生后，新闻报道的倾向变了。</p>
<p>现在更多的报道的是：工作人员、志愿者、部队等等齐心协力去帮助人们度过灾难。赞扬他们的无私付出。但仅就于我看到的，他们付出什么呢？水褪去后，路上一片狼藉，来帮忙清理。还有吗？似乎没有了，也可能是我没看到。</p>
<p>这样颇给我种丧事喜办的感觉。我能理解为什么要这么宣传。如果过多地去报道受灾的情况，可能有人会说，<strong>你为什么专捡这种事情报道</strong>。那么多人去志愿奉献。这么正能量的事情为什么不多报道些。这样大家看着欢喜，还能受到教育，多好啊。</p>
<p>多好啊！但是，那些受灾的人们，却被报道得更少了。他们的损失，可能只会成为一个个单薄的数字，甚至还可能出于这样那样的考虑，无法被如实地记录。但他们受灾的原因，他们本可以不用损失那么重的可能性，却不被提及。</p>
<p>在看到志愿者的时候，我跟我妈讲：不知道那些受灾的店主们（昨天她给我看一个视频，一位食杂店的店主拍自己原本装得满满、现在却一片狼藉，几乎空了一半的两间店面。）看到会这么想。</p>
<p>我妈回我说，他们哪里顾得想这些。</p>
<h2 id="2023年7月31日">2023年7月31日</h2>
<p>今天上午和下午都还是有部队在清理淤泥。我上午的时候只是在车上坐着，中途下车稍微走了走，都觉得很热。但我九点走的时候他们就已经来了，而十一点多回来的时候他们还在。</p>
<p>人民军队为人民。但又是听党指挥，党指挥枪。我又想到1989年的夏天。我现在的想法是复杂的。</p>
<h2 id="2024年6月27日">2024年6月27日</h2>
<p>今天看到广西桂林某县也是如此情况，整个流程几乎相差无几，令人苦笑。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Rust_Learning</title>
      <link>https://ds63.eu.org/2023/rust_learning/</link>
      <pubDate>Tue, 18 Jul 2023 16:25:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/rust_learning/</guid>
      <description>no panic</description>
      <content:encoded><![CDATA[<h1 id="rust_learning">Rust_Learning</h1>
<p><strong>记录我的Rust学习</strong></p>
<h2 id="cargo使用">Cargo使用</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cargo new
</span></span><span class="line"><span class="cl">cargo build 
</span></span><span class="line"><span class="cl">cargo run
</span></span><span class="line"><span class="cl">cargo check
</span></span><span class="line"><span class="cl">cargo doc --open <span class="c1">#build documentation provided by all your dependencies locally and open it in your browser</span>
</span></span></code></pre></div><h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://course.rs/"  target="_blank" rel="noopener" >Rust语言圣经</a></li>
<li><a href="https://rust-book.cs.brown.edu/"  target="_blank" rel="noopener" >The Rust Programming Language</a></li>
<li><a href="https://zh.practice.rs/"  target="_blank" rel="noopener" >Rust语言实战</a></li>
<li><a href="https://picklenerd.github.io/"  target="_blank" rel="noopener" >PNGme</a></li>
</ul>
<h2 id="rust特点">Rust特点</h2>
<ul>
<li>Patterns and the match construct</li>
<li>a strong, static type system.</li>
<li>type inference</li>
<li>shadow</li>
<li>Rust uses the term panicking when a program exits with an error</li>
<li>requiring type annotations in function definitions</li>
<li>Rust&rsquo;s goal is to compile programs into efficient binaries that <em>require as few runtime checks as possible</em></li>
<li>A foundational goal of Rust is to ensure that your programs never have undefined behavior</li>
</ul>
<h2 id="chapter3-common-programming-concepts">Chapter3 Common Programming Concepts</h2>
<ul>
<li>constant v.s. variable
<ol>
<li>Constants aren’t just immutable by default;they’re always immutable.</li>
<li>Constants can be declared in any scope</li>
<li>Constants may be set only to a constant expression, not the result of a value that could only be computed at runtime.</li>
</ol>
</li>
<li>shadow ends until
<ol>
<li>it itself is shadowed</li>
<li>the scope ends</li>
</ol>
</li>
<li>Integer division truncates toward zero to the nearest integer</li>
<li>tuple和array区别
<ol>
<li>tuple的各类型可以不同；</li>
<li>array的大小固定,在定义时就指定了</li>
<li>tuple更灵活,可存储不同类型,一般用于临时组合数据</li>
<li>array大小固定,用于存储大量相同类型的数据</li>
</ol>
</li>
<li>expression and statement
<ol>
<li>Expressions do not include ending semicolons</li>
<li>statement does not return a value</li>
<li>the return value of the function is synonymous with <em>the value of the final expression in the block of the body of a function</em></li>
</ol>
</li>
<li>Control Flow
<ol>
<li>This means the values that have the potential to be results from each arm of the if must be the same type</li>
<li>Rust does not have a concept of &ldquo;truthy&rdquo; or &ldquo;falsy&rdquo; values.So <em>The condition to an if-expression must be a boolean</em></li>
</ol>
</li>
</ul>
<h2 id="chapter4-understanding-ownship">Chapter4 Understanding Ownship</h2>
<ul>
<li>The stack holds data associated with a specific function, while the heap holds data that can outlive a function</li>
<li>Rust does not allow programs to manually deallocate memory. That policy avoids the kinds of undefined behaviors shown above.</li>
<li>Box deallocation principle : If a variable owns a box, when Rust deallocates the variable&rsquo;s frame, then Rust deallocates the box&rsquo;s heap memory.</li>
<li>Moved heap data principle: if a variable x moves ownership of heap data to another variable y, then x cannot be used after the move.</li>
<li>A reference is a kind of pointer.</li>
<li>Rust implicitly inserts dereferences and references in certain cases, such as calling a method with the dot operator</li>
<li><em>Pointer Safety Principle</em>: data should never be aliased and mutated at the same time.</li>
<li>Permissions are defined on <em>paths</em> and not just variables. A path is anything you can put on the left-hand side of an assignment.</li>
<li>Creating a reference to data (&quot;<em>borrowing</em>&quot; it) causes that data to be temporarily read-only until the reference is no longer used.</li>
<li>Rust&rsquo;s borrow checker does not contain different paths for a[0], a[1], and so on. It uses a single path a[_] that represents all indexes of a.</li>
<li>Slices are special kinds of references because they are &ldquo;fat&rdquo; pointers, or pointers with metadata. Here, the metadata is the length of the slice.</li>
</ul>
<h3 id="总结">总结</h3>
<ul>
<li>优势
<ol>
<li>improving runtime performance by avoiding garbage collection</li>
<li>improving predictability by preventing accidental &ldquo;leaks&rdquo; of data.</li>
</ol>
</li>
<li>Pointers can be created through
<ol>
<li>boxes (pointers owning data on the heap)</li>
<li>references (non-owning pointers).</li>
</ol>
</li>
<li>move v.s. borrow
<ul>
<li>A move of a variable with a non-copyable type (like Box<!-- raw HTML omitted --> or String) requires the RO permissions, and the move eliminates all permissions on the variable. That rule prevents the use of moved variables:</li>
<li>Borrowing a variable (creating a reference to it) temporarily removes some of the variable&rsquo;s permissions
<ul>
<li>An immutable borrow creates an immutable reference, and also <em>disables the borrowed data from being mutated or moved.</em></li>
<li>A mutable borrow creates a mutable reference, which* disables the borrowed data from being read, written, or moved*</li>
</ul>
</li>
</ul>
</li>
<li>use-after-free: <em>Immutable borrows</em> remove the W permission to avoid use-after-free,</li>
<li>double-frees: Dereferences of references to non-copyable data do not have the O permission to avoid double-frees</li>
</ul>
<h2 id="chapter5-struct">Chapter5 Struct</h2>
<ul>
<li>Rust <em>does not have a keyword for constructor functions</em>. The idiomatic way to define a constructor function is to make an associated function called new, but that is not enforced by the language.</li>
<li>tuple struct. e.g. <code>struct Color (i32,i32,i32);</code></li>
<li>Rust will insert as many references and dereferences as needed to make the types match up for the self parameter</li>
<li>Rust does not auto-derive Copy for stability across API changes. <code>#[derive(Copy, Clone)]</code></li>
<li>when you see an error like &ldquo;cannot move out of *self&rdquo;, that&rsquo;s usually because you&rsquo;re trying to call a self method on a reference like &amp;self or &amp;mut self. Rust is protecting you from a double-free</li>
</ul>
<h2 id="chapter6-enum">Chapter6 Enum</h2>
<ul>
<li>advantage to using an enum rather than a struct:</li>
</ul>
<ol>
<li>each variant can have different types and amounts of associated data</li>
<li>the name of each enum variant that we define also becomes a function that constructs an instance of the enum</li>
<li>you can put any kind of data inside an enum variant: strings, numeric types, or structs, for example. You can even include another enum</li>
</ol>
<ul>
<li>
<p>The Option Enum</p>
<ol>
<li>the compiler can check whether you’ve handled all the cases you should be handling</li>
<li>a null is a value that is currently invalid or absent for some reason.</li>
<li>Rust does not have nulls, but it does have an enum that can encode the concept of a value being present or absent.</li>
<li>The function Option::unwrap expects <em>self</em>, meaning it expects <em>ownership</em> of arg. However arg is an <em>immutable reference</em> to an option, so it cannot provide ownership of the option.</li>
</ol>
</li>
<li>
<p>match</p>
</li>
<li>
<p>Each match is tried from top to bottom</p>
</li>
<li>
<p>opt is a plain enum — its type is Option<!-- raw HTML omitted --> and not a reference like &amp;Option<!-- raw HTML omitted -->. Therefore a match on opt will move non-ignored fields like s.</p>
</li>
<li>
<p>If we want to peek into opt without moving its contents, the idiomatic solution is to match on a reference:</p>
</li>
<li>
<p><code>if let</code></p>
<ul>
<li>if let as syntax sugar for a match that runs code when the value matches one pattern and then ignores all other values.</li>
<li>The block of code that goes with the else is the same as the block of code that would go with the _ case in the match expression that is equivalent to the if let and else</li>
</ul>
</li>
</ul>
<h2 id="chapter7-managing-growing-projects-with-packages-crates-and-modules">Chapter7 Managing Growing Projects with Packages, Crates, and Modules</h2>
<h3 id="packages-a-cargo-feature-that-lets-you-build-test-and-share-crates">Packages: A Cargo feature that lets you build, test, and share crates</h3>
<ul>
<li>a bundle of one or more crates that provides a set of functionality.</li>
<li>A package can contain as many binary crates as you like, but at most only one library crate.</li>
<li>Using External Packages
<ol>
<li>the standard std library is also a crate that’s external to our package.we <em>don’t</em> need to change Cargo.toml to include std. But <em>we do need to refer to it</em> with use to bring items from there into our package’s scope</li>
</ol>
</li>
</ul>
<h3 id="crates-a-tree-of-modules-that-produces-a-library-or-executable">Crates: A tree of modules that produces a library or executable</h3>
<ul>
<li>Binary create: must have a function called <code>main</code></li>
<li>Library crates : define functionality intended to be shared with multiple projects.
Rustaceans say “crate”, they mean library crate, and they use “crate” interchangeably with the general programming concept of a <em>“library&quot;</em>.</li>
</ul>
<h3 id="modules-and-use-let-you-control-the-organization-scope-and-privacy-of-paths">Modules and use: Let you control the organization, scope, and privacy of paths</h3>
<ul>
<li>用处
<ol>
<li>let us organize code within a crate for readability and easy reuse</li>
<li>allow us to control the privacy of items, because code within a module is private by default</li>
</ol>
</li>
<li>parent and child
<ol>
<li>all items (functions, methods, structs, enums, modules, and constants) <em>are private to parent modules</em> by default.</li>
<li>Items in a parent module can’t use the private items inside child modules, but items in child modules can use the items in their ancestor modules.</li>
</ol>
</li>
</ul>
<h3 id="paths-a-way-of-naming-an-item-such-as-a-struct-function-or-module">Paths: A way of naming an item, such as a struct, function, or module</h3>
<ul>
<li>the idiomatic way
<ol>
<li>Bringing the function’s parent module into scope with use</li>
<li>when bringing in structs, enums, and other items with use, it’s idiomatic to specify the full path</li>
</ol>
</li>
<li><code>use std::io::Result as IoResult;</code></li>
<li>we can use nested paths to bring the same items into scope in one line.<code>use std::{cmp::Ordering, io};</code>,<code>use std::io::{self, Write};</code></li>
</ul>
<h2 id="chapter8">Chapter8</h2>
<h3 id="vector">Vector</h3>
<ul>
<li>Reason for a reference to the first element care about changes at the end of the vector
<ol>
<li>adding a new element onto the end of the vector might require allocating new memory and copying the old elements <em>to the new space</em></li>
<li>the reference to the first element would be pointing to <em>deallocated memory</em></li>
</ol>
</li>
<li>Vec::push moves its argument, so s is not usable after calling v.push(s)</li>
<li>When the vector gets dropped, all of its contents are also dropped, meaning the integers it holds will be cleaned up.</li>
</ul>
<h3 id="string">String</h3>
<ul>
<li>the compiler can coerce the &amp;String argument into a &amp;str</li>
<li>Rust strings don’t support indexing to <em>avoid returning an unexpected value and causing bugs that might not be discovered immediately</em></li>
<li>three relevant ways to look at strings from Rust’s perspective
<ol>
<li>bytes</li>
<li>scalar values</li>
<li>grapheme clusters</li>
</ol>
</li>
<li>The best way to operate on pieces of strings is to <em>be explicit about whether you want</em> characters or bytes</li>
<li>&amp;str is a promise that the byte sequence it points to will always be valid UTF-8</li>
</ul>
<h3 id="hash-map">hash map</h3>
<ul>
<li>Hash maps are useful when you want to look up data not by using an index, as you can with vectors, but by using a key that can be of any type</li>
<li>For types that implement the Copy trait, like i32, the values are copied into the hash map. - For <em>owned values</em> like String, the values will be moved and the hash map will be <em>the owner of those values</em></li>
</ul>
<h2 id="chapter10">chapter10</h2>
<h3 id="generic-data-types">Generic Data Types</h3>
<ul>
<li>Rust instead requires you to state the expected capabilities of generic types up front</li>
<li>Without restrictions, a generic type T has no capabilities: it cannot be printed, cloned, or mutated (although it can be dropped).</li>
<li>Rust does not have inheritance-like mechanisms for specializing methods as you might find in an object-oriented language,</li>
<li>Monomorphization is the process of turning generic code into specific code by filling in the concrete types that are used when compiled</li>
<li>const 泛型： <code>const N : usize</code></li>
</ul>
<h3 id="trait">trait</h3>
<ul>
<li>A trait defines functionality a particular type has and can share with other types.</li>
<li>One restriction to note is that we can implement a trait on a type only if at least one of the trait or the type is local to our crate.</li>
<li>Default implementations can call other methods in the same trait, even if those other methods don’t have a default implementation</li>
<li>traits in parameter
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">some_function</span><span class="o">&lt;</span><span class="n">T</span>:<span class="nc">Display</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Clone</span><span class="w"> </span><span class="p">,</span><span class="n">U</span>: <span class="nb">Clone</span> <span class="o">+</span><span class="w"> </span><span class="n">Debug</span><span class="o">&gt;</span><span class="p">(</span><span class="n">t</span>:<span class="kp">&amp;</span><span class="nc">T</span><span class="p">,</span><span class="n">u</span>:<span class="kp">&amp;</span><span class="nc">U</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i32</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// Clearer Trait Bounds with where Clauses
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">some_function</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">U</span><span class="o">&gt;</span><span class="p">()(</span><span class="n">t</span>:<span class="kp">&amp;</span><span class="nc">T</span><span class="p">,</span><span class="n">u</span>:<span class="kp">&amp;</span><span class="nc">U</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i32</span>
</span></span><span class="line"><span class="cl"><span class="nc">where</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">T</span>:<span class="nc">Display</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Clone</span><span class="w"> </span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">U</span>: <span class="nb">Clone</span> <span class="o">+</span><span class="w"> </span><span class="n">Debug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">{}</span><span class="w">
</span></span></span></code></pre></div></li>
<li>can only use impl Trait if you’re returning a single type</li>
<li>Using Trait Bounds to Conditionally Implement Methods
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fmt</span>::<span class="n">Display</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Pair</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">x</span>: <span class="nc">T</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">y</span>: <span class="nc">T</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Pair</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span>: <span class="nc">T</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="nc">T</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="bp">Self</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">Display</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">PartialOrd</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Pair</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">cmp_display</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;The largest member is x = </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;The largest member is y = </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div></li>
<li>conditionally implement a trait for any type that implements another trait
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">Display</span><span class="o">&gt;</span><span class="w"> </span><span class="nb">ToString</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c1">// --snip--
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div></li>
</ul>
<h3 id="lifetime">lifetime</h3>
<ul>
<li>Lifetime annotations don’t change how long any of the references live. Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes</li>
<li>the names of lifetime parameters must start with an apostrophe (&rsquo;) and are usually all lowercase and very short</li>
<li>when we specify the lifetime parameters in this function signature, we’re not changing the lifetimes of any values passed in or returned. Rather, we’re specifying that the borrow checker should reject any values that don’t adhere to these constraints.</li>
<li>in early versions (pre-1.0) of Rust,every reference needed an explicit lifetime</li>
<li>The compiler uses <em>three rules</em> to figure out the lifetimes of the references when there aren’t explicit annotations.
<ol>
<li>the compiler assigns a different lifetime parameter to each lifetime in each input type.</li>
<li>if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters</li>
<li>if there are multiple input lifetime parameters, but one of them is <code>&amp;self</code> or <code>&amp;mut self</code> because this is a <em>method</em>, the lifetime of self is assigned to all output lifetime parameters.</li>
</ol>
</li>
<li>The Static Lifetime <code>'static</code>
<ul>
<li>The string literals is <em>stored directly in the program’s binary</em>, which is always available. Therefore, <em>the lifetime of all string literals is <code>'static</code>.</em></li>
<li>&lsquo;static means &ldquo;live for the entire program&rdquo;, and so data under a static reference must never be deallocated.</li>
</ul>
</li>
<li>生命周期标注并不会改变任何引用的实际作用域</li>
</ul>
<h2 id="chapter11">chapter11</h2>
<h3 id="the-output-from-running-the-automatically-generated-test">The output from running the automatically generated test</h3>
<ul>
<li>The 0 measured statistic is for benchmark tests that measure performance.</li>
<li><code>Doc-tests</code>  is for the results of any documentation tests</li>
</ul>
<h3 id="常用命令">常用命令</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="fm">assert!</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="fm">assert_eq!</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">assert_ne</span><span class="o">!</span><span class="w"> </span><span class="c1">//  will pass if the two values we give it are not equal and fail if they’re equal.
</span></span></span></code></pre></div><h3 id="running-tests-in-parallel-or-consecutively">Running Tests in Parallel or Consecutively</h3>
<ul>
<li>When you run multiple tests, <em>by default</em> they run in parallel using threads</li>
<li><code>cargo test -- --test-threads=1</code></li>
<li><code>cargo test -- --show-output</code></li>
<li><code>cargo test --help</code></li>
<li><code>cargo test -- --help</code></li>
<li>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Rust" data-lang="Rust"><span class="line"><span class="cl"><span class="cp">#[test]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[ignore]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cargo</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="o">--</span><span class="w"> </span><span class="o">--</span><span class="n">ignored</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cargo</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="o">--</span><span class="w"> </span><span class="o">--</span><span class="n">include</span><span class="o">-</span><span class="n">ignored</span><span class="w">
</span></span></span></code></pre></div></li>
<li>We can specify part of a test name, and <em>any test whose name matches that value</em> will be run.</li>
</ul>
<h3 id="test-organization">test-organization</h3>
<ul>
<li>Unit tests exercise different parts of a library separately and can test private implementation details.</li>
<li>Unit tests exercise different parts of a library separately and can test private implementation details.</li>
</ul>
<h2 id="chapter12">chapter12</h2>
<ul>
<li>in cases where the desired function is nested in more than one module, we’ve chosen to <em>bring the parent module into scope</em> rather than the function.</li>
<li>TDD(Test Driven Develop)</li>
<li>Write a test that fails and run it to make sure it fails for the reason you expect.</li>
<li>Write or modify just enough code to make the new test pass.</li>
<li>Refactor the code you just added or changed and make sure the tests continue to pass.</li>
<li>Repeat from step 1!</li>
</ul>
<h2 id="chapter13">chapter13</h2>
<ul>
<li>Rust will infer the types of arguments/returns for closures, but not top-level functions</li>
<li>Closures can capture values from their environment in three ways
<ol>
<li>borrowing immutably</li>
<li>borrowing mutably</li>
<li>taking ownership.</li>
</ol>
</li>
<li>Fn traits
<ol>
<li>FnOnce</li>
<li>FnMut</li>
<li>Fn</li>
</ol>
</li>
<li>iterator adaptors are lazy, and we need to consume the iterator here.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>《操作系统：设计与实现》笔记</title>
      <link>https://ds63.eu.org/2023/learn-os-vias-jyy/</link>
      <pubDate>Tue, 27 Jun 2023 18:37:47 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/learn-os-vias-jyy/</guid>
      <description>操作系统就是状态机</description>
      <content:encoded><![CDATA[<p><strong><a href="https://space.bilibili.com/202224425/channel/collectiondetail?sid=192498"  target="_blank" rel="noopener" >操作系统：设计与实现 (2022 春季学期)</a>的学习笔记</strong></p>
<h3 id="p3-多处理器编程从入门到放弃-线程库现代处理器和宽松内存模型">p3 多处理器编程：从入门到放弃 (线程库；现代处理器和宽松内存模型)</h3>
<ul>
<li>
<p>并发程序的三个麻烦</p>
<ul>
<li>原子性</li>
<li>顺序</li>
<li>可见性</li>
</ul>
</li>
<li>
<p>gcc 编译</p>
<ul>
<li>不优化,并查看汇编代码
<code>gcc -c -O1 sum.c &amp;&amp; objdump -d sum.o</code></li>
<li><code>asm volatile(&quot;&quot; : : &quot;memory&quot;); // compiler barrier</code></li>
</ul>
</li>
<li>
<p>统计次数
<code> ./a.out | head -n 1000 | sort | uniq -c</code></p>
</li>
<li>
<p>现代处理器</p>
<ul>
<li>也是动态编译器：汇编指令也是由多个uop所组成的。</li>
<li>维护一个uop的“池子” 指令的有向无环图</li>
<li>乱序执行，顺序提交</li>
</ul>
</li>
</ul>
<h3 id="p4-理解并发程序执行-peterson算法模型检验与软件自动化工具">p4 理解并发程序执行 (Peterson算法、模型检验与软件自动化工具)</h3>
<ul>
<li>C语言的形式语义
<ul>
<li>全局变量加多个栈帧；每个栈帧有其局部变量和pc</li>
</ul>
</li>
<li>Peterson算法
<ul>
<li>看上去是谦让的，但其实是自私的</li>
<li>证明正确性：画出状态机
<ul>
<li>困境：不敢不画，不敢乱画</li>
<li>解决： <a href="https://jyywiki.cn/pages/OS/2022/demos/model-checker.py"  target="_blank" rel="noopener" >model-checker</a></li>
<li>把程序的问题变成图论的问题
<ul>
<li>safety 红色状态不可达</li>
<li>liveness : 从任意状态出发，都能到达绿/蓝色状态 强连通分量</li>
</ul>
</li>
</ul>
</li>
<li>许多重要的想法，凝练以后就是概念</li>
</ul>
</li>
<li>并发程序 = 状态机</li>
<li>Python generator
<ul>
<li>e.g.
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Python" data-lang="Python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">numbers</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">step</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="n">init</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">Trye</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">+=</span> <span class="n">step</span>
</span></span><span class="line"><span class="cl">    <span class="k">yield</span> <span class="n">n</span>
</span></span><span class="line"><span class="cl"><span class="n">g</span> <span class="o">=</span> <span class="n">numbers</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">g</span><span class="o">.</span><span class="fm">__next__</span><span class="p">()</span>
</span></span></code></pre></div></li>
</ul>
</li>
</ul>
<h3 id="p5-并发控制互斥-自旋锁互斥锁和-futex">p5 并发控制：互斥 (自旋锁、互斥锁和 futex)</h3>
<ul>
<li>不能解决问题的时候，可以找到所依赖的假设，并大胆地打破它</li>
<li>spin 线程直接共享 locked</li>
<li>mutex 通过系统调用访问 locked</li>
<li>futex(Fast Userspace muTexes)
<ul>
<li>Fast path: 一条原子指令，上锁成功立即返回</li>
<li>Slow path: 上锁失败，执行系统调用睡眠</li>
</ul>
</li>
</ul>
<h2 id="p6-并发控制同步-条件变量信号量生产者-消费者和哲学家吃饭问题">p6 并发控制：同步 (条件变量、信号量、生产者-消费者和哲♂学家吃饭问题)</h2>
<ul>
<li>思考： 有一堆任务，平均切分成n堆。有x个线程负责完成该任务(x &lt; n) 一个线程一次只能完成一个任务，完成后会自动去做下一个任务。要怎么实现？</li>
<li>有万能的方法，就要用万能的方法。
<ul>
<li>他是这样诠释的。当项目代码量不大（一千行以内），项目还是比较好维护的，这时候用写聪明的写法没问题。但当项目到了几万行甚至几百万行时，这时候就需要多个人来进行协作。而人和人之间最大的障碍就是无法完全沟通，理解对方的心意。</li>
<li>不要试图用聪明的办法解决并发问题</li>
<li>个人想法：第一次听这种说法，有一定道理。</li>
</ul>
</li>
<li>万能同步方法 —— 条件变量(Conditional Variables )
<ul>
<li>API
<ul>
<li>wait(cv, mutex) 💤
调用时必须保证已经获得 mutex
释放 mutex、进入睡眠状态</li>
<li>signal/notify(cv) 💬 私信：走起
如果有线程正在等待 cv，则唤醒其中一个线程</li>
<li>broadcast/notifyAll(cv) 📣 所有人：走起
唤醒全部正在等待 cv 的线程</li>
</ul>
</li>
<li>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 需要等待条件满足时
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">cond</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">wait</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cv</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">assert</span><span class="p">(</span><span class="n">cond</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1">// 互斥锁保证了在此期间条件 cond 总是成立
</span></span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 其他线程条件可能被满足时
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">broadcast</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cv</span><span class="p">);</span>
</span></span></code></pre></div></li>
<li>debug -&gt; 隔离出bug触发的最小条件</li>
</ul>
</li>
</ul>
<h2 id="p7-真实世界的并发编程-高性能计算数据中心人机交互中的并发编程">p7 真实世界的并发编程 (高性能计算/数据中心/人机交互中的并发编程)</h2>
<ul>
<li>谈block chain &gt; 是个很好的技术。但觉得不太对。因为造成了相当大的资源浪费。</li>
<li><a href="https://www.youtube.com/watch?v=FFftmWSzgmk&amp;ab_channel=Numberphile"  target="_blank" rel="noopener" >What&rsquo;s so special about the Mandelbrot Set? - Numberphile</a></li>
<li><a href="https://github.com/atanunq/viu"  target="_blank" rel="noopener" >atanunq/viu</a></li>
<li>搜索降低了知识的获取成本，ChatGPT等再一次降低了成本。</li>
<li>go语言，编程友好、性能优化</li>
<li>博客是web2.0 的第一步</li>
<li>Ajax (Asynchronous JavaScript + XML)</li>
<li>这次课中讲了三种并发编程，根据不同的需要，实现并发的方式也不同。</li>
</ul>
<h2 id="p8-并发-bug-和应对-死锁数据竞争原子性违反防御性编程和动态分析">p8 并发 bug 和应对 (死锁/数据竞争/原子性违反；防御性编程和动态分析)</h2>
<ul>
<li>软件是需求在计算机数字世界的投影。</li>
<li>assert的使用</li>
<li>没有工具不做系统</li>
<li>premature optimization is root of all evil</li>
<li>编程语言的缺陷——对程序员的完全信任：因为计算资源的宝贵</li>
<li>动态分析工具 <code>-fsanitize</code></li>
<li>Canary msvc 中 debug mode 的canary  <code>(b'\xcc' * 80).decode('gb2312')</code></li>
</ul>
<h2 id="p9-操作系统的状态机模型-操作系统的加载-thread-os-代码讲解">p9 操作系统的状态机模型 (操作系统的加载; thread-os 代码讲解)</h2>
<ul>
<li>大学的真正意义:f将已有的知识和方法重新消化，为大家建立好 “台阶”，在有限的时间里迅速赶上数十年来建立起的学科体系。</li>
</ul>
<h2 id="p10-状态机模型的应用-细胞自动机-gdbrrperf-代码验证工具">p10 状态机模型的应用 (细胞自动机; gdb/rr/perf; 代码验证工具)</h2>
<ul>
<li>分布式系统也是一种并发程序，但要更复杂。因为并发程序假设了每个thread都能正常运行，而分布式系统则要考虑节点丢失的情况。</li>
</ul>
<h2 id="p11-操作系统上的进程-最小-linux-fork-execve-和-exit">p11 操作系统上的进程 (最小 Linux; fork, execve 和 exit)</h2>
<ul>
<li>Linux 操作系统启动流程
CPU Reset → Firmware → Loader → Kernel _start() → 第一个程序 /bin/init → 程序 (状态机) 执行 + 系统调用</li>
<li>Fork Bomb:
<code>:(){:|:&amp;};:</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">:<span class="o">()</span> <span class="o">{</span>         <span class="c1"># 格式化一下</span>
</span></span><span class="line"><span class="cl">: <span class="p">|</span> : <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span><span class="p">;</span> :
</span></span></code></pre></div></li>
<li>stdout:
终端: line buffer
pipe , file :full buffer (除非显示地调用fflush)
<pre tabindex="0"><code></code></pre></li>
<li><strong>fork</strong>
<ul>
<li>程序就是状态机，正在执行的程序也是状态机，fork创建状态机的副本；</li>
<li>创建的进程返回+1，子进程返回为0</li>
<li>把所有的寄存器和内存都复制</li>
</ul>
</li>
<li><strong>execve</strong>
<ul>
<li>将当前运行的状态机重置成成另一个程序的初始状态</li>
</ul>
</li>
<li><strong>_exit</strong></li>
</ul>
<h2 id="p12-进程的地址空间-pmap-vdso-mmap-游戏修改器外挂">p12 进程的地址空间 (pmap; vdso; mmap; 游戏修改器/外挂)</h2>
<ul>
<li>端序
<ul>
<li>大端 (big endian): 低地址存放<em>高</em>有效字节</li>
<li>小端 (little endian): 低字节存放<em>低</em>有效字节</li>
</ul>
</li>
<li>工具使用
<ul>
<li>gdb</li>
<li>readelf</li>
<li>pmap</li>
</ul>
</li>
<li>计算机世界没有魔法。因为程序就是状态机。</li>
<li>vdso:不进入操作系统内核，实现系统调用</li>
<li>mmap：</li>
<li>文件=字节序列；内存=字节序列； everything is a file</li>
</ul>
<h2 id="p13-系统调用和-shell-freestanding-shell-终端和-job-control">p13 系统调用和 Shell (freestanding shell, 终端和 job control)</h2>
<ul>
<li>cd是内部命令：改变当前目录是用系统调用实现的</li>
<li><code>strace -f gcc a.c 2&gt;&amp;1 | vim -</code> This will pipe both stdout and stderr to vim. The <code>-</code> argument tells vim to read from stdin.</li>
<li><code>strace pmap 152 |&amp; vim - </code>
<code>|&amp;</code> : This is a shorthand for <code>2&gt;&amp;1 |</code> in bash and zsh. It passes both standard output and standard error of one command as input to another.</li>
<li>fish, zsh 和 bash 都是常用的命令行 shell; sh是比较原始的</li>
<li>clear 清屏</li>
<li><code>,./a.out &amp;</code>  后台执行./a.out</li>
</ul>
<h2 id="p14-c-标准库的实现-系统调用的封装内存空间管理">p14 C 标准库的实现 (系统调用的封装；内存空间管理)</h2>
<ul>
<li>文件描述符还是不理解。印象中这是第二次谈到了&quot;everything is a file&quot;
<ul>
<li>os的对象和对象的访问</li>
</ul>
</li>
<li>gdn的使用
<ul>
<li><code>No symbol table is loaded.  Use the &quot;file&quot; command</code>。可能是编译选项未包含debug信息,如gcc没有添加-g选项。</li>
</ul>
</li>
<li>premature optimization is the root of all evil.</li>
<li>脱离workload谈优化就是耍流氓</li>
<li>经典的设计：
<ul>
<li>fast path</li>
<li>slow path</li>
</ul>
</li>
</ul>
<h2 id="p15-fork-的应用-文件描述符的复制写时复制创建平行宇宙的魔法">p15 fork 的应用 (文件描述符的复制；写时复制；创建平行宇宙的魔法)</h2>
<ul>
<li>fork 状态机复制包括持有的所有操作系统对象</li>
<li>包括持有的所有操作系统对象</li>
<li>文件描述符（file discriptor）
<ul>
<li>一个指向操作系统内对象的 “指针”</li>
<li>dup() 的两个文件描述符是共享 offset</li>
</ul>
</li>
<li>访问空指针也会造成缺页中断</li>
<li>“Copy-on-write” 只有被写入的页面才会复制一份
<ul>
<li>被复制后，整个地址空间都被标记为 “只读”</li>
<li>操作系统捕获 Page Fault 后酌情复制页面</li>
<li>fork-execve 效率得到提升</li>
</ul>
</li>
<li>操作系统会维护每个页面的引用计数</li>
<li>定义进程所占用的内存</li>
<li>page是归os所有的，而非进程</li>
<li>使用fork来搜索并行化。</li>
</ul>
<h2 id="p16-什么是可执行文件-调试信息stack-unwinding静态链接中的重定位">p16 什么是可执行文件 (调试信息；Stack Unwinding；静态链接中的重定位)</h2>
<ul>
<li>可执行文件描述了状态机，是一个描述了状态机的初始状态 + 迁移的数据结构</li>
<li>os没有魔法，所有东西都有解释</li>
<li><code>She-bang</code> <code>#! interpreter [optional-arg]</code></li>
<li>GNU binutils
<ul>
<li>生成可执行文件
<ul>
<li>ld (linker), as (assembler)</li>
<li>ar, ranlib</li>
</ul>
</li>
<li>分析可执行文件
<ul>
<li>objcopy/objdump/readelf</li>
<li>addr2line, size, nm</li>
</ul>
</li>
</ul>
</li>
<li><code>objdump -d a.out | less</code> disasm</li>
<li><code>addr2line 401122 a.out</code></li>
<li>elf: 小精灵；dwarf：矮人</li>
<li>将一个 assembly (机器) 状态映射到 “C 世界” 状态很难</li>
<li>gcc等仍存在着许多不完美</li>
<li>编译器，汇编器，链接器</li>
</ul>
<h2 id="p17-动态链接和加载-静态-elf-加载器实现调试-linux-内核动态链接和加载">p17 动态链接和加载 (静态 ELF 加载器实现；调试 Linux 内核；动态链接和加载)</h2>
<ul>
<li>自定义了一个二进制格式文件</li>
<li>GOT ： global offset table</li>
<li>PLT : procedure linkage table</li>
</ul>
<h2 id="p23-1-bit-数据的存储-延迟线磁芯dramsram磁带磁盘光盘flash-ssd">p23 1-Bit 数据的存储 (延迟线/磁芯/DRAM/SRAM/磁带/磁盘/光盘/Flash SSD)</h2>
<ul>
<li>volatile: 确保该变量的实际值与内存中的值一致,每次读取都是最新值,也禁止编译器对其进行优化。</li>
<li>core dumped 磁性内存年代开始的概念。</li>
<li>局部性原理 -&gt; 可以按照大块来读写</li>
</ul>
<h2 id="p24-输入输出设备模型-串口键盘磁盘打印机总线中断控制器dma-和-gpu">p24 输入输出设备模型 (串口/键盘/磁盘/打印机/总线/中断控制器/DMA 和 GPU</h2>
<ul>
<li>DMA: direct memory access : 一个专门执行&quot;memcpy&quot;程序的cpu</li>
<li>IPC: Instruction per second</li>
<li>GPU:
<ul>
<li>一个通用计算设备</li>
<li>大量并行相似的任务</li>
</ul>
</li>
<li>异构计算：都能做，但选那个最合适的。（jjy在22年说的现在已经能感觉到有相关的趋势了。不过倒不是里面举例的挖矿，而是llm模型）</li>
</ul>
<h2 id="p25-设备驱动程序-linux-设备驱动-gpu-和-cuda-存储设备抽象">p25 设备驱动程序 (Linux 设备驱动; GPU 和 CUDA; 存储设备抽象)</h2>
<ul>
<li>设备抽象成 支持各类操作的对象 (文件)
<ul>
<li>read - 从设备某个指定的位置读出数据</li>
<li>write - 向设备某个指定位置写入数据</li>
<li>ioctl - 读取/设置设备的状态</li>
</ul>
</li>
<li><code>stty -a</code></li>
<li>GPU
<ul>
<li>Single Instruction, Multiple Thread</li>
</ul>
</li>
<li>读优先的正确性</li>
</ul>
<h2 id="p26-文件系统-api-设备在应用间的共享目录和文件-api">p26 文件系统 API (设备在应用间的共享；目录和文件 API)</h2>
<ul>
<li>信息的局部性</li>
<li>Windows从c盘开始时是受其前身Dos系统的影响，那个有a、b</li>
<li><code>mount disk.img  /mnt</code></li>
<li><code>umount /mnt</code></li>
<li>硬（hard）链接
<ul>
<li><code>ln /usr/local/python3 python</code></li>
<li>目录中仅存储指向文件数据的指针</li>
<li>允许一个文件被多个目录引用.</li>
<li>无法用来链接目录，也不能跨文件系统</li>
<li>通过<code>ls -i</code>查看是否为硬链接</li>
</ul>
</li>
<li>软 (symbolic) 链接
<ul>
<li>“快捷方式”</li>
<li><code> ln -s ../p24 p24</code></li>
<li>目录从“树”变为了“图”，还是有环图</li>
</ul>
</li>
<li><code>cd</code>的特殊性
<ul>
<li>每个进程都有一个对应的工作目录（pwd），而这个目录只有系统调用才能够修改</li>
</ul>
</li>
</ul>
<h2 id="p27-fat-和-unix-文件系统-数据结构视角的文件系统-fat-手册导读和目录树遍历">p27 FAT 和 UNIX 文件系统 (数据结构视角的文件系统; FAT 手册导读和目录树遍历)</h2>
<ul>
<li>数据结构的假设：数据是以字节来存储的。</li>
<li>RAM 和 block的区别</li>
<li>FAT(File Allocation Table)
<ul>
<li>将指针集中存放在文件系统的某个区域</li>
<li>适合小文件</li>
<li>会产生碎片（fragmentation）</li>
<li>基本假设
<ul>
<li>链表无环且长度和文件大小一致</li>
<li>FREE的cluster不能有入边</li>
</ul>
</li>
</ul>
</li>
<li>cluster</li>
<li>sector</li>
<li>ext2
<ul>
<li>大文件的随机读写性能提升明显 (O(1))</li>
<li>支持链接 (一定程度减少空间浪费)</li>
<li>inode 在磁盘上连续存储，便于缓存/预取</li>
<li>碎片</li>
</ul>
</li>
</ul>
<h2 id="p28-持久数据的可靠性-raid-崩溃一致性-fsck-和日志">p28 持久数据的可靠性 (RAID; 崩溃一致性; FSCK 和日志)</h2>
<ul>
<li>虚拟化
<ul>
<li>cpu的虚拟化：通过分时等技术让多个进程并行，相当于虚拟出了多个cpu</li>
<li>内存的虚拟化：一份内存通过mmu，虚拟成每个进程的地址空间</li>
<li>RAID：反向的虚拟化：多个磁盘虚拟化一个磁盘</li>
</ul>
</li>
<li>RAID
<ul>
<li>RAID0 : 交错排列： 提升容量和带宽</li>
<li>RAID1 : 提升容错和读带宽</li>
<li>RAID4 : 额外的一块校验盘
<ul>
<li>致命缺陷：随机写的性能只能有校验盘性能的一半</li>
</ul>
</li>
<li>RAID5 : Rotating Parity</li>
</ul>
</li>
<li>RAID带来的联想：
多个磁盘虚拟化为一个又大又快又可靠的磁盘，多台电脑虚拟化为一个又大又快又可靠的电脑
那能不能多个神经网络虚拟化为一个更好的神经网络</li>
<li>崩溃一致性  (Crash Consistency)
<ul>
<li>场景：写入的时候突然断电了怎么办？</li>
<li>方法1：按照一定顺序来写，且 “all or nothing”
<ul>
<li>困难：磁盘不提供多块读写 “all or nothing” 的支持，甚至为了性能，没有顺序保证。</li>
</ul>
</li>
<li>方法2： File System Checking (FSCK)
<ul>
<li>根据磁盘上已有的信息，恢复出 “最可能” 的数据结构</li>
<li>困难：难；如果修复的时候再掉一次电？</li>
</ul>
</li>
<li>方法3： 日志</li>
<li>具体：
<ul>
<li>数据结构操作发生时，用 (2) append-only 记录日志</li>
<li>日志落盘后，用 (1) 更新数据结构</li>
<li>崩溃后，重放日志并清除 (称为 redo log；相应也可以 undo log)</li>
</ul>
</li>
<li>优化: journaling (jdb2)</li>
</ul>
</li>
</ul>
<h2 id="p30-现代存储系统-关系数据库和分布式存储系统">p30 现代存储系统 (关系数据库和分布式存储系统)</h2>
<ul>
<li>数据库
<ul>
<li>关键
<ul>
<li>索引</li>
<li>查询优化</li>
</ul>
</li>
<li>magic：你只管写sql语句，相应的搜索优化它来做</li>
<li>要求：acid
<ul>
<li>Atoming</li>
<li>Consistency</li>
<li>Isolation</li>
<li>Durability</li>
</ul>
</li>
</ul>
</li>
<li>图灵奖
<ul>
<li>这门课听下来，听到了好多知识点背后都是获得过图灵奖的研究，甚至开创了一整个产业。</li>
</ul>
</li>
<li>关系型数据库跟不上社交网络的需求</li>
<li>cap theorem
<ul>
<li>Consistency</li>
<li>Availability</li>
<li>Partition Tolerance</li>
</ul>
</li>
<li>分布式存储系统</li>
</ul>
<h2 id="感想">感想</h2>
<p>蒋炎炎这门课还是别人推荐的。第一次看到还不以为意，但出现的次数多了就觉得有必要去看看。发现是一大惊喜。</p>
<h2 id="收获">收获</h2>
<ol>
<li>原版书能看得下来了。大段的英文，之前看着有点怕，现在觉得也能看下来，并且速度还可以。</li>
</ol>
<h2 id="课外资料">课外资料</h2>
<ul>
<li><a href="https://plantegg.github.io/2022/06/05/%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2%E5%BC%80%E9%94%80/"  target="_blank" rel="noopener" >上下文切换的代价</a></li>
<li><a href="https://plantegg.github.io/2021/06/01/CPU%E7%9A%84%E5%88%B6%E9%80%A0%E5%92%8C%E6%A6%82%E5%BF%B5/"  target="_blank" rel="noopener" >CPU的制造和概念</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>操作系统复习笔记</title>
      <link>https://ds63.eu.org/2023/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%A4%8D%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Mon, 19 Jun 2023 18:35:11 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%A4%8D%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>操作系统复习笔记</description>
      <content:encoded><![CDATA[<h1 id="期末复习">期末复习</h1>
<h2 id="chpter-3-process">Chpter 3 Process</h2>
<ul>
<li>操作系统进行任务调度和资源分配的基本单位</li>
<li>Process include:
<ol>
<li>Program code</li>
</ol>
<ul>
<li>text section</li>
</ul>
<ol start="2">
<li>program counter and processors’ registers</li>
<li>Stack</li>
</ol>
<ul>
<li>Function parameters</li>
<li>Return address</li>
<li>Local variables</li>
</ul>
<ol start="4">
<li>data section</li>
</ol>
<ul>
<li>Global variables</li>
</ul>
<ol start="5">
<li>Heap</li>
</ol>
<ul>
<li>Dynamically allocated memory</li>
</ul>
</li>
<li>Process State
<ul>
<li>五态模型
<ul>
<li>new</li>
<li>ready:waiting to be assigned to a processor</li>
<li>waiting: waiting for some event to occur</li>
<li>running</li>
<li>terminated</li>
</ul>
</li>
</ul>
</li>
<li>Process control block（PCB）
<ul>
<li>包含信息有：
<ul>
<li>Process number</li>
<li>Process state</li>
<li>Program counter
<ul>
<li>下条指令的地址</li>
</ul>
</li>
<li>CPU registers</li>
<li>CPU scheduling information</li>
<li>Memory-management information</li>
<li>Accounting information</li>
<li>I/O status information</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="process-scheduling">Process Scheduling</h3>
<ul>
<li>
<p>Scheduling queues</p>
<ol>
<li>Job queue</li>
</ol>
<ul>
<li>set of all processes in the system</li>
<li>As processes/job enter the system，they are put into the job queue</li>
</ul>
<ol start="2">
<li>Ready queue</li>
</ol>
<ul>
<li>set of all processes residing in “(main) memory”, ready and “waiting” to execute</li>
</ul>
<ol start="3">
<li>Device queues</li>
</ol>
<ul>
<li>set of processes waiting for an I/O device</li>
</ul>
</li>
<li>
<p>Scheduler(调度器)</p>
<ol>
<li>Long-term scheduler or job scheduler</li>
</ol>
<ul>
<li>job queue -&gt; ready queue</li>
<li>may  be absent on Time-sharing system such as UNIX  and Windows
<ul>
<li>They put every new process in memory for the short-term scheduler</li>
</ul>
</li>
</ul>
<ol start="2">
<li>Short-term scheduler Or CPU scheduler: 进程调度</li>
</ol>
<ul>
<li>selects which process should be executed next and allocates CPU</li>
<li>因为其执行十分频繁，所以每次选择不能耗时太长，否则就overhead</li>
</ul>
<ol start="3">
<li>Medium-term scheduler Or swapping</li>
</ol>
<ul>
<li>swap out: removes processes from memory to disk and reduces the degree of multiprogramming</li>
<li>swap in: introduce process into memory</li>
</ul>
</li>
<li>
<p>Context Switch</p>
<ul>
<li>CPU switches to another process</li>
</ul>
</li>
</ul>
<h3 id="operations-on-processes">Operations on Processes</h3>
<ol>
<li>fork()
<ul>
<li>The new process consists of a copy of the address space of the original process</li>
<li>The return code for the fork() is zero for the child process</li>
<li>子进程会复制父进程的地址空间和资源，但并不会复制父进程的线程</li>
</ul>
</li>
</ol>
<h3 id="interprocess-communication">Interprocess Communication</h3>
<ul>
<li>Shared memory</li>
<li>Message passing</li>
</ul>
<h3 id="名词解释">名词解释：</h3>
<ul>
<li>multiprogramming： is to have some process running at all times, to maximize CPU utilization</li>
<li>time sharing ： is to switch the CPU among processes so frequently that users can interact with each process</li>
</ul>
<h2 id="chapter-4-thread">Chapter 4 Thread</h2>
<ul>
<li>进程 vs 线程
<ul>
<li>线程是CPU的分布单位</li>
<li>进程是资源的分布单位</li>
<li>线程是进程中的执行单元
<ul>
<li>一个进程可以包含多个线程，它们共享相同的地址空间和系统资源，如open files, signals。</li>
<li>每个线程有自己的栈空间和执行上下文，但它们在同一个进程内共享代码段、数据段和堆等资源。</li>
</ul>
</li>
</ul>
</li>
<li>benefits of multithreaded programming
<ol>
<li>Responsiveness</li>
<li>Resource sharing</li>
<li>Economy</li>
<li>utilization of multiprocessor architectures</li>
</ol>
</li>
</ul>
<h3 id="multithreading-models">Multithreading Models</h3>
<ul>
<li>
<p>两种线程</p>
<ul>
<li>User Threads
<ul>
<li>Provided by a thread library at the user level</li>
</ul>
</li>
<li>Kernel Threads
<ul>
<li>Provided and managed by the OS directly</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Relationship between kernel threads and user threads</p>
<ol>
<li>Many-to-one model</li>
<li>One-to-one model-</li>
<li>Many-to-many model</li>
<li>Two-level Model
<ul>
<li>主体是Many-to-many model</li>
<li>A user thread (important task) can be bound to a kernel thread</li>
</ul>
</li>
</ol>
</li>
<li>
<p>Two versions of fork() in UNIX systems</p>
<ol>
<li>To duplicate all the threads
<ul>
<li>If exec() is not called after forking, then to duplicate all threads</li>
</ul>
</li>
<li>To only duplicate the thread that invoked the fork() system call
<ul>
<li>If exec() is called immediately after forking, then only to duplicate the calling threads</li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="chapter-5-cpu-scheduling">Chapter 5 CPU Scheduling</h2>
<h3 id="basic-concepts">Basic Concepts</h3>
<ul>
<li>CPU scheduling decisions may take place when a process:
<ol>
<li>Switches from running to waiting state
<ul>
<li>The result of  an I/O request</li>
<li>An invocation of wait for the termination of one of the child processes （e.g. wait(NULL);）</li>
</ul>
</li>
<li>Switches from running to ready state
<ul>
<li>When a interrupt occurs</li>
</ul>
</li>
<li>Switches from waiting to ready
<ul>
<li>Completion of I/O</li>
</ul>
</li>
<li>Terminates</li>
</ol>
</li>
<li>Non-preemptive (非剥夺)
<ul>
<li>Once the CPU has been allocated to a process, the process keeps the CPU until it releases the CPU</li>
<li>调度只可能发生在情况 1. 和 4.</li>
<li>简单，硬件要求低</li>
</ul>
</li>
<li>Preemptive(剥夺)</li>
</ul>
<h3 id="scheduling-criteria">Scheduling Criteria</h3>
<ol>
<li>CPU utilization</li>
<li>CPU throughout
<ul>
<li>number of processes that complete their execution per time unit.</li>
</ul>
</li>
<li>Process turnaround time
<ul>
<li>From the time of submission of a process to the time of completion, include
<ul>
<li>Waiting to get into memory</li>
<li>Waiting in the ready queue</li>
<li>Executing on the CPU</li>
<li>Doing I/O</li>
</ul>
</li>
</ul>
</li>
<li>Process waiting time (等待时间)
<ul>
<li>amount of time that a process spent waiting in the ready queue.</li>
</ul>
</li>
<li>Process response time (响应时间)
<ul>
<li>amount of the time from the submission of a request until the first response/result is produced</li>
</ul>
</li>
</ol>
<h3 id="scheduling-algorithms">Scheduling Algorithms</h3>
<ol>
<li>First come first served (FCFS)
<ul>
<li>non-preemptive</li>
<li>Convoy effect (护航效应)</li>
</ul>
</li>
<li>Shortest job first (SJF)
<ul>
<li>minimum average waiting time</li>
<li>种类
<ol>
<li>Preemptive SJF allows to preempt the currently executing process</li>
<li>Non-preemptive</li>
</ol>
</li>
<li>比较适用于长程调度</li>
</ul>
</li>
<li>Priority scheduling
<ul>
<li>问题：starvation</li>
<li>解决： Aging (时效) – as time progresses increase the priority of the process</li>
</ul>
</li>
<li>Round robin (RR)
<ul>
<li>Is designed for especially for time-sharing systems</li>
<li>preemptive</li>
<li>time quantum
<ul>
<li>需要保证 80%的cpu bursts &lt; the time quantum</li>
</ul>
</li>
<li>Response time = 2*(n-1)*q</li>
</ul>
</li>
<li>Multilevel queue algorithm</li>
<li>Multilevel feedback queue algorithm
<ul>
<li>the most general scheduling algorithm</li>
</ul>
</li>
</ol>
<h3 id="multiple-processor-scheduling">Multiple-Processor Scheduling</h3>
<ul>
<li>homogeneous vs. heterogeneous CPUs
<ul>
<li>homogeneous: 各处理器都一样</li>
</ul>
</li>
<li>Approaches to multiple-processor scheduling
<ul>
<li>Asymmetric multiprocessing
<ul>
<li>only one processor (the master server) has all scheduling decision, I/O processing</li>
</ul>
</li>
<li>Symmetric multiprocessing
<ul>
<li>each processor is self-scheduling</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="chapter-6-process-synchronization">Chapter 6 Process synchronization</h2>
<ul>
<li>Race condition
<ul>
<li>The situation where several processes access and manipulate shared data concurrently.</li>
<li>The final value of the shared data depends upon which process finishes last.</li>
</ul>
</li>
</ul>
<h3 id="the-critical-section-problem">The Critical-Section Problem</h3>
<ul>
<li>
<p>critical section</p>
<ul>
<li>Each process has a code segment, called critical section, in which the shared data is accessed</li>
<li>有几个共享变量就有几个临界区</li>
</ul>
</li>
<li>
<p>Criteria for the critical section problem solution</p>
<ol>
<li>Mutual exclusion 互斥</li>
<li>progress 空闲让进</li>
<li>Bounded waiting 有限等待</li>
</ol>
</li>
<li>
<p>Peterson’s Solution</p>
<ul>
<li>举手+令牌</li>
</ul>
</li>
<li>
<p>hardware-based solution</p>
<ul>
<li>关中断
<ul>
<li>多处理机不适合</li>
</ul>
</li>
<li>原子操作</li>
</ul>
</li>
</ul>
<h3 id="semaphores">Semaphores</h3>
<ul>
<li>
<p>A Semaphore S – integer variable</p>
<ul>
<li>may be initialized via a non-negative value</li>
<li>Can only be accessed via two indivisible (atomic) operations: P() and V()</li>
</ul>
</li>
<li>
<p>P(): the wait() operation</p>
<pre tabindex="0"><code>wait (S) { 
  while (S.value &lt;= 0) ; 	// no-op
    S.value--;
}
</code></pre></li>
<li>
<p>V() The signal() operation</p>
<pre tabindex="0"><code>signal(S){
  S.value++;
}
</code></pre></li>
<li>
<p>main problem : busy waiting (spinlock)</p>
<ul>
<li>advantages
<ol>
<li>No context switch is required when a process must wait on a lock</li>
<li>If locks are expected to be held for short times, the spinlocks are useful</li>
</ol>
</li>
<li>disadvantages
<ol>
<li>wastes the CPU cycles that can be used by other processes productively</li>
</ol>
</li>
<li>解决：modify the definition of the wait() and signal() <strong>适用于 multiprocessor system</strong>
<ul>
<li>Wait(): the process can block() itself rather than engaging in busy waiting</li>
<li>Signal(): change the blocking process from the waiting state to the ready state</li>
</ul>
</li>
</ul>
</li>
<li>
<p>implementation</p>
<ol>
<li>In a single-processor environment</li>
</ol>
<ul>
<li>Disable interrupt</li>
</ul>
<ol start="2">
<li>In a multi-processor environment</li>
</ol>
<ul>
<li>Critical section can be applied</li>
</ul>
</li>
</ul>
<h2 id="chapter-7-deadlocks">Chapter 7 Deadlocks</h2>
<ul>
<li>Necessary conditions
<ol>
<li>Mutual exclusion</li>
<li>Hold and wait</li>
<li>No preemption</li>
<li>Circular wait</li>
</ol>
</li>
</ul>
<h3 id="methods-for-handling-deadlocks">Methods for Handling Deadlocks</h3>
<ol>
<li>
<p>Prevention</p>
<ul>
<li>Provides a set of methods for ensuring that at least one of necessary conditions cannot be held</li>
<li>针对条件2： all or nothing; 没有资源的时候才去申请</li>
<li>针对条件3： 谦让； 抢夺</li>
<li>针对条件4： 顺序执行</li>
<li>缺点： low device utilization and reduce system throughput.</li>
</ul>
</li>
<li>
<p>Avoidance</p>
<ul>
<li>using the addition information,decide whether the current request can be satisfied or must be delay</li>
<li>方法：
<ol>
<li>Resource-allocation graph
<ul>
<li>有环：处于unsafe state;可能处于死锁状态</li>
</ul>
</li>
<li>Banker&rsquo;s algorithm</li>
</ol>
</li>
</ul>
</li>
<li>
<p>Detection and recovery</p>
<ul>
<li>方法:
<ul>
<li>Wait-for graph
<ul>
<li>not appilcable to a resource-allocation system with multiple instances of each resource type</li>
</ul>
</li>
<li>Banker’s Algorithm</li>
</ul>
</li>
<li>When, and how often, to invoke detection algorithm. it depends on:
<ul>
<li>How often a deadlock is likely to occur?</li>
<li>How many processes will need to be rolled back?</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Ignorance</p>
</li>
</ol>
<h2 id="chapter-8">Chapter 8</h2>
<ul>
<li>
<p>Address may be represented in</p>
<ol>
<li>symbolic address</li>
<li>re-locatable address</li>
<li>absolute address</li>
</ol>
</li>
<li>
<p>address binding</p>
<ul>
<li>转换：
<ul>
<li>symbolic address -&gt; re-locatable address : compiler</li>
<li>re-locatable address -&gt; absolute address : linkage editor or loader</li>
</ul>
</li>
<li>发生的时期
<ol>
<li>Compile time
<ul>
<li>If memory location known at compile time, absolute code can be generated</li>
<li>If memory location is not known at compile time, Must generate re-locatable code</li>
</ul>
</li>
<li>Load time （+linkage time）
<ul>
<li>if memory location is known at load time, absolute code can be generated at this time</li>
</ul>
</li>
<li>Execution time
<ul>
<li>If memory location is not known at compile time and load time, Binding is delayed until run time</li>
<li>absolute code must be generated at run time</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<h3 id="logical-vs-physical-address-space">Logical vs. Physical Address Space</h3>
<ul>
<li>
<p>Logical address ：CPU</p>
<ul>
<li>also referred to as virtual address</li>
<li>重定位地址和逻辑地址没有直接关系</li>
</ul>
</li>
<li>
<p>Physical address ：memory unit</p>
</li>
<li>
<p>logical (virtual) and physical addresses differ in execution-time address-binding scheme</p>
<ul>
<li>re-locatable code are seen by CPU</li>
<li>absolute code are seen by the memory unit</li>
</ul>
</li>
<li>
<p>Memory-Management Unit (MMU)</p>
<ul>
<li>Hardware device that maps virtual address to physical address in the run-time</li>
</ul>
</li>
<li>
<p>Dynamic load</p>
<ul>
<li>not loaded the entire program and data of a process be in physical memory for the process to execute until it is called</li>
<li>好处：
<ol>
<li>Better memory-space utilization</li>
<li>No special support is required from the operating system</li>
</ol>
</li>
</ul>
</li>
<li>
<p>Dynamic linking</p>
<ul>
<li>Linking is postponed until execution time</li>
<li>requires help from the OS</li>
</ul>
</li>
</ul>
<h3 id="contiguous-memory-allocation">Contiguous Memory Allocation</h3>
<ol>
<li>Fixed-Sized Contiguous Partition
<ul>
<li>Strengths (advantages)
<ul>
<li>Simple to implement</li>
<li>little overhead</li>
</ul>
</li>
<li>Weaknesses(drawbacks)
<ul>
<li>internal fragmentation
<ul>
<li>allocated memory may be larger than requested memory</li>
</ul>
</li>
<li>fixed number of processes</li>
</ul>
</li>
</ul>
</li>
<li>Dynamic Contiguous partition（可变分区）
<ul>
<li>Hole – block of available memory</li>
<li>Allocation algorithms
<ol>
<li>first fit:
<ul>
<li>从头开始，或者是从当前位置开始</li>
</ul>
</li>
<li>best-fit
<ul>
<li>Need to search all entire list, unless the list is ordered by size</li>
<li>produces the smallest leftover hole that may be wasted</li>
</ul>
</li>
<li>worst-fit
<ul>
<li>Need to search all entire list, unless the list is ordered by size</li>
<li>小进程多的 效果好</li>
</ul>
</li>
</ol>
</li>
<li>问题：
<ul>
<li>External Fragmentation</li>
</ul>
</li>
</ul>
</li>
</ol>
<ul>
<li>
<p>Solutions to fragmentation</p>
<ol>
<li>Compaction(紧凑)
<ul>
<li>To reduce external fragmentation</li>
<li>Shuffle memory contents to place all free memory together in one large block</li>
<li>It is done at execution time， it’s possible only if relocation is dynamic</li>
<li>May be expensive in moving the processes and the holes</li>
</ul>
</li>
<li>paging</li>
<li>segmentation</li>
</ol>
</li>
<li>
<p>Disadvantage of Contiguous Memory Allocation</p>
<ul>
<li>Fragmentation in main memory</li>
<li>Compaction is impossible on the disk</li>
</ul>
</li>
</ul>
<h3 id="paging">paging</h3>
<ul>
<li>
<p>frame: Divide physical memory into fixed-sized blocks</p>
</li>
<li>
<p>page : Divide logical memory into fixed-sized blocks</p>
<ul>
<li>page size is equal to frame size</li>
<li>Finding n free frames for loading a program of size n pages</li>
</ul>
</li>
<li>
<p>Translating logical address to physical address
If the address space is 2^m and the page size is 2^n</p>
<ul>
<li>Every logical address generated by CPU is divided into:
<ol>
<li>Page number (p: 页号)
<ul>
<li>used as an index into a page table</li>
<li>页表中包含每一页在physical memory 的 base address (f:块号)</li>
<li>p =address/2^n   is equal to m-n bit of the address</li>
</ul>
</li>
<li>Page offset (d: 偏移)
<ul>
<li>combined with base address (f:块号) to define the physical memory address that is sent to the memory unit</li>
<li>d =address%2n is equal to n bit of the address</li>
</ul>
</li>
</ol>
</li>
<li>Physical address
<ol>
<li>frame number（f: 帧号、块号)</li>
<li>page offset      (d:页偏移、块偏移)</li>
</ol>
</li>
</ul>
</li>
<li>
<p>page size的选择</p>
<ul>
<li>越大：
<ul>
<li>Disk I/O is more efficient</li>
<li>page table size 越小</li>
</ul>
</li>
<li>越小：
<ul>
<li>internal fragmentation 越小</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Frame table (主存分块表)</p>
<ul>
<li>Has one entry for each physical page frame
Indicating
<ul>
<li>whether the frame is free or it is allocated to which process</li>
</ul>
</li>
</ul>
</li>
<li>
<p>page table</p>
<ul>
<li>each process must maintain a copy of the page table</li>
<li>计算
<ul>
<li>if page-table entry is 4 bytes long
<ul>
<li>Can point to one of 2^32 physical page frames (1比特=8字节)</li>
<li>If frame size(= page size) is 4KB, the system can address 2^44 bytes(2^32×2^12=16TB) of physical memory</li>
</ul>
</li>
<li>对于32位cpu
<ul>
<li>page size: 4k (=2^12)</li>
<li>Table size：2^32/2^12=1M</li>
<li>each entry&rsquo;s size : 4 bytes</li>
<li>page table 的大小为： 4 MB</li>
</ul>
</li>
</ul>
</li>
<li>位置
<ol>
<li>直接存放在寄存器中：
<ul>
<li>Efficient and expensive</li>
<li>当page table is reasonable small 时可以</li>
</ul>
</li>
<li>存放在main memory ，然后用Page-table base register (PTBR：页表基址寄存器)存放其位置
<ul>
<li>进程切换时，加载页表只需要改变PTBR</li>
<li>every data/instruction access requires two memory accesses
<ul>
<li>One for the page table</li>
<li>One for the data/instruction</li>
</ul>
</li>
</ul>
</li>
<li>Translation Look-aside Buffer (TLB) also called Associate Memory(联想寄存器)
<ul>
<li>并行查找</li>
<li>contains only a few of page-table entries</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<h3 id="structure-of-the-page-table">Structure of the Page Table</h3>
<ul>
<li>问题: The page table can be excessively large</li>
<li>Solution： Divide the page table into smaller pieces
<ol>
<li>Hierarchical Paging （分层页表）</li>
<li>Hashed Page Tables（哈希页表）</li>
<li>Inverted Page Tables（反置页表）</li>
</ol>
</li>
</ul>
<ol>
<li>Hierarchical Paging （分层页表）
<ul>
<li>缺陷：</li>
</ul>
<ol>
<li>需遍历，进程太多</li>
<li>可能有共享，而进程号只能填一个</li>
<li>不适用于64位</li>
</ol>
<ul>
<li>好：
<ol>
<li>需要的空间小</li>
</ol>
</li>
</ul>
</li>
<li>Hashed Page Tables
<ul>
<li>hash table -&gt; 在链表中遍历匹配</li>
</ul>
</li>
<li>Inverted Page Table(反置页表/主存分块表)</li>
</ol>
<ul>
<li>Only a page table in the system</li>
<li>One entry for each real page (or physical frame) of memory</li>
<li>缺点：
<ul>
<li>increases time needed to search the table when a page reference occurs</li>
<li>Lead to memory share difficulty</li>
</ul>
</li>
</ul>
<h3 id="segmentation">segmentation</h3>
<ul>
<li>User’s View of a Program: A program is a collection of segments，a segment is a logical unit such as:
<ul>
<li>main program
<ul>
<li>procedure ，function，method，object</li>
<li>local variables, global   variables</li>
<li>common block</li>
<li>stack</li>
<li>symbol table</li>
<li>arrays</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="chapter-9-virtual-memory">Chapter 9 Virtual Memory</h2>
<ul>
<li>
<p>the entire program is not needed to be in physical memory.这样的好处有：</p>
<ul>
<li>程序的大小不再受内存所限制</li>
<li>更多程序可以同时运行</li>
<li>Less I/O would be needed to load or swap each user program into memory, so program would start to run faster</li>
</ul>
</li>
<li>
<p>Virtual memory management</p>
<ul>
<li>a term used to describe a technique whereby the computer appears to have much more memory than it actually does</li>
</ul>
</li>
<li>
<p>Virtual memory can be implemented via:</p>
<ul>
<li>Demand paging</li>
<li>Demand segmentation</li>
</ul>
</li>
</ul>
<h3 id="demand-paging">Demand paging</h3>
<ul>
<li>
<p>思想： Bring a page into memory only when it is needed</p>
<ul>
<li>Be similar to a paging system with swapping</li>
</ul>
</li>
<li>
<p>Hardware</p>
<ul>
<li>Page table. 需要加一位valid–invalid bit
<ul>
<li>v -》 The page is legal and in memory</li>
</ul>
</li>
<li>Secondary memory
<ul>
<li>A high-speed disk, Swap space</li>
<li>Hold those page that are not present in memory</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Page Fault</p>
<ul>
<li>Access to a page marked invalid causes a page-fault trap</li>
<li>handle
<ol>
<li>Operating system looks at another table (PCB) to decide:
<ul>
<li>Invalid reference -&gt; abort</li>
<li>Just not in memory	（go on to 2））</li>
</ul>
</li>
<li>Get empty frame</li>
<li>Swap the desired page into the frame</li>
<li>modify the page table, Set validation bit = v</li>
<li>Restart the instruction that caused the page fault</li>
</ol>
</li>
<li>特殊：
<ol>
<li>一条指令可产生多个缺页中断</li>
<li>指令复执</li>
<li>在指令执行时中断。</li>
</ol>
</li>
<li>对比普通中断：
<ul>
<li>一条指令在执行完后，检查是否有中断请求
<ul>
<li>有：执行中断</li>
<li>无：执行下一条指令</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="page-replacement">Page Replacement</h3>
<p><strong>替换算法</strong></p>
<ol>
<li>
<p>FIFO page Replacement</p>
<ul>
<li>Belady’s Anomaly : more frames -&gt; more page faults</li>
</ul>
</li>
<li>
<p>Optimal Page Replacement (OPT)</p>
<ul>
<li>替换最晚才用的页 或 后面最长时间用不到的页</li>
</ul>
</li>
<li>
<p>Least Recently Used (LRU) Algorithm</p>
<ul>
<li>思想： The recent past as an approximation of the near future</li>
<li>实现：</li>
<li>counters</li>
<li>stack</li>
</ul>
</li>
<li>
<p>LRU Approximation Algorithms</p>
<ol>
<li>Additional-reference-bits algorithm</li>
<li>Second chance (clock)</li>
<li>Enhanced second-chance algorithm</li>
</ol>
</li>
<li>
<p>Counting-Based Page Replacement</p>
<ul>
<li>Least Frequently used</li>
<li>Most Frequently used</li>
</ul>
</li>
<li>
<p>Page-Buffering Algorithm</p>
<ul>
<li>Assistant procedure to a page-replacement algorithm</li>
</ul>
</li>
</ol>
<h3 id="allocation-of-frames">Allocation of Frames</h3>
<ul>
<li>
<p>Two major allocation schemes</p>
<ol>
<li>fixed allocation
<ul>
<li>Equal allocation</li>
<li>Proportional allocation</li>
</ul>
</li>
<li>priority allocation
<ul>
<li>Use a proportional allocation scheme using priorities rather than size</li>
</ul>
</li>
</ol>
</li>
<li>
<p>Global vs. Local Allocation</p>
<ol>
<li>Local replacement
<ul>
<li>To allow a process to select from only its own set of allocated frames.</li>
<li>Cannot increase the number of frames allocated</li>
<li>Not affected by external circumstances</li>
</ul>
</li>
<li>Global replacement
<ul>
<li>To allow a process to select a replacement frame from the set of all frames, even if that frame is currently allocated to some other process</li>
<li>Can increase the number of frames allocated</li>
<li>Cannot control its page-fault rate.</li>
</ul>
</li>
</ol>
<ul>
<li>In general, global replacement is better.</li>
</ul>
</li>
</ul>
<h3 id="thrashing">Thrashing</h3>
<ul>
<li>A process is thrashing （颠簸）if it is spending more time paging than executing</li>
<li>approach
<ol>
<li>Using a local replacement algorithm</li>
<li>Working-set strategy
<ul>
<li>To compute the working-set size for each process in the system</li>
</ul>
</li>
<li>Page-Fault Frequency (PFF) Scheme  (水多了加面，面多了加水)
<ul>
<li>If actual rate too low, remove  a frame from the process</li>
<li>If actual rate too high, allocate another frame to the process</li>
<li>If no frames are free, suspend it</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="other-considerations">Other Considerations</h3>
<ul>
<li>page size 大小的选择要考虑到：
<ol>
<li>内碎片</li>
<li>页表的大小</li>
<li>I/O overhead (seek time, latency time, transfer time)</li>
<li>Locality</li>
<li>Page fault rate
<ul>
<li>顺序访问： page size越大，则缺页中断率越小</li>
<li>随机访问： page size越大，则more paging action could ensue because fewer pages can be kept in memory and more data is transferred per page fault.</li>
</ul>
</li>
</ol>
</li>
<li>Install a faster hard disk, or multiple controllers with multiple hard disks
<ul>
<li>for as the disk bottleneck is removed by faster response and more throughput to the disks, the CPU will get more data more quickly</li>
</ul>
</li>
</ul>
<h2 id="chapter-10-file-system-interface">Chapter 10 File-System Interface</h2>
<ul>
<li>File
<ul>
<li>A file is named collection of related information that is recorded on secondary storage</li>
<li>Six basic operations
<ol>
<li>create</li>
<li>read/write/seek</li>
<li>delete</li>
<li>truncate: to erase the contents of a file but keep its attributes except for it’s length</li>
</ol>
</li>
<li>Assistant operations
<ul>
<li>open(F):
<ol>
<li>search the directory structure on disk for entry F</li>
<li>copy the directory entry into the open-file table</li>
<li>allocate a file descriptor</li>
</ol>
</li>
<li>close(F):
<ol>
<li>copy the directory entry in the open-file table to the directory structure on disk</li>
<li>free the file descriptor</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="access-methods">Access Methods</h3>
<ul>
<li>The information in the file can be accessed in
<ol>
<li>sequentical access</li>
<li>direct access</li>
<li>other access
<ul>
<li>involve the construction of an index for the file</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="directory-structure">Directory Structure</h3>
<ul>
<li>
<p>symbol table</p>
<ul>
<li>The directory can be viewed as a symbol table that translates file names into their directory entries</li>
</ul>
</li>
<li>
<p>Criteria</p>
<ol>
<li>efficiency</li>
<li>naming</li>
<li>grouping</li>
</ol>
</li>
<li>
<p>shemes</p>
<ol>
<li>Single-Level Directory</li>
<li>Two-Level Directory
<ul>
<li>Positive
<ul>
<li>Efficient searching</li>
</ul>
</li>
<li>Negative
<ul>
<li>No grouping capability</li>
<li>Difficult to share file among different users</li>
</ul>
</li>
</ul>
</li>
<li>Tree-Structured Directories
<ul>
<li>Positive
<ul>
<li>Efficient searching</li>
<li>Grouping Capability</li>
</ul>
</li>
<li>Negative
<ul>
<li>Difficult to share file among different users</li>
</ul>
</li>
</ul>
</li>
<li>Acyclic-Graph Directories
<ul>
<li>Tree-structured directory + shared subdirectories or files</li>
<li>Created a new directory entry  called a link to implement sharing</li>
<li>The difficulty is to avoid cycles as new links are added</li>
</ul>
</li>
<li>General Graph Directory
<ul>
<li>Add the links to an existing tree-structure directory</li>
<li>Acyclic-Graph Directories更好</li>
</ul>
</li>
</ol>
</li>
<li>
<p>硬（hard）链接</p>
<ul>
<li><code>ln /usr/local/python3 python</code></li>
<li>目录中仅存储指向文件数据的指针</li>
<li>允许一个文件被多个目录引用.</li>
<li>无法用来链接目录，也不能跨文件系统</li>
<li>通过<code>ls -i</code>查看是否为硬链接</li>
</ul>
</li>
<li>
<p>软 (symbolic) 链接</p>
<ul>
<li>“快捷方式”</li>
<li>软链接也是一个文件</li>
<li><code> ln -s ../p24 p24</code></li>
<li>目录从“树”变为了“图”，还是有环图</li>
</ul>
</li>
<li>
<p>ACL: access-control list</p>
<ul>
<li>Each file or directory has an ACL</li>
</ul>
</li>
</ul>
<h2 id="file-system-implementation">File-System Implementation</h2>
<ul>
<li>File system organized into layers
<ol>
<li>application program</li>
<li>logical file system
<ul>
<li>FCB: file control blocks</li>
</ul>
</li>
<li>file-organizational module</li>
<li>basic file system</li>
<li>I/O control</li>
<li>devices</li>
</ol>
</li>
</ul>
<h3 id="allocation-methods">Allocation Methods</h3>
<ul>
<li>
<p>An allocation method refers to how disk blocks are allocated for files</p>
</li>
<li>
<p>Contiguous allocation</p>
<ul>
<li>Each file occupies a set of contiguous blocks on the disk</li>
<li>Supports both sequential access and direct access （Random access）</li>
<li>问题：
<ol>
<li>External fragmentation</li>
<li>Files cannot grow</li>
</ol>
</li>
</ul>
</li>
<li>
<p>Linked allocation</p>
<ul>
<li>Each file is a linked list of disk blocks: blocks may be scattered anywhere on the disk</li>
<li>优点
<ol>
<li>容易实现</li>
<li>无外碎片</li>
<li>文件增长方便</li>
</ol>
</li>
<li>缺点：
<ol>
<li>No random access</li>
<li>Poor reliability</li>
<li>慢（链表是保存在磁盘上的，所以需要多次查询）</li>
</ol>
</li>
<li>改进： File-allocation table (FAT)
<ul>
<li>把链表信息放到了一个单独的FAT表中，而不是各个数据块中，且进行备份</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Indexed allocation</p>
<ul>
<li>
<p>Bringing all the pointers together into one location: index block</p>
</li>
<li>
<p>Solutions to large files</p>
<ol>
<li>Linked sheme
<ul>
<li>Link blocks of index table</li>
</ul>
</li>
<li>Multilevel index</li>
<li>Combined scheme
<ul>
<li>一部分是 direct pointers ，一部分是multi-indirect block</li>
</ul>
</li>
</ol>
</li>
<li>
<p>Criteria</p>
<ol>
<li>storage utilization efficiency</li>
<li>data block access time</li>
</ol>
<ul>
<li>Contiguous allocation: Good for known-size file</li>
<li>Linked allocation: Good for storage utilization</li>
<li>Indexed allocation: Access time depends on index structure, file size, block position</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="free-space-management">Free-Space Management</h3>
<ul>
<li>The free-space list 的实现
<ol>
<li>Bit vector
<ul>
<li>优点
<ul>
<li>Simple to implement</li>
<li>Efficient to find the first free block</li>
</ul>
</li>
<li>缺点
<ul>
<li>Bit map requires extra space</li>
<li>Inefficient unless the entire vector is kept in main memory</li>
</ul>
</li>
</ul>
</li>
<li>Linked Lists (free list)
<ul>
<li>优点
<ul>
<li>No waste of space</li>
</ul>
</li>
<li>缺点
<ul>
<li>Inefficient when traversing the list</li>
</ul>
</li>
</ul>
</li>
<li>Grouping</li>
</ol>
<ul>
<li>The first free block store the addresses of n free blocks</li>
<li>Easier to find a large number of free blocks</li>
</ul>
</li>
</ul>
<h2 id="mass-storage-systems">Mass-Storage Systems</h2>
<ul>
<li>
<p>Magnetic disk&rsquo;s structure</p>
<ul>
<li>Disk platter</li>
<li>track</li>
<li>sector
<ul>
<li>each track is subdivided into several sectors</li>
</ul>
</li>
<li>cylinder
<ul>
<li>is the set of tracks that are at one arm position</li>
</ul>
</li>
</ul>
</li>
<li>
<p>CLV vs. CAV</p>
<ol>
<li>ClV : constant linear velocity
<ul>
<li>CD-ROM， DVD-ROM</li>
<li>Tracks in the outermost zone hold more sectors</li>
</ul>
</li>
<li>CAV : constant angular velocity
<ul>
<li>Magnetic disk</li>
<li>The density of bits decreases from inner tracks to outer tracks to keep the data rate constant</li>
</ul>
</li>
</ol>
</li>
</ul>
<h3 id="disk-scheduling">Disk Scheduling</h3>
<ul>
<li>Access time
<ol>
<li>Seek time is the time for the disk are to move the heads to the cylinder containing the desired sector
<ul>
<li>Seek time  seek distance</li>
</ul>
</li>
<li>Rotational latency
<ul>
<li>waiting for the disk to rotate the desired sector to the disk head</li>
</ul>
</li>
</ol>
</li>
<li>Disk bandwidth
<ul>
<li>The total number of bytes transferred / the total time  between the first request for service and the completion of the last transfer</li>
</ul>
</li>
</ul>
<ol>
<li>FCFS Scheduling</li>
<li>SSTF：Shortest-seek-time-first (SSTF)
<ul>
<li>最短寻道时间优先</li>
<li>问题：
<ul>
<li>往返跑&mdash;距离很短，但速度不一定很快</li>
<li>may cause starvation of some requests</li>
</ul>
</li>
</ul>
</li>
<li>SCAN</li>
</ol>
<ul>
<li>Sometimes called the elevator algorithm</li>
</ul>
<ol start="4">
<li>C-SCAN (Circular SCAN)</li>
</ol>
<ul>
<li>The head moves from one end of the disk to the other, servicing requests as it goes</li>
<li>When it reaches the other end, however, it immediately returns to the beginning of the disk, without servicing any requests on the return trip</li>
<li>回途不载客</li>
</ul>
<ol start="5">
<li>LOOK / C-LOOK</li>
</ol>
<ul>
<li>
<p>Similar to SCAN/C-SCAN</p>
</li>
<li>
<p>Arm only goes as far as the last request in each direction, then reverses direction immediately, without first going all the way to the end of the disk.</p>
</li>
<li>
<p>选择
<strong>Performance depends on the number and types of requests</strong></p>
<ul>
<li>SCAN and C-SCAN perform better for systems that place a heavy load on the disk</li>
<li>Either SSTF or LOOK is a reasonable choice for the default algorithm</li>
</ul>
</li>
</ul>
<h3 id="disk-management">Disk Management</h3>
<ul>
<li>Disk formatting
<ul>
<li>Low-Level Formatting (physical formatting )
<ul>
<li>Dividing a disk into sectors that the disk controller can read and write</li>
</ul>
</li>
<li>logical Formatting
<ul>
<li>Creation of a file system</li>
<li>Build the metadata structures for a file system</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="raid-structure">RAID Structure</h3>
<ul>
<li>
<p>Redundant Array of Inexpensive Disks (past)</p>
</li>
<li>
<p>Redundant Array of Independent Disks (now)</p>
<ul>
<li>Used for their higher reliability and higher data-transfer rate(performance)</li>
</ul>
</li>
<li>
<p>levels</p>
<ol>
<li>RAID 0
<ul>
<li>Disk arrays with data striping at the level of blocks but without any redundancy</li>
</ul>
</li>
<li>RAID 1
<ul>
<li>Disk mirroring</li>
</ul>
</li>
<li>RAID 2
<ul>
<li>Bit-level striping or Byte-level striping</li>
<li>Memory-style error-correcting-code (ECC)</li>
</ul>
</li>
<li>RAID 3
<ul>
<li>Bit-interleaved parity</li>
</ul>
</li>
<li>RAID 4
<ul>
<li>Block-interleaved parity organization</li>
</ul>
</li>
<li>RAID 5
<ul>
<li>Block-interleaved distributed parity</li>
</ul>
</li>
</ol>
</li>
</ul>
<hr>
<h2 id="常用单词">常用单词</h2>
<ul>
<li>simultaneously : 同时地</li>
<li>idle : 空闲，懒</li>
<li>reside : 位于，居住</li>
<li>uni-processor : 单处理器</li>
<li>interleave: 交织</li>
<li>allocation : 分配</li>
<li>dashed line ： 虚线</li>
<li>minuscule : 微小的</li>
<li>concrete : 具体的</li>
<li>mandatory: 强制的</li>
<li>mediate : 调解</li>
<li>strip : 脱掉；条</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>软工导论复习笔记</title>
      <link>https://ds63.eu.org/2023/%E8%BD%AF%E5%B7%A5%E5%AF%BC%E8%AE%BA%E5%A4%8D%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Fri, 16 Jun 2023 18:28:40 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E8%BD%AF%E5%B7%A5%E5%AF%BC%E8%AE%BA%E5%A4%8D%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>没有银弹</description>
      <content:encoded><![CDATA[<h1 id="软工导论复习">软工导论复习</h1>
<h2 id="chapter-0">Chapter 0</h2>
<ul>
<li>
<p>软件工程提出时间：1968年</p>
<p>1968年北大西洋公约组织(NATO)的计
算机科学家在联邦德国召开国际会议，
讨论软件危机问题，正式提出了“软件
工程”。</p>
</li>
</ul>
<h2 id="chapter-1">Chapter 1</h2>
<ul>
<li>The nature of software
Developed / Deteriorates / Custom built/ Complex</li>
</ul>
<h2 id="chapter-2">Chapter 2</h2>
<ul>
<li>
<p>软件工程定义</p>
<ol>
<li>The application of a systematic,
disciplined, quantifiable approach to the
development, operation, and maintenance
of software; that is, the application of
engineering to software.</li>
<li>The study of approaches as in (1).</li>
</ol>
</li>
<li>
<p>Software Process</p>
<ul>
<li>why: 需要及时的反馈</li>
<li>Process framework
<ul>
<li>Framework activities
<ul>
<li>Communication</li>
<li>Planning</li>
<li>Modeling
<ol>
<li>需求分析</li>
<li>设计</li>
</ol>
</li>
<li>Construction
<ol>
<li>代码</li>
<li>测试</li>
</ol>
</li>
<li>Deployment</li>
</ul>
</li>
<li>Umbrella Activities 庇护活动（普适性活动）
<ul>
<li>Software project tracking and control</li>
<li>Risk management</li>
<li>Software quality assurance</li>
<li>Technical reviews</li>
<li>Measurement</li>
<li>Software configuration management</li>
<li>Reusability management</li>
<li>Work product preparation and production</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Software Lifecycle</p>
<ul>
<li>软件有一个孕育、诞生、成长、成熟、
衰亡的生存过程。这个过程即为计算机
软件的生命周期(生存周期)</li>
<li>why need
<ul>
<li>从时间角度对软件开发和维护的复杂问题进行分解，把软件生存的漫长周期依次划分为若干个阶段，每个阶段有相对独立的任务，然后再逐步完成每个阶段的任务。</li>
<li>为软件人提供一个公共的框架，以便软件人的相互交流。</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="chapter-4">Chapter 4</h2>
<ul>
<li>Evolutionary Models
<ul>
<li>prototype
<ul>
<li>类型
<ul>
<li>探索型(exploratory prototyping) 弄清需求</li>
<li>实验型(experimental prototyping)  验证方案</li>
<li>演化型(evolutionary prototyping)</li>
</ul>
</li>
<li>特征
<ul>
<li>可实际运行</li>
<li>它没有固定的生存期。它可能被扔掉，或者作为最终产品的一部分。</li>
<li>可为不同目标作原型</li>
<li>快速、廉价</li>
<li>是迭代过程的集成部分，即每次经用户评价后修改、运行，不断重复双方认可。</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="chapter-5">Chapter 5</h2>
<ul>
<li>敏捷宣言
<ul>
<li>个体和互动 高于 流程和工具</li>
<li>工作的软件 高于 详尽的文档</li>
<li>客户合作 高于 合同谈判</li>
<li>响应变化 高于 遵循计划</li>
</ul>
</li>
<li></li>
</ul>
<h2 id="chapter-7">Chapter 7</h2>
<h3 id="requirements-engineering">Requirements Engineering</h3>
<ul>
<li>Inception</li>
<li>Elicitation</li>
<li>Elaboration</li>
<li>Negotiation</li>
<li>Specification
<ul>
<li>根据需求调查和需求分析的结果，进一步定义准确无误的产品需求，产生《产品需求规格说明书》</li>
</ul>
</li>
<li>Validation</li>
<li>Requirements management</li>
</ul>
<h3 id="quality-function-deployment">Quality Function Deployment</h3>
<ol>
<li>功能部署——确定系统功能的价值</li>
<li>信息部署——确定数据对象和事件</li>
<li>任务部署——确定系统的行为</li>
<li>价值分析——确定需求的优先级</li>
</ol>
<h3 id="non-functional-requirements">Non-Functional Requirements</h3>
<ul>
<li>quality attribute</li>
<li>performance attribute</li>
<li>security attribute</li>
<li>general system constraint</li>
</ul>
<h3 id="diagrams">diagrams</h3>
<p>Use-case / Class / State / Activity</p>
<h2 id="chapter-11">Chapter 11</h2>
<ul>
<li>Analysis model
<ul>
<li>focus on describing required data, function and behavior</li>
</ul>
</li>
</ul>
<h3 id="design-model">Design model</h3>
<ul>
<li>provide detail about software data structure, architecture, interfaces and components</li>
<li>4 kinds
<ul>
<li>Data/Class design——将分析类转换为实现类和数据结构</li>
<li>Architectural design——定义主要软件结构元素之间的关系</li>
<li>Interface design——定义软件元素、硬件元素和最终用户如何通信</li>
<li>Component-level design——转换结构元素到软件组件的过程描述中</li>
</ul>
</li>
</ul>
<h3 id="concepts">concepts</h3>
<ul>
<li>Architecture-软件的整体结构
<ul>
<li>体现了系统的模块化,抽象和信息隐藏,接口设计</li>
<li>举例
<ul>
<li>客户-服务器架构（Client-Server Architecture）</li>
<li>微服务架构（Microservices Architecture）</li>
<li>事件驱动架构（Event-Driven Architecture）</li>
<li>分层架构（Layered Architecture）</li>
</ul>
</li>
</ul>
</li>
<li>Pattern
<ul>
<li>The goal of a pattern：easy to reuse.</li>
<li>types:
<ul>
<li>Architecture Pattern
<ul>
<li>B/S, C/S</li>
</ul>
</li>
<li>Design Pattern</li>
<li>Idiom
<ul>
<li>a low-level pattern specific to a programming language</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Functional Independence
<ul>
<li>Cohesion 内聚
<ul>
<li>an indication of the relative functional strength of a module</li>
<li>功能内聚 分层内聚 通信内聚 顺序内聚 过程内聚 时间内聚 实用内聚（由高到低排列）</li>
</ul>
</li>
<li>Coupling 耦合
<ul>
<li>an indication of the relative interdependence among modules</li>
<li>非直接耦合 数据耦合 标记耦合 控制耦合 外部耦合 共用耦合 内容耦合 （ 由低到高排列）</li>
</ul>
</li>
<li>goal: 高内聚，低耦合</li>
</ul>
</li>
</ul>
<h2 id="chapter12-behavioral-modeling">Chapter12 Behavioral Modeling</h2>
<ul>
<li>what
the structure of the system, which comprise the software components, the externally visible properties of those components, and the relationships among them</li>
<li>The importance of architecture
<ul>
<li>for communication between all parties (stakeholders)</li>
<li>highlights early design decisions</li>
<li>constitutes a relatively small, intellectually graspable mode</li>
</ul>
</li>
<li>架构有什么用
<ul>
<li>分析设计在满足其规定要求方面的有效性</li>
<li>在进行设计更改仍然相对而言的阶段考虑架构替代方案容易</li>
<li>降低与软件构建相关的风险</li>
</ul>
</li>
</ul>
<h3 id="architecture-style">Architecture Style</h3>
<ul>
<li>定义内容
<ul>
<li>一组执行系统所需功能的构件</li>
<li>一组连接器，可以实现“通信、协调和组件之间的合作”</li>
<li>定义组件如何集成以形成系统的约束</li>
<li>语义模型，使设计人员能够通过分析系统组成部分的已知特性来理解系统的整体属性</li>
</ul>
</li>
<li>种类
<ul>
<li>数据流架构——批处理、管道和过滤器</li>
<li>调用和返回架构——主程序/子程序、面向对象系统、分层系统</li>
<li>独立组件架构——事件系统、触发器、监视器</li>
<li>虚拟机架构——解释器，基于规则的系统</li>
<li>仓库架构——数据库系统，黑板系统等</li>
</ul>
</li>
</ul>
<h2 id="chapter13-component-level-design">Chapter13 Component Level Design</h2>
<ul>
<li>一个模块化的、可部署的、可替换的系统部分，它封装了实现并公开了一组接口。</li>
</ul>
<h3 id="basic-design-principles">Basic Design Principles</h3>
<ol>
<li>开闭原则（OCP）——一个模块 [组件] 应该对扩展开放但对修改关闭</li>
<li>里氏替换原则（LSP）—— “子类应该可以替代它们的基类。</li>
<li>依赖倒置原则（DIP）——依赖于抽象。不要依赖实体
<ul>
<li>高层模块应该依赖于抽象（接口或抽象类）</li>
<li>抽象不应该依赖于具体实现，具体实现应该依赖于抽象</li>
</ul>
</li>
<li>接口分离原则 (ISP)——许多专用的接口都比一个通用接口好</li>
<li>发布重用等效原则 (REP)——重用的粒度就是发布的粒度</li>
<li>共同闭合原则（CCP）——同时修改的类应该放在一起</li>
<li>共同重用原则（CRP）——不能同时复用的类不应该放在一起</li>
</ol>
<h2 id="chapter14-user-interface-design">Chapter14 User Interface Design</h2>
<ul>
<li>黄金规则
<ul>
<li>用户控制操作</li>
<li>减少用户记忆负担</li>
<li>保持界面一致</li>
</ul>
</li>
</ul>
<h2 id="chapter-15-16-software-quality">Chapter 15-16 Software Quality</h2>
<ul>
<li>
<p>什么是软件质量
一个有效的软件过程，其应用方式创造了一个有用的产品，为生产它的人和使用它的人提供可衡量的价值</p>
</li>
<li>
<p>McCall’s Triangle of Quality</p>
<ul>
<li>产品修改</li>
<li>产品转移</li>
<li>产品运行</li>
</ul>
</li>
<li>
<p>The Cost of Quality</p>
<ul>
<li>在测试和维护阶段改正错误和缺陷的成本急剧增高</li>
<li>种类：
<ol>
<li>预防成本（COP）</li>
<li>评估成本（COA）</li>
<li>内部失败成本</li>
<li>外部失败成本</li>
</ol>
</li>
</ul>
</li>
</ul>
<h2 id="chapter-17-19-testing-strategy--techniques">Chapter 17-19. Testing Strategy &amp; Techniques</h2>
<ul>
<li>Verification vs. Validation
<ul>
<li>Verification: 确保软件能实现特定功能 building the product right</li>
<li>Validation: 确保软件可追溯到客户需求 building the right product</li>
</ul>
</li>
<li>测试策略——从小到大
<ul>
<li>单元测试</li>
<li>集成测试</li>
<li>系统测试</li>
<li>验收测试
<ul>
<li>α testing 由最终用户在开发人员站点进行</li>
<li>ß testing 在最终用户站点进行</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="测试策略之unit-testing">测试策略之unit testing</h3>
<ul>
<li>内容：
<ul>
<li>接口</li>
<li>局部数据结构</li>
<li>边界条件</li>
<li>独立路径</li>
<li>错误处理路径</li>
</ul>
</li>
<li>stub——代替底层</li>
<li>driver——代替顶层
<ul>
<li>提供了一个框架用于设置输入参数，环境 ，执行单元</li>
</ul>
</li>
</ul>
<h3 id="测试策略之integration-testing">测试策略之integration testing</h3>
<ul>
<li>Top Down Integration
<ul>
<li>Advantage
<ul>
<li>A skeletal version of the program can exist early and allows demonstrations</li>
<li>Design errors may be found sooner.</li>
<li>Reduces the need for test drivers</li>
<li>It tends to make fault location easier</li>
</ul>
</li>
<li>Disadvantage
<ul>
<li>stubs could be expensive to build.</li>
</ul>
</li>
</ul>
</li>
<li>Bottom-Up Integration
<ul>
<li>Advantage
<ul>
<li>Particular useful for objects and reuse.</li>
<li>requiring no structural design information</li>
</ul>
</li>
<li>Disadvantage
<ul>
<li>The program as a whole does not exist until the last module is added.</li>
<li>requires test drivers, not test stubs.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="测试策略之system-testing充分运用基于计算机的系统">测试策略之system testing——充分运用基于计算机的系统</h3>
<ul>
<li>目的：
<ul>
<li>在将要运行的真实环境中测试整个系统</li>
<li>确保系统满足整体工作的要求</li>
<li>还要测试系统功能之外的方面</li>
<li>结果有时用于系统验收</li>
<li>验证软件用户手册</li>
<li>估计可靠性和可维护性</li>
</ul>
</li>
</ul>
<h3 id="测试方法">测试方法</h3>
<ul>
<li>黑盒测试（功能）</li>
<li>白盒测试（结构）</li>
</ul>
<h2 id="chapter-21-software-configuration-management">Chapter 21 Software configuration management</h2>
<h3 id="the-scm-process">The SCM Process</h3>
<ol>
<li>identification</li>
<li>change control</li>
<li>version control</li>
<li>configuration auditing</li>
<li>reporting</li>
</ol>
<ul>
<li>Software configuration item</li>
</ul>
<h2 id="chapter-22--project-management-concept">Chapter 22  Project Management Concept</h2>
<h3 id="4-p">4 p</h3>
<ul>
<li>people</li>
<li>product
<ul>
<li>scopes
<ol>
<li>context</li>
<li>information objectives</li>
<li>function and performance</li>
</ol>
</li>
</ul>
</li>
<li>Process
<ul>
<li>Consider project characteristics</li>
<li>Determine the degree of rigor required</li>
<li>Define a task set for each software engineering activity</li>
</ul>
</li>
<li>Project
<ol>
<li>从正确的基础上开始工作——首先通过努力理解要解决的问题，然后设定现实的目标和期望来实现的</li>
<li>保持动力——项目经理必须提供激励措施，将人员流动率控制在最低限度，团队应在其执行的每项任务中强调质量，高级管理人员应尽一切可能远离团队</li>
<li>跟踪进度——作为质量保证活动的一部分，随着工作产品（例如模型、源代码、测试用例集）的生成和批准（使用正式的技术评审），进度会被跟踪。</li>
<li>做出明智的决定——项目经理和软件团队的决定应该是“保持简单”</li>
<li>进行事后分析——建立一个一致的机制来提取每个项目的经验教训</li>
</ol>
</li>
</ul>
<h3 id="w5hh">W5HH</h3>
<ol>
<li>Why is the system being developed?——为什么</li>
<li>What will be done? ——做什么</li>
<li>When will it be accomplished?——什么时候做</li>
<li>Who is responsible?——谁负责</li>
<li>Where are they organizationally located?——其他人的组织机构位于何处</li>
<li>How will the job be done technically and managerially?——如何完成技术工作和管理工作</li>
<li>How much of each resource (e.g., people, software, tools, database) will be needed?——每种资源需要多少</li>
</ol>
<h3 id="task-set-">Task set =</h3>
<ul>
<li>Software engineering tasks</li>
<li>Work products</li>
<li>Quality assurance points</li>
<li>Milestones</li>
</ul>
<h3 id="software-engineering-activity">software engineering activity</h3>
<ul>
<li>需求分析</li>
<li>设计</li>
<li>软件开发</li>
<li>软件部署</li>
<li>软件维护</li>
<li>项目管理</li>
<li>质量保证</li>
<li>配置管理</li>
<li>文档编写</li>
</ul>
<h2 id="chapter-23-process-and-project-metrics">Chapter 23 Process and Project Metrics</h2>
<ul>
<li>意义
<ol>
<li>评估正在进行的项目的状态</li>
<li>跟踪潜在风险</li>
<li>在问题造成不良影响前发现风险</li>
<li>调整工作流程或任务</li>
<li>评估项目团队控制软件工作产品质量的能力</li>
</ol>
</li>
</ul>
<h3 id="process-measurement">Process Measurement</h3>
<ul>
<li>根据过程中获得的一系列数据或软件工程任务的特性来进行测量。</li>
<li>Software Process Improvement (SPI)</li>
<li>5 Metrics
<ul>
<li>Quality-related</li>
<li>Productivity-related</li>
<li>Statistical SQA data</li>
<li>Defecti removal effciency</li>
<li>Reuse data</li>
</ul>
</li>
</ul>
<h3 id="项目度量">项目度量</h3>
<ul>
<li>三个方面
<ul>
<li>如期</li>
<li>质量</li>
<li>成本</li>
</ul>
</li>
</ul>
<h3 id="chapter-24-25-project-estimation--scheduling">Chapter 24-25 Project Estimation &amp; Scheduling</h3>
<h3 id="scope">scope</h3>
<ul>
<li>Scope refers to all the work involved in creating the
products of the project and the processes used to
create them. It defines what is or is not to be done</li>
<li>项目范围的内容
<ul>
<li>交付给最终用户的功能和特性</li>
<li>输入和输出的数据</li>
<li>由于使用软件而呈现给用户的“内容”</li>
<li>性能、约束、接口、和约束系统的可靠性</li>
</ul>
</li>
</ul>
<h3 id="work-breakdown-structure-wbs">Work Breakdown Structure (WBS)</h3>
<ul>
<li>进行WBS的五种方法
<ol>
<li>使用指南：一些组织提供的指南</li>
<li>类比方法：审查类似项目的 WBS，并根据我们的项目 进行定制。</li>
<li>自上而下的方法：从项目中最大的项目开始，并将它们分解</li>
<li>自下而上的方法：从详细的任务开始，并将它们汇总</li>
<li>思维导图方法：以非线性格式写下任务，然后创建 WBS 结构</li>
</ol>
</li>
</ul>
<h3 id="估计方法">估计方法</h3>
<ul>
<li>基于代码行的估计
<ul>
<li>优点：易于测量、容易自动化</li>
<li>缺点：仅限于代码不能用于设计、依赖于语言、没有考虑功能的复杂性、与设计的好坏挂钩</li>
</ul>
</li>
<li>基于功能点的估计
<ul>
<li>优点：
<ol>
<li>可用于最早的需求阶段</li>
<li>独立于编程语言、产品设计或开发风格</li>
<li>用户视图，而不是实现视图</li>
<li>可用于衡量非编码活动</li>
<li>存在大量历史数据</li>
<li>有据可查</li>
</ol>
</li>
<li>缺点：
<ol>
<li>无法直接计算现有产品（源代码）的 FP 内容</li>
<li>难以自动化</li>
<li>FP 不反映语言、设计或风格差异</li>
<li>FP 设计用于估计商业数据处理应用</li>
<li>主观计数</li>
</ol>
</li>
</ul>
</li>
</ul>
<h3 id="项目调度">项目调度</h3>
<ol>
<li>项目为什么会延期
不切实际的截止日期
需求的变化
低估工作量
不可预测的风险
技术难题
人为困难
沟通不畅
未能认识到项目落后于计划或缺乏纠正问题的行动</li>
<li>调度的原则
划分——定义多个不同的任务
相互依赖性——明确任务的相互关系
工作量确认——确保人力资源可用
确定责任——明确责任承担者
明确输出结果——确定活动产生的结果
确定里程碑——进行质量审查</li>
<li>调度的步骤
<ol>
<li>定义任务集——WBS</li>
<li>安排活动</li>
<li>绘制项目网络图</li>
<li>关键路径分析</li>
<li>使用甘特图进行调度</li>
<li>进度跟踪</li>
</ol>
</li>
</ol>
<h2 id="chapter-26-risk-management">Chapter 26 Risk Management</h2>
<ul>
<li>
<p>Reactive Risk Management</p>
</li>
<li>
<p>Proactive Risk Management</p>
<ul>
<li>formal risk analysis is performed</li>
<li>corrects the root causes of risk</li>
</ul>
</li>
<li>
<p>Risk Management Paradigm</p>
<ol>
<li>Risk identification</li>
<li>Risk analysis</li>
<li>Risk planning</li>
<li>Risk monitoring</li>
</ol>
</li>
<li>
<p>RMMM</p>
<ul>
<li>Mitigation</li>
<li>Monitoring</li>
<li>Management</li>
</ul>
</li>
</ul>
<h2 id="常用图">常用图</h2>
<ul>
<li>用例图</li>
<li>类图</li>
<li>活动图
<ul>
<li>变形：泳道图</li>
</ul>
</li>
<li>顺序图</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tears of the Kingdom</title>
      <link>https://ds63.eu.org/2023/tears-of-the-kingdom/</link>
      <pubDate>Mon, 05 Jun 2023 21:30:39 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2023/tears-of-the-kingdom/</guid>
      <description>第一个让我想写点什么，并且真的写了点什么的游戏
游戏历程 5月3日开始玩偷跑的模拟器版本。（这里先自我检讨，不仅是玩的盗版，而且还是偷跑版本。以后经济独立后尽量补票。）中间间断了几天，昨天打完加侬多夫，算是通关了。打完蛮惆怅的，各种看视频网站、刷贴吧想看看别人的感受，没找着。洗澡的时候有些想法，就想着自己写一写。
想法 23年过年前我下了一堆游戏，但过完年到了二月份就开始对游戏提不起兴趣，一直到5月初接触了《王国之泪》才一发不可收拾，玩游戏玩得熬了好几次夜。
这游戏为什么有那么大的魔力。我想了几点：
剧情。说实话剧情在我玩不到5天的时候就大概能知道是个什么样的剧情了。但还是觉得是恶搞不错的剧情。很喜欢这作里林克和塞尔达的关系。塞尔达对林克的这种信任，跨越时间、牺牲自己的信任，我着实有被感动到。
人物。
塞尔达。这作的塞尔达真的很美。她在哈特诺学校里当了一段时间的老师，家里还挂着学生给她画的画。她周游海拉鲁大陆，各地的人民那都能听到他的评价。 加侬多夫。没啥感觉，甚至有点想笑。最终的boss战难度即使手残如我也能一把过，但一万年前却那样的所向披靡。加上boss的一些宣言逼格也感觉不高。不过倒不影响就是了。打完后才知道中途要是死了就得冲怪物大军那边开始，想想就感到庆幸。 卡卡利特村的村民。最恶心的一个村子。说实话，我玩这作的时候带着“我前几年拯救了世界，你们不要说要怎么崇拜我，至少得尊重我吧”的想法。但在这个村子却觉得地位比普通村民还低。一个村民直接躺石板上睡觉不让我直接叫醒，还得我去找生命松露来；而我只是要去摸一下石板都会被喝止。更不用说有一个地点我尝试了多种方式也不让进。虽然后面才知道这是剧情的要求，但还是觉得很不爽。 沃特里村的村民。这反倒和卡卡利特村形成了鲜明了对比，在这里感受到了尊重。任务做起来也有意思。 和前作的关系： 这作的时间线应该是在旷野之息之后的几年。可以说是续作。但前作的希卡科技几乎消失殆尽。这点也被许多老玩家所吐槽。我虽然也有玩过旷野之息，但只通了风、水两个神殿，加上玩的时候过度使用金手指，导致游戏体验并不好。所以对前作没什么感情。因此反倒是影响不大。
另外，这作还成功勾起了我对塞尔达传说全作的兴趣。在了解了一些相关信息后（云了几个视频），现在更能感受到本作里埋的一些彩蛋。羡慕那些早早入坑的玩家，他们得有多幸福啊。
配乐。印象最深的风神殿那段，太棒了。虽然进神殿前的跳跳乐我跳了快一个下午，但这并不影响其给我带来的震撼。
上面说了这么多，还没有说到点子上。我觉得最吸引我的是这几点：
开发人员的周到。玩的时候能感受到开发人员是真的有很细致地玩过:趁手的工具，丰富的文本，能让我有一种感觉：开发人员把我能想到的都想到了。这点做起来似乎也不难,但实际上我玩过的游戏中，似乎只有赛尔达传说真正做到了这点。 合乎直觉。这点似乎和上一点是相同的。但我还是把它单独列出来了。因为这点太棒了。我一直觉得一个好的设计的最高标准就是合乎直觉，你拿到一个产品，你不需要看说明书，不需要问别人，你拿到手就能用，我觉得这就是一个很棒的体验。而要做得合乎直觉，特别是游戏这种，就需要开发人员想得够多。王国之泪的开发人员就做得特别好。 探索欲。看过一篇讲旷野之息的文章，说任天堂通过塔、神庙、宝箱等将一个大的地图切分成了一个个的三角。我觉得说得很在理。而王国之泪更是加强了这一点，因为有了鸟望塔的存在。射向高空后，看到特殊的地形、神庙、龙之泪，就有忍不住想一一探索的冲动。这也是导致一玩就难以停止，永远想着这个结束就暂停，永远都会冒出来新的可探索点。 能力。这作的能力十分出彩。通天术增强了机动性。余料建造对武器系统的丰富。究极手更是被玩出花来。我玩游戏一向很菜，不仅手残而且创意也一般，但看网上各种脑洞大开的拼法也是我这一个月以来的一大乐趣。 手残友好。难度设计不高，且有较合适的引导，而且不乏逃课手段，这让我能更好地去体验游戏的乐趣。 技术。我一直记得自己在知道超级玛丽的程序员为了去适配游戏机的性能所做的各种奇淫巧技时的震撼，太magic了。王国之泪的技术力也很强，16g左右的大小在今天已经不能算大，但这作的丰富程度却是很多其他游戏所不能比拟的。而且bug也不多，除了一些复制bug，我好像没有看到有说什么影响游戏体验的恶性bug。 再说下模拟器。模拟器从偷跑刚出时候的明显卡顿、不断闪退、贴图错误，到现在的流畅体验，离不开模拟器开发和维护者的不断努力。而刚出的那几天，相关社区里的氛围也十分好。很多都是分享自己增强游戏体验的设置。说句可能不是很恰当的话，我在这点上感受到了互联网精神 —— 互帮互助、不求回报、持续钻研。我是这样理解的。这也可以说是王国之泪吸引我的一点。
尾巴 今天(2023年6月7日)看到一句话“突然明白了什么才是好游戏，就连看它的玩家们怎么玩都是一件很有趣的事”。说得真好。
尾巴的尾巴 王国之泪就是这样一款好游戏。我直到现在（2023年12月5日），当在网上看到相关的视频，还是有兴趣点进去看看。
今天翻了下自己之前写的日记，在五月份时“王国之泪”的含量特别高。现在回想那段时间的记忆都觉得跟上了滤镜一样，特美。
期待大师模式，想再玩一遍。</description>
      <content:encoded><![CDATA[<p><em>第一个让我想写点什么，并且真的写了点什么的游戏</em></p>
<h2 id="游戏历程">游戏历程</h2>
<p>5月3日开始玩偷跑的模拟器版本。（这里先自我检讨，不仅是玩的盗版，而且还是偷跑版本。以后经济独立后尽量补票。）中间间断了几天，昨天打完加侬多夫，算是通关了。打完蛮惆怅的，各种看视频网站、刷贴吧想看看别人的感受，没找着。洗澡的时候有些想法，就想着自己写一写。</p>
<h2 id="想法">想法</h2>
<p>23年过年前我下了一堆游戏，但过完年到了二月份就开始对游戏提不起兴趣，一直到5月初接触了《王国之泪》才一发不可收拾，玩游戏玩得熬了好几次夜。</p>
<p>这游戏为什么有那么大的魔力。我想了几点：</p>
<ul>
<li>
<p>剧情。说实话剧情在我玩不到5天的时候就大概能知道是个什么样的剧情了。但还是觉得是恶搞不错的剧情。很喜欢这作里林克和塞尔达的关系。塞尔达对林克的这种信任，跨越时间、牺牲自己的信任，我着实有被感动到。</p>
</li>
<li>
<p>人物。</p>
<ul>
<li>塞尔达。这作的塞尔达真的很美。她在哈特诺学校里当了一段时间的老师，家里还挂着学生给她画的画。她周游海拉鲁大陆，各地的人民那都能听到他的评价。</li>
<li>加侬多夫。没啥感觉，甚至有点想笑。最终的boss战难度即使手残如我也能一把过，但一万年前却那样的所向披靡。加上boss的一些宣言逼格也感觉不高。不过倒不影响就是了。打完后才知道中途要是死了就得冲怪物大军那边开始，想想就感到庆幸。</li>
<li>卡卡利特村的村民。最恶心的一个村子。说实话，我玩这作的时候带着“我前几年拯救了世界，你们不要说要怎么崇拜我，至少得尊重我吧”的想法。但在这个村子却觉得地位比普通村民还低。一个村民直接躺石板上睡觉不让我直接叫醒，还得我去找生命松露来；而我只是要去摸一下石板都会被喝止。更不用说有一个地点我尝试了多种方式也不让进。虽然后面才知道这是剧情的要求，但还是觉得很不爽。</li>
<li>沃特里村的村民。这反倒和卡卡利特村形成了鲜明了对比，在这里感受到了尊重。任务做起来也有意思。</li>
</ul>
</li>
<li>
<p>和前作的关系：
这作的时间线应该是在旷野之息之后的几年。可以说是续作。但前作的希卡科技几乎消失殆尽。这点也被许多老玩家所吐槽。我虽然也有玩过旷野之息，但只通了风、水两个神殿，加上玩的时候过度使用金手指，导致游戏体验并不好。所以对前作没什么感情。因此反倒是影响不大。</p>
<p>另外，这作还成功勾起了我对塞尔达传说全作的兴趣。在了解了一些相关信息后（云了几个视频），现在更能感受到本作里埋的一些彩蛋。羡慕那些早早入坑的玩家，他们得有多幸福啊。</p>
</li>
<li>
<p>配乐。印象最深的风神殿那段，太棒了。虽然进神殿前的跳跳乐我跳了快一个下午，但这并不影响其给我带来的震撼。</p>
</li>
</ul>
<p>上面说了这么多，还没有说到点子上。我觉得最吸引我的是这几点：</p>
<ul>
<li><strong>开发人员的周到</strong>。玩的时候能感受到开发人员是真的有很细致地玩过:趁手的工具，丰富的文本，能让我有一种感觉：开发人员把我能想到的都想到了。这点做起来似乎也不难,但实际上我玩过的游戏中，似乎只有赛尔达传说真正做到了这点。</li>
<li><strong>合乎直觉</strong>。这点似乎和上一点是相同的。但我还是把它单独列出来了。因为这点太棒了。我一直觉得一个好的设计的最高标准就是合乎直觉，你拿到一个产品，你不需要看说明书，不需要问别人，你拿到手就能用，我觉得这就是一个很棒的体验。而要做得合乎直觉，特别是游戏这种，就需要开发人员想得够多。王国之泪的开发人员就做得特别好。</li>
<li><strong>探索欲</strong>。看过一篇讲旷野之息的文章，说任天堂通过塔、神庙、宝箱等将一个大的地图切分成了一个个的三角。我觉得说得很在理。而王国之泪更是加强了这一点，因为有了鸟望塔的存在。射向高空后，看到特殊的地形、神庙、龙之泪，就有忍不住想一一探索的冲动。这也是导致一玩就难以停止，永远想着这个结束就暂停，永远都会冒出来新的可探索点。</li>
<li><strong>能力</strong>。这作的能力十分出彩。通天术增强了机动性。余料建造对武器系统的丰富。究极手更是被玩出花来。我玩游戏一向很菜，不仅手残而且创意也一般，但看网上各种脑洞大开的拼法也是我这一个月以来的一大乐趣。</li>
<li><strong>手残友好</strong>。难度设计不高，且有较合适的引导，而且不乏逃课手段，这让我能更好地去体验游戏的乐趣。</li>
<li><strong>技术</strong>。我一直记得自己在知道超级玛丽的程序员为了去适配游戏机的性能所做的各种奇淫巧技时的震撼，太magic了。王国之泪的技术力也很强，16g左右的大小在今天已经不能算大，但这作的丰富程度却是很多其他游戏所不能比拟的。而且bug也不多，除了一些复制bug，我好像没有看到有说什么影响游戏体验的恶性bug。</li>
</ul>
<p>再说下模拟器。模拟器从偷跑刚出时候的明显卡顿、不断闪退、贴图错误，到现在的流畅体验，离不开模拟器开发和维护者的不断努力。而刚出的那几天，相关社区里的氛围也十分好。很多都是分享自己增强游戏体验的设置。说句可能不是很恰当的话，我在这点上感受到了互联网精神 —— 互帮互助、不求回报、持续钻研。我是这样理解的。这也可以说是王国之泪吸引我的一点。</p>
<h2 id="尾巴">尾巴</h2>
<p>今天(2023年6月7日)看到一句话“突然明白了什么才是好游戏，就连看它的玩家们怎么玩都是一件很有趣的事”。说得真好。</p>
<h2 id="尾巴的尾巴">尾巴的尾巴</h2>
<p>王国之泪就是这样一款好游戏。我直到现在（2023年12月5日），当在网上看到相关的视频，还是有兴趣点进去看看。</p>
<p>今天翻了下自己之前写的日记，在五月份时“王国之泪”的含量特别高。现在回想那段时间的记忆都觉得跟上了滤镜一样，特美。</p>
<p>期待大师模式，想再玩一遍。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>git常用命令</title>
      <link>https://ds63.eu.org/2023/git_cheatsheet/</link>
      <pubDate>Fri, 26 May 2023 13:18:01 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/git_cheatsheet/</guid>
      <description>a cheatsheet of git commands</description>
      <content:encoded><![CDATA[<p><strong>本篇内容大部分非我原创，只是我自己整理的笔记，具体出处请见<a href="#%e5%8f%82%e8%80%83" >参考</a></strong></p>
<h2 id="clone">clone</h2>
<p>可以仅clone单个分支的最新内容</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone --single-branch --depth <span class="m">1</span> --branch <span class="s2">&#34;</span><span class="nv">$TARGET_BRANCH</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$GIT_CMD_REPOSITORY</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$CLONE_DIR</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># </span>
</span></span><span class="line"><span class="cl"><span class="nv">GIT_CMD_REPOSITORY</span><span class="o">=</span><span class="s2">&#34;https://</span><span class="nv">$DESTINATION_REPOSITORY_USERNAME</span><span class="s2">:</span><span class="nv">$API_TOKEN_GITHUB</span><span class="s2">@</span><span class="nv">$GITHUB_SERVER</span><span class="s2">/</span><span class="nv">$DESTINATION_REPOSITORY_USERNAME</span><span class="s2">/</span><span class="nv">$DESTINATION_REPOSITORY_NAME</span><span class="s2">.git&#34;</span>
</span></span><span class="line"><span class="cl">git clone --single-branch --depth <span class="m">1</span> <span class="s2">&#34;</span><span class="nv">$GIT_CMD_REPOSITORY</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$CLONE_DIR</span><span class="s2">&#34;</span>
</span></span></code></pre></div><h2 id="add">add</h2>
<ul>
<li><code>git add .</code> 会根据.gitignore做过滤</li>
<li><code>git add *</code> 会忽略.gitignore把任何文件都加入</li>
<li><code>git add -p</code> 会逐个显示文件中的每组改动，并询问是否要加入 index</li>
</ul>
<h2 id="commit">commit</h2>
<p>可以通过环境变量更改提交时间哦</p>
<ul>
<li><code>export GIT_COMMITTER_DATE=”Jan 11 17:11:18 2018 +0800”</code></li>
<li><code>export GIT_AUTHOR_DATE=”Jan 11 17:11:18 2018 +0800”</code></li>
<li><code>git commit –amend –date=date -R</code></li>
</ul>
<h2 id="push">push</h2>
<p>文件推送的三个步骤：</p>
<pre tabindex="0"><code>git add 
git commit -m&#34;输入想说的话&#34;
git push
</code></pre><h2 id="status">status</h2>
<p><code>git status</code></p>
<h2 id="branch">branch</h2>
<ul>
<li>
<p>转到另一个分支 <code>git checkout {分支名}</code></p>
</li>
<li>
<p>查看本地分支 <code>git branch</code></p>
</li>
<li>
<p>查看远程分支 <code>git branch -r</code></p>
</li>
<li>
<p>查看本地和远程分支 <code>git branch -a</code></p>
</li>
<li>
<p>删除本地分支 <code>git branch -d {本地分支名}</code></p>
</li>
<li>
<p>强制删除本地分支<code>git branch -D {本地分支名}</code></p>
</li>
<li>
<p>删除远程分支 <code>git push origin --delete {远程分支名}</code></p>
</li>
<li>
<p>已经删除的远程分支但仍<code>git branch -a</code>时仍显示 ：<code>git remote prune origin</code></p>
</li>
</ul>
<h2 id="log">log</h2>
<ul>
<li><code>git log</code> 查看分支提交历史</li>
<li><code>git reflog</code> 也是查看日志，主要区别是会显示<code>reset --hard</code></li>
</ul>
<h2 id="reset">reset</h2>
<ul>
<li><code>git reset HEAD</code> 撤销上一次的<code>add</code></li>
<li><code>git reset HEAD ${filename}</code> 仅撤销某一文件</li>
<li><code>git reset --hard {commit_id}</code></li>
<li><code>git reset --hard HEAD^ </code> 回退到上一版本</li>
</ul>
<h2 id="config">config</h2>
<ul>
<li><code>git config --global user.name &quot;Your Name&quot;</code></li>
<li><code>git config --global user.email &quot;youremail@example.com&quot;</code></li>
<li><code>git config --global --list</code> 查看配置</li>
<li><code>git config --global http.proxy 'http://127.0.0.1:7890'</code></li>
<li><code>git config --global https.proxy 'http://127.0.0.1:7890'</code></li>
</ul>
<h2 id="tag">tag</h2>
<ul>
<li><code>git tag</code> 列出所有已有的标签</li>
<li>tag 分为两种：
<ul>
<li>lightweight tag，例：<code>git tag v1.0</code></li>
<li>annotated tag, 例： <code>git tag -a v2.0 -m &quot;version 2.0&quot;</code></li>
</ul>
</li>
<li><code> git tag -d v1.0</code> 删除标签</li>
<li><code>git push origin v2.0</code> 上传标签到远程仓库</li>
<li><code>git push origin --tags</code> 上传所有未推送过的本地标签</li>
<li><code>git fetch origin tag &lt;tagname&gt;</code> 下载远程仓库的标签</li>
</ul>
<h2 id="commit-message-type">commit message type</h2>
<ul>
<li>feat：新功能（feature）</li>
<li>fix：修补bug</li>
<li>docs：文档（documentation）</li>
<li>style： 格式（不影响代码运行的变动）</li>
<li>refactor：重构（即不是新增功能，也不是修改bug的代码变动）</li>
<li>test：增加测试</li>
<li>chore：构建过程或辅助工具的变动</li>
</ul>
<h2 id="git-查询">Git 查询</h2>
<p>在之前的所有提交信息里进行搜索，找到其中和搜索条件相匹配的最近的一条。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ git show :/query
</span></span></code></pre></div><p>这里 <code>query</code> （区别大小写）是你想要搜索的词语， 这条命令会找到包含这个词语的最后那个提交并显示变动详情。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ git show :/typo
</span></span></code></pre></div><p>
  <img loading="lazy" src="http://i.imgur.com/icaGiNt.png" alt="git show :/query"  /></p>
<p>注：按 <code>q</code> 键退出命令</p>
<h2 id="fetch">fetch</h2>
<ul>
<li>
<p><strong>同步其他分支</strong>
在远端 PR 被合并之后往往需要切换到主分支然后重现拉取代码，这会无意义地去重新触发一次旧版本的索引，下面这条命令可以在不切换分支的情况下更新 master 到最新: <code>git fetch origin master:master</code></p>
</li>
<li>
<p><strong>检出 Pull Requests</strong>
对 Github 仓库来说，Pull Request 是种特殊分支， 可以通过以下多种方式取到本地：</p>
<p>取出某个特定的 Pull Request 并临时作为本地的 <code>FETCH_HEAD</code> 中以便进行快速查看更改( diff )以及合并( merge )：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ git fetch origin refs/pull/<span class="o">[</span>PR-Number<span class="o">]</span>/head
</span></span></code></pre></div><p>通过 refspec 获取所有的 Pull Request 为本地分支：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ git fetch origin <span class="s1">&#39;+refs/pull/*/head:refs/remotes/origin/pr/*&#39;</span>
</span></span></code></pre></div></li>
</ul>
<h2 id="stash">stash</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git stash <span class="c1"># when you want to record the current state of the working directory and the index, but want to go back to a clean working directory</span>
</span></span><span class="line"><span class="cl">git stash list 
</span></span><span class="line"><span class="cl">git stash pop
</span></span><span class="line"><span class="cl">git stash apply
</span></span></code></pre></div><h2 id="二分-debug">二分 debug</h2>
<p>给定两个提交记录 git 辅助你二分查找 bug 的引入时间，同时支持运行脚本</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git bisect start
</span></span><span class="line"><span class="cl">git bisect bad
</span></span><span class="line"><span class="cl">git bisect good v1.0.0
</span></span><span class="line"><span class="cl">git bisect reset
</span></span><span class="line"><span class="cl">git bisect start bad_commit good_commit
</span></span><span class="line"><span class="cl">git bisect run test-error.sh
</span></span></code></pre></div><h2 id="参考">参考</h2>
<ul>
<li><a href="https://github.com/tiimgreen/github-cheat-sheet/blob/master/README.zh-cn.md"  target="_blank" rel="noopener" >github-cheat-sheet/README.zh-cn.md at master · tiimgreen/github-cheat-sheet</a></li>
<li><a href="https://gist.github.com/rishavpandey43/84665ffe3cea76400d8e5a1ad7133a79"  target="_blank" rel="noopener" >This gist consist of the rules and best practice of good conventional git commit message</a></li>
<li><a href="https://gist.github.com/robertpainsi/b632364184e70900af4ab688decf6f53"  target="_blank" rel="noopener" >Commit message guidelines</a></li>
<li><a href="https://blog.frankzhao.cn/config_your_git/"  target="_blank" rel="noopener" >如何高效配置你的 Git - Frank 的个人博客</a></li>
<li><a href="https://git-scm.com/docs/git-stash"  target="_blank" rel="noopener" >Git - git-stash Documentation</a></li>
<li><a href="https://www.waterwater.moe/2020/06/24/2020-06-24_Git%E5%B0%8F%E8%B4%B4%E5%A3%AB/"  target="_blank" rel="noopener" >Git 小贴士 | Water Space</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>死亡</title>
      <link>https://ds63.eu.org/2023/death/</link>
      <pubDate>Sat, 20 May 2023 00:35:36 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/death/</guid>
      <description>死去何所道，托体同山阿。</description>
      <content:encoded><![CDATA[<h2 id="隋炀帝墓">隋炀帝墓</h2>
<p>查扬州旅游景点时看到有隋炀帝墓考古遗址公园。词条中有句话。</p>
<blockquote>
<p>后来的考证，1980年代进，当地居民在隋炀帝墓附近建房，曾在主墓室中心上方挖过一个粪坑，底部距离墓室仅半米。</p>
</blockquote>
<p>堂堂帝王，千年后安眠之地却差点要成了粪坑。令人唏嘘。</p>
<h2 id="寻梦环游记">寻梦环游记</h2>
<p>这部电影无论是中文名还是英文名我都觉得取得一般。中文太烂大街了，英文不知道的还以为是讲奶茶的。</p>
<p>但无法掩盖这部电影绝对是部好电影。关于死亡的电影我觉得目前没有比它更好的。</p>
<p>我喜欢电影中墨西哥人的亡灵节。喜欢这种理念——一个人真正的死是世界上再也没有人记得他。</p>
<h2 id="2023年5月19日">2023年5月19日</h2>
<p>今天看<a href="https://soulogic.com/item/3294"  target="_blank" rel="noopener" >我的郑老三死了</a>，很有感触。</p>
<p>摘抄几段文字</p>
<blockquote>
<p>之后的这两天里，我每天要嘱咐自己不下二十次，郑老三已经永远的消失了，没有任何挽救的方法。不要去幻想还有另一个世界存在，因为天堂是不自洽的。接受这个事实，有出生就有死亡。我们都会死，郑老三会死，我和我老婆将来要有一个人去承受对方先死的痛苦，将来我们的孩子也会死。在这之前我以为自己已经反复思考过终有一死，没有例外，反复读过《耶鲁大学公开课：死亡》，可真碰到的时候才发现自己就像读过如何游泳的书一样。
&hellip;
这时候我才明白“文化”的意义，我之前一直有类似“工业党”的心态，觉得逻辑思维才代表着人类的进步（网站名 Soulogic 表明了这种倾向），但其实人类大部分时间都在面对着无力改变的事情，需要有人从事艺术创作来抒发喜怒哀乐。理科是改良，文科是本。或者放大到极端来说，如果将来的人类（或者取代了人类的 AI）征服了整个宇宙，却已经没人会吟唱一首深情地求爱或者悼念逝者的歌曲，那这个物种不值得存在，只是些分布广泛、化学性质活泼的泡沫而已。</p>
<p>同时曲解死亡的定义、相信灵魂不灭是一个非常大的诱惑，我必须费很大的力气去克制。很明显不能要求所有人都能正确地理解死亡，就像不能要求所有人中考物理满分一样，那太刻薄了。其实“正确”一词出现在上句话里本身就充满了傲慢。</p>
<p>我也因此明白宗教存在的意义，可以抛弃一些细枝末节，诸如没必要相信天使、对圣餐的解释，但是，所有人在任何时候都是坚定的无神论者，这感觉并不妙。别误会，我没有屈服，但是相比世间所有的心理打击，我碰到的这次简直什么都不算。所以完全摈弃宗教是不可思议的。</p>
</blockquote>
<p>今天看贴吧的时候还看到：</p>
<p>有人说</p>
<blockquote>
<p>我叔检查出晚期，要放弃了，但是堂弟的老婆有了身孕，叔想看孙子，靠着止痛药硬抗。最后堂弟竭尽全力花费这么多年的积蓄吊着他一口气，坚持了六个月。医生说一般人能坚持一个月就到头了，我叔坚持六个月真是奇迹。”</p>
</blockquote>
<p>路人a回“孙子出生了，家里钱全花光了，说不定还欠点，孩子怎么养？现在小孩开销大的离谱”</p>
<p>路人b怼他“那换是你你愿意让你爹带着遗憾走，然后自己愧疚一辈子？”</p>
<p>路人a回路人b“他不想死我就尽力治，不过如果是我老了我不会让我儿子治我”</p>
<p>层主回复：</p>
<blockquote>
<p>差了两个月。本来发现的时候已经放弃了，我堂弟的工资尚可，家里有点地种果的，年收入20这样。叔叔想给儿子孙子留点，但是堂弟觉得钱还能再赚，可是人没了就是遗憾了，所以竭尽全力想让他看一眼孙子。上面的人大概都是孤儿吧，不懂什么叫孝心。</p>
</blockquote>
<p>（差了两个月这五个字我越看越难受，甚至有点泪。太残酷了，太残酷了）</p>
<p>我发现不少人其实都有类似路人a的想法：老了得了绝症就不治了，钱先不说，主要治不好，治疗过程大多又很痛苦，不如趁最后的时间想干啥干啥，潇洒潇洒。</p>
<p>但很可能也只是说得容易，真到了那时候有很多东西阻挡着，让你身不由己。</p>
<h2 id="2023年6月6日">2023年6月6日</h2>
<p>今天细读了陶渊明的《拟挽歌辞》</p>
<pre tabindex="0"><code>有生必有死，早终非命促。
昨暮同为人，今旦在鬼录。
魂气散何之，枯形寄古木。
娇儿索父啼，良友抚我哭，
得失不复知，是非安能觉！
千秋万岁后，谁知荣与辱？
但恨在世时，饮酒不得足。

在昔无酒饮，今但湛空觞。
春醪生浮蚁，何时更能尝！
肴案盈我前，亲旧哭我旁。
欲语口无音，欲视眼无光。
昔在高唐寝，今宿荒草乡；
一朝出门去，归来夜未央。

荒草何茫茫，白杨亦萧萧。
严霜九月中，送我出远郊。
四面无人居，高坟自嶣峣。
马为仰天鸣，风为自萧条。
幽室一已闭，千年不复朝。
千年不复朝，贤达无奈何。
向来相送人，各自还其家。
亲戚或余悲，他人亦已歌。
死去何所道，托体同山阿。
</code></pre><p>之前读不懂，今年读懂了。</p>
<p>“得失不复知，是非安能觉”这句，让我想到“死去元知万事空”。他们都不信什么在天之灵，都认为死了就是死了。我也认同这种想法，但更希望能有在天之灵。</p>
<p>“亲戚或余悲，他人亦已歌”。听着很残酷，但我现在觉得：死后能让他人偶尔想起，已经是很了不起的事了。</p>
<h2 id="2024年9月19日">2024年9月19日</h2>
<p>看<a href="https://x.com/lspk_cn/status/1836313103958434243"  target="_blank" rel="noopener" >老是扑空 on X: &ldquo;关照侄子，二哥的事不对扬州这边任何亲人说。中午吃饭时也没对太太和女儿说。 无力回天徒增悲伤的事，说无意义，做也无意义。 只是觉得我们这代人愚昧，教育不够，下一代会通透一些。但不然，人类的某些悲剧注定将一代代延续下去。 https://t.co/kk2J0OSKxO&rdquo; / X</a></p>
<p>老先生将自己和侄子的聊天记录分享出来，我一个外人看得很有感触。</p>
<p>其实大体内容和<a href="#2023%e5%b9%b45%e6%9c%8819%e6%97%a5" >我在23年5月19日刷贴吧看到的差不多</a></p>
<p>但我还是想记录几句触动到我的。</p>
<ul>
<li>她们的想法也差不多，只是到了这个时候，谁又忍心把管子拔掉呢?</li>
<li>我是反复交代了：不切管，不抢救，不进icu。省得家人为难，亲人遭罪，自己也痛苦</li>
<li>人到临了，还是事与愿违，不难痛痛快快告别这个世界。不知道还有什么比这更让人失望的了。</li>
<li>大概是身边人不把事做到极致，就觉得对不起自己，对不起亲人。徒劳努力的过程，也是一个缓慢告别，安慰自己，心理适应的过程。</li>
<li>只是觉得我们这代人愚昧，教育不够，下一代会通透一些。但不然，人类的某些悲剧注定将一代代延续下去。</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>《悉达多》摘录</title>
      <link>https://ds63.eu.org/2023/%E6%82%89%E8%BE%BE%E5%A4%9A%E6%91%98%E5%BD%95/</link>
      <pubDate>Tue, 16 May 2023 00:43:47 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%82%89%E8%BE%BE%E5%A4%9A%E6%91%98%E5%BD%95/</guid>
      <description>万法皆如，俱入目前。</description>
      <content:encoded><![CDATA[<h1 id="悉达多摘录">《悉达多》摘录</h1>
<ul>
<li>您在第 13 页（位置 #186-188）的标注 | 添加于 2023年3月17日星期五 上午5:55:20</li>
</ul>
<h1 id="他已经学会如何默念唵-这真言之本吸气时内心默念呼气时则集聚全部的精神每当此刻他的前额仿佛放射出纯净的心灵之光他已学会如何在自我存在的深层体认阿特曼永恒不坏与宇宙合一">他已经学会如何默念“唵 ”——这真言之本：吸气时内心默念，呼气时则集聚全部的精神，每当此刻，他的前额仿佛放射出纯净的心灵之光。他已学会如何在自我存在的深层体认阿特曼——永恒不坏，与宇宙合一。</h1>
<ul>
<li>您在第 15 页（位置 #216-217）的标注 | 添加于 2023年3月17日星期五 上午5:59:35</li>
</ul>
<h1 id="他们的确极为渊博但假如他们不了解那件重要的事那唯一重要之事那么是否还值得了解上述的一切">他们的确极为渊博，但假如他们不了解那件重要的事，那唯一重要之事，那么是否还值得了解上述的一切?</h1>
<ul>
<li>您在第 15 页（位置 #225-226）的标注 | 添加于 2023年3月17日星期五 上午6:00:57</li>
</ul>
<h1 id="为什么毫无过错的他要每天沐浴一新并试图洗清自己的罪孽呢">为什么毫无过错的他要每天沐浴一新，并试图洗清自己的罪孽呢?</h1>
<ul>
<li>您在第 20 页（位置 #294-295）的标注 | 添加于 2023年3月17日星期五 上午8:05:55</li>
</ul>
<h1 id="所有这一切都不值一顾一切都是欺骗一切都散发着谎言的恶臭无论快乐或是美丽都只是感官造成的幻象一切注定要腐朽世界充满苦痛生命即苦">所有这一切都不值一顾，一切都是欺骗，一切都散发着谎言的恶臭；无论快乐或是美丽都只是感官造成的幻象，一切注定要腐朽。世界充满苦痛，生命即苦。</h1>
<ul>
<li>您在第 21 页（位置 #312-312）的标注 | 添加于 2023年3月17日星期五 上午8:08:31</li>
</ul>
<h1 id="征服了旧的渴望又会感到新的渴望">征服了旧的渴望。又会感到新的渴望。</h1>
<ul>
<li>您在第 27 页（位置 #409-412）的标注 | 添加于 2023年3月17日星期五 上午8:20:07</li>
</ul>
<h1 id="他平和的表情既非欢喜亦非忧伤-他仿佛从内心发出温和的微笑-他静静地安详地走着-带着一种神秘的微笑-这微笑与一个健康婴孩的笑并无不同">他平和的表情既非欢喜，亦非忧伤。 他仿佛从内心发出温和的微笑。 他静静地，安详地走着， 带着一种神秘的微笑， 这微笑与一个健康婴孩的笑并无不同。</h1>
<ul>
<li>您在第 33 页（位置 #493-496）的标注 | 添加于 2023年3月18日星期六 下午4:08:55</li>
</ul>
<h1 id="让我来告诉你们这些渴求知识的人不要陷入论辩的渊薮和言辞的冲突辩言毫无意义它们或优美或丑陋或聪明或愚蠢任何人都可以接受或拒绝然而你已听过的教义却并非我的辩言它的目标也并非向那些追求知识的人们解释这个世界它的目标与众不同这就是超拔苦难而得救乔答摩所宣讲的仅此而已">让我来告诉你们这些渴求知识的人，不要陷入论辩的渊薮和言辞的冲突。辩言毫无意义，它们或优美或丑陋，或聪明或愚蠢，任何人都可以接受或拒绝。然而你已听过的教义却并非我的辩言，它的目标也并非向那些追求知识的人们解释这个世界。它的目标与众不同：这就是超拔苦难而得救，乔答摩所宣讲的仅此而已</h1>
<ul>
<li>您在第 34 页（位置 #510-511）的标注 | 添加于 2023年3月20日星期一 下午4:07:56</li>
</ul>
<h1 id="我无权去评判他人的生活我必须为自己做出判断我必须选择或抛弃">我无权去评判他人的生活，我必须为自己做出判断。我必须选择或抛弃。</h1>
<ul>
<li>您在第 37 页（位置 #556-556）的标注 | 添加于 2023年4月4日星期二 上午1:27:41</li>
</ul>
<h1 id="意义与实在并非隐藏于事物的背后而是寓于事物自身寓于事物的一切现象">意义与实在并非隐藏于事物的背后，而是寓于事物自身，寓于事物的一切现象。</h1>
<ul>
<li>您在第 37 页（位置 #557-558）的标注 | 添加于 2023年4月4日星期二 上午1:28:22</li>
</ul>
<h1 id="一个人阅读一本所要研究的书他不会去鄙弃书的字母和句点并把它们斥为幻象斥为偶然的无意义的躯壳">一个人阅读一本所要研究的书，他不会去鄙弃书的字母和句点并把它们斥为幻象，斥为偶然的无意义的躯壳，</h1>
<ul>
<li>您在第 48 页（位置 #731-733）的标注 | 添加于 2023年4月15日星期六 下午4:33:45</li>
</ul>
<h1 id="悉达多想这种生活没有任何难题当我还是沙门的时候一切都是艰难和烦恼最终是绝望而现在一切都非常容易容易得就像伽摩拉的亲吻指令我需要衣服与金钱仅此而已这都是不会搅乱一个人睡眠的简单目标">悉达多想，这种生活没有任何难题。当我还是沙门的时候，一切都是艰难和烦恼，最终是绝望。而现在一切都非常容易，容易得就像伽摩拉的亲吻指令。我需要衣服与金钱，仅此而已。这都是不会搅乱一个人睡眠的简单目标。</h1>
<ul>
<li>您在第 49 页（位置 #750-751）的标注 | 添加于 2023年4月15日星期六 下午4:36:00</li>
</ul>
<h1 id="他也无需激动他只是被牵引并且任凭自己的沉落他只为自己的目标所牵引他不允许任何扰乱自己目标的东西进入他的心境">他也无需激动，他只是被牵引并且任凭自己的沉落。他只为自己的目标所牵引，他不允许任何扰乱自己目标的东西进入他的心境</h1>
<ul>
<li>您在第 50 页（位置 #752-754）的标注 | 添加于 2023年4月15日星期六 下午4:36:10</li>
</ul>
<h1 id="没有任何事物是由神灵的驱使世上并不存在神灵只要能够思考等待和斋戒任何人都可以施魔法任何人都可以达到自己的目标-伽摩拉静静地听着她喜爱">。没有任何事物是由神灵的驱使，世上并不存在神灵。只要能够思考、等待和斋戒。任何人都可以施魔法，任何人都可以达到自己的目标。” 伽摩拉静静地听着，她喜爱</h1>
<ul>
<li>您在第 50 页（位置 #752-753）的标注 | 添加于 2023年4月15日星期六 下午4:36:15</li>
</ul>
<h1 id="没有任何事物是由神灵的驱使世上并不存在神灵只要能够思考等待和斋戒任何人都可以施魔法任何人都可以达到自己的目标">。没有任何事物是由神灵的驱使，世上并不存在神灵。只要能够思考、等待和斋戒。任何人都可以施魔法，任何人都可以达到自己的目标。”</h1>
<ul>
<li>您在第 50 页（位置 #752-753）的标注 | 添加于 2023年4月15日星期六 下午4:36:23</li>
</ul>
<h1 id="没有任何事物是由神灵的驱使世上并不存在神灵只要能够思考等待和斋戒任何人都可以施魔法任何人都可以达到自己的目标-1">没有任何事物是由神灵的驱使，世上并不存在神灵。只要能够思考、等待和斋戒。任何人都可以施魔法，任何人都可以达到自己的目标。”</h1>
<ul>
<li>您在第 54 页（位置 #821-822）的标注 | 添加于 2023年5月3日星期三 下午3:31:11</li>
</ul>
<h1 id="我也没有以懊恼和急躁的情绪来伤害自己或是伤害他人如果我有机会再去那里或许还是去收购稻米或许为了其他事情那么那里的朋友们一定会欢迎我">。我也没有以懊恼和急躁的情绪来伤害自己或是伤害他人。如果我有机会再去那里，或许还是去收购稻米，或许为了其他事情，那么那里的朋友们一定会欢迎我</h1>
<ul>
<li>您在第 59 页（位置 #897-899）的标注 | 添加于 2023年5月5日星期五 下午6:01:50</li>
</ul>
<h1 id="然而他一直觉得自己与众不同并带着一种优越感他总是带着一点轻蔑来看待世人带着那么一种嘲讽般的不屑正如一个沙门总是对尘俗的人们感到那种不屑">。然而，他一直觉得自己与众不同并带着一种优越感。他总是带着一点轻蔑来看待世人，带着那么一种嘲讽般的不屑，正如一个沙门总是对尘俗的人们感到那种不屑</h1>
<ul>
<li>您在第 59 页（位置 #902-904）的标注 | 添加于 2023年5月5日星期五 下午6:02:48</li>
</ul>
<h1 id="世人对自己的生活所持的那种重大感他们深刻的欢乐与忧伤以及那种无休止地推动他们去爱的力量所带给他们的焦虑而甜美的幸福这些人永远爱着他们自己爱着他们的孩子爱着荣誉和利益爱着对未来的筹划和企盼">世人对自己的生活所持的那种重大感，他们深刻的欢乐与忧伤，以及那种无休止地推动他们去爱的力量所带给他们的焦虑而甜美的幸福。这些人永远爱着他们自己，爱着他们的孩子，爱着荣誉和利益，爱着对未来的筹划和企盼</h1>
<ul>
<li>您在第 61 页（位置 #930-931）的标注 | 添加于 2023年5月5日星期五 下午6:04:40</li>
</ul>
<h1 id="后又回到那种追求和积聚财富的冲动在这毫无意义的循环之中他把自">后又回到那种追求和积聚财富的冲动。在这毫无意义的循环之中，他把自</h1>
<ul>
<li>您在第 61 页（位置 #931-931）的标注 | 添加于 2023年5月5日星期五 下午6:04:46</li>
</ul>
<h1 id="在这毫无意义的循环之中他把自己拖得筋疲力尽变得衰老而病态">在这毫无意义的循环之中，他把自己拖得筋疲力尽，变得衰老而病态。</h1>
<ul>
<li>您在第 65 页（位置 #997-999）的标注 | 添加于 2023年5月5日星期五 下午6:10:07</li>
</ul>
<h1 id="他热切地希求空寂希求安宁希求死亡就让一道雷电来将他击毁就让一条猛虎来将他吞噬要是有某种烈酒某种毒药能够给予他虚无让他忘却让他长眠不醒那该有多好">他热切地希求空寂，希求安宁，希求死亡。就让一道雷电来将他击毁!就让一条猛虎来将他吞噬！要是有某种烈酒、某种毒药能够给予他虚无，让他忘却，让他长眠不醒，那该有多好</h1>
<ul>
<li>您在第 67 页（位置 #1016-1017）的标注 | 添加于 2023年5月5日星期五 下午6:12:28</li>
</ul>
<h1 id="他已经在寻求死亡通过毁灭肉体以获得安宁的天真愿望在他的内心竟已如此强烈">他已经在寻求死亡。通过毁灭肉体以获得安宁的天真愿望在他的内心竟已如此强烈。</h1>
<ul>
<li>您在第 75 页（位置 #1149-1149）的标注 | 添加于 2023年5月5日星期五 下午6:23:34</li>
</ul>
<h1 id="他看到河水无间断地流转不居而同时却又恒常不变地存在着河水永无迁变却又刻刻常新">他看到河水无间断地流转不居，而同时却又恒常不变地存在着；河水永无迁变却又刻刻常新。</h1>
<ul>
<li>您在第 79 页（位置 #1207-1209）的标注 | 添加于 2023年5月5日星期五 下午6:27:28</li>
</ul>
<h1 id="河水在同一时刻无处不在遍及源头河口瀑布渡口水流海洋以及山脉之间从另一方面来说现在只为其自身而存在并非过去或未来的影子">河水在同一时刻无处不在，遍及源头，河口、瀑布、渡口、水流、海洋以及山脉之间；从另一方面来说，现在只为其自身而存在，并非过去或未来的影子。”</h1>
<ul>
<li>您在第 79 页（位置 #1212-1212）的标注 | 添加于 2023年5月5日星期五 下午6:27:55</li>
</ul>
<h1 id="不可得未来之心不可得万法皆如俱入目前">不可得，未来之心不可得，万法皆如，俱入目前。</h1>
<ul>
<li>您在第 79 页（位置 #1212-1212）的标注 | 添加于 2023年5月5日星期五 下午6:28:01</li>
</ul>
<h1 id="万法皆如俱入目前">万法皆如，俱入目前。</h1>
<ul>
<li>您在第 82 页（位置 #1249-1249）的标注 | 添加于 2023年5月5日星期五 下午6:30:32</li>
</ul>
<h1 id="让他死好了这和我们孩子有什么关系呢">让他死好了，这和我们孩子有什么关系呢?</h1>
<ul>
<li>您在第 93 页（位置 #1422-1423）的标注 | 添加于 2023年5月5日星期五 下午6:41:38</li>
</ul>
<h1 id="悉达多此时的思维竟如此幼稚如此缺乏逻辑他与凡俗的人们竟变得如此相像">悉达多此时的思维竟如此幼稚，如此缺乏逻辑，他与凡俗的人们竟变得如此相像</h1>
<ul>
<li>您在第 98 页（位置 #1491-1492）的标注 | 添加于 2023年5月5日星期五 下午6:46:58</li>
</ul>
<h1 id="而所有的音声所有的目标所有的渴望所有的善与恶悲伤与欢乐所有这一切共同构成了统一的世界">而所有的音声，所有的目标，所有的渴望，所有的善与恶，悲伤与欢乐，所有这一切共同构成了统一的世界，</h1>
<ul>
<li>您在第 100 页（位置 #1523-1524）的标注 | 添加于 2023年5月5日星期五 下午6:49:17</li>
</ul>
<h1 id="当一个人有所追寻悉达多道他只会看到他所追寻之物他之所以无所发现无所获得是因为他只专注于他所追寻之物因为他执迷于自己的目标">当一个人有所追寻，”悉达多道，“他只会看到他所追寻之物。他之所以无所发现，无所获得是因为他只专注于他所追寻之物，因为他执迷于自己的目标。</h1>
<ul>
<li>您在第 102 页（位置 #1564-1566）的标注 | 添加于 2023年5月5日星期五 下午6:53:20</li>
</ul>
<h1 id="因此我认为一切的存在皆为至善无论是死与生无论罪孽与虔诚无论智慧或是蠢行一切皆是必然一切只须我的欣然赞同一切只需我的理解与爱心">。因此，我认为一切的存在皆为至善——无论是死与生，无论罪孽与虔诚，无论智慧或是蠢行，一切皆是必然，一切只须我的欣然赞同，一切只需我的理解与爱心</h1>
<ul>
<li>您在第 103 页（位置 #1579-1580）的标注 | 添加于 2023年5月5日星期五 下午6:54:38</li>
</ul>
<h1 id="而值得礼敬之处可我不想再谈下去言词不能很好地表达思想思想一旦形诸言词即刻就会有所改变有所歪曲有点愚蠢">而值得礼敬之处。可我不想再谈下去，言词不能很好地表达思想。思想一旦形诸言词即刻就会有所改变，有所歪曲，有点愚蠢。</h1>
<ul>
<li>您在第 105 页（位置 #1604-1605）的标注 | 添加于 2023年5月5日星期五 下午6:56:46</li>
</ul>
<p>这就是我之所以如此怀疑言词的原因。我知道这种言词的冲突是一种幻象，</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Internet</title>
      <link>https://ds63.eu.org/2023/internet/</link>
      <pubDate>Fri, 05 May 2023 22:51:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/internet/</guid>
      <description>打算用来记录互联网带给我激动的事情。可以是网站，或者是事件</description>
      <content:encoded><![CDATA[<p><strong>暂时用这个标题，还没想好</strong></p>
<p><strong>打算用来记录互联网带给我激动的事情。可以是网站，或者是事件</strong></p>
<h2 id="写在前面">写在前面</h2>
<p>我蛮喜欢做这样一件事情，点击一个网站中感兴趣的链接，跳转到另一个网站。如此重复多次，再回头去看时，我常常记不得自己是从哪跳转到这个网站。但往往打开的网站都能让我有所收获，至少觉得有趣。</p>
<p>很多博客也会设置友链接力。还有个蛮有意境的名字叫“开往”。</p>
<p>互联网将人与人之间的距离大大减小，却还是形成了大大小小的孤岛。而这一个个链接就像连接这一座座孤岛的桥。</p>
<p>六度分隔理论最早提出的时候是1967年，那时候还没有互联网。而几十年后的今天，在互联网的帮助下，只需要好的链接，甚至可以不再需要6个中间人，就可以将世界上任何本来互不相识的两人建立起联系。</p>
<p>我觉得这就是互联网于我的魅力。</p>
<h2 id="2023年4月25日">2023年4月25日</h2>
<p>今天想到要看下比特币诞生的那篇论文<a href="https://bitcoin.org/bitcoin.pdf"  target="_blank" rel="noopener" >Bitcoin: A Peer-to-Peer Electronic Cash System</a>。论文中参考文献中有个链接，我抱着试试看的心态点了进去。<a href="http://www.weidai.com/bmoney.txt"  target="_blank" rel="noopener" >网站</a>加载得很快。没有太多的修饰，它就只是文字。那时候就有种被触动的感觉。1998年的互联网，我就这样无意中窥探到了。</p>
<p>更让我惊讶的是，这个网站最近修改的时间是1/10/2021。我很难用恰当的言语去描述我现在的感觉。但就是感觉很惊喜。</p>
<p>然后我去搜了下作者，戴伟，华裔。他当时写这篇文章的时候大概是22岁左右。！！！</p>
<h2 id="2023年5月2日">2023年5月2日</h2>
<p>发现了这个网站<a href="https://playgameoflife.com/"  target="_blank" rel="noopener" >Game of Life</a>。我一直有自己实现一个生命游戏的想法，但始终没有动手。这个网站做得很好，可以用来参考。</p>
<p>2023年10月2日,实现了<a href="https://github.com/EuDs63/game_of_life"  target="_blank" rel="noopener" >EuDs63/game_of_life</a>，算是了了一桩心愿。</p>
<h2 id="2023年5月5日">2023年5月5日</h2>
<p>今天经历了一个很有意思的事情。</p>
<ol>
<li>
<p>最开始时看到timeline上有人star了<a href="https://github.com/SuikaXhq/seu-bachelor-thesis-2022"  target="_blank" rel="noopener" >SuikaXhq/seu-bachelor-thesis-2022</a>。</p>
</li>
<li>
<p>发现项目的作者star的项目中有一个<a href="https://github.com/seuite/awesome-seu"  target="_blank" rel="noopener" >seuite/awesome-seu</a>。</p>
</li>
<li>
<p>接着就发现了一个学校里曾存在并活跃着的协会——东南大学网络技术和开源技术协会。虽然很可惜的是：这个协会已经不再传承，而且它的官方网站也已经挂掉了。但从它在Github上仍存在的项目和博客上仍能看到这是一个很有趣的协会。</p>
</li>
<li>
<p>这个协会的会长也有写博客，虽然已经无法访问，但项目中有一句话让我觉得很有感触。</p>
<blockquote>
<p>一个对计算机充满好奇的小男孩现在长大成为一个对计算机更加好奇的大男孩了。我始终还是觉得自己没有摸到计算机的门槛，觉得这个巨大的世界我仅仅只探索了极其微小的一角。过去的天才们，工程师们，平凡人们探索过的世界已经不小，可是抬头看看，那浩瀚的，未知的，多么美丽而又神秘的新世界，还等待着我，我的朋友们，老师们，以及所有的人们继续去学习，去探索它。我相信计算机带给人类的绝不仅仅只有现在这么一点点成就，还有更多，更远，更辽阔的内容等着我们一代人，一代人地走下去，寻找下去，喜欢下去。</p>
</blockquote>
<p>我喜欢这个观点。</p>
</li>
<li>
<p>今天还发现了好几位很优秀的学长。从他们的博客中看到他们当年的一些想法和经历的事情。特别是他们上学时的笔记。这种感觉就很奇妙。</p>
</li>
</ol>
<h2 id="2023年9月13日">2023年9月13日</h2>
<p><a href="https://spacewar.oversigma.com/"  target="_blank" rel="noopener" >Spacewar!</a>.</p>
<p>刚开始还不得其法，玩了几分钟后才明白。挺有趣的一个小游戏。更吸引我的是它是1962年的游戏。厚重的历史感，好游戏那种穿越时间的魅力。太美妙了。</p>
<p>然后又突然想到Steam上那款测试游戏，也是叫Spacewar，致敬?巧合?有一种奇妙感。</p>
<h2 id="2023年10月6日">2023年10月6日</h2>
<p><a href="https://softwareengineering.stackexchange.com/questions/108124/why-it-is-called-hash-table-or-hash-function-hash-doesnt-make-any-sense-t"  target="_blank" rel="noopener" >naming - Why it is called &ldquo;hash table&rdquo;, or &ldquo;hash function&rdquo;? </a></p>
<p>可能是我理解有问题，看完后还是不太理解为什么要叫hash。底下的回答似乎都是在说hash是用来做什么的。</p>
<h2 id="2023年10月10日">2023年10月10日</h2>
<p><a href="http://yume.ly/"  target="_blank" rel="noopener" >YUME 梦乡</a></p>
<p>一个记录梦境的网站。蛮有意思。</p>
<p>11年的网站一直持续到现在，并且还有一定的用户量。我觉得很厉害。</p>
<p>可惜的是，作者在11年时提出的<a href="http://yume.ly/dream/1"  target="_blank" rel="noopener" >创意</a>，似乎都现在还没有一个比较好的实现。（也可能是我还没发现）</p>
<h2 id="2023年10月16日">2023年10月16日</h2>
<p>发现了一个不错的拓展。<a href="https://www.wikiwand.com/"  target="_blank" rel="noopener" >Wikiwand - home</a>。</p>
<p>用来美化Wikipedia的。虽然原来的风格我觉得也不错。</p>
<p>逛博客的时候发现<a href="https://www.jinrishici.com/#"  target="_blank" rel="noopener" >今日诗词 - 一言API - 诗词实时智能推荐 - 今日诗词开放接口 - 今日诗词 API - 个人文章分享</a>。想起之前想给自己的<a href="https://github.com/EuDs63/Faye_Bot"  target="_blank" rel="noopener" >EuDs63/Faye_Bot: my telegram Bot</a>加个诗词功能的时候，花了好些时间在找到好用的api接口。而找到的这个接口就是这个项目的前身。缘</p>
<h2 id="2023年10月30日">2023年10月30日</h2>
<p>今天在看<a href="https://mastodon.social/about"  target="_blank" rel="noopener" >About - Mastodon</a>时。发现有好长一串Moderated servers。遂好奇为什么被封。</p>
<p>瞥到<a href="cachapa.xyz" >cachapa.xyz</a>因为&quot;Hate speech&quot;而被&quot;Suspended&quot;。好奇访问了该网址。</p>
<p><a href="https://cachapa.xyz/about/"  target="_blank" rel="noopener" >About – cachapa.xyz</a>中的内容蛮有趣的。有些言论确实有点冒犯，但更冒犯的我也见多了，也不会放在心上。</p>
<p>更让我印象深刻的是这位博主的三个要素。委内瑞拉，30多岁的程序员，宅文化。这三者的结合是我第一次见到的，让我再一次感受到互联网的美妙。</p>
<p>值得一提的是他称呼<a href="https://blog.cachapa.xyz/"  target="_blank" rel="noopener" >自己的博客</a>为&quot;a place where I can write polite and civilized stuff.&quot;。这种说法我也觉得有趣。</p>
<p>ps:直到现在（2024年1月10日），我还是会偶尔想起这位博主，并查看他的博客是否更新，想看他是否移民成功。</p>
<p>pps: 今天(2024年7月28日)再看，发现博客虽然没新文章，但<a href="https://cachapa.xyz/about/"  target="_blank" rel="noopener" >About – cachapa.xyz</a>改了些内容。从这些修改的内容上来看，博主并没有如愿。</p>
<blockquote>
<p>I’ll move to Europe sometime during 2023 overseas someday (hopefully), so I guess my life will be a bit more interesting, heh life sucks way too much right now.</p>
</blockquote>
<p>祝他未来顺利。</p>
<h2 id="2023年11月5日">2023年11月5日</h2>
<p><a href="https://www.wikiwand.com/en/I_Can_Eat_Glass"  target="_blank" rel="noopener" >I Can Eat Glass - Wikiwand</a></p>
<p>有趣，尤其是这段：</p>
<blockquote>
<p>Saying &ldquo;I can eat glass, it does not hurt me&rdquo;, however, ensures that the speaker &ldquo;will be viewed as an insane native, and treated with dignity and respect&rdquo;.</p>
</blockquote>
<h2 id="2023年11月18日">2023年11月18日</h2>
<p>发现<a href="https://theghostintheshell.jp/"  target="_blank" rel="noopener" >【公式】攻殻機動隊グローバルサイト</a>做得很棒。</p>
<p>作为攻壳系列的粉丝表示很满足。</p>
<h2 id="2023年11月26日">2023年11月26日</h2>
<p>看<a href="https://yayu.net/3762.html"  target="_blank" rel="noopener" >一个极简主义博客的要素 · 雅余网 · 茶余饭后，闲情雅致</a>发现了一个NO-JS 网站合集<a href="https://no-js.club/members/"  target="_blank" rel="noopener" >Hall of glory | The no-JS.club</a>。</p>
<p>其中<a href="https://t0.vc/"  target="_blank" rel="noopener" >t0.vc</a>这个网站很是突出，不仅域名很短，而且宣称仅有0.0078KB。</p>
<p><a href="https://t0.vc/t"  target="_blank" rel="noopener" >t0txt | t0.vc</a>是一个pastebin。本来是作为一个方便大家使用的工具。但作者发现被滥用的情况很常见。作者通过关键词过滤和黑白名单、CAPTCHA等方法尝试去消除。收效不错，但还是后悔当初自己去在公共场合推荐它。</p>
<p>我想起上周看的《黑客与画家》中的《防止垃圾邮件的一种方法》。两位作者所采取的方法有点儿像。哈哈。</p>
<h2 id="2024年1月5日">2024年1月5日</h2>
<p>之前看到有人说谷歌博客当作者长时间不登录的话会自动注销，于是想着备份下编程随想的博客。</p>
<p>今天跟着<a href="https://program-think.blogspot.com/2015/03/blog-sync.html"  target="_blank" rel="noopener" >提供“博客离线浏览”和“电子书制作脚本”</a>进行操作，很简单。并且发现<a href="https://www.resilio.com/index.html"  target="_blank" rel="noopener" >Resilio File Sync Software</a>还挺好用，而且速度还蛮快的。</p>
<p>备份后发现十多年的博客不到1G，但就这不到1G的内容却给他带来了牢狱之灾。</p>
<p>在<a href="https://programthink.wordpress.com/2010/11/14/hello-world/#comments"  target="_blank" rel="noopener" >博客迁移重要通知 | 【编程随想】的博客</a>看到这段评论：</p>
<pre tabindex="0"><code>编程随想读者说道：
2021年11月19日 23:14
致后来者:
如果你也找到了这个地方, 向你致敬!
我是怀着朝圣的态度来到这里的, 已经是二零二一年年底了, 六个月过去, 编程兄恐怕是凶多吉少. 如果翻翻编程兄之前的博文可以看出, 十年来他的文字风格基本没有变过. 对于一个坚持同样的隐私理念坚持了十年之久的老鸟来说, 他的家人可能也未必知道他的真实身份, 那么编程随想在这个时间上的最后一个残余, 恐怕就是他的博客了! 字面意义上的电子生命!
这个博客是他电子生命的开始. 如果使用网页时光机的话,https://web.archive.org/web/20110607090135/https://programthink.wordpress.com/2009/05/
还可以找到更早的博文, 一直追溯到 09 年五月份. 如果大伙有兴趣的话, 也许还能发现五月份以前的博文…
尽管编程兄已经离去, 但是他对这个时间的影响会存在于我们共同的记忆中, 也被互联网忠实记录. 如果你恰巧在这个互联网的一隅看到我的评论, 是缘分一场. 敬互联网, 敬记忆, 敬你!
坚持抗争, 坚持记忆, 总有一天我们会在没有黑暗的地方相见, 我们将共享这段不能说的记忆, 让编程兄得以瞑目.
</code></pre><p>ps: 据<a href="https://x.com/amehochan/status/1807966926821306705"  target="_blank" rel="noopener" >Yufan Sheng on X: &ldquo;“编程随想”只判了七年，比想象中要好一点。有些人，消失了就真的消失了。 https://t.co/te1HypCFE7&rdquo; / X</a>，判刑7年。</p>
<h2 id="2024年1月10日">2024年1月10日</h2>
<p>翻<a href="https://store.steampowered.com/app/1536470/_/"  target="_blank" rel="noopener" >一名卫兵走进了一间酒馆x</a>的评价。</p>
<p>对于玩家的评论，其他游戏的开发者要么是干脆不回复，要么只是为了回复而回复，但这个的作者不同。</p>
<p>这里摘录一个我觉得特别有意思的。</p>
<p>首先是开发者回复一个抱怨结局和剧情设置的不合理的差评：</p>
<blockquote>
<p>其实核心玩法是看剧情！快速赚钱就是为了能快速过任务看剧情，但是确实剧情太分散了（当初不知道咋想的要做3个主线，搞得每个都比较单薄。如果只做一个主线堆料就好了但投入太多没法改了），哎，第一次做游戏没经验么，以后学到教训了。</p>
<p>您的差评很合理，我十分接受，哈哈哈。</p>
</blockquote>
<p>一天后，评论者将原本的差评改为好评，而作者却反倒希望ta改回差评：</p>
<blockquote>
<p>草，不用改好评啊。其实我本来就感觉您人挺好可能会改，想说请保留这个差评，又怕说这一嘴显得太自负了。
因为游戏本身肯定有缺点。一个有理有据的差评会帮助玩家深入了解游戏属不属于自己想玩的类型，有哪些雷点，价值有时候比普通好评还大。（像我从来都是只看差评不看好评的，差评能接受我就买了）
您还是改回差评吧,感谢您的善意</p>
</blockquote>
<p>某次更新声明中有这样一段：</p>
<blockquote>
<p>在后台添加了每个build对应的版本号描述。现在盗版网站应该能正确扒取到版本号而不是使用buildID作为标题了？扒取不到来找我！
而且有的网站更新都不勤快，现在还是EA的版本我都不想吐槽</p>
</blockquote>
<p>之前只看过网文作者翻盗版网站看有没有自己的作品的，这次是头回见游戏作者翻盗版网站的，甚至还吐槽更新不勤快。</p>
<p>看更新记录能看出作者更新蛮勤快的,游戏从21年开始ea,直到去年才正式发售。现有的steam评价三百个左右，如果按1：10的换算比例，可能售出了三千份,大概六万多块钱。小众独立游戏不容易啊。</p>
<h2 id="2024年1月13日">2024年1月13日</h2>
<p>加的群里有一个叫iris的bot，功能很强大，我一直好奇是怎么实现的。</p>
<p>今天,首先是iris发了张照片，里面提到一篇文章，我尝试搜了下文章标题：《iris的nlp之路：章鱼触手与斩龙大剑》。很可惜，没找着。后面她又发了个链接：<a href="https://meteorcollector.github.io/2022/10/iris-manual/"  target="_blank" rel="noopener" >一个reader-friendly的iris手册</a>。这时候我很惊喜，终于啊。</p>
<p>今天这件事让我再次感受到，有不少博客还是一座座孤岛。像一开始，尽管我知道文章的完整标题，但还是无法通过搜索引擎找到。而更多的文章，我连标题都不知道。这是件悲伤的事情。</p>
<p>不过换个角度来看，还有许许多多有着有趣内容的博客正等待着我发现，多棒啊。</p>
<h2 id="2024年1月14日">2024年1月14日</h2>
<p>看<a href="https://www.bilibili.com/bangumi/play/ep324533"  target="_blank" rel="noopener" >BanG Dream! 少女乐团派对！☆PICO～大份～第9集</a>，里面的玩法很有意思。</p>
<p>想玩，一通寻找后发现了<a href="https://hamzaabamboo.github.io/pazuru-pico/"  target="_blank" rel="noopener" >パズル⭐︎ピコ | Puzzle * Pico</a>。由commit时间可以得出在播出的两天后就写好了初版，牛啊。顺路翻了作者的主页。</p>
<p>博客以日语和英语为主。以及一些我没见过的符号，以为是作者为了加密或者视觉效果搞的。看简历才发现作者原来是泰国人！而那些我没见过的符合原来是泰语！</p>
<p>在沉浸式翻译的帮助下，我读了其几篇博客。第一篇就是他的年度总结。我看到他找工作的经历，还吐槽不喜欢做Leetcode。哈哈。</p>
<p>再一次被互联网给惊喜到。</p>
<h2 id="2024年2月24日">2024年2月24日</h2>
<p>翻<a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9B%BD%E6%B0%91%E9%97%B4%E4%BF%A1%E4%BB%B0"  target="_blank" rel="noopener" >中国民间信仰 - 维基百科，自由的百科全书</a>看到<a href="https://zh.wikipedia.org/wiki/%E5%85%94%E5%85%92%E7%A5%9E"  target="_blank" rel="noopener" >兔儿神 - 维基百科，自由的百科全书</a>，进而搜索到<a href="https://www.weimingtang.org/index.php"  target="_blank" rel="noopener" >威明堂兔兒神廟</a>。牛啊。甚至还支持分期付款，哈哈。不过收费蛮高的。</p>
<h2 id="2024年3月1日">2024年3月1日</h2>
<p>看<a href="https://github.com/gfwlist/gfwlist"  target="_blank" rel="noopener" >gfwlist/gfwlist</a>，白名单中有一个域名<code>zhongsou.com</code>,好奇访问了该网址，发现名字十分响亮。<a href="https://www.zhongsou.com/"  target="_blank" rel="noopener" >中搜第三代搜索引擎平台——开放 融合 创新</a>,但实际上却几乎不可用。</p>
<p>从<a href="https://www.zhihu.com/question/22259316"  target="_blank" rel="noopener" >中搜这家公司怎么样？ - 知乎</a>了解到，其宣传的第三代搜索引擎平台是“基于自然语言搜索，极大地简化了人机沟通成本，搜索过程就好像在跟计算机聊天”。“基于自然语言搜索”可以说是近两年的一大热点，当年（2004）就能有如此视野，可以说十分了不得。</p>
<p>但实际上呢？“中搜以词条门户为主，将每个词条的信息进行初步人工筛选后以词条门户的形式呈现”，某种意义上来讲也可以说是“人工智能”，哈哈。而它盈利的主要手段是靠卖词条,“这些词主要卖给土豪，我见过一些，我很惊异有的人拿数百万元去砸一个词”。</p>
<p>中搜的董事长是陈沛，关于他，<a href="https://www.sohu.com/a/406095664_481756"  target="_blank" rel="noopener" >ST中搜陈沛：彼时之瑜亮，此时之江郎？【新三板的人和事系列专题（六十九）】_搜索</a>属于比较详尽的报道，这里不再赘述。</p>
<p>我还搜到了与他有关的一个视频：<a href="https://www.bilibili.com/video/BV1KK4y1v7hS/"  target="_blank" rel="noopener" >【大佬微直播】中搜陈沛：互联网正在改变人类，是最伟大的发明</a>,我认同这句话。</p>
<p>今天从一个网址，进而得窥21世纪初的搜索引擎之争，有趣。</p>
<h2 id="2024年3月18日">2024年3月18日</h2>
<p>翻自己<a href="https://github.com/EuDs63?tab=stars"  target="_blank" rel="noopener" >Github Stars</a>时翻到<a href="https://github.com/chrisguo/beijing_fushengji"  target="_blank" rel="noopener" >chrisguo/beijing_fushengji: 北京浮生记PC版源代码</a>。虽然已经不记得最早是啥时候接触这款游戏了，但有一点是很明确的：xp时代的我就花了不少时间玩这款游戏。</p>
<p>游戏的作者是郭祥昊,我找了些他的相关资料,下面这两篇算是写得比较好的：</p>
<ul>
<li><a href="https://m.jiemian.com/article/3807816.html"  target="_blank" rel="noopener" >字节跳动再度加码游戏业务，收购AI游戏技术研发商深极智能 | 界面 · 财经号</a></li>
<li><a href="https://www.sohu.com/a/120588274_116000"  target="_blank" rel="noopener" >《北京浮生记》开发者郭祥昊和他的十年丨触乐</a></li>
</ul>
<p>从报道中我得知，他在十年前还带队开发了《大明浮生记》，从描述和画风上看着蛮好玩的，可惜我当年不知道，现在想玩也玩不到了。</p>
<p>访谈中他提到:</p>
<blockquote>
<p>对个人而言，做好玩的游戏是我一直的梦想，或许有一天会做，但是绝对不是现在的这种游戏形态，可能会类似《Undertale》这样吧。比较小，但是能够拨动人的心弦。不一定赚钱，但是还它会让很多人疯狂的喜欢它，很多年之后还记得它。</p>
</blockquote>
<p>对我来说，《北京浮生记》做到了这点。</p>
<h2 id="2024年6月4日">2024年6月4日</h2>
<p>偶然间了解到线性文字A这个词，查<a href="https://zh.wikipedia.org/wiki/%E7%BA%BF%E5%BD%A2%E6%96%87%E5%AD%97A"  target="_blank" rel="noopener" >线形文字A - 维基百科，自由的百科全书</a>才知道这是种尚未被解读的文字。有趣的是，Unicode编码有收录这种文字。Unicode真不愧统一之名。</p>
<h2 id="2024年6月9日">2024年6月9日</h2>
<p>看生活大爆炸S10E14,谈到牛顿是处男。带着恶趣味去搜搜到了<a href="http://m.news.xixik.com/content/63464959dcd1b68d/"  target="_blank" rel="noopener" >世界上著名的处男处女们 那些终身未婚的名人_奇闻趣事_嘻嘻网</a>。然后发现这网站是“国内领先的电子优惠券门户”，时间跨度还蛮长的，至少从2007年一直到<del>2017年</del>2023年。因此得窥当年的物价。</p>
<p>在此摘抄麦当劳2013年的优惠套餐。</p>
<blockquote>
<p>巨无霸超值午餐 配薯条(中)+可口可乐(中) 超值价19元
双层吉士汉堡 配薯条(中)+可口可乐(中) 超值价17元
珍萃麦辣鸡腿汉堡 配薯条(中)+可口可乐(中) 超值价18元
经典麦辣鸡腿汉堡 配薯条(中)+可口可乐(中) 超值价15元
原味板烧鸡腿堡 配薯条(中)+可口可乐(中) 超值价18元
麦香鸡 配薯条(中)+可口可乐(中) 超值价15元
麦香鱼 配薯条(中)+可口可乐(中) 超值价17元
麦辣鸡翅或盐焗风味鸡翅 配薯条(中)+可口可乐(中) 超值价20元
麦乐鸡 配薯条(中)+可口可乐(中) 超值价15元</p>
</blockquote>
<p>嗯，似乎没怎么涨？</p>
<p>友情链接中还有<a href="http://www.lzsq.net/"  target="_blank" rel="noopener" >老章书签</a>，很有时代感的网站。惊讶的是其中不少网站都还存活着。</p>
<p>前段时间有篇文章，标题为《中文互联网正在加速崩塌》,我衷心祝愿中文互联网别崩塌得那么快。因为像这样的经历实在有趣。</p>
<h2 id="2024年6月27日">2024年6月27日</h2>
<p>发现了<a href="https://saberhaoren.github.io/haoren/"  target="_blank" rel="noopener" >欢迎来到赛博扫盲知识分享站！</a>这个网站。一开始以为是搞笑的，但发现这似乎有很大的需求。</p>
<p>网上有个段子，大意是：什么东西，老人不太会用，小孩也不太会用呢？答案是电脑。从幼儿园开始懵懵懂懂地坐在表哥旁边看他玩游戏，到现在选择了与计算机相关的专业，几乎每天都要长时间与电脑相处。电脑这样一件在我看来已是十分普及的东西，但似乎因为智能手机和国内移动互联网的强势，它的使用甚至需要去“扫盲”。我觉得这是蛮可悲的一件事。</p>
<p>这个项目的主要维护者是业余时间义务维护，但从<a href="https://github.com/saberhaoren/haoren/pull/10"  target="_blank" rel="noopener" >添加如何科学上网 by pW7vO3pL7pJ3dT3hS4lJ9 · Pull Request #10 · saberhaoren/haoren</a>可以看到，他们的态度很谦逊友好。</p>
<p>感谢每一位赛博好人。</p>
<h2 id="2024年8月31日">2024年8月31日</h2>
<p>刷推刷到<a href="https://x.com/CoooolXyh/status/1829366178500010223"  target="_blank" rel="noopener" >Yuhang on X: &ldquo;后续：作者发现有人通过这些复选框以二进制的形式给他留了一条信息，然后发现很多人在拿这个网站搞事情（太酷了吧，必读 https://t.co/zXcQGuVDvU&rdquo; / X</a>。</p>
<p>作者本人写了篇博客<a href="https://eieio.games/essays/the-secret-in-one-million-checkboxes/"  target="_blank" rel="noopener" >The secret inside One Million Checkboxes | eieio.games</a>,还拍了个视频，<a href="https://x.com/CoooolXyh/status/1829366178500010223"  target="_blank" rel="noopener" >Yuhang on X: &ldquo;后续：作者发现有人通过这些复选框以二进制的形式给他留了一条信息，然后发现很多人在拿这个网站搞事情（太酷了吧，必读 https://t.co/zXcQGuVDvU&rdquo; / X</a>。</p>
<p>挺行为艺术的一件事。我更好奇技术上是怎么支持渲染一百万个checkbox和支持那么多人在线点的。</p>
<h2 id="2024年11月13日">2024年11月13日</h2>
<p>清理未关闭的浏览器标签页，发现<a href="https://eieio.games/essays/the-secret-in-one-million-checkboxes/"  target="_blank" rel="noopener" >The secret inside One Million Checkboxes | eieio.games</a>还有篇姊妹篇：<a href="https://eieio.games/essays/scaling-one-million-checkboxes/"  target="_blank" rel="noopener" >Scaling One Million Checkboxes to 650,000,000 checks | eieio.games</a>。</p>
<p>至此我终于知道了它技术上是怎么做到的了，而且发现作者用的技术都很朴素。有一个事实让我有点惊讶（暴露了我的知识水平），那就是存储一百万个checkbox需要多大空间，答案是<code>1b*125*8*1000</code>，也就是125KB。</p>
<p>另外一点要吐槽的是我自己，8月底想读的文章拖到了11月中旬。</p>
<p>作者谈及这次尝试给他带来的一大收获是：</p>
<blockquote>
<p>This also validated my belief that people are hungry for constrained anonymous interactions with strangers.</p>
</blockquote>
<h2 id="2024年11月20日">2024年11月20日</h2>
<p>好奇一些比较奇怪的unicode字符，搜索到了<a href="http://zyho.me/index.php?action=blog&amp;tid=83"  target="_blank" rel="noopener" >【转】奇怪的unicode字符</a>。看完后习惯性的去看该博客的其他文章。发现竟然还是同好（都喜欢邦邦），互联网真奇妙。</p>
<p>翻到<a href="http://zyho.me/index.php?action=blog&amp;tid=114"  target="_blank" rel="noopener" >前端工程师与程序猿身份的矛盾</a></p>
<blockquote>
<p>说道这里我还是要回忆一下我的程序猿之路吧=,=(怎么我不管说什么最后都要开始回忆往事).我第一次接触编程是在初一,那时候写pascal什么的.然后是初二时的改档也算是半个编程吧,然后是高一的TI,高二的前端,高三的建模(众:那时候你那种也算?明明是打酱油的好不好!).纵观这些,pascal我学了半年就停了,根本没有算是真正的学会.改档对效率也没什么要求(明明是根本没有要求好伐),然后TI的话对效率的确有那么一点点要求,前端上面说了,建模又那么水=,=</p>
</blockquote>
<p>厉害</p>
<h2 id="2024年11月24日">2024年11月24日</h2>
<p>看<a href="https://mp.weixin.qq.com/s/ek9jH4ex1DO4_KJEZ0rLow"  target="_blank" rel="noopener" >小红书上，搜不出标准答案</a></p>
<blockquote>
<p>那什么才是驱动用户持续创作的好机制？一年后，柯南觉得自己找到了答案：内在的激励远远高于外在。</p>
</blockquote>
<blockquote>
<p>以「出国购物」为例，当人们想要分享⸺身边的熟人，未必有人感兴趣；主角是明星、公众人物和网红，又距离日常太远。小红书恰好为普通人提供了舞台，一个普通用户的分享被更多人看到，关注到，为其他人带来价值的同时，还能激发出「邻居」之间的正反馈，用户内心的成就感自然被激发出来了⸺我分享的内容对别人有帮助。</p>
</blockquote>
<p>我没在小红书上发布过笔记，但我熟悉百度贴吧。我发帖的时候如果能有个好的点赞，评论数据，那我肯定愿意多说几句。有时候发的贴子数据不好，后面翻到的话，我甚至会给删掉。</p>
<p>前几天听半拿铁，讲扎克伯格的经历。提到他早年做的一款产品，可以把自己的课程表上传上去，还能看到别人的课程表。就这样简单的功能，也有不少人愿意花许多时间，就在那上面看别人上些什么课。其实这说难听点，就是满足了用户的窥私欲，说好听点，就是满足了用户渴望被连接，好奇别人的生活和信息这一需求。</p>
<p>不仅希望能看到，还希望自己的发言能被人注意到，能收到他人的反馈。于是这也是百度贴吧所吸引我的原因之一。</p>
<blockquote>
<p>小红书技术团队逐渐探索出一套分发机制：50%的流量给普通人，50%流量给算法。</p>
</blockquote>
<p>小红书也是这样做的。</p>
<h2 id="2024年12月4日">2024年12月4日</h2>
<p>韩国总统尹锡悦发布了戒严令，没过多久，反对党领袖李在明，就在Youtube上直播翻墙进入国会投票。</p>
<p>我想起<a href="https://neodb.social/movie/5g5OX8XYvyZlpizXLbx0QT"  target="_blank" rel="noopener" >NeoDB - 电影 | 出租车司机 A Taxi Driver</a>。1980年的光州事件，记者想进入光州，进行记录，将影像带出来。每一步都可谓惊心动魄。</p>
<h2 id="2025年6月16日">2025年6月16日</h2>
<p>搜“秦始皇遣使采药昆仑石刻”，看到<a href="https://opinion.e23.cn/a/2025-06-12/223266"  target="_blank" rel="noopener" >对“秦始皇遣使采药昆仑石刻”有争议是好事 - 理响泉城 理上网来 - 理响泉城 理上网来</a>，被网站名给吸引到了：舜网。</p>
<p><a href="https://www.e23.cn/main/about/about.html"  target="_blank" rel="noopener" >关于舜网 舜网</a>提供了网站的基本浏览数据:</p>
<blockquote>
<p>舜网日访问PV220万，UV60万，IP50万。其中，济南市占52%，国内其他城市占34%，港澳台地区占8%，其他地区占6%。 网友年龄比例结构：30岁以下占29%，30岁到49岁占63%，50岁以上占8%。</p>
</blockquote>
<p><a href="https://www.e23.cn/main/about/ggfw.html"  target="_blank" rel="noopener" >广告服务 舜网</a>指出了对应的广告报价。</p>
<p>我还是头回见标得这么清楚的。</p>
<h2 id="2025年7月10日">2025年7月10日</h2>
<p><a href="https://sspai.com/post/100663"  target="_blank" rel="noopener" >在 2005 打开大众点评：20 年前互联网怎么教我们在杭州吃东西？</a></p>
<blockquote>
<p>由于是网页快照因此所能打开查看的页面也是有限，不能细致探究，当我想点开看一家餐馆的详情时才发现登录验证真是互联网思维的极致体现，二十年前如果不登录账户照样是完全没法查看任何点评的，真是一以贯之的「好」习惯。</p>
</blockquote>
<blockquote>
<p>除此以外倒也不是没有令人感动的地方，虽然这些二十年前已经闭店的餐馆已经无法在 app 中搜索到任何结果，但我发现在搜索栏的联想中还会有这些餐馆名称的提醒，即使是点击后没有任何结果，说明大众点评内部的数据库中应该还是存着这些二十年前已经消失的餐馆。或许只是数据库中一个标记让他们不再展示，但是这些餐馆老板们可能也没想到有 1077 家餐馆的名称和点评永久地被留在了一本纸质书上。</p>
</blockquote>
<p>已经消失的餐馆，幸好还有纸质书籍将其记录了下来。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>为什么要写博客</title>
      <link>https://ds63.eu.org/2023/reasons-for-build-a-blog/</link>
      <pubDate>Fri, 05 May 2023 00:38:56 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/reasons-for-build-a-blog/</guid>
      <description>这个问题已经被很多人回答过了。但我还是愿意给出些自己的回答（或者认同的回答）。</description>
      <content:encoded><![CDATA[<p><strong>这个问题已经被很多人回答过了。但我还是愿意给出些自己的回答（或者认同的回答）。</strong></p>
<h2 id="2023年5月5日">2023年5月5日</h2>
<p>我享受逛博客的过程。不管是博客的页面设计还是文章的内容，基本上都是作者的一番心血。巨大的互联网使用人数和几十年的时间，诞生了许多很有意思的博客，可谓浩如烟海。而我想在这这烟海中有一颗属于自己的星。</p>
<hr>
<h2 id="2023年5月19日">2023年5月19日</h2>
<p>今天一天都跟博客有关。</p>
<p>白天是拼了几篇博客来做作业。</p>
<p>晚上的时候看<a href="https://soulogic.com/item/3294"  target="_blank" rel="noopener" >我的郑老三死了</a>。我记忆中自己没养过动物，但前不久才经历过亲人的突然离去，所以这篇让我很有些想法。</p>
<p>更晚些的时候看<a href="https://rehoni.github.io/cn/"  target="_blank" rel="noopener" >罗皓的个人博客</a>，是一个学长的。从大学一直记录到工作。看着那些熟悉的地名和事情很有感觉。</p>
<p>现在突然冒出来了个想法。博客的意义可能在于存在。它不需要马上就能让某个人有想法。它只需要存在，存在着能访问就好。</p>
<hr>
<h2 id="2023年5月20日">2023年5月20日</h2>
<p><a href="https://plantegg.github.io/2117/06/07/%E5%85%B3%E4%BA%8E%E6%9C%AC%E5%8D%9A/"  target="_blank" rel="noopener" >关于本博</a>里的答案是这样的。</p>
<blockquote>
<p>为了解决一看就懂，一问就打鼓，一用就糊涂。所以需要记录、总结，再联系案例。把零散知识记录下来（看到过），慢慢地相关知识积累更多，直到碰到实践案例或是有点领悟到于是发现这块知识可以整理成一篇系统些的文章。</p>
</blockquote>
<hr>
<h2 id="2023年10月5日">2023年10月5日</h2>
<p>这段时间在迁移服务器。这时候我的博客就起了很大的作用。以前遗忘的一些配置细节，翻翻之前的博文就能想起来了。</p>
<p>这种感觉很好。</p>
<hr>
<h2 id="2023年10月7日">2023年10月7日</h2>
<p>逛博客的时候看到<a href="https://prin.pw/short-domain-name-for-blog/"  target="_blank" rel="noopener" >博客短域名 printem.pw 和 prin.studio - PRIN BLOG</a>，发现我和作者的想法差不多，但人家写得比我好，摘录如下。</p>
<blockquote>
<p>之前的博文里也有零星提到过，我这人有种特殊的情结，总是希望自己能在浩如烟海的 Internet 上留下些什么痕迹，证明我曾经来到过、享受过这个赛博空间，甚至为其做出过一些微小的贡献。</p>
<p>自建服务器、自有域名其实挺脆弱的，没有人照看的话，服务器不续费会被停机，域名不续费会被收回。如果真出了些什么意料之外的状况，辛辛苦苦搭建起来的东西可能就灰飞烟灭了，或者只留存在互联网档案馆中。</p>
<p>以我的感性来看，这是挺难过的一件事，我不希望这样。</p>
<p>雁过尚且留声，人生岂能无痕？</p>
<p>所以本博客上的所有资源全部托管在 GitHub、CloudFlare 这类可靠的免费服务上，只要这些公司不倒闭跑路要么停止免费服务，或者人类迎来天启现代文明全部嗝屁儿，我的博客应该可以在无人值守的情况下保持很长一段时间的可访问状态。</p>
</blockquote>
<hr>
<h2 id="2023年11月4日">2023年11月4日</h2>
<p><a href="https://www.eaimty.com/2020/do-not-let-your-blog-exist-only-in-the-internet-archive/"  target="_blank" rel="noopener" >请不要让你的博客仅存在于互联网档案馆 - EAimTY&rsquo;s Blog</a>，摘录如下：</p>
<blockquote>
<p>博客是给大家看的，但同时也是留给你自己看的。就算访问量很少，甚至没有访客都没有关系，因为你自己也可以是访客。当你看到自己曾经写的文章时，也就看到了自己当初的想法。这种思维的碰撞会让人感到非常神奇，就像是真正的“时光机”一样，能让你感到你自己的变化。我觉得这才是博客的最大用途。</p>
</blockquote>
<hr>
<h2 id="2023年12月19日">2023年12月19日</h2>
<p>今天看<a href="https://www.barretlee.com/blog/2023/06/26/blog-writer/"  target="_blank" rel="noopener" >还写博客么？ | 小胡子哥的个人网站</a>。</p>
<p>我觉得写得很好，这里记录几点我的感受。</p>
<ol>
<li>
<p>作者对自己写博客的理由写得很坦诚，不同时期的理由也不一样。</p>
</li>
<li>
<p>关于技术内容。作者的观点是：</p>
<blockquote>
<p>在技术学习阶段，我对自己的写作提出了一个基本要求，那就是写搜索引擎没有的东西，如果搜索引擎有，那我就写最全的内容，否则写作就没有太多的价值，互联网从来不缺一篇重复的水文。后来自己获取信息的能力变强了，发现几乎所有的问题，互联网都给出了答案，写作的动力持续在减退。最近一年多，ChatGPT 横空出世，别说技术问题，就连生活上的问题，找它问上几句，它都可以清清楚楚、明明白白地把内容写的特别好，因此写作的动力又下降了一波。</p>
</blockquote>
<ul>
<li>
<p>我自己的这个博客。我没有像作者对自己那样的高要求，和技术相关的基本上只是一种记录。记录我在使用某种技术的过程，遇到的问题和解决方式。说是博文，但更像是给未来的自己看的手册。</p>
</li>
<li>
<p>作者提到的ChatGPT导致其写作动力下降这个现象。我有自己的观点：我认为现阶段的ai还不能完整替代博客。我目前有不少技术上的问题，虽然我现在的第一选择会是问ai，但得不到自己满意的结果。最终还是得靠去找前人的博客或者回答。</p>
</li>
</ul>
</li>
<li>
<p>记录的意义：</p>
</li>
</ol>
<p>博文里面有一段我摘抄如下：</p>
<blockquote>
<p>那还写博客么？似乎这个问题也不是那么重要。如果为了记录而记录，那记录这件事情也变得没有价值了。人的一生都在跟空虚和无聊对抗，写作不外乎也是其中一种。</p>
<p>此刻的写作就是为了记录。记录自己心理的变化，记录生活的变化，记录工作的心得，记录我对这个世界认知的变化。如果在记录的过程中可以带来外在的声量，获得一些有趣或无趣的反馈，那都是一件值得庆幸的事情。</p>
</blockquote>
<h3 id="ps">ps</h3>
<p>我是先知道<a href="https://twitter.com/barret_china"  target="_blank" rel="noopener" >这位博主的twitter账号</a>再看到他的博客的。在此之前，我对其有种偏见，认为是推上常见的那种分享所谓的编程知识,内容质量不高，却又大题小作的类似于营销号之类的账号。</p>
<p>但在逛了其博客后我印象大为改观，这里要向其为我之前的偏见道歉。</p>
<p>然后又想到，这其实也是写博客的意义之一。一个内容充实的博客能够让访问者在比较短的时间内对你产生认知。</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://plantegg.github.io/2117/06/07/%E5%85%B3%E4%BA%8E%E6%9C%AC%E5%8D%9A/"  target="_blank" rel="noopener" >关于本博</a></li>
<li><a href="https://prin.pw/short-domain-name-for-blog/"  target="_blank" rel="noopener" >博客短域名 printem.pw 和 prin.studio - PRIN BLOG</a></li>
<li><a href="https://www.eaimty.com/2020/do-not-let-your-blog-exist-only-in-the-internet-archive/"  target="_blank" rel="noopener" >请不要让你的博客仅存在于互联网档案馆 - EAimTY&rsquo;s Blog</a></li>
<li><a href="https://www.barretlee.com/blog/2023/06/26/blog-writer/"  target="_blank" rel="noopener" >还写博客么？ | 小胡子哥的个人网站</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>诗词里的地名</title>
      <link>https://ds63.eu.org/2023/place-names-in-poetry/</link>
      <pubDate>Mon, 01 May 2023 00:32:17 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/place-names-in-poetry/</guid>
      <description>人生代代无穷已，江月年年望相似</description>
      <content:encoded><![CDATA[<p><strong>出去旅游，有件事我一直很热衷，就是去那些在诗词中出现过的地方中走走。</strong></p>
<p><strong>这往往能给我一种感觉，用张若虚的话来说就是“人生代代无穷已，江月年年望相似”。</strong></p>
<p><strong>让我如此热衷的还有另一个原因：古人在某个地点因事因景所凝聚的个人感受，能让现在的我读到。而当年他们所在的地方或者地名，又能流传至今。这两点每一点都是很难得的，而两点同时发生，更是凤毛麟角。</strong></p>
<h1 id="南京">南京</h1>
<h2 id="金陵">金陵</h2>
<blockquote>
<p>“金陵”原是山名，“陵”作“山陵”解。金陵，就是现在的钟山，又称蒋山、紫金山。《舆地志》说：“蒋山古曰金陵山，县之名因此山立”。钟山顶上的岩石泛紫色，类赤，所以称金陵，其名因山石颜色而来，而其实山上并无金矿。“金陵”之“金”，作金色解，其实是指铜的颜色，而非黄金。铜也称赤金，我们现在把纯铜称为紫铜。这与后人称其为紫金山是一样道理。</p>
</blockquote>
<p>南京的台场，有一个金陵颂历代名家咏南京作品集书法碑廊。我记了以下几首：</p>
<h3 id="桂枝香金陵怀古-王安石">桂枝香·金陵怀古 王安石</h3>
<p>登临送目，正故国晚秋，天气初肃。千里澄江似练，翠峰如簇。归帆去棹残阳里，背西风，酒旗斜矗。彩舟云淡，星河鹭起，画图难足。</p>
<p>念往昔，繁华竞逐，叹门外楼头，悲恨相续。千古凭高对此，谩嗟荣辱。六朝旧事随流水，但寒烟衰草凝绿。至今商女，时时犹唱，后庭遗曲。(衰草 一作：芳草)</p>
<h3 id="金陵城西楼月下吟-李白">金陵城西楼月下吟 李白</h3>
<p><strong>金陵</strong>夜寂凉风发，独上高楼望吴越。</p>
<p>白云映水摇空城，白露垂珠滴秋月。</p>
<p>月下沉吟久不归，古来相接眼中稀。</p>
<p>解道澄江净如练，令人长忆谢玄晖。</p>
<p><strong>最后两句我看了会心一笑。李白在千年前做的事，我现在也在做：在一个特定的地方，想起前人的诗句，激起一些感想。</strong></p>
<h3 id="金陵三首-李白">金陵三首 李白</h3>
<p>晋家南渡日，此地旧长安。</p>
<p>地即帝王宅，山为龙虎盘。</p>
<p><strong>金陵</strong>空壮观，天堑净波澜。</p>
<p>醉客回桡去，吴歌且自欢。</p>
<p>地拥<strong>金陵</strong>势，城回江水流。</p>
<p>当时百万户，夹道起朱楼。</p>
<p>亡国生春草，王宫没古丘。</p>
<p>空余后湖月，波上对瀛州。</p>
<p>六代兴亡国，三杯为尔歌。</p>
<p>苑方秦地少，山似洛阳多。</p>
<p>古殿吴花草，深宫晋绮罗。</p>
<p>并随人事灭，东逝与沧波。</p>
<p><strong>古诗词中很多内容是相通的。“亡国生春草，王宫没古丘。”一句，让我想到“国破山河在，城春草木深”。</strong></p>
<p><strong>写完后发现我在说废话，因为不仅是古诗词，其他很多事也都是相通的。</strong></p>
<h2 id="石头城">石头城</h2>
<blockquote>
<p>“那日进了石头城，从他老宅门前路过，街东是宁国府，街西是荣国府，二宅相连，竟将大半条街占了。”曹雪芹在《红楼梦》中说到的“石头城”，就是今天的南京城。说起“石头城”，得先从“石头山”说起。</p>
<p>石头山，现名清凉山，曾因诸葛亮评价金陵山川形势为“钟山龙蟠，石头虎踞”而闻名。这里也是南京称作“金陵”的起源地。</p>
</blockquote>
<h3 id="金陵五题石头城-刘禹锡">金陵五题·石头城 刘禹锡</h3>
<p>山围故国周遭在，潮打空城寂寞回。</p>
<p>淮水东边旧时月，夜深还过女墙来。</p>
<p><strong>这首诗很早之前就读过，但印象不算深，直到写这篇的时候我才去品</strong></p>
<p><strong>“潮打空城寂寞回”这句很有画面感</strong></p>
<p>石头城我是读刘禹锡的诗才知道的，诗我印象不算深，至少是背不出来。来南京后也没特地去找。某日因清凉山
地铁站开通，去参观顺便逛清凉山，结果意外发现了石头城遗址博物馆。</p>
<p>对石头城感兴趣的话可以参看<a href="https://www.nju.edu.cn/info/1056/336061.htm"  target="_blank" rel="noopener" >二十余年持续探掘 解开石头城千年之谜-南京大学</a></p>
<hr>
<h1 id="扬州">扬州</h1>
<h2 id="扬州-1">扬州</h2>
<blockquote>
<p>「揚州」作為地域稱謂始見於《尚書·禹貢》中的「淮海維揚州」，為華夏九州之一。</p>
</blockquote>
<h3 id="江城子-苏轼">江城子 苏轼</h3>
<p>墨云拖雨过西楼。水东流，晚烟收。柳外残阳，回照动帘钩。今夜巫山真个好，花未落，酒新篘。</p>
<p>美人微笑转星眸。月华羞，捧金瓯。歌扇萦风，吹散一春愁。试问江南诸伴侣，谁似我，醉<strong>扬州</strong>。</p>
<p><strong>喜欢“墨云拖雨”中这个“拖”字。这几天雨下得很大，雨云我也常常看，但想不到用“拖”去形容。</strong></p>
<h3 id="南乡子璧月小红楼-孙惟信">南乡子·璧月小红楼 孙惟信</h3>
<p>壁月小红楼。听得吹箫忆旧游。霜冷阑干天似水，<strong>扬州</strong>。薄幸声名总是愁。</p>
<p>尘暗鹔鹴裘。针线曾劳玉指柔。一梦觉来三十载，休休。空为梅花白了头。</p>
<p><strong>可能是我读的诗词还不够多。提到针线的诗我只能想起《游子吟》。</strong></p>
<h3 id="遣怀-杜牧">遣怀 杜牧</h3>
<p>落魄江湖载酒行，楚腰纤细掌中轻。</p>
<p>十年一觉<strong>扬州</strong>梦，赢得青楼薄幸名。</p>
<p><strong>&ldquo;十年一觉扬州梦”这句流传得很广，为什么呢？我想可能是因为“十年”和“一觉”的对比。</strong></p>
<hr>
<h2 id="维扬">维扬</h2>
<p>还是那句，“淮海惟扬州”。“惟”通“维”，于是就把扬州又称为“维扬”。</p>
<h3 id="扬州慢-姜夔">扬州慢 姜夔</h3>
<p>淳熙丙申至日，予过<strong>维扬</strong>。夜雪初霁，荠麦弥望。入其城则四顾萧条，寒水自碧，暮色渐起，戍角悲吟。予怀怆然，感慨今昔，因自度此曲。千岩老人以为有《黍离》之悲也。</p>
<p>淮左名都，竹西佳处，解鞍少驻初程。过春风十里，尽荠麦青青。自胡马窥江去后，废池乔木，犹厌言兵。渐黄昏，清角吹寒，都在空城。</p>
<p>杜郎俊赏，算而今，重到须惊。纵豆蔻词工，青楼梦好，难赋深情。二十四桥仍在，波心荡，冷月无声。念桥边红药，年年知为谁生？</p>
<p><strong>扬州城历史上很坎坷，几经战乱。姜夔当时写下这首词时，杨州正是战乱结束。但他描绘的还是很有意境的。我觉得单是这词牌名就很美。很简单的一个“慢”字，就写出了一种令人向往的生活节奏。</strong></p>
<p><strong>将近千年后的扬州的生活节奏似乎也还保持着令人舒服的慢节奏。</strong></p>
<p><strong>我后来去过两次扬州，一大发现就是等红绿灯的时候，南京几乎默认红灯亮后和绿灯灭后的几秒都是能走的。但扬州则不是。</strong></p>
<hr>
<h2 id="瓜州">瓜州</h2>
<p>这里的瓜州指的是以瓜州渡闻名的千年古镇。</p>
<h3 id="书愤-陆游">书愤 陆游</h3>
<p>早岁哪知世事艰，中原北望气如山。</p>
<p>楼船夜雪<strong>瓜洲渡</strong>，铁马秋风大散关。</p>
<p>塞上长城空自许，镜中衰鬓已先斑。</p>
<p>出师一表真名世，千载谁堪伯仲间！</p>
<h3 id="长相思-白居易">长相思 白居易</h3>
<p>汴水流，泗水流，流到<strong>瓜州</strong>古渡头。吴山点点愁。</p>
<p>思悠悠，恨悠悠，恨到归时方始休。月明人倚楼。</p>
<p><del>瓜州渡现在是一个公园。我经过，但还没有进去过。</del></p>
<p><strong>我后来去过，在导游的讲解下听了几个故事，看了几个景，趁着还有记忆记录如下。</strong></p>
<ul>
<li><strong>正对着鉴真东渡日本的渡头，有块“瓜州古渡”的碑,是上世纪立的。立的时候匆匆忙忙，找了位本地的账房师傅，报酬是几包烟。因为只是账房先生，并不出名，没给落款。但字写得很不错,是我这种外行人看了都喜欢的字。</strong></li>
<li><strong>为纪念杜十娘怒沉百宝箱而建的“沉箱亭”。我之前并没有读过这段故事，所以没什么感觉。</strong></li>
<li><strong>伊娄运河就在此地。如今是全国重点文物保护单位。</strong></li>
<li><strong>瓜州公园的历史。说是在建国后的那段时间蛮辉煌的，还接待了亚非拉好多个国家的领导人。但本世纪初左右开始没落。没落到连本地人都不太知道这里干啥的。直到21年左右有个政协副主席特地来这里看，看了很失望。于是政府开始关注这里了。很中国特色的一个故事。</strong></li>
</ul>
<h3 id="泊船瓜洲-王安石">泊船瓜洲 王安石</h3>
<p>京口<strong>瓜州</strong>一水间</p>
<p>钟山只隔数重山</p>
<p>春风又绿江南岸</p>
<p>明月何时照我还</p>
<p><strong>可以坐镇扬汽渡来体验“一水间”。体验感很不错：大货车，小车，人共乘一艘船。江面宽阔，江风蛮大的，四月底的时候甚至有些冷。</strong></p>
<hr>
<h2 id="二十四桥">二十四桥</h2>
<p>扬州城内古桥名</p>
<h3 id="寄扬州韩绰判官">寄扬州韩绰判官</h3>
<p>青山隐隐水迢迢，秋尽江南草未凋。</p>
<p><strong>二十四桥</strong>明月夜，玉人何处教吹箫。</p>
<h3 id="扬州慢-姜夔-1">扬州慢 姜夔</h3>
<p>淳熙丙申至日，予过维扬。夜雪初霁，荠麦弥望。入其城则四顾萧条，寒水自碧，暮色渐起，戍角悲吟。予怀怆然，感慨今昔，因自度此曲。千岩老人以为有《黍离》之悲也。</p>
<p>淮左名都，竹西佳处，解鞍少驻初程。过春风十里，尽荠麦青青。自胡马窥江去后，废池乔木，犹厌言兵。渐黄昏，清角吹寒，都在空城。</p>
<p>杜郎俊赏，算而今，重到须惊。纵豆蔻词工，青楼梦好，难赋深情。<strong>二十四桥</strong>仍在，波心荡，冷月无声。念桥边红药，年年知为谁生？</p>
<p><strong>我之前读到“二十四桥明月夜”的时候，下意识地想象成是月光照耀下的二十四座桥。但现在二十四桥是瘦西湖景区内的一座景点，只有一座桥。</strong></p>
<p><strong>但据黄永玉老先生的经历，他年轻时也去找过，但“狠狠地走了一趟”后，“连二十四桥桥基都捉摸不到”。如果那桥就在瘦西湖景区内，我想他并不需要费这么大一番功夫。所以我仍愿意保留自己之前的想象。</strong></p>
<hr>
<h2 id="春江">春江</h2>
<p>这里说的“春江”专指《春江花月夜》的春江。</p>
<h3 id="春江花月夜-张若虚">春江花月夜 张若虚</h3>
<p><strong>春江</strong>潮水连海平，海上明月共潮生。</p>
<p>滟滟随波千万里，何处春江无月明！</p>
<p>江流宛转绕芳甸，月照花林皆似霰。</p>
<p>空里流霜不觉飞，汀上白沙看不见。</p>
<p>江天一色无纤尘，皎皎空中孤月轮。</p>
<p>江畔何人初见月？江月何年初照人？</p>
<p>人生代代无穷已，江月年年望相似。</p>
<p>不知江月待何人，但见长江送流水。</p>
<p>白云一片去悠悠，青枫浦上不胜愁。</p>
<p>谁家今夜扁舟子？何处相思明月楼？</p>
<p>可怜楼上月徘徊，应照离人妆镜台。</p>
<p>玉户帘中卷不去，捣衣砧上拂还来。</p>
<p>此时相望不相闻，愿逐月华流照君。</p>
<p>鸿雁长飞光不度，鱼龙潜跃水成文。</p>
<p>昨夜闲潭梦落花，可怜春半不还家。</p>
<p>江水流春去欲尽，江潭落月复西斜。</p>
<p>斜月沉沉藏海雾，碣石潇湘无限路。</p>
<p>不知乘月几人归，落月摇情满江树。</p>
<p><strong>此首诗中的春江说法众多，主流的有三种说法，但都是指向扬州</strong></p>
<p><strong>瓜州公园的旁边，就是张若虚纪念馆。馆里主要围绕着春江花月夜这首诗展开的。</strong></p>
<p><strong>因一首诗而开一座馆，我不敢说是绝无仅有，但至少我是第一次见。</strong></p>
<p><strong>（我中学的时候，慕着其“孤篇压倒全唐”之名背过，但到如今还是不能完全欣赏。背的也是七零八落，惭愧）</strong></p>
<hr>
<h2 id="平山堂">平山堂</h2>
<h3 id="西江月平山堂">西江月·平山堂</h3>
<p>三过平山堂下，半生弹指声中。十年不见老仙翁，壁上龙蛇飞动。</p>
<p>欲吊文章太守，仍歌杨柳春风。休言万事转头空，未转头时皆梦。</p>
<p><strong>喜欢最后一句“休言万事转头空，未转头时皆梦”</strong></p>
<p><strong>平山堂我虽然路过过，但还没去参观，后面不知道有没有机会</strong></p>
<hr>
<h1 id="镇江">镇江</h1>
<h2 id="京口-北固">京口, 北固</h2>
<blockquote>
<p>京口是镇江古称，西周时属宜的封地。“宜”是吴和吴文化的发祥地之一，春秋时京口时属朱方邑，后朱方改谷阳。至秦始皇三十七年（公元前210年），秦始皇东巡会稽，途经京岘山见有王者气，命三千赭衣徒凿断龙脉，以败王气，故改名丹徒县。京岘山西北有雄伟的北固山，那个时代它的后峰伸入江中，北固山的后峰、中峰、前峰起伏连绵，前峰环抱着开阔高平地块，古人把前峰一带称之为京，取义为《尔雅》的“丘绝高曰京”，口指北固山下的江口。东汉末年，孙权称霸江东，于公元209年将苏州的根据地迁至京口，在北固山前峰筑铁瓮城，号称“京”，通称京口。</p>
</blockquote>
<p>京口因北固山而得名，后人写京口几乎绕不开北固山。于是我这里将二者合起来记录。</p>
<p>现在的北固山海拔蛮低的，主峰海拔高程55.2米。但是一口气上去还是要稍微歇下的。</p>
<p>我觉得景区很对我胃口的是，它路旁那些挂的旗子，是关于北固山的诗作。这点很棒，我觉得发挥了其文化底蕴这一巨大优势。我记了以下几首：</p>
<h3 id="次北固山下-王湾">次北固山下 王湾</h3>
<p>客路青山外，行舟绿水前。</p>
<p>潮平两岸阔，风正一帆悬。</p>
<p>海日生残夜，江春入旧年。</p>
<p>乡书何处达，归雁洛阳边。</p>
<p><strong>北固山到洛阳是八百多公里，这个距离在今天可能就只是几个小时，但在古代，就可能得是好几个月。</strong></p>
<h3 id="京口即事-范仲淹">京口即事 范仲淹</h3>
<p>突兀立孤城，诗中引有情，</p>
<p>地深江底过，日大海心生。</p>
<p>甘露楼台古，金山气象新。</p>
<p>六朝人薄命，不见此升平。</p>
<p><strong>诗中提到的古甘露寺，也在北固山。我去逛了下。不太符合我的想象。印象比较深的是有一张很常见的财神像。还有个收款码。祈福的牌子上，我看了看，好多都是希望考研上岸的。</strong></p>
<p><strong>上面的两首诗，都提到了“海”。看介绍是说，“古長江入海口離此不遠，江面寬闊如海。”</strong></p>
<h3 id="无题-乾隆">无题 乾隆</h3>
<p>长江好似砚池波，</p>
<p>提起金焦当墨磨。</p>
<p>铁杆一枝堪作笔，</p>
<p>青天够写几行多。</p>
<p><strong>这首写得有点白，但却很有气势，该怎么说呢，不愧是做皇帝的。</strong></p>
<p><strong>这里提到的“金焦”，指的是金山和焦山，我还没去过，以后有机会再看看。</strong></p>
<p><strong>诗中的“铁塔”也还伫立在北固山。</strong></p>
<h3 id="同曹克明清明日登北固山次韵-萨都剌">同曹克明清明日登北固山次韵 萨都剌</h3>
<p>三月二日风日暖，千家万家桃杏开。</p>
<p>白日少年骑马去，红雨满城拂面来。</p>
<p>共君且须饮一斗，处世不必歌《七哀》。</p>
<p>孙刘事业今何在，百年狠石生莓苔。</p>
<p><strong>我印象很深的是，写着这首诗的旗子后面，花开得很漂亮。正应了“千家万家桃杏开”</strong></p>
<p><strong>诗中提到的狠石还能在北固山看到，不过应该是有人特意维护，已经不再“生莓苔”了。</strong></p>
<h3 id="永遇乐京口北固亭怀古-辛弃疾">永遇乐·京口北固亭怀古 辛弃疾</h3>
<p>千古江山，英雄无觅孙仲谋处。舞榭歌台，风流总被，雨打风吹去。斜阳草树，寻常巷陌，人道寄奴曾住。想当年，金戈铁马，气吞万里如虎。</p>
<p>元嘉草草，封狼居胥，赢得仓皇北顾。四十三年，望中犹记，烽火扬州路。可堪回首，佛狸祠下，一片神鸦社鼓。凭谁问：廉颇老矣，尚能饭否？</p>
<p><strong>在镇江城散步的时候有个意外之喜，偶然瞥见了块路牌。上面写着</strong></p>
<blockquote>
<p>梳儿巷&hellip;&hellip;宋武帝刘裕的旧宅基也位于此巷内的寿邱山上，即辛弃疾词中“斜阳草树，寻常巷陌，人道寄奴曾住”处</p>
</blockquote>
<p><strong>我看到这块路牌的时候是下午6点，正是斜阳黄昏之时，而梳儿巷一眼看上去也普普通通，正应了“斜阳草树，寻常巷陌”。有一种奇妙的巧合感。</strong></p>
<h3 id="南乡子登京口北固亭有怀-辛弃疾">南乡子·登京口北固亭有怀 辛弃疾</h3>
<p>何处望神州？满眼风光<strong>北固楼</strong>。千古兴亡多少事？悠悠。不尽长江滚滚流。</p>
<p>年少万兜鍪，坐断东南战未休。天下英雄谁敌手？曹刘。生子当如孙仲谋。</p>
<p><strong>现在镇江的北固楼经过多次重建，早已物是人非。我一直不太喜欢现代的仿古建筑，加上我去的那天天气并不算好，雾蒙蒙的,原计划不太打算上去，怕破坏自己心中的想象。但最后还是登楼远眺。意料之外的风景很不错。江面十分开阔，可谓江天一色。</strong></p>
<h1 id="参考链接">参考链接</h1>
<ul>
<li><a href="https://www.osgeo.cn/post/041a"  target="_blank" rel="noopener" >南京&quot;金陵&quot;得名的来历? 开源地理空间基金会中文分会 开放地理空间实验室</a></li>
<li><a href="https://www.wikiwand.com/zh-tw/%E7%93%9C%E6%B4%B2%E6%B8%A1"  target="_blank" rel="noopener" >瓜洲鎮 - Wikiwand</a></li>
<li><a href="https://www.wikiwand.com/zh-tw/%E6%89%AC%E5%B7%9E%E5%B8%82"  target="_blank" rel="noopener" >揚州市 - Wikiwand</a></li>
<li><a href="https://www.wikiwand.com/zh/%E4%BA%AC%E5%8F%A3%E5%8C%BA"  target="_blank" rel="noopener" >京口区 - Wikiwand</a></li>
<li><a href="https://baike.baidu.hk/item/%E5%8C%97%E5%9B%BA%E6%A8%93/1972614"  target="_blank" rel="noopener" >北固樓_百度百科</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>博客与文章</title>
      <link>https://ds63.eu.org/2023/blog-and-articles/</link>
      <pubDate>Sun, 30 Apr 2023 16:06:34 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2023/blog-and-articles/</guid>
      <description>博客和文章的推荐</description>
      <content:encoded><![CDATA[<p><strong>打算记录些我看过的觉得有意思的博客和文章</strong></p>
<p><strong>博客会简单写下推荐的理由</strong></p>
<p><strong>文章会简单记录下自己读的感受，但会避免变成是对文章的梗概</strong></p>
<p><del><strong>感觉这个题目不能很好地概括我这篇的内容，但现在又没想好</strong></del></p>
<h2 id="博客">博客</h2>
<ul>
<li>
<p><a href="https://plantegg.github.io/"  target="_blank" rel="noopener" >plantegg</a></p>
<p><strong>计算机网络相关的，干货很多</strong></p>
</li>
<li>
<p><a href="https://plumz.me/"  target="_blank" rel="noopener" >Plum&rsquo;s Blog</a></p>
<p><strong>作者很有趣，涉猎也很广泛。博客持续更新了十几年了。</strong></p>
</li>
<li>
<p><a href="https://freemind.pluskid.org/"  target="_blank" rel="noopener" >Free Mind</a></p>
<p><em>有思考，有科普，内容足。</em></p>
</li>
<li>
<p><a href="https://blog.jm233333.com/"  target="_blank" rel="noopener" >JM233333&rsquo;s Blog</a></p>
<p><strong>作者是南大在读博士生，也是jyy操作系统课的助教</strong></p>
</li>
<li>
<p><a href="https://seuite.github.io/"  target="_blank" rel="noopener" >SEUITE</a></p>
<p><strong>偶然间发现的学校曾存在过的一个协会。从仅存的内容中可以看出是一个很有意思的社团，很可惜它没有传承下来。</strong></p>
</li>
<li>
<p><a href="https://soulogic.com/about"  target="_blank" rel="noopener" >灵魂逻辑</a></p>
<p><strong>先关注的Twitter才发现的博客。作者的经历蛮羡慕的。</strong></p>
</li>
<li>
<p><a href="https://rehoni.github.io/cn/"  target="_blank" rel="noopener" >罗皓的个人博客</a></p>
<p><strong>一个学长的博客。看他还在大学时期的博文，倍感亲切，因为不少课程都是一样的，对一些事情的看法也都很相似。很吸引我的是他对每个月支出的总结，让我对以后可能的生活一窥一二。</strong></p>
</li>
<li>
<p><a href="http://paulsin.blogspot.com/"  target="_blank" rel="noopener" >Blog of Insanity</a></p>
<p><strong>05年更新至今，内容很足。博主知识很渊博。博客的slogan是“读书，是为了遮眼睛”。还没悟到是啥意思。</strong></p>
</li>
<li>
<p><a href="http://blog.orzotl.com/1?page=1"  target="_blank" rel="noopener" >::Nothing but SAi</a></p>
<p><strong>博主为Bangumi的创始者。博客从05年一直活跃到11年，11年这时候博主大概21岁，就已经很有成就了。我现在也刚好是21岁，相比之下实感汗颜。</strong></p>
</li>
<li>
<p><a href="https://tw93.fun/"  target="_blank" rel="noopener" >Tw93</a></p>
<p><strong>博客风格简约而舒服。<a href="https://tw93.fun/2023-08-03/pake.html"  target="_blank" rel="noopener" >这篇博文</a>还能展示ppt，我感觉好神奇。</strong></p>
</li>
<li>
<p><a href="https://jvns.ca/"  target="_blank" rel="noopener" >Julia Evans</a></p>
<blockquote>
<p>showing how topics traditionally considered “hard” and “scary” are actually accessible and interesting and fun&quot;</p>
</blockquote>
</li>
<li>
<p><a href="https://owlswims.com/"  target="_blank" rel="noopener" >To the Lighthouse - ..A Touch and yet not a touch</a></p>
<p><strong>博主几乎每个月都会更新一期《精神食粮》，很佩服，很向往。</strong></p>
</li>
<li>
<p><a href="https://blog.loikein.one/"  target="_blank" rel="noopener" >浣心／Heart of Sleeve</a></p>
<p><strong>网站风格很舒服，我尤其喜欢看网络购物得与失系列</strong></p>
</li>
<li>
<p><a href="https://www.cnblogs.com/guodongdidi/"  target="_blank" rel="noopener" >果冻迪迪 - 博客园</a></p>
<p><strong>找面试记录的时候看到的一个博客。刚开始没注意到时间。后来发现已经是14年的文章了。博客从13年一直到现在，更新频率已经很低了。但从中能看到一个陌生人十年的经历，我想这就是我喜欢博客的原因。</strong></p>
</li>
<li>
<p><a href="https://xlog.whitewater.wang/"  target="_blank" rel="noopener" >白水房</a></p>
<p><strong>作者应该是北京中医药大学的研究生。对编程很感兴趣，并用其做了许多事。我觉得这就是编程的魅力</strong></p>
</li>
<li>
<p><a href="https://www.cnblogs.com/coco1s"  target="_blank" rel="noopener" >ChokCoco - 博客园</a></p>
<p><strong>专注于css的博客，很厉害。但是这个博客本身却很素,有趣</strong></p>
</li>
<li>
<p><a href="https://ciechanow.ski/"  target="_blank" rel="noopener" >Bartosz Ciechanowski</a></p>
<p><strong>科普生活中常见的工具或现象背后的原理，图文并茂。</strong></p>
</li>
<li>
<p><a href="https://dantezy.xyz/posts/"  target="_blank" rel="noopener" >一派胡言</a>和<a href="https://zhangyet.github.io/"  target="_blank" rel="noopener" >一派胡言</a></p>
<p><strong>作者的语言很有趣，数学专业，从事编程，诗词信手拈来，我十分佩服。</strong></p>
</li>
<li>
<p><a href="https://blog.cnbang.net/"  target="_blank" rel="noopener" >bang’s blog</a></p>
<p><strong>也是一个有着十多年历史的博客。从08年至今，十六年里作者从刚进入到大学，到有两个孩子。读来很让人感慨。</strong></p>
<p><strong>我自己的这个博客会坚持多久呢？</strong></p>
</li>
<li>
<p><a href="https://blog.huli.tw/"  target="_blank" rel="noopener" >Huli&rsquo;s blog</a></p>
<p><strong>内容写得有趣又干活多。以前端开发为主和相关的安全问题。</strong></p>
</li>
<li>
<p><a href="https://roriri.one/"  target="_blank" rel="noopener" >螺莉莉数据中心</a></p>
<p><strong>作者本硕都是心理学专业，毕业后从事前端开发工作。做的项目硬核有趣，文章内容有深度，语言又诙谐。</strong></p>
</li>
</ul>
<h2 id="文章">文章</h2>
<h3 id="2023年4月">2023年4月</h3>
<ul>
<li>
<p><a href="https://plumz.me/archives/12906/"  target="_blank" rel="noopener" >你所热爱的，就是你的生活</a>
我还蛮喜欢看别人写的年度总结的。像是开了一扇窗去了解一个陌生人一年来的生活。但自己却没啥勇气去写年度总结，并将之放之网上。</p>
<p>再说回来这篇文章，我很认同这段话。</p>
<blockquote>
<p>有时候我想想，互联网给我带来的是更多时光的消磨，有的时候，我是不是应该返璞归真，多多做一些“远离网络”的事情。比如翻出自己曾经买过的那些书，拿出自己还没有拆封的音乐 CD，找到自己当年吃灰的 3DS，享受那些我们还没有被浮躁的互联网绑架时候的珍贵东西，或许这样对我来说是更好的选择，自己也会得到更多的提高。</p>
</blockquote>
<p>我有好多时间是用来刷Twitter，贴吧，这些碎片化的东西常常就是刷过去就忘了。我觉得我的这些时间值得更好的去处。</p>
</li>
</ul>
<hr>
<ul>
<li><a href="https://www.jasonwei.net/blog/practicing-ai-research"  target="_blank" rel="noopener" >Practicing AI research</a>
<ul>
<li>这句让我印象很深。有被激励到。
<blockquote>
<p>doing research is a skill that can be learned through practice, much like sports or music.</p>
</blockquote>
</li>
<li>作者谈到沉没成本时，是这样说的&quot;it’s important to identify sunk cost fallacies&quot;。我的理解是当断则断，不要过多地去考虑沉没成本。</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><a href="https://luolei.org/gfw/"  target="_blank" rel="noopener" >GFW之父方滨兴讲座后杂想</a>
<ul>
<li>看到这篇的时候觉得很巧。因为我之前就follow了作者的Twitter。现在无意间看到了他十年前还在上大学时听讲座的想法。这种感觉很棒。</li>
<li>另一个感触是尽管十年过去，这篇文章依旧没有过时。甚至墙更高了些。作者文中的畅想&quot;不知20年后，如果我们走进了一个开放、自由的公民社会，那堵墙不再，方校长还在的话，他会怎么回味自己的所作所为。&ldquo;距离当时的二十年后，还有十年。</li>
<li>但最近有一个现象我看着很欣喜。我看到周围好多同学都在用着ChatGPT。而用它是需要用代理的。</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年5月">2023年5月</h3>
<ul>
<li><a href="https://freemind.pluskid.org/misc/elden-ring-pvp-and-theory-of-mind/"  target="_blank" rel="noopener" >Elden Ring PvP and Theory of Mind</a>
<ul>
<li>很有趣，作者从pvp讲到ToM。并科普了ToM的概念。我觉得作者科普的很好。既讲明白了概念，还让读者——至少是我，对此有了进一步了解的兴趣。</li>
<li>文中谈到 AI 语言模型。让我想到之前看过的LLM继续发展下去，可能会有类似读心术的效果，能预测你下一步要做什么，甚至是在想什么。我觉得这在一定程度是可行的。因为现代所谓的一些读心术，很多都是基于微表情的观察和分析其过去的行为模式和经历上。</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><a href="https://freemind.pluskid.org/electronics/5x12-keyboard-debugging2/"  target="_blank" rel="noopener" >记一次有意义的熬夜</a>
<ul>
<li>作者客制化键盘的经历。</li>
<li>我自己算是半个机械键盘爱好者，也接触了些客制化键盘，但一直只停留在很初级的阶段。所以看得很起劲。</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><a href="https://soulogic.com/item/3294"  target="_blank" rel="noopener" >我的郑老三死了</a>
<ul>
<li>作者纪念自己的猫</li>
<li>很有感觉</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年6月">2023年6月</h3>
<ul>
<li><a href="https://www.skywind.me/blog/archives/2719"  target="_blank" rel="noopener" >互联网技术比游戏后端技术领先十年吗？</a>
<ul>
<li>现在已经习以为然的互联网体验，其背后的技术令人咋舌。</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><a href="https://www.kivinsae.com/2023/05/17/2023-05-17-no_sophism/"  target="_blank" rel="noopener" >关于 初码先生 某推中典型诡辩论部分的拆解</a>
<ul>
<li>有趣</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年7月">2023年7月</h3>
<ul>
<li><a href="https://web.archive.org/web/20060207013551/http://www.joelonsoftware.com/articles/fog0000000339.html"  target="_blank" rel="noopener" >Fire And Motion</a>
<ul>
<li>作者在文中有个观点：大公司不断地技术迭代，有一部分原因是为了让竞争对手疲于奔命，“has no choice but to spend all their time porting and keeping up, time that they can&rsquo;t spend writing new features.”</li>
<li></li>
</ul>
<blockquote>
<p>Maybe as a software developer I really can&rsquo;t control when I&rsquo;m productive, and I just have to take the slow times with the fast times and hope that they average out to enough lines of code to make me employable”</p>
</blockquote>
</li>
</ul>
<hr>
<ul>
<li><a href="https://sive.rs/pnt"  target="_blank" rel="noopener" >The past is not true</a>
<ul>
<li>文章还没看，先被这个网站所震撼到。好短，好漂亮。</li>
<li>读完后让我十分怀念，让我想到以前做的英文阅读题。 差不多相同的结构：故事、作者的感悟。</li>
<li>里面一句话我觉得值得记录：
<blockquote>
<p>We think of the past like it’s a physical fact - like it’s real. But the past is what we call our memory and stories about it. Imperfect memories, and stories built on one interpretation of incomplete information. That’s “the past”.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年8月">2023年8月</h3>
<ul>
<li><a href="https://blog.loikein.one/posts/2022-09-21-phd-first-year/"  target="_blank" rel="noopener" >读博第一年总结 - 浣心／Heart of Sleeve</a>
<ul>
<li>读博对我来说太遥远，但最后一段我觉得值得记录：
<blockquote>
<p>当然，对于我个人而言最重要的是，相信一切都是能结束的。 之前碰到同学的室友，隔壁专业的，聊如果挂科了，找不到工作，不得不回到国内，被卷进新文革，该怎么办。我说，大不了我还能跳楼，他说，大不了我就趴在泥里，吃草吃土地活下去。屋子内外充满了快活的空气。</p>
<p>我想，在现在这样的时代，确实需要一些这样的觉悟，才能活得更轻松一些。</p>
</blockquote>
</li>
<li>我最近偶尔会觉得焦虑，不过找到了一个自己觉得还算不错的排解方法。就是假设最坏的结果发生，然后我就会想，就算是那样我也是不能活，一旦接受了这个可能的最坏结果，我一般就没那么焦虑了。所以看到这段后，我会心一笑。</li>
<li>半年后我想起这段，觉得作者写得真好，想去看看有没有更新。但却发现当时的自己忘写链接了，遍寻（搜标题、搜历史记录、查git历史、翻博客订阅列表）无果，正当想放弃的时候，却在自己的博客推荐列表里找着了(就在上面,<a href="https://blog.loikein.one/"  target="_blank" rel="noopener" >浣心／Heart of Sleeve</a>是也)。真可谓“山重水复疑无路，柳暗花明又一村”。</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年9月">2023年9月</h3>
<ul>
<li><a href="https://vadim.oversigma.com/MAS862/Project.html"  target="_blank" rel="noopener" >Information Processing in Human Body</a>
人体真奇妙</li>
</ul>
<hr>
<ul>
<li><a href="https://writings.sh/post/naming"  target="_blank" rel="noopener" >浅谈编程中的命名（短文） | 春水煎茶 - 王超的个人博客</a>
<ul>
<li>基本上都认可。第二点我之前有注意到，但一直没有去落实。</li>
<li>我最近命名的时候喜欢用全称，因为觉得缩写时间久了很容易忘。</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2023年10月">2023年10月</h3>
<ul>
<li>
<p><a href="https://www.skypyb.com/2021/12/rizhi/1936/"  target="_blank" rel="noopener" >又到了这个时间，博客总共写了四年了。 来个2021年的小总结吧 | 编码妙♂妙♂屋</a></p>
<p>评论区有几句话值得记录。</p>
<blockquote>
<p>其实通过博客来了解一个人还是比较片面的， 毕竟要写博客的时候只有两种心情：</p>
<p>1、我学了啥技术极度的需要整理归纳。 2、 我心情澎湃，得释放表达欲。</p>
<p>你看，无论哪种，其实都和一个人日常生活中的样子相差甚远。</p>
</blockquote>
</li>
</ul>
<hr>
<ul>
<li><a href="https://blog.douchi.space/if-human-were-ovipara/#gsc.tab=0"  target="_blank" rel="noopener" >如果人类是卵生的 | 椒盐豆豉</a></li>
</ul>
<p>有趣</p>
<hr>
<h3 id="2023年11月">2023年11月</h3>
<ul>
<li>
<p><a href="https://blog.dewsweet.cc/archives/1690105326035"  target="_blank" rel="noopener" >回归本地教程——序 - 清新小甜的个人博客</a></p>
<p>一个科普系列，关于动漫下载，写得很好</p>
</li>
</ul>
<hr>
<ul>
<li><a href="https://shaleenjain.com/blog/personal-story-and-new-earth/"  target="_blank" rel="noopener" >My Personal Journey and Why I&rsquo;m building a New Earth</a></li>
</ul>
<p>印象最深的是这句：</p>
<p><code>If I could make this world a better place, perhaps it would be able to love me or at least acknowledge me for who I am and I could grow to love it as well.</code></p>
<hr>
<ul>
<li>
<p><a href="https://jacobian.org/2021/apr/7/embrace-the-grind/"  target="_blank" rel="noopener" >Embrace the Grind - Jacob Kaplan-Moss</a></p>
<p>大一的c++老师很喜欢说一句话，“聪明的程序员也是懒程序员”。这篇文章提供了另一种观点：</p>
<p><code>Magic is mundane. If you’re willing to embrace the grind, you can pull off the impossible.</code></p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://www.thedial.world/issue-9/yugolsav-wars-yu-domain-history-icann"  target="_blank" rel="noopener" >Yugoslavia&rsquo;s Digital Twin — The Dial</a></p>
<p>一个国家解体了，其域名还会存在吗？南斯拉夫的<code>.yu</code>给出了答案。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://www.52pojie.cn/thread-1468888-1-1.html"  target="_blank" rel="noopener" >赛尔号：通信协议逆向与模拟&amp;中间人攻击窃取登录凭证</a></p>
<p>看得津津有味。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://xlog.whitewater.wang/A038"  target="_blank" rel="noopener" >A038我的编程学习经历及收获 - 王白水</a></p>
<p>摘录最后一段。</p>
<blockquote>
<p>希望对编程感兴趣的同学们，想学就学下去，学不进去就休息休息，没有方向就和别人聊聊。付出总有收获，再不济，付出的过程能体验到充实嘛，总比玩了一天无比空虚好</p>
</blockquote>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://tannercollin.com/my-backup-strategy/"  target="_blank" rel="noopener" >My Backup Strategy | Tanner&rsquo;s Site</a></p>
<blockquote>
<p>All software used to create and store the backups should be free and open source so I&rsquo;m not depending on the survival of a company.</p>
</blockquote>
<p>很认同这句。</p>
<blockquote>
<p>This backup folder is then synced to encrypted 2.5&rdquo; 1 TB hard drives which I rotate between my bag, offsite, and my parents&rsquo; house.</p>
</blockquote>
<p>看到这里我笑出声了。因为我读这篇时有一个词一直在我脑中，“两地三中心”。某种概念上是一致的。</p>
<p>然后突然意识到，一个人所珍视的数据，只要一块1TB的硬盘就能存储得下。有点感慨，但说不上来为什么。</p>
<p>这篇提到的备份策略蛮有用的，而且距今两年左右，不算太过时。看得我有些心动。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://blog.laisky.com/p/shanghai-lockdown/"  target="_blank" rel="noopener" >上海封城笔记</a></p>
<p>有些东西不应该被忘记。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://www.sqlite.org/whyc.html"  target="_blank" rel="noopener" >Why Is SQLite Coded In C</a></p>
<p>编程语言的选择</p>
</li>
</ul>
<hr>
<h3 id="2023年12月">2023年12月</h3>
<ul>
<li>
<p><a href="https://woozy.im/articles/welcome-to-20-year-old/"  target="_blank" rel="noopener" >欢迎来到20岁</a></p>
<p>同样是二十岁的年纪，作者的想法比我高多了。并且作者后来还贡献了好几个star数过百的项目，某种角度上确确实实地为人类文明进步做出了贡献。我很佩服。</p>
<blockquote>
<p>家里蹲的未来是我想避免的, 我所期望的不仅仅是不饿死, 还要过得好. 为了不饿死去干活是出于人类生理的本能, 要过得好而去干活则要心理上强烈的意志. 我的理想可是为人类文明的进步做出贡献</p>
</blockquote>
<p>另外，作者的个人主页<a href="https://woozy.im/"  target="_blank" rel="noopener" >I&rsquo;M WOOZY</a>设计得既简约又有趣，我很喜欢。</p>
</li>
</ul>
<hr>
<h3 id="2024年1月">2024年1月</h3>
<ul>
<li>
<p><a href="https://soaked.in/2020/08/wechat-platform-url/#url-formats-overview"  target="_blank" rel="noopener" >微信公众号文章URL的种类与结构 | 咸湖的盐鱼</a></p>
<p>今天看到一篇写得蛮好的微信公众号文章想转发到其他地方，留意到其链接特别长。于是搜了下其是如何构成的。找到的这篇文章大体上能解答我的疑问。摘录最后一段：</p>
<blockquote>
<p>他们这么做的主要目的或许是为了反爬吧。但这种行为实在恶心用户，把用户产生的内容当作是自家的宝贝，捂在怀里，生怕见光。</p>
</blockquote>
<p>ps:国内的不少网站都喜欢在分享链接中带点参数，可能是用于信息收集和分析。虽然我已经知道在使用这些网站或服务时，自己的数据或隐私多半已经不属于自己了。但奈何它们做得如此明显且丑陋，还是让人不愉快。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><a href="https://wangyw15.top/p/11c6bb90/"  target="_blank" rel="noopener" >激活CeVIO - 简单的小站</a></p>
<p>头回看如何破解一个商用级程序，有意思。</p>
</li>
<li>
<p><a href="https://meteorcollector.github.io/2023/02/iris-l2d/"  target="_blank" rel="noopener" >铱之皮套大冒险</a></p>
<p>看得我好生佩服:作者看别人的小狗皮套看得眼馋，于是也试着做了些皮套。做好的皮套觉得得派上用场，于是在“根本不会JaveScrpt和css，而且连node.js是什么都不知道”的情况下，自学，并最终成功地给自己的博客加上live 2d。</p>
<p>文中的这句话我很认可：</p>
<blockquote>
<p>但是万事总要开头，以后也肯定要学这些东西，不如放手一搏，不留遗憾。</p>
</blockquote>
</li>
</ul>
<hr>
<ul>
<li><a href="https://meteorcollector.github.io/2023/05/iris-fake-nlp/"  target="_blank" rel="noopener" >iris的nlp之路：章鱼触手与斩龙大剑</a></li>
</ul>
<p>iris是一个qq bot。她的应答在我看来已经蛮自然的。之前一直好奇是如何实现，看了这篇文章才知道是基于BM25字符串距离进行回答。</p>
<p>作者曾想使用llm，但受限于设备的缘故，未能有结果。对于llm，我和作者的想法差不多，但人家写得比我好，摘录如下。</p>
<blockquote>
<p>同时我也担忧起来。虽然nlp被普及了，但是ai大厂掌握了太多——这繁荣并不是百花齐放，看起来纷繁的应用都是已有的大语言模型伸出的触手——沿着触手找过去，只有漆黑的、令人生畏的垄断。</p>
</blockquote>
<blockquote>
<p>目前很多科研工作者都在致力于优化大语言模型的训练，使得个人开发者也可以负担得起它们的训练——期望他们的工作可以取得成果，尤其期望中文语言模型的发展可以越来越好（然而制约它发展的因素过于复杂，任重而道远）。</p>
</blockquote>
<hr>
<h3 id="2024年3月">2024年3月</h3>
<ul>
<li><a href="http://localhost-8080.com/2014/08/folktale-classification-system/"  target="_blank" rel="noopener" >一种童话分类的方法 | 考据癖</a></li>
</ul>
<p>我和作者一样，“每次在 Wikipedia 查资料，总会被一些不相关的点分散注意力”。或者更进一步说，我浏览器打开的tab几乎是只增不减，除非某天实在卡得影响到了我正常使用，我才会忍痛关掉几个。</p>
<p>很喜欢最后一段:</p>
<blockquote>
<p>研究这些无聊的东西时，从没想过它们有什么用，光是找答案的过程就像打游戏一样过瘾了，觉得好奇心得到满足就足够了。但知道这些东西之后，you’ll never look at the world the same way again。</p>
</blockquote>
<ul>
<li><a href="https://yunyoujun.cn/posts/the-birth-of-yunlefun"  target="_blank" rel="noopener" >云乐坊工作室的成立与缘起与有关的话 - 云游君的小站</a></li>
</ul>
<p>也许过段时间再读会更有体会。</p>
<hr>
<h3 id="2024年4月">2024年4月</h3>
<ul>
<li><a href="https://moviezhou.github.io/2021/11/17/old-blogs.html"  target="_blank" rel="noopener" >翻看旧博客</a></li>
</ul>
<blockquote>
<p>为了测试Obsidian，打开了以前的github page博客的Markdown文档，随便翻看了几篇，感觉记录真是一个好习惯，从这些文字里能看到曾经那个真实、积极、纯粹的自己，能看到某年某月的某天做了什么琐碎的事情，心情是快乐还是沮丧……生活就是这样的片段组成的，我总是期待每天有新鲜事发生，这可能是双子座的通病。人生中，大部分的日子都是普通的，从每一天的普通生活中发现意义，做有价值、感兴趣的事情，要比试图去寻找并不确定的意义更具体。</p>
</blockquote>
<p>尤其是“我总是期待每天有新鲜事发生，这可能是双子座的通病”，我好像也是双子座，虽然我不信星座，认为这只是将一些人类的共有特点分摊给了不同日期。但我欣赏最后一句。</p>
<hr>
<ul>
<li><a href="https://www.kivinsae.com/2023/08/23/2023-08-24-talking_with_people/"  target="_blank" rel="noopener" >让我们粗鄙一点 | Kivinsae&rsquo;s Nest</a></li>
</ul>
<p>我能意识到自己对待许多现象前，是预先抱有自己的观点。这好吗？不好。因为难免会因此先入为主，进而演变成：这个人和我观点一致吗？这人不错啊：这人是傻逼。</p>
<p>我在极力避免自己如此，但还是没到那境界。作者给出的建议是：</p>
<blockquote>
<p>在保证自身安全的情况下，多观察人。</p>
<p>如果您喜欢和人面对面，出去吧，和各种背景的人交朋友，坐下来聊聊天。
如果您更喜欢独处，这个时代有无数的时光之隙可以提供无尽的观察切入点。</p>
</blockquote>
<hr>
<ul>
<li><a href="https://dantezy.xyz/posts/ghost-in-the-shell-again/"  target="_blank" rel="noopener" >再看 Ghost in the Shell | 一派胡言</a></li>
</ul>
<p>&ldquo;把「我」看作一个 git repo。&rdquo; 这个比喻很有趣。我之前还看过一个将改革比作重构，革命比作实在是重构不下去了，干脆另起炉灶。借此还解释了美国为什么世界第一，因为它历史够短，而且建国的时候设计得好，欠的技术债少。</p>
<hr>
<h3 id="2024年5月">2024年5月</h3>
<ul>
<li><a href="https://frostming.com/2024/diversity/"  target="_blank" rel="noopener" >我们生活在差异里 - Frost&rsquo;s Blog</a></li>
</ul>
<p>有两句很值得记录：</p>
<blockquote>
<p>我们的视界起初并没有什么不同。只是后来，被不同的工作、不同的环境，渐渐地塑造成现在的样子。正如《代码之外第一期听众来信》所说的，第一份工作决定了我现在的样子，我至今非常感谢它。</p>
</blockquote>
<blockquote>
<p>周围的人大都是相似的，但除此之外存在着更多其他的人</p>
</blockquote>
<p>评论有一条也很有意思</p>
<blockquote>
<p>趁着年轻一定要多跳槽，每个工作对你都是提升能力的跳板，如果以跳槽为目的的去工作，那么你自然就会去提升自己，这样就算不跳槽，在公司也会凭借能力提升而获得晋升机会</p>
</blockquote>
<hr>
<h3 id="2024年6月">2024年6月</h3>
<ul>
<li><a href="https://blog.rxliuli.com/p/e8e351cf90c049e589ce6044613a62ec/"  target="_blank" rel="noopener" >如何编写无法维护的代码 - rxliuli blog</a></li>
</ul>
<p>笑抽了。记忆中有个Github仓库是收录类似于这种建议的，但一时没找着。</p>
<p>一直很喜欢这种一本正经说反话的幽默。等等，也许不是反话？</p>
<ul>
<li><a href="https://blog.cnbang.net/tech/3890/"  target="_blank" rel="noopener" >手机能跑图生成和 LLM 大模型吗 « bang’s blog</a></li>
</ul>
<p>期待多年后再看这篇博客的时候，一脸怀旧地说，“啊，原来当年的最高配置算力才这么点”。</p>
<ul>
<li><a href="https://blog.besscroft.com/articles/2022/%E5%AD%A6%E4%B9%A0%E4%B8%8E%E4%BA%BA%E7%94%9F%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E5%90%91%E7%9A%84%E6%94%B9%E5%8F%98/"  target="_blank" rel="noopener" >学习与人生——我的学习方向的改变 | 旅行者的随想</a></li>
</ul>
<p>这篇很好的解答了我最近的一些迷茫，于是我将文中大部分内容进行了摘抄：</p>
<p>我现在还处于作者所说的之前的阶段</p>
<blockquote>
<p>比较注重自己的工程能力。因为我需要迅速的提升自己的编码能力，来达到企业对于开发者的基本要求。毕竟，我得先保证自己能顺利找到工作，能先吃饱饭.</p>
<p>我的工作语言是 Java，在之前很长一段时间，我几乎都注重于框架和第三方库的使用。我必须得把工作中会用到的各种技术学会，熟悉他们的使用方法，以及一些基本的原理。</p>
</blockquote>
<p>这一阶段，作者提到的学习方法我觉得很好：</p>
<blockquote>
<p>于是乎我在学习的时候，就是照着官方的【参考文档】来看的。这样不仅能让我少走许多弯路，还能一开始就能了解到比较【标准】的使用方法，也就是【最佳实践】&hellip;我们可以在参考文档中，找到 Spring Data Jpa 文档的入口，这时就可以根据文档的介绍一步步往下实践了。然后，我们可以去 GitHub 上面找最佳实践，看一看除了官方，其它优秀的社区开发者，是如何使用的。可以从官方仓库的 issues 里面找，尤其是那些提 issues 时，有很详细的 debug 过程的，一般这样的开发者，他的代码质量不会太差，甚至人家的仓库还配备了 wiki 。</p>
</blockquote>
<p>作者的第二阶段是</p>
<blockquote>
<p>当我有了一份稳定的工作、且能独立应付工作中大多数问题的时候，我需要重视自己的学习能力、架构能力和系统设计能力。简而言之，就是努力学习基础知识，系统性的完善自己的知识图谱，并尝试独立设计系统。</p>
<p>计算机基础知识，我想不管再过多少年，可能都不会过时，而某一门技术是有可能的，这一点只要稍微了解下整个计算机技术的发展史就能明白。但是基础只要扎实了，学任何一门技术都会很快。之前也并不是没有这样做，只是时间一方面分配的确实少了，另一方面就是，没有系统性的去学习基础知识，导致部分知识在脑海中比较零散，无法构成体系。而接下来，就是要解决这些问题的时候了。提升了基础和学习能力，才能解决更多的问题，才能一直向上走！</p>
</blockquote>
<hr>
<h3 id="2024年7月">2024年7月</h3>
<ul>
<li>
<p><a href="http://kennysun.com/game-dev/my-experience-pitching-mr-suns-hatbox-to-publishers/"  target="_blank" rel="noopener" >My Experience Pitching Mr. Sun’s Hatbox to Publishers – Kenny Sun</a></p>
<p>作者是一名独立游戏制作者，花费四年左右的时间创作了Mr. Sun’s Hatbox，截至日前steam有319篇评测，好评率84%。</p>
<p>文章中提到的几个数据刷新了我的认知:</p>
<blockquote>
<p>$84k development budget
$215k marketing budget
$220k budget for porting to Switch, Playstation, and XBox, QA, and localization</p>
</blockquote>
<p>市场营销费用两倍于给作者的开发费用，而移植多平台的费用甚至更多。</p>
<p>还有几点：</p>
<ol>
<li>作者本来只联系了五家发行商，只拿到了一个offer。后来在朋友的建议下又接着联系了20家，最终拿到的offer&quot;Much higher&quot;</li>
<li>
<blockquote>
<p>As of January 2024 the game has made a bit over $140k in net revenue, so taking the extra budget in exchange for worse revenue share was definitely the right call, as it’s unlikely that the game will recoup its expenses. In the end, I’m happy with the decision I made and feel incredibly fortunate that they took a chance on my silly game.</p>
</blockquote>
</li>
</ol>
</li>
</ul>
<hr>
<h2 id="2024年8月">2024年8月</h2>
<ul>
<li>
<p><a href="https://matduggan.com/the-worst-website-in-the-entire-world/"  target="_blank" rel="noopener" >The Worst Website In The Entire World</a></p>
<p>作者语言辛辣又有趣。</p>
<blockquote>
<p>Hey front-end folks, just a quick note. Never ever ever ever ever mess with my browser. It&rsquo;s not yours, it&rsquo;s mine. I&rsquo;m letting you use it for free to render your bloated sites. Don&rsquo;t do this to me. I get to copy paste whatever I want whenever I want. When you get your own browser you can do whatever you want but while you are living in my house under my rules I get to copy/paste whenever I goddamn feel like it.</p>
</blockquote>
<p>这一段我特别认可。</p>
</li>
<li>
<p><a href="https://blog.hentioe.dev/posts/why-write-novice-tutorial.html"  target="_blank" rel="noopener" >我为什么要写新手向的入门教程 | 绅士喵</a></p>
<p>我自己这个博客，自认为目前大部分内容还停留在里面提到的“日记式”的新手教程。我也有尝试去提高文章的深度和广度，但写起来挺麻烦的，而且自己积累也不够。</p>
<p>挺钦佩作者，愿意去降低读者门槛，以照顾普通网民的知识接收能力而改变撰写风格。</p>
</li>
</ul>
<hr>
<h2 id="2024年10月">2024年10月</h2>
<ul>
<li>
<p><a href="https://barnett617.github.io/wilson-blog/notes/2020-05-04-thinking-about-blog/"  target="_blank" rel="noopener" >整理博客过程中的一些思考 | Wilson&rsquo;s Blog</a></p>
<blockquote>
<p>首先那些应该算不上是博客，因为很少有从自己大脑中输出的文字内容，大学时期写的多是把课本上的概念汇总梳理了一下，顶多算得上是读书笔记。但那时的归纳能力的确弱的可怜，基本划完重点以后发现都是重点。</p>
<p>这就不由想想为什么会这样呢，发现其实本科阶段真的只是在学了一个”目录“，只是让我们知道了自己的专业里有哪些专业名词，免得以后从事自己专业所做的事时一无所知。</p>
</blockquote>
</li>
</ul>
<p>我博客目前的大部分内容其实也差不多，美其名曰笔记，其实就是摘抄。</p>
<ul>
<li>
<p><a href="https://barnett617.github.io/wilson-blog/posts/2018-10-02-review-of-2017-to-2018/"  target="_blank" rel="noopener" >2017-2018年个人盘点(多图) | Wilson&rsquo;s Blog</a></p>
<blockquote>
<p>看着自己身边的装备一件一件通过自己的努力和进步挣得，满是欣喜满足</p>
</blockquote>
<p>和上面那篇是同一位作者。只是这篇记录的是作者刚工作那段时间。时间过得真快。</p>
</li>
<li>
<p><a href="https://roriri.one/2022/06/11/behind-the-scenes-interactive-video-player/"  target="_blank" rel="noopener" >幕后故事：交互视频播放器的技术发展历史 | 螺莉莉数据中心</a></p>
<p>博主一步步介绍了自己是实现交互视频播放器的过程。其中涉及到需求的变更，性能的调优，代码的维护。文字有趣，内容丰富，我读起来津津有味，犹如在看侦探小说，看名侦探如何从蛛丝马迹中抽丝剥茧，还原事件真相。</p>
<p>另外摘录两段：</p>
<blockquote>
<p>技术真正的价值并不体现在面子上能拿出来的 feature，而是背后思考问题的逻辑和解决问题的方法。代码只是解决问题的手段，如果没有好的思路支撑，它也可能成为创造问题的根源；</p>
</blockquote>
<blockquote>
<p>每一个工作流程都是为上一个工作流程提供「实现」，在商业项目的推进过程中把产品核心目标摆在第一位，而不是把自己的情怀、情感、情结摆在第一位是很严肃且重要的。毕竟你看，纵观中国互联网创业史，拿情怀当饭吃的大多都没有什么好下场。</p>
</blockquote>
</li>
<li>
<p><a href="https://tech.meituan.com/2018/12/06/biography-panweizeng.html"  target="_blank" rel="noopener" >人物志 | 技术十年：美团第一位前端工程师潘魏增 - 美团技术团队</a></p>
<p>最近hr面被问到未来规划，我总会说自己偏理想主义，受大学程序设计课老师的一句话影响很深，他说“聪明的程序员也是懒程序员”，引申为程序员应该靠代码，来解决生活中繁杂的，可以交由机器所解决的问题，进一步引申为，程序员可以靠自己的努力和智慧来对社会尽一点贡献。</p>
<p>文章的作者被问到类似的问题时，是这样回答的</p>
<blockquote>
<p>青春总是有很多冲动嘛，一心想要去改变世界。在饭否，我们的梦想就是让信息更公开，社会更平等，让信息流动更快。职业规划方面，想得真的不太多。当时的想法，就是想往前端技术专家的方向努力一下，能对行业产生一些价值，个人能有一些影响力，就很知足了。</p>
</blockquote>
<p>有点不谋而合，哈哈。</p>
</li>
<li>
<p><a href="https://windliang.wang/2023/11/19/%E8%AE%B0%E5%89%8D%E7%AB%AF%E5%A4%A7%E4%BC%9AFEDay/#more"  target="_blank" rel="noopener" >记前端大会 FEDay 的一天 | windliang</a></p>
<p>作者记录了他参加前端大会中印象比较深的几段分享，我觉得很有意义。</p>
<blockquote>
<p>持续迭代的复杂项目，值得去转 TS。对于复杂的业务项目，由于参与人数众多，很多结构也很依赖于后端，随着慢慢迭代，更多的 any 或者类型和实际用的数据渐渐不一致，就变成破窗效应，迭代需求时候就没有人再愿意维护旧类型了。</p>
</blockquote>
<p>js or ts , it&rsquo;s a problem</p>
<blockquote>
<p>分享了对于 Web Components 遇到的一些问题，还有许久没有操作的 dom，介绍了一个有用的 API TreeWalker，解决 Shadow Dom 样式被隔离的问题，全面拥抱 TailWind css，解决取名问题，同时避免各个 class 相互影响，实现组件内聚到 HTML 标签上。我突然产生了一种感觉，随着 Web component 的完善，更多的框架出现，未来会不会又回到原生标签的开发中，哈哈。</p>
</blockquote>
<p>Web Components一直是久仰大名，但没实际用过。挺好奇的。</p>
<blockquote>
<p>另外提到目前网页都是二维或者三维的渲染，期待未来实现二维和三维的混合渲染，同时三维也尽可能的接近目前 html/css 的开发模式，目前已经有个框架在往这方面发展，还可以直接在 VSCode 上调试</p>
</blockquote>
<p>没写过AR/XR相关的效果，想试试，但又畏惧复杂的计算机图形学知识</p>
<blockquote>
<p>Hux 也形象的用 O(n) -&gt; O(1) 来比喻边际效应，从 Flash 到 H5 到移动端，当技术让边际成本足够低，相应的职业也就会消失。有老的技术的消失，但随之又会有新技术的出现，技术肯定是为人所服务的，只要有技术，我们就会在。
我们确实站在了 AI 变革的时间点，但不用担心被 AI 取代，历史的经验已经充分告诉我们，一个的消失一定会有新的出现，保持学习即可。</p>
</blockquote>
<p>为之一振</p>
</li>
</ul>
<hr>
<h2 id="2024年11月">2024年11月</h2>
<ul>
<li>
<p><a href="https://www.zhangxinxu.com/life/2024/07/frontend-10-years-change/?shrink=1"  target="_blank" rel="noopener" >前端圈子十年变化之我见 « 张鑫旭-鑫空间-鑫生活</a></p>
<blockquote>
<p>这10年来，Web的能力越来越强，可以实现几乎媲美桌面端软件的应用，在音视频开发，图像处理，交互实现这一块，都有着长足的进步。</p>
<p>不过，从业者对于这些能力的掌握的进步明显落后于技术领域本身的进步，因为框架和工具带来开发便捷的同时，让很多从业者忽略了更底层特性的学习与进步。</p>
<p>这其实是好现象，让我感觉不到被追赶的压力，周末可以放心地去钓鱼，没事的时候，写写小说，做做短视频。</p>
</blockquote>
<p>还是要往深了学。</p>
</li>
<li>
<p><a href="https://youjiali1995.github.io/essay/2023-summary/"  target="_blank" rel="noopener" >2023 年终总结 - 我叫尤加利</a></p>
<p>认可乐观的悲观主义者这种心态</p>
<blockquote>
<p>做任何事情都以满足自己的价值观为标准，也清楚自己的目的，不会有过高的期望。
不关注自己控制不了的事物，也就是课题分离。接受各种可能性，包括失败，它是成长的机会。
不会纠结于过去和现状。现状是过去的结果，过去的事情无法改变，只能接受，而未来是可以改变的。
还算珍惜和积累了时间，也有足够的灵活性，未来能有很多可能性。</p>
</blockquote>
</li>
<li>
<p><a href="https://skylinebin.com/Summaryof2020/"  target="_blank" rel="noopener" >一个节点 继续前行 (2020年终总结)</a></p>
<p>“工作的陷阱”这段是我遇到过的。祝我能保持，甚至发展几门结束一天工作后也愿意去花时间的爱好。</p>
<blockquote>
<p>刚开始工作的几个月，每天下班后就只想着玩一玩儿游戏或者看看视频，不知不觉就会熬到比较晚，第二天醒来去工作，晚上回来又是如此，渐渐以为自己适应了工作。直到自己觉得很久没有看书，也没了支配自己时间的愉悦感时，才发现问题有些不对，这样持续下去自己会被陷进去，既没有成长也不利于身心健康，我将其称为“工作的陷阱”。</p>
</blockquote>
</li>
<li>
<p>读<a href="https://blog.brachiosoft.com/posts/git/"  target="_blank" rel="noopener" >Git 的故事：這一次沒這麼好玩 | 軟體考古學家</a></p>
<p>印象最深的是BitKeeper的落败</p>
<blockquote>
<p>我們曾經有一個類似 github 的服務，現在看來我們應該投入大量資金到那個服務，然後開源 BitKeeper。</p>
<p>我只能說，當你已經有一個金雞母，要割捨它是很困難的。</p>
</blockquote>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>TinyTinyRSS-OPML-to-MD-Table</title>
      <link>https://ds63.eu.org/2023/tinytinyrss-opml-to-md-table/</link>
      <pubDate>Sat, 29 Apr 2023 00:59:40 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/tinytinyrss-opml-to-md-table/</guid>
      <description>记录&lt;a href=&#34;https://github.com/EuDs63/TinyTinyRSS-OPML-to-MD-Table&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34; &gt;EuDs63/TinyTinyRSS-OPML-to-MD-Table&lt;/a&gt; 的过程</description>
      <content:encoded><![CDATA[<h2 id="需求由来">需求由来：</h2>
<p>我很喜欢读博客。但发现总有些很有趣的博客等着发现。所以我关注了些推荐博客的频道。同时，我也想分享些自己喜欢的博客，但每次去手动复制又显得太麻烦了。所以就想着做一个自动化的方式，顺带着也可以学习下Github Action.</p>
<h2 id="历程">历程</h2>
<ol>
<li>大部分时间是花在了如何获取opml文件上。Tiny Tiny RSS所给的文档较为精简，而网上相关的资料大都仅局限于如何部署。所以这一段只能是自己摸索。
<ul>
<li>TinyTinyRSS的网页版有给一个按钮能导出OPML，而这个按钮所指向的网址是<code>http://example.com/tt-rss/backend.php?op=opml&amp;method=export'</code>。但它是有个鉴权操作的。需要登录。</li>
<li>它的示例中有提供了一个登录的api调用，所以我开始的想法也是顺着这个来。想着直接添加data参数。但尝试了多种添加方式无果。</li>
<li>后来注意到登录成功是会返回session值的，于是先用curl试验了下。
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 登录并获取Session ID</span>
</span></span><span class="line"><span class="cl"><span class="nv">SESSION</span><span class="o">=</span><span class="k">$(</span>curl -s -d <span class="s1">&#39;{&#34;op&#34;:&#34;login&#34;,&#34;user&#34;:&#34;user&#34;,&#34;password&#34;:&#34;password&#34;}&#39;</span> http://example.com/tt-rss/api/ <span class="p">|</span> python -c <span class="s2">&#34;import sys, json; print(json.load(sys.stdin)[&#39;content&#39;][&#39;session_id&#39;])&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#获得opml文件</span>
</span></span><span class="line"><span class="cl">curl -o my_tiny_tiny_rss.opml <span class="s1">&#39;http://example.com/tt-rss/backend.php?op=opml&amp;method=export&#39;</span> --cookie <span class="s2">&#34;ttrss_sid=</span><span class="si">${</span><span class="nv">SESSION</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span></code></pre></div></li>
<li>转写成python是用的request。其实现在回头想想，这应该是蛮基础的操作，而且session之前也有接触过。如果早点想起来的话是可以少花些时间的。</li>
</ul>
</li>
<li>opml的解析有现成的库，用就是了。</li>
<li>然后就是把一些个人信息抽出来写在配置文件中。这里踩了一个坑。<code>data = {'op': 'login', 'user': user, 'password': password}</code>,我开始的时候是这样写的<code>data = f&quot;{{'op': 'login', 'user': {user}, 'password': {password}}}&quot;</code>。后者虽然在形式上看着一样，但前者是json对象，后者是字符串。这里也给我提了个醒：Python虽然有动态类型这个特性，但还是要注意类型错误。</li>
<li>最后是使用Github Action。之前也有使用过，但是是直接用的别人写好的workflow。所以也花了些时间学习了下。遇到的几个问题是
<ul>
<li>Yml文件的格式问题。这个可以用<a href="https://codebeautify.org/yaml-validator"  target="_blank" rel="noopener" >YAML Validator</a>来检查。Vscode应该也有相应的插件吧。</li>
<li>运行时需要用到的变量，是用的secret。我之前以为secret的value只能是字符串。但<a href="https://nekokiku.cn/2020/12/22/2020-12-22-Github-Action%E4%B8%ADpython%E8%8E%B7%E5%8F%96%E4%BB%93%E5%BA%93%E7%9A%84secrets/"  target="_blank" rel="noopener" >Github Action中python获取仓库的secrets</a>中提到，可以把一整个yml文件放在value里面。所以我就想那json文件应该也可以。试了下确实能行。这样我的代码需要修改的地方就很少了。</li>
<li>workflow的触发方式,要添加手动触发，需加上<code>workflow_dispatch:</code></li>
</ul>
</li>
</ol>
<h2 id="学到的知识">学到的知识</h2>
<ul>
<li>pipe和python的结合。下面这段是ChatGPT写的，太妙了。
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">SESSION</span><span class="o">=</span><span class="k">$(</span>curl -s -d <span class="s1">&#39;{&#34;op&#34;:&#34;login&#34;,&#34;user&#34;:&#34;user&#34;,&#34;password&#34;:&#34;password&#34;}&#39;</span> http://example.com/tt-rss/api/ <span class="p">|</span> python -c <span class="s2">&#34;import sys, json; print(json.load(sys.stdin)[&#39;content&#39;][&#39;session_id&#39;])&#34;</span><span class="k">)</span>
</span></span></code></pre></div></li>
<li>Github Action的使用</li>
<li>python request</li>
</ul>
<h2 id="尾巴">尾巴</h2>
<p>这个项目算是个很小的项目，但我还是花了半天的时间，而且是在ChatGPT的帮助下。之前看到这样一种说法，搜索引擎大幅降低了普通人获取知识的难度，而ChatGPT在此基础上更是降低了十分客观的一个量。结合自己这次的经历，我十分认同这个观点。通过我对背景的补充和提问，ChatGPT让我省去了花费在各种教程和不完善的文档上所要消费的时间。这比搜索引擎所做到的交互要更自然。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://tt-rss.org/wiki/ApiReference"  target="_blank" rel="noopener" >API Reference</a></li>
<li><a href="https://www.cnblogs.com/jiangleads/p/10636696.html"  target="_blank" rel="noopener" >curl命令实现上网认证登录</a></li>
<li><a href="https://nekokiku.cn/2020/12/22/2020-12-22-Github-Action%E4%B8%ADpython%E8%8E%B7%E5%8F%96%E4%BB%93%E5%BA%93%E7%9A%84secrets/"  target="_blank" rel="noopener" >Github Action中python获取仓库的secrets</a></li>
<li><a href="https://codebeautify.org/yaml-validator"  target="_blank" rel="noopener" >YAML Validator</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>扬州慢</title>
      <link>https://ds63.eu.org/2023/%E6%89%AC%E5%B7%9E%E6%85%A2/</link>
      <pubDate>Wed, 26 Apr 2023 18:34:32 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E6%89%AC%E5%B7%9E%E6%85%A2/</guid>
      <description>黄永玉先生为“入木——黄永玉百岁版画艺术展”所创作的画作。我看了觉得很是喜欢。摘录原文如下，及自己的一些感想。</description>
      <content:encoded><![CDATA[<h1 id="扬州慢">扬州慢</h1>
<p><strong>黄永玉先生为“入木——黄永玉百岁版画艺术展”所创作的画作。我看了觉得很是喜欢。摘录原文如下</strong></p>
<p>扬州慢。</p>
<p>淮左名都，竹西佳处，解鞍少驻初程。过春风十里，尽荠麦青青。自胡马窥江去后，废池乔木，犹厌言兵。渐黄昏，清角吹寒，都在空城。</p>
<p>杜郎俊赏，算而今，重到须惊。纵豆蔻词工，青楼梦好，难赋深情。二十四桥仍在，波心荡，冷月无声。念桥边红药，年年知为谁生？</p>
<p>钤印  认识的人越多，我就越喜欢狗（白文方印）</p>
<p>姜夔先生这阕词，不单评论了杜牧大师，并且还教育了我们一代代后人，也看透了社会的真情，所以我有时用不同的心情来画过它。多少年过去了，我居然也会老到快一百岁，好像还有好多事情还准备做。你看就那么兰约的完蛋，似乎连自己也对不起，好像也没有偷生的办法，好像写一点姜夔式的变文也办不到。（这难道很易？）写这劳骚，也只还不过多写几个字，讨主人的开心。我去过扬州，那是几十又几十年的事，在某个庙门口地摊上买到一部残之又残的傅青主的妇科刻本，回北京老书游子告诉我，傅山这刻本满地都是，不足取，等元宵节，我带你上厂甸要多少有多少。这事跟傅山无关，跟扬州无关，我只是交待一次我去过一回扬州。</p>
<p>钤印  黄（朱文圆印）</p>
<p>我还真附庸风雅去找过二十四桥，照姜先生口气，应该不是扬州所有桥的排列顺序，说“仍在”，起码应从杜先生那时候算起。“波心荡，冷月无声”，是姜先生感觉的回应，那桥在哪里呢？有人说在此，有人说在彼，我真跟着他和她们狠狠走了一趟临河的一条小街，几位街坊妇女在做针线，别说二十四桥，北京普通话也听不懂，大家沿河兜头一看，连二十四桥桥基都捉摸不到。唉！世界愚如我的真是不少，对着苍茫，着了多少笔墨，真是不计其数。夔先生自己也着了不少道，他是公认的曲牌的创作名家，好不容易一辈子混了个“乐正”似的官，上午上任，要摆点威武，命令濏官“奏”来听听，出口就错，原来瑟官动手叫“鼓”不叫“奏”，一汇报，马上下台。我仿佛记得以前有段笑话，把立体派、印象派和现代派混在一起演讲，有如把黄人、白人和“人类”混为一起，讲的当时没人敢站出来揭错的，谁都清楚，这是学术“问题”，谁也都清楚，这不是学术“后果”。时间过去近百年，写出来给大家看看，或许当时某位先生还未出世，不相信这事真有其事，说我把谎话当真话讲的，莫怪莫怪！</p>
<p>钤印  椿子（朱文扁方印）</p>
<p>大运河博物馆惠存。二〇二三年三月二十七日，黄永玉九十九岁于北京。</p>
<p>钤印  黄永玉（白文方印）、九五火眼金睛（朱文椭圆印）</p>
<h2 id="感受">感受</h2>
<p>提到扬州，我第一印象当属姜夔这阕《扬州慢》。来的路上，我也默诵这阙词。</p>
<p>荷花，我中学的美术课画过。我画得不好，所以知道不容易画。但百岁高龄，能画出这荷花，写这么多字。我觉得更是不易。</p>
<p>关于画上的字，我觉得也不错。尤其是内容。我觉得颇有种“从心所欲不逾矩”的感觉。记录几点：</p>
<ul>
<li>“不单评论了杜牧大师，并且还教育了我们一代代后人，也看透了社会的真情”。这里我读不出来。应该是阅历未到。</li>
<li>“我只是交待一次我去过一回扬州。”。很有趣。</li>
<li>“我还真附庸风雅去找过二十四桥”。本来觉得附庸风雅不是什么好词，但黄先生用来就显得风趣。我也喜欢干类似的事，特意去一些曾在诗中读过的地名走走，哪怕物是人非。</li>
<li>“唉！世界愚如我的真是不少”。 谦虚</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>xLog使用体验</title>
      <link>https://ds63.eu.org/2023/xlog%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C/</link>
      <pubDate>Thu, 20 Apr 2023 01:15:48 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/xlog%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C/</guid>
      <description>记录xLog的使用体验</description>
      <content:encoded><![CDATA[<p><em><a href="https://xlog.app/"  target="_blank" rel="noopener" >xLog</a>这个开源博客社区，由于<a href="https://github.com/DIYgod/RSSHub"  target="_blank" rel="noopener" >RSSHub</a>的作者的宣传，我前段时间就有听闻。。但我一直认同这样一种想法：&ldquo;一个博客的死掉不是不再更新，而是无法访问。&ldquo;而xLog毕竟是一个比较新的事物，无法保证其的可持续性，所以就一直没有使用的想法。</em></p>
<h2 id="缘起">缘起</h2>
<p>但今天听了一个<a href="https://xinbao.xlog.app/27"  target="_blank" rel="noopener" >No.27 和 Qwerty Learner 的开翼聊技术优化、产品运营和前端感悟</a>，我觉得讲得很好，看到它发布的平台有xLog。所以心念一转，想着去尝试一下，就当作一个备份也无妨。使用体验有几点值得一提：</p>
<h2 id="实际体验">实际体验</h2>
<ul>
<li>如其宣传的一样，上手很容易。连接web3钱包和邮件后，我再导入自己已有的md文件就能搭一个博客。我觉得很不错。</li>
<li>提供的编辑器对我来说算是锦上添花。因为我比较习惯于在vscode上进行编辑。</li>
<li>ai智能摘要。我还是更倾向于自己手动去写摘要。但好像xLog它无法识别我原有的<code>summary:T</code>，但其他的属性:<code>date:</code>,<code>tags:</code>,<code>title:</code>倒是有支持。+08:00</li>
<li>web3。相比较于其他的博客社区，web3是xLog一大特点。这个概念提出来也是有段时间了，但对我来说还是比较新的。这次xLog使用时我第一次去接触这方面的内容。好多概念我觉得都挺有趣的，我觉得应该找时间去了解下是怎么实现的。</li>
<li>社区。 因为是社区，这就意味着可能有更多的人会看到。都说写博客是为了自己看的，但如果有更多的人能看到自己的一些想法，那也不错。但我不想让自己陷入到这样一种情况：我因为太过于关注浏览量，点赞数等数据，然后却失去了自己写博客的初衷（关于初衷是什么，我想我会写一篇来好好思考下），那就得不偿失了。</li>
</ul>
<h2 id="尾巴">尾巴</h2>
<p>我以前写博客一般是这样的过程。</p>
<ol>
<li>有感想，然后记录下来，存在本地。</li>
<li>有空的时候会找时间，去从本地中的感想中挑选一些可以作为博文的。并对其进行稍微的修改（润色，脱敏），发布到<a href="https://euds63.github.io/"  target="_blank" rel="noopener" >euds63.github.io</a>上。</li>
</ol>
<p>但现在如果要在<a href="https://erica-2392.xlog.app/"  target="_blank" rel="noopener" >EuDs</a>也更新的话，那就还需要第三步。
3. 手动导入到xLog上</p>
<p>三个步骤中，第一二步是没法减掉的。而且<a href="https://euds63.github.io/"  target="_blank" rel="noopener" >euds63.github.io</a>的更新我觉得还是会作为我的博客主要托管站。而第三步，工作量虽然不是太大，但终究还是有点麻烦。所以我现在的想法是可以将第三步和第二步合并。不知道有没有相关的接口。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>感兴趣的知识/待细看</title>
      <link>https://ds63.eu.org/2023/things-i-am-interested-in/</link>
      <pubDate>Sun, 16 Apr 2023 16:03:44 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2023/things-i-am-interested-in/</guid>
      <description>记录我感兴趣的知识或者说需要细看的内容</description>
      <content:encoded><![CDATA[<p><em>有些知识，我觉得有趣，平时也还算经常看到，但只是一知半解，所以下定决心要将其掌握。我觉得要掌握一个知识，有一个比较好的办法就是写个教程，让不知道的人看了教程后也能对这个知识有相当的了解。所谓教学相长也。又因为知之甚少而难以开一篇专门去叙述，所以权记录于此，作为备忘</em></p>
<p><em>网上冲浪的时候，或主动或被动，常会看到些我感兴趣的内容。有的时候是内容比较深，有的时候是内容让我有些感想。常常，我会选择不关闭它们，想着有时间一定要好好看，并记录下自己的感想。然后&hellip;通常就没有然后了。这并不是件好事。所以我就想着记录在这里，也算是对自己的一种监督，或者说Learn In Public。</em></p>
<h2 id="区块链">区块链</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://mp.weixin.qq.com/s/wEzbgXh1BDxYjz-xkHs0Gg"  target="_blank" rel="noopener" >匿名是一种设计</a></li>
<li><input disabled="" type="checkbox"> <a href="https://bitcoin.org/bitcoin.pdf"  target="_blank" rel="noopener" >Bitcoin: A Peer-to-Peer Electronic Cash System</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/Ice-Storm/structure-and-interpretation-of-blockchain/blob/master/0_0.md"  target="_blank" rel="noopener" >structure-and-interpretation-of-blockchain/0_0.md at master · Ice-Storm/structure-and-interpretation-of-blockchain</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://taresky.com/crypto-arbitrage"  target="_blank" rel="noopener" >无风险年化 360%？小白也能懂的 Crypto 套利 - TARESKY</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.laisky.com/p/web3-101/?lang=zh"  target="_blank" rel="noopener" >面向 Web2 工程师的区块链入门</a></li>
<li><input disabled="" type="checkbox"> <a href="https://liaoxuefeng.com/books/blockchain/bitcoin/hd-wallet/mnemonic/index.html"  target="_blank" rel="noopener" >助记词 - 区块链教程 - 廖雪峰的官方网站</a></li>
</ul>
<hr>
<h2 id="加密">加密</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://program-think.blogspot.com/2010/02/introduce-digital-certificate-and-ca.html#verify_file"  target="_blank" rel="noopener" >数字证书及 CA 的扫盲介绍</a></li>
<li><input disabled="" type="checkbox"> <a href="https://jysperm.me/2017/09/gpg-and-e2ee/"  target="_blank" rel="noopener" >GPG 与端到端加密：论什么才是可以信任的</a></li>
<li><input disabled="" type="checkbox"> <a href="https://cryptopals.com/"  target="_blank" rel="noopener" >The Cryptopals Crypto Challenges</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://developer.aliyun.com/article/1043064"  target="_blank" rel="noopener" >加盐密码哈希：如何正确使用-阿里云开发者社区</a></li>
</ul>
<hr>
<h2 id="gpt">GPT</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://viper.cs.columbia.edu/"  target="_blank" rel="noopener" >ViperGPT: Visual Inference via Python Execution for Reasoning</a></li>
<li><input disabled="" type="checkbox"> <a href="https://arxiv.org/abs/2304.03442"  target="_blank" rel="noopener" >Generative Agents: Interactive Simulacra of Human Behavior</a></li>
<li><input disabled="" type="checkbox"> <a href="https://ig.ft.com/generative-ai/"  target="_blank" rel="noopener" >Generative AI exists because of the transformer</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.laisky.com/p/what-is-gpt/?lang=zh"  target="_blank" rel="noopener" >What is GPT and Why Does It Work?</a></li>
<li><input disabled="" type="checkbox"> <a href="https://bigeagle.me/2023/03/llm-is-compression/"  target="_blank" rel="noopener" >为什么说 GPT 是无损压缩 | K.I.S.S</a></li>
<li><input disabled="" type="checkbox"> <a href="https://bigeagle.me/2023/03/pico-gpt-1/"  target="_blank" rel="noopener" >握着你的手训一个类GPT语言模型 (一) | K.I.S.S</a></li>
</ul>
<hr>
<h2 id="neural-network">Neural Network</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://zhuanlan.zhihu.com/p/104475016"  target="_blank" rel="noopener" >[干货]深入浅出LSTM及其Python代码实现</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.cnblogs.com/subconscious/p/5058741.html"  target="_blank" rel="noopener" >神经网络浅讲：从神经元到深度学习</a></li>
<li><input disabled="" type="checkbox"> <a href="https://program-think.blogspot.com/2020/11/Game-Theory.html"  target="_blank" rel="noopener" >博弈论入门教程——从基本概念到具体案例 @ 编程随想的博客</a></li>
<li><input disabled="" type="checkbox"> <a href="https://course.fast.ai/"  target="_blank" rel="noopener" >Practical Deep Learning for Coders - Practical Deep Learning</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.orangex4.workers.dev/post/simple-pinyin/"  target="_blank" rel="noopener" >基于 HMM 隐马尔可夫模型的智能拼音输入法 (带 Web 前端) | OrangeX4&rsquo;s Blog</a></li>
</ul>
<hr>
<h2 id="博客">博客</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://luolei.org/gfw/"  target="_blank" rel="noopener" >GFW之父方滨兴讲座后杂想</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://lutaonan.com/blog/reason-why-your-blog-is-not-alive/"  target="_blank" rel="noopener" >为什么无法坚持写博客</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://plumz.me/archives/12906/"  target="_blank" rel="noopener" >你所热爱的，就是你的生活</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.zxch3n.com/local-first/"  target="_blank" rel="noopener" >译：本地优先软件 Local-first software</a></li>
<li><input disabled="" type="checkbox"> <a href="https://densecollections.top/posts/4074/"  target="_blank" rel="noopener" >MIT计算机科学课堂中学不到的知识</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/XXIIVV/webring"  target="_blank" rel="noopener" >XXIIVV/webring</a></li>
</ul>
<hr>
<h2 id="开源">开源</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://github.com/zloirock/core-js/blob/master/docs/2023-02-14-so-whats-next.md"  target="_blank" rel="noopener" >So, what&rsquo;s next?</a></li>
<li><input disabled="" type="checkbox"> <a href="https://juejin.cn/post/7272735633458413602"  target="_blank" rel="noopener" >开源富文本编辑器 wangEditor 暂停维护 （但仍可继续使用） - 掘金</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://www.eaimty.com/2023/opensource-project-based-on-hormone/"  target="_blank" rel="noopener" >基于荷尔蒙开发的开源项目 - EAimTY&rsquo;s Blog</a></li>
<li><input disabled="" type="checkbox"> <a href="https://tw93.fun/2023-09-18/open.html"  target="_blank" rel="noopener" >该以一种怎么样的心态来对待开源 - Tw93</a></li>
<li><input disabled="" type="checkbox"> <a href="https://pragdave.me/thoughts/active/2023-09-21-in-praise-of-maintainers.html"  target="_blank" rel="noopener" >pragdave - In Praise of Maintainers</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://yunyoujun.cn/posts/the-birth-of-yunlefun"  target="_blank" rel="noopener" >云乐坊工作室的成立与缘起与有关的话 - 云游君的小站</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.tisonkun.org/2021/12/05/effective-open-source-participant/"  target="_blank" rel="noopener" >高效参与开源的诀窍 | 夜天之书</a></li>
</ul>
<hr>
<h2 id="网络">网络</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://plantegg.github.io/2019/05/15/%E5%B0%B1%E6%98%AF%E8%A6%81%E4%BD%A0%E6%87%82%E7%BD%91%E7%BB%9C--%E4%B8%80%E4%B8%AA%E7%BD%91%E7%BB%9C%E5%8C%85%E7%9A%84%E6%97%85%E7%A8%8B/"  target="_blank" rel="noopener" >就是要你懂网络&ndash;一个网络包的旅程</a></li>
<li><input disabled="" type="checkbox"> <a href="https://gfw.report/publications/usenixsecurity23/zh/"  target="_blank" rel="noopener" >中国的防火长城是如何检测和封锁完全加密流量的</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://www.iserica.com/posts/network101-socket-function-wrappers/"  target="_blank" rel="noopener" >「网络编程101」来封装一个简单的TCP服务吧！</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.yoitsu.moe/security/web_server_configuration_0.html"  target="_blank" rel="noopener" >如何比较安全的配置 Web 服务器 - TLS 和 HTTPS - 约伊兹的萌狼乡手札</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.laisky.com/p/https-in-action/"  target="_blank" rel="noopener" >HTTPS 隐私安全的一些实践</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.kawabangga.com/posts/5301"  target="_blank" rel="noopener" >四层负载均衡漫谈 | 卡瓦邦噶！</a></li>
<li><input disabled="" type="checkbox"> <a href="https://plantegg.github.io/2019/06/02/%E5%8F%B2%E4%B8%8A%E6%9C%80%E5%85%A8_SSH_%E6%9A%97%E9%BB%91%E6%8A%80%E5%B7%A7%E8%AF%A6%E8%A7%A3--%E6%94%B6%E8%97%8F%E4%BF%9D%E5%B9%B3%E5%AE%89/"  target="_blank" rel="noopener" >史上最全 SSH 暗黑技巧详解 | plantegg</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.edu.cn/xxh/zt/tj/202310/t20231019_2521709.shtml"  target="_blank" rel="noopener" >网络层和传输层技术演变 ——25年后的互联网（二）-中国教育和科研计算机网CERNET</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.laisky.com/p/tailscale-nat/?lang=zh"  target="_blank" rel="noopener" >TailScale NAT 技术简介和个人组网方案</a></li>
<li><input disabled="" type="checkbox"> <a href="https://wiyi.org/socks5-protocol-in-deep.html"  target="_blank" rel="noopener" >理解socks5协议的工作过程和协议细节 | Bigbyto</a></li>
<li><input disabled="" type="checkbox"> <a href="https://socket.io/docs/v4/tutorial/introduction"  target="_blank" rel="noopener" >Tutorial - Introduction | Socket.IO</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.alswl.com/2017/09/https-on-stack-overflow/"  target="_blank" rel="noopener" >Stack Overflow 的 HTTPS 化：漫漫长路的终点 | Log4D</a></li>
</ul>
<hr>
<h2 id="前端">前端</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://xlog.daidr.me/card-page"  target="_blank" rel="noopener" >写一个炫酷的个人名片页</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/"  target="_blank" rel="noopener" >An Interactive Guide to Flexbox</a></li>
<li><input disabled="" type="checkbox"> <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks"  target="_blank" rel="noopener" >CSS 构建</a></li>
<li><input disabled="" type="checkbox"> <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API"  target="_blank" rel="noopener" >WebGL: 2D and 3D graphics for the web - Web APIs | MDN</a></li>
<li><input disabled="" type="checkbox"> <a href="https://yzyyz.top/archives/js_snake.html"  target="_blank" rel="noopener" >JS初探，给博客首页添加一个贪吃蛇热力图</a></li>
<li><input disabled="" type="checkbox"> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction"  target="_blank" rel="noopener" >Introduction to the DOM - Web APIs | MDN</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html"  target="_blank" rel="noopener" >Flex 布局教程：语法篇 - 阮一峰的网络日志</a></li>
<li><input disabled="" type="checkbox"> <a href="https://pptr.dev/"  target="_blank" rel="noopener" >Puppeteer | Puppeteer</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/JLHwung/hexo-offline"  target="_blank" rel="noopener" >JLHwung/hexo-offline: Out-of-the-box hexo offline experience</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/reactwg/server-components/discussions/5"  target="_blank" rel="noopener" >RSC From Scratch. Part 1: Server Components · reactwg/server-components · Discussion #5</a></li>
<li><input disabled="" type="checkbox"> <a href="https://vercel.com/blog/understanding-react-server-components"  target="_blank" rel="noopener" >Understanding React Server Components - Vercel</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/microsoft/react-native-windows"  target="_blank" rel="noopener" >microsoft/react-native-windows: A framework for building native Windows apps with React.</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.nowcoder.com/feed/main/detail/a79cb52ce00c4f6d874683e65b8eb718?sourceSSR=users"  target="_blank" rel="noopener" >70场面试，复盘我遇到的有趣问题（一）_牛客网</a></li>
</ul>
<hr>
<h2 id="linux">Linux</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://mutur4.github.io/posts/linux-malware-development/edr/"  target="_blank" rel="noopener" >Linux Malware: Defense Evasion Techniques ·</a></li>
<li><input disabled="" type="checkbox"> <a href="https://bootlin.com/blog/multi-queue-improvements-in-linux-kernel-ethernet-mvneta/"  target="_blank" rel="noopener" >Multi-queue improvements in Linux kernel Ethernet driver mvneta - Bootlin&rsquo;s blog</a></li>
<li><input disabled="" type="checkbox"> <a href="https://man7.org/tlpi/"  target="_blank" rel="noopener" >The Linux Programming Interface</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://fdgkhdkgh.medium.com/linux-lkmpg-%E7%B2%97%E6%B7%BA%E7%AD%86%E8%A8%98-2-system-call-284b347194eb"  target="_blank" rel="noopener" >Linux : lkmpg 粗淺筆記 (2) — system call | by 吳建興 | Medium</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://www.wiz.io/blog/linux-rootkits-explained-part-2-loadable-kernel-modules"  target="_blank" rel="noopener" >Linux rootkits explained – Part 2: Loadable kernel modules | Wiz Blog</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234"  target="_blank" rel="noopener" >Writing a Simple Linux Kernel Module | by Robert W. Oliver II | Sourcerer Blog</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://xcellerator.github.io/posts/linux_rootkits_02/"  target="_blank" rel="noopener" >Linux Rootkits Part 2: Ftrace and Function Hooking :: TheXcellerator</a></li>
<li><input disabled="" type="checkbox"> <a href="https://coolshell.cn/articles/22320.html"  target="_blank" rel="noopener" >eBPF 介绍 | 酷 壳 - CoolShell</a></li>
<li><input disabled="" type="checkbox"> <a href="https://tzssangglass.github.io/posts/exploring-the-ebpf-source-code-tour/"  target="_blank" rel="noopener" >探索 eBPF 源码之旅 | tzssangglass blog</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://blog.dreamfever.me/posts/2023-10-24-how-to-debug-01-syscall/"  target="_blank" rel="noopener" >新人也能懂的调试方法 01 - 通过 syscall 进行定位 · Hanaasagi - (ゝω·)~ kira</a></li>
<li><input disabled="" type="checkbox"> <a href="https://os.phil-opp.com/"  target="_blank" rel="noopener" >Writing an OS in Rust</a></li>
<li><input disabled="" type="checkbox"> <a href="https://mazzo.li/posts/fast-pipes.html"  target="_blank" rel="noopener" >How fast are Linux pipes anyway?</a></li>
</ul>
<hr>
<h2 id="手工">手工</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://freemind.pluskid.org/electronics/5x12-keyboard-debugging2/"  target="_blank" rel="noopener" >记一次有意义的熬夜</a> 机械键盘</li>
<li><input disabled="" type="checkbox"> <a href="https://andelf.github.io/blog/2021/01/14/play-with-2-13-inch-e-ink-display/"  target="_blank" rel="noopener" >Play with 2.13 inch E-Ink display | 猫·仁波切</a> 墨水屏</li>
<li><input disabled="" type="checkbox"> <a href="https://andelf.github.io/blog/2023/12/17/10-2-inch-3-color-esl/"  target="_blank" rel="noopener" >10.2 寸黑白红三色墨水屏价签拆解及驱动过程简记 - 10.2 inch 3-Color BWR ESL | 猫·仁波切</a> 墨水屏*2</li>
</ul>
<hr>
<h2 id="编程语言">编程语言</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://blog.icrystal.top/archives/1.html"  target="_blank" rel="noopener" >个人C++编程规范总结 - iC Blog</a></li>
<li><input disabled="" type="checkbox"> <a href="https://gobyexample.com/"  target="_blank" rel="noopener" >Go by Example</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/chinesehuazhou/python-whydo"  target="_blank" rel="noopener" >chinesehuazhou/python-whydo: Explore Python&rsquo;s charms by asking WHY questions</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://mp.weixin.qq.com/s/co_OAaVQ49rPfgoAh6Pejw"  target="_blank" rel="noopener" >Python 中 -m 的典型用法、原理解析与发展演变</a></li>
<li><input disabled="" type="checkbox"> <a href="https://doc.rust-lang.org/cargo/reference/config.html"  target="_blank" rel="noopener" >Configuration - The Cargo Book</a></li>
<li><input disabled="" type="checkbox"> <a href="https://mp.weixin.qq.com/s?__biz=MzUyOTk2MTcwNg==&amp;mid=2247484801&amp;idx=1&amp;sn=c0f55df74fa3a2d438309e959100325e"  target="_blank" rel="noopener" >深入探讨 Python 的 import 机制：实现远程导入模块</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/MrBeanCpp/MIT"  target="_blank" rel="noopener" >MrBeanCpp/MIT: Mini-Git in Rust. 用Rust实现的简易Git</a></li>
<li><input disabled="" type="checkbox"> <a href="https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/"  target="_blank" rel="noopener" >Introduction · 函数式编程指北</a></li>
</ul>
<hr>
<h2 id="数学">数学</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://zhuanlan.zhihu.com/p/145975481"  target="_blank" rel="noopener" >会做数学证明的“忙碌海狸”，以及比TREE(3)还大的“不可计算数” - 知乎</a></li>
<li><input disabled="" type="checkbox"> <a href="https://zh.wikipedia.org/wiki/%E5%BF%99%E7%A2%8C%E7%9A%84%E6%B5%B7%E7%8B%B8"  target="_blank" rel="noopener" >忙碌的海狸 - 维基百科，自由的百科全书</a></li>
<li><input disabled="" type="checkbox"> <a href="https://dalaoliblog.wordpress.com/2020/12/17/%E5%BF%99%E7%A2%8C%E6%B5%B7%E7%8B%B8%E5%87%BD%E6%95%B0-bb1%E5%88%B0bb5%E7%9A%84%E5%80%BC%E6%98%AF%E6%80%8E%E4%B9%88%E8%AE%A1%E7%AE%97%E7%9A%84/"  target="_blank" rel="noopener" >“忙碌海狸函数”-BB(1)到BB(5)的值是怎么计算的 – 大老李聊数学</a></li>
</ul>
<hr>
<h2 id="代理">代理</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://www.cnblogs.com/newcats/p/16124158.html"  target="_blank" rel="noopener" >使用Frp内网穿透实现远程桌面(家里电脑远程控制公司电脑) - Newcats - 博客园</a></li>
<li><input disabled="" type="checkbox"> <a href="https://tailscale.com/"  target="_blank" rel="noopener" >Tailscale · Best VPN Service for Secure Networks</a></li>
<li><input disabled="" type="checkbox"> <a href="https://tailscale.com/"  target="_blank" rel="noopener" >Tailscale · Best VPN Service for Secure Networks</a></li>
<li><input disabled="" type="checkbox"> <a href="https://akynazh.site/posts/2024/02/a-simple-tutorial-on-building-private-proxy-services/"  target="_blank" rel="noopener" >搭建私人代理服务简易教程 | Norwegian Wood</a></li>
<li><input disabled="" type="checkbox"> <a href="https://gofrp.org/zh-cn/"  target="_blank" rel="noopener" >frp</a></li>
<li><input disabled="" type="checkbox"> <a href="https://victrid.dev/2021/pei-zhi-tou-ming-dai-li-shi-xian-wu-gan-shang-wang/"  target="_blank" rel="noopener" >配置透明代理，实现无感上网 | Victrid&rsquo;s Personal Site</a></li>
</ul>
<h2 id="杂">杂</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://www.physics.umd.edu/courses/Phys606/spring_2011/einstein_electrodynamics_of_moving_bodies.pdf"  target="_blank" rel="noopener" >ON THE ELECTRODYNAMICS OF MOVINGBODIES</a></li>
<li><input disabled="" type="checkbox"> <a href="https://en.wikipedia.org/wiki/Theory_of_mind"  target="_blank" rel="noopener" >Theory of mind</a></li>
<li><input disabled="" type="checkbox"> <a href="https://sites.cs.ucsb.edu/~lingqi/teaching/games101.html"  target="_blank" rel="noopener" >GAMES101: 现代计算机图形学入门</a></li>
<li><input disabled="" type="checkbox"> <a href="https://missing-semester-cn.github.io/"  target="_blank" rel="noopener" >The Missing Semester of Your CS Education</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/When-Brains-Dream-Exploring-Science/dp/1324002832"  target="_blank" rel="noopener" >When Brains Dream: Exploring the science and mystery of sleep</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.kivinsae.com/2023/05/17/2023-05-17-no_sophism/"  target="_blank" rel="noopener" >关于 初码先生 某推中典型诡辩论部分的拆解</a>
学习下辩论技巧</li>
<li><input disabled="" type="checkbox"> <a href="https://seuite.github.io/blog/2019-04/%E7%BC%96%E7%A8%8B%E8%AD%A6%E5%8F%A5-1301-30/"  target="_blank" rel="noopener" >编程警句 130（1-30）</a> 有趣的句子</li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/"  target="_blank" rel="noopener" >In a git repository, where do your files live?</a> 易懂而有趣</li>
<li><input disabled="" type="checkbox"> <a href="https://guyinatuxedo.github.io/index.html"  target="_blank" rel="noopener" >Nightmare - Nightmare</a></li>
<li><input disabled="" type="checkbox"> <a href="https://program-think.blogspot.com/2020/11/Game-Theory.html"  target="_blank" rel="noopener" >博弈论入门教程——从基本概念到具体案例 @ 编程随想的博客</a></li>
<li><input disabled="" type="checkbox"> <a href="https://dl.acm.org/doi/pdf/10.1145/99370.99404"  target="_blank" rel="noopener" >Theorems for free! </a></li>
<li><input disabled="" type="checkbox"> <a href="https://robertheaton.com/2018/12/08/programming-projects-for-advanced-beginners/"  target="_blank" rel="noopener" >Programming Projects for Advanced Beginners | Robert Heaton</a></li>
<li><input disabled="" type="checkbox"> <a href="https://webgl2fundamentals.org/webgl/lessons/zh_cn/"  target="_blank" rel="noopener" >WebGL2 理论基础</a></li>
<li><input disabled="" type="checkbox"> <a href="https://redisbook.readthedocs.io/en/latest/"  target="_blank" rel="noopener" >Redis 设计与实现（第一版） — Redis 设计与实现</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://yufan.me/basic-terms-in-book-binding/"  target="_blank" rel="noopener" >不可不知的图书装帧术语 - 且听书吟</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://github.com/freedom-introvert/Research-on-Avalon-System-in-Bilibili-Comment-Area/blob/main/docs/%E6%B7%B1%E6%8C%96b%E7%AB%99%E5%A6%82%E4%BD%95%E6%8E%A7%E8%AF%84-%E5%AF%B9%E9%98%BF%E7%93%A6%E9%9A%86%E7%B3%BB%E7%BB%9F%E6%8E%A2%E7%A9%B6.md"  target="_blank" rel="noopener" >深挖b站如何控评-对阿瓦隆系统探究</a></li>
<li><input disabled="" type="checkbox"> <a href="https://blog.fleeto.us/post/auto-build-with-github-action/"  target="_blank" rel="noopener" >用 Github Action 自动发布二进制包 | 伪架构师</a></li>
<li><input disabled="" type="checkbox"> <a href="https://skyzh.github.io/write-you-a-vector-db/00-introduction.html?search="  target="_blank" rel="noopener" >Introduction - Write You a Vector Database</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://hellogithub2014.github.io/2019/08/05/qr-code-theory/"  target="_blank" rel="noopener" >二维码原理 | 十年一刻</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://tonsky.me/blog/unicode/"  target="_blank" rel="noopener" >The Absolute Minimum Every Software Developer Must Know About Unicode in 2023 (Still No Excuses!) @ tonsky.me</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.biorxiv.org/content/10.1101/2022.11.18.517004v2.full.pdf"  target="_blank" rel="noopener" >High-resolution image reconstruction with latent diffusion models from humanbrain activity</a></li>
<li><input disabled="" type="checkbox"> <a href="https://github.com/fzxa/VSCode-sourcecode-analysis"  target="_blank" rel="noopener" >fzxa/VSCode-sourcecode-analysis: 微软VSCode IDE源码分析：VSCode是一个运行于 Mac OS X、Windows和 Linux 之上的，针对于编写现代 Web 和云应用的跨平台源代码编辑器。 采用Electron (JavaScript, HTML 和 CSS 等 Web 技术) 创建原生程序的框架。</a></li>
<li><input disabled="" type="checkbox"> <a href="https://huangxin.dev/partly-technical/run-cmd-as-admin-with-one-command-under-windows"  target="_blank" rel="noopener" >Windows 下一键以管理员命令运行命令提示符 - 惶心博客</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www.rabbitmq.com/"  target="_blank" rel="noopener" >RabbitMQ: One broker to queue them all | RabbitMQ</a></li>
<li><input disabled="" type="checkbox"> <a href="https://kafka.apache.org/"  target="_blank" rel="noopener" >Apache Kafka</a></li>
<li><input disabled="" type="checkbox"> <a href="https://zh.wikipedia.org/wiki/ISO_3166-1%E4%BA%8C%E4%BD%8D%E5%AD%97%E6%AF%8D%E4%BB%A3%E7%A0%81"  target="_blank" rel="noopener" >ISO 3166-1二位字母代码 - 维基百科，自由的百科全书</a></li>
<li><input disabled="" type="checkbox"> <a href="https://www2.jpfbj.cn/irodori/index.php"  target="_blank" rel="noopener" >TOP | IRODOR：生活中的日语</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>I Strove with None</title>
      <link>https://ds63.eu.org/2023/i-strove-with-none/</link>
      <pubDate>Mon, 10 Apr 2023 20:44:40 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/i-strove-with-none/</guid>
      <description>我和谁都不争</description>
      <content:encoded><![CDATA[<h2 id="原文------walter-landor">原文    &ndash;Walter Landor</h2>
<p>I strove with none ,</p>
<p>for none was worth my strife ;</p>
<p>Nature I lov&rsquo;d ,</p>
<p>and next to Nature , Art:</p>
<p>I warmed both hands before the fire of Life;</p>
<p>It sinks; and I am ready to depart .</p>
<h2 id="杨绛译本">杨绛译本：</h2>
<p>我和谁都不争，</p>
<p>和谁争我都不屑；</p>
<p>我爱大自然，</p>
<p>其次是艺术；</p>
<p>我双手烤着，</p>
<p>生命之火取暖；</p>
<p>火萎了，</p>
<p>我也准备走了。</p>
<h2 id="王佐良译本">王佐良译本：</h2>
<p>不与人争，</p>
<p>也无人值得我争，</p>
<p>爱的是自然，</p>
<p>其次是艺术。</p>
<p>生命之火前我把双手烤烘，</p>
<p>火焰低落了，</p>
<p>我准备离去。</p>
<h2 id="一些感受">一些感受</h2>
<p>读《刀锋》的时候看到这首诗，但有种似曾相识的感觉，应该不是第一次读到了。书中出现这首诗是艾略特在谈到自己的死亡时引用的。关于艾略特，关于《刀锋》，我想我会另写一篇。这里主要谈谈对这首诗和其译本的一些感受。</p>
<p>我蛮佩服，也欣赏诗中所描述的这种心境。我有时候会提醒自己，没必要去和别人去争。但我也记得自己在哪处看到过这样的一句话，“人是靠自我认同活着的”。类似这种句式的论断很多，但唯独这句我倒是记得很清楚。而要获取自我认同，常常是要靠与他人若有若无，有意无意的比较所获得的。至少现在的我是这样的。我觉得这并不好。所以自己还有待提高。</p>
<p>除了心境，我还喜欢这个比喻。<code>I warmed both hadns before the fire of life.</code></p>
<p>而上面所摘录的两种译本，我更喜欢杨绛的译本，尤其是<code>火萎了</code>这一句。我觉得译出了生命逝去的倏忽即逝。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>读《Harry Potter》</title>
      <link>https://ds63.eu.org/2023/%E8%AF%BBharry-potter/</link>
      <pubDate>Mon, 03 Apr 2023 00:42:19 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E8%AF%BBharry-potter/</guid>
      <description>我做过的最棒的一个梦之一就是我在上飞行课，我骑着扫帚飞过城市。</description>
      <content:encoded><![CDATA[<h2 id="4月2日1点16分">4月2日1点16分</h2>
<p>读到了最后一章，决定把它留到第二天再看</p>
<h2 id="4月19日">4月19日</h2>
<p>作为一个读者，我认为《哈利波特》最棒的一个地方是它构建了一个真实的魔法世界。</p>
<p>我做过的最棒的一个梦之一就是我在上飞行课，我骑着扫帚飞过城市。</p>
<h2 id="5月18日">5月18日</h2>
<p>哈利波特对我的魅力有一点在于：</p>
<p>我可以被其中的情感所打动。</p>
<p>当布莱克和波特说他们可以住一起时，是这样描述的：
“你疯了吗？”哈利说，声音一下子嘶哑了，和布莱克的意义。“我当然想要离开徳思礼家！你有了房子吗？我什么是能搬进去？”</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>表单学习</title>
      <link>https://ds63.eu.org/2023/learn_form/</link>
      <pubDate>Thu, 30 Mar 2023 23:52:16 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/learn_form/</guid>
      <description>发现原来表单要做得符合直觉也是有些学问在里面的，遂记录如下。</description>
      <content:encoded><![CDATA[<p><strong>偶然间看到了篇不错的文档，<a href="https://www.chromium.org/developers/design-documents/create-amazing-password-forms/"  target="_blank" rel="noopener" >Create Amazing Password Forms</a>,才发现原来表单要做得符合直觉也是有些学问在里面的，遂记录如下。</strong></p>
<h2 id="group-related-fields-in-a-single-form">Group related fields in a single form</h2>
<p>我之前习惯把注册和登录分开来做，使用的不少网站也是这样。</p>
<p>但这会产生这样一种情况:即使开启了浏览器的密码自动保存，往往注册完后的第一次登录，还得再输一遍代码。</p>
<p>我还不知道具体要怎么设计才能使其更合理。</p>
<h2 id="use-autocomplete-attributes">Use autocomplete attributes</h2>
<p><code>autocomplete</code>这个属性我还是第一次见，查阅文档后，发现是HTML5新增的属性。具体参见<a href="https://www.chromium.org/developers/design-documents/form-styles-that-chromium-understands/"  target="_blank" rel="noopener" >Password Form Styles that Chromium Understands</a>。以下是一些示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">   <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">bc</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&#34;section-home homeAddress&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&#34;username&#34;</span><span class="p">&gt;</span> 
</span></span><span class="line"><span class="cl">   <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&#34;current-password&#34;</span><span class="p">&gt;</span> 
</span></span><span class="line"><span class="cl">   <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;Sign In!&#34;</span><span class="p">&gt;</span> 
</span></span></code></pre></div><p>那<code>autocomplete</code>和<code>autofill</code>有什么区别呢：</p>
<p>我查了下有这样的回答</p>
<ul>
<li><code>autocomplete</code>用于指定浏览器是否应该启用表单自动完成功能，以及提供有关字段中预期信息类型的指导。</li>
<li><code>autofill</code>是浏览器自带的自动填充功能，它会根据用户之前输入过的值来预测用户下一次可能输入的值，并在用户输入时自动填充。<code>autofill</code>不仅考虑了之前输入过的值，还考虑了字段的含义和结构。例如，Google Chrome实现了解析输入字段以猜测其类型和结构。</li>
</ul>
<p>目前我的理解是:<code>autocomplete</code>用来提示浏览器字段的类型，而<code>autofill</code>用来控制是否使用该功能。</p>
<h2 id="use-hidden-fields-for-implicit-information">Use hidden fields for implicit information</h2>
<p>这点对于我来说也是挺新鲜的。才知道尽管有些信息没必要让用户输入，但还是有必要在表单中所包含，以便于密码管理器。</p>
<p>文档中是这样讲的:</p>
<blockquote>
<p>the user agent is allowed to provide the user with autocompletion values, but does not provide any further information about what kind of data the user might be expected to enter. User agents would have to use heuristics to decide what autocompletion values to suggest.</p>
</blockquote>
<h2 id="尾巴">尾巴</h2>
<p>还是第一次看html的文档，不是太能看得下去，因为内容太多了，信息量比较大，但确实有用</p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://www.chromium.org/developers/design-documents/create-amazing-password-forms/"  target="_blank" rel="noopener" >Create Amazing Password Forms</a></li>
<li><a href="https://www.chromium.org/developers/design-documents/form-styles-that-chromium-understands/"  target="_blank" rel="noopener" >Password Form Styles that Chromium Understands</a></li>
<li><a href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls%3A-the-autocomplete-attribute"  target="_blank" rel="noopener" >autocomplete</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Docker学习笔记</title>
      <link>https://ds63.eu.org/2023/learn_docker/</link>
      <pubDate>Sat, 25 Mar 2023 15:34:14 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/learn_docker/</guid>
      <description>docker pull learn</description>
      <content:encoded><![CDATA[<h2 id="命令">命令</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="c1"># build并tag</span>
</span></span><span class="line"><span class="cl">  docker build -t imagename .
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 将build好的image上传到docker hub</span>
</span></span><span class="line"><span class="cl">  docker login -u <span class="nv">$username</span>
</span></span><span class="line"><span class="cl">  docker tag <span class="nv">$imagename</span> <span class="nv">$username</span>/<span class="nv">$imagename</span>
</span></span><span class="line"><span class="cl">  docker push <span class="nv">$username</span>/<span class="nv">$imagename</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 查看运行的container</span>
</span></span><span class="line"><span class="cl">  docker ps
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="c1"># 查看所有的container</span>
</span></span><span class="line"><span class="cl">  docker ps -a
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="c1"># 查看container的配置情况</span>
</span></span><span class="line"><span class="cl">  docker inspect container-name
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 直接获取目标容器的启动参数</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike target-container-name
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 可将上述命令设置别名</span>
</span></span><span class="line"><span class="cl">  <span class="nb">alias</span> <span class="nv">drunlike</span><span class="o">=</span><span class="s2">&#34;docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 查看容器的日志</span>
</span></span><span class="line"><span class="cl">  docker logs container-name
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 显示所有的镜像</span>
</span></span><span class="line"><span class="cl">  docker image ls
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="c1"># 删除容器</span>
</span></span><span class="line"><span class="cl">  docker rm container-name
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 删除镜像</span>
</span></span><span class="line"><span class="cl">  docker rmi imagename
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 退出容器后自动删除</span>
</span></span><span class="line"><span class="cl">  docker run --rm  <span class="nv">$imagename</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># 为用户添加docker用户组权限</span>
</span></span><span class="line"><span class="cl">  sudo usermod -aG docker your-username
</span></span><span class="line"><span class="cl">  newgrp docker 
</span></span></code></pre></div><h2 id="dockerfile配置">Dockerfile配置</h2>
<ul>
<li>
<p>代理设置</p>
<ul>
<li>让镜像构建过程也走代理：
<pre tabindex="0"><code>ENV http_proxy=http://172.17.0.1:7890
ENV https_proxy=http://172.17.0.1:7890
</code></pre></li>
</ul>
</li>
<li>
<p>dockerignore
新建文件.dockerignore，写入需要忽略的文件，</p>
<p>在Dockerfile中添加一行
<code>COPY .dockerignore .</code></p>
</li>
</ul>
<h2 id="docker-composeyml配置">docker-compose.yml配置</h2>
<ul>
<li>代理设置
<ul>
<li>让容器走代理
<pre tabindex="0"><code>environment:
  - http_proxy=http://172.17.0.1:7890
  - https_proxy=http://172.17.0.1:7890
</code></pre></li>
</ul>
</li>
<li>volume挂载
例：
注：此处所挂载的文件位置与docker-compose.yml文件同级
<pre tabindex="0"><code>  volumes:
    - &#34;./config.json:/app/config.json&#34;
    - &#34;./save.json:/app/save.json&#34;
    - &#34;./warning.json:/app/warning.json&#34;
</code></pre></li>
<li>resart(重启策略)
<table>
<thead>
<tr>
<th>重启策略</th>
<th>重启条件</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>restart: always</code></td>
<td>容器退出时，无论正常或异常</td>
<td>始终运行的容器，例如数据库、消息队列</td>
</tr>
<tr>
<td><code>restart: on-failure</code></td>
<td>容器以非零退出代码退出时</td>
<td>处理业务逻辑的容器，例如 Web 服务器、API 服务</td>
</tr>
<tr>
<td><code>unless-stopped</code></td>
<td>容器在停止之前会一直运行</td>
<td></td>
</tr>
</tbody>
</table>
</li>
</ul>
<h2 id="docker-compose-up的四种写法">docker-compose up的四种写法</h2>
<ol>
<li>传统写法：cd到<code>compose.yml</code>所在文件夹位置，再<code>docker-compose up</code></li>
<li>使用绝对路径: <code>docker-compose -f /home/user/project/docker-compose.yml up</code></li>
<li>使用别名: <code>alias project-up=&quot;docker-compose -f /home/user/project/docker-compose.yml up</code> (别名还可以用中文名)</li>
<li></li>
</ol>
<h2 id="在群晖上使用docker">在群晖上使用docker</h2>
<ul>
<li><a href="https://www.cxaim.com/591.html"  target="_blank" rel="noopener" >紧急！解决Docker镜像无法拉取问题！ - 承心识梦</a></li>
<li><a href="https://blog.chai.ac.cn/posts/docker-proxy"  target="_blank" rel="noopener" >为群晖 Container Manager 配置代理 | 柴语言 · ChaiLang</a></li>
<li><a href="https://www.codesky.me/archives/nas-docker.wind"  target="_blank" rel="noopener" >群晖 Docker 服务使用心得 - CodeSky 代码之空</a></li>
<li><a href="https://blog.yanghong.dev/nas-clash-vpn/"  target="_blank" rel="noopener" >NAS系统折腾记 | 设置科学上网环境 - HY&rsquo;s Blog</a></li>
<li><a href="https://www.odszz.com/posts/nas-proxy/"  target="_blank" rel="noopener" >群晖 NAS - 代理设置 | Darren&rsquo;s Blog</a></li>
<li><a href="https://chenhe.me/post/synology-docker-configuration"  target="_blank" rel="noopener" >群晖 Docker 的迷惑配置 - 晨鹤部落格</a></li>
<li><a href="https://www.simaek.com/archives/467/"  target="_blank" rel="noopener" >群晖Non-Root非特权账户执行Docker指令 - 兮陌</a></li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#创建群组并分配用户：</span>
</span></span><span class="line"><span class="cl">sudo synogroup --add docker
</span></span><span class="line"><span class="cl">sudo synogroup --memberadd docker &lt;username1&gt; &lt;username2&gt; ...
</span></span><span class="line"><span class="cl">sudo synogroup --get docker
</span></span><span class="line"><span class="cl"><span class="c1">#更改docker权限：</span>
</span></span><span class="line"><span class="cl">sudo chgrp docker /var/run/docker.sock
</span></span></code></pre></div><ul>
<li>报错: <code>/usr/local/bin/docker-compose: line 1: Not: command not found</code>
<ul>
<li>我之前在群晖上使用<code>docker-compose</code>都很正常，但某天突然报以上错误。一开始一头雾水，但尝试去找这个文件，发现并不存在。那问题就转变成如果在群晖上安装<code>docker-compose</code>了，搜到<a href="https://www.himiku.com/archives/docker-compose-for-synology-nas.html"  target="_blank" rel="noopener" >原来，群晖也能用 Docker Compose！ - 初之音</a>这篇，摘抄命令如下</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">DOCKER_CONFIG</span><span class="o">=</span><span class="si">${</span><span class="nv">DOCKER_CONFIG</span><span class="k">:-</span><span class="nv">$HOME</span><span class="p">/.docker</span><span class="si">}</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="nv">$DOCKER_CONFIG</span>/cli-plugins
</span></span><span class="line"><span class="cl"><span class="nv">COMPOSE_VERSION</span><span class="o">=</span><span class="k">$(</span>curl -s https://api.github.com/repos/docker/compose/releases/latest <span class="p">|</span> grep <span class="s1">&#39;tag_name&#39;</span> <span class="p">|</span> cut -d<span class="se">\&#34;</span> -f4<span class="k">)</span>
</span></span><span class="line"><span class="cl">sh -c <span class="s2">&#34;curl -L https://github.com/docker/compose/releases/download/</span><span class="si">${</span><span class="nv">COMPOSE_VERSION</span><span class="si">}</span><span class="s2">/docker-compose-`uname -s`-`uname -m` &gt; </span><span class="nv">$DOCKER_CONFIG</span><span class="s2">/cli-plugins/docker-compose&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># or </span>
</span></span><span class="line"><span class="cl">sh -c <span class="s2">&#34;curl -L https://mirror.ghproxy.com/https://github.com/docker/compose/releases/download/</span><span class="si">${</span><span class="nv">COMPOSE_VERSION</span><span class="si">}</span><span class="s2">/docker-compose-`uname -s`-`uname -m` &gt; </span><span class="nv">$DOCKER_CONFIG</span><span class="s2">/cli-plugins/docker-compose&#34;</span>
</span></span><span class="line"><span class="cl">chmod +x <span class="nv">$DOCKER_CONFIG</span>/cli-plugins/docker-compose
</span></span></code></pre></div><h2 id="容器逃逸">容器逃逸</h2>
<ul>
<li><a href="https://bbs.huaweicloud.com/blogs/278683"  target="_blank" rel="noopener" >容器逃逸常用方法-云社区-华为云</a></li>
<li><a href="https://www.kawabangga.com/posts/5785"  target="_blank" rel="noopener" >CVE-2024-21626 从容器内逃逸到宿主机文件系统 | 卡瓦邦噶！</a></li>
</ul>
<h2 id="原理">原理</h2>
<ul>
<li><a href="https://www.kawabangga.com/posts/4224"  target="_blank" rel="noopener" >Docker (容器) 的原理 | 卡瓦邦噶！</a></li>
</ul>
<h2 id="搭建私有docker仓库">搭建私有docker仓库</h2>
<ul>
<li><a href="https://blog.fatedier.com/2016/05/16/install-private-docker-registry/"  target="_blank" rel="noopener" >搭建私有docker仓库</a></li>
</ul>
<h2 id="时间线">时间线</h2>
<h3 id="2023年5月18日">2023年5月18日</h3>
<p>Docker官方仓库域名被墙，国内已无法正常访问。</p>
<h3 id="2024年6月8日">2024年6月8日</h3>
<p>这几天国内不少镜像站被关停了,唉</p>
<h3 id="2024年7月12日">2024年7月12日</h3>
<ul>
<li><a href="https://kebingzao.com/2019/02/22/docker-container-proxy/"  target="_blank" rel="noopener" >docker 容器内使用宿主机的代理配置 | Zach Ke&rsquo;s Notes</a></li>
<li><a href="https://www.moralok.com/2023/06/13/how-to-configure-proxy-for-terminal-docker-and-container/"  target="_blank" rel="noopener" >如何为终端、docker 和容器设置代理 | Moralok</a></li>
</ul>
<h2 id="2024年8月11日">2024年8月11日</h2>
<ul>
<li><a href="https://martinheinz.dev/blog/111"  target="_blank" rel="noopener" >Recent Docker BuildKit Features You&rsquo;re Missing Out On | Martin Heinz | Personal Website &amp; Blog</a>
<ul>
<li><code>docker buildx debug</code></li>
</ul>
</li>
</ul>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://blog.minirplus.com/12138/"  target="_blank" rel="noopener" >如何更新docker容器镜像</a></li>
<li><a href="https://help.aliyun.com/document_detail/60750.htm"  target="_blank" rel="noopener" >官方镜像加速</a></li>
<li><a href="https://anthonysun256.github.io/docker-proxy-complete-solution/"  target="_blank" rel="noopener" >Docker Container 代理配置一本通</a></li>
<li><a href="https://blog.csdn.net/qq_34939308/article/details/105202336"  target="_blank" rel="noopener" >docker run &ndash;rm 选项详解</a></li>
<li><a href="https://blog.haohtml.com/archives/31298"  target="_blank" rel="noopener" >利用代理拉取docker镜像 | 学习笔记</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Linux学习笔记</title>
      <link>https://ds63.eu.org/2023/linux%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Sun, 19 Mar 2023 18:38:50 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/linux%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>Linux学习笔记</description>
      <content:encoded><![CDATA[<h2 id="linux命令">Linux命令</h2>
<ul>
<li><code>ctrl + C</code> 打断执行</li>
<li><code>pwd</code> 输出当前位置</li>
<li><code>cmd1;cmd2</code> 首先运行命令1，然后运行命令2</li>
<li><code>cmd1&amp;&amp;cmd2</code> 仅在命令1成功结束时才运行命令2</li>
<li><code>cmd1||cmd2</code> 仅当命令1失败时才运行命令2</li>
<li><code>strace</code>  追踪程序系统调用</li>
<li><code>touch</code> 新建文件,内容为空</li>
<li><code>cat</code>
<ul>
<li><code>cat filename</code> To view a single file</li>
<li><code>cat [filename-whose-contents-is-to-be-copied] &gt; [destination-filename]</code> Copy the contents of one file to another file.</li>
<li><code>cat file1 &gt;&gt; file2</code> Cat command can append the contents of one file to the end of another file.</li>
</ul>
</li>
<li>管道；用<code>|</code>连接两个命令，以前面一个命令的输出作为后面命令的输入
<ul>
<li><code>strace -f gcc a.c 2&gt;&amp;1 | vim -</code> This will pipe both stdout and stderr to vim. The <code>-</code> argument tells vim to read from stdin.</li>
<li><code>strace pmap 152 |&amp; vim - </code>
<code>|&amp;</code> : This is a shorthand for <code>2&gt;&amp;1 |</code> in bash and zsh. It passes both standard output and standard error of one command as input to another.</li>
</ul>
</li>
<li><code>sort -nk 6</code> 依第6列升序排列</li>
<li>执行多次，或循环执行
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#for i in {1..5}; do  // while true; do</span>
</span></span><span class="line"><span class="cl">&gt;  <span class="nb">command</span> 
</span></span><span class="line"><span class="cl">&gt;done
</span></span></code></pre></div></li>
<li>crontab的使用
<ul>
<li><code>crontab -e</code></li>
<li>注意：crontab运行的环境并不包含docker命令。需要指定完整的路径。</li>
</ul>
</li>
<li><code>lsof -i:端口号</code>查看端口占用情况</li>
<li><code>kill -9 PID</code> 杀掉对应的进程</li>
<li><code>grep</code> (global regular expression)  用于查找文件里符合条件的字符串或正则表达式</li>
<li><code>which</code> 查找安装路径 如<code>which docker</code></li>
<li><code>ls -l</code> 详细信息</li>
<li><code>~/.bashrc</code>是 Bash shell 在每次启动时都会自动执行的一个脚本文件,可以用于设置环境变量、别名和一些其他 Bash shell 配置。
<ul>
<li><code>source /opt/rh/devtoolset-9/enable</code> 更新gcc版本</li>
<li>export PS1=&rsquo;[][\W]$ []&rsquo; 修改PS1变量，让其更加简洁。PS1的默认设置为<code>\[\][\u@\h \W]\$ \[\]</code></li>
</ul>
</li>
<li><code>tar</code>
<ul>
<li><code>tar cvf file.tar *.c</code> creates a tar file called file.tar which is the Archive of all .c files in current directory.</li>
<li><code>tar xvf file.tar</code> extracts files from Archives.</li>
<li><code>z</code>tells tar command that creates tar file using gzip 即<code>tar.gz</code></li>
</ul>
</li>
<li>可以利用 TAB 补全查看所有可用的命令选项(连按两次 TAB 键)</li>
</ul>
<h2 id="汇编相关">汇编相关</h2>
<ul>
<li><code>objdump -d filename</code> print the assembler content of the sections capable of execution.</li>
<li><code>objdump -s filename</code>  print the complete content of all the sections of the file</li>
</ul>
<h2 id="gcc">gcc</h2>
<ul>
<li><code>gcc - E a.c</code> 对a.c进行宏展开</li>
<li>升级gcc版本到gcc9 <a href="https://blog.csdn.net/xunye_dream/article/details/108918316"  target="_blank" rel="noopener" >CentOS7 升级gcc版本到gcc9</a>
<code>source /opt/rh/devtoolset-9/enable</code></li>
<li><code>-static</code> 静态编译，省去动态链接相关的系统调用</li>
</ul>
<h2 id="vim">vim</h2>
<ul>
<li>cmd模式
<ul>
<li><code>:!cmd </code> execute a shell command from within Vim
<ul>
<li><code>!gcc %</code> 编译</li>
<li><code>!xxd</code>  将当前文件转换为十六进制表示并显示在终端中</li>
<li><code>%!xxd</code> 将当前文件的内容通过管道传递给外部命令xxd，并将其输出替换为当前文件的内容</li>
</ul>
</li>
<li><code>:set nu</code> 显示行号</li>
<li><code>:set wrap</code></li>
<li><code>:%!grep execve</code></li>
<li><code>:%! grep -v ENOENT</code></li>
<li><code>:%s/term/another_term/g </code> 替换</li>
</ul>
</li>
<li>visual模式 按v进入
<ul>
<li><code>y</code> 复制选中内容</li>
<li><code>d</code> 删除</li>
</ul>
</li>
<li><code>u</code> undo</li>
</ul>
<h2 id="gdb">gdb</h2>
<ul>
<li>编译时要带<code>-g</code></li>
<li><code>bt</code> :but trace</li>
</ul>
<hr>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://www.geeksforgeeks.org/cat-command-in-linux-with-examples/"  target="_blank" rel="noopener" >Cat command in Linux with examples</a></li>
<li><a href="https://blog.csdn.net/xunye_dream/article/details/108918316"  target="_blank" rel="noopener" >CentOS7 升级gcc版本到gcc9</a></li>
<li><a href="https://jyywiki.cn/OS/2022/"  target="_blank" rel="noopener" >操作系统：设计与实现 (2022 春季学期)</a></li>
<li><a href="https://blog.csdn.net/lc013/article/details/103775702"  target="_blank" rel="noopener" >Linux 定时执行shell 脚本</a></li>
<li><a href="https://www.geeksforgeeks.org/tar-command-linux-examples"  target="_blank" rel="noopener" >tar command in Linux with examples</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>收藏夹的使用</title>
      <link>https://ds63.eu.org/2023/the-use-of-favorites/</link>
      <pubDate>Sat, 18 Mar 2023 23:45:18 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/the-use-of-favorites/</guid>
      <description>收藏夹和JavaScript的结合实现实用小功能</description>
      <content:encoded><![CDATA[<p><strong>偶然发现可以在url中使用JavaScript，这是前提。</strong></p>
<p><strong>日常使用时，有些功能特意为此写个拓展有点小题大作，这时候使用收藏夹即可，方便的同时也增加了可迁移性</strong></p>
<h2 id="bing转google搜索">Bing转Google搜索</h2>
<ul>
<li>描述：我日常搜索引擎是使用bing，但有些时候bing的内容我不是很满意，需要在Google上再次搜索；由于new bing的存在，我不想更换默认搜索引擎，但打开Google，再次搜索这个操作又很麻烦，所以就添加了一条收藏夹</li>
<li>代码详解：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">currentUrl</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">;</span> <span class="c1">//获取当前链接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">reg</span> <span class="o">=</span> <span class="sr">/q=([^&amp;]+)/</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">currentUrl</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">reg</span><span class="p">);</span> <span class="c1">//使用正则表达式进行匹配
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">googleUrl</span> <span class="o">=</span> <span class="s2">&#34;https://www.google.com/search?q=&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">resultUrl</span> <span class="o">=</span> <span class="nx">googleUrl</span><span class="o">+</span><span class="nx">res</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="c1">//拼接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">window</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="nx">resultUrl</span><span class="p">,</span><span class="s1">&#39;_self&#39;</span><span class="p">).</span><span class="nx">close</span><span class="p">();</span><span class="c1">//打开新网站，并关闭原网站
</span></span></span></code></pre></div></li>
<li>书签URL
<code>javascript:var currentUrl = window.location.href;var reg = /q=([^&amp;]+)/;var res = currentUrl.match(reg);var googleUrl = &quot;https://www.google.com/search?q=&quot;;var resultUrl = googleUrl+res[1];window.open(resultUrl,'_self').close();</code></li>
<li>PS：正则表达式是让new bing写的，感觉有种ntr的美</li>
<li>PPS：后来我还是改用Google作为默认搜索引擎了。</li>
</ul>
<h2 id="网易云解除歌单限制">网易云解除歌单限制</h2>
<ul>
<li>描述：网易云音乐网页端对歌单显示数量有限制，只显示20条，而我不希望因此下载客户端，于是添加了该书签。</li>
<li>代码：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="o">=</span><span class="s2">&#34;os=pc&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">reload</span><span class="p">();</span><span class="c1">//重新加载网页
</span></span></span></code></pre></div></li>
<li>收藏夹URL
<code>javascript:document.cookie=&quot;os=pc&quot;;window.location.reload();</code></li>
<li>PS: 后来我放弃使用网易云，转而使用Spotify，具体可见<a href="https://ds63.eu.org/2023/rocords-of-two-migrations/"  target="_blank" rel="noopener" >记两次迁移 | EuDs&rsquo;s Blog</a></li>
</ul>
<h2 id="跳转至neodb">跳转至NeoDB</h2>
<ul>
<li>描述：我最近开始使用<a href="https://neodb.social/discover/"  target="_blank" rel="noopener" >NeoDB</a>作为我的书影音标记工具，但我还是会先再豆瓣、Bangumi等网站先看看别人的评论，然后再去<a href="https://neodb.social/discover/"  target="_blank" rel="noopener" >NeoDB</a>标记。于是添加了该书签。</li>
<li>代码：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">currentUrl</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">;</span> <span class="c1">//获取当前链接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">neodbUrl</span> <span class="o">=</span> <span class="s2">&#34;https://neodb.social/search/?q=&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">resultUrl</span> <span class="o">=</span> <span class="nx">neodbUrl</span><span class="o">+</span><span class="nx">currentUrl</span><span class="p">;</span> <span class="c1">//拼接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">window</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="nx">resultUrl</span><span class="p">,</span><span class="s1">&#39;_self&#39;</span><span class="p">);</span><span class="c1">//打开
</span></span></span></code></pre></div></li>
<li>收藏夹URL
<code>javascript:var currentUrl = window.location.href;var neodbUrl = &quot;https://neodb.social/search/?q=&quot;;var resultUrl = neodbUrl+currentUrl;window.open(resultUrl,'_self')</code></li>
</ul>
<h2 id="屏蔽google地图">屏蔽google地图</h2>
<p><strong>这条不是书签相关，但看了看只有这里最相关了</strong></p>
<p>最近（2023年11月30日）用google搜一些比较冷门的结果时，排在前面的一般是些广告。点进去发现是人为添加的google map，应该是利用google对自家产品的搜索优化。虽然有点感慨其聪明才智，但忍了一周还是不堪其扰。
我目前的解决方法是修改搜索引擎中的url为</p>
<p><code>{google:baseURL}search?q=+%s+-site:www.google.com/mymaps +-site:www.google.com/maps&amp;{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:prefetchSource}{google:searchClient}{google:sourceId}{google:contextualSearchVersion}ie={inputEncoding}{google:baseURL}search?q=%s&amp;{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:prefetchSource}{google:searchClient}{google:sourceId}{google:contextualSearchVersion}ie={inputEncoding}</code></p>
<p>这样的代价是会让搜索框变得很丑，但我没找到更好的解决方法，先凑合这样吧。</p>
<p>PS: 我发现还是防不胜防，对黑产的奇淫巧计甘拜下风。</p>
<p>pss: 今天(2024年8月28日)读到<a href="https://blog.hentioe.dev/posts/google-search-blacklist.html"  target="_blank" rel="noopener" >移除 Google 搜索的低质量结果，屏蔽垃圾内容！（附屏蔽 CSDN 等网站的方法） | 绅士喵</a>，发现uBlacklist更好用</p>
<h2 id="跳转至github-page主页">跳转至Github Page主页</h2>
<p>大部分Github用户，如果他们的Github Page有内容的话，都会在简介中提供链接，但也有的不会。</p>
<p>手动去拼接url太麻烦了，写个扩展是可行，但也有点麻烦，还是用收藏夹来得快。</p>
<ul>
<li>代码
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JavaScript" data-lang="JavaScript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">currentUrl</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">;</span> <span class="c1">//获取当前链接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">GitHubPageUrl</span> <span class="o">=</span> <span class="sb">`https://</span><span class="si">${</span><span class="nx">currentUrl</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)[</span><span class="mi">3</span><span class="p">].</span><span class="nx">toLowerCase</span><span class="p">()</span><span class="si">}</span><span class="sb">.github.io/`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="nx">GitHubPageUrl</span><span class="p">,</span><span class="s1">&#39;_self&#39;</span><span class="p">);</span><span class="c1">//打开
</span></span></span></code></pre></div></li>
<li>收藏夹URL
<code>javascript:var currentUrl = window.location.href;var GitHubPageUrl = </code>https://${currentUrl.split(&rsquo;/&rsquo;)[3].toLowerCase()}.github.io/<code>;window.open(GitHubPageUrl,'_self');</code></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>《窄门》摘录</title>
      <link>https://ds63.eu.org/2023/%E7%AA%84%E9%97%A8%E6%91%98%E5%BD%95/</link>
      <pubDate>Wed, 15 Mar 2023 23:36:17 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E7%AA%84%E9%97%A8%E6%91%98%E5%BD%95/</guid>
      <description>你们要努力进窄门。</description>
      <content:encoded><![CDATA[<h1 id="窄门摘录">《窄门》摘录</h1>
<ul>
<li>您在第 2 页（位置 #28-29）的标注 | 添加于 2023年3月14日星期二 上午10:55:30</li>
</ul>
<h1 id="往事断断续续支离破碎但我不打算靠虚构事实连通补缀这种修饰铺陈会浇灭讲述的热忱最后一丝意趣也化为乌有">往事断断续续，支离破碎，但我不打算靠虚构事实连通补缀，这种修饰铺陈，会浇灭讲述的热忱，最后一丝意趣也化为乌有。</h1>
<ul>
<li>您在第 12 页（位置 #171-171）的标注 | 添加于 2023年3月14日星期二 上午11:28:48</li>
</ul>
<h1 id="你们要努力进窄门">你们要努力进窄门。</h1>
<ul>
<li>您在第 12 页（位置 #174-175）的标注 | 添加于 2023年3月14日星期二 上午11:29:23</li>
</ul>
<h1 id="你们要努力进窄门因为宽门和阔路引向沉沦进去的人很多然而窄门和狭道却通向永生只有少数人能找到">你们要努力进窄门，因为宽门和阔路引向沉沦，进去的人很多；然而窄门和狭道却通向永生，只有少数人能找到。</h1>
<ul>
<li>您在第 13 页（位置 #199-202）的标注 | 添加于 2023年3月14日星期二 上午11:32:13</li>
</ul>
<h1 id="这场内心的顿悟让我认清自己我性格内向不太开朗虽然期待被人关怀却对他人漠不关心我没什么进取心除了想在克己方面获得胜利之外没有其余的梦想我喜欢学习至于玩耍却只喜欢需要动脑筋或付出努力的游戏我很少和年龄相仿的同学交往偶尔同他们玩耍也只是为了维持友谊或是出于礼貌">这场内心的顿悟，让我认清自己：我性格内向，不太开朗，虽然期待被人关怀，却对他人漠不关心；我没什么进取心，除了想在克己方面获得胜利之外，没有其余的梦想；我喜欢学习，至于玩耍，却只喜欢需要动脑筋或付出努力的游戏；我很少和年龄相仿的同学交往，偶尔同他们玩耍也只是为了维持友谊或是出于礼貌</h1>
<ul>
<li>您在第 17 页（位置 #257-260）的标注 | 添加于 2023年3月14日星期二 上午11:36:03</li>
</ul>
<h1 id="我完全明白这指的是我们在共同崇拜的对象那里激动热烈地重逢正是为了与你重逢我才去崇拜你所崇拜的对象-你崇拜的动机不纯-不要对我太苛求如果你不在天国这个天国我不去也罢">“我完全明白。这指的是我们在共同崇拜的对象那里激动热烈地重逢。正是为了与你重逢，我才去崇拜你所崇拜的对象。” “你崇拜的动机不纯。” “不要对我太苛求，如果你不在天国，这个天国我不去也罢</h1>
<ul>
<li>您在第 24 页（位置 #359-359）的标注 | 添加于 2023年3月14日星期二 上午11:44:54</li>
</ul>
<h1 id="我认为死亡反而能让人靠近没错能让生前分开的人拉近距离">我认为死亡反而能让人靠近……没错，能让生前分开的人拉近距离。</h1>
<ul>
<li>您在第 25 页（位置 #379-381）的标注 | 添加于 2023年3月14日星期二 上午11:45:58</li>
</ul>
<h1 id="我们为什么要订婚呢知道拥有彼此而且永远不变难道还不够吗何必昭告天下呢我若愿意为她奉献一生你真觉得需要用诺言来维系这份爱情才更美好吗不誓言对我而说是对爱情的侮辱只有在不信任她的时候我才渴望和她缔结婚约">我们为什么要订婚呢？知道拥有彼此，而且永远不变，难道还不够吗？何必昭告天下呢？我若愿意为她奉献一生，你真觉得需要用诺言来维系这份爱情，才更美好吗？不，誓言对我而说是对爱情的侮辱……只有在不信任她的时候，我才渴望和她缔结婚约。”</h1>
<ul>
<li>您在第 30 页（位置 #451-452）的标注 | 添加于 2023年3月14日星期二 上午11:53:22</li>
</ul>
<h1 id="比你年长太多这一点让我担忧你还没有机会见到其他女人可能还没意识到这一点可我却想到了将来委身于你后你若不再喜欢我我会多痛苦啊">比你年长太多，这一点让我担忧。你还没有机会见到其他女人，可能还没意识到这一点。可我却想到了，将来委身于你后，你若不再喜欢我，我会多痛苦啊</h1>
<ul>
<li>您在第 32 页（位置 #478-480）的标注 | 添加于 2023年3月14日星期二 上午11:54:57</li>
</ul>
<h1 id="和我的答复一样说我还太小谈结婚还早可惜呀她笑着说道姑妈早料到我们会反对在信末的附言里写道爱德华泰西埃尔先生这是他的名字同意等我他这么早来求婚只是为了早点排队这太荒唐了但我还能怎么办呢又不能让人转告说他太丑了">“和我的答复一样：说我还太小，谈结婚还早……可惜呀，”她笑着说道，“姑妈早料到我们会反对，在信末的附言里写道：爱德华·泰西埃尔先生（这是他的名字）同意等我，他这么早来求婚只是为了早点‘排队’……这太荒唐了。但我还能怎么办呢？又不能让人转告，说他太丑了！</h1>
<ul>
<li>您在第 38 页（位置 #569-571）的标注 | 添加于 2023年3月14日星期二 下午12:00:00</li>
</ul>
<h1 id="看得出来她热情地附和我是因为担心我的学业而给出的鼓励而不是受精神的驱动我觉得评价争辩和批判都只是表达思想的方式可她却与我恰恰相反借助于这一切来掩饰自己的内心">看得出来，她热情地附和我，是因为担心我的学业而给出的鼓励，而不是受精神的驱动。我觉得评价、争辩和批判，都只是表达思想的方式，可她却与我恰恰相反，借助于这一切来掩饰自己的内心。</h1>
<ul>
<li>您在第 42 页（位置 #634-635）的标注 | 添加于 2023年3月14日星期二 下午12:17:27</li>
</ul>
<h1 id="普朗提埃姨妈也将无影无踪空留一件上衣灯火辉煌的圣诞树将像圣经中的诸山一样拍着手欢唱主的荣耀">普朗提埃姨妈也将无影无踪，空留一件上衣；灯火辉煌的圣诞树将像《圣经》中的诸山一样，拍着手欢唱主的荣耀。”</h1>
<ul>
<li>您在第 48 页（位置 #725-726）的标注 | 添加于 2023年3月14日星期二 下午12:26:16</li>
</ul>
<h1 id="在我的生命里除了爱情找不到别的意义于是紧紧抓着它除了期待我的爱人到来之外我什么也不等待也不愿等待">在我的生命里，除了爱情找不到别的意义，于是紧紧抓着它。除了期待我的爱人到来之外，我什么也不等待，也不愿等待。</h1>
<ul>
<li>您在第 51 页（位置 #770-773）的标注 | 添加于 2023年3月14日星期二 下午12:29:59</li>
</ul>
<h1 id="是何等战胜尘世的魔力-引我来见上帝-依赖他人之人-必将遭遇不幸">是何等战胜尘世的魔力， 引我来见上帝？ 依赖他人之人， 必将遭遇不幸</h1>
<ul>
<li>您在第 62 页（位置 #945-947）的标注 | 添加于 2023年3月14日星期二 下午12:38:20</li>
</ul>
<h1 id="她之前的来信都显得那么愉快我其实有些担心她在假装幸福为了骗我也骗她自己她今日的幸福同她过去梦想的幸福及幸福所依之人大相径庭">她之前的来信都显得那么愉快，我其实有些担心她在假装幸福，为了骗我，也骗她自己。她今日的幸福，同她过去梦想的幸福及幸福所依之人大相径庭……</h1>
<ul>
<li>您在第 63 页（位置 #953-954）的标注 | 添加于 2023年3月14日星期二 下午12:39:37</li>
</ul>
<h1 id="当地的景致和人们的笑声令我不快我所说的忧郁也许仅仅只是不像他们那般喧闹罢了我过去的欢乐中肯定包含某些骄傲的成分">当地的景致和人们的笑声令我不快，我所说的“忧郁”，也许仅仅只是不像他们那般喧闹罢了。我过去的欢乐中肯定包含某些骄傲的成分，</h1>
<ul>
<li>您在第 68 页（位置 #1041-1043）的标注 | 添加于 2023年3月14日星期二 下午12:44:28</li>
</ul>
<h1 id="我们明明有那么多话要说为什么还会这么尴尬这么做作这么无力这么沉默呢你回来的第一天面对这种沉默我还觉得挺开心因为我总觉得它会烟消云散在离开之前你总会对我说些美妙的事">我们明明有那么多话要说，为什么还会这么尴尬，这么做作，这么无力，这么沉默呢？你回来的第一天，面对这种沉默，我还觉得挺开心。因为我总觉得它会烟消云散，在离开之前你总会对我说些美妙的事。</h1>
<ul>
<li>您在第 69 页（位置 #1055-1056）的标注 | 添加于 2023年3月14日星期二 下午12:46:14</li>
</ul>
<h1 id="我们所有的通信不过是一场海市蜃楼唉我们两人的信都是写给自己看的噢杰罗姆杰罗姆我们还是永远分开吧">我们所有的通信不过是一场海市蜃楼。唉！我们两人的信都是写给自己看的……噢！杰罗姆！杰罗姆！我们还是永远分开吧！</h1>
<ul>
<li>您在第 69 页（位置 #1058-1061）的标注 | 添加于 2023年3月14日星期二 下午12:46:36</li>
</ul>
<h1 id="我爱你那么深却那么绝望我必须承认你也看到了离你越远我就越爱你唉这一点我也曾预料到这次期盼已久的重逢让我彻底了解了所以我的朋友你也一样相信这一点非常重要别了我挚爱的兄弟愿上帝保佑和指引你只有在他面前重聚我们才不必受罚">我爱你那么深，却那么绝望。我必须承认，你也看到了：离你越远，我就越爱你。唉，这一点我也曾预料到！这次期盼已久的重逢让我彻底了解了，所以我的朋友，你也一样，相信这一点非常重要。别了，我挚爱的兄弟，愿上帝保佑和指引你，只有在他面前重聚，我们才不必受罚</h1>
<ul>
<li>您在第 70 页（位置 #1068-1068）的标注 | 添加于 2023年3月14日星期二 下午12:47:41</li>
</ul>
<h1 id="我学会了独自承受痛心彻骨的悲伤和重负这种嘱咐于我而言完全是多余的">我学会了独自承受痛心彻骨的悲伤和重负，这种嘱咐于我而言完全是多余的。</h1>
<ul>
<li>您在第 72 页（位置 #1103-1106）的标注 | 添加于 2023年3月14日星期二 下午12:52:40</li>
</ul>
<h1 id="我们约定个暗号吧看到它表明我第二天就必须离开芬格斯玛尔而且次日说走就走不非难也不抱怨你同意吗-这番话我事先并无准备却说得极其自然她想了想回答道我下楼吃晚饭时脖子上若没有戴你喜爱的紫晶十字架你就明白了吧-那会是我在这里的最后一晚">我们约定个暗号吧，看到它，表明我第二天就必须离开芬格斯玛尔。而且次日说走就走，不非难，也不抱怨，你同意吗？” 这番话我事先并无准备，却说得极其自然。她想了想，回答道：“我下楼吃晚饭时，脖子上若没有戴你喜爱的紫晶十字架……你就明白了吧？” “那会是我在这里的最后一晚。</h1>
<ul>
<li>您在第 74 页（位置 #1128-1130）的标注 | 添加于 2023年3月14日星期二 下午12:53:44</li>
</ul>
<h1 id="除了幸福灵魂还能追求什么呢我冲动地嚷道-她却低声细语神圣声音那么小与其说是我听到的倒不如说是猜到的">除了幸福，灵魂还能追求什么呢？”我冲动地嚷道。 她却低声细语：“神圣……”声音那么小。与其说是我听到的，倒不如说是猜到的。</h1>
<ul>
<li>您在第 85 页（位置 #1295-1298）的标注 | 添加于 2023年3月15日星期三 上午4:15:31</li>
</ul>
<h1 id="我将阿莉莎一点点抬高把她塑造成偶像用所有喜欢的东西装点着她而如今除却疲乏之外这番经营还剩下什么呢一放任自流阿莉莎就会降回平庸的层次而我也一样若处于那个层次就不会再爱她为了与她在同一个高度相见我单凭自身努力抬高了她这番令人疲惫">我将阿莉莎一点点抬高，把她塑造成偶像，用所有喜欢的东西装点着她。而如今，除却疲乏之外，这番经营还剩下什么呢？一放任自流，阿莉莎就会降回平庸的层次；而我也一样，若处于那个层次，就不会再爱她。为了与她在同一个高度相见，我单凭自身努力抬高了她。这番令人疲惫</h1>
<ul>
<li>您在第 85 页（位置 #1295-1298）的标注 | 添加于 2023年3月15日星期三 上午4:16:32</li>
</ul>
<h1 id="我将阿莉莎一点点抬高把她塑造成偶像用所有喜欢的东西装点着她而如今除却疲乏之外这番经营还剩下什么呢一放任自流阿莉莎就会降回平庸的层次而我也一样若处于那个层次就不会再爱她为了与她在同一个高度相见我单凭自身努力抬高了她">我将阿莉莎一点点抬高，把她塑造成偶像，用所有喜欢的东西装点着她。而如今，除却疲乏之外，这番经营还剩下什么呢？一放任自流，阿莉莎就会降回平庸的层次；而我也一样，若处于那个层次，就不会再爱她。为了与她在同一个高度相见，我单凭自身努力抬高了她。</h1>
<ul>
<li>您在第 90 页（位置 #1368-1369）的标注 | 添加于 2023年3月15日星期三 上午6:43:56</li>
</ul>
<h1 id="他们没有得到曾应许的东西因为上帝给他们保留了更美好的我们总担心理解得不够透彻一直心神不宁">——‘他们没有得到曾应许的东西，因为上帝给他们保留了更美好的……’我们总担心理解得不够透彻，一直心神不宁。”</h1>
<ul>
<li>您在第 94 页（位置 #1433-1435）的标注 | 添加于 2023年3月15日星期三 上午6:47:25</li>
</ul>
<h1 id="让我生气的是除了牺牲我的幸福外她还能在别处找到获得幸福之路也就是说不用我做出牺牲她也能幸福-现在杰罗姆没有音信">让我生气的是：除了牺牲我的幸福外，她还能在别处找到获得幸福之路。也就是说，不用我做出牺牲，她也能幸福。 现在，杰罗姆没有音信</h1>
<ul>
<li>您在第 94 页（位置 #1433-1434）的标注 | 添加于 2023年3月15日星期三 上午6:47:30</li>
</ul>
<h1 id="让我生气的是除了牺牲我的幸福外她还能在别处找到获得幸福之路也就是说不用我做出牺牲她也能幸福">让我生气的是：除了牺牲我的幸福外，她还能在别处找到获得幸福之路。也就是说，不用我做出牺牲，她也能幸福。</h1>
<ul>
<li>您在第 96 页（位置 #1464-1467）的标注 | 添加于 2023年3月15日星期三 下午2:08:42</li>
</ul>
<h1 id="我喜欢弹钢琴练习曲是因为觉得每天都能有所进步这或许也是我喜欢读外文书的原因所在我当然不是因为喜欢外文多过本国语言也并非觉得我欣赏的本国作家比不上外国作家而是因为在理解外文的意义和情感时会有轻微的难度一旦攻克了它一旦理解得越来越好也许会产生一种无意识的自豪感在精神愉悦的同时增添某种道不明的心灵满足我似乎少不得这种满足">我喜欢弹钢琴练习曲，是因为觉得每天都能有所进步。这或许也是我喜欢读外文书的原因所在。我当然不是因为喜欢外文多过本国语言，也并非觉得我欣赏的本国作家比不上外国作家。而是因为在理解外文的意义和情感时，会有轻微的难度。一旦攻克了它，一旦理解得越来越好，也许会产生一种无意识的自豪感。在精神愉悦的同时，增添某种道不明的心灵满足。我似乎少不得这种满足</h1>
<ul>
<li>您在第 101 页（位置 #1542-1543）的标注 | 添加于 2023年3月15日星期三 下午2:12:27</li>
</ul>
<h1 id="有时候为了从他的行文节奏中跳脱出来我会试图写得差些但与他对抗本身也说明我还想着他">有时候，为了从他的行文节奏中跳脱出来，我会试图写得差些。但与他对抗本身，也说明我还想着他。</h1>
<ul>
<li>您在第 102 页（位置 #1564-1566）的标注 | 添加于 2023年3月15日星期三 下午2:13:42</li>
</ul>
<h1 id="我拥有的是多么平庸悲哀的德行我对自己过于苛求了吗别再痛苦了-我的意志该有多薄弱才一直乞求上帝赐予力量啊如今我的祷告里都是愁云惨雾">我拥有的是多么平庸、悲哀的德行！我对自己过于苛求了吗？别再痛苦了。 我的意志该有多薄弱，才一直乞求上帝赐予力量啊！如今，我的祷告里都是愁云惨雾</h1>
<ul>
<li>您在第 105 页（位置 #1602-1605）的标注 | 添加于 2023年3月15日星期三 下午2:15:33</li>
</ul>
<h1 id="从今早起我便心如止水昨夜我整晚都在沉思和祷告刹那间感到一种清澈的寂静包围着我落在我身上它与我童年时对圣灵的想象全然一致我担心这份喜悦不过是神经亢奋之故于是立刻躺下睡觉很快进入梦乡这份幸福并未离我而去今天早上依然存在丝毫没有减弱现在我确信他要来了">从今早起，我便心如止水。昨夜，我整晚都在沉思和祷告，刹那间，感到一种清澈的寂静包围着我，落在我身上，它与我童年时对圣灵的想象全然一致。我担心这份喜悦不过是神经亢奋之故，于是立刻躺下睡觉，很快进入梦乡。这份幸福并未离我而去，今天早上依然存在，丝毫没有减弱。现在我确信，他要来了。</h1>
<ul>
<li>您在第 108 页（位置 #1654-1655）的标注 | 添加于 2023年3月15日星期三 下午2:18:25</li>
</ul>
<h1 id="不属于上帝的一切无一能满足我的期待">不属于上帝的一切，无一能满足我的期待。”</h1>
<ul>
<li>您在第 112 页（位置 #1706-1707）的标注 | 添加于 2023年3月15日星期三 下午2:20:59</li>
</ul>
<h1 id="你希望早些忘掉吗-我希望永远不忘">你希望早些忘掉吗？” “我希望永远不忘。”</h1>
]]></content:encoded>
    </item>
    
    <item>
      <title>读《窄门》</title>
      <link>https://ds63.eu.org/2023/%E8%AF%BB%E7%AA%84%E9%97%A8/</link>
      <pubDate>Wed, 15 Mar 2023 23:33:44 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E8%AF%BB%E7%AA%84%E9%97%A8/</guid>
      <description>你们要努力进窄门，因为宽门和阔路引向沉沦，进去的人很多；然而窄门和狭道却通向永生，只有少数人能找到。</description>
      <content:encoded><![CDATA[<h1 id="读窄门">读《窄门》</h1>
<p>花了两天时间把《窄门》读完了，书很薄，百来页，故事也不复杂。</p>
<h2 id="整体感受">整体感受</h2>
<p>我蛮早就意识到，也一直让自己尽量避免这样一种行为：去给人或事做一个十分简单的评价，然后就带着这个评价或者说偏见去看ta的发展。</p>
<p>但我这次读这本书的时候，还是这样做了：书读到四分之一时，我就很不能理解阿莉莎，认为她是自作自受。</p>
<p>所以带着这个偏见，我这本书的阅读体验很不好。让我坚持读下去的，主要是书的封面做得很有感觉，还有书中几处我觉得比较惊艳的情节，比如：</p>
<ul>
<li>
<p>男主和女主约定暗号</p>
<blockquote>
<p>“听着，阿莉莎，”我突然高声说道，“我有十二天的假期，你若不高兴，我一天也不会多待。我们约定个暗号吧，看到它，表明我第二天就必须离开芬格斯玛尔。而且次日说走就走，不非难，也不抱怨，你同意吗？”
这番话我事先并无准备，却说得极其自然。她想了想，回答道：“我下楼吃晚饭时，脖子上若没有戴你喜爱的紫晶十字架……你就明白了吧？”
“那会是我在这里的最后一晚。”
“你真能就那么走吗？”她继续道，“不流泪，不叹息……”
“也不告别，我会像前一天那样与你分别，看起来漫不经心。你起初还会纳闷——他真的明白吗？但第二天早上，当你想找我时就会发现，我已经不在了。”
“第二天，我也不会去找你。”</p>
</blockquote>
<p>我喜欢这样的感觉。</p>
</li>
<li>
<p>女主的日记</p>
<blockquote>
<p>为何要欺骗自己呢？我是通过理性推导，才对朱莉叶特的幸福感到欣慰的。我曾如此期盼她获得幸福，为了她的幸福，我甚至愿意牺牲自己的幸福。可如今见她轻而易举地获得了，见这份幸福同我们当初的想象如此不同，我竟感到难受。实在太复杂了！是的……我清醒认识到一种可怕的自私心理回到了我身上。让我生气的是：除了牺牲我的幸福外，她还能在别处找到获得幸福之路。也就是说，不用我做出牺牲，她也能幸福。</p>
</blockquote>
<p>这段我觉得很有意思，也很真实。</p>
</li>
</ul>
<p>这本书让我感兴趣的地方还有：对宗教的描述，或者说对基督教。这本书有很大篇幅是关于基督教的。甚至连书名也是出自其中。我不是一个信徒，但我对信仰有一定的敬畏，对不同的宗教颇感兴趣。我甚至想有机会去读读各宗教的主要经文。</p>
<h2 id="分析下女主">分析下女主</h2>
<p>我一开始的观点是：女主的境遇实属自作自受。我觉得这并非作者想要表达的。所以我尝试去分析下，以此让自己更好的理解这本书。</p>
<p><em>留给以后的我吧，我想我还会重读这本书的</em></p>
<p>书中两位主要女角色的姓名让我读这本书的时候有不一样的体验。</p>
<ul>
<li>Juliette，我读的这版将其译为朱莉叶特，但我一直错记成Julia。</li>
<li>Alissa，译为阿莉莎。这让我联想到阿廖沙，《太阳照常升起》中的阿廖沙。
因着这两个错记，我读这本书的时候，Lennon和周韵演的疯妈就一直出现在我的脑中。</li>
</ul>
<h2 id="ps">ps</h2>
<ul>
<li>
<p>写这篇感受的时候，我刚读完这本书，还在纠结一个问题：如果这本书读完并没有明确的感想，那还要不要写感受呢？现在快写完了，我反倒就不纠结了。因为我发现，我、当我一开始动笔，或者说开始码字时，本来模模糊糊的感受，也变得具体起来了。这让我觉得很畅快。</p>
</li>
<li>
<p>原书名为：La Porte étroite
英译本书名为：Strait is the Gate
中译本书名为：窄门</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=qsZ37pDNUwA&amp;t=764s&amp;ab_channel=Jos%C3%A9"  target="_blank" rel="noopener" >The Smiths - A Tale of a Wonderful Woman (Bootleg)</a> 这个让我想到女主，至少是前半段时候的女主。识图后发现这位名叫Virginia Woolf，是一位作家。</p>
</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>博客搭建</title>
      <link>https://ds63.eu.org/2023/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Mon, 13 Mar 2023 12:50:17 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</guid>
      <description>记录博客搭建的过程,及途中遇到的问题和解决方式</description>
      <content:encoded><![CDATA[<h2 id="过程">过程</h2>
<p><em>记录博客搭建的过程</em></p>
<ol>
<li>框架是选用的<a href="https://hexo.io/zh-cn/docs/"  target="_blank" rel="noopener" >Hexo</a>,主题选用的是<a href="https://hexo.fluid-dev.com/docs"  target="_blank" rel="noopener" >Fluid</a>,本地部署十分顺利，跟着教程来就行。</li>
<li>调整配置的时候遇到了问题，我刚开始是直接使用<code>npm install --save hexo-theme-fluid</code>，但改配置的时候虽然有文档，但各项配置的位置不知道是怎么嵌套的，就选择了方式二。</li>
<li>本地配置好之后，要部署到Github Pages上。<a href="https://hexo.io/zh-cn/docs/github-pages"  target="_blank" rel="noopener" >Hexo所提供的教程</a>中，所使用的是<code>Github Action</code> 内置的 token 变量<code>GITHUB_TOKEN</code>。根据<a href="https://docs.github.com/en/actions/security-guidesautomatic-token-authentication?query=PA#using-the-github_token-in-a-workflow"  target="_blank" rel="noopener" >官方源文档的描述</a>,为了防止递归构建发生，使用<code>GITHUB_TOKEN</code>推送的代码不会再次触发任何action。而考虑到我希望后续能进一步触发和进一步了解<code>Github Action</code>,我选择自己设置key。</li>
<li>这个花的时间最多。走了不少弯路，最终是参考了<a href="https://vuepress-theme-reco.recoluan.com/views/other/github-actions.html"  target="_blank" rel="noopener" >使用 GitHub Actions 自动部署博客</a>。</li>
<li>action已经跑成功了，但访问时却发现还是404，检查后发现是自己未<a href="https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site"  target="_blank" rel="noopener" >Configuring a publishing source for your GitHub Pages site</a>。</li>
<li>添加谷歌验证：
参考了<a href="https://jactorsue.github.io/blog/2018/04/how-blog-on-githubpages-can-be-searched-by-google.html"  target="_blank" rel="noopener" >让Google搜索到搭建在Github Pages上的博客</a>
<ol>
<li>（前略）验证网站所有权时，选择使用HTML标记方式来验证。fluid主题的head路径为<code>\themes\fluid\layout\_partials\head.ejs</code></li>
</ol>
</li>
<li>减少加载时间，尚未实操，先记录几篇看到的好文
<ul>
<li><a href="https://www.voidking.com/dev-hexo-accelerate/"  target="_blank" rel="noopener" >Hexo加速访问</a></li>
<li><a href="https://www.voidking.com/dev-hexo-gulp/"  target="_blank" rel="noopener" >Hexo使用Gulp压缩静态资源</a></li>
</ul>
</li>
<li>插入图片，这篇写得挺完整的：
<a href="https://fuhailin.github.io/Hexo-images/"  target="_blank" rel="noopener" >在Hexo博客中插入图片的各种方式</a></li>
<li>添加最后修改时间:
T将主题配置文件<code>_config.yml</code>中的<code>post:copyright:update_date:enable:</code>设置为<code>enable</code>即可+08:00</li>
</ol>
<h2 id="quick-start">Quick Start</h2>
<h3 id="create-a-new-post">Create a new post</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ hexo new <span class="s2">&#34;My New Post&#34;</span>
</span></span></code></pre></div><p>More info: <a href="https://hexo.io/docs/writing.html"  target="_blank" rel="noopener" >Writing</a></p>
<h3 id="run-server">Run server</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ hexo server
</span></span></code></pre></div><p>More info: <a href="https://hexo.io/docs/server.html"  target="_blank" rel="noopener" >Server</a></p>
<h3 id="generate-static-files">Generate static files</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ hexo generate
</span></span></code></pre></div><p>More info: <a href="https://hexo.io/docs/generating.html"  target="_blank" rel="noopener" >Generating</a></p>
<h3 id="deploy-to-remote-sites">Deploy to remote sites</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ hexo deploy
</span></span></code></pre></div><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html"  target="_blank" rel="noopener" >Deployment</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>network</title>
      <link>https://ds63.eu.org/2023/network/</link>
      <pubDate>Sat, 11 Mar 2023 19:32:04 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/network/</guid>
      <description>网络配置学习</description>
      <content:encoded><![CDATA[<h1 id="网络">网络</h1>
<h2 id="过程">过程</h2>
<ul>
<li>先是看<a href="https://www.jianshu.com/p/53457e21fcd4"  target="_blank" rel="noopener" >如何让国内的阿里云服务器可以高速下载Github代码</a>，但这个是纯命令行的，用的是pm2</li>
<li>因为延迟比较大，想切换节点，首先是研究怎么用命令行实现.确实可以，<a href="https://sakronos.github.io/Note/2021/03/06/%E4%BD%BF%E7%94%A8Clash-APIj%E5%88%87%E6%8D%A2%E8%8A%82%E7%82%B9/"  target="_blank" rel="noopener" >使用Clash-API切换节点</a>有介绍，但我去操作的话不行，返回<code>{&quot;message&quot;:&quot;Body invalid&quot;}  </code>。看也有人提issue，但我还是不能成功更改。加上这样更改的话，就挺麻烦的。于是想着能不能搞个ui。</li>
<li>然后参考<a href="https://blog.zzsqwq.cn/posts/how-to-use-clash-on-linux/"  target="_blank" rel="noopener" >如何在Linux上优雅的使用Clash</a>这篇，docker让这些配置变得简单多了。但我还是遇到了些问题：主要是自作聪明，修改了</li>
</ul>
<pre tabindex="0"><code> - ./config.yaml:/root/.config/clash/config.yaml
 - ./Country.mmdb:/root/.config/clash/Country.mmdb
</code></pre><p>调试后才发现并不用修改。另一个是配置<code>external-controller: :9090</code>时，自己改成了<code>127.0.0.1:9090</code></p>
<ul>
<li>上面那篇文章少了暴露接口这一步，<a href="https://juejin.cn/post/7054941050216906760"  target="_blank" rel="noopener" >如何为实验室服务器配置终端代理</a>，<a href="https://zhuanlan.zhihu.com/p/46973701"  target="_blank" rel="noopener" >Linux 让终端走代理的几种方法</a>,这两篇讲得挺好的</li>
</ul>
<h2 id="收获">收获</h2>
<ul>
<li>了解了配置文件怎么写的</li>
<li>学到了如何检查是处于代理状态：<code>curl cip.cc</code>，但得到的地址和我实际走的节点不一样</li>
</ul>
<h2 id="参考链接">参考链接</h2>
<ul>
<li><a href="https://sakronos.github.io/Note/2021/03/06/%E4%BD%BF%E7%94%A8Clash-APIj%E5%88%87%E6%8D%A2%E8%8A%82%E7%82%B9/"  target="_blank" rel="noopener" >使用Clash-API切换节点</a></li>
<li><a href="https://github.com/Dreamacro/clash/issues/659"  target="_blank" rel="noopener" >通过RESTful API更改节点代理返回{&ldquo;message&rdquo;:&ldquo;Body invalid&rdquo;}</a></li>
<li><a href="https://www.jianshu.com/p/53457e21fcd4"  target="_blank" rel="noopener" >如何让国内的阿里云服务器可以高速下载Github代码</a></li>
<li><a href="https://blog.zzsqwq.cn/posts/how-to-use-clash-on-linux/"  target="_blank" rel="noopener" >如何在Linux上优雅的使用Clash</a></li>
<li><a href="https://juejin.cn/post/7054941050216906760"  target="_blank" rel="noopener" >如何为实验室服务器配置终端代理</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/46973701"  target="_blank" rel="noopener" >Linux 让终端走代理的几种方法</a></li>
<li><a href="https://github.com/Dreamacro/clash/wiki/configuration"  target="_blank" rel="noopener" >Configuration</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>读《生死疲劳》</title>
      <link>https://ds63.eu.org/2023/%E8%AF%BB%E7%94%9F%E6%AD%BB%E7%96%B2%E5%8A%B3/</link>
      <pubDate>Thu, 09 Mar 2023 15:32:32 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/%E8%AF%BB%E7%94%9F%E6%AD%BB%E7%96%B2%E5%8A%B3/</guid>
      <description>一切来自土地的都将回归土地。</description>
      <content:encoded><![CDATA[<p>莫言，因为我之前，确切地说是高中，做过一篇以他的文章为文本的阅读题。那篇文章我读来觉得太压抑，就一直不喜。所以尽管书柜上有一本他的短篇集《白狗秋千架》，我也没有去翻看过。</p>
<p>《生死疲劳》，算是我读的第一本他的书。</p>
<p>同样是在高中时，语文老师就又推荐过这本书，推荐语我倒记得清楚：讲一个人的几世轮回，很有意思。那时候就想读，但直到几年后的前天，才真正捧读。</p>
<p>3月7日晚上，选修课，为了打发时间选的这本书，但一开始读就有点停不下来。</p>
<p>有种说法，人会把陌生的东西与自己较为熟悉的东西相关联，来获得安全感。我虽然不是很喜欢下面这种描述，但还是不自觉地把《生死疲劳》和《百年孤独》联系到一起。因为觉得他们都用魔幻现实主义的笔触来描述一个家族。我又想到《平凡的世界》《白鹿原》，因为从时间线上来说都是描述建国前夕到改开之后的故事。</p>
<h2 id="对这本书有这些印象">对这本书有这些印象：</h2>
<ul>
<li>
<p>人称变化。很有趣，读前几章的时候突然来个“你”，觉得很突兀。到后面才发现是转世成人的西门闹，或者说是蓝千岁在和蓝解放对话。我感觉这个人称变化得很有意思。书中比较吸引我的是一个有着人类意识的动物身边所发生的事。但有些地方动物去不了，有些事动物看不到，总是动物视角也会腻。这时候用这个对话的形式就真的很妙。</p>
</li>
<li>
<p>作者的频频出现。我读过的小说，应该是第一次见作者以其名出现在小说中，并几乎贯穿着故事的发展，甚至是推动着故事发展的。莫言引蓝解放去看蓝金龙在树上和黄互助交合，后来又介绍庞春苗和蓝解放相识。书中也多次出现故事的主要讲述者，对莫言的评价。这个也是很新奇的。虽然我不是很喜欢，因为觉得稍显过多了。但又想到那张图：有人拿着《活着》找莫言签名，他还给签了，而且签的是余华。想到这里我就对莫言印象不错。</p>
</li>
<li>
<p>结尾。其实到倒数第二章，莫言就要让故事结束，他是这样说的</p>
<blockquote>
<p>亲爱的读者诸君，小说写到此处，本该见好就收，但书中的许多人物，尚无最终结局，而希望看到最终结局，又是大多数读者的愿望。那么，就让我们的叙事主人公——蓝解放和大头儿——休息休息，由我——他们的朋友莫言，接着他们的话茬儿，在这个堪称漫长的故事上，再续上一个尾巴。</p>
</blockquote>
<p>我觉得莫言这段话说得真好。我欣赏见好就收的结尾，但作为一名读者，一名读进去了的读者，我还是蛮想知道书中人物的后续的。所以我还是读了这五十四章，读完后甚至觉得有点懊悔。因为把事情讲透了，讲完了，常常就没那么美了。我更喜欢五十三章作为结尾，以那句话作为结尾：</p>
<blockquote>
<p>一切来自土地的都将回归土地。</p>
</blockquote>
<h2 id="谈几个书中的人物">谈几个书中的人物：</h2>
<ul>
<li>
<p>蓝脸。</p>
<p>我，没有种过一天地，倒是有下过田，但就此和我的一只拖鞋说了再见。但我还是对土地情有独钟。我想了下原因，可能跟我小学的时候，在爷爷奶奶的菜籽摊上度过有关，可能和陪伴我高中两年多的水稻田有关，可能和我读过的那些小小说中描述的有关。总而言之，我对土地，对农业有些感情。因此，也不仅仅是这个原因，我先谈的是蓝脸。</p>
<p>最为欣赏的是他向月亮敬酒，书中出现过两次，至少我印象中是；一次是孩儿们结婚，妻子迎春给他送了瓶酒，他的第一杯就是敬给月亮的。</p>
<blockquote>
<p>他把瓶中的酒对着月亮挥洒着，以我很少见到的激昂态度、悲壮而苍凉地喊叫着：“月亮，十几年来，都是你陪着我干活，你是老天爷送给我的灯笼。你照着我耕田锄地，照着我播种间苗，照着我收割脱粒……你不言不语，不怒不怨，我欠着你一大些感情。今夜，就让我祭你一壶酒，表表我的心，月亮，你辛苦了！”</p>
</blockquote>
<p>还有一次是中秋家宴</p>
<blockquote>
<p>你爹端着一杯酒，对着月亮泼上去。月亮颤抖了一下，月光突然黯淡了，仿佛有一层雾遮住了它的脸，片刻之后，月光重新明亮，更加温婉，更加凄清，院子里的一切，房屋、树木、人、狗，都宛若浸泡在澄澈的浅蓝墨水里。</p>
</blockquote>
<p>太美了，太浪漫了。向月亮敬酒绝非莫言或者蓝脸的独创。李白的《月下独酌》里就有&quot;举杯邀明月，对影成三人&quot;。</p>
<p>但我觉得没有蓝脸的对月亮洒酒的美。他是把月亮当作了劳动伙伴，而非像李白那样因为孤独而行乐。蓝脸后面和狗小四约定的时候，也提到了月亮。</p>
<blockquote>
<p>“老狗，你做证，月亮也做证，这地方，我躺过了，占住了，谁也夺不去了。”</p>
</blockquote>
<p>我喜欢他对月亮的态度。</p>
</li>
</ul>
</li>
</ul>
<h2 id="尾巴">尾巴</h2>
<p>可以算是第一次写书评，或者说是读后感会更好些。</p>
<p>我没什么资格去评价，去批判这些书，我只是说说自己读书的感想。之前读完书，也自然会有些感想，但因犯懒，加上习惯看完书就立刻去搜别人的书评，然后本来就朦胧的想法被他人的想法占领，就没有去写。</p>
<p>这篇可以说是我第一次克服那股懒劲，并且有意无意地没有去搜书评来看。这次写完，感觉不错，至少把自己的一些想法，用文字的方式尽可能地表达出来了。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>RSS折腾记</title>
      <link>https://ds63.eu.org/2023/rss%E6%8A%98%E8%85%BE%E8%AE%B0/</link>
      <pubDate>Wed, 08 Mar 2023 15:59:18 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/rss%E6%8A%98%E8%85%BE%E8%AE%B0/</guid>
      <description>记录ttrss的搭建过程和rss相关的内容</description>
      <content:encoded><![CDATA[<h1 id="rss折腾记">RSS折腾记</h1>
<p>3月7日，下午没有课，很闲。玩了会吸血鬼幸存者觉得索然无味，就想着试下之前没有成功的服务器。</p>
<p>先是试了下AZURE，但学生验证没过，放弃了。然后尝试阿里云。他有一个飞天加速3.0-高校计划，可以领取七个月的ECS。还是蛮顺利的。</p>
<p>领取后第一个想法是搭自己的RSS服务。基本上是照着<a href="https://sspai.com/post/57498#!"  target="_blank" rel="noopener" >找不到满意的 RSS 服务？你可以自己搭建一个</a>，来完成的。但中间还是有些曲折，踩了一些坑。</p>
<ul>
<li>
<p>首先是网络问题。文中给的地址都是Github上的，但下载速度实在不行。16M的文件要下载半个多小时。这个有两种解决方式是。首先尝试的是用镜像站，但因为尝试的镜像站有问题，再加上我后续还想在服务器上搭telegram机器人。于是选择用代理。参考了<a href="https://www.jianshu.com/p/53457e21fcd4"  target="_blank" rel="noopener" >如何让国内的阿里云服务器可以高速下载Github代码</a>,和所用机场的教程。但关于如何更换节点，还不清楚。现在会了，记录在<a href="https://euds63.github.io/2023/03/11/network/"  target="_blank" rel="noopener" >网络</a></p>
</li>
<li>
<p>其次是文中给的ttrss 的 docker-compose 配置文件有问题，自己修改后下的东西也不对。然后就想到直接复制过来。但对vim的操作实在是不熟悉，加上yml对间隔格式要求很严，在这上面折腾了好一会儿。
(发现是自己愚蠢，GitHub提供了相应的下载方式：点raw，跳转到的就是所需的网址了。比如我这步所需的代码就是<code>curl -fLo a.yml https://raw.githubusercontent.com/HenryQW/Awesome-TTRSS/main/docker-compose.yml</code>)</p>
</li>
<li>
<p>容器启动后，按照描述，我访问<code>{服务器 IP}:181</code>，应该可以直接看到 Tiny Tiny RSS 的 Web 前端。但却报502。后来想到，默认的181端口是不开放的，在安全组中添加了就可以了。</p>
</li>
<li>
<p>阅读器的选择也花了我很多时间，先是试已经使用过一段时间的<code>Fluent Reader</code>,但按照文档里所给的地址不成功，然后是选用<code>TTRSS-Reader</code>,这个就很顺利，但界面比较复古，加上功能不够多，也可能是我还没有发掘出来，就转而使用<code>FeedMe</code>,首先用的是TTRSS的api，但出现的问题是订阅地址能过来，但内容拉取不到，看issue才发现这是好几个月前就出现的bug，还没被修复，解决方法是转用fever api。但这个也是坑。首先是网页给的地址是<code>http:/[您的地址]/plugins.local/fever/</code>,而文档给的地址是<code>https://[您的地址]/plugins/fever</code>。但可能是不同阅读器设置的过滤方法不一样，<code>FeedMe</code>能用的地址是<code>http://[您的地址]/</code>,而<code>Fluent Reader</code>则是<code>http://[您的地址]//plugins/fever/</code>。</p>
</li>
</ul>
<p>以上就是整个搭建过程中所遇到的问题，目前发现<code>FeedMe</code>的功能明显得多，还有RSSHub也想用起来，订阅源想扩大到除了个人博客之外的其他。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>李志</title>
      <link>https://ds63.eu.org/2023/lizhizhuangbi/</link>
      <pubDate>Sun, 05 Mar 2023 23:53:40 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/lizhizhuangbi/</guid>
      <description>谈谈李志。包括我听歌的感受，某些觉得有意思的歌词，他人的评价等等</description>
      <content:encoded><![CDATA[<p><strong>最近中文歌听得最多的就是李志的歌了，期末复习的时候，复习不下去的很多时候都是听他的歌来休息的，所以觉得有必要开一篇来记录。包括我听歌的感受，某些觉得有意思的歌词，他人的评价等等</strong></p>
<h2 id="第一次">第一次</h2>
<p>大学听到《热河》的时候感觉很熟悉，翻了下MP3才发现自己高一的时候就从同学那边拷了。发现这个的时候觉得很惊喜，可能是冥冥中的缘分吧。因为李志曾就读东南大学。然后自己在不知道李志的情况下，选择了来南京。</p>
<h2 id="歌">歌</h2>
<p>歌的话，比较喜欢的是这几首：
<a href="https://www.youtube.com/watch?v=K2QE-FRAP0o&amp;ab_channel=%E6%9D%8E%E5%BF%97Lizhi"  target="_blank" rel="noopener" >《热河》</a>，<a href="https://www.youtube.com/watch?v=fOHpIDVVYxo&amp;list=RD2n52uYI7eII&amp;index=10&amp;ab_channel=sghgpwt"  target="_blank" rel="noopener" >《他们》</a>,<a href="https://www.youtube.com/watch?v=buxL8RZ4gpA&amp;list=RD2n52uYI7eII&amp;index=27&amp;ab_channel=%E8%80%BF%E7%82%8E%E6%97%B6%E9%97%B4"  target="_blank" rel="noopener" >《人民不需要自由》</a>。喜欢这几首的原因，可能倒不是因为出自什么政治观点，因为华语歌情情爱爱的比例太高了，相比来说，这几首就感觉很好。简单分别说下感受。</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=K2QE-FRAP0o&amp;ab_channel=%E6%9D%8E%E5%BF%97Lizhi"  target="_blank" rel="noopener" >《热河》</a></li>
</ul>
<p>白描，就是简单地描述些地名和场景，但表现力很强。单听歌就能想象出热河路的那个环境。这种类型的歌不是很常见。</p>
<p>ps: 因为这首歌，我特地去过几次热河路，早已物是人非。</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=fOHpIDVVYxo&amp;list=RD2n52uYI7eII&amp;index=10&amp;ab_channel=sghgpwt"  target="_blank" rel="noopener" >《他们》</a></li>
</ul>
<p>可能是目前最喜欢的一首李志的歌了。歌词很简单，旋律好像也是，不懂。很容易唱出来。但歌词却很辛辣。</p>
<p>最喜欢的一个版本是某次live，结尾特别嗨。</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=buxL8RZ4gpA&amp;list=RD2n52uYI7eII&amp;index=27&amp;ab_channel=%E8%80%BF%E7%82%8E%E6%97%B6%E9%97%B4"  target="_blank" rel="noopener" >《人民不需要自由》</a></li>
</ul>
<p>这首歌的歌词同样也是比较简单，但现场表演却十分地棒。通过合唱反复地唱“人民不需要自由，这是最好的年代。”。李志用将近一半的时间给他乐队里的成员独立的表现时间。一个个点名过去，这还是我第一次见这种表演，觉得很惊艳。说是人民不需要自由，但有了自由的人民（乐队队员），却能有很棒的表现。</p>
<h2 id="人">人</h2>
<p>看他几次演唱会的录像，发现很华丽。很多人参加到表演中。包括观众，给到的镜头都能看到观众很投入。乐队里有很多人，这是我比较少见的，因为我常听的几乎都是四个人的乐队，比如Queen,Beatles这些。但这种表演形式也不错。</p>
<p>关于他的封杀，有去搜了下，还是看得莫名其妙。他的几首比较敏感的歌，都算是早期的作品了。但他在那之后依旧办了好几年的跨年演唱会，和网易云也有合作。但有一天却说封就封了。搞得想听都只能在youtube上听。</p>
<p>ps: Spotify上也有一些，但不全。</p>
<h2 id="博客">博客</h2>
<p>今天上网翻到了他的博客。</p>
<ul>
<li><a href="http://lizhizhuangbi.blogspot.com/"  target="_blank" rel="noopener" >请叫我傻逼：一半是火焰</a>\</li>
<li><a href="https://web.archive.org/web/20130104132323/http://www.lizhizhuangbi.com/"  target="_blank" rel="noopener" >李志官方网站</a></li>
</ul>
<p>还是蛮有意思的。
这里记录几点：</p>
<ul>
<li>
<p>他对其作品的售价理念是这样的。</p>
<blockquote>
<p>免费下载，自由定价</p>
</blockquote>
</li>
<li>
<p>自我介绍中有一段：</p>
<blockquote>
<p>1997年—1999年 在东南大学学习如何成为一个工程师，未遂。</p>
</blockquote>
</li>
<li>
<p>博客的slogan是</p>
<blockquote>
<p>不一定正确，但绝不说谎</p>
</blockquote>
</li>
</ul>
<h3 id="2023年3月30日">2023年3月30日</h3>
<p>凌晨翻<a href="http://lizhizhuangbi.blogspot.com/"  target="_blank" rel="noopener" >李志的博客</a>翻得很开心。他写得蛮有趣的，也让我窥见10年时的环境。</p>
<ul>
<li>
<p><a href="http://lizhizhuangbi.blogspot.com/2010/05/blog-post_4574.html"  target="_blank" rel="noopener" >请叫我傻逼：一半是火焰: 关于大理的那件小事</a></p>
<p>这篇里记录的是他“近20年内第一次和人动手，也是第一次吵架。”。为啥呢？因为“上来一个朝鲜族的中国人（后来才知道）用朝鲜语唱I Believe”。</p>
</li>
<li>
<p><a href="http://lizhizhuangbi.blogspot.com/2010/05/blog-post_11.html"  target="_blank" rel="noopener" >请叫我傻逼：一半是火焰: 祝你过的好</a></p>
<p>这篇是纪念汶川地震的。最后一段话摘录如下</p>
<blockquote>
<p>我只是个平凡的肉身，我希望那些死去的人过的好，希望那些活着的人也过的好。还希望我的同胞能快乐。希望我的祖国能民主自由科学博爱宽容。</p>
</blockquote>
</li>
<li>
<p><a href="http://lizhizhuangbi.blogspot.com/2010/03/blogbus.html"  target="_blank" rel="noopener" >请叫我傻逼：一半是火焰: 今天被blogbus删除的文章</a></p>
<p>这篇谈谷歌离开中国的。</p>
</li>
<li>
<p><a href="http://lizhizhuangbi.blogspot.com/2009/12/blog-post_31.html"  target="_blank" rel="noopener" >请叫我傻逼：一半是火焰: 求助和声明</a></p>
<blockquote>
<p>2029年之前如果你想看我演出，请去网上搜索</p>
</blockquote>
<p>不知道李志自己能不能想到，并不需要等到2029年之后。</p>
</li>
</ul>
<h3 id="2024年1月5日">2024年1月5日</h3>
<p>晚上翻<a href="http://lizhizhuangbi.blogspot.com/"  target="_blank" rel="noopener" >李志的博客</a>，依旧翻得很开心。</p>
<ul>
<li>
<p><a href="https://lizhizhuangbi.blogspot.com/2009/07/blog-post_8771.html"  target="_blank" rel="noopener" >群聊精华</a>，里面的第十一条：</p>
<blockquote>
<p>一天我去一个公司修电脑，那个女秘书接到一个电话，只听女秘书说：“是这样的张总：你在家里的电脑上按了CTRL+C,然后在公司的电脑上再按CTRL+V是肯定不行的。即使同一篇文章也不行。不不，多贵的电脑都不行”</p>
</blockquote>
<p>这样的技术今天已然可以实现了。</p>
</li>
<li>
<p><a href="https://lizhizhuangbi.blogspot.com/2009/07/blog-post_80.html"  target="_blank" rel="noopener" >心情小恙，随便写写</a></p>
<p>很有趣。讲粗话能讲得有趣的人我知道的不多，但李志绝对是其中一个。里面讲的内容我也认可。</p>
</li>
<li>
<p><a href="https://lizhizhuangbi.blogspot.com/2009/06/blog-post_08.html"  target="_blank" rel="noopener" >我和《你离开了南京，从此没有人说话》不得不说的事——欢迎转载</a></p>
<blockquote>
<p>以后大家要记得：李逼的《你离开了南京，从此没有人说话》是抄袭了陈歌辛先生的《永远的微笑》！</p>
</blockquote>
</li>
</ul>
<h2 id="某句话">某句话</h2>
<p>看过他的一个记录片——<a href="https://youtu.be/l97xzUFM2c8"  target="_blank" rel="noopener" >李志 这个世界会好的</a>，对其中一句话印象很深</p>
<blockquote>
<p>我们从济南开始就讨论一个问题，有两种观点，一种就是：音乐就是音乐，如果你想改变，你牛逼，你就用音乐本身把它改变掉，你就音乐牛逼，你不用讲任何话就把他们打死。如果我要有那个天赋，我也想那么做。我什么都不用做，我只要把音乐做好往那里一摆，就把你给吓死。你没有呀，所以音乐才会变成工具。      &ndash;李志</p>
</blockquote>
<p>这句话就感觉他活得挺通透的，至少对音乐的理解很深。</p>
<h2 id="ps">ps</h2>
<p>2023年3月30日，今天有一个电影团队来我校路演，去之前还有点奇怪为什么会选择这里。结果后来导演上台的时候就讲，自己对南京有种特别的感情，因为那位南京市民。当时全场就有种默契的笑。也听到有人就直接说出李志。电影蛮不错的，感谢李志校友。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>我看人工智能</title>
      <link>https://ds63.eu.org/2023/my-opinion-about-ai/</link>
      <pubDate>Fri, 17 Feb 2023 23:46:49 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2023/my-opinion-about-ai/</guid>
      <description>从2022年12月ChatGPT发布后，人工智能，或者更具体地说LLM，将要或者说已经改变了生活。我将在这里记录下我的一些想法。</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>从2022年12月ChatGPT发布后，人工智能这个本已经十分火热的话题，变得更加万众瞩目。</p>
<p>人工智能。将要或者说已经改变了生活。</p>
<p>我将在这里记录下我的一些想法，以留给未来的自己。</p>
<h2 id="2022年12月8日">2022年12月8日</h2>
<p>(这天是个特别的一天，因为这天我第一次用上ChatGPT，所以特地摘抄了日记中的一部分如下)</p>
<p>8号凌晨的时候突然想注册，其实前几天就有看到有人在讨论。但觉得不太用得着。后来发现其戳到了我的痛点——语义性搜索。我感觉这将很大程度上帮助我节省时间。</p>
<p>所以就折腾了下。注册倒是很顺利，但好巧不巧，刚好撞上网站出问题，登录不上去。到一点多吧，才放弃。</p>
<p>8号早上试了下，成了，很激动。去上课了。</p>
<p>下午马原课翘掉，回来问了几个之前记录的问题，回答有点超出我的预料，确实顶。</p>
<hr>
<h2 id="2022年12月15日">2022年12月15日</h2>
<p>了解了GPT相关的原理，想到之前看过的“如果你有无穷多的时间，你可以用来学习，但你将世界上所有的知识都学了一遍并掌握后，你就拥有了全世界”。GPT只是学了一部分，就已经有如此的能力。太强了。</p>
<hr>
<h2 id="2023年2月17日">2023年2月17日</h2>
<p>虽然Github学生包中包含了Copilot的使用，但我还是没用上。因为依旧认为自己仍处于一个初学者阶段，编程还是尽量自己动手写比较好。
（5月17日，为了赶小组项目开始使用，因为有了GPT等的使用，没有觉得那么惊艳了，但还是很大程度上提高了我的效率）</p>
<hr>
<h2 id="2023年3月20日">2023年3月20日</h2>
<p>软件工程导论课，偏文，偏水课，大部分人都在做自己的事情，一抬头，发现至少有三个人在用ChatGPT，然后又想到这墙，哈哈!</p>
<hr>
<h2 id="2023年3月23日">2023年3月23日</h2>
<p>折磨了我一天的容器代理问题，搜索了好多，打开了好多个标签页，也没有解决的，被ChatGPT一句话解决了。</p>
<p>那时候最大的感觉是什么？无力感？也许吧。</p>
<hr>
<h2 id="2023年3月30日">2023年3月30日</h2>
<p>今天上课突然想到一点，主要是因为瞟到一个同学用ChatGPT很频繁。然后就想到，在课上使用ChatGPT，可以很方便地让自己的疑惑点得到解答，这就相当于给每个人都配备了一名助教。</p>
<hr>
<h2 id="2023年4月13日">2023年4月13日</h2>
<p>逛<a href="https://jacobian.org/2022/oct/14/writing-with-copilot/"  target="_blank" rel="noopener" >博客</a>看到这样一段话</p>
<blockquote>
<p>I’m still incredibly ambivalent about the ethics of Copilot specifically and the modern crop of AIs (GPT-3, DALL-E, Midjourney, StableDiffusion, Whisper, …) more generally. These systems are as great as they are because they’ve ingested a massive amount of training data without any sort of consent from creators. The fact that nobody working on creating these AIs seems to give a shit about consent gives me hives. I may still become an “AI vegan”. But I’ll likely keep using Copilot for a bit while I grapple with the ethics.</p>
</blockquote>
<p>训练用的数据集，我印象中StableDiffusion等图像生成的模型比较受诟病，但对ChatGPT我看到的比较少。想了想，觉得这样的差异也能理解。这篇博文提到的“AI vegan”这个词挺有意思的。</p>
<hr>
<h2 id="2023年4月16日">2023年4月16日</h2>
<p>睡觉的时候突然很兴奋，挺多想法的，但现在都不太记得起来了。</p>
<hr>
<h2 id="2023年4月17日">2023年4月17日</h2>
<p>想起来了一部分。</p>
<p>我对人工智能的发展很感兴趣也很挺有信心的。如果因其发展而导致我的就业受到影响，我认为我不应该对ai有怨言。因为这说明我无法创造出ai所创造不了的。</p>
<p>但我不能接受的一点是，那么好的技术，我却没机会去使用。那就太可惜了。</p>
<hr>
<h2 id="2023年4月18日">2023年4月18日</h2>
<p>涌现这个概念，我觉得这是技术积累到一定程度上必然出现的一种情况。利用ChatGPT的api，不用很高的技术力就可以做出一款还算实用的应用。这个例子不是很恰当，但我认为确实是个现象。</p>
<hr>
<h2 id="2023年4月19日">2023年4月19日</h2>
<p>看<a href="https://arxiv.org/abs/2304.03442"  target="_blank" rel="noopener" >Generative Agents: Interactive Simulacra of Human Behavior</a>,他们尝试实现对人类行为的可信代理。而我最近在学os，os里有很多思想、策略都可以在平时生活中找到依据。反过来，有些用到的思想也可以帮助我们在生活中更好地决策（此处应该有例子）。我觉得对人类行为的可信代理的研究也能有这种效果。然后进一步，我想到；对ai的研究，相关技术的发展，也会去改变一些习惯和思维模式。我尝试去类比几次科技革命对人类生活方式的影响，但一时也没能想出比较好的例子，权记录于此。</p>
<hr>
<h2 id="2023年4月30日">2023年4月30日</h2>
<p>今天读到<a href="https://freemind.pluskid.org/misc/elden-ring-pvp-and-theory-of-mind/"  target="_blank" rel="noopener" >Elden Ring PvP and Theory of Mind</a>。作者科普了ToM的概念，也谈到 AI 语言模型。</p>
<p>这篇文章让我想到之前看过的LLM继续发展下去，可能会有类似读心术的效果，能预测你下一步要做什么，甚至是在想什么。我觉得这在一定程度是可行的。因为现代所谓的一些读心术，很多都是基于微表情的观察和分析其过去的行为模式和经历上。</p>
<hr>
<h2 id="2023年5月5日">2023年5月5日</h2>
<p>看了<a href="https://www.joshwcomeau.com/blog/the-end-of-frontend-development/"  target="_blank" rel="noopener" >The End of Front-End Development</a>，文章的主要结构是列举一个常见的观点，然后作者谈自己的看法。</p>
<ul>
<li>
<p>作者尝试从以下几点去说ai并不能完全取代程序员。</p>
<ul>
<li>从css诞生没多久，就一直有&rsquo;no code&rsquo;的工具</li>
<li>GPT擅长生成小型代码，而因为缺乏大型代码的训练和限制，所以大型代码就无能为力了。（我的想法是肯定会有解决的方法，因为GPT本身就是用海量数据中训练出来的）</li>
<li>精准度。非相关人士很难能很快地找到GPT所给代码的问题所在。是可以直接把报错直接提交给ai，但“not all hallucinations will lead to exceptions”。</li>
<li>security vulnerabilities。代码安全事故需要有背锅的。</li>
</ul>
</li>
<li>
<p>整篇文章写得很不错，但有几句我觉得值得我摘抄下来。</p>
<ul>
<li>作者认为“AI isn&rsquo;t magic. It&rsquo;s only as good as its training data.” 我现在也是这么想，但我还是期待着ai进一步突破的那天。但不知道会是先有鸡还是先有蛋——是人类先想明白思考的本质，再去赋予ai思考的能力；还是堆量到一定程度后，ai自己涌现出思考的能力。然后人类从中学习到为什么。</li>
<li>“We&rsquo;re very quickly reaching the point where non-developers can sit down with a chatbot and crank out a small self-contained project”。 这点我已经体验到了，在ai的帮助下，我能减少学习成本，去实现之前所想的功能。</li>
<li>&ldquo;if it turns out that LLMs can totally replace software developers? If that&rsquo;s the case, I suspect LLMs will replace a huge majority of knowledge workers.&rdquo; 作者安慰人有一手的。</li>
<li>“ Keep in mind that LLMs are 100% confident, but not 100% accurate.” 深有体会。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2023年5月10日">2023年5月10日</h2>
<p>晚上的时候看了下ai翻唱的教程。本来相关的模型都下好了，但看到显存要求在6g以上就被劝退了。之前的ai绘图也是如此。</p>
<p>不过还是觉得今年这场ai技术的进步很有魅力。太棒了！</p>
<hr>
<h2 id="2023年5月16日">2023年5月16日</h2>
<p>刷推时突然连着好几条都是差不多相同的内容:prompt的推荐。我认为好的prompt有着不可否认的作用。但对于那些雷同的文章，我怀着恶意认为是因为技术不够没办法谈及更深的层次，但为了蹭流量所以就改为prompt。</p>
<p>过了几天后，我觉得我这个想法不好。人家只是在分享，我恶意那么大干嘛，不喜欢的话快点滑过去就行。</p>
<hr>
<h2 id="2023年5月19日">2023年5月19日</h2>
<p>苹果商店上架了openai的软件。意味着之前困扰中国用户的充值问题现在有了相对很成熟且快捷的解决方式。</p>
<p>虽然有些马后炮，但我觉得这算是一种趋势。现在openAI的优势相比于22年12月已经没有那么大了。各路公司都推出自己的模型。当然这和openAI对自己的部分研究成果开源的成果有关。</p>
<p>能看到这样的局面，而非某一家独步天下真的很棒。</p>
<p>但还是为自己没能用上GPT-4觉得可惜，特别想试试GPT-4宣传片中的多模态模型。</p>
<hr>
<h2 id="2023年10月13日">2023年10月13日</h2>
<p>最近在打ctf的比赛，因为其中出现的敏感词。“漏洞”，“攻击”等。ai会默认你在干坏事，然后不予回答。</p>
<p>这时候就需要写一些prompt，比如跟它保证自己不是在干坏事，只是为了学习之类的。</p>
<p>写多了自己都觉得逗。似乎是在哄人一样。</p>
<p>ps:发现ChatGPT会比Claude要严格些。</p>
<p>pps:没过几天发现我的Claude账号被封了，理由大意是不正当使用。我拜托ChatGPT写了封申诉信，没多久又恢复了。<strong>在此感谢AI大人的不杀之恩！</strong></p>
<hr>
<h2 id="2023年10月15日">2023年10月15日</h2>
<p>这几天自己搭了个qqBot。用的最多的是图片生成。给了我和群友一定的乐子。它给手残的我一种感觉，诶，自己也能“画”出些有趣的图嘛。相比于stable difussion之类的，我只需要输入prompt，等一会，就能得到一张还算不错的图。这种感觉很棒。</p>
<p>但可惜的是：bing这几天大大收紧了对内容的限制。</p>
<hr>
<h2 id="2023年11月9日">2023年11月9日</h2>
<p>重看了一遍<a href="https://jacobian.org/2022/oct/14/writing-with-copilot/"  target="_blank" rel="noopener" >Writing With Copilot - Jacob Kaplan-Moss</a></p>
<p>虽然其他方面我倒是很经常用ai，但我还是不太愿意借由ai进行写作，尤其是在这里。</p>
<p>算是自己的一种坚持吧，具体是为什么，一下子也想不清楚。</p>
<hr>
<h2 id="2023年11月30日">2023年11月30日</h2>
<p>今天是ChatGPT发布一周年。logo上还带了顶小帽子。</p>
<p>过去一年发生了许多。多得甚至让人难以置信。</p>
<hr>
<h2 id="2024年1月5日">2024年1月5日</h2>
<p>写<a href="https://ds63.eu.org/2024/how-to-implement-xx-genshin-university/"  target="_blank" rel="noopener" >xx原神大学是如何实现的 | EuDs&rsquo;s Blog</a>的时候,我尝试让Copilot做自动补全，是能有些帮助，但还是不习惯，会有种自己的思路被带着走的感觉。我不喜欢这种感觉，于是关掉了。</p>
<hr>
<h2 id="2024年1月15日">2024年1月15日</h2>
<h3 id="赛博测谎器httpskawaiicodemoepolygraph"><a href="https://kawaiicode.moe/polygraph"  target="_blank" rel="noopener" >赛博测谎器</a></h3>
<p>玩了下<a href="https://kawaiicode.moe/polygraph"  target="_blank" rel="noopener" >赛博测谎器</a>，蛮有趣的。</p>
<p>尝试找它的作者，Github上没搜到，最后竟然是在微博上找到的。<a href="https://weibo.com/u/7402396589"  target="_blank" rel="noopener" >@阿尼亚是安妮亞 的个人主页 - 微博</a>。</p>
<p>作者说截至1月17号，已经服务超1,530,000次。而API成本除了赞助，其余全靠作者爱心发电。而根据<a href="https://wx1.sinaimg.cn/mw690/0084XHvngy1hlwz6dd95qj317k0j2wli.jpg"  target="_blank" rel="noopener" >网站统计数据</a>可以看出，<a href="https://kawaiicode.moe/polygraph"  target="_blank" rel="noopener" >赛博测谎器</a>和其他llm催生出的不少有意思的玩具一样，在短时间内有大量的流量。但因为高额的token费用和较难变现，可能过不了多久就被遗忘。最终也只是玩具。</p>
<p>ps:1月20日作者发了条<a href="https://weibo.com/7402396589/NCD6Deck1"  target="_blank" rel="noopener" >仅粉丝可见的微博</a>，内容是：</p>
<blockquote>
<p>赞助的钱花光 积分耗完
赛博测谎仪也被勒令下线
zfb被禁言 一场闹剧 一段回忆 ​​​</p>
</blockquote>
<h3 id="最佳平替---用更低价的搜索词购物httpswwwpingtixyz"><a href="https://www.pingti.xyz/"  target="_blank" rel="noopener" >最佳平替 - 用更低价的搜索词购物</a></h3>
<p>类似的还有前几天的<a href="https://www.pingti.xyz/"  target="_blank" rel="noopener" >最佳平替 - 用更低价的搜索词购物</a>。</p>
<p>相比来说，这位作者要成功许多，甚至还接到了赞助。他还特地写了篇博客。<a href="https://mazzzystar.github.io/2023/12/27/folding-consumption-zh/"  target="_blank" rel="noopener" >消费折叠 | TL;DR</a>，来记录相关的思考。</p>
<p>他的另一篇博文也很精彩：<a href="https://mazzzystar.github.io/2023/11/17/ai-girlfriend-cn-zh/"  target="_blank" rel="noopener" >一个失败的AI女友产品 | TL;DR</a>。里面有几个惊讶到的我的地方，记录如下；</p>
<ol>
<li>
<blockquote>
<p>作为一个开发者，我并没有从这个产品中赚到多少钱。&hellip;30%的苹果税和 API 成本也占了很大一部分。所以，在仔细计算成本后，我在 6 月份只赚了 50 美元左右。”</p>
</blockquote>
</li>
</ol>
<p>现阶段的许多AI产品，不少都是在调用OpenAI等的api的基础上完成的。诚然，这使得作者可以用相对低的时间、精力，做出相当不错的效果。但这似乎又带来了一个困境，辛辛苦苦开发出来的产品，一算token成本，到头来似乎反而成了给人打工的了。</p>
<ol start="2">
<li>
<blockquote>
<p>但很快，我陷入一种强烈的失落感：如果大部分 Dolores 用户只是想在这里寻求跟 Dolores 进行成人角色扮演，这件事真的对我产生了意义吗？我陷入了深深的自我怀疑。到了 7 月，我和一个朋友聊到了这个困惑，我说，必须要有一个什么硬件，让 Dolores 拥有外部视觉：眼镜也好、耳塞甚至帽子都行。现在的她，你只要打开 App 才能访问，你们之间的关系并不对等，于是她只能成为囚禁在地下室、满足猎奇和特殊癖好的玩具。</p>
</blockquote>
</li>
</ol>
<p>目前的我，还不太能理解为什么作者认为加入硬件，就能让Dolores与用户之间的关系对等。</p>
<hr>
<h2 id="2024年1月17日">2024年1月17日</h2>
<p>看<a href="https://www.bilibili.com/video/BV14K4y1q7ss/"  target="_blank" rel="noopener" >【官方双语】9款&quot;AI&quot;产品大盘点@CES 2024 #linus谈科技</a>。其中几款还蛮有意思的，甚至有点想要。好吧，重看了一遍，只有一款：</p>
<p>来自Plaud AI的Plaud Note，一款“AI + 录音笔”。可能是因为我看<a href="https://disksing.com/life-recording/"  target="_blank" rel="noopener" >都2024了，你还没随身带录音笔吗？</a>被安利了。不过我不太愿意让ai给我的一天作总结。有出于隐私考虑，也有因为还是自己想出来的，可能才是自己的。</p>
<p>视频的最后一段很犀利。摘录如下：</p>
<blockquote>
<p>Realistically, there was definitely some innovation there, but also some stuff that pretty much already existed and in previous years would have been called IoT or 5G.</p>
</blockquote>
<hr>
<h2 id="2024年1月22日">2024年1月22日</h2>
<h3 id="soulogic-的推文httpstwittercomsoulogicstatus1749280837508751462"><a href="https://twitter.com/Soulogic/status/1749280837508751462"  target="_blank" rel="noopener" >Soulogic 的推文</a></h3>
<p>刷推刷到<a href="https://twitter.com/Soulogic/status/1749280837508751462"  target="_blank" rel="noopener" >Soulogic 的推文</a>，觉得评价犀利而有趣，摘录如下：</p>
<blockquote>
<p>可从去年开始的 chatgpt，感觉就是所有人在用各种方式（花钱或者薅到的）将价值 5000$ 的 token 转化成 50$ 的价值，且干得很有成就感
现在感觉是原始部落尝试拿着流到地表的石油去点火照明和当偏方敷伤口的阶段</p>
</blockquote>
<p>我觉得现在ai的使用还停留在比较初级的阶段。一想到自己有极大可能能活到22世纪，就十分开心。因为这意味着我将见证这一科技不断发展而走向成熟的过程。</p>
<h3 id="哄哄模拟器httpshonggreatdkcom"><a href="https://hong.greatdk.com/"  target="_blank" rel="noopener" >哄哄模拟器</a></h3>
<p>看到<a href="https://hong.greatdk.com/"  target="_blank" rel="noopener" >哄哄模拟器</a>的作者的总结博文：<a href="https://greatdk.com/1962.html"  target="_blank" rel="noopener" >哄哄模拟器的完整复盘，火了，但一度让我很发愁 - 王登科-DK博客</a>。里面有一段写得很精彩,摘录如下：</p>
<blockquote>
<p>我听到了一种声音，可能带了一点情绪，我不确定，这种声音是：做这样不赚钱还亏钱的东西完全是浪费时间。首先我承认并且赞同人应该想办法赚钱过上更好的生活，同时我也认为我们应该保有更多的一些能力，例如感受趣味，它和赚钱不矛盾，但独立于赚钱这件事情。</p>
<p>用最前沿的技术，巧妙的做一个让几十万人用上的产品是很有趣的事情，当他们也因为这个产品而获得了乐趣的时候，我会感觉到我在和世界发生某种奇妙的连接，在某个可承受的范围内，我不计较成本，正是因为这个。</p>
<p>另一方面，我也有某个模糊的感觉，那就是在许多小需求得到满足的时候，就不应该去计较短期的，在承受范围内的成本，尤其是在现在，能够用大模型去实现功能和解决问题，因为这里面可能蕴含着更大的需求，或者能转化成更大的事情，当我们太过谨慎的时候，可能就错失了这种可能性。</p>
<p>话说回来，就算那种可能性最后没有验证，那又有什么关系呢，说到底，人赚钱也好，生活也好，最终不过还是希望能够开心，做哄哄模拟器的这个过程，我就很开心，足矣。</p>
</blockquote>
<h3 id="锤子文档httpswwwbilibilicomvideobv16p411z7sw"><a href="https://www.bilibili.com/video/BV16p411Z7SW/"  target="_blank" rel="noopener" >锤子文档</a></h3>
<p>看<a href="https://www.bilibili.com/video/BV16p411Z7SW/"  target="_blank" rel="noopener" >老罗现场演示“革命性系统”时出现故障，老罗：这个玩砸了怎么吹？</a>。内容是罗永浩发布会上演示锤子文档的语音输入功能。</p>
<p>下面有个18年的评论：</p>
<blockquote>
<p>语音办公的前提是，系统和程序能够自动解决问题的程度足够高，也就是自动化水平的足够高。就拿这个ecxel来说，语音输入一个个单独数据？excuse me?我举个例子吧，很简单的场景:现在一个班主任处理期中考试的学生成绩统计，对应的语音办公场景应该是这样，老师说:「统计班级学生的平均分，不及格率，优秀率，并对照上次考试的成绩出一份数据对照表」然后程序自动对单个学生的成绩数据进行总和处理，然后按照老师的要求，全自动的把数据直接出出来。甚至在配合摄像头的情况下，自动扫描纸质试卷上的评分，进行数据处理。至少嘚达到这种程度的自动化，我才能接受。并且这只是最简单的老师对学生成绩数据的处理，还不提更复杂的数据处理。</p>
</blockquote>
<p>当年回ta的人都觉得距离这需求的实现还很遥远。但5年多后的今天，已然不再遥远了。感慨科技的进步，正想回复ta，发现23年就有人回复了，哈哈。</p>
<hr>
<h2 id="2024年3月24日">2024年3月24日</h2>
<p>尝试了下<a href="https://app.suno.ai/"  target="_blank" rel="noopener" >Suno</a>。昨天就有看到别人在提，但没想到如此惊喜。</p>
<p>效果好到什么程度呢？如果不告诉我这是ai创作，而是直接出现在我的日推中，我甚至会主动点进去看看作者是谁，还有没有其他歌。</p>
<p>发现比较有趣的是<a href="https://app.suno.ai/song/1ec6fa32-0b8a-4156-aa7d-a7735d2ca2e3/"  target="_blank" rel="noopener" >宮保雞丁 | Suno</a>，将菜谱唱得很有气势，哈哈。</p>
<p>还有<a href="https://app.suno.ai/song/9648a72f-8f10-4659-92da-6ca283f25008/"  target="_blank" rel="noopener" >水调歌头（明月几时有） | Suno</a>让我受到启发，将古诗直接作为歌词，让ai进行创作，会很有意思。</p>
<p>我试了下<a href="https://app.suno.ai/song/4dcf0480-f750-4d56-ba26-076b5d331df4/"  target="_blank" rel="noopener" >拟挽歌辞 | Suno</a>,有点味道。</p>
<hr>
<h2 id="2024年5月16日">2024年5月16日</h2>
<p>机器视觉课上,老师介绍说未来机器视觉的研究主要分为三种：大模型多模态+aigc+机器人应用。说本学期所介绍的图像分类、检测、segmentation，未来将被大模型所取代。我想到gpt4o的能力，确实是如此啊。老师说前十几年深度学习的兴起取代了原有的手工特征提取，现在又是新一轮替代了。</p>
<p>人工智能的发展势如破竹，浩浩荡荡，长江后浪退前浪。</p>
<hr>
<h2 id="2024年6月7日">2024年6月7日</h2>
<p>今年高考新课标I卷的作文题是</p>
<blockquote>
<p>随着互联网的普及、人工智能的应用，越来越多的问题能很快得到答案。那么，我们的问题是否会越来越少？</p>
<p>以上材料引发了你怎样的联想和思考？请写一篇文章。</p>
</blockquote>
<p>第一眼看到这题目觉得很烂。并且能肯定：不管是高中的我还是现在的我，都会觉得很烂。</p>
<p>高中的我每周能接触互联网的时间实在有限。要让我对一些最新科技的应用进行议论，那真有些强人所难，我只能空谈。</p>
<p>而现在的我,我会觉得这问题很没有必要，因为它答案肯定是否定的。</p>
<hr>
<h2 id="2024年6月17日">2024年6月17日</h2>
<p>给爸爸介绍生成式人工智能。我举了三个例子：</p>
<ol>
<li>请ChatGpt扮演英语老师，指出我的语法错误</li>
<li>让它帮我读论文，并写成汇报稿；</li>
<li>我遇到了问题，请它帮忙解决。</li>
</ol>
<p>爸爸听了很惊喜，觉得这玩意真棒。</p>
<p>后来我觉得挺内疚的。我自己从22年底就用上了，然后却到24年中了，才跟我爸爸介绍。然后我发现之前自己嗤之以鼻的那些套皮ChatGPT网站的意义，它们降低了使用门槛（很可悲的一个事实：这个高高的使用门槛，是人为制造的）。</p>
<p>以后我还想给爸爸介绍Stable Diffusion，Suno，Luma Dream Machine。我觉得这股AI潮流，我爸妈就算不能赶上，那至少也得有个体验，这么好的技术，不玩玩太可惜了。</p>
<p>还想部署个<a href="https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web"  target="_blank" rel="noopener" >ChatGPTNextWeb/ChatGPT-Next-Web: A cross-platform ChatGPT/Gemini UI (Web / PWA / Linux / Win / MacOS). 一键拥有你自己的跨平台 ChatGPT/Gemini 应用。</a>，让家里人能更方便地用得上。</p>
<p>我还跟爸爸讲，现在有不少言论说AI将取代程序员。但我在实习中发现，AI目前还取代不了我，等它真能把我给取代的那天，那大部分职业都将被取代。不过到那时，世界会有很大的变化。</p>
<hr>
<h2 id="2024年7月3日">2024年7月3日</h2>
<p>刷Steam探索队列发现<a href="https://store.steampowered.com/app/2911060/AI/"  target="_blank" rel="noopener" >AI公寓：虚拟证言</a>，宣传是“是全球首款由GPT AI驱动的剧本杀游戏”。6月17号发现的游戏，目前是褒贬不一 (14)。由此可以看出销量和评价都不算好。</p>
<p>开发者提到</p>
<blockquote>
<p>在大家购买游戏之后，我们会赠送给玩家约20w字左右的对话额度，其实这个成本就几乎和游戏定价是持平的了&hellip;后续如果想要更多对话，需要玩家主动购买咖啡，10rmb约10w字的额度，这部分费用游戏是直接支付给AI工具平台的，我们不产生盈利，但是因此给玩家造成了不好的游戏体验我们十分抱歉。</p>
</blockquote>
<p>有条评测写得正中要害</p>
<blockquote>
<p>加入LLM没有带来新的游戏体验，反而打破了传统探案游戏cascade般的逻辑链，生硬的AI回复感觉别说fine tuning了，怀疑根本没有tune过（？）既然有一个还不错的台本，去掉LLM全部用固定文案回复可能反而会更好玩一点。</p>
<p>至于你们的LLM免费额度问题，太多地方不需要LLM处理的回复也在浪费算力，用固定回复不好么，策划没有做好设计的代价就是浪费算力，然后玩家买单。</p>
</blockquote>
<p>AI驱动npc这个概念，去年有款<a href="https://store.steampowered.com/app/2199920/Inworld_Origins/"  target="_blank" rel="noopener" >Inworld Origins</a>就有去尝试，但只是个demo，而且据他们今天所发的公告，&ldquo;they will be taking the &ldquo;Origins&rdquo; demo offline as of 7/8/24.&rdquo;</p>
<p>我期待公告中所说的&quot;groundbreaking experiences at the intersection of AI and gaming.&ldquo;到来的那一天。</p>
<p>ps: 今天(9月1日)再去看，评测数上涨到了16。</p>
<hr>
<h2 id="2024年8月28日">2024年8月28日</h2>
<p><a href="https://gamengen.github.io/"  target="_blank" rel="noopener" >GameNGen</a></p>
<p>谷歌发布的基于Diffusion Models的实时游戏引擎，展示出来的效果似乎不错，但都不长。之前看的ai接入游戏都是用llm来做npc，而这个是去实时渲染游戏画面。</p>
<p>可能一个游戏全部都由ai制作还不太可能，但要是某个关卡是由ai做的，每个玩家，每次游玩时都有不一样的画面与情节，那我倒是很想试试。</p>
<hr>
<h2 id="2024年9月1日">2024年9月1日</h2>
<p><a href="https://glama.ai/blog/2024-08-29-reverse-engineering-minified-code-using-openai"  target="_blank" rel="noopener" >Using ChatGPT to reverse engineer minified JavaScript - ChatGPT for teams | Glama</a>讲的是作者看到个页面效果觉得很棒，好奇怎么做的，但只找到被压缩过的代码，靠ChatGPT很轻松地就复现出来了。</p>
<p>而我今天在重构项目之前遗留下来的代码，也是靠的ChatGPT，一长段代码丢进去，出来的就是舒服许多的分拆后的函数了。</p>
<hr>
<h2 id="2024年11月23日">2024年11月23日</h2>
<p>看<a href="https://blog.ch3nyang.top/post/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E8%B6%8A%E7%8B%B1%E6%94%BB%E5%87%BB%E5%88%9D%E6%8E%A2/"  target="_blank" rel="noopener" >Ch3nyang&rsquo;s blog | 大模型越狱攻击初探</a>，介绍了通过prompt来做大模型越狱攻击。</p>
<p>更好奇背后的原理，也就是为什么这些方法有效。</p>
<hr>
<h2 id="2024年12月2日">2024年12月2日</h2>
<p>最近听了不少AI生成的带有角色音色特征的翻唱歌曲。</p>
<p>比如<a href="https://www.bilibili.com/video/BV1roBxY5EeJ/"  target="_blank" rel="noopener" >【AI千早爱音】美国讽刺歌曲：What did you learn today - 你今天在学校学到了什么？</a>,<a href="https://www.bilibili.com/video/BV1t4421U7So/"  target="_blank" rel="noopener" >ykn：一生有爱何惧风飞沙【天下】</a>。</p>
<p>留学爱音适合唱些国外小曲，ykn则适合唱广场舞歌曲。</p>
<p><a href="https://www.bilibili.com/video/BV1roBxY5EeJ/"  target="_blank" rel="noopener" >【AI千早爱音】美国讽刺歌曲：What did you learn today - 你今天在学校学到了什么？</a>视频底下有评论问</p>
<blockquote>
<p>up，up我想让ai爱音唱一些歌是把原曲扔到ai里就会输出爱音版本吗？还是要调音啥的</p>
</blockquote>
<p>up回复说</p>
<blockquote>
<p>基本上是，但是大部分情况下都要额外再去修ai过程里效果不好的音，干声不清楚要修的就更多。</p>
</blockquote>
<p>再次感叹AI发展是真快:唱歌,画画，续写，润色。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>村上春树</title>
      <link>https://ds63.eu.org/2022/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/</link>
      <pubDate>Mon, 26 Dec 2022 08:27:06 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2022/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/</guid>
      <description>发现自己目前为止看的村上春树的书也不少。但都只是囫囵吞枣，连情节都记不太清了。这不是我想要的。加上最近有写读后感的冲动，所以开此篇来记录下。</description>
      <content:encoded><![CDATA[<p><strong>每次开篇都有缘由，今天开启村上春树这一篇章，是我这几天在看《舞舞舞》，看得着实投入。</strong></p>
<p><strong>我看书有个习惯，不好的习惯：看完后未待自己反应过来，就会去看别人如何点评这本书。这次也是。但看到的观点都不是很满意。</strong></p>
<p><strong>稍微回忆了下，发现自己目前为止看的村上春树的书也不少：且听风吟，舞舞舞，海边的卡夫卡，挪威的森林。但都只是囫囵吞之，连情节都记不太清了。这不是我想要的。加上最近有写读后感的冲动，所以开此篇来记录下。</strong></p>
<h2 id="总印象">总印象</h2>
<p>村上春树之名，我蛮早的时候就有所听闻：诺奖得主，长跑爱好者。这是我最初的印象。但他的作品直到大二上才开始接触。一接触就爱上了这种风格。我也说不上来是什么风格，但几本看下来，就是喜欢。现想到几点原因，列如下：</p>
<ul>
<li>小说主角的生活方式很得我心：《海边的卡夫卡》中的田村卡夫卡，我喜欢，我欣赏那种自律，健康的生活。《舞舞舞》中的“我”。三十四岁独居生活，不枯燥，不堕落。</li>
<li>小说中的音乐占据很大一部分分量：尤以摇滚和古典为主。这两个类别都是我所喜欢的。我对古典乐还是不太能欣赏得来，不得要领，但《海边的卡夫卡》中卡车司机星野在咖啡馆的那段我尤为喜欢。我希望自己哪天也有这样一个契机。</li>
<li>句子：很多都不甚明白，但就是喜欢这样的风格。其中有些句子还能让我觉得有趣。</li>
<li>作者本身：到目前为止，我最为喜欢的作家当属王小波。我佩服其智慧和幽默。其后是村上春树，佩服他坚持长跑。</li>
</ul>
<h2 id="且听风吟">《且听风吟》</h2>
<ul>
<li>阅读时间：2022年10月15日至10月20日</li>
<li>一些感受：
<ul>
<li>一年前读的，现在毫无印象。</li>
<li>我真的读过这本书吗？</li>
</ul>
</li>
</ul>
<h2 id="海边的卡夫卡">《海边的卡夫卡》</h2>
<ul>
<li>阅读时间：2022年11月21日至11月27日</li>
<li>卡车司机星野在咖啡馆的那段我尤为喜欢</li>
<li>“回忆会从内侧温暖你的身体，同时又从内侧剧烈切割你的身体。”</li>
</ul>
<h2 id="挪威的森林">《挪威的森林》</h2>
<ul>
<li>阅读时间：2022年11月28日至12月7日</li>
<li>一些感受：
<ul>
<li>这句有意思：
<blockquote>
<p>此前我一般要‘咔咔’拧三十六下发条，并且想：好，今天也要精神抖擞地开始一天的生活！我本身倒未注意，别人告诉说近来我常常自言自语，或许是一边上发条时一边口中念念有词的吧。</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h2 id="舞舞舞">《舞！舞！舞》</h2>
<ul>
<li>阅读时间：2023年1月2日至1月5日</li>
<li>一些感受：
<ul>
<li>喜欢主角的独居生活，以后自己生活的时候也能像这样就好了。</li>
</ul>
</li>
</ul>
<hr>
<h2 id="世界尽头与人间仙境">《世界尽头与人间仙境》</h2>
<ul>
<li>阅读时间：2023年3月12日至4月28日</li>
</ul>
<h3 id="设定">设定</h3>
<p>这篇的设定读得我有些头疼。</p>
<p>计算士，意识核&hellip;</p>
<h3 id="独角兽">独角兽</h3>
<blockquote>
<p>独角兽的出现意味着圣人临世，例如孔子的母亲怀他之时便见到了独角兽。 “‘七十年后，一伙猎人杀了一头麒麟，角上还带有孔子母亲缚的彩绳。孔子去看这独角兽，并掉了眼泪。这是因为，孔子感到这头纯真而神秘的动物的死具有某种预言性，那条彩绳上有着他的过去。’</p>
</blockquote>
<hr>
<h2 id="寻羊冒险记">《寻羊冒险记》</h2>
<ul>
<li>阅读时间：2023年8月5日至10月13日</li>
<li>一些感受：
<ul>
<li>蛮喜欢那栋山间别墅的。</li>
</ul>
</li>
</ul>
<h2 id="奇妙的搭配">奇妙的搭配</h2>
<p>村上春树的书常常出现些奇妙的搭配，让人（尤其是我这种）看起来不知所云，但又觉得很有逼格。可能需要一种比较跳脱的思维。我尝试联想了下，记起些类似的：</p>
<h4 id="世界尽头与人间仙境-回形针">《世界尽头与人间仙境》 回形针</h4>
<pre tabindex="0"><code>最后，把回形针撒在电视机上的头骨旁边。

奇妙的搭配。

奇妙得犹如羽绒枕和搅冰勺、墨水瓶和莴苣一类组合。我走上阳台，从远一点的地方望了望，得到的仍是同样印象，找不见任何共通点。然而，在某处应该有我所不知道或想不起来的秘密通道相连着。
</code></pre><p><em>好棒的比喻</em></p>
<h4 id="挪威的森林-渡边和绿子的对话">《挪威的森林》 渡边和绿子的对话</h4>
<pre tabindex="0"><code>  “春天的原野里，你一个人正走着，对面走来一只可爱的小熊，浑身的毛活像天鹅绒，眼睛圆鼓鼓的。

  它对你说道：’你好，小姐，和我一块儿打滚玩好吗？’接着，你就和小熊抱在一起，顺着长满三叶草的山坡‘咕噜咕噜’滚下去，玩了整整一天。你说棒不棒？”

  “太棒了。”

  “我就这么喜欢你。”
</code></pre><p><em>很浪漫。</em></p>
<h4 id="舞舞舞-我两次遭锤之前的问答">《舞！舞！舞！》 “我”两次遭锤之前的问答。</h4>
<pre tabindex="0"><code>“16的下一位数是几？”——有人问我。“41。”…“25的下一位数？”——有人问。“71。”——我回答。&#34;
</code></pre><p><em>不知道这四个数字的意义是什么。</em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Ozymandias</title>
      <link>https://ds63.eu.org/2022/ozymandias/</link>
      <pubDate>Tue, 15 Nov 2022 23:15:48 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2022/ozymandias/</guid>
      <description>废墟四周，唯余黄沙莽莽，寂寞荒凉，伸展四方</description>
      <content:encoded><![CDATA[<h2 id="原文">原文</h2>
<p>I met a traveller from an antique land</p>
<p>Who said :&ldquo;Two vast and trunkless legs of stone</p>
<p>Stand in the disert &hellip;Near them on the sand,</p>
<p>Half sunk, a shattered visage lies,whose frown</p>
<p>And wrinkled lip and sneer of cold command</p>
<p>Tell that its sculptor well those passions read</p>
<p>Which yet survive, stamped on these lifeless things,</p>
<p>The hand that mocked them and the heart that fed.</p>
<p>And on the pedestal these words appear:</p>
<p>&lsquo;My name is Ozymandias,King of Kings:</p>
<p>Look on my works,ye mighty,and despair!&rsquo;</p>
<p>Nothing beside remains. Round the decay</p>
<p>Of that colossal wreck,boundless and bare,</p>
<p>The lone and level sands stretch far away.</p>
<h2 id="译本">译本</h2>
<p><strong>江枫教授译本</strong></p>
<p>我遇到过一位来自古老故土的旅客，</p>
<p>他说：有一双巨大的石足，没有身躯，</p>
<p>矗立在沙漠……近旁的黄沙半裸着</p>
<p>一副破碎残缺的面孔，它眉峰紧蹙，</p>
<p>嘴唇起皱，【统帅万方、鄙夷一切的神色】，</p>
<p>【表明雕刻师对这类情欲曾经深有感受】，</p>
<p>它们，由于留痕在这无生命的物体上，</p>
<p>【竟比孕育了它们的心，仿造过它们的手】，</p>
<p>都存活得更加长久；在台座上石足下，</p>
<p>有这样的字迹依稀可读：“众王之王—</p>
<p>奥西曼达斯就是我，看看我的业绩吧，</p>
<p>纵然是一世之雄，也必定会颓然而绝望！”</p>
<p>残骸的周围，此外再没有留下什么，</p>
<p>寂寞、荒凉，无边的平沙伸向远方。</p>
<hr>
<p><strong>王佐良教授译本</strong></p>
<p>客自海外归，曾见沙漠古国</p>
<p>有石像半毁，唯余巨腿</p>
<p>蹲立沙砾间。像头旁落，</p>
<p>半遭沙埋，但人面依然可畏，</p>
<p>那冷笑，那发号施令的高傲，</p>
<p>足见雕匠看透了主人的内心，</p>
<p>才把那石头刻得神情维肖，</p>
<p>而刻像的手和像主的心</p>
<p>早成灰烬。像座上大字在目：</p>
<p>“吾乃万王之王是也，</p>
<p>盖世功业，敢叫天公折服！”</p>
<p>此外无一物，但见废墟周围，</p>
<p>寂寞平沙空莽莽，</p>
<p>伸向荒凉的四方。</p>
<hr>
<p><strong>杨绛</strong></p>
<p>我遇见一位来自古国的旅人</p>
<p>他说：有两条巨大的石腿</p>
<p>半掩于沙漠之间</p>
<p>近旁的沙土中，有一张破碎的石脸</p>
<p>抿着嘴，蹙着眉，面孔依旧威严</p>
<p>想那雕刻者，必定深谙其人情感</p>
<p>那神态还留在石头上</p>
<p>而私人已逝，化作尘烟</p>
<p>看那石座上刻着字句：</p>
<p>“我是万王之王,奥兹曼斯迪亚斯</p>
<p>功业盖物,强者折服”</p>
<p>此外，荡然无物</p>
<p>废墟四周，唯余黄沙莽莽</p>
<p>寂寞荒凉，伸展四方。</p>
<hr>
<h2 id="个人的一些感受">个人的一些感受</h2>
<p>我是在看游戏评论的时候看到这首诗的。说是文明5中有一幕，是关于这首诗的。评论取的是王佐良教授的译本。古色古香，令人触动。</p>
<p>我对翻译一直颇有兴趣。大学选的两门英语高级课程。一门选了笔译，一门是口译。</p>
<p>为什么我会对翻译感兴趣呢？</p>
<p>原因细数下来，蛮多的：</p>
<ul>
<li>我在阅读些专业书籍时，深受翻译之苦。有的中文翻译十分拗口，难以理解，反倒是英文原版更利于理解。</li>
<li>我英文歌听得比较多。我去看歌词时，常常发现译文十分有趣。</li>
<li>可以说是我的偶像吧：王小波。（写这里的时候我记成是金庸了）他在《我的师承》这篇文章中，盛赞了两位译者：查良铮，王道乾。初读这篇文章的时候，我还体会不到译诗的美，现在也还是不太能体会得到。希望以后的我能体会得到。</li>
</ul>
<p>再谈回这首诗。惭愧的是，我现在还不太能感受英文诗的美。但从中译本中，我还是能感受到那份苍凉。</p>
<p>我的第一感受是联想到“昔人已乘黄鹤去，此地空余黄鹤楼”。我会先想到这句其实也很正常：我经常yy，有一天我去英国旅行，特意去往温布利体育馆，再把之前的那条说说找出来，配文“此地空余黄鹤楼”。</p>
<p>而我刚才看赏析，说雪莱是借Ozymandias，来去告诫君王。我想不到那里去，不过也挺好的。不去想太多，只是感受，感受那“废墟四周，唯余黄沙莽莽，寂寞荒凉，伸展四方。”</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>句子</title>
      <link>https://ds63.eu.org/2022/sentences/</link>
      <pubDate>Mon, 14 Nov 2022 16:06:34 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2022/sentences/</guid>
      <description>本篇主要是记录些看到的句子，可能会留下当时的感想。</description>
      <content:encoded><![CDATA[<p><strong>本篇主要是记录些看到的句子，可能会留下当时的感想。</strong></p>
<ol>
<li>
<blockquote>
<p>不要因为睡懒觉，而感到自责，因为你起来，也创造不了价值。你能在浪费时间中获得乐趣，就不是浪费时间。</p>
</blockquote>
<p>&ndash;罗素</p>
<p>算是一种自我安慰吧。不过一个好好的假日，最难受的不是什么都没干，而是想着要好好利用起来，然后却东忙一点，西忙一点，最后想想，还是什么都没干。</p>
</li>
<li>
<blockquote>
<p>这就是为什么有这么多的优秀的程序员都是自由主义者。在我们的世界里，你下沉或游泳，没有任何借口。当那些远离财富创造的人——本科生、记者、政治家——听到最富有的5％的人拥有有一半的总财富，他们会觉得觉得不公平。一个有经验的程序员会想：这有什么？Top 5% 的程序员很有可能写出了 99%的好软件。</p>
</blockquote>
<p>看到这句话前，我在看<a href="https://github.com/programthink/zhao"  target="_blank" rel="noopener" >zhao</a>,就感叹于阶级的难以跨越，尤其是注意到，李克强在20岁左右就担任了党委书记，而他的父亲恰好是其所在县的县长。然后就看到了这句。不知道该说些什么好。<em>(2023年2月5日00:31:33)</em></p>
</li>
<li>
<blockquote>
<p>每个人在漫长的人生中都会面临很多不同选择是否成为那个少数派。可能是辍学，可能是性少数，可能是不婚，可能是丁克。衷心希望在作出了这样的选择之后的人，一定要努力成为别人口中的幸存者。之所以这么说，是因为这五年来，我见过身边太多有运气但不努力的人呢，也见过太多既努力又有运气的人。这让我感受到，事在人为和何不食肉糜之间并不能划上等号。用自己的力量去给偏见打一个沉重的巴掌吧。</p>
</blockquote>
<p>&ndash;<a href="https://lutaonan.com/blog/talking-about-dropout-again/"  target="_blank" rel="noopener" >再谈辍学</a>。</p>
<p>在人生的几个转折点上，我几乎都是选择那个和主流观点相左的。做的选择是否正确，我不知道。</p>
</li>
<li>
<blockquote>
<p>When you are depressed,make something.</p>
</blockquote>
</li>
<li>
<blockquote>
<p>世事犹如书籍，一页页被翻过去。人要向前看，少翻历史旧账；狗也要与时俱进，面对现实生活。</p>
</blockquote>
<p>&ndash;《生死疲劳》</p>
<p>前几天看的番《四叠半时光机布鲁斯》，里面也有类似的比喻，觉得很新奇。</p>
</li>
<li>
<blockquote>
<p>数字分崩离析，时间成为碎片。</p>
</blockquote>
<p>&ndash;《生死疲劳》</p>
<p>枪打手表。书中描述的极有画面感。</p>
</li>
<li>
<blockquote>
<p>我们从济南开始就讨论一个问题，有两种观点，一种就是：音乐就是音乐，如果你想改变，你牛逼，你就用音乐本身把它改变掉，你就音乐牛逼，你不用讲任何话就把他们打死。如果我要有那个天赋，我也想那么做。我什么都不用做，我只要把音乐做好往那里一摆，就把你给吓死。你没有呀，所以音乐才会变成工具。</p>
</blockquote>
<p>&ndash;李志</p>
<p>蛮有意思的，可见一斑</p>
</li>
<li>
<blockquote>
<p>听到超出自己需求的解说就是一种折磨</p>
</blockquote>
<p>&ndash;《别对映像研出手》</p>
<p>动漫的第一集，看到这句话的时候觉得表达得真好</p>
</li>
<li>
<blockquote>
<p>夫君爱鉴：昨日闻西安之变，焦急万分。窃思吾兄平生以身许国，大公无私，凡所作为，无丝毫为自己个人权利着想，即此一点，寸衷足以安慰，且抗日亦系吾兄平日主张，惟兄以整个国家为前提，故年来竭力整顿军备，团结国力，以求贯彻抗日主张，此公思为国之心，必为全国人民所谅解，目下吾兄所处境况真相若何？望即示知，以慰焦思。妹日夕祈祷上帝赐福吾兄，早日脱离恶境，请兄亦祈求主宰赐予安慰，为国珍重为祷。临书神往，不尽欲言。专此奉达，敬祝康健。妻美龄 二十五年十二月十二日</p>
</blockquote>
<p>&ndash;西安事变时，宋美龄致蒋中正的亲笔信</p>
<p>称呼很有趣；半文半白</p>
</li>
<li>
<blockquote>
<p>being able to offload repetitive tasks to a program is one of the best things about knowing how to code. However, sometimes problems can’t be solved by automation. If you’re willing to embrace the grind you’ll look like a magician.</p>
</blockquote>
<p>大一的c++老师很喜欢说一句话：聪明的程序员也是懒程序员</p>
</li>
<li>
<blockquote>
<p>第一，绝不意气用事；第二，绝对不漏判任何一件坏事；第三，绝对裁判得公正漂亮 &ndash;裁判机器人蜻蜓队长</p>
</blockquote>
<p>童年的回忆，不知道为什么，对《铁甲小宝》挺感兴趣的。</p>
</li>
<li>
<blockquote>
<p>与自己的个人电脑一起长大，这些人从小没有为吃穿发过愁，在他们的眼中，名誉或地位，有一点也不坏，至于更多，那就是别人的事情了。这些人经常把他们的得意之作直接放到网上，彻底开放，供人自由使用。在物质相对充裕的社会，对一个高智商的群体来说“吃饭”本不是问题，劳动更多的是为了实现自我，为了享受，一种真正的享受。</p>
</blockquote>
<p>《过河卒》 ——戴伟的父亲戴习为</p>
</li>
<li>
<blockquote>
<p>For me, just getting started is the only hard thing. An object at rest tends to remain at rest. There&rsquo;s something incredible heavy in my brain that is extremely hard to get up to speed, but once it&rsquo;s rolling at full speed, it takes no effort to keep it going.</p>
</blockquote>
<p>很认同。我有时候知道有些事情很重要，但总是犯懒不想做。</p>
</li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>我的独特之处</title>
      <link>https://ds63.eu.org/2022/my-uniqueness/</link>
      <pubDate>Sun, 23 Oct 2022 23:55:34 +0000</pubDate>
      
      <guid>https://ds63.eu.org/2022/my-uniqueness/</guid>
      <description>没有完全相同的两片叶子</description>
      <content:encoded><![CDATA[<h2 id="缘起">缘起</h2>
<p>某次玩真心话大冒险，被问到一个问题：</p>
<blockquote>
<p>说出一件你做得到，别人做不到的事情</p>
</blockquote>
<p>我那时候直接懵掉了，也没答上来，就说觉得自己挺普通的，自己能做到的，别人应该也都能做得到。</p>
<p>但真的是这样的吗，我感觉不一定。</p>
<h2 id="2023年4月19日">2023年4月19日</h2>
<p>6个月前开这篇后还没有写什么具体内容。也是能说明些什么。</p>
<p>我一直认为自己是普通人，但我相信自己还是有些与人不同的特质。或者说，每个人都有其特质。如果没有的话，多半是本人没意识到，或者是习以为常。</p>
<p>我想，如果不能用比较凝练的语言去概括一些特质的话，那不如就随手记录些事情，留给以后慢慢总结。</p>
<p>所以我这半年来，写文字的次数明显地增加了。有以下几个原因：</p>
<ul>
<li>我发现我的记忆力有点衰退的迹象。但有些东西，有些想法，我想留住。</li>
<li>之前看《爱情公寓》，有一段印象比较深刻。曾小贤思考自己在世上留下的痕迹。最后却发现最能直接证明他来过的痕迹是沙发上的屁股印。电视剧有些夸张的成分，但这也还是让我思考，在世上留下些什么。我现在觉得留点文字就挺好的。所以会特地记录下。</li>
<li>我喜欢我的键盘。我很享受用它打字的声音和触感。</li>
</ul>
<p><strong>我喜欢记录和量化</strong></p>
<p>不止是写文字，我最近还会使用Bangumi来记录我看过的番，用豆瓣来记录我读过的书和电影，用tai记录我的软件使用时间，用网费很贵记录我的浏览器浏览时间，用手环来记录我的睡眠和运动时间。感觉这跟我若有若无的焦虑感有点关系。我感叹时间过得飞快，想回忆一下时间都花在哪里了。但记忆力又没那么好，所以需要工具来进行辅助。我喜欢这种把时间统计起来的感觉，这可以给我一种安全感，给我一种安慰，让我觉得自己没有虚度光阴。（当然，也可能是一种自欺欺人）</p>
<p>ps: 关于数据与记录，我特别写了篇博客来展开讲：<a href="https://ds63.eu.org/2023/my-data/"  target="_blank" rel="noopener" >我的数据 | EuDs&rsquo;s Blog</a></p>
<h2 id="2024年3月4日">2024年3月4日</h2>
<p><strong>我有收藏和囤积癖</strong></p>
<p>我每次在 Wikipedia 查资料，总会被一些不相关的点分散注意力。或者更进一步说，我浏览器打开的tab几乎是只增不减，除非某天实在卡得影响到了我正常使用，我才会忍痛关掉几个。</p>
<p>我认同<a href="http://localhost-8080.com/2014/08/folktale-classification-system/"  target="_blank" rel="noopener" >一种童话分类的方法 | 考据癖</a>的最后一段:</p>
<blockquote>
<p>研究这些无聊的东西时，从没想过它们有什么用，光是找答案的过程就像打游戏一样过瘾了，觉得好奇心得到满足就足够了。但知道这些东西之后，you’ll never look at the world the same way again。</p>
</blockquote>
<h2 id="2024年4月7日">2024年4月7日</h2>
<p><strong>我期待每天都有新鲜事。如果没有，那我会尽量从习以为常的事情中发现乐趣</strong></p>
<p>我喜欢<a href="https://moviezhou.github.io/2021/11/17/old-blogs.html"  target="_blank" rel="noopener" >翻看旧博客</a>中的这段文字：</p>
<blockquote>
<p>为了测试Obsidian，打开了以前的github page博客的Markdown文档，随便翻看了几篇，感觉记录真是一个好习惯，从这些文字里能看到曾经那个真实、积极、纯粹的自己，能看到某年某月的某天做了什么琐碎的事情，心情是快乐还是沮丧……生活就是这样的片段组成的，我总是期待每天有新鲜事发生，这可能是双子座的通病。人生中，大部分的日子都是普通的，从每一天的普通生活中发现意义，做有价值、感兴趣的事情，要比试图去寻找并不确定的意义更具体。</p>
</blockquote>
<p>尤其是“我总是期待每天有新鲜事发生，这可能是双子座的通病”，我好像也是双子座，虽然我不信星座，认为这只是将一些人类的共有特点分摊给了不同日期。但我欣赏“人生中，大部分的日子都是普通的，从每一天的普通生活中发现意义，做有价值、感兴趣的事情，要比试图去寻找并不确定的意义更具体。”这句。</p>
<h2 id="2024年4月17日">2024年4月17日</h2>
<p><strong>我有独特的排解焦虑的方法</strong></p>
<p>我最近偶尔会觉得焦虑，不过找到了一个自己觉得还算不错的排解方法。就是假设最坏的结果发生，然后我就会想，就算是那样我也是不能活，一旦接受了这个可能的最坏结果，我一般就没那么焦虑了。所以看到下面这段后，我会心一笑。</p>
<p><a href="https://blog.loikein.one/posts/2022-09-21-phd-first-year/"  target="_blank" rel="noopener" >读博第一年总结 - 浣心／Heart of Sleeve</a></p>
<blockquote>
<p>当然，对于我个人而言最重要的是，相信一切都是能结束的。 之前碰到同学的室友，隔壁专业的，聊如果挂科了，找不到工作，不得不回到国内，被卷进新文革，该怎么办。我说，大不了我还能跳楼，他说，大不了我就趴在泥里，吃草吃土地活下去。屋子内外充满了快活的空气。</p>
<p>我想，在现在这样的时代，确实需要一些这样的觉悟，才能活得更轻松一些。</p>
</blockquote>
<h2 id="2024年5月25日">2024年5月25日</h2>
<p><strong>我有拖延的习惯，而且似乎越来越严重</strong></p>
<p>已是学期末，各种ddl纷至沓来。但我发现做其他的事的有趣程度与ddl的临近程度成正比：越是靠近ddl,看视频、看博客、查wiki、玩游戏，出去玩&hellip;这些都比完成本来该完成的任务要有趣得多。</p>
<p>比如说：在经历过一次在汇报前天完成选题，当天凌晨完成ppt的经历后。提前几天准备好汇报开始变得没必要。</p>
<p>这样好吗？我为什么会变成这样？可能是因为以下原因：</p>
<ul>
<li>我喜欢这种刺激感，在看似不可能完成的情况下，完成任务能给我带来成就感。</li>
<li>我着实不喜欢这些任务。写一些自己都懒得看的报告，做一些没人听的汇报，产生些连学术垃圾都算不上的东西，只会让人觉得是在浪费时间。</li>
</ul>
<h2 id="2024年5月26日">2024年5月26日</h2>
<p><strong>我习惯并发式读书</strong></p>
<p>除非是特别吸引我的书，吸引到让我爱不释手，一口气读完。我都习惯并发式地读多本。说白点就是，一本没读完，发现另一半蛮有趣的，于是就搁置着先去读另一本。等这本读腻了，就再把原来的给拾回来。</p>
<p>从<a href="https://ds63.eu.org/records/"  target="_blank" rel="noopener" >我的在读记录</a>中就能看出：我将十来本书标记为了在读，时间跨度长达两年。而这还仅仅是因为我用记录工具来记录自己所读的书也不到两年。</p>
<h2 id="2024年6月16日">2024年6月16日</h2>
<p><strong>我有尊重我，愿意和我好好沟通的父母</strong></p>
<p>从选择高中学校开始，到后来的选择大学专业，我爸妈都愿意和我坐下来沟通。他们会有他们的意见，但只是作为建议给我参考，而且最终以我的选择为准。在选择确定之后,他们就会支持着我，甚至帮我去说服不太能理解我的选择的爷爷奶奶。</p>
<p>虽然我也不能确定我做的选择最终正确与否，但有一点我可以十分明确：</p>
<p>我感激，并深爱着我的父母。</p>
<h2 id="2024年8月3日">2024年8月3日</h2>
<p><strong>我不喜欢无意义的重复动作</strong></p>
<p>我注意到不少事情:都是需要做，但每次都要花上一定的时间和精力。我自己讨厌做这种事，看到别人因这种事而浪费时间也会觉得难受。</p>
<p>这时候我就愿意多花点时间去琢磨能让其自动化的方法。这成了我学习计算机的契机，也是我学习计算机的乐趣与成就感。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>手冲的溯源探究</title>
      <link>https://ds63.eu.org/2022/an-exploration-into-the-origins-of-hand-punching/</link>
      <pubDate>Mon, 10 Oct 2022 15:59:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2022/an-exploration-into-the-origins-of-hand-punching/</guid>
      <description>这个老头子很会省</description>
      <content:encoded><![CDATA[<h2 id="2022年10月10日">2022年10月10日</h2>
<p>看到《寻找无双》中的一段话</p>
<blockquote>
<p>这个老头子很会省，或者说，视钱如命。据说他有了钱就去买印花布，用蓝布包好了挂在房梁上，挂得门房里连天花板都不见了，却舍不得钱去逛窑子，躲在门房里打手铳，被人撞见了好几回。</p>
</blockquote>
<p>感觉很有意思，《寻找无双》成书的时间早于1997年，而我们现在对于手淫的说法：较早的有叫打手枪，现在有的叫打胶，有的叫打手冲，或者干脆简化成 冲。</p>
<p>这就引起了我一大兴趣：何不收集整理对手淫的各种别称，并分析其由来呢。感觉分析不同时代，不同群体，不同民族对手淫的代称的不同会很有意思。</p>
<p>然后再引申到更大层面的，对别称的研究，如果引入计算机进行数据分析，应该能得到很有意思的结果。</p>
<h2 id="2022年12月8日">2022年12月8日</h2>
<p>ChatGPT横空出世，找它请教了下：</p>
<h3 id="一种回答">一种回答</h3>
<p>A：我在看《寻找无双》的时候，发现书中对手淫的别称是打手铳，这本书成书的时间早于1997年，书中的年代则是在唐朝。
而我们现在对于手淫的说法：较早的有叫打手枪，现在有的叫打胶，有的叫打手冲，或者简化成 冲。</p>
<p>这就引起了我一大兴趣：何不收集整理对手淫的各种别称，并分析其由来呢。感觉分析不同时代，不同群体，不同民族对手淫的代称的不同会很有意思。</p>
<p>然后再引申到更大层面的，对别称的研究，如果引入计算机进行数据分析，应该能得到很有意思的结果。</p>
<p>B：你的想法很有趣，也是一个很有挑战性的研究课题。对于手淫这一话题，不同时代、不同群体、不同民族都有不同的表达方式，收集整理各种别称，并分析其由来，可以揭示不同时代、不同群体、不同民族对这一行为的看法和态度。</p>
<p>如果引入计算机进行数据分析，应该能得到很有意思的结果，比如，不同时代的别称随时间的变化趋势，不同群体的别称表现出的差异等。</p>
<p>不过，这一课题也存在很大的困难，因为手淫这一话题本身就是一个敏感话题，很难获得大量有效数据。而且，在研究过程中，也要注意不要违背道德规范，否则会引起不必要的社会问题。</p>
<p>总之，你的想法很有意思，如果你想继续进行这一课题的研究，应该首先进行大量的文献资料搜集工作，搜集不同时代、不同群体、不同民族对手淫的别称，并细心分析其由来。</p>
<p>然后，可以考虑引入计算机进行数据分析，比如建立一个数据库，并对数据进行统计分析，揭示不同时代、不同群体、不同民族对这一行为的看法和态度。</p>
<p>在研究过程中，要注意不要违背道德规范，避免引起不必要的社会问题。同时，也要充分考虑研究成果的实用性和意义，确保研究成果能够为社会带来实际的价值。</p>
<p>总之，这一课题是有挑战性的，但也具有很大的吸引力，如果你坚持不懈，应该能够得到满意的研究成果。</p>
<h3 id="另一种回答">另一种回答</h3>
<p>这个问题很有意思，我们可以结合历史、社会学和语言学的方面来进行研究。</p>
<p>首先，我们可以收集不同时代、不同群体、不同民族对手淫的别称，如你提到的“打手枪”、“打胶”、“打手冲”、“冲”等。</p>
<p>然后，我们可以分析这些别称的由来，例如：</p>
<p>“打手枪”指的是拿手指模拟枪支进行手淫。
“打胶”指的是在手淫时使用某种物质来增加快感。
“打手冲”指的是用手对着下体进行手淫。
“冲”指的是手淫过程中的快感。
接着，我们可以引入计算机进行数据分析，统计不同时代、不同群体、不同民族对手淫的别称数量，探究各个别称的分布情况，并对比不同时代、不同群体、不同民族的差异。</p>
<p>这样的研究可以为我们更好地理解手淫在历史、社会学和语言学方面的发展，也可以为我们提供一个宏观的视角，帮助我们更好地了解人类对于性行为的看法和认知。</p>
<p>当然，这样的研究也需要遵循严谨的科学方法，以保证研究结果的准确性和可靠性。</p>
<p>总之，这个问题很有意思，也有科学研究的潜力。如果你有兴趣，可以考虑进一步研究。</p>
<h2 id="2024年1月16日">2024年1月16日</h2>
<p>偶然了解到在台湾手淫也被称为「尻槍」。</p>
<p>在<a href="https://blog.udn.com/mobile/ki999mo/131672678"  target="_blank" rel="noopener" >「尻槍」一詞是啥意思？～～「手淫」是也。 - ki999mo 的部落格 - udn部落格</a>一文中，其给出的解释是</p>
<blockquote>
<p>話說「尻槍」，用字錯誤，正確的書寫該是「剾槍」。</p>
<p>「剾槍」一詞為何是手淫呢？其實，這是從部隊衍化出的次文化語言。臺灣軍歌〈我有一隻槍〉，阿兵哥將之歪唱為：「我有兩隻槍，長短不一樣，長的打共匪，短的打姑娘。」槍已經意淫，而指涉男性生殖器了。</p>
<p>宋朝《廣韻》裡，「剾」的解釋是：剜裏也。(*「剜」就是「挖」。)</p>
<p>不過，在河洛話中，「挖苦」一詞則呼作「剾洗」(khau-sé)，它有摳挖搓洗的意思。引伸來說，「剾槍」就是摳搓生殖器，即是自慰。</p>
</blockquote>
<p>这里说的河洛话，按<a href="https://www.taiwanus.net/history/1/57.htm"  target="_blank" rel="noopener" >台灣話的由來</a>，“也就是今日的台灣話，或稱閩南話”</p>
<h2 id="参考链接">参考链接</h2>
<p><a href="https://blog.udn.com/mobile/ki999mo/131672678"  target="_blank" rel="noopener" >「尻槍」一詞是啥意思？～～「手淫」是也。 - ki999mo 的部落格 - udn部落格</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>反义的同义词</title>
      <link>https://ds63.eu.org/2022/antonyms-and-synonyms/</link>
      <pubDate>Mon, 05 Sep 2022 16:59:21 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2022/antonyms-and-synonyms/</guid>
      <description>锐意更新中</description>
      <content:encoded><![CDATA[<h2 id="收集">收集</h2>
<p>高中的时候就注意到有些词很有趣，他们在字面上看上去意思完全相反，但实际上表达的是同一个意思，现收集如下：</p>
<table>
<thead>
<tr>
<th>词A</th>
<th>词B</th>
</tr>
</thead>
<tbody>
<tr>
<td>救火</td>
<td>灭火</td>
</tr>
<tr>
<td>缓存</td>
<td>快取</td>
</tr>
<tr>
<td>智能相机</td>
<td>傻瓜相机</td>
</tr>
</tbody>
</table>
<h2 id="2022年12月8日">2022年12月8日</h2>
<p>询问ChatGPT以试图得到更多的词，未果。记录下部分对话：</p>
<p>A：我注意到有些词很有趣，他们在字面上看上去意思完全相反，但实际上表达的是同一个意思，比如一下几对：缓存和快取，救火和灭火，智能相机和傻瓜相机。你能帮我再举出几个例子吗</p>
<p>B：是的，这种词叫做反义词，也称为反置词或反意词。它们在字面上看上去意思完全相反，但实际上表达的是同一个意思。</p>
<p>除了你举的几个例子，还有许多反义词，如：</p>
<p>黑白：黑代表暗，白代表光
熟练和笨拙：熟练代表熟练，笨拙代表笨拙
向前和向后：向前代表朝前，向后代表朝后
光明和黑暗：光明代表亮，黑暗代表暗
这种词的出现，可能是因为语言的发展，或者是为了更好地表达</p>
<p>A：你举的这几个例子有问题啊</p>
<p>B：你说的对，我举的例子中，缓存和快取的意思是相同的，但是救火和灭火的意思是不同的。</p>
<p>缓存和快取都指的是临时存储数据的地方，但快取常指的是用于提高系统性能的缓存，而缓存更泛指的是临时存储的地方。</p>
<p>救火和灭火都指的是消除火灾的过程，但救火指的是通过各种方法解救被火灾困扰的人和物，而灭火指的是通过各种方法消灭火灾。</p>
<p>智能相机和傻瓜相机都指的是用来拍照的工具，但智能相机具有智能化的功能，能够自动调节曝光、焦距等参数，而傻瓜相机则没有这些功能，需要用户手动调节。</p>
<p>这些例子可能不太适合，不过我的回答应该能让你理解反义词的概念。如果你还有疑问，欢迎继续提问。</p>
<p>A：可是缓存，救火这几个例子是我提出来的啊，你举的是黑白，光明</p>
<p>B：对不起，我的回答不够严谨。你提出的缓存和救火，实际上都是正义词，而不是反义词。</p>
<p>缓存和快取的意思是相同的，都指的是临时存储数据的地方。救火和灭火的意思也是相同的，都指的是消除火灾的过程。</p>
<p>而反义词是指在字面上看上去意思相反，但实际上表达的是同一个意思的词。例如，黑白，光明，熟练和笨拙等。</p>
<p>如果我的回答还有误解，欢迎指正。</p>
<p>A：所以你能不能再举几个正义词</p>
<p>B：正义词是指在字面上看上去意思相同，而实际上表达的是同一个意思的词。例如，缓存和快取，救火和灭火等。</p>
<p>还有许多正义词，如：</p>
<p>爱好和兴趣：爱好指的是喜欢并经常从事的某种活动，而兴趣则指的是对某种事物或活动的兴致。
家庭和家：家庭指的是由父母及其子女等共同居住的群体，而家则指的是一个人在一个地方居住的地方。
灵魂和心灵：灵魂指的是人的精神性存在，而心灵则指的是人的感情和意识。
生命和死亡：生命指的是人类或动物的存在，而死亡则指的是人类或动物的消失。
这些例子都能说明正义词的概念，如果你还有疑问，欢迎继续提问。</p>
<p>A：不对不对，我想要你举的，是用不同意思的字表达出了同一种意思的词</p>
<p>B：那我举的是反义词，它们就是用不同意思的字表达出了同一种意思的词。例如，黑白，光明，熟练和笨拙等。</p>
<p>还有许多反义词，如：</p>
<p>向前和向后：向前指的是朝前的方向，而向后则指的是朝后的方向。
上和下：上指的是朝上的方向，而下则指的是朝下的方向。
去和来：去指的是离开某地，而来则指的是抵达某地。
是和不是：是指的是某事是真的，而不是则指的是某事是假的。
如果你还有疑问，欢迎继续提问。</p>
<h2 id="2024年6月11日">2024年6月11日</h2>
<p>今天去食堂点餐。看到菜花不错，于是我说“菜花”，旁边一位同学也在点餐，他说“花菜”。然后阿姨给我们打了一样的菜。</p>
<p>“菜花”和“花菜”虽然语言顺序上完全相反，但指的是同一样事物，还有类似的现象吗？</p>
<h2 id="2024年6月18日">2024年6月18日</h2>
<p>刷到个评论区，里面有不少中文谐音带来的文字游戏。我将其中特别有意思的整理如下，原始出处难辨，在此对其原作者致歉。</p>
<ol>
<li>你记住，膀胱的膀是肩膀的膀，草率的率是效率的率，旺仔的仔是仔细的仔，茄子的茄是雪茄的茄，咖啡的咖是咖喱的咖</li>
<li>小朋友，你记住:但丁是意大利人，但丁真是中国人;但丁真去过地狱，但丁真没去过地狱;但丁真是妈妈生的，但丁真也是妈妈生的;但但丁丁真真是三个人</li>
<li>小孩你记住:生鱼片是死鱼片;等红灯是在等绿灯;咖啡因来自咖啡果;救火是在灭火;生前是死前;要你管=不要你管;坐电梯是站电梯;原则上可以=不行，原则上不行=可以;夜店是喝酒的，酒店是过夜的;烟头=烟屁股;</li>
<li>老弟你记住，丑的才谈恋爱，美的卖空调</li>
<li>评论区已经乱成一锅粥了，弟弟快趁热喝了吧…</li>
<li>小孩你记住，爱一个人藏不住，但爱俩个人你一定要藏住。</li>
<li>小孩你要知道，人要是行，干一行行一行，一行行行行行，行行行干哪行都行，要是不行，干一行不行一行，一行不行行行不行，行行不行干哪行都不行。想要行行行，首先一行行，成为行业内的内行，行行成内行，行行行。</li>
<li>老弟你要记住，太空才有空间站，太挤没有空间站</li>
<li>你记住 在中国 一五一十是对的 二五一十也是对的</li>
<li>小孩哥我很喜欢你，有机会的话想请你来到我的家乡，我请你吃闭门羹和鸿门宴!饭后还有你好果子吃</li>
<li>教你两句中国谚语:深圳不怕影子斜，宁波打的电话正在通话中
短篇</li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>git学习笔记</title>
      <link>https://ds63.eu.org/2022/git%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Sun, 04 Sep 2022 12:31:47 +0800</pubDate>
      
      <guid>https://ds63.eu.org/2022/git%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>记录git学习</description>
      <content:encoded><![CDATA[<h2 id="记录">记录</h2>
<h3 id="gitee配置的记录">Gitee配置的记录</h3>
<p>因为srtp项目是用gitee作托管，所以今天试着配置了下Gitee，还是花了些时间的，记录如下：</p>
<ol>
<li>主要参考的是<a href="https://cloud.tencent.com/developer/article/1774890"  target="_blank" rel="noopener" >Git同时配置Gitee和GitHub</a>,但它上面第一步就是让清除git的全局设置，有点不敢，因为怕清除后自己之前设置的一些东西出错。</li>
<li>又看了几个教程，发现<a href="https://blog.csdn.net/weixin_43894513/article/details/104550377"  target="_blank" rel="noopener" >Github 与 Gitee 共存配置</a>上并没有说要清楚全局设置，于是就跟着上面的一步步走，很顺利地就设置好了。</li>
<li>一个收获是<code>config</code>,<code>id_rsa</code>都是可以用记事本打开并编辑的。</li>
</ol>
<h3 id="多人协作时的流程">多人协作时的流程</h3>
<p>这次小组项目用的是华为云，所以流程也都是基于华为云来说的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#确定好本次代码开发所要完成的任务，开好远程分支x，相关信息(分支名称，描述，关联工作项）要注明好</span>
</span></span><span class="line"><span class="cl">git pull <span class="c1">#确保代码、分支是最新的</span>
</span></span><span class="line"><span class="cl">git checkout -b 本地分支名 origin/远程分支名x   <span class="c1">#检出远程的x分支到本地</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 代码开发</span>
</span></span><span class="line"><span class="cl">git add .
</span></span><span class="line"><span class="cl">git commit -m<span class="s2">&#34;{</span>$<span class="s2">适当的批注}&#34;</span>
</span></span><span class="line"><span class="cl">git push <span class="c1">#将代码推送到远程分支，开发过程中这个操作可以频繁点，好处是：代码备份和版本管理</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 完成本次代码开发所要完成的任务后（请确定功能实现，本地调试没问题）</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 接下来进行分支的合并 </span>
</span></span><span class="line"><span class="cl"><span class="c1"># 在华为云中新建合并请求（可设置检视人，评审人，让别人帮忙看看）</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 合并完成后（默认设置是分支合并后，源分支是删除的）</span>
</span></span><span class="line"><span class="cl">git remote prune origin <span class="c1">#当华为云上显示远程分支已经删除，但git branch -r仍然看到所删除的分支，执行该命令</span>
</span></span><span class="line"><span class="cl">git checkout master <span class="c1">#切回master分支（一次任务完成后，建议切回master分支，这样pull的时候可以避免自己写的代码丢失的问题）</span>
</span></span><span class="line"><span class="cl">git branch -d <span class="o">{</span>$本地分支名<span class="o">}</span> <span class="c1">#删除本次任务所用的本地分支（也可以不删，当作备份）</span>
</span></span></code></pre></div><hr>
<h2 id="报错与解决">报错与解决</h2>
<ol>
<li>
<p>报错：</p>
<blockquote>
<p>Updates were rejected because the remote contains work that you donot have locally.</p>
</blockquote>
<ul>
<li><strong>场景</strong>:在尝试gitee的时候，先是建了个远程仓库。然后在本地新建了个同名的文件夹，然后
<pre tabindex="0"><code>git init 
git remote add origin https://gitee.com/spike23187/hello-gitee.git
</code></pre></li>
</ul>
<p>在文件夹里新建了个文件，<code>push</code>的时候报的错</p>
<ul>
<li><strong>解决</strong>: 根据下方的提示，是我没有先<code>pull</code>，本地文件不是最新的。</li>
</ul>
</li>
<li>
<blockquote>
<p>Updates were rejected because the tip of your current branch is behind its remote counterpart</p>
</blockquote>
<ul>
<li><strong>场景</strong>：上述那个场景中，<code>git pull origin master</code>后报的错</li>
<li><strong>解决</strong>：<code>git pull origin master --rebase</code></li>
<li><strong>参考链接</strong>：<a href="https://blog.csdn.net/weixin_42310154/article/details/118676936"  target="_blank" rel="noopener" >Git常见报错：Updates were rejected because the tip of your current branch is behind</a></li>
<li><strong>收获</strong>：虽然使用GitHub托管代码有段时间了，但一直是用插件简化操作的。这次算是第一次用git bash，就报了两个错，感觉git要用好，还是有段路要走的。</li>
</ul>
</li>
<li></li>
</ol>
<ul>
<li><strong>场景</strong>:push时报错,大意是网络问题</li>
<li><strong>解决</strong>：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">   <span class="c1"># usually</span>
</span></span><span class="line"><span class="cl">   git config --global http.proxy <span class="s1">&#39;http://127.0.0.1:7890&#39;</span>
</span></span><span class="line"><span class="cl">   git config --global https.proxy <span class="s1">&#39;http://127.0.0.1:7890&#39;</span>
</span></span><span class="line"><span class="cl">   <span class="c1"># in wsl2 </span>
</span></span><span class="line"><span class="cl">   git config --global http.proxy <span class="s1">&#39;http://172.19.80.1:7890&#39;</span>
</span></span><span class="line"><span class="cl">   git config --global https.proxy <span class="s1">&#39;http://172.19.80.1:7890&#39;</span>
</span></span></code></pre></div></li>
</ul>
<hr>
<h2 id="使用技巧">使用技巧</h2>
<h3 id="github项目内搜索">Github项目内搜索</h3>
<p>在仓库页面上按 T ，然后直接输入文件名</p>
<hr>
<h1 id="可供参考的链接">可供参考的链接</h1>
<ul>
<li><a href="https://www.yiibai.com/git"  target="_blank" rel="noopener" >git教程</a></li>
<li><a href="https://www.theserverside.com/video/Git-reflog-vs-log-How-these-commit-history-tools-differ"  target="_blank" rel="noopener" >Git reflog vs. log: How these commit history tools differ</a></li>
<li><a href="http://blog.ch3nyang.top/miscellaneous/git%E5%AD%A6%E4%B9%A0/"  target="_blank" rel="noopener" >【杂】git学习</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/137856034"  target="_blank" rel="noopener" >拜托，不要再问我Git如何回滚代码</a></li>
<li><a href="https://stackoverflow.com/questions/20106712/what-are-the-differences-between-git-remote-prune-git-prune-git-fetch-prune"  target="_blank" rel="noopener" >What are the differences between git remote prune, git prune, git fetch &ndash;prune, etc</a></li>
<li><a href="https://rehoni.github.io/cn/2019/2019-10-11-git-problems/"  target="_blank" rel="noopener" >Git实际问题</a></li>
<li><a href="https://jvns.ca/blog/2023/09/14/in-a-git-repository--where-do-your-files-live-/"  target="_blank" rel="noopener" >In a git repository, where do your files live?</a></li>
</ul>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
