首页 文章 精选 留言 我的

精选列表

搜索[插件解析],共10000篇文章
优秀的个人博客,低调大师

NGINX配置PHP解析

<?php phpinfo(); ?> location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME usr/local/nginx/html$fastcgi_script_name; include fastcgi_params; } ------------------------------------------------------------- 作者: 罗穆瑞 出处: http://www.cnblogs.com/kazihuo/ 转载请保留此段声明,且在文章页面明显位置给出原文链接,谢谢! ------------------------------------------------------------------------------ 如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢! ------------------------------------------------------------------------------

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

springboot源码解析(一)

SpringBoot应用基础结构 我们每创建一个springboot应用就会发现,其目录结构中都会有一个以应用名为首的Application类(下文中都直接称为Application类),而其他包都是在这个类的同级或子级下面,结构如图: Application类作为应用的启动类,位于项目源码的根目录中,至于为什么结构会这么安排,我们下面会说。 Application类的结构 如上图所示,我们可以看到,最关键的地方有两个: @SpringBootApplication注解 SpringApplication.run()方法 任何的springboot应用都会由这两个部分组成。接下来我就来就这两个地方分析源码。 @SpringBootApplication注解 打开注解的源码我们可以看到,主要由以下几个注解组成: @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan @SpringBootConfiguration @SpringBootConfiguration注解是由@Configuration来注解的,因此也就表示Application类本身就是一个bean。虽然@SpringBootConfiguration注释中说该注解一个应用中只能用一次,但是配置多个也不会报错,只是建议在一个应用中只用一次,并且该注解也可以与@Configuration互换。 @ComponentScan @ComponentScan注解的功能与我们之前在xml文件配置的的功能是一样的,而上面也提到Application类放在源码的根目录下,其实就是与这个注解有关。@ComponentScan在没有指明basePackages忏属性的时候,默认会扫描该注解所在的类的包及其子包下的所有@Component注解过的类,包括@Controller,@Service,@Configuration这些注解。这也就是为什么我们不用做任何配置,就可以将springboot应用中的类扫描为bean。 @EnableAutoConfiguration @EnableAutoConfiguration注解,从名字我们也可以看出,是开启自配置配置的。从源码中我们可以看到,该注解中有一个@Import(AutoConfigurationImportSelector.class),而其中发挥自动配置作用就是AutoConfigurationImportSelector类。 从AutoConfigurationImportSelector的源码中可以知道,该类是通过SpringFactoriesLoader来加载自动配置的类的,从而进一步通过这些自动配置的类来完成默认配置。从而这也就解决了,为什么我们使用springboot的时候压根就不需要配置太多,原因就是因为SpringBoot通过自动配置将已经封装在jar包中的自动配置类加载进来生成了bean。而对于SpringFactoriesLoader的原理我们下面会说。 SpringApplication类 Application类是通过SpringApplication类的静态run方法来启动应用的。打开这个静态方法,该表态方法真正执行的是两部分: new SpringApplication() 执行对象run()方法 在SpringApplication的构造方法中,我们可以看到有如下几个步骤: 推断当前的环境是否是web环境,其中springboot2.0中又添加了reactive环境。 初始化ApplicationContextInitilizer,其中的原理也是通过SpringFactoriesLoader来实现的。 初始化ApplicationListener,原理同上。 推断当前启动的main方法所在的类。 推断当前应用环境 springboot在启动时需要推断当前的应用环境,springboot2.0当中一共定义了三种环境:none, servlet, reactive。none表示当前的应用即不是一个web应用也不是一个reactive应用,是一个纯后台的应用。servlet表示当前应用是一个标准的web应用。reactive是spring5当中的新特性,表示是一个响应式的web应用。而判断的依据就是根据Classloader中加载的类。如果是servlet,则表示是web,如果是DispatcherHandler,则表示是一个reactive应用,如果两者都不存在,则表示是一个非web环境的应用。 初始化ApplicationContextInitializer 在介绍初始化之前,先介绍一下SpringFactoiesLoader的原理。 SpringFactoiesLoader会扫描所有jar包中的META-INF/spring.factoies文件,该文件的格式都是key=value的格式。key是一个接口的名字,value是实现类的名字,如果value有多个值,则用逗号分隔。而我们上面提到的@EnableAutoConfiguration也是利用这个原理去扫描所有的自动配置类,以该注解的全限定类名作为key,所有的默认配置类为值。SpringFactoiesLoader内部有一个静态的双层ConcurrentMap,用来存储这些key-value,第一层map的key是classloader,springboot默认的classloader是appClassLoader,value则是一个MultiValueMap,是spring自己实现的一个hashmap。而这个MultiValueMap的key就是spring.factoies文件中的key,value是一个list,即spring.factoies文件中的value。SpringFactoiesLoader利用缓存机制,只在第一次扫描所有的META-INF/spring.factoies文件时,就把所有的key-value都加载到这个map中,后面再进从中获取值时,直接从map中取就可以了,就不需要再重新扫描了。 把ApplicationContextInitializer都加载了之后,还要进行一项工作就是会对所有的ApplicationContextInitializer实现类生成对象,SpringApplication中有一个属性,List类型的initializers,用来存储这些实例化后的对象,这些对象存储之后,会在后面的启动过程中初始化ApplicationContext。 初始化ApplicationListener ApplicationListener的过程与ApplicationContextInitializer是一样的,不过因为SpringFactoiesLoader已经扫描过一次了,所以这次执行的时候,就会直接从SpringFactoiesLoader中的静态map中取出值即可。同样的,也需要将所有的实现类生成对象,并保存在SpringApplication对象的listener list属性中。 注:springboot初始化过程中主要是扫描两个spring.factoies文件,其中定义的key-value中的类,是整个启动过程中要用到的。一个是spring-boot-2.0.3.RELEASE中的,一个是spring-boot-autoconfigure包中的。这两个jar包中的文件定义整个启动流程中要执行的所有默认配置好的类。 推断整个应用的main方法所在的类 其实我们已经从main方法中启动了,为什么后面还要再推断一下呢?其实这样做的目的,主要是为了将该类的对象存储在SpringApplication的对象中,创建日志Logger和打印日志用的。我们在启动时会看到主类的类名以及其他的打印信息,都是通过该对象来创建logger和打印日志的。 总结:从上面几个步骤中我们可以看出,前期的new SpringApplication()方法中主要是起到了一个预加载的功能,将前期的环境判断,后面要用到的对象都准备好,到run执行的时候就直接拿出来用就好了,也是大大方便了后面run方法执行的过程。

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

python 装饰器解析

一般来说,装饰器是一个函数,接受一个函数(或者类)作为参数,返回值也是也是一个函数(或者类)。首先来看一个简单的例子: -- coding: utf-8 -- def log_cost_time(func): def wrapped(*args, **kwargs): import time begin = time.time() try: return func(*args, **kwargs) finally: print 'func %s cost %s' % (func.__name__, time.time() - begin) return wrapped @log_cost_time def complex_func(num): ret = 0 for i in xrange(num): ret += i * i return ret complex_func = log_cost_time(complex_func) if name == '__main__': print complex_func(100000) code snippet 0 代码中,函数log_cost_time就是一个装饰器,其作用也很简单,打印被装饰函数运行时间。 装饰器的语法如下: @dec def func():pass 本质上等同于: func = dec(func)。 在上面的代码(code snippet 0)中,把line12注释掉,然后把line18的注释去掉,是一样的效果。另外staticmethod和classmethod是两个我们经常在代码中用到的装饰器,如果对pyc反编译,得到的代码一般也都是 func = staticmthod(func)这种模式。当然,@符号的形式更受欢迎些,至少可以少拼写一次函数名。 装饰器是可以嵌套的,如 @dec0 @dec1 def func():pass 等将于 func = dec0(dec1(fun))。 装饰器也有“副作用“”,对于被log_cost_time装饰的complex_calc, 我们查看一下complex_func.__name__,输出是:”wrapped“”。额,这个是log_cost_time里面inner function(wrapped)的名字,调用者当然希望输出是”complex_func”,为了解决这个问题,python提供了两个函数。 functools.update_wrapper 原型: functools.update_wrapper(wrapper, wrapped, assigned) 第三个参数,将wrapped的值直接复制给wrapper,默认为(__doc__, __name__, __module__) 第四个参数,update,默认为(__dict__) functools.wraps: update_wrapper的封装 This is a convenience function for invoking partial(update_wrapper,wrapped=wrapped,assigned=assigned,updated=updated) as a function decorator when defining a wrapper function. 简单改改代码: import functools def log_cost_time(func): @functools.wraps(func) def wrapped(*args, **kwargs): import time begin = time.time() try: return func(*args, **kwargs) finally: print 'func %s cost %s' % (func.__name__, time.time() - begin) return wrapped 再查看complex_func.__name__ 输出就是 “complex_func” 装饰器也是可以带参数的。我们将上面的代码略微修改一下: def log_cost_time(stream): def inner_dec(func): def wrapped(*args, **kwargs): import time begin = time.time() try: return func(*args, **kwargs) finally: stream.write('func %s cost %s \n' % (func.__name__, time.time() - begin)) return wrapped return inner_dec import sys @log_cost_time(sys.stdout) def complex_func(num): ret = 0 for i in xrange(num): ret += i * i return ret if name == '__main__': print complex_func(100000) code snippet 1 log_cost_time函数也接受一个参数,该参数用来指定信息的输出流,对于带参数的decorator @dec(dec_args) def func(args, *kwargs):pass 等价于 func = dec(dec_args)(args, *kwargs)。 装饰器对类的修饰也是很简单的,只不过平时用得不是很多。举个例子,我们需要给修改类的__str__方法,代码很简单。 def Haha(clz): clz.__str__ = lambda s: "Haha" return clz @Haha class Widget(object): ''' class Widget ''' if name == '__main__': w = Widget() print w 那什么场景下有必要使用decorator呢,设计模式中有一个模式也叫装饰器。我们先简单回顾一下设计模式中的装饰器模式,简单的一句话概述 动态地为某个对象增加额外的责任 由于装饰器模式仅从外部改变组件,因此组件无需对它的装饰有任何了解;也就是说,这些装饰对该组件是透明的。 下图来自《设计模式Java手册》或者GOF的《设计模式》 回到Python中来,用decorator语法实现装饰器模式是很自然的,比如文中的示例代码,在不改变被装饰对象的同时增加了记录函数执行时间的额外功能。当然,由于Python语言的灵活性,decorator是可以修改被装饰的对象的(比如装饰类的例子)。decorator在python中用途非常广泛,下面列举几个方面: (1)修改被装饰对象的属性或者行为 (2)处理被函数对象执行的上下文,比如设置环境变量,加log之类 (3)处理重复的逻辑,比如有N个函数都可能跑出异常,但是我们不关心这些异常,只要不向调用者传递异常就行了,这个时候可以写一个catchall的decorator,作用于所用可能跑出异常的函数 def catchall(func): @functools.wraps(func) def wrapped(*args, **kwargs): try: return func(*args, **kwargs) except: pass return wrapped (4)框架代码,如flask, bottle等等,让使用者很方便就能使用框架,本质上也避免了重复代码。 decorator的奇妙应用往往超出相应,经常在各种源码中看到各种神奇的用法,酷壳这篇文章举的例子也不错。 参考文献 [2]H. Berenson, P. Bernstein, J. Gray, J.Melton, E. O’Neil,and P. O’Neil. A critique of ANSI SQL isolation levels. InProceedings of the SIGMOD International Conference on Management of Data, pages1–10, May 1995. [3]Michael J. Cahill, Uwe Röhm, and Alan D.Fekete. 2008. Serializable isolation for snapshot databases. In SIGMOD ’08:Proceedings of the 2008 ACM SIGMOD international conference on Management of data, pages 729–738, New York, NY, USA. ACM. [4]Michael James Cahill. 2009. Serializable Isolation for Snapshot Databases. Sydney Digital Theses. University of Sydney, School of Information Technologies [5] A. Fekete, D. Liarokapis, E. O’Neil, P.O’Neil, andD. Shasha. Making snapshot isolation serializable. www.codexueyuan.com In ACM transactions on database systems, volume 39(2), pages 492–528, June 2005.

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

Android Fragment完全解析

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8881711 我们都知道,Android上的界面展示都是通过Activity实现的,Activity实在是太常用了,我相信大家都已经非常熟悉了,这里就不再赘述。 但是Activity也有它的局限性,同样的界面在手机上显示可能很好看,在平板上就未必了,因为平板的屏幕非常大,手机的界面放在平板上可能会有过分被拉长、控件间距过大等情况。这个时候更好的体验效果是在Activity中嵌入"小Activity",然后每个"小Activity"又可以拥有自己的布局。因此,我们今天的主角Fragment登场了。 Fragment初探 为了让界面可以在平板上更好地展示,Android在3.0版本引入了Fragment(碎片)功能,它非常类似于Activity,可以像Activity一样包含布局。Fragment通常是嵌套在Activity中使用的,现在想象这种场景:有两个Fragment,Fragment 1包含了一个ListView,每行显示一本书的标题。Fragment 2包含了TextView和ImageView,来显示书的详细内容和图片。 如果现在程序运行竖屏模式的平板或手机上,Fragment 1可能嵌入在一个Activity中,而Fragment 2可能嵌入在另一个Activity中,如下图所示: 而如果现在程序运行在横屏模式的平板上,两个Fragment就可以嵌入在同一个Activity中了,如下图所示: 由此可以看出,使用Fragment可以让我们更加充分地利用平板的屏幕空间,下面我们一起来探究下如何使用Fragment。 首先需要注意,Fragment是在3.0版本引入的,如果你使用的是3.0之前的系统,需要先导入android-support-v4的jar包才能使用Fragment功能。 新建一个项目叫做Fragments,然后在layout文件夹下新建一个名为fragment1.xml的布局文件: <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Thisisfragment1" android:textColor="#000000" android:textSize="25sp"/> </LinearLayout> 可以看到,这个布局文件非常简单,只有一个LinearLayout,里面加入了一个TextView。我们如法炮制再新建一个fragment2.xml : <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffff00"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Thisisfragment2" android:textColor="#000000" android:textSize="25sp"/> </LinearLayout> 然后新建一个类Fragment1,这个类是继承自Fragment的: publicclassFragment1extendsFragment{ @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){ returninflater.inflate(R.layout.fragment1,container,false); } } 我们可以看到,这个类也非常简单,主要就是加载了我们刚刚写好的fragment1.xml布局文件并返回。同样的方法,我们再写好Fragment2 : publicclassFragment2extendsFragment{ @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){ returninflater.inflate(R.layout.fragment2,container,false); } } 然后打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的Fragment: <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false"> <fragment android:id="@+id/fragment1" android:name="com.example.fragmentdemo.Fragment1" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1"/> <fragment android:id="@+id/fragment2" android:name="com.example.fragmentdemo.Fragment2" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout> 最后打开或新建MainActivity作为程序的主Activity,里面的代码非常简单,都是自动生成的: publicclassMainActivityextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } 现在我们来运行一次程序,就会看到,一个Activity很融洽地包含了两个Fragment,这两个Fragment平分了整个屏幕,效果图如下: 动态添加Fragment 你已经学会了如何在XML中使用Fragment,但是这仅仅是Fragment最简单的功能而已。Fragment真正的强大之处在于可以动态地添加到Activity当中,因此这也是你必须要掌握的东西。当你学会了在程序运行时向Activity添加Fragment,程序的界面就可以定制的更加多样化。下面我们立刻来看看,如何动态添加Fragment。 还是在上一节代码的基础上修改,打开activity_main.xml,将其中对Fragment的引用都删除,只保留最外层的LinearLayout,并给它添加一个id,因为我们要动态添加Fragment,不用在XML里添加了,删除后代码如下: <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false"> </LinearLayout> 然后打开MainActivity,修改其中的代码如下所示: publicclassMainActivityextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Displaydisplay=getWindowManager().getDefaultDisplay(); if(display.getWidth()>display.getHeight()){ Fragment1fragment1=newFragment1(); getFragmentManager().beginTransaction().replace(R.id.main_layout,fragment1).commit(); }else{ Fragment2fragment2=newFragment2(); getFragmentManager().beginTransaction().replace(R.id.main_layout,fragment2).commit(); } } } 首先,我们要获取屏幕的宽度和高度,然后进行判断,如果屏幕宽度大于高度就添加fragment1,如果高度大于宽度就添加fragment2。动态添加Fragment主要分为4步: 1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。 2.开启一个事务,通过调用beginTransaction方法开启。 3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。 4.提交事务,调用commit方法提交。 现在运行一下程序,效果如下图所示: 如果你是在使用模拟器运行,按下ctrl + F11切换到竖屏模式。效果如下图所示: Fragment的生命周期 和Activity一样,Fragment也有自己的生命周期,理解Fragment的生命周期非常重要,我们通过代码的方式来瞧一瞧Fragment的生命周期是什么样的: publicclassFragment1extendsFragment{ publicstaticfinalStringTAG="Fragment1"; @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){ Log.d(TAG,"onCreateView"); returninflater.inflate(R.layout.fragment1,container,false); } @Override publicvoidonAttach(Activityactivity){ super.onAttach(activity); Log.d(TAG,"onAttach"); } @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); Log.d(TAG,"onCreate"); } @Override publicvoidonActivityCreated(BundlesavedInstanceState){ super.onActivityCreated(savedInstanceState); Log.d(TAG,"onActivityCreated"); } @Override publicvoidonStart(){ super.onStart(); Log.d(TAG,"onStart"); } @Override publicvoidonResume(){ super.onResume(); Log.d(TAG,"onResume"); } @Override publicvoidonPause(){ super.onPause(); Log.d(TAG,"onPause"); } @Override publicvoidonStop(){ super.onStop(); Log.d(TAG,"onStop"); } @Override publicvoidonDestroyView(){ super.onDestroyView(); Log.d(TAG,"onDestroyView"); } @Override publicvoidonDestroy(){ super.onDestroy(); Log.d(TAG,"onDestroy"); } @Override publicvoidonDetach(){ super.onDetach(); Log.d(TAG,"onDetach"); } } 可以看到,上面的代码在每个生命周期的方法里都打印了日志,然后我们来运行一下程序,可以看到打印日志如下: 这时点击一下home键,打印日志如下: 如果你再重新进入进入程序,打印日志如下: 然后点击back键退出程序,打印日志如下: 看到这里,我相信大多数朋友已经非常明白了,因为这和Activity的生命周期太相似了。只是有几个Activity中没有的新方法,这里需要重点介绍一下: onAttach方法:Fragment和Activity建立关联的时候调用。 onCreateView方法:为Fragment加载布局时调用。 onActivityCreated方法:当Activity中的onCreate方法执行完后调用。 onDestroyView方法:Fragment中的布局被移除时调用。 onDetach方法:Fragment和Activity解除关联的时候调用。 Fragment之间进行通信 通常情况下,Activity都会包含多个Fragment,这时多个Fragment之间如何进行通信就是个非常重要的问题了。我们通过一个例子来看一下,如何在一个Fragment中去访问另一个Fragment的视图。 还是在第一节代码的基础上修改,首先打开fragment2.xml,在这个布局里面添加一个按钮: <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#ffff00"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Thisisfragment2" android:textColor="#000000" android:textSize="25sp"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Getfragment1text" /> </LinearLayout> 然后打开fragment1.xml,为TextView添加一个id: <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00"> <TextView android:id="@+id/fragment1_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Thisisfragment1" android:textColor="#000000" android:textSize="25sp"/> </LinearLayout> 接着打开Fragment2.java,添加onActivityCreated方法,并处理按钮的点击事件: publicclassFragment2extendsFragment{ @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){ returninflater.inflate(R.layout.fragment2,container,false); } @Override publicvoidonActivityCreated(BundlesavedInstanceState){ super.onActivityCreated(savedInstanceState); Buttonbutton=(Button)getActivity().findViewById(R.id.button); button.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ TextViewtextView=(TextView)getActivity().findViewById(R.id.fragment1_text); Toast.makeText(getActivity(),textView.getText(),Toast.LENGTH_LONG).show(); } }); } } 现在运行一下程序,并点击一下fragment2上的按钮,效果如下图所示: 我们可以看到,在fragment2中成功获取到了fragment1中的视图,并弹出Toast。这是怎么实现的呢?主要都是通过getActivity这个方法实现的。getActivity方法可以让Fragment获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图了。 好了,以上就是关于Fragment你所须知道的一切。如果想要切身体验一下Fragment的实战,请继续阅读Android手机平板两不误,使用Fragment实现兼容手机和平板的程序以及Android Fragment应用实战,使用碎片向ActivityGroup说再见 本文转自欢醉博客园博客,原文链接http://www.cnblogs.com/zhangs1986/p/3676372.html如需转载请自行联系原作者 欢醉

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

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等操作系统。

用户登录
用户注册