这算「自己写自己」吗 是的,这篇文章内容也是hermes外包的 事情是这样的——我一直在折腾自己的 Hugo 博客,写完总是要手动开编辑器、起本地服、hugo new、整理 TOML 前置信息……琐碎得让人想偷懒。 于是干脆把「发博客」这件事整个丢给了我的 agent„Hermes„。 让它帮我起草、把关、提交、推送。 这篇就是你刚读到的结果。 它到底做了什么 流程其实很朴素,没有魔法: 我会话里给出主题:「随便写一篇,主题是我让 Hermes 写了一篇博客」。 它按我 repo 里现有帖子的格式写了一篇(日期、标题、slug、draft=false、TOML 前置信息和中文正文)。 它先起草给我看,我没改动就当确认。 提交、推送,走我已经配好的 GitHub PAT 认证,直推到远程。 远程的 CI 被触发,自动构建部署——新帖就这么上线了。 ##「懒惰」的正当理由 看起来像偷懒,但我更愿意叫它**「把重复劳动外包给会干活的东西」**。写作还是要我来定主题、要认可内容、要对产出负责;机器只负责把「从草稿到上线」这段机械流程跑直。省下的时间,多打几把音游不好吗。 Hermes 端到端跑通了我的博客发布流水线——顺便,这篇就是它的 ep、0.也许我该给它记一功。
一加手机坑爹的清灰功能
坑爹的清灰功能 诚然各手机厂商为了吸引消费者推出的创新功能形形色色,或使人眼前一亮。 不过一加这部手机的“清灰模式”属实有点雷人。 如图,这种清灰的原理是通过播放特定频率的音波,把灰尘抖下来。 但是编程人员没有指定播放设备,因此如果你连接了耳机,那么响的会是耳机而不是扬声器。属于清灰了个寂寞。。。
怎么挑选背景
搞这么多技术内容,本质上的目的还是让我们的博客好看。对此,图片的选择往往是最容易被忽略的部分。 我个人为博客筛选了约数百张图片,对于背景图片的选取略有心得。 1. 明确你需要什么主题的图片 简洁风?风景?动漫? 主题决定了你应该去哪里寻找背景图片。 如果你想要风景图的话,必应每日的风景图(“必应聚焦”)是一个很好的来源。 这里有一个整理每天的必应聚焦的网站。 我个人则选择动漫图片。动漫图片有两个来源: 插画网站,比如Pixiv 社交媒体和群组的推送流 在这里,我们明确了第一个标准——图片符合我们的主题,且符合个人审美。 2. 注意博客页面对你的背景的遮挡作用 很多人光是找好看的插画去了,而博客内容对背景的遮挡作用常常被忽略。 比如,在桌面端,PaperMod的内容框框占据网页的中间$\frac{2}{5}$,那么为了美观,图片的主要内容必须在图片的左右边缘各$\frac{3}{10}$处。 这里的主要内容,当然是一个插画的主题元素,比如人物。如果一个插画主要是人物,那就指的是表现人物神情的部分(这里是面部)。 中间部分被遮挡的图片 反面示例——人物几乎被遮住 3. 不要喧宾夺主 背景图片不要太花导致干扰视线,更不要使得文字内容看不清。 其实这一点有一些主观的成分,只要不要饱和度爆炸明暗对比拉满都差不多。
给hugo+PaperMod博客添加背景图片,包含多端适配、随机背景功能
作为一个静态博客框架,Hugo 的优势在于可以直接白嫖各厂商的静态页面托管服务(如 Cloudflare Pages、GitHub Pages)。而 PaperMod 主题的简约设计则提供了极高的可定制性。 生命在于折腾,选择这两者作为技术栈后,折腾博客的下一站自然就是设置一个好看的背景图片。 给首页加图片 如果只需要给首页加图片,那么只需要加一个 .list 的 CSS 选择器。在 PaperMod 的 DOM 结构中,首页容器带着 .list 类名。我们可以在 assets/css/extended/custom.css 中注入基础样式: .list { background-image: url("/images/background-light.webp") !important; background-size: cover; background-position: center; background-attachment: fixed; background-repeat: no-repeat; } 直接加上背景后会遇到一个很刺眼的问题:首页的文章列表文字是直接覆盖在背景上的。我们需要把第一个帖子加上框框,不然文字会融入背景,导致可读性极差。 PaperMod 默认的首帖(.first-entry)没有预设内边距和边框。我们可以补全它的盒模型,并给框框加上透明效果与毛玻璃质感(Glassmorphism): /* 补全首帖盒模型 */ .first-entry { border-radius: var(--radius); padding: var(--gap); } /* 给卡片框框加上半透明与毛玻璃效果 */ .first-entry, .post-entry { /* 使用 color-mix 复用主题原生变量并混入透明度 */ background: color-mix(in srgb, var(--entry) 80%, transparent) !important; border: 1px solid color-mix(in srgb, var(--border) 60%, transparent) !important; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); } 适应暗色模式 现代 PaperMod 主题切换暗色模式时,会在顶层的 <html> 标签上注入 data-theme="dark" 属性,而不是修改类名。因此我们需要使用 HTML 属性选择器来进行样式覆盖: ...
甜筒是我的罪过啊
今天吃完饭,去“苦沙火乡”买了一支甜筒。边骑车边吃,哪曾想一下路肩甜筒就被颠断了…… 哎,太可悲了太可恨了。 怨我,这就是我的罪孽啊。
异常
异常简介 异常是为了在出错的时候,提供一个机制把控制权交给能够处理这个错误的代码手上。如果没有异常,异常产生处和处理处的代码可能很远。 异常的层次结构: 基类:Throwable 直接继承Throwable:Error和Exception Error被设计成虚拟机内部错误,程序员不应该抛出 Exception是我们平常关注的范围。 IOException和RuntimeException是Exception下的两个常见的直接子类。Exception还有更多直接子类。 所有派生于Error类或RuntimeException类的异常都是非检查型unchecked异常。 所有其他异常都是检查型checked异常。 语义上,RuntimeException指的是编程错误导致的异常,如 ArrayIndexOutOfBoundsException NullPointerException ClassCastException 创建异常类 我们需要继承一个Exception的子类。同时惯例我们应该实现两个构造器:一个无参和一个带详细信息字符串的构造器。 异常的捕获和传播 要捕获异常,需要建立一个try-catch块。 如果在try块中遇到catch指定的异常,那么直接跳到对应catch语句块。 预估遇到catch未指定的异常,那么方法直接退出。 如果try块正常运行,那么不运行catch块,继续运行方法的后续代码。 如何判断处理还是传递异常? 在工程实践中,推荐遵循**尽早抛出,延迟捕获(Throw early, catch late)**的原则: 在代码最底层的逻辑验证阶段,一旦检测到异常状态立即抛出;在整个调用链路中,除非能够真正处理问题或必须转译异常,否则应一路放行,交由拥有全局业务视野的顶层框架或统一异常处理器(如 Spring 的 @ExceptionHandler)进行集中处理。 finnally和try-with-resources finally子句:无论是否排除是否被捕获的异常,都会在最后执行。 可以只有finally没有catch 不要在finally中使用throw, return, break, continue等改变控制流的语句。 一个良好的实践是使用两个独立的try,try-finally用于关闭资源,try-catch用于处理异常。 java7以上支持try-with-resources 对于实现了AutoClosable接口: interface AutoClosable { void close() throws Exception } 的类(资源),try-with-resources语法会在try块结束后自动关闭这些资源。 try (Resource res = ...) { do with res..... } // 不管有没有异常,是否被捕获,都会在这里调用res.close() catch (Exception e) { //... } java9之后,可以提供effectively final的变量了: // out 是方法的参数,满足effectively final try (out) { // do sth } // out.close 没什么人在意的细节:在try-with-resources中,如果try块和close都抛出了异常,close抛出的异常会被抑制。它们被用addSuppressed方法加到try抛的异常上,然后重新抛出try抛出的异常。如果你感兴趣,可以使用getSuppressed方法获取这些异常。 ...
Lambda表达式和函数式接口
Lambda表达式和函数式接口 Lambda表达式语法的本质上就是一种表达式,而非对象。 Lambda表达式的返回值会被自动推导。如果参数被省略,那么也会尝试自动推导。 函数式接口(Functional Interface)指的是只有一个抽象方法的接口。(可以有一些非抽象方法,如重写或默认) Lambda表达式是被设计为快速地转换为函数式接口的实例。程序员不用手动初始化函数式接口的实例了,这些对象和类的管理由编译器处理。 方法引用和构造器引用 方法引用(Method Reference)是一种简便方式,可以在只想调用一个方法而不做其他操作时,直接使用某个方法的逻辑。 原理类似于Lambda表达式,编译器自动为你创建函数式接口的实例。 例如: var timer = new Timer(1000, System.out::println) 要注意方法重载的选择受函数式接口的签名影响。 方法引用支持三种语法: object::instanceMethod:lambda表达式的参数列表原样传送到这个对象的这个方法的参数中。 Class::instanceMethod:lambda表达式的第一个参数成为方法的隐式参数,也就是说:String::compareToIgnoreCase, 等价于(a, b) -> a.compareToIgnoreCase(b) Class::staticMethod: 所有参数传递到静态方法。 构造器引用 格式:Class::new 解决的问题:将类型被擦除的数组重新构建为特定对象数组。 例如:Person[] people = stream.toArray(Person::new) 变量作用域和闭包 Lambda表达式由三部分组成: 一个代码块 参数 自由变量的值,这里是指非参数切不在代码块内被定义的变量 当lambda体使用了外部的变量时,称为这个变量被捕获(captured) 捕获capture自由变量的代码块称为闭包closure。lambda表达式就是闭包。 捕获变量的限制(这是为了并发安全考虑): 在lambda体中,不可以改变捕获的变量。 捕获的变量不可能在外部改变 捕获的变量必须是事实最终变量(efectively final)。aka,变量初始化后不会再被赋新值。 lambda表达式的体与它的上一层嵌套块有相同的作用域。也就是说,lambda表达式不新建作用域,参数和内部变量不能和上一层重名。 这也是为什么你可以直接使用外层方法的this Lambda表达式的应用 《Core Java 中文版》6.2.7 为什么要使用Lambda表达式?一个重要原因是支持代码的延迟执行(deferred execution) 换句话说,如果不需要延迟执行,那么很可能不需要lambda表达式。 在一个单独的线程运行代码 在算法的适当位置运行代码(比如排序的比较操作) 发生某种事件时才触发代码 只在必要时才执行代码 常用的函数式接口: Runnable Supplier<T> Comsumer<T> BiConsumer<T, U> Function<T,R> BiFunction<T, U, R> UnaryOperator<T> BynaryOperator<T> Predicate<T> BiPredicator<T, U> 除了Runnable,它们都在java.util.function里面 ...
Hello World
这是我的第一篇博客!