0%

DOM 树是树形结构,且对 DOM 的操作可以在浏览器中看到,那么是否可以借此做对树形结构操作的可视化呢?

今日在写一个用来高亮 DOM 节点中匹配到指定正则的文本的代码时,实现了一个遍历 DOM 节点的函数:

const traverseNode = (node, cb, isChild) => {
  if (node.firstChild) {
    traverseNode(node.firstChild, cb, true);
  }

  cb(node);

  if (isChild && node.nextSibling) {
    traverseNode(node.nextSibling, cb, true);
  }
};

写完之后,我想到一个问题:既然 DOM 树是个树形结构,而且对 DOM 节点样式的修改可以被浏览器反映出来,那么是否可以做出遍历树形结构的可视化呢?

成果:

构建环境

安装 ESP32 工具链

在 Linux 环境开发,需要 xtensa-esp32-elf

安装依赖:

$ yay -S --needed gcc git make ncurses flex bison gperf
$ pip install pyserial

下载安装工具链:

$ wget -P ~/Downloads https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
$ mkdir -p ~/esp
$ cd ~/esp
$ tar -xzf ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

更新环境变量:

# ~/.profile
export PATH="$PATH:$HOME/esp/xtensa-esp32-elf/bin"
阅读全文 »

近日买了个新玩具:NodeMCU 32S,这是一个可玩性极强的 ESP32 开发版。

ESP32 是乐鑫出的提供了 Wi-Fi 与蓝牙功能的 MCU,功能强大,用途广泛,可用于低功耗传感器网络。成本很低,约 15 元。

$ esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 read_mac
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting.....
Chip is ESP32D0WDQ5 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 40:f5:20:79:d9:38
Uploading stub...
Running stub...
Stub running...
MAC: 40:f5:20:79:d9:38
Hard resetting via RTS pin...

近日在玩欧陆风云 4,为了完成成就,所以选择了铁人模式,由于是新手+铁人模式不能自由存档(新存档会覆盖旧存档),容错率较低,故考虑开发一个工具来管理存档,将新的存档备份起来,以便需要时读取。

第一版是使用 Node.js 实现的,通过 setInterval 定时备份存档文件。这种做法有些缺陷:

  • 没有 GUI,每次需要手动在 cmd 下执行
  • 不能监听存档文件的变动,手动保存的存档不一定会被备份
  • 会生成很多重复的文件
  • 不好查看备份操作的记录

于是考虑开发一个 GUI 应用,希望它具有以下能力

  • 跨平台(欧陆风云 4 支持 Windows/Linux/Mac)
  • 能够选择存档目录
  • 能够监听文件变动(做保存操作时能够触发,将新的存档备份)
  • 能够展示备份操作记录
  • 能力强大可扩展(为后续开发提供空间)

综合考虑后,决定使用 Python + PyQt 开发。

阅读全文 »

身边有很多人把 GitHub 的 Issues 用作个人博客,它具有写作方便、免于部署的优点,但是由于需要从仓库的 Issues 访问,定制化程度很低。

GitHub 提供了访问仓库的 Issues 的 API,我们可以自己开发定制前端页面,发布到 GitHub Pages,前端调用 API 读取 Issues 动态渲染页面。这样我们依旧能够在 GitHub 上新建/修改文章,同时不用再去进行发布操作。

简单实现

Github 当前提供了 2 种版本的 API:

它们都能满足我们的需求,但是 REST 版本返回的数据较多,里面有很多我们不需要的内容,所以这里我们选择可定制性更强的 GraphQL 版本。

查询语句的构建可以在 GraphQL API Explorer 进行。

阅读全文 »

做跨域请求时,会需要用到 HTTP 响应头部的 Access-Control-Allow-Origin 属性,但是这个属性只能配置一个域,当一个接口需要被多个域请求时,该如何配置呢?

很简单,动态设置这个值就好,以一个部署在阿里云上的函数为例:

module.exports.handler = function (req, resp, context) {
    const { queries, headers } = req;
    const { origin } = headers;

    if (/\.ihanai\.com/.test(origin)) {
        resp.setHeader('Access-Control-Allow-Origin', origin);
        resp.send('');
    } else {
        resp.setHeader('Access-Control-Allow-Origin', 'https://blog.ihanai.com');
        resp.send('');
    }
}

通常情况,当我们使用 fetch 发送网络请求,并获得 content-typeapplication/json 的 Response 时,我们需要使用 text()json() 得到 body 的 JSON 对象。但是 text()json() 仅支持 UTF-8 编码的 response,若编码为 GBK,则得到的 JSON 对象中会存在乱码。

若想正确解析 GBK 编码的 response,我们可以先将 response 的 body 转换为 Blob 对象,再使用 FileReader.readAsText(blob[, encoding]) 通过正确的 encoding 读取为文本。

(function () {
    const readBlobAsText = (blob, encoding) => {
        return new Promise((resolve, reject) => {
            const fr = new FileReader();
            fr.onload = event => {
                resolve(fr.result);
            };

            fr.onerror = err => {
                reject(err);
            };

            fr.readAsText(blob, encoding);
        });
    };

    fetch("https://api.github.com/users/hanai", {
        "body": null,
        "method": "GET"
    }).then(res => {
        const contentType = res.headers.get('content-type');
        if (contentType !== null) {
            if (/(^|;)application\/json($|;)/i.test(contentType)) {
                const charsetMatches = contentType.match(/(^|;)charset=([^;]+)($|;)/i);
                if (charsetMatches && charsetMatches.length && charsetMatches[2]) {
                    const charset = charsetMatches[2];
                    return res.blob().then(blob => readBlobAsText(blob, charset)).then(JSON.parse);
                } else {
                    return res.json();
                }
            }
        }
    }).then(data => {
        console.log(data);
    });
}());

部分 SSD 无法被 hddtemp 获取到温度信息:

$ sudo hddtemp /dev/sda
WARNING: Drive /dev/sda doesn't seem to have a temperature sensor.
WARNING: This doesn't mean it hasn't got one.
WARNING: If you are sure it has one, please contact me ([email protected]).
WARNING: See --help, --debug and --drivebase options.
/dev/sda: Samsung SSD 860 EVO 500G B              @:  no sensor

安装 smartmontools

$ sudo apt-get install smartmontools
阅读全文 »

从 Oracle 官网下载安装 jdk8

从 IB 官网下载 IB Gateway for Linux

使用二进制模式修改 ibgateway-stable-standalone-linux-x86.sh

$ vim -b ~/ibgateway-stable-standalone-linux-x86.sh

INSTALL4J_JAVA_HOME_OVERRIDE 赋值为安装的 jdk8 的路径

INSTALL4J_JAVA_HOME_OVERRIDE="/opt/jdk1.8.0_191/"

修改 test_jvm() 函数,删除版本检查的逻辑

  if [ "$ver_major" = "" ]; then
    return;
  fi
-  if [ "$ver_major" -lt "1" ]; then
-    return;
-  elif [ "$ver_major" -eq "1" ]; then
-    if [ "$ver_minor" -lt "8" ]; then
-      return;
-    elif [ "$ver_minor" -eq "8" ]; then
-      if [ "$ver_micro" -lt "0" ]; then
-        return;
-      elif [ "$ver_micro" -eq "0" ]; then
-        if [ "$ver_patch" -lt "152" ]; then
-          return;
-        fi
-      fi
-    fi
-  fi
-
-  if [ "$ver_major" = "" ]; then
-    return;
-  fi
-  if [ "$ver_major" -gt "1" ]; then
-    return;
-  elif [ "$ver_major" -eq "1" ]; then
-    if [ "$ver_minor" -gt "8" ]; then
-      return;
-    elif [ "$ver_minor" -eq "8" ]; then
-      if [ "$ver_micro" -gt "0" ]; then
-        return;
-      elif [ "$ver_micro" -eq "0" ]; then
-        if [ "$ver_patch" -gt "152" ]; then
-          return;
-        fi
-      fi
-    fi
-  fi

  app_java_home=$test_dir
}

安装 IB Gateway

$ ./ibgateway-stable-standalone-linux-x86.sh

安装完成后直接执行 IB Gateway 会提示

No suitable Java Virtual Machine could be found on your system.
The version of the JVM must be 1.8.0_152.
Please define INSTALL4J_JAVA_HOME to point to a suitable JVM.

需要使用同样的方式修改 ~/Jts/ibgateway/972/ibgateway