• unix是肯·汤普森和丹尼斯·里奇在AT&T开发的

  • 里奇在创造unix的过程中,发明了C语言

  • 汤普森和里奇后来对unix不太满意,要创造一个真正的”一切都是文件“的系统,称为”Plan 9“,utf-8是这个系统的副产品

  • 80年代unix有两个主要的版本:AT&T的版本System V和伯克利的BSD(Berkeley Software Distribution)

  • 从System V衍生出了hp-ux和Solaris

  • BSD主要是比尔乔伊在上学期间开发的,他还是vi的作者

  • 90年代,因为和AT&T版权问题,BSD替换了AT&T有版权的几个文件,变成了freeBSD

  • (Linux崛起有两个历史机遇,一是Unix在打官司两年没有更新,二是英特尔发布了80386,开始了32位时代

  • 理查德·斯托曼创立了GUN计划,主要的软件有gcc、glibc,因为Linux用了许多GNU软件,他认为应该命名为GNU/Linux,但Linus不同意。斯托曼同时也是Emacs的作者

  • Minix,是一个类unix系统,由塔能鲍姆Tanenbaum为了教学创造

#先复习一下yolov1

  • 输出的shape是$7\times7\times30$,分别是类别,置信度和坐标,虽然每个格子输出两个框,但只有一组类别
  • 坐标$x, y$是相对于每一个格的,$w, h$是相对于整个图的,这样做的好处是位置坐标的取值范围都是$[0, 1]$

preview

  • loss都统一认为是回归问题

preview

  • 里的转图是针对RGB图片的,YUV图片没办法直接用。
  • 解决办法是分开Y、U、V三个分量,分别进行转图。
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
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cmath>

using namespace std;
using namespace cv;

int main() {

// 原始bgr图像
Mat srcImage = imread("/Users/zhaijy/Desktop/test2.png");

// 转到YVU(YV21)
Mat dstImage;
cvtColor(srcImage, dstImage, COLOR_BGR2YUV_YV12);

// 前 height * width 是Y分量
int height = srcImage.rows, width = srcImage.cols;
Mat dstImageY = Mat(height, width, CV_8UC1);
memcpy(dstImageY.data, dstImage.data, height * width);
imwrite("/Users/zhaijy/Desktop/Y.jpg", dstImageY);

// 后面 height * witdth / 4 是V分量
Mat dstImageV = Mat(height / 2, width / 2, CV_8UC1);
memcpy(dstImageV.data, dstImage.data + height * width, height * width / 4);
imwrite("/Users/zhaijy/Desktop/V.jpg", dstImageV);

// 后面 height * witdth / 4 是U分量
Mat dstImageU = Mat(height / 2, width / 2, CV_8UC1);
memcpy(dstImageU.data, dstImage.data + height * width * 5 / 4, height * width / 4);
imwrite("/Users/zhaijy/Desktop/U.jpg", dstImageU);

// Y旋转
int rot_height = static_cast<int>(floor(sqrt(height * height + width * width) / 4)) * 4;
Point2f center(static_cast<float>(width / 2.), static_cast<float>(height / 2.));
Mat rot_mat = getRotationMatrix2D(center, 45, 1.0);
Mat rotImageY = Mat(rot_height, rot_height, CV_8UC1);
warpAffine(dstImageY, rotImageY, rot_mat, Size(rot_height, rot_height), INTER_LINEAR);
imwrite("/Users/zhaijy/Desktop/rotY.jpg", rotImageY);

// U旋转
int rot_height_uv = rot_height / 2;
Point2f center_uv(static_cast<float>(width / 4.), static_cast<float>(height / 4.));
Mat rot_mat_uv = getRotationMatrix2D(center_uv, 45, 1.0);
Mat rotImageU = Mat(rot_height / 2, rot_height / 2, CV_8UC1);
warpAffine(dstImageU, rotImageU, rot_mat_uv, Size(rot_height_uv, rot_height_uv), INTER_LINEAR);
imwrite("/Users/zhaijy/Desktop/rotU.jpg", rotImageU);

// V旋转
Mat rotImageV = Mat(rot_height / 2, rot_height / 2, CV_8UC1);
warpAffine(dstImageV, rotImageV, rot_mat_uv, Size(rot_height_uv, rot_height_uv), INTER_LINEAR);
imwrite("/Users/zhaijy/Desktop/rotV.jpg", rotImageV);

// 拼接YVU
Mat rotImageYVU = Mat(rot_height * 3 / 2, rot_height, CV_8UC1);
memcpy(rotImageYVU.data, rotImageY.data, rot_height * rot_height);
memcpy(rotImageYVU.data + rot_height * rot_height, rotImageV.data, rot_height * rot_height / 4);
memcpy(rotImageYVU.data + rot_height * rot_height * 5 / 4, rotImageU.data, rot_height * rot_height / 4);

// 转回BGR
Mat rotImageBGR;
cvtColor(rotImageYVU, rotImageBGR, COLOR_YUV2BGR_YV12);
imwrite("/Users/zhaijy/Desktop/rotImageBGR.jpg", rotImageBGR);

return 0;
}
  • 然后贴一些中间的图片

test2

原始图片

Y

V

U

分别是YVU分量

rotY

rotV

rotU

分别是旋转后的YVU分量

rotImageBGR

最后拼接完的效果
- 我看YVU的解释说,$U=B-Y$,$V=R-Y$,可能是因为这个,黑边变成了绿边了吧

用pygame实现的贪吃蛇AI,代码在这里

屏幕快照 2019-07-15 下午11.26.42

使用

1
2
pip3 install requirements.txt
python3 main-bfs2.py

思路

主要是参考这篇 实现贪吃蛇AI,原实现在这里,主要的思路是下面这个图

主要的思路是派出一条假蛇去探路,假蛇吃完食物还能活着,真蛇才会去吃(假蛇吃完食物怎么样算能活,这个比较难判断,我的改动也主要在这里,后面会说)

改动

只是做了一些微小的修改

  1. 把curses改为pygame,界面好看多了
  2. 加了没有什么卵用的类
  3. 假蛇吃到食物之后,怎么算和尾巴之间有通路?
    1. 头和尾相邻算没有通路(原方法),比较保守,走到最后经常会循环起来,不敢吃食
    2. 如果头尾相邻算成有通路,容易在前期就把自己撞死
    3. 没有解决这个问题,加了个判断,蛇默认是保守的,但如果长时间没有吃到食物,就变激进。从测试结果看解决了原有的问题,虽然不优雅

待改进

  1. 这个算法调起来像无底洞,我应该不会再改进这个了,感觉要加逻辑判断的地方很多,应该会有更优雅的实现
  2. 当最后蛇很长的时候,蛇走和食物的最短路径是不合理的,因为走最短路径留下的空隙很可能会被填上食物,还需要绕一大圈才能吃到。应该是到最后,蛇直接一排一排地扫,反而是最快的

听方应杭的知乎live记下来的,一部前端的发展史,就是一部逆袭的历史。

图片是他做的,应该不会找我侵删吧,红色是重大事件,蓝色是一些工具

image-20190714094504609

  1. 后端:最开始没有前端,后端写页面,不太会css,用table布局

  2. 后端+美工:开始出现美工,美工复制ps和css,用div布局

  3. 后端+美工:2004年,gmail发布,页面功能复杂,大量应用ajax,微软ie5加入ajax

    js开始受重视,后端写页面写js,美工加图片加特效

  4. 后端+美工+前端:乔布斯拟物化流行,用户体验大爆发,需要有人专门用js写界面逻辑,前后端开始分离

原先后来
页面分离页面由后端框架提供,前端只负责js和cssHtml、css、js全部给前端
数据分离数据隐藏到页面中以接口形式,ajax传给前端
人员分离前后端两个部门,人员分离
  1. 后端数据比较重要,前端只负责界面,不好晋升,现在也没有解决,但缓解了很多。
    1. 移动端设备兴起,2G、3G网络网络不好,页面性能优化
    2. 响应式,不同的设备尺寸不一
    3. 自动化、模块化怎么解决

image-20190714094525575

  1. js语言独立:node.js出现,js可以脱离浏览器运行,前端程序员开始做一些其他程序员在做的事

    1. 自动化和打包工具,Grunt、Gulp、Webpack
    2. 模块化约定,CommonJS、AMD、CMD、UMD,民间方案,已经过时
    3. rails社区技术支援,CoffeeScript、SASS、Pug(Jade),语言不行就升级
  2. 标准制定方语言升级:xhtml→html5、css2→css3、ES5→ES6

  3. 前端框架出现

    MVC框架出现了backbone

    MVVM框架(MVVM是从C#的WPF里开始用的)出现了Angular

    从Angular启发又出现了Vue

    facebook推出react,Redux的思想,有游戏开发的思路

  4. 可以做服务端:TJ加入了node,TJ以前写Ruby,express.js、koa.js,nodejs可以做后台应用

  5. 可以桌面端:node+webkit,github写了electron,微信、vscode、叮叮

  6. 移动端:react native可以做ios和android应用

今天意外地发现了Typora,几乎解决了我关于记笔记和写博客的所有问题。

1.日常记笔记

其实我大概三个月前是用纸笔记笔记的,直到我意识到我打字已经比写字快很多了。。。

然后我开始用word记事,当然是可以的,但是总觉得不够轻便

然后我开始用onenote,但功能又太少了,关键时刻连个公式都没有

直到今天,直到今天我发现了Typora

  1. 实现了markdown的所见所得,标题、加粗、插图,可以直接显示,实现了word的功能又不用频繁点鼠标。
  2. 公式可以直接用$\LaTeX{}$打啊,而且边写边预览!
  3. 可以直接贴代码啊,直接语法高亮啊!这个用word我是不会做的。
  4. 装了pandoc之后,能直接导出word,而且公式还是原生的word公式,不是mathtype的!

其实看了上面的功能,我就怀疑这个软件像是一个本地版的hexo,然后我在GitHub上找,没找到源码,但找到了到了Typora的组织,里面的仓库有node、有electron,emmm,我更加怀疑了🤔

2.Hexo

所以把Typora当作Hexo的客户端非常合适,好像Hexo写博客难受的几个点都可以解决了。

2.1实时预览

hexo里能实现的,Typora上也都能实现,所以其实就是实现了实时预览。

虽然理论上也可以开hexo server,但是毕竟还是要到浏览器里刷新一下才能看到变化的,比不上直接用这个来得直接。

2.2图片粘贴

贴图简直是hexo的灾难,最早我是把图传到七牛云的,然后复制了链接再手动写到博客里。

后来七牛云突然就不允许外链了,差点把我的图都搞丢,吃了教训之后,我把图都放到了source/images里,然后在贴图的时候用![](/images/ctc.jpg),图片是要自己复制的,路径也是要自己写的。

但是现在有Typora 了!可以实现图片直接粘贴了

设置好图片自动复制,不管是本地图片,还是网络图片,都复制到source/images,显示相对路径,同时需要设置图片根目录,

1
typora-root-url: ../../source

这样Typora生成的相对路径才可以正常在网站上显示。

屏幕快照 2019-07-14 上午1.15.21

但mac上好像不能批量设置图片根目录,所以修改默认的post配置,在scaffolds\post.md里,添加上面那一句。

以前写的博客没有这一句怎么办呢?我弄了半天的sed最终放弃了(mac的freebsd上的sed和gnu的sed不一致),还是用python一把梭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os

path_root = './_posts/'
files = os.listdir(path_root)
files = [path_root + x for x in files if x.endswith('.md')]
insert_line = 'typora-root-url: ../../source'

for file in files:
with open(file) as f:
lines = f.readlines()

if any([insert_line in x for x in lines]):
continue

lines.insert(2, insert_line + '\n') // 在哪一行插入都行
with open(file, 'w') as f:
f.writelines(lines)

##2.3一个Typora没解决的图片问题

后来想到还有一个问题没有解决,图片直接用的是原图,没有做裁剪和重命名。

参考这里做的,用gulp压缩图片。

package.jsondependencies里加入

1
2
3
4
5
6
7
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-clean-css": "^2.3.2",
"gulp-htmlclean": "^2.7.22",
"gulp-htmlmin": "^3.0.0",
"gulp-imagemin": "^3.4.0",
"gulp-uglify": "^2.1.2",

然后,

1
2
3
cnpm insall
cnpm update # 直接install后报错,update之后好了
cnpm audit fix

gulpfile.js做了一些修改,主要是压缩图片好事太长了,从部署流程里单独拉了出来

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
83
84
85
86
87
88
var gulp = require('gulp');
var minifycss = require('gulp-clean-css');
var uglify = require('gulp-uglify');
var htmlmin = require('gulp-htmlmin');
var htmlclean = require('gulp-htmlclean');
var imagemin = require('gulp-imagemin');
var del = require('del');
var runSequence = require('run-sequence');
var Hexo = require('hexo');


gulp.task('clean', function() {
return del(['public/**/*']);
});

// generate html with 'hexo generate'
var hexo = new Hexo(process.cwd(), {});
gulp.task('generate', function(cb) {
hexo.init().then(function() {
return hexo.call('generate', {
watch: false
});
}).then(function() {
return hexo.exit();
}).then(function() {
return cb()
}).catch(function(err) {
console.log(err);
hexo.exit(err);
return cb(err);
})
})

gulp.task('minify-css', function() {
return gulp.src('./public/**/*.css')
.pipe(minifycss({
compatibility: 'ie8'
}))
.pipe(gulp.dest('./public'));
});

gulp.task('minify-html', function() {
return gulp.src('./public/**/*.html')
.pipe(htmlclean())
.pipe(htmlmin({
removeComments: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}))
.pipe(gulp.dest('./public'))
});

gulp.task('minify-js', function() {
return gulp.src('./public/**/*.js')
.pipe(uglify())
.pipe(gulp.dest('./public'));
});

gulp.task('minify-img', function() {
return gulp.src('./public/images/**/*.*')
.pipe(imagemin())
.pipe(gulp.dest('./public/images'))
})

gulp.task('minify-img-aggressive', function() {
return gulp.src('./source/images/**/*.*') //直接压缩source里的图片,public里的不管了
.pipe(imagemin(
[imagemin.gifsicle({'optimizationLevel': 3}),
imagemin.jpegtran({'progressive': true}),
imagemin.optipng({'optimizationLevel': 7}),
imagemin.svgo()],
{'verbose': true}))
.pipe(gulp.dest('./source/images'))
})

gulp.task('img', ['minify-img-aggressive'])

gulp.task('compress', function(cb) {
runSequence(['minify-html', 'minify-css', 'minify-js'], cb);
// runSequence(['minify-html', 'minify-css', 'minify-js', 'minify-img-aggressive'], cb);
});

gulp.task('build', function(cb) {
runSequence('clean', 'generate', 'compress', cb)
});

gulp.task('default', ['build'])

压缩图片用这个

1
gulp img

部署用这个

1
gulp build && hexo d

Joint CTC-Attention

是一篇16年的文章,Joint CTC-Attention based End-to-End Speech Recognition using Multi-task Learning

作者说Attention有个问题,没有CTC一样从左到右的限制,所以不好对齐,weak on noisy speech,也不好训练,所以在训练的时候,把CTC也加进去,$\alpha$取0.2的时候效果最好
$$
L=\alpha L_{ctc} + (1-\alpha) L_{att}
$$
但是预测的时候没有ctc,还是用Attention做decoding

CTC Beam Search

看的是这里,CTC 有两种decoding的方法,一种是最简单的,直接取最大值,叫max decoding或叫greedy decoding。但是这么做有两个问题。

  1. 但是这么做其实已经做了近似,理论上的做法应该是这样的。遍历所有可能的路径,计算出每一条路径的概率值,然后把结果一致的路径的概率加起来,选择概率最大的那个结果,就是最终的结果。但是路径太多了,不能这么暴力。
  2. max decoding不能结合语义。

主要变量是PbPnbPb[t][l], is the probability that a prefix, l, at a specific time step, t, originates from one or more paths ending in the blank token

think of a language model as a function taking a sentence as input, which is often only partly constructed, and returning the probability of the last word given all the previous words.

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
83
84
85
86
87
from collections import defaultdict, Counter
from string import ascii_lowercase
import re
import numpy as np

def prefix_beam_search(ctc, lm=None, k=25, alpha=0.30, beta=5, prune=0.001):
"""
Performs prefix beam search on the output of a CTC network.

Args:
ctc (np.ndarray): The CTC output. Should be a 2D array (timesteps x alphabet_size)
lm (func): Language model function. Should take as input a string and output a probability.
k (int): The beam width. Will keep the 'k' most likely candidates at each timestep.
alpha (float): The language model weight. Should usually be between 0 and 1.
beta (float): The language model compensation term. The higher the 'alpha', the higher the 'beta'.
prune (float): Only extend prefixes with chars with an emission probability higher than 'prune'.

Retruns:
string: The decoded CTC output.
"""

lm = (lambda l: 1) if lm is None else lm # if no LM is provided, return 1
W = lambda l: re.findall(r'\w+[\s|>]', l)
alphabet = list(ascii_lowercase) + [' ', '>', '%']
F = ctc.shape[1]
ctc = np.vstack((np.zeros(F), ctc)) # just add an imaginative zero'th step
T = ctc.shape[0]

# STEP 1: Initiliazation
O = '' # means empty
Pb, Pnb = defaultdict(Counter), defaultdict(Counter)
Pb[0][O] = 1 # balnk prob is 1
Pnb[0][O] = 0 # non blank prob is 0
A_prev = [O]
# END: STEP 1

# STEP 2: Iterations and pruning
for t in range(1, T):
pruned_alphabet = [alphabet[i] for i in np.where(ctc[t] > prune)[0]]
for l in A_prev: # A_prev is a string list

if len(l) > 0 and l[-1] == '>': # < means end-character
Pb[t][l] = Pb[t - 1][l]
Pnb[t][l] = Pnb[t - 1][l]
continue

for c in pruned_alphabet:
c_ix = alphabet.index(c)
# END: STEP 2

# STEP 3: “Extending” with a blank
if c == '%': # % means blank, index is -1
Pb[t][l] += ctc[t][-1] * (Pb[t - 1][l] + Pnb[t - 1][l])
# END: STEP 3

# STEP 4: Extending with the end character
else:
l_plus = l + c
if len(l) > 0 and c == l[-1]:
Pnb[t][l_plus] += ctc[t][c_ix] * Pb[t - 1][l]
Pnb[t][l] += ctc[t][c_ix] * Pnb[t - 1][l]
# END: STEP 4

# STEP 5: Extending with any other non-blank character
# and LM constraints
#
elif len(l.replace(' ', '')) > 0 and c in (' ', '>'):
lm_prob = lm(l_plus.strip(' >')) ** alpha
Pnb[t][l_plus] += lm_prob * ctc[t][c_ix] * (Pb[t - 1][l] + Pnb[t - 1][l])
else:
Pnb[t][l_plus] += ctc[t][c_ix] * (Pb[t - 1][l] + Pnb[t - 1][l])
# END: STEP 5

# STEP 6: Make use of discarded prefixes
# 可能l_plus已经存在过,但在上一步的时候扔掉了,这里相当于补回来
if l_plus not in A_prev:
Pb[t][l_plus] += ctc[t][-1] * (Pb[t - 1][l_plus] + Pnb[t - 1][l_plus])
Pnb[t][l_plus] += ctc[t][c_ix] * Pnb[t - 1][l_plus]
# END: STEP 6

# STEP 7: Select most probable prefixes
A_next = Pb[t] + Pnb[t]
sorter = lambda l: A_next[l] * (len(W(l)) + 1) ** beta
A_prev = sorted(A_next, key=sorter, reverse=True)[:k]
# END: STEP 7

return A_prev[0].strip('>')

后来想起来,sequence to sequence都有beam search和 greedy search,但是只是CTC的softmax是fram synchronously,所以逻辑才比较复杂,所以Attention一样也可以用beam search。

Advanced Joint CTC-Attention

还是那几个作者的文章,升级版,Advances in Joint CTC-Attention based End-to-End Speech Recognition with a Deep CNN Encoder and RNN-LM。

训练的过程没有做修改,还是CTC和Attention一起训练。

预测解码的时候修改了,以前是只用Attention,现在需要两个结合起来,用beam search做。但beam search有一个问题,Attention的softmax是character synchronously的,而CTC的是fram synchronously,并不是能很好地对应起来。
$$
\alpha_{att}(g_l)=\alpha_{att}(g_{l-1})+log(p(c|g_{l-1},X))
$$
Attention的概率这么计算,$c$ is the last character of $g_l$。

CTC不能用上面这种公式计算,但是可以用CTC计算loss时的forward来计算$\alpha_{ctc}(g_l)$,和$\alpha_{att}(g_l)$用$\lambda$结合起来。

  • 最近在听蒋勋的细说红楼梦,那温柔的台普,那细腻的解读,那新颖的角度,那穿插在解说其中的娓娓道来的个人经历

  • 但是我搜了几个在线的FM,都没有资源,不得已在一个微信公众号上听,体验不是太好

  • 于是我想在网上找资源下载下来

  • 翻来翻去,找到了这个看着很古老的网站,我打开chrome的调试,音频资源直接大大方方地暴露在外面,没有任何反爬措施,奈斯

  • 于是就有了下面这个爬虫,其实代码主要是从这里抄的
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
# -*- coding: utf-8 -*-
import os
from contextlib import closing
import threading
import requests

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'
}

out_dir = './out' # 输出文件夹
thread_num = 4 # 线程数

if not os.path.exists(out_dir):
os.mkdir(out_dir)

def download(img_url, img_name):
if os.path.isfile(os.path.join(out_dir, img_name)):
return
with closing(requests.get(img_url, stream=True, headers=headers)) as r:
rc = r.status_code
if 299 < rc or rc < 200:
print 'returnCode%s\t%s' % (rc, img_url)
return
content_length = int(r.headers.get('content-length', '0'))
if content_length == 0:
print 'size0\t%s' % img_url
return
with open(os.path.join(out_dir, img_name), 'wb') as f:
for data in r.iter_content(1024):
f.write(data)

def get_imgurl_generate():
for i in range(1, 161):
yield ("http://mp3.aikeu.com/15626/{}.mp3".format(i), "{}.mp3".format(i))

lock = threading.Lock()

def loop(imgs):
print 'thread %s is running...' % threading.current_thread().name

while True:
try:
with lock:
img_url, img_name = next(imgs)
except StopIteration:
break
try:
download(img_url, img_name)
except:
print 'exceptfail\t%s' % img_url
print 'thread %s is end...' % threading.current_thread().name

img_gen = get_imgurl_generate()

for i in range(0, thread_num):
t = threading.Thread(target=loop, name='LoopThread%s' %i, args=(img_gen,))
t.start()

净资产 = 总资产 - 负债
股本数:发行的股票的数量
每股净资产 = 净资产 / 股本数
市值 = 每股价格 * 股本数
市净率(PB) = 市值 / 净资产 = 每股价格 / 每股净资产

每股利润 = 净利润 / 股本数
市盈率(PE) = 市值 / 净利润 = 每股价格 / 每股利润

市盈增长比(PEG) = 市盈率 / (平均增长率 * 100)

旧内容

1
2
3
npm install packageName -g //全局安装,安装在Node安装目录下的node_modules下
npm install packageName --save //安装到项目目录下,并在package.json文件的dependencies中写入依赖,简写为-S
npm install packageName --save-dev //安装到项目目录下,并在package.json文件的devDependencies中写入依赖,简写为-D

webpack,这个是webpack的入门教程。链接没了

2021年追加

最近在弄gitbook,发现需要node老版本,发现node也需要像python一样,搞点虚拟环境

所以卸载了node

装了nvm

0%