首页 文章 精选 留言 我的

精选列表

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

MongoDB mapReduce案例分析二

例2、查找订单中一个商品对应的订单总数和这个商品每个订单的平均销售数量 1、先看订单表orders的数据结构如下图 这样的数据共有6条,如下,只列出了items这个字段 2、下面给出map函数 1 2 3 4 5 6 7 8 9 10 var mapFunction2 = function () { for ( var idx = 0; idx < this .items.length; idx++) { var key = this .items[idx].sku; var value = { count: 1, qty: this .items[idx].qty }; emit(key, value); } }; 3、写reduce函数 1 2 3 4 5 6 7 8 var reduceFunction2 = function (keySKU, countObjVals) { reducedVal = { count: 0, qty: 0 }; for ( var idx = 0; idx < countObjVals.length; idx++) { reducedVal.count += countObjVals[idx].count; reducedVal.qty += countObjVals[idx].qty; } return reducedVal; }; 4、写finalize函数 1 2 3 4 var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; }; 5、执行mapReduce函数 6、查看结果 本文转自shayang8851CTO博客,原文链接:http://blog.51cto.com/janephp/1292033,如需转载请自行联系原作者

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

squid 日志分析 - hadoop hive

#!/usr/bin/env python #-*-coding:UTF-8-*- """ @Item : Hadoop analysis squid log @Author : Villiam Sheng @Group : Linux Group @Date : 2012-09-13 @Funtion: Use hadoop squid processing log ...................... """ import os,re,threading,tarfile,shutil,time,sys,datetime import sys,traceback sys.path.append('/usr/local/hive/lib/py') from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from hive_service import ThriftHive from hive_service.ttypes import HiveServerException class split_log(threading.Thread): def __init__(self,files,lock): threading.Thread.__init__(self) self.files = files self.path = '/data1/squid_log' self.lock = lock def log(self,info): files = open('%s/split_log'%self.path,'a') try: files.write(info) except IOError: files.close() files.close() size = os.path.getsize('%s/split_log'%self.path) / 1024 if size >= 1024: fp = open('%s/split_log'%self.path,'w') fp.write('') fp.close() def run(self): try: if not os.path.isdir(self.files): tar = tarfile.open('%s/%s'%(self.path,self.files)) for name in tar.getnames(): tar.extract(name,'/%s/%s/'%(self.path,self.files.split('.tgz')[0])) tar.close() self.log('%s file:%s run.info:tar done \n'%(time.ctime(),self.files)) except Exception,e: self.log('%s files:%s run.info:%s \n'%(time.ctime(),self.files,e)) try: fp = open('%s/%s/access.log.0'%(self.path,self.files.split('.tgz')[0]),'r') for i in fp.readlines(): b = i.split() fps = open('%s/%s/tmp.log'%(self.path,self.files.split('.tgz')[0]),'a+') fps.write("%s\t%s\t%s\t%s\t%s\n" %(datetime.datetime.strptime(b[3].split('[')[1],'%d/%b/%Y:%H:%M:%S').strftime('%Y%m%d%H%M%S'),b[0],i.split('/')[4],b[-5],b[-1])) fps.close() fp.close() except Exception,e: self.log('%s file:%s inert.info:insert done \n'%(time.ctime(),self.files.split('.tgz')[0])) try: asql="load data local inpath \'%s/%s/tmp.log\' overwrite into table squid.squid_tmp partition(pt_ip = \'%s\')" %(self.path,self.files.split('.tgz')[0],self.files.split('.tgz')[0]) self.lock.acquire() transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() try: client.execute(asql) except: pass transport.close() self.lock.release() os.remove ('%s/%s'%(self.path,self.files)) shutil.rmtree('%s/%s' %(self.path,self.files.split('.tgz')[0])) except: self.log('Exception error : %s '%traceback.print_exc()) def work(): ip_list = re.compile('^(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))$') lock = threading.RLock() for i in os.listdir('/data1/squid_log/'): if not ip_list.match(i.split('.tgz')[0]): continue st = split_log(i,lock) st.start() while threading.active_count() != 1: time.sleep(1) transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() client.execute("use squid") client.execute("set hive.exec.dynamic.partition=true") client.execute("set hive.exec.dynamic.partition.mode=nonstrict") sql = "insert into table squid_log partition(pt_ip, pt_dt) select visittime, clientip, visitdom, visiturl, visitstat, pt_ip, substr(visittime, 1, 8) as pt_dt from squid_tmp" client.execute(sql) transport.close() if __name__ == "__main__": try: pid = os.fork() if pid > 0 : sys.exit(0) os.setsid() os.chdir('/') sys.stdin = open("/dev/null","r+") sys.stdout = os.dup(sys.stdin.fileno()) sys.stderr = os.dup(sys.stdin.fileno()) while True: work() time.sleep(300) work() except: pass 本文转自 swq499809608 51CTO博客,原文链接:http://blog.51cto.com/swq499809608/1142212

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

squid 日志分析 - hive 删除

#!/usr/bin/env python #-*-coding:utf8-*- import os,re,threading,tarfile,shutil,time,sys,datetime import sys,traceback sys.path.append('/usr/local/hive/lib/py') from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from hive_service import ThriftHive from hive_service.ttypes import HiveServerException transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() client.execute("use squid") class threads_del(threading.Thread): def __init__(self,pt_ip,pt_dt): threading.Thread.__init__(self) self.pt_ip = pt_ip self.pt_dt = pt_dt def run(self): client.execute("set hive.exec.dynamic.partition=true") client.execute("set hive.exec.dynamic.partition.mode=nonstrict") sql = "alter table squid_log drop partition(pt_ip = '%s', pt_dt=%s)"%(self.pt_ip,self.pt_dt) client.execute(sql) def work(): client.execute('show partitions squid_log') info = client.fetchAll() infos = {} for i in info: a = re.split("/",i) try: infos[re.split("=",a[0])[1]].append(re.split("=",a[1])[1]) except: infos[re.split("=",a[0])[1]] = [] infos[re.split("=",a[0])[1]].append(re.split("=",a[1])[1]) for k,v in infos.items(): st = threads_del(k,min(v)) st.start() st.join() while threading.active_count() >1: time.sleep(1) transport.close() if __name__ == "__main__": st = work() 本文转自 swq499809608 51CTO博客,原文链接:http://blog.51cto.com/swq499809608/1142457

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

uboot移植之主Makefile分析

1:#uboot 的版本号 VERSION = 1 #主版本号 PATCHLEVEL = 3 #次版本号 SUBLEVEL = 4 #再次版本号 EXTRAVERSION = #关于uboo的一些另外的描述 #变量U_BOOT_VERSION用来保存uboot的版本信息 U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) VERSION_FILE = $(obj)include/version_autogenerated.h //存放变量U_BOOT_VERSION,也就是版本信息 # 这个文件是编译时产生的中间文件include/version_autogenerated.h,这个文件的内容为 #define U_BOOT_VERSION "U-Boot 1.3.4"。 2:HOSTARCH(主机架构)和HOSTOS(主机操作系统) HOSTARCH := $(shell uname -m | \ sed -e s/i.86/i386/ \ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ \ -e s/sa110/arm/ \ -e s/powerpc/ppc/ \ -e s/ppc64/ppc/ \ -e s/macppc/ppc/) HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ sed -e 's/\(cygwin\).*/cygwin/') export HOSTARCH HOSTOS (1)shell uname -m,脚本执行的方法,可以通过shell + 命令来直接执行, uname -m表示获取主机架构 (2)| 表示管道,前面的表达式的结果作为后面表达式的一个输入,从而得到最终的输出,这里也就是shell uname -m得到的结果通过管道作为 sed -e的输入。 (3)sed -e 直接在命令模式下进行sed的动作,s 表示替代。所以这部分的意识就是,通过执行uname -m来获取主机的架构,然后通过管道的方法根据主机的架构来得到我们需要的主机架构,比如,我的主机架构是i686,那么sed -e s /i.86/i386,所以HOSTARCH := i386。(:=表示覆盖之前的内容) (4)uname -s 表示获取操作系统的名字 ,我们在ubuntu下开发,所以操作系统就是Linux,然后通过tr '[:upper:]' '[:lower:]'将大写字母改为小写,也就是HOSTOS := linux 3:ifeq (,$(findstring s,$(MAKEFLAGS))) XECHO = echo else XECHO = : endif 判断是否为静默编译,静默编译就是不在控制台打印Makefile里面的信息,但是其他文件的信息还是会被打印出来。 $(findstring s,$(MAKEFLAGS)的意思是在MAKEFLAGS查找字符 s ,也就是假如我们编译的时候输入的是 make -s 则为静默编译。 4:ifdef O ifeq ("$(origin O)", "command line") BUILD_DIR := $(O) endif endif 原地编译或者是单独文件编译, 单独文件编译实现的方法有两种 (1)通过make O = xxx(输出文件的pathname)来实现,主要这种方式在我们配置和清除的时候也要添加 O = xxx,也就是 make distclean O = xxx make x210_sd_config O = xxx make O = xxx (2)通过定义 export BUILD_DIR=xxx(输出文件的pathname)来实现, O=xxx的优先级高于export BUILD_DIR=xxx 5:OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #输出文件目录 SRCTREE := $(CURDIR) #当前目录,Makefile的当前目录也就是uboot的根目录 TOPDIR := $(SRCTREE) #顶层目录 LNDIR := $(OBJTREE) #链接文件目录 export TOPDIR SRCTREE OBJTREE 根据上面选择的是原地编译还是单独文件编译来确定并且导出这几个环境变量,用于后面使用,当选择原地编译时OBJTREE = SRCTREE OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) 如果 (if $(BUILD_DIR)为真(也就是BUILD_DIR被赋值)则OBJTREE = BUILD_DIR,否则OBJTREE = CURDIR。 6:MKCONFIG := $(SRCTREE)/mkconfig export MKCONFIG 定义并保存环境变量MKCONFIG。uboot根目录下的mkconfig文件是一个很重要的文件,uboot的配置就是根据这个文件的内容来实现的。 7:include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC 包含$(obj)目录下的include目录下的config.mk文件,这个文件的内容为 ARCH = arm CPU = s5pc11x BOARD = x210 VENDOR = samsung SOC = s5pc110 config.mk文件也是在配置的时候生成的 obj = OBJTREE,当原地编译的时候OBJTREE = SRCTREE = 源码根目录, 8:ifeq ($(ARCH),arm) #CROSS_COMPILE = arm-linux- #CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux- #CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux- CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- 通过ARCH的值来确定交叉编译工具链的前缀,CROSS_COMPILE的值其实就是交叉编译工具链的前缀。 9:include $(TOPDIR)/config.mk 添加根目录下的config.mk文件,这个文件的主要作用是 (1)补全交叉编译工具链,前面,在CROSS_COMPILE变量中我们保存了交叉编译工具链的前缀,其后缀就是在这个文件中补全的 (2)sinclude $(OBJTREE)/include/autoconf.mk:添加编译目录下的/include/autoconf.mk文件,这个文件是配置后生成的,里面全是CONFIG_开头的宏,这些宏定义左右着配置的uboot属于哪一款开发板。而这个文件的生成材料是顶层目录下的include/configs/xxx.h这个头文件,里面的一个头文件对应一款开发板,这个头文件的内容就是去描述或者说是配置这个开发板的硬件相关的信息。 (3)TEXT_BASE:链接地址的值 10:OBJS = cpu/$(CPU)/start.o,以及后面的LIBS = lib_generic/libgeneric.a等是在指定编译时需要添加的文件。 11:ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(obj)u-boot.dis ifeq ($(ARCH),blackfin) ALL += $(obj)u-boot.ldr all: $(ALL) $(obj)u-boot.hex: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ 当我们make编译的时候其实就是make all,当我们make all的时候又会生成类似于u-boot.hex的很多小目标,其中要注意的是最后一个目标unconfig unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk \ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \ $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \ $(obj)board/$(VENDOR)/$(BOARD)/config.mk unconfig这个目标就是rm -f移除我们在配置的时候生成的配置文件,这也是我们在make x210_sd_config之后再次执行make x210_sd_config时得到的效果是一样的,原因就是x210_sd_config依赖于unconfig,unconfig而将我们之前配置的文件全部移除了。 12:x210_sd_config : unconfig @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110 @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk @表示静默执行 $(MKCONFIG) 表示引用MKCONFIG这个环境变量,也就是根目录下的mkconfig,并且向这个文件传递了$(@:_config=) arm s5pc11x x210 samsung s5pc110这6个参数。 当我们执行make x210_sd_config的时候其实就是执行了这里的x210_sd_config这个目标。 本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1919951

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

MongoDB mapReduce案例分析一

例子1:找出集合中的所有键以及每个键对应的次数 MongoDB没有模式,所以并不知道每个文档有多少个键。通常找到集合中的所有键的最好方法就是利用MapReduce。好了,接下来看例子吧。 1、首先通过mongo->shell生成几条测试数据记录。 2、写map函数 3、写reduce函数 4、调用MapReduce看结果 5、查看结果 本文转自shayang8851CTO博客,原文链接:http://blog.51cto.com/janephp/1290604,如需转载请自行联系原作者

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

Spark 分析网站排名热度

需求: / 解决是一个各个子模块内的热度排名--》 排名得用sortBy ---》 (可能就是简单的排序,或者是二次排序) ---》 // 前面有一个wordCount---》 算出次数出来 --》 考虑什么作为key //算的一个网站下面,每个子模块下面的网页热度前2名 : // 算的一个网站下面,每个子模块下面的网页热度前2名 --》 每个子模块下面的网页的次数的前2名 // 在实际开发中,真正代码时间可能只占20-30% ,其他时间都在理解需求,想思路 importjava.net.URL importorg.apache.spark.{SparkConf,SparkContext} objectData_anlysis{ defmain(args:Array[String]){ valconf=newSparkConf().setAppName("data-anysis").setMaster("local[2]") valsc=newSparkContext(conf) vallinesRDD=sc.textFile("d://web_data.log") valrdd01=linesRDD.map(line=>{ vallineSplited=line.split("\t") (lineSplited(1),1) }) valrdd02=rdd01.reduceByKey(_+_) valrdd03=rdd02.map(tup=>{ valurl=tup._1; valhost=newURL(url).getHost (host,url,tup._2) }) valrdd04=rdd03.groupBy(_._1) valrdd05=rdd04.mapValues(iter=>{ iter.toList.sortBy(_._3).reverse.take(2) }) println(rdd05.collect().toBuffer) sc.stop() } } 运行结果会把网站的日志数据按照某一模块的要求列出排名前2个结果展示出来。 本文转自 ChinaUnicom110 51CTO博客,原文链接:http://blog.51cto.com/xingyue2011/1950745

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

[Android Pro] Scroller使用分析

reference to :http://blog.csdn.net/a910626/article/details/51548840 一.Scroller是什么? Android里 Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用,在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时,并不会导致View的滚动,通常是用mScroller记录/计算View滚 动的位置,再重写View的computeScroll(),完成实际的滚动。 Scroller只是个计算器,提供插值计算,让滚动过程具有动画属性,但它并不是UI,也不是辅助UI滑动,反而是单纯地为滑动提供计算。 无论从构造方法还是其他方法,以及Scroller的属性可知,其并不会持有View,辅助ViewGroup滑动。 Scroller只是提供计算,那谁来调用computeScroll使得ViewGroup滑动 computeScroll也不是来让ViewGroup滑动的,真正让ViewGroup滑动的是scrollTo,scrollBy。computeScroll的作用是计算ViewGroup如何滑动。而computeScroll是通过draw来调用的。 computeScroll和Scroller都是计算,两者有啥关系?没有直接的关系。computeScroll和Scroller要 是飞得拉关系的话,那就是computeScroll可以参考Scroller计算结果来影响scrollTo,scrollBy,从而使得滑动发生改 变。也就是Scroller不会调用computeScroll,反而是computeScroll调用Scroller。 滑动时连续的,如何让Scroller的计算也是连续的?这个就问到了什么时候调用computeScroll了,如上所说 computeScroll调用Scroller,只要computeScroll调用连续,Scroller也会连续,实质上 computeScroll的连续性又invalidate方法控制,scrollTo,scrollBy都会调用invalidate,而 invalidate回去触发draw,从而computeScroll被连续调用,综上,Scroller也会被连续调用,除非invalidate停 止调用。 computeScroll如何和Scroller的调用过程保持一致?computeScroll参考Scroller影响 scrollTo,scrollBy,实质上,为了不重复影响scrollTo,scrollBy,那么Scroller必须终止计算 currX,currY。要知道计算有没有终止,需要通过mScroller.computeScrollOffset() 二.这个知识应用场景是?可以解决什么问题? 我们在需求实现时,经常遇到view滑动的情况,而scrollTo、scrollBy方法都可以实现view的滑动,但是效果是瞬间完成的, 用户体验并不好,我们可以使用scroller或者smoothScrollto(内部也是scroller实现的)来实现平滑移动的效果。常见于自定义 view中。 三.该类的常见API? mScroller.getCurrX() //获取mScroller当前水平滚动的位置 mScroller.getCurrY() //获取mScroller当前竖直滚动的位置 mScroller.getFinalX() //获取mScroller最终停止的水平位置 mScroller.getFinalY() //获取mScroller最终停止的竖直位置 mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置 mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置 //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间 mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms mScroller.startScroll(int startX, int startY, int dx, int dy, int duration) mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。 四.常规的用法是什么? Scroller的基本用法其实还是比较简单的,主要可以分为以下几个步骤: 1. 创建Scroller的实例 2. 调用startScroll()方法来初始化滚动数据并刷新界面 3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑 五.使用时的难点在哪里? 使用的难点在于startScroll的参数含义,然后根据参数含义给出合适的值,因为这个过程涉及android中坐标计算,所以较为复杂。 // void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration) // 第一个参数是起始移动的x坐标值, // 第二个是起始移动的y坐标值, // 第三个第四个参数都是移到某点的坐标值-初始的坐标值,即移动的距离值 // 而duration 当然就是执行移动的时间。 六.一个案例:来自《android群英传》 public class ScrollerDragView extends View { private Scroller mScroller; private int mLastX; private int mLastY; public ScrollerDragView(Context context) { super(context); initView(context); } public ScrollerDragView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) { setBackgroundColor(Color.BLUE); mScroller = new Scroller(context); } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) event.getX(); mLastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; // 貌似使用了getParent,就不再需要重置x,y的坐标了 ((View)getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: View viewGroup = (View) getParent(); mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY()); invalidate(); break; } return true; } /** * 这里不需要特别的理解,只要使用Scroller,这里都是一样的 */ @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { ((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } } 分类: Android Pro 本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/p/6113099.html如需转载请自行联系原作者 demoblog

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

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

WebStorm

WebStorm

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

用户登录
用户注册