diff --git a/2017/12/28/winter-dumplings/index.html b/2017/12/28/winter-dumplings/index.html new file mode 100644 index 0000000..cfd312c --- /dev/null +++ b/2017/12/28/winter-dumplings/index.html @@ -0,0 +1,122 @@ + + + + + + + + + 冬至日,北国的热门是饺子 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

冬至日,北国的热门是饺子

+
+ +
+

天与云与大地,上下一白,成栋楼、教学楼、研楼······还鼾鼾睡在冷风簌簌的清晨臂弯中时,北三、北四、南一、南二······,食堂身后的排风扇便早已薄薄喷涌出如丝如棉的热乎蒸汽,为新一天饥肠辘辘的人们精心忙碌着

+

前一天的下午,父亲就隔着微信,给我发来了几张饺子馅和发得软嫩筋道的饺子面的照片,下面配文——咱家要包饺子喽!唇齿间依稀留有母亲细细调拌的馅料的美味,我却抿起嘴角,小声嘟哝着:“我也想你们啊,还非得用包饺子的理由来馋馋我,门儿都没有,嘿嘿。”

+

可还没等我反应过来,母亲那头儿就又补上一句:“儿子,明天冬至可别忘了吃饺子啊,吃了饺子不冻耳朵。”母亲仍是说着那句这么多年来每逢冬至日都不曾改变的小幽默。“妈妈我明天就去饺子园抢座位!”心里一阵惊喜,我忙回复道。放下手机,脑海里却也还是那盏灯下父亲擀皮母亲包馅的画面,他们的眉眼里尽是笑意

+

哈尔滨的冷被二道门和双层玻璃结结实实地囚禁在了室外,那个院子却是除了被窝,冷得一览无余,在我的家里,冬至日的头一天晚上,总是要一家子围坐桌前,放上长长大大的案板,包上上百饺子,满满当当地放满几个大薄木板,开火揭锅,实实在在地盛上几大盘儿个儿大肚儿圆的饺子,美美地吃上一餐,意为“接冬”,诺大一个院子,像极了老北京的四合院,在一棵打我记事起就守在院落一角的粗壮梧桐树和东西相望的两棵高挑繁茂的香椿树的环抱下,静谧安然

+

次日五点半,父亲考虑到我要上学,又想让我吃一碗热乎饺子,就轻轻地把我拍醒,自己匆匆登上还裹挟着寒气的老棉裤下到一楼的厨屋

+

从小,父亲就教导我要有时间观念,当然,他也是一个办事利索、雷厉风行的人

+

推开厚重的门帘,俨然还是夜色浓重,邻家高大的红砖墙壁上,钉着一个暗得发昏的灯泡,和着天上的星点幽幽亮着,在枝叶掩映中,衬出这些建筑物的模糊轮廓

+

我小心翼翼摸索着下了楼梯,厨屋的玻璃窗上多年来沉积着一层暗黄色的油渍,却被屋内的光亮映出了琥珀的颜色,透过窗子,我依然可以看到蘑菇云般翻腾的蒸汽中,父亲忙得不亦乐乎

+

揉着辘辘饥肠,吱呀一声,我推开了屋门,父亲便笑着招呼我:“来吧!小懒虫!饺子煮好啦!起的早不如起的巧哇!”,紧接着便是热腾腾一碗饺子,香气扑鼻,被我捧在了手里

+

那种感觉也还记得,父亲笑呵呵地坐在我旁边,实实在在一大碗热乎饺子源源不断地暖着我的手心,汤汁鲜美满足着腹中和味蕾,偶尔抬头,也是和父亲相视一笑,一餐毕,早已从脚底暖到心头

+

第一次异乡的冬至,清早的心其实还是有一些空落的,翻翻朋友圈和qq空间,也有考到远方的同学朋友抱怨第一次冬至的早晨没有吃到饺子,却也能让我借以慰藉,即便饺子园人气爆棚,我和朋友依然打定主意,错开中午,半下午去碰碰运气,饺子不是母亲包的香菇白菜猪肉馅的,饺子质量也不如平日,大概是因为太忙了吧,然有友和饺子,这个冬至,或许也足矣

+

今夜的月亮像是被狠狠地啃了一大口的饺子,只剩下一个细细的边儿,兀自挂在树梢

+

蹉踏着路边闪耀光辉细细似沙的雪,裹紧棉袄,我瑟缩着从图书馆一步步朝着成栋楼的方向挪,萧红的一则短篇小说,很是凄惨悲凉,看得我心生难过,却自嘲这心情恰映这萧索清冷的景象,摸出手机拨通父亲的号码,我开玩笑似地倾诉着心情,想不到父亲却提起当年张国荣入戏太深的悲惨结局,我在电话这头儿苦笑,分明感受到的却是沉甸甸亲人的挂念,放下手机,却又分不清这眼前落雪闪烁着的,是月华,还是灯光

+

neau_winter_night

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2018/07/21/myfriend/index.html b/2018/07/21/myfriend/index.html new file mode 100644 index 0000000..5d05bb8 --- /dev/null +++ b/2018/07/21/myfriend/index.html @@ -0,0 +1,121 @@ + + + + + + + + + 你是我的狗子 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

你是我的狗子

+
+ +
+

今天周六,一大清早爸爸就从街市上买回一只大公鸡,九点钟就着手准备;菜式未知,但只因多了些神秘,肚皮十一点半比往常提早的咕噜声就好像和好奇的心思达成了共识,艳阳的炙烤也不能减轻蹬车子的力道,风从耳边呼呼而过,逆着家的方向…

+

刚进楼道就闻到了鸡肉炖东北野蘑菇的香味,那样的鲜美,是我自孩时的最爱。凑巧亲戚做客,大人和小孩,一家子围坐桌边共进午餐,着实愉悦而温暖

+

对于电影《汉娜》,有一句影评说 「真正的感情总会在你最不设防的时候突然决堤」。看着一桌子鸡骨头,我突然冒出来一句 「妈,这些都倒掉么」,听起来这句话并无异样,我却没敢再继续坐在饭桌前,收拾碗筷,躲进了厨房

+

我突然意识到我所有的记忆和习惯都还活在拆迁前的老家,那个树荫围绕,红墙黑瓦的院落

+

记得很小很小的时候,有一天爸爸突然抱回来一只小狗。十多年过去了,到现在我还记得那个小狗也很小很小,记得它有一对黝黑圆亮像桂圆核的眼睛,记得它一身黄灿灿阳光般的软毛,记得我拍着手摆出各种鬼脸发出各种声音和它不知疲倦地趴在地上玩儿了一个又一个的暖阳遍洒的下午

+

饭桌边多了一个毛茸茸的玩伴,我也从没把喂它食物看作是饲养,而一直把它看作家庭的一员,是伙伴,是朋友,年幼的我竟也能慢慢发现它的胃口和偏爱,自此以后,无论和谁,也无论去哪儿,只要吃饭过后有鸡骨或红薯,一向腼腆内敛的我总是厚着脸皮地向服务员或大人寻求一个塑料袋把这两样东西装起来,心里面惦记的,就是守护着院子还饿着肚子的它

+

渐渐地这成了习惯,只是因为我知道它最喜欢吃这两种东西

+

时间飞逝,爸妈盼我成长而为我用刀子标刻的身高线在门边一点点攀爬,它也经历了一次次褪毛,长得威风凛凛。安全起见,爸爸用锁链将它安置在了前门巷尾的香椿树下,又搭了一个砖棚,给它遮风挡雨

+

后来上了初中,我就成了住校生,越来越多的是上课还有一摞摞的作业习题,越来越少的是爸妈的身影和它的陪伴。每次周末放假回家,离大门还有足足三十米的地方,我就能听到它从前门巷尾发出的吠叫,声音和向造访院落的陌生人发出的决然不同,带着一种呜呜的声音,我能听出它的兴奋,像是在告诉我的爸妈我回来了,也像是久别重逢老友的招呼和寒暄,无比温暖

+

再后来拆迁了,是我还在学校的时候,爸妈搬进了小区,等到放假匆匆赶回去,眼前就只剩了一片废墟,没有它的吠叫声,我试着去呼唤,去聆听,可还是一声都没有,沉寂地让人慌张,让人害怕,就像我在失去给了我最美好回忆的大梧桐树的时候,那种惴惴不安甚至有一些绝望我真的不想去经历第二次,敝帚自珍和害怕失去的感觉我都有,但也并不全是。我近乎疯狂地去打听,去寻找,而且几乎没有人会在乎,能体会,父母的安慰也失去了作用。那三个晚上,失眠

+

慢慢洗着碗努力平复自己的心情,一直一直都心有歉疚,就像《忠犬八公》里说的 「它只是一条狗,你却是它的一生」 那样。只是被告诉它生活得很好,但我想见它,真的很想很想

+

还有,它的名字,叫欢欢

+

huanhuan

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2018/11/12/js-async/index.html b/2018/11/12/js-async/index.html new file mode 100644 index 0000000..bfc1188 --- /dev/null +++ b/2018/11/12/js-async/index.html @@ -0,0 +1,124 @@ + + + + + + + + + 初识 Js 中的异步处理方案 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

初识 Js 中的异步处理方案

+
+ +
+

Js 为什么需要「异步」呀 ?

因为由于 Js 单线程,同一时间只能做一件事,导致一旦遇到等待,就会阻塞代码的向下继续执行

+

这是让人不甘心的,因为这时 CPU 空闲

+

所以需要异步(形式上是回调函数),不阻塞代码的向下继续执行

+

举个例子

在浏览器端运行如下代码

+
1
2
3
console.log(1)
alert(3) // 网页会在这一行卡住(因为等待用户的交互)
console.log(2)
+ +

如果你希望按照 1 2 3 的顺序输出,那么就不能让alert(3)阻塞代码的向下继续执行

+

所以使用异步的手段,改写成如下代码

+
1
2
3
4
5
6
7
console.log(1)

setTimeout(() => {
alert(3)
}, 0)

console.log(2)
+ +
+

在 web 开发中,常使用异步手段把网络请求处理好

+
+

比如

+
1
2
3
4
5
6
7
8
9
var oImg = document.createElement('img')

// 异步
oImg.onload = () => {
document.body.appendChild(oImg)
console.log('图片加载完成')
}

oImg.src = 'https://github.com/xxx.jpg'
+ +

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2019/01/23/wechat-programe/index.html b/2019/01/23/wechat-programe/index.html new file mode 100644 index 0000000..8cf02cc --- /dev/null +++ b/2019/01/23/wechat-programe/index.html @@ -0,0 +1,202 @@ + + + + + + + + + 微信小程序初尝试-Pic装扮 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

微信小程序初尝试-Pic装扮

+
+ +
+
+

从期末考试结束开始着手做这个小程序,到 2019-01-22 正式上线,今天终于有时间来总结一下这些日子学到的东西,以便日后复习。

+
+

成果

+

这是一款用于图片编辑的工具小程序,(可以操作一波表情包啦),来认识一下它吧~

+
+

源码

+

image-20220503114239459

+

它的功能

    +
  1. 你可以从主页面上传手机相册中的图片,上传成功后会自动跳转到图片编辑页面
  2. +
  3. 你可将底部滚动栏中的挂饰图片添加到你上传的图片上,并可以用手调整挂饰的大小和位置
  4. +
  5. 点击保存并同意保存权限后小程序就会将编辑好的图片保存在你的相册中啦~
  6. +
+

接下来,你可以分享 or 斗图 or … if you like

+

挂件来源

+

Notes

    +
  • wxml<->html,wxss<->css
  • +
  • 微信小程序默认提供了很多 wxml 组件供我们使用
  • +
  • 微信小程序默认提供了很多强大的 API 接口供我们调用,本小程序用到的接口有
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExplainationAPI
上传图片wx.chooseImage()
获取图片信息wx.getImageInfo()
创建画布地图wx.createCanvasContext(“canvasId”)
保存图片到系统相册wx.saveImageToPhotosAlbum()
当前画布指定区域内容导出生成指定大小的图片wx.canvasToTempFilePath()
显示消息提示框wx.showToast()
创建 SelectorQuery 对象实例wx.createSelectorQuery()
+

图片等比例缩放原理

    +
  • 图片宽 / 图片高 = 画布宽 / 画布高
  • +
+

图片大小自适应原理

    +
  • 首先wx.createSelectorQuery()得到容器的宽高
  • +
  • 然后wx.getImageInfo()得到上传的图片的宽高
  • +
+
    +
  1. 图片瘦高 -> 即:图片高度/图片宽度 > 容器高度/容器宽度,则 -> 画布高 = 容器高,再由等比例缩放原理计算画布宽
  2. +
  3. 图片胖宽 -> 即:图片高度/图片宽度 < 容器高度/容器宽度,则 -> 画布宽 = 容器宽,再由等比例缩放原理计算画布高
  4. +
+

图片拖动原理

+

其实图片的拖拽和最初电影的原理是一样的,都是由一帧帧的画面连起来形成了一种移动的视觉效果

+
+

👉偏移值 x = 触摸点的clientX - 挂饰图片的clientX

+

👉偏移值 y = 触摸点的clientY - 挂饰图片的clientY

+

偏移值 x 和偏移值 y 在拖拽过程中保持不变 !

+

And then~

+

拖拽一旦开始,每时每刻我们都能获取到 touchPoint 的 clientX 和 clientY

+

分别减去对应的偏移值便可得到挂饰图片新位置的 clientX 和 clientY

+

然后进行实时更新(即在拖拽过程中不停地画新的场景)

+

图片缩放原理

1
2
// 实时计算缩放比例,然后在缩放过程中不停地画新场景以实现缩放
cfg.scale = cfg.scale + 0.0001 * (cfg.curDistance - cfg.initialDistance);
+ +
    +
  • 由勾股定理计算当前两手指之间的距离
  • +
  • 可以设置不能无限放大或缩小
  • +
+

BUG 处理

    +
  • 由于缩放结束的一瞬间会触发 touchEnd 事件,相当于又一次触碰到了屏幕,就会触发此函数🌚,为了解决这个问题,设置若离上次结束小于 600ms,则不处理
  • +
+
1
2
3
4
5
6
7
8
9
10
onTouchEnd() {
var date = new Date();
cfg.endTime = date.getTime();
}

if (new Date().getTime() - cfg.endTime < 600) {
return;
} else {
this.move(event);
}
+ +

细节

    +
  1. 触摸事件中,要判断执行的是拖拽操作还是缩放操作,可由触摸点的个数,即 event.touches.length 是否大于 1 来判断
  2. +
  3. 挂饰图片拖动结束都要记录下来其位置,这样更换挂饰时就会在当前挂饰位置而不会归位
  4. +
  5. 缩放比例需记录,防止更换挂饰时挂饰大小复原
  6. +
  7. 由于有可能在拖拽图片前进行了图片缩放,所以需要在获取挂饰图片的原始宽高后由当前的缩放比例计算新的宽高
  8. +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2020/07/16/goodnight/index.html b/2020/07/16/goodnight/index.html new file mode 100644 index 0000000..7b906a5 --- /dev/null +++ b/2020/07/16/goodnight/index.html @@ -0,0 +1,133 @@ + + + + + + + + + 今夜无梦 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

今夜无梦

+
+ +
+

现在是 23:25,今天是 2020 年入伏第一天

+

我侧身躺在明晃晃的玻璃窗下,耳边只有从窗外传来的窃窃虫鸣和驶来又远去的汽车声

+

安静让如今的世界显得空旷,我不喜欢这种空旷

+

如今的夏天太舒适了,住得高有电梯,天气热开空调,西瓜可以放冰箱里冰镇,抱着手机走到哪里都不会闲着

+

但我的夏天不该这样,我应该从蝉鸣艳阳或乌云雷雨的旧纱窗下醒来

+

如果是前者,那我就穿上裤衩汗衣儿,蹬上大拖鞋扑腾扑腾从二楼拐角泛出青苔的破水泥楼梯下到一楼院子

+

一把拧开墙根生了锈的铝水龙头抹一把脸,让头脑清醒

+

当我什么时候听见突突响的三马车从街口拐进来,大老远瞅见车后高高隆起,还盖着草席

+

就知道今天又能吃上大西瓜了

+

在梧桐树荫和香椿树荫的交相掩映下,浅绿墨绿相间的大西瓜半漂在满满当当盛着清凉井水的大铝盆中,反射着刺眼的日光

+

当它被捞出来湿漉漉地放在树下案板上的时候,便是暑天里最让人开心的时刻了

+

如果是后者,那我就扑腾坐起来,轻轻掩上微微掉漆裂纹的黄漆木窗,看一会儿天空的黑云卷动和香椿梧桐的枝摇叶摆

+

雨势大了,中庭红砖地面就会激起许许多多圆起又炸开的水泡儿,甚至泛起一层薄薄的水雾

+

欢欢拖着大铁链子窝在房沿下,一声不吭,对着面前的水雾眨巴着清澈的眼睛

+

待雷雨过后,水珠坠在绿叶上,在重现的阳光下晶晶莹莹

+

院东井盖上,西屋顶沿的水洼旁或一级一级的楼梯台阶上,一定能找到伸出触角的蜗牛黏糊糊慢悠悠地爬

+

我喜欢碰它的一对儿触角,然后静静观察它们一先一后地重新伸出来

+

我也特别愿意用大拖鞋的鞋底沾一沾水洼中的水,然后在已经晒干的地面上噼里啪啦跺下一片印章般的鞋印,开开心心

+

夜晚的月牙会浮身于树影间再爬到房梁上

+

而一轮圆月则往往高挂在院落正上方,围绕着点点明星

+

窗外除了叫没劲儿了的知了,偶尔还能听到蹑手蹑脚的野猫在瓦片间跳跃发出的脆响

+

欢欢卧在门口忠心耿耿值着夜班,风扇也在我的脚边不知疲倦地摇着头,一夜好梦

+

后来,我们就搬进了社区,住进了高楼

+

那个院落的四季和发生在那里鲜活恍如昨日的一切也都搬离了我的视线,住进了我的梦里

+

那些美好回忆我会永远珍藏,永远珍惜

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2020/09/26/MySQL/index.html b/2020/09/26/MySQL/index.html new file mode 100644 index 0000000..b7174de --- /dev/null +++ b/2020/09/26/MySQL/index.html @@ -0,0 +1,238 @@ + + + + + + + + + SQL & MySQL 用法速通 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

SQL & MySQL 用法速通

+
+ +
+

概述

image-20220305180750607

+

什么是数据库 ?数据库有啥用 ?

假设我们要做一个购物网站

+

如果我们将「用户信息、商品信息、…」这些重要数据放到内存中,那么服务器断电或重启都会导致数据的全部丢失

+

所以,我们需要将这些数据放到数据库中,达到数据持久化保存的目的

+

关系型数据库使用「表」来存储数据

+

image-20220305180159205

+

常见的关系型数据库管理系统

    +
  1. MySQL:开源免费跨平台、稳定高性能
  2. +
  3. Oracle:也挺适合大型系统,比如「银行系统、医院系统、…」
  4. +
  5. SQL Server:常见于 c# 和 .net 体系,适合在 Windows Server 中使用
  6. +
+

MySQL

+

一些高级知识和技巧本文不作介绍,如「一些常用函数、给表设置约束、表之间的关系、多表查询、子查询」

+
+

实验环境

ubuntu-20.04-lts、mysql8

+
1
2
3
4
5
6
7
8
# intallation
sudo apt update
sudo apt upgrade
sudo apt install mysql-server
mysql --version

sudo mysql_secure_installation # MySQL 的安全性配置
systemctl status mysql.service # 查验 MySQL 的运行状态
+ +

如何接入 MySQL

    +
  • 方法一
  • +
+
1
2
3
4
5
mysql -u root

OR

mysql -u root -p # passwd is needed.
+ +
    +
  • 方法二:使用图形化客户端,eg:dbeaver
  • +
+

SQL

结构化查询语言,用于操作关系型数据库

+

分类

    +
  1. 数据定义语言(Data Definition Language),用于操作数据库对象「库、表、列…」

    +
      +
    • createdropalter
    • +
    +
  2. +
  3. 数据操作语言(Data Manipulation Language),用于操作数据库中的数据

    +
      +
    • insertdeleteupdate
    • +
    +
  4. +
  5. 数据查询语言(Data Query Language)

    +
      +
    • select
    • +
    +
  6. +
+

注释

1
2
3
4
5
6
-- 单行注释

/*
多行
注释
*/
+ +

数据类型

1
2
3
4
5
6
7
8
9
10
11
int     -- 整型

double -- 浮点型,double(6,3) => 最长长度是 6 位,小数点后 3 位,999.999

char -- 固定长度字符串类型,char(10) => 不足 10 位的话会补足到 10 位,比如身份证号

varchar -- 可变长度字符串类型,char(10) => 不足 10 位不会补足,性能低于 char,比如个性签名

text -- 字符串,适用于大文本内容,例如文章内容

date -- 日期类型,yyyy-MM-dd
+ +

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 显示所有数据库
show databases;

-- 使用某数据库
use dbname;

-- 创建一个数据库
create database dbname;

-- 删除某数据库
drop database dbname;

-- 将某数据库的编解码方式设置为 utf8 以便支持中文字符
alter database dbname character set utf8
+ +
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
# 查看当前数据库中的所有表
show tables;

# 创建表
create table tbname(id int,name varchar(20),sex char(1));

# 查看某个表的格式
desc tbname;

# 查看某个表中的数据
select * from tbname;

# 向某表中新增一条数据
insert into tbname (id,name,sex) values (1,'小明','0');
# 注意,如果一条数据的每一个字段都要修改,则 tbname 后 values 前的内容(列名)可以省略

# 修改数据
update tbname set name='小王', sex='1' where id=1;

# 删除数据
delete from tbname where id=2;

# 删除表
drop table tbname;

# 修改表:改变字段名称
alter table tbname change name username varchar(20);

# 修改表:删除字段
alter table tbname drop sex;

# 修改表:添加字段
alter table tbname add achievement double(5,2);
+ +

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT
team_id, SUM(achievement)
FROM
students
WHERE
sex = 0
GROUP BY
team_id
HAVING
SUM(achievement) > 100
ORDER BY
SUM(achievement) DESC
LIMIT 2;
+ +

规范

基础规范

    +
  1. 大部分场景适合 Innodb,部分日志写入场景适合 tokudb 或 myrockets 引擎
  2. +
  3. 禁止大文件大照片直接存储在 Mysql 下(考虑下 mosaic)
  4. +
  5. 由于 emoji 表情等使用场景的普及,大部分存储需求可能需要使用 utf8mb4 来进行存储,utf8mb4 是 utf8 的超集
  6. +
  7. 高并发的互联网使用场景下,架构设计原则应该是 “解放 DB 的 CPU,将计算上移到服务层”,防止高并发的场景下,这些功能拖死数据库
  8. +
  9. 表名使用小写,表名中尽量不包含特殊字符或 / 符号等
  10. +
  11. 为方便业务开发以及后期维护,应该简单明了地标记用途
  12. +
  13. 数据表字段最好也有中文注释
  14. +
+

SQL 规范

    +
  1. 避免负向查询,主要指 not in,<>,not like 等,因为如果查询条件中只有这类条件,会导致全表扫描
  2. +
  3. % 开头的模糊查询,会导致查询无法使用索引来定位数据,会导致全表扫描
  4. +
  5. 如果只 select 索引字段,或者只 select 索引字段和主键,会全扫描索引树找到相应字段,但这不是利用索引来定位数据,因为要查询的字段就在索引树上
  6. +
  7. 模糊查询利用索引定位数据的解决方案:反转模糊查询的字段,但是对于 “%keyword%” 的索引,此方法无效
  8. +
+
1
2
3
4
5
select * from student where name like '%三';

-- 我们可以改造为

select * from student where reverse(name) like reverse('%三');
+ +
    +
  1. 如下
  2. +
+
1
2
3
4
5
6
7
select id from xxx where from_unixtime(start_day)>='2020-10-08';

-- 这会导致全表扫描

-- 正确写法是

select id from xxx where start_day>=unix_timestamp('2018-08-14');
+ +
    +
  1. 一般情况下,手机号推荐使用 varchar(32) 存储,因为会有地区等属性;如果 phone 是 varchar,则如下写法会触发隐式转换,导致全表扫描
  2. +
+
1
select id from xxx where phone = 15635638290;
+ +

(隐式转换的情况下,全表扫描一般是发生在字符类型字段,数字类型一般不会影响执行计划)

+
    +
  1. 避免使用 select *

    +
      +
    • select * 会获取不必要的列,这会增加 cpu,io,net 的消耗
    • +
    • 在有索引覆盖的情况下,会导致无法有效利用覆盖索引
    • +
    • 程序开发过程中容易因为忘记添加或删除字段,导致出现 bug
    • +
    +
  2. +
  3. 分片库的场景下,查询不带分片键容易引起查询放大的问题,会导致所有分片做无效查询

    +
  4. +
  5. 不允许在主库上执行统计 SQL(count/sum)

    +
  6. +
  7. 不允许大表使用 join,子查询

    +
  8. +
  9. 不允许超过 3 个表的 join 查询

    +
  10. +
+

image-20220320100805557

+

处理 bug

ERROR 1819 (HY000)

Your password does not satisfy the current policy requirements

+
+

其实这是 mysql 的默认安全级别导致的

+
+
1
2
3
4
5
6
-- 查看 mysql 的默认安全级别
show variables like "%validate%";

-- 由于是日常练习,所以可以将安全策略和密码长度的要求降低
set global validate_password.policy=0;
set global validate_password.length=4;
+ +
    +
  • 搞定~
  • +
+

ERROR 1698 (28000)

Access denied for user root@localhost

+
1
2
3
4
5
6
7
8
9
10
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

# 在 [mysqld] 下写入
skip-grant-tables
# 保存退出,这样你就能免密接入 mysql

service mysql restart

mysql -u root -p
# 遇见输入密码的提示直接回车即可
+ +
1
2
3
4
5
use mysql;
flush privileges;
ALTER user 'root'@'localhost' IDENTIFIED BY 'newpassward';
flush privileges;
quit
+ +
    +
  • skip-grant-tables注释或删除,更改密码成功~
  • +
+
+
    +
  • 现在,如果你在尝试接入 mysql 时依然报错,则需要再次让skip-grant-tables生效,并再次执行service mysql restart,无密接入 mysql 后执行如下操作
  • +
+
1
2
3
4
5
6
7
8
9
use mysql;
select user, plugin from user;

-- 将 root 的 plugin 字段改为和其他 user 的 plugin 字段一致,比如
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'mysql';

-- 复查确认是否修改成功
select user, plugin from user;
quit
+ +
    +
  • skip-grant-tables注释或删除,更改密码成功~
  • +
+

参考了

    +
  1. https://www.cnblogs.com/cpl9412290130/p/9583868.html
  2. +
  3. https://blog.csdn.net/r527665047/article/details/107056941
  4. +
  5. https://my.oschina.net/u/4327623/blog/4325113
  6. +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/08/11/c-toturial/index.html b/2021/08/11/c-toturial/index.html new file mode 100644 index 0000000..d5f0255 --- /dev/null +++ b/2021/08/11/c-toturial/index.html @@ -0,0 +1,248 @@ + + + + + + + + + C 语法入门 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

C 语法入门

+
+ +
+
+

GNU/Linux(64位)+ GCC_11.2.0

+
+

数据类型

4 种基本数据类型
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
数据类型中文名称所开辟的存储空间的大小(Byte)
int整型4
float单精度浮点型4
double双精度浮点型8
char字符型1
+
4 种限定符(施加于基本数据类型)

shortlongsignedunsigned

+

signed 和 unsigned 用于限定所有整型和字符型(包括被 short 或 long 限定了的整型)

+
给数据类型起别名,使用 typedef

image-20220509221931771

+

sizeof 根据数据类型获取数据元素所占内存空间的字节数

1
2
3
4
sizeof( ElemType );

// 举个例子
printf("%d\n", sizeof(int)); // 4
+ +

变量

可将变量理解为存储数据的容器

+
变量的命名规则
    +
  1. 字母或下划线开头,可包含数字
  2. +
  3. 字母严格区分大小写
  4. +
  5. 以下划线开头的变量名是有可能和系统定义的变量名冲突的
  6. +
  7. 拒绝使用关键字和保留字
  8. +
+
变量的声明 & 初始化
1
2
int foo;  // 声明变量
foo = 1; // 初始化变量
+ +

变量的声明和初始化可合二为一

+
1
int foo2 = 2;
+ +

只声明不初始化的变量其所在内存是脏的

+

常量

一旦初始化,则其值无法被改变的量

+
字符常量

字符 + 单引号 <=> 字符常量

+

字符常量参与运算时,实际上是其对应的 ASCII 码参与运算

+
1
printf("%d\n", 1 + '0'); // 49
+ +
字符串常量

请参考这里

+

运算符与表达式

算术运算符

+-*/%

+

++--

+

除法运算 & 取模运算(Python3 vs C)

+
赋值运算符

+=-=*=/=%=

+

=

+
关系运算符

==!=>>=<<=

+
逻辑运算符

&&||!

+
位运算符

按位与&、按位或|、按位异或^、按位取反~

+

「左移<<、右移>>」=> 保持符号位不变 !

+
+

如果你想看二进制,可以使用 C++ 的 bitset

+
+

eg:

+
1
2
short int a = 6;
cout << bitset<sizeof(a) * 8>(a) << endl;
+ +
三目运算符

expression1 ? res1 : res2

+

类型转换

在同一表达式中出现不同类型变量时,为了得出更精确或更能描述实际情况的结果

+

表达式中的变量们会根据某种规则,统一转换成某种类型

+
自动的类型转换
+

数据位短的类型会向数据位长的类型转换(可使用 C++ 的 typeid()验证)

+
+

image-20220509085908279

+
+

相比于 int,unsigned int 的数据位多一个

+
+

image-20220509090104459

+
+

char 和 short int 统一向 int 转换

+
+
1
2
3
4
short int a = 1;
char b = 'x';

printf("%d\n", sizeof(a + b)); // 4
+ +
+

有可能损失数据精度

+
+
1
2
3
4
5
6
7
float a = 100.5f;
int b = a;
printf("%d\n", b); // 100, 损失了数据精度

float c = 100;
int d = c;
printf("%d\n", d); // 100, 没损失数据精度
+ +

控制

条件判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (表达式1) {
...
} else if (表达式2) {
...
} else {
...
}

---

switch (表达式) {
case 常量表达式1: ...; break;
case 常量表达式2: ...; break;
case 常量表达式3: ...; break;
default: ...;
}
+ +
+

一个良好的代码风格是:永远都加上花括号,即使只有一行代码。

+
+
循环
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
// 当循环次数不确定,较适合用 while 循环
while (表达式) {

if () {
continue;
} else {
break;
}

}

---

// 当确定循环次数,较适合用 for 循环
for (表达式1; 表达式2; 表达式3) {
...
}

// 等价于
表达式1;
while (表达式2) {
...
表达式3;
}

// 因此如下是一种死循环
for (;;) {
...
}

---

// 先斩后奏型循环
do {

if () {
continue;
} else {
break;
}

} while (表达式);
+ +

函数

1
2
3
4
5
// 对于无参函数,参数列表建议写为 void
返回值类型 函数名 (参数列表) {
...
return 返回值;
}
+ +

返回值类型默认为整型

+

image-20220508223746456

+

抽象、封装、复用

+

开发者得以将更多时间用于专注业务逻辑的实现

+

作用域

+

除全局作用域外,一个花括号就能形成一个作用域

+
+

image-20220508232147708

+

image-20220508232342233

+

image-20220508233126388

+

结论:

+

外层作用域无法访问内层作用域

+

内层作用域可以访问外层作用域

+

生存期

1
2
3
4
5
6
7
8
9
int foo() {
int a = 2;
}

int main() {
int a = 1;
foo();
printf("%d\n", a); // 1
}
+ +

静态变量

相当于拥有局部作用域的全局生存期变量

+

image-20220508231315863

+

指针

指针与 const

https://liupj.top/2021/11/18/pointer&const/

+
指向函数的指针
1
2
3
4
5
6
7
8
9
10
11
int add(int a, int b) {
return a + b;
}

int main() {
int (*ptr)(int a, int b);

ptr = add;

printf("%d\n", ptr(1, 2)); // 3
}
+ +

递归

1
2
3
4
// 直接递归(形式上是自调用)+ 单递归入口
void r() {
r();
}
+ +
1
2
3
4
5
6
7
8
9
10
11
// 直接递归(形式上是自调用)+ 多递归入口

int i = 0;

void r() {
if (i < 2) {
r();
r();
i++;
}
}
+ +

代码优化思路:将全局变量 i 改为静态变量,放到 r() 的函数体中,以获得更好的封装性和可读性

+

image-20220509212113718

+
+

本文不介绍间接递归

+
+

数组

image-20220509214046922

+
数组的声明与初始化
1
2
int arr[4] = { 1, 2, 3, 4 };
// 数组容量可省略不写,由元素个数决定数组容量
+ +
1
2
3
4
5
6
7
8
9
10
11
int arr[4] = { 0 };
for (int i = 0; i < 4; i ++) { printf("%d", arr[i]); } // 0000
printf("\n");

int arr2[4];
for (int i = 0; i < 4; i ++) { printf("%d", arr2[i]); } // 乱七八糟
printf("\n");

int arr3[4] = { 1 };
for (int i = 0; i < 4; i ++) { printf("%d", arr3[i]); } // 1000
printf("\n");
+ +
数组与指针

https://liupj.top/2022/04/05/array&pointer/

+

结构体

数组中元素的数据类型相同,结构体中元素的数据类型可以不同

+
1
2
3
struct {
只能有成员变量
}
+ +

参考文档

c reference

+

c++ reference

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/08/31/01/index.html b/2021/08/31/01/index.html new file mode 100644 index 0000000..5e89e90 --- /dev/null +++ b/2021/08/31/01/index.html @@ -0,0 +1,186 @@ + + + + + + + + + 二进制 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

二进制

+
+ +
+

二进制的存储

+

无论内部存储器还是外部存储器,都是以 2 进制的方式进行存储的

+

就如同一张巨大的 excel 表格,每个格子中都可以存放一个 1 或一个 0

+
+

一大堆 0 和 1 怎么读呀 ?

不妨思考一下:一大堆 0 和 1,你咋知道几个 0 和 1 才表示一个数字 ?显然,如果事先规定好每 x 个 0 和 1 表示一个数字,那不就行了。

+

所以:我们不妨让每 8 位表示一个数字,多则溢出舍弃

+

存储单位的转换

1
2
3
4
5
6
7
8
9
10
11
1 bit				# 1 位

1 Byte = 8 bit # 1 字节

1 KB = 1024 Byte

1 MB = 1024 KB

1 GB = 1024 MB

...
+ +

2 进制加法

+ + + + + + + + + + + + + + + + + + + + +
10 进制2 进制8 进制16 进制
1012181161
012345678901012345670123456789abcdef
+
1
2
3
4
   1 0 0 1 0 0 1 1
1 0 1 0 1 0 0 1
-------------------
1 0 0 1 1 1 1 0 0
+ +

思考:计算机只能保存 01 那咋表示负数呢?

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
借用数学中 “用已知来研究未知” 的思想

现实生活中:

数字前添加 + 表示正数,+ 可省略不写

数字前添加 - 表示负数

比葫芦画瓢,既然我们用每 8 位表示一个数字,那么我们可不可以用第 1 位来表示正负号呢 ?比如:

0 代表正数

1 代表负数

按照我们的想法,数字 -1 就被表示成了

1 0 0 0 0 0 0 1

验证一下我们的想法,比如计算一下 1 + (-1)

0 0 0 0 0 0 0 1
+ 1 0 0 0 0 0 0 1
------------------
1 0 0 0 0 0 1 0 => -2

验证失败,故 => `在计算机中,负数不能直接表示成其二进制的方式`

重来!我们期望 00000001 + (-1的二进制表示) => 00000000,不妨设 -1 的二进制表示为 x

0 0 0 0 0 0 0 1
+ x => 显然这里的 x 是不存在的 !思考怎样才能让这个 x 存在 ?
-------------------
0 0 0 0 0 0 0 0
+ +
+

既然:我们使用 8 位表示一个数字,多则溢出舍弃

+

那么我们不妨从“多则溢出舍弃”这里寻找突破口 !

+
+
1
2
3
4
5
6
7
8
9
10
11
要想让 x 存在,那么我们只能思考:能否给被加数或结果添加溢出位,以达到让 x 存在的目的

显然如果给被加数添加溢出位,那么 x 仍然不存在

而如果给结果添加一个溢出位 1,即将结果写成 100000000,x 就存在了!

0 0 0 0 0 0 0 1
+ 1 1 1 1 1 1 1 1 <=> x
-------------------
(1) 0 0 0 0 0 0 0 0

+ +

故:-1 在计算机中就用 11111111 来表示(即直观上用 -127 表示了 -1)

+
+

为了庆祝负数在计算机中有了合理的表示形式,诞生了以下三个名词,以 -1 为例

+

原码:10000001

+

反码(符号位不动,其余位取反):11111110

+

补码(反码加一):11111111

+
+

ok,到此为止问题解决,结论:计算机中,负数以补码的形式来存储

+
+

意外的收获:我们顺带解决了 -0 和 +0 在计算机存储中的表示方式不一样的问题

+

0 => 00000000

+

-0 ==原=> 10000000 ==反=> 11111111 ==补=> 100000000(1溢出)=> 00000000

+

注意:

+

在原码反码补码的问题上,一般不讨论正数,因为这三个概念本身就只是问了让负数在计算机中有合理的表示而诞生的

+

非要说的话,那正数的原反补都是该正数的二进制

+
+

习题

1
cout << (unsigned int)(-1)
+ +

先不管无符号这一回事,有符号的 -1 是以补码存储的

+

原:10000000 00000000 00000000 00000001
反:11111111 11111111 11111111 11111110
补:11111111 11111111 11111111 11111111

+

所谓无符号,就是将符号位变为数据位

+

所以输出结果就是

+

11111111 11111111 11111111 11111111

+

即:2^32 - 1

+
+

补充知识

背景:在计算机中,数据都是以二进制的形式存储的

+

:对于有符号数,请写出 1000 0000 的十进制表示形式

+

分析

+

有符号 => 若 1 是符号位 => 则说明这是一个负数 => 计算该负数的原码:1000 0000 => 0111 1111 => 0000 0000 => 得出 0,这与该数是个负数相矛盾 => 说明 1 是数据位 => 说明符号位溢出了 => 若符号位是 0,即:0 1000 0000 => 128 => 与最大值 2^7-1,即 127 相矛盾 => 说明符号位是 1,即:1 1000 0000 => 计算该负数的原码:1 1000 0000 => 1 0111 1111 => 1 1000 0000 => -128

+

补充知识

背景:

+

十进制的科学计数法表示,eg:十进制的 1.5 => 1 * 10^0 + 5 * 10^(-1)

+

二进制的科学计数法表示,eg:二进制的 1.1 => 1 * 2^0 + 1 * 2^(-1) => 这也就转成了十进制 !!!

+

二进制的科学计数法表示,eg:二进制的 11.111 => 1 * 2^1 + 1 * 2^0 + 1 * 2^(-1) + 1 * 2^(-2) + 1 * 2^(-3) => 这也就转成了十进制 !!!

+

分析:

+

不难发现:有的十进制数是无法用二进制精确表示的

+

比如十进制的 0.1 就无法用二进制精确表示,1/16 + 1/32 + 1/256 + … 约等于 0.1,你只能无限趋近 0.1 但永远也到不了 0.1

+

结论:

+

因此,在以二进制的形式存储数据的计算机中,浮点数存在误差

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/09/12/rss/index.html b/2021/09/12/rss/index.html new file mode 100644 index 0000000..90edec2 --- /dev/null +++ b/2021/09/12/rss/index.html @@ -0,0 +1,203 @@ + + + + + + + + + RSS 新手入门指南 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

RSS 新手入门指南

+
+ +
+
+

本文基于这篇文章,对其进行了精简和提炼并补充记录了笔者实践 rss 的步骤,在此感谢这篇带我入门 rss 的文章的作者,致敬让我们的生活更方便的每一位开发者

+
+

为什么会诞生 rss 这么个东西(有需求,才会有产出)

    +
  • 生活中,你获取信息的方式可能是这样的
      +
    • 比如你想获取一个歌手的最新消息,可能就需要关注他的(微博、B站、抖音、……),于是你就需要下载安装这些平时你可能并不使用的 APP,并在订阅关注该歌手的同时给这些新安装的 APP 打开通知权限
    • +
    • 于是这些 APP 就会频繁地往你手机下拉通知面板中发送各种消息,如果你没给手机设置静音或免打扰模式,你的工作就很可能被这些时不时主动发送到你手机上的消息打断甚至打乱
    • +
    • 当你有一会儿没看你手机的下拉通知面板,里面就很可能接收到了一大堆消息,这些消息不仅杂乱无章,并且很可能含有很多由推荐算法和商业广告发来的垃圾消息,导致你很难快速地定位到你想知道的消息
    • +
    • 甚至你很可能一不小心就点到了你手机下拉通知面板的清空按钮,造成你可能就错过了你想知道的消息
    • +
    +
  • +
  • 总结
      +
    1. 你不想安装一大堆你并不使用的 APP
    2. +
    3. 你需要这样一个入口
        +
      1. 这个入口中拥有所有你想要及时获取的消息,而没有(各种推荐算法,商业广告)发来的垃圾消息
      2. +
      3. 这个入口中的消息可以被很好地归类,而不是像手机下拉通知面板中那样消息杂乱无章
      4. +
      5. 这个入口中的消息可以被很好地保存下来,但每条消息本身都有“已读”和“未读”两种状态
      6. +
      7. 这个入口可以在任何时候被你主动打开查阅,而不是像手机下拉通知面板中那样主动打扰你的手机
      8. +
      +
    4. +
    +
  • +
+

什么是 rss?

+

Really Simple Syndication

+
+
    +
  • rss-百度百科
  • +
  • rss 的用途:资讯聚合,并且它满足了上述总结中提到的所有需求
  • +
  • 别的不说,用 rss 来追番剧、追漫画、追星,可太舒服了……
  • +
+

我怎么用的 rss?

    +
  • 我的需求:

    +
      +
    • 使用 rss 订阅一些我喜欢的网络博客和其他平台的内容创作者
    • +
    • 让别人可以通过 rss 订阅我的网络博客
    • +
    +
  • +
  • 如何实现我的第一个需求(以订阅阮一峰大佬的博客为例):

    +
      +
    • 首先,在手机上安装开源应用商店F-Droid,然后从该应用商店中安装一款好用的 rss 阅读器,我选择:Feeder,开源软件,其源码仓库有以下两个

      + +
    • +
    • 然后,给 chrome 浏览器安装插件RSSHub Radar,开源软件,源码仓库如下

      + +
    • +
    • 点击阮神博客右上角 WIFI 形状的“订阅Feed”按钮,跳转页面,复制阮神提供的订阅链接

      +
    • +
    • 打开手机上安装的 Feeder,点击右上角添加订阅,将链接粘贴进去,回车确认即可,这样就订阅了阮神的博客

      +
    • +
    • 在 Feeder 阅读器中自行分类管理

      +
    • +
    • rss 源 + rss 阅读器,这便是 rss 最简单的用法

      +
    • +
    +
  • +
  • 第二个需求,对我的博客网站做了如下配置,搞定

    +
  • +
+
1
2
# blog:/
npm install hexo-generator-feed --save # https://github.com/hexojs/hexo-generator-feed
+ +
1
2
3
4
5
6
# blog:/source/_data/yun.yml
social:
- name: RSS
link: /atom.xml
icon: icon-rss-line
color: orange
+ +

怎么获取 rss 源

+

实际上,本身提供 rss 订阅的网站实在是太少了,这也是 rss 难以流行起来的一大原因

+
+
    +
  1. 一些网站平台会提供 rss 链接,你可以自行寻找,或借助 chrome 插件RSSHub Radar来寻找

    +
  2. +
  3. 那些不提供 rss 的网站,上RSSHub看有没有办法生成,但是!官方提供的 RSSHub 域名已经被墙了,解决这个问题不难,你可以科学上网,自建服务替换官方域名,或白嫖别人搭建好的服务(不推荐)

    +
  4. +
  5. 技巧:你可以 百度/Google 关键词「Welcome to RSSHub!」就能轻松找到不少别人搭好的 RSSHub 服务了,域名一换,搞定

    +
  6. +
+

Todo

    +
  • 自建 RSSHub 服务,替换官方域名(以下为这篇文章的拷贝,笔者尚未实践,因为能**)

    +

    你首先需要去腾讯云免费注册一个账号:https://cloud.tencent.com/

    +

    注册好之后登录,点击左上角产品 » 基础 » 找到「云开发」

    +

    点击进去,选择免费开通,然后在弹出的页面,新建一个环境,并点击更多

    +

    第一次使用腾讯云搭建 RSSHub 的话,需要先新建空模板,建好空模板之后点击「更多」才有 RSSHub 和其他的模板

    +

    你会发现,这里提供了 RSSHub 的一键搭建服务!

    +

    选中它并点击下一步

    +

    选择地区+自己给环境命名(这个随意)

    +

    然后选择「系统默认环境」即可,接着点击立即开通

    +

    然后切换到左边「我的应用」一栏,耐心等待等待等待等待等待,别看显示的预计 2-3 分钟,实际大概需要等待 10 分钟

    +

    自己多刷新几下,一直耐心等待到,状态显示为「运行中」则说明部署成功了

    +

    然后配置 RSSHub Rader 域名,无论你是白嫖别人的,还是自建的:复制 RSShub 页面的地址,打开 RSSHub Rader,设置到自定义域名

    +

    OK,你终于做好一切准备,基本上可以畅游 RSS 的世界了

    +
  • +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/09/22/ln/index.html b/2021/09/22/ln/index.html new file mode 100644 index 0000000..e5526d6 --- /dev/null +++ b/2021/09/22/ln/index.html @@ -0,0 +1,175 @@ + + + + + + + + + 硬链接和软链接 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

硬链接和软链接

+
+ +
+

什么是“链接” ?

+

记得 2008 年刚接触 windows 的时候,我“卸载”软件都是这么干的 => 将桌面上软件的图标移动到回收站,清空回收站,然后我就觉得软件已经被我卸载了

+

现在看来,当时的我只是删除了 windows 上应用软件的一个快捷方式而已,并没有将软件真正从我的电脑上卸载

+

而那时被我删掉的快捷方式就是“链接”的一种实现,显然,“链接”这种东西早就被应用在了计算机中,在我们的生活中扮演着不可或缺的角色

+

所以,你可以将“链接”狭义地理解成 windows 上的快捷方式,但接下来对“链接”的用途做更多的阐述

+
+

当用户独占计算机,经常用“链接”干什么 ?

+

这里讲的是大多数普通人在日常使用场景中会有意无意使用“链接”的情况

+
+

对于 windows 用户

+
    +
  • 快捷方式就是“链接”的一种实现,我们可以在一个容易找到的地方(比如桌面)创建应用的快捷方式来方便我们快速启动应用程序,而不是每次都逐层目录寻找应用程序到底在哪
  • +
+

对于 linux 用户 和 macOS 用户

+
    +
  • 和在 windows 中给应用程序创建快捷方式类似,我们通常会在一个容易被找到的目录中给一些目录层次较深的文件创建“链接”,以此方便我们的访问
  • +
  • 除此以外,我们还经常使用“链接”处理一些库的版本兼容性的问题
  • +
+

上述提到的链接,均指软链接(也称符号链接 symblic_link),在 linux 中链接的常见用法如下

+

image-20210922102919472

+

为什么需要有“链接”这种功能 ?

    +
  1. 首先你得知道,同一个操作系统是允许多个用户同时接入共享使用的

    +

    从“分时操作系统”时代起,就已经开始支持多用户宏观同时微观分时地访问操作系统了,就是说一个操作系统可以有多个用户,这些用户可以共享地使用计算机中的资源,甚至他们可以同时接入操作系统

    +

    多用户同时接入操作系统时,尽管我们感觉上像是自己独占整个系统但其实并不是(比如同一个 windows 上超级管理员和普通用户可以同时登入只不过系统微观上分时服务罢了)

    +

    听不懂也不没关系,有一个视频很形象,就是

    +
  2. +
  3. 其次你还得知道,什么叫共享

    +

    共享和文件复制是不一样的,用户共享文件意味着只有一份文件

    +

    比如系统中有一份独一无二的文件,用户 A 对其拥有读写权限,用户 B 对其也拥有读写权限,就说这两个用户共享该文件

    +

    一旦用户 A 修改了该文件的数据,那么用户 B 也可以看到文件数据的变化

    +
  4. +
  5. “链接”是为了让文件共享更安全而实现的,如果没有链接这种功能

    +

    举个例子,你家两个孩子,你有一个弟弟,但是你家家境普通,父母只能给你俩买一台电脑,只有你爹能用电脑上的管理员帐号,他给你俩一人开了个普通用户帐号

    +

    期末复习周,你爹拷了一份往年试卷放到了电脑中让你俩共享,你弟登入电脑一看,我去!这么多卷子,不写!哐哧你弟就给删了,假如没有“链接”这种东西,晚上你登你帐号还能看到卷子吗?不能!

    +
  6. +
  7. 但实际情况是卷子并没有被真正删除,虽然你弟看不到卷子且承担着可能挨打的风险但你依然可以看到卷子,这正是因为操作系统在实现文件共享功能的时候,为了防止共享文件被某个用户误删除,实现了“链接”的功能和基于“链接”的文件共享方式,链接分为“软链接”和“硬链接”

    +
  8. +
+

什么是硬链接,什么是软链接 ?

+

节选自王道-操作系统

+
+

image-20210922163152322

+

image-20210922163606353

+

image-20210922164024964

+

软链接和硬链接的异同

+

首先明确:由于用软链接的方式访问共享文件时需要查询多级目录,所以就会产生多次磁盘 I/O,因此理论上用软链接访问文件速度更慢

+
+
1
2
3
4
5
6
# 这里我们比较文件使用如下命令

ls -li

# -l, --long display extended file metadata as a table
# -i, --inode list each file's inode number
+ +

我们先创建一个普通文件,然后给该文件创建一个硬链接,看看区别

+

image-20210922172127580

+

hard.txt 和 src.txt 的 inode 值一样,都为 19407417,说明了它们指向物理磁盘中的同一个区块(同一索引节点)

+

且二者文件类型和权限完全相同

+

image-20210922172515608

+

image-20210922174914922

+

到此为止,已经印证了硬链接(基于索引节点的共享方式)的原理

+

接下来我们进行第二个实验:我们创建一个普通文件,然后给该文件创建一个软链接,看看区别

+

image-20210922175147752

+

现在我们很清楚地看到,软链接确实是 Link 类型的文件,权限为 777,且指向 src.txt

+

接下来我们再创建一个硬链接,并尝试删除 src.txt

+

image-20210922175705326

+

硬链接仍然有效,符合预期;软连接是一种新类型的文件(Link 类型)保存着它所指向文件的全路径,访问时会替换成绝对路径,我们 rm 掉了 src.txt 自然用软链接就找不到该文件

+

我们再向这个软链接写点东西(将这个软链接替换后的绝对路径文件创建出来)

+

image-20210922180847712

+

看吧,src.txt 又出现了,成功印证软链接访问时会替换成绝对路径的想法

+

image-20210922181433398

+

image-20220504155523985

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/10/02/staticLib-dynamicLib/index.html b/2021/10/02/staticLib-dynamicLib/index.html new file mode 100644 index 0000000..a6bcd21 --- /dev/null +++ b/2021/10/02/staticLib-dynamicLib/index.html @@ -0,0 +1,126 @@ + + + + + + + + + 浅谈静态库和动态库 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

浅谈静态库和动态库

+
+ +
+
+ +
+

原文链接:https://zhuanlan.zhihu.com/p/71372182

+
+
+ +

1_staticLib_dynamicLib

+

2_staticLib_dynamicLib

+

3_staticLib_dynamicLib

+

4_staticLib_dynamicLib

+

5_staticLib_dynamicLib

+

6_staticLib_dynamicLib

+

7_staticLib_dynamicLib

+

8_staticLib_dynamicLib

+

9_staticLib_dynamicLib

+

image-20211002195026553

+

image-20211002195112259

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/11/15/huffman/index.html b/2021/11/15/huffman/index.html new file mode 100644 index 0000000..f9d2d3f --- /dev/null +++ b/2021/11/15/huffman/index.html @@ -0,0 +1,267 @@ + + + + + + + + + 计算机数据的编解码与哈夫曼树 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

计算机数据的编解码与哈夫曼树

+
+ +
+

前言

    +
  • 你可能会遇到这样的情况
  • +
  • 某天,你像往常一样打开电脑,准备撰写文稿,这时,你的一个朋友给你发来一个信息:“Hey!快看看我新编的故事写得怎么样 ?!”,然后就给你发来了一个 .txt 文档
  • +
  • 你饶有兴致的接收了这个文档,然后鼠标双击打开了它…
  • +
+

image-20211115144145486

+
    +
  • 如果你确实遇到了诸如此类修仙三百年也不一定看得懂的文本内容,并且不知道如何处理,那就继续阅读本文吧~
  • +
  • 别忘了给你的朋友回复一句:“老哥写得牛批 !”
  • +
+

我假设你已经看了YOUTUBE上的计算机科学速成课

+

举个日常生活中的例子

    +
  • 以使用电脑写英语作文为例,我们会连续不断地敲击键盘,向电脑中输入英文字母
  • +
  • 当 ctrl+s 保存时,电脑就会将我们输入的这些英文字母所转换成的 0 和 1 们存储到我们电脑的硬盘中
  • +
  • 当下次再打开这个英语作文时,电脑就会从硬盘中读取出上次保存的这些 0 和 1,并将它们转换回正确的英文字母,进而显示到屏幕上
  • +
+

什么是 「编码、解码」 ?

    +
  • 在上面这个例子中

    +
      +
    • 英文字母被转换成一堆 0 和 1 的过程就被称为编码
    • +
    • 这些 0 和 1 被转换回英文字母的过程就被称为解码
    • +
    +
  • +
  • 可以用数学中的 「函数与反函数」 的知识来理解 「编码与解码」,基于上面这个例子

    +
      +
    • 将英文字母看作自变量,通过某种编码方式(映射方式)就能得到一堆 0 和 1
    • +
    • 将这堆 0 和 1 看作自变量,通过解码方式(编码方式的反函数)就能得到正确的英文字母
    • +
    +
  • +
+

文件乱码的处理方式

    +
  • 所以:
      +
    • 文件乱码的原因,就是所选的编解码方式错误,比如文章开头图片中的编解码方式显示在右下角,是 UTF-7,其实只需更改为正确的编解码方式 UTF-8 即可
    • +
    +
  • +
+

image-20211115172050165

+
+
+

以下为补充知识

+
+

固定长度编码 & 可变长度编码

    +
  • 固定长度编码:每个字符用相等长度的二进制位表示
  • +
  • 可变长度编码:不同字符允许用不等长的二进制位表示
  • +
+

对一个英文字母进行固定长度编码,它占几个 bit ?

    +
  • 计算机中的一个 「位(bit)」 可以存 0,也可以存 1,就是说一个位能区分两种状态

    +
  • +
  • 一共有 26 种英文字母,就需要用 0 和 1 来区分表示 26 种状态,显然需要更多的位

    +
  • +
  • 2^4 = 16,2^5 = 32,16 < 26 < 32,所以需要至少 5 个 bit 才能区分表示出 26 种状态

    +
  • +
  • 为了使用方便,我们规定用 1 Byte 的空间存储一个英文字母,即一个英文字母编码后,所占的空间大小为 8 bit(考研默认每个字符占 8 位

    +
  • +
+

字符集的概念

    +
  • 英文字符少,每一个英文字符都包含于 => ASCII字符集
  • +
  • 中文字符多,每一个中文字符都包含于 => Unicode字符集
  • +
+

备注

    +
  • 对于同一个字符集,可以采用不同的编解码方式,如 UTF-8、UTF-16…
  • +
  • 对一个字符采用不同的编码方式进行编码,所得的二进制数所需的存储空间大小是不一样的
  • +
+
+
+

以下为进阶知识,涉及 「哈夫曼树(最优二叉树)」、「哈夫曼编码(适用于数据压缩)」

+
+

从一个例子看 「固定长度编码的缺陷」

    +
  • 小渣和老渣是计算机系的两个学生,他们也学习了编解码的知识,于是打算在期末考试中用编解码的知识打暗号作弊(Tips:考试作弊已入刑法,违法必究)

    +
  • +
  • 他俩的思路是这样的:

    +
      +
    • 选择题一共有 A、B、C、D 四个选项
    • +
    • 将这四个选项进行二进制编码,得到答案选项的二进制表示
    • +
    • 用 「咳嗽」 表示 0,用 「打嗝」 表示 1
    • +
    • 然后就可以用连续的咳嗽和打嗝来传递信息,经过解码,答案就出来了
    • +
    +
  • +
  • 若采用固定长度编码:

    +
      +
    • 一共有 A、B、C、D 四种选项,要用 0 和 1 区分出这四种状态,每个答案选项就至少需要用 2 个 bit 来表示
    • +
    • 比如
        +
      • A <=> 00
      • +
      • B <=> 01
      • +
      • C <=> 10
      • +
      • D <=> 11
      • +
      +
    • +
    +
  • +
  • 怎么用呢 ?

    +
      +
    • 比如小渣要把 100 个答案传给老渣,小渣的答案中有(80 个 C、10 个 A、8 个 B、2 个 D)
    • +
    • 那他一共需要传递 80 * 2 + 10 * 2 + 8 * 2 + 2 * 2 = 200 个二进制位
    • +
    • 也就是需要咳嗽和打嗝 200 次,才能传完答案(监考老师热心关怀的概率:100%)
    • +
    • 小渣打了个冷颤,开始思考如何让传递的二进制位的个数尽可能地少
    • +
    +
  • +
+

分析这种缺陷的原因

    +
  • 上面这种固定长度编码的方式可以用 「树」 来表示
  • +
+

image-20211115185423296

+
    +
  • 80 * 2 + 10 * 2 + 8 * 2 + 2 * 2 = 200 正好是树的带权路径长度 WPL
  • +
  • 于是问题就转化为了 「如何让二叉树的带权路径长度最小」 ?
  • +
+

最优二叉树(哈夫曼树)

+

让二叉树的带权路径长度最小 ?

+

小渣灵光一现,构建最优二叉树 !(哈夫曼树 !)

+

明确:哈夫曼树(最优二叉树)不唯一 => 哈夫曼编码不唯一

+
+
    +
  • 把选项看作结点
  • +
  • 把选项出现的频度看作结点的权值
  • +
  • 用这 4 个带权结点构建最优二叉树(哈夫曼树)
  • +
  • 这样就得到了 WPL 最小的树,也就得到了一套哈夫曼编码(属于可变长度编码)
  • +
  • 能够确保传递的二进制信息最少(即实现了数据压缩)
  • +
  • 哈夫曼编码属于 「前缀编码」,即没有一个编码是另一个编码的前缀(否则传递的数据会有二义性)
  • +
+

image-20211115190829597

+
    +
  • 相比于之前的 200 次,若采用哈夫曼编码,小渣只需咳嗽打嗝 130 次,就可以传递 100 个答案,还是十分搞笑的
  • +
+

哈夫曼编码广泛用于数据的压缩

    +
  • 比如 26 个英文字母的使用频率是不同的,对于一段英文,如果它采用的是 ASCII 编码(属于固定长度的编码)
  • +
  • 那么就可以将这段英文采用哈夫曼编码(用这 26 个权值不同的结点构建哈夫曼树,可得哈夫曼编码)进行重新编码
  • +
  • 就实现了数据压缩
  • +
+

image-20211115120514176

+
+
+

以下为数据结构专业知识 ~ 哈夫曼树(最优二叉树)

+
+

啥叫 「结点的权」 ?

    +
  • 有某种现实含义的数值,比如表示结点的重要性等
  • +
+

啥叫 「结点的带权路径长度」 ?

    +
  • 从根结点到该结点的路径长度 * 该结点的权值
  • +
+

啥叫 「树的带权路径长度」 ?

    +
  • 树中所有叶子结点的带权路径长度之和(WPL, Weighted Path Length)
  • +
+

image-20211114203648441

+

image-20211114203933185

+

啥叫 「哈夫曼树」 ?

    +
  • 含有 n 个带权叶结点,且带权路径长度(WPL)最小二叉树被称为哈夫曼树,也叫最优二叉树
  • +
+

给出一堆带权叶结点 => 如何构造哈夫曼树 ?

+

步骤 2 左右子树顺序任意~

+
+

image-20211114205005741

+

哈夫曼树的特点

    +
  • 哈夫曼树中,结点的度为 0 或 2,不存在度为 1 的结点
  • +
  • 每个初始结点最终都成为叶结点,且权值越小的叶结点到根结点的路径长度越长
  • +
  • 由于每执行一次步骤 2 都会向哈夫曼树中新增一个结点,初始给定 n 个叶子结点,那么就会执行 n-1 次步骤 2,所以最终哈夫曼树中会有 n+(n-1) 个结点
  • +
  • 哈夫曼树不唯一 => 哈夫曼编码不唯一,但 WPL 必定相同且为最小值(最优)!
  • +
+

哈夫曼树小结

image-20211115120409324

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/11/19/pointer&const/index.html b/2021/11/19/pointer&const/index.html new file mode 100644 index 0000000..6c8f125 --- /dev/null +++ b/2021/11/19/pointer&const/index.html @@ -0,0 +1,124 @@ + + + + + + + + + 指针与 const - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

指针与 const

+
+ +
+
+

避免野指针:指针一定要初始化指向「某一内存地址 || NULL」

+
+

指针与 const

image-20211119210133602

+

image-20211119212005088

+
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
// 如果指针是 const,表示一旦得到某个变量的地址,就不能再指向其他变量

int a = 123;

int * const ptr = &a;

*ptr = 456; // --------> Ok~

printf("%d\n", a);

ptr++; // -------------> Error !

------

// 如果所指的是 const,表示不能通过该指针去修改那个变量,但是指针的指向可改变

int a = 123;

const int * ptr = &a;

a = 456; // ------------> Ok~

*ptr = 456; // ---------> Error !

------

int b = 999;

ptr = &b;// ------------> Ok~
+ +

可将数组名理解为指向不能变的指针

1
2
3
int arr[] = { 1, 2, 3 };
int * ptr = NULL; arr = ptr;
// 可将数组名理解为指向不能变的指针,本代码报错:assignment to expression with array type
+ +

for more information, see here

+

必须初始化赋值的情况

1
2
const int arr[] = { 1, 2, 3 };
// 每个数组元素都是 const 的 int,必须初始化赋值
+ +

函数的形参加 const 代表一种 「承诺」

eg:承诺你传进来一个指针,我这个函数绝对不会修改这个指针所指向的内容

+
1
2
3
4
5
6
7
void f(const int * a) { ... }

int a = 10;
f(&a); // -------------> Ok~

const int b = 20;
f(&a); // -------------> Ok~
+ +

const 可保护数组的值

image-20211119213852579

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2021/11/19/str/index.html b/2021/11/19/str/index.html new file mode 100644 index 0000000..449b3b3 --- /dev/null +++ b/2021/11/19/str/index.html @@ -0,0 +1,182 @@ + + + + + + + + + C 语言的字符串 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

C 语言的字符串

+
+ +
+

知识铺垫

+
1
2
3
4
5
// 字符数组
char arr[] = { 'm', 'o', 'r', 'n', 'i', 'n', 'g' };

// 字符数组 + '\0' <=> 字符串
char str[] = { 'm', 'o', 'r', 'n', 'i', 'n', 'g', '\0' };
+ +
+

所以:可以用访问数组的方式访问字符串~

+
+

注意

'\0',而不是 ‘0’

+

另外,0也能将字符数组变为字符串

+

但**推荐用 ‘\0’**,因为这能从字面上强调 「字符串的结束标志占 1 Byte」!

+
1
2
3
char str1[] = { 'a', 's', '\0' };
char str2[] = { 'a', 's', 0 };
printf("str1 = %s, str2 = %s\n", str1, str2);
+ +

下例代码编译运行输出 3,但其实字符串 str 的长度为 2,因为:**’\0’ 仅标志着字符串的结束,而并非字符串的一部分**

+
1
2
char str[] = { 'h', 'i', '\0' };
printf("%d\n", sizeof(str) / sizeof(str[0]));
+ +

字符串常量

≥ 0 个字符,被双引号引起来,就是字符串常量(eg:””、”hello”、…)

+

eg:"asd" => 字符串常量 => 会被转换成{'a', 's', 'd', '\0'} => 系统只会保留一份 => 放在一片只读的存储空间中 => 共享

+
1
2
3
4
char * str1 = "asd";
char * str2 = "asd";
printf("position of str1: %p\n", str1);
printf("position of str2: %p\n", str2);
+ +

试想:

+

如果字符串常量所存放的位置不是只读的

+

那当有很多指针指向它,其中任何一个指针对其的修改,都会导致其它指针对这种修改的不知情

+

从而可能导致不可预知的严重后果

+

举例如下

+
1
char * s = "hello";
+ +

解释:

+

s 是一个指针,初始化为指向一个字符串常量

+

所以这行代码实际上是 const char * s = "hello";

+

虽然由于历史原因,在这里,编译器不接受带 const 的写法

+

但任何试图对 s 所指向的内存空间做写入的操作都会导致严重后果 !

+
+

相邻的字符串常量默认会被连接起来 !

+
+
1
printf("%s\n", "hel"  "lo world");
+ +

字符串变量

可用字符串常量初始化字符串变量

+
1
char str[] = "hello";
+ +

解释:

+

用只读的 {'h', 'e', 'l', 'l', 'o', '\0'} 初始化一个可读写的普通字符数组 str

+

‘\0’ 让字符数组变成了字符串

+

当然写成下面这样也完全 ok

+
1
char str[10] = "hello";
+ +
+

空字符串 “” 其实是 { ‘\0’ }

+
+
1
2
char str[] = "";
printf("length of str = %d\n", sizeof(str) / sizeof(str[0]));
+ +

字符串数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 类比字符数组
char arr[] = { 'a', 's', 'd' };

// 字符串数组
char* arr[] = {
"hello",
"world",
};

// 也可用二维字符数组,但第二维一定要有确切的大小(strArr[0] <=> char str[10])
char strArr[][10] = {
"hello",
"world"
};
+ +

image-20211119204540151

+
习题
1
2
3
4
5
6
7
8
char* arr[] = {
"Jan",
"Feb",
"Mar",
};

printf("请输入月份:"); int month; scanf("%d", &month);
printf("%s\n", arr[month]);
+ +

I/O

scanf() 其实“破绽百出”
    +
  1. 「空格、tab、回车」 都是 scanf 输入结束的标志,这就导致 scanf 其实只能读入“单词”
  2. +
+
1
2
3
4
5
6
7
8
char str[20];
scanf("%s", str);

// 试试输入「hello world」

printf("%s\n", str);

// 其实输出的只有「hello」
+ +
+

注意:「空格、tab、回车」 只是输入结束的标志,不会被输到 str 中(在 Linux 上验证如下)

+
+

image-20220508163507995

+

关于上图中的 $ 符号,请看 => DOS 与 Linux 的断行字元

+
    +
  1. 单论读取“单词”而言,由于 scanf 并不知道需要读入多少字符,当输入的字符串过长,就可能导致缓冲区溢出,所以 scanf 并不安全
  2. +
+
1
2
3
// 安全的做法:在 %s 中间加一个数字,以此告诉 scanf 最多能读入几个字符
char str[10];
scanf("%9s", str);
+ +
+

那如果我们就是要读入一个英文句子,而不仅仅是一个单词

+

在 C 语言的官方文档中可查阅到曾有人设计了gets()函数,但该函数已被废除,因为文档描述了这样一段话:

+

image-20220508171150196

+

另外,如果你是一名 c++ 开发者,可以使用getline()函数,但我偏爱更简单纯粹的 C :)

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/02/05/multi-os/index.html b/2022/02/05/multi-os/index.html new file mode 100644 index 0000000..9c97732 --- /dev/null +++ b/2022/02/05/multi-os/index.html @@ -0,0 +1,218 @@ + + + + + + + + + 当你需要多种操作系统时的一些解决方案 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

当你需要多种操作系统时的一些解决方案

+
+ +
+

不推荐的方案

    +
  • 单硬盘,多系统
  • +
  • wine
  • +
+

还未尝试的方案

    +
  • 云电脑(选择的厂商的体量应足够大)
  • +
  • docker
  • +
+

制作系统安装盘的工具

+

推荐的方案(OS-togo)

适用场景:需要一个完整的相对成熟稳定的系统体验(包括摄像头、USB3.0等设备)

+

将操作系统安装到移动存储器(eg:移动硬盘、U盘、…)中,即插即用

+
+

注意:

+
    +
  1. 该操作会清空你的移动存储器,请提前做好数据备份

    +
  2. +
  3. 存储器容量尽量选择大于 100 GB 且为固态介质

    +
  4. +
  5. 请确保 USB 接口内为蓝色(USB 3.0),而不要是灰黑色(USB 2.0)

    +
  6. +
  7. 数据传输速度方面,USB 接口不如笔记本内置的硬盘接口

    +
  8. +
+
+
    +
  • 制作方法:
      +
    1. 制作一个系统安装盘
    2. +
    3. 插上存储器,向其中安装系统
    4. +
    +
  • +
+

推荐的方案(ssh)

适用场景:你真的有多台电脑,你在不同电脑上安装了不同的操作系统,着两台电脑你需要同时使用(着意味着你可能需要频繁在这两台电脑间切换),你又不想用比较吃性能且不如真机实装系统稳定的虚拟机

+

那么不妨使用 ssh 实现你的需求,可以看看这篇文章

+

推荐的方案(虚拟机)

适用场景:一台电脑上随时需要频繁切换不同系统,只是需要一个系统环境运行特定软件

+

注意:虚拟机的稳定性其实不如真机实装系统,但对于预算有限的人群来说仍然是一个好方法

+
+

虚拟机会和当前电脑的宿主系统共享电脑的硬件配置,故年代久远配置较低的硬件使用虚拟机可能会卡顿,若真是这样,也就到了买电脑的时候了

+

虚拟化软件可选用 virtualbox、vmware

+
+
1
2
3
4
5
6
7
8
9
10
# 确定宿主系统的内核版本,假设输出为:5.10.93-1-MANJARO,则接下来安装 linux510-virtualbox-host-modules
uname -r

# 安装虚拟化软件 virtualbox(on manjaro-linux)
sudo pacman -S virtualbox
sudo modprobe vboxdrv

# 请确保当前用户在 vboxusers 组中
groups $USER
sudo usermod --append --groups vboxusers $USER
+ +
    +
  • 借助 virtualbox 运行的操作系统无法全屏 ?

    +
      +
    • 下载安装增强功能
    • +
    +

    image-20220412214408940

    +
      +
    • 然后重启虚拟机就 ok 了

      +
    • +
    • 挂载的CD-ROM取消挂载就行

      +
    • +
    +
  • +
  • 虚拟机不识别 usb2/3 接口 ?

    +
      +
    • 这里下载对应版本的一个叫 Oracle_VM_VirtualBox_Extension_Pack 的扩展
    • +
    +
    1
    sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-6.x.xx-xxxxxx.vbox-extpack
    + + +
  • +
  • 在虚拟机和用户主机之间配置共享文件夹 ?

    +
      +
    • 没必要,为什么不直接用 U 盘呢 ?
    • +
    +
  • +
+

新系统没有网络连接怎么办 ?

    +
  • 大多数手机都拥有「USB 共享网络」功能,可通过 USB 数据线,将手机的网络共享给电脑
  • +
+

win10 激活 ?

+

管理员模式命令行

+
+
1
2
3
4
5
6
7
8
9
10
11
# win10 专业版

slmgr /ckms
slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX
slmgr /skms kms.03k.org
slmgr /ato

# win10 家庭中文版/企业版

slmgr /skms kms.03k.org
slmgr /ato
+ +

时间逻辑

    +
  • 联网后,操作系统同步用户本地时间
  • +
  • 关机时:
      +
    • windows 在硬件中直接保存用户本地时间
    • +
    • linux 在硬件中保存(用户本地时间 - 用户时区)
    • +
    +
  • +
  • 下次开机:
      +
    • windows:直接读取硬件中的时间
    • +
    • linux:硬件中的时间 + 用户时区
    • +
    +
  • +
  • 参考: +
  • +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/02/26/cloud-computing/index.html b/2022/02/26/cloud-computing/index.html new file mode 100644 index 0000000..f5e7d03 --- /dev/null +++ b/2022/02/26/cloud-computing/index.html @@ -0,0 +1,139 @@ + + + + + + + + + 认识云计算 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

认识云计算

+
+ +
+

image-20220314094000940

+

优秀科普视频

+

视频已下载到本地并做了备份,防止第三方视频跑路~

+
+ + + + +

网友精彩评论

image-20220314084811956

+

image-20220314084643589

+

image-20220314084839577

+

书籍推荐

    +
  1. 《计算机组成原理》- 唐朔飞
  2. +
  3. 《深度实践KVM》- 肖力、汪爱伟、杨俊俊、赵德禄(虚拟机相关)
  4. +
  5. 《云计算架构技术与实践》- 华为-顾炯炯
  6. +
  7. 《让云落地 云计算服务模式》- Michael J. Kavis 著(适合云计算咨询师阅读)
  8. +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/02/26/display-android-screen-to-manjaro-pc/index.html b/2022/02/26/display-android-screen-to-manjaro-pc/index.html new file mode 100644 index 0000000..c67c0d6 --- /dev/null +++ b/2022/02/26/display-android-screen-to-manjaro-pc/index.html @@ -0,0 +1,182 @@ + + + + + + + + + scrcpy,跨平台的多屏协同解决方案 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

scrcpy,跨平台的多屏协同解决方案

+
+ +
+
+

本文的实践目的如下图

+
+

image-20220226194133613

+

本文诞生的背景

我一直都是使用电脑学习网课,但最近买的资料书的配套视频是通过手机扫描二维码,跳转到微信公众号观看不支持分享链接的视频,这就很难受,手机屏幕太小了。。。

+

诶 ?如果能把手机投屏到电脑上就好了,就像 华为分享/多屏协同 那样

+

可是咱的手机就只是个装着 安卓-10 的荣耀8x呀,咱的电脑是个装了 manjaro 的宏碁笔记本呀,看来只能自己找其他解决方案了

+

解决方案

image-20220226192113702

+ +
    +
  1. 首先使用 usb 将安卓手机和 linux 电脑相连接,usb 连接方式为「传输文件」,然后打开安卓手机的 adb 调试,步骤依次为:设置 -> 关于手机 -> 连续点击版本号直到提示当前处于开发者模式 -> 返回一级 -> 搜索「开发人员选项」点击进入 -> 勾选 usb 调试 -> 确定
  2. +
  3. linux 电脑安装 scrcpy
  4. +
+
1
sudo pacman -S scrcpy
+ +
    +
  1. linux 电脑运行 scrcpy
  2. +
+
1
scrcpy
+ +

你有可能会遇到下图的问题,导致无法运行 scrcpy

+

image-20220226200053185

+

解决办法在这里,我执行如下命令就成功运行了 scrcpy,手机屏幕被投屏到了电脑上 !

+
1
scrcpy -m 1920
+ +
    +
  • 截个图(成功的喜悦)
  • +
+

image-20220226200620540

+
    +
  • 我不想让手机屏幕亮着,只想在电脑上操作,所以在启动 scrcpy 的时候,需要加一个-S参数
  • +
+
1
scrcpy -S -m 1920
+ +
    +
  • 我想让投屏到电脑上的手机保持常亮,而不是静置一会就熄屏了,所以需要加一个-w参数
  • +
+
1
scrcpy -w -S -m 1920
+ +
    +
  • 最后,我希望将现在的有线投屏变成无线投屏(TCP/IP)
      +
    • 文档中说的很详细了,参见下图
    • +
    +
  • +
+

image-20220226202538716

+
+

查看 scrcpy 的文档可知,其实 scrcpy 远不止投屏一个功能,查看其官网说明自行探索按需使用即可

+
+

下次开机的无线投屏方式

    +
  1. 使用 usb 将手机和电脑连接
  2. +
  3. 电脑执行命令adb tcpip 5555启用网络 adb 功能
  4. +
  5. 断开 usb 连接
  6. +
+
+
    +
  1. 电脑执行命令adb connect phoneIP:5555,让电脑和手机无线连接
  2. +
  3. 将 scrcpy 按照你希望的方式运行起来(比如我希望手机熄屏,而手机画面投屏到电脑上并保持常量,则只需解锁手机后在电脑上执行命令scrcpy -w -S -m 1920
  4. +
  5. 音频共享:参见下文
  6. +
+

image-20220226204709518

+

音频转发

+

最好的音频转发方式是通过蓝牙将手机和电脑相连接

+
+
+

如果你的蓝牙连接不好用,可以考虑使用如下方式

+

image-20220227103251252

+
1
yay -S vlc sndcpy
+ +
    +
  • 保持无线投屏正常运行,电脑终端执行命令sndcpy即可将音频在电脑上播放了,然后手机关静音即可,不影响电脑的音频正常播放
  • +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/04/disk-size/index.html b/2022/03/04/disk-size/index.html new file mode 100644 index 0000000..b1e494d --- /dev/null +++ b/2022/03/04/disk-size/index.html @@ -0,0 +1,116 @@ + + + + + + + + + 为什么我磁盘的实际容量总是比生产厂家标注的容量少了一些 ? - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

为什么我磁盘的实际容量总是比生产厂家标注的容量少了一些 ?

+
+ +
+

image-20220304223631068

+

我有一块固态硬盘,生产厂家标注的容量是 250 GB

+

image-20220303150038790

+

当我把它插到电脑上,操作系统显示出的磁盘容量却只有 232.8GB

+

image-20220303150321117

+

厂家缺斤短两 ?磁盘有质量问题 ?其实都不是 !

+

其实是因为:硬件生产厂家对单位 GB 的定义是 10^9,而操作系统对单位 GB 的定义是 2^30

+

image-20220303150641878

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/04/throttle-debounce/index.html b/2022/03/04/throttle-debounce/index.html new file mode 100644 index 0000000..6daffc2 --- /dev/null +++ b/2022/03/04/throttle-debounce/index.html @@ -0,0 +1,174 @@ + + + + + + + + + 你一定看得懂的「函数防抖」&「函数节流」 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

你一定看得懂的「函数防抖」&「函数节流」

+
+ +
+

image-20220304230326643

+

函数防抖(debounce)

    +
  • 问:

    +
      +
    • 啥是函数防抖啊 ?有啥用啊 ?
    • +
    +
  • +
  • 答:

    +
      +
    • 有的时候,一个函数有可能在很小的一个时间段内被频繁触发(比如双十一疯狂点击抢购按钮的时候),这会给整个系统造成不小的压力
    • +
    • 所以我们希望:只有当其中任意相邻两次触发之间的时间间隔达到一定长度,函数才会被执行一次,这就叫函数防抖
    • +
    +
  • +
+

举个例子

    +
  • 日常生活中我们赶公交,都希望赶得上吧 ?
  • +
  • 我们这里用代码模拟一下一旦有人上车,就立马发车的司机
  • +
+
1
2
3
4
5
6
7
8
9
function kaiChe() {
console.log('车开走了~');
}

// 车门
var door = document.getElementById('ipt');

// 一旦有人上车,就立马发车
door.oninput = kaiChe;
+ +
    +
  • 大家应该这辈子也不想碰见这种司机..
  • +
  • 既然如此就从我做起,做一名全心全意为乘客着想的好司机 !
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 准备一个秒表
var clock;

function kaiChe() {
// 将表清零
clearTimeout(clock);
// 10 秒内没人上车再发车
clock = setTimeout(() => {
kaiChe();
}, 10000);
}

var door = document.getElementById('ipt');
door.oninput = kaiChe;
+ +
    +
  • 但是我们没必要每次都是等待 10 秒钟,而且也并非只有在开公交的时候需要等人
  • +
  • 所以我们可以将这种等待再执行的操作抽象出来封装成函数,更具有通用性
  • +
+
1
2
3
4
// 期望的调用方式

door.oninput = debounce(kaiChe, 4000); // 4 秒之内无人上车再开车
me.onplan = debounce('睡懒觉', '周六'); // 我计划等到周六睡懒觉嘿嘿嘿
+
1
2
3
4
5
6
7
function debounce(fn, delay) {
var clock;
return function () {
clearTimeout(clock);
clock = setTimeout(fn, delay);
}
}
+ +
+

函数节流(throttle)

    +
  • 问:

    +
      +
    • 啥是函数节流啊 ?有啥用啊 ?
    • +
    +
  • +
  • 答:

    +
      +
    • 有的时候,一个函数有可能在很小的一个时间段内被频繁触发(比如双十一疯狂点击抢购按钮的时候),这会给整个系统造成不小的压力
    • +
    • 所以我们希望:只有当时间累积到一定程度,函数才允许被执行一次,这就叫函数节流
    • +
    +
  • +
+

举个例子

    +
  • 其实函数节流就像日常生活中一个没拧紧的,在一滴一滴地滴水的水龙头
  • +
  • 我们先用代码模拟一下:敲一下水龙头就立刻滴下一滴水的情景
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 取一个水桶
var oShuiTong = document.getElementById('shuitong');

// 滴水函数
function diShui() {
// 水桶中增加一滴水
oShuiTong.innerText = parseInt(oShuiTong.innerText) + 1;
}

// 一个神奇的水龙头
var oLongTou = document.getElementById('longtou');

// 敲一下水龙头就滴下一滴水
oLongTou.onclick = diShui;
+ +
    +
  • 众所周知生活中处处皆有熊孩子,如果让他们发现这么神奇的水龙头,恰好该熊孩子又天赋异禀,一瞬间可以敲击 1000 下水龙头!
  • +
+
1
2
3
for (var i = 0; i < 1000; i ++) {
oLongTou.click();
}
+ +
    +
  • 水桶中瞬间多了一瓢水。。这也太可怕了
  • +
  • 所以我们回归现实,水龙头上只有累积一定的水量,才能滴下一滴水
  • +
  • 这种每隔一定的时间才会执行一次的操作可以抽象出来封装为函数,更具通用性
  • +
+
1
2
// 期望的调用方式(eg:水龙头一秒钟滴下一滴水)
oLongTou.onclick = throttle(diShui, 1000);
+
1
2
3
4
5
6
7
8
9
10
function throttle(fn, waitTime) {
var lastTime = 0;
return function () {
var nowTime = new Date().getTime();
if (nowTime - lastTime > waitTime) {
fn();
lastTime = nowTime;
}
}
}
+ +

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/14/net-speed/index.html b/2022/03/14/net-speed/index.html new file mode 100644 index 0000000..7b125b0 --- /dev/null +++ b/2022/03/14/net-speed/index.html @@ -0,0 +1,113 @@ + + + + + + + + + 办理的千兆宽带,为啥实际下载速度只有几十兆每秒 ? - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

办理的千兆宽带,为啥实际下载速度只有几十兆每秒 ?

+
+ +
+

image-20220304223631068

+

1000M bps === 1000M bit/s === 1000M b/s === 1000 * 10^6 b/s === 1 * 10^9 b/s

+

即:理论上每秒可传输 10^9 个比特

+

1 * 10^9 / 8 / 10^3 / 10^3 = 125

+

考虑信号在传输过程中的损耗,故实际下载速度只有几十兆每秒。

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/15/nvm-nodejs-npm-nrm/index.html b/2022/03/15/nvm-nodejs-npm-nrm/index.html new file mode 100644 index 0000000..4dc62a3 --- /dev/null +++ b/2022/03/15/nvm-nodejs-npm-nrm/index.html @@ -0,0 +1,131 @@ + + + + + + + + + NVM、Node.js、NPM、NRM - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

NVM、Node.js、NPM、NRM

+
+ +
+

nodejs

+
+

注意:

+
    +
  1. 本文为作者自用(作者使用的操作系统:ManjaroLinux),适合 Linux 和 macOS 用户参考

    +
  2. +
  3. 本文会假设你的电脑当前没有安装部署任何本文将安装部署的软件包,如果有,请先将它们完全卸载,并清理干净所有相关的配置信息

    +
  4. +
  5. 本文将按照一定的逻辑和顺序从头安装部署它们

    +
  6. +
+
+
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
# 安装 NVM,方便日后进行 Node.js 版本的切换
https://github.com/nvm-sh/nvm

# 查验 NVM 是否安装成功
nvm -v

# 用 NVM 安装 Node.js
nvm ls-remote --lts # 搜索长期支持版(LTS)
nvm install 12.16.1 # 安装
nvm use 12.16.1 # 使用
node -v # 查验当前使用的 Node.js 的版本
npm -v # 查验当前使用的 NPM 的版本
nvm alias default 12.16.1 # 设置默认 Node.js 的版本

# 查看当前 NVM 管理 Node.js 的情况
nvm list

npm config get registry # 查看 NPM 对应的软件源
sudo npm i -g nrm # 全局安装 NRM
nrm ls # 查看可用的软件源
nrm test REGISTRY_NAME # 测试某个软件源的时间延迟
nrm use REGISTRY_NAME # 切换软件源
nrm current # 查看当前 NPM 对应的软件源

# 可选
nrm add REGISTRY_NAME REGISTRY_URL # 增加定制的软件源
nrm del REGISTRY_NAME # 删除定制的软件源

# 可选,你也可以不使用 NRM,而仅仅配置使用淘宝源
npm config set registry https://registry.npm.taobao.org/
+ +
+

当然,你也可以不切换软件源,而仅仅开启网络代理

+
+

BUG 处理

+
1
npm i -g Pana/nrm
+ +

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/25/aliyun-oss-picgo/index.html b/2022/03/25/aliyun-oss-picgo/index.html new file mode 100644 index 0000000..cd880c0 --- /dev/null +++ b/2022/03/25/aliyun-oss-picgo/index.html @@ -0,0 +1,136 @@ + + + + + + + + + 基于阿里云对象存储,搭建自用图床服务 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

基于阿里云对象存储,搭建自用图床服务

+
+ +
+
+

本文仅供参考

+
+

最终效果

使用截图软件将截图保存至剪贴板,然后使用 picgo 将剪贴板中的图片上传至 aliyun-oss

+

为什么需要自建图床

    +
  1. 自己的资源自己要有绝对掌控权(故任何第三方图床都不值得被推荐)
  2. +
  3. 第三方代码托管平台都不太适合被白嫖成图床的模样(白嫖虽香,但服务的可用性稳定性以及数据安全性都毫无保障)
  4. +
  5. 大厂(如:阿里云、腾讯云、又拍云、七牛云…)在云存储服务的(可用性、长期稳定性、数据安全性、经济实惠性)等方面都不错
  6. +
+
+

我看阿里云的对象存储顺眼,就用它了 !

+
+

参考了如下视频

+

注意:由于 typora 为专有软件,代码闭源,故笔者放弃使用 typora

+
+ + +

20221127103638

+

20221127103803

+

本地可视化管理云端文件

不建议使用 AUR 中的软件包,如果真要使用,先备份

+

oss-browser(阿里云对象存储浏览器)

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/03/26/mac-randomize/index.html b/2022/03/26/mac-randomize/index.html new file mode 100644 index 0000000..86938c9 --- /dev/null +++ b/2022/03/26/mac-randomize/index.html @@ -0,0 +1,121 @@ + + + + + + + + + MAC 地址随机化 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

MAC 地址随机化

+
+ +
+
    +
  • 为什么:See here
  • +
  • 怎么做:See here
  • +
+

简化步骤如下

image-20220326110728547

+
1
2
3
4
5
6
7
8
9
10
11
sudo -e /etc/NetworkManager/conf.d/wifi_rand_mac.conf

# 写入以下配置后保存退出
[device]
wifi.scan-rand-mac-address=yes
[connection-mac-randomization]
ethernet.cloned-mac-address=random
wifi.cloned-mac-address=random

# 重启网络管理器
sudo systemctl restart NetworkManager
+ +
    +
  • 搞定,重新连接网络,就可以发现自己的 MAC 地址已经改变,查询命令为
  • +
+
1
cat /sys/class/net/网卡名/address
+ +

image-20220326113700410

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/04/04/ether-net/index.html b/2022/04/04/ether-net/index.html new file mode 100644 index 0000000..781e244 --- /dev/null +++ b/2022/04/04/ether-net/index.html @@ -0,0 +1,223 @@ + + + + + + + + + 什么是以太网 ? - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

什么是以太网 ?

+
+ +
+
+

本文翻译自:https://realpars.com/ethernet/

+
+ +

以太网简介

    +
  • 以太网是 80 年代早期开发的一种通信标准,用于在本地环境中连接计算机和其他设备
  • +
  • 本地环境(LAN,LocalAreaNetwork),一般局限在一户普通人家或一个普通建筑物中,由多台设备互相连接而成,这些设备可以创建和存储信息,并且设备之间可以进行信息共享
  • +
  • 以太网是一种有线系统,其最初使用同轴电缆,现在已经成功发展到使用铜芯双绞线和光纤
  • +
+

image-20220404094112203

+
+

1881 年,亚历山大·格拉汉姆·贝尔发明了双绞线

+
+

image-20220404113144725

+ +

以太网的物理层

线缆

    +
  • 同轴电缆(不常见了已经)
  • +
  • 双绞线(目前最常见)
  • +
  • 光纤(比较先进)
  • +
+
双绞线
    +
  • 6 类双绞线的数据传输速率高达 1 Gbps
  • +
  • 6a 和 7 类双绞线的数据传输速率高达 10 Gbps
  • +
  • 5 和 5e 类双绞线仍在现有的许多应用中使用,但数据传输速度较低,介于 10~100 Mbps,且更容易受到噪声的影响
  • +
+

image-20220404114118868

+
    +
  • 以太网双绞线在电缆两端使用 RJ-45 八针连接器,用于以半双工或全双工模式传输和接收数据
  • +
+

image-20220404100922064

+
    +
  • 两对电线就能实现全双工
  • +
+

image-20220404114324995

+
光纤
    +
  • 光纤电缆使用玻璃或塑料光纤作为数据传输的导管,以光脉冲为数据载体,使以太网的数据传输速度更快,数据传输距离更远。
  • +
+

image-20220404101516865

+
    +
  • 根据实际应用需求的不同,光纤电缆可以使用类型不同的连接器
      +
    • 一些类型属于SFP(小型可插拔)
    • +
    • 一些类型属于SC(用户连接器,也称为方形连接器或标准连接器)
    • +
    +
  • +
+

image-20220404102032404

+
    +
  • 为了在使用双绞线进行布线的以太网网络中使用光纤,您需要使用“以太网到光纤转换器”
  • +
+

image-20220404102259811

+

设备

    +
  • 以太网设备由计算机、打印机或其他任何具有内部 NIC(网络接口卡)或基于 USB 或 PCI 的外部 NIC 设备组成
  • +
+
交换机 & 路由器
    +
  • 使用交换机和路由器可以将多台设备甚至多个网络连接在一起,使不同设备之间可以互相通信
  • +
+

网关 & 网桥

    +
  • “网关”和“网桥”用于将多个以太网连接在一起,允许它们互相通信
  • +
  • “网关”用于将两个“不同”的网络连接在一起
  • +
  • “网桥”用于将两个“相似”的网络连接在一起,然后你就只能看到一个网络
  • +
+

image-20220404103441426

+

以太网的数据链路层

    +
  • 数据链路层可分为两部分:
      +
    1. 逻辑链路控制(The Logical Link Control)
    2. +
    +
      +
    • 为以太网上的数据建立在设备之间传输的路径
    • +
    +
      +
    1. 媒体接入控制(The Media Access Control)
    2. +
    +
      +
    • 使用分配给网络接口卡(NIC)的硬件地址来标识特定的计算机或其他设备,以显示数据传输的源和目标
    • +
    +
  • +
+

image-20220404104105804

+
    +
  • 以太网使用 CSMA/CD 协议(载波监听多址接入/碰撞检测)在数据链路层传输数据包
  • +
  • CSMA/CD 协议是以太网标准的一部分,用于减少数据冲突,提高数据传输的成功率
  • +
  • 使用 CSMA/CD 协议的主机会对网络进行载波监听,一旦发现网络空闲,主机就会发送 1 比特数据并监测是否会发生碰撞
  • +
  • 如果这第一个 bit 的数据发送成功,那么主机就会继续一边发送数据,一边进行碰撞监测
  • +
  • 一旦监测到有碰撞发生,CSMA/CD 协议(算法)就会计算出一个等待时间,待到这段时间耗尽,再重复上述过程,直到数据传输完成
  • +
+

CSMACD-Algorithm

+
    +
  • 1 个交换机 + 多台设备 + 全双工模式 = 星型拓扑结构
  • +
  • 与所有设备共享同一路径的总线型拓扑结构相比,星型拓扑结构拥有多条传输路径,大大降低了冲突发生的概率
  • +
+

image-20220404105944649

+

以太网的优劣

    +
  • 时代变迁,新技术层出不穷,以太网的功能也在快速迭代变化
  • +
  • 近几年虽然数据传输速度越来越快,甚至出现了 10 Gbps,但这些新的以太网技术仍然价格不菲
  • +
+

image-20220404110615311

+
    +
  • 当局域网接入更大的网络,你就能获得更多的信息,创造更多的价值,拥有更多的可能性
  • +
+

image-20220404110854357

+
    +
  • 简言之,以太网几乎支持所有流行的网络协议,并且它在速度、成本和易于安装之间取得了良好的平衡
  • +
  • 因此,以太网很受欢迎,计算机市场广泛接收它
  • +
+

image-20220404115000603

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/04/06/array&pointer/index.html b/2022/04/06/array&pointer/index.html new file mode 100644 index 0000000..1c46c4e --- /dev/null +++ b/2022/04/06/array&pointer/index.html @@ -0,0 +1,147 @@ + + + + + + + + + 数组与指针 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

数组与指针

+
+ +
+
+

本文实验环境:Linux x86-64,gcc (GCC) 11.2.0

+
+
1
2
3
4
5
6
7
#include <stdio.h>

int main() {
int arr[5] = { 1, 2, 3, 4, 5 };
printf("&arr[0] = %p,\t arr[0] = %d\n", &arr[0], arr[0]); // 对照组
printf("arr = %p,\t\t *arr = %d\n", arr, *arr); // 实验组
}
+ +
+

arr是一个指针变量,其值为数组中首个元素的地址

+
+
1
2
3
4
5
6
7
#include <stdio.h>

int main() {
int arr[5] = { 1, 2, 3, 4, 5 };
printf("arr = %p,\t\t *arr = %d\n", arr, *arr); // 对照组
printf("arr + 1 = %p,\t *(arr + 1) = %d\n", arr + 1, *(arr + 1)); // 实验组
}
+ +
    +
  • arr + 1是将指针arr向后移动 1 个位置,指向数组的下一个元素
  • +
  • 由于数组元素的数据类型为 int,且sizeof(int) == 4
  • +
  • 所以
      +
    • printf("%d", arr);输出 0x7fffcf5000c0
    • +
    • printf("%d", arr + 1);输出 0x7fffcf5000c4
    • +
    +
  • +
+
1
2
3
4
5
6
7
#include<stdio.h>

int main() {
int arr[5] = { 1, 2, 3, 4, 5 };
printf("arr = %p,\t arr + 1 = %p\n", arr, arr + 1); // 对照组
printf("&arr = %p,\t &arr + 1 = %p\n", &arr, &arr + 1); // 实验组
}
+ +

image-20220406213615807

+

image-20220406221905290

+
    +
  • 练习题
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>

/**
* 工具函数
* 1. 输出指针变量中保存的地址
* 2. 指向的内存解读为 long,并以 16 进制 16 位的格式进行输出
*/
void printPtr(void * ptr) {
printf("ptr = %p, *ptr = %016lx\n", ptr, *(long *)ptr);
}

int main(int argc, char * argv[]) {
printPtr(argv); // 这是个指针变量
printPtr(&argv);

char * arr[5]; // 而这是个正儿八经的数组
printPtr(arr);
printPtr(&arr);
}
+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void foo(int brr[], int len) {
for (int i = 0; i < len; i ++) {
brr[i]++;
}
}

void main() {
int arr[] = { 1, 2, 3 }, len = sizeof(arr) / sizeof(arr[0]);
foo(arr, len);
for (int i = 0; i < len; i ++) {
printf("%d ", arr[i]);
}
printf("\n");
}
+ + +

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/04/09/spring-poem-2022/index.html b/2022/04/09/spring-poem-2022/index.html new file mode 100644 index 0000000..7071085 --- /dev/null +++ b/2022/04/09/spring-poem-2022/index.html @@ -0,0 +1,111 @@ + + + + + + + + + 春日小诗一则 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

春日小诗一则

+
+ +
+

旧木发新芽

+

绽出层层花

+

绿水微波里

+

鱼嬉桥边娃

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/04/19/TRM/index.html b/2022/04/19/TRM/index.html new file mode 100644 index 0000000..007c2cc --- /dev/null +++ b/2022/04/19/TRM/index.html @@ -0,0 +1,242 @@ + + + + + + + + + 思路:造一个最简单的能执行程序的计算机 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

思路:造一个最简单的能执行程序的计算机

+
+ +
+

故事起源

    +
  • 先驱想创造一个能执行程序的计算机,让我们来帮助他
  • +
+

开始构思 !

    +
  • 我们知道,程序是由(代码 & 数据)组成的
  • +
  • 比如:假设我们想要计算1+2+3+...+100,那么我们不费吹灰之力就能写一个程序来完成这件事
  • +
  • 不难理解:
      +
    1. 数据是程序处理的对象
    2. +
    3. 代码描述了程序是如何对数据进行处理的
    4. +
    +
  • +
+
+
+

ok,既然我们想让计算机执行程序,那应该将程序放在哪儿呢 ?

+
+
    +
  • 程序有几十行代码的“小程序”,也有上万行代码的“大程序”(比如大型游戏程序)
  • +
  • 显然,我们应该将程序放到一个拥有较大存储空间的“容器”中,这个容器叫:存储器
  • +
  • 于是,存储器诞生了,程序可被放入存储器中,等待着被 CPU 执行
  • +
+

等等,啥是 CPU ?

+
    +
  • CPU,中文名叫中央处理器,听起来牛逼吧 ?!
  • +
  • 嗯,它确实牛逼,它是负责处理数据的核心电路单元,程序执行全靠它
  • +
  • 还不懂 ?
      +
    • 你想啊,一个计算机它如果只有存储器,那还是不能计算嘛
    • +
    • 所以就得 CPU 扛起计算的重任喽
    • +
    • 咋扛呢 ?傻瓜,给 CPU 造运算器啊,然后就能对数据进行各种处理了
    • +
    • 啥 ?你觉得运算器太复杂 ?
    • +
    • 确实有点复杂哈,那就先只思考加法器吧~
    • +
    +
  • +
+
+
    +
  • 仍然以计算1+2+3+...+100为例
  • +
  • 对于本例,程序的编写方式是(将“部分”累加到“sum”上)
  • +
+
+

这就说明:有时候程序是需要对同一个数据进行连续的处理的

+
+
    +
  • 那么现在硬件视角的执行是下面这样的

    +
      +
    • 从存储器读出 sum 和 1,传入 CPU,1 被加到 sum 上,将 sum 写回存储器
    • +
    • 从存储器读出 sum 和 2,传入 CPU,2 被加到 sum 上,将 sum 写回存储器
    • +
    • 从存储器读出 sum 和 3,传入 CPU,3 被加到 sum 上,将 sum 写回存储器
    • +
    • +
    +
  • +
  • 啊西巴 !

    +
      +
    • 上面这样我们每完成一次累加都得将 sum 写回存储器,然后立刻就又将 sum 读出来继续加,这样太傻了啊
    • +
    +
  • +
  • 为什么说上面这种方式很傻呢 ?你可以想像这样的场景:

    +
      +
    • 考试的时候你做一道题就向你同桌借一次橡皮,上道题做完你立马就还回去,下道题还借…
    • +
    • 懂了吧 ?!
    • +
    +
  • +
  • 另外,大容量的存储器的读写速度是相对较慢的,这是谁都无法违背的材料特性规律

    +
  • +
  • 于是先驱创造了小容量但高速的寄存器,CPU 正在处理中的数据可被暂放其中

    +
  • +
+
+

至此,我们就有了(存储器、CPU、寄存器)

+
+

image-20220410180257453

+ +
+
    +
  • 为了让强大的 CPU 成为我们忠实的奴仆,指令诞生了

    +
  • +
  • 我们可以用指令来控制 CPU,让 CPU 做我们想做的事

    +
  • +
  • 但(发一条指令,CPU 就动一动)的方式还是不尽人意,于是先驱就和 CPU 做了一个简单的约定

    +
      +
    • 给你一段程序,你执行完一条指令之后,就继续执行下一条指令
    • +
    • 可 CPU 怎么知道现在执行到哪一条指令呢 ?
    • +
    • 为此,先驱为 CPU 创造了程序计数器(Program Counter,PC)
    • +
    • 在 x86 中,它有一个特殊的名字,叫(Extended Instruction Pointer,EIP)
    • +
    • 从此,计算机就只需做一件事
    • +
    +
    1
    2
    3
    4
    5
    while (1) {
    从 PC 指示的存储器位置取出指令;
    执行指令;
    更新 PC;
    }
  • +
+
+

至此,我们就设计出了一个足够简单的计算机

+

只需将一段指令序列放入存储器,然后让 PC 指向第一条指令,这段指令序列就会被计算机自动执行~

+
+

例如,下面的指令序列可以计算1+2+...+100

+

其中r1r2是两个寄存器,还有一个隐含的程序计数器PC,初值为0

+

为了帮助大家理解, 我们把指令的语义翻译成 C 代码放在右侧,其中每一行 C 代码前都添加了一个语句标号

+
1
2
3
4
5
6
0: mov  r1, 0         |  pc0: r1 = 0;
1: mov r2, 0 | pc1: r2 = 0;
2: addi r2, r2, 1 | pc2: r2 = r2 + 1;
3: add r1, r1, r2 | pc3: r1 = r1 + r2;
4: blt r2, 100, 2 | pc4: if (r2 < 100) goto pc2;
5: jmp 5 | pc5: goto pc5;
+ +

计算机执行以上的指令序列,最后会在 PC = 5 的指令处陷入死循环,此时计算已经结束,1+2+...+100的结果会被存放在寄存器r1

+

image-20220410183206046

+
    +
  • 事实上,开拓者图灵早在 1936 年就已经提出了类似的核心思想,「计算机科学之父」果然名不虚传
  • +
  • 而这个流传至今的核心思想,就是“存储程序” !
  • +
  • 为了表达对图灵的敬仰,我们将上面这个最简单的计算机称为「图灵机,Turing Machine,TRM」
  • +
  • 或许你已经听说过图灵机这个作为计算模型时的概念
  • +
  • 但这里我们只强调一个最简单的真实计算机需要满足哪些条件:
      +
    1. 结构上:TRM 有(存储器、PC、加法器、寄存器)
    2. +
    3. 工作方式上:TRM 不断重复以下过程
    4. +
    +
      +
    • 从 PC 指示的存储器位置取出指令 => 执行指令 => 更新 PC
    • +
    +
  • +
+
+
    +
  • 咦 ?(存储器、PC、加法器、寄存器)这些不都是数字逻辑电路课上学习过的部件吗 ?
  • +
  • 也许你会觉得难以置信,但你正面对着的这台无所不能的计算机,就是由只懂 0 和 1 的数字逻辑电路组成的 !
  • +
+
+

blame my 数字逻辑电路 teacher, blame myself.

+
+
    +
  • 可我们写的是 C 代码啊,这个冷冰冰的电路是如何理解凝结了人类智慧结晶的 C 代码的呢 ?
  • +
  • 先驱说:“计算机诞生的那些年还没有 C 语言,大家当时都是直接编写对人类来说晦涩难懂的机器指令,这也是最早的对电子计算机的编程方式了”
  • +
  • 后来人们发明了(高级语言 & 编译器),我们能直接编写高级语言代码,经由编译器处理,生成功能等价的,且 CPU 能理解的指令
  • +
  • CPU 执行这些指令,就相当于执行了我们写的代码
  • +
+
+

如今的计算机本质上仍然是”存储程序”这种工作方式

+

经过了无数计算机科学家们的努力,才使得我们今天可以轻松地使用计算机

+
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/05/05/regex/index.html b/2022/05/05/regex/index.html new file mode 100644 index 0000000..a74d2cf --- /dev/null +++ b/2022/05/05/regex/index.html @@ -0,0 +1,270 @@ + + + + + + + + + Regular Expression - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

Regular Expression

+
+ +
+

Make each program do one thing well - The Unix philosophy

image-20220506155429491

+

概述

原文链接

+

什么是正则表达式

有种标准叫做正则表示法,你可以依据该标准写出一些特殊的字符排列,叫做正则表达式

+

你可以利用正则表达式高效准确地匹配并处理一个或多个字符串

+

简言之:正则表达式就是一种处理字符串的方法

+
+

要想使用正则表达式,必须使用支持正则表达式的软件工具,比如 vim、grep、sed、awk、…

+
+

正则表达式的广泛用途

对于个人而言,使用正则表达式,能让你在使用主机时更精简高效地处理日常事务 !

+

比如:

+

当你使用编辑器之神 vim 编辑文本时,要想把「搜索/删除/替换」等动作做得漂亮,就需要配合使用正则表达式

+

再比如:

+

你的系统在繁忙时会生成成千上万行的信息,这些信息往往由极其重要的信息和无关紧要的信息杂糅(重要的信息比如:错误信息、系统被入侵的记录信息、…);要想成为一个合格的系统管理员,你就应当学会编写、学会利用正则表达式从这大量的信息中快速提取出重要信息,甚至输出生成便于查阅的报表,以此来方便自己

+

此外,由于正则表达式强大的字符串处理能力,有很多软件都支持正则表达式,有很多软件都使用正则表达式来实现一些功能

+

比如邮件服务器就使用正则表达式分析并过滤垃圾邮件

+

具体是怎么做的呢 ?

+

答:

+
    +
  1. 由于垃圾邮件几乎都有标题或内容
  2. +
  3. 因此,邮件服务器只需利用写好的正则表达式,就能对收到的信件的标题和内容进行字符串匹配
  4. +
  5. 如此,垃圾邮件们就能被过滤出来,进而被剔除
  6. +
+

自然这些邮件就不会被发送到用户端,既节省了用户的流量带宽,也规避了很多麻烦

+

啥 ?你觉得你会 ctrl+f 就够 ?

那我问你,假如你只想找到 VBird 或 Vbird 这个关键词(一个字母都不能差,大小写也不能差)

+

你咋办 ?

+

就拿被广泛使用但其实一点也不哇塞的 MS word 来举例,它并不支持正则表达式

+

显然,你需要分別以 VBird 和 Vbird 搜索两遍

+

或者你可以启用忽略大小写的功能,但这就会匹配出你不需要的关键词,比如 VBIRD、vbird、…

+

看吧,不支持正则表达式有时就很麻烦,但若用上正则表达式,这个需求就会和探囊取物一样简单

+
+

再举个例子

+

假如在系统开机的时候,总会出现一个与 mail 关键词相关的错误提示

+

这很令人别扭对吧 ?

+

你知道开机过程中的相关程序都放在 /lib/systemd/system/ 目录下,也就是说,在该目录下的某个文件中肯定有 mail 这个关键词

+

于是你想把这个不安分的文件“捉出来”,编辑它、修好它

+

你该怎么做 ?

+

你当然可以进入 /lib/systemd/system/ 目录,然后逐个文件地打开并搜索关键词 mail

+

但这个目录下很可能有大量文件 !

+

比如这个目录下可能会有 20 个文件,你愿意一个一个地打开搜索 ?

+

啥你愿意 ?你当求婚呢你愿意

+

假如该目录下有 100 个文件,不愿意一个一个地打开搜索了吧 ?!因为这 太 ! 慢 ! 了 !

+

如果你不会正则表达式,你的心情就可能是这样的

+

但如果你会用正则表达式,只需一行指令就找出来啦 !

+
1
grep 'mail' /lib/systemd/system/*
+ +

image-20220505173434394

+

再次强调:

+

只要一个软件工具支持正则表达式,那么就可以用该软件工具配合正则表达式来处理字符串

+

比如 vim、grep、awk、sed、… 这些软件工具,由于它们支持正则表达式,所以可以用这些软件工具配合正则表达式来处理字符串

+

而像 ls、cp、… 这些软件工具,由于它们不支持正则表达式,所以它们只能使用 bash 的万用字元(wildcard)

+
+

正则表达式 ≠ bash的万用字元 !这很重要 !!!

+
+

延伸型正则表达式

正则表达式分为「基础正则表达式 & 延伸型正则表达式」

+

对于延伸型正则表达式,除了做简单的一组字符串处理之外,还可以做群组的字符串处理

+

比如:当你想要搜索 VBird 或 netman 或 lman(注意是 或「OR」 而不是 和「AND」 ),你就需要使用延伸型正则表达式了

+

借助(|等特殊字元的帮助,就能实现这样的目的

+

虽然本文主要介绍基础正则表达式…

+

编码方式对正则表达式的影响

众所周知,计算机只能存储 0 和 1,电脑屏幕上显示的「数字、文字、…」都是由一些 0 和 1 根据某种编码方式映射转换而来

+

编码方式不同,正则表达式的执行结果就有可能不同

+

以英文大小写的编码为例,zh_TW.big5 和 C 这两种编码方式的编码顺序如下

+
1
2
LANG=C      =>  0 1 2 3 4 ... A B C D ... Z a b c d ...z
LANG=zh_TW => 0 1 2 3 4 ... a A b B c C d D ... z Z
+ +

我们可以清楚地看到:这两种编码方式的编码顺序是不同的 !

+

假设你想要提取大写字母,使用了[A-Z],你就会发现 LANG=C 时确实可以提取大写字母(因为是连续的)

+

但若 LANG=zh_TW.big5,你就会发现小写的 b-z 也被提取了出来…

+

这就是不同编码方式的不同编码顺序所造成的影响

+

因此:

+
+

使用正则表达式时,需要特别注意当时环境的编码方式是什么,否则就可能会发现与别人不同的执行结果 !

+
+

准备工作

    +
  1. 基于适合 POSIX 标准的编码方式
  2. +
+
1
2
export LANG=C;
export LC_ALL=C;
+ +
    +
  1. grep 若不带高亮,则设置高亮
  2. +
+
1
alias grep="grep --color=auto"
+ +
    +
  1. 下载本文练习用的文档
  2. +
+
1
2
3
wget https://gitee.com/pj-l/static/raw/master/regular_express.txt
wget https://gitee.com/pj-l/static/raw/master/demo.sh
wget https://gitee.com/pj-l/static/raw/master/printf.txt
+ +

基础正则表达式

一些特殊符号

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
特殊符号代表意义
[:digit:]代表数字,即 0-9
[:xdigit:]代表十六进制数字,因此包括 0-9, a-f, A-F
[:lower:]代表小写字母,即 a-z
[:upper:]代表大写字母,即 A-Z
[:alpha:]代表英文大小写字母,即 A-Z, a-z
[:alnum:]代表英文大小写字母和数字,即 A-Z, a-z, 0-9
[:blank:]代表「空格键、Tab」
[:graph:]代表除了「空格键、Tab」外的其它所有按键
[:space:]代表能产生空白的字元,比如「空格键、Tab、CR、…」
[:print:]代表任何可以被打印出来的字元
[:punct:]代表标点符号(punctuation symbol),包括「# ‘ “ $ …」
[:cntrl:]代表控制按键,包括「CR、LF、Tab、Del…」
+
+

一个好习惯是:用[:lower:],不用a-z,因为前者意思更明确(其它正则表达式同理)

+
+

练习笔记

如果我不想要开头是英文字母

image-20220506151220825

+
+

那个^符号,在字元集合符号[]之内与之外是不同的 ! 在[]内代表「反向选择」,在[]之外代表「定位在行首」

+
+
如果想寻找空行(hang)

image-20220506153312075

+
+

在 Linux 中,空行(hang) 就是 行(hang)首就是行(hang)尾定位符$

+
+
如果想去掉开头是#的行(hang)和空行(hang)以节省版面

image-20220506155934149

+

延伸型正则表达式

See here

+

Tools

格式化输出

printf

+

资料处理

倾向于整行(行)处理 => sed

+

倾向于一行当中分成多个栏位来处理 => awk,相当适合处理小型的资料文件,多结合 printf 进行格式化输出

+

档案比对

diff

+

cmp

+

patch

+

档案列印准备工具(给档案加标题、页码、…)

pr

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/05/09/single-char-io&shell-buffer/index.html b/2022/05/09/single-char-io&shell-buffer/index.html new file mode 100644 index 0000000..2d328b9 --- /dev/null +++ b/2022/05/09/single-char-io&shell-buffer/index.html @@ -0,0 +1,158 @@ + + + + + + + + + 单字符的I/O(getchar、putchar)& Shell中的缓冲区 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

单字符的I/O(getchar、putchar)& Shell中的缓冲区

+
+ +
+

知识铺垫:EOF

EOF 就是个 int 宏常量,表示 end-of-file,文档中有下面这么一段话:

+

image-20220509120708383

+

阮一峰老师也讲过:EOF是什么?

+
1
2
3
char ch;
ch = getchar(); // 直接 ^D,就能看到 EOF 值为 -1
printf("%d\n", ch);
+ +

image-20220509123350672

+

本图可点击

+

单字符的I/O

假设我想读入单个字符,该怎么办呢 ?=> 用getchar()

+

假设我想输出单个字符,该怎么办呢 ?=> 用putchar()

+

当然你可以可用 scanf() 和 printf(),并使用 %c

+
1
2
3
char ch;
scanf("%c", &ch);
printf("%c", ch);
+ +

关于 getchar() 的返回值是 int 这件事

文档中有下面这么一段话:

+

image-20220509120135429

+

举个例子

1
2
3
4
5
char ch;
while ((ch = getchar()) != EOF) {
putchar(ch);
}
printf("EOF\n");
+ +

这段代码的执行结果十分神奇

+

在命令行中,编译执行这段程序,命令行就会等待你用键盘输入内容,这符合预期

+

但接下来发生的事情可能就会和你的想法不太一样了

+

首先,你可以连续敲击键盘进行输入,只有当你按下「回车」,命令行才会有所回应

+

它会将你输入的内容原封不动地输出到你的显示屏上(就像 echo 一样)

+

接下来,你的命令行会继续等待你用键盘输入内容,并会如此循环往复

+

如果想停掉这个程序,你只能 ^C(你输入 EOF 或 -1 都不行),但并不会输出代码最后一行的 EOF

+

image-20220509124131967

+

这说明我们并没有正确地输入 EOF,也就并没有让我们的程序知道「输入结束」这件事情,我们只是在程序运行的中途就直接强制退出了该程序

+

那如何向 Shell 输入 EOF ?

Unix(Linux):^D

+

DOS(Windows):^Z

+

image-20211120151345087

+

image-20211120151456668

+
+

要理解上面这段程序背后发生了什么,我们必须了解一些关于 Shell 和其中的缓冲区的知识

+
+

Shell

键盘/显示器 <= Shell => 应用程序

+

Shell 是一个特殊的程序,它能将你的程序 run 起来,也能将运行着的程序 kill 掉

+

当 Shell 监听到用户按下了 ^C,运行着的程序就被 kill 掉了…

+

Shell 中的缓冲区

当用户在命令行中编译执行上面那段程序时,Shell 会负责将其 run 起来

+

不难看出程序会停在 getchar(),等待用户敲击键盘进行输入

+

比如你输入了一个字符 a,其实这个字符并没有被立刻送入你的应用程序,而是先被送到了 Shell 那里

+

Shell 会将收到的字符放在自己的缓冲区中,'\0'是缓冲区内容末尾的标志,就像下图这样

+

image-20211120153955045

+

由于此时 Shell 并没有接收到(回车符 || EOF),所以 Shell 会继续等待用户的输入(应用程序此时并不读取 Shell 的缓冲区中的内容)

+

假设你又输入了两个字符 b 和 c,缓冲区就变成了下面这个样子

+

image-20211120155135846

+

一旦你按下了「回车」,你的应用程序就会开始从 Shell 的缓冲区中读取内容(刚按下回车的缓冲区就像下面这样)

+

image-20211120155714429

+

上面那段程序中,getchar() 逐个字符地读取,读一个字符就输出一个字符

+

一旦读到 \0 就说明读到了缓冲区的末尾,对于上面那段程序,由于此时还没有读到 EOF,所以 while 循环会继续,也就会继续停在 getchar() 等待用户的输入

+

当用户按下了 ^D,Shell 的缓冲区就会收到信号 EOF,此时你的应用程序立刻就会读到 EOF

+

对于上面那段应用程序,不难看出就跳出了 while 循环,继续向下执行,直到程序全部执行结束,正常退出。

+

另外:缓冲区也可以从文件中读取内容

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/05/15/web-component/index.html b/2022/05/15/web-component/index.html new file mode 100644 index 0000000..d61654c --- /dev/null +++ b/2022/05/15/web-component/index.html @@ -0,0 +1,148 @@ + + + + + + + + + WEB COMPONENT TUTORIAL - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

WEB COMPONENT TUTORIAL

+
+ +
+

简介

在实际应用开发中,对重复代码或具有相同特征的代码进行 「抽象、封装、复用」 往往能够降低代码耦合度,使代码逻辑清晰,容易维护

+

但抽象封装同时包含 「结构、样式、功能」 的自定义 UI 控件对于初级开发者往往比较困难,一不小心就会使代码变得一团糟

+

Google 公司掌握着 Chrome 浏览器,他们给广大开发者以 API 的形式提供了部分浏览器权限,以允许开发者自定义具有特定样式和功能的浏览器原生组件(目前已经可以用于生产环境)

+

开发者只需将他们在项目之外自定义的 UI 控件引入项目,就可以以 html 标签的形式进行使用

+

这就是Web_Components

+

优点

    +
  1. 跨框架:任何 web 项目都可使用,无论你是使用 Vue/React 等前端组件式框架还是使用原生技术进行项目开发
  2. +
  3. 使用体验和浏览器默认提供的 html 标签一模一样,简单直接,符合直觉,代码量小
  4. +
  5. 使用 Shadow DOM 将组件的内部实现和外部代码相隔离(也就无命名冲突等问题)
  6. +
+

现有很多成品组件可供使用

webcomponents.org

+

Vue 的 SFC(单文件组件)正是借鉴于 Web_Components

+

那就写一个 Web_Component 吧

+

目标:Eating your own dog food

+
+
成果

https://github.com/Brannua/wc-scroll-button

+

我的所有笔记书都使用了该组件

+
组件命名的注意事项

根据规范,自定义组件必须包含连词线,以区别于浏览器内置的 HTML 标签

+

另外,你需要确保代码托管平台(eg:GitHub)和组件发布平台(eg:npmjs)无同名组件

+
RTFSC
1
2
3
4
./
├── index.html # 用于展示组件使用效果的页面
├── index.js # 组件封装于此
└── ...
+ +

of course, 我写的是 ES6 模块,结构框架如下

+
1
2
3
4
5
6
7
8
9
10
11
// index.js
class XXX extends HTMLElement {
constructor() {
super();
alert('开始开发吧~');
}
}
export default XXX;

// 告诉浏览器每一个 <your-component-name /> 都是 XXX 的实例
window.customElements.define("your-component-name", XXX);
+ +

代码写好测试无误之后,就该发布上线了~

+

发布

to npmjs.

+
1
npm init -y
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// package.json
{
"name": "xxx",
"version": "x.x.x",
"description": "xxx",
"keywords": ["xxx", "xxx", ...],
"main": "xxx",
"homepage": "https://github.com/xxx/xxx",
"author": "xxx <xxx@xxx.com>",
"license": "xxx",
"repository": {
"type": "git",
"url": "git+https://github.com/xxx/xxx.git"
},
"bugs": {
"url": "https://github.com/xxx/xxx/issues"
}
}
+ +
+

请确保你注册了npmjs账户,且邮箱验证通过

+
+
1
2
npm login
npm publish
+ +

如果你对组件进行了升级维护需要发布更新

+
1
2
3
npm login
npm version patch
npm publish
+ +

如何将组件引入项目

请参考Module 的加载实现

+

外部资源

http://www.ruanyifeng.com/blog/2019/08/web_components.html

+

https://developer.mozilla.org/en-US/docs/Web/Web_Components

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/05/16/23.5/index.html b/2022/05/16/23.5/index.html new file mode 100644 index 0000000..9df2a36 --- /dev/null +++ b/2022/05/16/23.5/index.html @@ -0,0 +1,144 @@ + + + + + + + + + 你的梦想是什么 ? - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

你的梦想是什么 ?

+
+ +
+

我第一次听到这个问题,是在上小学,老师开班会的时候

+

那时候老师应该没有说得这么高远,她说的应该类似于「你长大以后想干什么」这种更平白的话

+

那时候的我们哪儿懂得什么是科技创新的引领、哪儿懂得什么是救死扶伤的责任,哪儿懂得什么是匡扶正义的使命,什么是家国情怀,什么是民族复兴,…

+

毕竟这些字句大多只在电视或广播里循环播放,闻不到,也摸不着,离年幼的我们太遥远

+

很多同学都会说想当科学家,发明很多东西;想当宇航员,遨游未知的太空;想当医生,治好很多很多人的病;想当老师,培育祖国的未来…

+

似乎没有或者很少有同学会说想进一家国企,想考一个编制,想当一个公务员,想到工地搬砖头,进厂打螺丝,…

+

尽管现在网络流传“宇宙的尽头是考公”

+

那时我们说的都是我们觉得很酷的工作,我也不例外,我当时说我想当黑客,造外挂,造游戏,那简直酷毙了…

+

虽然这看起来似乎不切实际

+

一个个梦想被我们兴致盎然地写到纸片上,贴到教室后黑板旁的白墙上,希望有朝一日能再回来看看…

+

时钟不曾停止脚步,即使它没电了。

+

+

今日午休,我躺在床上,再次在心里问自己:「你的梦想是什么 ?」

+

是啊,我的梦想是什么 ?

+

仔细想来,从小升初、中考、高考,再到如今的毕业找工作,一切都是按照既定“步骤”来的(虽然还没找到工作,而且疫情和日益增长的人口也给这增加了不少难度)

+

但从语数外政史地生,到大学最终成绩单上竟有几十门课程,再到行测申论公共基础知识,国家考什么我就被要求学什么

+

一定能考上吗 ?不一定

+

就算考上了,父母夸奖你,同学羡慕你,甚至你能按月领工资,旱涝保收

+

可学过了的这些东西有什么用 ?

+

我想起那学过的几十门课程,陷入了深深的思考,

+

半数以上的课程都只能发挥帮助你升学帮助你拿到文凭这么一个功利的作用,而当你达到“目标”,它们在你的脑海里就只剩个名字

+

我不由感到一阵巨大的恐慌和自责,因为我感到浪费了太多时间,而时间就像迎面吹来的风,早已散在身后,一去不返

+

我开始有点厌恶这种功利的做法,这种看似全才的学习方式似乎很容易就让我失去对于探索未知的兴趣

+

而探索未知、发现未知、创造未知,让创造便利自己、便利他人难道不才是学习的目的和人生的动力么 ?

+

分数 ?排名 ?证书 ?仅仅把这些东西奉为学习信条简直荒唐

+

勒庞在《乌合之众》里提到过这样一个概念,叫「集体无意识」,是说一个处在集体中的人跟随集体行动,而失去了自我的意识

+

说白了,你可以理解为随大流

+

在网络遍布,信息流暴涨的今天,「emo、躺平、内卷、peer-presure」就像时代的大雾,横在我们的前路;我相信小镇做题家并不是点灯人,学会讨好企业也并不是泥潭上的救命稻草

+

相反,我很欣喜看到国内最近有一批顶尖高校退出了世界名校排名,因为这似乎是一个信号,一个沉下心来,求是求知,致力研究本土高等教育方法的信号,这极有可能成为推动未来社会快速发展的一支强心剂(尽管有点迟)

+

我不想迷失于集体无意识,也希望自己能沉下心来,于是我删除了 GitHub 个人账户上的很多旧代码,想要谋求改变,尽管这使得我的账户提交记录会大大减少致使明面上没那么“好看”,但这也使我意识到了问题的严重性,可以鞭策自己

+

+

再说到父母,他们是世界上最爱我的人,他们的所做所说都是站在他们的角度,基于他们的时代背景,观察他们的身边人,得出的可能有利于我的结论

+

但不一定完全适用于当今快速发展的社会

+

而且我认为他人的例子终究是他人,我能做的只能是分析和参考,而决不能模仿或复刻

+

所以我渴望谋求和父母的平等对话,排除辈分差别所有可能携带的些许偏见的干扰,尽管这有些困难

+

一份稳定的工作,没有太大压力以至身心俱疲,平平安安,是我和父母达成的一致,我会努力争取,但绝对不止如此

+

因为我不想成为一个没有梦想的咸鱼,我会时常问问自己,「还记得你的梦想吗 ?」

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/05/20/ssh-ubuntu/index.html b/2022/05/20/ssh-ubuntu/index.html new file mode 100644 index 0000000..b1b3b21 --- /dev/null +++ b/2022/05/20/ssh-ubuntu/index.html @@ -0,0 +1,132 @@ + + + + + + + + + 基于 openssh,连接到另一台电脑上 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

基于 openssh,连接到另一台电脑上

+
+ +
+
    +
  • 我有 2 台笔记本电脑

    +
      +
    • 一个运行着 ubuntu 系统,在我家局域网内充当服务器的角色

      +
    • +
    • 另一个运行着 manjaro 系统,是俺的日常主力机

      +
    • +
    +
  • +
+

只要两台电脑都开着机,我就能从其中任意一台电脑上轻松连接到另一台电脑上进行操作,这给我的日常带来了很大方便,具体是怎么实现的呢 ?请看下文

+

你得知道查看 IP 的方式

eg:

+
1
ip addr
+ +

首先对 ubuntu(服务器)进行操作

1
2
3
4
5
6
7
8
# 确保系统最新
sudo apt update
sudo apt upgrade

# 配置开启 ssh 服务
sudo apt install openssh-server
sudo systemctl enable --now ssh
sudo systemctl status ssh
+ +

然后就可以从 manjaro(主力机)上连接 ubuntu(服务器)

image-20220520085550466

+

那如果想从 ubuntu 上连接 manjaro 呢 ?

1
2
3
4
5
6
7
# 确保系统最新
sudo pacman -Syyu

# 配置开启 ssh 服务
sudo pacman -S openssh
sudo systemctl enable --now sshd
sudo systemctl status sshd
+ +

然后就可以从 ubuntu(服务器)上连接 manjaro(主力机)

image-20220520102623866

+

可以使用 ufw 配置防火墙,毕竟安全意识还是要有的

1
2
3
4
# Usage
tldr ufw
ufw --help
man ufw
+ +

自行配置吧~

+

当你需要多种操作系统,除了购买更多电脑

其它的一些解决方案

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/06/06/kde-connect/index.html b/2022/06/06/kde-connect/index.html new file mode 100644 index 0000000..e277bdd --- /dev/null +++ b/2022/06/06/kde-connect/index.html @@ -0,0 +1,128 @@ + + + + + + + + + 用 KDEConnect 取代微信的文件传输助手 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

用 KDEConnect 取代微信的文件传输助手

+
+ +
+

https://kdeconnect.kde.org/

+
    +
  • KDE 自带,电脑端无需安装

    +
  • +
  • 安卓端

    +
      +
    • 安装开源应用商店F-Droid
    • +
    • 从该应用商店中搜索并下载安装 KDEConnect
    • +
    +
  • +
  • 在同一局域网中,手机端和电脑端的 KDEConnect 进行配对连接,两端即可正常通信

    +
  • +
  • 注意:

    +
      +
    • 一旦切换网络代理,就需要重新配对
    • +
    • Android 9 以后不允许后台应用直接访问剪贴板了,必须用户手动从通知栏主动发送剪贴板内容到电脑
    • +
    • 插件设置列表的某些插件可以通过点击其名称跳转到该插件的设置页面
    • +
    +
  • +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/06/22/integrate-appimage-into-linuxDE/index.html b/2022/06/22/integrate-appimage-into-linuxDE/index.html new file mode 100644 index 0000000..4493daf --- /dev/null +++ b/2022/06/22/integrate-appimage-into-linuxDE/index.html @@ -0,0 +1,115 @@ + + + + + + + + + .AppImage 的用法 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

.AppImage 的用法

+
+ +
+

首先从 github 下载 .AppImage 软件包(当然从软件官网下载一样的,甚至你可以自己制作 .AppImage 软件包)

+

赋予可执行权限后将 .AppImage 软件包移动到 ~/AppImages 目录下

+

然后在 ~/.local/share/applications 目录下,编写对应的 .desktop 文件

+

文件内容举例如下

+
1
2
3
4
5
6
7
8
[Desktop Entry]
Type=Application
Name=PicGo
Icon=/home/lpj/AppImages/icons/PicGo.png
Exec=/home/lpj/AppImages/PicGo-2.3.0.AppImage
Categories=Utility
Comment="A image uploader"
Terminal=false
+ +

然后你就会发现系统已经可以自动检索到 .AppImage 软件包了

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/07/04/if-i-die/index.html b/2022/07/04/if-i-die/index.html new file mode 100644 index 0000000..e909449 --- /dev/null +++ b/2022/07/04/if-i-die/index.html @@ -0,0 +1,129 @@ + + + + + + + + + 如果我无了 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

如果我无了

+
+ +
+
+

事先声明:我目前身体健康、吃嘛嘛香、乐观开朗、未来可期 !

+
+

本文纯粹是因为看了最近热映的电影《人生大事》而产出的胡思乱想

+

+

正文开始

+

如果我无了,,,哈哈哈哈,,,我希望我的后事由我的家人这样办

+

首先,如果我的任何器官可以帮助他人脱离病痛,请无偿帮助,若身死仍能助人,酷毙了哈哈哈

+

葬礼一切从简吧,对于搭大棚开大灶摆大桌唱大戏,如果是我的话,我觉得太劳民伤财了

+

不如省下钱来让我的家人好好生活

+

我可不要又大又笨的棺材,真吓人,俺才不愿意让别人抬着,一个小小的骨灰盒就行,刻上名字但别贴照片(都埋地下了贴照片干啥)

+

骨灰盒内层要能是香椿木的就完美了,俺喜欢香椿那个味儿

+

墓地随便,但旁边要有一个枝繁叶茂的粗壮梧桐树

+

春天的梧桐花象、夏天的树荫、秋天的梧桐落叶、冬天的梧桐枝干,都很美

+

千万别种什么松柏啊啥乱七八糟的树,万古流芳啥的老一套我不喜欢

+

墓地视野要开阔,我喜欢蓝天白云和夜幕星空

+

不需要笨重的大石板墓碑,吓到路过的小朋友咋整

+

我期待真心想念我的人、期待想给我说真心话的人、期待想给我唠家常的人、期待想给我讲故事的人,他们的到来会让我开心

+

不要给我烧任何东西,污染环境 !影响我看蓝天白云 !给我放首音乐吧,曲风可以多变,但我偏爱乐呵的、舒缓的、听了让人开心的歌

+

然后,请善良勇敢乐观地过好你自己的今后人生 !!!

+

因为,我可能会变成星星,盯着你

+

哈哈哈哈哈哈哈

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/07/07/init/index.html b/2022/07/07/init/index.html new file mode 100644 index 0000000..50be6ae --- /dev/null +++ b/2022/07/07/init/index.html @@ -0,0 +1,168 @@ + + + + + + + + + 快速搭建实用个人博客网站的方法:hexo + githubAction - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

快速搭建实用个人博客网站的方法:hexo + githubAction

+
+ +
+

我的期望

    +
  1. 专注于内容创作,不需要花里胡哨的东西影响阅读和网站加载速度
  2. +
  3. 使用方便,在本地 source/_posts/ 中用 markdown 语法编写文章,使用 git 同步至远端私有仓库 then 自动触发用于自动编译部署站点的 githubActions
  4. +
+

依赖

    +
  • nvm (optional,but recommended)
  • +
  • nrm (optional, but recommended)
  • +
  • node.js
  • +
+

生成站点

1
2
3
4
5
6
7
8
9
10
11
12
13
# 初始化站点源码
npm i hexo-cli -g
hexo init blog

# 本地预览站点
cd blog
hexo s

# 给站点换个主题
https://github.com/chunqiuyiyu/hexo-theme-polk

# 再次预览
hexo s
+ +

部署站点

+

参考了这里,以我的 github 用户名 brannua 为例

+
+
    +
  • 在 github 上建立两个存储库:blog (private),brannua.github.io (public)
  • +
  • 私有存储库 blog 用于存储站点源码,公开仓库 brannua.github.io 用于部署站点
  • +
+
1
2
cd blog
npm i hexo-deployer-git --save
+ +
    +
  • 将如下配置写入 blog/_config.yml
  • +
+
1
2
3
4
deploy:
type: git
repo: https://github.com/Brannua/brannua.github.io
branch: master
+ +
1
2
3
# 部署
hexo clean
hexo deploy
+ +

好了,现在你可以去趟厕所,然后喝点水,伸个懒腰

+

网站的线上地址:https://brannua.github.io/

+

备份站点源码

1
2
3
4
5
6
7
8
9
cd blog/themes/polk
rm -rf .git

cd ../..
git init
git remote add origin https://github.com/Brannua/blog.git
git add .
git commit
git push --set-upstream origin master
+ +

配置站点信息

1
2
blog/_config.yml                # 站点的配置文件
blog/themes/polk/_config.yml # 主题的配置文件
+ +

githubActions

+

首先,借助 ssh,将私有仓库 blog 和公有仓库 brannua.github.io 打通

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 生成公私钥匙对儿
ssh-keygen -f gh-hexo-deploy

# 给私有仓库 blog 添加私钥
# blog -> Settings -> Secrets -> Actions -> New repository secret
Name: HEXO_DEPLOY_KEY
Value: ${cat ~/.ssh/gh-hexo-deploy}
# Add secret

# 给公有仓库 brannua.github.io 添加公钥
# brannua.github.io -> Settings -> Deploy keys -> Add deploy key
Title: HEXO_DEPLOY_PUB
Value: ${cat ~/.ssh/gh-hexo-deploy.pub}
# Allow write access
# Add key
+ +
+

修改 blog/_config.yml

+
+
1
2
3
4
deploy:
type: git
repo: git@github.com:Brannua/brannua.github.io.git
branch: master
+ +
+

然后配置 githubActions 实现 push 源码就触发站点的自动编译部署

+
+
1
2
mkdir -p blog/.github/workflows
vim blog/.github/workflows/deploy.yml
+ +
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
name: deploy-hexo-blog

on:
push:
branches:
- master

jobs:
build:
runs-on: ubuntu-18.04
if: github.event.repository.owner.id == github.event.sender.id

steps:
- name: 1. Setup Node.js...
uses: actions/setup-node@v1
with:
node-version: '12.x'

- name: 2. Setup Hexo...
run: |
npm i hexo-cli -g

- name: 3. Setup Git...
run: |
git config --global user.name "brannua-github-action"
git config --global user.email "374453156@qq.com"
git config --global init.defaultBranch master

- name: 4. Setup ssh...
env:
ACTION_DEPLOY_KEY: ${{ secrets.HEXO_DEPLOY_KEY }}
run: |
mkdir ~/.ssh/
echo "$ACTION_DEPLOY_KEY" > ~/.ssh/id_rsa
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts

- name: 5. Checkout source...
uses: actions/checkout@v2
with:
ref: master

- name: 6. Install dependences...
run: |
npm install

- name: 7. Build and Deploy...
run: |
hexo clean
hexo deploy
+ +
+

现在,我的所有期望已经实现

+
+

给网站配个域名

buy 域名 from aliyun.

+

实名认证 -> 创建相关信息模板 -> 设置邮箱 -> 解析域名

+

blog/source 中执行 echo ${域名} > CNAME

+

push 到 github,ok

+

域名解析生效需要一个午觉的时间

+

更具体的步骤谷歌一搜一大把,不再赘述

+

最终成果:https://liupj.top

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/07/10/mofang/index.html b/2022/07/10/mofang/index.html new file mode 100644 index 0000000..9d70065 --- /dev/null +++ b/2022/07/10/mofang/index.html @@ -0,0 +1,154 @@ + + + + + + + + + 三阶魔方还原笔记 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

三阶魔方还原笔记

+
+ +
+
    +
  1. 拼一朵白色的小花
  2. +
  3. 将白色小花变成白色十字
  4. +
  5. 还原第一层
  6. +
+
+

公式:上左下右

+
+
    +
  1. 还原第二层,只需归位 4 个棱块

    +

    从上层挑棱块并对好,然后:远离、公式、空档换手、公式

    +

    若顶层无符合条件的棱块,则没有条件就创造条件

    +
  2. +
  3. 顶面拼黄十字,拐弯右下角,直线放平行

    +
  4. +
+
+

公式:顺时针90,右手公式,逆时针90

+
+
    +
  1. 还原顶面
  2. +
+
+

公式:下右、上右、下右右上

+
+

先拼小鱼,然后鱼头对左上,做公式

+

对于拼小鱼

+
    +
  • 若少 2 点,则左后方一点黄,做公式
  • +
  • 若少 3 点,就是小鱼
  • +
  • 若少 4 点,后方无黄,做公式
  • +
+
    +
  1. 对好角块
  2. +
+

一组一样的角块对着我们,然后让黄色面对我们

+
+

公式:上右上,下180,下左上,下180;右180

+
+
    +
  1. ok
  2. +
+
+

公式:下左下右,下右下左,上左,右180

+
+

还原的侧面对着自己,做公式

+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/07/12/data-storage/index.html b/2022/07/12/data-storage/index.html new file mode 100644 index 0000000..bf2ad1b --- /dev/null +++ b/2022/07/12/data-storage/index.html @@ -0,0 +1,153 @@ + + + + + + + + + 个人数据存储方案 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

个人数据存储方案

+
+ +
+

前言

事实证明,网盘服务提供商提供的并非安全的数据备份服务,而是一种公开的数据共享服务

+

我在网盘中看到了无数人泄露的私密文件|知乎

+

故数据存储/数据备份,不使用网盘

+

另外,同步盘并不能承担备份的任务,因为任何本地的修改都会直接影响另一端,这哪还叫数据备份嘛。。

+

如果你不得不使用网盘服务

    +
  1. 你需要学会翻墙/科学上网
  2. +
  3. 然后使用新西兰的一款网盘 => Mega,因为其会自动将用户上传的文件加密,然后才存储于其服务端,数据安全性相对较高
  4. +
+

如果你不得不从外网访问家庭内网

就比如你身在公司,但是需要访问家中的电脑

+

推荐 => ZeroTier

+

其通过技术手段,允许用户构建类似于虚拟局域网的网络,任何加入用户自行创建的网络的主机均可相互通信

+

个人数据存储方案

+

考虑:数据安全性 & 服务稳定性 & 费用(包括存储费、流量费)

+
+
+

当存储体剩余不到 20% 空间时,就需要扩容了

+
+
    +
  • 需求一:自建图床

    + +
  • +
  • 需求二:个人工作环境配置文件的备份

    +
      +
    • 在 github 托管
    • +
    +
  • +
  • 需求三:个人操作系统的备份

    +
      +
    • 一个 240GB 的移动固态硬盘就足够了(反正配置文件和重要数据都有备份,即使系统崩了,大不了重做)
    • +
    • 用 timeshift 维护一组线性的系统镜像
    • +
    +
  • +
  • 需求四:其余数据的备份

    +
      +
    • 一份归档存 3 处(2 处于本地的两台 500GB linux 笔记本电脑上,1 处放阿里云的归档存储)
    • +
    • 归档只读
    • +
    +
  • +
+

Todo

    +
  • 给备份融入版本控制系统
  • +
+

(完)

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/07/22/gongkao-method/index.html b/2022/07/22/gongkao-method/index.html new file mode 100644 index 0000000..f50576f --- /dev/null +++ b/2022/07/22/gongkao-method/index.html @@ -0,0 +1,175 @@ + + + + + + + + + 公务员考试方法论(转载) - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

公务员考试方法论(转载)

+
+ +
+

公务员考试,如何上岸?

+

先说结论:通关上岸,课程占30%,刷题占60%,剩下10%交给运气。

+

30%课程:

+

很多考生总有这样一种执念,觉得xx机构的课程一定很厉害,学完基本就稳了,但就是有点贵,动辄几千上万。。还有点纠结值不值,其实,这不就明摆着割韭菜吗?

+

公考制度已经运行这么多年了,相应的课程都已经非常成熟,不存在课程决定结果的现象,如果真有这种课程,学完就上岸,你觉得会在市面上广泛流通吗?

+

公考现在是非常公平公正公开的,是除了高考之外为数不多的实现阶级跃升的方式,所以很多机构利用这一点大肆夸张宣传,所以各位,要擦亮双眼哦~

+

60%刷题:

+

公考的本质就是一个熟练度问题,刷题就是不断提高熟练度的过程,可以说刷题,是最直接有效的方法,没有之一,充分调动自身的主观能动性去实践,每做一道题相当于进行一次知识梳理,只会越来越熟练,越来越得心应手。

+

就像“你只管努力,剩下的交给天意”,“不要假装很努力,结果不会陪你演戏”,这种地摊鸡汤文写的一样。

+

“你只管刷题,剩下的交给快递,把入职通知书寄回到你家里,打开写着恭喜录取大吉大利,peace~”

+

强调一点,刷题一定要用真题,真题是最有指导意义的,可以熟悉命题规律和趋势。

+

10%运气:

+

我们都知道,行测考试时间为 120 分钟,省考一般为 120 道题,国考为 135道题,再除去涂卡时间,平均不到 50 秒钟一道题,考试的时候没有人可以全部认真思考并作答完毕!

+

因此,到最后势必会有不会做的,或者来不及做的题目,这个时候肯定不能空着不选吧,就是蒙也要选上,这个对于99%的考生来说,基本就是靠运气了,蒙的都对,那就是运气爆表,蒙的都错,也无能为力。

+

如何人为控制正确率,提高这最后一部分题目的正确率,可以看下这篇文章

+

ok,关于课程+刷题+运气,就说到这里,从宏观上做了一个扼要说明,那接下来不废话,开始正文,上备考干货。

+

行测我们按模块来,申论整体进行。

+

一、常识模块

+

这个小模块,好像很多同学认为是举足轻重的,尤其是当做过真题或者模拟题被“毒打”以后,感觉自己的公考之路马上要断送了,急需抢救一下,因为经常有同学问我,大老师,常识怎么复习,正确率好低呀。。。

+

怎么复习?不用复习,别在这浪费时间。

+

常识判断,说白了它是考察你这二十多年的一个积累,从小到大你的学习、见闻、经验、以及涉猎的其他知识,短时间的备考无法发生质的改变。

+

备考这个模块,只需利用碎片时间进行积累,等人的时间、睡觉之前、刷题休息的间隙。。。总之,不要占用正规学习时间,投入产出比太低,把有限的备考时间,用到其他能提升分数的模块上。

+

二、言语理解

+

常见的题型有:阅读理解、逻辑填空、语句表达

+

主要考察考生运用语言文字进行思考和交流、迅速准确地理解和把握文字材料内涵的能力。

+

这个模块与公务员工作联系还是比较紧密的,上级单位发的会议精神,领导要求你写的稿子,都需要快速、准确领会意图,并用文字精准的表达出来。

+

备考时,以刷题为主进行倒推,看自己哪种题型正确率偏低就着重学习哪类题型的课程,再回头进行有针对性的加强,这样一个学习思路,可以又快又准的完成此模块的备考。

+

当然,逻辑填空里的词语、成语辨析,也需要积累,学习方式同常识模块一样,利用碎片时间进行即可。

+

三、判断推理

+

由逻辑判断、图形推理、定义判断、类比推理,四个小模块组成,两推理+两判断,主要考察逻辑思维能力。

+

这个模块很多题目都是有固定公式,解题的时候千万不要当成言语理解去做,严格按照逻辑进行推演。

+

刷题之前的基础课程,务必要学扎实了,这是解题的“密钥”,很多逻辑推理规则是固定不变的,学会以后才有能去做题,不要本末倒置。

+

四、数资模块

+

数量关系+资料分析,这两个模块是行测高分的分水岭,换句话说,行测要

+

得高分,和其他考生拉开分差,这两个模块的正确率必须保证!

+

这两个模块放到一起,有相同之处又有各自的特点。

+

共同点:非常明显,对数学计算能力都有一定要求。

+

不同点:数量关系,都是各自独立的题型,例如,工程问题、抽屉原理、排列组合、年龄问题等等,每种题型之间并无关联,只要掌握某种题型,就可以做到“会一道,对一片”的效果,备考时不要过早打退堂鼓,数量关系来来回回就这么十多种题型,每种学完,花不了多少时间精力,剩下交给刷题,提高熟练度即可。

+

资料分析,是一个整体,通过一段材料或者表格数据,进行整体分析计算,其中会涉及到如何快速阅读、快速估算、定性分析,技巧性比较强

+

五、申论

+

写的好不如抄的好,不要过度发挥,忠于原材料,紧扣主旨。

+

小学都做过阅读理解题吧,其中就有一道题叫做概括段落大意,其实申论要得高分,道理一样,把它当成一篇大型的概括段落大意题,紧紧围绕主旨,再适当的地方加上你储备的一些金句。

+

再说下阅卷规则与注意的事项

+

申论都是网上阅卷,阅卷老师分成几个组,每组只阅一道题,而且只能在屏幕上看到这一道题,如果你写到格子外头去了,阅卷老师就看不到了。

+

80%以上的老师根本都没有看过申论试题和给出的材料,只需要记住答案要点就可以上阵了。每组都有组长。大家首先进行试评。一人20份卷子,评过之后统计时间和分数分布区间,每道题根据分值的不同划定出一个误差区间。

+

正常情况下,一道题会有两个老师阅卷,他们给出的分数可能有高有低,如果分数差在误差区间内,那就取两者的平均值为该题的分数;如果分数差超过了误差区间,那就要组长进行三评,并以组长给出的分数为准。

+

电脑会自动统计出该组的三评率,如果三评率超出了规定范围,则证明这个阅卷组对于阅卷没有达成共识,对不起,前面所有的工作白费,重新停下来,大家统一规则,然后重新试评20份,误差率合格了,再重新阅卷。

+

想想吧,如果因为你个人的原因,分数误差大了导致全组停工试评从头再来,那是多大的罪过啊!所以,阅卷老师们都会心照不宣的在中间分和安全分上徘徊,以免出现招人白眼的状况。

+

枪打出头鸟,每个老师所有给出的分数都是在电脑终端有统计的,如果给出的分数太高,或者高分太多,或者中间分数太少,那巡视员就会把这个老师叫到电脑终端屏幕前,让他看分数曲线,然后温和的说一句,要不然,你们组再试评一下?为了集体荣誉,绝对不能重来啊!所以,大家都会努力的向中间分靠拢。

+

那什么是中间分和安全分,举个例子,一道20分的题目,可能你觉得自己应该怎么也能打个14分吧,哈哈,错啦!一道20分的题目,中间分是10分,标准误差是3分,也就是说,万一一个老师给该题打了10分,那你作为另一个阅卷老师,最高打到13分,最低打到7分。

+

但是,万一你觉得挺好的文章,另一个老师只给八九9分,你打13分就超了啊!所以,保险一点,打个11分总不会错,就算另一个老师觉得该题答得不好,也不至于给到7分以下或者14分以上了吧。

+

这就是一个阅卷博弈,经过这样一番博弈,大家的默契就是:一般的,给8-9分;还不错的,9-10分;不怎样的,7-8分;非常差的,6-7分;非常好的,10-11分。打到6分以下的低分或者13分以上的高分都是冒着生命危险的,很难很难。这就是为什么很多人觉得自己答得不错但是100分的申论才只得了四五十分的原因。

+

申论的第一二道题是得分的关键。

+

这是因为,客观的点好找,容易达成共识,老师们数着采分点给分,一般差距不大,分数得的也理直气壮;

+

最可怕的是主观性的阅卷分数,太没谱了,老师就是觉得文章写得好,也不敢给高分。所以,临考不到一个月,努力抓好前两道题,练习找准采分点,比使劲练大文章要有用得多。

+

那什么是采分点呢?说起来也挺荒唐的。阅卷组拿到申论答案以后,会根据题目分值将答案进行分配。

+

比如说15年国考申论第一道题吧,20分由结构分2分,采分点16分(八个点),主观分2分构成,大概是只要能答出“文段说了两件事情”,有个“两件、二层”之类的字样,就能得到结构分2分,用了分号但是没写“两”,就没这2分;

+

然后“粮食安全”“民生”各两分;再有什么就已经记不得了。反正,其实批卷子到后来,已经麻木到连自己都记不得答案和完整的采分点是什么了。就是给个中间分安全分,字好一点的看着顺眼一点,有几个点的,就给个9分,字差一点或者采分点少一点的,就7、8分,保证不会出错,误差率也在可控范围,全组的阅卷率很容易通过。

+

要是后面的大题就更虚了,不可能将好几十分都拆成一个个采分点,所以都是划档给分的,这就比前两道题靠采分点给分要模糊得多。

+

一般来讲,还是给个中间分,50分的题目,给个23分-27分之间就可以了。

+

阅卷时间的话,都是在电脑屏幕上阅卷,想象一下,每天从早上八点半开始盯着屏幕一字一字的看枯燥的重复内容,一直到晚上六点。除了上厕所和吃饭,基本没什么休息,脖子会酸屁股会麻胃里恶心眼睛会瞎掉,很辛苦的!

+

所以大家都想快点结束战斗,第一是不要取消成绩重新试评,第二是单位时间尽量多批一点。而且组员之间和各个组之间也都有无声的较量,每个人的业绩量都是清晰可见的,你批得少,那就是赤裸裸的偷懒了,会遭人鄙视的。

+

相对来说,新手阅卷时间都比较长,反复看反复找,还要斟酌给多少分,一道200字的题目可能要阅15-30秒,这样单位时间内阅卷量就会非常少,电脑终端那里显示你的工作量和单位效率都很可怜,经过一会儿的磨练,新手就会逐渐赶超老手,争取每道题五六秒的速度,甚至更快。

+

400字的题目,阅卷大概是8到10秒。最可怕的是800到1000字的大文章,阅卷时间老手差不多12秒,新手也会在16秒左右结束战斗。也就是说你辛辛苦苦花两个小时写的东西,阅卷老师统共用不上30秒,已经决定了你的生死,这才是名副其实的秒杀!

+

还有一点,为了便于规范统一,采分点大多数都是题目中已经给出的关键词或字眼,或者稍加改装整理。除了重要领导的重要讲话,一般的别的词汇是不太可能成为标准答案中的采分点的。

+

所以,如何从材料中找出关键词关键字眼,然后把他们拼到答案中,是练习的关键。某些参考答案脱离材料天马行空的提对策,即使可行,也不会是采分点的。

+

所以,申论备考,就一句话,忠于原材料,总结采分点。

+

关于公考备考,其实没有多复杂,充分发挥主观能动性,反复去练习总结,上岸只是时间问题。加油了各位!

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/08/05/sigint-and-other-termination-signals-in-linux/index.html b/2022/08/05/sigint-and-other-termination-signals-in-linux/index.html new file mode 100644 index 0000000..52bdd2f --- /dev/null +++ b/2022/08/05/sigint-and-other-termination-signals-in-linux/index.html @@ -0,0 +1,167 @@ + + + + + + + + + SIGINT And Other Termination Signals in Linux(转载) - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

SIGINT And Other Termination Signals in Linux(转载)

+
+ +
+
+

原文地址:https://www.baeldung.com/linux/sigint-and-other-termination-signals

+
+

Overview

In Linux systems, processes can receive a variety of signals, such as SIGINT or SIGKILL. Each signal is sent in different situations and each has different behavior.

+

In this article, we’ll talk about SIGINT, SIGTERM, SIGQUIT, and SIGKILL. We’ll also see the difference between them.

+

Introduction to Signals

The signals are a method of communication between processes. When a process receives a signal, the process interrupts its execution and a signal handler is executed.

+

How the program behaves usually depends on the type of signal received. After handling the signal, the process may or may not continue its normal execution.

+

The Linux kernel can send signals, for instance, when a process attempts to divide by zero it receives the SIGFPE signal.

+

We can also send signals using the kill program. Let’s run a simple script in the background and stop it:

+
1
2
3
4
$ (sleep 30; echo "Ready!") &
[1] 26929
$ kill -SIGSTOP 26929
[1]+ Stopped ( sleep 30; echo "Ready!" )
+ +

Now, we can resume it using SIGCONT:

+
1
2
3
$ kill -SIGCONT 26929
Ready!
[1]+ Done ( sleep 30; echo "Ready!" )
+ +

Alternatively, we can send signals in a terminal using key combinations. For instance, Ctrl+C sends SIGINT, Ctrl+S sends SIGSTOP, and Ctrl+Q sends SIGCONT.

+

Each signal has a default action, but a process can override the default action and handle it differently, or ignore it. However, some signals can’t be ignored nor handled differently and the default action is always executed.

+

We can handle signals in bash using the trap command. For instance, we can add trap date SIGINT in a script and it will print the date when SIGINT is received.

+

SIGINT

SIGINT is the signal sent when we press Ctrl+C. The default action is to terminate the process. However, some programs override this action and handle it differently.

+

One common example is the bash interpreter. When we press Ctrl+C it doesn’t quit, instead, it prints a new and empty prompt line. Another example is when we use gdb to debug a program. We can send SIGINT with Ctrl+C to stop the execution and return it to the gdb’s interpreter.

+

We can think of SIGINT as an interruption request sent by the user. How it is handled usually depends on the process and the situation.

+

Let’s write handle_sigint.sh using the trap command to handle SIGINT and print the current date:

+
1
2
3
4
5
6
7
#!/bin/bash

trap date SIGINT

read input
echo User input: $input
echo Exiting now
+ +

We use read input to wait for the user interaction. Now, let’s run our script and let’s press Ctrl+C:

+
1
2
$ ./handle_sigint.sh 
^CSat Apr 10 15:32:07 -03 2021
+ +

We can see the script didn’t exit. We can now terminate the script by writing some input:

+
1
2
3
4
5
$ ./handle_sigint.sh 
^CSat Apr 10 15:32:07 -03 2021
live long and prosper
User input: live long and prosper
Exiting now
+ +

If we want to use a signal to terminate it, we can’t use SIGINT with this script. We should use SIGTERM, SIGQUIT, or SIGKILL instead.

+

SIGTERM and SIGQUIT

The SIGTERM and SIGQUIT signals are meant to terminate the process. In this case, we are specifically requesting to finish it. SIGTERM is the default signal when we use the kill command.

+

The default action of both signals is to terminate the process. However, SIGQUIT also generates a core dump before exiting.

+

When we send SIGTERM, the process sometimes executes a clean-up routine before exiting.

+

We can also handle SIGTERM to ask for confirmation before exiting. Let’s write a script called handle_sigterm.sh to terminate only If the user sends the signal twice:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

SIGTERM_REQUESTED=0
handle_sigterm() {
if [ $SIGTERM_REQUESTED -eq 0 ]; then
echo "Send SIGTERM again to terminate"
SIGTERM_REQUESTED=1
else
echo "SIGTERM received, exiting now"
exit 0
fi
}

trap handle_sigterm SIGTERM

TIMEOUT=$(date +%s)
TIMEOUT=$(($TIMEOUT + 60))

echo "This script will exit in 60 seconds"
while [ $(date +%s) -lt $TIMEOUT ]; do
sleep 1;
done
echo Timeout reached, exiting now
+ +

Now, let’s run it on background executing $ ./handle_sigterm.sh &. Then, we run $ kill <PID> twice:

+
1
2
3
4
5
6
7
$ ./handle_sigterm.sh &
[1] 6092
$ kill 6092
Send SIGTERM again to terminate
$ kill 6092
SIGTERM received, exiting now
[1]+ Done ./handle_sigterm.sh
+ +

As we can see, the script exited after it received the second SIGTERM.

+

SIGKILL

When a process receives SIGKILL it is terminated. This is a special signal as it can’t be ignored and we can’t change its behavior.

+

We use this signal to forcefully terminate the process. We should be careful as the process won’t be able to execute any clean-up routine.

+

One common way of using SIGKILL is to first send SIGTERM. We give the process some time to terminate, we may also send SIGTERM a couple of times. If the process doesn’t finish on its own, then we send SIGKILL to terminate it.

+

Let’s rewrite the previous example to try to handle SIGKILL and ask for confirmation:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

SIGKILL_REQUESTED=0
handle_sigkill() {
if [ $SIGKILL_REQUESTED -eq 0 ]; then
echo "Send SIGKILL again to terminate"
SIGKILL_REQUESTED=1
else
echo "Exiting now"
exit 0
fi
}

trap handle_sigkill SIGKILL

read input
echo User input: $input
+ +

Now, let’s run it on a terminal, and let’s send SIGKILL only once with $ kill -SIGKILL <pid>:

+
1
2
3
$ ./handle_sigkill.sh
Killed
$
+ +

We can see it terminate right away without asking to re-send the signal.

+

How SIGINT Relates to SIGTERM, SIGQUIT and SIGKILL

Now that we understand more about signals, we can see how they relate to each other.

+

The default action for SIGINT, SIGTERM, SIGQUIT, and SIGKILL is to terminate the process. However, SIGTERM, SIGQUIT, and SIGKILL are defined as signals to terminate the process, but SIGINT is defined as an interruption requested by the user.

+

In particular, if we send SIGINT (or press Ctrl+C) depending on the process and the situation it can behave differently. So, we shouldn’t depend solely on SIGINT to finish a process.

+

As SIGINT is intended as a signal sent by the user, usually the processes communicate with each other using other signals. For instance, a parent process usually sends SIGTERM to its children to terminate them, even if SIGINT has the same effect.

+

In the case of SIGQUIT, it generates a core dump which is useful for debugging.

+

Now that we have this in mind, we can see we should choose SIGTERM on top of SIGKILL to terminate a process. SIGTERM is the preferred way as the process has the chance to terminate gracefully.

+

As a process can override the default action for SIGINT, SIGTERM, and SIGQUIT, it can be the case that neither of them finishes the process. Also, if the process is hung it may not respond to any of those signals. In that case, we have SIGKILL as the last resort to terminate the process.

+

Conclusion

In this article, we learned about signals and the difference between SIGINT, SIGTERM, SIGQUIT, and SIGKILL. Also, we briefly learned how to handle signals in bash.

+

We saw how SIGINT sometimes doesn’t kill the process as it may a different meaning. On the other hand, the SIGKILL signal will always terminate the process.

+

We also learned that SIGQUIT generates a core dump by default and that SIGTERM is the preferred way to kill a process.

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/10/02/movies/index.html b/2022/10/02/movies/index.html new file mode 100644 index 0000000..e303f65 --- /dev/null +++ b/2022/10/02/movies/index.html @@ -0,0 +1,295 @@ + + + + + + + + + 记录我看过的影片 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

记录我看过的影片

+
+ +
+

记录一下我看过的,我认为好看的影片,大概以后会重温吧。

+

电影

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
片名
触不可及
辛德勒的名单
切尔诺贝利
后天
忠犬八公的故事
你好,李焕英
海上钢琴师
隐入尘烟
人生大事
当幸福来敲门
活着
肖申克的救赎
我不是药神
摔跤吧!爸爸
心灵捕手
被解救的姜戈
背靠背,脸对脸
1942
平凡英雄
血战台儿庄
小鬼当家(只有第一部好看)
困在时间里的父亲
唐山大地震
魔女(只有第一部好看)
珍珠港
决战中途岛
<++>
<++>
+

国产剧

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
片名
亮剑
小兵张嘎
恋爱先生
情满四合院
人民的名义
好先生
父母爱情
新三国
小欢喜
<++>
<++>
<++>
+

动画

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
片名
坏蛋联盟
终极细胞战
葫芦娃
狮子王
黑猫警长
猫咪小贝
哪吒闹海
虹猫蓝兔七侠传
机器猫(小叮当)
猫和老鼠
舒克贝塔
成龙历险记
<++>
<++>
<++>
+

to be continue…

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/10/22/1_big_20/index.html b/2022/10/22/1_big_20/index.html new file mode 100644 index 0000000..a4b31bd --- /dev/null +++ b/2022/10/22/1_big_20/index.html @@ -0,0 +1,123 @@ + + + + + + + + + 矢志不渝,争做踔厉奋发通信人 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

矢志不渝,争做踔厉奋发通信人

+
+ +
+
+

学习党的第二十次全国代表大会有感

+
+

十月金秋,我们党的第二十次全国代表大会在和畅惠风中徐徐拉开大幕,我怀着一颗无比崇敬而向往的心,认真收看学习了习总书记在开幕会上的精彩报告,颇受激励,遂有如下感悟。

+

漫漫征程看领航

+

回首过往百年,是我们党始终牢牢把握了民族复兴征途的航向,不惧艰险,拨开迷雾,团结带领着亿万人民砥砺前行。身为一名新时代青年,我深知初出茅庐的我肩负着为国家大业添砖加瓦的一份使命和责任,就像鲁迅先生曾说的那样——摆脱冷气向上走,有一份光,发一份热;又如习总书记说的那样——当代青年生逢其时,施展才干的舞台无比广阔,实现梦想的前景无比光明。我深以为然。故而更加坚定了心中紧紧跟党走的信念,更加笃定了为家国事业脚踏实地、谦虚谨慎、艰苦奋斗的底气和决心。

+

武装思想抓实践

+

托尔斯泰有言——文明的建立不是机器而是思想,我们党历经百年风雨,俨然壮大为今日国际最大的马克思主义政党,恰得益于我们国家一代代共产党人对先进马克思主义的深刻学习和领会,以及先辈们充分发挥主观能动性,审时度势因地制宜地不断改造发展马克思主义,让其越发闪耀出本土化、时代化光芒的创新之举。我们青年一代是祖国未来几十年发展的主力军,更应奋力扛起习近平新时代中国特色社会主义的伟大旗帜,不断坚定道路自信、理论自信、制度自信和文化自信,不断学习和发扬一代代革命先辈们的锐意进取、守正创新和矢志不渝,从实践中来,到实践中去,在今后的工作岗位上多尝试新思路、多思考新办法,承前人之硕果,不断提质增效,续写华夏新篇章。

+

回首成就固成因

+

十八大以来的十年里,我们党团结带领全国各族人民完成了脱贫攻坚、全面建成小康社会的历史任务,中国特色社会主义进入了新时代,能取得如此举世瞩目的成就,定然在过往的各项工作中我们收获了不可胜数弥足珍贵的实践经验,那么我们就应该将这些零零碎碎的经验好好梳理,穿成串、织成网,充实丰富我们改革开放民族复兴大业前行路上的工具箱,为新征程不断助力。见著而观微,身为当代通信人,我不断观察学习着行业同事们高效的工作方式,不断听取借鉴着行业前辈们宝贵的工作经验,我感受到他们的热心和友善,更感受到他们的信任和期盼,经验是行业的传承,发展是行业的目标,前辈们宝贵的实践经验给我的信心以支撑,给我的信念以动能,青年强则国强,行业兴则国兴,我们通信行业青年一代必会抬头看路埋头前行,继往开来不辱使命。

+

把握机遇迎挑战

+

新冠疫情肆虐,国际形势复杂多变,近些年着实不寻常、不平凡,在如此社会大背景下,作为肩挑国家通信事业大梁的主力军,我们应当从挑战中敏锐发现机遇、把握机遇,始终将一颗建设、服务的心同党和人民紧密联系在一起,深入基层,奉献社会,做好当前形势下的通信保障工作;我深知打铁还需自身硬,我们年轻一代通信人还应当积极学习更先进科学文化知识,用科技的力量促进高质量发展,推动我国通信事业不断迈向更高的台阶,用更强大的网络基础设施催生更多先进上层应用的实施研发,保障更多高新产业的落地推广;我们还应从提升自身的网络安全意识做起,主动向身边人、全社会普及网络安全知识,努力提高全民的网络安全防范化解风险意识,以更加从容的姿态直面风险、应对挑战。

+

前途光明,任重道远,空谈误国,实干兴邦,我们联通青年必将不忘初心跟党走,牢记使命勇前行。

+
+

天津联通河东分公司,刘培杰。

+
+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/12/09/music-linux-method/index.html b/2022/12/09/music-linux-method/index.html new file mode 100644 index 0000000..373d7e5 --- /dev/null +++ b/2022/12/09/music-linux-method/index.html @@ -0,0 +1,140 @@ + + + + + + + + + 我在 Linux 上听歌的方式 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

我在 Linux 上听歌的方式

+
+ +
+

前言

我喜欢听歌,但苦于国内各大音乐平台的割据状态(版权、音质、网速、…)

+

而我又喜欢双手不离开键盘(不用鼠标,尽可能地少用触控板)且我希望将尽可能多的工作在一个终端窗口中完成

+

于是我开始了如下探索,试图建立适合自己的听歌方式…

+

最佳的音乐播放体验

当然是从互联网中搜索无损音乐(.flac),下载到本地进行播放咯

+

从哪找没听过的歌呢

listen1

+

20221210150913

+

本地音乐播放器推荐

audacious

+

20221210150313

+

怎么把想听的歌下载到本地呢

https://github.com/zonemeen/musicn 404 了

+

musicn|npmjs

+

注意:该软件依赖 node.js 16+ 版本,我设置的版本为 v16.18.1,设置方式可参考这里

+

小技巧:echo "alias msc="msc -p DIR_TO_STORE_MUSICS" >> ~/.bashrc if you use bash.

+

哎嗨 !我们已经可以在终端中搜索并下载音乐了,测试使用效果如下

+

20221209150558

+
+
+

以下播放音乐的方式仅适用于播放单个音频文件,仅供参考,选看。

+
+

sox

如果只是想在终端中简单地播放一个音频文件/一首歌,那么推荐使用软件 sox 提供的 play 命令

+

Install by executing sudo pacman -S sox if you use ArchLinux like me.

+

测试使用效果如下

+

20221209152728

+

参考了:https://askubuntu.com/questions/920539/how-do-you-play-a-sound-from-the-terminal

+

ranger + vlc

vlc 是一款在 Linux 上广受好评的多媒体播放器,能播放视频和音乐

+

而且我习惯使用 Ranger, 一款为 vim/neovim 用户打造的文件浏览器,很好用 !

+

所以我希望 Ranger 能识别我的音乐文件并自动调用 vlc 播放

+

Luckily, Ranger ships with rifle, a file launcher that is good at automatically finding out which program to use for what file type. —— knowing from Ranger’s doc

+

所以我只需对 rifle配置文件进行一下简单的修改即可

+

20221210153018

+

测试使用效果如下,可以看到 Ranger 自动调用 vlc 开始播放音乐文件了

+

20221209160452

+

参考了:https://superuser.com/questions/724689/open-vlc-in-background

+

期望

受限于目前的工作和技术水平,我对目前的听歌方式还不够满意,希望在未来能打造一个适合我自己的音乐播放软件(GUI or CLI)running on linux which is both open-source、lightweight and reliable.

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/12/12/ill/index.html b/2022/12/12/ill/index.html new file mode 100644 index 0000000..5eaaed4 --- /dev/null +++ b/2022/12/12/ill/index.html @@ -0,0 +1,119 @@ + + + + + + + + + 小羊人的复盘与反思 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

小羊人的复盘与反思

+
+ +
+

稳住 !

+

明确

发热不是一件坏事,而是你的身体在与病毒做对抗

+

注意保暖,用煮鸡蛋和电解质水来为身体的免疫系统提供“弹药”支持

+

药品需要在药师的指导下使用,38.5 度以上才可考虑使用退烧药

+

去附近大医院发热门诊

+

医保码、挂号、缴费、出具检验报告、就诊ID,手机上都能整 !

+
+

+

书包、充好电的手机、身份证

+

口罩、酒精湿巾、保温杯、面包

+

毛巾、卫生纸

+

手套、围巾、帽子

+ +
+ +
+ + +
+ + +
+ + diff --git a/2022/12/31/windows10-in-virtualbox/index.html b/2022/12/31/windows10-in-virtualbox/index.html new file mode 100644 index 0000000..94401c1 --- /dev/null +++ b/2022/12/31/windows10-in-virtualbox/index.html @@ -0,0 +1,109 @@ + + + + + + + + + 在 ArchLinux 主机上安装 win10 虚拟机 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

在 ArchLinux 主机上安装 win10 虚拟机

+
+ +
+

想啥呢 !在 Linux 主机上安装虚拟机是一件非常痛苦的事情 !

+

从此以后,不再在 Linux 主机上折腾一切有关虚拟机的东西 !

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/01/07/why-chrome/index.html b/2023/01/07/why-chrome/index.html new file mode 100644 index 0000000..e6fce33 --- /dev/null +++ b/2023/01/07/why-chrome/index.html @@ -0,0 +1,119 @@ + + + + + + + + + 我为什么放弃了 firefox,重新回到 chrome - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

我为什么放弃了 firefox,重新回到 chrome

+
+ +
+

小孩子才做选择,chrome & firefox 我全都要 !

+

主 chrome

+

辅 firefox

+
+

以下为原文

+
+

course, v2raya is awesome.

+
+

firefox 的痛点让我换回了 chrome

+

1、对沙拉查词的支持度不如 chrome

+

2、firefox 的快捷键默认无法修改,在组合键 ctrl-shift-p 上与 picgo 冲突,虽然可以修改 picgo 的快捷键,但更换组合键不便于记忆

+

3、I hate programs creating files or folders in my home directory casually without my permission, such as ~/.mozilla

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/01/30/mac-ip/index.html b/2023/01/30/mac-ip/index.html new file mode 100644 index 0000000..2683fc6 --- /dev/null +++ b/2023/01/30/mac-ip/index.html @@ -0,0 +1,139 @@ + + + + + + + + + 分享一道计算机网络的经典面试题(关于为什么网络层地址和 MAC 地址共存) - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

分享一道计算机网络的经典面试题(关于为什么网络层地址和 MAC 地址共存)

+
+ +
+

有了 MAC 地址,为什么还需要 IP 地址 ?

计算机网络诞生之初,只是一个个小的局域网,还没有形成如今的互联网;

+

局域网内的计算机之间通信,需要对每个计算机进行唯一标识,所以就诞生了 MAC 地址。

+

随着计算机网络的发展,局域网之间开始互联互通,产生了计算机跨网络通信的需求;

+

试想,假设局域网 A 内的主机 A1 想要发送数据包给局域网 B 内的主机 B1

+

若 A1 只知道 B1 的 MAC 地址,显然 A1 无法知道应该将数据包发往哪个网络

+

即:MAC 地址并不具备标识网络的作用

+

所以,能够标识网络的 IP 地址诞生

+
+

既然 IP 地址的定位是标识网络,那么为什么要把 IP 地址设计成既能标识网络,又能标识主机 ?

举个例子,假设局域网 A 内的主机 A1 想要发送数据包给局域网 B 内的主机 B1

+

假设A1 只知道 B1 的 IP 地址

+

如果 IP 地址只能标识网络,那么 A1 就只能将数据包发往目的网络,然后数据包就不知该何去何从了

+

所以 IP 地址既要能标识网络,又要能标识主机

+
+

既然有了 IP 地址,为什么还要有 MAC 地址 ?或者说只靠 IP 地址进行互联网通信行不行 ?

+

参考了:http://liupj.top/2022/04/04/ether-net/

+
+

如果没有 MAC 地址,而是使用网络层协议进行通信,理论上来说是可以的,但是不好

+

因为在以太网诞生之初,IP 还没有垄断网络层协议(那时还有Novell网的IPX/SPX协议、DEC公司开发的CLNP网络协议,以及Apple公司开发的Apple Talk协议)

+

如果没有 MAC 地址,势必需要网卡解读网络层协议帧头的地址信息,而不同网络层协议帧头的地址都大相径庭,这就增加了以太网卡的实现复杂度。

+

如果网卡有了 MAC 地址,就可以不依赖于任何网络层协议,独立判断一个帧是否接收(依据 MAC 地址匹配),这就大大简化了网卡的实现。

+

即使以后出现更多的网络层协议,网卡也无需太多的改变,这就是网络分层的精髓

+

一层的内部实现无需知晓其上层、或下层

+
+

其实,《计算机网络自顶向下方法》对该问题有明确的回答

+

英文原版
20230130194206

+

中译版
20230130194400

+
+

综上所述,MAC 和 IP 缺一不可。

+

从 IP 到 MAC 的转换,使用 ARP 协议。

+
+

补充知识:

+

主机的 IP 地址是可以动态变化的,而 MAC 地址是写死的,一般不能变(当然也有随机 MAC 的手段

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/01/31/zerotier/index.html b/2023/01/31/zerotier/index.html new file mode 100644 index 0000000..35eb548 --- /dev/null +++ b/2023/01/31/zerotier/index.html @@ -0,0 +1,120 @@ + + + + + + + + + zerotier 简明教程 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

zerotier 简明教程

+
+ +
+

前言

一台 ArchLinux 放家里,一台 Windows10 放单位

+

用 zerotier 将这俩机器放到一个虚拟局域网

+

用 ssh 就能相互访问

+

用 zerotier 创建一个私有的(private)虚拟局域网,获取到网络ID

https://my.zerotier.com/

+

创建私有网络的好处是:任何机器想加入该网络都需要获得你的许可

+

ArchLinux 设置步骤

1
2
3
sudo pacman -S zerotier-one
sudo systemctl enable --now zerotier-one.service
sudo zerotier-cli join 网络ID
+ +

Windows10 设置步骤

下载地址:https://www.zerotier.com/download/

+

启动 zerotier,加入网络

+

最后

https://my.zerotier.com/ 对成员节点勾选授权

+

ok,至此,两台机器可以通过 ssh 相互访问

+

参考了

https://www.zerotier.com/manual/

+

https://jiajunhuang.com/articles/2019_09_11-zerotier.md.html

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/03/18/macos-m1-setup/index.html b/2023/03/18/macos-m1-setup/index.html new file mode 100644 index 0000000..48888ea --- /dev/null +++ b/2023/03/18/macos-m1-setup/index.html @@ -0,0 +1,123 @@ + + + + + + + + + 记录我上手使用 Macbook Air M1 的过程 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

记录我上手使用 Macbook Air M1 的过程

+
+ +
+

前言

2023-03-18, 我收到了我人生中第一台 MacBook Air M1

+

由于这是我第一次使用 macos,所以我打算记录下我上手 macos 的过程

+

希望将它慢慢打造成适合我的一把利器,那就开始吧

+

进入桌面前的初始化设置操作就自己弄吧,原则:最小化设置

+

设置触控板

点击屏幕左上角苹果 logo,然后选择系统设置,然后在打开的窗口的左侧边栏中下拉选择触控板

+

跟踪速度自行调整,勾选轻点来点按

+

设置键盘

由于我是 Vim 重度用户,所以习惯性将 Caps Lock 键设置为 Escape 键

+

系统设置 =》键盘 =》闲置后关闭键盘背光灯(5分钟后)=》键盘快捷键 =》修饰键 =》大写锁定键更改为 Escape 键 =》完成

+

设置三指拖移:系统设置 =》辅助功能 =》指针控制 =》触控板选项 =》打开“使用触控板进行拖移”(或“启用拖移”)=》选取“三指拖移”拖移样式

+

=》好

+

安装一些应用程序

qq音乐、微信,腾讯会议,阿里云盘,…

+

科学上网

节点 + clashX 开启系统代理

+

单独给 Terminal.app 设置代理

+
1
2
3
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export all_proxy=socks5://127.0.0.1:7890
+ +

打造命令行

包管理器:brew

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/03/28/how-to-buy-courses-on-udemy-in-china/index.html b/2023/03/28/how-to-buy-courses-on-udemy-in-china/index.html new file mode 100644 index 0000000..edc2878 --- /dev/null +++ b/2023/03/28/how-to-buy-courses-on-udemy-in-china/index.html @@ -0,0 +1,120 @@ + + + + + + + + + 如何购买国外的课程(在中国) - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

如何购买国外的课程(在中国)

+
+ +
+

先看看这篇文章:从支付、购买到售后:Google Play 购物指南

+

ok, 我选择使用【礼品卡】的付款方式

+

使用的设备

macbook、iqoo-z5

+

背景

我的每台设备均可以正常访问 google

+

读者可以各显神通以获得速度良好的外网访问权限

+

安卓手机如何下载 play 商店

下载渠道:apkmirror.com

+

参考了这个视频:https://www.youtube.com/watch?v=isERiuP5xTY

+

安卓手机通过验证码验证谷歌账号时若不显示验证码的输入框怎么办

将手机的【验证码安全保护】关闭即可,可在手机设置中搜索

+

感谢这个视频的评论区给予的帮助

+

在哪购买礼品卡

淘宝搜索【play 礼品卡】

+

根据自己需要哪个国家或地区的💰来选择购买礼品卡

+

笔者礼品卡购于咸鱼,使用方式可询问卖家

+

done

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/04/01/py_takeaway_message/index.html b/2023/04/01/py_takeaway_message/index.html new file mode 100644 index 0000000..bfae6bc --- /dev/null +++ b/2023/04/01/py_takeaway_message/index.html @@ -0,0 +1,117 @@ + + + + + + + + + 简单学了一下 python 脚本编程 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

简单学了一下 python 脚本编程

+
+ +
+

learn from: https://learn.udacity.com/courses/ud1110

+

A scripter to solve problem

1
2
3
4
5
6
7
8
9
10
repeat:

try it the slow way to understand what you are trying to achieve
do some learning(remember to look up documentation)

break up the problem into steps
choose data_types、control_flows、...
write down your pseudo_code

write code & test code
+ +

why you should choose data_type

An object’s type defines which operators and functions will work on that object and how they work,

+

different types have different properties,

+

so when you’re designing on computer program,

+

you need to choose types for your data based on how you’re going to use them.

+

For example, if you want to use a number as a part of a sentence in Python,

+

it’ll be easiest if that number is a string,

+

because there are specially designed operators and functions for working with these data.

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/06/24/mountTai/index.html b/2023/06/24/mountTai/index.html new file mode 100644 index 0000000..664ee20 --- /dev/null +++ b/2023/06/24/mountTai/index.html @@ -0,0 +1,178 @@ + + + + + + + + + 夜爬泰山有感 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

夜爬泰山有感

+
+ +
+

因为网上别人发表的攻略给了我不少帮助,所以我也决定写下这篇攻略,分享给大家

+

说实话,夜爬泰山之后,我是有些后怕的,为了大家的安全着想,我要先写一下此次夜爬我感受到的危险

+

我没有数我到底爬了多少级台阶,但据网友反映泰山大致需要爬六七千级台阶(但我觉得这每一级台阶都比普通住宅楼里的台阶更窄、更陡、更不平)

+

端午假期游人众多,十有八九都是二十啷当岁初生牛犊不怕虎的年轻人,达到了人挤人的状态,众多的爬山人和漆黑的夜色给山路增加了不少危险性

+

因为台阶上会有空的矿泉水瓶、西瓜皮、水果核,甚至还会有别人遗弃的登山杖,这些东西会向山下掉落,而你很难时刻注意你脚下的真实情况

+

一旦不小心踩住或绊住,就特别容易摔跤(下山路上不少台阶上已经干了的暗红色血迹真的让人不寒而栗)

+

而在人挤人的情况下,摔跤就变得更加危险,无论是自己摔跤还是别人摔跤,都极易造成连锁反应(幸好我没遇到)

+

另外,如果你爬到半山腰想放弃,你会进退两难,你只能向山路两边的护栏和岩石靠拢,而部分爬不动的人放倒在地面上的登山杖又容易绊倒上山的人

+

渴、饿、累、困、冷、拉肚子、低血糖,还有其他情况在高山上的夜晚都可能出现,商店很多,厕所不多,没有医院

+

另外,上山容易下山难,这是亘古不变的真理!!!

+

看到这里如果你觉得你可以,我要开始安利了

+

上山之前

你可以像我一样,下午去山东农大旁边的清真寺街吃当地的特色美食——姜片炒鸡

+

WechatIMG13

+

清真寺街的许家姜片炒鸡很好吃也很适合作为上山前补充体力的食物

+

鸡肉外香里嫩干而不柴,姜片是油炸过的,薄脆像薯片,很适合我这种不喜欢姜味的人哈哈哈哈哈

+

老板娘年轻美丽,长得像我高中语文老师,掌柜的慈眉善目和蔼可亲,看起来人很正派,希望他们家红火

+

我吃了一只炒鸡一碗大米半份蒜泥黄瓜,昏昏欲睡。。

+

那就去红门游客中心旁边开个房吧,钟点房一小时 20 元,一觉醒来八点半了。。

+

九点多向山顶进发!

+

爬山途中

一路上我竟然没有一丝困意,大概是太想登顶了吧,虽然我一直在出汗,一直在补水,到中天门没忍住,吃了两块西瓜

+

反正周围一片漆黑全是人啥风景也看不到,心中只有一个目标,冲向山顶!

+

早知道就不带风油精了,蚊子大概不知道该咬谁吧,全是人。。

+

脑海里竟然出现了角马大迁徙的场景,那个画面。。我们就是英勇无畏的角马!

+soMuchPeople + +

登山杖立起来啊朋友们我都害怕踩到前面人的登山杖。。

+

登顶了!

在一个看起来人不多的地方坐了下来,面前是齐鲁大地灯火辉煌的夜景,好令人震撼啊,打开手机指南针一看,正西。。

+

WechatIMG16

+

溜了溜了

+

果不其然,正东已经坐下了两三排人,一点多啊,我还以为我来早了。。

+

看到一个空位,两边都是小姐姐。。我滴妈呀。。问了一句她们竟然是同伴。。友善的小姐姐给我挪了个位置,小姐姐真好啊,带了薄荷口香糖提神用的,问她吃不吃,好像把我当坏人了。。防人之心不可无啊。。

+

山风一阵阵的,这届大学生果然优秀,我们喊着口号“青春没有售价,泰山就在脚下!” 啊!心情舒畅!

+ + +

扛旗的小伙子真酷啊!美丽的五星红旗在泰山之顶迎风飘荡,我们唱起了国歌!

+

租件大衣看来是正确的,山风一阵一阵的,没风的时候热,吹风的时候冷,嗨,还是穿着吧。。

+

好久没有看到过这么多的星星了啊,感觉真美好,可是星星不够亮,手机拍不出来。。

+

天蒙蒙亮了!岩石上一个小哥哥播放了下面这首歌,感谢他

+ + +

泰山之巅的启明星叫醒了不知名的鸟儿,歌声婉转,我的头顶还飞过了几只小蜜蜂,到底是谁喊了一句“md还有苍蝇”

+

远处的云竟然像一个齐平的大幕,太阳像一个烙红的热铁,又像一盏刚点亮的路灯,从云深处慢悠悠巍然而起

+

清晨的太阳变化很快,不一会儿就变得像一个顶着金色帽子的红色真知棒

+

前面的人开始下山,后面的人举着镜头向前,我开始饿了,找了个安全的地方开始补充体力,夜晚没看到的风景我要在凉爽的早晨补回来!

+

和一个刚毕业的小哥哥聊天了,我感觉他好有礼貌好帅气好紧张,我说我不年轻了,他说我心态年轻。。没毛病 95 后已经干不过 00 后了。。

+

我还是很感激他,告诉了我厕所在哪里,虽然我去了另一个厕所。。

+

在山顶休整了两个小时,山上开始变得冷清,我开始欣赏清晨的泰山景色,啊,山川大好,大好河山!

+

WechatIMG14

+

我在泰山顶的岩石上晾晒我湿了的衣服,心想咱也是在泰山顶上晾过衣服的人了哈哈哈

+

有个零零后的小男生翻过了护栏让他朋友拍照,脚的旁边就是万丈悬崖,我看得好害怕,友善提醒了一句,他没听,幸好他安全翻回来了

+

别做傻事啊朋友们,青春价虽高,生命诚可贵,也可能是我太胆小了吧,但我觉得小心驶得万年船

+

我看到有一家人也在山顶玩耍,感觉素质很高,孩子丢下的垃圾都捡走了,给他们点赞,朋友们在保证安全的情况下尽量别乱丢垃圾啊,清洁工很辛苦,泰山奶奶不容易

+

我和他们一起聊着天下山了,他们竟然也从天津来,本来说要一起去坐索道,但是我不想排队了,就下山去中天门了

+

下山路上的风景真好啊,空气看起来就特别清新的样子,呼吸让人舒畅

+

坐索道的人应该会看到不一样的风景吧

+

坐着大巴下山了,这个盘山路真刺激啊,窄窄的双行道只有两个大巴的宽度,连续不断的大巴车擦身而过,司机师傅太牛了

+

车上超级安静,司机超级淡定,我超级亢奋,这比跑跑卡丁车都刺激

+

到了山下手机信号才变好了,去的时候带点一块的纸币爬山路上用得着啊朋友们

+

拜拜泰山,拜拜沿路遇到的每一个友善的人

+
+

下次再来

+
+

手机,充电线,充电宝,身份证,家里的钥匙,纸币零钱(山路上人多信号不好买补给用)

+

usb充电式强光手电,保暖衣物,小包卫生纸,面包(山顶的早餐)

+

备一点应急药物也是 ok 的

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/09/10/eat-fish-noddle-at-morning/index.html b/2023/09/10/eat-fish-noddle-at-morning/index.html new file mode 100644 index 0000000..4924f90 --- /dev/null +++ b/2023/09/10/eat-fish-noddle-at-morning/index.html @@ -0,0 +1,118 @@ + + + + + + + + + 早起奔向面馆(转载) - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

早起奔向面馆(转载)

+
+ +
+
+

很喜欢这篇文章,所以转载到我的小站了,如有侵权请联系我
原文链接:https://www.yilinzazhi.com/2023/yl20231/2023111246.html

+
+

鱼面分离的长鱼汤面是小面馆的绝活儿,长鱼就是鳝鱼。一大碗汤面配上一小碟鳝鱼,足以作为一天的元气补给。汤面由青花瓷碗盛着,浸在奶白色泽的汤里。如果顾客无食忌,王师傅会加些葱花或韭菜提鲜。这碗汤,王师傅头天下午便开始熬。

+

这个熬可大有讲究,熬汤先熬骨。凌晨四点钟不到,已经开始忙活的王师傅加入鳝鱼片接着吊汤。直到清晨六点钟,汤熬毕,面备齐,小镇的八方食客也在来吃面的路上了。

+

“王师傅早!”“早上好!”王师傅利落地盛汤、盛面、迎客、送客。让我想起第一次看他“庖王片鳝”,原本呈二角面的鳝鱼骨头在王师傅手里瞬时变得不一样起来,似乎有了神圣的色彩。王师傅头一刀从鱼头扎下去,急速沿鱼肚破开,接着沿骨剖开,末了再来一刀,一条干净齐整的鱼骨就在这三刀间成功脱了鱼肉。后来熟悉了小面馆,熟悉了王师傅,知道他就是这样一个干净齐整的人,案板总是清清爽爽,菜码也是秩序分明。简单的汤面,鳝鱼摆盘,他也尽可能在最短的时间拾掇得适宜、美观。我夸他认真,他一边片他的鳝鱼,一边笑道:“日子不就是这样过的吗?”

+

日子一日三餐地过,举筷间我们一家人总要聊起小面馆,聊起认真过日子的王师傅。外公说:“做工作就要像老王,带劲!”他的确是带劲的,想来很大程度上缘于他有个好环境。在哪里工作,哪就是自己的领地。既然是领地,哪能潦草呢?除了“字典”里基本的整洁,王师傅还给自己的小面馆装了几盏灯。除了负责让店面更亮堂的暖黄灯管,还有星星一样的装饰灯,也是暖光的。他很得意地告诉我,这是他从儿子课本上看来的,书上说暖色调会刺激人的食欲。

+

用王师傅的话说“忙总要忙出名堂来的”。其实,他追求的也不过四个字——“健康美味”,只不过他从未搞错这两个词的顺序。王师傅不怕麻烦,我早就见识过,该先熬魚骨就先熬鱼骨,该下鱼肉了才下鱼肉,该几个小时就几个小时。直到准确的步骤和恰到好处的时间让鱼骨里的胶质毫无保留地煨在汤中,进入每个食客的胃中,暖身暖心,最终久久地写入他们的味蕾记忆。王师傅还不怕浪费,后来外公说起,我才知道他总是挑好的、贵的食材,从不吝啬。

+

一次,王师傅念小学的儿子给他打下手,小家伙一个没夹稳,食客要的荷包蛋“啪”的一声掉在了案板上,儿子拾起来就要往水池走,应该是想洗干净。王师傅停下手中的活儿,指着墙角的垃圾桶,说道:“扔掉。”得到大众认可总是有其道理的,而得到大家伙儿的肯定,除了能收获一众老客,还能收获满满的干劲。

+

在王师傅的小面馆里,的确蕴藏着极盛大的认真,大清早世界刚刚苏醒,他已带着足足的干劲盛汤、盛面、迎客、送客。热气扑向他,把他衬得像个早间厨神,好像人间千家万户的早餐,全都仰仗着他这双带劲的路膊。

+

我大喝一口乳白色的鲜鱼汤,由它把我体内的一个个器官朋友彻底激活。在早上急匆匆的城市大背景里选择稳当坐下来,认真吃一碗热腾腾、鲜入骨的长鱼汤面,也是我过日子所坚持的认真。

+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/11/19/relax/index.html b/2023/11/19/relax/index.html new file mode 100644 index 0000000..e11c1c0 --- /dev/null +++ b/2023/11/19/relax/index.html @@ -0,0 +1,131 @@ + + + + + + + + + 颓废文学 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

颓废文学

+
+ +
+
    +
  • 正义都能迟到,为什么我上班不能迟到

    +
  • +
  • 比我优秀的人都在努力,那我努力还有什么用

    +
  • +
  • 干一行,恨一行,三百六十行,行行干破防

    +
  • +
  • 安慰别人一套一套,安慰自己绳子一套

    +
  • +
  • 天生我材必有用,至今不知有何用

    +
  • +
  • 轻舟已过万重山,乌蒙山连着山外山

    +
  • +
  • 明知山有虎,不去明知山

    +
  • +
  • 任何困难都可以直接克服我

    +
  • +
  • 希望大家都能走出舒适圈,然后让我进去

    +
  • +
  • 生活不是无路可走,还有死路一条

    +
  • +
  • +
  • +
+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/12/03/structuredExpression/index.html b/2023/12/03/structuredExpression/index.html new file mode 100644 index 0000000..aefbca9 --- /dev/null +++ b/2023/12/03/structuredExpression/index.html @@ -0,0 +1,153 @@ + + + + + + + + + 公司内部培训笔记 - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

公司内部培训笔记

+
+ +
+

21世纪的 5 大生产要素:[数据]、土地、劳力、技术、资金

+

数据治理/运营是一种硬技能

+

做解决方案的思路

    +
  1. 让用户感受到我们了解他们行业,并且很专业(用户不愿意听一个外行的聒噪)

    +
  2. +
  3. 描述清楚客户的核心问题

    +
  4. +
  5. 针对性地提出方案

    +
  6. +
  7. 讲出用户和我们合作的理由(我们是很专业的)

    +
  8. +
  9. 口说无凭,给出我们做过的成功案例

    +
  10. +
+

用结构化的方式进行思考、表达

Tips:思考的过程中应拿笔将思考出的结构用笔写下来,进而进一步分析

+

读观点传达类的文章可以对文章进行解构分析,然后建构,以清楚全面了解文章观点

+

学习别人的PPT可以先解构,再建构,为我所用

+

解构4步法:PUTS

+
    +
  • P:means pick,即提取要点
  • +
  • U:means unit,即分组整理
  • +
  • T:means track,即查找关联,画出结构树状图
  • +
  • S:means summary,即总结概括
  • +
+

建构4原则:PGOS 树状图

+
    +
  • P:结论前置
  • +
  • G:共性分组
  • +
  • O:先后排序
  • +
  • S:上下对应
  • +
+

典型场景的结论撰写公式

    +
  • 计划型:准备做…. + 预期目标(结果)
  • +
  • 解释型:因为…… + 准备做…
  • +
  • 状态型:已进行到.. + 当前状态/阶段成果
  • +
  • 总结型:….已完成 + 结果/影响是…
  • +
  • 建议型:应该做…. + 以达到..目的/效果
  • +
  • 表态型:我认为…. + 因为…的原因
  • +
+

营销的一种结构

    +
  • 你的目的是:递观点
      +
    • 讲故事
    • +
    • 述情怀
    • +
    +
  • +
+ +
+ +
+ + +
+ + +
+ + diff --git a/2023/12/10/JavarGrammar/index.html b/2023/12/10/JavarGrammar/index.html new file mode 100644 index 0000000..10cc951 --- /dev/null +++ b/2023/12/10/JavarGrammar/index.html @@ -0,0 +1,625 @@ + + + + + + + + + Java Grammar - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+

Java Grammar

+
+ +
+

初学编程的常见误区

+

image-20230330001856416

+

Module 1: Java Fundamentals

Variables: store data

+

Conditionals: control how your code runs

+

Arrays: store and work with many values

+

Loops: control how many times a piece of code needs to run

+

Functions: perform tasks

+

Module 2: Object Oriented Programming

objects、immutable objects、list collections、map collections、exception handling、

+

package and import、static and final、enums、unit test、inheritance and polymorphism、

+

higher order functions、big decimal、interface、concurrency and multithreading

+

Reasons to learn Java

Java is general-purpose, which means that Java powers a wide range of applications.
As a Java developer,

+
    +
  • you can build web applications using Spring boot,
  • +
  • you can build applications on Android,
  • +
  • you can automate tasks using Selenium,
  • +
  • you can develop cloud native applications,
  • +
  • you can integrate microservices,
  • +
  • you can …
  • +
+

Java can run on any machine, it’s well known for its “write once, run anywhere”

+
    +
  • This is because the Java Virtual Machine, the JVM, which is responsible for executing compiled Java code, can be installed on any platform
  • +
+

Java is the No.1 language for developing enterprise applications

+

To run Java code, you need

    +
  1. A Java Compiler - to compile your code.

    +
  2. +
  3. A Java Runtime - to run the compiled code.

    +

    So, this is why JDK provides a Compiler、a Runtime、and a lot of other things.

    +

    +
  4. +
+

Roadmap

    +
  1. Install a JDK(Java Development Kit) on your machine => from Amazon Corretto is recomended.

    +

    Amazon Corretto is just a distribution which once installed, does the work of setting up a JDK on your machine.
    Basically all you need to do is install it and it’s going to do the heavy lifting.

    +
    1
    2
    javac -version  # check compiler
    java -version # check runtime
    + +

    Finished ! you’ve just installed a JDK, now your computer can compile and run Java code.

    +
  2. +
  3. Download a text editor to write code

    +

    I use vim & vscode(the extension pack for java is must).

    +

    Now you have everything you need to start building Java applications!

    +
  4. +
  5. Write & Run your first Java code

    +
    1
    2
    # Every java file needs to follow the naming convention -> CamelCase
    touch HelloJava.java
    +
    1
    2
    3
    4
    5
    // In java, you must write all of your code in a class.
    // And the ClassName needs to be the same as your FileName.
    // So here we create a class.
    class HelloJava {
    }
    +

    All right, so what’s next is the main() method, which is the entry point of a Java application.

    +

    And inside main, we’re going to print the message “Hello Java”

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class HelloJava {
    // not understand this line is doesn't matter now.
    public static void main(String[] args) {
    System.out.println("Hello Java");
    }
    }

    /* Notice:
    the semicolon is really important, which means end of statement.
    every statement in Java, every line of code, needs a semicolon at the end.
    so if you forget your semicolon, your code is not gonna run.
    */
    +

    Now we’re ready to compile and run our Java code.

    +
    1
    2
    3
    4
    5
    # The javac command compiles your javaCode into byteCode
    javac <FileName>.java

    # The java command executes the compiled code
    java <FileName>
    +

    For example

    +

    image-20230331230902548

    +
  6. +
+

See you in workbook 1.1

+

Variable

+

Store data inside variable.

+
+

Java is strongly typed

which means that variables can only store values of their type.

+

Java is case sensitive

eg: people is not the same as People

+

The convention to naming a variable

lowerCamelCase

+

eg: int peopleOnBus = 20;

+

Update the value inside a variable

Just set it equal to a new value, or use +=-=、…

+

See you in workbook 2.1

+

Use variables to store numeric data

Types: int and long

We can use int and long variables to store whole numbers.

+

You should know the difference between int and long and when to use int vs long.

+
1
2
3
4
5
int numberOfFans = 5000;

// 如下两行等价,但显然第二行的可读性更好
long population = 7000000000L;
long population = 7_000_000_000L;
+ +

为什么要在 7000000000 这个数后面加个 L ?

+

如果你不加 L,那么 Java 就只会看到这是一个很大的数,它并不知道你这个傻乎乎的开发者要将这个数存到什么地方,所以 Java 就慌了

+

因此,你只需在这个数后面加个 L 来告诉 Java:“放松啦~ 咱们要存的地方存得下这个数的。”,然后 Java 就平静了

+

Type: double

We can use double variables to store decimal numbers, which are given so much size in memory that a double value can reach 15 significant digits.

+
1
double percentage = 55.7;
+ +

Be careful !!!

Avoid just using integers for math calculations,

+

because if you multiply or divide two integers, the result will always be an integer,

+

because Java’s going to cut off all the decimals.

+
1
2
integer * integer => integer
integer / integer => integer
+ +

eg

+
1
2
3
4
5
6
7
8
9
int people = 3;
int wallet = 20;
System.out.println(wallet / people); // 6, which is not the result we want.

// So we need to make sure that at least one of these values is stored as a decimal,
// then Java's going to know to return a decimal result.
int people = 3;
double wallet = 20;
System.out.println(wallet / people); // 6.666666666666667, this is the result we want.
+ +

Golden Rule

If precision is important, use double for math calculations.

+

Type: String

We can use the type String to store text.

+
1
String sentence = "Hello world !";
+ +

String unlike int in memory,

+

no matter what you store in the integer variable, it’s always 4 bytes,

+

but with String, empty text alone takes up 24 bytes, and the more text that you add to a string, the more memory it takes up.

+
+

You can use the + operator to join two String values.

+
1
2
3
String sentence = "His name is: ";
String placeholder = "Harry";
System.out.println(sentence + placeholder);
+ +

You can use the + operator to blend values into a string.

+
1
2
3
double points = 50;
String announcement = " points for Gryffindor";
System.out.println(points + announcement); // 50.0 points for Gryffindor
+ + +

Type: char

We can use the char type to store single characters.

+
1
char gender = 'F';
+ +

We can join a String value with a char value using the + operator.

+
1
System.out.println("Gender: " + 'F');
+ +
+
1
String gender = "F";
+ +

It seems that String is more flexible than char,

+

so why not always use String ?

+

The answer is【memory】and【performance】!

+

char consumes less memory, and char is faster than String !

+

Summarize

There are 6 core data types (we didn’t cover boolean yet).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Data TypeValueAmount of Memory (Bytes)Valid Range of Values
intWhole numbers4From: -2147483648 To: 2147483647
longVery large whole numbers8From: -9223372036854775808 To: 9223372036854775807
doubleDecimals8Decimal can reach 15 significant digits
StringTextVaries, 24 bytes for empty text.-
charA single character2-
+

平时开发我基本不使用 byte, short, float

+

See you in workbook 2.2

+

补充知识

在以二进制存储数据的计算机中,浮点数存在误差 !=> https://liupj.top/2021/08/31/01/

+

Math operators

So far you’ve learned about: intlongdoubleString and char.

+

Now, you can use math operators shown as below to play with these values.

+

+, -, *, /, %, ++, --, +=, -=, ...

+

Pattern

An operation between whole numbers returns a whole number.

+

An operation between decimals will always perserve the decimal.

+

Think about that why do we care about the remainder ?

It’s very useful if you want to identify odd or even numbers.

+
1
int remainder = 10 % 2; // 0
+ +

See you in workbook 2.3

+

Type casting

In Java, we can cast variables from one type to another.

+
1
2
3
4
// Cast double to int
// Just telling Java the type that we're casting to.
double decimal = 4.3;
int integer = (int)decimal;
+ +

See you in workbook 2.4

+

Scanner

Scanner contains many methods that we can use to scan for user input.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
methodscan forexplaination
nextInt()integersskips the whiteSpace and picks up the next Integer
nextLong()integersskips the whiteSpace and picks up the next Long
nextDouble()decimalsskips the whiteSpace and picks up the next Double
next()textskips the whiteSpace and picks up the next String
nextLine()textpicks up a line of data
+
+

The default delimiter is white space.

+
+

Usage

1、Create an instance of Scanner which can receive input from the System.in.

+
1
2
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
+ +

2、Use Scanner’s methods to pick up (integers、decimals、text、…) from user input.

+
1
2
3
4
int coffeeAmount    = sc.nextInt();
double coffeePrice = sc.nextDouble();
String name = sc.nextLine();
...
+ +

3、Once you are done with Scanner, always close it, otherwise you’re going to get a resource leak.

+
1
sc.close();
+ +

Debugging

Fixing bugs in your code is called debugging, which is a must have skill for any programmer.

+

Debugging involves tracing the runTime step by step.

+

Please do not clutter your code with print statements to understand what’s going on,

+

use breakpoints instead !

+

the trap of nextLine()

recap

+ + + + + + + + + + + + + + + + + +
methodscans forexplaination
next()textskips the whiteSpace and picks up the next String
nextLine()textpicks up a line of data
+

表面现象

nextLine() gets skipped when placed after nextInt()nextLong()nextDouble() and next()

+

看清本质

这不就是我在大一学 C 语言的时候,那个曾经让我头疼万分的所谓“没有吃回车”的问题嘛

+

当时我还浅浅了解了一下什么是 Shell,什么是 Shell 的缓冲区

+

解决方案

显而易见,用 nextLine() “吃一下残留在 Shell 的缓冲区中的回车”呗~

+

即:place a throwaway nextLine before the ‘real’ nextLine

+

请阅读

+

See you in workbook 2.5

+

Booleans and Conditionals

In this section, you will gain full control over how your code runs.

+

Roadmap

    +
  1. Use conditions to control which parts of your code run.

    +
  2. +
  3. Execute code by comaring a [value] against a list of [cases].

    +
  4. +
+

boolean

1
2
boolean bool1 = true;
boolean bool2 = false;
+ +

Summarize

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Data TypeValueAmount of Memory (Bytes)Valid Range of Values
intWhole numbers4From: -2147483648 To: 2147483647
longVery large whole numbers8From: -9223372036854775808 To: 9223372036854775807
doubleDecimals8a decimal can reach 15 significant digits
StringTextVaries, 24 bytes for empty text.-
charA single character2-
boolean1true or false
+

Comparison Operators

>, Greater than, returns true if the value on the left is greater than the value on the right.

+

<, Less than, returns true if the value on the left is less than the value on the right.

+

>=, Greater than or equal to, returns true if the value on the left is greater than or equal to the value on the right.

+

<=, Less than or equal to, returns true if the value on the left is less than or equal to the value on the right.

+

==, returns true if two values are equal.

+

!=, returns true if two values are not equal.

+

Comparing Strings

Do not use == or != to compare strings.

+

Instead, you can compare one string to another by calling equals() from one of them.

+
1
2
3
4
5
String str1 = "hello";
String str2 = "hello";

str1.equals(str2); // true
!str1.equals(str2); // false
+ +

You should know about how memory is being allocated. but 目前老师并没有讲

+

See you in workbook 3.1

+

if - else

Goal: Use if - else to run specific code blocks based on various conditions.

+
1
2
3
4
5
if (condition) {
// Code runs if the condition is true
} else {
// Code runs if the condition is false
}
+ +

The condition is usually the result of a comparison that returns true or false.

+

See you in workbook 3.2

+
+

Not only can we test only one condition, but also many conditions by embedding a series of else if (condition) statements.

+
1
2
3
4
5
6
7
8
9
if (condition) {
// Code
} else if (condition) {
// Code
} else if (condition) {
// Code
} else {
// Code
}
+ +

See you in workbook 3.3 and 3.4

+

Logical Operators

We can use logical operators to make our conditionals a little more complex.

+

There are 3 types of logical operators,

+
+

&& returns true only if both comparisons are true.

+

( comparison1 && comparison2 )

+
+

|| returns true if either one of the comparison is true.

+

( comparison1 || comparison2 )

+
+

! reverses the value of a boolean expression.

+
+

See you in workbook 3.5

+

Switch Statements

whenever you’re comparing one variable against a long list of values, such as

+
1
2
3
4
5
6
7
8
9
if (weather.equals("sunny")) {
// code
} else if (weather.equals("cloudy")) {
// code
} else if (weather.equals("rainy")) {
// code
} else {
// code
}
+ +

you should avoid having a long list of else if statements, because this looks so disgusting !

+

Instead, you should favor using a switch statement which was designed to compare one variable against a list of cases.

+
1
2
3
4
5
6
switch (weather) {
case "sunny": // code break;
case "cloudy": // code break;
case "rainy": // code break;
default: // code
}
+ +

Then you might be asking that when to use if vs switch ?

+

The only thing you can really do with switch is compare one variable against a list of values.

+

if statement is more flexible so that suitable for complex conditions, such as when you need to compare multiple variables, they give you the flexibility to evaluate compound conditions using logical operators.

+
1
2
3
4
5
if (temperature >= 80 && humidity >= 60) {
System.out.println("It's too hot and humid\n");
} else {
System.out.println("It's comfortable\n");
}
+ +

See you in workbook 3.6 and 3.7

+

As you write more and more code inside main(), you’ll notice that it becomes increasingly cluttered and messy.

+

And the more code you write, the more unreadable that it becomes.

+

Functions

A function is a grouping of code, it performs a task, and obviously it’s reusable.

+

Some functions rely on parameters to perform their task.

+

Some functions will return a final value.

+

image-20230423202020449

+

Instead of writing all of your code inside of a single code block,

+

you can split it up into functions and call them as needed.

+

Let’s begin organizing your code using functions!

+

Define functions and call them

See video on udemy.

+

Notice

Functions’ name needs to represent the task it’s performing.

+

Notice

public means the function can be publicly accessed from any package or subfolder,

+

but because we’ve got only one package with a single class in it,

+

it doesn’t really matter what level of access you specify.

+

Notice

You can notice that main() is also a function, it has a very similar signature to our functions.

+

Every function has a specific task that it performs, the main() function performs the task of running our application.

+

The main() function has a very specific signature that the JVM looks for when you run your app, when it finds main() function, it executes it.

+

Parameters

Functions with parameters expect to receive values.(these functions rely on parameters to perform their task)

+

Functions【without】parameters【do not expect】to receive values.

+

Parameters are essentially just variables.

+

Arguments

A value that you pass into a function is known as an argument.

+

Parameters and Arguments makes functions completely reusable!

+

Notice

When a function defines parameters, then in order to call it,

+

you need to pass in a matching number of arguments based on the position of these parameters.

+

Return Values

+

You can return values from a function.

+
+

Notice

Bad practice: Your function handles the final result.

+

Good practice: Your function return the final result.

+

Notice

Whenever you specify a return type,

+

you need to make sure that something gets returned no matter what gets passed in.

+

Terminate the runTime

1
System.exit(0);
+ +

See you in workbook 4.3

+

Doc Comments

+

Can be used to describe what a function does.

+
+

If you’re working in a team of developers, you should have a document for every function.

+

How to write Doc Comments ?

See udemy

+

See you in workbook 4.4

+

Scope

+

The scope of a variable determines its life span.

+
+

The take home message is:
You can never access a variable outside the scope that it was defined in.

+

Global Scope

Please against using global variables,

+

instead, you should keep everything local and use parameters,

+

because when you have too many global variables, you start losing track of what’s really going on(such as from your debugger in vscode).

+
+

Please watch the video on udemy.

+
+

Built-in Functions

The JDK provides so many built-in functions that you can call out of the box.

+

But to be honest, a good developer never memorizes code!

+

Instead, a good developer uses the internet!
to read documentation.
to find resources.

+

See you in workbook 4.5

+

Loops

For Loops: designed to run code a specific number of times.

+

While Loops: designed to run code an unknown number of times.

+

You will use the break and continue keywords to gain full control over your loops.

+

For Loops

1
2
for (int i = 0; i < 3; i ++) {
}
+ +

While Loops

What is a while loop ?

+

A while loop keeps running while a condition is true.

+
1
2
while (condition) {
}
+ +

See you in workboook 5.8 ~ 5.10

+

continue

The continue keyword skips a run in the loop and continues with the next one.

+

break

The break keyword when invoked, breaks the loop entirely.

+

Nested Loops

A nested loop is a loop inside of another loop.

+

eg: useful when working with 2D arrays.

+
1
2
3
4
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
}
}
+ + +

Arrays、2D_Arrays

+

Looping Arrays、Updating Arrays

+

Arrays

Sometimes values can be closely related and creating one variable after another can be very messy such as below.

+
1
2
3
4
5
double price1 = 5.99;
double price2 = 6.99;
double price3 = 7.99;
double price4 = 8.99;
double price5 = 9.99;
+ +

So what we can do is to store all of these values at the same time in an organized way which is called an array.

+
1
double[] prices = { 5.99, 6.99, 7.99, 8.99, 9.99 };
+ +

Although an array can hold many values, all of them have to share the same type.

+

For example as below, integers points to an array of integer values.

+
1
int[] integers = { 1, 2, 3 };
+ +

Talk is cheap

1
String[] kindoms = { "qwe", "asd", "zxc" };
+ +

The truth is:

+

the variable kingdoms doesn’t store the array directly

+

instead

+

it stores a [reference] that points to it

+

202307291020173

+
1
2
3
// You can try to compile and run this line of code,
// you will get a hashcode representation of the reference.
System.out.println(kingdoms);
+ +

and each element is stored at an index

+

20230729103340

+

what will happen if I try to access an element outside the range of the array ?

+
1
System.out.println(kingdoms[3]);
+ +

20230729105228

+

20230729110015

+

Java throws an ArrayIndexOutOfBoundsException, in essence, crashing our application, telling us that we have an error in our code —— “Index 3 is out of bounds”

+

Preparing to loop arrays

The length of an array indicates the number of items it contains.

+
1
2
String[] items = { "apple", "banana", "cherry" };
System.out.println(items.length); // 3
+ +

So we can use the length property to loop arrays.

+

Looping arrays

+

Arrays and loops are like siblings.

+
+
1
2
3
4
5
6
7
8
9
10
11
12
String[] numbers = { 1, 2, 3, 4, 5, 6 };

// If you want to access each element in the array
// Would you perfer to index them all individually ?
numbers[0]
numbers[1]
numbers[2]
numbers[3]
numbers[4]
numbers[5]
// or use some kind of loop that iterates through every single element in the array ?
// I think the looping approach would be more efficient.
+ +
1
2
// Print the elements of an integer array using a loop
int[] numbers = {22, 24, 26, 29, 30};
+ +

for 循环

1
2
3
4
// autoComplete a for loop in vscode: fori<ENTER>
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
+ +

foreach 循环

foreach simplifies looping through an array without the need for a counter or a counter increment or anything.

+
1
2
3
4
// autoComplete a foreach loop in vscode: fore<ENTER>
for (int number : numbers) {
System.out.println(number);
}
+ +

It just automatically iterates through every single number inside of the numbers array.

+

So as you can see, foreach is much cleaner and concise than the traditional for loop,

+

but the traditional for loop is more flexible because the counter i give us more control over the looping process.

+

I’m a bit tired of using loops to print an array,

+

Java has a function called toString, it takes your array as an argument, and it returns a string that we can print.

+

toString

+

Updating Arrays

+

It’s time to learn how to update arrays.

+
+
1
2
String[] flavours = { "Sweet", "Sour", "Bitter" };
flavours[2] = "Salty";
+ +

Is it possible to change the array length ?

NO.

+

Once you create an array, you cannot resize it.

+
1
2
String[] menu = { "Espresso", "Iced Coffee", "Latte" };
String[] newMenu = new String[5];
+ +

newMenu

+
1
2
3
for (int i = 0; i < menu.length; i++) {
newMenu[i] = menu[i];
}
+ + +

The reference trap

+

I told you earlier that a variable cannot store an array, it stores a reference that points to it.

+

Because of this, another variable can actually store a reference that points to the same array.

+
+
1
2
int[] numbers = { 1, 2, 3 };
int[] numbers2 = numbers;
+ +

Do not set array variables equal to each other!

+

Instead, create a new array, then, copy every value using a for loop.

+

A better solution

Arrays.copyOf(a, b);

+

a means that the array you want to copy.

+

b means that how much of it you want to copy.

+

2D Arrays

1
2
3
4
5
int[][] grades = {
{72, 74, 78, 76},
{65, 64, 61, 67},
{95, 98, 99, 96}
};
+ +

When to work with 2D arrays ?

+

2D arrays is perfect for data in the form of a table.

+
+
1
2
int[][] integers = new int[3][4]; // 3 行 4 列
System.out.println(Arrays.toString(grades[0])); // [0, 0, 0, 0]
+ +

arrays and loops are like siblings

    +
  • nested loops

    +
      +
    • outer loop runs through every row (i)
    • +
    • inner loop runs through every item in that row
    • +
    +
    1
    2
    3
    4
    5
    for (int i = 0; i < grades.length; i++) {
    for (j = 0; j < grades[i].length; j++) {
    // ...
    }
    }
  • +
+ +
+ +
+ + +
+ + +
+ + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..ee4034e --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +liupj.top \ No newline at end of file diff --git a/archives/2017/12/index.html b/archives/2017/12/index.html new file mode 100644 index 0000000..ccf4861 --- /dev/null +++ b/archives/2017/12/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2017/index.html b/archives/2017/index.html new file mode 100644 index 0000000..ccf4861 --- /dev/null +++ b/archives/2017/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2018/07/index.html b/archives/2018/07/index.html new file mode 100644 index 0000000..46d0d59 --- /dev/null +++ b/archives/2018/07/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2018/11/index.html b/archives/2018/11/index.html new file mode 100644 index 0000000..07f13e8 --- /dev/null +++ b/archives/2018/11/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2018/index.html b/archives/2018/index.html new file mode 100644 index 0000000..c69ce2e --- /dev/null +++ b/archives/2018/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2019/01/index.html b/archives/2019/01/index.html new file mode 100644 index 0000000..d0b8caa --- /dev/null +++ b/archives/2019/01/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2019/index.html b/archives/2019/index.html new file mode 100644 index 0000000..d0b8caa --- /dev/null +++ b/archives/2019/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html new file mode 100644 index 0000000..f649c3f --- /dev/null +++ b/archives/2020/07/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html new file mode 100644 index 0000000..7f2def4 --- /dev/null +++ b/archives/2020/09/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2020/index.html b/archives/2020/index.html new file mode 100644 index 0000000..d90bda1 --- /dev/null +++ b/archives/2020/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2021/08/index.html b/archives/2021/08/index.html new file mode 100644 index 0000000..e630105 --- /dev/null +++ b/archives/2021/08/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2021/09/index.html b/archives/2021/09/index.html new file mode 100644 index 0000000..4bdfad9 --- /dev/null +++ b/archives/2021/09/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2021/10/index.html b/archives/2021/10/index.html new file mode 100644 index 0000000..62f4ef5 --- /dev/null +++ b/archives/2021/10/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2021/11/index.html b/archives/2021/11/index.html new file mode 100644 index 0000000..325ec6f --- /dev/null +++ b/archives/2021/11/index.html @@ -0,0 +1,100 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2021/index.html b/archives/2021/index.html new file mode 100644 index 0000000..ba0a723 --- /dev/null +++ b/archives/2021/index.html @@ -0,0 +1,125 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/02/index.html b/archives/2022/02/index.html new file mode 100644 index 0000000..2885151 --- /dev/null +++ b/archives/2022/02/index.html @@ -0,0 +1,100 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/03/index.html b/archives/2022/03/index.html new file mode 100644 index 0000000..1868386 --- /dev/null +++ b/archives/2022/03/index.html @@ -0,0 +1,115 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/04/index.html b/archives/2022/04/index.html new file mode 100644 index 0000000..f06a082 --- /dev/null +++ b/archives/2022/04/index.html @@ -0,0 +1,105 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/05/index.html b/archives/2022/05/index.html new file mode 100644 index 0000000..e8ae256 --- /dev/null +++ b/archives/2022/05/index.html @@ -0,0 +1,110 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/06/index.html b/archives/2022/06/index.html new file mode 100644 index 0000000..80b2fb2 --- /dev/null +++ b/archives/2022/06/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/07/index.html b/archives/2022/07/index.html new file mode 100644 index 0000000..28248d6 --- /dev/null +++ b/archives/2022/07/index.html @@ -0,0 +1,110 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/08/index.html b/archives/2022/08/index.html new file mode 100644 index 0000000..d33aac1 --- /dev/null +++ b/archives/2022/08/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/10/index.html b/archives/2022/10/index.html new file mode 100644 index 0000000..f1f8ddc --- /dev/null +++ b/archives/2022/10/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/12/index.html b/archives/2022/12/index.html new file mode 100644 index 0000000..c7dd00a --- /dev/null +++ b/archives/2022/12/index.html @@ -0,0 +1,100 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2022/index.html b/archives/2022/index.html new file mode 100644 index 0000000..76a7ee4 --- /dev/null +++ b/archives/2022/index.html @@ -0,0 +1,169 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/archives/2022/page/2/index.html b/archives/2022/page/2/index.html new file mode 100644 index 0000000..bd53d1f --- /dev/null +++ b/archives/2022/page/2/index.html @@ -0,0 +1,164 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/archives/2023/01/index.html b/archives/2023/01/index.html new file mode 100644 index 0000000..f4cd878 --- /dev/null +++ b/archives/2023/01/index.html @@ -0,0 +1,100 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/03/index.html b/archives/2023/03/index.html new file mode 100644 index 0000000..84517fa --- /dev/null +++ b/archives/2023/03/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/04/index.html b/archives/2023/04/index.html new file mode 100644 index 0000000..780446b --- /dev/null +++ b/archives/2023/04/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/06/index.html b/archives/2023/06/index.html new file mode 100644 index 0000000..a6fb24a --- /dev/null +++ b/archives/2023/06/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/09/index.html b/archives/2023/09/index.html new file mode 100644 index 0000000..0f0052f --- /dev/null +++ b/archives/2023/09/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html new file mode 100644 index 0000000..6c729a1 --- /dev/null +++ b/archives/2023/11/index.html @@ -0,0 +1,90 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html new file mode 100644 index 0000000..727bf31 --- /dev/null +++ b/archives/2023/12/index.html @@ -0,0 +1,95 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 0000000..62be1f3 --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,140 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + +
+ + diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000..8a8ebe2 --- /dev/null +++ b/archives/index.html @@ -0,0 +1,169 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 0000000..9ec8d6c --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,169 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 0000000..ba4c5dc --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,169 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 0000000..bf13b26 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,129 @@ + + + + + + + + + Archives - peijie's wiki + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

+ +
+ + + + + + +
+ + diff --git a/atom.xml b/atom.xml new file mode 100644 index 0000000..3b985a7 --- /dev/null +++ b/atom.xml @@ -0,0 +1,471 @@ + + + peijie's wiki + + + + + + 2023-12-22T03:02:26.239Z + https://liupj.top/ + + + lpj + + + + Hexo + + + Java Grammar + + https://liupj.top/2023/12/10/JavarGrammar/ + 2023-12-10T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 初学编程的常见误区

image-20230330001856416

Module 1: Java Fundamentals

Variables: store data

Conditionals: control how your code runs

Arrays: store and work with many values

Loops: control how many times a piece of code needs to run

Functions: perform tasks

Module 2: Object Oriented Programming

objects、immutable objects、list collections、map collections、exception handling、

package and import、static and final、enums、unit test、inheritance and polymorphism、

higher order functions、big decimal、interface、concurrency and multithreading

Reasons to learn Java

Java is general-purpose, which means that Java powers a wide range of applications.
As a Java developer,

  • you can build web applications using Spring boot,
  • you can build applications on Android,
  • you can automate tasks using Selenium,
  • you can develop cloud native applications,
  • you can integrate microservices,
  • you can …

Java can run on any machine, it’s well known for its “write once, run anywhere”

  • This is because the Java Virtual Machine, the JVM, which is responsible for executing compiled Java code, can be installed on any platform

Java is the No.1 language for developing enterprise applications

To run Java code, you need

  1. A Java Compiler - to compile your code.

  2. A Java Runtime - to run the compiled code.

    So, this is why JDK provides a Compiler、a Runtime、and a lot of other things.

Roadmap

  1. Install a JDK(Java Development Kit) on your machine => from Amazon Corretto is recomended.

    Amazon Corretto is just a distribution which once installed, does the work of setting up a JDK on your machine.
    Basically all you need to do is install it and it’s going to do the heavy lifting.

    1
    2
    javac -version  # check compiler
    java -version # check runtime

    Finished ! you’ve just installed a JDK, now your computer can compile and run Java code.

  2. Download a text editor to write code

    I use vim & vscode(the extension pack for java is must).

    Now you have everything you need to start building Java applications!

  3. Write & Run your first Java code

    1
    2
    # Every java file needs to follow the naming convention -> CamelCase
    touch HelloJava.java
    1
    2
    3
    4
    5
    // In java, you must write all of your code in a class.
    // And the ClassName needs to be the same as your FileName.
    // So here we create a class.
    class HelloJava {
    }

    All right, so what’s next is the main() method, which is the entry point of a Java application.

    And inside main, we’re going to print the message “Hello Java”

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class HelloJava {
    // not understand this line is doesn't matter now.
    public static void main(String[] args) {
    System.out.println("Hello Java");
    }
    }

    /* Notice:
    the semicolon is really important, which means end of statement.
    every statement in Java, every line of code, needs a semicolon at the end.
    so if you forget your semicolon, your code is not gonna run.
    */

    Now we’re ready to compile and run our Java code.

    1
    2
    3
    4
    5
    # The javac command compiles your javaCode into byteCode
    javac <FileName>.java

    # The java command executes the compiled code
    java <FileName>

    For example

    image-20230331230902548

See you in workbook 1.1

Variable

Store data inside variable.

Java is strongly typed

which means that variables can only store values of their type.

Java is case sensitive

eg: people is not the same as People

The convention to naming a variable

lowerCamelCase

eg: int peopleOnBus = 20;

Update the value inside a variable

Just set it equal to a new value, or use +=-=、…

See you in workbook 2.1

Use variables to store numeric data

Types: int and long

We can use int and long variables to store whole numbers.

You should know the difference between int and long and when to use int vs long.

1
2
3
4
5
int numberOfFans = 5000;

// 如下两行等价,但显然第二行的可读性更好
long population = 7000000000L;
long population = 7_000_000_000L;

为什么要在 7000000000 这个数后面加个 L ?

如果你不加 L,那么 Java 就只会看到这是一个很大的数,它并不知道你这个傻乎乎的开发者要将这个数存到什么地方,所以 Java 就慌了

因此,你只需在这个数后面加个 L 来告诉 Java:“放松啦~ 咱们要存的地方存得下这个数的。”,然后 Java 就平静了

Type: double

We can use double variables to store decimal numbers, which are given so much size in memory that a double value can reach 15 significant digits.

1
double percentage = 55.7;

Be careful !!!

Avoid just using integers for math calculations,

because if you multiply or divide two integers, the result will always be an integer,

because Java’s going to cut off all the decimals.

1
2
integer * integer => integer
integer / integer => integer

eg

1
2
3
4
5
6
7
8
9
int people = 3;
int wallet = 20;
System.out.println(wallet / people); // 6, which is not the result we want.

// So we need to make sure that at least one of these values is stored as a decimal,
// then Java's going to know to return a decimal result.
int people = 3;
double wallet = 20;
System.out.println(wallet / people); // 6.666666666666667, this is the result we want.

Golden Rule

If precision is important, use double for math calculations.

Type: String

We can use the type String to store text.

1
String sentence = "Hello world !";

String unlike int in memory,

no matter what you store in the integer variable, it’s always 4 bytes,

but with String, empty text alone takes up 24 bytes, and the more text that you add to a string, the more memory it takes up.


You can use the + operator to join two String values.

1
2
3
String sentence = "His name is: ";
String placeholder = "Harry";
System.out.println(sentence + placeholder);

You can use the + operator to blend values into a string.

1
2
3
double points = 50;
String announcement = " points for Gryffindor";
System.out.println(points + announcement); // 50.0 points for Gryffindor

Type: char

We can use the char type to store single characters.

1
char gender = 'F';

We can join a String value with a char value using the + operator.

1
System.out.println("Gender: " + 'F');

1
String gender = "F";

It seems that String is more flexible than char,

so why not always use String ?

The answer is【memory】and【performance】!

char consumes less memory, and char is faster than String !

Summarize

There are 6 core data types (we didn’t cover boolean yet).

Data TypeValueAmount of Memory (Bytes)Valid Range of Values
intWhole numbers4From: -2147483648 To: 2147483647
longVery large whole numbers8From: -9223372036854775808 To: 9223372036854775807
doubleDecimals8Decimal can reach 15 significant digits
StringTextVaries, 24 bytes for empty text.-
charA single character2-

平时开发我基本不使用 byte, short, float

See you in workbook 2.2

补充知识

在以二进制存储数据的计算机中,浮点数存在误差 !=> https://liupj.top/2021/08/31/01/

Math operators

So far you’ve learned about: intlongdoubleString and char.

Now, you can use math operators shown as below to play with these values.

+, -, *, /, %, ++, --, +=, -=, ...

Pattern

An operation between whole numbers returns a whole number.

An operation between decimals will always perserve the decimal.

Think about that why do we care about the remainder ?

It’s very useful if you want to identify odd or even numbers.

1
int remainder = 10 % 2; // 0

See you in workbook 2.3

Type casting

In Java, we can cast variables from one type to another.

1
2
3
4
// Cast double to int
// Just telling Java the type that we're casting to.
double decimal = 4.3;
int integer = (int)decimal;

See you in workbook 2.4

Scanner

Scanner contains many methods that we can use to scan for user input.

methodscan forexplaination
nextInt()integersskips the whiteSpace and picks up the next Integer
nextLong()integersskips the whiteSpace and picks up the next Long
nextDouble()decimalsskips the whiteSpace and picks up the next Double
next()textskips the whiteSpace and picks up the next String
nextLine()textpicks up a line of data

The default delimiter is white space.

Usage

1、Create an instance of Scanner which can receive input from the System.in.

1
2
import java.util.Scanner;
Scanner sc = new Scanner(System.in);

2、Use Scanner’s methods to pick up (integers、decimals、text、…) from user input.

1
2
3
4
int coffeeAmount    = sc.nextInt();
double coffeePrice = sc.nextDouble();
String name = sc.nextLine();
...

3、Once you are done with Scanner, always close it, otherwise you’re going to get a resource leak.

1
sc.close();

Debugging

Fixing bugs in your code is called debugging, which is a must have skill for any programmer.

Debugging involves tracing the runTime step by step.

Please do not clutter your code with print statements to understand what’s going on,

use breakpoints instead !

the trap of nextLine()

recap

methodscans forexplaination
next()textskips the whiteSpace and picks up the next String
nextLine()textpicks up a line of data

表面现象

nextLine() gets skipped when placed after nextInt()nextLong()nextDouble() and next()

看清本质

这不就是我在大一学 C 语言的时候,那个曾经让我头疼万分的所谓“没有吃回车”的问题嘛

当时我还浅浅了解了一下什么是 Shell,什么是 Shell 的缓冲区

解决方案

显而易见,用 nextLine() “吃一下残留在 Shell 的缓冲区中的回车”呗~

即:place a throwaway nextLine before the ‘real’ nextLine

请阅读

See you in workbook 2.5

Booleans and Conditionals

In this section, you will gain full control over how your code runs.

Roadmap

  1. Use conditions to control which parts of your code run.

  2. Execute code by comaring a [value] against a list of [cases].

boolean

1
2
boolean bool1 = true;
boolean bool2 = false;

Summarize

Data TypeValueAmount of Memory (Bytes)Valid Range of Values
intWhole numbers4From: -2147483648 To: 2147483647
longVery large whole numbers8From: -9223372036854775808 To: 9223372036854775807
doubleDecimals8a decimal can reach 15 significant digits
StringTextVaries, 24 bytes for empty text.-
charA single character2-
boolean1true or false

Comparison Operators

>, Greater than, returns true if the value on the left is greater than the value on the right.

<, Less than, returns true if the value on the left is less than the value on the right.

>=, Greater than or equal to, returns true if the value on the left is greater than or equal to the value on the right.

<=, Less than or equal to, returns true if the value on the left is less than or equal to the value on the right.

==, returns true if two values are equal.

!=, returns true if two values are not equal.

Comparing Strings

Do not use == or != to compare strings.

Instead, you can compare one string to another by calling equals() from one of them.

1
2
3
4
5
String str1 = "hello";
String str2 = "hello";

str1.equals(str2); // true
!str1.equals(str2); // false

You should know about how memory is being allocated. but 目前老师并没有讲

See you in workbook 3.1

if - else

Goal: Use if - else to run specific code blocks based on various conditions.

1
2
3
4
5
if (condition) {
// Code runs if the condition is true
} else {
// Code runs if the condition is false
}

The condition is usually the result of a comparison that returns true or false.

See you in workbook 3.2


Not only can we test only one condition, but also many conditions by embedding a series of else if (condition) statements.

1
2
3
4
5
6
7
8
9
if (condition) {
// Code
} else if (condition) {
// Code
} else if (condition) {
// Code
} else {
// Code
}

See you in workbook 3.3 and 3.4

Logical Operators

We can use logical operators to make our conditionals a little more complex.

There are 3 types of logical operators,


&& returns true only if both comparisons are true.

( comparison1 && comparison2 )


|| returns true if either one of the comparison is true.

( comparison1 || comparison2 )


! reverses the value of a boolean expression.


See you in workbook 3.5

Switch Statements

whenever you’re comparing one variable against a long list of values, such as

1
2
3
4
5
6
7
8
9
if (weather.equals("sunny")) {
// code
} else if (weather.equals("cloudy")) {
// code
} else if (weather.equals("rainy")) {
// code
} else {
// code
}

you should avoid having a long list of else if statements, because this looks so disgusting !

Instead, you should favor using a switch statement which was designed to compare one variable against a list of cases.

1
2
3
4
5
6
switch (weather) {
case "sunny": // code break;
case "cloudy": // code break;
case "rainy": // code break;
default: // code
}

Then you might be asking that when to use if vs switch ?

The only thing you can really do with switch is compare one variable against a list of values.

if statement is more flexible so that suitable for complex conditions, such as when you need to compare multiple variables, they give you the flexibility to evaluate compound conditions using logical operators.

1
2
3
4
5
if (temperature >= 80 && humidity >= 60) {
System.out.println("It's too hot and humid\n");
} else {
System.out.println("It's comfortable\n");
}

See you in workbook 3.6 and 3.7

As you write more and more code inside main(), you’ll notice that it becomes increasingly cluttered and messy.

And the more code you write, the more unreadable that it becomes.

Functions

A function is a grouping of code, it performs a task, and obviously it’s reusable.

Some functions rely on parameters to perform their task.

Some functions will return a final value.

image-20230423202020449

Instead of writing all of your code inside of a single code block,

you can split it up into functions and call them as needed.

Let’s begin organizing your code using functions!

Define functions and call them

See video on udemy.

Notice

Functions’ name needs to represent the task it’s performing.

Notice

public means the function can be publicly accessed from any package or subfolder,

but because we’ve got only one package with a single class in it,

it doesn’t really matter what level of access you specify.

Notice

You can notice that main() is also a function, it has a very similar signature to our functions.

Every function has a specific task that it performs, the main() function performs the task of running our application.

The main() function has a very specific signature that the JVM looks for when you run your app, when it finds main() function, it executes it.

Parameters

Functions with parameters expect to receive values.(these functions rely on parameters to perform their task)

Functions【without】parameters【do not expect】to receive values.

Parameters are essentially just variables.

Arguments

A value that you pass into a function is known as an argument.

Parameters and Arguments makes functions completely reusable!

Notice

When a function defines parameters, then in order to call it,

you need to pass in a matching number of arguments based on the position of these parameters.

Return Values

You can return values from a function.

Notice

Bad practice: Your function handles the final result.

Good practice: Your function return the final result.

Notice

Whenever you specify a return type,

you need to make sure that something gets returned no matter what gets passed in.

Terminate the runTime

1
System.exit(0);

See you in workbook 4.3

Doc Comments

Can be used to describe what a function does.

If you’re working in a team of developers, you should have a document for every function.

How to write Doc Comments ?

See udemy

See you in workbook 4.4

Scope

The scope of a variable determines its life span.

The take home message is:
You can never access a variable outside the scope that it was defined in.

Global Scope

Please against using global variables,

instead, you should keep everything local and use parameters,

because when you have too many global variables, you start losing track of what’s really going on(such as from your debugger in vscode).

Please watch the video on udemy.

Built-in Functions

The JDK provides so many built-in functions that you can call out of the box.

But to be honest, a good developer never memorizes code!

Instead, a good developer uses the internet!
to read documentation.
to find resources.

See you in workbook 4.5

Loops

For Loops: designed to run code a specific number of times.

While Loops: designed to run code an unknown number of times.

You will use the break and continue keywords to gain full control over your loops.

For Loops

1
2
for (int i = 0; i < 3; i ++) {
}

While Loops

What is a while loop ?

A while loop keeps running while a condition is true.

1
2
while (condition) {
}

See you in workboook 5.8 ~ 5.10

continue

The continue keyword skips a run in the loop and continues with the next one.

break

The break keyword when invoked, breaks the loop entirely.

Nested Loops

A nested loop is a loop inside of another loop.

eg: useful when working with 2D arrays.

1
2
3
4
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
}
}

Arrays、2D_Arrays

Looping Arrays、Updating Arrays

Arrays

Sometimes values can be closely related and creating one variable after another can be very messy such as below.

1
2
3
4
5
double price1 = 5.99;
double price2 = 6.99;
double price3 = 7.99;
double price4 = 8.99;
double price5 = 9.99;

So what we can do is to store all of these values at the same time in an organized way which is called an array.

1
double[] prices = { 5.99, 6.99, 7.99, 8.99, 9.99 };

Although an array can hold many values, all of them have to share the same type.

For example as below, integers points to an array of integer values.

1
int[] integers = { 1, 2, 3 };

Talk is cheap

1
String[] kindoms = { "qwe", "asd", "zxc" };

The truth is:

the variable kingdoms doesn’t store the array directly

instead

it stores a [reference] that points to it

202307291020173

1
2
3
// You can try to compile and run this line of code,
// you will get a hashcode representation of the reference.
System.out.println(kingdoms);

and each element is stored at an index

20230729103340

what will happen if I try to access an element outside the range of the array ?

1
System.out.println(kingdoms[3]);

20230729105228

20230729110015

Java throws an ArrayIndexOutOfBoundsException, in essence, crashing our application, telling us that we have an error in our code —— “Index 3 is out of bounds”

Preparing to loop arrays

The length of an array indicates the number of items it contains.

1
2
String[] items = { "apple", "banana", "cherry" };
System.out.println(items.length); // 3

So we can use the length property to loop arrays.

Looping arrays

Arrays and loops are like siblings.

1
2
3
4
5
6
7
8
9
10
11
12
String[] numbers = { 1, 2, 3, 4, 5, 6 };

// If you want to access each element in the array
// Would you perfer to index them all individually ?
numbers[0]
numbers[1]
numbers[2]
numbers[3]
numbers[4]
numbers[5]
// or use some kind of loop that iterates through every single element in the array ?
// I think the looping approach would be more efficient.
1
2
// Print the elements of an integer array using a loop
int[] numbers = {22, 24, 26, 29, 30};

for 循环

1
2
3
4
// autoComplete a for loop in vscode: fori<ENTER>
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}

foreach 循环

foreach simplifies looping through an array without the need for a counter or a counter increment or anything.

1
2
3
4
// autoComplete a foreach loop in vscode: fore<ENTER>
for (int number : numbers) {
System.out.println(number);
}

It just automatically iterates through every single number inside of the numbers array.

So as you can see, foreach is much cleaner and concise than the traditional for loop,

but the traditional for loop is more flexible because the counter i give us more control over the looping process.

I’m a bit tired of using loops to print an array,

Java has a function called toString, it takes your array as an argument, and it returns a string that we can print.

toString

Updating Arrays

It’s time to learn how to update arrays.

1
2
String[] flavours = { "Sweet", "Sour", "Bitter" };
flavours[2] = "Salty";

Is it possible to change the array length ?

NO.

Once you create an array, you cannot resize it.

1
2
String[] menu = { "Espresso", "Iced Coffee", "Latte" };
String[] newMenu = new String[5];

newMenu

1
2
3
for (int i = 0; i < menu.length; i++) {
newMenu[i] = menu[i];
}

The reference trap

I told you earlier that a variable cannot store an array, it stores a reference that points to it.

Because of this, another variable can actually store a reference that points to the same array.

1
2
int[] numbers = { 1, 2, 3 };
int[] numbers2 = numbers;

Do not set array variables equal to each other!

Instead, create a new array, then, copy every value using a for loop.

A better solution

Arrays.copyOf(a, b);

a means that the array you want to copy.

b means that how much of it you want to copy.

2D Arrays

1
2
3
4
5
int[][] grades = {
{72, 74, 78, 76},
{65, 64, 61, 67},
{95, 98, 99, 96}
};

When to work with 2D arrays ?

2D arrays is perfect for data in the form of a table.

1
2
int[][] integers = new int[3][4]; // 3 行 4 列
System.out.println(Arrays.toString(grades[0])); // [0, 0, 0, 0]

arrays and loops are like siblings

  • nested loops

    • outer loop runs through every row (i)
    • inner loop runs through every item in that row
    1
    2
    3
    4
    5
    for (int i = 0; i < grades.length; i++) {
    for (j = 0; j < grades[i].length; j++) {
    // ...
    }
    }
]]>
+ + + + + <p><a href="https://www.bilibili.com/video/BV1c54y1U7pp">初学编程的常见误区</a></p> +<p><img src="https://aliyun-oss-lpj.oss-cn-qingdao.aliyuncs.com/i + + + + + +
+ + + 公司内部培训笔记 + + https://liupj.top/2023/12/03/structuredExpression/ + 2023-12-03T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + 21世纪的 5 大生产要素:[数据]、土地、劳力、技术、资金

数据治理/运营是一种硬技能

做解决方案的思路

  1. 让用户感受到我们了解他们行业,并且很专业(用户不愿意听一个外行的聒噪)

  2. 描述清楚客户的核心问题

  3. 针对性地提出方案

  4. 讲出用户和我们合作的理由(我们是很专业的)

  5. 口说无凭,给出我们做过的成功案例

用结构化的方式进行思考、表达

Tips:思考的过程中应拿笔将思考出的结构用笔写下来,进而进一步分析

读观点传达类的文章可以对文章进行解构分析,然后建构,以清楚全面了解文章观点

学习别人的PPT可以先解构,再建构,为我所用

解构4步法:PUTS

  • P:means pick,即提取要点
  • U:means unit,即分组整理
  • T:means track,即查找关联,画出结构树状图
  • S:means summary,即总结概括

建构4原则:PGOS 树状图

  • P:结论前置
  • G:共性分组
  • O:先后排序
  • S:上下对应

典型场景的结论撰写公式

  • 计划型:准备做…. + 预期目标(结果)
  • 解释型:因为…… + 准备做…
  • 状态型:已进行到.. + 当前状态/阶段成果
  • 总结型:….已完成 + 结果/影响是…
  • 建议型:应该做…. + 以达到..目的/效果
  • 表态型:我认为…. + 因为…的原因

营销的一种结构

  • 你的目的是:递观点
    • 讲故事
    • 述情怀
]]>
+ + + + + <p>21世纪的 5 大生产要素:[数据]、土地、劳力、技术、资金</p> +<p>数据治理&#x2F;运营是一种硬技能</p> +<h3 id="做解决方案的思路"><a href="#做解决方案的思路" class="headerlink" title="做解决方案的思路"></ + + + + + +
+ + + 颓废文学 + + https://liupj.top/2023/11/19/relax/ + 2023-11-19T00:00:00.000Z + 2023-12-22T03:02:26.243Z + +
  • 正义都能迟到,为什么我上班不能迟到

  • 比我优秀的人都在努力,那我努力还有什么用

  • 干一行,恨一行,三百六十行,行行干破防

  • 安慰别人一套一套,安慰自己绳子一套

  • 天生我材必有用,至今不知有何用

  • 轻舟已过万重山,乌蒙山连着山外山

  • 明知山有虎,不去明知山

  • 任何困难都可以直接克服我

  • 希望大家都能走出舒适圈,然后让我进去

  • 生活不是无路可走,还有死路一条

  • ]]>
    + + + + + <ul> +<li><p>正义都能迟到,为什么我上班不能迟到</p> +</li> +<li><p>比我优秀的人都在努力,那我努力还有什么用</p> +</li> +<li><p>干一行,恨一行,三百六十行,行行干破防</p> +</li> +<li><p>安慰别人一套一套,安慰自己绳子一套< + + + + + +
    + + + 早起奔向面馆(转载) + + https://liupj.top/2023/09/10/eat-fish-noddle-at-morning/ + 2023-09-10T00:00:00.000Z + 2023-12-22T03:02:26.239Z + +

    很喜欢这篇文章,所以转载到我的小站了,如有侵权请联系我
    原文链接:https://www.yilinzazhi.com/2023/yl20231/2023111246.html

    鱼面分离的长鱼汤面是小面馆的绝活儿,长鱼就是鳝鱼。一大碗汤面配上一小碟鳝鱼,足以作为一天的元气补给。汤面由青花瓷碗盛着,浸在奶白色泽的汤里。如果顾客无食忌,王师傅会加些葱花或韭菜提鲜。这碗汤,王师傅头天下午便开始熬。

    这个熬可大有讲究,熬汤先熬骨。凌晨四点钟不到,已经开始忙活的王师傅加入鳝鱼片接着吊汤。直到清晨六点钟,汤熬毕,面备齐,小镇的八方食客也在来吃面的路上了。

    “王师傅早!”“早上好!”王师傅利落地盛汤、盛面、迎客、送客。让我想起第一次看他“庖王片鳝”,原本呈二角面的鳝鱼骨头在王师傅手里瞬时变得不一样起来,似乎有了神圣的色彩。王师傅头一刀从鱼头扎下去,急速沿鱼肚破开,接着沿骨剖开,末了再来一刀,一条干净齐整的鱼骨就在这三刀间成功脱了鱼肉。后来熟悉了小面馆,熟悉了王师傅,知道他就是这样一个干净齐整的人,案板总是清清爽爽,菜码也是秩序分明。简单的汤面,鳝鱼摆盘,他也尽可能在最短的时间拾掇得适宜、美观。我夸他认真,他一边片他的鳝鱼,一边笑道:“日子不就是这样过的吗?”

    日子一日三餐地过,举筷间我们一家人总要聊起小面馆,聊起认真过日子的王师傅。外公说:“做工作就要像老王,带劲!”他的确是带劲的,想来很大程度上缘于他有个好环境。在哪里工作,哪就是自己的领地。既然是领地,哪能潦草呢?除了“字典”里基本的整洁,王师傅还给自己的小面馆装了几盏灯。除了负责让店面更亮堂的暖黄灯管,还有星星一样的装饰灯,也是暖光的。他很得意地告诉我,这是他从儿子课本上看来的,书上说暖色调会刺激人的食欲。

    用王师傅的话说“忙总要忙出名堂来的”。其实,他追求的也不过四个字——“健康美味”,只不过他从未搞错这两个词的顺序。王师傅不怕麻烦,我早就见识过,该先熬魚骨就先熬鱼骨,该下鱼肉了才下鱼肉,该几个小时就几个小时。直到准确的步骤和恰到好处的时间让鱼骨里的胶质毫无保留地煨在汤中,进入每个食客的胃中,暖身暖心,最终久久地写入他们的味蕾记忆。王师傅还不怕浪费,后来外公说起,我才知道他总是挑好的、贵的食材,从不吝啬。

    一次,王师傅念小学的儿子给他打下手,小家伙一个没夹稳,食客要的荷包蛋“啪”的一声掉在了案板上,儿子拾起来就要往水池走,应该是想洗干净。王师傅停下手中的活儿,指着墙角的垃圾桶,说道:“扔掉。”得到大众认可总是有其道理的,而得到大家伙儿的肯定,除了能收获一众老客,还能收获满满的干劲。

    在王师傅的小面馆里,的确蕴藏着极盛大的认真,大清早世界刚刚苏醒,他已带着足足的干劲盛汤、盛面、迎客、送客。热气扑向他,把他衬得像个早间厨神,好像人间千家万户的早餐,全都仰仗着他这双带劲的路膊。

    我大喝一口乳白色的鲜鱼汤,由它把我体内的一个个器官朋友彻底激活。在早上急匆匆的城市大背景里选择稳当坐下来,认真吃一碗热腾腾、鲜入骨的长鱼汤面,也是我过日子所坚持的认真。

    ]]>
    + + + + + <blockquote> +<p>很喜欢这篇文章,所以转载到我的小站了,如有侵权请联系我<br>原文链接:<a href="https://www.yilinzazhi.com/2023/yl20231/2023111246.html">https://www.yilinzazhi + + + + + +
    + + + 夜爬泰山有感 + + https://liupj.top/2023/06/24/mountTai/ + 2023-06-24T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 因为网上别人发表的攻略给了我不少帮助,所以我也决定写下这篇攻略,分享给大家

    说实话,夜爬泰山之后,我是有些后怕的,为了大家的安全着想,我要先写一下此次夜爬我感受到的危险

    我没有数我到底爬了多少级台阶,但据网友反映泰山大致需要爬六七千级台阶(但我觉得这每一级台阶都比普通住宅楼里的台阶更窄、更陡、更不平)

    端午假期游人众多,十有八九都是二十啷当岁初生牛犊不怕虎的年轻人,达到了人挤人的状态,众多的爬山人和漆黑的夜色给山路增加了不少危险性

    因为台阶上会有空的矿泉水瓶、西瓜皮、水果核,甚至还会有别人遗弃的登山杖,这些东西会向山下掉落,而你很难时刻注意你脚下的真实情况

    一旦不小心踩住或绊住,就特别容易摔跤(下山路上不少台阶上已经干了的暗红色血迹真的让人不寒而栗)

    而在人挤人的情况下,摔跤就变得更加危险,无论是自己摔跤还是别人摔跤,都极易造成连锁反应(幸好我没遇到)

    另外,如果你爬到半山腰想放弃,你会进退两难,你只能向山路两边的护栏和岩石靠拢,而部分爬不动的人放倒在地面上的登山杖又容易绊倒上山的人

    渴、饿、累、困、冷、拉肚子、低血糖,还有其他情况在高山上的夜晚都可能出现,商店很多,厕所不多,没有医院

    另外,上山容易下山难,这是亘古不变的真理!!!

    看到这里如果你觉得你可以,我要开始安利了

    上山之前

    你可以像我一样,下午去山东农大旁边的清真寺街吃当地的特色美食——姜片炒鸡

    WechatIMG13

    清真寺街的许家姜片炒鸡很好吃也很适合作为上山前补充体力的食物

    鸡肉外香里嫩干而不柴,姜片是油炸过的,薄脆像薯片,很适合我这种不喜欢姜味的人哈哈哈哈哈

    老板娘年轻美丽,长得像我高中语文老师,掌柜的慈眉善目和蔼可亲,看起来人很正派,希望他们家红火

    我吃了一只炒鸡一碗大米半份蒜泥黄瓜,昏昏欲睡。。

    那就去红门游客中心旁边开个房吧,钟点房一小时 20 元,一觉醒来八点半了。。

    九点多向山顶进发!

    爬山途中

    一路上我竟然没有一丝困意,大概是太想登顶了吧,虽然我一直在出汗,一直在补水,到中天门没忍住,吃了两块西瓜

    反正周围一片漆黑全是人啥风景也看不到,心中只有一个目标,冲向山顶!

    早知道就不带风油精了,蚊子大概不知道该咬谁吧,全是人。。

    脑海里竟然出现了角马大迁徙的场景,那个画面。。我们就是英勇无畏的角马!

    soMuchPeople

    登山杖立起来啊朋友们我都害怕踩到前面人的登山杖。。

    登顶了!

    在一个看起来人不多的地方坐了下来,面前是齐鲁大地灯火辉煌的夜景,好令人震撼啊,打开手机指南针一看,正西。。

    WechatIMG16

    溜了溜了

    果不其然,正东已经坐下了两三排人,一点多啊,我还以为我来早了。。

    看到一个空位,两边都是小姐姐。。我滴妈呀。。问了一句她们竟然是同伴。。友善的小姐姐给我挪了个位置,小姐姐真好啊,带了薄荷口香糖提神用的,问她吃不吃,好像把我当坏人了。。防人之心不可无啊。。

    山风一阵阵的,这届大学生果然优秀,我们喊着口号“青春没有售价,泰山就在脚下!” 啊!心情舒畅!

    扛旗的小伙子真酷啊!美丽的五星红旗在泰山之顶迎风飘荡,我们唱起了国歌!

    租件大衣看来是正确的,山风一阵一阵的,没风的时候热,吹风的时候冷,嗨,还是穿着吧。。

    好久没有看到过这么多的星星了啊,感觉真美好,可是星星不够亮,手机拍不出来。。

    天蒙蒙亮了!岩石上一个小哥哥播放了下面这首歌,感谢他

    泰山之巅的启明星叫醒了不知名的鸟儿,歌声婉转,我的头顶还飞过了几只小蜜蜂,到底是谁喊了一句“md还有苍蝇”

    远处的云竟然像一个齐平的大幕,太阳像一个烙红的热铁,又像一盏刚点亮的路灯,从云深处慢悠悠巍然而起

    清晨的太阳变化很快,不一会儿就变得像一个顶着金色帽子的红色真知棒

    前面的人开始下山,后面的人举着镜头向前,我开始饿了,找了个安全的地方开始补充体力,夜晚没看到的风景我要在凉爽的早晨补回来!

    和一个刚毕业的小哥哥聊天了,我感觉他好有礼貌好帅气好紧张,我说我不年轻了,他说我心态年轻。。没毛病 95 后已经干不过 00 后了。。

    我还是很感激他,告诉了我厕所在哪里,虽然我去了另一个厕所。。

    在山顶休整了两个小时,山上开始变得冷清,我开始欣赏清晨的泰山景色,啊,山川大好,大好河山!

    WechatIMG14

    我在泰山顶的岩石上晾晒我湿了的衣服,心想咱也是在泰山顶上晾过衣服的人了哈哈哈

    有个零零后的小男生翻过了护栏让他朋友拍照,脚的旁边就是万丈悬崖,我看得好害怕,友善提醒了一句,他没听,幸好他安全翻回来了

    别做傻事啊朋友们,青春价虽高,生命诚可贵,也可能是我太胆小了吧,但我觉得小心驶得万年船

    我看到有一家人也在山顶玩耍,感觉素质很高,孩子丢下的垃圾都捡走了,给他们点赞,朋友们在保证安全的情况下尽量别乱丢垃圾啊,清洁工很辛苦,泰山奶奶不容易

    我和他们一起聊着天下山了,他们竟然也从天津来,本来说要一起去坐索道,但是我不想排队了,就下山去中天门了

    下山路上的风景真好啊,空气看起来就特别清新的样子,呼吸让人舒畅

    坐索道的人应该会看到不一样的风景吧

    坐着大巴下山了,这个盘山路真刺激啊,窄窄的双行道只有两个大巴的宽度,连续不断的大巴车擦身而过,司机师傅太牛了

    车上超级安静,司机超级淡定,我超级亢奋,这比跑跑卡丁车都刺激

    到了山下手机信号才变好了,去的时候带点一块的纸币爬山路上用得着啊朋友们

    拜拜泰山,拜拜沿路遇到的每一个友善的人

    下次再来

    手机,充电线,充电宝,身份证,家里的钥匙,纸币零钱(山路上人多信号不好买补给用)

    usb充电式强光手电,保暖衣物,小包卫生纸,面包(山顶的早餐)

    备一点应急药物也是 ok 的

    ]]>
    + + + + + <p>因为网上别人发表的攻略给了我不少帮助,所以我也决定写下这篇攻略,分享给大家</p> +<p>说实话,夜爬泰山之后,我是有些后怕的,为了大家的安全着想,我要先写一下此次夜爬我感受到的危险</p> +<p>我没有数我到底爬了多少级台阶,但据网友反映泰山大致需要爬六七千级台阶(但我觉 + + + + + +
    + + + 简单学了一下 python 脚本编程 + + https://liupj.top/2023/04/01/py_takeaway_message/ + 2023-04-01T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + learn from: https://learn.udacity.com/courses/ud1110

    A scripter to solve problem

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    repeat:

    try it the slow way to understand what you are trying to achieve
    do some learning(remember to look up documentation)

    break up the problem into steps
    choose data_types、control_flows、...
    write down your pseudo_code

    write code & test code

    why you should choose data_type

    An object’s type defines which operators and functions will work on that object and how they work,

    different types have different properties,

    so when you’re designing on computer program,

    you need to choose types for your data based on how you’re going to use them.

    For example, if you want to use a number as a part of a sentence in Python,

    it’ll be easiest if that number is a string,

    because there are specially designed operators and functions for working with these data.

    ]]>
    + + + + + <p>learn from: <a href="https://learn.udacity.com/courses/ud1110">https://learn.udacity.com/courses/ud1110</a></p> +<h2 id="A-scripter-to-sol + + + + + +
    + + + 如何购买国外的课程(在中国) + + https://liupj.top/2023/03/28/how-to-buy-courses-on-udemy-in-china/ + 2023-03-28T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 先看看这篇文章:从支付、购买到售后:Google Play 购物指南

    ok, 我选择使用【礼品卡】的付款方式

    使用的设备

    macbook、iqoo-z5

    背景

    我的每台设备均可以正常访问 google

    读者可以各显神通以获得速度良好的外网访问权限

    安卓手机如何下载 play 商店

    下载渠道:apkmirror.com

    参考了这个视频:https://www.youtube.com/watch?v=isERiuP5xTY

    安卓手机通过验证码验证谷歌账号时若不显示验证码的输入框怎么办

    将手机的【验证码安全保护】关闭即可,可在手机设置中搜索

    感谢这个视频的评论区给予的帮助

    在哪购买礼品卡

    淘宝搜索【play 礼品卡】

    根据自己需要哪个国家或地区的💰来选择购买礼品卡

    笔者礼品卡购于咸鱼,使用方式可询问卖家

    done

    ]]>
    + + + + + <p>先看看这篇文章:<a href="https://zhuanlan.zhihu.com/p/43166346">从支付、购买到售后:Google Play 购物指南</a></p> +<p>ok, 我选择使用【礼品卡】的付款方式</p> +<h2 id="使用的设备"><a h + + + + + +
    + + + 记录我上手使用 Macbook Air M1 的过程 + + https://liupj.top/2023/03/18/macos-m1-setup/ + 2023-03-18T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 前言

    2023-03-18, 我收到了我人生中第一台 MacBook Air M1

    由于这是我第一次使用 macos,所以我打算记录下我上手 macos 的过程

    希望将它慢慢打造成适合我的一把利器,那就开始吧

    进入桌面前的初始化设置操作就自己弄吧,原则:最小化设置

    设置触控板

    点击屏幕左上角苹果 logo,然后选择系统设置,然后在打开的窗口的左侧边栏中下拉选择触控板

    跟踪速度自行调整,勾选轻点来点按

    设置键盘

    由于我是 Vim 重度用户,所以习惯性将 Caps Lock 键设置为 Escape 键

    系统设置 =》键盘 =》闲置后关闭键盘背光灯(5分钟后)=》键盘快捷键 =》修饰键 =》大写锁定键更改为 Escape 键 =》完成

    设置三指拖移:系统设置 =》辅助功能 =》指针控制 =》触控板选项 =》打开“使用触控板进行拖移”(或“启用拖移”)=》选取“三指拖移”拖移样式

    =》好

    安装一些应用程序

    qq音乐、微信,腾讯会议,阿里云盘,…

    科学上网

    节点 + clashX 开启系统代理

    单独给 Terminal.app 设置代理

    1
    2
    3
    export http_proxy=http://127.0.0.1:7890
    export https_proxy=http://127.0.0.1:7890
    export all_proxy=socks5://127.0.0.1:7890

    打造命令行

    包管理器:brew

    ]]>
    + + + + + <h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>2023-03-18, 我收到了我人生中第一台 MacBook Air M1</p> +<p>由于这是我第一次使用 macos,所以我打算记录 + + + + + +
    + + + zerotier 简明教程 + + https://liupj.top/2023/01/31/zerotier/ + 2023-01-31T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + 前言

    一台 ArchLinux 放家里,一台 Windows10 放单位

    用 zerotier 将这俩机器放到一个虚拟局域网

    用 ssh 就能相互访问

    用 zerotier 创建一个私有的(private)虚拟局域网,获取到网络ID

    https://my.zerotier.com/

    创建私有网络的好处是:任何机器想加入该网络都需要获得你的许可

    ArchLinux 设置步骤

    1
    2
    3
    sudo pacman -S zerotier-one
    sudo systemctl enable --now zerotier-one.service
    sudo zerotier-cli join 网络ID

    Windows10 设置步骤

    下载地址:https://www.zerotier.com/download/

    启动 zerotier,加入网络

    最后

    https://my.zerotier.com/ 对成员节点勾选授权

    ok,至此,两台机器可以通过 ssh 相互访问

    参考了

    https://www.zerotier.com/manual/

    https://jiajunhuang.com/articles/2019_09_11-zerotier.md.html

    ]]>
    + + + + + <h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>一台 ArchLinux 放家里,一台 Windows10 放单位</p> +<p>用 zerotier 将这俩机器放到一个虚拟局域网</p> + + + + + +
    + + + 分享一道计算机网络的经典面试题(关于为什么网络层地址和 MAC 地址共存) + + https://liupj.top/2023/01/30/mac-ip/ + 2023-01-30T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 有了 MAC 地址,为什么还需要 IP 地址 ?

    计算机网络诞生之初,只是一个个小的局域网,还没有形成如今的互联网;

    局域网内的计算机之间通信,需要对每个计算机进行唯一标识,所以就诞生了 MAC 地址。

    随着计算机网络的发展,局域网之间开始互联互通,产生了计算机跨网络通信的需求;

    试想,假设局域网 A 内的主机 A1 想要发送数据包给局域网 B 内的主机 B1

    若 A1 只知道 B1 的 MAC 地址,显然 A1 无法知道应该将数据包发往哪个网络

    即:MAC 地址并不具备标识网络的作用

    所以,能够标识网络的 IP 地址诞生


    既然 IP 地址的定位是标识网络,那么为什么要把 IP 地址设计成既能标识网络,又能标识主机 ?

    举个例子,假设局域网 A 内的主机 A1 想要发送数据包给局域网 B 内的主机 B1

    假设A1 只知道 B1 的 IP 地址

    如果 IP 地址只能标识网络,那么 A1 就只能将数据包发往目的网络,然后数据包就不知该何去何从了

    所以 IP 地址既要能标识网络,又要能标识主机


    既然有了 IP 地址,为什么还要有 MAC 地址 ?或者说只靠 IP 地址进行互联网通信行不行 ?

    参考了:http://liupj.top/2022/04/04/ether-net/

    如果没有 MAC 地址,而是使用网络层协议进行通信,理论上来说是可以的,但是不好

    因为在以太网诞生之初,IP 还没有垄断网络层协议(那时还有Novell网的IPX/SPX协议、DEC公司开发的CLNP网络协议,以及Apple公司开发的Apple Talk协议)

    如果没有 MAC 地址,势必需要网卡解读网络层协议帧头的地址信息,而不同网络层协议帧头的地址都大相径庭,这就增加了以太网卡的实现复杂度。

    如果网卡有了 MAC 地址,就可以不依赖于任何网络层协议,独立判断一个帧是否接收(依据 MAC 地址匹配),这就大大简化了网卡的实现。

    即使以后出现更多的网络层协议,网卡也无需太多的改变,这就是网络分层的精髓

    一层的内部实现无需知晓其上层、或下层


    其实,《计算机网络自顶向下方法》对该问题有明确的回答

    英文原版
    20230130194206

    中译版
    20230130194400


    综上所述,MAC 和 IP 缺一不可。

    从 IP 到 MAC 的转换,使用 ARP 协议。


    补充知识:

    主机的 IP 地址是可以动态变化的,而 MAC 地址是写死的,一般不能变(当然也有随机 MAC 的手段

    ]]>
    + + + + + <h3 id="有了-MAC-地址,为什么还需要-IP-地址-?"><a href="#有了-MAC-地址,为什么还需要-IP-地址-?" class="headerlink" title="有了 MAC 地址,为什么还需要 IP 地址 ?"></a>有了 MAC 地址,为什么还 + + + + + +
    + + + 我为什么放弃了 firefox,重新回到 chrome + + https://liupj.top/2023/01/07/why-chrome/ + 2023-01-07T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + 小孩子才做选择,chrome & firefox 我全都要 !

    主 chrome

    辅 firefox


    以下为原文

    course, v2raya is awesome.

    firefox 的痛点让我换回了 chrome

    1、对沙拉查词的支持度不如 chrome

    2、firefox 的快捷键默认无法修改,在组合键 ctrl-shift-p 上与 picgo 冲突,虽然可以修改 picgo 的快捷键,但更换组合键不便于记忆

    3、I hate programs creating files or folders in my home directory casually without my permission, such as ~/.mozilla

    ]]>
    + + + + + <p>小孩子才做选择,chrome &amp; firefox 我全都要 !</p> +<p>主 chrome</p> +<p>辅 firefox</p> +<hr> +<p>以下为原文</p> +<blockquote> +<p>course, v2raya is awesome.</p> + + + + + +
    + + + 在 ArchLinux 主机上安装 win10 虚拟机 + + https://liupj.top/2022/12/31/windows10-in-virtualbox/ + 2022-12-31T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + 想啥呢 !在 Linux 主机上安装虚拟机是一件非常痛苦的事情 !

    从此以后,不再在 Linux 主机上折腾一切有关虚拟机的东西 !

    ]]>
    + + + + + <p>想啥呢 !在 Linux 主机上安装虚拟机是一件非常痛苦的事情 !</p> +<p>从此以后,不再在 Linux 主机上折腾一切有关虚拟机的东西 !</p> + + + + + + +
    + + + 小羊人的复盘与反思 + + https://liupj.top/2022/12/12/ill/ + 2022-12-12T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 稳住 !

    明确

    发热不是一件坏事,而是你的身体在与病毒做对抗

    注意保暖,用煮鸡蛋和电解质水来为身体的免疫系统提供“弹药”支持

    药品需要在药师的指导下使用,38.5 度以上才可考虑使用退烧药

    去附近大医院发热门诊

    医保码、挂号、缴费、出具检验报告、就诊ID,手机上都能整 !

    书包、充好电的手机、身份证

    口罩、酒精湿巾、保温杯、面包

    毛巾、卫生纸

    手套、围巾、帽子

    ]]>
    + + + + + <p>稳住 !</p> +<h3 id="明确"><a href="#明确" class="headerlink" title="明确"></a>明确</h3><p>发热不是一件坏事,而是你的身体在与病毒做对抗</p> +<p>注意保暖,用煮鸡蛋和电解质水来为身体的免疫系统提供“弹药 + + + + + +
    + + + 我在 Linux 上听歌的方式 + + https://liupj.top/2022/12/09/music-linux-method/ + 2022-12-09T00:00:00.000Z + 2023-12-22T03:02:26.243Z + + 前言

    我喜欢听歌,但苦于国内各大音乐平台的割据状态(版权、音质、网速、…)

    而我又喜欢双手不离开键盘(不用鼠标,尽可能地少用触控板)且我希望将尽可能多的工作在一个终端窗口中完成

    于是我开始了如下探索,试图建立适合自己的听歌方式…

    最佳的音乐播放体验

    当然是从互联网中搜索无损音乐(.flac),下载到本地进行播放咯

    从哪找没听过的歌呢

    listen1

    20221210150913

    本地音乐播放器推荐

    audacious

    20221210150313

    怎么把想听的歌下载到本地呢

    https://github.com/zonemeen/musicn 404 了

    musicn|npmjs

    注意:该软件依赖 node.js 16+ 版本,我设置的版本为 v16.18.1,设置方式可参考这里

    小技巧:echo "alias msc="msc -p DIR_TO_STORE_MUSICS" >> ~/.bashrc if you use bash.

    哎嗨 !我们已经可以在终端中搜索并下载音乐了,测试使用效果如下

    20221209150558


    以下播放音乐的方式仅适用于播放单个音频文件,仅供参考,选看。

    sox

    如果只是想在终端中简单地播放一个音频文件/一首歌,那么推荐使用软件 sox 提供的 play 命令

    Install by executing sudo pacman -S sox if you use ArchLinux like me.

    测试使用效果如下

    20221209152728

    参考了:https://askubuntu.com/questions/920539/how-do-you-play-a-sound-from-the-terminal

    ranger + vlc

    vlc 是一款在 Linux 上广受好评的多媒体播放器,能播放视频和音乐

    而且我习惯使用 Ranger, 一款为 vim/neovim 用户打造的文件浏览器,很好用 !

    所以我希望 Ranger 能识别我的音乐文件并自动调用 vlc 播放

    Luckily, Ranger ships with rifle, a file launcher that is good at automatically finding out which program to use for what file type. —— knowing from Ranger’s doc

    所以我只需对 rifle配置文件进行一下简单的修改即可

    20221210153018

    测试使用效果如下,可以看到 Ranger 自动调用 vlc 开始播放音乐文件了

    20221209160452

    参考了:https://superuser.com/questions/724689/open-vlc-in-background

    期望

    受限于目前的工作和技术水平,我对目前的听歌方式还不够满意,希望在未来能打造一个适合我自己的音乐播放软件(GUI or CLI)running on linux which is both open-source、lightweight and reliable.

    ]]>
    + + + + + <h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>我喜欢听歌,但苦于国内各大音乐平台的割据状态(版权、音质、网速、…)</p> +<p>而我又喜欢双手不离开键盘(不用鼠标,尽可能地少用触控板) + + + + + +
    + + + 矢志不渝,争做踔厉奋发通信人 + + https://liupj.top/2022/10/22/1_big_20/ + 2022-10-22T00:00:00.000Z + 2023-12-22T03:02:26.239Z + +

    学习党的第二十次全国代表大会有感

    十月金秋,我们党的第二十次全国代表大会在和畅惠风中徐徐拉开大幕,我怀着一颗无比崇敬而向往的心,认真收看学习了习总书记在开幕会上的精彩报告,颇受激励,遂有如下感悟。

    漫漫征程看领航

    回首过往百年,是我们党始终牢牢把握了民族复兴征途的航向,不惧艰险,拨开迷雾,团结带领着亿万人民砥砺前行。身为一名新时代青年,我深知初出茅庐的我肩负着为国家大业添砖加瓦的一份使命和责任,就像鲁迅先生曾说的那样——摆脱冷气向上走,有一份光,发一份热;又如习总书记说的那样——当代青年生逢其时,施展才干的舞台无比广阔,实现梦想的前景无比光明。我深以为然。故而更加坚定了心中紧紧跟党走的信念,更加笃定了为家国事业脚踏实地、谦虚谨慎、艰苦奋斗的底气和决心。

    武装思想抓实践

    托尔斯泰有言——文明的建立不是机器而是思想,我们党历经百年风雨,俨然壮大为今日国际最大的马克思主义政党,恰得益于我们国家一代代共产党人对先进马克思主义的深刻学习和领会,以及先辈们充分发挥主观能动性,审时度势因地制宜地不断改造发展马克思主义,让其越发闪耀出本土化、时代化光芒的创新之举。我们青年一代是祖国未来几十年发展的主力军,更应奋力扛起习近平新时代中国特色社会主义的伟大旗帜,不断坚定道路自信、理论自信、制度自信和文化自信,不断学习和发扬一代代革命先辈们的锐意进取、守正创新和矢志不渝,从实践中来,到实践中去,在今后的工作岗位上多尝试新思路、多思考新办法,承前人之硕果,不断提质增效,续写华夏新篇章。

    回首成就固成因

    十八大以来的十年里,我们党团结带领全国各族人民完成了脱贫攻坚、全面建成小康社会的历史任务,中国特色社会主义进入了新时代,能取得如此举世瞩目的成就,定然在过往的各项工作中我们收获了不可胜数弥足珍贵的实践经验,那么我们就应该将这些零零碎碎的经验好好梳理,穿成串、织成网,充实丰富我们改革开放民族复兴大业前行路上的工具箱,为新征程不断助力。见著而观微,身为当代通信人,我不断观察学习着行业同事们高效的工作方式,不断听取借鉴着行业前辈们宝贵的工作经验,我感受到他们的热心和友善,更感受到他们的信任和期盼,经验是行业的传承,发展是行业的目标,前辈们宝贵的实践经验给我的信心以支撑,给我的信念以动能,青年强则国强,行业兴则国兴,我们通信行业青年一代必会抬头看路埋头前行,继往开来不辱使命。

    把握机遇迎挑战

    新冠疫情肆虐,国际形势复杂多变,近些年着实不寻常、不平凡,在如此社会大背景下,作为肩挑国家通信事业大梁的主力军,我们应当从挑战中敏锐发现机遇、把握机遇,始终将一颗建设、服务的心同党和人民紧密联系在一起,深入基层,奉献社会,做好当前形势下的通信保障工作;我深知打铁还需自身硬,我们年轻一代通信人还应当积极学习更先进科学文化知识,用科技的力量促进高质量发展,推动我国通信事业不断迈向更高的台阶,用更强大的网络基础设施催生更多先进上层应用的实施研发,保障更多高新产业的落地推广;我们还应从提升自身的网络安全意识做起,主动向身边人、全社会普及网络安全知识,努力提高全民的网络安全防范化解风险意识,以更加从容的姿态直面风险、应对挑战。

    前途光明,任重道远,空谈误国,实干兴邦,我们联通青年必将不忘初心跟党走,牢记使命勇前行。

    天津联通河东分公司,刘培杰。

    ]]>
    + + + + + <blockquote> +<p>学习党的第二十次全国代表大会有感</p> +</blockquote> +<p>十月金秋,我们党的第二十次全国代表大会在和畅惠风中徐徐拉开大幕,我怀着一颗无比崇敬而向往的心,认真收看学习了习总书记在开幕会上的精彩报告,颇受激励,遂有如下感悟。</p> + + + + + + +
    + + + 记录我看过的影片 + + https://liupj.top/2022/10/02/movies/ + 2022-10-02T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 记录一下我看过的,我认为好看的影片,大概以后会重温吧。

    电影

    片名
    触不可及
    辛德勒的名单
    切尔诺贝利
    后天
    忠犬八公的故事
    你好,李焕英
    海上钢琴师
    隐入尘烟
    人生大事
    当幸福来敲门
    活着
    肖申克的救赎
    我不是药神
    摔跤吧!爸爸
    心灵捕手
    被解救的姜戈
    背靠背,脸对脸
    1942
    平凡英雄
    血战台儿庄
    小鬼当家(只有第一部好看)
    困在时间里的父亲
    唐山大地震
    魔女(只有第一部好看)
    珍珠港
    决战中途岛
    <++>
    <++>

    国产剧

    片名
    亮剑
    小兵张嘎
    恋爱先生
    情满四合院
    人民的名义
    好先生
    父母爱情
    新三国
    小欢喜
    <++>
    <++>
    <++>

    动画

    片名
    坏蛋联盟
    终极细胞战
    葫芦娃
    狮子王
    黑猫警长
    猫咪小贝
    哪吒闹海
    虹猫蓝兔七侠传
    机器猫(小叮当)
    猫和老鼠
    舒克贝塔
    成龙历险记
    <++>
    <++>
    <++>

    to be continue…

    ]]>
    + + + + + <p>记录一下我看过的,我认为好看的影片,大概以后会重温吧。</p> +<h3 id="电影"><a href="#电影" class="headerlink" title="电影"></a>电影</h3><table> +<thead> +<tr> +<th>片名</th> +</tr> + + + + + +
    + + + SIGINT And Other Termination Signals in Linux(转载) + + https://liupj.top/2022/08/05/sigint-and-other-termination-signals-in-linux/ + 2022-08-05T00:00:00.000Z + 2023-12-22T03:02:26.243Z + +

    原文地址:https://www.baeldung.com/linux/sigint-and-other-termination-signals

    Overview

    In Linux systems, processes can receive a variety of signals, such as SIGINT or SIGKILL. Each signal is sent in different situations and each has different behavior.

    In this article, we’ll talk about SIGINT, SIGTERM, SIGQUIT, and SIGKILL. We’ll also see the difference between them.

    Introduction to Signals

    The signals are a method of communication between processes. When a process receives a signal, the process interrupts its execution and a signal handler is executed.

    How the program behaves usually depends on the type of signal received. After handling the signal, the process may or may not continue its normal execution.

    The Linux kernel can send signals, for instance, when a process attempts to divide by zero it receives the SIGFPE signal.

    We can also send signals using the kill program. Let’s run a simple script in the background and stop it:

    1
    2
    3
    4
    $ (sleep 30; echo "Ready!") &
    [1] 26929
    $ kill -SIGSTOP 26929
    [1]+ Stopped ( sleep 30; echo "Ready!" )

    Now, we can resume it using SIGCONT:

    1
    2
    3
    $ kill -SIGCONT 26929
    Ready!
    [1]+ Done ( sleep 30; echo "Ready!" )

    Alternatively, we can send signals in a terminal using key combinations. For instance, Ctrl+C sends SIGINT, Ctrl+S sends SIGSTOP, and Ctrl+Q sends SIGCONT.

    Each signal has a default action, but a process can override the default action and handle it differently, or ignore it. However, some signals can’t be ignored nor handled differently and the default action is always executed.

    We can handle signals in bash using the trap command. For instance, we can add trap date SIGINT in a script and it will print the date when SIGINT is received.

    SIGINT

    SIGINT is the signal sent when we press Ctrl+C. The default action is to terminate the process. However, some programs override this action and handle it differently.

    One common example is the bash interpreter. When we press Ctrl+C it doesn’t quit, instead, it prints a new and empty prompt line. Another example is when we use gdb to debug a program. We can send SIGINT with Ctrl+C to stop the execution and return it to the gdb’s interpreter.

    We can think of SIGINT as an interruption request sent by the user. How it is handled usually depends on the process and the situation.

    Let’s write handle_sigint.sh using the trap command to handle SIGINT and print the current date:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash

    trap date SIGINT

    read input
    echo User input: $input
    echo Exiting now

    We use read input to wait for the user interaction. Now, let’s run our script and let’s press Ctrl+C:

    1
    2
    $ ./handle_sigint.sh 
    ^CSat Apr 10 15:32:07 -03 2021

    We can see the script didn’t exit. We can now terminate the script by writing some input:

    1
    2
    3
    4
    5
    $ ./handle_sigint.sh 
    ^CSat Apr 10 15:32:07 -03 2021
    live long and prosper
    User input: live long and prosper
    Exiting now

    If we want to use a signal to terminate it, we can’t use SIGINT with this script. We should use SIGTERM, SIGQUIT, or SIGKILL instead.

    SIGTERM and SIGQUIT

    The SIGTERM and SIGQUIT signals are meant to terminate the process. In this case, we are specifically requesting to finish it. SIGTERM is the default signal when we use the kill command.

    The default action of both signals is to terminate the process. However, SIGQUIT also generates a core dump before exiting.

    When we send SIGTERM, the process sometimes executes a clean-up routine before exiting.

    We can also handle SIGTERM to ask for confirmation before exiting. Let’s write a script called handle_sigterm.sh to terminate only If the user sends the signal twice:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #!/bin/bash

    SIGTERM_REQUESTED=0
    handle_sigterm() {
    if [ $SIGTERM_REQUESTED -eq 0 ]; then
    echo "Send SIGTERM again to terminate"
    SIGTERM_REQUESTED=1
    else
    echo "SIGTERM received, exiting now"
    exit 0
    fi
    }

    trap handle_sigterm SIGTERM

    TIMEOUT=$(date +%s)
    TIMEOUT=$(($TIMEOUT + 60))

    echo "This script will exit in 60 seconds"
    while [ $(date +%s) -lt $TIMEOUT ]; do
    sleep 1;
    done
    echo Timeout reached, exiting now

    Now, let’s run it on background executing $ ./handle_sigterm.sh &. Then, we run $ kill <PID> twice:

    1
    2
    3
    4
    5
    6
    7
    $ ./handle_sigterm.sh &
    [1] 6092
    $ kill 6092
    Send SIGTERM again to terminate
    $ kill 6092
    SIGTERM received, exiting now
    [1]+ Done ./handle_sigterm.sh

    As we can see, the script exited after it received the second SIGTERM.

    SIGKILL

    When a process receives SIGKILL it is terminated. This is a special signal as it can’t be ignored and we can’t change its behavior.

    We use this signal to forcefully terminate the process. We should be careful as the process won’t be able to execute any clean-up routine.

    One common way of using SIGKILL is to first send SIGTERM. We give the process some time to terminate, we may also send SIGTERM a couple of times. If the process doesn’t finish on its own, then we send SIGKILL to terminate it.

    Let’s rewrite the previous example to try to handle SIGKILL and ask for confirmation:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/bin/bash

    SIGKILL_REQUESTED=0
    handle_sigkill() {
    if [ $SIGKILL_REQUESTED -eq 0 ]; then
    echo "Send SIGKILL again to terminate"
    SIGKILL_REQUESTED=1
    else
    echo "Exiting now"
    exit 0
    fi
    }

    trap handle_sigkill SIGKILL

    read input
    echo User input: $input

    Now, let’s run it on a terminal, and let’s send SIGKILL only once with $ kill -SIGKILL <pid>:

    1
    2
    3
    $ ./handle_sigkill.sh
    Killed
    $

    We can see it terminate right away without asking to re-send the signal.

    How SIGINT Relates to SIGTERM, SIGQUIT and SIGKILL

    Now that we understand more about signals, we can see how they relate to each other.

    The default action for SIGINT, SIGTERM, SIGQUIT, and SIGKILL is to terminate the process. However, SIGTERM, SIGQUIT, and SIGKILL are defined as signals to terminate the process, but SIGINT is defined as an interruption requested by the user.

    In particular, if we send SIGINT (or press Ctrl+C) depending on the process and the situation it can behave differently. So, we shouldn’t depend solely on SIGINT to finish a process.

    As SIGINT is intended as a signal sent by the user, usually the processes communicate with each other using other signals. For instance, a parent process usually sends SIGTERM to its children to terminate them, even if SIGINT has the same effect.

    In the case of SIGQUIT, it generates a core dump which is useful for debugging.

    Now that we have this in mind, we can see we should choose SIGTERM on top of SIGKILL to terminate a process. SIGTERM is the preferred way as the process has the chance to terminate gracefully.

    As a process can override the default action for SIGINT, SIGTERM, and SIGQUIT, it can be the case that neither of them finishes the process. Also, if the process is hung it may not respond to any of those signals. In that case, we have SIGKILL as the last resort to terminate the process.

    Conclusion

    In this article, we learned about signals and the difference between SIGINT, SIGTERM, SIGQUIT, and SIGKILL. Also, we briefly learned how to handle signals in bash.

    We saw how SIGINT sometimes doesn’t kill the process as it may a different meaning. On the other hand, the SIGKILL signal will always terminate the process.

    We also learned that SIGQUIT generates a core dump by default and that SIGTERM is the preferred way to kill a process.

    ]]>
    + + + + + <blockquote> +<p>原文地址:<a href="https://www.baeldung.com/linux/sigint-and-other-termination-signals">https://www.baeldung.com/linux/sigint-and + + + + + +
    + + + 公务员考试方法论(转载) + + https://liupj.top/2022/07/22/gongkao-method/ + 2022-07-22T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 公务员考试,如何上岸?

    先说结论:通关上岸,课程占30%,刷题占60%,剩下10%交给运气。

    30%课程:

    很多考生总有这样一种执念,觉得xx机构的课程一定很厉害,学完基本就稳了,但就是有点贵,动辄几千上万。。还有点纠结值不值,其实,这不就明摆着割韭菜吗?

    公考制度已经运行这么多年了,相应的课程都已经非常成熟,不存在课程决定结果的现象,如果真有这种课程,学完就上岸,你觉得会在市面上广泛流通吗?

    公考现在是非常公平公正公开的,是除了高考之外为数不多的实现阶级跃升的方式,所以很多机构利用这一点大肆夸张宣传,所以各位,要擦亮双眼哦~

    60%刷题:

    公考的本质就是一个熟练度问题,刷题就是不断提高熟练度的过程,可以说刷题,是最直接有效的方法,没有之一,充分调动自身的主观能动性去实践,每做一道题相当于进行一次知识梳理,只会越来越熟练,越来越得心应手。

    就像“你只管努力,剩下的交给天意”,“不要假装很努力,结果不会陪你演戏”,这种地摊鸡汤文写的一样。

    “你只管刷题,剩下的交给快递,把入职通知书寄回到你家里,打开写着恭喜录取大吉大利,peace~”

    强调一点,刷题一定要用真题,真题是最有指导意义的,可以熟悉命题规律和趋势。

    10%运气:

    我们都知道,行测考试时间为 120 分钟,省考一般为 120 道题,国考为 135道题,再除去涂卡时间,平均不到 50 秒钟一道题,考试的时候没有人可以全部认真思考并作答完毕!

    因此,到最后势必会有不会做的,或者来不及做的题目,这个时候肯定不能空着不选吧,就是蒙也要选上,这个对于99%的考生来说,基本就是靠运气了,蒙的都对,那就是运气爆表,蒙的都错,也无能为力。

    如何人为控制正确率,提高这最后一部分题目的正确率,可以看下这篇文章

    ok,关于课程+刷题+运气,就说到这里,从宏观上做了一个扼要说明,那接下来不废话,开始正文,上备考干货。

    行测我们按模块来,申论整体进行。

    一、常识模块

    这个小模块,好像很多同学认为是举足轻重的,尤其是当做过真题或者模拟题被“毒打”以后,感觉自己的公考之路马上要断送了,急需抢救一下,因为经常有同学问我,大老师,常识怎么复习,正确率好低呀。。。

    怎么复习?不用复习,别在这浪费时间。

    常识判断,说白了它是考察你这二十多年的一个积累,从小到大你的学习、见闻、经验、以及涉猎的其他知识,短时间的备考无法发生质的改变。

    备考这个模块,只需利用碎片时间进行积累,等人的时间、睡觉之前、刷题休息的间隙。。。总之,不要占用正规学习时间,投入产出比太低,把有限的备考时间,用到其他能提升分数的模块上。

    二、言语理解

    常见的题型有:阅读理解、逻辑填空、语句表达

    主要考察考生运用语言文字进行思考和交流、迅速准确地理解和把握文字材料内涵的能力。

    这个模块与公务员工作联系还是比较紧密的,上级单位发的会议精神,领导要求你写的稿子,都需要快速、准确领会意图,并用文字精准的表达出来。

    备考时,以刷题为主进行倒推,看自己哪种题型正确率偏低就着重学习哪类题型的课程,再回头进行有针对性的加强,这样一个学习思路,可以又快又准的完成此模块的备考。

    当然,逻辑填空里的词语、成语辨析,也需要积累,学习方式同常识模块一样,利用碎片时间进行即可。

    三、判断推理

    由逻辑判断、图形推理、定义判断、类比推理,四个小模块组成,两推理+两判断,主要考察逻辑思维能力。

    这个模块很多题目都是有固定公式,解题的时候千万不要当成言语理解去做,严格按照逻辑进行推演。

    刷题之前的基础课程,务必要学扎实了,这是解题的“密钥”,很多逻辑推理规则是固定不变的,学会以后才有能去做题,不要本末倒置。

    四、数资模块

    数量关系+资料分析,这两个模块是行测高分的分水岭,换句话说,行测要

    得高分,和其他考生拉开分差,这两个模块的正确率必须保证!

    这两个模块放到一起,有相同之处又有各自的特点。

    共同点:非常明显,对数学计算能力都有一定要求。

    不同点:数量关系,都是各自独立的题型,例如,工程问题、抽屉原理、排列组合、年龄问题等等,每种题型之间并无关联,只要掌握某种题型,就可以做到“会一道,对一片”的效果,备考时不要过早打退堂鼓,数量关系来来回回就这么十多种题型,每种学完,花不了多少时间精力,剩下交给刷题,提高熟练度即可。

    资料分析,是一个整体,通过一段材料或者表格数据,进行整体分析计算,其中会涉及到如何快速阅读、快速估算、定性分析,技巧性比较强

    五、申论

    写的好不如抄的好,不要过度发挥,忠于原材料,紧扣主旨。

    小学都做过阅读理解题吧,其中就有一道题叫做概括段落大意,其实申论要得高分,道理一样,把它当成一篇大型的概括段落大意题,紧紧围绕主旨,再适当的地方加上你储备的一些金句。

    再说下阅卷规则与注意的事项

    申论都是网上阅卷,阅卷老师分成几个组,每组只阅一道题,而且只能在屏幕上看到这一道题,如果你写到格子外头去了,阅卷老师就看不到了。

    80%以上的老师根本都没有看过申论试题和给出的材料,只需要记住答案要点就可以上阵了。每组都有组长。大家首先进行试评。一人20份卷子,评过之后统计时间和分数分布区间,每道题根据分值的不同划定出一个误差区间。

    正常情况下,一道题会有两个老师阅卷,他们给出的分数可能有高有低,如果分数差在误差区间内,那就取两者的平均值为该题的分数;如果分数差超过了误差区间,那就要组长进行三评,并以组长给出的分数为准。

    电脑会自动统计出该组的三评率,如果三评率超出了规定范围,则证明这个阅卷组对于阅卷没有达成共识,对不起,前面所有的工作白费,重新停下来,大家统一规则,然后重新试评20份,误差率合格了,再重新阅卷。

    想想吧,如果因为你个人的原因,分数误差大了导致全组停工试评从头再来,那是多大的罪过啊!所以,阅卷老师们都会心照不宣的在中间分和安全分上徘徊,以免出现招人白眼的状况。

    枪打出头鸟,每个老师所有给出的分数都是在电脑终端有统计的,如果给出的分数太高,或者高分太多,或者中间分数太少,那巡视员就会把这个老师叫到电脑终端屏幕前,让他看分数曲线,然后温和的说一句,要不然,你们组再试评一下?为了集体荣誉,绝对不能重来啊!所以,大家都会努力的向中间分靠拢。

    那什么是中间分和安全分,举个例子,一道20分的题目,可能你觉得自己应该怎么也能打个14分吧,哈哈,错啦!一道20分的题目,中间分是10分,标准误差是3分,也就是说,万一一个老师给该题打了10分,那你作为另一个阅卷老师,最高打到13分,最低打到7分。

    但是,万一你觉得挺好的文章,另一个老师只给八九9分,你打13分就超了啊!所以,保险一点,打个11分总不会错,就算另一个老师觉得该题答得不好,也不至于给到7分以下或者14分以上了吧。

    这就是一个阅卷博弈,经过这样一番博弈,大家的默契就是:一般的,给8-9分;还不错的,9-10分;不怎样的,7-8分;非常差的,6-7分;非常好的,10-11分。打到6分以下的低分或者13分以上的高分都是冒着生命危险的,很难很难。这就是为什么很多人觉得自己答得不错但是100分的申论才只得了四五十分的原因。

    申论的第一二道题是得分的关键。

    这是因为,客观的点好找,容易达成共识,老师们数着采分点给分,一般差距不大,分数得的也理直气壮;

    最可怕的是主观性的阅卷分数,太没谱了,老师就是觉得文章写得好,也不敢给高分。所以,临考不到一个月,努力抓好前两道题,练习找准采分点,比使劲练大文章要有用得多。

    那什么是采分点呢?说起来也挺荒唐的。阅卷组拿到申论答案以后,会根据题目分值将答案进行分配。

    比如说15年国考申论第一道题吧,20分由结构分2分,采分点16分(八个点),主观分2分构成,大概是只要能答出“文段说了两件事情”,有个“两件、二层”之类的字样,就能得到结构分2分,用了分号但是没写“两”,就没这2分;

    然后“粮食安全”“民生”各两分;再有什么就已经记不得了。反正,其实批卷子到后来,已经麻木到连自己都记不得答案和完整的采分点是什么了。就是给个中间分安全分,字好一点的看着顺眼一点,有几个点的,就给个9分,字差一点或者采分点少一点的,就7、8分,保证不会出错,误差率也在可控范围,全组的阅卷率很容易通过。

    要是后面的大题就更虚了,不可能将好几十分都拆成一个个采分点,所以都是划档给分的,这就比前两道题靠采分点给分要模糊得多。

    一般来讲,还是给个中间分,50分的题目,给个23分-27分之间就可以了。

    阅卷时间的话,都是在电脑屏幕上阅卷,想象一下,每天从早上八点半开始盯着屏幕一字一字的看枯燥的重复内容,一直到晚上六点。除了上厕所和吃饭,基本没什么休息,脖子会酸屁股会麻胃里恶心眼睛会瞎掉,很辛苦的!

    所以大家都想快点结束战斗,第一是不要取消成绩重新试评,第二是单位时间尽量多批一点。而且组员之间和各个组之间也都有无声的较量,每个人的业绩量都是清晰可见的,你批得少,那就是赤裸裸的偷懒了,会遭人鄙视的。

    相对来说,新手阅卷时间都比较长,反复看反复找,还要斟酌给多少分,一道200字的题目可能要阅15-30秒,这样单位时间内阅卷量就会非常少,电脑终端那里显示你的工作量和单位效率都很可怜,经过一会儿的磨练,新手就会逐渐赶超老手,争取每道题五六秒的速度,甚至更快。

    400字的题目,阅卷大概是8到10秒。最可怕的是800到1000字的大文章,阅卷时间老手差不多12秒,新手也会在16秒左右结束战斗。也就是说你辛辛苦苦花两个小时写的东西,阅卷老师统共用不上30秒,已经决定了你的生死,这才是名副其实的秒杀!

    还有一点,为了便于规范统一,采分点大多数都是题目中已经给出的关键词或字眼,或者稍加改装整理。除了重要领导的重要讲话,一般的别的词汇是不太可能成为标准答案中的采分点的。

    所以,如何从材料中找出关键词关键字眼,然后把他们拼到答案中,是练习的关键。某些参考答案脱离材料天马行空的提对策,即使可行,也不会是采分点的。

    所以,申论备考,就一句话,忠于原材料,总结采分点。

    关于公考备考,其实没有多复杂,充分发挥主观能动性,反复去练习总结,上岸只是时间问题。加油了各位!

    ]]>
    + + + + + <p>公务员考试,如何上岸?</p> +<p>先说结论:通关上岸,课程占30%,刷题占60%,剩下10%交给运气。</p> +<p>30%课程:</p> +<p>很多考生总有这样一种执念,觉得xx机构的课程一定很厉害,学完基本就稳了,但就是有点贵,动辄几千上万。。还有点纠结值不值,其实 + + + + + +
    + + + 个人数据存储方案 + + https://liupj.top/2022/07/12/data-storage/ + 2022-07-12T00:00:00.000Z + 2023-12-22T03:02:26.239Z + + 前言

    事实证明,网盘服务提供商提供的并非安全的数据备份服务,而是一种公开的数据共享服务

    我在网盘中看到了无数人泄露的私密文件|知乎

    故数据存储/数据备份,不使用网盘

    另外,同步盘并不能承担备份的任务,因为任何本地的修改都会直接影响另一端,这哪还叫数据备份嘛。。

    如果你不得不使用网盘服务

    1. 你需要学会翻墙/科学上网
    2. 然后使用新西兰的一款网盘 => Mega,因为其会自动将用户上传的文件加密,然后才存储于其服务端,数据安全性相对较高

    如果你不得不从外网访问家庭内网

    就比如你身在公司,但是需要访问家中的电脑

    推荐 => ZeroTier

    其通过技术手段,允许用户构建类似于虚拟局域网的网络,任何加入用户自行创建的网络的主机均可相互通信

    个人数据存储方案

    考虑:数据安全性 & 服务稳定性 & 费用(包括存储费、流量费)

    当存储体剩余不到 20% 空间时,就需要扩容了

    • 需求一:自建图床

    • 需求二:个人工作环境配置文件的备份

      • 在 github 托管
    • 需求三:个人操作系统的备份

      • 一个 240GB 的移动固态硬盘就足够了(反正配置文件和重要数据都有备份,即使系统崩了,大不了重做)
      • 用 timeshift 维护一组线性的系统镜像
    • 需求四:其余数据的备份

      • 一份归档存 3 处(2 处于本地的两台 500GB linux 笔记本电脑上,1 处放阿里云的归档存储)
      • 归档只读

    Todo

    • 给备份融入版本控制系统

    (完)

    ]]>
    + + + + + <h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>事实证明,网盘服务提供商提供的并非安全的数据备份服务,而是一种公开的数据共享服务</p> +<p><a href="https://zhuan + + + + + +
    + + + 三阶魔方还原笔记 + + https://liupj.top/2022/07/10/mofang/ + 2022-07-10T00:00:00.000Z + 2023-12-22T03:02:26.239Z + +
  • 拼一朵白色的小花
  • 将白色小花变成白色十字
  • 还原第一层
  • 公式:上左下右

    1. 还原第二层,只需归位 4 个棱块

      从上层挑棱块并对好,然后:远离、公式、空档换手、公式

      若顶层无符合条件的棱块,则没有条件就创造条件

    2. 顶面拼黄十字,拐弯右下角,直线放平行

    公式:顺时针90,右手公式,逆时针90

    1. 还原顶面

    公式:下右、上右、下右右上

    先拼小鱼,然后鱼头对左上,做公式

    对于拼小鱼

    • 若少 2 点,则左后方一点黄,做公式
    • 若少 3 点,就是小鱼
    • 若少 4 点,后方无黄,做公式
    1. 对好角块

    一组一样的角块对着我们,然后让黄色面对我们

    公式:上右上,下180,下左上,下180;右180

    1. ok

    公式:下左下右,下右下左,上左,右180

    还原的侧面对着自己,做公式

    (完)

    ]]>
    + + + + + <ol> +<li>拼一朵白色的小花</li> +<li>将白色小花变成白色十字</li> +<li>还原第一层</li> +</ol> +<blockquote> +<p>公式:上左下右</p> +</blockquote> +<ol start="4"> +<li><p>还原第二层,只需归位 + + + + + +
    + +
    diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..be4833f --- /dev/null +++ b/contact.html @@ -0,0 +1,93 @@ + + + + + + + + + peijie's wiki + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +
    +

    +
    +
    +

    你好呀~

    +

    我是 lpj,一名遵纪守法的中国公民,家在河南的一个小县城

    +

    这个小站属性偏向私人,它历经风雨百折不挠地扛到了现在(surprise !)

    +

    我会在这里持续输出一些文字,保存自己的所见所思和所悟,希望自己不忘初心持续前进 !

    +

    2021 年夏天我从 neau 的 cs 专业毕业啦 !

    +

    目前我会在业余时间抱着初学者的心态学习计算机相关的基础知识,期望有朝一日成为魔法师般的野生 programmer !

    +

    如果你有任何问题想要与我取得联系,欢迎给我发邮件~

    +

    E-mail:lpj@liupj.top | 374453156@qq.com

    + +
    +
    + + +
    + + diff --git a/css/hbe.style.css b/css/hbe.style.css new file mode 100644 index 0000000..2935f20 --- /dev/null +++ b/css/hbe.style.css @@ -0,0 +1,749 @@ +.hbe, +.hbe:after, +.hbe:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.hbe-container{ + margin: 0 auto; + overflow: hidden; +} +.hbe-content { + text-align: center; + font-size: 150%; + padding: 1em 0; +} + +.hbe-input { + position: relative; + z-index: 1; + display: inline-block; + margin: 1em; + width: 80%; + min-width: 400px; + vertical-align: top; +} + +.hbe-input-field { + line-height: normal; + font-size: 100%; + margin: 0; + position: relative; + display: block; + float: right; + padding: 0.8em; + width: 60%; + border: none; + border-radius: 0; + background: #f0f0f0; + color: #aaa; + font-weight: 400; + font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif; + -webkit-appearance: none; /* for box shadows to show on iOS */ +} + +.hbe-input-field:focus { + outline: none; +} + +.hbe-input-label { + display: inline-block; + float: right; + padding: 0 1em; + width: 40%; + color: #696969; + font-weight: bold; + font-size: 70.25%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.hbe-input-label-content { + position: relative; + display: block; + padding: 1.6em 0; + width: 100%; +} + +.hbe-graphic { + position: absolute; + top: 0; + left: 0; + fill: none; +} + +/* hbe button in post page */ +.hbe-button { + width: 130px; + height: 40px; + background: linear-gradient(to bottom, #4eb5e5 0%,#389ed5 100%); /* W3C */ + border: none; + border-radius: 5px; + position: relative; + border-bottom: 4px solid #2b8bc6; + color: #fbfbfb; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + text-shadow: 1px 1px 1px rgba(0,0,0,.4); + font-size: 15px; + text-align: left; + text-indent: 5px; + box-shadow: 0px 3px 0px 0px rgba(0,0,0,.2); + cursor: pointer; + + display: block; + margin: 0 auto; + margin-bottom: 20px; +} + +.hbe-button:active { + box-shadow: 0px 2px 0px 0px rgba(0,0,0,.2); + top: 1px; +} + +.hbe-button:after { + content: ""; + width: 0; + height: 0; + display: block; + border-top: 20px solid #187dbc; + border-bottom: 20px solid #187dbc; + border-left: 16px solid transparent; + border-right: 20px solid #187dbc; + position: absolute; + opacity: 0.6; + right: 0; + top: 0; + border-radius: 0 5px 5px 0; +} +/* hbe button in post page */ + +/* default theme {{{ */ +.hbe-input-default { + overflow: hidden; +} + +.hbe-input-field-default { + width: 100%; + background: transparent; + padding: 0.5em; + margin-bottom: 2em; + color: #f9f7f6; + z-index: 100; + opacity: 0; +} + +.hbe-input-label-default { + width: 100%; + position: absolute; + text-align: left; + padding: 0.5em 0; + pointer-events: none; + font-size: 1em; +} + +.hbe-input-label-default::before, +.hbe-input-label-default::after { + content: ''; + position: absolute; + width: 100%; + left: 0; +} + +.hbe-input-label-default::before { + height: 100%; + background: #666666; + top: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + -webkit-transition: -webkit-transform 0.2s; + transition: transform 0.2s; +} + +.hbe-input-label-default::after { + height: 2px; + background: #666666; + top: 100%; + -webkit-transition: opacity 0.2s; + transition: opacity 0.2s; +} + +.hbe-input-label-content-default { + padding: 0; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s, color 0.2s; + transition: transform 0.2s, color 0.2s; +} + +.hbe-input-field-default:focus, +.hbe-input--filled .hbe-input-field-default { + opacity: 1; + -webkit-transition: opacity 0s 0.2s; + transition: opacity 0s 0.2s; +} + +.hbe-input-label-default::before, +.hbe-input-label-default::after, +.hbe-input-label-content-default, +.hbe-input-field-default:focus, +.hbe-input--filled .hbe-input-field-default { + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-default:focus + .hbe-input-label-default::before, +.hbe-input--filled .hbe-input-label-default::before { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-default:focus + .hbe-input-label-default::after, +.hbe-input--filled .hbe-input-label-default::after { + opacity: 0; +} + +.hbe-input-field-default:focus + .hbe-input-label-default .hbe-input-label-content-default, +.hbe-input--filled .hbe-input-label-default .hbe-input-label-content-default { + color: #555555; + -webkit-transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); + transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); +} +/* default theme }}} */ + +/* up theme {{{ */ +.hbe-input-up { + overflow: hidden; + padding-top: 2em; +} + +.hbe-input-field-up { + width: 100%; + background: transparent; + opacity: 0; + padding: 0.35em; + z-index: 100; + color: #837482; +} + +.hbe-input-label-up { + width: 100%; + bottom: 0; + position: absolute; + pointer-events: none; + text-align: left; + color: #8E9191; + padding: 0 0.5em; +} + +.hbe-input-label-up::before { + content: ''; + position: absolute; + width: 100%; + height: 4em; + top: 100%; + left: 0; + background: #fff; + border-top: 4px solid #9B9F9F; + -webkit-transform: translate3d(0, -3px, 0); + transform: translate3d(0, -3px, 0); + -webkit-transition: -webkit-transform 0.4s; + transition: transform 0.4s; + -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); + transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); +} + +.hbe-input-label-content-up { + padding: 0.5em 0; + -webkit-transform-origin: 0% 100%; + transform-origin: 0% 100%; + -webkit-transition: -webkit-transform 0.4s, color 0.4s; + transition: transform 0.4s, color 0.4s; + -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); + transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); +} + +.hbe-input-field-up:focus, +.input--filled .hbe-input-field-up { + cursor: text; + opacity: 1; + -webkit-transition: opacity 0s 0.4s; + transition: opacity 0s 0.4s; +} + +.hbe-input-field-up:focus + .hbe-input-label-up::before, +.input--filled .hbe-input-label-up::before { + -webkit-transition-delay: 0.05s; + transition-delay: 0.05s; + -webkit-transform: translate3d(0, -3.3em, 0); + transform: translate3d(0, -3.3em, 0); +} + +.hbe-input-field-up:focus + .hbe-input-label-up .hbe-input-label-content-up, +.input--filled .hbe-input-label-content-up { + color: #6B6E6E; + -webkit-transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); + transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); +} +/* up theme }}} */ + +/* wave theme {{{ */ +.hbe-input-wave { + overflow: hidden; + padding-top: 1em; +} + +.hbe-input-field-wave { + padding: 0.5em 0em 0.25em; + width: 100%; + background: transparent; + color: #9da8b2; + font-size: 1.25em; +} + +.hbe-input-label-wave { + position: absolute; + top: 0.95em; + font-size: 0.85em; + left: 0; + display: block; + width: 100%; + text-align: left; + padding: 0em; + pointer-events: none; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s 0.15s, color 1s; + transition: transform 0.2s 0.15s, color 1s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.hbe-graphic-wave { + stroke: #92989e; + pointer-events: none; + -webkit-transition: -webkit-transform 0.7s, stroke 0.7s; + transition: transform 0.7s, stroke 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-wave:focus + .hbe-input-label-wave, +.input--filled .hbe-input-label-wave { + color: #333; + -webkit-transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1); + transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1); +} + +.hbe-input-field-wave:focus ~ .hbe-graphic-wave, +.input--filled .graphic-wave { + stroke: #333; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* wave theme }}} */ + +/* flip theme {{{ */ +.hbe-input-field-flip { + width: 100%; + background-color: #d0d1d0; + border: 2px solid transparent; + -webkit-transition: background-color 0.25s, border-color 0.25s; + transition: background-color 0.25s, border-color 0.25s; +} + +.hbe-input-label-flip { + width: 100%; + text-align: left; + position: absolute; + bottom: 100%; + pointer-events: none; + overflow: hidden; + padding: 0 1.25em; + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + -webkit-transition: -webkit-transform 0.25s; + transition: transform 0.25s ; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.hbe-input-label-content-flip { + color: #8B8C8B; + padding: 0.25em 0; + -webkit-transition: -webkit-transform 0.25s; + transition: transform 0.25s; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.hbe-input-label-content-flip::after { + content: attr(data-content); + position: absolute; + font-weight: 800; + bottom: 100%; + left: 0; + height: 100%; + width: 100%; + color: #666666; + padding: 0.25em 0; + letter-spacing: 1px; + font-size: 1em; +} + +.hbe-input-field-flip:focus + .hbe-input-label-flip, +.input--filled .hbe-input-label-flip { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-flip:focus + .hbe-input-label-flip .hbe-input-label-content-flip, +.input--filled .hbe-input-label-content-flip { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} + +.hbe-input-field-flip:focus + .hbe-input-field-flip, +.input--filled .hbe-input-field-flip { + background-color: transparent; + border-color: #666666; +} +/* flip theme }}} */ + +/* xray theme {{{ */ +.hbe-input-xray { + overflow: hidden; + padding-bottom: 2.5em; +} + +.hbe-input-field-xray { + padding: 0; + margin-top: 1.2em; + width: 100%; + background: transparent; + color: #84AF9B ; + font-size: 1.55em; +} + +.hbe-input-label-xray { + position: absolute; + top: 2em; + left: 0; + display: block; + width: 100%; + text-align: left; + padding: 0em; + letter-spacing: 1px; + color: #84AF9B ; + pointer-events: none; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s 0.1s, color 0.3s; + transition: transform 0.2s 0.1s, color 0.3s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.hbe-graphic-xray { + stroke: #84AF9B ; + pointer-events: none; + stroke-width: 2px; + top: 1.25em; + bottom: 0px; + height: 3.275em; + -webkit-transition: -webkit-transform 0.7s, stroke 0.7s; + transition: transform 0.7s, stroke 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-xray:focus + .hbe-input-label-xray, +.input--filled .hbe-input-label-xray { + color: #84AF9B ; + -webkit-transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1); + transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1); +} + +.hbe-input-field-xray:focus ~ .hbe-graphic-xray, +.input--filled .graphic-xray { + stroke: #84AF9B ; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* xray theme }}} */ + +/* blink theme {{{ */ +.hbe-input-blink { + padding-top: 1em; +} + +.hbe-input-field-blink { + width: 100%; + padding: 0.8em 0.5em; + background: transparent; + border: 2px solid; + color: #8781bd; + -webkit-transition: border-color 0.25s; + transition: border-color 0.25s; +} + +.hbe-input-label-blink { + width: 100%; + position: absolute; + top: 0; + text-align: left; + overflow: hidden; + padding: 0; + pointer-events: none; + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); +} + +.hbe-input-label-content-blink { + padding: 0 1em; + font-weight: 400; + color: #b5b5b5; +} + +.hbe-input-label-content-blink::after { + content: attr(data-content); + position: absolute; + top: -200%; + left: 0; + color: #8781bd ; + font-weight: 800; +} + +.hbe-input-field-blink:focus, +.input--filled .hbe-input-field-blink { + border-color: #8781bd ; +} + +.hbe-input-field-blink:focus + .hbe-input-label-blink, +.input--filled .hbe-input-label-blink { + -webkit-animation: anim-blink-1 0.25s forwards; + animation: anim-blink-1 0.25s forwards; +} + +.hbe-input-field-blink:focus + .hbe-input-label-blink .hbe-input-label-content-blink, +.input--filled .hbe-input-label-content-blink { + -webkit-animation: anim-blink-2 0.25s forwards ease-in; + animation: anim-blink-2 0.25s forwards ease-in; +} + +@-webkit-keyframes anim-blink-1 { + 0%, 70% { + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + } + 71%, 100% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes anim-blink-2 { + 0% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 70%, 71% { + -webkit-transform: translate3d(0, 125%, 0); + transform: translate3d(0, 125%, 0); + opacity: 0; + -webkit-animation-timing-function: ease-out; + } + 100% { + color: transparent; + -webkit-transform: translate3d(0, 200%, 0); + transform: translate3d(0, 200%, 0); + } +} + +@keyframes anim-blink-1 { + 0%, 70% { + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + } + 71%, 100% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes anim-blink-2 { + 0% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 70%, 71% { + -webkit-transform: translate3d(0, 125%, 0); + transform: translate3d(0, 125%, 0); + opacity: 0; + -webkit-animation-timing-function: ease-out; + } + 100% { + color: transparent; + -webkit-transform: translate3d(0, 200%, 0); + transform: translate3d(0, 200%, 0); + } +} +/* blink theme }}} */ + +/* surge theme {{{ */ +.hbe-input-surge { + overflow: hidden; + padding-bottom: 1em; +} + +.hbe-input-field-surge { + padding: 0.25em 0.5em; + margin-top: 1.25em; + width: 100%; + background: transparent; + color: #D0D0D0; + font-size: 1.55em; + opacity: 0; +} + +.hbe-input-label-surge { + width: 100%; + text-align: left; + position: absolute; + top: 1em; + pointer-events: none; + overflow: hidden; + padding: 0 0.25em; + -webkit-transform: translate3d(1em, 2.75em, 0); + transform: translate3d(1em, 2.75em, 0); + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; +} + +.hbe-input-label-content-surge { + color: #A4A5A6; + padding: 0.4em 0 0.25em; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; +} + +.hbe-input-label-content-surge::after { + content: attr(data-content); + position: absolute; + font-weight: 800; + top: 100%; + left: 0; + height: 100%; + width: 100%; + color: #2C3E50; + padding: 0.25em 0; + letter-spacing: 1px; + font-size: 0.85em; +} + +.hbe-graphic-surge { + fill: #2C3E50; + pointer-events: none; + top: 1em; + bottom: 0px; + height: 4.5em; + z-index: -1; + -webkit-transition: -webkit-transform 0.7s, fill 0.7s; + transition: transform 0.7s, fill 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-surge:focus, +.input--filled .hbe-input-field-surge { + -webkit-transition: opacity 0s 0.35s; + transition: opacity 0s 0.35s; + opacity: 1; +} + +.hbe-input-field-surge:focus + .hbe-input-label-surge, +.input--filled .hbe-input-label-surge { + -webkit-transition-delay: 0.15s; + transition-delay: 0.15s; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-surge:focus + .hbe-input-label-surge .hbe-input-label-content-surge, +.input--filled .hbe-input-label-content-surge { + -webkit-transition-delay: 0.15s; + transition-delay: 0.15s; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} + +.hbe-input-field-surge:focus ~ .hbe-graphic-surge, +.input--filled .graphic-surge { + fill: #2C3E50; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* surge theme }}} */ + +/* shrink theme {{{ */ +.hbe-input-field-shrink { + width: 100%; + background: transparent; + padding: 0.5em 0; + margin-bottom: 2em; + color: #2C3E50; +} + +.hbe-input-label-shrink { + width: 100%; + position: absolute; + text-align: left; + font-size: 1em; + padding: 10px 0 5px; + pointer-events: none; +} + +.hbe-input-label-shrink::after { + content: ''; + position: absolute; + width: 100%; + height: 7px; + background: #B7C3AC; + left: 0; + top: 100%; + -webkit-transform-origin: 50% 100%; + transform-origin: 50% 100%; + -webkit-transition: -webkit-transform 0.3s, background-color 0.3s; + transition: transform 0.3s, background-color 0.3s; +} + +.hbe-input-label-content-shrink { + padding: 0; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.3s, color 0.3s; + transition: transform 0.3s, color 0.3s; +} + +.hbe-input-field-shrink:focus + .hbe-input-label-shrink::after, +.input--filled .hbe-input-label-shrink::after { + background: #84AF9B; + -webkit-transform: scale3d(1, 0.25, 1); + transform: scale3d(1, 0.25, 1); +} + +.hbe-input-field-shrink:focus + .hbe-input-label-shrink .hbe-input-label-content-shrink, +.input--filled .hbe-input-label-shrink .hbe-input-label-content-shrink { + color: #84AF9B; + -webkit-transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1); + transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1); +} +/* shrink theme }}} */ diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..20dec6d --- /dev/null +++ b/css/style.css @@ -0,0 +1,315 @@ +body { + margin: 0; +} +html, +body, +.container { + height: 100%; + font-family: Hiragino Sans GB, Microsoft YaHei, WenQuanYi, Airal, sans-serif; + color: #444; +} +.container { + max-width: 840px; + margin: 0 auto; +} +a { + color: #00f; + text-decoration: none; +} +.home { + display: table; + width: 100%; + height: 100%; +} +.home .info { + display: table-cell; + vertical-align: middle; + text-align: center; +} +.home .info .logo { + font-size: 2.5em; + font-weight: bold; +} +.home .info .subtitle { + font-size: 14px; + color: #808080; +} +.home .info .sns { + margin: 1em auto; +} +.home .info .sns a { + width: 55px; + color: #999; + display: inline-block; +} +.home .info .sns a:hover { + color: #000; +} +.home .info footer { + border: 0; + color: #000; + padding: 0; +} +.page { + margin: 0 20px; + margin-bottom: 2em; +} +.page p { + line-height: 1.5em; +} +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Tomorrow Comment */ +.highlight .comment, +.highlight .quote { + color: #8e908c; +} +/* Tomorrow Red */ +.highlight .variable, +.highlight .template-variable, +.highlight .tag, +.highlight .name, +.highlight .selector-id, +.highlight .selector-class, +.highlight .regexp, +.highlight .deletion { + color: #c82829; +} +/* Tomorrow Orange */ +.highlight .number, +.highlight .built_in, +.highlight .builtin-name, +.highlight .literal, +.highlight .type, +.highlight .params, +.highlight .meta, +.highlight .link { + color: #f5871f; +} +/* Tomorrow Yellow */ +.highlight .attribute { + color: #eab700; +} +/* Tomorrow Green */ +.highlight .string, +.highlight .symbol, +.highlight .bullet, +.highlight .addition { + color: #718c00; +} +/* Tomorrow Blue */ +.highlight .title, +.highlight .section { + color: #4271ae; +} +/* Tomorrow Purple */ +.highlight .keyword, +.highlight .selector-tag { + color: #8959a8; +} +.highlight { + display: block; + overflow-x: auto; + background: #fff; + color: #4d4d4c; + padding: 0.5em; +} +.highlight .emphasis { + font-style: italic; +} +.highlight .strong { + font-weight: bold; +} +.header { + margin-bottom: 2em; + padding: 0 20px; +} +.header .blog-title { + font-size: 2.5em; + text-align: center; + padding-top: 0.5em; +} +.header .subtitle { + font-size: 14px; + color: #808080; +} +.header .menu { + margin: 0; + padding: 0; + border-top: 1px solid transparent; + margin-top: 20px; +} +.header .menu .menu-item { + margin: 0 15px 0 0; + padding: 3px 0 3px 0; + float: left; + display: inline-block; +} +.header .menu .menu-item-link { + color: #999; +} +.header .menu .menu-item-link:hover { + color: #000; +} +.post { + padding: 0 20px; + margin-bottom: 1.5em; +} +.post img { + max-width: 100%; +} +.post table { + border-collapse: collapse; + border-spacing: 0; +} +.post table td, +.post table th { + padding: 6px 13px; + border: 1px solid #dfe2e5; +} +.post hr { + margin: 1.5em 0; +} +.post .post-content { + text-align: justify; +} +.post .post-content a { + border-bottom: 1px dotted; +} +.post .post-content a:hover { + border-bottom: 1px solid; +} +.post .post-content ul, +.post .post-content ol { + text-align: left; +} +.post .post-content ul li, +.post .post-content ol li { + padding: 5px; + line-height: 1.5em; +} +.post figure { + margin: 0; +} +.post figure table { + width: 100%; +} +.post figure table .code { + border: 0; + padding: 0; +} +.post figure .gutter { + display: none; +} +.post blockquote { + margin: 0; + padding: 0 15px; + color: #777; + border-left: 4px solid #ddd; +} +.post pre { + font-family: initial; + margin: 0; + padding: 0.5em 1.5em; + overflow: auto; + font-size: 85%; + line-height: 1.8; + background-color: #f7f7f7; + border: 1px solid #ccc; +} +.post code { + background: #f7f7f7; + border: 1px solid #d6d6d6; + font-family: inherit; + font-size: 90%; + margin: 5px; + padding: 0 5px; +} +.post p { + line-height: 1.5em; +} +.post .post-footer { + line-height: 1; + min-height: 1em; +} +.post .post-footer .top { + float: right; + color: #666; +} +.post .post-footer .top:hover { + color: #000; +} +.post .post-footer .post-tag-list { + display: inline-block; + padding: 0; + margin: 0 0 0.5em 0; + color: #999; +} +.post .post-footer .post-tag-list .post-tag-list-item { + display: inline-block; + margin: 0 1em 0 0; +} +.post .post-footer .post-tag-list .post-tag-list-item a { + font-size: 85%; +} +.post .post-footer .post-tag-list .post-tag-list-item:before { + content: '#'; +} +.article-title { + font-size: 1.5em; + line-height: 1.2em; +} +.archive { + padding: 0 20px; + margin-bottom: 1em; +} +.archive .post-archive { + list-style: none; + padding: 0; +} +.archive .post-archive .post-item { + margin: 6px 0; + line-height: 1.5; +} +.archive .post-archive .post-item .post-date { + float: right; +} +@media screen and (max-width: 425px) { + .archive .post-archive .post-item .post-date { + float: none; + margin-left: 0.5em; + font-size: 90%; + color: #999; + } +} +.archive .post-archive .post-item .post-title { + border-bottom: 1px dotted; +} +.archive .post-archive .post-item .post-title:hover { + border-bottom: 1px solid; +} +.page-nav { + padding: 0 20px; +} +.page-nav .prev, +.page-nav .page-number { + padding: 10px 20px 10px 0; +} +.page-nav .next { + float: right; +} +.page-nav a { + color: #777; +} +.page-nav a:hover { + color: #000; +} +footer { + margin: 0.5em 20px 0 20px; + border-top: 1px solid #ccc; + padding: 1em 0 1em 0; + font-size: 80%; + color: #888; +} +footer .author { + color: #000; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..a1845d1 --- /dev/null +++ b/index.html @@ -0,0 +1,170 @@ + + + + + + + + + peijie's wiki + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    + +
    + + + + + + + +
    + + diff --git a/lib/hbe.js b/lib/hbe.js new file mode 100644 index 0000000..bc024dc --- /dev/null +++ b/lib/hbe.js @@ -0,0 +1,293 @@ +(() => { + 'use strict'; + + const cryptoObj = window.crypto || window.msCrypto; + const storage = window.localStorage; + + const storageName = 'hexo-blog-encrypt:#' + window.location.pathname; + const keySalt = textToArray('hexo-blog-encrypt的作者们都是大帅比!'); + const ivSalt = textToArray('hexo-blog-encrypt是地表最强Hexo加密插件!'); + +// As we can't detect the wrong password with AES-CBC, +// so adding an empty div and check it when decrption. +const knownPrefix = ""; + + const mainElement = document.getElementById('hexo-blog-encrypt'); + const wrongPassMessage = mainElement.dataset['wpm']; + const wrongHashMessage = mainElement.dataset['whm']; + const dataElement = mainElement.getElementsByTagName('script')['hbeData']; + const encryptedData = dataElement.innerText; + const HmacDigist = dataElement.dataset['hmacdigest']; + + function hexToArray(s) { + return new Uint8Array(s.match(/[\da-f]{2}/gi).map((h => { + return parseInt(h, 16); + }))); + } + + function textToArray(s) { + var i = s.length; + var n = 0; + var ba = new Array() + + for (var j = 0; j < i;) { + var c = s.codePointAt(j); + if (c < 128) { + ba[n++] = c; + j++; + } else if ((c > 127) && (c < 2048)) { + ba[n++] = (c >> 6) | 192; + ba[n++] = (c & 63) | 128; + j++; + } else if ((c > 2047) && (c < 65536)) { + ba[n++] = (c >> 12) | 224; + ba[n++] = ((c >> 6) & 63) | 128; + ba[n++] = (c & 63) | 128; + j++; + } else { + ba[n++] = (c >> 18) | 240; + ba[n++] = ((c >> 12) & 63) | 128; + ba[n++] = ((c >> 6) & 63) | 128; + ba[n++] = (c & 63) | 128; + j += 2; + } + } + return new Uint8Array(ba); + } + + function arrayBufferToHex(arrayBuffer) { + if (typeof arrayBuffer !== 'object' || arrayBuffer === null || typeof arrayBuffer.byteLength !== 'number') { + throw new TypeError('Expected input to be an ArrayBuffer') + } + + var view = new Uint8Array(arrayBuffer) + var result = '' + var value + + for (var i = 0; i < view.length; i++) { + value = view[i].toString(16) + result += (value.length === 1 ? '0' + value : value) + } + + return result + } + + async function getExecutableScript(oldElem) { + let out = document.createElement('script'); + const attList = ['type', 'text', 'src', 'crossorigin', 'defer', 'referrerpolicy']; + attList.forEach((att) => { + if (oldElem[att]) + out[att] = oldElem[att]; + }) + + return out; + } + + async function convertHTMLToElement(content) { + let out = document.createElement('div'); + out.innerHTML = content; + out.querySelectorAll('script').forEach(async (elem) => { + elem.replaceWith(await getExecutableScript(elem)); + }); + + return out; + } + + function getKeyMaterial(password) { + let encoder = new TextEncoder(); + return cryptoObj.subtle.importKey( + 'raw', + encoder.encode(password), + { + 'name': 'PBKDF2', + }, + false, + [ + 'deriveKey', + 'deriveBits', + ] + ); + } + + function getHmacKey(keyMaterial) { + return cryptoObj.subtle.deriveKey({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': keySalt.buffer, + 'iterations': 1024 + }, keyMaterial, { + 'name': 'HMAC', + 'hash': 'SHA-256', + 'length': 256, + }, true, [ + 'verify', + ]); + } + + function getDecryptKey(keyMaterial) { + return cryptoObj.subtle.deriveKey({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': keySalt.buffer, + 'iterations': 1024, + }, keyMaterial, { + 'name': 'AES-CBC', + 'length': 256, + }, true, [ + 'decrypt', + ]); + } + + function getIv(keyMaterial) { + return cryptoObj.subtle.deriveBits({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': ivSalt.buffer, + 'iterations': 512, + }, keyMaterial, 16 * 8); + } + + async function verifyContent(key, content) { + const encoder = new TextEncoder(); + const encoded = encoder.encode(content); + + let signature = hexToArray(HmacDigist); + + const result = await cryptoObj.subtle.verify({ + 'name': 'HMAC', + 'hash': 'SHA-256', + }, key, signature, encoded); + console.log(`Verification result: ${result}`); + if (!result) { + alert(wrongHashMessage); + console.log(`${wrongHashMessage}, got `, signature, ` but proved wrong.`); + } + return result; + } + + async function decrypt(decryptKey, iv, hmacKey) { + let typedArray = hexToArray(encryptedData); + + const result = await cryptoObj.subtle.decrypt({ + 'name': 'AES-CBC', + 'iv': iv, + }, decryptKey, typedArray.buffer).then(async (result) => { + const decoder = new TextDecoder(); + const decoded = decoder.decode(result); + + // check the prefix, if not then we can sure here is wrong password. + if (!decoded.startsWith(knownPrefix)) { + throw "Decode successfully but not start with KnownPrefix."; + } + + const hideButton = document.createElement('button'); + hideButton.textContent = 'Encrypt again'; + hideButton.type = 'button'; + hideButton.classList.add("hbe-button"); + hideButton.addEventListener('click', () => { + window.localStorage.removeItem(storageName); + window.location.reload(); + }); + + document.getElementById('hexo-blog-encrypt').style.display = 'inline'; + document.getElementById('hexo-blog-encrypt').innerHTML = ''; + document.getElementById('hexo-blog-encrypt').appendChild(await convertHTMLToElement(decoded)); + document.getElementById('hexo-blog-encrypt').appendChild(hideButton); + + // support html5 lazyload functionality. + document.querySelectorAll('img').forEach((elem) => { + if (elem.getAttribute("data-src") && !elem.src) { + elem.src = elem.getAttribute('data-src'); + } + }); + + // support theme-next refresh + window.NexT && NexT.boot && typeof NexT.boot.refresh === 'function' && NexT.boot.refresh(); + + // TOC part + var tocDiv = document.getElementById("toc-div"); + if (tocDiv) { + tocDiv.style.display = 'inline'; + } + + var tocDivs = document.getElementsByClassName('toc-div-class'); + if (tocDivs && tocDivs.length > 0) { + for (var idx = 0; idx < tocDivs.length; idx++) { + tocDivs[idx].style.display = 'inline'; + } + } + + return await verifyContent(hmacKey, decoded); + }).catch((e) => { + alert(wrongPassMessage); + console.log(e); + return false; + }); + + return result; + + } + + function hbeLoader() { + + const oldStorageData = JSON.parse(storage.getItem(storageName)); + + if (oldStorageData) { + console.log(`Password got from localStorage(${storageName}): `, oldStorageData); + + const sIv = hexToArray(oldStorageData.iv).buffer; + const sDk = oldStorageData.dk; + const sHmk = oldStorageData.hmk; + + cryptoObj.subtle.importKey('jwk', sDk, { + 'name': 'AES-CBC', + 'length': 256, + }, true, [ + 'decrypt', + ]).then((dkCK) => { + cryptoObj.subtle.importKey('jwk', sHmk, { + 'name': 'HMAC', + 'hash': 'SHA-256', + 'length': 256, + }, true, [ + 'verify', + ]).then((hmkCK) => { + decrypt(dkCK, sIv, hmkCK).then((result) => { + if (!result) { + storage.removeItem(storageName); + } + }); + }); + }); + } + + mainElement.addEventListener('keydown', async (event) => { + if (event.isComposing || event.keyCode === 13) { + const password = document.getElementById('hbePass').value; + const keyMaterial = await getKeyMaterial(password); + const hmacKey = await getHmacKey(keyMaterial); + const decryptKey = await getDecryptKey(keyMaterial); + const iv = await getIv(keyMaterial); + + decrypt(decryptKey, iv, hmacKey).then((result) => { + console.log(`Decrypt result: ${result}`); + if (result) { + cryptoObj.subtle.exportKey('jwk', decryptKey).then((dk) => { + cryptoObj.subtle.exportKey('jwk', hmacKey).then((hmk) => { + const newStorageData = { + 'dk': dk, + 'iv': arrayBufferToHex(iv), + 'hmk': hmk, + }; + storage.setItem(storageName, JSON.stringify(newStorageData)); + }); + }); + } + }); + } + }); + } + + hbeLoader(); + +})(); diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 0000000..74cc8b8 --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,170 @@ + + + + + + + + + peijie's wiki + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    + +
    + + + + + + + +
    + + diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 0000000..58ab0fc --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,170 @@ + + + + + + + + + peijie's wiki + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    + +
    + + + + + + + +
    + + diff --git a/page/4/index.html b/page/4/index.html new file mode 100644 index 0000000..c24560a --- /dev/null +++ b/page/4/index.html @@ -0,0 +1,130 @@ + + + + + + + + + peijie's wiki + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    + +
    + + + + + + + +
    + + diff --git a/placeholder b/placeholder deleted file mode 100644 index e69de29..0000000