第一步,全局安装 sass
在命令行工具:
npm install -g sass
查看版本
sass --version
第二步:手动将sass 编译为css
1、创建一个test.scss :
2、在命令行终端 输入sass test.scss test.css进行编译
第三步、监听者目录,sass 自动编译: 通过传参数 --watch 告诉sass编译器监听者目录
sass-style是被监听的目录,css-style是被编译成css文件的存放目录
sass --watch sass-style:css-style
监听前 :
监听命令 :
监听后:
三、修改sass编译输出css的格式:--style 默认[expanded (default), compressed],目前只有这个2个值,可能是和我的版本有关系(1.56.0),默认是expanded
其他的版本可能有的值 1、nested:嵌套;默认
2、compact:紧凑 ;
3、expanded:展开;
4、compressed:压缩
格式比较: sass --watch sass-style:css-style --style compressed
sass --watch sass-style:css-style --style expanded
Sass 的用法:
第一:变量、混入@mixin name/@include name;占位符(%name)/选择器 继承extend %name;
1-1:变量的类型:number、string、boolean、null、map、list;
变量声明:$color:#fff;
1-2:混入的总结:
1、可以重复使用的css规则,一次声明多次使用;
2、不使用不会编译到,目标文件。
3、可以传参数。
// 声明变量 $primary:#fff; // 无参数 mixin @mixin border { border: 2px solid red; } /** * 声明mixin 带参数 * * 参数不传报错 * **/ @mixin ellipsis($line) { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp:$line; -webkit-box-orient: vertical; } /** * 声明mixin 带参数,有默认值 * * 1、不传参数:@include text; * * 2、按顺序传参:@include text(20, 600,2em); * * 3、指定传参:@include text($left:4em); **/ @mixin text($size:16,$weight:400,$left:2em) { font-size: $size; font-weight: $weight; padding-left: $left; } /* *可变参数 * *@include linearGradient(to top, red,green); */ @mixin linearGradient($direction,$gradient.
https://github.com/Linaom1214/TensorRT-For-YOLO-Series不支持动态模型
https://github.com/NVIDIA-AI-IOT/yolov5_gpu_optimization
上代码:
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { resolve } from 'path'; // https://vitejs.dev/config/ export default defineConfig({ server: { port: 9090, strictPort: true, // 严格端口 true:如果端口已被使用,则直接退出,而不会再进行后续端口的尝试。 /** * @description 解决chrome设置origin:*也跨域机制,代理/api前缀到服务基地址 * 最终的地址会将axios设置的baseUrl:/dev代理拼接成[target][/dev][/xxx/yyy] */ proxy: { '/dev': { target: 'http://www.baidu.com', // 接口基地址 rewrite: path => { console.log(path); // 打印[/dev/xxx/yyy] 这就是http-proxy要请求的url,如果服务器真实地址是没有/dev前缀的话要replace掉,如果有可以不replace return path.replace(/^\/dev/, ''); } } } }, plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, '.
1.B+树的背景 我们谈起B+树,可能最先想到它是MySQL中底层存储所采用的数据结构,其实B+树和二叉树、平衡二叉树一样,都是经典的数据结构。B+树由B树和索引顺序访问方法(ISAM,是不是很熟悉?对,这也是MyISAM引擎最初参考的数据结构)演化而来,MongDB中就采用的B树。
为啥MySQL中不采用B树,而采用B+树呢?(或者说MongDB中为啥不采用B+树呢?)
这是因为MySql是关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,底层索引组织数据使用B+树,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历。MongoDB使用B树,所有节点都有Data域,只要找到指索引就可以进行访问,单次查询从结构上来看要快于MySql。
2.B+树的定义 B+树是数据库所需而出现的一种B树的变形树。(这里借用王道书中,对B+树的定义)
一棵m阶的B+树需满足下列条件:
1)每个分支节点最多有m棵子树(子节点)。
2)非叶根节点至少有两棵子树,其他每个分支节点至少有⌈m/2⌉棵子树。
3)节点的子树与关键字个数相等。
4)所有叶节点包含全部关键字及指向相应记录的指针,而且叶节点中将关键字按大小顺序排列,并且相邻叶节点按大小顺序相互链接起来,m阶的B+树最多有m个关键字。
5)所有分支节点(可看成索引的索引)中仅包含他的各个子节点(即下一级的索引块)中关键字的最大值及指向其子节点的指针。
m阶的B+树与B树的主要差异在于:
在B+树中,具有n个关键字的节点只含有n棵子树,即每个关键字对应一棵子树;而在B树中,具有n个关键字的节点含有(n+1)棵子树。(节点与子树个数的对应关系)在B+树中,每个节点(非根内部节点)关键字个数n的范围是[⌈m/2⌉, m](根节点:[1,m]),在B树中,每个节点(非根内部节点)关键字个数n的范围是[⌈m/2-1⌉,m-1](根节点:[1,m-1])。(每个节点关键字个数的范围)在B+树中,叶节点包含信息,所有非叶节点仅起到索引作用,非叶节点中的每个索引项只含有对应子树的最大关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。在B+树中,叶节点包含了全部关键字,即在非叶节点中出现的关键字也会出现在叶节点中;而在B树中,叶节点包含的关键字和其他节点包含的关键字是不重复的。(叶节点包含全部关键字) 3.节点设计 isLeaf:起初想为叶子节点和非叶子节点设计两个数据结构,然后发现两个数据结构不如一个数据结构方便管理,所以选择一个结构,既能表示叶子节点,又能表示非叶子节点。(boolean)
parent:node的父节点,每次需要分裂节点,需要找到分裂节点的父节点,将新生成的节点作为父节点的子节点。(Node<K, V>)
nodeIndex:表示该节点node在父节点的索引值,这是因为当父节点的节点个数非常多的时候,直接根据索引找到node在父节点中的位置,如果没有nodeIndex,顺序查找未免太费时间了,这里属于是空间换时间了。(int)
degree:度,也是阶数,表示该节点能存储几个元素entry。(int)
entries:存储元素entry的列表;V是你传进来的类型,K是根据V生成的hash值,由KV共同构成Entry。(List<Entry<K, V>>)
nodeList:如果是叶子节点,则存储左节点和右节点;如果是非叶子节点,则存储子节点。(List<Node<K, V>>)
如下所示:
叶子节点
非叶子节点
4.B+树的初始化 degree:初始化B+树时,需要完成node的degree的赋值操作,表示degree阶B+树。
head:头节点,指向B+树的最高层的节点,增删查都需要用到head,head指向的节点的nodeIndex为-1。
half:等于(degree + 1) / 2;很多时候都会用到这个,例如节点分裂,节点合并时的可借和不可借,详情见后面代码。
初始化之后会生成一个叶节点,head指向叶节点
5.插入操作 当该节点的 entries的元素个数 <= degree 则能直接插入,插入之后,有两种情况:
entries的元素个数 <= degree ,直接返回
entries的元素个数 > degree ,分裂
分裂(文字流程在代码注释里,别怕,写得很详细了) 1)node不为head节点时,生成newNode,层数不变 (1)叶子节点分裂 (2)非叶子节点分裂 2)node为head节点时,生成newHead和newNode,升层 (1)head为叶子节点 (2)head为非叶子节点 6.删除元素 当该节点的 entries的元素个数 > half 则能直接删除,删除之后,有两种情况:
entries的元素个数 >= half,直接返回
entries的元素个数 < half,node借元素(左借,右借)和合并(左合并,右右合并),合并完是否降层
当ceil_mode = true时,将不足kernel_size大小的数据保存,自动补足NAN至kernel_size大小;
当ceil_mode = False时,剩余数据不足kernel_size大小时,直接舍弃。
例如:
inputs的大小为5*5, max_pool中kernel_size为2
inputs= [0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4]
当ceil_mode = True时:
0 0 | 0 0 | 0 ×
1 1 | 1 1 | 1 ×
————————————
2 2 | 2 2 | 2 ×
3 3 | 3 3 | 3 ×
题目链接:Cities (nowcoder.com)
input:
2 8 4 3 1 2 1 1 3 3 5 1 2 3 2 1 output:
3 2 题意:
有n个元素的数组,每个元素的值为1 ~ n ,给定一种操作,可以将在数组中相邻且值相等的一段元素变为任意1 ~ n ,问最少用多少次操作可以将整个数组变为全部一样的数
思路:
区间dp,但要加入对数据的预处理,和算法的优化。
首先处理数据,初始时每一段相邻且相等的元素,我们可以处理为一个元素,也就是去重,这样可以正常地使用dp,并且降低时间消耗。
本题的 dp[i][j] 表示 a[i] ~ a[j] 满足要求需要的最少操作数。
可以写出状态转移方程:dp[i][j] = min(dp[i + 1][j] , dp[i][j - 1]) + 1
但是到这里我们还没用上给出的初始数据。
分析可以发现,对于一段 dp[i][j],如果其中存在一个 s 点,将其分为dp[i][s] , dp[s + 1][j]两部分,如果说 a[s] 和 a[j] 是一样的,那么这两部分合起来其实不需要任何代价。在此条件下,我们可以得到这样的状态转移方程:dp[i][j] = min(dp[i][j] , dp[i][s] + dp[s + 1][j])
这是我大一的时候新入门C语言整个语法的时候,课堂中所练习的一些基础问题的源码,现分享给新入门C语言的小白,以便于学习了解C语言。 目录 1.将一个正整数分解质因数
2.判断一个数是否为水仙花数
3.找出1000以内的所有完数
4.求一个数是否为素数
5.求是否为闰年
6.求N!
7. 比较三个数的大小(从小到大输出)
1.将一个正整数分解质因数 #include<stdio.h> int main() { int x,i; printf("请输入一个整数:\n"); scanf("%d",&x); printf("%d=",x); for(i=2;i<=x;i++) { while(x!=1) //i=x时,循环结束 { if(x%i==0) //判断X%i是否能整除,如果能则把它作为一个新的数继续运算 { printf("%d",i); x=x/i; } else{ break; } } } printf("%d",x); } 运行截图:
2.判断一个数是否为水仙花数 #include<stdio.h> int main() { int x,a,b,c; printf("请输入一个三位数:\n"); scanf("%d",&x); a=x/100;b=x/10%10;c=x%10; if(x==a*a*a+b*b*b+c*c*c) printf("%d是水仙花数\n",x); else printf("%d不是水仙花数\n",x); return 0; } 运行截图:
3.找出1000以内的所有完数 #include<stdio.h> int main() { int n,i,sum; printf("1000以内的所有完数:\n"); for(n=1;n<=1000;n++) { sum=0; for(i=1;i<n;i++) { if(n%i==0) sum+=i; } if(sum==n) printf("
✨问题 很多小伙伴在使用Sevrlet时,在.class文件中导入javax包会报错
import javax.servlet.*; import javax.servlet.http.*; ✨原因 Servlet包是Tomcat自带的包,我们直接在Java程序里面导入会导致报错
✨解决方法 既然我们明白了问题所在,解决问题就变的很简单了
(1)点击:文件(File)---> 项目结构(Project Structure) (2)点击:库(Libraries) (3)选择Tomcat目录下的lib,并选中其中的servlet-api.jar包
(4)点击:应用、确认 (5)查看.class文件,不再报错 🎉成功啦!
文章目录 前言一、Linux内核的特征二、为什么要学Linux内核三、Linux操作系统结构1. Linux内核在系统中的位置2. Linux内核子系统之间的关系3. 系统主要的数据结构 三、Linux内核源码目录组织结构 前言 如果说CPU是计算机硬件的心脏,那么操作系统的内核就是整个计算机系统的心脏,或者说是最高管理机构。。。
一、Linux内核的特征 Linux内核组织形式为整体式、开放式结构,也就是说整个内核有许多个过程组成,每个过程可以单独编译。特点:内部结构简单,工作效率高。进程调度方式简单而有效。支持内核线程(守护进程),在后台运行的线程。支持多种平台的虚拟内存管理。内核有自己特殊的虚拟文件系统。模块机制,使得内核保持独立,又容易扩充。增加了系统调用,内核也允许用户自己添加系统调用。面向对象。 二、为什么要学Linux内核 提升研发出高水平软件;开发自己的操作系统;有助于计算机科学领域研究;Linux系统性能优化; 三、Linux操作系统结构 1. Linux内核在系统中的位置 Linux内核并不是孤立,要把它放到整个系统中去研究更容易理解,如下图所示内核在操作系统中的位置。
2. Linux内核子系统之间的关系 Linux内核由五大主要子系统组成,它们之间的关系为:
3. 系统主要的数据结构 在Linux内核中,有些使用频度较高的数据结构有:
task_struct:代表一个进程数据结构指针形成一个task数组。mm_struct:代表进程的虚拟内存。inode:代表虚拟文件系统中的文件、目录等对应的索引节点(inode)。 三、Linux内核源码目录组织结构 Linux内核版本有两种:稳定版和开发版,Linux内核版本号由三组数字组成。
第一组数字:目前发布的内核主版本;
第二组数字:偶数表示稳定版本,奇数表示开发中版本;
第三组数字:错误修补次数。
例如:Linux3.4.31
第一组数字:3,主版本号;
第二组数字:4, 次版本号,表示稳定版本(因为是偶数);
第三组数字:31,修订版本号,表示修改的次数,头两个数字全在一起可以描述内核系列。
为了深入地了解Linux的实现机制,还必须阅读Linux的内核源代码,下面是对有关源代码的介绍。内核源代码的版本多,对不同的内核版本,系统调用一般是相同的。新版本也许可以增加一个新的系统调用,在大多数情况下,设备文件将仍然相同,而另一方面,版本之间的内部接口有所变化。
本系列文章以Linux4.4.4版本为例。
arch目录:不同平台体系相关代码;
block目录:块设备驱动;
certs目录:与认证和签名相关代码;
crypto目录:内核常用加密。压缩算法等代码;
Documentation目录:描述模块功能和协议规范代码;
Drivers目录 :驱动程序(USB总线、PCI总线、显卡驱动等);
firmware目录 : 主要是一些二进制固件;
fs目录 : 虚拟文件系统代码;
include目录 :内核源码依赖的绝大部分头文件;
init目录 :内核初始化代码,联系到内存各个组件入口;
ipc目录:进程间通信实现,比如共享内存、信号量、匿名管道等;
kernel目录 :内核核心代码,包括进程管理、IRQ、时间等;
lib目录:C标准库的子集;
mm目录: 内存管理相关实现;
net目录: 网络协议代码,比如TCP、IPv6、WiFi、以太网实现等等;
samples目录: 内核实例代码;
scripts目录: 编译和配置内核所需脚本;perl/bash;
security目录: 内核安全模型相关代码;如selinux
sound目录: 声卡驱动源码;
tools目录: 与内核交互;
MSTP是多实例生成树,所谓多实例指的是不止一棵树,在mstp系统中可以有多个根桥,而他们分别属于不同的实例(instance),只要他们的实例之间是相互独立的,那么他们便不会产生冲突,他们同时存在的主要意义是使链路可以实现负载均衡,即解决闲置链路的问题
MSTP在RSTP的基础上引入了实例的概念,这是一种类似docker的系统,在每一个单独的实例中权限并不会冲突,很好地解决了生成树协议的闲置链路问题,让链路可以更加高效的被使用。
本实验的思路是使用MSTP协议让两个属于不同网段(vlan)的部门的主机可以在所有链路都有数据的情况下实现通信
实验步骤:
1.配置vlan
2.配置MSTP
3.配置路由
实验拓扑
1.配置vlan
vlan配置命令
vlan batch 10 20 /*每台交换机下均配置*/ int g 0/0/1 /*在trunk接口下配置*/ port link-type trunk port trunk allow-pass vlan 10 20 int g0/0/2 /*在access接口下配置*/ port link-type access port default vlan 10[20] /*依据直连主机的情况选择vlan号*/ 各交换机vlan明细如下
由于两台机器属于不同网段,所以我们需要在两台三层交换机的vlanif10和vlanif20下分别配置ip地址(主机的网关)
/*LSW5下配置*/ interface Vlanif 10 ip address 192.168.10.1 30 /*LSW6下配置*/ interface Vlanif 20 ip address 192.168.20.1 30 2.配置mstp
/*每台交换机均要配置*/ stp mode mstp stp region-configuration region-name xxx instance 2 vlan 10 instance 3 vlan 20 active region-configuration /*在三层交换机上为不同的实例赋权*/ /*LSW5*/ stp instance 2 root primary stp instance 3 root secondary stp instance 0 root primary/*实例是系统默认的实例,未分配实例的vlan都会进入实例0,后期为了通信我们建立的三层接口将会进入这个实例,为了防止二层交换机优先级较优而导致上层端口被阻塞,我们在此也要对instance0进行赋权*/ /*LSW6*/ stp instance 3 root primary stp instance 2 root secondary stp instance 0 root secondary 查看stp端口阻塞情况
前言
POSIX信号量
信号量的概念
信号量的工作原理
信号量函数
二元信号量模拟实现互斥功能
基于环形队列的生产消费模型
空间资源和数据资源
生产者和消费者申请和释放资源
必须遵守的两个规则
代码实现
信号量保护环形队列的原理
前言 将可能被多个执行流同时访问的资源叫做临界资源,临界资源需要进行保护否则会出现数据不一致等问题。当我们仅用一个互斥锁对临界资源进行保护时,相当于我们将这块临界资源看作一个整体,同一时刻只允许一个执行流对这块临界资源进行访问。但实际我们可以将这块临界资源再分割为多个区域,当多个执行流需要访问临界资源时,如果这些执行流访问的是临界资源的不同区域,那么我们可以让这些执行流同时访问临界资源的不同区域,此时不会出现数据不一致等问题。 POSIX信号量 信号量的概念 信号量本质是一个计数器(不设置全局变量是因为进程间是相互独立的,而这不一定能看到,看到也不能保证++引用计数为原子操作),用于多进程对共享数据对象的读取,它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。 每个执行流在进入临界区之前都应该先申请信号量,申请成功就有了操作特点的临界资源的权限,当操作完毕后就应该释放信号量。
信号量的工作原理 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
(1)P(sv):我们将申请信号量称为P操作,申请信号量的本质就是申请获得临界资源中某块资源的使用权限,当申请成功时临界资源中资源的数目应该减去一,因此P操作的本质就是让计数器减一,如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
(2)V(sv):我们将释放信号量称为V操作,释放信号量的本质就是归还临界资源中某块资源的使用权限,当释放成功时临界资源中资源的数目就应该加一,因此V操作本质就是让计数器加一,如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给他加1
PV操作必须是原子操作
多个执行流为了访问临界资源会竞争式的申请信号量, 因此信号量是会被多个执行流同时访问的,也就是说信号量本质也是临界资源。
信号量本质就是用于保护临界资源的,我们不可能再用信号量去保护信号量,所以信号量的PV操作必须是原子操作。
注意: 内存当中变量的++、--操作并不是原子操作,因此信号量不可能只是简单的对一个全局变量进行++、--操作。
申请信号量失败被挂起等待
当执行流在申请信号量时,可能此时信号量的值为0,也就是说信号量描述的临界资源已经全部被申请了,此时该执行流就应该在该信号量的等待队列当中进行等待,直到有信号量被释放时再被唤醒。
注意: 信号量的本质是计数器,但不意味着只有计数器,信号量还包括一个等待队列。
信号量函数 初始化信号量
初始化信号量的函数叫做sem_init,该函数的函数原型如下:
int sem_init(sem_t *sem, int pshared, unsigned int value); 参数说明:
sem:需要初始化的信号量。pshared:传入0值表示线程间共享,传入非零值表示进程间共享。value:信号量的初始值(计数器的初始值)。 返回值说明:
初始化信号量成功返回0,失败返回-1。 注意: POSIX信号量和System V信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的,但POSIX信号量可以用于线程间同步。
销毁信号量
销毁信号量的函数叫做sem_destroy,该函数的函数原型如下:
int sem_destroy(sem_t *sem); 参数说明:
sem:需要销毁的信号量。 返回值说明:
销毁信号量成功返回0,失败返回-1。 等待信号量(申请信号量)
等待信号量的函数叫做sem_wait,该函数的函数原型如下:
int sem_wait(sem_t *sem); 参数说明:
sem:需要等待的信号量。 返回值说明:
等待信号量成功返回0,信号量的值减一。等待信号量失败返回-1,信号量的值保持不变。 发布信号量(释放信号量)
程序由三种基本结构组成: 顺序结构 分支机构 循环结构 程序的流程图: 程序的基本结构 顺序结构 分支结构 循环结构 单分支结构:if语句 二分支结构:if-else语句 多分支结构:if-elif-else 循环结构:for语句 循环结构:while语句 循环保留字:break和continue
前面多篇博客都提到过,要善于从官网去熟悉一样东西。API部分详细介绍见
Point Cloud Library (PCL): Module registration
这里博主主要借鉴Tutorial里内容(博主整体都有看完)
Introduction — Point Cloud Library 0.0 documentation
接下来主要跑下Registration中的sample例子
一.直接运行下How to use iterative closet point中的代码(稍微做了变化,打印输出了Final点云)
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/registration/icp.h> int main() { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>(5, 1)); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>); // source->CloudIn data for (auto& point : *cloud_in) { point.x = 1024 * rand() / (RAND_MAX + 1.0f); point.y = 1024 * rand() / (RAND_MAX + 1.0f); point.z = 1024 * rand() / (RAND_MAX + 1.
文章目录 一、component1.介绍2.实践3.应用场景 二、directive1.介绍2.实践3.应用场景 总结 一、component 1.介绍 component是用来进行全局组件注册的。开发中经常有这样一个场景:一个组件可能在其他多个组件中被使用到,如果每次都像往常一样注册并导入就会显得十分多余。这时候就可以考虑使用component将这个组件注册成一个全局组件,就可以在其他组件中直接使用。
2.实践 入口文件: main.js
import { createApp } from 'vue/dist/vue.esm-bundler' import App from './App.vue' let app = createApp(App); /* 使用app.component来模仿写一个 Element UI 的全局组件 <el-button> 并能在各个组件中直接使用 */ app.component("el-button", { name: "el-button", template: '<button value="按钮">ElementUI按钮</button>' }); app.mount('#app'); App.vue
<template> <!-- 在App.vue上直接使用定义好的全局组件 --> <el-button /> </template> <script setup> // 此处无需再注册组件 </script> 成功渲染后的界面
3.应用场景 当需要使用到的组件在其他组件中也有使用时,就可以考虑使用全局组件。例如,Ant Design中的组件就会在多个组件中使用到,所以在使用时都会使用app.use(Element)。这个use的过程其实就是将一个个Ant Design组件注册成为全局组件,具体注册代码为:
components.forEach(component => { app.component(component.name, component); }) 如果当项目中也有一些业务组件可以提炼出来作为公共组件在多个组件中使用,就需要使用app.component来注册这些公共组件。
二、directive 1.介绍 directive主要是用来自定义指令的。这里应用该API进行全局指令的定义,一旦定义了就可以在各个组件中使用该指令。
1.建立拓扑
2.配置ip地址,其中ar3和ar4,我使用了1GEC接口里的GE接口,因为ethernet端口配置ip,是从2层转到3层,不是所有的eth端口都可以配置ip。
3.配置骨干区路由器(R1,R2,R3,R4)
Ping pc3和pc4查看是否成功
4.配置非骨干区路由器
需注意这里area为1
R1
R5
5.用display opsf peer指令,查看ospf邻居状态
6.用display ip routing-table protocol ospf 指令,查看ospf路由条目
7.用display ospf lsdb 指令,查看链路数据库
如何从API接口中获取数据并分配到每一个页面呢?😏
可是API是什么😐?在这里API就是服务器,里面有很多数据就是了🤣
言归正传。首先呢,我们在js文件的data中定义以下数据
data: { query: {},//用来存放onLoad函数传回来的数据 shopList: [],//创建一个数组 page: 1,//shoplist是第一个项目 pageSize: 10,//每一页获取多少个数据 total: 0,//总共的数据数 }, 接下来写一个函数,用来请求服务器的数据
getShopList() { wx.request({ url: `https://www.escook.cn/categories/${this.data.query.id}/shops`, method: 'GET', data: { _page: this.data.page, _limit: this.data.pageSize }, success: (res) => { console.log(res) this.setData({ shopList: [...this.data.shopList, ...res.data], total: res.header['X-Total-Count'] - 0 }) }, 1.其中id 和title 是每当我打开本页面时,就会发送给query 的2个数据,分别是id和title(如下图)
2.而${this.data.query.id}代表了数据请求时分类的id 因为这个页面的id就是data中query里的id(值为1)
3.这里的data代表请求的数据:
data中的_page代表了请求第几页的数据(在这里就是将data中page的值(1)赋值给_page)
_limit代表了请求的这一页的数据有几个(同理,是将data中pageSize的值(10)赋值给_page)
4.success函数是请求成功后的回调函数,创建一个res变量,利用setData来赋值,其中我们使用shoplist来使用展开运算符来进行拼接,拼接的就是res中data对应的数据,最终赋予shoplist数组
5.值得一提的是:res中的数据,就是我在success后面加入console.log()用来打印res中数据的原因。
6.最后就是对total进行赋值了(X-Total-Count表示这个页面总共有多少条数据),它身上的值就是res数据中的header中的X-Total-Count,but 由于X-Total-Count中间带了减号所以我们不能用点要用字符串的形式进行赋值,由于要输出的是一个数字所以后面加了一个 减0
这是我的学习笔记,最后如果各位觉得我的解释有什么问题,请多多指教!!
1、ONVIF简介 网络摄像机是网络设备,需要有通讯协议,早期的网络摄像机硬件提供商都采用私有协议。随着视频监控的网络化应用,产业链的分工将越来越细。有些厂商专门做摄像头,有些厂商专门做视频服务器,有些厂商则可能专门做平台等,然后通过集成商进行集成,提供给最终客户。私有协议无法胜任这种产业合作模式,行业标准化的接口由此应运而生。
ONVIF(Open Network Video Interface Forum)开放型网络视频接口论坛,ONVIF的目的是确保不同厂商的视频产品能够具有互通性。简单的说就是各家支持ONVIF的设备之间可以相互通信,这算是一套通用的安防协议。ONVIF标准的厂商覆盖芯片、视频前端设备、存储设备、系统平台、智能分析设备、门禁、传感设备等各个安防相关领域。
2、ONVIF Profile ONVIF Profile文件具备一组固定的、全面的功能,这些功能使产品能够根据Profile文件规范进行独立开发。Profile文件具有强制性和条件性的特点,并由以任何方式支持该特性(包括任何特定的方式)的ONVIF合规设备或客户端实施这些特性功能。为确保向后兼容性,Profile文件的规范无法更改。ONVIF profiles 可以轻松实现ONVIF规范的设备与客户端相互兼容。ONVIF profiles协议要求客户端和设备彼此必须支持一组功能,去确保支持Profile S的客户端与设备能确实彼此兼容。同时支持Profile S的客户端与设备中,一些特定的功能,也必须在双方同时被支持的前提下,才可以实现。ONVIF网络接口规范定义了ONVIF Profile协议文件的基本功能(包含特定功能)。客户端和设备可以支持多个ONVIF profile协议; 例如,具有本地存储功能的网络摄像机可以同时符合Profile S和G协议。符合profiles协议是确保符合ONVIF一致性的方法。因此,只有符合协议的认证产品才被视为符合ONVIF规范的产品。Profiles A、C、D和M 适用于门禁控制,Profiles G、Q、M、S与T 适用于视频系统。
3、ONVIF Profile 功能概述 M:Mandatory(强制)
C:Conditional(有条件的)
O:Optional(可选)
参考资料:
《https://www.onvif.org/ch/profiles/》
《https://www.onvif.org/wp-content/uploads/2021/06/onvif-profile-feature-overview.pdf?ccc393&ccc393》
背景
在微服务开发时,本地要启动太多的服务,比如基本服务,注册中心、网关、鉴权等等。还要启动当前代码所在的服务。这样,本地环境会特别卡,影响开发效率。
:
如下图所示:
在局域网内搭建一套开发环境,在开发时,这个开发环境启动的服务用来做“备胎”。
1.客户端访问的时候,携带自己想要优先访问的ip。
2.网关在转发时,发现客户端有想要优先访问的ip,则优先转发。
在整个微服务转发过程中,设计到进入网关时转发和RPC调用时转发;此只介绍网关转发时锁定远程ip。
如果是dubbo调用时想锁定远程ip可参考文章dubbo多服务本地开发调试
代码思路 网关层面在进行服务选择时,肯定会加载所有的服务,然后根据随机、轮训、权重等规则进行分发。只要自定义自己的路由规则即可。新建远程锁定ip负载均衡类LockRemoteIpLoadBalancer.java
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.*; import org.springframework.cloud.loadbalancer.core.*; import org.springframework.http.HttpHeaders; import reactor.core.publisher.Mono; import java.util.List; import java.util.concurrent.ThreadLocalRandom; public class LockRemoteIpLoadBalancer implements ReactorServiceInstanceLoadBalancer { private static final Log log = LogFactory.getLog(LockRemoteIpLoadBalancer.class); private static final String LockIp="lock-remote—ip"; ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider; final String serviceId; public LockRemoteIpLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) { this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; this.serviceId = serviceId; } @Override public Mono<Response<ServiceInstance>> choose(Request request) { ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider .
最近在看一些别人的项目代码,发现用自己的pycharm打开会缺少一些package,记录一下安装方法。
方法一
把光标移动到标红的包名上,一般pycharm有一个安装包的按钮,点击即可
方法二
有的时候方法一可能无法成功安装包,一般是python interpreter的版本问题,或者pip的版本问题。
那么可以采用下面的方法。
在pycharm中,file->settings->project->python interpreter
会显示如下界面
点击加号,然后在搜索框中输入要安装的包名,然后点击左下方的install package按钮即可
方法三
如果以上方法都不行,可以利用方法一的系统提示进行安装
1. 背景 Protobuf 用处很广,尤其是通讯数据序列化,反序列化。
TODO
2. 下载资源 protobuf镜像地址:github-protobuf
Android ndk下载:Android ndk
QNX tools下载: prebuilt_QNX700
下载完,解压!
TODO
3. 实操 废话不多数,直接上编译脚本
3.1 NDK交叉编译脚本 build_android.sh
#!/bin/sh ################################### #### build script for protobuf #### taget:qnx #### Date: 2022-11-01 #### Author: 村里小码农 ################################### # qnx bsp dir NDKROOT_PATH=/workspace/tools/android-ndk-r23b TOOLCHAIN=$NDKROOT_PATH/toolchains/llvm/prebuilt/linux-x86_64 # current dir CURRENT_PATH=$(pwd) # config Compile param. TARGET_API=28 # TARGET_ANDROID_PLATFORM=android-$TARGET_API #预留 TARGET=aarch64-linux-android #TARGET_ABI=armeabi-v7a TARGET_ABI=arm64-v8a PREFIX=$CURRENT_PATH/build/android/$TARGET_ABI if [ -d $PREFIX ];then rm -rf $PREFIX mkdir -p $PREFIX else mkdir -p $PREFIX fi if [ !