Dec 16

Mac 关闭内置显示器 不指定

felix021 @ 2023-12-16 20:34 [IT » 硬件] 评论(0) , 引用(0) , 阅读(2123) | Via 本站原创
// 日常吐槽莎币苹果。

MacOS 有很多很蠢的地方,比如没有快捷键可以让窗口在屏幕间移动;比如不能右键直接创建空文件;比如右键菜单有「复制」和「拷贝」两个选项;比如会莫名其妙出现左右声道不平衡的 bug 并且长期未修复;

再比如,不能在外接显示屏的情况下关闭内屏。

当然也不是完全不能,网友也有一些解决方案:

1. 合上屏幕当主机用,自然就息屏了。不过我需要用 mac 的键盘、触摸板和 TouchID 解锁。过。

2. 随身携带磁铁,欺骗 macOS 屏幕已经关闭。这可能是种行为艺术,可惜我不是艺术家。过。

3. SwitchResX,试了下,确实可以把内屏关闭,只不过拔了外显内屏还是关着的,折腾了几下甚至 mac 都不能识别外显了,重启才解决。卸。

4. 在「系统设置 -> 显示」里,将背光拉到 0;不能直接用 Fn 调节屏幕亮度,因为会把外接屏亮度一起调低(莎币值+1);而且每次接上外显或 wakeup 时,都要重新设置。过……吧?

好在作为一名码农,可以想一些自动化的方式来把方案 4 利用起来。

首先是用 brew install brightness (update: M3 Macbook can not use this. try Lunar, details below),可以用 `brightness -d 1 0` 把 display 1 的亮度调到 0 (注意把主屏设置为外接屏,且把内屏设置为拷贝外屏,这样内屏的编号就是 1,外显是 0)。

其次是有一个叫 hammerspoon 的软件(https://www.hammerspoon.org/),可以在 unlock 的时候自动执行一个 lua 脚本。

把下面这个 lua 脚本存为 ~/.hammerspoon/init.lua

-- init.lua 
    local log = hs.logger.new("", "info")

    local function ok2str(ok)
        if ok then return "ok" else return "fail" end
    end

    hs.caffeinate.watcher.new(function(event)
        local eventName = hs.caffeinate.watcher[event]
        log.f("got caffeinate event:%s (id:%d)", eventName, event)
   
        local script

        if event == hs.caffeinate.watcher.screensDidLock then     
            script = "${HOME}/.lock"
        elseif event == hs.caffeinate.watcher.screensDidUnlock then
            script = "${HOME}/.unlock"
        else       
            log.f("ignored event:%s (id:%d)", eventName, event)
            return
        end
   
        local ok, st, n = os.execute(script)
        log.f("exec:%s -> %s, %s, %d", script, ok2str(ok), st, n)
    end
    ):start()



然后再 touch ~/.unlock && chmod +x ~/.unlock,内容为:

#!/bin/bash

export PATH=$PATH:/usr/local/bin/

brightness -d 1 0
sleep 5 && brightness -d 1 0


sleep 5 是因为从睡眠状态恢复时,识别外屏会比较慢,可按需调整 sleep 时长。


如果你看到这里,说明你也需要注意日常用电脑的姿势了,避免头颈前倾。

(完)。

update @ 2023-12-12

实际体验下来还有一些问题,例如去倒杯水,锁屏但没有睡眠,解锁后就不会息屏。

最好用的方案往往只需要最简单的工具:crontab。

引用

MAILTO=""

* * * * * /Users/bytedance/bin/TurnOffScreen.sh
* * * * * sleep 15 && /Users/bytedance/bin/TurnOffScreen.sh
* * * * * sleep 30 && /Users/bytedance/bin/TurnOffScreen.sh
* * * * * sleep 45 && /Users/bytedance/bin/TurnOffScreen.sh



update @ 2024-01-26

brightness seems to be not working on M3 Macbooks, so I switched to lunar:

1. Download and install lunar
2. Run in terminal: /Applications/Lunar.app/Contents/MacOS/Lunar install-cli
3. Update the TurnOffScreen.sh to be (remember to replace with your monitor model or serial id in the pattern):
#!/bin/bash

pattern='S2721QS'

if ~/.local/bin/lunar displays | grep $pattern; then
    ~/.local/bin/lunar displays "Built-in" brightness 0
fi
Dec 26
先实现一个纯 Go 的版本:

// main.go
package main

import "fmt"

func fac(n uint) uint {
  var result uint = 1
  for n > 0 {
    result = result * n
    n -= 1
  }
  return result
}

func main() {
  fmt.Println(fac(10))
}


修改上述 fac 方法,只保留函数定义(即声明存在该函数,由汇编代码实现):
func fac(n uint) uint


新增 fac.s
TEXT ·fac(SB), $0-8
    MOVQ n+0(FP), CX
    MOVQ $1, DX
LOOP:
    IMULQ CX, DX
    DECQ CX
    JNZ LOOP
    MOVQ DX, result+8(FP)
    RET


编译运行:
引用

$ go run .
3628800


说明:

1. TEXT ·fac(SB), $0-8
- TEXT 表示这个方法在 TEXT 段中
- · 是Unicode的「中点」(中文输入法,1左边的按键),前面省略了包名,表示这是 main 包的 fac 函数
- SB 是 stack base pointer,Go ASM 中的「伪寄存器」(不是硬件寄存器),大致等同于程序的起始地址
- $0-8:0 表示这个函数没有局部变量,8 表示返回值占用8个字节

2. MOVQ n+0(FP), CX
- MOVQ 的 Q 表示 8 个字节
- n+0(FP) 表示变量 n 在 FP(Frame Pointer,伪寄存器,表示这个函数的栈帧起始位置) + 0 的位置(即第一个参数)。注意这个写法形式上是必须得,但是变量名n没有实际意义,只是用来注记。
- CX 即 x86/x86_64 的 CX(16bit),ECX(32bit),RCX(64bit) 寄存器,具体多长取决于前面的指令(MOVQ是64bit)
- 这句的意思是把第一个参数的值写入 RCX

3. MOVQ $1, DX
- $1:$开头的是立即数
- 这句的意思是给 RDX 赋值为 1

4. IMULQ CX, DX
- DX = DX * CX

5. DECQ CX
- CX = CX - 1

6. JNZ LOOP
- JNZ: Jump if Not Zero
- 当 CX 不等于 0 时跳转到 LOOP

7. MOVQ DX, result+8(FP)
- 将 RDX 的值写入到 FP+8 的位置。

8. RET
- 返回到调用方。


p.s. 这个汇编版本的实现并不等同于原来 Go 版本,只是这样写会更简单(只要一个jump)。

参考:
- Golang ASM 简明教程:https://jiajunhuang.com/articles/2020_04_22-go_asm.md.html
- A Quick Guide to Go's Assembler:https://go.dev/doc/asm
May 23

xdelta: 二进制文件patch 不指定

felix021 @ 2022-5-23 17:16 [IT » 软件] 评论(0) , 引用(0) , 阅读(2312) | Via 本站原创
手头项目每次 mvn package 得到的 jar 是 160M 左右,有时候需要替换到服务器上,上传时间较长。

Google 搜到这么个项目:xdelta

https://github.com/jmacd/xdelta-gpl/releases

可以对二进制文件做 patch,对 jar 的效果还挺好,两个相近的版本做 diff,生成的 patch 文件只有 500KB 左右。


用法:
引用
# 生成 patch
xdelta.exe -es v1.jar v2.jar v1-v2.patch

# 应用 patch
xdelta.exe -ds v1.jar v1-v2.patch v2.jar


有个小问题是,服务器是 centos 7 ,yum install 的是 xdelta 3.0.7 不支持最新的 lzma 压缩,因此生成 patch 的时候需要加上 -S djw 参数,指定为 djw 编码:

引用
xdelta.exe -S djw -es v1.jar v2.jar v1-v2.patch
May 16

Swagger API: 上传文件 不指定

felix021 @ 2022-5-16 23:11 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(2692) | Via 本站原创
踩了个小坑,记录一下。

swagger api 定义:
引用

/upload:
  post:
    tags:
      - "tag"
    summary: "summary"
    operationId: uploadFile
    consumes:
      - multipart/form-data
    parameters:
      - name: "data"
        in: "formData"
        type: "file"
        required: true
        description: "file content"
    responses:
      200:
        description: "success"
        schema:
          $ref: "#/definitions/UploadFileResponse"


生成的 API:
    @RequestMapping(value = {"/sf/express/upload_channel_file" }, produces = { "application/json" }, consumes = { "multipart/form-data" }, method = RequestMethod.POST)
    default ResponseEntity<UploadFileResponse> uploadFile(@ApiParam(value = "file detail") @Valid @RequestPart("file") MultipartFile data) {
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }


直接用这个 API 请求会报错:
swagger Required request part 'file' is not present

细看发现是 swagger 生成的是 @RequestPart("file") 而不是 @RequestPart("data"),需要手动修改过来才能正确读取到文件字段。
Feb 14

Java: NPE和单测覆盖率 不指定

felix021 @ 2022-2-14 17:50 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(2033) | Via 本站原创
切到新语言就是不断地踩坑呀。

手头有一个函数,输入一个 itemList,统计不同类型的个数,核心代码如下:

int xCount = 0, yCount = 0;
switch(typeParser.parse(item)) {
  case X:
    xCount++;
    break;
  case Y:
    yCount++;
    break;
  default:
    log.error("unknown type");
    break;
}


其他 typeParser 在遇到异常数据时会返回 null。

重构的时候,稳妥起见为它写了个单测,结果就在上述代码的第二行 NPE 了。

debug 时确认了 typeParser 和 item 都不是 null,猜测是 switch 不能处理 null ,但不熟悉 java 语法,搜了一下,果然如此。

由于 case 数量不多,就暂且改成了 if ... else if ... else 的结构。

由此可见,单测对于代码的覆盖率确实是很有帮助。
Jan 26
又遇到一个灵异的 intellij idea 问题。

背景:在项目 P 的同一个 Module M 下面, PKG P1 需要 import PKG P2 下面的 C1 和 C2 两个 class。

现象:import C1 成功,但是import C2失败;然而通过 mvn clean install 是可以正常完成编译的。

点击在新窗口中浏览此图片

删除 project 下的 .idea 目录重新 import 并没有解决这个问题。

在另一个同学的电脑上尝试,报的错竟然不一样,是在 C2 这个 class 下无法 import 另一个 class C3,但同样可以通过 mvn 命令行完成编译。

通过 Google 搜到 StackOverflow 的这个 thread:

  https://stackoverflow.com/a/66167190/802910

解决方案很简单:删掉 idea 的cache 目录,让它重建就好了。

在 windows 下,这个目录位于 %LOCALAPPDATA%\JetBrains\IdeaIC2021.2\caches (注意替换为自己版本号)

在 mac 下,目录应该是 ~/Library/Caches/JetBrains/IdeaIC2021.2

似乎 IDEA 本身也有清空 cache 的功能(File -> Invalidate Caches...),下次遇到再验证一下。

Aug 11
# 现象

手头有一个比较大的maven project,拆成了十几个module,如果我要在 Intellij IDEA 跑个单测什么的,就会报错,各种依赖找不到,即使 pom.xml 里是明明白白写着:

点击在新窗口中浏览此图片

依然无法识别,连 lombok 和 junit 都不行:

点击在新窗口中浏览此图片

尽管 idea 很好心地给了帮助 "Add JUnit4 to classpath",点击后也只是在 pom.xml 里再添加一次,并没有什么卵用。

这个问题有个很灵异的现象是,每次用 "mvn clean install" 整体编译的时候是正常的,但是在 idea 跑 test case,或启动某个 main,就会报错。


# 排查

打开 Project Structure 可以看到,这个 module 的 dependency 全是空的:

点击在新窗口中浏览此图片

说明 pom.xml 文件应该是有坑。

查看 maven reload 的output,发现是了问题是某个dependency没有指定版本号

引用
[ERROR] org.apache.maven.artifact.InvalidArtifactRTException: For artifact {org.apache.flink:flink-streaming-java_2.11:null:jar}: The version cannot be empty.


参考其他 module 指定正确的版本号:

引用
<version>1.10.1</version>


再重新reload,问题就解决了。


# 回顾

再回头想想前面提到的灵异现象,从结果倒推,大概是因为把项目作为整体编译的时候,同一个package只能有一个版本,即使模块A没有指定版本,只要模块B有指定,就能正常引用。

之前还遇到过另一个现象,整体编译没问题,但是在 iDEA 里跑单测的时候,会发现引用了旧版本,其实也是同样的问题了。


完。
Aug 1
~/.bashrc 中加上以下内容即可:
引用
export LANG=zh_CN.UTF-8


如果 git 命令(如 git diff)下仍有代码,可以再增加
引用
export LESSCHARSET=UTF-8


如果 vim 下依然有乱码,在 .vimrc 中增加
引用
set encoding=utf-8
set termencoding=utf-8


--

参考资料:
- Mac下使用SecureCRT时中文乱码问题解决
  https://blog.csdn.net/BabyFish13/article/details/101463105

- 记一次secureCRT中文乱码解决过程
  https://yunchangyue.github.io/blog/tools/2018/11/16/securecrt/
分页: 1/99 第一页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]