我并不是英雄
在没有英雄的年代里,
我只想做一个人。

——《宣言》美/北岛

前言

在共同抗击疫情的时刻,呆在家里也是对人民作出贡献的时刻,也要坚持接受新知识。毕竟,这是一个变化的时代,海浪拍来拍去,没有哪个人可以永驻风口浪尖。

另一个原因是当前工作的中心逐渐向业务偏转,不再是那个可以对着试验结果反复纠错一个月/半年的人设了。跟着创业的需求,前后端,算法,人工智能,都要知道明白,那就努力咯!:)

以下记录以下最近在逐渐学习前端的过程中接触到的知识/路径,即是笔记,也希望对他人有所增益。

当前火热的两大前端阵营 React v.s. Angular

阅读文章:ReactJS Vs Angular – A Complete Comparison For 2020

总结:

  • 小型项目/实时性要求高 –> ReactJS
  • 大型项目/复杂迭代 –> Angular2
  • ReactJS仅仅是View的库(Facebook支持),其他部分需要第三方支持
  • Angular2是一个完整的框架,View/路由/表单等等都有官方(Google)支持

什么是DOM,为什么DOM这么重要?

观看视频:DOM 是什么?

总结:

  • 网址 –> DNS –> IP地址 –> TCP/IP三次握手 –> html代码返回client端
  • html代码 –> DOM构造 –> CSS布局 –> browser绘制页面
  • 文档流(Document Object Model, DOM)与网页之间的关系,其实就是将一维节点映射到二维空间的关系

MVC架构 v.s. MVVM架构

阅读文章:MVC,MVP 和 MVVM 的图示

总结:

  • MVC(Model-View-Controller)单向通信,View 非常厚,业务逻辑都部署在 View
  • MVP(Model-View-Presenter)双向通信,View 与 Model 不发生联系,都通过 Presenter 传递,View 非常薄,”被动视图”(Passive View),Presenter非常厚,所有逻辑都部署在那里,Presenter可以看成原先的Controller
  • MVVM(Model-View-VIewModel)双向通信,类似MVP,用ViewModel取代Presenter,采用双向绑定,View和ViewModel的改变实时映射到彼此上

渐进式网页应用(Progressive Web App, PWA)

progressive-web-apps

总结:

  • Google 在2016年提出的概念,2017年落地的web技术
  • PWA作为一种思想和概念,目的就是对标原生app,提升Web网站的安全性(Reliable),性能(Fast),用户体验(Engaging)等方面指标,用户对网页的体验达到和APP相差无几
  • 黑科技,追寻极致的优化

这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。

——《我们这一代人的困惑》中/于宙

安装Hexo-WordCount

1
2
# 在部落格根目录下
npm install hexo-wordcount --save

配置Hexo-WordCount

NexT主题配置(已集成)

NexT主题默认已经集成了文章字数统计阅读时长统计功能,如果我们需要使用,只需要在主题配置文件 _config.yml 中打开 wordcount 统计功能即可。

1
2
3
4
5
6
7
8
# Post wordcount display settings
# Dependencies: https://github.com/willin/hexo-wordcount
post_wordcount:
item_text: true
wordcount: true
min2read: true
totalcount: true
separated_meta: true

非NexT主题配置(手动修改)

但是如果你的next版本过低或者你使用的hexo主题并没有集成该功能,那么你需要自己添加。我以我个人使用的这个hexo主题为例进行说明(该主题不是基于next主题)。

首先确认使用中的主题采用的哪种模板引擎,ejs or jade or swig。打开目录 xxx.github.io/themes/xxx/layout/_partial 查看文件扩展名即可。

对于如上三种模板引擎调用方式分别如下所示:

Swig

1
2
3
4
5
6
7
8
# Post Count:
<span class="post-count">{{ wordcount(post.content) }}</span>

# Post Minutes to Read:
<span class="post-count">{{ min2read(post.content) }}</span>

# Total Count:
<span class="post-count">{{ totalcount(site) }}</span>

Ejs

Post Count:

1
2
3
4
5
6
7
8
# Post Count:
<span class="post-count"><%= wordcount(post.content) %></span>

# Post Minutes to Read:
<span class="post-count"><%= min2read(post.content) %></span>

# Total Count:
<span class="post-count"><%= totalcount(site) %></span>

Jade

1
2
3
4
5
6
7
8
# Post Count:
span.post-count= wordcount(post.content)

# Post Minutes to Read:
span.post-count= min2read(post.content)

# Total Count:
span.post-count= totalcount(site)

找到post对应的文件,我的是article.ejs,内容如下:

1
2
3
4
5
<% if (!index){ %>
<span id="busuanzi_container_page_pv">
累计阅读次数<span id="busuanzi_value_page_pv"></span>
</span>
<% } %>

修改为

1
2
3
4
5
6
7
8
9
10
11
<% if (!index){ %>
<span id="busuanzi_container_page_pv">
| 阅读次数<span id="busuanzi_value_page_pv"></span>
</span>
<span class="post-count">
| 字数统计<%= wordcount(post.content) %>字
</span>
<span class="post-count">
| 阅读时长~<%= min2read(post.content) %>分钟 |
</span>
<% } %>

效果展示

Reference

  1. NexT主题 https://theme-next.iissnan.com/
  2. Hexo添加字数统计、阅读时长功能 https://www.bingyublog.com/2019/02/21/hexo%E6%B7%BB%E5%8A%A0%E5%AD%97%E6%95%B0%E7%BB%9F%E8%AE%A1%E3%80%81%E9%98%85%E8%AF%BB%E6%97%B6%E9%95%BF%E5%8A%9F%E8%83%BD/

你來時攜風帶雨 我無處可避
你走時亂了四季 我久病難醫

——《人间失格》日/太宰治

What is CDN & Choice

CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。

归纳起来,CDN具有以下主要功能:

  • 节省骨干网带宽,减少带宽需求量;
  • 提供服务器端加速,解决由于用户访问量大造成的服务器过载问题;
  • 服务商能使用Web Cache技术在本地缓存用户访问过的Web页面和对象,实现相同对象的访问无须占用主干的出口带宽,并提高用户访问因特网页面的相应时间的需求;
  • 能克服网站分布不均的问题,并且能降低网站自身建设和维护成本;
  • 降低“通信风暴”的影响,提高网络访问的稳定性。

本文撰写过程中考虑过的CDN有阿里云CDN/腾讯CDN/七牛云CDN/百度CDN/Amazon CDN/Fastly/Cloudflare/jsDelivr等,简单说一下:

  • 阿里腾讯七牛百度四家要求加速的网站在中国大陆备案,对于仅仅是个人部落格的搭建太过繁琐,我的域名cyfeng.science属于新顶级域名,工信部还暂时停止了此类顶级域名的备案,过
  • Fastly是GitHub使用的加速CDN服务商,因为近期中国大陆对GitHub的DNS混淆,国内体验很差,而且价格不适合个人部落格
  • Amazon CDN 在全球市场上处于领先地位,不适用纯粹是价格方面的考量,Amazon Cloud的新用户可以尝试一下,12个月每个月赠送免费的流量包
  • Cloudflare CDN 对个人用户提供免费的套餐,虽然有些功能不能使用吧,总体而言体验良好(关键是免备案,省心省力)。未来Cloudflare将和百度CDN合作,在中国大陆地区布局CDN的建设,为适应我国国情,国内使用必须取得MIIT的备案
  • jsDelivr CDN 是开源CDN,对于npm/GitHub/Wordpress三类进行加速。中国大陆地区jsDelivr和网宿公司合作,加速节点很充实。不过jsDelivr仅支持对公有仓库进行加速(开源嘛!),如果阅读过我上篇文章可以知道我现在使用的是Hexo+GitHub Pages+私仓+GitHub Action的配置(GitHub Action的配置可以参考 《使用GitHub Action集成Hexo自动部署GitHub Pages》 ),所以暂时舍弃了这种方式

Cloudflare

Cloudflare 是全球最大的 DNS 服务提供商之一。除此之外他们还提供 CDN、SSL 证书、DDos 保护等服务,并且 Cloudflare 与百度有合作,在国内也部署有大量的节点,还能顺便解决百度爬无法抓取 GitHub Pages 的问题。

开通服务

  1. Cloudflare注册一个账号
  2. 注册好后点击Add site添加需要配置CDN的域名
  3. 添加好后选择Free计划,$0/month
  4. 点击 Scan DNS Records,等待扫描完成。此时如果曾经在域名购买的网站添加过CNAME的解析,会直接获得一个指向xxx.github.io的CNAME条目,如果没有我们也可以后续自己添加
  5. 我们可以添加一条CNAME指向我们的xxx.github.io地址,添加A记录指向assets-cdn.github.com对应的地址,通过ipaddress.com查询为如下四个IP地址185.199.108.153/185.199.109.153/185.199.110.153/185.199.111.153,详细方法可以查看我原先的一篇blog《寻找Github在当前网络状况下最佳Host解析地址
  6. 然后 Cloudflare 会要求将 DNS 服务器替换成他提供的两个,需要我们去域名商那里设置一下,设置成功后会有传播延迟,过段时间Cloudflare确认更新成功后会发送邮件到账号注册邮箱
  7. 过段时间登录Cloudflare在你的网页下显示 Great news! Cloudflare is now protecting your site 说明设置成功

更多设置

Overview 面板

  • under attack mode:当你的网站被攻击的时候打开它,在访问您的网站时向访问者显示JavaScript挑战,这样可以阻止攻击
  • development mode:由于 Cloudflare 采用了缓存技术,当你更新了网站的内容,不一定能马上在前台看到更新的内容。这个时候你只要打开 development mode 就可以马上看到网站更新的内容。当然,正常情况下还是关掉比较好

SSL/TLS 菜单设置

  • SSL设置:如果你本来的网站有 SSL 证书(github pages提供),这里会显示full ,即浏览器到 Cloudflare 和 Cloudflare 到服务器都是加密的。
  • Always Use HTTPS 设置:这个打开,一直使用 https 链接。
  • Authenticated Origin Pulls & Opportunistic Encryption & Onion Routing 设置:这些设置都打开

Speed 菜单设置

  • Auto Minify:网页最小化处理,把 Javascript/css/html 前面都打勾即可(当然对于公共仓库js和css使用jsDelivr CDN做进一步的优化会取得更好的效果,毕竟Cloudflare在国内的节点性能不如网宿的好 XD)
  • Brotli:这是一种比 gzip 更好的网页压缩方式,打开即可

Caching 菜单设置

  • Caching Level:缓存水平设置,决定缓存哪些内容,这里选择 standard 即可
  • Browser Cache TTL:即浏览器缓存过期时间,决定浏览器多久向网站获取一次新缓存
  • Always Online:如果您的服务器出现故障,Cloudflare将从缓存中为网站的静态页面提供服务。永不下线,打开

APPs 菜单设置

APPs里面提供了很多小程序,适当的添加几个常用小程序可以增加网页的流行性,当然代价是速度和冲突,自行选择

Back To Top Button / PACE 之类的都不错啦

What is DNS(补充)

Domain Name System是互联网的一项服务,它作为域名和IP地址互相映射的一个分布式系统,让用户更方便访问互联网。互联网通信是只认IP地址的,但一串数字人是记不住的,人容易记住的是apple.com这样的单词,这个叫域名,让电脑知道apple.com就是要访问122.224.45.229,就通过DNS域名解析系统。DNS系统中,常见的资源记录类型有:

  • 主机记录(A记录):RFC 1035定义,A记录是用于名称解析的重要记录,它将特定的主机名映射到对应主机的IP地址上。
  • 别名记录(CNAME记录): RFC 1035定义,CNAME记录用于将某个别名指向到某个A记录上,这样就不需要再为某个新名字另外创建一条新的A记录。
  • IPv6主机记录(AAAA记录): RFC 3596定义,与A记录对应,用于将特定的主机名映射到一个主机的IPv6地址。
  • 服务位置记录(SRV记录): RFC 2782定义,用于定义提供特定服务的服务器的位置,如主机(hostname),端口(port number)等

Reference

  1. CDN百科
  2. Cloudflare
  3. DNS补充
  4. jsDelivr
  5. Hexo 配置 Cloudflare 免费 CDN
  6. 阿里云CDN
  7. 腾讯云CDN
  8. 七牛云CDN
  9. 百度云CDN
  10. Fastly
  11. 网宿科技

愿得一心人,白首不相离

——《白头吟》汉/卓文君

解释

Submodule 是一个多项目管理工具,它允许将子项目以独立的 git 项目添加到主项目,而主项目以 submodule 的形式拥有子项目。子项目拥有自己的 commit、push、pull,而与主项目互不干扰。主项目只需要记录子项目的地址和所需要的 commit id,通过地址和 commit id 就能够得到对应的子项目。

[常用情景] 在我们的项目中调用轮子且希望两者解藕,可以分别进行版本管理。

添加

1
2
3
4
5
/*
url: 子项目远程地址或本地地址
path: 子项目路径,可省略
*/
git submodule add [url] [path]

可以看到多了文件: .gitmodules,.gitmodules 储存了 submodule 的路径及远程地址。对改变进行提交。

1
2
git add
git commit -m "xxx"

克隆

在clone带有submodules的项目时,正常clone主项目地址不会拉取submodules,可以使用如下命令同时clone主项目和依赖模块:

1
git clone --recurse-submodules [url]

更新

因为我们的目的是解藕主项目对依赖项目的关联,我在主项目中设置git不跟踪submodules,此时对submodules的更新不会提交到依赖项目中。

在使用中发现依赖项目中存在错误时,切换进submodules自己独立的仓库进行修改和PR,非 submodule 的开发人员就不用关心 submodule 是否更新。

删除

1
2
3
4
5
6
7
8
9
10
11
12
13
# 逆初始化模块,submodule为子模块目录,执行后可发现子模块目录被清空
git submodule deinit [submodule_name]

# 执行如下命令还能看到子项目信息
git submodule

# 删除.gitmodules中记录的模块信息(--cached选项清除.git/modules中的缓存)
git rm --cached test2sub
# 执行如下命令已看看不到删除的子项目信息了
git submodule

# 提交修改
git commit -m "xxx"

P.S.

  • 使用GitHub Action进行自动部署的时候需要对submodules进行额外的配置
  • ↑所以我一般将更新频率慢(固定)的submodules融入自己的项目,以较低代价防止奇奇怪怪的事情发生

Reference

  1. https://gist.github.com/myusuf3/7f645819ded92bda6677

思量。能几许,忧愁风雨,一半相妨。又何须抵死,说短论长。
幸对清风皓月,苔茵展、云幕高张。江南好,千钟美酒,一曲满庭芳。

——《满庭芳》宋/苏轼

GitHub Pages服务对与每一个用户开放username.github.io的域名解析和托管,如果你是普通用户,gh-page服务将仅对公有仓库开放,将仓库转为私有后gh-page停止解析和更新;对于学生Pro和付费Pro及以上等级用户,gh-page服务将同时对公有和私有仓库提供服务,然而Travis CI仅对公有仓库免费使用。

综上,本文面向于想使用GitHub Pages服务应用于私有仓库的大家伙。

P.S. 把托管gh-page的仓库私有化可以减少隐私泄露。但,所有(部署分支的)文件仍然可以被爬取/扫描。

前言

之前一直用最简洁直白的GitHub Pages+Jekyll进行部落格的书写(反正没有关注度不是嘛)。

近期因为疾控问题在家思思发抖,但学习和工作不能停,就干些一直以来没时间做/没接触的事情。

  • 把gh-pages仓库私有
  • 使用Hexo替代Jekyll
  • 使用Github Action实现自动部署

使用ssh-keygen生成秘钥对实现部署

1
2
3
4
5
# set up private key for deploy
mkdir -p ~/.ssh/
echo "$ACTION_DEPLOY_KEY" | tr -d '\r' > ~/.ssh/id_rsa # 配置秘钥
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts

使用github personal access token实现部署

类似于 Google 两步验证中的备用验证码,不过google token是单次生成(可见/查询)使用后销毁,github personal token是单次生成销毁(不可见)多次使用。

依次进入 Settings >> Developer settings >> Personal access tokens,点击 Generate new token

部署部落格仅需要对repo的读写权限。此页面关闭之后 token 将不可见(快记下来!!)。

设置仓库

因为gh-pages服务默认部署的分支是master,所以有如下两种常见的仓库设置方法:

  • 双仓库:仓库A用于存储hexo源文件,仓库B(xxx.github.io)用于hexo生成文件的部署,push A触发GitHub Action更新部署仓库B
  • 单仓库:source分支用于存储hexo源文件,master分支用于hexo生成文件的部署,push source触发GitHub Action更新master并部署gh-pages

这里我采用的是单仓库双分支的设置,注意不要手贱merge了就好,不然还要花时间(action刷新master之后history会消失)。

上一步生成的 token 我们不能以明文形式存放,所以要设置为仓库的 Secrets,这样就可用 Secrets 隐式引用 token。依次进入(仓库的)setting >> Secrets >> Add a new secret,名称填 GITHUB_ACCESS_TOKEN,内容填刚刚的token。

配置 GitHub Action

修改 Hexo 的 _config.yml,将下面 id 和 仓库名修改为自己的。

1
2
3
4
deploy:
type: git
repo: https://[email protected]/your-github-id/your-github-repo-name.git
branch: master

在 Hexo 根目录下新建 .github/workflows/blogci.yml,内容如下,将 git 的信息修改为自己的:

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
name: BlogCI

on: [push]

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Download Source file
uses: actions/checkout@v2
with:
ref: source # 此处修改为自己存放 Hexo 源文件的分支

- name: Prepare Node env
uses: actions/setup-node@v1
with:
node-version: "10.x" # 此处和自己的nodejs版本对应(10,12测试成功)

- name: Set Env
env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_ACCESS_TOKEN }}
run: |
git config --global user.name 'my_name' # github用户名
git config --global user.email 'my_email' # github邮箱
sed -i "s/GITHUB_ACCESS_TOKEN/$GITHUB_ACCESS_TOKEN/g" ./_config.yml

- name: Hexo
run: |
npm i -g hexo-cli
npm i
hexo clean && hexo g && hexo d

最后也可以采用另一种写法(使用局部安装避免npm安装依赖出错):

1
2
3
4
5
6
- name: Hexo
run: |
npm install hexo
npm install
npx hexo clean
npx hexo g -d

保存后推送到 GitHub,再进入 Actions 会发现 BlogCI 已经在工作。

价格

目前GitHub Action采用免费时长的营销策略:

  • 对于普通用户每个月可以免费使用2000分钟
  • 对于Pro用户每个月免费使用3000分钟

据我统计一般成功的推送action执行时间在40~60s之间,执行时间较长的(3~5min)一般都是出错了 :(

按这个时间进行估算,用户在action上无需额外消费 :)

Reference

  1. gh-pages服务 https://pages.github.com/
  2. Jekyll部落格框架 https://jekyllrb.com/
  3. Google备用验证码 https://support.google.com/accounts/answer/1187538
  4. 参考的Blog 有改进和勘误 https://rook1e.com/p/6.html
  5. Hexo中文文档 https://hexo.io/zh-cn/docs/

Hands on empirically searching for learning rate

3e-4 is the best learning rate for Adam, hands down.

如果 3e-4 在我的数据集上无法作用于模型,我会采取两个办法:

  • 如果看不到损失值移动的明确方向,我会降低学习率。
  • 如果在小数点后 5 或 6 位才能看到损失减少,我会提高学习率。
  • 如有必要,我会再重复上面的过程。

2015 年,Leslie N. Smith 将上述的反复试验法形式化为一种名为 LR Range Test 的技术。这个方法很简单,你只需将模型和数据迭代几次,把学习率初始值设置得比较小,然后在每次迭代后增加。你需要记录学习率的每次损失并将它画出。

LR Range Test 图应该包括三个区域,第一个区域中学习率太小以至于损失几乎没有减少,第二个区域里损失收敛很快,最后一个区域中学习率太大以至于损失开始发散。

除了确保你正在选择最佳学习率之外,该技术还可以作为一种「保险」检查。如果 LR Range Test 没有显示上述 3 个区域,或者图中有断层(损失中有 NaN 值),则表示模型中有缺陷或者数据中有错误。在运行模型之前,最好获取一个理想的 LR range 图。