<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://liaoguoyin.com/atom.xml</id>
  <title>Coin&apos;s Blog</title>
  <link href="https://liaoguoyin.com" />
  <link rel="self" href="https://liaoguoyin.com/atom.xml" />
  <updated>2025-10-10T16:00:00.000Z</updated>
  <author>
    <name>coin</name>
  </author>
  <entry>
    <id>https://liaoguoyin.com/sync-with-git-bare</id>
    <title>用 Git 裸仓库在多台内网机器中同步代码</title>
    <link href="https://liaoguoyin.com/sync-with-git-bare" />
    <updated>2025-10-10T16:00:00.000Z</updated>
    <published>2025-10-10T16:00:00.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">由于一些特殊的环境限制，个人需要在多台内网主机之间同步代码仓库。

从表面上看，这似乎只是一个“文件同步”问题。我最初的方案也很直观：通过 Rsync, Syncthing 等应用软件同步代码文件夹和 .git 文件夹，这样既能同步代码数据，又能保留提交历史。

不过细想，这种做法经不起推敲。在弱网、断网或延迟同步的场景下，这种**文件层级的同步**几乎注定会破坏 .git 数据库。

举个简单的例子：如果 A、B 两台主机各自提交了新的代码（即形成了“硬分叉”），那么在它们重新联网、自动触发同步时，双向的文件更新会直接覆盖 .git 内部的索引与对象文件。结果不仅是当前分支元数据混乱，更严重的是整个历史记录可能被污染，甚至两台机器的仓库都可能损坏。而且这还只是两台主机的情况——随着同步节点数量增加，这种“分布式文件同步”方式只会让 .git 乱成一锅粥。

## 0. 问题分析

要避免上面的问题，必须重新审视两个核心点：

*   同步方向：原方案是“双向同步”，双方在网络恢复后会同时互相写入，无法保证优先级，从而破坏仓库一致性。
    
*   同步操作原子性：文件同步程序控制同步触发时机的不可靠，弱网或中断时可能发生“同步一半”的非原子状态。
    

经过一番调研后，发现 **Git 裸仓库（bare repository）同步** 能完美解决这两个问题：

*   **单向同步机制**：  
    Git 的 push/pull 天然是单向的。任何节点都可以主动推送或拉取，仓库的版本流向始终可控。
    
*   **原子性与一致性保证**：  
    Git 在传输时只处理对象级别的差异，并且会有文件粒度的哈希校验，push/pull 操作要么全部成功，要么全部失败，不会出现“同步到一半”的状态。
    
*   **离线友好**：  
    各主机在离线时可独立提交，网络恢复后通过 `git push` / `git pull` 合并更新，过程完全受版本控制系统管理。
    

因此，最后确定 **Git 裸仓库作为中转节点** 的方案做数据仓库同步，以下是一些相关的理论和实操记录，存档防忘。

## 1. 什么是「裸仓库」？

在普通 Git 仓库中，结构大致如下：

```markup

myrepo/
├── .git/ ← Git 数据库
└── src/ ← 工作区（实际文件）

```

而裸仓库（bare repository）去掉了工作区，只保留 .git 目录的内容结构：

```markup

myrepo.git/
├── HEAD
├── config
├── objects/
└── refs/

```

它只保存版本历史，不保存任何可编辑文件。也就是说，**不能直接编辑代码，只能被 push / pull。** 这也是 GitHub、GitLab 等远程托管服务背后的核心模型。

## 2. 为什么要用裸仓库？（典型应用场景）

*   在两台机器之间同步开发代码
    
*   自建局域网版「私有 GitHub」
    
*   自动镜像同步到 GitLab / Gitee / 备份服务器
    
*   国内服务器不方便拉 GitHub 代码的中转方案
    
*   建立 CI/CD 触发源（`post-receive` 钩子）
    

## 3. 动手实践：两台机器间同步

假设：

*   开发机：`A`
    
*   同步服务器：`B`
    

### 3.1 在 B 上创建裸仓库

```bash
mkdir -p /git-server/repo.git
cd /git-server/repo.git
git init --bare

```

执行后目录结构如下：

```markup
repo.git/
├── HEAD
├── objects/
├── refs/
└── config

```

### 3.2 在 A 上添加远程并推送

```bash
cd ~/workspace/myproject
git remote add b ssh://user@B_IP:/git-server/repo.git
git push b main

```

此时，B 的 `/git-server/repo.git` 完整保存了 A 推送的文件更新。

你可以在任意机器 `git clone ssh://user@B_IP:/git-server/repo.git` 拉取最新版本。

## 4. 在服务器也能看到最新源码

如果你希望在服务器 B 上也能直接查看代码，可基于裸仓库克隆一份工作区：

```bash
git clo</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/coin-device</id>
    <title>俺的电子垃圾列表</title>
    <link href="https://liaoguoyin.com/coin-device" />
    <updated>2025-08-31T07:09:00.000Z</updated>
    <published>2025-08-31T07:09:00.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">## 主力设备

*   Macbook Pro M3 Max，48GB+1TB
    
    *   天天摸的干活机器，一步到位战五年版
        
*   iPhone 15 Pro，256GB
    
    *   天天摸的手机，布老板官翻换新下来的，下一个不能换太好的，不然天天看
        
*   iPad Mini 6，Celluar，64GB
    
    *   车机补充和日常家庭投影主控。只有蜂窝版有 GPS，才能高精度定位
        
*   Macmini M4，16GB+256GB
    
    *   全屋软路由网关（Surge）
        
    *   Docker 运行载体（Orbstack）
        
*   AirPods Pro 3
    
    *   天天挂耳朵上，上班下班听李志。最近几年买得最值的电子产品，降噪一开就是沉浸
        
*   Apple Watch SE，44mm
    
    *   看时间
        
    *   睡眠检测，每天早上起床第一件事就是看昨天晚上有多久深度睡眠，睡得香的时候会和H老师比划比划
        
*   RedmiBook，16GB+512GB
    
    *   Windows 备用本。社长曾经干活的机器，回购后给了俺，目前只有联机打红警的时候会开机 🤣
        
*   零刻 ME mini NAS，4TB \* 2
    
    *   全闪 NAS，备份、跨设备同步
        
    *   Docker 运行载体
        
    *   影音中心，飞牛影视挂削效果不错，回拉 115 和百度云资源，缓存到本地方便H老师刷剧
        
*   JMGO P5X
    
    *   投影，1080P 分辨率，走到哪、提到哪、随便投屏（可投天花板）
        
*   理光 GR III HDF
    
    *   网红卡片机。其实网红不网红无所谓，愿意拿出来拍照的机器才最重要（iPhone 有话说）
        

## 外设

*   Apple Studio Display
    
    *   天天看的干活机器。C 口一线通+还不错的扬声器，买的时候觉得贵后牙槽都咬碎了，买之后天天用，香
        
*   Niz 86
    
    *   公司高强度长时间写代码用，手感软软的，喜欢
        
    *   静电容键盘，自己换了一套键帽（TODO：补图
        
*   Logi Anywhere3
    
    *   鼠标，公司用，买的时候觉得亏，现在已经离不开它的长滚动了
        
*   Logi MX Keys Mini
    
    *   在家天天摸的键盘，通过蓝牙多设备切换。插了收发 USB，作为显示器下游，跟随显示器上游 C 口线走
        
*   TrackPad V2
    
    *   在家天天摸的触控板，通过蓝牙多设备切换。插了数据线，作为显示器下游，跟随显示器上游 C 口线走
        
*   3D-Printed Topcase
    
    *   让键盘和触控板一体的塑料壳。实现了 Macbook 一样的键盘触控板布局体验
        
*   ZTE F50
    
    *   随身 Wifi，给 Macmini 提供 fallback 蜂窝数据网络
        

小件：

*   Samtisan R2
    
    *   收来感受锤子系统 TNT 和系统软件小巧思的，稳定吃灰中
        
*   Apple Magsafe Duo
    
    *   二合一无线充，7.5W巨慢充，聊胜于无的无线充
        
*   UGREEN 3 in 1
    
    *   三合一无限充，床头放，睡前迷糊磁吸充
        
*   Belkin 3 in 1
    
    *   三合一无线充，干活桌上放，耳机和手表随手一放就能充，买了之后再也不会没电了
        

## 智能家居

*   Xiaomi IoT
    
    *   买了一堆人在传感器和开关控制器改造，实现人来灯开人走灯灭
        
    *   扫地机器人
        
    *   空调伴侣
        
    *   窗帘伴侣
        
*   HomePod
    
    *   早起闹钟，隔空投送扬声</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/hacking-claude-code-using-kimi-k2</id>
    <title>Hack Claude Code 使用 Kimi K2 模型</title>
    <link href="https://liaoguoyin.com/hacking-claude-code-using-kimi-k2" />
    <updated>2025-07-12T13:39:00.000Z</updated>
    <published>2025-07-12T13:39:00.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">昨天晚上（20250711）刷到开源的 Kimi K2 模型（非推理模型）。

[官方号称：上下文 128K，总参数 1T，成本超低。](https://github.com/MoonshotAI/Kimi-K2)

意外地是看到支持 Anthropic 协议，印象里面还没有其他官方模型主动支持的（大家都是 OpenAI compatible），这不是一下就来了兴致。研究了一下怎么在 Claude Code 中用 Kimi K2。

直接说结论，在已安装过 ClaudeCode 的情况下，不用安装任何新的玩意就能用上，具体步骤如下：

*   [Kimi 官网生成 API key](https://platform.moonshot.cn/console/api-keys)
    
*   打开命令行导出两个环境变量即可（ANTHROPIC\_BASE\_URL 和 ANTHROPIC\_AUTH\_TOKEN），见 P1。
    

![](https://static.gridea.dev/98cd32d9-2e67-4904-bba1-f2457817463a/CMPTU0VEC.png)

```markup
export ANTHROPIC_AUTH_TOKEN=sk-qViCuNrhyQaDPrELy3aM3UVZXcQmIz5Oh4iNRtm8XXXXXXXX
export ANTHROPIC_BASE_URL=https://api.moonshot.cn/anthropic
claude

```

## 在 CC 中使用外部模型的方法

常规在 ClaudeCode 中使用外部模型有两种方法：Proxy 代理，LLM 网关。

### Proxy 代理

测了 claude-code-router（claude-bridge、anthropic-proxy 未测）。结果发现 Proxy 在上下文维持上有问题，初始化就会触发 TPM（每分钟 Token 处理量）限制，基本不可用，见 P2。

![](https://static.gridea.dev/98cd32d9-2e67-4904-bba1-f2457817463a/Jnc4vzfzR.png)

### LLM 网关（推荐）

[LLM Gateway 是 Claude Code 官方支持的企业级方案。](https://docs.anthropic.com/en/docs/claude-code/llm-gateway)

这个口子本来是开给企业级 Claude 模型用的，但是 Kimi K2 主动兼容支持了下，对 ClaueCode 客户端来说，它认为在与 Anthropic 服务器通信，实际上请求被重定向到了 Kimi 服务器，返回的响应也符合 Anthropic API 的格式要求，这样一来就能在 ClaueCode 中用 Kimi K2 模型啦。

#### 绕过 Claude Code 认证

打开项目文件夹，终端启动 Claude Code

```hljs
cd /path/to/your_project
claude

```

如果是首次启动 Claude Code，会弹出登录认证网页。

只需要编辑 `$HOME/.claude.json` 添加新字段 `&quot;hasCompletedOnboarding&quot;: true` 即可。

![](https://static.gridea.dev/98cd32d9-2e67-4904-bba1-f2457817463a/BoPZrYk8H.png)

至此就是全部配置完成啦。实际体验下来，用 ClaudeCode 过程中还有概率爆 TPM，[账号升级 T1 后 TPM 扩大到 128000 才基本可用](https://platform.moonshot.cn/docs/pricing/limits)（至少充 50 CNY），如果单次会话爆 TPM 可用 /clear 或开新会话。

![](https://static.gridea.dev/98cd32d9-2e67-4904-bba1-f2457817463a/KE99OYUCc.png)

#### VScode + Cline 使用 Kimi K2

另外，也尝试了下 VScode + Cline 使用 Kimi K2，UI 驱动逻辑打断太多，个人感觉没 ClaudeCode 丝滑。也可作为一个参考，见 P3。

![](https://static.gridea.dev/98cd32d9-2e67-4904-bba1-f2457817463a/9YSoSlhHx.png)

#### 初体验

最后用 CC + K2 实现了</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/clang-format-team-cpp-code-style</id>
    <title>使用 Clang-format 统一团队 C++ 代码风格</title>
    <link href="https://liaoguoyin.com/clang-format-team-cpp-code-style" />
    <updated>2025-04-11T18:47:48.000Z</updated>
    <published>2025-04-11T18:47:48.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
使用 Clang-format 工具在团队中统一 C++ 代码风格，提高代码可读性和维护性。


在团队中，统一代码风格可以有效提高内部项目可维护性，避免低级编码错误。

为实现这一目标，三板斧如下：

1. 确定格式化规范
2. 选择格式化工具，编写调试配置文件
3. 将规范集成到开发的各个流程中（编码开发，代码管理，编译打包），并跟进反馈修正

## 1. 确定格式化规范

代码格式化规范已经非常标准化。常规标准有 LLVM，Google，Webkit 等。

笔者组内已有 C++ 编码规范：

![组内 C++ 编码规范](https://cdn.liaoguoyin.com/images/clang-format-team-cpp-code-style_1.png)

常见的格式化规范要求涉及如下部分：

1. 命名规范

- 类、结构体、枚举、联合体、类型定义、作用域名
- 函数名(包括全局函数、作用域函数、成员函数)
- 全局变量(包括全局和命名空间域下的变量，类静态变量)，局部变量，函数参数，类、结构体和联合体中的成员变量名
- 宏、全局常量、枚举值、goto标签

2. 格式规范

- 括号位置
- 空格位置及使用情况
- 行宽
- 缩进

3. 注释规范
4. 语言级高级特性使用建议

## 2. 选择格式化工具

确定上述规范后，并不能指望团队成员能很好地应用规范。因此，需要选择格式化工具，通过介入开发的各个阶段，潜移默化地辅以开发者遵守规范。

CPP 常见的格式化工具有 [cpplint](https://github.com/cpplint/cpplint)，[clang-format](https://clang.llvm.org/docs/ClangFormat.html)，[clang-tidy](https://clang.llvm.org/extra/clang-tidy/index.html) 等：

- cpplint 是格式化工具，主要围绕 Google 规范展开，现已不再维护公开仓库
- clang-tidy 是静态代码分析工具，可以实现[变量名风格纠正替换](https://clang.llvm.org/extra/clang-tidy/checks/list.html)
- clang-format 是格式化工具，调整空格换行符等格式规范

经过初步调研后，发现 [clang-format 基本能满足所有需求（格式规范和注释规范），命名规范方面则可以结合 clang-tidy 可为补充](https://stackoverflow.com/questions/73788989/how-to-configure-naming-conventions-with-clang-format)：

&gt; Clang-format is all about local changes to the code in a way that is irrelevant to the compiler. Like changing whitespace. Renaming variables, on the other hand, is a completely different thing, since its impact is potentially very global (think about exported symbols consumed by other libraries, or just multiple files).

下文是笔者集成 Clang-format 的一点实践经验。

## 3. 编写 .clang-format

引入 Clang-format 需要编写 .clang-format 配置文件，通过配置文件的形式调用的好处很多：无论是在命令行脚本中或是 IDE 中或是 CICD 流程，都能很方便地集成同一套规范。

[Clang-format 支持的配置参数很多](https://clang.llvm.org/docs/ClangFormatStyleOptions.html)，为提高编写配置文件效率，[可以使用在线 .clang-format 配置预览网站](https://clang-format-configurator.site/)，修改后实时预览格式:
![image-20250412223702866](https://cdn.liaoguoyin.com/images/clang-format-team-cpp-code-style_2.png)

经过 GPT 辅助+文档查询+网站在线调试后，初版格式化配置文件如下：

```YAML
# .</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/new-mac-setup-configuration-guide</id>
    <title>配一台新 Mac 我都配些什么</title>
    <link href="https://liaoguoyin.com/new-mac-setup-configuration-guide" />
    <updated>2025-03-26T11:47:00.000Z</updated>
    <published>2025-03-26T11:47:00.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">最近装机频繁，抹掉系统之后装来装去就那几个 App，就那点设置。

索性记录下配置新 Mac 时的设置，顺便整理分享一些比较好用的 Mac App。

内容主要分为三大块：[系统设置](https://macos-defaults.com/)、安装应用软件(Homebrew)、数据迁移。

## 系统设置

### 键盘

为了方便连续输入，调整按键重复速度：系统偏好设置 &gt; 键盘

* 按键重复速度：最快

* 重复前延迟：短（或倒数第二格）

### 触控板

[默认触控板需要按到底，且部分手势没开启，按需调整](https://wild-flame.github.io/guides/docs/mac-os-x-setup-guide/preference_and_settings/readme)

![image-20250329124059851](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_1.png)

* 修改点按力度，开启轻按触摸：系统设置 &gt; 触控板 &gt; 光标与点按 &gt; 点按「**中**」

* 快速单词查询，开启三指轻点：系统设置 &gt; 触控板 &gt; 光标与点按 &gt; 查询数据检测器「**三指轻点**」

* 实现鼠标右键，开启双指点按：系统设置 &gt; 触控板 &gt; 光标与点按 &gt; 辅助点按「**双指点按**」

* 避免误触发，关闭轻点：系统设置 &gt; 触控板 &gt; 光标与点按 &gt; 辅助点按关闭「**轻点来点按**」

![image-20250329124642156](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_2.png)

* [三指选中多行文本](https://sspai.com/post/39202)。开启三指拖拽：系统设置 &gt; 辅助功能 &gt; 互动 &gt; 鼠标与触控板 &gt; 触控板选项「三指拖移」

### 台前调度设置

![1744471692361](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_3.png)非常糟糕的交互特性，容易误触，关闭台前调度中墙纸点按收放：设置 &gt; 桌面与拓展坞 &gt; 点按墙纸以显示桌面「仅在台前调度中」

### Finder 设置

![image-20250329123547842](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_4.png)打开 Finder，在屏幕右上角选择「偏好设置」（command + .）

* 设置新窗口默认打开位置：Home 目录

* 自定义侧边栏选项

* 显示路径栏和状态栏

### Terminal 设置

Mac 自带的 Terminal 终端很好用，但缺点是比较简陋，文本既没高亮，信息又不完整。

可以通过修改 Shell 配置文件 `~/.zshrc` 来实现 **文件夹高亮显示、完整路径显示。**

配置前后的差异如下：

![1](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_5.png)

```bash
export CLICOLOR=&apos;Yes&apos; # 是否输出颜色
export LSCOlORS=&apos;Exfxcxdxbxegedabagacad&apos; # 定义 ls 命令输出的颜色和样式
export LC_ALL=en_US.UTF-8 # 设置所有区域设置为美国英语，字符编码为 UTF-8
export LANG=en_US.UTF-8 # 设置默认语言为美国英语，字符编码为 UTF-8
export PS1=&quot;%B%F{034}%m%f%b:%d %% &quot; # 设置命令提示符格式，包含主机名和当前目录

export LC_ALL=en_US.UTF-8 # 重复设置所有区域设置
export LANG=en_US.UTF-8 # 重复设置默认语言

```

### Time Machine

![Xnip2024-11-21_23-52-39](https://cdn.liaoguoyin.com/images/new-mac-setup-configuration-guide_6.png)有 Mac，有 NAS，那么碎片化整机增量备份，Time Machine 自然少不了。

注：为避免 NAS 硬盘炒豆子噪音，可以降低备份频率到「每周一次」

### 远程连接

为了能</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/why-blog-in-2025-reflection</id>
    <title>在 2025 年写博客是为了什么</title>
    <link href="https://liaoguoyin.com/why-blog-in-2025-reflection" />
    <updated>2025-03-13T17:03:38.000Z</updated>
    <published>2025-03-13T17:03:38.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
2018 年，我注册了域名，写下了第一篇 Blog，当时的契机其实是模仿。一天大半夜，我刷到一个本科老大哥的博客，很崇拜他在学校做的事——写了个 iOS App。我把他写 iOS App 的几篇文章翻来覆去地看了好几遍还找到一些隐藏彩蛋，备受鼓舞，发了封邮件而且很快收到了回复。看完更是感觉自己浑身上下有使不完的牛劲，也能做点什么。于是第一步，照猫画虎搭起了学着老大哥的博客准备记录点东西。谁知道学没学到精髓，几年下来，博客程序换了一套又一套，正经文章却没写几篇。

最近几年 LLM 发展很快，极大程度改变了我们绝大多数人的搜索、思考、输出的方式。每个人每天都对着聊天框地抠着提示词，一个字都不愿多打就按下了回车，聊天框呼呼地滚着「答案」，这种状态下，静下来思考成了一种奢侈品，写文章更是让人觉得是一件投入产出比性价很低的事。

所以，2025 年，写博客/写作是为了什么？

**我的答案是：是让自己安静下来，梳理在做的事情，是在对着外界倒点垃圾**

## 是让自己安静下来，梳理在做的事情

&gt; 写点东西可以冷静下来，集中注意力干点事

在这个碎片化时代，我们的时间、精力、注意力也被敲碎成一块又一块。其实用不上什么下一代计算平台（Vision Pro 🤡），我们已经足够沉浸在手机世界里面，你可以现在抬头看窗外路过的人，会发现 60%+ 的年轻人都会一边走路一边刷着手机。

说来惭愧，我也是这群人的一员。不过是经常下班之后躺着刷，刷完了没有尽头的 Twitter/Rednote timeline，放下手机后一种空虚和焦虑的感觉席卷而来，缓过神来之后却又不知道自己要干什么。很长一段时间，感觉很难集中注意力，思维混乱，梳理不清东西。

写文档确实能让人冷静下来，因为写作本质还是脑力活动，不冷静下来去思考，没法写。

让我领略到这一点的是 L。一次我们一起梳理技术细节，他在共享文档上码了好多字，但在总结部分总觉得没写好，我看他二话不说直接删了全部重写。一开始不是很理解为什么这么干，这不是给自己找堵吗？后来我知道了，看到他从头重新捋了一遍，越梳理越清楚，才明白他是在通过写文档梳理思绪。

## 是在对着外界倒点垃圾

&gt; To be a creator but not user

前面有一段时间，我每天都逼着自己都在互联网上一些犄角旮旯随地大小💩，希望能每天都输出点东西。比如是发一张当天用心构图的照片、分享一些最近发现的新鲜玩意、写点什么感悟总结。

这么做的理由其实很简单，因为我不想只做一个内容消费者，我想创造点什么，如果恰好创造的东西不是垃圾，那就再好不过了。

坚持这样一件事情确实会让当下的感觉更丰富一些了，我会刻意去感受，去记录，去分享。不过这件事情我并没有坚持太久，直接原因是不好统一量化/记录我每天都发了什么（🤔）。不过我觉得这是一件有意义的事，后面还会尝试一下记录输出。

另一方面，LLM 冲击着我们的信息世界，它们生成的一波又一波的垃圾真正流回互联网，成为以后的训练推理数据，搞不好下一代就是 AI 学出来的数据教出来的。前段时间还看到 WDT 数字生命，大概是用自己的录音、视频、博客去训练了一个和自己语气很像的数字 Bot。

在这种背景下，个人的思考、文档、文章成了一种奢侈品，是最宝贵的数据。不过也是在这种背景下，虽然现在 LLM 遍地开花，纯手工写作成了件奢侈事，你随便整理点思路，它就能给你造一篇像样子的东西出来，但这都是从模型参数下吐出来的东西，不是我们自己思考的结果。相比之下，自己思考和沉淀的东西可能才是非常宝贵的财富。

## 期望

&gt; 避免「对完美有执念，对完成没态度」

从 2018 年到现在，个人记录了 950+ 备忘录，但流水账居多，大都没有发出来过（今天找借口了吗 🥵）

备忘录里面躺了太多垃圾都不如的信息废料。想一想就遗憾，确实错过了很多记录思考的机会。

其实写作应该是件很容易有反馈的事情，只要你不去想还有几个二级标题下面的内容没写完。一直打字写，写，写，它就总有写完的时候。写到这里算是想明白了，以后我的 Blog Post 里面，不应该再有 Draft 和 Done 两种状态。

要开坑就应该一鼓作气地开，先把垃圾框架发出来，坑再慢慢补。这么做的道理其实也很简单，好的文档/文章从来都不是写一次就能写好的，让我们造点垃圾。

这不，刚刚又造完一篇垃圾。不过感觉，好像也没想象中那么垃圾 🤔。

于 2025 年 3 月 14 日 01:01
</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/zerotier-custom-moon-acceleration-node</id>
    <title>Zerotier 组网之自建 Moon 加速节点</title>
    <link href="https://liaoguoyin.com/zerotier-custom-moon-acceleration-node" />
    <updated>2024-11-27T08:46:38.000Z</updated>
    <published>2024-11-27T08:46:38.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
ZeroTier 是商业级的 P2P 组网方案。因其服务器位于境外，中国大陆用户经常遇到延迟较高的问题。为解决这个问题，[从 ZeroTier 1.2.0 版本开始，引入了自建 Moon 节点功能](https://docs.zerotier.com/roots)，允许用户部署私有中转节点来优化网络性能。

本文记录了 Moon 节点的部署和使用步骤。

## 1. Moon 节点工作原理概述

ZeroTier 网络中的所有节点默认都位于 Planet 中，即 ZeroTier 的官方根服务器网络。Moon 节点作为用户自定义的根服务器，具有以下特点：

1. **双重路由机制**
   - 节点同时使用 Planet 和 Moon 服务器
   - 自动选择延迟最低的路由
   - 当两者都不可用时回退到官方服务器
2. **适用场景**
   - 优化特定地理位置的网络性能
   - 创建离线/内网组网环境（毕竟整个互联网也算是个大局域网）

## 2. 部署 moon 节点

前置条件：

- 节点需要具有静态 IP（可以是公网 IP 或内网 IP。如果没有公网 IP，无法通过路由公网访问）
- 开放 UDP 9993 端口（防火墙和安全组都需要放行，可在服务器防火墙和云服务商安全组中放行）
- 主要需求是稳定的网络连接

### 2.1 安装 Zerotier

打开命令行，在云服务器 linux 上安装 Zerotier：

```

# Linux 下载安装

curl -s https://install.zerotier.com/ | sudo bash

# 验证安装情况

zerotier-cli info

```

![image-20241204225936251](https://cdn.liaoguoyin.com/images/zerotier-custom-moon-acceleration-node_1.png)

### 2.2 生成 moon 配置文件

```

# 进入配置目录

cd /var/lib/zerotier-one

# 生成初始配置。读取 identity.public 中的公钥信息，生成初始的 moon 节点配置的 JSON 文件:

zerotier-idtool initmoon identity.public &gt; moon.json

```

&gt; 如果没有生成 moon.json 文件，可能是因为没有写文件的权限。可以 sudo -i 切换为超级用户后再执行命令

![image-20241204230001959](https://cdn.liaoguoyin.com/images/zerotier-custom-moon-acceleration-node_2.png)

```

# 生成最终配置文件。基于 moon.json 配置文件，生成最终的 moon 配置文件（通常命名为 000000xxxx.moon）：

zerotier-idtool genmoon moon.json

```

![image-20241204230044465](https://cdn.liaoguoyin.com/images/zerotier-custom-moon-acceleration-node_3.png)

如上图，最终的 000000a62f602019.moon，其中包含了完整的配置信息：

- 是二进制文件，不可读
- 带有加密签名
- 通常放在 /var/lib/zerotier-one/moons.d/ 目录下
- moon-id 为(10 位或 16 位标识符)：**000000a62f602019**或**a62f602019**

## 3. 使用 Moon 节点加速

同样地，首先需要在客户端安装 Zerotier，然后在在客户端中加入 moon 节点。

#### 3.1 在客户端添加 moon 节点

&gt; 不同客户端版本 moon-id 不一致，需要检查本机 zerotier 版本（zerotier-cli -v 命令可查看版本），如：
&gt;
&gt; - 在 zerotier 1.10.6 版本中，moon-id 是 16 位，前面有多余 0
&gt; - 在 zerotier 1.12.2 版本后，moon-id 是 10 位字符串
&gt;
&gt; 总的来说，在新版中 moon-id 是 10 位字符串，需要注意删除前面多余的 0
&gt;
&gt; 这是一个很奇怪的更新，在官方的文档中我没找到任何明确的说明，[还是自己去 Github 开 Issues 问到的（笑脸黄豆.jpg）](https://github.com/zerotier/ZeroTier</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/docker-file-permission-consistency-issues</id>
    <title>记 Docker 容器内外文件夹权限一致性问题的坑</title>
    <link href="https://liaoguoyin.com/docker-file-permission-consistency-issues" />
    <updated>2024-11-09T08:47:02.000Z</updated>
    <published>2024-11-09T08:47:02.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
最近频繁使用 docker-compose，发现在容器迁移、备份和使用方面非常便利。

容器的启停只需要 `docker-compose up` 和 `docker-compose down`，大大降低了心智负担。

但是在一次使用 `docker-compose up` 启动（创建）以下容器时，遇到了创建文件 ./data/config.json 失败的问题。

```
# https://hub.docker.com/r/shellngn/pro/
services:
  shellngn:
    image: shellngn/pro:latest
    container_name: shellngn
    ports:
      - &quot;8080:8080&quot;
    volumes:
      - ./data:/home/node/server/data
    environment:
      - HOST=0.0.0.0
      - TZ=Asia/Shanghai
    restart: unless-stopped
```

通过 `docker logs shellngn` 查看日志，发现是挂载本地目录 ./data 到容器后，容器在创建文件时报错：

```
shellngn is up-to-date
Attaching to shellngn
shellngn    | node:internal/fs/utils:356
shellngn    |     throw err;
shellngn    |     ^
shellngn    | 
shellngn    | Error: EACCES: permission denied, open &apos;./data/config.json&apos;
shellngn    |     at Object.openSync (node:fs:596:3)
shellngn    |     at Object.writeFileSync (node:fs:2322:35)
shellngn    |     at _0xb7420b.&lt;computed&gt;.&lt;computed&gt; [as init] (/home/node/server/bundle.js:1:1213484)
shellngn    |     at 40392 (/home/node/server/bundle.js:1:1069259)
shellngn    |     at _0x2d71f3 (/home/node/server/bundle.js:1:9475095)
shellngn    |     at /home/node/server/bundle.js:1:9475859
shellngn    |     at /home/node/server/bundle.js:1:9483783
shellngn    |     at Object.&lt;anonymous&gt; (/home/node/server/bundle.js:1:9483984)
shellngn    |     at Module._compile (node:internal/modules/cjs/loader:1364:14)
shellngn    |     at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) {
shellngn    |   errno: -13,
shellngn    |   syscall: &apos;open&apos;,
shellngn    |   code: &apos;EACCES&apos;,
shellngn    |   path: &apos;./data/config.json&apos;
shellngn    | }
shellngn    | Node.js v18.20.1

```

查阅资料后发现，这个问题通常是 **Docker 容器内外的操作用户权限不匹配** 导致的：

- 当使用 `docker-compose up` 创建文件夹时，这些文件夹通常是由容器内部的进程创建的。容器内部的进程可能以 root 用户或其他特定用户身份运行，而这个用户的 UID（用户 ID）可能与宿主机系统上的用户权限不匹配，这就导致了权限错误
- 相比之下，如果使用 Docker Volume 就不会有文件权限的问题。因为 Docker 守护进程创建文件夹时，它通常能够正确处理权限问题

## 解决方法

解决方法其实非常简单：限制、同步权限

### 方法一：使用 user 指令

在 docke</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/viral-xiaohongshu-tech-article-insights</id>
    <title>顺手发了篇爆款小红书技术文章所想到的</title>
    <link href="https://liaoguoyin.com/viral-xiaohongshu-tech-article-insights" />
    <updated>2023-09-25T03:34:01.000Z</updated>
    <published>2023-09-25T03:34:01.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
秋招好累，昨天下午实在无心学习，顺手写了个小红书抢亚运会转售票文章[《网页端半自动抢转售票心得》](https://www.xiaohongshu.com/explore/65100bc0000000001f03eaaa)

早上一睁眼发现满是红点，不到 12 个小时就 1w 阅读，1k 多收藏，从 0 新涨了一小波粉丝

![xiaohongshu-data](https://cdn.liaoguoyin.com/images/viral-xiaohongshu-tech-article-insights_1.png)

明明一个没有技术含量的东西（一句话就是浏览器插件自动刷新提醒库存方便抢票），效果却出奇地好 🤨

搞得我洗澡的时候想了好久：为什么？还能复刻吗？能尝试做点什么吗？

## 为什么效果还不错？

因为大家迫切地想解决抢转售票手机刷买不到的问题。

- 这个方法算是 **一点小小的优化**，能解决到别人的痛点，且学习成本低，用户体验好
- 行文逻辑里面放满了最后抢成功的图刺激他们的痛点神经，包括后面在评论区里面不断鼓励他们去做，有人跟着做着成功了来评论一下，效果正向反复促进
- 推荐算法牛逼，能帮你推送到目标用户，对他们直接产生价值
- 对用户来说能省下不少给黄牛的钱，对黄牛来说是致命的，甚至能催生新的代抢新黄牛

## 还能复刻吗？

可以，但是要降低身段，放弃所谓的技术洁癖，做有价值的内容，不需要炫技。

**做所谓的目标人群觉得有价值的内容，让他们觉得看了会有收获、能被激励到**

**快速扫两眼了解到的符合他们点开标题前的期望阈值，用户就会收藏或者点赞，文章权重就会上来，然后有更多的推荐流量，这和做 SEO 一个道理**

## 还有什么要注意的？ 一些思考

本来为了满足一点小小的虚荣心撒狗粮，在文章里面小秀了一下是给对象抢的出发点。

但是过了一点时间发现评论区好像有疑似 👊 言论

![1695615908864](https://cdn.liaoguoyin.com/images/viral-xiaohongshu-tech-article-insights_2.png)

&gt; 这个评论甚至是现在下面热度最高的，老实说，我本人看到这个没那么舒服。作为一个简单的攻略分享，我其实并没有这个方向的想法和立场。是我玻璃心了？不过，想了一下对我也没什么实质影响，也就没想那么多了，可能这就是现在互联网冲浪的常态吧

倒是这让我后背一凉，但凡我这个文章没有对他们有帮助就完蛋了，言论很大程度会被带偏翻车的

之前和专门做新浪微博自媒体的朋友聊过，她说很多人为了博流量造对立，让普通用户在评论区吵架然后博主直接给账号带权重 😅

我个人觉得，这种东西意味着：**有很多小心思要谨慎地表达，因为这会被互联网这种增益器无限放大，这种流量肯定是一玩就火的（有对立有评论有热度也就有了推荐），反噬也是肯定的**

## 能尝试做点什么吗？有什么经验

可以尝试一下，但是要缕清楚目标用户，要缕清楚方向保持一致性，最重要的是要行动起来。

- **多尝试多发。**本来这个抢票方法我 9 月 20 日 就实践了，当时就寻思要不要发一下，效果还很好其实想帮朋友抢一下，但是好像大家不感兴趣，犹豫了一下搞然后没发，昨天实在无聊发了一下，效果确实超乎想象，勇敢的 XXXXXX（摊手），本来今天下午有个面试我也是紧张到不行也不想写这个总结的，还是想着赶紧记录一下
-**技术是为业务服务的**。如果不能更好地解决问题，似乎再牛的技术也没什么不得了的（尝试麻痹自己 Doge
- **要想清楚目标用户。**举个简单的例子，这种没有技术含量的东西放在搞技术的人面前根本不值得一提，但是对小红书里面天天刷抢票的人来说简直是福音，现在帖子下面还有来还愿的，成就感++
-**要保持内容方向，才会有粘性。** 打造所谓的人设，做一个垂直方向，花心思想一下方向，其他的东西不要涉及，**尤其比较容易引战的内容**
- **行文逻辑需要锻炼下**。本来写完了帖子让 GPT 4 润色了下，结果发现机翻味浓厚，唯一的作用就是加上了一些 emoji 😈，《金字塔原理》还得看完

关于实际落地的内容，要从如何让用户感觉到学到了东西或者能学到东西想一下，不要太犹豫，主要是要赶紧行动，“小步快跑，快速迭代&quot;

另外一些简单经验可以参考我之前做网易云自媒体号的体会[《在云村搬运视频的一年多所感受到的》](https://liaoguoyin.com/post/livebot-netease-music/)

回想起来，网易云之前做了粉丝大概 9k，前阵子还做个微信工具公众号粉丝 9k，bilibili 做视频剪辑挂演唱会直播累计播放量也有几十万

越来越觉得这种东西做起</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/best-practice-for-cpp-function</id>
    <title>通过值传递、引用传递理解C++函数花里胡哨的写法</title>
    <link href="https://liaoguoyin.com/best-practice-for-cpp-function" />
    <updated>2022-06-14T06:29:48.000Z</updated>
    <published>2022-06-14T06:29:48.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">最近在 [CPlusPlus Tutorial](https://cplusplus.com/doc/tutorial/) 上发现一篇很棒的文章，很大程度上帮助我理解了 C++ 函数一堆标识符写法的用意：

```c++
inline string concatenate(const string&amp; a, const string&amp; b)
{
  return a+b;
}
```

C++ 函数参数是值传递还是引用传递？函数声明中给参数加上 &amp; 是什么操作？参数带 const 又是什么意思？inline 关键字又是干嘛的？

本来想提炼一下，发现还是摘抄 [原文](https://cplusplus.com/doc/tutorial/functions/) 然后对段翻译，才能尽可能地原汁原味。（部分意译，水平有限，读不通可以看该段下方的原文。）

## 参数的值传递和引用传递

&gt; Arguments passed by value and by reference

在前面（节选）函数中已经看到，参数总是通过值传递（译者注：数组除外，数组作为参数传递的是数组首地址指针，默认为引用传递）。这意味着，在调用函数时，传递的是调用瞬间各参数的值，这些参数的值被拷贝到函数参数变量中。例如：

&gt; In the functions seen earlier, arguments have always been passed by value. This means that, when calling a function, what is passed to the function are the values of these arguments on the moment of the call, which are copied into the variables represented by the function parameters. For example, take:

```c++
nt x=5, y=3, z;
z = addition(x, y);
```

在这个例子中，函数 addition() 传入了 5 和 3，也就是 x 和 y 值的拷贝。这些值（5 和 3）被用于初始化在函数中定义过的变量。在函数中修改这些变量并不会对函数外部的 x 和 y 变量产生影响，因为 x 和 y 本身并不被传递到函数中，那函数调用那一刻，传递的只是它们值的拷贝。

&gt; In this case, function addition is passed 5 and 3, which are copies of the values of x and y, respectively. These values (5 and 3) are used to initialize the variables set as parameters in the function&apos;s definition, but any modification of these variables within the function has no effect on the values of the variables x and y outside it, because x and y were themselves not passed to the function on the call, but only copies of their values at that moment.

然而，在某些情况下，需要从函数内部访问外部变量。为达成此目的，参数应该通过引用传递而不是值传递。例如，此代码中 duplicate() 函数拷贝了其三个参数的值，导致用作参数的变量实际上在调用中被修改：

&gt; In certain cases, though, it may be useful to access an external variable from within a function. To do that, arguments can be passed by reference, instead of by value. For example, the function duplicate in this code duplicates the value of its three arguments, causing the variables used as arguments to actually be modified by the call:

```c++
// passing parameters by r</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/loving-pic-1</id>
    <title>一点喜欢的摄影集</title>
    <link href="https://liaoguoyin.com/loving-pic-1" />
    <updated>2021-12-07T19:38:38.000Z</updated>
    <published>2021-12-07T19:38:38.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
&lt;!-- more --&gt;

![](https://cdn.liaoguoyin.com/images/loving-pic-1_1.jpg) ![](https://cdn.liaoguoyin.com/images/loving-pic-1_2.jpg)
![](https://cdn.liaoguoyin.com/images/loving-pic-1_3.jpg) ![](https://cdn.liaoguoyin.com/images/loving-pic-1_4.jpg)
![](https://cdn.liaoguoyin.com/images/loving-pic-1_5.jpg) ![](https://cdn.liaoguoyin.com/images/loving-pic-1_6.jpg)
![](https://cdn.liaoguoyin.com/images/loving-pic-1_7.jpg) ![](https://cdn.liaoguoyin.com/images/loving-pic-1_8.jpg)
![](https://cdn.liaoguoyin.com/images/loving-pic-1_9.jpg) ![](https://cdn.liaoguoyin.com/images/loving-pic-1_10.jpg)
</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/lntuhelper-ios-app-release</id>
    <title>「辽工大助手 iOS 客户端」公测版发布</title>
    <link href="https://liaoguoyin.com/lntuhelper-ios-app-release" />
    <updated>2020-12-10T16:10:22.000Z</updated>
    <published>2020-12-10T16:10:22.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
LNTUHelper 是辽工大学子的在校助手，App 集教务、素拓、图书馆数据查询功能为一体，简洁易用。

&lt;!-- more --&gt;

经过一段时间的努力，现已具备了绝大部分核心功能，不过 App 里有不少臭虫，UI 完全停留在原声控件阶段，难免有一些反人类的交互，这些是需要时间来打磨的。

为了让每一次的更新更有意义和重点，现发布公测版进行内测。

作为内测用户，你可以第一时间体验到一些实验功能（翻译：不稳定），期待你能把最直观的感受第一时间反馈给开发者（也就是俺），这将为 App 注入独特的新鲜活力。

## 公测对象

1. 辽工大在校朋友（拥有教务在线 ID）
2. iOS 用户(iPhone\iPad)，且系统满足 iOS 13+，iPadOS 13+

## 获取公测版

1. 通过 TestFlight 安装 https://testflight.apple.com/join/TWG460YJ
2. 为方便后续公测的持续进行，可加 QQ 群：646177319

## 预览

![IMG_1086.JPEG](https://cdn.liaoguoyin.com/images/lntuhelper-ios-app-release_1.jpg)

![IMG_1088.JPEG](https://cdn.liaoguoyin.com/images/lntuhelper-ios-app-release_2.jpg)

![IMG_1089.JPEG](https://cdn.liaoguoyin.com/images/lntuhelper-ios-app-release_3.jpg)
</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/hadoop-fully-distributed-cluster-setup</id>
    <title>Hadoop 完全分布式集群搭建指南</title>
    <link href="https://liaoguoyin.com/hadoop-fully-distributed-cluster-setup" />
    <updated>2020-11-24T19:31:26.000Z</updated>
    <published>2020-11-24T19:31:26.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
别问，问就是繁琐。

对自己的记忆力不太放心，也算是对近期实践的一个回顾，记录一下完全分布式 Hadoop 生态组件的基本搭建流程。

实质上，集群搭建只是繁琐，你只要熟悉一些基本的 Linux 命令，再简单理解一下集群架构就能很快上手，再把手翻过来，就会了。

所以严格来说，这应该算是一次 Linux 基本命令训练。

**本文内容包括：**
- 内网组建、免密登录、环境变量配置
- 搭建 Hadoop + MySQL + Hive + Zookeeper

**环境要求：**
- 操作系统：CentOS 7.6
- 读者需具备基本的 Linux 知识
- 了解 Hadoop 基本架构
- 预计阅读时间：15 分钟

## 环境准备

### 软件下载源

**建议使用国内镜像源：**
- [腾讯云 Apache 镜像](https://mirrors.cloud.tencent.com/apache/)
- [阿里云 Apache 镜像](https://mirrors.aliyun.com/apache/)

**国外源（备用）：**
- [Apache 官方软件源](https://archive.apache.org/dist/)

### 所需软件

- [OpenJDK 8](https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz)
- [MySQL Connector/J](https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar)

### 配置约定

**环境变量：**
- 统一写入 `/etc/profile`，对所有用户生效，容错更高

**软件安装路径：**
- 默认安装目录：`/usr/local`

## 准备工作

搭建集群前，为方便集群的启动和文件传递，主要要确保以下配置：
- 内网组建
- 免密登录
- 环境变量

### 组建内网

#### 修改主机名

`hostnamectl set-hostname master`

`hostnamectl set-hostname slave1`

`hostnamectl set-hostname slave2`

#### 编辑内网别名

为了方便集群间通信，设置了主机别名

查询内网 IP `ifconfig`

```
cat &gt; ~/etc/hosts &lt;&lt; EOF
10.104.0.1 master
10.104.0.2 slave1
10.104.0.3 slave2
EOF
```

#### 配置免密登录

生成密钥公钥 `ssh-keygen -t rsa`

拷贝公钥到信任授权列表 `ssh-copy-id -i id_rsa.pub master`

#### 配置环境变量

```
cat &gt;&gt; /etc/profile &lt;&lt; EOF

export JAVA_HOME=/usr/local/java-se-8u41-ri
export HADOOP_HOME=/usr/local/hadoop-2.9.2
export ZOOKEEPER_HOME=/usr/local/apache-zookeeper-3.5.8-bin
export HIVE_HOME=/usr/local/apache-hive-2.3.7-bin

export JAVA_BIN=\$JAVA_HOME/bin
export CLASSPATH=.:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar
export HADOOP_CONF_DIR=\$HADOOP_HOME/etc/hadoop

export PATH=\$JAVA_HOME/bin:\$ZOOKEEPER_HOME/bin:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin:\$HIVE_HOME/bin:\$PATH
EOF
```

生效环境变量 `source /etc/profile`

## 1. Java

解压 `tar -zxvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz -C /usr/local`

测试 `java -version`

## 2. Hadoop

`cat &gt; output.log &lt;&lt; EOF` 是 [heredoc 语法](https://stackove</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/ios-swift-corebluetooth-development</id>
    <title>iOS Swift CoreBluetooth 蓝牙开发入门</title>
    <link href="https://liaoguoyin.com/ios-swift-corebluetooth-development" />
    <updated>2020-10-15T11:33:36.000Z</updated>
    <published>2020-10-15T11:33:36.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
基于 iOS CoreBluetooth 框架的蓝牙开发实践，从 BLE 基础到实际开发经验分享。

&lt;!-- more --&gt;

因为一点机缘巧合，看了一下 iOS [CoreBluetooth 文档](https://developer.apple.com/bluetooth/)，做了一个和 [蓝牙交互传数据的 App](https://github.com/LiaoGuoYin/Bluetooth-iOS)

网上关于 iOS Swift 蓝牙开发的资料很少，遇到问题一度非常苦恼，好在最后把一点东西最基本的啃过来了，这里结合自己的一丁点儿开发经验方便以后查阅，也希望能给看到这里的朋友一点帮助。

## CoreBlueTooth 蓝牙基础

低功耗蓝牙 Bluetooth Low Energy (BLE) 指蓝牙 4.0，特色是 **小数据、低功耗**，而在蓝牙4.0 以前是经典蓝牙，[iOS Core Bluetooth 基于 Bluetooth 4.0 协议 ](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/AboutCoreBluetooth/Introduction.html#//apple_ref/doc/uid/TP40013257)，兼容 iPhone 4S+ 的机器。

一些 iOS 蓝牙开发基本概念：

- Central: 中心设备，可以理解为对外扫描蓝牙的设备，一般指本机
- Peripheral: 外围设备，可以理解为蓝牙外部硬件设备
- Services: 服务，可以理解为蓝牙低功耗硬件设备所提供的 **多个功能集合**
- Chracteristics: 特征，一个特征对应了 **一个功能**

Charateristics 的功能一般由以下三种能力组合而成：

1. Read: 读，表示设备为这个特征设置，可以被其他设备读取
2. Write: 写，表示设备可以被写入数据
3. Notify: 订阅/通知，该特诊对应的值可以被其他设备订阅，一旦本机对该值进行修改，就会把修改结果通知给订阅端

一图胜千言，用 `Bluetility` 这个工具能很好的帮助理解蓝牙的基本概念。

![Bluetility-macOS App](https://cdn.liaoguoyin.com/images/ios-swift-corebluetooth-development_1.jpg)

## CoreBlueTooth 蓝牙连接流程

中心设备 C: Central, 外围设备 P: Peripheral

蓝牙连接的主要代码逻辑如下：

1. 创建并开启中心设备 C
2. 开始 **扫描** 广播，寻找外围设备 P
3. 中心设备 C 扫描到外围设备 P 发出的广播后。回调用中心设备 C 的代理方法，来连接外围设备 P
4. **连接** 到外围设备 P 后。回调中心设备 C 的代理方法，来搜寻此外围设备 P 提供的服务
5. 通过 UUID 的比对找到合适的服务后。回调中心设备 C 的代理方法，来搜寻该服务下所有的特征
6. 找到合适的特征后。回调中心设备 C。的代理方法，通过 UUID、特征属性等筛选找到目标特征
7. 找到合适的写、读特征后。**手动调用中心设备 C 的方法对对应的特征进行订阅、写、读**，实现和外部设备 P 的数据收发读功能

## Demo Practice

2019 WWDC 上放出了一个经典蓝牙开发的 [Demo](https://developer.apple.com/documentation/corebluetooth/using_core_bluetooth_classic)，对着代码学习就完事了

1. 新建工程
2. 添加 Info.plist 确保用户能授权蓝牙权限

   iOS 12:  [`NSBluetoothPeripheralUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothperipheralusagedescription)

   iOS 13+: [`NSBluetoothAlwaysUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_l</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/automated-website-cookie-capture</id>
    <title>半自动化获取网站 Cookie 的方法</title>
    <link href="https://liaoguoyin.com/automated-website-cookie-capture" />
    <updated>2020-08-15T00:30:00.000Z</updated>
    <published>2020-08-15T00:30:00.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">

通过 Nginx 配置和 SSL 证书，实现半自动化获取网站 Cookie 的方法。

&lt;!-- more --&gt;

## 配置说明

当需要获取网站的 Cookie 时，特别是一些要求 Secure 标记的 Cookie，可以通过 Nginx 反向代理来实现。

### Nginx 配置示例

```nginx
server {
    listen 443;  # 如果微博Cookie要求Secure，需改为443并配置SSL
    server_name coin.weibo.cn;

    ssl_certificate /opt/homebrew/etc/nginx/ssl/coin.weibo.cn.crt;      # 证书路径
    ssl_certificate_key /opt/homebrew/etc/nginx/ssl/coin.weibo.cn.key;  # 私钥路径

    location /get_cookie {
        add_header x-self-cookie $http_cookie;  # 捕获请求中的Cookie
        return 200 &quot;Cookie captured successfully&quot;;
    }

    location / {
        root /Users/leocoin/html;  # 静态文件目录
        index index.html;    # 默认页面
    }
}
```



## nginx

Docroot is: /opt/homebrew/var/www

The default port has been set in /opt/homebrew/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.

nginx will load all files in /opt/homebrew/etc/nginx/servers/.

To start nginx now and restart at login:
  brew services start nginx
Or, if you don&apos;t want/need a background service you can just run:
  /opt/homebrew/opt/nginx/bin/nginx -g daemon\ off\;
</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/livebot-netease-music</id>
    <title>在云村搬运视频的一年多所感受到的</title>
    <link href="https://liaoguoyin.com/livebot-netease-music" />
    <updated>2020-01-02T19:45:38.000Z</updated>
    <published>2020-01-02T19:45:38.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
运营自媒体号的一丁儿点体会和展望

首先几张图回（xuan）顾（yao）下总数据：

![metamorphosis](https://cdn.liaoguoyin.com/images/livebot-netease-music_1.jpg)

几个比较有代表性的视频：

![最多播放量：内容比较能引起共鸣](https://cdn.liaoguoyin.com/images/livebot-netease-music_2.jpg)

![最高原创混剪：没技术含量，当时歌火而且原视频质量高](https://cdn.liaoguoyin.com/images/livebot-netease-music_3.jpg)

![标题党时期典范：回头看经常要恶心到自己](https://cdn.liaoguoyin.com/images/livebot-netease-music_4.jpg)

[链接 1: 幸运女孩给一个街边音乐家一个硬币之后，得到了最惊讶的回报...][1]
[链接 2:《你就不要想起我》翻唱合集 听直击灵魂 撕心裂肺的感觉][2]
[链接 3: 男生宿舍《说散就散》原以为是搞笑的，看完直接跪拜了][3]

虽然知道死粉占了绝大多数，但是看到粉丝一路涨到 8888 的心情还是点波动的（死粉估计 8500，现实朋友再有几十个，可能剩下的几百个也也是在掉粉边缘挣扎）

回过头来看这一路，但凡是了解点基础的内容运营常识，也不至于花了这么久的时间来涨一堆死粉，好在最后还有一丁点儿点感受和收获，记录总结一下。

---

这一切想法的源头，是在 2018 年 1 月份一个下午，[刷动态发现一个意思的视频](https://music.163.com/#/video?id=468B5610BE610FA00F1967E1AAA0DC69&amp;userid=410592593)，当时脑子一热。于是操着 Adobe Premiere 给视频加了个 BGM 传到了网易云和哔哩哔哩 (@[秋名山音乐台][4]) 上。当时在网易云上被 @音乐小纸条儿 转发了一下于是有了点曝光。至此，搬运的想法就这么埋了个芽儿。

于是问了一下音乐小纸条儿大哥相关的入行建议，当时收获了几点忠告：

- 现在做自媒体很难
- 要知道自己要搬运的大类型是什么（受众群体要固定？
- 标题非常重要

![Chat With MusicPaper](https://cdn.liaoguoyin.com/images/livebot-netease-music_5.jpg)

回想起来其实当时的动机有俩点：

- 当时比较陶醉那种涨粉的快感
- 能分（存）享（储）喜欢的视频到一个干净清爽的平台上（变了:X)，而且视频被加上的 logo 还不是那么很丑，还比较有意思

不过也没把忠告放在心上就开始瞎搞了，绞尽脑汁想到 ID：“秋名山音悦台”，整了个绿得发慌的绿头像。当时是觉得 “秋名山” 好被记住，绿绿的头像（？ 也不知道当时在想什么），应该也能在别人刷到动态的时候眼前一绿？

![雾仁-绿头](https://cdn.liaoguoyin.com/images/livebot-netease-music_6.png)

也就是因为前期搬运的边界很模糊，找不到固定合适的风格，所以动态一堆乱。我一度找不到自己要干什么，搬运视频？ 剪辑合集？ 视频配肥猪流音乐？（没有 🤣

后来才意识到，分享这件事，是一对多。内容应该是要有特别的受众群体的：我可以专注于不同的音乐类型，歌曲类型，乐器类型等等等... 但是当时不懂，结果就是一盘乱麻胡乱操作。潜在粉丝可能通过动态推荐的视频点开了我的主页，刷了几条动态缓缓地滑出一个？ 他猜不到我的动态下次会分享一个什么乱七八糟的东西，自然也就没有 follow 的欲望

然而，这些简单的不能再简单的运营知识，在第一年我全然无感。只是埋头研究其他自媒体一天天发几次动态，发的什么样的东西。不过，慢慢研究别人发视频的套路，也算是有点收获的。然后我摸到了一个 tips：做个标题党

实践发现，同一个视频，简单地描述这个视频的基本信息，效果远比不上那种很有套路的特色标题。尝试尝到甜头之后，我甚至尝试着精通一下：如何成为一个合格的标题党。甚至费劲心思找到了这种玩意儿:

![the-art-of-title-party](https://cdn.liaoguoyin.com/images/livebot-netease-music_7.jpg)

实战之后的效果还行，但也不是没有缺点：回头看视频的时候，会被做作的标题瘆得慌。因为这样搬运不舒服，连自己都不想回过头去点开视频，于是作罢。再然后到了现在，我对合格标题的理解还是发生了变化：**首先是内容的概</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/pic-2019</id>
    <title>2019 年度相册集</title>
    <link href="https://liaoguoyin.com/pic-2019" />
    <updated>2019-12-30T19:46:54.000Z</updated>
    <published>2019-12-30T19:46:54.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
用照片回忆 2019

&lt;!-- more --&gt;

# 在学校:

![海边小楼梯](https://cdn.liaoguoyin.com/images/pic-2019_1.jpg) ![路标](https://cdn.liaoguoyin.com/images/pic-2019_2.jpg)

![火龙果房子](https://cdn.liaoguoyin.com/images/pic-2019_3.jpg) ![小圆桌和房子](https://cdn.liaoguoyin.com/images/pic-2019_4.jpg)

![海边](https://cdn.liaoguoyin.com/images/pic-2019_5.jpg) ![海边 2](https://cdn.liaoguoyin.com/images/pic-2019_6.jpg)

![鸟](https://cdn.liaoguoyin.com/images/pic-2019_7.jpg) ![月亮](https://cdn.liaoguoyin.com/images/pic-2019_8.jpg)

![寝室外](https://cdn.liaoguoyin.com/images/pic-2019_9.jpg)

![一个变倆](https://cdn.liaoguoyin.com/images/pic-2019_10.jpg)

![影子](https://cdn.liaoguoyin.com/images/pic-2019_11.jpg) ![寝室](https://cdn.liaoguoyin.com/images/pic-2019_12.jpg)

![食堂影子](https://cdn.liaoguoyin.com/images/pic-2019_13.jpg) ![昆仑路](https://cdn.liaoguoyin.com/images/pic-2019_14.jpg)

![3D Touch](https://cdn.liaoguoyin.com/images/pic-2019_15.jpg) ![大风车](https://cdn.liaoguoyin.com/images/pic-2019_16.jpg)

# 在路上：

![天津教堂外](https://cdn.liaoguoyin.com/images/pic-2019_17.jpg) ![沈阳教堂窗内](https://cdn.liaoguoyin.com/images/pic-2019_18.jpg)

![沈阳天桥](https://cdn.liaoguoyin.com/images/pic-2019_19.jpg) ![沈阳故宫](https://cdn.liaoguoyin.com/images/pic-2019_20.jpg)

![沈阳教堂外](https://cdn.liaoguoyin.com/images/pic-2019_21.jpg) ![家通勤路牌](https://cdn.liaoguoyin.com/images/pic-2019_22.jpg)

![家里也要通勤](https://cdn.liaoguoyin.com/images/pic-2019_23.jpg) ![家那边的大厦](https://cdn.liaoguoyin.com/images/pic-2019_24.jpg)

# 在日本:

(也是在 2019，但是这趟旅程满意的照片有点多就特别拿出来了 233

![temple1](https://cdn.liaoguoyin.com/images/pic-2019_25.jpg) ![temple2](https://cdn.liaoguoyin.com/images/pic-2019_26.jpg)

![Subway1](https://cdn.liaoguoyin.com/images/pic-2019_27.jpg) ![Subway2](https://cdn.liaoguoyin.com/images/pic-2019_28.jpg)

![Subway3](https://cdn.liaoguoyin.com/images/pic-2019_29.jpg) ![Subway4](https://cdn.liaoguoyin.com/images/pic-2019_30.jpg)

![Subway5](https://cdn.liaoguoyin.com/images/pic-2019_31.jpg)  ![Subway6](https://cdn.liaoguoyin.com/images/pic-201</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/fake-enshi-app</id>
    <title>浅层逆向恩施人才App，并实现自动签到脚本</title>
    <link href="https://liaoguoyin.com/fake-enshi-app" />
    <updated>2019-07-23T19:48:04.000Z</updated>
    <published>2019-07-23T19:48:04.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
在 App Store，“恩施人才” 评分 1.3，算得上是目前为止我见过最 “有口碑“ 的应用，唯一拉高平均分的五分也在夸 “程序猿编程像cxk”，有多烂就不喷了，看图 🤣

![enshi-app](https://cdn.liaoguoyin.com/images/fake-enshi-app_1.jpg)

~~位置签到每天要在规定时间打卡，要想不在公司还光明正大的摸鱼。~~ 首先会想到虚拟定位（iOS 哭），但是每天要点开俩次 App 打卡，显然不够优雅。

换个思路，我们可以伪造签到 HTTP 请求发包，每天按时执行脚本自动签到，解放双手。

&gt; 懒得看中间的瓜皮分析过程，可以直接滑到最下面看应用部分

## 抓包

常见的逆向办法分为两种：

1. 静态分析法 是在不执行应用的情形下，对应用进行静态分析的一种方法。比如获取应用的文件系统结构，本地文件的分析、反汇编分析代码逻辑。
2. 动态分析法 是在应用的执行过程中进行动态分析的一种方法，通过调试分析内存状态，观察应用的文件、网络，分析应用的内部结构与原理。甚至可以用工具动态修改内存，给内存打补丁。

一般来说，两种办法需要结合使用，但是在本次尝试中发现，外包程序猿让一切变得简单起来。

`Thor`（iOS 上非常好使的抓包工具），启动！

走一遍流程之后，筛选 POST 请求，我们可以得出下面的接口：

![capture-apis](https://cdn.liaoguoyin.com/images/fake-enshi-app_2.jpg)

接下来详细看看

&gt; （拒绝查水表，下面的 HTTP请求 都已经作二次处理，同时选择性地省略了无关字段

### 登陆接口

首先现入眼帘的 URI 是 `/studentLogin.do`，很显然是登陆请求，Requests 长这样

```
POST http://119.96.243.148:90/studentLogin.do HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Referer: http://119.96.243.148:90/pages/esrc2019071902/mobile/ioslogin.html
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) 

usercode=15172215000&amp;userpass=testmima&amp;pushcid=dbba2782f2ed1bb7f3b0a37d5a80a82c
```

经过多次登陆发现 Reqeust Body 中第三个参数 `pushcid` 没有过多的实际意义，也就是说 pushcid=null 也是完全可以的。

在 Response Headers 中可以看到字段 `set-cookie : [&quot;JSESSIONID=84202004044C4CE0BAD531C313C5BAE3; Path=/; HttpOnly&quot;]`

首次登陆如果请求头中没有带 Cookie，那么服务器就会在响应请求头中带一个 `Set-Cookie` 字段，浏览器端就在替丁时间内被设置了唯一的身份标识，我们以后的每次域内请求都会带上这个 Cookie 而不是用户名密码。

![set-cookie](https://cdn.liaoguoyin.com/images/fake-enshi-app_3.jpg)

```Response
{
 &quot;msg&quot;: &quot;用户登录成功!&quot;,
 &quot;object&quot;: {
  &quot;user&quot;: {
    ...
   &quot;fjcXzq&quot;:&quot;3&quot;,
   &quot;sdm&quot;: &quot;422802191101011111&quot;,
   &quot;sid&quot;: &quot;c7d0de0ff62245a79657b65a8804d63d&quot;,
   &quot;sjylx&quot;: &quot;实习实训&quot;,
   &quot;sxm&quot;: &quot;姓名咕咕咕&quot;,
  }
 },
 &quot;success&quot;: true
}
```

Response Body 中，中英混沌匈牙利缩写命名法都来了（cxk 程序员干的好事）。同时可以看到姓名身份证和 `sid`，姑且不知道 `sid` 实际意义先放着，另外多次实验发现此字段只与账号有关。

总结一下：**这个登陆接口的使命在于，以用户名密码作为请求体，在响应头中取得 Cookie 供后面应用**

### 查询接口

#### 岗位查询

```Request
POST http://119.96.243.148:90/mobile/internship/list.do HTTP/1.1
Cookie: JSESSI</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/mysql-source-compilation-installation-guide</id>
    <title>编译安装 MySQL 配置跳坑记</title>
    <link href="https://liaoguoyin.com/mysql-source-compilation-installation-guide" />
    <updated>2019-07-07T19:53:38.000Z</updated>
    <published>2019-07-07T19:53:38.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
好好看官方文档
好好看官方文档
好好看官方文档

## 两种发行版

跌跌撞撞看了那么多辣鸡信息流，发现还是 [官方文档](https://dev.mysql.com/doc/refman/5.7/en/installing.html) 上手比较基础规整：

&gt; Several versions of MySQL are available, and most are available in several distribution formats. You can choose from pre-packaged distributions containing binary (precompiled) programs or source code. When in doubt, use a binary distribution. Oracle also provides access to the MySQL source code for those who want to see recent developments and test new code.

Oracle 公司为大多版本提供了两种发行版:

- source code distribution: 源码包，需要自己编译安装
- binary distribution (pre-packaged): 二进制程序安装包，直接安装(pre-compiled)

官方推荐，大多数情况下使用程序安装包 (binary distribution)，并给出几个选择另一种源码包安装的理由。也就是需要自己编译的场景：

- 想自定义安装路径的用户，程序安装包为用户提供了通用路径，因此目录结构可能是散乱的，如果想自定义，则可以编译安装
- 程序安装包中不包含我们想要得 MySQL feature 功能，需自己编译安装
- 程序安装包中包含了多余的部分 feature 功能，我们可能用不上，则可以自己编译
- 想看里面的 C 和 C++ 源代码，自己造轮子，源代码包含了更多的测试样例和示例

既然你都看到这里了，那么体验一把编译安装不需要理由 ：）

区别你所下载发行版的包类型：

&gt; File names for source distributions can be distinguished from those for **precompiled binary distributions in that source distribution names are generic and include no platform name**, whereas binary distribution names include a platform name indicating the type of system for which the distribution is intended (for example, pc-linux-i686 or winx64).

也就是直接通过文件名，未编译的源码包是有没操作系统名的，道理简单到令人发指 :emoji

## 安装

参考了两个手动编译安装配置文档：

- [Installing MySQL from Source](https://dev.mysql.com/doc/refman/5.7/en/source-installation.html) - MySQL 官方安装文档
- [Installing MySQL Server](http://howtolamp.com/lamp/mysql/5.6/installing/) - 非官方文档

### 找到安装包

第一步找 GA(Generally Available)安装包就给我整哭了，没有看文档的我瞎几把找也不知道浪费了多少时间，直到打开了文档：

&gt; Let us goto [http://dev.mysql.com/downloads/](http://dev.mysql.com/downloads/). On the top of page, click on the **Downloads tab**, which will take us to the download page listing different MySQL projects. Below MySQL Community Server, click on the **DOWNLOAD link**, which will take us to the download page. We will see a list of **Generally Available </content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/android-root</id>
    <title>玩转Android刷机Root</title>
    <link href="https://liaoguoyin.com/android-root" />
    <updated>2019-05-10T19:50:48.000Z</updated>
    <published>2019-05-10T19:50:48.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
9102 年了，一键 Root 已经成为回忆

&lt;!-- more --&gt;

关于 Root，以 CS某N 的带头大哥改个标题，复制粘贴就上的教程一抓一把，没成体系，乱得简直了。踩了点坑，所以，整合梳理了一下 XD

看完这篇 Blog，你应该能对刷机的常见联机模式（Recovery、Fastboot、Android 系统模式）有了解、对 Root 原理 有自己的理解、对 Root 的整体流程能有点感觉

本文分享的是通用刷机原理，各机型具体的刷机操作指南详见专门的帖子，此处无法赘述，另外诸如 ** 高通 9008 线刷 ** 之类的特技不在讨论范围，不会介绍某刷机助手、某线刷机宝 的使用，全部使用 adb 工具箱

文中具体的操作较少，主要堆了点基本概念

# 为什么刷机

你可以：在手机上自定义 ROM、Root 软件、自定义 Revocery、Xposed 框架、修改设备地址、系统字体、卸载预装 Apps..

总之，刷机之后，就可以光明正大的搞机了

# 刷机分类

从内容上可分为两类：

- 刷 ROM：重装一套系统
- 刷补丁：在原系统的基础上，拓展某些功能（获取 Root 权限、刷内核、安装 Xposed 框架、安装 Magisk 框架、安装谷歌服务等等）

```
关于 ROM iamge:
- ROM 是 ROM image（只读内存镜像）的简称，常用于手机定制系统玩家的圈子中。 一般手机刷机的过程，就是将只读内存镜像（ROM image）写入只读内存（ROM）的过程。 
- 常见的 ROM image 有 img、zip 等格式。前者通常用 fastboot 程序通过数据线刷入（线刷）；后者通常用 recovery 模式从 sd 刷入（卡刷），固 img 镜像也被称为线刷包，zip 镜像也被称为卡刷包。
- ROM 分三种：作业系统开发者的原生版本、手机制造商、其他人或团队所开发。
(依次：Google 开发的原生 Android One、小米的 MIUI 接口、Android 的 Lineage OS 团队）
- 固件一般是官方原厂包的叫法，ROM 一般是第三方刷机包的叫法。
```

![ROM kinds - Kim 工房](https://cdn.liaoguoyin.com/images/android-root_1.jpg)

## 刷机方式

卡刷：平时的手机系统升级，就是卡刷的一种。手机进入 Recovery 模式写入固件压缩包来更新、升级；或是直接进行 OTA 更新。

&gt; 卡刷本质是 **对系统文件替换的过程**，不会重新刷写整个分区，只是替换部分系统分区文件实现软件版本升级、更换第三方操作系统。即 ROM 包，它一定是一个 zip 压缩文件，打开卡刷包后里面一般都会有 system 和 META-INF 、boot.img (内核) 等文件与文件夹。

线刷：手机连接电脑，用 Android 调试桥接器 (ADB) 直接将 固件、系统底层、驱动程序 等等写入手机，如 Fastboot 模式。

&gt; 线刷是通过数据线连接电脑来进行刷机、系统底包。是手机生产厂商的一种升级方式，针对智能手机系统问题或非硬件损坏的手机故障来刷写固件，** 替换和覆盖各个分区 ** ，使手机功能恢复正常。一般是 tg 压缩文件，里面是一大堆 img 文件，某些底包里也有文件夹。

一句话总结下：**卡刷可以进行简单的刷机和系统更新等操作，线刷则可以进行更深度、更敏感的操作。 线刷彻底，卡刷方便**

# 刷机、Root 流程概述

通用 Root 流程是：`解锁 BL - 刷 REC - 线刷或卡刷刷入 SuperSU 或 Magisk`

详细一点就是：

1. 解锁 **Bootloader**
2. 用手机数据线连接手机按组合键进入 `Fastboot 模式`，使用 `adb` 命令行下刷入 第三方 Recovery：**TWRP**
3. 卡刷：按组合键进入 `Recovery 模式（TWRP）`，刷入 **SuperSU.zip** 或 **Magisk.zip** 获得 Root 权限，或者刷入 **ROM 包.zip** 重装手机系统
4. 或线刷：数据线连接手机、电脑，按组合键进入 `Recovery 模式（TWRP）`，在高级选项里开启 sideload 模式，在电脑上 cmd `adb sideload *.zip` 相比较优点是：不需要把包传到手机内存中）

# 刷机、Root 细节

## 解锁 BootLoader

一般来说，对绝大多数手机而言。解除 BL 锁，一定是第一步。

解锁 BL 的具体步骤，各机型五花八门：

- 有些需要向官网申请解锁权限并用专用工具解锁（华为、小米）</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/fake-aipao</id>
    <title>阳光体育长跑 APP 模拟技术探究</title>
    <link href="https://liaoguoyin.com/fake-aipao" />
    <updated>2019-05-10T11:49:19.000Z</updated>
    <published>2019-05-10T11:49:19.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
探究阳光体育长跑 APP 的模拟技术实现，包括 GPS 位置模拟和运动数据伪造的各种方法。

&lt;!-- more --&gt;

上次写下 [玩转 Android 刷机 Root](https://liaoguoyin.com/post/fake-xxt/) 收益颇多。其中最最重要的是认识了 哲 ♂ 学导师 czp，同时，给自己挖了坑 `阳光体育长跑`

关于这个阳光体育长跑，除了骑自行车、滑轮滑、踩滑板，应该还有几个打开（偷懒）姿势

# 模拟运动

一般来说，长跑 App 都调用本机 `GPS定位` 来实现运动记录（还有种是传感器定位，但较少 本文不讨论）。那么我们只要让手机 `GPS信号` 模拟动起来，问题就解决了。

关于模拟运动，介绍俩款 App：`Daniu`、`Fake Location`

这应该是现在市面上最广泛的所谓一块钱垃圾代跑的解决思路，唯一的麻烦的是 Root 后才能奔放:@(不出所料)

模拟定位和运动的操作简单，摸摸 App 就会，只是个思路，就贴不所谓的教程了。

关于 Root 刷机，可以参考这篇：[扒开 Android 刷机 Root 的衣服](https://liaoguoyin.typlog.io/2019/android-root)

## App 虚拟定位

### Daniu

[Daniu1.1.8.apk][3] 之前的版本免费。虽然免费版在这里共享出来了，还是建议支持作者吧，不贵。

![Daniu root 之后，开启新世界](https://cdn.liaoguoyin.com/images/fake-aipao_1.png) ![Fake Location 付费版](https://cdn.liaoguoyin.com/images/fake-aipao_2.png)

### Fake Location

[Fake Location.apk][5] 比于 Daniu **有步频模拟**。更重要的是，不用 Root 就能模拟运动（但是对某些 App 模拟不上，应该是权限问题， Root 就能完美解决），没有白嫖版，请支持作者。

（XJU西交体育是创高的产品，亲测 Daniu 模拟定位失败。但 Fake Location 不 Root 模式模拟定位，过阳光体育

### 安卓模拟器

Apple boy 苦于没有 Root 的安卓机。想过 Root 安卓模拟器，按网上的办法弄 n 次都失败，就丢坑。

不过，用安卓模拟器刷长步，也不是没有办法。

夜神模拟器有个自带的模拟位置，没有模拟扫街。那么我们就小范围地 连续切换 **模拟位置** 点，GPS 同样变化。

只要位置变化不太大，就有了运动的效果，同时在这里结合模拟器的摇一摇，甚至能模拟出步频出来。

这个操作效率不高，但是非常有意思，同时操作的时候需要把握点之间合适的距离，就能模拟运动和抖动。@自救默示录 [给出了比较硬核的推导（其实就是地球上经纬度算直线距离，只是我地理和数学都要丢了反三角都看不懂了，那就硬核把。）](https://www.cnblogs.com/delicious-hys/p/10611401.html)

## My Android Tools Hook 本地数据库

本方法需要 Root。[My Android Tools.apk][7] 又称写轮眼，它能管理 Android 的四大基本组件。说句人话，能实时修改 App 里各项本地数据数据库。

大致原理是：这个写轮眼，能修改你跑了多少 km，跑了多少 s。修改完之后再打开阳光体育，App 能自动检测到变化后的数据，然后触发上传，直接上传了修改后的记录。

坦白说这个也是楼上的 @自救默示录 的思路，[这里有个比较详细的操作教程](https://www.bilibili.com/video/av47968737)

# 其他问题

## 步频问题

通用的记步原理和手机传感器的加速度有关，你会发现你要是骑车刷长跑的话，步数会为 0。

要想在上传成绩中，拥有步数。有软办法和物理办法：

- 软办法：
  - 在安卓模拟器中，可以用摇一摇摇出步数来
  - 在付费版 Fake Location（Root模式） 中模拟步频
- 物理办法：
  - 当然是一直甩手一直摇摇摇
  - 摇步器

![Shaking](https://cdn.liaoguoyin.com/images/fake-aipao_3.png) ![Shaking2](https://cdn.liaoguoyin.com/images/fake-aipao_4.png)

## 多开问题

[多开分身.apk][9] 一台手机上能登陆多个微信，就不用每天换着登陆微信再验证阳</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/article-typography-standards</id>
    <title>初窥文章排版规范</title>
    <link href="https://liaoguoyin.com/article-typography-standards" />
    <updated>2019-04-05T19:52:12.000Z</updated>
    <published>2019-04-05T19:52:12.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
强迫症患者接触了一些代码规范，现在又来研究文章排版了。

# 标题的确定

- 标题不要过长，导致缩行
- 标题要引人入胜、朗朗上口（至少自己读起来要流畅），不使用&quot;的&quot;、&quot;了&quot;
- 尽量利用标题显示内容性质
- 可以使用有限的标点，如冒号、引号、问号
  - 尽量避免使用逗号
  - 如语气上确需停顿，可以在文字间使用空格

# 数字的使用

基本约定：数字全部使用 **半角** 输入

&gt; “2009 年” 不应写成 “２００９年”

## 一位数字

- 十以下、以及在强调数目的时候必须使用阿拉伯数字

  &gt; “一个梦想” 不应该写成 “1 个梦想”
  &gt;

## 分数

- 分母是从 1 到 10 ，应该写成十分之一、三分之一、五分之一
- 分母是 11 及以上，应该写成 1/11、2/37，等等

## 年月日时间

- 年数、年龄数是一位数字的用汉字，11 及以上没有限制
- 年月日用阿拉伯数字。

  &gt; 如：2019 年 4 月 6 日
  &gt;
- 时间用阿拉伯数字。

  &gt; 如：6 时 30 分、6 点
  &gt;

## 百分比

- 百分比应用阿拉伯数字和百分号 %，避免过长

# 标点的使用

基本约定：全部使用中文 **全角** 标点符号。

## 人名 / 称号

- 英文歌名不加标点、中文歌名加书名号。

  &gt; 如：最新单曲 Love of my life《命中挚爱》
  &gt;
- 英文乐队不加标点、中文译名加中文双引号。

  &gt; 如：Queen&quot;皇后乐队&quot;
  &gt;

## 引语的标点用法

- 直接引语

  &gt; 他说：“我们在等主管部门的决定。 ”（说字后用冒号、句号在引号里）
  &gt;
- 间接引语

  &gt; 他说，俱乐部出现一些不稳定 “也很正常”。（句号在引号外）
  &gt;
- 遇到完整的英文整句、特殊名词，其內容使用半角标点

  &gt; 推荐你阅读《Hackers &amp; Painters: Big Ideas from the Computer Age》，非常的有趣。
  &gt;

## 英文所有格

- 应该写 Tim&apos;s Apple，不应该写 Tim‘s Apple

## 空格的使用

「有研究顯示，打字的時候不喜歡在中文和英文之間加空格的人，感情路都走得很辛苦，有七成的比例會在 34 歲的時候跟自己不愛的人結婚，而其餘三成的人最後只能把遺產留給自己的貓。畢竟愛情跟書寫都需要適時地留白。」—— [vinta/paranoid-auto-spacing](https://github.com/vinta/paranoid-auto-spacing)

- 中英文之间需要增加空格

  &gt; 在 LeanCloud 上，数据存储是围绕 AVObject 进行的。
  &gt;
- 中文数字之间需要增加空格

  &gt; 今天出去买菜花了 5000 元。
  &gt;
- 全角标点与其他字符之间不加空格

  &gt; 刚刚买了一部 iPhone，好开心！
  &gt;
- 加入链接时增加空格

  &gt; 请 [点击这里](https://liaoguoyin.com/feed) 进行订阅！
  &gt;

# App 还是 app

首先需要明确的一点是，永远不会有 APP 这种表述方法。App 是英文单词 Application 的简写，应该读作 [æp]，而非 APP。

以下为使用 App 的情况：

- 用于标题时必须使用 App
- 用于强调或者总结性句子时用于 **标题** 或者正文内容指定 **某一特定** App 时
- App Store 等 **特定词汇** 必须使用 App

以下为使用 app 的情况：

- 用于正文内容 **泛指** 某些或某类 app 时
- 用于英文正文内容表示 **复数** 时用 app

# Recap

标点全部全角，数字全部半角

中文数字、中文英文之间需要加空格

找资料的过程中发现，无论什么行业、什么国家、什么地域，没有统一的排版标准，现阶段 Github 上 Star 最多的排版指南也就才 5.3k，换句话说：没有统一的标准。其实这种东西涉及到 **个性问题**，随心所欲就好了

其实最重要的：**心里面有一套自己的标准，就不容易乱来了**

# One More Thing

为了把强迫症实践到底, 这里推荐几个显著提升冲浪体验的工具:

一个用于阅读, 一个用于创作, 常规的使用应该是很够了

[自动为中英文之间添加一个空格](https://greasyfork.org/en/scripts/37950-%E7%A9%BA%E6%A0%BC%E4%B9%8B%E7%8E%8B-%E8%87%AA%E5%8A%A8%E4%B8%BA%E4%B8%AD%E8%8B</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/clean-code-standards-introduction</id>
    <title>初窥代码规范</title>
    <link href="https://liaoguoyin.com/clean-code-standards-introduction" />
    <updated>2019-02-16T19:54:24.000Z</updated>
    <published>2019-02-16T19:54:24.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
在 [@czp](https://www.hiczp.com) 脆猪皮老哥 issues 的字里行间，恍然认识到编码规范的重要性

&gt; 适当的规范和标准绝不是消灭代码内容的创造性、优雅性，而是限制过度个性化，以一种普遍认可的统一方式一起做事，提升协作效率，降低沟通成本。

读了 Clean Code 和文章尾部的一些相关文章，摘成此篇，后续会不断补充..

## 命名格式

- 匈牙利命名法(Hungarian): 变量类型缩写 + 名称英文 `char cMyName`
- 下划线命名法(UnderScoreCase): `student_id`
- 驼峰命名法(CamelCase \ PascalCase):
  - 小驼峰命名法：除了第一个单词，其他字母都大写 `myStuentId`
  - 大驼峰命名法（帕斯卡命名）: 所有单词首字母大写 `MyStudentId`

## 命名风格

命名规则尽量与所采用的操作系统或开发工具的风格保持一致:

- Windows 应用程序的标识符通常采用 “大小写” 混排的方式，如 AddChild
- Unix 应用程序的标识符通常采用 “小写加下划线” 的方式，如 add_child  别把这两类风格混在一起用

## 命名原则

- 代码命名不能以 下划线开头 或 美元符结尾.
- 代码命名避免纯拼音命名，严禁使用英文和中文拼音混合命名，更严禁直接中文命名
- 类名使用大驼峰命名法 TodayPromotion
- 方法名、变量名、参数使用小驼峰命名法 todayPromotion
- 常量命名全部大写，下划线分隔开，不用担心名字长.
- 抽象类命名以 Abstract 或 Base 开头，异常类以 Exception 结尾，测试类以 Test 结尾，枚举类以 Enumm 结尾
- 常量定义: long 或 Long 定义赋值时，用大写的 L 结尾避免歧义，即格式为: 2L
- 尽量 IDE 自动命名，例如输入 Scanner s , 再回车，好处是：变量名本身就表示了变量类型，它适用于这个变量没有其他含义，且全局只有它、用完即丢的变量，不需要为他起名.

## 代码格式

- 大括号的使用：如果大括号为空，则简介的写为 {}，不需要换行；如果非空:
  - 左大括号前不换行
  - 左大括号后换行
  - 右大括号前换行
  - 右大括号后还有 else 等代码则不换行；表示终止的右大括号后必须换行
- 左小括号与字符没有空格，右小括号与字符没有空格，反例: if(空格 a == b 空格)
- if/for/while/switch/do 等保留字和括号之间必须加空格: if(i == 0)
- 任何二目、三目运算符的左右俩边必须加空格: i = 5;
- 注释的双斜线和注释之间有且只有一个空格，注释写在类名和方法前. // 注释 1
- `+ - * / %` 等运算符号左右各要有一个空格.
- 方法参数在定义和传入时，在参数和逗号之后都有一个空格: Method(arg1, arg2, arg3);
- 不同逻辑、不同语义、不同业务的代码之间一行空格来提高可读性.

# Apple 模仿规范

iOS 开发不规范，满脑子雾水，苹果 SDK 中很多规范值得借鉴，规范就能解决这个问题，Class，var，let，function 命名: Camel case 命名：每个单词大写开头，第一个单词例外。（类首字母大写)

## 命名名称

- 自定义的类别继承自父类时，类别名称以父类名称结尾: customViewController
- UI 元件，变量名和类有关: questLabel
- Array 对象名加复数: var categories: [String]
- Controller 的视图生命周期调度中，会有设定画面内容的函数，自定义 function 可以 update 开头: updateUI(){}
- CustomTableViewControllerCell 中，[categories] 存储各种 UI 控件
- TableViewController 中，把文字渲染到 cell 内容的 function，可固定 func configure(cell: UITableViewCell, forItemAt indexPath: IndexPath) { }

## 静态化规范

- App 里有些负责特定功能的物件会在多个页面使用。可将它宣告成只会建立一次的型别常数 取名 shared 或 default，省去每次使用时重新生成的麻烦，并享有任何地方皆可方便存取的好处，就像以下例子的 URLSession.shared，UserDefaults.s</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/czp-coroutine-programming-tutorial</id>
    <title>猪皮课堂-czp 讲协程</title>
    <link href="https://liaoguoyin.com/czp-coroutine-programming-tutorial" />
    <updated>2019-02-12T19:35:20.000Z</updated>
    <published>2019-02-12T19:35:20.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
&gt; czp：每隔几个月来温习一遍，你就精通了

在冯诺伊曼计算机架构中：指令内存和数据内存在同一块主存储器中的，也就是说，程序的代码（机器码）和保存的变量，是在同一块内存条里面的，所以 CPU 的工作就非常简单了。

开机的时候要做的事情非常简单，那就是把程序写入到 0x00 这个地址，然后把 CPU 中的 program counter 写为 0，CPU 就会开始读取 0x00 这个地址上的指令，执行完之后，program counter 会自增，然后开始读取 0x01，你的 CPU 就开始运作了，但是顺序执行是不够的，所以就发明了 jump，这一条特殊的指令可以写入 prgram counter，使 CPU 执行另一个地方的指令，然后从另一个地方开始继续自增下去，由于数据和代码都在一个内存条上，内存地址是唯一的，所以非常方便地实现了各种读取、写入问题。

有些代码经常被执行，为了避免重复编码，发明了 `函数`，实际上函数就是先 jump 到指定位置，再 jump 回来，这叫一次 call（等会再讲），于是现代计算机的理论体系就这样被构建出来，看上去天衣无缝，非常完美，直到有一天，人们在想：

假如我有一个按钮，无论当前程序运行到何处，只要我按下这个按钮，就希望程序特别执行一个操作，怎么办？

方案一是让 CPU 不断的去查询这个按钮有没有被按下（这叫 `轮询`，这种等待方式叫做：自旋锁，自旋锁就导致 CPU 一直被占用，也就是一直查询按钮有没有被按下，实际上 CPU 在一个死循环里占用率持续 100%）这在单片机上可能没什么问题，但是随着程序越来越复杂，这种死循环会影响程序的正常流程，出了等待轮询按钮被按下时，就没办法干别的事情了。

于是发明了 `中断`，中断是一种硬件实现，他可以让一个硬件被激活时被改变 program counter 的值，这种中断改变了程序的流程。在 Unix 中，系统将许多信号封装为中断，这种中断是软件实现的，程序收到 Control+C 之后，会执行自己的函数，而不是关闭。这是通过注册对各种信号的中断函数实现的，中断可以改变程序原有的流程，因此有了一种想法：可不可以在这个时刻，执行程序 a，然后中断，执行程序 b。

对于 CPU 来说，不存在操作系统和应用程序的概念，这些只是代码而已，而中断只是简单地修改了 program counter 的值，系统上运行的程序 a、b 对 CPU 来说没有区别，这个想法是可以实现的。

历史的车轮滚滚滚向前（我倒..），直到有一天，丹尼斯从床上起来，他有了一个惊人的想法：能不能在一台电脑上，和基友一起玩游戏，就是那种：你用 wasd，我用上下左右的游戏。这也就意味着：系统必须同时处理控制 2 个程序，很快，沉迷于电子游戏的丹尼斯将这个想法实现了：它就是 Unix，人类历史上第一个真正多任务多用户操作系统，在这个操作系统上，系统让 CPU 来回执行各个进程，从而看起来像在同时执行多个程序。例如：0-0.01s 执行程序 a，0.01-0.05s 执行程序 b

那一天，人类的历史迎来了新的一页，丹尼斯将 Unix 时间戳设计为 1970 年 1 月 1 日 8:00 为原点，所以古人云，1970 年 1 月 1 日，上帝创世。

这种来回执行不同程序的方案，叫做：分时，这种操作系统，就叫做 `分时操作系统`。很快人们发现，虽然分时可以执行多个程序，但是多个程序之间共享数据非常麻烦，于是就想着，能不能在一个进程里面，有好几个同时执行的单元，于是有了线程的概念。

一个 `进程`，它里面会有好几个 `线程`，所有的线程共享同样的数据内存，这样线程 a 修改了变量 var1，线程 b 就可以取得修改后的值（这里有个线程安全的问题，后面讲），也就是说：在现代操作系统中，代码执行的逻辑是线程，每个线程都是被独立执行的，概念上我们认为他们是同时执行的。

如果一个程序只有 main 函数，那么他就只能有一个 Main Thread，程序必须至少要有一个线程，才能是活动的，否则就是僵尸进程（僵尸进程要涉及到程序的父子关系，后面讲），而这个线程，是操作系统控制的，操作系统会根据一个算法，来为所有线程分配时间片，这看起来天衣无缝，非常完美。直到有一天：互联网被发明了。

很快的，就出现了一件事，对于网络的操作，是非常慢的，在未完成之前，程序会一直卡在对网络的操作上，比如说：访问了 [bilibili.com](http://bilibili.com/) 在这个访问没有返回钱，程序就会一直卡在那一行，例如代码时这样的 val response = GET (&quot;[bilibili.com](http://bilibili.com/)&quot;) 假如网络奇慢无比，这个访问 30s 后才返</content>
  </entry>
  <entry>
    <id>https://liaoguoyin.com/fake-xxt</id>
    <title>轻松刷掉学习通、双创网课的猥琐思路</title>
    <link href="https://liaoguoyin.com/fake-xxt" />
    <updated>2018-11-29T19:55:18.000Z</updated>
    <published>2018-11-29T19:55:18.000Z</published>
    <author>
      <name>coin</name>
    </author>
    <content type="html">
学习通之类的网课，有点让人头疼。好的网课另说，但学校强制让看的大部分都是辣鸡玩意，浪费时间又占设备资源。

不过目前接触的两款学校要求的网课 App：创新创业云平台 和 超星尔雅，也不是没有骚办法的

# 基础

## 安卓端

安装：[Auto.js 学习通脚本](https://www.autojs.org/assets/uploads/files/1541238755343-%E8%B6%85%E6%98%9F%E5%AD%A6%E4%B9%A0%E9%80%9A.js)

原理：是通过 JavaScript 脚本把手动点击模拟为脚本自动点击下一步等一系列操作

感受：高配版的‘按键精灵’，模拟对操作句柄，iOS 似乎也有 JSBOX，可以自己写脚本

&gt; 今天去隔壁寝室 @wqs 简直太骚了（手机内置分屏功能

![Split-Screen](https://cdn.liaoguoyin.com/images/fake-xxt_1.png)

## 电脑端

因为电脑端的限制比较明显、比较多，这样一来可玩性就高多了，我们先捋捋电脑刷网课视频的尿点：

- 播放时鼠标必须悬停在播放器上方，鼠标移出播放器外视频就会自动停止播放.
- 没看过的部分不可以跳转，只有看过一次之后才可以任意跳转进度.
- 课程播放时会插入课程测试题，只有完成测试题之后才能继续观看.

两个基础认识，摘自 @cubicpill:

&gt; 这家网课平台的 Web 端的视频播放器是一个 Flash, 监听用户鼠标事件，一旦用户鼠标移出 Flash 区域或者将浏览器最小化，都将暂停视频直到鼠标重新放上

&gt; 而 Android 客户端就更是精彩绝伦，视频播放的那个 Activity 直接是一个 WebView, 同样是通过 js 来监听切换到后台的事件

![H5-Event](https://cdn.liaoguoyin.com/images/fake-xxt_2.png)

思路：

- 虚拟机加速播放
- 油猴脚本 js 自动化
- Mac 拖 Safari 进度条

### 虚拟机加速播放插件

![fake-xxt-in-virtualvm.jpg](https://cdn.liaoguoyin.com/images/fake-xxt_3.jpg)

胡锅巴在 [公众号 AimTao](https://mp.weixin.qq.com/s/Nb4cegzEUwk5V4NiV70hww) 里写了， Videospeed 浏览器插件加速 + 虚拟机:

&gt; 视频不能拖进度条，那就在客户端快速播放完视频，然后就具体用到了 Videospeed（最快 16 倍速）
&gt; 虚拟机（out 出虚拟机之后，虚拟机鼠标不动）解决了鼠标划出暂停、触发鼠标的监听事件的问题

轮子造得可以用了，但是还能改进，等会说

### 油猴脚本

安装油猴插件，再装 [脚本](https://greasyfork.org/zh-CN/scripts/369625-%E8%B6%85%E6%98%9F%E7%BD%91%E8%AF%BE%E5%8A%A9%E6%89%8B)，不到 40 行 js 代码，实现了三个功能：

- 切换其他页面时超星 mooc 不会暂停
- 播放完一节课自动加载下一节课
- 可以拖动进度条（可能被防作弊系统检测到）

### Mac 拖 Safari 进度条

look-at-touchbar.jpg
![look-at-touchbar.jpg](https://cdn.liaoguoyin.com/images/fake-xxt_4.jpg)

Touch Bar 会显示当前页面的播放进度条，直接就能搞定。（亲测能跳过几乎所有网站广告，去年就是利用这个办法，刷爆了形势与政策，一不小心看视频排名第一

&gt; 当然，首先你要去找一台有触控条的 MacBook（好像也能安插件玩玩

### 改进胡锅巴的思路

用过 Mac 的同学都知道，用 Safari 看视频全屏的话，会自动生成一个桌面分屏，随意切换桌面都能后台播放，这样一来，虚拟机的工序就可以省了 (至于 Videospeed 插件有没有兼容 Safari 就是另外一回事了)

这条路走到底的话，后台播放要知道什么时候去手动下一集？(开声音听不难受的吗)

于是 @xieyi 依据 [视频播放时的 CPU 占用率一定比暂停时高，这一点在 Flash Player 上体现的更明显](https://imxieyi.com/2016/11/28/%E5%88%A9%E7%94%A8%E7%AE%80%E5%8D%95%E7%9A%84powershell%E8%84%9A%E6%9C%AC%E5%AE%9</content>
  </entry>
</feed>