白屏是webview进程终止之后的表现,在webview因异常使用内存、CPU等资源时,webkit会终止当前m页展示的进程,在用户端表现为白页。
第一、webview的进程被终止的原因有哪些? ProcessTerminationReason { ExceededMemoryLimit,//超出内存限制 ExceededCPULimit,//超出CPU限制 RequestedByClient,//主动触发的terminate Crash,//web进程自己发生了crash NavigationSwap,//m页的加载环境出现了变化 }; 第二、内存限制是如何计算的? 1、苹果是如何计算当前内存的使用量的? 主要是通过计算当前进程的phys_footprint来度量内存的使用量
namespace WTF { size_t memoryFootprint() { task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count); if (result != KERN_SUCCESS) return 0; return static_cast<size_t>(vmInfo.phys_footprint); } } 2、内存使用过量的阈值是如何计算的? 内存超出的计算依赖了两个值:基于CPU框架的基本阈值baseThreshold和手机内存大小ramSize来计算阈值
static size_t thresholdForMemoryKillWithProcessState(WebsamProcessState processState, unsigned tabCount) { size_t baseThreshold = 2 * GB; #if CPU(X86_64) || CPU(ARM64) if (processState == WebsamProcessState::Active) baseThreshold = 4 * GB; if (tabCount > 1) baseThreshold += std::min(tabCount - 1, 4u) * 1 * GB; #else if ((tabCount > 1) || (processState == WebsamProcessState::Active)) baseThreshold = 3 * GB; #endif return std::min(baseThreshold, static_cast<size_t>(ramSize() * 0.
文章目录 1. 关于java - 代理模式2. 静态代理3. 动态代理3.1 JDK的Proxy类3.1 cglib类库 4. asm 和 instrument 1. 关于java - 代理模式 代理模式的组成:被代理类 和 代理类 2. 静态代理 代理类对象,通过聚合被代理类对象,调用对方的方法。eg: Thread的run方法实现。主要组成:接口 、实现类 和 代理类。 其中接口定义标准,是为了使代理更加规范可控,以及实现多级代理,实现类 也就是被代理类。
package com.demo.design.proxy; /** * 代理模式组成:接口、实现类、代理类 * 代理模式-静态代理:通过聚合持有被代理类实例,进行功能增强. eg: Thread的run方法的实现 */ public class ProxyPatternDemo { public static void main(String[] args) { Movable proxyObj = new ProxyMovable(new Bike()); proxyObj.move(); } } /** * 接口:可移动的 */ interface Movable { void move(); } /** * 被代理类(实现类):自行车 */ class Bike implements Movable { @Override public void move() { System.
论文:Unified Named Entity Recognition as Word-Word Relation Classification
发表方:武汉大学,发表于AAAI2022
论文链接:https://arxiv.org/abs/2112.10070
开源代码:https://github.com/ljynlp/W2NER
这篇论文主要是针对“flat NER”(就是最普通的NER)、“重叠NER”和“不连续NER”三种NER的子任务,提出了一种统一的word-word pair的标注框架,并且提出了一个相对应的模型结构来进行学习,他们在三个tasks的多个数据集上取得了SOTA的成绩。
标注框架 标注框架 我们首先来看一个论文中举的NER样本:
{ 'text': 'I am having aching in legs and shoulders', 'entity_list': [ {'entity_text': 'aching in legs', 'index': [3, 4, 5], 'entity_type': 'Symptom'}, {'entity_text': 'aching in shoulders', 'index': [3, 4, 7], 'entity_type': 'Symptom'} ] } 标注框架示例 上面的例子在这个标注框架中的示例如上图所示,对于一个句子,这个框架首先搞了一个word-word矩阵(如上图的右侧矩阵),在矩阵中定义了两种类型的标记:
NHW,Next-Neighboring-Word,这个类型的标记只会出现在上三角矩阵中(不包括对角线部分),上三角矩阵的元素取值只有0和1两种,(也就是图中矩阵中标注NHW的格子)表示,在某个实体中,第i个单词后面接着的是第j个单词,比如表示在某个实体中,第3个单词(从0开始数)aching后面跟着的单词是in。
THW-entity_type ,Tail-Head-Word-entity_type,这个类型的标记只会出现在下三角矩阵中(包括对角线部分),entity_type就是实体的类型,代码里面其实这个THW-entity_type直接就用entity_type的id就可以了,表示,第i个单词是某个实体类型ID为3的实体的结尾词(tail word),而第j个单词是这个实体的开始词(head word),比如表示单词shoulders是实体的结尾,这个实体的开头是aching,这个实体的类型是Symptom。
这个框架可以直接把三种NER的subtasks全部一勺烩了,借用论文中举的4个例子,大家感受一下:
不同类型的NER 解码方法 了解了标注框架后,我们来看看它的解码方法:
解码算法 其实就是一个DFS,大致步骤这里描述一下:
首先在下三角矩阵中找THW-entity_type标签,假设第i行第j列是THW-entity_type,如果,说明是一个单字实体,直接加入结果集E和T,否则去第2步
如果,则说明第i个单词是实体的尾部,第j个单词是实体的起始,那么一定会有,然后我们第j行的第j+1列开始找NNW,假设在第j行第k列找到NNW,则去第k行的第k+1列接着向后找,直到到达第i列为止,找到第i列的话,把从j开始通过NNW迄今为止串起来的token作为是一个实体加入结果集。
(但弱弱的说一句,这种情况的话,如果开头和结尾完全重叠,但中间不重叠的俩实体,岂不是就分不出来,是不是得在NNW上面也加上实体类型,哈哈)
模型结构 其实这篇论文这个标注的框架比较重要,但还是要介绍一下模型。
文章目录 1. 顺序表2. 顺序表的初始化 1. 顺序表 顺序表(顺序存储结构) 存储数据时,会提前申请一整块足够大小的物理空间,然后将数据依次存储到一整块连续的存储空间内,存储时做到数据元素之间不留一丝缝隙。
使用顺序表存储集合 {1,2,3,4,5},数据最终的存储状态如图所示:
2. 顺序表的初始化 使用顺序表存储数据之前,除了要申请足够大小的物理空间之外,为了方便后期使用表中的数据,顺序表还需要实时记录以下 2 项数据:
顺序表申请的存储容量;顺序表的长度,也就是表中当前存储数据元素的个数; 因此,我们需要自定义顺序表,C 语言实现代码如下:
typedef struct List { int *head; //声明了一个名为head的长度不确定的数组,也叫“动态数组” int length; //记录当前顺序表的长度 int size; //记录顺序表分配的存储容量 }SqList; 接下来初始化顺序表,即初步建立一个顺序表。建立顺序表需要做如下工作:
给 head 动态数组申请足够大小的物理空间;给 size 和 length 赋初值; C 语言初始化顺序表(创建空表)的代码如下:
#define SIZE 5 //对SIZE进行宏定义,表示顺序表申请空间的大小 SqList InitList() { SqList L; L.head = (int *)malloc(SIZE * sizeof(int)); //构造一个空的顺序表,动态申请存储空间 if(!(L.head)) //如果申请失败,作出提示并直接退出程序 { printf("初始化失败"); exit(0); } L.size = SIZE; //空表的初始存储空间为SIZE L.length = 0; //空表的长度初始化为0 return L; } 通过在主函数中调用 InitList 函数,就可以成功创建一个空的顺序表,然后我们可以试着向顺序表中添加一些元素再打印出来,C 语言完整代码清单如下:
1.问题描述
2000以内的不小于4的正偶数都能够分解为两个素数之和(即验证歌德巴赫猜想对2000以
内的正偶数成立)。
2.问题分析
根据问题描述,为了验证歌德巴赫猜想对2000以内的正偶数都是成立的,要将整数分解
为两部分,然后判断分解出的两个整数是否均为素数。若是,则满足题意,否则应重新进行
分解和判断。
针对该问题,我们可以给定如下的输入和输出限定。
输入时:每行输入一组数据,即2000以内的正偶数n,一直输入到文件结束符为止。
输出时:输出n能被分解成的素数a和b。如果不止一组解,则输出其中a最小的那组解。
当然,读者可以根据实际的需要规定不同的输入和输出形式。
输入示例:
4
6
8
10
12
输出示例:
2 2
3 3
3 5
3 7
5 7
3.算法设计
本问题我们可以采用函数来解决。
(1)fun(n)函数判断输入的n值是否为素数
定义一个函数,函数名设为fun,在其中判断传进来的形参——设为n(n≥2),是否为素
数,如果是素数则返回1,否则返回0。在判断是否为素数时,可以采用5.1节中介绍的方法。
需要注意的是,在所有偶数中,只有2是唯一的素数。因此,在函数fun()中,可以分为以下4
种情况来判断:
·n=2,是素数,返回1。
·n是偶数,不是素数,返回0。
·n是奇数,不是素数,返回0。
·n≠2,是素数,返回1。
(2)guess(n)函数用于验证哥德巴赫猜想
由于我们已经对输出做了限定,即当输出结果时,如果有多组解,则输出a最小的那组
解。显然,对每个读入的数据n,a必然小于或等于n//2,因此,定义循环变量i,使其从2~n/2
进行循环,每次循环都做如下判断:fun(i) and fun(n-i)是否为1。
如果fun(i) and fun(n-i)=1,则表示fun(i)=1同时fun(n-i)=1。由fun()函数的定义可知,此时i
和n-i都为素数,又由于i是从2~n/2按由小到大的顺序来迭代的,因此,(i,n-i)是我们求出
的一组解,且该组解必然是所有可能解中a值最小的。
还需要注意的是,由于除了2以外的偶数不可能是素数,因此,i值的可能取值只能是2和
所有的奇数。
4.确定程序框架
(1)程序主框架
程序的主框架是一个while循环,每输入一个数据就处理一次,直到人为结束程序或输入
非法数据而终止输入。代码如下:
while True: # 循环输入 n = int(input()) guess(n) # 调用函数验证哥德巴赫猜想 (2)使用函数判断n是否为素数
在算法设计中我们详细介绍了fun()函数,它的功能就是判断传进来的形参n是否为素数,
其代码如下:
文章目录 实时指标计算风险态势感知系统基于统计分析的方法核心风控指标数据核心业务数据 基于无监督学习的方法基于欺诈情报的方法预警系统 风险数据名单体系(名单库)欺诈情报体系数据情报技术情报事件情报情报分析 实时指标计算 首先,大致上都有哪些场景。
设备上登录 过多的账户1 天内设备上登录的账户过多设备使用 HTTP 代理登录设备某段时间的移动距 离、账号某段时间范围内的活跃天数等(累计) 在风控反欺诈业务中,专家规则和模型都需要使用到大量的指标,常见类型如表所示。
指标计算可以抽象总结出以下几个固有特征:
时间窗口事件主属性副属性计算逻辑 风险态势感知系统 通过风控系统,我们可以综合利用风险数据名单、专家规则和机器学习模型等方法,对已知的风险类型进行防控。但是’该系统仍面临以下几个方面的挑战:
专家的水平差异性运营人员操作风险产品和系统 Bug 从上面的综述可以看出反欺诈体系建设中的风险预警的重要性:如何快速发现现有风控系统的防御盲区,预警随着线上己经逐渐失效的防控策略,从实际对抗效果出发促进风控系统不断完善。
我们引入 态势感知的概念 来解决这类问题态势感知源于军事,覆盖感知、理解和预测 3个层次。在业务安全领域中,风险态势感知是以安全大数据为基础,从全局视角提升对业务安全威胁的发现识别、理解分析和处置响应的一种方式。
风险态势感知系统的方法主要有基于 统计分析的方法、基于半监督、无监督算法的聚类方法和基于业务情报的方法。这些分析方法基于以下几个前提:
正常业务具有连续性和稳定性’异常事件具有波动性。常用户总是表现出分布离散性,黑产总是表现出聚集性。 基于统计分析的方法 基于统计分析的方法,核心的统计数据主要包括以下两大类:
核心风险事件数据:主要指风控系统中产生的数据,包括实时决策系统的入参、 出参、中间计算结果、决策结果等。核心业务数据:主要指业务自身的核心数据指标’和具体业务场景相关’如电 商、O2O、直播等各不相同。 核心风控指标数据 调用量人申率PSI:PSI即风险分布情况字段获取率 核心业务数据 基于无监督学习的方法 有监督学习需要给样本数据打标,而无监督学习方法可以对大量未标注的数据集按照数据内部存在的数据特征划分为多个不同的类别。
因为每一个个体的行为都比较独立,如果把平台上账号的行为进行归类,则会发现普通用户的行为比较分散,而团伙的行为会形成异常的聚集点。通过这个思路,使用无监督学习方法可以有效地发现未知的欺诈的团伙。
无监督学习方法的步骤—般包括 特征抽取、建立连通图、群组聚类等。
基于欺诈情报的方法 当业务系统发生业务漏洞,无法防控黑,被黑产利用时,黑产往往会通过论坛、 社交网站、社交软件等方式进行讨论和分享。业务情报系统捕获这些情报信息之后,提 取业务场景、漏洞类型、攻击手法等信息。这时及时通知对应的策略运营人员,策略运营人员可以快速进行业务确认,并上线新的策略进行防控。
预警系统 风险数据名单体系(名单库) 欺诈情报体系 对于黑产情报的采集,—般通过卧底黑产网络、监控黑产论坛等方式进行。普通的信息采集工作会通过各种IM聊天机器人等自动化的工具实现,而深入追踪黑产网络则需要通过人工运营实现。
欺诈情报分为三大类 :数据情报、技术情报 和 事件情报,下面分别进行介绍。
数据情报 数据情报指的是能够沉淀手机号、IP、设备及邮箱账号等黑产名单数据的情报信息。这类情报对互联网平台是具有价值的情报’可以进行直接使用,快速打击黑产为平台止损。
技术情报 技术情报指的是针对某一种欺诈技术的详细信息,包括原理、用途、危害等。互联 网企业和黑产的对抗,在某种程度上就是_个推动技术发展的过程’黑产的攻击往往促使互联网平台研发和运用新的技术,不断更新自身的技术体系。
事件情报 情报体系捕获的某欺诈事件即将发生、正在发生或已经发生过的信息均可称为事件情报。事件情报可用于预警即将发生的风险事件、阻断正在发生的风险事件和事后溯源 已经发生过的风险。
情报分析 相似度算法去重
笔记来源:尚硅谷SpringData教程(springdata经典,spring data快速上手)
文章目录 Repository 子接口1、Repository 子接口2、CrudRepository 接口3、PagingAndSortingRepository 接口4、JpaRepository 接口5、JpaSpecificationExecutor 接口6、自定义 Repository 方法总结 Repository 子接口 1、Repository 子接口 在之前 01-Repository 中我们介绍过 Repository 的几个子接口,现在重新回顾下这几个子接口的知识
CrudRepository:继承于 Repository,实现了一组 CRUD 相关的方法PagingAndSortingRepository:继承于 CrudRepository,实现了一组分页排序相关的方法JpaRepository:继承于 PagingAndSortingRepository,实现了一组 JPA 规范相关的方法 Repository (org.springframework.data.repository) ----CrudRepository (org.springframework.data.repository) --------PagingAndSortingRepository (org.springframework.data.repository) ------------JpaRepository (org.springframework.data.jpa.repository) 另外,还介绍了
自定义的 XxxRepository:需要继承 JpaRepository,这样的 XxxRepository 接口就具备了通用的数据访问控制层的能力JpaSpecificationExecutor:不属于 Repository 体系,实现一组 JPA Criteria 查询相关的方法 2、CrudRepository 接口 CrudRepository 方法一览
CrudRepository 源码解析
@NoRepositoryBean public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { // 保存实体 <S extends T> S save(S entity); // 保存实体集 <S extends T> Iterable<S> save(Iterable<S> entities); // 通过 id 查找实体 T findOne(ID id); // 判断指定 id 的实体是否存在 boolean exists(ID id); // 返回该类型的所有实例 Iterable<T> findAll(); // 返回指定 ID 类型的所有实例 Iterable<T> findAll(Iterable<ID> ids); // 返回可用实体数 long count(); // 删除指定 ID 的实体 void delete(ID id); // 删除实体 void delete(T entity); // 删除实体集 void delete(Iterable<?
基于Java语言规范《JLS Java SE 8 Edition》。
类体(class body)可以包含类的成员(members of a class)、实例初始化器(instance initializer)、静态初始化器(static initializer)和构造器(constructor)。
ClassBody:{ {ClassBodyDeclaration} }
ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
成员 类的成员包括域(field)、方法(method)、类(class)和接口(interface),因此构造器、静态初始化器和实例初始化器不是成员。
ClassMemberDeclaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
InterfaceDeclaration
域 域即类的变量(variables of a class)。用static修饰的域是静态域(static field),有时称为类变量(class variable。注意和类的变量区分)。没有用static修饰的域(有时被称为非静态域(non-static field))被称为实例变量(instance variable)。
方法 用static修饰的方法是静态方法(static method),又叫类方法(class method)。没有用static修饰的方法被称为实例方法(instance method),有时被称为非静态方法(non-static method)。
1. 缓存位置 会依次查找 Service Worker、Memory Cache、Disk Cache、网络请求
2. 强制缓存 HTTP1.0
通过响应头设置 Pragma: no-cache;,表示每次都会向服务器发送请求
通过响应头设置 Expires: Thu, 10 Nov 2017 08:45:11 GMT,可以指定具体时间,表示还未到此时间点则不发起请求,但此时间是相对于服务器时间而言的,如果客户端时间和服务器时间不一致那就没什么用了
HTTP1.1
通过响应头设置 Cache-Control: max-age=3600; 表示资源缓存的最大时间,该时间内不会发起请求。注意区分 max-age=0、no-cache、no-store 的差异,max-age=0,会先检验 Last-Modified/ETag,并通过对应的请求头携带;no-cache 会缓存内容,每次会发起请求,是否使用此内容由后续的对比决定;no-store 不缓存,所有内容不走缓存直接发起请求
优先级
Pragma > Cache-Control > Expires
3. 对比缓存 对比缓存又叫协商缓存,当强制缓存失效时,就需要使用对比缓存,对比缓存在请求数量上和没有缓存并无差异,但若返回的 304 其实仅仅是一个状态码,并没有实际的内容,在响应体体积上的节省才是它的优化点
Last-Modified 和 If-Modified-Since
1、服务器响应 Last-Modified 字段标记最后一次被修改的时间
2、浏览器下一次请求相同资源时,在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段
3、服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比,相等则响应 304,反之则响应 200 状态码,并返回修改后的数据
缺陷:如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒
Etag 和 If-None-Match
1、服务器响应文件的特殊标识(摘要)Etag
2、浏览器下一次请求相同资源时,通过请求头 If-None-Match 带上 Etag
1.概述 JAVA常用的日志收集api和实现框架都有多种,不同的api和实现框架之间怎么相互兼容都比较复杂,不过大部分的日志框架实现也都提供了对其他日志收集方式的兼容和切换(可以参考slf4j、jcl、jul、log4j1、log4j2、logback大总结 - 乒乓狂魔 - OSCHINA - 中文开源技术交流社区)。本文主要介绍log4j2的Appenders下的组件列表,及几种比较常见的appender配置。
2.配置详解 log4j2.xml文件结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Configuration>
<Properties>
...
</Properties>
<Appenders>
...
</Appenders>
<Loggers>
...
</Loggers>
</Configuration>
配置文件由Properties、Appenders、Loggers三块组成。Properties配置基础变量,Loggers负责配置日志级别,Loggers配置日志收集方式、布局、输出、清理等功能。
2.1. appender组件列表 append描述AsyncAppender用于接受其他类型appender的引用,并使用单独线程异步写入logCassandraAppender将日志写入Cassandra数据库中,需要提前建立keyspace和tableConsoleAppender其日志写入System.out或System.err,默认为System.outFailoverAppender故障转移appender,可以指定主appender,并且包含一组appender集合,当主appender写入失败,则会依次使用其他append写入,直至写入成功或者全部appender写入失败FileAppender将日志写入文件,使用FileManager执行ioFlumeAppender将日志序列化后发送给Flume代理。
可选组件,由单独的jar提供。JDBCAppender使用标准JDBC将日志写入关系数据库表,必须使用连接池JMS Appender将日志发送至JMS中JPAAppender通过JPA将日志写入关系型数据库表,需要有单独的persistence.xml配置文件HttpAppender通过http请求发送日志,使用HttpURLConnection实现,响应2XX状态码为成功,否则抛出异常KafkaAppender将日志事件发送到Kafka的topic中MemoryMappedFileAppender2.1新增功能,将指定日志文件的一部分映射至内存,并将新日志事件写入此内存,达到阈值时将此内存刷新至存储设备NoSQLAppender使用内部轻量级Provider接口将日志事件写入NoSQL数据库。目前只有MongoDB和Apache CouchDB的Provider实现NoSQLAppender for MongoDB2.0.11开始,提供两个MongoDB模块:log4j-mongodb2、log4j-mongodb3NoSQLAppender for MongoDB 2使用MongoDB驱动程序版本2将日志写入MongoDB中NoSQLAppender for MongoDB 3使用MongoDB驱动程序版本3将日志写入MongoDB中NoSQLAppender for Apache CouchDB使用内部轻量级Provider将日志写入CouchDB中OutputStreamAppenderOutputStreamAppender不能直接配置,只是作为基础组件提供给其他Appender使用,如可以将日志事件写入输出流的File和SocketRandomAccessFileAppender与FileAppender相比,使用的I/O实现类不同,FileAppender使用FileOutputStream,RandomAccessFileAppender 使用RandomAccessFile。bufferedIO=true(默认是true)时,性能提高20-200% 。RewriteAppender用于在日志被其他Appender写入文件之前,通过RewritePolicy修改日志事件RollingFileAppender将日志写入文件,并根据TriggeringPolicy和RolloverPolicy规则将文件归档、清理RollingRandomAccessFileAppender与RollingFileAppender相比,使用的I/O实现类不同,RollingFileAppender使用FileOutputStream,RollingRandomAccessFileAppender使用RandomAccessFile。bufferedIO=true(默认是true)时,性能提高20-200% 。RoutingAppender配置不同的规则,将日志路由到不同的Appender进行输出SMTPAppender发生指定日志事件时,发送电子邮件ScriptAppenderSelector根据Script脚本的执行结果来选择AppenderSet中配置的Appender,并将结果输出至ScriptAppenderSelector的name中SocketAppender通过tcp或者udp,将日志写入远程目标中SyslogAppenderSyslogAppender是一个SocketAppender,它将其输出以符合BSD Syslog或RFC 5424格式的日志写入到远程目标ZeroMQ/JeroMQ AppenderZeroMQ Appender使用JeroMQ库将日志事件发送到一个或多个ZeroMQ端点 2.2.ConsoleAppender ConsoleAppender比较简单,就是把日志写入System.out或者System.err中,基本配置如下:
<Console name="STDOUT" target="SYSTEM_ERR">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %5p [%c:%L] - %m%n" />
</Console>
Console一般使用基本配置就可以,唯一要注意的就是输出格式pattern,pattern的配置释义如下:
参数描述%c或%logger输出logName,如 Logger log = LoggerFactory.
highlight.js(代码高亮插件) 官网用法查看 核心 API Highlight.js 将一些函数导出为hljs对象的方法
强调 highlight(code, {language, ignoreIllegals}) 核心高亮功能。接受代码以突出显示(字符串)和选项列表(对象)。该language参数必须存在并指定用于突出显示的语法的语言名称或别名。这ignoreIllegals是一个可选参数,即使在检测到语言的非法语法而不是抛出异常的情况下,真正强制突出显示完成时也是如此。
返回具有以下属性的对象:
language: 语言名称,与传入的名称相同languageName,返回以保持一致highlightAutorelevance: 表示相关性分数的整数值value: 带有高亮标记的 HTML 字符串top:当前模式堆栈的顶部illegal: boolean 表示是否发现任何非法匹配code:原始原始代码 高亮自动 highlightAuto(code, languageSubset) 使用语言检测突出显示。接受带有要突出显示的代码的字符串和一个可选的语言名称和别名数组,将检测限制为仅这些语言。也可以使用 设置子集configure,但如果设置了本地参数,则会覆盖该选项。
返回具有以下属性的对象:
language: 检测到的语言relevance: 表示相关性分数的整数值value: 带有高亮标记的 HTML 字符串secondBest:具有相同结构的对象,用于第二好的启发式检测语言(可能不存在) 高亮元素 highlightElement(element) 将突出显示应用于包含代码的 DOM 节点。
此函数用于在页面加载后或在第三方 JavaScript 框架的初始化代码中动态应用突出显示。
该函数默认使用语言检测,但您可以在classDOM 节点的属性中指定语言。有关所有可用的语言名称和范围,请参阅范围参考。
高亮全部 将突出显示应用于页面上匹配配置的所有元素cssSelector。默认cssSelector值为,它突出显示所有代码块。这可以在页面事件触发之前或之后调用。'pre code'``onload
配置 configure(options) 配置全局选项:
classPrefix: 在生成的标记中类名之前添加的字符串前缀,用于向后兼容样式表。languages:一组语言名称和别名,将自动检测限制为仅这些语言。languageDetectRe: 一个正则表达式,用于配置 CSS 类名如何映射到语言(允许类名,例如color-as-php与language-php的默认值等)noHighlightRe:一个正则表达式,用于配置要完全跳过哪些 CSS 类。cssSelector: 一个 CSS 选择器,用于配置受hljs.highlightAll. 默认为.'pre code'ignoreUnescapedHTML:不要在控制台中记录有关代码块中未转义 HTML 的警告throwUnescapedHTML``HTMLInjectionError:当highlightElement被要求突出显示包含未转义 HTML 的内容时抛出 接受一个对象,该对象表示具有要更新的值的选项。其他选项不变
hljs.configure({ noHighlightRe: /^do-not-highlightme$/i, languageDetectRe: /\bgrammar-([\w-]+)\b/i, // for `grammar-swift` style CSS naming classPrefix: '' // don't append class prefix // … other options aren't changed }); 注册语言 registerLanguage(languageName, languageDefinition) 以指定名称将新语言添加到库中。主要在内部使用。
文章目录 一、前言二、为什么推荐使用Addressables三、Addressables基础操作教程1、下载Addressables插件2、创建Addressables Settings3、给Group添加资源4、创建新的Group5、设置Build Path与Load Path6、修改RemoteBuildPath和RemoteLoadPath7、打Addressable资源包8、打Android APK9、加载Addressable资源9.1、方式一:通过Addressable Name来加载资源9.2、方式二:通过AssetReference来加载资源 10、Addressable资源三个加载模式10.1、Use Asset Database (fastest)10.2、Simulate Groups (advanced)10.3、Use Exising Build(requires built groups) 11、加载远程Addressable资源11.1、启用Hosting Services11.2、加载远程包的柯南图片11.3、Addressables是如何知道去哪里加载资源的11.4、打个APK包瞧瞧 12、如何把Group里的资源打成多个bundle文件13、使用Labels对Group内的资源进行二级分组13.1、新建Label13.2、给资源设置Label13.3、修改Bundle Mode为Pack Together By Label13.3、一个资源标记多个Label 14、批量加载同一个Label的所有资源(AssetLabelReference)15、打资源热更包15.1、开启Build Remote Catalog15.2、打包Addressable资源包15.3、加载小兰的图片15.4、打成APK15.5、替换小兰的图片15.6、打热更包,Update a Previous Build15.7、上传热更包15.8、热更测试 16、提前检测更新并下载(预下载)17、Addressable资源释放18、打包工具集成Addressable打包流程 四、答疑补充(Q&A)1、Addressables加载场景进度监听 五、完毕 一、前言 嗨,大家好,我是新发。
之前就有看过Unity的Addressable Asset System,简称AA,但那时候这个功能刚出来,出于稳定性考虑,所以暂时没有去使用它。现在,它已经迭代到1.16.19 Release版本了(中国版是1.19.16),经过了时间考验,可以拿出来讲讲啦,网上其实已经有不少讲Addressables系统的文章,不过很多不是最新版的教程,今天我就来写一下最新版的Addressables系统的使用教程吧~
二、为什么推荐使用Addressables 我在之前的好几篇文章中都介绍过Unity加载资源的几种方式,我还画过一个图,详细可以看我之前写的这篇文章:《Unity游戏开发——新发教你做游戏(三):3种资源加载方式》
可以看出来,资源的加载方式要根据应用场景进行区分,要注意资源存放的文件夹,要注意不同平台下的差异,如果使用AssetBundle形式,加载的时候要小心AB包之间的依赖关系,我之前也写了一篇文章讲如何去加载AB的依赖资源,《Unity 打包与加载AssetBundle(加载对应的依赖)》
如果要做资源热更新,也要自己去写工具实现增量资源包的打包,然后自己实现热更检测、资源下载、MD5比对,解压等等逻辑,我之前还专门写了一篇文章讲了热更新的流程,《【游戏开发高阶】从零到一教你Unity使用ToLua实现热更新(含Demo工程 | LuaFramework | 增量 | HotUpdate)》
相信你看完我的这些文章,就会吐槽,哇,好麻烦啊,对于新手来说,可能就是劝退,现在呢,不用怕了,Addressables系统统统搞定,用起来实在是太香了,本博主强烈推荐!
三、Addressables基础操作教程 1、下载Addressables插件 点击菜单Window / Package Manager,打开插件包管理界面,
搜索addressables,可以看到有两个插件包,带.CN结尾的是中国增强版,
这里要补充说一下,Addressables的打包方式其实也是AssetBundle格式,只是在此基础上做了一层封装,方便进行管理(比如打包、加载、依赖等)。而我们知道,没有加密的AssetBundle是可以使用AssetStudio等工具轻易进行资源逆向的,
注:AssetStudio资源逆向工具开源地址:https://github.com/Perfare/AssetStudio
Addressables.CN版本会对AssetBundle做加密处理,
为了方便下文演示资源逆向,我这里就先下载不带.CN结尾的版本,
注:实际项目中,建议大家下载Addressables.CN版本。
安装成功后,可以看到多出了一个Window / Asset Management / Addressables菜单,
理解操作系统里面的进程调度算法,作业调度算法,存储管理,磁盘调度算法,通过c语言(加了一点c++)模拟实际调度过程
事前准备 确定好了基本思路:
首先看课本,要理解相关的算法,在理解方面,作业调度里面的算法理解起来有点困难体现在:**什么时候调度作业?**最开始确定的是手动输入调度时间,找到在调度时间之前提交的作业,对这些作业进行调度。但是和老师交流后,发现调度时间并不是手动输入,而是应当在上一个作业完成时刻之后去调度。编程语言选择,因为实验报告上标注的是c/c++,所以我采用的是c语言,而没有考虑Java,事实上当老师说明可以使用Java的时候,我已经只剩下一个实验没有写,可见应当事先问清楚,搞清楚要求。所采用的方法:采用的是面向过程方法,先确定基本的数据结构,包括对相关实体的封装,然后画流程图和写伪代码,确定最基本的函数,然后确定函数的参数和返回值,最后解决函数调度次序和具体实现。在这个过程中,只要一开始理解了算法实现思路,编码并没有花太多的时间。测试数据准备:通过文件存储默认的数据,避免每次都需要输入测试数据,这在后面的测试中节约了大量的时间 实际实现过程 进程调度 没有遇到太大的困难,但是作为第一 v个实验,在构思(具体包括输入输出分析,数据结构设计,函数设计)上还是花了很多的时间。
首先确定了基本的数据结构为:链表和队列,并且可以实现其基本的操作,但是由于对c语言指针不熟悉以及一些特殊情况操作处理不足,花了很多时间在测试调试基本数据结构,总结经验如下
指针是地址,对应的是内存中的某一个存储单元,创建指针时,一定要制定 初始值,就算是空也要显示的说明为NULL;
结构体指针,特别时包含 next成员的时候,当需要独立出一个指针变量temp的时候,一定要做修改
temp->next=NULL; 否则,可以通过temp的next域访问其他节点,并不能达到独立temp指针的目的。
为结构体指针申请初始空间的时候,要显示的指定成员初始值,否则你也不知道编译器给它分配什么默认值,是一些特别奇怪的值
删除链表中指定元素考虑:链表为空(需要调用isEmpty()确定,而不能简单的使用list==NULL);删除的元素不存在;删除的元素为链表的头部,就算是维护最简单的数据结构,实现起来由于考虑不周也会产生问题。
特别是后面在实现双向队列的时候,在维护前向指针和后向指针的时候,的确花了点时间,关键是,这种基本的数据结构虽然在网上有详细的代码,但是我还是习惯自己动手实现。
借助基本数据结构及相关方法去实现具体的算法,并没有遇到太大的困难,但是由于一开始并没有考虑到的一些情况。在实现多级队列的时候,对于调度结果的输出,前面一直都正常,唯独最后一个进程在第四级队列开始执行时间和它在第三级队列执行的时间重合。这让我很郁闷?排除bug花了很长时间,发现原因在于判断进程是否执行完毕时,全局时间变量time++,导致时间对不上。进一步分析发现,不止最后一个进程时间输出有问题,前面的一些进程也有问题,问题归根于在于判断进程是否执行完毕时,全局时间变量time++。
作业调度 这一块遇到了较大的困难,主要是在理解算法上面,什么时候调度作业。是手动输入;还是自动确定调度时间。实现的第一版是按照手动输入调度时间进行的,但是不符合要求,后作出修改的时候,并没有遇到太大的阻碍,因为仅仅是修改全局事件变量time,而这个变量值的改变仅仅涉及几个主要的函数,这说明在设计函数阶段,每一个函数能够修改的变量不能过多,否则维护起来很麻烦。同时如果一个函数的功能过于复杂,要分解。在本次实验中做了如下分解:
接受用户输入函数input读取相关文件内容到queue,对应函数readMessage开始调度,定义全局时间变量time,平均周转时间,带权周转时间 找到time以前请求的作业findJobs到队列waitingQueue按照调度算法从waitingQueue中选取调度作业chooseJob到target执行target作业,run函数===》在后来的该动当中比较大在queue中移除target作业deleteJob计算并且更新相关时间computerAndPrintTime===》这一个函数参数很多,但是参数都属于时间这一类,因此从语义上来说,并不矛盾,在这里借用了c++里面的地址引用,其中传入函数的参数为变量地址引用判断作业是否执行完成。 输出平均周转时间和带权周转时间 无论是这里,还是上面的实验,都涉及到时间变量的定义和修改,应该满足下面几点要求:
系统中某个动作产生时,涉及开始执行时间,执行时间以及结束时间。当某个动作正在执行时,时间变量将被修改,模拟时间变量修改如下:
for(int time=startTime;time<=endTime;time++){ //执行一秒 //判断是否提前执行完毕 } 处理不同动作之间的并行,将不同动作写入同一个循环
startTime和endTime确定也比较麻烦,这里采用的是分别分析:
初始时,startTime为第一个作业的startTime,而endTime确定比较麻烦 在写此文时,我突然想到时间time变量应该独立出来,但是这种写法不适合并行执行操作
time=1;//初始时刻 while(1){ //执行各种各样的操作,他们都可以独立的修改time变量 time++; } 存储管理 这是我最得意的一个设计,整个过程下来行文流水,很顺利。无论是最后的测试结果还是中间的实现过程。我都很享受,其中令我最得意的是循环队列的设计
构思时很清楚,充分考虑了各种情况,编码环节很快乐,最后测试阶段仅仅执行了两次就通过所有的测试数据。
根据数据结构编写算法时,先确定基本的函数,实现基本函数。不过这里发生了一个小插曲,就是定位存储空间findMemory函数,根据什么查找存储区域。最开始是根据存储区域上运行的作业的名称,但是可能存在同一个作业多次申请空间,最后确定根据存储空间的开始地址和结束地址定位存储空间,的确可以标识唯一存储区域。
总结经验如下:
确定基本数据结构,编码完成之后需要测试基本功能,包括单个函数以及组合的函数
根据基本思路确定最关键的函数,分别实现函数,并测试
发现问题,运用调试解决,找到关键断点,需要使用if判断
if(断点条件){ 代码//在此处打断点,不要在if判断上 } 磁盘调度 相当简单,真的没有遇到什么困难,想必老师会失望,因为这个实验是选做的,而且估计是最简单的!!!!
完整项目地址
编者荐语
对于阅读英文文献和书籍,我并不赞成依赖于翻译软件,一定要自己先读原文,实在不懂再查单词,最后再去整句翻译(尤其是现在的很多翻译软件都支持整段甚至是整个文档的翻译,但真的不建议同学们这么做)。
随着 Zotero 6.0 的出现,我的工作流将会发生很大改变,最主要的原因就是zotero支持内置PDF,在阅读界面集PDF文档、标注和笔记于一体,且支持多篇文献笔记之间进行整合和文献互引,十分省心,软件用的越少也会让你在阅读的时候更加专注,效率也会更高。待阅读完毕之后,可直接导出markdown到Obsidian进行双链整合内化!
附上zotero链接:https://www.zotero.org/
Zotero更新太快了,去年,小编为了使用内置PDF浏览器功能,还在用beta版的Zotero。这次小编要介绍一个非常实用的插件PDF Translate, PDF Translate 是 Zotero 6.0 的附加组件之一,它为 Zotero内置的PDF浏览器提供了翻译功能。
链接:https://github.com/windingwind/zotero-pdf-translate
简介
功能演示
插件下载
点击右下角的链接【Release】,这是最新版本的PDFTranslate插件。
下载zotero-pdf-translate.xpi即可。
插件安装
接下来,就是安装PDFTranslate插件了,安装方法和zotero其他插件安装方法一样。打开Zotero,依次点击【Tools】-【Add-ons】,就能打开插件窗口。
在插件窗口,点击右上角齿轮,打开【install Add-on From File】,选择刚下载好的zotero-pdf-translate.xpi文件,就安装好了。安装好以后,会在插件列表看到这个插件。
在插件窗口,点击右上角齿轮,打开【install Add-on From File】,选择刚下载好的zotero-pdf-translate.xpi文件,就安装好了。安装好以后,会在插件列表看到这个插件。
安装以后,理论上应该需要重启。即Zotero PDF Translate 插件的扩展列表中单击【Restart】。
从Zotero菜单栏的【Edit】-【Preferences】可以打开PDF Translate 插件的设置面板,如下图所示。
使用方法
安装PDFTranslate插件后,打开收藏中的任何一篇英文PDF文件,体验一下。下图是笔者打开的一篇英文文献,用鼠标划取一段文字,会在附近弹出一个带有翻译结果的小窗口。同时,整个Zotero界面右边也给出了PDFTranslate插件的Translate面板。
PDF Translate 插件的 Translate 面板提供了多种翻译引擎,包括我们常用的谷歌、有道等。如下图所示,同学们可以自行选择一种适合自己的翻译引擎。
更多功能大家自行体验,小编这里就不多做介绍了。
再次附上链接:https://github.com/windingwind/zotero-pdf-translate
—THE END—
往期精彩回顾 适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载中国大学慕课《机器学习》(黄海广主讲)机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑机器学习交流qq群955171419,加入微信群请扫码
升级框架版本后spring-data-elasticsearch repository操作报错
java.lang.NoSuchFieldError: INDEX_CONTENT_TYPE at org.springframework.data.elasticsearch.core.RequestFactory.indexRequest(RequestFactory.java:623) at org.springframework.data.elasticsearch.core.RequestFactory.lambda$bulkRequest$1(RequestFactory.java:248) at java.util.ArrayList.forEach(ArrayList.java:1257) at org.springframework.data.elasticsearch.core.RequestFactory.bulkRequest(RequestFactory.java:245) 原因是springboot版本和spring-data-elasticsearch版本不对应
springboot:2.6.7
spring-data-elasticsearch:4.4.0
解决: 将spring-data-elasticsearch版本降低到4.3.4就好了
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-elasticsearch</artifactId> <version>4.3.4</version> </dependency> import com.lyh.api.entity.article.Hotel; import org.springframework.data.repository.PagingAndSortingRepository; public interface HotelRepository extends PagingAndSortingRepository<Hotel, Integer> { } @Autowired HotelRepository repository; @Test public void test5 (){ List<Hotel> hotels = hotelService.getAllList(); for (Hotel h:hotels ) { h.setSsuggest(new Completion(Arrays.asList(h.getBrand(),h.getBusiness()).toArray(new String[Arrays.asList(h.getBrand(),h.getBusiness()).size()]))); } repository.saveAll(hotels); } 怎么荔枝
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 前言一、petalinux官方提示二、使用步骤1.Makefile2.myapp.bb 总结 前言 petalinux工具自动生成的程序文件一般都是一个单一的C文件,内容是printf 一句话:“helloworld!”对于不熟悉Vitis 集成开发Linux platform的初学者,(比如本人,配置之后生成的SD卡文件无法启动系统……), 在petalinux中直接开发成了一个备用选项。可是看了很多参考文章,都是语焉不详,遇到问题的人很多,解决问题的人很少,绝大部分嵌入式Linux 教程的应用程序例子竟然都是单文件版本的!或者直接不在petalinux 工程里编译的。
一、petalinux官方提示 petalinux 工程应用程序文件目录下readme文件末尾有一段:
To add extra source code files (for example, to split a large application into multiple source files), add the relevant .o files to the list in the local Makefile where indicated. 仅仅修改Makefile,是不够的,还需要修改 程序名.bb 里的 SRC_URI 变量。
二、使用步骤 1.Makefile 只需要添加 APP_OBJS += xxxx.o 即可。
代码如下(示例):
APP = ledgpio # Add any other object files to this list below APP_OBJS = ledgpio.
sns.heatmap(ax = ax, data = M, annot = A, fmt='') 添加变量fmt=' ',就可以在图上显示符号
默认变量fmt='.2g'只能显示数值
参考链接:seaborn热图批注值错误:'numpy.str_'类型的对象的未知格式代码“g” - 我爱学习网 (5axxw.com)
文内所使用的Dart版本为2.17.0
一、对比 extends 数量: 仅一个
对象: 任意类(class)
附注:
可覆写(建议使用@override注解)被继承对象所有的非静态(static)的属性或方法。对于用abstract修饰的属性或方法,若继承者不为抽象类则必需覆写。对于用final修饰的属性则为覆写其get方法。 with 数量: 多个(至少一个)
对象: 没有构造方法的任意类(class)或任意混入(mixin)
附注: (这里为表述简洁,使用了子类的说法代指了混入关系)
属性和方法的覆写规则同extends。可以直接使用mixin关键字修饰with对象(一定程度上可以把mixin看作是特殊的abstract class),此时可使用on关键字限定一个class或mixin对象,只有该被限定对象的子类可通过with使用该mixin修饰的对象(当on限定对象为mixin且其子类同时使用该被修饰对象时,在其子类的with子句中被限定对象要排在该被修饰对象之前)。对于各被混入对象的同名属性或方法,排列靠后的覆盖排列靠前的。 implements 数量: 多个(至少一个)
对象: 任意类(class)或任意混入(mixin)
附注:
被实现对象的所有非静态(static)属性和方法均被视为是抽象的(abstract),无论是否使用了abstract修饰。在上一条的前提下,属性和方法的覆写规则同extends。 附注 三者可以同时使用,顺序依次为extends、with、implements。extends和with同时使用时,对于同名属性和方法的覆盖顺序为:类中的覆写 > with > extends,对于super的指代:with > extends。对于implements,因其特性所以不讨论覆盖顺序(因为它相当于没有值或方法体,可以认为始终处于覆盖顺序的最底层)。仅with和implements可以同时使用同一个对象,其效果等价于只有修饰了abstract关键字的属性或方法是抽象的。 二、示例 extends // 压缩排版,下同 void main() { final b = B(); b.c(); // B-c b.f(); // B-f } abstract class A { var a = 0; final b = 1; void c() { print('A-c'); } abstract int d; abstract final int e; void f(); } class B extends A { @override void c() { print('B-c'); } @override int d = 0; @override int get e => 1; @override void f() { print('B-f'); } } with 基本使用:
vue3中使用element plus,想要覆盖组件的样式,想到了/deep/样式穿透,样式一直不生效,代码如下:
<style scoped lang="sass"> .main_wrapper padding: 0 53px position: relative top: -20px >>> .el-tabs__item height: 30px line-height: 30px color: #fff!important </style> 上边的写法不会报错,但是也不会生效。改用下面的方式:
<style scoped lang="sass"> .main_wrapper padding: 0 53px position: relative top: -20px /deep/ .el-tabs__item height: 30px line-height: 30px color: #fff!important </style> 好码,这样就报错了,如下:
SassError: expected selector
看来sass不支持这个选择器。
解决方法:
尝试用 ::v-deep 替换 /deep/ ,成功解决了问题。
<style scoped lang="sass"> .main_wrapper padding: 0 53px position: relative top: -20px ::v-deep .el-tabs__item height: 30px line-height: 30px color: #fff!
目录
前言(阿巴阿巴)
安装
调整窗口
导入环境
前言(阿巴阿巴) 前几天无意间看到了一个叫做panda3d的东西,觉得挺好玩,就翻教程,发现现在中文教程似乎没有那么全面成体系,大部分都是复制粘贴过来官网的实例然后就发布出去了,看得云里雾里的,所以我决定自己去摸索一下这个panda3d,学panda3d的小伙伴中间肯定遇到过很多坑,也有过很多不理解的地方,不过没关系,来瞅瞅我的这个panda3d教程,给你个比较全面的讲解。
我整了个QQ群,180962166,有不会的进来问就行(如果我会的话)
好了,正式开始。
安装 想要用这个panda3d呢可以通过官网sdk下载或者通过pip命令安装,官网地址Panda3D | Open Source Framework for 3D Rendering & Games
安装sdk就点击中间那个按钮就行,很简单对吧,不过我用的是另一种方式,pip安装
命令pip install Panda3D , pip install panda3d 这俩都行,都能安装下来。
然后新建一个文件夹起名叫ch1(名字无所谓),然后新建一个game.py(名字随便起)的文件
大概是这个样子 调整窗口 下面直接贴代码块,讲解的内容也在代码块里(贴代码块省事,省的编辑格式了)
#第一步导入,导入这个叫做ShowBase的类,它是一个panda3d的基础类,用来创建窗口的 from direct.showbase.ShowBase import ShowBase #然后定义一个Game类,继承上面导入的ShowBase类,然后就是Game类init,showBase类init,没啥好说的 class Game(ShowBase): def __init__(self): ShowBase.__init__(self) #实例化一下这个Game类 game = Game() #ShowBase类里有一个run方法,启动窗口用的,这里Game也继承了ShowBase,所以直接game.run() game.run() 运行之后发现出现了一个灰色窗口,窗口里没有任何东西(实际上,你根本没写东西,显示出其他东西的话才见鬼了)
好了,如果你运行出来上面窗口了,恭喜你,你的环境没有任何问题,可以继续往下进行了。
我觉得这个窗口有点小,我想调成我想要的
#第一步导入,导入这个叫做ShowBase的类,它是一个panda3d的基础类,用来创建窗口的 from direct.showbase.ShowBase import ShowBase ############################################################# 导入一个叫做WindowProperties的东西,它可以帮你解决窗口大小问题 from panda3d.core import WindowProperties ############################################################# #然后定义一个Game类,继承上面导入的ShowBase类,然后就是Game类init,showBase类init,没啥好说的 class Game(ShowBase): def __init__(self): ShowBase.
前言
面向注解开发可以极大的提高我们的工作效率,所以熟练的使用注解可以帮助我们解决很多问题
借由此篇记录一下我在项目中常用的到一些注解
---------------------------------------------------------------------------------------------------------------------------------
注:需要下载lombok插件
@Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法
@NoArgsConstructor:生产一个无参的构造方法
@Accessors(chain = true) :开启链式编程,可以通过对象连续的调用set()方法@ToString(callSuper = true):重写ToString方法
@TableName(value = “数据库表名称”):用来标识实体类名称和数据表的对应关系@ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改
value–字段说明
name–重写属性名字
dataType–重写属性类型
required–是否必填
example–举例说明
hidden–隐藏
JAVA注解 @Configuration 标识当前类是配置类
@ComponentScan 包扫描注解 扫描注解
@Bean 标识该方法的返回值交给Spring容器管理
@Scope 控制多例和单例
@Lazy 懒加载
@PostConstruct 初始化方法
@PreDestroy 销毁方法
@Component 将当前类未来的对象交给容器管理
@Autowired 按照类型进行注入
@Qualifier 按照名称进行注入
@Repository 标识持久层注解
@Service 标识Service层
@Controller 标识Controller层
@Value 为属性赋值 @Value("${key}")
@PropertySource 加载指定路径的配置文件properties
@Aspect 标识当前类是一个切面类
@Pointcut 用于定义切入点表达式 表达式写法4种
@EnableAspectJAutoProxy 让AOP的注解有效果
@Before AOP-前置通知
@AfterReturning AOP-后置通知
@AfterThrowing AOP-异常通知
MyBatis Plus 联合查询 mybatis-plus-join使用方法安装使用 核心类 MPJLambdaWrapper和MPJQueryWrapperMPJLambdaWrapper用法简单的三表查询分页查询 MPJQueryWrapper简单的3表查询分页查询还可以这么操作,但不建议 mybatis-plus-join gitee演示工程一对一,一对多 使用方法 安装 Maven
<dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join</artifactId> <version>1.2.4</version> </dependency> Gradle
implementation 'com.github.yulichang:mybatis-plus-join:1.2.4' 或者clone代码到本地执行 mvn install, 再引入以上依赖
注意: mybatis plus version >= 3.4.0
使用 mapper继承MPJBaseMapper (必选)service继承MPJBaseService (可选)serviceImpl继承MPJBaseServiceImpl (可选) 核心类 MPJLambdaWrapper和MPJQueryWrapper MPJLambdaWrapper用法 简单的三表查询 class test { @Resource private UserMapper userMapper; void testJoin() { List<UserDTO> list = userMapper.selectJoinList(UserDTO.class, new MPJLambdaWrapper<UserDO>() .selectAll(UserDO.class) .select(UserAddressDO::getTel) .selectAs(UserAddressDO::getAddress, UserDTO::getUserAddress) .select(AreaDO::getProvince, AreaDO::getCity) .leftJoin(UserAddressDO.class, UserAddressDO::getUserId, UserDO::getId) .leftJoin(AreaDO.class, AreaDO::getId, UserAddressDO::getAreaId) .eq(UserDO::getId, 1) .
文章目录 一、简介二、原理三、例题四、代码 一、简介 在密码学中,恺撒密码(英语:Caesar cipher),或称 恺撒加密、恺撒变换、变换加密 ,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是 3 3 3 的时候,所有的字母 A A A 将被替换成 D D D , B B B 变成 E E E ,以此类推。这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系。
恺撒密码通常被作为其他更复杂的加密方法中的一个步骤,例如维吉尼亚密码。恺撒密码还在现代的 ROT13 系统中被应用。但是和所有的利用字母表进行替换的加密技术一样,恺撒密码非常容易被破解,而且在实际应用中也无法保证通信安全。
二、原理 凯撒密码加密的时候会将 明文 中的每个字母在字母表中往后移动 一定的长度 ,如果往后移动的长度超过了字母表的长度,那么就用当前字母的位置数加上偏移的数量 对字母表的长度取余 这个余数就是该字母加密后在字母表中的位置
(下标从 0 0 0 开始计算)例如我们的明文字母在字母表中的下标是 4 4 4,凯撒加密需要移动 30 30 30 位,而总字母表的长度是 26 26 26 ,那么加密后的字母位置就是 ( 4 + 30 ) (4+30) % 26 = 8 (4+30) ,其实就是一个循环的效果
具体的例子,如果我们的偏移量是 3 3 3 :
数据库的安全性维护
数据库除了数据管理之外,安全管理也是很重要的部分,其中的用户权限管理可以有效保证数据的安全访问,防止数据被非必要用户泄露、修改或删除。因此,MySQL提供了用户管理来保证数据的安全性。
MySQL.安全管理通过创建用户、用户授权、用户登录3个步骤的用户管理来实现。MySQL安全系统非常灵活,可以通过命令或界面化登录,而用户权限也可以从数据库、表、列及其他数据库对象的不同授权来达到,既满足用户的需求,又限制用户不能超出访问、操作的权限。
添加数据库用户
1、MySQL的权限表
MySQL通过权限表来控制用户对数据库的访问,MySQL数据库在安装时会自动安装多个数据库。MySQL权限表存放在名称为MySQL的数据库中。常用的权限表有user、db、host、table_ priv、columns_priv和procs_priv。
(1) user权限表。user是MySQI.中最重要的一个权限表,user列主要分为4个部分:用户列、权限列、安全列和资源控制列。
1、用户列:用户登录时通过表中的Host、User和Password列判断连接的IP、用户名称和密码是否存在于表中来通过身份验证或拒绝连接。
2、权限列:user表中包含多个以“_priv”结尾的字段,这些字段决定了该用户的权限,既包括查询权限、插入权限、更新权限、删除权限等普通权限,也包括关闭服务器和加载用户等高级管理权限。
3、安全列:ssl(加密)、x509(标识用户)开头的字段,以及 plugin和authenticationstring 字段(验证用户身份、授权的插件)。
4、资源控制列:max(最大允许次数,0表示无限制)开头的字段。
max_questions:表示每小时允许执行查询数据库的次数。
max_updates:表示每小时允许执行更新数据库的次数。
max_connections:表示每小时允许执行连接数据库的次数。
max_user_conntions:表示单个用户同时连接数据库的次数。
(2) db、host权限表。db权限表存储用户在各个数据库上的操作权限,决定哪些用户可以从哪些主机访问哪些数据库。
host权限表是db权限表的扩展,配合db权限表对给定主机上数据库级操作权限做更细致的控制。host权限表很少使用,只有在db表的范围内扩展一个条目时才会用到。
(3) table_priv权限表。记录数据表级别的操作权限。table_priv权限表与db权限表相似,不同之处是它用于数据表而不是数据库。
(4) columns_priv权限表。记录数据字段级别的操作权限。columns_priv权限表的作用与table_priv权限表类似,不同之处是它针对某些表的特定字段的权限。
(5) procs_priv权限表。该权限表存储用户在存储过程和函数上的操作权限。
2.添加用户
新安装的MySQL中只有一个名称为root的用户。这个用户是安装服务器时由系统创建并赋予了MySQL的所有权限。在对MySQL的实际操作中,通常需要创建不同层次要求的用户来确保数据的安全访问。添加用户可以通过CREATE USER.INSERT和GRANT语句来实现。
(1)CREATE USER语句的语法格式为:
CREATE USER<用户名>@<主机>[IDENTIFIED BY [PASSWORD][<'密码>]];
说明:
1、使用CREATE USER语句可以创建一个或多个用户,用户之间用逗号分隔。
2、“主机”可以是主机名或IP地址,本地主机名可以使用localhost,“%”表示一组主机。
3、“IDENTIFIED BY”关键字用于设置用户的密码,若指定用户登录不需要密码,则可以省略该选项。
4、 “PASSWORD”关键字指定使用哈希值设置密码。密码的哈希值可以使用PASSWORD()函数获取。
(2)INSERT语句的语法格式为:
INSERT INTO mysql.user(User, Host,Password)
Values(<'用户名>,<主机>,PASSWORD(<密码>));
说明:通常语句只能添加Host、 User、 Password字段的值,分别表示user数据表中的主机名字段、用户名字段和密码字段。
授予用户权限
GRANT语句不仅是授权语句,还可以达到添加新用户或修改用户密码的作用。GRANT语句的语法格式为:
GRANT<权限名称[(字段列表)]ON<对象名>TO<用户名>@<”主机[IDENTIFIED BY [PASSWORD]<新密码>] [WITH GRANT OPTION];
说明:
1“权限名称”中常用的权限如下。
ALL[PRIVILEGES]:除GRANT OPTION之外的所有简单权限。
CREATE:允许创建数据表。
ALTER:允许修改数据表。
DROP:允许删除数据表。
创建与使用触发器
1、触发器概述
触发器是特殊的存储过程,是一个被指定关联到数据表上的数据库对象,可以看作数据表定义的一部分,可用于实现数据库中数据的完整性。普通的存储过程通过Call命令调用,而触发器的调用不同,只能由数据库的特定事件来触发,且不能接收参数,它在插入、删除或修改指定数据表中数据时触发执行,从而实现数据的自动维护。
触发器有以下3个作用。
(1)安全性。可以使用户具有操作数据库的特定权利。例如,在“销售表”中插入一条销售记录,可以通过触发器实现对“商品一览表”中库存的更新,而不用直接将“商品一览表”展现在特定用户面前。
(2)实现复杂的数据完整性。实现数据完整性约束或规则,触发器可实现比约束更复杂的限制。
(3)实现复杂的非标准数据相关完整性。触发器可以对数据库中相关的表进行级联更新。例如,在“销售表”中插入一条销售记录,可以通过触发器实现对“商品一览表”中库存的级联更新。
2、创建触发器
创建触发器使用CREATE TRIGGER语句,其语法格式为:
CREATE TRIGGER触发器名 触发时刻 触发事件ON 表名
FOR EACH ROW
触发器动作;
说明:
1、触发器名。触发器名在当前数据库中必须具有唯一性,如果是在某个特定数据库中创建,在触发器名前加上数据库的名称。
2、触发时刻。触发时刻有两个选择:BEFORE或AFTER,以表示触发器在激活它的语句之前触发或之后触发。
3、触发事件。触发事件是指激活触发器执行的语句类型,可以是INSERT(插入记录时激活触发器)、DELETE(删除记录时激活触发器)、UPDATE(更新记录时激活触发器)。
4、表名。与触发器相关的数据表名称,在该数据表上发生触发事件时激活触发器。
5、FOR EACH ROW。行级触发器,指受触发事件每影响一行都会执行一次触发程序。
6、触发器动作。触发器激活时将要执行的语句,如果要执行多条语句可使用BEGIN·END复合语句。
触发器动作中可以使用NEW与OLD关键字:当插入记录时,在触发动作中可以使用NEW关键字表示新记录,当需要访问新记录的某个字段值时,可以使用“NEW.字段名”的方式访问;当删除记录时,在触发动作中可以使用OLD关键字表示旧记录,当需要访问旧记录的某个字段值时,可以使用“OLD.字段名”的方式访问;当更新某条记录时,在触发程序中可以使用OLD关键字表示更新前的旧记录,使用NEW关键字表示更新后的新记录。
注意,在MySQL触发器中不能直接在客户端界面返回结果,所以在触发器动作中不要使用SELECT语句,也不能在一个表上同时创建两个相同类型的触发器。因此,在一个表上最多创建6个触发器。
1、创建触发器:
Create trigger 触发器名 触发时刻 触发事件 on 表名 for each row 动作;
触发时刻:有两种,分别是 before 和after
Before:在事件之前;
After:在事件之后;
触发事件:insert(新增)、update(更新)、delete(删除);
Now():获取当前时间;
2、删除触发器:
Drop trigger 触发器名;
3、查看触发器:
Show triggers;
创建与使用存储过程
SQL.语句没有流程控制,无法实现复杂的应用,PL/SQL语言(Procedural Lan.guage/SQL)是将结构化查询与数据库过程控制结合为一体的强大语言,PL/SQL不但支持更多的数据类型,拥有变量声明、赋值语句,而且有选择、循环等流程控制语句。
系统开发过程中,经常会有同一个功能模块多次调用的情况,如果每次都编写代码会浪费大量的时间,为了解决这类问题,MySQL5.0开始引入存储过程。存储过程是一组为了完成特定功能的PL/SQL语句集,经编译后存储在数据库中,用户可以重复使用该存储过程,这样可以降低数据库开发人员的工作量。
游标是处理数据的一种方法,为了查看或处理结果集中的数据,游标提供了在结果集中一次一行浏览数据的能力。
事务是一个操作序列,这些操作要么都执行,要么都不执行,是一个不可分割的工作单元。
【任务6.1】 创建简单存储过程
1.PL/SQL的变量
变量。变量是指在程序运行过程中其值可以改变的量,包括用户变量、系统变量和局部变量。
1、用户变量。用户可以在PL/SQL中使用自己定义的变量,这样的变量称为用户变量。可以先在用户变量中保存一个数据,然后在以后的语句中引用该变量,这样就可以将数据从一条语句传递到另一条语句。用户变量在使用前必须定义和初始化,如果使用没有初始化的变量,其值为NULL。
2、系统变量。MySQL可以访问许多系统变量和连接变量,当服务器运行时许多变量可以动态更改。这样通常允许修改服务器操作而不需要停止并重启服务器。服务器维护两种变量,全局变量影响服务器整体操作,会话变量影响具体客户端连接的操作。
系统变量一般都以“@@”为前缀,如@@Version返回MySQL的版本。但某些特定的系统变量可以省略“@@”符号,如Current _Date、 Current _Time 和Current_User。
3、局部变量。在语句块(BEGIN到End之间)中定义的变量为局部变量,局部变量可以保存特定类型数据,其有效作用范围在存储过程和自定义函数的语句块中,在语句块结束以后,局部变量就失效了。
MySQL的局部变量必须先声明后使用。使用DECLARE语句声明局部变量,其声明语法格式为:
DECLARE<变量名称> 数据类型>[DEFAULT<默认值>];
说明:
1“DEFAULT”子句为变量指定默认值,若不指定则默认为NULL。2变量名称必须符合MySQL标识符的命名规则,在局部变量前面不使用“@”符号。 2.PL/SQL的运算符及表达式
1、运算符。运算符用于执行程序代码运算,会针对一个以上操作数项目进行运算。MySQL中的运算符主要有以下类型。
(1)算术运算符。算术运算符用于对表达式执行数学运算,操作数可以是任何数值
类型。 MySQL中的算术运算符有+(加)、一(减)、*(乘)、/(除)、%(取模)。
(2)赋值运算符。“=”是MySQL中的赋值运算符,可以将表达式的值赋给一个变量。
(3)比较运算符。比较运算符用于对两个表达式进行比较,数字以浮点值进行比较,字符串以不区分大小写的方式进行比较,若表达式成立则返回1,否则返回0。
MySQL中的比较运算符有=(等于)、>(大于)、<(小于)、>=(大于等于)、 (小于等于)、 (不等于)、!=(不等于)、<=>(相等或都等于空)。
(4)逻辑运算符。逻辑运算符用于对某些条件进行测试,以返回其真假。
MySQL中的逻辑运算符有And(与)、Or(或)、Not(非)。
(5)位运算符。位运算符用于对两个表达式执行二进制位操作。
MySQL中的位运算符有8.(位与)、(位或)、·(位异或)、~(位取反),>(位右移)、< (位左移)。
(6)一元运算符。一元运算符对一个操作数执行运算,该操作数可以是任何一种数据类型。
MySQL中的一元运算符有+(正)、一(负)和~(位取反)。
2、表达式。表达式是由操作数、运算符、分组符号(括号)和函数构成的组合,MySQL可以对表达式进行运算以获取结果,一个表达式通常可以得到一个值。
表达式的值同样具有字符类型、数值类型、日期时间类型等,根据表达式的值类型可分为字符型表达式、数值表达式和日期表达式。
3、运算符的优先级。当一个复杂的表达式有多个运算符时,运算符优先级决定执行运算的先后次序。执行的次序有时会影响所得到的运算结果。MySQL运算符优先级如表6-1所示,当一个表达式中的两个运算符有相同的优先级时,根据它们在表达式中的位置,一般而言,一元运算符按从右到左(即右结合性)的顺序运算,二元运算符按从左到右(即左结合性)的顺序运算。
MySQL的存储过程
1、存储过程是一组为了完成特定功能的SQL语句块,经编译后存储在数据库中,用户通过指定存储过程的名称并给定参数(如果该存储过程带有参数)来调用并执行它,存储过程能重复使用,这样可以大大减少数据库开发人员的工作量。
存储过程主要有以下优点。
(1)执行效率高:存储过程编译后存储在数据库服务器端,可以直接调用从而提高了SQL语句的执行效率。
(2)灵活:存储过程可以用结构化语句编写,可以完成较复杂的判断和运算。
(3)数据独立:用户在程序中调用存储过程,存储过程能把数据同用户程序隔离开,其优点是当数据表结构变化时,可以随时修改存储过程,不用修改程序源代码。
(4)安全:存储过程可被作为一种安全机制来充分利用,系统管理员通过设置存储过程的访问权限,从而实现相应数据的访问权限限制,避免了用户对数据表的直接访问,保证了数据的安全。
(5)降低网络流量:当在客户机上调用该存储过程时,网络中传送的只是该调用语句,而不是这一功能的全部代码,从而大大降低了网络负载。
2、DELIMITER命令。DELIMITER命令用于更改MySQL语句的结束符,如将默认结束符“;”更改为“$$”,避免与SQL语句默认结束符相冲突,其语法格式为:
DELIMITER<自定义结束符>
创建与使用事务
开始事务:
Start transaction;
提交事务:
Commit;
取消事务:
Rollbock;
设置事务级别
设置事务隔离级别:
set session transaction isolation level 隔离级别;
根据客户反馈,安装App时会出现安装失败的问题,如下图:
安装失败就算了,还被怀疑我亲自动手打包的App不是正版,这不能忍,这个问题我一定要处理掉。
可后来发现我错了,这让人不能忍的问题居然无法复现!!!
这怎么搞?同样是华为手机,为什么客户的手机如此优秀?
实在没办法了,不得已的去百度搜搜,虚心向广大网友讨要处理问题的方法
根据网友提供的信息,问题是出在了安装包打包的时候没有勾选上 V1(Jar Signature)与 V2(Full APK Signature)这两个选项或者少勾选了其中一个
或者可以将其配置写入build.gradle里
android{ signingConfigs { release { v1SigningEnabled true //打包时默认勾选 V1(Jar Signature) v2SigningEnabled true //打包时默认勾选 V2(Full APK Signature) } } } 勾选之后再次打包即可了
问题解决了,那么,V1(Jar Signature)与V2(Full APK Signature)到底是什么呢?勾选与不勾选又有何差别?
V1(Jar Signature):
验证未解压的文件内容,APK 签署后可进行许多修改 ,可以移动甚至重新压缩文件。
V2(Full APK Signature):
验证压缩文件的所有字节,而不是单个 ZIP 条目,在签名后无法再更改(包括 zipalign),压缩、调整和签署合并成一步完成。V2(Full APK Signature)更安全而且新的签名可缩短在设备上进行验证的时间(不需要费时地解压缩然后验证),从而加快应用安装速度。如有任何自定义任务篡改 APK 文件或对其进行后处理(无论以任何方式)
需要注意:
V2(Full APK Signature)是Android 7.0后才有的,为了更好的兼容,打包时还是把两个对选上较好,这样还能一定程度上避免一定的问题。
更改·后的代码 <view :style="{height:statusBarHeight+'px'}" class="status"></view> 第一种:onLoad(){ this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight console.log(this.statusBarHeight,'-') // this.statusBarHeight = wx.getSystemInfoSync()['statusBarHeight'] }, 第二种:onLoad(){ uni.getSystemInfo({ success:(e)=> { console.log(e.statusBarHeight;) this.statusBarHeight = e.statusBarHeight; } }) console.log(this.statusBarHeight,'-') }, //css .status{ width: 100%; background-color: red; }
错误代码: CommandInvokationFailure: Gradle build failed. C:\Program Files\Java\jdk1.8.0_311\bin\java.exe -classpath "D:\Program Files\Unity20200326\Unity 2020.3.26f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease" stderr[ Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8 FAILURE: Build failed with an exception. * Where: Build file 'F:\unity_programme526\VRTuoluo0519\【00】Programme_document\finaldesign01\Temp\gradleOut\launcher\build.gradle' line: 3 * What went wrong: A problem occurred evaluating project ':launcher'. > Failed to apply plugin [id 'com.android.internal.application'] > Your project path contains non-ASCII characters. This will most likely cause the build to fail on Windows. Please move your project to a different directory.
该论文发表在2018年CVPR上,用于多人姿态估计的级联金字塔网络
arxiv论文地址:https://arxiv.org/abs/1711.07319
github代码:https://github.com/GengDavid/pytorch-cpn,https://github.com/chenyilun95/tf-cpn
文档编辑参考:
1、论文笔记(CPN):Cascaded Pyramid Network for Multi-Person Pose Estimation
2、2018-CPN:Cascaded Pyramid Network for Multi-Person Pose Estimation - 知乎
一、背景 目前多人姿态估计中仍然存在的问题(hard” keypoints)(遮挡点,不可见点和拥挤的背景,是的人体关键点检测存在的问题),其原因归纳为两点:
1)只通过表层特征不能识别这些“难点”,例如:躯干点;
2)在训练过程中没有明确解决这些“难点”的检测问题;
因此,作者提出了一种新的网络结构,称为Cascaded Pyramid Network(CPN)级联金字塔网络,该网络可以有效缓解“hard” keypoints的检测问题,CPN网络分为两个阶段:GlobalNet和RefineNet。GlobalNet网络是一个特征金字塔网络,该网络用于定位简单的关键点,如眼睛和手等,但是对于遮挡点和不可见的点可能缺乏精确的定位;RefinNet网络该网络通过集合来自GolbalNet网络的多级别特征来明确解决“难点”的检测问题。
三大创新点:
提出了一个新的有效的网络:CPN,该网络由GlobalNet和RefineNet网络构成; 分析了在top-down结构中问题对于多人姿态估计产生影响的不同因素; 算法实现了在challenging COCO multi-persion keypoint benchmark数据集上的最好的结果,在test-dev dataset上达到73.0AP,在test challenge dataset 上达到72.1AP。 采用了top-down的路线:先在image上使用一个human detector得到人的bounding-boxes,然后再使用cpn网络进行关键点的检测;重点在cpn网络实现的关键点检测。
二、 Human Detector 类似于 Mask R-CNN,CPN pipeline 也是自顶而下的:首先通过人体检测器根据图像生成一个边界框集合bounding-boxes;然后使用bounding-boxes对原图进行裁剪,并将裁剪后的结果用于CPN网络,接着通过单人关键点估计器预测每个人关键点的详细定位。采用基于 FPN 的当前最优物体检测器作为人体检测器,并用 Mask R-CNN ROIAlign 替代 FPN ROIPooling。
2.1 FPN 目标检测算法FPN(Feature Pyramid Networks)简介
FPN使用不同分辨率的特征图感知不同大小的物体,并通过连续上采样和跨层融合机制使输出特征兼具底层视觉信息和高层语义信息。低层次的特征图语义不够丰富,不能直接用于分类,而深层的特征更值得信赖。将侧向连接与自上而下的连接组合起来,就可以得到不同分辨率的特征图,而它们都包含了原来最深层特征图的语义信息。
2.2 Mask R-CNN 回顾 R-CNN
基于STM32F103系列芯片keil工程的创建 第一步开始前的准备第二步基础项目的配置创建工程文件配置工程文件的移植移植完成的目录文件 工程项目文件的添加项目工程的配置补齐main.c文件测试编译 第一步开始前的准备 keil芯片包
芯片包下载地址
STM32官方库文件
库文件下载地址
第二步基础项目的配置 创建工程文件 在这里随便找个空的文件夹将项目创建至文件夹里
在这里还是以这款芯片为例,点击确定创建工程
弹出的对话框点击取消即可
在这里基础的项目工程就已经创建完成了
配置工程 在这里是重点
点击OK即可
文件的移植 首先找到我们创建项目的文件夹
建新三个文件夹在这里只做文件分类作用
main.c目前为空文件
在这里还有一个.h文件需要从官方的项目例程里找
文件复制到CMSIS文件夹里
截止到这里文件的移植就初步完成
移植完成的目录文件 工程项目文件的添加 在这里第一个文件就添加完成了,其他目录的文件夹里文件的添加这里就不再赘述
在这里需要Ctrl+A全选添加
项目工程的配置 添加项目目录文件
STM32F10X_HD,USE_STDPERIPH_DRIVER
补齐main.c文件 测试编译 零错误,零警告,基础项目创建完成🎉
一、设置VMware 打开 VMware Workstation Pro 里的 虚拟机 -> 设置
将网络适配器设置为桥接模式
将网络适配器设置为桥接模式后,会导致虚拟机无法上网,因此还需要建立一个新的网络适配器。并设置为NAT模式供虚拟机上网。
打开菜单栏的 编辑 -> 虚拟网络编辑器
点击虚拟网络编辑器的更改设置选项。
可以看到如下界面
如果没有VMnet0,则需要手动添加
开发板是直连到电脑的网口的,所以需要虚拟网络编辑器里的网络适配器 1(即 VMnet0)
桥接到有线网卡上。
设置完成后点击确定,再点击应用即可。
二、Ubuntu设置 在网络设置中有两个有线网络,其中一个还没有设置 IP 的,是我们的网络适配器 1,用来
桥接到开发板和 Windows 的,如下图所示ens33就是用来和开发板直接链接的网卡。ens38就是用来虚拟机上网的网卡。
这是我们用来桥接的网络适配器,不会自动分配IP,需要手动设置。这里要注意, VMnet0设置的网段不能和VMnet1、VMnet8 的网段一样,不然会有冲突。
将 IP 手动设置为192.168.10.100,子网掩码 255.255.255.0,网关 192.168.10.1。
三、 Windows设置 在 Windows 主机打开控制面板 -> 网络和 Internet -> 网络连接,找到以太网
选择以太网,右键打开菜单栏,选择属性。 在打开的网络设置中, 双击 Internet 协议版本 4
(TCP/IPv4),如下图所示
按照下图设置以太网的 IP 为 192.168.10.99,要和虚拟机的 VMnet0 在同一网段
四、U-boot设置 在u-boot中进行如下设置
setenv ipaddr 192.168.10.101 setenv ethaddr 00:04:9f:04:d2:35 setenv gatewayip 192.
简介 GORM查询官方文档
前置代码 package main import ( "database/sql" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "log" "os" "time" ) type User struct { ID uint Name string Email *string Age uint8 Birthday *time.Time MemberNumber sql.NullString ActivatedAt sql.NullTime CreatedAt time.Time UpdatedAt time.Time } func main() { // 连接对应的数据库 dsn := "root:root@tcp(192.168.193.128:3306)/grom_test?charset=utf8mb4&parseTime=True&loc=Local" newLogger := logger.New( log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注) logger.Config{ SlowThreshold: time.Second, // 慢 SQL 阈值 LogLevel: logger.Info, // 日志级别 IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误 Colorful: true, // 使用用彩色打印 }, ) db, err := gorm.
执行repo sync 指令时,出现的如图所示的报错:
解决方法:删除.repo/projects目录下所有的*.git文件,重新repo sync,同步成功,问题解决。
ACL 概述 ACL是由一系列permit或deny语句组成的、有序规则的列表。
ACL是一个匹配工具,能够对报文进行匹配和区分。
通过ACL可以实现对网络中报文流的精确识别和控制,达到控制网络访问行为、防止网络攻击和提高网络带宽利用率的目的,从而切实保障网络环境的安全性和网络服务质量的可靠性。
ACL是由permit或deny语句组成的一系列有顺序的规则的集合;它通过匹配报文的相关字段实现对报文的分类。
ACL是能够匹配一个IP数据包中的源IP地址、目的IP地址、协议类型、源目的端口等元素的基础性工具;ACL还能够用于匹配路由条目。
ACL的基本概念及其工作原理 ACL的组成 ACL由若干条permit或deny语句组成。每条语句就是该ACL的一条规则,每条语句中的permit或deny就是与这条规则相对应的处理动作。
规则编号 规则编号与步长 规则编号(Rule ID):
一个ACL中的每一条规则都有一个相应的编号。
步长(Step):
步长是系统自动为ACL规则分配编号时,每个相邻规则编号之间的差值,缺省值为5。步长的作用是为了方便后续在旧规则之间,插入新的规则。
Rule ID分配规则:
系统为ACL中首条未手工指定编号的规则分配编号时,使用步长值(例如步长=5,首条规则编号为5)作为该规则的起始编号;为后续规则分配编号时,则使用大于当前ACL内最大规则编号且是步长整数倍的最小整数作为规则编号。
通配符 通配符是一个32比特长度的数值,用于指示IP地址中,哪些比特位需要严格匹配,哪些比特位无需匹配。
通配符通常采用类似网络掩码的点分十进制形式表示,但是含义却与网络掩码完全不同。
当进行IP地址匹配的时候,后面会跟着32位掩码位,这32位称为通配符。
通配符,也是点分十进制格式,换算成二进制后,“0”表示“匹配”,“1”表示“不关心”。
具体看下这2条规则:
rule 5: 拒绝源IP地址为10.1.1.1报文通过——因为通配符为全0,所以每一位都要严格匹配,因此匹配的是主机IP地址10.1.1.1;
rule 15:允许源IP地址为10.1.1.0/24网段地址的报文通过——因为通配符:0.0.0.11111111,后8位为1,表示不关心,因此10.1.1.xxxxxxxx 的后8位可以为任意值,所以匹配的是10.1.1.0/24网段。
例子:如果要精确匹配192.168.1.1/24这个IP地址对应的网段地址,通配符是多少?
可以得出:网络位需要严格匹配,主机位无所谓,因此通配符为“0.0.0.255”。
匹配奇数IP地址 匹配192.168.1.0/24这个子网中的奇数IP地址,例如192.168.1.1、192.168.1.3、192.168.1.5等。
如果想匹配192.168.1.0/24网段中的奇数IP地址,通配符该怎么写呢?
我们先来看一看,奇数IP地址都有哪些:192.168.1.1、192.168.1.5、192.168.1.11……
后八位写成二进制:192.168.1.00000001、192.168.1.00000101、192.168.1.00001011……
可以看出共同点:最后8位的高7位是任意值,最低位固定为1,因此答案是:192.168.1.1 0.0.0.254(0.0.0.11111110)
这就得出了通配符的一个特点:通配符中的1或者0是可以不连续的。
还有两个特殊的通配符:
当通配符全为0来匹配IP地址时,表示精确匹配某个IP地址;
当通配符全为1来匹配0.0.0.0地址时,表示匹配了所有IP地址。
ACL的分类与标识 基于ACL规则定义方式的分类 基于ACL标识方法的分类 注意:用户在创建ACL时可以为其指定编号,不同的编号对应不同类型的ACL。同时,为了便于记忆和识别,用户还可以创建命名型ACL,即在创建ACL时为其设置名称。命名型ACL,也可以是“名称 数字”的形式,即在定义命名型ACL时,同时指定ACL编号。如果不指定编号,系统则会自动为其分配一个数字型ACL的编号。
基本ACL&高级ACL 基本ACL 主要针对IP报文的源IP地址进行匹配,基本ACL的编号范围是2000-2999。
比如这个例子,创建的是acl 2000,就意味着创建的是基本ACL。
高级ACL 可以根据IP报文中的源IP地址、目的IP地址、协议类型,TCP或UDP的源目端口号等元素进行匹配,可以理解为:基本ACL是高级ACL的一个子集,高级ACL可以比基本ACL定义出更精确、更复杂、更灵活的规则。
ACL的匹配机制 ACL的匹配机制概括来说就是:
配置ACL的设备接收报文后,会将该报文与ACL中的规则逐条进行匹配,如果不能匹配上,就会继续尝试去匹配下一条规则。
一旦匹配上,则设备会对该报文执行这条规则中定义的处理动作,并且不再继续尝试与后续规则匹配。
匹配流程:首先系统会查找设备上是否配置了ACL。
如果ACL不存在,则返回ACL匹配结果为:不匹配。
如果ACL存在,则查找设备是否配置了ACL规则。
如果规则不存在,则返回ACL匹配结果为:不匹配。
如果规则存在,则系统会从ACL中编号最小的规则开始查找。
如果匹配上了permit规则,则停止查找规则,并返回ACL匹配结果为:匹配(允许)。
如果匹配上了deny规则,则停止查找规则,并返回ACL匹配结果为:匹配(拒绝)。
如果未匹配上规则,则继续查找下一条规则,以此循环。如果一直查到最后一条规则,报文仍未匹配上,则返回ACL匹配结果为:不匹配。
CM3系列处理器优势:
功耗低。延长了电池的寿命——这简直就是便携式设备的命门(如无线网络应用)
实时性好。采用了很前卫甚至革命性的设计理念,使它能极速地响应中断,而且响应中断所需的周期数是确定的。
代码密度得到很大改善(应用thumb指令?)。一方面力挺大型应用程序,另一方面为低成本设计而省吃俭用。
降低成本还有一招,就是使基础代码在所有系统中都可以重用,至少要方便移植。CM3的内核架构非常精工细作,使它与C语言成为了一个梦幻绝配。优质的C程序代码三下五除二就可以移植并重用,使升级和移植一下子从拦路虎变成了纸老虎。
,CM3还突破性地引入了很多时尚的甚至崭新的技术,专门满足单片机应用程序的需求。比如,服务于“使命-关键”应用的不可屏蔽中断,极度敏捷并且拥有确定性的嵌套向量中断系统.
P15和P16有关于cortex-m和cortex-a其他系列的比较,讲的比较好。
还有关键的対实时系统的定义:
通用处理器能否胜任实时系统的控制,常遭受质疑,并且在这方面的争论从没停止过。从定义的角度讲,“实时”就是指系统必须在给定的死线(deadline,亦称作“最后期限”)内做出响应。在一个以ARM处理器为核心的系统中,决定能否达到“实时”这个目标的,有很多因素,包括是否使用“实时操作系统”,中断延迟,存储器延时,以及当时处理器是否在运行更高优先级的中断服务例程。
MMU,存储器管理单元,用于实现虚拟内存和内存的分区保护,这是应用处理器与嵌入式处理器的分水岭。电脑和数码产品所使用的处理器几乎清一色地都带MMU。但是MMU也引入了不确定性,这有时是嵌入式领域——尤其是实时系统不可接受的。然而对于安全关键(safety-critical)的嵌入式系统,还是不能没有内存的分区保护的。为解决矛盾,于是就有了MPU。可以把MPU认为是MMU的功能子集,它只支持分区保护,不支持具有“定位决定性”的虚拟内存机制。
1.5 Cortex-M3处理器的舞台也比较有意思
当呼叫一个子程序时,由R14存储返回地址
不像大多数其它处理器,ARM为了减少访问内存的次数(访问内存的操作往往要3个以上指令周期,带MMU和cache的就更加不确定了),把返回地址直接存储在寄存器中。这样足以使很多只有1级子程序调用的代码无需访问内存(堆栈内存),从而提高了子程序调用的效率。如果多于1级,则需要把前一级的R14值压到堆栈里。在ARM上编程时,应尽量只使用寄存器保存中间结果,迫不得以时才访问内存。
中断可屏蔽
既可以屏蔽优先级低于某个阈值的中断/异常[译注8](设置BASEPRI寄存器),也可以全体封杀(设置PRIMASK和FAULTMASK寄存器)。这是为了让时间关键(time-critical)的任务能在死线Cortex-M3权威指南 第 2 章 27
(deadline,或曰最后期限)到来前完成,而不被干扰。
Cortex-M3只使用Thumb-2指令集。这是个了不起的突破,因为它允许32位指令和16位指令水乳交融,代码密度与处理性能两手抓,两手都硬。而且虽然它很强大,却依然易于使用。
在过去,做ARM开发必须处理好两个状态。这两个状态是井水不犯河水的,它们是:32位的ARM状态和16位的Thumb状态。当处理器在ARM状态下时,所有的指令均是32位的(哪怕只是个”NOP”指令),此时性能相当高。而在Thumb状态下,所有的指令均是16位的,代码密度提高了一倍。不过,thumb状态下的指令功能只是ARM下的一个子集,结果可能需要更多条的指令去完成相同的工作,导致处理性能下降。
事实上,Cortex-M3内核干脆都不支持ARM指令,中断也在Thumb态下处理(以前的ARM总是在ARM状态下处理所有的中断和异常)。这可不是小便宜,它使CM3在好几个方面都比传统的ARM处理器更先进
因为CM3专情于最新的Thumb-2,旧的应用程序需要移植和重建。对于大多数C源程序,只需简单地重新编译就能重建,汇编代码则可能需要大面积地修改和重写,才能使用CM3的新功能,并且融入CM3新引入的统一汇编器框架(unified assembler framework)中。
Cortex-M3的设计允许单片机高频运行(现代半导体制造技术能保证100MHz以上的速度)。即使在相同的速度下运行,CM3的每指令周期数(CPI)也更低,于是同样的MHz下可以做更多的工作;另一方面,也使同一个应用在CM3上需要更低的主频。P32
这句话是不是说芯片刚启动是4MHZ,然后经过PLL倍频变为60M或者144MHZ?
先进的中断处理功能
内建的嵌套向量中断控制器支持多达240条外部中断输入。向量化的中断功能剧烈地缩短了中断延迟,因为不再需要软件去判断中断源。中断的嵌套也是在硬件水平上实现的,不需要软件代码来实现。怎么去体现粗体字,是不是指下面的东西
Cortex-M3在进入异常服务例程时,自动压栈了R0-R3, R12, LR, PSR和PC,并且在返回时自动弹出它们,这多清爽!既加速了中断的响应,也再不需要汇编语言代码了(第8章有详述)。
优化中断响应还有两招,它们分别是“咬尾中断机制”和“晚到中断机制”。
有些需要较多周期才能执行完的指令,是可以被中断-继续的——就好比它们是一串指令一样。这些指令包括加载多个寄存器(LDM),存储多个寄存器(STM),多个寄存器参与的PUSH,以及多个寄存器参与的POP。 这些不懂???
尽管PC的LSB总是0(因为代码至少是字对齐的),LR的LSB却是可读可写的。这是历史遗留的产物。在以前,由位0来指示ARM/Thumb状态。因为其它有些ARM处理器支持ARM和Thumb状态并存,为了方便汇编程序移植,CM3需要允许LSB可读可写。P38
上面这段是不是就解释了同页的
寄存器的PUSH和POP操作永远都是4字节对齐的——也就是说他们的地址必须是0x4,0x8,0xc,……。事实上,R13的最低两位被硬线连接到0,并且总是读出0(Read As Zero)。
如果向PC中写数据,就会引起一次程序的分支(但是不更新LR寄存器)。CM3中的指令至少是半字对齐的,所以PC的LSB总是读回0。然而,在分支时,无论是直接写PC的值还是使用分支指令,都必须保证加载到PC的数值是奇数(即LSB=1),用以表明这是在Thumb状态下执行。倘若写了0,则视为企图转入ARM模式,CM3将产生一个fault异常。
这句话又对上面的做了补充说明,粗体部分的原因是因为CM3还支持16位的指令
3.2.3 控制寄存器(CONTROL)的介绍
Ut-kernel里面只用了特权级和两种类型的堆栈,ut-kernel这方面设计得过于简单,使用户在编写应用程序时,竟然也可以访问特殊功能寄存器。给用户权限太大了。
代码依据:
Icrt0.s:
;;----------------------------------------------------------------------
;MSP setting
;;----------------------------------------------------------------------
mov r0, #0 ;MSP Effective ( privileged mode )
msr control, r0
isb ;It is necessary after control register is operated.
1.操作系统
centos7.3.1611
2.问题描述
2.1 服务器开机后进入如下画面
2.1.1 解决方法
输入密码进入紧急模式
输入journalctl -xb 查看日志,接着输入/mount搜索挂载相关日志,发现有一个挂载失败,如下图
编辑/etc/fstab文件,把挂载失败的行注释或删掉
注释或删除下图箭头所指的行
2.2 系统引导后一直停留在7字形状的图形界面(非登录系统的那个图形界面)
2.2.1 解决方法
重启系统,进入单用户模式,设置以字符界面登录系统 启动时任意键暂停启动 按e键进入编辑模式 将光标移动linux16开始的行,行尾添加 rw init=/sysroot/bin/sh 按ctrl-x启动 chroot /sysroot systemctl set-default multi-user.target touch /.autorelabel exit reboot 2.3 开机途中提示文件损坏
2.3.1 解决方法
xfs_repair /dev/sda5 -L reboot 2.4 显示器黑屏,重启报如下错误:
DIMM Error: System Halt.Please Check CHH_0 ! 内存错误 2.4.1解决方法
1.插拔内存条 2.更换内存条 </article>
2022.05.26更新
增加SMU激活函数 前言 激活函数是一种添加到人工神经网络中的函数,类似于人类大脑中基于神经元的模型,激活函数最终决定了要发射给下一个神经元的内容。
此图来自百度百科,其中step function就是激活函数,它是对之前一层进行汇总后信号进行激活,传给下一层神经元。
常用的激活函数有以下10个:
常用的10个激活函数 SigmoidTanhReLUSoftmaxLeaky ReLUELUPReLUSwishSquareplusSMU 1. Sigmoid 如上图是Sigmoid函数的函数图像。
Sigmoid 函数的图像看起来像一个 S 形曲线。
公式:
f ( x ) = 1 1 + e − x f(x)=\frac 1{1+e^{-x}} f(x)=1+e−x1
特点:
Sigmoid 函数的输出范围是 0 到 1。由于输出值在 0 到 1,所以它可以对每个神经元的输出进行了归一化。因为Sigmoid 函数的输出范围是 0 到 1,所以可以用于将预测概率作为输出的模型。梯度平滑,避免跳跃的输出值。容易梯度消失。函数输出不是以 0 为中心的,这会降低权重更新的效率。Sigmoid 函数是指数运算,计算机运行得较慢。 代码演示:
import matplotlib.pyplot as plt import numpy as np def sigmoid(x): return 1 / (1 + np.exp(-x)) fig, ax = plt.subplots() x = np.
一、Fastlane 安装 1)安装 Xcode command line tools:
打开终端输入命令
xcode-select --install
2)安装Fastlane
输入命令
sudo gem install fastlane -NV 或是 brew install fastlane
两个中任何一个都可以
3)初始化Fastlane
安装完成后就是在项目初始化Fastlane
cd到你的需要打包的项目目录,然后执行命令\
fastlane init
1:自动截屏。这个功能能帮我们自动截取APP中的截图,并添加手机边框(如果需要的话)
2:自动发布beta版本用于TestFlight
3:自动发布到AppStore
4:手动设置
我在这里选的是第四个(大家可根据自己需要选择,建议选择4)
紧接着一直点击enter键,直到安装成功
安装成功之后,会在我们的项目工程目录生成下面几个文件: 先不去修改这些文件,等安装好Jenkins和配置好后再来修改
二、Jenkins 安装 和 配置 1)首先检查是否有Jenkins依赖的java环境
终端输入命令
java -version
出现java version "1.8.xx"说明已经安装了java
如果没有安装,去下面官网下载对应自己电脑系统的版本安装:www.java.com
2)检查是否有安装HomeBrew
终端输入命令
brew -v
有显示Homebrew版本说明已经安装
如果没有则使用以下命令安装Homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 复制代码 终端输入下面命令安装最新版稳定Jenkins,安装时间较长
brew install jenkins-lts
启动Jenkins服务
brew services start jenkins-lts
其他命令
一、添加数据库用户
1、MySQL的权限表
MySQL通过权限表来控制用户对数据库的访问,MySQL数据库在安装时会自动安装多个数据库。MySQL权限表存放在名称为MySQL的数据库中,常用的权限表有user、hous、table_priv、db、columns_priv和procs_priv。
2、添加用户
添加用户可以通过create user,insert和grant语句来实现。
①create user "用户名"@"主机号" identified by "密码";
②insert into user (host,user,password,ssl_cipher,x509_issuer,x509_subject) values("主机号","用户名",password("密码"),"","","");
二、授予、回收数据库用户权限
1、授予用户权限
grant 权限 on 库名.表名 to "用户名"@"主机号";
2、查看用户权限
show grants for "用户名"@"主机号"\G;
3、回收用户权限
revoke all privileges,grant option from "用户名"@"主机号";
三、数据库用户管理
1、修改用户的名称
rename user ”旧的用户名称“@”主机号“ to ”新的用户名称“@”主机号“;
2、修改用户密码
①set password=password;
set password for "用户名"@"主机号"=password(”密码“);
②update user set password=password(”密码“)
wherer host=“主机号” and user=“用户名”;
3、删除用户
①drop user "用户名"@"主机号";
②delete from user where host=“主机号” and user=“用户名”;
注: 部分概念介绍来源于网络
transient 临时:这些设置在集群重启之前一直会生效。一旦整个集群重启,这些设置就会被清除。
persistent 永久:这些设置永久保存,除非再次被手动修改。是将修改持久化到文件中,重启之后也不影响。
PUT /_cluster/settings { "persistent" : { "cluster.routing.allocation.enable" : "none" //永久性关闭分片自动均衡 }, "transient" : { "cluster.routing.allocation.enable" : "none" //临时性关闭分片自动均衡,重启集群,设置失效 } }
注: 部分概念介绍来源于网络
写脚本的背景:业务的需求,需要添加一个配置,然后在不影响集群的情况下重启生效(业务可以接受短暂的yellow和red)。这样我就需要在集群恢复green之后,才能重启下一台机器。
脚本使用方法:脚本esrestart.sh和一个listIP列表放置es集群ip或域名。
执行如下命令:
sh esrestart.sh listIP
#!/bin/bash #0、本脚本用于重启es集群,其中active master必须手动启动,脚本无法重启此mater #1、判断参数 if [ $# -lt 1 ] then echo -e "\033[1;31m 参数不足,请重新执行... \033[0m" echo -e "\033[1;32m 此脚本传参使用方法:$0 第一个参数为待重启的es集群ip列表文件名 \033[0m" exit ; fi workdir=`pwd` #2、建立es相关的配合文件 list=$1 es_home="/home/es/software/elasticsearch" es_cluster_name="es-mimi6" list_ip=`cd ${workdir};cat $list` sum=`cat $list|sed '/^$/d'|wc -l` num=1 #4、人工判断脚本是否可以执行,防止误操作 while true ; do echo -ne "\033[33m本脚本会重启es集群,请在 120 秒内确认是否执行: (Y/N) \033[0m" ; read -t120 result [ -z "${result}" ] && break case ${result} in Y|y) break ;; N|n) echo -e "
写在前面:最近在学习php与数据库的交互,为了防止忘记数据库的操作,所以写了此篇文章来记录一下(附:本文章没有考虑sql注入问题和数据重复问题,即少了数据的检测和防止sql注入的操作,所以仅做初学者参考使用) 本篇文章使用的是php初级代码,前端没有导入好看的模板,旨在迅速的教会初学者使用php和mysql数据库进行交互,实现简单的增删改查功能。 运行代码环境:使用的是集成的wampserver服务器,自带mysql服务器和Apache,编辑器使用的是VSCODE,web使用的是360浏览器。
下面进入正式流程;
1.建立文件夹 (文件项目部署在wampserver服务器的www目标文件下,即安装了wampserver之后的wampserver本身自己在的那个文件夹,这样可以直接使用localhost进行本地访问,当然也可以根据自己的喜好放在别的文件夹下进行访问(此步骤需要对wampserver的配置文件进行修改,不建议使用,可以学习题主把文件丢在www文件下))。
2.文件夹已经创好,我们使用wampserver自带的phpmyadmin来创建一个数据库(进入方式,在浏览器的搜索栏输入localhost/phpmyadmin.php即可进入) 记得在进入数据库之前要先把wampserver运行起来,只有服务器运行起来之后我们才能够进入phpmyadmin.php(运行起来即桌面右下角的服务器图标变成绿色的)
3.创建一个数据库,左边是数据库的名称,右边是数据库的编码方式,我们选择编码方式为utf8_general_ci; 4.创建数据库完成之后我们在这个数据库里面创建一个新的表格,我们选择三个字段数来进行展示。 5.选择数据表的数据类型 这里我们为了更多的体现数据库的功能,我们设置了id为数据的主键,设置了age允许默认值是空值的情况,然后name设置的是varchar类型(这个地方要注意,后面可能会因此出现bug)
6.先在数据库可视化界面里面给数据库添加几个数据,点击最下面的执行按钮,即把数据成功的添加到了数据库当中 7.添加完成,可以看到数据库中已经存入了我们刚刚导入的数据。 8.开始代码的书写(在我们刚刚创建的文件夹中创建一个新的php文件,用于代码的书写) 9.先书写两行代码测试是否数据库已经完成了连接(测试数据库和环境配置是否出现了问题) 第2行的代码是进行数据库的连接,第一个参数是数据库的位置,因为我们是本地的数据库,所以我们就是localhost,然后第二个参数表示的是数据库登陆的用户名,第三个参数表示的是登陆数据库时的密码(默认就是0),第四个数据库就是表明我们要用的是哪个数据库,第五个参数是表明我们要使用服务器的哪个端口(可以不写,我们这里选择了用默认的,就让它自己使用默认值了)。
第三行的代码为测试代码,返回$link的值,如果返回了一个object对象,表示这个数据库已经连接成功了。
10.进入浏览器,输入http://localhost/zsgc/select.php,看到显示如下画面,显示生成了一个object界面,表示我们的数据库已经和代码连接成功了。 11.进行少量前端代码和后端代码的融合,看不懂的可以直接copy(下面会有解释),代码如下 select.php:
<?php $link=@mysqli_connect('localhost','root','','zsgc'); //var_dump($link); $select="select * from test"; //需要执行的sql语句 $result=mysqli_query($link,$select); //表明执行了数据库的语句之后的结果存在result中 while($data=mysqli_fetch_assoc($result)){ $html=<<<A <tr> <td>你的id为:{$data['id']}你的姓名为:{$data['name']}</td> </tr> <br> A; echo $html; } mysqli_close($link); ?> 变量$html的作用是为了在前端页面展示后端的数据,即把前端的数据封装成一个字符串类型的数据,然后把后端数据存进来之后再进行输出展示
12.运行之后的效果展示 可以看到,我们的数据已经被显示到了界面上,即已经实现了数据的查的功能。
13.实现删除操作,新建一个文件delete.php,这个文件主要是接收我们想要删除的文件的id,然后把数据传输到delete2.php这个文件里,这第二个文件的目的就是完成我们的目标,即完成数据的删除。 代码如下
delete.php:
<html> <head> <meta charset="utf-8" /> </head> <body> <form action="delete2.php" method="post"> 你要删除的数据的id为 <input type="text" name="id" /> <input type="submit" value="提交"> </form> </body> </html> delete2.
数据库除了数据管理之外,安全管理也是很重要的部分,其中的用户权限管理可以有效保证数据的安全访问,防止数据被非必要用户泄露、修改或删除。因此,MySQL提供了用户管理来保证数据的安全性。
MySQL 安全管理通过创建用户、用户授权、 用户登录3个步骤的用户管理来实现。MySQL 安全系统非常灵活,可以通过命令或界面化登录,而用户权限也可以从数据库、表、列及其他数据库对象的不同授权来达到,既满足用户的需求,又限制用户不能超出访问、操作的权限。
1.添加数据库用户 1.MySQL 的权限表 MySQL通过权限表来控制用户对数据库的访问,MySQL数据库在安装时会自动安装多个数据库。MySQL权限表存放在名称为MySQL的数据库中。常用的权限表有 user、db、host、table_priv、columns_priv和 procs_ priv。
(1)user权限表。user是MySQL中最重要的一个权限表,user列主要分为4个部分:用户列、权限列、安全列和资源控制列。
①用户列:用户登录时通过表中的Host、User和Password列判断连接的IP、用户名称和密码是否存在于表中来通过身份验证或拒绝连接。
②权限列:user表中包含多个以“_priv”结尾的字段,这些字段决定了该用户的权限,既包括查询权限、插入权限、更新权限、删除权限等普通权限,也包括关闭服务器和加载用户等高级管理权限。
③ 安全列:ssl(加密)、x509(标识用户)开头的字段,以及 plugin 和 authentication string字段(验证用户身份、授权的插件)。
④资源控制列:max(最大允许次数,0表示无限制)开头的字段。 max_questions:表示每小时允许执行查询数据库的次数。
max_updates:表示每小时允许执行更新数据库的次数。
max_connections:表示每小时允许执行连接数据库的次数。 max_user_conntions:表示单个用户同时连接数据库的次数。
(2)db、host权限表。db权限表存储用户在各个数据库上的操作权限,决定哪些用户可以从哪些主机访问哪些数据库。
host 权限表是db权限表的扩展,配合db权限表对给定主机上数据库级操作权限做更细致的控制。host 权限表很少使用,只有在db表的范围内扩展一个条目时才会用到。
(3)table_priv权限表。记录数据表级别的操作权限。table_priv权限表与db权限表相似,不同之处是它用于数据表而不是数据库。
(4)columns_priv权限表。记录数据字段级别的操作权限。columns_priv权限表的作用与table_priv权限表类似,不同之处是它针对某些表的特定字段的权限。
(5)procs_priv权限表。该权限表存储用户在存储过程和函数上的操作权限。
2.添加用户 新安装的MySQL 中只有一个名称为root的用户。这个用户是安装服务器时由系统创建并赋予了 MySQL 的所有权限。在对 MySQL 的实际操作中,通常需要创建不同层次要求的用户来确保数据的安全访问。添加用户可以通过 CREATE USER INSERT和 GRANT语句来实现。
(1)CREATE USER语句的语法格式为:
CREATE USER <'用户名>@<'主机'> [IDENTIFIED BY[PASSWORI[<'密码'>]];
说明:
①使用 CREATE USER 语句可以创建一个或多个用户,用户之间用逗号分隔。
②“主机”可以是主机名或IP 地址,本地主机名可以使用localhost,“%”表示一组主机。
③“IDENTIFIED BY”关键字用于设置用户的密码,若指定用户登录不需要密码,则可以省略该选项。
④“PASSWORD”关键字指定使用哈希值设置密码。密码的哈希值可以使用 PASSWORDO 函数获取。
(2)INSERT语句的语法格式为:
INSERT INTO mysql.user(User,Host,Password
Values(<'用户名'>,<'主机'>,PASSWORD(<'密码 '>));
D-Bus是一种高级的进程间通信机制,它由freedesktop.org项目提供,使用GPL许可证发行。D-Bus的主要概念为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,例如等待网络状态的转变或者计算机发出关机指令。
DBus的三层架构:
底层接口层:主要是通过libdbus这个函数库,使进程拥有使用DBus的能力。
总线层:主要是由Dbus 总线守护进程(daemon)提供的,在Linux/Qnx系统启动时运行,负责进程间的消息路由和传递,其中包括内核和桌面环境的消息传递。总线守护进程可同时与多个进程相连,并能把来自一个进程的消息路由到一个或者多个进程。
应用封装层:通过一系列基于特定应用程序框架将DBus的底层接口封装成友好的Wrapper库,供应用开发人员使用。
通信类型:
信号(Signal),最常用的通信方式。一个进程可以发送一个或多个信号给另一个进程(或多个进程),发送进程指定Dbus接口(interface)和信号(member),接收进程通过监听相应的接口和成员来接收信号。
方法(Method):处理比较复杂或比较大量的数据。通过Dbus调用另一个进程的方法,当方法执行完毕时会通过回调函数(Callback)来通知调用进程,调用进程可以在回调函数内处理返回的数据。
接收信号流程:
1.调用dbus_bus_register进行Dbus总线注册。注册dbus的进程需要设定一个dbus name用来在总线上标识自己,注册完成后会创建一个DBusConnection,相当于该进程与dbus总线的连接点。
2.调用dbus_bus_add_match()添加信号匹配条件,一般是以字符串列表(包含interface和member)的形式添加。告诉dbus总线该进程想要接收信号对应的接口和信号名,当dbus总线接收到对应的信号时就会发送给添加条件的进程。
3.调用dbus_connection_add_filter(conn, function, NULL, NULL)添加接收到消息时的处理函数。当进程接收到dbus总线通知的消息时会进入到该函数,在该函数内可以根据不同接口收到的信号分别进行处理。
发送信号流程:
1.第一步和接收信号流程的第一步一样,需要先进行注册,为dubs连接取名,创建一个发送信号的通道。
2.调用dbus_message_new_signal
(obj_path,interface,member)创建要发送的接口名和信号名。
3.调用dbus_message_append_args 设置发送消息的相关参数
4.调用dbus_connection_send(connection,msg) 把消息发送到指定的dubs连接
调用dbus_connection_flush(connection) 冲刷dbus连接,此时消息就会发送到dbus总线上。
欢迎关注微信公众号“日拱一卒不期而至”获取更多内容及学习资料。
最近几年,汽车电子领域有一个概念异常火爆,那就是域控制器。今天就从三个方面来介绍一下域控制器,分别是:什么是域控制器,为什么要引入域控制器,座舱域控制器简介。
什么是域控制器呢?简单来说就是把功能相近的多个传统ECU,集中到一个算力和资源都很强大的控制器里,这个控制器被称为域控制器,所以这里的域指的是功能域。该控制器需要包含多个传统ECU的功能,每个传统ECU对应域控制器里的一个或多个应用程序,而控制执行器的底层驱动由域控制器统一管理。
常见的域控制器有:动力总成域控制器,车身域控制器,底盘域控制器,辅助驾驶域控制器,座舱域控制器(或者信息娱乐域控制器)。
为什么要引入域控制器呢?窃以为有以下三个主要原因。
1.随着汽车电子化程度越来越高,车上的ECU数量也越来越多,奥迪A8上的ECU数量已经超过一百个。如此多的ECU,它们之间还要相互通信,让这么多ECU在整车上有条不紊地协调工作,有非常大的挑战。传统的做法是车上需要增加一个新的功能时就需要增加一个ECU,比如驾驶辅助系统就包括前向碰撞预警ECU、交通识别ECU、辅助泊车ECU等。加入一个新的ECU势必会打破整车原有的网络拓扑结构,也会给整车线束布置带来新的挑战。引入域控制器后,可以大量减少ECU的数量,域控制器之间通过CAN FD,Flecray或者车载以太网等高速率总线进行通信,如此可以降低整车网络拓扑的复杂性,同时也能减少整车线束数量。而且域控制器具有良好的扩展性,需要引入新功能时只需要在现有的域控制器上开发即可,OTA空中下载功能,也让车载软件更新更加便捷。
2.随着ADAS和娱乐信息系统的飞速发展,车载ECU需要处理越来越多的数据(交通标志,高精地图,个性化,多媒体等数据),同时对ECU的运算能力也有了更高的要求,传统的ECU已经不能满足日益增长的数据处理和运算能力的需求。此时把高性能的Soc(片上系统)引入到车载控制器上也就顺理成章了,Soc具有多个处理核心(四核或八核),拥有MCU无法比拟的运算能力,同时Soc可以配合片外DDR RAM和EMMC或UFS使用,为大量数据的处理和存储成为可能。
3.随着软件在整车中的比重越来越高,各大OEM都意识到自己开发核心软件的重要性,纷纷成立了自己的软件研发中心或子公司,在域控制器领域成功突破的OEM,将来留给零部件供应商的业务只有应用软件开发了。每个OEM都想在域控制器领域抢占先机,当然各大零部件供应商也不甘示弱,最后会是一个OEM和供应商合作与竞争并存的局面。
最后来简单介绍一下座舱域控制器,也称为信息娱乐域控制器。主要涵盖数字液晶仪表,中控娱乐屏,副驾和后座娱乐屏,HUD等。根据OEM的具体需求,所包含的部件类型和数量会有所不同。
一般的座舱域控制器会采用两个处理芯片,一个MCU和一个Soc。MCU一般采用Classic Autosar架构,通过整车网络(Flexray, CAN, LIN等)与其他零部件进行数据交换,以及管理域控制器的电源状态。Soc端可以通过Hypevisor运行两个操作系统,Qnx(或Linux)与安卓。Qnx用来处理对实时性和安全等级比较高的功能,比如液晶仪表、HUD等。而安卓主要用来处理对扩展性要求比较高的功能,比如导航、车辆设置、多媒体播放等功能,需要增加新的功能时只需要安装一个APP即可。MCU和Soc之间有一些数据需要交互,例如中控屏上的一些设置需要先把信号传送给MCU,再由MCU通过整车网络发送给其他零部件;MCU从整车网络接收到的一些状态信息,也需要先发送给Soc,再由Soc显示到液晶仪表或者中控娱乐屏上,比如车速、Telltale、电池电量、空调状态等信息。
MCU和Soc之间的通信方式由供应商或者OEM自己来定义,如果从传输速率和经济性两个方面考虑,SPI是一个比较好的选择。
以上就是对智能座舱的分享,如果觉得有用可以关注微信公众号“日拱一卒不期而至”,可以获得更多相关分享。
前不久有一个朋友想转去做汽车软件开发,问我需要学习什么内容。今天在这里做一个分享,希望可以帮到这位朋友以及以后想要从事汽车电子软件开发的朋友们。
随着SDV(软件定义汽车)概念的提出, 大家都认识到了软件在汽车电子领域的重要性,各大汽车主机厂纷纷成立了软件研发中心并争夺软件开发人才。上汽集团在今年年初成立了上汽软件中心(后改名为零束),长城汽车成立了诺博、诺创、诺博,还有很多OEM也成立或者扩大了各自的软件研发中心,这里都不赘述了。
总之,这对从事汽车软件开发的同僚们是很大的利好。2019年大家经历了汽车销量下滑带来的零部件供应商效益下滑,2020年的疫情对汽车行业来说更是雪上加霜,好在从9月份开始汽车销量迎来了不错的增长,给我们汽车电子从业者们带来了更多信心。未来随着SDV的进一步推进,以及汽车新四化的逐渐开展,对软件开发人员的需求也会进一步增加。
啰嗦了这么多就是想给正在或者想要从事软件开发的大家一点信心,提升自己的开发技能、做好自己的开发工作,未来大有可为。下面回到本文的主题,想要从事汽车软件开发需要掌握哪些技能,本文讨论的scope是单片机软件开发,关于带有操作系统的Soc软件开发我们以后可以讨论。
1.首先要对单片机(MCU)的基本构成有一个了解,如果是计算机或者电子信息相关的专业,大学应该都学过一门叫做“微机原理”的课程,那这一步就可以跳过了。如果没有学过这门课,可以自己买一本单片机原理的书来看一下,对单片机的各个组件(什么是ALU、RAM、ROM、寄存器等)有个基本的了解。
2.接下来就是C语言编程知识了,C语言是你和MCU进行沟通的语言,通过C程序告诉MCU你要它完成什么工作(比如通过一个端口输出一个PWM)。C语言的强大之处是可以直接操控硬件,大部分操作系统都是使用C语言来编写的,包括你每天都会使用的Windows系统和Android系统(部分组件是用汇编来写的),从世界编程流行语言排行榜上,常年霸占榜首就可以看出C语言的重要程度。相信大部分人大学应该都学过C语言这门课程,因为现在不管是不是理工科的专业,利用编程解决问题的思想还是有必要学习一下的。如果你没有学过C语言也不要方,可以自己买一本C语言的入门书籍来学习,掌握C语言的基本语法即可,更多的编程技巧可以在单片机编程的过程中强化学习。网上比较推荐《C Primer Plus》这本书来入门,本人没有看过这本书,不作评价,感兴趣的朋友可以先了解一下,再决定是否选择它作为入门书籍,鉴于目前国内的翻译水平参差不齐,英文没问题的话可以直接阅读原版。进阶的话有《C和指针》,《C陷阱与缺陷》。
3.MCU虽然很强大,但是如果只有一个MCU没有相关的外围电路它也干不了什么事情,因此我们需要能看懂和MCU交互的外围电路的原理图。比如现在让你通过MCU来控制一个LED的亮灭,首先你要看一下电路上这个LED连在了MCU的哪一个端口上了,如此你才知道通过控制哪个端口的电平状态来点亮和熄灭该LED。其次还要看一下端口输出什么电平可以点亮LED,同样的输出什么电平可以熄灭LED。我们举一个例子来说明,下图中的RGB_RED是连接到MCU的一个端口上的,通过该端口来控制红色LED的亮灭,那么如何点亮这个红色的LED呢?我们看到RGB_RED接到了一个NPN型(什么是NPN和PNP自行百度查阅)三极管的基极上(1),当端口RGB_RED输出高电平时集电极(3)到发射极(2)就会导通,红色LED的一端是5V(P5V0),另一端是GND,此时就会有电流流过红色LED,红色LED就会被点亮;相反,当端口RGB_RED输出低电平时集电极(3)到发射极(2)截止(不导通),就不会有电流通过红色LED,红色LED就会熄灭。真实的项目中除了控制LED的亮灭外,还要控制LED的亮度水平(白天亮度需要更高,夜晚亮度低一些),此时就要用到MCU的PWM(脉冲宽度调制)功能了,PWM其实就是一个频率和占空比可以调节的方波,通过调节占空比的大小(0%-100%)来调节LED的亮度。原理也很简单,调节占空比其实就是调节加在LED上面的电压:假设最大电压是5V,那50%占空比对应的就是2.5V,输出的电压和占空比是一个线性的关系。
4.有了上面的这些基础就可以开始简单的MCU编程了,推荐想要入门的同学可以买一个MCU开发板(最好带有CAN、LIN、SPI、I2C这些常用通信接口),开发板上有丰富的外围电路设备以及编写好的程序例程,跟着这些例程可以快速地掌握相关的开发技能。想要从事汽车电子领域的MCU软件开发工作,还需要掌握该领域内常用的一些通信接口,比如和整车其他模块交互的CAN、LIN网络,以及MCU和板上资源交互的I2C、SPI等串行通信接口。这些内容可以在具体的例程项目中去学习,也不是一朝一夕的事情,需要大家沉下心去钻研。
好了,以上就是本次分享的全部内容。如果大家对具体的MCU中的模块感兴趣的话,可以在讨论区留言。如果你觉得本文对你有用,可以点击阅读原文或者关注公众号"日拱一卒不期而至"一起学习交流。
文章目录 1.简介2.构造函数3.公共成员函数4.join()5.detach()6.joinable()7.operator=8.静态函数9.C线程库 1.简介 C++11 中提供的线程类叫做 std::thread,基于这个类创建一个新的线程非常的简单,只需要提供线程函数或者函数对象即可,并且可以同时指定线程函数的参数
2.构造函数 这个类提供的一些常用 API // ① //构造函数①:默认构造函,构造一个线程对象,在这个线程中不执行任何处理动作 thread() noexcept; // ② //构造函数②:移动构造函数,将 other 的线程所有权转移给新的 thread 对象。之后 other 不再表示执行线程。 thread( thread&& other ) noexcept; // ③ //构造函数③:创建线程对象,并在该线程中执行函数 f 中的业务逻辑,args 是要传递给函数 f 的参数 /* 任务函数 f 的可选类型有很多,具体如下: 普通函数,类成员函数,匿名函数,仿函数(这些都是可调用对象类型) 可以是可调用对象包装器类型,也可以是使用绑定器绑定之后得到的类型(仿函数) */ template< class Function, class... Args > explicit thread( Function&& f, Args&&... args ); // ④ //构造函数④:使用 =delete 显示删除拷贝构造,不允许线程对象之间的拷贝 thread( const thread& ) = delete; 3.公共成员函数 get_id()
BSW架构
上一篇文章提到了基础软件层BSW包含微处理器抽象层(MCAL)、ECU抽象层、服务层以及复杂驱动,而每一层按照功能模块可以进一步划分,如下图所示。
微处理器抽象层MCAL
我们先来看一下微处理器抽象层(MCAL),MCAL是BSW的最低层,它包含一些MCU内部驱动软件模块,这些驱动直接访问MCU内部外设(ADC、WatchDog、General Purpose Timer等)。MCAL这一层依赖于MCU,但是它的上面一层(ECU抽象层)则可以独立于具体的MCU。
MCAL主要包含下面这些模块:
微控制器驱动
MCU内部外设驱动,比如看门狗、通用功能定时器等。通信接口驱动
ECU板上通信接口驱动(如SPI, I2C)以及整车通信接口驱动(CAN, 以太网等)非易失性存储器(NVM)驱动
片上NVM驱动(内部Flash、EEPROM等),片外NVM驱动(外部Flash、EEPROM等)I/O驱动
模拟和数字I/O驱动(ADC、PWM、DIO等)加密模块驱动
片上加密模块驱动,如SHE、HSM ECU抽象层
ECU的全称是Eclectronic Control Unit,直译为电子控制单元,也称为行车电脑。通俗来讲就是MCU加上一些外围必要的电路组成的一个系统,可以对各种输入信号(传感器信号、车载网络信号等)进行加工处理,然后进行信号输出(控制执行器的信号、车载网络信号等)的一个专用嵌入式系统。
ECU抽象层对MCAL所包含的驱动进行封装,同时它还包含片外设备(板上设备)的驱动。ECU抽象层提供访问各种设备的接口,不管这些设备的位置在哪里(是MCU内部还是MCU外部),也不管它们是如何与MCU进行连接的(端口还是串行通信)。它的任务是让上层软件(服务层)独立于ECU硬件设备。
片外设备顾名思义是位于MCU外部的设备,或者说是ECU的板上设备。这些设备包括但不限于:
外部EEPROM外部看门狗外部FLASH 片外设备的驱动被称为外部驱动,它们位于ECU抽象层,它们通过MCAL层的驱动访问这些外部设备。一个例子是,具有SPI接口的外部EEPROM的驱动程序,通过MCAL的SPI总线驱动对外部EEPROM进行访问。
ECU抽象层通常包含一系列接口,这些接口是对位于它们下方的模块的抽象。它提供访问特定类型设备的通用API,不关心该类型设备存在的个数以及具体的硬件实现。接口层只负责数据的传递,不改变数据的内容。比如,一个CAN通信系统的接口提供访问CAN网络的API,调用者不必关心CAN控制器的个数,也不用关心CAN控制器的位置是在MCU内部还是MCU外部。
复杂驱动CDD
复杂驱动跨越MCAL、ECU抽象层和服务层,是AUTOSAR标准之外的基础软件模块。一般是通过特定中断或复杂的MCU外设,用来实现传感器处理和执行器驱动,比如电机控制、电磁阀控制、位置检测等。
复杂驱动的任务是实现特殊功能或者对时序有较高要求的功能,用以处理复杂的传感器和执行器。复杂驱动高度依赖于MCU、ECU和应用软件。
服务层
服务层是BSW的最高层,为上层的应用软件提供各种服务:
Input/Output
对传感器、执行器以及ECU板上设备的标准访问服务存储服务
对内部/外部存储设备的标准化访问服务(NVM)通信服务
对车载网络系统(CAN, LIN)、ECU板上通信系统(SPI, I2C)的标准访问服务Off-Board通信
对V2X通信,车内无线通信网络系统的标准化服务
系统服务标准化的系统服务(操作系统,定时器)诊断服务
UDS诊断服务,内存错误检测,DTC等ECU状态管理
ECU电源状态管理,模式管理服务,看门狗管理加密服务
对密码原语的标准化访问服务,包括内部/外部硬件加速器 以上是对BSW的介绍,下一篇介绍一下RTE层。更多干货,请关注微信公众号”日拱一卒不期而至“,我们后会有期。
IF 条件语句 IF ... THEN...END IF;IF ... THEN ... ELSE...END IF;IF ... THEN ... ELSEIF ... THEN ... END IF;IF ... THEN ... ELSEIF ... THEN ... ELSE...END IF; LOOP 循环语句 1、使用 IF 退出循环
Loop
逻辑块
IF… THEN
EXIT ; END IF;
END LOOP;
2、使用 WHEN 退出循环
LOOP
EXIT WHEN 条件;
CONTINUE WHEN 后续逻辑不执行直接进入下一迭代的条件;
逻辑块
END LOOP;
3、使用 CONTINUE 此次后续逻辑不执行直接进入下一迭代
LOOP
CONTINUE WHEN 条件;
逻辑块
END LOOP;
WHILE 循环 WHILE 条件 LOOP