0%

Windows 下 (推荐)

下载 nodejs 和 git

下载 nodejs 32 位 msi 安装包 (https://npm.taobao.org/mirrors/node/v12.13.1/node-v12.13.1-x86.msi)

下载 git 的安装包 (https://git-scm.com/download/win) (可能贼慢, 自行解决)

安装 nodejs 及 cnpm

首先将 node-v12.13.1-x86.msi 双击安装, 一路 next 就行了

然后将 git 也装上, 也是一路 next, 不要犹豫

安装淘宝cnpm

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

下载 hello-world 项目

找到一个空白文件夹, 准备放置项目, 右键 选择 Git bash here, 然后命令行中输入:

1
git clone https://github.com/gudqs7/my-electron-hello-world.git

下载好后, 不要关闭窗口, 继续下面操作

安装依赖

在命令行中, 进入文件夹, 输入命令安装依赖

1
2
cd my-electron-hello-world
cnpm i

试运行下 App

1
cnpm run dev

看到一个宽1200 高 850 的窗口里面写着一句 Hello world 没有! 那就成了.

打包 exe

1
2
3
4
#一步到位, 生成 xxx setup.exe 安装包. (推荐)
cnpm run dist
#仅生成文件夹, 内含 xxx.exe 可启动, 很多资源文件, 需要自己二次打包
cnpm run pack

打包成功后, 可在dist 文件夹下找到 exe 名称 Setup 1.0.1.exe, 复制拿走即可

MacOS 下

安装 brew 及 设置 brew 源镜像为清华源

自行谷歌, 不建议百度

安装 nodejs 和 cnpm (淘宝镜像 npm)

打开终端(建议使用 iTerm2), 输入命令:

1
2
brew install nodejs
npm install -g cnpm --registry=https://registry.npm.taobao.org

下载 hello-world 项目

找到一个空白文件夹, 准备放置项目, 然后进命令行并 cd 到这个目录下, 输入命令:

1
git clone https://github.com/gudqs7/my-electron-hello-world.git

下载好后, 不要关闭窗口, 继续下面操作

安装依赖

在命令行中, 进入文件夹, 输入命令安装依赖

1
2
cd my-electron-hello-world
cnpm i

试运行下 App

1
cnpm run dev

看到一个宽1200 高 850 的窗口里面写着一句 Hello world 没有! 那就成了.

打包成 Mac App

1
2
3
4
#生成 dmg 文件, 方便分享, 下载
cnpm run dist
#生成可直接运行的 App, 但实际上是个文件夹, 不方便给他人下载
cnpm run pack

打包命令执行完毕, 检查 dist 目录即可

打包成 windows exe

1
cnpm run win32

这个命令我自己都下载半天, 实在是久啊. 而且由于要使用 wine 啥的进行打包, 似乎失败率很高啊…… 建议试试 yarn(官方建议)

个人推荐直接用 windows 操作系统搞一下就行了

注意事项

1
2
platform = win32  # 这个字段的值, 使用 --win 命令可指定, 默认与电脑环境一致
arch=ia32 # 这个字段的值, 使用--ia32 或 --x64 指定, 建议 ia32 省的 32 位系统不兼容 64 位的程序

另外多说一句, 若使用 32 位 windows 系统, cnpm i 下载依赖时就会下载 electron 的一个 sdk(用于生成 exe 的核心文件), 这个 sdk 是区分平台和cpu架构的. 由于用命令行指定平台和 cpu 架构不仅麻烦, 而且他使用的下载地址, 网速偏慢(极慢), 而 cnpm i 下载时则相对较快(感谢马云), 所以推荐选择适当的操作系统来打包, 会比较快.

  • 另外, 尝试使用 electron . 这个命令在 windows 上是跑不来的, 但将其加入到 package.json 中的 script 然后使用 cnpm run xxx 就没问题了.

  • 送大家一个网址, 在线 ico 转换, 支持256x256 (https://www.aconvert.com/cn/icon/png-to-ico/)

设计模式

7 大原则

1
2
3
4
5
6
7
单一职责: 每个类只负责一个职责(或每个方法)
接口隔离: 一个类对另一个类的依赖应建立在最小的接口上
依赖倒转: 高层模块不应依赖低层模块, 二者都应该依赖接口而非细节. 细节依赖抽象, 面向接口编程
里式替换: 子类应该做到可以替换父类, 及子类应尽量不重写父类方法.
开闭原则: 对提供者而已可以修改, 对使用者而言不需要修改(即代码兼容性), 尽量使用扩展增加功能, 而非修改原有类
迪米特法则: 一个对象应该对其他对象保持最小了解(最少知道原则)
合成复用原则: 一个类使用另一个类的代码(方法), 尽量使用合成, 而不是继承

创建型

单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
原理: 确保一个类只有一个实例,并提供该实例的全局访问点。

饿汉式:
静态常量
静态代码块
懒汉式:
直接判断(线程不安全)
方法加 synchronized(线程安全, 效率低)
判断后再同步(错误写法)
双重判断(if-同步-if) (推荐写法)
匿名静态内部类 (简单, 推荐)
枚举(简单, 但对象方法写在枚举中, 略有不适)

示例:
java.lang.Runtime#getRuntime()
java.awt.Desktop#getDesktop()

原型模式

1
2
3
4
5
6
7
8
9
原理: 使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象.
示例: Java 的 Object 对象的 clone 方法, java.util.Arrays.ArrayList#toArray()

浅拷贝: 仅对基础类型及字符串类型的字段拷贝值
深拷贝: 同时对引用类型(如数组,对象) 也进行拷贝

深拷贝实现:
1.重写 clone, 一一处理每个引用对象(调用对象的 clone), 麻烦, 且若对象之间关系复杂, 其中一个未实现深拷贝则导致 bug.
2.利用序列化和反序列化, 如 Json, 或 Java 自带的序列化方式(二进制)

创建者模式(生成器模式)

1
2
3
4
5
6
原理:
封装一个对象的构造过程,并允许按步骤构造.
若对象的生成过于复杂(字段极多且赋值还有依赖关系, 需要顺序调用), 则可将赋值过程封装成一个build(), 并放到一个 Builder 类中. 此类对外提供各个字段的赋值方法并先保存起来, 直到调用 build(), 此方法返回对象实例.
使用此模式, 调用者无需关注构建过程, 只需设置自己想要的值, 然后调用 build() 即可得到对象实例. 且若增加或修改字段, 构造过程变化, 调用者无感知, 无需修改代码. 符合开闭原则.

示例: StringBuilder, 一些框架的 ConfigurationBuilder(如 xmpp), 用于构建配置.

简单工厂模式

1
2
3
4
5
原理:
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
此模式可避免多个调用者创建对象时判断创建哪个子类的重复代码, 且若多一个子类, 调用者无需修改代码.

示例: Spring ApplicationContext 的 getBean 方法.

工厂方法模式

1
2
3
4
5
6
原理:
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
此模式解决了简单工厂每增加一个子类需要修改工厂类的问题.
此模式存在问题, 若新增一个子类, 需同时新增一个子类工厂, 系统复杂性更高.

示例: Calendar, NumberFormat

抽象工厂模式

1
2
3
4
5
6
原理:
提供一个接口,用于创建 相关的对象家族.
同上, 由子类工厂决定创建哪些对象.
此模式是工厂方法的升级版, 不同之处在于它同时创建多个种类的对象(工厂类具有多个方法).
此模式将一个对象家族的新建集合到一个工厂类创建管理, 这些对象家族相互之间一般有关联, 在创建时就可以处理这些关联. 且对于 2 个子类工厂, 一般可以无缝切换, 使得修改代码极为方便(即换一个子类工厂).
此模式在新增一个对象家族的成员时非常麻烦(即所有工厂类需要新增一个方法), 但再新增一类对象家族时比较简单(即新增一个子类工厂).

结构型

适配器模式

1
2
3
4
5
6
原理:
把一个接口转换成另一个用户需要的接口.
定义一个类, 实现用户需要的接口, 并聚合一个需要转换的接口对象, 在重写的方法(用户需要的方法)中调用聚合的对象的方法, 若需要返回值, 且返回值类型不一致, 则还需要在方法中处理一番, 然后返回. 这个过程叫做适配.这个类叫做适配器类.
使用此模式可对一些老旧接口适配兼容.

示例: java.util.Arrays#asList() 将数组适配成 List, Spring MVC的 HandlerAdapter

装饰者模式

1
2
3
4
5
6
原理:
将一个或多个功能(方法)动态的新增到一个类中.
把需要新增功能类称为 A,定义一个类B,实现A的上层接口, 并聚合一个A 的实例对象, B类实现的接口中, 对其他不关心的方法直接调用聚合的对象的方法. 对于关心的方法则可以在调用前后进行加料处理(如一个方法返回一个数, 可以在原来的返回值上乘以 2), 同时, B类也可以新增一些其他方法, 这些方法就是多出的功能. B类就是装饰者类, A就是被装饰类.
此模式的优点是, 装饰类也可以当做被装饰类, 然后再来一层装饰, 可以无限的装饰.

示例: java IO 流

代理模式

1
2
3
4
5
6
7
8
9
10
11
原理:
控制其他对象的访问(方法级), 将一些前置或后置的处理, 通过代理对象注入到目标对象的方法前后. 面向切面编程.

类型:
静态代理: 定义一个代理类实现目标对象的上层接口, 并聚合一个目标对象, 重写方法时将前置后置处理加上.
动态代理:
JDK 动态代理: 需要目标对象有上层接口(自然接口内的方法才可以代理)
使用java.lang.reflect.Proxy#getProxyClass
CGLIB 动态代理: 是个类就行. 实现原理是 ASM 框架动态生成目标对象类的子类字节码, 然后通过反射生成代理对象.

示例: Spring AOP

桥接模式

1
2
3
4
5
原理:
将抽象与实现分离开来,使它们可以独立变化。
桥接的含义是, 一个桥, 放在哪里都有桥的 2 边, 桥的 2 边可以变化, 但桥始终不变. 此处, 桥代表一个操作(如手机上运行软件), 2 边代表 一个操作的 2 个维度(如手机和软件). 同时, 桥接后的操作也可以视为一个维度, 与另一个维度桥接(如手机上运行软件和人这 2 个维度, 可以进行桥接, 组成 3 维度嵌套桥接).

示例: JDBC 获取连接, 获取连接是一个维度, 数据库是一个维度, 数据库有多个, 所以这是一个数据库维度变化, 另一维度不变的桥接模式.

享元模式

1
2
3
4
5
原理:
利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。
如常见的 线程池, 常量池等, 使得对象的获取速度加快.

示例: java.lang.Integer#valueOf() java.lang.Boolean#valueOf()

组合模式

1
2
3
4
5
6
7
8
9
10
原理:
将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
一般需要部分和整体具有一定的相似度, 才能对其进行抽象.
对部分/整体进行抽象, 得出一个公共抽象类或接口, 再实现类中根据具体角色做不同处理.

示例:
javax.swing.JComponent#add(Component)
java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)

外观模式

1
2
原理:
提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用.

行为型

职责链(责任链)模式

1
2
3
4
5
6
原理:
使多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止, 从而避免请求的发送者和接收者之间的耦合关系。

示例:
javax.servlet.Filter#doFilter()
netty 的 Handler Chain

观察者模式

1
2
3
4
5
6
7
原理:
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

示例:
swing 的事件监听(按钮事件, 鼠标事件)
JS 的 事件监听

状态模式

1
2
3
原理:
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为.

策略模式

1
2
3
4
5
6
原理:
定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。
策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法.

示例: java.util.Comparator#compare() javax.servlet.http.HttpServlet

模板方法模式

1
2
3
4
5
原理:
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

示例: java.util.Collections#sort()

命令模式

1
2
3
4
5
原理:
将一个对象(命令接收者)的每个操作拆分到每一个命令类中, 再使用一个命令管理类来管理这些命令. 使得命令可以放入队列中有序执行, 且可以统一记录命令的操作日志, 还可以支持撤销操作(每个命令都实现对应的撤销即可).
此模式的好处是, 若将命令抽象为几个标准的命令(如开,关), 然后管理多个命令接收者(如灯,电视机,空调)的操作, 可使新增命令接收者变得简单, 即扩展性好.

又称万能遥控器.

中介模式

1
2
3
4
5
原理:
集中相关对象之间复杂的沟通和控制方式。降低子系统之间的耦合.
类似一个消息收发中心, 负责字系统的消息中转, 使得子系统之间可以进行一定的交互.

示例: 线程池管理者线程和要执行的任务.

备忘录模式

1
2
3
原理:
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
如对游戏的当前状态进行一个保存, 然后在后续游戏中死亡后可以读取这个状态重新开始.

访问者模式

1
2
3
原理: 
为一个对象结构(比如组合结构)增加新能力。
使用访问者模式可实现重载的动态绑定(即伪双分派), 效果与重载方法内使用 instanceof 是一样的, 但使用访问者模式, 可扩展性更好.

迭代器模式

1
2
3
4
原理:
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

示例: java.util.Iterator

解释器模式

1
2
3
4
原理:
为语言创建解释器,通常由语言的语法和语法分析来定义。

示例: EL 表达式, Freemaker模板

空对象模式

1
2
原理:
使用什么都不做的空对象来代替 NULL, 避免空对象判断, 避免空指针异常.

explain 语法

1
explain select * from mysql.user;

explain 输出

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL NULL

每列简单含义

Column JSON Name Meaning
id select_id 执行编号
select_type None 每个执行的类型(SIMPLE|PRIMARY|UNION|SUBQUERY|DERIVED)
table table_name 每个执行的表名(实际表名或引用其他执行)
partitions partitions The matching partitions
type access_type The join type
possible_keys possible_keys 预测会使用的索引
key key The index actually chosen
key_len key_length The length of the chosen key
ref ref The columns compared to the index
rows rows 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
filtered filtered 按表条件过滤的行百分比
Extra None 包含MySQL解决查询的详细信息

含义详解

select_type
1
2
3
4
5
6
7
8
9
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(UNION的结果)
(6) SUBQUERY(子查询中的第一个SELECT)
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)
(8) DERIVED(派生表的SELECT, FROM子句的子查询)
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
type
1
2
3
4
5
6
7
(1) ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
(2) index: Full Index Scan,index与ALL区别为index类型只遍历索引树
(3) range:只检索给定范围的行,使用一个索引来选择行
(4) ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
(5) eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
(6) const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,即为system
(7) NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

参考文档: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types

extra
1
2
3
4
5
6
7
(1) Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
(2) Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询
(3) Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”
(4) Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。(如给关联表即行记录的table的关联列加索引)
(5) Impossible where:这个值强调了where语句会导致没有符合条件的行。
(6) Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
(7) Using Index: 仅使用索引树中的信息从表中检索列信息,而不必进行其他查找以读取实际行。当查询仅使用属于单个索引的列时,可以使用此策略。

参考文档: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-extra-information

总结

一般先针对 type, 将 type 调优到 ref, range, index 级别

然后查看 extra 信息, 尽量消除 using filesort, using join buffer, using temporary, using where

针对复杂的查询条件, 建议添加复合索引且确保复合索引有效使用(不跨列,按顺序,最左原则)

注意事项

1
2
1.Using Join Buffer: 对关联列加索引是没错, 但记住是关联表加, 而不是主表.
2.使用Explain时, SQL语句中的条件最好不要太真实, 可能会影响分析(如一张表全部都是sex=男, sex加索引, 然后使用explain分析时带上where sex='男', 分析结果的type会是ALL, 但如果sex='', 则type为ref)

基本环境准备

  • Docker
  • docker-compose
  • docker 阿里镜像加速
  • Git

对于 Mac

上诉环境只需要下载 docker的 dmg 安装后即可拥有 docker 和 docker-compose

对于 CentOs

docker
1
2
3
4
5
6
7
8
9
10
11
12
13
sudo yum update
# 移除旧版本
yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

#安装 docker
sudo yum install docker-ce
sudo systemctl start docker
# 开机启动
sudo systemctl enable docker
# 验证
docker --version
docker-compose
1
2
3
curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-(uname−s)−(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
git
1
sudo yum install -y git
go
1
2
3
4
5
6
7
8
9
10
11
wget -c https://studygolang.com/dl/golang/go1.14.linux-amd64.tar.gz
tar -C /usr/local/ -zxvf go1.14.linux-amd64.tar.gz
vi /etc/profile
# 新增
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=/root/go/

source /etc/profile
#验证
go version

下载文件及 docker 镜像

一键脚本

1
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.0.0 1.4.4 0.4.18
  • 2.0.0:表示Hyperledger Fabric的版本号
  • 1.4.4:表示Fabric CA的版本号
  • 0.4.18:表示第三方引用的版本号

加速技巧

首先自己整个科学上网, 设置好 http 代理端口(如 1087)

然后在docker 偏好设置中设置代理, 如下图

image-20200310095814860

设置完成后点击 Apply & Restart 重启生效.

若没有科学上网, 则可以手动执行 docker pull 命令, 单个执行不容易卡住

1
2
3
4
5
6
7
8
9
10
11
docker pull hyperledger/fabric-peer:2.0.0
docker pull hyperledger/fabric-orderer:2.0.0
docker pull hyperledger/fabric-ccenv:2.0.0
docker pull hyperledger/fabric-tools:2.0.0
docker pull hyperledger/fabric-nodeenv:2.0.0
docker pull hyperledger/fabric-baseos:2.0.0
docker pull hyperledger/fabric-javaenv:2.0.0
docker pull hyperledger/fabric-ca:1.4.4
docker pull hyperledger/fabric-zookeeper:0.4.18
docker pull hyperledger/fabric-kafka:0.4.18
docker pull hyperledger/fabric-couchdb:0.4.18

最后检查

1
2
3
4
cd fabric-samples/bin
ls -l
export PATH=$PATH:$(pwd)
orderer version

1.存在 bin 目录

2.bin 下存在 orderer 等可执行文件

3.将 bin 添加到 PATH 下

4.检查 orderer 版本是否正确

测试网络

1
2
3
4
5
cd fabric-samples/test-network
#注意会删除全部容器
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
./network.sh up

1.进入测试网络目录

2.停止并删除之前的容器防止命名冲突

3.运行测试网络(通过 docker-compose)

链码入门示例(智能合约)

启动环境及安装 npm

1
2
3
4
5
6
cd fabric-samples/fabcar
#将启动 first-network 环境, 然后将早已存在镜像中的链码代码打包, 安装, 验证, 提交, 使其可执行
./startFabric.sh javascript
cd javascript
# 自行安装cnpm
cnpm i

测试链码

官方提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
JavaScript:

Start by changing into the "javascript" directory:
cd javascript

Next, install all required packages:
npm install

Then run the following applications to enroll the admin user, and register a new user
called user1 which will be used by the other applications to interact with the deployed
FabCar contract:
node enrollAdmin
node registerUser

You can run the invoke application as follows. By default, the invoke application will
create a new car, but you can update the application to submit other transactions:
node invoke

You can run the query application as follows. By default, the query application will
return all cars, but you can update the application to evaluate other transactions:
node query

通过SDK(js) 调用合约

1
2
3
4
5
6
7
8
9
#添加 admin 用户和普通用户 user1
node enrollAdmin.js
node registerUser.js
# 执行合约的 queryAll 方法
node query.js
# 执行合约的 createCar 方法
node invoke.js
# 重新查询
node query.js

实际合约(js 代码)

fabric-samples/chaincode/fabcar/javascript/lib/fabcar.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* SPDX-License-Identifier: Apache-2.0
*/

'use strict';

const { Contract } = require('fabric-contract-api');

class FabCar extends Contract {

async initLedger(ctx) {
console.info('============= START : Initialize Ledger ===========');
const cars = [
{
color: 'blue',
make: 'Toyota',
model: 'Prius',
owner: 'Tomoko',
},
{
color: 'red',
make: 'Ford',
model: 'Mustang',
owner: 'Brad',
},
{
color: 'green',
make: 'Hyundai',
model: 'Tucson',
owner: 'Jin Soo',
},
{
color: 'yellow',
make: 'Volkswagen',
model: 'Passat',
owner: 'Max',
},
{
color: 'black',
make: 'Tesla',
model: 'S',
owner: 'Adriana',
},
{
color: 'purple',
make: 'Peugeot',
model: '205',
owner: 'Michel',
},
{
color: 'white',
make: 'Chery',
model: 'S22L',
owner: 'Aarav',
},
{
color: 'violet',
make: 'Fiat',
model: 'Punto',
owner: 'Pari',
},
{
color: 'indigo',
make: 'Tata',
model: 'Nano',
owner: 'Valeria',
},
{
color: 'brown',
make: 'Holden',
model: 'Barina',
owner: 'Shotaro',
},
];

for (let i = 0; i < cars.length; i++) {
cars[i].docType = 'car';
await ctx.stub.putState('CAR' + i, Buffer.from(JSON.stringify(cars[i])));
console.info('Added <--> ', cars[i]);
}
console.info('============= END : Initialize Ledger ===========');
}

async queryCar(ctx, carNumber) {
const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state
if (!carAsBytes || carAsBytes.length === 0) {
throw new Error(`${carNumber} does not exist`);
}
console.log(carAsBytes.toString());
return carAsBytes.toString();
}

async createCar(ctx, carNumber, make, model, color, owner) {
console.info('============= START : Create Car ===========');

const car = {
color,
docType: 'car',
make,
model,
owner,
};

await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
console.info('============= END : Create Car ===========');
}

async queryAllCars(ctx) {
const startKey = 'CAR0';
const endKey = 'CAR999';
const allResults = [];
for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {
const strValue = Buffer.from(value).toString('utf8');
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push({ Key: key, Record: record });
}
console.info(allResults);
return JSON.stringify(allResults);
}

async changeCarOwner(ctx, carNumber, newOwner) {
console.info('============= START : changeCarOwner ===========');

const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state
if (!carAsBytes || carAsBytes.length === 0) {
throw new Error(`${carNumber} does not exist`);
}
const car = JSON.parse(carAsBytes.toString());
car.owner = newOwner;

await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
console.info('============= END : changeCarOwner ===========');
}

}

module.exports = FabCar;

装机指南

常规软件

App Store

1
2
3
4
5
6
1.QQ
2.Wechat
3.Netease Music
4.Magnet
5.Youku
...

otherTools

1
2
3
4
5
6
7
8
9
10
11
12
1.iTerm2
2.uTools
3.VSCode
4.VMWare
5.Jetbrains Toolbox
6.XunLei Thunder
7.Baidu Disk
8.WPS
9.Charles
10.Docker
11.KeyCastr (录屏时显示键盘)
12.v2ray

Exists

1
2
3
4
5
6
7
8
9
10
1.ForkLift
2.Chrome
3.JDK8
4.Karabiner-Elements(key-bind-change)
5.Microsoft Remote Desktop
6.RDM
7.ShadowsocksX NG
8.Sougou Input
9.SublimeText
10.Typora

Safari 扩展

1
2
3
4
1.AdBlock (App Store)
2.Save to Pocket (App Store)
3.Toast for Safari (App Store)
4.Vimari (Github)

IDEA 插件

1
2
3
4
5
6
7
1.Alibaba Java Coding Guidelines
2.ignore
3.Translation
4.Lombok
5.VisualVM Launcher
6.GenerateAllSetter
7.Git Commit Template

开发工具

命令行一套

1
2
3
4
5
6
7
8
9
# zsh + oh my zsh + 高亮 + vim 高亮
curl -L https://raw.githubusercontent.com/gudqs7/mycode/master/zsh/one_zsh.sh | sh

# Git 别名
curl -L https://raw.githubusercontent.com/gudqs7/mycode/master/git/git-alias.sh | sh

# git代理
git config --global http.https://github.com.proxy http://127.0.0.1:1087
git config --global https.https://github.com.proxy https://127.0.0.1:1087

ssh 代理

vi ~/.ssh/config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 保持心跳
Host *
ServerAliveInterval 60

# git
Host github.com
HostName github.com
PreferredAuthentications publickey
ProxyCommand /usr/bin/nc -x 127.0.0.1:1086 %h %p
IdentityFile ~/.ssh/id_rsa

Host bitbucket.org
HostName bitbucket.org
ProxyCommand /usr/bin/nc -x 127.0.0.1:1086 %h %p
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_bucket

Host e.coding.net
HostName e.coding.net
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_bucket

Homebrew

安装 HomeBrew 及设置源
1
2
3
4
5
6
7
8
9
10
11
12
13
#安装home brew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

#设置加速源(若有科学上网设置了 git 代理后, 不建议设置加速源)
cd "$(brew --repo)"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git

brew update

echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc
添加 taps
1
2
3
4
5
6
7
8
9
10
11
#以太坊
brew tap ethereum/ethereum
#cask
brew tap homebrew/cask
brew tap homebrew/cask-versions
#core
brew tap homebrew/core
#services
brew tap homebrew/services
#php
brew tap josegonzalez/php
添加常用小工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
brew install telnet
brew install nmap
brew install vim
brew install wget
brew install git-flow
#cat 增强版
brew install bat
#man 简化版
brew install tldr
#find 增强版
brew install fd
#top 增强版
brew install htop
brew install tree
brew install go python node pyenv
brew install mysql redis postgresql
#k8s 相关
brew install docker-machine docker-machine-driver-hyperkit kubernetes-cli
brew install hadoop
brew install rabbitmq
brew install nexus
brew install siege
brew install ffmpeg
brew install ethereum solidity
brew cask
1
2
3
4
5
# finder 快速预览增强
brew cask install provisionql qlprettypatch quicklook-json betterzip qlcolorcode qlstephen quicklookapk qlimagesize qlvideo quicklookase qlmarkdown quicklook-csv

brew cask install minikube
brew cask install keycastr

Nodejs

全局 npm 包
1
2
3
4
5
6
7
npm install -g asar composer-cli pm2
#wx unpacker
npm install -g cnpm n nrm npm
npm install -g css-tree cssbeautify escodegen esprima js-beautify uglify-es vm2
npm install -g electron-builder electron-packager electron-prebuilt
npm install -g ganache-cli remix-ide truffle
npm install -g vue-cli yo

目录参考

code/remote

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.
├── gitee
│   ├── Mapper
│   └── jeesite4
├── github
│   ├── gudqs7
│   │   ├── JVMStudy
│   │   ├── architecture
│   │   ├── grid-helper
│   │   ├── gudqs7.github.io
│   │   ├── idea-keymap
│   │   ├── memo
│   │   ├── mycode
│   │   ├── php-study
│   │   ├── poi-tl
│   │   ├── utools-plugin
│   │   └── wxappUnpacker
│   ├── gudqs7-team
│   │   ├── an-jie-api
│   │   ├── miniprogram-demo
│   │   └── noworry-mini
│   ├── java
│   │   ├── SpringBootBucket
│   │   └── netty
│   └── other
│   ├── QQPlugin-MacOS
│   └── WeChatPlugin-MacOS
└── other

所有 APP 参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ls /Applications
AdBlock.app HBuilderX.app SunloginControl.app
AirServer.app JD-GUI.app TeamViewer.app
Alfred 4.app JetBrains Toolbox.app Tencent Lemon.app
Antivirus One.app Karabiner-Elements.app Thunder.app
AppCleaner.app Karabiner-EventViewer.app Toast.app
Aria2GUI.app KeyCastr.app Typora.app
Axure RP 9.app Keynote.app Utilities
BaiduNetdisk_mac.app Luyten.app VMware Fusion.app
BetterZip.app Magnet.app Vimari.app
Blackmagic Disk Speed Test.app Microsoft Excel.app Visual Studio Code.app
CCtalk.app Microsoft Remote Desktop Beta.app WeChat.app
Charles.app Microsoft Word.app Weiyun.app
CheatSheet.app NemuPlayer.app Wireshark.app
Clarity Wallpaper Mac.app NeteaseMusic.app XMind.app
CleanerOne.app Numbers.app Xcode.app
Clover Configurator.app Outline Manager.app apps
DingTalk.app Outline.app balenaEtcher.app
Docker.app Pages.app iMovie.app
DrUnarchiver.app Postman.app iPic.app
Eclipse.app QQ.app iTerm.app
FileZilla.app QQLive.app mat.app
Firefox.app RDM.app sPlayerFree.app
ForkLift.app RedisDM.app uTools.app
Ganache.app Safari.app wechatwebdevtools.app
GarageBand.app Save to Pocket.app 优酷.app
Geekbench 4.app ShadowsocksX-NG.app 微信支付商户平台证书工具.app
Google Chrome.app Sketch.app

镜像下载及U盘制作

镜像下载地址:

1
网址: imac.hk

U盘制作工具

1
2
etcher
https://www.balena.io/etcher/