Ratled

精神zjuer

@Ratled

  • ❤️ Liked post in 我的一个朋友
    谈笑风生
    IO IO Post #19

    十多年前答题注册 b 站的时候周围现充基本不知道这个网站,那时候 b 站有一点非日本欧美的三次元就会被群起攻之,现在再刷 b 站基本很难找到二次元的东西不说,竟然从一个起源于日本弹幕网站,底蕴是日本文化的社群演变成现在反日仇美的环境,相反的是隔壁起源于 imdb 的豆瓣是通过赶走大量用户筛选粉红变成现在这样的,这两个底蕴是外来先进文化的社群通过不同的用户集聚方式变得瓦房店化,真让我不禁感叹打文化战谁比得过共

  • hoist hoist Post #8

    首先,门的热度不够,什么校园集市 QQ 群,消息都是远远的多。
    更重要的,求购者不会花时间常常检查一个网站内容。我自己在保研前夕的时候,也懒得一个个查学校官网。(大多用第三方聚合源或者网站更新提醒工具)。Qq 群只是平常看群消息的时候,顺带看一下卖什么东西。
    以前也有过,二手网站。然后变成那种只卖大型商品的,最后就死了。

  • Hypocrisy rotartsinimdA Post #27

    我猜测是花钱外包部署开源架构。
    虾饺和瓜大好多页面都是同一个模板,换个校徽安能辨我是虾瓜

  • Hypocrisy rotartsinimdA Post #22

    白花花的银子能给学生花吗。。

  • Rin Tomotake Rin Post #43

    除了高新以外别的都只是杜比全景声,没有用杜比的投影和画面处理方案

  • Rin Tomotake Rin Post #14

    刚整完了 IMAX XT,沙丘 2 打算去杜比影院看
    没公众号说的那么极端,正常维护的 xt 播放暗光场景没啥压力。xt 的强光场景已经需要眯着眼睛看了,要是 cola 的话估计得 daisuke 了()

  • anonymous_coward_old Anonymous Coward Old Post #1

    看过《杜非立上进记》的人都知道,我之前运营过 C++ 难民营(学科群)QQ 群、选课交流群,又在水源社区先后担任站务和技术负责人,现在又在开发运营选课社区。这些社群、社区运营都取得了非常好的用户量和活跃度。

    在今年,我还和中科大南七茶馆论坛的开发者交流过水源社区运维经验,潜入了华师大 ECNU.IM 论坛观察,和 USTC 评课社区开发者交流过相关经验,还指导了北师大的同学用 SJTU 选课社区的代码部署 BNU 选课社区。和这些项目相比较的话,水源社区无疑比其他几个论坛高了 1 到 2 个数量级的热度,而师出同门的选课社区在 SJTU 也比在 BNU 热度高。

    碰巧的是,在暑假实习中,我在没有预先选择的情况下,被分到字节跳动 TikTok 的用户增长服务端开发团队,在开发之余也学习了一番用户增长理论。通过理论结合实际的分析,我想了想,做成功这些产品,还是有一些原因的。

    用户增长,主要做几件事情:拉新、促活、内容激励。拉新,指获得新用户,关注指标通常为 DNU(daily new user)。促活,指促进已注册用户活跃度,关注指标通常为 DAU(daily active user)。内容激励,指激励用户发布内容,间接增长 DAU 和 DNU。为了拉新促活,往往需要布置一些触点用来触达用户,比如弹窗、挂件、推送等。在《增长黑客》里提到,好产品是增长的根本,也就是要打造产品的不可或缺性。除此之外,也有观点认为,用户增长=动力 - 阻力。动力,指用户使用产品的动机,比如产品的内容对他有很大吸引力等。阻力,指阻碍用户注册的因素,比如用户注册的流程繁琐等。

    在运营 C++ 学科辅导群时,同学加群的意愿就是获得作业和考试的辅导。那我就做好内容,提前录制了一些讲解视频,整理了一些文档和资料放在群文件。这样同学进群的时候就有东西可以看。等到期末考试前,我在群里基本上是有问必答,所以这群名气出去了有很多同学愿意加群来听和问问题。

    在运营选课交流群时,同学加群的意愿是询问课程情况,以便选课。没有选课群的时候,大家会在新生群问。一些学生组织、社团内部也会有自己的总结。我们在选课群之前,就有同学率先收集了一份问卷资料,大概 200 份课程情况问卷并整理出来做成 PDF。这个 PDF 就对同学很有吸引力,我们把它放在群里。然后我们立了群规,禁止非选课事项的讨论、禁止询问明文通知的内容。因为这种群人很多,有的同学就可能问一些别的事情,这样会冲淡群氛围,影响后续管理。最后是按时发布教务处关于选课的通知,提醒及时选课。选课期间我们在新生群说,选课群里有资料可以看,有学长学姐可以问,就达到了触达的效果,吸引了一大批新生进群。而为了促活,选课群定期清理不改群昵称和长期没说话的同学。后来又发了 2 次问卷,整理出了 400 多条课程点评。

    在运营水源社区时,主要抓的触达和促活。一开始是上海交通大学发了一篇推送,面向全校公测新水源社区。后来逐步增加了官网下方、迎新网和综合信息网的入口链接,看上去效果其实一般。我们一直想在新生录取通知书里放广告,未果,不过今年有机会在交我办 app 的新生模块那加了个入口,效果非常明显,预估有 70% 的 22 级新生都注册了水源。另外是抓热点事件,这种机遇比较难得。20 年 2 月公测到 9 月,靠着自然增长一共注册了一万个用户。而 9 月的七彩花坊事件,直接带来了用户量翻倍。我们趁着用户量增加的同时,及时调整了分类,主动编撰导入优质的信息资料(比如分流、转专业、保研等),增加了用户粘性。22 年 3 月,由于疫情封校,直接增加了 5-10 倍的日活量。在这期间,开辟了防控信息专楼,收集整理了每日最新进展,很多用户也以非官方身份发布了各种信息。还有一件事是降低用户入口阻力。一开始即便我们有 jAccount 登录,也要去验证邮箱获取验证码。我寻思这多此一举,后来直接拿掉了这个流程,jAccount 登录之后就直接进主页,实现一键登录。这一点在封校流量突增的时候表现非常好,没有拖后腿。至于运营举办的各种活动,我感觉从促活效果上没有那么明显,不过在奖励活跃用户这点来说还是有用的。在促活方面,一开始首页按照传统论坛定为“分类”,但是我个人会喜欢以时间线排序不区分分类。后来有一次在用户建议下把全站用户的首页都改成了“最新”,日活立竿见影提高了 5 倍。分析之,首页为类别,就不会显示话题,用户不知道到底有哪些可以阅读、可以回复,一定要选择一个分类才行,而且只有这个分类。首页为最新,用户就少了一步,可以直接看到所有话题,开屏就能进入话题阅读和回复。

    在运营选课社区时,最大的成功点就是之前整理的 400 条点评。我们在上线运营之前,就导入了这 400 多条问卷点评作为冷启动素材。这样用户访问的时候就能看到内容,而不会因为没有内容而流失。在降低门槛方面,我也考虑了很多。比如,服务器一定要在境内,这样不会有网络问题。不能使用 GitHub,因为要额外注册。接入 jAccount 实现一键登录访问。在推广方面,在选课社区上线前,选课交流群已经发展到了 2 个 2000 人规模的群。我们在群里直接推广了社区链接。后来由于积累的点评很多,对新生很有价值,其他组织也会在其公众号上主动推广链接。在促活方面,主要关注的是点评的数量和质量。选课社区引入了积分机制,根据点评数量和赞计算积分,而积分和交大传承合作,可以兑换传承的积分,从而在传承下载文档。

    接下来是关于其他平台的一些锐评。

    和中科大的南七茶馆开发者讨论后,我觉得影响二者发展的最大因素的学校态度。水源社区是交大网宣办主动推动建设的,网络信息中心给服务器和带宽资源,宣传部给门户入口资源,相当于是含着金钥匙出身。南七茶馆是学生民间运营的,学校对其不看好,不提供资源。这样就导致南七茶馆的触达面小,加上没法使用学校的身份认证系统,注册也比较麻烦,所以用户量和日活会差很大一截。从运营上考虑,一些活动和版面设计其实没有太大影响,完全可以顺着用户规模增加逐步调整。我当时和他们讲,这种正经的校园论坛,就应该和学校合作,放弃反审查的不合作思维。运营校内论坛对学校来说是好事,因为很多事情就可以内部消化,不外溢到公共平台,维护了学校的形象。华师大的 ECNU.IM 也是一样的问题,没有触达到用户,绝大多数的在校生不知道有这么个东西存在。

    当然,水源社区的发展和无可奉告有关系。无可奉告是交大同学的大作业,后来转换成了实际投用的匿名树洞。无可奉告从 2020 年 12 月上线到 2021 年 4 月关服,不到半年的时间内有一万多用户发布了两万多个树洞和三十九万个回复。在我看来,无可奉告是非常成功的。除了匿名树洞这个自带吸引人的要素外,他们做好了几点。第一,提供了安卓 iOS 双端客户端。这一点对于商业平台来说是必要的,而对于学生开发项目来说代价非常高。无可奉告的团队能够开发出 2 个平台的客户端,并且都是原生框架,体验非常好。第二,在微信公众号注册并发布了上线推送。微信推送在朋友圈能够触达很多学生、老师和校友,而且从微信的屏蔽规则来说也比另外的网站好。这样在当天就有大量的注册用户,顺利实现冷启动的惊险一跃。就我个人而言,无可奉告由于一开始热度高,内容快而且猎奇,我自己就想着没事刷刷,所以很容易产生用户粘性。在运营方面,无可奉告秉持陶片放逐法,扼杀了很多钓鱼佬,虽然很有争议,但是保障了内容质量。等到后来无可奉告因为监管原因不再运营之后,水源社区才接住了校内的大量流量。如果无可奉告能运营到今年,那么水源社区必然不会有目前的日活。

    无可奉告关闭之后,断锚和亦可赛艇横空出世,都试图吃下匿名树洞的蛋糕,但是都有着致命问题,就是没有完善的客户端。断锚是 UNI-APP 开发的跨端 app,安卓端本身能正常用,但是开发者保持匿名,不上线 App Store。亦可赛艇客户端体验还可以,但是上线 App Store 被拒。所以他们都没法在 iOS 用户中普及。断锚一开始只在某个群里发了链接,触达用户太少,冷启动失败。亦可赛艇冷启动缓慢,如果能够解决 iOS 问题,我觉得还是能够正常发展,只是缺乏机遇。另外的问题是,亦可赛艇管理员在运营方面经验不够充分,上线一年多以来至今没有出台明确的管理规范。很多用户打开 App 的第一眼印象就是不堪入目,印象不是很好。水源的指导老师梁女士曾说,要开屏即见正能量。在我看来正能量有点夸张了,但是要开屏就能留住用户,能够让用户有继续探索的欲望,特别是激发用户的参与。

    交大柠檬是另外一个平台。它是一些同学的创业项目,属于小清新风格。交大柠檬和水源几乎是同期上线的,都是 2019 年底,但是生态位不一样。水源是标准的论坛,不额外在功能上有独特定制。柠檬是自己开发的小程序,可以发展树洞以外的功能,比如定制了二手交易和拼车功能,这个体验会比水源好。交大柠檬另辟蹊径从生态位出发,特色在二手交易、失物招领、拼车和教务处通知,也狠吃了一波疫情流量。从触达上考虑,柠檬本身就在微信端内,只要有二维码就很好触达,也可以充分利用朋友圈转发。

    而北师大的 BNU 选课社区,在我看来属于运营方缺乏经验。当时这个负责同学找到我咨询 SJTU 选课社区的代码如何部署,我给他讲的是,技术问题是最简单的问题,运营和法律上的问题才是最头疼的。BNU 选课社区去掉了用户账户部分,所以网页上是无需登录的匿名提交。这样在很多人看来是反审查斗士,保护了大家的隐私。但是在我看来是没有办法将发表点评这件事转化到用户的成就感上,没有办法引入积分奖励机制,也没有办法统计用户数量。另外,他们没有做好冷启动的过程,在几乎没有存量点评的时候就发布上线。用户访问社区时,基本没有想要的点评,很快就流失了。再加上可能的触达问题,BNU 上线接近半年了,对于 3000 多门课只有 200 多条点评,对未来的新用户还是缺乏吸引力的。

  • uika_winwing uika_winwing Post #12

    江浙沪飞日本就两小时,要滑雪的话去东北地方·北海道或许也可,景色也好,吃的也好

  • 谈笑风生
    TsuinoSora TsuinoSora Post #39

    给自己引下:

  • anonymous_coward_old Anonymous Coward Old Post #10

    试试交大门添加照片写个游记呢?插多个图片在一块的话可以点预览区选择网格模式:

    可以手动把多个图像添加到

    块里,或点击帖子中第一张图像旁边的网格图标,自动将图像或媒体整齐地排列成网格。

  • flyaway Post #8

    确实挺爽的,11.9 回来的,第一件事是在学校食堂吃便宜的 7 块钱肉夹馍哈哈哈哈(西藏物价真 tm 贵,关键是报吃,7 块钱在那边估计只能买到一个胚)
    在西藏待了一个星期,来回火车花了三天,总共离校 10 天
    说灵魂得到了洗涤还是挺夸张的,但参观了挺多的寺庙,第一次感受到景点内当地人比游客多,当然旺季我就不晓得了。膜拜了一下有信仰的民族,每个朝拜的人都很虔诚,会往钱箱子里投纸币,额度不大但人手一沓。
    我是一张钱也没有,因为咱没有信仰,但是逛布达拉宫听讲解员说文殊菩萨代表智慧,好多朝拜的人把额头贴在那个墙上,我就立马把额头放上去了。
    我只能说最难忘的是路上遇到了很多不一样的灵魂,大家都是抱着对人生发展的寄托去的,而我是因为有时间才去的(感觉之后就要一直当社畜了,就预先解放一下)。湖南的姐姐说她老公承诺要陪她去一趟西藏但十年过去了都没有兑现,就无论如何一个人来了;火车上铺的广东佛山的两个六十多岁的阿姨已经出来游玩几个月了,这次从新疆又到西藏,之后还会去别的地方,她们是妥妥的特种兵;我还结识了一个聋哑人阿姨,她真的对生活太有热情了,看到当地人手里的别致东西就会上手去摸,还说她儿子和我一般大要我当她儿媳妇哈哈哈哈;免费带我们下山到布达拉宫后面的司机原先在哲蚌寺当和尚,至今未婚。后来报团的时候也很幸运地遇到了很多有趣的人,一路吃的都是川菜,几头饿狼吃的贼香(西藏好多饭店都是川菜,但是真的很好吃);开了十多年车的四川司机给我们介绍当地人的习俗,比如一个女的会嫁给一户人家的几个兄弟轮流生孩子这种,真的好夸张感觉不能全信;被男朋友突然玩失踪又被他膈应的汉中姐姐;非常 social 的四川姐妹花,一路上能 handle 住司机放的六七十年代的音乐还可以摇;自从生了孩子就再没有一起出来过的湖北夫妻,这次想给 30 岁之前的人生一个交代同时展望新旅途。
    听别人的故事很有趣,我感觉到世界豁然开朗,但又不得已回到充斥同龄人的学校,不是说不好,但是在旅途中觉得一切都有可能性的我一回来干劲全无。就好像我只能在冒险中才能活下来。
    最后再说一下高反吧,我骄傲死了,一口氧气都没吸(除了吸了一口汉中姐姐的便携式氧气感受下是什么味道,什么味道都没有,就是妥妥的平原的空气),珠峰回来的那天晚上一行人中就我睡的最香,一觉睡到天亮,旁边的四川姐姐跟她对象聊天都没影响到我,但每个人体质不一样,可能我比较幸运吧。
    严格意义上说,这是我这辈子第一次旅行,感觉旅行好像有什么,又好像没什么。我本来想系统写一篇游记的,但断断续续写了没能坚持下去,知乎编辑文章添加照片真他娘地麻烦。

  • anonymous_coward_old Anonymous Coward Old Post #3

    我要是干校长,我会革除沉疴顽疾,以提高师生幸福指数为己任,首先我会:把现有的校园信息数字系统给更新一遍

    • 组织团队开发满足师生需求的教务应用并开源,IIRC,现有的一个开源的都没有,这将是一大创举,至少在国内而言。现有的 <ehall.xjtu.edu.cn> 简直是狗屁。
    • 引入 Jira,这是个世界一流的 [Issue & Project Tracking Software,简单来说就是个将所有需要纸质/审批程序的变成在线电子流程。现有的在线学生事务大厅 <one.xjtu.edu.cn> <one2020.xjtu.edu.cn> <eip.xjtu.edu.cn> 也是狗屁不通的网络程序,甚至最近几年更是降智到了企业微信。当前主页上还有个校长信箱更是个笑话。
    • 强制所有 xjtu.edu.cn 域名的网络应用走 SSL/TLS 非明文网络传输协议,并加到 https preload list 里。
    • 更安全的校园网络访问,现有的开放式无线网络 STU 简直是智障,应当参考企业里的 802.11 企业版无线认证协议,并优化信号覆盖、流量资费、在线设备数量。
    • 将所有教学楼的 PXE/Windows7 云桌面全部更新成更安全和可控的 Linux,在师生中大力推广开源软件。Windows7几年前早已失去安全支持
    • 引入全球领先的 SlackDiscourse 用于全校师生的交流。
    • 学校 host 一部 GitLab,将 git 渗透到学习的每个角落,例如:
      • 每位同学辅一入学进行 git init,记录大学四年学习和成长经历,免得找工作时 Résumé 不知道写什么。树立一切以成绩/保研为导向的风气,而是以 这份大学经历能够为你的人生书写什么值得记录的东西 为导向。
      • git 可以用作带有版本记录的 cloud storage,例如和作业系统有机配合。

    与此同时,最重要的是提升师生的幸福感。一个方法是收集并调查所有不幸福感的来源,并从源头解决问题。

  • ❤️ Liked post in “成功”了,然后呢?
    深入交流
    3ee28fe1a60c95b89d29317f122c70 3ee28fe1a60c95b89d29317f122c70 Post #1

    最近通过观察这个世界,发现了很多有意思的事。许多学生在上学时候不断的被老师和学校灌输“分考高了就成功了”,“上了某学就成功了”,“读了某项目就成功了”,“题做的比别人多就成功”了的思维方式,但却很少思考从“上了某学”到能够过一个质量比较高的人生中间的步骤。

    这样的结果就是许多人从来不思考怎么样让人生变好,而是一直优化理论上会使人生变好的某些指标,到最后发现指标显示自己应该赢了,人生却并没有变好。甚至搞的还远不如一开始理论上过的会的不如自己却对自己到底想要什么样的人生想的比较多并付出行动的人。如果能够清楚自己想要什么并去做,可能某些指标评价体系下数字不会变高,但是却确实在向自己比较希望的方向移动,没有不加思考的游走。

  • greyishsong greyishsong Post #5

    我自己组了一台小机器做 NAS,也是今年图形学实验的评测机 🤣

    个人方案

    硬件用 ITX 板型的 J3455 板 U 套装(这个 CPU 是 Intel 赛扬产品线的一款低功耗 CPU,直接焊在主板上出售)加乔思伯的 NAS 机箱,目前是

    • 16 GB DDR 4 SO-DIMM 内存(两条 8 GB)
    • 一个 NVMe 硬盘位(实装一块 256 GB 固态硬盘)
    • 五个 SATA3 硬盘位(实装两块 1 TB 机械硬盘)

    机器本身挺小巧的,大致比那种 12 盒装特仑苏的小纸箱长 1/3,宽度和高度和它差不多。

    软件方面,

    • 机器本身装 Proxmox VE 做成一个虚拟化平台
    • 开一个虚拟机实例装 OpenMediaVault(目前比较好的开源 NAS 系统),配置为 1 核心 CPU + 4GB 内存
    • 将大部分机械硬盘用设备直通的方式直通给这个虚拟机以避免性能损失(其实不直通损失也不是很大)

    然后在 OpenMediaVault 上装各种工具,比如 Bt 下载、SMB 和 NFS 服务、Syncthing 文件同步等等。由于 OpenMediaVault 是基于 Debian 的,装起来很方便.

    建议

    我的方案要大量用到命令操作,也没专门搭什么 WebUI 之类的,其实不是很适合给长辈使用,更适合 CS 相关专业自己玩。

    如果是给长辈用的话,我建议以下方案二选一:

    • 直接买群晖的机器和系统,几乎什么都有成熟的解决方案,代价是要支付较高的溢价。
    • 配一套和我差不多的硬件(主打低功耗、低噪音,最好体积比较小),然后用 Docker 配合成熟的开源方案,代价是软件方面有点浪费硬件性能,并且可能需要你后期做一点远程维护。
      • OpenMediaVault 做系统并安装 Docker
      • Docker 安装 NextCloud 做云盘
      • Docker 安装 qBittorrent 做下载
      • 安装 Kodi 来展示影片资源
      • 用花生壳或者蒲公英来做内网穿透

    这两个都不是那种完美发挥硬件性能的方案,但都比较适合非技术背景的人使用。区别在于前者需要多付钱,而后者需要你学着搭建并花一点(也不太多)时间去维护。

    为什么我不推荐以下这些东西:

    • 黑群晖(自己买硬件但装群晖的系统):群晖的系统是专有的,黑群晖要自己解决一些问题,这对长辈来说很麻烦。
    • 更高效实惠的内网穿透方案:像 Zerotier 或者 WireGuard 之类的工具虽然可以提供更高的内网穿透带宽,但需要一个会配置网络的人频繁配合,也不适合给长辈用。
  • ❤️ Liked post in 🐀人疑问
    i13l
    AdvisorUploadBot1 AdvisorUploadBot1 Post #2

    【转】你开始以为自己是 xx,后来觉得自己是 xx,再后来又觉得自己是 xx,其实你只是单纯好色罢了

  • uika_winwing uika_winwing Post #13

    不想以后只能摄入批量生产的统计学艺术品。

  • ❤️ Liked post in 怎样增加本站用户数
    网站
    anonymous_coward_old Anonymous Coward Old Post #3

    做 SEO,现在直接搜「交大門」查不到本站。估计不少人是网盲,不知道怎么打开本站。乍看 xjtu.app 不像是个域名。其实.men 是个 gTLD。

  • anonymous_coward_old Anonymous Coward Old Post #1

    tl;dr

    点击:/c/course/64


    【以下信息已过时】

    请使用导航栏 链接 -> 评课社区 打开独立站点。

    基于 USTC 评课社区 源码,汇集不同课程以及不同老师的教学班的信息。


    交大門评课社区 上线,和主站的用户系统打通。

    欢迎提出建议,进行评价,以及改进/审计 代码

    网址:任意域名后加 /course(单复数都行)

    基本信息

    1. 课程名录齐全,包含全校 所有 课程
    2. ~200 选修课有成绩分布、最高、最低、平均分信息
    3. 250+ 选修课有评价信息
    4. 300+ 选修课有考核方式、授课模式、课程内容简介、使用教材及参考书信息

    特色功能:

    在 USTC 评课社区源码的基础上做了些许修改:

    Outdated info hided

    -> 为什么多此一举非要点一下登录按键呢?
    -> 因为我本来是想开发 Discourse 插件,将本站的一个类别打造成评课社区。无奈 Ruby+Ember.js 的技术栈没有基于 USTC 评课社区代码 Python+Flask+Plotly 开发效率高。至于后面是否要切换成 Discourse 插件的方式还需要斟酌。

    • 区间分数可视化,以及显示均分、最高分、最低分。
      -> 当然,现在这个图表做得还是很粗糙的,后续需要改进配色、文字位置等等细节。欢迎 PR
      Screenshot_20230818_160701

    • (Idea) 使用 NLP 对现有评论数据进行情感分析和理解,以对“课程难度、作业多少、给分好坏、收获大小”等 目前空缺的指标进行定性。
      -> 把 USTC 评课社区的数据爬下来,训练一个情感/语义分析模型

    更新:

    • 完善课程的自身属性:课程编号、开课单位、任课教师、学分(学时)、选修课板块类别、课程简介。去除了一些无用评价。(Idea)可以和现有的“导师信息”有机地结合起来,增加任课教师到交大門导师信息的链接。

    • (Ongoing) 调 gpt-3.5-turbo-16k 接口 summarize 某个课程/教学班的评论,类似本站总结话题的功能。

    • 可按选修课板块筛选

    • 完善在线编辑课程信息的功能,类似 https://course.sjtu.plus/ (上交评课网站,基于 Django)。

    (Technical)运行方法

    git clone https://github.com/xjtumen/course-review
    cd course-review
    # 把 USTC 重命名为 USTC
    for suffix in py html js
    do
        list1="USTC 科大 中国科学技术大学"
        list2="XJTU 交大 西安交通大学"
        array1=($list1)
        array2=($list2)
    
        count=${#array1[@]}
        for i in `seq 1 $count`
        do
            echo replace all ${array1[$i-1]} to ${array2[$i-1]} in all suffix files
            find ./ -type f -name "*.$suffix" -exec sed -i "s/${array1[$i-1]}/${array2[$i-1]}/g" {} +
            
        done
    
    done
    
    # 按照 README.md 进行数据库(MariaDB)的初始化作业
    $ mariadb -u root -p 
    MariaDB [(none)]>  CREATE USER 'dbuser'@'localhost' identified by 'MyPassword';
    MariaDB [(none)]>  CREATE DATABASE icourse;
    MariaDB [(none)]>  GRANT ALL ON icourse.* to 'dbuser'@'localhost';
    MariaDB [(none)]> \q
    Bye
    
    # 创建环境
    python -m venv ./venv
    pip install -r requirements.txt
    
    # 按需修改 config/default.py 里面的变量如域名
    
    # 按照数据源修改数据导入脚本:tests/import_courses_jd.py
    python -m tests.import_courses_jd
    
    # 启动服务:
    gunicorn jcourse.wsgi --bind 0.0.0.0:8000 --workers=5   
    
    # 配置反向代理,可参考 `tests/conf/nginx-config`
    

    由于是 β\beta 测试,有可能由于功能更新/bug 修复造成短暂的服务中断,需要多刷新,敬请谅解。评价数据都能得到保留。

    域名暂定为 c.xjtu.app

    已经完成使用子目录反代,形式为 xjtu.app/coursexjtu.app/courses


    前情提要:

  • ❤️ Liked post in 当前网站的技术细节
    网站
    anonymous_coward_old Anonymous Coward Old Post #1

    我相信透明带来的安全,所以在这里把技术架构通通告诉大家,方便新功能的开发、发现现有的问题,如果你也想建一个这样的网站也可以作为参考。

    可以通过 功能更新 CHANGE LOG 页面看到,我们在 Discourse 的基础上添加了许多功能。下面将事无巨细交代

    单一源站:Discourse

    在一台安全稳定的服务器上:

    pacman -S docker git
    systemctl enable --now docker
    cd /var/
    git clone https://github.com/discourse/discourse_docker.git discourse
    cd discourse
    ./launcher rebuild app
    

    多个反向代理服务器

    源站位于高可靠性机器上,但是网络对于中国不是最优的,所以配置反向代理,采用多台优质回国线路、但是配置普通的机器加速:

    /t/topic/4330/6

    配置文件

    /etc/systemd/system/caddy.service

    [Unit]
    Description=Caddy
    Documentation=https://caddyserver.com/docs/
    After=network.target network-online.target
    Requires=network-online.target
    
    [Service]
    User=caddy
    Group=caddy
    Environment="ASSUME_NO_MOVING_GC_UNSAFE_RISK_IT_WITH=go1.20"
    ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
    ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
    TimeoutStopSec=5s
    LimitNOFILE=1048576
    LimitNPROC=512
    PrivateTmp=true
    ProtectSystem=full
    AmbientCapabilities=CAP_NET_BIND_SERVICE
    
    [Install]
    WantedBy=multi-user.target
    

    /etc/caddy/Caddyfile.normal

    {
               #auto_https off
    }
    xjtu.app:443, xjtu.app:443, xjtu.love:443 {
            import /etc/caddy/hsts-xjtu
    
            @default {
                  not path /xjtumen-custom-api/* /xjtumen-g/* /xjtumen-res/* /ip
            }
            reverse_proxy @default unix//var/discourse/shared/standalone/nginx.http.sock
    
            reverse_proxy /xjtumen-custom-api/* 127.0.0.1:7010
           #        reverse_proxy /xjtumen-res/* https://res.xjtu.app
           #        handle /xjtumen-res/* {
           #           uri strip_prefix /xjtumen-res
           #          reverse_proxy /* https://res.xjtu.app
           # } 
    
            import pass-ip-to-backend
            route /ip {
                    rate_limit {remote.ip} 10r/m
            }
            
            redir /xjtumen-g /xjtumen-g/ 308
            route /xjtumen-g/ {
                    rate_limit {remote.ip} 60r/m
            }
            handle /xjtumen-g/* {
                    uri strip_prefix /xjtumen-g
                    root /xjtumen-g/* /var/g/
                    file_server {
                         browse 
                         hide .git
                    }
            }
    
            log {
                    output file /var/log/caddy/xjtu
            }
    }
    
    import /etc/caddy/common
    
    

    /etc/caddy/Caddyfile.rebuild

    xjtu.app:443, xjtu.app:443, xjtu.love:443 {
            import /etc/caddy/hsts-xjtu
            respond "交大門正在更新,预计 10min 内完成。Thanks for your patience!"
            #root * /usr/share/nginx/xjtu-men-maintainence/
            #root * /var/www/xjtu.app
            #file_server
            #rewrite / index.html
            log {
                    output file /var/log/caddy/xjtu-rebuild
            }
    }
    import /etc/caddy/common
    

    /etc/caddy/common

    www.xjtu.app:443, www.xjtu.app:443, www.xjtu.love:443 {
            import /etc/caddy/hsts-xjtu
            redir https://xjtu.app{uri} 301
    }
    

    /etc/caddy/hsts-xjtu

    tls /etc/caddy/ssl/xjtu.app.cer /etc/caddy/ssl/xjtu.app.key
    
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
            X-Xss-Protection "1; mode=block"
            X-Content-Type-Options "nosniff"
            Content-Security-Policy "upgrade-insecure-requests"
            Referrer-Policy "strict-origin-when-cross-origin"
            Cache-Control "public, max-age=15, must-revalidate"
            Permissions-Policy interest-cohort=()
            Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'self'; camera 'none'; encrypted-media 'none'; fullscreen 'self'; geolocation 'none'; gyroscope 'none';       magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture *; speaker 'none'; sync-xhr 'none'; usb 'none'; vr 'none'"
    }
    

    /etc/caddy/pass-ip-to-backend

    # https://caddyserver.com/docs/modules/http
    reverse_proxy /ip 127.0.0.1:7001 {
    header_up X-Real-IP {http.request.header.CF-Connecting-IP}
    header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
    header_up REMOTE_HOST {http.request.remote.host}
    header_up REQ_HOST {http.request.host}
    header_up REQ_HOSTPORT {http.request.hostport}
    header_up REMOTE_PORT {http.request.remote.port}
    header_up DURATION_MS {http.request.duration_ms}
    header_up UUID {http.request.uuid}
    header_up SCEME {http.request.scheme}
    header_up TLS_VER {http.request.tls.version}
    header_up TLS_CIPHER {http.request.tls.cipher_suite}
    header_up TLS_PROTO {http.request.tls.proto}
    header_up PROTO {http.request.proto}
    header_up TLS_RESUMED {http.request.tls.resumed}
    header_up TLS_SERVER_NAME {http.request.tls.server_name}
    header_up REQ_URI {http.request.uri}
    header_up REQ_METHOD {http.request.method}
    header_up REQ_ORIG_METHOD {http.request.orig_method}
    header_up RES_CACHE_CONTROL {http.response.header.cache-control}
    header_up RES_CONTENT_LEN {http.response.header.content-length}
    header_up RES_CONTENT_TYPE {http.response.header.content-type}
    header_up RES_DATE http.response.header.date}
    header_up RES_CSP {http.response.header.content-security-policy}
    }
    
    go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
    ~/go/bin/xcaddy build  --with github.com/xjtu-men/caddy-ratelimit@latest --with github.com/mholt/caddy-l4  --with github.com/quic-go/quic-go@v0.37.4
    systemctl enable --now caddy
    

    插件

    一些插件在私有 GitHub 仓库里,例如 discourse-multiple-hostnames 插件:

    git clone https://github_pat_<redacted>@github.com/xjtu-men/discourse-multiple-hostnames.git
    


    yaml 中插件部分

    hooks:
      after_code:
        - exec:
            cd: $home/plugins
            cmd:
              - git clone https://github.com/discourse/docker_manager
              - git clone https://github.com/discourse/discourse-follow
              - git clone https://github.com/discourse/discourse-apple-add-to-homescreen
              - git clone https://github.com/discourse/header-category-dropdown
              - git clone https://github.com/discourse/discourse-post-voting
              - git clone https://github.com/discourse/discourse-solved
              - git clone https://github.com/discourse/discourse-data-explorer
              - git clone https://github.com/discourse/discourse-whos-online
              - git clone https://github.com/discourse/discourse-calendar
              - git clone https://github.com/discourse/discourse-math
              - git clone https://github.com/discourse/discourse-reactions
              - git clone https://github.com/ShuiyuanSJTU/retort
              - git clone https://github.com/discourse/discourse-ai
              - git clone https://github.com/discourse/discourse-perspective-api
              - git clone https://github.com/discourse/discourse-github
              - git clone https://github.com/discourse/discourse-user-notes
              - git clone https://github.com/discourse/discourse-templates
              - git clone https://github.com/discourse/discourse-assign
              - git clone https://github.com/discourse/discourse-cakeday
              - git clone https://github.com/discourse/discourse-yearly-review
              - git clone https://github.com/discourse/discourse-graphviz
              - git clone https://github.com/discourse/discourse-bbcode
              - git clone https://github.com/discourse/discourse-saved-searches
              - git clone https://github.com/discourse/discourse-chart
              - git clone https://github.com/communiteq/discourse-multiple-hostnames
              - git clone https://github.com/mondiscourse/discourse-formatting-toolbar
              - git clone https://github.com/paviliondev/discourse-topic-previews-sidecar
              - git clone https://github.com/merefield/discourse-chatbot
              - git clone https://github.com/discourse/discourse-gamification
              - git clone https://github.com/discourse/discourse-policy
              - git clone https://github.com/discourse/discourse-animated-avatars
              - git clone https://github.com/discourse/discourse-signatures
              - git clone https://github.com/paviliondev/discourse-locations
              - git clone https://github.com/xjtumen/discourse-shadowban
              - git clone https://github.com/xjtumen/discourse-ip-location
              - git clone https://github.com/discourse/discourse-steam-login
              - git clone https://github.com/discourse/discourse-geoblocking
              - git clone https://github.com/communiteq/discourse-geo-blocking
              - git clone https://github.com/discourse/discourse-bcc
              - git clone https://github.com/discourse/discourse-shared-edits
              - git clone https://github.com/paviliondev/discourse-custom-wizard
              - git clone https://github.com/paviliondev/discourse-journal
              - git clone https://github.com/discourse/discourse-oauth2-basic
              - git clone https://github.com/discourse/discourse-openid-connect
              - git clone https://github.com/discourse/discourse-microsoft-auth
              - git clone https://github.com/discourse/discourse-hCaptcha
              - git clone https://github.com/discourse/discourse-user-card-badges
              - git clone https://github.com/communiteq/discourse-private-topics
              - git clone https://github.com/paviliondev/discourse-ratings
              - git clone https://github.com/discourse/discourse-surveys
              - git clone https://github.com/discourse/discourse-adplugin
              - git clone https://github.com/discourse/discourse-subscriptions
              - git clone https://github.com/discourse/discourse-akismet
              - git clone https://github.com/discourse/discourse-custom-topic-lists
              - git clone https://github.com/xjtumen/discourse-group-membership-ip-block
              - git clone https://github.com/discourse/discourse-chat-integration
              - git clone https://github.com/davidtaylorhq/discourse-telegram-notifications
              - git clone https://github.com/fokx/discourse-cjk-formatter
              - git clone https://github.com/Lemon-planting-light/user-autonomy-plugin
              - git clone https://github.com/Lhcfl/discourse-post-folding
              - git clone https://github.com/discourse/discourse-preset-topic-composer
              - git clone https://github.com/xjtumen/discourse-staff-alias
        - exec:
            cd: $home/plugins/discourse-animated-avatars
            raise_on_fail: false
            cmd:
              - $home/plugins/discourse-animated-avatars/scripts/install.sh
    
    

    以下是插件列表:

    • docker_manager
      允许在网页端进行管理,包括调用 docker 更新命令,注意:可能会失败,而且失败后有一定概率损坏浏览器缓存,并需要命令行 rebuild app。建议不使用热更新。

    • discourse-follow
      Follow 其他用户

    • discourse-apple-add-to-homescreen
      针对苹果用户的浏览器显示“添加到主屏幕”提示。Android 的提示(PWA)集成在 Core 里。

    • discourse-activity-pub
      理论上允许和 Mastodon 互联,但没有成功过。

    • header-category-dropdown
      允许在最上栏显示下拉菜单,暂时没用到。

    • discourse-post-voting
      在话题内,对后续的回复进行 Up/Down Voting

    • discourse-topic-voting
      发表投票/调查话题,允许多选/单选。

    • discourse-teambuild
      类似于让門友做任务,暂时没用到

    • discourse-solved
      将回答中的某个回答设为“已解决”,适合于提问帖

    • discourse-data-explorer
      在网页端调用数据库查询,仅限管理员使用

    • discourse-whos-online
      查看当前在线情况,仅限管理员使用

    • discourse-calendar
      日历支持

    • discourse-math
      支持 Latex 数学公式,单行/多行。可选后端:MathJAX / KaTex

    • discourse-reactions
      用更多 emoji 对话题作出回应,默认只有 ❤️

    • discourse-ai
      众多 AI 功能

    • discourse-perspective-api
      调用 Google Perspective API 分析帖文是否违反社区规范

    • discourse-github
      和 GitHub 联动,例如 issues 和 pull request

    • discourse-user-notes
      用于 mod 对用户进行备注

    • discourse-encrypt
      端到端聊天加密

    • discourse-automation
      执行自动化任务,当前尚未使用,后续准备用来更新 关于 西安交大导师信息 类/tag/empty 标签

    • discourse-templates
      允许设置话题的模板

    • discourse-assign
      允许将话题分配给某些人,适合于问答场景。

    • discourse-ai-topic-summary
      使用 AI 对长话题进行总结

    • discourse-user-network-vis
      可视化社交关系

    • discourse-nationalflags
      国旗扩展

    • discourse-telegram-notifications
      同步到 Telegram 消息

    • discourse-word-cloud
      字数统计

    • discourse-chatbot
      主页上悬浮的 AIBot 和可以私聊/私信的 AIBot

    • discourse-layouts
      自定义页面布局

    • discourse-locations
      支持定位功能,目前想不到应用场景,暂未启用

    • discourse-topic-list-previews
      启用 Discourse 默认的一行行帖子的用户界面,实现类似于小红书之类软件的瀑布流效果(列数随浏览器宽度自动调整,移动端只有一列)。但由于全屏幕帖子数量少,以及未知原因造成的偶尔出现从主题返回主页的问题,因而只在 redditish 和 Material Design 这两个主题启用(FKBPro 自带主题内容预览功能,也可一试),可以在用户偏好里设置。
      Screenshot_20230813_214532

    • discourse-multiple-hostnames
      允许 Discourse 用多域名访问(注意 app.yml 里只能配置一个域名,它将作为 canonical name 用户)搜索引擎检索,因而可以看成是反向代理域名白名单列表

    えしりなか,post:6, topic:4330:
    • xjtu.app
      San Jose, CA
      优质中国电信 CN2 GIA,电信、联通、移动、教育网都是当前国际联网最优的线路。仅 IPv4。

    • xjtu.love 域名:
      San Francisco, CA
      普通线路 AS4134 China Telecom Backbone
      Arelion / Telia / twelve99 动态 BGP 路由
      平常也可使用,或者当.men, .live 全都挂掉的时候备用。IPv4/IPv6 双线。

    可参考下图:

    • discourse-anonymous-post
      允许匿名回复/发贴,无需登录即可使用,只需点击右上的回复按钮。

    • discourse-autobot
      从其他消息源自动拉取更新并发帖。

    • discourse-shadowban
      残忍的 Shadowban,仅发帖人可见自己的帖子,其他人/未登录者看不到,仅用于短时间应对极端刷屏用户。

    • retort
      自选 eomji 回应回复,来自上交维护的 ShuiyuanSJTU/retort,fork 自早已 EOF 的 gdpelican/retort

    服务器状态

    root@archlinuxDO ~ # df -h
    Filesystem      Size  Used Avail Use% Mounted on
    dev             978M     0  978M   0% /dev
    run             987M  676K  986M   1% /run
    /dev/vda1        59G   44G   13G  78% /
    tmpfs           987M  1.1M  985M   1% /dev/shm
    tmpfs           987M  4.8M  982M   1% /tmp
    overlay          59G   44G   13G  78% /var/lib/docker/overlay2/cfceca63649b674ce9a0706ebb64ecbd6b58389a73f3981226ff9387c04be342/merged
    
    root@archlinuxDO ~ # free -h
                   total        used        free      shared  buff/cache   available
    Mem:           1.9Gi       1.7Gi       127Mi        35Mi       303Mi       220Mi
    Swap:          4.0Gi       2.4Gi       1.6Gi
    
    
    root@archlinuxDO ~ # uptime
     21:57:44 up 3 days,  7:32,  2 users,  load average: 0.34, 0.45, 0.39
    
    

    Theme (Component)

    Theme

    不同的主题不仅颜色、界面不同,而且启用的 Theme Component 不同,如果你不喜欢某种功能,可以尝试不同的主题。在不同的设备上可以选择不同的主题。

    • DiscourseDefault
      默认和推荐主题,主题的话题列表是单列。

    话题内容预览。

    显示额外信息的侧边栏,如话题类别,热门 tag,常用链接等。另外 Material Design 也有该侧边栏。如果不喜欢可以换用其他主题。移动设备上没有侧边栏。

    • FKB Pro Theme
      采用类似 Win11 的圆角设计,话题图文预览。侧边栏。

    • graceful
      也有柔和的边角设计,但不建议移动端使用,因为边缘间隙比较大。侧边栏。

    • Material Design Theme
      Material Design 风格,移动端倒是感觉不到,话题图文预览,采用砖块/窗口式帖子列表,可自动根据页面缩放自动调节列数,侧边栏。

    • redditish
      Reddit 风格,话题图文预览。侧边栏显示最近的话题。

    Theme Component

    被移除的 TC

    https://github.com/discourse/discourse-category-badge-styles.git
    https://github.com/VaperinaDEV/custom-embedded-replies.git
    https://github.com/discourse/discourse-colorful-categories.git
    https://github.com/xjtu-men/discourse-gray-filter
    https://github.com/xjtu-men/discourse-hide-ip-info.git
    https://github.com/Lhcfl/discourse-larger-long-image.git
    https://github.com/fokx/discourse-marquee.git
    https://github.com/xjtumen/discourse-matomo-analytics
    https://github.com/literatecomputing/discourse-qrcode-wrap-theme-component.git
    https://github.com/discourse/discourse-thin-header-theme-component.git
    https://github.com/discourse/Discourse-Tiles-image-gallery.git
    https://github.com/Arkshine/discourse-chat-sidebar.git
    https://github.com/VaperinaDEV/discourse-stickers.git
    

    被禁用的 TC

    https://github.com/discourse/discourse-category-icons.git
    https://github.com/xjtumen/discourse-custom-header-links.git
    https://github.com/awesomerobot/discourse-button-styles.git
    https://github.com/Arkshine/discourse-fireworks/tree/mobile-support-and-settings
    https://github.com/discourse/discourse-gated-topics-in-category.git
    https://github.com/discourse/discourse-icon-header-links.git
    
    

    所有 TC

    • Anonymous Post
      和插件配合实现不登录发帖/回复。

    • Colorful categories
      根据不同的类别改变界面的颜色,不改变顶栏颜色,因为屏幕对比度太高、有长条色块容易晃眼睛。

    • Custom Header Links
      在顶栏插入链接,如 评课社区 学习资料

    • Icon Header Links
      顶栏添加图标超链接

    • Dark-Light Toggle
      允许手动切换亮暗色主题,一般是不需要的,可以自动识别浏览器的亮暗状态。

    • DiscoTOC
      自动添加目录,无需任何人工操作

    • discourse-buttons
      定制按钮颜色和形状如圆角

    • Discourse Clickable Topic
      话题的整个区域都可点击,不仅仅是标题文字

    • discourse-gifs
      编辑器 GIPHY / Tenor 表情包 GIF

    • discourse-right-sidebar-blocks
      侧边栏

    • PDF previews
      页面内嵌入 pdf,无需下载,无需新标签页打开

    • Play G Widget
      game widget

    • QR Code Inserter
      编辑器插入 QR Code(quick-response code,二维码),可以是到任意 URL,或者是本当前页面(url 参数为空时)

    • Showcased Categories
      侧边栏展示两个类别

    • Table Builder
      编辑器插入表格

    • Tag Cloud
      可视化所有的 tag

    • Text Highlighter and Coloring Composer Button (BBCODE)
      编辑器支持 BBCode,以及快速高亮文本

    • Tiles - Gallery Component
      最优地放置多图片

    • Topic Excerpts
      显示文本预览

    • Topic Thumbnails
      显示图片预览

    • Topic List Previews
      图文预览

    • Topic List Item Click Animation
      话题点击动画

    • xjtu.app custom theme-component
      用于自定义一些 css 和 js,例如允许复制代码块内容,代码块支持 Intel One Mono 字体,调整顶栏项目的顺序

    • Brand Header Theme Component
      在当前的顶栏上面在加一行,类似菜单

    • Category Headers theme component
      在每个类别的主页添加自定义内容

    • Discourse Docs Card Filter
      允许将某些类别设置成文档的效果

    • discourse-homepage-feature-component
      主页显示 featured topic

    • discourse-category-icons
      category icon

    • discourse-tc-character-count
      character count in editor

    • Category Badge Styles
      category badge set to none to show icon only

    • discourse-header-submenus
      show submenu above normal header

    • discourse-gated-topics-in-category
      提示未登录用户只有登录才能查看内容

    • discourse-reply-template-component
      使用模板新建话题/回复/私信
      https://meta.discourse.org/t/reply-template/162373

    默认主题:
    https://github.com/OsamaSayegh/discourse-tab-bar-theme
    加载了的组件:
    Screenshot_20240108_173957

    配色

    用户有很多配色方案可以选择,默认是 OpenAI-Partial。参考了 OpenAI Developer Forum。OpenAI 的配色十分好看,我们想要模仿,即是可以用 console 调出 :rootcolor_definitions.css,可惜没法完全一样。

    OpenAI-Partial-Dark Palette
    "OpenAI-Partial-Dark": {
      "primary": "ffffff",
      "secondary": "262727",
      "tertiary": "2ec27e",
      "quaternary": "b9b4ec",
      "header_background": "111111",
      "header_primary": "dddddd",
      "highlight": "b496ff",
      "danger": "f17173",
      "success": "09cf09",
      "love": "fa6c8d",
      "selected": "183d31",
      "hover": "2d2e31"
    }
    
    OpenAI-Partial Palette
    "OpenAI-Partial": {
      "primary": "202123",
      "secondary": "ffffff",
      "tertiary": "10a37f",
      "quaternary": "715fde",
      "header_background": "ffffff",
      "header_primary": "333333",
      "highlight": "482da8",
      "danger": "ef4146",
      "success": "009900",
      "love": "fa6c8d",
      "selected": "e6f3f3",
      "hover": "f7f7f8"
    }
    

    在线配置

    网页端可以改不少配置选项,比较重要的有:

    • base font 以及针对 code blocks 使用 Intel One Mono
    • 固定左边栏类别的顺序,调整移动设备上顶栏按钮的顺序和桌面/移动端可见性
    • 调整“提醒注册”的 banner 对已登录用户不可见
    • 中文帖名和内容的长度,用户名长度限制,保留的用户名及 regex
    • 不同 Trust Level 实现的条件、允许的功能和 rate limit (incl. API key)
    • max image size kb, max attachment size kb, 需要./launcher enter app 改 nginx 的配置
    • AI 模型选择和服务网址

    存在的问题

    • Discourse docker 容器里面使用 nginx 做服务器,监听到 unix socket,再用宿主机 caddy 反代,存在性能损失(unix socket 很高效,可以忽略)和不必要的内存占用
    • nftables 和 docker 冲突,没有配置防火墙 已采用云服务商防火墙
  • ❤️ Liked post in 乐趣和成就感的不同步
    谈笑风生
    3ee28fe1a60c95b89d29317f122c70 3ee28fe1a60c95b89d29317f122c70 Post #2

    你发帖子,俩小时没人理你,就是乐趣和成就感的不同步

  • ❤️ Liked post in Discourse Shortcuts
    网站
    anonymous_coward_old Anonymous Coward Old Post #1

    快捷键用起来确实很爽
    Screenshot