C

Ceeji 笃志者 - 宁心勉学,慎思笃行

Recent content in Ceeji 笃志者 on 宁心勉学,慎思笃行

百言神通如何下载使用?一文读懂

百言神通是全新一代智能学习辅助平台。覆盖各科学、练、问全环节,结合权威知识库和强大的 AI 智能技术,给你前所未有的学习体验。 如何找到百言神通 很多朋友不清楚百言神通要在哪里下载,安装?其实百言神通并不需要下载、安装,它是微信小程序,可以直接使用。打开你的手机微信,在上方搜索框中搜索“百言神通”,找到标注为“小程序”的那一项就可以马上使用了。 你也可以点击此处访问百言神通官网,官网也支持一键跳转打开。 百言神通小程序首页 那么,百言神通都有哪些功能呢?让我们一起来了解一下。 全科辅导,不会发脾气的好老师 百言神通覆盖小学到高中的主流学科,内置超过 5000 个权威知识点。无论是数学难题、物理公式,还是文科的重难点解析,每个知识点都配有详细的讲解,并通过 AI 智学功能,实现“边学边练”的高效学习模式。它能够根据孩子的学习进度和薄弱环节,精准推送针对性练习,确保学会为止,真正做到循序渐进。 作业好帮手,节约更多时间 在学习中遇到难题,不用再苦苦钻研或等待老师解答,百言神通的 AI 答疑功能可以拍照识别题目并快速解题,为孩子提供解题思路,甚至支持理科难题的多步推导过程。此外,它还教会孩子独立思考,提供思路点拨而非单纯给出答案,让学与练相辅相成。通过高效完成作业,孩子不仅能够更好地理解知识点,还能每天多省出半小时自由时间。 专属英语外教,提升语言能力 英语学习一直是很多孩子的痛点,而百言神通的“AI 外教”功能可谓解决了这一难题。无论是口语、听力,还是语法、词汇,百言神通都能提供全方位的学习支持。它通过八大场景的模拟对练,让孩子仿佛拥有了一位随身英语外教。口语发音还可进行精准分析,帮助孩子发现并改正发音问题,让发音更地道、更流利。无论是日常英语提升,还是备战雅思托福,这一功能都能满足需求。 写作灵感启发,轻松应对作文难题 对于作文难题,百言神通提供启发式辅导,从选题、思路到文章架构,它都能全程陪伴。写完后,它还支持智能批改功能,能够识别并修改错别字、优化表达、调整语句流畅度,让孩子的作文更上一层楼。不仅如此,百言神通还能帮助孩子通过范文学习积累表达技巧,从而逐步提升写作水平。 记单词更高效,掌握词汇背后的秘密 针对单词记忆,百言神通提供了三种高效记忆法:词根词缀法、造句法和词以类记法,让孩子在轻松有趣的环境中记住单词。同时,它的 AI 查词功能还可以提供海量例句,帮助孩子学会单词在不同语境下的使用。 总之,百言神通不仅让学习更加高效,还让孩子在学习中感受到乐趣和成就感。无论是刷题、解疑、英语练习还是作文辅导,百言神通都能像一位无所不知、永不疲倦的好老师一样,陪伴孩子成长。如果你还没有体验过百言神通,不妨现在就搜索试试吧!

2025/1/13
articleCard.readMore

《学会提问,驾驭 AI》相关资料获取

<p><figure> <a href="tip.png" target="_blank" class="no-a-style"> <picture> <source srcset="https://cdn.ceeji.net/gptbook/resources/tip.png"/><img title="" alt="" src="https://cdn.ceeji.net/gptbook/resources/tip.png"> </picture> </a></figure> </p>

2024/5/9
articleCard.readMore

百言 AI

window.location.href = "https://ai.ceeji.net/"

2024/5/9
articleCard.readMore

读者福利

window.location.href = 'https://www.baiyan.tech/assets/book-to-course/book-promotion.html';

2024/5/9
articleCard.readMore

加入 C 哥 AI 社群

长按下列二维码图片,在弹出菜单点击 「C哥助理」 即可加入: ↑长按二维码后点击「C哥助理」 如无法成功加入,请点击加入。 --> // window.location.href = 'https://work.weixin.qq.com/ca/cawcde7c03e2d6a13a'; 判断用户是否处于微信环境 if (navigator.userAgent.toLowerCase().indexOf('micromessenger') === -1) { alert('请使用微信扫描二维码打开,否则将无法加入社群。'); }

2024/5/9
articleCard.readMore

绍兴之旅(4):阳明故里、沈园与书圣故里

这次旅程的第四天,我主要去了绍兴的阳明故里、沈园和书圣故里。 此心光明——阳明故里 阳明故里是王守仁(即「王阳明」)的故居所在地,其建筑已经只剩地基上一些桩石之类,现在看到的大多数内容是近几年新建的。但是,它在考古挖掘的重点区域通过透明玻璃的方式保留了现场,因此你可以看到一些「真家伙」。我去的时候刚好碰到政府的观光团,有导游随行讲解,也因此大致了解了王阳明相关的一些故事。整体而言,这个地方能看到的东西不多。 王阳明故居21mm f/6.3 E 17-28mm F2.8-2.8 王阳明故居玻璃下的考古现场17mm f/2.8 E 17-28mm F2.8-2.8 王阳明对死生非常豁达。据说其临死前留下的遗言为:「此心光明,亦复何言?」 此心光明20mm f/2.8 E 17-28mm F2.8-2.8 除了建筑,这个景点还有一个王阳明的纪念馆。但是里面的东西不是很多。看完阳明故里,我就抓紧赶往沈园,因为此刻已经是下午三四点钟。 去沈园步行路上27mm f/2.8 E 17-28mm F2.8-2.8 沈园门口的小河27mm f/2.8 E 17-28mm F2.8-2.8 沈园 昨天我去看了沈园之夜,今天继续来看白天的沈园。沈园也是建国后重修的,在门口有重修之记。 重建沈园碑记24mm f/2.8 E 17-28mm F2.8-2.8 沈园的名气几乎全依赖于陆游在此的故事。简单来说,陆游在父母的安排下,迎娶表妹唐婉为妻。两人的婚姻虽然是父母之命媒妁之言的老式婚姻,可是却超乎寻常的幸福。陆游的母亲唐氏本是这场婚姻的主导者,可是,在唐婉过门之后不到三年,唐氏就对自己的侄女唐婉厌恶不已,强逼着儿子把唐婉赶走。主要原因一是觉得陆游沉湎女色,不务正业,让父母焦虑不安。另一个原因,可能是唐婉不孕。古人多希望「早生贵子」,像陆游续娶王氏,次年就生了一个大胖小子。可唐婉婚后两年多,肚皮竟然一点消息也没有。这在古代可是「七出」之首的严重罪过。 于是,唐婉就有了两大罪名:让陆游倦于科举,影响仕途;婚后三年不孕,不能传宗接代。最终,陆母下令,将唐婉驱逐出陆家家门。 在31岁时,陆游偶然在春末游览沈园,巧遇唐婉,回想起过往种种,在沈园的墙壁上写下流传千古的《钗头凤》,表达自己的愁绪。据说后续唐婉也回诗一首,词牌也是「钗头凤」。 但这个故事的真实性我觉得很难说,很多细节在史料中没有证据。甚至有人认为唐婉这个名字是明清时编出来的,而且唐嫁也没嫁赵士程,赵士程是有老婆陈氏的,还有六个孩子,没了一个,剩下五个。 沈园中的两首钗头凤17mm f/2.8 E 17-28mm F2.8-2.8 沈园的风景是典型的江南园林。在入口有一块断了的石头,据说象征情缘断裂,我好奇这石头是不是重建沈园的时候专门找人砸开的? 断石27mm f/2.8 E 17-28mm F2.8-2.8 沈园的面积不小,重修经历了好几期,现在如果要全部转完需要点时间。里面有一个陆游的纪念馆,仅仅这一个纪念馆面积就不小。 陆游纪念馆最深处24mm f/2.8 E 17-28mm F2.8-2.8 书圣故里 我以为书圣故里是王羲之的某个故居之类,没想到又是一个历史街区,主要是古桥和古建筑。其中比较有名的是题扇桥。 书圣故里24mm f/2.8 E 17-28mm F2.8-2.8 题扇桥20mm f/2.8 E 17-28mm F2.8-2.8

2024/5/2
articleCard.readMore

绍兴之旅(3):兰亭景区、印山越国王陵、八字桥周边与沈园之夜

兰亭景区 因为公司有事,我在4月10日回到杭州处理事情。第二天,我重新出发踏上了旅途。这一次,我先来到了绍兴兰亭景区,这里主要是一些与王羲之有关的人文景观,其中最多的就是各种书法作品的石刻和亭台楼阁。据说「兰亭集序」就是王羲之在这里所写就。 兰亭入口24mm f/4.0 FE 24-105mm F4 G OSS 进入景区不久就是「鸢(yuān)池」,里面似乎养了几只鸢,但我并不知道「鸢」到底是什么,查了一下资料依然是云里雾里。 鸢池书法24mm f/4.0 FE 24-105mm F4 G OSS 鸢池的「鸢」56mm f/4.0 FE 24-105mm F4 G OSS 这里有一块康熙写的「兰亭」的碑,但在文化大革命中被损坏,成为残字。 「兰亭」碑亭24mm f/4.0 FE 24-105mm F4 G OSS 与之前一样,我并没有提前做什么功课,但我刚好碰到了它的「书圣节」,就是每年一度纪念王羲之以及举行一些书法活动的节日。因此,景区里人比较多,而且到处都是活动相关的内容。下面这张图的横幅就是活动所悬挂的,这里在我来之前不久刚举办过晋圣仪式。 晋圣仪式24mm f/4.0 FE 24-105mm F4 G OSS 在这个地方不远处就是传说中「九曲流觞」之地。一千年前,古人喜欢围坐在这样的小溪流边,放入酒杯,让酒杯顺水而流,流到谁那里就要作诗作文。而此刻,这个地方有几个外国留学生说着流利的中文在讨论问题。 流觞亭24mm f/4.0 FE 24-105mm F4 G OSS 九曲流觞之地24mm f/4.0 FE 24-105mm F4 G OSS 整个兰亭景区最多的就是「兰亭集序」,比如这里有一个非常高大的兰亭集序的书法碑文: 兰亭集序24mm f/4.0 FE 24-105mm F4 G OSS 由于书圣节,这里还在举办全国书法篆刻的展览。我进去简单看了一下,名家所写确实好看!我最喜欢的是下图中间的这一张: 书法篆刻展览24mm f/4.0 FE 24-105mm F4 G OSS 印山越国王陵 看完了兰亭景区,我马不停蹄地赶往旁边不远处地「印山越国王陵」。到了门口正好是下午4点整,停好车进去是4点2分的样子,保安不让进,说4点开始禁止进入,4点半停止营业。我执意要进,最后允许我进去了。这里是一个考古发现,发现的时间距今也不过二三十年。这个景区名气不太大,我是因为看地图发现的。这个陵墓缺乏直接的证据证明墓主人的身份,但据推测极有可能是越王勾践之父允常。这个王陵曾经在抖音上火过。 景区十分精简,在国内这种景区其实是不多见的。停车场就是一片土地,真的就只有土。而景区的入口旁边就是大片的农田。 印山越国王陵24mm f/4.0 FE 24-105mm F4 G OSS 在现场我看到了「木客大冢」四个大字,当时完全不明白是什么意思,看到上面有一只鸟的形状,更是非常神秘。后来查维基百科才知道这个地方在当地最初被称为「木客大冢」,因其所在地原为木客的聚居地而得名,是一座人工堆筑的大型古代墓葬。而这个山「印山」以前也叫「木客山」。 「木客大冢」24mm f/4.0 FE 24-105mm F4 G OSS 随着阶梯进入王陵内部后,又有一个保安看到了我,不耐烦地说快要下班了,让我不要进去。明明还有半个小时时间,王陵也很小,我就执意要进去。说真的,亲眼见到王陵还是挺壮观的,不虚此行。 王陵内部24mm f/4.0 FE 24-105mm F4 G OSS 王陵内部24mm f/4.0 FE 24-105mm F4 G OSS 王陵内部24mm f/4.0 FE 24-105mm F4 G OSS 有时候,不做规划的旅行最容易出现惊喜。在印山越国王陵,我没有见到一个游人,且天色已晚,又是强行进入,保安一直催,我本来并不觉得能看到什么东西。但我不但完整地看到了王陵内部,而且在往出口的时候偶然在地图上发现徐渭的墓地也在这个园区之中,于是躲过保安从山上小路直奔徐渭之墓。我基本不了解徐渭,一边走一边在网上简单了解了一下,知道他是明代中期的文学家和军事家。 路上经过一个私人的鱼塘,让人一度怀疑自己是不是还在景区之中。名字也十分有意思,叫「塘狗弄山塘」。 塘狗弄山塘24mm f/4.0 FE 24-105mm F4 G OSS 整个景区道路都人迹罕至,但标牌还比较清楚,而且路上竟然遇到了两三个刚从徐渭墓地出来的人。我加快了脚步,因为马上就四点半了,我想我估计进不去了。路上我路过一个指路牌,感觉字写得很有设计感,尤其是「渭」和「园」字格外好看,整体看也很庄重,于是拍了下来。 「徐渭墓园」路牌24mm f/4.0 FE 24-105mm F4 G OSS 快到的时候,路边种满了很小的松树,虽然不大但依然给人苍劲严肃之感,再加上四处宁静无人,气氛渲染的非常空灵。可惜的是,我还是没能进去,只能从墓园的门口遥望。可以感知的是,墓园内树木极多,花草繁茂。 去墓园的路上24mm f/4.0 FE 24-105mm F4 G OSS 徐渭墓园24mm f/4.0 FE 24-105mm F4 G OSS 八字桥周边 看完徐渭墓,我开车直奔八字桥,此时天色开始渐渐下雨。因为担心停车难,我把车停到了大概 1 公里外的一个停车场充电,然后步行前往八字桥周边。在来这里之前,我完全不清楚这里是什么。快到终点的时候,看到了一个天主教堂。再走几步路,八字桥映入眼帘,我才发现这里比我想象的要值得来看很多。几个词总结——纯天然、很干净、大面积、江南烟雨。 天主教堂35mm f/1.4 FE 35mm F1.4 GM 八字桥之牌35mm f/1.4 FE 35mm F1.4 GM 具体来说,这是一大片保留非常好的传统街区,有桥有水、建筑优美,商业化程度刚刚好,且原住民非常多。随便走走就能走到别人家里。因为刚好下雨,从桥上远眺,一片江南烟雨。 江南烟雨35mm f/1.4 FE 35mm F1.4 GM 八字桥周边35mm f/2.0 FE 35mm F1.4 GM 八字桥与水上乌篷船35mm f/2.0 FE 35mm F1.4 GM 走在其中,商业气息不是很浓,且移步换景。 从一个小巷中出来还有一个漂亮的寺庙。 沈园之夜 沈园即「沈氏园」,是绍兴的一个园林。里面流传着陆游的一个感情故事。这个景区做了一个晚上看的剧目「沈园之夜」,我趁着夜色把它给看了。我本来一度认为今天看不成了,因为当时雨下的挺大,但到了演出快开始的时候,雨差不多停了。我也刚好在演出开始前两三分钟才赶到了沈园。 但我认为这个剧写的不好,演的也一般。其实这个剧目确实也不好演,因为沈园之夜显然主要是说沈园,但陆游的这个感情故事,应该只有几个片段发生在沈园,大多数时候和沈园关系不大。在剧目中,硬生生被描绘成发生在沈园的故事,这在逻辑上有点怪。 沈园之夜35mm f/1.4 FE 35mm F1.4 GM

2024/4/30
articleCard.readMore

结合 TextRank 与 TF-IDF 更精准的提取文章关键词

我们往往需要从大量的文本中迅速提取出核心关键词,以便快速把握文章主旨。如果要做信息流分发、基于内容的推荐算法,这也是其中很重要的步骤,一般用于文章特征。 传统的 TF-IDF 方法虽然广泛使用,但有时候它并不能完全准确地反映出文章的关键内容。实际上,TextRank、PositionRank 等任意算法都很难保证不遗漏重要的关键词。为了提高关键词提取的准确性,我们可以采用结合多种算法的方式来提取关键词。我在产品中使用了 TextRank 算法和 TF-IDF 的方法来结合,实测效果不错。 不同的库实现的关键词提取,结果往往不同,因为其实现细节有优劣之分。这里我使用的是 pke_zh 和 textrank4zh 库,通过 Python 代码实现这一过程。 在介绍代码实现之前,我们先简单回顾一下 TF-IDF 和 TextRank 的基本概念。 TF-IDF TF-IDF(词频-逆文档频率)是一种用于信息检索与文本挖掘的常用加权技术。它通过计算词语的频率(TF)和其在文档集中的分布(IDF)来评估一个词语对于一个文件集或一个语料库中的其中一份文件的重要程度。TF-IDF 值越大,这个词在文本中的重要性越高。 你可以在这篇文章查看具体的计算方法和公式。 TextRank TextRank 是一种基于图的排序算法,通过将文本分割成多个单词,并将这些单词作为图中的节点,通过节点之间的相互影响,计算每个节点的重要性。在关键词提取的场景中,TextRank 可以帮助我们找出文本中的高权重关键词。 接下来,我们将详细讲解如何使用代码实现更精准的关键词提取。 文本预处理:首先,我们将文本转换为小写,并使用正则表达式移除所有的数字,这是为了确保后续处理的文本是纯粹的文本数据。 关键词提取:我们使用 TfIdf_m.extract 方法和 tr4w.analyze 方法分别提取 TF-IDF 和 TextRank 的结果。 关键词合并与向量生成:将两种方法提取的关键词合并,并为每个关键词生成相应的 TF-IDF 和 TextRank 向量。 数据归一化:为了使不同的指标具有可比性,我们使用 MinMaxScaler 对数据进行归一化处理。 混合向量计算:将归一化后的 TF-IDF 向量和 TextRank 向量按照一定的比例混合,从而得到一个综合考虑两者的混合向量。 关键词排序:根据混合向量的值对关键词进行排序,并选出排名前20的关键词作为最终的关键词。 完整代码如下,你可以花不到 1 元钱来查看这段代码,开箱即用: 此部分内容不支持在 RSS 阅读器中显示,请打开本文链接查看:https://ceeji.net/blog/combine-tf-idf-text-rank/ 通过结合 TF-IDF 和 TextRank 算法,我们可以更全面地考虑词语的重要性和文本结构,从而提高关键词提取的准确性。以上代码实现了一个基于这两种技术的混合关键词提取方法,有助于我们在实际应用中抽取出更加精准的关键信息。

2024/4/30
articleCard.readMore

绍兴之旅(2):会稽山兜率天、仓桥直街与鲁迅故居

会稽山兜率天 会稽山是绍兴名山,在中国历史上也有重要地位,后面我们还会多次提到这座山。虽然如此,但我此次来到会稽山并没有什么准备。当时我在前一天晚上看过柯桥古镇之后,就在地图上寻找附近可去的地方,发现了「会稽山兜率天景区」的字样,然后在网上简单搜了几句就决定第二天过去看看。我感觉,「会稽山」是一大片山脉,因为还有其他地方也属于会稽山。 这个地方的第一印象并不好,因为我不喜欢被强迫要求坐景区大巴上山,但也没有办法。上山之后我发现这个景区有个特别之处——景区大巴直接把我拉到了靠近山顶的地方,而且下车后先进入了一个建筑之内,里面全是纪念品商店。一般景区的纪念品商店都在出口,它却在入口。另外,走过纪念品商店后,需要坐好几层的电梯,然后会到达一个十分宽阔恢弘的平台,平台尽头就是景区的第一个主要景点——龙华寺。 龙华寺17mm f/8.0 E 17-28mm F2.8-2.8 龙华寺的牌坊十分大气和恢弘,我使用腾龙 17-28mm 镜头超广角拍摄下来效果十分震撼(上图),惊讶到我了,在这之前我除了拍摄星空,很少使用这颗镜头的 17mm 端。 接下来是同样震撼的大殿和其屋檐: 大雄宝殿28mm f/8.0 E 17-28mm F2.8-2.8 超广角下的屋檐 龙华寺建筑精美,但除此之外乏善可陈。走过龙华寺的几个大殿之后,我远远看到了景区主打的标志性景观「兜率天宫」。 远眺兜率天宫20mm f/9.0 E 17-28mm F2.8-2.8 「兜率天」是梵文 Tusita 的音译,也译成「兜率陀」。六欲天之一。此天有内、外两院,内院是弥勒居住的净土,普通信众若信仰弥勒,称诵其名号,死后便可往生(即上生)此天。 这也是一个人工建筑,完工于 2015 年。兜率天作为佛教极乐净土的所在,之前只存在于宗教典籍之中。提出修建该建筑的是潘建国先生(国学大师南怀瑾先生的弟子),用于教化与文化传播,吸引大量游客前往,利于佛教文化传播。按照《弥勒上生经》中善财童子参弥勒的描述,他提取出兜率天宫的主要元素——宝宫形态像须弥山,山下有香水海、七重宝垣,莲花也是兜率天宫必不可少的重要特征。 在去往兜率天宫的路上,需要先下山,然后再爬山,最后到达刻有名字的石头。 兜率天宫石刻20mm f/9.0 E 17-28mm F2.8-2.8 近观兜率天宫,发现其中分很多层,建筑外侧是非常恢弘的阶梯,在中间一层正在进行陶瓷艺术品展览,标价不菲。 兜率天宫28mm f/9.0 E 17-28mm F2.8-2.8 兜率天宫内部17mm f/4.0 E 17-28mm F2.8-2.8 兜率天宫顶部18mm f/6.3 E 17-28mm F2.8-2.8 从兜率天宫下来,我想再去它的另一个景点「大香林」看看,但时间已经十分紧张。我沿着山路抄小道一路走过去,大概用了半个多小时,一路上全是笋,十分壮观。到了大香林后发现这里并没有什么太多东西,只有一些古树。因为景区即将关门,我匆匆看了几眼就直接走了。 大香林景区的绣球花50mm f/6.3 E 50-400mm F4.5-6.3 A067 离开会稽山兜率天后,在路上看到好几个「黄酒小镇」的牌子,网上查了一下似乎是一个值得去的地方,于是跟着标志停车,停好车后才发现被骗了——这个「黄酒小镇」实则为酒厂。里面还煞有介事地搞了个黄酒博物馆。搞笑的是,在地图上,黄酒小镇和黄酒博物馆都存在,但位置是距离这里十几公里的越城区;而这里所谓的的「黄酒小镇」和「黄酒博物馆」,地图上完全没有标志。不过,这里的风景还不错,里面有一整墙的李白将进酒的诗句,还做了一些爱喝酒的古人的塑像。 所谓「黄酒小镇」35mm f/8.0 FE 35mm F1.4 GM 所谓「黄酒博物馆」35mm f/8.0 FE 35mm F1.4 GM 爱酒之人塑像35mm f/4.0 FE 35mm F1.4 GM 鲁迅故里附近 离开「黄酒小镇」附近后,我一路直奔鲁迅故里附近。这附近我已经来过几次,但因为是绍兴最经典的一片区域,我还是决定在附近转转,倒不是一定要进入核心景点,更多的是要在附近的步行街转转,感受一下。把车停好充电后,我来到了鲁迅故里步行街的核心位置,这里有一家王奶奶臭豆腐,我吃了感觉还挺不错。 鲁迅故里步行街牌坊35mm f/4.0 FE 35mm F1.4 GM 王奶奶臭豆腐35mm f/3.2 FE 35mm F1.4 GM 附近的餐饮店及乌篷船专用河35mm f/3.2 FE 35mm F1.4 GM 不禁感慨一下,鲁迅养活了多少绍兴人。直到现在,多少店铺都是靠着它留下的「营养」而吸引客户,例如「孔乙己茴香豆」等等,不一而足。 不知不觉天黑了,我突然发现鲁迅故里晚上竟然也开门,就故地重游了一下,其实我更主要的是想看鲁迅纪念馆,上次疫情期间它晚上不开门,错过了。 在鲁迅故居中,给我留下主要印象的是绍兴的「祝福」仪式: 祝福35mm f/1.8 FE 35mm F1.4 GM 而在鲁迅纪念馆中,主要感慨于鲁迅原配朱安和在一起生活的许广平的故事,以及鲁迅晚期病中的状态。当然,鲁迅为治中国人心病的一路历程每看一次都令人动容。 俯首甘为孺子牛35mm f/1.8 FE 35mm F1.4 GM 非常幸运,鲁迅刻「早」字的课桌原件展出在纪念馆中,而这件文物在过去数十年间一直没有对外展出,都是复制件。你能在课桌上找到「早」字在哪里吗?我当时硬是没有找到,后来在网上查资料后重新找,才找到了它的位置。你可以放大下面图片仔细找找。 鲁迅在三味书屋的课桌35mm f/1.8 FE 35mm F1.4 GM 仓桥直街 离开鲁迅故里附近,我直奔不远处的仓桥直街。 仓桥直街路牌35mm f/1.6 FE 35mm F1.4 GM 如前所述,我这次旅行没有做过多攻略,因此对仓桥直街也没什么太大概念。但到了之后我发现,这个街的小巷子很长,且老房子还是挺多的,走走及拍拍照,很不错。当然,老房子里经营的肯定都是中国古街清一色的内容——特色小吃。 古街小巷35mm f/1.4 FE 35mm F1.4 GM 古街对联35mm f/1.4 FE 35mm F1.4 GM 可以看出绍兴政府为了提振旅游做了不少努力。比如在仓桥直街的十字路口,发现其交叉的街道挂满了灯笼,估计是想营造打卡点,但其实在这里拍照有点危险,车不少: 树上灯笼35mm f/1.4 FE 35mm F1.4 GM 彻底离开仓桥直街,回去取我车的路上,突然无意间看到了秋瑾的纪念塑像。在夜光下这样的场景具有独特的视觉效果,配合孙中山的题词「巾帼英雄」,显得格外圣洁和印象深刻,大量敬赠的鲜花摆放在路边,这种不期而遇的震撼让我有点懵。 秋瑾纪念塑像及鲜花35mm f/2.8 FE 35mm F1.4 GM

2024/4/29
articleCard.readMore

国内 AI 应用创业为何举步维艰?国内 AI 创业者的出路何在?

不知道大家有没有发现,在当前 AI 技术蓬勃发展的浪潮中,海外涌现出众多独立开发者凭借创新应用斩获成功,而反观国内,AI 创业之路却步履蹒跚。 即使抛开AI,这个现象其实已经持续了几年了,而且愈演愈烈。做互联网产品,国内互联网的这一现象背后,凸显出国内互联网生态中流量分配的失衡,以及平台政策对独立开发者的壁垒。 首先,国内互联网流量高度集中于移动端的头部应用。据统计,微信和抖音两大平台占据了绝大部分的用户使用时长。这意味着,对于初创团队而言,要在短时间内获取可观的用户规模,只能依附于既有平台,而平台往往对第三方应用抱有排他性。微信对小程序访问链接的限制,以及抖音对外链跳转的封禁,无不凸显出平台对流量的垄断和控制。 因此,创业者们无法引导用户走出平台,独立 App 的生存空间被极度压缩。 其次,头部平台基于自身的商业逻辑,更青睐变现效率高、有助于延长用户时长的内容形态。这导致短视频和直播成为平台重点扶持的方向,而创新型应用则难觅机会。不少创业者被迫转型,从事内容生产,在擅长的技术之外耗费大量精力。平台主导的商业生态,并未给创新软件应用预留发展的空间。 相比之下,海外市场则呈现出不同的图景。得益于开放而中立的社交网络,用户可以自由地在平台间跳转。加之海量的 Web 端流量,使得初创团队能够通过搜索引擎优化等手段,持续获得忠实用户。再者,推特、脸书等社交媒体允许外链的存在,用户可以在平台内发现新鲜应用,继而走出围墙花园,与开发者直接互动。这些因素共同构筑起良性循环,催生出更多新颖独特的 AI 应用,引领创新浪潮。 那么,国内 AI 创业者的出路何在? 挺难的。 从长远来看,只有打破头部平台对流量的垄断格局,创新的土壤才能培育而生。倘若 App 端主导地位动摇, Web 端的复兴将为创业者带来新的想象空间。 综上所述,国内 AI 创业之困,根源在于头部平台对流量的垄断割裂。 短期内,出海或许是最理想的选择,借助海外开放而活跃的互联网生态,让创意落地生根。 而从国内市场来看,要么顺应平台“游戏规则”发力内容领域,要么立足细分赛道开拓创新路径。无论何种选择,创业者们都需要保持敏锐洞察,随时调整策略。在 AI 革命的浪潮中,唯有直面挑战、把握机遇,才能成就非凡。

2024/4/25
articleCard.readMore

为了造车,抛妻弃子?还有多少老婆孩子要被牺牲?

希望以后我们国产汽车的发布会,不要一个个像内卷到内伤的孩子在诉苦。 1 我无意间看到了智己L6发布会上联席CEO刘涛的这么一段话: 我们的同学甚至连自己小孩子的出生都会错过 我们有同学一狠心 把自己年幼的孩子送去了寄宿制学校…… 我们国人什么时候才能不被这种话语所感动? 令人欣慰的是,这话一出,网上并非一片感动,而是炸了锅。有人调侃道:「少买一辆智己,就少一个寄宿的孩子。」 有的甚至给L6贴上了「抛妻弃子车」的标签。 这位高管的苦衷,或许只有他自己心里清楚。但是,这不禁让人思考:在汽车行业里,这样的家庭牺牲是不是成了常态? 其实,智己并非个例。有些车企不仅将周六定为正常工作日,还让员工「悄悄」规避法律风险。这种情况在业内已经不是秘密。 牺牲了个人和家庭生活,真的能造出好车,销量就能飙升吗? 2 汽车行业的高速发展,似乎让一些企业忘了,造车不仅仅是生产线上的机械运转,更是人的智慧和生活体验的结晶。 在汽车行业的无情竞赛中,有一课似乎被遗忘了:亨利·福特的智慧。 1914年,福特汽车公司推出T型车后,福特宣布了一个震惊世界的决策:工人的日薪将达到5美元。这一创举不仅仅是对社会公平的贡献,更是一条精明的商业法则。福特深知,只有当工资高且稳定时,工人才能成为消费者,市场才会稳定增长,他们才买得起T型车。 福特的这一理念开启了一个良性循环:待遇优厚的工人带来了消费需求,进而促进了业务扩张和就业增加。他是最早明确提出这个概念的商业领袖之一。 福特的智慧并非孤例,其他高管和强大的工会组织也采纳了这一理念,通用汽车和全美汽车工人联合会签订的《底特律条约》便是最好的证明。这种「利益共享资本主义」的理念,曾带领美国经历了二战后的经济黄金时期,创造了前所未有的中产阶级繁荣景象。那时的商界领袖们深信,企业的成功与工人福利成正比。 像标准石油公司的弗兰克·W·艾布拉姆和通用电气的厄尔·S·威利斯等人,都提倡平衡各方利益,认为员工的经济安全是企业最宝贵的资产。 然而,自20世纪70年代晚期以来,这一理念似乎逐渐被边缘化。生产力虽然大幅提升,但工人的实际工资和福利却几乎停滞不前。公司利润飙升,而中产阶级的收入却停滞,我们正在为这种转变付出代价。福特曾预言,如果普通民众没有稳定的收入增长,经济将会停滞不前。 现在,我们似乎正遭受着这一预言的验证。就像福特说的那样,如果普通民众没有收入稳步增长的稳定工作,经济就会停滞不前。自20世纪90年代初以来,世界已经多次陷入「失业型复苏」的泥沼。 我们不能忘记,在造车的过程中,不仅需要技术和创新,还需要人的智慧和生活体验。没有时间去享受生活的人,如何能够理解用户的需求,造出能触动人心的产品? 汽车行业的领袖们应该回顾历史,重新领悟福特的智慧:只有当中产阶级能从国家经济收入中分到更多的份额,经济才能更快增长,我们的产品也才能更加卓越。 毕竟,只有幸福的员工,才能造出让人幸福的车。

2024/4/23
articleCard.readMore

正确实现根据用户偏好自动切换网页中文简繁版本

很多人都没有正确地实现中文简繁体语言的自动切换,其实现有瑕疵,造成用户体验和 SEO 的问题。这篇文章直接给你一个终极答案,照抄就可以了。 在给出具体的代码之前,先普及几个知识点: 根据规范,中文的语言代码有两种形式,一种是根据简繁来标识,如 zh-hans 代表简体中文,zh-hant 代表繁体中文;另一种是根据地区来标识,如 zh-cn 代表中国大陆地区的中文,zh-tw 代表台湾地区的中文。我们的代码要兼容两种形式。 大多数中文网站没必要针对台湾、香港、新加坡等不同地域实现不同的语言切换,例如台湾和香港我们一般共用繁体中文。因此,网站的繁体中文语言 url 前缀应该使用 zh-hant 而不是 zh-TW 或 zh-HK。 为了 SEO,我们需要注意两件事: 应该在网站的 <html> 标签上添加 lang 属性,以便搜索引擎正确识别网站的语言; 对于搜索引擎的爬虫(蜘蛛),不要自动跳转到其他语言版本,否则可能会导致其无法索引到各种语言的版本; 一些用户不知道如何在浏览器或操作系统中设置自己偏好的语言,因此用户会在网页上手工切换到自己偏好的语言。我们需要记住用户选择的语言,避免重复跳转到操作系统或浏览器设置的语言。 下面是我们的终极代码。 在你网页的 JavaScript 脚本中,添加如下代码: const beforeSwitchLanguage = (lang) => { localStorage.setItem("preferred_lang", lang); return true; } window.beforeSwitchLanguage = beforeSwitchLanguage; const autoSwitchLanguage = () => { // 是否为搜索引擎蜘蛛 let isBot = /(Googlebot\/|Googlebot-Mobile|Googlebot-Image|Googlebot-News|Googlebot-Video|AdsBot-Google([^-]|$)|AdsBot-Google-Mobile|Feedfetcher-Google|Mediapartners-Google|Mediapartners \(Googlebot\)|APIs-Google|Google-InspectionTool|Storebot-Google|GoogleOther|bingbot|Slurp|[wW]get|LinkedInBot|Python-urllib|python-requests|aiohttp|httpx|libwww-perl|httpunit|Nutch|Go-http-client|phpcrawl|msnbot|jyxobot|FAST-WebCrawler|FAST Enterprise Crawler|BIGLOTRON|Teoma|convera|seekbot|Gigabot|Gigablast|exabot|ia_archiver|GingerCrawler|webmon |HTTrack|grub\.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|findlink|msrbot|panscient|yacybot|AISearchBot|ips-agent|tagoobot|MJ12bot|woriobot|yanga|buzzbot|mlbot|yandex\.com\/bots|purebot|Linguee Bot|CyberPatrol|voilabot|Baiduspider|citeseerxbot|spbot|twengabot|postrank|Turnitin|scribdbot|page2rss|sitebot|linkdex|Adidxbot|ezooms|dotbot|Mail\.RU_Bot|discobot|heritrix|findthatfile|europarchive\.org|NerdByNature\.Bot|sistrix crawler|Ahrefs(Bot|SiteAudit)|fuelbot|CrunchBot|IndeedBot|mappydata|woobot|ZoominfoBot|PrivacyAwareBot|Multiviewbot|SWIMGBot|Grobbot|eright|Apercite|semanticbot|Aboundex|domaincrawler|wbsearchbot|summify|CCBot|edisterbot|SeznamBot|ec2linkfinder|gslfbot|aiHitBot|intelium_bot|facebookexternalhit|Yeti|RetrevoPageAnalyzer|lb-spider|Sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web-archive-net\.com\.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|it2media-domain-crawler|ip-web-crawler\.com|siteexplorer\.info|elisabot|proximic|changedetection|arabot|WeSEE:Search|niki-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|CC Metadata Scaper|g00g1e\.net|GrapeshotCrawler|urlappendbot|brainobot|fr-crawler|binlar|SimpleCrawler|Twitterbot|cXensebot|smtbot|bnf\.fr_bot|A6-Indexer|ADmantX|Facebot|OrangeBot\/|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive\.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|S[eE][mM]rushBot|yoozBot|lipperhey|Y!J|Domain Re-Animator Bot|AddThis|Screaming Frog SEO Spider|MetaURI|Scrapy|Livelap[bB]ot|OpenHoseBot|CapsuleChecker|collection@infegy\.com|IstellaBot|DeuSu\/|betaBot|Cliqzbot\/|MojeekBot\/|netEstate NE Crawler|SafeSearch microdata crawler|Gluten Free Crawler\/|Sonic|Sysomos|Trove|deadlinkchecker|Slack-ImgProxy|Embedly|RankActiveLinkBot|iskanie|SafeDNSBot|SkypeUriPreview|Veoozbot|Slackbot|redditbot|datagnionbot|Google-Adwords-Instant|adbeat_bot|WhatsApp|contxbot|pinterest\.com\/bot|electricmonk|GarlikCrawler|BingPreview\/|vebidoobot|FemtosearchBot|Yahoo Link Preview|MetaJobBot|DomainStatsBot|mindUpBot|Daum\/|Jugendschutzprogramm-Crawler|Xenu Link Sleuth|Pcore-HTTP|moatbot|KosmioBot|[pP]ingdom|AppInsights|PhantomJS|Gowikibot|PiplBot|Discordbot|TelegramBot|Jetslide|newsharecounts|James BOT|Bark[rR]owler|TinEye|SocialRankIOBot|trendictionbot|Ocarinabot|epicbot|Primalbot|DuckDuckGo-Favicons-Bot|GnowitNewsbot|Leikibot|LinkArchiver|YaK\/|PaperLiBot|Digg Deeper|dcrawl|Snacktory|AndersPinkBot|Fyrebot|EveryoneSocialBot|Mediatoolkitbot|Luminator-robots|ExtLinksBot|SurveyBot|NING\/|okhttp|Nuzzel|omgili|PocketParser|YisouSpider|um-LN|ToutiaoSpider|MuckRack|Jamie's Spider|AHC\/|NetcraftSurveyAgent|Laserlikebot|^Apache-HttpClient|AppEngine-Google|Jetty|Upflow|Thinklab|Traackr\.com|Twurly|Mastodon|http_get|DnyzBot|botify|007ac9 Crawler|BehloolBot|BrandVerity|check_http|BDCbot|ZumBot|EZID|ICC-Crawler|ArchiveBot|^LCC |filterdb\.iss\.net\/crawler|BLP_bbot|BomboraBot|Buck\/|Companybook-Crawler|Genieo|magpie-crawler|MeltwaterNews|Moreover|newspaper\/|ScoutJet|(^| )sentry\/|StorygizeBot|UptimeRobot|OutclicksBot|seoscanners|Hatena|Google Web Preview|MauiBot|AlphaBot|SBL-BOT|IAS crawler|adscanner|Netvibes|acapbot|Baidu-YunGuanCe|bitlybot|blogmuraBot|Bot\.AraTurka\.com|bot-pge\.chlooe\.com|BoxcarBot|BTWebClient|ContextAd Bot|Digincore bot|Disqus|Feedly|Fetch\/|Fever|Flamingo_SearchEngine|FlipboardProxy|g2reader-bot|G2 Web Services|imrbot|K7MLWCBot|Kemvibot|Landau-Media-Spider|linkapediabot|vkShare|Siteimprove\.com|BLEXBot\/|DareBoost|ZuperlistBot\/|Miniflux\/|Feedspot|Diffbot\/|SEOkicks|tracemyfile|Nimbostratus-Bot|zgrab|PR-CY\.RU|AdsTxtCrawler|Datafeedwatch|Zabbix|TangibleeBot|google-xrawler|axios|Amazon CloudFront|Pulsepoint|CloudFlare-AlwaysOnline|Google-Structured-Data-Testing-Tool|WordupInfoSearch|WebDataStats|HttpUrlConnection|Seekport Crawler|ZoomBot|VelenPublicWebCrawler|MoodleBot|jpg-newsbot|outbrain|W3C_Validator|Validator\.nu|W3C-checklink|W3C-mobileOK|W3C_I18n-Checker|FeedValidator|W3C_CSS_Validator|W3C_Unicorn|Google-PhysicalWeb|Blackboard|ICBot\/|BazQux|Twingly|Rivva|Experibot|awesomecrawler|Dataprovider\.com|GroupHigh\/|theoldreader\.com|AnyEvent|Uptimebot\.org|Nmap Scripting Engine|2ip\.ru|Clickagy|Caliperbot|MBCrawler|online-webceo-bot|B2B Bot|AddSearchBot|Google Favicon|HubSpot|Chrome-Lighthouse|HeadlessChrome|CheckMarkNetwork\/|www\.uptime\.com|Streamline3Bot\/|serpstatbot\/|MixnodeCache\/|^curl|SimpleScraper|RSSingBot|Jooblebot|fedoraplanet|Friendica|NextCloud|Tiny Tiny RSS|RegionStuttgartBot|Bytespider|Datanyze|Google-Site-Verification|TrendsmapResolver|tweetedtimes|NTENTbot|Gwene|SimplePie|SearchAtlas|Superfeedr|feedbot|UT-Dorkbot|Amazonbot|SerendeputyBot|Eyeotabot|officestorebot|Neticle Crawler|SurdotlyBot|LinkisBot|AwarioSmartBot|AwarioRssBot|RyteBot|FreeWebMonitoring SiteChecker|AspiegelBot|NAVER Blog Rssbot|zenback bot|SentiBot|Domains Project\/|Pandalytics|VKRobot|bidswitchbot|tigerbot|NIXStatsbot|Atom Feed Robot|[Cc]urebot|PagePeeker\/|Vigil\/|rssbot\/|startmebot\/|JobboerseBot|seewithkids|NINJA bot|Cutbot|BublupBot|BrandONbot|RidderBot|Taboolabot|Dubbotbot|FindITAnswersbot|infoobot|Refindbot|BlogTraffic\/\d\.\d+ Feed-Fetcher|SeobilityBot|Cincraw|Dragonbot|VoluumDSP-content-bot|FreshRSS|BitBot|^PHP-Curl-Class|Google-Certificates-Bridge|centurybot|Viber|e\.ventures Investment Crawler|evc-batch|PetalBot|virustotal|(^| )PTST\/|minicrawler|Cookiebot|trovitBot|seostar\.co|IonCrawl|Uptime-Kuma|SeekportBot|FreshpingBot|Feedbin|CriteoBot|Snap URL Preview Service|Better Uptime Bot|RuxitSynthetic|Google-Read-Aloud|Valve\/Steam|OdklBot\/|GPTBot|ChatGPT-User|YandexRenderResourcesBot\/|LightspeedSystemsCrawler|ev-crawler\/|BitSightBot\/|woorankreview\/|Google-Safety|AwarioBot|DataForSeoBot|Linespider|WellKnownBot|A Patent Crawler|StractBot|search\.marginalia\.nu|YouBot|Nicecrawler|Neevabot|BrightEdge Crawler|SiteCheckerBotCrawler|TombaPublicWebCrawler|CrawlyProjectCrawler|KomodiaBot|KStandBot|CISPA Webcrawler|MTRobot|hyscore\.io|AlexandriaOrgBot|2ip bot|Yellowbrandprotectionbot|SEOlizer|vuhuvBot|INETDEX-BOT|Synapse|t3versionsBot|deepnoc|Cocolyzebot|hypestat|ReverseEngineeringBot|sempi\.tech|Iframely|MetaInspector|node-fetch|lkxscan|python-opengraph|OpenGraphCheck|developers\.google\.com\/\+\/web\/snippet|SenutoBot|MaCoCu|NewsBlur|inoreader|NetSystemsResearch|PageThing|WordPress\/|PhxBot|ImagesiftBot|Expanse|InternetMeasurement|^BW\/|GeedoBot|Audisto Crawler|PerplexityBot\/|[cC]laude[bB]ot)/g.test(navigator.userAgent); if (isBot) { return; } // 如果用户手工切换过语言,则记住 let preferredLang = localStorage.getItem("preferred_lang"); if (!preferredLang) { // 查找浏览器第一偏好的 'zh' 类语言 let lang = navigator.languages.find((l) => l.startsWith("zh")); if (lang) { let isPreferSC = lang == "zh-CN" || lang == "zh-SG" || lang == "zh-hans"; preferredLang = isPreferSC ? "zh-hans" : "zh-hant"; } } if (preferredLang) { // 注意:此处需要根据你自己网站的情况进行改写,以获取到正确的跳转 url。 // 查找 id 为 link-lang-[preferredLang] 的 a 标签指向的链接 let link = document.getElementById("link-lang-" + preferredLang); // 如果找到,自动跳转 if (link) { window.location.href = link.href; } } } 这里的主要逻辑如下: 我们在 beforeSwitchLanguage 函数中使用 localStorage 来存储用户偏好的语言。 在 autoSwitchLanguage 函数中,我们首先判断用户是否是搜索引擎蜘蛛,如果是,则不进行自动切换。 然后我们查找用户浏览器的第一偏好的中文语言,如果找到,则自动切换到简体或繁体中文。 如果用户手工切换过语言,则记住用户的选择,下次访问时自动切换到用户偏好的语言。 要注意的是,自动跳转到相应语言的部分,需要你根据自己网站的情况判断正确的跳转 url。 我自己网站实现中,网页会有一个指向另一种中文的链接,因此我这里使用的是查找链接对应的 url 的方法来实现。这种实现比较适合于 Hugo 等静态网站,一般主题中会自带语言切换链接,因此在 JavaScript 脚本中不需要再手工生成链接,而是引用网页上的链接,这样也增加了可维护性。 最后还要做一件事,在用户手工切换语言的链接上调用 beforeSwitchLanguage 方法并传入要跳转的语言代码,这样我们就记住了用户的偏好。例如,如果你通过 a 标签进行跳转,可以这么写: <a onclick="beforeSwitchLanguage('zh-hant')" id="link-lang-zh-hant" class="menu-link" href="xxxxxx">繁體中文</a> 也就是添加一个 onclick 事件。

2024/4/23
articleCard.readMore

绍兴之旅(1):羊山石境与柯桥古镇

2024年4月,我决定趁着春光来一段浙东的旅行,从杭州出发,穿过绍兴,沿着浙东唐诗之路前往嵊州、新昌、天台方向。 为了方便看沿路的风景,同时也为了节约成本,我决定通过自驾的方式旅行,晚上尽量睡在车上,一路上不走高速,尽量用电而不是油。整个旅行持续了一周左右的时间,中间公司有事就回杭州,没事就睡车里以便第二天继续旅行。 我这次旅行的目的有两个,一是多看看浙江的人文景色;二是游山玩水,锻炼身体。在路线选择上,我曾经在一个偶然的机会去新昌开过会,另外还去过一次十九峰,感觉那边的景色十分不错。 这次旅行整体比较匆忙,没有怎么做攻略,但实际效果比我预期的要好不少。另外,这次旅行过程中频繁下雨,也算是烟雨江南了。 羊山石境 我是在知乎一篇讨论浙东唐诗之路的文章上看到羊山石境的。但在去之前,我并不太了解羊山石境的实际情况。到达现场的时候正在下雨,下车之后映入眼帘的却是杭州亚运会的攀岩运动馆(绍兴柯桥羊山攀岩中心), 仔细看的话会发现这个运动馆旁边还有一个山头。 绍兴柯桥羊山攀岩中心(亚运会攀岩场地) 而真正的羊山石镜在停车场边上一个很小的小路尽头。在景区入口,我了解了今日羊山的来历: 绍兴古代属于越国。史载,隋开皇九年,豪强高智慧在越州自称天子,皇帝命晋王杨广、水师总督杨素兴兵讨伐。为防后患,杨素采羊山石筑罗城。 羊山本来是一个完整的大山,但在千百年的采石过程后,只剩下断崖残壁,但反而形成了自己独有的特色:佛在石中,石在水中,水在山中。 萧山与绍兴这一带的平原,属于钱塘江冲积平原。水多山少,山少,石头就少。然而筑城,钱塘江拦坝,处处要用石头,而且是大石头。 杨素在杭州筑城,在绍兴扩城,需要石头,就到羊山开采。钱镠呢,创业当年,攻克山阴郡,首先攻占的就是羊山,并在此驻扎。还有林则徐,当年在钱塘江加固江堤时,需要大量石头,采自羊山。所以,羊山活在很多大人物的奏折中。 羊山石境介绍 进入羊山石镜后,看到的是一大片水,是一个面积不太大的湖,中间修有游步道。沿着湖走,绿树成荫,水波荡漾,但没有看到其他东西。 因为在门口我已经知道了「佛在石中」的景观,所以我一直沿着路走,一直走到了湖的尽头。这里果然别有洞天,有一个小寺庙「石佛禅寺」。此时雨越下越大。 石佛禅寺内部 这个寺在外面看着其貌不扬,进入之后也只看到了一个普通寺庙的样子。但是在它的一个殿的左侧,有一个很小的门,里面黑黑的,没有什么特别的标识。 从这里走进去,发现了羊山石镜真正的核心景点——这里有一个阶梯,可以通往羊山被开采后留下的孤岩。在阶梯上,我看到了文人墨客的崖刻。 石佛禅寺崖刻墨宝 从题字来看,大多数石刻可能来自于清代和民国时期。回家后搜索得知,其中的「飞跃」二字传为南宋名将韩世忠书。 继续往前走可到一个修建于孤石中的佛殿,当时我以为已经走到头了,但是仔细一看,在殿里的右侧有一入口,沿着这个口往外走,就到了石佛峰石窟造像,为江南四大石佛之一。我没有拍照,但这个石佛是真的很壮观,尤其是他的手,非常的令人震撼! 从寺中出来回到羊山湖,发现在寺外湖边还有一个佛像,好像是观音像? 寺外佛像 柯桥古镇 柯桥古镇并非我此次规划中的路线,但好在距离羊山很近,地图上一搜我就过去了。到了之后发现这个地方景色还挺不错,虽然很商业化、且大多数为现代重修的仿古建筑,但整体规划设计在国内古镇中我认为是上乘的。由于正在下雨,颇有江南烟雨的感觉。 下面这张图拍摄于蓝调时分雨中的柯桥古镇,是我这次旅行中拍摄的最满意的照片之一: 蓝调时分雨中的柯桥古镇 在古镇中走了一会儿,穿过一个小桥后,远远看到了一个仿古桥,在烟雨中很是漂亮,算是这次的一个小惊喜。 柯桥古镇 在古镇中雨越来越大,我走的时间不太长就出来了。我发现附近全是新疆餐厅,于是我就随便找了一家新疆菜来吃,毕竟新疆面是真的好吃。意外的是,对方还送了个小菜。 新疆菜馆的小菜 新疆面

2024/4/20
articleCard.readMore

Grub Filter Not Found 修复:系统升级后的引导修复

症状 如果你在服务器启动时遇到了提示 Grub Filter Not Found 并自动进入 Grub Rescue(救援模式)的问题,本文给出了 完整的解决方案。 昨天晚上我对时隔三五年没有更新过的服务器进行了升级, 把 Debian 10 经过两次更新升级到了 Debian 12。 随着系统更新,PHP 也从 7.4 升级到了 8.2; Nginx 从 1.15 升级到了 1.22.1。 升级之后,系统运行一切正常,所有网站也都能正常访问。 为了保证长期运行的稳定性(我的服务器常年不重启),我打算 在服务器升级后顺道重启一次。结果这下可好,重启后直接无法使用了。 首先是 SSH 无法连接,然后通过云服务器的 Web 终端登录后, 发现屏幕显示内容如下: error: symbol 'grub_file_filters' not found. Entering rescue mode... grub rescue> 原因分析 迅速分析和查阅了相关的资料,发现这个问题应该是在系统更新 过程中破坏了引导的 grub 配置造成的。网上大部分的资料都 需要挂载系统恢复光盘镜像来执行 grub-install,来完成引导 的修复。但对于云服务器,这是不可行的, 因为你无法插入 修复光盘镜像。 如果你和我一样无法挂载系统恢复光盘镜像,我提供两个解决思路。 方法一:云盘挂载在救援主机 阿里云、AWS 等服务器支持挂载云盘到其他主机。而有些云服务器, 例如青云,提供了救援主机功能。你可以利用这些功能把受损的 系统盘挂载在一个可以正常启动的服务器上,然后在这个服务器上修复 你的引导。 具体步骤如下: # 切换到 root 权限 sudo su # 查询被挂载的损坏的系统盘的盼复 fdisk -l # 把损坏的系统盘的一些内容挂载到可以正常启动的服务器 # 这里假设你在 fdisk 中查询到的系统盘符为 sdc, # 且系统挂载在其中的 sdc1: mount /dev/sdc1 /mnt mount --bind /dev /mnt/dev mount --bind /dev/pts /mnt/dev/pts mount --bind /proc /mnt/proc mount --bind /sys /mnt/sys chroot /mnt # 执行引导修复 grub-install /dev/sda 假如一切顺利,系统会提示: Installation finished. No error reported. 此时别忘了取消挂载: # 退出 chroot exit # 取消挂载 umount /mnt/dev/pts umount /mnt/dev umount /mnt/proc umount /mnt/sys umount /mnt 然后把云盘重新挂载回损坏的主机,重启该主机,应该可以进入系统。 方法二:手工引导系统 如果你和我一样倒霉,在运行 grub-install 时不成功,或者你没法 挂载系统盘到其他可用的主机,还有一个办法,那就是手工通过 grub 引导 进入系统,然后在系统内修复 grub 安装。 首先运行你的主机,在出现下面的提示时: error: symbol 'grub_file_filters' not found. Entering rescue mode... grub rescue> 又或者你进入的是 grub 命令行,而不是 grub rescue,也是可以的: grub> 小心地按照下列步骤执行命令。 首先执行一个可以让长输出进行分页的指令: grub> set pager=1 不要有多余的空格。 然后列出自己的磁盘: grub> ls (hd0) (hd0,msdos2) (hd0,msdos1) 怎么出来了一个 msdos?这说明你的磁盘使用的是以前的 MS-DOS 分区模式,而不是 GPT 模式。这不重要。 我们的重点是找到你的启动盘。比如我们尝试 (hd0,1) 这个盘: grub> ls (hd0,1)/ lost+found/ bin/ boot/ cdrom/ dev/ etc/ home/ lib/ lib64/ media/ mnt/ opt/ proc/ root/ run/ sbin/ srv/ sys/ tmp/ usr/ var/ vmlinuz vmlinuz.old initrd.img initrd.img.old 通过 ls 指令,你可以确认这个盘的内容以分析它是不是我们的启动盘。 你也可以通过 cat 指令进一步确认系统的版本号: grub> cat (hd0,1)/etc/issue Ubuntu 14.04 LTS n l 假如你有多个系统或者多个盘符,一定不要搞错。 接下来手工引导系统(先别急着复制执行,看解释): # 看完解释后再执行哦 grub> set root=(hd0,1) grub> linux /boot/vmlinuz-3.13.0-29-generic root=/dev/sda1 grub> initrd /boot/initrd.img-3.13.0-29-generic grub> boot 注意: 这里的 (hd0,1) 是你要修复引导的实际磁盘,要反复核实清楚; 这里的 /boot/vmlinuz-3.13.0-29-generic 只是一个实例, 你执行的时候,打出 /root/vmlinuz,然后按 Tab 键选出你 实际的 linux 内核版本号,不要照抄。如果有多个内核版本,一般 选最新的。 这里 /boot/initrd.img-3.13.0-29-generic 同上。 现在你应该可以进入系统了。 注意,这时候别急着高兴,赶紧修复 grub 引导,不然下次重启还是无法正常进入: # 更新 grub > update-grub # 系统可能输出类似内容: # Generating grub configuration file ... # Found background: /usr/share/images/grub/Apollo_17_The_Last_Moon_Shot_Edit1.tga # Found background image: /usr/share/images/grub/Apollo_17_The_Last_Moon_Shot_Edit1.tga # Found linux image: /boot/vmlinuz-3.13.0-29-generic # Found initrd image: /boot/initrd.img-3.13.0-29-generic # Found linux image: /boot/vmlinuz-3.13.0-27-generic # Found initrd image: /boot/initrd.img-3.13.0-27-generic # Found linux image: /boot/vmlinuz-3.13.0-24-generic # Found initrd image: /boot/initrd.img-3.13.0-24-generic # Found memtest86+ image: /boot/memtest86+.elf # Found memtest86+ image: /boot/memtest86+.bin # done # 重新安装 grub > grub-install /dev/sda # 可能的输出: # Installing for i386-pc platform. # Installation finished. No error reported. 这时候你的系统应该完全恢复了。 参考资料: Classic SysAdmin: How to Rescue a Non-booting GRUB 2 on Linux

2024/4/3
articleCard.readMore

自动更新阿里云的 CDN HTTPS 证书

开源地址 Github 使用说明 这是一个可以自动更新你的阿里云 CDN 证书的命令行工具。 基于 Golang 开发。无需安装繁重的 Python。 可以结合 acme.sh、let's encrypt 等工具,免费使用证书。 通过这个方法,你不需要每隔几个月就去手工更新你的 CDN 证书了。 Clone 这个项目。 在项目所在文件夹中安装依赖: go mod init ceeji.net/aliyun-cdn-cert-bot go get "github.com/denverdino/aliyungo/cdn" 编译 main.go 即可使用: go build main.go 运行之前请设置下列环境变量: ACCESS_KEY_ID、ACCESS_KEY_SECRET 为阿里云有权限的 RAM 子账号信息; ALI_DOMAIN 为阿里云 CDN 域名(非源站域名); ALI_CERT_PATH 为 CDN 证书文件名(注意要用 fullchain 的证书,否则可能有些客户端会报错); ALI_KEY_PATH 为 CDN 证书密钥文件名。 建议结合 crontab 设置定时任务,每天执行一次。 对于 acme.sh 用户,你可以直接设置相关路径到 ~/.acme.sh/证书名称/文件 这样的路径。

2024/4/1
articleCard.readMore

本站从 Wordpress 迁移到 Hugo

时隔多年,本站终于进行了一次较大的更新,从 Wordpress 迁移到了 Hugo。这篇文章记录了迁移的原因和过程。 缘由 想从 Wordpress 迁移到 Hugo 已经有五六年了,但一直没有进行。想迁移的原因非常简单: Wordpress 越来越臃肿。尤其是最近几年,我几乎都不想登录到 Wordpress 后台,太多的插件年久失修,也不敢乱动,甚至 Wordpress 自身升级后连新建页面都打不开了; Wordpress 对 Markdown 的支持是非原生的;虽然使用插件后看似效果不错,但从数据源的角度来说,本质上它还是存储为 HTML 格式,这导致文章的结构化和批量处理效果一般。 网站的访问中有相当比例来源于繁体中文使用者,因此想更好的支持繁体中文的阅读和使用。 关键步骤 从 Wordpress 备份提取 Markdown 这是看似很简单的步骤,因为有好几个插件都支持相关的功能,也有一些命令行的脚本。但是,最要命的是转换并不完美。 我使用的是基于 NodeJS 的 blog2md 脚本。 这个脚本的使用很简单,只需要在 Wordpress 后台导出备份的 .xml 文件,然后执行脚本就行了。 你的计算机需要有 Node 环境。 要注意的是,一定按照其 README 中的说明,添加 paragraph-fix 参数,否则很多换行和段落会出现问题。例如: node index.js w your-wordpress-backup-export.xml out m paragraph-fix 但是即使你采用了上面的参数,转换出的文章很多依然是有问题的。主要表现在: 部分段落丢失,即缺少换行; 很多之前的代码高亮的内容出现了多余的转义,例如 * 变成了 \*、] 变成了 \]。 我的理解是当初为了在 Wordpress 中存储代码高亮,相关插件本身做了转义,但在导出数据时就很痛苦了。 (更要命的)以 < 开头的内容丢失。可能因为和导出格式为 XML 有关,出现了语义上的冲突。这部分可能只能自己修了。 例如一个 C++ 程序: template<typename T> class ... 可能会变成 template typename T\> class ... 所以,我需要写脚本来解决这个问题。 使用脚本处理多余的转义 下面是一个 NodeJS 脚本,用来批量将指定目录下的 md 文件的正文部分包裹的代码块中的多余转义进行修复。 例如,它将 \[ 修复成 [,\_ 修复成 _。 const fs = require('fs'); const path = require('path'); // 指定目录路径 const DIRECTORY_PATH = 'path/to/content'; // 递归地查找.md文件 function findMarkdownFiles(dirPath) { let filesToProcess = []; const files = fs.readdirSync(dirPath); for (const file of files) { const filePath = path.join(dirPath, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { filesToProcess = filesToProcess.concat(findMarkdownFiles(filePath)); } else if (path.extname(filePath) === '.md') { filesToProcess.push(filePath); } } return filesToProcess; } // 处理.md文件中的代码块 function processMarkdownFile(filePath) { const content = fs.readFileSync(filePath, 'utf8'); // 使用正则表达式匹配所有代码块 const newContent = content.replace(/```[\s\S]*?```/g, (match) => { // 替换代码块中的反转义字符 return match.replace(/\\\[/g, '[') .replace(/\\\]/g, ']') .replace(/\\\*/g, '*') .replace(/\\_/g, '_') .replace(/\\\\/g, '\\') }); // 覆盖原文件 fs.writeFileSync(filePath, newContent, 'utf8'); } // 主函数 function main() { const markdownFiles = findMarkdownFiles(DIRECTORY_PATH); for (const filePath of markdownFiles) { processMarkdownFile(filePath); } console.log('所有.md文件中的代码块已处理完毕。'); } // 运行主函数 main(); .notice { --root-color: #444; --root-background: #eff; --title-color: #fff; --title-background: #7bd; --warning-title: #c33; --warning-content: #fee; --info-title: #fb7; --info-content: #fec; --note-title: #6be; --note-content: #e7f2fa; --tip-title: #5a5; --tip-content: #efe } html.dark .notice { --root-color: #ddd; --root-background: #eff; --title-color: #fff; --title-background: #7bd; --warning-title: #800; --warning-content: #400; --info-title: #a50; --info-content: #420; --note-title: #069; --note-content: #023; --tip-title: #363; --tip-content: #121 } .notice { padding: 18px; line-height: 24px; margin-bottom: 24px; border-radius: 4px; color: var(--root-color); background: var(--root-background) } .notice p:last-child { margin-bottom: 0 } .notice-title { margin: -18px -18px 12px; padding: 4px 18px; border-radius: 4px 4px 0 0; font-weight: 700; color: var(--title-color); background: var(--title-background) } .notice.warning .notice-title { background: var(--warning-title) } .notice.warning { background: var(--warning-content) } .notice.info .notice-title { background: var(--info-title) } .notice.info { background: var(--info-content) } .notice.note .notice-title { background: var(--note-title) } .notice.note { background: var(--note-content) } .notice.tip .notice-title { background: var(--tip-title) } .notice.tip { background: var(--tip-content) } .icon-notice { display: inline-flex; align-self: center; margin-right: 8px } .icon-notice img, .icon-notice svg { height: 1em; width: 1em; fill: currentColor } .icon-notice img, .icon-notice.baseline svg { top: .125em; position: relative } 警告 请修改 DIRECTORY_PATH 的值,并注意转义。 这个脚本会覆盖原文件,请提前备份。而且,由于其做了批量替换,可能会影响代码正常运行。需要手工检查。 移除不必要的 TOC(文章目录) 很多 Hugo 主题使用 toc 这个 Front Matter 来标记是否展开文章目录。对于老文章, 我写了一个脚本,可以根据这个文章是否有实际的二级标题来判断是否启用 toc。 也就是说,如果一个文章的 Markdown 里没有两个以上的二级标题,它会把: +++ title = '本站从 Wordpress 迁移到 Hugo' date = 2024-04-01T16:38:34+08:00 draft = false +++ 修改为 +++ title = '本站从 Wordpress 迁移到 Hugo' date = 2024-04-01T16:38:34+08:00 draft = false toc = false +++ 这样渲染出的文件就不会有目录了,并且不需要前端使用 Javascript 动态实现。 自动翻译简体中文到繁体中文(或相反) 因为这次升级的一个目的是更好地支持简繁两种汉字的使用者,因此我使用了一个脚本, 它可以将所有 Markdown 自动进行简繁转换。 Hugo 支持两种多语言模式,我使用的是文件模式,也就是简体、繁体的文章放在一起, 繁体文章增加 .zh-hant 后缀名。 简繁转换不能简单的字字对应,因为存在很多「一对多」的问题和各地习惯用语的问题。 Opencc 是一个不错的开源工具,可以帮我们实现以词汇为单位的简繁转换,提高转换的准确率。 根据统计,本站大部分繁体用户来自台湾,因此我在简体转换繁体时,使用了台湾的惯用词。 下面的脚本使用 opencc 的 NodeJS 版本进行简繁转换。 这个脚本会把转换后的结果放在 DIRECTORY_OUTPATH 目录下,文件名增加 .zh-hant 后缀。 它只转换文章的标题和正文,不会转换文章的元数据,例如 tag 和 url,因此比较安全。 使用前,你需要根据自己的情况对脚本进行适当的修改,并且需要安装 opencc: npm i opencc 你需要提前修改脚本中的 DIRECTORY_PATH 和 DIRECTORY_OUTPATH。 如果你使用 posts/xxx/index.md、posts/xxx/index.zh-hant.md 这种形式, 你可以将两个目录设置相同。 脚本内容如下: const fs = require("fs"); const path = require("path"); const OpenCC = require("opencc"); const converter = new OpenCC("s2twp.json"); const matter = require('gray-matter'); // 指定目录路径 const DIRECTORY_PATH = "path/to/blog/content"; const DIRECTORY_OUTPATH = "path/to/blog/content-hant"; // 递归地查找.md文件 function findMarkdownFiles(dirPath) { let filesToProcess = []; const files = fs.readdirSync(dirPath); for (const file of files) { const filePath = path.join(dirPath, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { filesToProcess = filesToProcess.concat(findMarkdownFiles(filePath)); } else if (path.extname(filePath) === ".md") { filesToProcess.push(filePath); } } return filesToProcess; } // 处理.md文件中的代码块 async function processMarkdownFile(filePath) { if (filePath.indexOf("zh-tw") >= 0) { return; } // 解析Markdown文件的front matter const content = matter(fs.readFileSync(filePath, "utf8")); // 翻译正文 content.content = await converter.convertPromise(content.content) // 翻译标题 if (content.data.title && content.data.title.length > 0) { content.data.title = await converter.convertPromise(content.data.title) } // 构造输出文件路径 const outFilePath = path.join(DIRECTORY_OUTPATH, path.basename(filePath, ".md") + ".zh-hant.md"); console.log(outFilePath) console.log(content.content) // 如果文件存在则不覆盖 if (fs.existsSync(outFilePath)) { return; } const newMarkdownContent = matter.stringify(content); fs.writeFileSync(outFilePath, newMarkdownContent) } // 主函数 function main() { const markdownFiles = findMarkdownFiles(DIRECTORY_PATH); for (const filePath of markdownFiles) { processMarkdownFile(filePath); } console.log("所有.md文件已处理完毕。"); } // 运行主函数 main(); 警告 不要使用 zh-tw、zh-hk、zh-cn 等作为语言标识。因为他们代表的是地区。作为一个小站点,你估计不太可能会为香港、台湾、新加坡各做一个不同的站点。 使用 zh-hant 代表传统汉字,zh-hans 代表简体中文是明显更加通用的选择。这也方便浏览器、搜索引擎判断你的目标用户。比如,你使用了 zh-hant,香港访问者不会被排除在外。 你可以访问 opencc 的 gihhub 页面,查找不同的配置文件。不同的配置文件会使用不同的惯用词,请根据你实际的需求进行修改。我使用的是 s2tw.json 文件,代表使用台湾惯用词进行简体到繁体的转换。 你也可以通过修改 s2twp.json 配置文件的名字实现繁体->简体的转换。 手工检查所有文章 虽然做了自动化处理,但很多文章依然有问题,需要手工检查一遍。 选择合适的评论系统 我选择的是 Waline,但你可以选择任何你喜欢的评论系统。唯一的建议是, 评论数据需要掌握在自己手里,因此必须选择可以备份评论数据的评论系统。 否则,一旦你的托管方式发生变化,你可能会追悔莫及。 Waline 支持多种数据源,我选择的是 sqlite,因为我有 自己的服务器,并且我希望一个节约内存的轻量化解决方案。 从 Wordpress 评论迁移到 Waline 目前网络上似乎还没有从 Wordpress 评论迁移到 Waline 的现成方案。 本文提供了一种方案,可以将 Wordpress 所有评论无损地迁移到 Waline。 首先从 Wordpress 后台,导出所有内容的 xml 文件。 然后执行我写的脚本(你需要有 NodeJS),对 xml 文件进行分析,生成可以导入 到 Waline 的导入格式(注意修改 WORDPRESS_XML_FILE 变量)。 这个脚本耗费了我不少心血,你可以选择花不到一块钱来给你节约时间: 此部分内容不支持在 RSS 阅读器中显示,请打开本文链接查看:https://ceeji.net/blog/migrate-from-wordpress-to-hugo/ 最后,在 Waline 的管理后台,选择导入导出功能: 先选择导出,打开导出后的 JSON 文件,格式类似如下: { "__version": "1.31.13", "type": "waline", "version": 1, "time": 1711963109933, "tables": [ "Comment", "Counter", "Users" ], "data": { "Comment": [] // 替换此处的数据 } } 把 Comment 处的内容替换为脚本生成的内容,即可进行导入。注意,导入会丢失所有现有数据, 如原来有数据的,需要手工合并或提前备份。 实现代码高亮的黑暗模式自适应 Hugo 自带的代码高亮功能,一般只能设置一个样式。如果你的主题支持自适应黑暗模式,可能会导致 在切换黑暗模式开关的时候,代码高亮不能跟着切换。 最新版本的 Hugo 使用 chroma 进行语法高亮。 首先,确定你想要使用的样式。比如我们在亮色模式下使用 monokailight 样式,在暗色模式下使用 onedark 样式。 接下来,创建对应的 .css 文件供 Hugo 使用: hugo gen chromastyles --style=monokailight > syntax_light.css hugo gen chromastyles --style=onedark > syntax_dark.css 将这两个文件移动到你的主题 assets 文件夹中(例如 ./themes/paper/assets/)。 接下来,确保我们的 Hugo 主题加载这些样式。 为此,编辑 ./themes/paper/layout/partials/head.html(或者负责在你的主题中添加头部部分的文件),添加以下内容: {{ $syntax_dark_css := resources.Get "syntax_dark.css" | minify }} {{ $syntax_light_css := resources.Get "syntax_light.css" | minify }} <link rel="preload stylesheet" as="style" href="{{ $syntax_dark_css.Permalink }}" /> <link rel="preload stylesheet" as="style" href="{{ $syntax_light_css.Permalink }}" /> 这将在使用 Hugo 构建站点时使 .css 文件可用,并允许页面加载它们。 顺序很重要:默认情况下,应用最后引用的文件中的样式,因为它会覆盖之前的样式! 为了让 Hugo 使用我们的 .css 文件作为 chroma 样式,我们需要在 Hugo 的 hugo.toml 文件中明确指定以下内容: [markup.highlight] noClasses = false 确保一切正常后,检查你的代码是否已使用设置的样式进行高亮显示。当你切换到暗色模式时,目前应该还不会有任何变化。 然后你需要写动态切换应用于代码片段的 .css 文件的脚本。 在 ./themes/papers/partials/header.html(或者负责在你的 Hugo 主题中切换模式的文件)中,找到切换模式的代码。 每个主题都不一样,你需要自己去找。 例如它可能类似这样: const setDark = (isDark) => { metaTheme.setAttribute('content', isDark ? '#000' : lightBg); htmlClass[isDark ? 'add' : 'remove']('dark'); localStorage.setItem('dark', isDark); }; 我们在这个函数调用中添加一个方法: const setDark = (isDark) => { metaTheme.setAttribute('content', isDark ? '#000' : lightBg); htmlClass[isDark ? 'add' : 'remove']('dark'); localStorage.setItem('dark', isDark); setSyntaxDark(isDark); // 添加的方法 }; 定义 setSyntaxDark 函数和一个额外的辅助函数: function getStyleSheet(file_name) { for (var i = 0; i < document.styleSheets.length; i++) { var sheet = document.styleSheets[i]; if (sheet.href.includes(file_name)) { return sheet; } } } function setSyntaxDark(isDark) { let sheet_light = getStyleSheet("syntax_light") let sheet_dark = getStyleSheet("syntax_dark") sheet_light.disabled = isDark ? true : false sheet_dark.disabled = isDark ? false : true } 随后,使用 Hugo 重新构建你的网站,确保一切正常。 简繁中文使用相同的评论数据,并自动翻译 简繁语言本就没什么大差距,不需要分开不同的评论。在 Waline 中, 你可以通过移除 url 中的语言部分使得不同语言版本共享同一个评论。 修改你的 waline 初始化代码: init({ el: "#xxx", serverURL: "xxx", locale: locale['{{ .Page.Lang }}'], // 注意这一行 dark: 'html.dark', // 可实现黑暗模式自适应 // path 中使用正则移除简繁部分的网址 path: window.location.pathname.replace(/zh-(hans|hant)\//, '') }); 同时我们需要定义一个 locale 变量实现 waline 的本地化,例如: const locale = { "zh-hans": { nick: '昵称', nickError: '昵称不能少于3个字符', mail: '邮箱', mailError: '请填写正确的邮件地址', link: '网址', optional: '可选', placeholder: '欢迎评论', sofa: '来发评论吧~', submit: '提交', like: '喜欢', cancelLike: '取消喜欢', reply: '回复', cancelReply: '取消回复', comment: '评论', refresh: '刷新', more: '加载更多...', preview: '预览', emoji: '表情', uploadImage: '上传图片', seconds: '秒前', minutes: '分钟前', hours: '小时前', days: '天前', now: '刚刚', uploading: '正在上传', login: '登录', logout: '退出', admin: '博主', sticky: '置顶', word: '字', wordHint: '评论字数应在 $0 到 $1 字之间!\n当前字数:$2', anonymous: '匿名', level0: '潜水', level1: '冒泡', level2: '吐槽', level3: '活跃', level4: '话痨', level5: '传说', gif: '表情包', gifSearchPlaceholder: '搜索表情包', profile: '个人资料', approved: '通过', waiting: '待审核', spam: '垃圾', unsticky: '取消置顶', oldest: '按倒序', latest: '按正序', hottest: '按热度', reactionTitle: '你认为这篇文章怎么样?' }, "zh-hant": { nick: '暱稱', nickError: '暱稱不能少於3個字元', mail: '郵箱', mailError: '請填寫正確的郵件地址', link: '網址', optional: '可選', placeholder: '歡迎評論', sofa: '來發評論吧~', submit: '提交', like: '喜歡', cancelLike: '取消喜歡', reply: '回覆', cancelReply: '取消回覆', comment: '評論', refresh: '重新整理', more: '載入更多...', preview: '預覽', emoji: '表情', uploadImage: '上傳圖片', seconds: '秒前', minutes: '分鐘前', hours: '小時前', days: '天前', now: '剛剛', uploading: '正在上傳', login: '登入', logout: '退出', admin: '博主', sticky: '置頂', word: '字', wordHint: '評論字數應在 $0 到 $1 字之間!\n當前字數:$2', anonymous: '匿名', level0: '潛水', level1: '冒泡', level2: '吐槽', level3: '活躍', level4: '話癆', level5: '傳說', gif: '表情包', gifSearchPlaceholder: '搜尋表情包', profile: '個人資料', approved: '透過', waiting: '待稽核', spam: '垃圾', unsticky: '取消置頂', oldest: '按倒序', latest: '按正序', hottest: '按熱度', reactionTitle: '你認為這篇文章怎麼樣?' } } 重定向 Feed(Rss/Atom)订阅地址 我的网站虽然是个小站,但依然有些人在订阅。为了避免他们走丢, 我需要能够保持原有的 Feed 订阅地址。如果你使用的 OSS 或其他 无服务器(Serverless)的方式进行托管,你可能需要在你的 CDN 页面使用 rewrite 来实现。 因为我是有服务器的,我使用 nginx 来实现了这一点。 Hugo 默认将 RSS/Atom 发布在根目录下的 index.xml 或类似的文件中。 找到这个文件的地址,然后你可以进行重定向: location ~ ^/blog/feed/?$ { rewrite ^ /index.xml last; } 上面的这段 nginx 配置可以把 /blog/feed 和 /blog/feed/ 指向 index.xml, 同时保持对外访问地址不变。 提示 一个小技巧:在你的 nginx 访问日志中搜索 feed,你可能可以看到有多少人订阅了你的网站。 除了解决 Feed 网址问题外,如果你和我一样通过 nginx 部署,建议你还要做两件事: 迁移早期定期访问 access log,查看是否有旧网址出现了 404 错误,这不利于 SEO; 在 nginx 配置文件里,设置正确的 404 页面。 图片管理 强力建议你采用下列的文件结构来存放图片: posts / article / index.md 1.jpg 这种方式管理方便,而且在 Markdown 编辑器中不会出现图片看不到的问题。 然后,你可以通过 render-image hook 实现图片的 CDN 化,提升全球访问速度。 具体可进行相关搜索。

2024/4/1
articleCard.readMore

智绘童话

亲爱的大朋友们和小朋友们, 《智绘童话》是一款微信小程序,它巧妙地将AI技术融入到儿童教育和家庭亲子活动中,通过先进的AI算法,根据孩子的兴趣和喜好推荐个性化故事内容,配以动人的声音和精美的图像,为孩子们创造出独一无二的故事体验。每一个环节都力求完美,真正实现了「故事自由」的理念。 我们知道,家长们在选择教育内容时,总希望能够提供既富有想象力又具有教育意义的素材。《智绘童话》正是基于这一需求而生。它不仅能够根据不同年龄段的孩子身心特点定制故事,还能通过精准的AI标签,让您用最简单的词汇就能找到所需的资源。更加令人兴奋的是,这些故事都是中英双语的,不仅能够丰富孩子的语言环境,还能在轻松愉快的氛围中提高英语听力水平。而AI语音技术的加持,更是让故事的讲述变得生动有趣,吸引孩子们的注意力,同时也让忙碌的家长们能够在繁重的育儿任务中稍作喘息。 《智绘童话》不仅仅是一款产品,它是一个家庭亲子互动的新平台,是AI技术与日常生活完美结合的实例。在这里,每一个家庭都能找到共同的乐趣。 目前,《智绘童话》正处于公测阶段,我们诚邀您与孩子一起探索这个充满想象力的童话世界。目前我们只上线了基础功能,在未来,我们将不断更新迭代,引入更多智能化功能,以期为您和孩子带来更加丰富、便捷的亲子互动体验。AI时代,让我们一起走进这个智慧的童话世界,探索知识的海洋,共绘美好的记忆。《智绘童话》期待与您和孩子一同成长,一起创造无限可能! 这是网页版,其中点击故事可以跳转到小程序: 智绘童话首页

2024/3/25
articleCard.readMore

假如杭州保留了南宋古建筑…

今天我使用人工智能绘图还原了南宋古建筑和现代城市交相辉映下的杭州,一起来看: 杭州夜景 西湖边的灯笼 武林广场与轻轨 杭州城站 西湖与飞鸟 高铁穿过群山 在街巷游玩的孩子

2024/1/28
articleCard.readMore

使用ChineseGenie学习中文

革命性地学习中文,由先进的AI技术、自然语言处理和语音识别能力驱动!随时随地与您的AI中文口语伙伴Viva聊天,谈论您最喜欢的书籍、法式餐厅等等。Viva具有与母语人士相同的地道普通话发音,但无需像真正的中文老师一样预约时间。始终在线且可用,无需担心按小时收费。 被一句你无法阅读或理解的句子难倒了吗?Viva将立即将其准确翻译成您的母语。自信地说话,因为Viva在那里纠正语法错误;需要写一篇中文报告吗?Viva将帮助您润色句子,不仅修复语法问题,还解决任何不当的用词。 Viva,您的中文精灵,是您学习语言过程中忠实的AI助手。通过ChineseGenie应用程序,发现一种全新、有趣且有效的方法来掌握中文! 访问 ChineseGenie 官网:https://chinese-language-learning-chinesegenie.baiyan.tech/

2023/6/16
articleCard.readMore

无法在阿里云控制台被使用的 CSI 插件特性:动态 NAS 存储池

在 Kubernetes 环境中,阿里云早已开发并支持基于 CSI 存储插件的动态 NAS PV 创建,其基于阿里开发的 CSI Plugin。但是,你会发现,在阿里云的控制台中,如果你创建 PVC,你会发现只有云盘才支持基于 StorageClass 自动生成 PV。其实你是可以通过命令行的方式来开启该功能的。 网上有些阿里官方的文档比较老,一些步骤里引用的链接不正确。目前创建的阿里 Kubernetes 集群都已经开启了 CSI Plugin 并且包含 NAS 支持,你并不需要手工安装。 首先要求用户使用NAS控制台 或 SDK/API 创建好NAS文件系统和挂载点。 然后,唯一需要的是创建一个 StorageClass, 详细参数说明见:https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/master/docs/nas-dynamic.md

2020/12/16
articleCard.readMore

HTML disabled 属性的一个坑

一天我在一个页面里写下如下的代码: <div disabled></div> 并在 CSS 中设置:#xx:disabled { background-color: red; }。 可是,此 CSS 并没有生效。 后来考虑到,disabled 这个属性是不是对 div 无效?经过查询,果然 disabled 属性是针对表单的,于是果断把 div 改为 button,发现依然无效。 果断在 W3School 查找,发现 disabled 属性只对 input 元素有效。

2016/11/26
articleCard.readMore

C# 与 Java 语言机制与语法的异同

本文是 从 C# 到 Java 系列的文章。此系列文章是为了方便从 C# 转到 Java 平台的工程师快速学习新的语言和平台。整个系列的目录请点击此处浏览。 这篇文章从基础的语言机制、语法层面来分析 C# 和 Java 的不同。部分与虚拟机(CLR | JVM)有关的不同会放在相关的另一篇里,详见总目录。 命名规范 Java 中的方法和变量,无论是否为public,都要以小写字母开头,其余与 C# 大体相当。 那些简单的同义词或近义词 下面的词汇,在 Java 和 C# 中是 同义 或 近义 的: C# 中获取一个对象的类型使用 typeof 关键词,Java 中使用 .class,如 String.class;C# 也可以使用对象实例的 GetType 方法,Java 中对应的是 getClass 方法。参考链接; 代表一个对象的类型的类型,C# 为 Type 类型,Java 则为 Class 类型。参考链接。 C# 中的 const (编译时常量)和 readonly(运行时常量)在 Java 中都是 final,同时还代表了一个类不能被继承(等同于 C# 的 sealed)。 Java 中的 native 关键字(声明使用 native 实现的代码)类似于 C# 中的 extern(当声明非托管的外部方法,如动态链接库时使用)。 string 与 String:在 Java 只有后者,在 C# 中前后两者是同义词。 Java 中的 synchronized 等同于 C# 语句块中的 lock,以及 方法体上的特性MethodImplOptions.Synchronized。 Java 中的 transient (短暂)等同于 C# 的 NonSerializableAttribute,代表在序列化中跳过。 Java 的 ... 操作符等同于 C# 的 params。例如:String... args,则 args 为一个所有参数组成的数组。 值类型与装箱 Java 的值类型(Value Types)仅限于原生类型,如 int、boolen 等。Java 不允许自定义值类型,即 Java 不存在 C# 中的 struct。 值类型 的作用可以从以下几个方面来考虑: 性能:C# 中的 struct 类型有助于减少 GC、减少内存使用、提高性能,但 Java 强大的虚拟机 JVM 通过优化部分缓解了这个问题。 语义:原生类型无法为 null,且通过传值方式赋值。 但是,由于 C# 中的值类型通过传值类型赋值造成了意外错误的可能(例如用类似类的方式在杯传递后的值类型中修改成员,试图影响到原有的值),使用值类型要警惕。 值类型在 Java 中不继承于 Object,但 C# 中却继承,这是通过自动装箱实现的。Java 的值类型可以通过装箱变为类实例,比如: int => Integer float => Float byte => Byte Java 具体的数据类型方面的内容,可以参考本系列文章中的另一篇:数据结构(文章末尾有目录导航)。 泛型 Java 支持泛型,但其支持的方式和 .NET 差别比较大。Java 的泛型使用 类型擦除 实现。所以,你虽然可以设置某个方法或类有一个类型参数 T,但是你在其实现内部却无法获知与该类型的任何信息,解决方法就是使用一个补偿的 class 类型(类似于 C# 中的 Type 类型)参数手工传递数据类型。 有关 Java 泛型的类型擦除,请参考链接 委托,事件 C# 中的委托(delegate)用于指向固定某个方法原型(一系列参数、某种返回值)的指针(姑且这么叫吧)。Java 中没有 delegate 的概念。 Java 中一般通过接口来实现类似委托的效果。 例如,C# 中假如有下面的定义: // 定义委托 public delegate void onClickListener(View v); // 定义委托的实现 public void listener(View v) { // foo } // 使用委托 onClickListener = listener; onClickListener(this); 在 Java 中可以这样实现。先定义一个接口: public interface OnClickListener { void onClick(View v); } 然后,使用这个接口来存储一个匿名类,其中带有具体的实现,例如: OnClickListener listener = new OnClickListener() { @Override void onClick(View v) { // 在此书写代码 } }; // 调用接口 listener.onClick(someView); 除了使用匿名类,也可以让某个命名类继承此接口: public class TestClass implements OnClickListener { void OnClick(View v) { // 在此书写代码 } void init() { OnClickListener listener = this; // 调用接口 listener.onClick(someView); } } C# 支持事件(event),其内部是通过委托来实现的。Java 中没有事件的概念。 一般来说,用于事件或委托的情况,Java 会使用接口来实现。 例如,C# 中的事件: public event EventHandler SomeEvent; // 事件的发出者 // 事件监听 someInstance.SomeEvent += (sender, args) => { /* xxx */ }; 大约等价于 Java 中的方法: // 先定义接口 public interface SomeEventListener { void onEvent(int arg); } // 搞一个东西用来存储接口的具体实现对象 private ArrayList<SomeEventListener> someEventListeners = new ArrayList<>(); // 在要产生事件的类中,添加一对方法用于监听或取消监听 public void addSomeEventListener(SomeEventListener listener) { someEventListeners.add(listener); } public void removeSomeEventListener(SomeEventListener listener) { someEventListeners.remove(listener); } // 触发事件 for (int i = 0; i < someEventListeners,size(); ++i) { someEventListeners.get(i).onEvent(5); } // 事件监听者,使用 Java8 中才支持的 Lambd 表达式 someInstance.addSomeEventListener(() -> { /* xxx */ }); // 事件监听者,使用 Java7 以前版本的 匿名类 someInstance.addSomeEventListener(new SomeEventListener() { @Override void onEvent(int arg) { // 代码逻辑 } }); 也可以参考这篇文章。 本文是 从 C# 到 Java 系列的文章。此系列文章是为了方便从 C# 转到 Java 平台的工程师快速学习新的语言和平台。整个系列的目录请点击此处浏览。

2016/11/15
articleCard.readMore

为什么要从 C# 转为 Java:浅谈 .NET 与 Java 生态

本文是 从 C# 到 Java 系列的第一篇文章。整个系列的目录请点击此处浏览。 C# 是 .NET 平台上最重要的一门语言,Java 是世界上使用最广的语言之一。这两门语言有着太多的恩怨情仇,也有很多相似之处。C# 在最初创立的时候,或多或少借鉴了 Java 语言的优秀特性,但后期发展又和 Java 走上了不同的道路。 那么,为什么你要从一门语言,转换为另一门很相似的语言呢?本文主要谈谈,为什么在某些情况下,你可能需要,或者愿意从基于 .NET 的 C# 转移到基于 JVM 的 Java 语言平台。 统一开发平台,重用现有资产 某些类型的开发不得不用 Java 开发,或者大多数人都在用 Java 开发。如 Android 开发,Android 的开发技术栈全部构建于 JVM 之上;所以整个团队的开发语言只能迁就于上述原因来选用 Java; 很多团队或公司中,有大量现存的基于 Java 的资产(代码、模块、应用),统一开发语言和平台可以降低团队磨合、学习成本,重用现有代码资产。而统一语言时显然无法选择 C#,因为 Java 适用面更广(即很少有 Java 可做而 C# 无法做的领域或平台)。 减少技术风险,方便技术学习 Java 的历史更长,开发人员更多,社区也更大,如果在开发上遇到问题,有很多成熟的解决方案可以参考(俗称的Google之); 开发特定领域的程序时,Java 可借鉴的代码和框架更多,避免遇到技术死角;大多数领域的开发已经在 Java 中有成功的案例,避免技术上潜在的风险。 某些第三方产品或接口,官方优先支持 Java 或只支持 Java,使用其他平台需要额外开发或进行封装,导致开发效率和性能的问题。 减少开支 靠谱的 Java 程序员更好招聘,可以减少用于招聘的人力资源成本;原因有二。一是 C# 确实比 Java 对开发者更贴心,所以导致了学习成本更低,造成了 C# 小白丧失了继续学习的进取心,客观上降低了 C# 开发者的平均水平;二是从绝对数量上来说,C# 开发者也少于 Java 开发者(如下图)。 基于 .NET 平台的开发工具和相关产品普遍需要付费;基于 Java 的开发工具和相关产品免费的更多。 下图为 2016年11月,在全球范围内 C# 与 Java 语言的流行度对比,Java 排名第一,C# 排第四。 C# 与 Java 流行度对比 基于 Java 开发将拥抱更广泛的生态 如上图所示,Java 长期在开发语言排行榜中流行程度排名第一,所以拥有更好的生态,即有成千上万的成熟类库、大量的技术资料、很多的现成代码; Java 更偏向于基于 Linux/Unix 平台的开发,而 .NET 在早期太多地依赖于 Windows,后期 .NET 虽然开源且跨平台,但已为时略晚。在互联网相关行业,Linux 及其生态圈比 Windows 繁荣得多。 Java 早已不是一个开发语言,而是一整个生态圈。 Java 在语法、平台技术上、开发效率上并非最好的,但却是够用的,且有出色的平衡性。虽然 Java 在哪个方面几乎都不是最强的,但却都说得过去。 说实话,我个人更偏爱 .NET 技术,其炫酷、性能优异、免费且跨平台、开发效率高,但是,基于以上原因,有时 Java 是更务实的选择。 如果你准备好了基于 Java,而不是 C# 开启你的下一段代码,就让我们一起来学习吧! 本文是 从 C# 到 Java 系列的第一篇文章。整个系列的目录请点击此处浏览。

2016/11/15
articleCard.readMore

从 C# 到 Java:总目录

引言 为了方便以前使用 C#(.NET),由于某些原因,需要学习 Java (JVM),或开发基于其的应用的人(比如开发 Android 应用),我打算写一篇系列文章,详细地描述中间可能遇到地问题、学习路径等。方便 .NET 开发人员快速转为 Java 开发人员。 具体来说,主要会通过对比和举例来行文。在过程中,不但会讲 Java,也会把 C#(.NET) 的一些内容讲一讲,算是起到两种语言甚至是平台的对比与深入。 下面是总目录,没写好的部分不可点击,有链接的部分才可以阅读。 总目录 为什么要从 C# 转为 Java:浅谈 .NET 与 Java 生态 C# 与 Java 语言机制与语法的异同 .NET 与 Java 数据结构异同 .NET 与 Java 核心类库的主要区别 CLR 与 JVM 对比 从 C# 到 Java:Java 包管理、主要框架与测试 从 C# 到 Java:开发范式与哲学

2016/11/15
articleCard.readMore

近期遇到的几个布局兼容性汇总

(实时更新) flex 可伸缩元素比例不正确(Android 4.0 - 4.3,iOS 低版本) 使用 flex 布局,在现阶段已经是非常靠谱的方案了,因为 flex 布局已经在大多数主流浏览器中兼容。但是,flex 布局还是有不少需要注意的兼容问题。 在 Android 4.0 - 4.3 和部分低版本 iOS 中,可伸缩元素(大小按比例缩放的元素)如果要确保比例正确,必须设置: xxx { width: 0px; } 其中,width,一般设置为 width: 0 或 1px、0.001% 等。 如果不设置,那么一旦 flex 的子元素的实际内容超过了按照伸缩比例应该拥有的宽度,在这些有 bug 的系统中就会出问题,具体表现是**子元素的宽度将根据实际宽度进行延伸,最多可以占据整个屏幕的宽度(即使它的 flex 布局的父元素设置了宽度,它自身仍然可以撑开以达到整个屏幕的宽度)。

2016/11/11
articleCard.readMore

Javascript 中的 undefined 与 未定义(not defined)

在 Javascript 中,有一种致命错误非常常见,即 ReferenceError:xxx is not defined. 但是,有时候当一个值从未被赋值的时候,并不会出错,而是返回 undefined,有必要对这两者进行梳理。 undefined undefined 表达的含义有三种情况: 这个变量存在,但是并没有给予任何值。 一种普通的数据类型和一种值。你可以手工将任何变量赋值为 undefined,此时其没有特别含义。 一个存在的对象中的一个不存在(没有声明)的值,会被认为是 undefined。 对这三种情况进行归纳,undefined 可以如下总结: 它是一种数据类型,也是一种值。 有这种值的时候,要么它本身被赋值,要么本身存在,要么其所在对象存在。完全不存在的变量不会是 undefined(注意,此处还有坑,往后看)。 下面举几个例子。 一个声明但没有赋值的变量为 undefined var p; alert(p); // undefined 一个不存在的对象成员为 undefined var p = { }; alert(p.a); // undefined 如果 p 还有一个成员 b,其值被手工赋值为 undefined,如何区分不存在的成员 a 和存在的成员 b?可以使用 Object.prototype.HasOwnProperty() 方法。 一个手工赋值的 undefined var p = 5; p = undefined; alert(p); // undefined 从上面的三个例子可以清楚看出 undefined 的一些情况。undefined 的优点在于正常使用有此值的变量不会抛出异常。 未定义(not defined) 一个 未定义 (not defined) 的变量是完全没有任何声明的变量。这样的变量在使用时会直接抛出致命错误。但是,如果使用 typeof 来判断这样的变量,不但不会出错,而且竟然会返回 undefined,这使得无法使用 typeof 来区分这两种情况。

2014/9/1
articleCard.readMore

iPhone 手机QQ 4.7.2 版本网络状态泄露用户隐私

iPhone 手机QQ 4.7.2 版本会在用户的在线状态旁边增加一行小字,「2G」,「3G」,「4G」,或「WiFi」。我目前没有找到关闭这项功能的方法。而这项内容其实是严重泄漏了用户的隐私信息的。 对于很多生活就是三点一线甚至两点一线的人来说,其所在区域的网络状态(2G、3G、WiFi)可以轻易让人确定其方位。尤其是,如果再加上电脑在线的状态,这四种状态很可能可以大体推断用户所在位置。 例如对于学生党而言: 2G:可能在旅游或火车上。 3G、4G:可能在课堂或市区。 WiFi:很可能在寝室或图书馆。 腾讯没有给出取消状态显示的方式,对于用户隐私考虑绝对是不周全的。

2014/7/1
articleCard.readMore

宋卿体育馆与六一惨案

在武汉大学文理学部第四教学楼前树立着一个六一亭,纪念着当年六一惨案中的遇难者。一九四七年六月一日黎明,国民党军警几千人武装包围了武汉大学校园。肆意搜捕进步师生陈如丰、王志德、黄鸣岚三人,并当场惨遭枪杀,造成震惊全国的「六一」惨案。 机枪扫射,军警包围,珞珈山竟成屠场,请看遍地鲜血,四项诺言何去? 四海同胞,人神共愤,清华园遥祭英魂,谨献一瓣心血,亿万青年继后来。 (摘自清华学生自治会的挽联) 同年8月,武汉大学进步师生在校内修建「六·一」惨案纪念亭。亭坐北朝南,边高6.5米,六角地尖顶,翠瓦飞檐,有6根朱漆圆柱支柱。在六一亭上写有纪念的碑文。 其不远处的桂园有一个著名的宋卿体育馆。宋卿体育馆用了「民国大总统」黎元洪的字「宋卿」作为名称,是因为其资金来源于黎元洪之子的捐赠。 然而之前我不知道的是,六一惨案的纪念仪式就是在距离其不远的宋卿体育馆举行的。 我也不知道的是,在黎元洪当年筹备十万大洋捐建武汉大学体育馆的时候,其是为了满足自己的一个心愿:能够让自己死后葬在风景如画的珞珈山南麓。黎元洪希望自己的捐赠能让武大置换给自己一块陵墓的位置。为了得葬于此地,黎元洪曾表示愿意向武大捐献一笔资金,不过被当时的武汉大学拒绝了,老武大前辈们当年的风骨可见一斑。 黎元洪早年曾想在武昌创办江汉大学,并筹款银洋10万元购买了当时的中兴煤矿股票1000股,以备日后作办学基金。黎元洪病逝后其子将股票折换成10万现大洋,并在1934年去信给武大称: 系于先君遗志,不敢辄忘,……拟将此项基金转移贵校,用以培植人才,藉了先君心愿。 武大派人到天津过户并同黎子约定这笔资金用来建设宋卿体育馆。

2014/4/19
articleCard.readMore

Nginx 无法处理软链接作为网站主目录的情况

近日我将本站点的服务器从北京迁移到了广州。在迁移的过程中,我发现 Nginx 无法处理软链接作为网站主目录的情况。 例如,我在 Dropbox 备份了服务器的网站主目录,位置在 /root/Dropbox/var/www. 我使用这条命令为其创建一个软链接: ln -s /root/Dropbox/var/www /var/www 修改目录和软链接的所有者以便 nginx 可以读取和执行: chown -h www-data:www-data /var/www chown -R www-data:www-data /root/Dropbox/var/www 然后,修改 nginx 配置文件中 sites-enabled 的网站,把其配置中的主目录设定为 /var/www; 随后运行,发现 nginx 报告 500 错误,查看 nginx 日志 /var/log/nginx/error.log,发现其中有这样的话: 13: Permision Denied 经过仔细检查,我认定无论如何设置权限, nginx 都无法处理软链作为主目录的情况。

2014/4/16
articleCard.readMore

甲午年,至关重要的使命

接下来的一年于我而言的重要,直接可以用人生选择来形容。我已经将创业作为了自己的发展方向和主业。接下来的半年,算是正式创业的开端。从此,作为一个职业创业者,今年的使命可以说「亚历山大」。 更核心的时期,应该是前半年,也就是我毕业之前的时间节点。在这段时间,我的业绩能做到如何,企业能否起步,将是相当重要的一个转折点。 加油。

2014/1/31
articleCard.readMore