feat: refactor screenshot capture implementation and update UI reload labels

This commit is contained in:
Lyz Coote
2026-02-18 16:58:48 +01:00
parent af7d8a0792
commit 9b9e01b107
6 changed files with 52 additions and 161 deletions

View File

@@ -8,32 +8,18 @@ import (
"image/png" "image/png"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/kbinani/screenshot"
) )
var ( var (
user32 = syscall.NewLazyDLL("user32.dll") user32 = syscall.NewLazyDLL("user32.dll")
gdi32 = syscall.NewLazyDLL("gdi32.dll")
dwmapi = syscall.NewLazyDLL("dwmapi.dll") dwmapi = syscall.NewLazyDLL("dwmapi.dll")
// user32 functions // user32 functions
getForegroundWindow = user32.NewProc("GetForegroundWindow") getForegroundWindow = user32.NewProc("GetForegroundWindow")
getWindowRect = user32.NewProc("GetWindowRect") getWindowRect = user32.NewProc("GetWindowRect")
getClientRect = user32.NewProc("GetClientRect")
getDC = user32.NewProc("GetDC")
releaseDC = user32.NewProc("ReleaseDC")
findWindowW = user32.NewProc("FindWindowW") findWindowW = user32.NewProc("FindWindowW")
getWindowDC = user32.NewProc("GetWindowDC")
printWindow = user32.NewProc("PrintWindow")
clientToScreen = user32.NewProc("ClientToScreen")
// gdi32 functions
createCompatibleDC = gdi32.NewProc("CreateCompatibleDC")
createCompatibleBitmap = gdi32.NewProc("CreateCompatibleBitmap")
selectObject = gdi32.NewProc("SelectObject")
bitBlt = gdi32.NewProc("BitBlt")
deleteDC = gdi32.NewProc("DeleteDC")
deleteObject = gdi32.NewProc("DeleteObject")
getDIBits = gdi32.NewProc("GetDIBits")
// dwmapi functions // dwmapi functions
dwmGetWindowAttribute = dwmapi.NewProc("DwmGetWindowAttribute") dwmGetWindowAttribute = dwmapi.NewProc("DwmGetWindowAttribute")
@@ -47,39 +33,7 @@ type RECT struct {
Bottom int32 Bottom int32
} }
// POINT structure for Windows API
type POINT struct {
X int32
Y int32
}
// BITMAPINFOHEADER structure
type BITMAPINFOHEADER struct {
BiSize uint32
BiWidth int32
BiHeight int32
BiPlanes uint16
BiBitCount uint16
BiCompression uint32
BiSizeImage uint32
BiXPelsPerMeter int32
BiYPelsPerMeter int32
BiClrUsed uint32
BiClrImportant uint32
}
// BITMAPINFO structure
type BITMAPINFO struct {
BmiHeader BITMAPINFOHEADER
BmiColors [1]uint32
}
const ( const (
SRCCOPY = 0x00CC0020
DIB_RGB_COLORS = 0
BI_RGB = 0
PW_CLIENTONLY = 1
PW_RENDERFULLCONTENT = 2
DWMWA_EXTENDED_FRAME_BOUNDS = 9 DWMWA_EXTENDED_FRAME_BOUNDS = 9
) )
@@ -113,82 +67,10 @@ func CaptureWindowByHandle(hwnd uintptr) (*image.RGBA, error) {
return nil, fmt.Errorf("invalid window dimensions: %dx%d", width, height) return nil, fmt.Errorf("invalid window dimensions: %dx%d", width, height)
} }
// Get window DC // Using kbinani/screenshot to capture the rectangle on screen
hdcWindow, _, err := getWindowDC.Call(hwnd) img, err := screenshot.CaptureRect(image.Rect(int(rect.Left), int(rect.Top), int(rect.Right), int(rect.Bottom)))
if hdcWindow == 0 { if err != nil {
return nil, fmt.Errorf("GetWindowDC failed: %v", err) return nil, fmt.Errorf("screenshot.CaptureRect failed: %v", err)
}
defer releaseDC.Call(hwnd, hdcWindow)
// Create compatible DC
hdcMem, _, err := createCompatibleDC.Call(hdcWindow)
if hdcMem == 0 {
return nil, fmt.Errorf("CreateCompatibleDC failed: %v", err)
}
defer deleteDC.Call(hdcMem)
// Create compatible bitmap
hBitmap, _, err := createCompatibleBitmap.Call(hdcWindow, uintptr(width), uintptr(height))
if hBitmap == 0 {
return nil, fmt.Errorf("CreateCompatibleBitmap failed: %v", err)
}
defer deleteObject.Call(hBitmap)
// Select bitmap into DC
oldBitmap, _, _ := selectObject.Call(hdcMem, hBitmap)
defer selectObject.Call(hdcMem, oldBitmap)
// Try PrintWindow first (works better with layered/composited windows)
ret, _, _ = printWindow.Call(hwnd, hdcMem, PW_RENDERFULLCONTENT)
if ret == 0 {
// Fallback to BitBlt
ret, _, err = bitBlt.Call(
hdcMem, 0, 0, uintptr(width), uintptr(height),
hdcWindow, 0, 0,
SRCCOPY,
)
if ret == 0 {
return nil, fmt.Errorf("BitBlt failed: %v", err)
}
}
// Prepare BITMAPINFO
bmi := BITMAPINFO{
BmiHeader: BITMAPINFOHEADER{
BiSize: uint32(unsafe.Sizeof(BITMAPINFOHEADER{})),
BiWidth: int32(width),
BiHeight: -int32(height), // Negative for top-down DIB
BiPlanes: 1,
BiBitCount: 32,
BiCompression: BI_RGB,
},
}
// Allocate buffer for pixel data
pixelDataSize := width * height * 4
pixelData := make([]byte, pixelDataSize)
// Get the bitmap bits
ret, _, err = getDIBits.Call(
hdcMem,
hBitmap,
0,
uintptr(height),
uintptr(unsafe.Pointer(&pixelData[0])),
uintptr(unsafe.Pointer(&bmi)),
DIB_RGB_COLORS,
)
if ret == 0 {
return nil, fmt.Errorf("GetDIBits failed: %v", err)
}
// Convert BGRA to RGBA
img := image.NewRGBA(image.Rect(0, 0, width, height))
for i := 0; i < len(pixelData); i += 4 {
img.Pix[i+0] = pixelData[i+2] // R <- B
img.Pix[i+1] = pixelData[i+1] // G <- G
img.Pix[i+2] = pixelData[i+0] // B <- R
img.Pix[i+3] = pixelData[i+3] // A <- A
} }
return img, nil return img, nil

View File

@@ -43,7 +43,8 @@
"settings_danger_reset_button": "Reset data", "settings_danger_reset_button": "Reset data",
"settings_danger_reload_ui_label": "Reload UI", "settings_danger_reload_ui_label": "Reload UI",
"settings_danger_reload_app_label": "Reload App", "settings_danger_reload_app_label": "Reload App",
"settings_danger_reload_hint": "Reloads the application interface. Useful if the UI becomes unresponsive.", "settings_danger_reload_all_label": "Reload UI/App",
"settings_danger_reload_hint": "Reloads the application interface. Useful if it becomes unresponsive.",
"settings_danger_reload_button_ui": "Reload UI", "settings_danger_reload_button_ui": "Reload UI",
"settings_danger_reload_button_app": "Reload app", "settings_danger_reload_button_app": "Reload app",
"settings_danger_reset_dialog_title": "Are you absolutely sure?", "settings_danger_reset_dialog_title": "Are you absolutely sure?",

View File

@@ -42,8 +42,9 @@
"settings_danger_reset_hint": "Questo cancellerà tutte le tue impostazioni e riporterà l'app allo stato predefinito.", "settings_danger_reset_hint": "Questo cancellerà tutte le tue impostazioni e riporterà l'app allo stato predefinito.",
"settings_danger_reset_button": "Reimposta dati", "settings_danger_reset_button": "Reimposta dati",
"settings_danger_reload_ui_label": "Ricarica UI", "settings_danger_reload_ui_label": "Ricarica UI",
"settings_danger_reload__app_label": "Ricarica App", "settings_danger_reload_app_label": "Ricarica App",
"settings_danger_reload_hint": "Ricarica l'interfaccia dell'applicazione. Utile se l'UI non risponde.", "settings_danger_reload_all_label": "Ricarica UI/App",
"settings_danger_reload_hint": "Ricarica l'interfaccia dell'applicazione. Utile se non risponde.",
"settings_danger_reload_button_ui": "Ricarica UI", "settings_danger_reload_button_ui": "Ricarica UI",
"settings_danger_reload_button_app": "Ricarica app", "settings_danger_reload_button_app": "Ricarica app",
"settings_danger_reset_dialog_title": "Sei assolutamente sicuro?", "settings_danger_reset_dialog_title": "Sei assolutamente sicuro?",

View File

@@ -195,10 +195,14 @@
}); });
// Sync update checker setting to backend config.ini // Sync update checker setting to backend config.ini
let previousUpdateCheckerEnabled = form.enableUpdateChecker; let previousUpdateCheckerEnabled = $state<boolean | undefined>(undefined);
$effect(() => { $effect(() => {
(async () => { (async () => {
if (!browser) return; if (!browser) return;
if (previousUpdateCheckerEnabled === undefined) {
previousUpdateCheckerEnabled = form.enableUpdateChecker;
return;
}
if (form.enableUpdateChecker !== previousUpdateCheckerEnabled) { if (form.enableUpdateChecker !== previousUpdateCheckerEnabled) {
try { try {
await SetUpdateCheckerEnabled(form.enableUpdateChecker ?? true); await SetUpdateCheckerEnabled(form.enableUpdateChecker ?? true);
@@ -354,7 +358,7 @@
}); });
</script> </script>
<div class="min-h-[calc(100vh-1rem)] bg-gradient-to-b from-background to-muted/30"> <div class="min-h-[calc(100vh-1rem)] bg-linear-to-b from-background to-muted/30">
<div <div
class="mx-auto flex max-w-3xl flex-col gap-4 px-4 py-6 sm:px-6 sm:py-10 opacity-80" class="mx-auto flex max-w-3xl flex-col gap-4 px-4 py-6 sm:px-6 sm:py-10 opacity-80"
> >
@@ -868,12 +872,13 @@
class="flex items-center justify-between gap-4 rounded-lg border border-destructive/30 bg-card p-4" class="flex items-center justify-between gap-4 rounded-lg border border-destructive/30 bg-card p-4"
> >
<div class="space-y-1"> <div class="space-y-1">
<Label class="text-sm">{m.settings_danger_reload_ui_label()}</Label> <Label class="text-sm">{m.settings_danger_reload_all_label()}</Label>
<div class="text-sm text-muted-foreground"> <div class="text-sm text-muted-foreground">
{m.settings_danger_reload_hint()} {m.settings_danger_reload_hint()}
</div> </div>
</div> </div>
<div class="flex items-center gap-2">
<a <a
data-sveltekit-reload data-sveltekit-reload
href="/" href="/"
@@ -882,18 +887,6 @@
> >
{m.settings_danger_reload_button_ui()} {m.settings_danger_reload_button_ui()}
</a> </a>
</div>
<div
class="flex items-center justify-between gap-4 rounded-lg border border-destructive/30 bg-card p-4"
>
<div class="space-y-1">
<Label class="text-sm">{m.settings_danger_reload_app_label()}</Label>
<div class="text-sm text-muted-foreground">
{m.settings_danger_reload_hint()}
</div>
</div>
<Button <Button
class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`} class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`}
onclick={restartEntireApp} onclick={restartEntireApp}
@@ -902,6 +895,7 @@
{m.settings_danger_reload_button_app()} {m.settings_danger_reload_button_app()}
</Button> </Button>
</div> </div>
</div>
<Separator /> <Separator />

4
go.mod
View File

@@ -4,6 +4,7 @@ go 1.24.4
require ( require (
github.com/jaypipes/ghw v0.21.2 github.com/jaypipes/ghw v0.21.2
github.com/kbinani/screenshot v0.0.0-20250624051815-089614a94018
github.com/teamwork/tnef v0.0.0-20200108124832-7deabccfdb32 github.com/teamwork/tnef v0.0.0-20200108124832-7deabccfdb32
github.com/wailsapp/wails/v2 v2.11.0 github.com/wailsapp/wails/v2 v2.11.0
golang.org/x/sys v0.40.0 golang.org/x/sys v0.40.0
@@ -13,18 +14,21 @@ require (
require ( require (
github.com/bep/debounce v1.2.1 // indirect github.com/bep/debounce v1.2.1 // indirect
github.com/gen2brain/shm v0.1.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect github.com/gorilla/websocket v1.5.3 // indirect
github.com/jaypipes/pcidb v1.1.1 // indirect github.com/jaypipes/pcidb v1.1.1 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/jezek/xgb v1.1.1 // indirect
github.com/labstack/echo/v4 v4.13.3 // indirect github.com/labstack/echo/v4 v4.13.3 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
github.com/leaanthony/gosod v1.0.4 // indirect github.com/leaanthony/gosod v1.0.4 // indirect
github.com/leaanthony/slicer v1.6.0 // indirect github.com/leaanthony/slicer v1.6.0 // indirect
github.com/leaanthony/u v1.1.1 // indirect github.com/leaanthony/u v1.1.1 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect

9
go.sum
View File

@@ -4,6 +4,8 @@ github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3IS
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gen2brain/shm v0.1.0 h1:MwPeg+zJQXN0RM9o+HqaSFypNoNEcNpeoGp0BTSx2YY=
github.com/gen2brain/shm v0.1.0/go.mod h1:UgIcVtvmOu+aCJpqJX7GOtiN7X2ct+TKLg4RTxwPIUA=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
@@ -20,6 +22,10 @@ github.com/jaypipes/pcidb v1.1.1/go.mod h1:x27LT2krrUgjf875KxQXKB0Ha/YXLdZRVmw6h
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/kbinani/screenshot v0.0.0-20250624051815-089614a94018 h1:NQYgMY188uWrS+E/7xMVpydsI48PMHcc7SfR4OxkDF4=
github.com/kbinani/screenshot v0.0.0-20250624051815-089614a94018/go.mod h1:Pmpz2BLf55auQZ67u3rvyI2vAQvNetkK/4zYUmpauZQ=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
@@ -36,6 +42,8 @@ github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
@@ -95,6 +103,7 @@ golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=