新电脑直接激活 Administrator 账号

2025年8月4日 没有评论

全新的办公电脑从去年发给我之后,一直没有打开。今天,终于打开并开始安装所需要的环境了。

在以前,我一直是先创建一个用户,进入系统后,然后激活默认的 Administrator,之后再删除新创建的用户。这么做有一个缺点就是即使在用户管理界面里删除了,但是用户目录还在。虽然手动删除掉似乎没有什么问题,但是对于强迫症,总觉得应该有更干净的做法。

这次借这个机会,就搜索了一番。你还别说,真有方法。来,手把手的步骤来了。

开机后,系统会进入欢迎和配置界面,让你选择地区、键盘布局、联网激活等等,行话叫做 OOBE。其实小软有一点不够地道,就是为啥非要默认让你联网。

直接在第一步,使用快捷键:Shift + Ctrl + F10,如果你的电脑默认 F10 是功能键的话,那么你还需要额外加一个 Fn 键。这时会打开一个命令行界面,在里面输入下面的指令:

net user Administrator /active:yes

然后再输入下面的指令:

oobe\msoobe && shutdown -r

请注意,网上有的文章里也提及了 oobe\bypassnro,和这里的不太一样,虽然我不清楚两者之间的区别,照葫芦画瓢就好了。

输入命令后,系统会重启,也不会要求联网了。不过印象中还是会有部分信息设置,例如跨境数据传输之类的,其实也没得选,下一步就好了。

不过衣服自己洗这里,还看到一个系统弹窗,提示账户不存在,没有管,也正常进入系统桌面了。

事情到这里其实我以为就结束了,事实上并不是这样。

衣服自己洗是如何发现的呢?就是我发现运行任何程序,都没有弹出 UAC 界面,看起来就好像任何程序都直接获取到管理员权限了。这可不是太好的行为。检查了 UAC 的弹窗设置,看着也正常。网上的教程都是教你如何去除 UAC,衣服自己洗这里需求却是反过来了。

在常见的系统设置的那几个地方,和另外一个电脑比较,都是一样的配置,并没有发现什么特别的地方。这不就奇怪了么~

一番搜索,还是要上组策略,计算机配置->Windows配置->安全设置->本地策略->安全选项,里面列表的后半部分,“用户账户控制:用于内置管理员账户的管理员批准模式”,双击,选择启用。

最后,重启电脑。

嗯,再运行一些程序,熟悉的 UAC 弹窗又回来了。

分类: 日常 标签:

老款 Mac 强制升级到新版本(续)

2025年7月7日 没有评论

在前面的文章中,我有实际操作从原本的 High Sierra 升级到 Catalina, 升级后系统可以感知到明显的卡顿,毕竟 i5双核的CPU+512机械硬盘这样的硬件配置在这里。

后来又在网上发现了 Github 开源的 OpenCore Legacy Patcher 这个工具,可以把玩一番,但是衣服自己洗这里没有去升级,主要是当前的性能跟不上了,另外一个原因是会变黑苹果。

变黑苹果的原因是这个工具会重新生成序列号。有兴趣的朋友可以看看 B 站视频,我这里提供两个地址:

https://support.apple.com/zh-cn/109033
https://www.chiphell.com/forum.php?mod=viewthread&tid=2574432

分类: 一句话 标签:

老款 Mac 升级记录

2025年6月7日 没有评论

我那个2011年的老 Macbook Pro停留在 High Sierra(10.13.6)再也无法获得更新,这是我的第一台水果电脑,当年学习iOS开发可是出了不少力,所以对这个电脑很有感情的。

在吃灰了好多年后,昨天有突发奇想就给开机了,这一开机后,就想着怎么给升级系统,如果升级后XCode 可以支持我的 iPhone 8 就更好了。

经过一番搜索,发现了一个叫做 macOS Catalina Patcher 的开源工具可以帮忙实现升级到 Catalina(10.15.7),这就不错了,升了2个版本的系统。

下载完成并解压缩后,打开这个工具,你可以看到一个选项窗口,询问你新的Catalina系统,如果你已经有系统副本,可以选择 Browse for a Copy。如果没有,就点击 Download 来下载一个,大概有8G左右。对于衣服自己洗来说,当然是直接下载比较直接了。下载略微需要点时间,不过感觉还好。

接下来,选择安装方法,我直接安装到系统盘,已经是老mac了,大概率也不会有问题。当然你还可以选择第二个选项,准备一个16GB 的 U 盘来安装。第三个是光盘安装,现在光盘和光驱已经很少见了。

后面就是无脑下一步了,下载完成后,点击安装。安装过程中,你会看到一些提示和选项。按照提示一步步操作就行。这里就不说细节了,因为已经忘记了。

接下来就是设置新系统了,电脑会自动重启几次。最后算是升级成功了吧。

说下我的感觉:

  1. 升级后电脑的发热量没有明显的变化,但是系统响应变慢了点。
  2. WiFi 无线会抽风断网,不知道是否和这个有关系。
  3. 原本 /Code 文件夹,给挪到桌面了,说是不兼容,估计因为是放根目录的原因。
  4. 升级后终于可以安装 .net8 和 Jetbrains 全家桶了,就是慢。

感谢观看。

分类: 日常 标签:

安装指定版本的 XCode

2025年5月17日 没有评论

在前面的文章里,我有提及强制升级 mac 的系统,但是由于 XCode 和系统的深度绑定,我们也需要升级 XCode 到对应的版本里。

众所周知,XCode 是可以从 Store 里下载的,但是 Store 里提供的版本太新了,并不能支持当下的操作系统,所以就需要手动找地址去下载了。

考虑到以前出现过 XCode 被人植入过木马病毒,这东西即使体积巨大,也只能是通过官网下载最为合适了。

但是官网并没有直接显眼的方式提供,也可能是我使用的方式不对。后来找到了一种方法,浏览器打开 https://developer.apple.com/download/all/?q=xcod ,然后在该页面里搜索你需要的 XCode 版本号,点击下载即可。

为了稳妥起见,建议同时也下载 xcode-select 工具,在页面里一般是和 XCode 成对出现的。

需要提醒两点:一是可能需要登录,所以没有买开发者账号的就比较绕了点。第二个就是上面的查询关键词是 xcod,而不是 xcode。我自己试了下,输入完整的反而搜索不到想要的结果。所以直接复制这里的地址就最简单了。

下载完成后,直接双击解压缩,得到 XCode.app,拖动到应用程序目录里,就可以了。

分类: 一句话 标签: ,

react-i18next 进阶用法

2025年4月14日 没有评论

在过去的 React 和 React Native 项目里,对于多语言处理,使用的是 react-i18next 来处理的。今天给大家分享下这个库的一些进阶用法和注意事项。

其实一开始的时候,我自己是有点困惑的,react-i18next 和 i18next 是什么关系?为什么项目要安装这2个库,而不是一个?而且为什么在代码里如何从 i18next 里导入某些变量会出现非预期的结果。所以这里也给小伙伴解释下,react-18next 是对 i18next 的 react 版本封装。换句话来说,一般情况下,大家直接使用 react-i18next 库就可以了。

安装很简单:

npm install react-i18next i18next --save

进阶一、兼容性问题

如果你的代码在运行时出现了下面的错误:
i18next::pluralResolver:
Your environment seems not to be Intl API compatible,
use an Intl.PluralRules polyfill.
Will fallback to the compatibilityJSON v3 format handling.
那么按照官方的说明(https://www.i18next.com/how-to/faq#why-are-my-plural-keys-not-working),表示当前环境不兼容 Intl API。

解决方法:

npm install intl-pluralrules --save

然后在多语言的初始化文件里导入:

import 'intl-pluralrules'

这取决于你的 项目结构,可能就在 index.js 里,我们的项目就是在 i18n.ts 文件里。

这个问题,在我们的 React Native 项目里有碰到过。

进阶二,传字段

例如有下面的 json 文件:

{
    "error": {
        "required": "{{field}}必填",
        "invalid": "无效的{{field}}"
    }
}

那么使用时,就是这样使用的:t(‘error.required’, { field: t(‘Email’) })

进阶三,自定义多语言层级分隔符

默认情况下,代码里使用 . 来表示层级,例如 error.required,当然也可以使用下面的配置来更改为使用 “/”:

i18n.use(initReactI18next).init({
  // ...
  keySeparator: '/'
})

那么前面的调用就成了 t(‘error/required’, { field: t(‘Email’) }),我是觉得这个一般情况下是不必无苦硬吃的,可能在特殊场合需要使用。大家看看就可以。

进阶四,自动单复数

i18next 对于自动单复数有预定的约定,只需要在 key 后面添加 “_other” 即可,当然前提是对应的语言描述有复数的用法哈。

{
"hours": "{{ count }} hour",
 "hours_other": "{{ count }} hours",
}

t('hours', { count: 5 }) 
// 5 hours

对于 0 来说,实际来看,会使用复数的翻译,例如 0 hours。如果需要为 0 来单独定义的话,可以添加 “_zero”,例如:

"hours_zero": "Now"

需要提醒的是,如果这里内置的 _zero、_other 和你的多语言冲突了,还是有这个可能的,那么可以修改使用自定义分隔符,例如下面这样:

// i18n.ts
i18n.use(initReactI18next).init({
  ...  // 其它配置   
  pluralSeparator: '__', // 双下划线
})

具体使用:

{
    "days": "{{count}} day",
    "days__other": "{{count}} days",
}

进阶五,Trans 组件

这里直接借用网上的一个示例,假如要显示下面的文字“你好 {userName},你有 {count} 条未读消息。点击查看。”,并且还需要支持点击操作。

在以前的写法中,我们需要将这句话单独的拆开,使用不同的组件包装起来,例如 count 希望是一个
红色的字体之类的,还要放到不同的多语言 key 里。太费劲了。

使用 Trans 组件,可以这么写,大家琢磨琢磨,是不是简单很多。

// en.json
{
    "userMessagesUnread": "Hello <1>{{userName}}</1>, you have {{count}} unread message. <5>Click to view</5>.",
    "userMessagesUnread_other": "Hello <1>{{userName}}</1>, you have {{count}} unread messages.  <5>Click to view</5>."
}

<Trans
    defaults={t('userMessagesUnread')}
    values={{ count, userName }}
    parent={Text}
    components={{
        1: <Text style={{ fontWeight: '500' }} />,
        5: <Text style={{ color: '#4682A9' }} onPress={() => {}} />
    }}
/>

可以看到,通过使用 components 属性,借助索引可以将指定位置的元素给替换包装起来。那么有人就问了,为什么这里是数字1和5,而不是其它的呢?

Trans 组件将上面的文本转换为下面的结构:

[
  'Hello ',
  { children: [{ user_name: 'Admin' }] },
  ', you have ',
  { count: 10 },
  ' unread messages. ',
  { children: ['Click to view'] },
  '.'
]

这么来看,是不是基于 0 的索引位置就出来啦。

更多内容,可以参考官方文档说明。

分类: 日常 标签: ,

Java 里的元组使用

2025年3月25日 没有评论

在最近的 Sping boot 项目里,想要一次性返回多个对象,按照过去 .Net的经验,很容易想到的就是使用元组 Tuple,但是第一下居然没有找到,不过有 HashMap,看起来似乎也是不错的选择,但是存在需要强制转换的情况,某些场景下可能会出错。

不是很死心,于是就搜索了一下,找到了 vavr 这个库,比较简单,大家可以凑活使用。

首先是在 pom.xml 里添加依赖:

<!-- https://mvnrepository.com/artifact/io.vavr/vavr -->
<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.10.6</version>
</dependency>

使用 Tuple.of 来创建对象代码示例:

Tuple2<String, LocalDateTime> element = Tuple.of("Name", LocalDateTime.now());

创建两个元素的是 Tuple2,三个元素就是 Tuple3,这个命名方式有点特别,哈哈。

更新元组里的内容:element.update1(“名称”); 也就是 update[1-n]的方式。

读取元组元素的内容,element._1() 是获取第一个值,element._2()就是获取第二个值,以此类推。

这个库是 Apache 协议,可以商用,不错。

我又继续搜索了下,元组只是其支持的一个功能,函数式编程也支持,andThen、compose 看起来好高级哇。

异常处理的写法也不错,我简单地复制下代码:

Try result = Try.of(() -> 0)
                .map((a) -> 10 / a) //即使此处抛出异常,不会导致当前线程结束。这里无需使用 try{}catch()对代码进行捕获
                .andThen(() -> System.out.printf("--抛出异常此处不会执行--")) //执行一个动作,不修改结果
                .map(i -> {
                    System.out.println("当前值:" + i);
                    return i + 10;
                })
                .onFailure(e -> e.printStackTrace())//失败时会触发onFailure
                .recover(ArithmeticException.class, 1000) //如果遇到 Exception类型的异常,则返回1000
                .map((a) -> a + 1);

        System.out.println("是否抛出异常:" + result.isFailure());
        System.out.println("执行结果:" + result.getOrElse(100)); //如果有异常发生,则返回100

延迟计算,这个也高级,但是潜意识感觉,如果用的不好,很容易给自己挖坑。

Lazy<Double> lazy = Lazy.of(Math::random)
                .map(i -> {
                    System.out.println("-----正在进行计算,此处只会执行一次------");
                    return i * 100;
                });
        System.out.println(lazy.isEvaluated());
        System.out.println(lazy.get()); //触发计算
        System.out.println(lazy.isEvaluated());
        System.out.println(lazy.get());//不会重新计算,返回上次结果

还有另外一种线程操作的写法:

System.out.println("当前线程名称:" + Thread.currentThread().getName());
        Integer result = Future.of(() -> {
            System.out.println("future线程名称:" + Thread.currentThread().getName());
            Thread.sleep(2000);
            return 100;
        })
                .map(i -> i * 10)
                .await(3000, TimeUnit.MILLISECONDS) //等待线程执行3000毫秒
                .onFailure(e -> e.printStackTrace())
                .getValue() //返回Optional<Try<Integer>>类型结果
                .getOrElse(Try.of(() -> 100)) //如果Option 为 empty时,则返回Try(100)
                .get();
        System.out.println(result); // 1000

大家放心用吧,一用一个不吱声。

分类: Java 标签:

解决 React Native: unable to load script 的问题

2025年3月7日 没有评论

最近又创建了一个 React Native 的项目,以前踩过的坑又忘记了,所以需要记录下来,真是好记性不如乱笔头。

现象是这样的:在有了基础页面,并运行了 npm run start 本地编译后,无论是安卓模拟器还是真机,都报告错误:

Unable to load script. Make sure you're either running Metro (run 'npx react-native start)or that your bundle index.android.bundle is packaged correctly for release.

开始的时候,以为是因为 React Native 升级到 0.78 的版本导致的,因为从 0.76 开始提示会有新的开发者工具,从0.78 开始使用新开发者工具。在回退了版本以后发现还是有这个问题。

经过检索,一个快速的解决方法是在 Android 的 Manifest 文件中加入

android:usesCleartextTraffic="true"

错误原因分析,应该是应用默认不再支持明文传输了,但是本地调试的 metro 服务,脚本传输时使用的又是 http 的数据流,导致无法获取到脚本,从而产生了前面提及的错误。

当然,在生产环境下,还是建议不要使用明文传输了哈。

分类: Android, 一句话 标签:

NAS 上使用 Let’s encrypt 动态 DNS 续期 SSL 证书

2025年2月2日 没有评论

背景是我在 NAS 上部署了 immich 来存放照片,基于方便使用和安全考虑,使用 https 可能更合适。熟悉 immich 的小伙伴可能知道,这个应用需要使用反向代理来支持 SSL,虽然对于不能直接支持感觉不可思议, 但是这也不是太大的问题,开个 nginx 镜像也就实现了反向代理,关键是如何支持 SSL 证书。

现在家庭使用的基本上都是动态 IP,想要正确解析域名到实际 IP 就比较麻烦,好在 NAS 上支持动态 DNS 的解析,衣服自己洗使用的是 DNSPod,所以从里面导出一个 api key,放到 NAS 里就可以了,因为只需要很简单地无脑下一步,所以这里就不展开描述了。

但是,接下来我有碰到一个问题,由于对于家庭 IP 地址来说,80 和 443 端口一般是被运营商给禁止了的,所以 DNS 校验的方式就走不通,退而求其次看域名解析,而 certbot 又不支持 DNSPod 的,搜索了一番,网上有现成的,于是做了一个 docker 镜像,在 NAS 上部署。

第一步:克隆仓库

git@github.com:chenlongqiang/docker-certbot-dnspod.git

第二步:构建镜像

cd docker-certbot-dnspod
docker build -t certbot-dnspod .

请注意,上面命令最后还有一个英文的句号哟。

第三步:更新 dnspod.ini 配置,可以在 https://console.dnspod.cn/account/token/token 进行 DNSPod Token 秘钥创建。

第四部:部署镜像

# 申请新证书,执行后会进行命令行交互,填写完信息后将在 certs 目录下生成申请成功的证书
docker run -it --rm -v ./conf/dnspod.ini:/data/certbot/dnspod.ini -v ./certs:/etc/letsencrypt certbot-dnspod -d your_domain.com -d "*.your_domain.com"

# 续期 certs 目录下的证书
docker run -it --rm -v ./conf/dnspod.ini:/data/certbot/dnspod.ini -v ./certs:/etc/letsencrypt certbot-dnspod renew

请注意,如果不需要一次性,那么可以不添加 –rm 参数。同时请修改 dnspod.ini 的路径为你的实际路径。

经过验证,确实可以获取到 Let’s encrypt 生成的证书,然后更新到 nginx 的路径里。

不过,一个 https 的地址还带端口号,看着就怪怪的。

分类: 日常 标签:

解决 error listen EACCES: permission denied 0.0.0.0:8081

2025年1月9日 没有评论

今天发现电脑在重启后,打开 NodeJS 项目后无法运行,提示 8081 端口被占用了。一开始以为是某个 node 非正常占用导致,关闭所有相关的软件并确认没有node 进程存在后,再次运行项目,发现还是提示端口被占用。

按照我先前整理的《查找端口被占用的程序,执行 netstat -ano | findstr 8081,发现找不到占用端口的进程。

看来要狂暴一下了。

经过一番搜索,网上有一个观点是端口被 WSL 占用了,大意是微软在使用 reservation/exclusion 机制来进行动态端口分配时,分配的端口号有的比较低,所以导致和其它软件冲突。

运行下面的命令:

netsh int ipv4 show excludedportrange protocol=tcp

发现 8081 端口在范围里面。

运行下面的命令:

netsh int ipv4 show dynamicport tcp

可以看到系统赋予的起始端口号确实比较低。

解决方法,就是重新设置动态端口的区间范围,例如运行下面的命令:

netsh int ipv4 set dynamic tcp start=49152 num=16384

非常重要的是,需要重启电脑。

重启后可以重新运行命令来确认下:

netsh int ipv4 show excludedportrange protocol=tcp

最后提醒大家的是,运行上面的命令时,最合适地是使用管理员权限来运行。

分类: 日常 标签:

限制 mysql 的内存占用

2024年12月5日 没有评论

最近发现站点经常无法打开,以往都是直接重启服务器,偷懒省事。后来无意间在控制台登录,发现原来是 mysql 的内存占用过大,导致 out of memory,被系统杀掉了进程。

按道理来说,一个小破站,真的需要那么大的内存占用么,而且这么多年来大部分时间都没有问题,也不清楚具体是从什么时候开始有这个问题了。

按照网上的教程,结合服务器上的配置。

cd /etc/mysql/mysql.conf.d

修改 mysqld.cnf 这个文件,添加或者更新一条配置

innodb_buffer_pool_size = 100M

大家结合自己的实际情况来修改吧,这个默认值看起来是 128M。

网上还有更新下面的配置,我没有设置,先跑跑看。

# 设置最大连接数
max_connections = 100
# 设置线程缓存大小
thread_cache_size = 16M
# 设置每个连接最大的查询缓存大小
query_cache_size = 64M

不要忘记 sudo service mysql restart

分类: Server, 日常 标签: