跳转至

2024

连词和复合句

英语中,句子(sentence)通常由好个子句子组成,这叫复合句(compound sentense), 由连词和子语句(Clause)、短语(Phase)、单词(Word)组成。

子句和短语

子句包含完整的主谓, 但短语没有主和谓, 有好多个phase组成。比较长度 Clause > Phase > Word, word很好区别。 短语是不完整的, 而子语句包含了完整的主谓(宾)。

Phrase: Meows so loudly
Clause: That cat meows so loudly

子句当名词

  • She completely understood everything he said. 拆成主谓宾'She understood XXX', 'everything he said' 是宾语XXX, 是一个名词
  • They remembered what the keynote speaker covered. 同上

子句当副词

  • She fixed the sink without facing difficulty. 拆成主谓宾'She fixed XXX'。'without facing difficulty'修饰动词'fix', 是副词
  • The pool was installed after they built the deck. 拆成主谓 'The poll was adj'。 'after they built the deck'是修饰形容词(或was), 是副词

子句当形容词

  • My friend who rides a motorcycle said it’s a great weekend to ride. 拆成主谓宾'XXX said XXX'。 'who rides a motorcycle' 形容词,形容'My Friend'
  • No matter what time of day we visit, we always run into the dog that barks. 同上, 形容'dog'

子句当名词和形容词时,比较好看出子句的主谓(宾), 而当副词

短句是几个单词组成,可以当很多成分

  • She runs every Sunday. 当副词
  • She was taller than all of her classmates. 当形容词
  • My small dog barks at ducks. 名词

连接词

连接词用来连接子句和短语

一致关系

for, and, nor, but, or, yet, so

FANBOYS

配对关系, 搭配用

both/and, either/or, neither/nor, not only/but, whether/or

主从关系

after, although, as, as if, as long as, as much as, as soon as, as though, because, before, by the time, even if, even though, if, in order that, in case, in the event that, lest, now that, once, only, only if, provided that, since, so, supposing, that, than, though, till, unless, until, when, whenever, where, whereas, wherever, whether or not, while

按功能分连接词

表示强调

indeed

表示递进

what's more, furthermore

表示转折

however, but

表示原因结果

because, as a result

yet 相关

yet 一直让我脑子转不过弯, 不知道怎么翻译成中文。例如歌名'Are you bored yet?', 没yet是‘你无聊吗?’。 当有yet时我以为翻译成’你还无聊吗?‘, 而结果翻译成‘你觉得无聊了吗?’

gptchat解释“yet表示提问者预期如此,也就是提问者预期被提问者无聊了。”, 所以正确理解应该是: “你应该无聊了吧?” 显然这里yet是副词,修饰bored。

当副词, 修饰形容词和动词

any yet 但是 nor yet 也不 ; 又不 ; 也没有 but yet 但还是 not yet 还没 why is there yet another problem

当连词, 连接子句和短语

Yet she 而她已经 Yet Moralistic 但注重道德

参考

https://www.grammarly.com/blog/parts-of-speech/conjunctions/ https://www.grammarly.com/blog/sentences/phrases/ https://www.grammarly.com/blog/grammar/clauses/

linux子进程

Linux的exec(3)是一系列函数。之前总是稀里糊涂地用,这次搞清楚了。

       #include <unistd.h>

       extern char **environ;

       int execl(const char *pathname, const char *arg, ...
                       /*, (char *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /*, (char *) NULL */);
       int execle(const char *pathname, const char *arg, ...
                       /*, (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], char *const envp[]);

规律

这6个函数可以分为两组'execl组'和'execv组'。 后缀p表示从$PATH中查找程序, 后缀e表示最后一个参数是数组,里面是环境变量。

验证

这里通过c语言和python调用命令cat hello.txt, 验证每个函数。

#include <unistd.h>

int main(){
  int pid=-1;
  pid=fork();
  if(pid == 0)
  execl("/usr/bin/cat", "cat", "hello-execl.txt", NULL);

  pid=fork();
  if(pid == 0)
  execlp("cat", "cat", "hello-execlp.txt", NULL);

  pid=fork();
  if(pid == 0)
  execle("/usr/bin/cat", "cat", "hello-execle.txt", NULL, (char*[]){NULL});

  pid=fork();
  if(pid == 0)
  execv("/usr/bin/cat",  (char*[]){"cat", "hello-execv.txt", NULL});

  pid=fork();
  if(pid == 0)
  execvp("cat",  (char*[]){"cat", "hello-execvp.txt", NULL});

  pid=fork();
  if(pid == 0)
  execve("/usr/bin/cat",  (char*[]){"cat", "hello-execve.txt", NULL}, (char*[]){NULL});
}
注意当使用选项参数时,选项和参数需要分开成两个字符串。例如grep -n 10 "target" file命令, 调用方法是
execlp("grep", "grep", "-n", "10",  "target", "file", NULL);

使用环境变量,要用sh来拓展ENV1符号

execle("/usr/bin/sh", "sh","-c" ,"echo $ENV1", NULL, (char*[]){"ENV1=HELLO", NULL});

python 的os库的方法更全,且不需要带NULL

>>> [method for method in dir(os) if method.startswith("exec")]
['execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe']

实现cat hello.txt

import os
os.execlp("cat", "cat", "hello.txt")

使用环境变量, 同样要用sh来拓展ENV1符号

import os

env = os.environ.copy()
env["ENV1"]="hello"
os.execlpe("sh", "sh", "-c", "echo $ENV1", env)

实用替代方法

exec族的函数都会替换当前进程的堆栈,所以需要用fork生成新的进程。更方便的方法是在c中用system, python中用subprocess

arduino-cli 使用

esp32中,使用了arduino-cli来编译和上传代码。这里记录下arduino-cli操作arduino nano的方法和问题

编译

说也非常奇怪,Linux的java GUI版本arduino编译提示找不到头文件'SoftwareSerial.h', 这个库是arduino自带的。但是不使用GUI的编译按钮而用GUI的输出中的命令编译又正常。

这是从GUI的IDE的编译上传的输出日志,得到的编译上传命令, 手动执行却正常。

cd ~/Arduino
BUILD_PATH=$(mktemp -d)
arduino-builder -verbose -compile -hardware /usr/share/arduino/hardware -tools /usr/share/arduino/hardware/tools/avr -libraries /
./Arduino/libraries  -build-cache ./arduino_cache -build-path $BUILD_PATH  -fqbn=arduino:avr:uno  -prefs=build.warn_data_percentage=75 ./TestSerial/TestSerial.ino
avrdude -C/etc/avrdude.conf -v -patmega328p -carduino -P/dev/ttyUSB0 -b115200 -D -Uflash:w:${BUILD_PATH}/TestSerial.ino.hex:i 

用arduino-cli编译也正常

arduino-cli compile --fqbn  arduino:avr:nano   TestSerial 

上传失败

但是用arduino-cli编译正常,上传失败,提示

arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyUSB0 TestSerial                                                                                                            
avrdude: error at /etc/avrdude.conf:402: syntax error                                                                                                                                           
avrdude: error reading system wide configuration file "/etc/avrdude.conf"                                                                                                                       
Failed uploading: uploading error: exit status 1   

后来用verbos输出对比GUI版本的命令,发现两个命令用的avrdude不一样。 一个是/usr/bin/avrdude, 一个是$HOME/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude。两个的版本不一样, 而后者使用了前者的配置文件 /etc/avrdude.conf。所以出现syntax error

arduino-cli upload -v  --fqbn arduino:avr:uno --port /dev/ttyUSB0 TestSerial                                                                                                        
"/home/jimery/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude" "-C/etc/avrdude.conf" -v -V -patmega328p -carduino "-P/dev/ttyUSB0" -b115200 -D "-Uflash:w:/home/jimery/.ca
che/arduino/sketches/57AA4FA906132DC236F48CCE34943FA0/TestSerial.ino.hex:i"                                                                                                                     

avrdude: Version 6.3-20190619                                                                                                                                                                   
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/                                                                                                                            
         Copyright (c) 2007-2014 Joerg Wunsch                                                   

         System wide configuration file is "/etc/avrdude.conf"                                                                                                                                  
avrdude: error at /etc/avrdude.conf:402: syntax error                                                                                                                                           
avrdude: error reading system wide configuration file "/etc/avrdude.conf"                                                                                                                       
Failed uploading: uploading error: exit status 1 

最后全部卸载了GUI包括avrdude, 再将$HOME目录的avrdude配置复制到/etc/avrdude.conf, 问题解决了。

玩转ESP32

ESP32的生态比较好,类似arduino, 但是集成了wifi和蓝牙,有的甚至集成了gps,功能很强大而且便宜。最近淘宝买了一个ESP32-USB-Geek, 带一个LCD屏幕和几个扩展接口,还有闪存口可以读写。

esp32-usb-geek.png.png

编译烧录

ESP32 有3种方式: 官方的idf, mpy, arduino。

官方工具

官方的idf分vscode插件和python脚本, vscode中没有成功,不过idf.py可以编译和烧录。

根据官方文档写的下载安装idf,解压后执行脚本。安装脚本依赖python-venv, 而我最常用vituralenv

bash v5.3.1/esp-idf/install.sh

进入淘宝店例子, 用cmake管理的。 在跟目录执行

idf.py set-target esp32-s3

这种方式支持非常复杂的配置

idf.py menuconfig

编译刷入

idf.py build

idf.py -p /dev/ttyACM0 flash

官方的方式最能了解物理设备了。看日志发现他生成了bin文件,并从0位置刷入bin文件。

mpy thonny ide

最好用pip安装最新的。 将python上传到esp后,点运行就可以了,还能在REPL中仿真调试,非常方便。

arduino

arduino ide gui版本编译失败,而且因为是Linux版是用java写的,操作非常慢。改用arduio-cli脚本成功, 官方文档也说了arduino-cli非常强大。这里说脚本使用方法。

初始化配置
  1. 首先下载压缩包,解压到PATH目录下。

  2. 初始化配置, arduino-cli config init 可以生成配置文件'~/.arduino15/arduino-cli.yaml'。

  3. 修改配置文件, 根据淘宝老板说的,ESP32的板子要从另外第三方源中, 因为这个源是githubcontent需要梯子才能访问,修改成如下

$ cat ~/.arduino15/arduino-cli.yaml

board_manager:

additional_urls: ['https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json']



network:

proxy: 'socks5://ip:port'
安装板子库和依赖库

当没有下载板子时,查看连接的设备会显示Unknown

$ arduino-cli board list

Port Protocol Type Board Name FQBN Core

/dev/ttyACM0 serial Serial Port (USB) Unknown

显示搜索所有板子(包括在添加的第三方源里的), 这里搜索ESP32核心板, 淘宝老板说,我的开发板叫 ESP32S3 Dev Module

$ arduino-cli board listall ESP32S3 Dev Module

ESP32S3 Dev Module esp32:esp32:esp32s3

安装板子module, 比较大要等待一会。 tips: 板子的包叫module, 软件依赖库叫library

$ arduino-cli core install esp32:esp32

搜索已安装的安装核心板

$ arduino-cli core search esp32

ID Version Name

arduino:esp32 2.0.18-arduino.5 Arduino ESP32 Boards

esp32:esp32 3.0.7 esp32
编译

编译淘宝店的例子LCD_Button,要在LCD_Button外面执行

arduino-cli compile --fqbn esp32:esp32:esp32s3 LCD_Button

上传到板子

arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3 LCD_Button

有时候失败了,要按住Boot键插入电脑再松开,就能正常上传。

esptool.py v4.6

Serial port /dev/ttyACM0

Connecting...

Traceback (most recent call last):

...

OSError: [Errno 71] Protocol error

Failed uploading: uploading error: exit status 1

看这个日志,原来arduino也是调用的官方的idf工具的esptool脚本。 重新插入USB, 再次查看已连接的开发板就不会显示Unknown了

$ arduino-cli board list

Port Protocol Type Board Name FQBN Core

/dev/ttyACM0 serial Serial Port (USB) ESP32 Family Device esp32:esp32:esp32_family esp32:esp32

连接串口UART

烧录了淘宝店给的串口收发例子,代码非常简单, 然后用我的USB转ttl工具测试成功。

import machine



uart = machine.UART(1, baudrate=115200, tx=machine.Pin(43), rx=machine.Pin(44))



def send_data(data):

uart.write(data)



def receive_data():

if uart.any():

data = uart.read()

print("Received data:",data)




while True:

send_data("Hello UART")

receive_data()

然而这里是不对的, 串口转TTL和ESP的USB都要连接到电脑上。单连一个都是进了mpy的repl。

usb-ttl-esp32-uart.png.png

起因

一直苦恼现在的手机没有3.5mm耳机孔,最近突然想到用airplay将音乐投到有耳机孔的电脑上听,发现有很多基于Linux的实现

用 wpasupplicant 管理wifi连接

用树莓派管理wifi连接的方法有 : * 通过配置文件/etc/wpa_supplicant/wpa_supplicant.conf * raspi-config * 其它工具iwctl nmtui等

后来发现配置文件管理wifi的优先级不生效,不能选择网络,当然可以用nmtui很方便,不过要安装新包。后来发现了wpa_cli工具很方便,来自安装包wpasupplicant

wpa_cli

先要选择网络接口,树莓派就是wlan0。 * 查看可用网络 wpa_cli -i wlan0 list_networks 这个命令会打印可用网络的id和名称 * 选择某个网络 wpa_cli -i wlan0 select_networks <网络id>

wpa_cli 还有交互模式

参考

https://superuser.com/a/759153

pve中给windows扩容

当初创建windows时给的40G硬盘,就一个分区,后来装了一些软件,发现不够用了,就第一次扩容,然后加了另一个分区。后来有些东西必须放在C盘里,这次扩容就比较复杂些。

第一次扩容

pve的web界面点击硬盘的resize可以修改硬盘大小,这个硬盘实际上是一个lvm块设备,而对于虚拟机Windows而言就是硬盘变大了。

硬盘加大后,进入windows磁盘管理,发现Windows已经有3个区:efi,C盘,恢复分区。为了方便直接加了一个D盘。

备注:pve的虚拟机安装在块设备上,而qemu是用文件(raw or qcow2),所以qemu的虚拟机可以复制移动,不过pve支持异地部署。

第二次扩容

这次扩容是为了增加C盘大小,而C盘后面有恢复分区和D分区。不得不在gparted 中执行: 1. 删除D分区 2. 移动恢复分区到磁盘末尾 3. 拓展C盘大小。 gparted操作很方便,不过windows启动不成功,通过windows安装iso修复之后正常了,恢复分区也还在。

virtual vnc 可视化打开gparted

因为pve没有连接显示器,只能用虚拟vnc,远程连接到pve桌面。

安装tigervnc服务端

pve只需要安装服务端,tigervnc-standalone-server。本地电脑安装客户端,选择很多例如 remmina。

启动

创建密码后启动vnc 服务端失败,提示没有桌面。原因是没有安装桌面环境更没有启动桌面,好在tigervnc 支持指定可视化进程(xVNC就不支持这种方式)。

tigervncserver -xstartup /usr/sbin/gparted  --  /dev/dm-15

这里直接给的gparted可执行文件路径和参数,--表示后面的参数是给gparted的,不是给tigervncserver的,/dev/dm-15是要操作的windows磁盘,也能在gparted界面里面再选。

remmina设置窗口大小

tigervncserver默认启动1024x768的窗口,当内容多时不方便。重新启动

tigervncserver -geometry 1920x1080 -xstartup /usr/sbin/gparted  --  /dev/dm-15

但是重新连接发现窗口还是很小,以为参数不生效。后来发现这时候窗口右下角可以拖动,手动拖成满屏

gparted问题

启动gparted后出现没有光标,后面按了鼠标右键就恢复X光标了。arch wiki里面有解决办法

替换招行的账单中发现vim和sed区别

在vim中 1. :%s/\n/,/g 2. :% s/\t,\t,\t,\t,/\r/g 用sed: cat bill.txt| sed -z 's/\n/,/g' | sed 's/\t,\t,\t,\t,/\n/g'

可见

  1. vim中匹配换行符用\n, 而替换用\r。替换成\n在vim中显示成^@
  2. sed 中的换行符统一用\n,这比vim好,但sed 中不能直接用\n匹配,还得加上 -z 参数。

进位位和溢出位(carry bit/overflow bit)

这两个标志位是运算器(alu)的组成部分,因为运算器在执行加法时,要关注两个问题:是否进位超了;是否溢出了。这两个问题很相似,但有区别。

加法和减法

对于减法而言,实际是将减数翻转,然后执行加法。即:

1 - 1 = 1 + (-1)

运算器做减法时要比较两数的绝对值大小再进行减法,符号设置成大的数的符号,例如

2 - 1 => 2 - 1 = 1 => 符号位设置成2的符号位
1 - 2 => 2 - 1 = 1 => 符号位设置成1的符号位

数字在内存中存放的是“补码”形式,补码很多好处,对于正数而言,源码、反码、补码的二进制形式相同。补码统一了+0和-0的形式,而且补码适合做减法运算。

+0/-0
原码: 0000 0000/ 1000 0000
反码: 0000 0000/ 1111 1111 正数不变,负数的符号位不变,其它位取反
补码: 0000 0000/10000 0000 正数不变,负数先转反码再加1,进位位丢掉后相同

进位标志位

进位位用来标志两数相加产生的进位超过了位数,例如 1+1 = 10,要多一位,如果运算器是8位的,执行 11111111+1的运算,就要进位,且超过了位数,这时候进位位就会置1。

判断方法 Carry = (Result >> n) & 1

溢出标志位

溢出位只针对有符号数的运算,有符号数的第一位表示正负,0代表正,1代表负,其它位表示值。当值的部分想加产生进位时,导致符号位覆盖。

判断方法(就8位而言) Overflow = (Result [7bit] XOR Op1[7bit] XOR Op2[7bit])

溢出位置1时,虽然符号为不正确,但其值是正确的(包含符号位)。

参考

源码/反码/补码 进位位/溢出位

firefox manual add search engine

  1. Open a new tab and type about:config in the address bar
  2. In the search box type: browser.urlbar.update2.engineAliasRefresh
  3. Click on the little + symbol on the right. This is what it should look like after you pressed it: boolean true value after pressing plus sign
  4. Go to firefox Settings → Search. Or enter this in the address bar: about:preferences#search
  5. In the "Search Shortcuts" section you should notice a new "add" button.

参考

https://superuser.com/questions/7327/how-to-add-a-custom-search-engine-to-firefox