问题1.
合约部署过程报以上错误, 解决方法:
export GOPROXY=https://goproxy.cn 问题2
安装jq即可,安装命令:
sudo apt-get install jq 问题3:Calipers测试工具安装问题
root权限问题,执行一下安装可消除
npm install --production --unsafe-perm=true --allow-root
内容来自对 chagpt 的咨询
一、对字符串进行 base64 编解码 base64 编码 要在Go语言中对字符串进行base64编码,你可以使用标准库中的encoding/base64包。以下是一个简单的示例:
package main import ( "encoding/base64" "fmt" ) func main() { data := "Hello, World!" encoded := base64.StdEncoding.EncodeToString([]byte(data)) fmt.Println("Encoded:", encoded) } 在Base64编码中,所有的字母数字都是安全的('A'到'Z','a'到'z'和'0'到'9')。但是,Base64有两个额外的字符:'+'和'/',它们在某些系统(例如URL)中可能并不安全。
因此,Base64提供了一个"URL和文件名安全"的变体Base64url(也称为URL安全的Base64),它使用"-"和"_"替换"+"和"/",消除了需要URL编码的需要。
这主要是在URL,Cookie,文件名等场景中使用Base64编码的时候需要考虑的问题,因为"+","/"和"="在这些环境中可能有特殊含义(例如URL中的路径分隔,查询字符串开始等)。
在Go语言中,可以使用base64.URLEncoding代替base64.StdEncoding达到URL安全的Base64编码,例如:
encodedURLSafe := base64.URLEncoding.EncodeToString([]byte(data)) 或者先用 base64.StdEncoding 编码后,手动将 "+","/" 替换成 "-"和"_"
data := "Hello, World!" encoded := base64.StdEncoding.EncodeToString([]byte(data)) fmt.Println("Encoded:", encoded) encoded = strings.ReplaceAll(encoded, "/", "_") encoded = strings.ReplaceAll(encoded, "+", "-") fmt.Println("Encoded:", encoded) base64 解码 如果使用 base64.StdEncoding.EncodeToString 进行编码,那么使用 base64.StdEncoding. DecodeString 进行解码;同理,如果使用 base64.
博主主页:一季春秋
博主简介:专注Java技术领域和毕业设计项目实战、Java、微信小程序、安卓等技术开发,远程调试部署、代码讲解、文档指导、ppt制作等技术指导。
主要内容:毕业设计(Java项目、小程序、安卓等)、简历模板、学习资料、技术咨询。
精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟
SpringBoot+Vue项目持续更新中
http://t.csdn.cn/1mgm8
🍅文末获取联系🍅
目录
一、项目介绍 二、项目主要技术 三、系统分析
3.1 系统功能分析和描述
3.2 系统UML用例分析
3.3 系统功能结构
四、系统实现
4.1 管理员功能模块
4.2 教师功能模块
4.3 学生功能模块
五、实现代码 5.1 选课关键代码 一、项目介绍 本系统前端框架采用了比较流行的渐进式JavaScript框架Vue.js。使用Vue-Router和Vuex实现动态路由和全局状态管理,Ajax实现前后端通信,Element UI组件库使页面快速成型。后端部分:采用SpringBoot作为开发框架,同时集成MyBatis、Redis等相关技术。
教务管理系统,主要的模块包括管理员;首页、个人中心、管理员管理、老师管理、老师申请、学生管理、报名管理 、成绩管理 、考试信息管理 、教材信息管理 、课程管理 、通知信息管理 、选课管理 、基础数据管理,学生;首页、个人中心、报名管理 、成绩管理 、考试信息管理 、教材信息管理 、课程管理 、老师评价 、通知信息管理、选课管理 ,教师;首页、个人中心、学生管理 、成绩管理 、课程管理 、老师申请 、通知信息管理等功能。
二、项目主要技术 开发语言:Java 使用框架:spring boot 前端技术:JavaScript、Vue 、css3 开发工具:IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库:MySQL 5.7/8.0 数据库管理工具:phpstudy/Navicat JDK版本:jdk1.8 Maven: apache-maven 3.8.1-bin 三、系统分析 3.1 系统功能分析和描述 使用教务管理系统分为管理员和学生、教师、教务处用户三个角色的权限子模块。
问题现象: 打开 plsql,执行 sql 语句,结果中中文显示乱码(如下图中所示):
解决方法: 1)查看数据库字符集 输入 sql 语句 select userenv('language') from dual 2)查看本地字符集 输入 sql 语句 select * from V$NLS_PARAMETERS ,查看第一行和第九行是否对应
3)查看环境变量的设置 查看是否有变量 NLS_LANG,没有则新建该变量
4)新建变量 新建系统环境变量,设置变量名:NLS_LANG,变量值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK(这里的变量值需要与数据库环境相同所以不固定:比如还会有 utf-8 等),确定即可
5)重新打开 plsql 执行 sql 语句,问题解决
QT配置MySQL数据库 我当前的软件版本:QT Creator 10.0.2 (community),MingW 6.4.3 (QT6),MySQL 8.0。
MySQL不配置支持的数据库有QList("QSQLITE", "QODBC", "QPSQL"),这个时候是不支持MYSQL数据库的,所以需要进行配置。通常老版本的QT配置是通过修改QT提供的源文件mysql.pro进行重新编译,可以参考QT - QT5.14.2 连接并操作MySQL8.0。对于新版本的QT并不存在mysql.pro文件,只有CMakeLists.txt文件,所以可以参考qt6.5.0MySQL驱动手动编译以及数据库连接详细教程以及注意事项附资源链接。按照这个教程进行执行到更改.cmake.conf的时候,可以看见需要配置MYSQL的路径,这里就会很容易出现问题。按照源作者的代码:
SET(FEATURE_sql_mysql ON) SET(MySQL_INCLUDE_DIR "刚才复制的include文件夹路径/include") SET(MySQL_LIBRARY "刚才复制的lib文件夹/lib/libmysql.lib") 有时我们在安装MYSQL就直接按照默认路径开始安装,所以MYSQL的路径在C:\Program Files\MySQL\MySQL Server 8.0这个目录下,所以路径中又存在中文,又有空格存在,如果正常执行下去,那么在项目构建的时候就会出现ninja: build stopped: subcommand failed,这个错误。找遍全网,没有明确解决方案,看见一个博主说是路径访问权限出现问题(没有C盘文件权限),所以考虑到QT编译的时候只需要include和lib文件夹下的文件,所以能不能直接拷贝出来,放到一个目录下进行编译。我们将MYSQL的include和lib文件夹拷贝到一个新文件夹中,现在的路径中没有空格也不再C盘。然后修改.cmake.conf对应的值。进行重新编译,就不会再出现错误了。
然后将编译文件拷贝到对应的路径下面
然后开始验证:
新建一个QT项目,在项目中加上以下代码,(需要根据自己的情况进行配置密码等):
bool MainWindow::createConnection() { QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");//添加一个默认连接,数据库驱动为QMYSQL //设置主机名有两种方式 // db.setHostName("127.0.0.1");//设置主机名,从MySQL的Workbench中查看 db.setHostName("localhost");//设置主机名,从MySQL的Workbench中查看 db.setPort(3306);//设置端口 db.setDatabaseName("chat");//设置数据库名(这个数据库必须是已经存在的数据库) db.setUserName("root");//设置用户名 db.setPassword("xiehou");//设置密码(你自己的密码) if(!db.open()) { QMessageBox::critical(0,"Cannot open database", "Unable to establish a database connection.",QMessageBox::Cancel);//提示出错 qDebug()<<db.lastError().text();//输出错误信息 return false; } else { QMessageBox::information(0,"Successfully","Establish a database connection",QMessageBox::Ok);//提示成功 } return true; } 另外需要在pro配置文件加上QT += sql和下方的MYSQL数据库配置信息(有空格也不要紧)才能引入SQL相关的头文件。
实验1:配置IBGP和EBGP 实验目的 熟悉IBGP和EBGP的应用场景掌握IBGP和EBGP的配置方法 实验拓扑 想要华为数通配套实验拓扑和配置笔记的朋友们点赞+关注,评论区留下邮箱发给你! 实验步骤 1.IP地址的配置
R1的配置
<Huawei>system-view Enter system view, return user view with Ctrl+Z.
[Huawei]undo info-center enable [Huawei]sysname R1
[R1]interface g0/0/0
[R1-GigabitEthernet0/0/0]ip address 12.1.1.1 24
[R1-GigabitEthernet0/0/0]quit
[R1]interface LoopBack 0
[R1-LoopBack0]ip address 1.1.1.1 32
[R1-LoopBack0]quit
R2的配置
<Huawei>system-view Enter system view, return user view with Ctrl+Z.
[Huawei]undo info-center enable [Huawei]sysname R2
[R2]interface g0/0/1
[R2-GigabitEthernet0/0/1]ip address 12.1.1.2 24
[R2-GigabitEthernet0/0/1]quit
[R2]interface g0/0/0
[R2-GigabitEthernet0/0/0]ip address 23.1.1.2 24
[R2-GigabitEthernet0/0/0]quit
[R2]interface LoopBack 0
收藏和点赞,您的关注是我创作的动力
文章目录 介绍 二、硬件三、操作模式四、 原理图五、 文章目录 介绍 用51单片机STC89C52、时钟芯片DS1302、液晶屏LCD1602、光敏电阻、红外对管、设计一个教室智能照明控制系统。使用4个LED灯模拟教室的照明灯,在符合条件开启时,人数小于10人亮一个灯,10-20人亮二个灯,20-30人亮三个灯,大于30人则全亮四个灯。
基于单片机的智能教室照明人数统计设计旨在通过传感器和单片机控制照明系统,实现对教室内人数的实时统计和照明的智能化调节。这项设计的目的和意义如下:
节省能源:传统教室照明通常是固定亮度或定时开启,无论教室内是否有人。而基于人数统计的智能照明设计可以根据实时统计的人数来自动调节照明亮度。当教室人数较少或无人时,照明系统可以自动降低亮度或关闭部分灯光,从而节省能源并降低能耗。
提升舒适性:智能教室照明设计可以根据教室内人数来自动调节照明亮度,保持适应环境的舒适度。当教室内人数增加时,照明系统可以增加亮度以确保足够的照明效果;而当人数减少时,照明系统可以调低亮度以提供更为舒适的光线,避免过强或过弱的照明对学生和教师的不适影响。
提高安全性:智能教室照明设计可以提高教室的安全性。通过实时统计教室内的人数,学校管理人员可以了解到教室内的人流情况。在突发状况发生时,例如火灾、紧急情况等,可以基于教室内人数的信息来做出相应应对措施,更精确地指导疏散和救援工作。
数据分析和管理:智能教室照明设计可以记录并存储教室内人数的历史数据,通过数据分析和统计可以了解教室的使用情况和人流趋势,为学校管理提供参考依据。这些数据还可以用于教育教学研究和实践中,优化教室规划和资源分配。
综上所述,基于单片机的智能教室照明人数统计设计具有节省能源、提升舒适性、提高安全性和数据分析管理等多方面的目的和意义,对于学校和教室管理来说是一项有益的创新技术应用。
二、硬件 单片机默认使用STC89C52,可选择AT89S52。
三、操作模式 系统分自动/手动模式,可以通过按键切换模式,并有LED指示当前所在模式,在自动模式下,可以设定定时时间段,在定时时间段内,当教室有人(人数大于0)的情况下,如果光线暗弱则自动打开照明灯,照明灯点亮个数根据人数而定,不在定时时间段或者教室无人的情况下,关闭所有照明灯,另外在手动模式下,可以通过手动开关控制照明灯的亮灭,人数统计部分仍然生效。
四、 原理图 五、 文章目录 目 录
摘要…………………………………………………………Ⅰ
Abstract…………………………………………………………Ⅱ
1绪论……………………………………………………………… 1
2系统总体设计……………………………………………………4
2.1电路总体设计…………………………………………2
2.2电路总原理图………………………………………………2
3系统各部分硬件电路……………………………………………4
3.1显示电路………………………………………………………2
3.2单片机的接口电路……………………………2
4软件部分设计……………………………………………………4
4.1主程序流程图…………………………………………………2
4.2各子程序流程图………………………………………………2
5系统测试…………………………………………………………4
5.1系统测试………………………………………………………2
5.2测试结果………………………………………………………2
6结论………………………………………………………………60
参考文献………………………………………………………… 61
致谢………………………………………………………………62
附录………………………………………………………………62
文章目录 一、NUMA二、虚拟机xml配置(重点) 参考文章 第一篇:KVM虚拟化CPU技术总结 第二篇:虚机cpu和mem的配置(cputune和numatune) 第三篇:libvirt 中cpu, numa 的配置 第四篇:如何提高虚拟机性能?利用这个特性来实现! 一、NUMA NUMA架构是一种解决多CPU共同工作的技术方案。
多CPU共同工作主要有三种架构:
SMPMPPNUMA SMP和MPP此处不多做介绍。
此处只简单介绍NUMA。
NUMA:每个处理器有自己的存储器,每个处理器也可以访问别的处理器的存储器
二、虚拟机xml配置(重点) 虚拟机配置要求
1. 8c16g 2. 100g-lvm 3. vcpu绑单NUMA核 关于lvm卷的创建,参看我的这篇文章:【操作系统】磁盘管理高级
此处简述,以/dev/nvme0n1p1为例
# 1.物理卷 pvcreate /dev/nvme0n1p1 # 2.卷组 vgcreate vgdata /dev/nvme0n1p1 # 3.逻辑卷 lvcreate -L 10G -n testblk vgdata 虚拟机xml关于磁盘的配置
<disk type='block' device='disk'> <driver name='qemu' type='raw'> <source dev='/dev/vgdata1/testblk'/> <target dev='sda' bus='virtio'/> <address type='pci' domain='0x0000' bus='0x08' slot='0x01' function='0x0'/> </disk> 下面开始准备绑核!!!
1.给虚拟机cpu绑定物理机核心 2.给虚拟机cpu分组(非必须) 3.给虚拟机cpu分配内存(非必须) 物理机numa分配
lscpu | grep -i numa
关于魔术命令 Jupyter Notebook 使用的 Python 内核通常是 IPython 内核。IPython 是 Python 的增强交互式解释器,它提供了许多额外的功能,使得在 Jupyter Notebook 中编写和执行 Python 代码更加方便和强大。所以jupyter使用的是IPython的语法
IPython的特殊命令被称为"魔术"命令, 这些命令用来简化常见任务。魔术命令的前缀符号是%
我们先在这里介绍我们接下来将会使用到的几个常用的魔术命令
%run命令 可以在jupyter中使用%run命令来运行任意的python程序文件, 将指定的python脚本加载进来并运行
用法
%run [py程序路径] %timeit和%time命令 %timeit命令 作用:多次运行单个语句(单行代码)计算平均执行时间, 在估算代码最短时间时有用
%timeit L = [i ** 2 for i in range(1000)] 输出: 195 µs ± 6.06 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each) %%timeit可以用来测量单元格代码(多行代码块)执行时间, 并计算平均执行时间, 以评估代码执行性能
%%timeit # 测试效率 L = [] for n in range(1000): L.
# 低分辨率绘图 # install.packages("scico") # library(gcookbook) # library(ggplot2) # library(scico) library(tidyverse) library(sf) library(raster) library(terra) library(dplyr) library(ggspatial) library(ggnewscale) library(ggplot2) library(showtext) #配置字体 showtext_auto(enable = TRUE) font_add("times", regular = "times.ttf", bold ="timesbd.ttf", italic="timesbi.ttf", bolditalic="timesi.ttf" ) cnfont <- "times" # 中国地图通常使用这样的坐标系 mycrs <- "+proj=aea +lat_0=0 +lon_0=105 +lat_1=25 +lat_2=47 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs" # 读取小地图版本的中国省级地图 read_sf("F:/R_codedata/使用 R 语言绘制历年中国省市区县地图(小地图版本+长版)/使用 R 语言绘制历年中国省市区县地图(小地图版本+长版)/provmapdata/minishp/chinaprov2021mini/chinaprov2021mini.shp") %>% filter(!is.na(省代码)) -> provmap # 线条 read_sf("F:/R_codedata/使用 R 语言绘制历年中国省市区县地图(小地图版本+长版)/使用 R 语言绘制历年中国省市区县地图(小地图版本+长版)/provmapdata/minishp/chinaprov2021mini/chinaprov2021mini_line.shp") %>% filter(class %in% c("
批量学习(Batch Learning)和在线学习(Online Learning) 批量学习 批量学习的概念非常容易理解,我们之前介绍的许多机器学习算法,如果没有特殊说明,都可以采用批量学习的方式。批量学习的过程通常包括以下步骤:
收集一定量的样本数据。将这些样本数据送给机器学习算法进行训练,以创建模型。训练好的模型可以用于预测或分类新的数据。模型通常不会在生产环境中发生变化,对新的数据进行分类时,仍然使用之前训练的模型, 这些新送来的样例不会再作为训练集来优化我们的模型。 批量学习的优点是非常简单,只需要学习一个机器学习算法,不需要考虑在生产环境中逐步优化算法以适应新数据的变化。然而,它也有一个明显的问题,即如何适应环境的变化?
在实际应用中,数据和环境可能会随时间变化,导致模型不再适用于新数据。例如,在垃圾邮件处理中,随着时间的推移,新类型的垃圾邮件不断涌现,导致过去的模型不再有效。为了解决这个问题,可以定期执行重新的批量学习,将新样本数据与原始数据合并,并重新训练模型,以适应环境的整体变化。这种方法可以用于适应变化相对较慢的情况。
然而,它也有缺点每次重新进行批量学习的过程可能需要大量的计算资源, 且运算量巨大,尤其是在需要频繁更新模型以适应快速变化的环境时,这种方法可能不切实际。因此,在某些情况下,需要探索更灵活的学习方法,以适应数据和环境的实时变化,而不是依赖于定期的批量学习。
在线学习 在某些情况下,即使我们的计算性能足够强大,使用批量学习也不是明智的选择。这是因为在某些环境中,变化发生得非常迅速,而批量学习无法及时适应这种快速变化的情况。一个典型的例子是股市,其中股价每时每刻都在不断波动。
如果我们试图使用批量学习来进行股市分析,每次都重新收集大量的历史数据进行训练,那么我们的模型可能永远跟不上市场的变化。在这种情况下,使用在线学习的方法更为合适。在线学习的基本思想是不断地接收新数据,及时更新模型,以适应环境的变化。
在线学习与批量学习的不同之处在于,每次输入新样本后,我们不仅获得了预测结果,而且还将新样本的信息用于改进模型,然后继续接收下一个样本。这种迭代的过程持续不断,相当于在线的过程, 因此被称为在线学习。
不仅仅是简单的应用这个模型去得到我们想要的结果。与此同时呢,我们还在不断的训练这个算法,让这个算法进行学习,所以叫做在线的学习。那么在线的学习它的优点当然非常显然,
它可以及时的反映新的环境的变化。
在线学习的优点包括:
及时适应变化:能够快速适应环境的变化,特别是在数据变化速度较快的情况下,如股市分析。 然而,在线学习也存在一些问题,包括:
新数据可能引入错误:由于模型在每个时刻都在学习和更新,新的不准确或有噪音的数据可能会导致模型性能下降。
对数据质量要求高:由于模型不断迭代学习,需要确保输入的数据质量良好,以避免错误的学习。
综上所述,在线学习适用于需要快速适应环境变化的情况,但也需要小心处理新数据可能引入的问题。在不同的应用场景中,需要权衡批量学习和在线学习之间的利弊,选择适合的学习方法。
在线学习的一个典型应用场景是在生产环境中,机器学习算法可能会接收到异常或不正常的数据,这些数据可能会迅速进入模型训练过程,导致模型性能下降或产生错误的结果。竞争对手也有可能利用这些异常数据来误用我们的系统。解决这个问题需要强化对数据的监控。
为了应对这种情况,通常会在部署在线学习时加强数据监控。这意味着我们需要及时检测到异常数据,并采取相应的措施来处理它们,以防止它们对模型产生不良影响。之前在非监督学习中提到过异常检测是一个应用场景,而在线学习可以在实时监测到异常数据时进行处理。
此外,有时候由于数据量巨大,一次性离线学习可能不可行。在线学习也可以用于离线学习,这意味着我们将离线学习的过程分成多个小批次来进行,最终得到我们所需的训练模型。这种方法在处理大规模数据集时可以提供更高的效率。
综上所述,在线学习适用于需要及时适应环境变化、处理异常数据或大规模数据集的情况。通过不断迭代学习和及时监控数据,可以使在线学习在实际应用中发挥重要作用。
参数学习和非参数学习 参数学习 Parametric Learning非参数学习 Noparametric Learning 参数学习 参数学习是机器学习中的一种方法,它的基本思想是通过学习一组参数来描述输入数据和输出之间的关系。以线性回归为例,假设我们有一个二维的特征空间,其中横坐标表示房屋的面积(X),纵坐标表示房屋的价格(Y)。在参数学习中,我们可以假设房屋的价格与面积之间存在线性关系,即:
Y = a ⋅ X + b Y = a \cdot X + b Y=a⋅X+b
在这个公式中,a和b是待学习的参数。参数学习的核心任务是找到合适的参数a和b,以使这个线性模型能够最好地描述训练数据中的房屋价格和面积之间的关系。这个过程是机器学习的训练过程,而参数a和b就是机器学习中的参数。
一旦我们学到了这些参数,训练数据集就不再需要,我们可以使用这个线性模型来对新的房屋进行价格预测。这是参数学习的一大特点:一旦参数学习完成,模型就可以用于预测新数据,而不再依赖于训练数据集。
总结来说,参数学习是一种基于学习一组参数来描述输入和输出之间关系的机器学习方法。在上述例子中,参数学习被应用于线性回归模型,但它是许多其他机器学习算法的基础。
非参数学习 非参数学习就是不对模型进行统计上过多的假设,没有过多的假设。通常在预测的过程中,喂给学习算法的那些数据集也要参与预测的过程中。实际上,很多非参数学习方法中仍然存在参数,只是不对整个问题进行参数建模,但在学习过程中仍然需要考虑参数。
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 一、我对大学三年专业课程的理解二、我为什么本科选择研究嵌入式这个方向?1.可以把理论变为实际应用——兴趣是最好的老师。2.嵌入式方向可以打的比赛非常多,天然具有竞赛优势 三、我对嵌入式方向的感想?①本科阶段很适合,研究生阶段最好接触更前沿的技术②工作党三件套:裸机编程+rtos操作系统+Linux 四、对于STM32(库函数版本)的学习,我的经历是:入门阶段:新手阶段:进阶阶段:中级阶段:高级阶段: 五、关于嵌入式芯片与系统设计竞赛,我的经验①选对赛道很重要②作品立意和应用前景很重要③勇敢参赛,一定要保证作品完工上交。 六、我的下一步打算1.重温C语言和数据结构与算法2.学习C++3.学习Linux的基本知识4.去导师课题组提前开启自己的研0生活 七、未完待续 本人来自武汉某工科211,学的是当下最为热门的电子信息专业,其实大学三年,对于电子信息工程来说属实学不够,今年成为大四学长了,也即将保研去西电开启研究生生活。这里想总结一下目前大学三年自己的感想。
一、我对大学三年专业课程的理解 我们学校对于通信工程和电子信息几乎是完全相同的培养方案,所以你在大一大二学到的东西非常杂。我觉得大致有这些细分的方向:
①底层电路设计:电路基础、模电、数电、高频电子线路、电子电工技术
②通信方向:通信原理、信息论与编码、电磁场与电磁波
③信号处理方向:复变函数、信号与系统、数字信号处理、数字图像/音频处理
④嵌入式方向:嵌入式原理(STM32)、嵌入式操作系统、传感器原理
⑤偏软件编程方向:C语言、数据结构与算法、JAVA、C++、计算机网络
我最大的感受是,由于学时以及培养计划的安排,我们被迫的对所有的方向进行了一个极为粗糙的学习,每个学期都会有这5个方向中的某些课程,但是现在回想起来,完全没有形成一个系统,而且仅仅只是对理论知识的学习,我无法去想象这些课程如何应用在实践生产中,所以很难培养出什么兴趣来。
很多人一直诟病的是什么呢?是根本学不深,所谓的万金油其实也意味着没有专精的方向。我在大一大二时只是按部就班的学习这些课程,这学期学完某一课,下一学期又忘了。也许期末考试有个还行的成绩,但是实际上完全没有理解这些课有什么作用。
所以我想表达的一个核心想法就是:尽早确定自己想要细致研究的方向,越早接触应用层面越好,不要只拘束于理论知识。
二、我为什么本科选择研究嵌入式这个方向? 1.可以把理论变为实际应用——兴趣是最好的老师。 我的感受是,传统通信和信号处理方面,大学本科属实接触不到前沿先进的技术,学的教科书是几十年前的知识,基础知识虽然重要但是我没什么深入学习的欲望,这两个方向最好提前找硕导博导,像现在的新型编码技术、5G基站、雷达天线、射频等方向,进他们的实验室课题组,作为本科生打打杂跟着学习,也能接触到一些很前沿的东西,可惜我没有这方面的经历。
嵌入式跟软件编程算是我们本科生就能上手,可以接触前沿技术的领域了。
对于学编程语言,搞前端后端开发,其实很好,但是现在计算机专业尚且卷成麻花,电子信息专业只能说稍微分一杯羹,这方面我只会C,所以就不发表看法了。
嵌入式开发,对于喜欢搞电子产品、做东西、做小车、机器人的,可以把理论变为实际应用,那一定是一个很好的方向。
2.嵌入式方向可以打的比赛非常多,天然具有竞赛优势 我们学校历来具有竞赛保研的传统,学院竞赛氛围非常浓厚。电赛、智能车、机器人大赛、集创赛、嵌入式大赛、机设赛、工巡赛,可以说,本科会熟练使用STM32,就天然的拿到了组队参加这些比赛的门票。而做项目、申请专利、申请大创项目,也都是水到渠成。
三、我对嵌入式方向的感想? ①本科阶段很适合,研究生阶段最好接触更前沿的技术 不是说嵌入式不好,但是目前这个方向就业压力很大,我本科做的项目都很浅显,需要两三年的时间深入学习,并且深深的感觉到嵌入式领域如果能结合研究生的某些专精课题的话,会更有前景。
②工作党三件套:裸机编程+rtos操作系统+Linux 经常看BOSS和猎聘,基本都是这三件套,从简单到困难,我是大三这一年才学完rtos操作系统,幸好保研了有个缓冲时间,否则直接面临找工作的话,自己的技能可能还很不足。
四、对于STM32(库函数版本)的学习,我的经历是: 入门阶段: ①买一块正点原子开发板,有点小贵,但是绝对值得,我的板子陪了我两年都没坏。
②学习正点原子附送的资料,尤其是里面那四五十个实验。
③B站看江科大的教学视频,跟着他学习,不用买他家的套件,用正点原子的板子做是一样的,只不过一些led、蜂鸣器、传感器要另外买。
④安装keil平台,把最基础的一些新建项目、编写代码、编译、烧录下载等操作学会。
⑤点亮第一颗LED,让很多个LED变成流水灯。
⑥注意:不要把那些实验全部学完,你花大量时间看完也不容易理解,把基础的GPIO、TIM、ADC、USART、中断这5个的例程学会就行,这5个我觉得很重要。
新手阶段: ①找一个最简单的综合项目来练手,我的是经典的环境检测,温湿度、空气质量、烟雾浓度、雨水、PH值、酒精浓度等等。
②首先学会在CSDN找相关项目,看一看大家都用的是什么传感器模块,然后去淘宝买这些模块。
③抄(借鉴)各个平台的模块代码,基本都是相通的,然后把这些模块的代码整合一下放keil里面。看不懂背后原理无所谓,主要是了解keil编程的思路。
④看别人写的代码,多看,把基本格式学会,然后就是调函数,改bug报错,编译通过,下载烧录,成功运行。
⑤对于这些环境数值的检测,就会用的很多单片机外设的知识,边看例程就能边理解一些外设的原理了。
进阶阶段: ①会查产品手册,知道哪些引脚具有哪些特定的外设;
②会使用调试手段,利用keil的调试功能打断点、测试运行是否正常
③深入理解内存结构、RAM和ROM、时钟树、定时器、DMA等底层知识
④把一些常用模块玩的清楚。
中级阶段: ①经典上云平台,随便找个云平台,可以实现上报数据和下发指令
②可以实现两个或者多个单片机之间的数据交流
③可以实现F103到F429的各种型号的代码编写
④理解IIC、SPI、CAN、RS485、RS232、wifi、蓝牙的通信原理
高级阶段: ①参加比赛,比赛一般用不到操作系统,一般裸机编程够用。
②做项目,比如我做了智能家居门窗,然后还有六足机器人等
③学习rtos操作系统,这里比较建议freertos和国产的rtthread。
④深入学习数据结构与算法,从内存管理、代码优化、指针的使用等层面优化自己的代码风格,提高代码的效率和稳定性。
五、关于嵌入式芯片与系统设计竞赛,我的经验 这个比赛目前举办了六届,是教育部认可的A类赛事,我觉得在嵌入式芯片应用方面还是很不错的。去年(2022)名气还不算大,今年我参加时已经有了六千多支队伍参赛,说明比赛的名气逐渐打响,而且含金量更高。我们团队也是很荣幸获得了国家级一等奖。
比赛具体的介绍我不细讲了,主要谈谈我的参赛经验:
①选对赛道很重要 因为绝大多数人都是STM32启蒙的,所以ST赛道属实是卷中卷,而其他企业赛道相对来说没那么卷。因此,可以尝试一下一些国产的芯片赛道,需要提前花一点时间去熟悉国产芯片的使用,比如开发平台、编程语言、芯片手册之类的。等上手之后,其实就轻车熟路了,嵌入式开发的本质都是差不多的,只能说对那些外设模块的国产开发平台的移植是比较难的,其他问题不大。
②作品立意和应用前景很重要 根据参加省赛和国赛,评委的一些关注点来看,作品的立意首先要细,要着眼于一些待续解决的实际问题,用我们的一些新点子去尝试解决。另外,作品必须看重能否应用,能否得到市场的良好反应。举个例子,做智能家居,现在市场上这类产品太多了,大学生的智能家居最多就是一个模块的堆砌,没有解决什么社会痛点,除非你的作品真的非常精美无可挑剔。
③勇敢参赛,一定要保证作品完工上交。 比赛周期长,一定要保证最后可以提交作品。抱着拿奖的想法的话,成功提交作品就已经成功了60%,因为会有很多很多组交不了作品。哪怕作品只有一个雏形,或者功能很简单,也要尝试去提交。至于到了区赛国赛,那肯定需要再下功夫去升级作品了。
首先mysql -uroot -p 进入MySQL 选择一个数据库并使用
在该数据库内创建表格
create table homework_tb(
id int(11) comment '编号',
company_name char(6) comment '公司名称',
introduce varchar(100) comment '介绍',
content1 tinytext comment '内容1',
content2 text comment '内容2',
content3 mediumtext comment '内容3',
content4 longtext comment '内容4',
description1 blob comment '描述1', description2 mediumblob comment '描述2',
description3 longblob comment '描述3',
iq tinyint comment '0705数据库IQ',
salary smallint comment '薪资',
five_plan mediumint comment '五年计划',
code_num bigint comment '代码量',
price float(8, 2) comment '价格',
使用到中重要的类,做个简单的介绍
QNetworkAccessManager:这个类是QT帮我们封装好的工具类,主要可以用来发送Http请求 QNetworkReply:这个类主要用来监听发送的请求,并得到请求的响应结果 QHttpMultiPart:这个类主要用于封装post请求的二进制参数的数据 QEventLoop:这个类是一个控制事件 QJsonDocument:这个类用于解析JSON 头文件:
#ifndef HTTPTEST_H #define HTTPTEST_H #include <QObject> #include <QDebug> #include <QHttpMultiPart> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QMetaObject> #include <QEventLoop> #include <QJsonDocument> //以下是json数据传送所需头文件 #include <QJsonParseError> #include <QJsonObject> #include <QJsonValue> #include <QJsonArray> #include <QFile> class myHttp : public QObject { Q_OBJECT public: explicit myHttp(QObject *parent = nullptr); void sendGetRequest(); void sendPostRequest(); QString resultGet; QString resultPost; public slots: void receiveReplyGet(QNetworkReply *reply); void receiveReplyPost(QNetworkReply *reply); }; #endif // HTTPTEST_H cpp文件
最近负责的车机项目是海外项目,涉及到全球多个地区。应用开发人员在使用时区时遇到一些问题,故本人做了一点学习;本文基于android9;
可以使用这些网址查询城市的时间时区等信息:
https://time.bmcx.com/Chatham_Islands__localtime/ 使用过程中发现在这个夏令时不准
http://www.timeofdate.com/city
目录 模块架构基本方法使用主要方法代码流程 一、模块架构 主要分为三个部分,API层AlarmManager,framework层AlarmManagerService,以及Native层com_android_server_AlarmManagerService;
AlarmManager:封装在framework.jar中,提供给APP调用的接口,会用到一些工具类zoneInfo、TzData等;
AlarmManagerService:service层,时区、时间等相关的逻辑处理,也会用到工具类zoneInfo、TimeZone等;
com_android_server_AlarmManagerService:Native层,通过JNI被服务层调用;
二、时区基本方法使用 使用比较简单,通过AlarmManager完成对alarm服务的一系列操作。基本的操作主要包括设置时区、监听时区变化、主动查询时区,基本满足应用开发的使用。主要demo代码如下:
2.1 设置系统默认时区 在系统层编译时,在mk文件中设置系统属性如下,调试时也可以根据查询这个属性确定当前得时区是哪里;
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += persist.sys.timezone=Asia/Shanghai //设置系统默认时区为上海时区 2.2 查询系统支持的时区 不是所有得城市都支持直接的城市时区设置。当前系统大体支持两种方式设置时区,一种是通过设置城市得到相应得时区,另一种是设置GMT时区获得到对应时区;如下方法可以获得当前支持设置得时区参数;
String[] availableIDs = TimeZone.getAvailableIDs(); Log.i("luyao", "onClick: bt_setzone可用zoneId总数 ="+availableIDs.length); for (String zoneId : availableIDs) { Log.i("luyao", "onClick: bt_setzone= "+zoneId); } 对应的打印如下
2020-08-15 00:37:26.957 12555-12555/com.example.mtktest I/luyao: onClick: bt_setzone可用zoneId总数 =591 2020-08-15 00:37:26.957 12555-12555/com.example.mtktest I/luyao: onClick: bt_setzone= Africa/Abidjan 2020-08-15 00:37:26.957 12555-12555/com.example.mtktest I/luyao: onClick: bt_setzone= Africa/Accra 2020-08-15 00:37:26.957 12555-12555/com.example.mtktest I/luyao: onClick: bt_setzone= Africa/Addis_Ababa 2020-08-15 00:37:26.
原因:一般是库文件没添加造成的。 方案:项目--》属性--》配置属性--》链接器-》输入--》附加依赖项在其中加入所需库文件 同时在“链接器--》常规--》附加库目录”中填入相应库名。这样应该就可以了。 应用之后在运行就成功了
1.缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会被打倒数据库上。
即这个数据根本不存在,如果黑客攻击时,启用很多个线程,一直对这个不存在的数据发送请求 ,那么请求就会一直被打到数据库上,很容易将数据库打崩。
解决方案:
1.缓存空对象
优点:实现简单,维护方便
缺点:额外的内存消耗,因为缓存了一些瞎编的id对应的空对象,但是可以通过给对象设置TTL解决,但是会造成短期的数据不一致
2.布隆过滤器
优点:内存占用少
缺点:实现复杂,存在误判
3.其他
使用bitmaps类型定义访问白名单,或进行实时监控,和运维人员配合排查访问对象和访问数据设置黑名单限制服务
2.缓存击穿 缓存击穿是指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db,属于常见的“热点”问题
解决方案:
1.预先设置热门数据,提前存入缓存
2.实时监控热门数据,调整key过期时长
3.二级缓存:对于热点数据进行二级缓存,并对于不同级别的缓存设定不同的失效时间。
4.设置分布式锁
3.缓存雪崩 大量的应用请求无法在Redis缓存中进行处理,紧接着应用将大量请求发送到数据库层,导致数据库层的压力激增
击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据。
原因一:缓存中有大量Key同时过期,导致大量请求无法得到处理,大量数据需要回源数据库
方案一 差异化设置过期时间
差异化缓存过期时间,不要让大量的 Key 在同一时间过期。比如,在初始化缓存的时候,给这些数据的过期时间增加一个较小的随机数,这样一来不同数据的过期时间有所差别又差别不大,即避免了大量数据同时过期又能保证这些数据在相近的时间失效
方案二 服务降级
允许核心业务访问数据库,非核心业务直接返回预定义的信息
方案三 不设置过期时间
初始化缓存数据的时候设置缓存永不过期,然后启动一个后台线程 30 秒一次定时把所有数据更新到缓存,而且通过适当的休眠,控制从数据库更新数据的频率,降低数据库压力。
原因二:Redis实例发生故障宕机,无法处理请求,就会导致大量请求积压到数据库层 方案一 服务熔断
暂停业务应用对缓存服务的访问,从而降低对数据库的压力
方案二 请求限流
控制每秒进入应用程序的请求数,避免过多的请求被发到数据库
方案三 Redis构建高可靠集群
通过主从节点的方式构建Redis高可靠集群。可以保证在Redis主节点故障宕机时,从节点切换到主节点,继续提供服务,避免由于缓存实例宕机导致缓存雪崩
eCongnition如何基于多光谱数据构建规则集,结合DSM高程数据提取建筑物、树木和绿地。
一、数据
数据来源:教程中的实验数据,共包含RGB三个波段,还有数字地表模型(以下简称DSM)文件。
图一 RGB影像
数据特征:数据范围较小,要素种类少,仅包含较多的建筑和大片的绿地。由于建筑的房顶使用的材料和材料颜色不同,所以建筑的光谱特征没有规律,是不连续的特征。而绿地的光谱特征则十分容易分辨。
但是建筑通常具有规则的形状,而且建筑相比于周围其他要素通常有较高的高程,因此也会在其周围产生阴影,结合以上两点,我们可以对建筑物进行初步提取。
建筑物提取 分割 首先对影像进行分割,采用多尺度分割,分割参数设置为尺度为25,形状为0.1紧凑度为0.5,结果如下:
图二 多尺度分割结果
分类 根据上文数据特征的描述,我们这里通过高程特征来提取建筑。打开Feature View窗口,选择Object feature下的Layer Values的Mean,双击 DSM波段,右键选择Update Range,此时Feature View视窗底部会更新出影像的高程范围。
图三 Feature View
勾选前面的单选框eCognition的数据视窗会显示影像分割对象的高程均值信息。
图四 分割对象的高程均值
通过调整Feature View窗口底部的高程均值范围可以在数据视窗预览特定高程范围内的分割对象。通过与原始影像的对比,可以筛选出建筑的分割对象。这里将范围设置为大于等于765,这样高程均值大于等于765的对象会被显示为蓝色和绿色,而不在此范围的对象显示为灰色。结果如下:
图五 高程均值大于等于765的对象
通过与原始影像的对比发现,在该范围内的对象与实际情况有很好的吻合效果。但是也存在一些其他不规则形状的非建筑对象,从原始影像可以发现这些对象是树木,因为树木也具有很大的高程,此为噪声信息,需要在后续步骤去除。
下面通过算法对建筑对象进行分类,在Process Tree中插入分类进程,选择assign class分类算法,在Threshold condition设置阈值条件为Mean DSM>=765,并在类别中设置为建筑类别,参数设置入下:
图六 assign class分类
在菜单栏将试图切换到View Classification可以查看分类结果,浅蓝色部分是建筑分类,结果如下:
图七 建筑分类结果
可以看出建筑分类结果与底图基本吻合,除了有树木的部分。因此下面需要把树木从建筑分类中分离。
树木具有大的高程数据是由于树木的枝叶反射光谱信息到传感器造成的,但是树木枝叶之间的空隙会有透过的电磁波到达地面,再反射到传感器,因此树木的高程数据会呈现出这样的特征:树木对象的高程数据是不均匀的,在较大的高程数据中有较小的高程数据。从DSM影像上看就表现为波浪状的纹理,如下图:
图八 DSM
而建筑的高程数据是十分均匀的,也就是说树木的高程信息和建筑相比具有较大的方差,通过这个特征可以将建筑与树木分离。
与分类建筑类似,从Feature View中选择Standard deviation下的DSM,更新范围后调整到大于等于6,在数据视窗显示DSM方差大于等于6的对象如下:
图九 DSM方差大于等于6的对象
从上图可以看出,建筑对象都呈现灰色,而树木均显示为蓝绿色,至此再使用assign class分类算法将DSM方差大于等于6的对象从建筑分类中分离。在分类时,将参数Class filter设置为“建筑”,这是因为树木对象在上一步被分到建筑类别中,其所属类别为建筑。最终结果如下:
图十 初步分离树木结果
通过与图七对比可以看出大部分树木已经从建筑中分类,但仍然有少量树木未被处理,这些树木枝叶间的间隙较少,所以透过的电磁辐射较少,导致其高程信息较为均一,方差较小。换言之,这类树木枝叶较为茂盛,在绿色波段会有较高的反射值,但是由于数据没有近红外波段,所以我们通过绿色波段的比率来分离树木。
在Feature View窗口Object features选择Customized自定义特征,输入表达式如下:
图十一 自定义特征
然后通过调整green ratio的取值范围来确定植被对象,这里调整到大于等于0.36,结果如下:
图十二 green ratio大于等于0.36的对象
一、新建工程 使用eCognition新建工程ImageSegmentation,加载影像数据,并编辑图层名称,将Layer 1、Layer 2、Layer 3、Layer 4的 Layer Alias 分别改为 Blue、Green、Red、如图1-1,图1-2所示:
图 1-1
图 1-2
设置加载影像的波段组合,如图2-1所示: 图 2-1
二、设置空间子集范围 选择1000×1000范围的空间子集,点击“File”菜单栏,选择“选择 Modify Open Project”下拉菜单,点击“Subset Selection”选择空间子集范围,如图3-1所示: 图 3-1
三、多种算法的影像分割结果对比 1.棋盘分割 第一步:点击“Process”菜单栏,下拉选择“Process Tree”菜单栏,在弹出的窗口中创建进程目录,右键选择“Append New”,如图4-1-1所示:
图 4-1-1
第二步:在“棋盘分割算法”目录下,右键点击 “Insert Child”, 添加执行进程,命名为“Chessboard Segmentation 10 ResultLevel1”,如图4-1-2所示:
图 4-1-2
各个参数含义解释:
Algorithm:选择的算法名称,这里选择“chessboard segmentation”。
Domain:算法的作用域,由于对栅格影像直接进行分割,选择 pixel level。
算法参数:
Object Size:分割后每个小正方形的大小,此处设置为 10(pixel)×10(Pixel)。
Level Name:分割后得到的矢量层名称,这里设置为“ResultLevel1”。
棋盘分割后的结果如图4-1-3所示:
图 4-1-3
第三步:清除分割结果,点击“Image Objects”菜单栏,点击“Delete Level(s)”,选中“ResultLevel1”,点击”ok”删除棋盘分割结果。
2.四叉树分割 第一步:右键选择“Append New”,添加”四叉树分割算法”目录,如图4-2-1所示:
图 4-2-1
第二步:在“四叉树分割算法”目录下,右键点击 “Insert Child”, 添加执行进程,命名为“QuadtreeSegmentation 10 ResultLevel2”,如图4-2-2所示:
一.事件分发的基础概念:
1.事件分发的本质:
将点击事件(MotionEvent)传递到某个具体的View或者ViewGroup处理的过程。
2.事件的类型:
这里的事件指的就是点击事件(MotionEvent),主要分为以下几个类型:
(1)ACTION_DOWN:手指刚碰到屏幕的时候;
(2)ACTION_UP:手指离开屏幕的时候;
(3)ACTION_CANCEL:结束事件的时候(子View处理事件的过程中,父View拦截事件,收回处理权,此时的子View会收到这个事件);
(4)ACTION_MOVE:手指在屏幕上进行滑动的时候;
3.事件分发的方法:
(1)dispatchTouchEvent():分发点击事件;
(2)onTouchEvent():处理点击事件;
(3)onInterceptTouchEvent():拦截某个事件;
4.事件分发方法的调用:
(1)dispatchTouchEvent():当点击事件能够传递给当前的View的时候调用;
(2)onTouchEvent():在dispatchTouchEvent()方法的内部调用;
(3)onInterceptTouchEvent():在ViewGroup的diapatchTouchEvent()方法的内部调用;
5.事件分发方法的图解:
6.事件分发的流程:
Activity->ViewGroup->View
二.事件分发的具体分析:
1.Activity的事件分发机制:
(1)源码分析:
/** *Activity的dispatchTouchEvent */ public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); } /** *Activity的onUserInteraction *为一个空方法 */ public void onUserInteraction() { } /** *Window的superDispatchTouchEvent *为一个抽象方法 */ public abstract boolean superDispatchTouchEvent(MotionEvent event); /** *PhoneWindow的superDispatchTouchEvent *PhoneWindow为Window的实现类 */ @Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.
每个正在操作系统中运行的应用程序都是一个进程,一个进程可以包括一个或多个线程。线程是操作系统分配处理器时间的基本单元。进程就好像是一个公司,公司中的每个员工就相当于线程,公司想要运行就必须得有负责人,负责人就相当于主线程。
单线程 单线程就是只有一个线程。默认情况下,系统为应用程序分配一个主线程,该线程执行程序中以Main方法开始和结束的代码。
多线程 需要用户交互的软件都必须尽可能的对用户的活动做出反应,以便提供更丰富的用户体验。但同时它又必须执行必要的计算,以便尽可能快的将数据呈现给用户,这时就要使用多线程。
优点:要提供对用户的响应速度并且处理所需数据,以便同时完成工作,使用多线程是一种强大的技术。多线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。
Thread类 Thread类位于System.Threading命名空间下,System.Threading命名空间提供一些可以进行多线程编程的类和接口。Thread类主要用于创建并控制线程、设置线程优先级并获取其状态。
Thread类的常用属性及说明 属性说明ApartmentState获取或设置该线程的单元状态CurrentContext获取线程正在其中执行的当前上下文CurrentThread获取当前线程正在运行的线程IsAlive获取一个值,该值指示当前线程的执行状态ManagedThreadld获取当前托管线程的唯一标识符Name获取或设置线程的名称Priority获取或设置一个值,改制指示线程的调度优先级ThreadState获取一个值,该值包含当前线程的状态 Thread类的常用属性及说明 方法说明Abort在调用该方法的线程上引发ThreadAbortException,以开始终止该线程的过程。调用该方法通常会终止线程GetApartmentState返回一个ApartmentState值,该值指示单元状态GetDomain返回当前线程正在其中运行的当前域GetDomainID返回唯一的应用程序标识符Interrupt中断处于WaitSleepJoin线程状态的线程Join阻止调用线程,直到某个线程终止时为止ResetAbort取消为当前线程请求的AbortResume继续已挂起的线程SetpartmentState在线程启动前设置其单元状态Sleep将当前线程阻止指定的毫秒数SpainWait导致线程等待由iterations参数定义的时间量Start使线程被安排进行执行Suapent挂起线程,或者如果线程已挂起,则不起作用VolatileRead读取字段值。无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值VolatileWrite立即向字段写入一个值,一边该值对计算机中的所有处理器都可见 演示使用Thread类的相关方法:
namespace Thread3 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { string strInfo = string.Empty;//定义一个空字符串,用来记录线程相关信息 Thread myThread = new Thread(new ThreadStart(threadOut));//实例化Thread线程类对象 myThread.Start(); //启动主线程 //获取线程相关信息 strInfo += "线程唯一标识符:" + myThread.ManagedThreadId; strInfo += "\n线程名称:" + myThread.Name; strInfo += "\n线程状态:" + myThread.ThreadState.ToString(); strInfo += "\n线程优先级;" + myThread.Priority.ToString(); strInfo += "
一、问题分析: 有老同事问我,想用maya mel语言为模型选择点,沿法向方向移动。如下图:
并使用了如下代码操作单个定点,成功了,:
string $pp[]; string $obj; $pp = `ls -sl`; for ($obj in $pp) { select -cl; select $obj; move -r -cs -ls -wd 1 0 0 ; } 之后,又同时选择多个点操作,出现了如下错误。
点不再沿着法线移动而是垂直向上了。
二、解决方法: 分析研究后发现,maya对元素点线面的选择时,会以一种集合方式操作。必须使用 filterExpand 命令来转化为独立的单个元素,才能在for循环里调用:
用editplus文本编辑器,批量文件搜索工具在maya官方scripts脚本中查找filterExpand 用法:如下图:
发现了各类元素的分解方法:
看看多边形点的分解方式:
// Copyright 2017 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form.
本文将介绍C#异步委托的三种实现方式,并给出相关示例代码及解析。 注意事项 用委托开启线程的前提是:创建项目时必须选择“.NET Framework",如果选择的是”.Net Core“,在调用BeginInvoke时,系统会报错”Operation is not supported on this platform.“。 异步调用的另一个前提是:委托的方法列表中只能包含一个方法。 等待至完成 通过BeginInvoke和EndInvoke实现。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace FrameworkDemo { public delegate long MyDel(int a, int b); class Program { static long sum(int a, int b) { Thread.Sleep(10 * 1000); return a + b; } static void Main(string[] args) { // 异步委托操作描述 IAsyncResult res = null; long result = 0; AsyncCallback callback = ar => { // 输出结果:“计算结果为:11” Console.
背景
1.最近需要迁移代码,因此为了安全与方面需要为不同的代码仓库设置不同的ssh公钥私钥对
生成秘钥 ssh-keygen -t rsa -b 1024 -f yourname -C "xxx@gmail.com" 注册秘钥 #ssh-agent激活,ssh-agent是验证公钥私钥对的执行者。ssh-agent可以记录不同的公钥私钥对的密码,可以避免多次输入密码。 #启动 eval $(ssh-agent -s) #上面的命令也可以转换为ssh-agent $SHELL来启动agent。 #将私钥添加到agent的代理范围内,这样可以避免多次输入密码 ssh-add ~/.ssh/ssh_rsa #上面语句中用的是私钥 #可以通过ssh-add -l来查询已经被代理的秘钥,注:虽然有时候我的显示为空,但是不影响公钥和私钥的使用 配置秘钥对 #当需要为不同的仓库或者服务器设置不同的秘钥的时候可以参考这里,比如github仓库,gitlab仓库等,这里说的仓库指的是一个域名对应一个仓库,比如github.com,gitlab.com,不过一个仓库可以对应多个秘钥对。 #设置密钥对的时候需要用~/.ssh/config文件,设置的格式如下 Host gitlab.xtalpi.xyz HostName gitlab.xxx.xyz User xxx IdentityFile /data/personal/xxx/.ssh/gitlab_company #Host之后为自己定义的仓库名(自定义即可) #HostName之后给定的是仓库的域名或者公网IP #User指定仓库对应的用户名 #IdentityFile指定的是私钥文件的绝对路径
git使用 1、cmd
#查看版本 git version 2、初识
Git GUI: Git提供的图形界面工具
Git Bash: Git提供的命令行工具
1.打开Git Bash 2.设置自己的用户名和邮箱地址 git config --global user.name "xxx" git config --global user.email "123456789@163.com" 查看配置是否成功 git config --global user.name git config --global user.email 3、创建本地仓库
要使用Git对我们的代码进行版本控制,首先需要获得本地仓库
在电脑的任意位置创建一个空目录 (例如test) 作为我们的本地Git仓库 进入这个目录中,点击右键打开Git bash窗口 执行命令git init 如果创建成功后可在文件夹下看到隐藏的.git目录 创建远程仓库
4.idea设置
5.idea终端
git init git add . git commit -m "first commit" git remote add origin 远程仓库地址 git push -u origin master
这边主要是对Android开发过程中的各个版本对应的API Levl做个总结,同时分析一下Https在哪个Android版本上面做强制要求。对于Android的开发也有一定的帮助。
目录
一.GC简介
二.如何判断对象是垃圾
1、引用计数算法
2、可达性分析算法
三.垃圾回收算法
1)标记清除算法:
2)复制算法:
3)标记-整理算法
4)分代收集算法:
四.垃圾收集器的分类
1.年轻代常见的垃圾收集器
2.老年代常见的垃圾收集器
五.什么情况下对象会从新生区到老年区
一.GC简介 垃圾收集 GC(Garbage Collection)是 Java 非常重要的核心技术之一,Java 开发中程序员不需要关心对象的内存分配和资源释放,这些都由 GC 来完成,这使得 Java 开发者只需要将注意力集中在业务逻辑的处理上。
学习 GC 需要从以下 4 个方面入手:
如何判断某个对象是垃圾,需要被回收?垃圾回收算法。不同内存区域的回收方式。垃圾收集器的分类 二.如何判断对象是垃圾 Java 对象被判定为垃圾的标准:没有被其他对象引用,判断方法有两种:
1、引用计数算法 通过判断对象的引用数量来决定是否要被回收,每一个对象实例都有一个计数器,被引用则+1,完成引用则-1。
什么是完成引用?
当该对象的引用超过了生命周期,或者引用指向了其他对象,在某方法中定义一个对象的引用变量,方法结束之后变量被虚拟机栈自动释放,则改对象的引用也就结束了,所以任何一个引用计数为 0 的对象是可以被当作垃圾回收的。
当发生循环引用时,会出现问题。
2、可达性分析算法 通过判断对象的引用链是否可达来决定对象是否要被回收,这个算法的基本思想就是通过一系列的称为 GC Root 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Root 没有任何引用链相连的话,则证明此对象是不可达的,即认为它不可用
怎么让一个被判定为垃圾的对象不被回收?
一个类实现finalize方法,当这个类的某个对象第一次被判定为垃圾的时候,GC的时候就可能会调用这个对象的finalize方法,相当于给他一次起死回生的机会(如果调用过finalize就不会再调用了)。
finalize方法是由finalizer这个线程去执行的,而这个线程的优先级非常低,每次GC的时候也不一定会执行到这个方法。所以这个方法有很大的不确定性。
3.什么对象可以作为 GC Root ?
虚拟机栈中的引用对象方法区中的常量引用对象方法区中的类静态属性引用对象本地方法栈中的引用对象活跃线程中的引用对象 三.垃圾回收算法 1)标记清除算法: 标记:先进行扫描,将已存活的对象进行标记;
清除:对堆内存进行遍历,回收没有标记的对象;
缺点:清楚后会产生大量不连续的内存碎片,也就是碎片化问题;这个问题可能导致后续创建较大的对象时无法找到足够的连续空间继而再次触发垃圾回收。
2)复制算法: 将可用内存分为对象面和空闲面,在对象面上创建对象,若对象面满,就将还存活的对象复制到空闲面,然后将对象面的所有对象清楚。
这个算法不会产生碎片化的问题,特别适用新生代,因为新生代的对象的存活率很低大部分都是"朝生夕死的",所以所需复制的对象也很少,所以效率会很高。
3)标记-整理算法 标记:先进行扫描,对存活的对象进行标记。
整理:移动所有存活的对象(有标记的对象),按内存地址依次排列,然后将末端地址以后的内存全部回收。
在标记-清除的基础上完成了移动,解决了内存碎片的问题,但是成本更高,适用于对象存活率较高的场景
一、查看python pip安装的包放在哪里 1、使用 pip list 查看已安装的包名
2、然后用 pip show 包名,就可以看到安装到哪了
通常安装在python目录下的lib/site-packages目录下
二、确定当前Python环境中的site-packages目录位置 Python查看自己的第三方库默认安装路径:
python -m site
没有pip的情况下,Python中列出所有已安装的软件包
在python的交互界面,输入
help('modules')
根据回显
输入具体的模块名,获取这个模块的帮助信息
help('grpc')
启动python命令行,输入以下两行命令
import networkx
networkx.version
>>> import requests >>> requests.__version__ '2.19.1' >>> import datetime >>> datetime.__version__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute '__version__' >>> help(requests) ... VERSION 2.19.1 AUTHOR Kenneth Reitz FILE d:\program files\python-3.7.0\lib\site-packages\requests\__init__.py ...
目录: 1. 基本查询
2. 条件查询(where)
3. 聚合函数(count、max、min、avg、sum)
4. 分组查询(group by)
5. 分组后查询(having)
6. 排序查询(order by)
7. 分页查询(limit)
1. 基本语法 SELECT
字段
FROM
表名
WHERE
条件
GROUP BY
分组
HAVING
分组后条件
ORDER BY
排序
LIMIT
分页参数
1.1. 查询多个字段 select 字段1,字段2,...from 表名;
1.2. 查询所有字段 select * from 表名;
1.3. 给字段设置别名 select 字段1 别名1, 字段2 别名2,... from 表名;
1.4. 去除重复记录 select distinct 字段 from 表名;
2. 条件查询(where) SELECT * FROM 表名 WHERE 条件
问题描述 import seaborn as sns # 读取数据 iris = sns.load_dataset("iris") 在代码中使用了seaborn ,并加载iris数据,结果产生了报错信息如下所示
问题分析 原因很简单,我们使用了sns.load_dataset("iris")来加载数据,结果你本地没有这个数据,远程加载呢,网络又不通畅,导致失败
解决 找到load_dataset()在本地的数据库地址。get_data_home()函数的作用就是获取load_dataset() 的数据库地址。 一般在
C:\Users\用户名\seaborn-data 目录下面
从github上下载这个文件,这是官方给的范例数据库: https://github.com/mwaskom/seaborn-data/ 下载以后,将内部数据直接复制一份,放到你本地的seaborn-data目录即可
问题如图所示
解决:右键我的电脑–>属性–>高级系统设置–>环境变量–>系统变量里面找到path–>双击path后即可在变量值中添加路径。
完成后大功告成,现在再试试pip、python以及ipython都可以顺利进入
GRE VPN GRE Generic Routing Encapsulation,通用路由封装
提供了一种协议的报文封装在另一种协议报文的机制,是一种隧道封装技术;
GRE的优点
1. 支持组播和动态路由协议(多种协议) 2. 基于IP层工作,是一种三层VPN封装技术 3. 配置简单,部署容易 GRE的缺点
1. 点到点隧道 2. 没有安全性可言,不提供加密 3. 不能分隔地址空间 4. 部署复杂连接关系时代价巨大 GRE的IP协议号:47
GRE载荷协议:0x0800:表示上层协议为IPv4
乘客协议(passenger):(IPv4/IPv6/MPLS)乘客,货物,携带的上层数据;
封装协议:(GRE)货车的车厢,用于装载货物的载体;
运输协议:(IPv4):负责传输协议,比如货车车头,在传输过程当中,只检测此部分,不会检测乘客协议
GRE VPN路由宣告注意事项:使用动态路由协议宣告接口时千万不能宣告公网接口
会出现递归死循环,当配置了GRE并宣告了公网路由时,会从隧道接口(Tunnel)同时学习到对端的公网路由和对端的隧道路由,这时,如果本局域网访问对端PC,根据本端的PC的IP地址查询路由表,出接口为本端Tunnel接口,进入并执行GRE封装,对封装后的公网IP地址再次查询本端路由表,这一查看本端的公网IP地址的出接口还是Tunnel接口,则又进入了Tunnel口,解封装了,出来之后再次根据第一次的本局域网私有IP地址查询路由表,则再次进入Tunnel接口封装公网IP地址,出来后再次根据公网IP地址查询路由表,无限循环,根本出不去,也称为:递归死循环;
GRE VPN隧道口虚假状态问题:只要有到达隧道目标的路由,隧道口的协议字段即可Up;
但是如果对端或者去往对端设备的路由不存在或者故障(不可达),隧道口是感知不到,还是Up状态;
解决办法:开启GRE的Keeplive,用于检测隧道对端是否可达; Keeplive缺省情况下未开启;
可以只在一端开启周期性发送Keeplive报文即可,对端会回显响应KeepliveReply报文;
如果只在一端开启的话,另一端则无法进行主动检测,只是在配合本端的检测而已;
Keeplive报文默认周期性5s发送,重传3次如果对端未回应,则认为此隧道Down掉;
关于Tunnel接口的IP地址配置
此接口地址可随意配置,不会影响GRE隧道的建立;
在封装GRE隧道时,会直接将原始数据的二层直接干掉,使用本地公网接口的二层MAC地址进行发送,当对端进行解封装后,就直接展现了三层数据(类似P2P链路)无关乎二层通讯,因此,通过GRE隧道,即使Tunnel接口的IP地址与对端Tunnel接口的IP地址不在相同网段,也是可以通讯的,也可以建立OSPF邻居和互访以及学习路由;
拓展补充:
在OSPF的P2P链路上,双端IP地址不在同网段时,是可以建立Full邻居并可以学习到路由以及可以互访的;
在OSPF的广播链路上,修改ospf network-type p2p时,可以建立Full邻居和学习路由,但是不能互访;
因为,在ping对端设备时,ARP会发送广播FFFF帧,对端收到后判断不是找自己的,则不会做出响应,无法通讯;
虽然修改了ospf链路类型,但是底层仍然是以太网链路,依然需要二层MAC通讯;
[R1]interface tunnel 0/0/0 //创建隧道口 最大支持512个隧道口 范围0~511 Tunnel-protocol gre //指定协议 华为默认无协议,思科默认GRE协议 Source 12.0.0.2 //指定隧道源 Destination 13.0.0.3 //指定隧道目标 Ip address x.x.x.x //Tunnel接口的IP,随意 Gre key dazhen //设置关键字key 类似密码,如果两端不相同,则丢弃 display interface tunnel 0/0/0 //查看隧道接口状态 Keepalive period 5 retry-times 3 //开启keepalive检测避免数据黑洞 ip route-static x.
一.背景介绍 每个HTTP请求都会被HandlerMapping映射到一个独立的HandlerExecutionChain实例中,该实例包含了处理器对象和拦截器对象。
HandlerMapping接口的作用是将HTTP请求映射到相应的处理器对象上,它提供了灵活的映射机制,支持多种URL映射规则和拦截器功能,使得Spring MVC框架能够更好地处理HTTP请求并返回相应的响应。
二.源码分析 HandlerMapping 1.boolean usesPathPatterns() 2.getHandler(HttpServletRequest request) 通过request构建自定义handler对象用HandlerExecutionChain执行链对象进行封装。
public interface HandlerMapping { String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler"; @Deprecated String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath"; String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping"; String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping"; String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables"; String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables"; String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes"; default boolean usesPathPatterns() { return false; } @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } 继承关系图 AbstractHandlerMapping 1.
原图 结果 代码 // Load source image cv::Mat src = cv::imread("answer_card.jpg", cv::IMREAD_COLOR); if (src.empty()) { return; } cv::Mat gray; cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); cv::Mat binary; double value = cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY_INV + cv::THRESH_OTSU); std::vector<cv::Point2f> imgCorners{ cv::Point2f(0, 0), cv::Point2f(src.cols, 0), cv::Point2f(src.cols, src.rows), cv::Point2f(0, src.rows) }; cv::Mat dilate; cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, 7)); cv::dilate(binary, dilate, kernel); std::vector<std::vector<cv::Point>> contours; cv::findContours(dilate, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); std::vector<cv::Point2f> corners; for (size_t i = 0; i < contours.
SqlRunner
import org.apache.commons.lang.StringUtils; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.RestOptions; import org.apache.flink.table.api.TableEnvironment; import org.apache.flink.util.FileUtils; import java.io.File; import java.util.ArrayList; import java.util.List; /** * Main class for executing SQL scripts. */ public class SqlRunner { // private static final Logger LOG = LoggerFactory.getLogger(SqlRunner.class); private static final String STATEMENT_DELIMITER = ";"; // a statement should end with `;` private static final String LINE_DELIMITER = "\n"; private static final String COMMENT_PATTERN = "(--.*)|(((\\/\\*)+?[\\w\\W]+?(\\*\\/)+))"; public static void main(String[] args) throws Exception { if (args.
GitHub - mrash/afl-cov: Produce code coverage results with gcov from afl-fuzz test cases
这里需要用到的工具之一是GCOV,它随gcc一起发布,所以不需要再单独安装,和afl-gcc插桩编译的原理一样,gcc编译时生成插桩的程序,用于在执行时生成代码覆盖率信息。
另外一个工具是LCOV,它是GCOV的图形前端,可以收集多个源文件的gcov数据,并创建包含使用覆盖率信息注释的源代码HTML页面。
最后一个工具是afl-cov,可以快速帮助我们调用前面两个工具处理来自afl-fuzz测试用例的代码覆盖率结果。
afl-cov可以解析已经执行完毕的afl-fuzz输出结果,也可以与afl-fuzz同时运行,实时监控每次测试的覆盖率。
安装afl-cov:
1、apt-get install afl-cov # 但这个版本似乎不支持分支覆盖率统计 2、从Github下载最新版本,下载完无需安装直接运行目录中的Python脚本即可使用 $ apt-get install lcov $ git clone https://github.com/mrash/afl-cov.git $ ./afl-cov/afl-cov -V 还是以Fuzz test.c为例,计算Fuzzing过程的代码覆盖率流程如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> int AFLTest(char *str) { int len = strlen(str); if(str[0] == 'A' && len == 6) { raise(SIGSEGV); //如果输入的字符串的首字符为A并且长度为6,则异常退出 } else if(str[0] == 'F' && len == 16) { raise(SIGSEGV); //如果输入的字符串的首字符为F并且长度为16,则异常退出 } else if(str[0] == 'L' && len == 66) { raise(SIGSEGV); //如果输入的字符串的首字符为F并且长度为66,则异常退出 } else { printf("
el-select 分页加载 el-select 分页懒加载监听的指令——loadMore指令的使用 el-select 分页懒加载 针对数据量大的选择器,需要分页从后端接口获取数据,前端监听选择器下拉框的滚动事件,当往下滚动至底部一定位置时,调接口
监听的指令——loadMore import Vue from 'vue' Vue.directive('loadMore', { bind(el, binding) { let value = '' el.addEventListener('input', function() { value = el.querySelector('.el-select__input').value }) // 获取滚动页面DOM const SCROLL_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap') let scrollPosition = 0 SCROLL_DOM.addEventListener('scroll', function() { // 当前的滚动位置 减去 上一次的滚动位置 // 如果为true则代表向上滚动,false代表向下滚动 const flag= this.scrollTop - scrollPosition > 0 // 记录当前的滚动位置 scrollPosition = this.scrollTop // 记录滚动位置距离底部的位置,在滚动位置距离滚动页面底部一定高度时在触发,例如距页面底部只有100px时触发loadMore事件 const LIMIT_HEIGHT= 10 const scrollBottom = this.scrollHeight - (this.
一.背景介绍 Adapter作为SpringMVC最重要的组件之一,跟Interceptor同等地位,它可以帮助我们在调用接口的前后做一个自定义的拓展。
二.源码分析 HandlerAdapter 处理程序适配器
public interface HandlerAdapter { boolean supports(Object handler); @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; @Deprecated long getLastModified(HttpServletRequest request, Object handler); 1.适配器 HandlerAdapter接口的实现链 2.MVC适配器的加载 HttpRequestHandlerAdapter SimpleServletHandlerAdapter 自定义用法 public class SimpleController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView(request.getRequestURI()); } } public class SimpleHandlerAdapter implements HandlerAdapter { @Override public boolean supports(Object handler) { return handler instanceof SimpleController; } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { SimpleController controller = (SimpleController) handler; return controller.
什么是Dockerfile Dockerfile是一个纯文本文件,里面记录了一系列构建命令,每个指令都会生成一个Layer,Docker顺序执行这个文件里的步骤最终就会创建出一个新的镜像。
编写Dockerfile FROM 构建镜像的第一条指令必须是FROM,FROM作用是用于选择基础镜像。
eg:
FROM alpine:3.15 #选择Alpine镜像 FROM ubuntu:bionic #选择Ubuntu镜像 COPY 如果需要将一些文件打包到镜像中(例如一些源码、配置)。可以使用COPY命令,用法类似Linux cp命令,但是复制的源文件必须是“构建上下文”的路径,不能随意指定文件。“构建上下文”是指docker build执行时所在的目录。
eg:
COPY ./aa.xml /tmp/aa.xml #将上下文中aa.xml复制到镜像的/tmp目录下 COPY /etc/host /tmp #错误,不能使用上下文之外的文件 RUN RUN指令包含很多shell指令。Dockerfile里一条指令只能是一行,因此RUN指令每行末尾使用续行符 \,命令之间需要使用 && 来连接。如果shell命令过长,可以将这些命令集中到一个脚本文件中,用COPY命令复制到镜像中使用RUN来执行
eg:
COPY ./setup.sh /tmp/ # 复制脚本到tmp目录 RUN cd /tmp && chmod +x setup.sh \ #到tmp目录,添加执行权限 && ./setup.sh && rm setup.sh # 执行脚本并在执行后删除 ARG 和 ENV 这两条指令都可以用来创建变量,实现参数化运行。它们的区别在于ARG创建的变量在镜像构建过程中可见,容器运行是不可见。ENV 镜像构建以及容器运行时都可见。
eg:
ARG USER="root" ENV USER="root" EXPOSE EXPOSE 指令用来暴露对外服务的端口号
EXPOSE 443 # 默认tcp协议 EXPOST 53/udp # 指定udp协议 每条指令都会生产一个镜像层,Dockerfile中不要滥用指令,尽量精简合并,避免镜像臃肿不堪。
1.创建带有json字段的表
CREATE TABLE `article` ( `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL, `tags` json DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; 2.插入数据
插入一条带有 JSON 内容的数据,执行 insert 语句:
INSERT INTO `article` (`title`, `tags`) VALUES ( '体验 Mysql JSON', '["Mysql", "Database"]' ); 这里插入的是一个 JOSN 数组 [“Mysql”, “Database”]
查询操作:
1.查找带有标签”Mysql”的所有文章
SELECT * FROM `article` WHERE JSON_CONTAINS(tags, '["Mysql"]'); 2.查找标签中以”Data”开头的文章
SELECT * FROM `article` WHERE JSON_SEARCH( tags, 'one', 'Data%' ) IS NOT NULL; 1.
一、下载
1、下载Ubuntu,放到C盘
官网下载https://ubuntu.com/download/desktop
2、下载EasyBCD
链接:https://pan.baidu.com/s/1_KDr6kmVKH2u43W6XKYURg
提取码:p6pj
或者官网下载https://neosmart.net/EasyBCD/
二、Windows磁盘分区,创建空闲分区,供Ubuntu系统使用。
1、win+x,打开磁盘管理
2、选择一个磁盘,点击压缩卷
3、输入压缩空间量,根据需求比如102400M,就是100G,点击压缩。
三、使用EasyBCD
1、设置NeoGrub引导,选择“添加新条目”选项,右边窗口选择NeoGrub,之后点击“安装”。 2、 在C:\NST文件夹中打开menu.lst,添加下面内容
title Install Ubuntu root (hd0,0) kernel (hd0,0)/vmlinuz boot=casper iso-scan/filename=/ubuntu-22.04.3-desktop-amd64.iso ro quiet splash locale=zh_CN.UTF-8 initrd (hd0,0)/initrd 注意:
(1)、代码第三行:vmlinuz,和代码最后一行的initrd,这两个名字到底有没有扩展名.lz和.efi是根据Ubuntu镜像文件确定的。ubuntu-22.04.3-desktop-amd64.iso是你自己下载的Ubuntu镜像文件名。
(2)、Ubuntu镜像文件中的casper文件夹打开。
(3)、将(1)中提到文件复制到C盘。
(4)、其中,部分(hd0,0)代表的是C盘的位置,hd0中的0表示磁盘序号,后面的0代表该磁盘上由左往右数C盘分区所处的位置(排在第几)。
3、重启电脑,会出现”NeoGrub引导加载器”的选项。
4、进入之后,可以进入Ubuntu桌面,桌面有一个”安装Ubuntu22.04LTS“ 选项。
(1)、双击安装,选择中文,点击继续。
(2)、 点击继续
(3)、选择最小安装,点击继续。
(4)、点击其他选项,点击继续。
(5)、 找到第二步中Windows空闲分区,右键点击,大小不用改,新分区类型选择逻辑分区,新分区的位置不用改,用于ext4,挂载点选择 /,/就是根目录,点击OK。
(6)、安装启动引导器的设备,选择刚才的根目录盘,再点击现在安装。
(7)、点击继续。
(8)、点击继续。
(9)、在地图上,点击中国,点击继续。
(10)、设置姓名,计算机名,用户名,密码,点击继续。
(11)、等待安装完成,重新启动,进入Windows系统EasyBCD设置Ununtu系统启动项。
5、在Windows系统的EasyBCD设置Ununtu系统启动项。
(1)、点击Linux/BSD,类型选择GRUB2,修改名称,驱动器选择你设置的根目录,点击添加。
(2)、重新启动,到系统选择界面,选择Ubuntu系统 。
在 Ubuntu 中安装 VSCode
如果想要通过 ubuntu 安装 vscode 有两种方式,可以通过应用中心下载,也可以通过安装包下载,以及指令安装。
方式一:
首先在 ubuntu 桌面左侧中找到 Ubuntu SoftWare 打开,搜索 Visual Studio Code
直接安装就行了,在所需的文件夹下 输入 code即可启动
方式二:
以 sudo 用户身份运行下面的命令,依赖软件:
sudo apt install software-properties-common apt-transport-https wget 使用 wget 命令插入 Microsoft GPG key :
wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add 启用 Visual Studio Code 源仓库,输入:
sudo add-apt-repository "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" 一旦 apt 软件源被启用,安装 Visual Studio Code 软件包:
sudo apt install code 安装完成后,在所需的文件夹下 输入 code
1、开启windows的WSL与虚拟平台 支持
首先在Win11开始菜单搜索“Windows 功能”,打开功能配置界面,勾选Linux子系统以及虚拟机平台2个选项。配置后,需要按照提示,重启电脑。
2、Windows安装wsl
通过如下命令查看当前支持的发行版。
wsl --list --online 然后选择需要版本通过 进行安装,下面的Ubuntu都要是发行版名称
wsl --install Ubuntu-22.04 给予Windows权限访问虚拟机
C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps\ubuntu2204.exe config --default-user root 提示:
(1)、也可以去下载https://learn.microsoft.com/zh-cn/windows/wsl/install-manual
(2)、启动wsl肯能遇到错误以及解决办法
如果出现 0x800701bc 错误,是版本匹配问题,需要更新wsl内核至最新版本。 如下地址下载 并安装
https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
如果出现 0x80370102 错误,是因为Windows的虚拟化功能未开启。进行步骤1或 以管理员身份运行PowerShell 输入如下命令
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform 按照提示,确认并重启。
(3)、安装Ubuntu遇到,系统找不到指定的文件。
原因是子系统没有卸载,
先看有什么系统,运行命令
wsl --list --all 注销系统
wsl --unregister Ubuntu-22.04 上述安装后,wsl的文件系统位于C盘,可能会把你的C盘爆掉。
此时需要明确将其跟文件系统迁移至其他目录,例如D盘等。
3、
(1)、停止正在运行的wsl
wsl --shutdown (2)、将需要迁移的Linux,进行导出
wsl --export Ubuntu-22.04 D:/export.tar (3)、导出完成之后,将原有的Linux卸载
wsl --unregister Ubuntu-22.04 (4)、然后将导出的文件放到需要保存的地方,进行导入即可
wsl --import Ubuntu-22.04 D:\Software\Ubuntu22\ D:\export.tar
目前很乱,有空整理
%AppData%\Microsoft\Windows\Recent\AutomaticDestinations
Windows应用程序设置快捷键
AutoHotkey组合键设置
热键重复调用
powertoy工具连接
Windows常用shell命令
2 台电脑共享键鼠最简单教程
QTTabBar 「资源管理器」该有的样子
win10电脑,蓝牙设置里莫名奇妙有很多设备,全是假的,已经连接的设备反倒一个没有 删掉“设备管理器”里面“软件设备”的“Microsoft Device Association Root Enumerator”就行了
C:\ProgramData\Microsoft\Windows\Start Menu\Programs开始菜单
#双键盘替换 新建立一个TXT文件,在里面输入 “^j::send,{left} ^l::send,{right} ^i::send,{up} ^k::send,{down} ,后缀名改为ahk,如text.ahk 后用AutoHotkey打开就能够使用ijkl来替代方向键了 #三l键替换 !j::send,{left} !l::send,{right} !i::send,{up} !k::send,{down} +!j::send,{shift}+{left} +!l::send,{shift}+{right} #注意将语言切换设计到这里的这里热键的进行更替 #现在就可以使用alt + shift + l or j 来进行复制了 这样就能够固定到快速访问了
shift + f10是右键
将脚本或者文件自启动 在我的电脑-右键-管理
参考文章
然后就在网上查了一下发现用cmd命令行切换目录,如果是从当前盘符切换到其它盘符的话,cd就不起作用了; 上面我想切换到E盘下的一个文件夹,可以直接输入E: 先切换到E盘中来,然后再用cd切换到想要的目录就ok了;
alt+left为返回上一级
上帝模式
链接
快捷键 ctrl + backspace可以删除一个单词
win+v打开历史剪贴板
win+shift+s截屏
win+g游戏模式
长按win键会出现帮助
输入栏
这里面有对输入法的设置
ftp服务器
点击查看链接
防火墙查看链接
在docker run完毕之后进去发现是非root用户,这样的话建议docker run是时候用root身份操作
docker run -d --name jenkins-test -u 0 -it 129f7dfd60d8 bash 这样再进去就是root用户了
docker exec -it jenkins-test bash
一、 服务器 1.购买一个服务器,使用密钥登录
2.ssh远程连接
ssh连接的工具很多,这里推荐用的是xshell
登录成功,开始配置环境。
二、docker环境部署 1、下载docker
yum install docker 2、启动docker服务
service docker start chkconfig docker on 3、测试是否安装成功
docker version 4、设置国内镜像
vi /etc/docker/daemon.json #添加后 { "registry-mirrors": ["https://mirror.ccs.tencentyun.com"], "live-restore": true } 5、重新启动docker服务
systemctl daemon-reload service docker restart 6、 检查是否生效
docker info 三、Docker Compose的安装 1、安装中间件
下载地址:
https://github.com/docker/compose/releases/download/1.28.6/docker-compose-Linux-x86_64
2、导入文件
cd /usr/local/bin #打开文件夹 rz #选择本地文件到服务器 3、将可执行权限应用于二进制文件
sudo chmod +x /usr/bin/docker/docker-compose 4、测试是否安装成功
docker-compose --version 四、docker常用命令 拉取docker镜像 docker pull image_name 查看宿主机上的镜像,Docker镜像保存在/var/lib/docker目录下: docker images 删除镜像 docker rmi docker.
介绍
Kasm(https://kasmweb.com/)是一家提供虚拟化和远程访问解决方案的公司。他们的主要产品是 Kasm Workspaces,它是一个基于浏览器的虚拟桌面和应用程序交付平台。
Kasm Workspaces 基于开源项目 Apache Guacamole 和 Chromium 浏览器引擎构建而成,通过在服务器端进行高性能的图形渲染,并通过 WebRTC 技术在客户端进行流式传输,将完整的桌面环境和应用程序传送到用户的 Web 浏览器中。这意味着用户可以在任何设备上,只需使用 Web 浏览器,就可以访问其个人的虚拟桌面环境和应用程序,无需安装和配置本地软件。
使用
官方镜像不支持启用root用户,所以不能安装软件。
但是官方提供了解决方案 Running as Root — Kasm 1.14.0 documentation
我制作的镜像,大家可以直接下载使用。
https://hub.docker.com/r/yingge2017/kasmsudo/tags
Dockerfile
#Dockerfile #sudo as root role. FROM kasmweb/core-ubuntu-focal:1.14.0 USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update \ && apt-get install -y sudo \ && echo 'kasm-user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers \ && rm -rf /var/lib/apt/list/* ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.
前言: 最近公司又重启了以前的一个项目,写分页的时候发现居然不生效,用的是mybatisplus(以下简称mp)的分页。
问题描述 mp也是我前端时间集成进去的了,只是最近又要追加需求,结果在写查询接口的时候就发现分页不管用,如图:
这是debug之后,返回体的情况,我表中一共12条数据,我测试的分页是第一页,条数是5。结果返回的列表还是12条,总数直接显示的0。只有页数和条数对了,这两个属性当然是对的,因为这个Page是我塞入这两个属性创建的。
根据以往的经验,我猜测是忘了加mp的分页拦截器。于是找到官网,准备添加如下代码:
/** * 添加分页插件 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加 //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType return interceptor; } 结果打开配置类才发现,当时我集成mp的时候,已经把这块拦截器写上了。。。它就是没生效!
原因分析: 那么我首先就去查一下为什么不生效,我第一反应是拦截器拼接sql有问题。是不是没获取到分页,然后我找到mp的分页拦截器PaginationInnerInterceptor中的beforeQuery,然后打了个断点,打算看一下分页参数有没有异常。
结果我测了好几次,居然一次都没进来。于是我找到mp的总拦截器MybatisPlusInterceptor的intercept方法,准备看一下分页拦截器是啥情况。结果,这个拦截器都没进入。
这下我大概明白了,拦截器有点问题,看了一下依赖,发现居然用了pagehelper。然后找到了它的拦截器PageInterceptor,找到了intercept方法,打了个断点。
果然是这样,它走了pagehelper的拦截器,没有走mp的。
解决方案: 既然知道了原因,那就很简单了。mp的分页是一个插件,只需要将这个插件放到sqlSessionFactory中即可。
@Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); String mapperLocations = env.getProperty("mybatis.mapperLocations"); String configLocation = env.getProperty("mybatis.configLocation"); typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); VFS.addImplClass(SpringBootVFS.class); final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean (); sessionFactory.setDataSource(dataSource); sessionFactory.
1. iPerf 简介 iPerf 是什么?无需我多言,官网这条醒目的宣传语,已表达的很简洁、准确,甚至透露着一丝霸气:
iPerf——支持TCP、UDP和SCTP的终极测速工具!
iPerf 官方支持的平台非常全面,包括:Windows、Android、iOS、macOS 和 Linux 的多个发行版本。但遗憾的是,Android 版本提供的是两个开发好的、包含 iPerf 工具的Android应用,可以在谷歌应用商店下载。不像其他平台,提供了单独的 iPerf 可执行程序。
我结合自己的需求,获取源码,用 NDK 交叉编译一个可以在 Android 平台运行的 iPerf 工具。期间确实也遇到了不少的问题,Google 了无数次,也参考了很多其他博客,我将用这篇博客整理记录整个实践过程,方便自己查看,也希望帮助后续探索的朋友避一些坑。
作为学习记录,我这里记录了3种编译方式:传统交叉编译,以及更符合 Android 平台的 ndk-build 和 CMake 编译。实际应用中选择一种合适方式就好。
iPerf 有 iPerf2 和 iPerf3 两个版本,两者区别可以参考官网或其他资料,本博客记录的是移植运行 iPerf3 v3.1.3 的过程。源码下载地址:iPerf - Download iPerf3 and original iPerf pre-compiled binaries。
2. 移植环境 移植时间:2020年11月iPerf3:iperf-3.1.3-source.tar.gz开发编译平台:macOS 10.14.6NDK 版本:ndk-r17c (17.2.4988734),通过 Android Studio 内的 SDK Manager 安装。 3. 传统交叉编译 编译阶段主要包括下面4个步骤:
下载源码压缩包,解压后进入源码根目录。配置交叉编译工具链;./configure --prefix=absolutepath/to/install_dirmake && make install 3.1 本机平台编译测试 在 macOS 或 Linux 平台下,如果执行上面那样写的第1、3、4步,不配置任何额外的参数,编译完成后,在 --prefix 指定的路径 bin 目录下,就已经生成了可以在本机上直接运行的可执行程序,非常简单,有兴趣的读者可以试试。
2023年国家统计局: http://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2022/
每年会更新最新的区域信息
一、准备mysql表结构,根据自己需求修改 CREATE TABLE `sys_area_new` ( `id` char(32) NOT NULL DEFAULT '' COMMENT 'ID', `is_deleted` bit(1) DEFAULT NULL COMMENT '已删除', `create_date` bigint(20) DEFAULT NULL COMMENT '创建日期', `edit_date` bigint(20) DEFAULT NULL COMMENT '编辑日期', `creator` varchar(100) DEFAULT NULL COMMENT '创建者', `editor` varchar(100) DEFAULT NULL COMMENT '编辑者', `parent` char(32) DEFAULT NULL COMMENT '级联关系', `level` varchar(20) DEFAULT NULL COMMENT '层级', `code` varchar(50) DEFAULT NULL COMMENT '编号', `name` varchar(100) DEFAULT NULL COMMENT '名称', `full_name` varchar(100) DEFAULT NULL COMMENT '全称', `is_leaf` bit(1) DEFAULT NULL COMMENT '叶子节点', `parentcode` varchar(50) DEFAULT NULL COMMENT '父级地区编码', `yn` bit(1) DEFAULT b'1' COMMENT '状态:1启用 2已作废', `remark` varchar(255) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`) USING BTREE, KEY `idx_sys_area` (`parent`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='地区'; 二、引入pom依赖 <dependencies> <dependency> <groupId>us.