我的博客

MacOS上使用Selenium控制Safari

目录

苹果官方文档:

https://developer.apple.com/documentation/webkit/about_webdriver_for_safari

https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari

  1. 首先要确认 safaridriver 已经安装,路径在 /usr/bin/safaridriver

  2. 然后修改 Safari 配置允许自动控制

    image.png

    先在配置中显示 Develop 菜单,然后到 Develop 菜单中开启运行远程自动控制

    image.png

  3. 安装 selenium

    pip3 install selenium

  4. 使用 selenium 启动浏览器

    1
    2
    3
    4
    from selenium import webdriver

    driver = webdriver.Safari()
    driver.get('https://codeplot.top/')

在Windows10上安装MacOS虚拟机(VirtualBox + AMD ryzen)

目录
  1. 安装依赖
  2. 开始安装

试了很多方法都失败了,最后找到了 https://github.com/myspaghetti/macos-virtualbox/

尝试使用 cywin 但是卡在这里了:

1
2
3
Please make sure the following packages are installed:
coreutils gzip unzip xxd wget
Please make sure the coreutils and gzip packages are the GNU variant.

然后尝试WSL,结果很好用

安装依赖

  1. unzip

    sudo apt install unzip

  2. dmg2image

    1
    2
    3
    sudo add-apt-repository universe
    sudo apt update
    sudo apt install dmg2img
  3. Oracle VM VirtualBox Extension Pack

    也是 virtualbox 下载页面下载https://www.virtualbox.org/wiki/Downloads

开始安装

git clone https://github.com/myspaghetti/macos-virtualbox.git

进入该目录后执行

1
2
chmod +x macos-guest-virtualbox.sh
./macos-guest-virtualbox.sh

可能是因为 AMD CPU 的问题,开机卡住了,最后一行是 EXITBS 之类的。

然后参考https://github.com/myspaghetti/macos-virtualbox/issues/8 解决,关闭虚拟机,到 virtual box 的安装目录执行 VBoxManage modifyvm "macOS" --cpu-profile "Intel Core i7-2635QM" 再次开机就可以了。

搭建局域网视频直播服务:使用 node media server

目录
  1. 服务器配置
  2. 直播端配置
  3. 客户端

推流软件(直播视频采集):OBS Studio,一款免费的开源软件,支持 Window,Linux 和 MacOS

直播服务器:nodejs 的 node media server(nms)

Web 端视频播放器:flv.js

直播端和服务器可以是同一台机器。

服务器配置

  1. 安装 nodejs

    访问官方网站: https://nodejs.org/en/

    下载安装包并安装,有 LTS 和 Current 都可以,一般选 LTS

    image.png

  2. 进入目录 nms 执行 install.bat

  3. 执行 run.cmd

  4. 执行 run2.cmd

    此时会显示网址,就是在局域网内可以访问的地址,等配置好直播端,直接访问这个地址就可以观看直播了。

    image.png

直播端配置

  1. 安装 OBS Studio

  2. 配置

    image.png

    点击 sources 的加号,选择 Display Capture,这个会捕获整个屏幕的视频。再点击确定。

image.png

然后点击右侧的 Start Streaming 开始推送,但是第一次使用没有配置服务器,会弹出提示,点击打开配置即可

image.png

打开配置后点击左侧第二个 Stream,右边的第一个 Service 选择 Custom(即自定义),Server 填 rtmp://127.0.0.1/live, Stream Key 填 test,然后点 OK。

配置好再次点击 Start Streaming

客户端

最后在同一个局域网的机器上打开上面的网址就可以观看直播了

打卡助手使用说明

目录

这是我业余开发的项目,主要是帮助大家整理乐心运动步数打卡的图片,可以自动识别出步数和日期,并整理出时间线。可以自定义提醒时间,如果到了提醒时间还没有完成打开会自动推送提醒(这个还没有开发完成)。

效果是:

image.png

使用方法:

  1. 关注我的公众号:Colander漏勺

    qrcode_for_gh_71c26a4b3cca_258.jpg

  2. 点击公众号右下角菜单漏勺首页进入首页并注册和登录

  3. (这步可以跳过,不绑定微信也可以使用多数功能,但是无法收到推送提醒)绑定微信,登录后选择微信管理,点击绑定微信,然后才能收到推送提醒

  4. 给公众号发送打卡图片,需要点击公众号底部的切换按钮切到发送消息模式,然后点击加号,发送乐心步数页面打卡图片。

Javascript 键盘事件

目录
  1. 遇到的坑
    1. keyCode 属性
    2. keypress 事件
  2. 总结
    1. keyboard event 属性
    2. JavaScript keyboard event keyCode
    3. 关于事件回调函数

JS 监听键盘事件

遇到的坑

keyCode 属性

keyboardEvent 的 keyCode 属性已经 Deprecated,新的浏览不一定会支持该属性。MDN 文档 建议使用 code 属性

这里有一个开源项目可以把 keyCode 转换为 code:

https://github.com/marijnh/w3c-keycode

https://www.npmjs.com/package/w3c-keycode

但是 keyCode 和 code 不是严格对应的,且不同浏览器,使用输入法等多种情况会影响 keyCode 的值。

keypress 事件

keypress 事件已经 Deprecated,新的浏览器不一定支持该事件。

keypress 事件一般是紧随 keydown 事件,但是 keypress 事件仅对可见字符有效,例如字母,数字,空格符号等,很多控制字符是不会触发该事件的。而且更重要的是,keypress 事件的 keycode 属性和 keyup,keydown 是不同的,它对应的是 ascii 码而不是键的编号。

总结

keyboard event 属性

demo:

1
2
3
4
5
6
7
8
9
10
11
<input>
<script>
let targetEvents = ['keydown', 'keyup','keypress']
let el = [];
targetEvents.forEach( function (s) {
document.addEventListener(s, function (e){
el.push(e)
console.log(e.type, e.keyCode,e. charCode, e.key, e.code);
});
});
</script>

code:IE 浏览器都不支持该属性,值是字符串,例如字母键:”KeyA”, “KeyB”, … “KeyZ”(一律是大写),数字键区分小键盘和和大键盘(小键盘:“Numpad4”, 大键盘:“Digit2”),ctrl shift 区分左右等等(ShiftRight, AltLeft 等),回车可以区分大键盘(Enter)和小键盘(NumpadEnter)。

key:对于可见字符就是该字符本身,控制字符则是这个字符的名称,例如 Enter (无法区分大键盘,小键盘),字母能体现大小写,

charCode

keyCode:整数值,主要是上面提到的 keypress 事件与其他两个事件的值含义不同,keypress 是 ASCII 码,keydown 和 keyup 是一套专门的编码。

JavaScript keyboard event keyCode

大键盘数字 0 ~ 9: 48 ~ 57

小键盘数字 0 ~ 9:96 ~ 105

字母 A - Z : 65 ~ 90

空格:32

回车:13

F1 ~ F24:112 ~ 135

BackSpace: 8

Tab: 9

Caps Lock:20

左上右下:37 ~ 40

关于事件回调函数

IE 浏览器版本 9 以下只能通过 window.event 获取事件对象,而 firefox 在某些情况下不能通过 window.event 获取该对象。

但是如果仅支持 IE9 和以上就可以直接使用回到函数的第一个参数获取事件对象了。

https://www.jianshu.com/p/e8a6fad0f7bc

Windows 获取实时 CPU 使用率

目录
  1. typeperf 命令
  2. wmic 命令
  3. vbs 脚本

https://stackoverflow.com/questions/9097067/get-cpu-usage-from-windows-command-prompt

typeperf 命令

连续输出:

typeperf "\processor(_total)\% processor time"

只输出一次:

typeperf "\Processor(_Total)\% Processor Time" -sc 1

输出:

C:\Users\sxwxs\MyBlog>typeperf “\Processor(_Total)\% Processor Time” -sc 3

“(PDH-CSV 4.0)”,”\DESKTOP-HRM3VGN\Processor(_Total)\% Processor Time”
“05/26/2020 16:48:59.930”,”5.565367”
“05/26/2020 16:49:00.932”,”4.185358”
“05/26/2020 16:49:01.935”,”6.002955”

命令成功结束。

wmic 命令

1
wmic cpu get loadpercentage

连续输出:

1
@for /f "skip=1" %p in ('wmic cpu get loadpercentage') do @echo %p%

输出:

C:\Users\sxwxs\MyBlog>wmic cpu get loadpercentage
LoadPercentage
22

vbs 脚本

https://blog.csdn.net/weixin_33819479/article/details/91870042

1
2
3
On Error Resume Next
Set objProc = GetObject("winmgmts:\\.\root\cimv2:win32_processor='cpu0'")
Wscript.Echo "cpu 使用率: " & objProc.LoadPercentage & "%"

vbs 输出只能是弹出对话框。

参考这篇博客:https://blog.csdn.net/codeh/article/details/5492951

WSH.Echo "print your message here"

然后使用 CScript tmp.vbs 运行脚本,可以输出到命令行。

在 multimodal Twitter dataset 上使用 VL-BERT

目录
  1. 预处理图片数据
  2. 训练
    1. 配置环境
    2. 初始化
    3. 训练
    4. 问题
    5. 测试

VL-BERT 代码:https://github.com/jackroos/VL-BERT/

预处理图片数据

VL-BERT 使用 fast rcnn 提取图片中的物体。

我使用 https://github.com/open-mmlab/mmdetection/ 提供的 resnet 101 fast rcnn 实现

下载模型,准备入口代码

1
2
3
mkdir mycode
cd mycode
wget https://open-mmlab.oss-cn-beijing.aliyuncs.com/mmdetection/models/faster_rcnn_r101_fpn_1x_20181129-d1468807.pth

创建 main.py,内容是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import mmcv
from mmcv.runner import load_checkpoint
from mmdet.models import build_detector
from mmdet.apis import inference_detector, show_result
from tqdm import tqdm
import os
import json

cfg = mmcv.Config.fromfile('configs/faster_rcnn_r101_fpn_1x.py')
cfg.model.pretrained = None

# construct the model and load checkpoint
model = build_detector(cfg.model, test_cfg=cfg.test_cfg)
_ = load_checkpoint(model, '/root/code/faster_rcnn_r101_fpn_1x_20181129-d1468807.pth')

image_list = os.listdir('/root/images')
# test a single image
for name in tqdm(image_list):
if not name.endswith('.jpg'):
continue
img = mmcv.imread('/root/images/%s' % name)
result = inference_detector(model, img, cfg)
rl = []
for r in result:
if r.shape[0] > 0:
for x in r:
rl.append(x.tolist())
with open('/root/features/%s.boxs' % name.split('.')[0], 'w') as f:
f.write(json.dumps(rl))

启动 docker 容器

1
2
docker pull vistart/mmdetection:v0.6.0
docker run --gpus all -v /home/sxw/jupyter_workspace/Data/sarcasm/dataset_image/:/root/images:ro -v /tmp/sarcasm_image2:/root/features -v /home/sxw/jupyter_workspace/mutil-model/mycode:/root/code:ro --rm -it vistart/mmdetection:v0.6.0 /bin/bash

进入容器后

1
2
3
4
pip3 install pycocotools tqdm
cd mmdetection/
cp /root/code/main.py .
python3 main.py

训练

配置环境

1
2
3
4
5
6
7
8
9
10
11
pip install torch==1.1.0

git clone https://github.com/NVIDIA/apex
cd apex
pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./

cd ../
git clone https://github.com/sxwxs/VL-BERT.git
cd VL-BERT
pip install Cython
pip install -r requirements.txt

初始化

1
./scripts/init.sh

下载对应的预训练模型

https://github.com/jackroos/VL-BERT/blob/master/model/pretrained_model/PREPARE_PRETRAINED_MODELS.md

训练

1
./scripts/nondist_run.sh twitter/train_end2end.py cfgs/twitter/base_4x16G_fp32.yaml ./out/ 2> err.log

问题

遇到一堆问题

RuntimeError: CUDA error: an illegal memory access was encountered

CUDA_LAUNCH_BLOCKING=1 ./scripts/nondist_run.sh twitter/train_end2end.py cfgs/twitter/base_4x16G_fp32.yaml ./out/ 2> err.log

测试

1
python twitter/test.py  --cfg cfgs/twitter/base_4x16G_fp32.yaml --ckpt out/output/vl-bert/twitter/base_4x16G_fp32/train2014+val2014_train/vl-bert_base_res101_vqa-0004.model --gpus 0 --result-path result_output --result-name test1 2> terr.log

python3 list 和 tuple 性能对比

目录
  1. 代码
    1. 代码一:tuple 版
    2. 代码二:list 版
    3. 代码三:list 版(使用同一个对象)
    4. 代码四
    5. 代码五
    6. 代码六
    7. 代码七
    8. 代码八

tuple 是不可变对象,理论上性能应该比 list 快。但是我在最近的次数据分析中发现,用 tuple 替换 list 反而导致内存和时间的消耗显著增多。所以我做了一个简单的实验。

定义一个 list,然后往 list 中 append 1 亿个 list 或者 tuple,其中的元素都是 1,2,3,4,5 五个数字。

1
2
3
4
5
6
7
8
9
$python3 test_tuple.py
100%|█████████████| 100000000/100000000 [00:23<00:00, 4185364.44it/s]

0.7727 GB

$ python3 test_list.py
100%|█████████████| 100000000/100000000 [01:14<00:00, 1339510.06it/s]

12.9193 GB

tuple 耗时 23 秒,使用内存 0.7727 GB (代码一)

list 耗时 74 秒,使用内存 12.9193 GB(代码二)

通过简单的读取 /proc/meminfo 获得大致的内存消耗,windows 无法运行,还需要安装依赖 tqdm(pip install tqdm

上面的实验是有问题的, 感谢 rainy 的评论,这里 tuple 比 list 快和省内存的原因是编译器优化了 tuple 的代码,每次 append 的 tuple 对象都是同一个,所以实际上这里只创建了一个对象。所以我添加了两个实验。

如 rainy 评论的,list 版在循环外定义一个 x = [1,2,3,4,5,] 每次 append(x), 得到的结果与 tuple 相同

耗时 24 秒,内存消耗 0.748 GB(代码三)

1
2
3
100%|██████████| 100000000/100000000 [00:24<00:00, 4051356.31it/s]

0.7480697631835938

所以说代码一的实际只创建了一个对象。

于是又做了一组实验,append 5 千万次,i 从 0 到 5 千万,每次 append 的是 [i+1, i+2, i+3, i+4, i+5,] 或者 (i+1, i+2, i+3, i+4, i+5,)。这样避免了解释器优化的问题。

1
2
3
4
5
6
7
8
9
10
11
tuple(代码四)

100%|██████████| 50000000/50000000 [00:27<00:00, 1825827.72it/s]

12.5092 GB

list(代码五)

100%|██████████| 50000000/50000000 [00:51<00:00, 970668.78it/s]

14.0284 GB

tuple 比 list 稍好一些

最后我仔细看了下之前的代码,复现了一下我当时遇到的问题。原来我当时是这样做的:[int(s, 16) for s in x], x 是一个数组,元素是 16 进制字符串。我误以为把 [] 换成 () 就从 list 换成 tuple 了,结果实际上

1
2
3
4
>>> [int(s, 16) for s in ['4f', 'e2']]
[79, 226]
>>> (int(s, 16) for s in ['4f', 'e2'])
<generator object <genexpr> at 0x00EFDB18>

换成 () 后得到的是 generator,换成 tuple(int(s, 16) for s in ['4f', 'e2']) 就好了。原来 generator 消耗这么大

实验结果:

1
2
3
4
5
6
7
8
9
10
11
tuple(代码六)
100%|██████████| 5000000/5000000 [00:36<00:00, 136155.14it/s]
1.5345726013183594

list (代码七)
100%|██████████| 5000000/5000000 [00:40<00:00, 124367.94it/s]
1.7481269836425781

generator(代码八,这个是无意中的错误,实际上不应该用 generator)
100%|██████████| 5000000/5000000 [00:53<00:00, 93451.91it/s]
5.271724700927734

代码

代码一:tuple 版

1
2
3
4
5
6
7
8
9
10
11
12
13
from tqdm import tqdm
def get_free_mem():
with open('/proc/meminfo') as f:
f.readline()
f.readline()
return int(f.readline().split()[1])
f1 = get_free_mem()
l = []
for i in tqdm(range(100000000)):
l.append((1,2,3,4,5,)
f2 = get_free_mem()
print(f1-f2)
print((f1-f2)/1024/1024)

代码二:list 版

1
2
3
4
5
6
7
8
9
10
11
12
13
from tqdm import tqdm
def get_free_mem():
with open('/proc/meminfo') as f:
f.readline()
f.readline()
return int(f.readline().split()[1])
f1 = get_free_mem()
l = []
for i in tqdm(range(100000000)):
l.append([1,2,3,4,5,])
f2 = get_free_mem()
print(f1-f2)
print((f1-f2)/1024/1024)

代码三:list 版(使用同一个对象)

1
2
3
4
5
6
7
8
f1 = get_free_mem()
l = []
x = [1,2,3,4,5,]
for i in tqdm(range(100000000)):
l.append(x)
f2 = get_free_mem()
print(f1-f2)
print((f1-f2)/1024/1024)

代码四

1
2
3
4
5
6
7
f1 = get_free_mem()
l = []
for i in tqdm(range(50000000)):
l.append((i+1, i+2, i+3, i+4, i+5,))
f2 = get_free_mem()
print(f1-f2)
print((f1-f2)/1024/1024)

代码五

1
2
3
4
5
6
7
f1 = get_free_mem()
l = []
for i in tqdm(range(50000000)):
l.append([i+1, i+2, i+3, i+4, i+5,])
f2 = get_free_mem()
print(f1-f2)
print((f1-f2)/1024/1024)

代码六

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from tqdm import tqdm
import json

def get_frre_mem():
with open('/proc/meminfo') as f:
f.readline()
f.readline()
return int(f.readline().split()[1])

f = open('/opt/sdb1/bitcoin_raw/index/block_foward_450001_500000')
d = {}
freem = [get_frre_mem()]
for _ in tqdm(range(5000000)):
l = f.readline()
if not l:
print('finish')
break
l = l.split('\t')
d[int(l[0], 16)] = tuple([int(x, 16) for x in json.loads(l[2])])
cur_fm = get_frre_mem()
freem.append(cur_fm)
print((freem[0]-cur_fm)/1024/1024)

代码七

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from tqdm import tqdm
import json

def get_frre_mem():
with open('/proc/meminfo') as f:
f.readline()
f.readline()
return int(f.readline().split()[1])

f = open('/opt/sdb1/bitcoin_raw/index/block_foward_450001_500000')
d = {}
freem = [get_frre_mem()]
for _ in tqdm(range(5000000)):
l = f.readline()
if not l:
print('finish')
break
l = l.split('\t')
d[int(l[0], 16)] = [int(x, 16) for x in json.loads(l[2])]
cur_fm = get_frre_mem()
freem.append(cur_fm)
print((freem[0]-cur_fm)/1024/1024)

代码八

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from tqdm import tqdm
import json

def get_frre_mem():
with open('/proc/meminfo') as f:
f.readline()
f.readline()
return int(f.readline().split()[1])

f = open('/opt/sdb1/bitcoin_raw/index/block_foward_450001_500000')
d = {}
freem = [get_frre_mem()]
for _ in tqdm(range(5000000)):
l = f.readline()
if not l:
print('finish')
break
l = l.split('\t')
d[int(l[0], 16)] = (int(x, 16) for x in json.loads(l[2]))
cur_fm = get_frre_mem()
freem.append(cur_fm)
print((freem[0]-cur_fm)/1024/1024)

比特币链上的重复交易

目录

比特币链上有两个 txid 为 e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468 的交易。它们分别是 91722 和 91880 块的 coinbase 交易

是因为算法缺陷导致 coinbase 交易的 txid 容易重复。

后来被修复了。

BIP 30 introduced a rule that prevented blocks from containing a TXID that already exists.
BIP 34 required coinbase transactions to include the height of the block the were mining in to their transaction data.

2020-04-22 笔试

目录
  1. 第一题
  2. 第二题

第一题

烤鱼

一人到店里吃烤鱼,厨师每 t 秒做好一条烤鱼,这个人需要 d 秒走到窗口,然后 d 秒回到自己座位,然后每吃一条烤鱼需要 x 秒。他只有在自己的座位上才能吃烤鱼,不能边走边吃。他每次可以拿任意数量的烤鱼。

0 秒时,他在自己座位上,窗口没有任何烤鱼。

输入四个数字 t,d,x,n。求他吃 1 条,2 条 … n 条烤鱼,分别最短需要多少时间。

第二题

输入两个数字,n ,m

把 n 分成相邻的 m 个数字,要求对着 m 个数字中每一个,不得同时出现下面两种情况:

  1. 一个数字的前一个数字比这个数字大
  2. 一个数字的后一个数字比这个数字大

求一共又多少种分法,结果对 1e9 + 7 取模

例如

5 3

可以分为

1 1 3
1 2 2
1 3 1
2 1 2 (非法)
2 2 1
3 1 1