-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.json
1 lines (1 loc) · 160 KB
/
index.json
1
[{"categories":["resources"],"contents":"在项目开发的过程中,合作是必不可少的,许多开发人员会同时开发一个项目,这意味着他们需要一个合适的方法来帮助他们协作,Git就是世界上最常用的版本控制软件,Github是世界上最大的代码托管平台。你会在下面的Microsoft Learn路径了解版本控制的必要性,与git和GitHub的基础使用方法,并顺便学会Markdown这一非常常用的标记语言工具。\n俱乐部有一些新生也可以积极参与的项目,学习git和GitHub是参与其中的必要一步。\nTips:Git与GitHub只是一种工具,你可以边参与开发边学习如何使用它,就像你从未系统学习过如何使用Microsoft Word,每次你需要使用到它的一些功能时你都会现查现学,本质是需要用起来学。不过跟随Microsoft Learn的路径进行互动式学习先了解一下也不失为一种好方法。\n了解并使用Git 有关版本控制与 Git 结合使用的简介\nhttps://docs.microsoft.com/zh-cn/learn/paths/intro-to-vc-git/\nGit 是领先的版本控制工具,对开发人员至关重要。 了解如何利用 Git 跟踪自己的更改并与他人协作。\nMarkdown与Github pages 使用 Markdown 和 GitHub Pages 与他人协作\nhttps://docs.microsoft.com/zh-cn/learn/paths/collaborate-markdown-github-pages/\n了解如何使用 Markdown 就 GitHub 问题、拉取请求、评论和文档有效地与他人协作。 然后,学习如何使用 GitHub Pages 构建项目网站和博客文章来推广你的项目。\n在此学习路径下,你将学习如何:\n 使用 Markdown 通过代码、图像、列表和表格来整理你的想法。 使用 GitHub 风格的 Markdown (GFM) 来突出显示常用编程语言的语法并关联找到问题、拉取请求和提交内容。 使用 GitHub Pages 创建包含自定义主题的项目页面和博客文章。 Tips:你需要注册一个GitHub账户\n源代码管理 在GitHub的使用过程中,一个核心的步骤是合并代码并解决冲突。\n在 GitHub 上使用合并冲突解决来解决竞争提交\nhttps://docs.microsoft.com/zh-cn/learn/modules/resolve-merge-conflicts-github/\n了解如何使用合并冲突解决来解决分支中的重叠提交。\n学习目标 在本模块中,你将学习以下内容:\n 了解合并的发生方式以及导致合并冲突的原因 轻松解决简单和复杂的合并冲突 与团队共享最佳做法以减少合并冲突 实践一下 访问俱乐部组织下的名字为“2020-mebmers”的仓库,fork并clone到本地,按照提示修改内容,然后提交pull request。\nhttps://github.com/uestc-msc/2020-members\n可以私聊我然后拉你进GitHub的俱乐部组织。\nGithub自动化 这个部分并不是必要的,但自动工作流是一个很强大的工具,可以省去很多重复性的工作,如果你在GitHub pages上发布自己的博客,那么学习GitHub Actions可以让你每次更新博客时少一些本地操作的步骤\n使用 GitHub Actions 自动执行工作流\nhttps://docs.microsoft.com/zh-cn/learn/paths/automate-workflow-github-actions/\n在此学习路径下,你将:\n GitHub Actions 工作流将软件开发生命周期自动化。 使用 GitHub Actions 自动构建应用程序。 使用 GitHub Actions 实现到 Microsoft Azure 的部署。 使用 GitHub 脚本与 GitHub API 交互。 Tips:部署到Azure的相关部分可以不看\n其他资料 实际上Github官网有QuickStart教程\nhttps://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/quickstart\n也有Git教程\nhttps://docs.github.com/en/free-pro-team@latest/github/using-git\nGitHub pages教程\nhttps://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages\n在仓库中管理文件\nhttps://docs.github.com/en/free-pro-team@latest/github/managing-files-in-a-repository\n","date":"2020-10-07T14:46:45+08:00","permalink":"https://luosuu.github.io/post/use-git-to-collaborate/","section":"post","tags":["git","github","Microsoft Learn","Microsoft Student Club"],"title":"Use Git to Collaborate"},{"categories":["resources"],"contents":"这里是成电微软学生俱乐部2020年度Python学习Guideline,将主要通过利用Microsoft Learn这个交互式引导学习平台,引导俱乐部新生入门并学习使用Python,甚至掌握一些基础的人工智能及数据科学的概念。\n我们希望你最终能够自己通过python编程实现一些有趣的小功能,并在2020年12月下旬的俱乐部年会做一些集中的展示,我们为你们的每一步都设置了奖励,如果你在年会上展示你自己编写的程序,我们会给你丰厚的奖励(无论你哪个年级,在年会上展示自己的程序都会获得奖励)。\n在学习过程中的任何问题,随时都十分欢迎在俱乐部大群里讨论交流。\n入门Python编程 使用Python迈出第一步\nhttps://docs.microsoft.com/zh-cn/learn/paths/python-first-steps/?WT.mc_id=learntv-video-learn\n想学习编程语言,但不知从何处着手? 从此处开始! 了解使用 Python 构建简单应用程序所需的基本语法和预期过程。\n在此学习路径下,你将:\n 编写第一批 Python 代码 存储和操作数据以修改其类型和外观 执行代码库中提供的内置功能 向代码添加逻辑以实现复杂的业务功能 完成此学习路径后,你将为后续的 Python 学习路径提供坚实的基础。 建议完成时间:2020/10/08 前\n了解Python如何发挥作用 了解 Python 在太空探索中扮演的角色\nhttps://docs.microsoft.com/zh-cn/learn/paths/introduction-python-space-exploration-nasa/\n此学习路径介绍了 Python 的世界。 但目标不是学习 Python,而是了解 Python 如何在 NASA 创建的创新型解决方案中发挥作用。 该学习路径通过太空探索镜头来激发持之以恒地学习、探索和创建的热情,让你有一天也能帮助我们所有人更多地了解一点外太空。\n通过这些模板,你将:\n 了解和安装学习编程所需的工具 了解核心编程概念并在实际的 NASA 问题中运用它们 了解机器学习和人工智能等领先技术 观看真实的 NASA 员工谈论他们的工作并给出建议 建议完成时间:2020/10/16 前\n开始了解面向数据的Python 使用 Python 和人工智能对太空岩石进行分类\nhttps://docs.microsoft.com/zh-cn/learn/paths/classify-space-rocks-artificial-intelligence-nasa/\n通过此学习路径,你可了解 AI 和太空的世界。 了解如何创建可对随机照片中的太空岩石的类型进行分类的 AI 模型。\n建议完成时间:2020/11/XX/\nTips:从这里开始你将学习一些实际的操作,但你可能现在还不太了解面向数据的Python等,我们计划你们开始这部分的学习时做一期Python相关的沙龙,来帮助你们更好的学习后续的内容。不过我们不会讨论Python的一些基础语法,因为这些你都可以在网上轻松的学习到,我们主要会讨论Python的一些常见的小问题,如Python的包管理器(pip和anaconda)并交流你们在学习Python的时候遇到的一些问题,然后在沙龙上我们会带领大家自己通过编写Python来画一个词云(WordCloud)。\n有关词云,可以自己先了解同济子豪兄的教程:\nhttps://zhuanlan.zhihu.com/p/66931750\n同济的张子豪同学是同济大学微软学生俱乐部的优秀成员,如今已经是一个分享了非常多技术干货的技术网红。\n他的很多文章都很有价值,且有很多新手入门向的教程。他的知乎专栏地址如下:\nhttps://www.zhihu.com/people/zhang-zi-hao-64-2/posts?page=1\n对人工智能原理感兴趣的同学可以阅读他专栏下的“大白话讲解卷积神经网络工作原理”\n他对于如何安装和配置Python也有新手向的教程:https://zhuanlan.zhihu.com/p/58790338\n关于人工智能的相关概念的入门 Azure上的人工智能入门\nhttps://docs.microsoft.com/zh-cn/learn/paths/get-started-with-artificial-intelligence-on-azure/\nTips:你可以只了解人工智能的相关概念,比如什么是机器学习,什么是计算机视觉,什么是自然语言处理等等。但如果条件允许,你也可以通过路径里的链接快速自己尝试一下相关的功能,里面有一些demo展示。\n注意路径里的链接里多了个中文句号,访问的时候把这个句号删掉就可以了,否则你可能会得到一个空白页或404 Not Found。\n关于数据科学的入门 数据科学基础知识\nhttps://docs.microsoft.com/zh-cn/learn/paths/foundations-data-science/\n加州大学伯克利分校的数据科学基础课程将三个方面结合在了一起:推理思维、计算思维和实际相关性。 假设数据来自某种实际现象,如何分析该数据才能了解该现象? 本课程教授计算机编程和统计推理的重要概念和技能,并结合对实际数据集的动手分析,其中包括经济数据、文档集合、地理数据和社交网络。 该课程会深入研究有关数据分析的社交问题,例如隐私和设计。\n与加州大学伯克利分校联合制作 - Ani Adhikari 和 John Denero,同时还有 David Wagner 参与编写计算思维和推理思维。\nTips:这是一个较为系统讲解如何学习数据科学的相关基础概念、方法以及使用Python实操的路径,内容较多,但也配备了完整的教材。学习完这个路径后你会掌握一些基础但非常实用的Python数据处理的能力,并建立数据科学的概念。\n使用Python做一些机器学习 通过机器学习预测火箭发射延迟\nhttps://docs.microsoft.com/zh-cn/learn/paths/machine-learning-predict-launch-delay-nasa/\n此学习路径介绍了机器学习的世界。 你将应对 NASA 面临的实际问题并应用机器学习来解决它。 学习目标是调动学生的积极性和好奇心,使其去发现机器学习可如何帮助解决太空探索及生活其他方面的其他问题。\n","date":"2020-10-03T23:10:38+08:00","permalink":"https://luosuu.github.io/post/microsoft-learn-python-path/","section":"post","tags":["python","Microsoft Student Club","Microsoft Learning"],"title":"Microsoft Learn Python Path"},{"categories":["OJ"],"contents":"题面:https://atcoder.jp/contests/abc173/tasks/abc173_d\n为了让每个值最大效用化,我们肯定是从大到小的插入,所以首先我们需要对输入的友好值序列排序。\n在插入值的过程中,为了让某个较大的值物尽其用,肯定是在它的顺时针方向旁边插一个,逆时针方向插一个,由于新插入的值肯定小于等于它,所以每个插入的值最多被感受两次友好值。事实上,除了第一个插入的数,都可以被感受两次达到物尽其用。都可以顺时针方向邻接插一个,逆时针方向邻接插一个。\n对于长度为n的友好值序列,会插值n次,也就是感受值序列也是长度为n。\n对于友好值序列\n5 4 3 2 1 它的感受值序列为\n0 5 4 4 3 那么我们只需要特殊处理第1个和第2个感受值,剩下的在n长度范围内将友好值第二高开始都计算两次,直到计算总次数达到n(包含特殊处理的第一次和第二次)。\n以下是C++代码\n#include \u0026lt;iostream\u0026gt;#include \u0026#34;algorithm\u0026#34;using namespace std; int main() { int N; cin \u0026gt;\u0026gt; N; long long int A[N]; for (int i = 0; i \u0026lt; N; ++i) { cin \u0026gt;\u0026gt; A[i]; } sort(A,A+N); long long int res = A[N-1]; int number = 2; for (int i = N-2; number\u0026lt;N ; i-- ) { if(number+2\u0026lt;=N) { res = res + 2 * A[i]; number+=2; }else{ res = res + A[i]; number++; } } cout \u0026lt;\u0026lt; res; return 0; } ","date":"2020-08-08T22:49:34+08:00","permalink":"https://luosuu.github.io/post/atabc173d/","section":"post","tags":["C++"],"title":"AtABC173D-环上的贪心"},{"categories":["OJ"],"contents":"题面:https://atcoder.jp/contests/abc173/tasks/abc173_c\n用题解的方式来理解,对于每一行是否被涂成红色,可以用一个二进制数来表示,假如有三行,以下可以做示例。\nNo,No,No-0,0,0,\nYes,No,No-0,0,1,\nNo,Yes,No-0,1,0,\nYes,Yes,No-0,1,1\n虽然看起来是位置反过来了,其实是说第一行被涂成红色了,那二进制数的第一位就是1。\n我们就可以枚举所有行和列的状态,对于三行四列来说,行有$2^3$个状态(0-7),列有$2^4$个状态(0-15),共有$2^3 \\cdot 2^4=2^{3+4}$个状态。\n对于每一个状态,我们可以检查黑色区域的数量,对于第i行第j列的区域,我们可以检查这个区域是否被涂成红色的行或列覆盖,与它本身是不是黑色。\n检查某个区域是不是被涂成红色的行或列覆盖的方法,就是通过将代表行状态的二进制数,右移i位并与1做与运算,判断结果是不是为0,如果是0,说明没有被覆盖。\n这是因为右移i位后,第i位就变成了第1位,与1做与运算,如果原本第i位是1(该行被涂成红色),结果就会是1,否则就是0。列同理。\nC++代码如下:\n#include \u0026lt;iostream\u0026gt;#include \u0026#34;string\u0026#34; using namespace std; int main() { int H,W,K; cin \u0026gt;\u0026gt; H \u0026gt;\u0026gt; W \u0026gt;\u0026gt; K; char map[H][W]; for (int i = 0; i \u0026lt; H; ++i) { scanf(\u0026#34;%s\u0026#34;,map[i]); } int solutions = 0; for (int i = 0; i \u0026lt; (1 \u0026lt;\u0026lt; H) - 1; ++i) { for (int j = 0; j \u0026lt; (1 \u0026lt;\u0026lt; W) - 1; ++j) { int black = 0; for (int k = 0; k \u0026lt; H; ++k) { for (int l = 0; l \u0026lt; W; ++l) { if( ( (i\u0026gt;\u0026gt;k)\u0026amp;1 )==0\u0026amp;\u0026amp;((j\u0026gt;\u0026gt;l)\u0026amp;1)==0\u0026amp;\u0026amp;map[k][l]==\u0026#39;#\u0026#39; ){ black++; } } } if(black==K){ solutions++; } } } cout \u0026lt;\u0026lt; solutions; return 0; } ","date":"2020-08-08T20:52:39+08:00","permalink":"https://luosuu.github.io/post/atabc173c/","section":"post","tags":["C++"],"title":"AtABC173C-状态压缩"},{"categories":["OJ"],"contents":"《浅谈ST表》完整请参考:https://www.luogu.com.cn/blog/zhouziheng666/qian-tan-st-biao\n核心要素\n 查询操作可以重叠,如max操作max(a,b,c)=max(max(a,b),max(b,c)) 采用倍增的方法构建,如果用$f(i,j)$代表从第i个数开始,共$2^j$个数的最大值,那么就有: $$ f(i,j)=max(f(i,j-1),f(i+2^{j-1},j-1)) $$\n 自然,$f(i,0)=a[i]$\n 由于查询的时候,查询的长度可能是小于等于N的任何一个整数,设该查询的长度是len,查询的数组的第一个数是整个数组的第r个数。我们可以用$max[r,r+len]$来代表被查询的数组的最大值,以上面的函数的定义,可以用 $$ f(r,log_{2}(len)) $$ 来表示。在输入数组总长度N后,我们需要对1到N的所有数求对数,提前存储好所有可能要用的log(len)。\n 对于某个从第r个数开始的被查询的长度为len数组,$f(r,log_{2}(len))$的实际来源为\n$$f(r,1)=max(f(r,1-1),f(r+2^{1-1},1-1))$$ $$f(r,2)=max(f(r,2-1),f(r+2^{2-1},2-1)) $$ $$f(r,3)=max(f(r,3-1),f(r+2^{3-1},3-1)) $$ $$\u0026hellip;$$ $$f(,log_{2}len)=max(f(r,log_{2}len-1),f(r+2^{log_{2}len-1},log_{2}len-1))$$\n在获取数组长度和数组内容后,实际上是用所有的$f(i,0)$获得了所有的$f(i,1)$,然后再用$f(i,1)$得到所有的$f(i,2)$(这个过程要保证$i+2^j$不超过N,否则会越界),一直到获得$f(0,log_{2}N)$。这样查询时,对于任意一个$f(r,log_{2}len)$都能立刻查询到,查询的复杂度为$O(1)$。\n 如果查询的数组长len,$[log_{2}len]$代表len对2取对数的向下取整,那么一次这种函数的构建最多能包含$2^{[log_{2}len]}$个数,如果len不是2的倍数,那么就会有数不会被包括进去,所以实际上为了求该数组的最大值,是从左端和右边分别构建一个函数($2^{[log_{2}len]}$肯定大于$len/2$),取这两个函数的最大值: $$ max[r,r+len]=max(f(r,log(len)), f(r-log(len)+1,log(len))) $$\n 对于任何可以重叠的查询操作,都可以使用ST表这种方法,无非是从$f(i,0)$开始向上构建时采用的方法不同。但构建逻辑和数据结构是一样的。\n ","date":"2020-08-08T14:34:53+08:00","permalink":"https://luosuu.github.io/post/stsheet/","section":"post","tags":["C++","洛谷"],"title":"STsheet"},{"categories":["OJ"],"contents":"题面:https://ac.nowcoder.com/acm/contest/6871/B\n分析 典型的字符串处理,而且出题人强调了没有括号嵌套(真亚撒西嘤嘤嘤)。\n因为分子式不同部分的计算方式是不一样的,可以用缓冲的思想来解决这个问题。\n在不考虑括号嵌套的情况下\n#include \u0026lt;iostream\u0026gt;#include \u0026#34;string\u0026#34;using namespace std; typedef long long ll; string a; int main(){ cin\u0026gt;\u0026gt;a; ll ans=0,cnt=0,res=0,sum=0; int len=a.length(); for(int i=0;i\u0026lt;a.length();) { if(a[i]==\u0026#39;C\u0026#39;||a[i]==\u0026#39;H\u0026#39;||a[i]==\u0026#39;O\u0026#39;){ if(a[i]==\u0026#39;C\u0026#39;)cnt=13; if(a[i]==\u0026#39;H\u0026#39;)cnt=1; if(a[i]==\u0026#39;O\u0026#39;)cnt=17; i++; res=0; while(i\u0026lt;len\u0026amp;\u0026amp;a[i]\u0026gt;=\u0026#39;0\u0026#39;\u0026amp;\u0026amp;a[i]\u0026lt;=\u0026#39;9\u0026#39;){ res=res*10+a[i]-\u0026#39;0\u0026#39;; i++; } if(!res)ans+=cnt; else ans+=cnt*res; } //遇到左括号,就先把未加进最终结果的非括号内元素们算入结果,清空缓冲区,准备计算括号内的分子式 if(a[i]==\u0026#39;(\u0026#39;\u0026amp;\u0026amp;i\u0026lt;len){ sum+=ans; ans=0; i++; } //遇到右括号,结算括号内部的 if(a[i]==\u0026#39;)\u0026#39;\u0026amp;\u0026amp;i\u0026lt;len){ i++; res=0; while(i\u0026lt;len\u0026amp;\u0026amp;a[i]\u0026gt;=\u0026#39;0\u0026#39;\u0026amp;\u0026amp;a[i]\u0026lt;=\u0026#39;9\u0026#39;){ res=res*10+a[i]-\u0026#39;0\u0026#39;; i++; } if(!res)sum+=ans; else sum+=ans*res; ans=0; } } sum+=ans; printf(\u0026#34;%lld\u0026#34;,sum); } 用递归的方式处理括号嵌套 如果要考虑括号内部的嵌套,就需要用到递归的方法了。\n先说缓冲区的部分,遇到常规字符C,H,O,将缓冲区算入结果,将常规字符的值读入缓冲区,以处理后面可能会出现的数字,括号等情况。\n遇到左括号,也是先将缓冲区算入结果,然后进入下一层函数,计算括号内部的分子式,遇到右括号时内部分子式返回来。如果内部还有括号,同理,会进入再下一层函数。最后将括号内的值读入缓冲区。\n遇到数字,就会继续往下读,直到把整个数字段都读出来(这个过程会转换为具体的数字times)。然后将缓冲区内的值乘以times算入结果,清空缓冲区(这里清空缓冲区是必要的,虽然读入下一个数据的时候会覆盖它,但是如果已经是最后一个数据,就会跳出循环,执行最后的缓冲区内数据算入结果,如果不清空会多算一次)。\n#include \u0026lt;cstdio\u0026gt;#include \u0026#34;string\u0026#34;#define ll long long using namespace std; char in[1000050]; int len; ll cal(int \u0026amp;now){ ll tmp=0,sum=0,times=0; for(now;now\u0026lt;len;){ if(in[now]\u0026gt;=\u0026#39;0\u0026#39;\u0026amp;\u0026amp;in[now]\u0026lt;=\u0026#39;9\u0026#39;){ times=(in[now]-\u0026#39;0\u0026#39;); now++; while(in[now]\u0026gt;=\u0026#39;0\u0026#39;\u0026amp;\u0026amp;in[now]\u0026lt;=\u0026#39;9\u0026#39;){ times*=10; times+=(in[now]-\u0026#39;0\u0026#39;); now++; } sum+=tmp*times; tmp=0; continue; } //遇到左括号时,先将缓冲区内部加入结果,然后进入下一层函数,计算内部分子式,遇到右括号再返回来 if(in[now]==\u0026#39;(\u0026#39;){ sum+=tmp; now++; tmp=cal(now); } else if(in[now]==\u0026#39;)\u0026#39;){ sum+=tmp; now++; return sum; } //遇到常规字符也是把上一个缓冲区的内容加入结果,把当前的加入缓冲区,以处理后面可能会出现的数字 if(in[now]==\u0026#39;C\u0026#39;){ sum+=tmp; tmp=13; now++; }else if(in[now]==\u0026#39;H\u0026#39;){ sum+=tmp; tmp=1; now++; }else if(in[now]==\u0026#39;O\u0026#39;){ sum+=tmp; tmp=17; now++; } } sum+=tmp; return sum; } void solve(int T){ scanf(\u0026#34;%s\u0026#34;,in); len=strlen(in); int now=0; printf(\u0026#34;%lld\u0026#34;,cal(now)); } signed main(){ int t=1; //scanf(\u0026#34;%d\u0026#34;,\u0026amp;t); for(int i=1;i\u0026lt;=t;i++){ solve(i); } } ","date":"2020-08-06T11:13:49+08:00","permalink":"https://luosuu.github.io/post/2020shanghai-b/","section":"post","tags":null,"title":"2020shanghai B - 缓冲区结算、括号嵌套的递归"},{"categories":["OJ"],"contents":"题面:https://atcoder.jp/contests/abc174/tasks/abc174_e\n分析 输入N个有长度A[n]的原木,现在要一共对这些木头切至多K刀,求切K刀后所有木材最长的木材的最短值。即让切K刀后的所有木材的最长值尽量短。\n检验一个木材最长值len是否符合切K刀的条件是简单的,只需要每个原木的长度除以len向上取整再减一,然后取和,就能检验是否符合切K刀的条件。\n这类找出 “最长值的最短”“最小值的最大”一类,也就是max(min(len))或min(max(len))一般是使用二分查找方法的提示。\n在寻找最长木材的最小值的过程中,我们可以先用1做开头,原木中最长值max_len做结尾,然后以这俩为首位进行二分查找。有三种情况\n 当中值mid的切割次数小于K次,说明mid取的太长了,将mid作为新的结尾;\n 如果mid的切割次数大于K次,说明取的太短了,应该把mid作为新的开头;\n 当mid的切割次数恰好等于K次,说明mid\u0026gt;=最长木材的最小值,应该继续往下探,将mid作为新的结尾。\n 代码如下\n#include \u0026lt;iostream\u0026gt;using namespace std; long long cut_times(long long *logs, long long cut_len, int log_num); int main() { int N,K; cin \u0026gt;\u0026gt; N \u0026gt;\u0026gt; K; long long logs[N]; long long max_long = 0; for(int i = 0;i\u0026lt;N;i++){ cin \u0026gt;\u0026gt; logs[i]; if(logs[i] \u0026gt; max_long) { max_long = logs[i]; } } if(K==0){ cout \u0026lt;\u0026lt; max_long; return 0; } long long start = 1; long long end = max_long; long long mid; //binary search while(start\u0026lt;end){ mid = (start + end)/2; if(cut_times(logs, mid, N)\u0026lt;=K){//cut times equals to k, still need to try a smaller one end = mid; }else if(cut_times(logs, mid, N)\u0026gt;K){ start = mid+1; } } cout \u0026lt;\u0026lt; start; } // Given max cut length, get needed cut times long long cut_times(long long *logs, long long cut_len, int log_num){ long long need_times = 0; for(int i = 0;i\u0026lt;log_num;i++){ if(*logs%cut_len==0){ need_times += *logs/cut_len-1; }else{ need_times += *logs/cut_len; } logs++; } return need_times; } ","date":"2020-08-06T10:04:10+08:00","permalink":"https://luosuu.github.io/post/atabc174-e/","section":"post","tags":null,"title":"AtABC174 E-二分查找"},{"categories":["OJ"],"contents":"题面:https://codeforces.com/contest/1399/problem/A\n存储每一例数据,排序,判断相邻的两个之间是否超过1即可。这里要注意的是输入输出的方式。\n以下注释掉的地方也都是可以采用的方式。\n其中一种方式是避免动态数组,使用用提前规定好的最大数组。(虽然这个题用动态数组也过了)\n#include \u0026#34;stdio.h\u0026#34;#include \u0026#34;algorithm\u0026#34;#include \u0026#34;iostream\u0026#34;using namespace std; //int a[1050]; void solve(){ int n; // scanf(\u0026#34;%d\u0026#34;,\u0026amp;n); cin \u0026gt;\u0026gt; n; int a[n]; for (int i = 0; i \u0026lt; n; ++i) { // scanf(\u0026#34;%d\u0026#34;,\u0026amp;a[i]); cin \u0026gt;\u0026gt; a[i]; } sort(a,a+n); for (int i = 1; i \u0026lt; n; ++i) { if(a[i]-a[i-1]\u0026gt;1){ // puts(\u0026#34;NO\u0026#34;); cout \u0026lt;\u0026lt; \u0026#34;NO\u0026#34; \u0026lt;\u0026lt;endl; return; } } // puts(\u0026#34;YES\u0026#34;); cout \u0026lt;\u0026lt; \u0026#34;YES\u0026#34; \u0026lt;\u0026lt; endl; } using namespace std; int main(){ int t; // scanf(\u0026#34;%d\u0026#34;,\u0026amp;t); cin \u0026gt;\u0026gt; t; for (int i = 0; i \u0026lt; t; ++i) { solve(); } return 0; } another 还有一道题也是和输入输出相关的\n题目描述:\n大学的同学来自全国各地,对于远离家乡步入陌生大学校园的大一新生来说,碰到老乡是多么激动的一件事,于是大家都热衷于问身边的同学是否与自己同乡,来自新疆的小赛尤其热衷。但是大家都不告诉小赛他们来自哪里,只是说与谁是不是同乡,从所给的信息中,你能告诉小赛有多少人确定是她的同乡吗?\n输入描述:\n包含多组测试用例。\n对于每组测试用例:\n第一行包括2个整数,N(1 \u0026lt;= N \u0026lt;= 1000),M(0 \u0026lt;= M \u0026lt;= N*(N-1)/2),代表现有N个人(用1~N编号)和M组关系;\n在接下来的M行里,每行包括3个整数,a,b, c,如果c为1,则代表a跟b是同乡;如果c为0,则代表a跟b不是同乡;\n已知1表示小赛本人。\n输入样例:\n3 1\n2 3 1\n5 4\n1 2 1\n3 4 0\n2 5 1\n3 2 1\n本题的输入部分可以这样写\n#include \u0026lt;stdio.h\u0026gt;int main() { int N, M; // 每组第一行是2个整数,N和M,至于为啥用while,因为是多组。 while(scanf(\u0026#34;%d %d\u0026#34;, \u0026amp;N, \u0026amp;M) != EOF) { printf(\u0026#34;%d %d\\n\u0026#34;, N, M); // 循环读取“接下来的M行” for (int i=0; i\u0026lt;M; i++) { int a, b, c; // 每行是3个整数,a,b,c。 scanf(\u0026#34;%d %d %d\u0026#34;, \u0026amp;a, \u0026amp;b, \u0026amp;c); printf(\u0026#34;%d %d %d\\n\u0026#34;, a, b, c); } // M行读取完了,就又要开始下一组了,去while那里。 } } and another one! 还有一道题是2020上海高校程序设计竞赛的C题\n计算每一例聊天记录里,含2的句子占的比例。\n#include \u0026lt;iostream\u0026gt;#include \u0026#34;string\u0026#34;using namespace std; int main() { int T; cin \u0026gt;\u0026gt; T; double rate[T]; double num[T]; for(int i = 0;i\u0026lt;T;i++){ num[i] = 0; int n; cin \u0026gt;\u0026gt; n; getchar(); for(int j = 0;j\u0026lt;n;j++){ string in; getline(cin,in); int len = in.size(); for(int k = 0;k\u0026lt;len;k++){ if(in[k]==\u0026#39;2\u0026#39;){ num[i]++; break; } } } rate[i] = num[i]/(n*1.0); cout \u0026lt;\u0026lt; rate[i] \u0026lt;\u0026lt; endl; } } one more thing 转载一下CSDN上的OJ之C++输入输出总结。\n不知道输入几组 计算a+b的和\n每行包含两个整数a和b\n对于每行输入对应输出一行a和b的和\n输入\n1 5\n输出\n6\n #include \u0026lt;iostream\u0026gt;using namespace std; int main() { int a,b; while(cin \u0026gt;\u0026gt; a \u0026gt;\u0026gt; b)//注意while处理多个case cout \u0026lt;\u0026lt; a+b \u0026lt;\u0026lt; endl; return 0; } 知道输入几组 先输入一个组数n,然后再循环读取n组数据。\n#include \u0026lt;iostream\u0026gt;using namespace std; int main() { int n; // 数据的组数 cin \u0026gt;\u0026gt; n; // 读取组数 for(int i=0; i\u0026lt;n; ++i){ int a, b; cin \u0026gt;\u0026gt; a \u0026gt;\u0026gt; b; cout \u0026lt;\u0026lt; a+b \u0026lt;\u0026lt;endl; } return 0; } 字符串的输入处理 因为OJ最终只比较文件,就不用保存所有输入,可以读一组数据计算一组数据。\n当读取字符串的时候需要注意,cin不能读取空白字符,比如空格,如果遇到空格则会直接终止字符串。\n#include \u0026lt;iostream\u0026gt;#include \u0026lt;string\u0026gt;using namespace std; int main() { string s; cin \u0026gt;\u0026gt; s; // 读到空白就结束当前的字符串 \tcout \u0026lt;\u0026lt; s; return 0; } 运行的结果:\nabc 123 abc请按任意键继续. . . 如果要读取整行字符串,可以使用getline()和cin.getline()这两个函数,两个函数都是遇到定界符,则结束这行的字符串,定界符默认设置为回车。两个函数略有不同的是,getline()操作的对象是string,cin.getline()操作的对象的char数组。详细的定义如下:\ngetline(),要使用这个函数需要包含头文件\u0026lt;string\u0026gt;,\nistream\u0026amp; getline(istream\u0026amp; is, string\u0026amp; str, char delim); istream\u0026amp; getline(istream\u0026amp; is, string\u0026amp; str); is:它是istream类的对象,告诉函数从何处读取输入流。 str:这是一个string字符串对象,从流中读取输入后,将输入存储在此对象中。 delim:这是定界字符,它告诉函数在达到该字符后停止读取进一步的输入。 返回值:此函数返回值是与输入参数is相同的输入流。 #include \u0026lt;iostream\u0026gt;#include \u0026lt;string\u0026gt;using namespace std; int main() { string s; getline(cin, s); cout \u0026lt;\u0026lt; s;\tsystem(\u0026#34;pause\u0026#34;); return 0; }\t12345678910 运行结果:\nabc 123 abc 123请按任意键继续. . . cin.getline()函数读取至新行结尾或直到达到最大限制的整行文本。函数定义如下:\n// (buffer, stream_size, delimiter) istream\u0026amp; getline(char*, int size, char=\u0026#39;\\n\u0026#39;) // The delimiter character is considered as \u0026#39;\\n\u0026#39; istream\u0026amp; getline(char*, int size) 12345 提取字符直到定界符。 将字符存储在缓冲区中。 提取的最大字符数为size-1。 #include \u0026lt;iostream\u0026gt; using namespace std; int main() { char str[20]; cin.getline(str, 20); cout \u0026lt;\u0026lt; str; return 0; } 123456789 运行结果:\nno bug forever no bug forever请按任意键继续. . . 12 例子:\n输入为9个数字,每个数字用逗号,分隔,将数字保存到一个一维数组中。\n 1,2,3,4,5,6,7,8,9\n #include \u0026lt;iostream\u0026gt;#include \u0026lt;string\u0026gt;#include \u0026lt;vector\u0026gt;using namespace std; void test() { string str; cin \u0026gt;\u0026gt; str; // 获取整行数据 \tvector\u0026lt;int\u0026gt; vec; // 将数字保存在数组中 \tfor (char\u0026amp; ch : str) { if (isdigit(ch)) vec.push_back(ch - \u0026#39;0\u0026#39;); // 如果是数字才保存,并且需要减去字符0 \t} for (int\u0026amp; i : vec) { cout \u0026lt;\u0026lt; i \u0026lt;\u0026lt; \u0026#39; \u0026#39;; } } int main() { test(); system(\u0026#34;pause\u0026#34;); return 0; } 123456789101112131415161718192021 运行结果:\n1,2,3,4,5,6,7,8,9 1 2 3 4 5 6 7 8 9 请按任意键继续. . . ","date":"2020-08-06T08:41:45+08:00","permalink":"https://luosuu.github.io/post/cf661-a/","section":"post","tags":null,"title":"Cf#661 A-输入输出"},{"categories":["OJ"],"contents":"题面:https://atcoder.jp/contests/abc174/tasks/abc174_c\n本题可以简单化简 $$ K \\cdot a=7 \\cdot \\frac{1-10^n}{1-10} $$\n等同于 $$ K \\cdot a \\cdot 9=7 \\cdot (10^n-1) $$\na是K的倍数,n为被除数的位数,n即为所求。只要右侧式能够整除9K(a是个整数),那么就满足要求。\n于是调试n,用右侧式对左侧进行取模操作即可。\n但计算过程中有$10^n$的限制,可能会超过long long 数据的最大值。\n这里要引出取模运算的运算规则\n(a+b)%p=(a%p+b%p)%p (a-b)%p=(a%p-b%p)%p (a*b%p)=(a%p * b%p)%p (a^b)%p=((a%p)^b)%p 观察右侧式,先抛去7这个乘数,它的变化应该是\n9 99 999 ... 可以表示为\nd(0)=9 d(1)=d(0)*10+9 d(2)=d(1)*10+9 ... d(n)=d(n-1)*10+9 现在要求d(n)能不能整除9K,可以递推式的表达,这样循环中每一次验证都只需要一次计算。\n最后考虑停机条件,时间限制为2s,以CPU 1GHz的速度来考虑,保守的可以设置停机条件为2e7。如果2e7位数还没有找到,大概率是没有了。\n完整的代码可以写为\n#include \u0026lt;iostream\u0026gt;using namespace std; int main() { long int K; cin \u0026gt;\u0026gt; K; long int s = 9 * K; if(K % 2 == 0 || K % 5 == 0){ cout \u0026lt;\u0026lt; -1; return 0; } long int d = 9; for(long i = 1;i\u0026lt;20000000;i++){ if((7*d)%s==0){ cout \u0026lt;\u0026lt; i; return 0; } d = (d*10+9)%s; } cout \u0026lt;\u0026lt; -1; return 0; } one more thing 关于模运算有很多有趣的知识,其中一些在OJ中经常常用,快速幂就是其中一个。\n快速幂的全称是“快速计算一个幂式的模(余)”\n假如我们要计算a^b mod c\n如果我们直接算\nint ans = 1; for(int i = 1;i\u0026lt;=b;i++) { ans = ans * a; } ans = ans % c; 那么当b比较大的时候,long long 也是撑不住的,数据会溢出。\n可以根据模运算的性质(a^b)%p=((a%p)^b)%p\n在算指数之前先取模,这样可以小一些\nint ans = 1; a = a % c; for(int i = 1;i\u0026lt;=b;i++) { ans = ans * a; } ans = ans % c; 如果一个因子取余不影响最终结果,那么中间的因子取余应该也是不影响结果的(反正最后都被消掉,可以在计算指数的过程中消掉)\nint ans = 1; a = a % c; for(int i = 1;i\u0026lt;=b;i++) { ans = (ans * a)%c; } ans = ans % c; 现在已经比最开始好很多了,但现在的复杂度式还是O(b),当b比较大的时候还是有可能超时。\n也就是问题出现在求指数的过程中,这里要考虑到如何快速计算幂式,我们可以这样考虑 $$ 2^{1000}=4^{500} $$ 底数做一次平方,运算次数少了一半,如果是奇数 $$ 2^{1001}=4^{500}*2 $$ 现在先不考虑幂式求模余的问题,如果单纯要求快速计算a^b\n方法应该是这样的\n当指数b是偶数时,平方底数,指数b自除2;\n当指数b是奇数时,先用一个数才收集落单的底数,然后平方底数,b自减1再除2。\n最后除到b为1的时候,用于收集落单的底数的数就会乘以最后的底,从而变成最终结果。\nint QuickPower(int a,int b){ int result = 1; while(b\u0026gt;0){ if(b % 2 == 1){ result = result*a; b = b - 1; } b = b/2; a = a * a; } } 如何应用在求幂式的模余中呢?应该是很简单的。\n当指数b是偶数时,平方底数,指数b自除2;\n当指数b是奇数时,先让ans乘以底数a(这里可以对c取模优化),用于收集落单的底数,然后平方底数,b自减1再除2。\nint PowerMod(int a, int b, int c) { int ans = 1; a = a % c; while(b\u0026gt;0) { if(b % 2 == 1){ ans = (ans * a) % c; } //由于是整形,不减1直接除二也是可以的 b = b/2; // 下面这种写法也是可以的,右移操作也是可以实现除二,并且自动舍去了余数(就是对整数这样操作不tidy) // b = b \u0026gt;\u0026gt; 1 a = (a * a) % c; } return ans; } ","date":"2020-08-04T17:04:51+08:00","permalink":"https://luosuu.github.io/post/atabc174_c/","section":"post","tags":null,"title":"AtABC174C-模运算"},{"categories":["software"],"contents":"最近参加了腾讯微信小程序开发训练营,记录一些有趣的点。\n参考文档:\n腾讯云开发训练营\n微信小程序开放文档\n用户登陆 登陆方式有很多种,可以用wx.login登陆,也可以使用云函数登陆 。所谓云函数,是在云端运行的代码,由微信私有协议天然鉴权,开发者只需编写业务逻辑代码。如果我们想对不同的用户有不同的记录,区分不同的用户的方式就是获取他们的openid。由服务器端云函数返回用户openid是简单的。在创建小程序项目时,选择基于云的小程序,其中的cloudfunctions/login就是登陆函数。\n以下是login云函数的主要内容\n// 云函数模板 // 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署” const cloud = require(\u0026#39;wx-server-sdk\u0026#39;) // 初始化 cloud cloud.init({ // API 调用都保持和云函数当前所在环境一致 env: cloud.DYNAMIC_CURRENT_ENV }) /** * 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端 * * event 参数包含小程序端调用传入的 data * */ exports.main = async (event, context) =\u0026gt; { // 可执行其他自定义逻辑 // console.log 的内容可以在云开发云函数调用日志查看 // 获取 WX Context (微信调用上下文),包括 OPENID、APPID、及 UNIONID(需满足 UNIONID 获取条件)等信息 const wxContext = cloud.getWXContext() console.log(\u0026#39;getWXContext返回的结果\u0026#39;,wxContext) return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, env: wxContext.ENV, } } 下面是一个使用云函数登陆的示例代码\nwx.cloud.callFunction({ name:\u0026#39;login\u0026#39;, data:{}, succeess:res=\u0026gt;{ //登陆成功后的处理,其中回调函数的res.result.openid就是云端返回的用户openid //在云端存储用户信息 wx.cloud.callFunction({ name:\u0026#39;setUserInfo\u0026#39; data:{ userid:res.result.openid //其他参数 //.... } }) } }) 文件存储 微信小程序支持本地缓存储存文件,也支持云存储文件。缓存文件只在用户小程序端存在,可以用来缓存用户个人信息等,云存储的文件可以用云开发控制台直接上传,获取cloud://开头的路径,就可以在小程序中直接使用了。\n当然我们也可以让用户上传文件,其中一种方式就是将本地的临时文件上传到云端,要使用wx.cloud.uploadFile\ncloudPath是文件在云端的路径,我们可以指定。\nfilePath是本地临时文件的路径。\nuploadFiles(e) { const filePath = this.data.files[0].src const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\\.[^.]+?$/) wx.cloud.uploadFile({ cloudPath,filePath }).then(res =\u0026gt; { this.setData({ fileID:res.fileID }) }).catch(error =\u0026gt; { console.log(\u0026#34;文件上传失败\u0026#34;,error) }) }, 生命周期 有时候我们需要数据跨页面渲染,我们当然可以全部都存储到云端然后读取、处理,但是也可以使用url带数据的方式将数据传递到下一个页面。\n对于一个链接来说\n / 分隔目录和子目录 ? 分隔实际的 URL 和参数 \u0026amp; URL 中指定的参数间的分隔符 = URL 中指定的参数的值 以下面这个链接为例\n\u0026lt;navigator url=\u0026#34;./../home/detail/detail?id={{index}}\u0026amp;name={{movies.name}}\u0026amp;img={{movies.img}}\u0026amp;desc={{movies.desc}}\u0026#34; class=\u0026#34;weui-media-box weui-media-box_appmsg\u0026#34; hover-class=\u0026#34;weui-cell_active\u0026#34;\u0026gt; 这是一个跳转链接,跳转到home/detail/detail页面,传递了变量id,name,img,desc。这些变量的值都在对应的本页面的js文件中定义。\n然后我们可以在跳转目标页面的js文件里,在onLoad中获得到这些变量,并赋给需要的地方,比如\nonLoad: function (options) { console.log(options) wx.setNavigationBarTitle({ title: options.name }) this.setData({ detail : options, }) }, 一丢丢心得 微信小程序开发主要还是需要熟悉微信小程序开发的框架与规定(与angularJs框架类似),虽然一个功能逻辑可以有很多种写法,但是有很多既定的推荐写法可以借鉴。\n云函数的开发要对各种API比较熟悉,不同的小程序之间可以方便的复用。但是我对云函数的调试并不满意,虽然提供了本地调试的选项,用起来也不是特别的方便。最后要吐槽很多功能的表现在电脑的开发者工具上预览的效果与手机实际效果是有不少差距的,debug的时候也很麻烦。\n","date":"2020-07-29T18:53:26+08:00","permalink":"https://luosuu.github.io/post/wx-miniprogram-tips/","section":"post","tags":["frontend","Tencent","WeChat-MiniProgram"],"title":"微信小程序开发训练营"},{"categories":["Diary"],"contents":"整理心情,重新出发\n我身边的朋友可能知道我最近遭遇了一点小挫折,大学道路陷入了一些迷茫。开下自己的玩笑,就是又“焦虑”了。\n然而高帆学长应该是在他无意之间,给我了很大的帮助。让我重新认识到我想要从事程序语言(PL)方向的初心,并认识到自己的规划的不合理之处。感谢学长的鞭策。\n这里我想重新谈一下sicp,当初读sicp是看重了两方面,一方面是想打基础修内功,另一方面是作为MIT的基础课程,上手难度不会太大。王垠前辈有一篇博客,讲的是如何构造自己的解释器。其中sicp的第一二章为先修内容。\n我曾经过分看重“如何设计一个语言”,“如何构造一个编译器”这种过于“落地”的问题,却忽略了内核,忽略了最开始我入坑的兴趣点。另外,我也太过于容易受旁人的影响,盲目去崇拜龙书、虎书等,并将编译器的工作和PL的工作混淆起来。\n国内的很多教材重视所谓“前端”,包括龙书在内将parser技术长篇大论。然正如对 Parser 的误解里王垠所言,语义转化和优化才是精华的内容,才是软件的核心。学习不是为了解决人为制造的困难而显得高级,而是为了理解其中的原理。如此“头重脚轻”,增大了学习的困难,消磨了学习的热情。\n我在上篇博客整理了下PL相关的学习内容,再结合我“烂尾”的Todo,我学习的优先顺序应该为:\n 南京大学《软件分析》课程 SICP EOPL 这个学期内,能够完成这些内容,可以说是善莫大焉。理解了核心的概念和理念之后,再去看编译器的构造一类,就是工程上的细枝末节和摸索了。\n最后想谈一下国内PL界的风云人物,有很多人确实是受大佬影响而了解的,但也终要能做出他们的影子,独立的思考与研究,真的找到自己感兴趣的内容和关键点才行,而不是大佬在做什么,我就想了解什么,想学什么。大佬之所以为大佬,是因为他们有由衷的热爱和踏实的努力。最后,还是要靠实力说话的。要看清自己该踏踏实实走的路,也莫要想走什么捷径。\n","date":"2020-03-27T12:00:09+08:00","permalink":"https://luosuu.github.io/post/always-know-what-is-important/","section":"post","tags":null,"title":"Always Know What Is Important"},{"categories":["Resources"],"contents":"资源整理向博客\n课程的完整列表可见:\n\thttps://github.com/shining1984/PL-Compiler-Resource\n课程 静态分析 南京大学《软件分析》课程 无教材 有PPT 国内老师,讲的很清楚 Upenn-Software Analysis and Testing Dr.Fernando-DCC888 有PPT,引用资料全 针对静态分析程序分析,及其优化部分 有一部分LLVM的内容 Universitas Arhusiensis-Static Program Analysis 覆盖了静态分析的基本内容 有教材,较成体系 北京大学《软件分析技术》 有课件 内容覆盖宽广 编译器 (1) Stanford CS143:Compilers 编译器基础知识 CS234:Advanced Compilers 程序分析和优化技术 CS 343 最新的研究成果 简化内容的视频资源:https://www.bilibili.com/video/av18939632\n(2) Upenn CIS 341-Compilers Spring 2020\n 基本编译器课程 词法/语法分析、代码生成、语义分析、优化和运行时支持 (4) Rice University COMP412\n(5) Sacramento CSC 151: Compiler Construction\n(6) UIUC CS426 CS526-2011 CS526-2020 (Not started yet) 其他 1.MIT-sicp\n博客 Haskell趣学指南 thautwarm的博客 梁杰的博客-20天刷完sicp okmij.org What is PL research and how is it useful 书 SICP Programming Language Pragmatics ","date":"2020-03-16T11:32:11+08:00","permalink":"https://luosuu.github.io/post/arrangement-of-learning-resources/","section":"post","tags":null,"title":"Arrangement of Learning Resources"},{"categories":["sicp"],"contents":"研究事物的原理和构造,掌握基本方法。\n记一个开始 今天我的SICP实体版到了,虽然有官方html转的PDF,并且英文版的表达也清晰优雅,但是还是抵不住实体版拿在手里的实在。\n这学期开始时我花了三到四周的时间读了《计算机网络:自顶向下方法》的主要内容,近期也准备写一个摘要清理一下脉络。\n我准备花我下半个学期的精力努力研读这本《Structre and Interpretation of Computer Programs》,争取在一月份初,也就是两个月后读完它的主要内容。\n鼓励下我自己:\n坚信一切都是纸老虎,投入全部的精力和时间去思考和研究,不要提前做规划,前面说的两个月只是参考,实际上是竭力而为。\n最后这里记一下PLT相关的,其他的参考资料:\n thautwarm的博客 [梁杰的博客](http://numbbbbb.com/2016/03/28/20160328_我如何用两周时间刷完 SICP/) 知乎专栏:雾雨魔法店 《程序语言设计:实践之路》 okmij.org What is PL research and how is it useful 准备工作 我推荐开始之前先看看上面的链接里第二个和最后一个,了解一下大概的情况以及这个领域关心的问题。\n然后这里搬运一下macOS如何安装MIT-scheme,因为SICP的代码都是基于MIT-scheme的,不过只要是符合IEEE-1990的scheme标准的lisp方言,都可以运行SICP第二版的代码(第二版前言述)。\n首先下载MIT-Scheme的 .dmg文件。\n64-bit\n由于macOS Catalina只支持64位的软件了,所以我推荐下载64位的。下面的是32位的下载链接:\n32-bit\n下载完成后,打开dmg文件把app拖进Application文件夹。\n64位请打开terminal运行\nsudo ln -s /Applications/MIT\\:GNU\\ Scheme.app/Contents/Resources /usr/local/lib/mit-scheme-x86-64 一般会要求你输入密码\n然后运行\nsudo ln -s /usr/local/lib/mit-scheme-x86-64/mit-scheme /usr/bin/scheme 如果不行,把 /usr/bin/scheme换成/usr/local/bin/scheme\n现在你可以在terminal里直接输入 scheme 启动了,启动后输入(+ 1 1)看看是不是运行正常。\n上述方法搬自JACKSON\u0026rsquo;S BLOG\n之后你就可以开始草书了。\n","date":"2020-03-05T18:38:45+08:00","permalink":"https://luosuu.github.io/post/start-plt/","section":"post","tags":null,"title":"Start PLT"},{"categories":["Diary"],"contents":"论学习能力的不同 我觉得学习的能力分为两种,一种是研究理论方法的能力,一种是动手实践解决问题的能力。\n这好比你学习了一种算法,你清楚了它的计算的过程,但是同等重要的是你能自己把代码写出来并且跑通。\n我认为在计算机系的学生,在本科阶段,虽然要坚固理论基础,但动手实践的能力同样也很重要。当你去实际写代码的时候你才会知道很多细节实际写起来要注意的地方很多,不同语言去实现差距会非常大。\n举个不恰当的例子,好比做电路的学生,在仿真软件里能跑通,实际自己去接电路的时候可能会毛手毛脚,会因为很多细节导致结果不够理想(比如元器件的引脚,导线的氧化等等)。\n在这个过程中学习到的,便是 实践的经验 ,这种经验也只能从实践中获得。\n个人觉得本人的实践能力就不够强,很多项目难以做到圆满的状态,很多都只做了主要的部分,很多细节都没有实现(甚至只有个框架和壳子)。\n这么转念一想,PLT领域的研究也许就是为了更多的消除这方面的阻力吧(笑),让大家写代码跟舒服一些,并且不会因为一些玄学出bug。\n","date":"2019-08-10T10:35:20+08:00","permalink":"https://luosuu.github.io/post/computerscience-practice/","section":"post","tags":["Practice"],"title":"计算机是一门实践学科"},{"categories":["Notes"],"contents":"简单记录一下在计算机中如何表示数值与简单运算的。\n进制转换 我们都知道计算机底层数值都是二进制的(由高低电平表示)。而我们生活中常用十进制,同时一些场合下也会用16进制。因此首先我们需要知道进制之间如何转换。\n二进制转十六进制 二进制数以小数点为界,整数部分从小数点从左到右数,每4位分为一组,不足四位的时候在左端补0;小数部分从小数点从右往左数,每四位为一组,不足四位则在右端补0。然后每组按照二进制数与十六进制数对应关系转换。因为2的四次方为16,所以十六进制的每单个数都可以用四位二进制数表示出来。\n十六进制转二进制 直接每位十六进制数都对应转换为四位二进制数即可。\n二进制转十进制 $$(101.01)_2=12^2+02^1+12^0+02^{-1}+1*2^{-2}$$\n十进制转二进制 十进制整数 十进制数不断除二,记录下每一次的余数,直到商为0。先得到的余数是二进制中的低位,后得到的是二进制整数中的高位。\n十进制小数 小数位不断乘二,记录下每一次结果的整数位(当然只有0或1),直到小数位为0。先得到的整数位是二进制中的高位,后得到的整数位是二进制中的低位。\n$$ 0.3125\\cdot2=0.625 $$ $$0.625\\cdot2=1.25$$ $$0.25\\cdot2=0.5$$ $$0.5\\cdot2=1 $$\n因此记录下来的二进制数为0.0101。即\n$$0.3125=(0.0101)_2$$\n当然存在无法达到小数位为0的情况。视精度进行取舍,假如要求五位精度,求到第六位看第六位是0还是1,如果是0直接舍去,如果是1则在第五位进位。\n补码制表示二进制数 上面我们讨论的二进制数都是无符号数,也就是无法用来表示这个数的正负。容易得知无符号数的表示范围是\n$$[0,2n−1]$$\n我们思考一种简单的标志正负的方式,如果用n位来表示一个数,那么我们用最高位来标志这个数的正负,一般最高位为0代表正数,最高位为1代表负数。此时最高位我们称为符号位,剩余的n-1位称为数值位。带有符号的数我们称之为符号数。\n考虑此时的n位二进制数的表示范围,以四位为例,对正数而言最大为0111,负数的表示范围为1111(-8)到1001(-1),此时0有1000和0000两种表示方法。也就是表示范围为\n$$[−2n−1,2n−1−1]$$\n但是这样做会增加运算逻辑的复杂程度,因为加法器要先检查操作,然后再检查二者的符号:符号相同则将二者数值位相加然后赋给结果相同的符号位;如果符号不同还需要比较二者数值部分的大小,用较大的减去较小的,然后赋给结果较大的操作数的符号。\n因此我们引进补码制来表示符号数。实际中的计算机符号数都是用补码制表示的。所以以后符号数就等同于补码制二进制数。\n补码运算 我们先来了解一下补码:一个n位二进制数D的补码为\n$$2^n-D_2$$\n求补码的运算我们称之为补码运算。\n补码运算可以变形\n$$2^n−D =(2^n−1−D)+1$$\n而$2^n-1-D$实际就是n位全1二进制数减去D,相当于对D取反。也就是说求D的补码的过程实际可以变成求D的补码然后再加一。这个运算过程对计算机硬件来说比减法容易得多。\n补码制表示规则和性质 在补码制下同样用最高位表示符号,且0为正,1为负。\n十进制数3的四位补码制二进制数同样为0011,而补码制下的负数为正数的补码。也就是-3表示为\n$$1100_2+1=1101_2$$\n如果你对补码制下的负数再进行补码运算,会得到该数的相反数,也就是变回正数。\n$$0010_2+1=0011_2$$\n这使得在补码制下正数与负数的相互转换非常方便,一对相反数互为对方的补码。\n考虑n位补码制二进制数的表示范围,以4位为例:\n正数最大为0111\n负数可以从 1000(-8)~1111(-1)注意和非补码制的区别\n0为0000,且0的补码仍为0000。\n也就是\n$$[−2n−1,2n−1−1]$$\n补码制下的拓展 对于无符号数,由于没有符号,从4位二进制数拓展到8位只需要在左端加四个0。称这种拓展方式位零拓展\n对于符号数,我们需要考虑它的符号,拓展的规则是直接按照它的符号位进行拓展,也就是1101拓展到8位就表示为了11111101。\n我们可以求一下拓展前后的补码验证一下,前者的补码为0011,也就是3,后者为00000011,也是3。\n对符号数的位数拓展方式我们称为符号拓展\n运算 加减 补码制的提出是为了简化运算。在补码制下运算不需要考虑符号位,符号位直接参与运算即可。并且如果操作为减法,那么就对后面的操作数求补码然后按加法运算即可。而且如果最高位产生了进位直接舍去最高位进位即可。\n$$1110+1010=1000$$\n溢出 运算正确的结果超出了给定的取值范围,就是溢出。这里给出的取值范围就是n位二进制补码表示的范围。\n最高位进位和溢出没有直接关系,可以证明异号相加不会溢出,同号相加才有可能溢出。\n如\n$$0100+0110=1010$$\n正确结果10超出了四位符号数的表示范围。\n判断溢出的方法很简单,如果两个相同符号的数相加,运算结果的符号位变化,那么就可以判断产生了溢出。\n乘除 略\n逻辑运算 移位 总位数不变\n左移:右端直接补0,1110左移两位–1000\n逻辑右移:左端直接补0,1110逻辑右移两位–0011\n算术右移:左端根据符号位补,1110算术右移–1111\n左移和算术右移本质为乘2的n次方(不丢有效位1的情况下)\n按位运算 省\n浮点数的表示和运算 我们现在开始考虑如何来表示小数。\n首先确定正负,我们还是取最高位为符号位,值用S表示。\n先不考虑小数点在哪里,先将这个值用无符号数的方式表示出来,这个过程中我们需要确定我们要取多少位,也就是有效长度。\n假设我们取a位有效长度,然后用a位的空间存储这个有效值A。\n最后我们通过移位的方式来确定小数点在哪里,实现方法是在后面用n位的长度用补码的方式存一个阶数,小数点从有效值的最右端根据阶数的值E移位。\n根据标准二进制浮点数运算标准IEEE-754,移位应该进行到有效值的最高位的后一位,也就是有效值那里的实际值永远是1.x,也就是在该规则方式下,我们用\n$$(-1)^S1.x2^E$$\n来表示带有小数部分的数。x我们称为尾数部分。\n在实际的存储中,如果尾数部分长度为m,那么a=m+1,因为1是公有的所以不需要特别去表示它,直接表示x的部分就行了,也因此存在一个隐藏位1。\n实际中我们需要经常比较阶数部分,为了方便比较,阶数部分实际存储的值都是阶数E+2^(n-1)-1,阶数部分存储的值我们称为阶码,其范围就变成了[000···000, 111···111],实际表示的范围[-2^(n-1)+1,2^(n-1)],这样比较两个浮点数的阶数就很方便了,直接比较的是阶码也就是无符号二进制数。\n根据浮点数标准IEEE-754,有两种浮点数,即单精度浮点数和双精度浮点数。\n二者的符号位都是1位。单精度的阶码位数有8位,尾数有23位;双精度阶码有11位,尾数有52位。\n几个特殊值 浮点数0:尾数全为0,阶码全为0\n无穷:尾数全为0,阶码全为1\n无效操作数:尾数不全为0,但阶码全为1\n因此实际储存中为了正常表示非0浮点数,阶码不能全为1或者0。\n浮点数运算 移位使得两个数的阶码相等,小阶去对等大阶,不要忘记了隐藏位1。 尾数作运算,为了对应可能产生的进位,需要把隐藏位拓展为两位01。 将隐藏位恢复为1,化为标准的浮点数 如果阶码减小到全为0,说明结果的指数太小,出现下溢;如果运算后阶码全变成1,说明结果的指数太大出现上溢。\n","date":"2019-08-10T10:26:12+08:00","permalink":"https://luosuu.github.io/post/value-pre-compute/","section":"post","tags":["计算机数值"],"title":"计算机数值的表示与计算"},{"categories":["Software"],"contents":"为你的zsh终端添加语法高亮\n请先下载并配置好zsh 首先进入到zsh的插件文件夹,我用的是omz,所以要进入omz的插件文件夹\ncd ~/.oh-my-zsh/custom/plugins 然后下载插件\ngit clone git://github.com/zsh-users/zsh-syntax-highlighting.git 然后更改.zshrc里的配置\nplugins=(zsh-syntax-highlighting) 然后读取配置即时生效\nsource ~/.zshrc ","date":"2019-07-10T10:39:35+08:00","permalink":"https://luosuu.github.io/post/zsh-highlight/","section":"post","tags":["shell"],"title":"Zsh Highlight"},{"categories":["Software"],"contents":"最近因为一些原因在折腾Azure,毕竟不能浪费微软爸爸发的每月150刀额度。\n创建资源组\naz group create \\ \t--name \u0026lt;Resourse Group Name\u0026gt; \\ \t--location eastus 运行容器\naz container create \\ \t--resource-group \u0026lt;Resourse Group Name\u0026gt; \\ \t--name \u0026lt;Container Tag Name\u0026gt; \\ \t--image \u0026lt;Your IMG\u0026gt; \\ \t--ports 8388 \\ \t--location eastus \\ \t--ip-address public \\ \t--restart-policy Always \\ \t--environment-variables \\ \tPASSWAORD=\u0026lt;YOUR PWD\u0026gt; \\ \tMETHOD=chacha20-ietf-poly1305 检查状态\naz container show \\ \t--resource-group \u0026lt;Resourse Group Name\u0026gt; \\ \t--name \u0026lt;Container Tag Name\u0026gt; 在容器中执行命令\naz container exec \\ --resource-group learn-deploy-aci-rg \\ --name mycontainer \\ --exec-command /bin/sh ","date":"2020-05-13T12:00:09+08:00","permalink":"https://luosuu.github.io/post/azure_contianer_cli/","section":"post","tags":null,"title":"Azure CLI to Deploy Containers"},{"categories":["Software"],"contents":"用Azure CLI快速部署一台实例。\n注意这些操作都可以用Azure门户快速实现,Azure CLI不是唯一选择。\n创建资源组\naz group create \\ --name \u0026lt;resource-group-name\u0026gt; \\ --location \u0026lt;resource-group-location\u0026gt; 在创建的资源组里创建VM\naz vm create \\ --resource-group servers \\ --name MeanStack \\ --image credativ:Debian:10:latest \\ --admin-username azureuser \\ --generate-ssh-keys 打开VM端口的80端口方便访问在其上的网页服务\naz vm open-port \\ --port 80\\ --resource-group [resource group name] \\ --name MeanStack 创建SSH与VM的链接,首先先把vm的ip地址存在bash的变量中方便操作\nipaddress=$(az vm show \\ --name MeanStack \\ --resource-group [resource group name] \\ --show-details \\ --query [publicIps] \\ --output tsv) ssh azureuser@$ipaddress 这样VM就已经准备就绪了\n","date":"2020-05-13T12:00:09+08:00","permalink":"https://luosuu.github.io/post/azure-vm-deployment/","section":"post","tags":null,"title":"Azure CLI VM Deployment"},{"categories":["Diary"],"contents":"记有关“同质化与多样化”一堂课的相关思考。\n专业化的高效和灵活化的强适应 在讨论“同质化和多样化之前”,我想先讨论下专业化和灵活化。\n拿最近武汉应对疫情的例子来说,武汉市在疫情爆发前,是得到表彰的模范城市,夺得多次奖项,但在疫情这种特殊紧急情况爆发的时候,出现了许多问题,并遭到了许多人的批评。从微观上来看,这是因为每一层的负责人在紧急情况下不敢跳出常规、当机立断,选择了最安全的做法,也就是等待上级的决断;而从宏观上来看,是因为科层制体制在长久的发展中已经过于专业化,失去了面对紧急情况需要具有的灵活性的强适应能力。\n这不是说科层制是错的,相反,科层制是全球普遍使用的,长期实践证明的高效组织管理形式。科层制通过对常规事件的层层流程化和规范化,保证了日常执行的高效和准确。问题在于,当紧急情况出现,超出了日常规范的范围之后,基层管理组织就会陷入混乱和被动,他们为了自保而选择等待上级的判断,而很多灾难是不等人的,就错过了管控和遏制的良机。我国的管理体制当然考虑到了这一点,提出的解决办法就是每一层都要制定所谓的“紧急预案”,在突发情况时给基层提供由常规态转到应急态的方式,这类“紧急预案”在我国统计已有550万份之多,然从这次疫情的情况来看,效果并不理想。\n那就没有什么好的办法了吗?这里我想提一下有关我国制造业的一个例子。1994年,我国实行分税制改革,革除包干制,地方政府不再”交齐国家的,剩下的就是自己的“,变成了一部分种类的税收归国家所有,剩下的一部分税种归地方政府所有,而建筑类税收就归地方所有,地方还可以拍卖土地使用权获得收入,这极大的促进了房地产和开发区的建设。有很多人称我国为”世界工厂“,是因为我国的城郊有许多“开发区”,在那里有许多许多企业,其中很多是制造类企业,这些制造类企业接受着来自世界各地的订单,生产着各型各样的产品。\n这些制造类企业通常不会很大,却十分专精,可能只专注于生产于一两个小零件,但是这些小企业可以互相组合,生产出五花八门的产品。每个小企业的专门化保证了生产的效率,而互相组合形成的网络产生了巨大的弹性,表现出了对市场的强适应性。而恰逢西方国家在20世纪末21世纪初转型进入“创新经济时代”,对产品的迭代速度和更新速度有了极大的要求,而企业很难在拥有一条完全自主的生产线保证高效化的同时保证产品的迭代速度,这导致了很多企业式微(如诺基亚就拥有一条完整的自主生产线,导致产品迭代变化的成本很高,最终渐渐倒塌),也逼迫很多企业将生产环节完全迁出,以避免快速迭代产品的巨大生产成本,自己只负责跟上顶层的产品设计。这和中国的发展开发区和企业园区的需求不谋而合。正所谓时势造英雄,中国就这样产生了制造业的高速发展,也是中国经济腾飞的奥秘。我相信这个例子,还是有很大参考的价值。\n同质化与多样化 与“专业化和灵活化”相对应的一个很重要的话题,是“同质化与多样化”。\n在押井守的著名动画电影《攻壳机动队》(1995)里,一个拥有自我意识的“生命体”诞生于网络中信息的海洋。它非常的清楚自己的缺陷,那就是它虽然可以不断复制,但是缺少了生物的多样性和唯一性,一个计算机病毒就可能将它和它的复制体全部摧毁,为了获得多样性和唯一性,它找上了片中的女主角草薙素子,希望能和她的意识融合。\n片中多次提及了关于同质化与多样化的内容。素子所在的公安九科全都是义体化非常高的生化人,除了脑组织以外大部分都是义肢,而素子却选择将一个保留了几乎全部肉身的警察陀古萨调到九科任职。当陀古萨问及为什么,素子表示虽然义体化的人机能强大,但是一个组织过于单一必将走向灭亡,而陀古萨就是用来增加组织的多样性和不确定性的。\n生物的族群虽然看起来每个个体都十分相似,但是每个人的基因和性状又如此独特而不同,每当灾难来临,虽然可能发生族群大部分的消亡,而经常有因其独特性而坚强活下来的个体,保证了种族的延续。\n关于这个话题,我想讨论的就是这些了,感谢你的阅读。\n","date":"2020-03-28T16:14:22+08:00","permalink":"https://luosuu.github.io/post/homogenization-and-diversification/","section":"post","tags":null,"title":"Homogenization and Diversification"},{"categories":["To Do"],"contents":"寒假ToDoList,用来公开处刑,完不成请私信我让我女装\nBasic sicp主要内容并写读书笔记 托福备考 C++ STL Additional 用SFML写linux下的STG 补课数学 钢琴基础,避免下学期被爆 ","date":"2020-03-05T19:31:15+08:00","permalink":"https://luosuu.github.io/post/to-do-2020-wintervacation/","section":"post","tags":null,"title":"To Do 2020 WinterVacation"},{"categories":["sicp"],"contents":"sicp的1-1主要内容是程序设计的基本元素\n基本元素 基本表达形式:对最简单的元素操作 组合的方法:将基本的表达组合起来形成一块复合的对象 抽象的方法:命名复合对象,使得他们能够封装成一个黑箱 表达式式的求值 基本表达式 规则如下:\n 数的值就是它表示的数值大小 运算符指能运行的操作的机器指令序列 其他名字是在该环境下关联于这个名字的对象 组合表达式 由表达式组合而成的组合式,组成这个组合式的表达式称为该组合式的子表达式(不排除该子表达式也是组合式),它的求值规则如下\n 求值该组合式的子表达式 运用该组合式的运算符号,应用于其实际参数(也就是实际的值而不是表达式,此时子表达式应该都已经计算为实际的数值) 考虑到子表达式也可能是个组合式,那么就需要不断进行第一步,直到我们运算的对象是基本元素,也就是求组合式的过程需要调用自己,也就是这个过程就是 递归 的。\n此时我们可以用树的方法来表示它。\n递归这种方法是处理层次性结构(比如树)的一种强有力的技术。\n在表达式的树里,数值从树的最末端不断向上移动,这种过程我们一般称为树形积累\n环境 环境是极其重要的,在我们定义的一个过程中(也就是我们抽象出来的一个过程),形式参数的命名应该是无关紧要的,这个过程中的同一个形式参数统一换成另外一个名字,应该是不对这个过程产生任何影响的。\n这对于我们封装一个过程极其重要,它可以依赖于外部的一些过程(和在这个过程在同一个环境的其他过程),但是它自己约束的变量,也就是它的形式参数不应该受到外界的控制。\n同时这有利于我们定义 块结构 ,所谓块结构,就是我们在抽象一个过程时,发现它可以用多个子过程实现,我们不选择在这个过程外抽象它的子过程,而选择在这个过程内部抽象它的子过程。\n在块结构中,我们抽象的子过程只能在这个块内使用,且对于子过程来说,该过程的形式参数是可以依赖和修改的。\n本来我们求立方根的过程是\n(define (sqrt x) (sqrt-iter 1.0 x)) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (define (good-enough? guess x) (\u0026lt; (abs (- (square guess) x)) 0.001)) (define (improve guess x) (average guess (/ x guess))) sqrt依赖的子过程全部改到它的内部后\n(define (sqrt x) (define (good-enough? guess x) (\u0026lt; (abs (- (square guess) x)) 0.001)) (define (improve guess x) (average guess (/ x guess))) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (sqrt-iter 1.0 x)) 然后我们发现在子过程中将x的值传来传去没啥意义,他们可以直接访问并且修改x\n(define (sqrt x) (define (good-enough? guess) (\u0026lt; (abs (- (square guess) x)) 0.001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1.0)) 解释的顺序:application-order与normal-order application-order就是将基本表达式求值,从基本的单元解释命名空间里的所有变量,然后一层层推上去,也就是上文组合式的表达方式。\nnormal-order则是先不去算表达式的值,先从外不断按照它的解释去展开定义,直到无法展开,只有计算基本表达式的时候才能往下推进时才计算基本表达式。\n可以证明,那些可以通过替换去模拟,并且产生合法值的所有过程,他们采用这两种方式输出的结果应该是一样的。\n一般而言,都是采用application-order,这样可以避免重复计算表达式。\n这里想要说明的是解释的顺序的重要性,比如SICP例题1-5和1-6就明显的说明了这个问题。\n对于1-5\n(define (p) (p)) (define (test x y) (if (= x 0) 0 y)) (test 0 (p)) 上面是一个用来测试过程是应用application-order还是norma-order的样例。\n如果采用前者,那么解释器会先尝试解释(p),然后再往上运行test的内容,然而(p)用自己解释自己,这样只会陷入死循环,不断输出它解释出来的内容,也就是\n(test 0 (p)) 如果采用normal-order,那么解释器就会先从test的内容开始,过程如下\n(test 0 (p)) (if (= 0 0) 0 (p)) (if #t 0 (p)) 0 对于1-6\n这位同学自己新定义的new-if的差距在于与if的解释顺序不同。\nnew-if在解释器看来就是一个普通的过程,所以解释器会去先尝试去解释那三个参数,如果这三个参数参与了递归过程,那么就是自解释了,陷入死循环。\n而if会先解释判别式,然后在去选择后面的值进行解释,不会陷入死循环。\n","date":"2020-03-05T18:53:26+08:00","permalink":"https://luosuu.github.io/post/sicp-1-1/","section":"post","tags":null,"title":"SICP-1.1:Element and Expressions"},{"categories":["sicp"],"contents":"迭代语法的解释/计算过程\n过程的产生 我们在Elements and Expressions里,已经讨论了程序的基本元素与表达式。\n现在的我们已经可以进行基本的算术操作,对操作进行组合然后抽象、定义为一个复合过程。但是我们还不能说我们已经了解了编程这件事,因为我们现在就像知道了手里的卡牌的使用方法,但是不清楚游戏常见的战术一样,也就是说我们现在缺乏经验,无法预知我们采取的每个动作的后果(执行一个过程的效果)。\n The ability to visualize the consequences of the actions under consideration is crucial to becoming an expert programmer, just as it is in any synthetic, creative activity. –sicp 1.2\n 也就是说,我们需要对我们执行的过程有足够的了解,了解他们运作的模式,还要研究这些计算过程消耗的资源(时间和空间)\n在1.2.1,我们主要关注递归语法的两种计算过程。\n在开始之前,我们要搞清楚一个事情,那就是 递归过程 和 递归计算过程 是两回事,前者指语法的结构的事实,也就是它的定义需要调用它自己,后者是解释递归语法的一种计算方式。\n递归计算过程(线性递归过程) 考虑一个递归,计算阶乘\n(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) 我们观察它的过程\n(factorial 6) (* 6 (factorial 5)) (* 6 (* 5 (factorial 4))) ... (* 6 (* 5 (* 4 (* 3 (* 2 (factorial 1)))))) (* 6 (* 5 (* 4 (* 3 (* 2 1))))) ... (* 6 120) 720 从“形状”上来看,它先不断展开,越来越长,这是因为它必须不断延后它需要实施的运算,然后他会不断收缩,这是实际运算不断实施的体现。\n这类“不断推延运算,需要解释器维护一个运算链条”的过程,我们称为 递归计算过程\n迭代计算过程(线性迭代过程) 然后我们考虑另外一个计算阶乘的过程,刚才我们是从大的数不断计算到小的数,现在我们反过来,从小的数的阶乘开始算,算到大头的数的阶乘。\n(define (factorial n) (fact-iter 1 1 n)) (define (fact-iter product counter max-count) (if (\u0026gt; counter max-count) product (fact-iter (* counter product) (+ counter 1) max-count))) 如果我们用到上一节的块结构,可以把fact-iter隐藏到函数内部\n(define (factorial n) (define (iter product counter) (if (\u0026gt; counter n) product (iter (* counter product) (+ counter 1)))) (iter 1 1)) 然后我们考虑它的计算过程\n(factorial 6) (fact-iter 1 1 6) (fact-iter 1 2 6) (fact-iter 2 3 6) (fact-iter 6 4 6) (fact-iter 24 5 6) (fact-iter 120 6 6) (fact-iter 720 7 6) 我们会发现它有如下重要的性质:\n首先它用的每一步的运算过程都可以独立出来,不需要维持上一步的运算,也就是它用三个 状态变量 完整的描述了这个计算过程,同时它又规定了变量如何向下一个状态转换的计算规则,还有一个(可能会有)的结束检测。\n也就是我们只需要提供这三个状态变量,解释器就可以计算下去,而对比上面说过的递归计算过程,除了变量以外,它还要维持一些隐形的信息(在这里就是外面有多少套嵌的乘法),其实二者的差别根本在于是否明示了 当前计算在这个过程的哪一处\n我们称这种计算方式为 迭代计算过程(线性迭代过程)\n注意,我们在这里我们并没有使用其他语言里常见的 特殊的循环结构 ,譬如 do while,for等等。scheme里的实现没有这一环,scheme总能 在常量空间里执行迭代计算过程,即使这个过程是用递归描述的 ,具有这一特性的实现,我们称其为 尾递归 的。\n有了尾递归的实现,我们就不需要一些特殊的专用迭代结构,可以用常规的过程调用来实表述迭代。\n对比 虽然在这里我们发现树形递归比线性递归要低效的多,但是我们要注意到树形递归的表达能力很好,它很直接了当,对于我们理解和设计程序非常有帮助。\n另外,当我们考虑一种层次结构性的数据上操作时,而不是对数操作时,我们会发现树形递归计算是一种自然、威力强大的工具。\n在Elements and Expression里,对于求值表达式,解释器采用的策略就是树形递归计算过程。\n","date":"2020-03-05T18:52:22+08:00","permalink":"https://luosuu.github.io/post/linear-recursion-and-iteration/","section":"post","tags":null,"title":"Linear Recursion and Iteration"},{"categories":["sicp"],"contents":"作为讨论线性迭代与递归的延续,我们来讨论计算过程的阶数。\n计算过程的阶数 经过Linear Recursion and Iteration我们大概知道了不同的计算过程的代价是不同的,为了实现同样的目标,不同的计算过程消耗的时空资源差距很大。\n因此我们需要提供一种评估不同计算过程消耗资源的情况的方法。\n我们用n来代表问题规模的大小,也就是某个模式下问题的输入。我们需要衡量的是当输入变大时(问题规模变大时),某一计算过程所需资源粗略的增长的情况。\n对于不同的问题我们取的n很可能是不一样的,但是确定的是n肯定是和计算过程的难度/步数紧密相关的,让我们可以根据它来分析计算过程。例如计算平方根的过程这个n我们可以取要精确的小数点后多少位,矩阵乘法可以取矩阵的行数。\n然后我们记R(n)为处理规模为n的问题时所需要的资源量,称之为 增长阶 。总之它是一个用n表达的函数。\nR(n)=Θ(f(n))R(n)=Θ(f(n))\n且对于任意大的n,存在与n无关的k1和k2,使得\nk1f(n)≤R(n)≤k2f(n)k1f(n)≤R(n)≤k2f(n)\n对于斐波那契计算,树形递归需要的步数是\nΘ(ϕn)Θ(ϕn)\n其中\nϕ2=ϕ+1ϕ2=ϕ+1\n空间为\nΘ(n)Θ(n)\n而对于线性迭代过程,步数和空间为\nΘ(n),Θ(1)Θ(n),Θ(1)\n也就是代表线性迭代过程的步数增长正比于n,而空间需求是个常数。\n增长阶的价值 注意这里的度量是一个很粗略的过程,比如一个计算过程的步数为\n3n2+10n+173n2+10n+17\n另外一个计算过程的步数为\n1000n21000n2\n那么这两个计算过程的增长的阶都是\nΘ(n2)Θ(n2)\n但是从外一个角度来看,我们可以通过增长阶窥见一个计算过程的增长变化。\n对于线性过程,规模增长一倍代表计算资源的需求也增长一倍;对于一个指数计算过程,问题规模每增长1都将导致所用资源按照某个常数倍增长;对于对数型增长的计算过程,但问题规模扩大一倍,所需资源量都只增加一个常数。\n","date":"2020-03-05T18:50:56+08:00","permalink":"https://luosuu.github.io/post/sicp-rank/","section":"post","tags":null,"title":"SICP: order of growth"},{"categories":["sicp"],"contents":"“用高阶的函数做抽象”,本次我们更关注于过程本身的一些特性,以及相关的抽象方式\nlambda lambda表达式可以增强我们的表达能力,使我们表达一些简单的过程时非常方便,如:\n(lambda (x) (+ x 4)) 这样我们在很多地方就无须再构建辅助过程了,直接使用lambda表达就可以,lambda表达式的优点之一还在于这个过程没有名字,不与环境中的任何名字相关联,且lambda表达式内部的环境和一般的过程一样,与外部独立。\n然后我们需要介绍一下lambda的另外一种用法\n((lambda (\u0026lt;var_1\u0026gt; ... \u0026lt;var_n\u0026gt;) \u0026lt;body\u0026gt;) \u0026lt;exp_1\u0026gt; ... \u0026lt;exp_n\u0026gt;) 其含义为,在body中将var_1至var_n解释为exp_1至exp_n\n比如\n(define (f x y) ((lambda (a b) (* a b)) (a (+ y (* x x))) (b (- (* x y) x)))) \u0008其中f就为\n$$f(x,y)=(x^2+y)\\cdot(x*y-x)$$\n这个使用方式有一个语法外衣let\n(let ((var_1 exp_1) ... (var_n exp_n) \u0026lt;body\u0026gt;)) let只是lambda上述使用方式的语法外衣,完全等效,但是看起来更舒适一点,var和exp一一对应。\nlisp中的过程 在lisp当中,过程是更一般的对象,也就是既可以作为参数也可以作为返回值,如同就和一般的变量一般。\n我们来看以下方法\n(define (average-damp f) (lambda (x) (average x (f x)))) average-damp是一个以f为参数的方法,返回的也是一个方法,返回的方法由lambda产生。\naverage-damp可以用来求x和f(x)的平均值\n使用它的例子可以如下\n((average-damp square) 10) 55 也就是说我们可以将过程(也就是计算的方式)作为参数传递进另外一个过程,而那另外一个过程无须关心f具体是什么。\n这是一种重要的抽象机制,也是典型的复合过程(思考下和前面几篇提到过的复合过程的区别)。\n一般而言,设计语言时会对计算元素可能使用方式作出限制,限制最少的元素就被称作是具有 第一级 的状态。\n在lisp中过程就是第一级状态的。(你可以想一下C语言中是否允许将函数作为参数进行传递)\n第一级元素有一些特权,如:\n 可以用变量命名 可以提供给过程作参数 可以作为过程的结果返回 可以包含在数据结构中(详情在sicp第二章中讲述) ","date":"2020-03-05T18:49:12+08:00","permalink":"https://luosuu.github.io/post/sicp-1-3/","section":"post","tags":null,"title":"sicp-1.3:Formulating Abstractions with Higher-Order Procedures"},{"categories":["sicp"],"contents":"SICP第二章的导引\n所谓数据抽象 我们在第一章关注了 计算过程,并了解了\n 基本的数据和基本的操作(Element and Expressions) 如何将一些过程组合起来形成复合过程(Formulating Abstractions with Higher-Order Procedures ) 简单的算法分析和计算模式(Order of growth,Linear Recursion and Iteration) 第二章将要关注构造 复合数据。也就是我们要构造一种将数据组合起来的计算对象。\n其中的关键在于:数据对象的如何表示的部分,与数据对象的如何使用部分互相隔离,使其具有一定的模块性,这种技术一般称作 数据抽象。\n进一步思考,如果分隔开了数据对象的表示细节和处理方法,那么理应站在处理方法的一侧看时,应该无须关心数据对象具体如何表示,无须为所用的数据做任何多余的假设;同时站在数据对象的表示一侧来看,它的数据定义应该和数据如何使用无关。将二者之间联通的部分(原书翻译为“界面”,或理解为“平台”),称为 选择函数 和 构造函数\n数据抽象是我们用来克服问题复杂性的技术,它可以用于在程序的不同部分建立适当的 抽象屏障。\n数据抽象的关键在于,程序设计语言中应该提供了一些“粘合剂“,可以将数据对象组合起来,形成更复杂的数据对象。在后面我们会解释其中的一些关键理念,如 闭包 和 符号表达式,他们用于构造和解释复杂的数据对象。\n而后我们需要一种”通用型的操作“,它必须能处理不同的数据结构。我们会引入数据导向型的程序设计。\n第二章的关键在于理解数据抽象的概念,掌握相关的理念和方法(用斜体标注出来了)\n","date":"2020-03-05T18:45:23+08:00","permalink":"https://luosuu.github.io/post/introduction-to-sicp-chapter-2/","section":"post","tags":null,"title":"Introduction to SICP Chapter 2"},{"categories":["sicp"],"contents":"为了引入第二章的概念和主题,我们尝试构建有理数的数据类型并且定义它的计算方法。\n表示有理数 我们知道有理数肯定可以用分数的方式来表示,而分数由分子和分母构成,因此我们可以用一对数的组合来表示分数,也就是有理数。\n好在scheme给我们提供了天然的数对结构Pairs,我们可以用以下方式将两个数组合起来\n(define x (cons 1 2)) (car x) 1 (cdr x) 2 我们用cons操作将1和2组合起来,称之为x,car返回x的首元素,cdr返回x的尾元素。值得一提的是,数对的元素还可以是数对。\n运算有理数 定义好了有理数,我们要定义有理数的运算方式。\n这里我们先定义三个基本的方法,分别是make-rat,numer,denom。\nmake-rat将将两个数组合成有理数,而numer返回分子,denom返回分母\n(define (make-rat n d) (cons n d)) (define (numer x) (car x)) (define (denom x) (cdr x)) 在考虑分子之间互相运算,加减乘除和判断相等分别可以定位为\n(define (add-rat x y) (make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y)))) (define (sub-rat x y) (make-rat (- (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y)))) (define (mul-rat x y) (make-rat (* (numer x) (numer y)) (* (denom x) (denom y)))) (define (div-rat x y) (make-rat (* (numer x) (denom y)) (* (denom x) (numer y))) (define (equal-rat? x y) (= (* (numer x) (denom y)) (* (numer y) (denom x)))) 我们现在可以构成、运算分数了,但是现在的分数还不不具备约分化简的能力,于是我们要用到1.2.5节的gcd,也就是查找最大公约数的方法修改make-rat\n(define (make-rat n d) (let ((g (gcd n d)) (cons (/ n g) (/d g)))) 现在我们就完成了有理数数据类型的基本结构了。然后我们来回顾一下这个过程然后思考一些问题。\n抽象屏障(Abstraction Barriers) 我们可以看到,上述有理数的数据设计是有明显的层次的\n上层都无须关注下层的具体实现,例如make-rat不需要关注序对怎么实现的,add-rat也不需要关心make-rat是怎么实现的。\n这种思想的有点基本可以概括为\n 程序容易维护和修改 可以先扔下底层的具体实现而先构建上层 第一点很好理解,对于第二点,我们可以举个例子\n对于刚才我们实现的三个基本方法,约分的步骤是在构造有理数的方法make-rat里实现的,但是我也可以让有理数就原原本本的保存,在取分子或者分母的时候再约分,如下\n(define (make-rat n d) (cons n d)) (define (numer x) (let ((g (gcd (car x) (cdr x))) (/ (car x) g)))) (define (denom x)) (let ((g (gcd (car x) (cdr x))) (/ (cdr x) g))) 区别只在于何时运用gcd约分,如果我们需要多次访问有理数的分子和分母,那么我们最好最开始构造有理数的时候就约分,如果情况并非如此,那么我们就可以取分子和取分母的时候再约分。\n而这种区别,对于上层我们如何设计add-rat等方法没有任何影响,我们可以先放下何时取约分这种细节问题,不让他干扰我们整体系统的设计。\n数据是什么 对于上面的例子,constructor就是make-rat,selector就是numer和denom。而数据就是由constructor和selector所构建的,当然constructor和selector不是随便的几个过程就行的,还要满足一些条件,对于上面有理数的例子,条件就是\n(define x (make-rat n d)) (equal-rat? x (cons (car x) (cdr x)))=true 因此我们可以说数据是由满足 使得表达式完整有意义的条件 的constructor和selector所构建的。\n","date":"2020-03-05T18:42:28+08:00","permalink":"https://luosuu.github.io/post/sicp-2-1-1/","section":"post","tags":null,"title":"sicp-2.1.1-Examples:Arithmetic Operations for Rational Numbers"},{"categories":["Diary"],"contents":"","date":"2020-08-08T18:05:13+08:00","permalink":"https://luosuu.github.io/post/sangxinbingkuang/","section":"post","tags":["capitalism"],"title":"丧心病狂的争论"},{"categories":["Software"],"contents":"Something magical\nConfig file on macOS vim /usr/local/etc/shadowsocks-libev.json Example:\n{ \u0026#34;server\u0026#34;:\u0026#34;abc.xyz.com\u0026#34;, \u0026#34;server_port\u0026#34;:8888, \u0026#34;local_port\u0026#34;:1080, \u0026#34;password\u0026#34;:\u0026#34;AbCdEfGhIjKlMn\u0026#34;, \u0026#34;timeout\u0026#34;:5, \u0026#34;method\u0026#34;:\u0026#34;chacha20-ietf-poly1305\u0026#34;, \u0026#34;mode\u0026#34;:\u0026#34;tcp_and_udp\u0026#34;, \u0026#34;plugin\u0026#34;: \u0026#34;obfs-local\u0026#34;, \u0026#34;plugin_opts\u0026#34;: \u0026#34;obfs=http;obfs-host=cloudflare.net\u0026#34; } Restart services\nbrew services restart shadowsocks-libev ","date":"2020-03-11T16:03:03+08:00","permalink":"https://luosuu.github.io/post/something-magical/","section":"post","tags":null,"title":"Something Magical"},{"categories":["Software"],"contents":"灵活管理JDK\nWhat\u0026rsquo;s jenv 在我安装weka的python包时,需要安装javabridge这个包,于是我先后下载了JDK13和openJDK1.8.0,需要管理JDK的环境(题外话,安装javabridge时需要环境为JDK8或者同等级的openJDk,太新的JDK13不行)\njenv 是一个命令行工具,可以在 Linux/OS X 平台使用,可以管理多个版本 JDK,方便在多个版本 JDK 之间切换,另外其还可以设置 JAVA_HOME 环境变量。\n使用 jenv 有一个前提,必须提前安装 JDK,其不提供下载安装 JDK 的功能。MacOSX 平台可以提前使用 brew 安装 JDK。\nInstall jenv brew install jenv macOS只需brew一行安装即可,其他平台请见下方\ngit clone https://github.com/jenv/jenv.git ~/.jenv 如果是bash:\necho \u0026#39;export PATH=\u0026#34;$HOME/.jenv/bin:$PATH\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.bash_profile echo \u0026#39;eval \u0026#34;$(jenv init -)\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.bash_profile source ~/.bash_profile 如果是zsh:\necho \u0026#39;export PATH=\u0026#34;$HOME/.jenv/bin:$PATH\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.zshrc echo \u0026#39;eval \u0026#34;$(jenv init -)\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc usage 先用下面这行查找出所有已安装的JDK\n/usr/libexec/java_home -V 找到JDK的路径后,使用\njenv add \u0026lt;JDK_path\u0026gt; 将JDK加入jenv的管理\n有些应用程序需要使用JAVA_HOME环境变量,可以设置jenv轻松变更该环境变量\njenv enable-plugin export ## 运行这个才会生效 exec $SHELL -l 可以用下面这条显示所有jenv管理的版本\njenv versions 对当前文件夹更换JDK环境\njenv local \u0026lt;version_number\u0026gt; 对当前shell里的所有操作更换JDK环境\njenv shell \u0026lt;version_numbers\u0026gt; 全局设置JDK环境\njenv global \u0026lt;version_numbers\u0026gt; 对jenv进行检查\njenv doctor 显示所有可行操作\njenv commands 如果使用过程中,发现JDK环境没有变(java -version),可以运行exec $SHELL -l尝试,然后看看JDK环境是否变化。\n","date":"2020-03-05T19:52:11+08:00","permalink":"https://luosuu.github.io/post/jenv-manage-jdk/","section":"post","tags":null,"title":"Jenv Manage JDK"},{"categories":null,"contents":"TUNA source\ntemporary using pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \u0026lt;example-package\u0026gt; default using pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple ","date":"2020-03-05T19:49:11+08:00","permalink":"https://luosuu.github.io/post/pip-change-source/","section":"post","tags":null,"title":"pip change source"},{"categories":["diary"],"contents":"我能跑多快?\n焦虑没有任何产出 找到自己真正喜欢的事情去做,发自内心的想去了解的好奇心才是动力源泉,在发现问题和解决问题的过程中才会得到成长。\n一味的被焦虑驱赶着想要找个方向或者事情给自己做,以求得心安的做法,不能说毫无收获,只能说效率极低,这是我假期时得到的惨痛教训。\n当然世界上应该有很多能逼迫自己做好自己不喜欢做的事情的人,只是我正好做不来这样的。\n","date":"2020-03-05T19:27:28+08:00","permalink":"https://luosuu.github.io/post/diary-2019-11-3/","section":"post","tags":null,"title":"Diary 2019 11 3"},{"categories":["UI"],"contents":"记录一下上学期写的Qt功能,窗口跳转\n代码 #include \u0026#34;mainwindow.h\u0026#34;#include \u0026lt;QMainWindow\u0026gt;#include \u0026lt;QPushButton\u0026gt;#include \u0026lt;QPixmap\u0026gt;#include \u0026lt;QSize\u0026gt;#include \u0026lt;QMouseEvent\u0026gt;#include \u0026lt;QMessageBox\u0026gt; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMainWindow *new_window = new QMainWindow; //创建一个新的窗口,这是我们接下来要跳转的目标。 QPushButton *toNewWindow = new QPushButton;//这是在this窗口里的按钮,我们要通过触发这个按钮跳转到新窗口 QPushButton *ReturnthisWindow = new QPushButton; QPixmap *newButtonIcon = new QPixmap(\u0026#34;:/SchoolGirls.jpg\u0026#34;);//创建一个QPixmap类型的对象,用作button的图标,括号里的是资源文件 QPixmap *returnButtonIcon = new QPixmap(\u0026#34;:/LeiMuu\u0026#34;); QSize *newButtonIconsize = new QSize(200,500);//括号里是像素的大小 QSize *reButtonIconsize = new QSize(300,300); QMessageBox *nihao = new QMessageBox; nihao-\u0026gt;setText(\u0026#34;helloworld\u0026#34;); nihao-\u0026gt;setParent(this); nihao-\u0026gt;move(200,200); this-\u0026gt;setFixedSize(400,400); new_window-\u0026gt;setFixedSize(400,400); toNewWindow-\u0026gt;setParent(this);//把按钮设置在this窗口上 toNewWindow-\u0026gt;setIcon(*newButtonIcon);//把按钮的图标加上 toNewWindow-\u0026gt;setIconSize(*newButtonIconsize);//调整图标的大小 toNewWindow-\u0026gt;setFixedSize(300,100);//调整Button的大小 toNewWindow-\u0026gt;move(50,120); ReturnthisWindow-\u0026gt;setParent(new_window); ReturnthisWindow-\u0026gt;setIcon(*returnButtonIcon); ReturnthisWindow-\u0026gt;setIconSize(*reButtonIconsize); ReturnthisWindow-\u0026gt;setFixedSize(*reButtonIconsize); ReturnthisWindow-\u0026gt;move(50,50); connect(toNewWindow,\u0026amp;QPushButton::clicked,new_window,\u0026amp;QMainWindow::show); connect(toNewWindow,\u0026amp;QPushButton::clicked,this,\u0026amp;QMainWindow::hide); connect(ReturnthisWindow,\u0026amp;QPushButton::clicked,this,\u0026amp;QMainWindow::show); connect(ReturnthisWindow,\u0026amp;QPushButton::clicked,new_window,\u0026amp;QMainWindow::hide); } MainWindow::~MainWindow() { } ","date":"2020-03-05T19:26:15+08:00","permalink":"https://luosuu.github.io/post/qt-windows-navigation/","section":"post","tags":null,"title":"Qt Windows Navigation"},{"categories":["C++"],"contents":"C语言中的结构体指针,曾在第一学期坑过我\n代码 typedef struct student { int id; char name[50]; float chinese; float math; float english; float sum; }student; //就像一个普通的变量一样,直接传指针就可以进行相应的操作,指针存储的是结构体首地址 void swap(struct student*a, struct student*b) { struct student temp = *a; *a = *b; *b = temp; }; 结构体的操作一般都是以指针的方式进行,有的结构体会很大,直接进行拷贝操作代价太高,因此在函数的传参中,结构体一般也是通过指针的形式传经函数。\n","date":"2020-03-05T19:25:41+08:00","permalink":"https://luosuu.github.io/post/c-struct-pointer/","section":"post","tags":null,"title":"C Struct Pointer"},{"categories":["diary"],"contents":"这里记录一下我参加pycon2019成都站的笔记和体会。\n类型推断,静态类型,JIT 语法树到语法树的函数 我们称之为宏。\n类型大小本质为将类型看作一个集合,计算集合的大小(取值区间的大小)\n学习路线:\nPython的Virtual Machine\nStack Machine\nLLVM Based Machine\ndis模块\nokmij.org\n编译原理\nPython字节码\nWEB API Web Application是和用户直接交互的。\nWeb API返回纯数据格式的(如XML和JSON),与机器(如Web Application,iOS,Android等)进行交互。\nRESTful API指符合REST规范的Web API,虽然几乎没有Web API完全符合REST规范。所以大概符合REST风格的现在都叫RESTful API。REST只是一个架构风格,而非强制要求。\nFlask是一个开发Web API的工具,只提供最基本的功能,有良好的拓展性。选择Flask表示比起Djanro的方便你选择了灵活和更多的可控制性。因此比起Flask+大而全的拓展更推荐Flask+一组优秀的工具。\n推荐的学习路线 了解Web API设计原则 学习Flask原生实现 学习其他搭配工具 李辉的个人网站 greyli.com\n网站里有很多python web开发的教程和分享。\nNLP 任何时候都不要忘记“当初你想解决的问题” 把问题转化为具体统计问题或者能够使用机器学习解决的问题(不知道该怎么做时可以用EDA把握数据倾向) 根据你的时间和预算选择分析方法和合适的模型 Just Python 其他 AWS 12要素应用宣言:无需猜测容量,摆脱无差异化工作等\nAWS云基础设施,Infrastructure is Code,用面向对象的方式描述和构建基础设施。(上一代为Infrastructure as Code,用JSON等记录和描述基础设施)。\n","date":"2020-03-05T19:24:46+08:00","permalink":"https://luosuu.github.io/post/pycon2019-chengdu/","section":"post","tags":null,"title":"Pycon2019 Chengdu"},{"categories":["Software"],"contents":"用nvm管理你的node和npm\nawesome nvm 前端开发经常必然需要很好的管理自己的npm和node。奈何mac上的homebrew不给力,经常有很多问题。\n通过查询知道还有nvm这样一种方便的工具可以使用。便立即学习了一下。\n首先需要安装nvm。\ncurl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash 然后你可以直接运行\nnvm install node 来直接安装最新的node。\n也可以使用\nnvm ls-remote 看看所有可用的版本。\n如果你有多个node版本。可以仿照下面的代码交换使用。\nnvm use v12.7.0 如果使用\nnvm use node 就切换到最新版了。\n其他用法可以看官方文档。\n","date":"2020-03-05T19:23:34+08:00","permalink":"https://luosuu.github.io/post/nvm-manage-node/","section":"post","tags":null,"title":"Nvm Manage Node"},{"categories":["Software"],"contents":"用ssh密钥文件登陆服务器\n用腾讯云自己生成的密钥文件 如果你购买了一个服务器,那么你肯定是需要远程登陆它的。\nssh密钥登陆就是受推崇的一种方式。它在安全性和便捷性间作出了非常好的折中。\n以腾讯云为例。你在购买腾讯云的服务器后,如果你想登陆服务器,那么就需要开放ssh端口。\n你可以通过它自带的方式生成一个密钥文件。腾讯云会为你保存名称和公钥,私钥文件需要自己下载保存。\n你下载下来的密钥文件的文件名应该是和你所起的名称是一致的。\n你可以直接使用这个密钥文件。\n使用之前你可能需要先更改这个文件的权限\nchmod 400 \u0026lt;文件路径\u0026gt; 修改以后你就可以直接使用以下命令来登陆服务器了。\nssh -i \u0026lt;文件路径\u0026gt; \u0026lt;服务器用户名\u0026gt;@\u0026lt;公网ip\u0026gt; 注意,如果你使用以上方法,那么你的文件名不能改,改了就不行了。\n更通常的做法 然而这个方式不优雅,也不是我们推崇的。\n一般操作系统都会自带~/.ssh文件夹,如果没有,你可以自己创建一个。\n进去后应该会有两个文件,一个是id_rsa,另外一个是id_rsa.pub。\n这是我们电脑默认的ssh加密文件。如果你曾经使用过git,那么不应该对他们很陌生。\n这两个文件各有用处,id_rsa负责储存私钥,id_rsa.pub负责储存公钥。\n如果你想使用腾讯云给你生成的密钥文件的内容。那么你可以将你之前下载的密钥文件重命名为id_rsa然后覆盖掉默认的。\n然后去腾讯云将公钥复制下来,创建一个id_rsa.pub的文件,将公钥内容复制进去。然后用你创建的id_rsa.pub文件覆盖掉默认的。\n然后你可能需要更改文件权限\nchmod 400 ~/.ssh/id_rsa 这样你就可以使用以下命令登陆服务器了\nssh \u0026lt;服务器用户名\u0026gt;@\u0026lt;公网ip\u0026gt; 如果你不想用腾讯云给你的密钥文件内容。我假设你之前没有密钥文件(因为有密钥文件的操作是包含在没有密钥文件的操作之中的)。\n在shell中输入以下命令\n# 这是在生成密钥对 ssh-keygen 然后会出现以下提示\nGenerating public/private rsa key pair. Enter file in which to save the key ~/.ssh/id_rsa): 这是让你在选择ssh密钥内容的保存位置。而这个文件位置一般就是~/.ssh/id_rsa,也就是我们期望的默认位置。直接回车。\n然后会出现以下提示\nEnter passphrase (empty for no passphrase): Enter same passphrase again: 然后会让你输入两次一个叫做passphrase的东西,你可以理解是对密钥文件的加密,也就是密钥文件的密码。一般来说直接回车两次就行了,这代表不设置passphrase。\n然后登陆服务器。进入服务器的~/.ssh目录,使用ls命令查看其中的文件。里面应该有一个叫做authorized_keys的文件。这个文件里面存有所有得到登陆授权的公钥。储存格式是每行一个公钥。\n我们可以编辑authorized_keys,然后将自己生成的公钥内容复制进去(记得保存)。\n然后我们就可以通过本地的ssh密钥对登陆了。\n从这里我们可以看出ssh密钥对的优势和好处。我们可以在服务器的authorized_keys储存多台电脑的ssh文件的公钥,就可以实现服务器的安全共享。\nssh文件的使用 为了方便,我们每个计算机都只保存一个ssh文件密钥对,也就是id_rsa与id_rsa.pub。然后任何需要使用ssh文件的地方都用这个密钥对。这样我们就免去了命令上的麻烦。\nssh命令中的-i实际上就是使用密钥文件的意思。以后我们登陆任何需要ssh文件的服务器,都直接使用\nssh \u0026lt;服务器用户名\u0026gt;@\u0026lt;公网ip\u0026gt; 就可以了。非常方便。\n","date":"2020-03-05T19:22:52+08:00","permalink":"https://luosuu.github.io/post/ssh-login-server/","section":"post","tags":null,"title":"Ssh Login Server"},{"categories":["eth"],"contents":"本文主要参考于Solidity develop文档。作为本人的学习笔记和再理解。\n对solidity的初步了解 Solidity是针对以太坊的编程语言,受到C++,Python,JavaScript等语言的影响。它的设计目的就是为了在以太坊上运行。\n它是一种静态语言。solidity支持一部分类的特性。solidity同样支持继承,和复杂的由用户自定义的特殊类型。因此我们可以说solidity是一种OOP(面对对象)的语言。我们在编写solidity代码时,应该以面对对象的编程方式定义变量(状态)和函数。并在solidity中,是大小写敏感的。\n我们知道以太坊上的每个节点实际上一般都是EVM,就算是矿工节点,一般也承担EVM的职责。以太坊区块链通过编写和执行智能合约来帮助拓展它的功能。EVM支持的语言很多,solidity是其中最流行也是最适合的。\nEVM和solidity EVM是最终执行智能合约代码的地方,但是它不能直接理解solidity里面的高级的结构。EVM能理解的是一种被称为字节码的一种低级指令。这种指令非常精简。深入了解EVM,你会发现EVM在实际运行代码时不能联网,权限也非常有限。包括使用精简的指令在内的这些特性,都是为了保证EVM的安全性。\n要把我们编写的solidity代码转换成字节码,需要编译器。solidity附带的编译器成为solidity编译器或者solc。\n那么这个工作流程就和普通的编译代码并运行它没有什么太大的区别了。\nsolidity代码 -\u0026gt; solc -\u0026gt; 字节码 -\u0026gt; 部署并在EVM上运行。\nsolidity文件 储存solidity代码的solidity文件的拓展名是.sol。solidity文件是人类可读的文件,可以在任何编辑器,甚至可以在记事本里打开。\nsolidity文件由以下四个高级结构组成\n 预编译指令 - pragma 注释 导入(import) 合约/库/接口 - contract/library/interface 其中solidity的注释是和C++是一样的,\\\\是单行注释,\\* *\\是多行注释。\n它们整体看起来像是这个样子的\npragma solidity 0.4.19; contract a{ //*** } library b{ //*** } interface c{ //*** } import语句 帮助我们导入其他solidity文件,使得当前的solidity文件可以访问其中的代码。这有助于我们编写模块化的代码。如:\nimport \u0026#39;commonLibrary.sol\u0026#39;; 预编译指令 通常指solidity文件的第一行代码,其形式一般为\npragma solidity \u0026lt;\u0026lt;version number\u0026gt;\u0026gt;; 注意是有分号作为结束的。\n在pragma指令的帮助下,你可以为你的代码选择合适的编译器。这是一种很好的习惯。\n其中版本号^0.4.0代表版本号为4的最新的版本。\nHello world pragma solidity ^0.4.18 contract Helloworld{ string private a = \u0026#34;Hello world\u0026#34;; function GetHelloWorld() public view returns (string){ return a; } } 这是用solidity输出\u0026quot;Hello world\u0026quot;的一个范例。我们可以从中简单的窥见solidity声明变量和函数的一些特点。\npragma关键字代表着编译器应该如何处理源代码,常见的就是声明使用的编译器版本。 我们可以窥见我们写的所谓合约contract其实在写一个很类似于C++类的东西,在其中声明了该合约的成员和成员函数,或公有供别人调用,或私有进行保护。\n我们写了这个合约,就可以进行发布,将它写在区块上,使其拥有一个特定的地址,这样别人就可以通过这个地址使用我们写的合约了。\n存储 pragma solidity ^0.4.0; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public view returns (uint) { return storedData; } } unit这个变量类型是最高256位的无符号整数,我们在上述代码里声明了一个unit类型的状态变量,叫做storedDate。\n后面我们声明了两个函数set与get,用于设定和返回合约SimpleStorage的成员storedDate。\n在solidity中,我们不需要this.来访问合约内部的变量。\n一个简单的货币实现 实际上,public关键字会让编译器自动生成函数,用于返回public变量或函数,理解这一点尤其重要。我们将分析下面这个最简单的加密货币:\npragma solidity ^0.4.21; contract Coin { // 关键字“public”让这些变量可以从外部读取 address public minter; mapping (address =\u0026gt; uint) public balances; // 轻客户端可以通过事件针对变化作出高效的反应 event Sent(address from, address to, uint amount); // 这是构造函数,只有当合约创建时运行 function Coin() public { minter = msg.sender; } function mint(address receiver, uint amount) public { if (msg.sender != minter) return; balances[receiver] += amount; } function send(address receiver, uint amount) public { if (balances[msg.sender] \u0026lt; amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); } } 我们在这里遇到了新的变量类型,address。 address类型是一个160位的值,如果你知道在以太坊中,用户之间是通过每个用户的公钥的前160位来区别,那么将很好理解。代码里我们声明了一个叫做minter的address的公有变量。 public关键字对于minter来讲,编译器自动生成的代码大致如下。\nfunction minter() returns (address) { return minter; } 编译器通过这种方式,使minter可以被其他合约访问。\n下一行\nmapping (address =\u0026gt; uint) public balances; 我们声明了一个叫做balances的公有变量,那么它的类型怎么理解呢?我们可以将它理解为一个转换器,也就是对于balances(address _account),它返回的是一个unit类型,并且每个_account都有互相独立的空间,你可以理解每个_account可以通过balances拥有一个自己成员/属性,就是自己的一个unit类型的值。通过balances我们实现了使每一个地址的用户都有储存自己余额的地方,我们也可以通过balances管理每个用户的余额从而实现货币的流通(实际上在以太坊里,balances就代表余额的意思)。我们一般可以称类似于balances这种变量为状态变量。 public关键字对balances生成的代码大致如下:\nfunction balances(address _account) public view returns (uint) { return balances[_account]; } 我们可以看到通过balances轻松的查询到每一位用户的余额。\nevent Sent(address from, address to, uint amount); event变量,即“事件”。这种变量类型是用来被传输信息的,也就是说可以被传送出去,并且携带一些我们希望它携带的信息。而用来监听这个事件并且获得信息的代码示例如下:\nCoin.Sent().watch({}, \u0026#39;\u0026#39;, function(error, result) { if (!error) { console.log(\u0026#34;Coin transfer: \u0026#34; + result.args.amount + \u0026#34; coins were sent from \u0026#34; + result.args.from + \u0026#34; to \u0026#34; + result.args.to + \u0026#34;.\u0026#34;); console.log(\u0026#34;Balances now:\\n\u0026#34; + \u0026#34;Sender: \u0026#34; + Coin.balances.call(result.args.from) + \u0026#34;Receiver: \u0026#34; + Coin.balances.call(result.args.to)); } }) 用户可以通过在自己的应用程序或者服务器上添加上面这个代码来获取事件的信息。这是event类型数据所允许的一种方式。\n请一定要注意balances函数是如何在用户界面调用的。不再是通过balances(_address)这种形式,而是通过balances.call(_address)这种形式调用。\n然后我们看到了构造函数:\nfunction Coin() public { minter = msg.sender; } 构造函数Coin()只会在合约创建的时候被调用,存入合约创建者的地址。msg是一个全局变量,其中msg.sender始终是当前函数调用的来源地址。这样就可以理解函数的内容了。\n函数mint和send是完成合约功能的两个函数。\n函数mint会先检验调用者是不是合约创建者,如果不是,那么就什么都不会发生,直接返回。而如果调用者就是合约创建者,就会执行内容,也就是给指定的接受地址的用户增加余额。\n函数send允许任何人调用,用于将自己的货币的余额的一部分转移到指定接受账户的余额里。并且送出事件Sent用于告知所有用户。后面就是用户更新自己账本了。具体流程可以看我的其他文档。\n","date":"2020-03-05T19:21:47+08:00","permalink":"https://luosuu.github.io/post/smart-contrast-dev/","section":"post","tags":null,"title":"Smart Contrast Dev"},{"categories":["eth"],"contents":"一些以太坊基础知识\n区块是怎么连接的 在区块链和以太坊中,每个区块都连接着另外一个区块,区块依次相连,形成一条长链。其中第一个区块成为创世区块。创世区块通过genesis.json文件产生。\n区块链中,两个相邻的区块之间是父子的关系,并且是一对一的关系(每个子都只有一个父)。那么如何确认这种关系并且将他们连接在一起呢?\n每个区块都由两个部分组成,区块头和区块体。其中区块头存储着当前区块的特征值,它包含了很多属性,如生成该区块的时间,本区块的区块体的散列,上一个区块的散列…\n通过上一个区块的散列这一属性,我们就将区块连接在一起了,并且可以互相认证。\n由于散列的特殊性,如果区块体的内容改变,那么她的散列一定会改变,那么就会连锁性质的导致它的子块,和子块下面的所有块都要改变。\n而快速改变多个区块是几乎不可能的,这要求它占据全网51%的算力。这样的方式保证了区块链的不可篡改性质。\n区块体的散列值的产生-Merkle根数 区块头的哈希值是怎么产生的?答案是Merkle根树。\nMerkle根叔,又称哈希二叉树(Merkle tree)。\n每个被储存在区块里的交易都会产生一个散列值,每个交易都有自己的时间戳,在区块里他们会按时间顺序排序,然后挖矿程序会按照顺序将它们两个一组两个一组的分组。\n如果恰巧交易ID的总共数量为奇数个呢?那么排在最后的这个交易ID就copy自己一份,凑成偶数。\n每个组的两个成员的哈希值相连接成为一个长字符串,然后在对其产生哈希,然后不断重复分组-相连-产生哈希的过程,最终生成最后的一个哈希值,这就是Merkle根哈希值(Merkle root)。\nMerkle tree大部分都是二叉的,但是也有别的形式的,三叉及以上也是有可能的。\nMerkle tree有什么用 在说这个之前,我们要提一句另外一种产生一系列内容的哈希值的方式,Hash List。\nHash List非常简单,就是对每一项内容都产生一个哈希,把这些哈希放进一个列表里,也就是Hash List,然后把这些哈希全都连接在一起,在对其产生一个哈希,用来检验Hash List。\n通过Merkle tree这种方式产生哈希,在P2P网络下载整个网络之前,我们可以先从可信源获得Merkle root,然后从其他不可信源下载Merkle tree,对比二者的Merkle root,由于哈希值的唯一性,我们可以认为如果Merkle root一致,那么整个Merkle tree都是正确的。在获得整棵树后,我们就可以单独对树上的某只分支进行验证了。\n从网络上下载,需要先进行验证保证内容的正确可信,这也是Merkle tree和Hash List的意义之一。验证通过后才能进行下载。\nMerkle tree和Hash List的主要区别在于,如果一部分内容损坏,Merkle tree的方式允许我们只下载这一部分数据所在的分支,然后验证这一个分支,验证通过后我们就可以开始下载内容了。Hash List则要求我们下载完整的Hash List才能验证。\n什么是gas gas,译为“燃料”。以太坊作为平台,对用户的每一项操作都要收取手续费,而衡量应该收取手续费的多少的计量单位就是gas。\n但是我们知道区块链技术是去中心的,这个手续费交给的不是平台,当然是为你做出计算劳动的矿工(尽管你支付给的对象的确是网络,但是网络会直接按照劳动量分配给矿工)。而平台只是表明多少计算量需要多少的gas。需要越多计算资源的操作自然需要的gas越多。\n但是gas是没有任何实际的标记(token)的,也就是说你不能拥有1000个gas之类的,gas只存在与以太坊虚拟机的内部,计算你所需的操作消耗的gas数量。以太坊会直接计算你的操作需要多少计算资源,然后将他们换算成gas。在你支付的时候,它们在换算成ether(以太坊内置机制中矿工生成区块记录内容的奖励)。\n为什么需要gas 以太坊直接有ether作为货币,为什么不直接以ether交易呢?这是由于以太坊在交易所进行公开买卖,它的价格会飘忽不定,这样你在以太坊内的操作的价格就会可能剧烈波动,在以太币的价格较低时如果人们交易量很大,那么可能就会形成“峰谷效应”,也就是执行量过大,造成平台超负荷运行。而gas可以缓解这一过程。等量计算资源消耗的操作所需要的gas数量是不变的,是事先确定的。\n如何支付gas 你最终的成本 = gas数量*gas单价 我每进行一个操作,都需要提前标注好自己的gas单价,然后附加上实际的以太币。你的gas单价会决定你在队列中的优先度,大家当然愿意先服务单价高的客户。接下来的情况就和你附加的以太币的数量有关了。\n矿工们每付出一些计算资源他们就会得到奖励,他们不会预先知道你附加的以太币是否足够支付整个操作,所以你的以太币是一点点被消耗的。矿工们的付出和获得是需要持久的,当停止支付时他们就会停止工作。所以如果你进行的操作需要的gas数量*你标记的gas单价 \u0026gt; 你附加的以太币,当你的以太币消耗完了之后,他们就会停止工作。然后他们会还原之前的处理,但是仍然会把这项交易失败的记录写入区块里,作为收取你费用的记录。而你会被提示\n您的交易中出现的gas与您的交易之间存在差异,没有足够高的费用来支持交易(out of gas) 你可能会觉得这个设计很坑,操作失败了竟然不给我退款,但是这是为了整个系统的稳定,矿工们付出了劳动,理应得到奖励。这要求每一个请求操作的人都谨慎的处理自己的代码,并且保证了系统的安全性,对整个系统来说是有益的。\n而如果你支付的以太币足够多,当请求的操作结束之后,会退还给你附加的多余的以太币。\ngas的限制 我们知道交易储存在区块中。在以太坊里,每个区块都有gas上限。待执行的交易要消耗的gas不能超过这个上限,这样就避免了所有区块都储存在最后一个区块里,达到gas上限后,其他交易就不能写入这个区块了,就会逼迫矿工挖矿,挖出下一个节点。这样可以保证整个系统的区块不断延长,保证整个系统的安全性。\n各种系统安装Geth的办法 Ubuntu sudo apt-get install software-properties-common sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update sudo apt-get install ethereum 禁用了PPA源的Linux发行版 可以考虑编译安装。\ngit clone https://github.com/ethereum/go-ethereum 安装Go\nsudo apt install golang 编译安装\nsudo apt-get install -y build-essential cd go-ethereum make geth 然后在最后的运行结果里你就可以知道你启动geth的路径,你可以把它加在你的环境变量里方便你使用。\n如何方便地启动geth 在你安装完geth后,会告诉你geth的安装路径,在shell中直接输入该路径,geth就启动了。\n但是我们想在shell中输入geth就能直接启动,而不是每次都要输入长长的路径。\n这里介绍一种办法。这个办法就是在用户目录下创建一个叫做bin文件夹,然后将其中储存一个软链接,链接到geth的路径。然后在.zshrc中添加环境变量,将咱们刚刚创建的bin文件夹添加进去。\n# 进入用户家目录,也就是~ cd # 创建文件夹 mkdir bin # 创建软链接 ln -s \u0026lt;geth路径\u0026gt; ~/bin/geth 至此我们成功地将软链接添加好了。\n然后我们添加环境变量。我们应该编辑.zshrc文件。在最后添加如下命令:\nexport PATH = $PATH:~/bin export是添加环境变量的语句,并且是一次性的。由于我们将它写入的.zshrc中,也就是zsh的配置文件,每次我们启动shell的时候都会随zsh的启动而实施。\n以上的方法是受推崇的,这样的做法十分安全,避免了sudo。并且保证了每个用户的独立性,也就是每个用户自己软件的不可见性。\n如果是个人用户,可以不这么麻烦。可以直接放在/usr/local/bin\nsudo ln -s \u0026lt;geth路径\u0026gt; /usr/local/bin/geth 这样需要sudo,并且如果是在服务器端,那么所有服务器用户都可以使用。\nGeth搭建私链 创建目录 首先我们需要创建一个我们用于储存私链数据的文件夹,geth客户端工作的时候导入数据就要从其中导入。\nmkdir private-geth cd private-geth touch gensis.json 创世区块 我们新建的gensis.json文件是创世区块的配置文件。\n这个文件会保证没有其他节点和你的节点的区块链版本一致,除非他们的创世区块的配置文件和你一模一样。\n每条链都应该有创世区块,也自然应该有自己的gensis.json\n以下是一个例子,你需要在了解其中的各项参数的意义后自己更改一下。\n{ \u0026#34;config\u0026#34;:{ \u0026#34;chainId\u0026#34;:39, \u0026#34;homesteadBlock\u0026#34;:0, \u0026#34;eip155Block\u0026#34;:0, \u0026#34;eip158Block\u0026#34;:0 }, \u0026#34;alloc\u0026#34; :{ \u0026#34;0xeb680f30715f347d4eb5cd03ac5eced297ac5046\u0026#34;:{\u0026#34;balance\u0026#34;:\u0026#34;10000000000000000\u0026#34;}}, \u0026#34;coinbase\u0026#34; : \u0026#34;0x0000000000000000000000000000000000000000\u0026#34;, \u0026#34;difficulty\u0026#34; : \u0026#34;0x20000\u0026#34;, \u0026#34;extraData\u0026#34; : \u0026#34;\u0026#34;, \u0026#34;gasLimit\u0026#34; : \u0026#34;0xffffffff\u0026#34;, \u0026#34;nonce\u0026#34; : \u0026#34;0x0000000000000039\u0026#34;, \u0026#34;mixhash\u0026#34; : \u0026#34;0x0000000000000000000000000000000000000000000000000000000000000000\u0026#34;, \u0026#34;parentHash\u0026#34; : \u0026#34;0x0000000000000000000000000000000000000000000000000000000000000000\u0026#34;, \u0026#34;timestamp\u0026#34; : \u0026#34;0x00\u0026#34; } 其中alloc代表初始账号,并且分配给他一定的余额。\n建议这里设置一个初始账号,方便我们以后的操作。账号可以自己随便写,只要格式正确,长度正确就可以,因为我们不会实际使用这个账号。\n初始化 然后我们需要使用创世区块的配置文件初始化我们的私链。首先我们需要一个储存链数据的位置。\n我们推荐在我们刚才创建的文件夹里在创建一个文件夹。\n# 名字不重要 mkdir db 然后我们需要执行初始化命令,进入我们最开始创建的文件夹里。\ngeth --datadir \u0026#34;./db\u0026#34; init gensis.json --datadir \u0026quot;./db\u0026quot;代表指定存储位置,后面的代表将gensis.json作为初始化配置文件。\n然后你可以进去使用ls命令看看里面都有些什么。\n启动节点 进入我们最开始创建的文件夹,使用以下命令启动节点。\ngeth --datadir \u0026#34;./db\u0026#34; --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain \u0026#34;*\u0026#34; --rpcapi \u0026#34;eth,net,web3,personal,admin,shh,txpool,debug,miner\u0026#34; --nodiscover --maxpeers 30 --networkid 3909 --port 30303 --mine --minerthreads 1 --etherbase \u0026#34;0xeb680f30715f347d4eb5cd03ac5eced297ac5046\u0026#34; --allow-insecure-unlock console 其中--allow-insecure-unlock我推荐加上去,否则会在后面的解锁账户时遇到麻烦,现在不允许以默认的方式解锁带http接口的账户了。\n-rpc就是开启了HTTP-RPC服务。\n启动节点后他就会开始挖矿。挖矿账户就是我们在gensis.json里设置的账户。\n最后我们如果想进一步操作,需要进入Geth的JavaScript控制台。\n我们需要通过attach命令,连接一个已经启动的节点,这里推荐新开一个终端窗口。\ngeth --datadir \u0026#39;./db\u0026#39; attach ipc:./db/geth.ipc 以太坊JavaScript控制台命令 以太坊JavaScript控制台中内置了一些对象,方便我们和以太坊交互,其中有eth, net, admin, miner, personal, txpool, web3。\n新建账号 personal.newAccount(\u0026#34;123456\u0026#34;) 括号里的字符串是你新建账号的密码。显示出的结果就是账号的公钥。\n生成的账户会保存在keystore文件夹。\n你可以新建两个账号,用于接下来我们尝试进行交易。\n新建完账号后,可以使用如下命令来查看当前链的账户。\neth.accounts 输出结果就是当前链的所有账户了。他们以数组的形式储存,所以可以用诸如eth.accounts[0]的形式调用它们。\n然后我们可以看看他们的余额。\nbalance = web3.fromWei(eth.getBalance(eth.accounts[0]),\u0026#34;ether\u0026#34;) eth.getBlance返回的是以wei为单位的余额,上面的命令,将wei单位转化为了ether单位。\n新建的两个账户的余额自然是0,想要实现交易至少得先有以太币,所以我们需要用一个账户挖矿,获得奖励。\n挖矿 首先设立本机挖矿奖励地址。\nminer.setEtherbase(eth.accounts[0]) 然后检查一下是否设置成功\neth.coinbase 上面这条命令就会返回挖矿的奖励地址。\n然后启动挖矿。\nminer.start(1) 括号里的数字代表线程数,代表开启几个线程进行挖矿。\n你可能遇到返回是null的情况,你可以检查下区块高度\neth.blockNumber 会返回一个数字,代表着现在的区块高度,你隔段时间检查一下,如果区块高度增高了,说明它已经开始挖矿了,没有问题。\n据我粗略观察,应该是咱们开了一个新的窗口,挖矿的具体信息都在原先的窗口里,如果你担心区块高度的增加是因为原先的挖矿没有停止,你可以先用miner.stop(),再用miner.start(1),然后检查区块高度是否增加\n交易 进行一段时间的挖矿后,你说设置的奖励账户里的余额应该增加了。\n然后就可以进行交易的准备。\n首先我们需要解锁账户,才能实施交易。之前在启动geth时添加的参数中,--allow-insecure-unlock就是为了方便这一步的。\n解锁命令为:\nweb3.personal.unlockAccount(web3.personal.listAccounts[0],\u0026#34;\u0026lt;password\u0026gt;\u0026#34;, 15000) 最后的数字代表解锁的时间,单位为秒。``代表你要解锁的账户的密码。\n虽然有另外一种解锁的方式,但是我没有成功。\npersonal.unlockAccount(eth.accounts[0],\u0026#34;\u0026lt;password\u0026gt;\u0026#34;,15000) 然后就可以交易啦。\neth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value:web3.toWei(1,\u0026#34;ether\u0026#34;)}) ","date":"2020-03-05T19:19:47+08:00","permalink":"https://luosuu.github.io/post/basic-eth/","section":"post","tags":null,"title":"Basic Eth"},{"categories":["C++"],"contents":"记录一下第一学期假期时跟着Github@guyaqi学长写的控制台小玩意\n代码 #include \u0026lt;stdio.h\u0026gt;#include \u0026lt;windows.h\u0026gt;#include \u0026lt;string.h\u0026gt;void putFrame(WORD wAttributes,char *a); void changeFrame(int a, WORD wAttributes); int main() { HANDLE handle; handle = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO cursor = { 100,FALSE };//隐藏光标 \tSetConsoleCursorInfo(handle, \u0026amp;cursor); int position = 1; int state = 0; char a[][128] = { \u0026#34;1. White \u0026amp; Green\u0026#34;, \u0026#34;2. Red \u0026amp; Grey\u0026#34;, \u0026#34;3. White \u0026amp; Black\u0026#34;, \u0026#34;4. White \u0026amp; Blue\u0026#34; }; printf(\u0026#34;----------------------------------\\n\\n\\n\u0026#34;); printf(\u0026#34; Colors\\n\\n\u0026#34;); putFrame(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY, *a); putFrame(FOREGROUND_INTENSITY | FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_RED,*(a+1)); putFrame(FOREGROUND_INTENSITY| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,*(a+2)); putFrame(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_BLUE,*(a+3)); SetConsoleTextAttribute(handle, 0); printf(\u0026#34;\\n\\n\u0026#34;); printf(\u0026#34; \u0026#34;); SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY); printf(\u0026#34;This is a test text.\u0026#34;); //交互 \twhile (true) { if (::GetAsyncKeyState(VK_UP) \u0026amp; 0x8000 \u0026amp;\u0026amp; position \u0026gt; 1 \u0026amp;\u0026amp; state == 0) { position--; state = 1; } if (::GetAsyncKeyState(VK_DOWN) \u0026amp; 0x8000 \u0026amp;\u0026amp; position \u0026lt; 4 \u0026amp;\u0026amp; state == 0) { position++; state = 1; } if (!(::GetAsyncKeyState(VK_UP) \u0026amp; 0x8000 \u0026amp;\u0026amp; position) \u0026amp;\u0026amp; !(::GetAsyncKeyState(VK_DOWN) \u0026amp; 0x8000)) { state = 0; } if (position == 1 \u0026amp;\u0026amp; state == 0) changeFrame(5,FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY); else if (position == 2 \u0026amp;\u0026amp; state == 0) changeFrame(6, FOREGROUND_INTENSITY | FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_RED); else if (position == 3 \u0026amp;\u0026amp; state == 0) changeFrame(7, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); else if (position == 4 \u0026amp;\u0026amp; state == 0)changeFrame(8, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_BLUE); } system(\u0026#34;pause\u0026#34;); } void putFrame(WORD wAttributes, char a[]) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0); printf(\u0026#34; \u0026#34;); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wAttributes); printf(\u0026#34;%s\\n\u0026#34;,a); } void changeFrame(int a, WORD wAttributes) { COORD coord; coord.X = 6; coord.Y = 4; for (int i = 0; i \u0026lt; 4; i++) { coord.Y += 1; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0); printf(\u0026#34; \u0026#34;); } coord.X = 6; coord.Y = a; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); printf(\u0026#34;-\u0026gt;\u0026#34;); coord.X = 7; coord.Y = 11; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wAttributes); printf(\u0026#34;This is a test text.\u0026#34;); } ","date":"2020-03-05T19:18:53+08:00","permalink":"https://luosuu.github.io/post/console-game/","section":"post","tags":null,"title":"Console Game"},{"categories":["UI"],"contents":"第二学期假期时去MSRA时速成了一下UWP\nUWP速成 夏令营期间速成了一下微软家的前端工具UWP。\n推荐环境:Blend for Visual Studio 2019 / Visual Studio 2019\n需要安装Visual Studio的UWP开发组件。在tools and extensions里面安装。\n如果你使用的是Visual Studio 2017,可能会出现无法使用实时preview功能,建议升级为2019版本。\nQuick Start 首先新建UWP项目。\n然后你会看到App.xaml和MainPage.xaml,前面的不用管。后面的就是我们的主页面。\nxaml文件类似于HTML文件,熟悉HTML的同学很快就能上手。\n关于常用的组件,可以去Windows store里面下载xaml Controls Gallery。里面有几乎所有常用的组件及其基本代码,更重要的是它本身就是用UWP写的,所以里面的组件都有展示效果,很方便很强大,缺点就是不够详细。\n比较详细的可以查阅文档,微软的UWP文档写的相当好。\nUWP doucumentation\n现在你可以看到MainPage.xaml的内容了。\n\u0026lt;Page x:Class=\u0026quot;Github_example.MainPage\u0026quot; xmlns=\u0026quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0026quot; xmlns:x=\u0026quot;http://schemas.microsoft.com/winfx/2006/xaml\u0026quot; xmlns:local=\u0026quot;using:Github_example\u0026quot; xmlns:d=\u0026quot;http://schemas.microsoft.com/expression/blend/2008\u0026quot; xmlns:mc=\u0026quot;http://schemas.openxmlformats.org/markup-compatibility/2006\u0026quot; mc:Ignorable=\u0026quot;d\u0026quot; Background=\u0026quot;{ThemeResource ApplicationPageBackgroundThemeBrush}\u0026quot;\u0026gt; \u0026lt;Grid\u0026gt; \u0026lt;/Grid\u0026gt; \u0026lt;/Page\u0026gt; ``中是页面的内容。\n``是一个组件,能按照几行几列分割页面。其基本的使用是:\n\u0026lt;Grid\u0026gt; \u0026lt;Grid.RowDefinitions\u0026gt; \u0026lt;RowDefinition Height = \u0026quot;50\u0026quot; /\u0026gt; \u0026lt;RowDefinition Height = \u0026quot;*\u0026quot;/\u0026gt; \u0026lt;RowDefinition Height = \u0026quot;2*\u0026quot;/\u0026gt; \u0026lt;/Grid.RowDefinitions\u0026gt; \u0026lt;Grid.ColumnDefinitions\u0026gt; \u0026lt;ColumnDefinition Width=\u0026quot;50\u0026quot; /\u0026gt; \u0026lt;ColumnDefinition Width=\u0026quot;Auto\u0026quot; /\u0026gt; \u0026lt;ColumnDefinition /\u0026gt; \u0026lt;/Grid.ColumnDefinitions\u0026gt; \u0026lt;StackPanel Orientation=\u0026quot;Vertical\u0026quot; Grid.Row=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;TextBlock Text=\u0026quot;Hello\u0026quot;/\u0026gt; \u0026lt;TextBlock Text=\u0026quot;world\u0026quot;/\u0026gt; \u0026lt;/StackPanel\u0026gt; \u0026lt;/Grid\u0026gt; *表示按比例分割区域,上面的代码就代表着第二行和第三行的比例是1:2\n想要在Grid中布置组件,只需要在``中声明组件,然后在组件的属性中加入如Grid.Row = \u0026quot;1\u0026quot;表示组件在Grid中的位置。上面的代码就在第一行的位置上布置了一个组件StackPanel。\nStackPanel能按照一定的方向排列组件。排列的方向由属性\u0026quot;Orientation\u0026quot;决定。\n常用的结构 UWP非常具有独特风格的NavigationView框架 \u0026lt;Page x:Class=\u0026quot;Github_example.MainPage\u0026quot; xmlns=\u0026quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0026quot; xmlns:x=\u0026quot;http://schemas.microsoft.com/winfx/2006/xaml\u0026quot; xmlns:local=\u0026quot;using:Github_example\u0026quot; xmlns:d=\u0026quot;http://schemas.microsoft.com/expression/blend/2008\u0026quot; xmlns:mc=\u0026quot;http://schemas.openxmlformats.org/markup-compatibility/2006\u0026quot; mc:Ignorable=\u0026quot;d\u0026quot; Background=\u0026quot;{ThemeResource ApplicationPageBackgroundThemeBrush}\u0026quot;\u0026gt; \u0026lt;NavigationView x:Name=\u0026quot;nvSample\u0026quot;\u0026gt; \u0026lt;NavigationView.MenuItems\u0026gt; \u0026lt;NavigationViewItem Icon=\u0026quot;Play\u0026quot; Content=\u0026quot;Menu Item1\u0026quot; Tag=\u0026quot;SamplePage1\u0026quot; /\u0026gt; \u0026lt;NavigationViewItem Icon=\u0026quot;Save\u0026quot; Content=\u0026quot;Menu Item2\u0026quot; Tag=\u0026quot;SamplePage2\u0026quot; /\u0026gt; \u0026lt;NavigationViewItem Icon=\u0026quot;Refresh\u0026quot; Content=\u0026quot;Menu Item3\u0026quot; Tag=\u0026quot;SamplePage3\u0026quot; /\u0026gt; \u0026lt;NavigationViewItem Icon=\u0026quot;Download\u0026quot; Content=\u0026quot;Menu Item4\u0026quot; Tag=\u0026quot;SamplePage4\u0026quot; /\u0026gt; \u0026lt;/NavigationView.MenuItems\u0026gt; \u0026lt;Frame x:Name=\u0026quot;contentFrame\u0026quot;\u0026gt; \u0026lt;Grid\u0026gt; \u0026lt;/Grid\u0026gt; \u0026lt;/Frame\u0026gt; \u0026lt;/NavigationView\u0026gt; \u0026lt;/Page\u0026gt; ``中就是除了框架的内容页面。\n使用了NavigationView自然要进行页面跳转。页面跳转的实现部分要放在MianPage.xaml.cs中实现。\n页面跳转有两种方法,一个是ItemInvoked,另外一个是SelectionChanged。前者只要发生NavigationView的item点击事件就会被检测到,后者只有当选择的item发生变化时才会发生。下面展示一个使用ItemInvoked的页面跳转的实现。所以你需要新建Blank page项目,修改.xaml.cs中的类的名称。\nprivate void NvSample_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { if (args.IsSettingsInvoked == true) { contentFrame.Navigate(typeof(SettingsPage), args.RecommendedNavigationTransitionInfo); } else { TextBlock ItemContent = args.InvokedItem as TextBlock; switch (ItemContent.Tag) { case \u0026#34;Recog_page\u0026#34;: { contentFrame.Navigate(typeof(Recog_page)); } break; case \u0026#34;SP2\u0026#34;: { contentFrame.Navigate(typeof(SamplePage2)); } break; case \u0026#34;SP3\u0026#34;: { contentFrame.Navigate(typeof(SamplePage3)); } break; case \u0026#34;SP4\u0026#34;: { contentFrame.Navigate(typeof(SamplePage4)); } break; default: { contentFrame.Navigate(typeof(MainPage)); } break; } } } 上述的实现通过识别item的不同tag属性来进行跳转。由于NavigationView自带的Setting不具备tag属性,所以就先只好判断IsSettingInvoked。\n使用contentFrame.Navigate(typeof())进行页面跳转,识别的是.xaml.cs文件中的类的名称,而不是xaml文件里的name。\nxaml文件的地位并不高,只是方便我们搭建框架而已,实际上xaml文件完全可以不写,完全使用C#搭建框架,只是这样没有编辑xaml直观方便。\n在UWP中使用图片 你可能需要使用到BitmapImage类,但是BitmapImage类默认不在UWP项目的引用列表里,所以需要手动添加\nusing windows.UI.Xaml.Media.Imaging; using \u0026lt;MianPage的命名空间,一般是项目名\u0026gt;.Views;//有的时候不必要添加 BitmapImage类使用Uri进行加载资源文件,UWP的资源文件默认都放在项目里的Assets文件夹里。\nBitmapImage picture = new BitmapImage(); picture.UriSource = new Uri(\u0026#34;ms-appx:Assets/dog.jpg\u0026#34;); 然后就可以把这个属性赋给一些图片,让他们重新加载资源图片。如果xaml文件里有一个Image组件,属性有x:name = Sample,那么就可以在.xaml.cs文件里,使用Sample.Source=picture来重新加载图片。\n","date":"2020-03-05T18:55:54+08:00","permalink":"https://luosuu.github.io/post/uwp-quickstart/","section":"post","tags":null,"title":"UWP Quickstart"},{"categories":["diary"],"contents":"微软学生夏令营记录\n微软文化改革 微软员工要从“无所不知”到“无所不学” 工程师文化不应该是高冷的,不应该是一种自负的,而应该时刻保持谦虚,坦诚地给出自己的意见和看法,不断发现和学习别人的长处。我知道这和所谓的“极客精神”有所出入,但是我认为这是一种更好,更融洽的相处方式。\n微软曾经公司文化崇尚竞争,各部门之间互相竞争,甚至同一个部门的各个团队都要互相竞争,他们有严格的排名制度,并且根据这个排名分配奖金,甚至还有罚金。此时的微软,市值已经蒸发到了顶峰时期的一半,改革势在必行。\n纳德拉上任后推崇合作,对员工的评判变成了“自己的成就”,“帮助别人完成的成就”,“在别人帮助下完成的成就”。\n帮助别人,保持一种好奇心,不断虚心的学习和为他们提供帮助,就是每个人的最好的相处方式,这样才能成就更多。\n有一句名言是“文化能把战略当早餐吃”。纳德拉能够带领微软改革成功,曾坦言“文化改革是整个公司改革的大半”。\n顺便说一句纳德拉受采访时回答的问题,深得我心。\n组织领导要:Listen more, talk less, but be decisive when time comes.\n看重员工:Do they create clarity, do they create energy.\n领导少说多听具有决断力,员工要“清晰而富有能量”。\n予力全球,成就不凡 empower every person and every organization on the planet to achieve more.\n这包含了微软的人文关怀精神。\n微软已经不是一家“软件公司”,而是一家“生产力平台公司”。这意味着微软的使命已经发生变化,让人们使用微软的技术去成就不凡已经是微软的目标。\n我们可以看到盲人也可以在微软成为工程师,达到令人尊敬的成就,并且仍在致力于用AI帮助盲人。\n微软提供了完整的学习资源平台和方便的工具,每一位开发者都可以构建属于他们的应用,使用AI和云服务去成就更多,实现更多,完成他们的创意和梦想。\n开源和“Geek精神” 不要尝试去理解整个大的开源项目是如何运行起来的,即使是资深的软件工程师都很难短时间内搞清楚,做这样的尝试只会令你有挫败感。\n当我们谈到开源,总会有人去聊一些“极客精神”和一些传奇的故事。然而现在的开源已经变成一项工作,是每个顶级公司必须要做的事情。这意味着开源已经变得工业化,也就会变得有规范。\n另外,参与开源项目对个人的提升是巨大的,因为参与开源项目本身要求的素质就有很多,代码能力是肯定的,但还包含与别人交流的能力,迅速融入一个社区的能力,以及一定的创造意识和共享精神。\n开源是趋势,是发展方向,未来开源的市场会越来越大,机会也会越来越多。\n可以从一些简单的小bug入手,参与开源项目,很多小bug都是故意留下来希望能够吸引更多人能够参与的。\n创新的勇气和时机 有勇气创新的人不缺乏创造力,抓住时机创新的人成就不凡。\n我曾经考虑一个东西的时候总是会优先考虑这个事情的可行性,无论是讨论一个流程的策划,还是讨论一个项目的开发。\n然而在这次微软夏令营的Hackathon中我体会到了这样做只能驻足在平庸之流,仅仅去考虑最终完成度的高低是限制人创造力和生产力的。\n最开始的时候我们选择了我们比较轻车熟路的路线,并急于立刻进行开发,希望能够在有限的时间中完成一个质量更好的demo。但是在随后的深入讨论中我发现,这不是我想做的,我们可以尝试去做一个更有趣更有价值的方向和idea。\n幸运的是我的队友和我见解相同,并且她有一个很好的故事。于是我们调整方向,这让我们更加富有热情。\n令我意外的是,当我调整了方向之后,我的创造力和生产力大大提升,并迅速的完成了框架的开发,我的队友的工作也很快有了进展。虽然我们最后没能拿到“BEST PROJECT”的荣誉,但是这次的比赛经历已经让我收获颇多。\n","date":"2020-03-05T18:55:03+08:00","permalink":"https://luosuu.github.io/post/msra-summercamp/","section":"post","tags":null,"title":"MSRA Summercamp"},{"categories":["Software"],"contents":"通过ustc源安装homebrew\nRuby Scripts brew_install.rb\n#!/usr/bin/ruby # This script installs to /usr/local only. To install elsewhere (which is # unsupported) you can untar https://github.com/Homebrew/brew/tarball/master # anywhere you like. HOMEBREW_PREFIX = \u0026#34;/usr/local\u0026#34;.freeze HOMEBREW_REPOSITORY = \u0026#34;/usr/local/Homebrew\u0026#34;.freeze HOMEBREW_CACHE = \u0026#34;#{ENV[\u0026#34;HOME\u0026#34;]}/Library/Caches/Homebrew\u0026#34;.freeze BREW_REPO = \u0026#34;https://mirrors.ustc.edu.cn/brew.git\u0026#34;.freeze # TODO: bump version when new macOS is released MACOS_LATEST_SUPPORTED = \u0026#34;10.15\u0026#34;.freeze # TODO: bump version when new macOS is released MACOS_OLDEST_SUPPORTED = \u0026#34;10.13\u0026#34;.freeze # no analytics during installation ENV[\u0026#34;HOMEBREW_NO_ANALYTICS_THIS_RUN\u0026#34;] = \u0026#34;1\u0026#34; ENV[\u0026#34;HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT\u0026#34;] = \u0026#34;1\u0026#34; # get nicer global variables require \u0026#34;English\u0026#34; module Tty module_function def blue bold 34 end def red bold 31 end def reset escape 0 end def bold(code = 39) escape \u0026#34;1;#{code}\u0026#34; end def underline escape \u0026#34;4;39\u0026#34; end def escape(code) \u0026#34;\\033[#{code}m\u0026#34; if STDOUT.tty? end end class Array def shell_s cp = dup first = cp.shift cp.map { |arg| arg.gsub \u0026#34; \u0026#34;, \u0026#34;\\\\\u0026#34; }.unshift(first).join(\u0026#34; \u0026#34;) end end def ohai(*args) puts \u0026#34;#{Tty.blue}==\u0026gt;#{Tty.bold}#{args.shell_s}#{Tty.reset}\u0026#34; end def warn(warning) puts \u0026#34;#{Tty.red}Warning#{Tty.reset}: #{warning.chomp}\u0026#34; end def system(*args) abort \u0026#34;Failed during: #{args.shell_s}\u0026#34; unless Kernel.system(*args) end def sudo(*args) args.unshift(\u0026#34;-A\u0026#34;) unless ENV[\u0026#34;SUDO_ASKPASS\u0026#34;].nil? ohai \u0026#34;/usr/bin/sudo\u0026#34;, *args system \u0026#34;/usr/bin/sudo\u0026#34;, *args end def getc system \u0026#34;/bin/stty raw -echo\u0026#34; if STDIN.respond_to?(:getbyte) STDIN.getbyte else STDIN.getc end ensure system \u0026#34;/bin/stty -raw echo\u0026#34; end def wait_for_user puts puts \u0026#34;Press RETURN to continue or any other key to abort\u0026#34; c = getc # we test for \\r and \\n because some stuff does \\r instead abort unless (c == 13) || (c == 10) end class Version include Comparable attr_reader :parts def initialize(str) @parts = str.split(\u0026#34;.\u0026#34;).map(\u0026amp;:to_i) end def \u0026lt;=\u0026gt;(other) parts \u0026lt;=\u0026gt; self.class.new(other).parts end def to_s parts.join(\u0026#34;.\u0026#34;) end end def macos_version @macos_version ||= Version.new(`/usr/bin/sw_vers -productVersion`.chomp[/10\\.\\d+/]) end def should_install_command_line_tools? if macos_version \u0026gt; \u0026#34;10.13\u0026#34; !File.exist?(\u0026#34;/Library/Developer/CommandLineTools/usr/bin/git\u0026#34;) else !File.exist?(\u0026#34;/Library/Developer/CommandLineTools/usr/bin/git\u0026#34;) || !File.exist?(\u0026#34;/usr/include/iconv.h\u0026#34;) end end def user_only_chmod?(path) return false unless File.directory?(path) mode = File.stat(path).mode \u0026amp; 0777 # u = (mode \u0026gt;\u0026gt; 6) \u0026amp; 07 # g = (mode \u0026gt;\u0026gt; 3) \u0026amp; 07 # o = (mode \u0026gt;\u0026gt; 0) \u0026amp; 07 mode != 0755 end def chmod?(path) File.exist?(path) \u0026amp;\u0026amp; !(File.readable?(path) \u0026amp;\u0026amp; File.writable?(path) \u0026amp;\u0026amp; File.executable?(path)) end def chown?(path) !File.owned?(path) end def chgrp?(path) !File.grpowned?(path) end # USER isn\u0026#39;t always set so provide a fall back for the installer and subprocesses. ENV[\u0026#34;USER\u0026#34;] ||= `id -un`.chomp # Invalidate sudo timestamp before exiting (if it wasn\u0026#39;t active before). Kernel.system \u0026#34;/usr/bin/sudo -n -v 2\u0026gt;/dev/null\u0026#34; at_exit { Kernel.system \u0026#34;/usr/bin/sudo\u0026#34;, \u0026#34;-k\u0026#34; } unless $CHILD_STATUS.success? # The block form of Dir.chdir fails later if Dir.CWD doesn\u0026#39;t exist which I # guess is fair enough. Also sudo prints a warning message for no good reason Dir.chdir \u0026#34;/usr\u0026#34; ####################################################################### script if RUBY_PLATFORM.to_s.downcase.include?(\u0026#34;linux\u0026#34;) abort \u0026lt;\u0026lt;-EOABORT To install Linuxbrew, paste at a terminal prompt: sh -c \u0026#34;$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)\u0026#34; EOABORT elsif macos_version \u0026lt; \u0026#34;10.7\u0026#34; abort \u0026lt;\u0026lt;-EOABORT Your Mac OS X version is too old. See: #{Tty.underline}https://github.com/mistydemeo/tigerbrew#{Tty.reset}\u0026#34; EOABORT elsif macos_version \u0026lt; \u0026#34;10.9\u0026#34; abort \u0026#34;Your OS X version is too old\u0026#34; elsif Process.uid.zero? abort \u0026#34;Don\u0026#39;t run this as root!\u0026#34; elsif !`dsmemberutil checkmembership -U \u0026#34;#{ENV[\u0026#34;USER\u0026#34;]}\u0026#34; -G admin`.include?(\u0026#34;user is a member\u0026#34;) abort \u0026#34;This script requires the user #{ENV[\u0026#34;USER\u0026#34;]}to be an Administrator.\u0026#34; elsif File.directory?(HOMEBREW_PREFIX) \u0026amp;\u0026amp; (!File.executable? HOMEBREW_PREFIX) abort \u0026lt;\u0026lt;-EOABORT The Homebrew prefix, #{HOMEBREW_PREFIX}, exists but is not searchable. If this is not intentional, please restore the default permissions and try running the installer again: sudo chmod 775 #{HOMEBREW_PREFIX} EOABORT # TODO: bump version when new macOS is released elsif macos_version \u0026gt; MACOS_LATEST_SUPPORTED || macos_version \u0026lt; MACOS_OLDEST_SUPPORTED who = \u0026#34;We\u0026#34; if macos_version \u0026gt; MACOS_LATEST_SUPPORTED what = \u0026#34;pre-release version\u0026#34; elsif macos_version \u0026lt; MACOS_OLDEST_SUPPORTED who \u0026lt;\u0026lt; \u0026#34; (and Apple)\u0026#34; what = \u0026#34;old version\u0026#34; else return end ohai \u0026#34;You are using macOS #{macos_version.parts.join(\u0026#34;.\u0026#34;)}.\u0026#34; ohai \u0026#34;#{who}do not provide support for this #{what}.\u0026#34; puts \u0026lt;\u0026lt;-EOS This installation may not succeed. After installation, you will encounter build failures with some formulae. Please create pull requests instead of asking for help on Homebrew\u0026#39;s GitHub, Discourse, Twitter or IRC. You are responsible for resolving any issues you experience while you are running this #{what}. EOS end ohai \u0026#34;This script will install:\u0026#34; puts \u0026#34;#{HOMEBREW_PREFIX}/bin/brew\u0026#34; puts \u0026#34;#{HOMEBREW_PREFIX}/share/doc/homebrew\u0026#34; puts \u0026#34;#{HOMEBREW_PREFIX}/share/man/man1/brew.1\u0026#34; puts \u0026#34;#{HOMEBREW_PREFIX}/share/zsh/site-functions/_brew\u0026#34; puts \u0026#34;#{HOMEBREW_PREFIX}/etc/bash_completion.d/brew\u0026#34; puts HOMEBREW_REPOSITORY.to_s # Keep relatively in sync with # https://github.com/Homebrew/brew/blob/master/Library/Homebrew/keg.rb group_chmods = %w[bin etc include lib sbin share opt var Frameworks etc/bash_completion.d lib/pkgconfig share/aclocal share/doc share/info share/locale share/man share/man/man1 share/man/man2 share/man/man3 share/man/man4 share/man/man5 share/man/man6 share/man/man7 share/man/man8 var/log var/homebrew var/homebrew/linked bin/brew] .map { |d| File.join(HOMEBREW_PREFIX, d) } .select { |d| chmod?(d) } # zsh refuses to read from these directories if group writable zsh_dirs = %w[share/zsh share/zsh/site-functions] .map { |d| File.join(HOMEBREW_PREFIX, d) } mkdirs = %w[bin etc include lib sbin share var opt share/zsh share/zsh/site-functions var/homebrew var/homebrew/linked Cellar Caskroom Homebrew Frameworks] .map { |d| File.join(HOMEBREW_PREFIX, d) } .reject { |d| File.directory?(d) } user_chmods = zsh_dirs.select { |d| user_only_chmod?(d) } chmods = group_chmods + user_chmods chowns = chmods.select { |d| chown?(d) } chgrps = chmods.select { |d| chgrp?(d) } unless group_chmods.empty? ohai \u0026#34;The following existing directories will be made group writable:\u0026#34; puts(*group_chmods) end unless user_chmods.empty? ohai \u0026#34;The following existing directories will be made writable by user only:\u0026#34; puts(*user_chmods) end unless chowns.empty? ohai \u0026#34;The following existing directories will have their owner set to #{Tty.underline}#{ENV[\u0026#34;USER\u0026#34;]}#{Tty.reset}:\u0026#34; puts(*chowns) end unless chgrps.empty? ohai \u0026#34;The following existing directories will have their group set to #{Tty.underline}admin#{Tty.reset}:\u0026#34; puts(*chgrps) end unless mkdirs.empty? ohai \u0026#34;The following new directories will be created:\u0026#34; puts(*mkdirs) end if should_install_command_line_tools? ohai \u0026#34;The Xcode Command Line Tools will be installed.\u0026#34; end wait_for_user if STDIN.tty? \u0026amp;\u0026amp; !ENV[\u0026#34;CI\u0026#34;] if File.directory? HOMEBREW_PREFIX sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;u+rwx\u0026#34;, *chmods unless chmods.empty? sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;g+rwx\u0026#34;, *group_chmods unless group_chmods.empty? sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;755\u0026#34;, *user_chmods unless user_chmods.empty? sudo \u0026#34;/usr/sbin/chown\u0026#34;, ENV[\u0026#34;USER\u0026#34;], *chowns unless chowns.empty? sudo \u0026#34;/usr/bin/chgrp\u0026#34;, \u0026#34;admin\u0026#34;, *chgrps unless chgrps.empty? else sudo \u0026#34;/bin/mkdir\u0026#34;, \u0026#34;-p\u0026#34;, HOMEBREW_PREFIX sudo \u0026#34;/usr/sbin/chown\u0026#34;, \u0026#34;root:wheel\u0026#34;, HOMEBREW_PREFIX end unless mkdirs.empty? sudo \u0026#34;/bin/mkdir\u0026#34;, \u0026#34;-p\u0026#34;, *mkdirs sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;g+rwx\u0026#34;, *mkdirs sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;755\u0026#34;, *zsh_dirs sudo \u0026#34;/usr/sbin/chown\u0026#34;, ENV[\u0026#34;USER\u0026#34;], *mkdirs sudo \u0026#34;/usr/bin/chgrp\u0026#34;, \u0026#34;admin\u0026#34;, *mkdirs end sudo \u0026#34;/bin/mkdir\u0026#34;, \u0026#34;-p\u0026#34;, HOMEBREW_CACHE unless File.directory? HOMEBREW_CACHE sudo \u0026#34;/bin/chmod\u0026#34;, \u0026#34;g+rwx\u0026#34;, HOMEBREW_CACHE if chmod? HOMEBREW_CACHE sudo \u0026#34;/usr/sbin/chown\u0026#34;, ENV[\u0026#34;USER\u0026#34;], HOMEBREW_CACHE if chown? HOMEBREW_CACHE sudo \u0026#34;/usr/bin/chgrp\u0026#34;, \u0026#34;admin\u0026#34;, HOMEBREW_CACHE if chgrp? HOMEBREW_CACHE system \u0026#34;/usr/bin/touch\u0026#34;, \u0026#34;#{HOMEBREW_CACHE}/.cleaned\u0026#34; if File.directory? HOMEBREW_CACHE if should_install_command_line_tools? \u0026amp;\u0026amp; macos_version \u0026gt;= \u0026#34;10.13\u0026#34; ohai \u0026#34;Searching online for the Command Line Tools\u0026#34; # This temporary file prompts the \u0026#39;softwareupdate\u0026#39; utility to list the Command Line Tools clt_placeholder = \u0026#34;/tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress\u0026#34; sudo \u0026#34;/usr/bin/touch\u0026#34;, clt_placeholder clt_label_command = \u0026#34;/usr/sbin/softwareupdate -l | \u0026#34; \\ \u0026#34;grep -B 1 -E \u0026#39;Command Line Tools\u0026#39; | \u0026#34; \\ \u0026#34;awk -F\u0026#39;*\u0026#39; \u0026#39;/^ *\\\\*/ {print $2}\u0026#39; | \u0026#34; \\ \u0026#34;sed -e \u0026#39;s/^ *Label: //\u0026#39; -e \u0026#39;s/^ *//\u0026#39; | \u0026#34; \\ \u0026#34;sort -V | \u0026#34; \\ \u0026#34;tail -n1\u0026#34; clt_label = `#{clt_label_command}`.chomp unless clt_label.empty? ohai \u0026#34;Installing #{clt_label}\u0026#34; sudo \u0026#34;/usr/sbin/softwareupdate\u0026#34;, \u0026#34;-i\u0026#34;, clt_label sudo \u0026#34;/bin/rm\u0026#34;, \u0026#34;-f\u0026#34;, clt_placeholder sudo \u0026#34;/usr/bin/xcode-select\u0026#34;, \u0026#34;--switch\u0026#34;, \u0026#34;/Library/Developer/CommandLineTools\u0026#34; end end # Headless install may have failed, so fallback to original \u0026#39;xcode-select\u0026#39; method if should_install_command_line_tools? \u0026amp;\u0026amp; STDIN.tty? ohai \u0026#34;Installing the Command Line Tools (expect a GUI popup):\u0026#34; sudo \u0026#34;/usr/bin/xcode-select\u0026#34;, \u0026#34;--install\u0026#34; puts \u0026#34;Press any key when the installation has completed.\u0026#34; getc sudo \u0026#34;/usr/bin/xcode-select\u0026#34;, \u0026#34;--switch\u0026#34;, \u0026#34;/Library/Developer/CommandLineTools\u0026#34; end abort \u0026lt;\u0026lt;-EOABORT if `/usr/bin/xcrun clang 2\u0026gt;\u0026amp;1` =~ /license/ \u0026amp;\u0026amp; !$CHILD_STATUS.success? You have not agreed to the Xcode license. Before running the installer again please agree to the license by opening Xcode.app or running: sudo xcodebuild -license EOABORT ohai \u0026#34;Downloading and installing Homebrew...\u0026#34; Dir.chdir HOMEBREW_REPOSITORY do # we do it in four steps to avoid merge errors when reinstalling system \u0026#34;git\u0026#34;, \u0026#34;init\u0026#34;, \u0026#34;-q\u0026#34; # \u0026#34;git remote add\u0026#34; will fail if the remote is defined in the global config system \u0026#34;git\u0026#34;, \u0026#34;config\u0026#34;, \u0026#34;remote.origin.url\u0026#34;, BREW_REPO system \u0026#34;git\u0026#34;, \u0026#34;config\u0026#34;, \u0026#34;remote.origin.fetch\u0026#34;, \u0026#34;+refs/heads/*:refs/remotes/origin/*\u0026#34; # ensure we don\u0026#39;t munge line endings on checkout system \u0026#34;git\u0026#34;, \u0026#34;config\u0026#34;, \u0026#34;core.autocrlf\u0026#34;, \u0026#34;false\u0026#34; system \u0026#34;git\u0026#34;, \u0026#34;fetch\u0026#34;, \u0026#34;origin\u0026#34;, \u0026#34;master:refs/remotes/origin/master\u0026#34;, \u0026#34;--tags\u0026#34;, \u0026#34;--force\u0026#34; system \u0026#34;git\u0026#34;, \u0026#34;reset\u0026#34;, \u0026#34;--hard\u0026#34;, \u0026#34;origin/master\u0026#34; system \u0026#34;ln\u0026#34;, \u0026#34;-sf\u0026#34;, \u0026#34;#{HOMEBREW_REPOSITORY}/bin/brew\u0026#34;, \u0026#34;#{HOMEBREW_PREFIX}/bin/brew\u0026#34; system \u0026#34;#{HOMEBREW_PREFIX}/bin/brew\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;--force\u0026#34; end warn \u0026#34;#{HOMEBREW_PREFIX}/bin is not in your PATH.\u0026#34; unless ENV[\u0026#34;PATH\u0026#34;].split(\u0026#34;:\u0026#34;).include? \u0026#34;#{HOMEBREW_PREFIX}/bin\u0026#34; ohai \u0026#34;Installation successful!\u0026#34; puts # Use the shell\u0026#39;s audible bell. print \u0026#34;\\a\u0026#34; # Use an extra newline and bold to avoid this being missed. ohai \u0026#34;Homebrew has enabled anonymous aggregate formulae and cask analytics.\u0026#34; puts \u0026lt;\u0026lt;-EOS #{Tty.bold}Read the analytics documentation (and how to opt-out) here: #{Tty.underline}https://docs.brew.sh/Analytics#{Tty.reset} EOS ohai \u0026#34;Homebrew is run entirely by unpaid volunteers. Please consider donating:\u0026#34; puts \u0026lt;\u0026lt;-EOS #{Tty.underline}https://github.com/Homebrew/brew#donations#{Tty.reset} EOS Dir.chdir HOMEBREW_REPOSITORY do system \u0026#34;git\u0026#34;, \u0026#34;config\u0026#34;, \u0026#34;--replace-all\u0026#34;, \u0026#34;homebrew.analyticsmessage\u0026#34;, \u0026#34;true\u0026#34; system \u0026#34;git\u0026#34;, \u0026#34;config\u0026#34;, \u0026#34;--replace-all\u0026#34;, \u0026#34;homebrew.caskanalyticsmessage\u0026#34;, \u0026#34;true\u0026#34; end ohai \u0026#34;Next steps:\u0026#34; puts \u0026#34;- Run `brew help` to get started\u0026#34; puts \u0026#34;- Further documentation: \u0026#34; puts \u0026#34; #{Tty.underline}https://docs.brew.sh#{Tty.reset}\u0026#34; Set Homebrew Core cd \u0026#34;$(brew --repo)/Library/Taps/homebrew/homebrew-core\u0026#34; git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git Set Homebrew Bottles echo \u0026#39;export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles\u0026#39; \u0026gt;\u0026gt; ~/.bash_profile source ~/.bash_profile Set Homebrew Cask cd \u0026#34;$(brew --repo)\u0026#34;/Library/Taps/homebrew/homebrew-cask git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git Finally, brew update\n","date":"2020-03-05T17:22:17+08:00","permalink":"https://luosuu.github.io/post/install-homebrew-ustc-source/","section":"post","tags":null,"title":"Homebrew Install Scripts"},{"categories":null,"contents":"University of Electronic Science and Technology of China, Undergraduate, 2018-2022\nMicrosoft Student Club, Chair, 2019-2020\nMicrosoft Student Ambassador, Beta Member, 2020-2021\nLearn more on GitHub.\n","date":"2019-10-28T00:00:00Z","permalink":"https://luosuu.github.io/about/","section":"","tags":null,"title":"About"},{"categories":null,"contents":"","date":"2019-05-28T00:00:00Z","permalink":"https://luosuu.github.io/archives/","section":"","tags":null,"title":""},{"categories":["themes","syntax"],"contents":"This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.\nHeadings The following HTML \u0026lt;h1\u0026gt;—\u0026lt;h6\u0026gt; elements represent six levels of section headings. \u0026lt;h1\u0026gt; is the highest section level while \u0026lt;h6\u0026gt; is the lowest.\nH1 H2 H3 H4 H5 H6 Paragraph Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.\nItatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.\nBlockquotes The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a footer or cite element, and optionally with in-line changes such as annotations and abbreviations.\nBlockquote without attribution Tiam, ad mint andaepu dandae nostion secatur sequo quae. Note that you can use Markdown syntax within a blockquote.\n Blockquote with attribution Don\u0026rsquo;t communicate by sharing memory, share memory by communicating.\n— Rob Pike1\n Tables Tables aren\u0026rsquo;t part of the core Markdown spec, but Hugo supports supports them out-of-the-box.\n Name Age Bob 27 Alice 23 Inline Markdown within tables Inline Markdown In Table italics bold strikethrough code Code Blocks Code block with backticks html \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026quot;en\u0026quot;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026quot;UTF-8\u0026quot;\u0026gt; \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Code block indented with four spaces \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026quot;en\u0026quot;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026quot;UTF-8\u0026quot;\u0026gt; \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Code block with Hugo\u0026rsquo;s internal highlight shortcode \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; List Types Ordered List First item Second item Third item Unordered List List item Another item And another item Nested list Item First Sub-item Second Sub-item Other Elements — abbr, sub, sup, kbd, mark GIF is a bitmap image format.\nH2O\nXn + Yn = Zn\nPress CTRL+ALT+Delete to end the session.\nMost salamanders are nocturnal, and hunt for insects, worms, and other small creatures.\n The above quote is excerpted from Rob Pike\u0026rsquo;s talk during Gopherfest, November 18, 2015. \u0026#x21a9;\u0026#xfe0e;\n ","date":"2019-03-11T00:00:00Z","permalink":"https://luosuu.github.io/post/markdown-syntax/","section":"post","tags":["markdown","css","html","themes"],"title":"Markdown Syntax Guide"},{"categories":null,"contents":"Lorem est tota propiore conpellat pectoribus de pectora summo.\nRedit teque digerit hominumque toris verebor lumina non cervice subde tollit usus habet Arctonque, furores quas nec ferunt. Quoque montibus nunc caluere tempus inhospita parcite confusaque translucet patri vestro qui optatis lumine cognoscere flos nubis! Fronde ipsamque patulos Dryopen deorum.\n Exierant elisi ambit vivere dedere Duce pollice Eris modo Spargitque ferrea quos palude Rursus nulli murmur; hastile inridet ut ab gravi sententia! Nomine potitus silentia flumen, sustinet placuit petis in dilapsa erat sunt. Atria tractus malis.\n Comas hunc haec pietate fetum procerum dixit Post torum vates letum Tiresia Flumen querellas Arcanaque montibus omnes Quidem et Vagus elidunt \nThe Van de Graaf Canon\nMane refeci capiebant unda mulcebat Victa caducifer, malo vulnere contra dicere aurato, ludit regale, voca! Retorsit colit est profanae esse virescere furit nec; iaculi matertera et visa est, viribus. Divesque creatis, tecta novat collumque vulnus est, parvas. Faces illo pepulere tempus adest. Tendit flamma, ab opes virum sustinet, sidus sequendo urbis.\nIubar proles corpore raptos vero auctor imperium; sed et huic: manus caeli Lelegas tu lux. Verbis obstitit intus oblectamina fixis linguisque ausus sperare Echionides cornuaque tenent clausit possit. Omnia putatur. Praeteritae refert ausus; ferebant e primus lora nutat, vici quae mea ipse. Et iter nil spectatae vulnus haerentia iuste et exercebat, sui et.\nEurytus Hector, materna ipsumque ut Politen, nec, nate, ignari, vernum cohaesit sequitur. Vel mitis temploque vocatus, inque alis, oculos nomen non silvis corpore coniunx ne displicet illa. Crescunt non unus, vidit visa quantum inmiti flumina mortis facto sic: undique a alios vincula sunt iactata abdita! Suspenderat ego fuit tendit: luna, ante urbem Propoetides parte.\n .canon { background: white; width: 100%; height: auto;} ","date":"2019-03-09T00:00:00Z","permalink":"https://luosuu.github.io/post/placeholder-text/","section":"post","tags":["markdown","text"],"title":"Placeholder Text"},{"categories":null,"contents":"Emoji can be enabled in a Hugo project in a number of ways.\nThe emojify function can be called directly in templates or Inline Shortcodes.\nTo enable emoji globally, set enableEmoji to true in your site’s configuration and then you can type emoji shorthand codes directly in content files; e.g.\n🙈 :see_no_evil: 🙉 :hear_no_evil: 🙊 :speak_no_evil:\nThe Emoji cheat sheet is a useful reference for emoji shorthand codes.\n N.B. The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.\n.emoji { font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols; } .emojify { font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols; font-size: 2rem; vertical-align: middle; } @media screen and (max-width:650px) { .nowrap { display: block; margin: 25px 0; } } ","date":"2019-03-05T00:00:00Z","permalink":"https://luosuu.github.io/post/emoji-support/","section":"post","tags":["emoji"],"title":"Emoji Support"}]