首页 文章 精选 留言 我的

精选列表

搜索[AI安全分析],共10000篇文章
优秀的个人博客,低调大师

区块链教程Fabric1.0源代码分析configtx#ChannelConfig-兄弟连

Fabric 1.0源代码笔记 之 configtx(配置交易) #ChannelConfig(通道配置) 1、ChannelConfig概述 ChannelConfig代码分布在common/config目录下。目录结构如下: channel_util.go,channel相关工具函数。 orderer_util.go,orderer(系统通道)相关工具函数。 application_util.go,应用通道相关工具函数。 consortiums_util.go,联盟相关工具函数。 api.go,核心接口定义,如Org、ApplicationOrg、Channel、Orderer、Application、Consortium、Consortiums、ValueProposer接口定义。 root.go,Root结构体及方法。 channel.go,ChannelGroup结构体及方法。 orderer.go,OrdererGroup结构体及方法。 application.go,ApplicationGroup结构体及方法。 2、工具函数 2.1、channel相关工具函数 //用key和value构建cb.ConfigGroup func configGroup(key string, value []byte) *cb.ConfigGroup { result := cb.NewConfigGroup() result.Values[key] = &cb.ConfigValue{ Value: value, } } //设置联盟 //ConsortiumKey = "Consortium" //configGroup(ConsortiumKey, utils.MarshalOrPanic(&cb.Consortium{Name: name})) func TemplateConsortium(name string) *cb.ConfigGroup //设置哈希函数 //HashingAlgorithmKey = "HashingAlgorithm" //configGroup(HashingAlgorithmKey, utils.MarshalOrPanic(&cb.HashingAlgorithm{Name: name})) func TemplateHashingAlgorithm(name string) *cb.ConfigGroup //默认哈希函数 //const defaultHashingAlgorithm = bccsp.SHA256 //TemplateHashingAlgorithm(defaultHashingAlgorithm) func DefaultHashingAlgorithm() *cb.ConfigGroup //设置块数据哈希结构 //BlockDataHashingStructureKey = "BlockDataHashingStructure" //configGroup(BlockDataHashingStructureKey, utils.MarshalOrPanic(&cb.BlockDataHashingStructure{Width: width})) func TemplateBlockDataHashingStructure(width uint32) *cb.ConfigGroup //默认块数据哈希结构 //const defaultBlockDataHashingStructureWidth = math.MaxUint32 //TemplateBlockDataHashingStructure(defaultBlockDataHashingStructureWidth) func DefaultBlockDataHashingStructure() *cb.ConfigGroup //设置Orderer地址 //OrdererAddressesKey = "OrdererAddresses" //configGroup(OrdererAddressesKey, utils.MarshalOrPanic(&cb.OrdererAddresses{Addresses: addresses})) func TemplateOrdererAddresses(addresses []string) *cb.ConfigGroup //默认Orderer地址 //var defaultOrdererAddresses = []string{"127.0.0.1:7050"} //TemplateOrdererAddresses(defaultOrdererAddresses) func DefaultOrdererAddresses() *cb.ConfigGroup //代码在common/config/channel_util.go 补充cb.ConfigGroup定义: type ConfigGroup struct { Version uint64 Groups map[string]*ConfigGroup Values map[string]*ConfigValue Policies map[string]*ConfigPolicy ModPolicy string } //代码在protos/common/configtx.pb.go 2.2、orderer相关工具函数 func ordererConfigGroup(key string, value []byte) *cb.ConfigGroup func TemplateConsensusType(typeValue string) *cb.ConfigGroup func TemplateBatchSize(batchSize *ab.BatchSize) *cb.ConfigGroup func TemplateBatchTimeout(batchTimeout string) *cb.ConfigGroup func TemplateChannelRestrictions(maxChannels uint64) *cb.ConfigGroup func TemplateKafkaBrokers(brokers []string) *cb.ConfigGroup //代码在common/config/orderer_util.go 2.3、应用通道相关工具函数 func applicationConfigGroup(orgID string, key string, value []byte) *cb.ConfigGroup func TemplateAnchorPeers(orgID string, anchorPeers []*pb.AnchorPeer) *cb.ConfigGroup //代码在common/config/application_util.go 2.4、联盟相关工具函数 func TemplateConsortiumsGroup() *cb.ConfigGroup func TemplateConsortiumChannelCreationPolicy(name string, policy *cb.Policy) *cb.ConfigGroup //代码在common/config/consortiums_util.go 3、核心接口定义 type Org interface { //组织接口 Name() string //组织名称 MSPID() string //组织MSPID } type ApplicationOrg interface { //应用组织接口 Org //嵌入Org AnchorPeers() []*pb.AnchorPeer //锚节点 } type Channel interface { //通道配置接口 HashingAlgorithm() func(input []byte) []byte //哈希算法 BlockDataHashingStructureWidth() uint32 //指定计算 BlockDataHash 时使用的 Merkle 树的宽度 OrdererAddresses() []string //Orderer地址 } type Application interface { //应用配置接口 Organizations() map[string]ApplicationOrg //应用组织map } type Consortiums interface { //联盟配置map接口 Consortiums() map[string]Consortium //Consortium map } type Consortium interface { //联盟配置接口 ChannelCreationPolicy() *cb.Policy //通道创建策略 } type Orderer interface { //Orderer配置接口 ConsensusType() string //共识类型 BatchSize() *ab.BatchSize //块中的最大消息数 BatchTimeout() time.Duration //创建批处理之前等待的时间量 MaxChannelsCount() uint64 //最大通道数 KafkaBrokers() []string //Kafka地址 Organizations() map[string]Org //Orderer组织 } type ValueProposer interface { BeginValueProposals(tx interface{}, groups []string) (ValueDeserializer, []ValueProposer, error) //配置Proposal前 RollbackProposals(tx interface{}) //回滚配置Proposal PreCommit(tx interface{}) error //提交前 CommitProposals(tx interface{}) //提交 } //代码在common/config/api.go 4、Root结构体及方法 type Root struct { channel *ChannelGroup mspConfigHandler *msp.MSPConfigHandler } func NewRoot(mspConfigHandler *msp.MSPConfigHandler) *Root //构造Root //启动新的配置Proposal,r.mspConfigHandler.BeginConfig(tx) func (r *Root) BeginValueProposals(tx interface{}, groups []string) (ValueDeserializer, []ValueProposer, error) //回滚配置Proposal,r.mspConfigHandler.RollbackProposals(tx) func (r *Root) RollbackProposals(tx interface{}) //提交前校验配置,r.mspConfigHandler.PreCommit(tx) func (r *Root) PreCommit(tx interface{}) error //提交配置Proposal,r.mspConfigHandler.CommitProposals(tx) func (r *Root) CommitProposals(tx interface{}) //获取r.channel func (r *Root) Channel() *ChannelGroup //获取r.channel.OrdererConfig() func (r *Root) Orderer() *OrdererGroup //获取r.channel.ApplicationConfig() func (r *Root) Application() *ApplicationGroup //获取r.channel.ConsortiumsConfig() func (r *Root) Consortiums() *ConsortiumsGroup { //代码在common/config/root.go 5、ChannelGroup结构体及方法 5.1、ChannelGroup结构体及方法 type ChannelGroup struct { *ChannelConfig //嵌入ChannelConfig *Proposer //嵌入Proposer mspConfigHandler *msp.MSPConfigHandler } type ChannelConfig struct { *standardValues protos *ChannelProtos hashingAlgorithm func(input []byte) []byte appConfig *ApplicationGroup ordererConfig *OrdererGroup consortiumsConfig *ConsortiumsGroup } type ChannelProtos struct { HashingAlgorithm *cb.HashingAlgorithm BlockDataHashingStructure *cb.BlockDataHashingStructure OrdererAddresses *cb.OrdererAddresses Consortium *cb.Consortium } 构造ChannelGroup,以及构造ChannelConfig和Proposer func NewChannelGroup(mspConfigHandler *msp.MSPConfigHandler) *ChannelGroup func (cg *ChannelGroup) Allocate() Values //构造channelConfigSetter //获取cg.ChannelConfig.ordererConfig func (cg *ChannelGroup) OrdererConfig() *OrdererGroup //获取cg.ChannelConfig.appConfig func (cg *ChannelGroup) ApplicationConfig() *ApplicationGroup //获取cg.ChannelConfig.consortiumsConfig func (cg *ChannelGroup) ConsortiumsConfig() *ConsortiumsGroup func (cg *ChannelGroup) NewGroup(group string) (ValueProposer, error) //构造ChannelConfig,NewStandardValues(cc.protos) func NewChannelConfig() *ChannelConfig //获取cc.hashingAlgorithm func (cc *ChannelConfig) HashingAlgorithm() func(input []byte) []byte //获取cc.protos.BlockDataHashingStructure.Width func (cc *ChannelConfig) BlockDataHashingStructureWidth() uint32 //获取cc.protos.OrdererAddresses.Addresses func (cc *ChannelConfig) OrdererAddresses() []string //获取cc.protos.Consortium.Name func (cc *ChannelConfig) ConsortiumName() string func (cc *ChannelConfig) Validate(tx interface{}, groups map[string]ValueProposer) error func (cc *ChannelConfig) validateHashingAlgorithm() error func (cc *ChannelConfig) validateBlockDataHashingStructure() error func (cc *ChannelConfig) validateOrdererAddresses() error //代码在common/config/channel.go 补充cb.HashingAlgorithm、cb.BlockDataHashingStructure、cb.OrdererAddresses、cb.Consortium定义: //哈希算法 type HashingAlgorithm struct { Name string } //块数据哈希结构 type BlockDataHashingStructure struct { Width uint32 //指定计算 BlockDataHash 时使用的 Merkle 树的宽度 } //Orderer地址 type OrdererAddresses struct { Addresses []string } type Consortium struct { Name string } //代码在protos/common/configuration.pb.go 5.2、Proposer结构体及方法 type Proposer struct { vh Handler pending map[interface{}]*config current *config pendingLock sync.RWMutex } func NewProposer(vh Handler) *Proposer func (p *Proposer) BeginValueProposals(tx interface{}, groups []string) (ValueDeserializer, []ValueProposer, error) func (p *Proposer) PreCommit(tx interface{}) error func (p *Proposer) RollbackProposals(tx interface{}) func (p *Proposer) CommitProposals(tx interface{}) //代码在common/config/proposer.go 5.3、OrdererGroup结构体及方法 type OrdererGroup struct { *Proposer *OrdererConfig mspConfig *msp.MSPConfigHandler } type OrdererConfig struct { *standardValues protos *OrdererProtos ordererGroup *OrdererGroup orgs map[string]Org batchTimeout time.Duration } type OrdererProtos struct { ConsensusType *ab.ConsensusType BatchSize *ab.BatchSize BatchTimeout *ab.BatchTimeout KafkaBrokers *ab.KafkaBrokers ChannelRestrictions *ab.ChannelRestrictions } //构造OrdererGroup,以及Proposer func NewOrdererGroup(mspConfig *msp.MSPConfigHandler) *OrdererGroup func (og *OrdererGroup) NewGroup(name string) (ValueProposer, error) func (og *OrdererGroup) Allocate() Values //构造OrdererConfig func NewOrdererConfig(og *OrdererGroup) *OrdererConfig //oc.ordererGroup.OrdererConfig = oc func (oc *OrdererConfig) Commit() //获取oc.protos.ConsensusType.Type func (oc *OrdererConfig) ConsensusType() string //获取oc.protos.BatchSize func (oc *OrdererConfig) BatchSize() *ab.BatchSize //获取oc.batchTimeout func (oc *OrdererConfig) BatchTimeout() time.Duration //获取oc.protos.KafkaBrokers.Brokers func (oc *OrdererConfig) KafkaBrokers() []string //获取oc.protos.ChannelRestrictions.MaxCount func (oc *OrdererConfig) MaxChannelsCount() uint64 //获取oc.orgs func (oc *OrdererConfig) Organizations() map[string]Org func (oc *OrdererConfig) Validate(tx interface{}, groups map[string]ValueProposer) error func (oc *OrdererConfig) validateConsensusType() error func (oc *OrdererConfig) validateBatchSize() error func (oc *OrdererConfig) validateBatchTimeout() error func (oc *OrdererConfig) validateKafkaBrokers() error func brokerEntrySeemsValid(broker string) bool //代码在common/config/orderer.go 5.4、ApplicationGroup结构体及方法 //代码在common/config/application.go 欢迎继续关注兄弟连区块链教程分享!

优秀的个人博客,低调大师

深入理解Node.js-背景了解:核心思想与源码分析【1】

node背景,了解一下 (1)体系架构 Node.js主要分为四大部分,Node Standard Library,Node Bindings,V8,Libuv,架构图如下: Node Standard Library 是我们每天都在用的标准库,如Http, Buffer 模块。 Node Bindings 是沟通JS 和 C++的桥梁,封装V8和Libuv的细节,向上层提供基础API服务。 这一层是支撑 Node.js 运行的关键,由 C/C++ 实现。 V8 是Google开发的JavaScript引擎,提供JavaScript运行环境,可以说它就是 Node.js 的发动机。 Libuv 是专门为Node.js开发的一个封装库,提供跨平台的异步I/O能力 C-ares:提供了异步处理 DNS 相关的能力。 http_parser、OpenSSL、zlib 等:提供包括 http 解析、SSL、数据压缩等其他的能力。 代码结构 树形结构查看,使用 tree 命令 nodejs git:(master) tree -L 1 . ├── AUTHORS ├── BSDmakefile ├── BUILDING.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── COLLABORATOR_GUIDE.md ├── CONTRIBUTING.md ├── GOVERNANCE.md ├── LICENSE ├── Makefile ├── README.md ├── ROADMAP.md ├── WORKING_GROUPS.md ├── android-configure ├── benchmark ├── common.gypi ├── config.gypi ├── config.mk ├── configure ├── deps ├── doc ├── icu_config.gypi ├── lib ├── node.gyp ├── out ├── src ├── test ├── tools └── vcbuild.bat 复制代码 进一步查看 deps目录: nodejs git:(master) tree deps -L 1 deps ├── cares ├── gtest ├── http_parser ├── npm ├── openssl ├── uv ├── v8 └── zlib 复制代码 node.js核心依赖六个第三方模块。其中核心模块 http_parser, uv, v8这三个模块在后续章节我们会陆续展开。 gtest是C/C++单元测试框架。 (2)libuv node.js最初开始于2009年,是一个可以让Javascript代码离开浏览器的执行环境也可以执行的项目。 node.js使用了Google的V8解析引擎和Marc Lehmann的libev。Node.js将事件驱动的I/O模型与适合该模型的编程语言(Javascript)融合在了一起。随着node.js的日益流行,node.js需要同时支持windows, 但是libev只能在Unix环境下运行。Windows 平台上与kqueue(FreeBSD)或者(e)poll(Linux)等内核事件通知相应的机制是IOCP。libuv提供了一个跨平台的抽象,由平台决定使用libev或IOCP。在node-v0.9.0版本中,libuv移除了libev的内容。 libuv是一个高性能的,事件驱动的I/O库,并且提供了跨平台(如windows, linux)的API。 随着libuv的日益成熟,它成为了拥有卓越性能的系统编程库。除了node.js以外,包括Mozilla的Rust编程语言,和许多的语言都开始使用libuv。 libuv的官网:http://docs.libuv.org/en/v1.x/,英文的,可以直接参考。 (3)V8 concept[概念] 架构图 现在 JS 引擎的执行过程大致是:源代码 --->抽象语法树 --->字节码 --->JIT--->本地代码。一段代码的抽象语法树示例如下: function demo(name) { console.log(name); } 复制代码 V8 更加直接的将抽象语法树通过 JIT 技术转换成本地代码,放弃了在字节码阶段可以进行的一些性能优化,但保证了执行速度。 在 V8 生成本地代码后,也会通过 Profiler 采集一些信息,来优化本地代码。虽然,少了生成字节码这一阶段的性能优化, 但极大减少了转换时间。 JIT就是即时编译器,可以根据字节码的使用频率对常用的字节码生成本地机器指令(运行时),并且保存下来 PS:Tuborfan 将逐步取代 Crankshaft 随着Web相关技术的发展,JavaScript所要承担的工作也越来越多,早就超越了“表单验证”的范畴,这就更需要快速的解析和执行JavaScript脚本。V8引擎就是为解决这一问题而生,在node中也是采用该引擎来解析JavaScript。 Node,开始学习! 1. Node能够解决什么问题? 应用场景:Node的首要目标是提供一种简单的,用于创建高性能服务器的开发工具 Web服务器的瓶颈在于并发的用户量,对比Java和Php的实现方式 Node在处理高并发 , I/O密集场景有明显的性能优势 I/O (input/output 文件的输入输出) 高并发,是指在同一时间并发访问服务器 I/O密集指的是文件操作、网络操作、数据库,相对的有CPU密集,CPU密集指的是逻辑处理运算、压缩、解压、加密、解密 2. Node是什么? Node.js 是一个基于 Chrome V8引擎的 JavaScript 运行环境,让JavaScript的执行效率与低端的C语言的相近的执行效率。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。 Node.js 的包管理器npm,是全球最大的开源库生态系统。 3. 进程与线程 进程是操作系统分配资源和调度任务的基本单位,线程是建立在进程上的一次程序运行单位,一个进程上可以有多个线程。 为什么JavaScript是单线程? 这是由 Javascript 这门脚本语言的用途决定的。 Web Worker并没有改变 JavaScript 单线程的本质。 // websocket let worker = new Worker('./1.worker.js'); worker.postMessage(10000); worker.onmessage = function (e) { console.log(e.data); } console.log('main thread') 复制代码 3.1 谈谈浏览器 用户界面-包括地址栏、前进/后退按钮、书签菜单等 浏览器引擎-在用户界面和呈现引擎之间传送指令(浏览器的主进程) 渲染引擎,也被称为浏览器内核(浏览器渲染进程) 一个插件对应一个进程(第三方插件进程) GPU提高网页浏览的体验(GPU进程) 由此可见浏览器是多进程的,并且从我们的角度来看我们更加关心浏览器渲染引擎 3.2 渲染引擎 渲染引擎内部是多线程的,内部包含两个最为重要的线程ui线程和js线程。这里要特别注意ui线程和js线程是互斥的,因为JS运行结果会影响到ui线程的结果。ui更新会被保存在队列中等到js线程空闲时立即被执行. 3.3 js单线程 javascript在最初设计时设计成了单线程,为什么不是多线程呢?如果多个线程同时操作DOM那岂不会很混乱?这里所谓的单线程指的是主线程是单线程的(node其实也是多线程的),所以在Node中主线程依旧是单线程的。 js线程和ui线程 是共享线程 不能两个线程,操作同一个DOM 什么是多线程? 同步 每次请求都会产生一个线程,可能会遇到同时操作一个文件,会给文件加锁 可以开一个工作线程,但是归主线程所管理 需要切换上下文执行 运用线程池可以优化多线程 什么是单线程? 异步 不会占用过多内存,并且不需要在切换执行上下文 什么是进程? 进程是系统分配任务和调度任务的基本单位 多进程 可能会遇到同时操作一个文件会给文件加锁 3.4 其他线程 浏览器事件触发线程(用来控制事件循环,存放setTimeout、浏览器事件、ajax的回调函数) 定时触发器线程(setTimeout定时器所在线程) 异步HTTP请求线程(ajax请求线程) 单线程不需要管锁的问题,这里简单说下锁的概念。例如大家都要去上厕所,厕所就一个,相当于所有人都要访问同一个资源。那么先进去的就要上锁。而对于node来说。就一个人去厕所,所以免除了锁的问题! 3.5. 浏览器中的Event Loop 主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环) V8引擎解析JavaScript脚本。 解析后的代码,调用Node API。 libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。 V8引擎再将结果返回给用户。 queue stack queue队列: 先进先出 push shift stack栈: 函数执行 3.6 Node.js的Event Loop 3.7. 同步与异步 同步和异步关注的是消息通知机制 同步就是发出调用后,没有得到结果之前,该调用不返回,一旦调用返回,就得到返回值了。 简而言之就是调用者主动等待这个调用的结果。 而异步则相反,调用者在发出调用后这个调用就直接返回了,所以没有返回结果。换句话说当一个异步过程调用发出后,调用者不会立刻得到结果,而是调用发出后,被调用者通过状态、通知或回调函数处理这个调用。 补充知识:宏任务 && 微任务(vue $nextTick) 异步方法 // 宏任务 setTimeout // 同步代码执行后才会执行异步 // 根据时间排序,当时间到达后把对应的回调放到队列 setTimeout(() => { console.log(1); setTimeout(() => { console.log(4); }, 1000); }, 1000); setTimeout(() => { console.log(2); }, 2000); setTimeout(() => { console.log(3); }, 3000); 复制代码 // 宏任务 setImmedate // setImmedate只兼容ie,默认是低于 setTimeout setImmediate(function () { console.log('setImmediate') }) setTimeout(function () { console.log('timeout') }, 4); console.log(1); 复制代码 // 宏任务 MessageChannel let messageChannel = new MessageChannel(); let prot2 = messageChannel.port2; // postMessage是异步执行的,要等待同步都执行完后才会被调用 messageChannel.port1.postMessage('111'); console.log(1); prot2.onmessage = function (e) { console.log(e.data); } console.log(2); 复制代码 // 宏任务 MutationObserver废弃了,兼容/性能有问题 let observe = new MutationObserver(function () { alert('已经dom更新好了') }); observe.observe(app,{childList:true}); for(let i = 0;i<1000;i++){ app.appendChild(document.createElement('span')); } 复制代码 3.8. 阻塞与非阻塞I/O 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态. 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。 3.9. 组合 同步异步取决于被调用者,阻塞非阻塞取决于调用者 同步阻塞 异步阻塞 同步非阻塞 异步非阻塞 4. 什么场合下应该考虑使用Node框架? 当应用程序需要处理大量并发的输入输出,而在向客户端响应之前,应用程序并不需要进行非常复杂的处理。 聊天服务器 电子商务网站 原文发布时间:2018年07月02日 原文作者:张倩1488543336000 本文来源 掘金,如需转载请紧急联系作者

优秀的个人博客,低调大师

Python爬虫(二)——对开封市58同城出租房数据进行分析

出租房面积(area) 出租房价格(price) 对比信息 代码 1 import matplotlib as mpl 2 import matplotlib.pyplot as plt 3 import pandas as pad 4 import seaborn as sns 5 import numpy as np 6 7 sns.set_style('dark') 8 kf = pad.read_csv('kf.csv') 9 10 def sinplotone(): 11 fig,ax = plt.subplots() 12 ax.violinplot(kf['price']) 13 plt.show() 14 15 def sinplottwo(): 16 sns.set_style('whitegrid') 17 sns.boxplot(kf['price'],palette='deep') 18 # sns.despine(left=True) 19 plt.show() 20 21 def sinplotthree(): 22 sns.distplot(kf['price']) 23 plt.show() 24 25 def s(): 26 df = pad.DataFrame(kf['area'],kf['price']) 27 sns.jointplot(x='x',y='y',data=df) 28 plt.show() 29 30 if __name__ == '__main__': 31 fig,ax = plt.subplots() 32 ax.scatter(kf['area'],kf['price'],12) 33 plt.show()

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册