Switch大气层系统升级

升级准备

  1. 大气层固件包
  2. Switch 固件包

升级过程

重启机器,进入 Hekate 界面 -> 工具 -> USB工具

点击 SD 卡,并连接 USB 到电脑

备份数据(emuMMC 和 Nintendo 之外的文件夹都挪到本地备份)

emuMMC是虚拟系统的数据
Nintendo是Nintendo Switch系统的数据(如果没有 Nindoo 就只保留 emuMMC)

删除上述备份过的数据(emuMMC 和 Nintendo 之外的文件夹)

复制大气层固件包和 Switch 固件包到 Switch 内存卡

红色边框内容保持原有不变。

绿色边框是 Switch 固件包,连带文件夹拷贝到根目录即可。

其他文件是大气层固件包的内容,拷贝到根目录即可。

弹出内存卡,进入大气层系统

查看当前版本

进入DayBreak

升级后查看版本

此时版本已更新,升级成功

报错

报错信息

报错原因

MacOS 复制升级文件到 Switch 内存卡时会导入隐藏文件

解决方法

连接USB,Mac上命令行运行 find /Volumes/Untitled/Firmware.18.1.0 -name ".*" -type f -delete

再次执行升级则会成功

2024.9.2东软面试记录

算法篇

(正常应该用Java做,Python代码比较短,直接写Python版本的)

题目一

input一个列表,内容是成绩,output一个列表,结果是对应的排名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# input: [90, 85, 90, 95]
# output: [2, 3, 2, 1]

data = [90, 85, 90, 95]

# 1. 排序并去重
sorted_unique_data = sorted(set(data), reverse=True)

# 2. 构造mapping
mapping = {value: rank + 1 for rank, value in enumerate(sorted_unique_data)}

# 3. 根据mapping构造结果
result = [mapping[score] for score in data]

print(result)
# [2, 3, 2, 1]

题目二

给定一个dto list,里面包含年级、成绩、姓名,求出每个年级的平均成绩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
dto_list = [
{"grade": 10, "score": 85, "name": "Alice"},
{"grade": 10, "score": 90, "name": "Bob"},
{"grade": 11, "score": 75, "name": "Charlie"},
{"grade": 11, "score": 80, "name": "David"},
{"grade": 12, "score": 95, "name": "Eve"}
]

grade_scores: dict[int, dict[str, int]] = {}
for dto in dto_list:
grade = dto["grade"]
score = dto["score"]
if grade not in grade_scores:
grade_scores[grade] = {"total_score": 0, "count": 0}
grade_scores[grade]["total_score"] += score
grade_scores[grade]["count"] += 1

for grade in grade_scores:
avg_score = grade_scores[grade]["total_score"] / grade_scores[grade]["count"]
print(f"年级 {grade} 的平均成绩是: {avg_score:.2f}")

SQL 篇

算法篇题目二的内容构成一张表,取出各年级平均成绩

1
2
3
4
5
6
7
SELECT 
grade,
AVG(score) AS average_score
FROM
students
GROUP BY
grade;

很简单,但是我忘记 SQL 语法了。。。没答上来,确实太久没写了😭

Java篇

题目一 值引用的问题。

基本数据类型会被改变,引用类型只会改变地址,不会改变对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
public static void main(String[] args) {
String s = "123";
int a = 1;
changeString(s);
changeInt(a);
System.out.println(s); // 123
System.out.println(a); // 1
}
public static void changeString(String tmp) {
tmp = "234";
}
public static void changeInt(int tmp) {
tmp = 3;
}
}

想要改变值只能 return 改变。

题目二 final 作用在类、方法、常量上分别有什么作用

答案

1
2
3
4
1. 修饰常量,值不可变 
2. 修饰对象,值可变,引用不变
3. 修饰方法,方法不可重写
4. 修饰类,无子类不可以被继承,更不可能被重写

之前确实没想过修饰对象的问题,记录一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Test {
void print() {
System.out.println("test");
}
}
public class Main {

public static void main(String[] args) {
final Test a = new Test();
a = new Test();
}
}
// Main.java:10: error: cannot assign a value to final variable a
// a = new Test();
// ^
// 1 error

测试篇

问题一

以 UT 为例,怎么保证测试分支全部覆盖?

1
利用 True/False 标注以及 Jacoco 等测试工具综合判断。

问题二

IT 的 Case 是自己写的吗?根据什么写的?

1
根据画面 シナリオ 编写。

问题三

A && B || C,这种条件下,如果 A 是 True、B 是 False、C 是 True,最终结果是什么?

1
2
True
先看 True && False 是 False,False || True 是True。

日语篇

提 QA 的时候,像客户反映问题。指定场景回答对应的日文。

问题一

A 条件和 B 条件的顺序应该反过来,并不是先判断 A 再判断 B。

1
2
答案来自 ChatGPT
A 条件と B 条件の順序は逆であるべきです。A を先に判断するのではなく、B を先に判断すべきです。

问题二

变量 X 只被使用过一次,应该放在方法内作为局部变量。

1
2
答案来自 ChatGPT
変数 X は一度しか使用されていないため、メソッド内のローカル変数として定義するべきです。

hexo配置超链接下载

在source文件夹下创建资源文件夹,比如download,然后将要下载的文件放入

文章里直接引用即可,例如[2020政府报告](/download/词云图/2020政府报告.zip)

OpenPyXL爬坑_第二弹

这是一段平平无奇的代码,用于获取冻结单元格

1
2
3
4
5
6
7
8
9
import shutil
import openpyxl

path = "/Users/xxx/Documents/tmp/openPyXLTest.xlsx"

wb = openpyxl.load_workbook(path)
sheet = wb["Sheet"]
print(sheet.freeze_panes)
wb.close()

文件内容如下

执行效果如下

看上去一切正常

但是当文件滚动条变更之后,如图

它的执行结果就变成了

没错,只要滚动条滚动了,取出来的值就是不正确的。如同源码展示的,它只会取 topLeftCell ,而这个值只会在加载的时候初始化,所以冻结的单元格行数,并不能准确取到。

已提交issue,期待回复

https://foss.heptapod.net/openpyxl/openpyxl/-/issues/2119

回复结果:

应该使用sheet.sheet_view.pane.ySplit获取冻结行数

输出结果 3.0

OpenPyXL爬坑

背景

接到需求,批量修改式样书的表纸页和履历页。本以为是简单的改动,但是深深踩了OpenPyXL的坑。

测试代码

1
2
3
4
5
6
7
8
9
10
11
import shutil
from openpyxl import load_workbook

path = "/Users/xxx/Documents/tmp/openPyXLTest.xlsx"
copyFile = "/Users/xxx/Documents/tmp/openPyXLTest2.xlsx"

shutil.copy(path, copyFile)

wb = load_workbook(copyFile)
wb.save(copyFile)
wb.close()

运行结果

图形问题解决

根据运行结果可以看出,只是简单的打开、关闭一个 excel 文件,会导致图片以及图形的丢失。

针对图形丢失在网上有很明确的说明,openpyxl 使用 Pillow 处理图片,所以需要安装 Pillow

pip install Pillow

安装 Pillow 之后,运行结果如下

图形依然丢失

去 OpenPyXL 仓库上翻了翻,这居然是一个陈年老bug https://foss.heptapod.net/openpyxl/openpyxl/-/issues/1268

彻底解决

使用 xlwings 库或者直接使用 VBA

xlwings: https://docs.xlwings.org/en/latest/quickstart.html#

xlwings示例

1
2
3
4
5
6
7
8
9
10
11
import shutil
import xlwings as xw

path = "/Users/xxx/Documents/tmp/openPyXLTest.xlsx"
copyFile = "/Users/xxx/Documents/tmp/openPyXLTest3.xlsx"

shutil.copy(path, copyFile)
wb = xw.Book(copyFile)
wb.save(copyFile)
wb.close()
print("done")

自定义RequestBodyAdvice实现接口打印

注意:只能接受@RequestBody类型的input参数。

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.demo.demos.web;

import org.springframework.web.bind.annotation.*;

@RestController
public class BasicController {

@RequestMapping("/hello")
@ResponseBody
public String hello(@RequestBody String name) {
return "Hello " + name;
}
}

Advice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.example.demo.demos.web;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;

@Slf4j
@RestControllerAdvice
public class RequestBodyAdviceImpl implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
RequestMapping requestMapping = parameter.getMethodAnnotation(RequestMapping.class);
log.info("url: " + Arrays.toString(requestMapping.value()));
log.info("method: " + parameter.getExecutable());
return inputMessage;
}

@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("param: " + body);
return body;
}

@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("body: body is Empty");
return body;
}
}

执行结果

退出他人Github仓库的方法

退出方法

  1. 点击右上角的头像
  2. 点击Settings
  3. 点击左边的Repositories
  4. 找到要退出的项目,点击右边的Leave

 

截图示例

Junit测试通过,MavenTest测试未通过

Run Unit Test和Maven test的区别

差异1:

在IDE中通过选中单元测试路径,点击右键选择run test和点击maven中的test是有区别的。在Maven执行测试的过程中,是不允许测试cases访问其他项目的测试类和其他项目的resources下文件的。也就是说,在a/src/test/java下的测试用例,是不能引用b/src/test/java中的类的,同时也不允许访问b/src/test/resources下的资源的。但是在IDE中的Run Unit Test几乎是没有这样的限制的。

差异2:

Maven强制要求src/test/java下不能存在resource的文件,必须放到src/test/reources文件夹下,但是IDE却很少有对应的约束。

解决方法

在maven插件配置:(surefire2.14以下版本)

1
2
3
4
5
6
7
8
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<forkMode>always</forkMode>
</configuration>
</plugin>

重点加入configureation的配置部分

在maven插件配置:(surefire2.14及其以上版本)

1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<reuseForks>false</reuseForks>
<forkCount>1</forkCount>
</configuration>
</plugin>

在2.14以上的版本中,forkMode配置项已经废弃了。

Java流内容替换

业务上有需求,需要将日语外字替换成指定字符,利用FilterInputStream实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class App {
public static void main(String[] args) throws Exception {
String str = "abc";
InputStream stream = new ByteArrayInputStream(str.getBytes());
// abc -> acc
replaceString(stream).stream().forEach( elt -> System.out.println(elt));
}

private static List<String> replaceString(InputStream inputStream) throws UnsupportedEncodingException {
List<String> result = new ArrayList<>();
FilterInputStream filterInputStream = new FilterInputStream(inputStream) {
@Override
public int read(byte[] b, int off, int len) throws IOException {
int bytesRead = super.read(b, off, len);
if (bytesRead != -1) {
for (int i = off; i < off + bytesRead - 1; i++) {
// ab -> ac
if (b[i] == (byte) 0x61 && b[i + 1] == (byte) 0x62) {
b[i] = (byte) 0x61;
b[i + 1] = (byte) 0x63;
}
}
}
return bytesRead;
}
};

BufferedReader br = new BufferedReader(new InputStreamReader(filterInputStream, "UTF8"));
br.lines().forEach( elt -> {
result.add(elt);
});
return result;
}
}

java外字处理爬坑

背景

日语内外字不在常规Unicode编码集内,需要手动更换成编码集内的文字。

坑点

外字在本地文档/服务器文档编码集符合文档提供的规则,但是在Stream流内会自动解析成\\uFFFD\\uxxxx。例如SJIS编码下F141的文字,在UTF8下编码为E08D,但是进入Stream流后变成了\\uFFFD\\u0041,所以要在代码内实际确认一下对应的编码。同时因为外字转成了\\uFFFD\\uxxxx,所以位数变成了2位,而且外字变换常规字符后可能会由一个字符变成多个字符,对应Byte的切分要注意位数变更。

相关代码段

打印字符串unicode编码

1
2
3
4
5
6
7
public static void printUnicode(String str) {
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
System.out.printf(String.format("\\u%04X ", (int) c));
}
System.out.println();
}

变换外字

1
2
3
4
5
6
7
8
9
10
Map<String, String> convertMap = new HashMap<>(); 
convertMap.put("\\uFFFD\\u0041", "さい");
convertMap.put("\\uFFFD\\u0042", "そね");

for (Map.Entry<String, String> entry : convertMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// repaceAll支持直接变换Unicode
String info = info.replaceAll(key, value);
}

时间戳四舍五入

因为项目原因,api返回的结果是6位毫秒(2023-04-12 20:56:31.589183),而存储到db然后导出是3位数毫秒(2023-04-12 20:56:31.589)。

这里牵扯到四舍五入,所以不能单纯截取,需要加500毫秒。

1
2
3
4
5
6
from datetime import datetime, timedelta
time_str = "2023-04-07 18:14:45.589183"
dt = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S.%f")
new_dt = dt + timedelta(microseconds=500)
new_time_str = new_dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
print(new_time_str)