在Spring Boot中,默认使用的是Logback作为日志框架。要配置Logback,可以在src/main/resources目录下创建一个名为logback-spring.xml的文件,然后在其中添加以下配置:
在 Logback 中,日志的输出被称为 appender,包含控制台输出、文件输出、网络输出等多种方式。以下是一个简单的 Logback 配置文件示例:
范例 <?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml" /> <!-- 日志输出级别 --> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> <!-- 控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 文件输出 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天滚动 --> <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 保留 7 天的日志 --> <maxHistory>7</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> </configuration> 在这个配置文件中,我们首先引入了Spring Boot默认的日志配置,然后定义了根日志级别(INFO),以及控制台和文件输出。控制台输出使用了ConsoleAppender,文件输出使用了RollingFileAppender,并配置了滚动策略。
文章目录 8 分治算法8.1 【递归】剑指 Offer 07 - 重建二叉树8.2 【递归】【快速幂】剑指 Offer 16 - 数值的整数次方8.3 【递归】剑指 Offer 33 - 二叉搜索树的后序遍历序列8.4 【递归】【分治】剑指 Offer 17 - 打印从1到最大的n位数8.5 【归并排序】【分治】剑指 Offer 51 - 数组中的逆序对 9 排序9.1 【冒泡排序】剑指 Offer 45 - 把数组排成最小的数9.2 【排序】剑指 Offer 61 - 扑克牌中的顺子9.3 【堆排序】剑指 Offer 40 - 最小的k个数9.4 【堆排序】【优先队列】剑指 Offer 41 - 数据流中的中位数 10 动态规划10.1 【动态规划】【哈希表】【DFS】剑指 Offer 10- I - 斐波那契数列10.2 【动态规划】【哈希表】【DFS】剑指 Offer 10- II - 青蛙跳台阶问题10.3 【动态规划】剑指 Offer 63 - 股票的最大利润10.4 【动态规划】【分治】剑指 Offer 42 - 连续子数组的最大和10.
代码
这里是算得是半年和一年之后的日期
var time = new Date('2021-12-17'); console.log('当前年月' + time) console.log(time.getFullYear()+'-'+(time.getMonth()+1)+'-'+time.getDate()) // 时间加一年 time.setMonth(time.getMonth() + 12); // 或者 time.setFullYear(time.getFullYear() + 1); console.log('一年后的年月' + time) console.log(time.getFullYear()+'-'+(time.getMonth()+1)+'-'+time.getDate()) // 时间加半年 time.setMonth(time.getMonth() + 6); console.log('半年后的时间' + time) console.log(time.getFullYear()+'-'+(time.getMonth()+1)+'-'+time.getDate()) var date = new Date() console.log('当前年月' + date) console.log(date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()) // 时间加一年 date.setMonth(date.getMonth() + 12); // 或者 time.setFullYear(time.getFullYear() + 1); console.log('一年后的年月' + date) console.log(date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()) // 时间加半年 date.setMonth(date.getMonth() + 6); console.log('半年后的时间' + date) console.log(date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate())
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 前言一、储备知识二、程序步骤2.程序展示 1.bootloader2.然后是主运行函数总结 前言 很久没有更新文章了。最近工作太忙,没有学习很多的知识,然后这两天不忙了,就学习了一下bootloader的程序升级,本文章是使用的STM32F103zet6这个硬件实现的
,本文章的bootloader存在bug哈,本文章只是博主记录一下自己学习bootloader的心得。最终是能成功的用串口更新程序的。
一、储备知识 在学习bootloader串口升级程序之前要知道stm32的flash和rom,flash就是掉电存储。用来存程序的。ROM是用来存单片机运行的数据的。
然后stm32的程序是从0x8000000开始的,程序运行产生的数据是从0x20000000开始的。然后1 为0x80000,可以知道stm32f103zet6的flash是(0x80000)h=524288/1024=512K,ROM(0x10000)h=65536/1024=64K。
STM32的主程序存储分为256页,每页占2K。
二、程序步骤 //-------------------------------------------------------------------- //---------------------------bootloader_2分区设置-------------------------------- //bootloader 0x8000000~0x8004000 //16K //运行程序 0x8004000~0x800C000 //32K //48K //程序下载缓存区 0x800C000~0x8014000 //32K //80K //程序更新标志位 0x807FC00~0x8080000 //1K //-------------------------------------------------------------------- 这是程序的分区。
我们的流程主要是
bootloader程序
运行程序
主要就是串口更新程序将程序写到0x800C000里面去并且将程序更新标志位置1
这里要注意程序烧录的地址哈,bootloader烧录到0x8000000,运行程序烧录到0x8004000里面去
2.程序展示 首先是stm32内部flash的读写
flash.c
#include "flash.h" #include "usart.h" //STM32G030F6P6的内部FLASH //注意STm32G030F6P6有16页,每页2K uint32_t STMFLASH_ReadWord(uint32_t faddr) { return *(volatile uint32_t*)faddr; } void STMFLASH_Read(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t NumToRead) //连续读取 { uint32_t i; for(i=0;i<NumToRead;i++) { pBuffer[i]=STMFLASH_ReadWord(ReadAddr); //读取4个字节. ReadAddr+=4; //偏移4个字节. } } HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data) //指定页写入数据 { HAL_StatusTypeDef ret = HAL_OK; HAL_FLASH_Unlock(); //解锁Flash扫写权限 ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data); if(ret!
需求:根据地理位置信息去请求免费的天气接口数据,拿到数据后进行展示,这边我用到了俩个key,一个是腾讯位置服务的key和心知天气的key,为什么要这么麻烦呢,是因为之前写过一版不需要获取地理位置,直接就可以请求天气获取数据,但是用了不到一个月,崩了,要我用升级版...,所以还是就麻烦一点吧。
1.获取腾讯位置服务的key,通过key获取到当前所在地区的位置信息
2.通过获取到的位置信息,比如武汉市,去请求心知天气的key,可以获取到当前地区的温度湿度等信息。
结果得到效果如下图
1.腾讯位置服务获取key需要注册开发者,在控制台申请
1.腾讯位置服务天气获取key 首先要注册成为个人或者企业的开发者。
其次点击右上角控制台点击应用管理==》我的应用==》创建应用如下图,名称随意填,类型选择出行
点击添加key
如下填写就行,得到了key
2.心知天气获取key 心知天气右上角注册登录后,点击右上角控制台,进入后会让你选产品==》选择免费就行,选好如下:
点击产品管理,得到公钥和私钥,复制私钥的key就行
3.请求地理位置接口获取数据请求天气接口完整代码 <template> <div class="box"> <p class="boxTemperature">{{ weatcherData.tem }}°</p> <p class="boxWeather">{{ weatcherData.wea }}</p> <p class="boxCity">{{ weatcherData.city }}市</p> </div> </template> <script> import axios from "axios"; export default { data() { return { weatcherData: { tem: "", wea: "", city: "" }, ipV: "", city: "" }; }, //生命周期 - 挂载完成(可以访问DOM元素) mounted() { this.gettianiq(); }, methods: { gettianiq() { axios({ url: "
编辑dockerfile文件,可以自行寻找相关教程
创建镜像
docker bulid -t imagename:tag . 查看镜像
docker images 如果想自己先试一下,那就需要运行容器
docker run -it -d -p 8000:8000 --name volume_name imagename:tag 查看容器
docker ps -a 进入容器的bash
docker exec -it volumename bash 导出
如果没有在容器中进行修改,那么可以直接save或者export都行
docker save -o name.tar imagename:v1 如果修改了需要保存最新的那么需要使用commit提交一下,然后再save
docker commit 容器id newimagename:tag linux安装docker并导入镜像可以查看另一篇博客
linux离线安装docker并导入tar镜像_docker tar包安装_vener_的博客-CSDN博客
目录
1. websocket解决的问题(服务器主动推送消息)
1.http存在的问题
2.long poll(长轮询)
3.Ajax轮询
4.websocket的改进
2.SpringBoot整合WebSocket
1、WebSocketConfig
2、WebSocketServer这里就是重点了,核心都在这里。
3.前端页面
1. websocket解决的问题(服务器主动推送消息) 1.http存在的问题 http是一种无状态协议,每当一次会话完成后,服务端都不知道下一次的客户端是谁,需要每次知道对方是谁,才进行相应的响应,因此本身对于实时通讯就是一种极大的障碍http协议采用一次请求,一次响应,每次请求和响应就携带有大量的header头,对于实时通讯来说,解析请求头也是需要一定的时间,因此,效率也更低下最重要的是,需要客户端主动发,服务端被动发,也就是一次请求,一次响应,不能实现主动发送 2.long poll(长轮询) 对于以上情况就出现了http解决的第一个方法——长轮询基于http的特性,简单点说,就是客户端发起长轮询,如果服务端的数据没有发生变更,会 hold 住请求,直到服务端的数据发生变化,或者等待一定时间超时才会返回。返回后,客户端又会立即再次发起下一次长轮询优点是解决了http不能实时更新的弊端,因为这个时间很短,发起请求即处理请求返回响应,实现了“伪·长连接”张三取快递的例子,张三今天一定要取到快递,他就一直站在快递点,等待快递一到,立马取走总的来看: 推送延迟。服务端数据发生变更后,长轮询结束,立刻返回响应给客户端。
服务端压力。长轮询的间隔期一般很长,例如 30s、60s,并且服务端 hold 住连接不会消耗太多服务端资源。
3.Ajax轮询 基于http的特性,简单点说,就是规定每隔一段时间就由客户端发起一次请求,查询有没有新消息,如果有,就返回,如果没有等待相同的时间间隔再次询问优点是解决了http不能实时更新的弊端,因为这个时间很短,发起请求即处理请求返回响应,把这个过程放大n倍,本质上还是request = response举个形象的例子(假设张三今天有个快递快到了,但是张三忍耐不住,就每隔十分钟给快递员或者快递站打电话,询问快递到了没,每次快递员就说还没到,等到下午张三的快递到了,but,快递员不知道哪个电话是张三的,(可不是只有张三打电话,还有李四,王五),所以只能等张三打电话,才能通知他,你的快递到了)总的来看,Ajax轮询存在的问题: 推送延迟。
服务端压力。配置一般不会发生变化,频繁的轮询会给服务端造成很大的压力。
推送延迟和服务端压力无法中和。降低轮询的间隔,延迟降低,压力增加;增加轮询的间隔,压力降低,延迟增高
4.websocket的改进 一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实现了“真·长链接”,实时性优势明显。
WebSocket有以下特点:
是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而HTTP长连接基于HTTP,是传统的客户端对服务器发起请求的模式。HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据,这显然和原有的HTTP协议有区别所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5) 2.SpringBoot整合WebSocket 创建 SpringBoot项目,引入 WebSocket依赖,前端这里比较简陋。
<!-- websocket dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.7.12</version>
</dependency>
1、WebSocketConfig 启用 WebSocket的支持也是很简单。
/**
* WebSocket配置类。开启WebSocket的支持
*/
@Configuration
public class WebSocketConfig {
需要安装的 VS Code
LLVM
VS Code 需要安装的插件: C/C++(用来配置 c_cpp_properties.json)
CodeLLDB(如果你要用 lldb 调试,那么这个插件就需要安装,用来连接到 lldb 调试器)
流程 我们都知道配置编译器要设置三个 json,task, launch, c_cpp_properties.json
task.json 直接通过 terminal - configure default build task - C/C++: clang++.exe build active file 设置
launch.json 不再是通过 C/C++: clang++.exe build and debug active file 设置,这样得到的是使用 cppdbg 调试的,我试了调试会失败,只能使用 cppvsdbg 或 lldb 调试
要使用 cppvsdbg 的话,launch.json 如下:
{ // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. // Pointez pour afficher la description des attributs existants.
如何创建代码片段 为什么要创建代码片段? 如果有要写好多代码段,但是这些代码里有很多内容是重复的,你不想一遍遍的手敲。
这时你会怎么解决这个问题?
你说:”我可以复制粘贴。”
确实,这也是一个不错的办法。但是你每次都要去先选中,复制,再回到代码页面,粘贴。如果你的剪切板里有东西,这需要你重新调整剪切板的内容。
这太麻烦了,我很懒,不想干,有没有更简单的办法?
答案是有的,这就要使用我们的代码片段了。
代码片段能干什么? 代码片段,字面意思,就是局部代码。具体是什么样子的呢。
比如我们在新建一个html页面的时候,大家一定使用过输入html就可以直接生成一大段代码。这个就是ide自带代码片段。
可是很多时候系统保存的这些代码片段根本满足不了我们的需求。这个时候我们就需要创建用户代码片段。
如何创建代码片段 VScode 点击左下角的齿轮按钮,点击用户代码片段 / 点击File ,Preferences,Configure User Snippets在搜索框中搜索要添加片段的语言 / 新建一个片段配置文件 全局:任意位置/文件下都可以使用
工作区:仅当前根目录下的文件有效
编辑配置文件 这里选择了html,在下面添加代码即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bU2dCKqH-1693248039087)(D:\Personal Releases\个人学习\programming\IDE\VScode\img\Snipaste_2023-08-28_23-35-02.png)]
在上面的示例中,我们定义了一个名为 Print to console 的代码片段,使用了 prefix 来触发代码片段,body 中包含了实际的代码块。$1 和 $2 是占位符,允许你在插入代码片段后依次跳转到它们进行编辑。
注意:
代码段每一行都需要使用双引号""包裹。
输入要在双引号中使用"",需要使用转义字符\"\"
如果是新建文件需要添加一行scope用于指定适用的语言,如下图注释中所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jDBFCQvM-1693248039088)(D:\Personal Releases\个人学习\programming\IDE\VScode\img\Snipaste_2023-08-29_01-44-06.png)]
代码片段在导入vue以后在script标签不能使用以v开头的前缀进行触发。 log正常触发
vbc则不能正常触发
在script标签外则可以正常触发
需求 1.web端H5 实现 上传图片 自动识别二维码内容
2.具体业务 比如 上传电影票 自动识别取票码或者其他的二维码上传(主要是为增加用户体验)
二维码(插件): 1.使用Npm安装qrcode-decoder
npm i qrcode-decoder --registry=https://registry.npm.taobao.org 2.创建一个方法 qrcode.js
// 引入qrcode-decoder, // import QrCode from 'qrcode-decoder' // 部分网友反应上面的引入,这个引入的是一个空对象,不能使用,已经给开发者提issues了,希望能尽快修复不能使用或报错,可以试试下面这种 import QrCode from '../../../../../node_modules/qrcode-decoder/dist/index'; // 传入file对象,返回promise export function getQrUrl(file) { //使用这个方法或者下面被注释的方法设置浏览器读取文件方式,chrome和ie有效,其他浏览器没测试 const URi = window.webkitURL.createObjectURL(file) || window.URL.createObjectURL(file) // if (window.webkitURL) { // URi = window.webkitURL.createObjectURL(file); // } else if (window.URL && window.URL.createObjectURL) { // URi = window.URL.createObjectURL(file); // } else { // URi = null; // } const url = URi // 初始化 const qr = new QrCode() // 解析二维码,返回promise return qr.
文章目录 详细介绍默认情况下,以局部坐标 详细介绍 在Unity中,Transform.Rotate() 是一个用于在物体上进行旋转的函数。它可以用来在局部坐标系下对物体进行旋转,也可以在世界坐标系下进行旋转。下面是关于 Transform.Rotate() 的详细介绍:
函数签名:
public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self); public void Rotate(float xAngle, float yAngle, float zAngle, Space relativeTo = Space.Self); 参数:
eulerAngles: 一个表示旋转欧拉角的 Vector3。这是旋转的角度,分别围绕物体的X、Y和Z轴。单位为度。xAngle, yAngle, zAngle: 分别表示围绕X、Y和Z轴旋转的角度。单位为度。relativeTo: 可选参数,指定旋转是基于局部坐标系(Space.Self)还是基于世界坐标系(Space.World)。默认为基于局部坐标系。 使用示例:
using UnityEngine; public class RotateObject : MonoBehaviour { public float rotationSpeed = 60.0f; // Update is called once per frame void Update() { // 在局部坐标系下绕Y轴旋转 transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime); // 在世界坐标系下绕X轴旋转 transform.
"ui"; **脚本源码:金猪脚本 **脚本作用:停止运行 *-*学习交流扣扣裙:741-318-378 ui.layout( <vertical> <button id="calc" align="center">文件选择</button> <text id="text_test" text="null"></text> </vertical> ); function pathToArray(dir) { current_dir_array = new Array(); current_dir_array = ["返回上级目录"]; files.listDir(dir.join("")).forEach((i) => { if (files.isDir(dir.join("") + i)) { current_dir_array.push(i + "/"); } else if (files.isFile(dir.join("") + i)) { current_dir_array.push(i); } }); return current_dir_array; } ui.calc.click(() => { var current_dir_array, dir = ["/", "sdcard", "/"]; //存储当前目录 function file_select(select_index) { switch (select_index) { case undefined: break; case -1: return; case 0: if (dir.
文章目录 总的介绍补充(用于摄像机跟随的场景) 总的介绍 transform.LookAt 是 Unity 引擎中 Transform 组件的一个方法,用于调整一个物体的旋转,使其朝向指定的位置。通常情况下,它被用来使一个物体(如摄像机、玩家角色等)朝向另一个物体、位置或方向。以下是关于 transform.LookAt 方法的详细介绍:
方法签名:
public void LookAt(Transform target, [Nullable] Vector3 worldUp = Vector3.up); public void LookAt(Vector3 worldPosition, [Nullable] Vector3 worldUp = Vector3.up); 参数说明:
target:要朝向的目标 Transform 组件。物体将会旋转以面向这个目标。注意,要是有重名的物体,那么就只能通过路径来查找 a/b/c/dworldPosition:一个在世界空间中的位置,物体将会旋转以面向这个位置。worldUp:一个可选的参数,指定旋转后的上方向。默认情况下是世界坐标中的正上方(Vector3.up)。 使用方法:
使用 LookAt 方法可以让一个物体旋转以面向给定的目标位置或方向。这在实现摄像机跟随玩家、敌人朝向玩家等场景中非常常见。 示例:
假设您有一个摄像机要始终朝向一个玩家角色:
using UnityEngine; public class CameraFollow : MonoBehaviour { public Transform playerTransform; // 玩家角色的Transform组件 private void Update() { // 让摄像机朝向玩家角色 transform.LookAt(playerTransform); } } 注意事项:
使用 LookAt 方法会直接影响物体的旋转,因此请谨慎使用。在某些情况下,您可能需要对目标位置或方向进行适当的调整,以确保物体朝向的效果是您预期的。默认情况下,物体的正前方(forward 方向)将指向目标位置或方向。如果您需要不同的朝向效果,可以通过调整 worldUp 参数来实现。LookAt 方法通常用于更新物体的旋转,因此最好在 Update 方法中调用,以确保每帧都进行更新。 总之,transform.
每次新项目都要重新配置一遍,有点麻烦,记录一下。
一、配置 ESLint 1.1 核心配置 执行 npm init @eslint/config 命令进行初始化,根据提示一路下一步即可,完成后会自动生成 eslintrc 文件并安装相关依赖。
1.2 React 编译模式配置 如果 React 使用的是新的编译模式(无需手动导入 React),需要在 extends 中加入 plugin:react/jsx-runtime。
{ "extends": [ "plugin:react/jsx-runtime", ], } 同时 tsconfig 文件中的 “jsx”: “react-jsx” 也是对应的新模式。
1.3 React 属性自动排序规则配置 安装依赖:
ni -D eslint-plugin-react 确保 eslint 配置文件中 extends 部分存在 plugin:react/recommended。
React 组件的属性可以借助 eslint 的能力来进行自动排序,在配置文件的 rule 中打开即可。
{ "rules": { "react/jsx-sort-props": [ "error", { "callbacksLast": true } ] } } 二、配置 Prettier 2.1 核心配置 # 安装 prettier ni -D prettier # 安装 prettier 整合 eslint 的库 ni -D eslint-plugin-prettier eslint-config-prettier 新建 .
**脚本源码:金猪脚本 **脚本作用:停止运行 *-*学习交流扣扣裙:741-318-378 var path = "/sdcard/脚本/悬浮按钮.js"; if (!files.exists(path)) { toast("脚本文件不存在: " + path); exit(); } var window = floaty.window( <frame> <button id="action" text="开始运行" w="90" h="40" bg="#77ffffff"/> </frame> ); window.exitOnClose(); var execution = null; window.action.click(() => { if (window.action.getText() == '开始运行') { threads.start(function() { //★功能开始 //★功能结束/ }); // execution = engines.execScriptFile(path); window.action.setText('停止运行'); } else { if (execution) { //execution.getEngine().forceStop(); } window.action.setText('开始运行'); exit(); //return; } }); window.action.longClick(() => { window.setAdjustEnabled(!window.isAdjustEnabled()); return true; }); setInterval(() => {}, 1000); 学习 交流扣扣裙:74-13-18-378
function deepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj); } if (obj instanceof Array) { const newArr = []; for (let i = 0; i < obj.length; i++) { newArr[i] = deepClone(obj[i]); } return newArr; } if (obj instanceof Object) { const newObj = {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = deepClone(obj[key]); } } return newObj; } }
1、在小城程序后台,点击设置->第三方设置->插件管理->添加插件。
搜索微信同声传译,添加到小程序即可。
2、基于uniapp开发的小程序,在uni项目中的的manifest.json文件中,找到 mp-weixin,添加plugins
"plugins": { // 引入插件 "WechatSI": { // 自定义的名字 "version": "0.3.5", // 引入插件的版本号 "provider": "wx069ba97219f66d99" // 引入插件的appID } } 3、添加成功之后,就可以在想要文字转语音的地方使用
示例:
1、先导入: let plugin = requirePlugin("WechatSI"); let manager = plugin.getRecordRecognitionManager(); 2、使用: plugin.textToSpeech({ lang: "zh_CN", tts: true, content: "",//需要转语音的文本 success: async function(res) { console.log("succ tts", res.filename) let music = null; music = uni.createInnerAudioContext(); //创建播放器对象 music.src = res.filename; music.volume = 1; music.playbackRate = 1.25; music.play(); //执行播放 music.onEnded(() => { //播放结束 music = null; }); }, fail: function(res) { // console.
若使用C++的FBX SDK开发,可以跳转下方官方手册目录查看说明!
1. 规律 起因是发现同样的fbx文件导入maya和max后,由于模型自身默认自带中文名,在Autodesk这两个软件中的名称不同(对比Maya2020(左)、3ds Max2022(右)。可能是默认编码方式原因)
中文命名在maya后台中,通过fbxRootNode.GetChild(0).GetName()得到的是unicode格式
u'\u5e73\u9762' # 平面
而实际上在场景中它的名字是一个string
’FBXASC229FBXASC185FBXASC179FBXASC233FBXASC157FBXASC162‘
规律十分简单:将unicode用UTF-8编码,得到的bytes(Python3)或string(Python2)的样式为:
b'\x e5\x b9\x b3\x e9\x 9d\x a2' 仔细观察可发现,e5、b9、b3、e9、9d、a2六个十六进制的数字转化为十进制分别为229、185、179、233、157、162。正好是每个FBXASC前缀后面带的三个数字。
2.问题 maya中用户无法将mesh名字改成中文或者带有其他“非法字符”的名字。但是如果mesh在导入之前就是中文名字,导入后就是这一长串FBXASC格式。(可能是因为maya2020默认编码方式为Ascii)这并不影响普通用户使用,因为它即使导出maya后,它存储的仍然是unicode格式,重新导入max后,还是能正常显示中文“平面”。
然而这可苦了开发者。理论上既然mesh的name保存的是unicode,其他对于命名的搜索,应该也是按unicode格式。但Autodesk剑走偏锋,例如像uv通道的获取方式就是按照FBXASC这个命名搜索的。如例:
fbxMeshName = ... DGpath = om.MDagPath.getAPathTo(om.MSelectionList().add(fbxMeshName).getDependNode(0)) 上例为fbx sdk官方文档中按照mesh名称(fbxMeshName)获取其uv通道的写法。若使用Unicode,在om.MSelectionList().add(fbxMeshName)时就丢失了查找对象,导致getDependNode(0)查找空的对象,报错。但是如果使用FBXASC...进行查找则能成功找到uv通道。
3.代码 了解了规律后,要做的事情非常简单。但是Python这个时候跳出来说:“让我再压榨你一点时间罢”。
原因在于Maya2020使用的是Python2,Maya直到2022版本才改用Python3,而3ds Max则是在2021版本兼容Python2 & Python3,2022版以后则为Python3。
Python3:
unicode_str = u'\u5e73\u9762' print(type(unicode_str)) hex_str = unicode_str.encode('UTF-8') print(hex_str,type(hex_str)) h = hex_str.hex() print(h,type(h)) # <class 'str'> # b'\xe5\xb9\xb3\xe9\x9d\xa2' <class 'bytes'> # e5b9b3e99da2 <class 'str'> Python3的hex()函数可以直接将bytes转换为string格式。往后的字符操作略去。
Python2:
unicode_str = u'\u5e73\u9762' print('------------------------') print(type(unicode_str)) h = unicode_str.
作为程序员每天开机都需要打开idea、数据库、xshell等开发软件,操作相对繁琐,于是想起了批处理来帮忙一键启动。
在桌面新建一个txt文件,改后缀名为.bat,并加上下面的代码。
代码一(推荐) cd /d C:\Users\PC\AppData\Local\Postman\app-5.5.2 start cmd /c start Postman choice /t 3 /d y cd /d C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.3\bin start cmd /c start idea64 choice /t 3 /d y cd /d C:\Users\PC\AppData\Local\MongoDBCompass start cmd /c start MongoDBCompass 代码执行流程
点击bat文件后先执行第一个语句进入到相应的目录。执行第二个命令:新打开一个cmd窗口,执行start Postman。因为使用的/c执行完关闭新打开的cmd窗口。执行第三个命令:等待3秒。执行第四个命令:进入到相应的目录。执行第五个命令:新打开一个cmd窗口,执行start idea64。因为使用的/c执行完关闭新打开的cmd窗口。以此类推…
代码结尾不加pause的原因是:执行.bat程序会打开一个窗口,执行完.bat程序后关闭当前窗口,因为不需要该窗口保留着,免得手动关闭。
注意:采用新打开一个cmd窗口执行程序,必须在后面写成start Postman,例如start cmd /c start Postman,如果没有start新打开的cmd窗口就算有/c也无法正常关闭。 代码二(起作用但多余的窗口关不了) cd /d C:\Users\PC\AppData\Local\Postman\app-5.5.2 start Postman choice /t 3 /d y cd /d C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.3\bin start idea64 choice /t 3 /d y cd /d C:\Users\PC\AppData\Local\MongoDBCompass start MongoDBCompass 代码执行流程
本插件主要用于分块传输绕WAF,不了解分块传输绕WAF的请阅读文末的文章。
项目地址
https://github.com/c0ny1/chunked-coding-converter
插件编译
mvn package 插件使用
相关文章
利用分块传输吊打所有WAF
在HTTP协议层面绕过WAF
编写Burp分块传输插件绕WAF
Java反序列化数据绕WAF之延时分块传输