-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.json
1 lines (1 loc) · 207 KB
/
index.json
1
[{"categories":null,"contents":"在意气风发的时候容易展现锐气,在失魂落魄的时候容易多愁善感。我发现我不太喜欢各种容易存在比较的活动,特别是在我容易失败或落下风的活动中,也许是我害怕失败。但我现在还有一个想法,我想尽量避免比较,因为比较会带来输赢,赢多了让人自大,输多了容易影响心情,让人产生嫉妒、甚至让人抓狂。而相反地,避免比较能够减少这些不好的情感产生,让注意力回归到自己身上,专注于自己的进度和计划;而不是将目光放到别人身上,不停地比较,让自己焦虑。做好自己就很好了。\n面对比较心理:寻找平衡之道 研究生阶段的学术环境与本科时期有着显著的不同。在本科和之前的阶段,分数与排名构成了评价体系的核心,这种以分数和排名为中心的体系在无形之中塑造了一种竞争意识,所以这么多年下来形成的潜意识就是追赶,特别是排名上的追赶。\n然而,进入研究生阶段,研究方向的细化以及学术圈子的缩小,使得原本以排名为导向的竞争模式逐渐失效。我相信在这种体系下,我已经逐步构建了一套适合自身发展的模式,并尽可能地融入了有意义的内容。但是因为总体的评价体系发生了变化,所以使得这套自驱体系随之失效/崩溃。\n而由于这么多年的惯性,身处人数有限的研究小组,与同门进行比较的心理便容易滋生。特别是当同门进展迅速,而自身进度相对滞后时,压力与自我怀疑也随之而来。不得不承认,这种比较所带来的负面影响是不容忽视的。在之前的经历中,我一直奉行“合适才是最好的”和“宁做虎头不做凤尾”的原则,这样不仅巧妙地避开了困境,还能依靠环境建立驱动力。另一方面,这也表明容错率其实很高,只要不是太差,都有可能需要处理 underqualified 的问题,所以也总是要学会怎么处理这种情况,调整心态。\n前些日子,我在小红书上偶然看到一篇探讨内驱力的帖子,大意是“自驱力强的人关注自己的进步,而不是关注他人”。这句话点明了比较的弊端:过度关注他人,本质上是一种比较,而比较往往会导致负面情绪。每个人的学习节奏与进程不尽相同,有人擅长快速突破,也有人更适合稳扎稳打。倘若一味地将自身的不足与他人的长处相比,眼里就看的永远都是最好的别人们,看到是最差的自己,则很容易陷入自我否定的循环之中。所以更好的一个状态还是达到关注于 inner attention,尽管道理如此,但在实践中却难以完全避免比较。长久以来的竞争惯性使得人们习惯于关注周围人的动态,并试图从中获取信息与动力。\n这就产生了一个矛盾:比较一方面会引发焦虑与压力,另一方面却也能在一定程度上提供前进的动力。特别是对于那些在学习后期容易动力不足的人而言,彻底摒弃比较或许会导致松懈。那么,如何在研究生阶段找到一个平衡点呢?是彻底告别比较,专注于自身,还是适度保留比较,将其作为一种激励?这个问题,恐怕没有一个普适的答案,还是根据自身的实际情况进行摸索与调整,不断尝试,才能找到最适合自己的前进方式。虽然时间上可能也有压力,但是我觉得还是维持好的心态和心理健康比较重要。意识到问题的时候就已经迈出了解决问题的第一步。\n总之,研究生阶段的学习,不仅仅是知识的积累,更是一种心态的调整,是一种自我认知的提升。在这个过程中,不断地调整自己的心态,找到适合自己的学习方式,才能在这个阶段走得更远。(谢谢 GPT,这段结尾写得真好 😘)\n隐形的财富:成绩之外的能力与多元发展的力量 在传统的评价体系中,成绩往往被视为衡量个人能力的核心指标。然而,在成绩之外,还存在着许多隐形的财富——那些难以被量化却同样重要的能力。这些能力也参与构成了一个人的综合实力,并且我认为它们在很多时候至关重要。\n记得高中时期,我们曾做过一次职业优势测评(似乎是霍兰德职业兴趣测试)。测试结果表明,兴趣类型相近的人可以形成合力,在职业发展上更具优势。对于这个观点,我至今仍持保留态度。当一个人在职业方面表现突出时,往往锐气十足;而当他在职业上遭遇挫折时,如果没有其他兴趣作为精神的避风港,又缺乏良好的自我调节能力,那么他很可能更容易崩溃。相反,我认为分散的兴趣具有其独特的价值。比如,一个理工科背景的人如果拥有良好的审美,这在另一个维度上将构成巨大的优势,而这种优势是其他人难以轻易弥补的(例如,许多理工科学生甚至缺乏基本的美术素养,连排版都一塌糊涂)。此外,当遇到挫折时,多元的兴趣爱好可以提供有效的缓冲,帮助个体更快地调整状态,或者更好地承受持续的压力。当然,这也可能意味着在某些时候难以与他人找到共同话题,就像他们在热烈讨论着英雄联盟,而你却在思考平面设计和排版;他们随口哼唱着流行歌曲,而你却不知道刘德华是歌手还是演员(查了一下好像都是)。\n另一方面,即使身处逆境,也要注重经验的积累,并将所学所做进行有效的固化——建立属于自己的知识索引。这既方便自己日后学习、参考、整理和归类,也便于快速回顾和上手使用。让时间的投入更高效地转化为自身的资产和财富。\n从“一次做对”到“反复修正”:实践中的调整 运营管理里面通常强调一次就做对,认为这样最节省时间。学习了这个理论后,我也尽可能多地在工作和学习中去用,希望能提高效率。但是在实际的项目工作中,却往往存在一个多方不断“battle”,交换信息、来回修正的过程,有点类似德尔菲法。通过不断地改,最后才能得到一个多方比较认可的方案。这就和之前运营管理里面强调的 “一次做对” 的原则有些冲突。因为第一次做得再好,其实在后续的 “battle” 过程中还是免不了要改。所以这是一个会让人感到困惑和迷茫的地方。所以感觉读研的心态和本科大作业/考试一次就做好的这种心态就不太一样,因为项目涉及到多个人,而不再是自己一个人的工作,而且还包含多方面的不确定性。\n其实,不只是团队项目,我逐渐发现自己的事情也是这样。在现实中,越复杂的事情越难保证一次就能全做对,总是要改来改去。如果改得不多还好,一旦需要大改,那之前做得太认真也可能白费。所以,倒不如先粗略地做一下,把整体先跑起来,然后有时间再慢慢改。(如果实在没时间也就罢了,天好像也塌不下来。这点有待验证,但我目前相信是这样的 ✅)\n巴黎奥运会开幕式上,由于工作人员操作失误,奥运会旗帜被反挂\n因此,有必要重新考虑工作量、时间限制,重新决定内容的质量要求,而不是一味要求自己做到完美。\n","date":"2025-01-27T20:23:54+08:00","permalink":"https://www.zhhuu.top/posts/thoughts2024/","section":"posts","tags":["学习","生活"],"title":"杂谈:调整心态和怎么做"},{"categories":["Coding"],"contents":"梯度下降的过程 挑选一个初始值 $w_0$ 重复迭代参数 $w_{t+1}=w_t-\\eta \\frac {\\partial L(w_t)}{\\partial w_t}$,其中: $w_t$ 是第 t 次迭代的参数 $\\eta$ 是学习率 $\\frac {\\partial L(w_t)}{\\partial w_t}$ 是损失函数 $L(w)$ 对参数 $w$ 的梯度 沿梯度方向将增加损失函数值,因此需要取负梯度方向,即变化量为 $-\\eta \\frac {\\partial L(w_t)}{\\partial w_t}$ 学习率 $\\eta$:步长的超参数。\n示例 优化 x² 💡 以函数求极值的视角来看\n假设损失函数为 $L(w)=w^2$,则 $\\frac {\\partial L(w)}{\\partial w}=2w$。\n初始值 $w_0=5$ 学习率 $\\eta=0.2$ 迭代次数 5 次 求解 $w_5$ 这里还默认设置了一个停止条件,即当 $|w_{t+1}-w_t|\u0026lt;0.01$ 时认为已经收敛,停止迭代。\n1def gd(w, lr): 2 while abs(w - lr * 2 * w) \u0026gt; 0.01: 3 w = w - lr * 2 * w 4 print(w) 5 6gd(5, 0.2) # 初始值 5,学习率 0.2 13.0 21.7999999999999998 31.0799999999999998 40.6479999999999999 50.3887999999999999 60.23327999999999993 7... 80.0005077997833420796 90.0003046798700052478 100.00018280792200314866 110.0001096847532018892 y=ax+b 拟合 📄代码附件\n数据生成 我们首先生成数据 $y$,其公式为: $$ y = 3x + 1/2 + \\epsilon $$ 其中,$\\epsilon$ 是服从均值为 0,标准差为 0.01 的正态分布噪声。而真正要拟合的函数为 $y=3x+1/2$。\n1import numpy as np 2 3# 生成x 4x = np.random.rand(100, 1) 5 6# 生成y 7y = 3 * x + 0.5 + np.random.normal(0, 0.01, (100, 1)) 8y.shape 损失及其梯度 损失函数采用均方误差(即平方和损失/样本量): $$ loss = \\frac{1}{n}\\sum_{i=1}^{n}(y_i - (ax_i+b))^2 $$\n损失函数本身用不到,只是用到通过损失函数求各个输入参数的梯度(偏导集合)。\n这里使用的损失函数是 $(y-(ax+b))^2$,其对 $a$ 和 $b$ 的偏导数分别为:\n$$ \\left\\{ \\begin{aligned} \\frac{\\partial J^{(i)}(a, b)}{\\partial a} \u0026= 2 \\left( (a x^{(i)} + b) - y^{(i)} \\right) x^{(i)} \\\\ \\frac{\\partial J^{(i)}(a, b)}{\\partial b} \u0026= 2 \\left( (a x^{(i)} + b) - y^{(i)} \\right) \\end{aligned} \\right. $$ 1def loss_partial_a(x, y, a, b): 2 return 2 * (a * x + b - y) * x 3 4def loss_partial_b(x, y, a, b): 5 return 2 * (a * x + b - y) 梯度下降计算过程 1# 初始化w和b 2a = np.random.rand(1, 1) 3b = np.random.rand(1, 1) 4 5print(f\u0026#34;init a={a}, b={b}\u0026#34;) 6 7# 训练参数 8lr = 0.1 9epoch = 3 10 11# 训练 12for e in range(epoch): 13 14 # 这里是对于每个样本都计算一次,因此就不涉及平均损失的问题 15 for k in range(len(x)): 16 i = x[k] 17 j = y[k] 18 # print(f\u0026#34;i={i}, j={j}\u0026#34;) 19 new_a = a - lr * loss_partial_a(i, j, a, b) 20 new_b = b - lr * loss_partial_b(i, j, a, b) 21 22 a = new_a 23 b = new_b 24 print(f\u0026#34;epoch={e}, k={k}, a={a}, b={b}\u0026#34;) 迭代结果 1init a=[[0.23760839]], b=[[0.39863307]] 2epoch=0, k=0, a=[[0.24371687]], b=[[0.46798773]] 3epoch=0, k=1, a=[[0.29139251]], b=[[0.63393353]] 4epoch=0, k=2, a=[[0.4018126]], b=[[0.86619184]] 5epoch=0, k=3, a=[[0.41131305]], b=[[0.90869003]] 6epoch=0, k=4, a=[[0.41032642]], b=[[0.83265673]] 7epoch=0, k=5, a=[[0.42432716]], b=[[0.89015401]] 8epoch=0, k=6, a=[[0.42327588]], b=[[0.88220623]] 9epoch=0, k=7, a=[[0.4301685]], b=[[0.91442126]] 10epoch=0, k=8, a=[[0.42865997]], b=[[0.84015194]] 11epoch=0, k=9, a=[[0.85950176]], b=[[1.27968261]] 12epoch=0, k=10, a=[[0.87845307]], b=[[1.32033154]] 13epoch=0, k=11, a=[[0.86892602]], b=[[1.29000569]] 14epoch=0, k=12, a=[[0.85606747]], b=[[1.23699777]] 15epoch=0, k=13, a=[[0.86349238]], b=[[1.25637342]] 16epoch=0, k=14, a=[[0.85133071]], b=[[1.1580821]] 17epoch=0, k=15, a=[[0.84363037]], b=[[1.0603727]] 18epoch=0, k=16, a=[[0.83911272]], b=[[1.03934112]] 19epoch=0, k=17, a=[[0.89684411]], b=[[1.1534493]] 20epoch=0, k=18, a=[[0.89302841]], b=[[1.13958303]] 21epoch=0, k=19, a=[[1.14469504]], b=[[1.4059118]] 22epoch=0, k=20, a=[[1.12518344]], b=[[1.28439373]] 23epoch=0, k=21, a=[[1.18891208]], b=[[1.37951491]] 24epoch=0, k=22, a=[[1.22565315]], b=[[1.4368382]] 25epoch=0, k=23, a=[[1.24702493]], b=[[1.47058983]] 26... 27epoch=2, k=96, a=[[2.94969047]], b=[[0.51946884]] 28epoch=2, k=97, a=[[2.94882856]], b=[[0.5175241]] 29epoch=2, k=98, a=[[2.94872719]], b=[[0.51584921]] 30epoch=2, k=99, a=[[2.94936074]], b=[[0.51847969]] 注意,这里的每次迭代都理解为沿着梯度方向步进的过程。\n批量大小 y=ax+b 拟合的示例中,可以将梯度下降部分的代码改为以下代码,使其成为小批量梯度下降(Mini-batch Gradient Descent):\n1# 训练 2for e in range(epoch): 3 4 # mini-batch 5 for i in range(0, len(x), batch_size): 6 x_batch = x[i:i+batch_size] 7 y_batch = y[i:i+batch_size] 8 new_a = a - lr * np.average(loss_partial_a(x_batch, y_batch, a, b)) 9 new_b = b - lr * np.average(loss_partial_b(x_batch, y_batch, a, b)) 10 11 a, b = (new_a, new_b) 12 13 print(f\u0026#34;epoch={e}, a={a}, b={b}\u0026#34;) 训练批量(batch_size) 的大小会显著影响 学习速度,具体表现在以下几个方面:\n每次迭代的计算量 小批量(small batch)\n每次训练迭代时,使用较小的批量(例如 32 或 64)时,每次参数更新需要的计算量较少,因为每次更新的样本数较少。 这意味着每次更新后模型的反馈比较快,但每次更新的梯度估计较为嘈杂,导致训练过程中梯度的波动较大。 因为每个批次计算的梯度较为不稳定,虽然每次迭代快,但收敛可能需要更多的迭代周期(epochs)才能达到较好的解。 大批量(large batch)\n使用较大的批量(例如 128、256、甚至更大)时,每次训练迭代需要计算的数据量更多,因此每次更新的计算量较大,计算时间也会增加。 然而,大批量可以更稳定地估计梯度,因为它基于更多的样本进行计算,因此梯度波动较小,训练过程更平稳。 大批量训练可能在每个 epoch 内更新的次数较少,但每次更新都较为精准,因此在较少的迭代中就能收敛,学习过程更为稳定。 训练的收敛速度 小批量(small batch)\n小批量会导致 梯度更新的不稳定性,从而影响模型收敛的平稳性。由于每次计算的梯度是基于较少的样本,梯度估计会有更大的噪声,导致收敛过程可能较为震荡,需要更多的训练周期(epochs)来收敛。 然而,这种噪声也有可能帮助模型逃脱局部最小值,从而可能找到更优的解。 大批量(large batch)\n大批量训练通常会 减少梯度的波动,使得每次梯度更新更加精确,收敛过程更加稳定,通常可以在较少的迭代周期内收敛。 然而,如果批量过大,可能会导致训练变得过于保守,无法快速跳出局部最小值,可能错过一些更优的解。 硬件效率和计算加速 GPU/并行计算\n使用较大的批量大小通常会更好地利用 GPU 或 TPU 等硬件的并行计算能力。因为现代深度学习框架(如 TensorFlow、PyTorch)和硬件都优化了批量计算,较大的批量大小能够加速矩阵运算,提高计算效率。 较大的批量在硬件加速下每次迭代的计算时间会比较短,虽然每个批次的计算量更大,但每个 epoch 的训练时间往往更短。 内存使用\n大的批量大小会占用更多的内存,因此在内存有限的情况下可能无法使用过大的批量。 适当的批量大小可以有效地平衡计算效率与内存使用,避免内存溢出。 学习率(Learning Rate)和批量大小的关系 学习率调整:批量大小和学习率之间有一个相互关系,通常 批量越大,学习率越大,这是因为大批量计算的梯度更精确,允许模型在更新时使用较大的步长。小批量训练由于梯度噪声较大,通常需要较小的学习率以避免模型的参数更新过于剧烈。 大批量 + 高学习率:加速训练,通常能在较少的周期内收敛。 小批量 + 低学习率:能够帮助模型更细致地优化参数,防止过度震荡。 泛化能力 小批量训练:由于小批量的梯度估计包含更多噪声,它在某些情况下可以帮助模型 避免过拟合,从而具有更好的 泛化能力。这种噪声实际上可以作为一种 正则化 方法,有助于提高模型在未见数据上的表现。 大批量训练:大批量通常使得梯度计算更加准确,优化过程更稳定,但由于每次更新较为平滑,模型有时可能会 过拟合 训练集,导致泛化能力降低。 结论 小批量:每次训练更新快、计算效率高,但收敛过程可能不稳定,且需要更多的迭代周期才能达到理想的解。 大批量:计算更稳定,能更快收敛,但每次更新的计算量大,可能导致过拟合,需要调节学习率和批量大小的关系。 选择合适的批量大小需要根据实际情况来决定。通常,使用 中等大小的批量(如 64、128、256)能提供较好的计算效率与稳定性。在硬件资源允许的情况下,可以进行实验并调整批量大小和学习率,以找到最佳的训练速度和收敛效果。\n","date":"2024-12-09T11:42:28+08:00","permalink":"https://www.zhhuu.top/posts/gradient-descent/","section":"posts","tags":["优化","算法","编程","Python"],"title":"梯度下降"},{"categories":null,"contents":"缘由 旧主题来源于 2017 年的hexo-theme-material,但是作者很早已经停止维护。后来我自己修改了一些样式,虽然观感有点提升,但是还是有很多问题,比如我一直没有找到一个很好的文字排版显示样式,代码高亮、数学公式显示等等都多少有点问题。而且之前的网站维护经验不足,添加了一堆有的没的 CDN 外链,不知道什么时候就会失效,维护起来有点费力。所以我决定换一个新的主题,降低维护难度,把需要的资源和链接全部迁移到 GitHub Page 和 Cloudflare 上,顺便尝试一下 Hugo。\n旧主题样式 其实旧主题整体上还是很好看的,但是加载上也是莫名其妙有点慢\n新主题样式 换的另一个原因是在 Hugo theme 上逛了一圈好不容易看中了一个主题,pehtheme-hugo\n过程 hexo 换成 hugo 还是有一些区别,比如帖子格式得重新设置,图片存放位置等都要做相应调整,全部放到文章对应的文件夹下面等。费了一点力气,好在不多,顺便也删除了一些没有什么作用的历史文章,留下的要么感觉比较实用,要么留作纪念。\n换这个主题也是花费了一些时间的,主要是在我手上压了一段时间。一方面是最近比较忙,另一方面是时间主要花在调整主题功能上面了。用惯了 VuePress 后感觉这个主题功能缺失有点多,比如目录、评论、搜索、数学公式显示这些都没有,感觉比较塑料。\n但是这个主题的优点是简洁好看,和其他人的主题看上去也不太一样(比如经典的 Hexo Next 系列及其衍生主题,以及屏幕樱花乱飘、点击还会跳出来彩色字的那种),而且还是 Material Design 3 的设计,所以还是没有办法,选择了这个(我之前爆改 Hexo 主题也是因为有的地方看着不合适)。\n在迁移的过程中非常感谢自己之前抽空学了 Git 和 PowerShell 的一些基本操作,省下了很多“体力劳动”耗费的时间,如通过命令行批量将文件设置为指定格式,逐步记录对于新主题的修改。说明《计算机教育中缺失的一课》还是非常实用的(可以把 PowerShell 看成 Bash)。还有以前自己学的 TailwindCSS 在快速修改了主题的一些样式上也起到了一些作用,不过其实大多都还要归功于 ChatGPT,它确实是一个很好的帮手(工具人)。\n当然现在有的功能还是没来得及添加,比如评论,也不知道以后加不加,看情况吧。\n规划 其实最近不是很想动 Blog 这边了,感觉时间也不是很多,可以看到我 2022 年左右就已经断更了。一是感觉没有什么很特别的东西可以共享出来,一些碎碎念都放到伊龙马的平台上了;二是这段时间虽然也有在写,但是主要都放上 Obsidian 上面变成了自己的知识库,大多是课程笔记之类的东西(比如 6.0001、6.0002 之类的学习笔记),虽然比较实用,但是和网上太多重复感觉再放上来也没什么意义。\n不过具体也再看吧,也许以后有的 Obsidian 内容会想着放上来,作为某种知识的整理。\n","date":"2024-07-21T14:00:00Z","permalink":"https://www.zhhuu.top/posts/new-theme/","section":"posts","tags":["前端","feature"],"title":"启用新主题"},{"categories":["Skills","feature"],"contents":" 最后更新于 2025/2/2\n写这篇文章总结的想法很早就有了,但是一直没有动笔写,也不知道应该以什么形式写下来。也就是晚上 11 点有动力和灵感写一篇这样的文章,总结一下大学两年半使用电子产品(硬件和软件)进行学习和生活的状态。探索并梳理工作流的新鲜感让我觉得很爽,这样的折腾可能也是一直促进我学习的因素之一。\n而且像我这样买 Surface Pro 还用了那么久的人估计也不多,到了大学教室里面一个专业也很难见到一个用 Surface 的人,更别说我这种把它当平板用的了,就像当年 Windows Phone 的 1%🤣。因此,也顺便分享一下大学过程中随着 Windows Update 为 Windows 带来日新月异的体验(bug)后我使用 Surface 的感受。\n此外,学习过程中也积累了一些比较好用的软件 🤣 我的专业是物流工程,虽然后面介绍的软件有一部分可能是计算机相关专业同学比较熟悉的软件,但并不影响使用和享受其带来的便捷。所以,虽然介绍的方向可能偏工科专业,但是我认为其实也适合很多其他专业的同学。毕竟,在如今这个时代,什么都离不开电脑、手机和云计算。特别是上云这件事,有时候能减少很多麻烦。\n环境 下面我介绍一下我在大学前三年中使用的 EDC(硬件)和日常生活和学习中使用到的软件。\n硬件设备 按照购买时间排序:\n平板:Surface Pro 6,高三的时候买的。升级了 Windows 11,耗电多了、速度慢了,但是 Win11 的触控优化对于 Win10 是质的飞跃。升级了 Win11 以后,随着触控键盘可以缩小尺寸等针对平板的优化,能够脱离 Surface Type Cover 使用的场景变多了。虽然很多场景还是必须要键盘鼠标,但是对于看视频看资料写写画画之类的场景确实已经能够脱离 Type Cover 了。(不过现在已经刷回 Windows 10 了) 手机:小米 10,资本弃舰不多说。 电脑:ROG 幻 15,大一下学期买的,当时正好显卡荒,本子都被挖矿的抢走了,笔记本加价都不一定能买到,拯救者被抢疯了。当时 10999 抢到 R9+16G+1T+3060 还是很幸运的。 软件 高频使用的学习软件:\nOneNote:笔记软件,功能很丰富,我在电脑、平板、手机(以下简称“全平台”)上都有安装,方便各种场合使用。具体场景包括:考试前没带平板拿手机多看两眼笔记、在上高年级课程的时候老师突然提问高数概率论相关知识,迅速查找相关笔记。电脑上主要往上面记录打字类型的笔记、平板主要往上写、手机主要在没带平板或电脑的时候看,这样就全平台任意时候都能直接参考记录下来的笔记。电脑版 OneNote(非 OneNote for Windows10,是 Office 版本的 OneNote)可以将笔记保存到本地,方便进行备份,不用担心巨硬跑路。\nOffice 365 教育版:拿到学校邮箱以后立刻申请了 Office 365 教育版,拿一个 1TB 的 OneDrive 云空间,把 OneNote 笔记都记在教育版账户上。教育版账户(事实上仍然是海外服务器)实测下载文件能有 1Mb/s 或者更高的速度,不会出现网传的丢笔记,同步不上的问题。如果真的遇到问题点多几次同步或者关掉再打开就可以解决(在 OneNote for Windows10 上总说同步不上感觉像是显示的问题,写几下一会就显示同步上了),同步速度还可以,主要是比较稳定。\n滴答清单:一个待办清单软件,我同样全平台安装。主要用于生活中各种琐碎待办的记录,防止事情过多忘记做某些事情。我最喜欢的点在于全平台安装后,只要手头有设备就可以添加待办。如果设置了时间提醒弹出通知也特别及时 👍(特别是在 Windows 端)\n2025/2/2 Update:现已改用 Microsoft Todo,微软的 Office 相关软件还是有点东西的。Todo 和 Outlook 的整合也很好,可以直接在 Outlook 里面查看待办事项。iOS 平台的同学可以直接登录 Outlook 在内置的待办事项 App 中同步待办清单,获得更加原生的软件体验。当然滴答清单功能方面也做得很好。\n潮汐:白噪声软件。当室友特别吵而必须在宿舍进行学习的时候,带上降噪耳机、将白噪音声音开大,逐渐就能进入专注的状态。对于我来说,专注学习的最大障碍有时候会蹦出来很多想法,这个时候就可以结合待办清单软件将它们记录下来,等专注时间过了以后再实现。\nWindows 时钟:专注计时,和“潮汐”二选一使用即可。当环境不是特别嘈杂而阻碍专注的因素来自于自身的时候,可以将里面的专注时段打开并缩小悬挂于屏幕右上角,提醒自己处于专注时间以及剩余时长,合理安排时间。我一般在用 Surface 学习的时候将它挂在右上角。\n飞书妙记:会议记录软件。飞书妙记是飞书里面的一个应用。我身边几乎没有人用飞书,但是里面飞书妙记倒是挺好用的。我的用法就是网课录屏上传视频语音转文字。\n其他软件/学习软件推荐:\n墨墨背单词:背单词软件,只要坚持就有成效。(就是坚持最难 😭)\nVSCode:万能编辑器,对于我这种业余编辑的倒是不在乎它的大小,主要在乎它的各种编辑功能。利用快捷键实现多行编辑,免去编辑文本格式的重复性无意义劳动,也很快捷。还有,通过插件它能支持很多类型代码的高亮、格式化、Snippet 操作,对于轻度写代码也非常友好。具体可以看我博客里面的介绍 VSCode 多光标输入 | Hikaru\u0026rsquo;s Blog\nPhotomath/Geogebra:算高数的时候可以求方程、积分,算线性代数的时候可以算简单的矩阵。PhotoMath 有时候由于网络差可能进不去,可以改用 Geogebra。此外,Geogebra 支持的画图功能很强,也有网页版。但我还是比较习惯 PhotoMath。\nBTW,一定要好好学习计算器的使用,991 系列的计算器可以解决很多问题,比如说解方程、积分、矩阵运算(特别是求逆、矩阵乘法)等,在高数、线代、概率统计等课程(考试 🧐)中都能用到。\nPowerToys:Windows 上的工具箱,能够实现窗口置顶、屏幕常亮、快捷键静音禁摄像头等操作。如果电脑没有一键静音的快捷键,用这个也不错,至少不会在腾讯会议上社死。最近还推出了检测文件占用的功能,弹出 U 盘/硬盘的时候终于知道到底是谁在占用磁盘了 🤩\nOBS Studio:最专业的录屏软件之一,开源软件。\n学习工作流介绍 上面可能已经介绍了一些了,下面也许会有点重复,不过也会比较完整。大部分都是基于以上的硬件和软件实现的,可以看看有没有参考价值。\n课程和作业 老师发 PPT/作业 存到 OneDrive 上对应课程的文件夹中,以便多端同步文件版本。考虑到上课场景,通常是平板编辑(用笔标注 PPT/PDF),电脑偶尔也编辑一下。存到 OneDrive 上就实现了上云,在任何下载了 OneDrive 的设备上都能看。\n用 Word 写作业 建议直接在 OneDrive 上对应课程文件夹里面写。推荐 OneDrive 而不是别的云盘的原因是,OneDrive 有一个 “文件恢复”功能。如果有时候文件弄乱了,可以通过 OneDrive 恢复到之前的版本,这就相当于有一个免费的备份。同时,OneDrive是一个同步云盘,这意味着你可以在多态设备之间切换编辑同一个文档,而不用担心文件版本不一致。\n特别是如果你使用 Office 2021 及以上版本或 Office 365,Office 中的自动保存功能依赖于 OneDrive。开启此功能并将文件保存在 OneDrive 上时,编辑过程中的文件会自动保存版本,所以可以做到随时可以恢复\u0026amp;对比之前的版本,再也不怕电脑蓝屏作业文档没保存。\n我见过其他同学论文写到结尾了一直都没保存,然后电脑突然蓝屏文件全丢的情况,这会非常令人沮丧。如果使用了 Office 这套工作流,我认为丢文件是一个非常小概率的事件。剩下就是作业能不能写出来的问题了 🤣。\n上面说的申请教育版 Office 365 主要就是为了获取 100G OneDrive。上云的好处夸张一点来说,如果写文档的时候有联网同步,就算设备灭失了,只要给一台能上网的电脑就可以把文档取出来,甚至你可以在这台联网的电脑上通过 Office 在线版继续编写文档。\n如果是写程序,IDE 创建的项目不建议放到 OneDrive 上写,因为每次编译生成软件都会有文件变化,而这些文件的各个版本都会被 OneDrive 上传占用的存储空间。但是单个脚本文件的源代码还是可以放进去的,主要看个人习惯。\n网课录屏\u0026amp;转文字 如果是网课,这是最绝杀的复习手段。打开 OBS 录屏,建议码率控制在一个适当的范围内,便于备份和上传。因为网课一般都是老师播 PPT,所录课的码率一般不用很高也能看清楚。等有需要的时候或者期末把所有课程都上传到飞书妙记可以辅助复习。复习的时候如果有不懂的地方可以搜索录屏的语音转文本内容重播,比普通录屏回放的效率更高。\n线下上课可以打开手机录音代替,不过我觉得效果打折比较多,因为缺少对应位置的 PPT 以及老师上课的标记\n视频转文字是最有效的复习手段之一。上传到飞书妙记后,左边是视频右边是文字,可以直接点击文字跳到视频的对应位置。这样就不用看一整节课了,只需要看自己不懂的地方,还有对应位置的视频回放。这个功能对于我这种听课效率低的人来说是一个很好的补充。现在飞书有限额,如果你有显卡的话也可以使用 faster-whisper 生成字幕配合 potplayer 的字幕列表,效果差一点,但也还算能用。\n由于文本以二维排列,相比于视频/音频的线性播放,其非线性/更高一维度的阅读更适合快速查找信息。\n学习和记录 准备进入学习状态的时候,你可能需要一个 Appetizer/Starter 帮助你进入状态,先从简单的事情做起。\n嘈杂的环境学习 戴上降噪耳机,打开潮汐,设定一个合理的专注时长。先将白噪音音量调大直到盖过噪音尝试专注,当进入状态后可以适当减小白噪音音量。如果尝试专注 15 分钟后仍然无法专注,那你可能真的需要换一个环境学习。\n浮躁的状态学习 打开 Windows 计时器/潮汐,设定专注时间。如果在 Windows 上建议将计时移到窗口右上角。我感觉浮躁的状态下听或者不听音乐/白噪音会有很大的区别,每次的需求可能都不一样,当发现听音乐/白噪音无法让你进入状态时可以把音乐停掉试试。我认为最重要的是要注意休息。\n上课笔记 我一般直接用 Drawboard PDF 记在电子课本或者老师发的 PPT 上,回头整理。上课一般是来不及抄录太多课本上/PPT 上就有的内容,也没必要,用尽可能简单的标记追求记录效率即可。回头体系化整理的时候再补充细节可以更好地理解和增强记忆。\n整理笔记 因为我是用 Windows,所以我自然地用了 OneNote,好处在于 OneNote 的纸可以无限扩大,不用担心笔记的排版问题。需要补充的时候可以用自带的工具直接拉一片空间出来,或直接拉个箭头到别的地方继续补充;使用套索工具随时调整内容的位置,总体自由度很高。学数学的时候,可以充分利用里面的“数学”模块,它可以计算微积分、解方程、画图等,做练习的时候不确定的答案可以用它算一遍验证一下。\n并且,在本科学习阶段,你可以发现 OneNote 的目录结构和课程章节设置是非常贴合的。这种目录结构的设置可以帮助你更好地对应所学章节整理笔记,同时也会方便记忆。所以本科阶段我确实比较推荐使用 OneNote。\n这里吹一下 Surface Pen,设置好快捷键以后按一下后面的按钮可以截屏,直接用笔把 PPT 上的内容截下来,粘贴到 OneNote 上即可,非常方便。\n其他 保存 PPT 老师传到微信群里的文件不会一直在那里,微信并不可靠,总是在你需要那份文件的时候提醒你文件已过期。当老师每次发了什么 PPT 和作业,可以一股脑全部保存 OneDrive 上。别人问你要过期 PPT 的时候就可以积累一下人缘 🤣\n我一般每个学期结束的时候会将相关课程的文件夹移到 OneDrive 上的其他文件夹,在高年级或以后的某个时候它们可能会有用。\n找资料 Edge 的集锦挺好用的。看到什么相关主题的网页可以新建一个集锦保存,等不需要的时候又可以整个删掉。手机上我也装了 Edge,账号密码在国内都可以无缝同步,而且通过 Edge 网页可以发到指定设备上继续看,一打开那台设备上的 Edge 就会弹出提示框。\n建议大学期间逐渐积累一下浏览器的收藏夹。除了收藏夹,积累一下知识库似乎也是很必要的\n这个时代没有任何人比 AI 更加博学,因此需要学会有效积累和管理知识,做到知识的有效利用——方山厨子\n除了上面提到的做笔记是一种知识积累的方式,还有一些其他的管理软件可以帮助你积累知识。总的来说,我目前的记录途径有下面这些。可能和前面稍有重合,但主要还是希望做到全面。\n手写型笔记:用于记录思路、思维导图,公式推导等弱结构化内容。随时可以引出箭头补充内容,方便理解。(OneNote;iOS:GoodNotes、无边记) 文字型笔记:用于记录文字、代码、公式等,整理为结构化的内容,方便查找、复习。 OneNote:不适合代码,公式一般,容易导致字体格式混乱。 Obsidian:适合代码、公式,图片管理不太好,同步需要自己搭建。 Notion,可以试试,算是云笔记。但我没用过,和 Obsidian 二选一即可。 生活 南方同学/记忆力差的同学去澡堂洗澡建议 生活方面嘛,我高中也没住过校,突然就住校了,我一个南方人也没洗过澡堂,给没住过校的同学也带点经验 🤣\n在手机备忘录上建立一个洗澡物品清单,去洗澡前一项项确认,确保没有遗漏物品。原因在于:首先,如果宿舍和澡堂距离比较远,一来一回要的时间还是挺可观的;其次,对于南方同学来说,考你们一下:如果冬天你去澡堂洗澡,洗到一半发现没带毛巾你会怎么做?不管怎么样,澡堂有设置通风口,我只知道天气还是挺冷的 😂\n出门 摸一下口袋里有没有纸巾、饭卡、手机。手机里只要有 OneDrive 和 OneNote,就相当于带上了你所有的学习资料,随时随地只要有网都能看。\n其他吐槽 我用的这台 Surface Pro 6 什么都好,就是充电很令人难受。充电的时候触摸屏经常断触失灵,包括笔也是经常光标漂移,或者写不出字。这属于硬件缺陷,不知道后代版本有没有这个问题。满电状态下会好一点,但是毕竟还是充电的时候多。如果后代型号还有类似问题,我认为这是最劝退的点。由于我这台丐版 SP6 没有风扇,充电发热的时候会严重影响手写笔笔迹,造成掰手指可数的延迟\u0026hellip;但是后代版本好像都配备风扇了。\n小米 10 机器本身硬件还是很好的,但我觉得到现在就没有出过一个称心如意的 MIUI 版本,刷过很多版本最好的就是 12.5.6 和 12.0.11。现在解锁 Root 打算强行苟到毕业,云控逼我换机不可能的,要么就换别家的。\n大四已换 🍎,忍不了一点 🙃\n微软的软件总要在手机上登录,要么就要挂 Authenticator 的后台,增加耗电。\nAuthenticator 在 iOS 上特别好用,登录活动立刻推送通知。终于知道为什么微软给员工发 🍎😭\n","date":"2023-02-03T23:00:00Z","permalink":"https://www.zhhuu.top/posts/undergraduate-workflow/","section":"posts","tags":["学习","生活"],"title":"本科学习生活工作流"},{"categories":["Coding"],"contents":"物流信息管理课程MicroCity学习笔记\nLua的小特性:集合 虽然Lua里面把它自己的数组称作table,但是我认为这个数据结构更类似于Python的集合或者json,里面可以存储任何东西,不受结构约束。\n1collection = {{\u0026#34;a\u0026#34;, 1, 2}, \u0026#34;abc\u0026#34;, {2, 3}} 如果需要查询数组的长度,只需要在数组名前面添加#即可得到\n1list = {1, 2, 3, 4, 5} 2for i=1,#list do 3 print(list[i]) 4end Lua的数组(集合)下标从1开始,不同于C类语言的0\nMicroCity的内置函数 为什么要写这个?因为MicroCity自带的编辑器相比较于“现代”的编辑器来说还是不够好用(如VSCode等)。我已经遇到了很多同学自己无法解决,找我排除代码中存在的问题。而这些问题98%都是由于语法问题,如缺少关键字(如end、then等)。但是我用VSCode,Lua插件一般都会直接给我自动补全。就算有什么问题也会高亮,或者使用快捷键格式化代码的时候也能看出问题。\n我认为,相比于更加现代的编辑器,MicroCity自带的编辑器“ScriptEditor”由于语法问题的标示不明显、格式化代码功能缺失等使用便利性上的问题,特别是对于Lua语言不熟练的新手,造成代码编写的错误率更高。\n说明:也许其中提到的功能存在于内在编辑器中,但是我反正是没有找到。\n对于我个人来说,VSCode的操作快捷键和各种特性我已经很熟悉,所以我也更倾向于使用VSCode编写Lua语言的脚本。但是对于使用VSCode编写适用于MicroCity运行的Lua脚本(.mcs)而言,由于MicroCity内置了一些函数,无法在VSCode上高亮显示,因此需要特别整理出来方便日后使用。\n常用函数 这里的函数不是全集,只是我用了多少就写多少😂 全部图形函数及使用方法参见 MicroCity文档(英文) 4.3 Shapes And Tables\n在本页中浏览可以使用右上角的目录列表快速转到对应函数。\n图形 函数 作用 Open 打开图形文件,并获取图形文件对象 Update 刷新图形 Open Open(\u0026quot;路径\u0026quot;),返回图形文件对象。\n1countryObject = Open(\u0026#34;countries.shp\u0026#34;) Update Update([图形对象]),刷新图形对象,显示最新的图形。\n1Update(countryGRD) 矢量图 函数 作用 GetRecCount 获取图形文件中记录的图形对象个数 GetShape 从图形文件对象中获取图形对象 GetPartCount 获取对应图形对象分为多少个部分 GetPointCount 获取对应图形对象(部分)有多少个点 GetPointXY 获取图形对象指定部分、指定点编号的XY坐标 GetValue 获取图形对象的属性值 SetValue 设置图形对象的属性值 GetShapeLen 获取图形对象的长度 GetDistance 获取坐标点之间的距离 GetRecCount GetRecCount([图形文件对象]),返回图形文件中记录的图形对象个数。\n1countryNum = GetRecCount(countriesObject) GetShape GetShape([图形文件对象], [图形对象编号]),返回对应的图形对象。\n1China = GetShape(countries, 31) GetPartCount GetPartCount([图形对象]),返回对应图形对象有多少个部分。\n1part_num_of_China = GetPartCount(China) GetPointCount GetPointCount([图形对象(部分)], [图形部分编号]),返回此部分图形的点的总数。\n1point_num = GetPointCount(China, i) GetPointXY GetPointXY([图形对象], [图形部分点编号], [图形部分]),返回对应点的X坐标和Y坐标。形式为x,y\n1local x,y = GetPointXY(country, pointIndex, partIndex) GetValue GetaValue([图形对象], \u0026quot;属性名\u0026quot;),返回对应图形对象的属性值。\n1name = GetValue(country, \u0026#34;NAME\u0026#34;) SetValue 设置图形对象的属性值。也可以是对应图形表中的值。\n函数重载:\n1-- 对单个图形对象进行属性设置 2SetValue([图形对象], [设置值], \u0026#34;属性名\u0026#34;) 3SetValue([图形对象], [设置值1], \u0026#34;属性名1\u0026#34;, [设置值2], \u0026#34;属性值2\u0026#34;, ...) 4 5-- 设置图形文件对象中固定编号(index)对象的属性值(Shapes中包含有多个图形对象) 6SetValue (Shapes, [设置值], \u0026#34;属性名\u0026#34;, [index]) 7-- 也可以设置多个编号的同一个属性名为同一个值 8SetValue (Shapes, [设置值], \u0026#34;属性名\u0026#34;, [index1], [index2], ...) 使用实例\n1SetValue(shape, 0, \u0026#34;W\u0026#34;) --设置图形的W(表中)属性值为0 GetShapeLen 返回图形的长度\n函数重载:\n1GetShapeLen([图形]) 2GetShapeLen([图形1], [图形2], ...) 使用实例\n1local len = GetShapeLen(route) --获取线路(line形状)的长度 GetDistance 根据坐标值返回坐标点的长度。如果输入了多个坐标点,则返回每两对点之间的距离。(x1,y1), (x2,y2), (x3,y3)\n1GetDistance(x1, y1, x2, y2 [, x3, y3, ...]) 栅格图 函数 作用 ShapeToGrid 将矢量图转化为栅格图 GetGridMaxXY 返回栅格图形的最大X和Y坐标 GetValue 获取栅格图指定点的值 SetValue 设置栅格图指定点的值 ShapeToGrid ShapeToGrid([栅格图形对象], [矢量图形对象], \u0026quot;表属性名称\u0026quot;),将矢量图形转化为栅格图形,栅格图形中的点填充为表中属性对应值\n1ShapeToGrid(countryGridObject, countryShapeObject, \u0026#34;Population\u0026#34;) --矢量图形转化为栅格图形,填充值为表中的Population列对应值 GetGridMaxXY GetGridMaxXY([栅格图形对象]),返回栅格图形的XMax坐标和YMax坐标(最大坐标)。\n1local XMax, YMax = GetGridMaxXY(gridObject) GetValue GetValue([栅格图形对象], x, y),返回栅格图指定xy坐标点上的值\n1value = GetValue(gridObject, x, y) SetValue SetValue([栅格图形对象], [设置值], x, y),将栅格图形上指定xy坐标点的值更改为“设置值”。\n1SetValue(gridObject, 0, x, y) --将(x,y)点的值设为0 MicroCity文档和更多学习笔记已经整合到MicroCity笔记中,并在其中提供搜索功能。\n","date":"2022-09-23T16:20:36Z","permalink":"https://www.zhhuu.top/posts/lua-microcity/","section":"posts","tags":["Lua","编程","语法"],"title":"MicroCity内置的LUA函数"},{"categories":["Coding"],"contents":"算法设计,附源码\n概述 当涉及非线性规划问题或者难以在短时间内求得满意解的线性规划问题,可以通过求其近似解(或满意解)而非精确解。使用遗传算法求解近似解所消耗的时间远少于求解精确解,多数时候近似解的效果都可以接受。 遗传算法的优势体现在:在小规模问题上,遗传算法求解得到的通常是精确解;而在大规模问题上,遗传算法通常可以通过较短的时间求得精确解。 同样的问题通过遗传算法求解近似解和线性规划求解精确解,遗传算法花费的时间显著短于精确算法。\n算法 时长 结果(此处结果越小越好) 遗传算法 123s (2m03s) 371.06 精确算法 201s (3m21s) 367.07 模型描述 目标函数 $minf=P\\sum_{k=1}^K\\sum_{i=1}^N\\sum_{j=1}^Nx_{kij}d_{ij}+\\frac{P_a}{Q}\\sum_{i=1}^N\\sum_{j=1}^N(y_{ij}+z_{ij})x_{kij}d_{ij}+P_m\\sum_{k=1}^K\\sum_{i=1}^N\\sum_{j=M}^Nx_{kij}q_j$\n约束方程 $$ s.t.\\left\\{ \\begin{array}{**lr**} \\sum_{k=1}^K\\sum_{i=1}^Nx_{kij}=1 \u0026 j=2,3,...,N \\\\ \\sum_{j=1}^Nx_{kij} = \\sum_{j=1}^Nx_{kij} \u0026 i=1,2,...,N;k=1,2,...,K \\\\ \\sum_{j=1}^Nx_{k1j} \\le 1 \u0026 k=1,2,...,K \\\\ y_{ij}+z_{ij} \\le Q\\sum_{k=1}^Kx_{kij} \u0026 i,j=2,3,...,N \\\\ \\sum_{i=1}^N\\sum_{j=1}^Nx_{kij}d_{ij} \\leq D \u0026 k=1,2,...,K \\\\ \\sum_{j=1}^Nz_{ij}-\\sum_{j=1}^Nz_{ij}=p_i \u0026 i=2,3,...,N \\\\ \\sum_{i=1}^Nx_{kii}=0 \u0026 j=1,2,...,N \\\\ \\sum_{i=2}^N\\sum_{j=1}^Nx_{kij} \\le V \u0026 k=1,2,...,K \\\\ y_{ij} \\ge 0 ,z_{ij} \\ge 0 \u0026 i,j=1,2,...,N \\end{array} \\right. $$ 遗传算法设计 经过本次从0开始编写遗传算法求解模型,我将遗传算法划分为几个模块(步骤)\n初始可行解的生成 目标函数的表示 基因序列的设计和交叉方式 种群管理 初始可行解的生成 我自认为这个部分写得不太好。如果按照我这个方法生成初始可行解,可能比较需要天时地利。如果模型规模变大可能初始可行解的生成就会很慢,我暂时还没有想到改进的方法,因为约束确实也有点多,只能尽可能在这部分通过算法节约时间。 在我的模型中,初始可行解的生成受到几个约束:\n客户需要被完全分配。我提供的代码中的分配部分已经有改进的方案(我懒得改了🤣),即使用Random.shuffle()函数对一个序列进行打乱。如给定序列[1,2,3,4,5,6,7,8],可以通过这个函数对序列顺序进行打乱再进行切割,达到分组分配的目的。 车辆每段送货路径的载重量之和不能超过最大允许载重量。 车辆的单个环路(从仓库出发到返回仓库)的里程之和不能超过单台车辆允许行驶的里程上限。 后两个约束属于限制,我的函数在进行检测的过程中如果发现其中任何的路径不符合要求会直接break循环,节约算力和时间。\n以下是生成初始可行解的相关代码:\n1def item_generate(): # 生成个体 2 w_max = -1 3 s_max = -1 4 nc = N - 1 5 k_num_list = [] # 每辆车服务客户数量如 [4, 2, 3, 5] 6 k_visit_arr = [] # 车辆服务客户顺序列表如 [[12, 11, 14, 3, 6, 13], [9, 4, 7, 2], [5, 8], [10, 15]] 7 k_x_scatter = [] # 每辆车ij的列表如 [[[1,2],[2,3],...],[...],...]; [车[点[,]]] 8 9 while w_max \u0026lt; 0 or s_max \u0026lt; 0 or s_max \u0026gt; D or w_max \u0026gt; Q: # 要求生成的方案满足重量约束和距离约束 10 11 # 生成每辆车要访问的顾客数 12 while nc != 0: # 如果不能完全分配要重新生成 13 # 初始化生成 14 k_num_list = [] 15 nc = N - 1 16 # 生成 17 for i in range(K - 1): 18 num = random.randint(0, min(nc, V)) 19 nc -= num # 从顾客中删除num个 20 k_num_list.append(num) 21 if nc \u0026lt; V: 22 k_num_list.append(nc) 23 nc = 0 24 k_num_list.sort(reverse=True) # 从大到小排列车辆服务客户数量 25 26 # 根据每辆车服务客户数量生成配送方案 27 [k_visit_arr, k_x_scatter] = generate_d_arr(k_num_list) 28 29 # 检测是否符合载货量要求(见函数) 30 w_max = cal_w_max(k_visit_arr) 31 # for debug 32 if w_max \u0026gt; Q and print_debug: 33 print(\u0026#34;超重\u0026#34;, w_max) 34 35 # 检测是否符合最远距离要求 36 s_max = cal_s_max(k_x_scatter) 37 if s_max \u0026gt; D and print_debug: # for debug 38 print(\u0026#34;超距离\u0026#34;, s_max) 39 40 return [k_num_list, k_visit_arr, k_x_scatter] 41 42# 根据每辆车的服务顺序生成配送方案 43def generate_d_arr(k_num_list): # 输入服务顺序,如 [4,2,3,5] 44 # 生成客户列表 45 customers = [] 46 for i in range(2, N + 1): # (客户:2~15(14个)) 47 customers.append(i) 48 49 # 生成每辆车服务的顺序和决策点 50 k_visit_arr = [] # 车辆服务客户顺序列表如 [[12, 11, 14, 3, 6, 13], [9, 4, 7, 2], [5, 8], [10, 15]] 51 k_x_scatter = [] # 每辆车ij的列表如 [[[1,2],[2,3],...],[...],...]; [车[点[,]]] 52 for i in range(K): 53 visit_arr = [] # 定义一辆车服务顺序向量 54 x_scatter = [] # 访问点 55 for j in range(k_num_list[i]): # 根据服务数量生成每辆车要服务的客户的顺序 56 # 抽取客户 57 nc_remain = len(customers) 58 c_rand = customers[random.randint(0, nc_remain - 1)] # 随机选中的客户 59 visit_arr.append(c_rand) 60 customers.remove((c_rand)) # 从列表中删除客户 61 62 # 组合决策点x 63 if j == 0: # 第一个 64 x_scatter.append([1, c_rand]) 65 else: 66 x_scatter.append([visit_arr[-2], visit_arr[-1]]) # 已经加进去了,所以[-2],[-1]是最新的 67 if j == (k_num_list[i] - 1): # 如果是最后一个 68 x_scatter.append([c_rand, 1]) 69 70 # 添加到列表 71 k_visit_arr.append(visit_arr) # 添加这辆车的访问客户顺序 72 k_x_scatter.append(x_scatter) # 添加这辆车的访问决策点 73 74 return [k_visit_arr, k_x_scatter] 75 76# 输入车辆服务顺序矩阵,计算最大重量是否超标,返回最大重量 77def cal_w_max(k_visit_arr): 78 # 检测是否符合载货量要求 79 w_max = 0 80 for karr in k_visit_arr: # 每辆车 81 q_all = [] # 初始化送货重量 82 p_all = [] # 初始化取货重量 83 # todo: 计算初始运货量的载重 w_sum 84 for id in karr: # 每个客户(id),从2开始(扫描数据) 85 # print(id) 86 q_all.append(q[id - 2]) # 加入指定客户的送货重量(q为向量) 87 p_all.append(p[id - 2]) # 加入指定客户的取货重量 88 w_sum = sum(q_all) # 初始载重量(离开仓库时) 89 w_max = max(w_sum, w_max) # 更新最大值 90 91 if w_max \u0026gt; Q: # 如果此时已经超过最大允许载重量,直接跳出循环,不再计算 92 break 93 94 # todo: 计算每一段路程的载重 95 for i in range(len(karr)): # 0~5 每个节点计算 96 w_sum += (-q_all[i] + p_all[i]) # 更新过程重量 97 w_max = max(w_sum, w_max) # 更新最大值 98 99 return w_max 100 101 102def cal_s_max(k_x_scatter): # 计算路程(最大值) 103 s_max = 0 104 for k in range(K): # 每辆车都计算 105 s = [] # 初始化距离 106 for o in k_x_scatter[k]: 107 if (o != 0): 108 xi = o[0] - 1 109 xj = o[1] - 1 110 s.append(d[xi][xj]) 111 s_max = max(sum(s), s_max) 112 113 if s_max \u0026gt; D: # 如果已经超距离 114 break 115 return s_max 模块测试代码:\n1[k_num_list, k_visit_arr, k_x_scatter] = item_generate() 2print(\u0026#34;最终结果\u0026#34;) 3print(k_num_list) 4print(k_visit_arr) 5print(k_x_scatter) 1[k_visit_arr,k_x_scatter] = generate_d_arr([4,2,3,5]) 2score = cal_score([[4, 12, 11, 15, 5, 7], [2, 9, 6], [10, 14, 3], [13, 8]]) 3print(score) 目标函数的表示 这部分没什么好说的,按照模型里面给定的目标函数编写就是了。下面附上我的目标函数\n1# 计算成本 2def cal_score(k_visit_arr): 3 score = 0.0 4 p_w_sums = [] # 每段路径对应的取货量之和 5 q_w_sums = [] # 每段路径运送的送货量之和 6 w_sums = [] # 每段路径的总载重量 7 for nodes in k_visit_arr: 8 p_all = [] 9 q_all = [] 10 w_all = [] 11 12 for node in nodes: 13 p_all.append(p[node - 2]) # 从向量中获取取货数值,刨除仓库占1,再考虑从0开始 14 q_all.append(q[node - 2]) # 从向量中获取送货数值,同上 15 16 p_w_sum = [] 17 q_w_sum = [] 18 for i in range(len(nodes)): # 全路程取送货量计算(从仓库出发到回到仓库) 19 p_w_sum.append(sum(p_all[:i + 1])) 20 q_w_sum.append(sum(q_all[i:])) 21 22 if len(q_w_sum) != 0: 23 w_all.append(q_w_sum[0]) # 运往第一个节点 24 for i in range(0, len(nodes) - 1): 25 w_all.append(p_w_sum[i] + q_w_sum[i + 1]) 26 w_all.append(p_w_sum[-1]) 27 28 p_w_sums.append(p_w_sum) 29 q_w_sums.append(q_w_sum) 30 w_sums.append(w_all) 31 32 k_x_scatter = get_scatter(k_visit_arr) # 获取散点集合 33 for y in range(len(k_x_scatter)): 34 for z in range(len(k_x_scatter[y])): 35 # 转化为下标索引 36 i = k_x_scatter[y][z][0] - 1 37 j = k_x_scatter[y][z][1] - 1 38 score += P * d[i][j] 39 score += w_sums[y][z] * d[i][j] * Pa / Q 40 41 score += Pm * sum(q[Med - 1:]) # 配送药店药物额外加固费用 42 43 return score 在我的模型中,k_visit_arr是访问的客户的编号的向量。函数测试代码如下:\n1print(cal_score([13,6,7,8,3,14,2,9,15,5,11,12,10,4])) 基因序列的设计和交叉方式 基因序列的设计 基因编码:5, 5, 4, 0, 4, 10, 12, 11, 5, 9, 2, 3, 14, 15, 13, 6, 7, 8\n在我的模型中,由于车辆数为4,设定前4位分别为每辆车服务的客户数量。 后14位客户的服务顺序,根据车辆服务客户的数量依次分配。交叉时不切断前四位,保证交换后的方案在一定程度上的可行。\n基因相关代码:\n1def get_gene(k_num_list, k_visit_arr): # 获取基因(K+(N-1));前K位为形状,后N-1位为顺序 2 gene = copy.deepcopy(k_num_list) 3 for items in k_visit_arr: 4 for item in items: 5 gene.append(item) 6 return gene 7 8 9def grow(gene): # 根据基因恢复 10 structure = gene[:4] # 切割位置在4位末尾 11 content = gene[4:] 12 adult = [] # 声明恢复目标 13 for num in structure: 14 arr = [] # 每辆车的服务顺序 15 i = 0 # 声明切割点 16 for i in range(num): 17 arr.append(content[i]) 18 content = content[i + 1:] 19 adult.append(arr) 20 21 return [structure, adult] # 返回结构和内容 模块测试代码\n1print(get_gene([5, 5, 2, 2],[[13, 9, 2, 6, 14], [15, 8, 12, 4, 11], [5, 7], [3, 10]])) 2 3print(grow([5, 5, 2, 2, 13, 9, 2, 6, 14, 15, 8, 12, 4, 11, 5, 7, 3, 10])) 交叉方法 一对基因交叉会产生两个新的序列。\n先从4位后确定交换片段的长度,基因交叉时在4位后随机选取位点。 先插入0(无意义,原序列也不存在),再删除基因4位后中存在的即将要插入片段中包括的所有数值。 将片段插入到基因中,最后删除0,得到可用的基因。 这种交叉方式在一定程度上保留了访问客户的顺序,相比直接交叉避免了客户被重复服务或者被漏掉的情况。\n交叉相关代码:\n1def cross(item1, item2): # 交叉 2 structures = [item1[:4], item2[:4]] # 储存结构 3 gene_1 = item1[4:] 4 gene_2 = item2[4:] 5 6 swap_len = random.randint(1, int(len(gene_1) / 2)) # 交换长度 7 sec_p = random.randint(0, len(gene_1) - swap_len) # 截取位点 8 insert_p = random.randint(0, len(gene_1)) # 插入位点 9 10 sections = [gene_1[sec_p:sec_p + swap_len], gene_2[sec_p:sec_p + swap_len]] # 截取的交换片段 11 12 genes_s = [gene_1[:], gene_2[:]] # 要返回的基因 13 14 for i in range(2): 15 genes_s[i].insert(insert_p, 0) # 插入的0无意义,只是一个标记 16 17 for sec in sections[i]: 18 genes_s[i].remove(sec) 19 tag = genes_s[i].index(0) # 0的标记位点 20 21 for j in range(swap_len): 22 genes_s[i].insert(tag + j, sections[i][j]) 23 genes_s[i].remove(0) # 移除标记位点 24 25 for i in range(K): 26 genes_s[0].insert(i, structures[0][i]) 27 genes_s[1].insert(i, structures[1][i]) 28 return genes_s 模块测试代码:\n1print(cross([6, 6, 1, 1, 7, 15, 5, 11, 6, 13, 3, 14, 12, 10, 4, 9, 2, 8],[6, 4, 3, 1, 13, 14, 11, 5, 3, 15, 6, 7, 8, 12, 4, 9, 2, 10])) 种群管理 生成初始种群 生成初始种群时通过之前的item_generate()生成个体函数生成可行个体,再通过cal_score()函数计算个体的分数,通过get_gene()函数获取个体对应的基因。最终按照个体的分数进行从小到大排序。\n代码如下:\n1def init_gen(): # 初始种群 2 population = [] # 声明初始种群 3 4 for index in range(init_population_num): 5 [k_num_list, k_visit_arr, k_x_scatter] = item_generate() 6 7 score = cal_score(k_visit_arr) 8 gene = get_gene(k_num_list, k_visit_arr) 9 population.append([score, gene]) 10 population.sort() # 此处排序为分数从小到大 11 12 print(\u0026#34;已生成初始种群并完成排序\u0026#34;) 13 return population # 返回种群:[[分数,基因],...] 种群的迭代 种群迭代需要考虑变异,根据分数得到每个个体的选取概率,从个体中抽取进行交叉。整体大致的算法流程为:\n生成初始种群。 将初始种群迭代:根据适应度计算每个个体被选择的概率并随机抽取一定的个体进行交叉(轮盘赌),按照变异概率发生变异,得到本次迭代后种群中的最优值。如果交叉一直失败,达到交叉失败次数的上限,则放弃继续交叉,使用新生成个体弥补。 如果迭代过程中一直维持一个最优值不变,且到达迭代步数上限,则停止迭代。否则迭代步数清零,重新计算迭代步数。 代码如下:\n1def evolution(population): 2 3 if random.random() \u0026lt; mutation_rate: # 触发变异 4 print(\u0026#34;触发变异\u0026#34;) 5 for i in range(mutation_num): 6 [k_num_list, k_visit_arr, _] = item_generate() 7 gene = get_gene(k_num_list, k_visit_arr) 8 score = cal_score(k_visit_arr) 9 population.append([score, gene]) 10 11 # 统计分数 12 scores = [] 13 for item in population: 14 scores.append(item[0]) 15 min_score = min(scores) # 最低成本统计 16 print(\u0026#34;最低成本\u0026#34;, min_score) 17 18 # 计算比例 19 proportion = [] # 比例(累计) 20 proportion_sum = 0 21 score_max = max(scores) # 得到成本最高值 22 adjusted_scores = [] 23 24 for score in scores: # 预处理 25 adjusted_scores.append((score_max - score + 20)) 26 27 scores_sum = sum(adjusted_scores) 28 for score in adjusted_scores: 29 proportion_sum += score / scores_sum 30 proportion.append(proportion_sum) 31 32 selected_population = [] # 随机抽取的个体 33 bests_selected = [] # 用于交叉的好的个体(不是了, 也改成了随机个体) 34 pairs = evo_pairs # 新增对数 35 for i in range(pairs): # 根据需要添加的个体数,抽取交换的一对 36 r = random.random() 37 for j in range(len(proportion)): 38 if r \u0026lt; proportion[j]: 39 selected_population.append(population[j][1]) # 添加随机抽取的个体基因 40 break 41 for j in range(len(proportion)): 42 if r \u0026lt; proportion[j]: 43 bests_selected.append(population[j][1]) # 添加随机抽取的个体基因 44 break 45 46 for i in range(len(bests_selected)): # 交叉后结果 47 passed_gene = [] 48 count = 0 49 while len(passed_gene) \u0026lt; 2 and count \u0026lt; swap_max: # 合格的基因个数不够,且在交叉尝试的范围内 50 51 genes = cross(bests_selected[i], selected_population[i]) 52 53 # 获取基本信息 54 k_visit_arrs = [get_visit_arr_by_gene(genes[0]), get_visit_arr_by_gene(genes[1])] 55 56 k_x_scatters = [get_scatter(k_visit_arrs[0]), get_scatter(k_visit_arrs[1])] 57 # 检验是否可行 58 w_maxs = [cal_w_max(k_visit_arrs[0]), cal_w_max(k_visit_arrs[1])] 59 s_maxs = [cal_s_max(k_x_scatters[0]), cal_s_max(k_x_scatters[1])] 60 61 for j in range(2): 62 if w_maxs[j] \u0026lt;= Q and s_maxs[j] \u0026lt;= D: # 符合要求 63 passed_gene.append(genes[j]) # 添加到合格的基因 64 65 if len(passed_gene) \u0026lt; 2: # 没交叉出来 66 gene_remain = 2 - len(passed_gene) # 剩余多少个达到标准 67 for r in range(gene_remain): 68 [k_num_list, k_visit_arr, _] = item_generate() 69 passed_gene.append(get_gene(k_num_list, k_visit_arr)) 70 71 scores = [cal_score(get_visit_arr_by_gene(passed_gene[0])), 72 cal_score(get_visit_arr_by_gene(passed_gene[0]))] # 只取前两个 73 population.append([scores[0], passed_gene[0]]) 74 population.append([scores[1], passed_gene[1]]) 75 76 # for debug 77 scores = [] 78 for item in population: 79 scores.append(item[0]) 80 min_score = min(scores) # 最高分统计 81 print(\u0026#34;进化后最低成本\u0026#34;, min_score) 82 83 population.sort() # 排序 84 population = population[:init_population_num] # 将数量调整回初始种群数量 85 return [min_score, population] 遗传算法参数设置 调试参数设置如下:\n1# 调试参数 2print_debug = 0 # 是否显示debug信息 3init_population_num = 100 # 初始种群数量 4evo_pairs = 50 # 每代多少个杂交对(新生成个体的数量 = evo_pairs*2) 5swap_max = 80 # 最大单次交换次数 6max_iterate = 1000 # 最大单次迭代步数 7mutation_rate = 0.2 # 变异概率 8mutation_num = 60 # 产生变异的个数 初始种群:随机生成含有 100 个可行个体的初始种群。 杂交:每次迭代的时候根据适应度计算的概率随机抽取 50 对个体进行杂交,杂交出另 50 对个体(100 个个体)。 单次交换:杂交可能失败,最多允许尝试 80 次,否则使用随机生成的个体补充。 单次迭代:如果最优值在迭代 1000 次后都没有发生变化,则停止迭代,输出结果。 变异:变异概率设置为 0.2,如果发生变异产生 60 个可行的变异个体。\n","date":"2022-07-13T12:07:30Z","permalink":"https://www.zhhuu.top/posts/ga/","section":"posts","tags":["物流","优化","语法","算法","编程","Python"],"title":"使用Python编写遗传算法"},{"categories":null,"contents":"最近上课自学了CPLEX,感觉和之前浅浅接触过的LINGO的语法很像。记录一下以免以后忘了怎么用。此外,还在其中记录一下本次自学的遗传算法。\n概述 求解大规模线性优化问题的时候不可能使用单纯形算法一个个地列单纯形表去手算,必须借助计算机求解才能使求解精确解的求解速度在可接受的范围内。可接受的求解时间范围根据每个人的接受情况不同大多分布于3小时或1天之内。此处记录一下之前稍微了解到的LINGO软件的语言、这次自学的CPLEX软件的OPL语言,这两个软件都可以用于求解线性规划问题。\nLINGO语法 LINGO的整个线性规划模型大致可以描述为:\n集合(Sets) 变量(Data) 模型(Model) LINGO的集合 先上一段代码\n1sets: 2\tS/1..6/: a, b, d ; // S为1~6的集合,a有6个分量(a1~a6),b、d、e等同理 3\tT/1,2/: e, x, y; // T为1和2组成的集合, 4\tU(S,T): c ; // 定义了双下标的集合(c为双下标变量c_ij) 5endsets 第2行描述了三个变量abd各自都有6个分量,如a可以看成a1,a2,...,a6,在LINGO里面引用就是a(1),a(2),...,a(6),剩下两个变量b和d同理。 第四行定义了U为双下标集合,如果将U的每个元素看作Uij,那么i的范围为[1,6],整数;j的范围为{1,2}。在LINGO里面引用就是U(i,j)。根据定义的集合,U(i,j)共有12个变量。\nLINGO的变量 代码\n1data: 2\ta=1 2 3 4 5 6; // 定义a(n)的值 3\tb=1 2 3 4 5 6; 4\tx=5 2; 5\ty=1 7; 6enddata 第2行表示a(1)到a(6)的值分别为1、2、3、4、5、6。\nLINGO的模型 模型又可以分为两个部分:\n目标函数 约束方程 在这之前,需要先了解集合函数,方便规模化地表示模型的目标函数和约束方程。\nLINGO的集合函数 我也不知道它是不是叫这个名字,姑且先用集合函数表示他们。当时简单了解到的集合函数有两个。\n函数表示 功能 @sum 求和 @for 遍历,但不操作 仅求和而言,大致有以下2种情况:\n双变量求和 $\\sum_{i=1}^{n}\\sum_{j=1}^{k}x_{ij}$:可以直接对集合 T(i,j) 使用集合函数 @sum 进行求和 双变量求和 $\\sum_{i=1}^n\\sum_{j=1}^{k}x_{j}$ 或 $\\sum_{j=1}^kx_{ij}$, $i\\in{1,2,3,\u0026hellip;,6}$:可以直接对集合 T(i,j) 使用集合函数 @sum 进行求和 如果同时用到两个下标进行求和的时候,可以直接使用集合函数@sum对其直接进行求和,否则应考虑如何使用@for函数遍历所有情况。\nLINGO中目标函数的表示 数学公式:\n$$min\\sum_{j=1}^2\\sum_{i=1}^6\\sqrt{(x_j-a_i)^2+(y_j-b_i)^2}$$\nLINGO代码:\n1min = @sum(T(j): @sum(S(i): 2\tc(i,j)*@sqrt( ( x(j) - a(i) )^2 + ( y(j) - b(i) )^2 ) 3) ) 范围不同,需要使用两次@sum进行求和操作。@sum内表示了求和操作的对象,如T(j)和S(i),其冒号后跟的是求和对象。\nLINGO中约束方程的表示 数学公式\n$$ \\left\\{ \\begin{array}{**lr**} \\sum_{j=1}^2c_{ij}=d_i , i=1,2,...,6 \\\\ \\sum_{i=1}^6c_{ij} \\leq d_i, j=1,2 \\end{array} \\right. $$ LINGO代码\n1min = @sum(T(j): @sum(S(i): 2\tc(i,j)*@sqrt( ( x(j) - a(i) )^2 + ( y(j) - b(i) )^2 ) 3) ) 4 5@for( S(i): @sum(T(j): c(i,j)) = d(i) ); 6@for( T(j): @sum(S(i): c(i,j)) ) \u0026lt;= e(j); 集合函数用法同函数表示中的描述。\nOPL语法 OPL语法是CPLEX的线性规划求解语法,我认为语法类似LINGO,但是相比LINGO更清楚。 一个OPL描述的模型也可以分为几个区域:\n定义已知变量 定义未知变量 目标函数 约束条件 变量类型 变量符号 含义 int 整数 int 非负整数 float 实数 float+ 非负实数 boolean 0-1变量 range 范围 举例说明 range range k = 1..4;\n利用range定义变量 定义p1~p4:p[1..4]=[12, 11, 9, 8];\n矩阵描述 此处的矩阵描述方法类似json,如下:\n1int c[1..3][1..3] = [ 2 [1,2,3], 3 [4,5,6], 4 [7,8,9] 5]; 最后需要添加分号结束\n定义未知变量 1dvar [关键字] [变量名]; 如\n1dvar int x; 这些未知变量要么是求解变量,要么是过程变量。\n目标函数的表示 目标函数要么求最大,要么求最小。\n关键字 目标函数类型 minimize 最小化目标函数 maximize 最大化目标函数 1minimize 3*x + 2*y; //目标函数为3x+2y,求最小化值 集合语言 类似LINGO中的集合函数,此处分为3种情况\n$\\sum_{j=1}^n p_j x_j$:sum(j in 1..n) p[j]*x[j] $\\sum_{i=1}^n \\sum_{j=1}^m x_{ij}$:sum(i in 1..n) sum(j in 1..m) x[i][j] $\\sum_{i=1}^n x_{ij}$:forall(j in 1..m) sum(i in 1..n) x[i][j] 其实也就还是sum和for函数。建议sum和for函数里面使用range。\nSUM 1//sum的范围既可以分开写,也可以合并写。我更偏向于第二种 2sum(i in 1..n) sum(j in 1..m) x[i][j]; 3sum(i in 1..n, j in 1..m) x[i][j]; 此处的1..n和1..m都是范围,都可以使用range类型的变量代替\nFORALL 我认为forall除了功能与sum不同(不进行操作,只遍历所有可能性),其他与sum完全相同。sum和forall同时使用的时候我一般把forall放在sum前面。\n1//forall的范围也可以合并写 2forall(i in 1..n) sum(j in 1..m) x[i][j]; 3forall(i in 1..n, j in 1..m) sum(k in 1..p) x[i][j][k]; 此外,有意思的是,forall的有效范围似乎是整行,而sum的有效范围只是后方紧跟的函数或变量。\n约束条件 1subject to { 2 //在这里直接写约束条件; 3 //里面每句最后都要跟分号,就和C语言一样 4} 脚本 脚本这部分我还没用到,不太清楚。可以用于输出、修改数据。\n1execute { 2\t//脚本代码 3} 代码实例 此部分只展示我作业OPL源代码中范围、决策变量、目标函数和约束方程的部分,我认为这些部分会对理解比较有帮助。\n1// 范围 2range rk=1..K; //车辆 3range rn=1..N; //所有节点 4range rc=2..N; //客户 5 6// 决策变量 7dvar boolean x[k in rk][i in rn][j in rn]; //路线决策 8dvar int+ y[i in rn][j in rn]; //路段总送货量 9dvar int+ z[i in rn][j in rn]; //路段总收货量 10 11// 目标函数 12minimize sum(k in rk,i in rn,j in rn) x[k][i][j]*d[i][j]*P 13\t+ sum(k in rk, i,j in rn)(y[i][j]+z[i][j])*x[k][i][j]*d[i][j]*Pa/Q 14\t+ sum(k in rk, i in rn, j in Med+1..N) x[k][i][j]*q[j]*Pm; 15 16// 约束方程 17subject to{ 18 forall(j in rc) sum(i in rn,k in rk) x[k][i][j] == 1; //每个客户都只访问一次 19 forall(i in rn, k in rk) sum(j in rn) x[k][i][j] == sum(j in rn) x[k][j][i]; //到达节点的数量和离开节点的数量相同 20 forall(k in rk) sum(j in rn) x[k][1][j] \u0026lt;= 1; //每辆车只能离开仓库一次 21 forall(i,j in rn) y[i][j]+z[i][j] \u0026lt;= Q*sum(k in rk) x[k][i][j]; //任意路段的载重量不超过车辆容量 22 forall(k in rk) sum(i,j in rn) x[k][i][j]*d[i][j] \u0026lt;= D; //每辆车的行驶里程上限 23 forall(i in rc) sum(j in rn) y[j][i] - sum(j in rn) y[i][j] == q[i]; //所有客户的送货量递推约束 24 forall(i in rc) sum(j in rn) z[i][j] - sum(j in rn) z[j][i] == p[i]; //所有客户的取货递推约束 25 forall(k in rk) sum(i in rn) x[k][i][i] == 0; //不允许自己运给自己 26 forall(k in rk) sum(i in rc, j in rn) x[k][i][j] \u0026lt;= V; //车辆服务客户数量限制 27} ","date":"2022-07-12T22:22:54Z","permalink":"https://www.zhhuu.top/posts/optimization-code/","section":"posts","tags":["物流","优化","语法"],"title":"优化软件语法"},{"categories":["Skills"],"contents":"1SELECT * 2FROM table 3WHERE column LIKE \u0026#39;条件\u0026#39; 4Order by 1 5LIMIT 100 基本语法 注释 --后面是注释内容。--是sql的注释标志\n运算符 运算符 说明 AND 和,AND的优先级一般会高于OR OR 或者 NOT 非 () 括号,提高优先级。 条件 符号 含义 % n个任意字符 _ 1个任意字符 正则表达式 REGEXP(Regular Expression)\n1WHERE column REGEXP \u0026#39;表达式\u0026#39; 符号 意义 例子 ^ 以..开头 ^field $ 以..结尾 field$ \\ 或者 ^field|mac|rose [] 匹配中括号内的所有字符 [gim]e,匹配ge、ie、me,\n[a-c]d,匹配\nad、bd、cd,\n[1-3]同理 注意:由于我使用的markdown编译器无法将表格中的代码中的|识别为符号,以上的|为全角符号\nNULL 表达式 含义 IS NULL 值为null IS NOT NULL 值不为null AS 在原有数据基础上新建一列数据,或者理解为处理完原有列数据填入新一列中\n1score + 10 AS new _score SELECT 选择表内的数据\n1SELECT first _name, last _name ORDER BY 根据什么值排序\n1ORDER BY first _name 多值排序 1ORDER BY state, first _name 根据列排序 1ORDER BY 1, 2 DESC descending:降序 1ORDER BY first _name DESC 多值排序 1ORDER BY state DESC, first _name LIMIT 表达式 含义 LIMIT 6 设定返回查询数据的最大条数为6 LIMIT 6, 3 跳过前6条,再返回3条数据(返回第7-9条数据) Alias 简写 1SELECT customer _id c 2From table_t 3ORDER BY c JOIN和ON JOIN用于联系多个表的数据列。\n1SELECT * 2FROM orders o 3JOIN customers c 4 ON o.customer _id = c.customer _id 切换数据库 1USE 数据库名 2 3SELECT * 4FROM 另一个数据库名.数据表 5… UNION 用于合并多个查询结果。\n1SELECT first _name 2FROM customers 3UNION 4SELECT name 5FROM shippers 如果一个查询里面有多个语句,一个语句结束后要使用分号(;) UNION连接的查询语句只算一个语句 属性 列属性 数据类型 类型 含义 INT(11) VARCHAR(50) 最大50个字符,且最大占用50个字符的空间,常用于保存string CHAR(50) 最大50个字符,占用50个字符的的空间 数据属性 缩写 全称 含义 PK Primary Key 数据主键 NN Not Null 是否能接受NULL值?(可选值?) AI Auto Increment 自动递增 Default / Expression - 默认值 数据管理 添加行 按照数据排列顺序,包含在VALUES里面添加。\n全部添加 1INSERT INTO customers 2-- 如果想要用自动递增,可以直接填DEFAULT 3-- 如果是可选值,不填入数据的话就填NULL 4VALUES ( 5 DEFAULT, 6 \u0026#39;first name value\u0026#39;, 7 \u0026#39;last name value\u0026#39;, 8 \u0026#39;1990-01-01\u0026#39;, 9 NULL, 10 \u0026#39;address\u0026#39;, 11 \u0026#39;city\u0026#39;, 12 \u0026#39;CA\u0026#39;) 选择部分变量添加 1INSERT INTO customers( 2 first _name, 3 last _name, 4 birth _date) 5-- VALUES的顺序根据上面定义的顺序来,上面定义的数据顺序可以根据自己的喜好 6VAULES( 7 \u0026#39;first name value\u0026#39;, 8 \u0026#39;last name value\u0026#39;, 9 \u0026#39;date of birth\u0026#39;) 添加多个变量 1INSERT INTO shippers (name) 2VALUES(\u0026#39;shipper1\u0026#39;), 3 (\u0026#39;shipper2\u0026#39;), 4 (\u0026#39;shipper3\u0026#39;) 向不同的表格添加变量 1INSERT INTO orders (customer _id, order _date, status) 2VALUES (1, \u0026#39;2019-01-02\u0026#39;, 1); 3INSERT INTO order _items 4VALUES (LAST _INSERT _ID(), 1, 1, 2.95), 5VALUES (LAST _INSERT _ID(), 2, 1, 3.95) 从一个数据表添加变量到另一个数据表 新建为数据表(CREATE)\n1CREATE TABLE ordres _archived AS 2SELECT * FROM orders 3-- 这里的SELECT语句是SubQuery 右键数据表的“truncate table”是清空数据表的所有数据 插入到数据表(INSERT) 1INSERT INTO orders _archived 2SELECT * 3FROM orders 4WHERE order _date \u0026lt; \u0026#39;2019-01-01\u0026#39; 更新数据 更新单行数据 1UPDATE table 2SET payment _total = 10, payment _date = \u0026#39;2019-03-01\u0026#39; 3WHERE invoice _id = 1 更新多行数据 1UPDATE table 2SET payment _total = 10, payment _date = \u0026#39;2019-03-01\u0026#39; 3WHERE invoice _id IN (3, 4) 4-- 如果要更新数据表中的所有值,只需留空WHERE 删除数据 1DELETE FROM table 2-- 如果没有WHERE语句,将会删除所有数据,非常危险。 3WHERE client _id = ( 4 SELECT client _id 5 FROM clients 6 WHERE name = \u0026#39;Myworks\u0026#39;) ","date":"2022-03-27T11:52:50Z","permalink":"https://www.zhhuu.top/posts/sql-basics/","section":"posts","tags":["编程","后端"],"title":"SQL入门"},{"categories":["Coding"],"contents":"Task 线程的问题:线程(Thread)是用来创建并发的一种低级别工具,尤其在于以下方面有一些限制:\n虽然开始线程的时候可以方便地传入数据,但是当Join(等待)的时候,很难从线程获得返回值。 可能需要设置一些共享字段 如果抛出异常,捕获和传播该异常都很麻烦 无法告诉线程在结束时开始做另外的工作,必须进行Join操作,在进程中阻塞当前的进程,等待线程结束。 对手动同步的更大依赖以及随之而来的问题 Task类可以很好地解决上述问题。Task是一个相对高级的抽象,它代表了一个并发操作(concurrent),该操作可能由Thread支持,或不由Thread支持。并且,Task是可组合的。 Tasks可以使用线程池来减少启动延迟 使用TaskCompletionSource,Tasks可以利用回调的方式在等待I/O绑定操作是完全避免线程。 开始一个Task 开始一个Task最简单的方法就是使用Task.Run这个静态方法。(.NET4.5开始,.NET4.0的时候是Task.Factory.StartNew这个静态方法) 使用方法:传入一个Action委托即可。\nTask默认使用线程池,也就是后台线程。当主线程结束时,创建的所有任务都会结束。\n1static void Main(string[] args) 2{ 3 Task.Run(() =\u0026gt; Console.WriteLine(\u0026#34;Foo\u0026#34;)); 4 Console.ReadLine(); // 可以达到阻塞线程的效果。 5 // 如果程序运行完了,由于Task是后台线程,Task也会被关闭。 6} Task.Run返回一个Task对象,可以使用它来监视其过程。Task.Run之后没有调用Start,因为该方法创建的是“热”任务(hot task);可以通过Task的构造函数创建“冷”任务(cold task),但很少这样做。\nWait 调用Task的Wait方法会进行阻塞直到操作完成(相当于调用Thread上的Join方法)\n1static void Main(string[] args) 2{ 3 Task task = Task.Run(() =\u0026gt; 4 { 5 Thread.Sleep(3000); 6 Console.WriteLine(\u0026#34;Foo\u0026#34;); 7 }); //创建一个“热任务” 8 9 Console.WriteLine(task.IsCompleted); //False 10 11 task.Wait(); //阻塞至task完成操作 12 13 Console.WriteLine(task.IsCompleted); //True 14 15 // False 16 // Foo 17 // True 18} Wait也可以指定一个超时时间和取消令牌来提前结束等待。\n长时间运行的任务 默认情况下,CLR在线程池中运行Task,这非常适合短时间运行的Compute-Bound类工作 针对长时间运行的任务或者阻塞操作(例如前面的例子),可以不采用线程池 如果同时运行多个long-running tasks(尤其是其中有处于阻塞态的),那么性能将会受很大影响,这时有比TaskCreationOptions.LongRunning更好的办法: 如果任务是IO-Bound,TaskCompletionSource和异步函数可以让你用回调代替线程实现并发。 如果任务是Compute-Bound,生产者/消费者队列允许你对任务的并发性进行限流,避免把其它线程和进程饿死。(并行编程) Task的返回值 Task有一个泛型子类叫做Task\u0026lt;TResult\u0026gt;,他允许发出一个返回值。\n使用Func\u0026lt;TResult\u0026gt;委托或兼容的Lambda表达式来调用Task.Run就可以得到Task\u0026lt;TResult\u0026gt;,随后可以通过Result属性来获得返回的结果。\n如果这个task还没有完成操作,访问Result属性会阻塞该线程直到该task完成操作。\n1static void Main(string[] args) 2{ 3 Task\u0026lt;int\u0026gt; task = Task.Run(() =\u0026gt; 4 { 5 Console.WriteLIne(\u0026#34;Foo\u0026#34;); 6 return 3; 7 }); //Lambda表达式与Func\u0026lt;TResult\u0026gt;兼容 8 9 int result = task.Result; //如果task没完成,会阻塞当前进程,直到返回结果 10 Console.WriteLine(result); //3 11} Task\u0026lt;TResult\u0026gt;可以看作是一种所谓得“许诺”,在它里面包裹着一个Result,在稍后的时候就会变得可用。\nTask的异常 不同于Thread,Task可以很方便地传播异常。如果task里面抛出了ige未处理的异常(故障),那么异常就会重新抛出给:\n调用了wait()的地方、 访问了Task\u0026lt;TResult\u0026gt;的Result属性的地方 无需重新抛出异常,通过Task的IsFaulted和IsCancelled属性也可以检测出Task是否发生了故障:\n如果两个属性都返回false,那么没有错误发生。 如果IsCanceled位true,那就说明一个OperationCanceledException为该Task抛出了异常 如果IsFaulted为true,那就说明另一个类型的异常被抛出,而Exception属性也将指明错误 “自治”的Task “自治”的Task制“设置完就不管了”的Task。指不通过调用Wait()方法、Result属性或continuation进行会合的任务。\n针对自治的Task,需要像Thread一样,显式地处理异常,避免发生“悄无声息”的故障。 自治Task上未处理的异常称为未观察到的异常。\n未观察到的异常 可以通过全局的TaskScheduler.UnobservedTaskException来订阅未观察到的异常。\n使用超时进行等待的Task,如果在超时后发生故障,那么它将会产生一个“未观察到的异常”\n在Task发生故障后,如果访问Task的Exception属性,那么该异常就被认为是“已观察到的异常”\nContinuation 当Task结束的时候,继续做其它事情。Continuation通常是通过回调的方式实现的,当操作一结束,就开始执行。\n在Task上调用GetAwaiter会返回一个awaiter对象。它的OnCompleted方法会告诉task:“当你结束/发生故障时要执行委托”\n可以将Continuation附加到已经结束的task上面,此时Continuation将会被安排立即执行。\nAwaiter awaiter是可以暴露下列两个方法和一个属性的对象:\nOnCompleted GetResult IsCompleted(bool属性) 其中,OnCompleted是INotifyCompletion的一部分 如果发生故障,调用awaiter.GetResult()的时候,异常会重新抛出。 无需调用GetResult,task的Result属性也可以直接访问。\n非泛型Task 非泛型的task,GetResult()方法有一个void返回值,只用来重新抛出异常。\n未完\u0026hellip;\nasync 标志着这些代码是异步的,编译器必须重新排列它。\n","date":"2022-03-25T11:56:41Z","permalink":"https://www.zhhuu.top/posts/csharp-task/","section":"posts","tags":["C#","编程"],"title":"C# Task"},{"categories":["Coding"],"contents":"Thread 线程 一个可执行路径,独立于其它线程执行。\n线程被抢占 线程的执行与另外一个线程上代码的执行交织的那一点。\n线程的属性\u0026amp;特性 线程一旦开始执行,IsAlive为true;线程结束变成false 线程结束的条件:线程构造函数传入的委托执行结束 线程一旦结束,无法重启 每个线程都有Name属性,通常用于调试。Name只能设置一次,更改会抛出异常。 静态的Thread.CurrentThread属性返回当前执行的线程。 Join 调用Join方法,可以等待另一个线程结束。\n1Thread t = new Thread(Go); 2t.Start(); //开始线程 3t.Join(); //等待线程执行完成 4Console.WriteLine(\u0026#34;Thread t has ended!\u0026#34;); //线程结束 5 6static void Go() //线程构造函数传入的委托 7{ 8 for (int i = 0; i \u0026lt; 1000; i++) 9 Console.Write(\u0026#39;y\u0026#39;); 10} 添加超时 调用Join的时候,可以设置一个超时,可以使用毫秒或者TimeSpan 如果返回true,线程结束;如果超时,返回false\n1bool IsTerminated = thread1.Join(2000); //等待2秒后线程是否执行结束 Sleep Thread.Sleep()方法会暂停当前的线程,并等待一段时间。可以是毫秒或者TimeSpan\n1Thread.Sleep(500); //线程休眠500ms Thread.Sleep(0)会导致线程立即放弃当前的时间片,自动将CPU移交给其它线程。 Thread.Yield()做同样的事情,但是它只会把执行交给同一处理器上的其它线程。 当等待Sleep或Join的时候,线程处于阻塞的状态。 阻塞:正在等待某一事件发生,根据原因可设置多个阻塞队列\n❔ 如果在代码中任何地方插入Thread.Yield()就破坏了程序,程序几乎肯定会有bug\n阻塞 线程的执行由于某种原因导致暂停。 可以通过ThreadState属性判断线程是否处于被阻塞的状态。\nThreadState ThreadState是一个flags enum(可以有多个枚举值),通过**按位**的形式可以合并数据的选项。\n枚举值是2^n\n举例 状态(只列举部分状态) 枚举值 二进制枚举值 ThreadState.Unstarted 8 1000 (2^3) ThreadState.Stopped 16 10000 (2^4) ThreadState.WaitSleepJoin 32 100000 (2^5) 1var state = ThreadState.Unstarted | ThreadState.Stopped | ThreadState.WaitSleepJoin; 2// 得到的状态为xxx000 通过ThreadState判断线程是否处于被阻塞的状态\n1bool blocked = (someThread.ThreadState \u0026amp; ThreadState.WaitSleepJoin) != 0; 常用的线程状态\nUnstarted:未开始 Running:运行 WaitSleepJoin:阻塞 Stopped:停止 剥离出这四种状态\n1public static ThreadState SimpleThreadState(ThreadState ts) 2{ 3 return ts \u0026amp; (ThreadState.Unstarted | 4 ThreadState.WaitSleepJoin | 5 ThreadState.Stopped); 6} 解除阻塞 四种情况\n阻塞条件被满足 操作超时(如果设置了超时) Thread.Interrupt()进行打断 Thread.Abort()进行中止 异常处理 创建线程时在作用范围内的try/catch/finally块,在线程开始执行后就与线程无关了。\n在WPF、WinForm里,可以订阅全局异常处理事件:\nApplication.DispatcherUnhaandledException Application.ThreadException 主线程(UI线程)上有未处理的异常,会触发以上两个线程;非UI线程不会触发以上两个线程。\n任何线程有任何未处理的异常都会触发:\nAppDomain.CurrentDomain.UnhandledException 前台和后台线程 默认情况下,手动创建的线程是前台线程。\n只要由前台线程在运行,应用程序就会一直处于活动状态,后台线程却不行。 一旦所有的前台线程停止,那么应用程序就停止,任何的后台线程也会突然终止。 可以通过IsBackground判断线程是否后台线程。 线程优先级 线程的优先级(Thread的Priority属性)决定了相对于操作系统中其它活跃线程所占的执行时间。 优先级:enum ThreadPriority {Lowest, BelowNormal, Normal, AboveNormal, Highest}\n信号 有时候需要让线程一直处于等待的状态,直至接收到其它线程发来的通知。这就叫做signaling(发送信号) 最简单的信号结构为ManualResetEvent,调用其上面的WaitOne()方法会阻塞当前的线程,直到另一个线程通过调用Set()方法来开启信号。\n1var signal = new ManualResetEvent(false); 2new Thread(()=\u0026gt; 3{ 4 Console.WriteLine(\u0026#34;Waiting for signal...\u0026#34;); 5 signal.WaitOne(); 6 signal.Dispose(); 7 Console.WriteLine(\u0026#34;Got signal!\u0026#34;); 8}).Start(); 9 10Thread.Sleep(3000); 11signal.Set(); //打开信号(线程) 调用完Set()之后,信号会处于“打开”状态,可以通过调用Reset()方法将其关闭。\n富客户端应用程序的线程 在有UI的程序中,如果在主线程执行耗时的操作,就会导致整个程序无响应。针对这种耗时的操作,一种流行的做法是启用一个worker线程,执行完操作后再将结果更新到UI。 富客户端应用的线程模型:\nUI元素和控件只能从创建它们的线程来进行访问(通常是主UI线程)\n当想从worker线程更新UI的时候,必须把请求交给UI线程 如:在WPF中,在元素的Dispatcher对象上调用BeginInvoke或Invoke;在WinForm中,调用控件的BeginInvoke或Invoke;UWP中,调用Dispatcher对象上的RunAsync或Invoke。这些方法都接收一个委托。\nBeginInvoke或RunAsync通过将委托排队到UI线程的消息队列来执行工作。\nInvoke也会执行相同的操作,但随后会进行阻塞,直到UI线程读取并处理消息。所以Invoke允许从方法中获取返回值。\n从其它线程直接更改UI会引发System.InvalidOperationException错误(无法更新主线程上的UI) 应该调用Dispatcher.BeginInvoke(),把委托排队发送到UI线程的消息队列(处理键盘鼠标事件、定时事件等)\n1Action action = () =\u0026gt; MessageText.Text = message; // 委托 2Dispatcher.BeginInvoke(action); // 将委托发送到消息队列 线程池 线程池可以通过预先创建一个可循环使用线程的池来减小类似“创建一个新的局部变量栈(stack)”这样的开销。 线程池允许在不被线程启动的开销淹没的情况下运行短期操作。(操作事件没有线程启动的时间长) 线程池对于高效的并行编程和细粒度的并发是必不可少的。\n使用线程池需要注意的几点:\n不可以设置池线程的Name 池线程都是后台线程 阻塞池线程可使性能降级 可以自由地更改池线程的优先级,当它释放回池的时候优先级将还原为正常状态。 可以通过Thread.CurrentThread.IsThreadPoolThread属性判断是否执行在池线程上。 进入线程池 最简单的、显式地在线程池运行代码地方式就是Task.Run\n参考资料 位操作 运算符 含义 \u0026amp; 按位与 \\ 按位或 ^ 按位异或 \u0026laquo; 左移 \u0026raquo; 右移 按位与(\u0026amp;)和按位或(|) 按位与(\u0026amp;)和按位或(|)运算规则同与(\u0026amp;\u0026amp;)和或(|),不同在于按位运算是按照二进制位运算。\n例如:一个二进制数1101 1001,只要它的后四位 只需要进行如下操作:1101 1001 \u0026amp; 0000 1111即可。\n数值 1101 1001 \u0026amp; 与运算 0000 1111 结果 0000 1001 按位或运算同理 按位异或(^) 只要参与运算的双方不同,结果为1,否则为0\n运算 结果 0^0 0 0^1 1 1^0 1 1^1 0 左移 将目标二进制数字向左/右移动相应的位数 换算为十进制为原来的1/2 左移补0; 1011 1111 \u0026lt;\u0026lt; 1 == 0111 1110\n右移 需要看符号位:负数补1,正数补0 换算为十进制为原来的1/2 1011 1111 \u0026gt;\u0026gt; 1 == 0101 1111\n位移运算:左乘右除\n上下文切换 当线程阻塞或解除阻塞时,操作系统将执行上下文切换。\nI/O-bound 花费大部分时间等待某件事发生的操作。 Compute-bound或CPU-bound 花费大部分事件执行CPU密集型工作的操作 引用 ThreadState 枚举 (System.Threading) | Microsoft Docs\n","date":"2022-03-25T11:31:09Z","permalink":"https://www.zhhuu.top/posts/csharp-thread/","section":"posts","tags":["编程","C#"],"title":"C# 线程"},{"categories":["Coding"],"contents":"操作系统方面的进程管理\n进程 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程,是操作系统进行资源分配和保护的基本单位。进程是程序在处理机上的一次执行过程。\n动态性:创建👉产生;调度👉执行;得不到资源👉阻塞;撤销👉消亡 并发性:多个进程可同时存在于内存中,在一段时间内同时运行。 独立性:独立获得资源的基本单位 异步性:各进程按各自独立的不可预知的速度执行 交往性(制约性):进程至今啊相互制约,互斥地使用某些资源、相关进程之间同步、通信等。 进程的静态描述 进程控制块:反映了进程的动态特征。 程序段:能被调度程序选中,并在CPU上执行的程序代码段 数据段:进程对应的原始数据、中间或最终数据 进程控制块 进程控制块 PCB(Process Control Block)\n是操作系统为了管理进程设置的一个数据结构,用于记录和描述进程。 系统利用PCB控制和管理进程。一个进程只有一个PCB,PCB是进程是否存在的唯一标记,是系统感知进程存在的唯一标志。 进程与PCB一一对应。 PCB包含如下信息:\n描述信息:ID、进程组关系(父进程、子进程) 控制信息:状态、优先级、外存地址、运行同级信息等 资源管理信息:指针、占用内存大小等 CPU现场保护结构:当前进程的执行被打断,储存进程现场数据 PCB组织方式:线性、链接(链表)、索引\n进程上下文 操作系统中,把进程物理实体和支持进程运行的环境合称为进程上下文。 系统调度新进程时,新老进程的上下文将进行切换。\n进程的状态 进程的三种基本状态\n就绪态:已经得到除了CPU以外的其它资源 运行态:占用CPU 阻塞态:正在等待某一事件发生 进程的控制 fork():进程创建。调用者用fork()建立一个子进程和自己独立并发地运行。创建的子进程基本拷贝父进程的上下文(正文段(代码)共享) fork()返回值为-1:进程创建不成功 fork()返回值大于0:在父进程的上下文中,fork()返回值为子进程标识号 fork()返回值等于0:在子进程的上下文中。 wait():进程挂起等待(封锁)。调用者进入封锁状态等待它的子进程终止。 exit():进程终止。调用者将终止自己,并解除父进程的封锁(wait())。 execvp(filename,argp):进程上下文更换。用文件名filename所指定的可执行文件来替换当前进程上下文中的程序和数据部分,并转入执行。 常见代码段 循环创建线程。如果创建不成功(返回值为1),则执行;语句\n1while((i=fork()) == -1); 创建子线程。父线程和子线程将(将开始)同时在这里执行。\n1i=fork(); 判断现在执行的是父线程还是子线程\n1if (i==0) // 子线程 2else // 父线程(i为大于0的进程id) 线程 线程和进程的区别和联系 线程是进程的一部分,它是进程内的一个执行体。 引入线程的操作系统中,资源分配的对象是进程,而不是线程。 引入线程的操作系统中,调度的基本单位是线程而不是进程。 进程之间可以并发执行,而一个进程中的这些线程之间亦可以并发执行。 进程调度,系统需要进行进程上下文的切换,需要大量的系统开销。 线程切换比进程切换快得多。 从一个进程的线程向另一个进程的线程切换,将引起线程的上下文切换。 从安全的角度来看,线程不如进程安全。 线程控制块 在管理线程的时候,同样也使用一种数据结构,称之为线程控制块TCB(Thread Control Block) 线程控制块包含如下信息:\n线程标识信息:系统内唯一的标识符; 线程状态和调度信息 现场信息:主要是CPU内各个寄存器的内容 线程私有存储区:系统栈和用户栈的指针 指向PCB的指针:该线程归属于哪个进程,使用哪个进程的资源。 线程的状态 线程的关键状态有:\n运行态 就绪态 阻塞态 线程的级别 内核级线程 内核线程的建立与销毁都是由操作系统负责 如果一个进程中没有就绪态的线程,这个进程也不会被调度占用CPU。\n用户级线程 用户线程时不能被操作系统感知的。操作系统一如既往地进行进程调度,就像根本没有线程一样。 线程运行库决定运行哪一个用户线程。\n混合式线程 混合式线程中,一个应用中的多个线程能同时在多处理器上并行执行,且阻塞一个线程时并不需要封锁整个进程。\n进程调度 调度的层次 高级调度:建立PCB(存在于早期的操作系统,无内存参与调度) 中级调度:调入调出外存等待(得益于虚拟内存技术,将外存扩充为内存使用)。存在外存的进程为挂起态。 低级调度:内存中选取就绪态的进程占用资源执行 剥夺方式(抢占方式) 非剥夺方式(不可抢占式) 调度的概念 调度算法的分类和目标 所有系统\n公平性 系统策略(调度策略)的强制执行 均衡性:各种类型的进程 批处理系统\n吞吐量 周转时间 CPU利用率 交互式系统\n相应时间 相称性 实时系统:着重于实时提供服务\n截止线 可预测性 批处理系统的调度 先来先服务FCFS(First-Come First-Served):按照作业进入系统后备队列的先后次序挑选作业。属于非剥夺式算法。 最短作业优先SJF(Shortest Job First):以进入系统的作业所要求的CPU时间长短为标准,字面意思。是一种非剥夺式算法。 最短剩余时间优先SRTF(Shortest Remaining Time First):一个作业正在执行时,一个新作业进入就绪态,如果新作业需要的CPU时间比当前正在执行的作业剩余时间短,则新作业抢占并开始执行。是一种剥夺式算法。(称为最短剩余时间优先算法/SRTF算法) 高响应比优先HHRF(Highest Response Ratio First):每当调度一个作业运行时,都要计算后被作业队列中每个队列的响应比,选择响应比最高的投入运行。属于非剥夺式算法。(可能会提高周转时间)响应比 交互式系统的调度 时间片轮转法RR(Round Robin):当一个时间片结束时,强迫一个进程让出CPU,让它排列到就绪队列的尾部,等待下一轮调度。轮转法调度是一种剥夺式调度。 优先级调度(Priority): 静态优先级:在进程创建时即被确定,在以后整个执行期间不再改变。 动态优先级:在进程的执行期间,按照某种原则不断修改进程的优先级。优先级一般随进程的等待时间、CPU占用时间变化。 多级反馈队列MFQ(Multi-level Feedback Queue):多级反馈队列调度算法的主要思想是将就绪进程分为多个级别,系统相应建立多个就绪队列,较高优先级的队列一般分配给较短的时间片。调度程序每次先从高一级的就绪队列中选取可占有CPU的进程,同一队列中按时间片原则排队,只有在该队列为空时,才从较低一级的就绪队列中选取。 相关公式 周转时间相关 $$ 周转时间 = 等待时间 + 执行时间 $$ $$ 平均周转时间 = \\frac{周转时间}{进程数量} $$ 带权周转时间相关 $$ 带权作业周转时间 = \\frac{周转时间}{作业时间} $$\n$$ 平均带权作业周转时间 = \\frac{\\sum_{i=1}^n\\frac{周转时间}{作业时间}}{进程数量} $$\n响应比 $$ 响应比 = \\frac{作业周转时间}{作业估计计算时间} = \\frac{等待时间 + 执行时间}{执行时间} = 1+\\frac{等待时间}{执行时间} $$\n","date":"2022-03-22T23:13:13Z","permalink":"https://www.zhhuu.top/posts/multi-threading-hardware/","section":"posts","tags":["编程"],"title":"进程管理(操作系统)"},{"categories":["Coding"],"contents":"主要是Xaml的“绑定”和“资源”\nXaml静态资源绑定 需要绑定一个resource的时候,需要的表达式就是大括号里面有“StaticResource”,再加上resource的名字。这种绑定只在App运行的时候进行一次,因为是静态资源,所以它就不会变了。 如:\n1\u0026lt;TextBlock Foreground = \u0026#34;{StaticResource MyBrush}\u0026#34; /\u0026gt; StaticResource表明了我们所绑定的资源的类型\n单个属性的绑定 可以创建单个属性的资源绑定,如:\n1\u0026lt;Page.Resources\u0026gt; 2 \u0026lt;SolidColorBrush x:Key=\u0026#34;MyBrush\u0026#34; Color=\u0026#34;Brown\u0026#34;/\u0026gt; 3\u0026lt;/Page.Resources\u0026gt; 4 5\u0026lt;!-- 使用 --\u0026gt; 6\u0026lt;TextBlock Text=\u0026#34;Hello World\u0026#34; Foreground=\u0026#34;{StaticResource MyBrush}\u0026#34;/\u0026gt; 还可以创建值绑定,如将Slider的值绑定到ProgessBar中:\n1\u0026lt;ProgressBar Maximum=\u0026#34;100\u0026#34; Value=\u0026#34;{x:Bind MySlider.Value, Mode=OneWay}\u0026#34;\u0026gt; 多个属性的绑定(Style) 也可以创建多个值类型的绑定,如设置背景、字体、字号等属性,如:\n1\u0026lt;Page.Resources\u0026gt; 2 \u0026lt;Style TargetType=\u0026#34;Button\u0026#34; x:Key=\u0026#34;MyButtonStyle\u0026#34;\u0026gt; 3 \u0026lt;!-- 定义了目标类型、样式(资源)名称 --\u0026gt; 4 \u0026lt;!-- 下面是各个属性值的设置 --\u0026gt; 5 \u0026lt;Setter Property=\u0026#34;Background\u0026#34; Value=\u0026#34;Blue\u0026#34;/\u0026gt; 6 \u0026lt;Setter Property=\u0026#34;FontFamily\u0026#34; Value=\u0026#34;Arial Black\u0026#34;/\u0026gt; 7 \u0026lt;Setter Property=\u0026#34;FontSize\u0026#34; Value=\u0026#34;36\u0026#34;/\u0026gt; 8 \u0026lt;/Style\u0026gt; 9\u0026lt;/Page.Resources\u0026gt; 10 11\u0026lt;Button Content=\u0026#34;My Button Style Example\u0026#34; 12 Height=\u0026#34;100\u0026#34; 13 Style=\u0026#34;{StaticResource MyButtonStyle}\u0026#34; /\u0026gt; 14 \u0026lt;!-- 资源的名称是“MyButtonStyle” --\u0026gt; 属性的继承 使用BasedOn属性 如HeaderTextBlockStyle就是继承自BaseTextBlockStyle 原文引用:\n1\u0026lt;Style x:Key=\u0026#34;HeaderTextBlockStyle\u0026#34; TargetType=\u0026#34;TextBlock\u0026#34; BasedOn=\u0026#34;{StaticResource BaseTextBlockStyle}\u0026#34;\u0026gt; 2 ... 3\u0026lt;/Style\u0026gt; 跨页引用资源 如果要跨页引用属性定义,需要在App.xaml的Application.Resources里面添加定义 在App.xaml中添加定义:\n1\u0026lt;Application.Resources\u0026gt; 2 \u0026lt;!-- 在这里添加属性的定义 --\u0026gt; 3\u0026lt;/Application.Resources\u0026gt; 这样,样式就已经在整个App中定义了。\nResource Dictionary 在Application.Resources中设定的Resource Dictionary(资源字典)可以用于设置\nResources SolidColorBrush Strings Styles StaticResource Control Templates Animation \u0026hellip; 不仅在Page和Application层面可以创建Resource Dictionary,还可以创建名为Merged Resource Dictionary,用于在多个文件中定义Resource Dictionary,以此降低程序的复杂性,并允许在不同的项目中重复使用Dictionary文档。 比如,在项目中创建一个Dictionary1.xaml文件(ResourceDictionary类型),内容如下:\n1\u0026lt;ResourceDictionary 2 xmlns=\u0026#34;\u0026#34; 3 ...\u0026gt; 4 \u0026lt;x:String x:Key=\u0026#34;greeting\u0026#34;\u0026gt;Hello World\u0026lt;/x:String\u0026gt; 5\u0026lt;ResourceDictionary/\u0026gt; 在其它文件中的引用(以Page为例):\n1\u0026lt;Page.Resources\u0026gt; 2 \u0026lt;ResourceDictionary\u0026gt; 3 \u0026lt;ResourceDictionary.MergedDictionaries\u0026gt; 4 \u0026lt;!-- 可以合并多个Dictionary入这个文件,只需要向里面添加 --\u0026gt; 5 \u0026lt;ResourceDicitonary Source=\u0026#34;Dictionary1.xaml\u0026#34;\u0026gt; 6 \u0026lt;ResourceDictionary.MergedDictionaries/\u0026gt; 7 \u0026lt;ResourceDictionary/\u0026gt; 8\u0026lt;Page.Resources/\u0026gt; 使用系统已经构建好的主题 可以直接在Style=\u0026quot;{StaticResource ...}\u0026quot;里面根据IntelliSense查找,或者在控件的属性框内,找到Miscellaneous中的Style,选中System Resource,进行选择。\nXaml非静态资源绑定 ThemeResource ThemeResource和系统主题有关,使用系统主题中的颜色:\n1\u0026lt;!-- 使用系统的主题色 --\u0026gt; 2\u0026lt;Rectangle Fill=\u0026#34;{ThemeResource SystemAccentColor}\u0026#34;\u0026gt; 3\u0026lt;!-- 使用系统的窗口颜色(亮/暗等) --\u0026gt; 4\u0026lt;Rectangle Fill=\u0026#34;{ThemeResource SystemColorWindowColor}\u0026#34;\u0026gt; ","date":"2022-03-16T22:08:15Z","permalink":"https://www.zhhuu.top/posts/xaml-summary/","section":"posts","tags":["C#","编程","后端"],"title":"Xaml学习小结"},{"categories":["Coding"],"contents":"LINQ:语言继承查询\n限制运算符 Where where语句的基本示例\n1int[] numbers = {5,4,1,3,9,8,6,7,2,0}; 2var lowNums = from num in numbers 3 where num \u0026lt; 5 4 select num; // 只选择小于5的数字 筛选符合属性条件的元素\n1var soldOutProducts = from prod in products 2 where prod.UnitsInStock == 0 3 select prod; // 从集合中选出符合属性的元素 用多个条件筛选元素\n1var expensiveInStockProducts = from prod in products 2 where prod.UnitsInStock \u0026gt; 0 \u0026amp;\u0026amp; prod.UnitPrice \u0026gt; 3.00M 3 select prod; // 从集合中选出符合上述两个条件的元素 基于元素在列表中位置的筛选\n1string[] digits = {\u0026#34;zero\u0026#34;, \u0026#34;one\u0026#34;, \u0026#34;two\u0026#34;, \u0026#34;three\u0026#34;, \u0026#34;four\u0026#34;, \u0026#34;five\u0026#34;, \u0026#34;six\u0026#34;, \u0026#34;seven\u0026#34;, \u0026#34;eight\u0026#34;, \u0026#34;nine\u0026#34;}; 2var shortDigits = digits.Where((digit,index) =\u0026gt; digit.Length \u0026lt; index); 3 // 其中,index为元素的位置下标(从0开始),digit为digits的子元素。 以\u0026hellip;开始 使用AutoSuggestBox控件 Xaml:\n1\u0026lt;AutoSuggestBox Name=\u0026#34;MyAutoSuggestBox\u0026#34; 2 QueryIcon=\u0026#34;Find\u0026#34; 3 PlaceholderText=\u0026#34;Search\u0026#34; 4 TextChanged=\u0026#34;MyAutoSuggestBox_TextChanged\u0026#34;/\u0026gt; C#\n1private string[] selectionItems = new string[] {\u0026#34;Ferdinand\u0026#34;, \u0026#34;Nigel\u0026#34;, \u0026#34;Tag\u0026#34;,...}; 2 3private void MyAutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs e) 4{ 5 var autoSuggestBox = (AutoSuggestBox)sender; 6 var fileterd = selectionItems.Where(p =\u0026gt; p.StartWith(AutoSuggestBox.Text)).ToArray(); 7 autoSuggestBox.ItemSource = filtered; 8} 投影(转换)运算符 Select 以下的例子展示了如何用select修改输入的元素序列。\n1int[] numbers = {5,4,1,3,9,8,6,7,2,0}; 2 3var numsPlusOne = from n in numbers 4 select n+1; 选择一个单独的属性\n1var productNames = from p in products 2 select p.ProductName; // 选择了p的ProductName属性 用select进行一些变换\n1int[] numbers = {5,4,1,3,9,8,6,7,2,0}; // 数字序列 2string[] strings = {\u0026#34;zero\u0026#34;, \u0026#34;one\u0026#34;, \u0026#34;two\u0026#34;, \u0026#34;three\u0026#34;, \u0026#34;four\u0026#34;, \u0026#34;five\u0026#34;, \u0026#34;six\u0026#34;, \u0026#34;seven\u0026#34;, \u0026#34;eight\u0026#34;, \u0026#34;nine\u0026#34;}; // 单词序列 3 4var textNums = from n in numbers 5 select strings[n]; // 用数字序列的元素作为下标选择单词序列中的元素 选择匿名类型或元组\n注意:创建新类型的时候,需要使用new关键字\n1string[] words = { \u0026#34;aPPLE\u0026#34;, \u0026#34;BlUeBeRrY\u0026#34;, \u0026#34;cHeRry\u0026#34; }; 2 3var upperLowerWords = from w in words 4 select new { Upper = w.ToUpper(), Lower = w.ToLower() }; 5 // 生成的Upper和Lower里面分别是这些单词的大写和小写版本 6 7// 使用元组的方法(从C#7开始) 8var upperLowerWords = from w in words 9 select new { Upper: w.ToUpper(), Lower: w.ToLower() }; 使用select创建新类型\n1int[] numbers = {5,4,1,3,9,8,6,7,2,0}; // 数字序列 2string[] strings = {\u0026#34;zero\u0026#34;, \u0026#34;one\u0026#34;, \u0026#34;two\u0026#34;, \u0026#34;three\u0026#34;, \u0026#34;four\u0026#34;, \u0026#34;five\u0026#34;, \u0026#34;six\u0026#34;, \u0026#34;seven\u0026#34;, \u0026#34;eight\u0026#34;, \u0026#34;nine\u0026#34;}; // 单词序列 3 4var digitOddEvens = from n in numbers 5 select new { Digit = strings[n], Even = (n % 2 == 0)}; 6 // 创建了两个类型: 7 // Digit:对应数字的单词序列 8 // Even:偶数序列 选择属性的子集 我还没试,Try.NET坏了\u0026hellip;😭\n1var productInfos = from p in products 2 select (p.ProductName, p.Category, Price: p.UnitPrice); 3 4Console.WriteLine(\u0026#34;Product Info:\u0026#34;); 5foreach (var productInfo in productInfos) 6{ 7 Console.WriteLine($\u0026#34;{productInfo.ProductName} is in the category {productInfo.Category} and costs {productInfo.Price} per unit.\u0026#34;); 8} 用元素的index对其进行选择\n1int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2var numsInPlace = numbers.Select((num, index) =\u0026gt; (Num: num, InPlace: (num == index))); 3// 得到的numsInPlace中有Num和InPlace,其中InPlace为num==index的值 在多输入序列中进行选择\n1int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 2int[] numbersB = { 1, 3, 5, 7, 8 }; 3 4var pairs = from a in numbersA 5 from b in numbersB 6 where a \u0026lt; b 7 select (a, b); // 符合条件的(a,b)对(pairs) 8 9Console.WriteLine(\u0026#34;Pairs where a \u0026lt; b:\u0026#34;); 10foreach (var pair in pairs) 11{ 12 Console.WriteLine($\u0026#34;{pair.a} is less than {pair.b}\u0026#34;); 13 // 把所有的a和所有的b逐个进行比较 14} 在相关的输入序列中进行选择\n1var orders = from c in customers 2 from o in c.Orders 3 where o.Total \u0026lt; 500.00M 4 select (c.CustomerID, o.OrderID, o.Total); 5 // cutomers -\u0026gt; c:顾客 6 // c -\u0026gt; c.o:订单(与c相关联) 7 // c.o -\u0026gt; o:订单信息 带有Where的符合选择\n1var orders = from c in customers 2 from o in c.Orders 3 where o.OrderDate \u0026gt;= new DateTime(1998, 1, 1) 4 select (c.CustomerID, o.OrderID, o.OrderDate); Query Syntax 查询语法(分区运算符) Take n.Take(n);获取前n个元素\n1int[] numbers={5,4,3,2,1}; 2var first3Numbers = numbers.Take(3); // First3Numbers是一个集合,有3个数 Take也可以嵌套到其它查询语句中\n1var first3WAOrders = ( 2\tfrom customer in customers 3\tfrom order in cutomer.Orders 4\twhere customer.Region == \u0026#34;WA\u0026#34; 5\tselect (customer.CustomerID, order.OrderID, order.OrderDate) 6\t.Take(3); 7) // 得到前3个 Skip n.Skip(n)跳过前n个元素\n1int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2var allButFirst4Numbers = numbers.Skip(4); 先查询,再在结果中跳过\n1var waOrders = from cust in customers 2 from order in cust.Orders 3 where cust.Region == \u0026#34;WA\u0026#34; 4 select (cust.CustomerID, order.OrderID, order.OrderDate); 5 6var allButFirst2Orders = waOrders.Skip(2); // 查询完毕后,从查询结果中跳过前2个结果 TakeWhile 理解为While循环下的Take()。一旦不符合条件就停止。\n1int[] numbers = {5,4,1,3,9,8,6,7,2,0}; 2var firstNumbersLessThan6 = numbers.TakeWhile(n =\u0026gt; n\u0026lt;6); 3 // 从开始一直Take(),直到n\u0026lt;6的条件不成立 用index作为条件的TakeWhile\n1int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2var firstSmallNumbers = numbers.TakeWhile((n, index) =\u0026gt; n \u0026gt;= index); SkipWhile 以下例子只显示分数小于80的成绩。\n1int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; 2 3IEnumerable\u0026lt;int\u0026gt; lowerGrades = 4 grades 5 .OrderByDescending(grade =\u0026gt; grade) 6 .SkipWhile(grade =\u0026gt; grade \u0026gt;= 80); 7 8Console.WriteLine(\u0026#34;All grades below 80:\u0026#34;); 9foreach (int grade in lowerGrades) 10{ 11 Console.WriteLine(grade); 12} 13 14// This code produces the following output: 15 16// All grades below 80: 17// 70 18// 59 19// 56 使用n和index进行筛选\n1int[] amounts = { 5000, 2500, 9000, 8000, 2 6500, 4000, 1500, 5500 }; 3 4IEnumerable\u0026lt;int\u0026gt; query = 5 amounts.SkipWhile((amount, index) =\u0026gt; amount \u0026gt; index * 1000); 6 7foreach (int amount in query) 8{ 9 Console.WriteLine(amount); 10} 11 12 13// This code produces the following output: 14 15// 4000 16// 1500 17// 5500 排序运算符 orderby 升序 升序:0,1,2,\u0026hellip; 使用orderby根据宠物年龄进行升序排序\n1class Pet 2{ 3 public string Name { get; set; } 4 public int Age { get; set; } 5} 6 7public static void OrderByEx1() 8{ 9 Pet[] pets = { new Pet { Name=\u0026#34;Barley\u0026#34;, Age=8 }, 10 new Pet { Name=\u0026#34;Boots\u0026#34;, Age=4 }, 11 new Pet { Name=\u0026#34;Whiskers\u0026#34;, Age=1 } }; 12 13 // Sort the Pet objects in the array by Pet.Age. 14 IEnumerable\u0026lt;Pet\u0026gt; query = 15 pets.AsQueryable().OrderBy(pet =\u0026gt; pet.Age); 16 17 foreach (Pet pet in query) 18 Console.WriteLine($\u0026#34;{pet.Name} - {pet.Age}\u0026#34;); 19} 20 21// This code produces the following output: 22 23// Whiskers - 1 24// Boots - 4 25// Barley - 8 orderby descending 使用orderby和descending关键字对数字进行降序排序。\n1double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 }; 2 3var sortedDoubles = from d in doubles 4 orderby d descending // 注意descending的用法 5 select d; 6 7Console.WriteLine(\u0026#34;The doubles from highest to lowest:\u0026#34;); 序列操作 EqualAll 如果两个序列相同,返回True\n1var wordsA = new string[] { \u0026#34;cherry\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;blueberry\u0026#34; }; 2var wordsB = new string[] { \u0026#34;cherry\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;blueberry\u0026#34; }; 3 4bool match = wordsA.SequenceEqual(wordsB); 5 6Console.WriteLine($\u0026#34;The sequences match: {match}\u0026#34;); //True 7// 如果以上两个序列中的元素顺序进行了调换,输出值则为False Zip 1int[] vectorA = { 0, 2, 4, 5, 6 }; 2int[] vectorB = { 1, 3, 5, 7, 8 }; 3 4int dotProduct = vectorA.Zip(vectorB, (a, b) =\u0026gt; a * b).Sum(); 5 // 把A中的元素和B中的对应元素进行操作。 6 // Sum()为求和 7 8Console.WriteLine($\u0026#34;Dot product: {dotProduct}\u0026#34;); 9// Dot product:109 Query(查询)执行模式 懒惰执行 如果数据经常变化,可以考虑使用“懒惰查询”,需要时再进行查询。\n1int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2 3int i = 0; 4var q = from n in numbers 5 select ++i; //i: 0 → 1 6 7// Note, the local variable \u0026#39;i\u0026#39; is not incremented 8// until each element is evaluated (as a side-effect): 9// 直到每个值被使用时才执行++i 10foreach (var v in q) 11{ 12 Console.WriteLine($\u0026#34;v = {v}, i = {i}\u0026#34;); 13 // ++i在这里才被执行并存入v中。 14 // 这里的i是原来的i(int i=0时定义的) 15} 如果把foreach再完整执行一遍,v和i的值将会到达20\n急迫执行 当数据不会变时使用“急迫执行”,因为再次查询数据也不会变。\n1// Methods like ToList() cause the query to be 2// executed immediately, caching the results. 3// 类似ToList()的方法可以使query立即执行。 4 5int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 6 7int i = 0; 8var q = (from n in numbers 9 select ++i) 10 .ToList(); 11 12// The local variable i has already been fully 13// incremented before we iterate the results: 14// 在输出结果之前,++i已经全部执行完了 15foreach (var v in q) 16{ 17 Console.WriteLine($\u0026#34;v = {v}, i = {i}\u0026#34;); 18} 如果把foreach再完整执行一遍,i的值仍然全为10,v的值也不变\n","date":"2022-03-12T16:29:27Z","permalink":"https://www.zhhuu.top/posts/linq/","section":"posts","tags":["C#","编程","后端"],"title":"LINQ笔记\u0026实例"},{"categories":["Skills"],"contents":"VSCode多行光标功能的使用\n参考 Visual Studio Code Basics: This topic takes you through the basics of the editor and helps you get moving with your code StackOverflow: Multiline editing in Visual Studio Code 多行光标的使用 用键盘使用多行光标 快捷键 作用 Ctrl+D 选择下一个匹配的内容 Ctrl+U 撤销上一个光标操作 Esc 取消多行选择 Ctrl+Backspace 智能删除 使用 Ctrl+D 时,右上角的小部件,从左到右依次是: 区分大小写 Alt+C、全字匹配 Alt+W、使用正则表达式 Alt+R\nCtrl+Shift+P 能够呼出万能指令窗口\nCtrl+Shift+P 指令 作用 Cursor Undo 撤销光标操作 Cursor Redo 重做光标操作 用鼠标使用多行光标 有时候可能会想要跳过某一个位置,这时使用Ctrl+D就难以做到。使用鼠标控制会令多行光标的使用更灵活。(比如说跳过注释部分的“:”)\n使用方法 按住 Alt 并点击\n多行光标特性 合并 当两个光标移动到重合时,会自动合并。例如下面的删除: 有时候在一行中分布有很多光标,当用 Ctrl+← 将光标置于行开头的时候,也会因此自动合并。 这个特性可以在VSCode选项中关闭,默认开启。\n复制粘贴 Ctrl+← 或者 Ctrl+→ 是智能移动。当另外按下 Shift 的时候还会对文本进行选择。\n当多行光标选中多项复制以后,粘贴会逐行粘贴选中的内容。 当有多行光标时,每个光标都会逐行粘贴之前多行复制的内容。 但是,如果光标数量和复制的时候一致,粘贴时会在相应的位置粘贴。多行复制粘贴同理。 在上面/下面插入光标 Ctrl+Alt+↑ 或者 Ctrl+Alt+↓ ,上就是向上选择,下就是向下选择\n方形选(Column (box) selection) 先正常选择,再按住 Alt+Shift\n扩大、缩小选择区域 Shift+Alt+Left 和 Shift+Alt+Right\n添加光标到顶部、底部,在行尾添加光标 Ctrl+Shift+P\nAdd Cursors To Top Add Cursors To Bottom Add Cursors To Line Ends Alt+Shift+l 适用于HTML的快速输入 ","date":"2021-07-11T15:00:42Z","permalink":"https://www.zhhuu.top/posts/vscode-multicursor/","section":"posts","tags":["前端","快捷键"],"title":"VSCode多光标输入"},{"categories":["Skills"],"contents":"在npm中,包(package)、模块(module)、依赖(dependency)都是一个东西。\nnpm常用操作 npm配置项 初始化 npm init(其实就是创建一个package.json文件),之后让你填入许多信息(package name, version, description, entry point, test command, git repository, key words, author) npm init -y相当于npm init但信息都为空,初始化后npm会认为你的项目是一个包\nnpm搜索 npm search \u0026lt;包名\u0026gt; 如:npm search jquery\n包安装 操作 命令 直接安装 npm install \u0026lt;包名\u0026gt;,简写为npm i \u0026lt;包名\u0026gt; 安装指定版本/旧版本 npm install \u0026lt;包名\u0026gt;@\u0026lt;版本号\u0026gt; 安装指定tag的包 npm install \u0026lt;包名\u0026gt;@\u0026lt;tag\u0026gt; 参数 -g 安装到全局环境下,这样在任何一个目录下都能识别,比如 npm install npm@latest -g 参数 --save-dev或者-D 表明是开发环境下的依赖,不会在生产环境中出现 包卸载 npm uninstall \u0026lt;包名\u0026gt; -D 卸载包,并从package.json的devDependencies中删除。 老版本的npm中卸载包要加--save才能保存到package.json中\n常用操作 操作 命令 更新包 npm update \u0026lt;包名\u0026gt;,局部更新。加-g全局更新 列出已安装包 npm list默认列出局部依赖。加-g 列出已安装的全局依赖。 检查过期包(依赖) npm outdated 查看依赖安装路径 npm root,也就是node_modules的路径,加-g查看全局安装路径 查看模块的注册信息 npm view \u0026lt;包名\u0026gt; versions,列出所有版本。\nnpm view \u0026lt;包名\u0026gt; dependencies,列出所有依赖 使用npm的优势 以引用jQuery为例,先新建html文件。\n以往的工作流\n搜索jQuery的网络CDN 在html文件中插入\u0026lt;script src='\u0026lt;网络CDN地址\u0026gt;'\u0026gt;\u0026lt;/script\u0026gt;引用jQuery。 利用npm的工作流\n命令行进入工作目录,进行npm init npm i jquery,npm自动将文件安装到目录下的node_modules文件夹中。 node_modules文件夹中找到jquery.js,在html文件中插入\u0026lt;script src='\u0026lt;node_modules中jquery的位置\u0026gt;'\u0026gt;\u0026lt;/script\u0026gt;进行引用 好处:就算删掉node_modules也没关系,因为依赖信息已经写到项目文件夹中的package.json中(dependencies)。只需要运行npm i就会重新安装上。\n更改源 npm config ls 查看你的 npm 配置 淘宝仓库源和npm仓库源每10分钟同步一次,基本满足你的需求 淘宝: npm config set registry https://registry.npm.taobao.org/ 官网: npm config set registry http://www.npmjs.org\n","date":"2021-07-10T19:13:03Z","permalink":"https://www.zhhuu.top/posts/npm-overview/","section":"posts","tags":["前端","后端","js"],"title":"npm快速上手"},{"categories":["Skills"],"contents":"git是版本控制系统。应用最为广泛,适用于中小项目。本身是命令行工具。 GitKraken图形化客户端,界面漂亮,功能全面。\n🔗链接\nGitKraken Git的基本概念和操作 代码仓库(Repository) 创建一个代码仓库(Repository),可以是本地仓库,也可以是保存在远程服务器上的仓库。仓库之间可以相互同步。 显示代码的所有提交历史,其中每项代表一个提交(Commit),提交相当于检查点或者快照。对代码作出修改后可以提交这次修改,Git会保存当前的代码快照,之后可以轻松回溯到这里。 新建代码仓库的时候会自动创建一个提交。 选中提交后可以看到所有修改的文件。\nGitKraken 中打开git目录可以点击“文件”-“在文件浏览器中打开”,找到代码仓库在本地计算机上存放的位置\n作出更改后文件历史中多出 //WIP (Work In Progress),代表这个提交正在施工中。 Git要求在提交修改的文件前要对它们先 Stage,点击Stage。Stage可看作提交前防止误操作。其中必填本次提交的描述。最后\u0026quot;Commit\u0026quot;完成提交,这里的提交还是在本地计算机的提交。 如果要远程提交到代码仓库,就需要 \u0026ldquo;Push\u0026quot;s,推送提交即可。\n拉取(Pull) 从远程服务器 拉取(Pull) 提交 提交历史会多出来一条。master和电脑图标的标签表示本地仓库的提交,上面的表示Github上的远程仓库提交(master是分支)。(origin通常代表远程仓库)。如果想把远程提交同步到本地仓库只需要点击**\u0026ldquo;Pull\u0026rdquo;**。点击后两个图标重合在一起,代表远程仓库和本地仓库的提交历史已经完全相同。\n合并(Merge) 两边同时作出了修改后提交历史会产生分叉 如果想要将两个修改同时应用在本地仓库中,需要合并。Pull的时候会自动合并远程提交到本地的提交中。Pull后Git会自动生成一个新提交。 如果同时修改代码的同一处位置,再次Pull的时候,会自动合并失败,需要手动合并冲突(Conflict)的部分。 下面的窗口用于手动解决冲突 最终完成提交 提交改写(Amend) 用于提交代码有误或者提交信息出错,对已提交的文件和信息进行修改。在提交前勾选Amend后正常提交。这个操作只会修改已经存在的提交。但是最好本地使用。\n分支(Branch) 创建一个新分支,点击Branch按钮。创建好后分支的提交历史和原来相同,但是往后的提交会相互独立。默认只会推送master分支到远程服务器,如果要推送其他分支,点右键然后选择Push。\n合并分支(Merge Branches) 将test合并到master上,先双击切换到master分支,在test分支上右键点“合并test分支到master分支”。(可能需要手动解决代码冲突)\n暂存(Stash) 暂存当前的修改,源代码会被还原到之前的状态,可以进行其他操作。 最后可以通过Pop将暂存的代码恢复出来,甚至可以切换到很老的版本将暂存的修改恢复出来。\n变基(Rebase) 在合并分支的过程中,会将整个分支摘取下来,嫁接到另一个分支上(改变了原有的基底)。相比Merge,Merge的优点在于原先的提交历史会被完整地保留下来。 比如将test分支变基到master分支,先选择test分支,右键选择“将test分支变基到master分支上”,完成操作。最后将master分支指向最新的提交,这样master分支的内容才是最新的。(用到Fast Forward)\n快进(Fast Forward) 直接让master的指针快进到test分支。\n签出(Checkout) 回退到早期的版本完成一些bug的修复。在想要回到的节点上右键点击签出,此时Head标签指向当前提交。 修改完后提交是基于早期的提交,最后可以将其变基到当前的提交上,变基完成后提交会变成一条直线。\n撤销操作(Undoing) 常用于在Git中错误提交了代码或者错误合并了一个分支。得益于每次的操作都记录在Reflog的类似日志的文件里,能够帮你轻松回退之前的状态。GitKraken中就是状态栏中的undo操作。包括分支切换、合并、修改甚至删除等等。\n恢复(Revert) 常用于撤销已提交的代码(远程)。在GitKraken中在提交上点右键,Git会创建一个完全相反的提交以恢复。\n图形化界面对应的命令行命令 第一部分(常用基础部分) 配置基本用户信息 git config --global user.name \u0026lt;用户名\u0026gt; git config --global user.email \u0026lt;邮箱地址\u0026gt;\n创建一个新仓库 git init\n从远程服务器克隆一个仓库 git clone \u0026lt;远程仓库url\u0026gt;\n显示当前的工作目录下的提交文件的状态 git status\n将指定文件Stage(标记为将要被提交的文件) git add \u0026lt;文件路径\u0026gt;\n将指定文件Unstage(取消标记为将要被提交的文件) git reset \u0026lt;文件路径\u0026gt;\n创建一个提交并提供提交信息 git commit -m \u0026quot;提交信息\u0026quot;\n显示提交历史(类似GitKraken中间窗口的提交历史) git log\n向远程仓库推送(Push) git push\n从远程仓库拉去(Pull) git pull\n第二部分(基础进阶部分) 修改(Amend)上一个提交 git commit --amend -m \u0026lt;新的提交信息\u0026gt;\n查看所有分支 git branch\n创建新的分支 git branch \u0026lt;分支名字\u0026gt;\n切换分支 git checkoout \u0026lt;分支名字\u0026gt;\n重命名分支 git branch -m \u0026lt;旧名字\u0026gt; \u0026lt;新名字\u0026gt;\n删除分支 git branch -d \u0026lt;分支名字\u0026gt;\n将分支变基(Rebase)到master\n注:需要先切换到分支后,再完成变基\ngit checkout \u0026lt;分支名字\u0026gt; git rebase master\n使用快进(Fast-Forward)将分支合并到master git checkout \u0026lt;分支名字\u0026gt; git merge -ff-only master\n中止这一次提交的合并(当遇到冲突时) git merge --abort\n将未提交的修改暂存(Stash) git stach save \u0026quot;\u0026lt;可以输入一个信息\u0026gt;\u0026quot;\n将上一个暂存的修改恢复并从暂存列表中删除 git stash pop\n签出指定的提交 git checkout \u0026lt;提交的hash\u0026gt;\n撤销旧的提交\n注:Revert并不会修改旧的提交历史,而是在工作树中生成一个与之前提交完全相反的修改。\ngit revert \u0026lt;旧提交的hash\u0026gt;\n利用reflog查看本地仓库中的所有操作 git reflog\n","date":"2021-07-09T20:56:37Z","permalink":"https://www.zhhuu.top/posts/git-basic/","section":"posts","tags":["git","前端","后端","feature"],"title":"利用Gitkraken了解Git"},{"categories":null,"contents":"简单介绍下两种设计风格:波普(POP)风格和孟菲斯风格(Memphis)\n波普风格 波普艺术被定义为:大众传播媒介的形式与技巧,并以人们日常生活中随处可见的广告、大众传媒与通俗文化中的形象为主题的艺术创作。\n特征 波普本身颠覆了人们对艺术的印象,而总结波普的特点,可以归纳为以下三个:\n通俗化 波普模糊了艺术和非艺术、现存品和艺术品、精英文化与大众文化、高雅与低俗之间的界限,把艺术从神坛上拉下来,成为所有人都可享受之物。\n商业化 波普艺术的重要特点就是将着眼于日趋发达的商业流行文化,用极为通俗化的方式直接表现物质生活,强调消费主义与物质主义。\n形式主义 波普艺术的作品追求别具一格外形,装饰,追求纯粹的视觉快感,希望新颖多样的艺术表现形式来反抗现代主义的“无趣、无聊、一成不变”。\n表现手法 元素:借用大众传媒和日常生活物品 在波普艺术中,常常会借用广告、商业、流行文化图像,以及名人或者虚构人物形象来作为主要视觉资源,因此来呈现消费型社会具有的各种杂乱表象。\nAndy Warhol的金宝汤(Campbell\u0026rsquo;s Soup Cans)\n手法:拼接、覆盖、粘贴、重复 波普的重要特质之一就是能够通过不同的载体和复制形式体现出趣味。 Tom Wesselmann的静物拼贴作品\n色彩 波普的作品中通常更注重色彩表现的刺激性效应。例如使用高度饱和的色彩,以及强化无彩色系(黑白灰)与有彩色系之间的对比张力,营造一种强烈而廉价的色彩感,并同时用来暗示物质主义对人们的诱惑。 Keith Haring\n美国波普代表艺术家 安迪·沃霍尔(Andy Warhol):色彩组合、质感 凯斯·哈林(Keith Haring):涂鸦风格 罗伊·里奇特斯坦(Roy Lichtenstein):漫画风格 孟菲斯风格 风格介绍 孟菲斯风格最早形成于1981年,是由一群意大利籍家具设计师探索出来的一种装饰艺术的设计风格。他们反对单调冷峻的现代主义,提倡装饰,强调手工艺方法制作的产品,并积极从波普艺术、东方艺术、非洲拉美的传统艺术中寻求灵感。\n上个世纪70年代,非常流行极简主义和现代主义,物极必反,不会有一种设计风格永远流行,总有人看多了没有装饰性、没有个性化的设计风格,厌倦了单调冷峻的现代主义,所以才有了孟菲斯风格的诞生。孟菲斯的兴起可以说是“装饰主义”的复苏。\n特点 而要追究到底是什么造就了这种引人注目的设计风格,则必须追溯到孟菲斯设计师们的设计主张:\n反对“功能主义”的设计理念 无限制的材料使用 强调个性化的装饰 无限制的材料使用 孟菲斯设计师们认为材料是一种积极交流感情的媒介,因此孟菲斯对于材料的态度是感性而非理性的,他们不考虑材料的真实感,不管是大理石、木材还是塑料像,在孟菲斯设计师看来都无区别。他们看重的是材料的表现力,例如材料的肌理、花纹、色彩、浓度、透明度、发光度、反光率等等。例如孟菲斯很喜欢当时被认为很“俗气”的材料——三聚氰胺塑料胶合板,用表达朝气蓬勃,活泼向上的生活态度。\n强调个性化的装饰 在装饰方面,孟菲斯一直抵制现代主义的“装饰即罪恶”、“少即是多”理论,总是在设计中表现富有个性的设计形式和文化涵义。\n孟菲斯的美学灵感主要汲取自装饰艺术和波普艺术,在设计中通常采用抽象图案来作为装饰元素,使它布满产品表面,变产品的静态为活跃的动态结构。而且在色彩方面,反现代主义设计规定的色彩学法则和配色规律而行,喜欢采用色调差别很大的色块并列,产生一种颤动的视觉效果,甚至不惜互相干扰,以创造一种风趣、滑稽、诙谐、戏谑的后现代情调,造成亦庄亦谐的效果。\n现代孟菲斯的特征:\n高饱和度的颜色 重复的几何图形 黑色粗描边 孟菲斯风格在色彩上,常常打破配色规律,喜欢用一些靓丽、纯度高、大胆、对比强烈的配色,借鉴了波普艺术的配色。\n在排版上,元素之间没有过多的联系,元素的排列常常无规律可循,正是因为无规律可循,跳跃的色彩和元素运用得好,反而更能吸引人的眼球,但是要做到“形散神不散”,构图上一定要保持平衡,这是做好孟菲斯风格的必要条件。\n孟菲斯风格还有一个很明显的特点,就是运用大量的几何元素,点、线、面综合运用。规则的几何图形有圆形、三角形、矩形、圆环、波浪线、网格、斜杠等等,不规则的几何图形也是由点、线、面拼贴而成。把这些规则的几何图形和不规则的几何图形排列好,再加上大胆跳跃的配色,就可以做出孟菲斯风格了。\n应用 孟菲斯风格最初是运用于室内设计比较多。后来由于孟菲斯风格在设计上比较大胆,比较吸引人眼球,适合做招贴、海报,慢慢地也运用在了平面设计当中。\n","date":"2021-05-20T12:21:56Z","permalink":"https://www.zhhuu.top/posts/two-design-style/","section":"posts","tags":["设计"],"title":"两种设计风格"},{"categories":null,"contents":"迅哥儿快被踢出课本了,这都是各种鲁迅名言的摘抄🤣\n沉默和孤独 惟沉默是最高的轻蔑。——《且介亭杂文附集》\n猛兽总是独行,牛羊才成群结队。\n当我沉默的时候,我觉得很充实,当我开口说话,就感到了空虚。\n楼下一个男人病得要死,那间隔壁的一家唱着留声机,对面是弄孩子。楼上有两人狂笑;还有打牌声。河中的船上有女人哭着她死去的母亲。人类的悲欢并不相通,我只觉得他们吵闹。——《而已集•小杂感》\n这4句是鲁迅说沉默和孤独的,嗯,我们迅哥儿还是有点傲娇的。因此愿意独行,不想像新月派、鸳鸯蝴蝶派的“牛羊”一样成群结队。\n工作 哪里有什么天才,我只是把别人喝咖啡的时间用在工作上了。\n伟大的成绩和辛勤劳动是成正比例的,有一分劳动就有一分收获,日积月累,从少到多,奇迹就可以创造出来。\n这两句说明,鲁迅其实也是工作狂,每周996,相信一分耕耘一分收获,把喝咖啡的时间都用在了写作上,所以才著作等身,成为近现代作家中的第一大咖(或许只有胡适才能齐名)\n情 待我成尘时,你将见我的微笑。\n无情未必真豪杰,怜子如何不丈夫。\n渡尽劫波兄弟在,相逢一笑泯恩仇。\n友谊是两颗心真诚相待,而不是一颗心对另一颗心的敲打。\n人生得一知已足矣,斯世当以同怀视之。\n我寄你的信,总要送往邮局,不喜欢放在街边的绿色邮筒中,我总疑心那里会慢一点。\n这6句话可以归为一类:迅哥儿看感情——儿女之情、兄弟之情和朋友之情。我们的教材,经常把鲁迅塑造成头发如钢针、横眉冷对千夫指的刚毅硬汉,其实迅哥儿也有自己温柔的一面。上面5句话,就表达了迅哥儿作为暖男的一面,不管是对朋友、兄弟还是妻儿,都有无限柔情。\n责任和担当 无穷的远方,无数的人们,都与我有关。\n必须敢于正视,这才可望敢想,敢说,敢做,敢当。\n我们自古以来,就有埋头苦干的人,有拼命硬干的人,有为民请命的人,有舍身求法的人。虽是等于为帝王将相作家谱的所谓“正史”,也往往掩不住他们的光辉,这就是中国的脊梁。\n愿中国青年都摆脱冷气,只是向上走,不必听自暴自弃者流的话。能做事的做事,能发声的发声。有一分热,发一分光,就令萤火一般,也可以在黑暗里发一点光,不必等候炬火。此后如竟没有炬火:我便是唯一的光。倘若有了炬火,出了太阳,我们自然心悦诚服的消失,不但毫无不平,而且还要随喜赞美这炬火或太阳;因为他照了人类,连我都在内。\n中国的孩子,只要生,不管他好不好,只要多,不管他才不才,生他们的人,不负教他的责任。虽然“人口众多”这一句话,很可以闭了眼睛自负,然而这许多人口,便只在尘土中辗转,小的时候,不把他当人,大了以后也做不了人。——《随感录廿五》\n杂谈 谣言世家的子弟是以谣言杀人,也以谣言被杀的。\n讽刺和冷嘲只隔一张纸,有趣和肉麻也一样。\n悲剧将人生的有价值的东西毁灭给人看,喜剧将那无价值的撕破给人看。\n若举世唯科学是崇,则人生必将归于枯寂。\n我之所谓生存,并不是苟活,所谓温饱,不是奢侈,所谓发展,也不是放纵。\n面具戴太久,就会长到脸上,再想揭下来,除非伤筋动骨扒皮。\n人生最苦痛的是梦醒了无路可走,做梦的人是幸福的;倘没有看出可走的路,最要紧的是不要去惊醒他。\n有缺点的战士终竟是战士,完美的苍蝇也终竟不过是苍蝇。 ——《战士和苍蝇》\n这些话不太好归类,干脆就全放一起,就叫鲁迅杂谈吧。迅哥儿杂文写得多,这些名言就算迅哥儿杂谈好了。\n创新 从来如此,便对么?\n其实地上本没有路,走的人多了,也便成了路。\n同是不满于现状,但打破现状的手段却不同:一是革新,一是复古。\n从原虫到人类,从野蛮到文明,就因为没有一刻不在革命。\n既然像螃蟹这样的东西,人们都很爱吃,那么蜘蛛也一定有人吃过,只不过后来知道不好吃才不吃了,但是第一个吃螃蟹的人一定是个勇士。\n这一类名言,主题都指向了一个点:创新(不守旧)。\n抨击黑暗 中国人的性情是总喜欢调和折中的,譬如你说,这屋子太暗,须在这里开一个窗,大家一定不允许的。但如果你主张拆掉屋顶他们就来调和,愿意开窗了。\n我独不解中国人何以于旧状况那么心平气和,于较新的机运就这么疾首蹙额;于已成之局那么委曲求全;于初兴之事就这么求全责备? ——《这个与那个》\n一见短袖子,立刻想到白臂膊,立刻想到全裸体,立刻想到生殖器,立刻想到性交,立刻想到杂交,立刻想到私生子。中国人的想象惟在这一层能够如此跃进。\n一部《红楼梦》,单是命意,就因读者的眼光而有种种:经学家看见《易》,道学家看见淫,才子看见缠绵,革命家看见排满,流言家看见宫闱秘事。\n我翻开历史一查,这历史没有年代。歪歪斜斜的每页上都写着“仁义道德”几个字,我横竖睡不着,仔细看了半夜,才从字缝里看出来,满本上都写着两个字“吃人”!\n中国一向就少有失败的英雄,少有韧性的反抗,少有敢单身鏖战的武人,少有敢抚哭叛徒的吊客;见胜兆则纷纷聚集,见败兆则纷纷逃亡。\n他们这群人,又想吃人,又是鬼鬼祟祟,想法子遮掩,不敢直截下手,真要令我笑死。我忍不住,便放声大笑起来,十分快活。自己晓得这笑声里面,有的是义勇和正气。——《狂人日记》\n但究竟是夷人可恶,偏要讲什么科学。科学虽然给我们许多惊奇,但也搅坏了我们许多好梦。——《春末闲谈》\n群众,尤其是中国的——永远是戏剧的看客。牺牲上场,如果显得慷慨,他们就看了悲壮剧;如果显得觳觫,他们就看了滑稽剧。北京的羊肉铺常有几个人张嘴看剥羊,仿佛颇为愉快,人的牺牲能给他们的益处,也不过如此。而况事后走不几步,他们并这一点也就忘了。 ——《娜拉走后怎样》\n真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血。这是怎样的哀痛者和幸福者?然而造化又常常为庸人设计,以时间的流驶,来洗涤旧迹,仅使留下淡红的血色和微漠的悲哀。在这淡红的血色和微漠的悲哀中,又给人暂得偷生,维持着这似人非人的世界。我不知道这样的世界何时是一个尽头!——《纪念刘和珍君》\n这一类就不用我多说了,作为成天怼天怼地怼空气的迅哥儿,最喜欢怼的就是民族劣根性了。以上,都是怼民族劣根性的。虽然当下也有很多粪青,但,这些粪青只是“愤”,却不知“情”,也就是不能从根子里了解问题所在。像迅哥儿这般,既“愤”,又能鞭辟入里,直指要害的,太少了。所以,大师永远是大师,路人甲只是路人甲。\n结尾 于浩歌狂热之际中寒;于天上看见深渊。于一切眼中看见无所有;于无所希望中得救。——鲁迅\n","date":"2021-03-05T23:13:51Z","permalink":"https://www.zhhuu.top/posts/luxun-sayings/","section":"posts","tags":["文章"],"title":"鲁迅名言"},{"categories":["Skills"],"contents":"hexo版本太旧,将hexo从3.9.0升级到5.4.0 以前尝试了几次,这次终于成功了(把所有问题都解决了)\n升级前后版本变化 升级前\n1hexo: 3.9.0 2hexo-cli: 4.2.0 升级后\n1hexo: 5.4.0 2hexo-cli: 4.2.0 3uv: 1.33.1 升级操作 先运行了npm update查看了一下有没有需要升级的软件,我这边提示有需要升级的软件,所以手动升级了一下\n然后是正经的检查更新\n1npm install -g npm-check 2npm install -g npm-upgrade 后面看来好像还是npm-check更有用一点🤣 分别执行\n1npm-check 2npm-upgrade 其中npm-check占用资源比较多,耗时比较久。最后是通过提示的 npm-check -u 完成升级\n问题解决 由于主题比较老旧,多年没有更新,但是又很喜欢,所以我一直都在魔改并解决问题。\n遇到的问题 在执行hexo操作的时候总会弹出错误\nWARN Deprecated config detected: \u0026ldquo;external_link\u0026rdquo; with a Boolean value is deprecated. See https://hexo.io/docs/configuration for more details.\n主题底部的换页按钮样式失效,直接显示html源码\n本来升级hexo的目的是想尝试修复页面中h3存在时,目录错位显示错误的问题,但是升级后也还是没有解决\u0026hellip;\n[+]那个好像就是一个奇怪的bug也不知道怎么修复,下次注意标题层次好像就没什么大问题了😂\n解决方法 _config.yml文件中的external_link改为external_link.enable,详见 https://hexo.io/docs/configuration#Writing\n主题底部换页显示错误,找到主题文件中的index.ejs中的paginator部分,添加escape:false(记得在上一行最末尾加逗号)。再hexo clean并hexo g应该就能解决\n","date":"2021-02-21T23:25:49Z","permalink":"https://www.zhhuu.top/posts/hexo-update/","section":"posts","tags":["hexo"],"title":"Hexo升级记录"},{"categories":["Skills"],"contents":"尝试了 docker 的一些常用操作\n查看正在运行的容器 查看正在运行的容器 docker ps\n如果 docker 没有运行,则会显示错误\n查看所有容器 docker ps -a\n建立容器 docker run ubuntu -it\n参数 作用 -i 与容器互动(类似 ssh,可以输入指令) -t 创造一个终端 容器常用操作 本地容器操作容器: 运行但不进入: docker start [容器ID/容器ID开头的几个字]\n进入容器: docker attach [容器ID/容器ID开头的几个字]\n离开容器: Ctrl+P Ctrl+Q\n停止容器: docker stop [容器ID/容器ID开头的几个字]\n查看已经下载到本地的容器: docker image ls 移除本地容器: docker rm [容器名称]\n移除本地镜像: docker rmi [镜像名称]\n镜像名称在 REPOSITORY 下\n新建容器 搜索镜像从 Docker Hub 下载\ndocker run (参数) [容器名称]\n参数 作用 --name [name] 更改容器名称 -d 运行成 Detached 模式 -p [端口]:[容器端口] 端口映射 -v [路径]:[容器路径] 文件映射。将电脑的文件映射入容器 第一次使用的镜像会自动从 Docker Hub 下载\n假设要开启 ngnix 服务器: 跳转到目标目录,运行docker run --name web-server -d -p 8000:80 -v $(pwd):/usr/share/ngnix/html\n自建镜像 查看更改: docker diff [容器名称]\n标识 含义 A 新增档案 C 更新档案 D 删除档案 生成镜像: docker commit 容器ID [镜像名称]\n建议命名方式 [username]/[image-name]:[version]\n启用镜像: 需要进入容器: docker run -it [镜像名称]\n只需要执行命令: docker run [包名] [命令]\n","date":"2021-01-23T17:34:33Z","permalink":"https://www.zhhuu.top/posts/docker-startup/","section":"posts","tags":["树莓派","docker","linux","安装","后端","系统"],"title":"初探Docker"},{"categories":null,"contents":"重新刷入系统进行各项设置安装\n系统下载安装 有3个系统可以选择\nRaspbian Ubuntu:默认账号ubuntu,密码ubuntu,进入后会要求修改密码 OPENFANS Raspbian:一个由Debian重新构建的系统 软件源 修改apt软件源 备份软件源后对其进行修改 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak\n在这里使用清华tuna源 在 ARM(arm64, armhf)、PowerPC(ppc64el)、RISC-V(riscv64) 和 S390x 等架构的设备上(对应官方源为ports.ubuntu.com)使用 ubuntu-ports 镜像。\n1# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 2deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal main restricted universe multiverse 3# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal main restricted universe multiverse 4deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse 5# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse 6deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse 7# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse 8deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse 9# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse 10 11# 预发布软件源,不建议启用 12# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-proposed main restricted universe multiverse 13# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-proposed main restricted universe multiverse 修改pip/pip3源 这里发现清华源好像就不太好用了,下载安装的时候我看都用的是阿里的源。但是可以先配置上: 1.创建.pip文件夹\n1mkdir ~/.pip 2vim ~/.pip/pip.conf 2.创建pip.conf配置文件\n1[global] 2index-url = https://mirrors.aliyun.com/pypi/simple/ 3 4[install] 5trusted-host=mirrors.aliyun.com 文件内容来自 阿里云 - pypi镜像\nVim 新建vim配置文件 vim ~/.vimrc\nvim配置\n1syntax enable \u0026#34;自动检测语法 2syntax on \u0026#34;自动语法高亮 3set number \u0026#34;显示行号 4colorscheme industry \u0026#34;设定配色方案 5set guifont=Consolas:h12:cANSI \u0026#34;英文字体 6set guifontwide=SimSun-ExtB:h12:cGB2312 \u0026#34;设置文字宽度 7set tabstop=4 \u0026#34;表示Tab代表4个空格的宽度 8set expandtab \u0026#34;表示Tab自动转换成空格 9set autoindent \u0026#34;表示换行后自动缩进 10set autoread \u0026#34;当文件在外部被修改时,自动重新读取 11set history=400 \u0026#34;vim记住的历史操作的数量,默认的是20 12set nocompatible \u0026#34;使用vim自己的键盘模式,而不是兼容vi的模式 13set confirm \u0026#34;处理未保存或者只读文件时,给出提示 14set smartindent \u0026#34;智能对齐 15set shiftwidth=4 \u0026#34;偏移4个空格 16set helplang=cn \u0026#34;中文帮助文档(前提是下了中文包) Python相关 安装pip sudo apt install python3-pip\n安装Selenium对浏览器进行控制 pip3 install selenium\n安装火狐 sudo apt install firefox 如果出现错误,可以尝试 sudo apt install firefox-esr\n安装虚拟屏幕:在shell中也可以使用Selenium sudo apt install xvfb pip3 install pyvirtualdisplay\n安装Samba服务器用于传文件 sudo apt install samba\n备份Samba配置文件后修改 sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak sudo vim /etc/samba/smb.conf\n防乱码:在[default]下添加\n1unix charset = UTF-8 2dos charset = cp936 文件夹权限 先用两张表格\nr 读取 w 写入 x 执行 4 2 1 d rwx rwx rwx 文件(-)/目录(d) 4+2+1 4+2+1 4+2+1 将文件夹权限更改为777\n配置 1[share] 2path = /home/pi/terminal 3available = yes 4browseable = yes 5public = yes 6writable = yes 7valid users = pi 8create mask = 0777 9directory mask =0777 10force user = pi 11force group = samba-public 添加用户组\n1sudo useradd -rs /bin/false samba-public 2sudo chown samba-public /home/pi/terminal 3sudo chmod u+rwx /home/pi/terminal 添加名为pi的用户 sudo smbpasswd -a pi\n测试配置是否有错误 sudo testparm\n重新启动Samba服务器 sudo service smbd restart\n设置时区:防止执行时间错误 timedatectl set-timezone Asia/Shanghai\n设置定时任务 crontab -e\n查看crontab日志 sudo cat /var/log/syslog | grep -i cron\n开机启动 编辑开机启动服务 sudo vim /lib/systemd/system/rc-local.service\n以某一用户执行命令(screen -S main为命令、pi为用户) su -c 'screen -S main' pi\n添加\n1[Install] 2WantedBy=multi-user.target 3Alias=rc-local.service rc.local (/etc/rc.local)\n1#!/bin/sh 2 3# 这里添加要开机执行的脚本和命令等等 4 5exit 0 添加可执行权限 sudo chmod +x /etc/rc.local\n创建软链接?? sudo ln -s /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service\n安装ngnix sudo apt install nginx 编辑默认配置 /etc/nginx/sites-available/default 其中的 root 是网页目录\n重启nginx service nginx restart\nQ\u0026amp;A Q:缺少依赖 1Preparing to unpack terminal/webmin_1.970_all.deb ... 2Unpacking webmin (1.970) over (1.970) ... 3dpkg: dependency problems prevent configuration of webmin: 4 webmin depends on libnet-ssleay-perl; however: 5 Package libnet-ssleay-perl is not installed. 6 webmin depends on libauthen-pam-perl; however: 7 Package libauthen-pam-perl is not installed. 8 webmin depends on libio-pty-perl; however: 9 Package libio-pty-perl is not installed. 10 webmin depends on unzip; however: 11 Package unzip is not installed. A: sudo apt install -f\nQ: .vimrc在sudo中不生效 A: cp ~/.vimrc /root\n","date":"2021-01-20T10:02:05Z","permalink":"https://www.zhhuu.top/posts/raspi-setup/","section":"posts","tags":["树莓派","安装","linux","后端","系统"],"title":"树莓派安装设置"},{"categories":["Skills"],"contents":"🔗 链接\n正则表达式在线测试 | 菜鸟工具 标记 表达式 作用 示例 作用 ^ 匹配行首 ^a 匹配 a 在行首的情况 $ 结匹配行尾 a$ 匹配 a 在行尾的情况 普通字符(大小写敏感) 表达式 作用 示例 作用 [] 只能匹配中括号中的字符 [ABC] 匹配字符串中的所有 A、B、C [^A] 除去 [^ABC] 得到除了 ABC 以外的所有字符 [A-Z] 某一个区间(可以是大写区间、小写区间、数字区间) [A-C] 匹配 A-C 的区间 . 匹配 除换行符的所有单个字符,相当于[^\\n\\r] [\\s] 匹配 空白字符(空格、换行) [\\s] 匹配 非空白字符(包括换行) [\\w] 匹配 字母、数字、下划线,相当于[A-Za-z0-9] 非打印字符 符号 作用 示例 作用 \\ca 匹配 control+a 的快捷键(\\c 是表示 c,\\为转义)(\\cx 的 x 必须是 A-Z 或者 a-z) \\cv 匹配 ctrl+v 的快捷键 \\f 换页符 \\n 换行符 \\r 回车 \\s 空白字符,包括空格、制表符、换页符等等 \\S 非空白字符,包括回车 \\t 制表符(Tab) \\v 垂直制表符(Vertical Tab) \\d 数字字符,等价于[0-9] \\D 非数字字符,等价于[^0-9] \\w 单词(word) \\W 非单词 特殊字符 符号 作用 示例 作用 $ 匹配字符串的结尾位置 () 标记一个子表达式开始和结束的位置 * 匹配前面的子表达式 0 次或多次 go*gle 可以匹配 ggle,google,gooooogle 等 + 匹配前面的子表达式 1 次或多次(1+) go+gle 可以匹配 gogle,goooogle 等 . 匹配除换行符之外的任何单字符 [ 标记一个中括号表达式的开始 ? 匹配前面的字符可有可无,或指明一个非贪婪限定符 \\ 转义符 ^ 匹配输入字符串的开始位置 { 标记限定符表达式的开始 | 或(两项之间的选择) a|b 匹配 a 或 b 限定符 符号 作用 {n} 匹配 n 次 {n,} 匹配 n 次及以上 {n,m} 至少匹配 n 次,至多匹配 m 次 高级匹配 贪婪匹配: 匹配到最后 \u0026lt;.+\u0026gt;默认贪婪匹配任意字符 懒惰匹配: 匹配到就停止 \u0026lt;.+?\u0026gt;懒惰匹配任意字符 ","date":"2020-12-31T19:32:35Z","permalink":"https://www.zhhuu.top/posts/regular-expression/","section":"posts","tags":["编程","语法","后端"],"title":"正则表达式笔记"},{"categories":["Coding"],"contents":"删除对象 类似C#中的 =null\n1var1 = 1 2var2 = 10 3 4del var1,var2 #关闭 5 6print(var1) 字符串截取 字符串的截取的语法格式: \u0026lsquo;变量[头下标:尾下标:步长]\u0026rsquo; 头下标从0开始,尾下标从-1开始 某一下标后的所有内容 \u0026lsquo;str[1:]\u0026rsquo;\n列表同理,将str替换为list\n都是闭区间\n步长:间距截取,默认间隔为1,为-1时表示逆向读取 join() str.join() 方法用于将序列中的元素以指定的字符(str)连接生成一个新的字符串。 list → string\nsplit() split() 通过指定分隔符(str)对字符串进行切片形成列表\n数据类型 Number(数字) String(字符串) List(列表) []:元素可以修改 Tuple(元组)():元素不可修改,也可以用+进行拼接 1tup1 = () # 空元组 2tup2 = (20,) # 一个元素,需要在元素后添加逗号 Set(集合){}: 可以进行集合运算 1a = set(\u0026#39;abracadabra\u0026#39;) 2b = set(\u0026#39;alacazam\u0026#39;) 3 4print(a - b) # a 和 b 的差集 5print(a | b) # a 和 b 的并集 6print(a \u0026amp; b) # a 和 b 的交集 7print(a ^ b) # a 和 b 中不同时存在的元素 创建空集合set() Dictionary(字典){a:b}:内容写法与集合不同 1dict = {} 2dict[\u0026#39;one\u0026#39;] = \u0026#34;1 - 菜鸟教程\u0026#34; 3dict[2] = \u0026#34;2 - 菜鸟工具\u0026#34; 4 5tinydict = {\u0026#39;name\u0026#39;: \u0026#39;runoob\u0026#39;,\u0026#39;code\u0026#39;:1, \u0026#39;site\u0026#39;: \u0026#39;www.runoob.com\u0026#39;} 6 7print (dict[\u0026#39;one\u0026#39;]) # 输出键为 \u0026#39;one\u0026#39; 的值 8print (dict[2]) # 输出键为 2 的值 9print (tinydict) # 输出完整的字典 10print (tinydict.keys()) # 输出所有键 11print (tinydict.values()) # 输出所有值 12 13tinydic2 = dict(Runoob=1, Google=2, Taobao=3) 数据类型转换 数据类型的转换,你只需要将数据类型作为函数名即可\nstr(x) float(x) list(x)\n注释 1\u0026#39;\u0026#39;\u0026#39; 2comment1 3\u0026#39;\u0026#39;\u0026#39; 4 5\u0026#34;\u0026#34;\u0026#34; 6comment2 7\u0026#34;\u0026#34;\u0026#34; 8 9# comment3 运算符 运算符 功能 \\\\ 除法并取整 % 取余 ** 乘方 \\n 换行 逻辑运算符 Python C# and \u0026amp;\u0026amp; or ` not ! != != (新接触)\n运算符 意义 in 如果在指定的序列中找到值返回 True,否则返回 False。 not in - is is 是判断两个标识符是不是引用自一个对象 is not - and or not特性: 在python里面,0、’’、[]、()、{}、None为假,其它任何东西都为真。\nand(偏好False): 如果没有False值,返回的是最后一个True值,如果有False值,则返回的是第一个False值。 or(偏好True): 如果没有True值,返回的是最后一个False值,如果有True值,则返回的是第一个True值。 偏好与C#相同\n","date":"2020-10-08T09:25:58Z","permalink":"https://www.zhhuu.top/posts/python-note-1/","section":"posts","tags":["Python","后端"],"title":"PythonNote1"},{"categories":"Skills","contents":"Word的一点小技巧\n快捷键/按键 快捷键 功能 Del 向后删除 Backspace 向前删除 Ctrl + Enter 插入分页符 单位 单位可以直接输入,例如“50磅” 修改默认单位可以在“文件-选项-高级-显示-度量单位”修改 格式 粘贴时可以只粘贴文本而不粘贴格式:“右键-只保留文本”,修改默认粘贴方式可以在 “文件-选项-高级-剪切、复制和粘贴” 处修改默认值(从其他程序粘贴-\u0026gt;“仅保留文本”) 定制功能区提高效率(高级选手)【Word选项-自定义功能区】 参考:元卅的B站主页\n个人信息排版 用表格排版,防止改字体改信息以后引起排版问题 表头可以使用分散对齐,点击表格左上角的控制柄后设置居中可以使表格内容竖直和水平居中 最后去掉表格框线,再加下框线达到下划线的效果 设置目录 引用选项卡-插入(插入目录) 使用 “样式” 让Word软件知道你的文章结构(标题等),软件可以以此自动生成目录 右键 “样式” 中的样式可以修改样式 更改 “正文” 的样式会改变后面所有自带样式 分隔符 文件-选项-显示-显示所有格式标记 显示特殊排版符号 符号 使用方法 分页符 Ctrl+Enter 插入分页符 分节符 “布局-分隔符-分节符” 再页眉页脚插入分节符可以达到每一页页眉页脚不同/数字不同的效果,点击与上一页相同取消内容与上一页相同 有奇偶页不同的选项 公式 插入公式:“插入-公式” 或者 Alt + = 公式分为 行内公式(嵌入) 和 单行公式(显示) 鼠标悬停在公式的符号上就可以看到字符的转义代码 符号 特殊字符/用法 上标 ^ 下标 _ ×(叉乘号) \\times ·(点乘号) \\cdot 矢量 \\vec 写方程组时加\u0026amp;可以上下对齐 插入域:Seq Alt + F9 , SEQ后面加序列名字,再按Alt + F9退出,光标点到标号按F9更新序号,自动标号 F9自动更新文档内数据内容 图片显示不全时,改行距(单倍/多倍行距) ","date":"2020-07-16T22:12:31Z","permalink":"https://www.zhhuu.top/posts/word-typesetting/","section":"posts","tags":["Office","学习"],"title":"Word排版技巧"},{"categories":null,"contents":"终究止不住折腾,终于还是把卡住很久的这个功能做出来了。\n🔗参考链接\nMozilla A2HS Mozilla A2HS demo Google A2HS | App install banners Google A2HS | Web app manifest manifest的设置 一开始的时候瞎瞄两眼介绍,就天真地以为只要manifest.json或者manifest.webmanifest这个文件存在就好了,结果后来慢慢了解发现还有事呢..反正让它跑起来再说\u0026hellip;\n不管怎么说,先把manifest.webmanifest写好 (当然你写manifest.json也是可以的,只不过时改了一下后缀名而已,内容相同,看哪个顺眼就用哪个) 那既然要这个文件,就先找最简单的抄了一个,内容如下(来自Mozilla A2HS demo)\n1{ 2 \u0026#34;background_color\u0026#34;: \u0026#34;purple\u0026#34;, 3 \u0026#34;description\u0026#34;: \u0026#34;Shows random fox pictures. Hey, at least it isn\u0026#39;t cats.\u0026#34;, 4 \u0026#34;display\u0026#34;: \u0026#34;fullscreen\u0026#34;, 5 \u0026#34;icons\u0026#34;: [ 6 { 7 \u0026#34;src\u0026#34;: \u0026#34;icon/fox-icon.png\u0026#34;, 8 \u0026#34;sizes\u0026#34;: \u0026#34;192x192\u0026#34;, 9 \u0026#34;type\u0026#34;: \u0026#34;image/png\u0026#34; 10 } 11 ], 12 \u0026#34;name\u0026#34;: \u0026#34;Awesome fox pictures\u0026#34;, 13 \u0026#34;short_name\u0026#34;: \u0026#34;Foxes\u0026#34;, 14 \u0026#34;start_url\u0026#34;: \u0026#34;/pwa-examples/a2hs/index.html\u0026#34; 15} 反正这些属性会英文的都看得懂,照着改就是了。值得一提的有两个属性:\nicons:这个属性我觉得其实挺狗的,按照 Google Developers 上面的要求,至少要有192x192和512x512两种尺寸的图标。反正那个时候我被hexo坑住了,以为这是硬性规定,所以就用格式工厂强行转化出了这两种尺寸的图标。后来发现并不是这样,因为我现在的icons属性内容如下: 1 \u0026#34;icons\u0026#34;: [{ 2 \u0026#34;src\u0026#34;: \u0026#34;~.png\u0026#34;, 3 \u0026#34;sizes\u0026#34;: \u0026#34;720x720\u0026#34;, 4 \u0026#34;type\u0026#34;: \u0026#34;image/png\u0026#34; 5 }, 6 { 7 \u0026#34;src\u0026#34;: \u0026#34;~.png\u0026#34;, 8 \u0026#34;sizes\u0026#34;: \u0026#34;192x192\u0026#34;, 9 \u0026#34;type\u0026#34;: \u0026#34;image/png\u0026#34; 10 } 11 ], (此处隐去文件目录) 所以应该是最好这么做,让浏览器有缩放的空间,因为 Google Developers上有这么一句话 成功:包括192x192像素图标和512x512像素图标。Chrome会自动缩放设备的图标。如果您希望缩放自己的图标并将其调整为完美像素,请以48dp的增量提供图标。(来自机翻)\nstart_url:这里参考了一下友链中的网站,发现了他的manifest.webmanifest中有这样的一行\u0026quot;start_url\u0026quot;: \u0026quot;.\u0026quot;,,所以我猜只要根目录下存在index.html并且这个文件被设为为默认主页的话只需要如上设置就可以了。 manifest的生效 manifest文件需要被引用才会生效,所以要在\u0026lt;head\u0026gt;里面加入引用如下\u0026lt;link rel=\u0026quot;manifest\u0026quot; href=\u0026quot;manifest.webmanifest\u0026quot;\u0026gt;。需要注意的是,经过多次实验,引用的这行标签必须放在\u0026lt;head\u0026gt;里面才会生效,其他地方则无效。 (没错,这就是我被hexo坑的地方)\n根据Google Developers上的资料,manifest文件生效还有如下几点:\n完整的基本属性。(参见开头链接) https连接 serviceworker的存在(或许是?) 最终结果 Ctrl+C \u0026amp; Ctrl+V 的ServiceWorker 说实话我也完全不懂这到底是怎么回事,但是大概知道ServiceWorker是注册服务的,有弹出横幅的功能。 应该是来源于manifest.js中。 首先添加manifest.js的引用\u0026lt;script src=\u0026quot;manifest.js\u0026quot; defer\u0026gt;\u0026lt;/script\u0026gt;(来源于开头的demo)\nmanifest.js的内容如下\n1// Register service worker to control making site work offline 2 3if (\u0026#39;serviceWorker\u0026#39; in navigator) { 4 navigator.serviceWorker 5 .register(\u0026#39;serviceworker.js\u0026#39;) 6 .then(function() { console.log(\u0026#39;Service Worker Registered\u0026#39;); }); 7} 8 9// Code to handle install prompt on desktop 10 11let deferredPrompt; 12const addBtn = document.querySelector(\u0026#39;.add-button\u0026#39;); 13addBtn.style.display = \u0026#39;none\u0026#39;; 14 15window.addEventListener(\u0026#39;beforeinstallprompt\u0026#39;, (e) =\u0026gt; { 16 // Prevent Chrome 67 and earlier from automatically showing the prompt 17 e.preventDefault(); 18 // Stash the event so it can be triggered later. 19 deferredPrompt = e; 20 // Update UI to notify the user they can add to home screen 21 addBtn.style.display = \u0026#39;block\u0026#39;; 22 23 addBtn.addEventListener(\u0026#39;click\u0026#39;, (e) =\u0026gt; { 24 // hide our user interface that shows our A2HS button 25 addBtn.style.display = \u0026#39;none\u0026#39;; 26 // Show the prompt 27 deferredPrompt.prompt(); 28 // Wait for the user to respond to the prompt 29 deferredPrompt.userChoice.then((choiceResult) =\u0026gt; { 30 if (choiceResult.outcome === \u0026#39;accepted\u0026#39;) { 31 console.log(\u0026#39;User accepted the A2HS prompt\u0026#39;); 32 } else { 33 console.log(\u0026#39;User dismissed the A2HS prompt\u0026#39;); 34 } 35 deferredPrompt = null; 36 }); 37 }); 38}); 发现两个问题:\nmanifest.js内部还存在引用.js文件sw.js,内容如下:\n1 self.addEventListener(\u0026#39;install\u0026#39;, function(e) { 2 e.waitUntil( 3 caches.open(\u0026#39;video-store\u0026#39;).then(function(cache) { 4 return cache.addAll([ 5 \u0026#39;/pwa-examples/a2hs/\u0026#39;, 6 \u0026#39;/pwa-examples/a2hs/index.html\u0026#39;, 7 \u0026#39;/pwa-examples/a2hs/index.js\u0026#39;, 8 \u0026#39;/pwa-examples/a2hs/style.css\u0026#39;, 9 \u0026#39;/pwa-examples/a2hs/images/fox1.jpg\u0026#39;, 10 \u0026#39;/pwa-examples/a2hs/images/fox2.jpg\u0026#39;, 11 \u0026#39;/pwa-examples/a2hs/images/fox3.jpg\u0026#39;, 12 \u0026#39;/pwa-examples/a2hs/images/fox4.jpg\u0026#39; 13 ]); 14 }) 15 ); 16 }); 17 18 self.addEventListener(\u0026#39;fetch\u0026#39;, function(e) { 19 console.log(e.request.url); 20 e.respondWith( 21 caches.match(e.request).then(function(response) { 22 return response || fetch(e.request); 23 }) 24 ); 25 }); 说明这是安装时执行的脚本,我觉得部分脚本对我的情况来说还是存在实际意义的,于是去掉了demo中的存储本地媒体的动作内容,修改后如下:\n1 self.addEventListener(\u0026#39;fetch\u0026#39;, function(e) { 2 console.log(e.request.url); 3 e.respondWith( 4 caches.match(e.request).then(function(response) { 5 return response || fetch(e.request); 6 }) 7 ); 8 }); 9 10 self.addEventListener(\u0026#39;install\u0026#39;, function(e) { 11 e.waitUntil( 12 caches.open(\u0026#39;video-store\u0026#39;).then(function(cache) { 13 return cache.addAll([ 14 15 ]); 16 }) 17 ); 18 }); 最终复制到了manifest.webmanifest的同目录下。\n打开浏览器后报错说addBtn.style.display = 'none';无法执行。经实践发现demo中有一个button \u0026lt;button class=\u0026quot;add-button\u0026quot;\u0026gt;Add to home screen\u0026lt;/button\u0026gt; 经查,这是充当电脑版浏览器中引发\u0026quot;添加至主屏幕弹窗\u0026quot;事件的按钮,所以只要在页面中给他找个地方放上就行了。要是在原有页面上修改的话记得把要充当这个button的组件上加个class=\u0026quot;add-button\u0026quot;即可。\n关于引用插入到hexo中的\u0026lt;head\u0026gt; 可能时由于hexo-material这个主题的关系,经实践表明,hexo\\themes\\material\\layout\\_partial\\head.ejs中注释Custom-head的标签所在位置已经在\u0026lt;body\u0026gt;的地方了!所以我把插入\u0026lt;link rel=\u0026quot;manifest\u0026quot; href=\u0026quot;manifest.webmanifest\u0026quot;\u0026gt;的地方稍微提前到了注释WebAPP Icons的上一行,总算被Chrome识别出来了。\nAt last 假期差不多结束了,应该不会有什么更新了。See ya!\n","date":"2019-07-27T15:45:10Z","permalink":"https://www.zhhuu.top/posts/a2hs/","section":"posts","tags":["前端"],"title":"为本站添加A2HS"},{"categories":["Skills"],"contents":"每次新安装Office诚然是一件很头疼地事情。这里介绍可以快速在电脑上安装Office的方法。\nOffice Tool Plus 如果你想深入了解Office Tool Plus,也请访问官方网站。 打开网站以后,点击立即下载,并打开Office Tool Plus。打开以后可能会进行自动更新。更新完之后进入软件界面 个人快速安装Office 如果仅在一台电脑上安装,你可以直接转到安装选项卡进行安装。 1、选择你需要的Office套件。\nWin10推荐使用Office2019,Win7推荐使用Office2016 建议安装零售版,即Retail\n2、根据你需要的Office软件勾选应用程序。\n完整版Office安装的项目为Excel Powerpoint Word Access Publisher。大学生建议勾选完整版Office的安装项目。\n3、安装设置: 根据系统,设置体系结构。为了获取较新的Office版本,建议把通道设置为\u0026quot;每月通道\u0026quot;。安装方式无需更改。 设置可选设置下的更新设置。 注意其中的禁用Office更新和使用配置管理器管理更新,建议取消勾选。 更新通道建议更改为\u0026quot;每月通道\u0026quot; 激活设置中,按需要进行勾选。 4、以上设置完毕后,即可点击开始安装。等待安装完毕即可使用。\n批量快速安装Office 这种情况适用于多台设备需要安装Office。首先需要在一台机器上完成配置设置。\n转到下载选项卡。点击版本号,查询版本号。 设置常规设置中的通道、体系结构以及版本。 点击上方的开始按钮。\n下载完成后,转到安装选项卡,参照上文个人快速安装Office的前三个步骤。不同的是,安装设置中的安装方式应设置为离线安装。 点击开始安装旁边的三角形,选择保存配置为XML。\n找到并打开你保存的XML文件,转到其中SourcePath所指的目录,复制整个文件夹到你的U盘。 把你保存的XML文件也复制到U盘下的同一个文件夹。\n当你需要在其他电脑上从U盘安装Office时,修改其中SourcePath所指的目录为你的U盘所在的同文件夹目录,打开Office Tool Plus,进入安装选项卡,点击开始安装旁边的三角形,选择选择XML文件,选择你的XML文件,点击开始安装。或者使用微软的Office Deployment Tool,用CMD的方式进行安装。这里不再介绍这种方法,请百度。\n","date":"2019-05-25T18:00:00Z","permalink":"https://www.zhhuu.top/posts/deploy-office-faster/","section":"posts","tags":["Office","安装","系统"],"title":"更快地部署Office"},{"categories":null,"contents":" 说明:经查,网站已经失效,本文仅作存档\n这个网站可以把自己的城市设置为壁纸。具体步骤如下:\n你会看到如下界面 可以在 Map Location 那一栏输入自己想要的城市。我输入的是深圳。 同时,你也可以更改地图颜色。共有4种颜色可选。 还可以选图片大小。部分热门机型已经有预设了,可以直接选择。 如果没有,可以手动设置图片大小。我这里设置1080P。 最后点击 蓝色按钮 Generate,Download 下载即可。\n","date":"2019-05-19T20:00:00Z","permalink":"https://www.zhhuu.top/posts/city-phone-background/","section":"posts","tags":["壁纸","设计"],"title":"把自己的城市地图设置为壁纸"},{"categories":null,"contents":"发现CMD不能达到此目的,更换更高级的Powershell来执行这个任务~\n最近有的人经常更换电脑桌面壁纸,而且壁纸我觉得也不算好看(很难看),基本上就是起到哗众取宠的目的,所以我打算利用脚本自动定时更换电脑壁纸,达到锁定电脑壁纸的目的。\n准备工作 学校的电脑系统是Win7,默认设置不允许执行脚本(不知道是不是Ghost系统的人设置的),所以第一步要解除限制。 Powershell中执行命令如下: Set-ExecutionPolicy Unrestricted 执行完毕之后就能运行.ps1脚本了。\n自动更换壁纸的函数方法 保存如下代码到一个.ps1文件中。(可以用记事本编辑再更改文件拓展名)\n1Function Set-WallPaper($Value) 2{ 3 Set-ItemProperty -path \u0026#39;HKCU:\\Control Panel\\Desktop\\\u0026#39; -name wallpaper -value $value 4 rundll32.exe user32.dll, UpdatePerUserSystemParameters 1, True 5} 6 7Set-WallPaper -value \u0026#34;C:\\Windows\\Web\\Wallpaper\\Homes_Background.bmp\u0026#34; 将其中C:\\Windows\\Web\\Wallpaper\\Homes_Background.bmp更改成壁纸所在处,执行脚本即生效。\n添加到计划任务 计划任务的位置在 \u0026ldquo;控制面板\u0026rdquo;-(\u0026ldquo;系统和安全\u0026rdquo;)-\u0026ldquo;管理工具\u0026rdquo;-\u0026ldquo;计划任务\u0026rdquo; 打开后点击 \u0026ldquo;添加基本任务\u0026rdquo; ,之后就可以跟着向导走了。执行文件填写 powershell ,参数填写刚刚保存的脚本文件位置即可。 还可以 每日获取Bing图片并设为壁纸\n1function Save-BingTodayImage() 2{ 3 #必应图片故事API 4 $bingImageApi =\u0026#39;http://www.bing.com/HPImageArchive.aspx?format=xml\u0026amp;idx=0\u0026amp;n=1\u0026amp;mkt=zh-cn\u0026#39; 5 $bingUri = \u0026#39;http://www.bing.com/\u0026#39; 6 7 # 获取图片链接 8 [xml]$bingImageXml = (Invoke-WebRequest -Uri $bingImageApi).Content 9 Write-Host \u0026#34; 今日图片故事: $( $bingImageXml.images.image.copyright ) \u0026#34; 10 $imgLink = \u0026#39;{0}{1}\u0026#39; -f $bingUri , $bingImageXml.images.image.url 11 12 # 下载和保存图片 13 $imageDir = \u0026#34;$HOME\\Pictures\\Bing\\\u0026#34; 14 if( -not (Test-Path $imageDir) ) 15 { 16 mkdir $imageDir | Out-Null 17 } 18 $imageFile = Join-Path $imageDir ( \u0026#39;{0}.jpg\u0026#39; -f $bingImageXml.images.image.fullstartdate) 19 20 Invoke-WebRequest -Uri $imgLink -OutFile $imageFile 21 22 return $imageFile 23} 24 25Function Set-DesktopWallPaper($imagePath) 26{ 27 Set-ItemProperty -path \u0026#39;HKCU:\\Control Panel\\Desktop\\\u0026#39; -name wallpaper -value $imagePath 28 RUNDLL32.EXE USER32.DLL UpdatePerUserSystemParameters ,1 ,True 29} 30 31# 获取今日必应背景图片 32$image=Save-BingTodayImage 33 34#设置为桌面墙纸 35Set-DesktopWallPaper -imagePath $image ","date":"2019-03-15T19:00:08Z","permalink":"https://www.zhhuu.top/posts/powershell-wallpaper/","section":"posts","tags":["壁纸","后端"],"title":"使用Powershell自动设置壁纸"},{"categories":["Skills"],"contents":"其实做了这么多的 PPT 以后,慢慢摸索出了一种做 PPT 的方式技巧。但其实下面包括的也不仅仅是技巧,还包含了一套我认为比较成熟的设计系统(借鉴+创新),目的是为了使演示过程更加流畅。当然,要制造出这样的 PPT,达到这样的效果是肯定要花费一些时间的。可能只有像我这种对美有变态追求的人可能才会花费如此多的时间做 PPT,如果您有兴趣的话,可以继续看下去。\n所需: Microsoft PowerPoint 2016 或以上 耐心\n引言 Microsoft Office 2016 中新引进了“变体”的切换效果。通过这个全新的切换效果能更准确地实现Material Design和Microsoft Fluent Design System中的一些内容,使整个幻灯片的设计更加系统化。\n🔗 链接\nMaterial Design Microsoft Fluent Design System 变体的简单应用 \u0026ldquo;变体\u0026quot;是 Office 2016 中新增加的一种切换效果。它可以自动识别两张相邻的幻灯片之间的变化并自动插补动画。下面通过两个例子介绍这种切换动画的使用方法。\n精确的位移 在第一张幻灯片中创建一个正方形。 在第二张幻灯片中创建一个正方形,并移动到你想要的位置。 选中第二张幻灯片,在顶栏的\u0026quot;切换\u0026quot;中选择\u0026quot;变体\u0026rdquo;。 放映幻灯片,正方形从第一张幻灯片的位置移动到第二张幻灯片的位置。\n精确地位移并更改大小 在上述的操作的基础上您可以尝试改变第二张幻灯片中正方形的形状和大小,您可以发现放映幻灯片的时候原来的正方形自动变成了第二张幻灯片中的样式(大小,位置,甚至颜色,形状的改变)。\n因此,您可以利用变体的这一特性实现后文中卡片的大小,位置甚至深度(阴影大小)的变化。\n多动画连续播放和延迟 1.创建矩形若干个,并纵向排列。\n2.拖动鼠标选中所有创建的矩形,在顶栏的\u0026quot;动画\u0026quot;选项卡中选择\u0026quot;淡出\u0026quot;动画。此时,选中的所有矩形在幻灯片放映时会同时淡出。\n3.为了遵循 Material Design 中的\u0026quot;有层次的时序\u0026quot;的原则,我们将每个矩形相对其上层的矩形延迟 0.1 秒钟淡出,直至最后一个矩形。\n建议使用\u0026quot;缩放\u0026quot;动画实现矩形的顺次进入屏幕,这么做的依据是下文中所提将到的\u0026quot;视觉连贯性\u0026quot;原则。缩放在大部分情况下是最适合几何形状进入屏幕的方式,而顺次淡出则适合文字进入屏幕。 上文使用矩形是为了简化演示过程。\n圆的场景切换的实现 1.您将在第一张幻灯片中创建这个场景切换。这意味着这一张幻灯片将包含两章节的内容(前一章节的结束部分和后一章节的开头部分)。这里用\u0026quot;标题\u0026quot;二字表示上一章节的结束部分。\n2.创建一个与演示区域大小相当的正圆,并将其移动到演示区域的中心。\n3.选中刚才创建的圆形,给所选圆形添加**\u0026ldquo;缩放\u0026rdquo;**动画(在顶栏的\u0026quot;动画\u0026quot;中找到\u0026quot;缩放\u0026quot;,并点击)。从含圆的那张幻灯片开始放映幻灯片,您就能观察到\u0026quot;圆形场景切换\u0026quot;。\n元素 卡片(Cards) 分隔各组不同的内容,并归类。\n卡片是包含一组特定数据集的纸片,数据集含有各种相关信息,例如,关于单一主题的照片,文本,和链接。卡片通常是通往更详细复杂信息的入口。卡片有固定的宽度和可变的高度。最大高度限制于可适应平台上单一视图的内容,但如果需要它可以临时扩展(例如,显示评论栏)。卡片不会翻转以展示其背后的信息。\n显示这些内容时使用卡片布局:\n为一个集合,由多种数据类型组成(例如,卡片集包含照片,电影,文本,图像) 不要求直接比较(观看者不直接与图像或字符串比较) 包含可变长度内容,例如评论 如果使用列表需要显示超过三行文本 制作卡片 1.在顶栏的\u0026quot;插入\u0026quot;选项卡中选择\u0026quot;形状\u0026quot;,选择矩形。\n2.在创建好的卡片上右击,选择\u0026quot;设置形状格式\u0026quot;。\n3.在右边弹出来的边栏上选择\u0026quot;油桶\u0026quot;的选项卡,选择纯色填充,将填充颜色设置为白色。线条选择无线条。\n4.选择\u0026quot;五边形\u0026quot;选项卡,设置阴影,将阴影的预设样式设置为框选的样式。\n5.最终效果如图。\n按钮(Buttons) 在 PPT 中,一般使用的是圆形按钮。圆形按钮能更方便地引导转场。圆形按钮一般与图标配合使用。更有想象力的用法可以参照此处\n在 PPT 中,用于表示一段演示的结束,并引出完全切换的转场(动画)。\n按钮有阴影,因此与卡片的制作方式大同小异。不同的是按钮一般被赋予颜色而不是白色,并且按钮中心一般会有图标显示其作用。您可以按照您的需求定制按钮。 纸条(Chips) 拓展可能性,作为一个原因容器。入场一般用横向拉取。\n图标(Icons) 增强观者对当前页的理解,增强视觉体验。\n🔗 链接\nMaterial Design 图标 Material Design 图标下载 色彩 如果你手头没有拿得出手的颜色可以选择的话,我推荐使用这个配色工具。这是 Material Design 的配色工具(Color Tool),你可以在线搭配所需颜色,同时会生成颜色代码(HTML 格式)。得到HTML 格式的颜色代码以后转换成RGB 格式,最终导入 PPT 内使用。\n🔗 链接\nMaterial Design 配色工具 颜色转换器 转场 为什么要设计转场?\n使整个演示过程更流畅,更有层次感。 交代屏幕中元素去向,尽量避免观者产生不适感 转场包括这两部分:\n完全切换(Material 圆) 分支情况:可以使用卡片进行自由扩展 视觉连贯性(Fluency) 在两个视觉效果不同的页面之间的转场应该平滑、轻快,更重要的是使观看者感觉清晰而非困惑。一个好的转场可以四两拨千斤,让观看者清楚地了解他们应该关注哪里。每一个转场应该包含以下三类元素:\n新入元素(Incoming elements): 全新的元素进入屏幕时需要被引导,从已有场景中转变而来的元素需要重新被识别 淡出元素(Outgoing elements):与当前场景不相关的元素应当以恰当的方式被移除 通用元素(Shared elements):指那些从转场开始到结束都没有发生变化的元素。可以是细微至单个图标,也可以是显著到占据屏幕的图片展示 有层次的时序(Layering) 在建立转场的时候,对于元素移动的顺序和时机都要详加考虑。要确保这个动画能使信息的展示具有层次感。也就是说,它能引导观看者的关注力,将最重要的内容传递给观看者。\n然而,这并不是说最重要的东西先动,最不重要的东西就后动。元素转场的时序要平滑并且避免脱节的感觉。\n应用:逐条展示时,用\u0026quot;淡出\u0026quot;顺次引出对象,每条延时应为 0.1 秒。\n真实的动作(Authentic Motion) 感知一个物体有形的部分可以帮助我们理解如何去控制它。观察一个物理的运动可以告诉我们它轻还是重,柔性还是刚性,小还是大。在 material design 设计规范中,动作不止是呈现着它美丽的一面,它还意味着在空间中的关系、功能以及在整个系统中的趋势。当一张卡片被强调或选中时,其离地面的距离增大,视觉上看起来被抬高,z 轴距离增大,因此阴影应变大。当然,为了凸显这一动作,您可以为卡片的背景套上一层灰色的半透明层。 体积和重量(Mass and Weight) 物理世界中物体拥有质量,所以只有当施加给它们力量的时候才会移动,因此,物体没法在瞬间开始或者结束动作。动画突然开始或者停止,或者在运动时突兀的变化方向,都会使用户感到意外和不和谐的干扰。在现实世界中,事物不会立即开始或停止移动。他们需要时间来加速和减速。宽松使元素移动,好像受摩擦等自然力的影响。因此,大的元素质量大,运动所需时间会更长。在 PPT 中,设置的运动时间也应该相应地更长。 场景(纯原创) 拓展屏幕(Extended Display):屏幕只是充当一个查看器,不局限于屏幕大小。 1.可将部分下一张 PPT 中的元素暴露于当前屏幕中,暗示当前章节未结束,增强连续性。\n示例\n2.充当放大器,使转场不失流畅。放大后若要继续当前章节,应还原屏幕(退回放大前的状态)再继续当前章节,交代元素去向。\ne.g 地图放大,强调场景。\n下一章节 从当前屏幕拉出下一章节按钮(圆形),并由按钮进行转场,由按钮决定下一章节的背景颜色。\nthumb_up_alt 前言到正文的转场 拓展卡片(Extended Card) 卡片大小也可以改变。(参见 material card),当卡片拓展(放大)后,可引出详细内容。若被放大的卡片周围有卡片,此卡片将会推开周围的卡片,而不是直接覆盖其它卡片上。当卡片收缩时,若其周围本有卡片,则应将其它卡片拉回。若无,也可以借此机会引出新的卡片。\n拓展时不宜覆盖其它卡片 若不是极大地改变卡片的面积则不应该更改卡片的深度(表现为阴影的大小) 示例文件 📄 示例文件\n","date":"2018-11-23T20:09:45Z","permalink":"https://www.zhhuu.top/posts/ppt-design-guide/","section":"posts","tags":["PPT","设计"],"title":"PPT设计指南"},{"categories":null,"contents":"File Getter使用说明 功能 启动后持续扫描电脑上盘符数,当盘符数量有变更时检索新增盘符内文件。当检索到指定文件时复制到电脑中指定目录(C:/got)下。\n使用方法 直接打开(建议存入电脑C盘中某个位置再打开),当你程序成功开始运行后发出短暂(哔)声。当有新盘符插入时,扫描盘符内文件,若有指定类型文件则复制。当扫描完成后程序发出长(1s,哔)声,并自动退出。\n使用技巧 当你在程序运行目录下新建以下文件程序运行逻辑会发生改变:\ndebug.txt 当程序运行时,只要检测到运行目录下有此文件,日志窗口会显示出来。当检测到此文件被删去,窗口则会被隐藏。 注意:此操作在程序运行时是实时的,命令即刻执行(在下一个循环时)\nkeeprunning.txt 当程序完成扫描新磁盘(不管有没有复制)后,若检测到此文件则会继续运行下去。终止程序运行方法参见下文。\nexit.txt 当程序在运行时检测到此文件后则立刻终止运行。\n支持的指定类型文件 .xls .xlsx\n其他说明 本程序仅供学习用途使用。\n","date":"2018-04-29T19:13:31Z","permalink":"https://www.zhhuu.top/posts/file-getter-instructions/","section":"posts","tags":["后端","软件开发","C#"],"title":"FileGetter使用说明"},{"categories":["Skills"],"contents":"Visual Studio 快捷键整理\n窗口快捷键 记忆诀窍:\n凡跟窗口挂上钩的快捷键必有一个W(Windows); Ctrl+W,W: 浏览器窗口 (浏览橱窗用有道的翻译是window shopping)\nCtrl+W,S: 解决方案管理器 (Solution)\nCtrl+W,C: 类视图 (Class)\nCtrl+W,E: 错误列表 (Error)\nCtrl+W,O: 输出窗口(输出Output;输出程序的的编译信息 ;可在vs中“工具”—-“选项”—-“调试”—-“输出窗口”进行配置需要查看哪些信息)\nCtrl+W,P: 属性窗口 (属性 Property)\nCtrl+W,T: 任务列表 (任务Task)\nCtrl+W,X: 工具箱 (事实上工具应该是Tool 但t已被任务列表占用了 ;参照一些大神的记忆方法:“X”长得四通八达,而工具就有这样一个特点,所以属性的快捷键是“X”)\nCtrl+W,B: 书签窗口 (书签 Bookmark 书签非常好用,如果有几千行代码,在寻找代码的时候添加书签找起来要快很多)\nCtrl+W,U: 文档大纲 (OutLine;使用第二个字母U)\nCtrl+D,B: 断点窗口 (breakpoint)\nCtrl+D,I: 即时窗口 (immediately)\n项目功能快捷键 规律: Ctrl 是强制功能键 Shift 有给项目增加功能\nCTRL + F6 /CTRL + TAB 下一个文档窗口即活动窗体切换 (windows操作系统是alt+tab表示在任务之间切换\nCTRL + SHIFT + F6 /CTRL + SHIFT + TAB 上一个文档窗口 (在windows系统操作中 相信大家都知道shift有相反的功能 哈哈 在这里体现了)\nF7: 查看代码 (WebForm开发里面,是查看后台代码)\nShift+F7: 查看窗体设计器 (在后台cs文件的时候,这种方式很方便跳转到前台.aspx页面)\nCtrl+Shift+N: 新建项目 (N是New新建的意思 那如果需要强制在项目中新建项目的话 自然就是组合键Ctrl+Shift+N)\nCtrl+Shift+O: 打开项目 (Open)\nCTRL + SHIFT + C 显示类视图窗口(C代表Class类的意思)\nCTRL + F4 关闭文档窗口 (相信用过qq的大家都有使用alt+f4来关闭当前聊天窗口 想想用ctrl+tab在活动标签窗口切换就知道为什么关闭当前标签窗口是ctrl+f4)\nCTRL + SHIFT + E 显示资源视图 (E代表Explorer资源管理器的意思)\nCTRL + SHIFT + B 生成解决方案 (B代表Build生成的意思 其实用F6也可以实现)\nShift+F6 表示生成当前项目 (上面已经说过使用f6可以生成整个解决方案 那如果是当前项目的生成那自然就是加上功能键shift了 )\nF4 显示属性窗口 SHIFT + F4显示项目属性窗口\nCtrl+Shift+S: 全部保存 (S代表Save保存的意思 这里表示全部保存是因为如果只是单个保存Ctrl+S跟整个项目没有任何瓜葛 而全部保存的概念应该是说在整个项目中 所以组合键中自然会有shift了哦)\nCtrl+Shift+A: 新建项(A是Add的意思)\nShift+Alt+C: 新建类 (shift是跟项目有关的功能键;Alt用的非常多,空格(用的非常多)旁;C是Class;而且添加类用的非常多;所以自然就是:Shift+Alt+C)\n查找相关快捷键 Ctrl+F: 查找 (Find) Ctrl+Shift+F: 在文件中查找 (上面已经提过了shift是表示在项目中 所以如果需要在项目中的文件中查找的话 那自然就少不了Shift)\nF3: 查找下一个 (相信使用过windows系统的人都知道f3是查找的快捷键)\nShift+F3: 查找上一个 (shift在此有反向的功能哦)\nCtrl+H: 替换\nCtrl+Shift+H: 在文件中替换\n代码快捷键 Ctrl+E,D(ctrl+k,d) —-格式化全部代码 ;让你的代码瞬间整洁起来。\nCtrl+E,F —-格式化选中的代码(如果你已经记住Ctrl+E+D是格式化全部代码的话 那你想想规律不就知道了吗 F不就在D的右边表示它是特定某一范围)\nCtrl+K,C: 注释选定内容 (Comment)\nCtrl+K,U: 取消选定注释内容 (UnComment)\nCtrl+J /Ctrl+K,L: 智能提示 列出成员 (kernel核心内容 list列表 如果我们想查看一个对象具有的成员具体信息的时候试下这个快捷键吧)\nCtrl+K,P: 参数信息 (kernel核心内容 Parameters参数 如果我们想查看一个方法的具体参数的时候这个组合键可是挺有用的哦)\nCtrl+K,I: 快速查看信息(Infomation)\nCtrl+K,S: 外侧代码(平时个人惯会时不时的用#region 用了region之后代码看起来就特别整洁 所以自然而然的就用惯了这个)\nCTRL + M, CTRL + M 折叠或展开当前方法\nCTRL + M, CTRL + O 折叠所有方法\nCTRL + M, CTRL + L 展开所有方法 CTRL + M, CTRL + P 展开所有方法\nCtrl+M,P: 停止大纲显示 (用了region将代码折叠起来之后试试用这组组合键吧 体验一下折叠和展开的吧 看着舒服的代码我相信你记住这对快捷键肯定是值得的)\nctrl+shift+f10:自动添加using命名空间(在实例化对象的时候,使用的非常多)\n调试快捷键 F5: 启动调试\nCtrl+F5: 开始执行(不调试)\nShift+F5: 停止调试\nCtrl+Shift+F5: 重启调试\nF9: 启用/关闭断点\nCtrl+F9: 停止断点\nCtrl+Shift+F9: 删除全部断点\nF10: 逐过程 Ctrl+F10: 运行到光标处 F11: 逐语句\n6、编辑快捷键 Shift+Alt+Enter: 切换全屏编辑(如果想一心一意的只写代码 让整个vs铺满全屏 感觉还不错哦)\nF12: 转到所调用过程或变量的定义\nAlt+F12: 查找符号(列出所有查找结果)\nshift+f12:查找所有引用(讲光标放在单词上, 然后按Shift + F12)\nCtrl+U: 全部变为小写 (的sql语句全部转换成大写以提高性能 )\nCtrl+Shift+U: 全部变为大写 (U表示Upper )\nCtrl+Shift+V: 剪贴板循环 (平时我们都只惯用ctrl+c 和ctrl+v 大家可能还不知道事实上微软都已经帮我们把多次剪切的结果都保存了下来 记下这组快捷键吧 可以粘贴上几次剪切的结果 一用便知道它的强大厉害之处)\nCtrl+Shift+L: 删除当前行 (这个很有用哦 因为大家常常会要删除多余的空行 哈哈 这组快捷键会让你省力不少)\nCtrl+E,S: 查看空白(ctrl+r,w 和它一样可以查看空白或者说显示或隐藏tab标记)\nCtrl+E,W: 自动换行 (代码太长还有滚动条,特别是写append(sql.toString)语句的时候,太长,所以这时候就不得不拖动滚动条,这样以后就可以换行显示了)\nCtrl+G: 转到指定行 (通过情况下 我们想在跳转到具体某一行 用它太方便了)\nShift+Alt+箭头键: 选择矩形文本 Alt+鼠标左按钮: 选择矩形文本\nCTRL + DELETE 删除至词尾\nCTRL + BACKSPACE 删除至词头\nSHIFT + TAB 取消制表符\nCtrl+左右箭头键:一次可以移动一个单词\nCtrl+单击: 选中当前点击的整个单词\nSHIFT + END 选择至行尾 SHIFT + HOME 选择至行开始处\nCTRL + SHIFT + END 选择至文档末尾 CTRL + SHIFT + HOME选择至文档末尾开始\nCTRL + SHIFT + PAGE UP 选择至本页前面 CTRL + SHIFT + PAGE DOWN选择至本页后面\nCTRL + PAGE DOWN 光标定位到窗口上方 CTRL + PAGE UP光标定位到窗口下方\nCTRL + END 文档定位到最后 CTRL + HOME文档定位到最前\n按两下Tab快速生成代码段(写for, foreach循环,或者try, 还有绑定事件方法)\nCtrl+减号:回退到光标上一次的位置(这个真心挺有用的)\n","date":"2018-04-29T18:07:34Z","permalink":"https://www.zhhuu.top/posts/visual-studio-hotkey/","section":"posts","tags":["后端"],"title":"Visual Studio 快捷键"},{"categories":["Coding"],"contents":"创建多线程?太麻烦了!来试试更快更便捷的异步。程序无须按照代码顺序自上而下的执行。\n什么是异步编程 什么是异步编程呢?举个简单的例子:\n1using System.Net.Http; 2using System.Threading.Tasks; 3using static System.Console; 4 5namespace Core 6{ 7 class Async 8 { 9 static void Main() 10 { 11 Start(); 12 End(); 13 } 14 15 static void Wait()=\u0026gt;WriteLine(\u0026#34;waiting...\u0026#34;); 16 static void End()=\u0026gt;WriteLine(\u0026#34;end...\u0026#34;); 17 static int Start() 18 { 19 WriteLine(\u0026#34;start...\u0026#34;); 20 HttpClient client = new HttpClient(); 21 Waiting(); 22 var result = client.GetStringAsync(\u0026#34;https://www.visualstudio.com/\u0026#34;); 23 string str = result.Result; 24 return str.Length; 25 } 26 } 27} 上面这段代码中,Main方法中的代码是按照自上而下的顺序执行的。网络状况不佳时,Start() 方法是比较耗时 (注意,这里在Start方法中调用了异步方法GetStringAsync,但该方法在此处是以同步方式执行的,具体原因下文会进行说明) ,在 Start() 方法执行完毕之前,整个程序处于阻塞状态。而异步编程可以很好的解决这个问题,一句简单的话来概括异步编程就是,程序无须按照代码顺序自上而下的执行。\nasync/await C#5.0新增了async和await关键字,使用这两个关键字可以大大简化异步编程\n使用 async 关键字可将方法、lambda 表达式或匿名方法标记为异步,即,方法中应该包含一个或多个await表达式,但async关键字本身不会创建异步操作。\n1public async Task Asy() 2{ 3 //do something... 4} 这里需要注意一点,若使用async关键字标记的方法中没有使用await关键字(编译器会给出警告但不报错),那么该方法将会以同步方式执行。\n定义异步方法的几点要求 定义一个异步方法应满足以下几点:\n使用async关键字来修饰方法 在异步方法中使用await关键字(不使用编译器会给出警告但不报错),否则异步方法会以同步方式执行 尽量不使用void作为返回类型,若希望异步方法返回void类型,请使用Task 异步方法名称以Async结尾 异步方法中不能声明使用 ref 或 out 关键字修饰的变量 下面定义一个异步方法StartAsync():\n1static async Task\u0026lt;int\u0026gt; StartAsync() 2{ 3 HttpClient client = new HttpClient(); 4 var str = await client.GetStringAsync(\u0026#34;https://www.visualstudio.com/\u0026#34;); 5 return str.Length; 6} 异步返回类型 Task(T) 返回类型 任务返回类型 Void 返回类型 通用的异步返回类型和 ValueTask 异步方法可以具有以下返回类型:\nTask(对于返回值的异步方法)。\nTask(对于执行操作但不返回任何值的异步方法)。\nvoid(对于事件处理程序)。\n从 C#7 开始,任何具有可访问的 GetAwaiter 方法的类型。 GetAwaiter 方法返回的对象必须实现 System.Runtime.CompilerServices.ICriticalNotifyCompletion 接口。\n有关异步方法的详细信息,请参阅使用 Async 和 Await 的异步编程 (C#)。\n在以下其中一节检查每个返回类型,且在本主题末尾可以找到使用全部三种类型的完整示例。\nTask(T) 返回类型 Task 返回类型用于某种异步方法,此异步方法包含 return (C#) 语句,其中操作数具有类型 TResult。\n在下面的示例中,GetLeisureHours 异步方法包含返回整数的 return 语句。 因此,该方法声明必须指定 Task\u0026lt;int\u0026gt; 的返回类型。 FromResult 异步方法是返回字符串的操作的占位符。\n1using System; 2using System.Linq; 3using System.Threading.Tasks; 4 5public class Example 6{ 7 public static void Main() 8 { 9 Console.WriteLine(ShowTodaysInfo().Result); 10 } 11 12 private static async Task\u0026lt;string\u0026gt; ShowTodaysInfo() 13 { 14 string ret = $\u0026#34;Today is {DateTime.Today:D}\\n\u0026#34; + 15 \u0026#34;Today\u0026#39;s hours of leisure: \u0026#34; + 16 $\u0026#34;{await GetLeisureHours()}\u0026#34;; 17 return ret; 18 } 19 20 static async Task\u0026lt;int\u0026gt; GetLeisureHours() 21 { 22 // Task.FromResult is a placeholder for actual work that returns a string. 23 var today = await Task.FromResult\u0026lt;string\u0026gt;(DateTime.Now.DayOfWeek.ToString()); 24 25 // The method then can process the result in some way. 26 int leisureHours; 27 if (today.First() == \u0026#39;S\u0026#39;) 28 leisureHours = 16; 29 else 30 leisureHours = 5; 31 32 return leisureHours; 33 } 34} 35// The example displays output like the following: 36// Today is Wednesday, May 24, 2017 37// Today\u0026#39;s hours of leisure: 5 38// \u0026lt;/Snippet \u0026gt; 在 ShowTodaysInfo 方法中从 await 表达式内调用 GetLeisureHours 时,await 表达式检索存储在由 GetLeisureHours 方法返回的任务中的整数值(leisureHours 的值)。 有关 await 表达式的详细信息,请参阅 await。\n通过从应用程序 await 中分离对 GetLeisureHours 的调用,你可以更好地了解此操作,如下面的代码所示。 对非立即等待的方法 TaskOfT_MethodAsync 的调用返回 Task\u0026lt;int\u0026gt;,正如你从方法声明预料的一样。 该任务指派给示例中的 integerTask 变量。 因为 integerTask 是 Task,所以它包含类型 TResult 的 Result 属性。 在这种情况下,TResult 表示整数类型。 await 应用于 integerTask,await 表达式的计算结果为 integerTask 的 Result 属性内容。 此值分配给 result2 变量。\n重要:Result 属性为阻止属性。 如果你在其任务完成之前尝试访问它,当前处于活动状态的线程将被阻止,直到任务完成且值为可用。 在大多数情况下,应通过使用 await 访问此值,而不是直接访问属性。 上一示例通过检索 Result 属性的值来阻止主线程,从而使 ShowTodaysInfo 方法可在应用程序结束之前完成执行。\n1var infoTask = GetLeisureHours(); 2 3// You can do other work that does not rely on integerTask before awaiting. 4 5string ret = $\u0026#34;Today is {DateTime.Today:D}\\n\u0026#34; + 6 \u0026#34;Today\u0026#39;s hours of leisure: \u0026#34; + 7 $\u0026#34;{await infoTask}\u0026#34;; 任务返回类型 不包含 return 语句的异步方法或包含不返回操作数的 return 语句的异步方法通常具有返回类型 Task。 如果此类方法同步运行,它们将返回 void。 如果在异步方法中使用 Task 返回类型,调用方法可以使用 await 运算符暂停调用方的完成,直至被调用的异步方法结束。\n如下示例中,WaitAndApologize 异步方法不包含 return 语句,因此此方法返回 Task 对象。 通过这样可等待 WaitAndApologize。 请注意,Task 类型不包含 Result 属性,因为它不具有任何返回值。\n1using System; 2using System.Threading.Tasks; 3 4public class Example 5{ 6 public static void Main() 7 { 8 DisplayCurrentInfo().Wait(); 9 } 10 11 static async Task DisplayCurrentInfo() 12 { 13 await WaitAndApologize(); 14 Console.WriteLine($\u0026#34;Today is {DateTime.Now:D}\u0026#34;); 15 Console.WriteLine($\u0026#34;The current time is {DateTime.Now.TimeOfDay:t}\u0026#34;); 16 Console.WriteLine(\u0026#34;The current temperature is 76 degrees.\u0026#34;); 17 } 18 19 static async Task WaitAndApologize() 20 { 21 // Task.Delay is a placeholder for actual work. 22 await Task.Delay(2000); 23 // Task.Delay delays the following line by two seconds. 24 Console.WriteLine(\u0026#34;\\nSorry for the delay. . . .\\n\u0026#34;); 25 } 26} 27// The example displays the following output: 28// Sorry for the delay. . . . 29// 30// Today is Wednesday, May 24, 2017 31// The current time is 15:25:16.2935649 32// The current temperature is 76 degrees. 通过使用 await 语句而不是 await 表达式等待 WaitAndApologize,类似于返回 void 的同步方法的调用语句。 Await 运算符的应用程序在这种情况下不生成值。\n如同上一个 Task 示例,可以从 await 运算符的应用程序中分离对 Task_MethodAsync 的调用,如以下代码所示。 但是,请记住,Task 没有 Result 属性,并且当 await 运算符应用于 Task 时不产生值。\n以下代码将调用 WaitAndApologize 方法和等待此方法返回的任务分离。\n1Task wait = WaitAndApologize(); 2 3string output = $\u0026#34;Today is {DateTime.Now:D}\\n\u0026#34; + 4 $\u0026#34;The current time is {DateTime.Now.TimeOfDay:t}\\n\u0026#34; + 5 $\u0026#34;The current temperature is 76 degrees.\\n\u0026#34;; 6await wait; 7Console.WriteLine(output); Void 返回类型 在异步事件处理程序中使用 void 返回类型,这需要 void 返回类型。 对于事件处理程序以外的不返回值的方法,应返回 Task,因为无法等待返回 void 的异步方法。 这种方法的任何调用方必须能够继续完成,而无需等待调用的异步方法完成,并且调用方必须独立于异步方法生成的任何值或异常。\n返回 void 的异步方法的调用方无法捕获从该方法引发的异常,且此类未经处理的异常可能会导致应用程序故障。 如果返回 Task 或 Task 的异步方法中出现异常,此异常将存储于返回的任务中,并在等待该任务时再次引发。 因此,请确保可以产生异常的任何异步方法都具有返回类型 Task 或 Task,并确保会等待对方法的调用。\n有关如何在异步方法中捕捉异常的更多信息,请参阅 try-catch。\n以下示例定义一个异步事件处理程序。\n1using System; 2using System.Threading.Tasks; 3 4public class Counter 5{ 6 private int threshold = 0; 7 private int iterations = 0; 8 private int ctr = 0; 9 10 event EventHandler\u0026lt;EventArgs\u0026gt; ThresholdReached; 11 12 public Counter(int threshold) 13 { 14 this.threshold = threshold; 15 ThresholdReached += thresholdReachedEvent; 16 } 17 18 public async Task\u0026lt;int\u0026gt; StartCounting(int limit) 19 { 20 iterations = 1; 21 for (int index = 0; index \u0026lt;= limit; index++) { 22 if (ctr == threshold) 23 thresholdReachedEvent(this, EventArgs.Empty); 24 ctr++; 25 await Task.Delay(500); 26 } 27 int retval = ctr + (iterations - 1) * threshold; 28 Console.WriteLine($\u0026#34;On iteration {iterations}, reached {limit}\u0026#34;); 29 return retval; 30 } 31 32 async void thresholdReachedEvent(object sender, EventArgs e) 33 { 34 Console.WriteLine($\u0026#34;Reached {ctr}. Resetting...\u0026#34;); 35 await Task.Delay(1000); 36 ctr = 0; 37 iterations++; 38 } 39} 40 41public class Example 42{ 43 public static void Main() 44 { 45 RunCounter().Wait(); 46 } 47 48 private static async Task RunCounter() 49 { 50 var count = new Counter(5); 51 await count.StartCounting(8); 52 } 53} 通用的异步返回类型和 ValueTask 从 C# 7 开始,异步方法可返回任何具有可访问的 GetAwaiter 方法的类型。 Task 和 Task 是引用类型,因此,性能关键路径中的内存分配会对性能产生负面影响,尤其当分配出现在紧凑循环中时。 支持通用返回类型意味着可返回轻量值类型(而不是引用类型),从而避免额外的内存分配。\n.NET 提供 System.Threading.Tasks.ValueTask 结构作为返回任务的通用值的轻量实现。 要使用 System.Threading.Tasks.ValueTask 类型,必须向项目添加 System.Threading.Tasks.Extensions NuGet 包。 如下示例使用 ValueTask 结构检索两个骰子的值。\n1using System; 2using System.Threading.Tasks; 3 4class Program 5{ 6 static Random rnd; 7 8 static void Main() 9 { 10 Console.WriteLine($\u0026#34;You rolled {GetDiceRoll().Result}\u0026#34;); 11 } 12 13 private static async ValueTask\u0026lt;int\u0026gt; GetDiceRoll() 14 { 15 Console.WriteLine(\u0026#34;...Shaking the dice...\u0026#34;); 16 int roll1 = await Roll(); 17 int roll2 = await Roll(); 18 return roll1 + roll2; 19 } 20 21 private static async ValueTask\u0026lt;int\u0026gt; Roll() 22 { 23 if (rnd == null) 24 rnd = new Random(); 25 26 await Task.Delay(500); 27 int diceRoll = rnd.Next(1, 7); 28 return diceRoll; 29 } 30} 31// The example displays output like the following: 32// ...Shaking the dice... 33// You rolled 8 请参阅 FromResult\n演练:使用 Async 和 Await 访问 Web (C#)\n异步程序中的控制流 (C#)\nAsync await\n","date":"2018-04-08T21:14:06Z","permalink":"https://www.zhhuu.top/posts/csharp-async/","section":"posts","tags":["后端","软件开发","C#"],"title":"C#异步介绍"},{"categories":null,"contents":"UEFI BIOS可以说是legacy BIOS的继承者,也就是传统BIOS的后代。以后的主流模式。\nGPT MBR与GPT的区别 传统的MBR最大支持2TB的单分区,最多能设置4个主分区;GPT支持2TB以上的单分区,理论上能设置128个主分区(硬盘的4k对齐与GPT无关联,AHCI和GPT无关联)\nMBR分区表:Master Boot Record,即硬盘主引导记录分区表,只支持容量在 2.1TB 以下的硬盘,超过2.1TB的硬盘只能管理2.1TB,最多只支持4个主分区或三个主分区和一个扩展分区,扩展分区下可以有多个逻辑分区。 GPT分区表:GPT,全局唯一标识分区表(GUID Partition Table),与MBR最大4个分区表项的限制相比,GPT对分区数量没有限制,但Windows最大仅支持128个GPT分区,GPT可管理硬盘大小达到了18EB。只有基于UEFI平台的主板才支持GPT 分区引导启动。\nGPT-ESP ESP分区:EFI system partition,该分区用于采用了EFI BIOS的电脑系统,用来启动操作系统。分区内存放引导管理程序、驱动程序、系统维护工具等。如果电脑采用了EFI系统,或当前磁盘用于在EFI平台上启动操作系统,则应建议ESP分区。如果只是作为仓库盘,就没必要设置这个分区了。\nGPT-MSR ESP分区:EFI system partition,该分区用于采用了EFI BIOS的电脑系统,用来启动操作系统。分区内存放引导管理程序、驱动程序、系统维护工具等。如果电脑采用了EFI系统,或当前磁盘用于在EFI平台上启动操作系统,则应建议ESP分区。如果只是作为仓库盘,也同样没必要设置这个分区。\nSECURE BOOT(Windows8+) SECURE BOOT功能:Windows 8中增加了一个新的安全功能,Secure Boot内置于UEFI BIOS中,用来对抗感染MBR、BIOS的恶意软件, Windows 8 缺省将使用Secure Boot,在启动过程中,任何要加载的模块必须签名(强制的),UEFI固件会进行验证, 没有签名或者无法验证的,将不会加载。\nUEFI UEFI全称“统一的可扩展固件接口”(Unified Extensible Firmware Interface), 是一种详细描述类型接口的标准。这种接口用于操作系统自动从预启动的操作环境,加载到一种操作系统上。\nUEFI的优点 1.纠错特性:与BIOS显著不同的是,UEFI是用模块化、C语言风格的参数堆栈传递方式、动态链接的形式构建系统,它比BIOS更易于实现,容错和纠错特性也更强,从而缩短了系统研发的时间。更加重要的是,它运行于32位或64位模式,突破了传统16位代码的寻址能力,达到处理器的最大寻址,此举克服了BIOS代码运行缓慢的弊端。\n2.兼容性:与BIOS不同的是,UEFI体系的驱动并不是由直接运行在CPU上的代码组成的,而是用EFI Byte Code(EFI字节代码)编写而成的。Java是以“Byte Code”形式存在的,正是这种没有一步到位的中间性机制,使Java可以在多种平台上运行。UEFI也借鉴了类似的做法。EFI Byte Code是一组用于UEFI驱动的虚拟机器指令,必须在UEFI驱动运行环境下被解释运行,由此保证了充分的向下兼容性。\n3.鼠标操作:UEFI内置图形驱动功能,可以提供一个高分辨率的彩色图形环境,用户进入后能用鼠标点击调整配置,一切就像操作Windows系统下的应用软件一样简单。\n4.强大的可扩展性:UEFI将使用模块化设计,它在逻辑上分为硬件控制与OS(操作系统)软件管理两部分,硬件控制为所有UEFI版本所共有,而OS软件管理其实是一个可编程的开放接口。借助这个接口,主板厂商可以实现各种丰富的功能。比如我们熟悉的各种备份及诊断功能可通过UEFI加以实现,主板或固件厂商可以将它们作为自身产品的一大卖点。UEFI也提供了强大的联网功能,其他用户可以对你的主机进行可靠的远程故障诊断,而这一切并不需要进入操作系统。\n5.图形界面:目前UEFI主要由这几部分构成:UEFI初始化模块、UEFI驱动执行环境、UEFI驱动程序、兼容性支持模块、UEFI高层应用和GUID磁盘分区组成。\n在什么情况下能使用UEFI+GPT模式来装系统呢? win7/8 64位系统+UEFI才能在GPT中引导哦。但是现在使用传统legacy+MBR模式装系统的,还是比较多的。\nAHCI AHCI(Serial ATA Advanced Host Controller Interface)串行ATA高级主控接口/高级主机控制器接口),是在Intel的指导下,由多家公司联合研发的接口标准,它允许存储驱动程序启用高级串行 ATA 功能,\nAHCI本质是一种PCI类设备,在系统内存总线和串行ATA设备内部逻辑之间扮演一种通用接口的角色(即它在不同的操作系统和硬件中是通用的)。这类设备描述了一个含控制和状态区域、命令序列入口表的通用系统内存结构;每个命令表入口包含SATA设备编程信息,和一个指向(用于在设备和主机传输数据的)描述表的指针。 AHCI通过包含一个PCI BAR(基址寄存器),来实现原生SATA功能。由于AHCI统一接口的研发成功,使得支持串行ATA产品的开发工作大为简化,操作系统和设备制造商省去了单独开发接口的工作,取而代之的是直接在统一接口上进行操作,可以实现包括NCQ(Native Command Queuing)在内的诸多功能。 AHCI模式则与IDE模式相反,装系统时需要安装SATA驱动(而且貌似只有这个模式能打开NCQ功能)。\n开启AHCI有什么好处 可以提升性能。\nAHCI是串行ATA高级主控接口的英文缩写,它是Intel所主导的一项技术,它允许存储驱动程序启用高级SATA功能,如本机命令队列(NCQ)和热插拔。开启AHCI之后可以发挥SATA硬盘的潜在的性能,理论上大约可增加30%的硬盘读写速度。 硬盘在更改为AHCI模式之后,系统启动的速度变化不大。不过在进行大文件拷贝时,速度由原来的60MB/S提升到了71MB/S,性能提升约20%。硬盘在Windwos7中的系统评分中,也由开始的5.9分提升到了6.5分。由此可见硬盘开启AHCI之后,效果是不错的。\nTIPS Mac OS X 10.X基本上都用的是GPT+UEFI 安装新系统时推荐使用GPT+UEFI\n","date":"2018-04-07T13:01:03Z","permalink":"https://www.zhhuu.top/posts/gpt-partition/","section":"posts","tags":["硬盘","安装"],"title":"GPT分区是啥?"},{"categories":null,"contents":"昨天重新灌了电脑的系统,发现 hexo 不能用了\n安装基本软件 Git Node.js 注意:必须使用 Node v12.14.0 旧版 Hexo 才不会报错\n注:Node.js(中文网站)没有使用 https,原因是使用后可能导致无法打开此网页\n步骤 假使 hexo 目录为 D:/hexo\n打开 CMD [按下**(win+r)**组合键,输入 cmd] 输入 npm:如果没有 npm 的详细信息,请重装 Node.js CMD 中定位到 hexo 目录 1d: 2cd hexo 安装 hexo:在 CMD 中输入npm install -g hexo 安装完成后关闭 CMD 打开 Git,定位到 hexo 的目录cd d:/hexo 可以使用啦! 密钥问题 打开 Github,转到你的设置 找到SSH and GPG keys,添加新的密钥\n1git config --global user.name \u0026#34;用户名\u0026#34; 2git config --global user.email \u0026#34;邮箱\u0026#34; 3 4ssh-keygen -t rsa -C \u0026#34;邮箱\u0026#34; 你的 windows 账户文件夹内,会有.ssh 的文件夹,找到里面的id_rsa.pub文件。将其内部所有内容复制到 github 的密钥框中,确定即可。\n注:如果上面配置 ssh 时叫你设置密码设置空密码就可以了。\n","date":"2017-08-28T23:05:40Z","permalink":"https://www.zhhuu.top/posts/wakeup-hexo/","section":"posts","tags":["hexo","前端"],"title":"如何唤醒在硬盘中的hexo"},{"categories":["Skills"],"contents":"介绍如何用Markdown语法在hexo上写文章,发现自己对这类东西还不是很熟悉233\u0026hellip;\nMarkdown语法 粗体 样式 **样式**\n斜体 样式 *样式*\n删除线 样式 ~~样式~~\n分割线 样式\n细线:--- 粗线:***\n外链 样式 [描述](链接地址) 代码行 样式 `样式`\n##代码块\n1@Echo off 2Echo \u0026#34;Hello World!\u0026#34; 3Pause ``` @Echo off Echo \u0026ldquo;Hello World!\u0026rdquo; Pause ```\n引用 样式\n\u0026gt; 样式\n插入图片 ![描述](图片链接地址)\n分级标题 1H1 : # Header 1 2H2 : ## Header 2 3H3 : ### Header 3 4H4 : #### Header 4 5H5 : ##### Header 5 6H6 : ###### Header 6 我是一级标题 我是二级标题 1我是一级标题 2==== 3 4 5我是二级标题 6---- 无序列表 可以用+或-或*\n示例:\n无序列表项1 无序列表项2 无序列表项3 有序列表 使用数字和英文句点表示有序列表, 不要求数字一定要连续。\n示例:\n有序列表项1 有序列表项2 有序列表项3 绘制表格 列1 列2 列3 1,1 1.2 1,3 2,1 2,2 2,3 3,1 3,2 3,3 4,1 4,2 4,3 1| 列1\t| 列2\t| 列3\t| 2|------:|------:|------:| 3| 1,1\t| 1.2\t| 1,3\t| 4| 2,1\t| 2,2\t| 2,3\t| 5| 3,1\t| 3,2\t| 3,3\t| 6| 4,1\t| 4,2\t| 4,3\t| 反斜杠 Markdown 支持在以下这些符号前面加上反斜杠来帮助插入普通的符号:\n1\\ 反斜线 2` 反引号 3* 星号 4_ 底线 5{} 花括号 6[] 方括号 7() 括弧 8# 井字号 9+ 加号 10- 减号 11. 英文句点 12! 惊叹号 总结 大概就是这么多了,足够写文章了2333\u0026hellip;\n","date":"2017-08-08T09:30:38Z","permalink":"https://www.zhhuu.top/posts/hexo-grammer/","section":"posts","tags":["Hexo","语法","前端"],"title":"Hexo书写语法"},{"categories":null,"contents":"A calculator was written by huuhghhgyg [2022-03-02]:该项目已被归档,只是留作纪念。\n链接 View on Github 在Github查看 Download .zip 下载.zip文件 Download .tar.gz 下载.tar.gz文件\n说明 若要访问原网页点击\u0026gt;这里\u0026lt;\n嗯,就只是一个计算器嘛没什么好看的….要下赶快下XDD\n历代大版本更新 计算器1.0(最初版本) 基本的傻瓜计算器功能,差不多支持键盘乱弹。\n计算器2.0(已遗失) 作为向Material Design的过渡 计算器3.0 拥有更好的界面,Material Design设计标准,更多的功能。支持生成随机数,计算日期之间的间隔等新功能。\n计算器4.0(当前版本) 新增了科学计算器。改进了科学计算器的界面。持续改进!\n","date":"2017-06-26T08:51:34Z","permalink":"https://www.zhhuu.top/posts/hcalculator/","section":"posts","tags":["后端","软件开发","C#"],"title":"HCalculator"}]