-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 46.1 KB
/
content.json
1
{"meta":{"title":"Dynamic_Pigeon","subtitle":null,"description":"好少年光芒万丈","author":"Dynamic_Pigeon","url":"https://chy669086.github.io"},"pages":[{"title":"bangumi","date":"2019-02-10T13:32:48.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"bangumi/index.html","permalink":"https://chy669086.github.io/bangumi/index.html","excerpt":"","text":"","keywords":null},{"title":"about","date":"2024-10-01T14:14:36.000Z","updated":"2024-10-02T08:53:15.676Z","comments":false,"path":"about/index.html","permalink":"https://chy669086.github.io/about/index.html","excerpt":"","text":"[Dynamic_Pigeon の秘密对话] 与 Dynamic_Pigeon 对话中... bot_ui_ini()","keywords":"关于"},{"title":"comment","date":"2018-12-20T15:13:48.000Z","updated":"2024-10-08T14:32:31.230Z","comments":true,"path":"comment/index.html","permalink":"https://chy669086.github.io/comment/index.html","excerpt":"","text":"念两句诗 叙别梦、扬州一觉。 【宋代】吴文英《夜游宫·人去西楼雁杳》","keywords":"留言板"},{"title":"client","date":"2018-12-20T15:13:35.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"client/index.html","permalink":"https://chy669086.github.io/client/index.html","excerpt":"","text":"直接下载 or 扫码下载:","keywords":"Android客户端"},{"title":"lab","date":"2019-01-05T13:47:59.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"lab/index.html","permalink":"https://chy669086.github.io/lab/index.html","excerpt":"","text":"sakura主题balabala","keywords":"Lab实验室"},{"title":"donate","date":"2018-12-20T15:13:05.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"donate/index.html","permalink":"https://chy669086.github.io/donate/index.html","excerpt":"","text":"","keywords":"谢谢饲主了喵~"},{"title":"links","date":"2018-12-19T15:11:06.000Z","updated":"2024-09-30T16:15:47.829Z","comments":true,"path":"links/index.html","permalink":"https://chy669086.github.io/links/index.html","excerpt":"","text":"","keywords":"友人帐"},{"title":"music","date":"2018-12-20T15:14:28.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"music/index.html","permalink":"https://chy669086.github.io/music/index.html","excerpt":"","text":"","keywords":"喜欢的音乐"},{"title":"tags","date":"2018-12-12T14:14:16.000Z","updated":"2024-09-30T16:15:47.829Z","comments":true,"path":"tags/index.html","permalink":"https://chy669086.github.io/tags/index.html","excerpt":"","text":""},{"title":"rss","date":"2018-12-20T15:09:03.000Z","updated":"2024-09-30T16:15:47.829Z","comments":true,"path":"rss/index.html","permalink":"https://chy669086.github.io/rss/index.html","excerpt":"","text":""},{"title":"theme-sakura","date":"2019-01-04T14:53:25.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"theme-sakura/index.html","permalink":"https://chy669086.github.io/theme-sakura/index.html","excerpt":"","text":"Hexo主题Sakura修改自WordPress主题Sakura,感谢原作者Mashiro","keywords":"Hexo 主题 Sakura 🌸"},{"title":"video","date":"2018-12-20T15:14:38.000Z","updated":"2024-09-30T16:15:47.829Z","comments":false,"path":"video/index.html","permalink":"https://chy669086.github.io/video/index.html","excerpt":"","text":"var videos = [ { img: 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '放送时间: 2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' }, { img : 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' } ] .should-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:95%;}.should-ellipsis-full{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%;}.should-ellipsis i{position:absolute;right:24px;}.grey-text{color:#9e9e9e !important}.grey-text.text-darken-4{color:#212121 !important}html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}img{border-style:none}progress{display:inline-block;vertical-align:baseline}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;box-sizing:inherit}ul:not(.browser-default){padding-left:0;list-style-type:none}ul:not(.browser-default)>li{list-style-type:none}.card{-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2);box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}.hoverable{-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s}.hoverable:hover{-webkit-box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}i{line-height:inherit}i.right{float:right;margin-left:15px}.bangumi .right{float:right !important}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:\"\";display:table;clear:both}.row .col{float:left;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}@media only screen and (min-width:601px){.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}}html{line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width:0){html{font-size:14px}}@media only screen and (min-width:992px){html{font-size:14.5px}}@media only screen and (min-width:1200px){html{font-size:15px}}.card{position:relative;margin:.5rem 0 1rem 0;background-color:#fff;-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-content{padding:24px;border-radius:0 0 2px 2px}.card .card-content p{margin:0}.card .card-content .card-title{display:block;line-height:32px;margin-bottom:8px}.card .card-content .card-title i{line-height:32px}.card .card-reveal{padding:24px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;left:0;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;-webkit-transition:.3s ease-out;transition:.3s ease-out}.waves-effect img{position:relative;z-index:-1}.waves-block{display:block}::-webkit-input-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}::-ms-input-placeholder{color:#d1d1d1}[type=\"radio\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"radio\"]:not(:checked)+span{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-transition:.28s ease;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border-radius:50%}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border:2px solid #5a5a5a}[type=\"radio\"]:not(:checked)+span:after{-webkit-transform:scale(0);transform:scale(0)}[type=\"checkbox\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"checkbox\"]:not(:checked):disabled+span:not(.lever):before{border:none;background-color:rgba(0,0,0,0.42)}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}input[type=checkbox]:not(:disabled) ~ .lever:active:before,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before{-webkit-transform:scale(2.4);transform:scale(2.4);background-color:rgba(0,0,0,0.08)}input[type=range].focused:focus:not(.active)::-webkit-slider-thumb{-webkit-box-shadow:0 0 0 10px rgba(38,166,154,0.26);box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-ms-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)} 番组计划 这里将是永远的回忆 window.onload = function(){ videos.forEach(function(video, i){ $('#rootRow').append(` ${video.title} ${video.jp} ${video.status} ${video.title} ${video.jp} 放送时间: ${video.time} ${video.desc} ${video.status} `) }) }","keywords":"B站"}],"posts":[{"title":"从源码编译安装gcc","slug":"从源码编译安装gcc","date":"2025-01-27T10:42:23.000Z","updated":"2025-01-27T10:42:23.000Z","comments":true,"path":"2025/01/27/从源码编译安装gcc/","link":"","permalink":"https://chy669086.github.io/2025/01/27/%E4%BB%8E%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85gcc/","excerpt":"","text":"这是一个个人编译安装 gcc 的存档。 本人操作系统 Debian-12 下载源码以及依赖http://gcc.gnu.org/install/ # 官方下载源 http://mirrors.nju.edu.cn/gnu/gcc/ # 南京大学源 https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/ # 清华源 可以选择自己需要的版本进行下载,这里我下载的是 gcc-14.2。 wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-14.2.0/gcc-14.2.0.tar.xz tar xf gcc-14.2.0.tar.xz cd gcc-14.2.0 # 这一步可能需要给执行权限 sudo chmod a+x ./contrib/download_prerequisites # 或者 bash ./contrib/download_prerequisites ./contrib/download_prerequisites 配置并编译mkdir build cd build # 安装到默认位置的话不需要使用 --prefix,需要其他语言自行添加 ../configure --enable-checking=release \\ --enable-languages=c,c++ \\ --disable-multilib \\ --enable-bootstrap \\ --prefix=<your-path> 执行完毕后或有成功的提示,如果报错,请根据提示操作。 # 这里看你 cpu 有多少核心,我是 13900 所以给了 24 核 # 过程中可能会提示两个文件没有执行权限,给权限就行了 # 只查看 warning 和 error 使用 make -j 24 > /dev/null make -j 24 大概等待 1~2 小时后就会编译完(看电脑性能)。 make install 配置路径使用默认路径的应该可以跳过 # 在 ~/.bashrc 中 # 替换 <your-path> 为你设置的路径 export PATH="<your-path>/gcc-14.2/bin:$PATH" export LD_LIBRARY_PATH="<your-path>/gcc-14.2/lib64:<your-path>/gcc-14.2/lib:$LD_LIBRARY_PATH" 当然也可以直接换掉原本的 gcc 编译器。 # 替换之前最好备份一下本来的编译器 # 也可以直接 sudo apt remove g++ gcc ln -sf <your-path>/bin/gcc /usr/bin/gcc ln -sf <your-path>/bin/g++ /usr/bin/g++ 现在查看一下版本,应该是 gcc-14.2 了。 然后你大概会发现 gdb 查看 stl 的功能爆炸了,这时候你可能还需要重新编译一下最新的 gdb(偷笑","categories":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"gcc","slug":"gcc","permalink":"https://chy669086.github.io/tags/gcc/"}],"keywords":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}]},{"title":"Rust 开源操作系统训练营结营报告","slug":"Rust-开源操作系统训练营结营报告","date":"2024-12-22T14:28:34.000Z","updated":"2024-12-22T14:28:34.000Z","comments":true,"path":"2024/12/22/Rust-开源操作系统训练营结营报告/","link":"","permalink":"https://chy669086.github.io/2024/12/22/Rust-%E5%BC%80%E6%BA%90%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%AE%AD%E7%BB%83%E8%90%A5%E7%BB%93%E8%90%A5%E6%8A%A5%E5%91%8A/","excerpt":"","text":"仓库链接:https://github.com/chy669086/futex 参与方向:宏内核,posix 接口相关。 我在四阶段中编写的是 futex 有关的代码。 设计思路暂时请求了五个 os 需要实现的接口,分别是 sched_yield 退出当前的任务,不放回调度队列。 translate_vaddr 将当前任务的虚拟地址转换成操作系统可以访问的地址 current_task 取得当前任务 current_prosess_id 取得进程 id wake 传入一个 FutexQ 类型,唤醒任务(提供了 get_task 函数取得任务) FutexQ 是存放任务的重要类型,内有 key bitset task 三个字段,其中 key 和 bitset 是用来唤醒任务的重要字段。 FutexKey 是一个枚举,现在只实现了一个 Private,Shared 暂时没有开发的思路。 任务等待队列存储在 FutexQueues 中,通过一个 futex 的唯一 key 通过哈希变换后放入或唤醒。 现在实现的调用有:FUTEX_WAIT FUTEX_WAKE FUTEX_REQUEUE FUTEX_CMP_REQUEUE FUTEX_WAKE_OP 以及对应的 bitset 版本 因为三阶段提供的宏内核中没有合适的线程实现,二阶短的项目不知道什么原因不能编译 link-me 的代码,所以我直接把整个模块删除 linkme 后移植到了阶段二的仓库,并编写测试通过。 收获说实话还是不是很擅长编写 no_std 的代码,所以我还是依赖了很多外部库。 虽然没有通过最初的设想去适配到任何一个系统里去(直接移植还是太不松耦合了),但是我也花了很多时间去尝试适配,其中阶段二的项目仓库是最接近完成的一个,结果编译错误了,经过测试发现把 futex::syscall::sys_futex 函数调用去掉就可以通过编译,一时间不知道从何改起。转到 arceos 适配的时候,在被迫阅读了大量源码之后,发现提供的宏内核示例压根没有创建线程的系统调用,自己写了半天并没有写出来,所以又放弃了。 虽然写的挺差的,而且最近也到学校的期末周了,确实有没有太多时间写这个项目了,但是通过这次 posix 接口的编写,我还是学会了不少东西。 总结从训练营开始到现在也过去 12 周了,看着自己从对操作系统毫无概念一步步到现在还是很感慨的。感谢老师的辛勤付出,感谢训练营能给我一个这样的平台。","categories":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Rust","slug":"Rust","permalink":"https://chy669086.github.io/tags/Rust/"}],"keywords":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}]},{"title":"C++ ADL 简介","slug":"C-ADL-简介","date":"2024-11-20T07:49:21.000Z","updated":"2024-11-20T07:49:21.000Z","comments":true,"path":"2024/11/20/C-ADL-简介/","link":"","permalink":"https://chy669086.github.io/2024/11/20/C-ADL-%E7%AE%80%E4%BB%8B/","excerpt":"","text":"前两天水群水到的,突然感觉开发了新大陆。 ADL 简介相信很多人应该都写过类似这样的代码 #include <algorithm> #include <vector> int main() { std::vector<int> a{1, 2, 3, 4}; sort(a.begin(), a.end()); return 0; } 这里并没有 using namespace std 却可以不用显示指定 std::sort 来调用,应该不止我一个人在第一次写出这个并意识到的时候感到惊讶。 更重要的是,以下代码会 CE #include <algorithm> int main() { int a[10]{}; sort(a, a + 10); return 0; } 难道是 std::vector 的问题? 没错,就是因为 std::vector! 接下来让我来正式介绍一下 ADL(argument-dependent lookup)! 实参依赖查找(ADL),又称 Koenig 查找,是一组对函数调用表达式(包括对重载运算符的隐式函数调用)中的无限定的函数名进行查找的规则。在通常无限定名字查找所考虑的作用域和命名空间之外,还会在它的各个实参的命名空间中查找这些函数。[1] 简单来说就是,在进行函数调用的时候,先会在当前作用域(名称空间)寻找定义,找不到就会在实参的命名空间中寻找定义,还找不到就会报错。 在这些调用中,包含类自身,基类,外围类和最内层类的外层命名空间(当然,对于基础类型,如int之类其关联集为空);如果类模板已经特化实参,则还增加对实参类的命名空间及以其为成员的类。 注解 对于更多的细节,请查阅 cppreference.com 然后我们就可以写出这样的代码: #include <algorithm> #include <vector> class vec : public std::vector<int> { public: vec() : std::vector<int>() {} vec(std::initializer_list<int> il) : std::vector<int>(il) {} }; int main() { vec a{1, 2, 3, 4}; sort(a.begin(), a.end()); return 0; } sort 调用的时候,发现当前没有定义,然后到实参定义域中找,没有找到,又去他的基类找,基类是 std::vector<int>,在 std 名称空间中,于是找到了 std::sort 进行调用。 ADL 的用途通过前面的例子来看,这个东西好像除了增加阅读难度(完全不知道哪里来的函数)之外就没有用了,那么接下来举一个例子: #include <algorithm> #include <iostream> #include <vector> namespace test { class Demo { public: Demo(int a) : a(a) {} int get() const { return a; } friend std::ostream &operator<<(std::ostream &os, const Demo &d) { os << d.a; return os; } private: int a; }; } int main() { test::Demo d(114514); std::cout << d << '\\n'; return 0; } std::cout << 调用的时候通过 ADL 找到了位于 test 名称空间的 std::ostream &operator<<(std::ostream &os, const Demo &d),大大的简化了代码。 ADL 允许函数模板在不同名称空间定义,而不需要显示的指定作用域或者全局空间限定。 再来看一个例子: namespace N1 { struct X {}; void f(X); } namespace N2 { void f(N1::X); } void g() { N1::X x; f(x); // 调用 N1::f N2::f(x); // 调用 N2::f using N2::f; f(x); // 错误,Call to 'f' is ambiguous,同时存在了 N1::f 和 N2::f } 可以发现 using 的函数并不被当作当前作用域,而被当作了与 N1 同级的函数。 总结ADL 是 C++ 的一个重要语法概念,不过带来便利的同时也带来的一些不确定性(万一调用调飞了就全毁了),不过这个和允许函数重载是一样的,好用与否,还是在于使用的人。 参考文献[1] https://zh.cppreference.com/w/cpp/language/adl","categories":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"C++","slug":"C","permalink":"https://chy669086.github.io/tags/C/"}],"keywords":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}]},{"title":".bashrc 向 .zshrc 迁移的小妙招","slug":"bashrc-向-zshrc-迁移的小妙招","date":"2024-10-11T09:45:00.000Z","updated":"2024-10-11T09:45:00.000Z","comments":true,"path":"2024/10/11/bashrc-向-zshrc-迁移的小妙招/","link":"","permalink":"https://chy669086.github.io/2024/10/11/bashrc-%E5%90%91-zshrc-%E8%BF%81%E7%A7%BB%E7%9A%84%E5%B0%8F%E5%A6%99%E6%8B%9B/","excerpt":"","text":"昨天兴致突发安装了 zsh 并使用了 powerlevel10k 主题。有一说一 zsh 使用体验比 bash 好太多了,但是今天我发现了一个重大的问题:之前的所有配置都在 .bashrc,这些不会自动继承到 .zshrc,这可咋办?而且 zsh 和 bash 命令并不兼容,不能简单在 .zshrc 加一句 source $HOME/.bashrc 来解决。 直接 source $HOME/.bashrc 会出现以下报错 /usr/share/bash-completion/bash_completion:45: command not found: shopt /usr/share/bash-completion/bash_completion:1596: parse error near `|' 一种方法是把所有配置文件都重新迁移到 .zshrc,但是我懒,所以我找到了些小妙招。 发现在 bash 直接运行 zsh 会让 zsh 继承 bash 的所有环境变量,所以只要想办法让 zsh 启动的时候启动 bash 再用 bash 启动 zsh 就好了。 解决方法手动解决一种方法是手动解决 # 在 zsh 中执行 exec bash # 在 bash 中执行 exec zsh 改写配置文件另一种方法是改写 .zshrc 和 .bashrc。 首先,我们在 .zshrc 头部加入 if [[ -v __USE_ZSH ]]; then unset __USE_ZSH else echo "ENTER BASH!" export __USE_ZSH=1 exec bash fi 然后在 .bashrc 底部加入 if [[ $__USE_ZSH -eq 1 ]]; then echo "ENTER ZSH!" exec zsh fi 这两个命令大概就是:进入 zsh 先判断有没有 __USE_ZSH 这变量,有,就 unset 掉,否则创建 __USE_ZSH=1 然后进入 bash,bash 中如果发现 __USE_ZSH==1,就会进入 zsh,就很妙的把 bash 的环境变量偷过来了。 参考资料https://blog.csdn.net/qq_49030008/article/details/137921205","categories":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"linux","slug":"linux","permalink":"https://chy669086.github.io/tags/linux/"},{"name":"bash","slug":"bash","permalink":"https://chy669086.github.io/tags/bash/"},{"name":"zsh","slug":"zsh","permalink":"https://chy669086.github.io/tags/zsh/"}],"keywords":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}]},{"title":"2024 秋冬季开源操作系统训练营学习笔记","slug":"2024-秋冬季开源操作系统训练营学习笔记","date":"2024-10-08T13:07:47.000Z","updated":"2024-12-22T11:15:32.000Z","comments":true,"path":"2024/10/08/2024-秋冬季开源操作系统训练营学习笔记/","link":"","permalink":"https://chy669086.github.io/2024/10/08/2024-%E7%A7%8B%E5%86%AC%E5%AD%A3%E5%BC%80%E6%BA%90%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%AE%AD%E7%BB%83%E8%90%A5%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/","excerpt":"","text":"个人 Rust 开源训练营学习笔记(感觉更像日记),大概会隔一段时间更新一次 2024-11-23 >展开隐藏 快一个月没有更新了 今天又回去看了地址空间的知识。之前还是学的不扎实,昨天写阶段三的练习的时候又在想操作系统是怎么管理虚拟地址和物理地址的映射的。现在搞懂了,记录一下。 risc-v 在开启 mmu 之后所有地址访问都是虚拟地址,操作系统为了管理所有的内存,在开启 mmu 之前,需要提前建立一个虚拟地址到物理地址的映射。在 arceos 中是建立了一个零偏移的的虚拟地址到物理地址的映射(才知道地址可以被重复映射),初始化映射表之后,就可以进入 mmu 模式,之后就可以启动应用程序进入用户态了。 arceos 内核和应用用了两张页表,也就说每次 trap 的时候都需要刷一下 TLB 来保证地址访问正确。 每个进程申请内存的时候,操作系统都会从剩余物理空间中找一些空间来映射,虚拟地址的连续不代表物理地址的连续,也就是跨页的数据在物理上不一定是连续的(感觉好色)。 操作系统访问用户地址只需要找到用户的页表(前面整个内存都已经被操作系统映射了,所以操作系统可以访问所有的内存),并根据虚拟页表找到对应的物理页表,就可以直接访问(arceos 因为建立了零偏移的映射,所以不需要下一步转换,如果不是零偏移的转换需要再进行转换)。 2024-10-27 >展开隐藏 ch8 在 10-21 已经写完了,昨天又花了一些时间重构了一下,这个训练营无疑大大提高了我的编码能力和阅读能力。 在和群友的热烈讨论下,我也学习到了很多之前不怎么清楚的东西,但是还有很多不太懂的东西。 很期待三阶段的学习! 2024-10-18 >展开隐藏 ch6 简直噩梦 感觉写的东西问题很大,也没有完全搞懂文件系统和内存系统,就是照葫芦画瓢,我的文件系统是有严重的泄露问题的,但是不会改 今天一口气写了很多垃圾代码,然后还包括一个死锁(同志们调函数的时候一定要注意这个函数要不要持有锁)。 写好一个项目真是一门艺术。我 ch3 的代码在 ch4 ch5 ch6 分别重构了一遍,现在是我比较满意的一版。但是其他的我感觉写的就很怪,谁家结构体数据全部 pub 啊() 最近都没有去训练,都去写 os camp 了,现在只剩下最后一个要写代码的实验了,感觉晋级在望!感觉在这个训练营学到的真的很多,本来对操作系统只是一知半解,现在经过浅层的学习,了解到了很多以前只知道名词的概念,也对操作系统的数据组织形式有了更深的了解,同时也解开了以前对汇编的疑问。以前在想为什么汇编要有操作系统作为链接,一直以为汇编是和机器绑定的,是机器码。学习了之后才知道,原来系统中断是操作系统提供的,而且寻址也是被操作系统调整过的,操作系统调度了所有程序的运行,所有程序最终都是回归到操作系统中去的。 2024-10-12 >展开隐藏 ch3 在昨天看了一天才看懂要干什么我好菜啊 ch3 写完后本地单独测试都能过,但是一起测试就会起飞,debug 后发现 get_time() 函数一直输出的是 0。群内老哥说应该是 sbi 的问题,我也不懂我也不知道啊(x 然后我就重构了一下,我然后就写了一个很弱智的代码,重现一下大概是这个感觉: use std::cell::RefCell; fn main() { let task = Task::new(1); println!("Task id: {}", task.get_id()); } struct TaskInner { arr: [u32; 10], id: usize, } struct Task { inner: RefCell<TaskInner>, } impl Task { fn get_id(&self) -> u32 { self.inner.borrow_mut().arr[self.inner.borrow_mut().id] } fn new(id: u32) -> Task { Task { inner: RefCell::new(TaskInner { arr: [id; 10], id: 0, }), } } } self.inner.borrow_mut().arr[self.inner.borrow_mut().id] 直接借用两次直接起飞( 警钟撅烂 ch3 我的实现十分的垃圾,感觉性能完全不行( ch4 直接告诉我要重写( 杀了我算了 2024-10-9 >展开隐藏 一上来第一件事就是抛开了 rust 标准库。我应该能想到的,毕竟标准库需要依赖系统,但是 OS Camp 要开发一个系统。这下轮子都要自己造了。 我不会 RISV-V 汇编啊! 训练营用的是 Qemu7.0 模拟器模拟环境。rust 编译使用 riscv64gc-unknown-none-elf 编译环境 注解 riscv64gc-unknown-none-elf 的 CPU 架构是 riscv64gc,厂商是 unknown,操作系统是 none, elf 表示没有标准的运行时库。没有任何系统调用的封装支持,但可以生成 ELF 格式的执行程序。 我们不选择有 linux-gnu 支持的 riscv64gc-unknown-linux-gnu,是因为我们的目标是开发操作系统内核,而非在 linux 系统上运行的应用程序。 在加入编译命令 riscv64gc-unknown-none-elf 后再在 main.rs 加入 #![no_std] 后,如果在 vsc 使用 rust-analyzer 的时候会出现 Can't find crete test 的报错,但是程序又是没有问题的,这是一个 bug,官方 issue。 只要在 vsc 的 settings.json 加入以下内容就行了 { "rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.checkOnSave.extraArgs": [ "--target", "riscv64gc-unknown-none-elf" ] } 以及训练营给出的解答: { // Prevent "can't find crate for `test`" error on no_std // Ref: https://github.com/rust-lang/vscode-rust/issues/729 // For vscode-rust plugin users: "rust.target": "riscv64gc-unknown-none-elf", "rust.all_targets": false, // For Rust Analyzer plugin users: "rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf", "rust-analyzer.checkOnSave.allTargets": false, // "rust-analyzer.cargo.features": [ // "board_qemu" // ] } 实验是在裸机平台上进行的(这不是放屁吗,os 还能在哪里跑)。 看见那些中断和汇编调用,我已经要去世了 api 与 abi 的区别 说真的之前都不知道有 abi 这个东西。 API Application Programming Interface ABI Application Binary Interface 简单来说,ABI 就是二进制接口,来自系统底层,所有程序都可以通过遵守 ABI 来调用;API 一般局限在一个编程语言,定义了源码级别的操作。 训练营给的解释 API 与 ABI 的区别 应用程序二进制接口 ABI 是不同二进制代码片段的连接纽带。ABI 定义了二进制机器代码级别的规则,主要包括基本数据类型、通用寄存器的使用、参数的传递规则、以及堆栈的使用等等。ABI 与处理器和内存地址等硬件架构相关,是用来约束链接器 (Linker) 和汇编器 (Assembler) 的。在同一处理器下,基于不同高级语言编写的应用程序、库和操作系统,如果遵循同样的 ABI 定义,那么它们就能正确链接和执行。 应用程序编程接口 API 是不同源代码片段的连接纽带。API 定义了一个源码级(如 C 语言)函数的参数,参数的类型,函数的返回值等。因此 API 是用来约束编译器 (Compiler) 的:一个 API 是给编译器的一些指令,它规定了源代码可以做以及不可以做哪些事。API 与编程语言相关,如 libc 是基于 C 语言编写的标准库,那么基于 C 的应用程序就可以通过编译器建立与 libc 的联系,并能在运行中正确访问 libc 中的函数。 link 2024-10-8 >展开隐藏 上学期第一次了解到 rust 语言。第一次听到 rust 是来自他的外号“语言神”(原神启动!),以及了解到 rust 的最大特色:编译错误。 学习了一段时间后,感觉 rust 是真**的优雅,所有权、生命周期、借用规则让我醍醐灌顶。也让我把这套规则移动到了其他语言使用,也是大大加速了我的编写速度。 学习阶段去写了 rustling、mini-lsm 开源学习项目(mini-lsm week3 开头给我干爆炸了就没有继续写下去)。 感觉还是不是很深得 rust 开发的精髓。写起来 C 里 C 气。感觉取悦编译器也是一门技术活(最经典的 rust 序列访问会生成 assert,所以可以提前 assert 减少 assert 次数)。 cargo 是世界上最好的包管理器! 感谢 Rust语言圣经(Rust Course)、Rust 程序设计语言 和其他网络上的作者贡献的大量的学习资源。 现开源训练营一阶段晋级。(牛魔的 unsafe 链表真是依托) 顺便吐槽一下 C++ 那依托的 tuple","categories":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"2024 秋冬季开源操作系统训练营","slug":"2024-秋冬季开源操作系统训练营","permalink":"https://chy669086.github.io/tags/2024-%E7%A7%8B%E5%86%AC%E5%AD%A3%E5%BC%80%E6%BA%90%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%AE%AD%E7%BB%83%E8%90%A5/"},{"name":"Rust","slug":"Rust","permalink":"https://chy669086.github.io/tags/Rust/"},{"name":"学习笔记","slug":"学习笔记","permalink":"https://chy669086.github.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"keywords":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}]},{"title":"C++ CRTP 简介","slug":"C-CRTP-简介","date":"2024-10-05T14:08:24.000Z","updated":"2024-11-27T04:11:35.000Z","comments":true,"path":"2024/10/05/C-CRTP-简介/","link":"","permalink":"https://chy669086.github.io/2024/10/05/C-CRTP-%E7%AE%80%E4%BB%8B/","excerpt":"","text":"最近看群友讨论到了“虚函数就是历史遗留问题,现在完全可以用 CRTP 代替”,好奇,就去搜索了什么是 CRTP,结果发现这么早的一个技术我现在才知道,真是落后时代 10 余年。 虚函数与动态链接C++ 的多态是通过虚函数实现的,虚函数的实质是在对象中开辟了一个空间来存储函数指针(虚函数表 vtable),调用这个函数是通过这个指针去访问,而不能在编译期确定。 比如: class Animal { public: virtual void jump() = 0; }; class Cat : public Animal { public: void jump() override { std::cout << "cat jump\\n"; } }; int main() { Animal *p = new Cat; p->jump(); return 0; } 调用 p->jump() 的时候,程序会去虚函数表寻找那个指针,在这个程序中最终会调用 Cat::jump()。 但是查表终究是有代价的,有没有兼顾多态和效率的做法呢,于是,CRTP(Curiously Recurring Template Pattern) 应运而生。 通过模板实现静态绑定首先复习一个概念,C++ 的模板是编译期多态,是零成本抽象。我们在子类和父类中定义同一个函数,但是不声明为虚函数,通过编译期多态来实现绑定。 template <typename T> class Base { public: void show() const { static_cast<const T*>(this)->show(); } }; class Driver : public Base<Driver> { public: void show() const { std::cout << "This is class Driver." << std::endl; } }; int main() { Base<Driver> *p = new Driver; p->show(); return 0; } 这是一个简单的例子,有下列特点 基类是模板类,用来接收子类的名字,因此继承类似于 ClassName : public Base<ClassName>。 基类的函数中,用 static_cast<> 将基类的指针转换成子类的指针实现绑定。 运行上述程序,得到结果 This is class Driver. 说明我们成功进行了子类与父类的绑定,实打实的调用了子类的 show() 函数。 有什么用,怎么用众所周知,多态一般需要类似 std::vector<Base*> 的形式,但是由于我们的基类是模板类,不能通过这种方式多态,不如说,没有多态,因为 Animal<Cat>* 和 Animal<Dog>* 是两个完全不同的指针。 那怎么办? 考虑到一次查表的开销不是特别大,虚函数带来的大量开销主要是多层继承带来的巨大链条带来的查询开销,继承链很短的话开销其实是在预期内的。 那我们用一个模板基类继承一个普通基类,这个普通基类使用虚函数,但是模板基类使用静态绑定,派生类去继承这个模板基类,那么不论如何,我们都只需要查一次表就可以定位到对应的函数,大大降低了多次继承带来的开销。 class Animal { public: virtual void say() const = 0; virtual ~Animal() {} }; template <typename T> class Animal_CRTP : public Animal { public: void say() const override { static_cast<const T*>(this)->say(); } }; class Cat : public Animal_CRTP<Cat> { public: void say() const { std::cout << "I'm a cat.\\n"; } }; class Dog : public Animal_CRTP<Dog> { public: void say() const { std::cout << "I'm a dog.\\n"; } }; int main() { std::vector<Animal*> v; v.push_back(new Dog); v.push_back(new Cat); for (auto x : v) { x->say(); } return 0; } 输出结果 I'm a dog. I'm a cat. 不过写起来确实很麻烦,而且没有 override 带来的部分编译提示(字打错了跑哪里哭去),但是这样写我们同时赢得了多态和效率(同时代码量极致膨胀)。 为什么有人还在用继承啊 2024-11-27 ADDC++23 带来了一个神奇的 this auto &&self 语法, CRTP 于是有了一个神奇的写法 #include <cstdio> struct Base { void name(this auto &&self) { self.impl(); } }; struct D1 : public Base { void impl() { std::puts("D1::impl()"); } }; struct D2 : public Base { void impl() { std::puts("D2::impl()"); } }; int main() { D1 d1; d1.name(); D2 d2; d2.name(); } C++ 标准有点过于色琴了 参考文献[1] https://en.cppreference.com/w/cpp/language/crtp","categories":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"C++","slug":"C","permalink":"https://chy669086.github.io/tags/C/"}],"keywords":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}]},{"title":"2022 ICPC 杭州区域赛 K 题题解","slug":"2022-ICPC-杭州区域赛-K-题题解","date":"2024-10-02T09:01:08.000Z","updated":"2024-10-02T09:01:08.000Z","comments":true,"path":"2024/10/02/2022-ICPC-杭州区域赛-K-题题解/","link":"","permalink":"https://chy669086.github.io/2024/10/02/2022-ICPC-%E6%9D%AD%E5%B7%9E%E5%8C%BA%E5%9F%9F%E8%B5%9B-K-%E9%A2%98%E9%A2%98%E8%A7%A3/","excerpt":"","text":"题目大意给你 $n$ 个字符串,然后有 $q$ 次询问,每次询问给出一个字典序,请你输出在这个字典序下的逆序对个数。 题解首先考虑暴力,每次询问可以 $O(|S|\\log(n))$ 处理,显然会超时。 考虑优化,注意到两个字符串比较出结果一定是在某个位置发生的(称这个比出大小的比较为决定性比较),这两个字符串一定有一个相同的前缀(长度可能是 0)。那么可以把问题转换成判断某个字符和其他字符发生了几次决定性的的比较,那么对于每次询问我们和 $O(26 \\times 26)$ 处理。 如何找到发生了几次决定性的比较呢,注意前面的一个性质,决定性比较之前的两个字符串一定是同前缀,这正好撞上了字典树的性质:相同前缀共用一条链。 我们只要统计每个节点的后继节点字符总数,就可以对每一个新插入的字符串进行决定性比较的统计。对于 a 和 aa 这种串,我们可以简单在每个串后面加一个字符,并人为将这个字符的字典序设置为最小 // 字段树节点 struct node { // 后继节点位置 std::array<int, 27> nxt; // 后继节点个数统计 std::array<int, 27> sum; node() { std::fill(all(nxt), -1); std::fill(all(sum), 0); } }; // 决定性比较次数统计 int cnt[27][27]; struct Trie { std::vector<node> nodes; int root = 0; Trie() { nodes.emplace_back(); } void insert(const std::string &s) { int cur = root; for (char c : s) { if (nodes[cur].nxt[c - 'a'] == -1) { nodes[cur].nxt[c - 'a'] = nodes.size(); nodes.emplace_back(); } // 统计这个串的这个位置决定性比较次数 for (int i = 0; i < 27; i++) { cnt[c - 'a'][i] += nodes[cur].sum[i]; } // 后继节点计数加一 nodes[cur].sum[c - 'a']++; cur = nodes[cur].nxt[c - 'a']; } } }; 全部代码 #include <algorithm> #include <array> #include <cassert> #include <cctype> #include <cmath> #include <cstdint> #include <cstdio> #include <cstring> #include <iostream> #include <ostream> #include <string> #include <vector> #ifdef DYNAMIC_PIGEON #include "algo/debug.h" #else #define debug(...) 114514 #endif #define Dynamic_Pigeon 0 using i64 = std::int64_t; using u64 = std::uint64_t; using u32 = std::uint32_t; constexpr i64 MOD = i64(1e9) + 7; constexpr int INF = 1e9; constexpr i64 INF_LONG_LONG = 1e18; #define all(a) a.begin(), a.end() #define rall(a) a.rbegin(), a.rend() #define int i64 struct node { std::array<int, 27> nxt; std::array<int, 27> sum; node() { std::fill(all(nxt), -1); std::fill(all(sum), 0); } }; int cnt[27][27]; struct Trie { std::vector<node> nodes; int root = 0; Trie() { nodes.emplace_back(); } void insert(const std::string &s) { int cur = root; for (char c : s) { if (nodes[cur].nxt[c - 'a'] == -1) { nodes[cur].nxt[c - 'a'] = nodes.size(); nodes.emplace_back(); } for (int i = 0; i < 27; i++) { cnt[c - 'a'][i] += nodes[cur].sum[i]; } nodes[cur].sum[c - 'a']++; cur = nodes[cur].nxt[c - 'a']; } } }; void tizzytyt_SuKi() { int n, q; std::cin >> n >> q; Trie trie; for (int i = 0; i < n; i++) { std::string s; std::cin >> s; s.push_back('a' + 26); trie.insert(s); } while (q--) { std::string s; std::cin >> s; s = (char)('a' + 26) + s; i64 ans = 0; for (int i = 0; i < 27 - 1; i++) { for (int j = i + 1; j < 27; j++) { ans += cnt[s[i] - 'a'][s[j] - 'a']; } } std::cout << ans << '\\n'; } } signed main() { #ifdef DYNAMIC_PIGEON freopen("input.in", "r", stdin); #else std::cin.tie(0)->sync_with_stdio(0); #endif tizzytyt_SuKi(); return Dynamic_Pigeon; }","categories":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"C++","slug":"C","permalink":"https://chy669086.github.io/tags/C/"},{"name":"ICPC","slug":"ICPC","permalink":"https://chy669086.github.io/tags/ICPC/"},{"name":"题解","slug":"题解","permalink":"https://chy669086.github.io/tags/%E9%A2%98%E8%A7%A3/"}],"keywords":[{"name":"笔记","slug":"笔记","permalink":"https://chy669086.github.io/categories/%E7%AC%94%E8%AE%B0/"}]},{"title":"C++ search 函数","slug":"C-search-函数","date":"2024-10-01T12:34:15.000Z","updated":"2024-10-01T12:34:15.000Z","comments":true,"path":"2024/10/01/C-search-函数/","link":"","permalink":"https://chy669086.github.io/2024/10/01/C-search-%E5%87%BD%E6%95%B0/","excerpt":"","text":"简介std::search 函数在 C++ 很早的版本就开始存在了,但是在 C++17 中添加了一些重载和辅助类,这大大提高了这个函数的使用价值。这篇文章主要来介绍下面这个重载。 template< class ForwardIt, class Searcher > ForwardIt search( ForwardIt first, ForwardIt last, const Searcher& searcher ); 元素名称 元素意义 first, last 要检验的元素范围 —— 一般是迭代器 searcher 封装搜索算法和搜索模式的搜索器 这是从 C++17 开始给 std::search 添加的函数重载,Searcher 是搜索器,接下来就是这个函数最有用的地方了,C++ std 提供了三种搜索器: default_searcher (C++17) 标准 C++ 库搜索算法实现 boyer_moore_searcher (C++17) Boyer-Moore 搜索算法实现 boyer_moore_horspool_searcher (C++17) Boyer-Moore-Horspool 搜索算法实现 注意到标准库提供了 BM 算法的搜索器,BM 算法一直被称为最快的字符串搜索算法,在实际表现中一般比 KMP 快 2~3 倍(暴力算法在大部分时候其实表现也比 KMP 好)。但是由于 BM 算法的最坏时间复杂度是 $O(nm)$,所以不建议在算法竞赛中使用,但是在生产环境中,BM 算法无疑是最佳选择。 使用举例#include <functional> #include <iostream> #include <string> int main() { std::string s = "never"; // 用 s 创建一个搜索器 std::boyer_moore_searcher searcher(s.begin(), s.end()); std::string text = "never say never"; // 在 text 中搜索 s auto result = std::search(text.begin(), text.end(), searcher); if (result != text.end()) { std::cout << "The text contains the substring \\"never\\" at position " << result - text.begin() << '\\n'; } else { std::cout << "The text does not contain the substring \\"never\\"\\n"; } // 在另一个文本中搜索 s text = "always say always"; result = std::search(text.begin(), text.end(), searcher); if (result != text.end()) { std::cout << "The text contains the substring \\"never\\" at position " << result - text.begin() << '\\n'; } else { std::cout << "The text does not contain the substring \\"never\\"\\n"; } return 0; } 输出结果 The text contains the substring "never" at position 0 The text does not contain the substring "never" 参考链接cppreferrence.com","categories":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"C++","slug":"C","permalink":"https://chy669086.github.io/tags/C/"}],"keywords":[{"name":"技术","slug":"技术","permalink":"https://chy669086.github.io/categories/%E6%8A%80%E6%9C%AF/"}]}]}