#927 CPU 架构

2023-06-12

OSChina 上发布的资讯《Debian 13 “Trixie” 将提供 RISC-V 64 位支持》中提到:

最新发布的 Debian 12 支持九种架构: AMD64、AArch64、ARMEL、ARMHF、i386、MIPS、64 位 MIPS、POWER 和 IBM System Z。

这应该是现在最流行的 CPU 架构了吧。

  • x86_64
  • AMD64
  • i386
  • ARM
  • AArch64
  • ARMEL:Little Endian
  • ARMHF:Hard Float,使用硬件浮点寄存器和指令来提高计算性能
  • MIPS
  • MIPS
  • MIPS64
  • POWER
  • IBM System Z
  • RISC-V

#926 爸小猪故事

2023-06-11

从前,有三只可爱的小猪,它们是一家的兄弟姐妹。老大哥哥叫皮鲁,老二妹妹叫皮娜,老三弟弟叫皮休。他们住在一个美丽的森林中,一起快乐地生活着。

#925 头上的辫子与心里的辫子

2023-06-11

假发

近日有新闻讨论香港法官至今保留原宗主国戴假发的传统(陋习)。

先说一下我对这个司法假发的一点了解。
16 世纪,欧洲贵族社会性病流行,其中症状之一就是脱发严重。于是,随着时间的流逝,上层社会戴假发的习俗慢慢演化成了地位的象征。
医疗技术发展起来之后,带假发的这种习俗就迅速消亡了,谁会喜欢没事带着这么个劳什子呢,想想都不舒服嘛。

不过,因为英国有立法,规定法律从业人士的着装要求,其中就包括必须戴假发(WTF)。
一种长发及肩,用在刑法庭,一种短些,用在民法庭。

PS:可以搜索一下带假发的法官图片,简直丑的一批,我想应该是没有人会喜欢这玩意儿吧。
PS:美国第三任总统托马斯·杰斐逊:“(英国法官)像躲在棉絮下面向外窥视的老鼠”。

因为英国到处侵略与殖民,将本国的法律推及到很多地方,包括中国香港。
所以,部分地区的司法界保留了这个传统直到近代。

根据维基百科的信息,英国、加拿大、澳大利亚、新西兰已经部分废除了假发在法庭中的使用。但香港司法界至今坚持必须戴假发上庭。
我对司法制度不了解,但是这个假发就是一个配饰,完全无关司法精神吧,为什么必须用法律法规来强制佩戴呢?
这个和清朝遗民舍不得辫子是何其相识!

辫子

说到辫子,不禁想起了《建党大业》中,辜鸿铭的经典台词:“我的辫子长在脑后,笑我的人,辫子长在心头。老夫头上的辫子是有形的,而诸公心中的辫子却是无形的。”
这句话说的其实也挺在理的,因为比人家弱,就什么都要跟人家学习,觉得自己家什么都是糟粕,这何尝不是辫子长在心头呢!
辫子就是不自信,就是觉得自己低人一头,就是外国的月亮比较圆。

假发是外在的辫子,皇民心态是内在的辫子。而我们希望他们能彻底抹除原宗主国的痕迹,有没有一点辫子的意味呢?
我的意思是,从发展的眼光看问题,他们这顶可笑的假发早晚是会消失的,但我们是否过于着急了,这种心态是不是对于过去的屈辱历史过于耿耿于怀了,算不算文化上的不自信呢?

参考资料与拓展阅读

#924 关于自托管邮件服务

2023-06-10

看到科技爱好者周刊推荐的一篇文章,介绍了自托管邮件服务的一些现状,主要是 Gmail 这样的主流邮箱服务提供商(MSP)拒收来自自托管邮件服务的邮件(或标记成垃圾邮件),导致自托管邮件服务的运营遇到很大的困难。

电子邮件在因特网没有出现之前就已经诞生,简单、开放,易于开发和使用,人人都能成为 Email 网络中的一个节点。实际上,大部分人都是使用的一些大 MSP 的服务,但也有部分人(或者组织)使用的是自己部署的邮件服务。他们会发现哪怕所有应该做的都做了,比如 SPF,DKIM,DMARC,他们的邮件还是经常无法正常投递出去(被拒、限流等),或者在收件人的垃圾文件夹中。

在一定程度上,MSP 的做法也是可以理解的,垃圾邮件泛滥成灾,确实防不胜防。因为邮件服务本身是毫无门槛。除非上一个手机实名制这样的严格管控,或许能解决这个问题。

文章提出的主要价值点是,什么情况下我们有必要自建邮箱服务?

  1. 准备好投入很多时间和精力来维护这套系统
  2. 搭建系统
  3. 留意 SPF 和 DMARC 报告
  4. 有服务器管理能力(Linux,Docker)
  5. ISP 支持开放 25、143、465、587、993 端口
  6. 静态 IP + rDNS 配置权限
  7. 一个合适的域名

#923 gotip 命令

2023-05-30

gotip 是官方推出的,从最新的开发分支下拉代码,编译生成 go 运行时的工具。
如果希望体验最新特性,可以在编译成功之后,可以直接用 gotip 取代 go 命令用来执行 go 程序。
gotip 就可以理解为开发版的 go。

go install golang.org/dl/gotip@latest

gotip
gotip: not downloaded. Run 'gotip download' to install to C:\Users\nosch\sdk\gotip

gotip download
Cloning into 'C:\Users\nosch\sdk\gotip'...
...
Building Go cmd/dist using C:\Program Files\Go. (go1.20.5 windows/amd64)
Building Go toolchain1 using C:\Program Files\Go.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for windows/amd64.

成功的时候:
---
Installed Go for windows/amd64 in C:\Users\nosch\sdk\gotip
Installed commands in C:\Users\nosch\sdk\gotip
Success. You may now run 'gotip'!

失败的时候:
# runtime/cgo
gcc_libinit_windows.c: In function '_cgo_beginthread':
gcc_libinit_windows.c:143:27: error: implicit declaration of function '_beginthread'; did you mean '_cgo_beginthread'? [-Werror=implicit-function-declaration]
  143 |                 thandle = _beginthread(func, 0, arg);
      |                           ^~~~~~~~~~~~
      |                           _cgo_beginthread
cc1: all warnings being treated as errors
go tool dist: FAILED: C:\Users\nosch\sdk\gotip\pkg\tool\windows_amd64\go_bootstrap install std: exit status 1
Success. You may now run 'gotip'!

#922 Go set 类型

2023-05-29

Go 并没有支持集合类型,我们需要自己实现:

https://go.dev/play/p/uVDCiN4Cbpt

package main

import "fmt"

type Set map[string]bool

func (s Set) Add(item string) {
    s[item] = true
}

func (s Set) Remove(item string) {
    delete(s, item)
}

func (s Set) Contains(item string) bool {
    _, exists := s[item]
    return exists
}

func main() {
    mySet := make(Set)
    mySet.Add("apple")
    mySet.Add("banana")
    mySet.Add("orange")

    for item := range mySet {
        fmt.Println(item)
    }

    fmt.Println(mySet.Contains("apple")) // 输出: true
    fmt.Println(mySet.Contains("grape")) // 输出: false

    mySet.Remove("banana")
    fmt.Println(mySet.Contains("banana")) // 输出: false
}

注意:

  1. 使用 map 做底层存储,因此实现的 set 也是无序的
  2. map 不是线程安全的,如果有并发操作,需要加锁
  3. 如果真的要使用集合类型,应该再扩充一下交集,差集等方法

改进

参考 https://github.com/deckarep/golang-set 的设计:

https://go.dev/play/p/BKWT84lXfuz

package main

import "fmt"

type Set[T comparable] map[T]struct{}

func (s Set[T]) Add(item T) {
    s[item] = struct{}{}
}

func (s Set[T]) Remove(item T) {
    delete(s, item)
}

func (s Set[T]) Contains(item T) bool {
    _, exists := s[item]
    return exists
}

func main() {
    mySet := make(Set[string])
    mySet.Add("apple")
    mySet.Add("banana")
    mySet.Add("orange")

    for item := range mySet {
        fmt.Println(item)
    }

    fmt.Println(mySet.Contains("apple")) // 输出: true
    fmt.Println(mySet.Contains("grape")) // 输出: false

    mySet.Remove("banana")
    fmt.Println(mySet.Contains("banana")) // 输出: false
}

优化点

  1. 空结构体不占空间
  2. 泛型让代码复用性更好

#919 SSH 转义序列

2023-05-19

Closing a stale SSH connection(关闭过时的 SSH 连接)中介绍了利用 SSH 转义序列来关闭失去响应的 SSH 连接。

也就是说在 SSH 终端输入 ~. 会直接中断 SSH 连接。
经过试验,确实有效(使用 SSH 代理建立的连接就没效)。

所有 SSH 转义序列:

[root@dell ~]# ~?
Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

#918 ChatGPT 插件开发

2023-05-05

体验

获得 ChatGPT 4 的资格(购买 Pro)之后,就可以看到左边页面多了一个 Model 选项,选中了 GPT 4
如果 Model 选择 Plugin 那一项,右边又会多出来一个 Plugins 选项


右边的 Plugins 选项一直往下拖,最下面一栏是 Plugin store,点击进入。

上面的插件可以选中体验体验。

安装

可以看到下方有 Install an unverified pluginDevelop your own plugin 两项。

我们开发的插件就是服务器端 API + 相关声明文件,如果就只是放在自己的服务器上,那就算 unverified plugin。
第一选项就是用来安装这样未经验证的插件,可以在 https://www.gptplugins.app/ 找一个试一下。
输入域名,ChatGPT 自动去获取声明文件 https://域名/.well-known/ai-plugin.json

第二项是用来注册插件到 ChatGPT,也可以用来调试本地插件。
如果是注册插件就填域名好了,如果是调试就输入 localhost:3000 这样的地址。
我用局域网 IP,似乎是不行的,可能只支持 localhost 这个主机名。

使用

现阶段最多能够同时勾选三个插件。
聊天过程中,ChatGPT 自动判断是否需要触发插件的使用。

开发

经过我的体验,开发非常简单,除了原本的服务之外,需要的额外工作就两项:清单文件,OpenAPI(如果原本没有的话)。

清单文件:

{
  "schema_version": "v1",
  "name_for_model": "todo",
  "name_for_human": "Todo Plugin",
  "description_for_model": "Simple task management, task description, task date, task completion. Supports adding, deleting, and querying.",
  "description_for_human": "Simple task management.",
  "auth": {
    // 本地测试 Auth Type 必须是 none
    "type": "none"
  },
  "api": {
    "url": "http://localhost:8080/.well-known/openapi.yaml",
    "has_user_authentication": true,
    "type": "openapi"
  },
  "logo_url": "http://localhost:8080/.well-known/logo.png",
  "contact_email": "hello@contact.com",
  "legal_info_url": "hello@legal.com"
}