Zhao Li https://livc.io 2018-07-03T13:47:45+00:00 livc@outlook.com 见字如面(一) https://livc.io/blog/227 2018-06-17T00:00:00+00:00 Zhao Li https://livc.io/blog/227 《见字如面》是最近在看的一个很喜欢的文化类综艺节目,每期邀请嘉宾朗读历史书信。现代社会很多人不读书、不写作,以书信为载体的文字更是很有可能会彻底消失。没人能够阻止时代的发展,但有些记忆注定让人记忆犹新,这里记录一些第一季中我喜欢的书信。

蔡琴写给杨德昌

这封信是歌手蔡琴写给台湾导演杨德昌的,被誉为“最佳放手信”。 二人十年无性婚姻后因杨德昌有其他爱人而离异。在得知杨德昌逝世后蔡琴发出感慨: “早知道他生命这么短暂,我应该早点放他离开。”

“杨德昌,你怎么可以就这样走了呢?”每个人对爱情的定义和理解不一样,有人选择了哀怨和仇恨,有人选择了宽恕和感激,这也是对待同一件事,完全不同的人生态度。

曹禺与黄永玉

这是来自戏剧作家曹禺和著名画家黄永玉的两封信, 曹禺晚年的作品不尽人意,黄永玉作为一个晚辈写信给他直言“我不喜欢你解放后的戏,一个也不喜欢”“你为势位所误!”,并希望他像萧伯纳,像伏尔泰那样,“到老还那么精确,那么不饶点滴,不饶自己”,“醒来啊马克白,把沉睡赶走!”

曹禺回信中承认自己“泥溷在不情愿的艺术创作中”,并认为他们之间的感情“丰满、美好、深挚、诚厚”。曹禺将这封批评信视为“不可数量的珍宝”,将其裱了起来。

现代社会很少听到批评的声音,尤其作为一个公众人物或艺术大家,在复杂的商业环境下,对待作品的退步也很少有人说出来。黄永玉的开诚布公和曹禺的虚心反思,诠释了何为“君子之交”。

《与韩荆州书》

《与韩荆州书》是李白写给唐朝政治人物韩朝宗的信,韩朝宗因为热心提拔青年才俊而受到大家推崇 ,但李白并没有得到韩朝宗的赏识,反而这封信成为名篇。

“生不用封万户侯,但愿一识韩荆州”“一登龙门,则声价十倍”,李白开篇很直接地拍了韩荆州的马屁,表达希望得到脱颖而出的机会。“白,陇西布衣,流落楚、汉。十五好剑术,遍干诸侯。三十成文章,历抵卿相。虽长不满七尺,而心雄万夫。”讲述身世,让人想起诸葛亮的“臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯”。

“必若接之以高宴,纵之以清谈,请日试万言,倚马可待”,“所以不归他人,而愿委身国士。傥急难有用,敢效微躯”,在说尽溜须拍马之词的同时,能够很明显地感受到李白压抑不住的豪情与潇洒,等不及地施展自己才华的心情。

韩荆州可能并不喜欢这个性格的人才,后来李白遇到贺知章,被推荐给唐玄宗,度过了最辉煌的翰林供奉的三年,所以千里马可能需要合适的伯乐。有人认为此文的谄媚和李白“诗仙”的形象不匹,是李白人生的一个败笔,我倒是觉得原来李白也和每个普通人一样,希望得到赏识和重用。书生意气、豪情万丈,这才是真正的李白。

《报孙会宗书》

这是一封西汉政治家、司马迁外孙杨恽写给好友孙会宗的信。孙劝他闭门思过、戒除骄奢淫逸,杨恽以嬉笑怒骂的口吻写此回信,批驳孙的规劝,并向当时的士大夫们表明“道不同,不相为谋”。

杨恽直言自己“材朽行秽,文质无所底”,“怀禄贪势,不能自退”,“君子游道,乐以忘忧;小人全躯,说以忘罪”,认为犯错后(杨恽之前因为拿皇上开玩笑获罪过)自己一直当个农民就挺好的,“长为农夫以末世矣”,觉得家中喝酒唱歌也是很正常的事。面对好友的规劝,杨恽最后写到“这正是大汉盛世,你去努力吧,跟你没话(方当盛汉之隆,愿勉旃,毋多谈)。”

这封信给我印象很深,乍一读有点无耻,锋芒毕露,仿佛明明白白地告诉你“我不做伪君子,我就是真小人”。但是仔细一想,这里面的人生观颇为有趣。中国古代历来主张忧国忧民的积极自由,却忽视了这种消极自由,就像有人认为人的一生就要做大事、赚大钱、实现梦想,有人则认为平平淡淡、自给自足的过完一生就很好,这是两种不同的人生态度,并无孰对孰错。中国主流文化一直在推崇积极自由,但消极自由也是人的权利和选择。

后有人告发杨恽骄奢的生活,抄家时发现了这封信,在意识形态比较统一的汉代,这种玩世不恭、反主流的消极态度并不会被允许,杨恽因此被腰斩,妻子被流放,孙也被罢官。

闻一多写给父母

1919 年,在清华读书的闻一多积极投身到五四运动中,这封写给父母的信记录了五四运动的细节和感受:

“唯独一帮学生敢冒天下之大不韪,起而抗之。虽于事无大济,然而其心可悲,其志可嘉,其勇可佩”,“一年没回家了,这一年家中又多变故,孩儿我又何尝不想回家看看你们。我留在这里为国家做事,不是说非得有我在国家才可以不亡,而是国家育养了这么多学生,每年花费巨万,一旦有事,学生如果不出力,更待谁人呢?而且孩儿我在学校中总被看做是深明大义的人,刚刚遇到这点儿事,就不能牺牲,难道还能谈什么爱国吗?”

值得一提的是,写这封信时闻一多只有 18 岁,在整个新文化运动时只有陈独秀是 70 后,鲁迅、胡适、傅斯年都是 80 后、90 后,而闻一多是 99 年的:一百年前的中国历史是由 80 后、90 后改变的,正是我们现在的年龄。

100 年前的文字今天读起来仍然铿锵有力,热血澎湃。国运不同,今天的我们可能不会有这样为民族奋起的机会,但不同的年代总有不同实现自我的方式,重要的是这个年纪的我们应该有担当的勇气。

《与高司谏书》

《与高司谏书》作于景祐三年(1036年)。当时主张改革政治的范仲淹因批评弊政,与宰相吕夷简发生冲突。吕夷简给范仲淹加上“越职言事,离间群臣,引用朋党”的罪名。范仲淹由此被贬饶州知州。这时,身为谏官的高若讷,面对范仲淹被贬的错误处置,非但不谏,反而落井下石,跟在吕夷简的后面诋毁范仲淹。欧阳修对此非常不满,于是写下这封信给高若讷。

欧阳修在这封信中真的是骂的非常痛快,让人无可遁形。信中指责高司谏“为言事之官,而俯仰默默,无异众人”,十四年多次怀疑他的人品最终得出结论:“今者推其实迹而较之,然后决知足下非君子也”,“足下在其位而不言,便当去之,无妨他人之堪其任者也”,“是足下不复知人间有羞耻事尔”,“若犹以谓希文不贤而当逐,则予今所言如此,乃是朋邪之人尔。愿足下直携此书于朝,使正予罪而诛之,使天下皆释然知希文之当逐,亦谏臣之一効也。”

在信中欧阳修一一为范仲淹辩护,有理有据,痛骂高司谏位高权贵却毫不作为,酣畅淋漓。北宋时君子的直言纳谏不再是个例,而变成了一种制度,欧阳修字里行间的浩然正气在现代社会读起来,不禁让人唏嘘与感动。

白求恩遗书

加拿大共产党员白求恩不远万里来到中国, 为晋察冀边区的军民救死扶伤。生命弥留之际,他给聂荣臻司令写下这封遗书。

“我在这里十分快乐,我惟一的希望就是能够多做贡献”,白求恩为遗物安排的非常妥当“两张行军床、两双英国皮鞋,你和聂夫人留用吧。马靴、马裤,请转交吕司令。贺将军,也要给他一些纪念品……”,其中并没有什么值钱的物品。“最近两年,是我平生最愉快、最有意义的日子。在这里,我还有很多话要对同志们说,可我不能再写下去了。让我把千百倍的谢忱送给你和千百万亲爱的同志们。”

毛泽东在《纪念白求恩》中高度赞扬了他的国际主义精神:“一个高尚的人,一个纯粹的人,一个有道德的人,一个脱离了低级趣味的人,一个有益于人民的人”,背下来这段话很容易,然而理解可能需要一生的时间。

陈觉与赵云霄[1][2]

这是两位革命烈士的信,看得人心如刀割。一封是丈夫就义前写给妻子的诀别信,一封是母亲留给尚在襁褓中女儿的遗书,二人先后英勇就义,牺牲时年仅 25 岁、23 岁。

“谁无父母,谁无儿女,谁无情人!我们正是为了救助全中国人民的父母和妻儿,所以牺牲了自己的一切。我们虽然是死了,但我们的遗志自有未死的同志来完成。大丈夫不成功便成仁,死又何憾!”

《贺进士王参元失火书》

这是一封非常有意思的信,唐元和年间,王参元家遭遇大火,柳宗元“始而骇”、“中而疑”、“终乃大喜”,写此信向王参元祝贺。

柳宗元直指一般人可能会说“皆曰盈虚倚伏,去来之不可常”,或者是“将大有为也,乃始厄困震悸,于是有水火之孽,有群小之愠,劳苦变动,而后能光明”,过去有很多人相信这一套,实际很不靠谱。作者接下来点明了祝贺的原因:“京城人多言足下家有积货,士之好廉名者,皆畏忌,不敢道足下之善”,意思是你家里太有钱了,有名之士忌讳于此,不敢说你好话,容易被流言蜚语弄得百口难辩。幸运的是,这一把火之后,所有人的担心、顾虑都烟消云散,虽然钱财一无所有,但你的才能可以好好传承,不会被玷污。

这篇文章揭露了几个传统:一是类似于“天将降大任于斯人也”,“先灾后福”的虚礼;二是位高权贵的人不能太有钱的“清流”传统;三是“仇富”传统。

]]>
EOS 开发:合约 https://livc.io/blog/226 2018-06-12T00:00:00+00:00 Zhao Li https://livc.io/blog/226 EOS 现在更新非常频繁,之前的命令可能很快就会有变动,于是我新编译了一个版本,不再使用之前的 Docker 环境。

EOS 的合约在 ~/eos/contracts 目录之下,比如 hello 合约为 ~/eos/contracts/hello/hello.cpp

#include <eosiolib/eosio.hpp>
using namespace eosio;

class hello : public eosio::contract {
  public:
      using contract::contract;

      /// @abi action
      void hi( account_name user ) {
         print( "Hello, ", name{user} );
      }
};

EOSIO_ABI( hello, (hi) )

从 CPP 编译成 WebAssembly 文件:

eosiocpp -o hello.wast hello.cpp

生成 abi 文件:

$ eosiocpp -g hello.abi hello.cpp
Generated hello.abi ...

上传合约到账户中(其中 livc 是 account name):

$ cleos --url http://127.0.0.1:8887 set contract livc ~/eos/contracts/hello -p livc
Reading WAST/WASM from /Users/zhao/eos/contracts/hello/hello.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: e35b8ec816d7556fee73f12c31c64e146c8a7af0fa56846a2466b87ef506c7ef  4168 bytes  5181 us
#         eosio <= eosio::setcode               {"account":"livc","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e60027e7e0...
#         eosio <= eosio::setabi                {"account":"livc","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d6501000000000...

$ cleos --url http://127.0.0.1:8887 push action livc hi '["hhhhh"]' --permission livc@active
executed transaction: a193f474503bb79ea6ecafa04419ea851cf4fd5d88c18710f0d8052a2f65e2bb  104 bytes  1269 us
#          livc <= livc::hi                     {"user":"hhhhh"}

其中,-p 代表使用该账户的 active 的授权,cleos 调用了 setcodesetabi 两个函数。

Token 合约

eosio.token 合约是一个 token 标准合约,类似于 ETH 的 ERC20 标准。

eosiocpp -o eosio.bios.wast eosio.bios.cpp

由于目录已存在 abi 文件,不需再次生成。

$ cleos --url http://127.0.0.1:8887 set contract eosio ~/eos/contracts/eosio.bios -p eosio
Reading WAST/WASM from /Users/zhao/eos/contracts/eosio.bios/eosio.bios.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 0fa7093a92ed900c88aaad2cf8b9a0e142d19625731cbd35eb4b5fc87b05cd43  3712 bytes  847 us
#         eosio <= eosio::setcode               {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001621260037f7e7f0060057f7e7e7e7e...
#         eosio <= eosio::setabi                {"account":"eosio","abi":"0e656f73696f3a3a6162692f312e30050c6163636f756e745f6e616d65046e616d650f7065...

创建 eosio.token 账户和合约:

$ cleos create key
(eosio.token owner)
Private key: 5HuTB56H49GP6VnKYk5xHNXQBESfqs8nwBCuhekbbLgS9PPA7mh
Public key: EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq

$ cleos create key
(eosio.token private)
Private key: 5J9svtsttiFvfHdeHwNruyfRfAF8i9yC1EcSzWUYy6MniuT1SAt
Public key: EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj

$ cleos wallet create -n eosio.token
Creating wallet: eosio.token
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5JiCuwwW3qJxU4mj8qvQYsHKGE78FmUtFH8UhJorW2hkmEWrevA"

$ cleos wallet import 5HuTB56H49GP6VnKYk5xHNXQBESfqs8nwBCuhekbbLgS9PPA7mh
imported private key for: EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq

$ cleos wallet import 5J9svtsttiFvfHdeHwNruyfRfAF8i9yC1EcSzWUYy6MniuT1SAt
imported private key for: EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj

$ cleos --url http://127.0.0.1:8887 create account eosio eosio.token EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj
executed transaction: b4ea4231f9cdcc5c97d9777bdf4a0d67a49a3312674fe62571e8de76a43aa803  200 bytes  621 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"eosio.token","owner":{"threshold":1,"keys":[{"key":"EOS71oCDtXFzjU1p5rn4o...

$ cleos --url http://127.0.0.1:8887 set contract eosio.token ~/eos/contracts/eosio.token -p eosio.token
Reading WAST/WASM from /Users/zhao/eos/contracts/eosio.token/eosio.token.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: effb485662fe1003b00a872aca556e5f16f6715c872ce61657302a09d3d87b0a  8112 bytes  1124 us
#         eosio <= eosio::setcode               {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e...
#         eosio <= eosio::setabi                {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...

$ cleos --url http://127.0.0.1:8887 push action eosio.token create '["eosio","1000000000.0000 EOS",0,0,0]' -p eosio.token
executed transaction: f5e3a7f3138f03c8dcac789e40bc8af2ac76750581aa9f97ab241edbdee8b4c8  120 bytes  1460 us
#   eosio.token <= eosio.token::create          {"issuer":"eosio","maximum_supply":"1000000000.0000 EOS"}

创建一个账户 bob 并给他转账:

$ cleos create key
(bob owner)
Private key: 5JPZkcPwVfRAZYjD2CkLLf1TwsaWk7JGJcUZJM9Vtw4XQuVXsh1
Public key: EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb

$ cleos create key
(bob private)
Private key: 5Jg1Y9u8HDsMzo7WtSXHXkRwAbdy9hBsgTMf1gSoZDRbp76G4Ge
Public key: EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1

$ cleos wallet create -n bobwallet
Creating wallet: bobwallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J1SNSox7ozdETfnDeFFQYYrGjCwsV7trcoyX4GbCtcjtfpwqny"

$ cleos wallet import 5JPZkcPwVfRAZYjD2CkLLf1TwsaWk7JGJcUZJM9Vtw4XQuVXsh1
imported private key for: EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb

$ cleos wallet import 5Jg1Y9u8HDsMzo7WtSXHXkRwAbdy9hBsgTMf1gSoZDRbp76G4Ge
imported private key for: EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1

$ cleos --url http://127.0.0.1:8887 create account eosio bob EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1
executed transaction: 32269bbfa553468ee798e5c2f70df1262258eecfa241eabe800d2bae2651775e  200 bytes  232 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS7URUGippnvXCifEao2quScqHGa...

$ cleos --url http://127.0.0.1:8887 push action eosio.token issue '[ "bob", "100.0000 EOS", "memo" ]' -p eosio
executed transaction: 39d7ba273c549db9ba1746a74938b026b57b8a3f0bf49919529b25119498767d  128 bytes  1622 us
#   eosio.token <= eosio.token::issue           {"to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#   eosio.token <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#         eosio <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#           bob <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}

再创建一个账号 Mary,从 Bob 给 Mary 转账:

$ cleos create key
Private key: 5K4ooajerHnUikiQG1pfrAxsveoBg7Zs7BMkrgeyBZLTszmL4R2
Public key: EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw

$ cleos create key
Private key: 5JS9VHiHgpjC5P1bFjjGDumANoR3nhibFwJpDrmqg25Jk4EQU75
Public key: EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X

$ cleos wallet create -n marywallet
Creating wallet: marywallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J2gAWRz7hqcT8ASU66XeRsEDHnfrAqj8djYyXs8vNBWf6Th2Fr"

$ cleos wallet import 5K4ooajerHnUikiQG1pfrAxsveoBg7Zs7BMkrgeyBZLTszmL4R2
imported private key for: EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw

$ cleos wallet import 5JS9VHiHgpjC5P1bFjjGDumANoR3nhibFwJpDrmqg25Jk4EQU75
imported private key for: EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X

$ cleos --url http://127.0.0.1:8887 create account eosio mary EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X
executed transaction: 1d0aac267f86a645f278910a20c527b73fda20832e315f26b82d6b388986a144  200 bytes  469 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"mary","owner":{"threshold":1,"keys":[{"key":"EOS8jxG15Zd4MGGrb5aNo3ZoBGEx...

$ cleos --url http://127.0.0.1:8887 push action eosio.token transfer '[ "bob", "mary", "25.0000 EOS", "m" ]' -p bob
executed transaction: cb664fc62c5bbf480aa73ab8ae19aecd85c68b09d9fdd70f0e7ee0e83a7ee433  128 bytes  976 us
#   eosio.token <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}
#           bob <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}
#          mary <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}

检查余额:

$ cleos --url http://127.0.0.1:8887 get currency balance eosio.token mary
25.0000 EOS

$ cleos --url http://127.0.0.1:8887 get currency balance eosio.token bob
75.0000 EOS

Reference

  • https://www.eosdocs.io/dappdevelopment/tokencontract/
  • https://www.eosdocs.io/dappdevelopment/helloworldcontract/
]]>
Mysql 数据变动备份 https://livc.io/blog/225 2018-06-06T00:00:00+00:00 Zhao Li https://livc.io/blog/225 本文保存 Mysql 数据库变动的思路是把变动(前或后)的数据保存到一个新的表中。

假如原表名为 tablename,创建一个新表命名为 history_table,其中字段都跟 tablename 一致,创建一个触发器命名为 trigger1,在每次更新后都把新的数据插入到备份表中,这样就知道每次数据库做了哪些改动:

CREATE TRIGGER `trigger1`
AFTER UPDATE ON `tablename`
FOR EACH ROW
    INSERT INTO history_table                 
    VALUES
    (
        NEW.field1,
        NEW.field2
    );

把里面的 field1, field2 换成自己表中的字段即可。

也可以在 phpmyadmin 中直接创建 trigger,

直接在定义中写入

INSERT INTO history_table                 
VALUES
(
    NEW.field1,
    NEW.field2
);

即可。

可能会有的问题是,如果原表主键是数字,那么修改原表这一行一次以上的话,备份表就会出现两行相同的主键数据。我们可以在备份表中另建一个主键来解决。

Reference

  1. https://kahimyang.com/kauswagan/code-blogs/552/create-history-record-for-every-change-in-mysql-table-audit-trail-mysql-trigger
]]>
LNMP + Laravel https://livc.io/blog/224 2018-06-05T00:00:00+00:00 Zhao Li https://livc.io/blog/224 本文是在 LNMP 1.5 环境下部署 Laravel 的教程,其中 LNMP 使用 https://lnmp.org 的一键安装包。

打开 proc_open

laravel 需要 proc_open 等函数,需要在 /usr/local/php/etc/php.ini 中的 disable_functions 删掉 proc_openproc_get_status,保存后 lnmp php-fpm restart 重启 php。

NGINX 配置

在 nginx 的配置中,设置了强制跳转 https,也包含了伪静态的重写文件。

server
    {
        listen 80;
        #listen [::]:80;
        server_name freecandy.one www.freecandy.one;
        rewrite ^(.*)$ https://freecandy.one$1 permanent;

    }

server
    {
        listen 443 ssl http2;
        #listen [::]:443 ssl http2;
        server_name freecandy.one ;
        index index.php index.htm index.html default.html default.htm default.php;
        root  /home/wwwroot/freecandy.one/public;
        ssl on;
        ssl_certificate /usr/local/nginx/conf/ssl/freecandy.one/fullchain.cer;
        ssl_certificate_key /usr/local/nginx/conf/ssl/freecandy.one/freecandy.one.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;

        include rewrite/laravel.conf;

        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass  unix:/tmp/php-cgi.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }        

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

        access_log off;

    }

修改权限

通过 chown -R www:www freecandy.one 将网站目录的权限从 root 修改为 www。默认的路径在 /home/wwwroot/freecandy.one/

删掉防跨目录

在Thinkphp、codeigniter、Laravel等框架下,网站目录一般是在public下,但是public下的程序要跨目录调用public上级目录下的文件,因为LNMP默认是不允许跨目录访问的,所以都是必须要将防跨目录访问的设置去掉,有时候这些框架类的程序提示500错误也可能是这个问题引起的。

LNMP 1.4上如果不想用防跨目录或者修改.user.ini的防跨目录的目录还需要将 /usr/local/nginx/conf/fastcgi.conf 里面的fastcgi_param PHP_ADMIN_VALUE “open_basedir=$document_root/:/tmp/:/proc/”; 在该行行前添加 # 或删除改行,需要重启nginx。

LNMP 1.4上也可以直接使用lnmp1.4/tools/ 目录下的 ./remove_open_basedir_restriction.sh 进行移除。

其他

删掉网站目录时,需要先 chattr +i /网站目录/.user.ini 之后即可删除。

Reference

  1. https://lnmp.org/faq/lnmp-vhost-add-howto.html
]]>
EOS 开发:账户 https://livc.io/blog/223 2018-05-16T00:00:00+00:00 Zhao Li https://livc.io/blog/223 1. 创建账户

上一篇钱包的文章后,我们有了一个解锁后的钱包和三个钥匙对。

新账户必须从另一个账户中创建出来,因此我们从 eosio 中创建出 default 账户。

# 替换括号中为之前创建的 key
cleos --wallet-url http://wallet:5555 -u http://server:7777 create account eosio default {Default owner Public Key} {Default active Public Key}

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 -u http://server:7777 create account eosio default EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L
executed transaction: f5ff3597191f50e24be7d17b6688c0813d7357063313d0b78d7f354e7dcc1607  352 bytes  102400 cycles
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"default","owner":{"threshold":1,"keys":[{"key":"EOS5KSUCYnHgpxZwSnFNBkJ1L...

注意账户名字必须小写并且不能超过 13 个字符(仅支持 12345abcdefghijklmnopqrstuvwxyz67890不允许)。

2. 查看账户信息

root@0ad6e73c14f2:~# cleos -u http://server:7777 get account default
{
  "account_name": "default",
  "permissions": [{
      "perm_name": "active",
      "parent": "owner",
      "required_auth": {
        "threshold": 1,
        "keys": [{
            "key": "EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L",
            "weight": 1
          }
        ],
        "accounts": []
      }
    },{
      "perm_name": "owner",
      "parent": "",
      "required_auth": {
        "threshold": 1,
        "keys": [{
            "key": "EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB",
            "weight": 1
          }
        ],
        "accounts": []
      }
    }
  ]
}

也可以通过 public key 查看所有关联的账户:

$ cleos  -u http://server:7777 get accounts EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB

Reference

  • https://www.eosdocs.io/dappdevelopment/accounts/
]]>
EOS 开发:钱包 https://livc.io/blog/222 2018-05-13T00:00:00+00:00 Zhao Li https://livc.io/blog/222 EOS 中有两种方式启动钱包:

  1. 一个用 nodeos server 启动的插件
  2. 一个独立的后台程序,能够运行在一个独立于 nodeos server 的 server 上

我们将使用后者示范。

重要的概念

很多人认为钱包是存储 token 的,实际上这是一个错误的概念。

钱包实际上存储的是钥匙对(key pairs)。下图表明了 keosd daemon 有多个钱包,并且每个钱包有多个 public+private key pairs。

1. 启动 keosd 并创建钱包

上一篇中我们已经在 5555 端口上面运行了钱包程序,但这里需要注意的是,在上一篇文章中启动 wallet 容器的方式是 —rm,这意味着退出后容器会自动删除,当然创建的钱包文件也就不见了,所以我们需要去掉 —rm,让这个容器持久化:

docker run --name wallet --network=eosnetwork -p 5555:5555 -i binaryfocus/eosdawn-2018-04-27-alpha-dev /bin/bash -c "keosd --http-server-address=0.0.0.0:5555"

然后创建钱包:

root@0ad6e73c14f2:/# cleos --wallet-url http://wallet:5555 wallet create
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J7CKieZrxCCegG3DgFHUdcAc7YTJzxCGWDYQMW6ogyWJmvSfc7"

这时我们已经得到了这个默认钱包的密码,你需要把它保存起来。

默认钱包的地址是 ~/eosio-wallet/default.wallet,注意这个地址是在 wallet 容器中,而不是我们当前操作的 tools 容器,你可以通过 docker exec -it wallet bash 开启一个 wallet 容器的终端来访问这个目录。

这时钱包里会有一个(publict+private)钥匙对

root@0ad6e73c14f2:/# cleos --wallet-url http://wallet:5555 wallet keys
[[
    "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
    "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
  ]
]

2. 加载钱包

初次启动 keosd 时需要通过 open 加载钱包,然后钱包才能运行。

比如说,现在查看一下钱包的状态,它是正在运行的:

root@0ad6e73c14f2:/# cleos --wallet-url http://wallet:5555 wallet list
Wallets:
[
  "default *"
]

然后重启 wallet 容器:

# ctrl+c 退出
docker start wallet
docker attach wallet

再次查看钱包状态:

root@0ad6e73c14f2:/# cleos --wallet-url http://wallet:5555 wallet list
Wallets:
[]

这时是空的,因为初次启动 keosd 其实需要先手动加载钱包:

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet open
Opened: default
root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet list
Wallets:
[
  "default"
]

3. 解锁钱包

当然,仅仅 open 钱包之后也什么都做不了,你还需要用密码 unlock:

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet unlock
password:
Unlocked: default

现在再 list 一下,钱包名会多出一个 * 代表它已经被解锁了。

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet list
Wallets:
[
  "default *"
]

4. 添加 KEY

每个账户有两个权限:owner, active,因此多数情况下需要创建两个 key。

创建 key 并导入钱包:

root@0ad6e73c14f2:~# cleos create key
Private key: 5KRg9KJQhRzqBVppMuzWJooMTQP99Z8BpEwhpB4J3mXrivMd2HD
Public key: EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet import 5KRg9KJQhRzqBVppMuzWJooMTQP99Z8BpEwhpB4J3mXrivMd2HD
imported private key for: EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB


root@0ad6e73c14f2:~# cleos create key
Private key: 5JguJAMAGq3oY5TYq3cMqhcJQBXZfkUdfkWVxG5F3z5guLw1MDv
Public key: EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet import 5JguJAMAGq3oY5TYq3cMqhcJQBXZfkUdfkWVxG5F3z5guLw1MDv
imported private key for: EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L

这时钱包中就有了三个 key pair 啦,一个是 master key(创建钱包时生成的),另外两对是刚刚导入的。

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet keys
[[
    "EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB",
    "5KRg9KJQhRzqBVppMuzWJooMTQP99Z8BpEwhpB4J3mXrivMd2HD"
  ],[
    "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
    "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
  ],[
    "EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L",
    "5JguJAMAGq3oY5TYq3cMqhcJQBXZfkUdfkWVxG5F3z5guLw1MDv"
  ]
]

但是这三个 key pair 的用处都不同,需要自己区分好,比如拿出笔记本记上:

eosio Public Key: "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
eosio Private Key: "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"

MyAccount owner Public Key: "EOS5KSUCYnHgpxZwSnFNBkJ1LCdqU1iFwazQbEgQAbysV2FLFSBDB"
MyAccount owner Private Key: "5KRg9KJQhRzqBVppMuzWJooMTQP99Z8BpEwhpB4J3mXrivMd2HD"

MyAccount active Public Key: "EOS6twXkcVomuTH2rih8SgeSPATVLnKts1HR3Q76bvy7aoeC1Yv6L"
MyAccount active Private Key: "5JguJAMAGq3oY5TYq3cMqhcJQBXZfkUdfkWVxG5F3z5guLw1MDv"

5. 多钱包工作

keosd 能够让你操作多个钱包,在上述的例子中都省略了钱包的名字,你可以通过 -n 指定:

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet create -n MyTestWallet
Creating wallet: MyTestWallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5JjXK7zpGBwBpspZ3gQDtvZwmPyDKADB5ja2bGFLfC3PqnsSVSb"

root@0ad6e73c14f2:~# cleos --wallet-url http://wallet:5555 wallet list
Wallets:
[
  "MyTestWallet *",
  "default *"
]

如果想要删除这个钱包直接在 wallet 的容器中直接 rm ~/eosio-wallet/MyTestWallet.wallet 并重启钱包程序即可。

Reference

  • https://www.eosdocs.io/dappdevelopment/wallets/
]]>
EOS 开发:环境准备 https://livc.io/blog/221 2018-05-12T00:00:00+00:00 Zhao Li https://livc.io/blog/221 这个系列选择使用 EOS New York 开发的 Docker 环境,需要具备基本的 docker 知识。

0. EOS 开发工具

eos 目前的开发生态大致如下图所示,其中

  • eosiocpp:编译 C++ 代码,能够上传到区块链上
  • cleos:命令行工具,用来和区块链交互
  • keosd:钱包管理器
  • nodeos:运行区块链的服务端软件

1. 下载镜像并测试运行

# 下载镜像
docker pull binaryfocus/eosdawn-2018-04-27-alpha-dev

# 运行 container
docker run --rm -it binaryfocus/eosdawn-2018-04-27-alpha-dev bash

# 运行 cleos
root@bc5d7d727921:/# cleos
ERROR: RequiredError: Subcommand required
Command Line Interface to EOSIO Client
Usage: cleos [OPTIONS] SUBCOMMAND

Options:
  -h,--help                   Print this help message and exit
  -u,--url TEXT=http://localhost:8888/
                              the http/https URL where nodeos is running
  --wallet-url TEXT=http://localhost:8888/
                              the http/https URL where keosd is running
  -v,--verbose                output verbose actions on error

Subcommands:
  version                     Retrieve version information
  create                      Create various items, on and off the blockchain
  get                         Retrieve various items and information from the blockchain
  set                         Set or update blockchain state
  transfer                    Transfer EOS from account to account
  net                         Interact with local p2p network connections
  wallet                      Interact with local wallet
  sign                        Sign a transaction
  push                        Push arbitrary transactions to the blockchain
  multisig                    Multisig contract commands
  system                      Send eosio.system contract action to the blockchain.

# 退出容器
root@bc5d7d727921:/# exit
exit

由于我们使用 —rm 运行的容器,在退出后会自动删除。

2. 创建 docker 网络

docker network 能够让容器之间进行通信。

docker network create eosnetwork

3. 运行容器

在 7777 端口上运行名为 server 的容器,并执行引号中的 nodeos 命令,启动服务:

docker run --name server --network=eosnetwork --rm -p 7777:7777 -i binaryfocus/eosdawn-2018-04-27-alpha-dev /bin/bash -c "nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::chain_api_plugin --plugin eosio::http_plugin -d /mnt/dev/data --http-server-address=0.0.0.0:7777 --access-control-allow-origin=*"

在 5555 端口上运行钱包:

docker run --name wallet --network=eosnetwork --rm -p 5555:5555 -i binaryfocus/eosdawn-2018-04-27-alpha-dev /bin/bash -c "keosd --http-server-address=0.0.0.0:5555"

再以 bash 启动一个容器,用来运行一些命令:

docker run --name tools --network=eosnetwork --rm -it binaryfocus/eosdawn-2018-04-27-alpha-dev /bin/bash

4. 测试

首先打开 http://localhost:7777/v1/chain/get_info 确保本地服务正常,然后输入下列命令测试是否 work:

root@0ad6e73c14f2:/# cleos -u http://server:7777 get info
{
  "server_version": "45fb9218",
  "head_block_num": 20660,
  "last_irreversible_block_num": 20659,
  "head_block_id": "000050b48f1b117aacfbe59fd5d66ca2fd6ecc16325d29206239e19c8861c902",
  "head_block_time": "2018-05-12T14:36:16",
  "head_block_producer": "eosio"
}

# 由于我们还没有创建钱包,所以返回为空
root@0ad6e73c14f2:/# cleos --wallet-url http://wallet:5555 wallet list keys
Wallets:
[]
[]

Reference

  • https://www.eosdocs.io/dappdevelopment/software/docker/
]]>
GitHub Pages 自定义域名开始支持 https https://livc.io/blog/220 2018-05-03T00:00:00+00:00 Zhao Li https://livc.io/blog/220 GitHub 从昨天开始为自定义域名支持 HTTPS,这就方便了许多,不需要再去 cf 配置 https,按照官方教程:https://help.github.com/articles/setting-up-an-apex-domain/ 可以很方便地配上小绿锁,但这里有一个问题需要注意一下。

在 repo 中重新添加 custom domain 时,首先清空保存后必须等待网站 publish 到 xxx.github.io 后,才能再次添加你的域名。否则如果删掉后马上再添加会说你的配置不对( Unavailable for your site because your domain is not properly configured to support HTTPS),强制 https 框框是灰色的,无法选中,我搞了两天才发现是这个原因。我已经向 GitHub 团队反应这个问题。

另外如果你配置好 https 后发现没有小绿锁,那一般是因为站点上有资源是 http 的。

]]>
非 root 安装 zsh/oh-my-zsh https://livc.io/blog/219 2018-04-18T00:00:00+00:00 Zhao Li https://livc.io/blog/219 安装 zsh

如果系统没有自带zsh的话需要手动安装。没有 sudo 权限的话可以选择从源码编译安装 zsh,但是最近发现了一个linux上的包管理工具linuxbrew,相当于Mac上的brew,对于没有sudo权限的人来说安装软件比较方便。

sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
test -d ~/.linuxbrew && PATH="$HOME/.linuxbrew/bin:$HOME/.linuxbrew/sbin:$PATH"
test -r ~/.bashrc && echo "export PATH='$(brew --prefix)/bin:$(brew --prefix)/sbin'":'"$PATH"' >>~/.bashrc
brew install zsh

设置ZSH为默认SHELL

如果系统没有自带的zsh并且没有权限向/etc/shells 中添加,那么需要设置刚才安装在自己目录中的zsh为默认shell。

.bashrc中添加一行:

exec ~/.linuxbrew/bin/zsh

这时登录后会自动切换zsh。

安装oh-my-zsh

http://ohmyz.sh 上有一键安装命令:

sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

如果提示系统中没有zsh的话,是因为没检测到刚刚安装在自己目录的zsh,那么可以手动下载install.sh脚本并将检测是否安装zsh那几行注释掉,执行即可。

#  CHECK_ZSH_INSTALLED=$(grep /zsh$ /etc/shells | wc -l)
#  if [ ! $CHECK_ZSH_INSTALLED -ge 1 ]; then
#    printf "${YELLOW}Zsh is not installed!${NORMAL} Please install zsh first!\n"
#    exit
#  fi
#  unset CHECK_ZSH_INSTALLED
]]>
《头号玩家》其实是一部《硅谷》 https://livc.io/blog/218 2018-04-09T00:00:00+00:00 Zhao Li https://livc.io/blog/218 《头号玩家》应该是最近大热的一部片子了,看了后确实非常炫酷,各种特效秀的飞起。遗憾的是里面除了闪灵和金刚其他我都没有看过,我也不是科幻迷或游戏迷。所以这篇不聊科幻、游戏,不聊动漫、音乐,也不聊怀旧和情怀,聊聊里面的科技故事。

《硅谷》是一部来自 HBO 的创业神剧,虽然没有同门《权力的游戏》有名,但也颇受欢迎。里面的每一个剧情几乎都能在硅谷找到原型:比如主角 Richard 被逐出自己公司,让人想起当年乔布斯被逐出苹果的故事;Richard 的天使投资人是按照硅谷传奇投资人 Peter Thiel 的事迹和个性来塑造的;剧中巨头公司 Hooli 的 CEO 的原型是甲骨文的老板,当然也有人认为和 Google 创始人很像。除此之外,Richard 被投资机构约见,没想到对方实际想剽窃其核心压缩算法;Pied Piper 夺冠的 Hackathon 原型实际是 TechCrunch 的创业大赛,这在创投圈也非常有名……这些都是科技工作者才明白的梗。

回过头来看《头号玩家》,它其实也是一部《硅谷》。

VR 的未来

《头号玩家》是一部改编于小说却超越原作的电影,实际上原作两三年前在硅谷 VR 圈就火过一次了。

2015 年的 Oculus Connect 2 开发者大会上,官方送的小礼品中就有这本《头号玩家》,而此次会议正是那一波 VR 热潮顶峰的标志性事件之一,因此几乎 VR 圈的每个人都读过这本书。然而几年后的今天,VR 的热度可能还需要《头号玩家》来拉一把。

很多时候,人们需要被《头号玩家》这样的作品激发想象力,尤其是创业者,某种程度上我们可以在里面看到未来的真实世界。

目前市面上的 VR 设备很容易造成眩晕,其中重要一点是:VR 画面的逼真使大脑认为你在做剧烈运动,然而你坐在椅子上是静止的状态,二者的联动性并不同步。《头号玩家》提出了一些探索:反派大 Boss 躺在特质的座椅中,四肢离地;主角一行五人在车上面吊着几根绳子,使自己能够运动;普通的反派杀手角色是在一个类似蛋壳的踏步机上面使用 VR;最后就是大街上一群人跑来跑去……这些其实都是不让 VR 运动和现实移动脱节的解决方案。

现在如果在街上看到有人带着 VR 眼镜或头盔,一定觉得很奇怪。但是在未来的 VR 世界,人们会像剧中的所有玩家一样,佩戴 VR 设备和佩戴手表、使用手机一样普遍,没有人会觉得奇怪,这个场景的到来只是时间问题。

互联网寡头

2018 年开始人们对科技公司的负面情绪持续加重,这个趋势非常明显。最近几年,从百度的医疗广告事件到今年的 Facebook 隐私泄露、特朗普炮轰 Amazon,包括千禧一代的滴滴杀熟,头条、快手接连整顿,整个社会都在思考未来科技公司无穷大的影响力,尤其是互联网寡头。

这在《头号玩家》中也非常明显:两个公司争夺虚拟世界,没人在乎现实世界,政府甚至都没有存在感(警察最后才出现)。IOI 公司能够轻易地找到男主角的住所并进行打击,这和我们今天的隐私泄露又何尝不是同一回事呢?

在未来的十年内,中心化的互联网模式会被颠覆:互联网领域中寡头盘旋在所有产业之上,他们所拥有的用户能力和资本能力对所有产业构成了压迫式的降维打击。但随着区块链和物联网技术的推广,十年后,这种中心化的互联网格局很可能被彻底的解构,进入到一个全新的万物互联的时代。

——吴晓波

巧合的是,《硅谷》Richard 的目标也是建立一个完全去中心化的互联网:没有防火墙,没有收费,没有政府监管,没有间谍。现在谈去中心化的话人们自然而然想到区块链,仿佛区块链成为了去中心化的代名词。实际上在很早以前就有非常多的去中心化尝试,旨在取代中心化解决方案。比如 ZeroNet 提出去中心化的互联网;Tox 等去中心化的 IM 工具;Resilio Sync 等去中心化网盘工具……

去中心化一定是好事吗?我认为需要辩证来看。一个没有监管的国家和一个没有制度的公司一样,绝对是一盘散沙,千万不要指望人的自律,在诱惑和利益面前,这些都不堪一击,这是人性的弱点。

《头号玩家》最后主角击败了哥斯拉,成为绿洲的新一代主人,但是之后的故事呢?在现实生活中极有可能是屠龙少年终成恶龙,当然这会让整部影片变了味。

Geek 文化

接下来我们把目光聚集到绿洲游戏的创办者—— Holiday。他在影片末尾也说:“我之所以创造‘绿洲’,只是因为我不知道在现实世界如何与人沟通。”这种科技男形象是不是像极了扎克伯格和乔布斯这类人?更有意思的是,Holiday 将合伙人赶出公司,这俩人也做过这事。

从乔布斯的黑色高领衫、扎克伯格的灰色T恤、甚至是吴恩达的蓝色衬衫,到现在科技公司简单而干净的印有公司 Logo 的T恤,这种 Geek 文化竟然不知不觉间成为科技圈的时尚,仿佛在传递出一种“我很宅,但我能改变世界”的冷酷和不屑。

《头号玩家》中的 2045 年,地球许多地方成为了贫民窟,人们为了逃避现实而进入虚拟世界。这不得不让人联想起人工智能可能带来潜在的失业潮,人们无所事事,沉迷虚拟世界,这些其实都是极有可能发生的事。因此《头号玩家》不光是一部科幻片,除了游戏、电影、动漫,里面的科技故事也同样有趣。

]]>