0%

最近做一个web3 的 NFT 项目, 对这方面比较陌生,记录下开发中学到的相关知识

区块链

区块链(1.0)是一个基于密码学安全的分布式账本,是一个方便验证,不可篡改的账本。
通常认为与智能合约相结合的区块链为区块链2.0, 如以太坊是典型的区块链2.0

智能合约

以太坊与比特币很大的不同是以太坊拥有智能合约的概念。 比特币是数字货币-价值存储。 而以太坊不单单是数字货币,它们是可以区块链上运行代码。

首先要了解的是智能合约是以太坊网络上的一种特殊帐户。 我们有用户帐户,还可以拥有智能合约帐户。

阅读全文 »

方法1

两层for循环,遍历两个链表,判断第一个链表里面的节点是否在第二个链表里面,时间复杂度O(m*n)

方法二

分别把两个链表的节点放入两个栈中,从两个栈的栈顶开始比较,直到找到最后一个相同的节点,就是他们的公共点。

阅读全文 »

反转链表, 大致有递归和非递归方法

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 定义链表结构为
class ListNode {
constructor(value = null) {
this.value = value;
this.next = null;
}

/**
* 为了方便调试,增加一个打印方法
* 打印出来像这样: 1->2->3
*/
print() {
let result = this.value;
let head = this;
while (head.next) {
result += '->' + head.next.value;
head = head.next;
}
console.log(result);
}
}

/**
* 创建长度为 length 的链表
* @param length
* @returns {ListNode}
*/
function createListNode(length) {
if (length <= 0) return null;
const node = new ListNode(length);
node.next = createListNode(--length);
return node;
}
// 测试创建链表
const testNone = createListNode(10);
testNone.print();
// 10->9->8->7->6->5->4->3->2->1

// 反转链表递归写法:
/**
* 反转链表
* @param node
* @returns {*}
*/
function reverseNode(node) {
let result;
(function reverseNodeAndGetTailNode(node) {
if (node.next === null) return result = node;
const next = node.next;
node.next = null;
reverseNodeAndGetTailNode(next).next = node;
return node;
})(node);

return result;
}
// 测试反转链表1
const testNoneRevert1 = reverseNode(testNone);
testNoneRevert1.print();
// 1->2->3->4->5->6->7->8->9->10

/**
* 反转链表,循环迭代写法
* @param head
* @returns {*}
*/
function reverseNode2(head) {
// 记录上一个节点
let prev = null;

while (head) {
const next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
// 测试反转链表2
const testNoneRevert2 = reverseNode(testNoneRevert1);
testNoneRevert2.print();
// 10->9->8->7->6->5->4->3->2->1

补充
总觉得自己的递归写法有点别扭,每次返回的是尾结点,还得用个变量保存最后的结果,也就是反转后的头结点。
搜了一下其他人的写法,然后自己再写还是差点绕晕了 - - 还是太菜了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function reverseNodeByRecursive(node) {
if (!node.next) return node;

const newNode = reverseNodeByRecursive(node.next);
node.next.next = node;
node.next = null;

return newNode;
}

// 测试:
const testNoneRevert3 = createListNode(10);
testNoneRevert3.print();
// 10->9->8->7->6->5->4->3->2->1

const result = reverseNodeByRecursive(testNoneRevert3)
result.print();
// 1->2->3->4->5->6->7->8->9->10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 递归
function printListNodeFromTail(head) {
if (!head) return;
printListNodeFromTail(head.next);
console.log(head.value);
return head;
}

// 非递归
function printListNodeFromTail2(head) {
const listNodeArray = [];
while (head) {
listNodeArray.unshift(head);
head = head.next;
}

listNodeArray.forEach(item => console.log(item.value));
}

nginx.conf

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
worker_connections 65535;
# multi_accept on;
use epoll;
}

http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# Logging Settings
##
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$request_body" $request_time "$upstream_response_time" $upstream_status';
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}



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
server {
listen 80;
index index.html index.htm;
server_name dev-saas.dding.net;
access_log /var/log/nginx/dev-saas.dding.net.log;
error_log /var/log/nginx/dev-saas.dding.net.error.log warn;
root /home/gitlab-runner/saas-fe-3.0/dist/;

charset utf-8;
client_max_body_size 16m;

location / {
expires 5m;
try_files $uri $uri/ /index.html;
}

location /v3/ {
proxy_pass http://127.0.0.1:7001/v3/;

}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}

location ~ .*\.(js|css)?$ {
expires 7d;
}
}

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
server {
listen 80;
index index.html index.htm;
server_name dev-manage.dding.net;
access_log /var/log/nginx/dev-manage.dding.net.log main;
error_log /var/log/nginx/dev-manage.dding.net.error.log warn;
root /home/gitlab-runner/saas-manager-fe/dist/;
charset utf-8;
client_max_body_size 16m;

location / {
expires 5m;
}

location /v3/ {
proxy_pass http://127.0.0.1:7002/v3/;

}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}

location ~ .*\.(js|css)?$ {
expires 7d;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/user/(.*)$ /$1 break;
proxy_pass http://user;
}

location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://user/;
}

could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

  • 使用 docker network ls 查看network数量
  • docker network prune 关闭未使用的网络
1
2
3
4
5
6
7
8
9
10
11
12
FROM node:10-alpine

RUN npm config set registry https://registry.npm.taobao.org
ADD ./package.json /apps/
WORKDIR /apps
RUN npm install

COPY ./ /apps
RUN npm run release

FROM nginx:alpine
COPY --from=0 /apps/dist/ /usr/share/nginx/html/
1
2
# 删除所有 <none> image 
docker rmi `docker images | grep "<none>" | awk '{print $3}'`
1
2
3
4
5
6
7
8
9
10
11
12
13
# 删除所有 <none> image 
docker rmi `docker images | grep "months ago" | awk '{print $3}'`

docker stop `docker ps | grep "weeks ago" | awk '{print $1}'`

# 删除半年前的image
docker image prune -a --force --filter "until=4320h"

# 这个命令会删除所有关闭的容器以及dangling镜像。
docker system prune

# 磁盘占用情况
docker system df

h,j,k,l h表示往左,j表示往下,k表示往右,l表示往上
ggdG 删除所有
I 前插入
A 后插入
w, W 跳到单词的后面,小写包括标点
b, B 以单词为单位往前跳动光标,小写包含标点
O 开启新的一行
^ 一行的开始
$ 一行的结尾
gg 文档的第一行
[N]G 文档的第N行或者最后一行
u 撤销
ctrl r 反撤销
dd 删除一行
dw 删除后面单词 db 删除前面单词

字节序分2种

  1. Little endian:小端字节序, 将低序字节存储在起始地址
  2. Big endian:大端字节序, 将高序字节存储在起始地址

JS里面的体现: 同一段数据用不同视图读取

1
2
3
4
5
const uint8 = new Uint8Array([1, 2]);
// Uint8Array(2) [1, 2]

const uint16 = new Uint16Array(Uint8.buffer);
// Uint16Array [513]

上面代码生成一个 2 个长度的Uint8 TypedArray,然后在它的buffer基础上,建立了一个 16 位整数的视图。
那么这段数据对应的二进制应该是 00000001 00000010

1
2
0b0000000100000010
// 258

用16位无符号整数读出来应该是 0b0000000100000010, 应该是258, 为什么是 513呢 ?

解释:

这说明本电脑采用的小端字节序(little endian),相对重要的字节排在后面的内存地址,相对不重要字节排在前面的内存地址, 即 00000010 00000001

1
2
0b0000001000000001
// 513

那么如果想手动指定字节序呢 ?

DataView 视图:

  1. 支持多种类型读写
  2. 支持设置字节序

DataView视图提供更多操作选项,而且支持设定字节序。
默认情况下,DataView的get方法使用大端字节序解读数据,如果需要使用小端字节序解读,必须在get方法的第二个参数指定true。

1
2
3
4
5
6
const dv = new DataView(uint8.buffer);
dv.getUint16(0)
// 258 大端字节序

dv.getUint16(0, true)
// 513 小端字节序

写入数据同理。

最近开发支付宝小程序蓝牙相关功能,由于支付宝小程序和微信小程序api设计有些不同,需要在 base64, ArrayBuffer, 16进制字符串直接进行转换,记录一下

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 { Base64 } from 'js-base64';

export function arrayBufferToBase64(buffer: ArrayBuffer): string {
return Base64.btoa(String.fromCharCode(...new Uint8Array(buffer)));
}

export function base64ToArrayBuffer(base64: string): ArrayBuffer {
const binaryString = Base64.atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}

export function buffer2Hex(buffer: ArrayBuffer): string {
const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
return ('00' + bit.toString(16)).slice(-2);
});
return hexArr.join('');
}

export function hex2Buffer(hexStr: string): ArrayBuffer {
const Uint8Numbers = hexStr.match(/../g).map((x) => Number('0x' + x));
return new Uint8Array(Uint8Numbers).buffer;
}


  1. sudo spctl --master-disable
  2. “系统偏好设置”–“安全与隐私”。在“通用”一览中,会看到“允许从以下位置下载的应用:”设置。这个时候应该已经有了三个可选项:“App Store、App和被认可的开发者、任何来源”。
  3. 解锁后选择 “任何来源”
  4. 休眠后没有声音 sudo killall coreaudiod
  5. 修改环境变量 export PATH=/Users/wangyulong/Downloads:$PATH