《世上为什么要有图书馆》读书笔记

最近读到的一本文字流畅,内容清爽的小书。书里描述了大学教授杨素秋,在西安市碑林区文化旅游局挂职一年,筹办区图书馆的经历。这是个繁杂、具体,有时甚至需要挑战权威的工作: 区里提供的馆址是个地下空间,需要在有限的预算内,找到合适的装修公司,把这个地下空间改造成舒适的阅读空间。 在图书采购过程中,供应商惯于提供劣质的,滥竽充数的图书,为采购者支付回扣。作者不屑于收受回扣,一心为公,希望图书馆里都是经历了时间检验的好书。 为一个图书馆选书,工程浩大,无法仅凭一己之力完成。作者发动自己的人脉,联系了诸多好友帮忙选书。选书缘由,荐者心路,作者缓缓道来,推卷而述,好不痛快。 尽管困难重重,作者心有所往,逆流而上,不畏险阻,最终得偿所愿。主线之余,作者夹叙一年挂职生活所遇的形色人等,有的让人牙关紧咬,有的让人唏嘘感慨,说尽人情冷暖。西安的美食,官场中的博弈,选书朋友们的人生故事,对弱势群体的关照,五味杂陈,乒乓作响,读者吃到的是酸辣爽口的一餐。 附录里的书单 童书(含漫画) 书名 作者 出版年份 豆瓣评分 豆瓣链接 《安徒生童话》 [丹麦] 汉斯·克里斯蒂安·安徒生 1835年 9.2 链接 《镖人》 许先哲 2015年 9.0 链接 《冰菓》 [日] 米澤穂信 2001年 8.6 链接 《查理和巧克力工厂》 [英] 罗尔德·达尔 1964年 8.9 链接 《虫师》 [日] 漆原友纪 1999年 9.4 链接 《宝可梦(宠物小精灵)》 [日] 日下秀宪 / 真斗 1997年 9.0 链接 《窗边的小豆豆》 [日] 黑柳彻子 1981年 8.8 链接 《吹小号的天鹅》 [美] E.B. 怀特 1970年 8.9 链接 《丁丁历险记》 [比利时] 埃尔热 1929年 9.4 链接 《机动战士高达》 [日] 富野由悠季 / 矢立肇 1979年 9.2 链接 《给孩子的故事》 黄永玉 2015年 8.2 链接 《灌篮高手》 [日] 井上雄彦 1990年 9.7 链接 《哈利·波特》 [英] J.K. 罗琳 1997年 9.2 链接 《海贼王》 [日] 尾田荣一郎 1997年 9.6 链接 《汉声中国童话》 汉声杂志社 1982年 9.5 链接 《荷花镇的早市》 周翔 2014年 8.8 链接 《黑子的篮球》 [日] 藤卷忠俊 2008年 8.1 链接 《护生画集》 丰子恺 / 弘一法师 1929年 9.4 链接 《火影忍者》 [日] 岸本齐史 1999年 9.3 链接 《精灵鼠小弟》 [美] E.B. 怀特 1945年 8.6 链接 《可怕的科学》 [英] 尼克·阿诺德 1996年 9.3 链接 《拉比的猫》 [法] 尤安·斯法 2002年 8.8 链接 《了不起的狐狸爸爸》 [英] 罗尔德·达尔 1970年 8.8 链接 《龙珠Z》 (漫画原作) [日] 鸟山明 1984年 9.7 链接 《玛蒂尔达》 [英] 罗尔德·达尔 1988年 9.1 链接 《玛法达》 [阿根廷] 季诺 1964年 9.4 链接 《名侦探柯南》 [日] 青山刚昌 1994年 9.3 链接 《排球少年》 [日] 古馆春一 2012年 9.7 链接 《七龙珠》 [日] 鸟山明 1984年 9.7 链接 《棋魂》 [日] 堀田由美 / 小畑健 1999年 9.5 链接 《犬夜叉》 [日] 高桥留美子 1996年 9.1 链接 《三毛流浪记》 张乐平 1947年 9.1 链接 《圣斗士星矢》 [日] 车田正美 1986年 9.2 链接 《死神》 (BLEACH) [日] 久保带人 2001年 9.0 链接 《死亡笔记》 [日] 大场鸫 / 小畑健 2003年 9.2 链接 《四月是你的谎言》 [日] 新川直司 2011年 8.7 链接 《太空》 [美] H.A. 雷 1957年 9.1 链接 《网球王子》 [日] 许斐刚 1999年 8.8 链接 《文豪野犬》 [日] 朝雾卡夫卡 / 春河35 2012年 8.4 链接 《希利尔讲艺术史》 [美] V.M. 希利尔 1924年 8.8 链接 《夏洛的网》 [美] E.B. 怀特 1952年 8.6 链接 《夏目友人帐》 [日] 绿川幸 2005年 9.4 链接 《写给孩子的哲学启蒙书》 [法] 布里吉特·拉贝 等 2001年 8.8 链接 《银魂》 [日] 空知英秋 2003年 9.5 链接 《幽游白书》 [日] 冨㭴义博 1990年 9.5 链接 《月刊少女野崎君》 [日] 椿泉 2011年 9.2 链接 文学类 书名 作者 出版年份 豆瓣评分 豆瓣链接 《奥德赛》 [古希腊] 荷马 公元前8世纪 8.7 链接 《白鹿原》 陈忠实 1993年 9.3 链接 《冰与火之歌》 [美] 乔治·R.R. 马丁 1996年 9.4 链接 《查令十字街84号》 [美] 海莲·汉芙 1970年 8.5 链接 《传习录》 王阳明 约1518年 9.1 链接 《东周列国志》 [明] 冯梦龙 约1620年代 9.3 链接 《读库》 张立宪 (主编) 2006年 9.3 链接 《儿女英雄传》 [清] 文康 约1878年 7.6 链接 《反骨仔》 王朔 2007年 7.0 链接 《废都》 贾平凹 1993年 8.2 链接 《古文观止》 [清] 吴楚材 / 吴调侯 1695年 9.4 链接 《哈克贝利·费恩历险记》 [美] 马克·吐温 1884年 8.7 链接 《海边的卡夫卡》 [日] 村上春树 2002年 8.2 链接 《海底两万里》 [法] 儒勒·凡尔纳 1870年 8.6 链接 《汉字王国》 [瑞典] 林西莉 1989年 9.0 链接 《红楼梦》 [清] 曹雪芹 约1791年 9.6 链接 《活着》 余华 1993年 9.4 链接 《基督山伯爵》 [法] 大仲马 1844年 9.2 链接 《卡拉马佐夫兄弟》 [俄] 陀思妥耶夫斯基 1880年 9.7 链接 《克林索尔的最后夏天》 [德] 赫尔曼·黑塞 1920年 8.8 链接 《老人与海》 [美] 欧内斯特·海明威 1952年 8.5 链接 《礼物》 [美] 弗拉基米尔·纳博科夫 1938年 8.8 链接 《裂缝》 [英] 多丽丝·莱辛 2007年 7.9 链接 《流言》 张爱玲 1944年 8.8 链接 《鲁滨孙漂流记》 [英] 丹尼尔·笛福 1719年 8.4 链接 《鲁迅全集》 鲁迅 1938年 9.7 链接 《论语》 孔子弟子及再传弟子 战国时期 9.4 链接 《罗生门》 [日] 芥川龙之介 1915年 8.7 链接 《麦田里的守望者》 [美] J.D. 塞林格 1951年 8.2 链接 《魔戒》 [英] J.R.R. 托尔金 1954年 9.4 链接 《墓法墓天》 不带剑 2017年 7.9 链接 《那不勒斯四部曲》 [意] 埃莱娜·费兰特 2011年 8.8 链接 《挪威的森林》 [日] 村上春树 1987年 8.1 链接 《胚胎奇谭》 [英] 朱利安·巴恩斯 1984年 8.5 链接 《契诃夫文集》 [俄] 安东·巴甫洛维奇·契诃夫 19世纪末 9.6 链接 《人间词话》 王国维 1910年 9.0 链接 《人间喜剧》 [法] 奥诺雷·德·巴尔扎克 1829-1848年 9.2 链接 《三国演义》 [明] 罗贯中 14世纪 9.2 链接 《三体》 刘慈欣 2006年 8.9 链接 《诗的八堂课》 张晓风 2011年 8.3 链接 《诗歌手册》 [法] 保尔·瓦雷里 1942年 8.7 链接 《诗经》 佚名 公元前11-7世纪 9.0 链接 《史记》 [汉] 司马迁 约公元前94年 9.6 链接 《世说新语》 [南朝宋] 刘义庆 约430年 9.1 链接 《鼠疫》 [法] 阿尔贝·加缪 1947年 9.1 链接 《太平广记》 [宋] 李昉 等 978年 9.5 链接 《汤姆·索亚历险记》 [美] 马克·吐温 1876年 8.5 链接 《唐诗别裁集》 [清] 沈德潜 1717年 9.0 链接 《唐诗三百首》 [清] 蘅塘退士 约1763年 9.2 链接 《天龙八部》 金庸 1963年 9.2 链接 《推拿》 毕飞宇 2008年 8.7 链接 《文苑英华》 [宋] 李昉 等 987年 9.7 链接 《我弥留之际》 [美] 威廉·福克纳 1930年 8.8 链接 《西南联大国文课》 闻一多 / 朱自清 等 - 8.4 链接 《献给阿尔吉侬的花束》 [美] 丹尼尔·凯斯 1966年 9.1 链接 《小城之恋》 [英] L.P. 哈特利 1953年 8.1 链接 《小说课》 毕飞宇 2017年 8.6 链接 《写作法宝》 [美] 斯蒂芬·金 2000年 8.9 链接 《伊利亚特》 [古希腊] 荷马 公元前8世纪 8.8 链接 《阴阳师》 [日] 梦枕貘 1986年 8.6 链接 《银河帝国》 [美] 艾萨克·阿西莫夫 1951年 9.4 链接 《酉阳杂俎》 [唐] 段成式 9世纪 9.2 链接 《战国争鸣记》 [日] 宫崎市定 1947年 8.5 链接 《朝花夕拾》 鲁迅 1928年 8.8 链接 《正常人》 [爱尔兰] 萨莉·鲁尼 2018年 8.0 链接 《纸牌屋》 [英] 迈克尔·多布斯 1989年 8.6 链接 《最后一个匈奴》 高建群 1993年 8.1 链接 《左传》 [春秋] 左丘明 (传) 战国时期 9.4 链接 《作文七巧》 夏丏尊 / 叶圣陶 1980年 8.0 链接 人文社科 书名 作者 出版年份 豆瓣评分 豆瓣链接 《1844年经济学哲学手稿》 [德] 卡尔·马克思 1932年 9.2 链接 《奥斯威辛:一部历史》 [英] 劳伦斯·里斯 2005年 9.3 链接 《奥义书》 佚名 公元前800-500年 9.1 链接 《巴尔扎克传》 [奥] 斯蒂芬·茨威格 1946年 9.1 链接 《保卫马克思》 [法] 路易·阿尔都塞 1965年 8.8 链接 《藏在碑林里的国宝》 郭志呈 / 郭强 2019年 8.5 链接 《册府元龟》 [宋] 王钦若 / 杨亿 1013年 9.8 链接 《纯粹理性批判》 [德] 伊曼努尔·康德 1781年 9.2 链接 《丛书集成》 王云五 (主编) 1935年 9.7 链接 《大藏经》 历代高僧 历代 9.8 链接 《抵抗的群体》 [美] 王人英 2011年 8.8 链接 《第二性》 [法] 西蒙·娜·德·波伏娃 1949年 8.8 链接 《洞穴奇案》 [美] 彼得·萨伯 1998年 9.4 链接 《对影胡说》 胡兰成 1980年 7.2 链接 《二十四史》 历代史学家 历代 9.7 链接 《二手时间》 [白俄] S.A.阿列克谢耶维奇 2013年 9.2 链接 《佛家名相通释》 熊十力 1937年 9.1 链接 《傅山的世界》 [美] 白谦慎 2006年 9.1 链接 《伽利略传》 [德] 贝托尔特·布莱希特 1943年 8.9 链接 《关于他人的痛苦》 [美] 苏珊·桑塔格 2003年 8.5 链接 《观看之道》 [英] 约翰·伯格 1972年 8.5 链接 《汉字书法之美》 蒋勋 2009年 8.5 链接 《汉字与文物的故事》 孙机 2021年 9.2 链接 《黑镜头》 [美] 罗伯特·普雷基 2002年 8.8 链接 《黄泉下的美术》 巫鸿 2005年 8.6 链接 《火车上的中国人》 王福春 2001年 8.8 链接 《基督教神学原理》 [美] 奥尔森 1992年 8.9 链接 《基督教要义》 [法] 约翰·加尔文 1536年 9.5 链接 《加德纳艺术通史》 [美] 弗雷德·S. 克莱纳 1926年 9.4 链接 《剑桥中国史》 [英] 费正清 等 1978年 9.4 链接 《咖啡厅、餐馆内景实例》 - - 6.7 链接 《康德传》 [德] 曼弗雷德·库恩 2001年 9.1 链接 《旷野呼告》 [美] 杰克·伦敦 1903年 8.8 链接 《拉丁美洲被切开的血管》 [乌拉圭] 爱德华多·加莱亚诺 1971年 9.3 链接 《蓝色血脉》 朱大可 1991年 8.1 链接 《劳特利奇哲学史》 G.H.R.帕金森 (主编) 1993年 9.3 链接 《理解一张照片》 [英] 约翰·伯格 2013年 8.3 链接 《理想城市》 [美] 简·雅各布斯 1961年 9.4 链接 《另一种讲述的方式》 [英] 约翰·伯格 1982年 8.8 链接 《伦理学》 [荷] 巴鲁赫·斯宾诺莎 1677年 9.2 链接 《论摄影》 [美] 苏珊·桑塔格 1977年 8.7 链接 《毛以后的中国》 [美] 罗德里克·麦克法夸尔 2008年 9.3 链接 《美术、神话与祭祀》 张光直 1988年 9.0 链接 《明朝那些事儿》 当年明月 2006年 9.2 链接 《墨庄漫录》 [宋] 张邦基 南宋 8.6 链接 《纽约摄影学院摄影教材》 [美] Don Sheff 1970年 8.7 链接 《欧洲大学史》 [法] 克里斯托夫·夏尔勒 2002年 8.3 链接 《破〈破新唯识论〉》 熊十力 1923年 8.6 链接 《囚徒的困境》 [美] 威廉·庞德斯通 1992年 8.4 链接 《让房子与你的灵魂契合》 [美] 克莱尔·库珀·马库斯 1995年 8.0 链接 《人类简史》 [以色列] 尤瓦尔·赫拉利 2011年 9.1 链接 《如何建造美好家园》 [英] 约翰·布鲁克斯 1984年 8.6 链接 《撒马尔罕的金桃》 [美] 薛爱华 1963年 9.2 链接 《僧侣与哲学家》 [法] 让-弗朗索瓦·勒维尔 1997年 8.5 链接 《送法下乡》 苏力 2000年 8.7 链接 《山川悠远》 方闻 2004年 8.5 链接 《设计中的设计》 [日] 原研哉 2003年 8.5 链接 《摄影哲学的思考》 [捷] 维兰·傅拉瑟 1983年 8.5 链接 《身体·性别·摄影》 [日] 笠原美智子 2003年 8.0 链接 《神话学》 [法] 罗兰·巴特 1957年 8.4 链接 《生活与命运》 [苏] 瓦西里·格罗斯曼 1980年 9.6 链接 《圣经·旧约》 摩西 等 公元前13世纪-前2世纪 9.2 链接 《圣经·新约》 马太 / 马可 / 路加 等 公元1世纪 9.2 链接 《世界摄影史》 [美] 内奥米·罗森布拉姆 1984年 8.8 链接 《世界摄影艺术史》 [法] 安德烈·胡耶 2005年 8.3 链接 《世界通史》 [美] 斯塔夫里阿诺斯 1970年 9.1 链接 《市井西仓》 胡武功 2006年 8.1 链接 《私人生活史》 [法] 菲利普·阿里埃斯 等 1985年 8.7 链接 《斯宾诺莎导读》 [美] 史蒂文·纳德勒 2006年 8.7 链接 《四库全书》 [清] 纪昀 等 1782年 9.9 链接 《俗世威尔》 [英] 特里·伊格尔顿 2008年 8.5 链接 《涑水记闻》 [宋] 司马光 北宋 8.7 链接 《太平御览》 [宋] 李昉 等 983年 9.8 链接 《天真的人类学家》 [英] 奈吉尔·巴利 1983年 8.4 链接 《同性恋亚文化》 李银河 / 王小波 1998年 8.5 链接 《图书馆入门》 [日] 若松英辅 2013年 8.1 链接 《完美店铺设计指南》 - - 7.0 链接 《唯识二十论》 [古印度] 世亲 约4世纪 9.2 链接 《为什么我不是基督教徒》 [英] 伯特兰·罗素 1927年 8.7 链接 《未来简史》 [以色列] 尤瓦尔·赫拉利 2015年 8.4 链接 《文字的力与美》 [日] 杉浦康平 2002年 8.7 链接 《无知的教师》 [法] 雅克·朗西埃 1987年 8.5 链接 《乡土中国》 费孝通 1947年 9.3 链接 《湘山野录》 [宋] 释文莹 北宋 8.2 链接 《新教伦理与资本主义精神》 [德] 马克斯·韦伯 1905年 8.9 链接 《新唯识论》 熊十力 1932年 9.1 链接 《新游牧民》 [日] 四方田犬彦 2002年 7.9 链接 《幸运者》 [英] 约翰·伯格 1967年 8.8 链接 《修剪菩提树》 [美] 唐纳德·S.洛佩兹 1995年 8.7 链接 《雅典与耶路撒冷》 [俄] 列夫·舍斯托夫 1938年 9.1 链接 《艺术哲学》 [法] 丹纳 1865年 9.1 链接 《隐士建筑》 [日] 中村好文 2011年 8.6 链接 《永字八法》 佚名 唐代 8.3 链接 《犹太教》 [英] 诺曼·所罗门 1996年 8.3 链接 《与古为徒和娟娟发屋》 巫鸿 2005年 9.0 链接 《与小泽征尔共度的午后音乐时光》 [日] 村上春树 / 小泽征尔 2011年 8.7 链接 《造型的诞生》 [日] 杉浦康平 1999年 9.1 链接 《怎样阅读照片》 [英] 伊安·杰夫里 1981年 8.4 链接 《詹森艺术史》 [美] H.W. 詹森 1962年 9.4 链接 《正面管教》 [美] 简·尼尔森 1981年 8.4 链接 《知日》 苏静 (主编) 2011年 7.5 链接 《直角之诗》 [法] 勒·柯布西耶 1955年 8.9 链接 《纸上纪录片》 崔永元 (主编) 2002年 8.7 链接 《中国碑帖名品》 - - 9.2 链接 《中国摄影史》 陈申 / 徐希景 1987年 8.4 链接 《中国照相馆史》 [美] 泰瑞·贝内特 2013年 8.9 链接 《宗教生活的基本形式》 [法] 埃米尔·涂尔干 1912年 9.0 链接 《走向新建筑》 [法] 勒·柯布西耶 1923年 8.6 链接 自然科学 书名 作者 出版年份 豆瓣评分 豆瓣链接 《别闹了,费曼先生》 [美] 理查德·费曼 1985年 9.3 链接 《城市自然故事》 张瑜 2021年 8.9 链接 《从一到无穷大》 [美] G. 伽莫夫 1947年 9.2 链接 《地球编年史》 [美] 撒迦利亚·西琴 1976年 8.1 链接 《第三种黑猩猩》 [美] 贾雷德·戴蒙德 1991年 8.5 链接 《哥德尔、艾舍尔、巴赫》 [美] 侯世达 1979年 9.4 链接 《给忙碌者的天体物理学》 [美] 奈尔·德葛拉司·泰森 2017年 8.6 链接 《给青年科学家的信》 [美] 爱德华·威尔逊 2013年 8.4 链接 《果壳中的宇宙》 [英] 斯蒂芬·霍金 2001年 9.0 链接 《剑桥科学史》 [英] 科林·A.罗南 1983年 8.9 链接 《科学的历程》 吴国盛 1995年 9.1 链接 《盲眼钟表匠》 [英] 理查德·道金斯 1986年 9.0 链接 《上帝掷骰子吗?》 曹天元 2006年 9.3 链接 《什么是科学》 吴国盛 2016年 8.6 链接 《实验室女孩》 [美] 霍普·洁伦 2016年 8.6 链接 《贪婪的多巴胺》 [美] 丹尼尔·利伯曼 等 2018年 7.9 链接 《物理世界奇遇记》 [美] G. 伽莫夫 1940年 9.1 链接 《现实不似你所见》 [意] 卡洛·罗韦利 2014年 8.9 链接 《园丁的一年》 [捷克] 卡雷尔·恰佩克 1929年 8.7 链接 《云彩收集者手册》 [英] 加文·弗雷特-平尼 2006年 8.0 链接 《杂草的故事》 [英] 理查德·梅比 2012年 8.8 链接 《怎样观察一棵树》 [美] 南希·罗斯·哈格 2005年 8.5 链接 《这里是中国》 星球研究所 / 中国青藏高原研究会 2018年 9.3 链接 《自私的基因》 [英] 理查德·道金斯 1976年 8.9 链接 其他系列书 书名 作者 出版年份 豆瓣评分 豆瓣链接 《中国在梁庄》(“梁庄”系列) 梁鸿 2010年 8.9 链接 《玛格南世纪》(“玛格南”系列) 玛格南图片社 1999年 9.4 链接 “牛津树”系列 [英] Roderick Hunt 等 1986年 9.7 链接 “培生”系列 培生教育集团 - 9.1 链接 《失落的一代》(“中国纪实三部曲”) [法] 潘鸣啸 1994年 9.2 链接

2025/9/29
articleCard.readMore

《纳瓦尔宝典》推荐阅读

纳瓦尔·拉维坎特(Naval Ravikant)在《纳瓦尔宝典》中不仅分享了他关于财富和幸福的智慧,还推荐了大量影响他思维的优质书籍和博客。这些推荐读物构成了一个完整的知识体系,涵盖科学、哲学、商业、灵修等多个领域。 《纳瓦尔宝典》提及书籍与博客索引(含博客链接) 以下列表依照在《The Almanack of Naval Ravikant》中首次出现顺序整理,并补充中文译名及 Naval 的一句话点评。博客及博文已附可点击链接。 序 英文原名(含链接) 中文译名 类 型  Naval 一句点评 1 The Beginning of Infinity 无穷的开始:世界进步的本源 书籍 不算易读,却真正把我读聪明了。 2 Sapiens: A Brief History of Humankind 人类简史:从动物到上帝 书籍 近十年读过的最佳著作,洞见满页。 3 The Rational Optimist 理性乐观派:人类经济进步史 书籍 多年里最睿智、最启发我的一本书。 4 Genome 基因组:人类自传23章 书籍 Ridley 的其他作品,我全读且反复读。 5 The Red Queen 红皇后:性与人类进化 书籍 Ridley 必读之作之一。 6 The Origins of Virtue 美德的起源 书籍 Ridley 探讨合作本能的佳作。 7 The Evolution of Everything 万物演化 书籍 解释新思想如何诞生的前瞻之书。 8 Skin in the Game 非对称风险 书籍 2018 年最佳读物之一,商业模型极佳。 9 The Bed of Procrustes 暂无中文版 书籍 Taleb 的古典智慧箴言集。 10 The Black Swan 黑天鹅 书籍 Taleb 另一部必读之作。 11 Antifragile 反脆弱 书籍 Taleb 另一部必读之作。 12 Fooled by Randomness 随机漫步的傻瓜 书籍 Taleb 另一部必读之作。 13 Six Easy Pieces 费曼物理学讲义·六篇轻松小品 书籍 我会送给孩子的物理入门书。 14 Six Not-So-Easy Pieces 费曼物理学讲义·六篇不太轻松小品 书籍 与上册并读收获更大。 15 Perfectly Reasonable Deviations… 合理的偏差:费曼书信集 书籍 展示费曼思考魅力的书信精选。 16 Genius: The Life and Science of Richard Feynman 天才:理查德·费曼的一生 书籍 费曼传记,值得再三回味。 17 Thing Explainer 万物解释者 书籍 用千常用词解释复杂世界,妙不可言。 18 Thinking Physics 思考物理 书籍 小学到研究生都能悟到物理真义。 19 The Lessons of History 历史的教训 书籍 短小却犀利,概括宏大历史主题。 20 The Sovereign Individual 主权个人 书籍 自《人类简史》以来最打动我的书。 21 Poor Charlie’s Almanack 穷查理宝典 书籍 芒格之道的最全面记录。 22 Reality Is Not What It Seems 现实并非如你所见 书籍 现代物理的诗意科普。 23 Seven Brief Lessons on Physics 七堂极简物理课 书籍 物理学的极简浪漫入门。 24 The Compleat Strategyst 策略家的博弈 书籍 博弈论的轻松读物,受益匪浅。 25 The Evolution of Cooperation 合作的进化 书籍 合作的博弈论经典。 26 Theory of Everything (Dreamstate Trilogy) 暂无中文版 书籍 探索意识与现实边界的小说。 27 Jed McKenna’s Notebook 暂无中文版 书籍 对自我探寻的极端反思。 28 A Master’s Secret Whispers 暂无中文版 书籍 灵性启蒙手册。 29 Direct Truth 暂无中文版 书籍 直指真理的心灵炸弹。 30 Atmamun 暂无中文版 书籍 意识自由的个人记录。 31 The Book of Life 生命之书 书籍 克里希那穆提思想精粹。 32 Total Freedom 彻底的自由 书籍 通往绝对自由的途径。 33 Siddhartha 悉达多 书籍 每个人的精神旅程寓言。 34 The Book of Secrets 秘密之书 书籍 奥修对人生的114条开示。 35 The Great Challenge 暂无中文版 书籍 奥修晚期谈话录。 36 The Way to Love 爱的方式 书籍 孟德信简练的灵修指引。 37 The Untethered Soul 觉醒的你 书籍 如何超越自我束缚。 38 Meditations 沉思录 书籍 斯多葛智慧的原典读法。 39 Love Yourself Like Your Life Depends on It 像生命一样爱自己 书籍 简单却有效的自爱练习。 40 The Tao of Seneca 暂无中文版 书籍 与纳瓦尔同频的斯多葛精选。 41 How to Change Your Mind 如何改变你的想法 书籍 揭开迷幻药疗愈潜力。 42 Striking Thoughts 搏击思想 书籍 李小龙哲学火花。 43 The Prophet 先知 书籍 简洁而永恒的人生诗篇。 44 Ficciones 虚构集 书籍 每一页都折射无限宇宙。 45 Stories of Your Life and Others 你一生的故事 书籍 科幻与哲思的完美融合。 46 Exhalation 呼吸 书籍 最富想象力的当代科幻集。 47 The Lifecycle of Software Objects 软件体的生命周期 书籍 AI 伦理预演,深刻摄人。 48 Snow Crash 雪崩 书籍 网络与文化的先知小说。 49 The Diamond Age 钻石年代 书籍 纳瓦尔常提的教育乌托邦。 50 The Last Question 最后的问题 书籍 短篇里藏着宇宙终极命题。 51 Tools of Titans 巨人的工具 书籍 实践者的心法大全。 52 Thermoinfocomplexity 暂无中文版 书籍 信息热力学的深度论文。 53 Pre-Suasion 瞬时说服 书籍 说服术的时机艺术。 54 The Story of Philosophy 哲学的故事 书籍 通俗入门哲学名著。 55 God’s Debris 神的碎片 书籍 思辨小说的奇葩精品。 56 Tao Te Ching 道德经 书籍 智慧源头,日日可读。 57 The Undercover Economist 卧底经济学 书籍 经济学视角的日常透镜。 58 Illusions: The Adventures of a Reluctant Messiah 幻灭 书籍 寓言式的自由宣言。 59 The Three-Body Problem 三体 书籍 科幻史诗,引人沉思。 60 Man’s Search for Meaning 活出生命的意义 书籍 逆境中的意义之书。 61 Sex at Dawn 黎明前的性 书籍 重新审视人类亲密关系。 62 Melting Asphalt (Kevin Simler) 暂无中文版 博客 洞悉人性与社会的深度博文。 63 Farnam Street (Shane Parrish) 范南街 博客 思维模型的宝库。 64 Stratechery (Ben Thompson) 战略学 博客 商业与科技的清晰分析。 65 Idle Words (Maciej Cegłowski) 闲言碎语 博客 写作优雅,观点锐利。 66 The Munger Operating System: How to Live a Life That Really Works 芒格操作系统:如何过一种真正有效的生活 博文 芒格智慧的浓缩指南。 67 The Day You Became a Better Writer 你成为更好作家的那一天 博文 写作质量跃迁之道。 68 Crony Beliefs 裙带信念 博文 自我欺骗的深刻剖析。 69 Career Decisions 职业决策 博文 择业思考框架。 70 Think Like Reality 像现实一样思考 博文 量子并不怪——怪的是你。 71 Lazy Leadership 懒惰的领导力 博文 以无为治有为。 72 EdLatimore.com Ed Latimore 个人网站 博客 拳击与人生哲理的结合。 73 You and Your Research 你和你的研究 博文 做重要工作的心法。

2025/7/5
articleCard.readMore

与冰山交谈

每个人都是一座冰山。当你与人交谈,想象你是在和冰山交谈,目之所及的只是水面之上的部分。如果你希望达成交流,你必须具备耐心,从身体和情绪感受出发,逐层递进,弄清原委。

2025/7/5
articleCard.readMore

Claude Code Complexity: Safety, Safety, Safety

I tried Claude Code this week, and instantly felt the empowerment from the tool, and was stunned by how naturally it blends into developer workflows. It demonstrated how easy the LLM model makers can disrupt the application makers (Cursor in this case). This reminds me of the analogy Andrej Karpathy made in Software Is Changing (Again) presentation that LLM has strong analogies to operating systems. The LLM model makers can easily disrupt app makers like Apple can sherlock other softwares running on top of macOS. With a similar tool from Google called Gemini CLI released, I begin to question about what is the main complexity Claude Code has, and whether that complexity is challenging enough to support companies relying on building agentic tools. I found the following video where Boris Cherny (who is the creator of Claude Code) answered my first question: Audience: I was wondering what was the hardest implementation, like part of the implementation for you of building it? Boris: I think there’s a lot of tricky parts. I think one part that is tricky is the things that we do to make bash commands safe. Bash is inherently pretty dangerous and it can change system state in unexpected ways. But at the same time, if you have to manually approve every single bash command, it’s super annoying as an engineer. Boris: … the thing we landed on is there’s commands that are read-only, there’s static analysis that we do in order to figure out which commands can be combined in safe ways, and then we have this pretty complex tiered permission system so that you can allow list and block list commands at different levels. This highlights a key insight: In agentic systems, safety isn’t an afterthought—it’s the core challenge. How do we know if a command is safe to run? How can these tools predict the consequences of an action? Currently, the burden is shifted to the developer via permission dialogs. But eventually, developers will expect these tools to act more autonomously—without compromising safety. For commands that only affect local environments, Docker might offer a partial solution. But many real-world use cases involve remote effects—like modifying a task in Linear or changing a GitHub label. These remote side effects raise thorny questions about trust, auditability, and failure handling. After exploring Claude Code and Gemini CLI, I’m excited about where this space is headed. The next breakthroughs may come not just from smarter agents—but from safer ones. – EOF –

2025/6/27
articleCard.readMore

微信读书:LLM 自动化问答 PK

为了增加用户活跃度,微信读书团队开发了一个微信小游戏——问答 PK。这是一个双人对决形式的知识问答天梯,题目内容主要基于常识,比如成语填字,古诗词接上下句。 玩了几天后发现,光靠我的知识储备和记忆力,很难持续提升段位。答案在网上一搜就能找到,但是 10 秒钟的答题时间来不及搜索,于是我想到借助 DeepSeek 来自动答题。说干就干,Vide-Coding 了一个 Python 脚本,自动化了整个答题过程,并最终达到了最高等级。本文记录在开发过程中,遇到的问题与一些观察。 技术难点与观察 OCR 错误率导致的复杂度 我首先想到的是将窗口截图转为文字,这一步涉及图片到文字的模态转换: macOS 自带的 OCR 中文识别准确率并不完美。有些中文字符在不同帧中会被错误识别为相似字形。 为了判断题目是否更新,程序需要实现较复杂的题目刷新检测逻辑。 在存储与提取已答题目上,也因此增加了额外复杂度。 后来想到可以利用 macOS 的 Accessibility API 来获取小程序窗口的文字信息,实现起来就简单多了。 结论: 如果可以获取文本内容,应当优先使用文本内容,尽量避免不必要的复杂度。 第一个想到的方法不一定是最好的方法,实现之前可以再多花一点时间比较一下其他方法。 反馈机制的设计 LLM 并不能保证每道题都能准确回答,因此,需要设计一种反馈机制,用于处理错误回答,并逐步提高系统表现: 每次答题后,程序会记录实际答案与 LLM 输出是否一致。 若识别为错误,会将题目及正确答案保存进本地题库,供后续匹配使用。 随着题库积累,LLM 的回答可以逐步退居辅助角色,以“已知题目匹配”为主、生成式回答为辅。 在实践中,这种混合策略显著提高了答题准确率,也使系统更加可控。 工具效率与资源消耗 这类依赖模态转换和实时反馈的程序在效率上也面临挑战,尤其当一方发生变化、但未提供明确的推送机制时,工具只能通过“轮询”方式不断查询变化状态: 本例中,为了判断题目是否已经刷新,程序只能定期抓取小程序里的文字内容,并比对,轮询带来了显著的资源消耗。这种“拉取式”的检测逻辑效率低下,不适合长期运行。 本质上,这类问题的根源在于缺乏变化触发的事件通知机制。如果 macOS 或目标应用能提供“题目变动事件”的观察接口,将显著提高系统效率。期待苹果在接下来的几年持续进化 macOS 来帮助第三方软件加入更多 AI 驱动的功能。 实现的过程中用到了 MacPaw 开源的 macapptree 来抓取应用的 Accessibility Tree。估计 MacPaw 团队在开发 Envy 的 actions 也依赖 Accessibility API 来实现各种软件的自动化。 结论:在系统设计中,应尽量选择或构建具备事件驱动机制的组件,避免盲目轮询所带来的能耗与复杂度。 Vibe-Coding 作为一个 Weekend Fun Project,没有 Vibe-Coding,我无论如何也无法在两三天里快速迭代实现各种预想中的功能,修复各种 bug,并最终把程序跑起来,自动化整个答题过程的。不得不说,有了 Cursor 以后,没有办法回到一行一行写代码的日子了。Vibe-Coding is fun and the future for everyone。 – EOF –

2025/6/22
articleCard.readMore

Working on Moonshot Projects

Sundar Pichai: CEO of Google and Alphabet | Lex Fridman Podcast: Sundar Pichai views “moonshot” projects as crucial for several reasons: Driving Innovation: He believes that aiming for audacious, seemingly impossible goals, like the original moon landing, forces radical rethinking and leads to breakthroughs that wouldn’t happen with incremental improvements. It’s about finding “10X” improvements rather than “10 percent” improvements. Inspiring Talent and Passion: Big, challenging problems ignite both the hearts and minds of people. It’s easier to attract passionate and talented individuals to work on projects that could redefine humanity. Societal Impact: Moonshots, even if their initial goal is not fully realized, can lead to numerous technological advancements with real-world applications and inspire future generations. For example, Google considers fighting climate change as a “moonshot” due to its profound societal importance. Leveraging Constraints: Pichai has also highlighted that constraints can act as catalysts for innovation. Working within defined limits encourages teams to be more creative and focused, leading to groundbreaking ideas.

2025/6/11
articleCard.readMore

Vibe Coding - Baby Sleep Tracker

To monitor our baby from other rooms, we purchased a Nanit Baby Monitor. Using image recognition, Nanit provides insights into our baby’s nighttime sleep patterns through its app. Each state transition point includes a video for review. However, the display isn’t very intuitive — the chart doesn’t show the exact timestamps for each transition. For example, the start and end times of the two longer sleep sessions are not clearly marked. To more intuitively view this information and more flexibly display the baby’s sleep duration and time periods throughout the night, I used Cursor and video-coding to build a Web App: Fetch data from Nanit API for any given date Render sleep sessions throughout the day Plot sleeping trend of most recent dates Lessons learnt: Think through the main features and their designs you want before code generation with Cursor. Although LLM can generate code for you. You would still need to think through what are the features you have in mind, and what things would look like (the design). This reminds me how Firebase Studio is trying to help build a PRD (Product Requirements Document) before beginning to generate code. Remind me apps like https://stitch.withgoogle.com/ Think about testing if you would like to have some code maintainability. Fully AI generated code without any review and test is not maintainable. As a weekend project to meet myself’s requirements, I didn’t put much effort into how to make it maintainable. I feel the joy of vibe coding goes down slowly when I put more features to it as new changes could break existing features. I probably should add some end-to-end tests to make sure that new changes won’t break existing features. However, I didn’t figure out how to put tests in the iteration loop in Cursor yet. Tighter development loop and more agentic behaviors are needed. Cursor stops itself frequently even with agent mode to ask for all kinds of inputs: human input (confirmation, or opinion on design choices) app console output For the human input, I found myself becoming the bottleneck for it to do more useful things. When it’s waiting for some input, I wish it would begin working on other parts which don’t require human input. For the app console output, I wish it has a tighter loop so that I don’t need to copy console output from Chrome DevTools back to Cursor. (Maybe Chrome could provide something to close the loop here?) Analyzing images through AI generated code doesn’t work. As Nanit doesn’t provide a way to export data, I was trying to use app screenshots to parse the sleep information (which is challenging for me to code manually), and it turns out that the current AI models cannot do that as well even with dozens of prompts back and forth. I ended up using Proxyman to capture HTTPs requests and responses from the Nanit app to understand the API, and calling that directly from Python. Used some go code from https://github.com/gregory-m/nanit in the prompt to help LLM to implement the authentication part.

2025/6/4
articleCard.readMore

独立思考的人

独立思考的人, 世界上大部分的问题悬而未决, 观点就像流过身体的水, 保持质疑一切的态度, 听到一个观点之后, 做好随时修正持有观点的准备, 论辩不是为了输赢, 放下偏见和自傲,

2025/4/25
articleCard.readMore

Magic Moment

使用了一整天 MacWhisper 之后的感受: 语音输入文字本身并不是什么新鲜的功能,但就像 iPhone 键盘 的诞生一样,它背后仿佛存在着一道无形的界限——在跨越这道界限之前,一切都显得繁琐笨重;而一旦突破,用户才能真正感受到那种 Magic Moment,仿佛一切变得自然、顺畅,甚至有些神奇。

2025/4/22
articleCard.readMore

《思辨力35讲:像辩手一样思考》读书笔记

《思辨力35讲:像辩手一样思考》是最近读到的干货满满的一本书。 这本书前两章系统地整理了分析问题的逻辑框架和常见的逻辑谬误,对于如何提高思辨能力能有帮助。第三章辩论实战部分讲如何应用在辩论中,对于不直接参与辩论的读者不如前两章实用。 塑造理论的整体结构(第二章的内容) MECE(Mutually Exclusive, Collectively Exhaustive) 定义:相互独立、完全穷尽。这些点与点彼此不重合,叫相互独立;它们加在一起能够完整地覆盖对这个问题的分析,叫完全穷尽。 MECE这个概念对我比较有启发,工作中的一些讨论缺乏对问题的总体上的思考。 明确定义是讨论的开始 明确定义,达成共识,挖掘更深洞见 有标准,才有意义 比较标准是建立论证的关键因素 比较标准的公开是建立共识的前提。选择辩论队员上场的例子。 检视标准是发现分歧、明确重点的方式 比较标准的反驳:有效性、合理性与归谬反驳 明确比较标准:洞悉底层价值,引导决策方向 权衡价值与利益的“需根解损” 政策性辩论/价值性辩论 需根解损是政策性辩论的分析框架 概念: 需求:可以是问题导向(空气污染)、利益导向(更好的工作)或目标导向(更文明的社会)。 根属性指的是之所以会存在这个需求,其根本原因是什么。 解决力,也就是这个政策解决问题的效果。包含可行性和效果。 损益比,比比落实这个政策带来的好处和它产生的弊害,划算吗? 量化和补救措施 需根解损这个概念我是在这本书里第一次了解到。工作当中常用的一个决定项目优先级的框架和这个有相似之处:RICE(Rich,Impact,Confidence,Effort)。 没有绝对共识,但可比较利弊 为生命提供避风VS助长遗弃之风 利弊比较:让思考完整清晰,但没有绝对真理。利弊比较往往涉及到价值排序,所以因人而异,难以有绝对的共识。 利可否被替代,弊可否被规避 寻找同一标尺,平行比较利弊 看清事件本质,用价值排序判断利弊 不说废话,从“决胜点意识”开始 辩论中的决胜点意识:对,但为什么更对 明确目的,达成目的 论证观点,检视自己 如何论证论点? 论证的三个部分:逻辑、事实、价值 论证强度与论证责任 演绎论证:前提真实,逻辑有效,结果必然 归纳论证:结论超越前提,缺乏绝对有效性 归纳论证的4种方法:摆事实、举数据、讲机理、举例子、引用权威理论。 论证强度:标准不统一,视损益比而定 比例原则:论证强度与对应行为成比例 推定利益与举证责任 让道理听得进去 用例子完善逻辑,用故事锦上添花 说服力 常见的逻辑谬误(第一章的内容) 相关不等于因果。“错把相关当因果”是我们生活和工作中最常见的逻辑错误之一。 因果倒置 C同时带来A和B 如何克服:尝试反向思维,对于观点A带来B,B带来A成立吗;控制变量; 实然不能论证应然。 概念理解 如何理解“落后就要挨打”这句话?第一种理解:落后时更容易有人来欺负我。第二种理解:如果我落后了,别人打我、欺负我无可厚非,落后的人和国家就应该被欺负,甚至被消灭。两种不同的理解分别对应了两个概念——实然和应然。实然,descriptive,是指对现实的描述;应然,normative,讨论的是什么是应该的、好的、对的、值得追求的。这一讲我们就来区分这两个概念。 区分实然还是应然 门当户对是否过时?实然层面,只需要做问卷调查。应然层面,探讨现代人应不应该还在乎门当户对。 实然不能论证应然 对于存在即合理的误读。“合理”在黑格尔的原意是:凡是现实的都是有原因的、可被归因的、有迹可循的。 实然是对真实世界的确认,属于求真。应然是道德层面上的讨论。 行,但不对 行不行,指的是这些行为能否实现行为实施者的功利性目的;对不对,指的是这些行为在道德上是不是正义的和应该做的。 营救式刑求,行不行? 用一个例子来讲解功利道德观和道德绝对主义道德观之间的交锋。 利弊权衡中隐藏的风险与危机 功利主义更容易被认同。 如何推广这种绝对的道德观?创造某种沉浸式的体验;论证为什么持这样的道德观的世界会更好,这有些类似在功利主义角度去辩驳,杀一也许不能救百。 滑坡是谬误,也是合理质疑 滑坡谬误:一环连着一环的不成立 如果A发生,B就会发生;如果B发生,C就会发生。后半部分是真的吗? 关于同性婚姻的滑坡论证:有效自愿与道德原则 文明社会的两条最基本的行为原则是自愿和对他人无害。 根属性。一件事情发生的根属性是什么?利于艾滋病传播的因素不见得根属于同性性行为,而是根属于未受保护的同性性行为。 平等与正义之间隔着一个公平 Equity illustration: Equality(平等):每个人都被给予相同的资源或机会,但由于本身的差异,有人仍然无法受益。 Equity(公平):资源分配考虑到了个人的具体需要,使每个人都能达到同样的成果。 Justice(正义):通过系统性的改革(如移除障碍),让每个人都不再需要额外的帮助就能获得平等的机会。 《平权法案》(Affirmative action) 目标状态,起始状态和过渡状态 三段论里的不证自明 引子 大前提:人活着是好事。 小前提:我的伴侣是人。 结论:复活伴侣是好事。 什么是三段论? 大前提,小前提和结论。包含关系。 演绎论证(Deductive Argument)和归纳论证(Inductive Arument) 不是所有分歧都叫偷换概念 什么是偷换概念? 偷换概念指的是在同一思维过程中,用一个概念代替另一不同的概念,也就是说,同样的词或短语在同一个论证逻辑中,第一次和第二次出现时表面意思相同,但是实际上却是两个不同的概念,它违反了同一律要求,从而造成逻辑错误。 类比不当不是偷换概念 “人不可能伤害自己的孩子,因为虎毒还不食子呢!”你可以反驳我这句话是类比不当,因为人和老虎在对待孩子的恶毒程度上不见得足够相似,或者说人类世界的复杂程度要远远高于动物世界的复杂程度。但这并不是偷换概念。 稻草人谬误与红鲱鱼谬误 在辩论中故意把对方的观点曲解为一个更容易反驳的版本然后对其反驳并觉得自己赢了,这就是稻草人谬误。 稻草人谬误是对观点复杂性的粗暴简化 如何反驳稻草人谬误:忠实原则与宽容原则 所谓忠实原则,是当对方表达观点后,我们要尽可能按照他的本意去理解、去复述、去反驳,而不是编造出另一个不符合他本意的东西。 所谓宽容原则,是将疑点、利益归于提出观点的人,尽可能使他的论证有说服力。当然这也要在忠于他的原意的前提下。 在这样的前提下,我们反驳的才是这个观点,否则反驳的只是另一个概念,或者我们战胜的只是对方一时没说清的失误而已。 红鲱鱼谬误(Red Herring Fallacy) 比喻那些为了让人分散注意力而提出的不相干的观点甚至是错误信息。 如何反驳红鲱鱼谬误:识别被转移的焦点 样本偏误不可信 幸存者偏差:无视“牺牲者”的数据谬误 Survivorship bias 选择偏差:具有倾向性的样本无法代表总体全貌 Selection bias:选择样本是不是随机的 自选择偏差:主体自我选择带有的特征会影响因果关系的判定 Self-selection bias 离婚律师分析离婚 参与偏差(无反应偏差) Non-response bias 条件概率:收集信息,理解自己 Conditionial Probability 回避论证过程的循环谬误(Begging the question) 好马不吃回头草,因为吃回头草的不是好马。 进退两难也许只是假象 什么是虚假两难?虚假两难也称非黑即白,指的是在本来有其他选项的情况下,却要求人们做出非此即彼的选择。 光谱思维 人身攻击无法论证观点 人身攻击谬误 诉诸权威谬误 充分吗?必要吗? 比较级:面对有限现状,量化最优选项 我最求高尚,但是不追求更高尚。 充分与必要,充分不必要,必要不充分 霸道定义,包山包海:条件不中立,标准不统一 - EOF -

2025/4/21
articleCard.readMore

Daily Watched YouTube Videos

const svg = document.querySelector('.line-chart') const lineChart = new chartXkcd.Bar(svg, { title: 'Daily Watched YouTube Videos', // optional xLabel: 'Year', // optional data: { labels: ['2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022'], datasets: [ { label: 'Number of Videos', data: [2, 2, 2, 7, 13, 15, 18, 26, 30], }], }, options: { // optional yTickCount: 3, legendPosition: chartXkcd.config.positionType.upLeft } }); - EOF -

2022/5/11
articleCard.readMore

深度体验

明明都是在刷手机,为什么有的时候我觉得自己有所收获,有的时候却觉得是浪费时间? 在我看来,这是深与浅的区别。深指的是内容层面的深,围绕一个固定的主题深入地阅读、理解和体验,得到的信息和情感逻辑连贯,充满细节。浅指的也是内容层面的浅,草草地划过一条由没头没尾信息组成的时间线,看似获取了大量的信息,却不知是大量低质量、重复甚至毫无价值的信息。这里的浅当然还包括行为的被动性。注意力被设计好的时间线牢牢捕获,盲目追求一种完整感,生怕错过一些实际上没什么价值的信息(即 FOMO:Fear of Missing Out)。 深度体验包括但不限于: 阅读一本书 观看一部电影 玩一场剧本杀 与朋友深入交谈 浅层体验包括但不限于: 浏览社交网络 浏览社会新闻 刷短视频 深层体验需要付出努力才能获得,让人获得复杂的情感体验,予人进步。浅层体验无需努力即可获得,让人轻松娱乐,但是长久进行会让人变得麻木,丧失自由意志。时间对每个人都是公平的。花更多时间浅层体验,就势必会减少深度体验的时间。面对充满诱惑的浅层体验,我们必须学会如何分配自己的时间,跳出浅层体验的陷阱。

2022/5/9
articleCard.readMore

家酿 Windows 媒体服务器

和很多人一样,我也喜欢把喜欢的视频、音频拖到本地,待日后慢慢享用。这里一步到位的方案是买一台 NAS 服务器,加上若干硬盘,插上电,下载应用,设置一下,即可开始使用。退而求其次的方法是一直开着一台电脑,把硬盘共享出来。 我只是存一些视频网站上看到的视频,Audible 上买的一些有声电子书,没有那么多大文件需要存储,就没买 NAS,一直是用一台 iMac 来充当这个媒体服务器的角色。搬家以后,iMac 装在箱子里了一段时间,最近老婆新买的桌子到了,才让它重见天日。这台 iMac 的硬盘是 Fusion Drive,容量也只有 1TiB,用起来捉襟见肘。平时主要是老婆在用,如果要当媒体服务器的话,要一直登录着我的账号。Fusion Drive 本来就慢,再加上一个额外的 macOS 账号登录着,跑着一些有的没的进程,更是慢上加慢。这些细节老婆也不清楚,就是觉得游戏开得慢,怨声载道。所以,我就着手另搭一台媒体服务器。 我有一台装了 Windows 的 NUC,本来是设想给它插上 eGPU 来打游戏的,无奈买的 eGPU 插上电就吱吱作响,加上工作书桌上堆得满满登登,再加上 Switch 上的游戏够我玩的了,就下电闲置了,这里刚好让它排上用场。 搬了新家以后,终于有了一个可以放电子设备的角落。我给 NUC 插上了两块移动硬盘,进系统给 Windows 简单设置了一下,确保系统不会自动休眠,远程登录正常,Plex Media Server 可以开机自动启动,一切就准备就系。 为什么没把系统刷成 Linux? 一是懒得折腾,二是万一那天想玩 PC 游戏,可以把 eGPU 插上开撸,三是其他电脑都是 macOS,有一个 Windows 系统跑着才好不要和时代脱节。 如何上传和下载? Windows 10 自带的文件共享功能足够好用了。开启之后,macOS 可以直接通过 Finder > Go > Connect to Server 挂载,挂载之后就是个本地文件夹,可以为所欲为。 远程播放媒体文件的话,推荐 Plex,出门在外也可以播放家里的影音文件。有在手机上离线的需求的话, 可以考虑购买 Plex Pass。 如何备份 NUC 上插的移动硬盘不是为 NAS 设计的,所以每周 7x24 这么跑着,相比 NAS 硬盘而言,更高可能哪天跑着就挂了。尽管重要的数据有其他备份,存在里面的数据没有那么重要,丢了还是怪麻烦的,所以我给这台主机上了份 Backblaze,作为它的远程备份。这样一旦硬盘挂了,可以从 Backblaze 恢复数据。 总结 基本上就是这些,大体上非常满意,折腾起来得心应手。一番折腾下来,最大收获是独立性。在这个视频、音频、照片纷纷被各大公司接管的今天,在本地保留一份拷贝,自由选择使用的方式,完全不受广告和推荐的打扰,实在是难能可贵。 - EOF -

2021/3/14
articleCard.readMore

2020 年订阅付费列表

2020 年,我为以下订阅内容付费: 项目 每月费用 1Password Family Plan $ 4.99 Amazon Prime $ 12.99 Audible Membership $ 14.95 Digital Ocean $ 5 iCloud Storage $ 2.99 Netflix Family Plan $ 11.99 Nintendo Switch Online Family Plan $ 3 Spotify Premium Duo Plan $ 12.99 Stratechery + Dithering $ 12.5 YouTube Premium Family Plan $ 14.99

2020/8/3
articleCard.readMore

Spotify Player

周末花时间学习了一下 React,试写了一个 Spotify 播放器。功能有限,添不添新功能随缘,Spotify 订阅用户可以一试。 访问地址:https://wangyi.ai/player Spotify Web Playback SDK 所限,不支持 Safari 以及手机上的浏览器,具体支持列表见 Spotify 官方文档。

2020/4/25
articleCard.readMore

cloudwu/coroutine 在 macOS 上的 bug

周末阅读了云风八年前用 C 语言实现的协程库。代码非常简洁,只有二百来行,展示了如何基于 ucontext 函数库实现非对称协程(Asymmetric Coroutine),且不同的协程共享同一个栈空间。 运行测试程序的时候发现,测试程序在 Linux 上可以成功运行,然而在 macOS 上却会进入一个死循环,看上去是由于 ucontext 在不同平台的实现不同引起的。于是,花了一些时间阅读 ucontext 在 macOS 上的实现,理解了协程无法继续运行的原因,并提供了一个解决思路。 什么是 ucontext? ucontext 是指 C 语言库函数中用来控制函数调用上下文(context)的一组函数:getcontext, setcontext, makecontext 和 sawapcontext。这组函数可以被用来实现协程。这组函数作为 POSIX 标准只存在了短短七年时间(从 POSIX.1-2001 到 POSIX.1-2008),如今已经被移除了 POSIX 标准,类似的功能改为由 pthreads (POSIX Threads) 提供。尽管这几个函数已经被移除了标准,我们还能在大部分操作系统中找到实现。以苹果为例,macOS 的 ucontext 实现在其网站开源:https://opensource.apple.com/source/Libc/Libc-825.25/x86_64/gen。云风开源的协程库就是在 ucontext 之上实现的。 光说不练假把式,以下是一个简单的用例: #define _XOPEN_SOURCE 600L #include <stdio.h> #include <stdlib.h> #include <ucontext.h> static ucontext_t uctx_main, uctx_func1; #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) static void func1(void) { printf("func1: started\n"); } int main(int argc, char *argv[]) { char func1_stack[1024*1024]; // 131072 if (getcontext(&uctx_func1) == -1) handle_error("getcontext"); uctx_func1.uc_stack.ss_sp = func1_stack; uctx_func1.uc_stack.ss_size = sizeof(func1_stack); uctx_func1.uc_link = &uctx_main; makecontext(&uctx_func1, func1, 0); printf("main: swapcontext(&uctx_main, &uctx_func1)\n"); if (swapcontext(&uctx_main, &uctx_func1) == -1) handle_error("swapcontext"); printf("main: exiting\n"); exit(EXIT_SUCCESS); } // Output: // main: swapcontext(&uctx_main, &uctx_func1) // func1: started // main: exiting swapcontext 要说清楚 bug 的原因,需要阅读 swapcontext 在 macOS 上的实现。由于非常简洁,只有短短十五行,直接上代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) { int ret; if ((oucp == NULL) || (ucp == NULL)) { errno = EINVAL; return (-1); } oucp->uc_flags &= ~UCF_SWAPPED; ret = getcontext(oucp); if ((ret == 0) && !(oucp->uc_flags & UCF_SWAPPED)) { oucp->uc_flags |= UCF_SWAPPED; ret = setcontext(ucp); } return (ret); } 这里的 8~11 行让人费解,先是将 uc_flags 的 UCF_SWAPPED 位设为 0,然后判断该位是不是为0(难道不是一定为 0 ?),如果为 0, 设为 1 并且执行 setcontext,否则直接返回。 打了断点调试了一下才发现,原来这里的判断语句会被执行两次。如图,从 Main 这个 context 来看,第一次是在首次执行 switchcontext 时,因为 UCF_SWAPPED 位刚刚被设为 0,所以会执行 11~12 行,即切换到 Func context,第二次是在 context 被恢复时,因为 getcontext 记录的是其返回地址,所以恢复之后会从第 10 行继续执行,而由于在第一次执行时,UCF_SWAPPED 已经被设为 1 了,所以这次不会执行 11~12 行。 了解了上述机制之后,再看 coroutine 是如何保存堆栈,然后使用 switchcontext 的。 1 2 3 4 5 6 7 8 9 10 void coroutine_yield(struct schedule * S) { int id = S->running; assert(id >= 0); struct coroutine * C = S->co[id]; assert((char *)&C > S->stack); _save_stack(C,S->stack + STACK_SIZE); C->status = COROUTINE_SUSPEND; S->running = -1; swapcontext(&C->ctx , &S->main); } 第 6 行保存堆栈信息,然后在第 9 行调用 swapcontext,由于函数的返回地址是被保存在栈中的,所以在恢复这里保存的 context 时,使用的是第 6 行保存的堆栈,即返回地址为第 7 行,而在 swapcontext 执行完 10~15 行之后,会继续执行 coroutine_yield 的 7~9 行,也就导致 swapcontext 再次被调用,context 被再次切换回 S->main,然而在 S->main 当中会等待协程完成,所以程序进入了死循环。 理解了造成 bug 的原因,修复起来也就不难了。自行实现 swapcontext 的内容,在同一个函数里保存堆栈,然后再执行原有的程序内容即可。 static int save_and_swapcontext( ucontext_t *oucp, const ucontext_t *ucp, struct schedule * S, struct coroutine *C) { _save_stack(C, S->stack + STACK_SIZE); C->status = COROUTINE_SUSPEND; S->running = -1; int ret; if ((oucp == NULL) || (ucp == NULL)) { errno = EINVAL; return (-1); } oucp->uc_flags &= ~UCF_SWAPPED; ret = getcontext(oucp); if ((ret == 0) && !(oucp->uc_flags & UCF_SWAPPED)) { oucp->uc_flags |= UCF_SWAPPED; ret = setcontext(ucp); } return (ret); } ... void coroutine_yield(struct schedule * S) { int id = S->running; assert(id >= 0); struct coroutine * C = S->co[id]; assert((char *)&C > S->stack); save_and_swapcontext(&C->ctx , &S->main, S, C); } 总结 因为是第一次尝试阅读汇编语言,单步调试操作系统提供的函数,再加上函数调用时内存空间的分布在脑子里不是一清二楚,最终花费了一天半的时间,才算彻底弄清楚造成死循环的原因。至于为什么相同的代码在 Linux 上可以成功运行,还有待于进一步阅读 swapcontext 在 GNU 中的实现。 在解决这个 bug 的过程中获益良多:阅读和单步调试了一些汇编语言,复习了一些在《程序员的自我修养》中读到的关于函数调用过程的知识,也算对线程/协程是如何实现的有了一些更底层的认识和理解。 参考链接 直接相关 云风 coroutine 协程库源码分析 | 编程沉思录 The benchmark reports of coroutine 苹果 ucontext 实现相关 Adventure with ucontext on Linux and Mac - albertnetymk’s notes Apple-FOSS-Mirror/Libc PSA: avoiding the “ucontext routines are deprecated” error on Mac OS X Snow Leopard Stack Overflow - What does -D_XOPEN_SOURCE do/mean? Stack Overflow c - Context switching - Is makecontext and swapcontext working here (OSX):switchcontext 在 macOS 上的另一个限制 汇编语言相关 Low-Level Programming: C, Assembly, and Program Execution on Intel® 64 Architecture Notes on x86-64 programming Stock Overflow - What registers are preserved through a linux x86-64 function call Stock Overflow - What’s the purpose of the LEA instruction? Stock Overflow - Word, Doubleword, Quadword Stock Overflow - xorl %eax, %eax in x86_64 assembly code produced by gcc Understanding C by learning assembly - Blog - Recurse Center x64 Cheat Sheet X86 64 Register and Instruction Quick Start - CDOT Wiki x86 ARITHMETIC AND LOGICAL OPERATIONS 调试 DYLD 相关: Stack Overflow - debug disassembled dylib with hopper? Reverse Engineering - disassembly - Importing external libraries in Hopper scripts? - Reverse Engineering Stack Exchange 0xc010d/DYLDSharedCache.hopperLoader: DYLD shared cache loader for Hopper Debugging Dyld - Low Level Bits Reverse | Mini灬哆啦 LLDB 相关 Variable Formatting — The LLDB Debugger Stack Overflow - Watch points on memory address Stack Overflow - xcode - How to print memory in 0xb0987654 using lldb? - Stack Overflow Linux 的 swapcontext 实现相关 swapcontext.S source code [glibc/sysdeps/unix/sysv/linux/x86_64/swapcontext.S] - Woboq Code Browser glibc/swapcontext.S at master · git-mirror/glibc · GitHub Stack Unwinding / _Unwind_Frames_Extra on Linux 相关 使用LeakTracer检测android NDK C C 代码中的memory leak EditNew Page WolfcsTech Deep Wizardry: Stack Unwinding Github Search · _Unwind_Frames_Extra Using the GNU Compiler Collection (GCC): x86 control-flow protection intrinsics 其他 Coroutine in Boost - 1.72.0 danluu.com danluu/debugging-stories: A collection of debugging stories. PRs welcome (sorry for the backlog) :-) danluu/setjmp-longjmp-ucontext-snippets: Implementing coroutines, channels, message passing, etc. davidbalbert/thimble: A small OS that doesn’t do much sigaltstack sigsetmask Stack Overflow - c - Is there something to replace the functions in ucontext.h?

2020/2/18
articleCard.readMore

我的 macOS 软件列表(2020 年)

距离上次列出我的软件列表,已经有两年有余。这两年多,因为大部分时间在使用公司的笔记本,用我自己笔记本做的事情有了很大不同,再加上期间换硬盘的原因,又重装了几次电脑,有一些两年前经常使用的软件,如今已经不再使用了。这里列出仍在频繁使用的软件,以供将来按图索骥。 软件名称 用途 1Password Family Plan 付费用户 Alfred 用来用去,还是不习惯系统自带的 Spotlight,所以就换回了 Alfred BackBlaze 备份 CodeRunner 学习各种编程语言 Docker 学习 Docker Homebrew 装一些命令行的软件 Intel Power Gadget 监控 CPU 负载 iSat Menus 在 Menu Bar 上实时显示: 上传和下载的网络速度,CPU 的当前温度 MDBG Chinese-English Dictionary 新发现的中英词典,分词之后的翻译非常好用 MindNode 整理思路,读书笔记 MWeb 中文博客书写必备 NetNewsWire 偶尔打开,阅读关注的技术博客 Notes 全功能笔记应用 Safari 浏览因特网 Spectacle 窗口管理 Spotify Family Plan 付费用户 Steam 买游戏 Sublime Text 复杂文本编辑 Transmit 博客文件管理 Triode 电台休闲时光 Twitter 新闻客户端 Turbo Boost Switcher Pro 现在在使用的这个笔记本,是 2012 年上市,最初代的 15 寸带 Retina 屏幕的 Macbook Pro。在经历了近七年的不间断使用之后,除了电池之外的各个部件运行良好。使用起来唯一的困扰就是,这颗四核 i7 的处理器在开启 Turbo Boost 之后,单核频率会达到在 3.0 GHz 以上,并迅速把 CPU 温度升到 100 摄氏度左右,然后风扇全速运转,其噪声让人心烦到无法使用。后来购入了 Turbo Boost Switcher Pro,以便在不需要这些额外计算力的时候,关闭 Turbo Boost,才得以安静地使用。 了解这个软件主要是在 Accidental Tech Podcast 上。期待苹果在今年的 macOS 上加入 Low Power Mode,这样就不需要这个实现上有点危险的软件了。 - EOF -

2020/1/27
articleCard.readMore

Docker 入门

Docker 说到底就是一个轻量级的“虚拟机”管理器,只不过这里的“虚拟机”不是真正的虚拟机,而是用起来像是虚拟机的一种东西,姑且称之为容器(Container)。之所以较之虚拟机更为轻量级,这是因为运行这些容器的其实是同一个操作系统。 Docker 作为一个整体的解决方案,提供的是一整套围绕容器的解决方案,包含如何构建容器,如何分发容器以及如何运行容器。 如何构建和分发容器 容器在被运行起来之前,有另外一个名字——镜像(image),这里你可以把镜像和容器的关系想象成程序和进程的关系。 Docker 提供了两种方法来构建镜像,一种是直接使用别人提供的镜像(image),一种是在别人镜像的基础上,提供 Dockerfile 构建镜像。当然,这两者都离不开一个默认的分发平台——Docker Hub。Docker Hub 就相当于一个镜像的“菜市场”,你可以在这里挑选你需要的镜像。主要的命令有 docker pull 和 Docker push。 $ docker pull --help Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST] Pull an image or a repository from a registry Options: -a, --all-tags Download all tagged images in the repository --disable-content-trust Skip image verification (default true) --platform string Set platform if server is multi-platform capable -q, --quiet Suppress verbose output $ docker push --help Usage: docker push [OPTIONS] NAME[:TAG] Push an image or a repository to a registry Options: --disable-content-trust Skip image signing (default true) docker pull 用来下载镜像,docker push 用来上传镜像。 比如说下面几条命令就是下载一个镜像,改了名字,上传到你的 Docker Hub 上: $ docker pull l.gcr.io/google/bazel:latest $ docker image tag l.gcr.io/google/bazel <your docker hub name>/bazel:1.0 $ docker push <your docker hub name>/bazel:1.0 更多和镜像相关的命令可以通过 docker image --help 来查看 $ docker image --help Usage: docker image COMMAND Manage images Commands: build Build an image from a Dockerfile history Show the history of an image import Import the contents from a tarball to create a filesystem image inspect Display detailed information on one or more images load Load an image from a tar archive or STDIN ls List images prune Remove unused images pull Pull an image or a repository from a registry push Push an image or a repository to a registry rm Remove one or more images save Save one or more images to a tar archive (streamed to STDOUT by default) tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE Run 'docker image COMMAND --help' for more information on a command. 接下来是基于 Dockerfile 的构建。具体的用法可以参见官方文档。 如何运行容器 有了镜像之后,就可以开始运行这些镜像了。最主要的命令就是 docker run,这个命令可以被用来运行一个新的容器。最常用的几个选项有 -i, --interactive 连接输入输出。 -t, --tty 分配一个虚拟的 TTY -v, --volum list 挂载一个硬盘 -p, --publish list 暴露一个容器的端口给宿主机,宿主机端口:容器端口 --name 指定生成的容器的名字 譬如说,新建一个容器 $ docker run -itv $(pwd):/issue-tracker \ -p 8080:80 \ --name development \ --entrypoint /bin/bash \ l.gcr.io/google/bazel 连入一个正在运行的容器 docker exec -it development /bin/bash $ docker run --help Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container Options: --add-host list Add a custom host-to-IP mapping (host:ip) -a, --attach list Attach to STDIN, STDOUT or STDERR --blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0) --blkio-weight-device list Block IO weight (relative device weight) (default []) --cap-add list Add Linux capabilities --cap-drop list Drop Linux capabilities --cgroup-parent string Optional parent cgroup for the container --cidfile string Write the container ID to the file --cpu-period int Limit CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota --cpu-rt-period int Limit CPU real-time period in microseconds --cpu-rt-runtime int Limit CPU real-time runtime in microseconds -c, --cpu-shares int CPU shares (relative weight) --cpus decimal Number of CPUs --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) -d, --detach Run container in background and print container ID --detach-keys string Override the key sequence for detaching a container --device list Add a host device to the container --device-cgroup-rule list Add a rule to the cgroup allowed devices list --device-read-bps list Limit read rate (bytes per second) from a device (default []) --device-read-iops list Limit read rate (IO per second) from a device (default []) --device-write-bps list Limit write rate (bytes per second) to a device (default []) --device-write-iops list Limit write rate (IO per second) to a device (default []) --disable-content-trust Skip image verification (default true) --dns list Set custom DNS servers --dns-option list Set DNS options --dns-search list Set custom DNS search domains --domainname string Container NIS domain name --entrypoint string Overwrite the default ENTRYPOINT of the image -e, --env list Set environment variables --env-file list Read in a file of environment variables --expose list Expose a port or a range of ports --gpus gpu-request GPU devices to add to the container ('all' to pass all GPUs) --group-add list Add additional groups to join --health-cmd string Command to run to check health --health-interval duration Time between running the check (ms|s|m|h) (default 0s) --health-retries int Consecutive failures needed to report unhealthy --health-start-period duration Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s) --health-timeout duration Maximum time to allow one check to run (ms|s|m|h) (default 0s) --help Print usage -h, --hostname string Container host name --init Run an init inside the container that forwards signals and reaps processes -i, --interactive Keep STDIN open even if not attached --ip string IPv4 address (e.g., 172.30.100.104) --ip6 string IPv6 address (e.g., 2001:db8::33) --ipc string IPC mode to use --isolation string Container isolation technology --kernel-memory bytes Kernel memory limit -l, --label list Set meta data on a container --label-file list Read in a line delimited file of labels --link list Add link to another container --link-local-ip list Container IPv4/IPv6 link-local addresses --log-driver string Logging driver for the container --log-opt list Log driver options --mac-address string Container MAC address (e.g., 92:d0:c6:0a:29:33) -m, --memory bytes Memory limit --memory-reservation bytes Memory soft limit --memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) --mount mount Attach a filesystem mount to the container --name string Assign a name to the container --network network Connect a container to a network --network-alias list Add network-scoped alias for the container --no-healthcheck Disable any container-specified HEALTHCHECK --oom-kill-disable Disable OOM Killer --oom-score-adj int Tune host's OOM preferences (-1000 to 1000) --pid string PID namespace to use --pids-limit int Tune container pids limit (set -1 for unlimited) --privileged Give extended privileges to this container -p, --publish list Publish a container's port(s) to the host -P, --publish-all Publish all exposed ports to random ports --read-only Mount the container's root filesystem as read only --restart string Restart policy to apply when a container exits (default "no") --rm Automatically remove the container when it exits --runtime string Runtime to use for this container --security-opt list Security Options --shm-size bytes Size of /dev/shm --sig-proxy Proxy received signals to the process (default true) --stop-signal string Signal to stop a container (default "SIGTERM") --stop-timeout int Timeout (in seconds) to stop a container --storage-opt list Storage driver options for the container --sysctl map Sysctl options (default map[]) --tmpfs list Mount a tmpfs directory -t, --tty Allocate a pseudo-TTY --ulimit ulimit Ulimit options (default []) -u, --user string Username or UID (format: <name|uid>[:<group|gid>]) --userns string User namespace to use --uts string UTS namespace to use -v, --volume list Bind mount a volume --volume-driver string Optional volume driver for the container --volumes-from list Mount volumes from the specified container(s) -w, --workdir string Working directory inside the container 所有和容器相关的命令可以通过 docker container --help 来找到: $ docker container --help Usage: docker container COMMAND Manage containers Commands: attach Attach local standard input, output, and error streams to a running container commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem exec Run a command in a running container export Export a container's filesystem as a tar archive inspect Display detailed information on one or more containers kill Kill one or more running containers logs Fetch the logs of a container ls List containers pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container prune Remove all stopped containers rename Rename a container restart Restart one or more containers rm Remove one or more containers run Run a command in a new container start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers wait Block until one or more containers stop, then print their exit codes Run 'docker container COMMAND --help' for more information on a command. 掌握了基本概念和基本用法之后,才能不在每次使用时都新建一个容器,而是恰当地选择继续使用已有的容器,或者新建容器。

2020/1/19
articleCard.readMore

Minimum Selenium Tutorial

Selenium is an umbrella project for a range of tools and libraries that enable and support the automation of web browsers. In my own words, it’s a solution for you to manipulate a browser in scripts. As you can imagine, this can be useful in many ways. In tech companies, this is used to test web pages. For personal projects, we can use it to crawl some information which is hard to query directly. There are quite a few programming languages supported to write Selenium scripts. Here in this tutorial, I will use Java. As a minimum Selenium tutorial, CodeRunner, which means the native macOS application, not the VS Code extension, will be used instead of a completed IDE. First, download ChromeDriver from this Google site, which is a binary file, and save it somewhere for future usage. Please pay attention to the version you are downloading, as you will need the exact version as your Chrome assuming that you have already had Chrome installed. Secondly, download Java Selenium Client from Selenium’s website. After uncompress, it should looks like this: The last step, open up a new CodeRunner tab with Java as the selected language. Copy and paste the following code: import org.openqa.selenium.*; import org.openqa.selenium.chrome.*; class Untitled { public static void main(String[] args) throws InterruptedException { System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver"); WebDriver driver = new ChromeDriver(); driver.get("http://www.google.com/"); Thread.sleep(5000); // Let the user actually see something! WebElement searchBox = driver.findElement(By.name("q")); searchBox.sendKeys("ChromeDriver"); searchBox.submit(); Thread.sleep(5000); // Let the user actually see something! driver.quit(); } } To compile above code with the downloaded Selenium Java client library, some setting need to changed in CodeRunner. Click “Run Settings…” button in the tool bar, and put the following code to the “Run Command” section: java -cp "${compiler%:*}:/path/to/selenium-java-3/client-combined-3.141.59.jar:/path/to/selenium-java-3/libs/*" "${compiler#*:}" and put the following line to the “Compile Flags” section: -cp "/path/to/selenium-java-3/client-combined-3.141.59.jar" Now the setting should looks like this: Click “Run”, and you should have Chrome running and following your script now. - EOF -

2020/1/14
articleCard.readMore

Migrate Away from Octopress

I have been using Octopress since 2012, and it works fine for me in all these years. But unfortunately the project has been abandoned since January 2015, which means it depends on a lot of legacy packages, and misses a lot of fancy new features. For example, the version I was using depends on jekyll-0.11.2, while jekyll-4.0.0 was already released in August 2019. Although I don’t bother using the legacy software and was satisfied with the feature set as long as it’s working, setting up a new environment for the legacy software becomes harder and harder. On macOS, I need to use rbenv to compile and install a specific Ruby version for Octopress: Ruby at 1.9.3-p392. As the version is very old, when using Apple’s latest compiler (Apple clang version 11.0.0) or other GCC versions which are available on HomeBrew (I have tried GCC-4.9 and GCC-9), there are warnings during compilation (see this GitHub issue for an example warning), which ensures a failed installation. $ rbenv install 1.9.3-p392 Downloading yaml-0.1.4.tar.gz... -> http://dqw8nmjcqpjn7.cloudfront.net/36c852831d02cf90508c29852361d01b Installing yaml-0.1.4... Installed yaml-0.1.4 to /usr/local/opt/rbenv/versions/1.9.3-p392 Downloading ruby-1.9.3-p392.tar.gz... -> http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p392.tar.gz Installing ruby-1.9.3-p392... BUILD FAILED Inspect or clean up the working tree at /var/folders/mx/mfxgb8450d97ssnd588_bg980000gn/T/ruby-build.20130222110749.98264 Results logged to /var/folders/mx/mfxgb8450d97ssnd588_bg980000gn/T/ruby-build.20130222110749.98264.log Last 10 log lines: compiling safe.c compiling signal.c compiling sprintf.c compiling st.c st.c:520:35: error: implicit conversion loses integer precision: 'st_index_t' (aka 'unsigned long') to 'int' [-Werror,-Wshorten-64-to-32] i = table->num_entries++; ~ ~~~~~~~~~~~~~~~~~~^~ 1 error generated. make: *** [st.o] Error 1 make: *** Waiting for unfinished jobs.... It’s for sure that I can dive into the issue and solve it for now1, but it also means that I have to go through the fix again and again to setup new environments. Besides, Octopress 2.0 is just a bunch of Ruby plugins and a beautiful theme on top of Jekyll, which is hard to understand 2, maintain and upgrade 3. With a such layer in the middle, I feel frustrated when I want to change my blog’s behaviors, but find out that I couldn’t figure out how to do it. With these obstacles on my way forward, I decided migrating away from the legacy blog system. There are two ways in front of me: Build a static blog generator from ground up with minimum features I need for my blog, most likely in Python, as learning Ruby before writing the project is too much fun for a weekend project. Migrate to the latest version of Jekyll. No matter which way to way, I need to trim the current code base to figure out what’s the minimum feature set I need for my blog. In my old blogs, I mainly use the following Plugins from Octopress: Code Block. { % codeblock %} code snippet { % endcodeblock %} Include Code. { % include_code [title] [lang:language] path/to/file %} Gist Tag. { % gist 4321346 %} Block Quote. { % blockquote [author[, source]] [link] [source_link_title] %} Quote string { % endblockquote %} Image Tag. { % img [class names] /path/to/image [width] [height] [title text [alt text]] %} For the first two usages, it’s straight-forward to replace them with triple backticks ```. For Gist tag, replace them with the GitHub embedded script. For quote block, switch to the standard markdown syntax: > at the beginning of the paragraphs I want to quote. For image tag, I mainly use the tag to set a width or height to prevent an image becomes too large, which can be achieved with the following syntax support from kramdown. ![smiley](smiley.png){:height="36px" width="36px"} After all these changes, my blogs finally don’t contain any Octopress specific syntaxes. In the process of replacing all these usages, I began getting familiar with how Octopress works on top of Jekyll, and realized that it’s just a bunch of Ruby plugins, so it’s possible to migrate to Jekyll, while keeping the current theme and layouts with small updates to the current html templates. Although I am not married to the theme, I did spend a lot of time tweaking the CSS to make it look right. Several hours later After several hours tweaking, I have successfully migrated my blog to Jekyll 4.0.0, and it’s blazing fast now! With Octopress, it often takes more than 10 seconds to generate, while now, it only take less than 2 seconds. Besides, I am familiar with all the templates now and feel empowered to make any change. Yo Ho!🍺 PS: As I have a very unique setting for my blog (no comments, no sharing, made a lot of changes to the Octopress default theme), I am not sure whether or not the way I migrate will be useful for others. Please send me an email if you are interested to check it, and I can share it with you. there are many ways to do so, but I don’t plan to expand them. ↩ Mostly because I don’t know Ruby at all. ↩ See this blog for more explanations about why it’s hard to upgrade Octopress from the author. For similar reasons, I didn’t upgrade my blog to Octopress 3.0. ↩

2020/1/13
articleCard.readMore