Contents

I graduated from Shanghai Jiaotong University in 1997 and received my Ph.D. from Osaka City University in 2004. I began my career as a software engineer at a small startup. In 2007, I joined OMRON Corporation, where I have spent nine years developing various computer vision technologies for mobile applications. In 2016, I established my own company, tiwaki Co., Ltd. I am now a chair professor of Dalian University of Technology (DUT). To learn more about me, please check my posts on this website written in English, Chinese or Japanese.

As an engineer, I developed the world’s first commercial facial beautifier application for digital cameras and mobile phones in 2007, prior to the release of the first generation of the iPhone. Currently, I hold over 50 patents including granted patents and patent applications in progress. 1 A few of my patents can be found here.

I am working on problems related to computer vision and machine learning. My research interests include saliency detection, object detection, visual retrieval and more. I serve as reviewer for many top tier journals and conferences such as TPAMI, TIP, CVPR and ICCV, and others. I maintain the well-known saliency detection dataset DUT-OMRON and DUTS. Additionally, I am the author of the python implementation of Manifold Ranking Saliency algorithm. You can find my work on Google Scholar and DBLP.

I embarked on a new adventure in my career as an entrepreneur in 2016. Running a startup is never easy, but I relish the challenge and am constantly learning something new.

很多年前写专栏的时候,有一帮笔友。有一次大家说要写一个命题作为接龙,就叫我的1976。我记得当时在家里很无聊,对着网络论坛敲了20多分钟。最近看一个朋友把他的旧作翻出来帖在朋友圈,我找了一下,我的居然也还在,那就也发出来备份一下。一晃已经是20年前的文字了。那时候我年轻得和sb似的,写了报纸专栏赚口粮还有功夫在网络上和人逗贫,除了有病还真的有时间。。

1976年周总理去世。我和所有人一样,哭得死去活来,白天哭,晚上哭,想起来就哭,想不起来也哭。我和很多人一样,根本不知道为什么就哭,哭到后来,自己以为自己知道了,就接着哭。

1976年唐山大地震,我在我们院儿的招待所楼下,朦朦胧胧得看着前面摇摇欲坠的大楼,半睁着睡眼,用眼睛记录下历史一刻,然后在以后的睡梦里多次回顾。有人告诉我,我那天依然在微笑,所谓泰山崩于前而不动声色者,鄙人是也。不服的,出来溜两圈儿?

1976年毛主席也驾甭了。再哭过周总理后,我继续保持旺盛的精力哭着毛主席。那年我还没有参加工作,有的是时间,因为总是吃不饱肚子,虽然现在不记得了,但是可能当时觉得毛主席晚驾甭两年,我们可以吃得更饱,所以饿醒了就哭,真感人。

1976年文革结束。我的父辈也和我一样,不记得当时什么感觉,可能高兴,可能伤心。

1976年中国第一颗返回式人造卫星成功上天,成功落地。当时我根本不知道这个事情,很多年之后,有人回顾历史,于是我和大家一起欢欣鼓舞,士气高涨。

1976年,我对这个世界有着纯朴的感情。不思考环境污染问题,不思考WPO,不思考人口过剩,不思考社会道德沦丧,信用度低的问题,不思考中美关系,不思考反日运动是非成败。有人说1976年对中国有着非凡的意义,但是我觉得吕不韦纳妾那年对中国有着更非凡的意义,不过因为大家都没机会掺和一下,所以就忽略了它。

1976年我对世界的看法简单而直白,并且现在一点也想不起来。

1976年,我面对这个从来没有也永远不会干净起来的肮脏的世界充满犹豫。有时,我会撅起屁股,直接给它一泡屎,我的尿冲天而起,有力而愤怒!这不是行为艺术,这是一个人对世界本来应该有的本能的抗争。

过了1976年后,我开始懂得看人的脸色,听人的口气,有人说1976年后中国走向新世纪,其实如果你和我一样的状态走过1976年,你就会知道,1976年和任何一个年代都没有区别。

1976年,我正式满一岁了。

这两天看了几部新老电影。

  • 阿凡达3

    去电影院之前,因为家附近没有imax,觉得有点遗憾,不过看完电影后,遗憾荡然无存。三个小时饱和的不要不要的色彩,场景,声光电,如果还是imax,我觉得自己这老朽的身板扛不住。这个系列我看还是就算了吧,至此打住最好。事实上即使是第一部,情节上也没太感动我,虽然全世界都在山呼万岁。对我个人而言,阿凡达的终极观影看点还是特技和场景,他就是一部非常棒的,创造历史的爆米花电影。这么说,会被粉丝骂死,但是我得诚实啊。至少我没有从第一部中看到任何深刻的主题,至于大家说的环境保护啥的,我不知道这个事儿有什么值得被如此吹捧的。抛开环境保护这么个具而体的概念,阿凡达本质上其实就是一个讲殖民和反殖民的电影,聊的是被无数左派(卡梅隆是左派没错吧)艺术家玩残了的概念。当然,我们不去judge这种左右派的逻辑,只是说在一个相对比较陈旧的主题下,伸拉硬拽得延展到第三集,其实已经很为难卡梅隆老师了。还是抛开大场面的审美疲劳,继续说内容。阿凡达的情节设定很乌托邦,拍一集没问题,连续拍下去,乌托邦是撑不住的。到了这一集里,潘多拉开始出现反乌托邦的坏蛋,那个长得怪吓人的女首领,我也不记得她叫什么,总之她就是不相信潘多拉的理念,而且认为潘多拉大神压根不理睬她,不照顾她。你琢磨这事儿,很简单,编剧自己也不相信如果殖民者不来,这个乌托邦里的各个没事儿就大呼小叫的原始人群就能一直单纯可爱又天真下去。说白了,环境有没有人破坏不知道,一大堆智慧生物凑在一起,总有一天得出点乱子,得有人误入歧途,不然生活都要枯燥起来。这就是所有乌托邦故事的最大bug,和谐和幸福的生活不能靠又傻又天真撑着。但要这么说,那就人性本恶吗?也不是,中国人的祖宗早就说过这事儿,叫:水至清则无鱼。说白了,傻白甜不是问题,问题是傻白甜的幸福生活不能靠只有傻白甜支撑下去。人可以是人性本善的,但这个世界总得有点不和谐才对。没有不和谐,谁知道人性本善的珍贵?所以,阿凡达的情节设定在我看来是有问题的,他从一开始就不是一个可以做系列电影的主题。话说,看了这一集,不管是喜欢还是不喜欢,还有人觉得潘多拉星球和第一集一样是人间天堂吗?人设崩了,再拍续集也行,只是潘多拉不再。所以我看阿凡达就是看个热闹,但是他确实热闹,热闹的值回票价,就这些,不多不少,正好。

  • 攻壳机动队

    无聊在家里看了电影版攻壳机动队。美国人拍的日本动漫,恩,有点怪怪的。就是那种京都街头看到穿着和服逛荡的洋人的感觉。你说这有啥不可的吗?没有。但是你说有多养眼,很难认同,而且他无关颜值。合适这件事儿,不是道德判断,就是:他就不应该是那个样子。语言贫乏,你要实在看不懂,就闭眼琢磨一下。人同此心,你懂的。

    据说《matrix》的创作深受攻壳机动队的影响,但是我觉得攻壳的主题比matrix要深刻很多。他讨论的是,人之所以为人的定义在哪里?这是超越自由意识主题的。如果映射到matrix里面,其实他是在问,matrix里插着管子的同志们难道不可以享受其中吗?这个问题谁能回答?

  • 日挂中天

    辛芷蕾2025年凭借此片斩获威尼斯电影节最佳女演员奖。先说演员,辛芷蕾是好演员,我喜欢。男主角的张颂文,应该也是好演员吧,不过我不是特别能欣赏。张颂文肯定是非常专业非常敬业的演员,但是不知道为什么我总觉得他演戏匠气十足,没有灵气。演员这个职业太残酷了,专业和敬业都不足以完备这个职业。当然这是我个人观点,严重拒绝粉丝讨伐。

    想说的是这部电影,他耽误也浪费了两位好演员(虽然辛芷蕾确实拿到了国际大奖),一言以蔽之,电影配不上演员。这电影应该是所谓文艺片,但是他文艺的点在哪里?我看了大概20分钟后,依然没办法理清楚人物关系。甚至包括辛芷蕾和张颂文在医院的相遇,到了电影差不多后半我才明白,这个相遇是偶然事件,是个多年之后的不期而遇,但是在当时的镜头里,我完全没看出来。导演的剪辑也很无厘头,这电影基本上是线性时间线,但是我就是活生生看得眼球打转,脑浆非线性迸射。问题就在于,他的很多场景是没有前后逻辑关联的,放在前放在后都可以。你可以是文艺的那一趴,但是至少要让作为不懂文艺的我最起码看得懂故事梗概。因为如果你是意识流,你是非线性叙事,我智商缺斤短两看不明白是我的人品和水平问题,但你是狼外婆故事线,从头讲到尾按着地球公转走的,我还是看不懂,那么我即使是俗人也拒绝为你的文艺买单。但是这些还不是最要命的,要命的是他的故事不感人。我能理解辛芷蕾角色的走投无路和狼狈不堪,但她的最后那一刀到底刺的是什么?白白挨了一刀的张颂文到底是替谁在挨那一刀?反正我不太理解。女主当年肇事逃逸,男主为爱顶罪,女主在男主坐牢期间莫名离开,之后多年后相遇开始忏悔,要照顾男主下半生。怎奈生活破碎不堪,无以为继,男主终于要离开,女主被压垮,一刀刺倒男主然后嚎啕大哭。有趣的是,男主挨了一刀之后,忘记了所有对女主的抱怨,貌似无限理解得带着肚子上的刀和女主相拥而泣。这整个一套下来,我只有一个问题,我要不要共情女主?她可能确实过得很辛苦,但是生活并没有对不起她,因为我们不能说肇事逃逸,做小三生子都是生活所迫。我们当然要同情弱者,但是弱者把刀刺向她曾经背叛的,而从来没有对不起她的人,这种崩溃的力量他不感人。我也不是一点不知道导演要表达啥,反正就是生活重压下的无奈呗,这个逻辑确实是通的,但是他担不起最后那一刀。反正我不感动。同样有一把刀子,是杨德昌的牯岭街少年杀人事件,那把刀子捅进去他是感人而又有巨大撕裂感的,因为少年在万般无奈下,只要一刀刺向生活,刺向他的周遭。

    这片子最文艺范的就是女主在厕所里把流产的孩子冲走的镜头。多残酷,多让人鸡皮疙瘩四起,但是我想问,有必要吗?就为了个文艺?没必要。差不多得了。

年轻的时候,为了糊口,写专栏啥的都干过.最近整理一下文件,看看当时写的专栏里的小说,放上来做个备份.糊口之作,随想随写,也不讲究.不过其实我挺喜欢这个题材和写法,以后再无俗事烦身的时候,可能会认真的按照这个玩法,多写些东西.话虽如此,哪天才能再无俗事在心头呢?无妨,且备份:

  本文纯属虚构,与历史不符,和现实雷同。

  春天来得早,刘备又蠢蠢欲动。张飞很不耐烦:哥,诸葛亮到底有什么好?已经去了两次都吃闭门羹,你还要去。一边说,张飞一边修著胡子。世人都以为张飞是莽撞人,其实张飞是文化人,写得一笔好字,而且工于新派诗歌。因为诗的风格过于前卫而不被主流文坛接受。其实他曾经在洛阳“洛漂”过多年,以非主流地下诗人的形象debut,可惜不成功。最终大彻大悟,回来和刘备一起搞民主运动。其实很多年以后,主流开始不吃香,非主流开始吃香,才成就了竹林七贤这些明星人物,说起来张飞是他们的鼻祖。人,生不逢时总是有的。当然这都是后话,也不是张飞所能了解的事情。

  张飞有首新派诗,这样写道:汉朝,如果你是我们中国人的脊梁,那么,请问,尾骨长在何方?在当时没人能明白他写了些什么。张飞曾经和刘备说,其实咱们就是可能已经退化或者幸运地留下来的尾巴骨。刘备以为张飞大脑缺氧,只是跟他说:三弟,争取自由的道路还很长。你不要想太多,跟著我,没错的。刘备不明白,张飞抗拒去找诸葛亮的真正原因是,张飞根本看不起诸葛亮。装非主流?那是我玩剩下的。

  张飞发脾气的时候,关羽会拉住他。关羽是个细皮嫩肉的人,为人温和,身材高挑消瘦,但是内心高傲,对自己的相貌充满自信。他一样“洛漂”过,希望凭藉自己的英俊脸蛋和标准身材可以以名模身份进入洛阳上流社会的交际圈。但是当时乃董卓当道,因为董是个大胖子,所以洛阳主要媒体在相当长的时间里刻意地推崇以胖为美。洛阳日报登著号召大家增肥的公益广告:天子英明,大汉太平,多吃长肉,消灾去病。关羽因此感到再无出头之日,痛定思痛认为是社会制度不公,于是投奔刘备共举自由大旗,进行反政府运动。其实,关羽刚刚离开不久,董卓就被点了天灯。洛阳审美观骤然一变,洛阳日报的公益广告变成:满身肥肉,混蛋流油,大汉精英,谁人不瘦?当时关羽因为参与民主运动,已经被洛阳宣布为不受欢迎的人,他看到洛阳日报的新版公益广告后顿足捶胸,后悔不已,心想:我当时要再咬牙熬两年多好?没准儿现在已经身价百倍了。

  现实就是现实,关羽无奈地接受,但是却无法心平气和。他因此得了眼疾,需要不停地滴眼药水。后来眼睛越洗越乾净,反而更加难受。外面有一点灰尘,眼睛都会红肿,所以关羽只能时时刻刻眯缝著眼睛。这个和日本人得花粉症原理相近,都是太乾净给闹的。

  关羽拉住张飞说:三弟,大哥要去你就让他去好了。这么多年了,他干事儿从来就没有过准主意,这次总算找到一件下决心干到底的事情,你就别和他较真儿。再说,咱们现在也是举步维艰,光那些往洛阳投放的免费印刷宣传品就已经折腾得咱们入不敷出了。要是这个诸葛亮真的是个经营管理的人才,对咱们也没坏处。反正是自己骑马去隆中,又不花路费,就当春游得了。关羽边说边想起这些年东奔西走的辛苦,自己的绿袍子都打了补丁也没钱去换件新的,遥想洛阳花花绿绿的各种布店,那个时尚大都市里人穿著日日在翻新,自己却整天穿著单调的绿色,连帽子都是绿帽子,不禁悲从中来,声音有些哽塞。张飞听来老大不高兴,但是也不好说什么,点点头,但是心里想:我一个诗人都没怎么样,你模特出身搞得这么多愁善感算是怎么回事儿?切!

  关张在一边议论的时候,刘备在掏耳朵。他的招风耳因为以平面方式向左右张开,所以非常招灰,耳屎巨多,需要不时地清理。刘备的心思没人知道。从少年时起他就决心要做一个成功的商人,卖草鞋卖了多年,最后还是关张大吉。很多人看不起他,觉得他碌碌无为,平庸得紧。每到这时,他都会紧闭嘴巴,心中暗想:燕雀安知鸿鹄之志,总有一天你们的脚上都会穿上我制作的草鞋。可惜,理想和现实的差距如此之大。东汉末年,政局震荡,消费者都争先把钱换成黄金存在自己炕头底下,哪还有闲心打扮自己的脚?刘备苦思冥想了很久后,明白了一个道理。生逢乱世,想要发财,一定要做得够狠。所以为了自己成为一个草鞋大亨,他先转行去做军火商。没成想,卖著卖著兵器,自己变成了用兵器的人。但是他明白了,玩政治其实就是乱世中的最大生意。因为他和政府的核心官员刘家有远房亲戚关系,现在却出来反政府,更显得不同流合污。短短数年间已经一跃成为人民心目中真正的民主英雄。加之,刘备多年来一直东奔西跑,没有落脚的地方,生活拮据,这些事情经过很多地下杂志的渲染已经传奇化。很多洛阳的老百姓私下说,相比孙权的富甲天下,刘备才是真正为了大汉自由民主在操心劳力的人。

  当然,作为传奇的主人公,刘备自己心里知道自己有多苦。而且,他始终在心里深深埋藏著的秘密还没有人知道。他总是对自己说,无论如何,我要成为最好的草鞋制造商。所以,为了他现在的民主运动,为了他心底的终极理想,他一定要请出诸葛亮:这个传说中汉朝最好的职业经理人

  本文纯属虚构,与历史不符,和现实雷同。

  卧龙岗的春天分外美丽,蓝天白云,青草悠悠。刘备骑在马上,有柳条打在脸上,他抬手挠了挠痒,心里有些不舒服。去年徐庶的离去是他心里永远的痛。民间的说法是说徐庶因为母亲被曹操软禁,大孝子因此不得不离开他。但是刘备自己心里很清楚,那是次纯纯粹粹的跳槽行为。曹操给徐庶的不光是高官厚禄,更重要的是一个安定的环境。谋士,在这个年代是高级人才。谋士看重的不是钱,要的是那种运筹帷幄、决胜千里的情调。说成白话就是,我坐在帐篷里喝著茶,翘著二郎腿,一张嘴500公里外三军响应,战鼓催动。这是汉朝流行的知识分子派头,知识分子活著为了什么?不就是要个高人一等的派头么?现在天下能给谋士这种工作环境的只有曹操,满打满算也不过再有位孙权。

  让刘备担心的是,徐庶都会离自己而去,这个卧龙先生又怎么会跟随他呢?什么样的方法能请动卧龙?当时为了感动徐庶,刘备把路上一整片树林都砍了,徐最终也没有回头,可见谈感情是留不住人才的,人才是不谈感情的(徐庶走后,当地农民向刘备索赔损害树林的费用,害得刘备拿出两个偏将一年的俸禄并解释说砍掉树林其实是为了在当地建一块草坪作为市民活动用地才平息了纠纷维持住了爱民形象。这些都是刘备说不出的一肚子苦水)。那么我到底能和诸葛亮谈什么呢?刘备心里很慌。

  有只鸟在天上叫,而刘备的心思,关羽和张飞并不知道。关羽一路上只顾往眼睛里滴药水。他去看过华佗的专家门诊,华大夫跟他说,春天他的眼睛会更敏感,要多点眼药水。这里顺便说点八卦,那次看眼睛,关羽忘记送红包,很多年后华佗给关羽治胳膊的箭伤,要做外科手术刮骨疗毒,华佗把关羽的骨头刮得咯咯做响,像剔排骨肉一样。史书上一直说是关羽不要麻醉,装硬汉。其实不是,华佗其实带了麻药但是假装说忘在家里了。关羽到死都不知道,看病是要送红包的。和张飞不同,模特不是关羽的理想,只是他生活的某种工具。关羽没有理想,他只是羡慕别人可以高堂满座,呼来唤去的都是上流社会的大人物。像他这样带著一身醋味儿的山西农民,想要飞黄腾达太难了。所以他读书,他拼命地读《春秋》,心想,有一天我倒背如流,张嘴就是齐桓公、鲁庄公的私人小故事,上流社会还会不接纳我么?但是过了很多年后他才明白,乡下人靠读书最多只能是在城里当个小职员。上流社会是讲血统的,上流社会根本就他妈的不读书。读书也没有用,哪本书里也不会写你和一位贵族小姐出门,走路应该是先抬左脚还是先抬右脚,吃饭的时候什么时候要出声音,什么时候不能出声音。看到什么东西要表示惊奇,看到什么东西要表示不屑一顾。读书说到底是知识分子的事情,上流社会要知识干嘛?关羽最终的研究结果是,对一位没有任何优秀身世和家庭背景的人来说,混入上流社会只有靠容貌。幸好他长得不错。当模特因此成为他的终极目标。但是正如我们前面介绍过的一样,关羽生不逢时,自己的美貌和当时的审美以及政治标准不符。这是千百年来做艺人共同的苦恼。就是到了两千年后也没变。你天生美貌又怎样?如果时代流行中性模样,谁都没办法。这是为什么李宇春当超女冠军的原因。关羽当然不明白这些,他眯缝著眼睛看著外面的青山绿水,心里有些感动。想起“洛飘”的时候,洛阳的熙熙攘攘和现在投身政治后四处的鸟语花香,感叹人生境遇的奇妙。他对诸葛亮并不感兴趣,只是想,要是能在这么漂亮的地方终老,我还做什么模特,我还搞什么反政府运动?

  但是张飞并不是这么想,他理解诸葛亮,知道诸葛亮,尤其明白这个卧龙玩的跟他从前在文坛混日子时候是一个路数。装!你就使劲儿装,看你能装到什么地方去!张飞恶狠狠地想。其实张飞心里隐隐有些醋酸在膨胀,只是嘴里不承认罢了。“洛飘”的时候写诗没人认同,被迫转入地下做非主流。暗地里他也拜访过当时文坛重量级的几位大人物,但是都不得重视。最惨痛的一次经历是去见孔融。当时孔融到洛阳出差顺便看看朋友,张飞得知后赶快去拜访,并呈上自己的诗作20首,孔融看了后一头雾水。张飞的新派诗歌虽是大白话,但是放在一起常常显得非常晦涩难懂。孔融当然不会承认自己不懂加之他本来就讨厌新派诗歌,所以对张飞做不屑一顾状。张飞说,孔先生觉得如何?孔融说,不错。但是你的思想表达过于直白。文字的运用是一种天赋,你要努力发掘自己的这种天赋如果你有的话。我在让梨的岁数就开始有意地启迪自己的文字能力。张飞郁闷地回到家中。朋友说,跟你说了写诗给这些人看,要尽量的写得有思想有深度,你怎么搞的?张飞骂街道,操他妈,我已经够绕弯子的了,屁大的事情都用10个暗喻,20个不相干的事情绕来绕去地装深刻,那厮还说太直白,这不是扯淡么?朋友说,你说了半天,这些诗写了些什么,你自己都明白么?张飞张大眼睛说,谁他妈的告诉你写诗的人自己要明白自己说什么的?对了,问你个事儿,孔融说自己让梨的时候如何如何,这让梨是什么意思?朋友叹了口气,难怪你不成气候,拍马屁最基本的一点就是要了解马的习性和生平。我看你没戏了,一辈子做非主流吧……张飞想著这些伤痛往事,遥望远处的村落,心中无限伤感。老子在洛阳做非主流都没人理,你个诸葛亮在这么乡下的地方装清高,居然有人主动找上门来?这么同人不同命,你他妈的凭什么?张飞鼻子居然有点发酸。

  想著想著,前面刘备下了马。他说快到了,咱们一起走过去,算是悠悠闲闲地踏踏青。关张当然明白,一直骑马,马累了要找地方休息吃草。这些费用能省就省,现在经费确实吃紧。不过还好,朦朦胧胧中诸葛亮的草堂已经隐隐在现。这已经是第三次来了,刘关张都不想空手而归。

  诸葛亮的草庐前有一条甬道,两侧遍植花草。走进竹篱笆环绕的小院子,隔著篱笆的缝隙看得到四周的农田,远远有放牛娃的笛子声音。刘关张回头看来时路,一条小河上的木板桥曲曲弯弯的指向远方,而远方被一片竹林挡住视线。他们从竹林那边来,看得到行路的终点,却找不到归途。隐士据说都是这样隐起来的。关键是,被人知道的隐士还算不算隐士?

  现在刘备走在通往房间的小道上,回想刚才小书童开门的情景:小孩子脸上透著似笑非笑的一股子得意,“你们又来了?”“是啊,这次先生在家么?”“在啊!请进,请进。”

  刘备的大手开始冒汗,见到诸葛亮说什么,他还没想好。短短的青石板甬道一会儿就走完了,“麻烦你先进去通报一声”,“那您先等会儿,我去叫先生起床。”“什么?”刘备好像抓住了救命稻草,满脸笑得打褶,“先生在睡觉么?”“是啊,先生可不知道您要来。”书童强调说,“那不要去叫醒他,让他好好睡觉,我可以等。”

  张飞胡子翘起来了:“大哥,你没事儿吧。做什么事情咱们得有个分寸,人家要派头咱们给派头,人家要诚意咱们给诚意。但是戏做过了头,戏子累,那看的人估计也不自在。”刘备的脸一下子就红了,马上给张飞一个侧脸。这不是为了显示他愤怒,而是用自己的招风大耳朵挡住红透了的脸。他声音有点激动:“你这厮净说屁话。我现在也懒得理你,你给我在门外站著,我一个人到里面去等先生起床。二弟,你也不要进去,帮我在外面看著这个混账东西,不准他乱来!”小书童就笑:“行了,先生。一块儿进去等吧,没事儿。”小书童笑得有点坏,刘备心里不舒服,脸更红。他也想给书童一个侧脸,但是发现给了书童侧脸就要正面面对张飞关羽,于是很不自然地把头低下了:“你不要管他们,我三弟只会捣乱,我一个人在屋里等先生起床,让他们在门外站著。”说完就径自进了草庐。

  刘备一进门,看见门厅正面一个大屏风,把内室给挡住了。这草庐一共没有多大地方,估计屏风后面就是诸葛亮起居的地方。隐隐传来轻轻的呼噜声,刘备推测诸葛亮应该是个白面书生,因为除了白面书生,男人很少有这么睡觉安静的主儿。他垂手站在那里,心里非常迅速地打著草稿,安排著见到诸葛亮后的种种说辞。

  窗外,春光明媚。

  关羽和张飞都没有说话,张飞吹胡子瞪眼没好气,关羽只随他去,懒得理会。关羽根本不想进房间去,那个年代的建筑通风性能不好,房间里空气污浊,而且因为都是木质结构,年久了会有小虫子飞来飞去。这种环境一来对皮肤不好,二来对关羽的眼睛有害。他现在站在门外,斜眼看春光还不停地滴眼药水,很是惬意。

  在当时的文艺界和政界都普遍流传著一个说法,说刘关张三个人其实是gay。尤其是洛阳方面的小报,常有对此绘声绘色的描写。但是后来越传越厉害,连大报纸也开始写这方面的报道,被曹操知道后,他下令禁止对政治人物作八卦报道。很多政治评论家认为,这是曹操作为政治家非常了不起的一点,有博大的胸襟,即使是对政敌也抱有相当的正义感。其实他们不知道,曹操有自己的想法。媒体的八卦只能扼杀而不能纵容,不然总有一天引火烧身。当时已经有很多小报开始曝料,传他和蔡文姬之间的绯闻。尽管曹操一再否认但是显然效果不好,最后逼得他无论干什么都要带上正室大老婆,搞得任何出巡和到民间体察疾苦都索然无味了,而且他老婆安徽口音太重,根本不符合当时最普及的洛阳话标准。这种尴尬导致曹操下定决心要禁止民间对政治人物的品头论足。

  其实八卦有时候是真的,有时候是假的。曹操只是心虚,毕竟蔡文姬出嫁是他心中永远的痛,但是刘关张则不同。他们根本不是同性恋,在当时对同性恋还有歧视的年代,就是前卫如张飞也不太能接受,更何况是一个同性三角关系呢。

  关羽事实上看不起张飞。他讨厌搞文学的人。文艺界的人讨厌文学界的人,这道理亘古不变,因为文学界的人是写别人的,而文艺界的人是被人写的。

  但是不止这些,张飞的个人卫生不太好,常年不洗澡,身上总有一股子汗臭味儿。吃饭的时候满嘴喷米粒儿,一坐下就抠脚,这种种的一切都让关羽忍受不了。另外,关羽也受不了张飞的黑皮肤。他总是想,我是在洛阳做过模特的,我出入的是上流社会,你一个盲流现在也和我一起走来走去的,成什么样子?这些话他从来没和人说过,但是心里总有这么个不舒服的疙瘩。现在跟著刘备搞政治为的还是出人头地进入上流社会。既然在洛阳不能成功,就自己打出一片天地来。总有一天,我也可以住大房子,出门就坐车。这是关羽唯一想的事情。对政治他不关心,反正刘备做什么他都支持,只要能在政界混出名堂就可以。另外,他心里微微有点怕刘备。这种恐惧只有他自己明白,至少他觉得刘备不知道。

  而张飞呢,他对关羽不感兴趣。模特,对他这个诗人来说不过是文盲才做的工作。张飞是有学历歧视的,所以他根本没把这位二哥放在眼里。投奔刘备是不得已,但是当时他觉得刘备既然是汉室宗亲,应该多少受过些教育。再这么也应该比孙权强,孙权是跟著他哥哥孙策在马背上长大的,这种人我跟他就没共同语言,张飞这样想。没想到认识刘备后才知道,这哥们除了对草鞋设计还有些研究外,其他的方面简直是狗屁不懂。但是已经到了这个地步,而且现在和政府也搞翻了,被迫走上民主运动的道路,一时间也不可能回头。张飞认命。但是他努力的希望影响刘备,把自己的学者气质传给他。这也是为什么张飞总发脾气的原因,所谓恨铁不成钢是也!其实他根本不知道刘备希望成为汉朝第一大草鞋商的伟大理想。政治只是刘备的副业。

  世人都以为刘备喜欢张飞。错了。刘备怕张飞。他知道,张飞是读书人,而自己根本就是半文盲。张飞总是试图和他谈人生,谈文学。每到此时,刘备就甩开大嘴侃民主运动,侃政治理念,直到张飞打著哈欠地走开。他怕露怯,虽然整个大汉的子民都知道玩政治的都是文盲,但是他始终保持一个儒雅的形象。如果在自己的乾弟弟前面都维持不住形象,还怎么指望哄住老百姓。而世人都以为刘备敬重关羽,又错了!刘备最讨厌关羽。他自惭形秽,自己有猪一样的招风耳,猩猩一样的长胳膊,和关羽的丹凤眼、卧蚕眉怎么比?当然这不是他讨厌关羽的真正原因。他知道关羽怕自己,更知道原因。坊间都说,关羽义薄云天,千里走单骑,护嫂寻兄。去他妈的护嫂寻兄!他两个老婆这么多年来闷闷不乐,只有见到关羽才喜笑颜开,这里面的猫腻,刘备能不清楚么?长得漂亮很了不起么?刘备常常这么恶狠狠地想,但是想完了自己也叹气,谁叫自己寒碜呢!所以他要尽快在政治上混出点名堂来,至少作为民主运动领袖,他得能有点拿得出手的东西。因此他需要诸葛亮这样的专业人才,模特和诗人是帮不上大忙的。他心想。

  这是世人不了解的刘关张。现在三个人两个在室外,一个在房间里面。四处草长莺飞,三人也各自怀著心事默默地站在原地。时间彷佛停止了一般,直到房间里屏风后有人打了个哈欠,咳嗽了一声。

   屏风后传来的是一个慵懒的声音,吟诗道:大梦谁先觉,平生我自知。草堂春睡足,窗外日迟迟。最后一句有点断续,只好用咳嗽来弥补一下。屏风前的刘备暗暗赞道:好诗!虽然听不太懂要说什么,但是确实是好诗。刚睡醒就能做诗,真不是一般人!这么想著,刘备觉得真的找到能人了,却忘记了张飞也是个诗人。

  屏风后有书童的声音传来,很小,偶尔听到一句:……来了……之后就听到一个清脆的声音大声说:你为什么不早点通报?怎么可以让客人等待这么久?快请使君入室,我更衣之后随后就到。于是书童出来对刘备说:先生醒了,请您进去,他更衣之后马上来见您。刘备笑,随著书童进入厅堂。原来屏风后是个客厅,而客厅旁边又有一间小屋,用竹帘隔断,隐隐看得到小屋中一席凉床,应该是诸葛亮睡觉的地方。刘备在客厅里面坐下,喝了一口书童送上的茶水,四处打量。隐士之家,有琴,有画,当然还有书。各个错落有致,清新典雅。刘备有点紧张,心想这种环境谈话难度很高。客套的时候,要是谈论到琴棋书画我该怎么办?难道把张飞叫进来一起侃两句?哎,当初好好读点书真的很重要。

  正想著的时候,竹帘开启,诸葛亮亮相了。白衣,胜雪!有关羽的飘逸,有张飞的不羁,诸葛亮似笑非笑的书生脸庞令刘备眼前一亮。诸葛亮□著羽毛扇慢慢地走到刘备前面,深深一礼,微笑道:书童失礼了,让先生久等,是亮的罪过。早知先生已经来过两次,本应去府上拜访,只是一直没有空闲,今日又劳动大驾,亲自登门,亮不胜恐慌!刘备慌了神儿,拼命回礼:别,别这么说,这是刘备的荣幸,荣幸。诸葛亮笑:先生一再登门,定有要事。亮才疏学浅,但是盛情难却,敢问先生有什么事情亮可以效劳的么?刘备想:这人怎么这么单刀直入?忙说:刘备每天都在为天下苍生的生存状况担忧,希望可以为他们做点事情。可惜刘备力不从心,所以希望先生可以出山帮我。诸葛亮笑:使君,亮只想知道你要亮为你做什么?刘备奇怪地看看诸葛亮,又说:先生,难道我辞不达意么?刚才我已经说了,希望先生您能出山帮我拯万民于水火,为大汉建立一个自由民主的政治环境。诸葛亮微微摇摇羽扇,盯住刘备的眼睛说:使君到底要亮做什么?刘备开始冒汗,委屈地说:刘备只想要先生帮我实现理想。诸葛亮大笑:那么使君的理想是什么?刘备终于要崩溃了,怯怯地嘟囔著:我就是希望天下人都吃得好,穿得好。诸葛亮马上跟著问:怎样才能吃得好,穿得好?

  刘备彻底晕菜,长长地叹了口气,挺起胸膛看著诸葛亮说:先生旷世奇才,备远不及。我的出身先生应该也知道,我一生的愿望就是成为大汉最好的草鞋制造商。但是很不幸,生逢乱世,现在人们哪里有心思把钱花在服饰上面。经过多年的挣扎,我的草鞋依然不能传世。我很痛苦,但是也想明白了一些道理,坚持理想是很重要的,但是要懂得妥协,乱世中要生存就要按照乱世中的规则行事。既然战争四起,我就买卖兵器。只要我有了足够的本钱,终有一天会实现理想,让天下苍生都知道我刘备的草鞋是大汉最好的鞋子。哎,路漫漫其修远,这一天不知道要等多久。因为买卖兵器,我和各路诸侯都有接触,也经常直接到战场上去推销。不瞒先生说,我天生胆小,而且晕血,那些尸横遍野、人仰马翻的场面每每让我惊恐失措,彻夜难眠。说到这里,刘备喝了口茶,看了眼诸葛亮,继续说:这样的日子过多了,常常会感叹,我大汉子民怎么会沦落到如此地步,你征我伐,苦的都是天下的苍生。百姓何罪?争来争去都是各路诸侯的一己之私。再往深里想更是汗透衣襟,我刘备买卖兵器,岂不是助纣为虐?有多少孤儿寡母是因为我卖出的兵器才痛失家人的?每每思及此处,就忍不住顿足捶胸,痛不欲生。所以我放弃了所有的生意,四处飘荡,过了很长时间浑浑噩噩的日子。直到一天,午夜梦回,幡然醒悟,我不入地狱谁入地狱?与其自责,不如奋起,以一己之力拯万民于水火,还我大汉百年磐石之基!我天生资质愚钝,但是心里只存著这一个念头,这么多年来东奔西跑,风餐露宿,也曾食不果腹,也曾妻离子散,不知不觉走到今天,可是天下依然征战不断,百姓依然流离失所,苦不堪言,而我刘备已经人到中年。难道真的是上苍嫌弃我刘备无能,真的是上苍要抛弃千万的大汉子民么?

  说著说著,刘备已经不知不觉中泪流满面,他用手擦了一下鼻涕,然后用同一只手擦了一下眼泪,自己也吓了一跳,心里暗想:原来我从事的是这么伟大的事业,原来我这个人这么高尚。想到这里,他使劲地擦去最后一把鼻涕和最后一把眼泪,看著诸葛亮,大声说:如果有先生这样的能人帮我,我一定可以揽大厦于将倾,复兴大汉而万古流芳。如果天下百姓可以因此过上富足安康的生活,我刘备就是此生再不做草鞋又有何不可?说到这里,刘备被自己感动得痛哭失声。

  听到刘备的一番表白,诸葛亮站起身来,脸色微微泛红,好像有些激动的样子。他走到刘备跟前,慢慢地掏出一个手巾,笑著说:使君先擦擦鼻涕,哦,还有眼泪。此时,刘备还沉浸在自我感动中不能自拔,鼻涕眼泪随风飘散。看到诸葛亮的手巾,才如梦初醒,赶紧说:失礼了,失礼了。诸葛亮笑:使君一席话,亮很是感动。其实我闲来无事,也为使君筹谋天下大事。刘备吓了一跳:先生的意思是……?

  诸葛亮慢慢走到刘备对面的墙壁边,墙上挂著一块布。他取下来,翻过面来摊在刘备的面前,原来上面画满了点点线线。诸葛亮说:使君请看,这是我手绘的大汉地图。刘备因为从小不分东南西北,所以从来看不懂地图,只好不懂装懂地说:真像,真像。诸葛亮摇了摇羽扇,慢慢地说:方今曹操占据北方,势力强大。您不要小看曹操,从刺董卓未遂后,他白手起家,一路争杀到现在挟天子以令诸侯,这个人实在是一代英豪。现在的曹操,在政治上直接把握著中央的喉舌,洛阳大小媒体都在他的控制之下,且不要说疆土的大小,他现在是大汉的正统,匈奴都只承认一个大汉,哪次来使都是直接晋见曹操。与曹操在政治上争是不智的,他什么都不用做,光洛阳各大媒体向外公告一下,只怕这世上就再没有一个国家敢和使君您来往了。而经济上呢,北方的商家大都和曹操有这样那样的关联,他们直接掌握大汉国家资源。不瞒您说,曹操家上下200多人,做服装和草鞋买卖的就有20多人,都是大字号,垄断北方市场多年。您的草鞋再有特色,又怎么可能与这些官商对抗呢?所以,北方使君您就不必劳心了。

  刘备点头称是。诸葛亮又说:南面现在有孙权。这个人长得难看点儿,但是弟继兄业,现在守著江东六郡八十一州,可以说是要人有人,要粮有粮。江南人自古就聪明绝顶,这些聪明人大都也到了孙权手下听用,而江南气候宜人,鱼米之乡,孙权不但兵精粮足,更有长江天险,就是曹操也怕孙权三分。我们再看经济,江南原本就繁荣,江南人更是个个都是经商好手,精明无比。再加之江南盛产丝绸,服装也好,鞋帽也好,向来是江南手艺人的强项,就是洛阳的时尚也颇受江南影响。您的草鞋自信可以和江南人一较长短么?再说,孙权更不会让您轻易染指他的风水宝地。所以,政治上也好,经济上也好,江南您都不用考虑了。

  刘备听到这里,长叹一声:先生,照您的说法,我刘备再无容身之地了?诸葛亮哈哈大笑:使君,亮为使君谋划已久,要是没有容身之地,我又何必再对使君费喉舌呢?当务之急,使君您要先占住荆州落脚,之后,亮为使君寻得一方宝地。您看!说著,诸葛亮用羽毛扇一指地图。刘备痛苦地失声叫道:东瀛?诸葛亮笑:错,这里是西面,这块地方叫做四川。刘备擦了一下冷汗,说:哦。我看反了,看反了。诸葛亮继续说:四川地处盆地,天府之国,而且出入四川的道路难于上青天,一旦入川,易守难攻之势出于自然,还怕什么曹操的铁甲,孙权的水军?川人虽然聪明无比,但是民心纯朴,尚未开化。大汉天下川人所知甚少,您到了之后,只要广施德政,得到民心易如反掌。人都说:天下者有德者居之。其实这天下是先来者居之。越是开化的百姓越是难以统治。比起曹操治洛阳,孙权治建业,您治理成都要容易得多。另外,越是经济不发达的地方,越容易做生意。到了四川,您的草鞋生意就可以大展宏图了。川人哪里见过洛阳、江南的丝竹管弦、红男绿女?您的草鞋可以轻易领导川中时尚。到时候,您一手军政,一手买卖,不就是川中的曹操了么?占住四川,再徐图天下,何乐而不为呢?

  刘备听到这里,眼泪和鼻涕又掉了下来。先生,您未出茅庐而三分天下,这等大才真的是前无古人,后无来者。诸葛亮微微一笑,刘备翻身拜倒:先生,请一定要出山帮我刘备一展宏图!诸葛亮赶忙把刘备搀扶起来:使君如此诚意,亮敢不尽心竭力么?说罢,两人对视大笑不止。

  ……

  很多年以后,有人问关羽:你一向心高气傲,为什么独服诸葛亮呢?

  关羽说:我不是服他,只是他说要进四川。我知道四川地处盆地,潮湿多雨,川妹子都是水灵灵的,这样的地方对皮肤好,适合我居住。而且雨水多,地方也乾净些,对我的眼疾只怕也有好处。

  但是关羽说这番话的时候,并没有料到,他终身都没有入川,最后还是死在江东。天下人误读了关羽,说他是义薄云天的好汉,其实一个古代模特的心思,谁又能懂呢?

  很多年以后,有人问张飞:你一直看不上诸葛亮,为什么诸葛亮出山后,你又佩服得不得了呢?

  张飞笑了:诸葛亮是读书人,我也是。诸葛亮做过非主流,我也做过。但是诸葛亮比我厉害。我从他身上明白了一些道理。吟诗作画、写文章是最下作的读书人,真正的读书人是要当官的。

  张飞说番话的时候,他不知道,千百年后,没有人知道张飞是读书人,都以为张飞不过是一介莽夫。知识分子靠知识是没办法传世的,张飞明白了这个道理却来不及去改正自己的人生了。这个道理到了现代中国依然是颠扑不破,可惜没人知道,这是张飞悟出来的。

  很多年以后,有人问诸葛亮:以你的大才,干吗要去辅佐刘备,到曹操和孙权那里不是更可以有所作为么?

  诸葛亮说:一,曹操、孙权那里能人太多,就算我比他们都出色,也未必能出人头地。中国人的地方,不是你有才能就能出头的。二,刘备是天生的政治家,而且一定是会飞黄腾达的人物。为什么?因为这个世界上能自己把自己骗得满眼流泪的人实在不多。

  而很多年以后,有人问刘备:你说得诸葛亮如鱼得水,你真的这么想么?

  刘备仰天长笑:诸葛亮是不世出的奇才。得到诸葛亮当然是如鱼得水了。另外,诸葛亮还有一个优点,就是他知道自己是个奇才。一个知道或者以为自己比别人聪明很多的人,无论在哪里都是最好的二把手,无论是治国还是经商。

  很多年以后,有人为诸葛亮刘备最后的那个相视而笑画了一幅画。画中两人站在屏风前,双手紧握,但是不是相视的,而是面向大家开怀大笑。中国古人的创造力和艺术加工能力真是无比惊人,这种艺术手法至今我们还可以在中央电视台的各种新闻中看到。

  历史上将刘备和诸葛亮的这次会面称作:隆中对。

  (全文完)

之前看到微信上有个如下视频号

忍不住写了一首小诗,作为律诗,对仗不太工整,不过无所谓,暂且记录吧

雪白骏马足
月黑千山路
剑鸣老寺钟
月冷仇人户

匆匆读完了王朔100万余字的新书《起初》。推荐一下,书就不多说了。 特别想说一下王朔。

我一直觉得当代中国文坛欠王朔一个皇冠。没错,就是皇冠。 你要说我没文化,没见识,不懂文学,我不反驳,恩,毕竟事实是没法反驳的。但是不重要,在我心里王朔一直是当代活着的中国作家里最好的,几乎没有之一。

说为什么觉得朔爷牛呢? 因为王朔文字能力强到令人发指。白话入文,这种事儿很多作家都干,但是能做到王朔那个水准的,我没见过。王朔曾经吹牛逼说,他认真了要给中文写出时态来。这个他做没做到我不知道。但是我觉得朔爷要愿意,他是可以写一篇100万字的小说,通篇只有对话,只用对话,但是写人物,写故事,写结构,写景致,写氛围,写心理,无一遗漏,他真的有这个能力。这么说不是我在替他吹牛逼,拿他早期的《我是你爸爸》做例子,那个父子对话,你把所有内容全忘记了,父子两个的音容笑貌还是在脑子里绕着挥不去。 再来,王朔是骨子里很谦卑和真诚的。他不说大话,小说里只提问题,不给答案。他也很少和很多中文作家一样,痴迷于苦难。很少写苦难,就是谦卑和真诚的表现。因为大部分写苦难的作家,骨子里都是上帝视角,或俯瞰,或蓦然回首,但是朔爷不干这个,他所有的视角都是平视的,他眼里看过去的世界不过都是些不堪和蝇营狗苟,再下做也就是屎尿屁加上流氓无赖,没有圣人也没有十恶不赦。这种姿态叫做谦卑,写字的人,有了谦卑,才带得出悲天悯人。一旦有了上帝视角,那万物都刍狗了,你就是掉了眼泪,一肚子怜悯也不过是对着小动物大呼可爱,回头烤肉一片不落得满口留油罢了。中文作家,我觉得谦卑的人很少,谦卑是非常优秀的品质,不止作家,大部分人都没有,当然包括我自己。

朔爷也不是没毛病,太懒。他的懒惰配不上他的野心。对,他真的有野心。我记得很多年前他吹牛逼的时候说,哪天高兴了,也能写出部红楼梦来。这话,有两层意思。一个是朔爷真的推崇红楼梦。当然这个也没毛病,全世界能和红楼梦碰一下的世界名著,也真的超不过一位数。另一层意思是,朔爷有野心想给中文小说立个杆子。但是就他那个慵懒的样子,我觉得这辈子够呛了。懒,也不算缺点,但是你有野心,还懒,那怎么也算是个臭毛病。

说回《起初》。如果我没记错的话,王朔是非常不喜欢汉武帝的,说他穷兵黩武。但是他写的汉武帝够调皮,当然调皮的不是汉武帝,是一生少年的朔爷。

还是忍不住写点儿什么。 2024年到了临了,琼瑶走了,刘元也走了。

我们这代的男孩儿是以看琼瑶为耻的,得读金庸古龙,一男的怎么能读琼瑶呢?因为这个,我活到这么大,不止没读过琼瑶的小说,她拍的所有电视剧也都没完整看过一部。即使是据说一两代人共同回忆的还珠格格,年年重播我也没看过。

关于琼瑶为什么写了那么多奇怪的三角恋故事,基本上江湖上已经传遍了,人人都知道。她是位狠人。我虽然从来不看她的作品,但是她这次对自己下狠手,不管别人怎么评说,我觉得老阿姨很朋克。她的人生走向成功到最后结束,都很朋克。她不是个案,这是她们那一代人很多都有的风骨。就是那种现在说得烂大街,但是其实没什么人真的做的到的三个字:做自己。

刘元比琼瑶低一辈。先说一下,ADO的“我不能随便说”,一直在我跑步的曲单list里面,陪我跑过几千上万公里了,百听不厌。刘元的名字,于我,是和崔健连在一起的。我看过很多年轻人,有意无意,明里暗里的说崔健和他们的音乐土。我是音乐盲,不敢从专业角度说啥,但是作为一个喜欢听歌的半大老头子,很想说,在80年代末崔健的一无所有专辑里,短短10首歌就包含了说唱,雷鬼和爵士,到了现在,这些还是流行音乐装B犯们必须要提的时尚因素,但是刘元他们40年前就耍起来了。崔健太喜欢爵士,而刘元的萨克斯就是崔健的定海神针。崔健自己是吹小号出身的,他有多爱刘元可想而知。不是想说刘元们有多牛,而是想说他们那一代人在贫瘠的土壤里冒出头来,都是不顾一切的要走在最潮流的队伍前面,用,自己的,方式。这,是他们那一代常有的风骨。

我比刘元们又要小一辈。我们这代人是中国上下五千年享受了最多时代红利的一代人,前无古人,看起来也可能后无来者。和琼瑶,刘元那几代人比,我们最大的特点是吃饱了喝足了,然后还有什么,我自己不太清楚。但是不重要,一年年有人出生有人死去。是一代人成就了一个时代,然后又被时代塑造,谁也别想例外。

沉积了2年,乐队夏天第三季终于开播了,借这个档口说说乐队夏天相关的话题。

首先是马东。他是如假包换的星二代,而且算是巨星二代吧。马季在中国的文艺史上,不管你喜欢不喜欢,关注不关注,肯定是绕不过的一个人,他的儿子怎么也算是上一号人物。但是马东身上基本看不出任何明星后代的样子,沉静,练达而且踏实。当然,你要说这个不过是表面或者台面上的马东,那我也不反对,公众人物可能总有两幅面孔也说不定,但是我作为观众,只能就看得到的样子做评论。

马东这两年最被关注的事情不是他做了奇葩说,一年一度喜剧大赛或者乐夏,好像是许知远对他的一次采访,采访后N多人说他犬儒。他当时说的话,细节我不太记得了,大致意思是说,世界上5%的人是精英,剩下95%的人是芸芸众生,不关心宏大的事情。我们(指米未或者相关的文艺工作)只要让95%的人高兴就好了。这话一出,各种社会责任感爆棚的自觉知识分子们就怒了,指责他犬儒。我觉得大部分批评马东犬儒的人,他们甚至没有明白马东这句话里其实带着的刺儿,而且这个刺儿就是用来刺这些后来的批评者的。马东这段话,我看过原视频,结合许知远的前言后语,马这段话其实是反话。我理解他想说的是,5%的那些才是sb,才是庸庸无为的一群,我为什么要让你们高兴。马东骨子里其实有点愤青,他不止不犬儒,他对社会有深刻的观察和而且始终希望触手可及得参与社会改造。

当然这种评价,马东看了可能会不同意。不重要,我作为一个旁观者是这么觉得的。以这样的一个马东,他做的节目注定是有特色的,而且是鲜明的个人特色。无论是奇葩说,一年一度喜剧大赛,他们的切入点都很一样,让从前不能或者没渠道发生的人,用在中国还不多见的节目形式发出声音(话说,一年一度喜剧大赛比脱口秀大会好出一整个维度,这个可以单开一个话题另说)。这些节目背后的逻辑都是:深入社会话题,多元讨论,发出观点,不给结论。更重要的是,节目小心翼翼得走在国内的游戏规则之内,绝不越轨。这种安全,“世故”的姿态,可能就是马东被批评犬儒的原因。那些批评他犬儒的人可能从来没有想明白的一点是,每一个发出的声音,都是宏大的叙事。同样的一片土地,你在天上俯瞰下去是一小块豆腐块,你站在人群中平视过去,是无边无际的一大片广袤。这是视角和姿态的问题,和观点与立场无关。

说回乐队夏天。不太清楚是什么契机让马东做了这个节目,他自称完全不了解乐队,我想那只是说他和我一样是乐盲罢了,而不是真的不听摇滚乐。他年轻的时候不听崔健吗?我不相信。乐夏有不可避免的国内综艺的套路,但是看得出他确实在努力做到不同,努力做到不和其他的综艺同流合污。其他的不说,在最热闹的时候停办两年,然后重新启动,这个,至少从商业的角度看,够有范儿了。

再把话题往回拉,直接聊乐夏3刚过去的第一集吧。 先说超级乐迷

  • 高叶:因为看了狂飙才知道这个演员。不太了解。从她说话的范儿来看,像是喜欢摇滚乐的女孩(当然乐夏不是只有摇滚乐)
  • 张亚东:没毛病,虽然太闷骚。
  • 彭磊:咋说呢?从他第一集的表现可以告诉我们一件事,生活中的贫嘴毒舌和能在镜头前口吐莲花是两回事儿。当然,他刚到这个角色位置,还没玩明白也是有可能,可以继续看下去。
  • 那英:话题人物。估计录制的时候,刀郎的歌还没出,她还没被骂上热搜,但是节目播出的当下,她正好在风口浪尖儿上,对她的心理承受力也确实是个考验。我挺喜欢那英的,不太明白为什么那么多人讨厌她。很多人说她不懂乐队,而且不会作词作曲制作,压根儿不是音乐人,凭什么做超级乐迷。这角色又不是评委,叫”乐迷",而且投票权也和普通观众一样,为啥做不得?甭管多讨厌她,那英唱歌在全球华语女歌手里也是头几名。她连个乐迷都做不了?这也太刻薄了。另外,总有人拿她和田震比,我觉得,单论唱歌,她比田震要强太多了,根本不是一个量级的选手。黑们就少说两句吧。
  • 大张伟:当然,不管超级乐迷都有谁,如果没有大张伟,这个节目可看性就去掉了50%。大张伟基本上包揽了这个节目乐队唱歌以外的所有看点。这孩子真的是人精,用生命朋克着的摇滚人。我对他的喜爱毫不掩饰,也因此经常被朋友嘲笑。他和马东正好配对,一唱一和,可以给这个节目定基调,也可以给这个节目上档次,当然前提是你得听得懂他说话的弦外之音。说他说话有弦外之音,并不是说大张伟说话说一半儿留一半儿,或者故意打着什么隐喻。而是他说话的边界感很强,虽然看上去口不择言,直接尖锐,但是他清楚地知道话头从那里起,在那里收住,可以不给节目带来麻烦,也不给对话者带来困扰。他说话没有什么话术,想到什么说什么,但是不会给他人找麻烦。这样的人,不要说娱乐圈,生活中都很少。我们总是夸奖那些所谓心直口快的人,但是常常忘记,心直口快和礼貌,善意是不矛盾的。总是说摇滚乐要be real,但是没有礼貌和善意的real,根本一文不值。大张伟在这个节目可以做照妖镜,看看那些人是real的real,那些人是不那么real的real。

最后聊聊第一集里出现的乐队。

  • 新学校废物合唱团:东北朋克教父的歌,我挺喜欢的。简单,旋律上口,歌词给力,这就是朋克,就是摇滚。
  • 橘子海:夏日漱石这个歌名是整首歌里唯一出现汉字的地方。听着还不错,不过我个人不太理解为什么一定要用英文写歌,作为听众没觉得写英文词有什么特别的必要性。
  • Mr.Miss:这个组合拉跨的是主唱,那个自觉很明星的刘恋。他们做的歌挺好,但是刘恋唱歌真的没有爵士味道。再加上她因为一些综艺,成了有知名度的明星,举手投足总是一股子我风情万种的样子,让人很出戏。不知道别人怎么看,我希望看到的爵士乐是更自由,随意没有设计和接地气的东西。
  • 柏林护士:我心里第一集中最好的乐队。没什么好说的,就是很rock
  • 康士坦的变化球:这乐队是乐夏今年要重点推的乐队吗?真的是给了他们足够长时间的PR。大家都在夸他们的歌如何感人,为什么我不是太能感同身受的?我能理解这首歌表达的情绪,事实上歌名已经直接给出来了:美好的事可不可以发生在我身上。但是这种表达总显得有点自怜自艾,堵在一个情绪点里走不出来,又不呐喊,仿佛一个人偷偷掉眼泪,然后叫大家一起来合伙悲伤一下。至少这样的歌不是我喜欢听到的那种摇滚乐。
  • 虎啸春:歌没怎么记住,就看他的乐手去一位一位得拥抱超级乐迷。然后还看到超级乐迷们感动。不知道这情绪是哪儿来的,可能是因为不在现场的缘故,所以感染不到我。反正这些都和他们的歌没一毛钱关系。
  • Nova Heart:被疯狂称颂的乐队,尤其是主唱的大飒妞。歌是真不错,大飒妞也是唱得真好,不过我更喜欢柏林护士。呵呵

总的来说,第一集没有特别让我跳脚的乐队,等着看后面乐队出场啦。

之前在国外想看国内的最新影视作品,很难做到同步,多少有些时差。感谢现在可以翻墙回国的VPN和互联网大厂对海外观众的开放,去国多年第一次在国外和天朝同步了最新的电影和电视剧。从新年到现在,大概把2023年最新的一些片子都捋了一编。说说感想

  • 流浪地球2

    怎么说呢,明显比不上1。虽说90%的影视续集都没办法超越原生第一代,但是我说流浪地球2比不上1,倒不是这个意思。流浪地球1我很喜欢,他确实是和好莱坞不一样的中国式的科幻,或者说是东方式的地球末日情节吧。没那么多走投无路的矫情,没有一个人拯救一个物种的舍我其谁,更没有好像地球上从来只有白人的自大,流浪地球1说的是很直白的慌慌张张,忙忙碌碌,有伤感,有别离,有无可奈何,更有无能为力,东亚似的,哪怕用个偏贬义的词“自怜自爱”也没关系的情感输出。并不是说这种情绪或者表达多么好,但是他就是我们这个民族原有的样子。但是到了流浪地球2开始变味儿,有种大国崛起的德行。个人不太喜欢。为什么会有这种变化不得而知,或许是因为战狼吴京在这一集的深度参与。你看李雪健从头到尾穿着中山装,一发言就是高屋建瓴,我朝在上的样子,很吴京。

    当然讨厌看美国拯救地球,但是同样不喜欢看中国拯救地球。真有地球毁灭在即的那一天,咱们这个物种的每一个个体,每一个群体都应该不知所措,都应该惊慌失措。不是说世间没有英雄,没有可能到时候哪个国家振臂一呼,四方相应最后带领大家绝处逢生,而是说到了那个时候,谁还在乎谁是领袖,谁是霸主,谁比谁更加慷慨激昂呢。

    总的来说,流浪地球2,特技很棒,情节有点拖沓,更重要的开始硬上价值,一个IP要被玩儿坏了。

  • 满江红

    很多人不喜欢,或者看不上张国师,但不管怎么说,在我眼里满江红比流浪地球2好很多。个人也曾经不太看得上国师那种傻乎乎,未成年似的的家国情怀。尤其是在《英雄》里展示的那个“不杀”的和平主题,当年骤一听还以为是少先队老师出来讲课,透着浓浓的红领巾味道。但是随着张国师在电影,主题活动,开幕式的各种作品展示,我忽然觉得,他的家国情怀,其实朴素而自然,和战狼似的那种所谓爱国情怀完全不同,是非常个人化而且内向的。没有什么不好,而且很可爱。

    电影拍得很棒,至少对我一个外行人来说,大师拍的东西,哪怕是游戏之作,他的水准也是在线的。其实张艺谋很在行拍这种闷骚的轻喜剧。《有话好好说》,到现在为止,在我心里依然是大陆最好的喜剧电影之一。满江红里的小滑稽好在没有刻意,是你我他平时互相逗逗闷子的那种,这样的喜剧在大陆已经很久不见了。大陆喜剧被徐峥们彻底搞烂,满大街都是呲牙咧嘴,大指甲挠胳肢窝那种用力过猛的片子。

    电影最后的齐诵满江红,无论是不是很多人不喜欢,我觉得对张艺谋而言他是水到渠成的,他是必须要有的一个情节。我觉得张艺谋在拍这一段的时候,自己是感动的。他在电影过场中用了很多豫剧,猛一听还以为是秦腔。当然,岳飞是河南人,但是这故事里没有岳飞,一个南宋的故事,一帮天南海北的人物,张艺谋选择了大段的铿锵有力的源于秦腔的豫剧做背景音乐,我觉得这就是他的家国情节。一个人他忘不了乡土,那就是可爱的。

  • 宇宙探索俱乐部

    电影类型写的是“科幻喜剧片”。我看到快结束,只看到喜剧,没明白科幻是咋回事儿,还以为这个类型介绍本身就是喜剧的一部分呢。到了最后,孙大通被外星人接走才算圆了“科幻”的主题。

    好电影,必须的。

    不过有两点。其一,是这种通篇的第一视角的运动镜头,不要说在电影院里,我在家里看电视都看得有点头疼。真要在电影院里看,我怀疑一半儿以上的观众得看到呕吐。这种运镜真的是考验观影者的小脑发育机能。属于体检的一种吧。

    其二是,不太喜欢最后外星人真的降临地球的情节。虽然终于靠这个情节把电影搞成了科幻类,但是他也可以不是科幻,谁规定非要科幻呢。如果我是编剧,我会让主人公最后摔下山崖,然后昏迷不醒。被世人救起后,大家以为他真的找到了外星人,等到他醒来,全世界都在追捧他的第一类接触。他因此成了寻找外星人事业的领头人,功成而名就。开始虽然有点怀毅,到了最后,他自己也开始相信自己确实接触过外星人了,唯一的悬念是孙大通不知所踪,但是不重要,电影嘎然而止。

    总觉得所有的探索,所有的出走都是原地打转。哪怕人类走出太阳系,我们依然困在自己的体系之中,除了自鸣得意一无所获。扯远了,和电影品质无关,个人口味罢了

  • 狂飙

    很棒的电视剧,比从前的人民名义强多得多。 一边看我一边在想一个问题,这片子是怎么过审的?后来想明白了,因为编剧很狡猾。

    其实这部剧分成两部分,一部分是主线故事,另一部分是吴刚演的(话说,吴刚真的没整容吗?再问一遍,真的没整容吗?回答我说没有的话,我就再问一遍)纪委干部带出来的副线,而副线是为了过审用的,没有他,狂飙再狂,也狂不到屏幕上来。之所以说人民名义不如狂飙,就是因为我记得人民名义里也有类似的结构,但是他的副线和主线混在在一起了,导致人民的名义最终成了宣宣们要看的电视剧。而狂飙的狡猾在于,拍给宣宣们的情节和主线是几乎独立的,你把吴刚出演的那些情节大部分都删除,会发现根本不影响整个故事的展开。这种刁钻的结构设计,简直是。。。。我太喜欢了!

  • 漫长的季节

    这十几年来看过的最讲究的大陆电视剧,没有之一。 辛爽作为摇滚乐手出身,光配乐一项就已经碾压似的强过了大部分大陆电视剧导演。

    至于说道讲究二字,是相对大陆电视剧一贯的粗制滥造而言的。现在我天朝有钱了,无论是电影还是电视剧,CG,大场面,豪华服装等等毫不吝啬得一坨一坨得往屏幕上堆,透着非常地道,自信的两个字:富裕!但是“粗”和“烂”这两样病,靠钱都治不好。画面全是修图,修完了人脸修背景,很多片子拍的是实景,看到的都是每一个像素上的合成色。情节更是相当考验观众的修养,时缓时急,前面挖一堆坑,后面叠一排山走到哪儿算哪儿,没有逻辑只有漏洞。演员就更不能提,全部换成CG会导致片子整体表演水平的提升。台词更是想怎么说就怎么说,前言搭上后语属于中奖行为。

    反观漫长的季节,每一帧都可以上大屏幕。光影,布局都有导演的精心设计。运镜里的小心思,画面里看似不经意的前后呼应,丰富的细节支撑起一集一小时的时间,丝毫感觉不到冗长,反而觉得转瞬即逝,忍不住要看下一集。演员都是正经八百的演员,都是正经八百得在演戏。而老戏骨们的对手戏,每一场都精彩。有冲突,有个性,而且有趣。台词很用功,没有废话,照顾人物个性的同时,用最有效率的方式推动情节发展。

    写到这里才发现,上面这些夸辞,不都是一个电视剧应有的品质吗?可见观众苦大陆电视剧久矣。

    漫长的季节,我看也算是东北文艺复兴的一部分吧。看东北的故事总有一种让人唏嘘的感觉。在我天朝,让人唏嘘的事儿,一般都过不了审,这个片子能过审而且过得如此丝滑,我猜是因为90年代毁掉东北的下岗潮是前朝的事儿。前朝之谬大,愈显我朝之英明。但不重要,重要的是这片子真好,而且还能让我们看到。其他的,去他妈的吧。

有一个走廊,很安静,有人唱歌的话可能会扰民。有这么一个人,有点不识好歹,时不时要哼几句歌儿。可能确实有点扰民,虽然唱歌儿的人自己不太清楚,因为没人告诉他唱什么歌儿,唱多大声音算是扰民。这时候出现另外一个人,他没完没了得对唱歌儿的人吐口水。有趣的点是,吐口水的原因并不是因为唱歌的人扰民,而是因为他觉得唱歌的人唱得不好听,唱的不是他想听的歌儿。

吐口水的人就一直吐一直吐。唱歌儿的人一直不理会,直到被吐得浑身上下都是臭口水,忍无可忍了就回击起来。这时候一直沉默的走廊居民们出来劝架了,说,要以和为贵,不要争吵。说唱歌的人,你一把年纪了还那么大脾气。也有人说,你看你唱歌儿确实扰民了。

问题来了,大家的点都无懈可击。你看,做人不要和人起冲突,大家和平相处。没毛病。扰民这件事情做得不对,也没毛病。唱得不好听,唱得不合人口味,虽然只是听歌人的个人视角,但也无可厚非。当所有观点都很在理的时候,没人想得起,也没人在乎,有人被吐口水这件事情。

那么这个问题的解决方案是什么呢?就是唱歌儿的人闭嘴,而且最好永远闭嘴。唱歌儿的人闭嘴后,吵架的问题解决了,扰民的问题解决了,唱歌难听的问题也解决了。而被吐口水这件事情呢?他开始就不是个问题,因为口水没溅到唱歌以外的任何人身上,而且唱歌的人闭嘴了,口水可能也就不吐了。

这件事情告诉我们,如果被吐口水,而且口水只在你一个人身上,那一定是,嗯,你错了。。。

今天和某日本客户(严格意思上不能叫客户,该叫什么我也不清楚,不过不重要),因为一些工作和合约上的问题面对面争吵了整整两个小时。两个小时说得自己口干舌燥,结果是正面的,我得到了想要的结果。

要说的不是这次争吵的内容,要说的是这两个小时里体会到的关于争吵的一些小感想。争吵这件事最要不得是在口舌上争胜负。这说起来有点奇怪,争吵不就是在嘴上较劲儿掰斥吗?其实不是。说到底之所以要争吵,都是有原因的,没人会为了要锻炼嘴皮子跑出去和人吵架。所以在争吵中不要忘记“初心”。如果你没在一场精疲力尽的争吵后实现自己要得到的结果,那么就是把对方说得哑口无言,或者像诸葛亮骂死王朗一样,用嘴皮子送对方上了西天,吵完了也不会觉得自己获得胜利。拿不到想要的战利品的战争,就绝对不会是一场胜利的战争。道理显而易见。

所以如何守住自己的逻辑主线才是争吵的王道。今天的争吵里,有好几次,对方试图模糊焦点,腾挪了好几个不同论点,其中有一两个其实很尖锐,可以说我这方不能说完全占理。而在那种上头的情况下,会不自觉地要在每一个话题的口论中压倒对方,哪怕自己不占理。还好我中途感到有问题,及时止损,硬生生得将话题拉回来,放弃了在他方论点上的一较高下。之后对方一直试图从我的基本论点上跳出,但是我不管他说什么,就是不离开自己的基本盘。最后,对方开始进入沉默,无话可说,原因很简单,他知道没办法将我从我的话题阵地上引开到他可以大展手脚的题目上去。而在我的基本盘上,他原本是不占理的,所以既然我守住原阵地不动如山,他除了沉默就别无他法了。最终,争论的结果是我让他承认他原本不愿承认的事情。在这之前,在他几次强行跳转到的话题上,我是退让的。我可以让他赢一两个论点,我甚至接受他的一些指责,但是一定要死死得把他套在我需要在这场争论中最终赢得,而他原本不想给我结果那个话题,或者说逻辑主线上。因为这个才是自己口干舌燥要用两个小时时间来和他对峙的初心。

另外一个争吵中很重要的点是,千万不要上头。口舌之争,你来我往,很容易肾上腺飙升,最后眼红脖子粗。今天对方很显然有备而来,打印了一堆资料,一进房间,不等我开口就直接甩出他的第一个论点,而这个论点毫无意外得激怒了我,因为太胡搅蛮缠,并且罔顾事实。因此就直接引发了近10分钟的相互指责,各不相让。在这期间,我忽然反应过来,不对,这是对方的策略。虽然对方也看起来和我一样言语激烈,但是看得出来,他并没有像我一样真的愤怒。原因很简单,这本来就是他甩出来的话题,而且对我的指责也是在他设计好的路线上在你来我往。这就有趣了,我要聊的是A,而他一上来跳过B,开始谈C。他的战略很简单,在C上双方大刀挥动互砍一番,然后自然延伸到D,E,最后我自己估计都找不到路回到A。想到此,我忽然冷静了,声调降低,语速和语频也放缓,大部分时候在听他说,等他说完后,我慢条斯理得直接跳到A,仿佛刚才我被他激怒的事儿不存在一样。一转移到A,就感到他开始上头。他上头不是因为愤怒,而是因为他发现自己精心设计的作战战略被瓦解或者消弭了。说起来,冷静是争论里守住自己阵地的唯一办法。所有的争论,无论是有意还是无意,都是逻辑碰撞。只有心无杂念得守住自己的逻辑才能和别人硬碰硬。

吵架这事儿也许伤身,但是一定醒脑。– Xiang Ruan

Here comes my new website! I will explain this new website in details soon.

新しい個人ウェブサイトを立ち上げました!このサイトの構築について、後日に説明する予定です。

我的崭新个人网页开张了。过两天会更新一篇文章聊聊这个网站的制作。

I just released a personal project, and I guess you could call it my first “Vibe Coding” output.

Github: https://github.com/ruanxiang/fuji

I hesitated for a long time about whether to release this. First, I’m genuinely busy. Second, I’m a lazy villager at heart—if I can lie down, I’ll never stand. Being an open-source maintainer is often a thankless chore (though realistically, probably no one will ask me to maintain this little project anyway), so I rarely open-source my personal tools. But in the end, I felt this one was worth sharing.

This is a tool built for Emacsers like me. It started because I wanted a better way to read academic papers. Everyone is using LLMs to read papers now, but I just couldn’t stand the workflow: upload a PDF to an AI, open a web page or an app, click around with the mouse, switch contexts… For an Emacs user, this workflow is incredibly inefficient.

I wanted a tool that allows me to live entirely inside Emacs: open a paper, and immediately start pair-programming with an AI to discuss it. As I wrote it, it grew into exactly what it needed to be.

You can think of it as a Personal Digital Library with an Emacs Frontend. I named it Fuji. The name has two layers of meaning: in Chinese, it sounds like “shoulder the satchel and travel” (a metaphor for scholarly pursuit); in Japanese, it sounds like “Mount Fuji” (implying “admiring the high mountain”).

You can throw any format at it—PDF, DOCX, EPUB, JPG, or even a URL. It handles academic papers, news articles, or just your daily scratchpad notes.

  1. No Mouse : Everything happens within two keystrokes.
  2. Text is King : No bloated databases or flashy UIs. The engine is text-based—clean, convenient, and blazing fast.
  3. Pluggable & Extensible : By design, *Extraction Tools and RAG Backends are fully pluggable . While built-in support is currently limited (Marker, Graphlit, etc.), you can easily extend it to hook into any service or MCP interface you prefer.
  4. Pure Emacs : It adheres to the purest Emacs philosophy.

In short, Fuji is a Personal Knowledge Base tightly bound to its user, featuring the geekiest UI and the most efficient operations. If you are an Emacser, you feel me!

  1. 📚 Digital Library Add or remove documents, manage tags. Fuji supports Full-Text Search, not just filenames. Whether it’s a PDF or an EPUB, you can fuzzy search with any text—or Regex if you’re hardcore. Even with thousands of books, search is instant. Browsing a document in Emacs and like it? One command adds it to your library and switches you to Fuji Reading Mode.

  2. 📖 Immersive Reading Emacs split layout: Original document (PDF/DOCX/EPUB) on the left, AI chat on the right. The AI’s context isn’t just the current file; it connects to your entire library’s Knowledge Graph. Most importantly, **Conversation is Memory**—any time you reopen a document, your previous discussion history loads automatically. Seamless continuity.

  3. 🎓 Academic Writing & Citation This was the original spark.

    • BibTeX Management: One-key fetch of DOI info into your Bib file.
    • Citation God Mode: Writing a paper and need a citation but can’t remember the details? Launch the Citation command, search your library with keywords (full-text match, not just titles!), select, and hit enter. The correct citation format inserts instantly.
  4. 🧠 Private Think Tank As your documents grow, Fuji becomes your second brain. You can lock the AI conversation to a specific scope of knowledge (RAG). It doesn’t just understand you; it engages with you in the most precise context.

I released Fuji because I have ambitious ideas for it—I want to craft a reading tool unlike anything before. But I am lazy, and busy. I don’t know if the next big version will be out in a year or never.

But whatever, let’s just ship it. Github: https://github.com/ruanxiang/fuji (Star it if you like, Maintenance is… sporadic at best)

Note for Package Users: I plan to submit this to MELPA for easy `package-install`. But given my lazy nature, this might take a while. Don’t rush me, let it flow.

The nougat package has a pesky bug in how it handles PDFs. Don’t worry, it’s an easy fix! Here’s how to install it from the source and apply a manual patch, based on this pull request.

  1. First, Make a Home for Your Project

    mkdir -p /path/to/nougat
    cd /path/to/nougat
    
  2. Whip Up a Virtual Environment This keeps all the project’s Python bits neatly tucked away from the rest of your system.

    python3 -m venv .venv
    source .venv/bin/activate
    

    (If you’re a pyenv user, you can set a local Python version before you start.)

  3. Install Nougat Straight from GitHub

    pip3 install git+https://github.com/facebookresearch/nougat
    

    Heads up: This can take a few minutes, especially on an older machine. Go grab a coffee!

  4. Time for a Little Open-Source Surgery Alright, here comes the magic. We need to manually edit one of Nougat’s files to fix the PDF rendering.

    • Hunt down the file: Find and open `rasterize.py` inside your virtual environment. The path will look something like this: .venv/lib/pythonX.Y/site-packages/nougat/utils/rasterize.py

    • Find this chunk of code:

      # As pypdfium2 does not render pages at the document level rather it is done at the page level
      renderer = pdf.render(
                  pypdfium2.PdfBitmap.to_pil,
                  page_indices=pages,
                  scale=dpi / 72,
              )
      for i, image in zip(pages, renderer):
      
    • Swap it out with this better version:

      images = []
      for idx in pages:
          page = pdf.get_page(idx)
          pil_image = page.render(
              scale=dpi / 72,
              rotation=0,
          ).to_pil()
          images.append(pil_image)
          page.close()
      for i, image in zip(pages, images):
      
  5. Take It for a Spin! With our patch in place, you’re ready to go.

    • To run it while your venv is active:

      nougat --help
      
    • To run it from anywhere, just use the full path:

      /path/to/nougat/.venv/bin/nougat --help
      
    • And when you’re done, you can leave the virtual environment:

      deactivate
      

Full disclosure: I’ve actually switched to using marker for my own work. I find it way more powerful than nougat, and the best part is how lightweight and fast it is—it runs like a dream even on a CPU-only machine.

After years of using Bitbucket for personal version control, I’ve decided to migrate to GitHub. While I still feel Bitbucket offers advantages in user experience and pricing, my main motivation is specific to my workflow: I couldn’t find a satisfactory Emacs client for Bitbucket. This ultimately prompted the move to GitHub.

For interacting with GitHub in Emacs, I recommend consult-gh. It leverages the GitHub CLI (gh) and Consult to provide easy control and browsing of GitHub directly within Emacs. I won’t detail its features here, but if you’re interested in managing GitHub without leaving Emacs, give consult-gh a try.

I’ve just created a script using Tersercat for OCR on PDF or image files. Since Tesseract cannot directly handle PDF files, I employ ImageMagick to convert them into PNGs before proceeding with OCR. For multi-page PDFs, the script converts each page into a separate PNG and processes them individually, consolidating the results into a single file with “==== New Page [page name] =” marking the separation between pages.

The script offers four options:

  • `-h`, `–help` : Displays the help message
  • `-r <resolution>` : Sets the resolution for PDF conversion, defaulting to 300 DPI
  • `-l <language>` : Specifies the OCR language, defaulting to English; refer to Tesseract for available languages
  • `-p`, `–prompt` : Prompts the user before overwriting an existing output file; without this option, the script automatically overwrites the file
#!/bin/bash

# Set default values
DEFAULT_RESOLUTION=300
DEFAULT_LANGUAGE=eng

# Function to check and install required software
check_and_install() {
    if ! command -v "$1" &> /dev/null; then
        echo "Error: $1 is not installed."
        echo "Install using: sudo apt-get install $1"
        exit 1
    fi
}

check_and_install convert
check_and_install tesseract


# Function to handle potential errors and cleanup
handle_error() {
    rm -f "$OUTPUT_IMAGE_PREFIX"*.png 2>/dev/null
    exit 1
}

# Help function
help_message() {
    echo "Usage: $0 [OPTIONS] <input_pdf> [output_txt]"
    echo "  Options:"
    echo "    -h, --help           Display this help message"
    echo "    -r <resolution>      Specify resolution for conversion (default: $DEFAULT_RESOLUTION DPI)"
    echo "    -l <language>        Specify OCR language (default: $DEFAULT_LANGUAGE)"
    echo "    -p, --prompt         Ask user if overwrite existed output file"
    exit 0
}

LANGUAGE="$DEFAULT_LANGUAGE"
RESOLUTION="$DEFAULT_RESOLUTION"
OVERWRITE=1
# Parse options
while getopts ":r:l:h:p" opt; do
    case $opt in
        r) RESOLUTION="$OPTARG";;
        l) LANGUAGE="$OPTARG";;
        h) help_message; exit 0;;
        p) OVERWRITE=0;;
        \?) echo "Invalid option: -$OPTARG"; handle_error;;
    esac
done

shift $((OPTIND - 1))


if [[ $# -lt 1 ]]; then
    # echo "Error: Please specify an input PDF file."
    echo "Error: Please specify an input image file."
    help_message
fi

INPUT_FILE="$1"
shift

OUTPUT_TEXT="output.txt"
if [[ -n "$1" ]]; then
    OUTPUT_TEXT="$1"
fi

if [ "$OVERWRITE" -eq 0 -a -f "$OUTPUT_TEXT" ]; then
    echo "$OUTPUT_TEXT already exists, overwrite it? (yes/no): "
    read answer
    case "$answer" in
        yes|yes)
            rm "$OUTPUT_TEXT" 2>/dev/null
            ;;
        no|no)
            exit 1
            ;;
    esac
fi

OUTPUT_IMAGE_PREFIX="${INPUT_FILE%.*}"

if [ ! -f "$INPUT_FILE" ]; then
    echo "Error: Input file not found: $INPUT_FILE"
    exit 1
fi

# Use the file command to determine the file type
file_type=$(file -b --mime-type "$INPUT_FILE")

if [ "$file_type" == "application/pdf" ]; then
    convert -density "$RESOLUTION" "$INPUT_FILE" "$OUTPUT_IMAGE_PREFIX"-%04d.png 2>/dev/null || handle_error
    for img in "$OUTPUT_IMAGE_PREFIX"*.png; do
        OUTPUT_PAGE_TEXT="$img"
        echo "converting new page.."
        tesseract "$img" "$OUTPUT_PAGE_TEXT" -l "$LANGUAGE" 2>/dev/null || handle_error
        echo "================" >> "$OUTPUT_TEXT"
        echo "== Page $page ==" >> "$OUTPUT_TEXT"
        echo "================" >> "$OUTPUT_TEXT"
        cat "$OUTPUT_PAGE_TEXT".txt >> "$OUTPUT_TEXT"
        rm -f "$OUTPUT_PAGE_TEXT".txt
    done
    rm -f "$OUTPUT_IMAGE_PREFIX"*.png 2>/dev/null
else
    tesseract "$INPUT_FILE" "${OUTPUT_TEXT%.*}" -l "$LANGUAGE" 2>/dev/null || handle_error
fi

echo "OCR completed successfully. Output in $OUTPUT_TEXT"

I uploaded the script to my github repository

My .emacs file has more than 2500 lines, making it increasingly difficult to maintain. At the same time, I frequently update my .emacs for two main reasons:

  • There are new modes that I really want to use (Emacs enthusiasts will know what I mean)
  • I need to modify my .emacs configuration to fix bugs caused by the latest Emacs update.

Finally, I have decided to find a smarter way to maintain my .emacs file. My solution is to use org mode with org-babel.

Babel is an org mode extension that allows org to execute source code within an Org document. It is a powerful and helpful tool for writing articles with source code snippets. Org-babel also provides a “tangle” function which links source code blocks in the Org document to external files. This linkage is bi-directional, meaning that updating the source code in a block in the Org document can easily tangle to the external source code files, and updates made to the source code file can also be easily reflected back in the source code block in the Org document it is linked to. Using the tangle function of babel, I can maintain the contents of my .emacs file in Org format and use org-tangle to automatically generate the .emacs file.

For exampale, let’s say I have an Org file as given below:

* Load Paths
#+begin_src emacs-lisp :tangle dot_emacs.el :comments link
  ;; Latest Org mode source code
  (add-to-list 'load-path "~/.emacs.d/org-mode/lisp")
  ;; mpvi
  (add-to-list 'load-path "~/.emacs.d/mpvi/")
#+end_src
* General Settings
#+begin_src emacs-lisp :tangle dot_emacs.el :comments link

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; General Settings
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (setq warning-minimum-level :emergency)

  (set-default-coding-systems 'utf-8)

  ;; preferred apprarence settings
  (size-indication-mode 1)
  (scroll-bar-mode 0)
  (menu-bar-mode 0)
  (display-battery-mode 1)
  (display-time-mode t)
  (display-line-numbers-mode 1)
#+end_src
* Make Emacs beautiful and east to use
** Lin mode
#+begin_src emacs-lisp :tangle dot_emacs.el :comments link

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; lin setting
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (require 'lin)
  (setq lin-face 'lin-blue) ; check doc string for alternative styles
  ;; You can use this to live update the face:
  ;; (customize-set-variable 'lin-face 'lin-green)
  (setq lin-mode-hooks
        '(bongo-mode-hook
          dired-mode-hook
          elfeed-search-mode-hook
          git-rebase-mode-hook
          ibuffer-mode-hook
          ilist-mode-hook
          ledger-report-mode-hook
          log-view-mode-hook
          magit-log-mode-hook
          mu4e-headers-mode
          notmuch-search-mode-hook
          notmuch-tree-mode-hook
          occur-mode-hook
          org-agenda-mode-hook
          tabulated-list-mode-hook))
  (global-display-line-numbers-mode)
#+end_src
** Pulsar mode
Pulsar mode is .........
#+begin_src emacs-lisp :tangle dot_emacs.el :comments link

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; pulsar: hightlight current line
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (require 'pulsar)

  (setq pulsar-pulse-functions
        '(recenter-top-bottom
          move-to-window-line-top-bottom
          reposition-window
          forward-page
          backward-page
          scroll-up-command
          scroll-down-command
          org-next-visible-heading
          org-previous-visible-heading
          org-forward-heading-same-level
          org-backward-heading-same-level
          outline-backward-same-level
          outline-forward-same-level
          outline-next-visible-heading
          outline-previous-visible-heading
          outline-up-heading))

  (setq pulsar-pulse-on-window-change t)
  (setq pulsar-pulse t)
  (setq pulsar-delay 0.1)
  (setq pulsar-iterations 10)
  (setq pulsar-face 'pulsar-red)
  (setq pulsar-highlight-face 'pulsar-yellow)

  (pulsar-global-mode 1)

  ;; OR use the local mode for select mode hooks

  (dolist (hook '(org-mode-hook emacs-lisp-mode-hook))
    (add-hook hook #'pulsar-mode))
#+end_src

This Org file has three headings: “Load Paths”, “General Settings”, and “Make Emacs Beautiful and Easy to Use”. I placed all of the load-paths under the “Load Paths” heading, and some general settings under the “General Settings” heading. For modes that modify Emacs' default interfaces or make Emacs more convenient to use, I placed their configurations under the “Make Emacs Beautiful and Easy to Use” heading. You can certainly add any heading you like, such as a “Coding” heading for modes related to programming. The contents you want to include in .emacs can be well organized using Org.

In the above sample Org file, there is a property in every source code block.

:tangle dot_emacs.el :comments link

This directs org-babel to extract the current source code block and save it to an external file named dot_emacs.el. Since all the source code blocks in the previous Org file are being saved to the same dot_emacs.el file, when Org executes the tangle command, all these source code blocks will be automatically included in the dot_emacs.el file. To tangle the source code, simply

M-x org-babel-tangle

Then, there should be a dot_emacs.el file in the same folder as the Org file. It is something like

;; [[file:test.org::*Load Paths][Load Paths:1]]
;; Latest Org mode source code
(add-to-list 'load-path "~/.emacs.d/org-mode/lisp")
;; mpvi
(add-to-list 'load-path "~/.emacs.d/mpvi/")
;; Load Paths:1 ends here

;; [[file:test.org::*General Settings][General Settings:1]]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General Settings
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq warning-minimum-level :emergency)

(set-default-coding-systems 'utf-8)

;; preferred apprarence settings
(size-indication-mode 1)
(scroll-bar-mode 0)
(menu-bar-mode 0)
(display-battery-mode 1)
(display-time-mode t)
(display-line-numbers-mode 1)
;; General Settings:1 ends here

;; [[file:test.org::*Lin mode][Lin mode:1]]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; lin setting
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'lin)
(setq lin-face 'lin-blue) ; check doc string for alternative styles
;; You can use this to live update the face:
;; (customize-set-variable 'lin-face 'lin-green)
(setq lin-mode-hooks
      '(bongo-mode-hook
        dired-mode-hook
        elfeed-search-mode-hook
        git-rebase-mode-hook
        ibuffer-mode-hook
        ilist-mode-hook
        ledger-report-mode-hook
        log-view-mode-hook
        magit-log-mode-hook
        mu4e-headers-mode
        notmuch-search-mode-hook
        notmuch-tree-mode-hook
        occur-mode-hook
        org-agenda-mode-hook
        tabulated-list-mode-hook))
(global-display-line-numbers-mode)
;; Lin mode:1 ends here

;; [[file:test.org::*Pulsar mode][Pulsar mode:1]]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; pulsar: hightlight current line
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'pulsar)

(setq pulsar-pulse-functions
      '(recenter-top-bottom
        move-to-window-line-top-bottom
        reposition-window
        forward-page
        backward-page
        scroll-up-command
        scroll-down-command
        org-next-visible-heading
        org-previous-visible-heading
        org-forward-heading-same-level
        org-backward-heading-same-level
        outline-backward-same-level
        outline-forward-same-level
        outline-next-visible-heading
        outline-previous-visible-heading
        outline-up-heading))

(setq pulsar-pulse-on-window-change t)
(setq pulsar-pulse t)
(setq pulsar-delay 0.1)
(setq pulsar-iterations 10)
(setq pulsar-face 'pulsar-red)
(setq pulsar-highlight-face 'pulsar-yellow)

(pulsar-global-mode 1)

;; OR use the local mode for select mode hooks

(dolist (hook '(org-mode-hook emacs-lisp-mode-hook))
  (add-hook hook #'pulsar-mode))
;; Pulsar mode:1 ends here

By doing this, maintaining my .emacs becomes really easy. :-)

I have just uploaded some of my personal Emacs tools on GitHub and made them public.

This repository includes some of my Lisp tools that I use in my everyday work. All these tools are very personal, which means that I may not provide detailed support, and they may have bugs. Additionally, since they are designed for my personal use, the interface or usage may not be user-friendly, making it difficult for some people to use them.

However, I am sharing these tools for those who have a similar working style to mine. It would be highly appreciated if you download these tools, and even more so if you provide feedback for any improvements.

I will continue to upload my tools to the repository, and I also hope that people will share their personal tools with me as well. :-)

I heavily rely on org mode for my daily schedule, project management, personal learning, paper/book reading, and all forms of writing. One of the crucial aspects of my workflow is using org-agenda to gather my schedules, to-dos, and appointments from all the org files in my working folder. This function has significantly improved my efficiency.

However, org-agenda does not automatically update the file list for aggregation. For instance, if you set org-agenda-file to monitor a folder such as $HOME/Org/Work, org-agenda fails to add a new org file under $HOME/Org/Work to its file list unless you manually update org-agenda-file by evaluating the command

(setq org-agenda-file '(xxx xxx xxx))

again.

To solve the problem, I first try to get help by using filenotify mode. The plan is to utilize the file-notify-add-watch function of filenotify to monitor files or folders for org-agenda’s aggregation. Whenever there is any change, it will automatically re-evaluate org-agenda-file. After doing some research, I wrote a script similar to this.

(require 'filenotify)
(defun my-notify-callback(event)
  (setq org-agenda-files (append
                          '("path_to_folder")
                          )))
(file-notify-add-watch
 "path_to_folder" '(change attribute-change) 'my-notify-callback)

I believe this is the best solution for my problem. However, it appears that it is not working as expected, and I am unsure why. Despite my attempts at debugging and searching for solutions on Google, I have had no luck so far.

Thus, I opted for another method. I added a hook function that evaluates org-agenda-file to the org-agenda-mode-hook. The code is straightforward:

(defun my-set-agenda-files()
  (setq org-agenda-files (append
                          '("path_to_folder")
                          )))
(add-hook 'org-agenda-mode-hook 'my-set-agenda-files)

The Org-agenda-mode-hook is activated before org-agenda is executed, meaning that Emacs will evaluate org-agenda-files every time org-agenda is invoked or restarted. While this solution may not be perfect, especially for those with a large number of org files in the watched folder, it works for my needs. Additionally, since I do not have a large number of org files in my working folders, the potential slow down issue is not a concern for me.

Note: org-agenda-files does not monitor all the org files within a specific folder. I am not sure where the problem lies, but it seems like org-agenda only gathers the org files directly within the folder specified and does not look up files recursively. To resolve this issue, you can specify the folder as follows:

(setq org-agenda-files (append
                        '("path_to_a_file")
                        (directory-files-recursively "path_to_folder" "\\`[^.].*\\.org\\'")
                        )))

The function directory=files-recursively is the solution. :-)

In my line of work, writing slides for different purposes is a regular task. To ensure seamless work without leaving Emacs, I typically use org mode to create my slides and then present directly via org-tree-slide or export the org file to beamer. These methods work well for most of my presentations as the slides turn out simple and visually appealing. However, for more complex presentations that require multimedia such as embedded videos, large background images, animations, like those created in PowerPoint, additional steps may be necessary.

I do not wish to use PowerPoint as it is not available on Linux. While there are alternatives such as LibreOffice, WPS, and online document services like Google Sheets, I prefer to write my slides in Emacs using text.

There is an Org exporter called “org-reveal” available on GitHub that helps users write Org files and export them to reveal.js files. If you are unfamiliar with reveal.js, please visit the official website (https://revealjs.com/) for more information. Simply put, reveal.js is a framework for creating HTML-based presentations. It is a powerful tool, and the slides produced by Reveal.js are visually stunning. However, I found org-reveal somewhat challenging to use. For simple slides, the process is quite straightforward; write an Org file and export it using org-reveal. Then, open the exported HTML in the browser to present the slides. However, to fully leverage Reveal.js’s capabilities, you may need to customize your Org file using many “PROPERTIES.” Additionally, I found the layout definition of Reveal.js to be somewhat confusing. Of course, this is all subjective, and it could be that I simply do not have enough experience with Reveal.js or org-reveal. I’m sure there are many fans of org-reveal and Reveal.js out there; it’s just not my favorite tool.

What I finally found is Webslides, an HTML-based presentation tool that is different from Reveal.js in that it is very easy to use. Here’s how to use Webslides:

  1. Download the Webslides files (a zip file) from the top page of index.html of Webslides.
  2. Unzip the file.
  3. Start creating your slides by editing index.html under the root of the folder you just unzipped (or first rename the index.html to a new file name of your choosing).
  4. Open the file in a browser for presentation.
  5. Leverage Webslides' capabilities by simply copying and pasting HTML source code from files under the “demos” folder (HTML files under the “demos” folder are documents of Webslides).
  6. After finishing your slide writing, you can delete the demo folder and other files under the static/image folder not used in your slides to make your slide folder clean.
  7. Repeat the above steps for other slides writing.

Editing HTML files under Emacs is fairly simple, particularly when utilizing the web-mode mode. To streamline the process of writing content instead of designing slides, I created several Yasnippet snippets to insert HTML clips specifically for webslides. Here is an example:

# -*- mode: snippet -*-
# name: mywebslidesflexblock
# key: /mywebslidesflexblock
# --
<ul class="flexblock ${1:$$(yas-choose-value '("client" "client border" "steps" "features" "specs" "activity" "gallery" "metrics border" "plan blink"))}">
    <li>

    </li>
    <li>

    </li>
</ul>

The code snippet is used to insert a Webslides flexblock into the website. As shown, I have included options for various flexblock properties to customize the appearance of the block. With the help of these snippets, creating Webslides presentations becomes effortless, as I can concentrate on the content while leaving the design and layout aspects up to the code. This ensures that my pages look visually appealing and are easy to navigate using Webslides.

I still want to use org mode to make my slides, and I am considering writing an Org exporter for Webslides. I am not sure if I will be able to create it, but if I do, it will be the perfect tool for writing slides for me!

Note
I wrote a blog post on my old website about installing Debian on the Matebook X Pro 2019 in 2019. Although it was written four years ago, I believe it is still relevant and helpful to some people today. I have now copied the post to my new website here, and while some of the information may be outdated, I have not made any updates. Please find the original blog post below

I recently purchased the Huawei Matebook X Pro, which I had been eyeing for a few weeks. While Apple is a great company with quality products, I had grown tired of their closed source OS and exclusive ecosystem. As a Linux user, I found myself spending the majority of my time on my Macbook Pro using open source software installed through iTerm and homebrew. What I truly desired was a laptop with a pure Linux operating system.

Unfortunately, Linux had serious power management issues in the past and Windows laptops could not compare to the beautifully designed Macbook. However, I am pleased to say that the power management issue has been resolved with current versions of Linux (see power management section below). And even more exciting, I finally found a laptop that exceeds the Macbook Pro in both design and hardware performance - the Huawei Matebook X Pro.

The laptop is stunning, as the image depicts.

Figure 1: Matebook X Pro 2019

Figure 1: Matebook X Pro 2019

With a price almost as same as the Macbook Pro (even slightly cheaper), its specifications are impressive.

display13.9 inch touchscreen LTPS LCD
contrast1500:1
resolution3K: \(3000\times 2000\)
fingerprintyes
CPUIntel core i7 8550U
mem16GB
HDD512GB SSD (NVMe PCIe)
graphicsNVidia Geforce MX150, GDDR5 2GB
speakerDolby Atoms surrounding speakers
battery15.8 Hours(official)
interfaceUSB-C X 2, USB-A X 1
weight1.33kg
size304mm X 217mm X 14.6

I won’t delve into the details of how excellent the Matebook X Pro is since this memo is solely about installing Linux on the device and not a product review. There are numerous review articles available online for anyone interested. In my opinion, it’s the best laptop in the market, surpassing even the Macbook Pro, and Huawei has truly outdone themselves!

For those interested, I’ve compiled a brief summary of my Linux (Debian 10) installation process on the Matebook X Pro below:

Follow the website https://techbear.co/matebook-pro-debian-linux-guide/ to create a bootable USB using the Debian testing netinst ISO file. Restart your computer (press F12) to initiate the installation process. The only important thing to keep in mind, as mentioned on the website, is that the

  • Debian netinst ISO does not include the driver for the Intel wireless card of the Matebook Pro X. Therefore, you need to manually download the driver from https://packages.debian.org/buster/all/firmware-iwlwifi/download and save the file in the newly created ‘firmware’ directory on the USB stick before installation."
  • google drive

    My everyday work heavily depends on Google Drive. Unfortunately, Google has not yet released a Linux version of Google Drive. (I am so disappointed with Google for this!) In Gnome, one can add their Google account to Gnome’s online account to use Google Drive as local folders. However, it is not a syncing scheme, but rather an online mount by Google-Drive-ocamlfuse, which can be very slow in some situations, especially for large file transfers. There are several commercial Google Drive clients for Linux, but I have found that the best one for me is Insync.

  • display

    The Matebook X Pro features a HiDPI display with a resolution of \(3000\times 2000\), which can cause the default windows of many Linux applications to appear very small. Personally, I use Gnome as my desktop manager, which takes care of this issue by enlarging its applications with a certain scale. Unfortunately, I do not have a general solution for non-Gnome applications. However, for those using QT-based applications, you can follow the steps outlined on this website to modify the application’s default resolution. To provide an example, I have created a script to launch Insync (my Google Drive client for Linux) with the adjusted resolution. Simply use this script instead of the original Insync command to start the application.

    QT_AUTO_SCREEN_SCALE_FACTOR=1 insync start
    
  • fingerprint

    The Matebook X Pro has a great fingerprint sensor, but unfortunately, Linux cannot recognize it. There are some people currently working on driving the fingerprint sensor for Linux, but the projects are still in progress. I hope this project will be officially released soon, as I personally don’t need the fingerprint sensor for quick login, so this problem doesn’t bother me.

  • power management

    Linux has suffered from not having good power management on laptop for a long time, however things seem have changed in recent years. TLP is a great power management tool for Linux that has dramatically improved the battery life of laptops, as reported on the internet (example report 1 , exmpale report 2)

    To use TLP, simply…

    sudo apt install tlp tlp-drw tlpui # tlpui is a python GUI for tlp.
    

    With TLP, in my case, a full charge can support at least up to 7 hours usage.

  • speaker

    The Matebook X Pro has a fantastic 4-speaker system that is supported by DOLBY Atmos. To use it with Linux, check out “Update 1” on this blog.

I am constantly searching for a simple way to maintain and update my personal website. Here is what I would like to achieve:

  • Updating the website without having to leave Emacs
  • Writing all content in org mode
  • Managing versions of my source code
  • Creating a static website with no database or dynamic content generation
  • Enabling full-text search
  • Allowing comments
  • Including LaTeX equations, charts/figures, and multimedia through plain text, which automatically renders on my website
  • Designing a beautiful website

Essentially, all I need to do to maintain my website is write some text and save it. All other updating tasks should be automatically processed by a machine.

Some may believe this workflow impossible to achieve, but I have discovered some Emacs tools that fulfill most of the above functions. While none are flawless, they are still impressive and only require one more step to reach perfection.

Finally, I have found the solution. I can use hugo, oxhugo, and netlify. If you are reading this blog on my website, then you know how well this solution works.

Below, I summarize my setup for this workflow. There are numerous steps, and I do not describe them all in detail. However, if you have a basic understanding of Emacs, org-mode, and web applications, I believe this tutorial could be helpful. So let’s get started.

Hugo is known as

The world’s fastest framework for building websites – Hogo official website

For those who may not be familiar with Hugo, please check out its official website for more details. In Debian, you can easily install Hugo by

sudo aptitude install hugo

To get started using Hugo, follow the steps outlined in its documentation

$> hugo new site quickstart # make new project
$> cd quickstart # go into project folder
$> git init # start git
$> git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke themes/ananke # add a theme
$> echo "theme = 'ananke'" >> config.toml # set theme name in config
$> hugo server # start a local hugo develop site

There are many themes available for Hugo at https://themes.gohugo.io/, allowing you to customize your project even further. You can edit the config.toml file to configure Hugo, but for more detailed information, please refer to the Hugo documentation.

I assume that you are familiar with Emacs and org mode, or at least you use Emacs for your daily work. If you are not an Emacs user, then this article may not be for you. :-(

ox-hugo is an org exporter that exports org files to Hugo markdown files. To install ox-hugo, use package-install and add the following to your .emacs file:

(require 'ox-hugo)

Then you will be ready to go!

“Create a folder within your hugo project folder, such as ‘content-org’ or any name you prefer. There are two ways to write org files for Hugo: one post per file or one post per subtree. The latter is recommended by ox-hugo due to its flexible content exporting and use of inherited tags.

To facilitate exporting to Hugo, ox-hugo uses PROPERTIES in the org file to specify what and how to export to Hugo markdown files. Here are some examples:

:EXPORT_HUGO_SECTION: sectionname
:export_file_name: index
:export_date: 2023-04-04

I created Yasnippet snippets to simplify the process of writing these properties, but you can also create your own to make your life easier.

If you want to add shortcode for theme in ox-hugo, check ox-hugo’s shortcode document.

For a detailed usage guide of Ox-Hugo, please refer to its official website.

Setting up a Hugo theme may be the most important step in creating a website. There are many themes available on Hugo’s theme website, and you can select any theme you like. However, it’s important to note that a configuration for a specific theme may not work well for another. Therefore, it’s important to carefully choose a theme before publishing your website to avoid problems when transferring themes.

I choose LoveIt theme for my website, which I think it is simple and beautiful. I believe you can also find theme you like most. Most themes have very detailed configure document. The simplest way to make your own config file is to copy theme’s example config file and modify it.

  • Shortcode To embed equations or multimedia in you website, shortcode is what you have to check. It is very easy to add chortcode in Loveit, check here for details

  • Search I believe that the most important function for a static website is the full-text search. Most themes can add a search function by using online search services such as Lunr or Algolia. In my opinion, Lunr is easier to use than Algolia because it can be used locally without uploading an index file to its website, on the other hand, one has to upload an index file to Algolia to keep the search index updated. However, the downside of Lunr is that it cannot search CJK characters well, which prevented me from using it on my website. Instead, I use Algolia for my search backend.

    Fortunately, as I will mention later, if you host your website on Netfily like I do, the Algolia plugin for Netfily will take care of uploading the index for you, making use Algolia as simple as Lunr.

    I will come back to this topic on how to configure Algolia in Hugo in the next section of Netlify.

The final step in building your website is to select a website hosting service. Since we are discussing building a website using Hugo, the chosen website hosting service should be Hugo-focused. Currently, I believe Netlify is one of the best website hosting services for a Hugo-based website.

Go to Netlify and sign up for an account. Once you’ve signed up, log in to your account and select a plan. For a simple personal webpage like mine, which doesn’t involve large file transfers, I recommend choosing the free starter plan, as it should provide everything you need.

Under the personal account page, one can set up website hosting by clicking on “Add new site”. As the website source code is hosted on the Git server, the best way to add a new site to Netlify is by “Importing an existing project”. You can then choose the Git server where the source code is located. Follow Netlify’s instructions and select the repository of the website’s source code and other settings. After site settings, the next step is to link your domain to Netlify. This can be done easily by following Netlify’s instructions. If you don’t have your own domain, you can access your website through Netlify’s subdomain with a URL like “accountname.netlify.app” where “accountname” is the site name of your web hosting on Netlify that was set during site setting. It’s recommended to set up an SSL/TLS certificate for your website if your domain already has one.

To ensure that the domain is fully functional for web hosting, it is necessary to verify that the DNS settings have been updated on your domain management service with the NDS servers recommended by Netfily. Additionally, it is important to ensure that the ‘baseURL’ parameter in the ‘config.toml’ file of Hugo is correctly set to your domain address.

If you also host your domain’s email on a domain service like Google Domain, you have to migrate the email DNS record to Netlify, or else your email system may crash. For a complete migration to Netlify, follow the steps outlined by this website and this website:

  • Access your Netlify account page’s “Domain” setting and add a new DNS record.
  • Go to your current domain service website, such as Google Domain. In the DNS settings under “Google Workspace” and “Default name servers,” you will see DNS records like MX, SPF, and TXT.
  • Refer to the information above, return to your Netlify account, and add the new DNS records for MX, SPF, and TXT one by one.
  • After adding email DNS records, it’s time to set the domain pointing to Netlify. In the DNS settings of Google Domain, activate “Custom name servers,” then add Netlify’s name servers, found on the “Name server” list in the “Domain” setting on Netlify.
  • Add your domain as the primary domain in the “Domain” setting on Netlify.
  • Finished. The setting may take time to take effect, usually 10 minutes to a few hours, although Google claims it can take up to 48 hours to change.”

Here comes the last configuration - to me, the most important function needed by my website: searching. As I mentioned in the last section, I use Algolia service for search. Regardless of the service you use, Lunr or Algolia, the basic steps to add a search function to Hugo are the same. Go to the service website, sign up for an account, log in to the service, retrieve your service’s API information such as appID and API token, and configure the config.toml of Hugo to enable connection with the service via its web API.

Since I mentioned that using Algolia requires uploading an index file whenever the content to be indexed is updated, it is possible to create a script for automation to avoid having to do it manually. However, the best solution is to use Algolia’s Netlify plugin, which automatically uploads the index file to Algolia as soon as the website on Netlify is updated.

Thus, adding a search function using Algolia involves the following steps:

  • Signing up for an Algolia account and logging in
  • Following the tutorial on how to add a crawler for Netlify on the Algolia website
  • Editing the config.toml file to add Algolia parameters The format of the configuration may depend on the Hugo theme being used. Refer to the theme’s documentation to find out how to configure search parameters. In my case, I use LoveIt theme, the basic configuration may look like the following.
    [params.search]
      enable = true
      type = "algolia"
      contentLength = 4000
      placeholder = "search my website"
      maxResultLength = 10
      snippetLength = 30
      highlightTag = "em"
      absoluteURL = false
    [params.search.algolia]
      index = "indexname"
      appID = "ID"
      searchKey = "xxxxxxx"
      siteID = "xxxxx"
    

    Where “index” refers to the name of your Algolia indexing, which can be found on the “Crawler Netfily” application setting page on Algolia. “appID” is the ID of the “Crawler Netfily” application, “searchKey” is the “Search-Only API Key” for “Crawler Netfily”, and “siteID” is the “Site ID” of the Netfily web hosting. You can find the “Site ID” in the “Site Details” section of the site settings on Netfily.

Great news! The website construction is now complete. Here’s how you can post new content or add a new blog post to your website:

  1. Open the org file, which is the source for your website. Write your content along with the necessary properties for ox-hugo.
  2. Use the keybinding “C-e H” to export your content to a Hugo md file using the ox-hugo exporter of org mode.
  3. Commit the new content to git and push it to your hosting git repository.
  4. That’s it! Your website will be updated in a few seconds, and Algolia will also update its index for you.
  • If the website is hosted on Netlify, you don’t need to push the “public” folder to the Git server as Netlify will compile the md files and generate static HTML files for you. It’s recommended to add ‘public’ to .gitignore. When using ‘hugo server’ to preview changes on your local machine, Hugo will generate HTML files under the ‘public’ folder. Ignoring it in Git is a good idea.
  • I didn’t do this, but it’s possible to add hook functions to make the process from ox-hugo exporting to Git commit and push fully automatic. This could simplify the workflow: edit the org file, save it, and you’re done!
  • Using Yasnippet snippets can make adding properties to org files very simple.
  • Learn to use shortcodes in org files to make the website more beautiful and functional with multimedia. There are various methods to directly handle shortcodes in ox-hugo’s org file. Consider the example given below:
    • Firstly, add a header to the org file:
      #+HUGO_PAIRED_SHORTCODES: admonition
      
    • Then, you can add the admonition shortcode in the org file as follows:
      #+begin_admonition :type tip :title: "Note:" :open open
        This is my tip.
      #+end_admonition
      
    • You can use the above steps to include other shortcodes. In the code above, “type”, “title,” and “open” are parameters of the admonition shortcode.
    • For more details, please refer to this website and this website.
  • Enabling comments on the website is easy using comments services like Disqus or Gtalk. Please check LoveIt’s documentation for details.
  • To easily add a new post, you can configure an org template and add your website source org file to the re-file target. Then, you are able to start writing a post anywhere within Emacs. After writing, simply submit the template or refile it to the website source code. However, I haven’t done this yet. :-)

  1. Global patent in different country areas are counted respectively ↩︎