keil5中文乱码

许多同学在使用keil5时,会出现中文注释乱码的情况那是因为我们的配置不对: 下面我们来解决一下这个问题: 第一步:Eeit -> Configuration 第二步:Editor -> Encoding 这里就可以修改我们的中文格式 一般情况下你在什么格式下输入中文,在该模式下就会显示中文,但更换到其他格式后就会出现乱码的情况 但如果是在网上复制粘贴过来的中文显示乱码,就可以将格式改为Chinese GB2312(Simplified) 这样就不会再出现乱码了. 进入我们的设置界面其实还有一个简单的途径(点击图中的小扳手就可以跳转到我们的设置界面了)

小学生都听得懂的数据库范式

什么是范式? 数据库就像是一个巨大的文件柜,用来存储很多信息。这些信息被组织成很多小表格。而在数据库的世界里,我们有一些规则来确保这些表格整齐、有序,不会乱七八糟。这些规则就叫做范式。 范式就像我们要求字写得工整、清晰、有条理一样,是一种让数据库变得更加规范和整洁的方法。范式有很多级别,每个级别都有自己的标准和要求。 第一范式要求每个属性都是原子性的,不能再分解成更小的部分。就像我们写字一样,每个字只能由一个个笔画组成,不能再分解成更小的部分。第二范式要求每个非主键属性都完全依赖于主键。就像我们写信需要写上地址,才能保证信能准确到达收件人。第三范式要求每个非主键属性都不依赖于其他非主键属性,就像我们写信的时候,信封上只需要写上一个地址就可以了,不需要写上其他无关的信息。第四范式要要求每个非主键属性都与主键直接相关,而不是间接相关。就像我们在学习时,需要直接学习相关的知识点,而不是先学习一些无关的知识点再间接地学习相关的知识点。 详细解释什么是第一范式(1NF) 比如,我们有一张学生表,其中一个字段是地址。如果我们把地址拆分成省份、城市、街道、门牌号等多个字段存储,那么这就不符合第一范式的要求了,因为地址被分解成了多个部分,不再是原子性的了。正确的做法是把地址作为一个属性,存储为一个完整的字符串。 详细解释什么是第二范式(2NF) 什么是函数依赖? 函数依赖是指在一个关系中,一个或多个属性的值可以唯一地决定另一个属性的值。就像我们在算数中,如果我们知道了某些数字的值,就可以唯一地确定另一个数字的值。 举个例子,假设我们有一个学生表,其中包括学生姓名、年龄、班级、学号等字段。我们可以发现,一个学生的学号是唯一的,并且可以唯一地确定该学生的姓名、年龄、班级等信息。而反过来,如果我们只知道一个学生的姓名、年龄、班级等信息,就无法唯一地确定该学生的学号。因此,学号函数依赖于姓名、年龄、班级等属性。 什么是完全函数依赖? 完全函数依赖是指在一个关系中,一个或多个属性的值可以唯一地决定另一个属性的值,且这个属性不依赖于任何一个属性的真子集。我们可以通过一个简单的例子来解释: 假设我们有一个班级表,其中包括学号、姓名、性别、年龄、班级、电话等字段。我们可以发现,一个学生的电话号码可以唯一地确定该学生的信息,包括姓名、性别、年龄、班级等。而反过来,如果我们只知道一个学生的姓名、性别、年龄、班级等信息,就无法唯一地确定该学生的电话号码。但是,如果我们知道了该学生的学号,就可以唯一地确定该学生的电话号码。这就是一个完全函数依赖关系,因为电话号码只依赖于学号这个属性,而不依赖于任何一个属性的真子集。 什么是部分函数依赖? 部分函数依赖是指在一个关系中,一个或多个属性的值可以唯一地决定另一个属性的值,但是这个属性还依赖于其他属性。我们可以通过一个简单的例子来解释: 假设我们有一个订单表,其中包括订单号、客户名称、客户地址、产品名称、数量、单价等字段。我们可以发现,一个订单的客户地址可以唯一地确定该订单的客户名称,但是客户名称还依赖于客户地址和其他属性,比如邮编等。这就是一个部分函数依赖关系,因为客户名称既依赖于客户地址这个属性,又依赖于其他属性。 什么是第二范式? 比如,我们有一张学生成绩表,其中包括学生姓名、课程名称、成绩等字段。如果我们把学生姓名和课程名称合并成一个复合主键,那么成绩就不完全依赖于主键了,因为成绩既依赖于学生姓名,又依赖于课程名称。正确的做法是把学生姓名和课程名称分别作为主键和外键,成绩作为非主键属性。 详细解释什么是第三范式(3NF) 比如,我们有一张订单表,其中包括订单号、客户名称、产品名称、数量、单价等字段。如果我们在表中存储了订单总价这个计算属性,那么它就不符合第三范式的要求了,因为订单总价依赖于数量和单价两个非主键属性。正确的做法是将订单总价作为一个视图或者计算字段来展示,不存储在表中。 详细解释什么是第四范式(4NF) 比如,我们有一张部门表和员工表,其中部门表的主键是部门编号,员工表的主键是员工编号,部门表和员工表之间通过部门编号建立了关联。如果我们在员工表中存储部门名称这个属性,那么它就不符合第四范式的要求了,因为部门名称与主键部门编号只是间接相关,并不直接相关。正确的做法是在查询时将部门名称通过关联查询获得,而不是存储在员工表中。

手动创建数据集(csv文件),用于Pytorch深度学习

文章目录 基础知识创建多级目录多级路径拼接打开文件并对文件进行读写 创建CSV数据集的简单例子 基础知识 创建多级目录 os.makedirs()是Python中一个用于创建多级目录的函数,如果指定的目录不存在,则会递归地创建它。 函数定义如下: os.makedirs(name, mode=0o777, exist_ok=False) 参数说明: name: 要创建的目录的路径。可以是绝对路径或相对路径。如果包含多级目录,且其中某一级目录不存在,函数将会递归创建该目录及其所有父目录。mode: 可选参数,指定目录权限。默认值为0o777,即最大权限。(这个参数在Windows系统上不起作用)。exist_ok: 可选参数,指定当目录已经存在时是否抛出异常。如果设置为True,则不会抛出异常;如果设置为False,则会抛出FileExistsError异常。默认值为False。 多级路径拼接 在Python的os模块中,os.path.join()函数是用来拼接路径的函数。这个函数可以将多个字符串拼接成一个路径,保证路径的正确性,适用于各种操作系统。 os.path.join(path1[, path2[, ...]]) 返回值:将多个路径组合后返回一个新的路径字符串。 使用示例: import os # 用os.path.join()函数将多个路径拼接成一个完整的路径 path = os.path.join('Users', 'tom', 'Documents', 'file.txt') print(path) # 输出:Users/tom/Documents/file.txt 上面的示例中,我们将多个路径片段拼接起来,并使用os.path.join()函数生成一个完整的路径。注意,在不同操作系统上生成的路径可能会有所不同,但使用os.path.join()函数可以保证生成的路径是正确的。 打开文件并对文件进行读写 在Python中,使用with open as语句可以方便地打开文件并进行读写操作。这种语法可以让我们不用手动地打开和关闭文件,而是在语句块结束时自动关闭文件,从而避免了因忘记关闭文件而导致的资源泄漏和其他问题。 使用with open as语句的一般形式如下: with open(filename, mode) as file: # 在语句块中进行文件操作 其中,filename是要打开的文件名,可以是相对路径或绝对路径;mode是打开文件的模式,可以是’r’(只读模式)、‘w’(覆盖写入模式)、‘a’(追加写入模式)等等。 在with open as语句块中,我们可以使用file这个文件对象进行文件操作,例如读取文件内容、写入文件等等。在语句块结束时,Python会自动关闭文件。 创建CSV数据集的简单例子 import os os.makedirs(os.path.join('..', 'data'), exist_ok=True) data_file = os.path.join('..', 'data', 'house_tiny.csv') with open(data_file, 'w') as f: f.

淘宝购物车页面实现

代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>淘宝购物车页面实现</title> <style> .Tbsl{ background-color: #FFFFFF; height: 80px; margin: 0px 0px 24px; } .box{ text-align: center; overflow: hidden; } button{ height: 18px; width: 22px; text-align: center; border: #F5F5F5; } </style> </head> <body> <table> <tr> <td width="68%"><img src="TB1R5fsgyDsXe8jSZR0XXXK6FXa-281-80.jpg" /> </td> <td> <div id="Tbsl"> <select style=" outline: none; width:50px;height:32px;border: 3px solid orangered;border-right: none;color: gainsboro;"> <option selected="selected" disabled="disabled">宝贝</option> <optgroup label="鞋靴"> <option value="1">单鞋</option> <option value="2" >运动鞋</option> <option value="

VMware:最小化安装 centos 并联外网

VMware可以在官网下载,具体地址为:https://www.vmware.com/cn/products/workstation-pro/workstation-pro-evaluation.html centos下载地址为:CentOS Linux 点进去找个镜像url选个最小化包(mini版本)下载 下载完后就安装Vmware,然后新建虚拟机,典型安装,选择centos包配置参数即可,具体如下: BIOS里CPU开启了虚拟化的话可以开启VMware的虚拟化,这样可以提高虚拟化性能,不然这个虚拟化引擎白加了。 新建好虚拟机就安装centos,基本是选中文一路next,选择自动分区、填好root密码即可。 安装完重启后,就能登录centos了,这时发现ifconfig等命令无法使用,需要联网安装一些包。但由于centos默认启动是不开启network的,需要修改其配置文件重启network即可。 具体如下: 1、cd /etc/sysconfig/network-scripts 修改ifcfg-ens33(每台机子的这个文件名可能不一样,但可以查看文件内容),将ONBOOT=no改为ONBOOT=yes 改好后启动 network即可:service network restart 最后ping通百度,说明已连外网了

Nginx代理后获取客户端真实IP地址

1、场景 在项目实际应用中,我们可能会需要获取到用户也就是客户端的真实IP地址,比如记录系统操作日志等情况。 2、使用 通常情况下我们可以使用以下方式来获取IP地址 request.getRemoteAddr() 但是当我们使用Nginx反向代理项目地址后,使用以上方法只能获取到Nginx服务器的IP地址,并不是客户端的IP地址。 3、解决 解决方法很简单,同样也是在Nginx中进行配置,然后在Java中获取即可。 首先在nginx.conf配置中添加一行即可: proxy_set_header X-Real-IP $remote_addr; 添加位置如下: 可以看到我这里还添加了其他的 proxy_set_header 配置,后面都可以自行打印看下效果。 接下来就是在程序中获取真实IP地址了,使用以下代码即可获取到: String realIP = request.getHeader("X-Real-IP"); 注意:getHeader()中的参数名就是nginx.conf中配置的名字 4、解释 一个请求肯定是可以分为请求头和请求体的,而我们客户端的IP地址信息一般都是存储在请求头里的。而 proxy_set_header 语法就是允许重新定义或者添加发往后端服务器的请求头,所以在 java端,需要获取 proxy_set_header 的参数时,需要使用 request.getHeader()。

element-plus 将语言设置为中文

<!-- App.vue --> <template> <el-config-provider :locale="locale"> <router-view/> </el-config-provider> </template> <script lang="ts"> import { ElConfigProvider } from 'element-plus' import zhCn from 'element-plus/lib/locale/lang/zh-cn' export default { components: { [ElConfigProvider.name]: ElConfigProvider }, setup() { // 切换为中文 let locale = zhCn; return { locale } } } </script>

OpenGL原理与实践——核心模式(一):VBO、VAO等原理解析及项目初始设置

目录 序言——OpenGL在是什么?为什么?做什么? OpenGL实现了什么 OpenGL内模型数据的本质——顶点数据 我们需要研究什么——三角形,一个图形基元 MVP变换 OpenGL渲染流程的关键——摄像机变换 OpenGL渲染管线概览 准备——项目配置 项目初始代码框架及注释 初识——三角形绘制 OpenGL中的顶点数据格式——float数组 OpenGL中shader如何从CPU中获取数据——layout(锚点) Shader VBO:Vertex Buffer Object VAO:解决锚点问题,记录了VBO的锚点信息 编译shader 设定VAO并进行渲染 整体源码 序言——OpenGL在是什么?为什么?做什么? OpenGL实现了什么 将三维物体映射到视线方向上的一个裁剪空间(屏幕)上 OpenGL内模型数据的本质——顶点数据 我们需要研究什么——三角形,一个图形基元 MVP变换 OpenGL渲染流程的关键——摄像机变换 OpenGL渲染管线概览 准备——项目配置 GLFW Download | GLFW GLAD https://glad.dav1d.de 下载后,进行相应配置。 项目初始代码框架及注释 #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } } int main() { //初始化OpenGL上下文环境,OpenGL是一个状态机,会保存当前状态下的渲染状态以及管线的状态 glfwInit(); //,3版本以上 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //用OpenGL核心开发模式 glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE); //创建窗体 GLFWwindow* window = glfwCreateWindow(800, 600, "

es数据库基本操作

1.es建立索引: curl -XPUT 'http://10.xx.xx.xx:9200/索引名称' 2.es查询所有索引: curl -XGET 'http://10.xx.xx.xx:9200/_cat/indices?v' 3.es查询单个索引内容: curl -XGET 'http://10.xx.xx.xx:9200/索引名称/_search?pretty=true' 还有一种带时间的情况> curl -XGET 'http://10.xx.xx.xx:9200/索引名称-2018-08-01/_search?pretty=true' 4.es删除某个索引下的内容 curl -XDELETE 'http://10.xx.xx.xx:9200/索引名称?pretty' 以上是linux命令行操作,如果是连接内网的情况下,直接将引号的内容复制到浏览器请求就可以返回数据, 查看效果比linux好。

css优化--vue2和vue3中虚拟滚动,懒加载实现

重绘(repaint):只是当页面的颜色、透明度等信息发生变化时会导致重绘。例如:color、background-color、visibility等,结构不变。 回流、重排(reflow):整个dom树重新渲染。 假设实际开发中服务端一次响应10万条列表数据,此时设备屏幕只允许容纳10条,那么用户理论上只可以看见10条数据。此时如果前端将10万条数据全部渲染成DOM元素,可能造成程序卡顿,占用较大资源,非常影响用户体验,那么虚拟滚动技术就完美的解决了这一问题。 【虚拟滚动的实现】 1、获取滚动高度 2、列表单个item的高度 3、计算屏幕容纳几个item 4、计算滚动了几个item到顶部不可见区域 5、使用css3的transform属性将滚动到上方不可见区域的DOM元素偏移到可见区域,同时进行数据的更新(重绘操作节约性能)。 使用 react,vue 等页面框架来编写 view 页面,采用虚拟 DOM 技术,极可能的将多次重排浓缩成一次 vue2代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- import CSS --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script> <!-- import JavaScript --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <title>虚拟滚动原理</title> </head> <body> <div id="app"> <el-row :gutter="10"> <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2"> <el-button type="danger" @click="virtualScrolling(20)">20条</el-button> </el-col> <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2"> <el-button type="primary" @click="virtualScrolling(100)">一百条</el-button> </el-col> <el-col :xs="6" :sm="6" :md="5" :lg="

【Java基础】之AWT,一篇文章搞懂awt(包含绘图)

🌈博客主页:屠一乐的博客 📅 发文时间:2022.3.15 🎈 一定存在只有你才能做成的事 🌹 博主水平有限,如有错误,欢迎指正 欢迎给位👍收藏💎评论✉ Java awt 👑👑 AWT📜📜Java AWT简介 (Introduction to Java AWT)🏮🏮层次结构 (Hierarchy) 💐💐2.4 LayoutManage布局管理器小案例 🌺🌺2.5 AWT中常用组件()🧨🧨乱码问题🎠🎠2.6 事件处理🎧🎧监听器案例菜单小案例🎃🎃绘图案例 👑👑 AWT 📜📜Java AWT简介 (Introduction to Java AWT) Java AWT (Abstract Window Toolkit) package is a library used for designing graphical user interfaces. Java AWT(抽象窗口工具包)软件包是用于设计图形用户界面的库。 It contains classes for placing various user intractable components and graphics. However, the components of this class are platform dependent. They are heavy and rely on the OS for their functioning.

解决:mysql报错ERROR 1049 (42000): Unknown database ‘数据库‘

其实我是犯了一个很严重的错误,报这个错无非就两个原因。 原因一:你的账户密码后面多了一个空格,也就是说你的数据库不对。 解决办法:如果是登录密码的时候就报这个错误,如下图所示: 那么就有可能p和123之间多个一个空格,然后你去掉中间的空格就好了。把p和123连在一起输入就行了p123 原因二:你的语法错了,因为use后面只能是跟数据库名,千万别写表名。写错了或者写成了表名就会报如下的错误。 解决办法:再次检查一下你的数据库,看数据库有没有tb_emp6。 再检查一下你的表,看是不是你的表名。 果然是表名,看来就是表名和数据库名弄混了。 总结就是先确认数据库的库名是不是存在的,有没有拼写错误等,如果没有再就看下你的语法错了没。 这样就比较好定位你的问题,其实说白了这是我犯了一个愚蠢的错误,不过也算吃一斤长一智了。 希望对你有所帮助,谢谢~

找不到vtkCommoncore-8.2.dll,vtkImagingSources.dll问题的解决方法。

如果报错找不到vtkCommoncore-8.2.dll时,在VS2019的调试器里添加: C:/vtk8.2.0/bin是我的VTK用cmake在C:/vtk8.2.0中构建出来的路径。 如果还搞不定,就说明dll路径有问题,VTK中编译好dll文件的没有放进VS中。 在C:\Program Files\VTK\bin中,找到对应的.dll文件,如vtkImagingSources-8.2.dll.dll,复制到路径C:\VTK-8.2.0\bin\bin\Debug下面。就能被VS2019读取了。

台式电脑重装系统失败怎么办

当大家使用一键重装系统软件给自己电脑重装系统的时候,都可能会遇到一些故障问题造成台式电脑重装系统失败的情况发生.那么大家遇到台式电脑重装系统失败怎么办呢?现在小编就教下大家相关的方法教程,大家一起来看看吧。 工具/原料: 系统版本:windows 10系统 品牌型号: 联想(Lenovo)天逸510S 方法/步骤: 1、启动项设置问题 台式电脑重装系统失败怎么办呢?电脑进入系统,但是大家无法使用u盘启动盘或光盘进行重装,或者重装后出现蓝屏的现象,可能是因为主引导记录导致损坏的原因。 解决方法:我们可以通过u盘启动盘来修复系统引导分区。然后设置u盘启动之后,我们接着选择DiskGen磁盘分区管理,右键点击系统安装的磁盘,选择硬盘-重建主引导记录(MBR)即可。检查GHOST系统文件完整是否。方法二: 2、电脑中毒 现在病毒很有可能会通过软跳线的方式,篡改了主板BIOS启动的启动设置等等,这情况重装系统就不一定有用了。 或者我们的电脑灰尘过多,导致硬件接触不良,又或者机器内部器件松动都有可能造成重装失败。 解决方法:我们进入bios设置主页面,然后选择进入“Advanced BIOS Features”设置项界面,将“First Boot Device”将其设置为“CDROM”即可。 3、电脑硬件问题 如果自己电脑灰尘过多的话,硬件接触就会不良,或者是机器内部器件松动都有可能造成重装失败。 解决方法:我们注意需要逐个检测并排查各个硬件的情况等等。 如果是系统兼容问题,建议选择一个U盘制作其它版本的系统U盘,给电脑重新安装上其它版本的系统。 ​

在linux上如何安装docker?

1、切换到root账户,输入su root,再输入密码即可。 2、docker安装要求: Docker要求CentOS系统的内核版本高于 3.10 ,通过 uname -r 命令查看你当前的内核版本是否支持安账docker。 3、输入:sudo yum update 4、输入y,点击确定 5.继续输入y,点击确定 6、输入 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 7、 输入:sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 官网地址 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 阿里云地址 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 8、选择特定版本安装:yum list docker-ce --showduplicates | sort -r 也可以直接安装:sudo yum install 3:19.03.5-3.el7 9、输入:sudo yum install docker-ce-17.12.0.ce,输入y,点击确定 10、 再输入y,点击确定 11、这样就安装好了 12、输入:docker version 13、先输入:sudo systemctl start docker,再输入:sudo systemctl enable docker 14、再次输入:docker version,出现了client和server就代表安装成功了。 15、查看docker启动状态:systemctl status docker(如下图即启动成功) 16、卸载命令: a.查询docker安装过的包:yum list installed | grep docker

解决docker报错Job for docker.service failed because start of the service was attempted too often

docker安装之后重新安装报错如下: Job for docker.service failed because start of the service was attempted too often. See "systemctl status docker.service" and "journalctl -xe" for details. To force a start use "systemctl reset-failed docker.service" followed by "systemctl start docker.service" again. 解决办法:直接把配置文件名称修改一下即可。 1.首先切换为root用户,输入su root,再输入密码即可。 2.进入目录下修改配置文件名称,路径:cd /etc/docker/ 3.查看当前目录的配置文件,输入:ls 4.把daemon.json配置文件改成daemon.conf即可,命令:mv daemon.json daemon.conf。 然后再输入ll,看看有没有修改过来了。 5.重新启动服务,命令:sudo service docker restart 6.然后再docker ps, 运行ok了。 如果上述方法还是不行的话,建议卸载了重新再安装一遍。 1.卸载老版本docker 较旧版本的Docker被称为docker或docker-engine.请卸载它们以及相关的依赖项 $ sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine

全网最详细中英文ChatGPT-API文档(一)开始使用ChatGPT——导言

开始使用ChatGPT导言 Introduction 导言Overview 概述Key concepts 关键概念Prompts and completions 提示和完成Tokens 标记/符号Models 模型Next steps 下一步步骤 其它资料下载 Introduction 导言 Overview 概述 The OpenAI API can be applied to virtually any task that involves understanding or generating natural language or code. We offer a spectrum of models with different levels of power suitable for different tasks, as well as the ability to fine-tune your own custom models. These models can be used for everything from content generation to semantic search and classification.

【小猫爪】AUTOSAR学习笔记10-Communication Stack之CanTsyn模块

【小猫爪】AUTOSAR学习笔记10-Communication Stack之CanTsyn模块 前言1 时间同步的引入2 时间同步的角色3 时间同步过程3.1 四种报文3.2 时间同步过程 END 前言 这一节来稍微介绍一下基于CAN总线实现时间同步的CanTsyn模块。 1 时间同步的引入 时间同步有啥用呢?就拿现在爆火的ADAS来说,域控制器需要融合雷达,摄像头等传感器的数据,然后进行算法融合所有传感器的数据后最终才能进行判断和执行,这个时候就存在一个问题,因为传感器数据并不都是来源于同一个ECU,所以就需要一个手段来保证域控融合的所有传感器数据都是产自同一时刻,所以传感器在向域控制器发送传感数据时都需要加上一个时间戳,所以让车上所有的ECU里面的时间戳都保证一模一样就成了必要的事情。 而CanTsyn模块就是基于CAN总线的时间同步方案,所以它的功能也是非常的简单,就是接收一些时间同步报文,然后根据报文中包含的时间信息获取当前时间。 这里多说一句,还有在Ethernet总线上的负责时间同步的模块叫做EthTSyn模块,这个模块其实就是基于PTP (Precision Time Protocol)协议搞出来的,有的朋友可能还知道gPTP,gPTP其实是PTP协议的一个子集,而EthTSyn模块则是针对汽车应用基于PTP还额外做出一点点改变,感兴趣的朋友可自行搜索一下。 2 时间同步的角色 时间同步框架如下图所示: Time Domain:表示哪些组件(例如节点,通信系统)链接到某个时基。一个时域可以没有、包含一个或多个子时域。如果时域的时序层次结构中不包含时间网关,即所有节点都连接到同一总线系统,则不存在子时域。 Time Subdomain:表示哪些组件(例如节点)链接到某个时基,范围仅限于一条通信总线。 Global Time Master: 在整个Time Domain中提供全局时钟基准的主时钟。 Time Master:在同一个Time Subdomain中提供全局时间基准的主时钟。 Time Gateway:在整个Time Domain中既作为上级时钟源的从时钟,又同时作为下级时钟源的主时钟源。 Time Slave:在一个Time Subdomain中作为需要同步的从时钟。 3 时间同步过程 基于CAN总线的时间同步过程从下至上可分为CANDrv、CanIf、CanTsyn、StbM四个模块,如下: 其中CanTsync模块负责时间同步实现,而StbM则负责抽象基于不同传输介质的AUTOSAR时间同步协议,为整个软件系统来提供时间同步之后的全局时间戳。其他总线原理和过程一样,下面就以CanTsync模块为例说明一下时间同步过程。 3.1 四种报文 在时间同步过程中主要有SYNC、FUP、OFS、OFNS 这四种报文,每一种报文又分为需要校验 CRC 和不需要校验 CRC 两种方式,有无CRC校验由参数CanTSynGlobalTimeTxCrcSecured决定。 在时间同步过程中,SYNC和FUP报文为一组,需要成对发送和接收,其格式如下: 报文类型(Type)Byte0Byte1Byte2Byte3Byte4~Byte7SYNC no CRC0x10User Data, 默认为 0bit7 ~ bit4:Time Domain bit3 ~ bit0:Sequence CountUser Data, 默认为 0SyncTimeSec:48 位秒的低 32 位的部分时间SYNC CRC0x20CRCTime Domain(bit7 ~ bit4)

【小猫爪】AUTOSAR学习笔记01-AUTOSAR架构简介

【小猫爪】AUTOSAR学习笔记01-AUTOSAR架构简介 前言1 背景介绍2 基本概念3 方法论4 分层软件架构4.1 Application Layer(APP)4.2 Basic Software(BSW)4.3 Runtime Environment(RTE) 5 BSW模块简介5.1 Microcontroller Abstraction Layer5.2 ECU Abstraction Layer5.3 Services Layer5.4 Complex Drivers 6 功能安全END 前言 这一章来看看AUTOSAR的简介,来大略了解一下AUTOSAR,它究竟是一个什么东西啊。 1 背景介绍 首先来说说AUTOSAR这个玩意诞生的背景,相信有很多懂行的朋友都看到过下面的一段话: 这确实是AUTOSAR诞生的主要原因,但是我觉得这其中还有一条非常重要的原因,就是那些车厂大牛想搞钱,搞门槛,都是资本的力量,你懂的。 一开始几个车厂大牛在一起商量,想要迫切的去搞钱,哦不对,想要迫切的去解决当时汽车复杂的电子系统所面临的问题,于是就成立了AUTOSAR联盟,率先提出了AUTOSAR,迫于形势,后面慢慢的其他车厂,汽车电子供应商,研发商等待汽车电子市场周边都陆陆续续加入进来了,AUTOSAR飞速发展,从2003年联盟成立,到2008年AUTOSAR3.0发布,短短5年,一个属于AUTOSAR的时代正在逐渐头角峥嵘。直到如今的2023年,AUTOSAR已然变成庞然大物,吃相难看啊。 2 基本概念 AUTOSAR的提出就是为了解决上述问题,那么AUTOSAR到底是一个什么样的存在呢?AUTOSAR是automotive open system architecture的简称,粗略的翻译一下就是汽车开放式系统架构,但是作为一名嵌入式软件工程师,我觉得这玩意其实就是一个软件架构,它给你一个很大很大的软件架构然后再把一些细节全部给你定义好(细到什么程度呢,细到连函数名称都给你定义好了,就离谱),告诉你这个软件应该这么设计,应该这么写。所以对于基于AUTOSAR的软件研发一般都是第三方软件供应商会根据AUTOSAR架构把基础软件全部写好了,并且提供一系列代码配置工具,然后车厂或者Tier1直接把这一套软件买过来,根据自己的需求在工具上点一点,配一配,然后一键生成代码,这样基础软件就搞定了,然后再在matlab上完成应用层软件的开发,然后再对接起来。这样的话省事是省事,快也是真的快,但是只能说这其实就是一个“巨婴”养成计划,本人有幸做过一段时间的FAE,发现现在很多工程师被妥妥的养猪了,哎,一言难尽。 经过处理器和汽车电子的飞速发展,AUTOSAR也在飞速的适应着时代,现在根据不同的应用场景分裂出了两种SAR,分别是Classic Platform(CP)和Adaptive Platform(AP),在这里我只能简单的说一下,CP一般用在MCU上,而AP一般用在MPU上。想搞懂这两者的具体区别的朋友可以参考这篇文章:《【AutoSAR】 CP 和 AP》。接下来的所有关于AutoSAR的介绍都是基于CP的,我这里就简称AUTOSAR了。 CP AUTOSAR针对的的一般汽车ECU应用场景如下: CP AUTOSAR针对这一类的应用场景,指定了非常丰富且完整的软件分层结构来实现。这些后面会详细细说。 3 方法论 AUTOSAR还有另外一个不得不说的玩意叫做AUTOSAR的方法论,这个玩意是什么呢?Vector的培训材料里亲切的将其称为菜谱,花里胡哨的。其实这玩意说白了就是开发说明书,它就是想告诉你,要想把基于AUTOSAR完成一个项目,你就得先学这个,然后做那个,再搞这个,有着一套标准流程,等你安装它定义的标准流程把所有的东西都搞定了,最后,啪,一整合,妈的,一大堆bug,然后再去找bug,解决掉bug还有掩藏的bug,几次循环后最后就能基于AUTOSAR把这个项目给做好了,so easy。 其中贯穿整个AUTOSAR开发流程有一个非常重要的文件叫做ARXML文件,它是开发过程中的输入输出文件,打个比方,当你需要完成一个功能的时候,你必须要先使用配置工具根据功能需求生成ARXML,然后就可以通过这个ARXML文件再生成代码,这样的话,开发者只需要将注意力放在系统应用上的设计,而不去过多去关心底层软件的实现。 对于方法伦的具体介绍,我这里就不多作介绍了,我只能说方法伦的理论对于我们这种软件开发来说,并没有什么大用,我们只需要知道怎么开发就行了,感兴趣的朋友可参考这篇文章自行学习:《详解AUTOSAR:AUTOSAR方法论》。 4 分层软件架构 接下来来看看AutoSAR的最关键部分,分层软件架构,前面提到了如果基于AutoSAR做项目,会涉及到软件拼接,这就意味着一个项目的软件代码是两家甚至是三家的,为了顺利得让代码拼接成功,那么AutoSAR要求整个软件有着严格得分层。AutoSAR分层软件架构如下: 显而易见,AutoSAR软件架构自上而下分成了APP, RTE, BSW三层,至于那个Microcontroller指的是芯片MCU硬件,不属于软件。 4.1 Application Layer(APP) 这一个层就是大家常说的APP了,属于控制策略层,实现算法。这一部分的开发,都是在Matlab中去实现的,里面牵扯到一些SWC, Ports,Runnables等一些概念,在这里我也不多说了,毕竟我在这里不是专业,感兴趣的朋友可以自行百度谷歌,网上一大堆说明资料。 4.2 Basic Software(BSW) 这一层叫做基础软件层,它最大的功能就是隔绝APP和控制器的关系,并且为APP提供一系列服务。是整个软件架构中占比最大的一部分,大部分代码都是通过工具链配置生成的,只有一些特殊的一小部分需要自行实现,这一部分被称为Complex Driver,后面会细说。

S32K144-NXP EB tresos MCU驱动配置详解

S32K144平台 MCAL MCU驱动 在EB中的相关配置解析以及实战。 多图预警!!!!!!!!! MCUGeneral配置参数 ①Mcu Development Error Detect:Mcu模块开发错误检测使能。 ②Mcu Get Ram State API:获取RAM状态API使能。 ③Mcu Init Clock API:初始化时钟API使能。 ④Mcu No PLL:锁相环禁用。 ⑤Mcu Enter Low-Power Mode:进入低功耗模式使能。 ⑥Mcu Perform Reset API:执行复位API使能等。 MCURestReasonConf 导致MCU复位的原因有很多,如果硬件允许,Mcu模块可以获取复位的原因。McuResetReasonConf配置可以添加不同的Mcu复位原因。 McuModuleConfiguration配置 这个是重点的重点 第一步:McuModuleConfiguration→General配置 这里要对应着S32K144微控制器的时钟数来理解,比如这个RTC时钟32K 第二步:McuModuleConfiguration→McuClockSettingConfig配置 进入界面,点击+号添加 McuClockSettingConfig配置 进入McuModuleConfiguration→McuClockSettingConfig→General配置 注意这个General可不是上面那个MCU的General,而是你刚刚添加的一个时钟配置。 从上图你可以看到时钟配置有三个模式:Run\VLpr\Hsrun,可以简单理解为正常运行\超低功耗运行\超高速运行,每种模式对应的最高频率是不一样的。 这是竖着看,横着看你还会发现多出来了很多的标签栏:SOSC\SIRC\FIRC\PLL\SIM\PCC 这些都是对应的时钟,进入不同的标签栏下面,就是配置不同的时钟。 实例:SOSC,8M晶振通过PLL倍频变成80MHz 比如我们要使用外部时钟SOSC,8M晶振通过PLL倍频变成80MHz的内核时钟: 一般先看时钟树,需要配置什么参数: 然后进入到SOSC标签栏对其进行配置: 然后进入PLL标签栏下:输入倍频系数40,40*8=320M(图里写错了)/2=160M,再二分频就是80M,完美!!! 到这一步算是完成了系统时钟与锁相环,下一步就是对输出时钟进行全局的配置! 进入McuPeripheralClockCof标签栏下:一定要点这个小人,把所有都添加上,代表所有的外设我都分配好时钟了,没落下的。(一定要!!!不然报错!!!) 然后进入McuClockReferencePoint标签栏,这里你可以理解为映射可将外设时钟通过McuClockReferencePoint与其他BSW模块联系起来。 添加你需要的,还可以自己命名,用于什么用途就怎么改。 这个时候你会发现,哎呀这个RUN_SYS_CLK是啥呀? 还记得前面说的MCU三种模式下的频率嘛,进入General下,选择SPLL也就是咱们前面配置的PLL输出时钟。 完美!!!!!! 到这里可以说你的时钟配置就完成了,之后你添加什么外设或者什么驱动,别忘记到进入McuClockReferencePoint标签栏把该对应的都对应上就可以了。 重点还是要了解MCU的时钟树,以及相关的外设,软件的操作与配置属于技层面,对时钟的理解是术层面。 对了还有一些API函数也要了解一下: MCU API接口函数 Mcu_Init; Mcu_InitClock; Mcu_GetPllStatus(若使用PLL,直到PLL锁相环配置成功); Mcu_DistributePllClock(若使用PLL); Mcu_InitRamSection(按照具体需求,可不调用) 总结 细节真的很多,有些东西稍不注意就忘记了,而且EB这个软件设计上也是,很多相关的配置参数使能,非要隔这么远在不同的标签栏下,一不小心就忽略了,错误也不好排查,很吃熟练度和经验。

Layer子iframe传数据到父页面的两种方式【按钮和非按钮】

以下两种方式均实测通过,按钮式通信如下, 首先是父页面的js代码 <script> //表单组件的渲染 function form_open(){ layer.open({ title:'<i class="bi-table" style="font-size: 1rem; ">表单</i>' ,btn:['确定'] ,type: 2 ,maxmin: true //开启最大化最小化按钮 ,content: 'form.html' ,area: ['344px', '100%'] ,offset: 'lt' //左上角 ,anim: 4 ,shade:false ,yes: function (index, layero) { var iframeWin = window[layero.find('iframe')[0]['name']]; var iframeModel = iframeWin.GetValue();//接收iframe传递过来的值 //console.info(iframeModel); if (iframeModel != null) { $("#design_div").append(iframeModel); layer.close(index); } else { layer.msg("请选择组件!"); layer.close(index); } } }); } </script> 父页面的代码核心在于下面这两句,其中GetValue()函数是子页面中的 var iframeWin = window[layero.find('iframe')[0]['name']]; //这两句很重要 var iframeModel = iframeWin.

UE5像素流公网多人部署

前言: 本机需要安装 node.js node安装与配置 打包项目时需要启用插件 Pixel Streaming 一、打包项目后进入 Samples\PixelStreaming\WebServers\SignallingWebServer 目录 1、在目录下新建 文本文档 添加以下内容,然后改名与后缀为 setup.bat :: Copyright Epic Games, Inc. All Rights Reserved. pushd %~dp0 npm install popd 2、同上创建一个 run.bat 添加以下内容 :: Copyright Epic Games, Inc. All Rights Reserved. @echo off pushd %~dp0 call setup.bat title Cirrus ::Run node server ::If running with frontend web server and accessing outside of localhost pass in --publicIp=<ip_of_machine> node cirrus %* popd pause 3、修改 config.

Java中Json转List(Jackson)

Jackson是一个常用的Java序列化和反序列化库,可以方便地将Json数据转换为Java对象。需要先在pom.xml中添加Jackson库的依赖: <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency> 然后使用ObjectMapper的readValue方法将Json数据转换为List对象: import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; public class Main { public static void main(String[] args) throws Exception { String json = "[{\"name\":\"Tom\",\"age\":18},{\"name\":\"Jerry\",\"age\":20}]"; ObjectMapper objectMapper = new ObjectMapper(); List<Person> personList = objectMapper.readValue(json, new TypeReference<List<Person>>(){}); System.out.println(personList); } } class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.

运维36讲第29课:虚拟化关键技术浅析(NUMA、dpdk、绑核)

本课时我们来学习虚拟化关键技术。对于虚拟化技术原理的了解有助于我们对虚拟化技术的应用。 虚拟化技术演变 我这里列了一张图,把一些常见的虚拟主机技术进行罗列,横坐标是时间轴,纵坐标是具体的一些虚拟化技术名称。 虚拟化技术里,有 Virtualbox、KVM、 Docker 及各个虚拟技术。结合横坐标轴,我们可以看到在最早期的虚拟主机是使用软件系统层的虚拟化技术实现的,列举的Virtualbox 是在 2000 年前诞生的,它就是基于软件虚拟化技术实现的。 随着对性能的要求越来越高,硬件也逐步承担了一些虚拟化的工作,就诞生了硬件层次的虚拟化,在硬件层次的虚拟化的里程碑中, KVM 就是一个典型的硬件虚拟化实践机制的开源虚拟化技术。 当前离我们现在最近的虚拟化技术是轻量级的虚拟化,如 Docker 或更早期的 LXC,相比纯主机虚拟的方式,容器的虚拟化更加轻量级,易于发布管理和迁移等等,属于现在广为流行的一种虚拟化服务应用。 虚拟化技术的原理是我们这节课重点讲解的。虚拟化中实现的关键技术,我认为通常可以列举出如下: 对于资源的虚拟化实现;NUMA 技术;CPU 绑核;资源隔离;虚拟机的热迁移等等。 以上都是在虚拟化技术里我认为非常关键的技术,本课时,我们将摘取其中的一部分内容来为你讲解。通过学习这些内容,可以帮助你加深对虚拟化技术的了解,方便进行虚拟化应用,同时也可以帮助你在面试过程中,更好地应对虚拟化技术上的一些常见的面试问题。对运维技术面试是十分有帮助的。 资源虚拟化技术 首先我们来讲解资源虚拟化的实现。常见的虚拟化资源实现,可以分为如下的一些类型: CPU 虚拟化;内存虚拟化;IO 虚拟化;网络虚拟化;磁盘虚拟化;GPU 虚拟化。 每一个虚拟化的实现都有它针对的技术和对应的一些原理,这些需要我们针对性地去了解。其中我认为最重要就是对于计算资源虚拟化,也就是 CPU 的虚拟化了,它可谓是虚拟化的基础。 接下来我们就以 CPU 虚拟化为例来给你进行讲解。 CPU 虚拟化原理 在 Linux 操作系统里,进程运行级别可以分为用户态和内核态,而对应 CPU 的指令级别则是通过 Ring 级别来进行访问控制的,级别共分 4 层,从 Ring0 到 Ring3,Ring0 是权限级别最大的,Ring3 是权限级别最小的。Ring3 的权限级对应用户态模式,Ring0 对应内核态。当应用程序执行特权指令时,会通过中断或异常来实现用户态到内核态的切换,比如访问磁盘、写文件,那就要通过执行系统调用(函数),执行系统调用的时候,CPU 的运行级别会发生从 ring3 到 ring0 的切换,并跳转到系统调用对应的内核代码位置执行。 了解这个概念后我们如果在底层系统层再安装虚拟机,那么就是遵循:硬件层-->物理机系统-->虚拟机管理软件VMM-->虚拟主机系统-->虚拟主机应用 这样一个层次关系。那么在虚拟化技术中虚拟机应用所需要执行特权指令该如何切换呢? CPU 全虚拟化原理 下面这张图展示了 CPU 虚化早期的全虚拟化原理的实现方式: 可以看到,内核态 Ring0 级别运行一个叫作 VMM 的软件,这个软件主要是用来做特权指令集的翻译。虚拟机系统 OS 在 Ring1,虚拟机上的应用 App 需要执行特权的底层调用指令时,它会先给自己运行的虚拟机的 OS 系统上发送对应的指令。它在执行特权指令时,会触发异常,然后 VMM 捕获这个异常,在异常里面做翻译模拟,返回到 OS。

使用opencv-python和dlib实现的简单换脸程序

准备 pip安装opencv-python、dlib下载dlib人脸形状检测器模型数据:shape_predictor_68_face_landmarks.dat.bz2,并解压在models文件夹下 实现步骤 使用dlib的shape_predictor_68_face_landmarks.dat模型获取人脸图片im1和摄像头图片im2的68个人脸特征点。根据上一步获得的特征点得到两张图片的人脸掩模im1_mask和im2_mask。利用68个特征点中的3个特征点,对人脸图片im1进行仿射变换使其脸部对准摄像头图片中的脸部,得到图片affine_im1。对人脸图片的掩模im1_mask也进行相同的仿射变换得到affine_im1_mask。对掩模im2_mask和掩模affine_im1_mask的掩盖部分取并集得到union_mask。利用opencv里的seamlessClone函数对仿射变换后的affine_im1和摄像头图片im2进行泊松融合,掩模为union_mask,得到融合后的图像seamless_im。 换脸效果 周杰伦的帅气照: 利用杰伦的脸作为替换的脸的换脸效果:

sharding-jdbc四种分片策略

一、标准分片策略(standard) 1、精确分片 配置文件 spring: shardingsphere: #开启sql显示 props: sql: show: true datasource: # 配置数据源 names: db0,db1 db0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/sharding_test_0?useUnicode=true&character_set_server=utf8mb4&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai username: root password: root db1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/sharding_test_1?useUnicode=true&character_set_server=utf8mb4&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai username: root password: root sharding: #唯一库数据 default-data-source-name: db0 #分库 default-database-strategy: standard: # 添加数据分库字段(根据字段插入数据到那个表) sharding-column: id #精确分片 precise-algorithm-class-name: com.example.sharding_test.strategy.database.DatabasePreciseAlgorithm #分表 tables: #表名 db_user: actual-data-nodes: db$->{0..1}.db_user_$->{0..2} key-generator: column: id # 主键ID type: SNOWFLAKE # 生成策略雪花id table-strategy: standard: sharding-column: id #精确分片 precise-algorithm-class-name: com.

Java框架 | Spring和MyBatis中的#与$

为什么要有#和$? Spring和MyBatis的#和$都是为了解决配置文件中的属性值问题而引入的。 在Spring中,$符号表示属性占位符,可以将属性文件中的属性值替换到Spring配置文件中的属性值中;而#{}符号则表示SpEL表达式占位符,可以通过表达式来计算属性值。 在MyBatis中,#符号表示参数占位符,可以防止SQL注入攻击;而$符号则表示文本替换符,直接将变量替换到SQL语句中,可能存在SQL注入风险。 在Spring和MyBatis中的#和$有什么相同点和不同点? 共同点: 在Spring和MyBatis中,#和$都可以用于参数占位符,用于将参数值动态地传递给SQL语句。 区别点: 在Spring中 #是SpEL表达式占位符,可以通过表达式来计算属性值;$是属性占位符,可以将属性文件中的属性值替换到Spring配置文件中的属性值中。在MyBatis中 #是预编译处理,可以有效防止SQL注入攻击;$是字符串替换,不具备防止SQL注入攻击的功能。在MyBatis中,#通常用于替换参数,$通常用于替换列名或表名。 在Spring中SpEL表达式有哪些?最重要的是哪些? Spring Expression Language(SpEL)是Spring框架中的一种表达式语言,可以在运行时计算表达式的值。它支持在Spring框架中访问和操作对象图,包括Spring bean和属性文件中的属性。 SpEL表达式可以通过以下方式使用: 字面值:包括字符串,数字,布尔值和null引用对象:包括Spring bean和静态类的引用属性访问:访问对象的属性方法调用:调用对象的方法运算符:支持算术,比较和逻辑运算符表达式列表:支持在表达式中使用列表,集合和数组正则表达式:支持正则表达式赋值:支持将值赋给对象的属性 其中最重要的SpEL表达式是引用对象和属性访问。 它们使得我们可以轻松地在Spring框架中访问和操作对象图,而不需要编写复杂的Java代码。 为什么MyBatis中的#能够防止恶意的注入攻击? 在MyBatis中使用#可以防止SQL注入攻击的原因是,#号会将传入的参数视为一个完整的值,并对这个值进行预编译处理,最终在将其绑定到SQL语句中时,会将其转换成一个占位符,然后再与SQL语句进行拼接。因此,无论传入的参数是什么,都不会对SQL语句造成影响。 举个例子:#{name}传入的是'admin' or 1=1',其最终会转换成什么传入SQL语句呢? 传入入的值为'admin' or 1=1',在使用#时,MyBatis会将其转义为'admin\' or 1=1'; 传入SQL语句后,数据库会将其视为一个普通的字符串,而不会将or 1=1解析成一个条件语句。 因此,使用#可以有效地防止SQL注入攻击。 配置文件中使用的#与占位符时使用有什么区别? MyBatis配置文件中,如果您看到类似${...}的语法,那么它与Spring配置文件中的${...}语法具有相同的目的:从外部属性文件中引用属性值。这里的$符号用于从属性文件中获取配置值。请注意,这与MyBatis在SQL映射文件中使用#{...}和${...}作为参数占位符的语法是不同的。 在MyBatis配置文件(mybatis-config.xml)中,您可以使用${...}语法引用外部属性文件中的值 <dataSource type="POOLED"> <property name="driver" value="${db.driverClassName}" /> <property name="url" value="${db.url}" /> <property name="username" value="${db.username}" /> <property name="password" value="${db.password}" /> </dataSource> 这个示例中的${db.driverClassName}、${db.url}、${db.username}和${db.password}用于从外部属性文件中获取数据库配置信息。这种方法允许您在不修改应用程序代码的情况下轻松更改数据库配置。 请注意,这里的$与MyBatis中的#{...}和$参数占位符是不同的。在MyBatis SQL映射文件中,#{...}用于传递预编译参数,而${...}用于直接插入SQL参数。 总结 在MyBatis中,尽量使用#解决配置文件中的属性值问题,因为其能防止恶意注入攻击;但对动态拼接SQL语句时,可能需要使用$符号进行占位符替换。 在Spring中,$使用简单方便,而#可以进行更复杂的运算和处理。

InfluxDB:时序型数据库学习笔记,就这一篇吧o(╥﹏╥)o

一、什么是时序型数据库 ​时序数据库全称为时间序列数据库。时间序列数据库指主要用于处理带时间标签(按照时间的顺序变化,即时间序列化)的数据,带时间标签的数据也称为时间序列数据。 时间序列数据主要由电力行业、化工行业、气象行业、地理信息等各类型实时监测、检查与分析设备所采集、产生的数据,这些工业数据的典型特点是:产生频率快(每一个监测点一秒钟内可产生多条数据)、严重依赖于采集时间(每一条数据均要求对应唯一的时间)、测点多信息量大(常规的实时监测系统均有成千上万的监测点,监测点每秒钟都产生数据,每天产生几十GB的数据量)。基于时间序列数据的特点,关系型数据库无法满足对时间序列数据的有效存储与处理,因此迫切需要一种专门针对时间序列数据来做优化的数据库系统,即时间序列数据库。 ​InfluxDB是一个开源的、高性能的时序型数据库,在时序型数据库DB-Engines Ranking上排名第一。 二、InfluxDB 相关概念 InfluxDB是一个由InfluxData开发的开源时序型数据。它由Go写成,着力于高性能地查询与存储时序型数据。 名称说明organization组织Member用户,可设置权限API TOKEN调用API时使用的tokenbucket数据桶(数据库)measurement数据表point数据点,表示单条数据记录,point由时间戳(time)、数据(field)、标签(tag)三类字段组成retention policy数据保留策略,可以定义数据保留的时长,每个数据库可以有多个数据保留策略,但只能有一个默认策略time代表每条数据的时间字段,是measurement中的数据主键,因此time字段具有索引属性。一条point只能有一个timefield代表各种数据的字段,例如气温、压力、股价等。field字段没有索引属性,一条point可以包括多个fieldtag代表各类非数据字段,例如设备编码、地区、姓名等。tag字段有索引属性,一条point可以包括多个tag(tag只能为字符串类型) InfluxDB与常用的关系型数据库(MySQL)的概念对比: MySQLInfluxDB数据库databasebucket表名tablemeasurement记录rowspoint字段columnstime+tag+field 三、Linux环境下安装InfluxDB 本人使用的是influxDB V2.3.0版本,想下载的朋友点这里:influxDB V2.3.0 镜像包 1、镜像包拷贝到Linux服务器上,加载镜像 docker load -i influx.tar.gz >/dev/null 2、启动容器 docker run -d --name influxdb \ -p 8086:8086 \ --restart=always \ -v /mnt/influxdb/data:/var/lib/influxdb2 \ -v /etc/localtime:/etc/localtime \ influxdb >/dev/null 接下来是重点喽!!! (1)influxDB 1.x 版本,配置文件在 etc/influxdb/influxdb.conf,而到了 2.x 版本,进入容器中,通过执行 influxd print-config 命令查看 influxdb 的默认配置。当然也可以手动创建一个名为 config.*的文件,config支持json,toml,yaml格式,将config.*文件放到 etc/influxdb2/文件夹下,启动容器时修改环境变量,指定配置文件读取的路径 --env INFLUXD_CONFIG_PATH=/etc/influxdb2,influxdb启动时会自动检测这个文件。同样可以进入容器,执行 influxd print-config 查看你自定义的配置是否生效; docker run -d --name influxdb \ -p 8086:8086 \ --restart=always \ --env INFLUXD_CONFIG_PATH=/etc/influxdb2 \ -v /opt/mountdir/influxdb/config/:/etc/influxdb2 \ -v /mnt/influxdb/data:/var/lib/influxdb2 \ -v /etc/localtime:/etc/localtime \ influxdb >/dev/null 四、Springboot 整合 InfluxDB 1、pom.

这对情侣火了,你猜是因为啥

注意看,这张情侣照在网上转疯了: —— 本文转载自量子位 旧厂街风格,带着浓浓90年代氛围感,但是,他俩一夜爆火的原因,你可能想象不到—— 这二位并不是真人!而是由AI一键生成的! (不论是乍眼看去或是放大细瞧,都会觉得是拿相机拍的真人吧!) 这就是Midjourney最新V5版本解锁的逆天神技。 就连AI绘画最被诟病的手,这次也完全能hold住了。 而且很多网友一开始不相信这是AI画的,于是他们亲自下场输入提示词来验证: A pair of young Chinese lovers, wearing jackets and jeans, sitting on the roof, the background is Beijing in the 1990s, and the opposite building can be seen —v 5 —s 250 —q 2. 一对年轻的中国情侣,穿着夹克和牛仔裤,坐在屋顶上,背景是20世纪90年代的北京,可以看到对面的建筑—v 5 —s 250 —q 2。 在自己体验了一把之后,不少网友这次真的直呼: 人类画师别活了。 把我吓坏了。 逼真的不像话 90年代的中国情侣以假乱真,那么现代版的呢? 把提示词中的年代改成2023年: 无论是时尚的破洞裤、潮流的发型,还是背景的楼宇环境,一下子都拉回到了现在。 还有这样的: △来自微博@谷大白话 甚至有人觉得人物的眼神,根据时代不同也在发生变化。 而且逼真程度也是骗过了不少网友: 当然,“欧美爱情故事”也是不在话下: 当然,大家最关心的还是“手”画的怎么样。 于是,一位网友就专门加大难度来测试Midjourney V5的这项能力。 例如一张印度美人露手的全身像: 妥妥是影楼大片级别了。 再生成竖大拇哥的: 不仅没有拉胯,甚至Midjourney能把镜头的聚焦感体现出来。 那么只生成手呢?

【FFMPEG】encoder深入分析

从前面一篇文章ffmpeg内部组件总结可以知道encoder的具体使用方法: char *filename = "/data/record/test.mp4" AVFormatContext *format_ctx = NULL; //通过输入url找到对应的muxer即format_ctx->oformat并malloc AVFormatContext format_ctx = avformat_alloc_output_context2(&format_ctx, NULL, NULL, filename); //通过url找到并初始化IO模块 avio_open2(&format_ctx->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); //通过codec找到对应的encoder AVCodec *enc = avcodec_find_encoder(format_ctx->oformat->video_codec); AVCodecContext *enc_ctx = avcodec_alloc_context3(enc); //打开encoder avcodec_open2(enc_ctx, enc, NULL); AVStream *stream = avformat_new_stream(format_ctx, enc); avcodec_parameters_from_context(stream->codecpar, enc_ctx); while(!exit) { //将输入源的数据送到encoder中编码 avcodec_send_frame(enc_ctx, frame); AVPacket *pkt = av_packet_alloc(); //从encoder中获取编码后的数据 avcodec_receive_packet(enc_ctx, pkt); //将编码后的数据送到muxer中 av_write_frame(format_ctx, pkt); } 本篇文章将以struct FFCodec ff_mpeg4_encoder深入分析下, encoder需要外部传入什么参数?输入/输出buffer的处理encoder内部是否有数据缓存? 接下来重点分析下这四个接口: avcodec_open2(…), avcodec_parameters_from_context(…), avcodec_send_frame(…), avcodec_receive_packet(…)分别干了什么。 avcodec_open2 int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) { int ret = 0; AVCodecInternal *avci; const FFCodec *codec2; .

宝塔快速搭建网站

服务器搭建网站完整教程(宝塔面板+wordpress) 纵横数据 纵横数据云计算(www.155cloud.com) 40 人赞同了该文章 服务器最大的用途,就是可以搭建网站,许多人都认为搭建网站是一件很难的事情,因为包含许多的比较专业东西,比如服务器、编程之类的,确实,在几年前是这样的,普通人想要自己做一个网站太难了 但是随着网站发展了那么多年,已经有许多的其他人做好的工具我们可以利用起来,建一个网站已经越来越简单了,甚至不需要了解代码点几下鼠标就能创建自己的网站,而且比以前的更加的好用,今天主机笔记就介绍下新手如何使用宝塔面板和Wordpress搭建独立网站 建站准备 建网站本身是没有什么难度的,只是配套需要的东西有些繁琐,我们需要提前准备一些软件之类的必备的东西,其中主要包括: 服务器:推荐使用使用纵横数据云服务器https://www.155cloud.com/域名:注册域名,建议使用阿里云Xshell:用于连接Linux服务器,这款软件对于个人来说是免费使用的,如果你还不知道如何下载及使用的话,可以查看Xshell连接linux方法FTP软件:用于上传网站文件,这个网络上很多,我经常使用的是FlashFXP,网络上可以找到很多这样的软件 安装宝塔面板 安装宝塔面板之前,确保你的系统是纯净的,如果之前使用其他的一键安装,建议重装系统为Centos7系统 首先我们要进入自己的linux服务器,在命令行输入以下命令安装宝塔面板 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && bash install.sh 需要几分钟的时间,中途会停顿一下让选择web目录的位置,一般默认即可 等待安装完成之后,命令行会显示面板的登录地址、账号以及密码,一定将这些信息保存下来,后期的管理都需要使用该信息登录面板 安装网站环境 宝塔面板安装完成后,我们就可以登录后台面板了,使用刚刚记录的后台地址登录(如果你是使用的阿里云或者腾讯云的话,可能会登录不上,这时候你需要在后台开启安全组8888端口,阿里云ECS开放安全组端口) 接下来就会看到一键安装环境的界面,一般我们会选择左侧的LNMP架构,编译安装 这里我要说下关于不同配置的服务器环境的设置,因为一般常用的有512M内存的,还有就是1G内存的,这两个的环境选择是不一样的 如果是512M内存,那么使用默认的配置即可,Mysql 5.5 和 PHP 5.4如果是1G内存,推荐使用wordpress官方给的设置,Mysql 5.6 和 PHP 7.2 然后就是等待安装完成就可以了,一般会持续半小时到1个小时,根据你服务器的性能决定 服务器新建站点 等待所有的任务都完成以后,所有的环境就搭建好了,接下来就可以建立网站了 宝塔面板新建一个网站,点击下图中绿色的按钮新建一个站点 这里我们需要输入自己的网站域名,把带www和不带www的域名全部填写上,比如www.155cloud.com,该步骤就是绑定域名 然后FTP和数据库最好都创建,将这些信息都记录下来,以后我们都需要用到的 所有设置完毕之后我们点击提交,网站即创建完毕(这里指服务器为网站准备出空间,类似开一个虚拟主机,只不过我们对此有控制权) 域名解析到站点 这个其实很简单,就是添加域名解析的ip地址,可能就是不同的域名商操作方法不一样,这里我演示下阿里云的域名解析 我们先在后台管理中找到自己的域名,点击解析,然后添加解析 这里需要添加2个解析到服务器的ip地址 一个是 www 记录,这里设置www通用的,比如 http://www.155cloud.com 还有就是 @ 记录,这个是设置根域名,比如说主机笔记就是 http://155cloud.com,虽然说有时候用不到,最好还是设置一下,毕竟还是有很多人直接输入域名不输入www的 设置好解析以后,需要等待2分钟(其他的域名商可能会有延迟几个小时都有可能的,最好提前解析) 然后访问网页看到一个创建成功的页面,就证明解析已经好了,可以进行下一步 下载WordPress网站程序 服务器和域名都配置好以后,就可以开始配置我们的网站程序了 首先我这里选择的程序是wordpress,网站程序可以到wordpress中文官网下载,点击下载按钮 下载好之后我们会得到一个压缩包,但是它的目录结构是不能直接上传到服务器的,我们先将其解压 会看到如下的文件夹,这些就是网站根目录,我们要做的就是将所有的文件选中,然后再压缩上传 这里还需要注意一点,由于压缩软件默认是rar格式的,但是服务器是不支持解压rar格式的压缩包的,所以,我们要进一步设置为zip压缩 FTP上传压缩包到服务器 我的习惯是使用FTP上传到服务器,当然面板也比较方便,也可以使用宝塔后台的文件上传功能

Python中Pandas库教学(1)

Python中Pandas库教学(1) 什么是Pandas库? Pandas是一个数据处理库,用于数据分析、数据清洗和数据转换等任务。它提供了快速、灵活和富有表现力的数据结构,可以方便地进行数据操作和分析。 安装Pandas库 在安装Pandas库之前,你需要安装Python。安装Python的方法可以在Python官网找到。 安装Pandas库的方法有两种: 1.使用pip工具安装:在命令行(windows+R+cmd)中运行以下命令:pip install pandas 2.使用conda工具安装:在命令行中运行以下命令:conda install pandas 导入Pandas库 在使用Pandas库之前,你需要导入它。可以使用以下代码导入Pandas库: import pandas as pd Pandas库的数据结构 Pandas库提供了两种主要的数据结构:Series和DataFrame。 Series Series是一种类似于一维数组的数据结构,它可以存储任意类型的数据,例如数字、字符串和Python对象等。Series的重要特性是它具有索引,它可以让你对数据进行标记和引用。 你可以使用以下代码创建一个Series: import pandas as pd data = [1, 2, 3, 4, 5] s = pd.Series(data) print(s) 输出结果: 0 1 1 2 2 3 3 4 4 5 dtype: int64 DataFrame DataFrame是一种二维表格数据结构,它可以存储多种类型的数据,例如数字、字符串和Python对象等。DataFrame的重要特性是它具有行索引和列索引,它可以让你对数据进行标记和引用。 你可以使用以下代码创建一个DataFrame: import pandas as pd data = { 'name': ['Alice', 'Bob', 'Charlie', 'David'], 'age': [25, 32, 18, 47], 'city': ['New York', 'Paris', 'London', 'Tokyo'] } df = pd.

plsql:关于查询结果中汉字显示为问号和以汉字当别名出现ORA-00911:invadlid character的问题。

我的情况是这两个问题同时出现,以下是具体情况。 一、关于以汉字当别名出现ORA-00911:invadlid character的问题。 我第一次使用plsql时,对该软件还不懂就出现了此问题,我在网上看了很多帖子,解决办法引到了解决汉字显示为问号的问题上,以致于我搞了很久,都没有解决。 我的解决办法是:用双引号将汉字别名引住,英文双引号,例如:select a "啊" from b。将别名外加上英文的双引号即可。 二、关于查询结果中汉字显示为问号的问题 解决办法: 第一步: 在sql窗口中输入 select userenv('language')from dual,查看结果,我的结果显示的是AMERICAN_AMERICA.ZHS16GBK。这个意思是oracle服务器端字符集的编码是AMERICAN_AMERICA.ZHS16GBK这样的。在sql窗口中输入select * from V$NLS_PARAMETERS,查看本地字符集的编码,执行,会出现两列数据,看右边那列的第一、二、九行数据(有的是一、二、六行数据)依次拼接后和服务器端的数据对照,二者一样的话,说明二者的字符集编码方式一样,我的是一样的,但汉字显示的还是问号。所以我也进行了系统变量的添加。 第二步: 添加系统变量(不是用户变量),我们需要添加和服务器端字符集编码一样的变量,也就是说我们要添加的变量的值要和select userenv('language')from dual语句查出来的一样。即LANG=zh_CN.GBK 和 NLS_LANG=AMERICAN_AMERICA.ZHS16GBK 。为什么多了LANG=zh_CN.GBK这一句,是因为网上说本地端少了个什么东西,需要也添加这个系统变量,我也试过只添加NLS_LANG=AMERICAN_AMERICA.ZHS16GBK这一个系统变量,没用,还是汉字变成问号。我试了网上说的很多关于系统变量的操作,但都不行。只有这个成功了。 第三步: 很重要的一点是——添加系统变量之后要重启电脑。有的人情况是添加系统变量之后重启plsql就可以了,我的电脑是需要重启一下电脑才可以正常使用。 问题原理:我也不清楚,但看网上的很多帖子说是:服务器端和本地电脑的编码不一样,导致中文显示的是问号。

mysql驱动表与被驱动表及join优化

驱动表与被驱动表 先了解在join连接时哪个表是驱动表,哪个表是被驱动表: 1.当使用left join时,左表是驱动表,右表是被驱动表 2.当使用right join时,右表时驱动表,左表是驱动表 3.当使用join时,mysql会选择数据量比较小的表作为驱动表,大表作为被驱动表 注意:EXPLAIN语句分析出来的第一行的表即是驱动表 join查询如何选择驱动表与被驱动表 在sql优化中,永远是以小表驱动大表。 例如: A是小表,B是大表 使用left join 时,则应该这样写select * from A a left join B b on a.code=b.code A表时驱动表,B表是被驱动表 测试:A表140多条数据,B表20万左右的数据量 select * from A a left join B b on a.code=b.code 执行时间:7.5s select * from B b left join A a on a.code=b.code 执行时间:19s 结论:小表驱动大表优于大表驱动小表 join查询在有索引条件下 驱动表有索引不会使用到索引 被驱动表建立索引会使用到索引 在以小表驱动大表的情况下,再给大表建立索引会大大提高执行速度 测试:给A表,B表建立索引 分析:EXPLAIN select * from A a left join B b on a.code=b.code

C语言宏定义详解

宏定义引入 源程序在编译之前,会先进行预处理。 预处理并不是C语言编译器的组成部分,不能直接对它们进行编译。经过预处理后,程序就不再包括预处理命令了,最后再由编译程序对预处理之后的源程序进行编译处理,再经过链接得到可供执行的目标代码。 C 语言提供的预处理功能有三种,分别为宏定义、文件包含和条件编译。 宏定义在 C语言源程序中允许用一个标识符来表示一个字符串,称为“宏/宏体” ,被定义为“宏”的标识符称为“宏名”。 在预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去完全替换,这称为“宏替换”或“宏展开”。 宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的。 在 C 语言中,宏分为有参数和无参数两种。无参宏的宏名后不带参数,其定义的一般形式为: #define 标识符 字符串 #表示这是一条预处理命令(在C语言中凡是以#开头的均为预处理命令) define:宏定义命令 标识符:所定义的宏名 字符串:可以是常数、表达式、格式串等 无参宏和有参宏示例: // 不带参数的宏定义 #define MAX 10 /*带参宏定义*/ #define M(y) (((y)*(y))+(3*(y))) /*宏调用*/ k=M(MAX); 注意宏不是语句,结尾不需要加“;”,否则会被替换进程序中,如: #define N 10; // 宏定义 int c[N]; // 会被替换为: int c[10;]; //error:… main.c:133:11: Expected ']' 如果要写宏不止一行,则在结尾加反斜线符号使得多行能连接上,如: #define HELLO "hello \ the world" 而且注意第二行要对齐,不要出现预期之外的空格,否则,如: #define HELLO "hello the wo\ rld" printf("HELLO is %s\n", HELLO); //输出结果为: HELLO is hello the wo rld 也就是行与行之间的空格也会被作为替换文本的一部分

开发一个软件的主要流程

本文重点解决如下问题:开发一个软件的主要流程是什么?了解开发一个软件的主要流程对于编程者而言非常重要,它能够让编程者对如何开发一个软件有个整体的认知。开发一个软件的主要流程包括:1)软件前端界面设计;2)后台功能实现;3)前端和后台联合测试;4)软件的打包发布等步骤。 学习一门编程语言,怎么样才算是基本合格了?那就是你能够利用该编程语言编写并发布自己的软件,上传到Github这样的开源平台,如果你的软件受到下载者的好评,那么你对这门编程语言的掌握才算基本合格。遵循上面的软件开发的基本流程,在学习一门编程语言时,就应当思考:1)该编程语言在开发一个软件时,是怎么实现界面的设计的?针对此问题,在后面讨论具体的编程语言该如何学习的小节当中都会述及一下该语言的界面编程方式。2)界面中的每个功能,在后台是怎么实现的?是通过一个函数还是通过一个类?怎样将界面中的一个功能与后台的代码建立连接?3)怎样对开发出的软件的前端与后台进行联合测试,怎样找出软件中的bug?4)测试完成后,怎样发布自己的软件?是通过发布exe桌面端安装程序,还是通过发布网页,还是通过发布APP应用程序?学习一门编程语言,如果能够想明白上面四个问题并实现和发布一个具体软件,那么你对该编程语言的掌握也就过关了。 编程类似于学开车,开车只有上路开才能学会,编程就是要面向实战,通过写软件和做项目才能够学会。例如,如果需要开发一个“加法器”软件来实现任意两个实数的相加,那么该软件的开发流程如图 4-5所示。该图形象地展示了开发一个软件的主要流程。首先需要设计一个“加法器”的界面;然后通过后台编写代码实现单击“等号按钮”自动求和的功能,即鼠标单击等号后将用户输入到界面中的两个实数自动求和,再把结果显示在等号右边的文本框中;接下来将前端界面和后台代码进行联合测试;最后,经过测试确定程序没有问题后将程序打包生成后缀名为exe的软件供用户下载安装。读者在学习某一门编程语言时,建议仿照上面的流程自己编写并发布一个软件,如果能够达到这样的水平,则算是初步掌握了该编程语言。 图 4-5 开发一个软件的主要流程(以开发一个加法器软件为例) 怎么样编写软件的界面,编写软件的界面有哪几种方式?如果想搞清楚上述问题,敬请关注本公众号的下一篇文章《编写软件界面的方式》。 关于人工智能中编程能力和技能训练的更多介绍,可以购买《人工智能怎么学》进一步阅读。 图书购买方式 京东:https://item.jd.com/13395339.html 当当:http://product.dangdang.com/29469230.html 天猫:https://detail.tmall.com/item_o.htm?id=687374654836 为了让图书惠及更多的读者,为更多想学习人工智能的人提供帮助,经过向出版社申请,对图书《人工智能怎么学》的部分内容进行改编和连载。图书《人工智能怎么学》的全部内容包含了初级入门、中阶提高以及高级进阶三个级别的内容。连载的内容主要是初级入门级别,适合想对人工智能进行快速和高效入门的读者,对于已有一定的人工智能学习基础,希望进一步进阶或提高的读者,则需要购买图书《人工智能怎么学》,学习中阶提高以及高级进阶的内容。此外,对于学习人工智能感兴趣的读者,也可以加入知识星球《人工智能怎么学》,知识星球是一个构建学习社群的平台,通过加入《人工智能怎么学》的社群,你将获得更多的学习资料和课程信息。 与作者互动和了解更多信息 想跟作者一起学习人工智能和互动,你可以加入如下社群: 知识星球:https://t.zsxq.com/0aLkVg0os QQ群:600587177 想了解更多关于人工智能学习及实践的内容,请关注如下媒体: 官方网站:https://bigdatamininglab.github.io 官方微信公众号:人工智能怎么学(可扫描下方二维码或者微信搜索“人工智能怎么学”添加关注) CSDN:https://blog.csdn.net/audyxiao001 参考文献 Robert C. Martin. 代码整洁之道(第2版)[M]. 韩磊, 译. 北京: 中国工信出版集团, 人民邮电出版社, 2020. Herb Sutter, Andrei Alexandrescu. C++编程规范:101条规则、准则与最佳实践[M]. 刘基诚, 译. 北京: 人民邮电出版社, 2016. 杨冠宝. 阿里巴巴Java开发手册[M]. 北京: 电子工业出版社, 2020. James Gosling et al. The Java Language Specification:Java SE 8 Edition[M]. Upper Saddle River: Addison-Wesley, 2014. 老九君. C++的发展简史[EB/OL]. https://www.cnblogs.com/ljxt/p/11636342.html, 2019-10-08. 翁惠玉. C++程序设计:思想与方法(第2版)[M].

图形学学习推荐网址

http://www.onegreen.net/maps/m/world.htm 世界地图 http://www.scratchapixel.com/ http://www.opengl-tutorial.org/ https://developer.nvidia.com/gpugems/gpugems/contributors 英伟达gems系列 http://ogldev.atspace.co.uk/index.html 中文翻译版参看: http://wiki.jikexueyuan.com/project/modern-opengl-tutorial/ http://www.songho.ca/opengl/index.html https://learnopengl.com/#!Introduction 英文打不开可参看: https://learnopengl-cn.github.io/ 或者 http://bullteacher.com/category/zh_learnopengl_com http://www.lsngo.net/category/unityshader/ 大地形加载 https://catlikecoding.com/unity/tutorials/ https://www.jianshu.com/p/8ba49323ee8f 翻译了部分的catlike https://www.ronja-tutorials.com/ https://www.alanzucconi.com/2018/01/03/learning-shaders/ http://www.shaderslab.com/shaders.html https://github.com/Centribo/Unity-Shader-Basics-Tutorial https://unitygem.wordpress.com/ http://geekfaner.com/ https://github.com/Unity-Technologies/ScriptableRenderPipeline http://blog.three-eyed-games.com/ 光线追踪 https://github.com/openglredbook/examples opengl编程指南第九版git源码 http://www.realtimerendering.com/raytracing/Ray%20Tracing%20in%20a%20Weekend.pdf http://www.realtimerendering.com/raytracing/Ray Tracing_ The Next Week.pdf http://www.realtimerendering.com/raytracing/Ray Tracing_ the Rest of Your Life.pdf https://github.com/openglredbook/examples 红宝书 openg编程指南代码下载地址,下载git的源码,包含模型资源文件 https://github.com/openglsuperbible/sb7code 蓝宝书 opengl superbible代码下载地址 http://www.openglsuperbible.com/previous-editions/ 蓝宝书的其他版本的代码 http://www.realtimerendering.com/ 实时渲染官网 https://zhuanlan.zhihu.com/p/26409746 卡通渲染 https://www.zhihu.com/collection/76174725 知乎中的图形学网址 http://www.wjgbaby.com/ 大三学生的博客 https://www.xinpianchang.com/e14992?tdsourcetag=s_pcqq_aiomsg 常见贴图术语 https://academy.substance3d.com/courses/the-pbr-guide-part-1 https://academy.substance3d.com/courses/the-pbr-guide-part-2 substance 的pbr指南 https://vulkan-tutorial.com/ vulkan教程

vue 折叠面板,列表固定表头固定左侧

##调用 <common-list :titleArr="item.textArr" :list="item.children" :detph="0" ></common-list> // 展示数据 list2: [ { textArr: [{ name: "测试123" }], children: [ { textArr: [ { name: "测试123" }, { name: "区总监" }, { name: "维持" }, { name: "2023-03-31" }, { name: "维持" }, { name: "2023-03-31" }, ], }, { textArr: [ { name: "测试123" }, { name: "区总监" }, { name: "维持" }, { name: "2023-03-31" }, { name: "维持" }, { name: "

Windows10关闭占用端口号的进程

描述:经常遇到端口号占用异常,这时候就需要指定关闭这个占用的端口号进程,重启电脑是一个最简单的办法,但往往重启电脑后需要重新运行各种需要的程序,因此也不是长久之计,这时候需要用控制台关闭指定的进程。 一、Windows+R输入cmd回车,打开控制台,使用查看指定端口命令:netstat -ano | findstr 端口号 netstat -ano | findstr 端口号 如图所示: 查看端口时可能会出现以上两种情况:一种是LISTENING,另一种是TIME_WAIT ; 当参数为 TIME_WAIT时,表示占用此端口的那个进程正在改变状态,稍等一下可能这个进程就结束了。参数为LISTENING 时,就需要手动关闭这个进程了,最后一个参数是这个进程的进程号,即图中 20144。 二、关闭进程 2.1 方式一:手动关闭进程,运行查看进程命令:tasklist | findstr 进程号 tasklist | findstr 进程号 查看进程的详细信息,第一个参数是启动该进程的程序,即图中java.exe,使用任务管理器将其关闭 2.2 方式二:执行此命令强制关闭指定进程号的进程,运行关闭进程命令:taskkill -PID 进程号 -F 登录后复制 taskkill -PID 进程号 -F

vue 折叠面板

<template> <div class="accordion-root"> <ul class="list-root"> <multilevel-accordion-children v-for="(child, index) in tree.children" :key="index" :tree="child" :position="index" :interleaveOffset="1" :reference="`${index}`" :level="0" :marginLeft="marginLeft" > <template slot-scope="_"> <slot :tree="_.tree" :interleaved="_.interleaved" :expanded="_.expanded" :level="_.level" :leaf="_.leaf" ></slot> </template> </multilevel-accordion-children> </ul> </div> </template> <script> import MultilevelAccordionChildren from "./MultilevelAccordionChildren.vue"; export default { props: { tree: { type: Object }, marginLeft: { type: Number, default: 0 } }, components: { MultilevelAccordionChildren } }; </script> 子组件~~~~~~~~~~~~~~~~~~~ <template> <div class="accordion-children"> <li> <div class="accordion" @click="togglePanel()">

使用Spring-Security框架发送请求出现403错误

今天在学习security的自定义接口的时候,想着只需要只需4步就可以自定义一个简单的登录接口,分别是 1.使用AuthenticationManager进行认证 2.对认证失败进行响应 3.获取到用户信息,然后对用户Id进行jwt加密 4.将用户信息存入Redis中,以userId为Key,loginUser为键值。 想着很简单嘛,唯一的难点可能就是认证通过之后,如何获取到之后通过UserDatailsService接口将用户信息封装成LoginUser对象后,然后再如何获取到LoginUser对象,以便得到这个信息,存到Redis中,然后进行加密,并返回给前端。 这里的可以通过认证之后返回的那个Authentication对象,调用其getPrincipal()方法,即可获取到LoginUser对象,登录的业务实现完整代码如下: 由于之前学习Redis时,是基于Linux系统下面学习的,所以在我的本机电脑上面Redis没有,我还在网上去找了资源,下载好redis,然后启动redis,然后再执行程序,正当我兴奋的打开PostMan工具想尽快进行接口测试时,意外发生了,就一直报403的错误(简单概括就是服务器不认识你,没有权限访问),接连发了几次请求都是这样,我很不理解,马上询问度娘这到底是咋回事,查了许久,大概都是说打开了CSRF保护,这个是为了防止通过伪造用户请求来访问受信用站点的非法请求访问,开了这个导致的403,他说解决方案就是,关闭CSRF :http.csrf().disable(),我看了看我的配置,如下图所示: 也没问题呀,于是乎马上尝试另外的解决方案,还有的人说是因为实体类和表字段的映射出了问题,我又仔细检查了下,这里没问题,然后又查看另外的解决方案,还有人说要创建dns缓存,再cmd命令窗口,输入ipconfig flushdns即可,这个我没尝试,因为有点离谱。 ......就这样,进过一段时间的排错后,仍然没有解决问题,最后我突然想到,既然解决不了问题了,那我就debug呗,debug可以发现哪一段程序段,发生了问题,为此我还专门的学习了一下idea如何使用debug功能排错😂,然后我通过使用设置多个断点的方式,如下图所示: 我就断定肯定是认证出了问题,因为连第二个断点都没执行,if判断都没判断,相比就是上面 进行认证的这一关键步骤出了问题,随后我就想,既然是认证问题,那是不是会是密码检验出了问题呢?,结果还真是,因为我的数据库中密码字段存储的是明文,而我在项目中又做了 BCryptPasswordEncoder配置,一旦配置了这个,就总会将你在登录页面上输入的密码转化成加密后的字符串后,然后将这个字符串与数据库中的进行比较,因此只有当数据库中的密码字段值是暗文的时候,才能匹配成功,否则总是匹配失败,于是我立马使用一个单元测试方法 获取到这个暗文后,将其对数据库中的修改成这个,然后经过postMan测试成功了。 数据库修改: 在postMan上面测试成功: 总结: 发生这种情况原因可能有很多: 可能是没有关cfrf,也有可能是表字段和实体类属性映射出现了问题,还有可能是存在dns缓存,等等很多原因,而我的原因就在于,对数据库中密码字段值的忽略,没有修改成明文所对应的暗文。 总的来说,通过这次错误,让我见识到发生这种错误,可能是由哪些原因造成的,并且还学了debug,收获是有的。

基于STM32的ADC采样及各式滤波实现(HAL库,含VOFA+教程)

前言:本文为手把手教学ADC采样及各式滤波算法的教程,本教程的MCU采用STM32F103ZET6。以HAL库的ADC采样函数为基础进行教学,通过各式常见滤波的实验结果进行分析对比,搭配VOFA+工具直观的展示滤波效果。ADC与滤波算法都是嵌入式较为常见的,希望这篇博文能给读者朋友的工程项目给予些许帮助。(文末代码开源!) 实验硬件:STM32F103ZET6; 实验效果图: 一、ADC采样 1.1 ADC简介 单片机是数字芯片,只认识由0和1组成的逻辑序列。但实际情况下,生活中还有许多非0和1的模拟物理量存在,例如温度,湿度等。这时候往往需要使用到AD转换,AD转换的英文就是Analog(模拟) to Digital(数字) ,由模拟量转化为数字量;同理DA,则为Digital to Analog,数字量转化为模拟量。 ADC,Analog to Digital Converter 的缩写,中文名称模数转换器。它可以将外部的模拟信号转化成数字信号。使用它去读取IO口上的数值将不再是简单的0或1,而是连续可变的数值。ADC采样就是把随时间连续变化的模拟量转换为时间离散的模拟量。 ADC几个比较重要的参数: (1)测量范围:测量范围对于 ADC 来说就好比尺子的量程,ADC 测量范围决定了你外接的设备其信号输出电压范围,不能超过 ADC 的测量范围(比如,STM32系列的 ADC 正常就不能超过3.3V)。 (2)分辨率:假如 ADC 的测量范围为 0-5V,分辨率设置为12位,那么我们能测出来的最小电压就是 5V除以 2 的 12 次方,也就是 5/4096=0.00122V。很明显,分辨率越高,采集到的信号越精确,所以分辨率是衡量 ADC 的一个重要指标。 (3)采样时间:当 ADC 在某时刻采集外部电压信号的时候,此时外部的信号应该保持不变,但实际上外部的信号是不停变化的。所以在 ADC 内部有一个保持电路,保持某一时刻的外部信号,这样 ADC 就可以稳定采集了,保持这个信号的时间就是采样时间。 (4)采样率:也就是在一秒的时间内采集多少次。很明显,采样率越高越好,当采样率不够的时候可能会丢失部分信息,所以 ADC 采样率是衡量 ADC 性能的另一个重要指标(详细参考信号处理方向书籍)。 总之,只要是需要模拟信号转为数字信号的场合,那么肯定要用到 ADC。很多数字传感器内部会集成 ADC,传感器内部使用 ADC 来处理原始的模拟信号,最终给用户输出数字信号。 1.2 STM32的ADC STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC,STM32F103系列则有3个ADC和1个DAC),这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。

递归函数简介

当一个函数在其定义中直接或间接地调用了自身,我们称之为递归函数。递归函数通常用于处理具有递归结构的数据,例如树、图、链表等。 递归函数可以看作是解决问题的一种方式,一般使用递归函数可以使代码更加简洁、易懂。在实现递归函数时,需要满足两个条件: 递归结束条件(递归基):当递归到某个条件时,需要停止递归,返回结果。 递归调用:递归调用自身处理子问题,将子问题的结果合并为最终结果。 以下是一个简单的例子:计算 n!。 int factorial(int n) { if (n == 1 || n == 0) { // 递归结束条件return1; } else { return n * factorial(n - 1); // 递归调用 } } 在上面的例子中,当 n=1 或 n=0 时,函数返回 1,这是递归结束的条件,也称为递归基。如果 n>1,则函数将会调用自身来计算 n-1 的阶乘,然后将其乘以 n,这就是递归调用。 下面是另一个例子:求斐波那契数列第 n 项。 int fibonacci(int n) { if (n == 0) { // 递归结束条件1return0; } elseif (n == 1) { // 递归结束条件2return1; } else { return fibonacci(n - 1) + fibonacci(n - 2); // 递归调用 } } 在上面的例子中,当 n=0 时,函数返回 0,这是递归结束的条件之一。当 n=1 时,函数返回 1,这是递归结束的条件之二。如果 n>1,则函数将会调用自身来计算 n-1 和 n-2 的斐波那契数列值之和,这就是递归调用。

【已解决】mmcv/_ext.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN6caffe28TypeMeta21_typeMetaData

问题描述 使用MMDetection复现论文,出现如下Bug: ImportError:/home/quaiping/anaconda3/lib/python3.7/site-packages/mmcv/_ext.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN6caffe28TypeMeta21_typeMetaDataInstanceIdEEPKNS_6detail12TypeMetaDataEv 原因分析: mmcv官网点明了如何去判断并解决这类问题: 我这里稍微解释一下: 当报错中出现:“undefined symbol”或者“cannot open xxx.so”时,你可以从以下三个方面去考虑: 1.如果“undefined symbol”后面出现的是CUDA/C++ symbols, 具体来说,就是有Libcudart.so/GLIBXX类似内容,就检查CUDA/GCC运行时和编译mmcv时,是不是同一个版本。 补充:可能会有人问,如何去检查? 如果你是直接源码安装mmcv,或者通过pip install mmcv命令安装,那么mmcv在安装过程中有一个编译的过程,你只要保证这个过程的环境与最后运行代码的环境一致,就不会出问题。 如果你是通过下载编译好的whl文件去安装mmcv,就是通过类似命令:pip install mmcv-full==1.3.0 -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.8.0/index.html,那么你就去检查,你运行代码的环境中的cuda是不是与命令中的cu版本一致,查看自己环境的cuda版本命令:nvcc -V 很明显,我使用命令后,显示版本号为10.1,与cu101一致,如果你的结果不一致,就按照你自己环境中的cuda版本(红框中中对应的版本)去下载对应版本的mmcv. 2.如果“undefined symbol”后面出现的是Pytorch symbols,具体来说就是有caffe, aten, TH等内容,你就要检查你的环境中的pytorch版本与编译mmcv时使用的pytorch是否一致。 补充: 检查自己环境的pytorch:命令行依次键入:python import torch print(torch.--version--) 检查编译mmcv时的环境:看你通过pip install mmcv-full==1.3.0 -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.8.0/index.html安装mmcv时,torch是不是与你自己环境相对应。 3.进入目录./mmdet/utils ,运行python collect_env.py,查看PyTorch, torchvision, and MMCV 是否在同一个环境下运行。 解决方案: 很显然,我的bug属于第2种情况: _ZN6caffe28TypeMeta21_typeMetaDataInstanceIdEEPKNS_6detail12TypeMetaDataEv,我的undefined symbol后面出现了caffe字符,这时候需要我去检查我的pytorch版本。 我个人环境的pytorch版本为1.8.0,安装的mmcv是通过1.6.0的pytorch编译的,卸载1.6.0版本ptytorch编译的mmcv,安装对应1.8.0版本的mmcv就行了。

网页轮播图的代码原理分析和实现

一、结构搭建: <style> * { margin: 0; padding: 0 } img { border: 0; /*ie6*/ vertical-align: middle; } /*去掉列表前面的小点*/ li { list-style: none; } .fl { float: left; } .focus { position: relative; width: 721px; height: 455px; background-color: purple; overflow: hidden; } .focus ul { position: absolute; top: 0; left: 0; width: 600%; } .focus ul li { float: left; } .arrow-l, .arrow-r { display: none; position: absolute; top: 50%; margin-top: -20px; width: 24px; height: 40px; background: rgba(0, 0, 0, .

头结点和头指针

在链表的实现中,头结点和头指针是两个不同的概念。 头结点是一种特殊的结点,它不存储数据,仅用于方便链表的操作。头结点通常放在链表的最前面,是链表的第一个结点。头结点中一般包含链表的一些基本信息,比如链表长度、首结点位置等等。 头指针指向头结点的指针,它的作用是记录链表的起始位置。如果没有头结点,那么头指针指向的就是链表的第一个结点。但是为了方便链表的操作,通常都会添加一个头结点,这样头指针就指向头结点,而不是实际的数据结点。这样做的好处是,链表的插入、删除等操作可以统一处理,不需要针对链表首结点和其他结点分别处理。 下面以一个简单的单链表为例,来解释头结点和头指针的概念。 假设有如下链表: +----+ +----+ +----+ +----+ +----+ | |----->| |----->| |----->| |----->| | +----+ +----+ +----+ +----+ +----+ head 1st 2nd 3rd 4th 其中,head为头指针,指向头结点,1st为头结点,不存储数据,仅用于方便操作。 2nd、3rd、4th为链表中的实际数据结点。 在代码实现中,我们通常使用下列方式来定义头结点和头指针: typedefstructNode *PtrToNode;structNode { ElementType Data; PtrToNode Next; }; typedef PtrToNode List; typedef PtrToNode Position; List MakeEmpty() { List L = (List)malloc(sizeof(struct Node)); L->Next = NULL; return L; } 其中,List类型实际上是一个指向struct Node类型的指针,Position类型也是一个指向struct Node类型的指针。MakeEmpty函数中,创建了一个头结点,并将其Next指针初始化为NULL,然后返回头指针。这样,我们就可以通过头指针方便地操作链表了。

Camera HIDL接口实现camera preview功能

项目背景 为了在工厂测试中快速启动芯片外设测试项目,而不启动Android系统,使用fastmmi(FFBM: Fast Factory Boot Mode)测试框架。本人负责测试芯片中的camera外设,保证camera preview function,设置最原始的camera xml参数,preview图像清晰。使用Vendor NDK实现Android Camera preview.博客中使用vendor NDK的方式实现camera preview function。但是在项目中并没有能够使用,因为使用FFBM测试的时候发现camera service根本无法正常启动,所以只能使用HIDL interface来实现。 HIDL interface介绍 可以从Google的官方网站上查看,写得非常的详细:HIDL Interface.HIDL 的目标是可以在无需重新构建 HAL 的情况下上层系统替换框架。HAL 将由供应商或 SOC 制造商构建,并放置在设备的 /vendor 分区中,这样一来,就可以在框架自己的分区中通过 OTA 替换框架,而无需重新编译 HAL。这是一种解耦的思想,降低vendor和system 之间耦合度,通过把之间的接口媒介规定好,system和vendor各自升级替换都非常的方便。因为无法使用camera service作为中间媒介调用camera HAL,通过NDK interface就无法实现camera preview function。只能直接调用camera HAL层,虽然Qualcomm HAL是有interface提供使用的,但是太过于复杂而且并没有非常好的文档和sample支持。考虑使用Android camera HIDL interface,本身有Google强制规定接口形式和功能定义,并且有VTS testcase可以参考流程(虽然VTS testcase在configure stream中只是request一个buffer,result回调回来也没有进行处理,而是直接抛弃掉,但是configure stream的过程也是极具参考性) 源码逻辑分析 代码逻辑分析主要突出主干,送request到camera HAL进行处理,然后接收function callback result的一个循环。 代码中只给出大概的接口流程,突出整个camera设置的过程,并且讲解设置接口的意义,完整项目大家可以参考camera VTS code。 //获取HAL实现的命名 android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)[0]; //获取有几个camera device ICameraProvider::getService(service_name); getCameraDeviceNames(mProvider); //HIDL interface获取到device实例,本示例code中使用的是HAL所以是V3 ret = getCameraDeviceInterface_V3_x( name, [&](auto status, const auto& device) { ALOGI("

C++ 学习笔记 4 — 高级主题

C++ 学习笔记4 Overloading重载运算符自定义输出自增运算符重载 默认参数 异常处理catch 子句函数 try 块异常声明 命名空间匿名命名空间Using指令 模板函数模板类模板STL 参考 Overloading 函数签名包含了描述一个函数所必须的信息 函数名参数类型、个数、顺序等所在类和命名空间 当函数名相同时,编译器还是可以通过函数签名来决定究竟调用哪个函数。这里需要注意形参名称不是函数签名的一部分。函数声明时可以只给出参数类型的列表,因为形参名在声明时并不重要。有时可能见到函数的参数列表只有一个 void 关键字,代表不能传入参数 void main(void) {} 函数定义时也可以省略形参名 void fun(int) { cout << "fun called" << endl; } 重载运算符 重载的运算符可以是类中的一个成员函数 class Entry { public: int value; Entry(int value) : value(value) {} Entry operator+(const Entry& e) { return value + e.value; } }; void main() { Entry a(1), b(2); a + b; // a.+(b) } 也可以作为一个全局函数 class Entry { public: int value; Entry(int value) : value(value) {} }; Entry operator+(const Entry& lhs, const Entry& rhs) { return lhs.

SpringBoot集成 SpringSecurity安全框架

文章目录 一、CSRF跨站请求伪造攻击二、项目准备三、认识 SpringSecurity3.1 认证🎀①直接认证🎀②使用数据库认证 3.2 授权🍡①基于角色授权🍡②基于权限的授权🍡③使用注解判断权限 3.3 "记住我"3.4 登录和注销💥①原生登录界面💥②自定义登录界面💥注销 3.4 SecurityContext 提示:以下是本篇文章正文内容,Java 系列学习将会持续更新 一、CSRF跨站请求伪造攻击 我们时常会在 QQ 上收到别人发送的钓鱼网站链接,只要你在登录QQ账号的情况下点击链接,那么不出意外,你的号已经在别人手中了。实际上这一类网站都属于恶意网站,专门用于盗取他人信息,执行非法操作,甚至获取他人账户中的财产,非法转账等。 我们在 JavaWeb 阶段已经了解了 Session 和 Cookie 的机制,在一开始的时候,服务端会给浏览器一个名为 JSESSION 的 Cookie 信息作为会话的唯一凭据,只要用户携带此 Cookie 访问我们的网站,那么我们就可以认定此会话属于哪个浏览器。因此,只要此会话的用户执行了登录操作,那么就可以随意访问个人信息等内容。 要完成一次CSRF攻击,受害者必须依次完成两个步骤: 登录受信任网站A,并在本地生成 Cookie。在不登出A的情况下,访问危险网站B。 确实如此,我们无法保证以下情况不会发生: 你不能保证你登录了一个网站后,不再打开一个web页面并访问另外的网站。你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。 显然,我们之前编写的图书管理系统就存在这样的安全漏洞,而SpringSecurity就很好地解决了这样的问题。 二、项目准备 我们还是基于之前的 SpringBoot 项目 - 图书管理系统进行改造,需要实现以下: http://localhost:8080/index.html - 任何人都可以访问,不需要登录http://localhost:8080/book/{bid} - 任何人都可以访问,不需要登录http://localhost:8080/user/{bid} - 只有用户可以访问,必须登录http://localhost:8080/borrow/{uid} - 只有管理员可以访问,必须登录 回到目录… 三、认识 SpringSecurity Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理! 记住几个类: WebSecurityConfigurerAdapter:自定义 Security 策略AuthenticationManagerBuilder:自定义认证策略@EnableWebSecurity:开启 WebSecurity 模式 Spring Security 的两个主要目标是 “认证” 和 “授权”(访问控制)。