diff --git a/v3/.gitignore b/v3/.gitignore
index cc164c024..78e5d307a 100644
--- a/v3/.gitignore
+++ b/v3/.gitignore
@@ -6,3 +6,4 @@ cmd/wails/wails
/examples/menu/menu
/examples/clipboard/clipboard
/examples/plain/plain
+/website/venv/
diff --git a/v3/STATUS.md b/v3/STATUS.md
new file mode 100644
index 000000000..e5eeaaf4b
--- /dev/null
+++ b/v3/STATUS.md
@@ -0,0 +1,315 @@
+# Status
+
+Status of features in v3. Incomplete - please add as you see fit.
+
+## Application
+
+Application interface methods
+
+| Method | Windows | Linux | Mac | Notes |
+|---------------------------------------------------------------|---------|-------|-----|-------|
+| run() error | | | Y | |
+| destroy() | | | Y | |
+| setApplicationMenu(menu *Menu) | | | Y | |
+| name() string | | | Y | |
+| getCurrentWindowID() uint | | | Y | |
+| showAboutDialog(name string, description string, icon []byte) | | | Y | |
+| setIcon(icon []byte) | | | Y | |
+| on(id uint) | | | Y | |
+| dispatchOnMainThread(fn func()) | Y | | Y | |
+| hide() | Y | | Y | |
+| show() | Y | | Y | |
+| getPrimaryScreen() (*Screen, error) | | | Y | |
+| getScreens() ([]*Screen, error) | | | Y | |
+
+## Webview Window
+
+Webview Window Interface Methods
+
+| Method | Windows | Linux | Mac | Notes |
+|----------------------------------------------------|---------|-------|-----|------------------------------------------|
+| center() | Y | | Y | |
+| close() | | | Y | |
+| destroy() | | | Y | |
+| execJS(js string) | | | Y | |
+| focus() | Y | | Y | |
+| forceReload() | | | Y | |
+| fullscreen() | Y | | Y | |
+| getScreen() (*Screen, error) | | | Y | |
+| getZoom() float64 | | | Y | |
+| height() int | Y | | Y | |
+| hide() | Y | | Y | |
+| isFullscreen() bool | Y | | Y | |
+| isMaximised() bool | Y | | Y | |
+| isMinimised() bool | Y | | Y | |
+| maximise() | Y | | Y | |
+| minimise() | Y | | Y | |
+| nativeWindowHandle() (uintptr, error) | Y | | Y | |
+| on(eventID uint) | | | Y | |
+| openContextMenu(menu *Menu, data *ContextMenuData) | | | Y | |
+| position() (int, int) | Y | | Y | |
+| reload() | | | Y | |
+| run() | Y | | Y | |
+| setAlwaysOnTop(alwaysOnTop bool) | Y | | Y | |
+| setBackgroundColour(color RGBA) | Y | | Y | |
+| setFrameless(bool) | | | Y | |
+| setFullscreenButtonEnabled(enabled bool) | - | | Y | There is no fullscreen button in Windows |
+| setHTML(html string) | | | Y | |
+| setMaxSize(width, height int) | Y | | Y | |
+| setMinSize(width, height int) | Y | | Y | |
+| setPosition(x int, y int) | Y | | Y | |
+| setResizable(resizable bool) | Y | | Y | |
+| setSize(width, height int) | Y | | Y | |
+| setTitle(title string) | Y | | Y | |
+| setURL(url string) | | | Y | |
+| setZoom(zoom float64) | | | Y | |
+| show() | Y | | Y | |
+| size() (int, int) | Y | | Y | |
+| toggleDevTools() | | | Y | |
+| unfullscreen() | Y | | Y | |
+| unmaximise() | Y | | Y | |
+| unminimise() | Y | | Y | |
+| width() int | Y | | Y | |
+| zoom() | | | Y | |
+| zoomIn() | | | Y | |
+| zoomOut() | | | Y | |
+| zoomReset() | | | Y | |
+
+## Runtime
+
+### Application
+
+| Feature | Windows | Linux | Mac | Notes |
+|---------|---------|-------|-----|-------|
+| Quit | | | Y | |
+| Hide | Y | | Y | |
+| Show | Y | | Y | |
+
+### Dialogs
+
+| Feature | Windows | Linux | Mac | Notes |
+|----------|---------|-------|-----|-------|
+| Info | Y | | Y | |
+| Warning | Y | | Y | |
+| Error | Y | | Y | |
+| Question | Y | | Y | |
+| OpenFile | Y | | Y | |
+| SaveFile | Y | | Y | |
+
+### Clipboard
+
+| Feature | Windows | Linux | Mac | Notes |
+|---------|---------|-------|-----|-------|
+| SetText | | | Y | |
+| Text | | | Y | |
+
+### ContextMenu
+
+| Feature | Windows | Linux | Mac | Notes |
+|-----------------|---------|-------|-----|-------|
+| OpenContextMenu | | | Y | |
+
+### Screens
+
+| Feature | Windows | Linux | Mac | Notes |
+|------------|---------|-------|-----|-------|
+| GetAll | Y | | Y | |
+| GetPrimary | | | Y | |
+| GetCurrent | | | Y | |
+
+### Window
+
+| Feature | Windows | Linux | Mac | Notes |
+|---------------------|---------|-------|-----|--------------------------------------------------------------------------------------|
+| SetTitle | Y | | Y | |
+| SetSize | Y | | Y | |
+| Size | Y | | Y | |
+| SetPosition | Y | | Y | |
+| Position | Y | | Y | |
+| Focus | Y | | Y | |
+| FullScreen | Y | | Y | |
+| UnFullscreen | Y | | Y | |
+| Minimise | Y | | Y | |
+| UnMinimise | Y | | Y | |
+| Maximise | Y | | Y | |
+| UnMaximise | Y | | Y | |
+| Show | Y | | Y | |
+| Hide | Y | | Y | |
+| Center | Y | | Y | |
+| SetBackgroundColour | Y | | Y | https://github.com/MicrosoftEdge/WebView2Feedback/issues/1621#issuecomment-938234294 |
+| SetAlwaysOnTop | Y | | Y | |
+| SetResizable | Y | | Y | |
+| SetMinSize | Y | | Y | |
+| SetMaxSize | Y | | Y | |
+| Width | Y | | Y | |
+| Height | Y | | Y | |
+| ZoomIn | | | Y | Increase view scale |
+| ZoomOut | | | Y | Decrease view scale |
+| ZoomReset | | | Y | Reset view scale |
+| GetZoom | | | Y | Get current view scale |
+| SetZoom | | | Y | Set view scale |
+| Screen | | | Y | Get screen for window |
+
+### Window Options
+
+A 'Y' in the table below indicates that the option has been tested and is applied when the window is created.
+An 'X' indicates that the option is not supported by the platform.
+
+| Feature | Windows | Linux | Mac | Notes |
+|---------------------------------|---------|-------|-----|--------------------------------------------|
+| Name | Y | | | |
+| Title | Y | | | |
+| Width | Y | | | |
+| Height | Y | | | |
+| AlwaysOnTop | Y | | | |
+| URL | | | | |
+| DisableResize | Y | | | |
+| Frameless | Y | | | |
+| MinWidth | Y | | | |
+| MinHeight | Y | | | |
+| MaxWidth | Y | | | |
+| MaxHeight | Y | | | |
+| StartState | Y | | | |
+| Mac | - | - | | |
+| BackgroundType | | | | Acrylic seems to work but the others don't |
+| BackgroundColour | Y | | | |
+| HTML | | | | |
+| JS | | | | |
+| CSS | | | | |
+| X | Y | | | |
+| Y | Y | | | |
+| HideOnClose | Y | | | |
+| FullscreenButtonEnabled | Y | | | |
+| Hidden | Y | | | |
+| EnableFraudulentWebsiteWarnings | | | | |
+| Zoom | | | | |
+| ZoomControlEnabled | | | | |
+| OpenInspectorOnStartup | | | | |
+| EnableDragAndDrop | | | | |
+| Windows | Y | - | - | |
+| Focused | Y | | | |
+
+### Log
+
+To log or not to log? System logger vs custom logger.
+
+## Menu
+
+| Event | Windows | Linux | Mac | Notes |
+|--------------------------|---------|-------|-----|-------|
+| Default Application Menu | | | Y | |
+
+## Tray Menus
+
+| Feature | Windows | Linux | Mac | Notes |
+|--------------------|---------|-------|-----|----------------------------------------------------------------------|
+| Icon | Y | | Y | Windows has default icons for light/dark mode & supports PNG or ICO. |
+| Label | - | | Y | |
+| Label (ANSI Codes) | - | | | |
+| Menu | Y | | Y | |
+
+## Cross Platform Events
+
+Mapping native events to cross-platform events.
+
+| Event | Windows | Linux | Mac | Notes |
+|--------------------------|---------|-------|-----------------|-------|
+| WindowWillClose | | | WindowWillClose | |
+| WindowDidClose | | | | |
+| WindowDidResize | | | | |
+| WindowDidHide | | | | |
+| ApplicationWillTerminate | | | | |
+
+... Add more
+
+## Bindings Generation
+
+TBD
+
+## Models Generation
+
+TBD
+
+## Task file
+
+TBD
+
+## Theme
+
+| Mode | Windows | Linux | Mac | Notes |
+|--------|---------|-------|-----|-------|
+| Dark | Y | | | |
+| Light | Y | | | |
+| System | Y | | | |
+
+## NSIS Installer
+
+TBD
+
+## Templates
+
+TBD
+
+## Plugins
+
+Built-in plugin support:
+
+| Plugin | Windows | Linux | Mac | Notes |
+|-----------------|---------|-------|-----|-------|
+| Browser | | | Y | |
+| KV Store | | | Y | |
+| Log | | | Y | |
+| Single Instance | | | Y | |
+| SQLite | | | Y | |
+| Start at login | | | Y | |
+| Server | | | | |
+
+## Packaging
+
+| | Windows | Linux | Mac | Notes |
+|-----------------|---------|-------|-----|-------|
+| Icon Generation | | | Y | |
+| Icon Embedding | | | Y | |
+| Info.plist | - | | Y | |
+| NSIS Installer | | | - | |
+| Mac bundle | | | Y | |
+| Windows exe | | | - | |
+
+## Frameless Windows
+
+| Feature | Windows | Linux | Mac | Notes |
+|---------|---------|-------|-----|-------|
+| Resize | | | | |
+| Drag | | | | |
+
+## Mac Specific
+
+- [x] Translucency
+
+### Mac Options
+
+| Feature | Default | Notes |
+|-------------------------|-------------------|------------------------------------------------------|
+| Backdrop | MacBackdropNormal | Standard solid window |
+| DisableShadow | false | |
+| TitleBar | | Standard window decorations by default |
+| Appearance | DefaultAppearance | |
+| InvisibleTitleBarHeight | 0 | Creates an invisible title bar for frameless windows |
+
+## Windows Specific
+
+- [x] Translucency
+- [x] Custom Themes
+
+### Windows Options
+
+| Feature | Default | Notes |
+|-----------------------------------|---------|---------------------------------------------|
+| BackdropType | | |
+| DisableIcon | | |
+| Theme | | |
+| CustomTheme | | |
+| DisableFramelessWindowDecorations | | |
+| WindowMask | nil | Makes the window the contents of the bitmap |
+
+## Linux Specific
diff --git a/v3/TODO.md b/v3/TODO.md
deleted file mode 100644
index eb099a96d..000000000
--- a/v3/TODO.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# TODO
-
-Informal and incomplete list of things needed in v3.
-
-## General
-
-- [x] Generate Bindings
-- [x] Generate TS Models
-- [ ] Dev Mode
-- [ ] Generate Info.Plist from `info.json`
-
-- [ ] Windows Port
-- [ ] Linux Port
-
-## Runtime
-
-- [x] Pass window ID with window calls in JS
-- [x] Implement alias for `window` in JS
-- [x] Implement runtime dispatcher
- - [x] Log
- - [x] Same Window
- - [ ] Other Window
- - [x] Dialogs
- - [x] Info
- - [x] Warning
- - [x] Error
- - [x] Question
- - [x] OpenFile
- - [x] SaveFile
- - [x] Events
- - [x] Screens
- - [x] Clipboard
- - [x] Application
-- [ ] Create `.d.ts` file
-
-## Templates
-
-- [ ] Create plain template
-- [ ] Improve default template
-
-## Runtime
-
-- [ ] To log or not to log?
-- [ ] Unify cross-platform events, eg. `onClose`
-
-## Plugins
-
-- [ ] Move logins to `v3/plugins`
-- [ ] Expose application logger to plugins
\ No newline at end of file
diff --git a/v3/Taskfile.yaml b/v3/Taskfile.yaml
index 74b300ce8..362d1934b 100644
--- a/v3/Taskfile.yaml
+++ b/v3/Taskfile.yaml
@@ -3,124 +3,16 @@
version: "3"
includes:
+ runtime:
+ taskfile: ./internal/runtime
+ dir: ./internal/runtime
+
website:
taskfile: ./website
dir: ./website
optional: true
tasks:
- build-runtime-debug:
- dir: internal/runtime
- internal: true
- cmds:
- - npx esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_debug_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}}
-
- build-runtime-debug-windows:
- cmds:
- - task: build-runtime-debug
- vars:
- WINDOWS: true
- DARWIN: false
- LINUX: false
- PLATFORM: windows
-
- build-runtime-debug-linux:
- cmds:
- - task: build-runtime-debug
- vars:
- WINDOWS: false
- DARWIN: false
- LINUX: true
- PLATFORM: linux
-
- build-runtime-debug-darwin:
- cmds:
- - task: build-runtime-debug
- vars:
- WINDOWS: false
- DARWIN: true
- LINUX: false
- PLATFORM: darwin
-
- build-runtime-production:
- dir: internal/runtime
- internal: true
- cmds:
- - npx esbuild desktop/main.js --bundle --minify --outfile=runtime_production_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}}
-
- build-runtime-production-windows:
- cmds:
- - task: build-runtime-production
- vars:
- WINDOWS: true
- DARWIN: false
- LINUX: false
- PLATFORM: windows
-
- build-runtime-production-linux:
- cmds:
- - task: build-runtime-production
- vars:
- WINDOWS: false
- DARWIN: false
- LINUX: true
- PLATFORM: linux
-
- build-runtime-production-darwin:
- cmds:
- - task: build-runtime-production
- vars:
- WINDOWS: false
- DARWIN: true
- LINUX: false
- PLATFORM: darwin
-
- install-runtime-dev-deps:
- dir: internal/runtime/dev
- internal: true
- sources:
- - package.json
- cmds:
- - npm install
-
- install-runtime-deps:
- dir: internal/runtime
- internal: true
- sources:
- - package.json
- cmds:
- - npm install
-
- test-runtime:
- dir: internal/runtime
- cmds:
- - npx vitest run
-
- update-runtime:
- dir: internal/runtime
- cmds:
- - npx npm-check-updates -u
-
- build-runtime-all:
- dir: internal/runtime
- deps:
- - build-runtime-production-darwin
- - build-runtime-production-windows
- - build-runtime-production-linux
- - build-runtime-debug-darwin
- - build-runtime-debug-windows
- - build-runtime-debug-linux
-
- cmds:
- - cmd: echo "build complete"
-
- build-runtime:
- dir: internal/runtime
- deps:
- - install-runtime-deps
- cmds:
- - task: build-runtime-all
-
recreate-template-dir:
dir: internal/templates
internal: true
@@ -129,7 +21,7 @@ tasks:
- rm -rf {{.TEMPLATE_DIR}}
- mkdir -p {{.TEMPLATE_DIR}}
- generate-template:
+ generate:template:
dir: internal/templates/{{.TEMPLATE}}
deps:
- task: recreate-template-dir
@@ -156,49 +48,54 @@ tasks:
- go install
- echo "Reinstalled wails CLI"
- generate-templates:
+ generate:events:
+ dir: tasks/events
+ cmds:
+ - go run generate.go
+
+ generate:templates:
dir: internal/templates/
deps:
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: svelte
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: svelte-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: vue
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: vue-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: react
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: react-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: preact
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: preact-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: lit
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: lit-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: vanilla
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: vanilla-ts
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: react-swc
- - task: generate-template
+ - task: generate:template
vars:
TEMPLATE: react-swc-ts
cmds:
diff --git a/v3/V3 Changes.md b/v3/V3 Changes.md
index a002af2d5..9701d375b 100644
--- a/v3/V3 Changes.md
+++ b/v3/V3 Changes.md
@@ -59,6 +59,24 @@ TBD
Dialogs are now available in JavaScript!
+### Windows
+
+Dialog buttons in Windows are not configurable and are constant depending on the type of dialog. To trigger a callback when a button is pressed, create a button with the same name as the button you wish to have the callback attached to.
+Example: Create a button with the label `Ok` and use `OnClick()` to set the callback method:
+```go
+ dialog := app.QuestionDialog().
+ SetTitle("Update").
+ SetMessage("The cancel button is selected when pressing escape")
+ ok := dialog.AddButton("Ok")
+ ok.OnClick(func() {
+ // Do something
+ })
+ no := dialog.AddButton("Cancel")
+ dialog.SetDefaultButton(ok)
+ dialog.SetCancelButton(no)
+ dialog.Show()
+```
+
## Drag and Drop
Native drag and drop can be enabled per-window. Simply set the `EnableDragAndDrop` window config option to `true` and the window will allow files to be dragged onto it. When this happens, the `events.FilesDropped` event will be emitted. The filenames can then be retrieved from the WindowEventContext using the `DroppedFiles()` method. This returns a slice of strings containing the filenames.
@@ -180,3 +198,39 @@ const MyEnum = {
- Why use `float64`? Can't we use `int`?
- Because JavaScript doesn't have a concept of `int`. Everything is a `number`, which translates to `float64` in Go. There are also restrictions on casting types in Go's reflection package, which means using `int` doesn't work.
+
+### BackgroundColour
+
+In v2, this was a pointer to an `RGBA` struct. In v3, this is an `RGBA` struct value.
+
+### WindowIsTranslucent
+
+This flag has been removed. Now there is a `BackgroundType` flag that can be used to set the type of background the window should have.
+This flag can be set to any of the following values:
+- `BackgroundTypeSolid` - The window will have a solid background
+- `BackgroundTypeTransparent` - The window will have a transparent background
+- `BackgroundTypeTranslucent` - The window will have a translucent background
+
+On Windows, if the `BackgroundType` is set to `BackgroundTypeTranslucent`, the type of translucency can be set using the
+`BackdropType` flag in the `WindowsWindow` options. This can be set to any of the following values:
+- `Auto` - The window will use an effect determined by the system
+- `None` - The window will have no background
+- `Mica` - The window will use the Mica effect
+- `Acrylic` - The window will use the acrylic effect
+- `Tabbed` - The window will use the tabbed effect
+
+
+## Windows Application Options
+
+### WndProcInterceptor
+
+If this is set, the WndProc will be intercepted and the function will be called. This allows you to handle Windows
+messages directly. The function should have the following signature:
+
+```go
+func(hwnd uintptr, msg uint32, wParam, lParam uintptr) (returnValue uintptr, shouldReturn)
+```
+
+The `shouldReturn` value should be set to `true` if the returnValue should be returned by the main wndProc method.
+If it is set to `false`, the return value will be ignored and the message will continue to be processed by the main
+wndProc method.
\ No newline at end of file
diff --git a/v3/examples/binding/go.mod b/v3/examples/binding/go.mod
index affecaa9f..6e43aef56 100644
--- a/v3/examples/binding/go.mod
+++ b/v3/examples/binding/go.mod
@@ -5,15 +5,20 @@ go 1.20
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
require (
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/samber/lo v1.37.0 // indirect
+ github.com/wailsapp/go-webview2 v1.0.1 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 // indirect
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
golang.org/x/net v0.7.0 // indirect
+ golang.org/x/sys v0.8.0 // indirect
)
replace github.com/wailsapp/wails/v3 => ../..
diff --git a/v3/examples/binding/go.sum b/v3/examples/binding/go.sum
index c06e0dbc6..56af9c50a 100644
--- a/v3/examples/binding/go.sum
+++ b/v3/examples/binding/go.sum
@@ -1,7 +1,13 @@
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
@@ -18,6 +24,8 @@ github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpo
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II=
+github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
@@ -25,8 +33,12 @@ golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/v3/examples/binding/main.go b/v3/examples/binding/main.go
index ed0bd6331..24b148fb9 100644
--- a/v3/examples/binding/main.go
+++ b/v3/examples/binding/main.go
@@ -19,14 +19,15 @@ func main() {
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
- })
-
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
Assets: application.AssetOptions{
FS: assets,
},
})
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ URL: "/",
+ })
+
err := app.Run()
if err != nil {
diff --git a/v3/examples/build/main.go b/v3/examples/build/main.go
index 48ba24088..5bb3f0df1 100755
--- a/v3/examples/build/main.go
+++ b/v3/examples/build/main.go
@@ -67,7 +67,7 @@ func main() {
if runtime.GOOS == "darwin" {
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Mac: application.MacWindow{
TitleBar: application.MacTitleBarHiddenInset,
InvisibleTitleBarHeight: 25,
@@ -81,7 +81,7 @@ func main() {
})
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Mac: application.MacWindow{
TitleBar: application.MacTitleBarHiddenInsetUnified,
InvisibleTitleBarHeight: 50,
@@ -95,7 +95,7 @@ func main() {
})
myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Mac: application.MacWindow{
TitleBar: application.MacTitleBarHidden,
InvisibleTitleBarHeight: 25,
diff --git a/v3/examples/contextmenus/main.go b/v3/examples/contextmenus/main.go
index a94b9d340..ad428e091 100644
--- a/v3/examples/contextmenus/main.go
+++ b/v3/examples/contextmenus/main.go
@@ -25,7 +25,7 @@ func main() {
},
})
- mainWindow := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ mainWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Context Menu Demo",
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
@@ -34,7 +34,7 @@ func main() {
},
})
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Context Menu Demo",
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
diff --git a/v3/examples/dialogs/main.go b/v3/examples/dialogs/main.go
index ff55949ae..2301fd983 100644
--- a/v3/examples/dialogs/main.go
+++ b/v3/examples/dialogs/main.go
@@ -2,6 +2,7 @@ package main
import (
_ "embed"
+ "github.com/wailsapp/wails/v3/pkg/icons"
"log"
"os"
"runtime"
@@ -19,6 +20,7 @@ func main() {
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
})
+
// Create a custom menu
menu := app.NewMenu()
menu.AddRole(application.AppMenu)
@@ -45,7 +47,7 @@ func main() {
dialog := app.InfoDialog()
dialog.SetTitle("Custom Icon Example")
dialog.SetMessage("Using a custom icon")
- dialog.SetIcon(application.DefaultApplicationIcon)
+ dialog.SetIcon(icons.ApplicationDarkMode256)
dialog.Show()
})
@@ -85,7 +87,7 @@ func main() {
dialog := app.QuestionDialog()
dialog.SetTitle("Custom Icon Example")
dialog.SetMessage("Using a custom icon")
- dialog.SetIcon(application.WailsLogoWhiteTransparent)
+ dialog.SetIcon(icons.WailsLogoWhiteTransparent)
dialog.SetDefaultButton(dialog.AddButton("I like it!"))
dialog.AddButton("Not so keen...")
dialog.Show()
@@ -112,7 +114,7 @@ func main() {
dialog := app.WarningDialog()
dialog.SetTitle("Custom Icon Example")
dialog.SetMessage("Using a custom icon")
- dialog.SetIcon(application.DefaultApplicationIcon)
+ dialog.SetIcon(icons.ApplicationLightMode256)
dialog.Show()
})
@@ -137,7 +139,7 @@ func main() {
dialog := app.ErrorDialog()
dialog.SetTitle("Custom Icon Example")
dialog.SetMessage("Using a custom icon")
- dialog.SetIcon(application.WailsLogoWhite)
+ dialog.SetIcon(icons.WailsLogoWhite)
dialog.Show()
})
diff --git a/v3/examples/drag-n-drop/main.go b/v3/examples/drag-n-drop/main.go
index 1346a2bac..7558ce55d 100644
--- a/v3/examples/drag-n-drop/main.go
+++ b/v3/examples/drag-n-drop/main.go
@@ -25,7 +25,7 @@ func main() {
},
})
- window := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ window := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Drag-n-drop Demo",
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
diff --git a/v3/examples/events/main.go b/v3/examples/events/main.go
index 7f0c23653..5cf34796c 100644
--- a/v3/examples/events/main.go
+++ b/v3/examples/events/main.go
@@ -26,10 +26,12 @@ func main() {
},
})
+ // Custom event handling
app.Events.On("myevent", func(e *application.WailsEvent) {
log.Printf("[Go] WailsEvent received: %+v\n", e)
})
+ // OS specific application events
app.On(events.Mac.ApplicationDidFinishLaunching, func() {
for {
log.Println("Sending event")
@@ -41,7 +43,12 @@ func main() {
}
})
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ // Platform agnostic events
+ app.On(events.Common.ApplicationStarted, func() {
+ println("events.Common.ApplicationStarted fired!")
+ })
+
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Events Demo",
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
@@ -49,7 +56,7 @@ func main() {
InvisibleTitleBarHeight: 50,
},
})
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Events Demo",
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
diff --git a/v3/examples/frameless/assets/index.html b/v3/examples/frameless/assets/index.html
new file mode 100644
index 000000000..89618b751
--- /dev/null
+++ b/v3/examples/frameless/assets/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
Draggable
+
Not Draggable
+
Not Draggable
+
Draggable
+
+
+
diff --git a/v3/examples/frameless/main.go b/v3/examples/frameless/main.go
new file mode 100644
index 000000000..06f8bdb49
--- /dev/null
+++ b/v3/examples/frameless/main.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "embed"
+ _ "embed"
+ "log"
+
+ "github.com/wailsapp/wails/v3/pkg/application"
+)
+
+//go:embed assets
+var assets embed.FS
+
+func main() {
+
+ app := application.New(application.Options{
+ Name: "Frameless Demo",
+ Description: "A demo of frameless windows",
+ Mac: application.MacOptions{
+ ApplicationShouldTerminateAfterLastWindowClosed: true,
+ },
+ Assets: application.AssetOptions{
+ FS: assets,
+ },
+ })
+
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ Frameless: true,
+ })
+
+ err := app.Run()
+
+ if err != nil {
+ log.Fatal(err.Error())
+ }
+}
diff --git a/v3/examples/kitchensink/main.go b/v3/examples/kitchensink/main.go
index 509da3415..f5a6ae273 100644
--- a/v3/examples/kitchensink/main.go
+++ b/v3/examples/kitchensink/main.go
@@ -2,6 +2,7 @@ package main
import (
_ "embed"
+ "github.com/wailsapp/wails/v3/pkg/icons"
"log"
"runtime"
"sync"
@@ -62,9 +63,9 @@ func main() {
mySystray := app.NewSystemTray()
mySystray.SetLabel("Wails")
if runtime.GOOS == "darwin" {
- mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
+ mySystray.SetTemplateIcon(icons.SystrayMacTemplate)
} else {
- mySystray.SetIcon(application.DefaultApplicationIcon)
+ mySystray.SetIcon(icons.ApplicationDarkMode256)
}
myMenu := app.NewMenu()
myMenu.Add("Item 1")
@@ -102,20 +103,20 @@ func main() {
mySystray := app.NewSystemTray()
mySystray.SetLabel("Wails is awesome")
if runtime.GOOS == "darwin" {
- mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
+ mySystray.SetTemplateIcon(icons.SystrayMacTemplate)
} else {
- mySystray.SetIcon(application.DefaultApplicationIcon)
+ mySystray.SetIcon(icons.ApplicationDarkMode256)
}
mySystray.SetMenu(myMenu)
mySystray.SetIconPosition(application.NSImageLeading)
- myWindow := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ myWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Kitchen Sink",
Width: 600,
Height: 400,
AlwaysOnTop: true,
DisableResize: false,
- BackgroundColour: &application.RGBA{
+ BackgroundColour: application.RGBA{
Red: 255,
Green: 255,
Blue: 255,
@@ -184,7 +185,7 @@ func main() {
*/
var myWindow2 *application.WebviewWindow
var myWindow2Lock sync.RWMutex
- myWindow2 = app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ myWindow2 = app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "#2",
Width: 1024,
Height: 768,
diff --git a/v3/examples/menu/main.go b/v3/examples/menu/main.go
index 3ca15cf47..b98393a8f 100644
--- a/v3/examples/menu/main.go
+++ b/v3/examples/menu/main.go
@@ -29,7 +29,12 @@ func main() {
// Click callbacks
myMenu.Add("Click Me!").OnClick(func(ctx *application.Context) {
- ctx.ClickedMenuItem().SetLabel("Thanks mate!")
+ switch ctx.ClickedMenuItem().Label() {
+ case "Click Me!":
+ ctx.ClickedMenuItem().SetLabel("Thanks mate!")
+ case "Thanks mate!":
+ ctx.ClickedMenuItem().SetLabel("Click Me!")
+ }
})
// You can control the current window from the menu
@@ -82,7 +87,15 @@ func main() {
beatles.SetLabel("Hello")
}
})
-
+ myMenu.Add("Hide the beatles").OnClick(func(ctx *application.Context) {
+ if beatles.Hidden() {
+ ctx.ClickedMenuItem().SetLabel("Unhide the beatles!")
+ beatles.SetHidden(false)
+ } else {
+ beatles.SetHidden(true)
+ ctx.ClickedMenuItem().SetLabel("Hide the beatles!")
+ }
+ })
app.SetMenu(menu)
app.NewWebviewWindow()
diff --git a/v3/examples/plain/main.go b/v3/examples/plain/main.go
index bc8406e82..83cfdea11 100644
--- a/v3/examples/plain/main.go
+++ b/v3/examples/plain/main.go
@@ -4,6 +4,7 @@ import (
_ "embed"
"log"
"net/http"
+ "time"
"github.com/wailsapp/wails/v3/pkg/application"
)
@@ -23,7 +24,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; user-select: none; -ms-user-select: none; -webkit-user-select: none; } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
@@ -38,6 +39,21 @@ func main() {
println("clicked")
})
+ go func() {
+ time.Sleep(5 * time.Second)
+
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ Title: "Plain Bundle new Window from GoRoutine",
+ Width: 500,
+ Height: 500,
+ Mac: application.MacWindow{
+ Backdrop: application.MacBackdropTranslucent,
+ TitleBar: application.MacTitleBarHiddenInsetUnified,
+ InvisibleTitleBarHeight: 50,
+ },
+ })
+ }()
+
err := app.Run()
if err != nil {
diff --git a/v3/examples/screen/main.go b/v3/examples/screen/main.go
index e71f5c4be..566dca2cf 100644
--- a/v3/examples/screen/main.go
+++ b/v3/examples/screen/main.go
@@ -24,7 +24,7 @@ func main() {
},
})
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Screen Demo",
Width: 800,
Height: 600,
diff --git a/v3/examples/systray/main.go b/v3/examples/systray/main.go
index 2beb4501d..3c7bdf8e7 100644
--- a/v3/examples/systray/main.go
+++ b/v3/examples/systray/main.go
@@ -2,12 +2,21 @@ package main
import (
_ "embed"
+ "fmt"
+ "github.com/wailsapp/wails/v3/pkg/icons"
"log"
"runtime"
"github.com/wailsapp/wails/v3/pkg/application"
)
+var counter int
+
+func clickCount() int {
+ counter++
+ return counter
+}
+
func main() {
app := application.New(application.Options{
Name: "Systray Demo",
@@ -17,26 +26,50 @@ func main() {
},
})
+ window := app.NewWebviewWindow().Hide()
+
systemTray := app.NewSystemTray()
if runtime.GOOS == "darwin" {
- systemTray.SetIcon(application.DefaultMacTemplateIcon)
+ systemTray.SetTemplateIcon(icons.SystrayMacTemplate)
}
myMenu := app.NewMenu()
myMenu.Add("Hello World!").OnClick(func(ctx *application.Context) {
- app.InfoDialog().SetTitle("Hello World!").SetMessage("Hello World!").Show()
+ println("Hello World!")
+ q := app.QuestionDialog().SetTitle("Ready?").SetMessage("Are you feeling ready?")
+ q.AddButton("Yes").OnClick(func() {
+ println("Awesome!")
+ })
+ q.AddButton("No").SetAsDefault().OnClick(func() {
+ println("Boo!")
+ })
+ q.Show()
})
subMenu := myMenu.AddSubmenu("Submenu")
subMenu.Add("Click me!").OnClick(func(ctx *application.Context) {
ctx.ClickedMenuItem().SetLabel("Clicked!")
})
myMenu.AddSeparator()
+ myMenu.AddCheckbox("Checked", true).OnClick(func(ctx *application.Context) {
+ println("Checked: ", ctx.ClickedMenuItem().Checked())
+ app.InfoDialog().SetTitle("Hello World!").SetMessage("Hello World!").Show()
+ })
+ myMenu.Add("Enabled").OnClick(func(ctx *application.Context) {
+ println("Click me!")
+ ctx.ClickedMenuItem().SetLabel("Disabled!").SetEnabled(false)
+ })
+ myMenu.AddSeparator()
myMenu.Add("Quit").OnClick(func(ctx *application.Context) {
app.Quit()
})
systemTray.SetMenu(myMenu)
+ systemTray.OnClick(func() {
+ window.SetTitle(fmt.Sprintf("Clicked %d times", clickCount()))
+ window.Show().Focus()
+ })
+
err := app.Run()
if err != nil {
diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go
index 7a6e174c5..c9de5fde7 100644
--- a/v3/examples/window/main.go
+++ b/v3/examples/window/main.go
@@ -2,14 +2,8 @@ package main
import (
_ "embed"
- "fmt"
- "log"
- "math/rand"
- "runtime"
- "strconv"
- "time"
-
"github.com/wailsapp/wails/v3/pkg/events"
+ "log"
"github.com/wailsapp/wails/v3/pkg/application"
)
@@ -25,257 +19,261 @@ func main() {
app.On(events.Mac.ApplicationDidFinishLaunching, func() {
log.Println("ApplicationDidFinishLaunching")
})
-
- currentWindow := func(fn func(window *application.WebviewWindow)) {
- if app.CurrentWindow() != nil {
- fn(app.CurrentWindow())
- } else {
- println("Current WebviewWindow is nil")
- }
- }
-
- // Create a custom menu
- menu := app.NewMenu()
- menu.AddRole(application.AppMenu)
-
- windowCounter := 1
-
- // Let's make a "Demo" menu
- myMenu := menu.AddSubmenu("New")
-
- myMenu.Add("New WebviewWindow").
- SetAccelerator("CmdOrCtrl+N").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindow().
- SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
- SetPosition(rand.Intn(1000), rand.Intn(800)).
- SetURL("https://wails.io").
- Show()
- windowCounter++
- })
- myMenu.Add("New WebviewWindow (Hide on Close").
- SetAccelerator("CmdOrCtrl+H").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{HideOnClose: true}).
- SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
- SetPosition(rand.Intn(1000), rand.Intn(800)).
- SetURL("https://wails.io").
- Show()
- windowCounter++
- })
- myMenu.Add("New Frameless WebviewWindow").
- SetAccelerator("CmdOrCtrl+F").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
- X: rand.Intn(1000),
- Y: rand.Intn(800),
- Frameless: true,
- Mac: application.MacWindow{
- InvisibleTitleBarHeight: 50,
- },
- }).Show()
- windowCounter++
- })
- if runtime.GOOS == "darwin" {
- myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
- Mac: application.MacWindow{
- TitleBar: application.MacTitleBarHiddenInset,
- InvisibleTitleBarHeight: 25,
- },
- }).
- SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
- SetPosition(rand.Intn(1000), rand.Intn(800)).
- SetHTML("
A MacTitleBarHiddenInset WebviewWindow example
").
- Show()
- windowCounter++
- })
- myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
- Mac: application.MacWindow{
- TitleBar: application.MacTitleBarHiddenInsetUnified,
- InvisibleTitleBarHeight: 50,
- },
- }).
- SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
- SetPosition(rand.Intn(1000), rand.Intn(800)).
- SetHTML("
A MacTitleBarHiddenInsetUnified WebviewWindow example
").
- Show()
- windowCounter++
- })
- myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
- OnClick(func(ctx *application.Context) {
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
- Mac: application.MacWindow{
- TitleBar: application.MacTitleBarHidden,
- InvisibleTitleBarHeight: 25,
- },
- }).
- SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
- SetPosition(rand.Intn(1000), rand.Intn(800)).
- SetHTML("
A MacTitleBarHidden WebviewWindow example
").
- Show()
- windowCounter++
- })
- }
-
- sizeMenu := menu.AddSubmenu("Size")
- sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetSize(800, 600)
- })
+ //
+ //currentWindow := func(fn func(window *application.WebviewWindow)) {
+ // if app.CurrentWindow() != nil {
+ // fn(app.CurrentWindow())
+ // } else {
+ // println("Current WebviewWindow is nil")
+ // }
+ //}
+ //
+ //// Create a custom menu
+ //menu := app.NewMenu()
+ //menu.AddRole(application.AppMenu)
+ //
+ //windowCounter := 1
+ //
+ //// Let's make a "Demo" menu
+ //myMenu := menu.AddSubmenu("New")
+ //
+ //myMenu.Add("New WebviewWindow").
+ // SetAccelerator("CmdOrCtrl+N").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindow().
+ // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
+ // SetPosition(rand.Intn(1000), rand.Intn(800)).
+ // SetURL("https://wails.io").
+ // Show()
+ // windowCounter++
+ // })
+ //myMenu.Add("New WebviewWindow (Hide on Close").
+ // SetAccelerator("CmdOrCtrl+H").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{HideOnClose: true}).
+ // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
+ // SetPosition(rand.Intn(1000), rand.Intn(800)).
+ // SetURL("https://wails.io").
+ // Show()
+ // windowCounter++
+ // })
+ //myMenu.Add("New Frameless WebviewWindow").
+ // SetAccelerator("CmdOrCtrl+F").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ // X: rand.Intn(1000),
+ // Y: rand.Intn(800),
+ // Frameless: true,
+ // Mac: application.MacWindow{
+ // InvisibleTitleBarHeight: 50,
+ // },
+ // }).Show()
+ // windowCounter++
+ // })
+ //if runtime.GOOS == "darwin" {
+ // myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ // Mac: application.MacWindow{
+ // TitleBar: application.MacTitleBarHiddenInset,
+ // InvisibleTitleBarHeight: 25,
+ // },
+ // }).
+ // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
+ // SetPosition(rand.Intn(1000), rand.Intn(800)).
+ // SetHTML("
A MacTitleBarHiddenInset WebviewWindow example
").
+ // Show()
+ // windowCounter++
+ // })
+ // myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ // Mac: application.MacWindow{
+ // TitleBar: application.MacTitleBarHiddenInsetUnified,
+ // InvisibleTitleBarHeight: 50,
+ // },
+ // }).
+ // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
+ // SetPosition(rand.Intn(1000), rand.Intn(800)).
+ // SetHTML("
A MacTitleBarHiddenInsetUnified WebviewWindow example
").
+ // Show()
+ // windowCounter++
+ // })
+ // myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
+ // OnClick(func(ctx *application.Context) {
+ // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ // Mac: application.MacWindow{
+ // TitleBar: application.MacTitleBarHidden,
+ // InvisibleTitleBarHeight: 25,
+ // },
+ // }).
+ // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
+ // SetPosition(rand.Intn(1000), rand.Intn(800)).
+ // SetHTML("
A MacTitleBarHidden WebviewWindow example
").
+ // Show()
+ // windowCounter++
+ // })
+ //}
+ //
+ //sizeMenu := menu.AddSubmenu("Size")
+ //sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetSize(800, 600)
+ // })
+ //})
+ //
+ //sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200)
+ // })
+ //})
+ //sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetMinSize(200, 200)
+ // })
+ //})
+ //sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetFullscreenButtonEnabled(false)
+ // w.SetMaxSize(600, 600)
+ // })
+ //})
+ //sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // width, height := w.Size()
+ // app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show()
+ // })
+ //})
+ //
+ //sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetMinSize(0, 0)
+ // })
+ //})
+ //
+ //sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetMaxSize(0, 0)
+ // w.SetFullscreenButtonEnabled(true)
+ // })
+ //})
+ //positionMenu := menu.AddSubmenu("Position")
+ //positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetPosition(0, 0)
+ // })
+ //})
+ //positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetPosition(rand.Intn(1000), rand.Intn(800))
+ // })
+ //})
+ //
+ //positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // x, y := w.Position()
+ // app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show()
+ // })
+ //})
+ //
+ //positionMenu.Add("Center").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Center()
+ // })
+ //})
+ //stateMenu := menu.AddSubmenu("State")
+ //stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Minimise()
+ // time.Sleep(2 * time.Second)
+ // w.Restore()
+ // })
+ //})
+ //stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Maximise()
+ // })
+ //})
+ //stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Fullscreen()
+ // })
+ //})
+ //stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.UnFullscreen()
+ // })
+ //})
+ //stateMenu.Add("Restore").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Restore()
+ // })
+ //})
+ //stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.Hide()
+ // time.Sleep(2 * time.Second)
+ // w.Show()
+ // })
+ //})
+ //stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetAlwaysOnTop(true)
+ // })
+ //})
+ //stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetAlwaysOnTop(false)
+ // })
+ //})
+ //stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetURL("https://google.com")
+ // })
+ //})
+ //stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // w.SetURL("https://wails.io")
+ // })
+ //})
+ //stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) {
+ // screen, err := app.GetPrimaryScreen()
+ // if err != nil {
+ // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
+ // return
+ // }
+ // msg := fmt.Sprintf("Screen: %+v", screen)
+ // app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show()
+ //})
+ //stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) {
+ // screens, err := app.GetScreens()
+ // if err != nil {
+ // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
+ // return
+ // }
+ // for _, screen := range screens {
+ // msg := fmt.Sprintf("Screen: %+v", screen)
+ // app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
+ // }
+ //})
+ //stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) {
+ // currentWindow(func(w *application.WebviewWindow) {
+ // screen, err := w.GetScreen()
+ // if err != nil {
+ // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
+ // return
+ // }
+ // msg := fmt.Sprintf("Screen: %+v", screen)
+ // app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
+ // })
+ //})
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
+ Mac: application.MacWindow{
+ DisableShadow: true,
+ },
})
- sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200)
- })
- })
- sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetMinSize(200, 200)
- })
- })
- sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetFullscreenButtonEnabled(false)
- w.SetMaxSize(600, 600)
- })
- })
- sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- width, height := w.Size()
- app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show()
- })
- })
-
- sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetMinSize(0, 0)
- })
- })
-
- sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetMaxSize(0, 0)
- w.SetFullscreenButtonEnabled(true)
- })
- })
- positionMenu := menu.AddSubmenu("Position")
- positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetPosition(0, 0)
- })
- })
- positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetPosition(rand.Intn(1000), rand.Intn(800))
- })
- })
-
- positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- x, y := w.Position()
- app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show()
- })
- })
-
- positionMenu.Add("Center").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Center()
- })
- })
- stateMenu := menu.AddSubmenu("State")
- stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Minimise()
- time.Sleep(2 * time.Second)
- w.Restore()
- })
- })
- stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Maximise()
- })
- })
- stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Fullscreen()
- })
- })
- stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.UnFullscreen()
- })
- })
- stateMenu.Add("Restore").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Restore()
- })
- })
- stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.Hide()
- time.Sleep(2 * time.Second)
- w.Show()
- })
- })
- stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetAlwaysOnTop(true)
- })
- })
- stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetAlwaysOnTop(false)
- })
- })
- stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetURL("https://google.com")
- })
- })
- stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- w.SetURL("https://wails.io")
- })
- })
- stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) {
- screen, err := app.GetPrimaryScreen()
- if err != nil {
- app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
- return
- }
- msg := fmt.Sprintf("Screen: %+v", screen)
- app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show()
- })
- stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) {
- screens, err := app.GetScreens()
- if err != nil {
- app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
- return
- }
- for _, screen := range screens {
- msg := fmt.Sprintf("Screen: %+v", screen)
- app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
- }
- })
- stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) {
- currentWindow(func(w *application.WebviewWindow) {
- screen, err := w.GetScreen()
- if err != nil {
- app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
- return
- }
- msg := fmt.Sprintf("Screen: %+v", screen)
- app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
- })
- })
- app.NewWebviewWindow()
-
- app.SetMenu(menu)
+ //app.SetMenu(menu)
err := app.Run()
if err != nil {
diff --git a/v3/examples/windowjs/main.go b/v3/examples/windowjs/main.go
index ff7f61cd7..d1c20642e 100644
--- a/v3/examples/windowjs/main.go
+++ b/v3/examples/windowjs/main.go
@@ -34,7 +34,7 @@ func main() {
newWindow := func() {
windowName := "WebviewWindow " + strconv.Itoa(windowCounter)
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Name: windowName,
}).
SetTitle(windowName).
diff --git a/v3/examples/wml/main.go b/v3/examples/wml/main.go
index 1a9f4723b..d615e0dfc 100644
--- a/v3/examples/wml/main.go
+++ b/v3/examples/wml/main.go
@@ -24,7 +24,7 @@ func main() {
},
})
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Wails ML Demo",
Width: 800,
Height: 600,
diff --git a/v3/go.mod b/v3/go.mod
index 4ffb85ce6..4109f9653 100644
--- a/v3/go.mod
+++ b/v3/go.mod
@@ -3,8 +3,11 @@ module github.com/wailsapp/wails/v3
go 1.19
require (
+ github.com/bep/debounce v1.2.1
+ github.com/go-ole/go-ole v1.2.6
github.com/go-task/task/v3 v3.20.0
github.com/google/go-cmp v0.5.9
+ github.com/google/uuid v1.3.0
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
github.com/leaanthony/clir v1.6.0
@@ -16,7 +19,9 @@ require (
github.com/pterm/pterm v0.12.51
github.com/samber/lo v1.37.0
github.com/tc-hib/winres v0.1.6
+ github.com/wailsapp/go-webview2 v1.0.1
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6
+ golang.org/x/sys v0.8.0
modernc.org/sqlite v1.21.0
)
@@ -27,8 +32,8 @@ require (
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
- github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.2 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/joho/godotenv v1.4.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
@@ -53,7 +58,6 @@ require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.1.12 // indirect
diff --git a/v3/go.sum b/v3/go.sum
index ff474ab93..8d2aa703b 100644
--- a/v3/go.sum
+++ b/v3/go.sum
@@ -12,6 +12,8 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.1 h1:a9Fqx6vQrHQ4CyiaLhktfTTelwGotmFWy8MNhyaohw8=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
+github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
+github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
@@ -23,6 +25,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/task/v3 v3.20.0 h1:pTavuhP+AiEpKLzh5I6Lja9Ux7ypYO5QMsEPTbhYEDc=
@@ -39,6 +43,8 @@ github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
github.com/jackmordaunt/icns/v2 v2.2.1 h1:MGklwYP2yohKn2Bw7XxlF69LZe98S1vUfl5OvAulPwg=
github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI=
+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/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -138,6 +144,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8=
github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
+github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II=
+github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
@@ -167,8 +175,10 @@ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -182,8 +192,8 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
diff --git a/v3/internal/commands/icons.go b/v3/internal/commands/icons.go
index 4eee8734f..f4fcf7a7c 100644
--- a/v3/internal/commands/icons.go
+++ b/v3/internal/commands/icons.go
@@ -4,6 +4,8 @@ import (
"bytes"
"fmt"
"image"
+ "image/color"
+ "image/png"
"os"
"strconv"
"strings"
@@ -124,3 +126,39 @@ func generateWindowsIcon(iconData []byte, sizes []int, options *IconsOptions) er
}
return nil
}
+
+func GenerateTemplateIcon(data []byte, outputFilename string) error {
+ // Decode the input file as a PNG
+ buffer := bytes.NewBuffer(data)
+ img, err := png.Decode(buffer)
+ if err != nil {
+ return fmt.Errorf("failed to decode input file as PNG: %w", err)
+ }
+
+ // Create a new image with the same dimensions and RGBA color model
+ bounds := img.Bounds()
+ iconImg := image.NewRGBA(bounds)
+
+ // Iterate over each pixel of the input image
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ // Get the alpha of the pixel
+ _, _, _, a := img.At(x, y).RGBA()
+ iconImg.SetRGBA(x, y, color.RGBA{R: 0, G: 0, B: 0, A: uint8(a)})
+ }
+ }
+
+ // Create the output file
+ outFile, err := os.Create(outputFilename)
+ if err != nil {
+ return fmt.Errorf("failed to create output file: %w", err)
+ }
+ defer outFile.Close()
+
+ // Encode the template icon image as a PNG and write it to the output file
+ if err := png.Encode(outFile, iconImg); err != nil {
+ return fmt.Errorf("failed to encode output image as PNG: %w", err)
+ }
+
+ return nil
+}
diff --git a/v3/internal/debug/debug.go b/v3/internal/debug/debug.go
index 47db8b626..be3480a23 100644
--- a/v3/internal/debug/debug.go
+++ b/v3/internal/debug/debug.go
@@ -1,12 +1,12 @@
package debug
import (
- "github.com/samber/lo"
"path/filepath"
"runtime"
-)
+ "runtime/debug"
-import "runtime/debug"
+ "github.com/samber/lo"
+)
// Why go doesn't provide this as a map already is beyond me.
var buildSettings = map[string]string{}
@@ -20,7 +20,7 @@ func init() {
buildSettings = lo.Associate(buildInfo.Settings, func(setting debug.BuildSetting) (string, string) {
return setting.Key, setting.Value
})
- if isLocalBuild() {
+ if isLocalBuild() || buildInfo.Path == "" {
modulePath := RelativePath("..", "..", "..")
LocalModulePath, _ = filepath.Abs(modulePath)
}
diff --git a/v3/internal/go-common-file-dialog/LICENSE b/v3/internal/go-common-file-dialog/LICENSE
new file mode 100644
index 000000000..508b6978e
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Harry Phillips
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/v3/internal/go-common-file-dialog/README.md b/v3/internal/go-common-file-dialog/README.md
new file mode 100644
index 000000000..1cb5902d1
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/README.md
@@ -0,0 +1,31 @@
+# Common File Dialog bindings for Golang
+
+[Project Home](https://github.com/harry1453/go-common-file-dialog)
+
+This library contains bindings for Windows Vista and
+newer's [Common File Dialogs](https://docs.microsoft.com/en-us/windows/win32/shell/common-file-dialog), which is the
+standard system dialog for selecting files or folders to open or save.
+
+The Common File Dialogs have to be accessed via
+the [COM Interface](https://en.wikipedia.org/wiki/Component_Object_Model), normally via C++ or via bindings (like in C#)
+.
+
+This library contains bindings for Golang. **It does not require CGO**, and contains empty stubs for non-windows
+platforms (so is safe to compile and run on platforms other than windows, but will just return errors at runtime).
+
+This can be very useful if you want to quickly get a file selector in your Golang application. The `cfdutil` package
+contains utility functions with a single call to open and configure a dialog, and then get the result from it. Examples
+for this are in [`_examples/usingutil`](_examples/usingutil). Or, if you want finer control over the dialog's operation,
+you can use the base package. Examples for this are in [`_examples/notusingutil`](_examples/notusingutil).
+
+This library is available under the MIT license.
+
+Currently supported features:
+
+* Open File Dialog (to open a single file)
+* Open Multiple Files Dialog (to open multiple files)
+* Open Folder Dialog
+* Save File Dialog
+* Dialog "roles" to allow Windows to remember different "last locations" for different types of dialog
+* Set dialog Title, Default Folder and Initial Folder
+* Set dialog File Filters
diff --git a/v3/internal/go-common-file-dialog/cfd/CommonFileDialog.go b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog.go
new file mode 100644
index 000000000..58e97aa4e
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog.go
@@ -0,0 +1,72 @@
+// Cross-platform.
+
+// Common File Dialogs
+package cfd
+
+type Dialog interface {
+ // Show the dialog to the user.
+ // Blocks until the user has closed the dialog.
+ Show() error
+ // Sets the dialog's parent window. Use 0 to set the dialog to have no parent window.
+ SetParentWindowHandle(hwnd uintptr)
+ // Show the dialog to the user.
+ // Blocks until the user has closed the dialog and returns their selection.
+ // Returns an error if the user cancelled the dialog.
+ // Do not use for the Open Multiple Files dialog. Use ShowAndGetResults instead.
+ ShowAndGetResult() (string, error)
+ // Sets the title of the dialog window.
+ SetTitle(title string) error
+ // Sets the "role" of the dialog. This is used to derive the dialog's GUID, which the
+ // OS will use to differentiate it from dialogs that are intended for other purposes.
+ // This means that, for example, a dialog with role "Import" will have a different
+ // previous location that it will open to than a dialog with role "Open". Can be any string.
+ SetRole(role string) error
+ // Sets the folder used as a default if there is not a recently used folder value available
+ SetDefaultFolder(defaultFolder string) error
+ // Sets the folder that the dialog always opens to.
+ // If this is set, it will override the "default folder" behaviour and the dialog will always open to this folder.
+ SetFolder(folder string) error
+ // Gets the selected file or folder path, as an absolute path eg. "C:\Folder\file.txt"
+ // Do not use for the Open Multiple Files dialog. Use GetResults instead.
+ GetResult() (string, error)
+ // Sets the file name, I.E. the contents of the file name text box.
+ // For Select Folder Dialog, sets folder name.
+ SetFileName(fileName string) error
+ // Release the resources allocated to this Dialog.
+ // Should be called when the dialog is finished with.
+ Release() error
+}
+
+type FileDialog interface {
+ Dialog
+ // Set the list of file filters that the user can select.
+ SetFileFilters(fileFilter []FileFilter) error
+ // Set the selected item from the list of file filters (set using SetFileFilters) by its index. Defaults to 0 (the first item in the list) if not called.
+ SetSelectedFileFilterIndex(index uint) error
+ // Sets the default extension applied when a user does not provide one as part of the file name.
+ // If the user selects a different file filter, the default extension will be automatically updated to match the new file filter.
+ // For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists.
+ // For Save File Dialog, this extension will be used whenever a user does not specify an extension.
+ SetDefaultExtension(defaultExtension string) error
+}
+
+type OpenFileDialog interface {
+ FileDialog
+}
+
+type OpenMultipleFilesDialog interface {
+ FileDialog
+ // Show the dialog to the user.
+ // Blocks until the user has closed the dialog and returns the selected files.
+ ShowAndGetResults() ([]string, error)
+ // Gets the selected file paths, as absolute paths eg. "C:\Folder\file.txt"
+ GetResults() ([]string, error)
+}
+
+type SelectFolderDialog interface {
+ Dialog
+}
+
+type SaveFileDialog interface { // TODO Properties
+ FileDialog
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go
new file mode 100644
index 000000000..3ab969850
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_nonWindows.go
@@ -0,0 +1,28 @@
+//go:build !windows
+// +build !windows
+
+package cfd
+
+import "fmt"
+
+var unsupportedError = fmt.Errorf("common file dialogs are only available on windows")
+
+// TODO doc
+func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) {
+ return nil, unsupportedError
+}
+
+// TODO doc
+func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) {
+ return nil, unsupportedError
+}
+
+// TODO doc
+func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) {
+ return nil, unsupportedError
+}
+
+// TODO doc
+func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) {
+ return nil, unsupportedError
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go
new file mode 100644
index 000000000..69f46118e
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/CommonFileDialog_windows.go
@@ -0,0 +1,79 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import "github.com/go-ole/go-ole"
+
+func initialize() {
+ // Swallow error
+ _ = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE)
+}
+
+// TODO doc
+func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) {
+ initialize()
+
+ openDialog, err := newIFileOpenDialog()
+ if err != nil {
+ return nil, err
+ }
+ err = config.apply(openDialog)
+ if err != nil {
+ return nil, err
+ }
+ return openDialog, nil
+}
+
+// TODO doc
+func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) {
+ initialize()
+
+ openDialog, err := newIFileOpenDialog()
+ if err != nil {
+ return nil, err
+ }
+ err = config.apply(openDialog)
+ if err != nil {
+ return nil, err
+ }
+ err = openDialog.setIsMultiselect(true)
+ if err != nil {
+ return nil, err
+ }
+ return openDialog, nil
+}
+
+// TODO doc
+func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) {
+ initialize()
+
+ openDialog, err := newIFileOpenDialog()
+ if err != nil {
+ return nil, err
+ }
+ err = config.apply(openDialog)
+ if err != nil {
+ return nil, err
+ }
+ err = openDialog.setPickFolders(true)
+ if err != nil {
+ return nil, err
+ }
+ return openDialog, nil
+}
+
+// TODO doc
+func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) {
+ initialize()
+
+ saveDialog, err := newIFileSaveDialog()
+ if err != nil {
+ return nil, err
+ }
+ err = config.apply(saveDialog)
+ if err != nil {
+ return nil, err
+ }
+ return saveDialog, nil
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/DialogConfig.go b/v3/internal/go-common-file-dialog/cfd/DialogConfig.go
new file mode 100644
index 000000000..221dbef27
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/DialogConfig.go
@@ -0,0 +1,120 @@
+// Cross-platform.
+
+package cfd
+
+type FileFilter struct {
+ // The display name of the filter (That is shown to the user)
+ DisplayName string
+ // The filter pattern. Eg. "*.txt;*.png" to select all txt and png files, "*.*" to select any files, etc.
+ Pattern string
+}
+
+type DialogConfig struct {
+ // The title of the dialog
+ Title string
+ // The role of the dialog. This is used to derive the dialog's GUID, which the
+ // OS will use to differentiate it from dialogs that are intended for other purposes.
+ // This means that, for example, a dialog with role "Import" will have a different
+ // previous location that it will open to than a dialog with role "Open". Can be any string.
+ Role string
+ // The default folder - the folder that is used the first time the user opens it
+ // (after the first time their last used location is used).
+ DefaultFolder string
+ // The initial folder - the folder that the dialog always opens to if not empty.
+ // If this is not empty, it will override the "default folder" behaviour and
+ // the dialog will always open to this folder.
+ Folder string
+ // The file filters that restrict which types of files the dialog is able to choose.
+ // Ignored by Select Folder Dialog.
+ FileFilters []FileFilter
+ // Sets the initially selected file filter. This is an index of FileFilters.
+ // Ignored by Select Folder Dialog.
+ SelectedFileFilterIndex uint
+ // The initial name of the file (I.E. the text in the file name text box) when the user opens the dialog.
+ // For the Select Folder Dialog, this sets the initial folder name.
+ FileName string
+ // The default extension applied when a user does not provide one as part of the file name.
+ // If the user selects a different file filter, the default extension will be automatically updated to match the new file filter.
+ // For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists.
+ // For Save File Dialog, this extension will be used whenever a user does not specify an extension.
+ // Ignored by Select Folder Dialog.
+ DefaultExtension string
+ // ParentWindowHandle is the handle (HWND) to the parent window of the dialog.
+ // If left as 0 / nil, the dialog will have no parent window.
+ ParentWindowHandle uintptr
+}
+
+var defaultFilters = []FileFilter{
+ {
+ DisplayName: "All Files (*.*)",
+ Pattern: "*.*",
+ },
+}
+
+func (config *DialogConfig) apply(dialog Dialog) (err error) {
+ if config.Title != "" {
+ err = dialog.SetTitle(config.Title)
+ if err != nil {
+ return
+ }
+ }
+
+ if config.Role != "" {
+ err = dialog.SetRole(config.Role)
+ if err != nil {
+ return
+ }
+ }
+
+ if config.Folder != "" {
+ err = dialog.SetFolder(config.Folder)
+ if err != nil {
+ return
+ }
+ }
+
+ if config.DefaultFolder != "" {
+ err = dialog.SetDefaultFolder(config.DefaultFolder)
+ if err != nil {
+ return
+ }
+ }
+
+ if config.FileName != "" {
+ err = dialog.SetFileName(config.FileName)
+ if err != nil {
+ return
+ }
+ }
+
+ dialog.SetParentWindowHandle(config.ParentWindowHandle)
+
+ if dialog, ok := dialog.(FileDialog); ok {
+ var fileFilters []FileFilter
+ if config.FileFilters != nil && len(config.FileFilters) > 0 {
+ fileFilters = config.FileFilters
+ } else {
+ fileFilters = defaultFilters
+ }
+ err = dialog.SetFileFilters(fileFilters)
+ if err != nil {
+ return
+ }
+
+ if config.SelectedFileFilterIndex != 0 {
+ err = dialog.SetSelectedFileFilterIndex(config.SelectedFileFilterIndex)
+ if err != nil {
+ return
+ }
+ }
+
+ if config.DefaultExtension != "" {
+ err = dialog.SetDefaultExtension(config.DefaultExtension)
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/errors.go b/v3/internal/go-common-file-dialog/cfd/errors.go
new file mode 100644
index 000000000..c097c8eb2
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/errors.go
@@ -0,0 +1,7 @@
+package cfd
+
+import "errors"
+
+var (
+ ErrorCancelled = errors.New("cancelled by user")
+)
diff --git a/v3/internal/go-common-file-dialog/cfd/iFileOpenDialog.go b/v3/internal/go-common-file-dialog/cfd/iFileOpenDialog.go
new file mode 100644
index 000000000..42f83814a
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/iFileOpenDialog.go
@@ -0,0 +1,201 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import (
+ "github.com/go-ole/go-ole"
+ "github.com/google/uuid"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ fileOpenDialogCLSID = ole.NewGUID("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}")
+ fileOpenDialogIID = ole.NewGUID("{d57c7288-d4ad-4768-be02-9d969532d960}")
+)
+
+type iFileOpenDialog struct {
+ vtbl *iFileOpenDialogVtbl
+ parentWindowHandle uintptr
+}
+
+type iFileOpenDialogVtbl struct {
+ iFileDialogVtbl
+
+ GetResults uintptr // func (ppenum **IShellItemArray) HRESULT
+ GetSelectedItems uintptr
+}
+
+func newIFileOpenDialog() (*iFileOpenDialog, error) {
+ if unknown, err := ole.CreateInstance(fileOpenDialogCLSID, fileOpenDialogIID); err == nil {
+ return (*iFileOpenDialog)(unsafe.Pointer(unknown)), nil
+ } else {
+ return nil, err
+ }
+}
+
+func (fileOpenDialog *iFileOpenDialog) Show() error {
+ return fileOpenDialog.vtbl.show(unsafe.Pointer(fileOpenDialog), fileOpenDialog.parentWindowHandle)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetParentWindowHandle(hwnd uintptr) {
+ fileOpenDialog.parentWindowHandle = hwnd
+}
+
+func (fileOpenDialog *iFileOpenDialog) ShowAndGetResult() (string, error) {
+ isMultiselect, err := fileOpenDialog.isMultiselect()
+ if err != nil {
+ return "", err
+ }
+ if isMultiselect {
+ // We should panic as this error is caused by the developer using the library
+ panic("use ShowAndGetResults for open multiple files dialog")
+ }
+ if err := fileOpenDialog.Show(); err != nil {
+ return "", err
+ }
+ return fileOpenDialog.GetResult()
+}
+
+func (fileOpenDialog *iFileOpenDialog) ShowAndGetResults() ([]string, error) {
+ isMultiselect, err := fileOpenDialog.isMultiselect()
+ if err != nil {
+ return nil, err
+ }
+ if !isMultiselect {
+ // We should panic as this error is caused by the developer using the library
+ panic("use ShowAndGetResult for open single file dialog")
+ }
+ if err := fileOpenDialog.Show(); err != nil {
+ return nil, err
+ }
+ return fileOpenDialog.GetResults()
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetTitle(title string) error {
+ return fileOpenDialog.vtbl.setTitle(unsafe.Pointer(fileOpenDialog), title)
+}
+
+func (fileOpenDialog *iFileOpenDialog) GetResult() (string, error) {
+ isMultiselect, err := fileOpenDialog.isMultiselect()
+ if err != nil {
+ return "", err
+ }
+ if isMultiselect {
+ // We should panic as this error is caused by the developer using the library
+ panic("use GetResults for open multiple files dialog")
+ }
+ return fileOpenDialog.vtbl.getResultString(unsafe.Pointer(fileOpenDialog))
+}
+
+func (fileOpenDialog *iFileOpenDialog) Release() error {
+ return fileOpenDialog.vtbl.release(unsafe.Pointer(fileOpenDialog))
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetDefaultFolder(defaultFolderPath string) error {
+ return fileOpenDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetFolder(defaultFolderPath string) error {
+ return fileOpenDialog.vtbl.setFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetFileFilters(filter []FileFilter) error {
+ return fileOpenDialog.vtbl.setFileTypes(unsafe.Pointer(fileOpenDialog), filter)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetRole(role string) error {
+ return fileOpenDialog.vtbl.setClientGuid(unsafe.Pointer(fileOpenDialog), StringToUUID(role))
+}
+
+// This should only be callable when the user asks for a multi select because
+// otherwise they will be given the Dialog interface which does not expose this function.
+func (fileOpenDialog *iFileOpenDialog) GetResults() ([]string, error) {
+ isMultiselect, err := fileOpenDialog.isMultiselect()
+ if err != nil {
+ return nil, err
+ }
+ if !isMultiselect {
+ // We should panic as this error is caused by the developer using the library
+ panic("use GetResult for open single file dialog")
+ }
+ return fileOpenDialog.vtbl.getResultsStrings(unsafe.Pointer(fileOpenDialog))
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetDefaultExtension(defaultExtension string) error {
+ return fileOpenDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileOpenDialog), defaultExtension)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetFileName(initialFileName string) error {
+ return fileOpenDialog.vtbl.setFileName(unsafe.Pointer(fileOpenDialog), initialFileName)
+}
+
+func (fileOpenDialog *iFileOpenDialog) SetSelectedFileFilterIndex(index uint) error {
+ return fileOpenDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileOpenDialog), index)
+}
+
+func (fileOpenDialog *iFileOpenDialog) setPickFolders(pickFolders bool) error {
+ const FosPickfolders = 0x20
+ if pickFolders {
+ return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
+ } else {
+ return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
+ }
+}
+
+const FosAllowMultiselect = 0x200
+
+func (fileOpenDialog *iFileOpenDialog) isMultiselect() (bool, error) {
+ options, err := fileOpenDialog.vtbl.getOptions(unsafe.Pointer(fileOpenDialog))
+ if err != nil {
+ return false, err
+ }
+ return options&FosAllowMultiselect != 0, nil
+}
+
+func (fileOpenDialog *iFileOpenDialog) setIsMultiselect(isMultiselect bool) error {
+ if isMultiselect {
+ return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
+ } else {
+ return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
+ }
+}
+
+func (vtbl *iFileOpenDialogVtbl) getResults(objPtr unsafe.Pointer) (*iShellItemArray, error) {
+ var shellItemArray *iShellItemArray
+ ret, _, _ := syscall.Syscall(vtbl.GetResults,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(&shellItemArray)),
+ 0)
+ return shellItemArray, hresultToError(ret)
+}
+
+func (vtbl *iFileOpenDialogVtbl) getResultsStrings(objPtr unsafe.Pointer) ([]string, error) {
+ shellItemArray, err := vtbl.getResults(objPtr)
+ if err != nil {
+ return nil, err
+ }
+ if shellItemArray == nil {
+ return nil, ErrorCancelled
+ }
+ defer shellItemArray.vtbl.release(unsafe.Pointer(shellItemArray))
+ count, err := shellItemArray.vtbl.getCount(unsafe.Pointer(shellItemArray))
+ if err != nil {
+ return nil, err
+ }
+ var results []string
+ for i := uintptr(0); i < count; i++ {
+ newItem, err := shellItemArray.vtbl.getItemAt(unsafe.Pointer(shellItemArray), i)
+ if err != nil {
+ return nil, err
+ }
+ results = append(results, newItem)
+ }
+ return results, nil
+}
+
+func StringToUUID(str string) *ole.GUID {
+ return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String())
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/iFileSaveDialog.go b/v3/internal/go-common-file-dialog/cfd/iFileSaveDialog.go
new file mode 100644
index 000000000..ddee7b246
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/iFileSaveDialog.go
@@ -0,0 +1,92 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import (
+ "github.com/go-ole/go-ole"
+ "unsafe"
+)
+
+var (
+ saveFileDialogCLSID = ole.NewGUID("{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}")
+ saveFileDialogIID = ole.NewGUID("{84bccd23-5fde-4cdb-aea4-af64b83d78ab}")
+)
+
+type iFileSaveDialog struct {
+ vtbl *iFileSaveDialogVtbl
+ parentWindowHandle uintptr
+}
+
+type iFileSaveDialogVtbl struct {
+ iFileDialogVtbl
+
+ SetSaveAsItem uintptr
+ SetProperties uintptr
+ SetCollectedProperties uintptr
+ GetProperties uintptr
+ ApplyProperties uintptr
+}
+
+func newIFileSaveDialog() (*iFileSaveDialog, error) {
+ if unknown, err := ole.CreateInstance(saveFileDialogCLSID, saveFileDialogIID); err == nil {
+ return (*iFileSaveDialog)(unsafe.Pointer(unknown)), nil
+ } else {
+ return nil, err
+ }
+}
+
+func (fileSaveDialog *iFileSaveDialog) Show() error {
+ return fileSaveDialog.vtbl.show(unsafe.Pointer(fileSaveDialog), fileSaveDialog.parentWindowHandle)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetParentWindowHandle(hwnd uintptr) {
+ fileSaveDialog.parentWindowHandle = hwnd
+}
+
+func (fileSaveDialog *iFileSaveDialog) ShowAndGetResult() (string, error) {
+ if err := fileSaveDialog.Show(); err != nil {
+ return "", err
+ }
+ return fileSaveDialog.GetResult()
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetTitle(title string) error {
+ return fileSaveDialog.vtbl.setTitle(unsafe.Pointer(fileSaveDialog), title)
+}
+
+func (fileSaveDialog *iFileSaveDialog) GetResult() (string, error) {
+ return fileSaveDialog.vtbl.getResultString(unsafe.Pointer(fileSaveDialog))
+}
+
+func (fileSaveDialog *iFileSaveDialog) Release() error {
+ return fileSaveDialog.vtbl.release(unsafe.Pointer(fileSaveDialog))
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetDefaultFolder(defaultFolderPath string) error {
+ return fileSaveDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetFolder(defaultFolderPath string) error {
+ return fileSaveDialog.vtbl.setFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetFileFilters(filter []FileFilter) error {
+ return fileSaveDialog.vtbl.setFileTypes(unsafe.Pointer(fileSaveDialog), filter)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetRole(role string) error {
+ return fileSaveDialog.vtbl.setClientGuid(unsafe.Pointer(fileSaveDialog), StringToUUID(role))
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetDefaultExtension(defaultExtension string) error {
+ return fileSaveDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileSaveDialog), defaultExtension)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetFileName(initialFileName string) error {
+ return fileSaveDialog.vtbl.setFileName(unsafe.Pointer(fileSaveDialog), initialFileName)
+}
+
+func (fileSaveDialog *iFileSaveDialog) SetSelectedFileFilterIndex(index uint) error {
+ return fileSaveDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileSaveDialog), index)
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/iShellItem.go b/v3/internal/go-common-file-dialog/cfd/iShellItem.go
new file mode 100644
index 000000000..6a747f4d9
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/iShellItem.go
@@ -0,0 +1,53 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import (
+ "github.com/go-ole/go-ole"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ procSHCreateItemFromParsingName = syscall.NewLazyDLL("Shell32.dll").NewProc("SHCreateItemFromParsingName")
+ iidShellItem = ole.NewGUID("43826d1e-e718-42ee-bc55-a1e261c37bfe")
+)
+
+type iShellItem struct {
+ vtbl *iShellItemVtbl
+}
+
+type iShellItemVtbl struct {
+ iUnknownVtbl
+ BindToHandler uintptr
+ GetParent uintptr
+ GetDisplayName uintptr // func (sigdnName SIGDN, ppszName *LPWSTR) HRESULT
+ GetAttributes uintptr
+ Compare uintptr
+}
+
+func newIShellItem(path string) (*iShellItem, error) {
+ var shellItem *iShellItem
+ pathPtr := ole.SysAllocString(path)
+ ret, _, _ := procSHCreateItemFromParsingName.Call(
+ uintptr(unsafe.Pointer(pathPtr)),
+ 0,
+ uintptr(unsafe.Pointer(iidShellItem)),
+ uintptr(unsafe.Pointer(&shellItem)))
+ return shellItem, hresultToError(ret)
+}
+
+func (vtbl *iShellItemVtbl) getDisplayName(objPtr unsafe.Pointer) (string, error) {
+ var ptr *uint16
+ ret, _, _ := syscall.Syscall(vtbl.GetDisplayName,
+ 2,
+ uintptr(objPtr),
+ 0x80058000, // SIGDN_FILESYSPATH
+ uintptr(unsafe.Pointer(&ptr)))
+ if err := hresultToError(ret); err != nil {
+ return "", err
+ }
+ defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(ptr)))
+ return ole.LpOleStrToString(ptr), nil
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/iShellItemArray.go b/v3/internal/go-common-file-dialog/cfd/iShellItemArray.go
new file mode 100644
index 000000000..84f26fa20
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/iShellItemArray.go
@@ -0,0 +1,67 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import (
+ "github.com/go-ole/go-ole"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ iidShellItemArrayGUID = "{b63ea76d-1f85-456f-a19c-48159efa858b}"
+)
+
+var (
+ iidShellItemArray *ole.GUID
+)
+
+func init() {
+ iidShellItemArray, _ = ole.IIDFromString(iidShellItemArrayGUID)
+}
+
+type iShellItemArray struct {
+ vtbl *iShellItemArrayVtbl
+}
+
+type iShellItemArrayVtbl struct {
+ iUnknownVtbl
+ BindToHandler uintptr
+ GetPropertyStore uintptr
+ GetPropertyDescriptionList uintptr
+ GetAttributes uintptr
+ GetCount uintptr // func (pdwNumItems *DWORD) HRESULT
+ GetItemAt uintptr // func (dwIndex DWORD, ppsi **IShellItem) HRESULT
+ EnumItems uintptr
+}
+
+func (vtbl *iShellItemArrayVtbl) getCount(objPtr unsafe.Pointer) (uintptr, error) {
+ var count uintptr
+ ret, _, _ := syscall.Syscall(vtbl.GetCount,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(&count)),
+ 0)
+ if err := hresultToError(ret); err != nil {
+ return 0, err
+ }
+ return count, nil
+}
+
+func (vtbl *iShellItemArrayVtbl) getItemAt(objPtr unsafe.Pointer, index uintptr) (string, error) {
+ var shellItem *iShellItem
+ ret, _, _ := syscall.Syscall(vtbl.GetItemAt,
+ 2,
+ uintptr(objPtr),
+ index,
+ uintptr(unsafe.Pointer(&shellItem)))
+ if err := hresultToError(ret); err != nil {
+ return "", err
+ }
+ if shellItem == nil {
+ return "", ErrorCancelled
+ }
+ defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
+ return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem))
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/vtblCommon.go b/v3/internal/go-common-file-dialog/cfd/vtblCommon.go
new file mode 100644
index 000000000..21015c27c
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/vtblCommon.go
@@ -0,0 +1,48 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+type comDlgFilterSpec struct {
+ pszName *int16
+ pszSpec *int16
+}
+
+type iUnknownVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+}
+
+type iModalWindowVtbl struct {
+ iUnknownVtbl
+ Show uintptr // func (hwndOwner HWND) HRESULT
+}
+
+type iFileDialogVtbl struct {
+ iModalWindowVtbl
+ SetFileTypes uintptr // func (cFileTypes UINT, rgFilterSpec *COMDLG_FILTERSPEC) HRESULT
+ SetFileTypeIndex uintptr // func(iFileType UINT) HRESULT
+ GetFileTypeIndex uintptr
+ Advise uintptr
+ Unadvise uintptr
+ SetOptions uintptr // func (fos FILEOPENDIALOGOPTIONS) HRESULT
+ GetOptions uintptr // func (pfos *FILEOPENDIALOGOPTIONS) HRESULT
+ SetDefaultFolder uintptr // func (psi *IShellItem) HRESULT
+ SetFolder uintptr // func (psi *IShellItem) HRESULT
+ GetFolder uintptr
+ GetCurrentSelection uintptr
+ SetFileName uintptr // func (pszName LPCWSTR) HRESULT
+ GetFileName uintptr
+ SetTitle uintptr // func(pszTitle LPCWSTR) HRESULT
+ SetOkButtonLabel uintptr
+ SetFileNameLabel uintptr
+ GetResult uintptr // func (ppsi **IShellItem) HRESULT
+ AddPlace uintptr
+ SetDefaultExtension uintptr // func (pszDefaultExtension LPCWSTR) HRESULT
+ // This can only be used from a callback.
+ Close uintptr
+ SetClientGuid uintptr // func (guid REFGUID) HRESULT
+ ClearClientData uintptr
+ SetFilter uintptr
+}
diff --git a/v3/internal/go-common-file-dialog/cfd/vtblCommonFunc.go b/v3/internal/go-common-file-dialog/cfd/vtblCommonFunc.go
new file mode 100644
index 000000000..a92100010
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfd/vtblCommonFunc.go
@@ -0,0 +1,227 @@
+//go:build windows
+// +build windows
+
+package cfd
+
+import (
+ "fmt"
+ "github.com/go-ole/go-ole"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+func hresultToError(hr uintptr) error {
+ if hr < 0 {
+ return ole.NewError(hr)
+ }
+ return nil
+}
+
+func (vtbl *iUnknownVtbl) release(objPtr unsafe.Pointer) error {
+ ret, _, _ := syscall.Syscall(vtbl.Release,
+ 0,
+ uintptr(objPtr),
+ 0,
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iModalWindowVtbl) show(objPtr unsafe.Pointer, hwnd uintptr) error {
+ ret, _, _ := syscall.Syscall(vtbl.Show,
+ 1,
+ uintptr(objPtr),
+ hwnd,
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setFileTypes(objPtr unsafe.Pointer, filters []FileFilter) error {
+ cFileTypes := len(filters)
+ if cFileTypes < 0 {
+ return fmt.Errorf("must specify at least one filter")
+ }
+ comDlgFilterSpecs := make([]comDlgFilterSpec, cFileTypes)
+ for i := 0; i < cFileTypes; i++ {
+ filter := &filters[i]
+ comDlgFilterSpecs[i] = comDlgFilterSpec{
+ pszName: ole.SysAllocString(filter.DisplayName),
+ pszSpec: ole.SysAllocString(filter.Pattern),
+ }
+ }
+ ret, _, _ := syscall.Syscall(vtbl.SetFileTypes,
+ 2,
+ uintptr(objPtr),
+ uintptr(cFileTypes),
+ uintptr(unsafe.Pointer(&comDlgFilterSpecs[0])))
+ return hresultToError(ret)
+}
+
+// Options are:
+// FOS_OVERWRITEPROMPT = 0x2,
+// FOS_STRICTFILETYPES = 0x4,
+// FOS_NOCHANGEDIR = 0x8,
+// FOS_PICKFOLDERS = 0x20,
+// FOS_FORCEFILESYSTEM = 0x40,
+// FOS_ALLNONSTORAGEITEMS = 0x80,
+// FOS_NOVALIDATE = 0x100,
+// FOS_ALLOWMULTISELECT = 0x200,
+// FOS_PATHMUSTEXIST = 0x800,
+// FOS_FILEMUSTEXIST = 0x1000,
+// FOS_CREATEPROMPT = 0x2000,
+// FOS_SHAREAWARE = 0x4000,
+// FOS_NOREADONLYRETURN = 0x8000,
+// FOS_NOTESTFILECREATE = 0x10000,
+// FOS_HIDEMRUPLACES = 0x20000,
+// FOS_HIDEPINNEDPLACES = 0x40000,
+// FOS_NODEREFERENCELINKS = 0x100000,
+// FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
+// FOS_DONTADDTORECENT = 0x2000000,
+// FOS_FORCESHOWHIDDEN = 0x10000000,
+// FOS_DEFAULTNOMINIMODE = 0x20000000,
+// FOS_FORCEPREVIEWPANEON = 0x40000000,
+// FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
+func (vtbl *iFileDialogVtbl) setOptions(objPtr unsafe.Pointer, options uint32) error {
+ ret, _, _ := syscall.Syscall(vtbl.SetOptions,
+ 1,
+ uintptr(objPtr),
+ uintptr(options),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) getOptions(objPtr unsafe.Pointer) (uint32, error) {
+ var options uint32
+ ret, _, _ := syscall.Syscall(vtbl.GetOptions,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(&options)),
+ 0)
+ return options, hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) addOption(objPtr unsafe.Pointer, option uint32) error {
+ if options, err := vtbl.getOptions(objPtr); err == nil {
+ return vtbl.setOptions(objPtr, options|option)
+ } else {
+ return err
+ }
+}
+
+func (vtbl *iFileDialogVtbl) removeOption(objPtr unsafe.Pointer, option uint32) error {
+ if options, err := vtbl.getOptions(objPtr); err == nil {
+ return vtbl.setOptions(objPtr, options&^option)
+ } else {
+ return err
+ }
+}
+
+func (vtbl *iFileDialogVtbl) setDefaultFolder(objPtr unsafe.Pointer, path string) error {
+ shellItem, err := newIShellItem(path)
+ if err != nil {
+ return err
+ }
+ defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
+ ret, _, _ := syscall.Syscall(vtbl.SetDefaultFolder,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(shellItem)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setFolder(objPtr unsafe.Pointer, path string) error {
+ shellItem, err := newIShellItem(path)
+ if err != nil {
+ return err
+ }
+ defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
+ ret, _, _ := syscall.Syscall(vtbl.SetFolder,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(shellItem)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setTitle(objPtr unsafe.Pointer, title string) error {
+ titlePtr := ole.SysAllocString(title)
+ ret, _, _ := syscall.Syscall(vtbl.SetTitle,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(titlePtr)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) close(objPtr unsafe.Pointer) error {
+ ret, _, _ := syscall.Syscall(vtbl.Close,
+ 1,
+ uintptr(objPtr),
+ 0,
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) getResult(objPtr unsafe.Pointer) (*iShellItem, error) {
+ var shellItem *iShellItem
+ ret, _, _ := syscall.Syscall(vtbl.GetResult,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(&shellItem)),
+ 0)
+ return shellItem, hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) getResultString(objPtr unsafe.Pointer) (string, error) {
+ shellItem, err := vtbl.getResult(objPtr)
+ if err != nil {
+ return "", err
+ }
+ if shellItem == nil {
+ return "", ErrorCancelled
+ }
+ defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
+ return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem))
+}
+
+func (vtbl *iFileDialogVtbl) setClientGuid(objPtr unsafe.Pointer, guid *ole.GUID) error {
+ ret, _, _ := syscall.Syscall(vtbl.SetClientGuid,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(guid)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setDefaultExtension(objPtr unsafe.Pointer, defaultExtension string) error {
+ if defaultExtension[0] == '.' {
+ defaultExtension = strings.TrimPrefix(defaultExtension, ".")
+ }
+ defaultExtensionPtr := ole.SysAllocString(defaultExtension)
+ ret, _, _ := syscall.Syscall(vtbl.SetDefaultExtension,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(defaultExtensionPtr)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setFileName(objPtr unsafe.Pointer, fileName string) error {
+ fileNamePtr := ole.SysAllocString(fileName)
+ ret, _, _ := syscall.Syscall(vtbl.SetFileName,
+ 1,
+ uintptr(objPtr),
+ uintptr(unsafe.Pointer(fileNamePtr)),
+ 0)
+ return hresultToError(ret)
+}
+
+func (vtbl *iFileDialogVtbl) setSelectedFileFilterIndex(objPtr unsafe.Pointer, index uint) error {
+ ret, _, _ := syscall.Syscall(vtbl.SetFileTypeIndex,
+ 1,
+ uintptr(objPtr),
+ uintptr(index+1), // SetFileTypeIndex counts from 1
+ 0)
+ return hresultToError(ret)
+}
diff --git a/v3/internal/go-common-file-dialog/cfdutil/CFDUtil.go b/v3/internal/go-common-file-dialog/cfdutil/CFDUtil.go
new file mode 100644
index 000000000..aa3a783b2
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/cfdutil/CFDUtil.go
@@ -0,0 +1,45 @@
+package cfdutil
+
+import (
+ "github.com/wailsapp/wails/v3/internal/go-common-file-dialog/cfd"
+)
+
+// TODO doc
+func ShowOpenFileDialog(config cfd.DialogConfig) (string, error) {
+ dialog, err := cfd.NewOpenFileDialog(config)
+ if err != nil {
+ return "", err
+ }
+ defer dialog.Release()
+ return dialog.ShowAndGetResult()
+}
+
+// TODO doc
+func ShowOpenMultipleFilesDialog(config cfd.DialogConfig) ([]string, error) {
+ dialog, err := cfd.NewOpenMultipleFilesDialog(config)
+ if err != nil {
+ return nil, err
+ }
+ defer dialog.Release()
+ return dialog.ShowAndGetResults()
+}
+
+// TODO doc
+func ShowPickFolderDialog(config cfd.DialogConfig) (string, error) {
+ dialog, err := cfd.NewSelectFolderDialog(config)
+ if err != nil {
+ return "", err
+ }
+ defer dialog.Release()
+ return dialog.ShowAndGetResult()
+}
+
+// TODO doc
+func ShowSaveFileDialog(config cfd.DialogConfig) (string, error) {
+ dialog, err := cfd.NewSaveFileDialog(config)
+ if err != nil {
+ return "", err
+ }
+ defer dialog.Release()
+ return dialog.ShowAndGetResult()
+}
diff --git a/v3/internal/go-common-file-dialog/util/util.go b/v3/internal/go-common-file-dialog/util/util.go
new file mode 100644
index 000000000..723fbedc0
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/util/util.go
@@ -0,0 +1,10 @@
+package util
+
+import (
+ "github.com/go-ole/go-ole"
+ "github.com/google/uuid"
+)
+
+func StringToUUID(str string) *ole.GUID {
+ return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String())
+}
diff --git a/v3/internal/go-common-file-dialog/util/util_test.go b/v3/internal/go-common-file-dialog/util/util_test.go
new file mode 100644
index 000000000..2e8ffeb05
--- /dev/null
+++ b/v3/internal/go-common-file-dialog/util/util_test.go
@@ -0,0 +1,14 @@
+package util
+
+import (
+ "github.com/go-ole/go-ole"
+ "testing"
+)
+
+func TestStringToUUID(t *testing.T) {
+ generated := *StringToUUID("TestTestTest")
+ expected := *ole.NewGUID("7933985F-2C87-5A5B-A26E-5D0326829AC2")
+ if generated != expected {
+ t.Errorf("not equal. expected %s, found %s", expected.String(), generated.String())
+ }
+}
diff --git a/v3/internal/runtime/.gitignore b/v3/internal/runtime/.gitignore
new file mode 100644
index 000000000..cdd93f315
--- /dev/null
+++ b/v3/internal/runtime/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+.task
\ No newline at end of file
diff --git a/v3/internal/runtime/Taskfile.yaml b/v3/internal/runtime/Taskfile.yaml
new file mode 100644
index 000000000..7cbdc6b18
--- /dev/null
+++ b/v3/internal/runtime/Taskfile.yaml
@@ -0,0 +1,108 @@
+# https://taskfile.dev
+
+version: "3"
+
+tasks:
+ install-deps:
+ internal: true
+ sources:
+ - package.json
+ cmds:
+ - npm install
+
+ test:
+ cmds:
+ - npx vitest run
+
+ update:
+ cmds:
+ - npx npm-check-updates -u
+
+ build:debug:
+ internal: true
+ cmds:
+ - npx esbuild desktop/main.js --bundle --tree-shaking=true --sourcemap=inline --outfile=runtime_debug_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
+
+ build:debug:windows:
+ cmds:
+ - task: build:debug
+ vars:
+ WINDOWS: true
+ DARWIN: false
+ LINUX: false
+ PLATFORM: windows
+ INVOKE: "chrome.webview.postMessage"
+
+ build:debug:linux:
+ cmds:
+ - task: build:debug
+ vars:
+ WINDOWS: false
+ DARWIN: false
+ LINUX: true
+ PLATFORM: linux
+ INVOKE: "webkit.messageHandlers.external.postMessage"
+
+ build:debug:darwin:
+ cmds:
+ - task: build:debug
+ vars:
+ WINDOWS: false
+ DARWIN: true
+ LINUX: false
+ PLATFORM: darwin
+ INVOKE: "webkit.messageHandlers.external.postMessage"
+
+ build:production:
+ internal: true
+ cmds:
+ - npx esbuild desktop/main.js --bundle --tree-shaking=true --minify --outfile=runtime_production_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
+
+ build:production:windows:
+ cmds:
+ - task: build:production
+ vars:
+ WINDOWS: true
+ DARWIN: false
+ LINUX: false
+ PLATFORM: windows
+ INVOKE: "chrome.webview.postMessage"
+
+ build:production:linux:
+ cmds:
+ - task: build:production
+ vars:
+ WINDOWS: false
+ DARWIN: false
+ LINUX: true
+ PLATFORM: linux
+ INVOKE: "webkit.messageHandlers.external.postMessage"
+
+ build:production:darwin:
+ cmds:
+ - task: build:production
+ vars:
+ WINDOWS: false
+ DARWIN: true
+ LINUX: false
+ PLATFORM: darwin
+ INVOKE: "webkit.messageHandlers.external.postMessage"
+
+ build:all:
+ internal: true
+ deps:
+ - build:debug:windows
+ - build:debug:linux
+ - build:debug:darwin
+ - build:production:windows
+ - build:production:linux
+ - build:production:darwin
+
+ cmds:
+ - cmd: echo "Build Complete."
+
+ build:
+ deps:
+ - install-deps
+ cmds:
+ - task: build:all
diff --git a/v3/internal/runtime/desktop/README.md b/v3/internal/runtime/desktop/README.md
index bd4d5d0ab..78ef387e4 100644
--- a/v3/internal/runtime/desktop/README.md
+++ b/v3/internal/runtime/desktop/README.md
@@ -1,3 +1,3 @@
# README
-After updating any files in this directory, you must run `wails task build-runtime` to regenerate the compiled JS.
\ No newline at end of file
+After updating any files in this directory, you must run `wails task build:runtime` to regenerate the compiled JS.
\ No newline at end of file
diff --git a/v3/internal/runtime/desktop/drag.js b/v3/internal/runtime/desktop/drag.js
new file mode 100644
index 000000000..78c1efd36
--- /dev/null
+++ b/v3/internal/runtime/desktop/drag.js
@@ -0,0 +1,69 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+/* jshint esversion: 9 */
+
+import {invoke} from "./invoke";
+
+let shouldDrag = false;
+
+export function dragTest(e) {
+ let val = window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");
+ if (val) {
+ val = val.trim();
+ }
+
+ if (val !== "drag") {
+ return false;
+ }
+
+ // Only process the primary button
+ if (e.buttons !== 1) {
+ return false;
+ }
+
+ return e.detail === 1;
+}
+
+export function setupDrag() {
+ window.addEventListener('mousedown', onMouseDown);
+ window.addEventListener('mousemove', onMouseMove);
+ window.addEventListener('mouseup', onMouseUp);
+}
+
+function onMouseDown(e) {
+ if (dragTest(e)) {
+ // Ignore drag on scrollbars
+ if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
+ return;
+ }
+ shouldDrag = true;
+ } else {
+ shouldDrag = false;
+ }
+}
+
+function onMouseUp(e) {
+ document.body.style.cursor = window.wails.previousCursor || 'auto';
+ shouldDrag = false;
+}
+
+function onMouseMove(e) {
+ if (shouldDrag) {
+ shouldDrag = false;
+ let mousePressed = e.buttons !== undefined ? e.buttons : e.which;
+ if (mousePressed > 0) {
+ window.wails.previousCursor = document.body.style.cursor;
+ document.body.style.cursor = 'grab';
+ invoke("drag");
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v3/internal/runtime/desktop/invoke.js b/v3/internal/runtime/desktop/invoke.js
new file mode 100644
index 000000000..144066de1
--- /dev/null
+++ b/v3/internal/runtime/desktop/invoke.js
@@ -0,0 +1,14 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+/* jshint esversion: 9 */
+
+// defined in the Taskfile
+export let invoke = (WINDOWS?chrome.webview.postMessage:window.webkit.messageHandlers.external.postMessage);
diff --git a/v3/internal/runtime/desktop/main.js b/v3/internal/runtime/desktop/main.js
index 26b4e9de9..e5a2439ed 100644
--- a/v3/internal/runtime/desktop/main.js
+++ b/v3/internal/runtime/desktop/main.js
@@ -20,6 +20,7 @@ import {dispatchWailsEvent, Emit, Off, OffAll, On, Once, OnMultiple} from "./eve
import {dialogCallback, dialogErrorCallback, Error, Info, OpenFile, Question, SaveFile, Warning,} from "./dialogs";
import {enableContextMenus} from "./contextmenu";
import {reloadWML} from "./wml";
+import {setupDrag} from "./drag";
window.wails = {
...newRuntime(null),
@@ -78,6 +79,8 @@ if (DEBUG) {
enableContextMenus(true);
+setupDrag();
+
document.addEventListener("DOMContentLoaded", function(event) {
reloadWML();
});
\ No newline at end of file
diff --git a/v3/internal/runtime/package-lock.json b/v3/internal/runtime/package-lock.json
index a029e31be..c822ec225 100644
--- a/v3/internal/runtime/package-lock.json
+++ b/v3/internal/runtime/package-lock.json
@@ -9,7 +9,7 @@
"version": "3.0.0",
"license": "ISC",
"devDependencies": {
- "esbuild": "^0.17.5",
+ "esbuild": "^0.17.19",
"happy-dom": "^8.1.5",
"nanoid": "^4.0.0",
"npm-check-updates": "^16.6.3",
@@ -18,9 +18,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.5.tgz",
- "integrity": "sha512-crmPUzgCmF+qZXfl1YkiFoUta2XAfixR1tEnr/gXIixE+WL8Z0BGqfydP5oox0EUOgQMMRgtATtakyAcClQVqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
"cpu": [
"arm"
],
@@ -34,9 +34,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.5.tgz",
- "integrity": "sha512-KHWkDqYAMmKZjY4RAN1PR96q6UOtfkWlTS8uEwWxdLtkRt/0F/csUhXIrVfaSIFxnscIBMPynGfhsMwQDRIBQw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
"cpu": [
"arm64"
],
@@ -50,9 +50,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.5.tgz",
- "integrity": "sha512-8fI/AnIdmWz/+1iza2WrCw8kwXK9wZp/yZY/iS8ioC+U37yJCeppi9EHY05ewJKN64ASoBIseufZROtcFnX5GA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
"cpu": [
"x64"
],
@@ -66,9 +66,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.5.tgz",
- "integrity": "sha512-EAvaoyIySV6Iif3NQCglUNpnMfHSUgC5ugt2efl3+QDntucJe5spn0udNZjTgNi6tKVqSceOw9tQ32liNZc1Xw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
"cpu": [
"arm64"
],
@@ -82,9 +82,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.5.tgz",
- "integrity": "sha512-ha7QCJh1fuSwwCgoegfdaljowwWozwTDjBgjD3++WAy/qwee5uUi1gvOg2WENJC6EUyHBOkcd3YmLDYSZ2TPPA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
"cpu": [
"x64"
],
@@ -98,9 +98,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.5.tgz",
- "integrity": "sha512-VbdXJkn2aI2pQ/wxNEjEcnEDwPpxt3CWWMFYmO7CcdFBoOsABRy2W8F3kjbF9F/pecEUDcI3b5i2w+By4VQFPg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
"cpu": [
"arm64"
],
@@ -114,9 +114,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.5.tgz",
- "integrity": "sha512-olgGYND1/XnnWxwhjtY3/ryjOG/M4WfcA6XH8dBTH1cxMeBemMODXSFhkw71Kf4TeZFFTN25YOomaNh0vq2iXg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
"cpu": [
"x64"
],
@@ -130,9 +130,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.5.tgz",
- "integrity": "sha512-YBdCyQwA3OQupi6W2/WO4FnI+NWFWe79cZEtlbqSESOHEg7a73htBIRiE6uHPQe7Yp5E4aALv+JxkRLGEUL7tw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
"cpu": [
"arm"
],
@@ -146,9 +146,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.5.tgz",
- "integrity": "sha512-8a0bqSwu3OlLCfu2FBbDNgQyBYdPJh1B9PvNX7jMaKGC9/KopgHs37t+pQqeMLzcyRqG6z55IGNQAMSlCpBuqg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
"cpu": [
"arm64"
],
@@ -162,9 +162,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.5.tgz",
- "integrity": "sha512-uCwm1r/+NdP7vndctgq3PoZrnmhmnecWAr114GWMRwg2QMFFX+kIWnp7IO220/JLgnXK/jP7VKAFBGmeOYBQYQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
"cpu": [
"ia32"
],
@@ -178,9 +178,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.5.tgz",
- "integrity": "sha512-3YxhSBl5Sb6TtBjJu+HP93poBruFzgXmf3PVfIe4xOXMj1XpxboYZyw3W8BhoX/uwxzZz4K1I99jTE/5cgDT1g==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
"cpu": [
"loong64"
],
@@ -194,9 +194,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.5.tgz",
- "integrity": "sha512-Hy5Z0YVWyYHdtQ5mfmfp8LdhVwGbwVuq8mHzLqrG16BaMgEmit2xKO+iDakHs+OetEx0EN/2mUzDdfdktI+Nmg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
"cpu": [
"mips64el"
],
@@ -210,9 +210,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.5.tgz",
- "integrity": "sha512-5dbQvBLbU/Y3Q4ABc9gi23hww1mQcM7KZ9KBqabB7qhJswYMf8WrDDOSw3gdf3p+ffmijMd28mfVMvFucuECyg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
"cpu": [
"ppc64"
],
@@ -226,9 +226,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.5.tgz",
- "integrity": "sha512-fp/KUB/ZPzEWGTEUgz9wIAKCqu7CjH1GqXUO2WJdik1UNBQ7Xzw7myIajpxztE4Csb9504ERiFMxZg5KZ6HlZQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
"cpu": [
"riscv64"
],
@@ -242,9 +242,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.5.tgz",
- "integrity": "sha512-kRV3yw19YDqHTp8SfHXfObUFXlaiiw4o2lvT1XjsPZ++22GqZwSsYWJLjMi1Sl7j9qDlDUduWDze/nQx0d6Lzw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
"cpu": [
"s390x"
],
@@ -258,9 +258,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.5.tgz",
- "integrity": "sha512-vnxuhh9e4pbtABNLbT2ANW4uwQ/zvcHRCm1JxaYkzSehugoFd5iXyC4ci1nhXU13mxEwCnrnTIiiSGwa/uAF1g==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
"cpu": [
"x64"
],
@@ -274,9 +274,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.5.tgz",
- "integrity": "sha512-cigBpdiSx/vPy7doUyImsQQBnBjV5f1M99ZUlaJckDAJjgXWl6y9W17FIfJTy8TxosEF6MXq+fpLsitMGts2nA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
"cpu": [
"x64"
],
@@ -290,9 +290,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.5.tgz",
- "integrity": "sha512-VdqRqPVIjjZfkf40LrqOaVuhw9EQiAZ/GNCSM2UplDkaIzYVsSnycxcFfAnHdWI8Gyt6dO15KHikbpxwx+xHbw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
"cpu": [
"x64"
],
@@ -306,9 +306,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.5.tgz",
- "integrity": "sha512-ItxPaJ3MBLtI4nK+mALLEoUs6amxsx+J1ibnfcYMkqaCqHST1AkF4aENpBehty3czqw64r/XqL+W9WqU6kc2Qw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
"cpu": [
"x64"
],
@@ -322,9 +322,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.5.tgz",
- "integrity": "sha512-4u2Q6qsJTYNFdS9zHoAi80spzf78C16m2wla4eJPh4kSbRv+BpXIfl6TmBSWupD8e47B1NrTfrOlEuco7mYQtg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
"cpu": [
"arm64"
],
@@ -338,9 +338,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.5.tgz",
- "integrity": "sha512-KYlm+Xu9TXsfTWAcocLuISRtqxKp/Y9ZBVg6CEEj0O5J9mn7YvBKzAszo2j1ndyzUPk+op+Tie2PJeN+BnXGqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
"cpu": [
"ia32"
],
@@ -354,9 +354,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.5.tgz",
- "integrity": "sha512-XgA9qWRqby7xdYXuF6KALsn37QGBMHsdhmnpjfZtYxKxbTOwfnDM6MYi2WuUku5poNaX2n9XGVr20zgT/2QwCw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
"cpu": [
"x64"
],
@@ -1451,9 +1451,9 @@
"dev": true
},
"node_modules/esbuild": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.5.tgz",
- "integrity": "sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
"dev": true,
"hasInstallScript": true,
"bin": {
@@ -1463,28 +1463,28 @@
"node": ">=12"
},
"optionalDependencies": {
- "@esbuild/android-arm": "0.17.5",
- "@esbuild/android-arm64": "0.17.5",
- "@esbuild/android-x64": "0.17.5",
- "@esbuild/darwin-arm64": "0.17.5",
- "@esbuild/darwin-x64": "0.17.5",
- "@esbuild/freebsd-arm64": "0.17.5",
- "@esbuild/freebsd-x64": "0.17.5",
- "@esbuild/linux-arm": "0.17.5",
- "@esbuild/linux-arm64": "0.17.5",
- "@esbuild/linux-ia32": "0.17.5",
- "@esbuild/linux-loong64": "0.17.5",
- "@esbuild/linux-mips64el": "0.17.5",
- "@esbuild/linux-ppc64": "0.17.5",
- "@esbuild/linux-riscv64": "0.17.5",
- "@esbuild/linux-s390x": "0.17.5",
- "@esbuild/linux-x64": "0.17.5",
- "@esbuild/netbsd-x64": "0.17.5",
- "@esbuild/openbsd-x64": "0.17.5",
- "@esbuild/sunos-x64": "0.17.5",
- "@esbuild/win32-arm64": "0.17.5",
- "@esbuild/win32-ia32": "0.17.5",
- "@esbuild/win32-x64": "0.17.5"
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
}
},
"node_modules/esbuild-android-64": {
@@ -5127,156 +5127,156 @@
},
"dependencies": {
"@esbuild/android-arm": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.5.tgz",
- "integrity": "sha512-crmPUzgCmF+qZXfl1YkiFoUta2XAfixR1tEnr/gXIixE+WL8Z0BGqfydP5oox0EUOgQMMRgtATtakyAcClQVqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.5.tgz",
- "integrity": "sha512-KHWkDqYAMmKZjY4RAN1PR96q6UOtfkWlTS8uEwWxdLtkRt/0F/csUhXIrVfaSIFxnscIBMPynGfhsMwQDRIBQw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.5.tgz",
- "integrity": "sha512-8fI/AnIdmWz/+1iza2WrCw8kwXK9wZp/yZY/iS8ioC+U37yJCeppi9EHY05ewJKN64ASoBIseufZROtcFnX5GA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.5.tgz",
- "integrity": "sha512-EAvaoyIySV6Iif3NQCglUNpnMfHSUgC5ugt2efl3+QDntucJe5spn0udNZjTgNi6tKVqSceOw9tQ32liNZc1Xw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.5.tgz",
- "integrity": "sha512-ha7QCJh1fuSwwCgoegfdaljowwWozwTDjBgjD3++WAy/qwee5uUi1gvOg2WENJC6EUyHBOkcd3YmLDYSZ2TPPA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.5.tgz",
- "integrity": "sha512-VbdXJkn2aI2pQ/wxNEjEcnEDwPpxt3CWWMFYmO7CcdFBoOsABRy2W8F3kjbF9F/pecEUDcI3b5i2w+By4VQFPg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.5.tgz",
- "integrity": "sha512-olgGYND1/XnnWxwhjtY3/ryjOG/M4WfcA6XH8dBTH1cxMeBemMODXSFhkw71Kf4TeZFFTN25YOomaNh0vq2iXg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.5.tgz",
- "integrity": "sha512-YBdCyQwA3OQupi6W2/WO4FnI+NWFWe79cZEtlbqSESOHEg7a73htBIRiE6uHPQe7Yp5E4aALv+JxkRLGEUL7tw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.5.tgz",
- "integrity": "sha512-8a0bqSwu3OlLCfu2FBbDNgQyBYdPJh1B9PvNX7jMaKGC9/KopgHs37t+pQqeMLzcyRqG6z55IGNQAMSlCpBuqg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.5.tgz",
- "integrity": "sha512-uCwm1r/+NdP7vndctgq3PoZrnmhmnecWAr114GWMRwg2QMFFX+kIWnp7IO220/JLgnXK/jP7VKAFBGmeOYBQYQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.5.tgz",
- "integrity": "sha512-3YxhSBl5Sb6TtBjJu+HP93poBruFzgXmf3PVfIe4xOXMj1XpxboYZyw3W8BhoX/uwxzZz4K1I99jTE/5cgDT1g==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.5.tgz",
- "integrity": "sha512-Hy5Z0YVWyYHdtQ5mfmfp8LdhVwGbwVuq8mHzLqrG16BaMgEmit2xKO+iDakHs+OetEx0EN/2mUzDdfdktI+Nmg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.5.tgz",
- "integrity": "sha512-5dbQvBLbU/Y3Q4ABc9gi23hww1mQcM7KZ9KBqabB7qhJswYMf8WrDDOSw3gdf3p+ffmijMd28mfVMvFucuECyg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.5.tgz",
- "integrity": "sha512-fp/KUB/ZPzEWGTEUgz9wIAKCqu7CjH1GqXUO2WJdik1UNBQ7Xzw7myIajpxztE4Csb9504ERiFMxZg5KZ6HlZQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.5.tgz",
- "integrity": "sha512-kRV3yw19YDqHTp8SfHXfObUFXlaiiw4o2lvT1XjsPZ++22GqZwSsYWJLjMi1Sl7j9qDlDUduWDze/nQx0d6Lzw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.5.tgz",
- "integrity": "sha512-vnxuhh9e4pbtABNLbT2ANW4uwQ/zvcHRCm1JxaYkzSehugoFd5iXyC4ci1nhXU13mxEwCnrnTIiiSGwa/uAF1g==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.5.tgz",
- "integrity": "sha512-cigBpdiSx/vPy7doUyImsQQBnBjV5f1M99ZUlaJckDAJjgXWl6y9W17FIfJTy8TxosEF6MXq+fpLsitMGts2nA==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.5.tgz",
- "integrity": "sha512-VdqRqPVIjjZfkf40LrqOaVuhw9EQiAZ/GNCSM2UplDkaIzYVsSnycxcFfAnHdWI8Gyt6dO15KHikbpxwx+xHbw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.5.tgz",
- "integrity": "sha512-ItxPaJ3MBLtI4nK+mALLEoUs6amxsx+J1ibnfcYMkqaCqHST1AkF4aENpBehty3czqw64r/XqL+W9WqU6kc2Qw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.5.tgz",
- "integrity": "sha512-4u2Q6qsJTYNFdS9zHoAi80spzf78C16m2wla4eJPh4kSbRv+BpXIfl6TmBSWupD8e47B1NrTfrOlEuco7mYQtg==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.5.tgz",
- "integrity": "sha512-KYlm+Xu9TXsfTWAcocLuISRtqxKp/Y9ZBVg6CEEj0O5J9mn7YvBKzAszo2j1ndyzUPk+op+Tie2PJeN+BnXGqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.5.tgz",
- "integrity": "sha512-XgA9qWRqby7xdYXuF6KALsn37QGBMHsdhmnpjfZtYxKxbTOwfnDM6MYi2WuUku5poNaX2n9XGVr20zgT/2QwCw==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
"dev": true,
"optional": true
},
@@ -6088,33 +6088,33 @@
"dev": true
},
"esbuild": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.5.tgz",
- "integrity": "sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==",
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
"dev": true,
"requires": {
- "@esbuild/android-arm": "0.17.5",
- "@esbuild/android-arm64": "0.17.5",
- "@esbuild/android-x64": "0.17.5",
- "@esbuild/darwin-arm64": "0.17.5",
- "@esbuild/darwin-x64": "0.17.5",
- "@esbuild/freebsd-arm64": "0.17.5",
- "@esbuild/freebsd-x64": "0.17.5",
- "@esbuild/linux-arm": "0.17.5",
- "@esbuild/linux-arm64": "0.17.5",
- "@esbuild/linux-ia32": "0.17.5",
- "@esbuild/linux-loong64": "0.17.5",
- "@esbuild/linux-mips64el": "0.17.5",
- "@esbuild/linux-ppc64": "0.17.5",
- "@esbuild/linux-riscv64": "0.17.5",
- "@esbuild/linux-s390x": "0.17.5",
- "@esbuild/linux-x64": "0.17.5",
- "@esbuild/netbsd-x64": "0.17.5",
- "@esbuild/openbsd-x64": "0.17.5",
- "@esbuild/sunos-x64": "0.17.5",
- "@esbuild/win32-arm64": "0.17.5",
- "@esbuild/win32-ia32": "0.17.5",
- "@esbuild/win32-x64": "0.17.5"
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
}
},
"esbuild-android-64": {
diff --git a/v3/internal/runtime/package.json b/v3/internal/runtime/package.json
index e923ea45a..f8c9c6023 100644
--- a/v3/internal/runtime/package.json
+++ b/v3/internal/runtime/package.json
@@ -7,7 +7,7 @@
"author": "Lea Anthony ",
"license": "ISC",
"devDependencies": {
- "esbuild": "^0.17.5",
+ "esbuild": "^0.17.19",
"happy-dom": "^8.1.5",
"nanoid": "^4.0.0",
"npm-check-updates": "^16.6.3",
diff --git a/v3/internal/runtime/runtime_debug_desktop_darwin.js b/v3/internal/runtime/runtime_debug_desktop_darwin.js
index 0ca537592..4dc032864 100644
--- a/v3/internal/runtime/runtime_debug_desktop_darwin.js
+++ b/v3/internal/runtime/runtime_debug_desktop_darwin.js
@@ -523,6 +523,56 @@
addWMLWindowListeners();
}
+ // desktop/invoke.js
+ var invoke = false ? chrome.webview.postMessage : window.webkit.messageHandlers.external.postMessage;
+
+ // desktop/drag.js
+ var shouldDrag = false;
+ function dragTest(e) {
+ let val = window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");
+ if (val) {
+ val = val.trim();
+ }
+ if (val !== "drag") {
+ return false;
+ }
+ if (e.buttons !== 1) {
+ return false;
+ }
+ return e.detail === 1;
+ }
+ function setupDrag() {
+ window.addEventListener("mousedown", onMouseDown);
+ window.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("mouseup", onMouseUp);
+ }
+ function onMouseDown(e) {
+ if (dragTest(e)) {
+ if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
+ return;
+ }
+ shouldDrag = true;
+ } else {
+ shouldDrag = false;
+ }
+ }
+ function onMouseUp(e) {
+ document.body.style.cursor = window.wails.previousCursor || "auto";
+ shouldDrag = false;
+ }
+ function onMouseMove(e) {
+ if (shouldDrag) {
+ shouldDrag = false;
+ let mousePressed = e.buttons !== void 0 ? e.buttons : e.which;
+ if (mousePressed > 0) {
+ window.wails.previousCursor = document.body.style.cursor;
+ document.body.style.cursor = "grab";
+ invoke("drag");
+ return;
+ }
+ }
+ }
+
// desktop/main.js
window.wails = {
...newRuntime(null)
@@ -575,8 +625,9 @@
console.log("Wails v3.0.0 Debug Mode Enabled");
}
enableContextMenus(true);
+ setupDrag();
document.addEventListener("DOMContentLoaded", function(event) {
reloadWML();
});
})();
-//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvbWFpbi5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNsaXBib2FyZFwiKTtcblxuLyoqXG4gKiBTZXQgdGhlIENsaXBib2FyZCB0ZXh0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTZXRUZXh0KHRleHQpIHtcbiAgICB2b2lkIGNhbGwoXCJTZXRUZXh0XCIsIHt0ZXh0fSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFRleHQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJUZXh0XCIpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5jb25zdCBydW50aW1lVVJMID0gd2luZG93LmxvY2F0aW9uLm9yaWdpbiArIFwiL3dhaWxzL3J1bnRpbWVcIjtcblxuZnVuY3Rpb24gcnVudGltZUNhbGwobWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKSB7XG4gICAgbGV0IHVybCA9IG5ldyBVUkwocnVudGltZVVSTCk7XG4gICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJtZXRob2RcIiwgbWV0aG9kKTtcbiAgICBpZiAoYXJncykge1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChcImFyZ3NcIiwgSlNPTi5zdHJpbmdpZnkoYXJncykpO1xuICAgIH1cbiAgICBsZXQgZmV0Y2hPcHRpb25zID0ge1xuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICB9O1xuICAgIGlmICh3aW5kb3dOYW1lKSB7XG4gICAgICAgIGZldGNoT3B0aW9ucy5oZWFkZXJzW1wieC13YWlscy13aW5kb3ctbmFtZVwiXSA9IHdpbmRvd05hbWU7XG4gICAgfVxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGZldGNoKHVybCwgZmV0Y2hPcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgICAgICAgICAgICAgICAvLyBjaGVjayBjb250ZW50IHR5cGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpICYmIHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpLmluZGV4T2YoXCJhcHBsaWNhdGlvbi9qc29uXCIpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS50ZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVqZWN0KEVycm9yKHJlc3BvbnNlLnN0YXR1c1RleHQpKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihkYXRhID0+IHJlc29sdmUoZGF0YSkpXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4gcmVqZWN0KGVycm9yKSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lQ2FsbGVyKG9iamVjdCwgd2luZG93TmFtZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAobWV0aG9kLCBhcmdzPW51bGwpIHtcbiAgICAgICAgcmV0dXJuIHJ1bnRpbWVDYWxsKG9iamVjdCArIFwiLlwiICsgbWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKTtcbiAgICB9O1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiYXBwbGljYXRpb25cIik7XG5cbi8qKlxuICogSGlkZSB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEhpZGUoKSB7XG4gICAgdm9pZCBjYWxsKFwiSGlkZVwiKTtcbn1cblxuLyoqXG4gKiBTaG93IHRoZSBhcHBsaWNhdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gU2hvdygpIHtcbiAgICB2b2lkIGNhbGwoXCJTaG93XCIpO1xufVxuXG5cbi8qKlxuICogUXVpdCB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XG4gICAgdm9pZCBjYWxsKFwiUXVpdFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImxvZ1wiKTtcblxuLyoqXG4gKiBMb2dzIGEgbWVzc2FnZS5cbiAqIEBwYXJhbSB7bWVzc2FnZX0gTWVzc2FnZSB0byBsb2dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExvZyhtZXNzYWdlKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJMb2dcIiwgbWVzc2FnZSk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuU2NyZWVufSBTY3JlZW5cbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwic2NyZWVuc1wiKTtcblxuLyoqXG4gKiBHZXRzIGFsbCBzY3JlZW5zLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuW10+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gR2V0QWxsKCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0QWxsXCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIHByaW1hcnkgc2NyZWVuLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldFByaW1hcnkoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRQcmltYXJ5XCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIGN1cnJlbnQgYWN0aXZlIHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEN1cnJlbnQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRDdXJyZW50XCIpO1xufSIsICJsZXQgdXJsQWxwaGFiZXQgPVxuICAndXNlYW5kb20tMjZUMTk4MzQwUFg3NXB4SkFDS1ZFUllNSU5EQlVTSFdPTEZfR1FaYmZnaGprbHF2d3l6cmljdCdcbmV4cG9ydCBsZXQgY3VzdG9tQWxwaGFiZXQgPSAoYWxwaGFiZXQsIGRlZmF1bHRTaXplID0gMjEpID0+IHtcbiAgcmV0dXJuIChzaXplID0gZGVmYXVsdFNpemUpID0+IHtcbiAgICBsZXQgaWQgPSAnJ1xuICAgIGxldCBpID0gc2l6ZVxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGlkICs9IGFscGhhYmV0WyhNYXRoLnJhbmRvbSgpICogYWxwaGFiZXQubGVuZ3RoKSB8IDBdXG4gICAgfVxuICAgIHJldHVybiBpZFxuICB9XG59XG5leHBvcnQgbGV0IG5hbm9pZCA9IChzaXplID0gMjEpID0+IHtcbiAgbGV0IGlkID0gJydcbiAgbGV0IGkgPSBzaXplXG4gIHdoaWxlIChpLS0pIHtcbiAgICBpZCArPSB1cmxBbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIDY0KSB8IDBdXG4gIH1cbiAgcmV0dXJuIGlkXG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmltcG9ydCB7IG5hbm9pZCB9IGZyb20gJ25hbm9pZC9ub24tc2VjdXJlJztcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY2FsbFwiKTtcblxubGV0IGNhbGxSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGNhbGxSZXNwb25zZXMuaGFzKHJlc3VsdCkpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWxsQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gY2FsbFJlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbEVycm9yQ2FsbGJhY2soaWQsIG1lc3NhZ2UpIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY2FsbEJpbmRpbmcodHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJjYWxsLWlkXCJdID0gaWQ7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuc2V0KGlkLCB7cmVzb2x2ZSwgcmVqZWN0fSk7XG4gICAgICAgIGNhbGwodHlwZSwgb3B0aW9ucykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENhbGwob3B0aW9ucykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogQ2FsbCBhIHBsdWdpbiBtZXRob2RcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbHVnaW5OYW1lIC0gbmFtZSBvZiB0aGUgcGx1Z2luXG4gKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kTmFtZSAtIG5hbWUgb2YgdGhlIG1ldGhvZFxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgbWV0aG9kXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fSAtIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFBsdWdpbihwbHVnaW5OYW1lLCBtZXRob2ROYW1lLCAuLi5hcmdzKSB7XG4gICAgcmV0dXJuIGNhbGxCaW5kaW5nKFwiQ2FsbFwiLCB7XG4gICAgICAgIHBhY2thZ2VOYW1lOiBcIndhaWxzLXBsdWdpbnNcIixcbiAgICAgICAgc3RydWN0TmFtZTogcGx1Z2luTmFtZSxcbiAgICAgICAgbWV0aG9kTmFtZTogbWV0aG9kTmFtZSxcbiAgICAgICAgYXJnczogYXJncyxcbiAgICB9KTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNpemV9IFNpemVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuLi9hcGkvdHlwZXNcIikuUG9zaXRpb259IFBvc2l0aW9uXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdXaW5kb3cod2luZG93TmFtZSkge1xuICAgIGxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcIndpbmRvd1wiLCB3aW5kb3dOYW1lKTtcbiAgICByZXR1cm4ge1xuICAgICAgICAvLyBSZWxvYWQ6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFJlbG9hZEFwcDogKCkgPT4gY2FsbCgnV1InKSxcbiAgICAgICAgLy8gU2V0U3lzdGVtRGVmYXVsdFRoZW1lOiAoKSA9PiBjYWxsKCdXQVNEVCcpLFxuICAgICAgICAvLyBTZXRMaWdodFRoZW1lOiAoKSA9PiBjYWxsKCdXQUxUJyksXG4gICAgICAgIC8vIFNldERhcmtUaGVtZTogKCkgPT4gY2FsbCgnV0FEVCcpLFxuICAgICAgICAvLyBJc0Z1bGxzY3JlZW46ICgpID0+IGNhbGwoJ1dJRicpLFxuICAgICAgICAvLyBJc01heGltaXplZDogKCkgPT4gY2FsbCgnV0lNJyksXG4gICAgICAgIC8vIElzTWluaW1pemVkOiAoKSA9PiBjYWxsKCdXSU1OJyksXG4gICAgICAgIC8vIElzV2luZG93ZWQ6ICgpID0+IGNhbGwoJ1dJRicpLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENlbnRlcnMgdGhlIHdpbmRvdy5cbiAgICAgICAgICovXG4gICAgICAgIENlbnRlcjogKCkgPT4gdm9pZCBjYWxsKCdDZW50ZXInKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgdGl0bGUuXG4gICAgICAgICAqIEBwYXJhbSB0aXRsZVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0VGl0bGU6ICh0aXRsZSkgPT4gdm9pZCBjYWxsKCdTZXRUaXRsZScsIHt0aXRsZX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYWtlcyB0aGUgd2luZG93IGZ1bGxzY3JlZW4uXG4gICAgICAgICAqL1xuICAgICAgICBGdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ0Z1bGxzY3JlZW4nKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5mdWxsc2NyZWVuIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBVbkZ1bGxzY3JlZW46ICgpID0+IHZvaWQgY2FsbCgnVW5GdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCBUaGUgd2luZG93IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgVGhlIHdpbmRvdyBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiBjYWxsKCdTZXRTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTaXplPn0gVGhlIHdpbmRvdyBzaXplXG4gICAgICAgICAqL1xuICAgICAgICBTaXplOiAoKSA9PiB7IHJldHVybiBjYWxsKCdTaXplJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1heGltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1heFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1heFNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1pbmltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1pblNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1pblNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB3aW5kb3cgdG8gYmUgYWx3YXlzIG9uIHRvcC5cbiAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBvblRvcCBXaGV0aGVyIHRoZSB3aW5kb3cgc2hvdWxkIGJlIGFsd2F5cyBvbiB0b3BcbiAgICAgICAgICovXG4gICAgICAgIFNldEFsd2F5c09uVG9wOiAob25Ub3ApID0+IHZvaWQgY2FsbCgnU2V0QWx3YXlzT25Ub3AnLCB7YWx3YXlzT25Ub3A6b25Ub3B9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XG4gICAgICAgICAqL1xuICAgICAgICBTZXRQb3NpdGlvbjogKHgsIHkpID0+IGNhbGwoJ1NldFBvc2l0aW9uJywge3gseX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBwb3NpdGlvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8UG9zaXRpb24+fSBUaGUgd2luZG93IHBvc2l0aW9uXG4gICAgICAgICAqL1xuICAgICAgICBQb3NpdGlvbjogKCkgPT4geyByZXR1cm4gY2FsbCgnUG9zaXRpb24nKTsgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBzY3JlZW4gdGhlIHdpbmRvdyBpcyBvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAgICAgICAgICovXG4gICAgICAgIFNjcmVlbjogKCkgPT4geyByZXR1cm4gY2FsbCgnU2NyZWVuJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhpZGUgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgSGlkZTogKCkgPT4gdm9pZCBjYWxsKCdIaWRlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIE1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ01heGltaXNlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNob3cgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgU2hvdzogKCkgPT4gdm9pZCBjYWxsKCdTaG93JyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENsb3NlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIENsb3NlOiAoKSA9PiB2b2lkIGNhbGwoJ0Nsb3NlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRvZ2dsZSB0aGUgd2luZG93IG1heGltaXNlIHN0YXRlXG4gICAgICAgICAqL1xuICAgICAgICBUb2dnbGVNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdUb2dnbGVNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNaW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNaW5pbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1pbmltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGJhY2tncm91bmQgY29sb3VyIG9mIHRoZSB3aW5kb3cuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gZyAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGIgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0QmFja2dyb3VuZENvbG91cjogKHIsIGcsIGIsIGEpID0+IHZvaWQgY2FsbCgnU2V0QmFja2dyb3VuZENvbG91cicsIHtyLCBnLCBiLCBhfSksXG4gICAgfTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5XYWlsc0V2ZW50fSBXYWlsc0V2ZW50XG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImV2ZW50c1wiKTtcblxuLyoqXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcbiAqXG4gKiBAY2xhc3MgTGlzdGVuZXJcbiAqL1xuY2xhc3MgTGlzdGVuZXIge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICAgICAqIEBtZW1iZXJvZiBMaXN0ZW5lclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgICAgICB0aGlzLmV2ZW50TmFtZSA9IGV2ZW50TmFtZTtcbiAgICAgICAgLy8gRGVmYXVsdCBvZiAtMSBtZWFucyBpbmZpbml0ZVxuICAgICAgICB0aGlzLm1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2soZGF0YSk7XG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhDYWxsYmFja3MgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRGVjcmVtZW50IG1heENhbGxiYWNrcy4gUmV0dXJuIHRydWUgaWYgbm93IDAsIG90aGVyd2lzZSBmYWxzZVxuICAgICAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgLT0gMTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm1heENhbGxiYWNrcyA9PT0gMDtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBXYWlsc0V2ZW50IGRlZmluZXMgYSBjdXN0b20gZXZlbnQuIEl0IGlzIHBhc3NlZCB0byBldmVudCBsaXN0ZW5lcnMuXG4gKlxuICogQGNsYXNzIFdhaWxzRXZlbnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAqIEBwcm9wZXJ0eSB7YW55fSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gKi9cbmV4cG9ydCBjbGFzcyBXYWlsc0V2ZW50IHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFdhaWxzRXZlbnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBOYW1lIG9mIHRoZSBldmVudFxuICAgICAqIEBwYXJhbSB7YW55PW51bGx9IGRhdGEgLSBEYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGUgZXZlbnRcbiAgICAgKiBAbWVtYmVyb2YgV2FpbHNFdmVudFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKG5hbWUsIGRhdGEgPSBudWxsKSB7XG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgZXZlbnRMaXN0ZW5lcnMgPSBuZXcgTWFwKCk7XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGBtYXhDYWxsYmFja3NgIHRpbWVzIGJlZm9yZSBiZWluZyBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpIHx8IFtdO1xuICAgIGNvbnN0IHRoaXNMaXN0ZW5lciA9IG5ldyBMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xuICAgIGxpc3RlbmVycy5wdXNoKHRoaXNMaXN0ZW5lcik7XG4gICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50TmFtZSwgbGlzdGVuZXJzKTtcbiAgICByZXR1cm4gKCkgPT4gbGlzdGVuZXJPZmYodGhpc0xpc3RlbmVyKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgZXZlcnkgdGltZSB0aGUgZXZlbnQgaXMgZW1pdHRlZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FuY2VsIHRoZSBsaXN0ZW5lclxuICovXG5leHBvcnQgZnVuY3Rpb24gT24oZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uY2UoZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xufVxuXG4vKipcbiAqIGxpc3RlbmVyT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT25cbiAqXG4gKiBAcGFyYW0ge0xpc3RlbmVyfSBsaXN0ZW5lclxuICovXG5mdW5jdGlvbiBsaXN0ZW5lck9mZihsaXN0ZW5lcikge1xuICAgIGNvbnN0IGV2ZW50TmFtZSA9IGxpc3RlbmVyLmV2ZW50TmFtZTtcbiAgICAvLyBSZW1vdmUgbG9jYWwgbGlzdGVuZXJcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50TmFtZSkuZmlsdGVyKGwgPT4gbCAhPT0gbGlzdGVuZXIpO1xuICAgIGlmIChsaXN0ZW5lcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudE5hbWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgfVxufVxuXG4vKipcbiAqIGRpc3BhdGNoZXMgYW4gZXZlbnQgdG8gYWxsIGxpc3RlbmVyc1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7V2FpbHNFdmVudH0gZXZlbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpc3BhdGNoV2FpbHNFdmVudChldmVudCkge1xuICAgIGNvbnNvbGUubG9nKFwiZGlzcGF0Y2hpbmcgZXZlbnQ6IFwiLCB7ZXZlbnR9KTtcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50Lm5hbWUpO1xuICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgICAgLy8gaXRlcmF0ZSBsaXN0ZW5lcnMgYW5kIGNhbGwgY2FsbGJhY2suIElmIGNhbGxiYWNrIHJldHVybnMgdHJ1ZSwgcmVtb3ZlIGxpc3RlbmVyXG4gICAgICAgIGxldCB0b1JlbW92ZSA9IFtdO1xuICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaChsaXN0ZW5lciA9PiB7XG4gICAgICAgICAgICBsZXQgcmVtb3ZlID0gbGlzdGVuZXIuQ2FsbGJhY2soZXZlbnQpO1xuICAgICAgICAgICAgaWYgKHJlbW92ZSkge1xuICAgICAgICAgICAgICAgIHRvUmVtb3ZlLnB1c2gobGlzdGVuZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gcmVtb3ZlIGxpc3RlbmVyc1xuICAgICAgICBpZiAodG9SZW1vdmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgbGlzdGVuZXJzID0gbGlzdGVuZXJzLmZpbHRlcihsID0+ICF0b1JlbW92ZS5pbmNsdWRlcyhsKSk7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudC5uYW1lKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50Lm5hbWUsIGxpc3RlbmVycyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT24sXG4gKiBvcHRpb25hbGx5IG11bHRpcGxlIGxpc3RlbmVycyBjYW4gYmUgdW5yZWdpc3RlcmVkIHZpYSBgYWRkaXRpb25hbEV2ZW50TmFtZXNgXG4gKlxuIFt2MyBDSEFOR0VdIE9mZiBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtICB7Li4uc3RyaW5nfSBhZGRpdGlvbmFsRXZlbnROYW1lc1xuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmKGV2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXMpIHtcbiAgICBsZXQgZXZlbnRzVG9SZW1vdmUgPSBbZXZlbnROYW1lLCAuLi5hZGRpdGlvbmFsRXZlbnROYW1lc107XG4gICAgZXZlbnRzVG9SZW1vdmUuZm9yRWFjaChldmVudE5hbWUgPT4ge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBPZmZBbGwgdW5yZWdpc3RlcnMgYWxsIGxpc3RlbmVyc1xuICogW3YzIENIQU5HRV0gT2ZmQWxsIG9ubHkgdW5yZWdpc3RlcnMgbGlzdGVuZXJzIHdpdGhpbiB0aGUgY3VycmVudCB3aW5kb3dcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPZmZBbGwoKSB7XG4gICAgZXZlbnRMaXN0ZW5lcnMuY2xlYXIoKTtcbn1cblxuLyoqXG4gKiBFbWl0IGFuIGV2ZW50XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50IFRoZSBldmVudCB0byBlbWl0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFbWl0KGV2ZW50KSB7XG4gICAgdm9pZCBjYWxsKFwiRW1pdFwiLCBldmVudCk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk1lc3NhZ2VEaWFsb2dPcHRpb25zfSBNZXNzYWdlRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk9wZW5EaWFsb2dPcHRpb25zfSBPcGVuRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNhdmVEaWFsb2dPcHRpb25zfSBTYXZlRGlhbG9nT3B0aW9uc1xuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImRpYWxvZ1wiKTtcblxubGV0IGRpYWxvZ1Jlc3BvbnNlcyA9IG5ldyBNYXAoKTtcblxuZnVuY3Rpb24gZ2VuZXJhdGVJRCgpIHtcbiAgICBsZXQgcmVzdWx0O1xuICAgIGRvIHtcbiAgICAgICAgcmVzdWx0ID0gbmFub2lkKCk7XG4gICAgfSB3aGlsZSAoZGlhbG9nUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgaWYgKGlzSlNPTikge1xuICAgICAgICAgICAgcC5yZXNvbHZlKEpTT04ucGFyc2UoZGF0YSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICB9XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cbmV4cG9ydCBmdW5jdGlvbiBkaWFsb2dFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBkaWFsb2dSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBkaWFsb2codHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJkaWFsb2ctaWRcIl0gPSBpZDtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIFNob3dzIGFuIEluZm8gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBJbmZvKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiSW5mb1wiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBXYXJuaW5nIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2FybmluZyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIldhcm5pbmdcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gRXJyb3IgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFcnJvcihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkVycm9yXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGEgUXVlc3Rpb24gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWVzdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlF1ZXN0aW9uXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIE9wZW4gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXXxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlIG9yIGFuIGFycmF5IG9mIHNlbGVjdGVkIGZpbGVzIGlmIEFsbG93c011bHRpcGxlU2VsZWN0aW9uIGlzIHRydWUuIEEgYmxhbmsgc3RyaW5nIGlzIHJldHVybmVkIGlmIG5vIGZpbGUgd2FzIHNlbGVjdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gT3BlbkZpbGUob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJPcGVuRmlsZVwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFNhdmUgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNhdmVGaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiU2F2ZUZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbiIsICJpbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY29udGV4dG1lbnVcIik7XG5cbmZ1bmN0aW9uIG9wZW5Db250ZXh0TWVudShpZCwgeCwgeSwgZGF0YSkge1xuICAgIHJldHVybiBjYWxsKFwiT3BlbkNvbnRleHRNZW51XCIsIHtpZCwgeCwgeSwgZGF0YX0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29udGV4dE1lbnVzKGVuYWJsZWQpIHtcbiAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGNvbnRleHRNZW51SGFuZGxlcik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBjb250ZXh0TWVudUhhbmRsZXIoZXZlbnQpIHtcbiAgICBwcm9jZXNzQ29udGV4dE1lbnUoZXZlbnQudGFyZ2V0LCBldmVudCk7XG59XG5cbmZ1bmN0aW9uIHByb2Nlc3NDb250ZXh0TWVudShlbGVtZW50LCBldmVudCkge1xuICAgIGxldCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51Jyk7XG4gICAgaWYgKGlkKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIG9wZW5Db250ZXh0TWVudShpZCwgZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtY29udGV4dG1lbnUtZGF0YScpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgcGFyZW50ID0gZWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgICAgICBpZiAocGFyZW50KSB7XG4gICAgICAgICAgICBwcm9jZXNzQ29udGV4dE1lbnUocGFyZW50LCBldmVudCk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCAiXG5pbXBvcnQge0VtaXQsIFdhaWxzRXZlbnR9IGZyb20gXCIuL2V2ZW50c1wiO1xuaW1wb3J0IHtRdWVzdGlvbn0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuXG5mdW5jdGlvbiBzZW5kRXZlbnQoZXZlbnROYW1lLCBkYXRhPW51bGwpIHtcbiAgICBsZXQgZXZlbnQgPSBuZXcgV2FpbHNFdmVudChldmVudE5hbWUsIGRhdGEpO1xuICAgIEVtaXQoZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxFdmVudExpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC1ldmVudF0nKTtcbiAgICBlbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGV2ZW50VHlwZSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1ldmVudCcpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VuZEV2ZW50KGV2ZW50VHlwZSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcblxuICAgICAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuXG4gICAgICAgIC8vIEFkZCBuZXcgbGlzdGVuZXJcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gY2FsbFdpbmRvd01ldGhvZChtZXRob2QpIHtcbiAgICBpZiAod2FpbHMuV2luZG93W21ldGhvZF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIldpbmRvdyBtZXRob2QgXCIgKyBtZXRob2QgKyBcIiBub3QgZm91bmRcIik7XG4gICAgfVxuICAgIHdhaWxzLldpbmRvd1ttZXRob2RdKCk7XG59XG5cbmZ1bmN0aW9uIGFkZFdNTFdpbmRvd0xpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC13aW5kb3ddJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCB3aW5kb3dNZXRob2QgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtd2luZG93Jyk7XG4gICAgICAgIGNvbnN0IGNvbmZpcm0gPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtY29uZmlybScpO1xuICAgICAgICBjb25zdCB0cmlnZ2VyID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXRyaWdnZXInKSB8fCBcImNsaWNrXCI7XG5cbiAgICAgICAgbGV0IGNhbGxiYWNrID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKGNvbmZpcm0pIHtcbiAgICAgICAgICAgICAgICBRdWVzdGlvbih7VGl0bGU6IFwiQ29uZmlybVwiLCBNZXNzYWdlOmNvbmZpcm0sIEJ1dHRvbnM6W3tMYWJlbDpcIlllc1wifSx7TGFiZWw6XCJOb1wiLCBJc0RlZmF1bHQ6dHJ1ZX1dfSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQgIT09IFwiTm9cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWxvYWRXTUwoKSB7XG4gICAgYWRkV01MRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuXG5pbXBvcnQgKiBhcyBDbGlwYm9hcmQgZnJvbSAnLi9jbGlwYm9hcmQnO1xuaW1wb3J0ICogYXMgQXBwbGljYXRpb24gZnJvbSAnLi9hcHBsaWNhdGlvbic7XG5pbXBvcnQgKiBhcyBMb2cgZnJvbSAnLi9sb2cnO1xuaW1wb3J0ICogYXMgU2NyZWVucyBmcm9tICcuL3NjcmVlbnMnO1xuaW1wb3J0IHtQbHVnaW4sIENhbGwsIGNhbGxFcnJvckNhbGxiYWNrLCBjYWxsQ2FsbGJhY2t9IGZyb20gXCIuL2NhbGxzXCI7XG5pbXBvcnQge25ld1dpbmRvd30gZnJvbSBcIi4vd2luZG93XCI7XG5pbXBvcnQge2Rpc3BhdGNoV2FpbHNFdmVudCwgRW1pdCwgT2ZmLCBPZmZBbGwsIE9uLCBPbmNlLCBPbk11bHRpcGxlfSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7ZGlhbG9nQ2FsbGJhY2ssIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssIEVycm9yLCBJbmZvLCBPcGVuRmlsZSwgUXVlc3Rpb24sIFNhdmVGaWxlLCBXYXJuaW5nLH0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuaW1wb3J0IHtlbmFibGVDb250ZXh0TWVudXN9IGZyb20gXCIuL2NvbnRleHRtZW51XCI7XG5pbXBvcnQge3JlbG9hZFdNTH0gZnJvbSBcIi4vd21sXCI7XG5cbndpbmRvdy53YWlscyA9IHtcbiAgICAuLi5uZXdSdW50aW1lKG51bGwpLFxufTtcblxuLy8gSW50ZXJuYWwgd2FpbHMgZW5kcG9pbnRzXG53aW5kb3cuX3dhaWxzID0ge1xuICAgIGRpYWxvZ0NhbGxiYWNrLFxuICAgIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssXG4gICAgZGlzcGF0Y2hXYWlsc0V2ZW50LFxuICAgIGNhbGxDYWxsYmFjayxcbiAgICBjYWxsRXJyb3JDYWxsYmFjayxcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lKHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBDbGlwYm9hcmQ6IHtcbiAgICAgICAgICAgIC4uLkNsaXBib2FyZFxuICAgICAgICB9LFxuICAgICAgICBBcHBsaWNhdGlvbjoge1xuICAgICAgICAgICAgLi4uQXBwbGljYXRpb24sXG4gICAgICAgICAgICBHZXRXaW5kb3dCeU5hbWUod2luZG93TmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXdSdW50aW1lKHdpbmRvd05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBMb2csXG4gICAgICAgIFNjcmVlbnMsXG4gICAgICAgIENhbGwsXG4gICAgICAgIFBsdWdpbixcbiAgICAgICAgV01MOiB7XG4gICAgICAgICAgICBSZWxvYWQ6IHJlbG9hZFdNTCxcbiAgICAgICAgfSxcbiAgICAgICAgRGlhbG9nOiB7XG4gICAgICAgICAgICBJbmZvLFxuICAgICAgICAgICAgV2FybmluZyxcbiAgICAgICAgICAgIEVycm9yLFxuICAgICAgICAgICAgUXVlc3Rpb24sXG4gICAgICAgICAgICBPcGVuRmlsZSxcbiAgICAgICAgICAgIFNhdmVGaWxlLFxuICAgICAgICB9LFxuICAgICAgICBFdmVudHM6IHtcbiAgICAgICAgICAgIEVtaXQsXG4gICAgICAgICAgICBPbixcbiAgICAgICAgICAgIE9uY2UsXG4gICAgICAgICAgICBPbk11bHRpcGxlLFxuICAgICAgICAgICAgT2ZmLFxuICAgICAgICAgICAgT2ZmQWxsLFxuICAgICAgICB9LFxuICAgICAgICBXaW5kb3c6IG5ld1dpbmRvdyh3aW5kb3dOYW1lKSxcbiAgICB9O1xufVxuXG5pZiAoREVCVUcpIHtcbiAgICBjb25zb2xlLmxvZyhcIldhaWxzIHYzLjAuMCBEZWJ1ZyBNb2RlIEVuYWJsZWRcIik7XG59XG5cbmVuYWJsZUNvbnRleHRNZW51cyh0cnVlKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDcEMsWUFBTSxLQUFLLFlBQVksRUFDbEIsS0FBSyxjQUFZO0FBQ2QsWUFBSSxTQUFTLElBQUk7QUFFYixjQUFJLFNBQVMsUUFBUSxJQUFJLGNBQWMsS0FBSyxTQUFTLFFBQVEsSUFBSSxjQUFjLEVBQUUsUUFBUSxrQkFBa0IsTUFBTSxJQUFJO0FBQ2pILG1CQUFPLFNBQVMsS0FBSztBQUFBLFVBQ3pCLE9BQU87QUFDSCxtQkFBTyxTQUFTLEtBQUs7QUFBQSxVQUN6QjtBQUFBLFFBQ0o7QUFDQSxlQUFPLE1BQU0sU0FBUyxVQUFVLENBQUM7QUFBQSxNQUNyQyxDQUFDLEVBQ0EsS0FBSyxVQUFRLFFBQVEsSUFBSSxDQUFDLEVBQzFCLE1BQU0sV0FBUyxPQUFPLEtBQUss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QUFJLENBQUMsRUFBQyxDQUFDLEVBQUUsS0FBSyxTQUFVLFFBQVE7QUFDdkgsZ0JBQUksV0FBVyxNQUFNO0FBQ2pCLCtCQUFpQixZQUFZO0FBQUEsWUFDakM7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSx5QkFBaUIsWUFBWTtBQUFBLE1BQ2pDO0FBR0EsY0FBUSxvQkFBb0IsU0FBUyxRQUFRO0FBRzdDLGNBQVEsaUJBQWlCLFNBQVMsUUFBUTtBQUFBLElBQzlDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxZQUFZO0FBQ3hCLHlCQUFxQjtBQUNyQiwwQkFBc0I7QUFBQSxFQUMxQjs7O0FDbERBLFNBQU8sUUFBUTtBQUFBLElBQ1gsR0FBRyxXQUFXLElBQUk7QUFBQSxFQUN0QjtBQUdBLFNBQU8sU0FBUztBQUFBLElBQ1o7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDSjtBQUVPLFdBQVMsV0FBVyxZQUFZO0FBQ25DLFdBQU87QUFBQSxNQUNILFdBQVc7QUFBQSxRQUNQLEdBQUc7QUFBQSxNQUNQO0FBQUEsTUFDQSxhQUFhO0FBQUEsUUFDVCxHQUFHO0FBQUEsUUFDSCxnQkFBZ0JDLGFBQVk7QUFDeEIsaUJBQU8sV0FBV0EsV0FBVTtBQUFBLFFBQ2hDO0FBQUEsTUFDSjtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBLEtBQUs7QUFBQSxRQUNELFFBQVE7QUFBQSxNQUNaO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBLE9BQUFDO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUTtBQUFBLFFBQ0o7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLE1BQ0o7QUFBQSxNQUNBLFFBQVEsVUFBVSxVQUFVO0FBQUEsSUFDaEM7QUFBQSxFQUNKO0FBRUEsTUFBSSxNQUFPO0FBQ1AsWUFBUSxJQUFJLGlDQUFpQztBQUFBLEVBQ2pEO0FBRUEscUJBQW1CLElBQUk7QUFFdkIsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvaW52b2tlLmpzIiwgImRlc2t0b3AvZHJhZy5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJjbGlwYm9hcmRcIik7XG5cbi8qKlxuICogU2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICovXG5leHBvcnQgZnVuY3Rpb24gU2V0VGV4dCh0ZXh0KSB7XG4gICAgdm9pZCBjYWxsKFwiU2V0VGV4dFwiLCB7dGV4dH0pO1xufVxuXG4vKipcbiAqIEdldCB0aGUgQ2xpcGJvYXJkIHRleHRcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBUZXh0KCkge1xuICAgIHJldHVybiBjYWxsKFwiVGV4dFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuY29uc3QgcnVudGltZVVSTCA9IHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gKyBcIi93YWlscy9ydW50aW1lXCI7XG5cbmZ1bmN0aW9uIHJ1bnRpbWVDYWxsKG1ldGhvZCwgd2luZG93TmFtZSwgYXJncykge1xuICAgIGxldCB1cmwgPSBuZXcgVVJMKHJ1bnRpbWVVUkwpO1xuICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKFwibWV0aG9kXCIsIG1ldGhvZCk7XG4gICAgaWYgKGFyZ3MpIHtcbiAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJhcmdzXCIsIEpTT04uc3RyaW5naWZ5KGFyZ3MpKTtcbiAgICB9XG4gICAgbGV0IGZldGNoT3B0aW9ucyA9IHtcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgfTtcbiAgICBpZiAod2luZG93TmFtZSkge1xuICAgICAgICBmZXRjaE9wdGlvbnMuaGVhZGVyc1tcIngtd2FpbHMtd2luZG93LW5hbWVcIl0gPSB3aW5kb3dOYW1lO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBmZXRjaCh1cmwsIGZldGNoT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgY29udGVudCB0eXBlXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKSAmJiByZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKS5pbmRleE9mKFwiYXBwbGljYXRpb24vanNvblwiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UudGV4dCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlamVjdChFcnJvcihyZXNwb25zZS5zdGF0dXNUZXh0KSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZGF0YSA9PiByZXNvbHZlKGRhdGEpKVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHJlamVjdChlcnJvcikpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbmV3UnVudGltZUNhbGxlcihvYmplY3QsIHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG1ldGhvZCwgYXJncz1udWxsKSB7XG4gICAgICAgIHJldHVybiBydW50aW1lQ2FsbChvYmplY3QgKyBcIi5cIiArIG1ldGhvZCwgd2luZG93TmFtZSwgYXJncyk7XG4gICAgfTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImFwcGxpY2F0aW9uXCIpO1xuXG4vKipcbiAqIEhpZGUgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBIaWRlKCkge1xuICAgIHZvaWQgY2FsbChcIkhpZGVcIik7XG59XG5cbi8qKlxuICogU2hvdyB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNob3coKSB7XG4gICAgdm9pZCBjYWxsKFwiU2hvd1wiKTtcbn1cblxuXG4vKipcbiAqIFF1aXQgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWl0KCkge1xuICAgIHZvaWQgY2FsbChcIlF1aXRcIik7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJsb2dcIik7XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuXG4gKiBAcGFyYW0ge21lc3NhZ2V9IE1lc3NhZ2UgdG8gbG9nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2cobWVzc2FnZSkge1xuICAgIHJldHVybiBjYWxsKFwiTG9nXCIsIG1lc3NhZ2UpO1xufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcInNjcmVlbnNcIik7XG5cbi8qKlxuICogR2V0cyBhbGwgc2NyZWVucy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbltdPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEFsbCgpIHtcbiAgICByZXR1cm4gY2FsbChcIkdldEFsbFwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBwcmltYXJ5IHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRQcmltYXJ5KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0UHJpbWFyeVwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBjdXJyZW50IGFjdGl2ZSBzY3JlZW4uXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTY3JlZW4+fVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRDdXJyZW50KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0Q3VycmVudFwiKTtcbn0iLCAibGV0IHVybEFscGhhYmV0ID1cbiAgJ3VzZWFuZG9tLTI2VDE5ODM0MFBYNzVweEpBQ0tWRVJZTUlOREJVU0hXT0xGX0dRWmJmZ2hqa2xxdnd5enJpY3QnXG5leHBvcnQgbGV0IGN1c3RvbUFscGhhYmV0ID0gKGFscGhhYmV0LCBkZWZhdWx0U2l6ZSA9IDIxKSA9PiB7XG4gIHJldHVybiAoc2l6ZSA9IGRlZmF1bHRTaXplKSA9PiB7XG4gICAgbGV0IGlkID0gJydcbiAgICBsZXQgaSA9IHNpemVcbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICBpZCArPSBhbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIGFscGhhYmV0Lmxlbmd0aCkgfCAwXVxuICAgIH1cbiAgICByZXR1cm4gaWRcbiAgfVxufVxuZXhwb3J0IGxldCBuYW5vaWQgPSAoc2l6ZSA9IDIxKSA9PiB7XG4gIGxldCBpZCA9ICcnXG4gIGxldCBpID0gc2l6ZVxuICB3aGlsZSAoaS0tKSB7XG4gICAgaWQgKz0gdXJsQWxwaGFiZXRbKE1hdGgucmFuZG9tKCkgKiA2NCkgfCAwXVxuICB9XG4gIHJldHVybiBpZFxufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNhbGxcIik7XG5cbmxldCBjYWxsUmVzcG9uc2VzID0gbmV3IE1hcCgpO1xuXG5mdW5jdGlvbiBnZW5lcmF0ZUlEKCkge1xuICAgIGxldCByZXN1bHQ7XG4gICAgZG8ge1xuICAgICAgICByZXN1bHQgPSBuYW5vaWQoKTtcbiAgICB9IHdoaWxlIChjYWxsUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbENhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBpZiAoaXNKU09OKSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoSlNPTi5wYXJzZShkYXRhKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGxFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBjYWxsUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNhbGxCaW5kaW5nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiY2FsbC1pZFwiXSA9IGlkO1xuICAgICAgICBjYWxsUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBDYWxsKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gY2FsbEJpbmRpbmcoXCJDYWxsXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIENhbGwgYSBwbHVnaW4gbWV0aG9kXG4gKiBAcGFyYW0ge3N0cmluZ30gcGx1Z2luTmFtZSAtIG5hbWUgb2YgdGhlIHBsdWdpblxuICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZE5hbWUgLSBuYW1lIG9mIHRoZSBtZXRob2RcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZFxuICogQHJldHVybnMge1Byb21pc2U8YW55Pn0gLSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBQbHVnaW4ocGx1Z2luTmFtZSwgbWV0aG9kTmFtZSwgLi4uYXJncykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwge1xuICAgICAgICBwYWNrYWdlTmFtZTogXCJ3YWlscy1wbHVnaW5zXCIsXG4gICAgICAgIHN0cnVjdE5hbWU6IHBsdWdpbk5hbWUsXG4gICAgICAgIG1ldGhvZE5hbWU6IG1ldGhvZE5hbWUsXG4gICAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgfSk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TaXplfSBTaXplXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlBvc2l0aW9ufSBQb3NpdGlvblxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TY3JlZW59IFNjcmVlblxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbmV3V2luZG93KHdpbmRvd05hbWUpIHtcbiAgICBsZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJ3aW5kb3dcIiwgd2luZG93TmFtZSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLy8gUmVsb2FkOiAoKSA9PiBjYWxsKCdXUicpLFxuICAgICAgICAvLyBSZWxvYWRBcHA6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFNldFN5c3RlbURlZmF1bHRUaGVtZTogKCkgPT4gY2FsbCgnV0FTRFQnKSxcbiAgICAgICAgLy8gU2V0TGlnaHRUaGVtZTogKCkgPT4gY2FsbCgnV0FMVCcpLFxuICAgICAgICAvLyBTZXREYXJrVGhlbWU6ICgpID0+IGNhbGwoJ1dBRFQnKSxcbiAgICAgICAgLy8gSXNGdWxsc2NyZWVuOiAoKSA9PiBjYWxsKCdXSUYnKSxcbiAgICAgICAgLy8gSXNNYXhpbWl6ZWQ6ICgpID0+IGNhbGwoJ1dJTScpLFxuICAgICAgICAvLyBJc01pbmltaXplZDogKCkgPT4gY2FsbCgnV0lNTicpLFxuICAgICAgICAvLyBJc1dpbmRvd2VkOiAoKSA9PiBjYWxsKCdXSUYnKSxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDZW50ZXJzIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBDZW50ZXI6ICgpID0+IHZvaWQgY2FsbCgnQ2VudGVyJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHRpdGxlLlxuICAgICAgICAgKiBAcGFyYW0gdGl0bGVcbiAgICAgICAgICovXG4gICAgICAgIFNldFRpdGxlOiAodGl0bGUpID0+IHZvaWQgY2FsbCgnU2V0VGl0bGUnLCB7dGl0bGV9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWFrZXMgdGhlIHdpbmRvdyBmdWxsc2NyZWVuLlxuICAgICAgICAgKi9cbiAgICAgICAgRnVsbHNjcmVlbjogKCkgPT4gdm9pZCBjYWxsKCdGdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFVuZnVsbHNjcmVlbiB0aGUgd2luZG93LlxuICAgICAgICAgKi9cbiAgICAgICAgVW5GdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ1VuRnVsbHNjcmVlbicpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggVGhlIHdpbmRvdyB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IFRoZSB3aW5kb3cgaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gY2FsbCgnU2V0U2l6ZScsIHt3aWR0aCxoZWlnaHR9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgc2l6ZS5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2l6ZT59IFRoZSB3aW5kb3cgc2l6ZVxuICAgICAgICAgKi9cbiAgICAgICAgU2l6ZTogKCkgPT4geyByZXR1cm4gY2FsbCgnU2l6ZScpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtYXhpbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNYXhTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNYXhTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtaW5pbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNaW5TaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNaW5TaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgd2luZG93IHRvIGJlIGFsd2F5cyBvbiB0b3AuXG4gICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gb25Ub3AgV2hldGhlciB0aGUgd2luZG93IHNob3VsZCBiZSBhbHdheXMgb24gdG9wXG4gICAgICAgICAqL1xuICAgICAgICBTZXRBbHdheXNPblRvcDogKG9uVG9wKSA9PiB2b2lkIGNhbGwoJ1NldEFsd2F5c09uVG9wJywge2Fsd2F5c09uVG9wOm9uVG9wfSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHBvc2l0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0UG9zaXRpb246ICh4LCB5KSA9PiBjYWxsKCdTZXRQb3NpdGlvbicsIHt4LHl9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFBvc2l0aW9uPn0gVGhlIHdpbmRvdyBwb3NpdGlvblxuICAgICAgICAgKi9cbiAgICAgICAgUG9zaXRpb246ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1Bvc2l0aW9uJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB0aGUgc2NyZWVuIHRoZSB3aW5kb3cgaXMgb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gICAgICAgICAqL1xuICAgICAgICBTY3JlZW46ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1NjcmVlbicpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBIaWRlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIEhpZGU6ICgpID0+IHZvaWQgY2FsbCgnSGlkZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTaG93IHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFNob3c6ICgpID0+IHZvaWQgY2FsbCgnU2hvdycpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDbG9zZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBDbG9zZTogKCkgPT4gdm9pZCBjYWxsKCdDbG9zZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUb2dnbGUgdGhlIHdpbmRvdyBtYXhpbWlzZSBzdGF0ZVxuICAgICAgICAgKi9cbiAgICAgICAgVG9nZ2xlTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVG9nZ2xlTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5tYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWluaW1pc2UgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5taW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1pbmltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSBiYWNrZ3JvdW5kIGNvbG91ciBvZiB0aGUgd2luZG93LlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gciAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGcgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYSAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICovXG4gICAgICAgIFNldEJhY2tncm91bmRDb2xvdXI6IChyLCBnLCBiLCBhKSA9PiB2b2lkIGNhbGwoJ1NldEJhY2tncm91bmRDb2xvdXInLCB7ciwgZywgYiwgYX0pLFxuICAgIH07XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuV2FpbHNFdmVudH0gV2FpbHNFdmVudFxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJldmVudHNcIik7XG5cbi8qKlxuICogVGhlIExpc3RlbmVyIGNsYXNzIGRlZmluZXMgYSBsaXN0ZW5lciEgOi0pXG4gKlxuICogQGNsYXNzIExpc3RlbmVyXG4gKi9cbmNsYXNzIExpc3RlbmVyIHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIExpc3RlbmVyLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAgICAgKiBAbWVtYmVyb2YgTGlzdGVuZXJcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpIHtcbiAgICAgICAgdGhpcy5ldmVudE5hbWUgPSBldmVudE5hbWU7XG4gICAgICAgIC8vIERlZmF1bHQgb2YgLTEgbWVhbnMgaW5maW5pdGVcbiAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgPSBtYXhDYWxsYmFja3MgfHwgLTE7XG4gICAgICAgIC8vIENhbGxiYWNrIGludm9rZXMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIGdpdmVuIGRhdGFcbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIHRoaXMgbGlzdGVuZXIgc2hvdWxkIGJlIGRlc3Ryb3llZFxuICAgICAgICB0aGlzLkNhbGxiYWNrID0gKGRhdGEpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGRhdGEpO1xuICAgICAgICAgICAgLy8gSWYgbWF4Q2FsbGJhY2tzIGlzIGluZmluaXRlLCByZXR1cm4gZmFsc2UgKGRvIG5vdCBkZXN0cm95KVxuICAgICAgICAgICAgaWYgKHRoaXMubWF4Q2FsbGJhY2tzID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIERlY3JlbWVudCBtYXhDYWxsYmFja3MuIFJldHVybiB0cnVlIGlmIG5vdyAwLCBvdGhlcndpc2UgZmFsc2VcbiAgICAgICAgICAgIHRoaXMubWF4Q2FsbGJhY2tzIC09IDE7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXhDYWxsYmFja3MgPT09IDA7XG4gICAgICAgIH07XG4gICAgfVxufVxuXG5cbi8qKlxuICogV2FpbHNFdmVudCBkZWZpbmVzIGEgY3VzdG9tIGV2ZW50LiBJdCBpcyBwYXNzZWQgdG8gZXZlbnQgbGlzdGVuZXJzLlxuICpcbiAqIEBjbGFzcyBXYWlsc0V2ZW50XG4gKiBAcHJvcGVydHkge3N0cmluZ30gbmFtZSAtIE5hbWUgb2YgdGhlIGV2ZW50XG4gKiBAcHJvcGVydHkge2FueX0gZGF0YSAtIERhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudFxuICovXG5leHBvcnQgY2xhc3MgV2FpbHNFdmVudCB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBXYWlsc0V2ZW50LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAgICAgKiBAcGFyYW0ge2FueT1udWxsfSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gICAgICogQG1lbWJlcm9mIFdhaWxzRXZlbnRcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihuYW1lLCBkYXRhID0gbnVsbCkge1xuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGV2ZW50TGlzdGVuZXJzID0gbmV3IE1hcCgpO1xuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbihXYWlsc0V2ZW50KTogdm9pZH0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAqIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgIGxldCBsaXN0ZW5lcnMgPSBldmVudExpc3RlbmVycy5nZXQoZXZlbnROYW1lKSB8fCBbXTtcbiAgICBjb25zdCB0aGlzTGlzdGVuZXIgPSBuZXcgTGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKTtcbiAgICBsaXN0ZW5lcnMucHVzaCh0aGlzTGlzdGVuZXIpO1xuICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgcmV0dXJuICgpID0+IGxpc3RlbmVyT2ZmKHRoaXNMaXN0ZW5lcik7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGV2ZXJ5IHRpbWUgdGhlIGV2ZW50IGlzIGVtaXR0ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAtMSk7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIG9uY2UgdGhlbiBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAxKTtcbn1cblxuLyoqXG4gKiBsaXN0ZW5lck9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uXG4gKlxuICogQHBhcmFtIHtMaXN0ZW5lcn0gbGlzdGVuZXJcbiAqL1xuZnVuY3Rpb24gbGlzdGVuZXJPZmYobGlzdGVuZXIpIHtcbiAgICBjb25zdCBldmVudE5hbWUgPSBsaXN0ZW5lci5ldmVudE5hbWU7XG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyXG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpLmZpbHRlcihsID0+IGwgIT09IGxpc3RlbmVyKTtcbiAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBldmVudExpc3RlbmVycy5zZXQoZXZlbnROYW1lLCBsaXN0ZW5lcnMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBkaXNwYXRjaGVzIGFuIGV2ZW50IHRvIGFsbCBsaXN0ZW5lcnNcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkaXNwYXRjaFdhaWxzRXZlbnQoZXZlbnQpIHtcbiAgICBjb25zb2xlLmxvZyhcImRpc3BhdGNoaW5nIGV2ZW50OiBcIiwge2V2ZW50fSk7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudC5uYW1lKTtcbiAgICBpZiAobGlzdGVuZXJzKSB7XG4gICAgICAgIC8vIGl0ZXJhdGUgbGlzdGVuZXJzIGFuZCBjYWxsIGNhbGxiYWNrLiBJZiBjYWxsYmFjayByZXR1cm5zIHRydWUsIHJlbW92ZSBsaXN0ZW5lclxuICAgICAgICBsZXQgdG9SZW1vdmUgPSBbXTtcbiAgICAgICAgbGlzdGVuZXJzLmZvckVhY2gobGlzdGVuZXIgPT4ge1xuICAgICAgICAgICAgbGV0IHJlbW92ZSA9IGxpc3RlbmVyLkNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgICAgIGlmIChyZW1vdmUpIHtcbiAgICAgICAgICAgICAgICB0b1JlbW92ZS5wdXNoKGxpc3RlbmVyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8vIHJlbW92ZSBsaXN0ZW5lcnNcbiAgICAgICAgaWYgKHRvUmVtb3ZlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IGxpc3RlbmVycy5maWx0ZXIobCA9PiAhdG9SZW1vdmUuaW5jbHVkZXMobCkpO1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnQubmFtZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudC5uYW1lLCBsaXN0ZW5lcnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIE9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uLFxuICogb3B0aW9uYWxseSBtdWx0aXBsZSBsaXN0ZW5lcnMgY2FuIGJlIHVucmVnaXN0ZXJlZCB2aWEgYGFkZGl0aW9uYWxFdmVudE5hbWVzYFxuICpcbiBbdjMgQ0hBTkdFXSBPZmYgb25seSB1bnJlZ2lzdGVycyBsaXN0ZW5lcnMgd2l0aGluIHRoZSBjdXJyZW50IHdpbmRvd1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSAgey4uLnN0cmluZ30gYWRkaXRpb25hbEV2ZW50TmFtZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9mZihldmVudE5hbWUsIC4uLmFkZGl0aW9uYWxFdmVudE5hbWVzKSB7XG4gICAgbGV0IGV2ZW50c1RvUmVtb3ZlID0gW2V2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXNdO1xuICAgIGV2ZW50c1RvUmVtb3ZlLmZvckVhY2goZXZlbnROYW1lID0+IHtcbiAgICAgICAgZXZlbnRMaXN0ZW5lcnMuZGVsZXRlKGV2ZW50TmFtZSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogT2ZmQWxsIHVucmVnaXN0ZXJzIGFsbCBsaXN0ZW5lcnNcbiAqIFt2MyBDSEFOR0VdIE9mZkFsbCBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmQWxsKCkge1xuICAgIGV2ZW50TGlzdGVuZXJzLmNsZWFyKCk7XG59XG5cbi8qKlxuICogRW1pdCBhbiBldmVudFxuICogQHBhcmFtIHtXYWlsc0V2ZW50fSBldmVudCBUaGUgZXZlbnQgdG8gZW1pdFxuICovXG5leHBvcnQgZnVuY3Rpb24gRW1pdChldmVudCkge1xuICAgIHZvaWQgY2FsbChcIkVtaXRcIiwgZXZlbnQpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5NZXNzYWdlRGlhbG9nT3B0aW9uc30gTWVzc2FnZURpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5PcGVuRGlhbG9nT3B0aW9uc30gT3BlbkRpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5TYXZlRGlhbG9nT3B0aW9uc30gU2F2ZURpYWxvZ09wdGlvbnNcbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSAnbmFub2lkL25vbi1zZWN1cmUnO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJkaWFsb2dcIik7XG5cbmxldCBkaWFsb2dSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGRpYWxvZ1Jlc3BvbnNlcy5oYXMocmVzdWx0KSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpYWxvZ0NhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGRpYWxvZ1Jlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nRXJyb3JDYWxsYmFjayhpZCwgbWVzc2FnZSkge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZGlhbG9nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiZGlhbG9nLWlkXCJdID0gaWQ7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5zZXQoaWQsIHtyZXNvbHZlLCByZWplY3R9KTtcbiAgICAgICAgY2FsbCh0eXBlLCBvcHRpb25zKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBTaG93cyBhbiBJbmZvIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gSW5mbyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkluZm9cIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gV2FybmluZyBkaWFsb2cgd2l0aCB0aGUgZ2l2ZW4gb3B0aW9ucy5cbiAqIEBwYXJhbSB7TWVzc2FnZURpYWxvZ09wdGlvbnN9IG9wdGlvbnNcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBsYWJlbCBvZiB0aGUgYnV0dG9uIHByZXNzZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdhcm5pbmcob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJXYXJuaW5nXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIEVycm9yIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gRXJyb3Iob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJFcnJvclwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFF1ZXN0aW9uIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gUXVlc3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJRdWVzdGlvblwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBPcGVuIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nW118c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZSBvciBhbiBhcnJheSBvZiBzZWxlY3RlZCBmaWxlcyBpZiBBbGxvd3NNdWx0aXBsZVNlbGVjdGlvbiBpcyB0cnVlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9wZW5GaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiT3BlbkZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYSBTYXZlIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZS4gQSBibGFuayBzdHJpbmcgaXMgcmV0dXJuZWQgaWYgbm8gZmlsZSB3YXMgc2VsZWN0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTYXZlRmlsZShvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlNhdmVGaWxlXCIsIG9wdGlvbnMpO1xufVxuXG4iLCAiaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNvbnRleHRtZW51XCIpO1xuXG5mdW5jdGlvbiBvcGVuQ29udGV4dE1lbnUoaWQsIHgsIHksIGRhdGEpIHtcbiAgICByZXR1cm4gY2FsbChcIk9wZW5Db250ZXh0TWVudVwiLCB7aWQsIHgsIHksIGRhdGF9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnRleHRNZW51cyhlbmFibGVkKSB7XG4gICAgaWYgKGVuYWJsZWQpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51JywgY29udGV4dE1lbnVIYW5kbGVyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY29udGV4dE1lbnVIYW5kbGVyKGV2ZW50KSB7XG4gICAgcHJvY2Vzc0NvbnRleHRNZW51KGV2ZW50LnRhcmdldCwgZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBwcm9jZXNzQ29udGV4dE1lbnUoZWxlbWVudCwgZXZlbnQpIHtcbiAgICBsZXQgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1jb250ZXh0bWVudScpO1xuICAgIGlmIChpZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBvcGVuQ29udGV4dE1lbnUoaWQsIGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51LWRhdGEnKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHBhcmVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgICAgICAgaWYgKHBhcmVudCkge1xuICAgICAgICAgICAgcHJvY2Vzc0NvbnRleHRNZW51KHBhcmVudCwgZXZlbnQpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwgIlxuaW1wb3J0IHtFbWl0LCBXYWlsc0V2ZW50fSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7UXVlc3Rpb259IGZyb20gXCIuL2RpYWxvZ3NcIjtcblxuZnVuY3Rpb24gc2VuZEV2ZW50KGV2ZW50TmFtZSwgZGF0YT1udWxsKSB7XG4gICAgbGV0IGV2ZW50ID0gbmV3IFdhaWxzRXZlbnQoZXZlbnROYW1lLCBkYXRhKTtcbiAgICBFbWl0KGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gYWRkV01MRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtZXZlbnRdJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBldmVudFR5cGUgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtZXZlbnQnKTtcbiAgICAgICAgY29uc3QgY29uZmlybSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1jb25maXJtJyk7XG4gICAgICAgIGNvbnN0IHRyaWdnZXIgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtdHJpZ2dlcicpIHx8IFwiY2xpY2tcIjtcblxuICAgICAgICBsZXQgY2FsbGJhY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlybSkge1xuICAgICAgICAgICAgICAgIFF1ZXN0aW9uKHtUaXRsZTogXCJDb25maXJtXCIsIE1lc3NhZ2U6Y29uZmlybSwgQnV0dG9uczpbe0xhYmVsOlwiWWVzXCJ9LHtMYWJlbDpcIk5vXCIsIElzRGVmYXVsdDp0cnVlfV19KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdCAhPT0gXCJOb1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZW5kRXZlbnQoZXZlbnRUeXBlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG5cbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIGNhbGxXaW5kb3dNZXRob2QobWV0aG9kKSB7XG4gICAgaWYgKHdhaWxzLldpbmRvd1ttZXRob2RdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJXaW5kb3cgbWV0aG9kIFwiICsgbWV0aG9kICsgXCIgbm90IGZvdW5kXCIpO1xuICAgIH1cbiAgICB3YWlscy5XaW5kb3dbbWV0aG9kXSgpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtd2luZG93XScpO1xuICAgIGVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qgd2luZG93TWV0aG9kID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXdpbmRvdycpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG5cbiAgICAgICAgLy8gQWRkIG5ldyBsaXN0ZW5lclxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVsb2FkV01MKCkge1xuICAgIGFkZFdNTEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgYWRkV01MV2luZG93TGlzdGVuZXJzKCk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLy8gZGVmaW5lZCBpbiB0aGUgVGFza2ZpbGVcbmV4cG9ydCBsZXQgaW52b2tlID0gKFdJTkRPV1M/Y2hyb21lLndlYnZpZXcucG9zdE1lc3NhZ2U6d2luZG93LndlYmtpdC5tZXNzYWdlSGFuZGxlcnMuZXh0ZXJuYWwucG9zdE1lc3NhZ2UpO1xuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7aW52b2tlfSBmcm9tIFwiLi9pbnZva2VcIjtcblxubGV0IHNob3VsZERyYWcgPSBmYWxzZTtcblxuZXhwb3J0IGZ1bmN0aW9uIGRyYWdUZXN0KGUpIHtcbiAgICBsZXQgdmFsID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZS50YXJnZXQpLmdldFByb3BlcnR5VmFsdWUoXCItLXdhaWxzLWRyYWdnYWJsZVwiKTtcbiAgICBpZiAodmFsKSB7XG4gICAgICAgIHZhbCA9IHZhbC50cmltKCk7XG4gICAgfVxuXG4gICAgaWYgKHZhbCAhPT0gXCJkcmFnXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIE9ubHkgcHJvY2VzcyB0aGUgcHJpbWFyeSBidXR0b25cbiAgICBpZiAoZS5idXR0b25zICE9PSAxKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZS5kZXRhaWwgPT09IDE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cERyYWcoKSB7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIG9uTW91c2VEb3duKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgb25Nb3VzZU1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25Nb3VzZVVwKTtcbn1cblxuZnVuY3Rpb24gb25Nb3VzZURvd24oZSkge1xuICAgIGlmIChkcmFnVGVzdChlKSkge1xuICAgICAgICAvLyBJZ25vcmUgZHJhZyBvbiBzY3JvbGxiYXJzXG4gICAgICAgIGlmIChlLm9mZnNldFggPiBlLnRhcmdldC5jbGllbnRXaWR0aCB8fCBlLm9mZnNldFkgPiBlLnRhcmdldC5jbGllbnRIZWlnaHQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzaG91bGREcmFnID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbk1vdXNlVXAoZSkge1xuICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gd2luZG93LndhaWxzLnByZXZpb3VzQ3Vyc29yIHx8ICdhdXRvJztcbiAgICBzaG91bGREcmFnID0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIG9uTW91c2VNb3ZlKGUpIHtcbiAgICBpZiAoc2hvdWxkRHJhZykge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgICAgIGxldCBtb3VzZVByZXNzZWQgPSBlLmJ1dHRvbnMgIT09IHVuZGVmaW5lZCA/IGUuYnV0dG9ucyA6IGUud2hpY2g7XG4gICAgICAgIGlmIChtb3VzZVByZXNzZWQgPiAwKSB7XG4gICAgICAgICAgICB3aW5kb3cud2FpbHMucHJldmlvdXNDdXJzb3IgPSBkb2N1bWVudC5ib2R5LnN0eWxlLmN1cnNvcjtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gJ2dyYWInO1xuICAgICAgICAgICAgaW52b2tlKFwiZHJhZ1wiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cblxuaW1wb3J0ICogYXMgQ2xpcGJvYXJkIGZyb20gJy4vY2xpcGJvYXJkJztcbmltcG9ydCAqIGFzIEFwcGxpY2F0aW9uIGZyb20gJy4vYXBwbGljYXRpb24nO1xuaW1wb3J0ICogYXMgTG9nIGZyb20gJy4vbG9nJztcbmltcG9ydCAqIGFzIFNjcmVlbnMgZnJvbSAnLi9zY3JlZW5zJztcbmltcG9ydCB7UGx1Z2luLCBDYWxsLCBjYWxsRXJyb3JDYWxsYmFjaywgY2FsbENhbGxiYWNrfSBmcm9tIFwiLi9jYWxsc1wiO1xuaW1wb3J0IHtuZXdXaW5kb3d9IGZyb20gXCIuL3dpbmRvd1wiO1xuaW1wb3J0IHtkaXNwYXRjaFdhaWxzRXZlbnQsIEVtaXQsIE9mZiwgT2ZmQWxsLCBPbiwgT25jZSwgT25NdWx0aXBsZX0gZnJvbSBcIi4vZXZlbnRzXCI7XG5pbXBvcnQge2RpYWxvZ0NhbGxiYWNrLCBkaWFsb2dFcnJvckNhbGxiYWNrLCBFcnJvciwgSW5mbywgT3BlbkZpbGUsIFF1ZXN0aW9uLCBTYXZlRmlsZSwgV2FybmluZyx9IGZyb20gXCIuL2RpYWxvZ3NcIjtcbmltcG9ydCB7ZW5hYmxlQ29udGV4dE1lbnVzfSBmcm9tIFwiLi9jb250ZXh0bWVudVwiO1xuaW1wb3J0IHtyZWxvYWRXTUx9IGZyb20gXCIuL3dtbFwiO1xuaW1wb3J0IHtzZXR1cERyYWd9IGZyb20gXCIuL2RyYWdcIjtcblxud2luZG93LndhaWxzID0ge1xuICAgIC4uLm5ld1J1bnRpbWUobnVsbCksXG59O1xuXG4vLyBJbnRlcm5hbCB3YWlscyBlbmRwb2ludHNcbndpbmRvdy5fd2FpbHMgPSB7XG4gICAgZGlhbG9nQ2FsbGJhY2ssXG4gICAgZGlhbG9nRXJyb3JDYWxsYmFjayxcbiAgICBkaXNwYXRjaFdhaWxzRXZlbnQsXG4gICAgY2FsbENhbGxiYWNrLFxuICAgIGNhbGxFcnJvckNhbGxiYWNrLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIG5ld1J1bnRpbWUod2luZG93TmFtZSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIENsaXBib2FyZDoge1xuICAgICAgICAgICAgLi4uQ2xpcGJvYXJkXG4gICAgICAgIH0sXG4gICAgICAgIEFwcGxpY2F0aW9uOiB7XG4gICAgICAgICAgICAuLi5BcHBsaWNhdGlvbixcbiAgICAgICAgICAgIEdldFdpbmRvd0J5TmFtZSh3aW5kb3dOYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ld1J1bnRpbWUod2luZG93TmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIExvZyxcbiAgICAgICAgU2NyZWVucyxcbiAgICAgICAgQ2FsbCxcbiAgICAgICAgUGx1Z2luLFxuICAgICAgICBXTUw6IHtcbiAgICAgICAgICAgIFJlbG9hZDogcmVsb2FkV01MLFxuICAgICAgICB9LFxuICAgICAgICBEaWFsb2c6IHtcbiAgICAgICAgICAgIEluZm8sXG4gICAgICAgICAgICBXYXJuaW5nLFxuICAgICAgICAgICAgRXJyb3IsXG4gICAgICAgICAgICBRdWVzdGlvbixcbiAgICAgICAgICAgIE9wZW5GaWxlLFxuICAgICAgICAgICAgU2F2ZUZpbGUsXG4gICAgICAgIH0sXG4gICAgICAgIEV2ZW50czoge1xuICAgICAgICAgICAgRW1pdCxcbiAgICAgICAgICAgIE9uLFxuICAgICAgICAgICAgT25jZSxcbiAgICAgICAgICAgIE9uTXVsdGlwbGUsXG4gICAgICAgICAgICBPZmYsXG4gICAgICAgICAgICBPZmZBbGwsXG4gICAgICAgIH0sXG4gICAgICAgIFdpbmRvdzogbmV3V2luZG93KHdpbmRvd05hbWUpLFxuICAgIH07XG59XG5cbmlmIChERUJVRykge1xuICAgIGNvbnNvbGUubG9nKFwiV2FpbHMgdjMuMC4wIERlYnVnIE1vZGUgRW5hYmxlZFwiKTtcbn1cblxuZW5hYmxlQ29udGV4dE1lbnVzKHRydWUpO1xuXG5zZXR1cERyYWcoKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFD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O0FBQUEsUUFDaEM7QUFBQSxNQUNKO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0EsS0FBSztBQUFBLFFBQ0QsUUFBUTtBQUFBLE1BQ1o7QUFBQSxNQUNBLFFBQVE7QUFBQSxRQUNKO0FBQUEsUUFDQTtBQUFBLFFBQ0EsT0FBQUM7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxNQUNKO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUSxVQUFVLFVBQVU7QUFBQSxJQUNoQztBQUFBLEVBQ0o7QUFFQSxNQUFJLE1BQU87QUFDUCxZQUFRLElBQUksaUNBQWlDO0FBQUEsRUFDakQ7QUFFQSxxQkFBbUIsSUFBSTtBQUV2QixZQUFVO0FBRVYsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
diff --git a/v3/internal/runtime/runtime_debug_desktop_linux.js b/v3/internal/runtime/runtime_debug_desktop_linux.js
index 0ca537592..4dc032864 100644
--- a/v3/internal/runtime/runtime_debug_desktop_linux.js
+++ b/v3/internal/runtime/runtime_debug_desktop_linux.js
@@ -523,6 +523,56 @@
addWMLWindowListeners();
}
+ // desktop/invoke.js
+ var invoke = false ? chrome.webview.postMessage : window.webkit.messageHandlers.external.postMessage;
+
+ // desktop/drag.js
+ var shouldDrag = false;
+ function dragTest(e) {
+ let val = window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");
+ if (val) {
+ val = val.trim();
+ }
+ if (val !== "drag") {
+ return false;
+ }
+ if (e.buttons !== 1) {
+ return false;
+ }
+ return e.detail === 1;
+ }
+ function setupDrag() {
+ window.addEventListener("mousedown", onMouseDown);
+ window.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("mouseup", onMouseUp);
+ }
+ function onMouseDown(e) {
+ if (dragTest(e)) {
+ if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
+ return;
+ }
+ shouldDrag = true;
+ } else {
+ shouldDrag = false;
+ }
+ }
+ function onMouseUp(e) {
+ document.body.style.cursor = window.wails.previousCursor || "auto";
+ shouldDrag = false;
+ }
+ function onMouseMove(e) {
+ if (shouldDrag) {
+ shouldDrag = false;
+ let mousePressed = e.buttons !== void 0 ? e.buttons : e.which;
+ if (mousePressed > 0) {
+ window.wails.previousCursor = document.body.style.cursor;
+ document.body.style.cursor = "grab";
+ invoke("drag");
+ return;
+ }
+ }
+ }
+
// desktop/main.js
window.wails = {
...newRuntime(null)
@@ -575,8 +625,9 @@
console.log("Wails v3.0.0 Debug Mode Enabled");
}
enableContextMenus(true);
+ setupDrag();
document.addEventListener("DOMContentLoaded", function(event) {
reloadWML();
});
})();
-//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvbWFpbi5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNsaXBib2FyZFwiKTtcblxuLyoqXG4gKiBTZXQgdGhlIENsaXBib2FyZCB0ZXh0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTZXRUZXh0KHRleHQpIHtcbiAgICB2b2lkIGNhbGwoXCJTZXRUZXh0XCIsIHt0ZXh0fSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFRleHQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJUZXh0XCIpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5jb25zdCBydW50aW1lVVJMID0gd2luZG93LmxvY2F0aW9uLm9yaWdpbiArIFwiL3dhaWxzL3J1bnRpbWVcIjtcblxuZnVuY3Rpb24gcnVudGltZUNhbGwobWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKSB7XG4gICAgbGV0IHVybCA9IG5ldyBVUkwocnVudGltZVVSTCk7XG4gICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJtZXRob2RcIiwgbWV0aG9kKTtcbiAgICBpZiAoYXJncykge1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChcImFyZ3NcIiwgSlNPTi5zdHJpbmdpZnkoYXJncykpO1xuICAgIH1cbiAgICBsZXQgZmV0Y2hPcHRpb25zID0ge1xuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICB9O1xuICAgIGlmICh3aW5kb3dOYW1lKSB7XG4gICAgICAgIGZldGNoT3B0aW9ucy5oZWFkZXJzW1wieC13YWlscy13aW5kb3ctbmFtZVwiXSA9IHdpbmRvd05hbWU7XG4gICAgfVxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGZldGNoKHVybCwgZmV0Y2hPcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgICAgICAgICAgICAgICAvLyBjaGVjayBjb250ZW50IHR5cGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpICYmIHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpLmluZGV4T2YoXCJhcHBsaWNhdGlvbi9qc29uXCIpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS50ZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVqZWN0KEVycm9yKHJlc3BvbnNlLnN0YXR1c1RleHQpKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihkYXRhID0+IHJlc29sdmUoZGF0YSkpXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4gcmVqZWN0KGVycm9yKSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lQ2FsbGVyKG9iamVjdCwgd2luZG93TmFtZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAobWV0aG9kLCBhcmdzPW51bGwpIHtcbiAgICAgICAgcmV0dXJuIHJ1bnRpbWVDYWxsKG9iamVjdCArIFwiLlwiICsgbWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKTtcbiAgICB9O1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiYXBwbGljYXRpb25cIik7XG5cbi8qKlxuICogSGlkZSB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEhpZGUoKSB7XG4gICAgdm9pZCBjYWxsKFwiSGlkZVwiKTtcbn1cblxuLyoqXG4gKiBTaG93IHRoZSBhcHBsaWNhdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gU2hvdygpIHtcbiAgICB2b2lkIGNhbGwoXCJTaG93XCIpO1xufVxuXG5cbi8qKlxuICogUXVpdCB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XG4gICAgdm9pZCBjYWxsKFwiUXVpdFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImxvZ1wiKTtcblxuLyoqXG4gKiBMb2dzIGEgbWVzc2FnZS5cbiAqIEBwYXJhbSB7bWVzc2FnZX0gTWVzc2FnZSB0byBsb2dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExvZyhtZXNzYWdlKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJMb2dcIiwgbWVzc2FnZSk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuU2NyZWVufSBTY3JlZW5cbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwic2NyZWVuc1wiKTtcblxuLyoqXG4gKiBHZXRzIGFsbCBzY3JlZW5zLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuW10+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gR2V0QWxsKCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0QWxsXCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIHByaW1hcnkgc2NyZWVuLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldFByaW1hcnkoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRQcmltYXJ5XCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIGN1cnJlbnQgYWN0aXZlIHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEN1cnJlbnQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRDdXJyZW50XCIpO1xufSIsICJsZXQgdXJsQWxwaGFiZXQgPVxuICAndXNlYW5kb20tMjZUMTk4MzQwUFg3NXB4SkFDS1ZFUllNSU5EQlVTSFdPTEZfR1FaYmZnaGprbHF2d3l6cmljdCdcbmV4cG9ydCBsZXQgY3VzdG9tQWxwaGFiZXQgPSAoYWxwaGFiZXQsIGRlZmF1bHRTaXplID0gMjEpID0+IHtcbiAgcmV0dXJuIChzaXplID0gZGVmYXVsdFNpemUpID0+IHtcbiAgICBsZXQgaWQgPSAnJ1xuICAgIGxldCBpID0gc2l6ZVxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGlkICs9IGFscGhhYmV0WyhNYXRoLnJhbmRvbSgpICogYWxwaGFiZXQubGVuZ3RoKSB8IDBdXG4gICAgfVxuICAgIHJldHVybiBpZFxuICB9XG59XG5leHBvcnQgbGV0IG5hbm9pZCA9IChzaXplID0gMjEpID0+IHtcbiAgbGV0IGlkID0gJydcbiAgbGV0IGkgPSBzaXplXG4gIHdoaWxlIChpLS0pIHtcbiAgICBpZCArPSB1cmxBbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIDY0KSB8IDBdXG4gIH1cbiAgcmV0dXJuIGlkXG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmltcG9ydCB7IG5hbm9pZCB9IGZyb20gJ25hbm9pZC9ub24tc2VjdXJlJztcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY2FsbFwiKTtcblxubGV0IGNhbGxSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGNhbGxSZXNwb25zZXMuaGFzKHJlc3VsdCkpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWxsQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gY2FsbFJlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbEVycm9yQ2FsbGJhY2soaWQsIG1lc3NhZ2UpIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY2FsbEJpbmRpbmcodHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJjYWxsLWlkXCJdID0gaWQ7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuc2V0KGlkLCB7cmVzb2x2ZSwgcmVqZWN0fSk7XG4gICAgICAgIGNhbGwodHlwZSwgb3B0aW9ucykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENhbGwob3B0aW9ucykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogQ2FsbCBhIHBsdWdpbiBtZXRob2RcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbHVnaW5OYW1lIC0gbmFtZSBvZiB0aGUgcGx1Z2luXG4gKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kTmFtZSAtIG5hbWUgb2YgdGhlIG1ldGhvZFxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgbWV0aG9kXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fSAtIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFBsdWdpbihwbHVnaW5OYW1lLCBtZXRob2ROYW1lLCAuLi5hcmdzKSB7XG4gICAgcmV0dXJuIGNhbGxCaW5kaW5nKFwiQ2FsbFwiLCB7XG4gICAgICAgIHBhY2thZ2VOYW1lOiBcIndhaWxzLXBsdWdpbnNcIixcbiAgICAgICAgc3RydWN0TmFtZTogcGx1Z2luTmFtZSxcbiAgICAgICAgbWV0aG9kTmFtZTogbWV0aG9kTmFtZSxcbiAgICAgICAgYXJnczogYXJncyxcbiAgICB9KTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNpemV9IFNpemVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuLi9hcGkvdHlwZXNcIikuUG9zaXRpb259IFBvc2l0aW9uXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdXaW5kb3cod2luZG93TmFtZSkge1xuICAgIGxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcIndpbmRvd1wiLCB3aW5kb3dOYW1lKTtcbiAgICByZXR1cm4ge1xuICAgICAgICAvLyBSZWxvYWQ6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFJlbG9hZEFwcDogKCkgPT4gY2FsbCgnV1InKSxcbiAgICAgICAgLy8gU2V0U3lzdGVtRGVmYXVsdFRoZW1lOiAoKSA9PiBjYWxsKCdXQVNEVCcpLFxuICAgICAgICAvLyBTZXRMaWdodFRoZW1lOiAoKSA9PiBjYWxsKCdXQUxUJyksXG4gICAgICAgIC8vIFNldERhcmtUaGVtZTogKCkgPT4gY2FsbCgnV0FEVCcpLFxuICAgICAgICAvLyBJc0Z1bGxzY3JlZW46ICgpID0+IGNhbGwoJ1dJRicpLFxuICAgICAgICAvLyBJc01heGltaXplZDogKCkgPT4gY2FsbCgnV0lNJyksXG4gICAgICAgIC8vIElzTWluaW1pemVkOiAoKSA9PiBjYWxsKCdXSU1OJyksXG4gICAgICAgIC8vIElzV2luZG93ZWQ6ICgpID0+IGNhbGwoJ1dJRicpLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENlbnRlcnMgdGhlIHdpbmRvdy5cbiAgICAgICAgICovXG4gICAgICAgIENlbnRlcjogKCkgPT4gdm9pZCBjYWxsKCdDZW50ZXInKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgdGl0bGUuXG4gICAgICAgICAqIEBwYXJhbSB0aXRsZVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0VGl0bGU6ICh0aXRsZSkgPT4gdm9pZCBjYWxsKCdTZXRUaXRsZScsIHt0aXRsZX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYWtlcyB0aGUgd2luZG93IGZ1bGxzY3JlZW4uXG4gICAgICAgICAqL1xuICAgICAgICBGdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ0Z1bGxzY3JlZW4nKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5mdWxsc2NyZWVuIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBVbkZ1bGxzY3JlZW46ICgpID0+IHZvaWQgY2FsbCgnVW5GdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCBUaGUgd2luZG93IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgVGhlIHdpbmRvdyBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiBjYWxsKCdTZXRTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTaXplPn0gVGhlIHdpbmRvdyBzaXplXG4gICAgICAgICAqL1xuICAgICAgICBTaXplOiAoKSA9PiB7IHJldHVybiBjYWxsKCdTaXplJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1heGltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1heFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1heFNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1pbmltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1pblNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1pblNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB3aW5kb3cgdG8gYmUgYWx3YXlzIG9uIHRvcC5cbiAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBvblRvcCBXaGV0aGVyIHRoZSB3aW5kb3cgc2hvdWxkIGJlIGFsd2F5cyBvbiB0b3BcbiAgICAgICAgICovXG4gICAgICAgIFNldEFsd2F5c09uVG9wOiAob25Ub3ApID0+IHZvaWQgY2FsbCgnU2V0QWx3YXlzT25Ub3AnLCB7YWx3YXlzT25Ub3A6b25Ub3B9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XG4gICAgICAgICAqL1xuICAgICAgICBTZXRQb3NpdGlvbjogKHgsIHkpID0+IGNhbGwoJ1NldFBvc2l0aW9uJywge3gseX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBwb3NpdGlvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8UG9zaXRpb24+fSBUaGUgd2luZG93IHBvc2l0aW9uXG4gICAgICAgICAqL1xuICAgICAgICBQb3NpdGlvbjogKCkgPT4geyByZXR1cm4gY2FsbCgnUG9zaXRpb24nKTsgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBzY3JlZW4gdGhlIHdpbmRvdyBpcyBvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAgICAgICAgICovXG4gICAgICAgIFNjcmVlbjogKCkgPT4geyByZXR1cm4gY2FsbCgnU2NyZWVuJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhpZGUgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgSGlkZTogKCkgPT4gdm9pZCBjYWxsKCdIaWRlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIE1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ01heGltaXNlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNob3cgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgU2hvdzogKCkgPT4gdm9pZCBjYWxsKCdTaG93JyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENsb3NlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIENsb3NlOiAoKSA9PiB2b2lkIGNhbGwoJ0Nsb3NlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRvZ2dsZSB0aGUgd2luZG93IG1heGltaXNlIHN0YXRlXG4gICAgICAgICAqL1xuICAgICAgICBUb2dnbGVNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdUb2dnbGVNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNaW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNaW5pbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1pbmltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGJhY2tncm91bmQgY29sb3VyIG9mIHRoZSB3aW5kb3cuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gZyAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGIgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0QmFja2dyb3VuZENvbG91cjogKHIsIGcsIGIsIGEpID0+IHZvaWQgY2FsbCgnU2V0QmFja2dyb3VuZENvbG91cicsIHtyLCBnLCBiLCBhfSksXG4gICAgfTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5XYWlsc0V2ZW50fSBXYWlsc0V2ZW50XG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImV2ZW50c1wiKTtcblxuLyoqXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcbiAqXG4gKiBAY2xhc3MgTGlzdGVuZXJcbiAqL1xuY2xhc3MgTGlzdGVuZXIge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICAgICAqIEBtZW1iZXJvZiBMaXN0ZW5lclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgICAgICB0aGlzLmV2ZW50TmFtZSA9IGV2ZW50TmFtZTtcbiAgICAgICAgLy8gRGVmYXVsdCBvZiAtMSBtZWFucyBpbmZpbml0ZVxuICAgICAgICB0aGlzLm1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2soZGF0YSk7XG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhDYWxsYmFja3MgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRGVjcmVtZW50IG1heENhbGxiYWNrcy4gUmV0dXJuIHRydWUgaWYgbm93IDAsIG90aGVyd2lzZSBmYWxzZVxuICAgICAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgLT0gMTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm1heENhbGxiYWNrcyA9PT0gMDtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBXYWlsc0V2ZW50IGRlZmluZXMgYSBjdXN0b20gZXZlbnQuIEl0IGlzIHBhc3NlZCB0byBldmVudCBsaXN0ZW5lcnMuXG4gKlxuICogQGNsYXNzIFdhaWxzRXZlbnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAqIEBwcm9wZXJ0eSB7YW55fSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gKi9cbmV4cG9ydCBjbGFzcyBXYWlsc0V2ZW50IHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFdhaWxzRXZlbnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBOYW1lIG9mIHRoZSBldmVudFxuICAgICAqIEBwYXJhbSB7YW55PW51bGx9IGRhdGEgLSBEYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGUgZXZlbnRcbiAgICAgKiBAbWVtYmVyb2YgV2FpbHNFdmVudFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKG5hbWUsIGRhdGEgPSBudWxsKSB7XG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgZXZlbnRMaXN0ZW5lcnMgPSBuZXcgTWFwKCk7XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGBtYXhDYWxsYmFja3NgIHRpbWVzIGJlZm9yZSBiZWluZyBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpIHx8IFtdO1xuICAgIGNvbnN0IHRoaXNMaXN0ZW5lciA9IG5ldyBMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xuICAgIGxpc3RlbmVycy5wdXNoKHRoaXNMaXN0ZW5lcik7XG4gICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50TmFtZSwgbGlzdGVuZXJzKTtcbiAgICByZXR1cm4gKCkgPT4gbGlzdGVuZXJPZmYodGhpc0xpc3RlbmVyKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgZXZlcnkgdGltZSB0aGUgZXZlbnQgaXMgZW1pdHRlZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FuY2VsIHRoZSBsaXN0ZW5lclxuICovXG5leHBvcnQgZnVuY3Rpb24gT24oZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uY2UoZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xufVxuXG4vKipcbiAqIGxpc3RlbmVyT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT25cbiAqXG4gKiBAcGFyYW0ge0xpc3RlbmVyfSBsaXN0ZW5lclxuICovXG5mdW5jdGlvbiBsaXN0ZW5lck9mZihsaXN0ZW5lcikge1xuICAgIGNvbnN0IGV2ZW50TmFtZSA9IGxpc3RlbmVyLmV2ZW50TmFtZTtcbiAgICAvLyBSZW1vdmUgbG9jYWwgbGlzdGVuZXJcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50TmFtZSkuZmlsdGVyKGwgPT4gbCAhPT0gbGlzdGVuZXIpO1xuICAgIGlmIChsaXN0ZW5lcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudE5hbWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgfVxufVxuXG4vKipcbiAqIGRpc3BhdGNoZXMgYW4gZXZlbnQgdG8gYWxsIGxpc3RlbmVyc1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7V2FpbHNFdmVudH0gZXZlbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpc3BhdGNoV2FpbHNFdmVudChldmVudCkge1xuICAgIGNvbnNvbGUubG9nKFwiZGlzcGF0Y2hpbmcgZXZlbnQ6IFwiLCB7ZXZlbnR9KTtcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50Lm5hbWUpO1xuICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgICAgLy8gaXRlcmF0ZSBsaXN0ZW5lcnMgYW5kIGNhbGwgY2FsbGJhY2suIElmIGNhbGxiYWNrIHJldHVybnMgdHJ1ZSwgcmVtb3ZlIGxpc3RlbmVyXG4gICAgICAgIGxldCB0b1JlbW92ZSA9IFtdO1xuICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaChsaXN0ZW5lciA9PiB7XG4gICAgICAgICAgICBsZXQgcmVtb3ZlID0gbGlzdGVuZXIuQ2FsbGJhY2soZXZlbnQpO1xuICAgICAgICAgICAgaWYgKHJlbW92ZSkge1xuICAgICAgICAgICAgICAgIHRvUmVtb3ZlLnB1c2gobGlzdGVuZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gcmVtb3ZlIGxpc3RlbmVyc1xuICAgICAgICBpZiAodG9SZW1vdmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgbGlzdGVuZXJzID0gbGlzdGVuZXJzLmZpbHRlcihsID0+ICF0b1JlbW92ZS5pbmNsdWRlcyhsKSk7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudC5uYW1lKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50Lm5hbWUsIGxpc3RlbmVycyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT24sXG4gKiBvcHRpb25hbGx5IG11bHRpcGxlIGxpc3RlbmVycyBjYW4gYmUgdW5yZWdpc3RlcmVkIHZpYSBgYWRkaXRpb25hbEV2ZW50TmFtZXNgXG4gKlxuIFt2MyBDSEFOR0VdIE9mZiBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtICB7Li4uc3RyaW5nfSBhZGRpdGlvbmFsRXZlbnROYW1lc1xuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmKGV2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXMpIHtcbiAgICBsZXQgZXZlbnRzVG9SZW1vdmUgPSBbZXZlbnROYW1lLCAuLi5hZGRpdGlvbmFsRXZlbnROYW1lc107XG4gICAgZXZlbnRzVG9SZW1vdmUuZm9yRWFjaChldmVudE5hbWUgPT4ge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBPZmZBbGwgdW5yZWdpc3RlcnMgYWxsIGxpc3RlbmVyc1xuICogW3YzIENIQU5HRV0gT2ZmQWxsIG9ubHkgdW5yZWdpc3RlcnMgbGlzdGVuZXJzIHdpdGhpbiB0aGUgY3VycmVudCB3aW5kb3dcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPZmZBbGwoKSB7XG4gICAgZXZlbnRMaXN0ZW5lcnMuY2xlYXIoKTtcbn1cblxuLyoqXG4gKiBFbWl0IGFuIGV2ZW50XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50IFRoZSBldmVudCB0byBlbWl0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFbWl0KGV2ZW50KSB7XG4gICAgdm9pZCBjYWxsKFwiRW1pdFwiLCBldmVudCk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk1lc3NhZ2VEaWFsb2dPcHRpb25zfSBNZXNzYWdlRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk9wZW5EaWFsb2dPcHRpb25zfSBPcGVuRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNhdmVEaWFsb2dPcHRpb25zfSBTYXZlRGlhbG9nT3B0aW9uc1xuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImRpYWxvZ1wiKTtcblxubGV0IGRpYWxvZ1Jlc3BvbnNlcyA9IG5ldyBNYXAoKTtcblxuZnVuY3Rpb24gZ2VuZXJhdGVJRCgpIHtcbiAgICBsZXQgcmVzdWx0O1xuICAgIGRvIHtcbiAgICAgICAgcmVzdWx0ID0gbmFub2lkKCk7XG4gICAgfSB3aGlsZSAoZGlhbG9nUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgaWYgKGlzSlNPTikge1xuICAgICAgICAgICAgcC5yZXNvbHZlKEpTT04ucGFyc2UoZGF0YSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICB9XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cbmV4cG9ydCBmdW5jdGlvbiBkaWFsb2dFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBkaWFsb2dSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBkaWFsb2codHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJkaWFsb2ctaWRcIl0gPSBpZDtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIFNob3dzIGFuIEluZm8gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBJbmZvKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiSW5mb1wiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBXYXJuaW5nIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2FybmluZyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIldhcm5pbmdcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gRXJyb3IgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFcnJvcihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkVycm9yXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGEgUXVlc3Rpb24gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWVzdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlF1ZXN0aW9uXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIE9wZW4gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXXxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlIG9yIGFuIGFycmF5IG9mIHNlbGVjdGVkIGZpbGVzIGlmIEFsbG93c011bHRpcGxlU2VsZWN0aW9uIGlzIHRydWUuIEEgYmxhbmsgc3RyaW5nIGlzIHJldHVybmVkIGlmIG5vIGZpbGUgd2FzIHNlbGVjdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gT3BlbkZpbGUob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJPcGVuRmlsZVwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFNhdmUgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNhdmVGaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiU2F2ZUZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbiIsICJpbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY29udGV4dG1lbnVcIik7XG5cbmZ1bmN0aW9uIG9wZW5Db250ZXh0TWVudShpZCwgeCwgeSwgZGF0YSkge1xuICAgIHJldHVybiBjYWxsKFwiT3BlbkNvbnRleHRNZW51XCIsIHtpZCwgeCwgeSwgZGF0YX0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29udGV4dE1lbnVzKGVuYWJsZWQpIHtcbiAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGNvbnRleHRNZW51SGFuZGxlcik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBjb250ZXh0TWVudUhhbmRsZXIoZXZlbnQpIHtcbiAgICBwcm9jZXNzQ29udGV4dE1lbnUoZXZlbnQudGFyZ2V0LCBldmVudCk7XG59XG5cbmZ1bmN0aW9uIHByb2Nlc3NDb250ZXh0TWVudShlbGVtZW50LCBldmVudCkge1xuICAgIGxldCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51Jyk7XG4gICAgaWYgKGlkKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIG9wZW5Db250ZXh0TWVudShpZCwgZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtY29udGV4dG1lbnUtZGF0YScpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgcGFyZW50ID0gZWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgICAgICBpZiAocGFyZW50KSB7XG4gICAgICAgICAgICBwcm9jZXNzQ29udGV4dE1lbnUocGFyZW50LCBldmVudCk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCAiXG5pbXBvcnQge0VtaXQsIFdhaWxzRXZlbnR9IGZyb20gXCIuL2V2ZW50c1wiO1xuaW1wb3J0IHtRdWVzdGlvbn0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuXG5mdW5jdGlvbiBzZW5kRXZlbnQoZXZlbnROYW1lLCBkYXRhPW51bGwpIHtcbiAgICBsZXQgZXZlbnQgPSBuZXcgV2FpbHNFdmVudChldmVudE5hbWUsIGRhdGEpO1xuICAgIEVtaXQoZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxFdmVudExpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC1ldmVudF0nKTtcbiAgICBlbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGV2ZW50VHlwZSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1ldmVudCcpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VuZEV2ZW50KGV2ZW50VHlwZSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcblxuICAgICAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuXG4gICAgICAgIC8vIEFkZCBuZXcgbGlzdGVuZXJcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gY2FsbFdpbmRvd01ldGhvZChtZXRob2QpIHtcbiAgICBpZiAod2FpbHMuV2luZG93W21ldGhvZF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIldpbmRvdyBtZXRob2QgXCIgKyBtZXRob2QgKyBcIiBub3QgZm91bmRcIik7XG4gICAgfVxuICAgIHdhaWxzLldpbmRvd1ttZXRob2RdKCk7XG59XG5cbmZ1bmN0aW9uIGFkZFdNTFdpbmRvd0xpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC13aW5kb3ddJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCB3aW5kb3dNZXRob2QgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtd2luZG93Jyk7XG4gICAgICAgIGNvbnN0IGNvbmZpcm0gPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtY29uZmlybScpO1xuICAgICAgICBjb25zdCB0cmlnZ2VyID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXRyaWdnZXInKSB8fCBcImNsaWNrXCI7XG5cbiAgICAgICAgbGV0IGNhbGxiYWNrID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKGNvbmZpcm0pIHtcbiAgICAgICAgICAgICAgICBRdWVzdGlvbih7VGl0bGU6IFwiQ29uZmlybVwiLCBNZXNzYWdlOmNvbmZpcm0sIEJ1dHRvbnM6W3tMYWJlbDpcIlllc1wifSx7TGFiZWw6XCJOb1wiLCBJc0RlZmF1bHQ6dHJ1ZX1dfSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQgIT09IFwiTm9cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWxvYWRXTUwoKSB7XG4gICAgYWRkV01MRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuXG5pbXBvcnQgKiBhcyBDbGlwYm9hcmQgZnJvbSAnLi9jbGlwYm9hcmQnO1xuaW1wb3J0ICogYXMgQXBwbGljYXRpb24gZnJvbSAnLi9hcHBsaWNhdGlvbic7XG5pbXBvcnQgKiBhcyBMb2cgZnJvbSAnLi9sb2cnO1xuaW1wb3J0ICogYXMgU2NyZWVucyBmcm9tICcuL3NjcmVlbnMnO1xuaW1wb3J0IHtQbHVnaW4sIENhbGwsIGNhbGxFcnJvckNhbGxiYWNrLCBjYWxsQ2FsbGJhY2t9IGZyb20gXCIuL2NhbGxzXCI7XG5pbXBvcnQge25ld1dpbmRvd30gZnJvbSBcIi4vd2luZG93XCI7XG5pbXBvcnQge2Rpc3BhdGNoV2FpbHNFdmVudCwgRW1pdCwgT2ZmLCBPZmZBbGwsIE9uLCBPbmNlLCBPbk11bHRpcGxlfSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7ZGlhbG9nQ2FsbGJhY2ssIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssIEVycm9yLCBJbmZvLCBPcGVuRmlsZSwgUXVlc3Rpb24sIFNhdmVGaWxlLCBXYXJuaW5nLH0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuaW1wb3J0IHtlbmFibGVDb250ZXh0TWVudXN9IGZyb20gXCIuL2NvbnRleHRtZW51XCI7XG5pbXBvcnQge3JlbG9hZFdNTH0gZnJvbSBcIi4vd21sXCI7XG5cbndpbmRvdy53YWlscyA9IHtcbiAgICAuLi5uZXdSdW50aW1lKG51bGwpLFxufTtcblxuLy8gSW50ZXJuYWwgd2FpbHMgZW5kcG9pbnRzXG53aW5kb3cuX3dhaWxzID0ge1xuICAgIGRpYWxvZ0NhbGxiYWNrLFxuICAgIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssXG4gICAgZGlzcGF0Y2hXYWlsc0V2ZW50LFxuICAgIGNhbGxDYWxsYmFjayxcbiAgICBjYWxsRXJyb3JDYWxsYmFjayxcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lKHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBDbGlwYm9hcmQ6IHtcbiAgICAgICAgICAgIC4uLkNsaXBib2FyZFxuICAgICAgICB9LFxuICAgICAgICBBcHBsaWNhdGlvbjoge1xuICAgICAgICAgICAgLi4uQXBwbGljYXRpb24sXG4gICAgICAgICAgICBHZXRXaW5kb3dCeU5hbWUod2luZG93TmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXdSdW50aW1lKHdpbmRvd05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBMb2csXG4gICAgICAgIFNjcmVlbnMsXG4gICAgICAgIENhbGwsXG4gICAgICAgIFBsdWdpbixcbiAgICAgICAgV01MOiB7XG4gICAgICAgICAgICBSZWxvYWQ6IHJlbG9hZFdNTCxcbiAgICAgICAgfSxcbiAgICAgICAgRGlhbG9nOiB7XG4gICAgICAgICAgICBJbmZvLFxuICAgICAgICAgICAgV2FybmluZyxcbiAgICAgICAgICAgIEVycm9yLFxuICAgICAgICAgICAgUXVlc3Rpb24sXG4gICAgICAgICAgICBPcGVuRmlsZSxcbiAgICAgICAgICAgIFNhdmVGaWxlLFxuICAgICAgICB9LFxuICAgICAgICBFdmVudHM6IHtcbiAgICAgICAgICAgIEVtaXQsXG4gICAgICAgICAgICBPbixcbiAgICAgICAgICAgIE9uY2UsXG4gICAgICAgICAgICBPbk11bHRpcGxlLFxuICAgICAgICAgICAgT2ZmLFxuICAgICAgICAgICAgT2ZmQWxsLFxuICAgICAgICB9LFxuICAgICAgICBXaW5kb3c6IG5ld1dpbmRvdyh3aW5kb3dOYW1lKSxcbiAgICB9O1xufVxuXG5pZiAoREVCVUcpIHtcbiAgICBjb25zb2xlLmxvZyhcIldhaWxzIHYzLjAuMCBEZWJ1ZyBNb2RlIEVuYWJsZWRcIik7XG59XG5cbmVuYWJsZUNvbnRleHRNZW51cyh0cnVlKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDcEMsWUFBTSxLQUFLLFlBQVksRUFDbEIsS0FBSyxjQUFZO0FBQ2QsWUFBSSxTQUFTLElBQUk7QUFFYixjQUFJLFNBQVMsUUFBUSxJQUFJLGNBQWMsS0FBSyxTQUFTLFFBQVEsSUFBSSxjQUFjLEVBQUUsUUFBUSxrQkFBa0IsTUFBTSxJQUFJO0FBQ2pILG1CQUFPLFNBQVMsS0FBSztBQUFBLFVBQ3pCLE9BQU87QUFDSCxtQkFBTyxTQUFTLEtBQUs7QUFBQSxVQUN6QjtBQUFBLFFBQ0o7QUFDQSxlQUFPLE1BQU0sU0FBUyxVQUFVLENBQUM7QUFBQSxNQUNyQyxDQUFDLEVBQ0EsS0FBSyxVQUFRLFFBQVEsSUFBSSxDQUFDLEVBQzFCLE1BQU0sV0FBUyxPQUFPLEtBQUss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QUFJLENBQUMsRUFBQyxDQUFDLEVBQUUsS0FBSyxTQUFVLFFBQVE7QUFDdkgsZ0JBQUksV0FBVyxNQUFNO0FBQ2pCLCtCQUFpQixZQUFZO0FBQUEsWUFDakM7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSx5QkFBaUIsWUFBWTtBQUFBLE1BQ2pDO0FBR0EsY0FBUSxvQkFBb0IsU0FBUyxRQUFRO0FBRzdDLGNBQVEsaUJBQWlCLFNBQVMsUUFBUTtBQUFBLElBQzlDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxZQUFZO0FBQ3hCLHlCQUFxQjtBQUNyQiwwQkFBc0I7QUFBQSxFQUMxQjs7O0FDbERBLFNBQU8sUUFBUTtBQUFBLElBQ1gsR0FBRyxXQUFXLElBQUk7QUFBQSxFQUN0QjtBQUdBLFNBQU8sU0FBUztBQUFBLElBQ1o7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDSjtBQUVPLFdBQVMsV0FBVyxZQUFZO0FBQ25DLFdBQU87QUFBQSxNQUNILFdBQVc7QUFBQSxRQUNQLEdBQUc7QUFBQSxNQUNQO0FBQUEsTUFDQSxhQUFhO0FBQUEsUUFDVCxHQUFHO0FBQUEsUUFDSCxnQkFBZ0JDLGFBQVk7QUFDeEIsaUJBQU8sV0FBV0EsV0FBVTtBQUFBLFFBQ2hDO0FBQUEsTUFDSjtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBLEtBQUs7QUFBQSxRQUNELFFBQVE7QUFBQSxNQUNaO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBLE9BQUFDO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUTtBQUFBLFFBQ0o7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLE1BQ0o7QUFBQSxNQUNBLFFBQVEsVUFBVSxVQUFVO0FBQUEsSUFDaEM7QUFBQSxFQUNKO0FBRUEsTUFBSSxNQUFPO0FBQ1AsWUFBUSxJQUFJLGlDQUFpQztBQUFBLEVBQ2pEO0FBRUEscUJBQW1CLElBQUk7QUFFdkIsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvaW52b2tlLmpzIiwgImRlc2t0b3AvZHJhZy5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJjbGlwYm9hcmRcIik7XG5cbi8qKlxuICogU2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICovXG5leHBvcnQgZnVuY3Rpb24gU2V0VGV4dCh0ZXh0KSB7XG4gICAgdm9pZCBjYWxsKFwiU2V0VGV4dFwiLCB7dGV4dH0pO1xufVxuXG4vKipcbiAqIEdldCB0aGUgQ2xpcGJvYXJkIHRleHRcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBUZXh0KCkge1xuICAgIHJldHVybiBjYWxsKFwiVGV4dFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuY29uc3QgcnVudGltZVVSTCA9IHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gKyBcIi93YWlscy9ydW50aW1lXCI7XG5cbmZ1bmN0aW9uIHJ1bnRpbWVDYWxsKG1ldGhvZCwgd2luZG93TmFtZSwgYXJncykge1xuICAgIGxldCB1cmwgPSBuZXcgVVJMKHJ1bnRpbWVVUkwpO1xuICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKFwibWV0aG9kXCIsIG1ldGhvZCk7XG4gICAgaWYgKGFyZ3MpIHtcbiAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJhcmdzXCIsIEpTT04uc3RyaW5naWZ5KGFyZ3MpKTtcbiAgICB9XG4gICAgbGV0IGZldGNoT3B0aW9ucyA9IHtcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgfTtcbiAgICBpZiAod2luZG93TmFtZSkge1xuICAgICAgICBmZXRjaE9wdGlvbnMuaGVhZGVyc1tcIngtd2FpbHMtd2luZG93LW5hbWVcIl0gPSB3aW5kb3dOYW1lO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBmZXRjaCh1cmwsIGZldGNoT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgY29udGVudCB0eXBlXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKSAmJiByZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKS5pbmRleE9mKFwiYXBwbGljYXRpb24vanNvblwiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UudGV4dCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlamVjdChFcnJvcihyZXNwb25zZS5zdGF0dXNUZXh0KSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZGF0YSA9PiByZXNvbHZlKGRhdGEpKVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHJlamVjdChlcnJvcikpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbmV3UnVudGltZUNhbGxlcihvYmplY3QsIHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG1ldGhvZCwgYXJncz1udWxsKSB7XG4gICAgICAgIHJldHVybiBydW50aW1lQ2FsbChvYmplY3QgKyBcIi5cIiArIG1ldGhvZCwgd2luZG93TmFtZSwgYXJncyk7XG4gICAgfTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImFwcGxpY2F0aW9uXCIpO1xuXG4vKipcbiAqIEhpZGUgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBIaWRlKCkge1xuICAgIHZvaWQgY2FsbChcIkhpZGVcIik7XG59XG5cbi8qKlxuICogU2hvdyB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNob3coKSB7XG4gICAgdm9pZCBjYWxsKFwiU2hvd1wiKTtcbn1cblxuXG4vKipcbiAqIFF1aXQgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWl0KCkge1xuICAgIHZvaWQgY2FsbChcIlF1aXRcIik7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJsb2dcIik7XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuXG4gKiBAcGFyYW0ge21lc3NhZ2V9IE1lc3NhZ2UgdG8gbG9nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2cobWVzc2FnZSkge1xuICAgIHJldHVybiBjYWxsKFwiTG9nXCIsIG1lc3NhZ2UpO1xufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcInNjcmVlbnNcIik7XG5cbi8qKlxuICogR2V0cyBhbGwgc2NyZWVucy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbltdPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEFsbCgpIHtcbiAgICByZXR1cm4gY2FsbChcIkdldEFsbFwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBwcmltYXJ5IHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRQcmltYXJ5KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0UHJpbWFyeVwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBjdXJyZW50IGFjdGl2ZSBzY3JlZW4uXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTY3JlZW4+fVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRDdXJyZW50KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0Q3VycmVudFwiKTtcbn0iLCAibGV0IHVybEFscGhhYmV0ID1cbiAgJ3VzZWFuZG9tLTI2VDE5ODM0MFBYNzVweEpBQ0tWRVJZTUlOREJVU0hXT0xGX0dRWmJmZ2hqa2xxdnd5enJpY3QnXG5leHBvcnQgbGV0IGN1c3RvbUFscGhhYmV0ID0gKGFscGhhYmV0LCBkZWZhdWx0U2l6ZSA9IDIxKSA9PiB7XG4gIHJldHVybiAoc2l6ZSA9IGRlZmF1bHRTaXplKSA9PiB7XG4gICAgbGV0IGlkID0gJydcbiAgICBsZXQgaSA9IHNpemVcbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICBpZCArPSBhbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIGFscGhhYmV0Lmxlbmd0aCkgfCAwXVxuICAgIH1cbiAgICByZXR1cm4gaWRcbiAgfVxufVxuZXhwb3J0IGxldCBuYW5vaWQgPSAoc2l6ZSA9IDIxKSA9PiB7XG4gIGxldCBpZCA9ICcnXG4gIGxldCBpID0gc2l6ZVxuICB3aGlsZSAoaS0tKSB7XG4gICAgaWQgKz0gdXJsQWxwaGFiZXRbKE1hdGgucmFuZG9tKCkgKiA2NCkgfCAwXVxuICB9XG4gIHJldHVybiBpZFxufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNhbGxcIik7XG5cbmxldCBjYWxsUmVzcG9uc2VzID0gbmV3IE1hcCgpO1xuXG5mdW5jdGlvbiBnZW5lcmF0ZUlEKCkge1xuICAgIGxldCByZXN1bHQ7XG4gICAgZG8ge1xuICAgICAgICByZXN1bHQgPSBuYW5vaWQoKTtcbiAgICB9IHdoaWxlIChjYWxsUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbENhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBpZiAoaXNKU09OKSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoSlNPTi5wYXJzZShkYXRhKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGxFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBjYWxsUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNhbGxCaW5kaW5nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiY2FsbC1pZFwiXSA9IGlkO1xuICAgICAgICBjYWxsUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBDYWxsKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gY2FsbEJpbmRpbmcoXCJDYWxsXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIENhbGwgYSBwbHVnaW4gbWV0aG9kXG4gKiBAcGFyYW0ge3N0cmluZ30gcGx1Z2luTmFtZSAtIG5hbWUgb2YgdGhlIHBsdWdpblxuICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZE5hbWUgLSBuYW1lIG9mIHRoZSBtZXRob2RcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZFxuICogQHJldHVybnMge1Byb21pc2U8YW55Pn0gLSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBQbHVnaW4ocGx1Z2luTmFtZSwgbWV0aG9kTmFtZSwgLi4uYXJncykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwge1xuICAgICAgICBwYWNrYWdlTmFtZTogXCJ3YWlscy1wbHVnaW5zXCIsXG4gICAgICAgIHN0cnVjdE5hbWU6IHBsdWdpbk5hbWUsXG4gICAgICAgIG1ldGhvZE5hbWU6IG1ldGhvZE5hbWUsXG4gICAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgfSk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TaXplfSBTaXplXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlBvc2l0aW9ufSBQb3NpdGlvblxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TY3JlZW59IFNjcmVlblxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbmV3V2luZG93KHdpbmRvd05hbWUpIHtcbiAgICBsZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJ3aW5kb3dcIiwgd2luZG93TmFtZSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLy8gUmVsb2FkOiAoKSA9PiBjYWxsKCdXUicpLFxuICAgICAgICAvLyBSZWxvYWRBcHA6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFNldFN5c3RlbURlZmF1bHRUaGVtZTogKCkgPT4gY2FsbCgnV0FTRFQnKSxcbiAgICAgICAgLy8gU2V0TGlnaHRUaGVtZTogKCkgPT4gY2FsbCgnV0FMVCcpLFxuICAgICAgICAvLyBTZXREYXJrVGhlbWU6ICgpID0+IGNhbGwoJ1dBRFQnKSxcbiAgICAgICAgLy8gSXNGdWxsc2NyZWVuOiAoKSA9PiBjYWxsKCdXSUYnKSxcbiAgICAgICAgLy8gSXNNYXhpbWl6ZWQ6ICgpID0+IGNhbGwoJ1dJTScpLFxuICAgICAgICAvLyBJc01pbmltaXplZDogKCkgPT4gY2FsbCgnV0lNTicpLFxuICAgICAgICAvLyBJc1dpbmRvd2VkOiAoKSA9PiBjYWxsKCdXSUYnKSxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDZW50ZXJzIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBDZW50ZXI6ICgpID0+IHZvaWQgY2FsbCgnQ2VudGVyJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHRpdGxlLlxuICAgICAgICAgKiBAcGFyYW0gdGl0bGVcbiAgICAgICAgICovXG4gICAgICAgIFNldFRpdGxlOiAodGl0bGUpID0+IHZvaWQgY2FsbCgnU2V0VGl0bGUnLCB7dGl0bGV9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWFrZXMgdGhlIHdpbmRvdyBmdWxsc2NyZWVuLlxuICAgICAgICAgKi9cbiAgICAgICAgRnVsbHNjcmVlbjogKCkgPT4gdm9pZCBjYWxsKCdGdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFVuZnVsbHNjcmVlbiB0aGUgd2luZG93LlxuICAgICAgICAgKi9cbiAgICAgICAgVW5GdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ1VuRnVsbHNjcmVlbicpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggVGhlIHdpbmRvdyB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IFRoZSB3aW5kb3cgaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gY2FsbCgnU2V0U2l6ZScsIHt3aWR0aCxoZWlnaHR9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgc2l6ZS5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2l6ZT59IFRoZSB3aW5kb3cgc2l6ZVxuICAgICAgICAgKi9cbiAgICAgICAgU2l6ZTogKCkgPT4geyByZXR1cm4gY2FsbCgnU2l6ZScpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtYXhpbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNYXhTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNYXhTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtaW5pbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNaW5TaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNaW5TaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgd2luZG93IHRvIGJlIGFsd2F5cyBvbiB0b3AuXG4gICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gb25Ub3AgV2hldGhlciB0aGUgd2luZG93IHNob3VsZCBiZSBhbHdheXMgb24gdG9wXG4gICAgICAgICAqL1xuICAgICAgICBTZXRBbHdheXNPblRvcDogKG9uVG9wKSA9PiB2b2lkIGNhbGwoJ1NldEFsd2F5c09uVG9wJywge2Fsd2F5c09uVG9wOm9uVG9wfSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHBvc2l0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0UG9zaXRpb246ICh4LCB5KSA9PiBjYWxsKCdTZXRQb3NpdGlvbicsIHt4LHl9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFBvc2l0aW9uPn0gVGhlIHdpbmRvdyBwb3NpdGlvblxuICAgICAgICAgKi9cbiAgICAgICAgUG9zaXRpb246ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1Bvc2l0aW9uJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB0aGUgc2NyZWVuIHRoZSB3aW5kb3cgaXMgb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gICAgICAgICAqL1xuICAgICAgICBTY3JlZW46ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1NjcmVlbicpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBIaWRlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIEhpZGU6ICgpID0+IHZvaWQgY2FsbCgnSGlkZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTaG93IHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFNob3c6ICgpID0+IHZvaWQgY2FsbCgnU2hvdycpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDbG9zZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBDbG9zZTogKCkgPT4gdm9pZCBjYWxsKCdDbG9zZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUb2dnbGUgdGhlIHdpbmRvdyBtYXhpbWlzZSBzdGF0ZVxuICAgICAgICAgKi9cbiAgICAgICAgVG9nZ2xlTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVG9nZ2xlTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5tYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWluaW1pc2UgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5taW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1pbmltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSBiYWNrZ3JvdW5kIGNvbG91ciBvZiB0aGUgd2luZG93LlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gciAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGcgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYSAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICovXG4gICAgICAgIFNldEJhY2tncm91bmRDb2xvdXI6IChyLCBnLCBiLCBhKSA9PiB2b2lkIGNhbGwoJ1NldEJhY2tncm91bmRDb2xvdXInLCB7ciwgZywgYiwgYX0pLFxuICAgIH07XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuV2FpbHNFdmVudH0gV2FpbHNFdmVudFxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJldmVudHNcIik7XG5cbi8qKlxuICogVGhlIExpc3RlbmVyIGNsYXNzIGRlZmluZXMgYSBsaXN0ZW5lciEgOi0pXG4gKlxuICogQGNsYXNzIExpc3RlbmVyXG4gKi9cbmNsYXNzIExpc3RlbmVyIHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIExpc3RlbmVyLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAgICAgKiBAbWVtYmVyb2YgTGlzdGVuZXJcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpIHtcbiAgICAgICAgdGhpcy5ldmVudE5hbWUgPSBldmVudE5hbWU7XG4gICAgICAgIC8vIERlZmF1bHQgb2YgLTEgbWVhbnMgaW5maW5pdGVcbiAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgPSBtYXhDYWxsYmFja3MgfHwgLTE7XG4gICAgICAgIC8vIENhbGxiYWNrIGludm9rZXMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIGdpdmVuIGRhdGFcbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIHRoaXMgbGlzdGVuZXIgc2hvdWxkIGJlIGRlc3Ryb3llZFxuICAgICAgICB0aGlzLkNhbGxiYWNrID0gKGRhdGEpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGRhdGEpO1xuICAgICAgICAgICAgLy8gSWYgbWF4Q2FsbGJhY2tzIGlzIGluZmluaXRlLCByZXR1cm4gZmFsc2UgKGRvIG5vdCBkZXN0cm95KVxuICAgICAgICAgICAgaWYgKHRoaXMubWF4Q2FsbGJhY2tzID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIERlY3JlbWVudCBtYXhDYWxsYmFja3MuIFJldHVybiB0cnVlIGlmIG5vdyAwLCBvdGhlcndpc2UgZmFsc2VcbiAgICAgICAgICAgIHRoaXMubWF4Q2FsbGJhY2tzIC09IDE7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXhDYWxsYmFja3MgPT09IDA7XG4gICAgICAgIH07XG4gICAgfVxufVxuXG5cbi8qKlxuICogV2FpbHNFdmVudCBkZWZpbmVzIGEgY3VzdG9tIGV2ZW50LiBJdCBpcyBwYXNzZWQgdG8gZXZlbnQgbGlzdGVuZXJzLlxuICpcbiAqIEBjbGFzcyBXYWlsc0V2ZW50XG4gKiBAcHJvcGVydHkge3N0cmluZ30gbmFtZSAtIE5hbWUgb2YgdGhlIGV2ZW50XG4gKiBAcHJvcGVydHkge2FueX0gZGF0YSAtIERhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudFxuICovXG5leHBvcnQgY2xhc3MgV2FpbHNFdmVudCB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBXYWlsc0V2ZW50LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAgICAgKiBAcGFyYW0ge2FueT1udWxsfSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gICAgICogQG1lbWJlcm9mIFdhaWxzRXZlbnRcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihuYW1lLCBkYXRhID0gbnVsbCkge1xuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGV2ZW50TGlzdGVuZXJzID0gbmV3IE1hcCgpO1xuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbihXYWlsc0V2ZW50KTogdm9pZH0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAqIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgIGxldCBsaXN0ZW5lcnMgPSBldmVudExpc3RlbmVycy5nZXQoZXZlbnROYW1lKSB8fCBbXTtcbiAgICBjb25zdCB0aGlzTGlzdGVuZXIgPSBuZXcgTGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKTtcbiAgICBsaXN0ZW5lcnMucHVzaCh0aGlzTGlzdGVuZXIpO1xuICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgcmV0dXJuICgpID0+IGxpc3RlbmVyT2ZmKHRoaXNMaXN0ZW5lcik7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGV2ZXJ5IHRpbWUgdGhlIGV2ZW50IGlzIGVtaXR0ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAtMSk7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIG9uY2UgdGhlbiBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAxKTtcbn1cblxuLyoqXG4gKiBsaXN0ZW5lck9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uXG4gKlxuICogQHBhcmFtIHtMaXN0ZW5lcn0gbGlzdGVuZXJcbiAqL1xuZnVuY3Rpb24gbGlzdGVuZXJPZmYobGlzdGVuZXIpIHtcbiAgICBjb25zdCBldmVudE5hbWUgPSBsaXN0ZW5lci5ldmVudE5hbWU7XG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyXG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpLmZpbHRlcihsID0+IGwgIT09IGxpc3RlbmVyKTtcbiAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBldmVudExpc3RlbmVycy5zZXQoZXZlbnROYW1lLCBsaXN0ZW5lcnMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBkaXNwYXRjaGVzIGFuIGV2ZW50IHRvIGFsbCBsaXN0ZW5lcnNcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkaXNwYXRjaFdhaWxzRXZlbnQoZXZlbnQpIHtcbiAgICBjb25zb2xlLmxvZyhcImRpc3BhdGNoaW5nIGV2ZW50OiBcIiwge2V2ZW50fSk7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudC5uYW1lKTtcbiAgICBpZiAobGlzdGVuZXJzKSB7XG4gICAgICAgIC8vIGl0ZXJhdGUgbGlzdGVuZXJzIGFuZCBjYWxsIGNhbGxiYWNrLiBJZiBjYWxsYmFjayByZXR1cm5zIHRydWUsIHJlbW92ZSBsaXN0ZW5lclxuICAgICAgICBsZXQgdG9SZW1vdmUgPSBbXTtcbiAgICAgICAgbGlzdGVuZXJzLmZvckVhY2gobGlzdGVuZXIgPT4ge1xuICAgICAgICAgICAgbGV0IHJlbW92ZSA9IGxpc3RlbmVyLkNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgICAgIGlmIChyZW1vdmUpIHtcbiAgICAgICAgICAgICAgICB0b1JlbW92ZS5wdXNoKGxpc3RlbmVyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8vIHJlbW92ZSBsaXN0ZW5lcnNcbiAgICAgICAgaWYgKHRvUmVtb3ZlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IGxpc3RlbmVycy5maWx0ZXIobCA9PiAhdG9SZW1vdmUuaW5jbHVkZXMobCkpO1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnQubmFtZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudC5uYW1lLCBsaXN0ZW5lcnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIE9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uLFxuICogb3B0aW9uYWxseSBtdWx0aXBsZSBsaXN0ZW5lcnMgY2FuIGJlIHVucmVnaXN0ZXJlZCB2aWEgYGFkZGl0aW9uYWxFdmVudE5hbWVzYFxuICpcbiBbdjMgQ0hBTkdFXSBPZmYgb25seSB1bnJlZ2lzdGVycyBsaXN0ZW5lcnMgd2l0aGluIHRoZSBjdXJyZW50IHdpbmRvd1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSAgey4uLnN0cmluZ30gYWRkaXRpb25hbEV2ZW50TmFtZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9mZihldmVudE5hbWUsIC4uLmFkZGl0aW9uYWxFdmVudE5hbWVzKSB7XG4gICAgbGV0IGV2ZW50c1RvUmVtb3ZlID0gW2V2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXNdO1xuICAgIGV2ZW50c1RvUmVtb3ZlLmZvckVhY2goZXZlbnROYW1lID0+IHtcbiAgICAgICAgZXZlbnRMaXN0ZW5lcnMuZGVsZXRlKGV2ZW50TmFtZSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogT2ZmQWxsIHVucmVnaXN0ZXJzIGFsbCBsaXN0ZW5lcnNcbiAqIFt2MyBDSEFOR0VdIE9mZkFsbCBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmQWxsKCkge1xuICAgIGV2ZW50TGlzdGVuZXJzLmNsZWFyKCk7XG59XG5cbi8qKlxuICogRW1pdCBhbiBldmVudFxuICogQHBhcmFtIHtXYWlsc0V2ZW50fSBldmVudCBUaGUgZXZlbnQgdG8gZW1pdFxuICovXG5leHBvcnQgZnVuY3Rpb24gRW1pdChldmVudCkge1xuICAgIHZvaWQgY2FsbChcIkVtaXRcIiwgZXZlbnQpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5NZXNzYWdlRGlhbG9nT3B0aW9uc30gTWVzc2FnZURpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5PcGVuRGlhbG9nT3B0aW9uc30gT3BlbkRpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5TYXZlRGlhbG9nT3B0aW9uc30gU2F2ZURpYWxvZ09wdGlvbnNcbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSAnbmFub2lkL25vbi1zZWN1cmUnO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJkaWFsb2dcIik7XG5cbmxldCBkaWFsb2dSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGRpYWxvZ1Jlc3BvbnNlcy5oYXMocmVzdWx0KSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpYWxvZ0NhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGRpYWxvZ1Jlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nRXJyb3JDYWxsYmFjayhpZCwgbWVzc2FnZSkge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZGlhbG9nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiZGlhbG9nLWlkXCJdID0gaWQ7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5zZXQoaWQsIHtyZXNvbHZlLCByZWplY3R9KTtcbiAgICAgICAgY2FsbCh0eXBlLCBvcHRpb25zKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBTaG93cyBhbiBJbmZvIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gSW5mbyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkluZm9cIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gV2FybmluZyBkaWFsb2cgd2l0aCB0aGUgZ2l2ZW4gb3B0aW9ucy5cbiAqIEBwYXJhbSB7TWVzc2FnZURpYWxvZ09wdGlvbnN9IG9wdGlvbnNcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBsYWJlbCBvZiB0aGUgYnV0dG9uIHByZXNzZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdhcm5pbmcob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJXYXJuaW5nXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIEVycm9yIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gRXJyb3Iob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJFcnJvclwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFF1ZXN0aW9uIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gUXVlc3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJRdWVzdGlvblwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBPcGVuIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nW118c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZSBvciBhbiBhcnJheSBvZiBzZWxlY3RlZCBmaWxlcyBpZiBBbGxvd3NNdWx0aXBsZVNlbGVjdGlvbiBpcyB0cnVlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9wZW5GaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiT3BlbkZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYSBTYXZlIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZS4gQSBibGFuayBzdHJpbmcgaXMgcmV0dXJuZWQgaWYgbm8gZmlsZSB3YXMgc2VsZWN0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTYXZlRmlsZShvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlNhdmVGaWxlXCIsIG9wdGlvbnMpO1xufVxuXG4iLCAiaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNvbnRleHRtZW51XCIpO1xuXG5mdW5jdGlvbiBvcGVuQ29udGV4dE1lbnUoaWQsIHgsIHksIGRhdGEpIHtcbiAgICByZXR1cm4gY2FsbChcIk9wZW5Db250ZXh0TWVudVwiLCB7aWQsIHgsIHksIGRhdGF9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnRleHRNZW51cyhlbmFibGVkKSB7XG4gICAgaWYgKGVuYWJsZWQpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51JywgY29udGV4dE1lbnVIYW5kbGVyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY29udGV4dE1lbnVIYW5kbGVyKGV2ZW50KSB7XG4gICAgcHJvY2Vzc0NvbnRleHRNZW51KGV2ZW50LnRhcmdldCwgZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBwcm9jZXNzQ29udGV4dE1lbnUoZWxlbWVudCwgZXZlbnQpIHtcbiAgICBsZXQgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1jb250ZXh0bWVudScpO1xuICAgIGlmIChpZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBvcGVuQ29udGV4dE1lbnUoaWQsIGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51LWRhdGEnKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHBhcmVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgICAgICAgaWYgKHBhcmVudCkge1xuICAgICAgICAgICAgcHJvY2Vzc0NvbnRleHRNZW51KHBhcmVudCwgZXZlbnQpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwgIlxuaW1wb3J0IHtFbWl0LCBXYWlsc0V2ZW50fSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7UXVlc3Rpb259IGZyb20gXCIuL2RpYWxvZ3NcIjtcblxuZnVuY3Rpb24gc2VuZEV2ZW50KGV2ZW50TmFtZSwgZGF0YT1udWxsKSB7XG4gICAgbGV0IGV2ZW50ID0gbmV3IFdhaWxzRXZlbnQoZXZlbnROYW1lLCBkYXRhKTtcbiAgICBFbWl0KGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gYWRkV01MRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtZXZlbnRdJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBldmVudFR5cGUgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtZXZlbnQnKTtcbiAgICAgICAgY29uc3QgY29uZmlybSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1jb25maXJtJyk7XG4gICAgICAgIGNvbnN0IHRyaWdnZXIgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtdHJpZ2dlcicpIHx8IFwiY2xpY2tcIjtcblxuICAgICAgICBsZXQgY2FsbGJhY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlybSkge1xuICAgICAgICAgICAgICAgIFF1ZXN0aW9uKHtUaXRsZTogXCJDb25maXJtXCIsIE1lc3NhZ2U6Y29uZmlybSwgQnV0dG9uczpbe0xhYmVsOlwiWWVzXCJ9LHtMYWJlbDpcIk5vXCIsIElzRGVmYXVsdDp0cnVlfV19KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdCAhPT0gXCJOb1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZW5kRXZlbnQoZXZlbnRUeXBlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG5cbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIGNhbGxXaW5kb3dNZXRob2QobWV0aG9kKSB7XG4gICAgaWYgKHdhaWxzLldpbmRvd1ttZXRob2RdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJXaW5kb3cgbWV0aG9kIFwiICsgbWV0aG9kICsgXCIgbm90IGZvdW5kXCIpO1xuICAgIH1cbiAgICB3YWlscy5XaW5kb3dbbWV0aG9kXSgpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtd2luZG93XScpO1xuICAgIGVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qgd2luZG93TWV0aG9kID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXdpbmRvdycpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG5cbiAgICAgICAgLy8gQWRkIG5ldyBsaXN0ZW5lclxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVsb2FkV01MKCkge1xuICAgIGFkZFdNTEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgYWRkV01MV2luZG93TGlzdGVuZXJzKCk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLy8gZGVmaW5lZCBpbiB0aGUgVGFza2ZpbGVcbmV4cG9ydCBsZXQgaW52b2tlID0gKFdJTkRPV1M/Y2hyb21lLndlYnZpZXcucG9zdE1lc3NhZ2U6d2luZG93LndlYmtpdC5tZXNzYWdlSGFuZGxlcnMuZXh0ZXJuYWwucG9zdE1lc3NhZ2UpO1xuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7aW52b2tlfSBmcm9tIFwiLi9pbnZva2VcIjtcblxubGV0IHNob3VsZERyYWcgPSBmYWxzZTtcblxuZXhwb3J0IGZ1bmN0aW9uIGRyYWdUZXN0KGUpIHtcbiAgICBsZXQgdmFsID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZS50YXJnZXQpLmdldFByb3BlcnR5VmFsdWUoXCItLXdhaWxzLWRyYWdnYWJsZVwiKTtcbiAgICBpZiAodmFsKSB7XG4gICAgICAgIHZhbCA9IHZhbC50cmltKCk7XG4gICAgfVxuXG4gICAgaWYgKHZhbCAhPT0gXCJkcmFnXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIE9ubHkgcHJvY2VzcyB0aGUgcHJpbWFyeSBidXR0b25cbiAgICBpZiAoZS5idXR0b25zICE9PSAxKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZS5kZXRhaWwgPT09IDE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cERyYWcoKSB7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIG9uTW91c2VEb3duKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgb25Nb3VzZU1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25Nb3VzZVVwKTtcbn1cblxuZnVuY3Rpb24gb25Nb3VzZURvd24oZSkge1xuICAgIGlmIChkcmFnVGVzdChlKSkge1xuICAgICAgICAvLyBJZ25vcmUgZHJhZyBvbiBzY3JvbGxiYXJzXG4gICAgICAgIGlmIChlLm9mZnNldFggPiBlLnRhcmdldC5jbGllbnRXaWR0aCB8fCBlLm9mZnNldFkgPiBlLnRhcmdldC5jbGllbnRIZWlnaHQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzaG91bGREcmFnID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbk1vdXNlVXAoZSkge1xuICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gd2luZG93LndhaWxzLnByZXZpb3VzQ3Vyc29yIHx8ICdhdXRvJztcbiAgICBzaG91bGREcmFnID0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIG9uTW91c2VNb3ZlKGUpIHtcbiAgICBpZiAoc2hvdWxkRHJhZykge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgICAgIGxldCBtb3VzZVByZXNzZWQgPSBlLmJ1dHRvbnMgIT09IHVuZGVmaW5lZCA/IGUuYnV0dG9ucyA6IGUud2hpY2g7XG4gICAgICAgIGlmIChtb3VzZVByZXNzZWQgPiAwKSB7XG4gICAgICAgICAgICB3aW5kb3cud2FpbHMucHJldmlvdXNDdXJzb3IgPSBkb2N1bWVudC5ib2R5LnN0eWxlLmN1cnNvcjtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gJ2dyYWInO1xuICAgICAgICAgICAgaW52b2tlKFwiZHJhZ1wiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cblxuaW1wb3J0ICogYXMgQ2xpcGJvYXJkIGZyb20gJy4vY2xpcGJvYXJkJztcbmltcG9ydCAqIGFzIEFwcGxpY2F0aW9uIGZyb20gJy4vYXBwbGljYXRpb24nO1xuaW1wb3J0ICogYXMgTG9nIGZyb20gJy4vbG9nJztcbmltcG9ydCAqIGFzIFNjcmVlbnMgZnJvbSAnLi9zY3JlZW5zJztcbmltcG9ydCB7UGx1Z2luLCBDYWxsLCBjYWxsRXJyb3JDYWxsYmFjaywgY2FsbENhbGxiYWNrfSBmcm9tIFwiLi9jYWxsc1wiO1xuaW1wb3J0IHtuZXdXaW5kb3d9IGZyb20gXCIuL3dpbmRvd1wiO1xuaW1wb3J0IHtkaXNwYXRjaFdhaWxzRXZlbnQsIEVtaXQsIE9mZiwgT2ZmQWxsLCBPbiwgT25jZSwgT25NdWx0aXBsZX0gZnJvbSBcIi4vZXZlbnRzXCI7XG5pbXBvcnQge2RpYWxvZ0NhbGxiYWNrLCBkaWFsb2dFcnJvckNhbGxiYWNrLCBFcnJvciwgSW5mbywgT3BlbkZpbGUsIFF1ZXN0aW9uLCBTYXZlRmlsZSwgV2FybmluZyx9IGZyb20gXCIuL2RpYWxvZ3NcIjtcbmltcG9ydCB7ZW5hYmxlQ29udGV4dE1lbnVzfSBmcm9tIFwiLi9jb250ZXh0bWVudVwiO1xuaW1wb3J0IHtyZWxvYWRXTUx9IGZyb20gXCIuL3dtbFwiO1xuaW1wb3J0IHtzZXR1cERyYWd9IGZyb20gXCIuL2RyYWdcIjtcblxud2luZG93LndhaWxzID0ge1xuICAgIC4uLm5ld1J1bnRpbWUobnVsbCksXG59O1xuXG4vLyBJbnRlcm5hbCB3YWlscyBlbmRwb2ludHNcbndpbmRvdy5fd2FpbHMgPSB7XG4gICAgZGlhbG9nQ2FsbGJhY2ssXG4gICAgZGlhbG9nRXJyb3JDYWxsYmFjayxcbiAgICBkaXNwYXRjaFdhaWxzRXZlbnQsXG4gICAgY2FsbENhbGxiYWNrLFxuICAgIGNhbGxFcnJvckNhbGxiYWNrLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIG5ld1J1bnRpbWUod2luZG93TmFtZSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIENsaXBib2FyZDoge1xuICAgICAgICAgICAgLi4uQ2xpcGJvYXJkXG4gICAgICAgIH0sXG4gICAgICAgIEFwcGxpY2F0aW9uOiB7XG4gICAgICAgICAgICAuLi5BcHBsaWNhdGlvbixcbiAgICAgICAgICAgIEdldFdpbmRvd0J5TmFtZSh3aW5kb3dOYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ld1J1bnRpbWUod2luZG93TmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIExvZyxcbiAgICAgICAgU2NyZWVucyxcbiAgICAgICAgQ2FsbCxcbiAgICAgICAgUGx1Z2luLFxuICAgICAgICBXTUw6IHtcbiAgICAgICAgICAgIFJlbG9hZDogcmVsb2FkV01MLFxuICAgICAgICB9LFxuICAgICAgICBEaWFsb2c6IHtcbiAgICAgICAgICAgIEluZm8sXG4gICAgICAgICAgICBXYXJuaW5nLFxuICAgICAgICAgICAgRXJyb3IsXG4gICAgICAgICAgICBRdWVzdGlvbixcbiAgICAgICAgICAgIE9wZW5GaWxlLFxuICAgICAgICAgICAgU2F2ZUZpbGUsXG4gICAgICAgIH0sXG4gICAgICAgIEV2ZW50czoge1xuICAgICAgICAgICAgRW1pdCxcbiAgICAgICAgICAgIE9uLFxuICAgICAgICAgICAgT25jZSxcbiAgICAgICAgICAgIE9uTXVsdGlwbGUsXG4gICAgICAgICAgICBPZmYsXG4gICAgICAgICAgICBPZmZBbGwsXG4gICAgICAgIH0sXG4gICAgICAgIFdpbmRvdzogbmV3V2luZG93KHdpbmRvd05hbWUpLFxuICAgIH07XG59XG5cbmlmIChERUJVRykge1xuICAgIGNvbnNvbGUubG9nKFwiV2FpbHMgdjMuMC4wIERlYnVnIE1vZGUgRW5hYmxlZFwiKTtcbn1cblxuZW5hYmxlQ29udGV4dE1lbnVzKHRydWUpO1xuXG5zZXR1cERyYWcoKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDcEMsWUFBTSxLQUFLLFlBQVksRUFDbEIsS0FBSyxjQUFZO0FBQ2QsWUFBSSxTQUFTLElBQUk7QUFFYixjQUFJLFNBQVMsUUFBUSxJQUFJLGNBQWMsS0FBSyxTQUFTLFFBQVEsSUFBSSxjQUFjLEVBQUUsUUFBUSxrQkFBa0IsTUFBTSxJQUFJO0FBQ2pILG1CQUFPLFNBQVMsS0FBSztBQUFBLFVBQ3pCLE9BQU87QUFDSCxtQkFBTyxTQUFTLEtBQUs7QUFBQSxVQUN6QjtBQUFBLFFBQ0o7QUFDQSxlQUFPLE1BQU0sU0FBUyxVQUFVLENBQUM7QUFBQSxNQUNyQyxDQUFDLEVBQ0EsS0FBSyxVQUFRLFFBQVEsSUFBSSxDQUFDLEVBQzFCLE1BQU0sV0FBUyxPQUFPLEtBQUssQ0FBQztBQUFBLElBQ3JDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxpQkFBaUIsUUFBUSxZQUFZO0FBQ2pELFdBQU8sU0FBVSxRQUFRLE9BQUssTUFBTTtBQUNoQyxhQUFPLFlBQVksU0FBUyxNQUFNLFFBQVEsWUFBWSxJQUFJO0FBQUEsSUFDOUQ7QUFBQSxFQUNKOzs7QURsQ0EsTUFBSSxPQUFPLGlCQUFpQixXQUFXO0FBS2hDLFdBQVMsUUFBUSxNQUFNO0FBQzFCLFNBQUssS0FBSyxXQUFXLEVBQUMsS0FBSSxDQUFDO0FBQUEsRUFDL0I7QUFNTyxXQUFTLE9BQU87QUFDbkIsV0FBTyxLQUFLLE1BQU07QUFBQSxFQUN0Qjs7O0FFN0JBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQWNBLE1BQUlBLFFBQU8saUJBQWlCLGFBQWE7QUFLbEMsV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCO0FBS08sV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCO0FBTU8sV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCOzs7QUNwQ0E7QUFBQTtBQUFBO0FBQUE7QUFjQSxNQUFJQyxRQUFPLGlCQUFpQixLQUFLO0FBTTFCLFdBQVMsSUFBSSxTQUFTO0FBQ3pCLFdBQU9BLE1BQUssT0FBTyxPQUFPO0FBQUEsRUFDOUI7OztBQ3RCQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFrQkEsTUFBSUMsUUFBTyxpQkFBaUIsU0FBUztBQU05QixXQUFTLFNBQVM7QUFDckIsV0FBT0EsTUFBSyxRQUFRO0FBQUEsRUFDeEI7QUFNTyxXQUFTLGFBQWE7QUFDekIsV0FBT0EsTUFBSyxZQUFZO0FBQUEsRUFDNUI7QUFPTyxXQUFTLGFBQWE7QUFDekIsV0FBT0EsTUFBSyxZQUFZO0FBQUEsRUFDNUI7OztBQzNDQSxNQUFJLGNBQ0Y7QUFXSyxNQUFJLFNBQVMsQ0FBQyxPQUFPLE9BQU87QUFDakMsUUFBSSxLQUFLO0FBQ1QsUUFBSSxJQUFJO0FBQ1IsV0FBTyxLQUFLO0FBQ1YsWUFBTSxZQUFhLEtBQUssT0FBTyxJQUFJLEtBQU0sQ0FBQztBQUFBLElBQzVDO0FBQ0EsV0FBTztBQUFBLEVBQ1Q7OztBQ0hBLE1BQUlDLFFBQU8saUJBQWlCLE1BQU07QUFFbEMsTUFBSSxnQkFBZ0Isb0JBQUksSUFBSTtBQUU1QixXQUFTLGFBQWE7QUFDbEIsUUFBSTtBQUNKLE9BQUc7QUFDQyxlQUFTLE9BQU87QUFBQSxJQUNwQixTQUFTLGNBQWMsSUFBSSxNQUFNO0FBQ2pDLFdBQU87QUFBQSxFQUNYO0FBRU8sV0FBUyxhQUFhLElBQUksTUFBTSxRQUFRO0FBQzNDLFFBQUksSUFBSSxjQUFjLElBQUksRUFBRTtBQUM1QixRQUFJLEdBQUc7QUFDSCxVQUFJLFFBQVE7QUFDUixVQUFFLFFBQVEsS0FBSyxNQUFNLElBQUksQ0FBQztBQUFBLE1BQzlCLE9BQU87QUFDSCxVQUFFLFFBQVEsSUFBSTtBQUFBLE1BQ2xCO0FBQ0Esb0JBQWMsT0FBTyxFQUFFO0FBQUEsSUFDM0I7QUFBQSxFQUNKO0FBRU8sV0FBUyxrQkFBa0IsSUFBSSxTQUFTO0FBQzNDLFFBQUksSUFBSSxjQUFjLElBQUksRUFBRTtBQUM1QixRQUFJLEdBQUc7QUFDSCxRQUFFLE9BQU8sT0FBTztBQUNoQixvQkFBYyxPQUFPLEVBQUU7QUFBQSxJQUMzQjtBQUFBLEVBQ0o7QUFFQSxXQUFTLFlBQVksTUFBTSxTQUFTO0FBQ2hDLFdBQU8sSUFBSSxRQUFRLENBQUMsU0FBUyxXQUFXO0FBQ3BDLFVBQUksS0FBSyxXQUFXO0FBQ3BCLGdCQUFVLFdBQVcsQ0FBQztBQUN0QixjQUFRLFNBQVMsSUFBSTtBQUNyQixvQkFBYyxJQUFJLElBQUksRUFBQyxTQUFTLE9BQU0sQ0FBQztBQUN2QyxNQUFBQSxNQUFLLE1BQU0sT0FBTyxFQUFFLE1BQU0sQ0FBQyxVQUFVO0FBQ2pDLGVBQU8sS0FBSztBQUNaLHNCQUFjLE9BQU8sRUFBRTtBQUFBLE1BQzNCLENBQUM7QUFBQSxJQUNMLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxLQUFLLFNBQVM7QUFDMUIsV0FBTyxZQUFZLFFBQVEsT0FBTztBQUFBLEVBQ3RDO0FBU08sV0FBUyxPQUFPLFlBQVksZUFBZSxNQUFNO0FBQ3BELFdBQU8sWUFBWSxRQUFRO0FBQUEsTUFDdkIsYUFBYTtBQUFBLE1BQ2IsWUFBWTtBQUFBLE1BQ1o7QUFBQSxNQUNBO0FBQUEsSUFDSixDQUFDO0FBQUEsRUFDTDs7O0FDM0RPLFdBQVMsVUFBVSxZQUFZO0FBQ2xDLFFBQUlDLFFBQU8saUJBQWlCLFVBQVUsVUFBVTtBQUNoRCxXQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFlSCxRQUFRLE1BQU0sS0FBS0EsTUFBSyxRQUFRO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU1oQyxVQUFVLENBQUMsVUFBVSxLQUFLQSxNQUFLLFlBQVksRUFBQyxNQUFLLENBQUM7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUtsRCxZQUFZLE1BQU0sS0FBS0EsTUFBSyxZQUFZO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLeEMsY0FBYyxNQUFNLEtBQUtBLE1BQUssY0FBYztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU81QyxTQUFTLENBQUMsT0FBTyxXQUFXQSxNQUFLLFdBQVcsRUFBQyxPQUFNLE9BQU0sQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNMUQsTUFBTSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxNQUFNO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU9uQyxZQUFZLENBQUMsT0FBTyxXQUFXLEtBQUtBLE1BQUssY0FBYyxFQUFDLE9BQU0sT0FBTSxDQUFDO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BT3JFLFlBQVksQ0FBQyxPQUFPLFdBQVcsS0FBS0EsTUFBSyxjQUFjLEVBQUMsT0FBTSxPQUFNLENBQUM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BTXJFLGdCQUFnQixDQUFDLFVBQVUsS0FBS0EsTUFBSyxrQkFBa0IsRUFBQyxhQUFZLE1BQUssQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU8xRSxhQUFhLENBQUMsR0FBRyxNQUFNQSxNQUFLLGVBQWUsRUFBQyxHQUFFLEVBQUMsQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNaEQsVUFBVSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxVQUFVO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNM0MsUUFBUSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxRQUFRO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBLE1BS3ZDLE1BQU0sTUFBTSxLQUFLQSxNQUFLLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUs1QixVQUFVLE1BQU0sS0FBS0EsTUFBSyxVQUFVO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLcEMsTUFBTSxNQUFNLEtBQUtBLE1BQUssTUFBTTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BSzVCLE9BQU8sTUFBTSxLQUFLQSxNQUFLLE9BQU87QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUs5QixnQkFBZ0IsTUFBTSxLQUFLQSxNQUFLLGdCQUFnQjtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BS2hELFlBQVksTUFBTSxLQUFLQSxNQUFLLFlBQVk7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUt4QyxVQUFVLE1BQU0sS0FBS0EsTUFBSyxVQUFVO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLcEMsWUFBWSxNQUFNLEtBQUtBLE1BQUssWUFBWTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFTeEMscUJBQXFCLENBQUMsR0FBRyxHQUFHLEdBQUcsTUFBTSxLQUFLQSxNQUFLLHVCQUF1QixFQUFDLEdBQUcsR0FBRyxHQUFHLEVBQUMsQ0FBQztBQUFBLElBQ3RGO0FBQUEsRUFDSjs7O0FDMUlBLE1BQUlDLFFBQU8saUJBQWlCLFFBQVE7QUFPcEMsTUFBTSxXQUFOLE1BQWU7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLElBUVgsWUFBWSxXQUFXLFVBQVUsY0FBYztBQUMzQyxXQUFLLFlBQVk7QUFFakIsV0FBSyxlQUFlLGdCQUFnQjtBQUdwQyxXQUFLLFdBQVcsQ0FBQyxTQUFTO0FBQ3RCLGlCQUFTLElBQUk7QUFFYixZQUFJLEtBQUssaUJBQWlCLElBQUk7QUFDMUIsaUJBQU87QUFBQSxRQUNYO0FBRUEsYUFBSyxnQkFBZ0I7QUFDckIsZUFBTyxLQUFLLGlCQUFpQjtBQUFBLE1BQ2pDO0FBQUEsSUFDSjtBQUFBLEVBQ0o7QUFVTyxNQUFNLGFBQU4sTUFBaUI7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxJQU9wQixZQUFZLE1BQU0sT0FBTyxNQUFNO0FBQzNCLFdBQUssT0FBTztBQUNaLFdBQUssT0FBTztBQUFBLElBQ2hCO0FBQUEsRUFDSjtBQUVPLE1BQU0saUJBQWlCLG9CQUFJLElBQUk7QUFXL0IsV0FBUyxXQUFXLFdBQVcsVUFBVSxjQUFjO0FBQzFELFFBQUksWUFBWSxlQUFlLElBQUksU0FBUyxLQUFLLENBQUM7QUFDbEQsVUFBTSxlQUFlLElBQUksU0FBUyxXQUFXLFVBQVUsWUFBWTtBQUNuRSxjQUFVLEtBQUssWUFBWTtBQUMzQixtQkFBZSxJQUFJLFdBQVcsU0FBUztBQUN2QyxXQUFPLE1BQU0sWUFBWSxZQUFZO0FBQUEsRUFDekM7QUFVTyxXQUFTLEdBQUcsV0FBVyxVQUFVO0FBQ3BDLFdBQU8sV0FBVyxXQUFXLFVBQVUsRUFBRTtBQUFBLEVBQzdDO0FBVU8sV0FBUyxLQUFLLFdBQVcsVUFBVTtBQUN0QyxXQUFPLFdBQVcsV0FBVyxVQUFVLENBQUM7QUFBQSxFQUM1QztBQU9BLFdBQVMsWUFBWSxVQUFVO0FBQzNCLFVBQU0sWUFBWSxTQUFTO0FBRTNCLFFBQUksWUFBWSxlQUFlLElBQUksU0FBUyxFQUFFLE9BQU8sT0FBSyxNQUFNLFFBQVE7QUFDeEUsUUFBSSxVQUFVLFdBQVcsR0FBRztBQUN4QixxQkFBZSxPQUFPLFNBQVM7QUFBQSxJQUNuQyxPQUFPO0FBQ0gscUJBQWUsSUFBSSxXQUFXLFNBQVM7QUFBQSxJQUMzQztBQUFBLEVBQ0o7QUFRTyxXQUFTLG1CQUFtQixPQUFPO0FBQ3RDLFlBQVEsSUFBSSx1QkFBdUIsRUFBQyxNQUFLLENBQUM7QUFDMUMsUUFBSSxZQUFZLGVBQWUsSUFBSSxNQUFNLElBQUk7QUFDN0MsUUFBSSxXQUFXO0FBRVgsVUFBSSxXQUFXLENBQUM7QUFDaEIsZ0JBQVUsUUFBUSxjQUFZO0FBQzFCLFlBQUksU0FBUyxTQUFTLFNBQVMsS0FBSztBQUNwQyxZQUFJLFFBQVE7QUFDUixtQkFBUyxLQUFLLFFBQVE7QUFBQSxRQUMxQjtBQUFBLE1BQ0osQ0FBQztBQUVELFVBQUksU0FBUyxTQUFTLEdBQUc7QUFDckIsb0JBQVksVUFBVSxPQUFPLE9BQUssQ0FBQyxTQUFTLFNBQVMsQ0FBQyxDQUFDO0FBQ3ZELFlBQUksVUFBVSxXQUFXLEdBQUc7QUFDeEIseUJBQWUsT0FBTyxNQUFNLElBQUk7QUFBQSxRQUNwQyxPQUFPO0FBQ0gseUJBQWUsSUFBSSxNQUFNLE1BQU0sU0FBUztBQUFBLFFBQzVDO0FBQUEsTUFDSjtBQUFBLElBQ0o7QUFBQSxFQUNKO0FBV08sV0FBUyxJQUFJLGNBQWMsc0JBQXNCO0FBQ3BELFFBQUksaUJBQWlCLENBQUMsV0FBVyxHQUFHLG9CQUFvQjtBQUN4RCxtQkFBZSxRQUFRLENBQUFDLGVBQWE7QUFDaEMscUJBQWUsT0FBT0EsVUFBUztBQUFBLElBQ25DLENBQUM7QUFBQSxFQUNMO0FBT08sV0FBUyxTQUFTO0FBQ3JCLG1CQUFlLE1BQU07QUFBQSxFQUN6QjtBQU1PLFdBQVMsS0FBSyxPQUFPO0FBQ3hCLFNBQUtELE1BQUssUUFBUSxLQUFLO0FBQUEsRUFDM0I7OztBQzNLQSxNQUFJRSxRQUFPLGlCQUFpQixRQUFRO0FBRXBDLE1BQUksa0JBQWtCLG9CQUFJLElBQUk7QUFFOUIsV0FBU0MsY0FBYTtBQUNsQixRQUFJO0FBQ0osT0FBRztBQUNDLGVBQVMsT0FBTztBQUFBLElBQ3BCLFNBQVMsZ0JBQWdCLElBQUksTUFBTTtBQUNuQyxXQUFPO0FBQUEsRUFDWDtBQUVPLFdBQVMsZUFBZSxJQUFJLE1BQU0sUUFBUTtBQUM3QyxRQUFJLElBQUksZ0JBQWdCLElBQUksRUFBRTtBQUM5QixRQUFJLEdBQUc7QUFDSCxVQUFJLFFBQVE7QUFDUixVQUFFLFFBQVEsS0FBSyxNQUFNLElBQUksQ0FBQztBQUFBLE1BQzlCLE9BQU87QUFDSCxVQUFFLFFBQVEsSUFBSTtBQUFBLE1BQ2xCO0FBQ0Esc0JBQWdCLE9BQU8sRUFBRTtBQUFBLElBQzdCO0FBQUEsRUFDSjtBQUNPLFdBQVMsb0JBQW9CLElBQUksU0FBUztBQUM3QyxRQUFJLElBQUksZ0JBQWdCLElBQUksRUFBRTtBQUM5QixRQUFJLEdBQUc7QUFDSCxRQUFFLE9BQU8sT0FBTztBQUNoQixzQkFBZ0IsT0FBTyxFQUFFO0FBQUEsSUFDN0I7QUFBQSxFQUNKO0FBRUEsV0FBUyxPQUFPLE1BQU0sU0FBUztBQUMzQixXQUFPLElBQUksUUFBUSxDQUFDLFNBQVMsV0FBVztBQUNwQyxVQUFJLEtBQUtBLFlBQVc7QUFDcEIsZ0JBQVUsV0FBVyxDQUFDO0FBQ3RCLGNBQVEsV0FBVyxJQUFJO0FBQ3ZCLHNCQUFnQixJQUFJLElBQUksRUFBQyxTQUFTLE9BQU0sQ0FBQztBQUN6QyxNQUFBRCxNQUFLLE1BQU0sT0FBTyxFQUFFLE1BQU0sQ0FBQyxVQUFVO0FBQ2pDLGVBQU8sS0FBSztBQUNaLHdCQUFnQixPQUFPLEVBQUU7QUFBQSxNQUM3QixDQUFDO0FBQUEsSUFDTCxDQUFDO0FBQUEsRUFDTDtBQVFPLFdBQVMsS0FBSyxTQUFTO0FBQzFCLFdBQU8sT0FBTyxRQUFRLE9BQU87QUFBQSxFQUNqQztBQU9PLFdBQVMsUUFBUSxTQUFTO0FBQzdCLFdBQU8sT0FBTyxXQUFXLE9BQU87QUFBQSxFQUNwQztBQU9PLFdBQVNFLE9BQU0sU0FBUztBQUMzQixXQUFPLE9BQU8sU0FBUyxPQUFPO0FBQUEsRUFDbEM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7OztBQ3JIQSxNQUFJQyxRQUFPLGlCQUFpQixhQUFhO0FBRXpDLFdBQVMsZ0JBQWdCLElBQUksR0FBRyxHQUFHLE1BQU07QUFDckMsV0FBT0EsTUFBSyxtQkFBbUIsRUFBQyxJQUFJLEdBQUcsR0FBRyxLQUFJLENBQUM7QUFBQSxFQUNuRDtBQUVPLFdBQVMsbUJBQW1CLFNBQVM7QUFDeEMsUUFBSSxTQUFTO0FBQ1QsYUFBTyxpQkFBaUIsZUFBZSxrQkFBa0I7QUFBQSxJQUM3RCxPQUFPO0FBQ0gsYUFBTyxvQkFBb0IsZUFBZSxrQkFBa0I7QUFBQSxJQUNoRTtBQUFBLEVBQ0o7QUFFQSxXQUFTLG1CQUFtQixPQUFPO0FBQy9CLHVCQUFtQixNQUFNLFFBQVEsS0FBSztBQUFBLEVBQzFDO0FBRUEsV0FBUyxtQkFBbUIsU0FBUyxPQUFPO0FBQ3hDLFFBQUksS0FBSyxRQUFRLGFBQWEsa0JBQWtCO0FBQ2hELFFBQUksSUFBSTtBQUNKLFlBQU0sZUFBZTtBQUNyQixzQkFBZ0IsSUFBSSxNQUFNLFNBQVMsTUFBTSxTQUFTLFFBQVEsYUFBYSx1QkFBdUIsQ0FBQztBQUFBLElBQ25HLE9BQU87QUFDSCxVQUFJLFNBQVMsUUFBUTtBQUNyQixVQUFJLFFBQVE7QUFDUiwyQkFBbUIsUUFBUSxLQUFLO0FBQUEsTUFDcEM7QUFBQSxJQUNKO0FBQUEsRUFDSjs7O0FDM0JBLFdBQVMsVUFBVSxXQUFXLE9BQUssTUFBTTtBQUNyQyxRQUFJLFFBQVEsSUFBSSxXQUFXLFdBQVcsSUFBSTtBQUMxQyxTQUFLLEtBQUs7QUFBQSxFQUNkO0FBRUEsV0FBUyx1QkFBdUI7QUFDNUIsVUFBTSxXQUFXLFNBQVMsaUJBQWlCLGtCQUFrQjtBQUM3RCxhQUFTLFFBQVEsU0FBVSxTQUFTO0FBQ2hDLFlBQU0sWUFBWSxRQUFRLGFBQWEsZ0JBQWdCO0FBQ3ZELFlBQU0sVUFBVSxRQUFRLGFBQWEsa0JBQWtCO0FBQ3ZELFlBQU0sVUFBVSxRQUFRLGFBQWEsa0JBQWtCLEtBQUs7QUFFNUQsVUFBSSxXQUFXLFdBQVk7QUFDdkIsWUFBSSxTQUFTO0FBQ1QsbUJBQVMsRUFBQyxPQUFPLFdBQVcsU0FBUSxTQUFTLFNBQVEsQ0FBQyxFQUFDLE9BQU0sTUFBSyxHQUFFLEVBQUMsT0FBTSxNQUFNLFdBQVUsS0FBSSxDQUFDLEVBQUMsQ0FBQyxFQUFFLEtBQUssU0FBVSxRQUFRO0FBQ3ZILGdCQUFJLFdBQVcsTUFBTTtBQUNqQix3QkFBVSxTQUFTO0FBQUEsWUFDdkI7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSxrQkFBVSxTQUFTO0FBQUEsTUFDdkI7QUFHQSxjQUFRLG9CQUFvQixTQUFTLFFBQVE7QUFHN0MsY0FBUSxpQkFBaUIsU0FBUyxRQUFRO0FBQUEsSUFDOUMsQ0FBQztBQUFBLEVBQ0w7QUFFQSxXQUFTLGlCQUFpQixRQUFRO0FBQzlCLFFBQUksTUFBTSxPQUFPLE1BQU0sTUFBTSxRQUFXO0FBQ3BDLGNBQVEsSUFBSSxtQkFBbUIsU0FBUyxZQUFZO0FBQUEsSUFDeEQ7QUFDQSxVQUFNLE9BQU8sTUFBTSxFQUFFO0FBQUEsRUFDekI7QUFFQSxXQUFTLHdCQUF3QjtBQUM3QixVQUFNLFdBQVcsU0FBUyxpQkFBaUIsbUJBQW1CO0FBQzlELGFBQVMsUUFBUSxTQUFVLFNBQVM7QUFDaEMsWUFBTSxlQUFlLFFBQVEsYUFBYSxpQkFBaUI7QUFDM0QsWUFBTSxVQUFVLFFBQVEsYUFBYSxrQkFBa0I7QUFDdkQsWUFBTSxVQUFVLFFBQVEsYUFBYSxrQkFBa0IsS0FBSztBQUU1RCxVQUFJLFdBQVcsV0FBWTtBQUN2QixZQUFJLFNBQVM7QUFDVCxtQkFBUyxFQUFDLE9BQU8sV0FBVyxTQUFRLFNBQVMsU0FBUSxDQUFDLEVBQUMsT0FBTSxNQUFLLEdBQUUsRUFBQyxPQUFNLE1BQU0sV0FBVSxLQUFJLENBQUMsRUFBQyxDQUFDLEVBQUUsS0FBSyxTQUFVLFFBQVE7QUFDdkgsZ0JBQUksV0FBVyxNQUFNO0FBQ2pCLCtCQUFpQixZQUFZO0FBQUEsWUFDakM7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSx5QkFBaUIsWUFBWTtBQUFBLE1BQ2pDO0FBR0EsY0FBUSxvQkFBb0IsU0FBUyxRQUFRO0FBRzdDLGNBQVEsaUJBQWlCLFNBQVMsUUFBUTtBQUFBLElBQzlDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxZQUFZO0FBQ3hCLHlCQUFxQjtBQUNyQiwwQkFBc0I7QUFBQSxFQUMxQjs7O0FDNURPLE1BQUksU0FBVSxRQUFRLE9BQU8sUUFBUSxjQUFZLE9BQU8sT0FBTyxnQkFBZ0IsU0FBUzs7O0FDQy9GLE1BQUksYUFBYTtBQUVWLFdBQVMsU0FBUyxHQUFHO0FBQ3hCLFFBQUksTUFBTSxPQUFPLGlCQUFpQixFQUFFLE1BQU0sRUFBRSxpQkFBaUIsbUJBQW1CO0FBQ2hGLFFBQUksS0FBSztBQUNMLFlBQU0sSUFBSSxLQUFLO0FBQUEsSUFDbkI7QUFFQSxRQUFJLFFBQVEsUUFBUTtBQUNoQixhQUFPO0FBQUEsSUFDWDtBQUdBLFFBQUksRUFBRSxZQUFZLEdBQUc7QUFDakIsYUFBTztBQUFBLElBQ1g7QUFFQSxXQUFPLEVBQUUsV0FBVztBQUFBLEVBQ3hCO0FBRU8sV0FBUyxZQUFZO0FBQ3hCLFdBQU8saUJBQWlCLGFBQWEsV0FBVztBQUNoRCxXQUFPLGlCQUFpQixhQUFhLFdBQVc7QUFDaEQsV0FBTyxpQkFBaUIsV0FBVyxTQUFTO0FBQUEsRUFDaEQ7QUFFQSxXQUFTLFlBQVksR0FBRztBQUNwQixRQUFJLFNBQVMsQ0FBQyxHQUFHO0FBRWIsVUFBSSxFQUFFLFVBQVUsRUFBRSxPQUFPLGVBQWUsRUFBRSxVQUFVLEVBQUUsT0FBTyxjQUFjO0FBQ3ZFO0FBQUEsTUFDSjtBQUNBLG1CQUFhO0FBQUEsSUFDakIsT0FBTztBQUNILG1CQUFhO0FBQUEsSUFDakI7QUFBQSxFQUNKO0FBRUEsV0FBUyxVQUFVLEdBQUc7QUFDbEIsYUFBUyxLQUFLLE1BQU0sU0FBUyxPQUFPLE1BQU0sa0JBQWtCO0FBQzVELGlCQUFhO0FBQUEsRUFDakI7QUFFQSxXQUFTLFlBQVksR0FBRztBQUNwQixRQUFJLFlBQVk7QUFDWixtQkFBYTtBQUNiLFVBQUksZUFBZSxFQUFFLFlBQVksU0FBWSxFQUFFLFVBQVUsRUFBRTtBQUMzRCxVQUFJLGVBQWUsR0FBRztBQUNsQixlQUFPLE1BQU0saUJBQWlCLFNBQVMsS0FBSyxNQUFNO0FBQ2xELGlCQUFTLEtBQUssTUFBTSxTQUFTO0FBQzdCLGVBQU8sTUFBTTtBQUNiO0FBQUEsTUFDSjtBQUFBLElBQ0o7QUFBQSxFQUNKOzs7QUM1Q0EsU0FBTyxRQUFRO0FBQUEsSUFDWCxHQUFHLFdBQVcsSUFBSTtBQUFBLEVBQ3RCO0FBR0EsU0FBTyxTQUFTO0FBQUEsSUFDWjtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxFQUNKO0FBRU8sV0FBUyxXQUFXLFlBQVk7QUFDbkMsV0FBTztBQUFBLE1BQ0gsV0FBVztBQUFBLFFBQ1AsR0FBRztBQUFBLE1BQ1A7QUFBQSxNQUNBLGFBQWE7QUFBQSxRQUNULEdBQUc7QUFBQSxRQUNILGdCQUFnQkMsYUFBWTtBQUN4QixpQkFBTyxXQUFXQSxXQUFVO0FBQUEsUUFDaEM7QUFBQSxNQUNKO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0EsS0FBSztBQUFBLFFBQ0QsUUFBUTtBQUFBLE1BQ1o7QUFBQSxNQUNBLFFBQVE7QUFBQSxRQUNKO0FBQUEsUUFDQTtBQUFBLFFBQ0EsT0FBQUM7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxNQUNKO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUSxVQUFVLFVBQVU7QUFBQSxJQUNoQztBQUFBLEVBQ0o7QUFFQSxNQUFJLE1BQU87QUFDUCxZQUFRLElBQUksaUNBQWlDO0FBQUEsRUFDakQ7QUFFQSxxQkFBbUIsSUFBSTtBQUV2QixZQUFVO0FBRVYsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
diff --git a/v3/internal/runtime/runtime_debug_desktop_windows.js b/v3/internal/runtime/runtime_debug_desktop_windows.js
index 0ca537592..e93ed9e3e 100644
--- a/v3/internal/runtime/runtime_debug_desktop_windows.js
+++ b/v3/internal/runtime/runtime_debug_desktop_windows.js
@@ -523,6 +523,56 @@
addWMLWindowListeners();
}
+ // desktop/invoke.js
+ var invoke = true ? chrome.webview.postMessage : window.webkit.messageHandlers.external.postMessage;
+
+ // desktop/drag.js
+ var shouldDrag = false;
+ function dragTest(e) {
+ let val = window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");
+ if (val) {
+ val = val.trim();
+ }
+ if (val !== "drag") {
+ return false;
+ }
+ if (e.buttons !== 1) {
+ return false;
+ }
+ return e.detail === 1;
+ }
+ function setupDrag() {
+ window.addEventListener("mousedown", onMouseDown);
+ window.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("mouseup", onMouseUp);
+ }
+ function onMouseDown(e) {
+ if (dragTest(e)) {
+ if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
+ return;
+ }
+ shouldDrag = true;
+ } else {
+ shouldDrag = false;
+ }
+ }
+ function onMouseUp(e) {
+ document.body.style.cursor = window.wails.previousCursor || "auto";
+ shouldDrag = false;
+ }
+ function onMouseMove(e) {
+ if (shouldDrag) {
+ shouldDrag = false;
+ let mousePressed = e.buttons !== void 0 ? e.buttons : e.which;
+ if (mousePressed > 0) {
+ window.wails.previousCursor = document.body.style.cursor;
+ document.body.style.cursor = "grab";
+ invoke("drag");
+ return;
+ }
+ }
+ }
+
// desktop/main.js
window.wails = {
...newRuntime(null)
@@ -575,8 +625,9 @@
console.log("Wails v3.0.0 Debug Mode Enabled");
}
enableContextMenus(true);
+ setupDrag();
document.addEventListener("DOMContentLoaded", function(event) {
reloadWML();
});
})();
-//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvbWFpbi5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNsaXBib2FyZFwiKTtcblxuLyoqXG4gKiBTZXQgdGhlIENsaXBib2FyZCB0ZXh0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTZXRUZXh0KHRleHQpIHtcbiAgICB2b2lkIGNhbGwoXCJTZXRUZXh0XCIsIHt0ZXh0fSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFRleHQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJUZXh0XCIpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5jb25zdCBydW50aW1lVVJMID0gd2luZG93LmxvY2F0aW9uLm9yaWdpbiArIFwiL3dhaWxzL3J1bnRpbWVcIjtcblxuZnVuY3Rpb24gcnVudGltZUNhbGwobWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKSB7XG4gICAgbGV0IHVybCA9IG5ldyBVUkwocnVudGltZVVSTCk7XG4gICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJtZXRob2RcIiwgbWV0aG9kKTtcbiAgICBpZiAoYXJncykge1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChcImFyZ3NcIiwgSlNPTi5zdHJpbmdpZnkoYXJncykpO1xuICAgIH1cbiAgICBsZXQgZmV0Y2hPcHRpb25zID0ge1xuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICB9O1xuICAgIGlmICh3aW5kb3dOYW1lKSB7XG4gICAgICAgIGZldGNoT3B0aW9ucy5oZWFkZXJzW1wieC13YWlscy13aW5kb3ctbmFtZVwiXSA9IHdpbmRvd05hbWU7XG4gICAgfVxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGZldGNoKHVybCwgZmV0Y2hPcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgICAgICAgICAgICAgICAvLyBjaGVjayBjb250ZW50IHR5cGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpICYmIHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwiQ29udGVudC1UeXBlXCIpLmluZGV4T2YoXCJhcHBsaWNhdGlvbi9qc29uXCIpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS50ZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVqZWN0KEVycm9yKHJlc3BvbnNlLnN0YXR1c1RleHQpKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihkYXRhID0+IHJlc29sdmUoZGF0YSkpXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4gcmVqZWN0KGVycm9yKSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lQ2FsbGVyKG9iamVjdCwgd2luZG93TmFtZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAobWV0aG9kLCBhcmdzPW51bGwpIHtcbiAgICAgICAgcmV0dXJuIHJ1bnRpbWVDYWxsKG9iamVjdCArIFwiLlwiICsgbWV0aG9kLCB3aW5kb3dOYW1lLCBhcmdzKTtcbiAgICB9O1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiYXBwbGljYXRpb25cIik7XG5cbi8qKlxuICogSGlkZSB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEhpZGUoKSB7XG4gICAgdm9pZCBjYWxsKFwiSGlkZVwiKTtcbn1cblxuLyoqXG4gKiBTaG93IHRoZSBhcHBsaWNhdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gU2hvdygpIHtcbiAgICB2b2lkIGNhbGwoXCJTaG93XCIpO1xufVxuXG5cbi8qKlxuICogUXVpdCB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XG4gICAgdm9pZCBjYWxsKFwiUXVpdFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImxvZ1wiKTtcblxuLyoqXG4gKiBMb2dzIGEgbWVzc2FnZS5cbiAqIEBwYXJhbSB7bWVzc2FnZX0gTWVzc2FnZSB0byBsb2dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExvZyhtZXNzYWdlKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJMb2dcIiwgbWVzc2FnZSk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuU2NyZWVufSBTY3JlZW5cbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwic2NyZWVuc1wiKTtcblxuLyoqXG4gKiBHZXRzIGFsbCBzY3JlZW5zLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuW10+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gR2V0QWxsKCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0QWxsXCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIHByaW1hcnkgc2NyZWVuLlxuICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldFByaW1hcnkoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRQcmltYXJ5XCIpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIGN1cnJlbnQgYWN0aXZlIHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEN1cnJlbnQoKSB7XG4gICAgcmV0dXJuIGNhbGwoXCJHZXRDdXJyZW50XCIpO1xufSIsICJsZXQgdXJsQWxwaGFiZXQgPVxuICAndXNlYW5kb20tMjZUMTk4MzQwUFg3NXB4SkFDS1ZFUllNSU5EQlVTSFdPTEZfR1FaYmZnaGprbHF2d3l6cmljdCdcbmV4cG9ydCBsZXQgY3VzdG9tQWxwaGFiZXQgPSAoYWxwaGFiZXQsIGRlZmF1bHRTaXplID0gMjEpID0+IHtcbiAgcmV0dXJuIChzaXplID0gZGVmYXVsdFNpemUpID0+IHtcbiAgICBsZXQgaWQgPSAnJ1xuICAgIGxldCBpID0gc2l6ZVxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGlkICs9IGFscGhhYmV0WyhNYXRoLnJhbmRvbSgpICogYWxwaGFiZXQubGVuZ3RoKSB8IDBdXG4gICAgfVxuICAgIHJldHVybiBpZFxuICB9XG59XG5leHBvcnQgbGV0IG5hbm9pZCA9IChzaXplID0gMjEpID0+IHtcbiAgbGV0IGlkID0gJydcbiAgbGV0IGkgPSBzaXplXG4gIHdoaWxlIChpLS0pIHtcbiAgICBpZCArPSB1cmxBbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIDY0KSB8IDBdXG4gIH1cbiAgcmV0dXJuIGlkXG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmltcG9ydCB7IG5hbm9pZCB9IGZyb20gJ25hbm9pZC9ub24tc2VjdXJlJztcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY2FsbFwiKTtcblxubGV0IGNhbGxSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGNhbGxSZXNwb25zZXMuaGFzKHJlc3VsdCkpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWxsQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gY2FsbFJlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbEVycm9yQ2FsbGJhY2soaWQsIG1lc3NhZ2UpIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY2FsbEJpbmRpbmcodHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJjYWxsLWlkXCJdID0gaWQ7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuc2V0KGlkLCB7cmVzb2x2ZSwgcmVqZWN0fSk7XG4gICAgICAgIGNhbGwodHlwZSwgb3B0aW9ucykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENhbGwob3B0aW9ucykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogQ2FsbCBhIHBsdWdpbiBtZXRob2RcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbHVnaW5OYW1lIC0gbmFtZSBvZiB0aGUgcGx1Z2luXG4gKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kTmFtZSAtIG5hbWUgb2YgdGhlIG1ldGhvZFxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgbWV0aG9kXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fSAtIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFBsdWdpbihwbHVnaW5OYW1lLCBtZXRob2ROYW1lLCAuLi5hcmdzKSB7XG4gICAgcmV0dXJuIGNhbGxCaW5kaW5nKFwiQ2FsbFwiLCB7XG4gICAgICAgIHBhY2thZ2VOYW1lOiBcIndhaWxzLXBsdWdpbnNcIixcbiAgICAgICAgc3RydWN0TmFtZTogcGx1Z2luTmFtZSxcbiAgICAgICAgbWV0aG9kTmFtZTogbWV0aG9kTmFtZSxcbiAgICAgICAgYXJnczogYXJncyxcbiAgICB9KTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNpemV9IFNpemVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuLi9hcGkvdHlwZXNcIikuUG9zaXRpb259IFBvc2l0aW9uXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdXaW5kb3cod2luZG93TmFtZSkge1xuICAgIGxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcIndpbmRvd1wiLCB3aW5kb3dOYW1lKTtcbiAgICByZXR1cm4ge1xuICAgICAgICAvLyBSZWxvYWQ6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFJlbG9hZEFwcDogKCkgPT4gY2FsbCgnV1InKSxcbiAgICAgICAgLy8gU2V0U3lzdGVtRGVmYXVsdFRoZW1lOiAoKSA9PiBjYWxsKCdXQVNEVCcpLFxuICAgICAgICAvLyBTZXRMaWdodFRoZW1lOiAoKSA9PiBjYWxsKCdXQUxUJyksXG4gICAgICAgIC8vIFNldERhcmtUaGVtZTogKCkgPT4gY2FsbCgnV0FEVCcpLFxuICAgICAgICAvLyBJc0Z1bGxzY3JlZW46ICgpID0+IGNhbGwoJ1dJRicpLFxuICAgICAgICAvLyBJc01heGltaXplZDogKCkgPT4gY2FsbCgnV0lNJyksXG4gICAgICAgIC8vIElzTWluaW1pemVkOiAoKSA9PiBjYWxsKCdXSU1OJyksXG4gICAgICAgIC8vIElzV2luZG93ZWQ6ICgpID0+IGNhbGwoJ1dJRicpLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENlbnRlcnMgdGhlIHdpbmRvdy5cbiAgICAgICAgICovXG4gICAgICAgIENlbnRlcjogKCkgPT4gdm9pZCBjYWxsKCdDZW50ZXInKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgdGl0bGUuXG4gICAgICAgICAqIEBwYXJhbSB0aXRsZVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0VGl0bGU6ICh0aXRsZSkgPT4gdm9pZCBjYWxsKCdTZXRUaXRsZScsIHt0aXRsZX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYWtlcyB0aGUgd2luZG93IGZ1bGxzY3JlZW4uXG4gICAgICAgICAqL1xuICAgICAgICBGdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ0Z1bGxzY3JlZW4nKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5mdWxsc2NyZWVuIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBVbkZ1bGxzY3JlZW46ICgpID0+IHZvaWQgY2FsbCgnVW5GdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCBUaGUgd2luZG93IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgVGhlIHdpbmRvdyBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiBjYWxsKCdTZXRTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTaXplPn0gVGhlIHdpbmRvdyBzaXplXG4gICAgICAgICAqL1xuICAgICAgICBTaXplOiAoKSA9PiB7IHJldHVybiBjYWxsKCdTaXplJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1heGltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1heFNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1heFNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IG1pbmltdW0gc2l6ZS5cbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAgICAgICAgICovXG4gICAgICAgIFNldE1pblNpemU6ICh3aWR0aCwgaGVpZ2h0KSA9PiB2b2lkIGNhbGwoJ1NldE1pblNpemUnLCB7d2lkdGgsaGVpZ2h0fSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB3aW5kb3cgdG8gYmUgYWx3YXlzIG9uIHRvcC5cbiAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBvblRvcCBXaGV0aGVyIHRoZSB3aW5kb3cgc2hvdWxkIGJlIGFsd2F5cyBvbiB0b3BcbiAgICAgICAgICovXG4gICAgICAgIFNldEFsd2F5c09uVG9wOiAob25Ub3ApID0+IHZvaWQgY2FsbCgnU2V0QWx3YXlzT25Ub3AnLCB7YWx3YXlzT25Ub3A6b25Ub3B9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XG4gICAgICAgICAqL1xuICAgICAgICBTZXRQb3NpdGlvbjogKHgsIHkpID0+IGNhbGwoJ1NldFBvc2l0aW9uJywge3gseX0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdGhlIHdpbmRvdyBwb3NpdGlvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8UG9zaXRpb24+fSBUaGUgd2luZG93IHBvc2l0aW9uXG4gICAgICAgICAqL1xuICAgICAgICBQb3NpdGlvbjogKCkgPT4geyByZXR1cm4gY2FsbCgnUG9zaXRpb24nKTsgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBzY3JlZW4gdGhlIHdpbmRvdyBpcyBvbi5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2NyZWVuPn1cbiAgICAgICAgICovXG4gICAgICAgIFNjcmVlbjogKCkgPT4geyByZXR1cm4gY2FsbCgnU2NyZWVuJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhpZGUgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgSGlkZTogKCkgPT4gdm9pZCBjYWxsKCdIaWRlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIE1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ01heGltaXNlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNob3cgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgU2hvdzogKCkgPT4gdm9pZCBjYWxsKCdTaG93JyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENsb3NlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIENsb3NlOiAoKSA9PiB2b2lkIGNhbGwoJ0Nsb3NlJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRvZ2dsZSB0aGUgd2luZG93IG1heGltaXNlIHN0YXRlXG4gICAgICAgICAqL1xuICAgICAgICBUb2dnbGVNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdUb2dnbGVNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1heGltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNaW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNaW5pbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVbm1pbmltaXNlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFVuTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVW5NaW5pbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGJhY2tncm91bmQgY29sb3VyIG9mIHRoZSB3aW5kb3cuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gZyAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGIgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0QmFja2dyb3VuZENvbG91cjogKHIsIGcsIGIsIGEpID0+IHZvaWQgY2FsbCgnU2V0QmFja2dyb3VuZENvbG91cicsIHtyLCBnLCBiLCBhfSksXG4gICAgfTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5XYWlsc0V2ZW50fSBXYWlsc0V2ZW50XG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImV2ZW50c1wiKTtcblxuLyoqXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcbiAqXG4gKiBAY2xhc3MgTGlzdGVuZXJcbiAqL1xuY2xhc3MgTGlzdGVuZXIge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICAgICAqIEBtZW1iZXJvZiBMaXN0ZW5lclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgICAgICB0aGlzLmV2ZW50TmFtZSA9IGV2ZW50TmFtZTtcbiAgICAgICAgLy8gRGVmYXVsdCBvZiAtMSBtZWFucyBpbmZpbml0ZVxuICAgICAgICB0aGlzLm1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2soZGF0YSk7XG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhDYWxsYmFja3MgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRGVjcmVtZW50IG1heENhbGxiYWNrcy4gUmV0dXJuIHRydWUgaWYgbm93IDAsIG90aGVyd2lzZSBmYWxzZVxuICAgICAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgLT0gMTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm1heENhbGxiYWNrcyA9PT0gMDtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBXYWlsc0V2ZW50IGRlZmluZXMgYSBjdXN0b20gZXZlbnQuIEl0IGlzIHBhc3NlZCB0byBldmVudCBsaXN0ZW5lcnMuXG4gKlxuICogQGNsYXNzIFdhaWxzRXZlbnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAqIEBwcm9wZXJ0eSB7YW55fSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gKi9cbmV4cG9ydCBjbGFzcyBXYWlsc0V2ZW50IHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFdhaWxzRXZlbnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBOYW1lIG9mIHRoZSBldmVudFxuICAgICAqIEBwYXJhbSB7YW55PW51bGx9IGRhdGEgLSBEYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGUgZXZlbnRcbiAgICAgKiBAbWVtYmVyb2YgV2FpbHNFdmVudFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKG5hbWUsIGRhdGEgPSBudWxsKSB7XG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgZXZlbnRMaXN0ZW5lcnMgPSBuZXcgTWFwKCk7XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGBtYXhDYWxsYmFja3NgIHRpbWVzIGJlZm9yZSBiZWluZyBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpIHx8IFtdO1xuICAgIGNvbnN0IHRoaXNMaXN0ZW5lciA9IG5ldyBMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xuICAgIGxpc3RlbmVycy5wdXNoKHRoaXNMaXN0ZW5lcik7XG4gICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50TmFtZSwgbGlzdGVuZXJzKTtcbiAgICByZXR1cm4gKCkgPT4gbGlzdGVuZXJPZmYodGhpc0xpc3RlbmVyKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgZXZlcnkgdGltZSB0aGUgZXZlbnQgaXMgZW1pdHRlZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FuY2VsIHRoZSBsaXN0ZW5lclxuICovXG5leHBvcnQgZnVuY3Rpb24gT24oZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb24oV2FpbHNFdmVudCk6IHZvaWR9IGNhbGxiYWNrXG4gQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uY2UoZXZlbnROYW1lLCBjYWxsYmFjaykge1xuICAgIHJldHVybiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xufVxuXG4vKipcbiAqIGxpc3RlbmVyT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT25cbiAqXG4gKiBAcGFyYW0ge0xpc3RlbmVyfSBsaXN0ZW5lclxuICovXG5mdW5jdGlvbiBsaXN0ZW5lck9mZihsaXN0ZW5lcikge1xuICAgIGNvbnN0IGV2ZW50TmFtZSA9IGxpc3RlbmVyLmV2ZW50TmFtZTtcbiAgICAvLyBSZW1vdmUgbG9jYWwgbGlzdGVuZXJcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50TmFtZSkuZmlsdGVyKGwgPT4gbCAhPT0gbGlzdGVuZXIpO1xuICAgIGlmIChsaXN0ZW5lcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudE5hbWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgfVxufVxuXG4vKipcbiAqIGRpc3BhdGNoZXMgYW4gZXZlbnQgdG8gYWxsIGxpc3RlbmVyc1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7V2FpbHNFdmVudH0gZXZlbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpc3BhdGNoV2FpbHNFdmVudChldmVudCkge1xuICAgIGNvbnNvbGUubG9nKFwiZGlzcGF0Y2hpbmcgZXZlbnQ6IFwiLCB7ZXZlbnR9KTtcbiAgICBsZXQgbGlzdGVuZXJzID0gZXZlbnRMaXN0ZW5lcnMuZ2V0KGV2ZW50Lm5hbWUpO1xuICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgICAgLy8gaXRlcmF0ZSBsaXN0ZW5lcnMgYW5kIGNhbGwgY2FsbGJhY2suIElmIGNhbGxiYWNrIHJldHVybnMgdHJ1ZSwgcmVtb3ZlIGxpc3RlbmVyXG4gICAgICAgIGxldCB0b1JlbW92ZSA9IFtdO1xuICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaChsaXN0ZW5lciA9PiB7XG4gICAgICAgICAgICBsZXQgcmVtb3ZlID0gbGlzdGVuZXIuQ2FsbGJhY2soZXZlbnQpO1xuICAgICAgICAgICAgaWYgKHJlbW92ZSkge1xuICAgICAgICAgICAgICAgIHRvUmVtb3ZlLnB1c2gobGlzdGVuZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gcmVtb3ZlIGxpc3RlbmVyc1xuICAgICAgICBpZiAodG9SZW1vdmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgbGlzdGVuZXJzID0gbGlzdGVuZXJzLmZpbHRlcihsID0+ICF0b1JlbW92ZS5pbmNsdWRlcyhsKSk7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLmRlbGV0ZShldmVudC5uYW1lKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXZlbnRMaXN0ZW5lcnMuc2V0KGV2ZW50Lm5hbWUsIGxpc3RlbmVycyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT24sXG4gKiBvcHRpb25hbGx5IG11bHRpcGxlIGxpc3RlbmVycyBjYW4gYmUgdW5yZWdpc3RlcmVkIHZpYSBgYWRkaXRpb25hbEV2ZW50TmFtZXNgXG4gKlxuIFt2MyBDSEFOR0VdIE9mZiBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtICB7Li4uc3RyaW5nfSBhZGRpdGlvbmFsRXZlbnROYW1lc1xuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmKGV2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXMpIHtcbiAgICBsZXQgZXZlbnRzVG9SZW1vdmUgPSBbZXZlbnROYW1lLCAuLi5hZGRpdGlvbmFsRXZlbnROYW1lc107XG4gICAgZXZlbnRzVG9SZW1vdmUuZm9yRWFjaChldmVudE5hbWUgPT4ge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBPZmZBbGwgdW5yZWdpc3RlcnMgYWxsIGxpc3RlbmVyc1xuICogW3YzIENIQU5HRV0gT2ZmQWxsIG9ubHkgdW5yZWdpc3RlcnMgbGlzdGVuZXJzIHdpdGhpbiB0aGUgY3VycmVudCB3aW5kb3dcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPZmZBbGwoKSB7XG4gICAgZXZlbnRMaXN0ZW5lcnMuY2xlYXIoKTtcbn1cblxuLyoqXG4gKiBFbWl0IGFuIGV2ZW50XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50IFRoZSBldmVudCB0byBlbWl0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFbWl0KGV2ZW50KSB7XG4gICAgdm9pZCBjYWxsKFwiRW1pdFwiLCBldmVudCk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk1lc3NhZ2VEaWFsb2dPcHRpb25zfSBNZXNzYWdlRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLk9wZW5EaWFsb2dPcHRpb25zfSBPcGVuRGlhbG9nT3B0aW9uc1xuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNhdmVEaWFsb2dPcHRpb25zfSBTYXZlRGlhbG9nT3B0aW9uc1xuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImRpYWxvZ1wiKTtcblxubGV0IGRpYWxvZ1Jlc3BvbnNlcyA9IG5ldyBNYXAoKTtcblxuZnVuY3Rpb24gZ2VuZXJhdGVJRCgpIHtcbiAgICBsZXQgcmVzdWx0O1xuICAgIGRvIHtcbiAgICAgICAgcmVzdWx0ID0gbmFub2lkKCk7XG4gICAgfSB3aGlsZSAoZGlhbG9nUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nQ2FsbGJhY2soaWQsIGRhdGEsIGlzSlNPTikge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgaWYgKGlzSlNPTikge1xuICAgICAgICAgICAgcC5yZXNvbHZlKEpTT04ucGFyc2UoZGF0YSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICB9XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cbmV4cG9ydCBmdW5jdGlvbiBkaWFsb2dFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBkaWFsb2dSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBwLnJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLmRlbGV0ZShpZCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBkaWFsb2codHlwZSwgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBpZCA9IGdlbmVyYXRlSUQoKTtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIG9wdGlvbnNbXCJkaWFsb2ctaWRcIl0gPSBpZDtcbiAgICAgICAgZGlhbG9nUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIFNob3dzIGFuIEluZm8gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBJbmZvKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiSW5mb1wiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBXYXJuaW5nIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2FybmluZyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIldhcm5pbmdcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gRXJyb3IgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFcnJvcihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkVycm9yXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGEgUXVlc3Rpb24gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge01lc3NhZ2VEaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiBwcmVzc2VkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWVzdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlF1ZXN0aW9uXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIE9wZW4gZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXXxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlIG9yIGFuIGFycmF5IG9mIHNlbGVjdGVkIGZpbGVzIGlmIEFsbG93c011bHRpcGxlU2VsZWN0aW9uIGlzIHRydWUuIEEgYmxhbmsgc3RyaW5nIGlzIHJldHVybmVkIGlmIG5vIGZpbGUgd2FzIHNlbGVjdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gT3BlbkZpbGUob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJPcGVuRmlsZVwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFNhdmUgZGlhbG9nIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09wZW5EaWFsb2dPcHRpb25zfSBvcHRpb25zXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBSZXR1cm5zIHRoZSBzZWxlY3RlZCBmaWxlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNhdmVGaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiU2F2ZUZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbiIsICJpbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxubGV0IGNhbGwgPSBuZXdSdW50aW1lQ2FsbGVyKFwiY29udGV4dG1lbnVcIik7XG5cbmZ1bmN0aW9uIG9wZW5Db250ZXh0TWVudShpZCwgeCwgeSwgZGF0YSkge1xuICAgIHJldHVybiBjYWxsKFwiT3BlbkNvbnRleHRNZW51XCIsIHtpZCwgeCwgeSwgZGF0YX0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29udGV4dE1lbnVzKGVuYWJsZWQpIHtcbiAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGNvbnRleHRNZW51SGFuZGxlcik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBjb250ZXh0TWVudUhhbmRsZXIoZXZlbnQpIHtcbiAgICBwcm9jZXNzQ29udGV4dE1lbnUoZXZlbnQudGFyZ2V0LCBldmVudCk7XG59XG5cbmZ1bmN0aW9uIHByb2Nlc3NDb250ZXh0TWVudShlbGVtZW50LCBldmVudCkge1xuICAgIGxldCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51Jyk7XG4gICAgaWYgKGlkKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIG9wZW5Db250ZXh0TWVudShpZCwgZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtY29udGV4dG1lbnUtZGF0YScpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgcGFyZW50ID0gZWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgICAgICBpZiAocGFyZW50KSB7XG4gICAgICAgICAgICBwcm9jZXNzQ29udGV4dE1lbnUocGFyZW50LCBldmVudCk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCAiXG5pbXBvcnQge0VtaXQsIFdhaWxzRXZlbnR9IGZyb20gXCIuL2V2ZW50c1wiO1xuaW1wb3J0IHtRdWVzdGlvbn0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuXG5mdW5jdGlvbiBzZW5kRXZlbnQoZXZlbnROYW1lLCBkYXRhPW51bGwpIHtcbiAgICBsZXQgZXZlbnQgPSBuZXcgV2FpbHNFdmVudChldmVudE5hbWUsIGRhdGEpO1xuICAgIEVtaXQoZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxFdmVudExpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC1ldmVudF0nKTtcbiAgICBlbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGV2ZW50VHlwZSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1ldmVudCcpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VuZEV2ZW50KGV2ZW50VHlwZSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcblxuICAgICAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuXG4gICAgICAgIC8vIEFkZCBuZXcgbGlzdGVuZXJcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gY2FsbFdpbmRvd01ldGhvZChtZXRob2QpIHtcbiAgICBpZiAod2FpbHMuV2luZG93W21ldGhvZF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIldpbmRvdyBtZXRob2QgXCIgKyBtZXRob2QgKyBcIiBub3QgZm91bmRcIik7XG4gICAgfVxuICAgIHdhaWxzLldpbmRvd1ttZXRob2RdKCk7XG59XG5cbmZ1bmN0aW9uIGFkZFdNTFdpbmRvd0xpc3RlbmVycygpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXdtbC13aW5kb3ddJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCB3aW5kb3dNZXRob2QgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtd2luZG93Jyk7XG4gICAgICAgIGNvbnN0IGNvbmZpcm0gPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtY29uZmlybScpO1xuICAgICAgICBjb25zdCB0cmlnZ2VyID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXRyaWdnZXInKSB8fCBcImNsaWNrXCI7XG5cbiAgICAgICAgbGV0IGNhbGxiYWNrID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKGNvbmZpcm0pIHtcbiAgICAgICAgICAgICAgICBRdWVzdGlvbih7VGl0bGU6IFwiQ29uZmlybVwiLCBNZXNzYWdlOmNvbmZpcm0sIEJ1dHRvbnM6W3tMYWJlbDpcIlllc1wifSx7TGFiZWw6XCJOb1wiLCBJc0RlZmF1bHQ6dHJ1ZX1dfSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQgIT09IFwiTm9cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbFdpbmRvd01ldGhvZCh3aW5kb3dNZXRob2QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJlbW92ZSBleGlzdGluZyBsaXN0ZW5lcnNcbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWxvYWRXTUwoKSB7XG4gICAgYWRkV01MRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuXG5pbXBvcnQgKiBhcyBDbGlwYm9hcmQgZnJvbSAnLi9jbGlwYm9hcmQnO1xuaW1wb3J0ICogYXMgQXBwbGljYXRpb24gZnJvbSAnLi9hcHBsaWNhdGlvbic7XG5pbXBvcnQgKiBhcyBMb2cgZnJvbSAnLi9sb2cnO1xuaW1wb3J0ICogYXMgU2NyZWVucyBmcm9tICcuL3NjcmVlbnMnO1xuaW1wb3J0IHtQbHVnaW4sIENhbGwsIGNhbGxFcnJvckNhbGxiYWNrLCBjYWxsQ2FsbGJhY2t9IGZyb20gXCIuL2NhbGxzXCI7XG5pbXBvcnQge25ld1dpbmRvd30gZnJvbSBcIi4vd2luZG93XCI7XG5pbXBvcnQge2Rpc3BhdGNoV2FpbHNFdmVudCwgRW1pdCwgT2ZmLCBPZmZBbGwsIE9uLCBPbmNlLCBPbk11bHRpcGxlfSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7ZGlhbG9nQ2FsbGJhY2ssIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssIEVycm9yLCBJbmZvLCBPcGVuRmlsZSwgUXVlc3Rpb24sIFNhdmVGaWxlLCBXYXJuaW5nLH0gZnJvbSBcIi4vZGlhbG9nc1wiO1xuaW1wb3J0IHtlbmFibGVDb250ZXh0TWVudXN9IGZyb20gXCIuL2NvbnRleHRtZW51XCI7XG5pbXBvcnQge3JlbG9hZFdNTH0gZnJvbSBcIi4vd21sXCI7XG5cbndpbmRvdy53YWlscyA9IHtcbiAgICAuLi5uZXdSdW50aW1lKG51bGwpLFxufTtcblxuLy8gSW50ZXJuYWwgd2FpbHMgZW5kcG9pbnRzXG53aW5kb3cuX3dhaWxzID0ge1xuICAgIGRpYWxvZ0NhbGxiYWNrLFxuICAgIGRpYWxvZ0Vycm9yQ2FsbGJhY2ssXG4gICAgZGlzcGF0Y2hXYWlsc0V2ZW50LFxuICAgIGNhbGxDYWxsYmFjayxcbiAgICBjYWxsRXJyb3JDYWxsYmFjayxcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBuZXdSdW50aW1lKHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBDbGlwYm9hcmQ6IHtcbiAgICAgICAgICAgIC4uLkNsaXBib2FyZFxuICAgICAgICB9LFxuICAgICAgICBBcHBsaWNhdGlvbjoge1xuICAgICAgICAgICAgLi4uQXBwbGljYXRpb24sXG4gICAgICAgICAgICBHZXRXaW5kb3dCeU5hbWUod2luZG93TmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXdSdW50aW1lKHdpbmRvd05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBMb2csXG4gICAgICAgIFNjcmVlbnMsXG4gICAgICAgIENhbGwsXG4gICAgICAgIFBsdWdpbixcbiAgICAgICAgV01MOiB7XG4gICAgICAgICAgICBSZWxvYWQ6IHJlbG9hZFdNTCxcbiAgICAgICAgfSxcbiAgICAgICAgRGlhbG9nOiB7XG4gICAgICAgICAgICBJbmZvLFxuICAgICAgICAgICAgV2FybmluZyxcbiAgICAgICAgICAgIEVycm9yLFxuICAgICAgICAgICAgUXVlc3Rpb24sXG4gICAgICAgICAgICBPcGVuRmlsZSxcbiAgICAgICAgICAgIFNhdmVGaWxlLFxuICAgICAgICB9LFxuICAgICAgICBFdmVudHM6IHtcbiAgICAgICAgICAgIEVtaXQsXG4gICAgICAgICAgICBPbixcbiAgICAgICAgICAgIE9uY2UsXG4gICAgICAgICAgICBPbk11bHRpcGxlLFxuICAgICAgICAgICAgT2ZmLFxuICAgICAgICAgICAgT2ZmQWxsLFxuICAgICAgICB9LFxuICAgICAgICBXaW5kb3c6IG5ld1dpbmRvdyh3aW5kb3dOYW1lKSxcbiAgICB9O1xufVxuXG5pZiAoREVCVUcpIHtcbiAgICBjb25zb2xlLmxvZyhcIldhaWxzIHYzLjAuMCBEZWJ1ZyBNb2RlIEVuYWJsZWRcIik7XG59XG5cbmVuYWJsZUNvbnRleHRNZW51cyh0cnVlKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDcEMsWUFBTSxLQUFLLFlBQVksRUFDbEIsS0FBSyxjQUFZO0FBQ2QsWUFBSSxTQUFTLElBQUk7QUFFYixjQUFJLFNBQVMsUUFBUSxJQUFJLGNBQWMsS0FBSyxTQUFTLFFBQVEsSUFBSSxjQUFjLEVBQUUsUUFBUSxrQkFBa0IsTUFBTSxJQUFJO0FBQ2pILG1CQUFPLFNBQVMsS0FBSztBQUFBLFVBQ3pCLE9BQU87QUFDSCxtQkFBTyxTQUFTLEtBQUs7QUFBQSxVQUN6QjtBQUFBLFFBQ0o7QUFDQSxlQUFPLE1BQU0sU0FBUyxVQUFVLENBQUM7QUFBQSxNQUNyQyxDQUFDLEVBQ0EsS0FBSyxVQUFRLFFBQVEsSUFBSSxDQUFDLEVBQzFCLE1BQU0sV0FBUyxPQUFPLEtBQUssQ0FBQztBQUFBLElBQ3JDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxpQkFBaUIsUUFBUSxZQUFZO0FBQ2pELFdBQU8sU0FBVSxRQUFRLE9BQUssTUFBTTtBQUNoQyxhQUFPLFlBQVksU0FBUyxNQUFNLFFBQVEsWUFBWSxJQUFJO0FBQUEsSUFDOUQ7QUFBQSxFQUNKOzs7QURsQ0EsTUFBSSxPQUFPLGlCQUFpQixXQUFXO0FBS2hDLFdBQVMsUUFBUSxNQUFNO0FBQzFCLFNBQUssS0FBSyxXQUFXLEVBQUMsS0FBSSxDQUFDO0FBQUEsRUFDL0I7QUFNTyxXQUFTLE9BQU87QUFDbkIsV0FBTyxLQUFLLE1BQU07QUFBQSxFQUN0Qjs7O0FFN0JBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQWNBLE1BQUlBLFFBQU8saUJBQWlCLGFBQWE7QUFLbEMsV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCO0FBS08sV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCO0FBTU8sV0FBUyxPQUFPO0FBQ25CLFNBQUtBLE1BQUssTUFBTTtBQUFBLEVBQ3BCOzs7QUNwQ0E7QUFBQTtBQUFBO0FBQUE7QUFjQSxNQUFJQyxRQUFPLGlCQUFpQixLQUFLO0FBTTFCLFdBQVMsSUFBSSxTQUFTO0FBQ3pCLFdBQU9BLE1BQUssT0FBTyxPQUFPO0FBQUEsRUFDOUI7OztBQ3RCQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFrQkEsTUFBSUMsUUFBTyxpQkFBaUIsU0FBUztBQU05QixXQUFTLFNBQVM7QUFDckIsV0FBT0EsTUFBSyxRQUFRO0FBQUEsRUFDeEI7QUFNTyxXQUFTLGFBQWE7QUFDekIsV0FBT0EsTUFBSyxZQUFZO0FBQUEsRUFDNUI7QUFPTyxXQUFTLGFBQWE7QUFDekIsV0FBT0EsTUFBSyxZQUFZO0FBQUEsRUFDNUI7OztBQzNDQSxNQUFJLGNBQ0Y7QUFXSyxNQUFJLFNBQVMsQ0FBQyxPQUFPLE9BQU87QUFDakMsUUFBSSxLQUFLO0FBQ1QsUUFBSSxJQUFJO0FBQ1IsV0FBTyxLQUFLO0FBQ1YsWUFBTSxZQUFhLEtBQUssT0FBTyxJQUFJLEtBQU0sQ0FBQztBQUFBLElBQzVDO0FBQ0EsV0FBTztBQUFBLEVBQ1Q7OztBQ0hBLE1BQUlDLFFBQU8saUJBQWlCLE1BQU07QUFFbEMsTUFBSSxnQkFBZ0Isb0JBQUksSUFBSTtBQUU1QixXQUFTLGFBQWE7QUFDbEIsUUFBSTtBQUNKLE9BQUc7QUFDQyxlQUFTLE9BQU87QUFBQSxJQUNwQixTQUFTLGNBQWMsSUFBSSxNQUFNO0FBQ2pDLFdBQU87QUFBQSxFQUNYO0FBRU8sV0FBUyxhQUFhLElBQUksTUFBTSxRQUFRO0FBQzNDLFFBQUksSUFBSSxjQUFjLElBQUksRUFBRTtBQUM1QixRQUFJLEdBQUc7QUFDSCxVQUFJLFFBQVE7QUFDUixVQUFFLFFBQVEsS0FBSyxNQUFNLElBQUksQ0FBQztBQUFBLE1BQzlCLE9BQU87QUFDSCxVQUFFLFFBQVEsSUFBSTtBQUFBLE1BQ2xCO0FBQ0Esb0JBQWMsT0FBTyxFQUFFO0FBQUEsSUFDM0I7QUFBQSxFQUNKO0FBRU8sV0FBUyxrQkFBa0IsSUFBSSxTQUFTO0FBQzNDLFFBQUksSUFBSSxjQUFjLElBQUksRUFBRTtBQUM1QixRQUFJLEdBQUc7QUFDSCxRQUFFLE9BQU8sT0FBTztBQUNoQixvQkFBYyxPQUFPLEVBQUU7QUFBQSxJQUMzQjtBQUFBLEVBQ0o7QUFFQSxXQUFTLFlBQVksTUFBTSxTQUFTO0FBQ2hDLFdBQU8sSUFBSSxRQUFRLENBQUMsU0FBUyxXQUFXO0FBQ3BDLFVBQUksS0FBSyxXQUFXO0FBQ3BCLGdCQUFVLFdBQVcsQ0FBQztBQUN0QixjQUFRLFNBQVMsSUFBSTtBQUNyQixvQkFBYyxJQUFJLElBQUksRUFBQyxTQUFTLE9BQU0sQ0FBQztBQUN2QyxNQUFBQSxNQUFLLE1BQU0sT0FBTyxFQUFFLE1BQU0sQ0FBQyxVQUFVO0FBQ2pDLGVBQU8sS0FBSztBQUNaLHNCQUFjLE9BQU8sRUFBRTtBQUFBLE1BQzNCLENBQUM7QUFBQSxJQUNMLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxLQUFLLFNBQVM7QUFDMUIsV0FBTyxZQUFZLFFBQVEsT0FBTztBQUFBLEVBQ3RDO0FBU08sV0FBUyxPQUFPLFlBQVksZUFBZSxNQUFNO0FBQ3BELFdBQU8sWUFBWSxRQUFRO0FBQUEsTUFDdkIsYUFBYTtBQUFBLE1BQ2IsWUFBWTtBQUFBLE1BQ1o7QUFBQSxNQUNBO0FBQUEsSUFDSixDQUFDO0FBQUEsRUFDTDs7O0FDM0RPLFdBQVMsVUFBVSxZQUFZO0FBQ2xDLFFBQUlDLFFBQU8saUJBQWlCLFVBQVUsVUFBVTtBQUNoRCxXQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFlSCxRQUFRLE1BQU0sS0FBS0EsTUFBSyxRQUFRO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU1oQyxVQUFVLENBQUMsVUFBVSxLQUFLQSxNQUFLLFlBQVksRUFBQyxNQUFLLENBQUM7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUtsRCxZQUFZLE1BQU0sS0FBS0EsTUFBSyxZQUFZO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLeEMsY0FBYyxNQUFNLEtBQUtBLE1BQUssY0FBYztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU81QyxTQUFTLENBQUMsT0FBTyxXQUFXQSxNQUFLLFdBQVcsRUFBQyxPQUFNLE9BQU0sQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNMUQsTUFBTSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxNQUFNO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU9uQyxZQUFZLENBQUMsT0FBTyxXQUFXLEtBQUtBLE1BQUssY0FBYyxFQUFDLE9BQU0sT0FBTSxDQUFDO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BT3JFLFlBQVksQ0FBQyxPQUFPLFdBQVcsS0FBS0EsTUFBSyxjQUFjLEVBQUMsT0FBTSxPQUFNLENBQUM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BTXJFLGdCQUFnQixDQUFDLFVBQVUsS0FBS0EsTUFBSyxrQkFBa0IsRUFBQyxhQUFZLE1BQUssQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQU8xRSxhQUFhLENBQUMsR0FBRyxNQUFNQSxNQUFLLGVBQWUsRUFBQyxHQUFFLEVBQUMsQ0FBQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNaEQsVUFBVSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxVQUFVO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFNM0MsUUFBUSxNQUFNO0FBQUUsZUFBT0EsTUFBSyxRQUFRO0FBQUEsTUFBRztBQUFBO0FBQUE7QUFBQTtBQUFBLE1BS3ZDLE1BQU0sTUFBTSxLQUFLQSxNQUFLLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUs1QixVQUFVLE1BQU0sS0FBS0EsTUFBSyxVQUFVO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLcEMsTUFBTSxNQUFNLEtBQUtBLE1BQUssTUFBTTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BSzVCLE9BQU8sTUFBTSxLQUFLQSxNQUFLLE9BQU87QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUs5QixnQkFBZ0IsTUFBTSxLQUFLQSxNQUFLLGdCQUFnQjtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BS2hELFlBQVksTUFBTSxLQUFLQSxNQUFLLFlBQVk7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUt4QyxVQUFVLE1BQU0sS0FBS0EsTUFBSyxVQUFVO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFLcEMsWUFBWSxNQUFNLEtBQUtBLE1BQUssWUFBWTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsTUFTeEMscUJBQXFCLENBQUMsR0FBRyxHQUFHLEdBQUcsTUFBTSxLQUFLQSxNQUFLLHVCQUF1QixFQUFDLEdBQUcsR0FBRyxHQUFHLEVBQUMsQ0FBQztBQUFBLElBQ3RGO0FBQUEsRUFDSjs7O0FDMUlBLE1BQUlDLFFBQU8saUJBQWlCLFFBQVE7QUFPcEMsTUFBTSxXQUFOLE1BQWU7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLElBUVgsWUFBWSxXQUFXLFVBQVUsY0FBYztBQUMzQyxXQUFLLFlBQVk7QUFFakIsV0FBSyxlQUFlLGdCQUFnQjtBQUdwQyxXQUFLLFdBQVcsQ0FBQyxTQUFTO0FBQ3RCLGlCQUFTLElBQUk7QUFFYixZQUFJLEtBQUssaUJBQWlCLElBQUk7QUFDMUIsaUJBQU87QUFBQSxRQUNYO0FBRUEsYUFBSyxnQkFBZ0I7QUFDckIsZUFBTyxLQUFLLGlCQUFpQjtBQUFBLE1BQ2pDO0FBQUEsSUFDSjtBQUFBLEVBQ0o7QUFVTyxNQUFNLGFBQU4sTUFBaUI7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxJQU9wQixZQUFZLE1BQU0sT0FBTyxNQUFNO0FBQzNCLFdBQUssT0FBTztBQUNaLFdBQUssT0FBTztBQUFBLElBQ2hCO0FBQUEsRUFDSjtBQUVPLE1BQU0saUJBQWlCLG9CQUFJLElBQUk7QUFXL0IsV0FBUyxXQUFXLFdBQVcsVUFBVSxjQUFjO0FBQzFELFFBQUksWUFBWSxlQUFlLElBQUksU0FBUyxLQUFLLENBQUM7QUFDbEQsVUFBTSxlQUFlLElBQUksU0FBUyxXQUFXLFVBQVUsWUFBWTtBQUNuRSxjQUFVLEtBQUssWUFBWTtBQUMzQixtQkFBZSxJQUFJLFdBQVcsU0FBUztBQUN2QyxXQUFPLE1BQU0sWUFBWSxZQUFZO0FBQUEsRUFDekM7QUFVTyxXQUFTLEdBQUcsV0FBVyxVQUFVO0FBQ3BDLFdBQU8sV0FBVyxXQUFXLFVBQVUsRUFBRTtBQUFBLEVBQzdDO0FBVU8sV0FBUyxLQUFLLFdBQVcsVUFBVTtBQUN0QyxXQUFPLFdBQVcsV0FBVyxVQUFVLENBQUM7QUFBQSxFQUM1QztBQU9BLFdBQVMsWUFBWSxVQUFVO0FBQzNCLFVBQU0sWUFBWSxTQUFTO0FBRTNCLFFBQUksWUFBWSxlQUFlLElBQUksU0FBUyxFQUFFLE9BQU8sT0FBSyxNQUFNLFFBQVE7QUFDeEUsUUFBSSxVQUFVLFdBQVcsR0FBRztBQUN4QixxQkFBZSxPQUFPLFNBQVM7QUFBQSxJQUNuQyxPQUFPO0FBQ0gscUJBQWUsSUFBSSxXQUFXLFNBQVM7QUFBQSxJQUMzQztBQUFBLEVBQ0o7QUFRTyxXQUFTLG1CQUFtQixPQUFPO0FBQ3RDLFlBQVEsSUFBSSx1QkFBdUIsRUFBQyxNQUFLLENBQUM7QUFDMUMsUUFBSSxZQUFZLGVBQWUsSUFBSSxNQUFNLElBQUk7QUFDN0MsUUFBSSxXQUFXO0FBRVgsVUFBSSxXQUFXLENBQUM7QUFDaEIsZ0JBQVUsUUFBUSxjQUFZO0FBQzFCLFlBQUksU0FBUyxTQUFTLFNBQVMsS0FBSztBQUNwQyxZQUFJLFFBQVE7QUFDUixtQkFBUyxLQUFLLFFBQVE7QUFBQSxRQUMxQjtBQUFBLE1BQ0osQ0FBQztBQUVELFVBQUksU0FBUyxTQUFTLEdBQUc7QUFDckIsb0JBQVksVUFBVSxPQUFPLE9BQUssQ0FBQyxTQUFTLFNBQVMsQ0FBQyxDQUFDO0FBQ3ZELFlBQUksVUFBVSxXQUFXLEdBQUc7QUFDeEIseUJBQWUsT0FBTyxNQUFNLElBQUk7QUFBQSxRQUNwQyxPQUFPO0FBQ0gseUJBQWUsSUFBSSxNQUFNLE1BQU0sU0FBUztBQUFBLFFBQzVDO0FBQUEsTUFDSjtBQUFBLElBQ0o7QUFBQSxFQUNKO0FBV08sV0FBUyxJQUFJLGNBQWMsc0JBQXNCO0FBQ3BELFFBQUksaUJBQWlCLENBQUMsV0FBVyxHQUFHLG9CQUFvQjtBQUN4RCxtQkFBZSxRQUFRLENBQUFDLGVBQWE7QUFDaEMscUJBQWUsT0FBT0EsVUFBUztBQUFBLElBQ25DLENBQUM7QUFBQSxFQUNMO0FBT08sV0FBUyxTQUFTO0FBQ3JCLG1CQUFlLE1BQU07QUFBQSxFQUN6QjtBQU1PLFdBQVMsS0FBSyxPQUFPO0FBQ3hCLFNBQUtELE1BQUssUUFBUSxLQUFLO0FBQUEsRUFDM0I7OztBQzNLQSxNQUFJRSxRQUFPLGlCQUFpQixRQUFRO0FBRXBDLE1BQUksa0JBQWtCLG9CQUFJLElBQUk7QUFFOUIsV0FBU0MsY0FBYTtBQUNsQixRQUFJO0FBQ0osT0FBRztBQUNDLGVBQVMsT0FBTztBQUFBLElBQ3BCLFNBQVMsZ0JBQWdCLElBQUksTUFBTTtBQUNuQyxXQUFPO0FBQUEsRUFDWDtBQUVPLFdBQVMsZUFBZSxJQUFJLE1BQU0sUUFBUTtBQUM3QyxRQUFJLElBQUksZ0JBQWdCLElBQUksRUFBRTtBQUM5QixRQUFJLEdBQUc7QUFDSCxVQUFJLFFBQVE7QUFDUixVQUFFLFFBQVEsS0FBSyxNQUFNLElBQUksQ0FBQztBQUFBLE1BQzlCLE9BQU87QUFDSCxVQUFFLFFBQVEsSUFBSTtBQUFBLE1BQ2xCO0FBQ0Esc0JBQWdCLE9BQU8sRUFBRTtBQUFBLElBQzdCO0FBQUEsRUFDSjtBQUNPLFdBQVMsb0JBQW9CLElBQUksU0FBUztBQUM3QyxRQUFJLElBQUksZ0JBQWdCLElBQUksRUFBRTtBQUM5QixRQUFJLEdBQUc7QUFDSCxRQUFFLE9BQU8sT0FBTztBQUNoQixzQkFBZ0IsT0FBTyxFQUFFO0FBQUEsSUFDN0I7QUFBQSxFQUNKO0FBRUEsV0FBUyxPQUFPLE1BQU0sU0FBUztBQUMzQixXQUFPLElBQUksUUFBUSxDQUFDLFNBQVMsV0FBVztBQUNwQyxVQUFJLEtBQUtBLFlBQVc7QUFDcEIsZ0JBQVUsV0FBVyxDQUFDO0FBQ3RCLGNBQVEsV0FBVyxJQUFJO0FBQ3ZCLHNCQUFnQixJQUFJLElBQUksRUFBQyxTQUFTLE9BQU0sQ0FBQztBQUN6QyxNQUFBRCxNQUFLLE1BQU0sT0FBTyxFQUFFLE1BQU0sQ0FBQyxVQUFVO0FBQ2pDLGVBQU8sS0FBSztBQUNaLHdCQUFnQixPQUFPLEVBQUU7QUFBQSxNQUM3QixDQUFDO0FBQUEsSUFDTCxDQUFDO0FBQUEsRUFDTDtBQVFPLFdBQVMsS0FBSyxTQUFTO0FBQzFCLFdBQU8sT0FBTyxRQUFRLE9BQU87QUFBQSxFQUNqQztBQU9PLFdBQVMsUUFBUSxTQUFTO0FBQzdCLFdBQU8sT0FBTyxXQUFXLE9BQU87QUFBQSxFQUNwQztBQU9PLFdBQVNFLE9BQU0sU0FBUztBQUMzQixXQUFPLE9BQU8sU0FBUyxPQUFPO0FBQUEsRUFDbEM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7QUFPTyxXQUFTLFNBQVMsU0FBUztBQUM5QixXQUFPLE9BQU8sWUFBWSxPQUFPO0FBQUEsRUFDckM7OztBQ3JIQSxNQUFJQyxRQUFPLGlCQUFpQixhQUFhO0FBRXpDLFdBQVMsZ0JBQWdCLElBQUksR0FBRyxHQUFHLE1BQU07QUFDckMsV0FBT0EsTUFBSyxtQkFBbUIsRUFBQyxJQUFJLEdBQUcsR0FBRyxLQUFJLENBQUM7QUFBQSxFQUNuRDtBQUVPLFdBQVMsbUJBQW1CLFNBQVM7QUFDeEMsUUFBSSxTQUFTO0FBQ1QsYUFBTyxpQkFBaUIsZUFBZSxrQkFBa0I7QUFBQSxJQUM3RCxPQUFPO0FBQ0gsYUFBTyxvQkFBb0IsZUFBZSxrQkFBa0I7QUFBQSxJQUNoRTtBQUFBLEVBQ0o7QUFFQSxXQUFTLG1CQUFtQixPQUFPO0FBQy9CLHVCQUFtQixNQUFNLFFBQVEsS0FBSztBQUFBLEVBQzFDO0FBRUEsV0FBUyxtQkFBbUIsU0FBUyxPQUFPO0FBQ3hDLFFBQUksS0FBSyxRQUFRLGFBQWEsa0JBQWtCO0FBQ2hELFFBQUksSUFBSTtBQUNKLFlBQU0sZUFBZTtBQUNyQixzQkFBZ0IsSUFBSSxNQUFNLFNBQVMsTUFBTSxTQUFTLFFBQVEsYUFBYSx1QkFBdUIsQ0FBQztBQUFBLElBQ25HLE9BQU87QUFDSCxVQUFJLFNBQVMsUUFBUTtBQUNyQixVQUFJLFFBQVE7QUFDUiwyQkFBbUIsUUFBUSxLQUFLO0FBQUEsTUFDcEM7QUFBQSxJQUNKO0FBQUEsRUFDSjs7O0FDM0JBLFdBQVMsVUFBVSxXQUFXLE9BQUssTUFBTTtBQUNyQyxRQUFJLFFBQVEsSUFBSSxXQUFXLFdBQVcsSUFBSTtBQUMxQyxTQUFLLEtBQUs7QUFBQSxFQUNkO0FBRUEsV0FBUyx1QkFBdUI7QUFDNUIsVUFBTSxXQUFXLFNBQVMsaUJBQWlCLGtCQUFrQjtBQUM3RCxhQUFTLFFBQVEsU0FBVSxTQUFTO0FBQ2hDLFlBQU0sWUFBWSxRQUFRLGFBQWEsZ0JBQWdCO0FBQ3ZELFlBQU0sVUFBVSxRQUFRLGFBQWEsa0JBQWtCO0FBQ3ZELFlBQU0sVUFBVSxRQUFRLGFBQWEsa0JBQWtCLEtBQUs7QUFFNUQsVUFBSSxXQUFXLFdBQVk7QUFDdkIsWUFBSSxTQUFTO0FBQ1QsbUJBQVMsRUFBQyxPQUFPLFdBQVcsU0FBUSxTQUFTLFNBQVEsQ0FBQyxFQUFDLE9BQU0sTUFBSyxHQUFFLEVBQUMsT0FBTSxNQUFNLFdBQVUsS0FBSSxDQUFDLEVBQUMsQ0FBQyxFQUFFLEtBQUssU0FBVSxRQUFRO0FBQ3ZILGdCQUFJLFdBQVcsTUFBTTtBQUNqQix3QkFBVSxTQUFTO0FBQUEsWUFDdkI7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSxrQkFBVSxTQUFTO0FBQUEsTUFDdkI7QUFHQSxjQUFRLG9CQUFvQixTQUFTLFFBQVE7QUFHN0MsY0FBUSxpQkFBaUIsU0FBUyxRQUFRO0FBQUEsSUFDOUMsQ0FBQztBQUFBLEVBQ0w7QUFFQSxXQUFTLGlCQUFpQixRQUFRO0FBQzlCLFFBQUksTUFBTSxPQUFPLE1BQU0sTUFBTSxRQUFXO0FBQ3BDLGNBQVEsSUFBSSxtQkFBbUIsU0FBUyxZQUFZO0FBQUEsSUFDeEQ7QUFDQSxVQUFNLE9BQU8sTUFBTSxFQUFFO0FBQUEsRUFDekI7QUFFQSxXQUFTLHdCQUF3QjtBQUM3QixVQUFNLFdBQVcsU0FBUyxpQkFBaUIsbUJBQW1CO0FBQzlELGFBQVMsUUFBUSxTQUFVLFNBQVM7QUFDaEMsWUFBTSxlQUFlLFFBQVEsYUFBYSxpQkFBaUI7QUFDM0QsWUFBTSxVQUFVLFFBQVEsYUFBYSxrQkFBa0I7QUFDdkQsWUFBTSxVQUFVLFFBQVEsYUFBYSxrQkFBa0IsS0FBSztBQUU1RCxVQUFJLFdBQVcsV0FBWTtBQUN2QixZQUFJLFNBQVM7QUFDVCxtQkFBUyxFQUFDLE9BQU8sV0FBVyxTQUFRLFNBQVMsU0FBUSxDQUFDLEVBQUMsT0FBTSxNQUFLLEdBQUUsRUFBQyxPQUFNLE1BQU0sV0FBVSxLQUFJLENBQUMsRUFBQyxDQUFDLEVBQUUsS0FBSyxTQUFVLFFBQVE7QUFDdkgsZ0JBQUksV0FBVyxNQUFNO0FBQ2pCLCtCQUFpQixZQUFZO0FBQUEsWUFDakM7QUFBQSxVQUNKLENBQUM7QUFDRDtBQUFBLFFBQ0o7QUFDQSx5QkFBaUIsWUFBWTtBQUFBLE1BQ2pDO0FBR0EsY0FBUSxvQkFBb0IsU0FBUyxRQUFRO0FBRzdDLGNBQVEsaUJBQWlCLFNBQVMsUUFBUTtBQUFBLElBQzlDLENBQUM7QUFBQSxFQUNMO0FBRU8sV0FBUyxZQUFZO0FBQ3hCLHlCQUFxQjtBQUNyQiwwQkFBc0I7QUFBQSxFQUMxQjs7O0FDbERBLFNBQU8sUUFBUTtBQUFBLElBQ1gsR0FBRyxXQUFXLElBQUk7QUFBQSxFQUN0QjtBQUdBLFNBQU8sU0FBUztBQUFBLElBQ1o7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDSjtBQUVPLFdBQVMsV0FBVyxZQUFZO0FBQ25DLFdBQU87QUFBQSxNQUNILFdBQVc7QUFBQSxRQUNQLEdBQUc7QUFBQSxNQUNQO0FBQUEsTUFDQSxhQUFhO0FBQUEsUUFDVCxHQUFHO0FBQUEsUUFDSCxnQkFBZ0JDLGFBQVk7QUFDeEIsaUJBQU8sV0FBV0EsV0FBVTtBQUFBLFFBQ2hDO0FBQUEsTUFDSjtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBLEtBQUs7QUFBQSxRQUNELFFBQVE7QUFBQSxNQUNaO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBLE9BQUFDO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUTtBQUFBLFFBQ0o7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLE1BQ0o7QUFBQSxNQUNBLFFBQVEsVUFBVSxVQUFVO0FBQUEsSUFDaEM7QUFBQSxFQUNKO0FBRUEsTUFBSSxNQUFPO0FBQ1AsWUFBUSxJQUFJLGlDQUFpQztBQUFBLEVBQ2pEO0FBRUEscUJBQW1CLElBQUk7QUFFdkIsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9jbGlwYm9hcmQuanMiLCAiZGVza3RvcC9ydW50aW1lLmpzIiwgImRlc2t0b3AvYXBwbGljYXRpb24uanMiLCAiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9zY3JlZW5zLmpzIiwgIm5vZGVfbW9kdWxlcy9uYW5vaWQvbm9uLXNlY3VyZS9pbmRleC5qcyIsICJkZXNrdG9wL2NhbGxzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3AvZXZlbnRzLmpzIiwgImRlc2t0b3AvZGlhbG9ncy5qcyIsICJkZXNrdG9wL2NvbnRleHRtZW51LmpzIiwgImRlc2t0b3Avd21sLmpzIiwgImRlc2t0b3AvaW52b2tlLmpzIiwgImRlc2t0b3AvZHJhZy5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJjbGlwYm9hcmRcIik7XG5cbi8qKlxuICogU2V0IHRoZSBDbGlwYm9hcmQgdGV4dFxuICovXG5leHBvcnQgZnVuY3Rpb24gU2V0VGV4dCh0ZXh0KSB7XG4gICAgdm9pZCBjYWxsKFwiU2V0VGV4dFwiLCB7dGV4dH0pO1xufVxuXG4vKipcbiAqIEdldCB0aGUgQ2xpcGJvYXJkIHRleHRcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBUZXh0KCkge1xuICAgIHJldHVybiBjYWxsKFwiVGV4dFwiKTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuY29uc3QgcnVudGltZVVSTCA9IHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gKyBcIi93YWlscy9ydW50aW1lXCI7XG5cbmZ1bmN0aW9uIHJ1bnRpbWVDYWxsKG1ldGhvZCwgd2luZG93TmFtZSwgYXJncykge1xuICAgIGxldCB1cmwgPSBuZXcgVVJMKHJ1bnRpbWVVUkwpO1xuICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKFwibWV0aG9kXCIsIG1ldGhvZCk7XG4gICAgaWYgKGFyZ3MpIHtcbiAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoXCJhcmdzXCIsIEpTT04uc3RyaW5naWZ5KGFyZ3MpKTtcbiAgICB9XG4gICAgbGV0IGZldGNoT3B0aW9ucyA9IHtcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgfTtcbiAgICBpZiAod2luZG93TmFtZSkge1xuICAgICAgICBmZXRjaE9wdGlvbnMuaGVhZGVyc1tcIngtd2FpbHMtd2luZG93LW5hbWVcIl0gPSB3aW5kb3dOYW1lO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBmZXRjaCh1cmwsIGZldGNoT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgY29udGVudCB0eXBlXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKSAmJiByZXNwb25zZS5oZWFkZXJzLmdldChcIkNvbnRlbnQtVHlwZVwiKS5pbmRleE9mKFwiYXBwbGljYXRpb24vanNvblwiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UudGV4dCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlamVjdChFcnJvcihyZXNwb25zZS5zdGF0dXNUZXh0KSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZGF0YSA9PiByZXNvbHZlKGRhdGEpKVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHJlamVjdChlcnJvcikpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbmV3UnVudGltZUNhbGxlcihvYmplY3QsIHdpbmRvd05hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG1ldGhvZCwgYXJncz1udWxsKSB7XG4gICAgICAgIHJldHVybiBydW50aW1lQ2FsbChvYmplY3QgKyBcIi5cIiArIG1ldGhvZCwgd2luZG93TmFtZSwgYXJncyk7XG4gICAgfTtcbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImFwcGxpY2F0aW9uXCIpO1xuXG4vKipcbiAqIEhpZGUgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBIaWRlKCkge1xuICAgIHZvaWQgY2FsbChcIkhpZGVcIik7XG59XG5cbi8qKlxuICogU2hvdyB0aGUgYXBwbGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNob3coKSB7XG4gICAgdm9pZCBjYWxsKFwiU2hvd1wiKTtcbn1cblxuXG4vKipcbiAqIFF1aXQgdGhlIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBRdWl0KCkge1xuICAgIHZvaWQgY2FsbChcIlF1aXRcIik7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJsb2dcIik7XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuXG4gKiBAcGFyYW0ge21lc3NhZ2V9IE1lc3NhZ2UgdG8gbG9nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2cobWVzc2FnZSkge1xuICAgIHJldHVybiBjYWxsKFwiTG9nXCIsIG1lc3NhZ2UpO1xufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4vYXBpL3R5cGVzXCIpLlNjcmVlbn0gU2NyZWVuXG4gKi9cblxuaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcInNjcmVlbnNcIik7XG5cbi8qKlxuICogR2V0cyBhbGwgc2NyZWVucy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbltdPn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEdldEFsbCgpIHtcbiAgICByZXR1cm4gY2FsbChcIkdldEFsbFwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBwcmltYXJ5IHNjcmVlbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRQcmltYXJ5KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0UHJpbWFyeVwiKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBjdXJyZW50IGFjdGl2ZSBzY3JlZW4uXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTY3JlZW4+fVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBHZXRDdXJyZW50KCkge1xuICAgIHJldHVybiBjYWxsKFwiR2V0Q3VycmVudFwiKTtcbn0iLCAibGV0IHVybEFscGhhYmV0ID1cbiAgJ3VzZWFuZG9tLTI2VDE5ODM0MFBYNzVweEpBQ0tWRVJZTUlOREJVU0hXT0xGX0dRWmJmZ2hqa2xxdnd5enJpY3QnXG5leHBvcnQgbGV0IGN1c3RvbUFscGhhYmV0ID0gKGFscGhhYmV0LCBkZWZhdWx0U2l6ZSA9IDIxKSA9PiB7XG4gIHJldHVybiAoc2l6ZSA9IGRlZmF1bHRTaXplKSA9PiB7XG4gICAgbGV0IGlkID0gJydcbiAgICBsZXQgaSA9IHNpemVcbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICBpZCArPSBhbHBoYWJldFsoTWF0aC5yYW5kb20oKSAqIGFscGhhYmV0Lmxlbmd0aCkgfCAwXVxuICAgIH1cbiAgICByZXR1cm4gaWRcbiAgfVxufVxuZXhwb3J0IGxldCBuYW5vaWQgPSAoc2l6ZSA9IDIxKSA9PiB7XG4gIGxldCBpZCA9ICcnXG4gIGxldCBpID0gc2l6ZVxuICB3aGlsZSAoaS0tKSB7XG4gICAgaWQgKz0gdXJsQWxwaGFiZXRbKE1hdGgucmFuZG9tKCkgKiA2NCkgfCAwXVxuICB9XG4gIHJldHVybiBpZFxufVxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tICduYW5vaWQvbm9uLXNlY3VyZSc7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNhbGxcIik7XG5cbmxldCBjYWxsUmVzcG9uc2VzID0gbmV3IE1hcCgpO1xuXG5mdW5jdGlvbiBnZW5lcmF0ZUlEKCkge1xuICAgIGxldCByZXN1bHQ7XG4gICAgZG8ge1xuICAgICAgICByZXN1bHQgPSBuYW5vaWQoKTtcbiAgICB9IHdoaWxlIChjYWxsUmVzcG9uc2VzLmhhcyhyZXN1bHQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsbENhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGNhbGxSZXNwb25zZXMuZ2V0KGlkKTtcbiAgICBpZiAocCkge1xuICAgICAgICBpZiAoaXNKU09OKSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoSlNPTi5wYXJzZShkYXRhKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwLnJlc29sdmUoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgY2FsbFJlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGxFcnJvckNhbGxiYWNrKGlkLCBtZXNzYWdlKSB7XG4gICAgbGV0IHAgPSBjYWxsUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNhbGxCaW5kaW5nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiY2FsbC1pZFwiXSA9IGlkO1xuICAgICAgICBjYWxsUmVzcG9uc2VzLnNldChpZCwge3Jlc29sdmUsIHJlamVjdH0pO1xuICAgICAgICBjYWxsKHR5cGUsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBDYWxsKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gY2FsbEJpbmRpbmcoXCJDYWxsXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIENhbGwgYSBwbHVnaW4gbWV0aG9kXG4gKiBAcGFyYW0ge3N0cmluZ30gcGx1Z2luTmFtZSAtIG5hbWUgb2YgdGhlIHBsdWdpblxuICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZE5hbWUgLSBuYW1lIG9mIHRoZSBtZXRob2RcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZFxuICogQHJldHVybnMge1Byb21pc2U8YW55Pn0gLSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBQbHVnaW4ocGx1Z2luTmFtZSwgbWV0aG9kTmFtZSwgLi4uYXJncykge1xuICAgIHJldHVybiBjYWxsQmluZGluZyhcIkNhbGxcIiwge1xuICAgICAgICBwYWNrYWdlTmFtZTogXCJ3YWlscy1wbHVnaW5zXCIsXG4gICAgICAgIHN0cnVjdE5hbWU6IHBsdWdpbk5hbWUsXG4gICAgICAgIG1ldGhvZE5hbWU6IG1ldGhvZE5hbWUsXG4gICAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgfSk7XG59IiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TaXplfSBTaXplXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vYXBpL3R5cGVzXCIpLlBvc2l0aW9ufSBQb3NpdGlvblxuICogQHR5cGVkZWYge2ltcG9ydChcIi4uL2FwaS90eXBlc1wiKS5TY3JlZW59IFNjcmVlblxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbmV3V2luZG93KHdpbmRvd05hbWUpIHtcbiAgICBsZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJ3aW5kb3dcIiwgd2luZG93TmFtZSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLy8gUmVsb2FkOiAoKSA9PiBjYWxsKCdXUicpLFxuICAgICAgICAvLyBSZWxvYWRBcHA6ICgpID0+IGNhbGwoJ1dSJyksXG4gICAgICAgIC8vIFNldFN5c3RlbURlZmF1bHRUaGVtZTogKCkgPT4gY2FsbCgnV0FTRFQnKSxcbiAgICAgICAgLy8gU2V0TGlnaHRUaGVtZTogKCkgPT4gY2FsbCgnV0FMVCcpLFxuICAgICAgICAvLyBTZXREYXJrVGhlbWU6ICgpID0+IGNhbGwoJ1dBRFQnKSxcbiAgICAgICAgLy8gSXNGdWxsc2NyZWVuOiAoKSA9PiBjYWxsKCdXSUYnKSxcbiAgICAgICAgLy8gSXNNYXhpbWl6ZWQ6ICgpID0+IGNhbGwoJ1dJTScpLFxuICAgICAgICAvLyBJc01pbmltaXplZDogKCkgPT4gY2FsbCgnV0lNTicpLFxuICAgICAgICAvLyBJc1dpbmRvd2VkOiAoKSA9PiBjYWxsKCdXSUYnKSxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDZW50ZXJzIHRoZSB3aW5kb3cuXG4gICAgICAgICAqL1xuICAgICAgICBDZW50ZXI6ICgpID0+IHZvaWQgY2FsbCgnQ2VudGVyJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHRpdGxlLlxuICAgICAgICAgKiBAcGFyYW0gdGl0bGVcbiAgICAgICAgICovXG4gICAgICAgIFNldFRpdGxlOiAodGl0bGUpID0+IHZvaWQgY2FsbCgnU2V0VGl0bGUnLCB7dGl0bGV9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWFrZXMgdGhlIHdpbmRvdyBmdWxsc2NyZWVuLlxuICAgICAgICAgKi9cbiAgICAgICAgRnVsbHNjcmVlbjogKCkgPT4gdm9pZCBjYWxsKCdGdWxsc2NyZWVuJyksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFVuZnVsbHNjcmVlbiB0aGUgd2luZG93LlxuICAgICAgICAgKi9cbiAgICAgICAgVW5GdWxsc2NyZWVuOiAoKSA9PiB2b2lkIGNhbGwoJ1VuRnVsbHNjcmVlbicpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBzaXplLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggVGhlIHdpbmRvdyB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IFRoZSB3aW5kb3cgaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gY2FsbCgnU2V0U2l6ZScsIHt3aWR0aCxoZWlnaHR9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgc2l6ZS5cbiAgICAgICAgICogQHJldHVybnMge1Byb21pc2U8U2l6ZT59IFRoZSB3aW5kb3cgc2l6ZVxuICAgICAgICAgKi9cbiAgICAgICAgU2l6ZTogKCkgPT4geyByZXR1cm4gY2FsbCgnU2l6ZScpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtYXhpbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNYXhTaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNYXhTaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIHdpbmRvdyBtaW5pbXVtIHNpemUuXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XG4gICAgICAgICAqL1xuICAgICAgICBTZXRNaW5TaXplOiAod2lkdGgsIGhlaWdodCkgPT4gdm9pZCBjYWxsKCdTZXRNaW5TaXplJywge3dpZHRoLGhlaWdodH0pLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgd2luZG93IHRvIGJlIGFsd2F5cyBvbiB0b3AuXG4gICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gb25Ub3AgV2hldGhlciB0aGUgd2luZG93IHNob3VsZCBiZSBhbHdheXMgb24gdG9wXG4gICAgICAgICAqL1xuICAgICAgICBTZXRBbHdheXNPblRvcDogKG9uVG9wKSA9PiB2b2lkIGNhbGwoJ1NldEFsd2F5c09uVG9wJywge2Fsd2F5c09uVG9wOm9uVG9wfSksXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgd2luZG93IHBvc2l0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geFxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geVxuICAgICAgICAgKi9cbiAgICAgICAgU2V0UG9zaXRpb246ICh4LCB5KSA9PiBjYWxsKCdTZXRQb3NpdGlvbicsIHt4LHl9KSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSB3aW5kb3cgcG9zaXRpb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFBvc2l0aW9uPn0gVGhlIHdpbmRvdyBwb3NpdGlvblxuICAgICAgICAgKi9cbiAgICAgICAgUG9zaXRpb246ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1Bvc2l0aW9uJyk7IH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB0aGUgc2NyZWVuIHRoZSB3aW5kb3cgaXMgb24uXG4gICAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFNjcmVlbj59XG4gICAgICAgICAqL1xuICAgICAgICBTY3JlZW46ICgpID0+IHsgcmV0dXJuIGNhbGwoJ1NjcmVlbicpOyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBIaWRlIHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIEhpZGU6ICgpID0+IHZvaWQgY2FsbCgnSGlkZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBNYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBNYXhpbWlzZTogKCkgPT4gdm9pZCBjYWxsKCdNYXhpbWlzZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTaG93IHRoZSB3aW5kb3dcbiAgICAgICAgICovXG4gICAgICAgIFNob3c6ICgpID0+IHZvaWQgY2FsbCgnU2hvdycpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDbG9zZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBDbG9zZTogKCkgPT4gdm9pZCBjYWxsKCdDbG9zZScpLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUb2dnbGUgdGhlIHdpbmRvdyBtYXhpbWlzZSBzdGF0ZVxuICAgICAgICAgKi9cbiAgICAgICAgVG9nZ2xlTWF4aW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnVG9nZ2xlTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5tYXhpbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1heGltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWF4aW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWluaW1pc2UgdGhlIHdpbmRvd1xuICAgICAgICAgKi9cbiAgICAgICAgTWluaW1pc2U6ICgpID0+IHZvaWQgY2FsbCgnTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVW5taW5pbWlzZSB0aGUgd2luZG93XG4gICAgICAgICAqL1xuICAgICAgICBVbk1pbmltaXNlOiAoKSA9PiB2b2lkIGNhbGwoJ1VuTWluaW1pc2UnKSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSBiYWNrZ3JvdW5kIGNvbG91ciBvZiB0aGUgd2luZG93LlxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gciAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGcgLSBBIHZhbHVlIGJldHdlZW4gMCBhbmQgMjU1XG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gQSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDI1NVxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYSAtIEEgdmFsdWUgYmV0d2VlbiAwIGFuZCAyNTVcbiAgICAgICAgICovXG4gICAgICAgIFNldEJhY2tncm91bmRDb2xvdXI6IChyLCBnLCBiLCBhKSA9PiB2b2lkIGNhbGwoJ1NldEJhY2tncm91bmRDb2xvdXInLCB7ciwgZywgYiwgYX0pLFxuICAgIH07XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9hcGkvdHlwZXNcIikuV2FpbHNFdmVudH0gV2FpbHNFdmVudFxuICovXG5cbmltcG9ydCB7bmV3UnVudGltZUNhbGxlcn0gZnJvbSBcIi4vcnVudGltZVwiO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJldmVudHNcIik7XG5cbi8qKlxuICogVGhlIExpc3RlbmVyIGNsYXNzIGRlZmluZXMgYSBsaXN0ZW5lciEgOi0pXG4gKlxuICogQGNsYXNzIExpc3RlbmVyXG4gKi9cbmNsYXNzIExpc3RlbmVyIHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIExpc3RlbmVyLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAgICAgKiBAbWVtYmVyb2YgTGlzdGVuZXJcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpIHtcbiAgICAgICAgdGhpcy5ldmVudE5hbWUgPSBldmVudE5hbWU7XG4gICAgICAgIC8vIERlZmF1bHQgb2YgLTEgbWVhbnMgaW5maW5pdGVcbiAgICAgICAgdGhpcy5tYXhDYWxsYmFja3MgPSBtYXhDYWxsYmFja3MgfHwgLTE7XG4gICAgICAgIC8vIENhbGxiYWNrIGludm9rZXMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIGdpdmVuIGRhdGFcbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIHRoaXMgbGlzdGVuZXIgc2hvdWxkIGJlIGRlc3Ryb3llZFxuICAgICAgICB0aGlzLkNhbGxiYWNrID0gKGRhdGEpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGRhdGEpO1xuICAgICAgICAgICAgLy8gSWYgbWF4Q2FsbGJhY2tzIGlzIGluZmluaXRlLCByZXR1cm4gZmFsc2UgKGRvIG5vdCBkZXN0cm95KVxuICAgICAgICAgICAgaWYgKHRoaXMubWF4Q2FsbGJhY2tzID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIERlY3JlbWVudCBtYXhDYWxsYmFja3MuIFJldHVybiB0cnVlIGlmIG5vdyAwLCBvdGhlcndpc2UgZmFsc2VcbiAgICAgICAgICAgIHRoaXMubWF4Q2FsbGJhY2tzIC09IDE7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXhDYWxsYmFja3MgPT09IDA7XG4gICAgICAgIH07XG4gICAgfVxufVxuXG5cbi8qKlxuICogV2FpbHNFdmVudCBkZWZpbmVzIGEgY3VzdG9tIGV2ZW50LiBJdCBpcyBwYXNzZWQgdG8gZXZlbnQgbGlzdGVuZXJzLlxuICpcbiAqIEBjbGFzcyBXYWlsc0V2ZW50XG4gKiBAcHJvcGVydHkge3N0cmluZ30gbmFtZSAtIE5hbWUgb2YgdGhlIGV2ZW50XG4gKiBAcHJvcGVydHkge2FueX0gZGF0YSAtIERhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudFxuICovXG5leHBvcnQgY2xhc3MgV2FpbHNFdmVudCB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBXYWlsc0V2ZW50LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTmFtZSBvZiB0aGUgZXZlbnRcbiAgICAgKiBAcGFyYW0ge2FueT1udWxsfSBkYXRhIC0gRGF0YSBhc3NvY2lhdGVkIHdpdGggdGhlIGV2ZW50XG4gICAgICogQG1lbWJlcm9mIFdhaWxzRXZlbnRcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihuYW1lLCBkYXRhID0gbnVsbCkge1xuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGV2ZW50TGlzdGVuZXJzID0gbmV3IE1hcCgpO1xuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbihXYWlsc0V2ZW50KTogdm9pZH0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAqIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgIGxldCBsaXN0ZW5lcnMgPSBldmVudExpc3RlbmVycy5nZXQoZXZlbnROYW1lKSB8fCBbXTtcbiAgICBjb25zdCB0aGlzTGlzdGVuZXIgPSBuZXcgTGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKTtcbiAgICBsaXN0ZW5lcnMucHVzaCh0aGlzTGlzdGVuZXIpO1xuICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudE5hbWUsIGxpc3RlbmVycyk7XG4gICAgcmV0dXJuICgpID0+IGxpc3RlbmVyT2ZmKHRoaXNMaXN0ZW5lcik7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGV2ZXJ5IHRpbWUgdGhlIGV2ZW50IGlzIGVtaXR0ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuICogQHJldHVybnMge2Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbmNlbCB0aGUgbGlzdGVuZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAtMSk7XG59XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIG9uY2UgdGhlbiBkZXN0cm95ZWRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFdhaWxzRXZlbnQpOiB2b2lkfSBjYWxsYmFja1xuIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYW5jZWwgdGhlIGxpc3RlbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAxKTtcbn1cblxuLyoqXG4gKiBsaXN0ZW5lck9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uXG4gKlxuICogQHBhcmFtIHtMaXN0ZW5lcn0gbGlzdGVuZXJcbiAqL1xuZnVuY3Rpb24gbGlzdGVuZXJPZmYobGlzdGVuZXIpIHtcbiAgICBjb25zdCBldmVudE5hbWUgPSBsaXN0ZW5lci5ldmVudE5hbWU7XG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyXG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudE5hbWUpLmZpbHRlcihsID0+IGwgIT09IGxpc3RlbmVyKTtcbiAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBldmVudExpc3RlbmVycy5zZXQoZXZlbnROYW1lLCBsaXN0ZW5lcnMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBkaXNwYXRjaGVzIGFuIGV2ZW50IHRvIGFsbCBsaXN0ZW5lcnNcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge1dhaWxzRXZlbnR9IGV2ZW50XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkaXNwYXRjaFdhaWxzRXZlbnQoZXZlbnQpIHtcbiAgICBjb25zb2xlLmxvZyhcImRpc3BhdGNoaW5nIGV2ZW50OiBcIiwge2V2ZW50fSk7XG4gICAgbGV0IGxpc3RlbmVycyA9IGV2ZW50TGlzdGVuZXJzLmdldChldmVudC5uYW1lKTtcbiAgICBpZiAobGlzdGVuZXJzKSB7XG4gICAgICAgIC8vIGl0ZXJhdGUgbGlzdGVuZXJzIGFuZCBjYWxsIGNhbGxiYWNrLiBJZiBjYWxsYmFjayByZXR1cm5zIHRydWUsIHJlbW92ZSBsaXN0ZW5lclxuICAgICAgICBsZXQgdG9SZW1vdmUgPSBbXTtcbiAgICAgICAgbGlzdGVuZXJzLmZvckVhY2gobGlzdGVuZXIgPT4ge1xuICAgICAgICAgICAgbGV0IHJlbW92ZSA9IGxpc3RlbmVyLkNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgICAgIGlmIChyZW1vdmUpIHtcbiAgICAgICAgICAgICAgICB0b1JlbW92ZS5wdXNoKGxpc3RlbmVyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8vIHJlbW92ZSBsaXN0ZW5lcnNcbiAgICAgICAgaWYgKHRvUmVtb3ZlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IGxpc3RlbmVycy5maWx0ZXIobCA9PiAhdG9SZW1vdmUuaW5jbHVkZXMobCkpO1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBldmVudExpc3RlbmVycy5kZWxldGUoZXZlbnQubmFtZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGV2ZW50TGlzdGVuZXJzLnNldChldmVudC5uYW1lLCBsaXN0ZW5lcnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIE9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uLFxuICogb3B0aW9uYWxseSBtdWx0aXBsZSBsaXN0ZW5lcnMgY2FuIGJlIHVucmVnaXN0ZXJlZCB2aWEgYGFkZGl0aW9uYWxFdmVudE5hbWVzYFxuICpcbiBbdjMgQ0hBTkdFXSBPZmYgb25seSB1bnJlZ2lzdGVycyBsaXN0ZW5lcnMgd2l0aGluIHRoZSBjdXJyZW50IHdpbmRvd1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSAgey4uLnN0cmluZ30gYWRkaXRpb25hbEV2ZW50TmFtZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9mZihldmVudE5hbWUsIC4uLmFkZGl0aW9uYWxFdmVudE5hbWVzKSB7XG4gICAgbGV0IGV2ZW50c1RvUmVtb3ZlID0gW2V2ZW50TmFtZSwgLi4uYWRkaXRpb25hbEV2ZW50TmFtZXNdO1xuICAgIGV2ZW50c1RvUmVtb3ZlLmZvckVhY2goZXZlbnROYW1lID0+IHtcbiAgICAgICAgZXZlbnRMaXN0ZW5lcnMuZGVsZXRlKGV2ZW50TmFtZSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogT2ZmQWxsIHVucmVnaXN0ZXJzIGFsbCBsaXN0ZW5lcnNcbiAqIFt2MyBDSEFOR0VdIE9mZkFsbCBvbmx5IHVucmVnaXN0ZXJzIGxpc3RlbmVycyB3aXRoaW4gdGhlIGN1cnJlbnQgd2luZG93XG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gT2ZmQWxsKCkge1xuICAgIGV2ZW50TGlzdGVuZXJzLmNsZWFyKCk7XG59XG5cbi8qKlxuICogRW1pdCBhbiBldmVudFxuICogQHBhcmFtIHtXYWlsc0V2ZW50fSBldmVudCBUaGUgZXZlbnQgdG8gZW1pdFxuICovXG5leHBvcnQgZnVuY3Rpb24gRW1pdChldmVudCkge1xuICAgIHZvaWQgY2FsbChcIkVtaXRcIiwgZXZlbnQpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5NZXNzYWdlRGlhbG9nT3B0aW9uc30gTWVzc2FnZURpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5PcGVuRGlhbG9nT3B0aW9uc30gT3BlbkRpYWxvZ09wdGlvbnNcbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2FwaS90eXBlc1wiKS5TYXZlRGlhbG9nT3B0aW9uc30gU2F2ZURpYWxvZ09wdGlvbnNcbiAqL1xuXG5pbXBvcnQge25ld1J1bnRpbWVDYWxsZXJ9IGZyb20gXCIuL3J1bnRpbWVcIjtcblxuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSAnbmFub2lkL25vbi1zZWN1cmUnO1xuXG5sZXQgY2FsbCA9IG5ld1J1bnRpbWVDYWxsZXIoXCJkaWFsb2dcIik7XG5cbmxldCBkaWFsb2dSZXNwb25zZXMgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSUQoKSB7XG4gICAgbGV0IHJlc3VsdDtcbiAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IG5hbm9pZCgpO1xuICAgIH0gd2hpbGUgKGRpYWxvZ1Jlc3BvbnNlcy5oYXMocmVzdWx0KSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpYWxvZ0NhbGxiYWNrKGlkLCBkYXRhLCBpc0pTT04pIHtcbiAgICBsZXQgcCA9IGRpYWxvZ1Jlc3BvbnNlcy5nZXQoaWQpO1xuICAgIGlmIChwKSB7XG4gICAgICAgIGlmIChpc0pTT04pIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICB9XG59XG5leHBvcnQgZnVuY3Rpb24gZGlhbG9nRXJyb3JDYWxsYmFjayhpZCwgbWVzc2FnZSkge1xuICAgIGxldCBwID0gZGlhbG9nUmVzcG9uc2VzLmdldChpZCk7XG4gICAgaWYgKHApIHtcbiAgICAgICAgcC5yZWplY3QobWVzc2FnZSk7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5kZWxldGUoaWQpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZGlhbG9nKHR5cGUsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgaWQgPSBnZW5lcmF0ZUlEKCk7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICBvcHRpb25zW1wiZGlhbG9nLWlkXCJdID0gaWQ7XG4gICAgICAgIGRpYWxvZ1Jlc3BvbnNlcy5zZXQoaWQsIHtyZXNvbHZlLCByZWplY3R9KTtcbiAgICAgICAgY2FsbCh0eXBlLCBvcHRpb25zKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICBkaWFsb2dSZXNwb25zZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBTaG93cyBhbiBJbmZvIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gSW5mbyhvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIkluZm9cIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYW4gV2FybmluZyBkaWFsb2cgd2l0aCB0aGUgZ2l2ZW4gb3B0aW9ucy5cbiAqIEBwYXJhbSB7TWVzc2FnZURpYWxvZ09wdGlvbnN9IG9wdGlvbnNcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBsYWJlbCBvZiB0aGUgYnV0dG9uIHByZXNzZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdhcm5pbmcob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJXYXJuaW5nXCIsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFNob3dzIGFuIEVycm9yIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gRXJyb3Iob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJFcnJvclwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhIFF1ZXN0aW9uIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtNZXNzYWdlRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGxhYmVsIG9mIHRoZSBidXR0b24gcHJlc3NlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gUXVlc3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBkaWFsb2coXCJRdWVzdGlvblwiLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTaG93cyBhbiBPcGVuIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nW118c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZSBvciBhbiBhcnJheSBvZiBzZWxlY3RlZCBmaWxlcyBpZiBBbGxvd3NNdWx0aXBsZVNlbGVjdGlvbiBpcyB0cnVlLiBBIGJsYW5rIHN0cmluZyBpcyByZXR1cm5lZCBpZiBubyBmaWxlIHdhcyBzZWxlY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE9wZW5GaWxlKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGlhbG9nKFwiT3BlbkZpbGVcIiwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogU2hvd3MgYSBTYXZlIGRpYWxvZyB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuICogQHBhcmFtIHtPcGVuRGlhbG9nT3B0aW9uc30gb3B0aW9uc1xuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUmV0dXJucyB0aGUgc2VsZWN0ZWQgZmlsZS4gQSBibGFuayBzdHJpbmcgaXMgcmV0dXJuZWQgaWYgbm8gZmlsZSB3YXMgc2VsZWN0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTYXZlRmlsZShvcHRpb25zKSB7XG4gICAgcmV0dXJuIGRpYWxvZyhcIlNhdmVGaWxlXCIsIG9wdGlvbnMpO1xufVxuXG4iLCAiaW1wb3J0IHtuZXdSdW50aW1lQ2FsbGVyfSBmcm9tIFwiLi9ydW50aW1lXCI7XG5cbmxldCBjYWxsID0gbmV3UnVudGltZUNhbGxlcihcImNvbnRleHRtZW51XCIpO1xuXG5mdW5jdGlvbiBvcGVuQ29udGV4dE1lbnUoaWQsIHgsIHksIGRhdGEpIHtcbiAgICByZXR1cm4gY2FsbChcIk9wZW5Db250ZXh0TWVudVwiLCB7aWQsIHgsIHksIGRhdGF9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnRleHRNZW51cyhlbmFibGVkKSB7XG4gICAgaWYgKGVuYWJsZWQpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51JywgY29udGV4dE1lbnVIYW5kbGVyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjb250ZXh0TWVudUhhbmRsZXIpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY29udGV4dE1lbnVIYW5kbGVyKGV2ZW50KSB7XG4gICAgcHJvY2Vzc0NvbnRleHRNZW51KGV2ZW50LnRhcmdldCwgZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBwcm9jZXNzQ29udGV4dE1lbnUoZWxlbWVudCwgZXZlbnQpIHtcbiAgICBsZXQgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1jb250ZXh0bWVudScpO1xuICAgIGlmIChpZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBvcGVuQ29udGV4dE1lbnUoaWQsIGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRleHRtZW51LWRhdGEnKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHBhcmVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgICAgICAgaWYgKHBhcmVudCkge1xuICAgICAgICAgICAgcHJvY2Vzc0NvbnRleHRNZW51KHBhcmVudCwgZXZlbnQpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwgIlxuaW1wb3J0IHtFbWl0LCBXYWlsc0V2ZW50fSBmcm9tIFwiLi9ldmVudHNcIjtcbmltcG9ydCB7UXVlc3Rpb259IGZyb20gXCIuL2RpYWxvZ3NcIjtcblxuZnVuY3Rpb24gc2VuZEV2ZW50KGV2ZW50TmFtZSwgZGF0YT1udWxsKSB7XG4gICAgbGV0IGV2ZW50ID0gbmV3IFdhaWxzRXZlbnQoZXZlbnROYW1lLCBkYXRhKTtcbiAgICBFbWl0KGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gYWRkV01MRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtZXZlbnRdJyk7XG4gICAgZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBldmVudFR5cGUgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtZXZlbnQnKTtcbiAgICAgICAgY29uc3QgY29uZmlybSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC1jb25maXJtJyk7XG4gICAgICAgIGNvbnN0IHRyaWdnZXIgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS13bWwtdHJpZ2dlcicpIHx8IFwiY2xpY2tcIjtcblxuICAgICAgICBsZXQgY2FsbGJhY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlybSkge1xuICAgICAgICAgICAgICAgIFF1ZXN0aW9uKHtUaXRsZTogXCJDb25maXJtXCIsIE1lc3NhZ2U6Y29uZmlybSwgQnV0dG9uczpbe0xhYmVsOlwiWWVzXCJ9LHtMYWJlbDpcIk5vXCIsIElzRGVmYXVsdDp0cnVlfV19KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdCAhPT0gXCJOb1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZW5kRXZlbnQoZXZlbnRUeXBlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbmRFdmVudChldmVudFR5cGUpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG5cbiAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHRyaWdnZXIsIGNhbGxiYWNrKTtcblxuICAgICAgICAvLyBBZGQgbmV3IGxpc3RlbmVyXG4gICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIGNhbGxXaW5kb3dNZXRob2QobWV0aG9kKSB7XG4gICAgaWYgKHdhaWxzLldpbmRvd1ttZXRob2RdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJXaW5kb3cgbWV0aG9kIFwiICsgbWV0aG9kICsgXCIgbm90IGZvdW5kXCIpO1xuICAgIH1cbiAgICB3YWlscy5XaW5kb3dbbWV0aG9kXSgpO1xufVxuXG5mdW5jdGlvbiBhZGRXTUxXaW5kb3dMaXN0ZW5lcnMoKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS13bWwtd2luZG93XScpO1xuICAgIGVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qgd2luZG93TWV0aG9kID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLXdpbmRvdycpO1xuICAgICAgICBjb25zdCBjb25maXJtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd21sLWNvbmZpcm0nKTtcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXdtbC10cmlnZ2VyJykgfHwgXCJjbGlja1wiO1xuXG4gICAgICAgIGxldCBjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChjb25maXJtKSB7XG4gICAgICAgICAgICAgICAgUXVlc3Rpb24oe1RpdGxlOiBcIkNvbmZpcm1cIiwgTWVzc2FnZTpjb25maXJtLCBCdXR0b25zOlt7TGFiZWw6XCJZZXNcIn0se0xhYmVsOlwiTm9cIiwgSXNEZWZhdWx0OnRydWV9XX0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBcIk5vXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxXaW5kb3dNZXRob2Qod2luZG93TWV0aG9kKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBSZW1vdmUgZXhpc3RpbmcgbGlzdGVuZXJzXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0cmlnZ2VyLCBjYWxsYmFjayk7XG5cbiAgICAgICAgLy8gQWRkIG5ldyBsaXN0ZW5lclxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHJpZ2dlciwgY2FsbGJhY2spO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVsb2FkV01MKCkge1xuICAgIGFkZFdNTEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgYWRkV01MV2luZG93TGlzdGVuZXJzKCk7XG59XG4iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG5cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cblxuLy8gZGVmaW5lZCBpbiB0aGUgVGFza2ZpbGVcbmV4cG9ydCBsZXQgaW52b2tlID0gKFdJTkRPV1M/Y2hyb21lLndlYnZpZXcucG9zdE1lc3NhZ2U6d2luZG93LndlYmtpdC5tZXNzYWdlSGFuZGxlcnMuZXh0ZXJuYWwucG9zdE1lc3NhZ2UpO1xuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cbmltcG9ydCB7aW52b2tlfSBmcm9tIFwiLi9pbnZva2VcIjtcblxubGV0IHNob3VsZERyYWcgPSBmYWxzZTtcblxuZXhwb3J0IGZ1bmN0aW9uIGRyYWdUZXN0KGUpIHtcbiAgICBsZXQgdmFsID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZS50YXJnZXQpLmdldFByb3BlcnR5VmFsdWUoXCItLXdhaWxzLWRyYWdnYWJsZVwiKTtcbiAgICBpZiAodmFsKSB7XG4gICAgICAgIHZhbCA9IHZhbC50cmltKCk7XG4gICAgfVxuXG4gICAgaWYgKHZhbCAhPT0gXCJkcmFnXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIE9ubHkgcHJvY2VzcyB0aGUgcHJpbWFyeSBidXR0b25cbiAgICBpZiAoZS5idXR0b25zICE9PSAxKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZS5kZXRhaWwgPT09IDE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cERyYWcoKSB7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIG9uTW91c2VEb3duKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgb25Nb3VzZU1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25Nb3VzZVVwKTtcbn1cblxuZnVuY3Rpb24gb25Nb3VzZURvd24oZSkge1xuICAgIGlmIChkcmFnVGVzdChlKSkge1xuICAgICAgICAvLyBJZ25vcmUgZHJhZyBvbiBzY3JvbGxiYXJzXG4gICAgICAgIGlmIChlLm9mZnNldFggPiBlLnRhcmdldC5jbGllbnRXaWR0aCB8fCBlLm9mZnNldFkgPiBlLnRhcmdldC5jbGllbnRIZWlnaHQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzaG91bGREcmFnID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbk1vdXNlVXAoZSkge1xuICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gd2luZG93LndhaWxzLnByZXZpb3VzQ3Vyc29yIHx8ICdhdXRvJztcbiAgICBzaG91bGREcmFnID0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIG9uTW91c2VNb3ZlKGUpIHtcbiAgICBpZiAoc2hvdWxkRHJhZykge1xuICAgICAgICBzaG91bGREcmFnID0gZmFsc2U7XG4gICAgICAgIGxldCBtb3VzZVByZXNzZWQgPSBlLmJ1dHRvbnMgIT09IHVuZGVmaW5lZCA/IGUuYnV0dG9ucyA6IGUud2hpY2g7XG4gICAgICAgIGlmIChtb3VzZVByZXNzZWQgPiAwKSB7XG4gICAgICAgICAgICB3aW5kb3cud2FpbHMucHJldmlvdXNDdXJzb3IgPSBkb2N1bWVudC5ib2R5LnN0eWxlLmN1cnNvcjtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yID0gJ2dyYWInO1xuICAgICAgICAgICAgaW52b2tlKFwiZHJhZ1wiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cbn0iLCAiLypcbiBfXHQgICBfX1x0ICBfIF9fXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cblxuaW1wb3J0ICogYXMgQ2xpcGJvYXJkIGZyb20gJy4vY2xpcGJvYXJkJztcbmltcG9ydCAqIGFzIEFwcGxpY2F0aW9uIGZyb20gJy4vYXBwbGljYXRpb24nO1xuaW1wb3J0ICogYXMgTG9nIGZyb20gJy4vbG9nJztcbmltcG9ydCAqIGFzIFNjcmVlbnMgZnJvbSAnLi9zY3JlZW5zJztcbmltcG9ydCB7UGx1Z2luLCBDYWxsLCBjYWxsRXJyb3JDYWxsYmFjaywgY2FsbENhbGxiYWNrfSBmcm9tIFwiLi9jYWxsc1wiO1xuaW1wb3J0IHtuZXdXaW5kb3d9IGZyb20gXCIuL3dpbmRvd1wiO1xuaW1wb3J0IHtkaXNwYXRjaFdhaWxzRXZlbnQsIEVtaXQsIE9mZiwgT2ZmQWxsLCBPbiwgT25jZSwgT25NdWx0aXBsZX0gZnJvbSBcIi4vZXZlbnRzXCI7XG5pbXBvcnQge2RpYWxvZ0NhbGxiYWNrLCBkaWFsb2dFcnJvckNhbGxiYWNrLCBFcnJvciwgSW5mbywgT3BlbkZpbGUsIFF1ZXN0aW9uLCBTYXZlRmlsZSwgV2FybmluZyx9IGZyb20gXCIuL2RpYWxvZ3NcIjtcbmltcG9ydCB7ZW5hYmxlQ29udGV4dE1lbnVzfSBmcm9tIFwiLi9jb250ZXh0bWVudVwiO1xuaW1wb3J0IHtyZWxvYWRXTUx9IGZyb20gXCIuL3dtbFwiO1xuaW1wb3J0IHtzZXR1cERyYWd9IGZyb20gXCIuL2RyYWdcIjtcblxud2luZG93LndhaWxzID0ge1xuICAgIC4uLm5ld1J1bnRpbWUobnVsbCksXG59O1xuXG4vLyBJbnRlcm5hbCB3YWlscyBlbmRwb2ludHNcbndpbmRvdy5fd2FpbHMgPSB7XG4gICAgZGlhbG9nQ2FsbGJhY2ssXG4gICAgZGlhbG9nRXJyb3JDYWxsYmFjayxcbiAgICBkaXNwYXRjaFdhaWxzRXZlbnQsXG4gICAgY2FsbENhbGxiYWNrLFxuICAgIGNhbGxFcnJvckNhbGxiYWNrLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIG5ld1J1bnRpbWUod2luZG93TmFtZSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIENsaXBib2FyZDoge1xuICAgICAgICAgICAgLi4uQ2xpcGJvYXJkXG4gICAgICAgIH0sXG4gICAgICAgIEFwcGxpY2F0aW9uOiB7XG4gICAgICAgICAgICAuLi5BcHBsaWNhdGlvbixcbiAgICAgICAgICAgIEdldFdpbmRvd0J5TmFtZSh3aW5kb3dOYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ld1J1bnRpbWUod2luZG93TmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIExvZyxcbiAgICAgICAgU2NyZWVucyxcbiAgICAgICAgQ2FsbCxcbiAgICAgICAgUGx1Z2luLFxuICAgICAgICBXTUw6IHtcbiAgICAgICAgICAgIFJlbG9hZDogcmVsb2FkV01MLFxuICAgICAgICB9LFxuICAgICAgICBEaWFsb2c6IHtcbiAgICAgICAgICAgIEluZm8sXG4gICAgICAgICAgICBXYXJuaW5nLFxuICAgICAgICAgICAgRXJyb3IsXG4gICAgICAgICAgICBRdWVzdGlvbixcbiAgICAgICAgICAgIE9wZW5GaWxlLFxuICAgICAgICAgICAgU2F2ZUZpbGUsXG4gICAgICAgIH0sXG4gICAgICAgIEV2ZW50czoge1xuICAgICAgICAgICAgRW1pdCxcbiAgICAgICAgICAgIE9uLFxuICAgICAgICAgICAgT25jZSxcbiAgICAgICAgICAgIE9uTXVsdGlwbGUsXG4gICAgICAgICAgICBPZmYsXG4gICAgICAgICAgICBPZmZBbGwsXG4gICAgICAgIH0sXG4gICAgICAgIFdpbmRvdzogbmV3V2luZG93KHdpbmRvd05hbWUpLFxuICAgIH07XG59XG5cbmlmIChERUJVRykge1xuICAgIGNvbnNvbGUubG9nKFwiV2FpbHMgdjMuMC4wIERlYnVnIE1vZGUgRW5hYmxlZFwiKTtcbn1cblxuZW5hYmxlQ29udGV4dE1lbnVzKHRydWUpO1xuXG5zZXR1cERyYWcoKTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICByZWxvYWRXTUwoKTtcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7O0FDWUEsTUFBTSxhQUFhLE9BQU8sU0FBUyxTQUFTO0FBRTVDLFdBQVMsWUFBWSxRQUFRLFlBQVksTUFBTTtBQUMzQyxRQUFJLE1BQU0sSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSSxhQUFhLE9BQU8sVUFBVSxNQUFNO0FBQ3hDLFFBQUksTUFBTTtBQUNOLFVBQUksYUFBYSxPQUFPLFFBQVEsS0FBSyxVQUFVLElBQUksQ0FBQztBQUFBLElBQ3hEO0FBQ0EsUUFBSSxlQUFlO0FBQUEsTUFDZixTQUFTLENBQUM7QUFBQSxJQUNkO0FBQ0EsUUFBSSxZQUFZO0FBQ1osbUJBQWEsUUFBUSxxQkFBcUIsSUFBSTtBQUFBLElBQ2xEO0FBQ0EsV0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFD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O0FBQUEsUUFDaEM7QUFBQSxNQUNKO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0EsS0FBSztBQUFBLFFBQ0QsUUFBUTtBQUFBLE1BQ1o7QUFBQSxNQUNBLFFBQVE7QUFBQSxRQUNKO0FBQUEsUUFDQTtBQUFBLFFBQ0EsT0FBQUM7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxNQUNKO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDSjtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsTUFDSjtBQUFBLE1BQ0EsUUFBUSxVQUFVLFVBQVU7QUFBQSxJQUNoQztBQUFBLEVBQ0o7QUFFQSxNQUFJLE1BQU87QUFDUCxZQUFRLElBQUksaUNBQWlDO0FBQUEsRUFDakQ7QUFFQSxxQkFBbUIsSUFBSTtBQUV2QixZQUFVO0FBRVYsV0FBUyxpQkFBaUIsb0JBQW9CLFNBQVMsT0FBTztBQUMxRCxjQUFVO0FBQUEsRUFDZCxDQUFDOyIsCiAgIm5hbWVzIjogWyJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJjYWxsIiwgImNhbGwiLCAiY2FsbCIsICJldmVudE5hbWUiLCAiY2FsbCIsICJnZW5lcmF0ZUlEIiwgIkVycm9yIiwgImNhbGwiLCAid2luZG93TmFtZSIsICJFcnJvciJdCn0K
diff --git a/v3/internal/runtime/runtime_production_desktop_darwin.js b/v3/internal/runtime/runtime_production_desktop_darwin.js
index be519faa5..80b3dc812 100644
--- a/v3/internal/runtime/runtime_production_desktop_darwin.js
+++ b/v3/internal/runtime/runtime_production_desktop_darwin.js
@@ -1 +1 @@
-(()=>{var Z=Object.defineProperty;var p=(t,e)=>{for(var n in e)Z(t,n,{get:e[n],enumerable:!0})};var v={};p(v,{SetText:()=>te,Text:()=>ne});var $=window.location.origin+"/wails/runtime";function ee(t,e,n){let i=new URL($);i.searchParams.append("method",t),n&&i.searchParams.append("args",JSON.stringify(n));let o={headers:{}};return e&&(o.headers["x-wails-window-name"]=e),new Promise((l,f)=>{fetch(i,o).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(t,e){return function(n,i=null){return ee(t+"."+n,e,i)}}var k=r("clipboard");function te(t){k("SetText",{text:t})}function ne(){return k("Text")}var S={};p(S,{Hide:()=>ie,Quit:()=>re,Show:()=>oe});var C=r("application");function ie(){C("Hide")}function oe(){C("Show")}function re(){C("Quit")}var M={};p(M,{Log:()=>ae});var le=r("log");function ae(t){return le("Log",t)}var E={};p(E,{GetAll:()=>ue,GetCurrent:()=>se,GetPrimary:()=>ce});var b=r("screens");function ue(){return b("GetAll")}function ce(){return b("GetPrimary")}function se(){return b("GetCurrent")}var fe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var w=(t=21)=>{let e="",n=t;for(;n--;)e+=fe[Math.random()*64|0];return e};var de=r("call"),c=new Map;function me(){let t;do t=w();while(c.has(t));return t}function A(t,e,n){let i=c.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),c.delete(t))}function W(t,e){let n=c.get(t);n&&(n.reject(e),c.delete(t))}function R(t,e){return new Promise((n,i)=>{let o=me();e=e||{},e["call-id"]=o,c.set(o,{resolve:n,reject:i}),de(t,e).catch(l=>{i(l),c.delete(o)})})}function T(t){return R("Call",t)}function P(t,e,...n){return R("Call",{packageName:"wails-plugins",structName:t,methodName:e,args:n})}function y(t){let e=r("window",t);return{Center:()=>void e("Center"),SetTitle:n=>void e("SetTitle",{title:n}),Fullscreen:()=>void e("Fullscreen"),UnFullscreen:()=>void e("UnFullscreen"),SetSize:(n,i)=>e("SetSize",{width:n,height:i}),Size:()=>e("Size"),SetMaxSize:(n,i)=>void e("SetMaxSize",{width:n,height:i}),SetMinSize:(n,i)=>void e("SetMinSize",{width:n,height:i}),SetAlwaysOnTop:n=>void e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,i)=>e("SetPosition",{x:n,y:i}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>void e("Hide"),Maximise:()=>void e("Maximise"),Show:()=>void e("Show"),Close:()=>void e("Close"),ToggleMaximise:()=>void e("ToggleMaximise"),UnMaximise:()=>void e("UnMaximise"),Minimise:()=>void e("Minimise"),UnMinimise:()=>void e("UnMinimise"),SetBackgroundColour:(n,i,o,l)=>void e("SetBackgroundColour",{r:n,g:i,b:o,a:l})}}var pe=r("events"),L=class{constructor(e,n,i){this.eventName=e,this.maxCallbacks=i||-1,this.Callback=o=>(n(o),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},g=class{constructor(e,n=null){this.name=e,this.data=n}},u=new Map;function x(t,e,n){let i=u.get(t)||[],o=new L(t,e,n);return i.push(o),u.set(t,i),()=>we(o)}function N(t,e){return x(t,e,-1)}function F(t,e){return x(t,e,1)}function we(t){let e=t.eventName,n=u.get(e).filter(i=>i!==t);n.length===0?u.delete(e):u.set(e,n)}function D(t){console.log("dispatching event: ",{event:t});let e=u.get(t.name);if(e){let n=[];e.forEach(i=>{i.Callback(t)&&n.push(i)}),n.length>0&&(e=e.filter(i=>!n.includes(i)),e.length===0?u.delete(t.name):u.set(t.name,e))}}function U(t,...e){[t,...e].forEach(i=>{u.delete(i)})}function z(){u.clear()}function h(t){pe("Emit",t)}var ge=r("dialog"),s=new Map;function xe(){let t;do t=w();while(s.has(t));return t}function G(t,e,n){let i=s.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),s.delete(t))}function B(t,e){let n=s.get(t);n&&(n.reject(e),s.delete(t))}function d(t,e){return new Promise((n,i)=>{let o=xe();e=e||{},e["dialog-id"]=o,s.set(o,{resolve:n,reject:i}),ge(t,e).catch(l=>{i(l),s.delete(o)})})}function I(t){return d("Info",t)}function Q(t){return d("Warning",t)}function H(t){return d("Error",t)}function m(t){return d("Question",t)}function J(t){return d("OpenFile",t)}function Y(t){return d("SaveFile",t)}var he=r("contextmenu");function ve(t,e,n,i){return he("OpenContextMenu",{id:t,x:e,y:n,data:i})}function j(t){t?window.addEventListener("contextmenu",q):window.removeEventListener("contextmenu",q)}function q(t){X(t.target,t)}function X(t,e){let n=t.getAttribute("data-contextmenu");if(n)e.preventDefault(),ve(n,e.clientX,e.clientY,t.getAttribute("data-contextmenu-data"));else{let i=t.parentElement;i&&X(i,e)}}function _(t,e=null){let n=new g(t,e);h(n)}function Ce(){document.querySelectorAll("[data-wml-event]").forEach(function(e){let n=e.getAttribute("data-wml-event"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function K(t){wails.Window[t]===void 0&&console.log("Window method "+t+" not found"),wails.Window[t]()}function Se(){document.querySelectorAll("[data-wml-window]").forEach(function(e){let n=e.getAttribute("data-wml-window"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function O(){Ce(),Se()}window.wails={...V(null)};window._wails={dialogCallback:G,dialogErrorCallback:B,dispatchWailsEvent:D,callCallback:A,callErrorCallback:W};function V(t){return{Clipboard:{...v},Application:{...S,GetWindowByName(e){return V(e)}},Log:M,Screens:E,Call:T,Plugin:P,WML:{Reload:O},Dialog:{Info:I,Warning:Q,Error:H,Question:m,OpenFile:J,SaveFile:Y},Events:{Emit:h,On:N,Once:F,OnMultiple:x,Off:U,OffAll:z},Window:y(t)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);document.addEventListener("DOMContentLoaded",function(t){O()});})();
+(()=>{var te=Object.defineProperty;var w=(e,t)=>{for(var n in t)te(e,n,{get:t[n],enumerable:!0})};var C={};w(C,{SetText:()=>ie,Text:()=>re});var ne=window.location.origin+"/wails/runtime";function oe(e,t,n){let o=new URL(ne);o.searchParams.append("method",e),n&&o.searchParams.append("args",JSON.stringify(n));let i={headers:{}};return t&&(i.headers["x-wails-window-name"]=t),new Promise((l,f)=>{fetch(o,i).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(e,t){return function(n,o=null){return oe(e+"."+n,t,o)}}var W=r("clipboard");function ie(e){W("SetText",{text:e})}function re(){return W("Text")}var M={};w(M,{Hide:()=>le,Quit:()=>ue,Show:()=>ae});var b=r("application");function le(){b("Hide")}function ae(){b("Show")}function ue(){b("Quit")}var S={};w(S,{Log:()=>ce});var se=r("log");function ce(e){return se("Log",e)}var L={};w(L,{GetAll:()=>fe,GetCurrent:()=>me,GetPrimary:()=>de});var E=r("screens");function fe(){return E("GetAll")}function de(){return E("GetPrimary")}function me(){return E("GetCurrent")}var pe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var g=(e=21)=>{let t="",n=e;for(;n--;)t+=pe[Math.random()*64|0];return t};var we=r("call"),s=new Map;function ge(){let e;do e=g();while(s.has(e));return e}function y(e,t,n){let o=s.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),s.delete(e))}function A(e,t){let n=s.get(e);n&&(n.reject(t),s.delete(e))}function T(e,t){return new Promise((n,o)=>{let i=ge();t=t||{},t["call-id"]=i,s.set(i,{resolve:n,reject:o}),we(e,t).catch(l=>{o(l),s.delete(i)})})}function R(e){return T("Call",e)}function P(e,t,...n){return T("Call",{packageName:"wails-plugins",structName:e,methodName:t,args:n})}function D(e){let t=r("window",e);return{Center:()=>void t("Center"),SetTitle:n=>void t("SetTitle",{title:n}),Fullscreen:()=>void t("Fullscreen"),UnFullscreen:()=>void t("UnFullscreen"),SetSize:(n,o)=>t("SetSize",{width:n,height:o}),Size:()=>t("Size"),SetMaxSize:(n,o)=>void t("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>void t("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>void t("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>t("SetPosition",{x:n,y:o}),Position:()=>t("Position"),Screen:()=>t("Screen"),Hide:()=>void t("Hide"),Maximise:()=>void t("Maximise"),Show:()=>void t("Show"),Close:()=>void t("Close"),ToggleMaximise:()=>void t("ToggleMaximise"),UnMaximise:()=>void t("UnMaximise"),Minimise:()=>void t("Minimise"),UnMinimise:()=>void t("UnMinimise"),SetBackgroundColour:(n,o,i,l)=>void t("SetBackgroundColour",{r:n,g:o,b:i,a:l})}}var xe=r("events"),k=class{constructor(t,n,o){this.eventName=t,this.maxCallbacks=o||-1,this.Callback=i=>(n(i),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},x=class{constructor(t,n=null){this.name=t,this.data=n}},u=new Map;function v(e,t,n){let o=u.get(e)||[],i=new k(e,t,n);return o.push(i),u.set(e,o),()=>ve(i)}function N(e,t){return v(e,t,-1)}function F(e,t){return v(e,t,1)}function ve(e){let t=e.eventName,n=u.get(t).filter(o=>o!==e);n.length===0?u.delete(t):u.set(t,n)}function U(e){console.log("dispatching event: ",{event:e});let t=u.get(e.name);if(t){let n=[];t.forEach(o=>{o.Callback(e)&&n.push(o)}),n.length>0&&(t=t.filter(o=>!n.includes(o)),t.length===0?u.delete(e.name):u.set(e.name,t))}}function z(e,...t){[e,...t].forEach(o=>{u.delete(o)})}function G(){u.clear()}function h(e){xe("Emit",e)}var he=r("dialog"),c=new Map;function Ce(){let e;do e=g();while(c.has(e));return e}function I(e,t,n){let o=c.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),c.delete(e))}function B(e,t){let n=c.get(e);n&&(n.reject(t),c.delete(e))}function d(e,t){return new Promise((n,o)=>{let i=Ce();t=t||{},t["dialog-id"]=i,c.set(i,{resolve:n,reject:o}),he(e,t).catch(l=>{o(l),c.delete(i)})})}function H(e){return d("Info",e)}function Q(e){return d("Warning",e)}function Y(e){return d("Error",e)}function m(e){return d("Question",e)}function J(e){return d("OpenFile",e)}function q(e){return d("SaveFile",e)}var be=r("contextmenu");function Me(e,t,n,o){return be("OpenContextMenu",{id:e,x:t,y:n,data:o})}function j(e){e?window.addEventListener("contextmenu",X):window.removeEventListener("contextmenu",X)}function X(e){V(e.target,e)}function V(e,t){let n=e.getAttribute("data-contextmenu");if(n)t.preventDefault(),Me(n,t.clientX,t.clientY,e.getAttribute("data-contextmenu-data"));else{let o=e.parentElement;o&&V(o,t)}}function _(e,t=null){let n=new x(e,t);h(n)}function Se(){document.querySelectorAll("[data-wml-event]").forEach(function(t){let n=t.getAttribute("data-wml-event"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function K(e){wails.Window[e]===void 0&&console.log("Window method "+e+" not found"),wails.Window[e]()}function Ee(){document.querySelectorAll("[data-wml-window]").forEach(function(t){let n=t.getAttribute("data-wml-window"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function O(){Se(),Ee()}var Z=window.webkit.messageHandlers.external.postMessage;var p=!1;function Le(e){let t=window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");return t&&(t=t.trim()),t!=="drag"||e.buttons!==1?!1:e.detail===1}function $(){window.addEventListener("mousedown",ke),window.addEventListener("mousemove",We),window.addEventListener("mouseup",Oe)}function ke(e){if(Le(e)){if(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight)return;p=!0}else p=!1}function Oe(e){document.body.style.cursor=window.wails.previousCursor||"auto",p=!1}function We(e){if(p&&(p=!1,(e.buttons!==void 0?e.buttons:e.which)>0)){window.wails.previousCursor=document.body.style.cursor,document.body.style.cursor="grab",Z("drag");return}}window.wails={...ee(null)};window._wails={dialogCallback:I,dialogErrorCallback:B,dispatchWailsEvent:U,callCallback:y,callErrorCallback:A};function ee(e){return{Clipboard:{...C},Application:{...M,GetWindowByName(t){return ee(t)}},Log:S,Screens:L,Call:R,Plugin:P,WML:{Reload:O},Dialog:{Info:H,Warning:Q,Error:Y,Question:m,OpenFile:J,SaveFile:q},Events:{Emit:h,On:N,Once:F,OnMultiple:v,Off:z,OffAll:G},Window:D(e)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);$();document.addEventListener("DOMContentLoaded",function(e){O()});})();
diff --git a/v3/internal/runtime/runtime_production_desktop_linux.js b/v3/internal/runtime/runtime_production_desktop_linux.js
index be519faa5..80b3dc812 100644
--- a/v3/internal/runtime/runtime_production_desktop_linux.js
+++ b/v3/internal/runtime/runtime_production_desktop_linux.js
@@ -1 +1 @@
-(()=>{var Z=Object.defineProperty;var p=(t,e)=>{for(var n in e)Z(t,n,{get:e[n],enumerable:!0})};var v={};p(v,{SetText:()=>te,Text:()=>ne});var $=window.location.origin+"/wails/runtime";function ee(t,e,n){let i=new URL($);i.searchParams.append("method",t),n&&i.searchParams.append("args",JSON.stringify(n));let o={headers:{}};return e&&(o.headers["x-wails-window-name"]=e),new Promise((l,f)=>{fetch(i,o).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(t,e){return function(n,i=null){return ee(t+"."+n,e,i)}}var k=r("clipboard");function te(t){k("SetText",{text:t})}function ne(){return k("Text")}var S={};p(S,{Hide:()=>ie,Quit:()=>re,Show:()=>oe});var C=r("application");function ie(){C("Hide")}function oe(){C("Show")}function re(){C("Quit")}var M={};p(M,{Log:()=>ae});var le=r("log");function ae(t){return le("Log",t)}var E={};p(E,{GetAll:()=>ue,GetCurrent:()=>se,GetPrimary:()=>ce});var b=r("screens");function ue(){return b("GetAll")}function ce(){return b("GetPrimary")}function se(){return b("GetCurrent")}var fe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var w=(t=21)=>{let e="",n=t;for(;n--;)e+=fe[Math.random()*64|0];return e};var de=r("call"),c=new Map;function me(){let t;do t=w();while(c.has(t));return t}function A(t,e,n){let i=c.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),c.delete(t))}function W(t,e){let n=c.get(t);n&&(n.reject(e),c.delete(t))}function R(t,e){return new Promise((n,i)=>{let o=me();e=e||{},e["call-id"]=o,c.set(o,{resolve:n,reject:i}),de(t,e).catch(l=>{i(l),c.delete(o)})})}function T(t){return R("Call",t)}function P(t,e,...n){return R("Call",{packageName:"wails-plugins",structName:t,methodName:e,args:n})}function y(t){let e=r("window",t);return{Center:()=>void e("Center"),SetTitle:n=>void e("SetTitle",{title:n}),Fullscreen:()=>void e("Fullscreen"),UnFullscreen:()=>void e("UnFullscreen"),SetSize:(n,i)=>e("SetSize",{width:n,height:i}),Size:()=>e("Size"),SetMaxSize:(n,i)=>void e("SetMaxSize",{width:n,height:i}),SetMinSize:(n,i)=>void e("SetMinSize",{width:n,height:i}),SetAlwaysOnTop:n=>void e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,i)=>e("SetPosition",{x:n,y:i}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>void e("Hide"),Maximise:()=>void e("Maximise"),Show:()=>void e("Show"),Close:()=>void e("Close"),ToggleMaximise:()=>void e("ToggleMaximise"),UnMaximise:()=>void e("UnMaximise"),Minimise:()=>void e("Minimise"),UnMinimise:()=>void e("UnMinimise"),SetBackgroundColour:(n,i,o,l)=>void e("SetBackgroundColour",{r:n,g:i,b:o,a:l})}}var pe=r("events"),L=class{constructor(e,n,i){this.eventName=e,this.maxCallbacks=i||-1,this.Callback=o=>(n(o),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},g=class{constructor(e,n=null){this.name=e,this.data=n}},u=new Map;function x(t,e,n){let i=u.get(t)||[],o=new L(t,e,n);return i.push(o),u.set(t,i),()=>we(o)}function N(t,e){return x(t,e,-1)}function F(t,e){return x(t,e,1)}function we(t){let e=t.eventName,n=u.get(e).filter(i=>i!==t);n.length===0?u.delete(e):u.set(e,n)}function D(t){console.log("dispatching event: ",{event:t});let e=u.get(t.name);if(e){let n=[];e.forEach(i=>{i.Callback(t)&&n.push(i)}),n.length>0&&(e=e.filter(i=>!n.includes(i)),e.length===0?u.delete(t.name):u.set(t.name,e))}}function U(t,...e){[t,...e].forEach(i=>{u.delete(i)})}function z(){u.clear()}function h(t){pe("Emit",t)}var ge=r("dialog"),s=new Map;function xe(){let t;do t=w();while(s.has(t));return t}function G(t,e,n){let i=s.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),s.delete(t))}function B(t,e){let n=s.get(t);n&&(n.reject(e),s.delete(t))}function d(t,e){return new Promise((n,i)=>{let o=xe();e=e||{},e["dialog-id"]=o,s.set(o,{resolve:n,reject:i}),ge(t,e).catch(l=>{i(l),s.delete(o)})})}function I(t){return d("Info",t)}function Q(t){return d("Warning",t)}function H(t){return d("Error",t)}function m(t){return d("Question",t)}function J(t){return d("OpenFile",t)}function Y(t){return d("SaveFile",t)}var he=r("contextmenu");function ve(t,e,n,i){return he("OpenContextMenu",{id:t,x:e,y:n,data:i})}function j(t){t?window.addEventListener("contextmenu",q):window.removeEventListener("contextmenu",q)}function q(t){X(t.target,t)}function X(t,e){let n=t.getAttribute("data-contextmenu");if(n)e.preventDefault(),ve(n,e.clientX,e.clientY,t.getAttribute("data-contextmenu-data"));else{let i=t.parentElement;i&&X(i,e)}}function _(t,e=null){let n=new g(t,e);h(n)}function Ce(){document.querySelectorAll("[data-wml-event]").forEach(function(e){let n=e.getAttribute("data-wml-event"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function K(t){wails.Window[t]===void 0&&console.log("Window method "+t+" not found"),wails.Window[t]()}function Se(){document.querySelectorAll("[data-wml-window]").forEach(function(e){let n=e.getAttribute("data-wml-window"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function O(){Ce(),Se()}window.wails={...V(null)};window._wails={dialogCallback:G,dialogErrorCallback:B,dispatchWailsEvent:D,callCallback:A,callErrorCallback:W};function V(t){return{Clipboard:{...v},Application:{...S,GetWindowByName(e){return V(e)}},Log:M,Screens:E,Call:T,Plugin:P,WML:{Reload:O},Dialog:{Info:I,Warning:Q,Error:H,Question:m,OpenFile:J,SaveFile:Y},Events:{Emit:h,On:N,Once:F,OnMultiple:x,Off:U,OffAll:z},Window:y(t)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);document.addEventListener("DOMContentLoaded",function(t){O()});})();
+(()=>{var te=Object.defineProperty;var w=(e,t)=>{for(var n in t)te(e,n,{get:t[n],enumerable:!0})};var C={};w(C,{SetText:()=>ie,Text:()=>re});var ne=window.location.origin+"/wails/runtime";function oe(e,t,n){let o=new URL(ne);o.searchParams.append("method",e),n&&o.searchParams.append("args",JSON.stringify(n));let i={headers:{}};return t&&(i.headers["x-wails-window-name"]=t),new Promise((l,f)=>{fetch(o,i).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(e,t){return function(n,o=null){return oe(e+"."+n,t,o)}}var W=r("clipboard");function ie(e){W("SetText",{text:e})}function re(){return W("Text")}var M={};w(M,{Hide:()=>le,Quit:()=>ue,Show:()=>ae});var b=r("application");function le(){b("Hide")}function ae(){b("Show")}function ue(){b("Quit")}var S={};w(S,{Log:()=>ce});var se=r("log");function ce(e){return se("Log",e)}var L={};w(L,{GetAll:()=>fe,GetCurrent:()=>me,GetPrimary:()=>de});var E=r("screens");function fe(){return E("GetAll")}function de(){return E("GetPrimary")}function me(){return E("GetCurrent")}var pe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var g=(e=21)=>{let t="",n=e;for(;n--;)t+=pe[Math.random()*64|0];return t};var we=r("call"),s=new Map;function ge(){let e;do e=g();while(s.has(e));return e}function y(e,t,n){let o=s.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),s.delete(e))}function A(e,t){let n=s.get(e);n&&(n.reject(t),s.delete(e))}function T(e,t){return new Promise((n,o)=>{let i=ge();t=t||{},t["call-id"]=i,s.set(i,{resolve:n,reject:o}),we(e,t).catch(l=>{o(l),s.delete(i)})})}function R(e){return T("Call",e)}function P(e,t,...n){return T("Call",{packageName:"wails-plugins",structName:e,methodName:t,args:n})}function D(e){let t=r("window",e);return{Center:()=>void t("Center"),SetTitle:n=>void t("SetTitle",{title:n}),Fullscreen:()=>void t("Fullscreen"),UnFullscreen:()=>void t("UnFullscreen"),SetSize:(n,o)=>t("SetSize",{width:n,height:o}),Size:()=>t("Size"),SetMaxSize:(n,o)=>void t("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>void t("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>void t("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>t("SetPosition",{x:n,y:o}),Position:()=>t("Position"),Screen:()=>t("Screen"),Hide:()=>void t("Hide"),Maximise:()=>void t("Maximise"),Show:()=>void t("Show"),Close:()=>void t("Close"),ToggleMaximise:()=>void t("ToggleMaximise"),UnMaximise:()=>void t("UnMaximise"),Minimise:()=>void t("Minimise"),UnMinimise:()=>void t("UnMinimise"),SetBackgroundColour:(n,o,i,l)=>void t("SetBackgroundColour",{r:n,g:o,b:i,a:l})}}var xe=r("events"),k=class{constructor(t,n,o){this.eventName=t,this.maxCallbacks=o||-1,this.Callback=i=>(n(i),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},x=class{constructor(t,n=null){this.name=t,this.data=n}},u=new Map;function v(e,t,n){let o=u.get(e)||[],i=new k(e,t,n);return o.push(i),u.set(e,o),()=>ve(i)}function N(e,t){return v(e,t,-1)}function F(e,t){return v(e,t,1)}function ve(e){let t=e.eventName,n=u.get(t).filter(o=>o!==e);n.length===0?u.delete(t):u.set(t,n)}function U(e){console.log("dispatching event: ",{event:e});let t=u.get(e.name);if(t){let n=[];t.forEach(o=>{o.Callback(e)&&n.push(o)}),n.length>0&&(t=t.filter(o=>!n.includes(o)),t.length===0?u.delete(e.name):u.set(e.name,t))}}function z(e,...t){[e,...t].forEach(o=>{u.delete(o)})}function G(){u.clear()}function h(e){xe("Emit",e)}var he=r("dialog"),c=new Map;function Ce(){let e;do e=g();while(c.has(e));return e}function I(e,t,n){let o=c.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),c.delete(e))}function B(e,t){let n=c.get(e);n&&(n.reject(t),c.delete(e))}function d(e,t){return new Promise((n,o)=>{let i=Ce();t=t||{},t["dialog-id"]=i,c.set(i,{resolve:n,reject:o}),he(e,t).catch(l=>{o(l),c.delete(i)})})}function H(e){return d("Info",e)}function Q(e){return d("Warning",e)}function Y(e){return d("Error",e)}function m(e){return d("Question",e)}function J(e){return d("OpenFile",e)}function q(e){return d("SaveFile",e)}var be=r("contextmenu");function Me(e,t,n,o){return be("OpenContextMenu",{id:e,x:t,y:n,data:o})}function j(e){e?window.addEventListener("contextmenu",X):window.removeEventListener("contextmenu",X)}function X(e){V(e.target,e)}function V(e,t){let n=e.getAttribute("data-contextmenu");if(n)t.preventDefault(),Me(n,t.clientX,t.clientY,e.getAttribute("data-contextmenu-data"));else{let o=e.parentElement;o&&V(o,t)}}function _(e,t=null){let n=new x(e,t);h(n)}function Se(){document.querySelectorAll("[data-wml-event]").forEach(function(t){let n=t.getAttribute("data-wml-event"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function K(e){wails.Window[e]===void 0&&console.log("Window method "+e+" not found"),wails.Window[e]()}function Ee(){document.querySelectorAll("[data-wml-window]").forEach(function(t){let n=t.getAttribute("data-wml-window"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function O(){Se(),Ee()}var Z=window.webkit.messageHandlers.external.postMessage;var p=!1;function Le(e){let t=window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");return t&&(t=t.trim()),t!=="drag"||e.buttons!==1?!1:e.detail===1}function $(){window.addEventListener("mousedown",ke),window.addEventListener("mousemove",We),window.addEventListener("mouseup",Oe)}function ke(e){if(Le(e)){if(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight)return;p=!0}else p=!1}function Oe(e){document.body.style.cursor=window.wails.previousCursor||"auto",p=!1}function We(e){if(p&&(p=!1,(e.buttons!==void 0?e.buttons:e.which)>0)){window.wails.previousCursor=document.body.style.cursor,document.body.style.cursor="grab",Z("drag");return}}window.wails={...ee(null)};window._wails={dialogCallback:I,dialogErrorCallback:B,dispatchWailsEvent:U,callCallback:y,callErrorCallback:A};function ee(e){return{Clipboard:{...C},Application:{...M,GetWindowByName(t){return ee(t)}},Log:S,Screens:L,Call:R,Plugin:P,WML:{Reload:O},Dialog:{Info:H,Warning:Q,Error:Y,Question:m,OpenFile:J,SaveFile:q},Events:{Emit:h,On:N,Once:F,OnMultiple:v,Off:z,OffAll:G},Window:D(e)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);$();document.addEventListener("DOMContentLoaded",function(e){O()});})();
diff --git a/v3/internal/runtime/runtime_production_desktop_windows.js b/v3/internal/runtime/runtime_production_desktop_windows.js
index be519faa5..928481a63 100644
--- a/v3/internal/runtime/runtime_production_desktop_windows.js
+++ b/v3/internal/runtime/runtime_production_desktop_windows.js
@@ -1 +1 @@
-(()=>{var Z=Object.defineProperty;var p=(t,e)=>{for(var n in e)Z(t,n,{get:e[n],enumerable:!0})};var v={};p(v,{SetText:()=>te,Text:()=>ne});var $=window.location.origin+"/wails/runtime";function ee(t,e,n){let i=new URL($);i.searchParams.append("method",t),n&&i.searchParams.append("args",JSON.stringify(n));let o={headers:{}};return e&&(o.headers["x-wails-window-name"]=e),new Promise((l,f)=>{fetch(i,o).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(t,e){return function(n,i=null){return ee(t+"."+n,e,i)}}var k=r("clipboard");function te(t){k("SetText",{text:t})}function ne(){return k("Text")}var S={};p(S,{Hide:()=>ie,Quit:()=>re,Show:()=>oe});var C=r("application");function ie(){C("Hide")}function oe(){C("Show")}function re(){C("Quit")}var M={};p(M,{Log:()=>ae});var le=r("log");function ae(t){return le("Log",t)}var E={};p(E,{GetAll:()=>ue,GetCurrent:()=>se,GetPrimary:()=>ce});var b=r("screens");function ue(){return b("GetAll")}function ce(){return b("GetPrimary")}function se(){return b("GetCurrent")}var fe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var w=(t=21)=>{let e="",n=t;for(;n--;)e+=fe[Math.random()*64|0];return e};var de=r("call"),c=new Map;function me(){let t;do t=w();while(c.has(t));return t}function A(t,e,n){let i=c.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),c.delete(t))}function W(t,e){let n=c.get(t);n&&(n.reject(e),c.delete(t))}function R(t,e){return new Promise((n,i)=>{let o=me();e=e||{},e["call-id"]=o,c.set(o,{resolve:n,reject:i}),de(t,e).catch(l=>{i(l),c.delete(o)})})}function T(t){return R("Call",t)}function P(t,e,...n){return R("Call",{packageName:"wails-plugins",structName:t,methodName:e,args:n})}function y(t){let e=r("window",t);return{Center:()=>void e("Center"),SetTitle:n=>void e("SetTitle",{title:n}),Fullscreen:()=>void e("Fullscreen"),UnFullscreen:()=>void e("UnFullscreen"),SetSize:(n,i)=>e("SetSize",{width:n,height:i}),Size:()=>e("Size"),SetMaxSize:(n,i)=>void e("SetMaxSize",{width:n,height:i}),SetMinSize:(n,i)=>void e("SetMinSize",{width:n,height:i}),SetAlwaysOnTop:n=>void e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,i)=>e("SetPosition",{x:n,y:i}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>void e("Hide"),Maximise:()=>void e("Maximise"),Show:()=>void e("Show"),Close:()=>void e("Close"),ToggleMaximise:()=>void e("ToggleMaximise"),UnMaximise:()=>void e("UnMaximise"),Minimise:()=>void e("Minimise"),UnMinimise:()=>void e("UnMinimise"),SetBackgroundColour:(n,i,o,l)=>void e("SetBackgroundColour",{r:n,g:i,b:o,a:l})}}var pe=r("events"),L=class{constructor(e,n,i){this.eventName=e,this.maxCallbacks=i||-1,this.Callback=o=>(n(o),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},g=class{constructor(e,n=null){this.name=e,this.data=n}},u=new Map;function x(t,e,n){let i=u.get(t)||[],o=new L(t,e,n);return i.push(o),u.set(t,i),()=>we(o)}function N(t,e){return x(t,e,-1)}function F(t,e){return x(t,e,1)}function we(t){let e=t.eventName,n=u.get(e).filter(i=>i!==t);n.length===0?u.delete(e):u.set(e,n)}function D(t){console.log("dispatching event: ",{event:t});let e=u.get(t.name);if(e){let n=[];e.forEach(i=>{i.Callback(t)&&n.push(i)}),n.length>0&&(e=e.filter(i=>!n.includes(i)),e.length===0?u.delete(t.name):u.set(t.name,e))}}function U(t,...e){[t,...e].forEach(i=>{u.delete(i)})}function z(){u.clear()}function h(t){pe("Emit",t)}var ge=r("dialog"),s=new Map;function xe(){let t;do t=w();while(s.has(t));return t}function G(t,e,n){let i=s.get(t);i&&(n?i.resolve(JSON.parse(e)):i.resolve(e),s.delete(t))}function B(t,e){let n=s.get(t);n&&(n.reject(e),s.delete(t))}function d(t,e){return new Promise((n,i)=>{let o=xe();e=e||{},e["dialog-id"]=o,s.set(o,{resolve:n,reject:i}),ge(t,e).catch(l=>{i(l),s.delete(o)})})}function I(t){return d("Info",t)}function Q(t){return d("Warning",t)}function H(t){return d("Error",t)}function m(t){return d("Question",t)}function J(t){return d("OpenFile",t)}function Y(t){return d("SaveFile",t)}var he=r("contextmenu");function ve(t,e,n,i){return he("OpenContextMenu",{id:t,x:e,y:n,data:i})}function j(t){t?window.addEventListener("contextmenu",q):window.removeEventListener("contextmenu",q)}function q(t){X(t.target,t)}function X(t,e){let n=t.getAttribute("data-contextmenu");if(n)e.preventDefault(),ve(n,e.clientX,e.clientY,t.getAttribute("data-contextmenu-data"));else{let i=t.parentElement;i&&X(i,e)}}function _(t,e=null){let n=new g(t,e);h(n)}function Ce(){document.querySelectorAll("[data-wml-event]").forEach(function(e){let n=e.getAttribute("data-wml-event"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function K(t){wails.Window[t]===void 0&&console.log("Window method "+t+" not found"),wails.Window[t]()}function Se(){document.querySelectorAll("[data-wml-window]").forEach(function(e){let n=e.getAttribute("data-wml-window"),i=e.getAttribute("data-wml-confirm"),o=e.getAttribute("data-wml-trigger")||"click",l=function(){if(i){m({Title:"Confirm",Message:i,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};e.removeEventListener(o,l),e.addEventListener(o,l)})}function O(){Ce(),Se()}window.wails={...V(null)};window._wails={dialogCallback:G,dialogErrorCallback:B,dispatchWailsEvent:D,callCallback:A,callErrorCallback:W};function V(t){return{Clipboard:{...v},Application:{...S,GetWindowByName(e){return V(e)}},Log:M,Screens:E,Call:T,Plugin:P,WML:{Reload:O},Dialog:{Info:I,Warning:Q,Error:H,Question:m,OpenFile:J,SaveFile:Y},Events:{Emit:h,On:N,Once:F,OnMultiple:x,Off:U,OffAll:z},Window:y(t)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);document.addEventListener("DOMContentLoaded",function(t){O()});})();
+(()=>{var te=Object.defineProperty;var w=(e,t)=>{for(var n in t)te(e,n,{get:t[n],enumerable:!0})};var C={};w(C,{SetText:()=>ie,Text:()=>re});var ne=window.location.origin+"/wails/runtime";function oe(e,t,n){let o=new URL(ne);o.searchParams.append("method",e),n&&o.searchParams.append("args",JSON.stringify(n));let i={headers:{}};return t&&(i.headers["x-wails-window-name"]=t),new Promise((l,f)=>{fetch(o,i).then(a=>{if(a.ok)return a.headers.get("Content-Type")&&a.headers.get("Content-Type").indexOf("application/json")!==-1?a.json():a.text();f(Error(a.statusText))}).then(a=>l(a)).catch(a=>f(a))})}function r(e,t){return function(n,o=null){return oe(e+"."+n,t,o)}}var W=r("clipboard");function ie(e){W("SetText",{text:e})}function re(){return W("Text")}var M={};w(M,{Hide:()=>le,Quit:()=>ue,Show:()=>ae});var b=r("application");function le(){b("Hide")}function ae(){b("Show")}function ue(){b("Quit")}var S={};w(S,{Log:()=>ce});var se=r("log");function ce(e){return se("Log",e)}var L={};w(L,{GetAll:()=>fe,GetCurrent:()=>me,GetPrimary:()=>de});var E=r("screens");function fe(){return E("GetAll")}function de(){return E("GetPrimary")}function me(){return E("GetCurrent")}var pe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var g=(e=21)=>{let t="",n=e;for(;n--;)t+=pe[Math.random()*64|0];return t};var we=r("call"),s=new Map;function ge(){let e;do e=g();while(s.has(e));return e}function y(e,t,n){let o=s.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),s.delete(e))}function A(e,t){let n=s.get(e);n&&(n.reject(t),s.delete(e))}function T(e,t){return new Promise((n,o)=>{let i=ge();t=t||{},t["call-id"]=i,s.set(i,{resolve:n,reject:o}),we(e,t).catch(l=>{o(l),s.delete(i)})})}function R(e){return T("Call",e)}function P(e,t,...n){return T("Call",{packageName:"wails-plugins",structName:e,methodName:t,args:n})}function D(e){let t=r("window",e);return{Center:()=>void t("Center"),SetTitle:n=>void t("SetTitle",{title:n}),Fullscreen:()=>void t("Fullscreen"),UnFullscreen:()=>void t("UnFullscreen"),SetSize:(n,o)=>t("SetSize",{width:n,height:o}),Size:()=>t("Size"),SetMaxSize:(n,o)=>void t("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>void t("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>void t("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>t("SetPosition",{x:n,y:o}),Position:()=>t("Position"),Screen:()=>t("Screen"),Hide:()=>void t("Hide"),Maximise:()=>void t("Maximise"),Show:()=>void t("Show"),Close:()=>void t("Close"),ToggleMaximise:()=>void t("ToggleMaximise"),UnMaximise:()=>void t("UnMaximise"),Minimise:()=>void t("Minimise"),UnMinimise:()=>void t("UnMinimise"),SetBackgroundColour:(n,o,i,l)=>void t("SetBackgroundColour",{r:n,g:o,b:i,a:l})}}var xe=r("events"),k=class{constructor(t,n,o){this.eventName=t,this.maxCallbacks=o||-1,this.Callback=i=>(n(i),this.maxCallbacks===-1?!1:(this.maxCallbacks-=1,this.maxCallbacks===0))}},x=class{constructor(t,n=null){this.name=t,this.data=n}},u=new Map;function v(e,t,n){let o=u.get(e)||[],i=new k(e,t,n);return o.push(i),u.set(e,o),()=>ve(i)}function N(e,t){return v(e,t,-1)}function F(e,t){return v(e,t,1)}function ve(e){let t=e.eventName,n=u.get(t).filter(o=>o!==e);n.length===0?u.delete(t):u.set(t,n)}function U(e){console.log("dispatching event: ",{event:e});let t=u.get(e.name);if(t){let n=[];t.forEach(o=>{o.Callback(e)&&n.push(o)}),n.length>0&&(t=t.filter(o=>!n.includes(o)),t.length===0?u.delete(e.name):u.set(e.name,t))}}function z(e,...t){[e,...t].forEach(o=>{u.delete(o)})}function G(){u.clear()}function h(e){xe("Emit",e)}var he=r("dialog"),c=new Map;function Ce(){let e;do e=g();while(c.has(e));return e}function I(e,t,n){let o=c.get(e);o&&(n?o.resolve(JSON.parse(t)):o.resolve(t),c.delete(e))}function B(e,t){let n=c.get(e);n&&(n.reject(t),c.delete(e))}function d(e,t){return new Promise((n,o)=>{let i=Ce();t=t||{},t["dialog-id"]=i,c.set(i,{resolve:n,reject:o}),he(e,t).catch(l=>{o(l),c.delete(i)})})}function H(e){return d("Info",e)}function Q(e){return d("Warning",e)}function Y(e){return d("Error",e)}function m(e){return d("Question",e)}function J(e){return d("OpenFile",e)}function q(e){return d("SaveFile",e)}var be=r("contextmenu");function Me(e,t,n,o){return be("OpenContextMenu",{id:e,x:t,y:n,data:o})}function j(e){e?window.addEventListener("contextmenu",X):window.removeEventListener("contextmenu",X)}function X(e){V(e.target,e)}function V(e,t){let n=e.getAttribute("data-contextmenu");if(n)t.preventDefault(),Me(n,t.clientX,t.clientY,e.getAttribute("data-contextmenu-data"));else{let o=e.parentElement;o&&V(o,t)}}function _(e,t=null){let n=new x(e,t);h(n)}function Se(){document.querySelectorAll("[data-wml-event]").forEach(function(t){let n=t.getAttribute("data-wml-event"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&_(n)});return}_(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function K(e){wails.Window[e]===void 0&&console.log("Window method "+e+" not found"),wails.Window[e]()}function Ee(){document.querySelectorAll("[data-wml-window]").forEach(function(t){let n=t.getAttribute("data-wml-window"),o=t.getAttribute("data-wml-confirm"),i=t.getAttribute("data-wml-trigger")||"click",l=function(){if(o){m({Title:"Confirm",Message:o,Buttons:[{Label:"Yes"},{Label:"No",IsDefault:!0}]}).then(function(f){f!=="No"&&K(n)});return}K(n)};t.removeEventListener(i,l),t.addEventListener(i,l)})}function O(){Se(),Ee()}var Z=chrome.webview.postMessage;var p=!1;function Le(e){let t=window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");return t&&(t=t.trim()),t!=="drag"||e.buttons!==1?!1:e.detail===1}function $(){window.addEventListener("mousedown",ke),window.addEventListener("mousemove",We),window.addEventListener("mouseup",Oe)}function ke(e){if(Le(e)){if(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight)return;p=!0}else p=!1}function Oe(e){document.body.style.cursor=window.wails.previousCursor||"auto",p=!1}function We(e){if(p&&(p=!1,(e.buttons!==void 0?e.buttons:e.which)>0)){window.wails.previousCursor=document.body.style.cursor,document.body.style.cursor="grab",Z("drag");return}}window.wails={...ee(null)};window._wails={dialogCallback:I,dialogErrorCallback:B,dispatchWailsEvent:U,callCallback:y,callErrorCallback:A};function ee(e){return{Clipboard:{...C},Application:{...M,GetWindowByName(t){return ee(t)}},Log:S,Screens:L,Call:R,Plugin:P,WML:{Reload:O},Dialog:{Info:H,Warning:Q,Error:Y,Question:m,OpenFile:J,SaveFile:q},Events:{Emit:h,On:N,Once:F,OnMultiple:v,Off:z,OffAll:G},Window:D(e)}}console.log("Wails v3.0.0 Debug Mode Enabled");j(!0);$();document.addEventListener("DOMContentLoaded",function(e){O()});})();
diff --git a/v3/internal/templates/_base/default/go.mod.tmpl b/v3/internal/templates/_base/default/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/_base/default/go.mod.tmpl
+++ b/v3/internal/templates/_base/default/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/_base/default/main.go.tmpl b/v3/internal/templates/_base/default/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/_base/default/main.go.tmpl
+++ b/v3/internal/templates/_base/default/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/lit-ts/go.mod.tmpl b/v3/internal/templates/lit-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/lit-ts/go.mod.tmpl
+++ b/v3/internal/templates/lit-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/lit-ts/main.go.tmpl b/v3/internal/templates/lit-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/lit-ts/main.go.tmpl
+++ b/v3/internal/templates/lit-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/lit/go.mod.tmpl b/v3/internal/templates/lit/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/lit/go.mod.tmpl
+++ b/v3/internal/templates/lit/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/lit/main.go.tmpl b/v3/internal/templates/lit/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/lit/main.go.tmpl
+++ b/v3/internal/templates/lit/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/preact-ts/go.mod.tmpl b/v3/internal/templates/preact-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/preact-ts/go.mod.tmpl
+++ b/v3/internal/templates/preact-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/preact-ts/main.go.tmpl b/v3/internal/templates/preact-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/preact-ts/main.go.tmpl
+++ b/v3/internal/templates/preact-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/preact/go.mod.tmpl b/v3/internal/templates/preact/go.mod.tmpl
index 5fbc49867..bc1cc31ea 100644
--- a/v3/internal/templates/preact/go.mod.tmpl
+++ b/v3/internal/templates/preact/go.mod.tmpl
@@ -12,6 +12,6 @@ require (
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/preact/main.go.tmpl b/v3/internal/templates/preact/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/preact/main.go.tmpl
+++ b/v3/internal/templates/preact/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/react-swc-ts/go.mod.tmpl b/v3/internal/templates/react-swc-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/react-swc-ts/go.mod.tmpl
+++ b/v3/internal/templates/react-swc-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/react-swc-ts/main.go.tmpl b/v3/internal/templates/react-swc-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/react-swc-ts/main.go.tmpl
+++ b/v3/internal/templates/react-swc-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/react-swc/go.mod.tmpl b/v3/internal/templates/react-swc/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/react-swc/go.mod.tmpl
+++ b/v3/internal/templates/react-swc/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/react-swc/main.go.tmpl b/v3/internal/templates/react-swc/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/react-swc/main.go.tmpl
+++ b/v3/internal/templates/react-swc/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/react-ts/go.mod.tmpl b/v3/internal/templates/react-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/react-ts/go.mod.tmpl
+++ b/v3/internal/templates/react-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/react-ts/main.go.tmpl b/v3/internal/templates/react-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/react-ts/main.go.tmpl
+++ b/v3/internal/templates/react-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/react/go.mod.tmpl b/v3/internal/templates/react/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/react/go.mod.tmpl
+++ b/v3/internal/templates/react/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/react/main.go.tmpl b/v3/internal/templates/react/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/react/main.go.tmpl
+++ b/v3/internal/templates/react/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/svelte-ts/go.mod.tmpl b/v3/internal/templates/svelte-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/svelte-ts/go.mod.tmpl
+++ b/v3/internal/templates/svelte-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/svelte-ts/main.go.tmpl b/v3/internal/templates/svelte-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/svelte-ts/main.go.tmpl
+++ b/v3/internal/templates/svelte-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/svelte/go.mod.tmpl b/v3/internal/templates/svelte/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/svelte/go.mod.tmpl
+++ b/v3/internal/templates/svelte/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/svelte/main.go.tmpl b/v3/internal/templates/svelte/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/svelte/main.go.tmpl
+++ b/v3/internal/templates/svelte/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/templates.go b/v3/internal/templates/templates.go
index e0da5a48b..c3fae1bb6 100644
--- a/v3/internal/templates/templates.go
+++ b/v3/internal/templates/templates.go
@@ -3,9 +3,11 @@ package templates
import (
"embed"
"fmt"
+ "github.com/pterm/pterm"
"github.com/wailsapp/wails/v3/internal/debug"
"io/fs"
"os"
+ "path/filepath"
"github.com/wailsapp/wails/v3/internal/flags"
@@ -154,7 +156,7 @@ func Install(options *flags.Init) error {
templateData := TemplateOptions{
options,
- debug.LocalModulePath,
+ filepath.FromSlash(debug.LocalModulePath + "/"),
}
template, found := lo.Find(defaultTemplates, func(template TemplateData) bool {
return template.Name == options.TemplateName
@@ -167,7 +169,7 @@ func Install(options *flags.Init) error {
templateData.ProjectDir = lo.Must(os.Getwd())
}
templateData.ProjectDir = fmt.Sprintf("%s/%s", options.ProjectDir, options.ProjectName)
- fmt.Printf("Installing template '%s' into '%s'\n", options.TemplateName, options.ProjectDir)
+ pterm.Printf("Installing template '%s' into '%s'\n", options.TemplateName, filepath.FromSlash(options.ProjectDir))
tfs, err := fs.Sub(template.FS, options.TemplateName)
if err != nil {
return err
diff --git a/v3/internal/templates/vanilla-ts/go.mod.tmpl b/v3/internal/templates/vanilla-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/vanilla-ts/go.mod.tmpl
+++ b/v3/internal/templates/vanilla-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/vanilla-ts/main.go.tmpl b/v3/internal/templates/vanilla-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/vanilla-ts/main.go.tmpl
+++ b/v3/internal/templates/vanilla-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/vanilla/go.mod.tmpl b/v3/internal/templates/vanilla/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/vanilla/go.mod.tmpl
+++ b/v3/internal/templates/vanilla/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/vanilla/main.go.tmpl b/v3/internal/templates/vanilla/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/vanilla/main.go.tmpl
+++ b/v3/internal/templates/vanilla/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/vue-ts/go.mod.tmpl b/v3/internal/templates/vue-ts/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/vue-ts/go.mod.tmpl
+++ b/v3/internal/templates/vue-ts/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/vue-ts/main.go.tmpl b/v3/internal/templates/vue-ts/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/vue-ts/main.go.tmpl
+++ b/v3/internal/templates/vue-ts/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/internal/templates/vue/go.mod.tmpl b/v3/internal/templates/vue/go.mod.tmpl
index 3c878c9ab..a05b62ce6 100644
--- a/v3/internal/templates/vue/go.mod.tmpl
+++ b/v3/internal/templates/vue/go.mod.tmpl
@@ -16,6 +16,6 @@ require (
golang.org/x/net v0.7.0 // indirect
)
{{if gt (len .LocalModulePath) 0}}
-replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
-replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
+replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
+replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
{{end}}
diff --git a/v3/internal/templates/vue/main.go.tmpl b/v3/internal/templates/vue/main.go.tmpl
index 1bc6a4868..16f808e8a 100644
--- a/v3/internal/templates/vue/main.go.tmpl
+++ b/v3/internal/templates/vue/main.go.tmpl
@@ -20,7 +20,7 @@ func main() {
},
})
// Create window
- app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
+ app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go
index b2667bf00..7508afda3 100644
--- a/v3/pkg/application/application.go
+++ b/v3/pkg/application/application.go
@@ -1,6 +1,5 @@
package application
-import "C"
import (
"log"
"net/http"
@@ -9,6 +8,10 @@ import (
"strconv"
"sync"
+ "github.com/wailsapp/wails/v3/pkg/icons"
+
+ "github.com/samber/lo"
+
"github.com/wailsapp/wails/v2/pkg/assetserver"
"github.com/wailsapp/wails/v2/pkg/assetserver/webview"
assetserveroptions "github.com/wailsapp/wails/v2/pkg/options/assetserver"
@@ -20,10 +23,17 @@ import (
var globalApplication *App
+// isDebugMode is true if the application is running in debug mode
+var isDebugMode func() bool
+
func init() {
runtime.LockOSThread()
}
+type EventListener struct {
+ callback func()
+}
+
func New(appOptions Options) *App {
if globalApplication != nil {
return globalApplication
@@ -33,7 +43,8 @@ func New(appOptions Options) *App {
result := &App{
options: appOptions,
- applicationEventListeners: make(map[uint][]func()),
+ applicationEventListeners: make(map[uint][]*EventListener),
+ windows: make(map[uint]*WebviewWindow),
systemTrays: make(map[uint]*SystemTray),
log: logger.New(appOptions.Logger.CustomLoggers...),
contextMenus: make(map[string]*Menu),
@@ -45,6 +56,13 @@ func New(appOptions Options) *App {
result.log.AddOutput(&logger.Console{})
}
+ // Patch isDebug if we aren't in prod mode
+ if isDebugMode == nil {
+ isDebugMode = func() bool {
+ return true
+ }
+ }
+
result.Events = NewWailsEventProcessor(result.dispatchEventToWindows)
opts := assetserveroptions.Options{
@@ -92,24 +110,32 @@ func mergeApplicationDefaults(o *Options) {
o.Description = "An application written using Wails"
}
if o.Icon == nil {
- o.Icon = DefaultApplicationIcon
+ o.Icon = icons.ApplicationLightMode256
}
}
-type platformApp interface {
- run() error
- destroy()
- setApplicationMenu(menu *Menu)
- name() string
- getCurrentWindowID() uint
- showAboutDialog(name string, description string, icon []byte)
- setIcon(icon []byte)
- on(id uint)
- dispatchOnMainThread(id uint)
- hide()
- show()
-}
+type (
+ platformApp interface {
+ run() error
+ destroy()
+ setApplicationMenu(menu *Menu)
+ name() string
+ getCurrentWindowID() uint
+ showAboutDialog(name string, description string, icon []byte)
+ setIcon(icon []byte)
+ on(id uint)
+ dispatchOnMainThread(id uint)
+ hide()
+ show()
+ getPrimaryScreen() (*Screen, error)
+ getScreens() ([]*Screen, error)
+ }
+
+ runnable interface {
+ run()
+ }
+)
// Messages sent from javascript get routed here
type windowMessage struct {
@@ -152,7 +178,7 @@ var webviewRequests = make(chan *webViewAssetRequest)
type App struct {
options Options
- applicationEventListeners map[uint][]func()
+ applicationEventListeners map[uint][]*EventListener
applicationEventListenersLock sync.RWMutex
// Windows
@@ -170,7 +196,10 @@ type App struct {
menuItemsLock sync.Mutex
// Running
- running bool
+ running bool
+ runLock sync.Mutex
+ pendingRun []runnable
+
bindings *Bindings
plugins *PluginManager
@@ -187,7 +216,8 @@ type App struct {
contextMenus map[string]*Menu
contextMenusLock sync.Mutex
- assets *assetserver.AssetServer
+ assets *assetserver.AssetServer
+ startURL string
// Hooks
windowCreatedCallbacks []func(window *WebviewWindow)
@@ -213,17 +243,28 @@ func (a *App) deleteWindowByID(id uint) {
delete(a.windows, id)
}
-func (a *App) On(eventType events.ApplicationEventType, callback func()) {
+func (a *App) On(eventType events.ApplicationEventType, callback func()) func() {
eventID := uint(eventType)
a.applicationEventListenersLock.Lock()
defer a.applicationEventListenersLock.Unlock()
- a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], callback)
+ listener := &EventListener{
+ callback: callback,
+ }
+ a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], listener)
if a.impl != nil {
go a.impl.on(eventID)
}
+
+ return func() {
+ // lock the map
+ a.applicationEventListenersLock.Lock()
+ defer a.applicationEventListenersLock.Unlock()
+ // Remove listener
+ a.applicationEventListeners[eventID] = lo.Without(a.applicationEventListeners[eventID], listener)
+ }
}
func (a *App) NewWebviewWindow() *WebviewWindow {
- return a.NewWebviewWindowWithOptions(&WebviewWindowOptions{})
+ return a.NewWebviewWindowWithOptions(WebviewWindowOptions{})
}
func (a *App) GetPID() int {
@@ -264,16 +305,10 @@ func (a *App) error(message string, args ...any) {
})
}
-func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *WebviewWindow {
- // Ensure we have sane defaults
- if windowOptions == nil {
- windowOptions = WebviewWindowDefaults
- }
+func (a *App) NewWebviewWindowWithOptions(windowOptions WebviewWindowOptions) *WebviewWindow {
newWindow := NewWindow(windowOptions)
id := newWindow.id
- if a.windows == nil {
- a.windows = make(map[uint]*WebviewWindow)
- }
+
a.windowsLock.Lock()
a.windows[id] = newWindow
a.windowsLock.Unlock()
@@ -283,9 +318,7 @@ func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *
hook(newWindow)
}
- if a.running {
- newWindow.run()
- }
+ a.runOrDeferToAppRun(newWindow)
return newWindow
}
@@ -293,13 +326,13 @@ func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *
func (a *App) NewSystemTray() *SystemTray {
id := a.getSystemTrayID()
newSystemTray := NewSystemTray(id)
+
a.systemTraysLock.Lock()
a.systemTrays[id] = newSystemTray
a.systemTraysLock.Unlock()
- if a.running {
- newSystemTray.Run()
- }
+ a.runOrDeferToAppRun(newSystemTray)
+
return newSystemTray
}
@@ -307,7 +340,6 @@ func (a *App) Run() error {
a.info("Starting application")
a.impl = newPlatformApp(a)
- a.running = true
go func() {
for {
event := <-applicationEvents
@@ -346,21 +378,21 @@ func (a *App) Run() error {
}
}()
- // run windows
- for _, window := range a.windows {
- go window.run()
- }
+ a.runLock.Lock()
+ a.running = true
- // run system trays
- for _, systray := range a.systemTrays {
- go systray.Run()
+ for _, systray := range a.pendingRun {
+ go systray.run()
}
+ a.pendingRun = nil
+
+ a.runLock.Unlock()
// set the application menu
- a.impl.setApplicationMenu(a.ApplicationMenu)
-
- // set the application Icon
- a.impl.setIcon(a.options.Icon)
+ if runtime.GOOS == "darwin" {
+ a.impl.setApplicationMenu(a.ApplicationMenu)
+ a.impl.setIcon(a.options.Icon)
+ }
err := a.impl.run()
if err != nil {
@@ -380,7 +412,7 @@ func (a *App) handleApplicationEvent(event uint) {
return
}
for _, listener := range listeners {
- go listener()
+ go listener.callback()
}
}
@@ -514,11 +546,11 @@ func (a *App) SaveFileDialog() *SaveFileDialog {
}
func (a *App) GetPrimaryScreen() (*Screen, error) {
- return getPrimaryScreen()
+ return a.impl.getPrimaryScreen()
}
func (a *App) GetScreens() ([]*Screen, error) {
- return getScreens()
+ return a.impl.getScreens()
}
func (a *App) Clipboard() *Clipboard {
@@ -599,3 +631,48 @@ func (a *App) GetWindowByName(name string) *WebviewWindow {
}
return nil
}
+
+func (a *App) runOrDeferToAppRun(r runnable) {
+ a.runLock.Lock()
+ running := a.running
+ if !running {
+ a.pendingRun = append(a.pendingRun, r)
+ }
+ a.runLock.Unlock()
+
+ if running {
+ r.run()
+ }
+}
+
+func invokeSync(fn func()) {
+ var wg sync.WaitGroup
+ wg.Add(1)
+ globalApplication.dispatchOnMainThread(func() {
+ fn()
+ wg.Done()
+ })
+ wg.Wait()
+}
+
+func invokeSyncWithResult[T any](fn func() T) (res T) {
+ var wg sync.WaitGroup
+ wg.Add(1)
+ globalApplication.dispatchOnMainThread(func() {
+ res = fn()
+ wg.Done()
+ })
+ wg.Wait()
+ return res
+}
+
+func invokeSyncWithResultAndError[T any](fn func() (T, error)) (res T, err error) {
+ var wg sync.WaitGroup
+ wg.Add(1)
+ globalApplication.dispatchOnMainThread(func() {
+ res, err = fn()
+ wg.Done()
+ })
+ wg.Wait()
+ return res, err
+}
diff --git a/v3/pkg/application/application_darwin.go b/v3/pkg/application/application_darwin.go
index b299c1f67..0c32a3cf5 100644
--- a/v3/pkg/application/application_darwin.go
+++ b/v3/pkg/application/application_darwin.go
@@ -7,9 +7,9 @@ package application
#cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c
#cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.13
-#include "application.h"
-#include "app_delegate.h"
-#include "webview_window.h"
+#include "application_darwin.h"
+#include "application_darwin_delegate.h"
+#include "webview_window_darwin.h"
#include
extern void registerListener(unsigned int event);
@@ -137,6 +137,10 @@ type macosApp struct {
parent *App
}
+func getNativeApplication() *macosApp {
+ return globalApplication.impl.(*macosApp)
+}
+
func (m *macosApp) hide() {
C.hide()
}
@@ -182,6 +186,7 @@ func (m *macosApp) run() error {
C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy))
C.activateIgnoringOtherApps()
})
+ m.setupCommonEvents()
// setup event listeners
for eventID := range m.parent.applicationEventListeners {
m.on(eventID)
diff --git a/v3/pkg/application/application.h b/v3/pkg/application/application_darwin.h
similarity index 100%
rename from v3/pkg/application/application.h
rename to v3/pkg/application/application_darwin.h
diff --git a/v3/pkg/application/app_delegate.h b/v3/pkg/application/application_darwin_delegate.h
similarity index 100%
rename from v3/pkg/application/app_delegate.h
rename to v3/pkg/application/application_darwin_delegate.h
diff --git a/v3/pkg/application/app_delegate.m b/v3/pkg/application/application_darwin_delegate.m
similarity index 99%
rename from v3/pkg/application/app_delegate.m
rename to v3/pkg/application/application_darwin_delegate.m
index d20a48fda..5c6b10c25 100644
--- a/v3/pkg/application/app_delegate.m
+++ b/v3/pkg/application/application_darwin_delegate.m
@@ -1,5 +1,5 @@
//go:build darwin
-#import "app_delegate.h"
+#import "application_darwin_delegate.h"
#import "../events/events.h"
extern bool hasListeners(unsigned int);
@implementation AppDelegate
diff --git a/v3/pkg/application/application_production.go b/v3/pkg/application/application_production.go
new file mode 100644
index 000000000..14be48cb7
--- /dev/null
+++ b/v3/pkg/application/application_production.go
@@ -0,0 +1,10 @@
+//go:build production
+
+package application
+
+// We use this to patch the application to production mode.
+func init() {
+ isDebugMode = func() bool {
+ return false
+ }
+}
diff --git a/v3/pkg/application/application_windows.go b/v3/pkg/application/application_windows.go
new file mode 100644
index 000000000..7a045007c
--- /dev/null
+++ b/v3/pkg/application/application_windows.go
@@ -0,0 +1,246 @@
+//go:build windows
+
+package application
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/wailsapp/wails/v3/pkg/events"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+
+ "github.com/samber/lo"
+)
+
+var windowClassName = lo.Must(syscall.UTF16PtrFromString("WailsWebviewWindow"))
+
+type windowsApp struct {
+ parent *App
+
+ instance w32.HINSTANCE
+
+ windowMap map[w32.HWND]*windowsWebviewWindow
+ systrayMap map[w32.HMENU]*windowsSystemTray
+
+ mainThreadID w32.HANDLE
+ mainThreadWindowHWND w32.HWND
+
+ // Windows hidden by application.Hide()
+ hiddenWindows []*windowsWebviewWindow
+ focusedWindow w32.HWND
+
+ // system theme
+ isDarkMode bool
+}
+
+func getNativeApplication() *windowsApp {
+ return globalApplication.impl.(*windowsApp)
+}
+
+func (m *windowsApp) getPrimaryScreen() (*Screen, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (m *windowsApp) getScreens() ([]*Screen, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (m *windowsApp) hide() {
+ // Get the current focussed window
+ m.focusedWindow = w32.GetForegroundWindow()
+
+ // Iterate over all windows and hide them if they aren't already hidden
+ for _, window := range m.windowMap {
+ if window.isVisible() {
+ // Add to hidden windows
+ m.hiddenWindows = append(m.hiddenWindows, window)
+ window.hide()
+ }
+ }
+ // Switch focus to the next application
+ hwndNext := w32.GetWindow(m.mainThreadWindowHWND, w32.GW_HWNDNEXT)
+ w32.SetForegroundWindow(hwndNext)
+}
+
+func (m *windowsApp) show() {
+ // Iterate over all windows and show them if they were previously hidden
+ for _, window := range m.hiddenWindows {
+ window.show()
+ }
+ // Show the foreground window
+ w32.SetForegroundWindow(m.focusedWindow)
+}
+
+func (m *windowsApp) on(eventID uint) {
+ //C.registerListener(C.uint(eventID))
+}
+
+func (m *windowsApp) setIcon(icon []byte) {
+ //C.setApplicationIcon(unsafe.Pointer(&icon[0]), C.int(len(icon)))
+}
+
+func (m *windowsApp) name() string {
+ //appName := C.getAppName()
+ //defer C.free(unsafe.Pointer(appName))
+ //return C.GoString(appName)
+ return ""
+}
+
+func (m *windowsApp) getCurrentWindowID() uint {
+ //return uint(C.getCurrentWindowID())
+ return uint(0)
+}
+
+func (m *windowsApp) setApplicationMenu(menu *Menu) {
+ if menu == nil {
+ // Create a default menu for windows
+ menu = defaultApplicationMenu()
+ }
+ menu.Update()
+
+ // Convert impl to macosMenu object
+ //m.applicationMenu = (menu.impl).(*macosMenu).nsMenu
+ //C.setApplicationMenu(m.applicationMenu)
+}
+
+func (m *windowsApp) run() error {
+ // Add a hook to the ApplicationDidFinishLaunching event
+ //m.parent.On(events.Mac.ApplicationDidFinishLaunching, func() {
+ // C.setApplicationShouldTerminateAfterLastWindowClosed(C.bool(m.parent.options.Mac.ApplicationShouldTerminateAfterLastWindowClosed))
+ // C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy))
+ // C.activateIgnoringOtherApps()
+ //})
+ // setup event listeners
+ for eventID := range m.parent.applicationEventListeners {
+ m.on(eventID)
+ }
+
+ _ = m.runMainLoop()
+
+ //C.run()
+ return nil
+}
+
+func (m *windowsApp) destroy() {
+ //C.destroyApp()
+}
+
+func (m *windowsApp) init() {
+ // Register the window class
+
+ icon := w32.LoadIconWithResourceID(m.instance, w32.IDI_APPLICATION)
+
+ var wc w32.WNDCLASSEX
+ wc.Size = uint32(unsafe.Sizeof(wc))
+ wc.Style = w32.CS_HREDRAW | w32.CS_VREDRAW
+ wc.WndProc = syscall.NewCallback(m.wndProc)
+ wc.Instance = m.instance
+ wc.Background = w32.COLOR_BTNFACE + 1
+ wc.Icon = icon
+ wc.Cursor = w32.LoadCursorWithResourceID(0, w32.IDC_ARROW)
+ wc.ClassName = windowClassName
+ wc.MenuName = nil
+ wc.IconSm = icon
+
+ if ret := w32.RegisterClassEx(&wc); ret == 0 {
+ panic(syscall.GetLastError())
+ }
+
+ m.isDarkMode = w32.IsCurrentlyDarkMode()
+}
+
+func (m *windowsApp) wndProc(hwnd w32.HWND, msg uint32, wParam, lParam uintptr) uintptr {
+
+ // Handle the invoke callback
+ if msg == wmInvokeCallback {
+ m.invokeCallback(wParam, lParam)
+ return 0
+ }
+
+ // If the WndProcInterceptor is set in options, pass the message on
+ if m.parent.options.Windows.WndProcInterceptor != nil {
+ returnValue, shouldReturn := m.parent.options.Windows.WndProcInterceptor(hwnd, msg, wParam, lParam)
+ if shouldReturn {
+ return returnValue
+ }
+ }
+
+ switch msg {
+ case w32.WM_SETTINGCHANGE:
+ settingChanged := w32.UTF16PtrToString((*uint16)(unsafe.Pointer(lParam)))
+ if settingChanged == "ImmersiveColorSet" {
+ isDarkMode := w32.IsCurrentlyDarkMode()
+ if isDarkMode != m.isDarkMode {
+ applicationEvents <- uint(events.Windows.SystemThemeChanged)
+ m.isDarkMode = isDarkMode
+ }
+ }
+ return 0
+ case w32.WM_POWERBROADCAST:
+ switch wParam {
+ case w32.PBT_APMPOWERSTATUSCHANGE:
+ applicationEvents <- uint(events.Windows.APMPowerStatusChange)
+ case w32.PBT_APMSUSPEND:
+ applicationEvents <- uint(events.Windows.APMSuspend)
+ case w32.PBT_APMRESUMEAUTOMATIC:
+ applicationEvents <- uint(events.Windows.APMResumeAutomatic)
+ case w32.PBT_APMRESUMESUSPEND:
+ applicationEvents <- uint(events.Windows.APMResumeSuspend)
+ case w32.PBT_POWERSETTINGCHANGE:
+ applicationEvents <- uint(events.Windows.APMPowerSettingChange)
+ }
+ return 0
+ }
+
+ if window, ok := m.windowMap[hwnd]; ok {
+ return window.WndProc(msg, wParam, lParam)
+ }
+
+ if systray, ok := m.systrayMap[hwnd]; ok {
+ return systray.wndProc(msg, wParam, lParam)
+ }
+
+ // Dispatch the message to the appropriate window
+
+ return w32.DefWindowProc(hwnd, msg, wParam, lParam)
+}
+
+func (m *windowsApp) registerWindow(result *windowsWebviewWindow) {
+ m.windowMap[result.hwnd] = result
+}
+
+func (m *windowsApp) registerSystemTray(result *windowsSystemTray) {
+ m.systrayMap[result.hwnd] = result
+}
+
+func (m *windowsApp) unregisterWindow(w *windowsWebviewWindow) {
+ delete(m.windowMap, w.hwnd)
+
+ // If this was the last window...
+ if len(m.windowMap) == 0 && !m.parent.options.Windows.DisableQuitOnLastWindowClosed {
+ w32.PostQuitMessage(0)
+ }
+}
+
+func newPlatformApp(app *App) *windowsApp {
+ err := w32.SetProcessDPIAware()
+ if err != nil {
+ println("Fatal error in application initialisation: ", err.Error())
+ os.Exit(1)
+ }
+
+ result := &windowsApp{
+ parent: app,
+ instance: w32.GetModuleHandle(""),
+ windowMap: make(map[w32.HWND]*windowsWebviewWindow),
+ systrayMap: make(map[w32.HWND]*windowsSystemTray),
+ }
+
+ result.init()
+ result.initMainLoop()
+
+ return result
+}
diff --git a/v3/pkg/application/clipboard.go b/v3/pkg/application/clipboard.go
index e823ace92..0217057ee 100644
--- a/v3/pkg/application/clipboard.go
+++ b/v3/pkg/application/clipboard.go
@@ -1,7 +1,5 @@
package application
-import "C"
-
type clipboardImpl interface {
setText(text string) bool
text() string
diff --git a/v3/pkg/application/clipboard_windows.go b/v3/pkg/application/clipboard_windows.go
new file mode 100644
index 000000000..483c51567
--- /dev/null
+++ b/v3/pkg/application/clipboard_windows.go
@@ -0,0 +1,28 @@
+//go:build windows
+
+package application
+
+type windowsClipboard struct{}
+
+func (m windowsClipboard) setText(text string) bool {
+ //clipboardLock.Lock()
+ //defer clipboardLock.Unlock()
+ //cText := C.CString(text)
+ //success := C.setClipboardText(cText)
+ //C.free(unsafe.Pointer(cText))
+ //return bool(success)
+ panic("implement me")
+}
+
+func (m windowsClipboard) text() string {
+ //clipboardLock.RLock()
+ //defer clipboardLock.RUnlock()
+ //clipboardText := C.getClipboardText()
+ //result := C.GoString(clipboardText)
+ //return result
+ panic("implement me")
+}
+
+func newClipboardImpl() *windowsClipboard {
+ return &windowsClipboard{}
+}
diff --git a/v3/pkg/application/dialogs.go b/v3/pkg/application/dialogs.go
index d7e8d6671..1b7d75e24 100644
--- a/v3/pkg/application/dialogs.go
+++ b/v3/pkg/application/dialogs.go
@@ -1,6 +1,5 @@
package application
-import "C"
import (
"strings"
"sync"
@@ -49,11 +48,22 @@ type Button struct {
Label string
IsCancel bool
IsDefault bool
- callback func()
+ Callback func()
}
-func (b *Button) OnClick(callback func()) {
- b.callback = callback
+func (b *Button) OnClick(callback func()) *Button {
+ b.Callback = callback
+ return b
+}
+
+func (b *Button) SetAsDefault() *Button {
+ b.IsDefault = true
+ return b
+}
+
+func (b *Button) SetAsCancel() *Button {
+ b.IsCancel = true
+ return b
}
type messageDialogImpl interface {
@@ -86,7 +96,6 @@ func newMessageDialog(dialogType DialogType) *MessageDialog {
return &MessageDialog{
MessageDialogOptions: MessageDialogOptions{
DialogType: dialogType,
- Title: defaultTitles[dialogType],
},
impl: nil,
}
@@ -101,7 +110,7 @@ func (d *MessageDialog) Show() {
if d.impl == nil {
d.impl = newDialogImpl(d)
}
- d.impl.show()
+ invokeSync(d.impl.show)
}
func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog {
@@ -249,7 +258,7 @@ func (d *OpenFileDialog) PromptForSingleSelection() (string, error) {
if d.impl == nil {
d.impl = newOpenFileDialogImpl(d)
}
- selection, err := d.impl.show()
+ selection, err := invokeSyncWithResultAndError(d.impl.show)
var result string
if len(selection) > 0 {
result = selection[0]
@@ -273,7 +282,7 @@ func (d *OpenFileDialog) PromptForMultipleSelection() ([]string, error) {
if d.impl == nil {
d.impl = newOpenFileDialogImpl(d)
}
- return d.impl.show()
+ return invokeSyncWithResultAndError(d.impl.show)
}
func (d *OpenFileDialog) SetMessage(message string) *OpenFileDialog {
@@ -338,10 +347,12 @@ type SaveFileDialogOptions struct {
AllowOtherFileTypes bool
HideExtension bool
TreatsFilePackagesAsDirectories bool
+ Title string
Message string
Directory string
Filename string
ButtonText string
+ Filters []FileFilter
}
type SaveFileDialog struct {
@@ -356,10 +367,12 @@ type SaveFileDialog struct {
directory string
filename string
buttonText string
+ filters []FileFilter
window *WebviewWindow
- impl saveFileDialogImpl
+ impl saveFileDialogImpl
+ title string
}
type saveFileDialogImpl interface {
@@ -367,6 +380,7 @@ type saveFileDialogImpl interface {
}
func (d *SaveFileDialog) SetOptions(options *SaveFileDialogOptions) {
+ d.title = options.Title
d.canCreateDirectories = options.CanCreateDirectories
d.showHiddenFiles = options.ShowHiddenFiles
d.canSelectHiddenExtension = options.CanSelectHiddenExtension
@@ -379,6 +393,16 @@ func (d *SaveFileDialog) SetOptions(options *SaveFileDialogOptions) {
d.buttonText = options.ButtonText
}
+// AddFilter adds a filter to the dialog. The filter is a display name and a semicolon separated list of extensions.
+// EG: AddFilter("Image Files", "*.jpg;*.png")
+func (d *SaveFileDialog) AddFilter(displayName, pattern string) *SaveFileDialog {
+ d.filters = append(d.filters, FileFilter{
+ DisplayName: strings.TrimSpace(displayName),
+ Pattern: strings.TrimSpace(pattern),
+ })
+ return d
+}
+
func (d *SaveFileDialog) CanCreateDirectories(canCreateDirectories bool) *SaveFileDialog {
d.canCreateDirectories = canCreateDirectories
return d
@@ -413,7 +437,7 @@ func (d *SaveFileDialog) PromptForSingleSelection() (string, error) {
if d.impl == nil {
d.impl = newSaveFileDialogImpl(d)
}
- return d.impl.show()
+ return invokeSyncWithResultAndError(d.impl.show)
}
func (d *SaveFileDialog) SetButtonText(text string) *SaveFileDialog {
diff --git a/v3/pkg/application/dialogs_darwin.go b/v3/pkg/application/dialogs_darwin.go
index ca27e7da6..860697c52 100644
--- a/v3/pkg/application/dialogs_darwin.go
+++ b/v3/pkg/application/dialogs_darwin.go
@@ -9,7 +9,7 @@ package application
#import
#import
-#import "dialogs_delegate.h"
+#import "dialogs_darwin_delegate.h"
extern void openFileDialogCallback(uint id, char* path);
extern void openFileDialogCallbackEnd(uint id);
@@ -364,8 +364,8 @@ func (m *macosDialog) show() {
buttonPressed := int(C.dialogRunModal(m.nsDialog))
if len(m.dialog.Buttons) > buttonPressed {
button := reversedButtons[buttonPressed]
- if button.callback != nil {
- button.callback()
+ if button.Callback != nil {
+ button.Callback()
}
}
})
diff --git a/v3/pkg/application/dialogs_delegate.h b/v3/pkg/application/dialogs_darwin_delegate.h
similarity index 100%
rename from v3/pkg/application/dialogs_delegate.h
rename to v3/pkg/application/dialogs_darwin_delegate.h
diff --git a/v3/pkg/application/dialogs_delegate.m b/v3/pkg/application/dialogs_darwin_delegate.m
similarity index 95%
rename from v3/pkg/application/dialogs_delegate.m
rename to v3/pkg/application/dialogs_darwin_delegate.m
index 67f34e2eb..5cbd46a2b 100644
--- a/v3/pkg/application/dialogs_delegate.m
+++ b/v3/pkg/application/dialogs_darwin_delegate.m
@@ -1,6 +1,6 @@
//go:build darwin
-#import "dialogs_delegate.h"
+#import "dialogs_darwin_delegate.h"
// Override shouldEnableURL
@implementation OpenPanelDelegate
diff --git a/v3/pkg/application/dialogs_windows.go b/v3/pkg/application/dialogs_windows.go
new file mode 100644
index 000000000..713917cc2
--- /dev/null
+++ b/v3/pkg/application/dialogs_windows.go
@@ -0,0 +1,192 @@
+//go:build windows
+
+package application
+
+import (
+ "github.com/wailsapp/wails/v3/internal/go-common-file-dialog/cfd"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+ "golang.org/x/sys/windows"
+ "path/filepath"
+ "strings"
+)
+
+func (m *windowsApp) showAboutDialog(title string, message string, icon []byte) {
+ panic("implement me")
+}
+
+type windowsDialog struct {
+ dialog *MessageDialog
+
+ //dialogImpl unsafe.Pointer
+}
+
+func (m *windowsDialog) show() {
+
+ title := w32.MustStringToUTF16Ptr(m.dialog.Title)
+ message := w32.MustStringToUTF16Ptr(m.dialog.Message)
+ flags := calculateMessageDialogFlags(m.dialog.MessageDialogOptions)
+
+ button, _ := windows.MessageBox(windows.HWND(0), message, title, flags|windows.MB_SYSTEMMODAL)
+ // This maps MessageBox return values to strings
+ responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"}
+ result := "Error"
+ if int(button) < len(responses) {
+ result = responses[button]
+ }
+ // Check if there's a callback for the button pressed
+ for _, button := range m.dialog.Buttons {
+ if button.Label == result {
+ if button.Callback != nil {
+ button.Callback()
+ }
+ }
+ }
+}
+
+func newDialogImpl(d *MessageDialog) *windowsDialog {
+ return &windowsDialog{
+ dialog: d,
+ }
+}
+
+type windowOpenFileDialog struct {
+ dialog *OpenFileDialog
+}
+
+func newOpenFileDialogImpl(d *OpenFileDialog) *windowOpenFileDialog {
+ return &windowOpenFileDialog{
+ dialog: d,
+ }
+}
+
+func getDefaultFolder(folder string) (string, error) {
+ if folder == "" {
+ return "", nil
+ }
+ return filepath.Abs(folder)
+}
+
+func (m *windowOpenFileDialog) show() ([]string, error) {
+
+ defaultFolder, err := getDefaultFolder(m.dialog.directory)
+ if err != nil {
+ return nil, err
+ }
+
+ config := cfd.DialogConfig{
+ Title: m.dialog.title,
+ Role: "PickFolder",
+ FileFilters: convertFilters(m.dialog.filters),
+ Folder: defaultFolder,
+ }
+
+ if m.dialog.window != nil {
+ config.ParentWindowHandle, err = m.dialog.window.NativeWindowHandle()
+ if err != nil {
+ w32.Fatal(err.Error())
+ }
+ }
+
+ var result []string
+ if m.dialog.allowsMultipleSelection {
+ temp, err := showCfdDialog(
+ func() (cfd.Dialog, error) {
+ return cfd.NewOpenMultipleFilesDialog(config)
+ }, true)
+ if err != nil {
+ return nil, err
+ }
+ result = temp.([]string)
+ } else {
+ temp, err := showCfdDialog(
+ func() (cfd.Dialog, error) {
+ return cfd.NewOpenFileDialog(config)
+ }, false)
+ if err != nil {
+ return nil, err
+ }
+ result = []string{temp.(string)}
+ }
+
+ return result, nil
+}
+
+type windowSaveFileDialog struct {
+ dialog *SaveFileDialog
+}
+
+func newSaveFileDialogImpl(d *SaveFileDialog) *windowSaveFileDialog {
+ return &windowSaveFileDialog{
+ dialog: d,
+ }
+}
+
+func (m *windowSaveFileDialog) show() (string, error) {
+ defaultFolder, err := getDefaultFolder(m.dialog.directory)
+ if err != nil {
+ return "", err
+ }
+
+ config := cfd.DialogConfig{
+ Title: m.dialog.title,
+ Role: "SaveFile",
+ FileFilters: convertFilters(m.dialog.filters),
+ FileName: m.dialog.filename,
+ Folder: defaultFolder,
+ }
+
+ result, err := showCfdDialog(
+ func() (cfd.Dialog, error) {
+ return cfd.NewSaveFileDialog(config)
+ }, false)
+ return result.(string), nil
+}
+
+func calculateMessageDialogFlags(options MessageDialogOptions) uint32 {
+ var flags uint32
+
+ switch options.DialogType {
+ case InfoDialog:
+ flags = windows.MB_OK | windows.MB_ICONINFORMATION
+ case ErrorDialog:
+ flags = windows.MB_ICONERROR | windows.MB_OK
+ case QuestionDialog:
+ flags = windows.MB_YESNO
+ for _, button := range options.Buttons {
+ if strings.TrimSpace(strings.ToLower(button.Label)) == "no" && button.IsDefault {
+ flags |= windows.MB_DEFBUTTON2
+ }
+ }
+ case WarningDialog:
+ flags = windows.MB_OK | windows.MB_ICONWARNING
+ }
+
+ return flags
+}
+
+func convertFilters(filters []FileFilter) []cfd.FileFilter {
+ var result []cfd.FileFilter
+ for _, filter := range filters {
+ result = append(result, cfd.FileFilter(filter))
+ }
+ return result
+}
+
+func showCfdDialog(newDlg func() (cfd.Dialog, error), isMultiSelect bool) (any, error) {
+ dlg, err := newDlg()
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ err := dlg.Release()
+ if err != nil {
+ println("ERROR: Unable to release dialog:", err.Error())
+ }
+ }()
+
+ dlg.SetParentWindowHandle(0)
+ if multi, _ := dlg.(cfd.OpenMultipleFilesDialog); multi != nil && isMultiSelect {
+ return multi.ShowAndGetResults()
+ }
+ return dlg.ShowAndGetResult()
+}
diff --git a/v3/pkg/application/events.go b/v3/pkg/application/events.go
index 41ac872ff..3006e8714 100644
--- a/v3/pkg/application/events.go
+++ b/v3/pkg/application/events.go
@@ -24,6 +24,8 @@ type WailsEvent struct {
Sender string `json:"sender"`
}
+var commonEvents = make(chan uint)
+
func (e WailsEvent) ToJSON() string {
marshal, err := json.Marshal(&e)
if err != nil {
diff --git a/v3/pkg/application/events_common_darwin.go b/v3/pkg/application/events_common_darwin.go
new file mode 100644
index 000000000..0a9eb1af7
--- /dev/null
+++ b/v3/pkg/application/events_common_darwin.go
@@ -0,0 +1,17 @@
+//go:build darwin
+
+package application
+
+import "github.com/wailsapp/wails/v3/pkg/events"
+
+var commonApplicationEventMap = map[events.ApplicationEventType]events.ApplicationEventType{
+ events.Mac.ApplicationDidFinishLaunching: events.Common.ApplicationStarted,
+}
+
+func (m *macosApp) setupCommonEvents() {
+ for sourceEvent, targetEvent := range commonApplicationEventMap {
+ m.parent.On(sourceEvent, func() {
+ applicationEvents <- uint(targetEvent)
+ })
+ }
+}
diff --git a/v3/pkg/application/icons.go b/v3/pkg/application/icons.go
deleted file mode 100644
index 13ef1f389..000000000
--- a/v3/pkg/application/icons.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package application
-
-var DefaultApplicationIcon = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 64, 0, 0, 0, 64, 8, 3, 0, 0, 0, 157, 183, 129, 236, 0, 0, 1, 2, 80, 76, 84, 69, 0, 0, 0, 255, 255, 255, 20, 20, 20, 14, 14, 14, 255, 255, 255, 9, 9, 9, 103, 103, 103, 255, 255, 255, 255, 255, 255, 185, 185, 185, 255, 255, 255, 16, 16, 16, 27, 27, 27, 2, 2, 2, 23, 23, 23, 62, 62, 62, 105, 105, 105, 12, 12, 12, 21, 21, 21, 36, 36, 36, 41, 41, 41, 51, 51, 51, 55, 55, 55, 78, 78, 78, 146, 146, 146, 226, 226, 226, 0, 0, 0, 225, 225, 225, 79, 79, 79, 17, 17, 17, 76, 76, 76, 221, 221, 221, 101, 101, 101, 64, 64, 64, 223, 223, 223, 217, 217, 217, 133, 133, 133, 104, 104, 104, 94, 94, 94, 6, 6, 6, 202, 202, 202, 198, 198, 198, 110, 110, 110, 97, 97, 97, 70, 70, 70, 55, 55, 55, 13, 13, 13, 211, 211, 211, 188, 188, 188, 176, 176, 176, 117, 117, 117, 91, 91, 91, 73, 73, 73, 34, 35, 34, 27, 27, 27, 21, 21, 21, 173, 173, 173, 166, 166, 166, 161, 162, 162, 150, 150, 150, 142, 143, 143, 136, 136, 136, 119, 119, 119, 90, 90, 90, 87, 87, 87, 50, 50, 50, 44, 44, 45, 41, 41, 41, 32, 32, 32, 4, 4, 4, 214, 214, 214, 178, 178, 178, 158, 158, 158, 153, 153, 153, 148, 148, 148, 123, 123, 123, 82, 82, 82, 67, 67, 67, 66, 66, 66, 208, 208, 208, 192, 192, 192, 190, 190, 190, 184, 184, 184, 127, 127, 127, 126, 126, 126, 60, 60, 61, 204, 47, 21, 237, 0, 0, 0, 26, 116, 82, 78, 83, 0, 12, 195, 213, 16, 227, 64, 19, 14, 29, 9, 198, 164, 248, 176, 96, 59, 213, 184, 145, 130, 110, 106, 78, 37, 20, 109, 186, 18, 188, 0, 0, 2, 46, 73, 68, 65, 84, 88, 195, 237, 150, 123, 83, 26, 49, 20, 197, 89, 107, 91, 10, 84, 251, 126, 220, 128, 91, 150, 151, 96, 65, 64, 121, 169, 80, 68, 169, 90, 31, 125, 233, 247, 255, 42, 206, 238, 222, 51, 73, 112, 38, 201, 50, 227, 140, 227, 120, 254, 217, 61, 155, 156, 223, 228, 113, 179, 147, 212, 147, 30, 153, 50, 158, 187, 50, 119, 227, 95, 63, 174, 173, 184, 43, 247, 217, 91, 200, 191, 202, 82, 50, 189, 79, 235, 195, 207, 81, 82, 173, 235, 3, 120, 157, 24, 176, 162, 77, 226, 13, 37, 214, 243, 85, 21, 240, 98, 9, 192, 203, 251, 1, 52, 243, 172, 89, 232, 10, 108, 250, 161, 233, 161, 169, 104, 2, 236, 11, 214, 255, 208, 109, 177, 201, 135, 230, 0, 77, 101, 3, 64, 246, 234, 134, 110, 196, 102, 35, 52, 155, 104, 106, 154, 0, 101, 244, 170, 132, 51, 240, 21, 192, 17, 90, 234, 100, 2, 156, 163, 91, 149, 136, 242, 66, 1, 124, 131, 153, 24, 1, 93, 116, 155, 98, 65, 0, 216, 131, 57, 50, 2, 26, 74, 166, 246, 19, 102, 87, 49, 109, 50, 1, 228, 64, 139, 68, 69, 161, 0, 154, 120, 111, 152, 1, 59, 202, 82, 151, 37, 64, 206, 45, 232, 155, 1, 23, 200, 204, 148, 125, 19, 223, 137, 78, 248, 117, 72, 102, 192, 6, 50, 61, 58, 20, 10, 160, 16, 96, 119, 44, 128, 75, 100, 250, 52, 81, 1, 0, 251, 3, 11, 224, 6, 153, 22, 181, 85, 192, 152, 223, 246, 200, 2, 192, 184, 131, 121, 47, 122, 198, 235, 112, 73, 117, 254, 126, 97, 3, 160, 96, 75, 84, 137, 158, 241, 78, 92, 29, 227, 115, 203, 6, 64, 207, 109, 26, 70, 3, 248, 17, 23, 69, 149, 63, 255, 34, 27, 160, 143, 19, 51, 240, 163, 1, 48, 224, 12, 139, 97, 5, 20, 80, 176, 211, 56, 25, 3, 174, 182, 121, 92, 53, 43, 160, 197, 251, 221, 57, 141, 2, 243, 184, 50, 113, 66, 198, 100, 5, 212, 124, 6, 148, 226, 41, 199, 128, 33, 234, 219, 14, 160, 18, 23, 12, 31, 201, 170, 226, 68, 125, 238, 0, 248, 45, 164, 74, 45, 6, 176, 206, 201, 14, 224, 138, 65, 217, 233, 128, 153, 11, 224, 143, 18, 216, 225, 255, 50, 235, 47, 185, 0, 254, 201, 64, 48, 208, 1, 13, 39, 64, 71, 6, 58, 164, 1, 130, 99, 39, 192, 72, 38, 42, 252, 139, 99, 157, 144, 19, 224, 84, 38, 122, 58, 96, 203, 13, 176, 47, 160, 54, 105, 0, 127, 224, 6, 56, 16, 208, 68, 7, 140, 200, 13, 48, 22, 208, 161, 14, 152, 58, 2, 174, 17, 216, 140, 108, 69, 86, 165, 35, 160, 139, 68, 89, 7, 156, 145, 35, 160, 129, 68, 81, 7, 236, 186, 2, 106, 5, 214, 162, 189, 11, 120, 88, 151, 172, 229, 239, 137, 203, 223, 84, 179, 158, 10, 240, 214, 18, 3, 62, 165, 52, 125, 121, 155, 48, 159, 75, 47, 222, 247, 63, 100, 159, 185, 235, 221, 58, 231, 85, 121, 233, 85, 87, 165, 51, 169, 39, 61, 36, 221, 2, 115, 72, 10, 51, 166, 156, 57, 80, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
-var DefaultMacTemplateIcon = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 64, 0, 0, 0, 64, 8, 3, 0, 0, 0, 157, 183, 129, 236, 0, 0, 0, 135, 80, 76, 84, 69, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 106, 145, 255, 17, 0, 0, 0, 45, 116, 82, 78, 83, 0, 225, 11, 16, 14, 7, 26, 18, 79, 65, 23, 221, 100, 91, 176, 74, 217, 118, 95, 34, 20, 211, 201, 133, 104, 69, 149, 110, 53, 189, 167, 161, 125, 86, 76, 45, 198, 154, 143, 136, 57, 41, 185, 203, 192, 69, 76, 133, 225, 0, 0, 1, 243, 73, 68, 65, 84, 88, 195, 237, 214, 109, 111, 130, 48, 16, 7, 240, 107, 41, 34, 48, 31, 65, 116, 62, 59, 231, 220, 220, 190, 255, 231, 155, 216, 187, 28, 213, 164, 61, 98, 150, 152, 197, 255, 27, 57, 219, 254, 44, 133, 34, 240, 204, 63, 139, 110, 145, 248, 118, 120, 146, 69, 70, 158, 40, 211, 224, 166, 212, 208, 46, 165, 113, 167, 159, 64, 219, 100, 158, 74, 20, 227, 204, 185, 211, 30, 136, 163, 123, 129, 228, 111, 128, 101, 23, 179, 175, 171, 8, 139, 75, 115, 65, 77, 169, 15, 152, 43, 204, 182, 174, 198, 88, 116, 235, 226, 131, 154, 166, 30, 128, 123, 141, 234, 106, 141, 197, 91, 93, 124, 83, 211, 210, 7, 76, 169, 215, 172, 62, 131, 188, 1, 124, 81, 203, 187, 119, 13, 182, 212, 109, 124, 46, 186, 84, 12, 206, 197, 11, 207, 205, 7, 140, 168, 219, 142, 22, 132, 128, 13, 21, 95, 94, 96, 161, 120, 214, 241, 164, 1, 196, 67, 60, 62, 121, 47, 35, 79, 52, 5, 72, 85, 3, 248, 164, 227, 133, 31, 232, 53, 150, 122, 202, 64, 227, 220, 58, 126, 96, 71, 253, 246, 0, 149, 162, 188, 2, 244, 241, 176, 15, 126, 96, 64, 99, 10, 216, 43, 6, 248, 138, 142, 3, 64, 202, 51, 29, 53, 1, 130, 243, 210, 15, 240, 90, 25, 88, 53, 129, 35, 30, 109, 130, 155, 137, 198, 64, 113, 249, 168, 16, 120, 167, 93, 225, 7, 248, 134, 29, 194, 204, 110, 28, 123, 77, 11, 250, 90, 135, 0, 234, 57, 177, 203, 94, 245, 44, 64, 87, 119, 14, 33, 160, 67, 59, 166, 204, 47, 19, 64, 224, 64, 139, 17, 4, 18, 236, 185, 218, 217, 145, 8, 76, 112, 94, 113, 16, 208, 116, 191, 28, 236, 0, 11, 208, 14, 57, 66, 16, 136, 115, 4, 134, 246, 148, 45, 64, 15, 150, 207, 48, 0, 184, 233, 172, 243, 134, 0, 170, 21, 8, 128, 137, 226, 12, 13, 62, 21, 49, 91, 9, 80, 41, 206, 6, 92, 96, 47, 1, 126, 20, 167, 231, 2, 43, 144, 0, 39, 30, 144, 103, 46, 176, 16, 1, 125, 30, 208, 199, 39, 20, 165, 16, 1, 107, 30, 48, 35, 128, 60, 17, 176, 105, 252, 162, 11, 188, 200, 128, 185, 187, 102, 12, 228, 153, 12, 248, 80, 148, 145, 11, 172, 65, 6, 28, 21, 101, 233, 2, 187, 48, 192, 255, 109, 124, 223, 206, 248, 174, 148, 1, 252, 40, 157, 186, 192, 1, 132, 192, 130, 70, 164, 46, 48, 144, 2, 113, 132, 185, 46, 111, 129, 199, 122, 201, 202, 238, 124, 79, 188, 255, 77, 85, 71, 173, 129, 236, 206, 183, 245, 196, 192, 149, 80, 26, 45, 143, 201, 204, 237, 162, 104, 19, 73, 99, 52, 60, 243, 72, 249, 5, 251, 207, 25, 192, 218, 106, 27, 249, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
-var WailsLogoBlack = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 128, 0, 0, 0, 128, 8, 3, 0, 0, 0, 244, 224, 145, 249, 0, 0, 3, 0, 80, 76, 84, 69, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 254, 254, 254, 8, 1, 1, 227, 49, 49, 255, 255, 255, 5, 5, 5, 0, 0, 0, 6, 1, 1, 203, 44, 44, 227, 50, 50, 35, 6, 6, 160, 22, 29, 244, 53, 53, 150, 17, 26, 234, 51, 51, 36, 6, 6, 7, 1, 1, 59, 10, 12, 255, 255, 255, 6, 5, 5, 13, 2, 2, 23, 4, 4, 212, 212, 212, 15, 2, 2, 234, 51, 51, 188, 35, 38, 171, 27, 33, 78, 17, 17, 240, 52, 52, 231, 231, 231, 51, 8, 10, 26, 26, 26, 76, 76, 76, 163, 163, 163, 171, 30, 34, 218, 42, 45, 210, 42, 44, 214, 45, 46, 23, 23, 23, 13, 13, 13, 195, 41, 42, 225, 49, 49, 135, 25, 28, 42, 7, 8, 66, 13, 14, 148, 29, 31, 111, 23, 23, 154, 154, 154, 225, 48, 48, 204, 39, 42, 198, 38, 41, 146, 28, 30, 131, 12, 21, 105, 17, 20, 186, 35, 38, 139, 139, 139, 88, 12, 16, 48, 7, 9, 186, 30, 36, 5, 5, 5, 219, 47, 47, 183, 31, 36, 35, 35, 35, 247, 246, 246, 209, 44, 45, 253, 252, 252, 116, 116, 116, 118, 23, 24, 11, 2, 2, 77, 14, 15, 126, 23, 25, 33, 5, 6, 253, 55, 55, 128, 5, 17, 55, 9, 10, 242, 242, 242, 145, 15, 24, 27, 4, 5, 238, 238, 238, 225, 225, 225, 179, 29, 35, 179, 179, 179, 20, 3, 3, 171, 34, 36, 40, 40, 40, 166, 33, 35, 89, 18, 18, 235, 235, 235, 207, 207, 207, 93, 93, 93, 43, 8, 9, 53, 8, 10, 230, 46, 48, 196, 33, 38, 115, 4, 16, 194, 194, 194, 60, 60, 60, 140, 18, 25, 170, 170, 170, 103, 103, 103, 160, 34, 34, 99, 20, 21, 135, 28, 29, 72, 14, 15, 146, 146, 146, 148, 30, 31, 206, 36, 40, 12, 12, 12, 64, 10, 12, 22, 3, 4, 191, 34, 38, 163, 23, 30, 163, 30, 33, 72, 11, 13, 217, 47, 47, 47, 47, 47, 153, 22, 28, 216, 216, 216, 156, 28, 32, 221, 221, 221, 51, 51, 51, 96, 17, 19, 178, 36, 38, 104, 17, 20, 38, 4, 6, 141, 26, 29, 222, 47, 48, 68, 68, 68, 131, 131, 131, 87, 87, 87, 114, 13, 19, 202, 202, 202, 24, 3, 4, 229, 229, 229, 189, 189, 189, 148, 148, 148, 91, 8, 15, 100, 17, 20, 125, 10, 19, 203, 40, 43, 145, 20, 27, 62, 62, 62, 191, 39, 41, 104, 20, 22, 194, 194, 194, 173, 173, 173, 85, 15, 17, 203, 203, 203, 206, 19, 21, 198, 198, 198, 159, 159, 159, 163, 24, 30, 126, 126, 126, 212, 44, 45, 108, 108, 108, 248, 248, 248, 134, 25, 27, 129, 23, 26, 141, 26, 29, 186, 116, 121, 64, 8, 12, 99, 16, 19, 250, 234, 235, 227, 80, 80, 227, 201, 204, 224, 103, 104, 35, 35, 35, 243, 187, 187, 163, 73, 80, 114, 114, 114, 183, 183, 183, 10, 0, 1, 255, 238, 238, 146, 40, 50, 212, 71, 73, 230, 148, 149, 0, 0, 0, 203, 53, 56, 86, 14, 17, 0, 0, 0, 227, 50, 50, 255, 255, 255, 5, 1, 1, 224, 48, 49, 216, 45, 46, 221, 47, 48, 218, 46, 47, 214, 44, 46, 210, 43, 45, 4, 4, 4, 2, 2, 2, 205, 41, 43, 225, 49, 49, 194, 36, 40, 212, 44, 45, 222, 48, 48, 184, 32, 36, 209, 42, 44, 219, 47, 47, 198, 37, 41, 177, 29, 34, 188, 34, 38, 192, 35, 39, 202, 39, 42, 204, 40, 42, 200, 39, 41, 251, 251, 251, 187, 33, 37, 180, 30, 35, 172, 27, 33, 182, 31, 36, 218, 48, 48, 247, 54, 54, 236, 51, 52, 229, 50, 50, 207, 41, 43, 190, 34, 38, 175, 28, 33, 129, 8, 19, 8, 8, 8, 196, 36, 40, 169, 25, 31, 245, 245, 245, 154, 34, 34, 164, 24, 30, 154, 19, 27, 133, 9, 20, 231, 50, 50, 167, 24, 31, 135, 11, 21, 120, 5, 17, 240, 52, 52, 125, 7, 18, 170, 26, 32, 141, 14, 23, 137, 12, 22, 214, 41, 44, 157, 20, 28, 145, 15, 24, 190, 31, 37, 211, 42, 44, 223, 43, 46, 203, 36, 40, 148, 31, 32, 173, 26, 32, 162, 22, 29, 199, 35, 40, 220, 43, 46, 210, 37, 40, 183, 27, 34, 153, 33, 33, 124, 0, 8, 252, 54, 55, 29, 193, 86, 184, 0, 0, 0, 182, 116, 82, 78, 83, 254, 251, 225, 249, 254, 254, 254, 249, 244, 246, 247, 245, 249, 248, 254, 254, 254, 254, 241, 251, 241, 246, 246, 246, 241, 239, 252, 250, 247, 247, 247, 251, 247, 243, 242, 241, 235, 230, 254, 250, 249, 248, 246, 244, 243, 242, 242, 241, 240, 240, 237, 252, 250, 247, 245, 244, 243, 241, 240, 233, 252, 251, 250, 249, 248, 248, 247, 245, 244, 243, 242, 242, 241, 239, 230, 251, 250, 249, 248, 247, 246, 245, 245, 245, 244, 244, 243, 242, 242, 242, 239, 237, 235, 235, 233, 254, 251, 251, 245, 245, 244, 243, 242, 240, 238, 236, 236, 235, 234, 253, 253, 252, 249, 248, 248, 246, 246, 245, 245, 245, 243, 243, 242, 240, 240, 239, 254, 254, 253, 250, 247, 246, 242, 241, 238, 234, 231, 231, 249, 249, 248, 248, 241, 239, 236, 235, 235, 234, 230, 226, 253, 252, 247, 246, 239, 236, 236, 235, 234, 229, 224, 220, 234, 224, 223, 246, 246, 243, 240, 239, 234, 234, 224, 223, 211, 248, 247, 244, 239, 229, 215, 214, 81, 124, 11, 18, 0, 0, 15, 238, 73, 68, 65, 84, 120, 218, 236, 152, 107, 72, 83, 97, 24, 199, 223, 211, 216, 106, 43, 117, 46, 73, 209, 173, 240, 131, 115, 160, 203, 162, 108, 134, 137, 146, 161, 89, 138, 129, 40, 245, 65, 81, 8, 180, 40, 74, 51, 36, 232, 250, 33, 250, 208, 141, 130, 8, 34, 232, 126, 161, 160, 123, 59, 109, 78, 151, 59, 187, 232, 212, 57, 156, 171, 188, 49, 97, 115, 154, 121, 77, 69, 187, 16, 61, 239, 57, 59, 30, 187, 88, 218, 205, 47, 253, 81, 16, 207, 129, 255, 239, 125, 222, 231, 242, 190, 7, 205, 81, 19, 234, 217, 212, 127, 128, 255, 0, 255, 1, 254, 3, 252, 7, 248, 71, 0, 104, 118, 1, 16, 31, 126, 103, 17, 64, 163, 81, 7, 75, 166, 66, 248, 251, 0, 176, 124, 34, 102, 7, 0, 168, 103, 7, 0, 150, 191, 104, 91, 244, 226, 41, 2, 240, 215, 1, 144, 6, 150, 31, 181, 49, 5, 169, 53, 234, 217, 0, 128, 85, 103, 239, 8, 123, 185, 143, 167, 230, 171, 103, 1, 0, 85, 169, 137, 245, 201, 1, 61, 81, 217, 106, 62, 154, 5, 0, 240, 12, 137, 8, 120, 229, 77, 140, 81, 107, 102, 167, 15, 8, 139, 162, 95, 82, 100, 216, 114, 2, 88, 254, 53, 0, 68, 31, 73, 14, 108, 12, 52, 147, 175, 10, 133, 120, 3, 48, 67, 213, 191, 2, 64, 8, 220, 68, 203, 23, 188, 212, 106, 201, 87, 243, 179, 185, 4, 252, 123, 0, 8, 49, 63, 85, 88, 154, 42, 88, 126, 208, 153, 141, 222, 26, 146, 244, 42, 194, 241, 83, 2, 17, 66, 132, 178, 119, 31, 202, 205, 221, 13, 239, 253, 62, 0, 226, 60, 17, 237, 249, 21, 76, 112, 90, 216, 75, 221, 10, 146, 36, 155, 183, 137, 114, 243, 50, 182, 159, 59, 158, 178, 163, 108, 79, 68, 97, 218, 245, 188, 96, 244, 7, 34, 128, 144, 70, 163, 249, 42, 232, 4, 15, 241, 230, 45, 12, 61, 22, 114, 72, 146, 23, 127, 102, 99, 243, 11, 18, 251, 39, 151, 149, 100, 37, 189, 29, 29, 144, 239, 148, 238, 75, 217, 181, 155, 248, 115, 91, 128, 64, 60, 33, 18, 166, 134, 134, 30, 243, 59, 148, 23, 180, 107, 125, 252, 241, 19, 105, 39, 79, 158, 206, 28, 186, 112, 113, 73, 143, 121, 5, 246, 23, 40, 100, 181, 111, 223, 214, 39, 200, 148, 251, 195, 131, 121, 4, 194, 131, 1, 253, 9, 0, 209, 134, 9, 207, 163, 5, 5, 42, 85, 103, 102, 230, 144, 88, 236, 1, 13, 122, 196, 171, 19, 189, 100, 13, 137, 69, 81, 249, 31, 19, 100, 167, 227, 130, 66, 132, 216, 67, 195, 231, 220, 127, 19, 96, 81, 124, 122, 65, 122, 122, 123, 123, 39, 86, 183, 79, 253, 253, 253, 125, 125, 253, 251, 78, 45, 32, 205, 102, 198, 63, 240, 212, 233, 184, 24, 63, 17, 161, 198, 238, 26, 244, 39, 199, 241, 238, 130, 55, 5, 175, 105, 189, 121, 243, 6, 147, 116, 131, 121, 223, 80, 95, 230, 234, 196, 102, 202, 76, 9, 40, 240, 215, 6, 22, 30, 19, 17, 104, 10, 243, 223, 173, 130, 77, 39, 95, 23, 48, 246, 237, 96, 15, 254, 24, 160, 255, 194, 41, 1, 44, 95, 75, 81, 20, 246, 143, 74, 85, 131, 176, 249, 95, 232, 3, 40, 60, 29, 251, 115, 0, 96, 159, 185, 250, 8, 105, 214, 105, 181, 0, 32, 32, 169, 230, 232, 60, 110, 233, 127, 161, 17, 17, 165, 221, 92, 0, 112, 4, 186, 47, 36, 11, 180, 58, 179, 150, 6, 32, 5, 100, 216, 89, 110, 4, 252, 149, 78, 184, 240, 120, 39, 11, 0, 9, 216, 9, 203, 167, 106, 106, 124, 0, 2, 129, 246, 213, 14, 33, 156, 65, 126, 21, 224, 167, 232, 56, 178, 217, 71, 59, 95, 183, 99, 125, 250, 212, 174, 186, 144, 76, 213, 84, 232, 116, 58, 179, 153, 142, 128, 182, 71, 26, 12, 254, 51, 7, 64, 124, 62, 193, 19, 206, 35, 112, 251, 6, 253, 120, 19, 36, 39, 219, 95, 127, 250, 244, 41, 253, 193, 213, 171, 79, 228, 84, 57, 172, 31, 0, 24, 127, 60, 2, 52, 232, 87, 0, 54, 169, 182, 166, 93, 186, 124, 244, 224, 193, 184, 179, 215, 175, 199, 239, 42, 45, 141, 217, 126, 45, 239, 208, 33, 63, 137, 100, 195, 177, 208, 208, 80, 209, 162, 212, 121, 72, 13, 112, 60, 30, 82, 19, 185, 233, 111, 148, 119, 175, 222, 90, 119, 231, 230, 200, 139, 242, 138, 10, 6, 0, 139, 92, 80, 132, 112, 6, 254, 194, 22, 160, 12, 255, 177, 241, 142, 177, 177, 177, 218, 90, 199, 199, 143, 31, 45, 9, 9, 197, 197, 197, 78, 75, 130, 116, 245, 153, 51, 189, 189, 178, 156, 136, 136, 136, 195, 135, 15, 43, 183, 93, 186, 28, 119, 240, 68, 220, 221, 91, 55, 230, 62, 187, 127, 251, 252, 7, 5, 248, 87, 112, 17, 104, 142, 141, 11, 23, 209, 37, 56, 243, 28, 64, 126, 153, 227, 98, 104, 169, 131, 254, 32, 183, 187, 171, 163, 183, 169, 13, 96, 156, 150, 186, 214, 122, 151, 235, 221, 104, 67, 203, 240, 192, 192, 128, 252, 253, 251, 145, 17, 106, 228, 230, 141, 103, 107, 31, 37, 159, 127, 145, 88, 201, 1, 128, 200, 72, 177, 71, 166, 138, 73, 5, 123, 254, 47, 148, 225, 26, 79, 151, 103, 124, 124, 220, 221, 213, 213, 1, 238, 77, 109, 224, 95, 235, 112, 56, 19, 18, 156, 22, 139, 165, 14, 4, 40, 245, 70, 163, 203, 101, 181, 157, 127, 120, 7, 150, 159, 88, 89, 89, 14, 0, 19, 57, 72, 30, 41, 233, 22, 123, 198, 146, 246, 109, 145, 16, 184, 13, 206, 16, 0, 8, 6, 59, 60, 254, 227, 110, 32, 96, 0, 176, 63, 152, 55, 54, 214, 181, 50, 214, 86, 171, 221, 214, 208, 96, 48, 24, 244, 45, 59, 63, 84, 42, 76, 12, 0, 36, 33, 179, 3, 130, 172, 118, 177, 103, 208, 191, 203, 146, 159, 149, 178, 148, 7, 81, 208, 160, 153, 1, 32, 76, 224, 198, 225, 159, 12, 192, 16, 176, 0, 118, 155, 13, 8, 90, 244, 38, 147, 105, 216, 4, 254, 44, 0, 16, 144, 177, 233, 125, 98, 241, 160, 187, 183, 169, 214, 245, 33, 118, 85, 204, 34, 64, 224, 207, 100, 22, 32, 32, 240, 239, 29, 252, 14, 64, 29, 7, 0, 254, 24, 160, 90, 175, 215, 211, 1, 96, 139, 192, 12, 9, 160, 234, 28, 26, 242, 248, 187, 155, 106, 157, 150, 86, 195, 123, 69, 206, 150, 84, 60, 138, 103, 116, 59, 6, 130, 49, 127, 102, 7, 32, 5, 113, 14, 50, 91, 80, 199, 248, 51, 0, 6, 12, 80, 173, 55, 49, 59, 48, 1, 144, 88, 246, 166, 175, 79, 76, 3, 88, 234, 140, 46, 123, 165, 96, 65, 212, 242, 16, 2, 16, 102, 52, 142, 215, 184, 219, 152, 44, 156, 148, 134, 190, 60, 0, 6, 216, 130, 9, 0, 253, 23, 0, 218, 21, 178, 130, 238, 254, 33, 0, 232, 162, 1, 108, 134, 106, 147, 206, 251, 106, 175, 146, 78, 6, 52, 109, 0, 32, 216, 179, 58, 43, 43, 43, 41, 33, 161, 177, 241, 109, 125, 126, 126, 254, 187, 119, 163, 163, 59, 119, 182, 128, 101, 245, 240, 176, 205, 138, 183, 224, 123, 17, 16, 72, 11, 218, 89, 0, 135, 165, 213, 101, 51, 232, 203, 43, 106, 4, 129, 61, 11, 10, 99, 132, 184, 49, 76, 23, 0, 169, 67, 54, 108, 200, 205, 13, 15, 207, 88, 179, 102, 77, 198, 185, 167, 231, 206, 197, 239, 223, 127, 226, 32, 116, 200, 43, 87, 174, 236, 136, 173, 182, 114, 57, 48, 25, 128, 74, 62, 249, 186, 179, 187, 111, 72, 60, 56, 222, 209, 230, 176, 212, 27, 49, 64, 141, 25, 247, 166, 158, 176, 213, 235, 1, 65, 141, 190, 5, 224, 205, 232, 32, 192, 227, 17, 68, 248, 202, 1, 43, 222, 2, 122, 7, 38, 85, 161, 54, 81, 166, 242, 1, 184, 59, 218, 156, 141, 70, 123, 67, 181, 169, 66, 167, 37, 177, 154, 123, 2, 78, 21, 225, 230, 132, 166, 57, 142, 159, 35, 172, 137, 171, 78, 149, 79, 106, 172, 140, 149, 3, 118, 22, 160, 210, 7, 160, 171, 209, 173, 144, 14, 150, 168, 218, 251, 251, 134, 60, 80, 133, 181, 206, 198, 122, 91, 165, 110, 133, 192, 27, 248, 106, 9, 86, 96, 96, 192, 198, 232, 109, 146, 175, 139, 238, 30, 63, 56, 52, 116, 33, 136, 199, 227, 137, 68, 11, 69, 172, 126, 120, 156, 0, 130, 114, 187, 1, 50, 2, 0, 184, 54, 160, 141, 245, 119, 119, 148, 165, 247, 251, 170, 208, 146, 180, 45, 38, 99, 87, 233, 226, 73, 42, 93, 124, 98, 123, 234, 215, 0, 126, 215, 226, 227, 142, 170, 84, 91, 105, 157, 62, 189, 108, 95, 225, 230, 205, 57, 57, 7, 138, 160, 114, 126, 72, 32, 183, 227, 28, 228, 0, 42, 180, 145, 37, 227, 80, 55, 101, 157, 108, 17, 180, 22, 175, 10, 18, 254, 236, 176, 129, 30, 171, 121, 68, 176, 36, 232, 248, 81, 149, 184, 107, 236, 227, 91, 16, 20, 154, 181, 97, 88, 113, 246, 199, 4, 187, 26, 228, 54, 253, 36, 128, 10, 115, 98, 150, 127, 71, 71, 83, 147, 44, 179, 143, 173, 66, 251, 251, 176, 168, 229, 18, 4, 61, 128, 147, 102, 138, 171, 25, 33, 20, 102, 47, 45, 221, 159, 86, 38, 75, 106, 117, 185, 92, 198, 122, 107, 228, 89, 248, 176, 242, 35, 2, 133, 220, 62, 169, 17, 234, 142, 72, 253, 59, 232, 190, 37, 203, 20, 15, 194, 159, 184, 8, 140, 182, 145, 192, 249, 105, 208, 3, 166, 60, 29, 48, 85, 192, 94, 245, 16, 1, 20, 219, 227, 148, 155, 165, 43, 203, 223, 143, 8, 224, 203, 194, 243, 41, 174, 101, 176, 20, 226, 92, 244, 136, 193, 196, 1, 196, 186, 25, 127, 135, 83, 70, 23, 129, 163, 177, 222, 218, 208, 98, 208, 55, 7, 68, 47, 163, 123, 0, 31, 253, 168, 19, 34, 196, 81, 240, 130, 253, 130, 138, 148, 133, 81, 209, 151, 133, 220, 134, 177, 239, 240, 225, 53, 166, 20, 136, 107, 23, 203, 171, 77, 62, 0, 93, 164, 172, 11, 252, 233, 174, 157, 80, 226, 113, 247, 182, 57, 49, 64, 53, 174, 144, 192, 128, 176, 156, 248, 96, 14, 97, 170, 50, 228, 40, 64, 4, 33, 10, 9, 143, 63, 6, 0, 236, 191, 153, 39, 204, 51, 158, 40, 91, 18, 180, 126, 255, 153, 247, 44, 64, 141, 34, 169, 11, 183, 108, 122, 110, 183, 38, 149, 184, 155, 218, 156, 117, 70, 12, 0, 109, 192, 108, 246, 6, 44, 129, 129, 128, 48, 194, 148, 0, 223, 82, 128, 24, 227, 42, 182, 7, 17, 194, 96, 73, 120, 204, 150, 229, 202, 85, 57, 210, 83, 43, 19, 229, 250, 106, 182, 13, 188, 40, 238, 98, 166, 22, 30, 23, 245, 198, 164, 146, 94, 60, 9, 236, 6, 26, 0, 174, 73, 230, 230, 158, 37, 201, 202, 92, 176, 226, 79, 243, 251, 192, 36, 10, 130, 71, 164, 238, 206, 13, 138, 143, 75, 91, 181, 39, 75, 26, 187, 50, 114, 120, 0, 107, 88, 15, 98, 27, 97, 108, 47, 187, 124, 60, 173, 92, 249, 73, 62, 0, 61, 13, 0, 162, 204, 100, 79, 64, 244, 62, 92, 150, 252, 233, 127, 33, 65, 161, 75, 243, 74, 139, 142, 42, 203, 54, 103, 73, 243, 173, 54, 251, 232, 168, 29, 132, 207, 35, 204, 56, 100, 59, 113, 69, 164, 108, 204, 193, 46, 31, 138, 216, 106, 139, 58, 0, 57, 232, 178, 1, 64, 141, 153, 34, 105, 9, 180, 100, 96, 79, 216, 129, 245, 244, 76, 154, 238, 205, 40, 116, 235, 78, 7, 238, 12, 173, 117, 220, 97, 208, 200, 29, 71, 216, 78, 172, 72, 106, 114, 56, 28, 190, 229, 27, 1, 208, 16, 123, 101, 207, 187, 58, 43, 51, 138, 40, 48, 247, 33, 80, 176, 19, 81, 69, 208, 11, 171, 208, 180, 0, 128, 224, 176, 177, 201, 193, 28, 136, 184, 3, 25, 119, 28, 193, 4, 176, 3, 197, 240, 142, 147, 243, 135, 199, 166, 148, 120, 104, 38, 13, 45, 166, 114, 157, 153, 244, 122, 155, 89, 145, 164, 183, 39, 96, 111, 202, 38, 52, 237, 187, 97, 72, 132, 177, 141, 61, 15, 77, 6, 96, 8, 32, 194, 90, 193, 138, 149, 109, 181, 240, 10, 216, 51, 143, 225, 97, 131, 60, 39, 68, 41, 55, 54, 84, 3, 0, 117, 68, 145, 184, 224, 11, 133, 45, 129, 153, 132, 166, 5, 128, 212, 104, 67, 132, 171, 118, 2, 192, 200, 0, 128, 108, 116, 130, 235, 20, 210, 194, 229, 65, 251, 243, 157, 206, 198, 137, 240, 211, 209, 49, 69, 6, 101, 23, 15, 219, 241, 59, 212, 197, 203, 75, 119, 111, 242, 155, 172, 77, 126, 25, 211, 4, 192, 95, 60, 55, 68, 188, 171, 229, 142, 196, 32, 60, 229, 7, 228, 242, 200, 216, 28, 229, 150, 165, 248, 27, 136, 48, 101, 212, 210, 200, 44, 31, 236, 153, 228, 88, 145, 198, 91, 127, 164, 133, 174, 66, 111, 216, 234, 45, 162, 95, 190, 158, 35, 13, 38, 248, 204, 174, 185, 252, 52, 17, 196, 113, 124, 38, 174, 84, 164, 166, 41, 143, 182, 1, 12, 175, 42, 65, 16, 75, 193, 70, 56, 152, 240, 8, 66, 72, 8, 120, 144, 34, 68, 14, 36, 42, 207, 152, 16, 12, 1, 73, 56, 233, 149, 40, 49, 49, 106, 248, 47, 102, 183, 11, 145, 214, 202, 74, 137, 138, 104, 210, 199, 5, 131, 135, 30, 122, 241, 32, 112, 49, 6, 127, 211, 97, 186, 45, 22, 221, 88, 123, 210, 111, 160, 205, 46, 179, 251, 253, 252, 126, 251, 155, 157, 71, 248, 72, 167, 196, 180, 18, 97, 142, 3, 75, 163, 242, 139, 179, 142, 154, 92, 203, 49, 122, 37, 188, 27, 201, 73, 219, 183, 215, 44, 252, 88, 223, 80, 102, 205, 216, 182, 3, 0, 10, 236, 86, 24, 58, 38, 219, 171, 161, 49, 29, 138, 92, 76, 90, 139, 80, 37, 128, 36, 188, 93, 31, 91, 43, 175, 131, 13, 191, 222, 106, 51, 70, 204, 28, 193, 55, 66, 119, 38, 190, 190, 97, 181, 17, 157, 166, 65, 207, 240, 149, 151, 144, 174, 74, 121, 53, 218, 9, 148, 229, 96, 160, 202, 118, 3, 140, 84, 103, 141, 0, 156, 96, 247, 195, 167, 221, 177, 186, 66, 231, 249, 123, 185, 93, 153, 204, 28, 162, 81, 111, 150, 93, 248, 229, 213, 59, 150, 126, 218, 47, 64, 25, 173, 152, 12, 235, 125, 62, 217, 43, 130, 106, 253, 198, 64, 129, 179, 205, 196, 7, 4, 237, 0, 156, 160, 238, 180, 173, 166, 173, 218, 124, 140, 5, 206, 205, 213, 90, 205, 173, 92, 123, 79, 195, 135, 236, 179, 57, 170, 56, 107, 34, 184, 61, 178, 228, 5, 0, 134, 16, 10, 20, 213, 223, 182, 16, 226, 1, 4, 205, 0, 188, 18, 31, 92, 224, 129, 67, 4, 220, 92, 149, 139, 228, 79, 236, 172, 179, 240, 95, 176, 85, 146, 119, 178, 132, 16, 115, 125, 196, 47, 114, 201, 203, 33, 67, 81, 86, 107, 54, 31, 16, 180, 3, 0, 1, 179, 57, 122, 215, 43, 103, 238, 236, 198, 75, 30, 62, 216, 43, 203, 74, 248, 18, 180, 45, 209, 135, 21, 49, 14, 65, 132, 215, 144, 35, 151, 47, 82, 52, 3, 0, 1, 247, 78, 174, 227, 142, 12, 88, 43, 67, 245, 113, 127, 89, 86, 140, 215, 192, 7, 215, 116, 200, 34, 23, 27, 147, 130, 17, 189, 115, 152, 141, 73, 26, 0, 180, 109, 91, 229, 56, 6, 54, 192, 159, 61, 125, 31, 91, 164, 203, 161, 201, 108, 226, 33, 57, 206, 125, 127, 72, 100, 226, 3, 130, 49, 2, 111, 134, 19, 108, 76, 210, 12, 240, 27, 127, 218, 249, 249, 211, 87, 162, 59, 133, 94, 111, 193, 67, 106, 80, 93, 101, 240, 139, 25, 92, 94, 250, 171, 200, 161, 96, 81, 22, 157, 160, 16, 148, 58, 0, 98, 254, 137, 225, 103, 208, 72, 141, 78, 12, 41, 192, 189, 29, 145, 112, 240, 144, 140, 198, 160, 97, 95, 111, 131, 9, 10, 74, 21, 0, 252, 109, 3, 60, 253, 44, 124, 176, 167, 242, 134, 154, 187, 8, 130, 252, 12, 85, 85, 102, 37, 213, 228, 179, 69, 75, 170, 25, 240, 80, 127, 216, 40, 137, 79, 63, 175, 55, 177, 160, 247, 96, 70, 117, 148, 112, 126, 126, 138, 0, 136, 249, 179, 244, 243, 167, 207, 229, 13, 223, 210, 176, 238, 77, 5, 0, 185, 96, 24, 26, 88, 75, 168, 190, 248, 122, 15, 53, 91, 216, 172, 250, 23, 74, 9, 32, 234, 175, 86, 191, 204, 253, 99, 210, 183, 241, 213, 93, 58, 50, 64, 227, 31, 13, 175, 172, 44, 169, 213, 39, 30, 82, 216, 129, 9, 74, 19, 128, 234, 207, 58, 95, 50, 127, 49, 148, 117, 37, 109, 0, 224, 111, 26, 53, 174, 174, 194, 184, 167, 246, 189, 159, 0, 244, 195, 196, 149, 182, 71, 144, 185, 88, 11, 239, 127, 190, 75, 229, 79, 170, 218, 33, 236, 65, 105, 2, 176, 156, 233, 8, 211, 55, 92, 36, 98, 160, 10, 36, 213, 126, 179, 153, 184, 210, 3, 128, 135, 39, 246, 230, 246, 162, 250, 78, 245, 57, 185, 246, 78, 165, 11, 0, 209, 159, 212, 245, 239, 252, 47, 217, 127, 128, 63, 1, 64, 160, 216, 167, 27, 190, 18, 254, 148, 112, 204, 26, 36, 30, 242, 99, 245, 148, 91, 109, 163, 61, 3, 232, 111, 197, 233, 38, 84, 110, 164, 29, 0, 97, 16, 251, 66, 236, 211, 67, 98, 194, 84, 241, 55, 75, 60, 102, 237, 19, 227, 192, 166, 113, 19, 189, 159, 102, 128, 138, 17, 171, 125, 164, 135, 148, 89, 173, 35, 165, 164, 127, 193, 110, 191, 137, 98, 87, 247, 88, 237, 118, 235, 211, 113, 226, 142, 53, 110, 128, 51, 119, 137, 231, 192, 13, 247, 47, 140, 88, 251, 85, 55, 184, 114, 222, 218, 55, 213, 247, 164, 236, 50, 65, 90, 1, 26, 243, 36, 65, 55, 136, 30, 233, 164, 150, 25, 60, 37, 8, 186, 6, 196, 19, 136, 26, 116, 146, 32, 52, 245, 144, 45, 126, 147, 153, 22, 104, 92, 198, 50, 12, 24, 231, 238, 11, 146, 206, 142, 1, 144, 19, 61, 207, 147, 64, 66, 119, 41, 217, 210, 12, 80, 44, 9, 197, 141, 21, 157, 210, 118, 119, 79, 69, 147, 180, 121, 85, 189, 182, 98, 90, 218, 222, 150, 174, 207, 147, 45, 78, 84, 166, 219, 20, 166, 27, 161, 1, 3, 104, 156, 146, 58, 117, 253, 60, 99, 112, 98, 48, 15, 174, 0, 130, 199, 38, 237, 0, 63, 168, 45, 99, 21, 213, 129, 40, 12, 79, 112, 96, 226, 237, 21, 210, 5, 99, 163, 229, 150, 22, 194, 138, 105, 5, 69, 16, 162, 85, 36, 54, 194, 150, 34, 110, 167, 178, 168, 213, 194, 46, 139, 203, 178, 246, 11, 187, 237, 240, 151, 201, 35, 204, 11, 92, 200, 155, 220, 99, 226, 36, 123, 183, 138, 183, 187, 163, 112, 156, 113, 78, 230, 227, 255, 231, 76, 166, 118, 34, 128, 209, 154, 200, 123, 31, 142, 0, 134, 250, 110, 17, 73, 234, 42, 142, 222, 58, 87, 192, 37, 128, 113, 83, 247, 217, 61, 1, 119, 215, 50, 210, 9, 198, 156, 43, 197, 173, 163, 56, 150, 101, 88, 24, 192, 3, 6, 139, 13, 143, 209, 31, 181, 0, 49, 203, 82, 141, 0, 92, 112, 116, 28, 166, 21, 48, 230, 136, 49, 44, 103, 0, 91, 194, 182, 111, 117, 66, 36, 219, 67, 174, 224, 151, 217, 84, 171, 82, 4, 224, 238, 5, 216, 57, 71, 156, 181, 246, 1, 175, 38, 67, 45, 112, 15, 202, 59, 161, 242, 158, 1, 220, 237, 17, 243, 86, 230, 185, 65, 130, 192, 106, 230, 0, 165, 128, 0, 6, 77, 201, 88, 84, 188, 12, 127, 19, 128, 53, 17, 226, 4, 251, 211, 6, 130, 220, 1, 87, 32, 174, 123, 168, 184, 122, 87, 178, 198, 18, 138, 207, 152, 190, 123, 148, 110, 56, 9, 82, 210, 0, 52, 62, 19, 32, 9, 170, 122, 164, 152, 2, 71, 240, 151, 3, 236, 39, 120, 207, 10, 149, 109, 38, 64, 213, 7, 6, 19, 114, 217, 101, 122, 133, 81, 7, 188, 235, 200, 76, 144, 33, 9, 50, 215, 130, 36, 101, 241, 68, 132, 252, 201, 148, 97, 113, 128, 182, 15, 238, 173, 48, 108, 225, 180, 67, 162, 95, 190, 163, 17, 80, 221, 137, 155, 242, 37, 149, 173, 207, 158, 47, 242, 42, 89, 34, 22, 239, 185, 221, 4, 90, 179, 160, 64, 46, 133, 172, 48, 192, 47, 130, 174, 8, 229, 186, 16, 21, 160, 174, 39, 69, 70, 139, 67, 109, 107, 4, 80, 215, 34, 147, 194, 228, 121, 67, 3, 176, 69, 15, 74, 57, 236, 219, 98, 68, 48, 64, 178, 13, 194, 194, 0, 213, 61, 20, 135, 125, 239, 10, 10, 194, 201, 78, 185, 198, 138, 192, 190, 158, 5, 240, 42, 53, 0, 213, 10, 39, 207, 53, 128, 83, 1, 149, 206, 247, 131, 153, 80, 182, 156, 6, 239, 105, 78, 81, 0, 227, 245, 108, 155, 111, 110, 132, 82, 176, 218, 23, 128, 136, 109, 5, 20, 0, 206, 243, 186, 107, 7, 228, 121, 114, 240, 229, 130, 172, 22, 237, 154, 113, 97, 110, 126, 58, 70, 121, 134, 43, 1, 228, 1, 28, 124, 99, 28, 206, 10, 80, 137, 233, 51, 37, 224, 160, 207, 249, 251, 160, 79, 158, 38, 25, 44, 222, 178, 11, 184, 177, 225, 10, 162, 223, 163, 255, 163, 36, 167, 102, 139, 253, 190, 3, 142, 101, 245, 10, 11, 216, 1, 49, 239, 79, 217, 129, 199, 113, 247, 81, 11, 32, 111, 7, 232, 197, 65, 107, 168, 98, 248, 119, 23, 128, 91, 15, 113, 103, 155, 21, 65, 187, 142, 158, 82, 128, 95, 74, 1, 216, 180, 15, 106, 49, 184, 126, 157, 20, 3, 184, 1, 176, 50, 101, 64, 193, 42, 167, 0, 209, 217, 110, 192, 54, 229, 26, 20, 244, 219, 97, 45, 128, 238, 52, 3, 104, 12, 144, 180, 186, 145, 102, 177, 73, 5, 49, 7, 196, 254, 170, 50, 100, 239, 187, 177, 245, 198, 34, 119, 247, 96, 205, 168, 155, 218, 89, 157, 83, 247, 77, 202, 233, 114, 108, 125, 125, 164, 0, 236, 145, 102, 62, 55, 50, 123, 107, 251, 213, 195, 120, 60, 182, 38, 68, 156, 42, 244, 106, 119, 85, 199, 114, 245, 250, 5, 1, 218, 166, 105, 150, 210, 144, 207, 48, 204, 164, 203, 74, 151, 152, 106, 78, 191, 203, 9, 99, 62, 231, 239, 172, 198, 98, 49, 106, 50, 90, 255, 95, 175, 100, 236, 231, 168, 142, 133, 90, 116, 9, 161, 44, 14, 160, 111, 145, 58, 100, 45, 76, 186, 58, 230, 51, 191, 63, 60, 76, 27, 251, 49, 240, 223, 93, 203, 255, 12, 59, 24, 117, 192, 168, 3, 70, 29, 48, 234, 128, 81, 7, 140, 58, 96, 212, 1, 84, 7, 0, 13, 207, 230, 190, 92, 185, 148, 184, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
-var WailsLogoBlackTransparent = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 128, 0, 0, 0, 128, 8, 3, 0, 0, 0, 244, 224, 145, 249, 0, 0, 2, 250, 80, 76, 84, 69, 0, 0, 0, 227, 50, 50, 36, 32, 32, 201, 41, 45, 29, 29, 29, 227, 50, 49, 153, 23, 31, 225, 45, 46, 30, 30, 30, 198, 33, 33, 226, 47, 47, 227, 50, 50, 30, 30, 30, 226, 50, 50, 206, 41, 43, 30, 30, 30, 183, 31, 36, 185, 32, 37, 30, 30, 30, 228, 50, 50, 30, 30, 30, 30, 30, 30, 219, 47, 47, 30, 30, 30, 228, 50, 50, 28, 28, 28, 192, 35, 38, 173, 27, 33, 187, 33, 37, 227, 50, 50, 228, 50, 50, 30, 30, 30, 205, 40, 43, 215, 44, 45, 208, 42, 44, 178, 29, 35, 29, 29, 29, 183, 31, 36, 29, 29, 29, 33, 33, 33, 197, 37, 40, 210, 43, 44, 197, 37, 40, 30, 30, 30, 29, 29, 29, 29, 29, 29, 226, 49, 49, 225, 49, 49, 220, 47, 47, 30, 30, 30, 29, 29, 29, 30, 30, 30, 29, 29, 29, 192, 36, 39, 29, 29, 29, 167, 24, 31, 212, 43, 45, 206, 41, 43, 29, 29, 29, 30, 30, 30, 222, 48, 48, 30, 30, 30, 163, 24, 27, 119, 5, 16, 204, 40, 43, 196, 37, 40, 178, 29, 35, 177, 29, 35, 227, 50, 50, 164, 23, 30, 226, 49, 49, 217, 45, 47, 162, 23, 30, 172, 27, 33, 228, 50, 50, 227, 49, 49, 200, 38, 40, 30, 30, 30, 29, 29, 29, 29, 29, 29, 31, 31, 31, 150, 18, 26, 166, 24, 31, 227, 50, 49, 178, 30, 34, 228, 50, 50, 190, 34, 38, 30, 30, 30, 205, 40, 43, 30, 30, 30, 207, 41, 43, 176, 28, 34, 226, 49, 49, 195, 37, 40, 30, 30, 30, 199, 38, 41, 30, 30, 30, 127, 8, 19, 28, 28, 28, 210, 34, 36, 214, 45, 46, 200, 38, 41, 131, 11, 21, 190, 34, 38, 227, 49, 49, 190, 34, 38, 191, 34, 39, 192, 35, 39, 186, 32, 37, 226, 49, 50, 30, 30, 30, 216, 46, 46, 171, 27, 32, 199, 37, 41, 146, 16, 26, 141, 14, 25, 211, 47, 48, 120, 0, 3, 136, 15, 25, 158, 21, 29, 203, 39, 42, 218, 46, 47, 208, 42, 43, 156, 20, 28, 227, 49, 49, 191, 34, 39, 172, 27, 33, 184, 31, 36, 30, 30, 30, 204, 40, 42, 208, 42, 44, 120, 5, 17, 207, 41, 44, 204, 41, 44, 186, 32, 37, 148, 17, 25, 227, 50, 49, 224, 48, 49, 227, 49, 49, 151, 18, 26, 228, 50, 50, 125, 7, 18, 156, 20, 28, 130, 4, 17, 152, 19, 27, 177, 29, 34, 151, 18, 26, 229, 50, 51, 204, 40, 43, 189, 34, 38, 213, 44, 45, 227, 49, 49, 126, 8, 19, 145, 16, 24, 130, 9, 20, 162, 23, 29, 232, 52, 51, 254, 253, 253, 219, 75, 77, 218, 46, 46, 196, 37, 40, 184, 32, 36, 211, 43, 44, 152, 19, 27, 201, 39, 41, 165, 24, 30, 175, 28, 34, 123, 7, 18, 182, 31, 35, 170, 26, 32, 212, 43, 45, 125, 7, 18, 172, 27, 33, 247, 217, 217, 127, 8, 19, 141, 14, 23, 198, 37, 40, 118, 4, 16, 220, 196, 199, 155, 61, 69, 226, 108, 109, 233, 151, 151, 188, 111, 117, 178, 86, 92, 130, 9, 20, 119, 5, 16, 122, 6, 18, 138, 13, 23, 238, 223, 225, 197, 142, 146, 237, 173, 174, 139, 19, 28, 220, 47, 48, 31, 31, 31, 227, 50, 50, 215, 45, 46, 219, 46, 47, 224, 48, 49, 213, 44, 45, 221, 47, 48, 209, 42, 44, 33, 33, 33, 222, 48, 48, 246, 54, 54, 207, 41, 43, 205, 40, 43, 192, 34, 38, 217, 45, 46, 226, 49, 49, 211, 42, 44, 200, 38, 41, 194, 36, 40, 190, 33, 38, 232, 51, 51, 203, 40, 42, 188, 33, 37, 186, 32, 37, 229, 50, 50, 197, 37, 40, 184, 32, 36, 131, 10, 21, 180, 29, 35, 169, 25, 32, 178, 29, 34, 199, 38, 41, 182, 31, 35, 123, 6, 17, 236, 51, 51, 174, 27, 33, 172, 26, 32, 164, 23, 30, 139, 13, 23, 128, 7, 18, 136, 11, 21, 242, 52, 53, 176, 28, 34, 202, 38, 41, 167, 24, 31, 143, 14, 24, 153, 18, 27, 148, 16, 25, 238, 52, 52, 223, 45, 47, 161, 22, 30, 219, 43, 46, 206, 38, 42, 199, 34, 39, 215, 41, 44, 158, 21, 28, 195, 35, 39, 183, 30, 35, 160, 21, 29, 250, 55, 55, 253, 55, 55, 105, 176, 83, 104, 0, 0, 0, 193, 116, 82, 78, 83, 0, 254, 5, 5, 8, 250, 7, 11, 252, 8, 27, 194, 246, 168, 18, 249, 251, 29, 241, 54, 233, 212, 23, 221, 170, 20, 252, 252, 249, 246, 225, 186, 177, 33, 252, 250, 56, 50, 38, 14, 253, 248, 248, 175, 156, 149, 89, 65, 251, 204, 194, 162, 127, 43, 25, 252, 251, 249, 226, 168, 124, 92, 22, 253, 247, 231, 208, 90, 83, 82, 38, 249, 248, 247, 234, 147, 146, 142, 114, 85, 31, 246, 239, 238, 229, 207, 201, 181, 160, 135, 119, 102, 98, 81, 74, 71, 66, 52, 44, 254, 251, 249, 246, 245, 229, 191, 180, 136, 126, 110, 107, 76, 74, 59, 37, 26, 10, 253, 252, 245, 241, 168, 168, 168, 159, 157, 136, 112, 99, 95, 88, 247, 243, 227, 221, 220, 214, 202, 187, 181, 133, 105, 48, 18, 15, 239, 233, 219, 215, 211, 198, 180, 151, 90, 74, 63, 47, 250, 245, 244, 239, 238, 233, 207, 197, 194, 191, 173, 171, 150, 139, 123, 119, 243, 211, 196, 108, 88, 250, 244, 243, 238, 235, 232, 231, 229, 190, 139, 246, 242, 239, 236, 219, 38, 121, 14, 209, 0, 0, 13, 162, 73, 68, 65, 84, 120, 218, 236, 152, 87, 76, 147, 97, 20, 134, 91, 177, 24, 52, 154, 18, 19, 98, 4, 13, 208, 144, 80, 46, 132, 27, 34, 77, 8, 171, 64, 41, 112, 131, 130, 33, 160, 33, 70, 89, 130, 1, 65, 209, 168, 64, 84, 196, 129, 162, 56, 113, 239, 189, 247, 30, 233, 78, 41, 180, 20, 126, 104, 75, 203, 42, 171, 12, 129, 150, 173, 38, 158, 239, 231, 47, 85, 131, 8, 13, 200, 133, 188, 225, 134, 64, 250, 62, 223, 251, 157, 239, 156, 3, 164, 25, 205, 104, 70, 51, 154, 209, 140, 254, 19, 217, 4, 146, 166, 85, 254, 33, 14, 164, 105, 148, 77, 200, 82, 127, 210, 52, 202, 63, 66, 123, 136, 52, 125, 10, 12, 89, 82, 180, 136, 68, 178, 32, 77, 131, 144, 233, 234, 253, 88, 81, 196, 220, 233, 241, 7, 157, 159, 79, 209, 98, 193, 41, 211, 226, 111, 69, 34, 205, 217, 184, 180, 27, 227, 112, 60, 73, 211, 36, 215, 211, 156, 110, 50, 5, 91, 132, 96, 44, 44, 44, 44, 173, 172, 172, 44, 73, 255, 72, 112, 124, 155, 67, 9, 221, 24, 133, 220, 186, 223, 129, 180, 153, 244, 111, 4, 135, 28, 22, 254, 246, 230, 41, 225, 248, 100, 236, 248, 249, 145, 31, 219, 184, 111, 138, 137, 217, 100, 61, 37, 158, 191, 23, 153, 67, 200, 74, 56, 62, 133, 163, 36, 71, 230, 167, 50, 163, 179, 147, 147, 110, 39, 174, 90, 149, 152, 25, 181, 198, 125, 193, 164, 24, 207, 154, 53, 90, 93, 91, 30, 73, 79, 203, 63, 119, 246, 204, 153, 168, 121, 152, 22, 142, 207, 225, 40, 233, 225, 126, 225, 5, 154, 242, 190, 190, 202, 220, 13, 201, 107, 156, 108, 38, 251, 57, 32, 203, 181, 96, 121, 248, 240, 189, 119, 133, 59, 242, 30, 61, 186, 182, 239, 216, 177, 240, 189, 75, 180, 24, 178, 39, 43, 47, 209, 106, 6, 251, 250, 20, 225, 96, 238, 126, 116, 18, 125, 143, 60, 121, 114, 248, 222, 189, 194, 194, 91, 183, 222, 62, 124, 248, 240, 245, 235, 184, 184, 12, 93, 243, 151, 47, 93, 93, 157, 157, 93, 157, 84, 46, 134, 201, 40, 28, 228, 175, 28, 28, 210, 132, 223, 204, 98, 66, 238, 147, 171, 163, 183, 234, 247, 120, 123, 215, 215, 183, 180, 180, 168, 213, 106, 29, 168, 25, 244, 5, 105, 197, 54, 10, 25, 132, 252, 57, 152, 239, 141, 59, 209, 78, 94, 164, 41, 208, 218, 55, 45, 224, 15, 26, 97, 192, 1, 154, 195, 174, 92, 34, 115, 248, 124, 25, 242, 39, 119, 207, 207, 79, 159, 178, 22, 120, 214, 27, 101, 96, 2, 192, 9, 208, 241, 101, 124, 144, 12, 252, 41, 221, 17, 54, 164, 41, 212, 225, 250, 250, 61, 166, 4, 192, 94, 167, 11, 187, 194, 226, 243, 197, 200, 95, 38, 227, 80, 176, 149, 174, 83, 58, 3, 45, 11, 213, 120, 21, 32, 0, 93, 70, 179, 78, 157, 177, 98, 155, 152, 47, 68, 254, 124, 228, 175, 84, 110, 52, 243, 131, 9, 89, 224, 26, 227, 4, 233, 111, 213, 40, 130, 22, 117, 70, 134, 26, 66, 8, 139, 103, 241, 133, 60, 49, 1, 64, 161, 104, 119, 78, 110, 195, 3, 89, 90, 90, 25, 101, 9, 223, 64, 33, 234, 226, 32, 253, 150, 45, 91, 182, 196, 125, 90, 225, 227, 38, 230, 241, 132, 4, 0, 153, 223, 122, 192, 198, 188, 252, 189, 242, 189, 188, 142, 28, 29, 223, 212, 58, 187, 7, 153, 111, 201, 120, 246, 242, 229, 94, 15, 49, 79, 202, 19, 10, 137, 43, 224, 99, 199, 93, 205, 188, 255, 180, 188, 125, 121, 121, 121, 59, 64, 119, 238, 100, 101, 101, 221, 191, 159, 29, 29, 205, 100, 6, 164, 166, 158, 219, 228, 228, 228, 238, 238, 96, 109, 237, 181, 96, 142, 149, 5, 81, 136, 123, 212, 207, 94, 125, 120, 250, 224, 197, 69, 55, 30, 87, 202, 35, 0, 64, 28, 178, 39, 196, 102, 105, 86, 216, 103, 194, 26, 7, 154, 154, 58, 144, 170, 65, 182, 182, 108, 118, 65, 65, 193, 149, 240, 240, 220, 220, 220, 147, 39, 97, 160, 36, 110, 216, 96, 191, 61, 50, 50, 52, 52, 212, 51, 244, 213, 211, 247, 23, 46, 60, 120, 206, 234, 151, 130, 191, 9, 128, 172, 116, 201, 59, 227, 133, 79, 101, 51, 20, 112, 172, 122, 235, 215, 175, 134, 166, 38, 0, 104, 108, 104, 107, 171, 209, 212, 13, 85, 41, 42, 203, 75, 74, 6, 7, 85, 125, 114, 121, 123, 123, 69, 49, 72, 34, 145, 136, 122, 47, 62, 184, 112, 225, 197, 197, 117, 235, 4, 92, 174, 212, 148, 128, 76, 73, 15, 235, 218, 122, 227, 126, 26, 170, 105, 51, 9, 12, 6, 67, 211, 114, 144, 45, 18, 141, 6, 16, 212, 42, 5, 80, 0, 70, 89, 153, 170, 182, 86, 14, 20, 18, 81, 233, 186, 139, 31, 159, 227, 246, 92, 34, 1, 188, 8, 57, 110, 65, 186, 78, 67, 245, 114, 191, 44, 39, 146, 89, 10, 216, 218, 24, 4, 9, 64, 4, 144, 193, 112, 8, 154, 186, 42, 72, 1, 0, 22, 47, 46, 43, 115, 118, 118, 150, 203, 43, 42, 42, 138, 29, 139, 123, 233, 224, 47, 16, 152, 0, 144, 63, 133, 173, 238, 234, 28, 104, 106, 24, 170, 203, 205, 140, 49, 155, 0, 1, 116, 252, 2, 96, 74, 0, 34, 0, 0, 252, 26, 214, 137, 192, 255, 215, 4, 148, 241, 234, 102, 4, 80, 221, 86, 53, 168, 242, 181, 223, 61, 199, 44, 130, 134, 32, 34, 129, 134, 134, 182, 26, 184, 1, 34, 1, 240, 71, 87, 128, 238, 0, 7, 16, 137, 68, 165, 35, 0, 66, 28, 128, 195, 200, 80, 127, 233, 234, 252, 218, 212, 88, 83, 87, 89, 214, 91, 154, 115, 106, 227, 92, 51, 8, 130, 218, 130, 140, 53, 64, 3, 81, 145, 236, 236, 22, 35, 193, 13, 212, 202, 127, 7, 144, 26, 1, 56, 172, 176, 250, 102, 2, 160, 170, 178, 76, 94, 204, 21, 178, 14, 120, 158, 55, 131, 64, 131, 178, 135, 240, 135, 134, 134, 80, 250, 40, 126, 120, 8, 144, 63, 4, 128, 106, 96, 4, 192, 84, 2, 32, 25, 101, 133, 183, 26, 7, 232, 0, 128, 242, 50, 185, 68, 196, 21, 43, 101, 199, 67, 22, 78, 148, 128, 185, 2, 196, 102, 179, 109, 109, 209, 67, 172, 82, 160, 103, 168, 130, 55, 216, 43, 1, 79, 73, 236, 31, 0, 196, 100, 59, 239, 22, 29, 2, 48, 116, 52, 104, 20, 37, 170, 118, 73, 41, 151, 39, 86, 106, 177, 132, 249, 254, 115, 240, 166, 62, 110, 130, 252, 212, 115, 169, 169, 169, 1, 1, 76, 38, 51, 58, 58, 58, 59, 59, 59, 57, 57, 57, 41, 41, 41, 20, 20, 233, 219, 31, 11, 254, 163, 0, 112, 114, 226, 188, 213, 8, 96, 192, 80, 13, 0, 139, 93, 124, 24, 116, 150, 155, 219, 146, 37, 176, 162, 5, 47, 90, 182, 224, 15, 43, 174, 229, 108, 203, 95, 101, 5, 115, 103, 172, 201, 180, 230, 114, 143, 15, 74, 64, 244, 27, 0, 159, 197, 142, 171, 71, 0, 248, 35, 168, 171, 108, 239, 239, 151, 234, 101, 24, 214, 221, 173, 213, 118, 23, 21, 97, 17, 135, 198, 127, 19, 99, 55, 177, 53, 219, 122, 124, 140, 1, 24, 1, 208, 48, 182, 27, 8, 138, 131, 43, 232, 26, 6, 176, 243, 245, 101, 8, 4, 44, 55, 10, 18, 74, 1, 163, 140, 130, 112, 36, 109, 45, 40, 45, 45, 221, 203, 203, 43, 221, 218, 164, 209, 8, 208, 13, 154, 8, 160, 13, 16, 1, 16, 9, 240, 93, 12, 77, 213, 91, 227, 116, 198, 71, 16, 191, 225, 113, 76, 204, 238, 213, 203, 140, 242, 247, 95, 182, 122, 217, 66, 139, 223, 1, 214, 62, 185, 87, 120, 235, 209, 62, 208, 181, 107, 55, 110, 220, 188, 121, 115, 21, 232, 250, 245, 168, 177, 23, 170, 221, 219, 244, 62, 224, 255, 51, 0, 159, 190, 220, 208, 81, 109, 27, 166, 30, 121, 4, 190, 246, 187, 108, 198, 49, 0, 143, 166, 175, 61, 123, 248, 221, 142, 107, 199, 6, 26, 135, 160, 216, 203, 203, 203, 161, 122, 69, 62, 127, 35, 200, 209, 231, 252, 2, 32, 102, 209, 12, 168, 115, 217, 134, 53, 119, 118, 26, 112, 0, 185, 132, 113, 10, 122, 192, 248, 118, 67, 171, 244, 252, 212, 232, 172, 29, 126, 5, 154, 193, 246, 222, 222, 10, 121, 113, 206, 223, 8, 124, 244, 116, 32, 32, 0, 164, 66, 183, 120, 3, 222, 185, 53, 236, 48, 226, 17, 148, 171, 42, 4, 122, 222, 231, 16, 87, 132, 48, 206, 209, 188, 32, 237, 28, 51, 57, 51, 209, 215, 69, 212, 163, 228, 221, 29, 251, 223, 47, 187, 24, 64, 48, 146, 128, 56, 118, 121, 117, 3, 248, 215, 212, 81, 217, 93, 80, 131, 168, 13, 56, 87, 56, 10, 120, 74, 14, 244, 128, 137, 253, 133, 62, 199, 218, 105, 205, 227, 80, 251, 189, 87, 61, 73, 99, 42, 229, 106, 143, 135, 17, 64, 76, 103, 119, 192, 220, 64, 99, 67, 97, 23, 212, 137, 191, 194, 18, 85, 133, 72, 32, 21, 202, 180, 216, 202, 131, 171, 109, 38, 188, 27, 45, 8, 76, 217, 109, 243, 199, 164, 28, 54, 165, 236, 138, 58, 209, 227, 65, 12, 67, 225, 122, 26, 225, 143, 150, 23, 187, 32, 67, 35, 0, 148, 213, 226, 0, 124, 50, 7, 211, 46, 57, 224, 25, 72, 50, 95, 38, 95, 167, 152, 93, 81, 73, 145, 246, 215, 79, 236, 189, 202, 112, 164, 27, 219, 0, 207, 45, 190, 3, 236, 9, 255, 146, 50, 234, 114, 124, 20, 213, 22, 227, 0, 28, 50, 66, 32, 239, 135, 129, 96, 166, 142, 90, 59, 197, 48, 179, 147, 50, 55, 36, 158, 244, 189, 236, 226, 220, 94, 12, 213, 95, 10, 222, 165, 4, 128, 148, 23, 107, 219, 48, 108, 143, 251, 171, 92, 168, 141, 26, 52, 138, 138, 69, 92, 30, 0, 112, 0, 129, 140, 105, 149, 9, 59, 83, 44, 38, 184, 165, 7, 48, 163, 179, 238, 220, 78, 244, 203, 189, 18, 111, 7, 31, 44, 71, 59, 161, 28, 223, 135, 24, 142, 142, 142, 198, 87, 200, 163, 211, 8, 127, 124, 101, 112, 86, 181, 95, 14, 71, 143, 0, 7, 16, 203, 0, 0, 103, 80, 66, 49, 156, 94, 141, 15, 132, 241, 114, 88, 223, 86, 208, 106, 170, 240, 85, 8, 215, 240, 58, 0, 4, 196, 44, 68, 1, 172, 103, 185, 121, 80, 27, 145, 61, 238, 143, 22, 22, 121, 241, 182, 204, 240, 190, 197, 42, 57, 62, 11, 101, 208, 135, 71, 186, 177, 114, 229, 193, 9, 45, 40, 78, 126, 125, 26, 90, 93, 29, 218, 70, 236, 42, 137, 149, 148, 88, 71, 192, 223, 145, 78, 95, 47, 224, 201, 120, 241, 13, 104, 103, 82, 24, 127, 1, 240, 74, 67, 239, 15, 170, 98, 43, 36, 2, 174, 80, 172, 108, 253, 86, 212, 218, 10, 95, 184, 190, 125, 111, 93, 26, 226, 58, 254, 61, 205, 221, 175, 132, 70, 197, 239, 214, 180, 17, 226, 254, 12, 6, 221, 81, 196, 147, 41, 149, 250, 75, 46, 192, 104, 58, 62, 242, 103, 72, 79, 185, 223, 134, 153, 45, 2, 0, 254, 202, 136, 136, 165, 193, 9, 75, 71, 148, 16, 156, 48, 207, 51, 112, 34, 25, 208, 168, 196, 78, 108, 220, 72, 99, 99, 125, 24, 162, 30, 189, 76, 95, 122, 245, 84, 100, 84, 74, 114, 165, 130, 10, 246, 68, 252, 40, 28, 71, 1, 221, 213, 250, 114, 41, 3, 111, 3, 193, 59, 253, 3, 29, 206, 187, 186, 46, 52, 201, 213, 213, 97, 66, 183, 64, 165, 42, 140, 43, 169, 179, 139, 139, 139, 92, 210, 175, 215, 11, 114, 78, 216, 223, 221, 181, 201, 1, 122, 156, 85, 102, 159, 194, 174, 196, 120, 124, 84, 28, 30, 30, 208, 70, 31, 247, 139, 28, 185, 168, 13, 4, 31, 220, 56, 138, 223, 4, 9, 126, 208, 102, 254, 46, 9, 132, 97, 28, 127, 95, 228, 56, 50, 12, 34, 184, 41, 67, 27, 29, 202, 37, 112, 144, 72, 8, 7, 215, 168, 73, 104, 17, 34, 155, 130, 38, 49, 154, 4, 149, 134, 64, 205, 177, 165, 169, 63, 227, 245, 39, 94, 200, 157, 118, 130, 173, 110, 210, 162, 120, 184, 40, 244, 220, 251, 88, 167, 114, 147, 220, 125, 254, 129, 239, 243, 189, 247, 121, 223, 231, 199, 225, 80, 112, 19, 248, 214, 167, 147, 105, 47, 243, 14, 198, 205, 213, 211, 105, 82, 55, 6, 6, 60, 28, 158, 155, 137, 198, 171, 72, 124, 227, 16, 228, 96, 141, 105, 35, 150, 53, 11, 194, 70, 17, 252, 236, 3, 95, 221, 158, 170, 234, 129, 162, 239, 14, 141, 47, 225, 191, 82, 3, 104, 31, 245, 225, 102, 190, 29, 147, 147, 140, 146, 128, 75, 64, 41, 132, 160, 29, 164, 121, 65, 216, 218, 48, 2, 189, 221, 209, 245, 110, 228, 246, 241, 201, 122, 215, 121, 31, 153, 6, 58, 61, 227, 243, 99, 125, 132, 238, 32, 12, 5, 179, 218, 10, 226, 194, 200, 120, 3, 98, 101, 94, 16, 92, 27, 69, 80, 106, 151, 146, 96, 124, 23, 76, 88, 115, 29, 81, 207, 254, 237, 131, 126, 176, 159, 119, 17, 215, 199, 40, 88, 91, 188, 66, 16, 194, 192, 187, 29, 222, 52, 25, 78, 76, 227, 214, 236, 22, 161, 71, 227, 250, 216, 32, 182, 148, 11, 120, 249, 221, 185, 161, 151, 33, 148, 23, 4, 108, 10, 29, 64, 242, 53, 209, 62, 232, 47, 134, 68, 190, 165, 58, 14, 14, 4, 70, 25, 194, 67, 96, 133, 52, 228, 163, 253, 250, 147, 207, 195, 191, 207, 143, 83, 178, 160, 149, 9, 16, 150, 153, 128, 242, 102, 65, 128, 9, 65, 36, 182, 114, 202, 245, 85, 44, 140, 184, 170, 82, 104, 63, 22, 53, 10, 120, 121, 238, 165, 43, 8, 76, 211, 176, 32, 216, 198, 142, 161, 175, 130, 125, 208, 71, 251, 138, 2, 94, 113, 83, 184, 23, 147, 189, 84, 88, 163, 175, 97, 131, 98, 155, 126, 147, 235, 163, 125, 220, 84, 66, 0, 240, 183, 200, 32, 62, 156, 13, 229, 53, 134, 242, 108, 46, 95, 120, 206, 37, 27, 86, 136, 168, 95, 95, 181, 111, 64, 251, 7, 126, 2, 136, 207, 217, 252, 182, 21, 151, 57, 79, 92, 178, 65, 63, 85, 85, 67, 120, 250, 11, 125, 243, 222, 197, 137, 193, 131, 223, 109, 133, 36, 185, 163, 81, 209, 6, 253, 70, 29, 245, 77, 251, 8, 156, 129, 135, 56, 137, 169, 111, 97, 31, 207, 160, 32, 17, 39, 65, 253, 74, 168, 178, 148, 125, 108, 9, 202, 132, 35, 226, 44, 47, 169, 49, 234, 155, 246, 87, 2, 208, 210, 196, 81, 196, 95, 1, 237, 79, 129, 122, 31, 110, 63, 74, 28, 116, 240, 49, 208, 16, 148, 68, 0, 237, 7, 91, 15, 45, 251, 48, 192, 33, 89, 90, 78, 156, 115, 70, 28, 135, 216, 15, 178, 30, 108, 63, 166, 3, 110, 122, 51, 208, 12, 40, 42, 188, 122, 12, 172, 226, 31, 127, 252, 248, 10, 216, 230, 198, 1, 254, 100, 240, 209, 44, 8, 226, 21, 42, 33, 128, 23, 9, 72, 192, 0, 136, 13, 130, 53, 110, 52, 115, 0, 59, 31, 39, 59, 17, 128, 153, 97, 20, 140, 2, 0, 113, 100, 172, 194, 48, 8, 69, 209, 71, 112, 232, 80, 40, 136, 82, 156, 178, 136, 25, 170, 67, 99, 112, 104, 201, 39, 164, 205, 154, 37, 148, 124, 64, 191, 33, 191, 246, 70, 255, 170, 134, 130, 74, 233, 144, 118, 201, 25, 174, 92, 148, 235, 125, 188, 191, 41, 2, 239, 35, 153, 252, 46, 247, 240, 197, 127, 198, 17, 66, 10, 216, 142, 34, 234, 102, 8, 39, 126, 170, 224, 58, 109, 58, 5, 163, 213, 67, 15, 173, 53, 122, 134, 136, 210, 218, 232, 70, 164, 52, 49, 88, 99, 100, 26, 183, 189, 118, 186, 133, 156, 209, 214, 231, 82, 223, 9, 172, 70, 81, 68, 42, 225, 228, 145, 77, 80, 123, 196, 91, 250, 175, 9, 22, 47, 10, 98, 156, 220, 35, 238, 31, 241, 65, 85, 250, 3, 14, 249, 184, 79, 138, 11, 220, 193, 234, 10, 61, 67, 164, 83, 21, 148, 41, 65, 23, 141, 121, 130, 47, 5, 152, 76, 97, 99, 240, 199, 84, 168, 231, 161, 192, 156, 237, 95, 82, 191, 67, 244, 158, 147, 245, 59, 112, 47, 118, 171, 29, 215, 65, 24, 8, 90, 145, 11, 23, 150, 44, 161, 32, 139, 138, 6, 133, 2, 40, 248, 40, 5, 136, 35, 240, 233, 80, 154, 40, 202, 1, 56, 67, 174, 54, 165, 111, 245, 214, 122, 47, 54, 148, 238, 223, 40, 10, 90, 203, 222, 157, 29, 47, 35, 180, 109, 242, 101, 43, 173, 54, 127, 113, 144, 19, 22, 215, 151, 39, 176, 83, 193, 38, 119, 113, 22, 65, 69, 78, 16, 194, 195, 64, 200, 52, 149, 105, 192, 16, 36, 177, 109, 170, 51, 17, 122, 250, 135, 248, 248, 163, 173, 17, 66, 33, 90, 60, 129, 201, 72, 12, 62, 249, 19, 150, 188, 63, 112, 25, 44, 65, 158, 63, 23, 10, 66, 8, 196, 89, 67, 153, 117, 182, 25, 232, 187, 203, 119, 187, 66, 196, 87, 68, 163, 35, 144, 23, 70, 30, 239, 124, 135, 64, 157, 83, 232, 41, 43, 232, 132, 5, 33, 175, 129, 122, 148, 232, 161, 71, 13, 180, 254, 66, 119, 32, 170, 52, 228, 238, 42, 220, 107, 40, 236, 204, 225, 44, 8, 225, 3, 72, 108, 57, 11, 1, 111, 12, 234, 9, 186, 128, 158, 20, 228, 226, 210, 241, 20, 208, 11, 169, 208, 185, 165, 183, 29, 216, 39, 133, 78, 144, 8, 211, 145, 64, 82, 24, 8, 12, 151, 16, 39, 226, 169, 17, 186, 198, 240, 192, 181, 6, 226, 196, 79, 180, 4, 218, 155, 192, 65, 243, 23, 128, 254, 205, 184, 19, 196, 72, 236, 39, 27, 92, 83, 16, 186, 32, 239, 44, 140, 144, 66, 204, 179, 81, 18, 168, 152, 195, 3, 80, 227, 10, 90, 115, 4, 62, 246, 206, 19, 198, 189, 32, 74, 45, 54, 244, 12, 222, 49, 4, 226, 60, 64, 2, 154, 92, 1, 244, 217, 108, 132, 128, 124, 186, 76, 119, 202, 36, 135, 18, 64, 235, 8, 116, 70, 161, 96, 182, 162, 23, 228, 206, 206, 24, 1, 107, 105, 1, 86, 216, 90, 2, 169, 77, 78, 237, 113, 71, 96, 1, 20, 0, 1, 20, 20, 126, 185, 202, 95, 61, 188, 32, 241, 107, 125, 187, 153, 152, 199, 11, 155, 45, 171, 32, 2, 165, 37, 208, 177, 201, 42, 240, 56, 242, 2, 96, 64, 72, 249, 95, 186, 164, 54, 226, 236, 212, 10, 50, 214, 69, 238, 140, 17, 195, 208, 67, 32, 192, 8, 9, 19, 164, 117, 187, 10, 82, 69, 153, 19, 224, 166, 33, 101, 53, 183, 56, 88, 223, 218, 67, 29, 108, 137, 151, 38, 34, 210, 104, 104, 255, 215, 24, 41, 84, 64, 23, 82, 159, 85, 134, 188, 251, 98, 59, 54, 181, 151, 183, 163, 85, 205, 217, 66, 143, 235, 250, 87, 243, 69, 129, 202, 252, 75, 160, 233, 8, 253, 202, 239, 169, 209, 252, 170, 54, 228, 65, 4, 198, 102, 219, 118, 186, 208, 166, 72, 71, 63, 154, 29, 133, 51, 53, 149, 110, 105, 249, 53, 71, 27, 84, 137, 39, 80, 54, 197, 182, 21, 155, 243, 221, 91, 21, 95, 163, 190, 153, 67, 172, 208, 127, 67, 217, 7, 243, 224, 126, 149, 159, 119, 158, 247, 156, 151, 242, 228, 158, 112, 246, 143, 127, 252, 108, 20, 140, 130, 81, 48, 10, 70, 193, 40, 24, 5, 88, 1, 0, 48, 20, 121, 13, 171, 25, 166, 148, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
-var WailsLogoWhiteTransparent = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 128, 0, 0, 0, 128, 8, 3, 0, 0, 0, 244, 224, 145, 249, 0, 0, 2, 244, 80, 76, 84, 69, 0, 0, 0, 190, 37, 40, 145, 21, 31, 222, 46, 46, 208, 42, 44, 228, 50, 50, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 227, 50, 49, 227, 50, 50, 207, 38, 39, 224, 48, 49, 255, 255, 255, 227, 48, 48, 227, 50, 50, 255, 255, 255, 214, 44, 45, 202, 40, 43, 210, 42, 44, 174, 27, 33, 206, 41, 43, 255, 255, 255, 186, 33, 37, 255, 255, 255, 186, 32, 37, 134, 12, 22, 183, 31, 36, 150, 19, 25, 228, 50, 50, 255, 255, 255, 187, 34, 37, 255, 255, 255, 142, 14, 23, 196, 37, 40, 169, 25, 31, 220, 47, 47, 215, 45, 46, 227, 50, 50, 203, 40, 42, 198, 37, 40, 255, 255, 255, 255, 255, 255, 255, 255, 255, 120, 5, 16, 227, 50, 49, 203, 40, 42, 255, 255, 255, 255, 255, 255, 161, 22, 29, 227, 49, 49, 189, 33, 37, 255, 255, 255, 192, 35, 39, 255, 255, 255, 225, 49, 49, 255, 255, 255, 255, 255, 255, 167, 24, 31, 255, 255, 255, 255, 255, 255, 188, 33, 38, 179, 30, 35, 227, 50, 50, 225, 48, 48, 151, 18, 26, 205, 40, 43, 228, 50, 50, 192, 35, 38, 184, 32, 36, 255, 255, 255, 255, 255, 255, 218, 46, 47, 224, 48, 49, 228, 49, 49, 221, 46, 48, 255, 255, 255, 130, 11, 22, 196, 36, 40, 227, 50, 50, 191, 34, 39, 255, 255, 255, 227, 50, 50, 176, 28, 34, 176, 29, 33, 148, 17, 25, 255, 255, 255, 121, 6, 17, 228, 50, 50, 255, 255, 255, 188, 33, 38, 255, 255, 255, 255, 255, 255, 221, 47, 48, 226, 49, 49, 206, 40, 43, 255, 255, 255, 191, 34, 38, 255, 255, 255, 151, 18, 26, 227, 50, 50, 195, 37, 40, 174, 28, 33, 216, 46, 46, 146, 16, 26, 255, 255, 255, 210, 34, 36, 180, 30, 35, 150, 18, 26, 227, 50, 50, 211, 43, 45, 227, 49, 49, 195, 36, 40, 206, 41, 43, 255, 255, 255, 186, 32, 37, 225, 48, 49, 208, 42, 44, 156, 20, 28, 195, 37, 39, 125, 7, 18, 196, 37, 40, 149, 16, 27, 119, 0, 3, 217, 46, 47, 203, 39, 42, 203, 41, 43, 149, 17, 26, 178, 29, 34, 207, 41, 44, 255, 255, 255, 167, 25, 31, 164, 23, 30, 205, 40, 43, 227, 49, 49, 198, 37, 39, 228, 50, 50, 216, 45, 46, 175, 28, 33, 127, 8, 19, 255, 255, 255, 206, 41, 43, 255, 255, 255, 255, 255, 255, 186, 33, 37, 177, 29, 34, 155, 20, 27, 255, 255, 255, 255, 255, 255, 182, 31, 35, 224, 48, 48, 211, 43, 45, 131, 10, 20, 186, 32, 37, 227, 49, 49, 173, 27, 33, 126, 8, 19, 255, 255, 255, 221, 47, 48, 116, 4, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 234, 53, 51, 127, 8, 19, 139, 13, 23, 227, 50, 49, 133, 10, 21, 124, 6, 18, 255, 255, 255, 255, 255, 255, 234, 216, 218, 172, 81, 88, 146, 16, 25, 214, 44, 46, 178, 30, 34, 168, 24, 31, 122, 6, 18, 166, 24, 31, 255, 255, 255, 216, 67, 69, 251, 216, 216, 226, 108, 109, 233, 151, 151, 188, 111, 117, 142, 17, 26, 165, 24, 31, 199, 38, 41, 214, 184, 187, 219, 87, 90, 224, 79, 80, 197, 142, 146, 149, 48, 57, 237, 173, 174, 227, 50, 50, 255, 255, 255, 223, 48, 48, 215, 45, 46, 221, 47, 48, 218, 46, 47, 213, 44, 45, 211, 43, 45, 203, 39, 42, 193, 35, 39, 219, 46, 47, 191, 34, 38, 206, 41, 43, 188, 33, 38, 246, 54, 54, 183, 31, 36, 199, 38, 41, 186, 32, 37, 209, 42, 44, 173, 27, 33, 179, 29, 35, 197, 37, 40, 176, 28, 34, 229, 50, 50, 181, 30, 35, 233, 51, 51, 170, 26, 32, 168, 24, 31, 201, 38, 41, 164, 23, 30, 236, 52, 52, 124, 6, 17, 131, 11, 21, 242, 53, 53, 195, 35, 39, 161, 22, 29, 222, 45, 47, 147, 16, 25, 137, 12, 22, 128, 8, 19, 140, 13, 23, 153, 18, 26, 219, 43, 46, 157, 20, 28, 205, 39, 42, 200, 35, 40, 231, 50, 50, 207, 39, 42, 215, 41, 44, 252, 55, 55, 238, 52, 52, 217, 45, 46, 212, 40, 44, 132, 6, 18, 235, 51, 51, 226, 46, 48, 239, 50, 51, 194, 134, 147, 194, 0, 0, 0, 195, 116, 82, 78, 83, 0, 5, 7, 11, 254, 253, 7, 251, 9, 4, 250, 169, 8, 253, 248, 27, 194, 244, 22, 17, 249, 249, 246, 233, 251, 164, 29, 254, 249, 24, 226, 222, 45, 19, 254, 252, 252, 251, 250, 246, 249, 248, 179, 56, 38, 254, 237, 176, 156, 149, 247, 87, 53, 24, 247, 241, 203, 185, 173, 243, 213, 208, 208, 90, 55, 32, 246, 239, 221, 196, 134, 127, 93, 68, 62, 51, 38, 13, 243, 233, 211, 181, 132, 102, 102, 65, 48, 44, 247, 232, 226, 221, 202, 190, 168, 120, 120, 113, 110, 107, 89, 82, 81, 79, 76, 37, 29, 254, 231, 182, 181, 165, 160, 154, 145, 143, 125, 94, 88, 79, 73, 54, 33, 15, 254, 245, 229, 217, 216, 206, 198, 196, 193, 170, 159, 145, 139, 133, 130, 118, 111, 100, 96, 88, 84, 240, 239, 236, 218, 194, 191, 189, 178, 169, 166, 151, 151, 151, 138, 111, 93, 78, 72, 67, 41, 221, 201, 173, 134, 74, 64, 33, 244, 237, 225, 224, 224, 209, 187, 139, 120, 245, 244, 243, 238, 235, 234, 228, 167, 254, 245, 245, 242, 240, 239, 163, 91, 109, 90, 0, 0, 13, 94, 73, 68, 65, 84, 120, 218, 236, 152, 105, 72, 147, 113, 28, 199, 159, 212, 17, 44, 87, 177, 182, 33, 186, 137, 168, 51, 247, 66, 3, 19, 19, 4, 205, 19, 52, 209, 36, 21, 195, 23, 133, 88, 41, 105, 165, 216, 97, 167, 69, 183, 18, 84, 208, 29, 245, 162, 19, 186, 163, 251, 238, 105, 30, 59, 156, 186, 195, 185, 205, 99, 78, 55, 231, 60, 166, 166, 89, 175, 250, 253, 159, 103, 143, 51, 203, 114, 166, 249, 34, 63, 136, 40, 27, 251, 126, 254, 191, 231, 247, 255, 255, 254, 12, 155, 101, 150, 89, 102, 153, 101, 150, 255, 4, 102, 34, 54, 163, 44, 61, 18, 137, 205, 32, 204, 139, 158, 75, 177, 25, 100, 93, 168, 254, 24, 54, 115, 36, 94, 92, 92, 59, 15, 195, 230, 96, 51, 0, 10, 93, 181, 82, 87, 187, 50, 114, 102, 242, 129, 21, 243, 232, 122, 93, 96, 206, 140, 228, 187, 98, 152, 243, 149, 24, 125, 31, 142, 175, 193, 102, 136, 132, 77, 248, 32, 78, 215, 205, 67, 50, 115, 230, 204, 113, 114, 117, 117, 117, 194, 254, 17, 176, 124, 230, 49, 207, 65, 29, 157, 214, 22, 19, 137, 57, 99, 255, 6, 88, 36, 9, 177, 247, 22, 106, 244, 56, 29, 215, 197, 92, 27, 121, 153, 233, 149, 182, 99, 71, 176, 251, 180, 100, 142, 109, 178, 200, 35, 129, 131, 125, 116, 26, 174, 161, 109, 78, 223, 16, 145, 154, 85, 20, 119, 225, 76, 120, 120, 74, 193, 218, 245, 94, 139, 166, 40, 248, 87, 125, 237, 180, 139, 151, 155, 158, 182, 61, 59, 251, 202, 66, 157, 30, 167, 225, 56, 174, 225, 60, 120, 152, 119, 74, 91, 109, 181, 214, 100, 166, 20, 173, 247, 98, 78, 233, 118, 160, 34, 139, 111, 103, 151, 149, 221, 186, 117, 249, 124, 126, 254, 141, 146, 146, 123, 47, 95, 237, 93, 172, 239, 163, 161, 124, 218, 30, 118, 125, 187, 213, 170, 200, 75, 137, 67, 75, 159, 58, 118, 93, 189, 122, 181, 236, 214, 229, 203, 231, 31, 61, 186, 113, 253, 250, 245, 164, 164, 36, 15, 179, 197, 187, 163, 163, 163, 171, 171, 163, 139, 91, 222, 167, 131, 229, 3, 26, 141, 164, 174, 62, 239, 76, 92, 4, 25, 62, 149, 2, 231, 91, 51, 2, 2, 2, 90, 91, 59, 59, 13, 134, 97, 15, 15, 179, 217, 108, 177, 88, 188, 189, 59, 188, 189, 195, 162, 225, 209, 51, 112, 2, 93, 242, 193, 75, 169, 193, 60, 108, 26, 40, 78, 26, 38, 4, 64, 1, 57, 120, 32, 7, 16, 176, 68, 157, 220, 67, 195, 133, 66, 28, 65, 211, 207, 75, 231, 77, 219, 17, 120, 59, 0, 213, 128, 18, 48, 160, 124, 139, 25, 150, 207, 128, 120, 82, 128, 174, 15, 101, 98, 211, 72, 89, 107, 107, 70, 235, 40, 1, 139, 217, 3, 150, 207, 16, 10, 25, 164, 0, 93, 23, 152, 48, 173, 51, 208, 233, 242, 112, 64, 6, 228, 35, 1, 244, 0, 12, 222, 97, 28, 134, 176, 162, 66, 72, 128, 211, 52, 154, 43, 147, 252, 96, 27, 115, 72, 176, 113, 225, 61, 26, 70, 37, 64, 241, 195, 195, 195, 134, 168, 147, 126, 194, 10, 233, 72, 62, 93, 191, 101, 106, 15, 60, 192, 201, 201, 149, 194, 9, 254, 193, 138, 175, 155, 51, 160, 250, 157, 187, 119, 239, 78, 122, 25, 198, 225, 11, 43, 237, 249, 140, 182, 80, 230, 228, 234, 207, 75, 231, 241, 22, 237, 154, 216, 212, 186, 157, 49, 12, 225, 1, 73, 119, 95, 188, 216, 199, 98, 84, 66, 190, 237, 9, 224, 12, 93, 76, 252, 36, 159, 127, 110, 126, 73, 126, 126, 254, 33, 224, 210, 165, 199, 143, 227, 74, 75, 75, 83, 83, 35, 34, 54, 108, 216, 145, 150, 22, 28, 236, 229, 181, 211, 221, 157, 185, 200, 217, 213, 246, 217, 87, 51, 12, 31, 238, 190, 191, 115, 231, 249, 59, 190, 180, 124, 200, 46, 192, 192, 105, 107, 160, 108, 78, 147, 42, 118, 118, 148, 170, 167, 165, 165, 165, 9, 104, 68, 176, 217, 236, 83, 167, 78, 229, 229, 229, 61, 200, 204, 12, 15, 15, 143, 141, 141, 77, 73, 89, 242, 250, 245, 225, 130, 194, 194, 227, 71, 239, 190, 185, 51, 119, 254, 211, 103, 123, 6, 134, 32, 127, 84, 5, 52, 130, 252, 108, 30, 57, 149, 29, 103, 251, 233, 166, 32, 163, 209, 8, 14, 96, 160, 106, 104, 168, 175, 215, 214, 41, 20, 53, 213, 213, 146, 246, 118, 181, 85, 222, 220, 44, 22, 247, 246, 202, 100, 253, 253, 50, 151, 254, 39, 79, 63, 45, 123, 254, 100, 227, 198, 170, 242, 242, 202, 81, 2, 26, 86, 84, 71, 208, 193, 210, 92, 212, 211, 127, 99, 224, 139, 80, 177, 217, 224, 0, 18, 117, 10, 183, 26, 164, 33, 105, 87, 203, 229, 200, 66, 230, 34, 218, 248, 246, 227, 51, 34, 158, 20, 160, 10, 192, 15, 50, 119, 25, 155, 124, 247, 199, 5, 99, 192, 100, 12, 26, 131, 32, 31, 149, 0, 106, 0, 69, 104, 128, 124, 16, 168, 1, 1, 137, 68, 226, 227, 227, 67, 24, 136, 101, 80, 7, 214, 198, 47, 85, 85, 200, 0, 242, 109, 2, 56, 141, 109, 232, 232, 234, 105, 81, 105, 235, 50, 11, 118, 76, 210, 64, 21, 68, 246, 1, 41, 0, 5, 64, 21, 80, 80, 21, 80, 83, 2, 46, 202, 141, 74, 17, 228, 255, 32, 160, 9, 241, 176, 32, 1, 223, 134, 186, 118, 117, 242, 146, 109, 206, 147, 49, 8, 66, 6, 68, 62, 41, 96, 175, 0, 249, 8, 40, 1, 23, 165, 136, 18, 160, 90, 0, 231, 120, 27, 188, 59, 186, 140, 45, 141, 13, 117, 53, 237, 189, 34, 206, 217, 43, 11, 28, 55, 200, 14, 106, 8, 242, 69, 176, 17, 245, 92, 192, 13, 64, 2, 62, 192, 79, 2, 246, 30, 196, 249, 81, 173, 150, 17, 1, 137, 92, 86, 110, 226, 135, 30, 191, 54, 9, 3, 45, 90, 58, 85, 124, 98, 245, 228, 242, 209, 3, 240, 25, 71, 0, 12, 232, 97, 1, 6, 16, 232, 49, 54, 169, 234, 161, 2, 114, 153, 75, 185, 80, 35, 140, 57, 146, 224, 176, 193, 171, 48, 0, 150, 175, 106, 176, 237, 67, 8, 183, 54, 139, 123, 251, 251, 149, 95, 250, 253, 199, 171, 0, 206, 13, 232, 244, 48, 219, 4, 20, 213, 106, 177, 76, 84, 46, 101, 104, 244, 186, 213, 91, 214, 57, 19, 135, 250, 132, 13, 210, 211, 210, 210, 54, 0, 17, 17, 17, 169, 169, 169, 89, 89, 165, 69, 69, 69, 113, 113, 71, 143, 22, 22, 20, 28, 222, 59, 224, 111, 107, 194, 49, 2, 56, 39, 41, 192, 128, 122, 16, 9, 104, 21, 33, 2, 127, 14, 203, 143, 207, 95, 188, 152, 142, 227, 171, 111, 110, 93, 52, 206, 233, 231, 52, 22, 87, 152, 59, 191, 155, 76, 235, 163, 187, 253, 33, 159, 18, 176, 111, 2, 62, 59, 169, 213, 96, 70, 2, 208, 2, 218, 154, 230, 47, 3, 67, 38, 188, 79, 167, 31, 212, 235, 7, 107, 107, 117, 43, 143, 173, 112, 100, 48, 99, 227, 131, 12, 144, 0, 202, 167, 4, 42, 164, 66, 134, 91, 79, 80, 82, 39, 37, 80, 231, 150, 156, 236, 47, 170, 242, 227, 51, 232, 0, 170, 130, 142, 30, 250, 179, 194, 174, 220, 226, 226, 226, 244, 220, 92, 30, 194, 221, 14, 24, 252, 98, 241, 163, 12, 56, 35, 45, 64, 85, 128, 33, 48, 182, 52, 69, 121, 152, 169, 77, 16, 146, 146, 21, 31, 191, 109, 235, 214, 165, 54, 214, 45, 221, 186, 106, 235, 242, 177, 93, 192, 43, 190, 90, 118, 249, 252, 141, 146, 123, 247, 74, 74, 30, 30, 4, 206, 156, 137, 5, 14, 172, 253, 253, 133, 106, 91, 180, 137, 51, 70, 64, 200, 242, 53, 54, 53, 250, 70, 121, 128, 0, 180, 0, 236, 194, 228, 37, 39, 152, 19, 24, 128, 187, 120, 233, 183, 203, 110, 157, 191, 113, 186, 71, 85, 87, 77, 32, 81, 139, 149, 254, 127, 50, 224, 152, 56, 74, 165, 253, 32, 172, 20, 250, 177, 141, 232, 236, 102, 71, 89, 186, 200, 93, 88, 45, 239, 231, 28, 56, 142, 106, 62, 145, 222, 119, 229, 165, 111, 79, 125, 124, 232, 225, 41, 173, 4, 198, 157, 88, 46, 227, 252, 217, 128, 53, 170, 2, 21, 252, 16, 34, 191, 65, 203, 142, 178, 239, 194, 42, 83, 229, 253, 139, 241, 72, 97, 130, 163, 121, 81, 110, 90, 68, 209, 133, 216, 76, 129, 178, 187, 79, 122, 252, 247, 95, 191, 156, 0, 3, 74, 0, 122, 80, 208, 210, 164, 82, 17, 167, 70, 88, 71, 15, 252, 173, 69, 2, 46, 34, 169, 6, 247, 156, 7, 103, 128, 35, 56, 187, 7, 175, 207, 42, 60, 119, 63, 26, 12, 126, 71, 78, 116, 55, 139, 18, 168, 96, 177, 33, 159, 24, 156, 10, 183, 176, 46, 98, 23, 74, 144, 192, 80, 5, 254, 85, 23, 184, 105, 21, 211, 225, 187, 17, 51, 49, 103, 27, 115, 220, 74, 237, 12, 206, 57, 177, 118, 95, 55, 85, 129, 10, 63, 46, 228, 19, 115, 27, 14, 77, 110, 144, 145, 156, 4, 98, 151, 170, 202, 10, 6, 142, 235, 244, 139, 67, 215, 36, 98, 127, 15, 228, 238, 56, 177, 246, 232, 225, 37, 7, 246, 237, 141, 230, 176, 88, 34, 234, 28, 226, 135, 64, 219, 147, 249, 48, 53, 124, 184, 190, 141, 245, 132, 128, 18, 4, 132, 56, 78, 3, 5, 124, 229, 145, 229, 147, 206, 117, 247, 74, 139, 200, 138, 43, 72, 137, 13, 207, 76, 22, 200, 197, 50, 232, 126, 18, 242, 28, 26, 146, 10, 124, 81, 62, 117, 121, 83, 251, 112, 209, 38, 128, 89, 168, 44, 39, 4, 144, 66, 159, 94, 227, 185, 37, 199, 193, 187, 50, 15, 190, 222, 136, 187, 4, 223, 110, 100, 158, 60, 233, 86, 221, 174, 38, 174, 132, 205, 232, 151, 191, 204, 197, 126, 12, 72, 89, 108, 85, 61, 181, 124, 137, 68, 173, 22, 39, 231, 161, 30, 108, 70, 163, 8, 70, 52, 9, 77, 163, 135, 102, 32, 7, 194, 68, 61, 220, 15, 41, 216, 245, 104, 85, 36, 232, 66, 6, 128, 6, 53, 11, 161, 0, 126, 126, 124, 63, 46, 149, 15, 239, 1, 77, 121, 111, 244, 133, 7, 214, 16, 155, 0, 14, 231, 48, 157, 58, 141, 53, 129, 103, 87, 57, 114, 65, 9, 222, 111, 37, 238, 4, 110, 192, 152, 251, 144, 11, 192, 98, 249, 85, 73, 241, 202, 16, 21, 188, 135, 92, 62, 188, 1, 189, 44, 42, 44, 109, 87, 11, 160, 7, 203, 43, 24, 154, 182, 207, 181, 109, 109, 240, 67, 240, 249, 115, 155, 231, 197, 248, 137, 111, 75, 175, 253, 18, 46, 151, 188, 16, 218, 111, 132, 98, 192, 159, 195, 97, 137, 164, 223, 250, 52, 166, 61, 130, 122, 120, 7, 185, 124, 9, 121, 95, 148, 13, 29, 72, 188, 48, 64, 10, 8, 3, 87, 134, 198, 172, 94, 237, 105, 35, 38, 102, 117, 160, 231, 194, 53, 137, 14, 24, 180, 107, 145, 129, 77, 0, 229, 203, 253, 1, 101, 183, 233, 155, 73, 116, 255, 192, 225, 181, 57, 69, 53, 10, 238, 200, 242, 229, 196, 211, 169, 98, 197, 239, 12, 249, 226, 79, 108, 130, 192, 45, 235, 174, 69, 174, 72, 72, 88, 110, 99, 197, 138, 229, 9, 9, 145, 152, 3, 6, 86, 46, 81, 1, 178, 7, 4, 2, 129, 92, 57, 96, 50, 85, 113, 246, 157, 59, 122, 34, 33, 210, 21, 78, 241, 75, 86, 133, 27, 188, 72, 45, 31, 53, 167, 180, 16, 203, 26, 80, 178, 208, 38, 160, 5, 110, 186, 242, 139, 60, 199, 12, 190, 179, 103, 126, 47, 77, 133, 97, 28, 127, 198, 233, 44, 221, 60, 169, 103, 146, 205, 11, 115, 196, 92, 178, 161, 103, 168, 115, 133, 25, 130, 165, 230, 194, 95, 23, 33, 253, 16, 10, 111, 118, 161, 150, 4, 34, 164, 23, 65, 81, 32, 94, 133, 222, 86, 130, 23, 221, 246, 31, 236, 40, 153, 118, 177, 139, 32, 14, 131, 24, 76, 118, 37, 75, 157, 12, 245, 166, 231, 153, 239, 122, 183, 154, 180, 214, 14, 122, 225, 231, 226, 236, 98, 135, 243, 121, 190, 103, 239, 251, 62, 239, 57, 187, 144, 44, 192, 227, 185, 244, 45, 182, 179, 185, 179, 54, 77, 193, 107, 100, 96, 200, 253, 219, 30, 30, 159, 252, 181, 81, 175, 0, 13, 81, 44, 0, 39, 65, 104, 23, 215, 128, 91, 172, 33, 228, 85, 65, 219, 143, 228, 32, 220, 88, 75, 36, 98, 117, 51, 13, 24, 124, 74, 128, 116, 166, 218, 18, 158, 84, 252, 51, 56, 55, 113, 102, 62, 235, 6, 223, 244, 126, 45, 205, 66, 17, 75, 216, 170, 30, 31, 33, 125, 126, 37, 52, 181, 197, 214, 191, 111, 199, 54, 122, 111, 60, 126, 56, 89, 99, 201, 118, 70, 239, 78, 93, 42, 254, 106, 242, 81, 113, 255, 53, 54, 204, 79, 203, 118, 90, 5, 68, 145, 214, 0, 214, 16, 12, 249, 85, 176, 126, 183, 255, 230, 245, 166, 170, 35, 3, 76, 78, 39, 46, 51, 127, 178, 57, 218, 181, 121, 3, 24, 158, 28, 216, 37, 182, 10, 5, 180, 112, 216, 81, 54, 220, 158, 239, 56, 248, 219, 155, 206, 170, 153, 205, 243, 164, 39, 255, 225, 115, 106, 125, 15, 64, 169, 55, 226, 8, 48, 68, 106, 8, 38, 218, 151, 234, 129, 220, 240, 149, 173, 140, 232, 39, 189, 36, 105, 195, 0, 208, 109, 15, 155, 2, 12, 214, 147, 58, 104, 131, 82, 120, 255, 38, 234, 41, 62, 243, 47, 75, 166, 208, 40, 32, 195, 65, 212, 166, 67, 15, 41, 75, 141, 130, 14, 126, 212, 179, 219, 191, 76, 72, 218, 208, 34, 53, 210, 209, 184, 35, 163, 0, 17, 119, 231, 33, 106, 8, 5, 247, 243, 248, 8, 253, 228, 218, 32, 32, 61, 67, 65, 135, 136, 152, 232, 64, 31, 216, 149, 68, 45, 132, 27, 148, 69, 40, 16, 22, 244, 211, 230, 144, 199, 63, 140, 26, 90, 2, 98, 48, 18, 143, 4, 127, 35, 18, 140, 199, 131, 245, 230, 17, 25, 254, 27, 3, 249, 63, 87, 172, 102, 196, 103, 237, 191, 186, 29, 16, 225, 85, 223, 124, 89, 54, 188, 94, 243, 160, 92, 8, 255, 23, 242, 163, 62, 211, 79, 99, 239, 41, 16, 37, 237, 165, 217, 144, 229, 82, 159, 79, 40, 128, 63, 154, 242, 51, 61, 39, 100, 6, 125, 33, 255, 88, 116, 181, 34, 51, 62, 71, 235, 144, 65, 47, 184, 127, 165, 118, 37, 109, 242, 5, 50, 48, 53, 130, 174, 112, 63, 143, 159, 193, 214, 56, 232, 138, 64, 254, 172, 241, 25, 90, 159, 5, 56, 250, 248, 217, 75, 106, 73, 146, 184, 151, 47, 253, 14, 61, 255, 56, 47, 121, 129, 126, 54, 250, 146, 126, 241, 207, 2, 180, 151, 160, 27, 83, 11, 145, 61, 109, 111, 47, 188, 123, 16, 65, 130, 217, 137, 87, 91, 116, 187, 5, 221, 11, 11, 99, 15, 24, 230, 163, 88, 26, 247, 233, 86, 128, 96, 41, 17, 114, 192, 0, 167, 156, 114, 82, 40, 54, 22, 25, 139, 225, 248, 40, 134, 99, 199, 230, 183, 253, 83, 33, 205, 19, 138, 123, 194, 5, 239, 172, 202, 128, 31, 230, 172, 110, 101, 150, 127, 231, 82, 20, 183, 210, 105, 3, 35, 48, 108, 3, 86, 183, 219, 201, 227, 118, 89, 39, 148, 46, 72, 3, 175, 243, 230, 222, 125, 101, 206, 8, 57, 227, 106, 81, 213, 114, 39, 92, 85, 213, 202, 59, 240, 92, 85, 213, 143, 220, 215, 169, 34, 23, 93, 80, 4, 12, 103, 57, 158, 252, 254, 215, 9, 182, 43, 234, 57, 117, 0, 210, 120, 212, 162, 18, 173, 126, 200, 185, 4, 127, 37, 169, 111, 211, 209, 101, 43, 167, 35, 191, 126, 171, 138, 84, 58, 121, 1, 111, 169, 32, 126, 194, 135, 86, 44, 96, 22, 56, 206, 22, 245, 172, 138, 92, 43, 202, 189, 128, 230, 159, 237, 85, 49, 143, 178, 64, 20, 220, 138, 93, 155, 77, 182, 34, 84, 132, 22, 45, 160, 32, 6, 162, 181, 52, 52, 54, 38, 70, 10, 66, 103, 235, 79, 176, 190, 156, 133, 182, 151, 124, 94, 167, 237, 253, 132, 247, 195, 190, 217, 83, 246, 97, 114, 133, 244, 76, 162, 102, 55, 207, 157, 121, 51, 111, 33, 36, 218, 206, 110, 150, 233, 126, 197, 119, 33, 0, 166, 195, 246, 55, 11, 104, 65, 120, 172, 132, 199, 124, 218, 220, 122, 121, 175, 137, 164, 174, 115, 147, 15, 24, 130, 12, 109, 158, 103, 43, 50, 144, 1, 203, 229, 7, 107, 15, 72, 74, 73, 243, 127, 44, 224, 11, 101, 129, 64, 69, 223, 16, 230, 242, 10, 24, 112, 84, 213, 245, 52, 100, 104, 151, 112, 108, 122, 193, 201, 225, 52, 199, 121, 153, 59, 111, 230, 147, 92, 248, 100, 74, 71, 168, 10, 148, 125, 113, 119, 45, 248, 118, 21, 150, 44, 89, 211, 57, 18, 131, 80, 237, 32, 160, 68, 255, 20, 150, 72, 35, 224, 11, 221, 18, 205, 211, 144, 76, 235, 24, 178, 37, 8, 90, 1, 176, 33, 69, 223, 237, 15, 66, 65, 60, 76, 129, 186, 64, 192, 129, 194, 152, 194, 131, 38, 205, 230, 41, 235, 199, 39, 92, 88, 57, 134, 141, 79, 72, 196, 25, 82, 117, 134, 176, 157, 5, 193, 148, 224, 189, 252, 153, 71, 134, 75, 42, 214, 228, 195, 139, 69, 36, 250, 87, 46, 152, 73, 2, 69, 135, 111, 155, 249, 70, 40, 54, 196, 244, 13, 129, 178, 123, 77, 192, 106, 208, 179, 51, 38, 105, 164, 108, 26, 210, 96, 76, 69, 127, 162, 117, 185, 39, 236, 185, 30, 75, 155, 121, 36, 20, 27, 162, 97, 153, 234, 43, 216, 44, 81, 179, 192, 92, 188, 47, 192, 78, 46, 109, 167, 13, 97, 226, 245, 149, 111, 7, 78, 210, 65, 66, 176, 193, 9, 88, 217, 132, 45, 13, 27, 178, 205, 196, 43, 62, 177, 233, 179, 75, 111, 32, 176, 2, 114, 123, 56, 218, 227, 255, 157, 108, 154, 246, 195, 148, 30, 134, 156, 253, 176, 35, 39, 233, 124, 219, 111, 186, 117, 213, 148, 19, 209, 88, 85, 131, 4, 36, 150, 100, 37, 14, 214, 129, 117, 95, 87, 135, 218, 123, 10, 136, 118, 40, 253, 97, 119, 215, 208, 99, 22, 231, 184, 35, 219, 47, 168, 40, 182, 54, 2, 53, 32, 2, 48, 27, 242, 111, 34, 37, 163, 231, 83, 126, 69, 132, 100, 76, 218, 216, 158, 47, 213, 179, 159, 123, 72, 122, 126, 114, 9, 120, 9, 205, 33, 154, 234, 215, 7, 177, 70, 59, 67, 248, 193, 140, 225, 159, 252, 118, 188, 123, 25, 65, 10, 213, 35, 209, 189, 80, 46, 115, 61, 229, 75, 112, 166, 95, 36, 28, 255, 3, 129, 18, 67, 80, 30, 227, 184, 69, 160, 199, 56, 47, 121, 156, 127, 176, 108, 208, 84, 29, 231, 73, 246, 108, 218, 46, 82, 44, 58, 1, 201, 165, 136, 227, 56, 63, 57, 215, 210, 165, 239, 111, 235, 38, 18, 131, 48, 81, 202, 155, 216, 31, 207, 19, 12, 79, 121, 234, 177, 171, 186, 109, 94, 112, 13, 128, 50, 135, 42, 202, 34, 37, 70, 140, 24, 49, 98, 196, 136, 17, 35, 70, 252, 137, 255, 156, 118, 125, 151, 11, 217, 82, 191, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
-var WailsLogoWhite = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 128, 0, 0, 0, 128, 8, 3, 0, 0, 0, 244, 224, 145, 249, 0, 0, 3, 0, 80, 76, 84, 69, 255, 255, 255, 255, 255, 255, 252, 252, 252, 26, 26, 26, 255, 255, 255, 250, 250, 250, 255, 254, 254, 228, 57, 57, 161, 22, 30, 225, 39, 40, 255, 254, 254, 230, 72, 72, 2, 2, 2, 14, 14, 14, 253, 247, 247, 173, 11, 16, 183, 32, 37, 227, 49, 49, 51, 51, 51, 252, 243, 243, 249, 249, 249, 160, 5, 12, 251, 224, 224, 253, 246, 246, 42, 42, 42, 185, 36, 41, 207, 32, 34, 254, 249, 249, 31, 31, 31, 215, 47, 49, 221, 28, 28, 228, 228, 228, 209, 42, 44, 243, 196, 197, 198, 19, 22, 204, 18, 20, 236, 236, 236, 252, 235, 236, 73, 73, 73, 248, 248, 248, 244, 244, 244, 60, 60, 60, 227, 53, 53, 202, 202, 202, 129, 129, 129, 239, 215, 217, 113, 113, 113, 213, 36, 37, 151, 2, 9, 227, 44, 44, 246, 186, 186, 230, 63, 63, 45, 45, 45, 197, 67, 71, 174, 174, 174, 66, 66, 66, 178, 18, 24, 108, 0, 0, 252, 239, 239, 228, 189, 191, 82, 82, 82, 232, 82, 82, 242, 189, 190, 193, 30, 34, 184, 23, 28, 198, 37, 41, 195, 49, 53, 192, 37, 40, 250, 220, 221, 94, 94, 94, 162, 23, 30, 221, 102, 104, 242, 163, 163, 122, 122, 122, 231, 114, 115, 219, 54, 55, 121, 0, 6, 220, 47, 48, 72, 72, 72, 5, 5, 5, 239, 207, 208, 216, 99, 101, 148, 17, 25, 37, 37, 37, 237, 122, 122, 235, 106, 107, 245, 245, 245, 117, 2, 13, 250, 230, 230, 181, 34, 39, 216, 216, 216, 22, 22, 22, 248, 229, 230, 222, 163, 165, 238, 152, 152, 223, 223, 223, 174, 54, 60, 213, 213, 213, 225, 131, 132, 236, 181, 182, 216, 139, 141, 245, 235, 236, 172, 27, 33, 130, 9, 20, 163, 7, 14, 152, 152, 152, 254, 253, 253, 110, 110, 110, 248, 204, 204, 184, 184, 184, 164, 164, 164, 103, 103, 103, 225, 187, 189, 209, 65, 68, 239, 133, 133, 235, 167, 168, 235, 200, 201, 185, 44, 49, 51, 51, 51, 221, 151, 153, 221, 37, 37, 244, 181, 182, 208, 52, 55, 142, 34, 44, 189, 58, 62, 249, 217, 217, 209, 104, 107, 155, 66, 74, 245, 223, 224, 158, 158, 158, 221, 107, 108, 232, 185, 186, 222, 139, 141, 176, 22, 27, 196, 196, 196, 207, 34, 36, 17, 17, 17, 221, 84, 85, 191, 191, 191, 119, 119, 119, 249, 210, 210, 239, 145, 145, 243, 175, 175, 194, 107, 112, 233, 93, 93, 201, 81, 85, 242, 228, 230, 199, 147, 151, 221, 120, 122, 178, 25, 30, 239, 204, 205, 229, 150, 151, 233, 142, 143, 216, 170, 173, 161, 41, 49, 136, 136, 136, 216, 178, 181, 211, 117, 121, 173, 99, 105, 37, 37, 37, 187, 29, 33, 145, 145, 145, 84, 84, 84, 101, 101, 101, 212, 96, 99, 140, 140, 140, 223, 69, 70, 151, 27, 36, 215, 85, 87, 169, 57, 63, 89, 89, 89, 204, 114, 119, 187, 96, 101, 203, 26, 28, 172, 78, 84, 127, 15, 26, 190, 127, 132, 200, 83, 86, 200, 54, 57, 183, 122, 129, 192, 192, 192, 238, 223, 224, 255, 255, 255, 255, 254, 254, 254, 253, 253, 226, 49, 49, 228, 50, 50, 218, 46, 47, 216, 45, 46, 222, 47, 48, 220, 47, 47, 254, 250, 250, 212, 43, 45, 224, 48, 49, 214, 44, 46, 254, 248, 248, 208, 42, 44, 255, 252, 252, 251, 250, 250, 228, 52, 52, 204, 40, 43, 197, 37, 40, 200, 39, 42, 186, 32, 37, 194, 36, 40, 33, 33, 33, 191, 35, 38, 189, 34, 38, 180, 30, 35, 210, 42, 44, 30, 30, 30, 129, 10, 20, 173, 27, 33, 23, 23, 23, 207, 40, 43, 225, 31, 31, 228, 44, 44, 10, 10, 10, 202, 39, 42, 183, 31, 36, 170, 26, 32, 165, 24, 30, 134, 12, 22, 124, 7, 18, 236, 116, 116, 228, 48, 47, 19, 19, 19, 223, 50, 50, 176, 28, 34, 37, 37, 37, 138, 13, 23, 178, 29, 35, 204, 45, 47, 194, 40, 44, 227, 38, 38, 143, 14, 23, 150, 17, 25, 168, 25, 31, 156, 20, 28, 208, 47, 49, 229, 56, 56, 175, 33, 39, 212, 47, 49, 166, 31, 38, 189, 39, 43, 202, 28, 30, 189, 17, 21, 181, 12, 17, 196, 25, 29, 200, 45, 48, 199, 32, 35, 189, 24, 28, 132, 0, 6, 224, 55, 55, 213, 27, 29, 147, 22, 30, 49, 94, 55, 29, 0, 0, 0, 182, 116, 82, 78, 83, 251, 225, 254, 254, 248, 245, 246, 254, 254, 253, 250, 244, 254, 254, 248, 253, 254, 249, 245, 246, 254, 254, 248, 254, 254, 254, 254, 248, 248, 254, 253, 246, 246, 244, 254, 253, 245, 243, 237, 252, 246, 244, 244, 241, 240, 236, 233, 254, 254, 249, 247, 246, 245, 242, 238, 238, 254, 253, 250, 249, 245, 244, 240, 254, 254, 248, 247, 245, 243, 243, 243, 242, 240, 235, 254, 254, 254, 250, 249, 249, 248, 248, 247, 246, 242, 241, 252, 252, 248, 248, 246, 246, 244, 244, 244, 243, 243, 240, 240, 238, 237, 249, 247, 247, 246, 244, 243, 243, 242, 242, 242, 242, 240, 240, 239, 238, 232, 232, 230, 227, 250, 246, 245, 243, 241, 240, 240, 240, 239, 235, 235, 253, 251, 249, 248, 247, 246, 245, 244, 244, 243, 242, 241, 241, 241, 241, 240, 240, 240, 239, 238, 238, 234, 233, 246, 244, 243, 242, 237, 236, 236, 234, 231, 230, 223, 247, 243, 241, 240, 229, 225, 224, 249, 246, 242, 241, 233, 233, 222, 246, 228, 205, 116, 60, 49, 81, 0, 0, 16, 106, 73, 68, 65, 84, 120, 218, 236, 152, 107, 72, 83, 97, 24, 199, 79, 99, 45, 87, 224, 22, 203, 196, 133, 177, 21, 131, 16, 196, 76, 6, 102, 152, 87, 76, 42, 161, 164, 48, 161, 68, 76, 45, 162, 15, 154, 69, 217, 69, 165, 18, 9, 42, 75, 211, 50, 42, 250, 16, 93, 232, 94, 116, 222, 179, 153, 206, 53, 215, 230, 20, 83, 54, 84, 212, 37, 50, 209, 121, 75, 179, 214, 197, 174, 207, 251, 158, 169, 179, 102, 185, 210, 250, 80, 255, 47, 162, 135, 115, 254, 191, 247, 121, 159, 247, 121, 158, 87, 106, 6, 77, 209, 127, 83, 255, 1, 254, 3, 252, 7, 248, 15, 240, 207, 0, 32, 231, 127, 254, 99, 0, 218, 191, 11, 128, 84, 19, 133, 224, 207, 0, 168, 24, 90, 20, 233, 252, 209, 159, 0, 64, 26, 154, 146, 110, 136, 164, 145, 211, 24, 76, 63, 0, 44, 223, 125, 151, 79, 230, 4, 123, 48, 253, 0, 120, 249, 193, 11, 19, 16, 173, 117, 250, 120, 186, 1, 24, 154, 150, 109, 240, 111, 92, 205, 5, 16, 167, 154, 102, 0, 45, 77, 101, 6, 244, 244, 4, 203, 38, 244, 159, 70, 0, 146, 116, 155, 54, 242, 155, 218, 125, 164, 19, 251, 79, 31, 0, 98, 16, 205, 141, 246, 105, 212, 41, 252, 19, 40, 154, 113, 164, 114, 212, 180, 1, 32, 176, 140, 60, 181, 176, 125, 80, 201, 223, 136, 19, 128, 97, 24, 45, 136, 249, 214, 127, 154, 0, 16, 164, 252, 130, 132, 185, 61, 131, 58, 5, 127, 142, 140, 246, 164, 39, 210, 20, 2, 32, 134, 195, 209, 170, 158, 170, 176, 96, 157, 104, 103, 112, 163, 114, 150, 66, 217, 30, 112, 28, 63, 164, 104, 138, 75, 115, 100, 243, 35, 139, 139, 101, 104, 170, 0, 16, 195, 112, 84, 156, 167, 79, 53, 154, 121, 26, 45, 195, 161, 29, 21, 116, 194, 31, 47, 95, 169, 208, 37, 165, 236, 78, 59, 178, 101, 239, 209, 139, 247, 79, 203, 31, 156, 190, 184, 119, 119, 16, 188, 249, 219, 0, 104, 222, 188, 121, 42, 237, 120, 79, 88, 34, 119, 166, 40, 197, 215, 119, 93, 90, 73, 70, 240, 66, 88, 62, 72, 41, 73, 140, 47, 202, 13, 20, 8, 4, 111, 189, 228, 23, 143, 108, 34, 86, 232, 183, 35, 128, 236, 249, 204, 229, 209, 59, 82, 82, 10, 118, 175, 88, 81, 82, 88, 120, 239, 210, 173, 59, 55, 18, 207, 95, 139, 253, 18, 117, 121, 31, 89, 190, 82, 169, 91, 19, 223, 42, 8, 20, 228, 134, 159, 78, 150, 202, 184, 216, 71, 245, 148, 161, 127, 123, 11, 16, 45, 42, 185, 80, 82, 248, 240, 225, 165, 236, 236, 236, 3, 7, 14, 220, 221, 102, 108, 91, 251, 145, 213, 210, 222, 222, 162, 152, 193, 193, 79, 74, 236, 63, 168, 14, 244, 16, 196, 203, 47, 110, 205, 225, 17, 115, 79, 13, 174, 199, 83, 1, 144, 146, 189, 60, 110, 57, 209, 90, 144, 209, 104, 236, 236, 236, 236, 253, 66, 20, 181, 127, 214, 160, 197, 162, 192, 210, 241, 35, 18, 47, 110, 89, 231, 78, 190, 175, 113, 52, 255, 253, 45, 240, 189, 187, 188, 13, 100, 4, 61, 39, 234, 196, 8, 189, 189, 177, 151, 99, 148, 138, 50, 53, 184, 67, 252, 155, 54, 250, 138, 200, 183, 85, 26, 21, 222, 181, 169, 4, 160, 211, 226, 226, 218, 226, 218, 28, 32, 176, 127, 103, 148, 68, 167, 44, 179, 168, 73, 250, 233, 218, 131, 69, 184, 29, 145, 83, 9, 154, 74, 0, 32, 64, 133, 16, 130, 241, 0, 157, 120, 249, 101, 101, 106, 53, 1, 208, 41, 125, 118, 210, 90, 21, 155, 114, 83, 14, 0, 181, 157, 186, 180, 220, 56, 206, 255, 121, 148, 68, 161, 46, 47, 83, 91, 0, 0, 251, 251, 71, 147, 22, 224, 50, 0, 114, 34, 167, 49, 88, 146, 77, 8, 70, 178, 0, 150, 175, 46, 47, 135, 0, 128, 192, 95, 199, 223, 192, 163, 85, 180, 203, 0, 32, 39, 52, 204, 119, 66, 140, 22, 39, 162, 145, 4, 224, 227, 71, 227, 54, 88, 126, 121, 41, 248, 19, 2, 124, 0, 32, 1, 52, 244, 47, 0, 120, 6, 205, 230, 241, 240, 169, 69, 20, 232, 199, 111, 94, 136, 91, 219, 134, 79, 225, 129, 75, 55, 31, 236, 179, 60, 46, 45, 135, 8, 176, 254, 150, 166, 128, 157, 224, 239, 50, 0, 196, 122, 93, 226, 249, 27, 55, 110, 220, 202, 191, 149, 159, 127, 243, 102, 242, 22, 80, 73, 73, 218, 58, 144, 175, 111, 78, 80, 80, 144, 72, 36, 218, 129, 48, 28, 151, 139, 104, 170, 48, 110, 237, 129, 236, 123, 190, 51, 87, 6, 243, 75, 31, 151, 150, 130, 255, 200, 22, 204, 141, 70, 180, 74, 133, 92, 4, 32, 4, 23, 250, 150, 190, 240, 88, 138, 229, 193, 106, 251, 118, 65, 96, 96, 110, 110, 81, 209, 229, 240, 240, 240, 131, 242, 7, 242, 245, 235, 215, 175, 58, 124, 248, 230, 209, 132, 132, 115, 249, 23, 224, 160, 7, 173, 90, 252, 217, 27, 252, 9, 0, 155, 132, 202, 176, 59, 23, 220, 113, 245, 97, 92, 4, 192, 105, 187, 34, 170, 239, 149, 219, 43, 86, 47, 177, 188, 132, 93, 117, 194, 150, 234, 103, 207, 66, 67, 63, 124, 248, 16, 242, 238, 13, 104, 17, 209, 226, 171, 50, 90, 116, 86, 178, 216, 219, 251, 201, 24, 0, 72, 41, 137, 253, 184, 52, 113, 139, 12, 1, 130, 214, 197, 28, 128, 228, 90, 225, 182, 244, 149, 27, 200, 108, 238, 239, 111, 109, 53, 153, 76, 29, 0, 0, 242, 122, 13, 234, 238, 238, 126, 79, 100, 181, 90, 7, 6, 108, 233, 91, 87, 45, 246, 91, 243, 228, 201, 99, 135, 8, 88, 148, 49, 81, 207, 221, 220, 60, 60, 14, 38, 231, 80, 128, 160, 114, 237, 20, 48, 140, 157, 192, 12, 0, 173, 24, 160, 163, 163, 163, 174, 174, 174, 165, 165, 186, 26, 162, 80, 91, 91, 83, 83, 83, 85, 101, 48, 52, 55, 55, 235, 27, 6, 26, 242, 196, 222, 67, 21, 4, 96, 36, 7, 45, 138, 185, 69, 198, 190, 190, 23, 175, 94, 6, 10, 34, 206, 172, 227, 98, 4, 151, 142, 33, 7, 19, 120, 188, 34, 0, 253, 44, 64, 215, 40, 64, 45, 6, 168, 98, 1, 244, 250, 134, 202, 202, 138, 161, 138, 138, 10, 240, 119, 216, 2, 101, 196, 182, 94, 0, 48, 183, 190, 244, 250, 240, 38, 108, 213, 202, 29, 24, 193, 5, 0, 216, 5, 66, 224, 16, 129, 46, 236, 223, 50, 22, 0, 2, 160, 39, 0, 149, 245, 224, 207, 2, 148, 179, 0, 10, 201, 182, 231, 189, 189, 47, 220, 204, 173, 29, 194, 215, 221, 195, 182, 188, 99, 25, 34, 220, 143, 92, 40, 68, 90, 198, 78, 96, 79, 1, 66, 64, 0, 48, 129, 115, 0, 54, 0, 24, 32, 38, 182, 173, 179, 183, 15, 3, 116, 9, 159, 213, 188, 183, 214, 251, 249, 93, 77, 144, 81, 208, 23, 38, 95, 9, 25, 66, 240, 210, 100, 122, 201, 74, 232, 5, 122, 141, 213, 77, 100, 0, 53, 55, 59, 5, 80, 207, 77, 141, 123, 206, 2, 152, 186, 90, 158, 213, 24, 244, 67, 222, 165, 124, 126, 192, 174, 67, 92, 8, 3, 154, 36, 0, 33, 136, 218, 78, 36, 24, 209, 91, 44, 56, 129, 239, 64, 19, 71, 64, 17, 17, 103, 100, 1, 250, 77, 117, 213, 181, 85, 134, 134, 250, 39, 229, 22, 69, 83, 207, 220, 141, 82, 30, 4, 23, 77, 10, 128, 212, 131, 130, 221, 32, 24, 247, 142, 128, 246, 130, 146, 147, 147, 143, 130, 146, 174, 128, 222, 15, 235, 157, 0, 0, 1, 36, 192, 120, 128, 230, 202, 138, 199, 229, 106, 139, 78, 217, 222, 227, 127, 106, 25, 32, 32, 39, 0, 92, 196, 124, 175, 137, 10, 8, 226, 114, 41, 74, 26, 102, 179, 218, 183, 160, 194, 17, 64, 29, 147, 186, 173, 141, 5, 128, 28, 36, 0, 13, 0, 80, 6, 243, 9, 168, 169, 103, 78, 180, 200, 133, 171, 25, 135, 5, 193, 34, 63, 237, 66, 248, 214, 39, 53, 216, 172, 250, 134, 6, 54, 0, 99, 91, 96, 137, 127, 225, 182, 205, 8, 254, 118, 128, 238, 225, 97, 177, 216, 111, 223, 62, 190, 93, 141, 11, 125, 118, 69, 82, 223, 220, 11, 10, 60, 11, 82, 82, 82, 68, 238, 11, 176, 220, 71, 181, 224, 7, 227, 4, 98, 104, 105, 179, 109, 128, 0, 216, 203, 0, 27, 128, 48, 55, 115, 127, 20, 156, 194, 62, 114, 10, 91, 34, 178, 182, 74, 151, 101, 102, 102, 46, 27, 83, 102, 244, 74, 247, 241, 31, 166, 30, 165, 221, 187, 4, 195, 245, 181, 107, 215, 206, 159, 79, 76, 76, 60, 136, 37, 151, 167, 167, 159, 165, 104, 213, 143, 8, 244, 64, 48, 14, 160, 84, 45, 49, 187, 65, 237, 138, 101, 1, 76, 112, 10, 195, 214, 75, 121, 78, 222, 254, 46, 7, 230, 21, 164, 21, 230, 223, 57, 31, 75, 90, 160, 32, 48, 180, 58, 36, 100, 120, 248, 246, 185, 159, 16, 88, 197, 64, 48, 6, 80, 90, 22, 147, 234, 134, 43, 87, 106, 108, 39, 201, 193, 174, 150, 218, 170, 69, 139, 210, 79, 68, 34, 90, 235, 233, 169, 81, 105, 88, 169, 38, 200, 1, 138, 203, 43, 72, 219, 155, 127, 58, 49, 62, 55, 48, 244, 67, 173, 193, 58, 144, 119, 150, 11, 4, 104, 194, 255, 62, 172, 204, 19, 15, 56, 22, 194, 152, 8, 226, 223, 209, 149, 26, 59, 122, 8, 172, 3, 126, 159, 125, 72, 13, 112, 94, 135, 88, 128, 217, 156, 167, 64, 200, 254, 198, 219, 92, 188, 37, 41, 75, 30, 30, 178, 104, 145, 205, 6, 49, 208, 210, 200, 249, 85, 216, 83, 67, 101, 220, 246, 27, 114, 0, 8, 51, 247, 219, 91, 103, 234, 216, 41, 108, 24, 90, 195, 95, 232, 179, 1, 239, 132, 6, 91, 252, 160, 14, 48, 42, 205, 8, 5, 87, 20, 185, 242, 236, 153, 235, 251, 243, 146, 120, 227, 19, 6, 105, 73, 32, 237, 195, 54, 181, 85, 226, 55, 52, 2, 80, 46, 73, 5, 127, 82, 180, 171, 189, 162, 70, 78, 161, 30, 202, 128, 229, 83, 123, 163, 255, 169, 147, 164, 33, 160, 159, 14, 36, 28, 248, 60, 34, 127, 167, 22, 108, 222, 153, 177, 153, 0, 32, 196, 1, 186, 177, 203, 21, 76, 100, 238, 178, 67, 210, 147, 209, 233, 226, 17, 128, 114, 239, 120, 51, 246, 39, 61, 163, 214, 43, 202, 108, 234, 128, 66, 12, 0, 79, 74, 203, 212, 186, 65, 101, 15, 63, 56, 90, 6, 201, 160, 153, 76, 29, 128, 117, 218, 41, 224, 5, 208, 104, 9, 231, 82, 188, 160, 156, 226, 173, 103, 147, 14, 175, 79, 223, 47, 177, 222, 22, 215, 215, 215, 219, 203, 64, 76, 132, 25, 122, 22, 241, 135, 166, 93, 19, 111, 110, 37, 157, 128, 5, 80, 40, 8, 2, 52, 4, 10, 143, 105, 147, 43, 68, 48, 120, 143, 76, 149, 20, 151, 18, 109, 46, 222, 186, 55, 41, 235, 180, 60, 60, 60, 44, 36, 4, 186, 129, 109, 88, 172, 175, 108, 0, 0, 123, 33, 12, 107, 53, 129, 125, 157, 144, 244, 108, 232, 151, 241, 173, 117, 66, 12, 80, 207, 2, 0, 130, 14, 42, 161, 207, 134, 157, 60, 140, 48, 249, 155, 81, 80, 113, 218, 150, 228, 172, 251, 242, 240, 8, 97, 40, 59, 18, 134, 132, 64, 39, 50, 232, 173, 32, 210, 9, 8, 64, 169, 36, 213, 84, 55, 186, 124, 240, 111, 142, 40, 234, 170, 126, 86, 133, 1, 236, 133, 152, 69, 128, 134, 176, 18, 16, 84, 204, 164, 0, 16, 162, 55, 201, 61, 114, 5, 48, 21, 135, 134, 182, 144, 165, 213, 116, 119, 227, 97, 128, 52, 67, 82, 8, 89, 127, 239, 120, 19, 59, 52, 217, 231, 5, 67, 243, 254, 43, 123, 66, 187, 171, 12, 99, 157, 128, 141, 130, 174, 157, 15, 201, 0, 249, 200, 160, 73, 0, 176, 4, 2, 47, 50, 146, 146, 105, 196, 97, 28, 113, 4, 120, 28, 65, 252, 171, 89, 127, 242, 88, 156, 148, 28, 24, 98, 96, 123, 161, 162, 125, 84, 10, 128, 105, 106, 12, 56, 177, 9, 193, 199, 127, 10, 64, 10, 94, 206, 30, 32, 104, 17, 58, 25, 200, 42, 65, 245, 245, 126, 160, 48, 240, 23, 218, 67, 196, 62, 181, 138, 143, 229, 100, 189, 125, 175, 39, 0, 159, 2, 102, 205, 29, 39, 255, 125, 208, 147, 224, 235, 63, 5, 32, 131, 129, 47, 16, 8, 191, 153, 8, 155, 173, 184, 23, 138, 65, 146, 171, 171, 18, 164, 201, 130, 106, 97, 245, 104, 248, 73, 159, 174, 151, 72, 55, 135, 189, 179, 146, 67, 16, 112, 238, 80, 208, 166, 249, 142, 218, 52, 255, 248, 252, 73, 94, 207, 17, 38, 120, 235, 37, 28, 157, 201, 217, 12, 24, 182, 217, 108, 121, 251, 143, 157, 201, 56, 180, 0, 222, 230, 102, 189, 245, 114, 88, 62, 222, 154, 33, 191, 36, 110, 198, 155, 134, 10, 0, 176, 180, 67, 25, 114, 119, 178, 191, 147, 2, 160, 145, 138, 16, 124, 37, 215, 108, 66, 162, 138, 194, 48, 124, 208, 169, 193, 188, 14, 168, 145, 162, 205, 24, 106, 150, 63, 76, 136, 98, 17, 52, 149, 25, 53, 9, 149, 164, 17, 41, 73, 181, 236, 7, 202, 141, 185, 136, 114, 165, 166, 82, 32, 228, 54, 132, 112, 219, 230, 156, 171, 134, 83, 212, 232, 74, 161, 64, 102, 102, 151, 138, 144, 110, 148, 161, 12, 21, 165, 247, 124, 115, 244, 202, 205, 159, 153, 46, 67, 139, 222, 129, 81, 231, 220, 123, 223, 231, 251, 238, 249, 206, 185, 231, 56, 0, 128, 195, 44, 250, 224, 50, 138, 112, 249, 208, 163, 11, 189, 158, 6, 27, 139, 12, 21, 220, 241, 238, 215, 172, 17, 190, 124, 74, 113, 30, 107, 119, 176, 154, 220, 48, 141, 67, 131, 115, 174, 178, 46, 26, 3, 50, 124, 126, 191, 143, 228, 143, 42, 3, 6, 193, 15, 60, 148, 206, 142, 159, 94, 89, 92, 57, 219, 210, 223, 211, 212, 153, 206, 4, 109, 254, 80, 77, 203, 190, 186, 184, 100, 132, 143, 142, 233, 124, 95, 125, 159, 31, 104, 201, 114, 14, 201, 34, 88, 181, 79, 6, 48, 6, 48, 154, 147, 98, 223, 33, 33, 130, 241, 51, 139, 139, 43, 231, 30, 61, 125, 237, 105, 160, 61, 55, 161, 166, 4, 149, 205, 171, 149, 185, 75, 27, 225, 203, 145, 105, 184, 185, 139, 241, 187, 89, 67, 168, 66, 89, 130, 11, 64, 40, 173, 195, 195, 72, 100, 52, 22, 49, 1, 16, 193, 137, 202, 87, 61, 77, 87, 211, 109, 212, 51, 97, 46, 76, 61, 197, 83, 185, 252, 93, 86, 198, 23, 229, 63, 156, 244, 50, 155, 179, 59, 107, 211, 0, 24, 148, 12, 163, 246, 193, 128, 156, 16, 112, 122, 134, 30, 83, 6, 136, 224, 217, 93, 10, 28, 1, 40, 115, 243, 1, 142, 254, 220, 121, 233, 79, 3, 19, 252, 167, 63, 22, 117, 98, 36, 109, 119, 173, 2, 64, 150, 191, 154, 16, 146, 187, 170, 112, 157, 12, 127, 76, 0, 176, 141, 216, 32, 235, 219, 236, 206, 59, 106, 126, 126, 54, 210, 143, 21, 194, 244, 116, 210, 69, 52, 117, 54, 7, 71, 7, 200, 31, 28, 64, 24, 197, 156, 84, 123, 223, 70, 235, 246, 24, 0, 224, 237, 135, 185, 216, 182, 84, 51, 106, 114, 85, 239, 131, 191, 90, 37, 7, 235, 108, 92, 176, 91, 174, 5, 114, 87, 227, 49, 16, 228, 34, 197, 35, 231, 36, 159, 1, 96, 77, 228, 63, 63, 175, 194, 31, 146, 246, 180, 89, 89, 86, 133, 204, 101, 215, 5, 236, 240, 222, 16, 77, 8, 115, 165, 167, 186, 247, 32, 42, 159, 2, 176, 238, 159, 55, 79, 19, 51, 236, 35, 225, 211, 86, 105, 41, 54, 138, 4, 175, 42, 154, 179, 195, 85, 105, 64, 253, 72, 74, 74, 190, 117, 152, 234, 199, 50, 128, 224, 217, 23, 164, 191, 41, 124, 244, 252, 96, 29, 3, 29, 235, 118, 5, 39, 131, 127, 106, 46, 144, 90, 219, 201, 184, 176, 10, 160, 147, 191, 42, 62, 35, 124, 249, 154, 44, 187, 33, 151, 185, 159, 30, 23, 157, 74, 222, 82, 69, 111, 123, 15, 91, 204, 128, 240, 147, 127, 228, 169, 128, 226, 143, 132, 79, 0, 131, 165, 221, 224, 67, 146, 247, 238, 219, 90, 54, 223, 73, 7, 1, 88, 244, 15, 27, 189, 143, 194, 7, 0, 4, 2, 170, 3, 188, 118, 144, 197, 91, 224, 35, 127, 115, 239, 83, 37, 135, 123, 128, 127, 217, 233, 240, 0, 4, 137, 171, 119, 37, 106, 177, 146, 1, 129, 241, 175, 53, 47, 28, 254, 16, 89, 155, 170, 222, 39, 147, 15, 17, 72, 234, 19, 48, 238, 40, 75, 0, 228, 239, 12, 111, 238, 125, 235, 195, 46, 49, 32, 5, 181, 116, 237, 56, 1, 224, 254, 183, 170, 77, 82, 216, 147, 191, 52, 133, 12, 128, 228, 116, 28, 22, 31, 0, 21, 191, 211, 136, 31, 0, 102, 77, 166, 122, 184, 47, 62, 0, 66, 240, 189, 61, 89, 213, 213, 206, 106, 104, 21, 178, 111, 169, 209, 199, 76, 196, 5, 0, 254, 13, 253, 121, 107, 82, 46, 82, 96, 107, 185, 202, 210, 185, 47, 46, 0, 88, 26, 183, 95, 90, 215, 183, 237, 85, 123, 32, 62, 0, 144, 30, 53, 107, 188, 170, 224, 95, 3, 8, 93, 236, 46, 93, 236, 226, 255, 31, 125, 157, 47, 118, 0, 161, 67, 72, 32, 189, 235, 82, 220, 144, 78, 141, 230, 131, 77, 237, 166, 203, 141, 140, 140, 232, 127, 155, 1, 17, 221, 199, 98, 251, 63, 213, 87, 60, 18, 244, 24, 0, 24, 196, 133, 216, 120, 23, 194, 184, 50, 163, 70, 211, 7, 155, 28, 229, 241, 155, 9, 224, 203, 246, 28, 61, 194, 240, 91, 148, 0, 130, 231, 123, 221, 110, 239, 77, 222, 225, 118, 151, 228, 240, 138, 62, 183, 251, 161, 106, 2, 72, 35, 154, 220, 111, 174, 243, 17, 174, 148, 95, 114, 207, 139, 131, 117, 101, 153, 80, 209, 231, 117, 87, 192, 205, 240, 47, 190, 87, 112, 185, 224, 197, 3, 236, 251, 69, 7, 160, 243, 198, 122, 45, 84, 95, 44, 206, 107, 41, 245, 183, 217, 113, 45, 116, 165, 68, 36, 40, 0, 81, 162, 133, 82, 180, 107, 55, 249, 117, 5, 203, 111, 183, 105, 41, 109, 29, 17, 32, 161, 243, 163, 5, 218, 132, 230, 101, 60, 97, 253, 98, 236, 121, 189, 150, 50, 53, 17, 42, 207, 225, 251, 163, 205, 64, 78, 90, 226, 88, 90, 78, 126, 121, 98, 102, 121, 99, 254, 181, 196, 153, 52, 121, 174, 74, 78, 225, 68, 230, 204, 88, 90, 49, 63, 178, 14, 208, 145, 56, 51, 86, 168, 14, 16, 56, 183, 112, 42, 115, 172, 66, 168, 104, 1, 94, 124, 48, 148, 57, 51, 49, 245, 245, 50, 178, 22, 21, 0, 162, 248, 77, 125, 249, 242, 168, 15, 131, 113, 124, 161, 12, 113, 89, 205, 114, 98, 98, 9, 134, 240, 39, 16, 212, 178, 153, 217, 137, 51, 32, 72, 78, 128, 32, 72, 32, 128, 195, 99, 200, 229, 120, 9, 8, 2, 23, 12, 250, 210, 238, 21, 224, 106, 154, 84, 204, 54, 217, 251, 248, 61, 219, 122, 27, 151, 51, 76, 254, 38, 104, 186, 246, 233, 243, 201, 247, 249, 67, 87, 63, 73, 228, 140, 247, 67, 134, 78, 211, 79, 44, 80, 160, 145, 80, 45, 173, 62, 16, 227, 194, 218, 231, 0, 116, 55, 140, 69, 179, 157, 3, 116, 71, 146, 217, 123, 18, 230, 2, 244, 34, 198, 184, 231, 79, 252, 26, 169, 60, 27, 130, 198, 86, 34, 115, 118, 53, 44, 225, 204, 142, 17, 183, 215, 138, 61, 164, 218, 38, 98, 156, 33, 107, 149, 75, 242, 242, 102, 88, 114, 83, 37, 119, 197, 179, 250, 224, 220, 156, 22, 17, 104, 129, 5, 242, 107, 90, 87, 169, 242, 84, 8, 222, 7, 17, 218, 126, 251, 0, 96, 118, 131, 136, 155, 245, 60, 194, 83, 71, 178, 237, 9, 217, 59, 90, 161, 106, 111, 96, 196, 162, 7, 49, 87, 37, 49, 7, 65, 6, 109, 48, 80, 0, 247, 4, 160, 211, 78, 173, 73, 9, 0, 62, 112, 109, 113, 18, 230, 206, 148, 124, 169, 229, 193, 217, 97, 100, 245, 77, 105, 207, 193, 161, 74, 10, 15, 51, 190, 166, 176, 86, 8, 18, 84, 115, 128, 144, 172, 49, 138, 133, 175, 131, 1, 125, 30, 192, 7, 128, 94, 100, 94, 132, 217, 143, 133, 189, 2, 99, 165, 39, 44, 152, 46, 68, 25, 0, 212, 113, 227, 145, 228, 163, 21, 56, 204, 5, 177, 148, 32, 202, 166, 125, 49, 24, 147, 23, 149, 1, 207, 1, 128, 31, 102, 118, 112, 208, 195, 167, 45, 79, 244, 11, 243, 140, 150, 124, 51, 155, 160, 201, 27, 156, 167, 138, 224, 131, 67, 190, 100, 57, 73, 19, 65, 162, 24, 237, 30, 194, 93, 73, 94, 49, 14, 80, 180, 4, 192, 37, 98, 246, 132, 205, 231, 134, 109, 115, 209, 215, 8, 85, 41, 216, 195, 136, 185, 13, 112, 217, 207, 68, 166, 132, 174, 135, 76, 12, 26, 170, 8, 82, 65, 152, 13, 130, 132, 121, 75, 190, 67, 101, 226, 52, 13, 238, 79, 3, 44, 110, 80, 58, 144, 128, 115, 35, 102, 220, 254, 206, 107, 176, 1, 39, 217, 95, 95, 136, 139, 37, 249, 1, 56, 66, 14, 66, 204, 21, 0, 253, 156, 32, 238, 76, 139, 127, 3, 154, 120, 112, 49, 66, 206, 12, 246, 208, 39, 1, 180, 101, 34, 154, 191, 184, 2, 0, 26, 180, 242, 8, 184, 72, 48, 46, 49, 172, 5, 53, 5, 240, 186, 137, 98, 113, 208, 96, 86, 8, 210, 153, 181, 234, 144, 114, 89, 99, 60, 175, 180, 218, 90, 42, 128, 39, 21, 160, 164, 103, 48, 132, 174, 218, 97, 8, 66, 244, 126, 34, 64, 94, 54, 17, 231, 82, 34, 206, 147, 206, 211, 74, 61, 182, 7, 80, 101, 103, 104, 84, 10, 253, 104, 128, 102, 142, 227, 67, 222, 164, 204, 117, 115, 24, 220, 70, 192, 221, 209, 201, 189, 4, 0, 182, 184, 179, 39, 7, 108, 197, 163, 46, 4, 63, 19, 96, 106, 66, 27, 222, 28, 3, 22, 115, 255, 93, 181, 66, 232, 218, 177, 229, 230, 69, 240, 186, 132, 190, 27, 51, 233, 87, 73, 37, 107, 140, 142, 16, 152, 199, 92, 30, 75, 84, 1, 165, 7, 67, 70, 157, 5, 89, 194, 224, 169, 250, 9, 41, 189, 26, 24, 155, 11, 178, 55, 112, 100, 214, 19, 0, 0, 219, 15, 163, 200, 238, 22, 69, 208, 49, 4, 198, 50, 90, 106, 10, 192, 29, 226, 152, 35, 140, 47, 122, 41, 128, 221, 182, 217, 60, 83, 58, 223, 54, 189, 53, 248, 206, 34, 160, 191, 193, 244, 76, 72, 215, 107, 122, 183, 105, 18, 81, 10, 19, 120, 247, 213, 200, 195, 91, 191, 117, 154, 240, 120, 46, 81, 31, 231, 245, 131, 105, 179, 145, 55, 7, 255, 101, 110, 68, 53, 93, 215, 171, 217, 160, 50, 0, 126, 43, 122, 58, 13, 95, 146, 177, 242, 176, 115, 145, 219, 165, 123, 210, 109, 69, 66, 55, 198, 227, 113, 27, 138, 166, 252, 149, 44, 252, 53, 16, 250, 119, 181, 40, 182, 63, 123, 232, 239, 67, 232, 157, 148, 2, 80, 183, 72, 53, 168, 135, 86, 138, 183, 247, 199, 157, 149, 7, 191, 201, 218, 47, 171, 48, 155, 255, 103, 215, 242, 127, 195, 1, 70, 29, 48, 234, 128, 81, 7, 140, 58, 96, 212, 1, 163, 14, 24, 117, 0, 213, 1, 0, 87, 162, 212, 25, 139, 217, 220, 95, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}
diff --git a/v3/pkg/application/image.go b/v3/pkg/application/image.go
new file mode 100644
index 000000000..fd77e06fd
--- /dev/null
+++ b/v3/pkg/application/image.go
@@ -0,0 +1,20 @@
+package application
+
+import (
+ "bytes"
+ "image"
+ "image/draw"
+ "image/png"
+)
+
+func pngToImage(data []byte) (*image.RGBA, error) {
+ img, err := png.Decode(bytes.NewReader(data))
+ if err != nil {
+ return nil, err
+ }
+
+ bounds := img.Bounds()
+ rgba := image.NewRGBA(bounds)
+ draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
+ return rgba, nil
+}
diff --git a/v3/pkg/application/mainthread_windows.go b/v3/pkg/application/mainthread_windows.go
new file mode 100644
index 000000000..f2f03454c
--- /dev/null
+++ b/v3/pkg/application/mainthread_windows.go
@@ -0,0 +1,126 @@
+//go:build windows
+
+package application
+
+import (
+ "github.com/wailsapp/wails/v3/pkg/w32"
+ "runtime"
+ "sort"
+ "unsafe"
+)
+
+var (
+ wmInvokeCallback uint32
+)
+
+func init() {
+ wmInvokeCallback = w32.RegisterWindowMessage(w32.MustStringToUTF16Ptr("WailsV0.InvokeCallback"))
+}
+
+// initMainLoop must be called with the same OSThread that is used to call runMainLoop() later.
+func (m *windowsApp) initMainLoop() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if m.mainThreadWindowHWND != 0 {
+ panic("initMainLoop was already called")
+ }
+
+ // We need a hidden window so we can PostMessage to it, if we don't use PostMessage for dispatching to a HWND
+ // messages might get lost if a modal inner loop is being run.
+ // We had this once in V2: https://github.com/wailsapp/wails/issues/969
+ // See: https://devblogs.microsoft.com/oldnewthing/20050426-18/?p=35783
+ // See also: https://learn.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues#creating-a-message-loop
+ // > Because the system directs messages to individual windows in an application, a thread must create at least one window before starting its message loop.
+ m.mainThreadWindowHWND = w32.CreateWindowEx(
+ 0,
+ windowClassName,
+ w32.MustStringToUTF16Ptr("__wails_hidden_mainthread"),
+ w32.WS_DISABLED,
+ w32.CW_USEDEFAULT,
+ w32.CW_USEDEFAULT,
+ 0,
+ 0,
+ 0,
+ 0,
+ w32.GetModuleHandle(""),
+ nil)
+
+ m.mainThreadID, _ = w32.GetWindowThreadProcessId(m.mainThreadWindowHWND)
+}
+
+func (m *windowsApp) runMainLoop() int {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if m.invokeRequired() {
+ panic("invokeRequired for runMainLoop, the mainloop must be running on the same OSThread as the mainThreadWindow has been created on")
+ }
+
+ msg := (*w32.MSG)(unsafe.Pointer(w32.GlobalAlloc(0, uint32(unsafe.Sizeof(w32.MSG{})))))
+ defer w32.GlobalFree(w32.HGLOBAL(unsafe.Pointer(m)))
+
+ for w32.GetMessage(msg, 0, 0, 0) != 0 {
+ w32.TranslateMessage(msg)
+ w32.DispatchMessage(msg)
+ }
+
+ return int(msg.WParam)
+}
+
+func (m *windowsApp) dispatchOnMainThread(id uint) {
+ mainThreadHWND := m.mainThreadWindowHWND
+ if mainThreadHWND == 0 {
+ panic("initMainLoop was not called")
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if m.invokeRequired() {
+ w32.PostMessage(mainThreadHWND, wmInvokeCallback, uintptr(id), 0)
+ } else {
+ mainThreadFunctionStoreLock.Lock()
+ fn := mainThreadFunctionStore[id]
+ delete(mainThreadFunctionStore, id)
+ mainThreadFunctionStoreLock.Unlock()
+
+ if fn == nil {
+ Fatal("dispatchOnMainThread called with invalid id: %v", id)
+ }
+ fn()
+ }
+}
+
+func (m *windowsApp) invokeRequired() bool {
+ mainThreadID := m.mainThreadID
+ if mainThreadID == 0 {
+ panic("initMainLoop was not called")
+ }
+
+ return mainThreadID != w32.GetCurrentThreadId()
+}
+
+func (m *windowsApp) invokeCallback(wParam, lParam uintptr) {
+ // TODO: Should we invoke just one or all queued? In v2 we always invoked all pendings...
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if m.invokeRequired() {
+ panic("invokeCallback must always be called on the MainOSThread")
+ }
+
+ mainThreadFunctionStoreLock.Lock()
+ fnIDs := make([]uint, 0, len(mainThreadFunctionStore))
+ for id := range mainThreadFunctionStore {
+ fnIDs = append(fnIDs, id)
+ }
+ sort.Slice(fnIDs, func(i, j int) bool { return fnIDs[i] < fnIDs[j] })
+
+ fns := make([]func(), len(fnIDs))
+ for i, id := range fnIDs {
+ fns[i] = mainThreadFunctionStore[id]
+ delete(mainThreadFunctionStore, id)
+ }
+ mainThreadFunctionStoreLock.Unlock()
+
+ for _, fn := range fns {
+ fn()
+ }
+}
diff --git a/v3/pkg/application/menu.go b/v3/pkg/application/menu.go
index 80cf213dd..5a6139031 100644
--- a/v3/pkg/application/menu.go
+++ b/v3/pkg/application/menu.go
@@ -22,7 +22,7 @@ func (m *Menu) Add(label string) *MenuItem {
}
func (m *Menu) AddSeparator() {
- result := newMenuItemSeperator()
+ result := newMenuItemSeparator()
m.items = append(m.items, result)
}
@@ -96,14 +96,3 @@ func (m *Menu) setContextData(data *ContextMenuData) {
func (a *App) NewMenu() *Menu {
return &Menu{}
}
-
-func defaultApplicationMenu() *Menu {
- menu := NewMenu()
- menu.AddRole(AppMenu)
- menu.AddRole(FileMenu)
- menu.AddRole(EditMenu)
- menu.AddRole(ViewMenu)
- menu.AddRole(WindowMenu)
- menu.AddRole(HelpMenu)
- return menu
-}
diff --git a/v3/pkg/application/menu_darwin.go b/v3/pkg/application/menu_darwin.go
index b14be232a..250172f20 100644
--- a/v3/pkg/application/menu_darwin.go
+++ b/v3/pkg/application/menu_darwin.go
@@ -6,7 +6,7 @@ package application
#cgo CFLAGS: -mmacosx-version-min=10.10 -x objective-c
#cgo LDFLAGS: -framework Cocoa
-#include "menuitem.h"
+#include "menuitem_darwin.h"
extern void setMenuItemChecked(void*, unsigned int, bool);
@@ -103,3 +103,14 @@ func (m *macosMenu) processMenu(parent unsafe.Pointer, menu *Menu) {
}
}
+
+func defaultApplicationMenu() *Menu {
+ menu := NewMenu()
+ menu.AddRole(AppMenu)
+ menu.AddRole(FileMenu)
+ menu.AddRole(EditMenu)
+ menu.AddRole(ViewMenu)
+ menu.AddRole(WindowMenu)
+ menu.AddRole(HelpMenu)
+ return menu
+}
diff --git a/v3/pkg/application/menu_windows.go b/v3/pkg/application/menu_windows.go
new file mode 100644
index 000000000..efa1bd0ee
--- /dev/null
+++ b/v3/pkg/application/menu_windows.go
@@ -0,0 +1,121 @@
+//go:build windows
+
+package application
+
+import (
+ "github.com/wailsapp/wails/v3/pkg/w32"
+)
+
+type windowsMenu struct {
+ menu *Menu
+
+ hWnd w32.HWND
+ hMenu w32.HMENU
+ currentMenuID int
+ menuMapping map[int]*MenuItem
+ checkboxItems []*Menu
+}
+
+func newMenuImpl(menu *Menu) *windowsMenu {
+ result := &windowsMenu{
+ menu: menu,
+ menuMapping: make(map[int]*MenuItem),
+ }
+
+ return result
+}
+
+func (w *windowsMenu) update() {
+ if w.hMenu != 0 {
+ w32.DestroyMenu(w.hMenu)
+ }
+ w.hMenu = w32.NewPopupMenu()
+ w.processMenu(w.hMenu, w.menu)
+}
+
+func (w *windowsMenu) processMenu(parentMenu w32.HMENU, inputMenu *Menu) {
+ for _, item := range inputMenu.items {
+ if item.Hidden() {
+ continue
+ }
+ w.currentMenuID++
+ itemID := w.currentMenuID
+ w.menuMapping[itemID] = item
+
+ flags := uint32(w32.MF_STRING)
+ if item.disabled {
+ flags = flags | w32.MF_GRAYED
+ }
+ if item.checked {
+ flags = flags | w32.MF_CHECKED
+ }
+ if item.IsSeparator() {
+ flags = flags | w32.MF_SEPARATOR
+ }
+ //
+ //if item.IsCheckbox() {
+ // w.checkboxItems[item] = append(w.checkboxItems[item], itemID)
+ //}
+ //if item.IsRadio() {
+ // currentRadioGroup.Add(itemID, item)
+ //} else {
+ // if len(currentRadioGroup) > 0 {
+ // for _, radioMember := range currentRadioGroup {
+ // currentRadioGroup := currentRadioGroup
+ // p.radioGroups[radioMember.MenuItem] = append(p.radioGroups[radioMember.MenuItem], ¤tRadioGroup)
+ // }
+ // currentRadioGroup = RadioGroup{}
+ // }
+ //}
+
+ if item.submenu != nil {
+ flags = flags | w32.MF_POPUP
+ newSubmenu := w32.CreateMenu()
+ w.processMenu(newSubmenu, item.submenu)
+ itemID = int(newSubmenu)
+ }
+
+ var menuText = w32.MustStringToUTF16Ptr(item.Label())
+
+ w32.AppendMenu(parentMenu, flags, uintptr(itemID), menuText)
+ }
+}
+
+func (w *windowsMenu) ShowAtCursor() {
+ invokeSync(func() {
+ x, y, ok := w32.GetCursorPos()
+ if !ok {
+ return
+ }
+ w.ShowAt(x, y)
+ })
+}
+
+func (w *windowsMenu) ShowAt(x int, y int) {
+ w.update()
+ w32.TrackPopupMenuEx(w.hMenu,
+ w32.TPM_LEFTALIGN,
+ int32(x),
+ int32(y),
+ w.hWnd,
+ nil)
+ w32.PostMessage(w.hWnd, w32.WM_NULL, 0, 0)
+}
+
+func (w *windowsMenu) ProcessCommand(cmdMsgID int) {
+ item := w.menuMapping[cmdMsgID]
+ if item == nil {
+ return
+ }
+ item.handleClick()
+}
+
+func defaultApplicationMenu() *Menu {
+ menu := NewMenu()
+ menu.AddRole(FileMenu)
+ menu.AddRole(EditMenu)
+ menu.AddRole(ViewMenu)
+ menu.AddRole(WindowMenu)
+ menu.AddRole(HelpMenu)
+ return menu
+}
diff --git a/v3/pkg/application/menuitem.go b/v3/pkg/application/menuitem.go
index da943156b..e30750781 100644
--- a/v3/pkg/application/menuitem.go
+++ b/v3/pkg/application/menuitem.go
@@ -38,6 +38,7 @@ type menuItemImpl interface {
setDisabled(disabled bool)
setChecked(checked bool)
setAccelerator(accelerator *accelerator)
+ setHidden(hidden bool)
}
type MenuItem struct {
@@ -46,6 +47,7 @@ type MenuItem struct {
tooltip string
disabled bool
checked bool
+ hidden bool
submenu *Menu
callback func(*Context)
itemType menuItemType
@@ -67,7 +69,7 @@ func newMenuItem(label string) *MenuItem {
return result
}
-func newMenuItemSeperator() *MenuItem {
+func newMenuItemSeparator() *MenuItem {
result := &MenuItem{
itemType: separator,
}
@@ -173,6 +175,8 @@ func newRole(role Role) *MenuItem {
return newMinimizeMenuItem()
case Zoom:
return newZoomMenuItem()
+ case FullScreen:
+ return newFullScreenMenuItem()
default:
println("No support for role:", role)
@@ -255,10 +259,38 @@ func (m *MenuItem) SetChecked(checked bool) *MenuItem {
return m
}
+func (m *MenuItem) SetHidden(hidden bool) *MenuItem {
+ m.hidden = hidden
+ if m.impl != nil {
+ m.impl.setHidden(m.hidden)
+ }
+ return m
+}
+
func (m *MenuItem) Checked() bool {
return m.checked
}
+func (m *MenuItem) IsSeparator() bool {
+ return m.itemType == separator
+}
+
+func (m *MenuItem) IsSubmenu() bool {
+ return m.itemType == submenu
+}
+
+func (m *MenuItem) IsCheckbox() bool {
+ return m.itemType == checkbox
+}
+
+func (m *MenuItem) IsRadio() bool {
+ return m.itemType == radio
+}
+
+func (m *MenuItem) Hidden() bool {
+ return m.hidden
+}
+
func (m *MenuItem) OnClick(f func(*Context)) *MenuItem {
m.callback = f
return m
diff --git a/v3/pkg/application/menuitem_darwin.go b/v3/pkg/application/menuitem_darwin.go
index daee2a521..e8303e131 100644
--- a/v3/pkg/application/menuitem_darwin.go
+++ b/v3/pkg/application/menuitem_darwin.go
@@ -1,3 +1,5 @@
+//go:build darwin
+
package application
/*
@@ -5,8 +7,8 @@ package application
#cgo LDFLAGS: -framework Cocoa -framework WebKit
#include "Cocoa/Cocoa.h"
-#include "menuitem.h"
-#include "application.h"
+#include "menuitem_darwin.h"
+#include "application_darwin.h"
#define unicode(input) [NSString stringWithFormat:@"%C", input]
@@ -58,6 +60,14 @@ void setMenuItemDisabled(void* nsMenuItem, bool disabled) {
});
}
+// set menu item hidden
+void setMenuItemHidden(void* nsMenuItem, bool hidden) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ MenuItem *menuItem = (MenuItem *)nsMenuItem;
+ [menuItem setHidden:hidden];
+ });
+}
+
// set menu item tooltip
void setMenuItemTooltip(void* nsMenuItem, char *tooltip) {
MenuItem *menuItem = (MenuItem *)nsMenuItem;
@@ -329,29 +339,33 @@ import (
"unsafe"
)
-type macosMenuItem struct {
+type windowsMenuItem struct {
menuItem *MenuItem
nsMenuItem unsafe.Pointer
}
-func (m macosMenuItem) setTooltip(tooltip string) {
+func (m windowsMenuItem) setTooltip(tooltip string) {
C.setMenuItemTooltip(m.nsMenuItem, C.CString(tooltip))
}
-func (m macosMenuItem) setLabel(s string) {
+func (m windowsMenuItem) setLabel(s string) {
C.setMenuItemLabel(m.nsMenuItem, C.CString(s))
}
-func (m macosMenuItem) setDisabled(disabled bool) {
+func (m windowsMenuItem) setDisabled(disabled bool) {
C.setMenuItemDisabled(m.nsMenuItem, C.bool(disabled))
}
-func (m macosMenuItem) setChecked(checked bool) {
+func (m windowsMenuItem) setChecked(checked bool) {
C.setMenuItemChecked(m.nsMenuItem, C.bool(checked))
}
-func (m macosMenuItem) setAccelerator(accelerator *accelerator) {
+func (m windowsMenuItem) setHidden(hidden bool) {
+ C.setMenuItemHidden(m.nsMenuItem, C.bool(hidden))
+}
+
+func (m windowsMenuItem) setAccelerator(accelerator *accelerator) {
// Set the keyboard shortcut of the menu item
var modifier C.int
var key *C.char
@@ -364,8 +378,8 @@ func (m macosMenuItem) setAccelerator(accelerator *accelerator) {
C.setMenuItemKeyEquivalent(m.nsMenuItem, key, modifier)
}
-func newMenuItemImpl(item *MenuItem) *macosMenuItem {
- result := &macosMenuItem{
+func newMenuItemImpl(item *MenuItem) *windowsMenuItem {
+ result := &windowsMenuItem{
menuItem: item,
}
@@ -604,7 +618,7 @@ func newMinimizeMenuItem() *MenuItem {
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
- currentWindow.Minimize()
+ currentWindow.Minimise()
}
})
}
@@ -618,3 +632,13 @@ func newZoomMenuItem() *MenuItem {
}
})
}
+
+func newFullScreenMenuItem() *MenuItem {
+ return newMenuItem("Fullscreen").
+ OnClick(func(ctx *Context) {
+ currentWindow := globalApplication.CurrentWindow()
+ if currentWindow != nil {
+ currentWindow.Fullscreen()
+ }
+ })
+}
diff --git a/v3/pkg/application/menuitem.h b/v3/pkg/application/menuitem_darwin.h
similarity index 100%
rename from v3/pkg/application/menuitem.h
rename to v3/pkg/application/menuitem_darwin.h
diff --git a/v3/pkg/application/menuitem.m b/v3/pkg/application/menuitem_darwin.m
similarity index 84%
rename from v3/pkg/application/menuitem.m
rename to v3/pkg/application/menuitem_darwin.m
index f875d0de5..39369502d 100644
--- a/v3/pkg/application/menuitem.m
+++ b/v3/pkg/application/menuitem_darwin.m
@@ -2,7 +2,7 @@
#import
-#import "menuitem.h"
+#import "menuitem_darwin.h"
@implementation MenuItem
diff --git a/v3/pkg/application/menuitem_windows.go b/v3/pkg/application/menuitem_windows.go
new file mode 100644
index 000000000..9cec67a8e
--- /dev/null
+++ b/v3/pkg/application/menuitem_windows.go
@@ -0,0 +1,251 @@
+//go:build windows
+
+package application
+
+import (
+ "github.com/wailsapp/wails/v3/pkg/w32"
+ "unsafe"
+)
+
+type windowsMenuItem struct {
+ menuItem *MenuItem
+
+ hMenu w32.HMENU
+ id int
+ label string
+ disabled bool
+ checked bool
+ itemType menuItemType
+ hidden bool
+ submenu w32.HMENU
+}
+
+func (m *windowsMenuItem) setHidden(hidden bool) {
+ m.hidden = hidden
+}
+
+func (m *windowsMenuItem) Checked() bool {
+ return m.checked
+}
+
+func (m *windowsMenuItem) IsSeparator() bool {
+ return m.itemType == separator
+}
+
+func (m *windowsMenuItem) IsCheckbox() bool {
+ return m.itemType == checkbox
+}
+
+func (m *windowsMenuItem) Enabled() bool {
+ return !m.disabled
+}
+
+func (m *windowsMenuItem) update() {
+ var mii w32.MENUITEMINFO
+ mii.CbSize = uint32(unsafe.Sizeof(mii))
+ mii.FMask = w32.MIIM_FTYPE | w32.MIIM_ID | w32.MIIM_STATE | w32.MIIM_STRING
+ if m.IsSeparator() {
+ mii.FType = w32.MFT_SEPARATOR
+ } else {
+ mii.FType = w32.MFT_STRING
+ //var text string
+ //if s := a.shortcut; s.Key != 0 {
+ // text = fmt.Sprintf("%s\t%s", a.text, s.String())
+ // shortcut2Action[a.shortcut] = a
+ //} else {
+ // text = a.text
+ //}
+ mii.DwTypeData = w32.MustStringToUTF16Ptr(m.label)
+ mii.Cch = uint32(len([]rune(m.label)))
+ }
+ mii.WID = uint32(m.id)
+ if m.Enabled() {
+ mii.FState &^= w32.MFS_DISABLED
+ } else {
+ mii.FState |= w32.MFS_DISABLED
+ }
+
+ if m.IsCheckbox() {
+ mii.FMask |= w32.MIIM_CHECKMARKS
+ }
+ if m.Checked() {
+ mii.FState |= w32.MFS_CHECKED
+ }
+
+ if m.menuItem.submenu != nil {
+ mii.FMask |= w32.MIIM_SUBMENU
+ mii.HSubMenu = m.submenu
+ }
+
+ w32.SetMenuItemInfo(m.hMenu, uint32(m.id), false, &mii)
+}
+
+func (m *windowsMenuItem) setLabel(label string) {
+ m.label = label
+ m.update()
+}
+
+func (m *windowsMenuItem) setDisabled(disabled bool) {
+ m.disabled = disabled
+ m.update()
+}
+
+func (m *windowsMenuItem) setChecked(checked bool) {
+ m.checked = checked
+ m.update()
+}
+
+func (m *windowsMenuItem) setAccelerator(accelerator *accelerator) {
+ //// Set the keyboard shortcut of the menu item
+ //var modifier C.int
+ //var key *C.char
+ //if accelerator != nil {
+ // modifier = C.int(toMacModifier(accelerator.Modifiers))
+ // key = C.CString(accelerator.Key)
+ //}
+ //
+ //// Convert the key to a string
+ //C.setMenuItemKeyEquivalent(m.nsMenuItem, key, modifier)
+}
+
+func newMenuItemImpl(item *MenuItem, parentMenu w32.HMENU, ID int) *windowsMenuItem {
+ result := &windowsMenuItem{
+ menuItem: item,
+ hMenu: parentMenu,
+ id: ID,
+ disabled: item.disabled,
+ checked: item.checked,
+ itemType: item.itemType,
+ label: item.label,
+ hidden: item.hidden,
+ }
+
+ return result
+}
+
+func newSpeechMenu() *MenuItem {
+ panic("implement me")
+}
+
+func newHideMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newHideOthersMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newUnhideMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newUndoMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+// newRedoMenuItem creates a new menu item for redoing the last action
+func newRedoMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newCutMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newCopyMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newPasteMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newPasteAndMatchStyleMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newDeleteMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newQuitMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newSelectAllMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newAboutMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newCloseMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newReloadMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newForceReloadMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newToggleFullscreenMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newToggleDevToolsMenuItem() *MenuItem {
+ panic("implement me")
+}
+
+func newZoomResetMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newZoomInMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newZoomOutMenuItem() *MenuItem {
+ panic("implement me")
+
+}
+
+func newMinimizeMenuItem() *MenuItem {
+ panic("implement me")
+}
+
+func newZoomMenuItem() *MenuItem {
+ panic("implement me")
+}
+
+func newFullScreenMenuItem() *MenuItem {
+ panic("implement me")
+}
+
+// ---------- unsupported on windows ----------
+
+func (m *windowsMenuItem) setTooltip(_ string) {
+ // Unsupported
+}
diff --git a/v3/pkg/application/messageprocessor_window.go b/v3/pkg/application/messageprocessor_window.go
index cf36b9c31..7789cad7c 100644
--- a/v3/pkg/application/messageprocessor_window.go
+++ b/v3/pkg/application/messageprocessor_window.go
@@ -46,7 +46,7 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
window.UnFullscreen()
m.ok(rw)
case "Minimise":
- window.Minimize()
+ window.Minimise()
m.ok(rw)
case "UnMinimise":
window.UnMinimise()
@@ -102,7 +102,7 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
m.Error("Invalid SetBackgroundColour Message: 'a' value required")
return
}
- window.SetBackgroundColour(&RGBA{
+ window.SetBackgroundColour(RGBA{
Red: *r,
Green: *g,
Blue: *b,
diff --git a/v3/pkg/application/options_application.go b/v3/pkg/application/options_application.go
index 0a768a0b7..f37b2dc7e 100644
--- a/v3/pkg/application/options_application.go
+++ b/v3/pkg/application/options_application.go
@@ -12,6 +12,7 @@ type Options struct {
Description string
Icon []byte
Mac MacOptions
+ Windows WindowsApplicationOptions
Bind []any
Logger struct {
Silent bool
diff --git a/v3/pkg/application/options_mac.go b/v3/pkg/application/options_mac.go
index 7ad1c5f0f..109071021 100644
--- a/v3/pkg/application/options_mac.go
+++ b/v3/pkg/application/options_mac.go
@@ -44,6 +44,7 @@ const (
// MacWindow contains macOS specific options
type MacWindow struct {
Backdrop MacBackdrop
+ DisableShadow bool
TitleBar MacTitleBar
Appearance MacAppearanceType
InvisibleTitleBarHeight int
diff --git a/v3/pkg/application/options_webview_window.go b/v3/pkg/application/options_webview_window.go
index 99e40d054..3367ccd2d 100644
--- a/v3/pkg/application/options_webview_window.go
+++ b/v3/pkg/application/options_webview_window.go
@@ -12,7 +12,8 @@ const (
type WebviewWindowOptions struct {
Name string
Title string
- Width, Height int
+ Width int
+ Height int
AlwaysOnTop bool
URL string
DisableResize bool
@@ -22,8 +23,9 @@ type WebviewWindowOptions struct {
MaxWidth int
MaxHeight int
StartState WindowState
- Mac MacWindow
- BackgroundColour *RGBA
+ Centered bool
+ BackgroundType BackgroundType
+ BackgroundColour RGBA
HTML string
JS string
CSS string
@@ -34,7 +36,12 @@ type WebviewWindowOptions struct {
Hidden bool
EnableFraudulentWebsiteWarnings bool
Zoom float64
+ ZoomControlEnabled bool
EnableDragAndDrop bool
+ OpenInspectorOnStartup bool
+ Mac MacWindow
+ Windows WindowsWindow
+ Focused bool
}
var WebviewWindowDefaults = &WebviewWindowOptions{
@@ -42,8 +49,22 @@ var WebviewWindowDefaults = &WebviewWindowOptions{
Width: 800,
Height: 600,
URL: "",
+ BackgroundColour: RGBA{
+ Red: 255,
+ Green: 255,
+ Blue: 255,
+ Alpha: 255,
+ },
}
type RGBA struct {
Red, Green, Blue, Alpha uint8
}
+
+type BackgroundType int
+
+const (
+ BackgroundTypeSolid BackgroundType = iota
+ BackgroundTypeTransparent
+ BackgroundTypeTranslucent
+)
diff --git a/v3/pkg/application/options_win.go b/v3/pkg/application/options_win.go
new file mode 100644
index 000000000..cefd32195
--- /dev/null
+++ b/v3/pkg/application/options_win.go
@@ -0,0 +1,83 @@
+package application
+
+type WindowsApplicationOptions struct {
+ // WndProcInterceptor is a function that will be called for every message sent in the application.
+ // Use this to hook into the main message loop. This is useful for handling custom window messages.
+ // If `shouldReturn` is `true` then `returnCode` will be returned by the main message loop.
+ // If `shouldReturn` is `false` then returnCode will be ignored and the message will be processed by the main message loop.
+ WndProcInterceptor func(hwnd uintptr, msg uint32, wParam, lParam uintptr) (returnCode uintptr, shouldReturn bool)
+
+ // DisableQuitOnLastWindowClosed disables the auto quit of the application if the last window has been closed.
+ DisableQuitOnLastWindowClosed bool
+}
+
+type BackdropType int32
+
+const (
+ Auto BackdropType = 0
+ None BackdropType = 1
+ Mica BackdropType = 2
+ Acrylic BackdropType = 3
+ Tabbed BackdropType = 4
+)
+
+type WindowsWindow struct {
+ // Select the type of translucent backdrop. Requires Windows 11 22621 or later.
+ BackdropType BackdropType
+ // Disable the icon in the titlebar
+ DisableIcon bool
+ // Theme. Defaults to SystemDefault which will use whatever the system theme is. The application will follow system theme changes.
+ Theme Theme
+ // Custom colours for dark/light mode
+ CustomTheme *ThemeSettings
+
+ // Disable all window decorations in Frameless mode, which means no "Aero Shadow" and no "Rounded Corner" will be shown.
+ // "Rounded Corners" are only available on Windows 11.
+ DisableFramelessWindowDecorations bool
+
+ // WindowMask is used to set the window shape. Use a PNG with an alpha channel to create a custom shape.
+ WindowMask []byte
+ WindowMaskDraggable bool
+
+ // Path where the WebView2 stores the user data. If empty %APPDATA%\[BinaryName.exe] will be used.
+ // If the path is not valid, a messagebox will be displayed with the error and the app will exit with error code.
+ WebviewUserDataPath string
+
+ // Path to the directory with WebView2 executables. If empty WebView2 installed in the system will be used.
+ WebviewBrowserPath string
+
+ // WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview
+ WebviewGpuIsDisabled bool
+
+ // ResizeDebounceMS is the amount of time to debounce redraws of webview2
+ // when resizing the window
+ ResizeDebounceMS uint16
+}
+
+type Theme int
+
+const (
+ // SystemDefault will use whatever the system theme is. The application will follow system theme changes.
+ SystemDefault Theme = 0
+ // Dark Mode
+ Dark Theme = 1
+ // Light Mode
+ Light Theme = 2
+)
+
+// ThemeSettings defines custom colours to use in dark or light mode.
+// They may be set using the hex values: 0x00BBGGRR
+type ThemeSettings struct {
+ DarkModeTitleBar int32
+ DarkModeTitleBarInactive int32
+ DarkModeTitleText int32
+ DarkModeTitleTextInactive int32
+ DarkModeBorder int32
+ DarkModeBorderInactive int32
+ LightModeTitleBar int32
+ LightModeTitleBarInactive int32
+ LightModeTitleText int32
+ LightModeTitleTextInactive int32
+ LightModeBorder int32
+ LightModeBorderInactive int32
+}
diff --git a/v3/pkg/application/popupmenu_windows.go b/v3/pkg/application/popupmenu_windows.go
new file mode 100644
index 000000000..dd77042a4
--- /dev/null
+++ b/v3/pkg/application/popupmenu_windows.go
@@ -0,0 +1,213 @@
+package application
+
+import (
+ "fmt"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+)
+
+const (
+ MenuItemMsgID = w32.WM_APP + 1024
+)
+
+type RadioGroupMember struct {
+ ID int
+ MenuItem *MenuItem
+}
+
+type RadioGroup []*RadioGroupMember
+
+func (r *RadioGroup) Add(id int, item *MenuItem) {
+ *r = append(*r, &RadioGroupMember{
+ ID: id,
+ MenuItem: item,
+ })
+}
+
+func (r *RadioGroup) Bounds() (int, int) {
+ p := *r
+ return p[0].ID, p[len(p)-1].ID
+}
+
+func (r *RadioGroup) MenuID(item *MenuItem) int {
+ for _, member := range *r {
+ if member.MenuItem == item {
+ return member.ID
+ }
+ }
+ panic("RadioGroup.MenuID: item not found:")
+}
+
+type PopupMenu struct {
+ menu w32.PopupMenu
+ parent w32.HWND
+ menuMapping map[int]*MenuItem
+ checkboxItems map[*MenuItem][]int
+ radioGroups map[*MenuItem][]*RadioGroup
+ menuData *Menu
+ currentMenuID int
+ onMenuClose func()
+ onMenuOpen func()
+}
+
+func (p *PopupMenu) buildMenu(parentMenu w32.PopupMenu, inputMenu *Menu) {
+ var currentRadioGroup RadioGroup
+ for _, item := range inputMenu.items {
+ if item.Hidden() {
+ continue
+ }
+ p.currentMenuID++
+ itemID := p.currentMenuID
+ p.menuMapping[itemID] = item
+
+ menuItemImpl := newMenuItemImpl(item, w32.HWND(parentMenu), itemID)
+
+ flags := uint32(w32.MF_STRING)
+ if item.disabled {
+ flags = flags | w32.MF_GRAYED
+ }
+ if item.checked && item.IsCheckbox() {
+ flags = flags | w32.MF_CHECKED
+ }
+ if item.IsSeparator() {
+ flags = flags | w32.MF_SEPARATOR
+ }
+
+ if item.IsCheckbox() {
+ p.checkboxItems[item] = append(p.checkboxItems[item], itemID)
+ }
+ if item.IsRadio() {
+ currentRadioGroup.Add(itemID, item)
+ } else {
+ if len(currentRadioGroup) > 0 {
+ for _, radioMember := range currentRadioGroup {
+ currentRadioGroup := currentRadioGroup
+ p.radioGroups[radioMember.MenuItem] = append(p.radioGroups[radioMember.MenuItem], ¤tRadioGroup)
+ }
+ currentRadioGroup = RadioGroup{}
+ }
+ }
+
+ if item.submenu != nil {
+ flags = flags | w32.MF_POPUP
+ newSubmenu := w32.CreatePopupMenu()
+ p.buildMenu(newSubmenu, item.submenu)
+ itemID = int(newSubmenu)
+ menuItemImpl.submenu = w32.HWND(newSubmenu)
+ }
+
+ var menuText = item.Label()
+
+ ok := parentMenu.Append(flags, uintptr(itemID), menuText)
+ if !ok {
+ w32.Fatal(fmt.Sprintf("Error adding menu item: %s", menuText))
+ }
+
+ item.impl = menuItemImpl
+ }
+ if len(currentRadioGroup) > 0 {
+ for _, radioMember := range currentRadioGroup {
+ currentRadioGroup := currentRadioGroup
+ p.radioGroups[radioMember.MenuItem] = append(p.radioGroups[radioMember.MenuItem], ¤tRadioGroup)
+ }
+ currentRadioGroup = RadioGroup{}
+ }
+}
+
+func (p *PopupMenu) Update() {
+ p.menu = w32.CreatePopupMenu()
+ p.menuMapping = make(map[int]*MenuItem)
+ p.currentMenuID = MenuItemMsgID
+ p.buildMenu(p.menu, p.menuData)
+ p.updateRadioGroups()
+}
+
+func NewPopupMenu(parent w32.HWND, inputMenu *Menu) *PopupMenu {
+ result := &PopupMenu{
+ parent: parent,
+ menuData: inputMenu,
+ checkboxItems: make(map[*MenuItem][]int),
+ radioGroups: make(map[*MenuItem][]*RadioGroup),
+ }
+ result.Update()
+ return result
+}
+
+func (p *PopupMenu) ShowAtCursor() {
+ x, y, ok := w32.GetCursorPos()
+ if ok == false {
+ w32.Fatal("GetCursorPos failed")
+ }
+
+ w32.SetForegroundWindow(p.parent)
+
+ if p.onMenuOpen != nil {
+ p.onMenuOpen()
+ }
+
+ if p.menu.Track(p.parent, w32.TPM_LEFTALIGN, int32(x), int32(y-5)) == false {
+ w32.Fatal("TrackPopupMenu failed")
+ }
+
+ if p.onMenuClose != nil {
+ p.onMenuClose()
+ }
+
+ if !w32.PostMessage(p.parent, w32.WM_NULL, 0, 0) {
+ w32.Fatal("PostMessage failed")
+ }
+
+}
+
+func (p *PopupMenu) ProcessCommand(cmdMsgID int) {
+ item := p.menuMapping[cmdMsgID]
+ if item == nil {
+ return
+ }
+ if item.IsRadio() {
+ item.checked = true
+ p.updateRadioGroup(item)
+ }
+ if item.callback != nil {
+ item.handleClick()
+ }
+}
+
+func (p *PopupMenu) Destroy() {
+ p.menu.Destroy()
+}
+
+func (p *PopupMenu) UpdateMenuItem(item *MenuItem) {
+ if item.IsCheckbox() {
+ for _, itemID := range p.checkboxItems[item] {
+ p.menu.Check(uintptr(itemID), item.checked)
+ }
+ return
+ }
+ if item.IsRadio() && item.checked == true {
+ p.updateRadioGroup(item)
+ }
+}
+
+func (p *PopupMenu) updateRadioGroups() {
+ for menuItem := range p.radioGroups {
+ if menuItem.checked {
+ p.updateRadioGroup(menuItem)
+ }
+ }
+}
+
+func (p *PopupMenu) updateRadioGroup(item *MenuItem) {
+ for _, radioGroup := range p.radioGroups[item] {
+ thisMenuID := radioGroup.MenuID(item)
+ startID, endID := radioGroup.Bounds()
+ p.menu.CheckRadio(startID, endID, thisMenuID)
+ }
+}
+
+func (p *PopupMenu) OnMenuOpen(fn func()) {
+ p.onMenuOpen = fn
+}
+
+func (p *PopupMenu) OnMenuClose(fn func()) {
+ p.onMenuClose = fn
+}
diff --git a/v3/pkg/application/roles.go b/v3/pkg/application/roles.go
index 0aec3bd48..fe48a0d1e 100644
--- a/v3/pkg/application/roles.go
+++ b/v3/pkg/application/roles.go
@@ -42,8 +42,9 @@ const (
ZoomOut Role = iota
ToggleFullscreen Role = iota
- Minimize Role = iota
- Zoom Role = iota
+ Minimize Role = iota
+ Zoom Role = iota
+ FullScreen Role = iota
//Front Role = iota
//WindowRole Role = iota
@@ -132,6 +133,12 @@ func newWindowMenu() *MenuItem {
menu := NewMenu()
menu.AddRole(Minimize)
menu.AddRole(Zoom)
+ if runtime.GOOS == "darwin" {
+ menu.AddSeparator()
+ menu.AddRole(FullScreen)
+ } else {
+ menu.AddRole(Close)
+ }
subMenu := newSubMenuItem("Window")
subMenu.submenu = menu
return subMenu
diff --git a/v3/pkg/application/screen_darwin.go b/v3/pkg/application/screen_darwin.go
index d45753f7b..0669d531a 100644
--- a/v3/pkg/application/screen_darwin.go
+++ b/v3/pkg/application/screen_darwin.go
@@ -128,12 +128,12 @@ func cScreenToScreen(screen C.Screen) *Screen {
}
}
-func getPrimaryScreen() (*Screen, error) {
+func (m *macosApp) getPrimaryScreen() (*Screen, error) {
cScreen := C.GetPrimaryScreen()
return cScreenToScreen(cScreen), nil
}
-func getScreens() ([]*Screen, error) {
+func (m *macosApp) getScreens() ([]*Screen, error) {
cScreens := C.getAllScreens()
defer C.free(unsafe.Pointer(cScreens))
numScreens := int(C.GetNumScreens())
diff --git a/v3/pkg/application/systemtray.go b/v3/pkg/application/systemtray.go
index 23ba6f286..4cb95e14d 100644
--- a/v3/pkg/application/systemtray.go
+++ b/v3/pkg/application/systemtray.go
@@ -22,14 +22,25 @@ type systemTrayImpl interface {
setIconPosition(position int)
setTemplateIcon(icon []byte)
destroy()
+ setDarkModeIcon(icon []byte)
}
type SystemTray struct {
id uint
label string
icon []byte
+ darkModeIcon []byte
iconPosition int
+ clickHandler func()
+ rightClickHandler func()
+ doubleClickHandler func()
+ rightDoubleClickHandler func()
+ mouseEnterHandler func()
+ mouseLeaveHandler func()
+ onMenuOpen func()
+ onMenuClose func()
+
// Platform specific implementation
impl systemTrayImpl
menu *Menu
@@ -49,23 +60,38 @@ func (s *SystemTray) SetLabel(label string) {
s.label = label
return
}
- s.impl.setLabel(label)
+ invokeSync(func() {
+ s.impl.setLabel(label)
+ })
}
func (s *SystemTray) Label() string {
return s.label
}
-func (s *SystemTray) Run() {
+func (s *SystemTray) run() {
s.impl = newSystemTrayImpl(s)
- s.impl.run()
+ invokeSync(s.impl.run)
}
func (s *SystemTray) SetIcon(icon []byte) *SystemTray {
if s.impl == nil {
s.icon = icon
} else {
- s.impl.setIcon(icon)
+ invokeSync(func() {
+ s.impl.setIcon(icon)
+ })
+ }
+ return s
+}
+
+func (s *SystemTray) SetDarkModeIcon(icon []byte) *SystemTray {
+ if s.impl == nil {
+ s.darkModeIcon = icon
+ } else {
+ invokeSync(func() {
+ s.impl.setDarkModeIcon(icon)
+ })
}
return s
}
@@ -74,7 +100,9 @@ func (s *SystemTray) SetMenu(menu *Menu) *SystemTray {
if s.impl == nil {
s.menu = menu
} else {
- s.impl.setMenu(menu)
+ invokeSync(func() {
+ s.impl.setMenu(menu)
+ })
}
return s
}
@@ -83,7 +111,9 @@ func (s *SystemTray) SetIconPosition(iconPosition int) *SystemTray {
if s.impl == nil {
s.iconPosition = iconPosition
} else {
- s.impl.setIconPosition(iconPosition)
+ invokeSync(func() {
+ s.impl.setIconPosition(iconPosition)
+ })
}
return s
}
@@ -93,7 +123,9 @@ func (s *SystemTray) SetTemplateIcon(icon []byte) *SystemTray {
s.icon = icon
s.isTemplateIcon = true
} else {
- s.impl.setTemplateIcon(icon)
+ invokeSync(func() {
+ s.impl.setTemplateIcon(icon)
+ })
}
return s
}
@@ -104,3 +136,33 @@ func (s *SystemTray) Destroy() {
}
s.impl.destroy()
}
+
+func (s *SystemTray) OnClick(handler func()) *SystemTray {
+ s.clickHandler = handler
+ return s
+}
+
+func (s *SystemTray) OnRightClick(handler func()) *SystemTray {
+ s.rightClickHandler = handler
+ return s
+}
+
+func (s *SystemTray) OnDoubleClick(handler func()) *SystemTray {
+ s.doubleClickHandler = handler
+ return s
+}
+
+func (s *SystemTray) OnRightDoubleClick(handler func()) *SystemTray {
+ s.rightDoubleClickHandler = handler
+ return s
+}
+
+func (s *SystemTray) OnMouseEnter(handler func()) *SystemTray {
+ s.mouseEnterHandler = handler
+ return s
+}
+
+func (s *SystemTray) OnMouseLeave(handler func()) *SystemTray {
+ s.mouseLeaveHandler = handler
+ return s
+}
diff --git a/v3/pkg/application/systemtray_darwin.go b/v3/pkg/application/systemtray_darwin.go
index f5a464341..b176ab6b2 100644
--- a/v3/pkg/application/systemtray_darwin.go
+++ b/v3/pkg/application/systemtray_darwin.go
@@ -7,7 +7,7 @@ package application
#cgo LDFLAGS: -framework Cocoa -framework WebKit
#include "Cocoa/Cocoa.h"
-#include "menuitem.h"
+#include "menuitem_darwin.h"
// Create a new system tray
void* systemTrayNew() {
@@ -91,6 +91,10 @@ type macosSystemTray struct {
isTemplateIcon bool
}
+func (s *macosSystemTray) setDarkModeIcon(icon []byte) {
+ // Is this even possible?
+}
+
func (s *macosSystemTray) setIconPosition(position int) {
s.iconPosition = position
}
diff --git a/v3/pkg/application/systemtray_windows.go b/v3/pkg/application/systemtray_windows.go
new file mode 100644
index 000000000..513a67639
--- /dev/null
+++ b/v3/pkg/application/systemtray_windows.go
@@ -0,0 +1,250 @@
+//go:build windows
+
+package application
+
+import (
+ "github.com/wailsapp/wails/v3/pkg/icons"
+ "syscall"
+ "unsafe"
+
+ "github.com/samber/lo"
+ "github.com/wailsapp/wails/v3/pkg/events"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+)
+
+const (
+ WM_USER_SYSTRAY = w32.WM_USER + 1
+)
+
+type windowsSystemTray struct {
+ parent *SystemTray
+
+ menu *PopupMenu
+
+ // Platform specific implementation
+ uid uint32
+ hwnd w32.HWND
+ lightModeIcon w32.HICON
+ darkModeIcon w32.HICON
+ currentIcon w32.HICON
+}
+
+func (s *windowsSystemTray) setMenu(menu *Menu) {
+ s.updateMenu(menu)
+}
+
+func (s *windowsSystemTray) run() {
+ s.hwnd = w32.CreateWindowEx(
+ 0,
+ windowClassName,
+ nil,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ w32.HWND_MESSAGE,
+ 0,
+ 0,
+ nil)
+ if s.hwnd == 0 {
+ panic(syscall.GetLastError())
+ }
+
+ nid := w32.NOTIFYICONDATA{
+ HWnd: s.hwnd,
+ UID: uint32(s.parent.id),
+ UFlags: w32.NIF_ICON | w32.NIF_MESSAGE,
+ HIcon: s.currentIcon,
+ UCallbackMessage: WM_USER_SYSTRAY,
+ }
+ nid.CbSize = uint32(unsafe.Sizeof(nid))
+
+ if !w32.ShellNotifyIcon(w32.NIM_ADD, &nid) {
+ panic(syscall.GetLastError())
+ }
+
+ nid.UVersion = w32.NOTIFYICON_VERSION
+
+ if !w32.ShellNotifyIcon(w32.NIM_SETVERSION, &nid) {
+ panic(syscall.GetLastError())
+ }
+
+ if s.parent.icon != nil {
+ s.lightModeIcon = lo.Must(w32.CreateHIconFromImage(s.parent.icon))
+ } else {
+ s.lightModeIcon = lo.Must(w32.CreateHIconFromImage(icons.SystrayLight))
+ }
+ if s.parent.darkModeIcon != nil {
+ s.darkModeIcon = lo.Must(w32.CreateHIconFromImage(s.parent.darkModeIcon))
+ } else {
+ s.darkModeIcon = lo.Must(w32.CreateHIconFromImage(icons.SystrayDark))
+ }
+ s.uid = nid.UID
+
+ if s.parent.menu != nil {
+ s.updateMenu(s.parent.menu)
+ }
+
+ // Set Default Callbacks
+ if s.parent.clickHandler == nil {
+ s.parent.clickHandler = func() {
+ println("Left Button Clicked")
+ }
+ }
+ if s.parent.rightClickHandler == nil {
+ s.parent.rightClickHandler = func() {
+ if s.menu != nil {
+ s.menu.ShowAtCursor()
+ }
+ }
+ }
+
+ // Update the icon
+ s.updateIcon()
+
+ // Listen for dark mode changes
+ globalApplication.On(events.Windows.SystemThemeChanged, func() {
+ s.updateIcon()
+ })
+
+ // Register the system tray
+ getNativeApplication().registerSystemTray(s)
+
+}
+
+func (s *windowsSystemTray) updateIcon() {
+
+ var newIcon w32.HICON
+ if w32.IsCurrentlyDarkMode() {
+ newIcon = s.darkModeIcon
+ } else {
+ newIcon = s.lightModeIcon
+ }
+ if s.currentIcon == newIcon {
+ return
+ }
+
+ s.currentIcon = newIcon
+ nid := s.newNotifyIconData()
+ nid.UFlags = w32.NIF_ICON
+ if s.currentIcon != 0 {
+ nid.HIcon = s.currentIcon
+ }
+
+ if !w32.ShellNotifyIcon(w32.NIM_MODIFY, &nid) {
+ panic(syscall.GetLastError())
+ }
+ return
+}
+
+func (s *windowsSystemTray) newNotifyIconData() w32.NOTIFYICONDATA {
+ nid := w32.NOTIFYICONDATA{
+ UID: s.uid,
+ HWnd: s.hwnd,
+ }
+ nid.CbSize = uint32(unsafe.Sizeof(nid))
+ return nid
+}
+
+func (s *windowsSystemTray) setIcon(icon []byte) {
+ var err error
+ s.lightModeIcon, err = w32.CreateHIconFromImage(icon)
+ if err != nil {
+ panic(syscall.GetLastError())
+ }
+ if s.darkModeIcon == 0 {
+ s.darkModeIcon = s.lightModeIcon
+ }
+ // Update the icon
+ s.updateIcon()
+}
+func (s *windowsSystemTray) setDarkModeIcon(icon []byte) {
+ var err error
+ s.darkModeIcon, err = w32.CreateHIconFromImage(icon)
+ if err != nil {
+ panic(syscall.GetLastError())
+ }
+ if s.lightModeIcon == 0 {
+ s.lightModeIcon = s.darkModeIcon
+ }
+ // Update the icon
+ s.updateIcon()
+}
+
+func newSystemTrayImpl(parent *SystemTray) systemTrayImpl {
+ return &windowsSystemTray{
+ parent: parent,
+ }
+}
+
+func (s *windowsSystemTray) wndProc(msg uint32, wParam, lParam uintptr) uintptr {
+ switch msg {
+ case WM_USER_SYSTRAY:
+ msg := lParam & 0xffff
+ switch msg {
+ case w32.WM_LBUTTONUP:
+ if s.parent.clickHandler != nil {
+ s.parent.clickHandler()
+ }
+ case w32.WM_RBUTTONUP:
+ if s.parent.rightClickHandler != nil {
+ s.parent.rightClickHandler()
+ }
+ case w32.WM_LBUTTONDBLCLK:
+ if s.parent.doubleClickHandler != nil {
+ s.parent.doubleClickHandler()
+ }
+ case w32.WM_RBUTTONDBLCLK:
+ if s.parent.rightDoubleClickHandler != nil {
+ s.parent.rightDoubleClickHandler()
+ }
+ case 0x0406:
+ if s.parent.mouseEnterHandler != nil {
+ s.parent.mouseEnterHandler()
+ }
+ case 0x0407:
+ if s.parent.mouseLeaveHandler != nil {
+ s.parent.mouseLeaveHandler()
+ }
+ }
+ //println(w32.WMMessageToString(msg))
+
+ // TODO: Menu processing
+ case w32.WM_COMMAND:
+ cmdMsgID := int(wParam & 0xffff)
+ switch cmdMsgID {
+ default:
+ s.menu.ProcessCommand(cmdMsgID)
+ }
+ default:
+ //msg := int(wParam & 0xffff)
+ //println(w32.WMMessageToString(uintptr(msg)))
+ }
+
+ return w32.DefWindowProc(s.hwnd, msg, wParam, lParam)
+}
+
+func (s *windowsSystemTray) updateMenu(menu *Menu) {
+ s.menu = NewPopupMenu(s.hwnd, menu)
+ s.menu.onMenuOpen = s.parent.onMenuOpen
+ s.menu.onMenuClose = s.parent.onMenuClose
+ s.menu.Update()
+}
+
+// ---- Unsupported ----
+
+func (s *windowsSystemTray) setLabel(_ string) {
+ // Unsupported - do nothing
+}
+
+func (s *windowsSystemTray) setTemplateIcon(_ []byte) {
+ // Unsupported - do nothing
+}
+
+func (s *windowsSystemTray) setIconPosition(position int) {
+ // Unsupported - do nothing
+}
+
+func (s *windowsSystemTray) destroy() {
+}
diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go
index e9899fe82..736dacc1a 100644
--- a/v3/pkg/application/webview_window.go
+++ b/v3/pkg/application/webview_window.go
@@ -1,7 +1,9 @@
package application
import (
+ "errors"
"fmt"
+ "github.com/samber/lo"
"sync"
"time"
@@ -20,8 +22,7 @@ type (
setMinSize(width, height int)
setMaxSize(width, height int)
execJS(js string)
- restore()
- setBackgroundColour(color *RGBA)
+ setBackgroundColour(color RGBA)
run()
center()
size() (int, int)
@@ -51,27 +52,38 @@ type (
isMinimised() bool
isMaximised() bool
isFullscreen() bool
- disableSizeConstraints()
+ isNormal() bool
+ isVisible() bool
setFullscreenButtonEnabled(enabled bool)
+ focus()
show()
hide()
getScreen() (*Screen, error)
setFrameless(bool)
openContextMenu(menu *Menu, data *ContextMenuData)
+ nativeWindowHandle() uintptr
}
)
+type WindowEventListener struct {
+ callback func(ctx *WindowEventContext)
+}
+
type WebviewWindow struct {
- options *WebviewWindowOptions
+ options WebviewWindowOptions
impl webviewWindowImpl
implLock sync.RWMutex
id uint
- eventListeners map[uint][]func(ctx *WindowEventContext)
+ eventListeners map[uint][]*WindowEventListener
eventListenersLock sync.RWMutex
contextMenus map[string]*Menu
contextMenusLock sync.RWMutex
+
+ // A map of listener cancellation functions
+ cancellersLock sync.RWMutex
+ cancellers []func()
}
var windowID uint
@@ -84,7 +96,15 @@ func getWindowID() uint {
return windowID
}
-func NewWindow(options *WebviewWindowOptions) *WebviewWindow {
+// Use onApplicationEvent to register a callback for an application event from a window.
+// This will handle tidying up the callback when the window is destroyed
+func (w *WebviewWindow) onApplicationEvent(eventType events.ApplicationEventType, callback func()) {
+ cancelFn := globalApplication.On(eventType, callback)
+ w.addCancellationFunction(cancelFn)
+}
+
+// NewWindow creates a new window with the given options
+func NewWindow(options WebviewWindowOptions) *WebviewWindow {
if options.Width == 0 {
options.Width = 800
}
@@ -98,27 +118,38 @@ func NewWindow(options *WebviewWindowOptions) *WebviewWindow {
result := &WebviewWindow{
id: getWindowID(),
options: options,
- eventListeners: make(map[uint][]func(ctx *WindowEventContext)),
+ eventListeners: make(map[uint][]*WindowEventListener),
contextMenus: make(map[string]*Menu),
}
return result
}
+func (w *WebviewWindow) addCancellationFunction(canceller func()) {
+ w.cancellersLock.Lock()
+ defer w.cancellersLock.Unlock()
+ w.cancellers = append(w.cancellers, canceller)
+}
+
+// SetTitle sets the title of the window
func (w *WebviewWindow) SetTitle(title string) *WebviewWindow {
w.implLock.RLock()
defer w.implLock.RUnlock()
w.options.Title = title
if w.impl != nil {
- w.impl.setTitle(title)
+ invokeSync(func() {
+ w.impl.setTitle(title)
+ })
}
return w
}
+// Name returns the name of the window
func (w *WebviewWindow) Name() string {
return w.options.Name
}
+// SetSize sets the size of the window
func (w *WebviewWindow) SetSize(width, height int) *WebviewWindow {
// Don't set size if fullscreen
if w.IsFullscreen() {
@@ -154,7 +185,9 @@ func (w *WebviewWindow) SetSize(width, height int) *WebviewWindow {
}
if w.impl != nil {
- w.impl.setSize(width, height)
+ invokeSync(func() {
+ w.impl.setSize(width, height)
+ })
}
return w
}
@@ -166,17 +199,21 @@ func (w *WebviewWindow) run() {
w.implLock.Lock()
w.impl = newWindowImpl(w)
w.implLock.Unlock()
- w.impl.run()
+ invokeSync(w.impl.run)
}
+// SetAlwaysOnTop sets the window to be always on top.
func (w *WebviewWindow) SetAlwaysOnTop(b bool) *WebviewWindow {
w.options.AlwaysOnTop = b
- if w.impl == nil {
- w.impl.setAlwaysOnTop(b)
+ if w.impl != nil {
+ invokeSync(func() {
+ w.impl.setAlwaysOnTop(b)
+ })
}
return w
}
+// Show shows the window.
func (w *WebviewWindow) Show() *WebviewWindow {
if globalApplication.impl == nil {
return w
@@ -185,13 +222,15 @@ func (w *WebviewWindow) Show() *WebviewWindow {
w.run()
return w
}
- w.impl.show()
+ invokeSync(w.impl.show)
return w
}
+
+// Hide hides the window.
func (w *WebviewWindow) Hide() *WebviewWindow {
w.options.Hidden = true
if w.impl != nil {
- w.impl.hide()
+ invokeSync(w.impl.hide)
}
return w
}
@@ -199,38 +238,49 @@ func (w *WebviewWindow) Hide() *WebviewWindow {
func (w *WebviewWindow) SetURL(s string) *WebviewWindow {
w.options.URL = s
if w.impl != nil {
- w.impl.setURL(s)
+ invokeSync(func() {
+ w.impl.setURL(s)
+ })
}
return w
}
+// SetZoom sets the zoom level of the window.
func (w *WebviewWindow) SetZoom(magnification float64) *WebviewWindow {
w.options.Zoom = magnification
if w.impl != nil {
- w.impl.setZoom(magnification)
+ invokeSync(func() {
+ w.impl.setZoom(magnification)
+ })
}
return w
}
+// GetZoom returns the current zoom level of the window.
func (w *WebviewWindow) GetZoom() float64 {
if w.impl != nil {
- return w.impl.getZoom()
+ return invokeSyncWithResult(w.impl.getZoom)
}
return 1
}
+// SetResizable sets whether the window is resizable.
func (w *WebviewWindow) SetResizable(b bool) *WebviewWindow {
w.options.DisableResize = !b
if w.impl != nil {
- w.impl.setResizable(b)
+ invokeSync(func() {
+ w.impl.setResizable(b)
+ })
}
return w
}
+// Resizable returns true if the window is resizable.
func (w *WebviewWindow) Resizable() bool {
return !w.options.DisableResize
}
+// SetMinSize sets the minimum size of the window.
func (w *WebviewWindow) SetMinSize(minWidth, minHeight int) *WebviewWindow {
w.options.MinWidth = minWidth
w.options.MinHeight = minHeight
@@ -251,13 +301,18 @@ func (w *WebviewWindow) SetMinSize(minWidth, minHeight int) *WebviewWindow {
}
if w.impl != nil {
if newSize {
- w.impl.setSize(newWidth, newHeight)
+ invokeSync(func() {
+ w.impl.setSize(newWidth, newHeight)
+ })
}
- w.impl.setMinSize(minWidth, minHeight)
+ invokeSync(func() {
+ w.impl.setMinSize(minWidth, minHeight)
+ })
}
return w
}
+// SetMaxSize sets the maximum size of the window.
func (w *WebviewWindow) SetMaxSize(maxWidth, maxHeight int) *WebviewWindow {
w.options.MaxWidth = maxWidth
w.options.MaxHeight = maxHeight
@@ -278,13 +333,18 @@ func (w *WebviewWindow) SetMaxSize(maxWidth, maxHeight int) *WebviewWindow {
}
if w.impl != nil {
if newSize {
- w.impl.setSize(newWidth, newHeight)
+ invokeSync(func() {
+ w.impl.setSize(newWidth, newHeight)
+ })
}
- w.impl.setMaxSize(maxWidth, maxHeight)
+ invokeSync(func() {
+ w.impl.setMaxSize(maxWidth, maxHeight)
+ })
}
return w
}
+// ExecJS executes the given javascript in the context of the window.
func (w *WebviewWindow) ExecJS(js string) {
if w.impl == nil {
return
@@ -292,6 +352,7 @@ func (w *WebviewWindow) ExecJS(js string) {
w.impl.execJS(js)
}
+// Fullscreen sets the window to fullscreen mode. Min/Max size constraints are disabled.
func (w *WebviewWindow) Fullscreen() *WebviewWindow {
if w.impl == nil {
w.options.StartState = WindowStateFullscreen
@@ -299,7 +360,7 @@ func (w *WebviewWindow) Fullscreen() *WebviewWindow {
}
if !w.IsFullscreen() {
w.disableSizeConstraints()
- w.impl.fullscreen()
+ invokeSync(w.impl.fullscreen)
}
return w
}
@@ -307,7 +368,9 @@ func (w *WebviewWindow) Fullscreen() *WebviewWindow {
func (w *WebviewWindow) SetFullscreenButtonEnabled(enabled bool) *WebviewWindow {
w.options.FullscreenButtonEnabled = enabled
if w.impl != nil {
- w.impl.setFullscreenButtonEnabled(enabled)
+ invokeSync(func() {
+ w.impl.setFullscreenButtonEnabled(enabled)
+ })
}
return w
}
@@ -317,7 +380,15 @@ func (w *WebviewWindow) IsMinimised() bool {
if w.impl == nil {
return false
}
- return w.impl.isMinimised()
+ return invokeSyncWithResult(w.impl.isMinimised)
+}
+
+// IsVisible returns true if the window is visible
+func (w *WebviewWindow) IsVisible() bool {
+ if w.impl == nil {
+ return false
+ }
+ return invokeSyncWithResult(w.impl.isVisible)
}
// IsMaximised returns true if the window is maximised
@@ -325,15 +396,19 @@ func (w *WebviewWindow) IsMaximised() bool {
if w.impl == nil {
return false
}
- return w.impl.isMaximised()
+ return invokeSyncWithResult(w.impl.isMaximised)
}
// Size returns the size of the window
-func (w *WebviewWindow) Size() (width int, height int) {
+func (w *WebviewWindow) Size() (int, int) {
if w.impl == nil {
return 0, 0
}
- return w.impl.size()
+ var width, height int
+ invokeSync(func() {
+ width, height = w.impl.size()
+ })
+ return width, height
}
// IsFullscreen returns true if the window is fullscreen
@@ -343,13 +418,16 @@ func (w *WebviewWindow) IsFullscreen() bool {
if w.impl == nil {
return false
}
- return w.impl.isFullscreen()
+ return invokeSyncWithResult(w.impl.isFullscreen)
}
-func (w *WebviewWindow) SetBackgroundColour(colour *RGBA) *WebviewWindow {
+// SetBackgroundColour sets the background colour of the window
+func (w *WebviewWindow) SetBackgroundColour(colour RGBA) *WebviewWindow {
w.options.BackgroundColour = colour
if w.impl != nil {
- w.impl.setBackgroundColour(colour)
+ invokeSync(func() {
+ w.impl.setBackgroundColour(colour)
+ })
}
return w
}
@@ -358,170 +436,206 @@ func (w *WebviewWindow) handleMessage(message string) {
w.info(message)
// Check for special messages
if message == "test" {
- w.SetTitle("Hello World")
+ invokeSync(func() {
+ w.SetTitle("Hello World")
+ })
}
w.info("ProcessMessage from front end:", message)
}
+// Center centers the window on the screen
func (w *WebviewWindow) Center() {
if w.impl == nil {
+ w.options.Centered = true
return
}
- w.impl.center()
+ invokeSync(w.impl.center)
}
-func (w *WebviewWindow) On(eventType events.WindowEventType, callback func(ctx *WindowEventContext)) {
+// On registers a callback for the given window event
+func (w *WebviewWindow) On(eventType events.WindowEventType, callback func(ctx *WindowEventContext)) func() {
eventID := uint(eventType)
w.eventListenersLock.Lock()
defer w.eventListenersLock.Unlock()
- w.eventListeners[eventID] = append(w.eventListeners[eventID], callback)
+ windowEventListener := &WindowEventListener{
+ callback: callback,
+ }
+ w.eventListeners[eventID] = append(w.eventListeners[eventID], windowEventListener)
if w.impl != nil {
w.impl.on(eventID)
}
+
+ return func() {
+ w.eventListenersLock.Lock()
+ defer w.eventListenersLock.Unlock()
+ w.eventListeners[eventID] = lo.Without(w.eventListeners[eventID], windowEventListener)
+ }
+
}
func (w *WebviewWindow) handleWindowEvent(id uint) {
w.eventListenersLock.RLock()
- for _, callback := range w.eventListeners[id] {
- go callback(blankWindowEventContext)
+ for _, listener := range w.eventListeners[id] {
+ go listener.callback(blankWindowEventContext)
}
w.eventListenersLock.RUnlock()
}
+// Width returns the width of the window
func (w *WebviewWindow) Width() int {
if w.impl == nil {
return 0
}
- return w.impl.width()
+ return invokeSyncWithResult(w.impl.width)
}
+// Height returns the height of the window
func (w *WebviewWindow) Height() int {
if w.impl == nil {
return 0
}
- return w.impl.height()
+ return invokeSyncWithResult(w.impl.height)
}
+// Position returns the position of the window
func (w *WebviewWindow) Position() (int, int) {
w.implLock.RLock()
defer w.implLock.RUnlock()
if w.impl == nil {
return 0, 0
}
- return w.impl.position()
+ var x, y int
+ invokeSync(func() {
+ x, y = w.impl.position()
+ })
+ return x, y
}
func (w *WebviewWindow) Destroy() {
if w.impl == nil {
return
}
- w.impl.destroy()
+ // Cancel the callbacks
+ for _, cancelFunc := range w.cancellers {
+ cancelFunc()
+ }
+ invokeSync(w.impl.destroy)
}
+// Reload reloads the page assets
func (w *WebviewWindow) Reload() {
if w.impl == nil {
return
}
- w.impl.reload()
+ invokeSync(w.impl.reload)
}
+// ForceReload forces the window to reload the page assets
func (w *WebviewWindow) ForceReload() {
if w.impl == nil {
return
}
- w.impl.forceReload()
+ invokeSync(w.impl.forceReload)
}
+// ToggleFullscreen toggles the window between fullscreen and normal
func (w *WebviewWindow) ToggleFullscreen() {
if w.impl == nil {
return
}
- if w.IsFullscreen() {
- w.UnFullscreen()
- } else {
- w.Fullscreen()
- }
+ invokeSync(func() {
+ if w.IsFullscreen() {
+ w.UnFullscreen()
+ } else {
+ w.Fullscreen()
+ }
+ })
}
func (w *WebviewWindow) ToggleDevTools() {
if w.impl == nil {
return
}
- w.impl.toggleDevTools()
+ invokeSync(w.impl.toggleDevTools)
}
+// ZoomReset resets the zoom level of the webview content to 100%
func (w *WebviewWindow) ZoomReset() *WebviewWindow {
if w.impl != nil {
- w.impl.zoomReset()
+ invokeSync(w.impl.zoomReset)
}
return w
}
+// ZoomIn increases the zoom level of the webview content
func (w *WebviewWindow) ZoomIn() {
if w.impl == nil {
return
}
- w.impl.zoomIn()
+ invokeSync(w.impl.zoomIn)
}
+// ZoomOut decreases the zoom level of the webview content
func (w *WebviewWindow) ZoomOut() {
if w.impl == nil {
return
}
- w.impl.zoomOut()
+ invokeSync(w.impl.zoomOut)
}
+// Close closes the window
func (w *WebviewWindow) Close() {
if w.impl == nil {
return
}
- w.impl.close()
-}
-
-func (w *WebviewWindow) Minimize() {
- if w.impl == nil {
- return
- }
- w.impl.minimise()
+ invokeSync(w.impl.close)
}
func (w *WebviewWindow) Zoom() {
if w.impl == nil {
return
}
- w.impl.zoom()
+ invokeSync(w.impl.zoom)
}
+// SetHTML sets the HTML of the window to the given html string.
func (w *WebviewWindow) SetHTML(html string) *WebviewWindow {
w.options.HTML = html
if w.impl != nil {
- w.impl.setHTML(html)
+ invokeSync(func() {
+ w.impl.setHTML(html)
+ })
}
return w
}
+// SetPosition sets the position of the window.
func (w *WebviewWindow) SetPosition(x, y int) *WebviewWindow {
w.options.X = x
w.options.Y = y
if w.impl != nil {
- w.impl.setPosition(x, y)
+ invokeSync(func() {
+ w.impl.setPosition(x, y)
+ })
}
return w
}
+// Minimise minimises the window.
func (w *WebviewWindow) Minimise() *WebviewWindow {
if w.impl == nil {
w.options.StartState = WindowStateMinimised
return w
}
if !w.IsMinimised() {
- w.impl.minimise()
+ invokeSync(w.impl.minimise)
}
return w
}
+// Maximise maximises the window. Min/Max size constraints are disabled.
func (w *WebviewWindow) Maximise() *WebviewWindow {
if w.impl == nil {
w.options.StartState = WindowStateMaximised
@@ -529,74 +643,102 @@ func (w *WebviewWindow) Maximise() *WebviewWindow {
}
if !w.IsMaximised() {
w.disableSizeConstraints()
- w.impl.maximise()
+ invokeSync(w.impl.maximise)
}
return w
}
+// UnMinimise un-minimises the window. Min/Max size constraints are re-enabled.
func (w *WebviewWindow) UnMinimise() {
if w.impl == nil {
return
}
- w.impl.unminimise()
+ if w.IsMinimised() {
+ invokeSync(w.impl.unminimise)
+ }
}
+// UnMaximise un-maximises the window.
func (w *WebviewWindow) UnMaximise() {
if w.impl == nil {
return
}
- w.enableSizeConstraints()
- w.impl.unmaximise()
+ if w.IsMaximised() {
+ w.enableSizeConstraints()
+ invokeSync(w.impl.unmaximise)
+ }
}
+// UnFullscreen un-fullscreens the window.
func (w *WebviewWindow) UnFullscreen() {
if w.impl == nil {
return
}
- w.enableSizeConstraints()
- w.impl.unfullscreen()
+ if w.IsFullscreen() {
+ w.enableSizeConstraints()
+ invokeSync(w.impl.unfullscreen)
+ }
}
+// Restore restores the window to its previous state if it was previously minimised, maximised or fullscreen.
func (w *WebviewWindow) Restore() {
if w.impl == nil {
return
}
- if w.IsMinimised() {
- w.UnMinimise()
- } else if w.IsMaximised() {
- w.UnMaximise()
- } else if w.IsFullscreen() {
- w.UnFullscreen()
- }
+ invokeSync(func() {
+ if w.IsMinimised() {
+ w.UnMinimise()
+ } else if w.IsMaximised() {
+ w.UnMaximise()
+ } else if w.IsFullscreen() {
+ w.UnFullscreen()
+ }
+ })
}
func (w *WebviewWindow) disableSizeConstraints() {
if w.impl == nil {
return
}
- w.impl.setMinSize(0, 0)
- w.impl.setMaxSize(0, 0)
+ invokeSync(func() {
+ if w.options.MinWidth > 0 && w.options.MinHeight > 0 {
+ w.impl.setMinSize(0, 0)
+ }
+ if w.options.MaxWidth > 0 && w.options.MaxHeight > 0 {
+ w.impl.setMaxSize(0, 0)
+ }
+ })
}
func (w *WebviewWindow) enableSizeConstraints() {
if w.impl == nil {
return
}
- w.SetMinSize(w.options.MinWidth, w.options.MinHeight)
- w.SetMaxSize(w.options.MaxWidth, w.options.MaxHeight)
+ invokeSync(func() {
+ if w.options.MinWidth > 0 && w.options.MinHeight > 0 {
+ w.SetMinSize(w.options.MinWidth, w.options.MinHeight)
+ }
+ if w.options.MaxWidth > 0 && w.options.MaxHeight > 0 {
+ w.SetMaxSize(w.options.MaxWidth, w.options.MaxHeight)
+ }
+ })
}
+// GetScreen returns the screen that the window is on
func (w *WebviewWindow) GetScreen() (*Screen, error) {
if w.impl == nil {
return nil, nil
}
- return w.impl.getScreen()
+ return invokeSyncWithResultAndError(w.impl.getScreen)
}
+// SetFrameless removes the window frame and title bar
func (w *WebviewWindow) SetFrameless(frameless bool) *WebviewWindow {
w.options.Frameless = frameless
if w.impl != nil {
- w.impl.setFrameless(frameless)
+ invokeSync(func() {
+ w.impl.setFrameless(frameless)
+ })
}
return w
}
@@ -631,7 +773,7 @@ func (w *WebviewWindow) handleDragAndDropMessage(event *dragAndDropMessage) {
ctx := newWindowEventContext()
ctx.setDroppedFiles(event.filenames)
for _, listener := range w.eventListeners[uint(events.FilesDropped)] {
- listener(ctx)
+ listener.callback(ctx)
}
}
@@ -652,8 +794,25 @@ func (w *WebviewWindow) openContextMenu(data *ContextMenuData) {
w.impl.openContextMenu(menu, data)
}
+// RegisterContextMenu registers a context menu and assigns it the given name.
func (w *WebviewWindow) RegisterContextMenu(name string, menu *Menu) {
w.contextMenusLock.Lock()
defer w.contextMenusLock.Unlock()
w.contextMenus[name] = menu
}
+
+// NativeWindowHandle returns the platform native window handle for the window.
+func (w *WebviewWindow) NativeWindowHandle() (uintptr, error) {
+ if w.impl == nil {
+ return 0, errors.New("native handle unavailable as window is not running")
+ }
+ return w.impl.nativeWindowHandle(), nil
+}
+
+func (w *WebviewWindow) Focus() {
+ if w.impl == nil {
+ w.options.Focused = true
+ return
+ }
+ invokeSync(w.impl.focus)
+}
diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go
index c8728f2e9..6acf5e441 100644
--- a/v3/pkg/application/webview_window_darwin.go
+++ b/v3/pkg/application/webview_window_darwin.go
@@ -6,13 +6,13 @@ package application
#cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c
#cgo LDFLAGS: -framework Cocoa -framework WebKit
-#include "application.h"
-#include "webview_window.h"
+#include "application_darwin.h"
+#include "webview_window_darwin.h"
#include
#include "Cocoa/Cocoa.h"
#import
#import
-#import "webview_drag.h"
+#import "webview_window_darwin_drag.h"
extern void registerListener(unsigned int event);
@@ -642,6 +642,17 @@ void windowDestroy(void* nsWindow) {
});
}
+// Remove drop shadow from window
+void windowSetShadow(void* nsWindow, bool hasShadow) {
+ // Remove shadow on main thread
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // get main window
+ WebviewWindow* window = (WebviewWindow*)nsWindow;
+ // set shadow
+ [window setHasShadow:hasShadow];
+ });
+}
+
// windowClose closes the current window
static void windowClose(void *window) {
@@ -703,6 +714,12 @@ static bool isFullScreen(void *window) {
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
}
+static bool isVisible(void *window) {
+ // get main window
+ WebviewWindow* nsWindow = (WebviewWindow*)window;
+ return (nsWindow.occlusionState & NSWindowOcclusionStateVisible) == NSWindowOcclusionStateVisible;
+}
+
// windowSetFullScreen
static void windowSetFullScreen(void *window, bool fullscreen) {
if (isFullScreen(window)) {
@@ -802,6 +819,10 @@ type macosWebviewWindow struct {
parent *WebviewWindow
}
+func (w *macosWebviewWindow) focus() {
+ w.show()
+}
+
func (w *macosWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData) {
// Create the menu
thisMenu := newMenuImpl(menu)
@@ -831,6 +852,10 @@ func (w *macosWebviewWindow) setFrameless(frameless bool) {
}
}
+func (w *macosWebviewWindow) setHasShadow(hasShadow bool) {
+ C.windowSetShadow(w.nsWindow, C.bool(hasShadow))
+}
+
func (w *macosWebviewWindow) getScreen() (*Screen, error) {
return getScreenForWindow(w)
}
@@ -942,6 +967,14 @@ func (w *macosWebviewWindow) isFullscreen() bool {
})
}
+func (w *macosWebviewWindow) isNormal() bool {
+ return !w.isMinimised() && !w.isMaximised() && !w.isFullscreen()
+}
+
+func (w *macosWebviewWindow) isVisible() bool {
+ return bool(C.isVisible(w.nsWindow))
+}
+
func (w *macosWebviewWindow) syncMainThreadReturningBool(fn func() bool) bool {
var wg sync.WaitGroup
wg.Add(1)
@@ -1078,7 +1111,9 @@ func (w *macosWebviewWindow) run() {
w.setMaxSize(w.parent.options.MaxWidth, w.parent.options.MaxHeight)
}
//w.setZoom(w.parent.options.Zoom)
- w.enableDevTools()
+ if isDebugMode() {
+ w.enableDevTools()
+ }
w.setBackgroundColour(w.parent.options.BackgroundColour)
macOptions := w.parent.options.Mac
@@ -1143,14 +1178,25 @@ func (w *macosWebviewWindow) run() {
}
if w.parent.options.Hidden == false {
C.windowShow(w.nsWindow)
+ w.setHasShadow(!w.parent.options.Mac.DisableShadow)
+ } else {
+ // We have to wait until the window is shown before we can remove the shadow
+ var cancel func()
+ cancel = w.parent.On(events.Mac.WindowDidBecomeKey, func(_ *WindowEventContext) {
+ w.setHasShadow(!w.parent.options.Mac.DisableShadow)
+ cancel()
+ })
}
+
})
}
-func (w *macosWebviewWindow) setBackgroundColour(colour *RGBA) {
- if colour == nil {
- return
- }
+func (w *macosWebviewWindow) nativeWindowHandle() uintptr {
+ return uintptr(w.nsWindow)
+}
+
+func (w *macosWebviewWindow) setBackgroundColour(colour RGBA) {
+
C.windowSetBackgroundColour(w.nsWindow, C.int(colour.Red), C.int(colour.Green), C.int(colour.Blue), C.int(colour.Alpha))
}
diff --git a/v3/pkg/application/webview_window.h b/v3/pkg/application/webview_window_darwin.h
similarity index 100%
rename from v3/pkg/application/webview_window.h
rename to v3/pkg/application/webview_window_darwin.h
diff --git a/v3/pkg/application/webview_window.m b/v3/pkg/application/webview_window_darwin.m
similarity index 98%
rename from v3/pkg/application/webview_window.m
rename to v3/pkg/application/webview_window_darwin.m
index 70636fc47..82040b1d5 100644
--- a/v3/pkg/application/webview_window.m
+++ b/v3/pkg/application/webview_window_darwin.m
@@ -1,7 +1,7 @@
//go:build darwin
#import
#import
-#import "webview_window.h"
+#import "webview_window_darwin.h"
#import "../events/events.h"
extern void processMessage(unsigned int, const char*);
extern void processURLRequest(unsigned int, void *);
@@ -63,18 +63,21 @@ extern bool hasListeners(unsigned int);
// Handle script messages from the external bridge
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
NSString *m = message.body;
- /*
- // TODO: Check for drag
+
if ( [m isEqualToString:@"drag"] ) {
+ /*
if( [self IsFullScreen] ) {
return;
}
- if( self.mouseEvent != nil ) {
- [self.mainWindow performWindowDragWithEvent:self.mouseEvent];
+ */
+ if( self.leftMouseEvent != nil ) {
+ WKWebView *webView = message.webView;
+ WebviewWindow *window = (WebviewWindow*)webView.window;
+ [window performWindowDragWithEvent:self.leftMouseEvent];
}
return;
}
- */
+
const char *_m = [m UTF8String];
processMessage(self.windowId, _m);
}
diff --git a/v3/pkg/application/webview_window_devtools.go b/v3/pkg/application/webview_window_darwin_devtools.go
similarity index 94%
rename from v3/pkg/application/webview_window_devtools.go
rename to v3/pkg/application/webview_window_darwin_devtools.go
index 7dce43c52..2a6442156 100644
--- a/v3/pkg/application/webview_window_devtools.go
+++ b/v3/pkg/application/webview_window_darwin_devtools.go
@@ -8,7 +8,7 @@ package application
#import
-#include "webview_window.h"
+#include "webview_window_darwin.h"
@interface _WKInspector : NSObject
- (void)show;
diff --git a/v3/pkg/application/webview_drag.h b/v3/pkg/application/webview_window_darwin_drag.h
similarity index 100%
rename from v3/pkg/application/webview_drag.h
rename to v3/pkg/application/webview_window_darwin_drag.h
diff --git a/v3/pkg/application/webview_drag.m b/v3/pkg/application/webview_window_darwin_drag.m
similarity index 97%
rename from v3/pkg/application/webview_drag.m
rename to v3/pkg/application/webview_window_darwin_drag.m
index 057e68d95..345c5ee37 100644
--- a/v3/pkg/application/webview_drag.m
+++ b/v3/pkg/application/webview_window_darwin_drag.m
@@ -2,7 +2,7 @@
#import
#import
-#import "webview_drag.h"
+#import "webview_window_darwin_drag.h"
#import "../events/events.h"
diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go
new file mode 100644
index 000000000..34507973e
--- /dev/null
+++ b/v3/pkg/application/webview_window_windows.go
@@ -0,0 +1,1240 @@
+//go:build windows
+
+package application
+
+import (
+ "errors"
+ "fmt"
+ "github.com/bep/debounce"
+ "github.com/wailsapp/wails/v2/pkg/assetserver"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf16"
+ "unsafe"
+
+ "github.com/samber/lo"
+
+ "github.com/wailsapp/go-webview2/pkg/edge"
+ "github.com/wailsapp/wails/v3/pkg/events"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+)
+
+var showDevTools = func(window unsafe.Pointer) {}
+
+type windowsWebviewWindow struct {
+ windowImpl unsafe.Pointer
+ parent *WebviewWindow
+ hwnd w32.HWND
+
+ // Fullscreen flags
+ isCurrentlyFullscreen bool
+ previousWindowStyle uint32
+ previousWindowExStyle uint32
+ previousWindowPlacement w32.WINDOWPLACEMENT
+
+ // Webview
+ chromium *edge.Chromium
+ hasStarted bool
+ resizeDebouncer func(func())
+}
+
+func (w *windowsWebviewWindow) nativeWindowHandle() uintptr {
+ return w.hwnd
+}
+
+func (w *windowsWebviewWindow) setTitle(title string) {
+ w32.SetWindowText(w.hwnd, title)
+}
+
+func (w *windowsWebviewWindow) setSize(width, height int) {
+ rect := w32.GetWindowRect(w.hwnd)
+ width, height = w.scaleWithWindowDPI(width, height)
+ w32.MoveWindow(w.hwnd, int(rect.Left), int(rect.Top), width, height, true)
+}
+
+func (w *windowsWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) {
+ w32.SetWindowPos(w.hwnd,
+ lo.Ternary(alwaysOnTop, w32.HWND_TOPMOST, w32.HWND_NOTOPMOST),
+ 0,
+ 0,
+ 0,
+ 0,
+ uint(w32.SWP_NOMOVE|w32.SWP_NOSIZE))
+}
+
+func (w *windowsWebviewWindow) setURL(url string) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) setResizable(resizable bool) {
+ w.setStyle(resizable, w32.WS_THICKFRAME)
+}
+
+func (w *windowsWebviewWindow) setMinSize(width, height int) {
+ w.parent.options.MinWidth = width
+ w.parent.options.MinHeight = height
+}
+
+func (w *windowsWebviewWindow) setMaxSize(width, height int) {
+ w.parent.options.MaxWidth = width
+ w.parent.options.MaxHeight = height
+}
+
+func (w *windowsWebviewWindow) execJS(js string) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) setBackgroundColour(color RGBA) {
+ w32.SetBackgroundColour(w.hwnd, color.Red, color.Green, color.Blue)
+}
+
+func (w *windowsWebviewWindow) framelessWithDecorations() bool {
+ return w.parent.options.Frameless && !w.parent.options.Windows.DisableFramelessWindowDecorations
+}
+
+func (w *windowsWebviewWindow) run() {
+
+ options := w.parent.options
+
+ w.chromium = edge.NewChromium()
+
+ var exStyle uint
+ exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
+ if options.BackgroundType != BackgroundTypeSolid {
+ exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
+ }
+ if options.AlwaysOnTop {
+ exStyle |= w32.WS_EX_TOPMOST
+ }
+
+ var startX, _ = lo.Coalesce(options.X, w32.CW_USEDEFAULT)
+ var startY, _ = lo.Coalesce(options.Y, w32.CW_USEDEFAULT)
+
+ w.hwnd = w32.CreateWindowEx(
+ exStyle,
+ windowClassName,
+ w32.MustStringToUTF16Ptr(options.Title),
+ w32.WS_OVERLAPPEDWINDOW,
+ startX,
+ startY,
+ options.Width,
+ options.Height,
+ 0,
+ 0,
+ w32.GetModuleHandle(""),
+ nil)
+
+ if w.hwnd == 0 {
+ panic("Unable to create window")
+ }
+
+ // Register the window with the application
+ getNativeApplication().registerWindow(w)
+
+ w.setResizable(!options.DisableResize)
+
+ if options.Frameless {
+ // Inform the application of the frame change this is needed to trigger the WM_NCCALCSIZE event.
+ // => https://learn.microsoft.com/en-us/windows/win32/dwm/customframe#removing-the-standard-frame
+ // This is normally done in WM_CREATE but we can't handle that there because that is emitted during CreateWindowEx
+ // and at that time we can't yet register the window for calling our WndProc method.
+ // This must be called after setResizable above!
+ rcClient := w32.GetWindowRect(w.hwnd)
+ w32.SetWindowPos(w.hwnd,
+ 0,
+ int(rcClient.Left),
+ int(rcClient.Top),
+ int(rcClient.Right-rcClient.Left),
+ int(rcClient.Bottom-rcClient.Top),
+ w32.SWP_FRAMECHANGED)
+ }
+
+ // Icon
+ if !options.Windows.DisableIcon {
+ // App icon ID is 3
+ icon, err := NewIconFromResource(w32.GetModuleHandle(""), uint16(3))
+ if err == nil {
+ w.setIcon(icon)
+ }
+ } else {
+ w.disableIcon()
+ }
+
+ // Process the theme
+ switch options.Windows.Theme {
+ case SystemDefault:
+ w.updateTheme(w32.IsCurrentlyDarkMode())
+ w.parent.onApplicationEvent(events.Windows.SystemThemeChanged, func() {
+ w.updateTheme(w32.IsCurrentlyDarkMode())
+ })
+ case Light:
+ w.updateTheme(false)
+ case Dark:
+ w.updateTheme(true)
+ }
+
+ switch options.BackgroundType {
+ case BackgroundTypeSolid:
+ w.setBackgroundColour(options.BackgroundColour)
+ case BackgroundTypeTransparent:
+ case BackgroundTypeTranslucent:
+ w.setBackdropType(options.Windows.BackdropType)
+ }
+
+ // Process StartState
+ switch options.StartState {
+ case WindowStateMaximised:
+ if w.parent.Resizable() {
+ w.maximise()
+ }
+ case WindowStateMinimised:
+ w.minimise()
+ case WindowStateFullscreen:
+ w.fullscreen()
+ }
+
+ // Process window mask
+ if options.Windows.WindowMask != nil {
+ w.setWindowMask(options.Windows.WindowMask)
+ }
+
+ if options.Windows.ResizeDebounceMS > 0 {
+ w.resizeDebouncer = debounce.New(time.Duration(options.Windows.ResizeDebounceMS) * time.Millisecond)
+ }
+
+ if options.Centered {
+ w.center()
+ }
+
+ if options.Focused {
+ w.Focus()
+ }
+
+ w.setupChromium()
+
+ if !options.Hidden {
+ w.show()
+ w.update()
+ }
+}
+
+func (w *windowsWebviewWindow) center() {
+ w32.CenterWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) disableSizeConstraints() {
+ w.setMaxSize(0, 0)
+ w.setMinSize(0, 0)
+}
+
+func (w *windowsWebviewWindow) enableSizeConstraints() {
+ options := w.parent.options
+ if options.MinWidth > 0 || options.MinHeight > 0 {
+ w.setMinSize(options.MinWidth, options.MinHeight)
+ }
+ if options.MaxWidth > 0 || options.MaxHeight > 0 {
+ w.setMaxSize(options.MaxWidth, options.MaxHeight)
+ }
+}
+
+func (w *windowsWebviewWindow) size() (int, int) {
+ rect := w32.GetWindowRect(w.hwnd)
+ width := int(rect.Right - rect.Left)
+ height := int(rect.Bottom - rect.Top)
+ width, height = w.scaleToDefaultDPI(width, height)
+ return width, height
+}
+
+func (w *windowsWebviewWindow) Focus() {
+ w32.SetForegroundWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) update() {
+ w32.UpdateWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) width() int {
+ width, _ := w.size()
+ return width
+}
+
+func (w *windowsWebviewWindow) height() int {
+ _, height := w.size()
+ return height
+}
+
+func (w *windowsWebviewWindow) position() (int, int) {
+ rect := w32.GetWindowRect(w.hwnd)
+ left, right := w.scaleToDefaultDPI(int(rect.Left), int(rect.Right))
+ return left, right
+}
+
+func (w *windowsWebviewWindow) destroy() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) reload() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) forceReload() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) toggleDevTools() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) zoomReset() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) zoomIn() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) zoomOut() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) getZoom() float64 {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) setZoom(zoom float64) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) close() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) zoom() {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) setHTML(html string) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) setPosition(x int, y int) {
+ x, y = w.scaleWithWindowDPI(x, y)
+ info := w32.GetMonitorInfoForWindow(w.hwnd)
+ workRect := info.RcWork
+ w32.SetWindowPos(w.hwnd, w32.HWND_TOP, int(workRect.Left)+x, int(workRect.Top)+y, 0, 0, w32.SWP_NOSIZE)
+}
+
+// on is used to indicate that a particular event should be listened for
+func (w *windowsWebviewWindow) on(eventID uint) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (w *windowsWebviewWindow) minimise() {
+ w32.ShowWindow(w.hwnd, w32.SW_MINIMIZE)
+}
+
+func (w *windowsWebviewWindow) unminimise() {
+ w.restore()
+}
+
+func (w *windowsWebviewWindow) maximise() {
+ w32.ShowWindow(w.hwnd, w32.SW_MAXIMIZE)
+}
+
+func (w *windowsWebviewWindow) unmaximise() {
+ w.restore()
+}
+
+func (w *windowsWebviewWindow) restore() {
+ w32.ShowWindow(w.hwnd, w32.SW_RESTORE)
+}
+
+func (w *windowsWebviewWindow) fullscreen() {
+ if w.isFullscreen() {
+ return
+ }
+ if w.framelessWithDecorations() {
+ w32.ExtendFrameIntoClientArea(w.hwnd, false)
+ }
+ w.disableSizeConstraints()
+ w.previousWindowStyle = uint32(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
+ w.previousWindowExStyle = uint32(w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE))
+ monitor := w32.MonitorFromWindow(w.hwnd, w32.MONITOR_DEFAULTTOPRIMARY)
+ var monitorInfo w32.MONITORINFO
+ monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo))
+ if !w32.GetMonitorInfo(monitor, &monitorInfo) {
+ return
+ }
+ if !w32.GetWindowPlacement(w.hwnd, &w.previousWindowPlacement) {
+ return
+ }
+ // According to https://devblogs.microsoft.com/oldnewthing/20050505-04/?p=35703 one should use w32.WS_POPUP | w32.WS_VISIBLE
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, w.previousWindowStyle & ^uint32(w32.WS_OVERLAPPEDWINDOW) | (w32.WS_POPUP|w32.WS_VISIBLE))
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, w.previousWindowExStyle & ^uint32(w32.WS_EX_DLGMODALFRAME))
+ w.isCurrentlyFullscreen = true
+ w32.SetWindowPos(w.hwnd, w32.HWND_TOP,
+ int(monitorInfo.RcMonitor.Left),
+ int(monitorInfo.RcMonitor.Top),
+ int(monitorInfo.RcMonitor.Right-monitorInfo.RcMonitor.Left),
+ int(monitorInfo.RcMonitor.Bottom-monitorInfo.RcMonitor.Top),
+ w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED)
+}
+
+func (w *windowsWebviewWindow) unfullscreen() {
+ if !w.isFullscreen() {
+ return
+ }
+ if w.framelessWithDecorations() {
+ w32.ExtendFrameIntoClientArea(w.hwnd, true)
+ }
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, w.previousWindowStyle)
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, w.previousWindowExStyle)
+ w32.SetWindowPlacement(w.hwnd, &w.previousWindowPlacement)
+ w.isCurrentlyFullscreen = false
+ w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
+ w32.SWP_NOMOVE|w32.SWP_NOSIZE|w32.SWP_NOZORDER|w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED)
+ w.enableSizeConstraints()
+}
+
+func (w *windowsWebviewWindow) isMinimised() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_MINIMIZE != 0
+}
+
+func (w *windowsWebviewWindow) isMaximised() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_MAXIMIZE != 0
+}
+
+func (w *windowsWebviewWindow) isFullscreen() bool {
+ // TODO: Actually calculate this based on size of window against screen size
+ // => stffabi: This flag is essential since it indicates that we are in fullscreen mode even before the native properties
+ // reflect this, e.g. when needing to know if we are in fullscreen during a wndproc message.
+ // That's also why this flag is set before SetWindowPos in v2 in fullscreen/unfullscreen.
+ return w.isCurrentlyFullscreen
+}
+
+func (w *windowsWebviewWindow) isNormal() bool {
+ return !w.isMinimised() && !w.isMaximised() && !w.isFullscreen()
+}
+
+func (w *windowsWebviewWindow) isVisible() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_VISIBLE != 0
+}
+
+func (w *windowsWebviewWindow) setFullscreenButtonEnabled(_ bool) {
+ // Unused in Windows
+}
+
+func (w *windowsWebviewWindow) focus() {
+ w32.SetForegroundWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) show() {
+ w32.ShowWindow(w.hwnd, w32.SW_SHOW)
+}
+
+func (w *windowsWebviewWindow) hide() {
+ w32.ShowWindow(w.hwnd, w32.SW_HIDE)
+}
+
+// Get the screen for the current window
+func (w *windowsWebviewWindow) getScreen() (*Screen, error) {
+ hMonitor := w32.MonitorFromWindow(w.hwnd, w32.MONITOR_DEFAULTTONEAREST)
+
+ var mi w32.MONITORINFOEX
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ w32.GetMonitorInfoEx(hMonitor, &mi)
+ var thisScreen Screen
+ thisScreen.X = int(mi.RcMonitor.Left)
+ thisScreen.Y = int(mi.RcMonitor.Top)
+ thisScreen.Size = Size{
+ Width: int(mi.RcMonitor.Right - mi.RcMonitor.Left),
+ Height: int(mi.RcMonitor.Bottom - mi.RcMonitor.Top),
+ }
+ thisScreen.Bounds = Rect{
+ X: int(mi.RcMonitor.Left),
+ Y: int(mi.RcMonitor.Top),
+ Width: int(mi.RcMonitor.Right - mi.RcMonitor.Left),
+ Height: int(mi.RcMonitor.Bottom - mi.RcMonitor.Top),
+ }
+ thisScreen.WorkArea = Rect{
+ X: int(mi.RcWork.Left),
+ Y: int(mi.RcWork.Top),
+ Width: int(mi.RcWork.Right - mi.RcWork.Left),
+ Height: int(mi.RcWork.Bottom - mi.RcWork.Top),
+ }
+ thisScreen.ID = strconv.Itoa(int(hMonitor))
+ thisScreen.Name = string(utf16.Decode(mi.SzDevice[:]))
+ var xdpi, ydpi w32.UINT
+ w32.GetDPIForMonitor(hMonitor, w32.MDT_EFFECTIVE_DPI, &xdpi, &ydpi)
+ thisScreen.Scale = float32(xdpi) / 96.0
+ thisScreen.IsPrimary = mi.DwFlags&w32.MONITORINFOF_PRIMARY != 0
+
+ // TODO: Get screen rotation
+ // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodea
+
+ //// get display settings for monitor
+ //var dm w32.DEVMODE
+ //dm.DmSize = uint16(unsafe.Sizeof(dm))
+ //dm.DmDriverExtra = 0
+ //w32.EnumDisplaySettingsEx(&mi.SzDevice[0], w32.ENUM_CURRENT_SETTINGS, &dm, 0)
+ //
+ //// check display settings for rotation
+ //rotationAngle := dm.DmDi
+ //if rotationAngle == DMDO_0 {
+ // printf("Monitor is not rotated\n")
+ //} else if rotationAngle == DMDO_90 {
+ // printf("Monitor is rotated 90 degrees\n")
+ //} else if rotationAngle == DMDO_180 {
+ // printf("Monitor is rotated 180 degrees\n")
+ //} else if rotationAngle == DMDO_270 {
+ // printf("Monitor is rotated 270 degrees\n")
+ //} else {
+ // printf("Monitor is rotated at an unknown angle\n")
+ //}
+
+ return &thisScreen, nil
+}
+
+func (w *windowsWebviewWindow) setFrameless(b bool) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func newWindowImpl(parent *WebviewWindow) *windowsWebviewWindow {
+ result := &windowsWebviewWindow{
+ parent: parent,
+ }
+
+ return result
+}
+
+func (w *windowsWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData) {
+ // Create the menu
+ thisMenu := newMenuImpl(menu)
+ thisMenu.update()
+ //C.windowShowMenu(w.nsWindow, thisMenu.nsMenu, C.int(data.X), C.int(data.Y))
+}
+
+func (w *windowsWebviewWindow) setStyle(b bool, style int) {
+ currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
+ if currentStyle != 0 {
+ currentStyle = lo.Ternary(b, currentStyle|style, currentStyle&^style)
+ w32.SetWindowLongPtr(w.hwnd, w32.GWL_STYLE, uintptr(currentStyle))
+ }
+}
+func (w *windowsWebviewWindow) setExStyle(b bool, style int) {
+ currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE))
+ if currentStyle != 0 {
+ currentStyle = lo.Ternary(b, currentStyle|style, currentStyle&^style)
+ w32.SetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE, uintptr(currentStyle))
+ }
+}
+
+func (w *windowsWebviewWindow) setBackdropType(backdropType BackdropType) {
+ if !w32.IsWindowsVersionAtLeast(10, 0, 22621) {
+ var accent = w32.ACCENT_POLICY{
+ AccentState: w32.ACCENT_ENABLE_BLURBEHIND,
+ }
+ var data w32.WINDOWCOMPOSITIONATTRIBDATA
+ data.Attrib = w32.WCA_ACCENT_POLICY
+ data.PvData = w32.PVOID(&accent)
+ data.CbData = w32.SIZE_T(unsafe.Sizeof(accent))
+
+ w32.SetWindowCompositionAttribute(w.hwnd, &data)
+ } else {
+ w32.DwmSetWindowAttribute(w.hwnd, w32.DwmwaSystemBackdropType, w32.PVOID(&backdropType), unsafe.Sizeof(backdropType))
+ }
+}
+
+func (w *windowsWebviewWindow) setIcon(icon w32.HICON) {
+ w32.SendMessage(w.hwnd, w32.BM_SETIMAGE, w32.IMAGE_ICON, uintptr(icon))
+}
+
+func (w *windowsWebviewWindow) disableIcon() {
+
+ // TODO: If frameless, return
+ exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))
+ w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
+ uint(
+ w32.SWP_FRAMECHANGED|
+ w32.SWP_NOMOVE|
+ w32.SWP_NOSIZE|
+ w32.SWP_NOZORDER),
+ )
+}
+
+func (w *windowsWebviewWindow) updateTheme(isDarkMode bool) {
+
+ if w32.IsCurrentlyHighContrastMode() {
+ return
+ }
+
+ if !w32.SupportsThemes() {
+ return
+ }
+
+ w32.SetTheme(w.hwnd, isDarkMode)
+
+ // Custom theme processing
+ customTheme := w.parent.options.Windows.CustomTheme
+ // Custom theme
+ if w32.SupportsCustomThemes() && customTheme != nil {
+ if w.isActive() {
+ if isDarkMode {
+ w32.SetTitleBarColour(w.hwnd, customTheme.DarkModeTitleBar)
+ w32.SetTitleTextColour(w.hwnd, customTheme.DarkModeTitleText)
+ w32.SetBorderColour(w.hwnd, customTheme.DarkModeBorder)
+ } else {
+ w32.SetTitleBarColour(w.hwnd, customTheme.LightModeTitleBar)
+ w32.SetTitleTextColour(w.hwnd, customTheme.LightModeTitleText)
+ w32.SetBorderColour(w.hwnd, customTheme.LightModeBorder)
+ }
+ } else {
+ if isDarkMode {
+ w32.SetTitleBarColour(w.hwnd, customTheme.DarkModeTitleBarInactive)
+ w32.SetTitleTextColour(w.hwnd, customTheme.DarkModeTitleTextInactive)
+ w32.SetBorderColour(w.hwnd, customTheme.DarkModeBorderInactive)
+ } else {
+ w32.SetTitleBarColour(w.hwnd, customTheme.LightModeTitleBarInactive)
+ w32.SetTitleTextColour(w.hwnd, customTheme.LightModeTitleTextInactive)
+ w32.SetBorderColour(w.hwnd, customTheme.LightModeBorderInactive)
+ }
+ }
+ }
+}
+
+func (w *windowsWebviewWindow) isActive() bool {
+ return w32.GetForegroundWindow() == w.hwnd
+}
+
+func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintptr {
+ switch msg {
+ case w32.WM_SIZE:
+ return 0
+ case w32.WM_CLOSE:
+ if w.parent.options.HideOnClose {
+ w.hide()
+ return 0 // Do not let the DefWindowProc allow to close us
+ }
+
+ // Unregister the window with the application
+ windowsApp := globalApplication.impl.(*windowsApp)
+ windowsApp.unregisterWindow(w)
+ case w32.WM_NCLBUTTONDOWN:
+ w32.SetFocus(w.hwnd)
+ case w32.WM_MOVE, w32.WM_MOVING:
+ _ = w.chromium.NotifyParentWindowPositionChanged()
+ case w32.WM_SIZING:
+ // If the window is frameless, and we are minimizing, then we need to suppress the Resize on the
+ // WebView2. If we don't do this, restoring does not work as expected and first restores with some wrong
+ // size during the restore animation and only fully renders when the animation is done. This highly
+ // depends on the content in the WebView, see https://github.com/wailsapp/wails/issues/1319
+ if w.parent.options.Frameless && wparam == w32.SIZE_MINIMIZED {
+ return 0
+ }
+
+ // If we have a resize debouncer, use it
+ if w.resizeDebouncer != nil {
+ w.resizeDebouncer(func() {
+ invokeSync(func() {
+ w.chromium.Resize()
+ })
+ })
+ } else {
+ w.chromium.Resize()
+ }
+
+ case w32.WM_GETMINMAXINFO:
+ mmi := (*w32.MINMAXINFO)(unsafe.Pointer(lparam))
+ hasConstraints := false
+ options := w.parent.options
+ if options.MinWidth > 0 || options.MinHeight > 0 {
+ hasConstraints = true
+
+ width, height := w.scaleWithWindowDPI(options.MinWidth, options.MinHeight)
+ if width > 0 {
+ mmi.PtMinTrackSize.X = int32(width)
+ }
+ if height > 0 {
+ mmi.PtMinTrackSize.Y = int32(height)
+ }
+ }
+ if options.MaxWidth > 0 || options.MaxHeight > 0 {
+ hasConstraints = true
+
+ width, height := w.scaleWithWindowDPI(options.MaxWidth, options.MaxHeight)
+ if width > 0 {
+ mmi.PtMaxTrackSize.X = int32(width)
+ }
+ if height > 0 {
+ mmi.PtMaxTrackSize.Y = int32(height)
+ }
+ }
+ if hasConstraints {
+ return 0
+ }
+ case w32.WM_DPICHANGED:
+ newWindowSize := (*w32.RECT)(unsafe.Pointer(lparam))
+ w32.SetWindowPos(w.hwnd,
+ uintptr(0),
+ int(newWindowSize.Left),
+ int(newWindowSize.Top),
+ int(newWindowSize.Right-newWindowSize.Left),
+ int(newWindowSize.Bottom-newWindowSize.Top),
+ w32.SWP_NOZORDER|w32.SWP_NOACTIVATE)
+
+ }
+
+ if w.parent.options.Windows.WindowMask != nil {
+ switch msg {
+ case w32.WM_NCHITTEST:
+ if w.parent.options.Windows.WindowMaskDraggable {
+ return w32.HTCAPTION
+ }
+ return w32.HTCLIENT
+ }
+ }
+
+ if options := w.parent.options; options.Frameless {
+ switch msg {
+ case w32.WM_ACTIVATE:
+ // If we want to have a frameless window but with the default frame decorations, extend the DWM client area.
+ // This Option is not affected by returning 0 in WM_NCCALCSIZE.
+ // As a result we have hidden the titlebar but still have the default window frame styling.
+ // See: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea#remarks
+ if w.framelessWithDecorations() {
+ w32.ExtendFrameIntoClientArea(w.hwnd, true)
+ }
+ case w32.WM_NCHITTEST:
+ // Get the cursor position
+ x := int32(w32.LOWORD(uint32(lparam)))
+ y := int32(w32.HIWORD(uint32(lparam)))
+ ptCursor := w32.POINT{X: x, Y: y}
+
+ // Get the window rectangle
+ rcWindow := w32.GetWindowRect(w.hwnd)
+
+ // Determine if the cursor is in a resize area
+ bOnResizeBorder := false
+ resizeBorderWidth := int32(5) // change this to adjust the resize border width
+ if ptCursor.X >= rcWindow.Right-resizeBorderWidth {
+ bOnResizeBorder = true // right edge
+ }
+ if ptCursor.Y >= rcWindow.Bottom-resizeBorderWidth {
+ bOnResizeBorder = true // bottom edge
+ }
+ if ptCursor.X <= rcWindow.Left+resizeBorderWidth {
+ bOnResizeBorder = true // left edge
+ }
+ if ptCursor.Y <= rcWindow.Top+resizeBorderWidth {
+ bOnResizeBorder = true // top edge
+ }
+
+ // Return the appropriate value
+ if bOnResizeBorder {
+ if ptCursor.X >= rcWindow.Right-resizeBorderWidth && ptCursor.Y >= rcWindow.Bottom-resizeBorderWidth {
+ return w32.HTBOTTOMRIGHT
+ } else if ptCursor.X <= rcWindow.Left+resizeBorderWidth && ptCursor.Y >= rcWindow.Bottom-resizeBorderWidth {
+ return w32.HTBOTTOMLEFT
+ } else if ptCursor.X >= rcWindow.Right-resizeBorderWidth && ptCursor.Y <= rcWindow.Top+resizeBorderWidth {
+ return w32.HTTOPRIGHT
+ } else if ptCursor.X <= rcWindow.Left+resizeBorderWidth && ptCursor.Y <= rcWindow.Top+resizeBorderWidth {
+ return w32.HTTOPLEFT
+ } else if ptCursor.X >= rcWindow.Right-resizeBorderWidth {
+ return w32.HTRIGHT
+ } else if ptCursor.Y >= rcWindow.Bottom-resizeBorderWidth {
+ return w32.HTBOTTOM
+ } else if ptCursor.X <= rcWindow.Left+resizeBorderWidth {
+ return w32.HTLEFT
+ } else if ptCursor.Y <= rcWindow.Top+resizeBorderWidth {
+ return w32.HTTOP
+ }
+ }
+ return w32.HTCLIENT
+
+ case w32.WM_NCCALCSIZE:
+ // Disable the standard frame by allowing the client area to take the full
+ // window size.
+ // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks
+ // This hides the titlebar and also disables the resizing from user interaction because the standard frame is not
+ // shown. We still need the WS_THICKFRAME style to enable resizing from the frontend.
+ if wparam != 0 {
+ rgrc := (*w32.RECT)(unsafe.Pointer(lparam))
+ if w.isCurrentlyFullscreen {
+ // In Full-Screen mode we don't need to adjust anything
+ // It essential we have the flag here, that is set before SetWindowPos in fullscreen/unfullscreen
+ // because the native size might not yet reflect we are in fullscreen during this event!
+ w.chromium.SetPadding(edge.Rect{})
+ } else if w.isMaximised() {
+ // If the window is maximized we must adjust the client area to the work area of the monitor. Otherwise
+ // some content goes beyond the visible part of the monitor.
+ // Make sure to use the provided RECT to get the monitor, because during maximizig there might be
+ // a wrong monitor returned in multi screen mode when using MonitorFromWindow.
+ // See: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2549
+ monitor := w32.MonitorFromRect(rgrc, w32.MONITOR_DEFAULTTONULL)
+
+ var monitorInfo w32.MONITORINFO
+ monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo))
+ if monitor != 0 && w32.GetMonitorInfo(monitor, &monitorInfo) {
+ *rgrc = monitorInfo.RcWork
+
+ maxWidth := options.MaxWidth
+ maxHeight := options.MaxHeight
+ if maxWidth > 0 || maxHeight > 0 {
+ var dpiX, dpiY uint
+ w32.GetDPIForMonitor(monitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY)
+
+ maxWidth := int32(ScaleWithDPI(maxWidth, dpiX))
+ if maxWidth > 0 && rgrc.Right-rgrc.Left > maxWidth {
+ rgrc.Right = rgrc.Left + maxWidth
+ }
+
+ maxHeight := int32(ScaleWithDPI(maxHeight, dpiY))
+ if maxHeight > 0 && rgrc.Bottom-rgrc.Top > maxHeight {
+ rgrc.Bottom = rgrc.Top + maxHeight
+ }
+ }
+ }
+ w.chromium.SetPadding(edge.Rect{})
+ } else {
+ // This is needed to workaround the resize flickering in frameless mode with WindowDecorations
+ // See: https://stackoverflow.com/a/6558508
+ // The workaround originally suggests to decrese the bottom 1px, but that seems to bring up a thin
+ // white line on some Windows-Versions, due to DrawBackground using also this reduces ClientSize.
+ // Increasing the bottom also worksaround the flickering but we would loose 1px of the WebView content
+ // therefore let's pad the content with 1px at the bottom.
+ rgrc.Bottom += 1
+ w.chromium.SetPadding(edge.Rect{Bottom: 1})
+ }
+ return 0
+ }
+ }
+ }
+ return w32.DefWindowProc(w.hwnd, msg, wparam, lparam)
+}
+
+func (w *windowsWebviewWindow) DPI() (w32.UINT, w32.UINT) {
+ if w32.HasGetDpiForWindowFunc() {
+ // GetDpiForWindow is supported beginning with Windows 10, 1607 and is the most accureate
+ // one, especially it is consistent with the WM_DPICHANGED event.
+ dpi := w32.GetDpiForWindow(w.hwnd)
+ return dpi, dpi
+ }
+
+ if w32.HasGetDPIForMonitorFunc() {
+ // GetDpiForWindow is supported beginning with Windows 8.1
+ monitor := w32.MonitorFromWindow(w.hwnd, w32.MONITOR_DEFAULTTONEAREST)
+ if monitor == 0 {
+ return 0, 0
+ }
+ var dpiX, dpiY w32.UINT
+ w32.GetDPIForMonitor(monitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY)
+ return dpiX, dpiY
+ }
+
+ // If none of the above is supported fallback to the System DPI.
+ screen := w32.GetDC(0)
+ x := w32.GetDeviceCaps(screen, w32.LOGPIXELSX)
+ y := w32.GetDeviceCaps(screen, w32.LOGPIXELSY)
+ w32.ReleaseDC(0, screen)
+ return w32.UINT(x), w32.UINT(y)
+}
+
+func (w *windowsWebviewWindow) scaleWithWindowDPI(width, height int) (int, int) {
+ dpix, dpiy := w.DPI()
+ scaledWidth := ScaleWithDPI(width, dpix)
+ scaledHeight := ScaleWithDPI(height, dpiy)
+
+ return scaledWidth, scaledHeight
+}
+
+func (w *windowsWebviewWindow) scaleToDefaultDPI(width, height int) (int, int) {
+ dpix, dpiy := w.DPI()
+ scaledWidth := ScaleToDefaultDPI(width, dpix)
+ scaledHeight := ScaleToDefaultDPI(height, dpiy)
+
+ return scaledWidth, scaledHeight
+}
+
+func (w *windowsWebviewWindow) setWindowMask(imageData []byte) {
+
+ // Set the window to a WS_EX_LAYERED window
+ newStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE) | w32.WS_EX_LAYERED
+
+ if w.isAlwaysOnTop() {
+ newStyle |= w32.WS_EX_TOPMOST
+ }
+ // Save the current window style
+ w.previousWindowExStyle = uint32(w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE))
+
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(newStyle))
+
+ data, err := pngToImage(imageData)
+ if err != nil {
+ panic(err)
+ }
+
+ bitmap, err := w32.CreateHBITMAPFromImage(data)
+ hdc := w32.CreateCompatibleDC(0)
+ defer w32.DeleteDC(hdc)
+
+ oldBitmap := w32.SelectObject(hdc, bitmap)
+ defer w32.SelectObject(hdc, oldBitmap)
+
+ screenDC := w32.GetDC(0)
+ defer w32.ReleaseDC(0, screenDC)
+
+ size := w32.SIZE{CX: int32(data.Bounds().Dx()), CY: int32(data.Bounds().Dy())}
+ ptSrc := w32.POINT{X: 0, Y: 0}
+ ptDst := w32.POINT{X: int32(w.width()), Y: int32(w.height())}
+ blend := w32.BLENDFUNCTION{
+ BlendOp: w32.AC_SRC_OVER,
+ BlendFlags: 0,
+ SourceConstantAlpha: 255,
+ AlphaFormat: w32.AC_SRC_ALPHA,
+ }
+ w32.UpdateLayeredWindow(w.hwnd, screenDC, &ptDst, &size, hdc, &ptSrc, 0, &blend, w32.ULW_ALPHA)
+}
+
+func (w *windowsWebviewWindow) isAlwaysOnTop() bool {
+ return w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)&w32.WS_EX_TOPMOST != 0
+}
+
+// processMessage is given a message sent from JS via the postMessage API
+// We put it on the global window message buffer to be processed centrally
+func (w *windowsWebviewWindow) processMessage(message string) {
+ // We send all messages to the centralised window message buffer
+ windowMessageBuffer <- &windowMessage{
+ windowId: w.parent.id,
+ message: message,
+ }
+}
+
+func coreWebview2RequestToHttpRequest(coreReq *edge.ICoreWebView2WebResourceRequest) func() (*http.Request, error) {
+ return func() (r *http.Request, err error) {
+ header := http.Header{}
+ headers, err := coreReq.GetHeaders()
+ if err != nil {
+ return nil, fmt.Errorf("GetHeaders Error: %s", err)
+ }
+ defer headers.Release()
+
+ headersIt, err := headers.GetIterator()
+ if err != nil {
+ return nil, fmt.Errorf("GetIterator Error: %s", err)
+ }
+ defer headersIt.Release()
+
+ for {
+ has, err := headersIt.HasCurrentHeader()
+ if err != nil {
+ return nil, fmt.Errorf("HasCurrentHeader Error: %s", err)
+ }
+ if !has {
+ break
+ }
+
+ name, value, err := headersIt.GetCurrentHeader()
+ if err != nil {
+ return nil, fmt.Errorf("GetCurrentHeader Error: %s", err)
+ }
+
+ header.Set(name, value)
+ if _, err := headersIt.MoveNext(); err != nil {
+ return nil, fmt.Errorf("MoveNext Error: %s", err)
+ }
+ }
+
+ method, err := coreReq.GetMethod()
+ if err != nil {
+ return nil, fmt.Errorf("GetMethod Error: %s", err)
+ }
+
+ uri, err := coreReq.GetUri()
+ if err != nil {
+ return nil, fmt.Errorf("GetUri Error: %s", err)
+ }
+
+ var body io.ReadCloser
+ if content, err := coreReq.GetContent(); err != nil {
+ return nil, fmt.Errorf("GetContent Error: %s", err)
+ } else if content != nil {
+ body = &iStreamReleaseCloser{stream: content}
+ }
+
+ req, err := http.NewRequest(method, uri, body)
+ if err != nil {
+ if body != nil {
+ body.Close()
+ }
+ return nil, err
+ }
+ req.Header = header
+ return req, nil
+ }
+}
+
+type iStreamReleaseCloser struct {
+ stream *edge.IStream
+ closed bool
+}
+
+func (i *iStreamReleaseCloser) Read(p []byte) (int, error) {
+ if i.closed {
+ return 0, io.ErrClosedPipe
+ }
+ return i.stream.Read(p)
+}
+
+func (i *iStreamReleaseCloser) Close() error {
+ if i.closed {
+ return nil
+ }
+ i.closed = true
+ return i.stream.Release()
+}
+
+func (w *windowsWebviewWindow) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
+ /*
+ webviewRequests <- &webViewAssetRequest{
+ Request: webview.NewRequest(wkUrlSchemeTask),
+ windowId: uint(windowID),
+ windowName: globalApplication.getWindowForID(uint(windowID)).Name(),
+ }
+ */
+ // Setting the UserAgent on the CoreWebView2Settings clears the whole default UserAgent of the Edge browser, but
+ // we want to just append our ApplicationIdentifier. So we adjust the UserAgent for every request.
+ if reqHeaders, err := req.GetHeaders(); err == nil {
+ useragent, _ := reqHeaders.GetHeader(assetserver.HeaderUserAgent)
+ useragent = strings.Join([]string{useragent, assetserver.WailsUserAgentValue}, " ")
+ reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent)
+ reqHeaders.Release()
+ }
+
+ if globalApplication.assets == nil {
+ // We are using the devServer let the WebView2 handle the request with its default handler
+ return
+ }
+
+ //Get the request
+ uri, _ := req.GetUri()
+ reqUri, err := url.ParseRequestURI(uri)
+ if err != nil {
+ globalApplication.error("Unable to parse request uri %s: %s", uri, err)
+ return
+ }
+
+ if reqUri.Scheme != "http" {
+ // Let the WebView2 handle the request with its default handler
+ return
+ } else if reqUri.Host != "wails.localhost" {
+ // Let the WebView2 handle the request with its default handler
+ return
+ }
+
+ rw := httptest.NewRecorder()
+ globalApplication.assets.ProcessHTTPRequestLegacy(rw, coreWebview2RequestToHttpRequest(req))
+
+ headers := []string{}
+ for k, v := range rw.Header() {
+ headers = append(headers, fmt.Sprintf("%s: %s", k, strings.Join(v, ",")))
+ }
+
+ env := w.chromium.Environment()
+ response, err := env.CreateWebResourceResponse(rw.Body.Bytes(), rw.Code, http.StatusText(rw.Code), strings.Join(headers, "\n"))
+ if err != nil {
+ globalApplication.error("CreateWebResourceResponse Error: %s", err)
+ return
+ }
+ defer response.Release()
+
+ // Send response back
+ err = args.PutResponse(response)
+ if err != nil {
+ globalApplication.error("PutResponse Error: %s", err)
+ return
+ }
+}
+
+func (w *windowsWebviewWindow) setupChromium() {
+ chromium := w.chromium
+ debugMode := isDebugMode()
+
+ disableFeatues := []string{}
+
+ if !w.parent.options.EnableFraudulentWebsiteWarnings {
+ disableFeatues = append(disableFeatues, "msSmartScreenProtection")
+ }
+
+ opts := w.parent.options.Windows
+ chromium.DataPath = opts.WebviewUserDataPath
+ chromium.BrowserPath = opts.WebviewBrowserPath
+
+ if opts.WebviewGpuIsDisabled {
+ chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu")
+ }
+
+ if len(disableFeatues) > 0 {
+ arg := fmt.Sprintf("--disable-features=%s", strings.Join(disableFeatues, ","))
+ chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, arg)
+ }
+
+ chromium.MessageCallback = w.processMessage
+ chromium.WebResourceRequestedCallback = w.processRequest
+ chromium.NavigationCompletedCallback = w.navigationCompleted
+ chromium.AcceleratorKeyCallback = func(vkey uint) bool {
+ w32.PostMessage(w.hwnd, w32.WM_KEYDOWN, uintptr(vkey), 0)
+ return false
+ }
+
+ chromium.Embed(w.hwnd)
+ chromium.Resize()
+ settings, err := chromium.GetSettings()
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+ err = settings.PutAreDefaultContextMenusEnabled(debugMode)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+ err = settings.PutAreDevToolsEnabled(debugMode)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+
+ if w.parent.options.Zoom > 0.0 {
+ chromium.PutZoomFactor(w.parent.options.Zoom)
+ }
+ err = settings.PutIsZoomControlEnabled(w.parent.options.ZoomControlEnabled)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+
+ err = settings.PutIsStatusBarEnabled(false)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+ err = settings.PutAreBrowserAcceleratorKeysEnabled(false)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+ err = settings.PutIsSwipeNavigationEnabled(false)
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+
+ if debugMode && w.parent.options.OpenInspectorOnStartup {
+ chromium.OpenDevToolsWindow()
+ }
+
+ //TODO: Setup focus event handler
+ //onFocus := f.mainWindow.OnSetFocus()
+ //onFocus.Bind(f.onFocus)
+
+ // Set background colour
+ w.setBackgroundColour(w.parent.options.BackgroundColour)
+
+ chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow)
+ chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
+ chromium.Navigate("http://wails.localhost")
+
+}
+
+func (w *windowsWebviewWindow) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) {
+
+ // TODO: DomReady Event
+
+ // Todo: Resize hacks
+ /*
+ if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false {
+ f.ExecJS("window.wails.flags.enableResize = true;")
+ }
+ */
+
+ // TODO: Work out why we need this
+ //if w.hasStarted {
+ // return
+ //}
+ //w.hasStarted = true
+
+ // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
+ err := w.chromium.Hide()
+ if err != nil {
+ globalApplication.fatal(err.Error())
+ }
+ if w.parent.options.Hidden {
+ return
+ }
+ err = w.chromium.Show()
+ if err != nil {
+ globalApplication.fatal(err.Error())
+
+ }
+
+ //if w.parent.options.Hidden {
+ // return
+ //}
+
+ //switch f.frontendOptions.WindowStartState {
+ //case options.Maximised:
+ // if !f.frontendOptions.DisableResize {
+ // win32.ShowWindowMaximised(f.mainWindow.Handle())
+ // } else {
+ // win32.ShowWindow(f.mainWindow.Handle())
+ // }
+ //case options.Minimised:
+ // win32.ShowWindowMinimised(f.mainWindow.Handle())
+ //case options.Fullscreen:
+ // f.mainWindow.Fullscreen()
+ // win32.ShowWindow(f.mainWindow.Handle())
+ //default:
+ // if f.frontendOptions.Fullscreen {
+ // f.mainWindow.Fullscreen()
+ // }
+ // win32.ShowWindow(f.mainWindow.Handle())
+ //}
+ //
+ //f.mainWindow.hasBeenShown = true
+
+}
+
+func ScaleWithDPI(pixels int, dpi uint) int {
+ return (pixels * int(dpi)) / 96
+}
+
+func ScaleToDefaultDPI(pixels int, dpi uint) int {
+ return (pixels * 96) / int(dpi)
+}
+
+func NewIconFromResource(instance w32.HINSTANCE, resId uint16) (w32.HICON, error) {
+ var err error
+ var result w32.HICON
+ if result = w32.LoadIconWithResourceID(instance, resId); result == 0 {
+ err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId))
+ }
+ return result, err
+}
diff --git a/v3/pkg/events/events.go b/v3/pkg/events/events.go
index f26f53b2e..a3a36a8b9 100644
--- a/v3/pkg/events/events.go
+++ b/v3/pkg/events/events.go
@@ -7,6 +7,18 @@ const (
FilesDropped WindowEventType = iota
)
+var Common = newCommonEvents()
+
+type commonEvents struct {
+ ApplicationStarted ApplicationEventType
+}
+
+func newCommonEvents() commonEvents {
+ return commonEvents{
+ ApplicationStarted: 1152,
+ }
+}
+
var Mac = newMacEvents()
type macEvents struct {
@@ -260,3 +272,25 @@ func newMacEvents() macEvents {
WindowFileDraggingExited: 1145,
}
}
+
+var Windows = newWindowsEvents()
+
+type windowsEvents struct {
+ SystemThemeChanged ApplicationEventType
+ APMPowerStatusChange ApplicationEventType
+ APMSuspend ApplicationEventType
+ APMResumeAutomatic ApplicationEventType
+ APMResumeSuspend ApplicationEventType
+ APMPowerSettingChange ApplicationEventType
+}
+
+func newWindowsEvents() windowsEvents {
+ return windowsEvents{
+ SystemThemeChanged: 1146,
+ APMPowerStatusChange: 1147,
+ APMSuspend: 1148,
+ APMResumeAutomatic: 1149,
+ APMResumeSuspend: 1150,
+ APMPowerSettingChange: 1151,
+ }
+}
diff --git a/v3/pkg/events/events.txt b/v3/pkg/events/events.txt
index dbbe98db4..2857cfd88 100644
--- a/v3/pkg/events/events.txt
+++ b/v3/pkg/events/events.txt
@@ -120,4 +120,10 @@ mac:WebViewDidCommitNavigation
mac:WindowFileDraggingEntered
mac:WindowFileDraggingPerformed
mac:WindowFileDraggingExited
-
+windows:SystemThemeChanged
+windows:APMPowerStatusChange
+windows:APMSuspend
+windows:APMResumeAutomatic
+windows:APMResumeSuspend
+windows:APMPowerSettingChange
+common:ApplicationStarted
diff --git a/v3/pkg/icons/ApplicationDarkMode-256.png b/v3/pkg/icons/ApplicationDarkMode-256.png
new file mode 100644
index 000000000..10959272a
Binary files /dev/null and b/v3/pkg/icons/ApplicationDarkMode-256.png differ
diff --git a/v3/pkg/icons/ApplicationLightMode-256.png b/v3/pkg/icons/ApplicationLightMode-256.png
new file mode 100644
index 000000000..1652dfe91
Binary files /dev/null and b/v3/pkg/icons/ApplicationLightMode-256.png differ
diff --git a/v3/pkg/icons/DefaultApplicationIcon.png b/v3/pkg/icons/DefaultApplicationIcon.png
new file mode 100644
index 000000000..a6129a69f
Binary files /dev/null and b/v3/pkg/icons/DefaultApplicationIcon.png differ
diff --git a/v3/pkg/icons/DefaultMacTemplateIcon.png b/v3/pkg/icons/DefaultMacTemplateIcon.png
new file mode 100644
index 000000000..ee8ad2352
Binary files /dev/null and b/v3/pkg/icons/DefaultMacTemplateIcon.png differ
diff --git a/v3/pkg/icons/WailsLogoBlack.png b/v3/pkg/icons/WailsLogoBlack.png
new file mode 100644
index 000000000..97269c4bb
Binary files /dev/null and b/v3/pkg/icons/WailsLogoBlack.png differ
diff --git a/v3/pkg/icons/WailsLogoBlackTransparent.png b/v3/pkg/icons/WailsLogoBlackTransparent.png
new file mode 100644
index 000000000..2a767148d
Binary files /dev/null and b/v3/pkg/icons/WailsLogoBlackTransparent.png differ
diff --git a/v3/pkg/icons/WailsLogoWhite.png b/v3/pkg/icons/WailsLogoWhite.png
new file mode 100644
index 000000000..c0e9582cd
Binary files /dev/null and b/v3/pkg/icons/WailsLogoWhite.png differ
diff --git a/v3/pkg/icons/WailsLogoWhiteTransparent.png b/v3/pkg/icons/WailsLogoWhiteTransparent.png
new file mode 100644
index 000000000..e65c582ff
Binary files /dev/null and b/v3/pkg/icons/WailsLogoWhiteTransparent.png differ
diff --git a/v3/pkg/icons/icons.go b/v3/pkg/icons/icons.go
new file mode 100644
index 000000000..4023df127
--- /dev/null
+++ b/v3/pkg/icons/icons.go
@@ -0,0 +1,30 @@
+package icons
+
+import _ "embed"
+
+//go:embed DefaultMacTemplateIcon.png
+var SystrayMacTemplate []byte
+
+//go:embed systray-light.png
+var SystrayLight []byte
+
+//go:embed systray-dark.png
+var SystrayDark []byte
+
+//go:embed ApplicationDarkMode-256.png
+var ApplicationDarkMode256 []byte
+
+//go:embed ApplicationLightMode-256.png
+var ApplicationLightMode256 []byte
+
+//go:embed WailsLogoBlack.png
+var WailsLogoBlack []byte
+
+//go:embed WailsLogoBlackTransparent.png
+var WailsLogoBlackTransparent []byte
+
+//go:embed WailsLogoWhite.png
+var WailsLogoWhite []byte
+
+//go:embed WailsLogoWhiteTransparent.png
+var WailsLogoWhiteTransparent []byte
diff --git a/v3/pkg/icons/systray-dark.png b/v3/pkg/icons/systray-dark.png
new file mode 100644
index 000000000..6bfe5bd64
Binary files /dev/null and b/v3/pkg/icons/systray-dark.png differ
diff --git a/v3/pkg/icons/systray-light.png b/v3/pkg/icons/systray-light.png
new file mode 100644
index 000000000..a96c3b33c
Binary files /dev/null and b/v3/pkg/icons/systray-light.png differ
diff --git a/v3/pkg/w32/clipboard.go b/v3/pkg/w32/clipboard.go
new file mode 100644
index 000000000..89334c0a4
--- /dev/null
+++ b/v3/pkg/w32/clipboard.go
@@ -0,0 +1,143 @@
+//go:build windows
+
+/*
+ * Based on code originally from https://github.com/atotto/clipboard. Copyright (c) 2013 Ato Araki. All rights reserved.
+ */
+
+package w32
+
+import (
+ "runtime"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+const (
+ cfUnicodetext = 13
+ gmemMoveable = 0x0002
+)
+
+// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
+func waitOpenClipboard() error {
+ started := time.Now()
+ limit := started.Add(time.Second)
+ var r uintptr
+ var err error
+ for time.Now().Before(limit) {
+ r, _, err = procOpenClipboard.Call(0)
+ if r != 0 {
+ return nil
+ }
+ time.Sleep(time.Millisecond)
+ }
+ return err
+}
+
+func GetClipboardText() (string, error) {
+ // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
+ // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if formatAvailable, _, err := procIsClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 {
+ return "", err
+ }
+ err := waitOpenClipboard()
+ if err != nil {
+ return "", err
+ }
+
+ h, _, err := procGetClipboardData.Call(cfUnicodetext)
+ if h == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ l, _, err := kernelGlobalLock.Call(h)
+ if l == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])
+
+ r, _, err := kernelGlobalUnlock.Call(h)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ closed, _, err := procCloseClipboard.Call()
+ if closed == 0 {
+ return "", err
+ }
+ return text, nil
+}
+
+func SetClipboardText(text string) error {
+ // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
+ // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := waitOpenClipboard()
+ if err != nil {
+ return err
+ }
+
+ r, _, err := procEmptyClipboard.Call(0)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ data, err := syscall.UTF16FromString(text)
+ if err != nil {
+ return err
+ }
+
+ // "If the hMem parameter identifies a memory object, the object must have
+ // been allocated using the function with the GMEM_MOVEABLE flag."
+ h, _, err := kernelGlobalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
+ if h == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ defer func() {
+ if h != 0 {
+ kernelGlobalFree.Call(h)
+ }
+ }()
+
+ l, _, err := kernelGlobalLock.Call(h)
+ if l == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ r, _, err = kernelLstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ r, _, err = kernelGlobalUnlock.Call(h)
+ if r == 0 {
+ if err.(syscall.Errno) != 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ }
+
+ r, _, err = procSetClipboardData.Call(cfUnicodetext, h)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ h = 0 // suppress deferred cleanup
+ closed, _, err := procCloseClipboard.Call()
+ if closed == 0 {
+ return err
+ }
+ return nil
+}
diff --git a/v3/pkg/w32/comctl32.go b/v3/pkg/w32/comctl32.go
new file mode 100644
index 000000000..b66709f5f
--- /dev/null
+++ b/v3/pkg/w32/comctl32.go
@@ -0,0 +1,112 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomctl32 = syscall.NewLazyDLL("comctl32.dll")
+
+ procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
+ procImageList_Create = modcomctl32.NewProc("ImageList_Create")
+ procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy")
+ procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount")
+ procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount")
+ procImageList_Add = modcomctl32.NewProc("ImageList_Add")
+ procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon")
+ procImageList_Remove = modcomctl32.NewProc("ImageList_Remove")
+ procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent")
+)
+
+func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool {
+ ret, _, _ := procInitCommonControlsEx.Call(
+ uintptr(unsafe.Pointer(lpInitCtrls)))
+
+ return ret != 0
+}
+
+func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST {
+ ret, _, _ := procImageList_Create.Call(
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(flags),
+ uintptr(cInitial),
+ uintptr(cGrow))
+
+ if ret == 0 {
+ panic("Create image list failed")
+ }
+
+ return HIMAGELIST(ret)
+}
+
+func ImageList_Destroy(himl HIMAGELIST) bool {
+ ret, _, _ := procImageList_Destroy.Call(
+ uintptr(himl))
+
+ return ret != 0
+}
+
+func ImageList_GetImageCount(himl HIMAGELIST) int {
+ ret, _, _ := procImageList_GetImageCount.Call(
+ uintptr(himl))
+
+ return int(ret)
+}
+
+func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool {
+ ret, _, _ := procImageList_SetImageCount.Call(
+ uintptr(himl),
+ uintptr(uNewCount))
+
+ return ret != 0
+}
+
+func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int {
+ ret, _, _ := procImageList_Add.Call(
+ uintptr(himl),
+ uintptr(hbmImage),
+ uintptr(hbmMask))
+
+ return int(ret)
+}
+
+func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int {
+ ret, _, _ := procImageList_ReplaceIcon.Call(
+ uintptr(himl),
+ uintptr(i),
+ uintptr(hicon))
+
+ return int(ret)
+}
+
+func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int {
+ return ImageList_ReplaceIcon(himl, -1, hicon)
+}
+
+func ImageList_Remove(himl HIMAGELIST, i int) bool {
+ ret, _, _ := procImageList_Remove.Call(
+ uintptr(himl),
+ uintptr(i))
+
+ return ret != 0
+}
+
+func ImageList_RemoveAll(himl HIMAGELIST) bool {
+ return ImageList_Remove(himl, -1)
+}
+
+func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool {
+ ret, _, _ := procTrackMouseEvent.Call(
+ uintptr(unsafe.Pointer(tme)))
+
+ return ret != 0
+}
diff --git a/v3/pkg/w32/comdlg32.go b/v3/pkg/w32/comdlg32.go
new file mode 100644
index 000000000..d28922c33
--- /dev/null
+++ b/v3/pkg/w32/comdlg32.go
@@ -0,0 +1,40 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll")
+
+ procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW")
+ procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW")
+ procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
+)
+
+func GetOpenFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetOpenFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func GetSaveFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetSaveFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func CommDlgExtendedError() uint {
+ ret, _, _ := procCommDlgExtendedError.Call()
+
+ return uint(ret)
+}
diff --git a/v3/pkg/w32/constants.go b/v3/pkg/w32/constants.go
new file mode 100644
index 000000000..46e834ee9
--- /dev/null
+++ b/v3/pkg/w32/constants.go
@@ -0,0 +1,3602 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+const (
+ FALSE = 0
+ TRUE = 1
+)
+
+const (
+ NO_ERROR = 0
+ ERROR_SUCCESS = 0
+ ERROR_FILE_NOT_FOUND = 2
+ ERROR_PATH_NOT_FOUND = 3
+ ERROR_ACCESS_DENIED = 5
+ ERROR_INVALID_HANDLE = 6
+ ERROR_BAD_FORMAT = 11
+ ERROR_INVALID_NAME = 123
+ ERROR_MORE_DATA = 234
+ ERROR_NO_MORE_ITEMS = 259
+ ERROR_INVALID_SERVICE_CONTROL = 1052
+ ERROR_SERVICE_REQUEST_TIMEOUT = 1053
+ ERROR_SERVICE_NO_THREAD = 1054
+ ERROR_SERVICE_DATABASE_LOCKED = 1055
+ ERROR_SERVICE_ALREADY_RUNNING = 1056
+ ERROR_SERVICE_DISABLED = 1058
+ ERROR_SERVICE_DOES_NOT_EXIST = 1060
+ ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061
+ ERROR_SERVICE_NOT_ACTIVE = 1062
+ ERROR_DATABASE_DOES_NOT_EXIST = 1065
+ ERROR_SERVICE_DEPENDENCY_FAIL = 1068
+ ERROR_SERVICE_LOGON_FAILED = 1069
+ ERROR_SERVICE_MARKED_FOR_DELETE = 1072
+ ERROR_SERVICE_DEPENDENCY_DELETED = 1075
+)
+
+const (
+ SE_ERR_FNF = 2
+ SE_ERR_PNF = 3
+ SE_ERR_ACCESSDENIED = 5
+ SE_ERR_OOM = 8
+ SE_ERR_DLLNOTFOUND = 32
+ SE_ERR_SHARE = 26
+ SE_ERR_ASSOCINCOMPLETE = 27
+ SE_ERR_DDETIMEOUT = 28
+ SE_ERR_DDEFAIL = 29
+ SE_ERR_DDEBUSY = 30
+ SE_ERR_NOASSOC = 31
+)
+
+const (
+ CW_USEDEFAULT = ^0x7fffffff
+)
+
+const (
+ IMAGE_BITMAP = 0
+ IMAGE_ICON = 1
+ IMAGE_CURSOR = 2
+ IMAGE_ENHMETAFILE = 3
+)
+
+// ShowWindow constants
+const (
+ SW_HIDE = 0
+ SW_NORMAL = 1
+ SW_SHOWNORMAL = 1
+ SW_SHOWMINIMIZED = 2
+ SW_MAXIMIZE = 3
+ SW_SHOWMAXIMIZED = 3
+ SW_SHOWNOACTIVATE = 4
+ SW_SHOW = 5
+ SW_MINIMIZE = 6
+ SW_SHOWMINNOACTIVE = 7
+ SW_SHOWNA = 8
+ SW_RESTORE = 9
+ SW_SHOWDEFAULT = 10
+ SW_FORCEMINIMIZE = 11
+)
+
+// Window class styles
+const (
+ CS_VREDRAW = 0x00000001
+ CS_HREDRAW = 0x00000002
+ CS_KEYCVTWINDOW = 0x00000004
+ CS_DBLCLKS = 0x00000008
+ CS_OWNDC = 0x00000020
+ CS_CLASSDC = 0x00000040
+ CS_PARENTDC = 0x00000080
+ CS_NOKEYCVT = 0x00000100
+ CS_NOCLOSE = 0x00000200
+ CS_SAVEBITS = 0x00000800
+ CS_BYTEALIGNCLIENT = 0x00001000
+ CS_BYTEALIGNWINDOW = 0x00002000
+ CS_GLOBALCLASS = 0x00004000
+ CS_IME = 0x00010000
+ CS_DROPSHADOW = 0x00020000
+)
+
+// Predefined cursor constants
+const (
+ IDC_ARROW = 32512
+ IDC_IBEAM = 32513
+ IDC_WAIT = 32514
+ IDC_CROSS = 32515
+ IDC_UPARROW = 32516
+ IDC_SIZENWSE = 32642
+ IDC_SIZENESW = 32643
+ IDC_SIZEWE = 32644
+ IDC_SIZENS = 32645
+ IDC_SIZEALL = 32646
+ IDC_NO = 32648
+ IDC_HAND = 32649
+ IDC_APPSTARTING = 32650
+ IDC_HELP = 32651
+ IDC_ICON = 32641
+ IDC_SIZE = 32640
+)
+
+// Predefined icon constants
+const (
+ IDI_APPLICATION = 32512
+ IDI_HAND = 32513
+ IDI_QUESTION = 32514
+ IDI_EXCLAMATION = 32515
+ IDI_ASTERISK = 32516
+ IDI_WINLOGO = 32517
+ IDI_WARNING = IDI_EXCLAMATION
+ IDI_ERROR = IDI_HAND
+ IDI_INFORMATION = IDI_ASTERISK
+)
+
+// Button style constants
+const (
+ BS_3STATE = 5
+ BS_AUTO3STATE = 6
+ BS_AUTOCHECKBOX = 3
+ BS_AUTORADIOBUTTON = 9
+ BS_BITMAP = 128
+ BS_BOTTOM = 0x800
+ BS_CENTER = 0x300
+ BS_CHECKBOX = 2
+ BS_DEFPUSHBUTTON = 1
+ BS_GROUPBOX = 7
+ BS_ICON = 64
+ BS_LEFT = 256
+ BS_LEFTTEXT = 32
+ BS_MULTILINE = 0x2000
+ BS_NOTIFY = 0x4000
+ BS_OWNERDRAW = 0xB
+ BS_PUSHBUTTON = 0
+ BS_PUSHLIKE = 4096
+ BS_RADIOBUTTON = 4
+ BS_RIGHT = 512
+ BS_RIGHTBUTTON = 32
+ BS_TEXT = 0
+ BS_TOP = 0x400
+ BS_USERBUTTON = 8
+ BS_VCENTER = 0xC00
+ BS_FLAT = 0x8000
+ BS_SPLITBUTTON = 0x000C // >= Vista
+ BS_DEFSPLITBUTTON = 0x000D // >= Vista
+)
+
+// Button state constants
+const (
+ BST_CHECKED = 1
+ BST_INDETERMINATE = 2
+ BST_UNCHECKED = 0
+ BST_FOCUS = 8
+ BST_PUSHED = 4
+)
+
+// Predefined brushes constants
+const (
+ COLOR_3DDKSHADOW = 21
+ COLOR_3DFACE = 15
+ COLOR_3DHILIGHT = 20
+ COLOR_3DHIGHLIGHT = 20
+ COLOR_3DLIGHT = 22
+ COLOR_BTNHILIGHT = 20
+ COLOR_3DSHADOW = 16
+ COLOR_ACTIVEBORDER = 10
+ COLOR_ACTIVECAPTION = 2
+ COLOR_APPWORKSPACE = 12
+ COLOR_BACKGROUND = 1
+ COLOR_DESKTOP = 1
+ COLOR_BTNFACE = 15
+ COLOR_BTNHIGHLIGHT = 20
+ COLOR_BTNSHADOW = 16
+ COLOR_BTNTEXT = 18
+ COLOR_CAPTIONTEXT = 9
+ COLOR_GRAYTEXT = 17
+ COLOR_HIGHLIGHT = 13
+ COLOR_HIGHLIGHTTEXT = 14
+ COLOR_INACTIVEBORDER = 11
+ COLOR_INACTIVECAPTION = 3
+ COLOR_INACTIVECAPTIONTEXT = 19
+ COLOR_INFOBK = 24
+ COLOR_INFOTEXT = 23
+ COLOR_MENU = 4
+ COLOR_MENUTEXT = 7
+ COLOR_SCROLLBAR = 0
+ COLOR_WINDOW = 5
+ COLOR_WINDOWFRAME = 6
+ COLOR_WINDOWTEXT = 8
+ COLOR_HOTLIGHT = 26
+ COLOR_GRADIENTACTIVECAPTION = 27
+ COLOR_GRADIENTINACTIVECAPTION = 28
+)
+
+// Button message constants
+const (
+ BM_CLICK = 245
+ BM_GETCHECK = 240
+ BM_GETIMAGE = 246
+ BM_GETSTATE = 242
+ BM_SETCHECK = 241
+ BM_SETIMAGE = 247
+ BM_SETSTATE = 243
+ BM_SETSTYLE = 244
+)
+
+// Button notifications
+const (
+ BN_CLICKED = 0
+ BN_PAINT = 1
+ BN_HILITE = 2
+ BN_PUSHED = BN_HILITE
+ BN_UNHILITE = 3
+ BN_UNPUSHED = BN_UNHILITE
+ BN_DISABLE = 4
+ BN_DOUBLECLICKED = 5
+ BN_DBLCLK = BN_DOUBLECLICKED
+ BN_SETFOCUS = 6
+ BN_KILLFOCUS = 7
+)
+
+// TrackPopupMenu[Ex] flags
+const (
+ TPM_CENTERALIGN = 0x0004
+ TPM_LEFTALIGN = 0x0000
+ TPM_RIGHTALIGN = 0x0008
+ TPM_BOTTOMALIGN = 0x0020
+ TPM_TOPALIGN = 0x0000
+ TPM_VCENTERALIGN = 0x0010
+ TPM_NONOTIFY = 0x0080
+ TPM_RETURNCMD = 0x0100
+ TPM_LEFTBUTTON = 0x0000
+ TPM_RIGHTBUTTON = 0x0002
+ TPM_HORNEGANIMATION = 0x0800
+ TPM_HORPOSANIMATION = 0x0400
+ TPM_NOANIMATION = 0x4000
+ TPM_VERNEGANIMATION = 0x2000
+ TPM_VERPOSANIMATION = 0x1000
+ TPM_HORIZONTAL = 0x0000
+ TPM_VERTICAL = 0x0040
+)
+
+// GetWindowLong and GetWindowLongPtr constants
+const (
+ GWL_EXSTYLE = -20
+ GWL_STYLE = -16
+ GWL_WNDPROC = -4
+ GWLP_WNDPROC = -4
+ GWL_HINSTANCE = -6
+ GWLP_HINSTANCE = -6
+ GWL_HWNDPARENT = -8
+ GWLP_HWNDPARENT = -8
+ GWL_ID = -12
+ GWLP_ID = -12
+ GWL_USERDATA = -21
+ GWLP_USERDATA = -21
+)
+
+const (
+ GW_HWNDFIRST = 0
+ GW_HWNDLAST = 1
+ GW_HWNDNEXT = 2
+ GW_HWNDPREV = 3
+ GW_OWNER = 4
+ GW_CHILD = 5
+ GW_ENABLEDPOPUP = 6
+)
+
+// Window style constants
+const (
+ WS_OVERLAPPED = 0x00000000
+ WS_POPUP = 0x80000000
+ WS_CHILD = 0x40000000
+ WS_MINIMIZE = 0x20000000
+ WS_VISIBLE = 0x10000000
+ WS_DISABLED = 0x08000000
+ WS_CLIPSIBLINGS = 0x04000000
+ WS_CLIPCHILDREN = 0x02000000
+ WS_MAXIMIZE = 0x01000000
+ WS_CAPTION = 0x00C00000
+ WS_BORDER = 0x00800000
+ WS_DLGFRAME = 0x00400000
+ WS_VSCROLL = 0x00200000
+ WS_HSCROLL = 0x00100000
+ WS_SYSMENU = 0x00080000
+ WS_THICKFRAME = 0x00040000
+ WS_GROUP = 0x00020000
+ WS_TABSTOP = 0x00010000
+ WS_MINIMIZEBOX = 0x00020000
+ WS_MAXIMIZEBOX = 0x00010000
+ WS_TILED = 0x00000000
+ WS_ICONIC = 0x20000000
+ WS_SIZEBOX = 0x00040000
+ WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000
+ WS_POPUPWINDOW = 0x80000000 | 0x00800000 | 0x00080000
+ WS_CHILDWINDOW = 0x40000000
+)
+
+// Extended window style constants
+const (
+ WS_EX_DLGMODALFRAME = 0x00000001
+ WS_EX_NOPARENTNOTIFY = 0x00000004
+ WS_EX_TOPMOST = 0x00000008
+ WS_EX_ACCEPTFILES = 0x00000010
+ WS_EX_TRANSPARENT = 0x00000020
+ WS_EX_MDICHILD = 0x00000040
+ WS_EX_TOOLWINDOW = 0x00000080
+ WS_EX_WINDOWEDGE = 0x00000100
+ WS_EX_CLIENTEDGE = 0x00000200
+ WS_EX_CONTEXTHELP = 0x00000400
+ WS_EX_RIGHT = 0x00001000
+ WS_EX_LEFT = 0x00000000
+ WS_EX_RTLREADING = 0x00002000
+ WS_EX_LTRREADING = 0x00000000
+ WS_EX_LEFTSCROLLBAR = 0x00004000
+ WS_EX_RIGHTSCROLLBAR = 0x00000000
+ WS_EX_CONTROLPARENT = 0x00010000
+ WS_EX_STATICEDGE = 0x00020000
+ WS_EX_APPWINDOW = 0x00040000
+ WS_EX_OVERLAPPEDWINDOW = 0x00000100 | 0x00000200
+ WS_EX_PALETTEWINDOW = 0x00000100 | 0x00000080 | 0x00000008
+ WS_EX_LAYERED = 0x00080000
+ WS_EX_NOINHERITLAYOUT = 0x00100000
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000
+ WS_EX_LAYOUTRTL = 0x00400000
+ WS_EX_NOACTIVATE = 0x08000000
+)
+
+// Window message constants
+const (
+ WM_APP = 32768
+ WM_ACTIVATE = 6
+ WM_ACTIVATEAPP = 28
+ WM_AFXFIRST = 864
+ WM_AFXLAST = 895
+ WM_ASKCBFORMATNAME = 780
+ WM_CANCELJOURNAL = 75
+ WM_CANCELMODE = 31
+ WM_CAPTURECHANGED = 533
+ WM_CHANGECBCHAIN = 781
+ WM_CHAR = 258
+ WM_CHARTOITEM = 47
+ WM_CHILDACTIVATE = 34
+ WM_CLEAR = 771
+ WM_CLOSE = 16
+ WM_COMMAND = 273
+ WM_COMMNOTIFY = 68 /* OBSOLETE */
+ WM_COMPACTING = 65
+ WM_COMPAREITEM = 57
+ WM_CONTEXTMENU = 123
+ WM_COPY = 769
+ WM_COPYDATA = 74
+ WM_CREATE = 1
+ WM_CTLCOLORBTN = 309
+ WM_CTLCOLORDLG = 310
+ WM_CTLCOLOREDIT = 307
+ WM_CTLCOLORLISTBOX = 308
+ WM_CTLCOLORMSGBOX = 306
+ WM_CTLCOLORSCROLLBAR = 311
+ WM_CTLCOLORSTATIC = 312
+ WM_CUT = 768
+ WM_DEADCHAR = 259
+ WM_DELETEITEM = 45
+ WM_DESTROY = 2
+ WM_DESTROYCLIPBOARD = 775
+ WM_DEVICECHANGE = 537
+ WM_DEVMODECHANGE = 27
+ WM_DISPLAYCHANGE = 126
+ WM_DRAWCLIPBOARD = 776
+ WM_DRAWITEM = 43
+ WM_DROPFILES = 563
+ WM_ENABLE = 10
+ WM_ENDSESSION = 22
+ WM_ENTERIDLE = 289
+ WM_ENTERMENULOOP = 529
+ WM_ENTERSIZEMOVE = 561
+ WM_ERASEBKGND = 20
+ WM_EXITMENULOOP = 530
+ WM_EXITSIZEMOVE = 562
+ WM_FONTCHANGE = 29
+ WM_GETDLGCODE = 135
+ WM_GETFONT = 49
+ WM_GETHOTKEY = 51
+ WM_GETICON = 127
+ WM_GETMINMAXINFO = 36
+ WM_GETTEXT = 13
+ WM_GETTEXTLENGTH = 14
+ WM_HANDHELDFIRST = 856
+ WM_HANDHELDLAST = 863
+ WM_HELP = 83
+ WM_HOTKEY = 786
+ WM_HSCROLL = 276
+ WM_HSCROLLCLIPBOARD = 782
+ WM_ICONERASEBKGND = 39
+ WM_INITDIALOG = 272
+ WM_INITMENU = 278
+ WM_INITMENUPOPUP = 279
+ WM_INPUT = 0x00FF
+ WM_INPUTLANGCHANGE = 81
+ WM_INPUTLANGCHANGEREQUEST = 80
+ WM_KEYDOWN = 256
+ WM_KEYUP = 257
+ WM_KILLFOCUS = 8
+ WM_MDIACTIVATE = 546
+ WM_MDICASCADE = 551
+ WM_MDICREATE = 544
+ WM_MDIDESTROY = 545
+ WM_MDIGETACTIVE = 553
+ WM_MDIICONARRANGE = 552
+ WM_MDIMAXIMIZE = 549
+ WM_MDINEXT = 548
+ WM_MDIREFRESHMENU = 564
+ WM_MDIRESTORE = 547
+ WM_MDISETMENU = 560
+ WM_MDITILE = 550
+ WM_MEASUREITEM = 44
+ WM_GETOBJECT = 0x003D
+ WM_CHANGEUISTATE = 0x0127
+ WM_UPDATEUISTATE = 0x0128
+ WM_QUERYUISTATE = 0x0129
+ WM_UNINITMENUPOPUP = 0x0125
+ WM_MENURBUTTONUP = 290
+ WM_MENUCOMMAND = 0x0126
+ WM_MENUGETOBJECT = 0x0124
+ WM_MENUDRAG = 0x0123
+ WM_APPCOMMAND = 0x0319
+ WM_MENUCHAR = 288
+ WM_MENUSELECT = 287
+ WM_MOVE = 3
+ WM_MOVING = 534
+ WM_NCACTIVATE = 134
+ WM_NCCALCSIZE = 131
+ WM_NCCREATE = 129
+ WM_NCDESTROY = 130
+ WM_NCHITTEST = 132
+ WM_NCLBUTTONDBLCLK = 163
+ WM_NCLBUTTONDOWN = 161
+ WM_NCLBUTTONUP = 162
+ WM_NCMBUTTONDBLCLK = 169
+ WM_NCMBUTTONDOWN = 167
+ WM_NCMBUTTONUP = 168
+ WM_NCXBUTTONDOWN = 171
+ WM_NCXBUTTONUP = 172
+ WM_NCXBUTTONDBLCLK = 173
+ WM_NCMOUSEHOVER = 0x02A0
+ WM_NCMOUSELEAVE = 0x02A2
+ WM_NCMOUSEMOVE = 160
+ WM_NCPAINT = 133
+ WM_NCRBUTTONDBLCLK = 166
+ WM_NCRBUTTONDOWN = 164
+ WM_NCRBUTTONUP = 165
+ WM_NEXTDLGCTL = 40
+ WM_NEXTMENU = 531
+ WM_NOTIFY = 78
+ WM_NOTIFYFORMAT = 85
+ WM_NULL = 0
+ WM_PAINT = 15
+ WM_PAINTCLIPBOARD = 777
+ WM_PAINTICON = 38
+ WM_PALETTECHANGED = 785
+ WM_PALETTEISCHANGING = 784
+ WM_PARENTNOTIFY = 528
+ WM_PASTE = 770
+ WM_PENWINFIRST = 896
+ WM_PENWINLAST = 911
+ WM_POWER = 72
+ WM_POWERBROADCAST = 536
+ WM_PRINT = 791
+ WM_PRINTCLIENT = 792
+ WM_QUERYDRAGICON = 55
+ WM_QUERYENDSESSION = 17
+ WM_QUERYNEWPALETTE = 783
+ WM_QUERYOPEN = 19
+ WM_QUEUESYNC = 35
+ WM_QUIT = 18
+ WM_RENDERALLFORMATS = 774
+ WM_RENDERFORMAT = 773
+ WM_SETCURSOR = 32
+ WM_SETFOCUS = 7
+ WM_SETFONT = 48
+ WM_SETHOTKEY = 50
+ WM_SETICON = 128
+ WM_SETREDRAW = 11
+ WM_SETTEXT = 12
+ WM_SETTINGCHANGE = 26
+ WM_SHOWWINDOW = 24
+ WM_SIZE = 5
+ WM_SIZECLIPBOARD = 779
+ WM_SIZING = 532
+ WM_SPOOLERSTATUS = 42
+ WM_STYLECHANGED = 125
+ WM_STYLECHANGING = 124
+ WM_SYSCHAR = 262
+ WM_SYSCOLORCHANGE = 21
+ WM_SYSCOMMAND = 274
+ WM_SYSDEADCHAR = 263
+ WM_SYSKEYDOWN = 260
+ WM_SYSKEYUP = 261
+ WM_TCARD = 82
+ WM_THEMECHANGED = 794
+ WM_TIMECHANGE = 30
+ WM_TIMER = 275
+ WM_UNDO = 772
+ WM_USER = 1024
+ WM_USERCHANGED = 84
+ WM_VKEYTOITEM = 46
+ WM_VSCROLL = 277
+ WM_VSCROLLCLIPBOARD = 778
+ WM_WINDOWPOSCHANGED = 71
+ WM_WINDOWPOSCHANGING = 70
+ WM_WININICHANGE = 26
+ WM_KEYFIRST = 256
+ WM_KEYLAST = 264
+ WM_SYNCPAINT = 136
+ WM_MOUSEACTIVATE = 33
+ WM_MOUSEMOVE = 512
+ WM_LBUTTONDOWN = 513
+ WM_LBUTTONUP = 514
+ WM_LBUTTONDBLCLK = 515
+ WM_RBUTTONDOWN = 516
+ WM_RBUTTONUP = 517
+ WM_RBUTTONDBLCLK = 518
+ WM_MBUTTONDOWN = 519
+ WM_MBUTTONUP = 520
+ WM_MBUTTONDBLCLK = 521
+ WM_MOUSEWHEEL = 522
+ WM_MOUSEHWHEEL = 526
+ WM_MOUSEFIRST = 512
+ WM_XBUTTONDOWN = 523
+ WM_XBUTTONUP = 524
+ WM_XBUTTONDBLCLK = 525
+ WM_MOUSELAST = 525
+ WM_MOUSEHOVER = 0x2A1
+ WM_MOUSELEAVE = 0x2A3
+ WM_CLIPBOARDUPDATE = 0x031D
+ WM_DPICHANGED = 0x02E0
+)
+
+// WM_ACTIVATE
+const (
+ WA_INACTIVE = 0
+ WA_ACTIVE = 1
+ WA_CLICKACTIVE = 2
+)
+
+const LF_FACESIZE = 32
+
+// Font weight constants
+const (
+ FW_DONTCARE = 0
+ FW_THIN = 100
+ FW_EXTRALIGHT = 200
+ FW_ULTRALIGHT = FW_EXTRALIGHT
+ FW_LIGHT = 300
+ FW_NORMAL = 400
+ FW_REGULAR = 400
+ FW_MEDIUM = 500
+ FW_SEMIBOLD = 600
+ FW_DEMIBOLD = FW_SEMIBOLD
+ FW_BOLD = 700
+ FW_EXTRABOLD = 800
+ FW_ULTRABOLD = FW_EXTRABOLD
+ FW_HEAVY = 900
+ FW_BLACK = FW_HEAVY
+)
+
+// Charset constants
+const (
+ ANSI_CHARSET = 0
+ DEFAULT_CHARSET = 1
+ SYMBOL_CHARSET = 2
+ SHIFTJIS_CHARSET = 128
+ HANGEUL_CHARSET = 129
+ HANGUL_CHARSET = 129
+ GB2312_CHARSET = 134
+ CHINESEBIG5_CHARSET = 136
+ GREEK_CHARSET = 161
+ TURKISH_CHARSET = 162
+ HEBREW_CHARSET = 177
+ ARABIC_CHARSET = 178
+ BALTIC_CHARSET = 186
+ RUSSIAN_CHARSET = 204
+ THAI_CHARSET = 222
+ EASTEUROPE_CHARSET = 238
+ OEM_CHARSET = 255
+ JOHAB_CHARSET = 130
+ VIETNAMESE_CHARSET = 163
+ MAC_CHARSET = 77
+)
+
+const (
+ // PBT_APMPOWERSTATUSCHANGE - Power status has changed.
+ PBT_APMPOWERSTATUSCHANGE = 10
+
+ // PBT_APMRESUMEAUTOMATIC -Operation is resuming automatically from a low-power state. This message is sent every time the system resumes.
+ PBT_APMRESUMEAUTOMATIC = 18
+
+ // PBT_APMRESUMESUSPEND - Operation is resuming from a low-power state. This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.
+ PBT_APMRESUMESUSPEND = 7
+
+ // PBT_APMSUSPEND - System is suspending operation.
+ PBT_APMSUSPEND = 4
+
+ // PBT_POWERSETTINGCHANGE - A power setting change event has been received.
+ PBT_POWERSETTINGCHANGE = 32787
+)
+
+// Font output precision constants
+const (
+ OUT_DEFAULT_PRECIS = 0
+ OUT_STRING_PRECIS = 1
+ OUT_CHARACTER_PRECIS = 2
+ OUT_STROKE_PRECIS = 3
+ OUT_TT_PRECIS = 4
+ OUT_DEVICE_PRECIS = 5
+ OUT_RASTER_PRECIS = 6
+ OUT_TT_ONLY_PRECIS = 7
+ OUT_OUTLINE_PRECIS = 8
+ OUT_PS_ONLY_PRECIS = 10
+)
+
+// Font clipping precision constants
+const (
+ CLIP_DEFAULT_PRECIS = 0
+ CLIP_CHARACTER_PRECIS = 1
+ CLIP_STROKE_PRECIS = 2
+ CLIP_MASK = 15
+ CLIP_LH_ANGLES = 16
+ CLIP_TT_ALWAYS = 32
+ CLIP_EMBEDDED = 128
+)
+
+// Font output quality constants
+const (
+ DEFAULT_QUALITY = 0
+ DRAFT_QUALITY = 1
+ PROOF_QUALITY = 2
+ NONANTIALIASED_QUALITY = 3
+ ANTIALIASED_QUALITY = 4
+ CLEARTYPE_QUALITY = 5
+)
+
+// Font pitch constants
+const (
+ DEFAULT_PITCH = 0
+ FIXED_PITCH = 1
+ VARIABLE_PITCH = 2
+)
+
+// Font family constants
+const (
+ FF_DECORATIVE = 80
+ FF_DONTCARE = 0
+ FF_MODERN = 48
+ FF_ROMAN = 16
+ FF_SCRIPT = 64
+ FF_SWISS = 32
+)
+
+// DeviceCapabilities capabilities
+const (
+ DC_FIELDS = 1
+ DC_PAPERS = 2
+ DC_PAPERSIZE = 3
+ DC_MINEXTENT = 4
+ DC_MAXEXTENT = 5
+ DC_BINS = 6
+ DC_DUPLEX = 7
+ DC_SIZE = 8
+ DC_EXTRA = 9
+ DC_VERSION = 10
+ DC_DRIVER = 11
+ DC_BINNAMES = 12
+ DC_ENUMRESOLUTIONS = 13
+ DC_FILEDEPENDENCIES = 14
+ DC_TRUETYPE = 15
+ DC_PAPERNAMES = 16
+ DC_ORIENTATION = 17
+ DC_COPIES = 18
+ DC_BINADJUST = 19
+ DC_EMF_COMPLIANT = 20
+ DC_DATATYPE_PRODUCED = 21
+ DC_COLLATE = 22
+ DC_MANUFACTURER = 23
+ DC_MODEL = 24
+ DC_PERSONALITY = 25
+ DC_PRINTRATE = 26
+ DC_PRINTRATEUNIT = 27
+ DC_PRINTERMEM = 28
+ DC_MEDIAREADY = 29
+ DC_STAPLE = 30
+ DC_PRINTRATEPPM = 31
+ DC_COLORDEVICE = 32
+ DC_NUP = 33
+ DC_MEDIATYPENAMES = 34
+ DC_MEDIATYPES = 35
+)
+
+// GetDeviceCaps index constants
+const (
+ DRIVERVERSION = 0
+ TECHNOLOGY = 2
+ HORZSIZE = 4
+ VERTSIZE = 6
+ HORZRES = 8
+ VERTRES = 10
+ LOGPIXELSX = 88
+ LOGPIXELSY = 90
+ BITSPIXEL = 12
+ PLANES = 14
+ NUMBRUSHES = 16
+ NUMPENS = 18
+ NUMFONTS = 22
+ NUMCOLORS = 24
+ NUMMARKERS = 20
+ ASPECTX = 40
+ ASPECTY = 42
+ ASPECTXY = 44
+ PDEVICESIZE = 26
+ CLIPCAPS = 36
+ SIZEPALETTE = 104
+ NUMRESERVED = 106
+ COLORRES = 108
+ PHYSICALWIDTH = 110
+ PHYSICALHEIGHT = 111
+ PHYSICALOFFSETX = 112
+ PHYSICALOFFSETY = 113
+ SCALINGFACTORX = 114
+ SCALINGFACTORY = 115
+ VREFRESH = 116
+ DESKTOPHORZRES = 118
+ DESKTOPVERTRES = 117
+ BLTALIGNMENT = 119
+ SHADEBLENDCAPS = 120
+ COLORMGMTCAPS = 121
+ RASTERCAPS = 38
+ CURVECAPS = 28
+ LINECAPS = 30
+ POLYGONALCAPS = 32
+ TEXTCAPS = 34
+)
+
+// GetDeviceCaps TECHNOLOGY constants
+const (
+ DT_PLOTTER = 0
+ DT_RASDISPLAY = 1
+ DT_RASPRINTER = 2
+ DT_RASCAMERA = 3
+ DT_CHARSTREAM = 4
+ DT_METAFILE = 5
+ DT_DISPFILE = 6
+)
+
+// GetDeviceCaps SHADEBLENDCAPS constants
+const (
+ SB_NONE = 0x00
+ SB_CONST_ALPHA = 0x01
+ SB_PIXEL_ALPHA = 0x02
+ SB_PREMULT_ALPHA = 0x04
+ SB_GRAD_RECT = 0x10
+ SB_GRAD_TRI = 0x20
+)
+
+// GetDeviceCaps COLORMGMTCAPS constants
+const (
+ CM_NONE = 0x00
+ CM_DEVICE_ICM = 0x01
+ CM_GAMMA_RAMP = 0x02
+ CM_CMYK_COLOR = 0x04
+)
+
+// GetDeviceCaps RASTERCAPS constants
+const (
+ RC_BANDING = 2
+ RC_BITBLT = 1
+ RC_BITMAP64 = 8
+ RC_DI_BITMAP = 128
+ RC_DIBTODEV = 512
+ RC_FLOODFILL = 4096
+ RC_GDI20_OUTPUT = 16
+ RC_PALETTE = 256
+ RC_SCALING = 4
+ RC_STRETCHBLT = 2048
+ RC_STRETCHDIB = 8192
+ RC_DEVBITS = 0x8000
+ RC_OP_DX_OUTPUT = 0x4000
+)
+
+// GetDeviceCaps CURVECAPS constants
+const (
+ CC_NONE = 0
+ CC_CIRCLES = 1
+ CC_PIE = 2
+ CC_CHORD = 4
+ CC_ELLIPSES = 8
+ CC_WIDE = 16
+ CC_STYLED = 32
+ CC_WIDESTYLED = 64
+ CC_INTERIORS = 128
+ CC_ROUNDRECT = 256
+)
+
+// GetDeviceCaps LINECAPS constants
+const (
+ LC_NONE = 0
+ LC_POLYLINE = 2
+ LC_MARKER = 4
+ LC_POLYMARKER = 8
+ LC_WIDE = 16
+ LC_STYLED = 32
+ LC_WIDESTYLED = 64
+ LC_INTERIORS = 128
+)
+
+// GetDeviceCaps POLYGONALCAPS constants
+const (
+ PC_NONE = 0
+ PC_POLYGON = 1
+ PC_POLYPOLYGON = 256
+ PC_PATHS = 512
+ PC_RECTANGLE = 2
+ PC_WINDPOLYGON = 4
+ PC_SCANLINE = 8
+ PC_TRAPEZOID = 4
+ PC_WIDE = 16
+ PC_STYLED = 32
+ PC_WIDESTYLED = 64
+ PC_INTERIORS = 128
+)
+
+// GetDeviceCaps TEXTCAPS constants
+const (
+ TC_OP_CHARACTER = 1
+ TC_OP_STROKE = 2
+ TC_CP_STROKE = 4
+ TC_CR_90 = 8
+ TC_CR_ANY = 16
+ TC_SF_X_YINDEP = 32
+ TC_SA_DOUBLE = 64
+ TC_SA_INTEGER = 128
+ TC_SA_CONTIN = 256
+ TC_EA_DOUBLE = 512
+ TC_IA_ABLE = 1024
+ TC_UA_ABLE = 2048
+ TC_SO_ABLE = 4096
+ TC_RA_ABLE = 8192
+ TC_VA_ABLE = 16384
+ TC_RESERVED = 32768
+ TC_SCROLLBLT = 65536
+)
+
+// Static control styles
+const (
+ SS_BITMAP = 14
+ SS_BLACKFRAME = 7
+ SS_BLACKRECT = 4
+ SS_CENTER = 1
+ SS_CENTERIMAGE = 512
+ SS_EDITCONTROL = 0x2000
+ SS_ENHMETAFILE = 15
+ SS_ETCHEDFRAME = 18
+ SS_ETCHEDHORZ = 16
+ SS_ETCHEDVERT = 17
+ SS_GRAYFRAME = 8
+ SS_GRAYRECT = 5
+ SS_ICON = 3
+ SS_LEFT = 0
+ SS_LEFTNOWORDWRAP = 0xc
+ SS_NOPREFIX = 128
+ SS_NOTIFY = 256
+ SS_OWNERDRAW = 0xd
+ SS_REALSIZECONTROL = 0x040
+ SS_REALSIZEIMAGE = 0x800
+ SS_RIGHT = 2
+ SS_RIGHTJUST = 0x400
+ SS_SIMPLE = 11
+ SS_SUNKEN = 4096
+ SS_WHITEFRAME = 9
+ SS_WHITERECT = 6
+ SS_USERITEM = 10
+ SS_TYPEMASK = 0x0000001F
+ SS_ENDELLIPSIS = 0x00004000
+ SS_PATHELLIPSIS = 0x00008000
+ SS_WORDELLIPSIS = 0x0000C000
+ SS_ELLIPSISMASK = 0x0000C000
+)
+
+// Edit styles
+const (
+ ES_LEFT = 0x0000
+ ES_CENTER = 0x0001
+ ES_RIGHT = 0x0002
+ ES_MULTILINE = 0x0004
+ ES_UPPERCASE = 0x0008
+ ES_LOWERCASE = 0x0010
+ ES_PASSWORD = 0x0020
+ ES_AUTOVSCROLL = 0x0040
+ ES_AUTOHSCROLL = 0x0080
+ ES_NOHIDESEL = 0x0100
+ ES_OEMCONVERT = 0x0400
+ ES_READONLY = 0x0800
+ ES_WANTRETURN = 0x1000
+ ES_NUMBER = 0x2000
+)
+
+// Edit notifications
+const (
+ EN_SETFOCUS = 0x0100
+ EN_KILLFOCUS = 0x0200
+ EN_CHANGE = 0x0300
+ EN_UPDATE = 0x0400
+ EN_ERRSPACE = 0x0500
+ EN_MAXTEXT = 0x0501
+ EN_HSCROLL = 0x0601
+ EN_VSCROLL = 0x0602
+ EN_ALIGN_LTR_EC = 0x0700
+ EN_ALIGN_RTL_EC = 0x0701
+)
+
+// Edit messages
+const (
+ EM_GETSEL = 0x00B0
+ EM_SETSEL = 0x00B1
+ EM_GETRECT = 0x00B2
+ EM_SETRECT = 0x00B3
+ EM_SETRECTNP = 0x00B4
+ EM_SCROLL = 0x00B5
+ EM_LINESCROLL = 0x00B6
+ EM_SCROLLCARET = 0x00B7
+ EM_GETMODIFY = 0x00B8
+ EM_SETMODIFY = 0x00B9
+ EM_GETLINECOUNT = 0x00BA
+ EM_LINEINDEX = 0x00BB
+ EM_SETHANDLE = 0x00BC
+ EM_GETHANDLE = 0x00BD
+ EM_GETTHUMB = 0x00BE
+ EM_LINELENGTH = 0x00C1
+ EM_REPLACESEL = 0x00C2
+ EM_GETLINE = 0x00C4
+ EM_LIMITTEXT = 0x00C5
+ EM_CANUNDO = 0x00C6
+ EM_UNDO = 0x00C7
+ EM_FMTLINES = 0x00C8
+ EM_LINEFROMCHAR = 0x00C9
+ EM_SETTABSTOPS = 0x00CB
+ EM_SETPASSWORDCHAR = 0x00CC
+ EM_EMPTYUNDOBUFFER = 0x00CD
+ EM_GETFIRSTVISIBLELINE = 0x00CE
+ EM_SETREADONLY = 0x00CF
+ EM_SETWORDBREAKPROC = 0x00D0
+ EM_GETWORDBREAKPROC = 0x00D1
+ EM_GETPASSWORDCHAR = 0x00D2
+ EM_SETMARGINS = 0x00D3
+ EM_GETMARGINS = 0x00D4
+ EM_SETLIMITTEXT = EM_LIMITTEXT
+ EM_GETLIMITTEXT = 0x00D5
+ EM_POSFROMCHAR = 0x00D6
+ EM_CHARFROMPOS = 0x00D7
+ EM_SETIMESTATUS = 0x00D8
+ EM_GETIMESTATUS = 0x00D9
+ EM_SETCUEBANNER = 0x1501
+ EM_GETCUEBANNER = 0x1502
+)
+
+const (
+ CCM_FIRST = 0x2000
+ CCM_LAST = CCM_FIRST + 0x200
+ CCM_SETBKCOLOR = 8193
+ CCM_SETCOLORSCHEME = 8194
+ CCM_GETCOLORSCHEME = 8195
+ CCM_GETDROPTARGET = 8196
+ CCM_SETUNICODEFORMAT = 8197
+ CCM_GETUNICODEFORMAT = 8198
+ CCM_SETVERSION = 0x2007
+ CCM_GETVERSION = 0x2008
+ CCM_SETNOTIFYWINDOW = 0x2009
+ CCM_SETWINDOWTHEME = 0x200b
+ CCM_DPISCALE = 0x200c
+)
+
+// Common controls styles
+const (
+ CCS_TOP = 1
+ CCS_NOMOVEY = 2
+ CCS_BOTTOM = 3
+ CCS_NORESIZE = 4
+ CCS_NOPARENTALIGN = 8
+ CCS_ADJUSTABLE = 32
+ CCS_NODIVIDER = 64
+ CCS_VERT = 128
+ CCS_LEFT = 129
+ CCS_NOMOVEX = 130
+ CCS_RIGHT = 131
+)
+
+// ProgressBar messages
+const (
+ PROGRESS_CLASS = "msctls_progress32"
+ PBM_SETPOS = WM_USER + 2
+ PBM_DELTAPOS = WM_USER + 3
+ PBM_SETSTEP = WM_USER + 4
+ PBM_STEPIT = WM_USER + 5
+ PBM_SETRANGE32 = 1030
+ PBM_GETRANGE = 1031
+ PBM_GETPOS = 1032
+ PBM_SETBARCOLOR = 1033
+ PBM_SETBKCOLOR = CCM_SETBKCOLOR
+ PBS_SMOOTH = 1
+ PBS_VERTICAL = 4
+)
+
+// Trackbar messages and constants
+const (
+ TBS_AUTOTICKS = 1
+ TBS_VERT = 2
+ TBS_HORZ = 0
+ TBS_TOP = 4
+ TBS_BOTTOM = 0
+ TBS_LEFT = 4
+ TBS_RIGHT = 0
+ TBS_BOTH = 8
+ TBS_NOTICKS = 16
+ TBS_ENABLESELRANGE = 32
+ TBS_FIXEDLENGTH = 64
+ TBS_NOTHUMB = 128
+ TBS_TOOLTIPS = 0x0100
+)
+
+const (
+ TBM_GETPOS = WM_USER
+ TBM_GETRANGEMIN = WM_USER + 1
+ TBM_GETRANGEMAX = WM_USER + 2
+ TBM_GETTIC = WM_USER + 3
+ TBM_SETTIC = WM_USER + 4
+ TBM_SETPOS = WM_USER + 5
+ TBM_SETRANGE = WM_USER + 6
+ TBM_SETRANGEMIN = WM_USER + 7
+ TBM_SETRANGEMAX = WM_USER + 8
+ TBM_CLEARTICS = WM_USER + 9
+ TBM_SETSEL = WM_USER + 10
+ TBM_SETSELSTART = WM_USER + 11
+ TBM_SETSELEND = WM_USER + 12
+ TBM_GETPTICS = WM_USER + 14
+ TBM_GETTICPOS = WM_USER + 15
+ TBM_GETNUMTICS = WM_USER + 16
+ TBM_GETSELSTART = WM_USER + 17
+ TBM_GETSELEND = WM_USER + 18
+ TBM_CLEARSEL = WM_USER + 19
+ TBM_SETTICFREQ = WM_USER + 20
+ TBM_SETPAGESIZE = WM_USER + 21
+ TBM_GETPAGESIZE = WM_USER + 22
+ TBM_SETLINESIZE = WM_USER + 23
+ TBM_GETLINESIZE = WM_USER + 24
+ TBM_GETTHUMBRECT = WM_USER + 25
+ TBM_GETCHANNELRECT = WM_USER + 26
+ TBM_SETTHUMBLENGTH = WM_USER + 27
+ TBM_GETTHUMBLENGTH = WM_USER + 28
+ TBM_SETTOOLTIPS = WM_USER + 29
+ TBM_GETTOOLTIPS = WM_USER + 30
+ TBM_SETTIPSIDE = WM_USER + 31
+ TBM_SETBUDDY = WM_USER + 32
+ TBM_GETBUDDY = WM_USER + 33
+)
+
+const (
+ TB_LINEUP = 0
+ TB_LINEDOWN = 1
+ TB_PAGEUP = 2
+ TB_PAGEDOWN = 3
+ TB_THUMBPOSITION = 4
+ TB_THUMBTRACK = 5
+ TB_TOP = 6
+ TB_BOTTOM = 7
+ TB_ENDTRACK = 8
+)
+
+// GetOpenFileName and GetSaveFileName extended flags
+const (
+ OFN_EX_NOPLACESBAR = 0x00000001
+)
+
+// GetOpenFileName and GetSaveFileName flags
+const (
+ OFN_ALLOWMULTISELECT = 0x00000200
+ OFN_CREATEPROMPT = 0x00002000
+ OFN_DONTADDTORECENT = 0x02000000
+ OFN_ENABLEHOOK = 0x00000020
+ OFN_ENABLEINCLUDENOTIFY = 0x00400000
+ OFN_ENABLESIZING = 0x00800000
+ OFN_ENABLETEMPLATE = 0x00000040
+ OFN_ENABLETEMPLATEHANDLE = 0x00000080
+ OFN_EXPLORER = 0x00080000
+ OFN_EXTENSIONDIFFERENT = 0x00000400
+ OFN_FILEMUSTEXIST = 0x00001000
+ OFN_FORCESHOWHIDDEN = 0x10000000
+ OFN_HIDEREADONLY = 0x00000004
+ OFN_LONGNAMES = 0x00200000
+ OFN_NOCHANGEDIR = 0x00000008
+ OFN_NODEREFERENCELINKS = 0x00100000
+ OFN_NOLONGNAMES = 0x00040000
+ OFN_NONETWORKBUTTON = 0x00020000
+ OFN_NOREADONLYRETURN = 0x00008000
+ OFN_NOTESTFILECREATE = 0x00010000
+ OFN_NOVALIDATE = 0x00000100
+ OFN_OVERWRITEPROMPT = 0x00000002
+ OFN_PATHMUSTEXIST = 0x00000800
+ OFN_READONLY = 0x00000001
+ OFN_SHAREAWARE = 0x00004000
+ OFN_SHOWHELP = 0x00000010
+)
+
+// SHBrowseForFolder flags
+const (
+ BIF_RETURNONLYFSDIRS = 0x00000001
+ BIF_DONTGOBELOWDOMAIN = 0x00000002
+ BIF_STATUSTEXT = 0x00000004
+ BIF_RETURNFSANCESTORS = 0x00000008
+ BIF_EDITBOX = 0x00000010
+ BIF_VALIDATE = 0x00000020
+ BIF_NEWDIALOGSTYLE = 0x00000040
+ BIF_BROWSEINCLUDEURLS = 0x00000080
+ BIF_USENEWUI = BIF_EDITBOX | BIF_NEWDIALOGSTYLE
+ BIF_UAHINT = 0x00000100
+ BIF_NONEWFOLDERBUTTON = 0x00000200
+ BIF_NOTRANSLATETARGETS = 0x00000400
+ BIF_BROWSEFORCOMPUTER = 0x00001000
+ BIF_BROWSEFORPRINTER = 0x00002000
+ BIF_BROWSEINCLUDEFILES = 0x00004000
+ BIF_SHAREABLE = 0x00008000
+ BIF_BROWSEFILEJUNCTIONS = 0x00010000
+)
+
+// MessageBox flags
+const (
+ MB_OK = 0x00000000
+ MB_OKCANCEL = 0x00000001
+ MB_ABORTRETRYIGNORE = 0x00000002
+ MB_YESNOCANCEL = 0x00000003
+ MB_YESNO = 0x00000004
+ MB_RETRYCANCEL = 0x00000005
+ MB_CANCELTRYCONTINUE = 0x00000006
+ MB_ICONHAND = 0x00000010
+ MB_ICONQUESTION = 0x00000020
+ MB_ICONEXCLAMATION = 0x00000030
+ MB_ICONASTERISK = 0x00000040
+ MB_USERICON = 0x00000080
+ MB_ICONWARNING = MB_ICONEXCLAMATION
+ MB_ICONERROR = MB_ICONHAND
+ MB_ICONINFORMATION = MB_ICONASTERISK
+ MB_ICONSTOP = MB_ICONHAND
+ MB_DEFBUTTON1 = 0x00000000
+ MB_DEFBUTTON2 = 0x00000100
+ MB_DEFBUTTON3 = 0x00000200
+ MB_DEFBUTTON4 = 0x00000300
+)
+
+// COM
+const (
+ E_INVALIDARG = 0x80070057
+ E_OUTOFMEMORY = 0x8007000E
+ E_UNEXPECTED = 0x8000FFFF
+)
+
+const (
+ S_OK = 0
+ S_FALSE = 0x0001
+ RPC_E_CHANGED_MODE = 0x80010106
+)
+
+// GetSystemMetrics constants
+const (
+ SM_CXSCREEN = 0
+ SM_CYSCREEN = 1
+ SM_CXVSCROLL = 2
+ SM_CYHSCROLL = 3
+ SM_CYCAPTION = 4
+ SM_CXBORDER = 5
+ SM_CYBORDER = 6
+ SM_CXDLGFRAME = 7
+ SM_CYDLGFRAME = 8
+ SM_CYVTHUMB = 9
+ SM_CXHTHUMB = 10
+ SM_CXICON = 11
+ SM_CYICON = 12
+ SM_CXCURSOR = 13
+ SM_CYCURSOR = 14
+ SM_CYMENU = 15
+ SM_CXFULLSCREEN = 16
+ SM_CYFULLSCREEN = 17
+ SM_CYKANJIWINDOW = 18
+ SM_MOUSEPRESENT = 19
+ SM_CYVSCROLL = 20
+ SM_CXHSCROLL = 21
+ SM_DEBUG = 22
+ SM_SWAPBUTTON = 23
+ SM_RESERVED1 = 24
+ SM_RESERVED2 = 25
+ SM_RESERVED3 = 26
+ SM_RESERVED4 = 27
+ SM_CXMIN = 28
+ SM_CYMIN = 29
+ SM_CXSIZE = 30
+ SM_CYSIZE = 31
+ SM_CXFRAME = 32
+ SM_CYFRAME = 33
+ SM_CXMINTRACK = 34
+ SM_CYMINTRACK = 35
+ SM_CXDOUBLECLK = 36
+ SM_CYDOUBLECLK = 37
+ SM_CXICONSPACING = 38
+ SM_CYICONSPACING = 39
+ SM_MENUDROPALIGNMENT = 40
+ SM_PENWINDOWS = 41
+ SM_DBCSENABLED = 42
+ SM_CMOUSEBUTTONS = 43
+ SM_CXFIXEDFRAME = SM_CXDLGFRAME
+ SM_CYFIXEDFRAME = SM_CYDLGFRAME
+ SM_CXSIZEFRAME = SM_CXFRAME
+ SM_CYSIZEFRAME = SM_CYFRAME
+ SM_SECURE = 44
+ SM_CXEDGE = 45
+ SM_CYEDGE = 46
+ SM_CXMINSPACING = 47
+ SM_CYMINSPACING = 48
+ SM_CXSMICON = 49
+ SM_CYSMICON = 50
+ SM_CYSMCAPTION = 51
+ SM_CXSMSIZE = 52
+ SM_CYSMSIZE = 53
+ SM_CXMENUSIZE = 54
+ SM_CYMENUSIZE = 55
+ SM_ARRANGE = 56
+ SM_CXMINIMIZED = 57
+ SM_CYMINIMIZED = 58
+ SM_CXMAXTRACK = 59
+ SM_CYMAXTRACK = 60
+ SM_CXMAXIMIZED = 61
+ SM_CYMAXIMIZED = 62
+ SM_NETWORK = 63
+ SM_CLEANBOOT = 67
+ SM_CXDRAG = 68
+ SM_CYDRAG = 69
+ SM_SHOWSOUNDS = 70
+ SM_CXMENUCHECK = 71
+ SM_CYMENUCHECK = 72
+ SM_SLOWMACHINE = 73
+ SM_MIDEASTENABLED = 74
+ SM_MOUSEWHEELPRESENT = 75
+ SM_XVIRTUALSCREEN = 76
+ SM_YVIRTUALSCREEN = 77
+ SM_CXVIRTUALSCREEN = 78
+ SM_CYVIRTUALSCREEN = 79
+ SM_CMONITORS = 80
+ SM_SAMEDISPLAYFORMAT = 81
+ SM_IMMENABLED = 82
+ SM_CXFOCUSBORDER = 83
+ SM_CYFOCUSBORDER = 84
+ SM_TABLETPC = 86
+ SM_MEDIACENTER = 87
+ SM_STARTER = 88
+ SM_SERVERR2 = 89
+ SM_CMETRICS = 91
+ SM_REMOTESESSION = 0x1000
+ SM_SHUTTINGDOWN = 0x2000
+ SM_REMOTECONTROL = 0x2001
+ SM_CARETBLINKINGENABLED = 0x2002
+)
+
+const (
+ CLSCTX_INPROC_SERVER = 1
+ CLSCTX_INPROC_HANDLER = 2
+ CLSCTX_LOCAL_SERVER = 4
+ CLSCTX_INPROC_SERVER16 = 8
+ CLSCTX_REMOTE_SERVER = 16
+ CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
+)
+
+const (
+ COINIT_APARTMENTTHREADED = 0x2
+ COINIT_MULTITHREADED = 0x0
+ COINIT_DISABLE_OLE1DDE = 0x4
+ COINIT_SPEED_OVER_MEMORY = 0x8
+)
+
+const (
+ DISPATCH_METHOD = 1
+ DISPATCH_PROPERTYGET = 2
+ DISPATCH_PROPERTYPUT = 4
+ DISPATCH_PROPERTYPUTREF = 8
+)
+
+const (
+ CC_FASTCALL = iota
+ CC_CDECL
+ CC_MSCPASCAL
+ CC_PASCAL = CC_MSCPASCAL
+ CC_MACPASCAL
+ CC_STDCALL
+ CC_FPFASTCALL
+ CC_SYSCALL
+ CC_MPWCDECL
+ CC_MPWPASCAL
+ CC_MAX = CC_MPWPASCAL
+)
+
+const (
+ VT_EMPTY = 0x0
+ VT_NULL = 0x1
+ VT_I2 = 0x2
+ VT_I4 = 0x3
+ VT_R4 = 0x4
+ VT_R8 = 0x5
+ VT_CY = 0x6
+ VT_DATE = 0x7
+ VT_BSTR = 0x8
+ VT_DISPATCH = 0x9
+ VT_ERROR = 0xa
+ VT_BOOL = 0xb
+ VT_VARIANT = 0xc
+ VT_UNKNOWN = 0xd
+ VT_DECIMAL = 0xe
+ VT_I1 = 0x10
+ VT_UI1 = 0x11
+ VT_UI2 = 0x12
+ VT_UI4 = 0x13
+ VT_I8 = 0x14
+ VT_UI8 = 0x15
+ VT_INT = 0x16
+ VT_UINT = 0x17
+ VT_VOID = 0x18
+ VT_HRESULT = 0x19
+ VT_PTR = 0x1a
+ VT_SAFEARRAY = 0x1b
+ VT_CARRAY = 0x1c
+ VT_USERDEFINED = 0x1d
+ VT_LPSTR = 0x1e
+ VT_LPWSTR = 0x1f
+ VT_RECORD = 0x24
+ VT_INT_PTR = 0x25
+ VT_UINT_PTR = 0x26
+ VT_FILETIME = 0x40
+ VT_BLOB = 0x41
+ VT_STREAM = 0x42
+ VT_STORAGE = 0x43
+ VT_STREAMED_OBJECT = 0x44
+ VT_STORED_OBJECT = 0x45
+ VT_BLOB_OBJECT = 0x46
+ VT_CF = 0x47
+ VT_CLSID = 0x48
+ VT_BSTR_BLOB = 0xfff
+ VT_VECTOR = 0x1000
+ VT_ARRAY = 0x2000
+ VT_BYREF = 0x4000
+ VT_RESERVED = 0x8000
+ VT_ILLEGAL = 0xffff
+ VT_ILLEGALMASKED = 0xfff
+ VT_TYPEMASK = 0xfff
+)
+
+const (
+ DISPID_UNKNOWN = -1
+ DISPID_VALUE = 0
+ DISPID_PROPERTYPUT = -3
+ DISPID_NEWENUM = -4
+ DISPID_EVALUATE = -5
+ DISPID_CONSTRUCTOR = -6
+ DISPID_DESTRUCTOR = -7
+ DISPID_COLLECT = -8
+)
+
+const (
+ MONITOR_DEFAULTTONULL = 0x00000000
+ MONITOR_DEFAULTTOPRIMARY = 0x00000001
+ MONITOR_DEFAULTTONEAREST = 0x00000002
+
+ MONITORINFOF_PRIMARY = 0x00000001
+)
+
+const (
+ CCHDEVICENAME = 32
+ CCHFORMNAME = 32
+)
+
+const (
+ IDOK = 1
+ IDCANCEL = 2
+ IDABORT = 3
+ IDRETRY = 4
+ IDIGNORE = 5
+ IDYES = 6
+ IDNO = 7
+ IDCLOSE = 8
+ IDHELP = 9
+ IDTRYAGAIN = 10
+ IDCONTINUE = 11
+ IDTIMEOUT = 32000
+)
+
+// Generic WM_NOTIFY notification codes
+const (
+ NM_FIRST = 0
+ NM_OUTOFMEMORY = NM_FIRST - 1
+ NM_CLICK = NM_FIRST - 2
+ NM_DBLCLK = NM_FIRST - 3
+ NM_RETURN = NM_FIRST - 4
+ NM_RCLICK = NM_FIRST - 5
+ NM_RDBLCLK = NM_FIRST - 6
+ NM_SETFOCUS = NM_FIRST - 7
+ NM_KILLFOCUS = NM_FIRST - 8
+ NM_CUSTOMDRAW = NM_FIRST - 12
+ NM_HOVER = NM_FIRST - 13
+ NM_NCHITTEST = NM_FIRST - 14
+ NM_KEYDOWN = NM_FIRST - 15
+ NM_RELEASEDCAPTURE = NM_FIRST - 16
+ NM_SETCURSOR = NM_FIRST - 17
+ NM_CHAR = NM_FIRST - 18
+ NM_TOOLTIPSCREATED = NM_FIRST - 19
+ NM_LAST = NM_FIRST - 99
+)
+
+// ListView messages
+const (
+ LVM_FIRST = 0x1000
+ LVM_GETITEMCOUNT = LVM_FIRST + 4
+ LVM_SETIMAGELIST = LVM_FIRST + 3
+ LVM_GETIMAGELIST = LVM_FIRST + 2
+ LVM_GETITEM = LVM_FIRST + 75
+ LVM_SETITEM = LVM_FIRST + 76
+ LVM_INSERTITEM = LVM_FIRST + 77
+ LVM_DELETEITEM = LVM_FIRST + 8
+ LVM_DELETEALLITEMS = LVM_FIRST + 9
+ LVM_GETCALLBACKMASK = LVM_FIRST + 10
+ LVM_SETCALLBACKMASK = LVM_FIRST + 11
+ LVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ LVM_GETNEXTITEM = LVM_FIRST + 12
+ LVM_FINDITEM = LVM_FIRST + 83
+ LVM_GETITEMRECT = LVM_FIRST + 14
+ LVM_GETSTRINGWIDTH = LVM_FIRST + 87
+ LVM_HITTEST = LVM_FIRST + 18
+ LVM_ENSUREVISIBLE = LVM_FIRST + 19
+ LVM_SCROLL = LVM_FIRST + 20
+ LVM_REDRAWITEMS = LVM_FIRST + 21
+ LVM_ARRANGE = LVM_FIRST + 22
+ LVM_EDITLABEL = LVM_FIRST + 118
+ LVM_GETEDITCONTROL = LVM_FIRST + 24
+ LVM_GETCOLUMN = LVM_FIRST + 95
+ LVM_SETCOLUMN = LVM_FIRST + 96
+ LVM_INSERTCOLUMN = LVM_FIRST + 97
+ LVM_DELETECOLUMN = LVM_FIRST + 28
+ LVM_GETCOLUMNWIDTH = LVM_FIRST + 29
+ LVM_SETCOLUMNWIDTH = LVM_FIRST + 30
+ LVM_GETHEADER = LVM_FIRST + 31
+ LVM_CREATEDRAGIMAGE = LVM_FIRST + 33
+ LVM_GETVIEWRECT = LVM_FIRST + 34
+ LVM_GETTEXTCOLOR = LVM_FIRST + 35
+ LVM_SETTEXTCOLOR = LVM_FIRST + 36
+ LVM_GETTEXTBKCOLOR = LVM_FIRST + 37
+ LVM_SETTEXTBKCOLOR = LVM_FIRST + 38
+ LVM_GETTOPINDEX = LVM_FIRST + 39
+ LVM_GETCOUNTPERPAGE = LVM_FIRST + 40
+ LVM_GETORIGIN = LVM_FIRST + 41
+ LVM_UPDATE = LVM_FIRST + 42
+ LVM_SETITEMSTATE = LVM_FIRST + 43
+ LVM_GETITEMSTATE = LVM_FIRST + 44
+ LVM_GETITEMTEXT = LVM_FIRST + 115
+ LVM_SETITEMTEXT = LVM_FIRST + 116
+ LVM_SETITEMCOUNT = LVM_FIRST + 47
+ LVM_SORTITEMS = LVM_FIRST + 48
+ LVM_SETITEMPOSITION32 = LVM_FIRST + 49
+ LVM_GETSELECTEDCOUNT = LVM_FIRST + 50
+ LVM_GETITEMSPACING = LVM_FIRST + 51
+ LVM_GETISEARCHSTRING = LVM_FIRST + 117
+ LVM_SETICONSPACING = LVM_FIRST + 53
+ LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54
+ LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55
+ LVM_GETSUBITEMRECT = LVM_FIRST + 56
+ LVM_SUBITEMHITTEST = LVM_FIRST + 57
+ LVM_SETCOLUMNORDERARRAY = LVM_FIRST + 58
+ LVM_GETCOLUMNORDERARRAY = LVM_FIRST + 59
+ LVM_SETHOTITEM = LVM_FIRST + 60
+ LVM_GETHOTITEM = LVM_FIRST + 61
+ LVM_SETHOTCURSOR = LVM_FIRST + 62
+ LVM_GETHOTCURSOR = LVM_FIRST + 63
+ LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 64
+ LVM_SETWORKAREAS = LVM_FIRST + 65
+ LVM_GETWORKAREAS = LVM_FIRST + 70
+ LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73
+ LVM_GETSELECTIONMARK = LVM_FIRST + 66
+ LVM_SETSELECTIONMARK = LVM_FIRST + 67
+ LVM_SETHOVERTIME = LVM_FIRST + 71
+ LVM_GETHOVERTIME = LVM_FIRST + 72
+ LVM_SETTOOLTIPS = LVM_FIRST + 74
+ LVM_GETTOOLTIPS = LVM_FIRST + 78
+ LVM_SORTITEMSEX = LVM_FIRST + 81
+ LVM_SETBKIMAGE = LVM_FIRST + 138
+ LVM_GETBKIMAGE = LVM_FIRST + 139
+ LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140
+ LVM_SETVIEW = LVM_FIRST + 142
+ LVM_GETVIEW = LVM_FIRST + 143
+ LVM_INSERTGROUP = LVM_FIRST + 145
+ LVM_SETGROUPINFO = LVM_FIRST + 147
+ LVM_GETGROUPINFO = LVM_FIRST + 149
+ LVM_REMOVEGROUP = LVM_FIRST + 150
+ LVM_MOVEGROUP = LVM_FIRST + 151
+ LVM_GETGROUPCOUNT = LVM_FIRST + 152
+ LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 153
+ LVM_MOVEITEMTOGROUP = LVM_FIRST + 154
+ LVM_GETGROUPRECT = LVM_FIRST + 98
+ LVM_SETGROUPMETRICS = LVM_FIRST + 155
+ LVM_GETGROUPMETRICS = LVM_FIRST + 156
+ LVM_ENABLEGROUPVIEW = LVM_FIRST + 157
+ LVM_SORTGROUPS = LVM_FIRST + 158
+ LVM_INSERTGROUPSORTED = LVM_FIRST + 159
+ LVM_REMOVEALLGROUPS = LVM_FIRST + 160
+ LVM_HASGROUP = LVM_FIRST + 161
+ LVM_GETGROUPSTATE = LVM_FIRST + 92
+ LVM_GETFOCUSEDGROUP = LVM_FIRST + 93
+ LVM_SETTILEVIEWINFO = LVM_FIRST + 162
+ LVM_GETTILEVIEWINFO = LVM_FIRST + 163
+ LVM_SETTILEINFO = LVM_FIRST + 164
+ LVM_GETTILEINFO = LVM_FIRST + 165
+ LVM_SETINSERTMARK = LVM_FIRST + 166
+ LVM_GETINSERTMARK = LVM_FIRST + 167
+ LVM_INSERTMARKHITTEST = LVM_FIRST + 168
+ LVM_GETINSERTMARKRECT = LVM_FIRST + 169
+ LVM_SETINSERTMARKCOLOR = LVM_FIRST + 170
+ LVM_GETINSERTMARKCOLOR = LVM_FIRST + 171
+ LVM_SETINFOTIP = LVM_FIRST + 173
+ LVM_GETSELECTEDCOLUMN = LVM_FIRST + 174
+ LVM_ISGROUPVIEWENABLED = LVM_FIRST + 175
+ LVM_GETOUTLINECOLOR = LVM_FIRST + 176
+ LVM_SETOUTLINECOLOR = LVM_FIRST + 177
+ LVM_CANCELEDITLABEL = LVM_FIRST + 179
+ LVM_MAPINDEXTOID = LVM_FIRST + 180
+ LVM_MAPIDTOINDEX = LVM_FIRST + 181
+ LVM_ISITEMVISIBLE = LVM_FIRST + 182
+ LVM_GETNEXTITEMINDEX = LVM_FIRST + 211
+)
+
+// ListView notifications
+const (
+ LVN_FIRST = -100
+
+ LVN_ITEMCHANGING = LVN_FIRST - 0
+ LVN_ITEMCHANGED = LVN_FIRST - 1
+ LVN_INSERTITEM = LVN_FIRST - 2
+ LVN_DELETEITEM = LVN_FIRST - 3
+ LVN_DELETEALLITEMS = LVN_FIRST - 4
+ LVN_BEGINLABELEDITA = LVN_FIRST - 5
+ LVN_BEGINLABELEDITW = LVN_FIRST - 75
+ LVN_ENDLABELEDITA = LVN_FIRST - 6
+ LVN_ENDLABELEDITW = LVN_FIRST - 76
+ LVN_COLUMNCLICK = LVN_FIRST - 8
+ LVN_BEGINDRAG = LVN_FIRST - 9
+ LVN_BEGINRDRAG = LVN_FIRST - 11
+ LVN_ODCACHEHINT = LVN_FIRST - 13
+ LVN_ODFINDITEMA = LVN_FIRST - 52
+ LVN_ODFINDITEMW = LVN_FIRST - 79
+ LVN_ITEMACTIVATE = LVN_FIRST - 14
+ LVN_ODSTATECHANGED = LVN_FIRST - 15
+ LVN_HOTTRACK = LVN_FIRST - 21
+ LVN_GETDISPINFO = LVN_FIRST - 77
+ LVN_SETDISPINFO = LVN_FIRST - 78
+ LVN_KEYDOWN = LVN_FIRST - 55
+ LVN_MARQUEEBEGIN = LVN_FIRST - 56
+ LVN_GETINFOTIP = LVN_FIRST - 58
+ LVN_INCREMENTALSEARCH = LVN_FIRST - 63
+ LVN_BEGINSCROLL = LVN_FIRST - 80
+ LVN_ENDSCROLL = LVN_FIRST - 81
+)
+
+const (
+ LVSCW_AUTOSIZE = ^uintptr(0)
+ LVSCW_AUTOSIZE_USEHEADER = ^uintptr(1)
+)
+
+// ListView LVNI constants
+const (
+ LVNI_ALL = 0
+ LVNI_FOCUSED = 1
+ LVNI_SELECTED = 2
+ LVNI_CUT = 4
+ LVNI_DROPHILITED = 8
+ LVNI_ABOVE = 256
+ LVNI_BELOW = 512
+ LVNI_TOLEFT = 1024
+ LVNI_TORIGHT = 2048
+)
+
+// ListView styles
+const (
+ LVS_ICON = 0x0000
+ LVS_REPORT = 0x0001
+ LVS_SMALLICON = 0x0002
+ LVS_LIST = 0x0003
+ LVS_TYPEMASK = 0x0003
+ LVS_SINGLESEL = 0x0004
+ LVS_SHOWSELALWAYS = 0x0008
+ LVS_SORTASCENDING = 0x0010
+ LVS_SORTDESCENDING = 0x0020
+ LVS_SHAREIMAGELISTS = 0x0040
+ LVS_NOLABELWRAP = 0x0080
+ LVS_AUTOARRANGE = 0x0100
+ LVS_EDITLABELS = 0x0200
+ LVS_OWNERDATA = 0x1000
+ LVS_NOSCROLL = 0x2000
+ LVS_TYPESTYLEMASK = 0xfc00
+ LVS_ALIGNTOP = 0x0000
+ LVS_ALIGNLEFT = 0x0800
+ LVS_ALIGNMASK = 0x0c00
+ LVS_OWNERDRAWFIXED = 0x0400
+ LVS_NOCOLUMNHEADER = 0x4000
+ LVS_NOSORTHEADER = 0x8000
+)
+
+// ListView extended styles
+const (
+ LVS_EX_GRIDLINES = 0x00000001
+ LVS_EX_SUBITEMIMAGES = 0x00000002
+ LVS_EX_CHECKBOXES = 0x00000004
+ LVS_EX_TRACKSELECT = 0x00000008
+ LVS_EX_HEADERDRAGDROP = 0x00000010
+ LVS_EX_FULLROWSELECT = 0x00000020
+ LVS_EX_ONECLICKACTIVATE = 0x00000040
+ LVS_EX_TWOCLICKACTIVATE = 0x00000080
+ LVS_EX_FLATSB = 0x00000100
+ LVS_EX_REGIONAL = 0x00000200
+ LVS_EX_INFOTIP = 0x00000400
+ LVS_EX_UNDERLINEHOT = 0x00000800
+ LVS_EX_UNDERLINECOLD = 0x00001000
+ LVS_EX_MULTIWORKAREAS = 0x00002000
+ LVS_EX_LABELTIP = 0x00004000
+ LVS_EX_BORDERSELECT = 0x00008000
+ LVS_EX_DOUBLEBUFFER = 0x00010000
+ LVS_EX_HIDELABELS = 0x00020000
+ LVS_EX_SINGLEROW = 0x00040000
+ LVS_EX_SNAPTOGRID = 0x00080000
+ LVS_EX_SIMPLESELECT = 0x00100000
+)
+
+// ListView column flags
+const (
+ LVCF_FMT = 0x0001
+ LVCF_WIDTH = 0x0002
+ LVCF_TEXT = 0x0004
+ LVCF_SUBITEM = 0x0008
+ LVCF_IMAGE = 0x0010
+ LVCF_ORDER = 0x0020
+)
+
+// ListView column format constants
+const (
+ LVCFMT_LEFT = 0x0000
+ LVCFMT_RIGHT = 0x0001
+ LVCFMT_CENTER = 0x0002
+ LVCFMT_JUSTIFYMASK = 0x0003
+ LVCFMT_IMAGE = 0x0800
+ LVCFMT_BITMAP_ON_RIGHT = 0x1000
+ LVCFMT_COL_HAS_IMAGES = 0x8000
+)
+
+// ListView item flags
+const (
+ LVIF_TEXT = 0x00000001
+ LVIF_IMAGE = 0x00000002
+ LVIF_PARAM = 0x00000004
+ LVIF_STATE = 0x00000008
+ LVIF_INDENT = 0x00000010
+ LVIF_NORECOMPUTE = 0x00000800
+ LVIF_GROUPID = 0x00000100
+ LVIF_COLUMNS = 0x00000200
+)
+
+const LVFI_PARAM = 0x0001
+
+// ListView item states
+const (
+ LVIS_FOCUSED = 1
+ LVIS_SELECTED = 2
+ LVIS_CUT = 4
+ LVIS_DROPHILITED = 8
+ LVIS_OVERLAYMASK = 0xF00
+ LVIS_STATEIMAGEMASK = 0xF000
+)
+
+// ListView hit test constants
+const (
+ LVHT_NOWHERE = 0x00000001
+ LVHT_ONITEMICON = 0x00000002
+ LVHT_ONITEMLABEL = 0x00000004
+ LVHT_ONITEMSTATEICON = 0x00000008
+ LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON
+
+ LVHT_ABOVE = 0x00000008
+ LVHT_BELOW = 0x00000010
+ LVHT_TORIGHT = 0x00000020
+ LVHT_TOLEFT = 0x00000040
+)
+
+// ListView image list types
+const (
+ LVSIL_NORMAL = 0
+ LVSIL_SMALL = 1
+ LVSIL_STATE = 2
+ LVSIL_GROUPHEADER = 3
+)
+
+// InitCommonControlsEx flags
+const (
+ ICC_LISTVIEW_CLASSES = 1
+ ICC_TREEVIEW_CLASSES = 2
+ ICC_BAR_CLASSES = 4
+ ICC_TAB_CLASSES = 8
+ ICC_UPDOWN_CLASS = 16
+ ICC_PROGRESS_CLASS = 32
+ ICC_HOTKEY_CLASS = 64
+ ICC_ANIMATE_CLASS = 128
+ ICC_WIN95_CLASSES = 255
+ ICC_DATE_CLASSES = 256
+ ICC_USEREX_CLASSES = 512
+ ICC_COOL_CLASSES = 1024
+ ICC_INTERNET_CLASSES = 2048
+ ICC_PAGESCROLLER_CLASS = 4096
+ ICC_NATIVEFNTCTL_CLASS = 8192
+ INFOTIPSIZE = 1024
+ ICC_STANDARD_CLASSES = 0x00004000
+ ICC_LINK_CLASS = 0x00008000
+)
+
+// Dialog Codes
+const (
+ DLGC_WANTARROWS = 0x0001
+ DLGC_WANTTAB = 0x0002
+ DLGC_WANTALLKEYS = 0x0004
+ DLGC_WANTMESSAGE = 0x0004
+ DLGC_HASSETSEL = 0x0008
+ DLGC_DEFPUSHBUTTON = 0x0010
+ DLGC_UNDEFPUSHBUTTON = 0x0020
+ DLGC_RADIOBUTTON = 0x0040
+ DLGC_WANTCHARS = 0x0080
+ DLGC_STATIC = 0x0100
+ DLGC_BUTTON = 0x2000
+)
+
+// Get/SetWindowWord/Long offsets for use with WC_DIALOG windows
+const (
+ DWL_MSGRESULT = 0
+ DWL_DLGPROC = 4
+ DWL_USER = 8
+)
+
+// Registry predefined keys
+const (
+ HKEY_CLASSES_ROOT HKEY = 0x80000000
+ HKEY_CURRENT_USER HKEY = 0x80000001
+ HKEY_LOCAL_MACHINE HKEY = 0x80000002
+ HKEY_USERS HKEY = 0x80000003
+ HKEY_PERFORMANCE_DATA HKEY = 0x80000004
+ HKEY_CURRENT_CONFIG HKEY = 0x80000005
+ HKEY_DYN_DATA HKEY = 0x80000006
+)
+
+// Registry Key Security and Access Rights
+const (
+ KEY_ALL_ACCESS = 0xF003F
+ KEY_CREATE_SUB_KEY = 0x0004
+ KEY_ENUMERATE_SUB_KEYS = 0x0008
+ KEY_NOTIFY = 0x0010
+ KEY_QUERY_VALUE = 0x0001
+ KEY_SET_VALUE = 0x0002
+ KEY_READ = 0x20019
+ KEY_WRITE = 0x20006
+)
+
+const (
+ NFR_ANSI = 1
+ NFR_UNICODE = 2
+ NF_QUERY = 3
+ NF_REQUERY = 4
+)
+
+// Registry value types
+const (
+ RRF_RT_REG_NONE = 0x00000001
+ RRF_RT_REG_SZ = 0x00000002
+ RRF_RT_REG_EXPAND_SZ = 0x00000004
+ RRF_RT_REG_BINARY = 0x00000008
+ RRF_RT_REG_DWORD = 0x00000010
+ RRF_RT_REG_MULTI_SZ = 0x00000020
+ RRF_RT_REG_QWORD = 0x00000040
+ RRF_RT_DWORD = RRF_RT_REG_BINARY | RRF_RT_REG_DWORD
+ RRF_RT_QWORD = RRF_RT_REG_BINARY | RRF_RT_REG_QWORD
+ RRF_RT_ANY = 0x0000ffff
+ RRF_NOEXPAND = 0x10000000
+ RRF_ZEROONFAILURE = 0x20000000
+ REG_PROCESS_APPKEY = 0x00000001
+ REG_MUI_STRING_TRUNCATE = 0x00000001
+)
+
+// PeekMessage wRemoveMsg value
+const (
+ PM_NOREMOVE = 0x000
+ PM_REMOVE = 0x001
+ PM_NOYIELD = 0x002
+)
+
+// ImageList flags
+const (
+ ILC_MASK = 0x00000001
+ ILC_COLOR = 0x00000000
+ ILC_COLORDDB = 0x000000FE
+ ILC_COLOR4 = 0x00000004
+ ILC_COLOR8 = 0x00000008
+ ILC_COLOR16 = 0x00000010
+ ILC_COLOR24 = 0x00000018
+ ILC_COLOR32 = 0x00000020
+ ILC_PALETTE = 0x00000800
+ ILC_MIRROR = 0x00002000
+ ILC_PERITEMMIRROR = 0x00008000
+ ILC_ORIGINALSIZE = 0x00010000
+ ILC_HIGHQUALITYSCALE = 0x00020000
+)
+
+// Keystroke Message Flags
+const (
+ KF_EXTENDED = 0x0100
+ KF_DLGMODE = 0x0800
+ KF_MENUMODE = 0x1000
+ KF_ALTDOWN = 0x2000
+ KF_REPEAT = 0x4000
+ KF_UP = 0x8000
+)
+
+// Virtual-Key Codes
+/*
+const (
+ VK_LBUTTON = 0x01
+ VK_RBUTTON = 0x02
+ VK_CANCEL = 0x03
+ VK_MBUTTON = 0x04
+ VK_XBUTTON1 = 0x05
+ VK_XBUTTON2 = 0x06
+ VK_BACK = 0x08
+ VK_TAB = 0x09
+ VK_CLEAR = 0x0C
+ VK_RETURN = 0x0D
+ VK_SHIFT = 0x10
+ VK_CONTROL = 0x11
+ VK_MENU = 0x12
+ VK_PAUSE = 0x13
+ VK_CAPITAL = 0x14
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 0x20
+ VK_PRIOR = 0x21
+ VK_NEXT = 0x22
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_SELECT = 0x29
+ VK_PRINT = 0x2A
+ VK_EXECUTE = 0x2B
+ VK_SNAPSHOT = 0x2C
+ VK_INSERT = 0x2D
+ VK_DELETE = 0x2E
+ VK_HELP = 0x2F
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_OEM_NEC_EQUAL = 0x92
+ VK_OEM_FJ_JISHO = 0x92
+ VK_OEM_FJ_MASSHOU = 0x93
+ VK_OEM_FJ_TOUROKU = 0x94
+ VK_OEM_FJ_LOYA = 0x95
+ VK_OEM_FJ_ROYA = 0x96
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_AX = 0xE1
+ VK_OEM_102 = 0xE2
+ VK_ICO_HELP = 0xE3
+ VK_ICO_00 = 0xE4
+ VK_PROCESSKEY = 0xE5
+ VK_ICO_CLEAR = 0xE6
+ VK_OEM_RESET = 0xE9
+ VK_OEM_JUMP = 0xEA
+ VK_OEM_PA1 = 0xEB
+ VK_OEM_PA2 = 0xEC
+ VK_OEM_PA3 = 0xED
+ VK_OEM_WSCTRL = 0xEE
+ VK_OEM_CUSEL = 0xEF
+ VK_OEM_ATTN = 0xF0
+ VK_OEM_FINISH = 0xF1
+ VK_OEM_COPY = 0xF2
+ VK_OEM_AUTO = 0xF3
+ VK_OEM_ENLW = 0xF4
+ VK_OEM_BACKTAB = 0xF5
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)*/
+
+// Registry Value Types
+const (
+ REG_NONE = 0
+ REG_SZ = 1
+ REG_EXPAND_SZ = 2
+ REG_BINARY = 3
+ REG_DWORD = 4
+ REG_DWORD_LITTLE_ENDIAN = 4
+ REG_DWORD_BIG_ENDIAN = 5
+ REG_LINK = 6
+ REG_MULTI_SZ = 7
+ REG_RESOURCE_LIST = 8
+ REG_FULL_RESOURCE_DESCRIPTOR = 9
+ REG_RESOURCE_REQUIREMENTS_LIST = 10
+ REG_QWORD = 11
+ REG_QWORD_LITTLE_ENDIAN = 11
+)
+
+// Tooltip styles
+const (
+ TTS_ALWAYSTIP = 0x01
+ TTS_NOPREFIX = 0x02
+ TTS_NOANIMATE = 0x10
+ TTS_NOFADE = 0x20
+ TTS_BALLOON = 0x40
+ TTS_CLOSE = 0x80
+ TTS_USEVISUALSTYLE = 0x100
+)
+
+// Tooltip messages
+const (
+ TTM_ACTIVATE = WM_USER + 1
+ TTM_SETDELAYTIME = WM_USER + 3
+ TTM_ADDTOOL = WM_USER + 50
+ TTM_DELTOOL = WM_USER + 51
+ TTM_NEWTOOLRECT = WM_USER + 52
+ TTM_RELAYEVENT = WM_USER + 7
+ TTM_GETTOOLINFO = WM_USER + 53
+ TTM_SETTOOLINFO = WM_USER + 54
+ TTM_HITTEST = WM_USER + 55
+ TTM_GETTEXT = WM_USER + 56
+ TTM_UPDATETIPTEXT = WM_USER + 57
+ TTM_GETTOOLCOUNT = WM_USER + 13
+ TTM_ENUMTOOLS = WM_USER + 58
+ TTM_GETCURRENTTOOL = WM_USER + 59
+ TTM_WINDOWFROMPOINT = WM_USER + 16
+ TTM_TRACKACTIVATE = WM_USER + 17
+ TTM_TRACKPOSITION = WM_USER + 18
+ TTM_SETTIPBKCOLOR = WM_USER + 19
+ TTM_SETTIPTEXTCOLOR = WM_USER + 20
+ TTM_GETDELAYTIME = WM_USER + 21
+ TTM_GETTIPBKCOLOR = WM_USER + 22
+ TTM_GETTIPTEXTCOLOR = WM_USER + 23
+ TTM_SETMAXTIPWIDTH = WM_USER + 24
+ TTM_GETMAXTIPWIDTH = WM_USER + 25
+ TTM_SETMARGIN = WM_USER + 26
+ TTM_GETMARGIN = WM_USER + 27
+ TTM_POP = WM_USER + 28
+ TTM_UPDATE = WM_USER + 29
+ TTM_GETBUBBLESIZE = WM_USER + 30
+ TTM_ADJUSTRECT = WM_USER + 31
+ TTM_SETTITLE = WM_USER + 33
+ TTM_POPUP = WM_USER + 34
+ TTM_GETTITLE = WM_USER + 35
+)
+
+// Tooltip icons
+const (
+ TTI_NONE = 0
+ TTI_INFO = 1
+ TTI_WARNING = 2
+ TTI_ERROR = 3
+ TTI_INFO_LARGE = 4
+ TTI_WARNING_LARGE = 5
+ TTI_ERROR_LARGE = 6
+)
+
+// Tooltip notifications
+const (
+ TTN_FIRST = -520
+ TTN_LAST = -549
+ TTN_GETDISPINFO = TTN_FIRST - 10
+ TTN_SHOW = TTN_FIRST - 1
+ TTN_POP = TTN_FIRST - 2
+ TTN_LINKCLICK = TTN_FIRST - 3
+ TTN_NEEDTEXT = TTN_GETDISPINFO
+)
+
+const (
+ TTF_IDISHWND = 0x0001
+ TTF_CENTERTIP = 0x0002
+ TTF_RTLREADING = 0x0004
+ TTF_SUBCLASS = 0x0010
+ TTF_TRACK = 0x0020
+ TTF_ABSOLUTE = 0x0080
+ TTF_TRANSPARENT = 0x0100
+ TTF_PARSELINKS = 0x1000
+ TTF_DI_SETITEM = 0x8000
+)
+
+const (
+ SWP_NOSIZE = 0x0001
+ SWP_NOMOVE = 0x0002
+ SWP_NOZORDER = 0x0004
+ SWP_NOREDRAW = 0x0008
+ SWP_NOACTIVATE = 0x0010
+ SWP_FRAMECHANGED = 0x0020
+ SWP_SHOWWINDOW = 0x0040
+ SWP_HIDEWINDOW = 0x0080
+ SWP_NOCOPYBITS = 0x0100
+ SWP_NOOWNERZORDER = 0x0200
+ SWP_NOSENDCHANGING = 0x0400
+ SWP_DRAWFRAME = SWP_FRAMECHANGED
+ SWP_NOREPOSITION = SWP_NOOWNERZORDER
+ SWP_DEFERERASE = 0x2000
+ SWP_ASYNCWINDOWPOS = 0x4000
+)
+
+// Predefined window handles
+const (
+ HWND_BROADCAST = HWND(0xFFFF)
+ HWND_BOTTOM = HWND(1)
+ HWND_NOTOPMOST = ^HWND(1) // -2
+ HWND_TOP = HWND(0)
+ HWND_TOPMOST = ^HWND(0) // -1
+ HWND_DESKTOP = HWND(0)
+ HWND_MESSAGE = ^HWND(2) // -3
+)
+
+// Pen types
+const (
+ PS_COSMETIC = 0x00000000
+ PS_GEOMETRIC = 0x00010000
+ PS_TYPE_MASK = 0x000F0000
+)
+
+// Pen styles
+const (
+ PS_SOLID = 0
+ PS_DASH = 1
+ PS_DOT = 2
+ PS_DASHDOT = 3
+ PS_DASHDOTDOT = 4
+ PS_NULL = 5
+ PS_INSIDEFRAME = 6
+ PS_USERSTYLE = 7
+ PS_ALTERNATE = 8
+ PS_STYLE_MASK = 0x0000000F
+)
+
+// Pen cap types
+const (
+ PS_ENDCAP_ROUND = 0x00000000
+ PS_ENDCAP_SQUARE = 0x00000100
+ PS_ENDCAP_FLAT = 0x00000200
+ PS_ENDCAP_MASK = 0x00000F00
+)
+
+// Pen join types
+const (
+ PS_JOIN_ROUND = 0x00000000
+ PS_JOIN_BEVEL = 0x00001000
+ PS_JOIN_MITER = 0x00002000
+ PS_JOIN_MASK = 0x0000F000
+)
+
+// Hatch styles
+const (
+ HS_HORIZONTAL = 0
+ HS_VERTICAL = 1
+ HS_FDIAGONAL = 2
+ HS_BDIAGONAL = 3
+ HS_CROSS = 4
+ HS_DIAGCROSS = 5
+)
+
+// Stock Logical Objects
+const (
+ WHITE_BRUSH = 0
+ LTGRAY_BRUSH = 1
+ GRAY_BRUSH = 2
+ DKGRAY_BRUSH = 3
+ BLACK_BRUSH = 4
+ NULL_BRUSH = 5
+ HOLLOW_BRUSH = NULL_BRUSH
+ WHITE_PEN = 6
+ BLACK_PEN = 7
+ NULL_PEN = 8
+ OEM_FIXED_FONT = 10
+ ANSI_FIXED_FONT = 11
+ ANSI_VAR_FONT = 12
+ SYSTEM_FONT = 13
+ DEVICE_DEFAULT_FONT = 14
+ DEFAULT_PALETTE = 15
+ SYSTEM_FIXED_FONT = 16
+ DEFAULT_GUI_FONT = 17
+ DC_BRUSH = 18
+ DC_PEN = 19
+)
+
+// Brush styles
+const (
+ BS_SOLID = 0
+ BS_NULL = 1
+ BS_HOLLOW = BS_NULL
+ BS_HATCHED = 2
+ BS_PATTERN = 3
+ BS_INDEXED = 4
+ BS_DIBPATTERN = 5
+ BS_DIBPATTERNPT = 6
+ BS_PATTERN8X8 = 7
+ BS_DIBPATTERN8X8 = 8
+ BS_MONOPATTERN = 9
+)
+
+// TRACKMOUSEEVENT flags
+const (
+ TME_HOVER = 0x00000001
+ TME_LEAVE = 0x00000002
+ TME_NONCLIENT = 0x00000010
+ TME_QUERY = 0x40000000
+ TME_CANCEL = 0x80000000
+
+ HOVER_DEFAULT = 0xFFFFFFFF
+)
+
+// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
+const (
+ HTERROR = -2
+ HTTRANSPARENT = -1
+ HTNOWHERE = 0
+ HTCLIENT = 1
+ HTCAPTION = 2
+ HTSYSMENU = 3
+ HTGROWBOX = 4
+ HTSIZE = HTGROWBOX
+ HTMENU = 5
+ HTHSCROLL = 6
+ HTVSCROLL = 7
+ HTMINBUTTON = 8
+ HTMAXBUTTON = 9
+ HTLEFT = 10
+ HTRIGHT = 11
+ HTTOP = 12
+ HTTOPLEFT = 13
+ HTTOPRIGHT = 14
+ HTBOTTOM = 15
+ HTBOTTOMLEFT = 16
+ HTBOTTOMRIGHT = 17
+ HTBORDER = 18
+ HTREDUCE = HTMINBUTTON
+ HTZOOM = HTMAXBUTTON
+ HTSIZEFIRST = HTLEFT
+ HTSIZELAST = HTBOTTOMRIGHT
+ HTOBJECT = 19
+ HTCLOSE = 20
+ HTHELP = 21
+)
+
+// DrawText[Ex] format flags
+const (
+ DT_TOP = 0x00000000
+ DT_LEFT = 0x00000000
+ DT_CENTER = 0x00000001
+ DT_RIGHT = 0x00000002
+ DT_VCENTER = 0x00000004
+ DT_BOTTOM = 0x00000008
+ DT_WORDBREAK = 0x00000010
+ DT_SINGLELINE = 0x00000020
+ DT_EXPANDTABS = 0x00000040
+ DT_TABSTOP = 0x00000080
+ DT_NOCLIP = 0x00000100
+ DT_EXTERNALLEADING = 0x00000200
+ DT_CALCRECT = 0x00000400
+ DT_NOPREFIX = 0x00000800
+ DT_INTERNAL = 0x00001000
+ DT_EDITCONTROL = 0x00002000
+ DT_PATH_ELLIPSIS = 0x00004000
+ DT_END_ELLIPSIS = 0x00008000
+ DT_MODIFYSTRING = 0x00010000
+ DT_RTLREADING = 0x00020000
+ DT_WORD_ELLIPSIS = 0x00040000
+ DT_NOFULLWIDTHCHARBREAK = 0x00080000
+ DT_HIDEPREFIX = 0x00100000
+ DT_PREFIXONLY = 0x00200000
+)
+
+const CLR_INVALID = 0xFFFFFFFF
+
+// Background Modes
+const (
+ TRANSPARENT = 1
+ OPAQUE = 2
+ BKMODE_LAST = 2
+)
+
+// Global Memory Flags
+const (
+ GMEM_FIXED = 0x0000
+ GMEM_MOVEABLE = 0x0002
+ GMEM_NOCOMPACT = 0x0010
+ GMEM_NODISCARD = 0x0020
+ GMEM_ZEROINIT = 0x0040
+ GMEM_MODIFY = 0x0080
+ GMEM_DISCARDABLE = 0x0100
+ GMEM_NOT_BANKED = 0x1000
+ GMEM_SHARE = 0x2000
+ GMEM_DDESHARE = 0x2000
+ GMEM_NOTIFY = 0x4000
+ GMEM_LOWER = GMEM_NOT_BANKED
+ GMEM_VALID_FLAGS = 0x7F72
+ GMEM_INVALID_HANDLE = 0x8000
+ GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
+ GPTR = GMEM_FIXED | GMEM_ZEROINIT
+)
+
+// Ternary raster operations
+const (
+ SRCCOPY = 0x00CC0020
+ SRCPAINT = 0x00EE0086
+ SRCAND = 0x008800C6
+ SRCINVERT = 0x00660046
+ SRCERASE = 0x00440328
+ NOTSRCCOPY = 0x00330008
+ NOTSRCERASE = 0x001100A6
+ MERGECOPY = 0x00C000CA
+ MERGEPAINT = 0x00BB0226
+ PATCOPY = 0x00F00021
+ PATPAINT = 0x00FB0A09
+ PATINVERT = 0x005A0049
+ DSTINVERT = 0x00550009
+ BLACKNESS = 0x00000042
+ WHITENESS = 0x00FF0062
+ NOMIRRORBITMAP = 0x80000000
+ CAPTUREBLT = 0x40000000
+)
+
+// Clipboard formats
+const (
+ CF_TEXT = 1
+ CF_BITMAP = 2
+ CF_METAFILEPICT = 3
+ CF_SYLK = 4
+ CF_DIF = 5
+ CF_TIFF = 6
+ CF_OEMTEXT = 7
+ CF_DIB = 8
+ CF_PALETTE = 9
+ CF_PENDATA = 10
+ CF_RIFF = 11
+ CF_WAVE = 12
+ CF_UNICODETEXT = 13
+ CF_ENHMETAFILE = 14
+ CF_HDROP = 15
+ CF_LOCALE = 16
+ CF_DIBV5 = 17
+ CF_MAX = 18
+ CF_OWNERDISPLAY = 0x0080
+ CF_DSPTEXT = 0x0081
+ CF_DSPBITMAP = 0x0082
+ CF_DSPMETAFILEPICT = 0x0083
+ CF_DSPENHMETAFILE = 0x008E
+ CF_PRIVATEFIRST = 0x0200
+ CF_PRIVATELAST = 0x02FF
+ CF_GDIOBJFIRST = 0x0300
+ CF_GDIOBJLAST = 0x03FF
+)
+
+// Bitmap compression formats
+const (
+ BI_RGB = 0
+ BI_RLE8 = 1
+ BI_RLE4 = 2
+ BI_BITFIELDS = 3
+ BI_JPEG = 4
+ BI_PNG = 5
+)
+
+// SetDIBitsToDevice fuColorUse
+const (
+ DIB_PAL_COLORS = 1
+ DIB_RGB_COLORS = 0
+)
+
+const (
+ STANDARD_RIGHTS_REQUIRED = 0x000F
+)
+
+// Service Control Manager object specific access types
+const (
+ SC_MANAGER_CONNECT = 0x0001
+ SC_MANAGER_CREATE_SERVICE = 0x0002
+ SC_MANAGER_ENUMERATE_SERVICE = 0x0004
+ SC_MANAGER_LOCK = 0x0008
+ SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
+ SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
+ SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG
+)
+
+// Service Types (Bit Mask)
+const (
+ SERVICE_KERNEL_DRIVER = 0x00000001
+ SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
+ SERVICE_ADAPTER = 0x00000004
+ SERVICE_RECOGNIZER_DRIVER = 0x00000008
+ SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
+ SERVICE_WIN32_OWN_PROCESS = 0x00000010
+ SERVICE_WIN32_SHARE_PROCESS = 0x00000020
+ SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
+ SERVICE_INTERACTIVE_PROCESS = 0x00000100
+ SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
+)
+
+// Service State -- for CurrentState
+const (
+ SERVICE_STOPPED = 0x00000001
+ SERVICE_START_PENDING = 0x00000002
+ SERVICE_STOP_PENDING = 0x00000003
+ SERVICE_RUNNING = 0x00000004
+ SERVICE_CONTINUE_PENDING = 0x00000005
+ SERVICE_PAUSE_PENDING = 0x00000006
+ SERVICE_PAUSED = 0x00000007
+)
+
+// Controls Accepted (Bit Mask)
+const (
+ SERVICE_ACCEPT_STOP = 0x00000001
+ SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
+ SERVICE_ACCEPT_SHUTDOWN = 0x00000004
+ SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
+ SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
+ SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
+ SERVICE_ACCEPT_POWEREVENT = 0x00000040
+ SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
+ SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
+ SERVICE_ACCEPT_TIMECHANGE = 0x00000200
+ SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
+)
+
+// Service object specific access type
+const (
+ SERVICE_QUERY_CONFIG = 0x0001
+ SERVICE_CHANGE_CONFIG = 0x0002
+ SERVICE_QUERY_STATUS = 0x0004
+ SERVICE_ENUMERATE_DEPENDENTS = 0x0008
+ SERVICE_START = 0x0010
+ SERVICE_STOP = 0x0020
+ SERVICE_PAUSE_CONTINUE = 0x0040
+ SERVICE_INTERROGATE = 0x0080
+ SERVICE_USER_DEFINED_CONTROL = 0x0100
+
+ SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ SERVICE_QUERY_CONFIG |
+ SERVICE_CHANGE_CONFIG |
+ SERVICE_QUERY_STATUS |
+ SERVICE_ENUMERATE_DEPENDENTS |
+ SERVICE_START |
+ SERVICE_STOP |
+ SERVICE_PAUSE_CONTINUE |
+ SERVICE_INTERROGATE |
+ SERVICE_USER_DEFINED_CONTROL
+)
+
+// MapVirtualKey maptypes
+const (
+ MAPVK_VK_TO_CHAR = 2
+ MAPVK_VK_TO_VSC = 0
+ MAPVK_VSC_TO_VK = 1
+ MAPVK_VSC_TO_VK_EX = 3
+)
+
+// ReadEventLog Flags
+const (
+ EVENTLOG_SEEK_READ = 0x0002
+ EVENTLOG_SEQUENTIAL_READ = 0x0001
+ EVENTLOG_FORWARDS_READ = 0x0004
+ EVENTLOG_BACKWARDS_READ = 0x0008
+)
+
+// CreateToolhelp32Snapshot flags
+const (
+ TH32CS_SNAPHEAPLIST = 0x00000001
+ TH32CS_SNAPPROCESS = 0x00000002
+ TH32CS_SNAPTHREAD = 0x00000004
+ TH32CS_SNAPMODULE = 0x00000008
+ TH32CS_SNAPMODULE32 = 0x00000010
+ TH32CS_INHERIT = 0x80000000
+ TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
+)
+
+const (
+ MAX_MODULE_NAME32 = 255
+ MAX_PATH = 260
+)
+
+const (
+ NIM_ADD = 0x00000000
+ NIM_MODIFY = 0x00000001
+ NIM_DELETE = 0x00000002
+ NIM_SETVERSION = 0x00000004
+
+ NIF_MESSAGE = 0x00000001
+ NIF_ICON = 0x00000002
+ NIF_TIP = 0x00000004
+ NIF_STATE = 0x00000008
+ NIF_INFO = 0x00000010
+
+ NIS_HIDDEN = 0x00000001
+
+ NIIF_NONE = 0x00000000
+ NIIF_INFO = 0x00000001
+ NIIF_WARNING = 0x00000002
+ NIIF_ERROR = 0x00000003
+ NIIF_USER = 0x00000004
+ NIIF_NOSOUND = 0x00000010
+ NIIF_LARGE_ICON = 0x00000020
+ NIIF_RESPECT_QUIET_TIME = 0x00000080
+ NIIF_ICON_MASK = 0x0000000F
+)
+
+const (
+ FOREGROUND_BLUE = 0x0001
+ FOREGROUND_GREEN = 0x0002
+ FOREGROUND_RED = 0x0004
+ FOREGROUND_INTENSITY = 0x0008
+ BACKGROUND_BLUE = 0x0010
+ BACKGROUND_GREEN = 0x0020
+ BACKGROUND_RED = 0x0040
+ BACKGROUND_INTENSITY = 0x0080
+ COMMON_LVB_LEADING_BYTE = 0x0100
+ COMMON_LVB_TRAILING_BYTE = 0x0200
+ COMMON_LVB_GRID_HORIZONTAL = 0x0400
+ COMMON_LVB_GRID_LVERTICAL = 0x0800
+ COMMON_LVB_GRID_RVERTICAL = 0x1000
+ COMMON_LVB_REVERSE_VIDEO = 0x4000
+ COMMON_LVB_UNDERSCORE = 0x8000
+)
+
+// Flags used by the DWM_BLURBEHIND structure to indicate
+// which of its members contain valid information.
+const (
+ DWM_BB_ENABLE = 0x00000001 // A value for the fEnable member has been specified.
+ DWM_BB_BLURREGION = 0x00000002 // A value for the hRgnBlur member has been specified.
+ DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004 // A value for the fTransitionOnMaximized member has been specified.
+)
+
+// Flags used by the DwmEnableComposition function
+// to change the state of Desktop Window Manager (DWM) composition.
+const (
+ DWM_EC_DISABLECOMPOSITION = 0 // Disable composition
+ DWM_EC_ENABLECOMPOSITION = 1 // Enable composition
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SHOWCONTACT int32
+
+const (
+ DWMSC_DOWN = 0x00000001
+ DWMSC_UP = 0x00000002
+ DWMSC_DRAG = 0x00000004
+ DWMSC_HOLD = 0x00000008
+ DWMSC_PENBARREL = 0x00000010
+ DWMSC_NONE = 0x00000000
+ DWMSC_ALL = 0xFFFFFFFF
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SOURCE_FRAME_SAMPLING int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetPresentParameters function
+// to specify the frame sampling type
+const (
+ DWM_SOURCE_FRAME_SAMPLING_POINT = iota + 1
+ DWM_SOURCE_FRAME_SAMPLING_COVERAGE
+ DWM_SOURCE_FRAME_SAMPLING_LAST
+)
+
+// Flags used by the DWM_THUMBNAIL_PROPERTIES structure to
+// indicate which of its members contain valid information.
+const (
+ DWM_TNP_RECTDESTINATION = 0x00000001 // A value for the rcDestination member has been specified
+ DWM_TNP_RECTSOURCE = 0x00000002 // A value for the rcSource member has been specified
+ DWM_TNP_OPACITY = 0x00000004 // A value for the opacity member has been specified
+ DWM_TNP_VISIBLE = 0x00000008 // A value for the fVisible member has been specified
+ DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010 // A value for the fSourceClientAreaOnly member has been specified
+)
+
+// enum-lite implementation for the following constant structure
+type DWMFLIP3DWINDOWPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the Flip3D window policy
+const (
+ DWMFLIP3D_DEFAULT = iota + 1
+ DWMFLIP3D_EXCLUDEBELOW
+ DWMFLIP3D_EXCLUDEABOVE
+ DWMFLIP3D_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMNCRENDERINGPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the non-client area rendering policy
+const (
+ DWMNCRP_USEWINDOWSTYLE = iota + 1
+ DWMNCRP_DISABLED
+ DWMNCRP_ENABLED
+ DWMNCRP_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMTRANSITION_OWNEDWINDOW_TARGET int32
+
+const (
+ DWMTRANSITION_OWNEDWINDOW_NULL = -1
+ DWMTRANSITION_OWNEDWINDOW_REPOSITION = 0
+)
+
+// TODO: need to verify this construction
+// Flags used by the DwmGetWindowAttribute and DwmSetWindowAttribute functions
+// to specify window attributes for non-client rendering
+const (
+ DWMWA_NCRENDERING_ENABLED = iota + 1
+ DWMWA_NCRENDERING_POLICY
+ DWMWA_TRANSITIONS_FORCEDISABLED
+ DWMWA_ALLOW_NCPAINT
+ DWMWA_CAPTION_BUTTON_BOUNDS
+ DWMWA_NONCLIENT_RTL_LAYOUT
+ DWMWA_FORCE_ICONIC_REPRESENTATION
+ DWMWA_FLIP3D_POLICY
+ DWMWA_EXTENDED_FRAME_BOUNDS
+ DWMWA_HAS_ICONIC_BITMAP
+ DWMWA_DISALLOW_PEEK
+ DWMWA_EXCLUDED_FROM_PEEK
+ DWMWA_CLOAK
+ DWMWA_CLOAKED
+ DWMWA_FREEZE_REPRESENTATION
+ DWMWA_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type GESTURE_TYPE int32
+
+// TODO: use iota?
+// Identifies the gesture type
+const (
+ GT_PEN_TAP = 0
+ GT_PEN_DOUBLETAP = 1
+ GT_PEN_RIGHTTAP = 2
+ GT_PEN_PRESSANDHOLD = 3
+ GT_PEN_PRESSANDHOLDABORT = 4
+ GT_TOUCH_TAP = 5
+ GT_TOUCH_DOUBLETAP = 6
+ GT_TOUCH_RIGHTTAP = 7
+ GT_TOUCH_PRESSANDHOLD = 8
+ GT_TOUCH_PRESSANDHOLDABORT = 9
+ GT_TOUCH_PRESSANDTAP = 10
+)
+
+// Icons
+const (
+ ICON_SMALL = 0
+ ICON_BIG = 1
+ ICON_SMALL2 = 2
+)
+
+const (
+ SIZE_RESTORED = 0
+ SIZE_MINIMIZED = 1
+ SIZE_MAXIMIZED = 2
+ SIZE_MAXSHOW = 3
+ SIZE_MAXHIDE = 4
+)
+
+// XButton values
+const (
+ XBUTTON1 = 1
+ XBUTTON2 = 2
+)
+
+const (
+ LR_LOADFROMFILE = 0x00000010
+ LR_DEFAULTSIZE = 0x00000040
+)
+
+// Devmode
+const (
+ DM_SPECVERSION = 0x0401
+
+ DM_ORIENTATION = 0x00000001
+ DM_PAPERSIZE = 0x00000002
+ DM_PAPERLENGTH = 0x00000004
+ DM_PAPERWIDTH = 0x00000008
+ DM_SCALE = 0x00000010
+ DM_POSITION = 0x00000020
+ DM_NUP = 0x00000040
+ DM_DISPLAYORIENTATION = 0x00000080
+ DM_COPIES = 0x00000100
+ DM_DEFAULTSOURCE = 0x00000200
+ DM_PRINTQUALITY = 0x00000400
+ DM_COLOR = 0x00000800
+ DM_DUPLEX = 0x00001000
+ DM_YRESOLUTION = 0x00002000
+ DM_TTOPTION = 0x00004000
+ DM_COLLATE = 0x00008000
+ DM_FORMNAME = 0x00010000
+ DM_LOGPIXELS = 0x00020000
+ DM_BITSPERPEL = 0x00040000
+ DM_PELSWIDTH = 0x00080000
+ DM_PELSHEIGHT = 0x00100000
+ DM_DISPLAYFLAGS = 0x00200000
+ DM_DISPLAYFREQUENCY = 0x00400000
+ DM_ICMMETHOD = 0x00800000
+ DM_ICMINTENT = 0x01000000
+ DM_MEDIATYPE = 0x02000000
+ DM_DITHERTYPE = 0x04000000
+ DM_PANNINGWIDTH = 0x08000000
+ DM_PANNINGHEIGHT = 0x10000000
+ DM_DISPLAYFIXEDOUTPUT = 0x20000000
+)
+
+// ChangeDisplaySettings
+const (
+ CDS_UPDATEREGISTRY = 0x00000001
+ CDS_TEST = 0x00000002
+ CDS_FULLSCREEN = 0x00000004
+ CDS_GLOBAL = 0x00000008
+ CDS_SET_PRIMARY = 0x00000010
+ CDS_VIDEOPARAMETERS = 0x00000020
+ CDS_RESET = 0x40000000
+ CDS_NORESET = 0x10000000
+
+ DISP_CHANGE_SUCCESSFUL = 0
+ DISP_CHANGE_RESTART = 1
+ DISP_CHANGE_FAILED = -1
+ DISP_CHANGE_BADMODE = -2
+ DISP_CHANGE_NOTUPDATED = -3
+ DISP_CHANGE_BADFLAGS = -4
+ DISP_CHANGE_BADPARAM = -5
+ DISP_CHANGE_BADDUALVIEW = -6
+)
+
+const (
+ ENUM_CURRENT_SETTINGS = 0xFFFFFFFF
+ ENUM_REGISTRY_SETTINGS = 0xFFFFFFFE
+)
+
+// PIXELFORMATDESCRIPTOR
+const (
+ PFD_TYPE_RGBA = 0
+ PFD_TYPE_COLORINDEX = 1
+
+ PFD_MAIN_PLANE = 0
+ PFD_OVERLAY_PLANE = 1
+ PFD_UNDERLAY_PLANE = -1
+
+ PFD_DOUBLEBUFFER = 0x00000001
+ PFD_STEREO = 0x00000002
+ PFD_DRAW_TO_WINDOW = 0x00000004
+ PFD_DRAW_TO_BITMAP = 0x00000008
+ PFD_SUPPORT_GDI = 0x00000010
+ PFD_SUPPORT_OPENGL = 0x00000020
+ PFD_GENERIC_FORMAT = 0x00000040
+ PFD_NEED_PALETTE = 0x00000080
+ PFD_NEED_SYSTEM_PALETTE = 0x00000100
+ PFD_SWAP_EXCHANGE = 0x00000200
+ PFD_SWAP_COPY = 0x00000400
+ PFD_SWAP_LAYER_BUFFERS = 0x00000800
+ PFD_GENERIC_ACCELERATED = 0x00001000
+ PFD_SUPPORT_DIRECTDRAW = 0x00002000
+ PFD_DIRECT3D_ACCELERATED = 0x00004000
+ PFD_SUPPORT_COMPOSITION = 0x00008000
+
+ PFD_DEPTH_DONTCARE = 0x20000000
+ PFD_DOUBLEBUFFER_DONTCARE = 0x40000000
+ PFD_STEREO_DONTCARE = 0x80000000
+)
+
+const (
+ INPUT_MOUSE = 0
+ INPUT_KEYBOARD = 1
+ INPUT_HARDWARE = 2
+)
+
+const (
+ MOUSEEVENTF_ABSOLUTE = 0x8000
+ MOUSEEVENTF_HWHEEL = 0x01000
+ MOUSEEVENTF_MOVE = 0x0001
+ MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000
+ MOUSEEVENTF_LEFTDOWN = 0x0002
+ MOUSEEVENTF_LEFTUP = 0x0004
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
+ MOUSEEVENTF_RIGHTUP = 0x0010
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
+ MOUSEEVENTF_MIDDLEUP = 0x0040
+ MOUSEEVENTF_VIRTUALDESK = 0x4000
+ MOUSEEVENTF_WHEEL = 0x0800
+ MOUSEEVENTF_XDOWN = 0x0080
+ MOUSEEVENTF_XUP = 0x0100
+)
+
+// Windows Hooks (WH_*)
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
+const (
+ WH_CALLWNDPROC = 4
+ WH_CALLWNDPROCRET = 12
+ WH_CBT = 5
+ WH_DEBUG = 9
+ WH_FOREGROUNDIDLE = 11
+ WH_GETMESSAGE = 3
+ WH_JOURNALPLAYBACK = 1
+ WH_JOURNALRECORD = 0
+ WH_KEYBOARD = 2
+ WH_KEYBOARD_LL = 13
+ WH_MOUSE = 7
+ WH_MOUSE_LL = 14
+ WH_MSGFILTER = -1
+ WH_SHELL = 10
+ WH_SYSMSGFILTER = 6
+)
+
+// ComboBox return values
+const (
+ CB_OKAY = 0
+ CB_ERR = ^uintptr(0) // -1
+ CB_ERRSPACE = ^uintptr(1) // -2
+)
+
+// ComboBox notifications
+const (
+ CBN_ERRSPACE = -1
+ CBN_SELCHANGE = 1
+ CBN_DBLCLK = 2
+ CBN_SETFOCUS = 3
+ CBN_KILLFOCUS = 4
+ CBN_EDITCHANGE = 5
+ CBN_EDITUPDATE = 6
+ CBN_DROPDOWN = 7
+ CBN_CLOSEUP = 8
+ CBN_SELENDOK = 9
+ CBN_SELENDCANCEL = 10
+)
+
+// ComboBox styles
+const (
+ CBS_SIMPLE = 0x0001
+ CBS_DROPDOWN = 0x0002
+ CBS_DROPDOWNLIST = 0x0003
+ CBS_OWNERDRAWFIXED = 0x0010
+ CBS_OWNERDRAWVARIABLE = 0x0020
+ CBS_AUTOHSCROLL = 0x0040
+ CBS_OEMCONVERT = 0x0080
+ CBS_SORT = 0x0100
+ CBS_HASSTRINGS = 0x0200
+ CBS_NOINTEGRALHEIGHT = 0x0400
+ CBS_DISABLENOSCROLL = 0x0800
+ CBS_UPPERCASE = 0x2000
+ CBS_LOWERCASE = 0x4000
+)
+
+// ComboBox messages
+const (
+ CB_GETEDITSEL = 0x0140
+ CB_LIMITTEXT = 0x0141
+ CB_SETEDITSEL = 0x0142
+ CB_ADDSTRING = 0x0143
+ CB_DELETESTRING = 0x0144
+ CB_DIR = 0x0145
+ CB_GETCOUNT = 0x0146
+ CB_GETCURSEL = 0x0147
+ CB_GETLBTEXT = 0x0148
+ CB_GETLBTEXTLEN = 0x0149
+ CB_INSERTSTRING = 0x014A
+ CB_RESETCONTENT = 0x014B
+ CB_FINDSTRING = 0x014C
+ CB_SELECTSTRING = 0x014D
+ CB_SETCURSEL = 0x014E
+ CB_SHOWDROPDOWN = 0x014F
+ CB_GETITEMDATA = 0x0150
+ CB_SETITEMDATA = 0x0151
+ CB_GETDROPPEDCONTROLRECT = 0x0152
+ CB_SETITEMHEIGHT = 0x0153
+ CB_GETITEMHEIGHT = 0x0154
+ CB_SETEXTENDEDUI = 0x0155
+ CB_GETEXTENDEDUI = 0x0156
+ CB_GETDROPPEDSTATE = 0x0157
+ CB_FINDSTRINGEXACT = 0x0158
+ CB_SETLOCALE = 0x0159
+ CB_GETLOCALE = 0x015A
+ CB_GETTOPINDEX = 0x015b
+ CB_SETTOPINDEX = 0x015c
+ CB_GETHORIZONTALEXTENT = 0x015d
+ CB_SETHORIZONTALEXTENT = 0x015e
+ CB_GETDROPPEDWIDTH = 0x015f
+ CB_SETDROPPEDWIDTH = 0x0160
+ CB_INITSTORAGE = 0x0161
+ CB_MULTIPLEADDSTRING = 0x0163
+ CB_GETCOMBOBOXINFO = 0x0164
+)
+
+// TreeView styles
+const (
+ TVS_HASBUTTONS = 0x0001
+ TVS_HASLINES = 0x0002
+ TVS_LINESATROOT = 0x0004
+ TVS_EDITLABELS = 0x0008
+ TVS_DISABLEDRAGDROP = 0x0010
+ TVS_SHOWSELALWAYS = 0x0020
+ TVS_RTLREADING = 0x0040
+ TVS_NOTOOLTIPS = 0x0080
+ TVS_CHECKBOXES = 0x0100
+ TVS_TRACKSELECT = 0x0200
+ TVS_SINGLEEXPAND = 0x0400
+ TVS_INFOTIP = 0x0800
+ TVS_FULLROWSELECT = 0x1000
+ TVS_NOSCROLL = 0x2000
+ TVS_NONEVENHEIGHT = 0x4000
+ TVS_NOHSCROLL = 0x8000
+)
+
+const (
+ TVS_EX_NOSINGLECOLLAPSE = 0x0001
+ TVS_EX_MULTISELECT = 0x0002
+ TVS_EX_DOUBLEBUFFER = 0x0004
+ TVS_EX_NOINDENTSTATE = 0x0008
+ TVS_EX_RICHTOOLTIP = 0x0010
+ TVS_EX_AUTOHSCROLL = 0x0020
+ TVS_EX_FADEINOUTEXPANDOS = 0x0040
+ TVS_EX_PARTIALCHECKBOXES = 0x0080
+ TVS_EX_EXCLUSIONCHECKBOXES = 0x0100
+ TVS_EX_DIMMEDCHECKBOXES = 0x0200
+ TVS_EX_DRAWIMAGEASYNC = 0x0400
+)
+
+const (
+ TVIF_TEXT = 0x0001
+ TVIF_IMAGE = 0x0002
+ TVIF_PARAM = 0x0004
+ TVIF_STATE = 0x0008
+ TVIF_HANDLE = 0x0010
+ TVIF_SELECTEDIMAGE = 0x0020
+ TVIF_CHILDREN = 0x0040
+ TVIF_INTEGRAL = 0x0080
+ TVIF_STATEEX = 0x0100
+ TVIF_EXPANDEDIMAGE = 0x0200
+)
+
+const (
+ TVIS_SELECTED = 0x0002
+ TVIS_CUT = 0x0004
+ TVIS_DROPHILITED = 0x0008
+ TVIS_BOLD = 0x0010
+ TVIS_EXPANDED = 0x0020
+ TVIS_EXPANDEDONCE = 0x0040
+ TVIS_EXPANDPARTIAL = 0x0080
+ TVIS_OVERLAYMASK = 0x0F00
+ TVIS_STATEIMAGEMASK = 0xF000
+ TVIS_USERMASK = 0xF000
+)
+
+const (
+ TVIS_EX_FLAT = 0x0001
+ TVIS_EX_DISABLED = 0x0002
+ TVIS_EX_ALL = 0x0002
+)
+
+const (
+ TVI_ROOT = ^HTREEITEM(0xffff)
+ TVI_FIRST = ^HTREEITEM(0xfffe)
+ TVI_LAST = ^HTREEITEM(0xfffd)
+ TVI_SORT = ^HTREEITEM(0xfffc)
+)
+
+// TVM_EXPAND action flags
+const (
+ TVE_COLLAPSE = 0x0001
+ TVE_EXPAND = 0x0002
+ TVE_TOGGLE = 0x0003
+ TVE_EXPANDPARTIAL = 0x4000
+ TVE_COLLAPSERESET = 0x8000
+)
+
+const (
+ TVGN_CARET = 9
+)
+
+// TreeView messages
+const (
+ TV_FIRST = 0x1100
+
+ TVM_INSERTITEM = TV_FIRST + 50
+ TVM_DELETEITEM = TV_FIRST + 1
+ TVM_EXPAND = TV_FIRST + 2
+ TVM_GETITEMRECT = TV_FIRST + 4
+ TVM_GETCOUNT = TV_FIRST + 5
+ TVM_GETINDENT = TV_FIRST + 6
+ TVM_SETINDENT = TV_FIRST + 7
+ TVM_GETIMAGELIST = TV_FIRST + 8
+ TVM_SETIMAGELIST = TV_FIRST + 9
+ TVM_GETNEXTITEM = TV_FIRST + 10
+ TVM_SELECTITEM = TV_FIRST + 11
+ TVM_GETITEM = TV_FIRST + 62
+ TVM_SETITEM = TV_FIRST + 63
+ TVM_EDITLABEL = TV_FIRST + 65
+ TVM_GETEDITCONTROL = TV_FIRST + 15
+ TVM_GETVISIBLECOUNT = TV_FIRST + 16
+ TVM_HITTEST = TV_FIRST + 17
+ TVM_CREATEDRAGIMAGE = TV_FIRST + 18
+ TVM_SORTCHILDREN = TV_FIRST + 19
+ TVM_ENSUREVISIBLE = TV_FIRST + 20
+ TVM_SORTCHILDRENCB = TV_FIRST + 21
+ TVM_ENDEDITLABELNOW = TV_FIRST + 22
+ TVM_GETISEARCHSTRING = TV_FIRST + 64
+ TVM_SETTOOLTIPS = TV_FIRST + 24
+ TVM_GETTOOLTIPS = TV_FIRST + 25
+ TVM_SETINSERTMARK = TV_FIRST + 26
+ TVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+ TVM_SETITEMHEIGHT = TV_FIRST + 27
+ TVM_GETITEMHEIGHT = TV_FIRST + 28
+ TVM_SETBKCOLOR = TV_FIRST + 29
+ TVM_SETTEXTCOLOR = TV_FIRST + 30
+ TVM_GETBKCOLOR = TV_FIRST + 31
+ TVM_GETTEXTCOLOR = TV_FIRST + 32
+ TVM_SETSCROLLTIME = TV_FIRST + 33
+ TVM_GETSCROLLTIME = TV_FIRST + 34
+ TVM_SETINSERTMARKCOLOR = TV_FIRST + 37
+ TVM_GETINSERTMARKCOLOR = TV_FIRST + 38
+ TVM_GETITEMSTATE = TV_FIRST + 39
+ TVM_SETLINECOLOR = TV_FIRST + 40
+ TVM_GETLINECOLOR = TV_FIRST + 41
+ TVM_MAPACCIDTOHTREEITEM = TV_FIRST + 42
+ TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43
+ TVM_SETEXTENDEDSTYLE = TV_FIRST + 44
+ TVM_GETEXTENDEDSTYLE = TV_FIRST + 45
+ TVM_SETAUTOSCROLLINFO = TV_FIRST + 59
+)
+
+// TreeView notifications
+const (
+ TVN_FIRST = ^uint32(399)
+
+ TVN_SELCHANGING = TVN_FIRST - 50
+ TVN_SELCHANGED = TVN_FIRST - 51
+ TVN_GETDISPINFO = TVN_FIRST - 52
+ TVN_ITEMEXPANDING = TVN_FIRST - 54
+ TVN_ITEMEXPANDED = TVN_FIRST - 55
+ TVN_BEGINDRAG = TVN_FIRST - 56
+ TVN_BEGINRDRAG = TVN_FIRST - 57
+ TVN_DELETEITEM = TVN_FIRST - 58
+ TVN_BEGINLABELEDIT = TVN_FIRST - 59
+ TVN_ENDLABELEDIT = TVN_FIRST - 60
+ TVN_KEYDOWN = TVN_FIRST - 12
+ TVN_GETINFOTIP = TVN_FIRST - 14
+ TVN_SINGLEEXPAND = TVN_FIRST - 15
+ TVN_ITEMCHANGING = TVN_FIRST - 17
+ TVN_ITEMCHANGED = TVN_FIRST - 19
+ TVN_ASYNCDRAW = TVN_FIRST - 20
+)
+
+// TreeView hit test constants
+const (
+ TVHT_NOWHERE = 1
+ TVHT_ONITEMICON = 2
+ TVHT_ONITEMLABEL = 4
+ TVHT_ONITEM = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON
+ TVHT_ONITEMINDENT = 8
+ TVHT_ONITEMBUTTON = 16
+ TVHT_ONITEMRIGHT = 32
+ TVHT_ONITEMSTATEICON = 64
+ TVHT_ABOVE = 256
+ TVHT_BELOW = 512
+ TVHT_TORIGHT = 1024
+ TVHT_TOLEFT = 2048
+)
+
+type HTREEITEM HANDLE
+
+type TVITEM struct {
+ Mask uint32
+ HItem HTREEITEM
+ State uint32
+ StateMask uint32
+ PszText uintptr
+ CchTextMax int32
+ IImage int32
+ ISelectedImage int32
+ CChildren int32
+ LParam uintptr
+}
+
+/*type TVITEMEX struct {
+ mask UINT
+ hItem HTREEITEM
+ state UINT
+ stateMask UINT
+ pszText LPWSTR
+ cchTextMax int
+ iImage int
+ iSelectedImage int
+ cChildren int
+ lParam LPARAM
+ iIntegral int
+ uStateEx UINT
+ hwnd HWND
+ iExpandedImage int
+}*/
+
+type TVINSERTSTRUCT struct {
+ HParent HTREEITEM
+ HInsertAfter HTREEITEM
+ Item TVITEM
+ // itemex TVITEMEX
+}
+
+type NMTREEVIEW struct {
+ Hdr NMHDR
+ Action uint32
+ ItemOld TVITEM
+ ItemNew TVITEM
+ PtDrag POINT
+}
+
+type NMTVDISPINFO struct {
+ Hdr NMHDR
+ Item TVITEM
+}
+
+type NMTVKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+type TVHITTESTINFO struct {
+ Pt POINT
+ Flags uint32
+ HItem HTREEITEM
+}
+
+// TabPage support
+
+const TCM_FIRST = 0x1300
+const TCN_FIRST = -550
+
+const (
+ TCS_SCROLLOPPOSITE = 0x0001
+ TCS_BOTTOM = 0x0002
+ TCS_RIGHT = 0x0002
+ TCS_MULTISELECT = 0x0004
+ TCS_FLATBUTTONS = 0x0008
+ TCS_FORCEICONLEFT = 0x0010
+ TCS_FORCELABELLEFT = 0x0020
+ TCS_HOTTRACK = 0x0040
+ TCS_VERTICAL = 0x0080
+ TCS_TABS = 0x0000
+ TCS_BUTTONS = 0x0100
+ TCS_SINGLELINE = 0x0000
+ TCS_MULTILINE = 0x0200
+ TCS_RIGHTJUSTIFY = 0x0000
+ TCS_FIXEDWIDTH = 0x0400
+ TCS_RAGGEDRIGHT = 0x0800
+ TCS_FOCUSONBUTTONDOWN = 0x1000
+ TCS_OWNERDRAWFIXED = 0x2000
+ TCS_TOOLTIPS = 0x4000
+ TCS_FOCUSNEVER = 0x8000
+)
+
+const (
+ TCS_EX_FLATSEPARATORS = 0x00000001
+ TCS_EX_REGISTERDROP = 0x00000002
+)
+
+const (
+ TCM_GETIMAGELIST = TCM_FIRST + 2
+ TCM_SETIMAGELIST = TCM_FIRST + 3
+ TCM_GETITEMCOUNT = TCM_FIRST + 4
+ TCM_GETITEM = TCM_FIRST + 60
+ TCM_SETITEM = TCM_FIRST + 61
+ TCM_INSERTITEM = TCM_FIRST + 62
+ TCM_DELETEITEM = TCM_FIRST + 8
+ TCM_DELETEALLITEMS = TCM_FIRST + 9
+ TCM_GETITEMRECT = TCM_FIRST + 10
+ TCM_GETCURSEL = TCM_FIRST + 11
+ TCM_SETCURSEL = TCM_FIRST + 12
+ TCM_HITTEST = TCM_FIRST + 13
+ TCM_SETITEMEXTRA = TCM_FIRST + 14
+ TCM_ADJUSTRECT = TCM_FIRST + 40
+ TCM_SETITEMSIZE = TCM_FIRST + 41
+ TCM_REMOVEIMAGE = TCM_FIRST + 42
+ TCM_SETPADDING = TCM_FIRST + 43
+ TCM_GETROWCOUNT = TCM_FIRST + 44
+ TCM_GETTOOLTIPS = TCM_FIRST + 45
+ TCM_SETTOOLTIPS = TCM_FIRST + 46
+ TCM_GETCURFOCUS = TCM_FIRST + 47
+ TCM_SETCURFOCUS = TCM_FIRST + 48
+ TCM_SETMINTABWIDTH = TCM_FIRST + 49
+ TCM_DESELECTALL = TCM_FIRST + 50
+ TCM_HIGHLIGHTITEM = TCM_FIRST + 51
+ TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52
+ TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53
+ TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+)
+
+const (
+ TCIF_TEXT = 0x0001
+ TCIF_IMAGE = 0x0002
+ TCIF_RTLREADING = 0x0004
+ TCIF_PARAM = 0x0008
+ TCIF_STATE = 0x0010
+)
+
+const (
+ TCIS_BUTTONPRESSED = 0x0001
+ TCIS_HIGHLIGHTED = 0x0002
+)
+
+const (
+ TCHT_NOWHERE = 0x0001
+ TCHT_ONITEMICON = 0x0002
+ TCHT_ONITEMLABEL = 0x0004
+ TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL
+)
+
+const (
+ TCN_KEYDOWN = TCN_FIRST - 0
+ TCN_SELCHANGE = TCN_FIRST - 1
+ TCN_SELCHANGING = TCN_FIRST - 2
+ TCN_GETOBJECT = TCN_FIRST - 3
+ TCN_FOCUSCHANGE = TCN_FIRST - 4
+)
+
+type TCITEMHEADER struct {
+ Mask uint32
+ LpReserved1 uint32
+ LpReserved2 uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+}
+
+type TCITEM struct {
+ Mask uint32
+ DwState uint32
+ DwStateMask uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+ LParam uintptr
+}
+
+type TCHITTESTINFO struct {
+ Pt POINT
+ flags uint32
+}
+
+type NMTCKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+// Menu support constants
+
+// Constants for MENUITEMINFO.fMask
+const (
+ MIIM_STATE = 1
+ MIIM_ID = 2
+ MIIM_SUBMENU = 4
+ MIIM_CHECKMARKS = 8
+ MIIM_TYPE = 16
+ MIIM_DATA = 32
+ MIIM_STRING = 64
+ MIIM_BITMAP = 128
+ MIIM_FTYPE = 256
+)
+
+// Constants for MENUITEMINFO.fType
+const (
+ MFT_BITMAP = 4
+ MFT_MENUBARBREAK = 32
+ MFT_MENUBREAK = 64
+ MFT_OWNERDRAW = 256
+ MFT_RADIOCHECK = 512
+ MFT_RIGHTJUSTIFY = 0x4000
+ MFT_SEPARATOR = 0x800
+ MFT_RIGHTORDER = 0x2000
+ MFT_STRING = 0
+)
+
+// Constants for MENUITEMINFO.fState
+const (
+ MFS_CHECKED = 8
+ MFS_DEFAULT = 4096
+ MFS_DISABLED = 3
+ MFS_ENABLED = 0
+ MFS_GRAYED = 3
+ MFS_HILITE = 128
+ MFS_UNCHECKED = 0
+ MFS_UNHILITE = 0
+)
+
+// Constants for MENUITEMINFO.hbmp*
+const (
+ HBMMENU_CALLBACK = -1
+ HBMMENU_SYSTEM = 1
+ HBMMENU_MBAR_RESTORE = 2
+ HBMMENU_MBAR_MINIMIZE = 3
+ HBMMENU_MBAR_CLOSE = 5
+ HBMMENU_MBAR_CLOSE_D = 6
+ HBMMENU_MBAR_MINIMIZE_D = 7
+ HBMMENU_POPUP_CLOSE = 8
+ HBMMENU_POPUP_RESTORE = 9
+ HBMMENU_POPUP_MAXIMIZE = 10
+ HBMMENU_POPUP_MINIMIZE = 11
+)
+
+// MENUINFO mask constants
+const (
+ MIM_APPLYTOSUBMENUS = 0x80000000
+ MIM_BACKGROUND = 0x00000002
+ MIM_HELPID = 0x00000004
+ MIM_MAXHEIGHT = 0x00000001
+ MIM_MENUDATA = 0x00000008
+ MIM_STYLE = 0x00000010
+)
+
+// MENUINFO style constants
+const (
+ MNS_AUTODISMISS = 0x10000000
+ MNS_CHECKORBMP = 0x04000000
+ MNS_DRAGDROP = 0x20000000
+ MNS_MODELESS = 0x40000000
+ MNS_NOCHECK = 0x80000000
+ MNS_NOTIFYBYPOS = 0x08000000
+)
+
+const (
+ MF_BYCOMMAND = 0x00000000
+ MF_BYPOSITION = 0x00000400
+ MF_BITMAP = 0x00000004
+ MF_CHECKED = 0x00000008
+ MF_DISABLED = 0x00000002
+ MF_ENABLED = 0x00000000
+ MF_GRAYED = 0x00000001
+ MF_MENUBARBREAK = 0x00000020
+ MF_MENUBREAK = 0x00000040
+ MF_OWNERDRAW = 0x00000100
+ MF_POPUP = 0x00000010
+ MF_SEPARATOR = 0x00000800
+ MF_STRING = 0x00000000
+ MF_UNCHECKED = 0x00000000
+)
+
+type MENUITEMINFO struct {
+ CbSize uint32
+ FMask uint32
+ FType uint32
+ FState uint32
+ WID uint32
+ HSubMenu HMENU
+ HbmpChecked HBITMAP
+ HbmpUnchecked HBITMAP
+ DwItemData uintptr
+ DwTypeData *uint16
+ Cch uint32
+ HbmpItem HBITMAP
+}
+
+type MENUINFO struct {
+ CbSize uint32
+ FMask uint32
+ DwStyle uint32
+ CyMax uint32
+ HbrBack HBRUSH
+ DwContextHelpID uint32
+ DwMenuData uintptr
+}
+
+// UI state constants
+const (
+ UIS_SET = 1
+ UIS_CLEAR = 2
+ UIS_INITIALIZE = 3
+)
+
+// UI state constants
+const (
+ UISF_HIDEFOCUS = 0x1
+ UISF_HIDEACCEL = 0x2
+ UISF_ACTIVE = 0x4
+)
+
+// Virtual key codes
+const (
+ VK_LBUTTON = 1
+ VK_RBUTTON = 2
+ VK_CANCEL = 3
+ VK_MBUTTON = 4
+ VK_XBUTTON1 = 5
+ VK_XBUTTON2 = 6
+ VK_BACK = 8
+ VK_TAB = 9
+ VK_CLEAR = 12
+ VK_RETURN = 13
+ VK_SHIFT = 16
+ VK_CONTROL = 17
+ VK_MENU = 18
+ VK_PAUSE = 19
+ VK_CAPITAL = 20
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 32
+ VK_PRIOR = 33
+ VK_NEXT = 34
+ VK_END = 35
+ VK_HOME = 36
+ VK_LEFT = 37
+ VK_UP = 38
+ VK_RIGHT = 39
+ VK_DOWN = 40
+ VK_SELECT = 41
+ VK_PRINT = 42
+ VK_EXECUTE = 43
+ VK_SNAPSHOT = 44
+ VK_INSERT = 45
+ VK_DELETE = 46
+ VK_HELP = 47
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_102 = 0xE2
+ VK_PROCESSKEY = 0xE5
+ VK_PACKET = 0xE7
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)
+
+// ScrollBar constants
+const (
+ SB_HORZ = 0
+ SB_VERT = 1
+ SB_CTL = 2
+ SB_BOTH = 3
+)
+
+// ScrollBar commands
+const (
+ SB_LINEUP = 0
+ SB_LINELEFT = 0
+ SB_LINEDOWN = 1
+ SB_LINERIGHT = 1
+ SB_PAGEUP = 2
+ SB_PAGELEFT = 2
+ SB_PAGEDOWN = 3
+ SB_PAGERIGHT = 3
+ SB_THUMBPOSITION = 4
+ SB_THUMBTRACK = 5
+ SB_TOP = 6
+ SB_LEFT = 6
+ SB_BOTTOM = 7
+ SB_RIGHT = 7
+ SB_ENDSCROLL = 8
+)
+
+// [Get|Set]ScrollInfo mask constants
+const (
+ SIF_RANGE = 1
+ SIF_PAGE = 2
+ SIF_POS = 4
+ SIF_DISABLENOSCROLL = 8
+ SIF_TRACKPOS = 16
+ SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
+)
+
+const AC_SRC_OVER = 0
+const AC_SRC_ALPHA = 1
+
+const ULW_COLORKEY = 1
+const ULW_ALPHA = 2
+const ULW_OPAQUE = 4
+const ULW_EX_NORESIZE = 8
diff --git a/v3/pkg/w32/consts.go b/v3/pkg/w32/consts.go
new file mode 100644
index 000000000..b9afe2794
--- /dev/null
+++ b/v3/pkg/w32/consts.go
@@ -0,0 +1,83 @@
+//go:build windows
+
+package w32
+
+import (
+ "golang.org/x/sys/windows/registry"
+ "strconv"
+ "syscall"
+)
+
+var (
+ modwingdi = syscall.NewLazyDLL("gdi32.dll")
+ procCreateSolidBrush = modwingdi.NewProc("CreateSolidBrush")
+)
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32")
+ kernelGlobalAlloc = kernel32.NewProc("GlobalAlloc")
+ kernelGlobalFree = kernel32.NewProc("GlobalFree")
+ kernelGlobalLock = kernel32.NewProc("GlobalLock")
+ kernelGlobalUnlock = kernel32.NewProc("GlobalUnlock")
+ kernelLstrcpy = kernel32.NewProc("lstrcpyW")
+)
+
+var windowsVersion, _ = getWindowsVersionInfo()
+
+func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
+ return windowsVersion.Major >= major &&
+ windowsVersion.Minor >= minor &&
+ windowsVersion.Build >= buildNumber
+}
+
+type WindowsVersionInfo struct {
+ Major int
+ Minor int
+ Build int
+ DisplayVersion string
+}
+
+func (w *WindowsVersionInfo) IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
+ return w.Major >= major && w.Minor >= minor && w.Build >= buildNumber
+}
+
+func getWindowsVersionInfo() (*WindowsVersionInfo, error) {
+ key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
+ if err != nil {
+ return nil, err
+ }
+
+ return &WindowsVersionInfo{
+ Major: regDWORDKeyAsInt(key, "CurrentMajorVersionNumber"),
+ Minor: regDWORDKeyAsInt(key, "CurrentMinorVersionNumber"),
+ Build: regStringKeyAsInt(key, "CurrentBuildNumber"),
+ DisplayVersion: regKeyAsString(key, "DisplayVersion"),
+ }, nil
+}
+
+func regDWORDKeyAsInt(key registry.Key, name string) int {
+ result, _, err := key.GetIntegerValue(name)
+ if err != nil {
+ return -1
+ }
+ return int(result)
+}
+
+func regStringKeyAsInt(key registry.Key, name string) int {
+ resultStr, _, err := key.GetStringValue(name)
+ if err != nil {
+ return -1
+ }
+ result, err := strconv.Atoi(resultStr)
+ if err != nil {
+ return -1
+ }
+ return result
+}
+
+func regKeyAsString(key registry.Key, name string) string {
+ resultStr, _, err := key.GetStringValue(name)
+ if err != nil {
+ return ""
+ }
+ return resultStr
+}
diff --git a/v3/pkg/w32/dwmapi.go b/v3/pkg/w32/dwmapi.go
new file mode 100644
index 000000000..b25310db2
--- /dev/null
+++ b/v3/pkg/w32/dwmapi.go
@@ -0,0 +1,36 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
+
+ procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
+ procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
+)
+
+func DwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) HRESULT {
+ ret, _, _ := procDwmSetWindowAttribute.Call(
+ hwnd,
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ cbAttribute)
+ return HRESULT(ret)
+}
+
+func dwmExtendFrameIntoClientArea(hwnd uintptr, margins *MARGINS) error {
+ ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(margins)))
+
+ if ret != 0 {
+ return syscall.GetLastError()
+ }
+
+ return nil
+}
diff --git a/v3/pkg/w32/gdi32.go b/v3/pkg/w32/gdi32.go
new file mode 100644
index 000000000..b4b9053e6
--- /dev/null
+++ b/v3/pkg/w32/gdi32.go
@@ -0,0 +1,526 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modgdi32 = syscall.NewLazyDLL("gdi32.dll")
+
+ procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
+ procDeleteObject = modgdi32.NewProc("DeleteObject")
+ procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW")
+ procAbortDoc = modgdi32.NewProc("AbortDoc")
+ procBitBlt = modgdi32.NewProc("BitBlt")
+ procPatBlt = modgdi32.NewProc("PatBlt")
+ procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile")
+ procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW")
+ procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect")
+ procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC")
+ procCreateDC = modgdi32.NewProc("CreateDCW")
+ procCreateDIBSection = modgdi32.NewProc("CreateDIBSection")
+ procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW")
+ procCreateIC = modgdi32.NewProc("CreateICW")
+ procDeleteDC = modgdi32.NewProc("DeleteDC")
+ procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile")
+ procEllipse = modgdi32.NewProc("Ellipse")
+ procEndDoc = modgdi32.NewProc("EndDoc")
+ procEndPage = modgdi32.NewProc("EndPage")
+ procExtCreatePen = modgdi32.NewProc("ExtCreatePen")
+ procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW")
+ procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader")
+ procGetObject = modgdi32.NewProc("GetObjectW")
+ procGetStockObject = modgdi32.NewProc("GetStockObject")
+ procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW")
+ procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W")
+ procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW")
+ procLineTo = modgdi32.NewProc("LineTo")
+ procMoveToEx = modgdi32.NewProc("MoveToEx")
+ procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile")
+ procRectangle = modgdi32.NewProc("Rectangle")
+ procResetDC = modgdi32.NewProc("ResetDCW")
+ procSelectObject = modgdi32.NewProc("SelectObject")
+ procSetBkMode = modgdi32.NewProc("SetBkMode")
+ procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx")
+ procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode")
+ procSetTextColor = modgdi32.NewProc("SetTextColor")
+ procSetBkColor = modgdi32.NewProc("SetBkColor")
+ procStartDoc = modgdi32.NewProc("StartDocW")
+ procStartPage = modgdi32.NewProc("StartPage")
+ procStretchBlt = modgdi32.NewProc("StretchBlt")
+ procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice")
+ procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat")
+ procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat")
+ procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat")
+ procGetPixelFormat = modgdi32.NewProc("GetPixelFormat")
+ procSetPixelFormat = modgdi32.NewProc("SetPixelFormat")
+ procSwapBuffers = modgdi32.NewProc("SwapBuffers")
+)
+
+func GetDeviceCaps(hdc HDC, index int) int {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(hdc),
+ uintptr(index))
+
+ return int(ret)
+}
+
+func DeleteObject(hObject HGDIOBJ) bool {
+ ret, _, _ := procDeleteObject.Call(
+ uintptr(hObject))
+
+ return ret != 0
+}
+
+func CreateFontIndirect(logFont *LOGFONT) HFONT {
+ ret, _, _ := procCreateFontIndirect.Call(
+ uintptr(unsafe.Pointer(logFont)))
+
+ return HFONT(ret)
+}
+
+func AbortDoc(hdc HDC) int {
+ ret, _, _ := procAbortDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) {
+ ret, _, _ := procBitBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXDest),
+ uintptr(nYDest),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(hdcSrc),
+ uintptr(nXSrc),
+ uintptr(nYSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("BitBlt failed")
+ }
+}
+
+func PatBlt(hdc HDC, nXLeft, nYLeft, nWidth, nHeight int, dwRop uint) {
+ ret, _, _ := procPatBlt.Call(
+ uintptr(hdc),
+ uintptr(nXLeft),
+ uintptr(nYLeft),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("PatBlt failed")
+ }
+}
+
+func CloseEnhMetaFile(hdc HDC) HENHMETAFILE {
+ ret, _, _ := procCloseEnhMetaFile.Call(
+ uintptr(hdc))
+
+ return HENHMETAFILE(ret)
+}
+
+func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE {
+ ret, _, _ := procCopyEnhMetaFile.Call(
+ uintptr(hemfSrc),
+ uintptr(unsafe.Pointer(lpszFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH {
+ ret, _, _ := procCreateBrushIndirect.Call(
+ uintptr(unsafe.Pointer(lplb)))
+
+ return HBRUSH(ret)
+}
+
+func CreateCompatibleDC(hdc HDC) HDC {
+ ret, _, _ := procCreateCompatibleDC.Call(
+ uintptr(hdc))
+
+ if ret == 0 {
+ panic("Create compatible DC failed")
+ }
+
+ return HDC(ret)
+}
+
+func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procCreateDC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP {
+ ret, _, _ := procCreateDIBSection.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pbmi)),
+ uintptr(iUsage),
+ uintptr(unsafe.Pointer(ppvBits)),
+ uintptr(hSection),
+ uintptr(dwOffset))
+
+ return HBITMAP(ret)
+}
+
+func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC {
+ ret, _, _ := procCreateEnhMetaFile.Call(
+ uintptr(hdcRef),
+ uintptr(unsafe.Pointer(lpFilename)),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(unsafe.Pointer(lpDescription)))
+
+ return HDC(ret)
+}
+
+func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC {
+ ret, _, _ := procCreateIC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpdvmInit)))
+
+ return HDC(ret)
+}
+
+func DeleteDC(hdc HDC) bool {
+ ret, _, _ := procDeleteDC.Call(
+ uintptr(hdc))
+
+ return ret != 0
+}
+
+func DeleteEnhMetaFile(hemf HENHMETAFILE) bool {
+ ret, _, _ := procDeleteEnhMetaFile.Call(
+ uintptr(hemf))
+
+ return ret != 0
+}
+
+func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool {
+ ret, _, _ := procEllipse.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func EndDoc(hdc HDC) int {
+ ret, _, _ := procEndDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func EndPage(hdc HDC) int {
+ ret, _, _ := procEndPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN {
+ ret, _, _ := procExtCreatePen.Call(
+ uintptr(dwPenStyle),
+ uintptr(dwWidth),
+ uintptr(unsafe.Pointer(lplb)),
+ uintptr(dwStyleCount),
+ uintptr(unsafe.Pointer(lpStyle)))
+
+ return HPEN(ret)
+}
+
+func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE {
+ ret, _, _ := procGetEnhMetaFile.Call(
+ uintptr(unsafe.Pointer(lpszMetaFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint {
+ ret, _, _ := procGetEnhMetaFileHeader.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(lpemh)))
+
+ return uint(ret)
+}
+
+func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int {
+ ret, _, _ := procGetObject.Call(
+ uintptr(hgdiobj),
+ uintptr(cbBuffer),
+ uintptr(lpvObject))
+
+ return int(ret)
+}
+
+func GetStockObject(fnObject int) HGDIOBJ {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(fnObject))
+
+ return HGDIOBJ(ret)
+}
+
+func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentExPoint.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpszStr)),
+ uintptr(cchString),
+ uintptr(nMaxExtent),
+ uintptr(unsafe.Pointer(lpnFit)),
+ uintptr(unsafe.Pointer(alpDx)),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentPoint32.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpString)),
+ uintptr(c),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool {
+ ret, _, _ := procGetTextMetrics.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lptm)))
+
+ return ret != 0
+}
+
+func LineTo(hdc HDC, nXEnd, nYEnd int32) bool {
+ ret, _, _ := procLineTo.Call(
+ uintptr(hdc),
+ uintptr(nXEnd),
+ uintptr(nYEnd))
+
+ return ret != 0
+}
+
+func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool {
+ ret, _, _ := procMoveToEx.Call(
+ uintptr(hdc),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(lpPoint)))
+
+ return ret != 0
+}
+
+func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool {
+ ret, _, _ := procPlayEnhMetaFile.Call(
+ uintptr(hdc),
+ uintptr(hemf),
+ uintptr(unsafe.Pointer(lpRect)))
+
+ return ret != 0
+}
+
+func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool {
+ ret, _, _ := procRectangle.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procResetDC.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ {
+ ret, _, _ := procSelectObject.Call(
+ uintptr(hdc),
+ uintptr(hgdiobj))
+
+ if ret == 0 {
+ panic("SelectObject failed")
+ }
+
+ return HGDIOBJ(ret)
+}
+
+func SetBkMode(hdc HDC, iBkMode int) int {
+ ret, _, _ := procSetBkMode.Call(
+ uintptr(hdc),
+ uintptr(iBkMode))
+
+ if ret == 0 {
+ panic("SetBkMode failed")
+ }
+
+ return int(ret)
+}
+
+func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool {
+ ret, _, _ := procSetBrushOrgEx.Call(
+ uintptr(hdc),
+ uintptr(nXOrg),
+ uintptr(nYOrg),
+ uintptr(unsafe.Pointer(lppt)))
+
+ return ret != 0
+}
+
+func SetStretchBltMode(hdc HDC, iStretchMode int) int {
+ ret, _, _ := procSetStretchBltMode.Call(
+ uintptr(hdc),
+ uintptr(iStretchMode))
+
+ return int(ret)
+}
+
+func SetTextColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetTextColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetTextColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func SetBkColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetBkColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetBkColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func StartDoc(hdc HDC, lpdi *DOCINFO) int {
+ ret, _, _ := procStartDoc.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpdi)))
+
+ return int(ret)
+}
+
+func StartPage(hdc HDC) int {
+ ret, _, _ := procStartPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) {
+ ret, _, _ := procStretchBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXOriginDest),
+ uintptr(nYOriginDest),
+ uintptr(nWidthDest),
+ uintptr(nHeightDest),
+ uintptr(hdcSrc),
+ uintptr(nXOriginSrc),
+ uintptr(nYOriginSrc),
+ uintptr(nWidthSrc),
+ uintptr(nHeightSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("StretchBlt failed")
+ }
+}
+
+func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int {
+ ret, _, _ := procSetDIBitsToDevice.Call(
+ uintptr(hdc),
+ uintptr(xDest),
+ uintptr(yDest),
+ uintptr(dwWidth),
+ uintptr(dwHeight),
+ uintptr(xSrc),
+ uintptr(ySrc),
+ uintptr(uStartScan),
+ uintptr(cScanLines),
+ uintptr(unsafe.Pointer(&lpvBits[0])),
+ uintptr(unsafe.Pointer(lpbmi)),
+ uintptr(fuColorUse))
+
+ return int(ret)
+}
+
+func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procChoosePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procDescribePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(nBytes),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint {
+ ret, _, _ := procGetEnhMetaFilePixelFormat.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return uint(ret)
+}
+
+func GetPixelFormat(hdc HDC) int {
+ ret, _, _ := procGetPixelFormat.Call(
+ uintptr(hdc),
+ )
+ return int(ret)
+}
+
+func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool {
+ ret, _, _ := procSetPixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return ret == TRUE
+}
+
+func SwapBuffers(hdc HDC) bool {
+ ret, _, _ := procSwapBuffers.Call(uintptr(hdc))
+ return ret == TRUE
+}
diff --git a/v3/pkg/w32/gdiplus.go b/v3/pkg/w32/gdiplus.go
new file mode 100644
index 000000000..2591ed71b
--- /dev/null
+++ b/v3/pkg/w32/gdiplus.go
@@ -0,0 +1,177 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ Ok = 0
+ GenericError = 1
+ InvalidParameter = 2
+ OutOfMemory = 3
+ ObjectBusy = 4
+ InsufficientBuffer = 5
+ NotImplemented = 6
+ Win32Error = 7
+ WrongState = 8
+ Aborted = 9
+ FileNotFound = 10
+ ValueOverflow = 11
+ AccessDenied = 12
+ UnknownImageFormat = 13
+ FontFamilyNotFound = 14
+ FontStyleNotFound = 15
+ NotTrueTypeFont = 16
+ UnsupportedGdiplusVersion = 17
+ GdiplusNotInitialized = 18
+ PropertyNotFound = 19
+ PropertyNotSupported = 20
+ ProfileNotFound = 21
+)
+
+func GetGpStatus(s int32) string {
+ switch s {
+ case Ok:
+ return "Ok"
+ case GenericError:
+ return "GenericError"
+ case InvalidParameter:
+ return "InvalidParameter"
+ case OutOfMemory:
+ return "OutOfMemory"
+ case ObjectBusy:
+ return "ObjectBusy"
+ case InsufficientBuffer:
+ return "InsufficientBuffer"
+ case NotImplemented:
+ return "NotImplemented"
+ case Win32Error:
+ return "Win32Error"
+ case WrongState:
+ return "WrongState"
+ case Aborted:
+ return "Aborted"
+ case FileNotFound:
+ return "FileNotFound"
+ case ValueOverflow:
+ return "ValueOverflow"
+ case AccessDenied:
+ return "AccessDenied"
+ case UnknownImageFormat:
+ return "UnknownImageFormat"
+ case FontFamilyNotFound:
+ return "FontFamilyNotFound"
+ case FontStyleNotFound:
+ return "FontStyleNotFound"
+ case NotTrueTypeFont:
+ return "NotTrueTypeFont"
+ case UnsupportedGdiplusVersion:
+ return "UnsupportedGdiplusVersion"
+ case GdiplusNotInitialized:
+ return "GdiplusNotInitialized"
+ case PropertyNotFound:
+ return "PropertyNotFound"
+ case PropertyNotSupported:
+ return "PropertyNotSupported"
+ case ProfileNotFound:
+ return "ProfileNotFound"
+ }
+ return "Unknown Status Value"
+}
+
+var (
+ token uintptr
+
+ modgdiplus = syscall.NewLazyDLL("gdiplus.dll")
+
+ procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile")
+ procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP")
+ procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap")
+ procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource")
+ procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream")
+ procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage")
+ procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown")
+ procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup")
+)
+
+func GdipCreateBitmapFromFile(filename string) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromFile.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromResource.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(resId)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromStream.Call(
+ uintptr(unsafe.Pointer(stream)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) {
+ var hbitmap HBITMAP
+ ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call(
+ uintptr(unsafe.Pointer(bitmap)),
+ uintptr(unsafe.Pointer(&hbitmap)),
+ uintptr(background))
+
+ if ret != Ok {
+ return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return hbitmap, nil
+}
+
+func GdipDisposeImage(image *uintptr) {
+ procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image)))
+}
+
+func GdiplusShutdown() {
+ procGdiplusShutdown.Call(token)
+}
+
+func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) {
+ ret, _, _ := procGdiplusStartup.Call(
+ uintptr(unsafe.Pointer(&token)),
+ uintptr(unsafe.Pointer(input)),
+ uintptr(unsafe.Pointer(output)))
+
+ if ret != Ok {
+ panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret)))
+ }
+}
diff --git a/v3/pkg/w32/icon.go b/v3/pkg/w32/icon.go
new file mode 100644
index 000000000..e84444e64
--- /dev/null
+++ b/v3/pkg/w32/icon.go
@@ -0,0 +1,65 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+func CreateIconFromResourceEx(presbits uintptr, dwResSize uint32, isIcon bool, version uint32, cxDesired int, cyDesired int, flags uint) (uintptr, error) {
+ icon := 0
+ if isIcon {
+ icon = 1
+ }
+ r, _, err := procCreateIconFromResourceEx.Call(
+ presbits,
+ uintptr(dwResSize),
+ uintptr(icon),
+ uintptr(version),
+ uintptr(cxDesired),
+ uintptr(cyDesired),
+ uintptr(flags),
+ )
+
+ if r == 0 {
+ return 0, err
+ }
+ return r, nil
+}
+
+func isPNG(fileData []byte) bool {
+ if len(fileData) < 4 {
+ return false
+ }
+ return string(fileData[:4]) == "\x89PNG"
+}
+
+func isICO(fileData []byte) bool {
+ if len(fileData) < 4 {
+ return false
+ }
+ return string(fileData[:4]) == "\x00\x00\x01\x00"
+}
+
+// CreateHIconFromImage creates a HICON from a PNG or ICO file
+func CreateHIconFromImage(fileData []byte) (HICON, error) {
+ if len(fileData) < 8 {
+ return 0, fmt.Errorf("invalid file format")
+ }
+
+ if !isPNG(fileData) && !isICO(fileData) {
+ return 0, fmt.Errorf("unsupported file format")
+ }
+ iconWidth := GetSystemMetrics(SM_CXSMICON)
+ iconHeight := GetSystemMetrics(SM_CYSMICON)
+ icon, err := CreateIconFromResourceEx(
+ uintptr(unsafe.Pointer(&fileData[0])),
+ uint32(len(fileData)),
+ true,
+ 0x00030000,
+ iconWidth,
+ iconHeight,
+ LR_DEFAULTSIZE)
+ return HICON(icon), err
+}
diff --git a/v3/pkg/w32/idispatch.go b/v3/pkg/w32/idispatch.go
new file mode 100644
index 000000000..4f610f3ff
--- /dev/null
+++ b/v3/pkg/w32/idispatch.go
@@ -0,0 +1,45 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIDispatchVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+ pGetTypeInfoCount uintptr
+ pGetTypeInfo uintptr
+ pGetIDsOfNames uintptr
+ pInvoke uintptr
+}
+
+type IDispatch struct {
+ lpVtbl *pIDispatchVtbl
+}
+
+func (this *IDispatch) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IDispatch) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) GetIDsOfName(names []string) []int32 {
+ return ComGetIDsOfName(this, names)
+}
+
+func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT {
+ return ComInvoke(this, dispid, dispatch, params...)
+}
diff --git a/v3/pkg/w32/image.go b/v3/pkg/w32/image.go
new file mode 100644
index 000000000..4a3036c10
--- /dev/null
+++ b/v3/pkg/w32/image.go
@@ -0,0 +1,53 @@
+package w32
+
+import (
+ "image"
+ "syscall"
+ "unsafe"
+)
+
+func CreateHBITMAPFromImage(img *image.RGBA) (HBITMAP, error) {
+ bounds := img.Bounds()
+ width, height := bounds.Dx(), bounds.Dy()
+
+ // Create a BITMAPINFO structure for the DIB
+ bmi := BITMAPINFO{
+ BmiHeader: BITMAPINFOHEADER{
+ BiSize: uint32(unsafe.Sizeof(BITMAPINFOHEADER{})),
+ BiWidth: int32(width),
+ BiHeight: int32(-height), // negative to indicate top-down bitmap
+ BiPlanes: 1,
+ BiBitCount: 32,
+ BiCompression: BI_RGB,
+ BiSizeImage: uint32(width * height * 4), // RGBA = 4 bytes
+ },
+ }
+
+ // Create the DIB section
+ var bits unsafe.Pointer
+
+ hbmp := CreateDIBSection(0, &bmi, DIB_RGB_COLORS, &bits, 0, 0)
+ if hbmp == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ // Copy the pixel data from the Go image to the DIB section
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ i := img.PixOffset(x, y)
+ r := img.Pix[i+0]
+ g := img.Pix[i+1]
+ b := img.Pix[i+2]
+ a := img.Pix[i+3]
+
+ // Write the RGBA pixel data to the DIB section (BGR order)
+ offset := y*width*4 + x*4
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 0))) = b
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 1))) = g
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 2))) = r
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 3))) = a
+ }
+ }
+
+ return hbmp, nil
+}
diff --git a/v3/pkg/w32/istream.go b/v3/pkg/w32/istream.go
new file mode 100644
index 000000000..a47fbbce1
--- /dev/null
+++ b/v3/pkg/w32/istream.go
@@ -0,0 +1,33 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIStreamVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+}
+
+type IStream struct {
+ lpVtbl *pIStreamVtbl
+}
+
+func (this *IStream) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IStream) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IStream) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
diff --git a/v3/pkg/w32/iunknown.go b/v3/pkg/w32/iunknown.go
new file mode 100644
index 000000000..8ddc605cc
--- /dev/null
+++ b/v3/pkg/w32/iunknown.go
@@ -0,0 +1,29 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+type pIUnknownVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+}
+
+type IUnknown struct {
+ lpVtbl *pIUnknownVtbl
+}
+
+func (this *IUnknown) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface(this, id)
+}
+
+func (this *IUnknown) AddRef() int32 {
+ return ComAddRef(this)
+}
+
+func (this *IUnknown) Release() int32 {
+ return ComRelease(this)
+}
diff --git a/v3/pkg/w32/kernel32.go b/v3/pkg/w32/kernel32.go
new file mode 100644
index 000000000..063a1b0ea
--- /dev/null
+++ b/v3/pkg/w32/kernel32.go
@@ -0,0 +1,332 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+ procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")
+ procMulDiv = modkernel32.NewProc("MulDiv")
+ procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId")
+ procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
+ procGetLogicalDriveStrings = modkernel32.NewProc("GetLogicalDriveStringsW")
+ procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
+ procLstrlen = modkernel32.NewProc("lstrlenW")
+ procLstrcpy = modkernel32.NewProc("lstrcpyW")
+ procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
+ procGlobalFree = modkernel32.NewProc("GlobalFree")
+ procGlobalLock = modkernel32.NewProc("GlobalLock")
+ procGlobalUnlock = modkernel32.NewProc("GlobalUnlock")
+ procMoveMemory = modkernel32.NewProc("RtlMoveMemory")
+ procFindResource = modkernel32.NewProc("FindResourceW")
+ procSizeofResource = modkernel32.NewProc("SizeofResource")
+ procLockResource = modkernel32.NewProc("LockResource")
+ procLoadResource = modkernel32.NewProc("LoadResource")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
+ procModule32First = modkernel32.NewProc("Module32FirstW")
+ procModule32Next = modkernel32.NewProc("Module32NextW")
+ procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
+ procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute")
+ procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procSetSystemTime = modkernel32.NewProc("SetSystemTime")
+ procGetSystemTime = modkernel32.NewProc("GetSystemTime")
+)
+
+func GetModuleHandle(modulename string) HINSTANCE {
+ var mn uintptr
+ if modulename == "" {
+ mn = 0
+ } else {
+ mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
+ }
+ ret, _, _ := procGetModuleHandle.Call(mn)
+ return HINSTANCE(ret)
+}
+
+func MulDiv(number, numerator, denominator int) int {
+ ret, _, _ := procMulDiv.Call(
+ uintptr(number),
+ uintptr(numerator),
+ uintptr(denominator))
+
+ return int(ret)
+}
+
+func GetConsoleWindow() HWND {
+ ret, _, _ := procGetConsoleWindow.Call()
+
+ return HWND(ret)
+}
+
+func GetCurrentThread() HANDLE {
+ ret, _, _ := procGetCurrentThread.Call()
+
+ return HANDLE(ret)
+}
+
+func GetCurrentThreadId() HANDLE {
+ ret, _, _ := procGetCurrentThreadId.Call()
+
+ return HANDLE(ret)
+}
+
+func GetLogicalDrives() uint32 {
+ ret, _, _ := procGetLogicalDrives.Call()
+
+ return uint32(ret)
+}
+
+func GetUserDefaultLCID() uint32 {
+ ret, _, _ := procGetUserDefaultLCID.Call()
+
+ return uint32(ret)
+}
+
+func Lstrlen(lpString *uint16) int {
+ ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))
+
+ return int(ret)
+}
+
+func Lstrcpy(buf []uint16, lpString *uint16) {
+ procLstrcpy.Call(
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(lpString)))
+}
+
+func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
+ ret, _, _ := procGlobalAlloc.Call(
+ uintptr(uFlags),
+ uintptr(dwBytes))
+
+ if ret == 0 {
+ panic("GlobalAlloc failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GlobalFree(hMem HGLOBAL) {
+ ret, _, _ := procGlobalFree.Call(uintptr(hMem))
+
+ if ret != 0 {
+ panic("GlobalFree failed")
+ }
+}
+
+func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procGlobalLock.Call(uintptr(hMem))
+
+ if ret == 0 {
+ panic("GlobalLock failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func GlobalUnlock(hMem HGLOBAL) bool {
+ ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))
+
+ return ret != 0
+}
+
+func MoveMemory(destination, source unsafe.Pointer, length uint32) {
+ procMoveMemory.Call(
+ uintptr(unsafe.Pointer(destination)),
+ uintptr(source),
+ uintptr(length))
+}
+
+func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
+ ret, _, _ := procFindResource.Call(
+ uintptr(hModule),
+ uintptr(unsafe.Pointer(lpName)),
+ uintptr(unsafe.Pointer(lpType)))
+
+ if ret == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ return HRSRC(ret), nil
+}
+
+func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
+ ret, _, _ := procSizeofResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("SizeofResource failed")
+ }
+
+ return uint32(ret)
+}
+
+func LockResource(hResData HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procLockResource.Call(uintptr(hResData))
+
+ if ret == 0 {
+ panic("LockResource failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
+ ret, _, _ := procLoadResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("LoadResource failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GetLastError() uint32 {
+ ret, _, _ := procGetLastError.Call()
+ return uint32(ret)
+}
+
+func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
+ inherit := 0
+ if inheritHandle {
+ inherit = 1
+ }
+
+ ret, _, _ := procOpenProcess.Call(
+ uintptr(desiredAccess),
+ uintptr(inherit),
+ uintptr(processId))
+ return HANDLE(ret)
+}
+
+func TerminateProcess(hProcess HANDLE, uExitCode uint) bool {
+ ret, _, _ := procTerminateProcess.Call(
+ uintptr(hProcess),
+ uintptr(uExitCode))
+ return ret != 0
+}
+
+func CloseHandle(object HANDLE) bool {
+ ret, _, _ := procCloseHandle.Call(
+ uintptr(object))
+ return ret != 0
+}
+
+func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
+ ret, _, _ := procCreateToolhelp32Snapshot.Call(
+ uintptr(flags),
+ uintptr(processId))
+
+ if ret <= 0 {
+ return HANDLE(0)
+ }
+
+ return HANDLE(ret)
+}
+
+func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32First.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+
+func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32Next.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+
+func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetSystemTimes.Call(
+ uintptr(unsafe.Pointer(lpIdleTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetProcessTimes.Call(
+ uintptr(hProcess),
+ uintptr(unsafe.Pointer(lpCreationTime)),
+ uintptr(unsafe.Pointer(lpExitTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
+ var csbi CONSOLE_SCREEN_BUFFER_INFO
+ ret, _, _ := procGetConsoleScreenBufferInfo.Call(
+ uintptr(hConsoleOutput),
+ uintptr(unsafe.Pointer(&csbi)))
+ if ret == 0 {
+ return nil
+ }
+ return &csbi
+}
+
+func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
+ ret, _, _ := procSetConsoleTextAttribute.Call(
+ uintptr(hConsoleOutput),
+ uintptr(wAttributes))
+ return ret != 0
+}
+
+func GetDiskFreeSpaceEx(dirName string) (r bool,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) {
+ ret, _, _ := procGetDiskFreeSpaceEx.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))),
+ uintptr(unsafe.Pointer(&freeBytesAvailable)),
+ uintptr(unsafe.Pointer(&totalNumberOfBytes)),
+ uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
+ return ret != 0,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes
+}
+
+func GetSystemTime() *SYSTEMTIME {
+ var time SYSTEMTIME
+ procGetSystemTime.Call(
+ uintptr(unsafe.Pointer(&time)))
+ return &time
+}
+
+func SetSystemTime(time *SYSTEMTIME) bool {
+ ret, _, _ := procSetSystemTime.Call(
+ uintptr(unsafe.Pointer(time)))
+ return ret != 0
+}
+
+func GetLogicalDriveStrings(nBufferLength uint32, lpBuffer *uint16) uint32 {
+ ret, _, _ := procGetLogicalDriveStrings.Call(
+ uintptr(nBufferLength),
+ uintptr(unsafe.Pointer(lpBuffer)),
+ 0)
+
+ return uint32(ret)
+}
diff --git a/v3/pkg/w32/ole32.go b/v3/pkg/w32/ole32.go
new file mode 100644
index 000000000..004099316
--- /dev/null
+++ b/v3/pkg/w32/ole32.go
@@ -0,0 +1,65 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modole32 = syscall.NewLazyDLL("ole32.dll")
+
+ procCoInitializeEx = modole32.NewProc("CoInitializeEx")
+ procCoInitialize = modole32.NewProc("CoInitialize")
+ procCoUninitialize = modole32.NewProc("CoUninitialize")
+ procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
+)
+
+func CoInitializeEx(coInit uintptr) HRESULT {
+ ret, _, _ := procCoInitializeEx.Call(
+ 0,
+ coInit)
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CoInitializeEx failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CoInitializeEx failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CoInitializeEx failed with E_UNEXPECTED")
+ }
+
+ return HRESULT(ret)
+}
+
+func CoInitialize() {
+ procCoInitialize.Call(0)
+}
+
+func CoUninitialize() {
+ procCoUninitialize.Call()
+}
+
+func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
+ stream := new(IStream)
+ ret, _, _ := procCreateStreamOnHGlobal.Call(
+ uintptr(hGlobal),
+ uintptr(BoolToBOOL(fDeleteOnRelease)),
+ uintptr(unsafe.Pointer(&stream)))
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
+ }
+
+ return stream
+}
diff --git a/v3/pkg/w32/oleaut32.go b/v3/pkg/w32/oleaut32.go
new file mode 100644
index 000000000..0bb8ef7da
--- /dev/null
+++ b/v3/pkg/w32/oleaut32.go
@@ -0,0 +1,50 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modoleaut32 = syscall.NewLazyDLL("oleaut32")
+
+ procVariantInit = modoleaut32.NewProc("VariantInit")
+ procSysAllocString = modoleaut32.NewProc("SysAllocString")
+ procSysFreeString = modoleaut32.NewProc("SysFreeString")
+ procSysStringLen = modoleaut32.NewProc("SysStringLen")
+ procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
+ procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
+)
+
+func VariantInit(v *VARIANT) {
+ hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke VariantInit error.")
+ }
+ return
+}
+
+func SysAllocString(v string) (ss *int16) {
+ pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
+ ss = (*int16)(unsafe.Pointer(pss))
+ return
+}
+
+func SysFreeString(v *int16) {
+ hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke SysFreeString error.")
+ }
+ return
+}
+
+func SysStringLen(v *int16) uint {
+ l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
+ return uint(l)
+}
diff --git a/v2/internal/platform/win32/menu.go b/v3/pkg/w32/popupmenu.go
similarity index 62%
rename from v2/internal/platform/win32/menu.go
rename to v3/pkg/w32/popupmenu.go
index f05886414..267b3af44 100644
--- a/v2/internal/platform/win32/menu.go
+++ b/v3/pkg/w32/popupmenu.go
@@ -1,15 +1,8 @@
-//go:build windows
-
-package win32
+package w32
type Menu HMENU
type PopupMenu Menu
-func CreatePopupMenu() PopupMenu {
- ret, _, _ := procCreatePopupMenu.Call(0, 0, 0, 0)
- return PopupMenu(ret)
-}
-
func (m Menu) Destroy() bool {
ret, _, _ := procDestroyMenu.Call(uintptr(m))
return ret != 0
@@ -19,31 +12,22 @@ func (p PopupMenu) Destroy() bool {
return Menu(p).Destroy()
}
-func (p PopupMenu) Track(flags uint, x, y int, wnd HWND) bool {
- ret, _, _ := procTrackPopupMenu.Call(
- uintptr(p),
- uintptr(flags),
- uintptr(x),
- uintptr(y),
- 0,
- uintptr(wnd),
- 0,
- )
- return ret != 0
+func (p PopupMenu) Track(hwnd HWND, flags uint32, x, y int32) bool {
+ return TrackPopupMenuEx(
+ HMENU(p),
+ flags,
+ x,
+ y,
+ hwnd,
+ nil)
}
-func (p PopupMenu) Append(flags uintptr, id uintptr, text string) bool {
+func (p PopupMenu) Append(flags uint32, id uintptr, text string) bool {
return Menu(p).Append(flags, id, text)
}
-func (m Menu) Append(flags uintptr, id uintptr, text string) bool {
- ret, _, _ := procAppendMenuW.Call(
- uintptr(m),
- flags,
- id,
- MustStringToUTF16uintptr(text),
- )
- return ret != 0
+func (m Menu) Append(flags uint32, id uintptr, text string) bool {
+ return AppendMenu(HMENU(m), flags, id, MustStringToUTF16Ptr(text))
}
func (p PopupMenu) Check(id uintptr, checked bool) bool {
@@ -70,7 +54,7 @@ func (m Menu) CheckRadio(startID int, endID int, selectedID int) bool {
func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint {
ret, _, _ := procCheckMenuItem.Call(
- uintptr(menu),
+ menu,
id,
uintptr(flags),
)
@@ -80,3 +64,13 @@ func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint {
func (p PopupMenu) CheckRadio(startID, endID, selectedID int) bool {
return Menu(p).CheckRadio(startID, endID, selectedID)
}
+
+func NewMenu() HMENU {
+ ret, _, _ := procCreateMenu.Call()
+ return HMENU(ret)
+}
+
+func NewPopupMenu() HMENU {
+ ret, _, _ := procCreatePopupMenu.Call()
+ return ret
+}
diff --git a/v3/pkg/w32/screen.go b/v3/pkg/w32/screen.go
new file mode 100644
index 000000000..7f43beb2b
--- /dev/null
+++ b/v3/pkg/w32/screen.go
@@ -0,0 +1,118 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+func MonitorsEqual(first MONITORINFO, second MONITORINFO) bool {
+ // Checks to make sure all the fields are the same.
+ // A cleaner way would be to check identity of devices. but I couldn't find a way of doing that using the win32 API
+ return first.DwFlags == second.DwFlags &&
+ first.RcMonitor.Top == second.RcMonitor.Top &&
+ first.RcMonitor.Bottom == second.RcMonitor.Bottom &&
+ first.RcMonitor.Right == second.RcMonitor.Right &&
+ first.RcMonitor.Left == second.RcMonitor.Left &&
+ first.RcWork.Top == second.RcWork.Top &&
+ first.RcWork.Bottom == second.RcWork.Bottom &&
+ first.RcWork.Right == second.RcWork.Right &&
+ first.RcWork.Left == second.RcWork.Left
+}
+
+func GetMonitorInformation(hMonitor HMONITOR) (*MONITORINFO, error) {
+ // Adapted from winc.utils.getMonitorInfo
+ // See docs for
+ //https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmonitorinfoa
+
+ var info MONITORINFO
+ info.CbSize = uint32(unsafe.Sizeof(info))
+ succeeded := GetMonitorInfo(hMonitor, &info)
+ if !succeeded {
+ return &info, fmt.Errorf("Windows call to getMonitorInfo failed")
+ }
+ return &info, nil
+}
+
+type Screen struct {
+ IsCurrent bool
+ IsPrimary bool
+ Width int
+ Height int
+}
+
+func EnumProc(hMonitor HMONITOR, hdcMonitor HDC, lprcMonitor *RECT, screenContainer *ScreenContainer) uintptr {
+ // adapted from https://stackoverflow.com/a/23492886/4188138
+
+ // see docs for the following pages to better understand this function
+ // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors
+ // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-monitorenumproc
+ // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfo
+ // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow
+
+ ourMonitorData := Screen{}
+ currentMonHndl := MonitorFromWindow(screenContainer.mainWinHandle, MONITOR_DEFAULTTONEAREST)
+ currentMonInfo, currErr := GetMonitorInformation(currentMonHndl)
+
+ if currErr != nil {
+ screenContainer.errors = append(screenContainer.errors, currErr)
+ screenContainer.monitors = append(screenContainer.monitors, Screen{})
+ // not sure what the consequences of returning false are, so let's just return true and handle it ourselves
+ return TRUE
+ }
+
+ monInfo, err := GetMonitorInformation(hMonitor)
+ if err != nil {
+ screenContainer.errors = append(screenContainer.errors, err)
+ screenContainer.monitors = append(screenContainer.monitors, Screen{})
+ return TRUE
+ }
+
+ height := lprcMonitor.Right - lprcMonitor.Left
+ width := lprcMonitor.Bottom - lprcMonitor.Top
+ ourMonitorData.IsPrimary = monInfo.DwFlags&MONITORINFOF_PRIMARY == 1
+ ourMonitorData.Height = int(width)
+ ourMonitorData.Width = int(height)
+ ourMonitorData.IsCurrent = MonitorsEqual(*currentMonInfo, *monInfo)
+
+ // the reason we need a container is that we have don't know how many times this function will be called
+ // this "append" call could potentially do an allocation and rewrite the pointer to monitors. So we save the pointer in screenContainer.monitors
+ // and retrieve the values after all EnumProc calls
+ // If EnumProc is multi-threaded, this could be problematic. Although, I don't think it is.
+ screenContainer.monitors = append(screenContainer.monitors, ourMonitorData)
+ // let's keep screenContainer.errors the same size as screenContainer.monitors in case we want to match them up later if necessary
+ screenContainer.errors = append(screenContainer.errors, nil)
+ return TRUE
+}
+
+type ScreenContainer struct {
+ monitors []Screen
+ errors []error
+ mainWinHandle HWND
+}
+
+func GetAllScreens(mainWinHandle HWND) ([]Screen, error) {
+ // TODO fix hack of container sharing by having a proper data sharing mechanism between windows and the runtime
+ monitorContainer := ScreenContainer{mainWinHandle: mainWinHandle}
+ returnErr := error(nil)
+ var errorStrings []string
+
+ dc := GetDC(0)
+ defer ReleaseDC(0, dc)
+ succeeded := EnumDisplayMonitors(dc, nil, syscall.NewCallback(EnumProc), unsafe.Pointer(&monitorContainer))
+ if !succeeded {
+ return monitorContainer.monitors, fmt.Errorf("Windows call to EnumDisplayMonitors failed")
+ }
+ for idx, err := range monitorContainer.errors {
+ if err != nil {
+ errorStrings = append(errorStrings, fmt.Sprintf("Error from monitor #%v, %v", idx+1, err))
+ }
+ }
+
+ if len(errorStrings) > 0 {
+ returnErr = fmt.Errorf("%v errors encountered: %v", len(errorStrings), errorStrings)
+ }
+ return monitorContainer.monitors, returnErr
+}
diff --git a/v3/pkg/w32/shcore.go b/v3/pkg/w32/shcore.go
new file mode 100644
index 000000000..72e9aab3d
--- /dev/null
+++ b/v3/pkg/w32/shcore.go
@@ -0,0 +1,29 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modshcore = syscall.NewLazyDLL("shcore.dll")
+
+ procGetDpiForMonitor = modshcore.NewProc("GetDpiForMonitor")
+)
+
+func HasGetDPIForMonitorFunc() bool {
+ err := procGetDpiForMonitor.Find()
+ return err == nil
+}
+
+func GetDPIForMonitor(hmonitor HMONITOR, dpiType MONITOR_DPI_TYPE, dpiX *UINT, dpiY *UINT) uintptr {
+ ret, _, _ := procGetDpiForMonitor.Call(
+ hmonitor,
+ uintptr(dpiType),
+ uintptr(unsafe.Pointer(dpiX)),
+ uintptr(unsafe.Pointer(dpiY)))
+
+ return ret
+}
diff --git a/v3/pkg/w32/shell32.go b/v3/pkg/w32/shell32.go
new file mode 100644
index 000000000..3b6f3e30f
--- /dev/null
+++ b/v3/pkg/w32/shell32.go
@@ -0,0 +1,243 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+type CSIDL uint32
+
+const (
+ CSIDL_DESKTOP = 0x00
+ CSIDL_INTERNET = 0x01
+ CSIDL_PROGRAMS = 0x02
+ CSIDL_CONTROLS = 0x03
+ CSIDL_PRINTERS = 0x04
+ CSIDL_PERSONAL = 0x05
+ CSIDL_FAVORITES = 0x06
+ CSIDL_STARTUP = 0x07
+ CSIDL_RECENT = 0x08
+ CSIDL_SENDTO = 0x09
+ CSIDL_BITBUCKET = 0x0A
+ CSIDL_STARTMENU = 0x0B
+ CSIDL_MYDOCUMENTS = 0x0C
+ CSIDL_MYMUSIC = 0x0D
+ CSIDL_MYVIDEO = 0x0E
+ CSIDL_DESKTOPDIRECTORY = 0x10
+ CSIDL_DRIVES = 0x11
+ CSIDL_NETWORK = 0x12
+ CSIDL_NETHOOD = 0x13
+ CSIDL_FONTS = 0x14
+ CSIDL_TEMPLATES = 0x15
+ CSIDL_COMMON_STARTMENU = 0x16
+ CSIDL_COMMON_PROGRAMS = 0x17
+ CSIDL_COMMON_STARTUP = 0x18
+ CSIDL_COMMON_DESKTOPDIRECTORY = 0x19
+ CSIDL_APPDATA = 0x1A
+ CSIDL_PRINTHOOD = 0x1B
+ CSIDL_LOCAL_APPDATA = 0x1C
+ CSIDL_ALTSTARTUP = 0x1D
+ CSIDL_COMMON_ALTSTARTUP = 0x1E
+ CSIDL_COMMON_FAVORITES = 0x1F
+ CSIDL_INTERNET_CACHE = 0x20
+ CSIDL_COOKIES = 0x21
+ CSIDL_HISTORY = 0x22
+ CSIDL_COMMON_APPDATA = 0x23
+ CSIDL_WINDOWS = 0x24
+ CSIDL_SYSTEM = 0x25
+ CSIDL_PROGRAM_FILES = 0x26
+ CSIDL_MYPICTURES = 0x27
+ CSIDL_PROFILE = 0x28
+ CSIDL_SYSTEMX86 = 0x29
+ CSIDL_PROGRAM_FILESX86 = 0x2A
+ CSIDL_PROGRAM_FILES_COMMON = 0x2B
+ CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C
+ CSIDL_COMMON_TEMPLATES = 0x2D
+ CSIDL_COMMON_DOCUMENTS = 0x2E
+ CSIDL_COMMON_ADMINTOOLS = 0x2F
+ CSIDL_ADMINTOOLS = 0x30
+ CSIDL_CONNECTIONS = 0x31
+ CSIDL_COMMON_MUSIC = 0x35
+ CSIDL_COMMON_PICTURES = 0x36
+ CSIDL_COMMON_VIDEO = 0x37
+ CSIDL_RESOURCES = 0x38
+ CSIDL_RESOURCES_LOCALIZED = 0x39
+ CSIDL_COMMON_OEM_LINKS = 0x3A
+ CSIDL_CDBURN_AREA = 0x3B
+ CSIDL_COMPUTERSNEARME = 0x3D
+ CSIDL_FLAG_CREATE = 0x8000
+ CSIDL_FLAG_DONT_VERIFY = 0x4000
+ CSIDL_FLAG_NO_ALIAS = 0x1000
+ CSIDL_FLAG_PER_USER_INIT = 0x8000
+ CSIDL_FLAG_MASK = 0xFF00
+
+ NOTIFYICON_VERSION = 4
+)
+
+var (
+ modshell32 = syscall.NewLazyDLL("shell32.dll")
+
+ procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW")
+ procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW")
+ procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles")
+ procDragQueryFile = modshell32.NewProc("DragQueryFileW")
+ procDragQueryPoint = modshell32.NewProc("DragQueryPoint")
+ procDragFinish = modshell32.NewProc("DragFinish")
+ procShellExecute = modshell32.NewProc("ShellExecuteW")
+ procExtractIcon = modshell32.NewProc("ExtractIconW")
+ procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW")
+ procShellNotifyIcon = modshell32.NewProc("Shell_NotifyIconW")
+)
+
+func ShellNotifyIcon(cmd uintptr, nid *NOTIFYICONDATA) bool {
+ ret, _, _ := procShellNotifyIcon.Call(cmd, uintptr(unsafe.Pointer(nid)))
+ return ret == 1
+}
+
+func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
+ ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi)))
+
+ return ret
+}
+
+func SHGetPathFromIDList(idl uintptr) string {
+ buf := make([]uint16, 1024)
+ procSHGetPathFromIDList.Call(
+ idl,
+ uintptr(unsafe.Pointer(&buf[0])))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func DragAcceptFiles(hwnd HWND, accept bool) {
+ procDragAcceptFiles.Call(
+ uintptr(hwnd),
+ uintptr(BoolToBOOL(accept)))
+}
+
+func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) {
+ ret, _, _ := procDragQueryFile.Call(
+ uintptr(hDrop),
+ uintptr(iFile),
+ 0,
+ 0)
+
+ fileCount = uint(ret)
+
+ if iFile != 0xFFFFFFFF {
+ buf := make([]uint16, fileCount+1)
+
+ ret, _, _ := procDragQueryFile.Call(
+ uintptr(hDrop),
+ uintptr(iFile),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(fileCount+1))
+
+ if ret == 0 {
+ panic("Invoke DragQueryFile error.")
+ }
+
+ fileName = syscall.UTF16ToString(buf)
+ }
+
+ return
+}
+
+func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {
+ var pt POINT
+ ret, _, _ := procDragQueryPoint.Call(
+ uintptr(hDrop),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), (ret == 1)
+}
+
+func DragFinish(hDrop HDROP) {
+ procDragFinish.Call(uintptr(hDrop))
+}
+
+func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
+ var op, param, directory uintptr
+ if len(lpOperation) != 0 {
+ op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
+ }
+ if len(lpParameters) != 0 {
+ param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
+ }
+ if len(lpDirectory) != 0 {
+ directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
+ }
+
+ ret, _, _ := procShellExecute.Call(
+ uintptr(hwnd),
+ op,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
+ param,
+ directory,
+ uintptr(nShowCmd))
+
+ errorMsg := ""
+ if ret != 0 && ret <= 32 {
+ switch int(ret) {
+ case ERROR_FILE_NOT_FOUND:
+ errorMsg = "The specified file was not found."
+ case ERROR_PATH_NOT_FOUND:
+ errorMsg = "The specified path was not found."
+ case ERROR_BAD_FORMAT:
+ errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
+ case SE_ERR_ACCESSDENIED:
+ errorMsg = "The operating system denied access to the specified file."
+ case SE_ERR_ASSOCINCOMPLETE:
+ errorMsg = "The file name association is incomplete or invalid."
+ case SE_ERR_DDEBUSY:
+ errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
+ case SE_ERR_DDEFAIL:
+ errorMsg = "The DDE transaction failed."
+ case SE_ERR_DDETIMEOUT:
+ errorMsg = "The DDE transaction could not be completed because the request timed out."
+ case SE_ERR_DLLNOTFOUND:
+ errorMsg = "The specified DLL was not found."
+ case SE_ERR_NOASSOC:
+ errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
+ case SE_ERR_OOM:
+ errorMsg = "There was not enough memory to complete the operation."
+ case SE_ERR_SHARE:
+ errorMsg = "A sharing violation occurred."
+ default:
+ errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
+ }
+ } else {
+ return nil
+ }
+
+ return errors.New(errorMsg)
+}
+
+func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON {
+ ret, _, _ := procExtractIcon.Call(
+ 0,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))),
+ uintptr(nIconIndex))
+
+ return HICON(ret)
+}
+
+func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool {
+ ret, _, _ := procGetSpecialFolderPath.Call(
+ uintptr(hwndOwner),
+ uintptr(unsafe.Pointer(lpszPath)),
+ uintptr(csidl),
+ uintptr(BoolToBOOL(fCreate)),
+ 0,
+ 0)
+
+ return ret != 0
+}
diff --git a/v3/pkg/w32/shlwapi.go b/v3/pkg/w32/shlwapi.go
new file mode 100644
index 000000000..89d17ce6f
--- /dev/null
+++ b/v3/pkg/w32/shlwapi.go
@@ -0,0 +1,26 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modshlwapi = syscall.NewLazyDLL("shlwapi.dll")
+
+ procSHCreateMemStream = modshlwapi.NewProc("SHCreateMemStream")
+)
+
+func SHCreateMemStream(data []byte) (uintptr, error) {
+ ret, _, err := procSHCreateMemStream.Call(
+ uintptr(unsafe.Pointer(&data[0])),
+ uintptr(len(data)),
+ )
+ if ret == 0 {
+ return 0, err
+ }
+
+ return ret, nil
+}
diff --git a/v3/pkg/w32/theme.go b/v3/pkg/w32/theme.go
new file mode 100644
index 000000000..1b358789f
--- /dev/null
+++ b/v3/pkg/w32/theme.go
@@ -0,0 +1,119 @@
+//go:build windows
+
+package w32
+
+import (
+ "unsafe"
+
+ "golang.org/x/sys/windows/registry"
+)
+
+type DWMWINDOWATTRIBUTE int32
+
+const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19
+const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20
+const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34
+const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35
+const DwmwaTextColor DWMWINDOWATTRIBUTE = 36
+const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38
+
+const SPI_GETHIGHCONTRAST = 0x0042
+const HCF_HIGHCONTRASTON = 0x00000001
+
+// BackdropType defines the type of translucency we wish to use
+type BackdropType int32
+
+func dwmSetWindowAttribute(hwnd uintptr, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) {
+ ret, _, err := procDwmSetWindowAttribute.Call(
+ hwnd,
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ cbAttribute)
+ if ret != 0 {
+ _ = err
+ // println(err.Error())
+ }
+}
+
+func SupportsThemes() bool {
+ // We can't support Windows versions before 17763
+ return IsWindowsVersionAtLeast(10, 0, 17763)
+}
+
+func SupportsCustomThemes() bool {
+ return IsWindowsVersionAtLeast(10, 0, 17763)
+}
+
+func SupportsBackdropTypes() bool {
+ return IsWindowsVersionAtLeast(10, 0, 22621)
+}
+
+func SupportsImmersiveDarkMode() bool {
+ return IsWindowsVersionAtLeast(10, 0, 18985)
+}
+
+func SetTheme(hwnd uintptr, useDarkMode bool) {
+ if SupportsThemes() {
+ attr := DwmwaUseImmersiveDarkModeBefore20h1
+ if SupportsImmersiveDarkMode() {
+ attr = DwmwaUseImmersiveDarkMode
+ }
+ var winDark int32
+ if useDarkMode {
+ winDark = 1
+ }
+ dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark))
+ }
+}
+
+func EnableTranslucency(hwnd uintptr, backdrop BackdropType) {
+ if SupportsBackdropTypes() {
+ dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop))
+ } else {
+ println("Warning: Translucency type unavailable on Windows < 22621")
+ }
+}
+
+func SetTitleBarColour(hwnd uintptr, titleBarColour int32) {
+ dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour))
+}
+
+func SetTitleTextColour(hwnd uintptr, titleTextColour int32) {
+ dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour))
+}
+
+func SetBorderColour(hwnd uintptr, titleBorderColour int32) {
+ dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour))
+}
+
+func IsCurrentlyDarkMode() bool {
+ key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE)
+ if err != nil {
+ return false
+ }
+ defer key.Close()
+
+ AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme")
+ if err != nil {
+ return false
+ }
+ return AppsUseLightTheme == 0
+}
+
+type highContrast struct {
+ CbSize uint32
+ DwFlags uint32
+ LpszDefaultScheme *int16
+}
+
+func IsCurrentlyHighContrastMode() bool {
+ var result highContrast
+ result.CbSize = uint32(unsafe.Sizeof(result))
+ res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0)
+ if res == 0 {
+ _ = err
+ return false
+ }
+ r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON
+ return r
+}
diff --git a/v3/pkg/w32/toolbar.go b/v3/pkg/w32/toolbar.go
new file mode 100644
index 000000000..ac9261fc4
--- /dev/null
+++ b/v3/pkg/w32/toolbar.go
@@ -0,0 +1,216 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+// ToolBar messages
+const (
+ TB_ENABLEBUTTON = WM_USER + 1
+ TB_CHECKBUTTON = WM_USER + 2
+ TB_PRESSBUTTON = WM_USER + 3
+ TB_HIDEBUTTON = WM_USER + 4
+ TB_INDETERMINATE = WM_USER + 5
+ TB_MARKBUTTON = WM_USER + 6
+ TB_ISBUTTONENABLED = WM_USER + 9
+ TB_ISBUTTONCHECKED = WM_USER + 10
+ TB_ISBUTTONPRESSED = WM_USER + 11
+ TB_ISBUTTONHIDDEN = WM_USER + 12
+ TB_ISBUTTONINDETERMINATE = WM_USER + 13
+ TB_ISBUTTONHIGHLIGHTED = WM_USER + 14
+ TB_SETSTATE = WM_USER + 17
+ TB_GETSTATE = WM_USER + 18
+ TB_ADDBITMAP = WM_USER + 19
+ TB_DELETEBUTTON = WM_USER + 22
+ TB_GETBUTTON = WM_USER + 23
+ TB_BUTTONCOUNT = WM_USER + 24
+ TB_COMMANDTOINDEX = WM_USER + 25
+ TB_SAVERESTORE = WM_USER + 76
+ TB_CUSTOMIZE = WM_USER + 27
+ TB_ADDSTRING = WM_USER + 77
+ TB_GETITEMRECT = WM_USER + 29
+ TB_BUTTONSTRUCTSIZE = WM_USER + 30
+ TB_SETBUTTONSIZE = WM_USER + 31
+ TB_SETBITMAPSIZE = WM_USER + 32
+ TB_AUTOSIZE = WM_USER + 33
+ TB_GETTOOLTIPS = WM_USER + 35
+ TB_SETTOOLTIPS = WM_USER + 36
+ TB_SETPARENT = WM_USER + 37
+ TB_SETROWS = WM_USER + 39
+ TB_GETROWS = WM_USER + 40
+ TB_GETBITMAPFLAGS = WM_USER + 41
+ TB_SETCMDID = WM_USER + 42
+ TB_CHANGEBITMAP = WM_USER + 43
+ TB_GETBITMAP = WM_USER + 44
+ TB_GETBUTTONTEXT = WM_USER + 75
+ TB_REPLACEBITMAP = WM_USER + 46
+ TB_GETBUTTONSIZE = WM_USER + 58
+ TB_SETBUTTONWIDTH = WM_USER + 59
+ TB_SETINDENT = WM_USER + 47
+ TB_SETIMAGELIST = WM_USER + 48
+ TB_GETIMAGELIST = WM_USER + 49
+ TB_LOADIMAGES = WM_USER + 50
+ TB_GETRECT = WM_USER + 51
+ TB_SETHOTIMAGELIST = WM_USER + 52
+ TB_GETHOTIMAGELIST = WM_USER + 53
+ TB_SETDISABLEDIMAGELIST = WM_USER + 54
+ TB_GETDISABLEDIMAGELIST = WM_USER + 55
+ TB_SETSTYLE = WM_USER + 56
+ TB_GETSTYLE = WM_USER + 57
+ TB_SETMAXTEXTROWS = WM_USER + 60
+ TB_GETTEXTROWS = WM_USER + 61
+ TB_GETOBJECT = WM_USER + 62
+ TB_GETBUTTONINFO = WM_USER + 63
+ TB_SETBUTTONINFO = WM_USER + 64
+ TB_INSERTBUTTON = WM_USER + 67
+ TB_ADDBUTTONS = WM_USER + 68
+ TB_HITTEST = WM_USER + 69
+ TB_SETDRAWTEXTFLAGS = WM_USER + 70
+ TB_GETHOTITEM = WM_USER + 71
+ TB_SETHOTITEM = WM_USER + 72
+ TB_SETANCHORHIGHLIGHT = WM_USER + 73
+ TB_GETANCHORHIGHLIGHT = WM_USER + 74
+ TB_GETINSERTMARK = WM_USER + 79
+ TB_SETINSERTMARK = WM_USER + 80
+ TB_INSERTMARKHITTEST = WM_USER + 81
+ TB_MOVEBUTTON = WM_USER + 82
+ TB_GETMAXSIZE = WM_USER + 83
+ TB_SETEXTENDEDSTYLE = WM_USER + 84
+ TB_GETEXTENDEDSTYLE = WM_USER + 85
+ TB_GETPADDING = WM_USER + 86
+ TB_SETPADDING = WM_USER + 87
+ TB_SETINSERTMARKCOLOR = WM_USER + 88
+ TB_GETINSERTMARKCOLOR = WM_USER + 89
+ TB_MAPACCELERATOR = WM_USER + 90
+ TB_GETSTRING = WM_USER + 91
+ TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME
+ TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME
+ TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+)
+
+// ToolBar notifications
+const (
+ TBN_FIRST = -700
+ TBN_DROPDOWN = TBN_FIRST - 10
+)
+
+// TBN_DROPDOWN return codes
+const (
+ TBDDRET_DEFAULT = 0
+ TBDDRET_NODEFAULT = 1
+ TBDDRET_TREATPRESSED = 2
+)
+
+// ToolBar state constants
+const (
+ TBSTATE_CHECKED = 1
+ TBSTATE_PRESSED = 2
+ TBSTATE_ENABLED = 4
+ TBSTATE_HIDDEN = 8
+ TBSTATE_INDETERMINATE = 16
+ TBSTATE_WRAP = 32
+ TBSTATE_ELLIPSES = 0x40
+ TBSTATE_MARKED = 0x0080
+)
+
+// ToolBar style constants
+const (
+ TBSTYLE_BUTTON = 0
+ TBSTYLE_SEP = 1
+ TBSTYLE_CHECK = 2
+ TBSTYLE_GROUP = 4
+ TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK
+ TBSTYLE_DROPDOWN = 8
+ TBSTYLE_AUTOSIZE = 16
+ TBSTYLE_NOPREFIX = 32
+ TBSTYLE_TOOLTIPS = 256
+ TBSTYLE_WRAPABLE = 512
+ TBSTYLE_ALTDRAG = 1024
+ TBSTYLE_FLAT = 2048
+ TBSTYLE_LIST = 4096
+ TBSTYLE_CUSTOMERASE = 8192
+ TBSTYLE_REGISTERDROP = 0x4000
+ TBSTYLE_TRANSPARENT = 0x8000
+)
+
+// ToolBar extended style constants
+const (
+ TBSTYLE_EX_DRAWDDARROWS = 0x00000001
+ TBSTYLE_EX_MIXEDBUTTONS = 8
+ TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16
+ TBSTYLE_EX_DOUBLEBUFFER = 0x80
+)
+
+// ToolBar button style constants
+const (
+ BTNS_BUTTON = TBSTYLE_BUTTON
+ BTNS_SEP = TBSTYLE_SEP
+ BTNS_CHECK = TBSTYLE_CHECK
+ BTNS_GROUP = TBSTYLE_GROUP
+ BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP
+ BTNS_DROPDOWN = TBSTYLE_DROPDOWN
+ BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE
+ BTNS_NOPREFIX = TBSTYLE_NOPREFIX
+ BTNS_WHOLEDROPDOWN = 0x0080
+ BTNS_SHOWTEXT = 0x0040
+)
+
+// TBBUTTONINFO mask flags
+const (
+ TBIF_IMAGE = 0x00000001
+ TBIF_TEXT = 0x00000002
+ TBIF_STATE = 0x00000004
+ TBIF_STYLE = 0x00000008
+ TBIF_LPARAM = 0x00000010
+ TBIF_COMMAND = 0x00000020
+ TBIF_SIZE = 0x00000040
+ TBIF_BYINDEX = 0x80000000
+)
+
+type NMMOUSE struct {
+ Hdr NMHDR
+ DwItemSpec uintptr
+ DwItemData uintptr
+ Pt POINT
+ DwHitInfo uintptr
+}
+
+type NMTOOLBAR struct {
+ Hdr NMHDR
+ IItem int32
+ TbButton TBBUTTON
+ CchText int32
+ PszText *uint16
+ RcButton RECT
+}
+
+type TBBUTTON struct {
+ IBitmap int32
+ IdCommand int32
+ FsState byte
+ FsStyle byte
+ //#ifdef _WIN64
+ // BYTE bReserved[6] // padding for alignment
+ //#elif defined(_WIN32)
+ BReserved [2]byte // padding for alignment
+ //#endif
+ DwData uintptr
+ IString uintptr
+}
+
+type TBBUTTONINFO struct {
+ CbSize uint32
+ DwMask uint32
+ IdCommand int32
+ IImage int32
+ FsState byte
+ FsStyle byte
+ Cx uint16
+ LParam uintptr
+ PszText uintptr
+ CchText int32
+}
diff --git a/v3/pkg/w32/typedef.go b/v3/pkg/w32/typedef.go
new file mode 100644
index 000000000..219a7885f
--- /dev/null
+++ b/v3/pkg/w32/typedef.go
@@ -0,0 +1,1107 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "golang.org/x/sys/windows"
+ "unsafe"
+)
+
+// From MSDN: Windows Data Types
+// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
+// ATOM WORD
+// BOOL int32
+// BOOLEAN byte
+// BYTE byte
+// CCHAR int8
+// CHAR int8
+// COLORREF DWORD
+// DWORD uint32
+// DWORDLONG ULONGLONG
+// DWORD_PTR ULONG_PTR
+// DWORD32 uint32
+// DWORD64 uint64
+// FLOAT float32
+// HACCEL HANDLE
+// HALF_PTR struct{} // ???
+// HANDLE PVOID
+// HBITMAP HANDLE
+// HBRUSH HANDLE
+// HCOLORSPACE HANDLE
+// HCONV HANDLE
+// HCONVLIST HANDLE
+// HCURSOR HANDLE
+// HDC HANDLE
+// HDDEDATA HANDLE
+// HDESK HANDLE
+// HDROP HANDLE
+// HDWP HANDLE
+// HENHMETAFILE HANDLE
+// HFILE HANDLE
+// HFONT HANDLE
+// HGDIOBJ HANDLE
+// HGLOBAL HANDLE
+// HHOOK HANDLE
+// HICON HANDLE
+// HINSTANCE HANDLE
+// HKEY HANDLE
+// HKL HANDLE
+// HLOCAL HANDLE
+// HMENU HANDLE
+// HMETAFILE HANDLE
+// HMODULE HANDLE
+// HPALETTE HANDLE
+// HPEN HANDLE
+// HRESULT int32
+// HRGN HANDLE
+// HSZ HANDLE
+// HWINSTA HANDLE
+// HWND HANDLE
+// INT int32
+// INT_PTR uintptr
+// INT8 int8
+// INT16 int16
+// INT32 int32
+// INT64 int64
+// LANGID WORD
+// LCID DWORD
+// LCTYPE DWORD
+// LGRPID DWORD
+// LONG int32
+// LONGLONG int64
+// LONG_PTR uintptr
+// LONG32 int32
+// LONG64 int64
+// LPARAM LONG_PTR
+// LPBOOL *BOOL
+// LPBYTE *BYTE
+// LPCOLORREF *COLORREF
+// LPCSTR *int8
+// LPCTSTR LPCWSTR
+// LPCVOID unsafe.Pointer
+// LPCWSTR *WCHAR
+// LPDWORD *DWORD
+// LPHANDLE *HANDLE
+// LPINT *INT
+// LPLONG *LONG
+// LPSTR *CHAR
+// LPTSTR LPWSTR
+// LPVOID unsafe.Pointer
+// LPWORD *WORD
+// LPWSTR *WCHAR
+// LRESULT LONG_PTR
+// PBOOL *BOOL
+// PBOOLEAN *BOOLEAN
+// PBYTE *BYTE
+// PCHAR *CHAR
+// PCSTR *CHAR
+// PCTSTR PCWSTR
+// PCWSTR *WCHAR
+// PDWORD *DWORD
+// PDWORDLONG *DWORDLONG
+// PDWORD_PTR *DWORD_PTR
+// PDWORD32 *DWORD32
+// PDWORD64 *DWORD64
+// PFLOAT *FLOAT
+// PHALF_PTR *HALF_PTR
+// PHANDLE *HANDLE
+// PHKEY *HKEY
+// PINT_PTR *INT_PTR
+// PINT8 *INT8
+// PINT16 *INT16
+// PINT32 *INT32
+// PINT64 *INT64
+// PLCID *LCID
+// PLONG *LONG
+// PLONGLONG *LONGLONG
+// PLONG_PTR *LONG_PTR
+// PLONG32 *LONG32
+// PLONG64 *LONG64
+// POINTER_32 struct{} // ???
+// POINTER_64 struct{} // ???
+// POINTER_SIGNED uintptr
+// POINTER_UNSIGNED uintptr
+// PSHORT *SHORT
+// PSIZE_T *SIZE_T
+// PSSIZE_T *SSIZE_T
+// PSTR *CHAR
+// PTBYTE *TBYTE
+// PTCHAR *TCHAR
+// PTSTR PWSTR
+// PUCHAR *UCHAR
+// PUHALF_PTR *UHALF_PTR
+// PUINT *UINT
+// PUINT_PTR *UINT_PTR
+// PUINT8 *UINT8
+// PUINT16 *UINT16
+// PUINT32 *UINT32
+// PUINT64 *UINT64
+// PULONG *ULONG
+// PULONGLONG *ULONGLONG
+// PULONG_PTR *ULONG_PTR
+// PULONG32 *ULONG32
+// PULONG64 *ULONG64
+// PUSHORT *USHORT
+// PVOID unsafe.Pointer
+// PWCHAR *WCHAR
+// PWORD *WORD
+// PWSTR *WCHAR
+// QWORD uint64
+// SC_HANDLE HANDLE
+// SC_LOCK LPVOID
+// SERVICE_STATUS_HANDLE HANDLE
+// SHORT int16
+// SIZE_T ULONG_PTR
+// SSIZE_T LONG_PTR
+// TBYTE WCHAR
+// TCHAR WCHAR
+// UCHAR uint8
+// UHALF_PTR struct{} // ???
+// UINT uint32
+// UINT_PTR uintptr
+// UINT8 uint8
+// UINT16 uint16
+// UINT32 uint32
+// UINT64 uint64
+// ULONG uint32
+// ULONGLONG uint64
+// ULONG_PTR uintptr
+// ULONG32 uint32
+// ULONG64 uint64
+// USHORT uint16
+// USN LONGLONG
+// WCHAR uint16
+// WORD uint16
+// WPARAM UINT_PTR
+type (
+ ATOM = uint16
+ BOOL = int32
+ COLORREF = uint32
+ DWM_FRAME_COUNT = uint64
+ WORD = uint16
+ DWORD = uint32
+ HACCEL = HANDLE
+ HANDLE = uintptr
+ HBITMAP = HANDLE
+ HBRUSH = HANDLE
+ HCURSOR = HANDLE
+ HDC = HANDLE
+ HDROP = HANDLE
+ HDWP = HANDLE
+ HENHMETAFILE = HANDLE
+ HFONT = HANDLE
+ HGDIOBJ = HANDLE
+ HGLOBAL = HANDLE
+ HGLRC = HANDLE
+ HHOOK = HANDLE
+ HICON = HANDLE
+ HIMAGELIST = HANDLE
+ HINSTANCE = HANDLE
+ HKEY = HANDLE
+ HKL = HANDLE
+ HMENU = HANDLE
+ HMODULE = HANDLE
+ HMONITOR = HANDLE
+ HPEN = HANDLE
+ HRESULT = int32
+ HRGN = HANDLE
+ HRSRC = HANDLE
+ HTHUMBNAIL = HANDLE
+ HWND = HANDLE
+ LPARAM = uintptr
+ LPCVOID = unsafe.Pointer
+ LRESULT = uintptr
+ PVOID = unsafe.Pointer
+ QPC_TIME = uint64
+ ULONG_PTR = uintptr
+ SIZE_T = ULONG_PTR
+ WPARAM = uintptr
+ UINT = uint
+)
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx
+type POINT struct {
+ X, Y int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
+type RECT struct {
+ Left, Top, Right, Bottom int32
+}
+
+func (r *RECT) String() string {
+ return fmt.Sprintf("RECT (%p): Left: %d, Top: %d, Right: %d, Bottom: %d", r, r.Left, r.Top, r.Right, r.Bottom)
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx
+type WNDCLASSEX struct {
+ Size uint32
+ Style uint32
+ WndProc uintptr
+ ClsExtra int32
+ WndExtra int32
+ Instance HINSTANCE
+ Icon HICON
+ Cursor HCURSOR
+ Background HBRUSH
+ MenuName *uint16
+ ClassName *uint16
+ IconSm HICON
+}
+
+type TPMPARAMS struct {
+ CbSize uint32
+ RcExclude RECT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
+type MSG struct {
+ Hwnd HWND
+ Message uint32
+ WParam uintptr
+ LParam uintptr
+ Time uint32
+ Pt POINT
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-minmaxinfo
+type MINMAXINFO struct {
+ PtReserved POINT
+ PtMaxSize POINT
+ PtMaxPosition POINT
+ PtMinTrackSize POINT
+ PtMaxTrackSize POINT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx
+type LOGFONT struct {
+ Height int32
+ Width int32
+ Escapement int32
+ Orientation int32
+ Weight int32
+ Italic byte
+ Underline byte
+ StrikeOut byte
+ CharSet byte
+ OutPrecision byte
+ ClipPrecision byte
+ Quality byte
+ PitchAndFamily byte
+ FaceName [LF_FACESIZE]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx
+type OPENFILENAME struct {
+ StructSize uint32
+ Owner HWND
+ Instance HINSTANCE
+ Filter *uint16
+ CustomFilter *uint16
+ MaxCustomFilter uint32
+ FilterIndex uint32
+ File *uint16
+ MaxFile uint32
+ FileTitle *uint16
+ MaxFileTitle uint32
+ InitialDir *uint16
+ Title *uint16
+ Flags uint32
+ FileOffset uint16
+ FileExtension uint16
+ DefExt *uint16
+ CustData uintptr
+ FnHook uintptr
+ TemplateName *uint16
+ PvReserved unsafe.Pointer
+ DwReserved uint32
+ FlagsEx uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
+type BROWSEINFO struct {
+ Owner HWND
+ Root *uint16
+ DisplayName *uint16
+ Title *uint16
+ Flags uint32
+ CallbackFunc uintptr
+ LParam uintptr
+ Image int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
+type GUID struct {
+ Data1 uint32
+ Data2 uint16
+ Data3 uint16
+ Data4 [8]byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
+type VARIANT struct {
+ VT uint16 // 2
+ WReserved1 uint16 // 4
+ WReserved2 uint16 // 6
+ WReserved3 uint16 // 8
+ Val int64 // 16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx
+type DISPPARAMS struct {
+ Rgvarg uintptr
+ RgdispidNamedArgs uintptr
+ CArgs uint32
+ CNamedArgs uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx
+type EXCEPINFO struct {
+ WCode uint16
+ WReserved uint16
+ BstrSource *uint16
+ BstrDescription *uint16
+ BstrHelpFile *uint16
+ DwHelpContext uint32
+ PvReserved uintptr
+ PfnDeferredFillIn uintptr
+ Scode int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx
+type LOGBRUSH struct {
+ LbStyle uint32
+ LbColor COLORREF
+ LbHatch uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx
+type DEVMODE struct {
+ DmDeviceName [CCHDEVICENAME]uint16
+ DmSpecVersion uint16
+ DmDriverVersion uint16
+ DmSize uint16
+ DmDriverExtra uint16
+ DmFields uint32
+ DmOrientation int16
+ DmPaperSize int16
+ DmPaperLength int16
+ DmPaperWidth int16
+ DmScale int16
+ DmCopies int16
+ DmDefaultSource int16
+ DmPrintQuality int16
+ DmColor int16
+ DmDuplex int16
+ DmYResolution int16
+ DmTTOption int16
+ DmCollate int16
+ DmFormName [CCHFORMNAME]uint16
+ DmLogPixels uint16
+ DmBitsPerPel uint32
+ DmPelsWidth uint32
+ DmPelsHeight uint32
+ DmDisplayFlags uint32
+ DmDisplayFrequency uint32
+ DmICMMethod uint32
+ DmICMIntent uint32
+ DmMediaType uint32
+ DmDitherType uint32
+ DmReserved1 uint32
+ DmReserved2 uint32
+ DmPanningWidth uint32
+ DmPanningHeight uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
+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
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx
+type RGBQUAD struct {
+ RgbBlue byte
+ RgbGreen byte
+ RgbRed byte
+ RgbReserved byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx
+type BITMAPINFO struct {
+ BmiHeader BITMAPINFOHEADER
+ BmiColors *RGBQUAD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx
+type BITMAP struct {
+ BmType int32
+ BmWidth int32
+ BmHeight int32
+ BmWidthBytes int32
+ BmPlanes uint16
+ BmBitsPixel uint16
+ BmBits unsafe.Pointer
+}
+
+type BLENDFUNCTION struct {
+ BlendOp byte
+ BlendFlags byte
+ SourceConstantAlpha byte
+ AlphaFormat byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx
+type DIBSECTION struct {
+ DsBm BITMAP
+ DsBmih BITMAPINFOHEADER
+ DsBitfields [3]uint32
+ DshSection HANDLE
+ DsOffset uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx
+type ENHMETAHEADER struct {
+ IType uint32
+ NSize uint32
+ RclBounds RECT
+ RclFrame RECT
+ DSignature uint32
+ NVersion uint32
+ NBytes uint32
+ NRecords uint32
+ NHandles uint16
+ SReserved uint16
+ NDescription uint32
+ OffDescription uint32
+ NPalEntries uint32
+ SzlDevice SIZE
+ SzlMillimeters SIZE
+ CbPixelFormat uint32
+ OffPixelFormat uint32
+ BOpenGL uint32
+ SzlMicrometers SIZE
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx
+type SIZE struct {
+ CX, CY int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx
+type TEXTMETRIC struct {
+ TmHeight int32
+ TmAscent int32
+ TmDescent int32
+ TmInternalLeading int32
+ TmExternalLeading int32
+ TmAveCharWidth int32
+ TmMaxCharWidth int32
+ TmWeight int32
+ TmOverhang int32
+ TmDigitizedAspectX int32
+ TmDigitizedAspectY int32
+ TmFirstChar uint16
+ TmLastChar uint16
+ TmDefaultChar uint16
+ TmBreakChar uint16
+ TmItalic byte
+ TmUnderlined byte
+ TmStruckOut byte
+ TmPitchAndFamily byte
+ TmCharSet byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx
+type DOCINFO struct {
+ CbSize int32
+ LpszDocName *uint16
+ LpszOutput *uint16
+ LpszDatatype *uint16
+ FwType uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx
+type NMHDR struct {
+ HwndFrom HWND
+ IdFrom uintptr
+ Code uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx
+type LVCOLUMN struct {
+ Mask uint32
+ Fmt int32
+ Cx int32
+ PszText *uint16
+ CchTextMax int32
+ ISubItem int32
+ IImage int32
+ IOrder int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx
+type LVITEM struct {
+ Mask uint32
+ IItem int32
+ ISubItem int32
+ State uint32
+ StateMask uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+ LParam uintptr
+ IIndent int32
+ IGroupId int32
+ CColumns uint32
+ PuColumns uint32
+}
+
+type LVFINDINFO struct {
+ Flags uint32
+ PszText *uint16
+ LParam uintptr
+ Pt POINT
+ VkDirection uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx
+type LVHITTESTINFO struct {
+ Pt POINT
+ Flags uint32
+ IItem int32
+ ISubItem int32
+ IGroup int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx
+type NMITEMACTIVATE struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+ UKeyFlags uint32
+}
+
+type NMLVKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx
+type NMLISTVIEW struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx
+type NMLVDISPINFO struct {
+ Hdr NMHDR
+ Item LVITEM
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx
+type INITCOMMONCONTROLSEX struct {
+ DwSize uint32
+ DwICC uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx
+type TOOLINFO struct {
+ CbSize uint32
+ UFlags uint32
+ Hwnd HWND
+ UId uintptr
+ Rect RECT
+ Hinst HINSTANCE
+ LpszText *uint16
+ LParam uintptr
+ LpReserved unsafe.Pointer
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx
+type TRACKMOUSEEVENT struct {
+ CbSize uint32
+ DwFlags uint32
+ HwndTrack HWND
+ DwHoverTime uint32
+}
+
+type NOTIFYICONDATA struct {
+ CbSize uint32
+ HWnd HWND
+ UID uint32
+ UFlags uint32
+ UCallbackMessage uint32
+ HIcon HICON
+ SzTip [128]uint16
+ DwState uint32
+ DwStateMask uint32
+ SzInfo [256]uint16
+ UVersion uint32
+ SzInfoTitle [64]uint16
+ DwInfoFlags uint32
+ GuidItem windows.GUID
+ HBalloonIcon HICON
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx
+type GdiplusStartupInput struct {
+ GdiplusVersion uint32
+ DebugEventCallback uintptr
+ SuppressBackgroundThread BOOL
+ SuppressExternalCodecs BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx
+type GdiplusStartupOutput struct {
+ NotificationHook uintptr
+ NotificationUnhook uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx
+type PAINTSTRUCT struct {
+ Hdc HDC
+ FErase BOOL
+ RcPaint RECT
+ FRestore BOOL
+ FIncUpdate BOOL
+ RgbReserved [32]byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx
+type EVENTLOGRECORD struct {
+ Length uint32
+ Reserved uint32
+ RecordNumber uint32
+ TimeGenerated uint32
+ TimeWritten uint32
+ EventID uint32
+ EventType uint16
+ NumStrings uint16
+ EventCategory uint16
+ ReservedFlags uint16
+ ClosingRecordNumber uint32
+ StringOffset uint32
+ UserSidLength uint32
+ UserSidOffset uint32
+ DataLength uint32
+ DataOffset uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx
+type SERVICE_STATUS struct {
+ DwServiceType uint32
+ DwCurrentState uint32
+ DwControlsAccepted uint32
+ DwWin32ExitCode uint32
+ DwServiceSpecificExitCode uint32
+ DwCheckPoint uint32
+ DwWaitHint uint32
+}
+
+/* -------------------------
+ Undocumented API
+------------------------- */
+
+type ACCENT_STATE DWORD
+
+const (
+ ACCENT_DISABLED ACCENT_STATE = 0
+ ACCENT_ENABLE_GRADIENT ACCENT_STATE = 1
+ ACCENT_ENABLE_TRANSPARENTGRADIENT ACCENT_STATE = 2
+ ACCENT_ENABLE_BLURBEHIND ACCENT_STATE = 3
+ ACCENT_ENABLE_ACRYLICBLURBEHIND ACCENT_STATE = 4 // RS4 1803
+ ACCENT_ENABLE_HOSTBACKDROP ACCENT_STATE = 5 // RS5 1809
+ ACCENT_INVALID_STATE ACCENT_STATE = 6
+)
+
+type ACCENT_POLICY struct {
+ AccentState ACCENT_STATE
+ AccentFlags DWORD
+ GradientColor DWORD
+ AnimationId DWORD
+}
+
+type WINDOWCOMPOSITIONATTRIBDATA struct {
+ Attrib WINDOWCOMPOSITIONATTRIB
+ PvData PVOID
+ CbData SIZE_T
+}
+
+type WINDOWCOMPOSITIONATTRIB DWORD
+
+const (
+ WCA_UNDEFINED WINDOWCOMPOSITIONATTRIB = 0
+ WCA_NCRENDERING_ENABLED WINDOWCOMPOSITIONATTRIB = 1
+ WCA_NCRENDERING_POLICY WINDOWCOMPOSITIONATTRIB = 2
+ WCA_TRANSITIONS_FORCEDISABLED WINDOWCOMPOSITIONATTRIB = 3
+ WCA_ALLOW_NCPAINT WINDOWCOMPOSITIONATTRIB = 4
+ WCA_CAPTION_BUTTON_BOUNDS WINDOWCOMPOSITIONATTRIB = 5
+ WCA_NONCLIENT_RTL_LAYOUT WINDOWCOMPOSITIONATTRIB = 6
+ WCA_FORCE_ICONIC_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 7
+ WCA_EXTENDED_FRAME_BOUNDS WINDOWCOMPOSITIONATTRIB = 8
+ WCA_HAS_ICONIC_BITMAP WINDOWCOMPOSITIONATTRIB = 9
+ WCA_THEME_ATTRIBUTES WINDOWCOMPOSITIONATTRIB = 10
+ WCA_NCRENDERING_EXILED WINDOWCOMPOSITIONATTRIB = 11
+ WCA_NCADORNMENTINFO WINDOWCOMPOSITIONATTRIB = 12
+ WCA_EXCLUDED_FROM_LIVEPREVIEW WINDOWCOMPOSITIONATTRIB = 13
+ WCA_VIDEO_OVERLAY_ACTIVE WINDOWCOMPOSITIONATTRIB = 14
+ WCA_FORCE_ACTIVEWINDOW_APPEARANCE WINDOWCOMPOSITIONATTRIB = 15
+ WCA_DISALLOW_PEEK WINDOWCOMPOSITIONATTRIB = 16
+ WCA_CLOAK WINDOWCOMPOSITIONATTRIB = 17
+ WCA_CLOAKED WINDOWCOMPOSITIONATTRIB = 18
+ WCA_ACCENT_POLICY WINDOWCOMPOSITIONATTRIB = 19
+ WCA_FREEZE_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 20
+ WCA_EVER_UNCLOAKED WINDOWCOMPOSITIONATTRIB = 21
+ WCA_VISUAL_OWNER WINDOWCOMPOSITIONATTRIB = 22
+ WCA_HOLOGRAPHIC WINDOWCOMPOSITIONATTRIB = 23
+ WCA_EXCLUDED_FROM_DDA WINDOWCOMPOSITIONATTRIB = 24
+ WCA_PASSIVEUPDATEMODE WINDOWCOMPOSITIONATTRIB = 25
+ WCA_USEDARKMODECOLORS WINDOWCOMPOSITIONATTRIB = 26
+ WCA_CORNER_STYLE WINDOWCOMPOSITIONATTRIB = 27
+ WCA_PART_COLOR WINDOWCOMPOSITIONATTRIB = 28
+ WCA_DISABLE_MOVESIZE_FEEDBACK WINDOWCOMPOSITIONATTRIB = 29
+ WCA_LAST WINDOWCOMPOSITIONATTRIB = 30
+)
+
+// -------------------------
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx
+type MODULEENTRY32 struct {
+ Size uint32
+ ModuleID uint32
+ ProcessID uint32
+ GlblcntUsage uint32
+ ProccntUsage uint32
+ ModBaseAddr *uint8
+ ModBaseSize uint32
+ HModule HMODULE
+ SzModule [MAX_MODULE_NAME32 + 1]uint16
+ SzExePath [MAX_PATH]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+type FILETIME struct {
+ DwLowDateTime uint32
+ DwHighDateTime uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx
+type COORD struct {
+ X, Y int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx
+type SMALL_RECT struct {
+ Left, Top, Right, Bottom int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx
+type CONSOLE_SCREEN_BUFFER_INFO struct {
+ DwSize COORD
+ DwCursorPosition COORD
+ WAttributes uint16
+ SrWindow SMALL_RECT
+ DwMaximumWindowSize COORD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
+type MARGINS struct {
+ CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx
+type DWM_BLURBEHIND struct {
+ DwFlags uint32
+ fEnable BOOL
+ hRgnBlur HRGN
+ fTransitionOnMaximized BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx
+type DWM_PRESENT_PARAMETERS struct {
+ cbSize uint32
+ fQueue BOOL
+ cRefreshStart DWM_FRAME_COUNT
+ cBuffer uint32
+ fUseSourceRate BOOL
+ rateSource UNSIGNED_RATIO
+ cRefreshesPerFrame uint32
+ eSampling DWM_SOURCE_FRAME_SAMPLING
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx
+type DWM_THUMBNAIL_PROPERTIES struct {
+ dwFlags uint32
+ rcDestination RECT
+ rcSource RECT
+ opacity byte
+ fVisible BOOL
+ fSourceClientAreaOnly BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx
+type DWM_TIMING_INFO struct {
+ cbSize uint32
+ rateRefresh UNSIGNED_RATIO
+ qpcRefreshPeriod QPC_TIME
+ rateCompose UNSIGNED_RATIO
+ qpcVBlank QPC_TIME
+ cRefresh DWM_FRAME_COUNT
+ cDXRefresh uint32
+ qpcCompose QPC_TIME
+ cFrame DWM_FRAME_COUNT
+ cDXPresent uint32
+ cRefreshFrame DWM_FRAME_COUNT
+ cFrameSubmitted DWM_FRAME_COUNT
+ cDXPresentSubmitted uint32
+ cFrameConfirmed DWM_FRAME_COUNT
+ cDXPresentConfirmed uint32
+ cRefreshConfirmed DWM_FRAME_COUNT
+ cDXRefreshConfirmed uint32
+ cFramesLate DWM_FRAME_COUNT
+ cFramesOutstanding uint32
+ cFrameDisplayed DWM_FRAME_COUNT
+ qpcFrameDisplayed QPC_TIME
+ cRefreshFrameDisplayed DWM_FRAME_COUNT
+ cFrameComplete DWM_FRAME_COUNT
+ qpcFrameComplete QPC_TIME
+ cFramePending DWM_FRAME_COUNT
+ qpcFramePending QPC_TIME
+ cFramesDisplayed DWM_FRAME_COUNT
+ cFramesComplete DWM_FRAME_COUNT
+ cFramesPending DWM_FRAME_COUNT
+ cFramesAvailable DWM_FRAME_COUNT
+ cFramesDropped DWM_FRAME_COUNT
+ cFramesMissed DWM_FRAME_COUNT
+ cRefreshNextDisplayed DWM_FRAME_COUNT
+ cRefreshNextPresented DWM_FRAME_COUNT
+ cRefreshesDisplayed DWM_FRAME_COUNT
+ cRefreshesPresented DWM_FRAME_COUNT
+ cRefreshStarted DWM_FRAME_COUNT
+ cPixelsReceived uint64
+ cPixelsDrawn uint64
+ cBuffersEmpty DWM_FRAME_COUNT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx
+type MilMatrix3x2D struct {
+ S_11, S_12, S_21, S_22 float64
+ DX, DY float64
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx
+type UNSIGNED_RATIO struct {
+ uiNumerator uint32
+ uiDenominator uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx
+type CREATESTRUCT struct {
+ CreateParams uintptr
+ Instance HINSTANCE
+ Menu HMENU
+ Parent HWND
+ Cy, Cx int32
+ Y, X int32
+ Style int32
+ Name *uint16
+ Class *uint16
+ dwExStyle uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
+type MONITORINFO struct {
+ CbSize uint32
+ RcMonitor RECT
+ RcWork RECT
+ DwFlags uint32
+}
+
+type WINDOWINFO struct {
+ CbSize DWORD
+ RcWindow RECT
+ RcClient RECT
+ DwStyle DWORD
+ DwExStyle DWORD
+ DwWindowStatus DWORD
+ CxWindowBorders UINT
+ CyWindowBorders UINT
+ AtomWindowType ATOM
+ WCreatorVersion WORD
+}
+
+type MONITOR_DPI_TYPE int32
+
+const (
+ MDT_EFFECTIVE_DPI MONITOR_DPI_TYPE = 0
+ MDT_ANGULAR_DPI MONITOR_DPI_TYPE = 1
+ MDT_RAW_DPI MONITOR_DPI_TYPE = 2
+ MDT_DEFAULT MONITOR_DPI_TYPE = 0
+)
+
+func (w *WINDOWINFO) isStyle(style DWORD) bool {
+ return w.DwStyle&style == style
+}
+
+func (w *WINDOWINFO) IsPopup() bool {
+ return w.isStyle(WS_POPUP)
+}
+
+func (m *MONITORINFO) Dump() {
+ fmt.Printf("MONITORINFO (%p)\n", m)
+ fmt.Printf(" CbSize : %d\n", m.CbSize)
+ fmt.Printf(" RcMonitor: %s\n", &m.RcMonitor)
+ fmt.Printf(" RcWork : %s\n", &m.RcWork)
+ fmt.Printf(" DwFlags : %d\n", m.DwFlags)
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx
+type MONITORINFOEX struct {
+ MONITORINFO
+ SzDevice [CCHDEVICENAME]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx
+type PIXELFORMATDESCRIPTOR struct {
+ Size uint16
+ Version uint16
+ DwFlags uint32
+ IPixelType byte
+ ColorBits byte
+ RedBits, RedShift byte
+ GreenBits, GreenShift byte
+ BlueBits, BlueShift byte
+ AlphaBits, AlphaShift byte
+ AccumBits byte
+ AccumRedBits byte
+ AccumGreenBits byte
+ AccumBlueBits byte
+ AccumAlphaBits byte
+ DepthBits, StencilBits byte
+ AuxBuffers byte
+ ILayerType byte
+ Reserved byte
+ DwLayerMask uint32
+ DwVisibleMask uint32
+ DwDamageMask uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
+type INPUT struct {
+ Type uint32
+ Mi MOUSEINPUT
+ Ki KEYBDINPUT
+ Hi HARDWAREINPUT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
+type MOUSEINPUT struct {
+ Dx int32
+ Dy int32
+ MouseData uint32
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx
+type KEYBDINPUT struct {
+ WVk uint16
+ WScan uint16
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx
+type HARDWAREINPUT struct {
+ UMsg uint32
+ WParamL uint16
+ WParamH uint16
+}
+
+type KbdInput struct {
+ typ uint32
+ ki KEYBDINPUT
+}
+
+type MouseInput struct {
+ typ uint32
+ mi MOUSEINPUT
+}
+
+type HardwareInput struct {
+ typ uint32
+ hi HARDWAREINPUT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
+type SYSTEMTIME struct {
+ Year uint16
+ Month uint16
+ DayOfWeek uint16
+ Day uint16
+ Hour uint16
+ Minute uint16
+ Second uint16
+ Milliseconds uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx
+type KBDLLHOOKSTRUCT struct {
+ VkCode DWORD
+ ScanCode DWORD
+ Flags DWORD
+ Time DWORD
+ DwExtraInfo ULONG_PTR
+}
+
+type HOOKPROC func(int, WPARAM, LPARAM) LRESULT
+
+type WINDOWPLACEMENT struct {
+ Length uint32
+ Flags uint32
+ ShowCmd uint32
+ PtMinPosition POINT
+ PtMaxPosition POINT
+ RcNormalPosition RECT
+}
+
+type SCROLLINFO struct {
+ CbSize uint32
+ FMask uint32
+ NMin int32
+ NMax int32
+ NPage uint32
+ NPos int32
+ NTrackPos int32
+}
diff --git a/v3/pkg/w32/user32.go b/v3/pkg/w32/user32.go
new file mode 100644
index 000000000..bb293bc3f
--- /dev/null
+++ b/v3/pkg/w32/user32.go
@@ -0,0 +1,1328 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ moduser32 = syscall.NewLazyDLL("user32.dll")
+
+ procRegisterClassEx = moduser32.NewProc("RegisterClassExW")
+ procLoadIcon = moduser32.NewProc("LoadIconW")
+ procLoadCursor = moduser32.NewProc("LoadCursorW")
+ procShowWindow = moduser32.NewProc("ShowWindow")
+ procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow")
+ procShowWindowAsync = moduser32.NewProc("ShowWindowAsync")
+ procUpdateWindow = moduser32.NewProc("UpdateWindow")
+ procCreateWindowEx = moduser32.NewProc("CreateWindowExW")
+ procAdjustWindowRect = moduser32.NewProc("AdjustWindowRect")
+ procAdjustWindowRectEx = moduser32.NewProc("AdjustWindowRectEx")
+ procDestroyWindow = moduser32.NewProc("DestroyWindow")
+ procDefWindowProc = moduser32.NewProc("DefWindowProcW")
+ procDefDlgProc = moduser32.NewProc("DefDlgProcW")
+ procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
+ procGetMessage = moduser32.NewProc("GetMessageW")
+ procTranslateMessage = moduser32.NewProc("TranslateMessage")
+ procDispatchMessage = moduser32.NewProc("DispatchMessageW")
+ procSendMessage = moduser32.NewProc("SendMessageW")
+ procPostMessage = moduser32.NewProc("PostMessageW")
+ procWaitMessage = moduser32.NewProc("WaitMessage")
+ procSetWindowText = moduser32.NewProc("SetWindowTextW")
+ procGetWindowTextLength = moduser32.NewProc("GetWindowTextLengthW")
+ procGetWindowText = moduser32.NewProc("GetWindowTextW")
+ procGetWindowRect = moduser32.NewProc("GetWindowRect")
+ procGetWindowInfo = moduser32.NewProc("GetWindowInfo")
+ procGetWindow = moduser32.NewProc("GetWindow")
+ procSetWindowCompositionAttribute = moduser32.NewProc("SetWindowCompositionAttribute")
+ procMoveWindow = moduser32.NewProc("MoveWindow")
+ procScreenToClient = moduser32.NewProc("ScreenToClient")
+ procCallWindowProc = moduser32.NewProc("CallWindowProcW")
+ procSetWindowLong = moduser32.NewProc("SetWindowLongW")
+ procSetWindowLongPtr = moduser32.NewProc("SetWindowLongW")
+ procGetWindowLong = moduser32.NewProc("GetWindowLongW")
+ procGetWindowLongPtr = moduser32.NewProc("GetWindowLongW")
+ procEnableWindow = moduser32.NewProc("EnableWindow")
+ procIsWindowEnabled = moduser32.NewProc("IsWindowEnabled")
+ procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
+ procSetFocus = moduser32.NewProc("SetFocus")
+ procGetFocus = moduser32.NewProc("GetFocus")
+ procSetActiveWindow = moduser32.NewProc("SetActiveWindow")
+ procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow")
+ procBringWindowToTop = moduser32.NewProc("BringWindowToTop")
+ procInvalidateRect = moduser32.NewProc("InvalidateRect")
+ procGetClientRect = moduser32.NewProc("GetClientRect")
+ procGetDC = moduser32.NewProc("GetDC")
+ procReleaseDC = moduser32.NewProc("ReleaseDC")
+ procSetCapture = moduser32.NewProc("SetCapture")
+ procReleaseCapture = moduser32.NewProc("ReleaseCapture")
+ procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId")
+ procMessageBox = moduser32.NewProc("MessageBoxW")
+ procGetSystemMetrics = moduser32.NewProc("GetSystemMetrics")
+ procPostThreadMessageW = moduser32.NewProc("PostThreadMessageW")
+ procRegisterWindowMessageA = moduser32.NewProc("RegisterWindowMessageA")
+ procCopyRect = moduser32.NewProc("CopyRect")
+ procEqualRect = moduser32.NewProc("EqualRect")
+ procInflateRect = moduser32.NewProc("InflateRect")
+ procIntersectRect = moduser32.NewProc("IntersectRect")
+ procIsRectEmpty = moduser32.NewProc("IsRectEmpty")
+ procOffsetRect = moduser32.NewProc("OffsetRect")
+ procPtInRect = moduser32.NewProc("PtInRect")
+ procSetRect = moduser32.NewProc("SetRect")
+ procSetRectEmpty = moduser32.NewProc("SetRectEmpty")
+ procSubtractRect = moduser32.NewProc("SubtractRect")
+ procUnionRect = moduser32.NewProc("UnionRect")
+ procCreateDialogParam = moduser32.NewProc("CreateDialogParamW")
+ procDialogBoxParam = moduser32.NewProc("DialogBoxParamW")
+ procGetDlgItem = moduser32.NewProc("GetDlgItem")
+ procDrawIcon = moduser32.NewProc("DrawIcon")
+ procCreateMenu = moduser32.NewProc("CreateMenu")
+ procDestroyMenu = moduser32.NewProc("DestroyMenu")
+ procCreatePopupMenu = moduser32.NewProc("CreatePopupMenu")
+ procCheckMenuRadioItem = moduser32.NewProc("CheckMenuRadioItem")
+ procCreateIconFromResourceEx = moduser32.NewProc("CreateIconFromResourceEx")
+ procInsertMenuItem = moduser32.NewProc("InsertMenuItemW")
+ procCheckMenuItem = moduser32.NewProc("CheckMenuItem")
+ procClientToScreen = moduser32.NewProc("ClientToScreen")
+ procIsDialogMessage = moduser32.NewProc("IsDialogMessageW")
+ procIsWindow = moduser32.NewProc("IsWindow")
+ procEndDialog = moduser32.NewProc("EndDialog")
+ procPeekMessage = moduser32.NewProc("PeekMessageW")
+ procTranslateAccelerator = moduser32.NewProc("TranslateAcceleratorW")
+ procSetWindowPos = moduser32.NewProc("SetWindowPos")
+ procFillRect = moduser32.NewProc("FillRect")
+ procDrawText = moduser32.NewProc("DrawTextW")
+ procAddClipboardFormatListener = moduser32.NewProc("AddClipboardFormatListener")
+ procRemoveClipboardFormatListener = moduser32.NewProc("RemoveClipboardFormatListener")
+ procOpenClipboard = moduser32.NewProc("OpenClipboard")
+ procCloseClipboard = moduser32.NewProc("CloseClipboard")
+ procEnumClipboardFormats = moduser32.NewProc("EnumClipboardFormats")
+ procGetClipboardData = moduser32.NewProc("GetClipboardData")
+ procSetClipboardData = moduser32.NewProc("SetClipboardData")
+ procEmptyClipboard = moduser32.NewProc("EmptyClipboard")
+ procGetClipboardFormatName = moduser32.NewProc("GetClipboardFormatNameW")
+ procIsClipboardFormatAvailable = moduser32.NewProc("IsClipboardFormatAvailable")
+ procBeginPaint = moduser32.NewProc("BeginPaint")
+ procEndPaint = moduser32.NewProc("EndPaint")
+ procGetKeyboardState = moduser32.NewProc("GetKeyboardState")
+ procMapVirtualKey = moduser32.NewProc("MapVirtualKeyExW")
+ procGetAsyncKeyState = moduser32.NewProc("GetAsyncKeyState")
+ procToAscii = moduser32.NewProc("ToAscii")
+ procSwapMouseButton = moduser32.NewProc("SwapMouseButton")
+ procGetCursorPos = moduser32.NewProc("GetCursorPos")
+ procSetCursorPos = moduser32.NewProc("SetCursorPos")
+ procSetCursor = moduser32.NewProc("SetCursor")
+ procCreateIcon = moduser32.NewProc("CreateIcon")
+ procDestroyIcon = moduser32.NewProc("DestroyIcon")
+ procMonitorFromPoint = moduser32.NewProc("MonitorFromPoint")
+ procMonitorFromRect = moduser32.NewProc("MonitorFromRect")
+ procMonitorFromWindow = moduser32.NewProc("MonitorFromWindow")
+ procGetMonitorInfo = moduser32.NewProc("GetMonitorInfoW")
+ procGetDpiForSystem = moduser32.NewProc("GetDpiForSystem")
+ procGetDpiForWindow = moduser32.NewProc("GetDpiForWindow")
+ procSetProcessDPIAware = moduser32.NewProc("SetProcessDPIAware")
+ procEnumDisplayMonitors = moduser32.NewProc("EnumDisplayMonitors")
+ procEnumDisplaySettingsEx = moduser32.NewProc("EnumDisplaySettingsExW")
+ procChangeDisplaySettingsEx = moduser32.NewProc("ChangeDisplaySettingsExW")
+ procSendInput = moduser32.NewProc("SendInput")
+ procSetWindowsHookEx = moduser32.NewProc("SetWindowsHookExW")
+ procUnhookWindowsHookEx = moduser32.NewProc("UnhookWindowsHookEx")
+ procCallNextHookEx = moduser32.NewProc("CallNextHookEx")
+ procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow")
+ procUpdateLayeredWindow = moduser32.NewProc("UpdateLayeredWindow")
+
+ procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW")
+ procSetClassLong = moduser32.NewProc("SetClassLongW")
+ procSetClassLongPtr = moduser32.NewProc("SetClassLongPtrW")
+
+ procSetMenu = moduser32.NewProc("SetMenu")
+ procAppendMenu = moduser32.NewProc("AppendMenuW")
+ procSetMenuItemInfo = moduser32.NewProc("SetMenuItemInfoW")
+ procDrawMenuBar = moduser32.NewProc("DrawMenuBar")
+ procTrackPopupMenuEx = moduser32.NewProc("TrackPopupMenuEx")
+ procGetKeyState = moduser32.NewProc("GetKeyState")
+ procGetSysColorBrush = moduser32.NewProc("GetSysColorBrush")
+
+ procGetWindowPlacement = moduser32.NewProc("GetWindowPlacement")
+ procSetWindowPlacement = moduser32.NewProc("SetWindowPlacement")
+
+ procGetScrollInfo = moduser32.NewProc("GetScrollInfo")
+ procSetScrollInfo = moduser32.NewProc("SetScrollInfo")
+
+ mainThread HANDLE
+)
+
+func init() {
+ runtime.LockOSThread()
+ mainThread = GetCurrentThreadId()
+}
+
+func GET_X_LPARAM(lp uintptr) int32 {
+ return int32(int16(LOWORD(uint32(lp))))
+}
+
+func GET_Y_LPARAM(lp uintptr) int32 {
+ return int32(int16(HIWORD(uint32(lp))))
+}
+
+func RegisterClassEx(wndClassEx *WNDCLASSEX) ATOM {
+ ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx)))
+ return ATOM(ret)
+}
+
+func GetDesktopWindow() HWND {
+ ret, _, _ := procGetDesktopWindow.Call()
+ return ret
+}
+
+func LoadIcon(instance HINSTANCE, iconName *uint16) HICON {
+ ret, _, _ := procLoadIcon.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(iconName)))
+
+ return HICON(ret)
+}
+
+func LoadIconWithResourceID(instance HINSTANCE, res uint16) HICON {
+ ret, _, _ := procLoadIcon.Call(
+ uintptr(instance),
+ uintptr(res))
+
+ return HICON(ret)
+}
+
+func LoadCursor(instance HINSTANCE, cursorName *uint16) HCURSOR {
+ ret, _, _ := procLoadCursor.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(cursorName)))
+
+ return HCURSOR(ret)
+}
+
+func LoadCursorWithResourceID(instance HINSTANCE, res uint16) HCURSOR {
+ ret, _, _ := procLoadCursor.Call(
+ uintptr(instance),
+ uintptr(res))
+
+ return HCURSOR(ret)
+}
+
+func ShowWindow(hwnd HWND, cmdshow int) bool {
+ ret, _, _ := procShowWindow.Call(
+ uintptr(hwnd),
+ uintptr(cmdshow))
+
+ return ret != 0
+}
+
+func ShowWindowAsync(hwnd HWND, cmdshow int) bool {
+ ret, _, _ := procShowWindowAsync.Call(
+ uintptr(hwnd),
+ uintptr(cmdshow))
+
+ return ret != 0
+}
+
+func UpdateWindow(hwnd HWND) bool {
+ ret, _, _ := procUpdateWindow.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func UpdateLayeredWindow(hwnd HWND, hdcDst HDC, pptDst *POINT, psize *SIZE,
+ hdcSrc HDC, pptSrc *POINT, crKey COLORREF, pblend *BLENDFUNCTION, dwFlags DWORD) bool {
+ ret, _, _ := procUpdateLayeredWindow.Call(
+ hwnd,
+ hdcDst,
+ uintptr(unsafe.Pointer(pptDst)),
+ uintptr(unsafe.Pointer(psize)),
+ hdcSrc,
+ uintptr(unsafe.Pointer(pptSrc)),
+ uintptr(crKey),
+ uintptr(unsafe.Pointer(pblend)),
+ uintptr(dwFlags))
+ return ret != 0
+}
+
+func PostThreadMessage(threadID HANDLE, msg int, wp, lp uintptr) {
+ procPostThreadMessageW.Call(threadID, uintptr(msg), wp, lp)
+}
+
+func RegisterWindowMessage(name *uint16) uint32 {
+ ret, _, _ := procRegisterWindowMessageA.Call(
+ uintptr(unsafe.Pointer(name)))
+
+ return uint32(ret)
+}
+
+func PostMainThreadMessage(msg uint32, wp, lp uintptr) bool {
+ ret, _, _ := procPostThreadMessageW.Call(mainThread, uintptr(msg), wp, lp)
+ return ret != 0
+}
+
+func CreateWindowEx(exStyle uint, className, windowName *uint16,
+ style uint, x, y, width, height int, parent HWND, menu HMENU,
+ instance HINSTANCE, param unsafe.Pointer) HWND {
+ ret, _, _ := procCreateWindowEx.Call(
+ uintptr(exStyle),
+ uintptr(unsafe.Pointer(className)),
+ uintptr(unsafe.Pointer(windowName)),
+ uintptr(style),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(parent),
+ uintptr(menu),
+ uintptr(instance),
+ uintptr(param))
+
+ return HWND(ret)
+}
+
+func AdjustWindowRectEx(rect *RECT, style uint, menu bool, exStyle uint) bool {
+ ret, _, _ := procAdjustWindowRectEx.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)),
+ uintptr(exStyle))
+
+ return ret != 0
+}
+
+func AdjustWindowRect(rect *RECT, style uint, menu bool) bool {
+ ret, _, _ := procAdjustWindowRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)))
+
+ return ret != 0
+}
+
+func DestroyWindow(hwnd HWND) bool {
+ ret, _, _ := procDestroyWindow.Call(hwnd)
+ return ret != 0
+}
+
+func HasGetDpiForWindowFunc() bool {
+ err := procGetDpiForWindow.Find()
+ return err == nil
+}
+
+func GetDpiForWindow(hwnd HWND) UINT {
+ dpi, _, _ := procGetDpiForWindow.Call(hwnd)
+ return uint(dpi)
+}
+
+func SetProcessDPIAware() error {
+ status, r, err := procSetProcessDPIAware.Call()
+ if status == 0 {
+ return fmt.Errorf("SetProcessDPIAware failed %d: %v %v", status, r, err)
+ }
+ return nil
+}
+
+func GetForegroundWindow() HWND {
+ ret, _, _ := procGetForegroundWindow.Call()
+ return HWND(ret)
+}
+
+func SetWindowCompositionAttribute(hwnd HWND, data *WINDOWCOMPOSITIONATTRIBDATA) bool {
+ if procSetWindowCompositionAttribute != nil {
+ ret, _, _ := procSetWindowCompositionAttribute.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(data)),
+ )
+ return ret != 0
+ }
+ return false
+}
+
+func DefWindowProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefWindowProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func DefDlgProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefDlgProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostQuitMessage(exitCode int) {
+ procPostQuitMessage.Call(
+ uintptr(exitCode))
+}
+
+func GetMessage(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int {
+ ret, _, _ := procGetMessage.Call(
+ uintptr(unsafe.Pointer(msg)),
+ uintptr(hwnd),
+ uintptr(msgFilterMin),
+ uintptr(msgFilterMax))
+
+ return int(ret)
+}
+
+func TranslateMessage(msg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+
+}
+
+func DispatchMessage(msg *MSG) uintptr {
+ ret, _, _ := procDispatchMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret
+
+}
+
+func SendMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procSendMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) bool {
+ ret, _, _ := procPostMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret != 0
+}
+
+func WaitMessage() bool {
+ ret, _, _ := procWaitMessage.Call()
+ return ret != 0
+}
+
+func SetWindowText(hwnd HWND, text string) {
+ procSetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))))
+}
+
+func GetWindowTextLength(hwnd HWND) int {
+ ret, _, _ := procGetWindowTextLength.Call(
+ uintptr(hwnd))
+
+ return int(ret)
+}
+
+func GetWindowInfo(hwnd HWND, info *WINDOWINFO) int {
+ ret, _, _ := procGetWindowInfo.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(info)),
+ )
+ return int(ret)
+}
+
+func GetWindow(hwnd HWND, cmd uint32) HWND {
+ ret, _, _ := procGetWindow.Call(
+ hwnd,
+ uintptr(cmd),
+ )
+ return HWND(ret)
+}
+
+func GetWindowText(hwnd HWND) string {
+ textLen := GetWindowTextLength(hwnd) + 1
+
+ buf := make([]uint16, textLen)
+ procGetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(textLen))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func GetWindowRect(hwnd HWND) *RECT {
+ var rect RECT
+ procGetWindowRect.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(&rect)))
+
+ return &rect
+}
+
+func MoveWindow(hwnd HWND, x, y, width, height int, repaint bool) bool {
+ ret, _, _ := procMoveWindow.Call(
+ uintptr(hwnd),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(BoolToBOOL(repaint)))
+
+ return ret != 0
+
+}
+
+func ScreenToClient(hwnd HWND, x, y int) (X, Y int, ok bool) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procScreenToClient.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func CallWindowProc(preWndProc uintptr, hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procCallWindowProc.Call(
+ preWndProc,
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func SetWindowLong(hwnd HWND, index int, value uint32) uint32 {
+ ret, _, _ := procSetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ uintptr(value))
+
+ return uint32(ret)
+}
+
+func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
+ ret, _, _ := procSetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ value)
+
+ return ret
+}
+
+func GetWindowLong(hwnd HWND, index int) int32 {
+ ret, _, _ := procGetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return int32(ret)
+}
+
+func GetWindowLongPtr(hwnd HWND, index int) uintptr {
+ ret, _, _ := procGetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return ret
+}
+
+func EnableWindow(hwnd HWND, b bool) bool {
+ ret, _, _ := procEnableWindow.Call(
+ uintptr(hwnd),
+ uintptr(BoolToBOOL(b)))
+ return ret != 0
+}
+
+func IsWindowEnabled(hwnd HWND) bool {
+ ret, _, _ := procIsWindowEnabled.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func IsWindowVisible(hwnd HWND) bool {
+ ret, _, _ := procIsWindowVisible.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func SetFocus(hwnd HWND) HWND {
+ ret, _, _ := procSetFocus.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func SetActiveWindow(hwnd HWND) HWND {
+ ret, _, _ := procSetActiveWindow.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func BringWindowToTop(hwnd HWND) bool {
+ ret, _, _ := procBringWindowToTop.Call(uintptr(hwnd))
+ return ret != 0
+}
+
+func SetForegroundWindow(hwnd HWND) HWND {
+ ret, _, _ := procSetForegroundWindow.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func GetFocus() HWND {
+ ret, _, _ := procGetFocus.Call()
+ return HWND(ret)
+}
+
+func InvalidateRect(hwnd HWND, rect *RECT, erase bool) bool {
+ ret, _, _ := procInvalidateRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(BoolToBOOL(erase)))
+
+ return ret != 0
+}
+
+func GetClientRect(hwnd HWND) *RECT {
+ var rect RECT
+ ret, _, _ := procGetClientRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&rect)))
+
+ if ret == 0 {
+ panic(fmt.Sprintf("GetClientRect(%d) failed", hwnd))
+ }
+
+ return &rect
+}
+
+func GetDC(hwnd HWND) HDC {
+ ret, _, _ := procGetDC.Call(
+ uintptr(hwnd))
+
+ return HDC(ret)
+}
+
+func ReleaseDC(hwnd HWND, hDC HDC) bool {
+ ret, _, _ := procReleaseDC.Call(
+ uintptr(hwnd),
+ uintptr(hDC))
+
+ return ret != 0
+}
+
+func SetCapture(hwnd HWND) HWND {
+ ret, _, _ := procSetCapture.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func ReleaseCapture() bool {
+ ret, _, _ := procReleaseCapture.Call()
+
+ return ret != 0
+}
+
+func GetWindowThreadProcessId(hwnd HWND) (HANDLE, int) {
+ var processId int
+ ret, _, _ := procGetWindowThreadProcessId.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&processId)))
+
+ return HANDLE(ret), processId
+}
+
+func MessageBox(hwnd HWND, title, caption string, flags uint) int {
+ ret, _, _ := procMessageBox.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
+ uintptr(flags))
+
+ return int(ret)
+}
+
+func GetSystemMetrics(index int) int {
+ ret, _, _ := procGetSystemMetrics.Call(
+ uintptr(index))
+
+ return int(ret)
+}
+
+func GetSysColorBrush(nIndex int) HBRUSH {
+ ret, _, _ := procGetSysColorBrush.Call(1,
+ uintptr(nIndex),
+ 0,
+ 0)
+
+ return HBRUSH(ret)
+}
+
+func CopyRect(dst, src *RECT) bool {
+ ret, _, _ := procCopyRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src)))
+
+ return ret != 0
+}
+
+func EqualRect(rect1, rect2 *RECT) bool {
+ ret, _, _ := procEqualRect.Call(
+ uintptr(unsafe.Pointer(rect1)),
+ uintptr(unsafe.Pointer(rect2)))
+
+ return ret != 0
+}
+
+func InflateRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procInflateRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func IntersectRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procIntersectRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func IsRectEmpty(rect *RECT) bool {
+ ret, _, _ := procIsRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func OffsetRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procOffsetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func PtInRect(rect *RECT, x, y int) bool {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procPtInRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return ret != 0
+}
+
+func SetRect(rect *RECT, left, top, right, bottom int) bool {
+ ret, _, _ := procSetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(left),
+ uintptr(top),
+ uintptr(right),
+ uintptr(bottom))
+
+ return ret != 0
+}
+
+func SetRectEmpty(rect *RECT) bool {
+ ret, _, _ := procSetRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func SubtractRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procSubtractRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func UnionRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procUnionRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func CreateDialog(hInstance HINSTANCE, lpTemplate *uint16, hWndParent HWND, lpDialogProc uintptr) HWND {
+ ret, _, _ := procCreateDialogParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplate)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return HWND(ret)
+}
+
+func DialogBox(hInstance HINSTANCE, lpTemplateName *uint16, hWndParent HWND, lpDialogProc uintptr) int {
+ ret, _, _ := procDialogBoxParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplateName)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return int(ret)
+}
+
+func GetDlgItem(hDlg HWND, nIDDlgItem int) HWND {
+ ret, _, _ := procGetDlgItem.Call(
+ uintptr(unsafe.Pointer(hDlg)),
+ uintptr(nIDDlgItem))
+
+ return HWND(ret)
+}
+
+func DrawIcon(hDC HDC, x, y int, hIcon HICON) bool {
+ ret, _, _ := procDrawIcon.Call(
+ uintptr(unsafe.Pointer(hDC)),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(hIcon)))
+
+ return ret != 0
+}
+
+func CreateMenu() HMENU {
+ ret, _, _ := procCreateMenu.Call(0,
+ 0,
+ 0,
+ 0)
+
+ return HMENU(ret)
+}
+
+func SetMenu(hWnd HWND, hMenu HMENU) bool {
+
+ ret, _, _ := procSetMenu.Call(hWnd, hMenu)
+ return ret != 0
+}
+
+func AppendMenu(hMenu HMENU, uFlags uint32, uIDNewItem uintptr, lpNewItem *uint16) bool {
+ ret, _, _ := procAppendMenu.Call(
+ hMenu,
+ uintptr(uFlags),
+ uIDNewItem,
+ uintptr(unsafe.Pointer(lpNewItem)))
+
+ return ret != 0
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-checkmenuradioitem
+func SelectRadioMenuItem(menuID uint16, startID uint16, endID uint16, hwnd HWND) bool {
+ ret, _, _ := procCheckMenuRadioItem.Call(
+ hwnd,
+ uintptr(startID),
+ uintptr(endID),
+ uintptr(menuID),
+ MF_BYCOMMAND)
+ return ret != 0
+
+}
+
+func CreatePopupMenu() PopupMenu {
+ ret, _, _ := procCreatePopupMenu.Call(0,
+ 0,
+ 0,
+ 0)
+
+ return PopupMenu(ret)
+}
+
+func TrackPopupMenuEx(hMenu HMENU, fuFlags uint32, x, y int32, hWnd HWND, lptpm *TPMPARAMS) bool {
+
+ ret, _, _ := procTrackPopupMenuEx.Call(
+ hMenu,
+ uintptr(fuFlags),
+ uintptr(x),
+ uintptr(y),
+ hWnd,
+ uintptr(unsafe.Pointer(lptpm)))
+
+ return ret != 0
+}
+
+func DrawMenuBar(hWnd HWND) bool {
+ ret, _, _ := procDrawMenuBar.Call(hWnd, 0, 0)
+ return ret != 0
+}
+
+func InsertMenuItem(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool {
+ ret, _, _ := procInsertMenuItem.Call(
+ hMenu,
+ uintptr(uItem),
+ uintptr(BoolToBOOL(fByPosition)),
+ uintptr(unsafe.Pointer(lpmii)),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func SetMenuItemInfo(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool {
+ ret, _, _ := procSetMenuItemInfo.Call(
+ hMenu,
+ uintptr(uItem),
+ uintptr(BoolToBOOL(fByPosition)),
+ uintptr(unsafe.Pointer(lpmii)),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func ClientToScreen(hwnd HWND, x, y int) (int, int) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+
+ procClientToScreen.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y)
+}
+
+func IsDialogMessage(hwnd HWND, msg *MSG) bool {
+ ret, _, _ := procIsDialogMessage.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+}
+
+func IsWindow(hwnd HWND) bool {
+ ret, _, _ := procIsWindow.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func EndDialog(hwnd HWND, nResult uintptr) bool {
+ ret, _, _ := procEndDialog.Call(
+ uintptr(hwnd),
+ nResult)
+
+ return ret != 0
+}
+
+func PeekMessage(lpMsg *MSG, hwnd HWND, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
+ ret, _, _ := procPeekMessage.Call(
+ uintptr(unsafe.Pointer(lpMsg)),
+ uintptr(hwnd),
+ uintptr(wMsgFilterMin),
+ uintptr(wMsgFilterMax),
+ uintptr(wRemoveMsg))
+
+ return ret != 0
+}
+
+func TranslateAccelerator(hwnd HWND, hAccTable HACCEL, lpMsg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(hwnd),
+ uintptr(hAccTable),
+ uintptr(unsafe.Pointer(lpMsg)))
+
+ return ret != 0
+}
+
+func SetWindowPos(hwnd, hWndInsertAfter HWND, x, y, cx, cy int, uFlags uint) bool {
+ ret, _, _ := procSetWindowPos.Call(
+ uintptr(hwnd),
+ uintptr(hWndInsertAfter),
+ uintptr(x),
+ uintptr(y),
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(uFlags))
+
+ return ret != 0
+}
+
+func FillRect(hDC HDC, lprc *RECT, hbr HBRUSH) bool {
+ ret, _, _ := procFillRect.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(lprc)),
+ uintptr(hbr))
+
+ return ret != 0
+}
+
+func DrawText(hDC HDC, text string, uCount int, lpRect *RECT, uFormat uint) int {
+ ret, _, _ := procDrawText.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
+ uintptr(uCount),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(uFormat))
+
+ return int(ret)
+}
+
+func AddClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procAddClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func RemoveClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procRemoveClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func OpenClipboard(hWndNewOwner HWND) bool {
+ ret, _, _ := procOpenClipboard.Call(
+ uintptr(hWndNewOwner))
+ return ret != 0
+}
+
+func CloseClipboard() bool {
+ ret, _, _ := procCloseClipboard.Call()
+ return ret != 0
+}
+
+func EnumClipboardFormats(format uint) uint {
+ ret, _, _ := procEnumClipboardFormats.Call(
+ uintptr(format))
+ return uint(ret)
+}
+
+func GetClipboardData(uFormat uint) HANDLE {
+ ret, _, _ := procGetClipboardData.Call(
+ uintptr(uFormat))
+ return HANDLE(ret)
+}
+
+func SetClipboardData(uFormat uint, hMem HANDLE) HANDLE {
+ ret, _, _ := procSetClipboardData.Call(
+ uintptr(uFormat),
+ uintptr(hMem))
+ return HANDLE(ret)
+}
+
+func EmptyClipboard() bool {
+ ret, _, _ := procEmptyClipboard.Call()
+ return ret != 0
+}
+
+func GetClipboardFormatName(format uint) (string, bool) {
+ cchMaxCount := 255
+ buf := make([]uint16, cchMaxCount)
+ ret, _, _ := procGetClipboardFormatName.Call(
+ uintptr(format),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(cchMaxCount))
+
+ if ret > 0 {
+ return syscall.UTF16ToString(buf), true
+ }
+
+ return "Requested format does not exist or is predefined", false
+}
+
+func IsClipboardFormatAvailable(format uint) bool {
+ ret, _, _ := procIsClipboardFormatAvailable.Call(uintptr(format))
+ return ret != 0
+}
+
+func BeginPaint(hwnd HWND, paint *PAINTSTRUCT) HDC {
+ ret, _, _ := procBeginPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+ return HDC(ret)
+}
+
+func EndPaint(hwnd HWND, paint *PAINTSTRUCT) {
+ procEndPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+}
+
+func GetKeyboardState(lpKeyState *[]byte) bool {
+ ret, _, _ := procGetKeyboardState.Call(
+ uintptr(unsafe.Pointer(&(*lpKeyState)[0])))
+ return ret != 0
+}
+
+func MapVirtualKeyEx(uCode, uMapType uint, dwhkl HKL) uint {
+ ret, _, _ := procMapVirtualKey.Call(
+ uintptr(uCode),
+ uintptr(uMapType),
+ uintptr(dwhkl))
+ return uint(ret)
+}
+
+func GetAsyncKeyState(vKey int) uint16 {
+ ret, _, _ := procGetAsyncKeyState.Call(uintptr(vKey))
+ return uint16(ret)
+}
+
+func ToAscii(uVirtKey, uScanCode uint, lpKeyState *byte, lpChar *uint16, uFlags uint) int {
+ ret, _, _ := procToAscii.Call(
+ uintptr(uVirtKey),
+ uintptr(uScanCode),
+ uintptr(unsafe.Pointer(lpKeyState)),
+ uintptr(unsafe.Pointer(lpChar)),
+ uintptr(uFlags))
+ return int(ret)
+}
+
+func SwapMouseButton(fSwap bool) bool {
+ ret, _, _ := procSwapMouseButton.Call(
+ uintptr(BoolToBOOL(fSwap)))
+ return ret != 0
+}
+
+func GetCursorPos() (x, y int, ok bool) {
+ pt := POINT{}
+ ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func SetCursorPos(x, y int) bool {
+ ret, _, _ := procSetCursorPos.Call(
+ uintptr(x),
+ uintptr(y),
+ )
+ return ret != 0
+}
+
+func SetCursor(cursor HCURSOR) HCURSOR {
+ ret, _, _ := procSetCursor.Call(
+ uintptr(cursor),
+ )
+ return HCURSOR(ret)
+}
+
+func CreateIcon(instance HINSTANCE, nWidth, nHeight int, cPlanes, cBitsPerPixel byte, ANDbits, XORbits *byte) HICON {
+ ret, _, _ := procCreateIcon.Call(
+ uintptr(instance),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(cPlanes),
+ uintptr(cBitsPerPixel),
+ uintptr(unsafe.Pointer(ANDbits)),
+ uintptr(unsafe.Pointer(XORbits)),
+ )
+ return HICON(ret)
+}
+
+func DestroyIcon(icon HICON) bool {
+ ret, _, _ := procDestroyIcon.Call(
+ uintptr(icon),
+ )
+ return ret != 0
+}
+
+func MonitorFromPoint(x, y int, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromPoint.Call(
+ uintptr(x),
+ uintptr(y),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromRect(rc *RECT, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromRect.Call(
+ uintptr(unsafe.Pointer(rc)),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromWindow(hwnd HWND, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromWindow.Call(
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool {
+ ret, _, _ := procGetMonitorInfo.Call(
+ uintptr(hMonitor),
+ uintptr(unsafe.Pointer(lmpi)),
+ )
+ return ret != 0
+}
+
+func GetMonitorInfoEx(hMonitor HMONITOR, lmpi *MONITORINFOEX) bool {
+ ret, _, _ := procGetMonitorInfo.Call(
+ uintptr(hMonitor),
+ uintptr(unsafe.Pointer(lmpi)),
+ )
+ return ret != 0
+}
+
+func EnumDisplayMonitors(hdc HDC, clip *RECT, fnEnum uintptr, dwData unsafe.Pointer) bool {
+ ret, _, _ := procEnumDisplayMonitors.Call(
+ hdc,
+ uintptr(unsafe.Pointer(clip)),
+ fnEnum,
+ uintptr(dwData),
+ )
+ return ret != 0
+}
+
+func EnumDisplaySettingsEx(szDeviceName *uint16, iModeNum uint32, devMode *DEVMODE, dwFlags uint32) bool {
+ ret, _, _ := procEnumDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(iModeNum),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(dwFlags),
+ )
+ return ret != 0
+}
+
+func ChangeDisplaySettingsEx(szDeviceName *uint16, devMode *DEVMODE, hwnd HWND, dwFlags uint32, lParam uintptr) int32 {
+ ret, _, _ := procChangeDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ lParam,
+ )
+ return int32(ret)
+}
+
+/*
+func SendInput(inputs []INPUT) uint32 {
+ var validInputs []C.INPUT
+
+ for _, oneInput := range inputs {
+ input := C.INPUT{_type: C.DWORD(oneInput.Type)}
+
+ switch oneInput.Type {
+ case INPUT_MOUSE:
+ (*MouseInput)(unsafe.Pointer(&input)).mi = oneInput.Mi
+ case INPUT_KEYBOARD:
+ (*KbdInput)(unsafe.Pointer(&input)).ki = oneInput.Ki
+ case INPUT_HARDWARE:
+ (*HardwareInput)(unsafe.Pointer(&input)).hi = oneInput.Hi
+ default:
+ panic("unkown type")
+ }
+
+ validInputs = append(validInputs, input)
+ }
+
+ ret, _, _ := procSendInput.Call(
+ uintptr(len(validInputs)),
+ uintptr(unsafe.Pointer(&validInputs[0])),
+ uintptr(unsafe.Sizeof(C.INPUT{})),
+ )
+ return uint32(ret)
+}*/
+
+func SetWindowsHookEx(idHook int, lpfn HOOKPROC, hMod HINSTANCE, dwThreadId DWORD) HHOOK {
+ ret, _, _ := procSetWindowsHookEx.Call(
+ uintptr(idHook),
+ uintptr(syscall.NewCallback(lpfn)),
+ uintptr(hMod),
+ uintptr(dwThreadId),
+ )
+ return HHOOK(ret)
+}
+
+func UnhookWindowsHookEx(hhk HHOOK) bool {
+ ret, _, _ := procUnhookWindowsHookEx.Call(
+ uintptr(hhk),
+ )
+ return ret != 0
+}
+
+func CallNextHookEx(hhk HHOOK, nCode int, wParam WPARAM, lParam LPARAM) LRESULT {
+ ret, _, _ := procCallNextHookEx.Call(
+ uintptr(hhk),
+ uintptr(nCode),
+ uintptr(wParam),
+ uintptr(lParam),
+ )
+ return LRESULT(ret)
+}
+
+func GetKeyState(nVirtKey int32) int16 {
+ ret, _, _ := procGetKeyState.Call(
+ uintptr(nVirtKey),
+ 0,
+ 0)
+
+ return int16(ret)
+}
+
+func DestroyMenu(hMenu HMENU) bool {
+ ret, _, _ := procDestroyMenu.Call(1,
+ uintptr(hMenu),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func GetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool {
+ ret, _, _ := procGetWindowPlacement.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(lpwndpl)),
+ 0)
+
+ return ret != 0
+}
+
+func SetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool {
+ ret, _, _ := procSetWindowPlacement.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(lpwndpl)),
+ 0)
+
+ return ret != 0
+}
+
+func SetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO, fRedraw bool) int32 {
+ ret, _, _ := procSetScrollInfo.Call(
+ hwnd,
+ uintptr(fnBar),
+ uintptr(unsafe.Pointer(lpsi)),
+ uintptr(BoolToBOOL(fRedraw)),
+ 0,
+ 0)
+
+ return int32(ret)
+}
+
+func GetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO) bool {
+ ret, _, _ := procGetScrollInfo.Call(
+ hwnd,
+ uintptr(fnBar),
+ uintptr(unsafe.Pointer(lpsi)))
+
+ return ret != 0
+}
diff --git a/v3/pkg/w32/utils.go b/v3/pkg/w32/utils.go
new file mode 100644
index 000000000..fb6612e21
--- /dev/null
+++ b/v3/pkg/w32/utils.go
@@ -0,0 +1,648 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "os"
+ "runtime/debug"
+ "strconv"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+func MustLoadLibrary(name string) uintptr {
+ lib, err := syscall.LoadLibrary(name)
+ if err != nil {
+ panic(err)
+ }
+
+ return uintptr(lib)
+}
+
+func MustGetProcAddress(lib uintptr, name string) uintptr {
+ addr, err := syscall.GetProcAddress(syscall.Handle(lib), name)
+ if err != nil {
+ panic(err)
+ }
+
+ return uintptr(addr)
+}
+
+func SUCCEEDED(hr HRESULT) bool {
+ return hr >= 0
+}
+
+func FAILED(hr HRESULT) bool {
+ return hr < 0
+}
+
+func LOWORD(dw uint32) uint16 {
+ return uint16(dw)
+}
+
+func HIWORD(dw uint32) uint16 {
+ return uint16(dw >> 16 & 0xffff)
+}
+
+func MAKELONG(lo, hi uint16) uint32 {
+ return uint32(uint32(lo) | ((uint32(hi)) << 16))
+}
+
+func BoolToBOOL(value bool) BOOL {
+ if value {
+ return 1
+ }
+
+ return 0
+}
+
+func UTF16PtrToString(cstr *uint16) string {
+ if cstr != nil {
+ us := make([]uint16, 0, 256)
+ for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
+ u := *(*uint16)(unsafe.Pointer(p))
+ if u == 0 {
+ return string(utf16.Decode(us))
+ }
+ us = append(us, u)
+ }
+ }
+
+ return ""
+}
+
+func ComAddRef(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1,
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComRelease(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1,
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
+ var disp *IDispatch
+ hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3,
+ uintptr(unsafe.Pointer(unknown)),
+ uintptr(unsafe.Pointer(id)),
+ uintptr(unsafe.Pointer(&disp)))
+ if hr != 0 {
+ panic("Invoke QieryInterface error.")
+ }
+ return disp
+}
+
+func ComGetIDsOfName(disp *IDispatch, names []string) []int32 {
+ wnames := make([]*uint16, len(names))
+ dispid := make([]int32, len(names))
+ for i := 0; i < len(names); i++ {
+ wnames[i] = syscall.StringToUTF16Ptr(names[i])
+ }
+ hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(unsafe.Pointer(&wnames[0])),
+ uintptr(len(names)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(unsafe.Pointer(&dispid[0])))
+ if hr != 0 {
+ panic("Invoke GetIDsOfName error.")
+ }
+ return dispid
+}
+
+func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
+ var dispparams DISPPARAMS
+
+ if dispatch&DISPATCH_PROPERTYPUT != 0 {
+ dispnames := [1]int32{DISPID_PROPERTYPUT}
+ dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
+ dispparams.CNamedArgs = 1
+ }
+ var vargs []VARIANT
+ if len(params) > 0 {
+ vargs = make([]VARIANT, len(params))
+ for i, v := range params {
+ //n := len(params)-i-1
+ n := len(params) - i - 1
+ VariantInit(&vargs[n])
+ switch v.(type) {
+ case bool:
+ if v.(bool) {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff}
+ } else {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0}
+ }
+ case *bool:
+ vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))}
+ case byte:
+ vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))}
+ case *byte:
+ vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))}
+ case int16:
+ vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))}
+ case *int16:
+ vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))}
+ case uint16:
+ vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))}
+ case *uint16:
+ vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))}
+ case int, int32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))}
+ case *int, *int32:
+ vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))}
+ case uint, uint32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))}
+ case *uint, *uint32:
+ vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))}
+ case int64:
+ vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)}
+ case *int64:
+ vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))}
+ case uint64:
+ vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))}
+ case *uint64:
+ vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))}
+ case float32:
+ vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))}
+ case *float32:
+ vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
+ case float64:
+ vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
+ case *float64:
+ vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
+ case string:
+ vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
+ case *string:
+ vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
+ case *IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
+ case **IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
+ case nil:
+ vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
+ case *VARIANT:
+ vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
+ default:
+ panic("unknown type")
+ }
+ }
+ dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
+ dispparams.CArgs = uint32(len(params))
+ }
+
+ var ret VARIANT
+ var excepInfo EXCEPINFO
+ VariantInit(&ret)
+ hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(dispid),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(dispatch),
+ uintptr(unsafe.Pointer(&dispparams)),
+ uintptr(unsafe.Pointer(&ret)),
+ uintptr(unsafe.Pointer(&excepInfo)),
+ 0)
+ if hr != 0 {
+ if excepInfo.BstrDescription != nil {
+ bs := UTF16PtrToString(excepInfo.BstrDescription)
+ panic(bs)
+ }
+ }
+ for _, varg := range vargs {
+ if varg.VT == VT_BSTR && varg.Val != 0 {
+ SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
+ }
+ }
+ result = &ret
+ return
+}
+
+func WMMessageToString(msg uintptr) string {
+ // Convert windows message to string
+ switch msg {
+ case WM_APP:
+ return "WM_APP"
+ case WM_ACTIVATE:
+ return "WM_ACTIVATE"
+ case WM_ACTIVATEAPP:
+ return "WM_ACTIVATEAPP"
+ case WM_AFXFIRST:
+ return "WM_AFXFIRST"
+ case WM_AFXLAST:
+ return "WM_AFXLAST"
+ case WM_ASKCBFORMATNAME:
+ return "WM_ASKCBFORMATNAME"
+ case WM_CANCELJOURNAL:
+ return "WM_CANCELJOURNAL"
+ case WM_CANCELMODE:
+ return "WM_CANCELMODE"
+ case WM_CAPTURECHANGED:
+ return "WM_CAPTURECHANGED"
+ case WM_CHANGECBCHAIN:
+ return "WM_CHANGECBCHAIN"
+ case WM_CHAR:
+ return "WM_CHAR"
+ case WM_CHARTOITEM:
+ return "WM_CHARTOITEM"
+ case WM_CHILDACTIVATE:
+ return "WM_CHILDACTIVATE"
+ case WM_CLEAR:
+ return "WM_CLEAR"
+ case WM_CLOSE:
+ return "WM_CLOSE"
+ case WM_COMMAND:
+ return "WM_COMMAND"
+ case WM_COMMNOTIFY /* OBSOLETE */ :
+ return "WM_COMMNOTIFY"
+ case WM_COMPACTING:
+ return "WM_COMPACTING"
+ case WM_COMPAREITEM:
+ return "WM_COMPAREITEM"
+ case WM_CONTEXTMENU:
+ return "WM_CONTEXTMENU"
+ case WM_COPY:
+ return "WM_COPY"
+ case WM_COPYDATA:
+ return "WM_COPYDATA"
+ case WM_CREATE:
+ return "WM_CREATE"
+ case WM_CTLCOLORBTN:
+ return "WM_CTLCOLORBTN"
+ case WM_CTLCOLORDLG:
+ return "WM_CTLCOLORDLG"
+ case WM_CTLCOLOREDIT:
+ return "WM_CTLCOLOREDIT"
+ case WM_CTLCOLORLISTBOX:
+ return "WM_CTLCOLORLISTBOX"
+ case WM_CTLCOLORMSGBOX:
+ return "WM_CTLCOLORMSGBOX"
+ case WM_CTLCOLORSCROLLBAR:
+ return "WM_CTLCOLORSCROLLBAR"
+ case WM_CTLCOLORSTATIC:
+ return "WM_CTLCOLORSTATIC"
+ case WM_CUT:
+ return "WM_CUT"
+ case WM_DEADCHAR:
+ return "WM_DEADCHAR"
+ case WM_DELETEITEM:
+ return "WM_DELETEITEM"
+ case WM_DESTROY:
+ return "WM_DESTROY"
+ case WM_DESTROYCLIPBOARD:
+ return "WM_DESTROYCLIPBOARD"
+ case WM_DEVICECHANGE:
+ return "WM_DEVICECHANGE"
+ case WM_DEVMODECHANGE:
+ return "WM_DEVMODECHANGE"
+ case WM_DISPLAYCHANGE:
+ return "WM_DISPLAYCHANGE"
+ case WM_DRAWCLIPBOARD:
+ return "WM_DRAWCLIPBOARD"
+ case WM_DRAWITEM:
+ return "WM_DRAWITEM"
+ case WM_DROPFILES:
+ return "WM_DROPFILES"
+ case WM_ENABLE:
+ return "WM_ENABLE"
+ case WM_ENDSESSION:
+ return "WM_ENDSESSION"
+ case WM_ENTERIDLE:
+ return "WM_ENTERIDLE"
+ case WM_ENTERMENULOOP:
+ return "WM_ENTERMENULOOP"
+ case WM_ENTERSIZEMOVE:
+ return "WM_ENTERSIZEMOVE"
+ case WM_ERASEBKGND:
+ return "WM_ERASEBKGND"
+ case WM_EXITMENULOOP:
+ return "WM_EXITMENULOOP"
+ case WM_EXITSIZEMOVE:
+ return "WM_EXITSIZEMOVE"
+ case WM_FONTCHANGE:
+ return "WM_FONTCHANGE"
+ case WM_GETDLGCODE:
+ return "WM_GETDLGCODE"
+ case WM_GETFONT:
+ return "WM_GETFONT"
+ case WM_GETHOTKEY:
+ return "WM_GETHOTKEY"
+ case WM_GETICON:
+ return "WM_GETICON"
+ case WM_GETMINMAXINFO:
+ return "WM_GETMINMAXINFO"
+ case WM_GETTEXT:
+ return "WM_GETTEXT"
+ case WM_GETTEXTLENGTH:
+ return "WM_GETTEXTLENGTH"
+ case WM_HANDHELDFIRST:
+ return "WM_HANDHELDFIRST"
+ case WM_HANDHELDLAST:
+ return "WM_HANDHELDLAST"
+ case WM_HELP:
+ return "WM_HELP"
+ case WM_HOTKEY:
+ return "WM_HOTKEY"
+ case WM_HSCROLL:
+ return "WM_HSCROLL"
+ case WM_HSCROLLCLIPBOARD:
+ return "WM_HSCROLLCLIPBOARD"
+ case WM_ICONERASEBKGND:
+ return "WM_ICONERASEBKGND"
+ case WM_INITDIALOG:
+ return "WM_INITDIALOG"
+ case WM_INITMENU:
+ return "WM_INITMENU"
+ case WM_INITMENUPOPUP:
+ return "WM_INITMENUPOPUP"
+ case WM_INPUT:
+ return "WM_INPUT"
+ case WM_INPUTLANGCHANGE:
+ return "WM_INPUTLANGCHANGE"
+ case WM_INPUTLANGCHANGEREQUEST:
+ return "WM_INPUTLANGCHANGEREQUEST"
+ case WM_KEYDOWN:
+ return "WM_KEYDOWN"
+ case WM_KEYUP:
+ return "WM_KEYUP"
+ case WM_KILLFOCUS:
+ return "WM_KILLFOCUS"
+ case WM_MDIACTIVATE:
+ return "WM_MDIACTIVATE"
+ case WM_MDICASCADE:
+ return "WM_MDICASCADE"
+ case WM_MDICREATE:
+ return "WM_MDICREATE"
+ case WM_MDIDESTROY:
+ return "WM_MDIDESTROY"
+ case WM_MDIGETACTIVE:
+ return "WM_MDIGETACTIVE"
+ case WM_MDIICONARRANGE:
+ return "WM_MDIICONARRANGE"
+ case WM_MDIMAXIMIZE:
+ return "WM_MDIMAXIMIZE"
+ case WM_MDINEXT:
+ return "WM_MDINEXT"
+ case WM_MDIREFRESHMENU:
+ return "WM_MDIREFRESHMENU"
+ case WM_MDIRESTORE:
+ return "WM_MDIRESTORE"
+ case WM_MDISETMENU:
+ return "WM_MDISETMENU"
+ case WM_MDITILE:
+ return "WM_MDITILE"
+ case WM_MEASUREITEM:
+ return "WM_MEASUREITEM"
+ case WM_GETOBJECT:
+ return "WM_GETOBJECT"
+ case WM_CHANGEUISTATE:
+ return "WM_CHANGEUISTATE"
+ case WM_UPDATEUISTATE:
+ return "WM_UPDATEUISTATE"
+ case WM_QUERYUISTATE:
+ return "WM_QUERYUISTATE"
+ case WM_UNINITMENUPOPUP:
+ return "WM_UNINITMENUPOPUP"
+ case WM_MENURBUTTONUP:
+ return "WM_MENURBUTTONUP"
+ case WM_MENUCOMMAND:
+ return "WM_MENUCOMMAND"
+ case WM_MENUGETOBJECT:
+ return "WM_MENUGETOBJECT"
+ case WM_MENUDRAG:
+ return "WM_MENUDRAG"
+ case WM_APPCOMMAND:
+ return "WM_APPCOMMAND"
+ case WM_MENUCHAR:
+ return "WM_MENUCHAR"
+ case WM_MENUSELECT:
+ return "WM_MENUSELECT"
+ case WM_MOVE:
+ return "WM_MOVE"
+ case WM_MOVING:
+ return "WM_MOVING"
+ case WM_NCACTIVATE:
+ return "WM_NCACTIVATE"
+ case WM_NCCALCSIZE:
+ return "WM_NCCALCSIZE"
+ case WM_NCCREATE:
+ return "WM_NCCREATE"
+ case WM_NCDESTROY:
+ return "WM_NCDESTROY"
+ case WM_NCHITTEST:
+ return "WM_NCHITTEST"
+ case WM_NCLBUTTONDBLCLK:
+ return "WM_NCLBUTTONDBLCLK"
+ case WM_NCLBUTTONDOWN:
+ return "WM_NCLBUTTONDOWN"
+ case WM_NCLBUTTONUP:
+ return "WM_NCLBUTTONUP"
+ case WM_NCMBUTTONDBLCLK:
+ return "WM_NCMBUTTONDBLCLK"
+ case WM_NCMBUTTONDOWN:
+ return "WM_NCMBUTTONDOWN"
+ case WM_NCMBUTTONUP:
+ return "WM_NCMBUTTONUP"
+ case WM_NCXBUTTONDOWN:
+ return "WM_NCXBUTTONDOWN"
+ case WM_NCXBUTTONUP:
+ return "WM_NCXBUTTONUP"
+ case WM_NCXBUTTONDBLCLK:
+ return "WM_NCXBUTTONDBLCLK"
+ case WM_NCMOUSEHOVER:
+ return "WM_NCMOUSEHOVER"
+ case WM_NCMOUSELEAVE:
+ return "WM_NCMOUSELEAVE"
+ case WM_NCMOUSEMOVE:
+ return "WM_NCMOUSEMOVE"
+ case WM_NCPAINT:
+ return "WM_NCPAINT"
+ case WM_NCRBUTTONDBLCLK:
+ return "WM_NCRBUTTONDBLCLK"
+ case WM_NCRBUTTONDOWN:
+ return "WM_NCRBUTTONDOWN"
+ case WM_NCRBUTTONUP:
+ return "WM_NCRBUTTONUP"
+ case WM_NEXTDLGCTL:
+ return "WM_NEXTDLGCTL"
+ case WM_NEXTMENU:
+ return "WM_NEXTMENU"
+ case WM_NOTIFY:
+ return "WM_NOTIFY"
+ case WM_NOTIFYFORMAT:
+ return "WM_NOTIFYFORMAT"
+ case WM_NULL:
+ return "WM_NULL"
+ case WM_PAINT:
+ return "WM_PAINT"
+ case WM_PAINTCLIPBOARD:
+ return "WM_PAINTCLIPBOARD"
+ case WM_PAINTICON:
+ return "WM_PAINTICON"
+ case WM_PALETTECHANGED:
+ return "WM_PALETTECHANGED"
+ case WM_PALETTEISCHANGING:
+ return "WM_PALETTEISCHANGING"
+ case WM_PARENTNOTIFY:
+ return "WM_PARENTNOTIFY"
+ case WM_PASTE:
+ return "WM_PASTE"
+ case WM_PENWINFIRST:
+ return "WM_PENWINFIRST"
+ case WM_PENWINLAST:
+ return "WM_PENWINLAST"
+ case WM_POWER:
+ return "WM_POWER"
+ case WM_PRINT:
+ return "WM_PRINT"
+ case WM_PRINTCLIENT:
+ return "WM_PRINTCLIENT"
+ case WM_QUERYDRAGICON:
+ return "WM_QUERYDRAGICON"
+ case WM_QUERYENDSESSION:
+ return "WM_QUERYENDSESSION"
+ case WM_QUERYNEWPALETTE:
+ return "WM_QUERYNEWPALETTE"
+ case WM_QUERYOPEN:
+ return "WM_QUERYOPEN"
+ case WM_QUEUESYNC:
+ return "WM_QUEUESYNC"
+ case WM_QUIT:
+ return "WM_QUIT"
+ case WM_RENDERALLFORMATS:
+ return "WM_RENDERALLFORMATS"
+ case WM_RENDERFORMAT:
+ return "WM_RENDERFORMAT"
+ case WM_SETCURSOR:
+ return "WM_SETCURSOR"
+ case WM_SETFOCUS:
+ return "WM_SETFOCUS"
+ case WM_SETFONT:
+ return "WM_SETFONT"
+ case WM_SETHOTKEY:
+ return "WM_SETHOTKEY"
+ case WM_SETICON:
+ return "WM_SETICON"
+ case WM_SETREDRAW:
+ return "WM_SETREDRAW"
+ case WM_SETTEXT:
+ return "WM_SETTEXT"
+ case WM_SETTINGCHANGE:
+ return "WM_SETTINGCHANGE"
+ case WM_SHOWWINDOW:
+ return "WM_SHOWWINDOW"
+ case WM_SIZE:
+ return "WM_SIZE"
+ case WM_SIZECLIPBOARD:
+ return "WM_SIZECLIPBOARD"
+ case WM_SIZING:
+ return "WM_SIZING"
+ case WM_SPOOLERSTATUS:
+ return "WM_SPOOLERSTATUS"
+ case WM_STYLECHANGED:
+ return "WM_STYLECHANGED"
+ case WM_STYLECHANGING:
+ return "WM_STYLECHANGING"
+ case WM_SYSCHAR:
+ return "WM_SYSCHAR"
+ case WM_SYSCOLORCHANGE:
+ return "WM_SYSCOLORCHANGE"
+ case WM_SYSCOMMAND:
+ return "WM_SYSCOMMAND"
+ case WM_SYSDEADCHAR:
+ return "WM_SYSDEADCHAR"
+ case WM_SYSKEYDOWN:
+ return "WM_SYSKEYDOWN"
+ case WM_SYSKEYUP:
+ return "WM_SYSKEYUP"
+ case WM_TCARD:
+ return "WM_TCARD"
+ case WM_THEMECHANGED:
+ return "WM_THEMECHANGED"
+ case WM_TIMECHANGE:
+ return "WM_TIMECHANGE"
+ case WM_TIMER:
+ return "WM_TIMER"
+ case WM_UNDO:
+ return "WM_UNDO"
+ case WM_USER:
+ return "WM_USER"
+ case WM_USERCHANGED:
+ return "WM_USERCHANGED"
+ case WM_VKEYTOITEM:
+ return "WM_VKEYTOITEM"
+ case WM_VSCROLL:
+ return "WM_VSCROLL"
+ case WM_VSCROLLCLIPBOARD:
+ return "WM_VSCROLLCLIPBOARD"
+ case WM_WINDOWPOSCHANGED:
+ return "WM_WINDOWPOSCHANGED"
+ case WM_WINDOWPOSCHANGING:
+ return "WM_WINDOWPOSCHANGING"
+ case WM_KEYLAST:
+ return "WM_KEYLAST"
+ case WM_SYNCPAINT:
+ return "WM_SYNCPAINT"
+ case WM_MOUSEACTIVATE:
+ return "WM_MOUSEACTIVATE"
+ case WM_MOUSEMOVE:
+ return "WM_MOUSEMOVE"
+ case WM_LBUTTONDOWN:
+ return "WM_LBUTTONDOWN"
+ case WM_LBUTTONUP:
+ return "WM_LBUTTONUP"
+ case WM_LBUTTONDBLCLK:
+ return "WM_LBUTTONDBLCLK"
+ case WM_RBUTTONDOWN:
+ return "WM_RBUTTONDOWN"
+ case WM_RBUTTONUP:
+ return "WM_RBUTTONUP"
+ case WM_RBUTTONDBLCLK:
+ return "WM_RBUTTONDBLCLK"
+ case WM_MBUTTONDOWN:
+ return "WM_MBUTTONDOWN"
+ case WM_MBUTTONUP:
+ return "WM_MBUTTONUP"
+ case WM_MBUTTONDBLCLK:
+ return "WM_MBUTTONDBLCLK"
+ case WM_MOUSEWHEEL:
+ return "WM_MOUSEWHEEL"
+ case WM_XBUTTONDOWN:
+ return "WM_XBUTTONDOWN"
+ case WM_XBUTTONUP:
+ return "WM_XBUTTONUP"
+ case WM_MOUSELAST:
+ return "WM_MOUSELAST"
+ case WM_MOUSEHOVER:
+ return "WM_MOUSEHOVER"
+ case WM_MOUSELEAVE:
+ return "WM_MOUSELEAVE"
+ case WM_CLIPBOARDUPDATE:
+ return "WM_CLIPBOARDUPDATE"
+ default:
+ return fmt.Sprintf("0x%08x", msg)
+ }
+}
+
+func Fatal(message string) {
+ println("***************** FATAL ERROR ******************")
+ fmt.Println("Message: " + message)
+ fmt.Println("Last Error: " + strconv.Itoa(int(GetLastError())))
+ fmt.Println("Stack: " + string(debug.Stack()))
+ os.Exit(1)
+}
diff --git a/v3/pkg/w32/uxtheme.go b/v3/pkg/w32/uxtheme.go
new file mode 100644
index 000000000..51ec0035f
--- /dev/null
+++ b/v3/pkg/w32/uxtheme.go
@@ -0,0 +1,152 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// LISTVIEW parts
+const (
+ LVP_LISTITEM = 1
+ LVP_LISTGROUP = 2
+ LVP_LISTDETAIL = 3
+ LVP_LISTSORTEDDETAIL = 4
+ LVP_EMPTYTEXT = 5
+ LVP_GROUPHEADER = 6
+ LVP_GROUPHEADERLINE = 7
+ LVP_EXPANDBUTTON = 8
+ LVP_COLLAPSEBUTTON = 9
+ LVP_COLUMNDETAIL = 10
+)
+
+// LVP_LISTITEM states
+const (
+ LISS_NORMAL = 1
+ LISS_HOT = 2
+ LISS_SELECTED = 3
+ LISS_DISABLED = 4
+ LISS_SELECTEDNOTFOCUS = 5
+ LISS_HOTSELECTED = 6
+)
+
+// TREEVIEW parts
+const (
+ TVP_TREEITEM = 1
+ TVP_GLYPH = 2
+ TVP_BRANCH = 3
+ TVP_HOTGLYPH = 4
+)
+
+// TVP_TREEITEM states
+const (
+ TREIS_NORMAL = 1
+ TREIS_HOT = 2
+ TREIS_SELECTED = 3
+ TREIS_DISABLED = 4
+ TREIS_SELECTEDNOTFOCUS = 5
+ TREIS_HOTSELECTED = 6
+)
+
+type HTHEME HANDLE
+
+var (
+ // Library
+ libuxtheme uintptr
+
+ // Functions
+ closeThemeData uintptr
+ drawThemeBackground uintptr
+ drawThemeText uintptr
+ getThemeTextExtent uintptr
+ openThemeData uintptr
+ setWindowTheme uintptr
+)
+
+func init() {
+ // Library
+ libuxtheme = MustLoadLibrary("uxtheme.dll")
+
+ // Functions
+ closeThemeData = MustGetProcAddress(libuxtheme, "CloseThemeData")
+ drawThemeBackground = MustGetProcAddress(libuxtheme, "DrawThemeBackground")
+ drawThemeText = MustGetProcAddress(libuxtheme, "DrawThemeText")
+ getThemeTextExtent = MustGetProcAddress(libuxtheme, "GetThemeTextExtent")
+ openThemeData = MustGetProcAddress(libuxtheme, "OpenThemeData")
+ setWindowTheme = MustGetProcAddress(libuxtheme, "SetWindowTheme")
+}
+
+func CloseThemeData(hTheme HTHEME) HRESULT {
+ ret, _, _ := syscall.Syscall(closeThemeData, 1,
+ uintptr(hTheme),
+ 0,
+ 0)
+
+ return HRESULT(ret)
+}
+
+func DrawThemeBackground(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pRect, pClipRect *RECT) HRESULT {
+ ret, _, _ := syscall.Syscall6(drawThemeBackground, 6,
+ uintptr(hTheme),
+ uintptr(hdc),
+ uintptr(iPartId),
+ uintptr(iStateId),
+ uintptr(unsafe.Pointer(pRect)),
+ uintptr(unsafe.Pointer(pClipRect)))
+
+ return HRESULT(ret)
+}
+
+func DrawThemeText(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags, dwTextFlags2 uint32, pRect *RECT) HRESULT {
+ ret, _, _ := syscall.Syscall9(drawThemeText, 9,
+ uintptr(hTheme),
+ uintptr(hdc),
+ uintptr(iPartId),
+ uintptr(iStateId),
+ uintptr(unsafe.Pointer(pszText)),
+ uintptr(iCharCount),
+ uintptr(dwTextFlags),
+ uintptr(dwTextFlags2),
+ uintptr(unsafe.Pointer(pRect)))
+
+ return HRESULT(ret)
+}
+
+func GetThemeTextExtent(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags uint32, pBoundingRect, pExtentRect *RECT) HRESULT {
+ ret, _, _ := syscall.Syscall9(getThemeTextExtent, 9,
+ uintptr(hTheme),
+ uintptr(hdc),
+ uintptr(iPartId),
+ uintptr(iStateId),
+ uintptr(unsafe.Pointer(pszText)),
+ uintptr(iCharCount),
+ uintptr(dwTextFlags),
+ uintptr(unsafe.Pointer(pBoundingRect)),
+ uintptr(unsafe.Pointer(pExtentRect)))
+
+ return HRESULT(ret)
+}
+
+func OpenThemeData(hwnd HWND, pszClassList *uint16) HTHEME {
+ ret, _, _ := syscall.Syscall(openThemeData, 2,
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(pszClassList)),
+ 0)
+
+ return HTHEME(ret)
+}
+
+func SetWindowTheme(hwnd HWND, pszSubAppName, pszSubIdList *uint16) HRESULT {
+ ret, _, _ := syscall.Syscall(setWindowTheme, 3,
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(pszSubAppName)),
+ uintptr(unsafe.Pointer(pszSubIdList)))
+
+ return HRESULT(ret)
+}
diff --git a/v3/pkg/w32/vars.go b/v3/pkg/w32/vars.go
new file mode 100644
index 000000000..cb69f9d19
--- /dev/null
+++ b/v3/pkg/w32/vars.go
@@ -0,0 +1,16 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+var (
+ IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
+ IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+ IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+)
diff --git a/v3/pkg/w32/window.go b/v3/pkg/w32/window.go
new file mode 100644
index 000000000..e4aaafdc1
--- /dev/null
+++ b/v3/pkg/w32/window.go
@@ -0,0 +1,217 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "github.com/samber/lo"
+ "log"
+ "strconv"
+ "sync"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ GCLP_HBRBACKGROUND int32 = -10
+)
+
+func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) {
+ // -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11)
+ // Also shows the caption buttons if transparent ant translucent but they don't work.
+ // 0: Adds the default frame styling but no aero shadow, does not show the caption buttons.
+ // 1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons
+ // are shown if transparent ant translucent.
+ var margins MARGINS
+ if extend {
+ margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons
+ }
+ if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil {
+ log.Fatal(fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err))
+ }
+}
+
+func IsVisible(hwnd uintptr) bool {
+ ret, _, _ := procIsWindowVisible.Call(hwnd)
+ return ret != 0
+}
+
+func IsWindowFullScreen(hwnd uintptr) bool {
+ wRect := GetWindowRect(hwnd)
+ m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
+ var mi MONITORINFO
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ if !GetMonitorInfo(m, &mi) {
+ return false
+ }
+ return wRect.Left == mi.RcMonitor.Left &&
+ wRect.Top == mi.RcMonitor.Top &&
+ wRect.Right == mi.RcMonitor.Right &&
+ wRect.Bottom == mi.RcMonitor.Bottom
+}
+
+func IsWindowMaximised(hwnd uintptr) bool {
+ style := uint32(getWindowLong(hwnd, GWL_STYLE))
+ return style&WS_MAXIMIZE != 0
+}
+func IsWindowMinimised(hwnd uintptr) bool {
+ style := uint32(getWindowLong(hwnd, GWL_STYLE))
+ return style&WS_MINIMIZE != 0
+}
+
+func RestoreWindow(hwnd uintptr) {
+ showWindow(hwnd, SW_RESTORE)
+}
+
+func ShowWindowMaximised(hwnd uintptr) {
+ showWindow(hwnd, SW_MAXIMIZE)
+}
+func ShowWindowMinimised(hwnd uintptr) {
+ showWindow(hwnd, SW_MINIMIZE)
+}
+
+func SetBackgroundColour(hwnd uintptr, r, g, b uint8) {
+ col := uint32(r) | uint32(g)<<8 | uint32(b)<<16
+ hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col))
+ setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush)
+}
+
+func IsWindowNormal(hwnd uintptr) bool {
+ return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd)
+}
+
+func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool {
+ proc := procSetClassLongPtr
+ if strconv.IntSize == 32 {
+ /*
+ https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
+ Note: To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr.
+ When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function
+
+ => We have to do this dynamically when directly calling the DLL procedures
+ */
+ proc = procSetClassLong
+ }
+
+ ret, _, _ := proc.Call(
+ hwnd,
+ uintptr(param),
+ val,
+ )
+ return ret != 0
+}
+
+func getWindowLong(hwnd uintptr, index int) int32 {
+ ret, _, _ := procGetWindowLong.Call(
+ hwnd,
+ uintptr(index))
+
+ return int32(ret)
+}
+
+func showWindow(hwnd uintptr, cmdshow int) bool {
+ ret, _, _ := procShowWindow.Call(
+ hwnd,
+ uintptr(cmdshow))
+ return ret != 0
+}
+
+func MustStringToUTF16Ptr(input string) *uint16 {
+ result, err := syscall.UTF16PtrFromString(input)
+ if err != nil {
+ Fatal(err.Error())
+ }
+ return result
+}
+
+func MustStringToUTF16uintptr(input string) uintptr {
+ ret := lo.Must(syscall.UTF16PtrFromString(input))
+ return uintptr(unsafe.Pointer(ret))
+}
+
+func MustStringToUTF16(input string) []uint16 {
+ return lo.Must(syscall.UTF16FromString(input))
+}
+
+func CenterWindow(hwnd HWND) {
+ windowInfo := getWindowInfo(hwnd)
+ frameless := windowInfo.IsPopup()
+
+ info := GetMonitorInfoForWindow(hwnd)
+ workRect := info.RcWork
+ screenMiddleW := workRect.Left + (workRect.Right-workRect.Left)/2
+ screenMiddleH := workRect.Top + (workRect.Bottom-workRect.Top)/2
+ var winRect *RECT
+ if !frameless {
+ winRect = GetWindowRect(hwnd)
+ } else {
+ winRect = GetClientRect(hwnd)
+ }
+ winWidth := winRect.Right - winRect.Left
+ winHeight := winRect.Bottom - winRect.Top
+ windowX := screenMiddleW - (winWidth / 2)
+ windowY := screenMiddleH - (winHeight / 2)
+ SetWindowPos(hwnd, HWND_TOP, int(windowX), int(windowY), int(winWidth), int(winHeight), SWP_NOSIZE)
+}
+
+func getWindowInfo(hwnd HWND) *WINDOWINFO {
+ var info WINDOWINFO
+ info.CbSize = uint32(unsafe.Sizeof(info))
+ GetWindowInfo(hwnd, &info)
+ return &info
+}
+
+func GetMonitorInfoForWindow(hwnd HWND) *MONITORINFO {
+ currentMonitor := MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
+ var info MONITORINFO
+ info.CbSize = uint32(unsafe.Sizeof(info))
+ GetMonitorInfo(currentMonitor, &info)
+ return &info
+}
+
+type WindowProc func(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr
+
+var windowClasses = make(map[string]HINSTANCE)
+var windowClassesLock sync.Mutex
+
+func getWindowClass(name string) (HINSTANCE, bool) {
+ windowClassesLock.Lock()
+ defer windowClassesLock.Unlock()
+ result, exists := windowClasses[name]
+ return result, exists
+}
+
+func setWindowClass(name string, instance HINSTANCE) {
+ windowClassesLock.Lock()
+ defer windowClassesLock.Unlock()
+ windowClasses[name] = instance
+}
+
+func RegisterWindow(name string, proc WindowProc) (HINSTANCE, error) {
+ classInstance, exists := getWindowClass(name)
+ if exists {
+ return classInstance, nil
+ }
+ applicationInstance := GetModuleHandle("")
+ if applicationInstance == 0 {
+ return 0, fmt.Errorf("get module handle failed")
+ }
+
+ var wc WNDCLASSEX
+ wc.Size = uint32(unsafe.Sizeof(wc))
+ wc.WndProc = syscall.NewCallback(proc)
+ wc.Instance = applicationInstance
+ wc.Icon = LoadIconWithResourceID(0, uint16(IDI_APPLICATION))
+ wc.Cursor = LoadCursorWithResourceID(0, uint16(IDC_ARROW))
+ wc.Background = COLOR_BTNFACE + 1
+ wc.ClassName = MustStringToUTF16Ptr(name)
+
+ atom := RegisterClassEx(&wc)
+ if atom == 0 {
+ panic(syscall.GetLastError())
+ }
+
+ setWindowClass(name, applicationInstance)
+
+ return applicationInstance, nil
+}
diff --git a/v3/tasks/Taskfile.yml b/v3/tasks/Taskfile.yml
index 1949fb8f9..a9a8505dd 100644
--- a/v3/tasks/Taskfile.yml
+++ b/v3/tasks/Taskfile.yml
@@ -1,7 +1,7 @@
version: '3'
tasks:
- generate:
+ generate:events:
dir: ./events
cmds:
- - go run generate.go
+ - go run generate.go
\ No newline at end of file
diff --git a/v3/tasks/events/generate.go b/v3/tasks/events/generate.go
index eafa27f89..e098b357d 100644
--- a/v3/tasks/events/generate.go
+++ b/v3/tasks/events/generate.go
@@ -16,6 +16,16 @@ const (
FilesDropped WindowEventType = iota
)
+var Common = newCommonEvents()
+
+type commonEvents struct {
+$$COMMONEVENTSDECL}
+
+func newCommonEvents() commonEvents {
+ return commonEvents{
+$$COMMONEVENTSVALUES }
+}
+
var Mac = newMacEvents()
type macEvents struct {
@@ -25,6 +35,18 @@ func newMacEvents() macEvents {
return macEvents{
$$MACEVENTSVALUES }
}
+
+var Windows = newWindowsEvents()
+
+type windowsEvents struct {
+$$WINDOWSEVENTSDECL}
+
+func newWindowsEvents() windowsEvents {
+ return windowsEvents{
+$$WINDOWSEVENTSVALUES }
+}
+
+
`
var eventsH = `//go:build darwin
@@ -53,7 +75,14 @@ func main() {
applicationDelegateEvents := bytes.NewBufferString("")
webviewDelegateEvents := bytes.NewBufferString("")
+ windowsEventsDecl := bytes.NewBufferString("")
+ windowsEventsValues := bytes.NewBufferString("")
+
+ commonEventsDecl := bytes.NewBufferString("")
+ commonEventsValues := bytes.NewBufferString("")
+
var id int
+ var maxMacEvents int
var line []byte
// Loop over each line in the file
for id, line = range bytes.Split(eventNames, []byte{'\n'}) {
@@ -94,6 +123,7 @@ func main() {
macEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
macEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
cHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n")
+ maxMacEvents = id
if ignoreEvent {
continue
}
@@ -128,15 +158,73 @@ func main() {
`)
}
-
+ case "common":
+ eventType := "ApplicationEventType"
+ if strings.HasPrefix(event, "Window") {
+ eventType = "WindowEventType"
+ }
+ if strings.HasPrefix(event, "WebView") {
+ eventType = "WindowEventType"
+ }
+ commonEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
+ commonEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
+ case "windows":
+ eventType := "ApplicationEventType"
+ if strings.HasPrefix(event, "Window") {
+ eventType = "WindowEventType"
+ }
+ if strings.HasPrefix(event, "WebView") {
+ eventType = "WindowEventType"
+ }
+ windowsEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
+ windowsEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
+ // cHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n")
+ // if ignoreEvent {
+ // continue
+ // }
+ // // Check if this is a window event
+ // if strings.HasPrefix(event, "Window") {
+ // windowDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification {
+ // if( hasListeners(Event` + eventTitle + `) ) {
+ // processWindowEvent(self.windowId, Event` + eventTitle + `);
+ // }
+ //}
+ //
+ //`)
+ // }
+ // // Check if this is a webview event
+ // if strings.HasPrefix(event, "WebView") {
+ // webViewFunction := strings.TrimPrefix(event, "WebView")
+ // webViewFunction = string(bytes.ToLower([]byte{webViewFunction[0]})) + webViewFunction[1:]
+ // webviewDelegateEvents.WriteString(`- (void)webView:(WKWebView *)webview ` + webViewFunction + `:(WKNavigation *)navigation {
+ // if( hasListeners(Event` + eventTitle + `) ) {
+ // processWindowEvent(self.windowId, Event` + eventTitle + `);
+ // }
+ //}
+ //
+ //`)
+ // }
+ // if strings.HasPrefix(event, "Application") {
+ // applicationDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification {
+ // if( hasListeners(Event` + eventTitle + `) ) {
+ // processApplicationEvent(Event` + eventTitle + `);
+ // }
+ //}
+ //
+ //`)
+ // }
}
}
- cHeaderEvents.WriteString("\n#define MAX_EVENTS " + strconv.Itoa(id-1) + "\n")
+ cHeaderEvents.WriteString("\n#define MAX_EVENTS " + strconv.Itoa(maxMacEvents+1) + "\n")
// Save the eventsGo template substituting the values and decls
templateToWrite := strings.ReplaceAll(eventsGo, "$$MACEVENTSDECL", macEventsDecl.String())
templateToWrite = strings.ReplaceAll(templateToWrite, "$$MACEVENTSVALUES", macEventsValues.String())
+ templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSEVENTSDECL", windowsEventsDecl.String())
+ templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSEVENTSVALUES", windowsEventsValues.String())
+ templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONEVENTSDECL", commonEventsDecl.String())
+ templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONEVENTSVALUES", commonEventsValues.String())
err = os.WriteFile("../../pkg/events/events.go", []byte(templateToWrite), 0644)
if err != nil {
panic(err)
@@ -150,7 +238,7 @@ func main() {
}
// Load the window_delegate.m file
- windowDelegate, err := os.ReadFile("../../pkg/application/webview_window.m")
+ windowDelegate, err := os.ReadFile("../../pkg/application/webview_window_darwin.m")
if err != nil {
panic(err)
}
@@ -180,13 +268,13 @@ func main() {
}
}
}
- err = os.WriteFile("../../pkg/application/webview_window.m", buffer.Bytes(), 0755)
+ err = os.WriteFile("../../pkg/application/webview_window_darwin.m", buffer.Bytes(), 0755)
if err != nil {
panic(err)
}
// Load the app_delegate.m file
- appDelegate, err := os.ReadFile("../../pkg/application/app_delegate.m")
+ appDelegate, err := os.ReadFile("../../pkg/application/application_darwin_delegate.m")
if err != nil {
panic(err)
}
@@ -214,7 +302,7 @@ func main() {
}
}
}
- err = os.WriteFile("../../pkg/application/app_delegate.m", buffer.Bytes(), 0755)
+ err = os.WriteFile("../../pkg/application/application_darwin_delegate.m", buffer.Bytes(), 0755)
if err != nil {
panic(err)
}
diff --git a/v3/tasks/png2bytes/png2bytes.go b/v3/tasks/png2bytes/png2bytes.go
deleted file mode 100644
index b51a472b6..000000000
--- a/v3/tasks/png2bytes/png2bytes.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package main
-
-import (
- "bytes"
- "os"
- "strconv"
-)
-
-func main() {
-
- if len(os.Args) != 2 {
- println("Please provide a filename")
- os.Exit(1)
- }
-
- data, err := os.ReadFile(os.Args[1])
- if err != nil {
- println("Error reading file:", err.Error())
- os.Exit(1)
- }
-
- var buffer bytes.Buffer
- buffer.WriteString("var image = []byte{")
- // Iterate over the bytes and print them out in decimal
- for _, b := range data {
- // convert byte to decimal
- buffer.WriteString(strconv.Itoa(int(b)) + ", ")
- }
- buffer.WriteString("}\n")
-
- // write to file
- err = os.WriteFile(os.Args[1]+".go", buffer.Bytes(), 0644)
- if err != nil {
- println("Error writing file:", err.Error())
- os.Exit(1)
- }
-
-}
diff --git a/v3/website/.gitignore b/v3/website/.gitignore
new file mode 100644
index 000000000..5c41f011a
--- /dev/null
+++ b/v3/website/.gitignore
@@ -0,0 +1 @@
+.hugo_build.lock
\ No newline at end of file
diff --git a/v3/website/.prettierignore b/v3/website/.prettierignore
new file mode 100644
index 000000000..9a2c4b1e9
--- /dev/null
+++ b/v3/website/.prettierignore
@@ -0,0 +1,2 @@
+archetypes
+content/zh-Hans
\ No newline at end of file
diff --git a/v3/website/.prettierrc.yml b/v3/website/.prettierrc.yml
new file mode 100644
index 000000000..685d8b6e7
--- /dev/null
+++ b/v3/website/.prettierrc.yml
@@ -0,0 +1,6 @@
+overrides:
+ - files:
+ - "**/*.md"
+ options:
+ printWidth: 80
+ proseWrap: always
diff --git a/v3/website/README.md b/v3/website/README.md
new file mode 100644
index 000000000..f1b0571f5
--- /dev/null
+++ b/v3/website/README.md
@@ -0,0 +1 @@
+# Website
diff --git a/v3/website/Taskfile.yml b/v3/website/Taskfile.yml
new file mode 100644
index 000000000..5fca86a43
--- /dev/null
+++ b/v3/website/Taskfile.yml
@@ -0,0 +1,60 @@
+# https://taskfile.dev
+
+version: "3"
+
+tasks:
+ install:
+ desc: Setup Hugo
+ cmds:
+ - go install github.com/gohugoio/hugo@latest
+
+ update-theme:
+ dir: ../../
+ cmds:
+ - git subtree pull --prefix v3/website/themes/hugo-theme-misidoc https://github.com/misix-themes/hugo-theme-misidoc.git main --squash
+
+ default:
+ desc: Preview Website
+ deps:
+ - install
+ - crowdin:update-translation-progress
+ aliases:
+ - start
+ - dev
+ cmds:
+ - hugo serve -D
+
+ build:
+ desc: Build Website
+ deps:
+ - install
+ - crowdin:update-translation-progress
+ cmds:
+ - hugo
+
+ format:md:
+ desc: Format Markdown files
+ cmds:
+ - npx prettier --write '**/*.md'
+
+ format:
+ desc: Format all files
+ cmds:
+ - task: format:md
+
+ crowdin:push:
+ desc: Upload source files to Crowdin
+ cmds:
+ - npx crowdin push -b v3
+ crowdin:pull:
+ desc: Download approved translation files from Crowdin to local
+ cmds:
+ - npx crowdin pull -b v3 --export-only-approved
+
+ crowdin:update-translation-progress:
+ desc: Get translation progress data
+ dir: tools/update-translation-progress
+ aliases:
+ - crowdin:utp
+ cmds:
+ - go run main.go
diff --git a/v3/website/archetypes/default.md b/v3/website/archetypes/default.md
new file mode 100644
index 000000000..00e77bd79
--- /dev/null
+++ b/v3/website/archetypes/default.md
@@ -0,0 +1,6 @@
+---
+title: "{{ replace .Name "-" " " | title }}"
+date: {{ .Date }}
+draft: true
+---
+
diff --git a/v3/website/content/en/_index.md b/v3/website/content/en/_index.md
new file mode 100644
index 000000000..85c5cb90f
--- /dev/null
+++ b/v3/website/content/en/_index.md
@@ -0,0 +1,6 @@
+---
+title: ""
+date: 2023-05-26T18:16:37+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/blog/_index.md b/v3/website/content/en/blog/_index.md
new file mode 100644
index 000000000..386156b26
--- /dev/null
+++ b/v3/website/content/en/blog/_index.md
@@ -0,0 +1,6 @@
+---
+title: "Blog"
+date: 2023-05-26T18:53:21+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/changelog.md b/v3/website/content/en/changelog.md
new file mode 100644
index 000000000..cef3b6d41
--- /dev/null
+++ b/v3/website/content/en/changelog.md
@@ -0,0 +1,6 @@
+---
+title: "Changelog"
+date: 2023-05-26T18:48:47+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/coc.md b/v3/website/content/en/coc.md
new file mode 100644
index 000000000..e4427f0af
--- /dev/null
+++ b/v3/website/content/en/coc.md
@@ -0,0 +1,5 @@
+---
+title: "Code Of Conduct"
+date: 2023-05-26T19:20:28+08:00
+draft: true
+---
diff --git a/v3/website/content/en/community-guide.md b/v3/website/content/en/community-guide.md
new file mode 100644
index 000000000..3d96fef40
--- /dev/null
+++ b/v3/website/content/en/community-guide.md
@@ -0,0 +1,6 @@
+---
+title: "Community Guide"
+date: 2023-05-26T19:20:22+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/community/_index.md b/v3/website/content/en/community/_index.md
new file mode 100644
index 000000000..1148db966
--- /dev/null
+++ b/v3/website/content/en/community/_index.md
@@ -0,0 +1,6 @@
+---
+title: "Community"
+date: 2023-05-26T18:59:39+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/docs/guide/_index.md b/v3/website/content/en/docs/guide/_index.md
new file mode 100644
index 000000000..aaa8be568
--- /dev/null
+++ b/v3/website/content/en/docs/guide/_index.md
@@ -0,0 +1,6 @@
+---
+title: "Guide"
+date: 2023-05-26T18:58:19+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/docs/introduction.md b/v3/website/content/en/docs/introduction.md
new file mode 100644
index 000000000..3eac61789
--- /dev/null
+++ b/v3/website/content/en/docs/introduction.md
@@ -0,0 +1,5 @@
+---
+title: "Introduction"
+date: 2023-05-26T18:15:57+08:00
+draft: true
+---
diff --git a/v3/website/content/en/fqa.md b/v3/website/content/en/fqa.md
new file mode 100644
index 000000000..b76decc09
--- /dev/null
+++ b/v3/website/content/en/fqa.md
@@ -0,0 +1,6 @@
+---
+title: "FAQ"
+date: 2023-05-26T18:51:29+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/showcase/_index.md b/v3/website/content/en/showcase/_index.md
new file mode 100644
index 000000000..0b897fa9b
--- /dev/null
+++ b/v3/website/content/en/showcase/_index.md
@@ -0,0 +1,6 @@
+---
+title: "Showcase"
+date: 2023-05-26T18:52:18+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/sponsor.md b/v3/website/content/en/sponsor.md
new file mode 100644
index 000000000..845e00d02
--- /dev/null
+++ b/v3/website/content/en/sponsor.md
@@ -0,0 +1,6 @@
+---
+title: "Sponsor"
+date: 2023-05-26T19:19:24+08:00
+draft: true
+---
+
diff --git a/v3/website/content/en/team.md b/v3/website/content/en/team.md
new file mode 100644
index 000000000..1a02b21f7
--- /dev/null
+++ b/v3/website/content/en/team.md
@@ -0,0 +1,6 @@
+---
+title: "Team"
+date: 2023-05-26T19:19:02+08:00
+draft: true
+---
+
diff --git a/v3/website/crowdin.yml b/v3/website/crowdin.yml
new file mode 100644
index 000000000..17fae47b5
--- /dev/null
+++ b/v3/website/crowdin.yml
@@ -0,0 +1,9 @@
+project_id: "531392"
+api_token_env: CROWDIN_PERSONAL_TOKEN
+preserve_hierarchy: true
+files:
+ - source: /content/en/**/*
+ translation: /content/%locale%/**/%original_file_name%
+
+ - source: /data/en/**/*
+ translation: /data/%locale%/**/%original_file_name%
diff --git a/v3/website/data/en/teams.yaml b/v3/website/data/en/teams.yaml
new file mode 100644
index 000000000..a54f2cf22
--- /dev/null
+++ b/v3/website/data/en/teams.yaml
@@ -0,0 +1,10 @@
+- name: Misite Bao
+ introduction: Technology serves evolution rather than control.
+ website: https://misitebao.com
+ location: US
+ language:
+ - English
+ - Chinese
+ github: misitebao
+ twitter: misitebao
+ sponsorLink: https://misitebao.com/sponsors/
diff --git a/v3/website/data/en/translation-progress.yaml b/v3/website/data/en/translation-progress.yaml
new file mode 100644
index 000000000..2b4178a7e
--- /dev/null
+++ b/v3/website/data/en/translation-progress.yaml
@@ -0,0 +1,6 @@
+fr: 72
+ja: 61
+ko: 12
+pt-PT: 31
+ru: 14
+zh-CN: 100
diff --git a/v3/website/hugo.toml b/v3/website/hugo.toml
new file mode 100644
index 000000000..d6f9be696
--- /dev/null
+++ b/v3/website/hugo.toml
@@ -0,0 +1,61 @@
+baseURL = "https://wails.io/"
+defaultContentLanguage = "zh-hans"
+
+theme = "hugo-theme-misidoc"
+
+[languages.en]
+contentDir = "content/en"
+title = "Wails"
+weight = 1
+languageCode = "en"
+languageName = "English"
+
+ [[languages.en.menu.main]]
+ name = "Home"
+ weight = 1
+ url = "/"
+
+ [[languages.en.menu.main]]
+ name = "Guide"
+ weight = 2
+ url = "/docs/guide/"
+
+ [[languages.en.menu.main]]
+ name = "API"
+ weight = 3
+ url = "/docs/api/"
+
+ # [languages.en.params.sidebar]
+ # autogenerate = false
+ # [languages.en.params.sidebar.docs]
+
+ # [[languages.en.params.sidebar.docs."/guide/"]]
+ # text = "Getting Started"
+
+ # [[languages.en.params.sidebar.docs."/guide/".items]]
+ # text = "Installation"
+ # url = "/guide/installation"
+
+ # [[languages.en.params.sidebar.docs."/guide/".items]]
+ # text = "First Project"
+ # url = "/guide/firstproject"
+
+ # [[languages.en.params.sidebar.docs."/guide/"]]
+ # text = "Reference"
+
+ # [[languages.en.params.sidebar.docs."/guide/".items]]
+ # text = "CLI"
+ # url = "/reference/cli"
+
+ # [[languages.en.params.sidebar.docs."/guide/".items]]
+ # text = "Options"
+ # url = "/reference/options"
+
+
+[languages.zh-Hans]
+contentDir = "content/zh-Hans"
+title = "Wails"
+weight = 2
+languageCode = "zh-Hans"
+languageName = "简体中文"
+hasCJKLanguage = true
diff --git a/v3/website/tools/release/main.go b/v3/website/tools/release/main.go
new file mode 100644
index 000000000..ac53977e0
--- /dev/null
+++ b/v3/website/tools/release/main.go
@@ -0,0 +1,8 @@
+package main
+
+import "fmt"
+
+func main() {
+ // TODO:Complete the document publishing script here
+ fmt.Println("Update Translation Done.")
+}
diff --git a/v3/website/tools/update-translation-progress/main.go b/v3/website/tools/update-translation-progress/main.go
new file mode 100644
index 000000000..54dd72df6
--- /dev/null
+++ b/v3/website/tools/update-translation-progress/main.go
@@ -0,0 +1,124 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "gopkg.in/yaml.v3"
+)
+
+const (
+ BaseURL = "https://api.crowdin.com/api/v2"
+)
+
+func doRequest(client *http.Client, method, url, token string) ([]byte, error) {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.StatusCode != 200 {
+ var data map[string]interface{}
+ err = json.Unmarshal(body, &data)
+ if err != nil {
+ return nil, err
+ }
+ return nil, fmt.Errorf("Request Error: %s", data["error"].(map[string]interface{})["message"])
+
+ }
+
+ return body, nil
+}
+
+func getBranchID(client *http.Client, projectID, branchName, token string) (int, error) {
+ body, err := doRequest(client, "GET", fmt.Sprintf("%s/projects/%s/branches", BaseURL, projectID), token)
+ if err != nil {
+ return 0, err
+ }
+
+ var data map[string]interface{}
+ err = json.Unmarshal(body, &data)
+ if err != nil {
+ return 0, err
+ }
+
+ for _, branch := range data["data"].([]interface{}) {
+ if branch.(map[string]interface{})["data"].(map[string]interface{})["name"] == branchName {
+ return int(branch.(map[string]interface{})["data"].(map[string]interface{})["id"].(float64)), nil
+ }
+ }
+
+ return 0, fmt.Errorf("branch not found")
+}
+
+func getLanguageProgress(client *http.Client, projectID string, branchID int, token string) (map[string]float64, error) {
+ body, err := doRequest(client, "GET", fmt.Sprintf("%s/projects/%s/branches/%d/languages/progress", BaseURL, projectID, branchID), token)
+ if err != nil {
+ return nil, err
+ }
+
+ var data map[string]interface{}
+ err = json.Unmarshal(body, &data)
+ if err != nil {
+ return nil, err
+ }
+
+ progress := make(map[string]float64)
+
+ for _, languageProgress := range data["data"].([]interface{}) {
+ languageID := languageProgress.(map[string]interface{})["data"].(map[string]interface{})["languageId"].(string)
+ approvalProgress := languageProgress.(map[string]interface{})["data"].(map[string]interface{})["approvalProgress"].(float64)
+ progress[languageID] = approvalProgress
+ }
+
+ return progress, nil
+}
+
+func main() {
+ projectID := "531392"
+ branchName := "v2"
+ token := os.Getenv("CROWDIN_PERSONAL_TOKEN")
+
+ client := &http.Client{}
+ branchID, err := getBranchID(client, projectID, branchName, token)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ progress, err := getLanguageProgress(client, projectID, branchID, token)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ progressYaml, err := yaml.Marshal(progress)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ err = os.WriteFile(filepath.Join("../../data/en/translation-progress.yaml"), progressYaml, 0644)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+}