极路由和 newifi 刷 BREED

极路由 1S

1S 有两款硬件:hc5661 和 hc5661a,刷错变砖,而且要刷的文件名有点迷惑性,意不意外?

原版 bootloader 有 DHCP 功能,自身 IP 是 192.168.2.1,比较特殊。

这里以 hc5661 为例,版本是:HC5661 - 1.4.11.21001s,破解式 root 或开发者解锁后,可以直接 mtd unlock u-boot,开不开心?

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
BusyBox v1.22.1 (2018-05-10 05:32:57 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

***********************************************************
__ __ _ _ ____ _ TM
/ / / / (_) _ __ (_) / __/ (_)
/ /_/ / / / | | /| / / / / / /_ / /
/ __ / / / | |/ |/ / / / / __/ / /
/_/ /_/ /_/ |__/|__/ /_/ /_/ /_/
http://www.hiwifi.com/ rooted by UMU
***********************************************************
root@HiUMU:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "hw_panic"
mtd2: 00010000 00010000 "Factory"
mtd3: 00020000 00010000 "oem"
mtd4: 00010000 00010000 "bdinfo"
mtd5: 00010000 00010000 "backup"
mtd6: 00f70000 00010000 "firmware"
mtd7: 00120000 00010000 "kernel"
mtd8: 00e50000 00010000 "rootfs"
mtd9: 00400000 00010000 "rootfs_data"
root@HiUMU:~# mtd unlock u-boot
Unlocking u-boot ...
root@HiUMU:~# cd /tmp
root@HiUMU:/tmp# mtd write ./breed-mt7620-hiwifi-hc5761.bin u-boot
Unlocking u-boot ...

Writing from ./breed-mt7620-hiwifi-hc5761.bin to u-boot ...
[e:0] [w0]
[e:1] [w1]

刷完,捅菊花进入的信息是:

CPU MediaTek MT7620A ver 2, eco 3
内存 128MB DDR2
Flash Winbond W25Q128 @ 24MHz (16MB)
以太网 MediaTek MT7620A built-in 5-port 10/100M switch
时钟频率 CPU: 580MHz, Bus: 193MHz
编译日期 2018-12-29 [git-135bed9]
版本 1.1 (r1266)

极路由 3

版本 HC5861 - 1.4.10.20837s,一样能开发者解锁后直接刷。这种不保护 bootloader 的 ROM,也是醉了,真香……已经过保,也不想恢复官方 ROM,直接刷 BREED,再刷 OpenWRT 18.06.5。

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
BusyBox v1.22.1 (2018-03-10 04:32:13 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

***********************************************************
__ __ _ _ ____ _ TM
/ / / / (_) _ __ (_) / __/ (_)
/ /_/ / / / | | /| / / / / / /_ / /
/ __ / / / | |/ |/ / / / / __/ / /
/_/ /_/ /_/ |__/|__/ /_/ /_/ /_/
http://www.hiwifi.com/
***********************************************************
root@Hiwifi:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "hw_panic"
mtd2: 00010000 00010000 "Factory"
mtd3: 00020000 00010000 "oem"
mtd4: 00010000 00010000 "bdinfo"
mtd5: 00010000 00010000 "backup"
mtd6: 00f70000 00010000 "firmware"
mtd7: 00120000 00010000 "kernel"
mtd8: 00e50000 00010000 "rootfs"
mtd9: 00380000 00010000 "rootfs_data"
root@Hiwifi:~# mtd unlock u-boot
Unlocking u-boot ...
root@Hiwifi:~# cd /tmp
root@Hiwifi:/tmp# mtd write breed-mt7620-hiwifi-hc5861.bin u-boot
Unlocking u-boot ...

Writing from breed-mt7620-hiwifi-hc5861.bin to u-boot ...
[e:0] [w0]
[e:1] [w1]

BREED 信息:

CPU MediaTek MT7620A ver 2, eco 6
内存 128MB DDR2
Flash Winbond W25Q128 @ 24MHz (16MB)
以太网 MediaTek MT7620A built-in 5-port 10/100M switch
时钟频率 CPU: 580MHz, Bus: 193MHz
编译日期 2018-12-29 [git-135bed9]
版本 1.1 (r1266)

嗯……这款路由器就是骗钱的。

Lenovo Y1S

这款最简单,直接捅菊花进官方恢复模式,刷这个文件:https://breed.hackpascal.net/breed-mt7620-lenovo-y1s.bin

Newifi D1

先官方 ROM 降级:xCloudOS_newifi-d1_Build20150922_v0.0.4.3500_beta_sign.bin 或更早的 xCloudOS_newifi-d1_Build_v0.0.4.2100_beta_sign.bin,自寻下载。

较老的版本可能和 Y1S 一样可以直接在恢复模式下刷,不过 UMU 忘记这样尝试。

0.0.4.3500, r33798 的版本,布局如下:

1
2
3
4
5
6
7
8
9
10
11
# cat /proc/mtd
dev: size erasesize name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "Factory"
mtd3: 02000000 00010000 "fullflash"
mtd4: 01fb0000 00010000 "firmware"
mtd5: 0012a926 00010000 "kernel"
mtd6: 01e656da 00010000 "rootfs"
mtd7: 01080000 00010000 "rootfs_data"
mtd8: 00020000 00010000 "panic_oops"

网上的刷机教程如下:

1
2
3
4
5
6
cd /tmp
wget https://breed.hackpascal.net/breed-mt7621-newifi-d1.bin --no-check-certificate
dd if=/dev/zero bs=1024 count=192 | tr "\000" "\377" >breed_192.bin
dd if=breed-mt7621-newifi-d1.bin of=breed_192.bin conv=notrunc
cat /tmp/breed_192.bin /dev/mtd1 /dev/mtd2 /dev/mtd4 >fullflash_with_breed.bin
mtd write fullflash_with_breed.bin fullflash

原理:u-boot 分区不能直接刷,但 fullflash 分区可以刷,fullflash 其实包含了 u-boot。

fullflash = u-boot + u-boot-env + firmware

以上命令就是组合成一个适合刷到 fullflash 的文件,而且是用 BREED 覆盖了 u-boot,然后刷到 fullflash,这样 u-boot 就被覆盖了,其它分区还是原来的内容。

值得注意的是:刷完 BREED,捅菊花的位置变了,不再是捅原来的菊花……而是天线下方那个红十字按钮,这原是用于 WPS 的。

Newifi D2

访问 http://192.168.99.1/newifi/ifiwen_hss.html 开启 SSHD,查看分区布局:

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
BusyBox v1.24.1 (2018-02-27 16:23:44 CST) built-in shell (ash)


_______________________________________________________________
| ____ _ ____ |
| | _ \ __ _ _ __ __| | ___ _ __ __ _| __ ) _____ __ |
| | |_) / _` | '_ \ / _` |/ _ \| '__/ _` | _ \ / _ \ \/ / |
| | __/ (_| | | | | (_| | (_) | | | (_| | |_) | (_) > < |
| |_| \__,_|_| |_|\__,_|\___/|_| \__,_|____/ \___/_/\_\ |
| |
| PandoraBox SDK Platform |
| The Core of SmartRouter |
| Copyright 2013-2016 D-Team Technology Co.,Ltd.SZ |
| http://www.pandorabox.org.cn |
|______________________________________________________________|
Base on OpenWrt BARRIER BREAKER (3.2.1.7418, 2018-03-06-git-bbccda9)
#cat /proc/mtd
dev: size erasesize name
mtd0: 00010000 00010000 "u-boot-env"
mtd1: 00010000 00010000 "Factory"
mtd2: 01fb0000 00010000 "firmware"
mtd3: 00146bf9 00010000 "kernel"
mtd4: 01e49407 00010000 "rootfs"
mtd5: 00d40000 00010000 "rootfs_data"
mtd6: 00020000 00010000 "panic_oops"
mtd7: 00010000 00010000 "nvram"

这是被隐藏掉两个分区的!

高端刷法,是用一个内核模块来刷的,自寻 newifi-d2-jail-break.ko,参考文章:https://www.right.com.cn/forum/thread-365936-1-1.html

按以上链接刷好是 1.1 (r1237) 版,进 BREED 刷最新 BREED:https://breed.hackpascal.net/breed-mt7621-newifi-d2.bin

信息为:

CPU MediaTek MT7621A ver 1, eco 3
内存 512MB DDR3
Flash Winbond W25Q256 @ 48MHz (32MB)
以太网 MediaTek MT7530 Gigabit switch
时钟频率 CPU: 880MHz, DDR: 1066MHz, Bus: 293MHz, Ref: 40MHz
编译日期 2018-12-29 [git-135bed9]
版本 1.1 (r1266)

八哥之神前传【5】

2042 年

第二天凌晨 4 点多,圣小开一个翻身醒来,死神坐在床边……

圣小开以为是在做梦,便出脚踢死神,没想到落空了,但是也就清醒过来,原来不是做梦,是产生幻觉!

圣小开惊悚地想:“完蛋!生命遭到威胁,难道寿命大限快到了?”

恐惧了 3 秒……“赶紧睡吧,死在梦里舒服些!”

清晨,稣在杏林豪华酒店出来,发现刚下过雨,地上湿滑。酒店在山脚下,地势较高,要下很多台阶,才能去找贾总。

于是干脆穿个旱冰鞋就滑下来。滑了很久后,天又黑了,居然来到一片田野。四周都是高山,顺着泥路往东走,就来到盐田。盐田有很多黑乎乎的深井。

稣开始怀疑人生,这地方好像来过,小时候住在岛中央,往西走是盐田阻碍,往东走是田野阻碍,虽然后来都明白,这些只是小东西,很容易就走出去的,但小时候就是走不出去,仿佛被它们困住,外围的高山也是触不及的存在,曾经以为他们是世界的尽头。为什么这些场景,突然把稣困住?

几个老妇人从东边走来。稣心想:这地方居然有人,不会又是什么妖魔鬼怪吧!

只见老妇人越来越近,原来是挑水要去浇菜,看到稣,主动说:“年轻人,这里出不去,就和我一样,挑水种菜,过着田园生活吧!”

稣呵呵一笑:“什么年轻人?老夫 60 岁了!这样的生活好无聊,稣还是原路返回吧!”

另一个老妇人也呵呵大笑:“回不去啦!我们也不愿意呀……回不去,回不去!”

叮叮叮!一阵闹钟把稣拉回床上!好险,还好可以吓醒。

贾力劣别墅

坐车去找贾总的路上发现,他的别墅就是在一片田野里,不过好在路是水泥路,杂草、农作物也没有梦里那么狰狞。

虽然如此圣小开的内心还是不得安宁。

此处省略无数对精英阶层别墅的描述和赞叹,尤其是那位日本籍女佣,简直无法言喻,只能用“咻咻咻”形容,好像前几天联网玩 S6x 游戏的那个萝莉……这个 S6x 系统正是贾力劣投资的项目,果然赚了好多钱。

贾力劣:“开哥,喜欢她?送一个给你?”

圣小开:“送?难道她是机器人?”

贾力劣:“是呀!”

贾力劣:“真像!有时候劣者怀疑大家都是机器人……”

贾力劣:“哈,开哥真爱开玩笑。不过你为何脸色不太好?”

圣小开:“是应该很差,劣者已经打过镇定剂才保持还好的!”

贾力劣:“赫赫,哥又开玩笑了!”

圣小开:“还真开不得玩笑……昨天去见齐总,想起一些不属于这个世界的事情。”

贾力劣:“哦?难道你也发病了!”

圣小开:“也?还有谁?”

贾力劣:“可不就是齐总,他可能被关出抑郁症,产生幻觉,然后感染了刘佾,现在又感染你。”

圣小开心想:“学长一点抑郁迹象都没有,而且经过锻炼,各方面比以前更积极向上,怎么会是病?肯定是贾总有问题。”于是话题一转,“贾总,还记得黄金灯吗?”

贾力劣:“嗯?我不认识这号人物呀!”

圣小开:“怎么会呢?你们打过架的。”

贾力劣:“开哥,我看你病的不清啊!你看我的职业是法官、投资人、教育家,会和人打架?”

圣小开:“你是不是信基督?”

贾力劣:“是啊,我们信基督的,讲究和平、和睦、和谐,怎么会打架?”

2047 年,非正常人类研究中心

黄金灯:“小开先生,为何不少人称呼你为稣呀?”

稣:“自从成年后,劣者一直是信道的。多年前,劣者认识一群基督教徒,他们说不信基督就是异端,要下地狱。好吧,作为坚定的道生,劣者选择下地狱。但是佛教徒又说地狱其实是地藏王管的,是他们佛教的地盘。劣者内牛满面,连下地狱都不行?咳,没办法,谁让咱们道生太老实了。劣者想起老子化胡为佛的故事,于是给自己取了一个名字叫做‘稣’。”

黄金灯:“这样呀!大部分基督徒还是蛮和谐的,也有一些比较过分,非要强迫我信。”

稣:“哈,是的,贾总就是基督徒,我看他还好。”

黄金灯:“好啥呀,他是被我打过才改正的!”

稣:“咦?大师为何打他?”

黄金灯:“我在这里信徒多,时不时就有人来让我改信其它宗教。但咱们是讲科学的人,有哪种信仰能像道这么科学的?佛祖号称慧眼观遍三界,他有提出啥科学知识吗?没有,除了一句‘一滴水有三千虫’,瞎蒙点道理之外,几乎没有什么拿得出手的理论。佛和基督也只是劝人向善这点有些积极意义,其它的邪教就很可怕了……”

稣:“信仰不同而已,可以兼容嘛!”

黄金灯:“当然可以,但是有些人说我是神经病,要强行给我洗脑,冷不防进行爱的感化教育,我要是不做点什么,表个态,他们都以为我好欺负!”

稣:“所以,你打了贾总?”

黄金灯:“是的,他看起来最弱,我出手后,果然如此。换成其他人,我没把握能打赢!”

稣:“原来如此!看来上健身房练练肌肉是有用的!”

2042 年,贾力劣别墅

贾力劣:“奇了个怪!你这么说,我还真有点印象!”

圣小开:“咳,还以为你要抵赖!”

贾力劣:“这是怎么回事?你讲这故事之前,我一点印象都没有,你讲着讲着,我突然就想起来,好像这记忆是刚刚被注入!”

圣小开心想:“嗯?他也是突然才想起来?是不是装的,得再试探试探。”圣小开提高音量,义正言辞地说:“贾力劣!你想起自己干的坏事了吗?”

2047 年,养老院

圣小开:“学长,劣者发现这个养老院的安乐死服务有古怪!”

齐凤卿:“我隐约也感觉不对劲。你是怎么发现的?”

圣小开:“劣者一直纳闷砂砂研究意识和记忆复制的那些人脑是哪里来的,她很少有事隐瞒,所以劣者自己调查了一番,大概可以推断出来源就是自愿安乐死的人。”

齐凤卿:“这不是挺好的?”

圣小开:“劣者听黄金灯说过养老院的很多人都是愿意死后捐赠遗体的,这里有个前提就是大家都将死亡定义为脑死,捐献的是遗体,并不包含能够用于研究意识、记忆的活脑。只有那些想安乐死的人才可能有活脑,问题是有人愿意把活脑捐出去?”

齐凤卿:“我是不愿意,很可能遭受惨绝人道、灭绝人性的科学研究……想想就吓出一身冷汗!”

圣小开:“以劣者愚见,这里的人都很聪明,应该没人愿意!除非技术已经成熟,大家可以享受到无风险服务。”

齐凤卿:“是的。不过话说回来,前几天孙朝穆告诉我,针对猴子的自身克隆体换脑术已经成熟,人类应该很快能享受恢复青春的美妙体验。”

圣小开:“这么说来应该更没人愿意捐献活脑了!即使一心求死的人,也没有理由捐,要是被试验得半死不活又永陷孤独与黑暗,不是哑巴吃黄连,比神话中说的十八层地狱、下油锅啥的还可怕。劣者严重怀疑,养老院是借安乐死之名非法取活脑!”

八哥之神前传【4】

2047 年,养老院

有一天齐凤卿找到稣传话:“我们那个富二代同学贾力劣投资一家高科技的养老院,你有兴趣过来一起研究研究吗?”

稣:“养老院?学长别开玩笑了,劣者为何不住自己家?”

真实世界是叫学长,月球脑联网世界是叫师兄。

齐凤卿:“在家里太无聊,养老院有不少同学,你前妻也在这边。而且还有前沿技术研究所,我们可以自由自主搞研究。”

稣:“什么!这么牛逼的养老院肯定很贵吧,说出来让劣者哭一下。”

齐凤卿:“赫赫,以哥和贾总的关系,会坑你吗?当然是免费的。”

稣:“哦?劣者和他关系一般,而且几十年没联系的,他会这么好心?”

齐凤卿:“你忘记他钱多得没地方花吗?我们都在这边生活一年多了,贾总和周老师是大老板,你还不放心?”

稣:“周老师!他居然还活着……劣者倒要去会会他。”

虎纠一小县城有一个神经精神病防治院,院里最靠后山的一栋楼是非正常人类研究中心,中心内有一名神人,名唤黄金灯,自称领悟宇宙真理,信徒众多。

防治院隔着一条路的斜对面就是养老院。2047 年,稣退休后,在院长贾力劣的号(hu)召(you)下,和一群同学住进养老院。

稣刚到养老院时,与周老师的会面就在黄金灯的演讲会上。周老师聚精会神地听讲,稣坐在他身旁跟着听起来。

没有钴、镍、铜、锌、锡、碘等人类必须的微量元素,人类将无法生存。

比如铜元素在线粒体上的电子传递链起到关键作用,电子传递给氧气的最后一步需要细胞色素氧化酶复合体中铜离子的作用,可以说没有铜元素,就没有有氧呼吸,好氧生命也将不存在。

没有锌、镓、银、钨、金、汞、铅、铀等,也将没有第二次工业革命,人类文明无法向高等发展。

生命的演化过程少不了这些重元素的参与,地球上的 94 种自然元素是地球生命能进化到第三次信息革命的基础。而超新星是宇宙中重元素的来源。地球上排在铁之后的元素,都是超新星爆发时产生的。所以超新星是真正的生命摇篮,恒星的演化末期,却是生命的开端。

但超新星爆发同样可能扼杀生命。

稣:“周老师好,刚才的演讲您应该早就懂了,为什么还听得津津有味?”

周易:“小开,乐趣不仅限于思考新的东西,优美的乐曲可以反复欣赏,不是吗?”

贾力劣:“是的。这里的信徒都认为超新星是上帝用来创造生命的灯,生命已经被迭代过很多次,每次调试发现缺乏某种元素会导致某种智障,就重来一遍,最终凑齐 94 种自然元素。”

贾力劣信耶稣。

稣:“然后呢?集齐 94 中元素,才有资格去见造物神吗?”

稣信太上道。

周易:“哈哈哈,一种生命的智能程度要发达到可以跳脱虚幻去见外层造物神并没有那么容易,当今的人类还无法做到。但这是我们的研究方向。”

稣:“难道……我们在这里的真正目的是……”

贾力劣:“没错!我们都是快去见上帝的人。所以急迫地想研究出一种方法,可以活着见到上帝。”

稣:“哦!原来是召集我们一起写科幻小说!那陈砂砂应该对这不感兴趣,她怎么也来了?”

周易:“赫赫,我们是认真地做科研。她研究的是人脑的复制,是很关键的基础。”

2042 年,监狱

圣小开一顿艰难地回忆,痛苦地低吟:“不可能,时间错乱了!”

齐凤卿:“开,我都记起来了,我亲眼看着你被取脑。原来他们要先取我的脑的,是你建议他们先取你,给我争取时间记下这些事。”

圣小开:“这更不可能了,劣者不记得自己这么英勇,还能舍己救人?开什么玩笑!再说,换个顺序能改变什么?劣者是让师兄逃跑吧!”

齐凤卿:“这我也不明白,可能你不敢看吧,反正我当时被感动了。”

圣小开:“哈哈哈哈哈,其实劣者乃是创世邪灵,在宇宙无尽轮回,这些生生死死都是小事,师兄不用放在心上。”

齐凤卿:“嗯,你当时和我说的,我还记得。我们生于无穷嵌套的宇宙牢笼,这里的每一个人都是一个平行宇宙,一个人死了,只是他的宇宙毁灭,其它人的宇宙还好好的。”

圣小开:“每个灵魂都会在每个肉身轮换,可以演过自己死后,下辈子却是演自己的父母!这种邪说,你也信?”

齐凤卿:“总之宇宙真奇妙!也许你转世到贾总身上就能发现真相。”

迷惑于宇宙,形累不知太初。

精神无始,冥乎无有。

圣小开:“原来线索在他身上,看来要冒险和他撕逼了!”

齐凤卿:“开,此去可能凶多吉少!”

圣小开:“死过很多次了,反正还会复活,无所谓。”

齐凤卿:“啥时候这么豁达了,你不是一向觉得记忆丢失很可惜吗?以后兄弟相见不相识,不是挺凄凉的?”

圣小开:“劣者现在有新的领悟,反复以低级的形式生存更可怕,被奴役却无法死亡更可怕。”

齐凤卿:“我们现在不就被控制着?记忆可能被消除,也可能被植入,无法分辨真假。”

圣小开:“超脱这个世界的时候到了!”

How to empty an array in JavaScript?

When I write pathfinding codes in JavaScript, I ran into this problem: how to empty the array?

Methods

  • Method 1
1
array = []
  • Method 2
1
array.length = 0
  • Method 3
1
array.splice(0, array.length)
  • Method 4
1
2
3
while (array.length > 0) {
array.pop()
}

Difference between Method 1 and the others

Method 1 only reassign a:

1
2
3
4
5
6
7
8
let a = [1, 2, 3]
let b = a

// empty a, but doesn't affect b
a = []

console.log('a =', a)
console.log('b =', b)

Method 2, 3, 4, will empty multiple variables referencing the same object:

1
2
3
4
5
6
7
8
let a = [1, 2, 3]
let b = a

// empty a and b
a.length = 0

console.log('a =', a)
console.log('b =', b)

More

See https://github.com/UMU618/js-empty-array#example

跟 UMU 一起玩 OpenWRT(入门篇15):ip-tiny 和 ip-full 的区别

起源

今天看到有网文《iptables+tproxy实现ss-redir的UDP转发的方法》说:“OpenWrt 做 UDP 转发需要的依赖是:iptables-mod-tproxy, kmod-ipt-tproxy 和 ip-full”。使用 opkg install ip 安装的默认是 ip-tiny,一般情况下都是够用的,不禁想弄明白两者有何区别。

探索

ip 命令对比测试:

  • ip-tiny
1
2
3
OBJECT := { link | address | route | rule | neigh | tunnel | maddress |
mroute | mrule | monitor | netns | macsec | token | ila |
vrf | sr }
  • ip-full
1
2
3
4
OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |
vrf | sr }

即 ip-full 多了这些对象: addrlabel | ntable | tuntap | xfrm | l2tp | fou | tcp_metrics | netconf。举个例子,只安装 ip-tiny 时,运行 ip xfrm 报错如下:

Object “xfrm” is unknown, try “ip help”.

相关知识:

xfrm is an IP framework for transforming packets (such as encrypting
their payloads). This framework is used to implement the IPsec
protocol suite (with the state object operating on the Security
Association Database, and the policy object operating on the Security
Policy Database). It is also used for the IP Payload Compression
Protocol and features of Mobile IPv6.

结论

实际上,转发普通 UDP 包,并不需要 ip-full,ip-tiny 即可。

强制 body-parser 解析无 Content-Type 请求

需求

原版 EOS 历史 API 插件将数据都保存在内存,随着历史数据越来越多,内存消耗高达 T 级以上,使得这个插件失去实用性。于是出现很多替代产品,比如把数据同步到 MongoDB,然后用 Nodejs 对接 MongoDB 来实现 API 服务。

2019 年 3 月份,MEET.ONE 实现了一个基于 MongoDB 的 EOS 历史 API 服务。劣者将去掉 MongoDB 交互部分的框架开源于 UMU618/eos-history-api-service

测试

这个 API 服务的开发者是公司另一名 Web 全栈开发,他测试通过之后,劣者用 cleos 一试,立马 bug!调试后端代码,发现 req.body 不是一个 JSON 对象。

劣者立刻用 tcpdump 抓包,发现 cleos 发出去的包并无异常,body 就是一段 JSON 数据。

交流后,发现测试工具的差异:劣者是 C++ 开发,自然而然使用 cleos 测试,而 Web 全栈开发对 cleos 比较陌生,他们会选择 postman 或者自己写测试性客户端。比如:

1
2
3
4
5
6
7
const request = require('request-json')
const client = request.createClient('http://127.0.0.1:8888/')

const json = {"id": "d5245026c757532ea3dd5b3a02a07620eb7238113d0a49cae5ebb93921a34135"};
client.post('/v1/history/get_transaction', json, function(err, res, body) {
console.log(res.statusCode, body)
})

后来劣者写了一个简易的 Web 服务器,显示请求头。

1
2
3
4
5
6
7
8
9
10
11
12
13
const http = require('http')

http.createServer(function (req, res) {
let buffer = req.method + ' ' + req.url + ' ' + req.httpVersion
console.log(buffer)
res.write(buffer + '\r\n')
for (let i = 0; i < req.rawHeaders.length; i += 2) {
buffer = req.rawHeaders[i] + ': ' + req.rawHeaders[i + 1]
console.log(buffer)
res.write(buffer + '\r\n')
}
res.end()
}).listen(8888)

经对比,cleos 发的请求不带 Content-Type。cleos 是 EOSIO 的官方工具,使用者众多,若不支持它是不合理的,后端也不能要求客户端都带上 Content-Type。

调试

检查后端代码,其对 body 的解析是用 body-parser 完成的:

1
app.use(bodyParser.json())

使用以下命令启动服务:

1
DEBUG=body-parser:* node app.js

发现有这样 2 行关键的调试信息:

1
2
body-parser:json content-type undefined +0ms
body-parser:json skip parsing +1ms

原来 body-parser 会检查 Content-Type,不符合它的预期,就不解析,于是 body 就不是 JSON 对象。

开发

暴力的解决方案

参考《Express 解析 json 格式 post 数据》后,我们这样解决:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 显式调用 JSON.parse 强行解析
app.use((req, res, next) => {
req.rawBody = ''
req.on('data', (chunk) => {
req.rawBody += chunk
})
req.on('end', () => {
try {
req.body = JSON.parse(req.rawBody)
} catch (err) {
req.body = null
}
next()
})
})

但劣者认为以上方案比较不优雅,JavaScript 作为一门高级语言,我们希望更多专注于业务逻辑,尽量复用现有代码,少自己写工具性代码。下面探讨使用 body-parser 的解法。

优雅的解决方案

劣者希望能告诉 body-parser 遇到不传 Content-Type 依然当它是 JSON 去解析。于是这就得去看它的代码!我们从上面关键的调试信息入手,可以很快发现:

1
2
3
4
5
6
// determine if request should be parsed
if (!shouldParse(req)) {
debug('skip parsing')
next()
return
}

而 shouldParse 是可以由传入的选项影响的:

1
2
3
4
5
6
7
8
9
10
11
12
function json (options) {
var opts = options || {}
// 省略部分无关代码
var type = opts.type || 'application/json'
// 省略部分无关代码

// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type
// 省略部分无关代码
}

于是最终的解决方案是:如果不传 Content-Type,当做 application/json;但如果有传,那得传对,否则也是不理。效果上,比之前无脑地当成 application/json,稍微好一些。实现上,则更优雅。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
// Force body-parser to parse data as JSON
const bodyParser = require('body-parser')
const typeis = require('type-is')

app.use(bodyParser.json({ type: function(req) {
if (undefined === req.headers['content-type']) {
// cleos POST data without content-type
return true
} else {
return Boolean(typeis(req, 'application/json'))
}
}}))

(完)

八哥之神前传【3】

AVILab

孙朝穆:“周老师的案例预示了我们当前技术的局限性。”

陈立姻:“是呀。人脑的寿命也是有限的,自然寿命才 185 年,现在的科技也只能延长到 800 年左右。”

孙朝穆:“必须研发新方案取代目前无脑人体装旧脑的方案!”

陈立姻:“复制猪脑的实验已经成功过几个案例,但无法验证复制出来的是不是同一只猪!人脑复制目前还没成功案例,很快死刑就要完全废止,到时候更难找到测试的志愿者。”

猪坚强。人娇嫩。

孙朝穆:“在下一直怀疑,复制过程中旧脑死亡,是无聊死或绝望死的。”

陈立姻:“有可能,之前你怀疑是吓死的,我们使用镇定剂后,持续时间变长了。”

圣小开加入对话:“两位大神在聊猪肉涨价吗?”

陈立姻:“死开,你耳朵越来越不好了……要不要给你换一个新耳朵?”

圣小开:“哟!这耳朵确实已经很乐射了,不过倒是清净,不换也罢。”

孙朝穆:“开哥!我们正在聊复制人脑,但最近都没有志愿者做实验,伤脑筋呢!”

圣小开:“哦……原来又在聊玩死,咳,人的科学实验!你们听过降落伞故障率如何降低的故事吗?”

孙朝穆:“哥又开玩笑了,我可没法给自己复制。”

圣小开:“孙总愿意献身的话,还不容易,让姻姻姐帮你。”

陈立姻:“少开玩笑,这个问题很严肃,目前形势也不容乐观。”

圣小开:“真不懂幽默,那些人都是被你们死板无聊的复制体验给憋死的,复制时让他们进识界玩玩 S6x 游戏,劣者就不信他们会想死。”

孙朝穆:“Diang!开哥果然英明,激起他们的性趣和求生欲,这是个不错的方向。”

陈立姻:“嗯?你们又在酝酿污的想法!”

圣小开:“耶!失去繁殖生命的冲动,和死有啥两样,激情,激情,你们懂吗?怎么感觉量子计算机创造的识界比你们人类还懂生命的意义?”

孙朝穆:“立姻姐,开哥说的可能就是解题关键。我们得把重心放在完善人脑全维度接入识界,然后找个志愿者试验新的复制方式。”

陈立姻:“哦哦,那我研究一下早期休眠停止发育的脑,如何在重新激活发育的过程中改写。”

孙朝穆:“对了,开哥,我们刚去看过凤哥,他想见你。”

圣小开:“嗯,是时候给你们找个志愿者了!”

孙朝穆:“啊?开哥,你想干嘛?”

圣小开:“凤哥不是很喜欢识界吗?劣者劝他移民识界算了,也省得蹲监狱。”

孙朝穆:“哦,有道理!去吧。”

监狱

齐凤卿:开,快进来坐。

圣小开:师兄,您怎么变帅了!那不是死不了了?

齐凤卿:什么死不了?人生 70 才开始。我在这边经常健身,也不熬夜了,身体比以前好很多。

圣小开:哦。小弟才 60。是说观众比较讨厌丑角,所以一般导演会让反派画一些妖异傻帽的妆,心理暗示观众诅咒他们早点挂掉。

齐凤卿:又开玩笑了。你觉得我是反派?

圣小开:当然不是。本剧最大的反派还没登场呢。

齐凤卿:嗯?难道你也预知到自己的劫数?

圣小开:是的,有些不明真相的人会搞破坏,咱们迟早会被害死。

齐凤卿:想必你没阻止我在识界大肆破坏,也是认清了这个世界的本质。

圣小开:是的,我们身处的世界和那个虚拟的识界其实没有本质区别。站在宇宙的角度看,毁灭和保护生灵,何者才是宇宙的意志?

齐凤卿:宇宙给人类自由主义的幻觉,人类会认为保护生灵才是真理。

圣小开:劣者并不认为哪者更正确,历史上那么多次战争,哪一次高维神明会出来阻止?杀累了,人类自己会回归和平。静静地观测才是劣者的设定。

齐凤卿:原来你认为自己是神……

圣小开:还不是,劣者只是用自然的角度思考问题而已。并且这场战争也不全是师兄造成的,识界本身就已经到了大战的临界点。不然委员会也不会只派两人走过场,还是一个想救,一个不想救的组合。而且大家判师兄入狱,一样是走过场,只是回收你的特权,关六个月后,不再限制你的人身自由。

齐凤卿:可惜刘佾不明白。

圣小开:师姐确实慈悲为怀……这是最厉害的杀器。

齐凤卿:不谈她了,我最近想明白很多事情。

圣小开:是不是委员会里有人想除掉咱们俩?

齐凤卿:虽然也有同感,但我想说的比这个更严重。是关于养老院的秘密。

投资必懂的市场理论

郁金香泡沫 (Tulip Bubble)

郁金香泡沫,又称郁金香效应,1636 年荷兰的郁金香投机是有据可查的人类历史上最早的泡沫经济案例。

在 1634 年以前,郁金香和其他花卉一样是由花农种植并直接经销的,价格波动的幅度并不大。在 1634 年底,荷兰的郁金香商人们组成了一种类似产业行会的组织(College),基本上控制了郁金香的交易市场。这个行会强行规定:任何郁金香买卖都必须要向行会缴纳费用。

1636 年底,荷兰郁金香市场上不仅买卖已经收获的郁金香球茎,而且还提前买卖在 1637 年将要收获的球茎。由于郁金香的需求上升,推动其价格上升,人们普遍看好郁金香的交易前景,纷纷投资购入郁金香合同。这是期货交易的雏形。

郁金香的交易被相对集中起来之后,买卖双方的信息得以迅速流通,交易成本被大大降低。在这个期货市场上没有很明确的规则,对买卖双方都没有什么具体约束。郁金香合同很容易被买进再卖出,在很短的时间内几经易手。这就使得商人们有可能在期货市场上翻云覆雨,买空卖空。在多次转手过程中,郁金香价格也被节节拔高。

在行会的控制和操纵之下,郁金香的价格被迅速抬了起来。买卖郁金香使得一些人获得了暴利。郁金香价格暴涨吸引了许多人从欧洲各地赶到荷兰,他们带来了大量资金。外国资本大量流入荷兰,给郁金香交易火上浇油。

1637 年新年前后,郁金香的期货合同在荷兰小酒店中被炒得热火朝天。到了 1637 年 2 月,倒买倒卖的人逐渐意识到郁金香交货的时间就快要到了。一旦把郁金香的球茎种到地里,也就很难再转手买卖。人们开始怀疑,花这么大的价钱买来的郁金香球茎就是开出花来到底能值多少钱?前不久还奇货可居的郁金香合同一下子就变成了烫手的山芋。持有郁金香合同的人宁可少要点价钱也要抛给别人。在人们信心动摇之后,郁金香价格立刻就开始下降。价格下降导致人们进一步丧失对郁金香市场的信心。持有郁金香合同的人迫不及待地要脱手,可是,在这个关头很难找到“傻瓜”。恶性循环的结果导致郁金香市场全线崩溃。

郁金香泡沫的高峰期仅仅持续了一个多月。由于许多郁金香合同在短时间内已经多次转手买卖且尚未交割完毕,最后一个持有郁金香合同的人开始向前面一个卖主追讨货款。这个人又向前面的人索债。荷兰的郁金香市场从昔日的景气场面顿时间变成了凄风苦雨和逼债逃债的地狱。

现在 00 后炒鞋就和以前荷兰人炒郁金香一样,鞋穿不炒。

幸存者偏差 (Survivorship Bias)

幸存者偏差是指当取得资讯的渠道仅来自于幸存者时(因为死人不会说话),此资讯可能会存在与实际情况不同的偏差。

此规律也适用于金融和商业领域。存活下来的企业往往被视为“传奇”,它们的做法被争相效仿。而其实有些也许只是因为偶然原因幸存下来而已。

在鞋圈、币圈,最明显的例子就是“我炒鞋赚大钱”或者“我一个朋友炒币亏得倾家荡产”等等。不管你的朋友和你关系如何好,如何值得信任和尊重,在客观规律面前他们都是等同的。市场不会因为你的喜好而照顾或者偏袒你的亲朋。

最近火热的炒鞋,收益翻倍的同样是少数幸存者。其实炒鞋历史悠久,最近才进入大众视野,为的就是大面积收割。

双盲实验和详细全面客观的数据纪录都是应对“幸存者偏差”的良方。所谓“兼听则明”也是这个道理,抛掉对个案的迷信,全面系统的了解才能克服这个偏差。

帕累托二八法则 (The Pareto Principle or The 80/20 Rule)

80/20 法则(The 80/20 Rule)又称为帕累托法则(Pareto Principle)、二八定律、帕累托定律、最省力法则、不平衡原则、犹太法则、马特莱法则。生活中大多数事情不是均匀分布的,大多数结果来自少数投入:

  • 某个软件的 80% 代码只占总分配时间的 20%(相反,最难的 20% 代码部分占用 80% 的时间)
  • 20% 的努力产生 80% 的结果
  • 20% 的工作创造 80% 的收入
  • 20% 的错误导致 80% 的崩溃
  • 20% 的功能导致 80% 的使用量

此法则是由美国罗马尼亚工程师约瑟夫·朱兰(Joseph M. Juran)博士根据维尔弗雷多·帕累托当年对意大利 20% 的人口拥有 80% 的财产的观察而推论出来的。约瑟夫·朱兰是举世公认的现代质量控制之父,他在 20 世纪 40 年代,开始将帕累托法则应用于质量问题。

炒股、炒币、炒鞋,赚大钱的都是少数人。

格雷欣法则 (Gresham’s Law)

400 多年前,英国经济学家格雷欣发现了一有趣现象,两种实际价值不同而名义价值相同的货币同时流通时,实际价值较高的货币,即良币,必然退出流通——它们被收藏、熔化或被输出国外;实际价值较低的货币,即劣币,则充斥市场。人们称之为格雷欣法则,亦称之为劣币驱逐良币规律

格雷欣法则在现代企业薪酬方面改革的贡献尤为突出。而在币圈,我们看的是格雷欣法则的逆反现象,因为数字货币是由信仰定义价值,没有国家或法律力量维系,所以劣币不仅无法驱逐良币,最终还会反被良币消灭。

破窗效应 (Break Pane Law; Broken windows theory)

环境中的不良现象如果被放任存在,会诱使人们仿效,甚至变本加厉。

生活中的例子:路边角落有些许纸屑,如果无人清理,不久后就会有更多垃圾,最终沦为垃圾堆。

破窗效应常出现于股票市场、社区治理,币圈自然也常见。

名人效应

粉丝容易因为信任名人而成为韭菜。但名人效应有时候会逐渐减弱,甚至在某些方面他们会完全没有效应。

破解名人效应的方法是独立思考。《大般涅槃经》有云:依法不依人,依义不依语,依智不依识。不因为他是名人、大师就信以为真。不因为符合逻辑或自己的观念,就信以为真。

这里讲一个寓言故事:

蝎子要过河,对身边不远处的青蛙说:“我想过河,但不会游泳,你可以背我过去吗?”

青蛙回答:“不行。你有个毒钩子,如果我背你到河心,你蜇我,那我岂不是死翘翘!”

听完青蛙的话,蝎子哈哈大笑:“不会的!我要是蜇死你,自己也会落水淹死。”

青蛙一想也是,就背起蝎子。当他们游到河心时,青蛙突然感应背上一阵撕心裂肺的痛,接着便四肢发麻。青蛙用最后的力气问道:“你想自杀?”

蝎子答道:“谁想自杀呀?我蜇你完全是出于下意识。”说完,这两个家伙双双沉入河底。

逻辑只在理性时有效,而下意识往往能战胜理性。在币圈,保持冷静和有意识主动控制情绪是必须的。

“Those whom God wishes to destroy, he first makes mad.” ——Euripides

损失厌恶 (Loss aversion)

损失厌恶是指人们面对同样数量的收益和损失时,认为损失更加令他们难以忍受。同量的损失带来的负效用为同量收益的正效用的 2.5 倍。

一美元拍卖陷阱

一美元拍卖陷阱是著名博弈论专家,耶鲁大学教授马丁·舒比克(M.Shubik)设计的经典案例。

在某大型场合,拍卖人拿出 1 张 1 美元钞票,请大家给这张钞票开价,每次叫价的增幅以 5 美分为单位,出价最高者得到这张 1 美元,但出价最高和次高者都要向拍卖人支付出价数目的费用。

最终出价最高和次高者因为厌恶损失(Loss Aversion),导致越陷越深的沼泽陷阱。1 美元拍卖在哈佛大学、耶鲁大学等高校进行过多次实验,最终的报价在 20 到 66 美元之间。

在币圈,此理论是交易所常用的盈利手段。举个例子:上币。交易所可以规定,交 1000 万人民币直接上主站,如果没这么多钱,还有机会,每个月交易所从测试站多个竞争币中选择一个符合要求的上主站。这可能导致一美元拍卖陷阱,最终多个竞争币拼命竞争,最终交易所赚到不止 1000 万人民币。

囚徒困境 (Prisoner’s dilemma)

囚徒困境是博弈论的非零和博弈中具代表性的例子,反映个人最佳选择并非团体最佳选择。囚徒困境最早由美国普林斯顿大学数学家阿尔伯特·塔克(Albert tucker)1950年提出。他当时编了一个故事向斯坦福大学的一群心理学家们解释什么是博弈论,这个故事后来成为博弈论中最著名的案例。故事内容是:两个嫌疑犯(A和B)作案后被警察抓住,隔离审讯;警方的政策是“坦白从宽,抗拒从严”,如果两人都坦白则各判 8 年;如果一人坦白另一人不坦白,坦白的放出去,不坦白的判 10 年;如果都不坦白则因证据不足各判 1 年。

囚徒困境的主旨为,虽然囚徒们彼此合作,坚不吐实,可为全体带来最佳利益,但在资讯不明的情况下,因为出卖同伙可为自己带来利益(缩短刑期),也因为同伙把自己招出来可为他带来利益,因此彼此出卖虽违反最佳共同利益,反而是自己最大利益所在。

单次发生的囚徒困境,和多次重复的囚徒困境结果不会一样。在重复的囚徒困境中,博弈被反复地进行。因而每个参与者都有机会去“惩罚”另一个参与者前一回合的不合作行为。欺骗的动机可能被受到惩罚的威胁所克服,从而可能导向一个较好的、合作的结果。这时,合作可能会作为均衡的结果出现,称之为纳什均衡 (Nash Equilibrium)。作为反复接近无限的数量,纳什均衡趋向于帕累托最优

由囚徒困境可以想到类似的韭菜困境:大跌时,韭菜无法信任其它韭菜,纷纷割肉快跑。