diff --git a/go.sum b/go.sum index 1fd5178da..0945cf3ce 100644 --- a/go.sum +++ b/go.sum @@ -79,7 +79,6 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c= golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/v2/cmd/wails/internal/commands/build/build.go b/v2/cmd/wails/internal/commands/build/build.go index c752931f5..2e5c89aa3 100644 --- a/v2/cmd/wails/internal/commands/build/build.go +++ b/v2/cmd/wails/internal/commands/build/build.go @@ -12,8 +12,6 @@ import ( "github.com/wailsapp/wails/v2/internal/system" - "github.com/wailsapp/wails/v2/internal/shell" - "github.com/leaanthony/clir" "github.com/leaanthony/slicer" "github.com/wailsapp/wails/v2/pkg/clilogger" @@ -29,10 +27,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { command := app.NewSubCommand("build", "Builds the application") - // Setup production flag - production := false - command.BoolFlag("production", "Build in production mode", &production) - // Setup pack flag pack := false command.BoolFlag("package", "Create a platform specific package", &pack) @@ -62,7 +56,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { tags := "" command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags) - // Retain assets outputFilename := "" command.StringFlag("o", "Output filename", &outputFilename) @@ -73,9 +66,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { webview2 := "download" command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2) - runDelve := false - command.BoolFlag("delve", "Runs the built binary in delve for debugging", &runDelve) - skipFrontend := false command.BoolFlag("s", "Skips building the frontend", &skipFrontend) @@ -96,12 +86,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { app.PrintBanner() } - // Setup mode - mode := build.Debug - if production { - mode = build.Production - } - // Check platform validPlatformArch := slicer.String([]string{ "darwin", @@ -157,18 +141,13 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { } } - // If we want to use delve we need to compile in DEBUG mode - if runDelve { - mode = build.Debug - } - // Create BuildOptions buildOptions := &build.Options{ Logger: logger, OutputType: outputType, OutputFile: outputFilename, CleanBuildDirectory: cleanBuildDirectory, - Mode: mode, + Mode: build.Production, Pack: pack, LDFlags: ldflags, Compiler: compilerCommand, @@ -178,7 +157,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { CompressFlags: compressFlags, UserTags: userTags, WebView2Strategy: wv2rtstrategy, - RunDelve: runDelve, } // Calculate platform and arch @@ -197,11 +175,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { w := new(tabwriter.Writer) w.Init(os.Stdout, 8, 8, 0, '\t', 0) - buildModeText := "debug" - if production { - buildModeText = "production" - } - // Write out the system information fmt.Fprintf(w, "\n") fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType) @@ -210,7 +183,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) { fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath) fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend) fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress) - fmt.Fprintf(w, "Build Mode: \t%s\n", buildModeText) fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack) fmt.Fprintf(w, "Clean Build Dir: \t%t\n", buildOptions.CleanBuildDirectory) fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags) @@ -242,40 +214,5 @@ func doBuild(buildOptions *build.Options) error { buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String())) buildOptions.Logger.Println("") - if buildOptions.RunDelve { - // Check delve exists - delveExists := shell.CommandExists("dlv") - if !delveExists { - return fmt.Errorf("cannot launch delve (Is it installed?)") - } - - // Get cwd - cwd, err := os.Getwd() - if err != nil { - return err - } - - // Launch delve - buildOptions.Logger.Println("Launching Delve on port 2345...") - cmdArgs := slicer.String([]string{"--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", outputFilename}) - if buildOptions.Verbosity == build.VERBOSE { - buildOptions.Logger.Println("\tRunning: dlv %s", cmdArgs.Join(" ")) - } - stdout, stderr, err := shell.RunCommand(cwd, "dlv", cmdArgs.AsSlice()...) - if buildOptions.Verbosity == build.VERBOSE || err != nil { - trimstdout := strings.TrimSpace(stdout) - if trimstdout != "" { - buildOptions.Logger.Println(trimstdout) - } - trimstderr := strings.TrimSpace(stderr) - if trimstderr != "" { - buildOptions.Logger.Println(trimstderr) - } - } - if err != nil { - return err - } - } - return nil } diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index 096736551..56a61492d 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -3,6 +3,7 @@ package dev import ( "fmt" "github.com/leaanthony/slicer" + "github.com/wailsapp/wails/v2/internal/project" "io" "log" "os" @@ -13,6 +14,7 @@ import ( "syscall" "time" + "github.com/pkg/browser" "github.com/wailsapp/wails/v2/internal/colour" "github.com/fsnotify/fsnotify" @@ -52,7 +54,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand) assetDir := "" - command.StringFlag("assets", "Serve assets from the given directory", &assetDir) + command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir) // extensions to trigger rebuilds extensions := "go" @@ -67,7 +69,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity) loglevel := "" - command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel) + command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel) command.Action(func() error { @@ -76,6 +78,30 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { app.PrintBanner() // TODO: Check you are in a project directory + cwd, err := os.Getwd() + if err != nil { + return err + } + projectConfig, err := project.Load(cwd) + if err != nil { + return err + } + + if projectConfig.AssetDirectory == "" && assetDir == "" { + return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.") + } + + if assetDir != "" && assetDir != projectConfig.AssetDirectory { + projectConfig.AssetDirectory = assetDir + err := projectConfig.Save() + if err != nil { + return err + } + } + + if assetDir == "" && projectConfig.AssetDirectory != "" { + assetDir = projectConfig.AssetDirectory + } watcher, err := fsnotify.NewWatcher() if err != nil { @@ -104,11 +130,20 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { // Do initial build logger.Println("Building application for development...") - newProcess, appBinary, err := restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity, assetDir) + newProcess, appBinary, err := restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity, assetDir, true) + if err != nil { + return err + } if newProcess != nil { debugBinaryProcess = newProcess } + // open browser + err = browser.OpenURL("http://localhost:34115") + if err != nil { + return err + } + if err != nil { return err } @@ -156,7 +191,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { // Do a rebuild // Try and build the app - newBinaryProcess, _, err = restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity, assetDir) + newBinaryProcess, _, err = restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity, assetDir, false) if err != nil { fmt.Printf("Error during build: %s", err.Error()) return @@ -251,11 +286,14 @@ exit: } } -func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, verbosity int, assetDir string) (*process.Process, string, error) { +func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, verbosity int, assetDir string, firstRun bool) (*process.Process, string, error) { appBinary, err := buildApp(logger, ldflags, compilerCommand, verbosity) println() if err != nil { + if firstRun { + return nil, "", err + } LogRed("Build error - continuing to run current version") LogDarkYellow(err.Error()) return nil, "", nil @@ -278,7 +316,7 @@ func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand str args := slicer.StringSlicer{} args.Add("-loglevel", loglevel) if assetDir != "" { - args.Add("-assets", assetDir) + args.Add("-assetdir", assetDir) } if len(passthruArgs) > 0 { @@ -308,15 +346,15 @@ func buildApp(logger *clilogger.CLILogger, ldflags string, compilerCommand strin // Create BuildOptions buildOptions := &build.Options{ - Logger: logger, - OutputType: "dev", - Mode: build.Debug, - Pack: false, - Platform: runtime.GOOS, - LDFlags: ldflags, - Compiler: compilerCommand, - OutputFile: outputFile, - IgnoreFrontend: true, + Logger: logger, + OutputType: "dev", + Mode: build.Dev, + Pack: false, + Platform: runtime.GOOS, + LDFlags: ldflags, + Compiler: compilerCommand, + //OutputFile: outputFile, + IgnoreFrontend: false, Verbosity: verbosity, } diff --git a/v2/go.mod b/v2/go.mod index 6232892a3..229b70d30 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -8,13 +8,15 @@ require ( github.com/fsnotify/fsnotify v1.4.9 github.com/go-git/go-billy/v5 v5.2.0 // indirect github.com/go-git/go-git/v5 v5.3.0 + github.com/gofiber/fiber/v2 v2.17.0 + github.com/gofiber/websocket/v2 v2.0.8 github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.1.2 // indirect github.com/gorilla/websocket v1.4.1 github.com/imdario/mergo v0.3.12 github.com/jackmordaunt/icns v1.0.0 github.com/jchv/go-webview2 v0.0.0-20210720204005-cbb937ae0f7f - github.com/klauspost/compress v1.11.3 // indirect + github.com/klauspost/compress v1.12.2 // indirect github.com/leaanthony/clir v1.0.4 github.com/leaanthony/debme v1.2.1 github.com/leaanthony/go-ansi-parser v1.0.1 @@ -26,6 +28,7 @@ require ( github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0 github.com/matryer/is v1.4.0 github.com/olekukonko/tablewriter v0.0.4 + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 // indirect github.com/tadvi/winc v0.0.0-20190405175627-5454f291903d @@ -37,20 +40,21 @@ require ( github.com/wzshiming/ctc v1.2.3 github.com/xyproto/xpm v1.2.1 github.com/ztrue/tracerr v0.3.0 - golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/mod v0.4.1 // indirect - golang.org/x/net v0.0.0-20210326060303-6b1517762897 - golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 - golang.org/x/text v0.3.5 // indirect + golang.org/x/net v0.0.0-20210510120150-4163338589ed + golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71 golang.org/x/tools v0.1.0 nhooyr.io/websocket v1.8.6 ) require ( github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/andybalholm/brotli v1.0.2 // indirect github.com/emirpasic/gods v1.12.0 // indirect + github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-ole/go-ole v1.2.4 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect @@ -59,10 +63,14 @@ require ( github.com/mattn/go-runewidth v0.0.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/tidwall/gjson v1.8.0 // indirect github.com/tidwall/match v1.0.3 // indirect github.com/tidwall/pretty v1.1.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.28.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect diff --git a/v2/go.sum b/v2/go.sum index 4bf78f4ab..8a11fdb7c 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -5,18 +5,24 @@ github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI= +github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -36,8 +42,10 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbK github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -51,15 +59,22 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= +github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= +github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k= +github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -74,18 +89,24 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU= github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= -github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -127,18 +148,25 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -165,6 +193,15 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4= +github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c= github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28= github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY= @@ -173,6 +210,7 @@ github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg= github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY= +github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= @@ -181,8 +219,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -191,11 +229,14 @@ golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -213,15 +254,19 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71 h1:X/2sJAybVknnUnV7AD2HdT6rm2p5BP6eH2j+igduWgk= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/v2/internal/app/debug.go b/v2/internal/app/debug.go index ecb7b775d..3a6a6916f 100644 --- a/v2/internal/app/debug.go +++ b/v2/internal/app/debug.go @@ -1,5 +1,5 @@ -//go:build debug -// +build debug +//go:build dev +// +build dev package app diff --git a/v2/internal/app/production.go b/v2/internal/app/production.go index ce083cb68..9a2554826 100644 --- a/v2/internal/app/production.go +++ b/v2/internal/app/production.go @@ -1,4 +1,5 @@ -// +build !debug +//go:build production +// +build production package app diff --git a/v2/internal/appng/app.go b/v2/internal/appng/app.go deleted file mode 100644 index abeaf19a3..000000000 --- a/v2/internal/appng/app.go +++ /dev/null @@ -1,97 +0,0 @@ -package appng - -import ( - "context" - "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/internal/menumanager" - "github.com/wailsapp/wails/v2/internal/signal" - "github.com/wailsapp/wails/v2/pkg/options" -) - -// App defines a Wails application structure -type App struct { - frontend frontend.Frontend - logger *logger.Logger - signal *signal.Manager - options *options.App - - menuManager *menumanager.Manager - - // Indicates if the app is in debug mode - debug bool - - // Startup/Shutdown - startupCallback func(ctx context.Context) - shutdownCallback func() - ctx context.Context -} - -func (a *App) Run() error { - err := a.frontend.Run(a.ctx) - if a.shutdownCallback != nil { - a.shutdownCallback() - } - return err -} - -// CreateApp creates the app! -func CreateApp(appoptions *options.App) (*App, error) { - var err error - - ctx := context.Background() - - // Merge default options - options.MergeDefaults(appoptions) - - // Set up logger - myLogger := logger.New(appoptions.Logger) - myLogger.SetLogLevel(appoptions.LogLevel) - - // Preflight Checks - err = PreflightChecks(appoptions, myLogger) - if err != nil { - return nil, err - } - - // Create the menu manager - menuManager := menumanager.NewManager() - - // Process the application menu - appMenu := options.GetApplicationMenu(appoptions) - err = menuManager.SetApplicationMenu(appMenu) - if err != nil { - return nil, err - } - - // Create binding exemptions - Ugly hack. There must be a better way - bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown} - appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) - eventHandler := runtime.NewEvents(myLogger) - ctx = context.WithValue(ctx, "events", eventHandler) - messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler) - - appFrontend := NewFrontend(appoptions, myLogger, appBindings, messageDispatcher) - eventHandler.SetFrontend(appFrontend) - - result := &App{ - ctx: ctx, - frontend: appFrontend, - logger: myLogger, - menuManager: menuManager, - startupCallback: appoptions.Startup, - shutdownCallback: appoptions.Shutdown, - } - - result.options = appoptions - - result.SetupFlags() - result.Init() - result.ctx = context.WithValue(result.ctx, "debug", result.debug) - - return result, nil - -} diff --git a/v2/internal/appng/app_debug.go b/v2/internal/appng/app_debug.go deleted file mode 100644 index 0da4897fe..000000000 --- a/v2/internal/appng/app_debug.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build debug -// +build debug - -package appng - -func (a *App) SetupFlags() { - a.debug = true -} diff --git a/v2/internal/appng/app_default.go b/v2/internal/appng/app_default.go deleted file mode 100644 index 2c728779d..000000000 --- a/v2/internal/appng/app_default.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !windows && !dev - -package appng - -import ( - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func PreflightChecks(_ *options.App, _ *logger.Logger) error { - return nil -} - -func (a *App) Init() { -} \ No newline at end of file diff --git a/v2/internal/appng/app_dev.go b/v2/internal/appng/app_dev.go index f62c4c620..62fb80fc0 100644 --- a/v2/internal/appng/app_dev.go +++ b/v2/internal/appng/app_dev.go @@ -1,4 +1,5 @@ //go:build dev +// +build dev package appng @@ -8,35 +9,112 @@ import ( "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/devserver" + "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/signal" pkglogger "github.com/wailsapp/wails/v2/pkg/logger" "github.com/wailsapp/wails/v2/pkg/options" - "os" ) -func NewFrontend(appoptions *options.App, myLogger *logger.Logger, bindings *binding.Bindings, dispatcher frontend.Dispatcher) frontend.Frontend { - return devserver.NewFrontend(appoptions, myLogger, bindings, dispatcher) +// App defines a Wails application structure +type App struct { + frontend frontend.Frontend + logger *logger.Logger + signal *signal.Manager + options *options.App + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // Startup/Shutdown + startupCallback func(ctx context.Context) + shutdownCallback func() + ctx context.Context } -func PreflightChecks(options *options.App, logger *logger.Logger) error { - return nil +func (a *App) Run() error { + err := a.frontend.Run(a.ctx) + if a.shutdownCallback != nil { + a.shutdownCallback() + } + return err } -func (a *App) Init() { +// CreateApp creates the app! +func CreateApp(appoptions *options.App) (*App, error) { + var err error + + ctx := context.WithValue(context.Background(), "debug", true) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + // Check for CLI Flags assetdir := flag.String("assetdir", "", "Directory to serve assets") loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error") flag.Parse() if assetdir != nil && *assetdir != "" { - a.ctx = context.WithValue(a.ctx, "assetdir", *assetdir) + ctx = context.WithValue(ctx, "assetdir", *assetdir) } if loglevel != nil && *loglevel != "" { level, err := pkglogger.StringToLogLevel(*loglevel) if err != nil { - println("ERROR:", err.Error()) - os.Exit(1) + return nil, err } - a.logger.SetLogLevel(level) + myLogger.SetLogLevel(level) } + // Attach logger to context + ctx = context.WithValue(ctx, "logger", myLogger) + + // Preflight checks + err = PreflightChecks(appoptions, myLogger) + if err != nil { + return nil, err + } + + // Merge default options + options.MergeDefaults(appoptions) + + var menuManager *menumanager.Manager + + // Process the application menu + if appoptions.Menu != nil { + // Create the menu manager + menuManager = menumanager.NewManager() + err = menuManager.SetApplicationMenu(appoptions.Menu) + if err != nil { + return nil, err + } + } + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown} + appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) + eventHandler := runtime.NewEvents(myLogger) + ctx = context.WithValue(ctx, "events", eventHandler) + messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler) + + appFrontend := devserver.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher, menuManager) + eventHandler.SetFrontend(appFrontend) + + result := &App{ + ctx: ctx, + frontend: appFrontend, + logger: myLogger, + menuManager: menuManager, + startupCallback: appoptions.Startup, + shutdownCallback: appoptions.Shutdown, + debug: true, + } + + result.options = appoptions + + return result, nil + } diff --git a/v2/internal/appng/app_production.go b/v2/internal/appng/app_production.go index 303bec415..1b06714c8 100644 --- a/v2/internal/appng/app_production.go +++ b/v2/internal/appng/app_production.go @@ -3,9 +3,98 @@ package appng -func (a *App) SetupFlags() { - a.debug = false +import ( + "context" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct { + frontend frontend.Frontend + logger *logger.Logger + signal *signal.Manager + options *options.App + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // Startup/Shutdown + startupCallback func(ctx context.Context) + shutdownCallback func() + ctx context.Context } -func (a *App) Init() { -} \ No newline at end of file +func (a *App) Run() error { + err := a.frontend.Run(a.ctx) + if a.shutdownCallback != nil { + a.shutdownCallback() + } + return err +} + +// CreateApp creates the app! +func CreateApp(appoptions *options.App) (*App, error) { + var err error + + ctx := context.Background() + + // Merge default options + options.MergeDefaults(appoptions) + + // Set up logger + myLogger := logger.New(appoptions.Logger) + myLogger.SetLogLevel(appoptions.LogLevel) + + // Preflight Checks + err = PreflightChecks(appoptions, myLogger) + if err != nil { + return nil, err + } + + // Create the menu manager + menuManager := menumanager.NewManager() + + // Process the application menu + if appoptions.Menu != nil { + err = menuManager.SetApplicationMenu(appoptions.Menu) + if err != nil { + return nil, err + } + } + + // Create binding exemptions - Ugly hack. There must be a better way + bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown} + appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) + eventHandler := runtime.NewEvents(myLogger) + ctx = context.WithValue(ctx, "events", eventHandler) + messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler) + + appFrontend := NewFrontend(appoptions, myLogger, appBindings, messageDispatcher, menuManager) + eventHandler.SetFrontend(appFrontend) + + result := &App{ + ctx: ctx, + frontend: appFrontend, + logger: myLogger, + menuManager: menuManager, + startupCallback: appoptions.Startup, + shutdownCallback: appoptions.Shutdown, + debug: false, + } + + result.options = appoptions + + result.ctx = context.WithValue(result.ctx, "debug", result.debug) + + return result, nil + +} diff --git a/v2/internal/appng/app_windows.go b/v2/internal/appng/app_windows.go index 6265a1b70..2c334e241 100644 --- a/v2/internal/appng/app_windows.go +++ b/v2/internal/appng/app_windows.go @@ -1,20 +1,13 @@ -//go:build windows && desktop +//go:build windows package appng import ( - "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime" - "github.com/wailsapp/wails/v2/internal/frontend" - "github.com/wailsapp/wails/v2/internal/frontend/windows" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" ) -func NewFrontend(appoptions *options.App, myLogger *logger.Logger, bindings *binding.Bindings, dispatcher frontend.Dispatcher) frontend.Frontend { - return windows.NewFrontend(appoptions, myLogger, bindings, dispatcher) -} - func PreflightChecks(options *options.App, logger *logger.Logger) error { _ = options @@ -32,6 +25,3 @@ func PreflightChecks(options *options.App, logger *logger.Logger) error { return nil } - -func (a *App) Init() { -} \ No newline at end of file diff --git a/v2/internal/frontend/assetserver/assetserver_desktop.go b/v2/internal/frontend/assetserver/assetserver_desktop.go index 59af215a2..962f5f9ff 100644 --- a/v2/internal/frontend/assetserver/assetserver_desktop.go +++ b/v2/internal/frontend/assetserver/assetserver_desktop.go @@ -1,54 +1,62 @@ -//go:build desktop -// +build desktop - package assetserver import ( "bytes" + "context" "embed" "fmt" "github.com/leaanthony/debme" "github.com/leaanthony/slicer" "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/logger" "io/fs" "net/http" "path/filepath" "strings" ) -type AssetServer struct { +type DesktopAssetServer struct { assets debme.Debme indexFile []byte runtimeJS []byte + assetdir string + logger *logger.Logger } -func NewAssetServer(assets embed.FS, bindingsJSON string) (*AssetServer, error) { - result := &AssetServer{} +func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON string) (*DesktopAssetServer, error) { + result := &DesktopAssetServer{} + + _logger := ctx.Value("logger") + if _logger != nil { + result.logger = _logger.(*logger.Logger) + } + + _assetdir := ctx.Value("assetdir") + if _assetdir != nil { + result.assetdir = _assetdir.(string) + absdir, err := filepath.Abs(result.assetdir) + if err != nil { + return nil, err + } + result.LogInfo("Loading assets from: %s", absdir) + } + var buffer bytes.Buffer - buffer.Write(runtime.IPCJS) buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") - buffer.Write(runtime.RuntimeJS) + buffer.Write(runtime.RuntimeDesktopJS) result.runtimeJS = buffer.Bytes() err := result.init(assets) return result, err } -func (a *AssetServer) IndexHTML() string { - return string(a.indexFile) +func (d *DesktopAssetServer) LogInfo(message string, args ...interface{}) { + if d.logger != nil { + d.logger.Info("[DesktopAssetServer] "+message, args...) + } } -func injectScript(input string, script string) ([]byte, error) { - splits := strings.Split(input, "
") - if len(splits) != 2 { - return nil, fmt.Errorf("unable to locate a tag in your html") - } - - var result bytes.Buffer - result.WriteString(splits[0]) - result.WriteString("") - result.WriteString(script) - result.WriteString(splits[1]) - return result.Bytes(), nil +func (d *DesktopAssetServer) SetAssetDir(assetdir string) { + d.assetdir = assetdir } func processAssets(assets embed.FS) (debme.Debme, error) { @@ -84,7 +92,7 @@ func processAssets(assets embed.FS) (debme.Debme, error) { return debme.FS(assets, path) } -func (a *AssetServer) init(assets embed.FS) error { +func (a *DesktopAssetServer) init(assets embed.FS) error { var err error a.assets, err = processAssets(assets) @@ -99,10 +107,14 @@ func (a *AssetServer) init(assets embed.FS) error { if err != nil { return err } + a.indexFile, err = injectScript(string(a.indexFile), ``) + if err != nil { + return err + } return nil } -func (a *AssetServer) Load(filename string) ([]byte, string, error) { +func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) { var content []byte var err error switch filename { @@ -111,9 +123,9 @@ func (a *AssetServer) Load(filename string) ([]byte, string, error) { case "/wails/runtime.js": content = a.runtimeJS case "/wails/ipc.js": - content = runtime.IPCJS + content = runtime.DesktopIPC default: - content, err = a.assets.ReadFile(filename) + content, err = a.ReadFile(filename) } if err != nil { return nil, "", err diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_dev.go b/v2/internal/frontend/assetserver/assetserver_desktop_dev.go new file mode 100644 index 000000000..0ce9010d3 --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_desktop_dev.go @@ -0,0 +1,13 @@ +//go:build dev + +package assetserver + +import ( + "os" + "path/filepath" +) + +func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) { + a.LogInfo("Loading file from disk: %s", filename) + return os.ReadFile(filepath.Join(a.assetdir, filename)) +} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_production.go b/v2/internal/frontend/assetserver/assetserver_desktop_production.go new file mode 100644 index 000000000..fb09ee1a3 --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_desktop_production.go @@ -0,0 +1,7 @@ +//go:build production + +package assetserver + +func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) { + return a.assets.ReadFile(filename) +} diff --git a/v2/internal/frontend/assetserver/assetserver_dev.go b/v2/internal/frontend/assetserver/assetserver_dev.go new file mode 100644 index 000000000..a84481869 --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_dev.go @@ -0,0 +1,89 @@ +//go:build dev +// +build dev + +package assetserver + +import ( + "bytes" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/pkg/options" + "path/filepath" +) + +/* + +The assetserver for dev serves assets from disk. +It injects a websocket based IPC script into `index.html`. + +*/ + +import ( + "net/http" + "os" +) + +type AssetServer struct { + indexFile []byte + runtimeJS []byte + assetdir string + appOptions *options.App +} + +func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) { + result := &AssetServer{ + assetdir: assetdir, + appOptions: appOptions, + } + + err := result.init() + if err != nil { + return nil, err + } + + var buffer bytes.Buffer + buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") + buffer.Write(runtime.RuntimeDesktopJS) + result.runtimeJS = buffer.Bytes() + err = result.init() + return result, err +} + +func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) { + return os.ReadFile(filepath.Join(a.assetdir, filename)) +} + +func (a *AssetServer) init() error { + indexHTML, err := a.loadFileFromDisk("index.html") + if err != nil { + return err + } + a.indexFile, err = injectScript(string(indexHTML), ``) + if err != nil { + return err + } + a.indexFile, err = injectScript(string(a.indexFile), ``) + if err != nil { + return err + } + return nil +} + +func (a *AssetServer) Load(filename string) ([]byte, string, error) { + var content []byte + var err error + switch filename { + case "/": + content = a.indexFile + case "/wails/runtime.js": + content = a.runtimeJS + case "/wails/ipc.js": + content = runtime.WebsocketIPC + default: + content, err = a.loadFileFromDisk(filename) + } + if err != nil { + return nil, "", err + } + mimeType := http.DetectContentType(content) + return content, mimeType, nil +} diff --git a/v2/internal/frontend/assetserver/common.go b/v2/internal/frontend/assetserver/common.go new file mode 100644 index 000000000..c66b66e09 --- /dev/null +++ b/v2/internal/frontend/assetserver/common.go @@ -0,0 +1,21 @@ +package assetserver + +import ( + "bytes" + "fmt" + "strings" +) + +func injectScript(input string, script string) ([]byte, error) { + splits := strings.Split(input, "") + if len(splits) != 2 { + return nil, fmt.Errorf("unable to locate a tag in your html") + } + + var result bytes.Buffer + result.WriteString(splits[0]) + result.WriteString("") + result.WriteString(script) + result.WriteString(splits[1]) + return result.Bytes(), nil +} diff --git a/v2/internal/frontend/desktop/desktop_windows.go b/v2/internal/frontend/desktop/desktop_windows.go new file mode 100644 index 000000000..f3c8e05d9 --- /dev/null +++ b/v2/internal/frontend/desktop/desktop_windows.go @@ -0,0 +1,16 @@ +//go:build windows + +package desktop + +import ( + "context" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/pkg/options" +) + +func NewFrontend(ctx context.Context, appoptions *options.App, logger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) frontend.Frontend { + return windows.NewFrontend(ctx, appoptions, logger, appBindings, dispatcher) +} diff --git a/v2/internal/frontend/windows/dialog.go b/v2/internal/frontend/desktop/windows/dialog.go similarity index 99% rename from v2/internal/frontend/windows/dialog.go rename to v2/internal/frontend/desktop/windows/dialog.go index cdc931e13..77e2629b7 100644 --- a/v2/internal/frontend/windows/dialog.go +++ b/v2/internal/frontend/desktop/windows/dialog.go @@ -1,3 +1,5 @@ +//go:build windows + package windows import "C" diff --git a/v2/internal/frontend/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go similarity index 82% rename from v2/internal/frontend/windows/frontend.go rename to v2/internal/frontend/desktop/windows/frontend.go index 20ac058e9..aed85625e 100644 --- a/v2/internal/frontend/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -1,3 +1,5 @@ +//go:build windows + package windows import ( @@ -29,13 +31,14 @@ type Frontend struct { debug bool // Assets - assets *assetserver.AssetServer + assets *assetserver.DesktopAssetServer // main window handle mainWindow *Window minWidth, minHeight, maxWidth, maxHeight int bindings *binding.Bindings dispatcher frontend.Dispatcher + servingFromDisk bool } func (f *Frontend) Run(ctx context.Context) error { @@ -183,6 +186,11 @@ func (f *Frontend) setupChromium() { if err != nil { log.Fatal(err) } + //c2, err := chromium.GetWebView2Controller2() + //err = c2.PutDefaultBackgroundColor(edge.COREWEBVIEW2_COLOR{R: 255, G: 0, B: 0, A: 255}) + //if err != nil { + // log.Fatal(err) + //} chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL) chromium.Navigate("file://wails/") f.chromium = chromium @@ -225,7 +233,11 @@ func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, arg } env := f.chromium.Environment() - response, err := env.CreateWebResourceResponse(content, 200, "OK", "Content-Type: "+mimeType) + headers := "Content-Type: " + mimeType + if f.servingFromDisk { + headers += "\nPragma: no-cache" + } + response, err := env.CreateWebResourceResponse(content, 200, "OK", headers) if err != nil { return } @@ -245,10 +257,21 @@ func (f *Frontend) processMessage(message string) { } return } - err := f.dispatcher.ProcessMessage(message) + result, err := f.dispatcher.ProcessMessage(message) if err != nil { f.logger.Error(err.Error()) } + if result == "" { + return + } + + switch result[0] { + case 'c': + // Callback from a method call + f.Callback(result[1:]) + default: + f.logger.Info("Unknown message returned from dispatcher: %+v", result) + } } func (f *Frontend) Callback(message string) { @@ -265,24 +288,31 @@ func (f *Frontend) startDrag() error { return nil } -func NewFrontend(appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { +func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { result := &Frontend{ frontendOptions: appoptions, logger: myLogger, bindings: appBindings, dispatcher: dispatcher, + ctx: ctx, } - // Setup the callback handler (Go -> JS) - dispatcher.SetCallbackHandler(result.Callback) + // Check if we have been given a directory to serve assets from. + // If so, this means we are in dev mode and are serving assets off disk. + // We indicate this through the `servingFromDisk` flag to ensure requests + // aren't cached by WebView2 in dev mode + _assetdir := ctx.Value("assetdir") + if _assetdir != nil { + result.servingFromDisk = true + } - if appoptions.Windows.Assets != nil { + if appoptions.Assets != nil { bindingsJSON, err := appBindings.ToJSON() if err != nil { log.Fatal(err) } - assets, err := assetserver.NewAssetServer(*appoptions.Windows.Assets, bindingsJSON) + assets, err := assetserver.NewDesktopAssetServer(ctx, *appoptions.Assets, bindingsJSON) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/windows/keys.go b/v2/internal/frontend/desktop/windows/keys.go similarity index 99% rename from v2/internal/frontend/windows/keys.go rename to v2/internal/frontend/desktop/windows/keys.go index 072f2eab0..4a7916b4c 100644 --- a/v2/internal/frontend/windows/keys.go +++ b/v2/internal/frontend/desktop/windows/keys.go @@ -1,3 +1,5 @@ +//go:build windows + package windows import ( diff --git a/v2/internal/frontend/windows/menu.go b/v2/internal/frontend/desktop/windows/menu.go similarity index 99% rename from v2/internal/frontend/windows/menu.go rename to v2/internal/frontend/desktop/windows/menu.go index 3aa0ba068..43425603a 100644 --- a/v2/internal/frontend/windows/menu.go +++ b/v2/internal/frontend/desktop/windows/menu.go @@ -1,3 +1,5 @@ +//go:build windows + package windows import ( diff --git a/v2/internal/frontend/windows/window.go b/v2/internal/frontend/desktop/windows/window.go similarity index 96% rename from v2/internal/frontend/windows/window.go rename to v2/internal/frontend/desktop/windows/window.go index 820324820..3c4b2aaa7 100644 --- a/v2/internal/frontend/windows/window.go +++ b/v2/internal/frontend/desktop/windows/window.go @@ -1,3 +1,5 @@ +//go:build windows + package windows import ( @@ -64,8 +66,8 @@ func NewWindow(parent winc.Controller, options *options.App) *Window { result.Fullscreen() } - if options.Windows.Menu != nil { - result.SetApplicationMenu(options.Windows.Menu) + if options.Menu != nil { + result.SetApplicationMenu(options.Menu) } return result diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 7395f2848..0616468cb 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -2,153 +2,341 @@ package devserver import ( "context" - "embed" + "encoding/json" + "fmt" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/websocket/v2" "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/frontend/assetserver" + "github.com/wailsapp/wails/v2/internal/frontend/desktop" "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" - "net/http" + "io/fs" + "log" + "path/filepath" + "strings" + "sync" + "time" ) -//go:embed runtime_debug_windows.js -var wailsFS embed.FS - type DevServer struct { - server *http.Server + server *fiber.App + ctx context.Context + appoptions *options.App + logger *logger.Logger + appBindings *binding.Bindings + dispatcher frontend.Dispatcher + assetServer *assetserver.AssetServer + socketMutex sync.Mutex + websocketClients map[*websocket.Conn]struct{} + menuManager *menumanager.Manager + starttime string + + // Desktop frontend + desktopFrontend frontend.Frontend } -func (d DevServer) Run(ctx context.Context) error { - wailsfs := http.FileServer(http.FS(wailsFS)) - http.Handle("/wails/", http.StripPrefix("/wails", wailsfs)) +func (d *DevServer) Run(ctx context.Context) error { + d.ctx = ctx - assetdir := ctx.Value("assetdir") - if assetdir != nil { - println("Serving assets from:", assetdir.(string)) - fs := http.FileServer(http.Dir(assetdir.(string))) - http.Handle("/", interceptor(fs)) + d.server.Get("/wails/ipc", websocket.New(func(c *websocket.Conn) { + d.newWebsocketSession(c) + // websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index + var ( + mt int + msg []byte + err error + ) + + for { + if mt, msg, err = c.ReadMessage(); err != nil { + break + } + d.logger.Info("[%p] %s", c, msg) + if string(msg) == "drag" { + continue + } + + if len(msg) > 2 && strings.HasPrefix(string(msg), "EE") { + d.broadcast(string(msg)[2:]) + //d.broadcastExcludingSender(string(msg)[2:], c) + continue + } + + result, err := d.dispatcher.ProcessMessage(string(msg)) + if err != nil { + d.logger.Error(err.Error()) + } + if result != "" { + if err = c.WriteMessage(mt, []byte(result)); err != nil { + log.Println("write:", err) + break + } + } + + } + })) + + _assetdir := ctx.Value("assetdir") + if _assetdir == nil { + return fmt.Errorf("no assetdir provided") } - err := d.server.ListenAndServe() - if err != nil && err != http.ErrServerClosed { + if _assetdir != nil { + assetdir := _assetdir.(string) + bindingsJSON, err := d.appBindings.ToJSON() + if err != nil { + log.Fatal(err) + } + d.assetServer, err = assetserver.NewAssetServer(assetdir, bindingsJSON, d.appoptions) + if err != nil { + log.Fatal(err) + } + absdir, err := filepath.Abs(assetdir) + if err != nil { + return err + } + d.LogInfo("Serving assets from: %s", absdir) + } + + d.server.Get("*", d.loadAsset) + + // Start server + go func(server *fiber.App, log *logger.Logger) { + err := server.Listen(":34115") + if err != nil { + log.Error(err.Error()) + } + d.LogInfo("Shutdown completed") + }(d.server, d.logger) + + d.LogInfo("Serving application at http://localhost:34115") + + // Launch desktop app + err := d.desktopFrontend.Run(ctx) + d.LogInfo("Starting shutdown") + err2 := d.server.Shutdown() + if err2 != nil { + d.logger.Error(err.Error()) + } + + return err +} + +func (d *DevServer) Quit() { + d.desktopFrontend.Quit() +} + +func (d *DevServer) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { + return d.desktopFrontend.OpenFileDialog(dialogOptions) +} + +func (d *DevServer) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { + return d.OpenMultipleFilesDialog(dialogOptions) +} + +func (d *DevServer) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { + return d.OpenDirectoryDialog(dialogOptions) +} + +func (d *DevServer) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { + return d.desktopFrontend.SaveFileDialog(dialogOptions) +} + +func (d *DevServer) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { + return d.desktopFrontend.MessageDialog(dialogOptions) +} + +func (d *DevServer) WindowSetTitle(title string) { + d.desktopFrontend.WindowSetTitle(title) +} + +func (d *DevServer) WindowShow() { + d.desktopFrontend.WindowShow() +} + +func (d *DevServer) WindowHide() { + d.desktopFrontend.WindowHide() +} + +func (d *DevServer) WindowCenter() { + d.desktopFrontend.WindowCenter() +} + +func (d *DevServer) WindowMaximise() { + d.desktopFrontend.WindowMaximise() +} + +func (d *DevServer) WindowUnmaximise() { + d.desktopFrontend.WindowUnmaximise() +} + +func (d *DevServer) WindowMinimise() { + d.desktopFrontend.WindowMinimise() +} + +func (d *DevServer) WindowUnminimise() { + d.desktopFrontend.WindowUnminimise() +} + +func (d *DevServer) WindowSetPos(x int, y int) { + d.desktopFrontend.WindowSetPos(x, y) +} + +func (d *DevServer) WindowGetPos() (int, int) { + return d.desktopFrontend.WindowGetPos() +} + +func (d *DevServer) WindowSetSize(width int, height int) { + d.desktopFrontend.WindowSetSize(width, height) +} + +func (d *DevServer) WindowGetSize() (int, int) { + return d.desktopFrontend.WindowGetSize() +} + +func (d *DevServer) WindowSetMinSize(width int, height int) { + d.desktopFrontend.WindowSetMinSize(width, height) +} + +func (d *DevServer) WindowSetMaxSize(width int, height int) { + d.desktopFrontend.WindowSetMaxSize(width, height) +} + +func (d *DevServer) WindowFullscreen() { + d.desktopFrontend.WindowFullscreen() +} + +func (d *DevServer) WindowUnFullscreen() { + d.desktopFrontend.WindowUnFullscreen() +} + +func (d *DevServer) WindowSetColour(colour int) { + d.desktopFrontend.WindowSetColour(colour) +} + +func (d *DevServer) SetApplicationMenu(menu *menu.Menu) { + d.desktopFrontend.SetApplicationMenu(menu) +} + +func (d *DevServer) UpdateApplicationMenu() { + d.desktopFrontend.UpdateApplicationMenu() +} + +func (d *DevServer) Notify(name string, data ...interface{}) { + d.desktopFrontend.Notify(name, data...) + // Notify Websockets.... + d.notify(name, data...) +} + +func (d *DevServer) loadAsset(ctx *fiber.Ctx) error { + data, mimetype, err := d.assetServer.Load(ctx.Path()) + if err != nil { + _, ok := err.(*fs.PathError) + if !ok { + return err + } + err := ctx.SendStatus(404) + if err != nil { + return err + } + return nil + } + err = ctx.SendStatus(200) + if err != nil { + return err + } + ctx.Set("Content-Type", mimetype) + err = ctx.Send(data) + if err != nil { return err } - return nil } -func (d DevServer) Quit() { - panic("implement me") +func (d *DevServer) LogInfo(message string, args ...interface{}) { + d.logger.Info("[DevServer] "+message, args...) } -func (d DevServer) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - panic("implement me") -} - -func (d DevServer) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { - panic("implement me") -} - -func (d DevServer) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - panic("implement me") -} - -func (d DevServer) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { - panic("implement me") -} - -func (d DevServer) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { - panic("implement me") -} - -func (d DevServer) WindowSetTitle(title string) { - panic("implement me") -} - -func (d DevServer) WindowShow() { - panic("implement me") -} - -func (d DevServer) WindowHide() { - panic("implement me") -} - -func (d DevServer) WindowCenter() { - panic("implement me") -} - -func (d DevServer) WindowMaximise() { - panic("implement me") -} - -func (d DevServer) WindowUnmaximise() { - panic("implement me") -} - -func (d DevServer) WindowMinimise() { - panic("implement me") -} - -func (d DevServer) WindowUnminimise() { - panic("implement me") -} - -func (d DevServer) WindowSetPos(x int, y int) { - panic("implement me") -} - -func (d DevServer) WindowGetPos() (int, int) { - panic("implement me") -} - -func (d DevServer) WindowSetSize(width int, height int) { - panic("implement me") -} - -func (d DevServer) WindowGetSize() (int, int) { - panic("implement me") -} - -func (d DevServer) WindowSetMinSize(width int, height int) { - panic("implement me") -} - -func (d DevServer) WindowSetMaxSize(width int, height int) { - panic("implement me") -} - -func (d DevServer) WindowFullscreen() { - panic("implement me") -} - -func (d DevServer) WindowUnFullscreen() { - panic("implement me") -} - -func (d DevServer) WindowSetColour(colour int) { - panic("implement me") -} - -func (d DevServer) SetApplicationMenu(menu *menu.Menu) { - panic("implement me") -} - -func (d DevServer) UpdateApplicationMenu() { - panic("implement me") -} - -func (d DevServer) Notify(name string, data ...interface{}) { - panic("implement me") -} - -func interceptor(nextHandler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - println("Serving file from disk:", r.RequestURI) - nextHandler.ServeHTTP(w, r) +func (d *DevServer) newWebsocketSession(c *websocket.Conn) { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + c.SetCloseHandler(func(code int, text string) error { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + delete(d.websocketClients, c) + d.LogInfo(fmt.Sprintf("Websocket client %p disconnected", c)) + return nil }) + d.websocketClients[c] = struct{}{} + d.LogInfo(fmt.Sprintf("Websocket client %p connected", c)) + // Send the starttime to see if the client needs to reload + c.WriteMessage(websocket.TextMessage, []byte("T"+d.starttime)) } -func NewFrontend(appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *DevServer { - result := &DevServer{} - result.server = &http.Server{Addr: ":34115"} +type EventNotify struct { + Name string `json:"name"` + Data []interface{} `json:"data"` +} + +func (d *DevServer) broadcast(message string) { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + for client := range d.websocketClients { + err := client.WriteMessage(websocket.TextMessage, []byte(message)) + if err != nil { + d.logger.Error(err.Error()) + return + } + } +} + +func (d *DevServer) notify(name string, data ...interface{}) { + // Notify + notification := EventNotify{ + Name: name, + Data: data, + } + payload, err := json.Marshal(notification) + if err != nil { + d.logger.Error(err.Error()) + return + } + d.broadcast("n" + string(payload)) +} + +func (d *DevServer) broadcastExcludingSender(message string, sender *websocket.Conn) { + d.socketMutex.Lock() + defer d.socketMutex.Unlock() + for client := range d.websocketClients { + if client == sender { + continue + } + err := client.WriteMessage(websocket.TextMessage, []byte(message)) + if err != nil { + d.logger.Error(err.Error()) + return + } + } +} + +func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher, menuManager *menumanager.Manager) *DevServer { + result := &DevServer{ + ctx: ctx, + desktopFrontend: desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, dispatcher), + appoptions: appoptions, + logger: myLogger, + appBindings: appBindings, + dispatcher: dispatcher, + server: fiber.New(fiber.Config{ + ReadTimeout: time.Second * 5, + DisableStartupMessage: true, + }), + menuManager: menuManager, + websocketClients: make(map[*websocket.Conn]struct{}), + starttime: time.Now().String(), + } return result } diff --git a/v2/internal/frontend/devserver/runtime_debug_windows.js b/v2/internal/frontend/devserver/runtime_debug_windows.js deleted file mode 100644 index 0f231bde0..000000000 --- a/v2/internal/frontend/devserver/runtime_debug_windows.js +++ /dev/null @@ -1,304 +0,0 @@ -(() => { - var __defProp = Object.defineProperty; - var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); - var __export = (target, all) => { - __markAsModule(target); - for (var name in all) - __defProp(target, name, {get: all[name], enumerable: true}); - }; - - // desktop/log.js - var log_exports = {}; - __export(log_exports, { - LogDebug: () => LogDebug, - LogError: () => LogError, - LogFatal: () => LogFatal, - LogInfo: () => LogInfo, - LogLevel: () => LogLevel, - LogPrint: () => LogPrint, - LogTrace: () => LogTrace, - LogWarning: () => LogWarning, - SetLogLevel: () => SetLogLevel - }); - - // desktop/ipc.js - var listeners = []; - - function SendMessage(message) { - if (true) { - window.chrome.webview.postMessage(message); - } else if (false) { - window.blah(); - } else { - console.error("Unsupported Platform"); - } - if (listeners.length > 0) { - for (let i = 0; i < listeners.length; i++) { - listeners[i](message); - } - } - } - - // desktop/log.js - function sendLogMessage(level, message) { - SendMessage("L" + level + message); - } - - function LogTrace(message) { - sendLogMessage("T", message); - } - - function LogPrint(message) { - sendLogMessage("P", message); - } - - function LogDebug(message) { - sendLogMessage("D", message); - } - - function LogInfo(message) { - sendLogMessage("I", message); - } - - function LogWarning(message) { - sendLogMessage("W", message); - } - - function LogError(message) { - sendLogMessage("E", message); - } - - function LogFatal(message) { - sendLogMessage("F", message); - } - - function SetLogLevel(loglevel) { - sendLogMessage("S", loglevel); - } - - var LogLevel = { - TRACE: 1, - DEBUG: 2, - INFO: 3, - WARNING: 4, - ERROR: 5 - }; - - // desktop/events.js - var Listener = class { - constructor(callback, maxCallbacks) { - maxCallbacks = maxCallbacks || -1; - this.Callback = (data) => { - callback.apply(null, data); - if (maxCallbacks === -1) { - return false; - } - maxCallbacks -= 1; - return maxCallbacks === 0; - }; - } - }; - var eventListeners = {}; - - function EventsOnMultiple(eventName, callback, maxCallbacks) { - eventListeners[eventName] = eventListeners[eventName] || []; - const thisListener = new Listener(callback, maxCallbacks); - eventListeners[eventName].push(thisListener); - } - - function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); - } - - function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); - } - - function notifyListeners(eventData) { - let eventName = eventData.name; - if (eventListeners[eventName]) { - const newEventListenerList = eventListeners[eventName].slice(); - for (let count = 0; count < eventListeners[eventName].length; count += 1) { - const listener = eventListeners[eventName][count]; - let data = eventData.data; - const destroy = listener.Callback(data); - if (destroy) { - newEventListenerList.splice(count, 1); - } - } - eventListeners[eventName] = newEventListenerList; - } - } - - function EventsNotify(notifyMessage) { - console.log("EventsNotify"); - let message; - try { - message = JSON.parse(notifyMessage); - } catch (e) { - const error = "Invalid JSON passed to Notify: " + notifyMessage; - throw new Error(error); - } - console.log({message}); - notifyListeners(message); - } - - function EventsEmit(eventName) { - const payload = { - name: eventName, - data: [].slice.apply(arguments).slice(1) - }; - notifyListeners(payload); - SendMessage("EE" + JSON.stringify(payload)); - } - - function EventsOff(eventName) { - eventListeners.delete(eventName); - SendMessage("EX" + eventName); - } - - // desktop/calls.js - var callbacks = {}; - - function cryptoRandom() { - var array = new Uint32Array(1); - return window.crypto.getRandomValues(array)[0]; - } - - function basicRandom() { - return Math.random() * 9007199254740991; - } - - var randomFunc; - if (window.crypto) { - randomFunc = cryptoRandom; - } else { - randomFunc = basicRandom; - } - - function Call(name, args, timeout) { - if (timeout == null) { - timeout = 0; - } - return new Promise(function (resolve, reject) { - var callbackID; - do { - callbackID = name + "-" + randomFunc(); - } while (callbacks[callbackID]); - var timeoutHandle; - if (timeout > 0) { - timeoutHandle = setTimeout(function () { - reject(Error("Call to " + name + " timed out. Request ID: " + callbackID)); - }, timeout); - } - callbacks[callbackID] = { - timeoutHandle, - reject, - resolve - }; - try { - const payload = { - name, - args, - callbackID - }; - SendMessage("C" + JSON.stringify(payload)); - } catch (e) { - console.error(e); - } - }); - } - - function Callback(incomingMessage) { - var message; - try { - message = JSON.parse(incomingMessage); - } catch (e) { - const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`; - wails.LogDebug(error); - throw new Error(error); - } - var callbackID = message.callbackid; - var callbackData = callbacks[callbackID]; - if (!callbackData) { - const error = `Callback '${callbackID}' not registered!!!`; - console.error(error); - throw new Error(error); - } - clearTimeout(callbackData.timeoutHandle); - delete callbacks[callbackID]; - if (message.error) { - callbackData.reject(message.error); - } else { - callbackData.resolve(message.result); - } - } - - // desktop/bindings.js - window.backend = {}; - - function SetBindings(bindingsMap) { - try { - bindingsMap = JSON.parse(bindingsMap); - } catch (e) { - console.error(e); - } - window.backend = window.backend || {}; - Object.keys(bindingsMap).forEach((packageName) => { - window.backend[packageName] = window.backend[packageName] || {}; - Object.keys(bindingsMap[packageName]).forEach((structName) => { - window.backend[packageName][structName] = window.backend[packageName][structName] || {}; - Object.keys(bindingsMap[packageName][structName]).forEach((methodName) => { - window.backend[packageName][structName][methodName] = function () { - let timeout = 0; - - function dynamic() { - const args = [].slice.call(arguments); - return Call([packageName, structName, methodName].join("."), args, timeout); - } - - dynamic.setTimeout = function (newTimeout) { - timeout = newTimeout; - }; - dynamic.getTimeout = function () { - return timeout; - }; - return dynamic; - }(); - }); - }); - }); - } - - // desktop/main.js - window.backend = {}; - window.runtime = { - ...log_exports, - EventsOn, - EventsOnce, - EventsOnMultiple, - EventsEmit, - EventsOff - }; - window.wails = { - Callback, - EventsNotify, - SetBindings - }; - window.wails.SetBindings(window.wailsbindings); - delete window.wails.SetBindings; - delete window.wailsbindings; - window.addEventListener("mousedown", (e) => { - let currentElement = e.target; - while (currentElement != null) { - if (currentElement.hasAttribute("data-wails-no-drag")) { - break; - } else if (currentElement.hasAttribute("data-wails-drag")) { - SendMessage("drag"); - break; - } - currentElement = currentElement.parentElement; - } - }); -})(); -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9pcGMuanMiLCAiZGVza3RvcC9ldmVudHMuanMiLCAiZGVza3RvcC9jYWxscy5qcyIsICJkZXNrdG9wL2JpbmRpbmdzLmpzIiwgImRlc2t0b3AvbWFpbi5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fXHJcbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cclxufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xyXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcclxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXHJcblRoZSBsaWdodHdlaWdodCBmcmFtZXdvcmsgZm9yIHdlYi1saWtlIGFwcHNcclxuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxyXG4qL1xyXG5cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuaW1wb3J0IHtTZW5kTWVzc2FnZX0gZnJvbSAnLi9pcGMnO1xyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgbG9nIG1lc3NhZ2UgdG8gdGhlIGJhY2tlbmQgd2l0aCB0aGUgZ2l2ZW4gbGV2ZWwgKyBtZXNzYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsZXZlbFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZnVuY3Rpb24gc2VuZExvZ01lc3NhZ2UobGV2ZWwsIG1lc3NhZ2UpIHtcclxuXHJcblx0Ly8gTG9nIE1lc3NhZ2UgZm9ybWF0OlxyXG5cdC8vIGxbdHlwZV1bbWVzc2FnZV1cclxuXHRTZW5kTWVzc2FnZSgnTCcgKyBsZXZlbCArIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiB0cmFjZSBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1RyYWNlKG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnVCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1ByaW50KG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnUCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBkZWJ1ZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ0RlYnVnKG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnRCcsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiBpbmZvIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nSW5mbyhtZXNzYWdlKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ0knLCBtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZyB0aGUgZ2l2ZW4gd2FybmluZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIExvZ1dhcm5pbmcobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdXJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGVycm9yIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nRXJyb3IobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdFJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGZhdGFsIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nRmF0YWwobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdGJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBMb2cgbGV2ZWwgdG8gdGhlIGdpdmVuIGxvZyBsZXZlbFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsb2dsZXZlbFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFNldExvZ0xldmVsKGxvZ2xldmVsKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ1MnLCBsb2dsZXZlbCk7XHJcbn1cclxuXHJcbi8vIExvZyBsZXZlbHNcclxuZXhwb3J0IGNvbnN0IExvZ0xldmVsID0ge1xyXG5cdFRSQUNFOiAxLFxyXG5cdERFQlVHOiAyLFxyXG5cdElORk86IDMsXHJcblx0V0FSTklORzogNCxcclxuXHRFUlJPUjogNSxcclxufTtcclxuIiwgIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgbGlnaHR3ZWlnaHQgZnJhbWV3b3JrIGZvciB3ZWItbGlrZSBhcHBzXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuLy8gSVBDIExpc3RlbmVyc1xyXG5jb25zdCBsaXN0ZW5lcnMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGEgbGlzdGVuZXIgdG8gSVBDIG1lc3NhZ2VzXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gQWRkSVBDTGlzdGVuZXIoY2FsbGJhY2spIHtcclxuXHRsaXN0ZW5lcnMucHVzaChjYWxsYmFjayk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kTWVzc2FnZSBzZW5kcyB0aGUgZ2l2ZW4gbWVzc2FnZSB0byB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFNlbmRNZXNzYWdlKG1lc3NhZ2UpIHtcclxuXHJcblx0Ly8gQ2FsbCBQbGF0Zm9ybSBzcGVjaWZpYyBpbnZva2UgbWV0aG9kXHJcblx0aWYgKFBMQVRGT1JNID09PSBcIndpbmRvd3NcIikge1xyXG5cdFx0d2luZG93LmNocm9tZS53ZWJ2aWV3LnBvc3RNZXNzYWdlKG1lc3NhZ2UpO1xyXG5cdH0gZWxzZSBpZiAoUExBVEZPUk0gPT09IFwiZGFyd2luXCIpIHtcclxuXHRcdHdpbmRvdy5ibGFoKCk7XHJcblx0fSBlbHNlIHtcclxuXHRcdGNvbnNvbGUuZXJyb3IoXCJVbnN1cHBvcnRlZCBQbGF0Zm9ybVwiKTtcclxuXHR9XHJcblxyXG5cdC8vIEFsc28gc2VuZCB0byBsaXN0ZW5lcnNcclxuXHRpZiAobGlzdGVuZXJzLmxlbmd0aCA+IDApIHtcclxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgbGlzdGVuZXJzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdGxpc3RlbmVyc1tpXShtZXNzYWdlKTtcclxuXHRcdH1cclxuXHR9XHJcbn1cclxuIiwgIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgbGlnaHR3ZWlnaHQgZnJhbWV3b3JrIGZvciB3ZWItbGlrZSBhcHBzXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuaW1wb3J0IHtTZW5kTWVzc2FnZX0gZnJvbSAnLi9pcGMnO1xyXG5cclxuLy8gRGVmaW5lcyBhIHNpbmdsZSBsaXN0ZW5lciB3aXRoIGEgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgdG8gY2FsbGJhY2tcclxuXHJcbi8qKlxyXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcclxuICpcclxuICogQGNsYXNzIExpc3RlbmVyXHJcbiAqL1xyXG5jbGFzcyBMaXN0ZW5lciB7XHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXHJcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xyXG4gICAgICogQG1lbWJlcm9mIExpc3RlbmVyXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpIHtcclxuICAgICAgICAvLyBEZWZhdWx0IG9mIC0xIG1lYW5zIGluZmluaXRlXHJcbiAgICAgICAgbWF4Q2FsbGJhY2tzID0gbWF4Q2FsbGJhY2tzIHx8IC0xO1xyXG4gICAgICAgIC8vIENhbGxiYWNrIGludm9rZXMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIGdpdmVuIGRhdGFcclxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXHJcbiAgICAgICAgdGhpcy5DYWxsYmFjayA9IChkYXRhKSA9PiB7XHJcbiAgICAgICAgICAgIGNhbGxiYWNrLmFwcGx5KG51bGwsIGRhdGEpO1xyXG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXHJcbiAgICAgICAgICAgIGlmIChtYXhDYWxsYmFja3MgPT09IC0xKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgLy8gRGVjcmVtZW50IG1heENhbGxiYWNrcy4gUmV0dXJuIHRydWUgaWYgbm93IDAsIG90aGVyd2lzZSBmYWxzZVxyXG4gICAgICAgICAgICBtYXhDYWxsYmFja3MgLT0gMTtcclxuICAgICAgICAgICAgcmV0dXJuIG1heENhbGxiYWNrcyA9PT0gMDtcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5sZXQgZXZlbnRMaXN0ZW5lcnMgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgYG1heENhbGxiYWNrc2AgdGltZXMgYmVmb3JlIGJlaW5nIGRlc3Ryb3llZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcclxuICogQHBhcmFtIHtudW1iZXJ9IG1heENhbGxiYWNrc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XHJcbiAgICBldmVudExpc3RlbmVyc1tldmVudE5hbWVdID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSB8fCBbXTtcclxuICAgIGNvbnN0IHRoaXNMaXN0ZW5lciA9IG5ldyBMaXN0ZW5lcihjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKTtcclxuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0ucHVzaCh0aGlzTGlzdGVuZXIpO1xyXG59XHJcblxyXG4vKipcclxuICogUmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIHRoYXQgd2lsbCBiZSBpbnZva2VkIGV2ZXJ5IHRpbWUgdGhlIGV2ZW50IGlzIGVtaXR0ZWRcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzT24oZXZlbnROYW1lLCBjYWxsYmFjaykge1xyXG4gICAgRXZlbnRzT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAtMSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcclxuICAgIEV2ZW50c09uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgMSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vdGlmeUxpc3RlbmVycyhldmVudERhdGEpIHtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGV2ZW50IG5hbWVcclxuICAgIGxldCBldmVudE5hbWUgPSBldmVudERhdGEubmFtZTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIGFueSBsaXN0ZW5lcnMgZm9yIHRoaXMgZXZlbnRcclxuICAgIGlmIChldmVudExpc3RlbmVyc1tldmVudE5hbWVdKSB7XHJcblxyXG4gICAgICAgIC8vIEtlZXAgYSBsaXN0IG9mIGxpc3RlbmVyIGluZGV4ZXMgdG8gZGVzdHJveVxyXG4gICAgICAgIGNvbnN0IG5ld0V2ZW50TGlzdGVuZXJMaXN0ID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXS5zbGljZSgpO1xyXG5cclxuICAgICAgICAvLyBJdGVyYXRlIGxpc3RlbmVyc1xyXG4gICAgICAgIGZvciAobGV0IGNvdW50ID0gMDsgY291bnQgPCBldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmxlbmd0aDsgY291bnQgKz0gMSkge1xyXG5cclxuICAgICAgICAgICAgLy8gR2V0IG5leHQgbGlzdGVuZXJcclxuICAgICAgICAgICAgY29uc3QgbGlzdGVuZXIgPSBldmVudExpc3RlbmVyc1tldmVudE5hbWVdW2NvdW50XTtcclxuXHJcbiAgICAgICAgICAgIGxldCBkYXRhID0gZXZlbnREYXRhLmRhdGE7XHJcblxyXG4gICAgICAgICAgICAvLyBEbyB0aGUgY2FsbGJhY2tcclxuICAgICAgICAgICAgY29uc3QgZGVzdHJveSA9IGxpc3RlbmVyLkNhbGxiYWNrKGRhdGEpO1xyXG4gICAgICAgICAgICBpZiAoZGVzdHJveSkge1xyXG4gICAgICAgICAgICAgICAgLy8gaWYgdGhlIGxpc3RlbmVyIGluZGljYXRlZCB0byBkZXN0cm95IGl0c2VsZiwgYWRkIGl0IHRvIHRoZSBkZXN0cm95IGxpc3RcclxuICAgICAgICAgICAgICAgIG5ld0V2ZW50TGlzdGVuZXJMaXN0LnNwbGljZShjb3VudCwgMSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFVwZGF0ZSBjYWxsYmFja3Mgd2l0aCBuZXcgbGlzdCBvZiBsaXN0ZW5lcnNcclxuICAgICAgICBldmVudExpc3RlbmVyc1tldmVudE5hbWVdID0gbmV3RXZlbnRMaXN0ZW5lckxpc3Q7XHJcbiAgICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBOb3RpZnkgaW5mb3JtcyBmcm9udGVuZCBsaXN0ZW5lcnMgdGhhdCBhbiBldmVudCB3YXMgZW1pdHRlZCB3aXRoIHRoZSBnaXZlbiBkYXRhXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG5vdGlmeU1lc3NhZ2UgLSBlbmNvZGVkIG5vdGlmaWNhdGlvbiBtZXNzYWdlXHJcblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c05vdGlmeShub3RpZnlNZXNzYWdlKSB7XHJcbiAgICBjb25zb2xlLmxvZyhcIkV2ZW50c05vdGlmeVwiKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgbWVzc2FnZVxyXG4gICAgbGV0IG1lc3NhZ2U7XHJcbiAgICB0cnkge1xyXG4gICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKG5vdGlmeU1lc3NhZ2UpO1xyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgIGNvbnN0IGVycm9yID0gJ0ludmFsaWQgSlNPTiBwYXNzZWQgdG8gTm90aWZ5OiAnICsgbm90aWZ5TWVzc2FnZTtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgY29uc29sZS5sb2coe21lc3NhZ2V9KTtcclxuICAgIG5vdGlmeUxpc3RlbmVycyhtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVtaXQgYW4gZXZlbnQgd2l0aCB0aGUgZ2l2ZW4gbmFtZSBhbmQgZGF0YVxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNFbWl0KGV2ZW50TmFtZSkge1xyXG5cclxuICAgIGNvbnN0IHBheWxvYWQgPSB7XHJcbiAgICAgICAgbmFtZTogZXZlbnROYW1lLFxyXG4gICAgICAgIGRhdGE6IFtdLnNsaWNlLmFwcGx5KGFyZ3VtZW50cykuc2xpY2UoMSksXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIE5vdGlmeSBKUyBsaXN0ZW5lcnNcclxuICAgIG5vdGlmeUxpc3RlbmVycyhwYXlsb2FkKTtcclxuXHJcbiAgICAvLyBOb3RpZnkgR28gbGlzdGVuZXJzXHJcbiAgICBTZW5kTWVzc2FnZSgnRUUnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzT2ZmKGV2ZW50TmFtZSkge1xyXG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyc1xyXG4gICAgZXZlbnRMaXN0ZW5lcnMuZGVsZXRlKGV2ZW50TmFtZSk7XHJcblxyXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xyXG4gICAgU2VuZE1lc3NhZ2UoJ0VYJyArIGV2ZW50TmFtZSk7XHJcbn0iLCAiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fXHJcbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cclxufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xyXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcclxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXHJcblRoZSBsaWdodHdlaWdodCBmcmFtZXdvcmsgZm9yIHdlYi1saWtlIGFwcHNcclxuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxyXG4qL1xyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXHJcblxyXG5pbXBvcnQgeyBTZW5kTWVzc2FnZSB9IGZyb20gJy4vaXBjJztcclxuXHJcbnZhciBjYWxsYmFja3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIGEgbnVtYmVyIGZyb20gdGhlIG5hdGl2ZSBicm93c2VyIHJhbmRvbSBmdW5jdGlvblxyXG4gKlxyXG4gKiBAcmV0dXJucyBudW1iZXJcclxuICovXHJcbmZ1bmN0aW9uIGNyeXB0b1JhbmRvbSgpIHtcclxuXHR2YXIgYXJyYXkgPSBuZXcgVWludDMyQXJyYXkoMSk7XHJcblx0cmV0dXJuIHdpbmRvdy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKGFycmF5KVswXTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgYSBudW1iZXIgdXNpbmcgZGEgb2xkLXNrb29sIE1hdGguUmFuZG9tXHJcbiAqIEkgbGlrZXMgdG8gY2FsbCBpdCBMT0xSYW5kb21cclxuICpcclxuICogQHJldHVybnMgbnVtYmVyXHJcbiAqL1xyXG5mdW5jdGlvbiBiYXNpY1JhbmRvbSgpIHtcclxuXHRyZXR1cm4gTWF0aC5yYW5kb20oKSAqIDkwMDcxOTkyNTQ3NDA5OTE7XHJcbn1cclxuXHJcbi8vIFBpY2sgYSByYW5kb20gbnVtYmVyIGZ1bmN0aW9uIGJhc2VkIG9uIGJyb3dzZXIgY2FwYWJpbGl0eVxyXG52YXIgcmFuZG9tRnVuYztcclxuaWYgKHdpbmRvdy5jcnlwdG8pIHtcclxuXHRyYW5kb21GdW5jID0gY3J5cHRvUmFuZG9tO1xyXG59IGVsc2Uge1xyXG5cdHJhbmRvbUZ1bmMgPSBiYXNpY1JhbmRvbTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBDYWxsIHNlbmRzIGEgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB0byBjYWxsIHRoZSBiaW5kaW5nIHdpdGggdGhlXHJcbiAqIGdpdmVuIGRhdGEuIEEgcHJvbWlzZSBpcyByZXR1cm5lZCBhbmQgd2lsbCBiZSBjb21wbGV0ZWQgd2hlbiB0aGVcclxuICogYmFja2VuZCByZXNwb25kcy4gVGhpcyB3aWxsIGJlIHJlc29sdmVkIHdoZW4gdGhlIGNhbGwgd2FzIHN1Y2Nlc3NmdWxcclxuICogb3IgcmVqZWN0ZWQgaWYgYW4gZXJyb3IgaXMgcGFzc2VkIGJhY2suXHJcbiAqIFRoZXJlIGlzIGEgdGltZW91dCBtZWNoYW5pc20uIElmIHRoZSBjYWxsIGRvZXNuJ3QgcmVzcG9uZCBpbiB0aGUgZ2l2ZW5cclxuICogdGltZSAoaW4gbWlsbGlzZWNvbmRzKSB0aGVuIHRoZSBwcm9taXNlIGlzIHJlamVjdGVkLlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzXHJcbiAqIEBwYXJhbSB7bnVtYmVyPX0gdGltZW91dFxyXG4gKiBAcmV0dXJuc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENhbGwobmFtZSwgYXJncywgdGltZW91dCkge1xyXG5cclxuXHQvLyBUaW1lb3V0IGluZmluaXRlIGJ5IGRlZmF1bHRcclxuXHRpZiAodGltZW91dCA9PSBudWxsKSB7XHJcblx0XHR0aW1lb3V0ID0gMDtcclxuXHR9XHJcblxyXG5cdC8vIENyZWF0ZSBhIHByb21pc2VcclxuXHRyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG5cclxuXHRcdC8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lEXHJcblx0XHR2YXIgY2FsbGJhY2tJRDtcclxuXHRcdGRvIHtcclxuXHRcdFx0Y2FsbGJhY2tJRCA9IG5hbWUgKyAnLScgKyByYW5kb21GdW5jKCk7XHJcblx0XHR9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xyXG5cclxuXHRcdC8vIFNldCB0aW1lb3V0XHJcblx0XHRpZiAodGltZW91dCA+IDApIHtcclxuXHRcdFx0dmFyIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRyZWplY3QoRXJyb3IoJ0NhbGwgdG8gJyArIG5hbWUgKyAnIHRpbWVkIG91dC4gUmVxdWVzdCBJRDogJyArIGNhbGxiYWNrSUQpKTtcclxuXHRcdFx0fSwgdGltZW91dCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU3RvcmUgY2FsbGJhY2tcclxuXHRcdGNhbGxiYWNrc1tjYWxsYmFja0lEXSA9IHtcclxuXHRcdFx0dGltZW91dEhhbmRsZTogdGltZW91dEhhbmRsZSxcclxuXHRcdFx0cmVqZWN0OiByZWplY3QsXHJcblx0XHRcdHJlc29sdmU6IHJlc29sdmVcclxuXHRcdH07XHJcblxyXG5cdFx0dHJ5IHtcclxuXHRcdFx0Y29uc3QgcGF5bG9hZCA9IHtcclxuXHRcdFx0XHRuYW1lLFxyXG5cdFx0XHRcdGFyZ3MsXHJcblx0XHRcdFx0Y2FsbGJhY2tJRCxcclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdC8vIE1ha2UgdGhlIGNhbGxcclxuXHRcdFx0U2VuZE1lc3NhZ2UoJ0MnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xyXG5cdFx0fSBjYXRjaCAoZSkge1xyXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcclxuXHRcdFx0Y29uc29sZS5lcnJvcihlKTtcclxuXHRcdH1cclxuXHR9KTtcclxufVxyXG5cclxuXHJcblxyXG4vKipcclxuICogQ2FsbGVkIGJ5IHRoZSBiYWNrZW5kIHRvIHJldHVybiBkYXRhIHRvIGEgcHJldmlvdXNseSBjYWxsZWRcclxuICogYmluZGluZyBpbnZvY2F0aW9uXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IGluY29taW5nTWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENhbGxiYWNrKGluY29taW5nTWVzc2FnZSkge1xyXG5cdC8vIERlY29kZSB0aGUgbWVzc2FnZSAtIENyZWRpdDogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzEzODY1NjgwXHJcblx0Ly9pbmNvbWluZ01lc3NhZ2UgPSBkZWNvZGVVUklDb21wb25lbnQoaW5jb21pbmdNZXNzYWdlLnJlcGxhY2UoL1xccysvZywgJycpLnJlcGxhY2UoL1swLTlhLWZdezJ9L2csICclJCYnKSk7XHJcblxyXG5cdC8vIFBhcnNlIHRoZSBtZXNzYWdlXHJcblx0dmFyIG1lc3NhZ2U7XHJcblx0dHJ5IHtcclxuXHRcdG1lc3NhZ2UgPSBKU09OLnBhcnNlKGluY29taW5nTWVzc2FnZSk7XHJcblx0fSBjYXRjaCAoZSkge1xyXG5cdFx0Y29uc3QgZXJyb3IgPSBgSW52YWxpZCBKU09OIHBhc3NlZCB0byBjYWxsYmFjazogJHtlLm1lc3NhZ2V9LiBNZXNzYWdlOiAke2luY29taW5nTWVzc2FnZX1gO1xyXG5cdFx0d2FpbHMuTG9nRGVidWcoZXJyb3IpO1xyXG5cdFx0dGhyb3cgbmV3IEVycm9yKGVycm9yKTtcclxuXHR9XHJcblx0dmFyIGNhbGxiYWNrSUQgPSBtZXNzYWdlLmNhbGxiYWNraWQ7XHJcblx0dmFyIGNhbGxiYWNrRGF0YSA9IGNhbGxiYWNrc1tjYWxsYmFja0lEXTtcclxuXHRpZiAoIWNhbGxiYWNrRGF0YSkge1xyXG5cdFx0Y29uc3QgZXJyb3IgPSBgQ2FsbGJhY2sgJyR7Y2FsbGJhY2tJRH0nIG5vdCByZWdpc3RlcmVkISEhYDtcclxuXHRcdGNvbnNvbGUuZXJyb3IoZXJyb3IpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xyXG5cdH1cclxuXHRjbGVhclRpbWVvdXQoY2FsbGJhY2tEYXRhLnRpbWVvdXRIYW5kbGUpO1xyXG5cclxuXHRkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdO1xyXG5cclxuXHRpZiAobWVzc2FnZS5lcnJvcikge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlamVjdChtZXNzYWdlLmVycm9yKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlc29sdmUobWVzc2FnZS5yZXN1bHQpO1xyXG5cdH1cclxufVxyXG4iLCAiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fICAgIFxyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApIFxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy8gIFxyXG5UaGUgbGlnaHR3ZWlnaHQgZnJhbWV3b3JrIGZvciB3ZWItbGlrZSBhcHBzXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuaW1wb3J0IHsgQ2FsbCB9IGZyb20gJy4vY2FsbHMnO1xyXG5cclxud2luZG93LmJhY2tlbmQgPSB7fTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBTZXRCaW5kaW5ncyhiaW5kaW5nc01hcCkge1xyXG5cdHRyeSB7XHJcblx0XHRiaW5kaW5nc01hcCA9IEpTT04ucGFyc2UoYmluZGluZ3NNYXApO1xyXG5cdH0gY2F0Y2ggKGUpIHtcclxuXHRcdGNvbnNvbGUuZXJyb3IoZSk7XHJcblx0fVxyXG5cclxuXHQvLyBJbml0aWFsaXNlIHRoZSBiYWNrZW5kIG1hcFxyXG5cdHdpbmRvdy5iYWNrZW5kID0gd2luZG93LmJhY2tlbmQgfHwge307XHJcblxyXG5cdC8vIEl0ZXJhdGUgcGFja2FnZSBuYW1lc1xyXG5cdE9iamVjdC5rZXlzKGJpbmRpbmdzTWFwKS5mb3JFYWNoKChwYWNrYWdlTmFtZSkgPT4ge1xyXG5cclxuXHRcdC8vIENyZWF0ZSBpbm5lciBtYXAgaWYgaXQgZG9lc24ndCBleGlzdFxyXG5cdFx0d2luZG93LmJhY2tlbmRbcGFja2FnZU5hbWVdID0gd2luZG93LmJhY2tlbmRbcGFja2FnZU5hbWVdIHx8IHt9O1xyXG5cclxuXHRcdC8vIEl0ZXJhdGUgc3RydWN0IG5hbWVzXHJcblx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV0pLmZvckVhY2goKHN0cnVjdE5hbWUpID0+IHtcclxuXHJcblx0XHRcdC8vIENyZWF0ZSBpbm5lciBtYXAgaWYgaXQgZG9lc24ndCBleGlzdFxyXG5cdFx0XHR3aW5kb3cuYmFja2VuZFtwYWNrYWdlTmFtZV1bc3RydWN0TmFtZV0gPSB3aW5kb3cuYmFja2VuZFtwYWNrYWdlTmFtZV1bc3RydWN0TmFtZV0gfHwge307XHJcblxyXG5cdFx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV1bc3RydWN0TmFtZV0pLmZvckVhY2goKG1ldGhvZE5hbWUpID0+IHtcclxuXHJcblx0XHRcdFx0d2luZG93LmJhY2tlbmRbcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdW21ldGhvZE5hbWVdID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdC8vIE5vIHRpbWVvdXQgYnkgZGVmYXVsdFxyXG5cdFx0XHRcdFx0bGV0IHRpbWVvdXQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdC8vIEFjdHVhbCBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZnVuY3Rpb24gZHluYW1pYygpIHtcclxuXHRcdFx0XHRcdFx0Y29uc3QgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIENhbGwoW3BhY2thZ2VOYW1lLCBzdHJ1Y3ROYW1lLCBtZXRob2ROYW1lXS5qb2luKCcuJyksIGFyZ3MsIHRpbWVvdXQpO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IHNldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHtcclxuXHRcdFx0XHRcdFx0dGltZW91dCA9IG5ld1RpbWVvdXQ7XHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IGdldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGltZW91dDtcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIGR5bmFtaWM7XHJcblx0XHRcdFx0fSgpO1xyXG5cdFx0XHR9KTtcclxuXHRcdH0pO1xyXG5cdH0pO1xyXG59XHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGxpZ2h0d2VpZ2h0IGZyYW1ld29yayBmb3Igd2ViLWxpa2UgYXBwc1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cclxuaW1wb3J0ICogYXMgTG9nIGZyb20gJy4vbG9nJztcclxuaW1wb3J0IHtFdmVudHNFbWl0LCBFdmVudHNOb3RpZnksIEV2ZW50c09mZiwgRXZlbnRzT24sIEV2ZW50c09uY2UsIEV2ZW50c09uTXVsdGlwbGV9IGZyb20gJy4vZXZlbnRzJztcclxuaW1wb3J0IHtDYWxsYmFja30gZnJvbSAnLi9jYWxscyc7XHJcbmltcG9ydCB7U2V0QmluZGluZ3N9IGZyb20gXCIuL2JpbmRpbmdzXCI7XHJcbi8vIGltcG9ydCB7QWRkU2NyaXB0LCBEaXNhYmxlRGVmYXVsdENvbnRleHRNZW51LCBJbmplY3RDU1N9IGZyb20gJy4vdXRpbHMnO1xyXG5pbXBvcnQge1NlbmRNZXNzYWdlfSBmcm9tICcuL2lwYyc7XHJcblxyXG4vLyBCYWNrZW5kIGlzIHdoZXJlIHRoZSBHbyBzdHJ1Y3Qgd3JhcHBlcnMgZ2V0IGJvdW5kIHRvXHJcbndpbmRvdy5iYWNrZW5kID0ge307XHJcblxyXG53aW5kb3cucnVudGltZSA9IHtcclxuICAgIC4uLkxvZyxcclxuICAgIEV2ZW50c09uLFxyXG4gICAgRXZlbnRzT25jZSxcclxuICAgIEV2ZW50c09uTXVsdGlwbGUsXHJcbiAgICBFdmVudHNFbWl0LFxyXG4gICAgRXZlbnRzT2ZmLFxyXG59O1xyXG5cclxuLy8gSW5pdGlhbGlzZSBnbG9iYWwgaWYgbm90IGFscmVhZHlcclxud2luZG93LndhaWxzID0ge1xyXG4gICAgQ2FsbGJhY2ssXHJcbiAgICBFdmVudHNOb3RpZnksXHJcbiAgICBTZXRCaW5kaW5ncyxcclxufTtcclxuXHJcbndpbmRvdy53YWlscy5TZXRCaW5kaW5ncyh3aW5kb3cud2FpbHNiaW5kaW5ncyk7XHJcbmRlbGV0ZSB3aW5kb3cud2FpbHNbJ1NldEJpbmRpbmdzJ107XHJcbmRlbGV0ZSB3aW5kb3dbJ3dhaWxzYmluZGluZ3MnXTtcclxuXHJcbi8vIFNldHVwIGRyYWcgaGFuZGxlclxyXG4vLyBCYXNlZCBvbiBjb2RlIGZyb206IGh0dHBzOi8vZ2l0aHViLmNvbS9wYXRyMG51cy9EZXNrR2FwXHJcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCAoZSkgPT4ge1xyXG4gICAgbGV0IGN1cnJlbnRFbGVtZW50ID0gZS50YXJnZXQ7XHJcbiAgICB3aGlsZSAoY3VycmVudEVsZW1lbnQgIT0gbnVsbCkge1xyXG4gICAgICAgIGlmIChjdXJyZW50RWxlbWVudC5oYXNBdHRyaWJ1dGUoJ2RhdGEtd2FpbHMtbm8tZHJhZycpKSB7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoY3VycmVudEVsZW1lbnQuaGFzQXR0cmlidXRlKCdkYXRhLXdhaWxzLWRyYWcnKSkge1xyXG4gICAgICAgICAgICBTZW5kTWVzc2FnZShcImRyYWdcIik7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjdXJyZW50RWxlbWVudCA9IGN1cnJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQ7XHJcbiAgICB9XHJcbn0pO1xyXG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBOzs7QUNZQSxNQUFNLFlBQVk7QUFlWCx1QkFBcUIsU0FBUztBQUdwQyxRQUFJLE1BQXdCO0FBQzNCLGFBQU8sT0FBTyxRQUFRLFlBQVk7QUFBQSxlQUN4QixPQUF1QjtBQUNqQyxhQUFPO0FBQUEsV0FDRDtBQUNOLGNBQVEsTUFBTTtBQUFBO0FBSWYsUUFBSSxVQUFVLFNBQVMsR0FBRztBQUN6QixlQUFTLElBQUksR0FBRyxJQUFJLFVBQVUsUUFBUSxLQUFLO0FBQzFDLGtCQUFVLEdBQUc7QUFBQTtBQUFBO0FBQUE7OztBRHJCaEIsMEJBQXdCLE9BQU8sU0FBUztBQUl2QyxnQkFBWSxNQUFNLFFBQVE7QUFBQTtBQVNwQixvQkFBa0IsU0FBUztBQUNqQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxvQkFBa0IsU0FBUztBQUNqQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxvQkFBa0IsU0FBUztBQUNqQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxtQkFBaUIsU0FBUztBQUNoQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxzQkFBb0IsU0FBUztBQUNuQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxvQkFBa0IsU0FBUztBQUNqQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCxvQkFBa0IsU0FBUztBQUNqQyxtQkFBZSxLQUFLO0FBQUE7QUFTZCx1QkFBcUIsVUFBVTtBQUNyQyxtQkFBZSxLQUFLO0FBQUE7QUFJZCxNQUFNLFdBQVc7QUFBQSxJQUN2QixPQUFPO0FBQUEsSUFDUCxPQUFPO0FBQUEsSUFDUCxNQUFNO0FBQUEsSUFDTixTQUFTO0FBQUEsSUFDVCxPQUFPO0FBQUE7OztBRTdGUix1QkFBZTtBQUFBLElBT1gsWUFBWSxVQUFVLGNBQWM7QUFFaEMscUJBQWUsZ0JBQWdCO0FBRy9CLFdBQUssV0FBVyxDQUFDLFNBQVM7QUFDdEIsaUJBQVMsTUFBTSxNQUFNO0FBRXJCLFlBQUksaUJBQWlCLElBQUk7QUFDckIsaUJBQU87QUFBQTtBQUdYLHdCQUFnQjtBQUNoQixlQUFPLGlCQUFpQjtBQUFBO0FBQUE7QUFBQTtBQUtwQyxNQUFJLGlCQUFpQjtBQVVkLDRCQUEwQixXQUFXLFVBQVUsY0FBYztBQUNoRSxtQkFBZSxhQUFhLGVBQWUsY0FBYztBQUN6RCxVQUFNLGVBQWUsSUFBSSxTQUFTLFVBQVU7QUFDNUMsbUJBQWUsV0FBVyxLQUFLO0FBQUE7QUFVNUIsb0JBQWtCLFdBQVcsVUFBVTtBQUMxQyxxQkFBaUIsV0FBVyxVQUFVO0FBQUE7QUFVbkMsc0JBQW9CLFdBQVcsVUFBVTtBQUM1QyxxQkFBaUIsV0FBVyxVQUFVO0FBQUE7QUFHMUMsMkJBQXlCLFdBQVc7QUFHaEMsUUFBSSxZQUFZLFVBQVU7QUFHMUIsUUFBSSxlQUFlLFlBQVk7QUFHM0IsWUFBTSx1QkFBdUIsZUFBZSxXQUFXO0FBR3ZELGVBQVMsUUFBUSxHQUFHLFFBQVEsZUFBZSxXQUFXLFFBQVEsU0FBUyxHQUFHO0FBR3RFLGNBQU0sV0FBVyxlQUFlLFdBQVc7QUFFM0MsWUFBSSxPQUFPLFVBQVU7QUFHckIsY0FBTSxVQUFVLFNBQVMsU0FBUztBQUNsQyxZQUFJLFNBQVM7QUFFVCwrQkFBcUIsT0FBTyxPQUFPO0FBQUE7QUFBQTtBQUszQyxxQkFBZSxhQUFhO0FBQUE7QUFBQTtBQVc3Qix3QkFBc0IsZUFBZTtBQUN4QyxZQUFRLElBQUk7QUFHWixRQUFJO0FBQ0osUUFBSTtBQUNBLGdCQUFVLEtBQUssTUFBTTtBQUFBLGFBQ2hCLEdBQVA7QUFDRSxZQUFNLFFBQVEsb0NBQW9DO0FBQ2xELFlBQU0sSUFBSSxNQUFNO0FBQUE7QUFFcEIsWUFBUSxJQUFJLEVBQUM7QUFDYixvQkFBZ0I7QUFBQTtBQVNiLHNCQUFvQixXQUFXO0FBRWxDLFVBQU0sVUFBVTtBQUFBLE1BQ1osTUFBTTtBQUFBLE1BQ04sTUFBTSxHQUFHLE1BQU0sTUFBTSxXQUFXLE1BQU07QUFBQTtBQUkxQyxvQkFBZ0I7QUFHaEIsZ0JBQVksT0FBTyxLQUFLLFVBQVU7QUFBQTtBQUcvQixxQkFBbUIsV0FBVztBQUVqQyxtQkFBZSxPQUFPO0FBR3RCLGdCQUFZLE9BQU87QUFBQTs7O0FDckp2QixNQUFJLFlBQVk7QUFPaEIsMEJBQXdCO0FBQ3ZCLFFBQUksUUFBUSxJQUFJLFlBQVk7QUFDNUIsV0FBTyxPQUFPLE9BQU8sZ0JBQWdCLE9BQU87QUFBQTtBQVM3Qyx5QkFBdUI7QUFDdEIsV0FBTyxLQUFLLFdBQVc7QUFBQTtBQUl4QixNQUFJO0FBQ0osTUFBSSxPQUFPLFFBQVE7QUFDbEIsaUJBQWE7QUFBQSxTQUNQO0FBQ04saUJBQWE7QUFBQTtBQWtCUCxnQkFBYyxNQUFNLE1BQU0sU0FBUztBQUd6QyxRQUFJLFdBQVcsTUFBTTtBQUNwQixnQkFBVTtBQUFBO0FBSVgsV0FBTyxJQUFJLFFBQVEsU0FBVSxTQUFTLFFBQVE7QUFHN0MsVUFBSTtBQUNKLFNBQUc7QUFDRixxQkFBYSxPQUFPLE1BQU07QUFBQSxlQUNsQixVQUFVO0FBR25CLFVBQUksVUFBVSxHQUFHO0FBQ2hCLFlBQUksZ0JBQWdCLFdBQVcsV0FBWTtBQUMxQyxpQkFBTyxNQUFNLGFBQWEsT0FBTyw2QkFBNkI7QUFBQSxXQUM1RDtBQUFBO0FBSUosZ0JBQVUsY0FBYztBQUFBLFFBQ3ZCO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQTtBQUdELFVBQUk7QUFDSCxjQUFNLFVBQVU7QUFBQSxVQUNmO0FBQUEsVUFDQTtBQUFBLFVBQ0E7QUFBQTtBQUlELG9CQUFZLE1BQU0sS0FBSyxVQUFVO0FBQUEsZUFDekIsR0FBUDtBQUVELGdCQUFRLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFjVixvQkFBa0IsaUJBQWlCO0FBS3pDLFFBQUk7QUFDSixRQUFJO0FBQ0gsZ0JBQVUsS0FBSyxNQUFNO0FBQUEsYUFDYixHQUFQO0FBQ0QsWUFBTSxRQUFRLG9DQUFvQyxFQUFFLHFCQUFxQjtBQUN6RSxZQUFNLFNBQVM7QUFDZixZQUFNLElBQUksTUFBTTtBQUFBO0FBRWpCLFFBQUksYUFBYSxRQUFRO0FBQ3pCLFFBQUksZUFBZSxVQUFVO0FBQzdCLFFBQUksQ0FBQyxjQUFjO0FBQ2xCLFlBQU0sUUFBUSxhQUFhO0FBQzNCLGNBQVEsTUFBTTtBQUNkLFlBQU0sSUFBSSxNQUFNO0FBQUE7QUFFakIsaUJBQWEsYUFBYTtBQUUxQixXQUFPLFVBQVU7QUFFakIsUUFBSSxRQUFRLE9BQU87QUFDbEIsbUJBQWEsT0FBTyxRQUFRO0FBQUEsV0FDdEI7QUFDTixtQkFBYSxRQUFRLFFBQVE7QUFBQTtBQUFBOzs7QUMvSC9CLFNBQU8sVUFBVTtBQUVWLHVCQUFxQixhQUFhO0FBQ3hDLFFBQUk7QUFDSCxvQkFBYyxLQUFLLE1BQU07QUFBQSxhQUNqQixHQUFQO0FBQ0QsY0FBUSxNQUFNO0FBQUE7QUFJZixXQUFPLFVBQVUsT0FBTyxXQUFXO0FBR25DLFdBQU8sS0FBSyxhQUFhLFFBQVEsQ0FBQyxnQkFBZ0I7QUFHakQsYUFBTyxRQUFRLGVBQWUsT0FBTyxRQUFRLGdCQUFnQjtBQUc3RCxhQUFPLEtBQUssWUFBWSxjQUFjLFFBQVEsQ0FBQyxlQUFlO0FBRzdELGVBQU8sUUFBUSxhQUFhLGNBQWMsT0FBTyxRQUFRLGFBQWEsZUFBZTtBQUVyRixlQUFPLEtBQUssWUFBWSxhQUFhLGFBQWEsUUFBUSxDQUFDLGVBQWU7QUFFekUsaUJBQU8sUUFBUSxhQUFhLFlBQVksY0FBYyxXQUFZO0FBR2pFLGdCQUFJLFVBQVU7QUFHZCwrQkFBbUI7QUFDbEIsb0JBQU0sT0FBTyxHQUFHLE1BQU0sS0FBSztBQUMzQixxQkFBTyxLQUFLLENBQUMsYUFBYSxZQUFZLFlBQVksS0FBSyxNQUFNLE1BQU07QUFBQTtBQUlwRSxvQkFBUSxhQUFhLFNBQVUsWUFBWTtBQUMxQyx3QkFBVTtBQUFBO0FBSVgsb0JBQVEsYUFBYSxXQUFZO0FBQ2hDLHFCQUFPO0FBQUE7QUFHUixtQkFBTztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7OztBQzFDWixTQUFPLFVBQVU7QUFFakIsU0FBTyxVQUFVO0FBQUEsT0FDVjtBQUFBLElBQ0g7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUE7QUFJSixTQUFPLFFBQVE7QUFBQSxJQUNYO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQTtBQUdKLFNBQU8sTUFBTSxZQUFZLE9BQU87QUFDaEMsU0FBTyxPQUFPLE1BQU07QUFDcEIsU0FBTyxPQUFPO0FBSWQsU0FBTyxpQkFBaUIsYUFBYSxDQUFDLE1BQU07QUFDeEMsUUFBSSxpQkFBaUIsRUFBRTtBQUN2QixXQUFPLGtCQUFrQixNQUFNO0FBQzNCLFVBQUksZUFBZSxhQUFhLHVCQUF1QjtBQUNuRDtBQUFBLGlCQUNPLGVBQWUsYUFBYSxvQkFBb0I7QUFDdkQsb0JBQVk7QUFDWjtBQUFBO0FBRUosdUJBQWlCLGVBQWU7QUFBQTtBQUFBOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/v2/internal/frontend/dispatcher.go b/v2/internal/frontend/dispatcher.go index a15ad76e8..8678ba26c 100644 --- a/v2/internal/frontend/dispatcher.go +++ b/v2/internal/frontend/dispatcher.go @@ -1,6 +1,5 @@ package frontend type Dispatcher interface { - ProcessMessage(message string) error - SetCallbackHandler(func(string)) + ProcessMessage(message string) (string, error) } diff --git a/v2/internal/frontend/dispatcher/calls.go b/v2/internal/frontend/dispatcher/calls.go index 183e1b4b8..85f0c78c5 100644 --- a/v2/internal/frontend/dispatcher/calls.go +++ b/v2/internal/frontend/dispatcher/calls.go @@ -11,24 +11,24 @@ type callMessage struct { CallbackID string `json:"callbackID"` } -func (d *Dispatcher) processCallMessage(message string) error { +func (d *Dispatcher) processCallMessage(message string) (string, error) { var payload callMessage err := json.Unmarshal([]byte(message[1:]), &payload) if err != nil { - return err + return "", err } // Lookup method registeredMethod := d.bindingsDB.GetMethod(payload.Name) // Check we have it if registeredMethod == nil { - return fmt.Errorf("method '%s' not registered", payload.Name) + return "", fmt.Errorf("method '%s' not registered", payload.Name) } args, err := registeredMethod.ParseArgs(payload.Args) if err != nil { - return fmt.Errorf("error parsing arguments: %s", err.Error()) + return "", fmt.Errorf("error parsing arguments: %s", err.Error()) } result, err := registeredMethod.Call(args) @@ -46,9 +46,8 @@ func (d *Dispatcher) processCallMessage(message string) error { // what now? d.log.Fatal(err.Error()) } - d.resultCallback(string(messageData)) - return nil + return "c" + string(messageData), nil } // CallbackMessage defines a message that contains the result of a call diff --git a/v2/internal/frontend/dispatcher/dispatcher.go b/v2/internal/frontend/dispatcher/dispatcher.go index 4d9a0824d..c671a6f62 100644 --- a/v2/internal/frontend/dispatcher/dispatcher.go +++ b/v2/internal/frontend/dispatcher/dispatcher.go @@ -8,11 +8,10 @@ import ( ) type Dispatcher struct { - log *logger.Logger - bindings *binding.Bindings - events frontend.Events - bindingsDB *binding.DB - resultCallback func(string) + log *logger.Logger + bindings *binding.Bindings + events frontend.Events + bindingsDB *binding.DB } func NewDispatcher(log *logger.Logger, bindings *binding.Bindings, events frontend.Events) *Dispatcher { @@ -24,13 +23,9 @@ func NewDispatcher(log *logger.Logger, bindings *binding.Bindings, events fronte } } -func (d *Dispatcher) SetCallbackHandler(handler func(string)) { - d.resultCallback = handler -} - -func (d *Dispatcher) ProcessMessage(message string) error { +func (d *Dispatcher) ProcessMessage(message string) (string, error) { if message == "" { - return errors.New("No message to process") + return "", errors.New("No message to process") } switch message[0] { case 'L': @@ -40,6 +35,6 @@ func (d *Dispatcher) ProcessMessage(message string) error { case 'C': return d.processCallMessage(message) default: - return errors.New("Unknown message from front end: " + message) + return "", errors.New("Unknown message from front end: " + message) } } diff --git a/v2/internal/frontend/dispatcher/events.go b/v2/internal/frontend/dispatcher/events.go index 7a02eb09d..41f55274a 100644 --- a/v2/internal/frontend/dispatcher/events.go +++ b/v2/internal/frontend/dispatcher/events.go @@ -10,9 +10,9 @@ type EventMessage struct { Data []interface{} `json:"data"` } -func (d *Dispatcher) processEventMessage(message string) error { +func (d *Dispatcher) processEventMessage(message string) (string, error) { if len(message) < 3 { - return errors.New("Invalid Event Message: " + message) + return "", errors.New("Invalid Event Message: " + message) } switch message[1] { @@ -20,7 +20,7 @@ func (d *Dispatcher) processEventMessage(message string) error { var eventMessage EventMessage err := json.Unmarshal([]byte(message[2:]), &eventMessage) if err != nil { - return err + return "", err } go d.events.Notify(eventMessage.Name, eventMessage.Data) case 'X': @@ -28,5 +28,5 @@ func (d *Dispatcher) processEventMessage(message string) error { go d.events.Off(eventName) } - return nil + return "", nil } diff --git a/v2/internal/frontend/dispatcher/log.go b/v2/internal/frontend/dispatcher/log.go index ead44eeb1..e42555397 100644 --- a/v2/internal/frontend/dispatcher/log.go +++ b/v2/internal/frontend/dispatcher/log.go @@ -14,9 +14,9 @@ var logLevelMap = map[byte]logger.LogLevel{ '5': pkgLogger.ERROR, } -func (d *Dispatcher) processLogMessage(message string) error { +func (d *Dispatcher) processLogMessage(message string) (string, error) { if len(message) < 3 { - return errors.New("Invalid Log Message: " + message) + return "", errors.New("Invalid Log Message: " + message) } messageText := message[2:] @@ -39,11 +39,11 @@ func (d *Dispatcher) processLogMessage(message string) error { case 'S': loglevel, exists := logLevelMap[message[2]] if !exists { - return errors.New("Invalid Set Log Level Message: " + message) + return "", errors.New("Invalid Set Log Level Message: " + message) } d.log.SetLogLevel(loglevel) default: - return errors.New("Invalid Log Message: " + message) + return "", errors.New("Invalid Log Message: " + message) } - return nil + return "", nil } diff --git a/v2/internal/frontend/runtime/desktop/calls.js b/v2/internal/frontend/runtime/desktop/calls.js index 0b8e809e6..40f32506d 100644 --- a/v2/internal/frontend/runtime/desktop/calls.js +++ b/v2/internal/frontend/runtime/desktop/calls.js @@ -9,7 +9,7 @@ The lightweight framework for web-like apps */ /* jshint esversion: 6 */ -var callbacks = {}; +export const callbacks = {}; /** * Returns a number from the native browser random function diff --git a/v2/internal/frontend/runtime/desktop/events.js b/v2/internal/frontend/runtime/desktop/events.js index 06b709781..d038bd5e7 100644 --- a/v2/internal/frontend/runtime/desktop/events.js +++ b/v2/internal/frontend/runtime/desktop/events.js @@ -41,7 +41,7 @@ class Listener { } } -let eventListeners = {}; +export const eventListeners = {}; /** * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed @@ -119,8 +119,6 @@ function notifyListeners(eventData) { */ export function EventsNotify(notifyMessage) { - console.log("EventsNotify"); - // Parse the message let message; try { @@ -129,7 +127,6 @@ export function EventsNotify(notifyMessage) { const error = 'Invalid JSON passed to Notify: ' + notifyMessage; throw new Error(error); } - console.log({message}); notifyListeners(message); } diff --git a/v2/internal/frontend/runtime/desktop/main.js b/v2/internal/frontend/runtime/desktop/main.js index 4fb1cdced..61cc99a0f 100644 --- a/v2/internal/frontend/runtime/desktop/main.js +++ b/v2/internal/frontend/runtime/desktop/main.js @@ -9,8 +9,8 @@ The lightweight framework for web-like apps */ /* jshint esversion: 9 */ import * as Log from './log'; -import {EventsEmit, EventsNotify, EventsOff, EventsOn, EventsOnce, EventsOnMultiple} from './events'; -import {Callback} from './calls'; +import {eventListeners, EventsEmit, EventsNotify, EventsOff, EventsOn, EventsOnce, EventsOnMultiple} from './events'; +import {Callback, callbacks} from './calls'; import {SetBindings} from "./bindings"; // Backend is where the Go struct wrappers get bound to @@ -30,6 +30,8 @@ window.wails = { Callback, EventsNotify, SetBindings, + eventListeners, + callbacks }; window.wails.SetBindings(window.wailsbindings); diff --git a/v2/internal/frontend/runtime/dev/build.js b/v2/internal/frontend/runtime/dev/build.js new file mode 100644 index 000000000..6106b8ce5 --- /dev/null +++ b/v2/internal/frontend/runtime/dev/build.js @@ -0,0 +1,50 @@ +/* jshint esversion: 8 */ + +let sveltePlugin = { + name: 'svelte', + setup(build) { + let svelte = require('svelte/compiler'); + let path = require('path'); + let fs = require('fs'); + + build.onLoad({filter: /\.svelte$/}, async (args) => { + // This converts a message in Svelte's format to esbuild's format + let convertMessage = ({message, start, end}) => { + let location + if (start && end) { + let lineText = source.split(/\r\n|\r|\n/g)[start.line - 1]; + let lineEnd = start.line === end.line ? end.column : lineText.length; + location = { + file: filename, + line: start.line, + column: start.column, + length: lineEnd - start.column, + lineText, + }; + } + return {text: message, location}; + }; + + // Load the file from the file system + let source = await fs.promises.readFile(args.path, 'utf8'); + let filename = path.relative(process.cwd(), args.path); + + // Convert Svelte syntax to JavaScript + try { + let {js, warnings} = svelte.compile(source, {filename}); + let contents = js.code + `//# sourceMappingURL=` + js.map.toUrl(); + return {contents, warnings: warnings.map(convertMessage)}; + } catch (e) { + return {errors: [convertMessage(e)]}; + } + }); + } +}; + +require('esbuild').build({ + minify: true, + entryPoints: ['main.js'], + bundle: true, + outfile: '../ipc_websocket.js', + plugins: [sveltePlugin], +}).catch(() => process.exit(1)); \ No newline at end of file diff --git a/v2/internal/frontend/runtime/dev/log.js b/v2/internal/frontend/runtime/dev/log.js new file mode 100644 index 000000000..e128c97f0 --- /dev/null +++ b/v2/internal/frontend/runtime/dev/log.js @@ -0,0 +1,8 @@ +export function log(message) { + // eslint-disable-next-line + console.log( + '%c wails dev %c ' + message + ' ', + 'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem', + 'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem' + ); +} \ No newline at end of file diff --git a/v2/internal/frontend/runtime/dev/main.js b/v2/internal/frontend/runtime/dev/main.js new file mode 100644 index 000000000..bf65807de --- /dev/null +++ b/v2/internal/frontend/runtime/dev/main.js @@ -0,0 +1,163 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The lightweight framework for web-like apps +(c) Lea Anthony 2019-present +*/ +/* jshint esversion: 6 */ + +import {log} from "./log"; + +let websocket = null; +let connectTimer; + +window.onbeforeunload = function () { + if (websocket) { + websocket.onclose = function () { + }; + websocket.close(); + websocket = null; + } +}; + +// ...and attempt to connect +connect(); + + +function setupIPCBridge() { + window.WailsInvoke = (message) => { + websocket.send(message); + }; +} + +// Handles incoming websocket connections +function handleConnect() { + log('Connected to backend'); + setupIPCBridge(); + clearInterval(connectTimer); + websocket.onclose = handleDisconnect; + websocket.onmessage = handleMessage; +} + +// Handles websocket disconnects +function handleDisconnect() { + log('Disconnected from backend'); + websocket = null; + connect(); +} + +// Try to connect to the backend every 1s (default value). +function connect() { + connectTimer = setInterval(function () { + if (websocket == null) { + websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc'); + websocket.onopen = handleConnect; + websocket.onerror = function (e) { + e.stopImmediatePropagation(); + e.stopPropagation(); + e.preventDefault(); + websocket = null; + return false; + }; + } + }, 1000); +} + +function handleMessage(message) { + + // ignore + if (message === "drag") { + return; + } + + // As a bridge we ignore js and css injections + switch (message.data[0]) { + // Wails library - inject! + // case 'b': + // message = message.data.slice(1); + // addScript(message); + // log('Loaded Wails Runtime'); + // + // // We need to now send a message to the backend telling it + // // we have loaded (System Start) + // window.wailsInvoke('SS'); + // + // // Now wails runtime is loaded, wails for the ready event + // // and callback to the main app + // // window.wails.Events.On('wails:loaded', function () { + // if (callback) { + // log('Notifying application'); + // callback(window.wails); + // } + // // }); + // break; + // Notifications + case 'n': + window.wails.EventsNotify(message.data.slice(1)); + break; + // // // Binding + // // case 'b': + // // const binding = message.data.slice(1); + // // //log("Binding: " + binding) + // // window.wails._.NewBinding(binding); + // // break; + // // // Call back + case 'c': + const callbackData = message.data.slice(1); + window.wails.Callback(callbackData); + break; + + // Application menu + /* + case 'M': + const menuData = message.data.slice(1); + window.appmenu = JSON.parse(menuData); + ApplicationMenu.set(window.appmenu); + console.log("Set application menu"); + break; + */ + case 'T': + const serverStartTime = message.data.slice(1); + const lastServerStartTime = localStorage.getItem('wails:lastServerStartTime'); + if (lastServerStartTime === null) { + localStorage.setItem('wails:lastServerStartTime', serverStartTime); + } + if (serverStartTime !== lastServerStartTime) { + localStorage.setItem('wails:lastServerStartTime', serverStartTime); + location.reload(true); + console.log("Reloaded"); + } + break; + // // Tray + // case 'T': + // const trayMessage = message.data.slice(1); + // switch (trayMessage[0]) { + // case 'S': + // // Set tray + // const trayJSON = trayMessage.slice(1); + // let tray = JSON.parse(trayJSON); + // setTray(tray); + // break; + // case 'U': + // // Update label + // const updateTrayLabelJSON = trayMessage.slice(1); + // let trayLabelData = JSON.parse(updateTrayLabelJSON); + // updateTrayLabel(trayLabelData); + // break; + // case 'D': + // // Delete Tray Menu + // const id = trayMessage.slice(1); + // deleteTrayMenu(id); + // break; + // default: + // log('Unknown tray message: ' + message.data); + // } + // break; + + default: + log('Unknown message: ' + message.data); + } +} diff --git a/v2/internal/frontend/runtime/dev/package-lock.json b/v2/internal/frontend/runtime/dev/package-lock.json new file mode 100644 index 000000000..122d45ad7 --- /dev/null +++ b/v2/internal/frontend/runtime/dev/package-lock.json @@ -0,0 +1,656 @@ +{ + "name": "dev", + "version": "2.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@zerodevx/svelte-toast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@zerodevx/svelte-toast/-/svelte-toast-0.5.1.tgz", + "integrity": "sha512-YxkHhs62hZG3ffhhdi8Jj/VdmH2q/pFs7UxIf/pczShQfL80nIDtJILbnT2jVBY4cv5fXLQex1q4wKNxst4BKA==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", + "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "esbuild": { + "version": "0.12.21", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz", + "integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-core-module": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", + "dev": true + }, + "string.prototype.padend": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", + "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svelte": { + "version": "3.42.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.2.tgz", + "integrity": "sha512-FOyNYKXb8wdE0Ot+Ctt2/OyDLsNBP8+V6PUE9ag6ZKeLslIou0LnMu1fhtWUA+HjzKTbAM1yj+4PFLtg/3pMJA==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + } + } +} diff --git a/v2/internal/frontend/runtime/dev/package.json b/v2/internal/frontend/runtime/dev/package.json new file mode 100644 index 000000000..843ce7761 --- /dev/null +++ b/v2/internal/frontend/runtime/dev/package.json @@ -0,0 +1,18 @@ +{ + "name": "dev", + "version": "2.0.0", + "description": "Wails JS Dev", + "main": "main.js", + "scripts": { + "build": "run-p build:*", + "build:dev": "node build.js" + }, + "author": "Lea Anthony