首页 文章 精选 留言 我的

精选列表

搜索[动态工作流],共10000篇文章
优秀的个人博客,低调大师

Eclipse Dirigible 4.4 发布,动态应用的集成开发环境

Dirigible 是一个云开发平台,提供开发工具和运行环境。它通过利用系统内编程模型和快速应用程序开发技术,支持按需应用程序的完整开发生命周期。 4.4版本更新内容如下: 特性 终端替换为 xterm.js 工作区可插入文件->新模板 模板中的主题 修复 消息处理程序修复 样式改进 次要修复 更新说明:https://www.dirigible.io/release/2020/04/04/news_new_release_4_4.html

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

[每日短篇] 23 - 动态给容器指定 Java 启动参数

在做 Java 程序容器化时都会遇到一个问题,ENTRYPOINT ["java", "$JAVA_OPTS", "-jar", ...] 这样的写法 $JAVA_OPTS 就是个字符串无法在运行时展开。为了不把参数硬编码到容器里,每次调整参数重新构建镜像,可以有多种方案,先介绍几种不够好的方案。 ENTRYPOINT java $JAVA_OPTS -jar ...,这种方式的问题是 java 不是容器主进程(至于为什么要保证 java 是主进程,又是一个话题,是容器化基本最佳实践之一); ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar ..."],这种写法其实等价于上面一种方式,上面一种方式在运行时就是以 /bin/sh -c "java $JAVA_OPTS -jar ..." 方式运行的,所以缺陷也是相同的; ENTRYPOINT ["entrypoint.sh"] 然后在脚本中启动 java,使用脚本对于需要在启动时做复杂操作的容器比较有用,但是对启动 java 来说未免小题大作,并且同样有 java 不是容器主进程的问题。 从 shell 角度出发,解决非主进程问题的方案是使用 exec 命令,exec 在启动其后参数中的指令时,不会创建子进程而是用指令进程替换自身,使指令进程占用自身的 PID(exec 其后的第一个指令替换了自身之后,后续的其它指令自然也不会被执行了)。于是上面 3 个方案可以改为 ENTRYPOINT exce java $JAVA_OPTS -jar ... ENTRYPOINT ["sh", "-c", "exce java $JAVA_OPTS -jar ..."] 脚本里写 exec java $JAVA_OPTS -jar ... 使用 exec 可以解决之前的问题,但是随之而来的问题是……丑,任何额外的命令都会破坏整洁,对于追求 clean code 的程序员来说 Dockerfile 也必须是整洁的。还好 java 是一个成熟的生态,其实本身提供了相应的环境变量 JDK_JAVA_OPTIONS 和 JAVA_TOOL_OPTIONS: JDK_JAVA_OPTIONS 是在 Java 9 引入的,java 程序启动时不需要在命令行指定就会自动读取的环境变量,它略微有些限制,主要是为了防止滥用不允许使用可能改变主类或者让主类不执行的参数,通常需要指定的内存、GC 等参数都可以使用。遇到不允许使用的参数时 java 会直接报错并退出,所以只要程序顺利启动就不用担心使用了不允许使用的参数。在这里指定的参数无法覆盖命令行的相同参数,需要锁定的配置可以直接指定在 ENTRYPOINT中。 JAVA_TOOL_OPTIONS 是存在很久的环境变量,这个环境变量同样不需要在命令行显式指定。它名字中的 TOOL 提示了除了 java 命令之外其它 java 工具命令例如 javac 之类的也会去读取这个变量的值。在这里指定的参数既不能覆盖命令行的相同参数,也不能覆盖 JDK_JAVA_OPTIONS 中的相同参数,优先级最低。 除此之外,还有各家专用的一些环境变量,比如 Oracle 家的 _JAVA_OPTIONS、IBM 家的 IBM_JAVA_OPTIONS,它们通常提供了覆盖命令行上相同参数的能力,但是环境变量名却不可移植,在 Xxx as Code 的时代并不是个好选择。 综上所述,可以得出这样的决策路径: Java 9 及以上(呃,话说现在还有 Java 9 以下?)的 java 命令使用 JDK_JAVA_OPTIONS CI/CD 或者打包工具之类的非 java 命令时使用 JAVA_TOOL_OPTIONS Java 9 以下(囧)的 java 命令使用 JAVA_TOOL_OPTIONS 极特殊情况下需要覆盖命令行上的参数时,先反思自己,再反思自己,最后找各家自己定义的环境变量 最后一个问题,看到这里可能会有疑问,设置环境变量会不会影响到其它 java 进程?如果遵循了容器化的最佳实践,那答案显然是不会,而且即使在主机上,要想多个进程间环境变量互不影响也是很简单的事情不是吗?

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

Android 中使用 dlib+opencv 实现动态人脸检测

1 概述 完成 Android 相机预览功能以后,在此基础上我使用 dlib 与 opencv 库做了一个关于人脸检测的 demo。该 demo 在相机预览过程中对人脸进行实时检测,并将检测到的人脸用矩形框描绘出来。具体实现原理如下: 采用双层 View,底层的 TextureView 用于预览,程序从 TextureView 中获取预览帧数据,然后调用 dlib 库对帧数据进行处理,最后将检测结果绘制在顶层的 SurfaceView 中。 2 项目配置 由于项目中用到了 dlib 与 opencv 库,因此需要对其进行配置。主要涉及到以下几个方面: 2.1 C++支持 在项目创建过程中依次选择 Include C++ Support、C++11、Exceptions Support ( -fexceptions )以及 Runtime Type Information Support ( -frtti ) 。最后生成的 build.gradle 文件如下: defaultConfig { applicationId "com.example.lightweh.facedetection" minSdkVersion 23 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { arguments "-DCMAKE_BUILD_TYPE=Release" cppFlags "-std=c++11 -frtti -fexceptions" } } } 其中,arguments 参数是后添加上去的,主要用于指定 CMake 的编译模式为 Release,因为在 Debug 模式下 dlib 库中相关算法的运行速度非常慢。前期如果需要调试 C++ 代码,可先将 arguments 参数注释。 2.2 dlib 与 opencv 下载 到dlib官网下载最新版本的源码,解压后将文件夹中的dlib目录复制到 Android Studio 工程的 cpp 目录下。 到 sourceforge 下载最新的 opencv-android 库,解压后将文件夹中的 native 目录同样复制到 Android Studio 工程的 cpp 目录下,并改名为 opencv。 2.3 CMakeLists 配置 在 CMakeLists 文件中,我们首先包含 dlib 的 cmake 文件,接下来添加 opencv 的 include 文件夹并引入 opencv 的 so 库,同时将 jni_common 目录中的文件及人脸检测相关文件添加至 native-lib 库中,最后进行链接。 # 设置native目录 set(NATIVE_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp) # 设置dlib include(${NATIVE_DIR}/dlib/cmake) # 设置opencv include文件夹 include_directories(${NATIVE_DIR}/opencv/jni/include) # 设置opencv的so库 add_library( libopencv_java3 SHARED IMPORTED) set_target_properties( libopencv_java3 PROPERTIES IMPORTED_LOCATION ${NATIVE_DIR}/opencv/libs/${ANDROID_ABI}/libopencv_java3.so) # 将jni_common目录中所有文件名,存至SRC_LIST中 AUX_SOURCE_DIRECTORY(${NATIVE_DIR}/jni_common SRC_LIST) add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). ${SRC_LIST} src/main/cpp/face_detector.h src/main/cpp/face_detector.cpp src/main/cpp/native-lib.cpp) find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log) target_link_libraries( # Specifies the target library. native-lib dlib libopencv_java3 jnigraphics # Links the target library to the log library # included in the NDK. ${log-lib}) # 指定release编译选项 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s -O3 -Wall") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s -O3 -Wall") 由于 C++ 代码中用到了头文件 "android/bitmap.h",所以链接时需要添加 jnigraphics 库。 3 JNI相关 Java 类定义 3.1 VisionDetRet 类 VisionDetRet 类的相关对象主要负责 C++ 与 Java 之间的数据传递。 public final class VisionDetRet { private int mLeft; private int mTop; private int mRight; private int mBottom; VisionDetRet() {} public VisionDetRet(int l, int t, int r, int b) { mLeft = l; mTop = t; mRight = r; mBottom = b; } public int getLeft() { return mLeft; } public int getTop() { return mTop; } public int getRight() { return mRight; } public int getBottom() { return mBottom; } } 3.2 FaceDet 类 FaceDet 类为 JNI 函数调用类,主要定义了一些需要 C++ 实现的 native 方法。 public class FaceDet { private static final String TAG = "FaceDet"; // accessed by native methods @SuppressWarnings("unused") private long mNativeFaceDetContext; static { try { // 预加载native方法库 System.loadLibrary("native-lib"); jniNativeClassInit(); Log.d(TAG, "jniNativeClassInit success"); } catch (UnsatisfiedLinkError e) { Log.e(TAG, "library not found"); } } public FaceDet() { jniInit(); } @Nullable @WorkerThread public List<VisionDetRet> detect(@NonNull Bitmap bitmap) { VisionDetRet[] detRets = jniBitmapDet(bitmap); return Arrays.asList(detRets); } @Override protected void finalize() throws Throwable { super.finalize(); release(); } public void release() { jniDeInit(); } @Keep private native static void jniNativeClassInit(); @Keep private synchronized native int jniInit(); @Keep private synchronized native int jniDeInit(); @Keep private synchronized native VisionDetRet[] jniBitmapDet(Bitmap bitmap); } 4 Native 方法实现 4.1 定义 VisionDetRet 类对应的 C++ 类 #include <jni.h> #define CLASSNAME_VISION_DET_RET "com/lightweh/dlib/VisionDetRet" #define CONSTSIG_VISION_DET_RET "()V" #define CLASSNAME_FACE_DET "com/lightweh/dlib/FaceDet" class JNI_VisionDetRet { public: JNI_VisionDetRet(JNIEnv *env) { // 查找VisionDetRet类信息 jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET); // 获取VisionDetRet类成员变量 jID_left = env->GetFieldID(detRetClass, "mLeft", "I"); jID_top = env->GetFieldID(detRetClass, "mTop", "I"); jID_right = env->GetFieldID(detRetClass, "mRight", "I"); jID_bottom = env->GetFieldID(detRetClass, "mBottom", "I"); } void setRect(JNIEnv *env, jobject &jDetRet, const int &left, const int &top, const int &right, const int &bottom) { // 设置VisionDetRet类对象jDetRet的成员变量值 env->SetIntField(jDetRet, jID_left, left); env->SetIntField(jDetRet, jID_top, top); env->SetIntField(jDetRet, jID_right, right); env->SetIntField(jDetRet, jID_bottom, bottom); } // 创建VisionDetRet类实例 static jobject createJObject(JNIEnv *env) { jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET); jmethodID mid = env->GetMethodID(detRetClass, "<init>", CONSTSIG_VISION_DET_RET); return env->NewObject(detRetClass, mid); } // 创建VisionDetRet类对象数组 static jobjectArray createJObjectArray(JNIEnv *env, const int &size) { jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET); return (jobjectArray) env->NewObjectArray(size, detRetClass, NULL); } private: jfieldID jID_left; jfieldID jID_top; jfieldID jID_right; jfieldID jID_bottom; }; 4.2 定义人脸检测类 人脸检测算法需要用大小位置不同的窗口在图像中进行滑动,然后判断窗口中是否存在人脸。本文采用的是 dlib 中的是HOG(histogram of oriented gradient)方法对人脸进行检测,其检测效果要好于 opencv。dlib 中同样提供了 CNN 方法来进行人脸检测,效果好于 HOG,不过需要使用 GPU 加速,不然程序运行会非常慢。 class FaceDetector { private: dlib::frontal_face_detector face_detector; std::vector<dlib::rectangle> det_rects; public: FaceDetector(); // 实现人脸检测算法 int Detect(const cv::Mat &image); // 返回检测结果 std::vector<dlib::rectangle> getDetResultRects(); }; FaceDetector::FaceDetector() { // 定义人脸检测器 face_detector = dlib::get_frontal_face_detector(); } int FaceDetector::Detect(const cv::Mat &image) { if (image.empty()) return 0; if (image.channels() == 1) { cv::cvtColor(image, image, CV_GRAY2BGR); } dlib::cv_image<dlib::bgr_pixel> dlib_image(image); det_rects.clear(); // 返回检测到的人脸矩形特征框 det_rects = face_detector(dlib_image); return det_rects.size(); } std::vector<dlib::rectangle> FaceDetector::getDetResultRects() { return det_rects; } 4.3 native 方法实现 JNI_VisionDetRet *g_pJNI_VisionDetRet; JavaVM *g_javaVM = NULL; // 该函数在加载本地库时被调用 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { g_javaVM = vm; JNIEnv *env; vm->GetEnv((void **) &env, JNI_VERSION_1_6); // 初始化 g_pJNI_VisionDetRet g_pJNI_VisionDetRet = new JNI_VisionDetRet(env); return JNI_VERSION_1_6; } // 该函数用于执行清理操作 void JNI_OnUnload(JavaVM *vm, void *reserved) { g_javaVM = NULL; delete g_pJNI_VisionDetRet; } namespace { #define JAVA_NULL 0 using DetPtr = FaceDetector *; // 用于存放人脸检测类对象的指针,关联Jave层对象与C++底层对象(相互对应) class JNI_FaceDet { public: JNI_FaceDet(JNIEnv *env) { jclass clazz = env->FindClass(CLASSNAME_FACE_DET); mNativeContext = env->GetFieldID(clazz, "mNativeFaceDetContext", "J"); env->DeleteLocalRef(clazz); } DetPtr getDetectorPtrFromJava(JNIEnv *env, jobject thiz) { DetPtr const p = (DetPtr) env->GetLongField(thiz, mNativeContext); return p; } void setDetectorPtrToJava(JNIEnv *env, jobject thiz, jlong ptr) { env->SetLongField(thiz, mNativeContext, ptr); } jfieldID mNativeContext; }; // Protect getting/setting and creating/deleting pointer between java/native std::mutex gLock; std::shared_ptr<JNI_FaceDet> getJNI_FaceDet(JNIEnv *env) { static std::once_flag sOnceInitflag; static std::shared_ptr<JNI_FaceDet> sJNI_FaceDet; std::call_once(sOnceInitflag, [env]() { sJNI_FaceDet = std::make_shared<JNI_FaceDet>(env); }); return sJNI_FaceDet; } // 从java对象获取它持有的c++对象指针 DetPtr const getDetPtr(JNIEnv *env, jobject thiz) { std::lock_guard<std::mutex> lock(gLock); return getJNI_FaceDet(env)->getDetectorPtrFromJava(env, thiz); } // The function to set a pointer to java and delete it if newPtr is empty // C++对象new以后,将指针转成long型返回给java对象持有 void setDetPtr(JNIEnv *env, jobject thiz, DetPtr newPtr) { std::lock_guard<std::mutex> lock(gLock); DetPtr oldPtr = getJNI_FaceDet(env)->getDetectorPtrFromJava(env, thiz); if (oldPtr != JAVA_NULL) { delete oldPtr; } getJNI_FaceDet(env)->setDetectorPtrToJava(env, thiz, (jlong) newPtr); } } // end unnamespace #ifdef __cplusplus extern "C" { #endif #define DLIB_FACE_JNI_METHOD(METHOD_NAME) Java_com_lightweh_dlib_FaceDet_##METHOD_NAME void JNIEXPORT DLIB_FACE_JNI_METHOD(jniNativeClassInit)(JNIEnv *env, jclass _this) {} // 生成需要返回的结果数组 jobjectArray getRecResult(JNIEnv *env, DetPtr faceDetector, const int &size) { // 根据检测到的人脸数创建相应大小的jobjectArray jobjectArray jDetRetArray = JNI_VisionDetRet::createJObjectArray(env, size); for (int i = 0; i < size; i++) { // 对检测到的每一个人脸创建对应的实例对象,然后插入数组 jobject jDetRet = JNI_VisionDetRet::createJObject(env); env->SetObjectArrayElement(jDetRetArray, i, jDetRet); dlib::rectangle rect = faceDetector->getDetResultRects()[i]; // 将人脸矩形框的值赋给对应的jobject实例对象 g_pJNI_VisionDetRet->setRect(env, jDetRet, rect.left(), rect.top(), rect.right(), rect.bottom()); } return jDetRetArray; } JNIEXPORT jobjectArray JNICALL DLIB_FACE_JNI_METHOD(jniBitmapDet)(JNIEnv *env, jobject thiz, jobject bitmap) { cv::Mat rgbaMat; cv::Mat bgrMat; jniutils::ConvertBitmapToRGBAMat(env, bitmap, rgbaMat, true); cv::cvtColor(rgbaMat, bgrMat, cv::COLOR_RGBA2BGR); // 获取人脸检测类指针 DetPtr mDetPtr = getDetPtr(env, thiz); // 调用人脸检测算法,返回检测到的人脸数 jint size = mDetPtr->Detect(bgrMat); // 返回检测结果 return getRecResult(env, mDetPtr, size); } jint JNIEXPORT JNICALL DLIB_FACE_JNI_METHOD(jniInit)(JNIEnv *env, jobject thiz) { DetPtr mDetPtr = new FaceDetector(); // 设置人脸检测类指针 setDetPtr(env, thiz, mDetPtr); return JNI_OK; } jint JNIEXPORT JNICALL DLIB_FACE_JNI_METHOD(jniDeInit)(JNIEnv *env, jobject thiz) { // 指针置0 setDetPtr(env, thiz, JAVA_NULL); return JNI_OK; } #ifdef __cplusplus } #endif 5 Java端调用人脸检测算法 在开启人脸检测之前,需要在相机 AutoFitTextureView 上覆盖一层自定义 BoundingBoxView 用于绘制检测到的人脸矩形框,该 View 的具体实现如下: public class BoundingBoxView extends SurfaceView implements SurfaceHolder.Callback { protected SurfaceHolder mSurfaceHolder; private Paint mPaint; private boolean mIsCreated; public BoundingBoxView(Context context, AttributeSet attrs) { super(context, attrs); mSurfaceHolder = getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT); setZOrderOnTop(true); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(5f); mPaint.setStyle(Paint.Style.STROKE); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mIsCreated = true; } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { mIsCreated = false; } public void setResults(List<VisionDetRet> detRets) { if (!mIsCreated) { return; } Canvas canvas = mSurfaceHolder.lockCanvas(); //清除掉上一次的画框。 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); canvas.drawColor(Color.TRANSPARENT); for (VisionDetRet detRet : detRets) { Rect rect = new Rect(detRet.getLeft(), detRet.getTop(), detRet.getRight(), detRet.getBottom()); canvas.drawRect(rect, mPaint); } mSurfaceHolder.unlockCanvasAndPost(canvas); } } 同时,需要在布局文件中添加对应的 BoundingBoxView 层,保证与 AutoFitTextureView 完全重合: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CameraFragment"> <com.lightweh.facedetection.AutoFitTextureView android:id="@+id/textureView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <com.lightweh.facedetection.BoundingBoxView android:id="@+id/boundingBoxView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/textureView" android:layout_alignTop="@+id/textureView" android:layout_alignRight="@+id/textureView" android:layout_alignBottom="@+id/textureView" /> </RelativeLayout> BoundingBoxView 添加完成以后,即可在 CameraFragment 中添加对应的人脸检测代码: private class detectAsync extends AsyncTask<Bitmap, Void, List<VisionDetRet>> { @Override protected void onPreExecute() { mIsDetecting = true; super.onPreExecute(); } protected List<VisionDetRet> doInBackground(Bitmap... bp) { List<VisionDetRet> results; // 返回检测结果 results = mFaceDet.detect(bp[0]); return results; } protected void onPostExecute(List<VisionDetRet> results) { // 绘制检测到的人脸矩形框 mBoundingBoxView.setResults(results); mIsDetecting = false; } } 然后,分别在 onResume 与 onPause 函数中完成人脸检测类对象的初始化和释放: @Override public void onResume() { super.onResume(); startBackgroundThread(); mFaceDet = new FaceDet(); if (mTextureView.isAvailable()) { openCamera(mTextureView.getWidth(), mTextureView.getHeight()); } else { mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); } } @Override public void onPause() { closeCamera(); stopBackgroundThread(); if (mFaceDet != null) { mFaceDet.release(); } super.onPause(); } 最后,在 TextureView 的回调函数 onSurfaceTextureUpdated 完成调用: @Override public void onSurfaceTextureUpdated(SurfaceTexture texture) { if (!mIsDetecting) { Bitmap bp = mTextureView.getBitmap(); // 保证图片方向与预览方向一致 bp = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), mTextureView.getTransform(null), true ); new detectAsync().execute(bp); } } 6 测试结果 经测试,960x720的 bitmap 图片在华为手机(Android 6.0,8核1.2GHz,2G内存)上执行一次检测约耗时800~850ms。Demo 运行效果如下: 更多Android进阶技术,面试资料系统整理分享,职业生涯规划,产品,思维,行业观察,谈天说地。可以加Android架构师群;701740775。

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

jQuery圆形滚动进度条动态加载loading效果

2017年12月13日 可以随时停止进度,需要计算时间清除定时器 .loading .wrap, .loading .circle, .loading .percent { position: absolute; width: 200px; height: 200px; border-radius: 50%; } .loading .wrap { top: 150px; left: 50%; margin-left: -100px; background-color: #ccc; } .loading .circle { box-sizing: border-box; border: 10px solid #ccc; clip: rect(0, 200px, 200px, 100px); } .loading .clip-auto { clip: rect(auto, auto, auto, auto); } .loading .percent { box-sizing: border-box; top: -10px; left: -10px; } .loading .left { transition: transform ease; border: 10px solid #51abe5; clip: rect(0, 100px, 200px, 0); } .loading .right { border: 10px solid #51abe5; clip: rect(0, 200px, 200px, 100px); } .loading .nothing { width: 0; } .loading .num { z-index: 1; position: absolute; left: 10px; top: 10px; width: 180px; height: 180px; color: #fff; line-height: 180px; text-align: center; font-size: 40px; border-radius: 50%; /*background-color: #fff;*/ background: #2b9cdb; box-sizing: border-box; } <div class="wrap"> <div class="circle"> <div class="percent left"></div> <div class="percent right nothing"></div> </div> <div class="num"><span class="export">0</span>%</div> </div> var percent = 0; //初始化百分比 var rcent = 100; //需要显示的百分比 var loading = setInterval(function() { if(percent > 100) { percent = 0; $('.circle').removeClass('clip-auto'); $('.right').addClass('nothing'); } else if(percent > 50) { $('.circle').addClass('clip-auto'); $('.right').removeClass('nothing'); } $('.left').css("-webkit-transform", "rotate(" + (18 / 5) * percent + "deg)"); $('.export').text(percent); if(percent == rcent) { //加载完成 clearInterval(loading); } else { percent++; } }, 50);

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

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文件系统,支持十年生命周期更新。

WebStorm

WebStorm

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

用户登录
用户注册