针对 性解决npm ERR! cb() never called! 问题

在开发项目安装依赖时(npm install) 往往会报 npm ERR! cb()never called!的错误 如图: 解决方法: 一、首先要以管理员模式打开cmd清除你的npm缓存 : npm cache clean -f 二、清除完缓存后,安装最新版本的Node helper: npm install -g n 注意:如果出现npm ERR! notsup Unsupported platform for n@2.1.8: wanted {"os":"!win32","arch":"any"} (current: {"os":"win32","arch":"x64"}) 这样错误信息 如图: 然后执行以下 npm install -g n --force 如图: 三、告诉助手(n)安装最新的稳定版Node:n stable 四、完成上一个命令后,您将获得最新信息。让我们再次运行安装: npm install 如果在执行npm install 非常缓慢的时候,可以试着更换镜像 npm install -g cnpm --registry=https://registry.npm.taobao.org 如图: 再执行 cnpm install,这时候就比较快一些安装依赖文件 安装完依赖文件后,执行 cnpm run dev ,项目就启动了。 以上是开发遇到的一个小问题,如有不足可以随时提出。谢谢

stm32毕设分享100例(一)

【单片机毕业设计项目分享系列】 🔥 这里是DD学长,单片机毕业设计及享100例系列的第一篇,目的是分享高质量的毕设作品给大家,包含全面内容:源码+原理图+PCB+实物演示+论文。 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的单片机项目缺少创新和亮点,往往达不到毕业答辩的要求,为此学长准备了相对容易且工作量达标,并包含创新点的项目分享给大家。 🧿 整理的题目标准: 相对容易工作量达标题目新颖,含创新点 🧿 项目分享: https://gitee.com/sinonfin/sharing 课题项目1 : stm32单片机老人健康及跌倒检测系统 可检测温度(ds18b20模拟),心率,血氧和是否摔倒,GPS定位,屏幕显示,手机短信提示,蓝牙连接手机,可以自己设置单片机的联系手机号,检测数据异常,会给手机发送消息提示,单片机也会发出声响,提醒周围人 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目2:stm32智能平衡小车 (1) 直立控制功能:车模的倾角作为控制的输入量,使用PD算法,控制车模稳定在平衡位置。 (2) 速度控制功能:直立车模的速度控制与普通的车模速度控制不同,在直立系统中,速度控制是通过改变车模倾角来完成的。具体实施思路是,对电机转速加入干扰,使车身偏离平衡位置,以此刺激直立控制任务,从而达到控制速度的目的,速度控制使用PI算法。 (3) 方向控制功能:通过控制两个电机的差速来达到转向的目的,方向控制使用PD算法,使用X轴的角速度作为微分项的因子,可以极大改善转向的动态性能,避免振荡。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目3:基于stm32与openmv的目标跟踪系统 1.通过OpenMV识别出被测物体(以红色小球为例)。 2.在OpenMV识别出目标物体后,判断物体所在区域,将区域信息通过串口传输给STM32。 3.利用STM32的串口部分的应用及原理知识,对接收到的数据进行处理。 4.利用STM32的应用及原理知识,对处理好的数据进行判断后,对舵机进行控制。 5.利用STM32的定时器部分和PWM控制的应用及原理知识,控制舵机,使其转动适当角度,使OpenMV对准目标物体。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目4:基于STM32与wifi的天气预报网时钟系统 1)实时温度显示; 2)年月日星期时分秒显示; 3)年月日星期时分秒调整; 4)闹钟定时小时分钟和秒; 5)数据外部联网; 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目5:stm32的RFID与指纹识别的门禁系统 数据采集模块、 存储模块、 显示模块、 门控模块、 警报模块、 键盘模块和上位机软件的设计几个方面。 数据采集模块: 读卡器 YHY502ATG 通过天线读取 RFID 卡的数据,然后将数据传送出去。 存储模块: AT89C52 接收到数据后, 将数据传送给 AT24C04 进行存储。 显示模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若两者完全相同, 则液晶显示正确的信息; 若不相同, 则液晶显示错误的信息。 门控模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若两者完全相同, 则进行开门操作; 若不相同, 则不开门。 警报模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若不相同则报警。 键盘模块: 通过键盘输入密码, 并根据输入密码的有效性做相应的操作。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档

git命令(新建分支,并拉取远程分支代码)报错“xxx” does not appear to be a git repository

#查看远程分支 git branch -r #查看本地分支 git branch #拉取本地分支 git checkout -b 本地分支 #拉取远程分支 git pull origin 远程分支 #创建并切换到新分支 git checkout -b panda #拉取分支 git pull #遇到本地冲突,先删除本地分支,再重新拉取远程分支 git branch -D 本地分支名称 #合并yan分支(dev分支需要yan分支代码) git merge yan 新建一个分支之后,需要做的(或者报错“xxx” does not appear to be a git repository) git remote -v: 查看远程仓库详细信息,可以看到仓库名称,关联地址 git remote remove orign:删除orign仓库(比如名称错误) 例子:git remote remove orign https://gitee.com/ois-web.git git remote add origin 仓库地址:重新添加远程仓库地址 gti push -u origin master: 提交到远程仓库的master主干

C# Winform应用程序重启

重启应用程序我们有两种方法: 一、Restart方法 System.Windows.Forms.Application.Restart(); 经测试发现有时候只会关闭程序,并不会重新启动 二、Process.Start()和Exit() System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location); Application.Exit(); 经测试发现有时候也只会关闭程序,并不会重新启动 三、进程的Start和Kill方法 System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location); System.Diagnostics.Process.GetCurrentProcess().Kill(); 经测试使用进程进行重启比较稳定。 //开启新的实例 System.Diagnostics.Process.Start(Application.ExecutablePath); //关闭当前实例 System.Diagnostics.Process.GetCurrentProcess().Kill(); Application.Exit();//退出当前项目,如果是子项目,则不会停止主项目 System.Environment.Exit(0);//停止所有项目 四:使用Process方式 Process p = new Process(); p.StartInfo.FileName = System.AppDomain.CurrentDomain.BaseDirectory + “xxx.exe”; p.StartInfo.UseShellExecute = false; p.Start(); Application.Current.Shutdown(); 未测试。 带参数重启 Process proc = new Process(); proc.StartInfo.FileName = @"MyExecutable.exe"; proc.StartInfo.Arguments = "\"C:\\My Docs\\SomeDirectory\\MyXMLPath.xml\""; proc.Start();

Linux机器内核参数理解(一)

一、fs.aio-nr & fs.aio-max-nr aio-nr is the running total of the number of events specified on the io_setup system call for all currently active aio contexts. If aio-nr reaches aio-max-nr then io_setup will fail with EAGAIN. Note that raising aio-max-nr does not result in the pre-allocation or re-sizing of any kernel data structures. aio-nr shows the current system-wide number of asynchronous io requests. aio-max-nr allows you to change the maximum value aio-nr can grow to.

AppCompatTextView文本设置为大写

如果你想让AppCompatTextView的文本全是大写,可以使用android:textAllCaps属性。将其设置为true即可。 例如: <androidx.appcompat.widget.AppCompatTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:textAllCaps="true" /> 这将使得AppCompatTextView显示的文本全部转化为大写。

shell查看进程指令

目录 ps aux elf top pstree -aup 进程是在 CPU 及内存中运行的程序代码,而每个进程可以创建一个或多个进程(父子进程)。 方法: 1、ps aux 2、ps -elf ps Linux 中的 ps 命令是 Process Status 的缩写。 ps 命令是最基本同时也是非常强大的进程查看命令。 ps 命令用来列出系统中当前运行的那些进程。 ps 命令列出的是当前那些进程的 快照,就是执行 ps 命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用 top 命令。 ps 命令用于报告当前系统中的进程状态,可以搭配 kill 指令随时中断、删除不必要的程序。 使用 ps 命令可以确定有哪些进程正在运行,以及运行的状态、进程是否结束、进程有没有僵死 ( z )、哪些进程占用了过多的资源(cpu 和内存)等等,总之大部分信息都是可以通过执行该命令得到的。 aux ps 指令有很多的参数,不同的参数的功能不同: ps aux 是以简单列表的形式显示出进程信息, 选项含义a显示当前终端下的所有进程信息,包括其他用户的进程。u 使用以用户为主的格式输出进程信息,user 为第一列; 如果没有 u 参数,则 PID 是第一列。 x显示当前用户在所有终端下的进程。 ps aux 命令的输出如下所示: 以上信息的字段的含义解释如下: 字段 含义USER 启动该进程的用户账号名称。 因为一台服务器可以有很多用户,每个用户都可以启动进程。 PID该进程的 ID 号,在当前系统中是唯一的。需要杀死进程的时候,就是 kill pid 命令杀死进程。%CPUCPU 占用的百分比。可以超过 100,因为 linux 系统一般都是多核心的。如果是 10 个核心,那总共就是 1000%。%MEM内存占用的百分比VSZ占用虚拟内存(swap空间)的大小。VSZ 表示如果一个程序完全驻留在内存的话需要占用多少内存空间;RSS占用常驻内存(物理内存)的大小。RSS 指明了当前实际占用了多少内存;TTY该进程在哪个终端上运行。?

SpringBoot启动控制台的banner是怎么回事

前言 每次启动SpringBoot项目时,总是能看到控制台打印了一串字符,隐约能辨认出是“Spring”,不知大家是否也好奇过是怎么实现的,是直接打印固定的字符串,还是根据什么算法去生成的?于是闲暇无事,探究一番。 只想修改banner可以跳到文末查看 SpringBoot是怎么打印的 Banner默认实现类 SpringBootBanner 1、根据控制台打印的字符进行全局搜索,笔者选取:: Spring Boot ::进行搜索,定位到了org.springframework.boot.SpringBootBanner。 IDEA全局搜索:CTRL + SHIFT + R 2、进入SpringBootBanner类,先看下注释Default Banner implementation which writes the 'Spring' banner.,说了两个信息:1、当前类是SpringBoot Banner的默认实现;2、打印的字符是“Spring”。 3、往下看,SpringBootBanner实现了Banner接口。Banner包括printBanner方法和枚举Mode。 根据Mode中的注释和枚举值可以看出,Banner有三种状态:关闭、打印到控制台、打印到日志。具体使用场景留待后续分析。 Banner源码 /** * Interface class for writing a banner programmatically. */ @FunctionalInterface public interface Banner { /** * Print the banner to the specified print stream. * @param environment the spring environment * @param sourceClass the source class for the application * @param out the output print stream */ void printBanner(Environment environment, Class<?

【华为云-玩转云耀云服务器HECS】使用HECS搭建WordPress博客平台

华为云-云耀云服务器(Hyper Elastic Cloud Server,HECS)是可以快速搭建简单应用的新一代云服务器,具备独立、完整的操作系统和网络功能,适用于网站搭建、开发环境等低负载应用场景。本文讲解如何使用HECS搭建WordPress博客平台。 文章目录 一、购买云服务1. 购买HECS2. 产品试用 二、项目实战概况三、搭建LNMP应用运行环境1. 安装Nginx1.1 配置yum源1.2 启动并进行测试 2. 安装MySQL2.1 下载并安装2.2 启动并设置密码 3. 安装PHP3.1 添加源并安装3.2 启动php-fpm服务 4. 启用PHP支持4.1 编辑配置文件4.2 测试LNMP的PHP支持 5. 数据库设置 四、安装并配置WordPress1. 下载并上传软件包1.1 下载英文版本并上传1.2 下载中文版本并上传 2. 解压软件包3. 移动目录并设置权限4. 配置WordPress配置文件4.1 复制模板文件4.2 编辑WordPress的配置文件 5. 安装WordPress6. 登录管理后台7. 查看主页8. 插件安装 五、总结 一、购买云服务 WordPress 博客平台需要部署到服务器上,所以需要购买一台ECS,再将服务部署上去。例如我们可以去主页购买HECS或者去领取产品试用名额来进行搭建。 1. 购买HECS 在华为云官网 按照产品→计算→云耀云服务器 HECS 路径,即可进入云耀云服务器 HECS主页面。 点击立即购买按钮 ,进入选购 HECS 详细配置页面。 之后就可以根据具体需求进行选择购买。 具体指引和操作可参考官方产品文档:https://support.huaweicloud.com/hecs/index.html 2. 产品试用 这段时间在官方开发者试用专区就有HECS的产品试用,感兴趣的小伙伴也可以到产品试用专区进行体验。具体操作如下: ①点击此处进入页面后点击“前往开发者试用专区”。 ②点击热门推荐,选择HECS免费试用。不过由于产品试用火爆,需要尽快领取,若错过时间,需要到下一天的9:30后进行领取,领完即止。 ③进行产品体验后即可体验产品的试用。 二、项目实战概况 项目名称:WordPress 官网地址:https://wordpress.org 项目简介:WordPress是一款个人博客系统,也可以把 WordPress当作一个内容管理系统(CMS)来使用,它是使用PHP语言和MySQL数据库 开发的,用户可以在支持PHP和MySQL数据库的服务器上使用自己的博客。

acwing 1050. 鸣人的影分身

acwing 1050. 鸣人的影分身 思路: 代码: #include <iostream> #include <algorithm> using namespace std; const int N = 25; int m, n; int t, res; int f(int a, int b) { if (a == 0) // 火影的能量值分完了 -- 》表示该方法可行---> 记录为一条通路 return 1; if (b == 0) // 如果火影的能量值有剩余,但是火影需要分配的人数已经分完了-- 》 说明这条路不通 return 0; if (a < b) // 火影的能量值完全不能满足的时候,那么100%需要有人能量值为0 { return f(a, a); // 那么我就不考虑多出来的了 } else { return f(a - b, b) + f(a, b - 1); // 火影的能量值可以满足的时候,只需要考虑剩下的人,有没有为0的情况 } } int main() { cin >> t; while (t--) { cin >> m >> n; res = f(m, n); cout << res << endl; } }

js 中的引用类型(内置对象)

前言 本篇笔记的目标是深刻理解引用类型的概念、理解基本的 JavaScript 类型、了解基本类型的方法和使用基本包装类型。需要了解每种引用类型的详细介绍可以查阅 MDN 文档。其他相关笔记还有如下几篇: JavaScript 基础(超详细)js 中的引用类型(内置对象)js 中的对象属性——configurable、writable 等(数据属性和访问器属性)js 中原型、原型链和继承概念(详细全面)函数使用进阶——递归——闭包 目录 前言1. 引用类型概述2. Object 类型2.1 创建 Object 实例2.2 访问实例对象属性2.3 常用属性和方法 3. Array 类型3.1 创建数组和访问数组元素3.2 Array 具有的方法3.2 Array 实例具有的方法3.2.1 转换方法3.2.1 栈方法(push 和 pop)3.2.2 队列方法(shift() 和 unshift())3.2.3 重排序方法3.2.4 操作方法3.2.5 位置方法3.2.6 迭代方法(重要)3.2.7 归并方法3.2.8 数组去重3.2.9 ES6新增方法 4. Date 类型4.1 Date 实例化4.1.1 实例化时的参数4.1.2 Date.now() 和 +new Date()4.1.3 月份传参注意问题 4.2 常用方法4.2.1 常用方法介绍4.2.2 倒计时案例 5. RegExp 类型5.1 正则表达式的创建和检测5.1.1 创建5.1.2 测试正则表达式 test5.1.2 replace() 5.2 正则表达式的组成5.2.1 正则表达式的模式5.

数组不赋初值,那么你将会面临以下麻烦

今天在写桶排序的时候,意外发现我的数据得不到正确结果 起先我这样写了一个桶排数组: int a[MAX]; codeblocks调试数组内存是这样的 (大量的随机数,页地址浪费内存,且有脏数据) 然后我将其赋初值 int a[MAX]={0}; 期初其初始化也是和上面一样,但是赋初值之后就变成只有0的下标的数据了 所以大家平时一定要给数组赋初值 或者将其写在main函数外面!!!!

【C++学习笔记】:对象指针

C++指向对象的指针 C++建立对象时,编译系统会为每一个对象分配一定存储空间,让存放其成员。对象空间的起始地址就是对象的指针,可以定义一个指针变量,用来存放对象的指针。 定义指向类对象的指针变量的一般形式为 类名 * 对象指针名; 可以通过对象指针访问对象和对象的成员 C++指向对象成员的指针 在C++中,对象是有地址的,存放对象初始地址的指针变量就是指向对象的指针变量,对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。 1、指向对象数据成员的指针 定义指向对象数据成员的指针变量的方法和定义指向普通变量的指针变量方法相同。 数据的指针变量 定义指向对象数据成员的指针变量的一般形式为 数据类型名 *指针变量名; 2、指向对象成员函数的指针 C++定义指向对象成员函数的指针变量的方法,与定义指向普通函数的指针变量方法有所不同。 成员函数与普通函数有一个最大的区别:成员函数是类中的一个成员。 定义指向公用成员函数的指针变量的一般形式为 数据类型名 (类名∷*指针变量名)(参数表列); 指针变量指向一个公用成员函数的一般形式为 指针变量名=&类名∷成员函数名; 案例:C++对象指针的使用 #include <iostream> using namespace std; class Time { public:Time(int,int,int); int hour,minute,second; void getTime(); //声明成员函数 }; Time::Time(int h,int m,int s) { hour=h; minute=m; second=s; } void Time::getTime()//定义成员函数 { cout<<hour<<"点"<<minute<<"分"<<second<<"秒"<<endl; } int main( )// 程序的主函数 { Time time(20,22,45); //定义Time类对象time time.getTime(); //调用函数 // 定义指向整型数据的指针变量point,并指向time.hour int *point=&time.hour; cout<<*point<<endl; return 0;

Python+Opencv颜色和形状检测

目录 一、场景需求解读二、算法原理简介三、算法实现步骤四、算法代码实现五、算法效果展示与分析参考资料注意事项 一、场景需求解读 现实场景中,我们有时需要自动的检测出图片中目标的颜色和其对应的形状,然后根据这些信息快速的找到我们需要的目标,这在真实场景中具有广泛的应用。下图展示了一张实例,我们需要知道图片中目标的颜色和形状信息。 二、算法原理简介 为了检测不同物体的颜色,本文的实现思路为:1)首先定义一个颜色标签类,该类中包含一个颜色字典,包含了需要的所有颜色;2)然后针对每一个轮廓(mask),计算当前lab*颜色值与图像平均值之间的距离;3)最终选择最小距离所代表的颜色值。 为了检测不同物体的形状,本文的实现思路为:1)首先对输入图片执行预处理;2)然后对预处理之后的图片执行二值化;3)接着进行轮廓检测,并根据顶点的个数进行形状的判断。 三、算法实现步骤 步骤1-读取输入图片; 步骤2-对输入图片执行裁剪操作; 步骤3-执行高斯模糊操作,进行图像去噪; 步骤4-执行图像灰度化操作; 步骤5-执行颜色空间变换,将RGB空间转换为LAB空间; 步骤6-执行二值化操作; 步骤7-遍历每一个轮廓,进行颜色和形状检测; 步骤8-绘制并显示结果。 四、算法代码实现 1、创建一个颜色标签类 # coding=utf-8 # 导入一些python包 from scipy.spatial import distance as dist from collections import OrderedDict import numpy as np import cv2 # 创建一个颜色标签类 class ColorLabeler: def __init__(self): # 初始化一个颜色词典 colors = OrderedDict({ "red": (255, 0, 0), "green": (0, 255, 0), "blue": (0, 0, 255)}) # 为LAB图像分配空间 self.lab = np.zeros((len(colors), 1, 3), dtype="uint8") self.

Python+Opencv测量物体之间的距离

目录 一、场景需求解读二、算法原理简介三、算法实现步骤四、算法代码实现五、算法效果展示与分析参考资料注意事项 一、场景需求解读 在现实场景中,我们可能会遇到这个问题,即需要自动的测量图像中的不同目标之间的距离。通过这个测量,我们可以明确的知道图像中各个目标的位置以及各个目标之间的距离,便于我们做出合理的规划。本文是在该博客的基础上面进行拓展而来的。下图展示了一个样例图片,即图中最左边的是我们的参考目标,我们需要做的就是自动的确定当前的参考目标和其它对象之间的距离。 二、算法原理简介 整个算法的核心是根据参考目标的实际距离和欧式距离计算出相应的像素比。首先需要进行一系列的像素预处理操作,包括灰度变换,高斯滤波,边缘检测等;然后使用轮廓检测算法获取到图中的参考目标和其它目标;最后将像素比分别应用在参考目标和其它目标之间的4个顶点和中心点上面。 三、算法实现步骤 步骤1-读取输入图片; 步骤2-执行灰度变换; 步骤3-进行高斯滤波去除一部分噪声; 步骤4-执行Canny边缘检测来获取目标的边缘映射,并使用膨胀和腐蚀操作来进行后处理; 步骤5-在边缘映射中寻找合适的轮廓; 步骤6-计算轮廓的外接矩形,并对轮廓进行排序; 步骤7-根据参考目标和实际距离的大小来计算出像素比; 步骤8-根据参考目标和其它目标之间的坐标信息计算并显示结果。 四、算法代码实现 # coding=utf-8 # 导入相应的pthon包 from scipy.spatial import distance as dist from imutils import perspective from imutils import contours import numpy as np import argparse import imutils import cv2 # 计算中心点函数 def midpoint(ptA, ptB): return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5) # 进行参数配置和解析 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to the input image"

CenterNet算法详解

Objects as Points-论文链接-代码链接 目录 1、需求解读2、CenterNet算法简介3、CenterNet算法详解3.1 CenterNet网络结构3.2 CenterNet实现细节详解3.2.1 训练阶段Heatmap生成3.2.2 Heatmap上应用高斯核 3.3 CenterNet损失函数3.3.1 Heatmap损失函数3.3.2 中心点偏移损失函数3.3.3 目标长宽损失函数 3.4 CenterNet推理阶段 4、CenterNet网络代码实现5、CenterNet效果展示与分析5.1 CenterNet客观效果展示与分析5.2 CenterNet主观效果展示与分析 6、总结与分析参考资料注意事项 1、需求解读 随着基于Anchor的目标检测性能达到了极限,基于Anchor-free的目标检测算法成为了当前的研究热点,具有代表性的工作包括CornerNet、FOCS与CenterNet等。除此之外,基于Anchor的目标检测算法存在着一些严重的问题,具体包括:(1)Anchros的定义在一定程度上会限制检测算法的性能;(2)NMS等后处理操作会降低整个检测算法的速度。为了解决这些问题,基于Anchor-free的目标检测算法应运而生,本文对CenterNet目标检测算法进行详细的剖析。 2、CenterNet算法简介 CenterNet是一个基于Anchor-free的目标检测算法,该算法是在CornerNet算法的基础上改进而来的。与单阶段目标检测算法yolov3相比,该算法在保证速度的前提下,精度提升了4个百分点。与其它的单阶段或者双阶段目标检测算法相比,该算法具有以下的优势: (1)该算法去除低效复杂的Anchors操作,进一步提升了检测算法性能;(2)该算法直接在heatmap图上面执行了过滤操作,去除了耗时的NMS后处理操作,进一步提升了整个算法的运行速度;(3)该算法不仅可以应用到2D目标检测中,经过简单的改变它还可以应用3D目标检测与人体关键点检测等其它的任务中,即具有很好的通用性。 3、CenterNet算法详解 3.1 CenterNet网络结构 上图展示了CenterNet网络的整体结构,整个网络结构比较简单。 (1)最左边表示输入图片。输入图片需要裁减到512*512大小,即长边缩放到512,短边补0,具体的效果如下图所示,由于原图的W>512,因而直接将其缩放为512;由于原图的H<512,因而对其执行补0操作; (2)中间表示基准网络,论文中尝试了Hourglass、ResNet与DLA3种网络架构,各个网络架构的精度及帧率为:Resnet-18 with up-convolutional layers:28.1% coco and 142 FPS、DLA-34:37.4% COCOAP and 52 FPS、Hourglass-104:45.1% COCOAP and 1.4 FPS。 上图展示了3中不同的网络架构,图(a)表示Hourglass网络,该网络是在ECCV2016中的Stacked hourglass networks for human pose estimation论文中提出的一种网络,用来解决人体位姿估计问题,其思路主要通过将多个漏斗形状的网络堆叠起来,从而获得多尺度信息,具体的细节请参考该博客。图(b)表示带有反卷积的ResNet网络,作者在每一个上采样层之前增加了一个3*3的膨胀卷积,即先使用反卷积来改变膨胀卷积的通道个数,然后使用反卷积来对特征映射执行上采样操作。图©表示用于语义分割的DLA34网络;图d表示改变的DLA34网络,该网络在原始的DLA34网络的基础上增加了更多的残差连接,该网络将Dense_Connection与FPN的思路融合起来,前者源于DenseNet,可以用来聚合语义信息,能够提升模型推断是“what”的能力;后者源于聚合空间信息,能够提升模型推断在“where”的能力,具体的细节如下图所示。 (3)最右边表示预测模块,该模块包含3个分支,具体包括中心点heatmap图分支、中心点offset分支、目标大小分支。heatmap图分支包含C个通道,每一个通道包含一个类别,heatmap中白色的亮区域表示目标的中心 点位置;中心点offset分支用来弥补将池化后的低heatmap上的点映射到原图中所带来的像素误差;目标大小分支用来预测目标矩形框的w与h偏差值。 3.2 CenterNet实现细节详解 3.2.1 训练阶段Heatmap生成 CenterNet将目标检测问题转换成中心点预测问题,即用目标的中心点来表示该目标,并通过预测目标中心点的偏移量与宽高来获取目标的矩形框。Heatmap表示分类信息,每一个类别将会产生一个单独的Heatmap图。对于每张Heatmap图而言,当某个坐标处包含目标的中心点时,则会在该目标处产生一个关键点,我们利用高斯圆来表示整个关键点,下图展示了具体的细节。 生成Heatmap图的具体步骤如下所示: 步骤1-将输入的图片缩放成512*512大小,对该图像执行R=4的下采样操作之后,获得一个128*128大小的Heatmap图; 步骤2-将输入图片中的Box缩放到128*128大小的Heatmap图上面,计算该Box的中心点坐标,并执行向下取整操作,并将其定义为point; 步骤3-根据目标Box大小来计算高斯圆的半径R; 关于高斯圆的半径确定,主要还是依赖于目标box的宽高, 实际情况下通常会取IOU=0.7,即下图中的overlap=0.7作为临界值,然后分别计算出三种情况的半径,取最小值作为高斯核的半径R,具体的实现细节如下图所示: (1)情况1-预测框pred_bbox包含gt_bbox框,对应于下图中的第1种情况,将整个IoU公式展开之后,成为一个二元一次方程的求解问题。 (2)情况2-gt_bbox包含预测框pred_bbox框,对应于下图中的第2种情况,将整个IoU公式展开之后,成为一个二元一次方程的求解问题。 (3)情况3-gt_bbox与预测框pred_bbox框相互重叠,对应于下图中的第3种情况,将整个IoU公式展开之后,成为一个二元一次方程的求解问题。

YOLOv4算法详解

YOLOv4: Optimal Speed and Accuracy of Object Detection-论文链接-代码链接 目录 1、需求解读2、YOLOv4算法简介3、YOLOv4算法详解3.1 YOLOv4网络架构3.2 YOLOv4实现细节详解3.2.1 YOLOv4基础组件3.2.2 输入端细节详解3.2.3 基准网络细节详解3.2.3 Neck网络细节详解3.2.4 Head网络细节详解 4、YOLOv4代码实现5、YOLOv4效果展示与分析5.1、YOLOv4主观效果展示与分析5.2、YOLOv4客观效果展示与分析 6、总结与分析参考资料注意事项 1、需求解读 作为一种经典的单阶段目标检测框架,YOLO系列的目标检测算法得到了学术界与工业界们的广泛关注。由于YOLO系列属于单阶段目标检测,因而具有较快的推理速度,能够更好的满足现实场景的需求。随着YOLOv3算法的出现,使得YOLO系列的检测算达到了高潮。YOLOv4则是在YOLOv3算法的基础上增加了很多实用的技巧,使得它的速度与精度都得到了极大的提升,本文将对YOLOv4算法的细节进行分析。 2、YOLOv4算法简介 YOLOv4是一种单阶段目标检测算法,该算法在YOLOv3的基础上添加了一些新的改进思路,使得其速度与精度都得到了极大的性能提升。主要的改进思路如下所示: 输入端:在模型训练阶段,做了一些改进操作,主要包括Mosaic数据增强、cmBN、SAT自对抗训练;BackBone基准网络:融合其它检测算法中的一些新思路,主要包括:CSPDarknet53、Mish激活函数、Dropblock;Neck中间层:目标检测网络在BackBone与最后的Head输出层之间往往会插入一些层,Yolov4中添加了SPP模块、FPN+PAN结构;Head输出层:输出层的锚框机制与YOLOv3相同,主要改进的是训练时的损失函数CIOU_Loss,以及预测框筛选的DIOU_nms。 3、YOLOv4算法详解 3.1 YOLOv4网络架构 上图展示了YOLOv4目标检测算法的整体框图。对于一个目标检测算法而言,我们通常可以将其划分为4个通用的模块,具体包括:输入端、基准网络、Neck网络与Head输出端,对应于上图中的4个红色模块。 输入端-输入端表示输入的图片。该网络的输入图像大小为608*608,该阶段通常包含一个图像预处理阶段,即将输入图像缩放到网络的输入大小,并进行归一化等操作。在网络训练阶段,YOLOv4使用Mosaic数据增强操作提升了模型的训练速度和网络的精度;利用cmBN及SAT自对抗训练来提升网络的泛化性能;基准网络-基准网络通常是一些性能优异的分类器种的网络,该模块用来提取一些通用的特征表示。YOLOv4中使用了CSPDarknet53作为基准网络;利用Mish激活函数代替原始的RELU激活函数;并在该模块中增加了Dropblock块来进一步提升模型的泛化能力 。Neck网络-Neck网络通常位于基准网络和头网络的中间位置,利用它可以进一步提升特征的多样性及鲁棒性。YOLOv4利用SPP模块来融合不同尺度大小的特征图;利用自顶向下的FPN特征金字塔于自底向上的PAN特征金字塔来提升网络的特征提取能力。Head输出端-Head用来完成目标检测结果的输出。针对不同的检测算法,输出端的分支个数不尽相同,通常包含一个分类分支和一个回归分支。YOLOv4利用CIOU_Loss来代替Smooth L1 Loss函数,并利用DIOU_nms来代替传统的NMS操作,从而进一步提升算法的检测精度。 3.2 YOLOv4实现细节详解 3.2.1 YOLOv4基础组件 CBM-CBM是Yolov4网络结构中的最小组件,由Conv+BN+Mish激活函数组成,如上图中模块1所示。CBL-CBL模块由Conv+BN+Leaky_relu激活函数组成,如上图中的模块2所示。Res unit-借鉴ResNet网络中的残差结构,用来构建深层网络,CBM是残差模块中的子模块,如上图中的模块3所示。CSPX-借鉴CSPNet网络结构,由卷积层和X个Res unint模块Concate组成而成,如上图中的模块4所示。SPP-采用1×1、5×5、9×9和13×13的最大池化方式,进行多尺度特征融合,如上图中的模块5所示。 3.2.2 输入端细节详解 Mosaic数据增强-YOLOv4中在训练模型阶段使用了Mosaic数据增强方法,该算法是在CutMix数据增强方法的基础上改进而来的。CutMix仅仅利用了两张图片进行拼接,而Mosaic数据增强方法则采用了4张图片,并且按照随机缩放、随机裁剪和随机排布的方式进行拼接而成,具体的效果如下图所示。这种增强方法可以将几张图片组合成一张,这样不仅可以丰富数据集的同时极大的提升网络的训练速度,而且可以降低模型的内存需求。 3.2.3 基准网络细节详解 CSPDarknet53-它是在YOLOv3主干网络Darknet53的基础上,借鉴了2019年发表的CSPNet算法的经验,所形成的一种Backbone结构,其中包含了5个CSP模块。每个CSP模型的实现细节如3.2.1所述。CSP模块可以先将基础层的特征映射划分为两部分,然后通过跨阶段层次结构将它们合并起来,这样不仅减少了计算量,而且可以保证模型的准确率。它的优点包括:(1)增强CNN网络的学习能力,轻量化模型的同时保持模型的精度;(2)降低整个模型的计算瓶颈;(3)降低算法的内存成本。有关CSP模块的更多细节请看该论文。Mish激活函数-该激活函数是在2019年提出的,该函数是在Leaky_relu算法的基础上改进而来的,具体的比较请看下图。当x>0时,Leaky_relu与Mish激活函数基本相同;当x<0时,Mish函数基本为0,而Leaky_relu函数为 λ x \lambda x λx。YOLOv4的Backbone中均使用了Mish激活函数,而后面的Neck网络中则使用了leaky_relu激活函数。总而言之,Mish函数更加平滑一些,可以进一步提升模型的精度。更多的细节请看该论文。 Dropblock-Dropblock是一种解决模型过拟合的正则化方法,它的作用与Dropout基本相同。Dropout的主要思路是随机的使网络中的一些神经元失活,从而形成一个新的网络。如下图所示,最左边表示原始的输入图片,中间表示经过Dropout操作之后的结果,它使得图像中的一些位置随机失活,Dropblock的作者认为:由于卷积层通常是三层结构,即卷积+激活+池化层,池化层本身就是对相邻单元起作用,因而卷积层对于这种随机丢弃并不敏感。除此之外,即使是随机丢弃,卷积层仍然可以从相邻的激活单元学习到相同的信息。因此,在全连接层上效果很好的Dropout在卷积层上效果并不好。最右边表示经过Dropblock操作之后的结果,我们可以发现该操作直接对整个局部区域进行失活(连续的几个位置)。 Dropblock是在Cutout数据增强方式的基础上改进而来的,Cutout的主要思路是将输入图像的部分区域清零,而Dropblock的创新点则是将Cutout应用到每一个特征图上面。而且并不是用固定的归零比率,而是在训练时以一个小的比率开始,随着训练过程线性的增加这个比率。与Cutout相比,Dropblck主要具有以下的优点:(1)实验效果表明Dropblock的效果优于Cutout;(2)Cutout只能应用到输入层,而Dropblock则是将Cutout应用到网络中的每一个特征图上面;(3)Dropblock可以定制各种组合,在训练的不同阶段可以灵活的修改删减的概率,不管是从空间层面还是从时间层面来讲,Dropblock更优一些。 3.2.3 Neck网络细节详解 为了获得更鲁棒的特征表示,通常会在基准网络和输出层之间插入一些层,YOLOv4的主要添加了SPP模块与FPN+PAN2种方式。 SPP模块-SPP模块通过融合不同大小的最大池化层来获得鲁棒的特征表示,YOLOv4中的k={1*1,5*5,9*9,13*13}包含这4种形式。这里的最大池化层采用padding操作,移动步长为1,比如输入特征图的大小为13x13,使用的池化核大小为5x5,padding=2,因此池化后的特征图大小仍然是13×13。YOLOv4论文表明:(1)与单纯的使用k*k最大池化的方式相比,采用SPP模块的方式能够更有效的增加主干特征的接收范围,显著的分离了最重要的上下文特征。(2)在COCO目标检测任务中,当输入图片的大小为608*608时,只需要额外花费0.5%的计算代价就可以将AP50提升2.7%,因此YOLOv4算法中也采用了SPP模块。 FPN+PAN-所谓的FPN,即特征金字塔网络,通过在特征图上面构建金字塔,可以更好的解决目标检测中尺度问题。PAN则是借鉴了图像分割领域PANet算法中的创新点,它是一种自底向上的结构,它在FPN的基础上增加了两个PAN结构,如下图中的2和3所示。(1)整个网络的输入图像大小为608*608;然后经过CSP块之后生成一个76*76大小的特征映射,经过下采样操作之后生成38*38的特征映射,经过下采样操作之后生成19*19的特征映射;(2)接着将其传入FPN结构中,依次对19*19、38*38、76*76执行融合操作,即先对比较小的特征映射层执行上采样操作,将其调整成相同大小,然后将两个同等大小的特征映射叠加起来。通过FPN操作可以将19*19大小的特征映射调整为76*76大小,这样不仅提升了特征映射的大小,可以更好的解决检测中尺度 问题,而且增加了网络的深度,提升了网络的鲁棒性。(3)接着将其传入PAN结构中,PANet网络的PAN结构是将两个相同大小的特征映射执行按位加操作,YOLOv4中使用Concat操作来代替它。经过两个PAN结构,我们将76*76大小的特征映射重新调整为19*19大小,这样可以在一定程度上提升该算法的目标定位能力。FPN层自顶向下可以捕获强语义特征,而PAF则通过自底向上传达强定位特征,通过组合这两个模块,可以很好的完成目标定位的功能。 3.2.4 Head网络细节详解 CIOU_loss-目标检测任务的损失函数一般由分类损失函数和回归损失函数两部分构成,回归损失函数的发展过程主要包括:最原始的Smooth L1 Loss函数、2016年提出的IoU Loss、2019年提出的GIoU Loss、2020年提出的DIoU Loss和最新的CIoU Loss函数。 1、IoU Loss-所谓的IoU Loss,即预测框与GT框之间的交集/预测框与GT框之间的并集。这种损失会存在一些问题,具体的问题如下图所示,(1)如状态1所示,当预测框和GT框不相交时,即IOU=0,此时无法反映两个框之间的距离,此时该 损失函数不可导,即IOU_Loss无法优化两个框不相交的情况。(2)如状态2与状态3所示,当两个预测框大小相同时,那么这两个IOU也相同,IOU_Loss无法区分两者相交这种情况。

排列组合(STL算法中next_permutation和prev_permutation剖析)

STL提供了两个用来计算排列组合关系的算法,分别是next_permucation和prev_permutation。解决全排列问题。 首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b, c)。这个序列有六个可能的排列组合: abc,acb,bac,bca,cab,cba。 这些排列组合根据less-than操作符做字典顺序(按照升序排列)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。同样道理,那些固定b(序列内次小元素)而做的排列组合,在次序上将先于那些固定c而做的排列组合。以bac和 bca为例,bac在 bca之前,因为序列ac小于序列ca。面对bca,我们可以说其前一个排列组合是bac,而其后一个排列组合是cab。序列abc没有“前一个”排列组合,cba没有“后一个”排列组合。 next_permutation next_permutation ( )会取得〔 first,last)所标示之序列的下一个排列组合。如果没有下一个排列组合,便返回false;否则返回true。 next_permutation 算法过程: 首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为 *ii,且满足*i< *ii。找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将 i,j元素对调,再将 ii 之后的所有元素颠倒排列。此即所求之“下一个”排列组合。 e.g.以序列{0,1,2,3,4}为例,获得”下一个”排列组合。 输入序列{0,1,2,3,4} 第一元素为*i == 3,第二元素为 *ii == 4,且满足*i< *ii. 找到这样一组相邻元素(3 4) 从最尾端开始往前检验,找出第一个大于*i的元素,令为*j == 4 将 i,j元素对调(*i == 4*j == 3),再将 ii 之后的所有元素颠倒排列 输出“下一个”排列组合{0,1,2,4,3}; e.g.以序列{0,1,2,4,3}为例,获得”下一个”排列组合。 输入序列{0,1,2,4,3} 第一元素为*i == 2,第二元素为 *ii == 4,且满足*i< *ii. 找到这样一组相邻元素(2 4) 从最尾端开始往前检验,找出第一个大于*i的元素,令为*j == 3 将 i,j元素对调(*i == 3 *j == 2),再将 ii 之后的所有元素颠倒排列 (4 2-->2 4)

利用Matlab替换图片部分颜色

目录 1. 需求分析 2. 技术分析 3. 程序代码 1. 需求分析 日常工作、研究、学习当中,往往需要对图片进行处理。其中图片重新着色、渲染是非常常见的。比如说去掉或则更换证件照底色;去掉遥感图像中黑边……为解决此类问题,而编写此代码。 2. 技术分析 图片处理主要其中有两个重要步骤:a.提取目标位置,获取索引;b.着色、渲染等处理;本代码也是按照这两个步骤来写的:a.利用find函数提取目标,获取其索引;b. 再根据索引,进行着色渲染处理。find函数用法如下: find - 查找非零元素的索引和值 此 MATLAB 函数 返回一个包含数组 X 中每个非零元素的线性索引的向量。 k = find(X) k = find(X,n) k = find(X,n,direction) [row,col] = find(___) [row,col,v] = find(___) 3. 程序代码 根据技术分析,进行编程。本人在网上找到一段相关代码,并基于此进行进一步编程。源代码如下: clear;close all;clc; image = imread('测试.JPG'); % 读取图像 figure('Name','原图') imshow(image); % 显示 R = image(:,:,1); % 红色 G = image(:,:,2); % 绿色 B = image(:,:,3); % 蓝色 index = find(R<20 & G<20 & B<20); % 索引,找出被替换颜色的范围 R(index) = 255; % 红色通道赋值 G(index) = 255; % 绿色通道赋值 B(index) = 255; % 蓝色通道赋值 Out_Image(:,:,1) = R; % 输出图像红色通道 Out_Image(:,:,2) = G; % 输出图像绿色通道 Out_Image(:,:,3) = B; % 输出图像蓝色通道 figure('Name','颜色改变之后的图') imshow(Out_Image); % 显示输出图像 上面这段代码来自:利用matlab代码怎么将黑色变为白色,而红色不变 – MATLAB中文论坛

60行代码,制作H5版飞机大战游戏

用最基础的代码逻辑,实现了飞机大战的核心玩法 点击这里可以试玩欧 制作使用了PIXI框架,对于制作H5应用的运行效率优化的还算不错。 感兴趣可以一起研究 制作了如下功能 1、制作了游戏的场景元素及动画效果 2、飞机的控制 3、发射子弹击落敌机,得分功能 4、Game Over后,重新游戏 功能涵盖了基本H5游戏的制作套路。 可通过“复制”“粘贴”大法,进行功能的丰富 源码可以在线调试,也手机直接浏览 源码地址:​​​​​​​​​​​​​​http://pro.youyu001.com 代码说明 以下内容可以作为H5游戏开发的帮助手册使用 1)创建应用 var app = new PIXI.Application(512,768); document.body.appendChild(app.view); 2)添加图片,设置图片位置与定位点 var plane = new PIXI.Sprite.fromImage("res/plane_blue_01.png"); app.stage.addChild(plane); //将图片放置到舞台 plane.anchor.x = 0.5; //设置图片锚点为图片中心 plane.anchor.y = 0.5; plane.x = 200; //设置图片的位置 plane.y = 600; 3)添加文本显示 var scoreTxt = new PIXI.Text("score 0"); app.stage.addChild(scoreTxt); //将文本添加到舞台 4)添加控制功能,获取鼠标位置 bg.interactive = true;//背景图片允许接受控制信息 bg.on("pointermove", movePlane); //滑动控制 function movePlane(event) { var pos = event.data.getLocalPosition(app.stage); //获取鼠标当前位置 plane.

vue+springboot前后端分离交互(快速上手)

文章目录 前言安装vue-cli脚手架启动vue项目管理器数据交互Element-ui的使用路由和动态导航栏分页查询数据添加数据修改删除数据 前言 本人是学习完SpringBoot的技术之后,认为现在的thymeleaf+SpringBoot的开发方式使用的并不多,现在大部分在使用的是前后端分离的开发方式,其中的一种是Vue+SpringBoot的开发方式。 前后端分离开发现在是流行的大趋势,所以我建议想要快速构建项目的小伙伴们一定要好好了解学习一下vue+springboot的开发方式。 idea,node.js mysql 这里我们按照大多数人的开发习惯,都以idea开发工具来准备。 需要先安装好nodejs,当然了,看到这里的同学们肯定也学习过vue了,node.js肯定也安装好了。这里就不再做过多的赘述了。 安装 node.js node.js官网:https://nodejs.org/zh-cn/ 具体代码地址:百度网盘下载 链接:https://pan.baidu.com/s/1fWO0i5iGxz2U8U4vmABIzA 提取码:wmlg 安装vue-cli脚手架 使用cmd命令打开命令行,输入以下命令 vue3.0以上的版本安装命令改成这个样子npm install -g @vue/cli npm install -g @vue/cli@4。4.6 这里我本人建议还是直接装4.4.6版本的脚手架,因为看了很多视频,其他版本多多少少都有不兼容的东西,后期学习其他的还得更换,所以还是直接安装4.4.6版本的标胶稳妥。当然了,这只是我个人的建议,希望可以让你们少走些弯路,少掉些头发 哈哈~~ 启动vue项目管理器 安装成功之后 命令行窗口输入:vue ui(注意在你想要创建项目的位置上,想在d盘上创建项目就切换到d盘之后再输入该命令。) 启动成功! 等启动成功之后会进入vue的项目管理器了。 之后使用方法在我上一篇博客已经写了:https://blog.csdn.net/lj20020302/article/details/129402966。 数据交互 前后端数据交互,需要axios来进行操作,所以我们先要下载axios。 在vue项目下载打开终端:输入以下命令 安装完成之后在你需要请求的页面上加如下代码: created() { const _this = this; axios.get('http://localhost:8082/list').then(function (resp) { _this.students =resp.data; }) } 我们初始化函数,写一个回调函数,然后打印data。这次可以打印出来自己的数据库里面的数据了。 跨域问题的话,我们新建一个配置类 CrosConfig 可以参考下面的代码: package com.guo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CrosConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.

RecyclerView.ViewHolder的adapterPosition属性被废弃了

RecyclerView.ViewHolder 中的 adapterPosition 属性在 API level 30(Android 11)中被标记为已废弃。 adapterPosition 是用于获取当前 ViewHolder 在 Adapter 中的位置的属性。然而,在某些情况下,adapterPosition 可能会返回不正确的位置,例如在 ViewHolder 已经被回收并重用后。为了解决这个问题,官方推荐使用 bindingAdapterPosition 或 absoluteAdapterPosition 属性来获取 ViewHolder 在 Adapter 中的位置。 bindingAdapterPosition 属性是用于在使用数据绑定时获取当前 ViewHolder 在 Adapter 中的位置的。absoluteAdapterPosition 属性是用于在 RecyclerView 中使用多个 Adapter 时获取当前 ViewHolder 在全局 Adapter 中的位置的。 需要注意的是,这两个属性也有可能返回不正确的位置,因此在使用时需要进行适当的判断和处理。 简单修改如下,一个简单的代码提交图对比:

【从现有的数据库中 反射flask-sqlalchemy的models】

从现有的数据库中 反射到flask-sqlalchemy的models def create_database_models(tables): """ 从已有的数据库中 建立flask-sqlalchemy的models :return: """ # xa_est_user xa_est_account cmd = f'flask-sqlacodegen "mysql+pymysql://user:password@ip/databases" --tables {",".join(tables)} --outfile "model_test.py" --flask' try: print(f"表: {tables}反映射成功") except: print(f"表: {tables}反映射失败") if __name__ == '__main__': # -------------------反映射model table_name = ["role_menu", "role"] # 表在数据库中已存在 create_database_models(table_name) 使用的依赖: Flask 1.1.4 Flask-Migrate 3.1.0 Flask-SQLAlchemy 2.5.1 flask-sqlacodegen 1.1.8 SQLAlchemy 1.4.9

深入理解Android插件化技术

插件化技术可以说是Android高级工程师所必须具备的技能之一,从2012年插件化概念的提出(Android版本),到2016年插件化的百花争艳,可以说,插件化技术引领着Android技术的进步。 插件化提要 可以说,插件化技术涉及得非常广泛,其中最核心的就是Android的类加载机制和反射机制,相关原理请大家自行百度。 插件化发展历史 插件化技术最初源于免安装运行apk的想法,这个免安装的apk可以理解为插件。支持插件化的app可以在运行时加载和运行插件,这样便可以将app中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现app功能的动态扩展。想要实现插件化,主要是解决下面三个问题: 插件中代码的加载和与主工程的互相调用 插件中资源的加载和与主工程的互相访问 四大组件生命周期的管理 下面是比较出名的几个开源的插件化框架,按照出现的时间排序。研究它们的实现原理,可以大致看出插件化技术的发展,根据实现原理可以将这几个框架划分成了三代。 第一代:dynamic-load-apk最早使用ProxyActivity这种静态代理技术,由ProxyActivity去控制插件中PluginActivity的生命周期。该种方式缺点明显,插件中的activity必须继承PluginActivity,开发时要小心处理context。而DroidPlugin通过Hook系统服务的方式启动插件中的Activity,使得开发插件的过程和开发普通的app没有什么区别,但是由于hook过多系统服务,异常复杂且不够稳定。 第二代:为了同时达到插件开发的低侵入性(像开发普通app一样开发插件)和框架的稳定性,在实现原理上都是趋近于选择尽量少的hook,并通过在manifest中预埋一些组件实现对四大组件的插件化。另外各个框架根据其设计思想都做了不同程度的扩展,其中Small更是做成了一个跨平台,组件化的开发框架。 第三代:VirtualApp比较厉害,能够完全模拟app的运行环境,能够实现app的免安装运行和双开技术。Atlas是阿里今年开源出来的一个结合组件化和热修复技术的一个app基础框架,其广泛的应用与阿里系的各个app,其号称是一个容器化框架。 插件化原理 类加载 Android中常用的有两种类加载器,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。相关源码如下: 区别在于调用父类构造器时,DexClassLoader多传了一个optimizedDirectory参数,这个目录必须是内部存储路径,用来缓存系统创建的Dex文件。而PathClassLoader该参数为null,只能加载内部存储目录的Dex文件。所以我们可以用DexClassLoader去加载外部的apk,用法如下: 其实,关于类加载更详细的内容,笔者也深入剖析过,可以查看下面的链接:类加载机制详解 双亲委托机制 ClassLoader调用loadClass方法加载类,代码如下: 可以看出ClassLoader加载类时,先查看自身是否已经加载过该类,如果没有加载过会首先让父加载器去加载,如果父加载器无法加载该类时才会调用自身的findClass方法加载,该机制很大程度上避免了类的重复加载。 DexPathList 这里要重点说一下DexClassLoader的DexPathList。DexClassLoader重载了findClass方法,在加载类时会调用其内部的DexPathList去加载。DexPathList是在构造DexClassLoader时生成的,其内部包含了DexFile。如下图所示: DexPathList的loadClass会去遍历DexFile直到找到需要加载的类。 腾讯的qq空间热修复技术正是利用了DexClassLoader的加载机制,将需要替换的类添加到dexElements的前面,这样系统会使用先找到的修复过的类。 单DexClassLoader与多DexClassLoader 通过给插件apk生成相应的DexClassLoader便可以访问其中的类,这边又有两种处理方式,有单DexClassLoader和多DexClassLoader两种结构。 对于多DexClassLoader结构来说,可以用下面的模型来标识。 对于每个插件都会生成一个DexClassLoader,当加载该插件中的类时需要通过对应DexClassLoader加载。这样不同插件的类是隔离的,当不同插件引用了同一个类库的不同版本时,不会出问题,RePlugin采用的就是此方案。 对于单DexClassLoader来说,其模型如下: 将插件的DexClassLoader中的pathList合并到主工程的DexClassLoader中。这样做的好处时,可以在不同的插件以及主工程间直接互相调用类和方法,并且可以将不同插件的公共模块抽出来放在一个common插件中直接供其他插件使用。Small采用的是这种方式。 插件和主工程的互相调用涉及到以下两个问题: 插件调用主工程 在构造插件的ClassLoader时会传入主工程的ClassLoader作为父加载器,所以插件是可以直接可以通过类名引用主工程的类。 主工程调用插件 若使用多ClassLoader机制,主工程引用插件中类需要先通过插件的ClassLoader加载该类再通过反射调用其方法。插件化框架一般会通过统一的入口去管理对各个插件中类的访问,并且做一定的限制。 若使用单ClassLoader机制,主工程则可以直接通过类名去访问插件中的类。该方式有个弊病,若两个不同的插件工程引用了一个库的不同版本,则程序可能会出错,所以要通过一些规范去避免该情况发生。 资源加载 Android系统通过Resource对象加载资源,下面代码展示了该对象的生成过程。 因此,只要将插件apk的路径加入到AssetManager中,便能够实现对插件资源的访问。 具体实现时,由于AssetManager并不是一个public的类,需要通过反射去创建,并且部分Rom对创建的Resource类进行了修改,所以需要考虑不同Rom的兼容性。 资源路径的处理 和代码加载相似,插件和主工程的资源关系也有两种处理方式: 合并式:addAssetPath时加入所有插件和主工程的路径; 独立式:各个插件只添加自己apk路径 合并式由于AssetManager中加入了所有插件和主工程的路径,因此生成的Resource可以同时访问插件和主工程的资源。但是由于主工程和各个插件都是独立编译的,生成的资源id会存在相同的情况,在访问时会产生资源冲突。 独立式时,各个插件的资源是互相隔离的,不过如果想要实现资源的共享,必须拿到对应的Resource对象。 Context的处理 通常我们通过Context对象访问资源,光创建出Resource对象还不够,因此还需要一些额外的工作。 对资源访问的不同实现方式也需要不同的额外工作。以VirtualAPK的处理方式为例。 第一步:创建Resource 第二步:hook主工程的Resource 对于合并式的资源访问方式,需要替换主工程的Resource,下面是具体替换的代码。 注意下上述代码hook了几个地方,包括以下几个hook点: 替换了主工程context中LoadedApk的mResource对象。 将新的Resource添加到主工程ActivityThread的mResourceManager中,并且根据Android版本做了不同处理。 第三步:关联resource和Activity 上述代码是在Activity创建时被调用的(后面会介绍如何hook Activity的创建过程),在activity被构造出来后,需要替换其中的mResources为插件的Resource。由于独立式时主工程的Resource不能访问插件的资源,所以如果不做替换,会产生资源访问错误。 做完以上工作后,则可以在插件的Activity中放心的使用setContentView,inflater等方法加载布局了。 解决资源冲突 合并式的资源处理方式,会引入资源冲突,原因在于不同插件中的资源id可能相同,所以解决方法就是使得不同的插件资源拥有不同的资源id。 资源id是由8位16进制数表示,表示为0xPPTTNNNN。PP段用来区分包空间,默认只区分了应用资源和系统资源,TT段为资源类型,NNNN段在同一个APK中从0000递增。如下表所示: 所以思路是修改资源ID的PP段,对于不同的插件使用不同的PP段,从而区分不同插件的资源。具体实现方式有两种: 修改aapt源码,编译期修改PP段。 修改resources.arsc文件,该文件列出了资源id到具体资源路径的映射。 四大组件支持 Android开发中有一些特殊的类,是由系统创建的,并且由系统管理生命周期。如常用的四大组件,Activity,Service,BroadcastReceiver和ContentProvider。 仅仅构造出这些类的实例是没用的,还需要管理组件的生命周期。其中以Activity最为复杂,不同框架采用的方法也不尽相同。下面以Activity为例详细介绍插件化如何支持组件生命周期的管理。 大致分为两种方式:

【Python实用小工具】PDF文件快速拆分

""" 需要先安装:pip/pip3 install PyPDF2==3.0.0 python3版本:3.10.6 PyPDF2版本:PyPDF2-3.0.0 执行命令:python3 pdf_div.py 优化记录:优化最后一个文件未写入磁盘的问题。 """ import PyPDF2 import os # 以多少页分割1个文件 PAGES_PER_FILE = 499 # 输入pdf文件路径 FILE_PATH = r'input.pdf' # 源文件所在的绝对路径 pdf_file = open(FILE_PATH, 'rb') # 获取原 PDF 文件 pdf_reader = PyPDF2.PdfReader(pdf_file) # 创建 PDF 对象 source_name = pdf_file.name # 获取源文件名称,包含绝对路径 pdf_writer = PyPDF2.PdfWriter() # 创建一个空白 PDF 对象 # print(f"pdf_reader.pages:{pdf_reader.pages}") new_name = source_name[:-4] + "-0.pdf" pdf_new_file = open(new_name, 'wb') # 创建一个新文件 print(f"new_name:{new_name}") for page_num in range(len(pdf_reader.

外包派遣3年华为,合同结束转正,转正后工资12k-15k,13薪,包三餐,值得去吗?

“但凡有点机会,千万别去外包! ” 在程序员圈子里面,外包程序员似乎永远处于一个尴尬的角色,如果你说他们不是程序员吧,他们也是程序员。应该说是外包这个词比较尴尬吧。赶着和正式工一样的伙,待遇缺天差地别,没有福利,逢年过节也没有礼品啥的。平常也不好去融进正式工的圈子。工作中都是一个人。 经常会有朋友问我:面试通过了·,但是在纠结到底该不该去外包,看网上都在说“千外不要去外包”搞得自己也很纠结。我只能说 如果能力不够,就不要眼高手低,可以接受外包,但不要一辈子都是外包,不要心安理得,要把“外包”作为一种跳板。其实现在就业还是比较艰难的,失业的被裁裁的比比皆是。所以在没有其他更好的选择的时候,去外包也不是不可。当然有不好的外包,就像有垃圾的大学一样,进去后只会浪费青春,浪费精力。一旦进入这种只会压榨劳动力,却无法成长的外包,就是跳进了火坑。 就我自身而已,大学学的是计算机专业,毕业的时候,对于找工作比较迷茫,也不知道当时怎么想的,一头就扎进了一家外包公司,一干就是4年。现在终于跳槽到了互联网公司了,我想说的是,只要自身技术够硬,外不外包都没关系。 刚开始竟然外包,被派遣到大大小小的公司。但是我不会想着这个项目结束了就可以了,会不断通过自身的优势在不同的环境中去学习他们的优势,也可以多多学习,这个习惯也让我的简历好看了不少。后来被外包派遣到了华为,项目一完成就跳槽到了华为。现在也是正式员工了 告诉大家我的经历就是想要说明,机会都是自己去选择的,大家纠结去外包的原因有以下几点 1.缺乏长期的技术积累,掌握不到核心技术。一般雇主公司比较核心或者底层的东西是不会让外包人员作的。外包人员一般做的都是“边角料”。 2.缺乏长期的公司积累。在一个普通软件公司里面,资历是一个比较重要的指标。一个程序员在公司呆的时间越长,对公司的贡献越大。而在外包公司基本没有什么积累。最多的收益应该是项目经验了。 3.在雇主公司内部会受到“歧视”。不用说,一般雇主公司的人员挑大梁,外包人员也就做些边角料的工作,或者雇主公司的人员作需求和设计,外包人员编写代码。 4.项目做完后,会马上失业。当然了,雇主公司都把做项目的酬劳付给外包公司了。外包公司项目完成后,就没有钱进帐了,难道他们会把你养的白白胖胖的? 如果你现在在外包公司,多学习争取把自己的技术提升上来,你还要明确自己的职业规划,这样你才有跳槽的资本,才有跟别人竞争的机会。 并不是所有的正式员工都是趾高气扬的,瞧不起外包的;有些挺古道热肠的,愿意沟通,愿意交流,也愿意做朋友,我就遇到过这样的同事。所以,我对外包没有一点偏见。 想要转正,我觉得有必要做好下面几点: 努力工作。不管是黑猫还是白猫,总要逮住老鼠。如果正式员工解决不了的问题,外包员工却可以解决,我相信人生很快就会逆袭,对吧?持续学习。一家公司,不管是好是坏,既然存在就有它的价值,我觉得不能非黑即白的下定义,外包就一定学习不到技术,公司用的什么技术很重要,更重要的是你愿意学习什么样的技术。时间紧?不是问题,当前的大环境下,每个项目的时间都赶的挺紧的;技术烂,不是问题,我们可以学习新鲜的技术来对旧的代码进行重构。如果抱怨说既没有时间,又没有精力可以学习,那不管是正式员工还是外包,都是没有前途的。投资自己。不管处于什么样的环境下,哪怕糟糕到极限,也不要忘记投资自己。在人类历史上,有过特别黑暗的阶段,不仅物质上匮乏,精神上也匮乏,但总有一小撮人,他们坚持投资自己,那机会来的时候,出现转机的时候,他们就是那群熠熠生辉、光芒万丈的人。 1.软件测试基础理论知识: 软件的质量模型:软件测试过程保障软件的质量,从哪些方面保障可以从质量模型出发思考测试分类:软件测试过程可以按照不同角度进行分类,基础测试到高级测试递进过程开发流程:告诉测试人员一个软件完整的生命周期,软件从无到有到消亡的过程测试流程:掌握并指导测试人员在实际项目中如何开展测试工作。这要求测试人员对常见的主流测试流程有较为透彻的理解。遇到不同的软件项目,知道从何处着实能最有效率的测试软件缺陷测试计划与方案:如何规划在项目中开展测试活动,确保测试活动有序进行设计用例方法:黑盒测试阶段必须掌握的一些测试用例的设计方法。比如黑盒测试- 用例的设计方法、测试用例元素等等软件缺陷:在测试执行过程中应该确定缺陷并提交缺陷报告缺陷管理:提交缺陷后在实际工作中如何和开发协助处理验证提交的问题。例如:- - bug的等级优先级分类、bug的描述、bug的生命周期、缺陷管理工具使用,如禅道等。测试报告:测试过程的回顾和结果确认,生成系统性的专业软件测试评估报告 2、软件测试功底技术——Linux系统 linux系统是主要的服务端操作系统,也是从事IT岗位的大部分人员必须具备的基本技术之一。作为软件测试工程师,我们常常需要在服务器端查看日志,从而定位问题的源头。 linux系统基本知识:多用户,多任务,发行版本等 常见 linux操作命令:日志查看,文件压缩、解压,用户管理,文件权限等 会部署和配置基本的应用jdk、 mysql、 tomcat docker安装使用 编写基本的 shell RAD本 远程终端工具使用: shell, xftps等 3、软件测试功底技术——Sql数据库 数据库作为软件系统必备的应用系统,在诸如接口测试、性能测试等等过程中往往需要操作数据库,验证数据正确性完整性,都离不开数据库的增删改查操作,在项目部署阶段数据库还需要配合项目部署。在性能测试、接口自动化测试中都需要数据库的支撑。 数据库基本概念 关系型数据库 MYSQL基本的增改查语句,存储过程 MYSQL复杂查询、多表查询 MYSQL索引及事务相关概念 数据库客户端工具使用:如 Navicat 4、软件测试功底技术——编程语言 推荐没有编程基础的朋友可以学习Python语言 Python语言的学习内容包含以下知识点: Python基础:Python语言特点、运行环境、基本语法、代码风格、示例程序 数据结构: 基本数据结构:数字、字符串、类型判断、类型转换、切片、字符串格式化、数值运算、位置参数和关键字参数;组合数据结构:列表、元组、范围、字典、集合、不可hash对象、解包、内存地数据结构址、不可变数据程序控制:顺序结构、循环结构、判断结构、异常处理、逻辑运算符函数:定义函数、函数的参数、返回值、变量作用域、匿名函数、常用内置函数模块和库:模块和包、import关键字、常用标准库、常用第三方库、包管理工具pip面向对象:面向对象起源和优势、面向对象的特性类和对象的联系、对象的特殊方法日志记录:baseConfig、文件日志、邮件日志、定制格式、内置占位符、等级过滤、分级传播、配置文件测试框架:unitest、pytest等并发编程:多进程、多线程、协程、线程池、同步控制、线程通信、分布式、猴子补丁、 async语法、生成器网络编程:socket编程基础、TCP服务端和客户端、并行请求处理、HTTP服务端和客户端 5、软件测试自动化进阶——接口测试 接口测试本质也是功能测试的一种,通过脚本或者工具,模拟客户端对服务端接口进行调用。因为是从接口层测试,所以能更早的发现问题,从而提高测试效率,降低修复成本。 http/httpst协议学习 常见请求方法学习:GET、POST cookie和 session学习 接口的基本概念 接口文档认识 接口测试用例编写 接口测试工具使用:postman、Jmeter、SoapUl 6、软件测试自动化进阶——性能测试 性能测试的技术要求很高,不仅仅要对性能测试的指标、测试分类、测试设计有很深刻的理解。还要学习系统业务和架构相关知识,这样才能更好的设计性能场景,分析出系统的性能瓶颈。性能测试常用的工具有jmeter和loadrunner,大家可以根据需要进行学习。 性能基本概念:性能测试意义、常见性能指标理解、性能测试的分类 性能测试流程:性能需求分析、性能场景设计、测试脚本编写、测试执行资源监控、性能调优、回归测试 Jmeter及 roadrunner使用 性能测试报告输出

阿里云ecs搭建zookeeper集群

准备两台ecs机器,为啥只有两台?因为买不起第三台。。。。好了,回归正题。 准备: 两台ecsjdk8及以上zookeeper, 我这里用的3.4.14 注意事项: 1、zookeeper 集群至少需要三台节点才能搭建集群。 2、ecs中安全组记得开放端口,建议为了便捷直接将ecs的全部端口开放。出,入方向都要设置。 步骤: 目前我是两台ecs,一台上有两个zookeeper节点 ,另一台一个zookeeper节点。配置hosts文件, 假设两台ip分别是xxx.xx.xxx.x , xxx.x.xxx.xx, 则在每台ecs配置hosts文件,加上 xxx.xx.xxx.x node01 xxx.x.xxx.xx node02 然后刷新网卡, systemctl network restart 在每个zookeeper节点外部创建两个文件夹,并分配权限。 # 一台 mkdir data mkdir logs mkdir cluster-data mkdir cluster-logs chmod 777 -R data chmod 777 -R log chmod 777 -R cluster-data chmod 777 -R cluster-logs # 另一台 mkdir data mkdir logs chmod 777 -R data chmod 777 -R logs 配置节点中zoo.cfg文件 # 第一个 # The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored.

【网页不同分辨率适配rem】

网页不同分辨率适配rem // 新建工具方法-flexible.js (function(win, lib) { var doc = win.document var docEl = doc.documentElement var metaEl = doc.querySelector('meta[name="viewport"]') var flexibleEl = doc.querySelector('meta[name="flexible"]') var dpr = 0 var scale = 0 var tid var flexible = lib.flexible || (lib.flexible = {}) if (metaEl) { console.warn('将根据已有的meta标签来设置缩放比例') var match = metaEl .getAttribute('content') // eslint-disable-next-line no-useless-escape .match(/initial\-scale=([\d\.]+)/) if (match) { scale = parseFloat(match[1]) dpr = parseInt(1 / scale) } } else if (flexibleEl) { var content = flexibleEl.

【vue/js 日期format转换格式集合】

对Date扩展 main.js // 对Date的扩展,将 Date 转化为指定格式的String // 月(M)、日(d)、小时(H)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) // 例子: // (new Date()).format("yyyy-MM-dd HH:mm:ss.S") ==> 2006-07-02 08:09:04.423 // (new Date()).format("yyyy-M-d H:m:s.S") ==> 2006-7-2 8:9:4.18 // eslint-disable-next-line no-extend-native Date.prototype.format = function(fmt) { // author: meizz var o = { 'M+': this.getMonth() + 1, // 月份 'd+': this.getDate(), // 日 'h+': this.getHours(), // 小时 'm+': this.getMinutes(), // 分 's+': this.getSeconds(), // 秒 'q+': Math.

Android中arm64-v8a、armeabi-v7a、armeabi是什么?

------《怎么利用Android Studio查看Android-SDK源码》 前言正题ABI是如何工作的ABI具体适配流程项目中该如何适配打包配置split分包ndk{abiFilters:}过滤 前言 首先:ARM是神马? 答:ARM是我们设备的CPU架构。 其次:arm64-v8a、armeabi-v7a、armeabi是神马? 答:在Android 系统上,每一个CPU架构对应一个ABI。他们就是我们的ABI类型 最后:ABI是神马? 答:应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。 补充:查询手机cpu命令行 答: adb shell getprop ro.product.cpu.abi 正题 armeabi-v7a: ARM v7架构之前的主流版本,现在也很多。 arm64-v8a: 64位支持,目前主流的版本。 ABI是如何工作的 一个Android设备可以支持多种ABI,设备主ABI和辅助ABI。 以arm64-v8a为主ABI的设备,辅助ABI为armeabi-v7a和armeabi。 以armeabi-v7a为主ABI的设备,辅助ABI为armeabi。 ABI具体适配流程 对于一个cpu是arm64-v8a架构的手机,它运行app时,进入jnilibs去读取库文件时,先看有没有arm64-v8a文件夹,如果没有该文件夹,去找armeabi-v7a文件夹,如果没有,再去找armeabi文件夹,如果连这个文件夹也没有,就抛出异常。 如果有arm64-v8a文件夹,那么就去找特定名称的.so文件,注意:如果没有找到想要的.so文件,不会再往下(armeabi-v7a文件夹)找了,而是直接抛出异常。 项目中该如何适配 问题:只适配了armeabi-v7a,那如果APP装在其他架构的手机上,如arm64-v8a上,会蹦吗? 答: 不会,但是反过来会。 因为armeabi-v7a和arm64-v8a会向下兼容: 只适配armeabi的APP可以跑在armeabi,x86,x86_64,armeabi-v7a,arm64-v8上 只适配armeabi-v7a可以运行在armeabi-v7a和arm64-v8a 只适配arm64-v8a 可以运行在arm64-v8a上 适配方案有哪些? 1、只适配armeabi 优点:基本上适配了全部CPU架构(除了淘汰的mips和mips_64) 缺点:性能低,相当于在绝大多数手机上都是需要辅助ABI或动态转码来兼容。 2、只适配 armeabi-v7a 同理方案一,只是又筛掉了一部分老旧设备,在性能和兼容二者中比较平衡。 3、只适配 arm64-v8 优点: 性能最佳 缺点: 只能运行在arm64-v8上,要放弃部分老旧设备用户。 这三种方案都是可以的,现在的大厂APP适配中,这三种都有,大部分是前2种方案。具体选哪一种就看自己的考量了,以性能换兼容就arm64-v8,以兼容换性能armeabi,二者稍微平衡一点的就armeabi-v7a。 打包配置 split分包 这个命令可以按照各种规则去分包,比如按照abi,屏幕密度(即ldpi,hdpi等)分包。 splits { abi { enable true reset() include 'x86','armabi' exclude 'armeabi', 'armeabi-v7a', "

CS和BS的区别

1.CS和BS的概念 CS,即C/S(Client/Server)结构,是一种客户机和服务器结构。cs也是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。 BS即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器,而客户端采用浏览器运行软件。 2.CS和BS区别 1.开发维护成本 cs开发维护成本高于bs。 因为因为采用cs结构时,对于不同的客户端要开发不同的程序,而且软件安装调试和升级都需要在所有客户机上进行。 bs只需要在软件服务器上升级就可以的。 2.安全性 cs安全性高于bs。 cs适用于专人使用的系统,可以通过严格的管理派发软件。 bs使用人数多,不固定,安全性低。 3.客户端负载 cs客户端负载大于bs。 cs客户端不仅负责和用户的交互,收集用户信息,而且还需要通过网络向服务器发出请求。 bs把事务处理逻辑部分交给了服务器,客户端只是负责显示。 4.相应速度 cs相应速度高于bs。 ———————————————— 版权声明:本文为CSDN博主「宾宾叔叔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_46429858/article/details/124396642

一篇文章搞懂华为的ACL

第十一章:ACL原理与配置 随着网络的飞速发展,网络安全问题日益突出。访问控制列表 (ACL, Access Control List) 可以通过对网络中报文流的精确识别,与其他技术结合,达到控制网络访问行为、防止网络攻击和提高网络带宽利用率的目的,从而切实保障网络环境的安全性和网络服务质量的可靠性。 11.1 ACL概述 访问控制列表简称为ACL,它使用包过滤技术,在路由器上读取第3层及第4层包头中的信息,如源地址、目的地址、源端口和目的端口等,根据预告定义好的规则对包进行过滤从而达到访问控制的目的。ACL分很多种,不同场合应用不同种类的ACL。 基本ACL 基本ACL最简单,是通过使用IP包中的源IP地址进行过滤,表号范围2000-2999。 高级ACL 高级ACL比基本ACL具有更多的匹配项,功能更加强大和细化,可以针对包括协议类型、源地址、目的地址、源端口、目的端口和TCP连接建立等进行过滤,表号范围3000-3999。 基于时间ACL ACL的生效时间段可以规定ACL规则在何时生效,比如某个特定时间段或者每周的某个固定时间段。 自反ACL 通过自反ACL可以实现网络节点的单向访问。 5、在访问控制列表的学习中,要特别注意以下两个术语。 ① 通配符掩码:一个32比特位的数字字符串,它规定了当一个IP地址与其他的IP地址进行比较时,该IP地址中哪些位应该被忽略。通配符掩码中的”1”表示忽略IP地址中对应的位,而”0”则表示该位必须匹配。两种特殊的通配符掩码是”255.255.255.255”和”0.0.0.0”,前者等价于关键字”any”,而后者等价于关键字”host”。 ② Inbound和Outbound:当在接口上应用访问控制列表时,用户要指明访问控制列表是应用于流入数据,还是流出数据。 11.2 实验一:基本ACL 1、实验需求  掌握ACL的配置方法 掌握ACL在接口下的应用方法 掌握流量过滤的基本方式 2、实验拓扑 实验拓扑如图11-1所示 图11-1 基本ACL 实验免费链接:【实战课】华为HCIA-Datacom认证实验教学-学习视频教程-腾讯课堂 实验步骤 (1)PC机的IP地址配置 PC1的配置,在ipv4下选择静态配置,输入对应的ip地址、子网掩码和网关,然后点击应用。PC2、sever同理PC1的配置如图11-2所示: 图11-2在PC1上手动添加IP地址 PC2的配置如图11-3所示: 图11-3在PC2上手动添加IP地址 (2)在交换机LSW1上创建VLAN10和20,把g0/0/1划分到vlan10,把g0/0/2划分到vlan20,把g0/0/3设置成trunk。 <Huawei>system-view [Huawei]sysname LSW1 [LSW1]undo info-center enable [LSW1]vlan batch 10 20 [LSW1]interface g0/0/1 [LSW1-GigabitEthernet0/0/1]port link-type access [LSW1-GigabitEthernet0/0/1]port default vlan 10 [LSW1-GigabitEthernet0/0/1]quit [LSW1]interface g0/0/2 [LSW1-GigabitEthernet0/0/2]port link-type access [LSW1-GigabitEthernet0/0/2]port default vlan 20

MySQL加速原理

MySQL必加速原理。对于HDD硬盘来说呀,都会将盘片划分成一个个大小都是512字节的扇区。但是对于SSD固态硬盘来说 ,不存在真正的扇区 ,就没有扇区这个定义了,它是由4KB的配置组成的。 先看应用场景最广泛的HDD硬盘。如果我们现在有这样一张买车购表。一共有32条数据,如果假设每条记录占用的存储空间是512字节,那么它就会占用32个扇区来存储这些数据。试想一下,如果我们现在要查找的目标数据的ID等于32,如果现在也没有建立索引,就一定会发生全面扫描,那么一定需要32次IO才能找到目标数据吗?其实并不是这样的,因为操作系统 ,都有连续读和缓冲数据的原理。 在计算机领域,当一个数据被用到时,通常它附近的数据也会被用到。因此磁盘在每一次发生读的操作的时候呢都会在找到目标数据之后都会去连续读取4KB的数据,比如说磁盘的磁头的转动,再连续读取4KB的数据。这样的话,它我在文件系统中,就把一个块的大小定义成了4KB。相当于每次IO操作,它会加载八个三区的数据到内存中。因此我们可以看见到在文件系统中,即使这个文件只存储了一个字节的数据,但是它占用的物理空间仍然是4KB。而MYSQL呢,又觉得4KB太小了。在MYSQL中,最小的存储单元是页。一个页的占用的存储空间呢是16KB。 这个是默认值,我们可以修改的。相当于是每次IO操作呢都可以缓存16KB的数据,它是以16KB作为一个存储单元 ,最小缓存16KB,然后会把这个16KB的数据呢放到八分铺中,在八分铺中每个bit buffer的大小恰好是16KB,而bit buffer的空间释放也不需要等待ZVM的GC操作。因此 ,就不会发生stop the world,这个效率就非常高了。因此,对于这个32行数据的表 ,即使我们不创建索引,我们在查找数据的时候也未必会感受到慢,这就是顺序读和八号铺给我们带来的便利。 但是当数据量达到几十万、几百万甚至上千万的时候,我们就不得不创建索引了。在mysql中 所有的数据都是被存储在配置中的 ,由配置去管理这些内容,因此 即使是我们看,呃,即使这样非常小的一张表。这个school表 ,非常小,它只有三列两行数据,但是它占用的存储空间是96KB。 ,它是16KB的六位,因为在MYSQL中 ,统计数据的占用空间是根据这个配置来计算的。一个配G的大小呢是16KB,如果。一行买折扣的记录是512字节,那么一个配置最多可以存储32条数据。因此我们可以假设这样一个场景 ,在我们这个假设的场景中,如果使用的是SSD硬盘,那么每一次加载数据呢,就相当于是对于IDD硬盘来说,可能要发生32次IO读 ,就是这种即使顺序读吧,才能把这个32条数据加载到。 内存中,但是对于SSSD硬盘来说,它的一次读呢,因为它的快呢是4KB ,相当于它读取的速度会更快。但是SSD的造价也是比较高的 ,这也就是说,呃,为什么SDD硬盘的应用范围是更广。好,我们回过头来。如果这个数据 。呃,都是这样杂乱无章的存储在这些配置中,那么这个查找数据就变成了大问题了,因为我们不知道这个数据究竟是放到哪个配置中,我们也不可能把所有的配置都变了一遍 。因此 ,这个时候我们就联想到了B加速索引,我们可以给ID这一列数据创建索引。当然这个索引呢,它也是要占用物理存储空间的,假设我们这个ID的数据类型是。并呢占用八字节的存储空间,而在in DB中索引指针,它占用的存储空间是六个字节。那么。一行索引占用的空间就是八加六等于14个字节,那么一个P字呢就可以存储。1170条索引。这是个什么概念呢?就相当于我们可以建立一个1170阶的一级索引,1170阶的索引就是指一个配置 ,可以指向1170个叶子节点。 我们就可以构建成,把这构建成这样的一个B加数,本来呀,这个B加数的叶子节点,它是一个单向的列表 ,列单向的链表,但是这个买circle呢,就把它优化成了双向链表,双向链表的好处我就不给大家说了 。我们想象一下,如果每个叶子节点可以存储32行记录,那么一级索引就可以 ,索引到1170乘以32等于37440条数据。而现在的数高仅仅是二。可见这个B加树 是一棵矮树,树的高度越矮的话,那么查找效率就越高。比如我们现在要查找的目标元素ID等于34,找这个数据。 那么在第一次发生IO磁盘操作的时候,他首先要访问根节点,把根节点,也就是这个一级索引加载到内存中。 ,也就是加载到buffer,把这个加载到buffer铺中,因为34 它是在33和64之间,因此就会在内存中去顺序查找,找到根节点,这个是33。然后访问根据点33指向的。这个叶子节点。现在呢?发生第二次操作,将这个月子节点的数据内容全部加载到内存中。然后顺序遍历叶子节点的顺序。找到,一直找到ID等于34这条数据为止。可见 ,现在仅仅发生了两次磁盘的IO操作。就找到了我们想要的目标数据。可见这个查找效率呢还是非常高的,在里边的这个都是发生的内存的顺序查找。想象一下,如果我们的数据不仅仅只有37000条,可能远远大于37000条。 这个时候呢,我们 ,就会联想到可以创建二级索引。二级索引呢的每个索引内容 ,存储的都是索引值,因此它也可以最多存储 1170个索引。去指向1170个子节点。二级索引呢,那么它就可以存储多少条数据呢?就是1170乘以1170,再乘以32, ,这是4300万条数据,相当于到了四千万级别的这个数据量。而每个二级索引呢,它又可以指向1170个一级索引 。而每个一级索引呢,又可以指向1170个叶子节点,这样呢,我们就把一个B加数给它构建完了。这时树的高度是三。如果我们现在要做一个范围查找,想查找ID在34到64之间的数据。 首先呢,它是将根节点加载到内存中,然后找到34所属的根节点一。然后找到根据点一指向的一级索引。将一级索引的内容加载到内存中,这是发生了第二次IO操作。在一级索引中呢,顺序查找34所属的这个索引33,然后把33指向的叶子节点再次加载到内存中。然后在内存中进行顺序查找,当找到目标节点是34 的时候呢,然后开始顺序向后遍历,一直变利到。64为止。 这都是内存便利。如果我们现在。查找的范围呢,扩大一些,比如说在66,最大值是66,那么他就通过这个指针再去找下一个配置的内容,然后去顺序读。可见 ,即使在这种千万级别的MYSQL表中,如果要想查找某条数据,或者用范围查找所花费的IO,也仅仅就是三次就可以做到。B加速呢?所有的索引查询发生的IO次数 ,都是树的高度。这就是B加数给我们带来的便利。B加数仅仅在叶子节点上存储数据,非叶子节点呢,存储的都是索引的信息。 因此呢,这个非叶节点占用的空间也不大。但是这也毕竟是占用空间 。因此。B加速呢,它也是一种用空间换时间的做法,用空间换时间的这种做法在计算机领域是非常普遍的。比如我们前面给大家讲解的跳跃表的原理,也是用空间换时间的做法。关于必加数呢?我们后面会逐渐给大家介绍B加处的插入删除操作,以及买收购表的索引失效的原因。

第一次在公司用git克隆项目办法

一、前言 首先,今天是入公司第一次在工作中使用git进行版本控制,留下一些笔记方便忘记时查看,笔记写的不好,各位大佬见笑,有些不对的望指正。 二、我们直奔主题 进入公司后,如果项目经理给你一个gitee的仓库地址,你需要先将项目克隆下来,完成任务后在进行上传即可。 首先,需要下载一个git的官方安装程序 官方网址:https://git-scm.com/ 如下图红框圈住的地方点进去, 我们会发现32位以及64位的选择电脑对应的位数即可,点击后就进行下载了。 下图就是下载后的一个文件,我没有用上图的新版本,这里注意辨别。 右键以管理员身份运行,然后无脑下一步即可,如果想切换其他盘符进行安装注意中间的安装中修改就好,这里就不截图了。 安装好后,新创建一个文件夹用来当你的本地克隆仓库(当然你可以在任何地方),在创建好的文件夹右键,会弹出如下图的两个git相关的小功能。 第一个是啥我也不清楚(哈哈哈哈) 我们一般都是使用第二个进行相关的操作,然后我们点击第二个Git Bash Here 会弹出如下的界面。 此时我们就可以进行项目经理给的gitee(码云)地址进行克隆仓库了,这一步很简单只需要输入 git clone [这里时你要下载的地址] 注意没有那个中括号 下图就时我自己的一个仓库地址,当出现如下图的情况时就是成功克隆仓库到本地了,你会发现他会生成在你右键点击git的文件夹中,我们通过cd指令切换到仓库中 ,会发现右侧有一个master的英文单词,这就表示我们成功的变成了一个本地的仓库。 这里我们注意一下,如果是第一次进行克隆文件需要先进行ssh公钥的设置,不配置的话每次上传文件到远程仓库都需要用户名和密码,点击主页的设置小图标就会如下图页面, 点击SSH公钥进去,如下图,点击怎样生成公钥就有具体的步骤这里我不做截图自行前往官网观看。 或者直接参考如下步骤 第一步: $ ssh-keygen -t rsa -C “自己的邮箱地址” 第二步: 一般情况本地密匙会生成到 C:\Users\Administrator.ssh 目录下,里面有公匙和私匙,私匙不能 泄露,公匙可以对外使用。 第三步: 将公匙.pub里面的内容设置到gitee里面即可,如下图位置。 还有一点可能会弹出如下图类似错误的东西,这里不是我们公钥设置不成功,而是windows拥有更安全的密码保护机制,将密码存储在 Windows 作位系统内建的 Windows Credential Store 存储仓中 (认证管理员),这里注意一定要正确输入你的gitee账号以及密码,不然会下载失败且不容易更改回来。 不过如果输入错误也可以更改,下面我来介绍下更改方法 搜索 凭据管理器点击进去,然后如下图点击Windows凭据删除下面git相关的凭据重新克隆输入密码即可。 以上就完成了最基本的仓库克隆以及git的凭据与SSH公钥设置。 接下来就是最基本的用户名以及邮箱设置到git中,通过如下指令便可进行设置 用户名和邮箱设置 git config --global user.name “Your Name” git config --global user.email “email@example.com” 接下来就是最关键的 1.将创建的文件加入到暂存区(缓存) git add ·[你要上传的文件全名包括后缀]

Android上图片文字识别

前言 OCR 是 Optical Character Recognition 的缩写,翻译为光学字符识别,指的是针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术(好吧,这是我查来的)。简单的来说,OCR技术就是可以把图片上的文字识别出来,并以文本格式的形式提取出来。 这个技术的应用方面很广泛,比如说把纸质书籍的内容转化为电子书,之前都需要人手打,但是现在只要扫描一下,将扫描出来的图片通过OCR技术转化成文本格式,效率和成本不知提升了多少倍。 可运行的步骤 1、添加依赖 implementation "com.rmtheis:tess-two:8.0.0" 2、下载字体识别库(chi_sim.traineddata 中文简体,chi_tra.traineddata 中文繁体,eng.traineddata 英文库) 3、为了apk的大小,我们需要将字体识别库文件拷贝到SD卡目录中,比如eng.traineddata的copy private String mDataPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator; private String mFilePath = mDataPath + File.separator + "tessdata" + File.separator + "eng.traineddata"; private void copyFile() { try { File mFile = new File(mFilePath); if (mFile.exists()) { mFile.delete(); } if (!mFile.exists()) { File p = new File(mFile.getParent()); if (!p.exists()) { p.mkdirs(); } try { mFile.createNewFile(); } catch (IOException e) { e.

C/C++删除目录文件夹下所有文件(递归)

一 问题 想要删除目录文件夹,类似于rm -r的操作 方式1:可以使用system直接执行rm -r的指令,system("rm -r ***");方式2:通过C语言内置的函数remove和rmdir来实现,但是linux下remove只能删除文件,rmdir指令只能删除空文件夹,因此无法删除具有子目录、子文件的目录/文件夹 二 方法 根据上一篇博客的读取文件的内容,递归删除文件夹下的所有文件 首先不断获取子目录下的文件,将文件删除,而后删除空文件夹,不断递归删除。 /** * @brief DeleteFolderRecurse 删除目录及其所有子文件、子文件夹 * @param sdir * @return */ bool DeleteFolderRecurse(const std::string& sdir = ".") { DIR* dp; struct dirent* dirp; std::string sub_directories; if ((dp = opendir(sdir.c_str())) != NULL) { while ((dirp = readdir(dp)) != NULL) { if (strcmp(".", dirp->d_name) == 0 || strcmp("..", dirp->d_name) == 0) continue; if (dirp->d_type == DT_DIR) { sub_directories = (sdir + "

Android---系统启动流程

目录 Android 系统启动流程 init 进程分析 init.rc 解析 Zygote 概叙 Zygote 触发过程 Zygote 启动过程 什么时Runtime? System Server 启动流程 Fork 函数 总结 面试题 Android 是 google 公司开发的一款基于 Linux 的开源操作系统。 Android 系统启动流程 android 系统启动的大概流程如下图所示: 第一步:启动电源以及系统启动 当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到 RAM,然后执行。 第二步:引导程序 引导程序是在 Android 操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如 reboot, uboot, qibootloader 或者开发自己的引导程序,它不是 Android 操作系统的一部分。引导程序是 OEM 厂商或者运营商加锁和限制的地方。 引导程序分两个阶段执行: 第一阶段:检测外部的RAM以及加载第二阶段有用的程序。 第二阶段:引导程序设置网络、内存等等。这些对于运行内核是必须的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。 Android 引导程序可以在 \bootable\bootloader\regacy\usbloader 找到。传统的加载器包含两个文件,需要在这里说明: init.s 初始化堆栈,清零 BBS 段,调用 main.c 的 main() 函数; main.c 初始化硬件(闹钟、主板、键盘、控制台) ,创建 linux 标签 第三步:内核(Kernel) Android 内核与桌面 linux 内核启动方式差不多。内核启动时,设置缓存、保护存储器、计划列表、加载驱动。当内核完成系统设置,它首先在系统文件种寻找 "

virtualbox 开启虚拟化支持kvm VT-x/AMD-V 功能

在virtualbox的 设置->系统->处理器中想要打开“启用嵌套VT-x/AMD-V 功能”时,发现是灰色的无法选择,但既然有这个选项一定有可以开启的方法。 此处需要在命令行里输入如下内容: VBoxManage.exe modifyvm "ubuntu20.04" --nested-hw-virt on 下面是一个对windows操作不熟悉的程序员的操作过程,请参考: PS C:\Users\tariq> D:\Program Files\Oracle\VirtualBox\VBoxManage.exe modifyvm "ubuntu20.04" --nested-hw-virt on D:\Program : 无法将“D:\Program”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请 确保路径正确,然后再试一次。 所在位置 行:1 字符: 1 + D:\Program Files\Oracle\VirtualBox\VBoxManage.exe modifyvm "ubuntu20. ... + ~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (D:\Program:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException PS C:\Users\tariq> d: PS D:\> cd Program Files\Oracle\VirtualBox Set-Location : 找不到接受实际参数“Files\Oracle\VirtualBox”的位置形式参数。 所在位置 行:1 字符: 1 + cd Program Files\Oracle\VirtualBox + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Set-Location],ParameterBindingException + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.

idea中GIT拉取代码失败

可能是pull代码的时候网络中断了一下,然后后面一直update project failed,而且手动git pull代码是也出现 fatal: bad object refs/remotes/origin/master error: "远程仓库地址"did not send all necessary objects 解决方法: 方法一: // 进去该项目下的.git文件内的本地远程分支目录 cd .git/logs/refs/remotes/origin/ // 删除该错误的本地远程分支 rm -rf xxx 方法二: 直接到该项目下,手动进入.git/logs/refs/remotes/orgin/目录下,将里边的远程分支删除 后续再pull代码即可成功 

【已解决】python openpyxl处理excel后原文档图片丢失问题

使用openpyxl打开一个excel并编辑其中的文字,存储或另存为以后,原有的图片丢失 原因:openpyxl使用到了Pillow来处理图片。如果电脑上没有安装Pillow,它就无法对图片进行处理。故会丢失图片 解决方案:安装Pillow库即可 pip install Pillow

Flume与Kafka的集成

1.flume/conf目录下创建flume与kafka的集成配置文件flume-kafka.conf a1.sources = r1 a1.sinks = k1 a1.channels = c1 a1.sources.r1.type = exec a1.sources.r1.command = tail -F /opt/flume/flume.log a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.bootstrap.servers = node01:9092,node02:9092,node03:9092 a1.sinks.k1.kafka.topic = englishscore a1.sinks.k1.kafka.flumeBatchSize = 20 a1.sinks.k1.kafka.producer.acks = 1 a1.sinks.k1.kafka.producer.linger.ms = 1 a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 100 a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 2.创建文件/opt/flume/flume.log touch /opt/flume/flume.log ls /opt/flume 3.启动flume与kafka的集成方案 bin/flume-ng agent -c conf/ -n a1 -f conf/flume-kafka.conf 4.运行CustomConsumer2消费者代码程序,截图如下 5.向/opt/flume/flume.log 里追加数据 echo "

Kafka消费者API的应用

需求:使用Kafka消费者API分别完成自动提交offset、手动同步提交offset和手动异步提交offset方式消费主题englishscore中的消息,并打印消费消息的offset、键和值的信息 编写Kafka消费者API分别完成自动提交offset并打印消费消息的offset、键和值的信息。创建类CustomConsumer完成此功能,编写此类的代码 package cn.lesson; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.Arrays; import java.util.Properties; public class CustomConsumer { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092"); props.put("group.id", "test020"); props.put("enable.auto.commit", "true"); //earliest //当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费 //latest //当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据 //none //topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常 props.put("auto.offset.reset", "earliest"); props.put("auto.commit.interval.ms", "1000"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props); consumer.subscribe(Arrays.asList("englishscore")); while (true) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) System.

Kafka生产者API的应用

在Kafka集群中创建主题名称为englishscore,主题的分区数为3,副本因子为3。分别使用生产者异步不带回调函数的API(前100名学生)、异步带回调函数的API(100~200名学生)、同步AP(200~300名学生)完成学生英语成绩的生产。键为姓名,值为成绩。 启动zookeeper集群 zkServer.sh start 启动kafka集群 cd /opt/kafka bin/kafka-server-start.sh -daemon config/server.properties 创建主题名称为englishscore,主题的分区数为3,副本因子为3 bin/kafka-topics.sh --zookeeper node01:2181,node02:2181 --partitions 3 --replication-factor 3 --create --topic englishscore 查看主题englishscore的详细信息 bin/kafka-topics.sh --zookeeper node01:2181,node02:2181 --describe --topic englishscore 打开IDEA开发工具,创建项目名称为kafkaApiApp,添加Pom文件 pom文件中添加kafka依赖 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>0.11.0.0</version> </dependency> </dependencies> 创建生产者异步不带回调函数的API(前100名学生)的类CustomProducer 键为zhangsan+序号,值为100以内的随机数 package cn.lesson; import org.apache.kafka.clients.producer.*; import java.util.Properties; import java.util.Random; public class CustomProducer { public static void main(String[] args) { Random random = new Random(); Properties props = new Properties(); //kafka 集群,broker-list props.

最新stm32毕设100例(四)

【单片机毕业设计项目分享系列】 🔥 这里是DD学长,单片机毕业设计及享100例系列的第一篇,目的是分享高质量的毕设作品给大家,包含全面内容:源码+原理图+PCB+实物演示+论文。 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的单片机项目缺少创新和亮点,往往达不到毕业答辩的要求,为此学长准备了相对容易且工作量达标,并包含创新点的项目分享给大家。 🧿 整理的题目标准: 相对容易工作量达标题目新颖,含创新点 🧿 项目分享: https://gitee.com/sinonfin/sharing 课题项目1 :STM32的FRID高速收费系统 主要功能: 一款基于STM32的FRID高速收费系统,可以实现小车和货车两种车型收费,当车辆超过了规定的重量后,出现声光报警提示,并且启动杆不会抬起,只有当车辆重量低于设置值时,启动杆才会自动抬起,当启动杆抬起后,开始计费,直到车辆驶离高速。 1、车辆称重,2个分区(小车:1kg以内、货车:2kg以内,利用按键选择),超重无法上高速,并声光报警。 2、刷卡之后杆子自动抬起落下(四相步进机),防追杆。功能,前车过去,闸门才自动落下(分离式红外对管) 3、刷卡后,开始时间计费(小车1元/分钟,货车2元/分钟)。 4、如果车辆长时间不出高速,会报警提示值班人员,对高速进行排查。 5、通过按键设置各阈值(超载值、计费单价、时长) 6、通过显示屏显示数据 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目2:STM32的wifi照明控制系统 主要功能: 此路灯系统使用STM32为主控制器,有两种工作模式,分别是手动模式和自动模式。 自动模式:使用光敏电阻模块采集环境亮度值和使用SR501检测人体,当环境亮度值较低且检测到人体的时候,灯会自动打开,且会根据环境亮度值的不同,灯光亮度会自动调节。 手动模式:通过按键控制灯的亮灭,使用按键调整灯光亮度,有三个档位可选择。 1.使用STM32F103C8T6单片机做主控制器。 2.使用OLED显示灯的状态、工作模式、环境亮度值、灯的档位。 3.使用WiFi模块(ESP-01)连接手机,可在手机端控制灯的状态、工作模式、工作档位。且采集的亮度值会上传至手机端。 4.使用光敏电阻模块采集当前环境的亮度值。 5.使用L298N驱动模块驱动路灯。 6.使用SR501传感器检测人体。 7.三个按键可控制灯的亮灭、工作模式、工作档位。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目3:STM32的智能饮水机控制系统 主要功能: 使用STM32为主控制器,LCD1602显示当前信息:水温、模式、设置水温。DS18b20检测当前饮水机水温,水位传感器检测是否有水,无水情况下蜂鸣器发出声光报警,且所有功能停止(防干烧)并显示:Water!(提醒加水)。 1.使用STM32F103C8T6单片机做主控制器。2.使用LCD1602显示采集到的水温、模式、设置水温值。3.使用DS18b20检测当前饮水机水温值。4.使用水位传感器检测是否有水。5.使用继电器控制加热片加热和水泵出水。6.当无水的情况下,蜂鸣器进行声光报警提醒,并且停止所有的功能,直到检测到有水。7.四个按键分别对应:加热、出水,温度加、温度减的功能。Normal:常温模式Water:缺水警告Hot:加热模式open:水泵出水 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目4:单片机恒温箱控制系统 主要功能:将温度控制在一个范围内,恒定温度的作用。使用DS18B20采集温度,当温度过高时,会自动降温,当温度过低时,会自动升温。让温度一直恒定在设置的范围内。 1.使用STC89C52RC单片机做主控制器。 2.使用LCD1602实时显示当前温度值、温度上限值、温度下限值。 3.使用DS18B20采集当前环境温度值。 4.使用三个按键可任意调整上下限阀值。 5.当温度超过了预设上下值时,蜂鸣器会自动报警,且会自动打开升温或降温的继电器,继电器会带动加热片加热或制冷片制冷。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 课题项目5:单片机酒驾酒精检测系统 主要功能有: 1.使用MQ-3检测驾驶人员是否存在酒驾行为。 2.使用LCD1602实时显示驾驶人员体内酒精含量,当驾驶人员体内酒精含量超过了预设阈值,蜂鸣器会自动进行报警,伴随红色指示灯点亮,继电器吸合。 3.单片机:将采集到的酒精含量送至显示屏,并与阀值进行比较,超标报警,未超标绿色指示灯常亮,表示可以通行。 4.阀值设置按键:报警阀值可通过三个按键进行任意调整。 5.继电器:模拟自动熄火装置,当酒精含量超标时,继电器自动吸合,模拟汽车自动熄火。 6.蜂鸣器报警:当检测到酒精含量超标后,蜂鸣器自动报警(并且红色指示灯点亮,表示不可通行)。 本设计主要由酒精探测传感器电路、单片机、灯光报警电路、负载驱动电路、控制程序和编解码程序等组成。: 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档 🥇项目综合综合评分(每项满分5分) 难度系数:3分工作量:4分创新点:4分 🧿 项目分享:

【ThreeJs】如何给模型打上文字标签?

一、概述 ThreeJs渲染中创建的网格模型,有时候我们需要给模型添加标签文字,方便识别不同的物体。 这时候我们可以使用CSS3DRenderer、CSS2DRenderer这两个库,里面提供了三种打标签的方式,随着相机角度的变化,三种标签的显示效果各不相同。 三种标签分别是: CSS 2DObject、CSS 3DObject 标签、CSS 3DSprite 标签 二、效果预览 1、角度不同 下面是从不同角度看同一组模型时的显示效果: 2、距离不同 这是前后两组模型的显示效果: 3、区别简述 可以看到,CSS 2DObject、CSS 3DSprite都可以让标签永远正对当前相机视角。不同的是,CSS 2DObject标签的尺寸不会受远近影响;CSS 3DSprite标签的尺寸受远近影响,远小近大; CSS 3DObject 标签朝向固定,不会随视角变化而改变,就仿佛是创建的模型对象,但实际这三种标签都是使用html+css来实现的,并且CSS 3DObject标签的大小也会受远近影响,远小近大。 三、代码实现 tag2D.js【创建CSS2DObject】 import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'; // 创建一个HTML标签 function tag(name) { // 创建div元素(作为标签) var div = document.createElement('div'); div.innerHTML = name; div.classList.add('tag'); //div元素包装为CSS2模型对象CSS2DObject var label = new CSS2DObject(div); div.style.pointerEvents = 'none';//避免HTML标签遮挡三维场景的鼠标事件 // 设置HTML元素标签在three.js世界坐标中位置 // label.position.set(x, y, z); return label;//返回CSS2模型标签 } // 创建一个CSS2渲染器CSS2DRenderer function labelRenderer(container) { var labelRenderer = new CSS2DRenderer(); labelRenderer.

在cmd中转到某一目录下及一些命令行操作

​在cmd中转到某一目录 win + E 打开文件资源管理器 找到你向转入的目录 单击上方地址栏(左键以下就好,为全选中状态),输入cmd,回车 一些 Windows 命令提示符(Command Prompt)中常用的命令和操作 cd进入指定目录。例如,cd C:\Users 可以进入 C:\Users 目录dir列出当前目录下的所有文件和子目录。例如,dir 可以列出当前目录下所有的文件和子目录cls清除命令提示符窗口上的所有文本。例如,cls 可以清除窗口上的所有文本exit退出命令提示符窗口。例如,exit 可以退出当前的命令提示符窗口。md创建新目录。例如,md C:\mydir 可以在 C 盘根目录下创建名为 mydir 的新目录。rd删除指定目录。例如,rd C:\mydir 可以删除 C 盘根目录下名为 mydir 的目录。copy复制文件。例如,copy C:\myfile.txt D:\ 可以将 C 盘根目录下的 myfile.txt 文件复制到 D 盘根目录下。xcopy复制目录及其内容。例如,xcopy C:\mydir D:\ /s /e 可以将 C 盘根目录下的 mydir 目录及其所有子目录和文件复制到 D 盘根目录下。del删除文件。例如,del C:\myfile.txt 可以删除 C 盘根目录下的 myfile.txt 文件。ren重命名文件或目录。例如,ren C:\myfile.txt newfile.txt 可以将 C 盘根目录下的 myfile.txt 文件重命名为 newfile.txt。tasklist列出当前正在运行的所有进程。例如,tasklist 可以列出当前正在运行的所有进程。taskkill结束指定的进程。例如,taskkill /IM notepad.exe /F 可以强制结束所有名为 notepad.

使用Docker运行Jenkins容器,并构建Maven项目,自动部署

准备Docker环境: Linux安装Docker(Centos)_Broad sky的博客-CSDN博客 安装JDK、Maven、Git 1.安装JDK: 官网下载地址: Java Downloads | Oracle 中国 # 解压缩 sudo tar -zxvf jdk-8u361-linux-x64.tar.gz # 配置环境变量 vi /etc/profile # 在文件最后插入下面这段 JAVA_HOME=/usr/local/java/jdk1.8.0_361 PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME PATH # 保存退出后重新加载配置 source /etc/profile # 测试 java -version 1.安装maven: 重点:maven去官网下载后扔到服务器解压,用这种方式安装。不要用yum的方式安装,挂载到jenkins容器会不识别!!!重要的事情说三遍: Maven不要用yum的方式安装,挂载到jenkins容器会不识别!!! Maven不要用yum的方式安装,挂载到jenkins容器会不识别!!! Maven不要用yum的方式安装,挂载到jenkins容器会不识别!!! Maven官网:Maven – Download Apache Maven # 解压缩,一般放在/usr/local/maven下 sudo tar -zxvf apache-maven-3.9.0-bin.tar.gz # 配置环境变量 vi /etc/profile # 在文件最后插入下面这段 MAVEN_HOME=/usr/local/maven/apache-maven-3.9.0 PATH=$MAVEN_HOME/bin:$PATH export MAVEN_HOME PATH # 保存退出后重新加载配置 source /etc/profile # 测试 mvn -v maven配置文件这里不多赘述,推荐把依赖库设置在apache-maven-3.