六十而耳顺 —— 60级小结

六十而耳顺 —— 60级小结

在Steem悄悄地升到了60级,本文简单梳理一下过去的文章和思考,以及接下来的一些想法。

耳顺

“六十而耳顺”,先来解读它的意思。

孔子云:“吾十有五而志于学,三十而立,四十而不惑,五十而知天命,六十而耳顺,七十而从心所欲不踰矩。” ——《论语·为政》

无论后世对孔子的褒贬如何,孔子都无愧于是当时的智仁勇兼具之人杰,缔造文明的核心人物,轴心时代的开创者。上文中,“立”、“不惑”、“耳顺”等当下常被人用于年龄的变化,但恐怕很多人没有真正理解孔子的本意,常常是误用。

一方面,这是孔子对自己一生的总结,未必适用于他人。孔子一生所历73年,这段话在约72岁时所作。另一方面,理解孔子,无须跪着解读,用常人的视角去观察更有意义。

孔子少年老成,十五岁便志于“学”(学问)。当下,无须说十五岁的青少年,便是终其一生也未必有志者,也不在寡。而十五六岁正是躁动的年纪,惹是生非者不少,这在西方和东方却也差不多。

孔子跳过二十多岁的成人之礼不说(孔子20岁成家生子),可见在他看来这并不重要。“三十而立”,用孔子自己的话说:“不知礼,无以立也”。孔子30岁时以“知礼”闻名,齐景公和晏婴向他问礼,所以“而立”说的是孔子知书达理、学而有成,并非很多人认为的“成家立业”或“物质独立”。

孔子成名之后,求仕于齐、鲁,但并不顺利,四十岁左右专心治学,于是能够“不惑”。

“五十而知天命”,便是知道自己命中注定该做什么。据说孔子50岁前因为学《易》知道自己应该做官,所以便出来求仕。

“六十而耳顺”,对古之贤达而言,有“善于倾听民间疾苦,善于接受贤达劝谏”之意[1]。60岁前后,孔子周游列国、颠沛流离,很不顺心,但孔子却很虚心。郑人说他“累累若丧家之狗”,孔子点头称是。毁誉置之度外、又能洞察世事,可以谓之“耳顺”。

七十在孔子的年代毫无疑问是高寿。70岁左右,孔子丧子、丧徒(颜回、仲由),反而“从心所欲、不逾矩”,大抵物我两忘,一切皆可放下,人之将死,也彻底自由。

那么,在Steem上的朋友,60级之后,对这一空间内的世事,可以不计毁誉、洞若观火,也可称得上耳顺了吧 :)

思考

在 Steem 上的旅程,与我最初的计划,似乎还是颇为匹配的。

先说说写作和思考相关的部分。

1. 开端与计划

第一篇《The Road Not Taken》 虽然是转载了Robert Frost的诗,并无原创,但也立了基调,即“took the one less traveled by”。

此后的两篇《在Steemit的写作计划 | My Writing Plan on Steemit》 以及 《【Steem之旅】2019年Steem世界的探索 | Exploring the Steem World in 2019》 大概确立了写作的路线,以及希望更深入地了解Steem、为社区做一些工作、认识更多朋友的想法。

随后的写作大概是沿着这个思路前进,但完成度目前还比较低,希望可以继续改进。

2. 《黑客之道》系列

谈技术哲学和技术之道,但目前还是只开了个头,还没有深入写。

  1. 序 - #1:如何培养真正的黑客?
  2. 序 - #2 真正的问题解决者
  3. 番外 | 墨子(一):奇人

3. 《科学与教育》系列

科学哲学与技术哲学是相伴相生的,为了谈好技术问题,先谈谈科学和教育问题,也会略有帮助。

  1. 【未来教育学】成年人需要什么样的STEM教育?(一)(二)(三)(四)(五)(六)(七):以STEM切入点,谈了一些科学教育方面的Why, What和How等问题。
  2. 【未来教育学】知 与 智:一篇杂文,抨击了网络和商业上流行的知识平台

4. 《观非常人,行非常事》系列

这个系列原以为已经写了好多篇了,原来还挺少的,可能是默默写了,没发到Steem吧。可以把上文的一篇《墨子》和对联活动的《梁羽生》也加到这个系列。

  1. 作为科普作家的艾萨克·阿西莫夫 | Isaac Asimov and Popular Science
  2. 程灵素:海棠无香
  3. 番外 | 墨子(一):奇人
  4. 下邳圯桥,张良进履
  5. 梁羽生与《名联观止》

5. 《标签的本质》系列

这个系列是把 “标签” 作为观察 Steem 和世界的一个视角来写的,是不错的话题,但只开了头,希望接下来可以继续写好。

  1. 标签的本质 | The Nature of Tags(一)

6. 《区块链与公共利益》系列

这个系列希望关注的是区块链与公共利益间的关联,也是我觉得区块链项目最有意义的方向。

  1. 区块链、Steem与公共利益 | Blockchain, Steem and Public Benefit
  2. 区块链、Steem与公共利益(二)– 开源与区块链 | Blockchain, Steem and Public Benefit (2) – Open Source and Blockchain

7. 其他杂文

  1. 【跨文化活动】地球文明的星际对话 | 宇宙政治与宇宙语言:参加阿朵 @itchyfeetdonica 的跨文化交流的活动

以上总计21篇。作为写作的部分,进度并不快,希望接下来能有更多进展。

实践

除了写作之外,有相当一部分文章是关于实践的,即如何参与 Steem社区的各种活动和建设,下面也做一些总结。

1. 新手村 @team-cn

给村里做的贡献不多,下面可能是有些帮助的:

  1. 和大家一起参与SP代理竞赛:《数英雄,论成败:评SP代理竞赛》
  2. @cn-hello 小门童 帮助邀请新人加入新手村:借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历
  3. @cn-curation 编辑
  4. @cn-activity 编辑(已经暂停)

2. Steem指南 @steem-guides

目前《Steem指南》的修订有了一些进展,但整体进展比较缓慢,需要改进执行力。

《Steem指南》修订计划:

  1. 《Steem指南》重新起航: https://steem-guides.github.io/steemh/
  2. 《Steem指南》 – 编辑的工作流 | Editors’ Workflow
  3. 《Steem指南》 – 编辑的工作流 | Editors’ Workflow | 第2版 | 2019/04/19更新
  4. Steem Guides + SCT = Wisdom about Steem | 《Steem指南》+ SCT = Steem之智慧

《Steem指南》新的子版块:建议收藏这两个链接

  1. Steem常用链接: https://steem-guides.github.io/links/zh | Steem Links:《Steem指南》子项目 | Subproject of Steem Guides
  2. 中文区花名册:https://steem-guides.github.io/roster/ | Steem 花名册:《Steem指北》子项目 | Steem Roster: A Sub-Project of Steem-People / 真·花名册 | Update of Steem Roster

《Steem指南》小助手

  1. @cn-hello 不仅帮助新人认识新手村,也介绍《Steem指南》等教程,也希望可以通过改进让《指南》越来越容易阅读和使用。

3. Steem工具和服务

steemblog 博客镜像服务:目前已经服务了近20位用户,有需要的可以留言

  1. steemblog: Steem时光机 | Steem Time Machine
  2. 用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

关于国内访问 steemit 的几种方式的文档:

  1. 【Steem指南】用eSteem Surfer发帖
  2. 【Steem指南】用requestly绕过 steemit 被禁问题
  3. 【Steem指南】浏览器插件:Steem Server选择工具;解决steemit被禁的问题

4. 其他社区参与

steemstem

  1. #cn-stem curator:最近收到的投稿较少,欢迎新人关注STEM

steemcleaners

  1. 翻译和介绍了账户安全问题,此问题值得持续关注:网络钓鱼的安全威胁,请中文区用户警惕 | Phishing Warning

5. 对联活动

起初是为了写梁羽生的生平,但觉得对联活动也不错,所以顺便组织活动、普及对联知识。本周我们会继续。

活动列表:https://steemblog.github.io/@robertyan/tags/cn-couplet/

  1. #1 梁羽生与《名联观止》
  2. #2 内外与五四
  3. #3 对偶与春秋
  4. #4 贺寿与建祠

前行

Steem 的内容丰富多彩,在这里认识了很多有趣的朋友,玩得很开心。

接下来的行进路线,与最开始的计划并无大的差异,但可能需要有更高的执行力、以及和社区里伙伴更好的合作。

思考与写作

其实写作计划一直是比较清晰的,但 Steem 能玩的太多了,有时候写作的进度就无法跟上了。希望可以提高执行力。

  1. 《黑客之道》系列:顺着大纲继续写
  2. 《语言与世界》系列:语言学和认知科学相关,用小号单独写
  3. 《标签的本质》系列:顺着大纲继续写
  4. 《区块链与公共利益》系列:需要整理下思路,可能会开一个番外《开源回忆录》

区块链与公共利益

在《区块链与公共利益》系列中我曾提到,我觉得公共利益是区块链在技术、经济和社交层面最有意义的价值体现。本质上,我认为这是对Web精神的继承与发扬(这是基于将区块链看成下一代Web的重要组成部分的这一观点得出的)。

对Steem世界的初步探索,也将逐步走向更有针对性的推动区块链实现更多公共利益。

我并不怀疑区块链技术会逐步纵向大众,但其带来的结果并不总是正面的,如何用其利而避其害,是我们需要思考的问题。区块链根植于“自由主义”的基因,驱使它可能向着“人之道,损不足以奉有余”的方向前进,使得财富聚拢而损害大多数人的利益。“自由”与“平等”的矛盾始终萦绕着商业世界。

区块链与公共利益的结合,是我认为可以寻找的出路的一个方面。

主要的工作会在以下几点:

  1. 《Steem指南》:Steem指南解决的是社区知识共享和沉淀的问题;但需要做一些反思和整理,解决目前的执行力的问题。
  2. 协助公共利益组织:如 @team-cn、@steemstem 等,具体来说包括:
    1. 改进 CN区 使用 steem 的各类服务的体验,如 steem-engine 等;
    2. 推动 CN区 的项目更好的发展,例如 @wherein,和 @iguazi 也有一些讨论;
    3. 帮助 @steemstem 改进 https://www.steemstem.io 的访问体验(刚开始);
    4. 了解和参与 utopian 社区;
  3. 更加系统地思考和研究如何帮助更多以公共利益为目的的组织发展和成长;
  4. 其他有趣、好玩、又有助于社区成长的事情(欢迎大家参加对联活动)。

最后

其实本文是对 @yellowbird 黄鸟大哥 提到的在 steemblog 中增加【置顶文章】板块的实验,否则可能不会写这篇总结的文章。

对于 steemblog 的用户,如果想要置顶文章或者调整首页的文章顺序,可以在文章的文本中加入如下的隐藏标签(可以加在末尾,像本文做的那样;别的地方也可以),你的文章会按照 position 的数值从小到大排列。如不设置,默认的position 是 9999,会按照时间排序;所以,一般需要置顶的文章才需要设置。

<div position=”1” />

参考文献

  1. 李零,《丧家狗 —— 我读论语》,山西人民出版社,2007年


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/06/%e5%85%ad%e5%8d%81%e8%80%8c%e8%80%b3%e9%a1%ba-60%e7%ba%a7%e5%b0%8f%e7%bb%93


This page is synchronized from the post: 六十而耳顺 —— 60级小结

真·花名册 | Update of Steem Roster

真·花名册 | Update of Steem Roster

本文是【花名册】项目的简要更新:‌

‌screenshot from: https://steem-guides.github.io/roster/

回顾

昨天我们分享了【花名册】(Steem Roster),用于帮助大家认识和分享CN区的朋友的诨名/花名/村民/绰号。‌

昨天分享的花名册中,总共包含了63位朋友的花名,但我审阅了一会发现了两个问题:‌

  1. 有很多重要的社区名人们都不在花名中,这显然不是一个有权威性的名册,恐贻笑大方。比如 阿廖 @htliao,O神 @oflyhigh,大伟哥 @rivalhw,坛子 @tumutanzi
  2. 有的花名则不够全面:比如 @julian2013 居然只叫小机机,而没有 机大爷的尊号;@shenchensucc 居然只有铁柱的村名,连Buddy爸爸都不在列表中。

‌为了修复这些问题,我们增加了【花名册】找花名的数据源,此修改将在下一节介绍。‌

改进

‌前文中,我们提到使用的数据源主要是:@teamcn-shop 新手村小卖部日报 的报告,但只有这个显然还是不够的。为了扩充数据源,我们想起小卖部送外卖时也会使用很多“村名”,例如

‌screenshots from busy.org: 来自这条留言

刚才,村长在本文的留言中,又提供了新手村毕业典礼的数据源(https://steemblog.github.io/@team-cn/egxwc0ewsi/),我们把这个名单也加到了要检索的数据中。

所以我们将现在的数据源扩展到了下面三类:‌

  1. @teamcn-shop 新手村小卖部日报: https://steemit.com/@teamcn-shop
  2. @teamcn-shop 新手村小卖部 送外卖给客户时的留言;
  3. @teamcn 新手村毕业典礼的名单;

经过修改后,我们现在总共包含了118位朋友的花名。下面是他们的花名,也可以在 https://steem-guides.github.io/roster/ 查看。

用户别名
@aaronli阿柔 ~~我叫伦舞~~ / 阿柔
@abcallen阿兰 / Allen / 鸭伦
@aellly瓜叔笑容满面,还自备西瓜汁 / 瓜叔 / 西瓜 / 瓜子
@also.einstein亦亦
@alvin0617Alvin / 小红
@amanda8250阿曼
@angelina6688朱师傅 / 朱莉
@annepink萍萍
@artsymelanie美丽姐 / 美丽 / 王美丽 / MW / 分子量
@auleo榴莲王子 阿奥 / 阿奥
@bichen芒果
@biorabbit思想家
@cairou包子
@ceci99斤斤
@cecilian粥粥
@changxiu北北
@cherryzz阿紫 / Cherry
@chineseman大饼
@circlepoint圈点
@coder-btsBTS / 码农
@crowflew维参
@crypto.talk大灰灰
@cryptocurrencyhk小编
@dapeng大鹏哥
@darrenych86华仔
@davidchen勇敢
@davidke20拉仔 / 金鱼佬
@deanliu刘美女
@elizachengEliza
@ericet村长 / 村Long / 村龙 / 村村
@fishlucy露西 / 鱼露
@gerer晨歌
@hansheng鸭子
@honeyday罗罗
@honoru米高哥 / 米高 / Michael / 村书记 / 村高
@htliao阿廖 / HT
@huiguannova元元
@iguazi123瓜子
@ishenyaya曲曲
@itchyfeetdonica阿朵
@janicechua佩芯
@jianan嘉南
@jiangchen姜臣 / 姜辰
@joythewandererJoy
@julian2013小机机 / 机大爷
@justyy行长 / 富根
@kadishakho卡姐
@kelvinzhang老K / kelvin
@kidsreturn小兔子一蹦一跳 / 小兔子 / Mandy / 兔兔 / 兔子
@kristylkho卡宝 / 小佩
@laoma老马
@lifelikeline金樽上 / 板凳作家 / Robert
@littlexiannv小仙女
@liubao阿宝
@liumei阿美 / 阿花
@liuzg老刘头 / 刘老头
@loongxiew隆哥
@lucindagoLulu
@lulucy小鹿
@maggieliew1704Maggie / 美琪
@mfxqaq小孟
@mia-cc斤斤
@miniu阿敏
@minloulou迷路
@minminlou小迷路
@morningshine小K
@nostalgic1212小冰
@odillegoghOdille
@oflyhighO哥
@olymim阿胖
@peanut77花生阿姨
@pgr小P / 老艺术家 / 老shi艺术家 / 鸡贼老艺术家 / 小R / 屁股热
@pizzapai批萨姐 / 披萨姐
@raynopssgold小昇
@rivalhw大伟哥
@robertyan阿盐
@robin.hanRobin
@sasaadrian一灯大师
@sharonqian虾仁 / Sharon
@shenchensucc铁柱 / Buddy爸爸 / buddy爸爸 / buddy粑粑
@sherry.gongSherry
@shine.wong金闪闪
@simpleslife阿安
@slientstorm阿杰 / 小杰
@snailsong小松
@softmetal软哥 / 软扣扣 / 软校长 / 铁蛋 / 村宽
@stabilowl笔哥
@starrouge阿星
@stepbie曾老公 / Stephen
@sunai三妞
@tanlikming阿力
@team-cn新手村
@thedreamsun66小刘
@tiffany4everITC9 / 师太
@tumutanzi坛爷
@tvb一姐
@tydebbie小迪 / Debbie / 小娣
@valleybkk腿 / Ham
@wanggang钢哥 / 钢天使
@weisheng167388金老师 / 金兽
@weitz大柱
@wilhb81小智&小白条 / 小智 & 小白条 / 小智
@windowglass糖糖
@winnie1998负婆
@wongshiying老王
@wuer吾儿
@xiaoguai小乖
@xiaoliu六子
@xiaoshancun三哥
@xiaoxiangyun阿云
@xiaoyuanwmm村长夫人 / 村凤
@yanhan小萍萍
@yanyanbebe茵茵
@yellowbird黄鸟
@ygrj阿洁
@zerofive欧爷
@zilin蔚阿姨
@zy-sb二姐

table from: https://steem-guides.github.io/roster/

但需要注意,这个名册依然是不够完整的,一些CN区的热心用户并不在其中,我们在之后也将进一步扩展数据源,完善名册。‌

另外,除了从花名册的网页访问,如果需要原始数据,可以通过下面这个链接下载最新的CSV文件,进行使用或处理。‌

扬名

对于新人而言,有一个靠谱的绰号,还是很有必要的,至少证明你一定程度上融入了社区。当然一方面也是因为我们这个圈子还没有那么大,所以很多人还是能叫得上“村名”的。如果人口达到了几百万,要管理你的社交圈可能就又得采用不同的方式了。‌

那么作为新人应该如何获得一个“别名”呢?当然,你可以在自己的自我介绍(#introduceyourself)文章中直接告知你愿意被如何称呼,但其实未必有效。‌

如果你是新手,目前可行的做法大概如下:‌

  1. 加入 新手村 @team-cn 的微信群,那么几乎你加入新手村的同时,会被赐予一个“村名”(嘿嘿嘿!!!);
  2. 或者至少在 Steem 上有一定的活跃度,发表有意义的内容、积极参与互动,引起他人的关注;
  3. 有可能的话,你可能会收到《新手村访谈》的邀请,对你进行访谈,那么你的村名可能会有更多人知道;
  4. 随着你的“作品”(不光是写作)的增加,可能会有越来越多的人认识你,这时你的花名,可能就已经有一定影响力了。“花名册”也可能会以你为荣。

当然,这只是新人踏足 Steem 世界的第一步。但在武侠世界里,不论什么角色,取个合适的名字还有一定意义的,但也不尽然:‌

  • 取名“郭靖”,一看就是要誓雪“靖康之耻”的“岳武穆”式人物(“靖康耻,犹未雪;臣子恨,何时灭”);
  • 取名“杨过”(字改之),一出生就背负了“原罪”,成长的过程也难免艰辛;
  • 但取名“张无忌”,办事却不一定无忌,反而处处优柔寡断;

最后,祝愿新人们在Steem,不仅有个不错的花名,也度过一段快乐的旅行。‌

参考文献



Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/06/%e7%9c%9f%c2%b7%e8%8a%b1%e5%90%8d%e5%86%8c-update-of-steem-roster


This page is synchronized from the post: 真·花名册 | Update of Steem Roster

steemblog: Steem时光机 | Steem Time Machine

steemblog: Steem时光机 | Steem Time Machine

本文我们将介绍 steemblog 的最新的进展。‌

‌Image Source: Pixabay

#1 回顾

‌steemblog 是一项 Steem 文章镜像服务。‌

如果你还不了解这个服务,或许你可以通过访问:https://steemblog.github.io/@team-cn/ 作为一个案例体验一下。‌

在文章《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中,我们提到过创建steemblog 服务的缘由,主要是为了更好的查看历史文章。‌

现在来看,它主要带来了以下几点助益:‌

  1. 首先,steemblog 作为一份档案和历史记录,将 steem 数据以便于阅读和查询的方式保存;虽然区块链技术被认为具有数据不可毁灭的潜力,但有一份额外的备份也存在价值;
  2. 其次,它提供了更好的用户体验访问速度,对于查询、搜索、整合个人或组织的文章,效率更高、更有愉悦感;
  3. 再次,它目前每日更新,虽然是存档,但基本可以保持是近实时的,多于过去几日的文章,也可以一并处理。

根据上一篇文章和微信群中的留言,我们已经帮以下12个账号部署了每日更新的博客镜像服务:‌

  1. @robertyan
  2. @andrewma
  3. @ericet
  4. @julian2013
  5. @annepink
  6. @bring
  7. @sunai
  8. @nostalgic1212
  9. @m18207319997
  10. @iguazi123
  11. @team-cn
  12. @lemooljiang

‌每日北京时间凌晨0点,steemblog 会自动同步镜像一次。‌

总体而言,对我来说 steemblog 是一个还比较好用的时光机(Time Machine),可以更好地学习和了解 steem 上各种有趣的事情。

下面举几个例子来看看吧:‌

#2 场景

‌以下是steemblog的几个有意思的应用场景。

(1)新手村访谈

初入CN区或者新手村的新人,想要了解一下社区内的朋友,其实没有看上去那么容易。去逐个翻看各个用户的历史文章,效率很低。‌

但新手村访谈部分解决了这个问题,我们只要看 #cn-interview 这个标签下的文章就行,但由于steemit / busy 查看标签历史或多或少都有点问题,所以也很难流畅地阅读。在以前,大概有2种方式:‌

  1. 看新手村的索引贴,例如2018版的:https://busy.org/@team-cn/2018-x61niax2i4/
  2. 阅读《Steem指南》的新手村计划部分:https://steem-guides.github.io/steemh/fl.html#section-17.3

但这两种方法更新可能不太及时,最近的访谈没有录入,而 steemblog 是及时更新的。 steemblog 的搜索功能也更快速和有针对性。‌

通过链接:https://steemblog.github.io/@team-cn/tags/cn-interview/,我们可以看到新手村历史上所有的访谈的记录:‌

最新的访谈:

最初的访谈:

按村名搜索:

screenshots from steemblog: https://steemblog.github.io/@team-cn/tags/cn-interview/

想要了解新手村 @team-cn 里的各位朋友,用 steemblog 看一看就一目了然了,确实很有趣。 这对新人也很有帮助,建议你们来看看。‌

(2)社区名人录

‌Steem是个社区,社区是由人组成的,其中有些人由于各种原因成为舆论的焦点或实际的掌权派,总是在历史上不断发生的事情。‌

—-‌

最近 #sct 标签称霸舆论,对于创始人之一的 Jack @jack8831 也接受到了大量的八卦和追捧。但要看家里有矿的男神的生辰八字,也不是这么容易的事啊。‌

steemblog 可以帮你解决这个问题。昨天服务器花了6分钟备份了 Jack @jack8831 的历史文章:https://steemblog.github.io/@jack8831/

然后,要阅读 Jack 的最新动态、历史观点、常用的标签,就容易多了。

不过韩文/朝鲜语我不懂,所以读起来还是需要借助机器翻译的力量。但不可思议的是,下面早期文章的图中的“基本英语”我居然看懂了!!

Jack 好像曾经喜欢给韩国朋友们分享英文,标题中也有“鲑鱼”(연어)的前缀:https://steemblog.github.io/@jack8831/tags/englishforkorean/

所以 steemcoinpan 上鲑鱼泛滥,似乎也在情理之中了。

‌screenshots from steemblog: https://steemblog.github.io/@jack8831/

Jack和团队做的 steemcoinpan 风头正劲,要向韩国朋友们学习,也不妨了解下他们的过往~‌

—-‌

回到CN区。‌

我之前读过《Steem指南》中的 《Steem 十讲》,觉得 刘美女 @deanliu 的观点和文章很独到,所以特地同步了刘美女的文章到 steemblog (服务器时间 18 分钟,刘美女的文章和标签都很多,同步较慢):https://steemblog.github.io/@deanliu/

刘美女已经写了 1400+ 文章,可谓笔耕不辍、涉猎广泛。

最常用的首标签(类别):除了CN区话题,摄影、旅游、美食、讨论 steem / blockchain、以及聊娃(TT)是日常。

最初的文章都是英文,拓荒时期CN区还没有形成规模吧:

老道茶馆的一些过往:https://steemblog.github.io/@deanliu/tags/laodr-teahouse/

‌screenshots from steemblog: https://steemblog.github.io/@deanliu/

不过其实之前 大鹏 @dapeng 也曾经帮助 刘美女 @deanliu 备份过文章( GitHub上的 文章 Markdown 源码 / Netlify 备份站点 ),只是并没有设置成自动更新、以及网站模板较简单罢了。从备份的角度,steemblog 也只是另一种工具和服务而已,并不新奇,但希望它也有所帮助。‌

—‌

我不是很喜欢八卦,所以八卦社区名人和豪杰们的任务,就交给大家自己去完成了。不过想要用 steemblog 来八卦哪些名人倒是可以给我提供一个名单,我可以帮助备份到 steemblog。‌

(3)活动的回顾

‌活动一般以标签的形式进行推广,所以与上面看到的以个人账户为主的文章展示方式并不相同。对于标签文章的备份,steemblog 也可以支持,但目前并没有部署单独对标签进行备份的案例,而且需要对界面做少量修改。‌

这里展示一下 我 @robertyan 主办的对联活动如何查看。‌

以 https://steemblog.github.io/@{username}/tags/{tag}/ 的格式,就能查看标签下的文章。由于对联活动的文章都是我发表的,所以可以这样查看:https://steemblog.github.io/@robertyan/tags/cn-couplet/

‌screenshot from steemblog: https://steemblog.github.io/@robertyan/tags/cn-couplet/

已经办到第四期了,欢迎对语言和文化有兴趣的朋友参与。这期的题目是给刚刚升级到50/60/70级的朋友们写寿联https://busy.org/@robertyan/qs55nyh8x9

(4)奇文共欣赏

‌第四种用途对我还是挺有帮助的:Steem上有一些极度认真的作者,对于喜欢看好文章用户,现在的steemit/busy/steempeak等界面都满足不了需求。‌

上面提到过我推崇 刘美女 @deanliu 的文章并在昨天同步到了 steemblog。其实更早之前,我还同步了 维参 @crowflew 的文章,是我之前在 steem 看到的最有意思的文章系列之一吧:https://steemblog.github.io/@crowflew/

对于阅读博客,steemblog 会显示目录方便作者通览全文和跳转到章节:

可以方便的跳转到前后文章、找到 steem的原文,以及回到顶部等:

‌screenshots from steemblog: https://steemblog.github.io/@crowflew/or-or-or-or/

当然,steem 上的奇文还有很多,如果你有觉得仔细希望阅读的作者,也不妨把他的账户分享给我,一起欣赏一下。‌

(5)揭秘黑历史

‌steemblog 不但能让有用的信息能够被快速查询到,还能让罪行无处遁形。是不是听着挺像一位侦探的?‌

好吧,下面我们来看看 机机 @julian2013 和 村长 @ericet 是如何互黑的。(其实你们是不是更愿意看 软哥 @softmetal 和 小P @pgr 互黑的桥段?)‌

到 steemblog 页面上,点击右上角的搜索进行“侦查”。‌

—-‌

机机谈论村长:

‌screenshots from https://steemblog.github.io/@julian2013/

—-‌

村长评价机机:

‌screenshots from https://steemblog.github.io/@ericet/

—-‌

看上去机机从来没说过村长“坏”话,而村长可不是这样。真的是这样吗?

那么到底究竟说了什么呢?还是要各位自己去看才行。真相永远只有一个,看了以后不妨告诉我。‌

(6)组织的起源

‌其实相比查看人的文章,我更感兴趣组织的发展历史和起源,以及它们的生长过程,比如 @team-cn、@steemstem、@utopian-io,这里也为他们备份了镜像以便于追根溯源、温故知新:‌

@team-cn

‌screenshot from https://steemblog.github.io/@team-cn/page/45/

—-‌

@steemstem

‌screenshot from https://steemblog.github.io/@steemstem/page/28/

—-‌

@utopian-io

‌screenshot from https://steemblog.github.io/@utopian-io/page/33/

希望这些团队不忘初心,破除艰险、勇往直前。‌

—-‌

以上这些例子,不知对你来说是不是也同样有趣或有帮助。‌

如果需要帮你镜像博客,可以在文章后面留言,本次提供5个免费服务名额,先到先得~‌

#3 进展

‌相比于《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中的描述,steemblog 最近也有一些功能和性能更新,这里简要介绍:‌

  1. 编译性能优化:编译速度提高了大约有20~100倍。
  2. 多平台部署:支持备份镜像到Netlify等平台。
  3. 渲染优化:由于采用了组件,进行了优化以保证用户体验
  4. 问题修复:比如类别(category)显示顺序、编译内存溢出等

(1)编译性能优化

‌其实 steemblog 的功能实现是相对比较简单的(可以参考上一篇文章)。但真正有困难的是在 hexo 的编译速度。‌

hexo 虽然号称速度极快,但实际编译的时候简直是灾难。当然,原因不能完全归罪与 hexo 框架本身,更多是 hexo theme的问题。‌

例如,以下是几个账户一开始的编译所有文章花费的时间:

@andrewma: 400+ posts, 80+ tags, ~20 mins

@ericet: 630+ posts, 260+ tags, > 60 mins

很多人的文章数量都接近这个量级,如果要全都同步的话,时间耗费还是很大的,每天更新就要消耗很多资源。‌

除了优化编译方式,另一种是采用增量更新(即只编译新增加的文章), hexo 虽然自称是支持增量更新的,但实际情况是基本不支持、且有很多潜在的问题。‌

—-‌

(a) 优化编译过程

其实原先我只打算做一个简单的服务,不想在主题(theme)优化上花太多功夫,但真正用起来才发现开源世界并不是那么美好 :) ‌

为了完成给大家的每天更新的承诺,以下是优化的方案。‌

  1. 修改主题:由于我们采用的主题(https://github.com/ppoffice/hexo-theme-icarus)较多的使用了各种控件和大量使用了标签和分类等,使得功能较为强大,但带来的问题是编译成静态页面时的成本也很高,为了修复这个主题的问题,我们fork原来的项目,采用了修改后的主题:https://github.com/steemblog/hexo-theme-icarus
  2. 大量使用缓存(cache):hexo 自带有fragment_cache和partial方法,以方便缓存重复使用的组件(如head, footer, sidebar等),但 theme 的作者有时候不清楚可以这样使用,所以我们需要修改。
  3. 控件页面分离:除了使用cache,像很多组件是可以通过 iframe 或者 ajax 异步加载的形式来展示的,这样可以在实现静态页面的时候减少很多冗余的 控件的 html,减少文件大小、提高效率。
  4. 采用时间线布局:原来的 index、tag、archive等页面,都采用了直接展示文章内容的布局,其实不是很有必要,不方便阅读而且使得静态 html 页面变得很庞大。所以我们改成了 timeline 的 layout。
  5. 增加每页文章数量:默认的分页是 6 篇文章一页,对于时间线模式是太少了,所以改成了 20 篇文章一页。编译的速度受页面数量影响很大,而一页展示的文章多了,html 页面总数自然就少了、速度会有明显提高。

策略1:修改主题:

.gitmodules

1
[submodule "theme"] path = themes/icarus url = https://github.com/steemblog/hexo-theme-icarus.git

‌‌code from https://github.com/steemblog/blog | MIT License

策略2:大量使用缓存(cache)

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<% if (page.__widget) { %>
<%- body %>
<% } else { %>
<!DOCTYPE html>
<html <%- has_config('language') ? ' lang="' + get_config('language').substring(0, 2) + '"' : '' %>>
<head>
<%- partial('common/head', {}, {cache: false}) %>
</head>
<body class="is-<%= column_count() %>-column">
<%- partial('common/navbar', { page }) %>
<% function main_column_class() {
switch (column_count()) {
case 1:
return 'is-12';
case 2:
return 'is-8-tablet is-8-desktop is-8-widescreen';
case 3:
return 'is-8-tablet is-8-desktop is-6-widescreen'
}
return '';
} %>
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>
<%- partial('common/footer', {}, {cache: true}) %>
<%- partial('common/scripts', {}, {cache: true}) %>

<% if (has_config('search.type')) { %>
<%- partial('search/' + get_config('search.type'), {}, {cache: true}) %>
<% } %>
</body>
</html>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

对于重复的模块,使用 partial(‘component’, {param}, {cache: true}) 来替换原来的实现‌

策略3:控件页面分离

将原来的 profile, recent_posts, category, tag, tagcloud, archive 等组件,生成独立的 html 页面,减少冗余的 html。此外,组件采用独立的页面也是实现增量编译所必须完成的,所以这一步必须要做。‌

themes/icarus/layout/layout.ejs 需要修改 generators,生成新的 widgets 页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Widget page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('widget', function (locals) {
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
const component_widgets = widgets.filter((w) => (w.component))

return component_widgets.map(function(widget){
return {
path: `widgets/${widget.type}.html`,
layout: 'component/pjax_widget_src',
data: {
widget: widget,
__widget: true
}
};
});
});
}

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_ref.ejs 将原来的组件用对页面的引用替换。

1
2
3
4
5
<div class="card widget">
<div class="card-content">
<div id="widget-<%= widget.type %>" data-pjax="<%= `${get_config("root")}widgets/${widget.type}` %>.html" style="position: relative; width: 100%; display: block;"></div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_src.ejs 对不同的组件,获取对应的内容

1
<%- partial(`widget/content/${page.widget.type}`, {widget: page.widget}) %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/source/js/pjax_widget.js 在页面加载时通过 ajax 来通过url获取组件的 html,替换控件的内容为实际内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (typeof(jQuery) !== 'undefined') {
(function($){
function load_pjax(element) {
// $.pjax({url: element.attr("data-pjax"), container: "#"+element.attr("id")})
$.get(element.attr("data-pjax"), function(data) {
element.html(data);
});
}
$("div[data-pjax]").each(function(){
load_pjax($(this));

})
})(jQuery);
} else {
(function(){
window.$ = document.querySelectorAll.bind(document);
function load_pjax(element) {
const url = element.getAttribute("data-pjax")
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
element.innerHTML = xhr.responseText;
};
xhr.send();
}
for (const e of $("div[data-pjax]")) {
load_pjax(e);
}
})();
}

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/common/widget.ejs 对控件,也要添加 cache 模式,减少冗余。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<% function render_widget(widget) {
const component = widget.component || false;
const cache = widget.cache || false;
if (component) {
const cahced_prefix = cache ? 'cached_' : '';
const template = `component/${cahced_prefix}pjax_widget_ref`;
return partial(template, { widget })
} else {
return partial('widget/' + widget.type, { widget, post: page }, {cache: cache});
}
} %>
<div class="column <%= side_column_class() %> <%= visibility_class() %> <%= order_class() %> column-<%= position %> <%= sticky_class(position) %>">
<% get_widgets(position).forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
<% if (position === 'left') { %>
<div class="column-right-shadow is-hidden-widescreen <%= sticky_class('right') %>">
<% get_widgets('right').forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
</div>
<% } %>
</div>
<% } %>

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

此外,每个组件都要重构将内容独立出来,这里不详细解释了。‌

策略4:采用时间线布局

将categories和tags页面的布局都显示为时间线模式,更容易浏览,且页面所占空间更小。‌

以 category 为例,展示为时间线 + 分页:‌

themes/icarus/layout/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="<%- url_for('/categories') %>"><%= _p('common.category', Infinity) %></a></li>
<% page.parents.forEach(category => { %>
<li><a href="<%- url_for(category.path) %>"><%= category.name %></a></li>
<% }) %>
<li class="is-active"><a href="#" aria-current="page"><%= page.category %></a></li>
</ul>
</nav>
</div>
</div>
<%- partial("component/timeline", {posts: page.posts}) %>
<% if (page.total > 1) { %>
<%- partial('common/paginator') %>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

采用时间线以后,同时也会每个展示的 item 添加 cache:‌

themes/icarus/layout/component/timeline.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="card widget">
<div class="card-content">
<% if (typeof(head) !== 'undefined' &amp;&amp; head) { %>
<h3 class="tag is-link">
<%= head %>
</h3>
<% } %>
<div class="timeline">
<% posts.each(post => { %>
<%- partial("component/cached_item", {post}) %>
<% }) %>
</div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

策略5:增加每页的文章数量

可以有效减少页面总数,减少编译的负担。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Pagination
## Set per_page to 0 to disable pagination
per_page: 6
pagination_dir: page

index_generator:
per_page: 6

archive_generator:
per_page: 20
yearly: true
monthly: true

category_generator:
per_page: 20

tag_generator:
per_page: 20

code from https://github.com/steemblog/blog | MIT License

经过以上各类方案,编译所有文章的速度已经得到的极大的提高,大约已经提到了10~50倍了。

@andrewma: 400+ posts, 80+ tags, 1~2 mins

@ericet: 630+ posts, 260+ tags, 1~2 mins

(b) 实现增量编译

但我们的目标是增量更新,为了实现这个目的,我们需要做两方面修改:‌

  1. 增量生成markdown:无须每次都从 steem 获取 posts 并生成 markdown;
  2. 只编译受影响的 html 文件:修改 hexo 的 tag, category, archive, 和 post的generators,只在 html 受影响时生成。

步骤1:增量生成 markdown

为了不重复生成过去的posts的 markdown 文件,我们用 git repo 来管理过去已经生成的 markdown 文件,并只更新最近1天左右的文章。‌

同时,我们需要和之前的 source 对比,从而知道哪些文章需要更新。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def setup_source_repo(self):
git_clone_cmd = "git clone --depth 1 --branch {} --single-branch https://{}github.com/{}.git {}".format(SOURCE_BRANCH, self._get_github_pat(), self._get_repo(prefix=False), SOURCE_REPO_FOLDER)
os.system(git_clone_cmd)
# on `source` branch after clone
logger.info("Cloned source repo into workspace: {}".format(SOURCE_REPO_FOLDER))

def _commit_source(self):
os.chdir(SOURCE_REPO_FOLDER)
# commit the files into source repo
os.system("git add --all *")
res = os.system('git commit -m "Source updated: {}"'.format(get_uct_time_str()))
os.chdir("..")

if res == 0:
logger.info("Commited source into [{}] folder".format(SOURCE_REPO_FOLDER))
return True
else:
logger.info("Failed to add new source into [{}] folder".format(SOURCE_REPO_FOLDER))
return False

def _diff_files(self):
os.chdir(SOURCE_REPO_FOLDER)
res = subprocess.run(['git', 'diff', 'HEAD', 'HEAD~1', '--name-only'], stdout=subprocess.PIPE).stdout.decode('utf-8')
os.chdir("..")
files = [f for f in res.split("\n") if len(f) > 0]
logger.info("{} different files:\n{}".format(len(files), res))
return files

code from https://github.com/steemblog/blog | MIT License

为了保证每个用户运行时,文章的内容不会混乱,需要多source的workspace也做一些管理,这里不详细叙述了。‌

步骤2:只编译受影响的 html 文件

在用主题进行编译时,也需要知道哪些 markdown 文件需要更新,以及由此判断更新哪些 html。‌

themes/icarus/includes/helpers/diff.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
hexo.extend.helper.register('list_updated_posts', function (link) {
if (_posts.length == 0) {
process.chdir("source")
const res = execSync("git diff --name-only --cached").toString('utf8');
process.chdir("..")

const paths = res.split("\n").filter((p)=>(p.length > 0))
_posts = paths
}
return _posts
});

hexo.extend.helper.register('list_updated_categories', function (link) {
if (_categoreis.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_categories(post.categories);
}
}
}
}
return _categoreis
});

hexo.extend.helper.register('list_updated_tags', function (link) {
if (_tags.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_tags(post.tags);
}
}
}
}
return _tags
});

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

在 generators 中,只考虑那些受影响的文件。以category 为例:‌

themes/icarus/includes/generators/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function needs_update(category) {
if (config.incremental) {
// in incremental mode, update the affected category pages only
const updated_categories = list_updated_categories();
if (updated_categories &amp;&amp; updated_categories.length > 0 &amp;&amp;
updated_categories.indexOf(category['name']) != -1) {
return true;
}
return false;
}
return true;
}

return locals.categories.reduce(function(result, category){
if (! needs_update(category)) {
return result;
}

const posts = category.posts.sort('-date');
const data = pagination(category.path, posts, {
perPage: perPage,
layout: ['category', 'archive', 'index'],
format: paginationDir + '/%d/',
data: {
category: category.name,
parents: findParent(category)
}
});

return result.concat(data);
}, []);

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

需要注意的是,这里需要找到 hexo 对应的几个 generator 的源码,并将其进行替换,例如 hexo-generator-tag、hexo-generator-category、hexo-generator-archive ‌

—‌

实现增量编译以后,经过测试,大概每天更新时,每个账户消耗的时间大约在几秒钟 到1分钟之间。12个账户更新时,总的耗时大约在2分钟至10分钟左右,包括环境部署的时间。

@andrewma: 400+ posts, 80+ tags, ~17s

@ericet: 630+ posts, 260+ tags, < 1min

—-‌

至此,编译性能优化的工作告一段落,可以支持更多账户的镜像同步了。‌

(2)多平台部署

‌除了 GitHub pages,现在常用的静态网站部署方式还有Netlify等。只需要按照Netlify的界面上步骤操作即可,或者参考 hexo deployment 一节的描述。‌

作为结果,我们可以将页面部署到不同环境:‌

‌注意:Netlify上目前只部署了 @robertyan 的文章,但也可以支持其他账户。‌

(3)渲染优化

‌由于采用了组件化的 html 页面内,在上文提到过需要动态加载 widget 的页面,由于页面加载资源的阻塞等问题,我们需要对页面做一些优化才能保证 widget 的渲染不被图片等资源影响太大。‌

这里主要是在 widget 的占位符组件被渲染以后,立即调用 ajax 加载组件的代码,以尽早显示这些 widgets;否则,首页打开时的卡顿还是挺明显的。‌

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

主要需要优化的渲染过程就是组件的渲染,其余目前并未做更多测试。‌

(4)问题修复

‌除了以上提到的问题,由于在编译或展示时还需要一些别的问题,也一同修复了。‌

  1. @andrewma 想可以将 category 和 tag 等按使用频率从大到小排序;
  2. 编译 @lemooljiang 的博客时,产生 node / v8 的内存溢出问题,编译失败。

这些问题较容易修改:前者只需渲染前进行排序;后者需要对node运行的参数进行配置,改上限为8GB。后者的修改在:‌

blog/command.py

1
2
3
def configure():
settings.set_env_var("NODE_OPTIONS", "--max-old-space-size=8192")
os.system("cp -f _config.theme.yml themes/icarus/_config.yml")

#4 未来

‌steemblog 实现时 只是为了满足更好的阅读、搜索文章的需要。简言之,它是一个更好的博客“阅读器”(当然也是一个有趣的“时光机”),并不具有写的功能。‌

这是它想要解决的问题决定的,但它的未来可以有着有趣的发展方向,我们从小和大两个方面来讲。‌

—-‌

:从steemblog的角度来讲,我们可以做各类改进,包括功能、性能、运营等。‌

  • 功能:支持语言切换、主题切换、留言(原来就有,为了性能隐藏了)、图片本地保存等
  • 性能:hexo 模板的渲染速度可进一步优化
  • 运营:可以扩展现有系统以支持更多用户、可以考虑付费模式以满足更多需求(费用可能是一次性 10 STEEM 之类的)
  • 扩展:用户可以借助此框架和其他建站服务,快速构建基于 steem 数据的各种网站,包括博客、简历、图库等,以及各种基于 steem 数据的展示组件、基于 steem-js 的写操作 等等;

‌—-

:steemblog 展示了一种基于blockchain 的 app 的更多的可能性。为什么这么说呢?主要原因如下:‌

  • 一份数据、多种展示:与传统数据库相比,blockchain 数据库的公开性和可访问性使得它可以被方便用于基于同一份数据构建多种应用。这也是dApp有趣的方面。steemblog 通过 将 steem blockchain 的数据,进行二次加工,形成了不同的展示方式,这体现了一份数据、多种应用场景的特点。 steemblog 的意图和 steemit 等客户端不完全相同。这里强调的展示有更多 “数据应用”(data apps)的意味,并不全然是 web app 或者 mobile app的视角。
  • 分久必合、强调综合:steem 等区块链平台,现在流行的 dApp 以web app的思维,不断产生新的应用和平台,使得数据不断分化、分裂,到了一定复杂度后,需要一个可以集中管理各类数据与事务的调度中心,steemblog 对于历史的总览体现了这一种思想的一个方面。
  • 数据基础的改进方向:steem 类应用的用户体验的局限性一部分在于其数据基础设施的不灵活与低效,steemblog 通过分离数据读和写,改进了用户体验,但这只是一个方向。blockchain 数据基础设施有着更多的发展的可能性。
  • 社会:生产还是消费?:steemblog 把 steem 数据展现出的一个用户的能力、经验、历史等方面,更有效的展现出来,这是一个更具有生产、企业或产业角度的意义的展示。 steemblog 可以让我们更清楚地看到一个用户的时间是如何被应用与转化的。这种方式对于大规模协作的价值大于娱乐消费型 app 的需要。

这只是一个大致的方向,或许随着思考的深入我们可以把它演变成新的应用。‌

但有三点应该是对的:(1)你在 steem 的历史不会消失;(2)更好的时光机将会不断被发明出来;(3)未来必定会来到。‌

基于这些前提,我们或许能不断看到更多有趣的应用吧。‌

—-‌

昨天 @holger80 在 discord 和我聊到了关于 hexo theme 的问题,同时创建了 steemsites 这个项目(https://github.com/holgern/steemsites),可能也有通过 steem 构建站点,或者其他方面的考虑。‌

对于 steemblog 和相关的项目,我们在之后会进一步思考和探索。如有任何建议请随时留言讨论~‌

参考文献

  1. Hexo博客框架:https://hexo.io
  2. Hexo icaru 主题:
    1. 修改后:https://github.com/steemblog/hexo-theme-icarus
    2. 原作者:https://github.com/ppoffice/hexo-theme-icarus
  3. steemblog 博客镜像服务:https://steemblog.github.io/ (源码:https://github.com/steemblog/blog | MIT License)


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/steemblog-steem%e6%97%b6%e5%85%89%e6%9c%ba-steem-time-machine


This page is synchronized from the post: steemblog: Steem时光机 | Steem Time Machine

贺寿与建祠

贺寿与建祠

上一期《对偶与春秋》中,我们谈到了对联的对称/阴阳本质,以及人类对时间的观念的变迁。本文循着时间这条路,我们简单谈谈时间相关的对联。‌

写人物的对联大概有婚联、寿联、挽联,如果是兼有祠堂的名人,则还包括祠堂的楹联。今天就说说贺寿和建祠过程中的一些对联。‌

–‌

贺寿

‌大多数寿联都是送给生者的“人情”,阿谀之辞在所难免。寿联大多属于应酬之作,感情一假,便不足为观。不过虽然平庸之作占了大多数,但佳作也是有的。以下选自《名联观止》[1]中一些不俗的寿联,可作一观。‌

如郑板桥的六十寿联,可见真性情:

常如作客,何问康宁;但使囊有余钱,瓮有余酿,釜有余粮,取数叶赏心旧纸,放浪吟哦,兴要阔,皮要顽,五官灵动胜千官,过到六旬犹少;

定欲成仙,空生烦恼;只令耳无俗声,眼无俗物,胸无俗事,将几枝随意新花,纵横穿插,睡得迟,起得早,一日清闲似两日,算来百岁已多。

‌郑板桥曾任山东范县、潍县知县,因得罪地方豪绅,托病弃官,寄居扬州卖画,称为“扬州八怪”之一,诗、书、画均不俗,人称“三绝”。曾做一四言诗:

学诗不成,去而学写。学写不成,去而学画。

日卖万钱,以代耕稼。实救困贫,托名风雅。

免谒当途,乞求官舍。座有清风,门无车马。

与自寿联一道,可见他的真性情。‌

光绪三十四年(1908年,戊申年)八月,袁世凯五十生辰,大开寿筵,有谄媚者献寿联:

戊戌八月,戊申八月;

我佛万年,我公万年。

‌”戊戌八月“为袁世凯得势之始(靠出卖维新变法之立宪派,即谭嗣同等),且此联也颂慈禧(”老佛爷“)。同年十月,慈禧病故,名士祝竹岩改此联为:

戊戌八月,戊申十月;

我佛万年,我公明年。

‌虽然袁项城未能明年就死,但此联也传诵一时。‌

image source: Wikipedia – 生日

建祠

‌寿联贺生人,挽联敬死者,祠联题名士。挽联今次先不谈,我们先看祠联。‌

祠联甚多,其中诸葛祠甚为有名,由杜甫《蜀相》(”丞相祠堂何处寻“)可知。‌

这里录两则短联,分别题张良与韩信。‌

于右任题张良庙联:

辞汉万户;

送秦一椎。

山西霍山题韩信墓联:

生死一知己;

存亡两妇人。

这里且卖一关子,能说明联中典故,奖励1 STEEM~‌

活动

上一期活动,我们以“四时(春夏秋冬)与四方(东南西北)‌”为题,两人一组对联。‌‌

下面为活动结果。‌‌

参与:

(上联)春夏秋冬四时雨 | @cecilian

(下联)东南西北八方客 | @mia-cc

(下联)东南西北四面风 | @doveyan

(上联)东邪西毒南帝北丐中神通 | @andrewma

(下联)春华秋实夏蝉冬雪光似水 | @julian2013

(下联)春生夏长秋收冬藏中养生 | @doveyan

(下联)東暖西凉南熱北寒中誼居 | @hertz300

(上联)东成西就 | @teamcn-shop

(下联)南辕北辙 | @annepink

(下联)南来北往 | julian2013

(下联)春华秋实 | @xiaoshancun

(上联)春夜漫漫无心睡 | @julian2013

(下联)秋昼绵绵惹人醉 | @andrewma

(下联)秋日私语情意长 | @annepnik

(下联)过来让我抱一下 | @softmetal

(下联)秋波漪漪想美丽 | @julian2013

(下联)望穿秋水盼君归 | @doveyan

以下都是上联,但没有人对下联。

春夏秋來又一年,南方四季缺冬天。 | @hertz300

春不覺來秋已去,南方天氣无冬天。 | @hertz300

春夏秋冬四季,南北西东八方。 | @zy-sb

点评:‌‌

  • 这期参与很活跃,也有很多有趣的作品,谢谢大家~

奖励:‌‌

经综合评价,以下两联较为妥当,分享 3 STEEM奖励,每人获得0.75 。其余每人0.1 STEEM奖励。奖励稍后发放。

春夏秋冬四时雨 | @cecilian

东南西北八方客 | @mia-cc

东邪西毒南帝北丐中神通 | @andrewma

春华秋实夏蝉冬雪光似水 | @julian2013

‌‌

—-‌‌

以下为本期对联活动内容:寿联,由本周内刚满50、60或70级的寿星报名,由其他人为其做寿联。

形式:‌

  1. 寿星自由报名
  2. 其他人自由发挥,为寿星做寿联
  3. 上面”建祠“部分有猜谜活动,也有奖励

规则:‌‌

  1. 满足对联的基本规则;
  2. 不许抄袭任何别人的成果;
  3. 不应当使用机器协助,如微软亚洲研究院开发的“自动对联”

奖励:寿星奖励 1 STEEM(有人帮他写对联为有效,最多3名,先到先得);最佳作品奖励 2 STEEM;参与奖,各0.1 STEEM,前10名都有奖 :)‌‌

参与方式:回复本文‌‌

评价方式:由寿星评判‌

时间:本文发布起7日内有效‌‌

参考文献

  1. 梁羽生,《名联观止》,北京大学出版社,2017年


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e8%b4%ba%e5%af%bf%e4%b8%8e%e5%bb%ba%e7%a5%a0


This page is synchronized from the post: 贺寿与建祠

用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

本文介绍将Steem文章同步到GitHub pages的开源工具和免费服务:‌

  1. 开源工具 “blog”:https://think-in-universe.github.io/blog/
  2. 免费服务 “steemblog”:https://steemblog.github.io/

Image Source: Pixabay

缘由

最近在用steem的时候,觉得不管是用busy, steempeak还是steemit等,它们的界面设计对于看自己以前的文章并不太方便(当然想看其他人的旧文章也比较麻烦),并且由于国内的网络访问这些站点的速度都不太快,所以以博客服务来看,用户体验是挺差的;至于要方便地搜索、归类自己的文章就更麻烦了。‌

之前曾经有过一些浏览历史文章较方便的服务(如chinabb和steemitfriends),似乎也或者关闭或者收费了,因此暂时没有找到好用的服务。‌

于是想到可以把Steem上的文章备份成镜像,每日自动同步,便于自己梳理和分析;虽然我文章写的不多,但如同在《标签的本质 | The Nature of Tags(一)》里提到的,组织信息是人类的本能,于是便实现了这里的工具和服务。‌

GitHub镜像博客

关于为什么需要自己写文章同步工具,其实是值得询问的:‌

  1. 首先,博客镜像的工作相信之前有人也已经做过了,这并非什么新想法(但我简单搜了一下也没有找到可以立即复用的工具)。但是搭建博客镜像是一项需要适应自身需求的工作,所以自己动手的话可以有更高的灵活性和掌控度。
  2. 其次,即便之前有类似工作的话,可能也并不是同步到GitHub,或者也未必会做到近实时的更新,所以这项工作也可以作为一种服务,也并非完全没有价值。

为了完成这项工作,我们基于steem API、GitHub pagesHexo[1]框架创建了博客镜像搭建工具,效果如下(示例:https://think-in-universe.github.io/blog/):‌

1. 博客首页

左侧是用户的profile,右侧是近期的文章,中间为最近文章。

‌screenshot from https://think-in-universe.github.io/blog/

2. 侧边栏:类别和标签

Steem上的标签和类别,会同步到hexo框架下面,并能够正常显示。遗憾的地方在于由于steem上没有类别层级的概念,所以要分类文章,相对来说没有那么灵活。

‌screenshots from https://think-in-universe.github.io/blog/

3. 侧边栏:近期文章和归档

‌显示最近5篇文章,以及每个月的文章数量。可以看出,作为写作者而言,我是比较懒惰的 :) 和大家比还有很大差距。

‌screenshots from https://think-in-universe.github.io/blog/

4. 文章展示:右侧目录、代码高亮和原文链接

‌在右侧添加了一个目录控件,对于阅读长文是有帮助的。‌

代码高亮对类似本文的有代码的文章有一定帮助,steemit对代码高亮的处理是比较初级的。‌

原文链接其实是为了方便我自己有时候引用文章需要,在steem上找文章比较低效。

‌screenshots from https://think-in-universe.github.io/blog/

5. 搜索

‌搜索功能对于想要快速查阅或引用自己的文章,较有帮助。点击右上角的搜索按钮,可以进行快速搜索。

‌screenshot from https://think-in-universe.github.io/blog/

6. 独立的归档、类别、标签页等

‌如果要单独查看这些信息,可以到分别的独立页面下查看,如有需要,也可以建立其他的标签页。例如,归档页面的时间线,比steem看起来简洁一点:https://think-in-universe.github.io/blog/archives/

‌screenshots from https://think-in-universe.github.io/blog/

页面展示大体如此,主要的价值在于从文章的角度,信息的组织更为清晰。如果想要获得一个类似的博客镜像,大抵有两种方法:‌

  1. 如果你了解GitHub和GitHub pages如何使用,可以使用本文发布的开源代码(https://github.com/think-in-universe/blog),根据其中的README,搭建一个类似的镜像就行了。
  2. 如果你希望可以使用一个免费的博客镜像服务,可以参考文章最后一章提到的 steemblog 博客镜像服务,或者直接联系我。

如何实现博客镜像工具?

‌为了实现以上功能,我们可以基于博客框架Hexo[1],搭建从Steem同步数据、并发布到GitHub pages的博客镜像工具,可以支持基于用户名、标签、日期等查询方式的数据同步。下面简要介绍如何实现这一博客镜像工具。‌

工具的代码在GitHub开源:https://github.com/think-in-universe/blog

关于具体如何使用此工具,可以参考上面项目中的README的介绍:可以在本地安装后使用,也可以通过travis-ci部署。‌

本项目的代码里重用了 @cn-hello 小门童实现时的一些基本框架,所以需要增加的功能较少。工具的工作流程如下,也比较简单:‌

  1. 下载你的Steem文章;
  2. 用Hexo编译成静态文件;
  3. 用GitHub pages部署博客;

(1)下载你的Steem文章

‌由于重用了之前的SteemReader的方法,我们可以指定通过账户或者标签以及时间(天数)来获取文章。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
class BlogBuilder(SteemReader):

def __init__(self, account=None, tag=None, days=None):
SteemReader.__init__(self, account=account, tag=tag, days=days)

def download(self):
if len(self.posts) == 0:
self.get_latest_posts()
if len(self.posts) > 0:
for post in self.posts:
self._write_content(post)

‌code from https://github.com/think-in-universe/blog | MIT License

为了将文章下载为hexo可识别的markdown格式,需要在markdown中加入相关ymal或json的元数据。以下为markdown模板,包含了标题、类别、日期、标签等信息,并指定显示文章的目录。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MESSAGES["blog"] = """
---
title: "{title}"
catalog: true
toc_nav_num: true
toc: true
date: {date}
categories:
- {category}
tags:
{tags}
thumbnail: {thumbnail}
---


{body}
"""

code from https://github.com/think-in-universe/blog | MIT License

使用Steem API,获取steem文章的元数据和markdown文本。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def _write_content(self, post):
folder = self._get_content_folder()
c = SteemComment(comment=post)

# retrieve necessary data from steem
title = post.title.replace('"', '')
body = post.body
date_str = post.json()["created"]
date = date_str.replace('T', ' ')
tags = "\n".join(["- {}".format(tag) for tag in c.get_tags()])
category = c.get_tags()[0]
thumbnail = c.get_pic_url() or ''
url = c.get_url()

# build content with template
template = get_message("blog")
content = template.format(title=title, date=date, tags=tags, category=category, thumbnail=thumbnail, body=body, url=url)

# write into MD files
filename = os.path.join(folder, "{}_{}.md".format(date_str.split('T')[0], post["permlink"]))
with open(filename, "w", encoding="utf-8") as f:
f.write(content)

logger.info("Download post [{}] into file {}".format(title, filename))

code from https://github.com/think-in-universe/blog | MIT License

(2)用Hexo编译成静态文件

‌我们需要为建立的博客设置一个美观的主题。‌

我们这里使用了 https://github.com/ppoffice/hexo-theme-icarus 主题,需要将其作为一个git submodule加入到git repository中。‌

.gitmodules

1
2
3
[submodule "theme"]
path = themes/icarus
url = https://github.com/ppoffice/hexo-theme-icarus.git

‌code from https://github.com/think-in-universe/blog | MIT License

随后使用hexo命令来将markdown转换成生成静态的文档。‌

blog/command.py

1
2
3
4
5
6
7
@task(help={
})
def build(ctx):
""" build the static pages from steem posts """

os.system("cp -f _config.theme.yml themes/icarus/_config.yml")
os.system("hexo generate")

‌code from https://github.com/think-in-universe/blog | MIT License

(3)用GitHub pages部署博客

‌正式部署时,我们有两种方式,一是在本地使用hexo命令部署,或者在travis-ci 中定期每日进行同步。‌

hexo命令部署:blog/command.py

1
2
3
4
5
6
7
@task(help={
})
def deploy(ctx):
""" deploy the static blog to the GitHub pages """

build(ctx)
os.system("hexo deploy")

‌code from https://github.com/think-in-universe/blog | MIT License

travis-ci部署:.travis/deploy.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ -z "${GITHUB_PAT}" ] &amp;&amp; exit 0
[ "${TRAVIS_BRANCH}" != "master" ] &amp;&amp; exit 0

git config --global user.email "${GIT_EMAIL}"
git config --global user.name "${GIT_USERNAME}"

git clone --depth 1 --branch gh-pages --single-branch https://${GITHUB_PAT}@github.com/${TRAVIS_REPO_SLUG}.git site
cd site
cp -r ../public/* ./

NOW=$(date +"%Y-%m-%d %H:%M:%S %z")
git add --all *
git commit -m "Site updated: ${NOW}" || true
git push -q origin gh-pages

‌code from https://github.com/think-in-universe/blog | MIT License

另外,需要注意,由于用travis-ci 部署时需要用户提供Git用户信息(用于commit到gh-pages)以及GitHub的token,所以需要以环境变量的方式进行配置。‌

博客镜像服务 http://steemblog.github.io/

‌今天在微信群中 岩哥 @andrewma 提到想要一个分析文章标签的服务,我想起搭建的这个博客镜像也有标签云和标签统计,所以帮助建一个类似的镜像服务就能解决该问题。‌

但由于岩哥对GitHub并不熟悉,使用上面提到的博客镜像工具可能较为困难,所以在此基于https://github.com/think-in-universe/blog 项目,建一个organization account用户管理博客,帮助有需要的人建博客镜像的子目录,这就是steemblog。‌

1. 如何使用博客镜像服务

‌目前,这个博客镜像服务可以在 https://steemblog.github.io 找到。‌

如果要添加一个新的用户到镜像同步中,只需添加账户到用户列表中即可(目前是手动添加的)。例如,我们添加了 @robertyan 和 @andrewma 到列表中。我们可以在以下链接访问他们的博客镜像:‌

  1. https://steemblog.github.io/@robertyan/
  2. https://steemblog.github.io/@andrewma/

与之前的工具需要手动配置用户信息不同,这里自动从steem同步了用户的profile。(不过跟我手动配置的差不多)

‌screenshot from https://steemblog.github.io/@robertyan/

@andrewma的博客镜像也创建成功了,不过头像和缩略图的处理可能需要做一些改进。

‌screenshot from https://steemblog.github.io/@andrewma/

比如岩哥关心的标签信息,可以在https://steemblog.github.io/@andrewma/ 中找到:

‌screenshots from https://steemblog.github.io/@andrewma/

同样的,我们可以继续添加新的用户,他们的镜像可以在 https://steemblog.github.io/@{账户名} 中找到。‌

对于这样的博客镜像,如有需要或建议,可以在文章后面留言讨论。‌

2. 如何建立博客镜像服务

https://github.com/steemblog/blog 是在 https://github.com/think-in-universe/blog 的基础上构建的,为了适应多用户的子目录的需要,需要对原来的项目的目录结构和部署方式做一些调整。‌

(1)从steem下载文章的同时,自动同步用户信息

通过steem获取的账户信息,自动更新_config.yml_config.theme.yml

相对应的模板在 blog/message.py 中,由于内容太长,这里不贴出。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def update_config(self):
if not self.account:
return

organization = BLOG_ORGANIZATION
logo = BLOG_AVATAR
favicon = BLOG_FAVICON

language = settings.get_env_var("LANGUAGE") or "en"

a = SteemAccount(self.account)
author = self.account
name = a.get_profile("name") or ""
# about = a.get_profile("about") or ""
location = a.get_profile("location") or ""
avatar = a.get_profile("profile_image") or ""
website = a.get_profile("website") or ""

# build config file with template
template = get_message("config")
config = template.format(organization=organization, language=language,
name=name, author=author)
filename = CONFIG_FILE
with open(filename, "w", encoding="utf-8") as f:
f.write(config)
logger.info("{} file has been updated for the account @{}".format(filename, author))

# build config theme file with template
template = get_message("config.theme")
config = template.format(organization=organization,
favicon=favicon, logo=logo,
author=author, name=name, location=location,
avatar=avatar, website=website)
filename = CONFIG_THEME_FILE
with open(filename, "w", encoding="utf-8") as f:
f.write(config)
logger.info("{} file has been updated for the account @{}".format(filename, author))

‌code from https://github.com/steemblog/blog | MIT License

(2)在生成静态网页时,相互隔离不同用户的路径

将不同账户的页面放置到@account子目录下。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://{organization}.github.io
root: /@{author}/
permalink: :category/:post_title/
permalink_defaults:

# Directory
source_dir: source
public_dir: public/@{author}

‌code from https://github.com/steemblog/blog | MIT License

编译指定的steem用户的文章为静态页面,隔离放置在发布目录下。‌

blog/command.py

1
2
3
4
5
6
7
8
9
10
11
@task(help={
})
def build_all(ctx):
""" download the posts of all the accounts, and generate pages """

accounts = settings.get_env_var("STEEM_ACCOUNTS") or []
if accounts and len(accounts) > 0:
for account in accounts.split(","):
clean(ctx)
download(ctx, account)
build(ctx)

‌code from https://github.com/steemblog/blog | MIT License

(3)部署时,将页面推送到 steemblog.github.io‌

只需修改 .travis/deploy.sh 中的目标代码仓库的参数即可。‌

最后

‌究其本质,本文是对steem上的数据进行处理的一种尝试,在开放的区块链数据的基础上,我们可以根据场景,采取多种灵活的数据展现方式,这里的镜像博客无疑又是其中的一种。‌

希望本文提供的工具或服务对你有帮助,如果需要帮助你开启博客镜像服务,可以在本文留言,我会尽量提供支持。由于travis的使用也有一些限制,优先帮助前5位留言的朋友提供服务 :)‌

参考文献

  1. https://hexo.io
  2. Hexo icarus主题:https://github.com/ppoffice/hexo-theme-icarus
  3. 博客镜像工具:https://think-in-universe.github.io/blog/
  4. 博客镜像服务:https://steemblog.github.io/


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e7%94%a8github%e5%88%9b%e5%bb%basteem%e6%96%87%e7%ab%a0%e9%95%9c%e5%83%8f-mirroring-your-steem-blogs-on-github-%e5%85%8d%e8%b4%b9%e5%8d%9a%e5%ae%a2%e5%a4%87%e4%bb%bd%e6%9c%8d%e5%8a%a1%ef%bc%9a-st


This page is synchronized from the post: 用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

最近,CN区多了一位叫 @cn-hello 的小朋友,自称是CN区的小门童,每天在CN区路口守望,看到新人便上去提供一些建议,比如:“少侠,我看你能量很少了啊,休息会来村里喝杯茶坐坐吧” ,“那个谁,请你不要抄别人文章啊,会被举报的啊”,……,顺便给新人点个小小的赞。‌

随后又开始忽悠新人:“少年,我看你骨骼清奇,这本《Steem指南》似乎很适合你,10块钱卖你了吧?什么,没钱?那白送你了。” / “小伙,我们村里藏龙卧虎、灵气充沛,只要你肯按时做作业,可保你练成盖世神功,你来还是来还是来?”‌

他看到新人通常都很热情,但新人有时却一脸懵逼,不明白这货是干嘛来了。。。但cn-hello却很自我,每天都要炫耀一下自己勾搭了几位新人。。。‌

其实,@cn-hello 原来是一为牛角挂书的小牧童,本是勤于读书问道解惑的,但有了一些学问之后,却有些好为人师,看到迷途之人,免不了希望上前寒暄两句、指教一二。结果就从牧童变成了门童,负责村中的接引、指路一事了。‌

本文以下简单介绍一下他的来历,相关的一些想法,以及之后的计划。欢迎大家给这位小朋友提供建议。

image source: Wikipedia – 颐和园长廊彩绘 | CC BY-SA 2.0

小门童的介绍

来历

设计 @cn-hello 这个机器人(bot)的意义是颇为直接的,相信很多人也遇到过这个场景:刚来Steem发帖的时候,兴冲冲发了一个帖子,却无人问津,想要找前辈们请教一下,却不知道应该找谁,到其他作者或大佬帖子下留言,也不见得会被回复。所以cn-hello最初的功能便是为了主动发现身处迷雾之中的新人,告诉他们第一步该怎么走、接下来该怎么做、加入什么组织。‌

然而,本质上说 @cn-hello 也只是另一个欢迎机器人罢了(yet another welcome bot),有些欢迎机器人也确实并不令人喜欢,但或许也有一些差异:‌

  1. 他只关注用中文发帖的新人,只给中文用户留言;提供的建议也只用中文表达;
  2. 他提供的帮助信息,如新手村 @team-cn,如《Steem指南》,都是专为中文社区的新人们所创建的,更有针对性与亲切感
  3. 与其他某些欢迎机器人(welcome bot)相比,他并不以私利为目的而留言或点赞,他不发广告、不求赞,只是希望更好的发现和帮助新人。

虽然只运行了几天,但在帮助新人获取信息、找到团体方面也确实有一些帮助,也帮助我们更好地了解和认识了新人们的生存状态。在后文我们会进一步介绍这些内容。‌

—-‌

除了上面提到的这个显而易见的痛点,开始要写这个机器人的动机也有两方面:‌

  1. 一方面是在讨论《Steem指南》相关问题时,发现虽然有《指南》但很多人还是没有阅读的习惯,所以考虑是否可以实现一个发布攻略的小助手(advisor),根据新人发帖的情况,给他提供相应的修改建议;
  2. 另一方面,源于和村长 @ericet 的交流,关于平时是如何找新人进村的,村长说一般是自己去看的,没用什么工具。所以我想可以写个工具和机器人自动化这部分工作,村长也提到已经注册了 @cn-hello 这个账号,想来做类似的事情。

于是大概简单实现了目前的这位 @cn-hello 小门童,或许以后会有更多的功能,也欢迎大家提供建议,目的仍然是切实帮助到新手们。‌

—-‌

实际上,#cn-hello 过去是一个CN区新人常用的自我介绍的标签,最近似乎用的人少了很多。这里用 @cn-hello 作账户,用意也在于帮助新人,所以在意义上较为接近的。‌

功能

目前 @cn-hello 主要有两方面的功能:‌

(1)欢迎新人并提供建议

搜索1天内在 #cn 标签下用中文发表帖子的新人,并在他们的文章下回复新人可能遇到的困难,以及相关的建议,如下图所示:

image source: screenshot from the account @cn-hello ‘s comment‌

特别地,由于很多新人不了解RC的消耗,回复中添加了新人目前的能量可以发表的文章或回帖的总数,以及每天恢复的能量能发帖的数量。‌

关于中文区新人的定义,目前采用的是如下规则:‌

  1. 声望在 [25, 35] 的区间内;
  2. SP < 100;
  3. 帖子使用中文发表

(2)统计1日和7日的新人动态

现在 @cn-hello 定时于北京时间每日晚10点运行,首先搜索新人并回复,然后发布新人相关的统计信息,如2019年05月10日的帖子。统计信息包括:‌

  1. 文章推荐:今日发布帖子的新人以及推荐其中一篇帖子(通常是最新一篇);
  2. 7日新人统计:罗列过去7日发现的新人,以及他们的声望、能量(RC)、帖子数、粉丝数等信息。

这部分统计设计时主要是为了方便老用户为新人提供建议或支持,也可以帮助关注自己在初期的一些关键指标。如下图所示:

image source: screenshot from the account @cn-hello ‘s post

image source: screenshot from the account @cn-hello ‘s post‌

—-‌

目前功能是较为简单的,但对于发现新人,确实也有一些帮助;村长也会根据统计和@的通知,找到新人的帖子并帮助一些新手加入村内。‌

同时,也存在一些问题,似乎并不太容易解决,例如:‌

  1. 获取反馈困难:一般很难知道新手是不是读了 @cn-hello 的建议,以及对建议的反馈如何;确实也有一些新人看到了相关的回复,然后主动联系,但总体来说相当少;
  2. 新手可能不理解规则或建议:推荐的新手的文章有一部分是有抄袭或搬砖的问题的,虽然回复新人时指出了这一点,但可能新手并不理解实际的情况或不愿意相信,依然我行我素,结果还是被踩了。

源码

总体来说,这是一个较为简单的工程,但基本包括了一个论坛机器人常见的功能:监控、过滤、文本分析、回复、点赞、发表文章、通知,等等。‌

下面是本项目的源代码,开源在 @steem-guides 的GitHub账户下。‌

该机器人提供了如下命令,可供执行:

1
2
3
4
5
6
7
8
Available tasks:

cn-hello.reply reply to a post by cn-hello
cn-hello.search search the latest posts by newbies
cn-hello.summarize publish summary post for daily and weekly update
cn-hello.vote vote a post by cn-hello
cn-hello.welcome send welcome messages to newbies
steem.list-posts list the post by account, tag, keyword, etc.


代码较为简单,这里不赘述。但或许有一些基础类可以被复用,这里简单提一下:‌

  1. steem 模块
    1. collector.py:封装了以账户、标签、天数、数量等查询文章和回复的基本方法,如有需要做此类查询的,或许可以复用其中的 get_posts() / get_comments();
    2. comment.py 和 account.py:封装了一些常用操作,如各类常用信息的查询、是否被某人赞或者踩、纯文本的提取等;
  2. data 模块
    1. page_language.py:对文本使用的语言检测的封装;
    2. reader.py:可帮助实现监听某tag最新文章;
  3. cn_hello 模块
    1. bot.py, command.py, message.py, newbies.py: 稍作修改可创建一个新的机器人。
1
2
3
4
5
6
├── cn_hello
│ ├── __init__.py
│ ├── bot.py # the behaviors of the bot
│ ├── command.py # the commands that trigger the bot to act
│ ├── message.py # the messages for the bot to speak
│ └── newbies.py # the data operations of newbies

对于如何安装、执行命令等,可以参考GitHub repo的readme中的介绍。‌

所以,如果希望自己快速创建一个机器人实现点赞、回复、监控、通知等功能,或许可以参考这里的开源代码。‌

—-‌

关于识别中文,这里直接使用了 langdetect 这个 package,是对https://code.google.com/p/language-detection/ 项目的python移植。‌

具体可参见Language Detection Library for Java 中对算法的介绍。其核心是采用了Naive Bayes with character n-gram,计算不同字符拼写特征在哪种语言中出现的概率最高。‌

核心代码在项目的detector.py文件中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def get_probabilities(self):
if self.langprob is None:
self._detect_block()
return self._sort_probability(self.langprob)

def _detect_block(self):
self.cleaning_text()
ngrams = self._extract_ngrams()
if not ngrams:
raise LangDetectException(ErrorCode.CantDetectError, 'No features in text.')

self.langprob = [0.0] * len(self.langlist)

self.random.seed(self.seed)
for t in xrange(self.n_trial):
prob = self._init_probability()
alpha = self.alpha + self.random.gauss(0.0, 1.0) * self.ALPHA_WIDTH

i = 0
while True:
self._update_lang_prob(prob, self.random.choice(ngrams), alpha)
if i % 5 == 0:
if self._normalize_prob(prob) > self.CONV_THRESHOLD or i >= self.ITERATION_LIMIT:
break
if self.verbose:
six.print_('>', self._sort_probability(prob))
i += 1
for j in xrange(len(self.langprob)):
self.langprob[j] += prob[j] / self.n_trial
if self.verbose:
six.print_('==>', self._sort_probability(prob))

def _extract_ngrams(self):
'''Extract n-grams from target text.'''
RANGE = list(xrange(1, NGram.N_GRAM + 1))

result = []
ngram = NGram()
for ch in self.text:
ngram.add_char(ch)
if ngram.capitalword:
continue
for n in RANGE:
# optimized w = ngram.get(n)
if len(ngram.grams) < n:
break
w = ngram.grams[-n:]
if w and w != ' ' and w in self.word_lang_prob_map:
result.append(w)
return result

code from langdetect project | license: Apache License 2.0‌

未来

目前 @cn-hello 小门童的工作主要以接待和引导新人为主。之后的拓展依然以尽力帮助新人为目的,主要的改进可能在以下几个方面,但总体而言目前的优先级并不是非常高:‌

  1. 提供改进建议:根据作者对标签的使用、收益的情况、文章的主题等,提供在标签使用、活动参与等方面的建议,将《Steem指南》中的特定章节也会一并推送;
  2. 优化新人统计信息:给新人推荐其他steem数据分析平台的链接,方便新人了解掌握自己主要的状态和潜在的改进方向,可能只看统计帖子并不是很方便或有效;
  3. 优化文章推荐:推荐新人高质量的文章,以及包括提高新人在snax等注意力奖励平台上的收益等。这点似乎很多机器人都在做了,所以或许并不是 @cn-hello 的重点。

对小门童有任何建议,或者希望他还能帮新人们做些什么,请在文章下面留言哦~

小门童的思考

对新人的观察

透过 @cn-hello 每日对新人的访问和记录,我们也能获得一些关于新人的观察:‌

  1. 搬砖的倾向:在过去7人接待的28位新人中,至少有5位由于搬砖(抄袭)的问题声望被踩到25以下。一方面,我们的提醒没有达成特别好的效果;另一方面,新人不了解规则并希望轻松撸币容易有搬砖的倾向。
  2. “老”新人:大部分 @cn-hello 找到的新人都是1个月以内的创建的(18 / 28),但也有部分账户(6 / 20)已经创建了 1年左右或以上的。或许当时新人来访时,没有很快找到融入社区的方式,所以一直呈现若离若即的状态,希望 cn-hello能帮助缓解这一问题,目前看来似乎也并不容易。
  3. 积极的新人:目前积极回应 @cn-hello 的新人只有 (6 / 28)个,并不算很多,但能得到一些有效回应,也算部分完成任务了。

对新人不够友好(同时也是为了防止小号和机器人的泛滥),是Steem的一个严重的问题,也是比较奇怪的地方,但恐怕也是无奈之举。从实际上确实阻碍了新生力量的入场,给新玩家设置了较高的门槛。或许本质上这是西方文明“人性恶”的假设在作怪吧。‌

为了对抗新人面对的挑战,小门童表示不打算放弃新人“拯救”计划。‌

机器人的印象

小门童 @cn-hello 是机器人,但令他感到不解的是,steem上很多机器人并不打算遵循阿基莫夫的机器人三大定律或者四大定律,甚至恶行昭彰。

第零法则:机器人不得伤害整体人类,或坐视整体人类受到伤害;

第一法则:除非违背第零法则,否则机器人不得伤害人类,或坐视人类受到伤害;

第二法则:除非违背第零或第一法则,否则机器人必须服从人类命令;

第三法则:除非违背第零、第一或第二法则,否则机器人必须保护自己。

‌总体来说,steem上机器人给人的整体印象是不够正面的,既不智能、也不正义(不仁、不智)。‌

事实上,像“三大定律”这样义务化的伦理确实不适合steem上的机器人,他们不过是人的延伸,并不具有被编码的“道德”。或许在可预见的未来,人工智能的潜在危害也不过是“恶”的延伸,问题不在与机器本身有多智能,而首先在于设计和使用它的人是否能约束自身的贪婪和享乐的倾向。‌

—-‌

如果想要进一步了解steem上的机器人,《Steem指南》的机器人篇对于机器人有一些不完全的介绍,可作参考。‌

在帮助新人方面,@cn-hello 也只不过是其中之一。CN区还有很多可爱的机器人,有些依然活跃,有些则已经进入休假状态,比如 @cn-cutie.pie 和 @cn-naughty.boy。‌

之前的一些过去关于机器人问题的讨论,或许也可以作为参考:‌

  1. 聊聊机器人🤖 / Robots on STEEMIT
  2. steemit 还是机器人的天下
  3. 机器人是否会破坏steemit上的生态平衡?

‌@maiyude 的机器人教程,也可供初学者阅读,我们稍后也会整合到《Steem指南》中。‌

  1. steem-python 介绍:(1)(2)
  2. 点赞机器人开发:(1)(2)(3)

—-‌

虽然对于steem上的机器人存在许多争议,但所谓“自反而缩,虽千万人,吾往矣”,小门童希望能尽自己的一点绵薄之力,便已经足够了 :)‌

参考文献

  1. Wikipedia,机器人三定律
  2. Shuyo NakataniLanguage Detection Library for Java,2010年


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e5%80%9f%e9%97%ae%e5%b8%88%e5%8f%8b%e4%bd%95%e5%a4%84%e6%9c%89%ef%bc%8c%e9%97%a8%e7%ab%a5%e9%81%a5%e6%8c%87%e6%96%b0%e6%89%8b%e6%9d%91-%e5%85%b3%e4%ba%8e-cn-hello-%e5%b0%8f%e5%8f%8b%e7%9a%84


This page is synchronized from the post: 借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×