From a4a4a7efaf1964abd0ca22c327e53abb934f0af7 Mon Sep 17 00:00:00 2001 From: Michael Riedmann Date: Tue, 21 Mar 2023 15:40:23 +0100 Subject: [PATCH] feat: Simple systray GUI (#78) * add gui boilerplate * add system tray menu * improve status check * add gui build step * add signing to gui build * add gui to msi * fix wix config (shortcut args) * add startup componentgroup in wix * remove terminal windows on gui start * fixed systray enter and cmd windows popup * add status visualization via icon color refactored and split check and refresh loop --------- Co-authored-by: Marco Blamauer --- .github/workflows/build.yml | 44 +- gui/.gitignore | 21 + gui/go.mod | 30 + gui/go.sum | 91 +++ gui/icon/icon.ico | Bin 0 -> 13252 bytes gui/icon/icon_err.ico | Bin 0 -> 12955 bytes gui/icon/icon_ok.ico | Bin 0 -> 12872 bytes gui/icon/icon_warn.ico | Bin 0 -> 12836 bytes gui/icon/iconunix.go | 56 ++ gui/icon/iconwin__warn.go | 1079 +++++++++++++++++++++++++++++++++ gui/icon/iconwin_default.go | 1114 +++++++++++++++++++++++++++++++++++ gui/icon/iconwin_err.go | 1089 ++++++++++++++++++++++++++++++++++ gui/icon/iconwin_ok.go | 1082 ++++++++++++++++++++++++++++++++++ gui/icon/make_icon.bat | 41 ++ gui/icon/make_icon.sh | 38 ++ gui/main.go | 7 + gui/menu/menu.go | 223 +++++++ msi/AzureSignGuiExe.ps1 | 9 + msi/Product.wixproj | 17 + msi/Product.wxs | 35 +- msi/SignGuiExe.ps1 | 17 + msi/SignInstaller.ps1 | 2 +- 22 files changed, 4982 insertions(+), 13 deletions(-) create mode 100644 gui/.gitignore create mode 100644 gui/go.mod create mode 100644 gui/go.sum create mode 100644 gui/icon/icon.ico create mode 100644 gui/icon/icon_err.ico create mode 100644 gui/icon/icon_ok.ico create mode 100644 gui/icon/icon_warn.ico create mode 100644 gui/icon/iconunix.go create mode 100644 gui/icon/iconwin__warn.go create mode 100644 gui/icon/iconwin_default.go create mode 100644 gui/icon/iconwin_err.go create mode 100644 gui/icon/iconwin_ok.go create mode 100644 gui/icon/make_icon.bat create mode 100644 gui/icon/make_icon.sh create mode 100644 gui/main.go create mode 100644 gui/menu/menu.go create mode 100644 msi/AzureSignGuiExe.ps1 create mode 100644 msi/SignGuiExe.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0fff2d..9be927e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,39 @@ on: branches: [ master ] jobs: + build-gui: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-go@v3 + with: + go-version: '^1.19.6' + + - run: go build -ldflags -H=windowsgui . + working-directory: gui + + - name: Sign the GUI Exe (test) + run: ./msi/SignGuiExe.ps1 + continue-on-error: true + env: + PFX_PASSPHRASE: ${{ secrets.PFX_PASSPHRASE }} + PFX_THUMBPRINT: ${{ secrets.PFX_THUMBPRINT }} + if: startsWith(github.ref, 'refs/tags/') != true + + - name: Sign the GUI Exe (release) + run: ./msi/AzureSignGuiExe.ps1 + env: + AZURE_SIGN_CLIENT_SECRET: ${{ secrets.AZURE_SIGN_CLIENT_SECRET }} + if: startsWith(github.ref, 'refs/tags/') + + - name: Upload Archive (tar) + uses: actions/upload-artifact@v3 + with: + name: gui-windows + path: gui/gui.exe + build-container: runs-on: ubuntu-latest @@ -28,7 +61,9 @@ jobs: build-msi: runs-on: windows-latest - needs: build-container + needs: + - build-container + - build-gui steps: - uses: actions/checkout@v3 @@ -40,10 +75,15 @@ jobs: WIX_PATH: ${{ env.wix }} run: echo "$env:WIX_PATH\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Download artifacts + - name: Download artifact (linux container image) uses: actions/download-artifact@v3 with: name: linux-container-image + + - name: Download artifact (gui client) + uses: actions/download-artifact@v3 + with: + name: gui-windows - name: Build the MSI Package run: ./msi/BuildInstaller.ps1 diff --git a/gui/.gitignore b/gui/.gitignore new file mode 100644 index 0000000..7cd1091 --- /dev/null +++ b/gui/.gitignore @@ -0,0 +1,21 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work \ No newline at end of file diff --git a/gui/go.mod b/gui/go.mod new file mode 100644 index 0000000..9f572ad --- /dev/null +++ b/gui/go.mod @@ -0,0 +1,30 @@ +module github.com/cloudflightio/dockerinwsl/gui + +go 1.20 + +require ( + fyne.io/systray v1.10.0 + github.com/docker/docker v23.0.1+incompatible +) + +require ( + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/stretchr/testify v1.8.2 // indirect + github.com/tevino/abool v1.2.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.6.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.1.12 // indirect + gotest.tools/v3 v3.4.0 // indirect +) diff --git a/gui/go.sum b/gui/go.sum new file mode 100644 index 0000000..892676f --- /dev/null +++ b/gui/go.sum @@ -0,0 +1,91 @@ +fyne.io/systray v1.10.0 h1:Yr1D9Lxeiw3+vSuZWPlaHC8BMjIHZXJKkek706AfYQk= +fyne.io/systray v1.10.0/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +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/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= +github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +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-20200226121028-0de0cce0169b/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.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/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= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/gui/icon/icon.ico b/gui/icon/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4712d1d012bff75768f49898b132843aad72e3f5 GIT binary patch literal 13252 zcmbVT1y>tQxDEs-xI=Nb;!xbRI23oc;_gzQSh3(5C@wATUZA*3aVb{ZgWr7j{)3xj zPc~=H?3`p~_I)e>037W3-vbUn1*qi#00?2{G3u)F7-*zuuu}|01sTo%TK_vxkYH~{ z?&UWBeR6SE)rOlY^2r7OcQ>CG|lllU5AW9nbAr0MFwsl1|8$& zZ8@~PyKm`UJ}@s0>c1;J_cuW6pj_H)OKl5>{?I3ET(jZM&897jQfRI#t7iq?b}B#e zixeWf3cT}eMOd|_$J)Ch8B6r1dtFrTBD{Ge$bLgK5s*%IIz|fvy zq~{`0=#O87m%f5b_stVIPuo z^3m((%MVfYjIUvB0>9=!dS{W3se81ws z9)29s_>h(KfVm`Sp~xV-lwDh<0l)^r4KDAGUi*12rhwl5xEQy0gtavhT_HkYwO#N& zYPFFki2IVQ*J?xL=Ng{pSYAFQJzu##Bt&hkhRW1&u^Hd7=vjDEh<}=uLTEi>S`WS0 zvAFrD9DIGmKX^A;T*XvMPH2bQ*1Fnr?C|rAz&L{ofe9L%HDlII0jArDZyPOKeRgOx z#0_Pn4tgJr9RKaNu~n4p@jrm2Kk<<sX<%)$3+afz=N@DIjg@-61DD;}))FemsZU)#&w!2)?8W1$-+&zJpG}$Vz zSWqPJ2|JnIlxMsPskC&&Ro;vpU*{*anNZS&GU6F(O(ZnyFlECRMAMLFPTcbT{wuD$ z-sNeqs_PJ~K_DrZ&Q^5{jI0^1G3%68t4ZAemIe+@PCKjV2OOrSz_r2?S%|$pm{vo{ z3v@$A-@FxK-^Ed9^3ZE)JbJ!b+#wMQW9R+ot&jfK6yG)eV8a-HNvnSOCPm^>os`E& z?3{NIi^G9X_B)jcH0KP8dKU@)uMe4ou9{Zqm;udHLhVAR^8ssDLE^@ zS@q`c*ty$Z>rCWmipg5dVhhu8voSLRKxuxmaA)*W1d{7d#FPvg{FKJ$U45vc#v*iI z!T%}}sl}cosVlgZb9LgV!$wD^*9&92DvqpPu;zw2NB1oekNBzkrdpqRzEEs_#z%AV ztH(jhaGwfumizrUn7X-HAw5lI@A3312wHG{Lc-mj| z0a-c;@6&4QKz9jvRj$xn8@@-So&57%Cam(_+EUS7If^WRz?c!*7wGu%$okWSWkMv3z5H13Yhjk z2X;bCC#86-#%*b*=?l;5=XKvRDV7%H=LGEz9(Qi(2NxF}dg`@z`VW>q2G9TI^W)#d z{J;yoQ&bT=`bJsvG;w&owu2T(H4UID>xvo4450>Foy_v-qr=hf*ZrKRX>GEYu6qZ-a zz@)YGoDxw~X`3559zgIk1A#^&id>m`wcPzP@%8=fN9-KG1KYZpEQz!Z4YcmTs;DX8 z4Vuc|k<7AwQ?U;VcxfSU6V(TUV-^Eekcg;v)<#SjILBC{+ogVifH(L}U-SOuiT=3s z!6D{>0E?@%s!0`k3r~a+S53w9zgB_(b}s@BJwii548Oszx+2Ac>Z6R1%d_}z)9oGK z$2>R1(Q0nQ{buTyHSOY`ZY*y3Z`igsDsYMGAF$PRql4WL(efrS+N^8$Qv|3MqH~I-=X;n1%J`R%u(P$acWo$<~Ztpyx)#{V`u5>$^bPf`qx? z0pO7DEU{?vN2i^>lOFz!u}u2Tv8N$Hpw||!uZ#y_VQpaqvC_5dabQ`8M&LwT^TSWH zJzmm*-9wB|y9FV?ejWxqUq3FE)?fF3wGhpFc25 z35A=QMw_nA8+$Na1PR5TCvPIG8L_m?JAVE}LN1x=$4tf=l)pkrbeexwepo&~ybhXG zqtMu~)c#8pxckdy(^mu643`UHU+a-2^P4t4f-|&K?=FE ziZqNK+UOjNckop*>Ha}!ZfFh!t8_kH$B;2ixy=;~&(Wg+qh1GC6ZS3C+0s$1}( z4kP6Jc?(|ZJ|Lgxrw89EE>oT5bCgUv_YC?l;bJWaAjvc z_eT+*RD-lArbBGp#Chfw10!Z%A3|fd={Rlt30m8umY4bj*=|J(Ia_CPvtvr%J^mB@ zyTcAC*VJIdd;6Fj<7-_CCsk*q`J4)WqKZ~j_xeiO|ILOo^OPGwi))^qc{xvff0X~ec}xJ( z9}?ZOq^eyyf1&L6j^)|f^+Dr8CbHN#PtN#9KqCc%Gee=)-Q?5z>|MYb2&RX_}#zWZ1FSBj4XzO{8&B!c;L)w^0Dq??g-PI9`xujQAX zcv;5a)-(i)!{v7;d2*xlc2q0r`DKgy#lHx<{t*glsVwERe07N1PgYk**847GSe4Fcaf5feO2$dK6+}0lL5NtRCg+z{!B2Ly;vGQeapgR_8`h?%0cAbih4IV zA*^$9GX9G_WB;HYIpLDvhV6o{F6Aig3d3uKMhdGp%cf0my271y=Y7jJ`NVE-*!4KCm1HylU(?^MKs?Ap z-Ymg;RD@lcAEKG(8A{%RLv$x*v}G=c{)yWlNpKS+5U>Elj)KMUm}tycVNwy}nqKM> zMZet=agl|7Rt$H*5Gy{p&bKS;7SkpCPkN1T`ONeze0PDm2eBb3xR&85GQ{njFZN+` zeb!?jso>0mI)6h^nVqwouT$Qc0emF)Gx=N=!jT{E0_E~&c6e?^oy&krW5YTF+0lQf zjX5kM^PIn&Es>NSTu7hym-ljXYh->R{g?^L8G+3uM2n*?9J15 zcX_#Nwz~lj#d+X2fIr1XG0<*_V{UeYgj^bx1VILnqem7RaAz5?hQQx^&ueb(u+PBr#L<}>>yWV_J6zr_z zmhF_^WNW)?Y3FB@iQ_u=C+)jlFq-P2aSPUQ{F7r(bzbDe$$*$!&iZ zhu!X<3sc@**#zG}JiSw{7nXJR%mU>owov1Ye$#S~`X!GCVfIsMPEVkgC_dXZ@g^bu zkDtBE%qurG?Jq}h=Pt=Gy0hYjM{DWJl~+p{mtojix~W06SGG-2Zl~xU^J2dw?_#BE zS1EFZv_#52S%w`MEwfB9`o$^OG$gc_?$6ir7oX3*CWIhzt;2xna+iOk6CVIzUa2LS z3Xl2ML!|D?RJ}K3Pud0>4uN~|jA?F1=8hC^Q6h;9(dxDtRuTgjBlI_?!O0K@his#} zK>-y}rngYMpm!)NY}8Anl&@BSNw-3F$S;*#@>wwOT;t8Dh#WLHrvD%eF9a;Yj;lR^ zmC947@|xpHYN(N%@i>aQ8&>;E)wJDxR#ZN4&zuueW^hQT1|9vZe)lqL$+KuI z1ivdOewNQ*lx2acca;5|v^OE|{)BtCuJMZeAsHQ;zhw|oV60eZkQt7a-X(vW0B$OYm2jTJ&e8hdr zI&YA!0Y|bMS|`qIa^dNRW&n-CJRA2|6filFBvBFu-F6fk1OCfH zXDHoB@2x%ojTStro-|Kz8P+sVuLp0KYkfu@d3^} z06}=*tBRJI_Ag^{_u0fz%3K=VNyE=>MfK{VA1sMWQwuv?z{fK$Z_Tt|aW?5%qpq5b zn13_mO+bzTPt<*FgV1a{GZ7-2^KYE*w>48u!^@4{^t$i{4(ogNprkn& z5;-FEj*|x4sXK|mz*&<|LE6jG_s_iA;HN8|_-}S zhNOUVy-OVnh(8}ed}b?uuKCSy3I<_opb?+(h^X0a6ot6*7?^Q3Z1b~s{!6-`S_wQu zjc(ylhH5itzzCN#(YSGbZHd<4q`~^w8N^(FmT!bU#=p?_NPZ`LGq<9A{{dcW&bm^j zKaodsBzT$jm@-kn9_-!@g&X zkUOH}KUbgD!n4h*zqbJth(B{ZM9X;~XaBm{&wk}xgPf+GG?>-MI*LdxWwah6w~=Ib z5hXI!*$!CViq0Llqx5oSeDOcg5@viu;F=;N3AIxW&gl5PCJs>#>qmRSe^6hoxbgeG zl@HUQR0azI4%gCXqbN#Ro|cN_2ilN89*X5YhUdw{b}M5@WT0aa(ySWgUSgx16-$nm zO%BQ4H{t1dT3(e&Z=P31moTMFAnu?Qr7Eul@o^#73Tw;a+)Y8oO3nqI8SWmSz!5L< z6enWNm*t;CK-WhVEZqpOv@~PLg4thn-_k&I3|@2MAv8O=fIf?BzzyK8#pOOjtl#)e z$bHJ=M150j$=|a+q{`(J*0Y}=(>{7BhXG zHYap3Z(u2ao213HpRvK&ag8LxF$F~91k*7OV5>jK1m!BUy%)##kbsQ>p~wBS zKkx50p&wMz1wmm9S=nG{5!VOLnLqH!nqIE4fs9_H7Q{nJ;Tq;3K_!~ATHBTB#SShJ zEzDx_Y=(hlv~1}Rm-78A^|<;DBaGQHokr59_kPX((n>L-SZU_fk(j3eBZ@hCx zQNTB+(10&;((}*Jtai8sjtn}4Z2De)Y5EfbZTlf|VHdP1dkh66nOE;Kw2-!=8O^Tn znyqB*+Aw9zNGKTc-Gio5!rGDGo+Tb$8ZP+sjdQk0Xeq+r#QS=%1TLkmi5*GKG^Eo) zs|+jwFpWtZx$O6m50YkTB9PyYe4Z6MiX6D4fC{hDPuZ37Z_$c+=U5*Y5#rFs4VyKV zaP~-|?Je&!%whsUK|&;Q3NuZz-h-M}Q{!ph+vP9aWbBC$aR*6a}(` z$3+A1*$;9xZ_1JLe+A8?YCdNg0hbK?TU?AMa6WZ%|J*r>}_q_UOsj*Cb=J4E9i=yK;Y?}~O3UrLH`Tk%9@D>@1 z4h32A{pH`C3?9)o6UrUX6QxLy?ZA55FM@*vhpD}7`*OS?)D04Lp9FP!hWPG3UBgyH zl{BDO#(gG=%JY%Z3>OvuePhe!>-6P<0UYkxYejRW^u^e%RWwj9JpC~Jk9mx3ErMvq@m7XU`BNQ-Zg&`I0A!zo*QFZ(j zQ%Q=ok{nw(alEU(4Q4Ta+Pc<*?V~pLEUPLO#p62B$jCy~F#e1Z;G1xQEa~-2Sga;> zk$q)id^l#EJpL%0liDRB|EJZ*J{=)#Gr($1Bzs!V9%xGswrz!55G*rwB)Xni_!sZ5 zV9MgF&X|j5Ra0q!!H6^2!@e1wk)Imhy3lwYzPaI^i@m!0JJC1^XS7kyn$S_d==ciw z8^Ge*(BvcVtXcrM#nQIK)0C7bisF}g{EK*V)72X{5vL@6JbG=DegtmR(bZZ{7scpJDO5o_;thU+iqq_7>HAl32@#l1(_n6|41+vYU?8dZ=dK_HsGn0u`cF_8gL!9? zd(p=iz>P3`qUh=!NLVOS8n_cb^p`JyIb_UrwxyJ)>gA|9%$%4N;%?+QbN=F`L*a)Y zspyW>bP&8%*G%v>Eh6slF4m-%cS)gQCLgI6CcXD@TH<3NTW9K=O*1VO7KJ=i0ek(m z&0HK_>l_?c*Bn5UX4kb*`G@)9_G)`BeqAb1e+=G}zn2H3|64_;sf|st+Bl-%L!KAD z`J?!p;h2A3(>UV%hWU1J?Bc_t5PkX?@Y}La-GX+j9 z{d>MHT_S@BNU#1Dggq&NUIQExK@|$)n#iU$5PXOjNRKgqj$A!pz$VU?6b${w{{1 zTtuyzI5btvjV5z6QsC6#B}S<2t^A8L4DCmge+EqNmSc=14Qp9b9UySV6Ktts%xj|W z9tbu*74HZTyW_jupc%Y$!BkGQ1hI;f7U}gj(-K4uiakT%dEj^hJjoEtGae#yEl2xH zLb;4QtZFln&aE5dzrMJIRwd3Jg;>kyy_!<7UJR6r?4em=M#F(D3BZy>`OK!LHc8zQ zh(h5My(pGs|Bfq06r>>jS+LvjM_ZGG?v8sxXLOSaB2ICg>-&C%3<78_TI^im?8-X+i_14ojtsdNXM*?DLxzH zV6S%-ZxjE+p%?D!3-+lc#0qhAfDL7pvd35RGiF?S@=Y8+ZQ0a ziTR8J+B2T4zpe4x%c33+$nnZKQyW+iGT;Z-Z1wUD$v5atvGwE|%kyf0x~6?t)}BqU zWjpP)u3_U-$eP>IvFyWCmD95jgDHukZeA{p6PXP=-#~GXBZ5+EzX~n(=B6NP%lv(@ zP}1|D6GA(=ConWW0*__&*q;aRH@VQZ{`27ei^N1!A$|x zcb)=D;>BS#ffq4IWoxoFzm0#(6&gw+%5G;}VZcaS=mtpQBhxf?64OppziFPjlp~%+j0$wXS8|D_JRkbV#TaRl|lSdvQ zsjslN|KUod`Cf4A05F&Y=F6*DQxOQw)F4}Sg^BwFho76Wusqhq#XC5nsid)HxKw%+ zO(!*Qb$sBxd&*aj!34w^dsaWM_(`2GRZFN-+-SuP?vICaKF&X1JB2ajHki4Cc6)bE!#oPMY9)etn8{*$~!hcaSq+- zwjyLnc5pry{0Z^KchIHqpM>?bi^9KsJ;expFG3QUGlMM>J-V3>J}E7vYja=Zj>99t zXCbj|$L1A5*kkd;>ha_RN?g&Bz-6G+#A>kGo=qm@s9rvP4sPO|85!g;=(LR+SLKEe zW6;q5`Rhbxzz(!l204}}8({J&`e=L_iX_1U-}+lRAhCLOC`&`p!zbcVa{3*zLt(wO zt~5s=<<5HXFG)i+mn${=G%zP&7Q3`BVWQhHZsD<-wA?TRcLdV`Fj;i(4iXKm&f42I z31iTY3u!q!qZnjwq&-N>I>OGdxTy--`9;bbetSo{9d+(u{b;lhquF5Z&%3)dT}zTh zAH7v1xLuA^NN?RL#-ylS3NFvsmOu3|yfa%;C1W^GI6JB^%C?dA9sK&%;KM~k0teH} zV<1slcG+vE1Mi3L0Y!AZk$9&?*K|~@qG5BbPvYeH%!!=~WrW-ZIbljM9i(7Li@Cf9 z@EoD^`oM8_8jJ@&gk)!V9iv*58sVX6AD-~aHg6LXV_r;&zoA!mK4sXxE!QJ zsQMRDsM{O6$Fzo{_mQ!Uz!+u?PoGF`ez;VyYTmi}Pv)B8nVz){NGJ~R%yYP{Uf4EfQeG8ccH5XQqJAMM@Nxc4SEL0D|O0(bT=4X}Pc#s?^YM1_T*`@FhoF$>FL}x(# zoquHt5v?C5lJ7+g(Hl8Pxm3;a7`PWvq=F$Mhq=ice2rt;o_p9^G{}*J+CK$cmqrJd z{cpmX(#5PmhX!#*=YPf~l1y!)1X({jVwe9)$ItJ+pXb&0$cm1yVF0?)M=?{|b)KAO>3uTM46B-)Hs<>O*-555m`bp%zr#}8i+1%1}r@DjI*^!JUj}W;uoaY95RI4 zkQ)V<^4(gvN&#K3!B&E!j5^iDz>iD(+NVb|D23WZAKW16llFD9U}V?Q4$@FlGN5jR zb^?;Q_}MraF!k?EA>AKx%d2hAm*%JY;Q&A&rVqlrL(TkDTl)c_(2M?)&$Ge?0{P#d ztHBD2NCF#MUN&9C?7smsyI-$k@Wy7go^f{fDKDJ_DjD^uW^awPB9h_vps4XN)oRKEj?jGyt( zo^1_Y6E=%YN#JTAj^zj)_gDBd>!Gz3gsc1SxlQH#ZaU5MPplE9dECE^FOp98;!QQ+ zOk-$sO5ac7WL=#e)&`HDrw?MflS)q*TOa?6nx$rGB3gY_2C^0eUo2wQ!sE)~xBu|^ z?<%gR{`|Zu!KHQ;52P%X!B$vgfOYJw61$hb>CV;Xdt{6{=7D1^@NE1<0>z&EwGvs9 zK+~2}8(?9FdgxgtEJ4w?QMV&&@{_H(;DSyxhf}L9-MOGyWCTgVXZjOH(`socDNMM> zGihXN#$D6C(~9M3VlM;zp6FNx9Da-To|V?e!Yfq_z0AfkI4SP*)pv5WerySqaT`7i zH8|wj$y^*rnqmI9xYVclugqsa0}a(KSDTi@BHbHo`9?0jAz9L&v95s_cXoht-X6^` zlG6EjfY-&mo8a)zkE@{(BDyMR`E5s$4?7p*&}^K|MHP3HmFM1_N5SJ_yAH?9K4CRv znnM!7hzDXId||ogBLSN@iJJVg9EMvo&X|ST+?`R2ylJx(K*0w{lUeb^7dLgI{-$(o zUPWKCLPaOXk)Q+F$ty#yH_5dZAcO34nN*6KD-%8^gnlab2WD;xn~MkEg_P}s>18Yq za+z`lkke|uovdzkQg6j~w-#Tl^i50V?g$VSQ zy-Du}ucH4^f3B@;8gmy=>bihj_fd@rK9CvTCeNM+Zhsgzv^S4Diaqg%TxJ~Sb}%k! zu1mx?ez&qgJY3Wba?wn|B8OgnGW8K8j!$YNga2oCj6-k1wO?gnedzuEZHoBdTyC!? zYGrI-PhS6_0}ub8#8P3}XP(O;n8iG+&k4`N*m!-Ac) zS7-TtWrErLas$@WByB(V_K0)O1I&T-@85NyjIqyYhX0;4EwMNzkIy%zgE(&6%I^Na zHVQ_!+m72A$FlYA%a565wc>-kuHI_Y0lPop^RS^%IC)($m2lCg`Ly-y+ZEi^zIY;G zJaxlhyK^?9pihZx6@hu?TR3i%=7C+Ri@${e_6Y^O*j7?+pK)-66)JBG!I8%T_5APR zZK%G)eF2fMhk5xN=P5Qm%vn#%3EcU$sAz1tqtb#0D=mDaSBLjvf(ty&5;G}%hqMDm z;1mKvS3U*oaACO_&5s4lBkpMLOI?ihD&FnIo_~R*vRHUkC`8wak=zNh;nqV;mX(hS z7u6aqr}1~njjVb75!KvX;MO~yH!V5~NX4~|nZc^AKoLqeEr|EdmskwDap&oQ@f$ z`37!pCAoqVJVuJ5i<7gFrWL;TqB-@*%X_vbe#RdR7c^r=26Hu>OZ$@l+r=10Nh;Nu z9&=Gm``I1DQD$8=a7FV|x=>l@{ zFMCUc89Xo-*172BvrsDJKIm3Q^`E(?#3dT~8iDr5TLexnqoV6@$uLD4e4^8jcElfQ zS|^0NZ}5g5$kZ=~;ZH)pvLX6|#L;*wbId*MQO*X)(TueV8Sp*|EZ(9kCa+J^>cz!9 zu l+w66F)`*=!O%ds1_+XwS+xnhXZjXbZ=(zFVl7Bq#CloF&U7FJ|OV;BP9OhiD z7x4W*d|spFR$z;rS-4V z9}flCrSrdT_XXZF9i1vBr_7QkgnjgYPmHCW?Z}_8P*kWq$<}u`ljniL!g|$1I9wm|)jISZr2Wm9 z7&#5fs-`ym&>i7JiAjj}pJ)p=k8u2hGp!f@mCHhH%1d|B4ZCUMRHT9!z`Q5^Nmv>Iqbdy1p&l@)fyHJmD=ykAb zBJNvn!HZD$x8Z38c9^n(3d^|F9?ouNY8Krg`(g~KrS<-3TPGd5W+ATk+d>*>M2n4v zkxAfL(aLtFcoaw*>^bn=fyu=AEFphj&ko-iZ3@g-G>jcD>;kKUilK^5uBaJ{#qeSg zN{>h^m&X~n+Gk5MDj~ogn|qmO1MM3ONyV#|!|nr!ds&erT6Q{h$CvNF2X<{(biYr0 zdYX0oPE3)I%&!q`P|HYI@zY)xSiRXNEHbeCPKcWEN9e4Xy={rKthVw+3_)lIcl=Fl z7`0`U`3^5C=Cf-%QLw71_QgjfneHqTZ0d7&Q}wI2tIzNq3&a;7(efDbR440iT@w3 z(uouQI-GpJHXNA#Qiicpc+@ptp5i|pAcJ1DV(EqK76WcXDt4AbT}zM(a49dNx_!O= zhG#%2@$cVpqSQ4yyvjs^c!eQX6BcYsHU)o~M*;8OYxGEv=Ba8Wm6Mb3aV3m?YK$tK zC&~0j8JbY1GG|bNz%v9gz_cTU{F?q73j$3g?HW-b40TvGYqlEU^Dk1-p4>>AQ~hSy zQGxlsJ6qE2?XosS`wY5(Fto@$o6mhSG+ulP611f-*CkMn10M@q!bBOC0|_95Bh}zv zyG7|HlGo^#f56?NWGaAkCSLK6<}m#zK9Ti9-LnUaG6`!m7dc7zVOwJ;362&KW+iaP z<)bNKDhVlxDAC2@(BltM(gOzZtl>wym@L)Lq)1}iMMu4uq&1KlMS3Vs^{5A37oZLk z%YMUX6AH<0kfBOzk;va%e_%0PXV0odZ;T$_u;X2ngcZ`*j#RQU9sAZCb`;fQN({~z zW9YrH*u+~gNW zxYB(b^cTN)oQITFQs8dRU?Lqv|9MK$;`(~-*E~O}Vp>6Of$_J^D(oeB6w=USS%UQ7 z`AHE_SNdMgzv(%3{fc*p*;s04yIl}me4WfENKwEx&?FK4nvyp!it)VO$V&TiV;ntekT41`keLWnaUcIL z^>_F)1(W*-kURtD=_;$`Qd^)cP06@3;9syFNN9-e%!F~M;Vi?kRoP2Na+b%^2f{=Z zA|eIbv%qw#7$tGU^_PfFJ^hm-4Bz3{E@DC>`6b8-)VuUr^-(QP2uLg9aH#6fEmkPq zsh}?;HI34lsaI~IDu{0H0gWo0+X+r&icz&2HamIa<4{ijc7retTvl&i*#V2`MrIMb zL-S-h@|alp1j|caWB2%8l5!}etA4=yKw_6NC-=0}JLXbgRdS;6dUK!!OPEDzs>N}g zi4UNsl<@qTV0vMt`$VD0JPmFh_XNNMA;;+8!^gy420nRHcjM0FTQdHl~>-g4~2 z+{x=H2;ZPhoIyRI={~bO^5p2HdcjYpPAq{h*B@I(S`_8kFw@=-;?f9TrfH z{_v>?Gbo86n6JGNF8btTK28u?7XsvvAQb&74~9BQL4=r`kqUszSt0#=c$F3XKT_61 z2-nw8i0Sy)jJ+{blec3I$n;fCWrqUOcB;i-;N9B9m(3py7`P*I_JtF5o7nUjDhkLhALmeR1wgkuE7U%fg^9vDqT)vg&_r}!4!|?b=^P8zVRDf66d5OjF z0upXa1tFZu`If>D8Cl0yNml;Xn-K=6InDwhb@#x;I%G3}z}+VA`2nsCq4BtHvbt@6 z84KiIoKQ(|7&1Yx1bi2Aa+vuAYf;CzT%@#26vNE&2G6HLo_XDUL z=E==$fnyT_k<5Bz3jJ9AW4LgXez~Z>i^{?ar+FXvv%maWP9B}OT|xQr)6*}Pj1r;# zP{#Ej#QV?I8Z{ zN2DX8PJ_EQKJQ*eRIsW_YS((aCOd~*x~c=#>+p@=KQs52qtNUls;jYa_3(UvF)9*W ztY&-EHsZ)^U+vrWZ>K?eI@wapPt{;@6$;X@3lNFL6@e`Xk>WshWL9Ix89e`$jXrDb zH6c+z;sL4q=^X!%6PpqR1F;KN{A_=4WERe?C$=^O$*-Uhm7cKvc+(HkYr&(O%K#^a zpTatWx7@c4h$HuTwS-wzq|71D%K6yU=)ZxP#2Y85Thd3AcDN%3>8K!unyZ7iU8zY!eWok z$WVbVwxgV*Wk?^^bq`=BSkpe_5Bj*oQ5O2*;;q16rnCQo=#+;Y6dF?7QZ(u4_&2=f zhfs{#>Ri;+TEc|}}K(UJ_ literal 0 HcmV?d00001 diff --git a/gui/icon/icon_err.ico b/gui/icon/icon_err.ico new file mode 100644 index 0000000000000000000000000000000000000000..c23ea66e4814c8bd2bc01e0435c03b6b54ec8c8f GIT binary patch literal 12955 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 z z0Ea7dD2Z$i-zvVOjZ=k1L#YucQx5dm>|H~U(>mJ=Jc9x2q_v|^yoZ)*dDRu~w;}eZ@m0N!D2A|fR0+ypR2YA<% z(tcmQCd=;B?ynlGxP7Kmhi~!a7Eh|N)CBOFQPU2Y1wJ_PrtU$(2j_p#gXFB&aLw6ldh?=-8CVw*& z(Fm7wol=#TI&Q;NHhlM3g8i~9zx-9_ycOtFI$}1w=Y-nJ2f-5U13b9laE94qCWM|c zc3OU7-H{0(m6gX20lfXjLOl&nbSygT*;it(V%Hi@@spJK5Cx{Fv6^QANTuJ19e>@4 ze^nYb*;)@;)2FQG-ll{rm2&WZp?-3oxXx%JIzQ_2<>>)$fPX}&USL*L(5MZgej?-0 z)?M=j3u4H`BId!dC$Aak`!#Qu6DatGKS-$XxPBn%JdSqSk^3slLd@%z_FeDAqd zNdI^@j%rr?qAzdd6TPzlo=Iubdrc+>p}Q@GjBHjrX!~_&3_B@s9_GFVzdnH?Bo}SV6KcBM==M_x_l5=ae3^nxImMbX>DinNJN3g z*)u7ua4_(rLzD2&e_>8xWHL zS--!EBAXdio!a{tjf{+B-&tX>g=TXvlu&b$Q$b|m`{>tAKy+Cv)x(Ow{qFQkAowh zuGaMlx7HezWX>R>(IkoM$l;3ClUoGoLjiss*v@LjfWT8<@ZCpPBC?~_0{Bq1t`TVg zn#3*yi`RUUt`F3mpNwSW)JnCdkOhhZc`6l2!JJ5omXgb)aF(&<(0Zafj)FPb`$0oZr6R!*U+I7r*jC- z1pF9h-b}_l#`uPLyT?J7r5qpQCiLDiiSy^n7yG(`J`iTC`(f?hM5WG$rn+ncUAT^m zYaPEKP{=IkgTEq9E>8Tkcztg({$T9)z>vfbeI2l0JGO;3IfVGnET$xtkHILMz}>Jl z^;YBh;M#`G&zp>KNwmT;8XHbhK%Y>S2nWqTz4hMWnnV73LwFjtVH1)6v`K*+7r@3y zZ(%ibxm0b5b{VTsuC2MN6NB#3oU!p8I;RsT38fHrs_pri!j_YPN1+H3sPIPz(gTF| zaNv3G2Z?I|lSxwQK-nyGb?a}bnnPo}T+n?l9Y{8(T>iPJlZVizv#Za9#A3tatfw|T z;LB!q>RjR0LoTmnr+$gOy`WT0y0t$6l{)l`&II@xZqD%X0{d4B_~kOaY7)#N48LJ2(?Wv-2pRvG9L@HD3?oCj?ndFl=nfJ zs4$UK_cDaC05b-4%QaoR2PshaJt;2Cb6T~Y?MgZHiQNz?lVfTOE~N(O0ayr%P{H(wg^$na;zJX z3@X+SB19o@P|OAlW+BnL>sXO?j7W~rRxfomH}UE9G>Y)H9K9)K9*RNDCpMIJ8WjUC z@qQcWPXdam0Zi!qkPpZfyGtv|(gIRKh8DTa zWhW9;Tty6n%EoBGj)(0Zf}vrTs=PFVNXOSrW_83c4W5jWbv)XjS*MNXr;~(NxtM^R z4A3YuVpeX^3>ODYnmNe4#EHv{7#I&n)+7-l&me>-8h{I+v5CF=39(m(p}+>9SweE% z3UF`}F&T~O$w95)UgAaiIm!i+qwWTGD=b=eaf4ptnu7|s)NK>6IdS07k^4z-k%m2) z2{#oV!tD_U`v~C#a%whb*2KXE;HK=+Q?snVaWZiGAM5)AY{0zq-C(Fy!6+$>IW63N zTq@f(3rztR+|+9Xn{6T>4fg-7tHe|Q=@Amtk|@tI#vUP!XaXCd)*0GpL+$i>5Tz1; zo34QI^$cIFP^IbgO&>fd(Aod;l0R3``5e4wg=%%1|1diH9-MG9zqX>`+?;V&csQk# z;KF0jp^HXWMRl9-$3cDLY#xJTE!Qa7gE8fpinj`&oXNK6*oF4Yic>^Gi+GO}o~O!a z?G=C;RKFTCC-6FiqM8|3=<1r9{AroGV7?yQXfsnE+9?-HXBw;mkBSx3ivNAPONcQ; z?2P>_8*3<<5S1l=5v(n_A++G!(5t9NZqn?R=T}23kOoLihif`{dpof|#_2(wUJ-o>thS{X^80NAIHm0GJoa;n8qQWt6dV!Ubz* z@SIA5$IUG_w9OjoWz#o}Y5MHCNHSn;4pT1D6UT--t;iwJxYyBCh#N~>O_K7>x0J_p#_5qb)Z9B~4A6dP!AJtLPvw>F zYd-2e6zI!4ucz$gzhhyrzVgYe^=&G1?8%2!CG*ql)-`$>IU7OXF3-}7y;0_4gvv|& z!s_S_&!D81B>C&hCF&Eic%odmG-63=_`JXQ{?!yCIv=&ucEcT{Tmpeq7ak*Q>%EhU z8&?N$-d7J4As`ov6yw-byvQ9o(_aaVgyb*RHM>P%_wl5{6=Oy|{zm%GDMe61nqFJ+ zoD@K$ML%*4!K&qtU35A?O3HBZI1)#3B*%oSQP3h`yuj@W==Bud!sFHFq zJTJyGI%v} ze5{+X?0-Dl3g=f5G(LAc=e?5?<63|_SIDUT__4@Bg;C0t*TmHlNE`zgpnUIs8U{~~ z>5=?AEB?gy2~gg3L;k0oowTS13sto^)Gml5A0`W>NdJ5Op@MK{j)dsd2{HN^BkK*;n1;u+u zdmxcv*E+FNtvDh6o=h=A=$$J%2!yE;?q}Rz7LLdgzj-#?$=e7hFEkOar^;vkO#v{k zB*y8roa6w;6%I2Oynk+7YuEp7I9)&k*@A zmR>sW9sTcalnNE#Ewq&9MmRKRC)e46TPuBWIke8pQTHniX#b-b0r07RPwM7-Q{|}| zS(?DoP8l|gW+PZ=Dpqh&m_gBJk~4gr|JFTEE^ZUC23} z4#LRjwvX-T23uYnZXJwBI(0QC0R|ChbXnW=gwev(83y?mq(hLNmQciJ+ZMNF-^lu- iE4XBiC#3fUVHB%`JSU*g#luRvc50aM9V4(=ynD&xS3oOAAMJ5(P3da``bMOw; zmuQGW_=3oJXN}`2+iRlc@^r}>#Q4Zjw+@C?#qCW;0FMr&d4o&5)EmcF~LVJ!v zgR|5&-EdK;z@dFAea=>l`zt*%gB20ZE`ZL#%Hm^O-*?D( z9B;5YrLreB1|{${LW$V&TFx()xlQYZsR#<6rT#NyO8QN7!&u-Zg)R`Y!GCF1U5gx0 zY8U0{2-47*5`b_3BaqbEqGAk>Cf1rzYtUs)>Zqo3>d{Z@x3WZ4b09%>eEGR77EH~V zQ*C_Y1#k;79Nc2Brz-`(>{fb0ib*``vexf#QO+Pte7a@T)S1T!HtGW&eQobLm|$5` z`cyaph30{;$@MFBe_j#~o$DG-;E-|DgA!&V*2g^bhj-HdyW8U@FSS2){;R{$1f~Pb^6;LD>6}c=G04dxr+Y(tTJ17xDcoX$T*&--UF$|p z6BisB#RUNMfqNmua$)vSF~%VzpJqxPsxj zz`Jg~m*pkBM5s84iY0jGC&1jt0p5l$GzuunV_3iRTz9V(0MDO*9!wu@V2Z%PIg-pVL0 zpvs#yetc9mv@b(NWdJ0oN#(;^6U8O;3CZIAnAG;K(=OjdFJ!+e0Mve)N>X68NTME! z+?oiUrSZD%ZeJ$l3bR?3CDwII?0K|MX}g&T=*VfH`4|Cnw}qWz#hW>lQxLUh}a zQ{U&$l`X{kEp{4SY)`7zLLZK8h@J+(JE9<$VJ3l zD+9n2q~hH{h(0AfMReNBcT=>w!D9>Sn>23N9@IOSL0-BE#=(Onxeb$2VBS<$7ry!o z5|M2XNfRs~0q(VMWg*+!r8s6@P50GMYH(MXNGbs0lD^{f&vsNYcsXh$e3T;Ivla*( z<4u8*Epcx;O{*@|vGssA(=mDW?qQFG6T`_)uPF*%SG~Psw@_jPk1;e3+P$Z37CZJg zU}R(5W59zI*4;8;w&Vw~)i~yPj?%r!sY(ojqh7mX^=1fkcCyr*{ zA=ryzSC~Jbafdf&n#yxeQK>m-EoS{c9lv3`O@RdAR<9|1a^ZfNwr!S5 zWaFXLN$c>pyQQB&<{@JD-~Qv}#m5gI-Mz0^5x940Egf%BT~LbK#Z60=1TyUziw-ia@Jaecd;x8(kJGs z@Ah~8{=Q9&yQc-DBHl{TjA}8*I~l&j+TlZHv3#@S(BJMN@^?N~`b@d;$i&o;SQFr* ze1%nEomXj2tRG2jQcN7QgSY9uxHdhy)}H^fp^qsB{SAO$iT^s^qdh#I(9*??y1EVDN zE*hZuXq$%=F`I<##9G4<8Ym$Ge)~(wvl_#_NS_K;+cvf0N#F}4o0IQhA>jef&9*gT zxlO&&4c%4isYQvTcs#@r*+)vL8knEH|>;7h(ska-UF} z+q=rJBdw2kyNSuW5|>GyZUuR%ztM*u-s1q-u%&#U)J~k#lbLFp(@OyicC_I4rAPzz zzC7nk3XN$;eCYH5e};z%Ea^iAx!@UY46e0PYH;%4EEZ9qEoWb;1-GA>%+1Hj?BDEJ z>ji9Ur-QaeOAZFzrTedS7_{WMj>se5GwOt4`aCW5IFH1j#lCDpJ?OMM?j66ojLgC( zMIS5DjlY(6Umd?0>@~#9zf-h$_`Wvce|9={#H^wrwqO+e&c#CAwrNPUx@KN2}bx>bNxpYCYAH}ee8EFJDZyJYB$UlkVOYDJZy0$T#2;KwTD{?e&UQ$gEu6)puab1|ZO996$uXIRa-um23HPn4OX z{JJta#rgqxUxbutyOUaP05WMDu-}&Ly7a2qD65K({kQ<)Fx`7Uh_#_>2$4Mkh|tCC zP?>I&?Ns=R z)`Kf^fOxYEIGrkLH%8&F)%K(>GV5R8d4j#OF)3eN8_8x6M+eX0{Sjd4b>x(7BlyP3 zhyx{PXH&5hzgD38i{;98BvaKVqo#eW?(JjO5Fn3I!XbxzPa+!};ngY8c2n;tC*Yz6 z_Et+Z4#;^2yT>L??sY;*>iu4Lczb}*E1~z2591G&U1Y< zINFNV`vg&$@}c#vV>U7;WF9WFnK0atC6VOhK z;XAXb6*wrV?Fq{JdSav_$roAg(ek@72AkA_#co4>-}gAZf=>OP+8&=h8ix zv=J6zKy|FCPWt#p?sqYJOn%&f@$94W?z3X$H}hq71E}~;`^)30Z6W6}<4j(h{lw2c z!*-1E*1E#GFa3cgm5&*}WZ^o!zj^`QG$hgIby{&qQz!fKhDN73Na2&Uj5&2;lPQ3k zth4h^_ys5CP_prq_Kmm@w!1xNZvHW+z-9e_IuD>wY`KtZ#1>-Ua?+(ZAb2fq-(7I< z9lzdp-N6+xH(CJPEB8vd3PYGYR&7tI+u~lG??%ARN?Nbh`j0D?<)GoE1u$E@P>Vn_ zN1EeqEK*9`yEXj4IAHc5>)!g?i{rH-Kv7@Xofg1P7%rr#@zF5?cXtp!W8{m1Fqw}h{#sr3`jr+|zqu{r@KMQL7d&D1UQaHLM_rgTU4 z+`@@>k6itVgos@<3p_U_H&BKwawDVA0@^XE^M`nJCp^2&qtY~&k9g{jg>qy)n;mTf zq|O&S%!A9>z&!2q$bgxip6R^XkkFDx<2R~VoynHA#6a3~gK$Uk-EIuI@l;3o_ zdmdT@kMWK}8aC-GKDZaA|Jbl8Eb!UQgh2W&xRDiroZRkUb+Pn-!o`w8wNpOoO4aJ> zd_j@nJ#mas*Q>e!*>_#8fMV0=M7K3_Sf_ya6=n>SAoB$m-2S?h98G z_Dek|k>syG?L0bEA1jH2Sg8Zhn7Yp9H(hT{T*8-GQkow+*c_OAzscIykL6H6t<(U? zu5iqS5l4C4CppEkk;kW2L95wRL{vE2IBLfU@}bX@10D)eds*9SuggRJ&Vnjg9+s-D zCi{w~B^E0^-(2s*Yi?J}O49^l6EM0s zVwBUVHhkMEG)_I5eWGvOk6+Ac$L@~NX35Nh2uO=P`4zxq+1-8L6qwD_6Key|j63_~ zoQJxhd#G0)*6C$0T*tH9581J6wG=gEtNQvKVxv>0V;K&FXs}s7ox{?*nEyqD^=!F!8!1lqL4{w5^C7Z7JGV(e!koYbyng+-3 z0`0&1dRBbjuHNug*rdsr#!pt!%F_S1z~w>rspC+))q*Nd5O~Ph`mo<7iX4bL$BDIxE)k6>J_L=EuY5JK$rxrKJw1L`%@r6$1iE9lN2Ma59VP6tPP?vEPNRb z*6;)@+a2!3Rd@DryK8O0W2)LzlP9?VR;9u&Zn~GV_VL~a{VB+r5ja*1piDfNt?Xl( z6!L@0TVVwTx3VwcC++!kNc?xNRs43=f*wJb2to3)jqhK&Sj&I*9&>?? z81mi#RUF{nF7}(0|1ps#*loscbYW_AoT?f**Yj;xhwG~Q&Gj5hNK8sdP#t^_q3B~b zWZ&RTvcL2W1B6@Zxei8aTgN$rJmmQl8Swm;M`RzXnSY6;SH*fAzX^d~ zz07@yC{P19ksAz}g`L_fMXqY|T_!sTf7d3K$!mpJ$pd^8YixClD1Eh(w|<+!m|g|e zke#jb6ME$+mjtZ3BhqAH0c|3jAxe~P(>_ya=5@VoQk-TH&4m9602lVYf9`;y3S^EY zUTNl)u5gh#!MIvq-r_FFb-PnNb_X z+l_BS&4NpO+9EPk>R_IKktu3B*k;c~0>~crc_bb>h-LshqCfgDA)hig^k%W8qB@@#@sfYSt0C5L&!Q?M#P!EmbO=Il&gyc6 zQ#UZbdRx)bE&I9AS3Ppe`=OV(bhtBza-pKDy#BW*jNj(!u~_Z-#y_I%ycr$g0F5h(tN+ivKZ#>x z;MM|+(SM%E+@(z1R?DLf875V>&&~Id=!6kmE^1K#A68o${c=3jg!gp*smZ_P`Y2+K zVa*M&11z{7_LDV>4l=FpQD;%S`(lj4Ra6X_4dJA|SGtH!rRq@Sca4o0i>O2OEvwjU(Ieb{R#fDPRfnIq z9+3VR?u=XYx`ScJoN14N#m751^p0o|#(5~#C)Qq&spNS422o&HTNn0QtL$Izv?(|e z5#->~SP;04KlyLta@ispW@8b$B+n02g!b?jK6?&=+uF+WvN3N~|G=-;F~VoxIXW7v zo-TzWZQB-nn6RsOP6|-k>W$ah6-i0N(9FOY!u~gPj<(VvDQgiehI5F5zsvtx|D2?W z=nW%I_2Qi@%5gi zR<}5uQ2cqSBIwCU3Nbi7-ovOz&(W}ZYYSM{fBLz9zph%oXyQ&Br0~!9ZZffdli4JU zzCj+01PJ^-Y$dmy&3f5rC>m+HX6#^Km?WKr#R)cUBgAhlZc}H*H?90nkM@v0rOhOf zK?fx8dtpYK6TGfn5ePK#4`nOmxg-x{ zl!wM|U4IuOCH-<>P|2M}llKhS5 zvhFqIM`Kq3nF+1FbsSPMRD1`l(|T`@mphwf^Y27KZrBK+F~#qszR;==L{9|`qEwRI zXP^Awcg(2$_06cW1k5luo1i8!*B^x=WsiB-zBAR)Jlix@#R)q8cVshdxs&V#DqtTi zewN%5SUhpLGH7OTf+xQX3+QjUpPSnzO_X|9VsqlfjsKlo+rDDVug3xM;&_7oo2F3K)%qQ1 zDC*&)Yj1Vg9)CYjj8luY3ei){eT>b{n_eb&&A&`_rRMmCC{?DXf^IUIPjJ15PA8cbp_i1 zmAC$C!uYkwN!Hs@QA==U5+VpN9+I~aym8-5Nf)mb1BD%IrKPgfT!*#hh?Msni*+7< zJ*M*cn7oy&@tfyU^QCbDnRZFHPRXBv=Z^bAgCpl$%v{?@O8kFco zv_z7Pve2q>)Sq^2Z4L`GHvUErqE;f?+s>s{BmL})O0gCNWxj^h>^$9t(Q4=vJ3cj} zPi5Y{Y;}sH+`&^6WsCy)9HaU_EGTRa5WRIJYkAarH7C}$Ul)~_2MXMR|$A5 z)b&u~M3htfIze|5x2exr<;3|4X@sz)nO-+7#S%O%_b-+3RU6OX8tSJ=yIH6|Vm(d- zPFXhwexaJg8J_*r5Z50wg2r~St~y`=v@tdRu11$<4J4{}%3X_dJsWbw_jlg1uRg|$ zb+>Z1e_;=BuB4id#;dOM@Wzz1uX*JV@LBZTn-BKi#|*E)JgfkDZ9JnYCsCn%^K=Rc zx+#uFg=-^xbX9ZNeCDaPBPPd&d{)BTSCXj&4>r>#xl3kXT>3n3;0K<(!cimssX%2( z5ra9hczE1FvrBabKVkga+yjGDdHpJcRT2OtUx}xMKgEA33=}p}Vf7kb{FXk2WslZE zYM6Pvo}%Edd9VvU(hACTUBPo`e%nE+KvFFea zrnQn`YjaYrw1&m|j?Lh(Xf6Zs!(mi7PB@~;Fy32iY4A&G^N@~24Pa4SRMOmqR)a4! zZGMrhzTF4yL-u7ap`r1-?1gtOa zo-ljVFV&v=~gsuTOO{hTu9PJVpzR98>^Iv3VS3GbW+&?TD zsr-pJh)tV&ez^LrE6R9<@;ar$kHsM+vIUKd#Tn1@VuqNc(y+eb8oniJ5JCZh8iMIj zu|~O*)>x*=Lf-wy#~Bu}6l3^J?DpgcBVt$T*f#$+#?0GSG$2nS9(l@yqMh!c z8U28_G(D~@Jp8Yu5S!xE#{;iAreft*wZ__m=4Y zRa0lgjFB4ZtVbtr$}E(@=~2lfy-i83=V+@WbSf!dpy2@AkYx$GfPm4KkJVyj zpHInoP4dJ1F~ri?*ug?EJrmA{c`SW~S@_4FIok$JWKA8|!V5svLK^R}Xr-)2g;#$# z$g+~qaE00cSQuv62xvv)WbKjv^Lg`SK3RgTxQ7^JIueQVD})FU#5}p@Vw0&;rV`>M z;*+bVd|MFE69>G8;euk>sZGGb60l?=^`-A6E}*h7TwotsPhCI$ug=H6DgQyxKbgC6 z(8lxxLV2RZM^k@%Rn+y}PBczMxF59emzm06J@tVe0s%V-VU4QXnRhSI6Jt1|@#6MzfX%iFjjl zcECs^*XaDcWq2V+hT0zu@%U_wQPFE*@petG*^e`w%2rDgc=r}wKotrOtpE>4V5MezQ6K1w5Ii2}8qE?0YNK;YUc-UOj zx@X(w{1xto=&3hhuB;9%04+`w3$=ZAcF0x=iniU?C(j8QWQ1WqjhcV)UH4Jg@O)>H z0^o`2;em_rHr>dnf=EwRW5l_@0_eGb;CJxbP zug@cTdy#yIHg#Ntc+Yn3j0#rL9$jt5h*YpPsV=qn9pL?)f5)^yh!}Gqh-@vJ0p2-s zyOdVeSOb*7{_zK5WnN}Ijumr60Xpo8Pb0RyunJ#I1;N7pajNg#v}hEKxtaH=H8|Z4s<3u%MoR}7W>qty+m<(!j1uOA!{&l5-6%G_OUm$~iYv)km(4+wQkr4O z8qL+11+qUlg<`VV%lg^AW-1eKKlD0C;x)5eILMDDirR7mBWN9IH7VSlI#z^Bx`4?m zwrkEBCel1g0NOl0=8m(=&GHjVpYG|Fc5ByosCb9fD<;pr3-JkK^4Fudox#s^5rkj= zj9ik<3jX%8Uh%s*Y)BG*f9jns7@rQH8+s^NdhwtZ%O;8a;Zy)8b;OM^g!hj#+=PrG z&x~sME}U#}&AH)Of)c=6IJIim6O^H0^ZW_n^#A2#6!Rz0zpuHkpaOFyL0`7q5!UH? z-DNAP+&IUD2YY?RS=REfYAlj7kIfLWxCD9wQ*iy16GF*KkiOEZdpF(SsvKL?Drk^_ zAa2^0{ED;t!7{Iw>W7 zo}kjx4>aPo@iU+O)WfTwpIGIOM1F19x2RkI9_+6Uy@89D^<+bB;yRW5ZdW=W&_WqK zQRcoq%7Rg}i`E+fKFdoFj_snKv;QJ=NP$0PtXiTqitDv#7z_t} z(!53V4gXt1J7E!ivmx*fE{@isGxr&RbesH;mfn=OEc#fyAH2+Q#PFf0l%>}^Ir!bm zPr#dnPt;|-ME=9qb#q5Bem#$ifZm+F($Yf2)?h6pSN&lYJ?rgGB^lFC3`gJ;c1lY?{>FhB;Ie=EUs@DWwPUhynYS#Qv zbxO28aJ6YBTFGWiszZQjhL)%!Fvq9VgG~hZ0LMB3OznjWXX<3yi(f{eKyM0*#L#!MOx!k72Ob;1bmkO*=CFX72frzh+GI;=#3mSBLTU)5RkaG}K z5c^vmR#XP`%|>cERb3q|WoAK4m71ia%MPfOq5kiljo6fM1m8Dm+AV9#Kj&9XA@mP*_fVzn?i+gP{j3 zZk{(rMw`b7QUKf}v+gs~=5Zm^?Jbh|J`qp^#~74XYR73r3`{}nk_s^s_aNjj5`YH~ zF^|3mW;SLf|Lfz$QYt+MT4NPyky$N1$v8zAjPF( z5r;F0hoJ8>LU5geqmqFjl@i3|8UxGur+Vt&(`#d3BM4Gu=*bzM!8cL}`u~rmntcJ> zFxQL|7H($*Lk*$h#$RdvZ`06B016HrGpqb6?LWG}I6<7ESLvVL z!aq`~6ZM^+ajT!<2&@}@c9m^f(%x^bm(>z%8`rqh9ZQ}K-?EG=eUBF(*r<1@5=+{`l)7B*E;0M<5Nb@n`XkxL(&Fl zXXa;#J<@%jKZmTTQqR0!0qDe%_jTNpBDndqqy zu0ImeHjECuEn*f43^%j8*u z_+II5@Wr>^^%I|o&lEQqNh~1Jg2o={e3C0H)v$)9_)KprFla=f$MpS2wxiwbdN=H- zV-bcmw4RHU_Y>>q!NQQ3sLo4Uv$0;@BZeOv?a@Ia!Fe-bQO&G>@K1PY)}Z1Ok@;s$7}E?AJvCZ~V~#u699fg7 zXER6a-c-C9`|& z*oZLty^+Wd3sKT|*cEq=L+{cxC& zmTpmar4O|2YI=(JrVt{VbEidsj+K>B| zD7ywM4)i;6o{(0O8cL&A#%B_!S9b#`0 z$gQPI`^|o*WK1r7M^oTY6aZ0}cD*#%yY65=9Jws~I+qP#>hdH%?-s=^v4tXs8}@Q{ z-zxXmNl-RFnu4Bwvck{BQ~*V@;voy29~r|B+3XRu|!Nfv@qyZ+x^{sUjQ*2I5@ zYJk_9{9_OgOypwsg3zm*uYmn_QRpIz)wN)0zMfXhW!MdIZ>`~pCgAmfZw!_~HAa#w z6SCoioN?DlG;AsK&)&gx2;bP)^9Q3G_>`W(EAegwn9aE7%1j}z?=}ar-z|#3(Uw_n z?a0`t?|BZUJoIIdOx%NkYm^^bdDM-mh=m4v`>ClkIr{_d3@Ob>$) zGs^w8@BQ1x%RKiQxHrV!0DYd>l2Tt!Kk;uazw&uppJHb~3y649juYxL%$0tV zioIX!0dXP<;LMsjPW8TuLKIgqtp~Ypg*g$mdn*R^au9ITMj;;iesc;yjqVT#I_vnNp+c iconwin.go +ECHO. >> iconwin.go +TYPE %1 | %GOPATH%\bin\2goarray Data icon >> iconwin.go +GOTO DONE + +:CREATEFAIL +ECHO Unable to create output file +GOTO DONE + +:INSTALL +ECHO Installing 2goarray... +go install github.com/cratonica/2goarray +IF ERRORLEVEL 1 GOTO GETFAIL +GOTO POSTINSTALL + +:GETFAIL +ECHO Failure running go install github.com/cratonica/2goarray. Ensure that go and git are in PATH +GOTO DONE + +:NOGO +ECHO GOPATH environment variable not set +GOTO DONE + +:NOICO +ECHO Please specify a .ico file +GOTO DONE + +:BADFILE +ECHO %1 is not a valid file +GOTO DONE + +:DONE + diff --git a/gui/icon/make_icon.sh b/gui/icon/make_icon.sh new file mode 100644 index 0000000..1cb5634 --- /dev/null +++ b/gui/icon/make_icon.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +if [ -z "$GOPATH" ]; then + echo GOPATH environment variable not set + exit +fi + +if command -v cygpath.exe > /dev/null 2>&1; then + GOPATH="$(cygpath.exe "$GOPATH")" +fi + +if [ ! -e "$GOPATH/bin/2goarray" ]; then + echo "Installing 2goarray..." + if ! go install github.com/cratonica/2goarray; then + echo Failure executing go install github.com/cratonica/2goarray + exit + fi +fi + +if [ -z "$1" ]; then + echo Please specify a PNG file + exit +fi + +if [ ! -f "$1" ]; then + echo "$1 is not a valid file" + exit +fi + +OUTPUT=iconunix.go +echo "Generating $OUTPUT" +echo "//+build linux darwin" > $OUTPUT +echo >> $OUTPUT +if ! "$GOPATH/bin/2goarray" Data icon >> $OUTPUT < "$1"; then + echo Failure generating $OUTPUT + exit +fi +echo Finished diff --git a/gui/main.go b/gui/main.go new file mode 100644 index 0000000..9e736f3 --- /dev/null +++ b/gui/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/cloudflightio/dockerinwsl/gui/menu" + +func main() { + menu.StartMenu() +} diff --git a/gui/menu/menu.go b/gui/menu/menu.go new file mode 100644 index 0000000..ea3594e --- /dev/null +++ b/gui/menu/menu.go @@ -0,0 +1,223 @@ +package menu + +import ( + "context" + "fmt" + "log" + "os/exec" + "strings" + "syscall" + "time" + + "fyne.io/systray" + "github.com/cloudflightio/dockerinwsl/gui/icon" + "github.com/docker/docker/client" +) + +const CMD_PATH = "C:\\Windows\\system32\\cmd.exe" + +type dockerStatus struct { + isDockerReachable bool + lastCheckTimestamp int64 +} + +type GlobalState int + +const ( + Default GlobalState = iota + Ok + Warn + Error +) + +func StartMenu() { + onExit := func() { + now := time.Now() + fmt.Println("Exit at", now.String()) + } + + systray.Run(onReady, onExit) +} + +func setGlobalState(s GlobalState) { + ic := icon.DataDefault + switch s { + case Ok: + ic = icon.DataOk + case Warn: + ic = icon.DataWarn + case Error: + ic = icon.DataErr + default: + ic = icon.DataDefault + } + systray.SetTemplateIcon(ic, ic) +} + +func onReady() { + systray.SetTemplateIcon(icon.DataDefault, icon.DataDefault) + systray.SetTitle("DockerInWsl") + systray.SetTooltip("DockerInWsl") + + statusMenu := systray.AddMenuItem("Docker status", "Docker status") + check := statusMenu.AddSubMenuItem("Check components", "") + systray.AddSeparator() + + enter := systray.AddMenuItem("Enter", "Enter") + enterRoot := systray.AddMenuItem("Enter with root", "Enter with root") + showLogs := systray.AddMenuItem("Show logs", "Show logs") + showConfig := systray.AddMenuItem("Show configs", "Show configs") + advanced := systray.AddMenuItem("Advanced", "Advanced") + restore := advanced.AddSubMenuItem("Restore", "Restore") + backup := advanced.AddSubMenuItem("Backup", "Backup") + systray.AddSeparator() + restart := systray.AddMenuItem("Restart", "Restart") + restartAll := systray.AddMenuItem("Restart all", "Restart all") + start := systray.AddMenuItem("Start", "Start") + stop := systray.AddMenuItem("Stop", "Stop") + systray.AddSeparator() + quit := systray.AddMenuItem("Quit", "Quit") + + status := dockerStatus{ + isDockerReachable: false, + lastCheckTimestamp: 0, + } + go startCheckDockerStatusLoop(&status) + go startStatusUpdateLoop(statusMenu, &status) + statusSubMenuItemMap := make(map[string]*systray.MenuItem) + + for { + var cmd *exec.Cmd + + select { + case <-quit.ClickedCh: + systray.Quit() + case <-enter.ClickedCh: + cmd = exec.Command("cmd", "/C", "start", "docker-wsl", "enter") + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + case <-enterRoot.ClickedCh: + cmd = exec.Command("cmd", "/C", "start", "docker-wsl", "enter-root") + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + case <-showLogs.ClickedCh: + cmd = exec.Command("docker-wsl", "show-logs") + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + case <-showConfig.ClickedCh: + cmd = exec.Command("docker-wsl", "show-config") + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + case <-restart.ClickedCh: + cmd = exec.Command("docker-wsl", "restart") + case <-restartAll.ClickedCh: + cmd = exec.Command("docker-wsl", "restart-all") + case <-start.ClickedCh: + cmd = exec.Command("docker-wsl", "start") + case <-stop.ClickedCh: + cmd = exec.Command("docker-wsl", "stop") + case <-restore.ClickedCh: + cmd = exec.Command("docker-wsl", "restore") + case <-backup.ClickedCh: + cmd = exec.Command("docker-wsl", "backup") + case <-check.ClickedCh: + checkSupervisorStatus(&statusSubMenuItemMap, statusMenu) + } + + if cmd != nil { + if err := cmd.Run(); err != nil { + log.Println("Error:", err) + } + } + } +} + +func startCheckDockerStatusLoop(status *dockerStatus) { + ctx := context.Background() + ticker := time.NewTicker(10 * time.Second) + + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + + if err != nil { + log.Println("Error:", err) + } + + defer cli.Close() + + if cli != nil { + for range ticker.C { + currentTimestamp := time.Now().Unix() + status.isDockerReachable = checkIfDockerIsReachable(ctx, cli) + status.lastCheckTimestamp = currentTimestamp + } + } +} + +func startStatusUpdateLoop(statusMenu *systray.MenuItem, status *dockerStatus) { + ticker := time.NewTicker(1 * time.Second) + + for range ticker.C { + currentTimestamp := time.Now().Unix() + statusMenu.SetTitle(getStatusMenuTitle(status)) + if !status.isDockerReachable { + setGlobalState(Error) + } else if status.lastCheckTimestamp+30 < currentTimestamp { + setGlobalState(Warn) + } else { + setGlobalState(Ok) + } + } +} + +func getStatusMenuTitle(status *dockerStatus) string { + if !status.isDockerReachable { + return "Docker is stopped" + } + + return "Docker is running" +} + +func checkIfDockerIsReachable(ctx context.Context, cli *client.Client) bool { + _, err := cli.Ping(ctx) + if err != nil { + log.Println("Error:", err) + return false + } + return true +} + +func checkSupervisorStatus(statusSubMenuItemMap *map[string]*systray.MenuItem, statusMenu *systray.MenuItem) { + status, err := getStatus() + + if err != nil { + log.Println(err) + } + + if !strings.Contains(status, "supervisor.sock") && !strings.Contains(status, "error") { + if len(*statusSubMenuItemMap) == 0 { + for _, line := range strings.Split(status, "\n") { + elements := strings.Fields(line) + if len(elements) > 0 { + item := statusMenu.AddSubMenuItem(getText(elements), "") + item.Disable() + (*statusSubMenuItemMap)[elements[0]] = item + } + } + } else { + for _, line := range strings.Split(status, "\n") { + elements := strings.Fields(line) + if len(elements) > 0 { + (*statusSubMenuItemMap)[elements[0]].SetTitle(getText(elements)) + } + } + } + } else { + log.Println(status) + } +} + +func getStatus() (output string, err error) { + bytes, err := exec.Command("docker-wsl", "status").Output() + + return string(bytes), err +} + +func getText(elements []string) string { + return elements[0] + ": " + strings.ToLower(elements[1]) +} diff --git a/msi/AzureSignGuiExe.ps1 b/msi/AzureSignGuiExe.ps1 new file mode 100644 index 0000000..d450178 --- /dev/null +++ b/msi/AzureSignGuiExe.ps1 @@ -0,0 +1,9 @@ +$msbuild = &"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe + +Push-Location $PSScriptRoot +& $msbuild /p:Configuration=Release /t:AzureSignGuiExe + +if ($LASTEXITCODE -ne 0) { + throw "Can't sign gui exe" +} +exit 0 diff --git a/msi/Product.wixproj b/msi/Product.wixproj index 2f1e02c..c3183da 100644 --- a/msi/Product.wixproj +++ b/msi/Product.wixproj @@ -82,6 +82,12 @@ + + + $(MSBuildProjectDirectory)\..\Certificate.pfx + + + @@ -97,5 +103,16 @@ + + + https://github.com/cloudflightio/dockerinwsl + https://cloudflight-code-signing.vault.azure.net + e21ebe2c-3b5b-4d4c-8d0e-c1ca0e8ea14b + 18462f44-aee3-42ac-aba8-bdfd3d4d8c23 + globalsign-ev-code-signing + http://timestamp.digicert.com + + + \ No newline at end of file diff --git a/msi/Product.wxs b/msi/Product.wxs index 04e81a0..04555a2 100644 --- a/msi/Product.wxs +++ b/msi/Product.wxs @@ -79,7 +79,7 @@ - + @@ -156,16 +156,31 @@ + + + + + + + + + + + + + + + + + - - - - - diff --git a/msi/SignGuiExe.ps1 b/msi/SignGuiExe.ps1 new file mode 100644 index 0000000..324a3df --- /dev/null +++ b/msi/SignGuiExe.ps1 @@ -0,0 +1,17 @@ +$ValidationErrors = @() +if (-not (Test-Path env:PFX_THUMBPRINT) -or (-not $env:PFX_THUMBPRINT)) { $ValidationErrors += @("PFX_THUMBPRINT envvar not set") } +if (-not (Test-Path env:PFX_PASSPHRASE) -or (-not $env:PFX_PASSPHRASE)) { $ValidationErrors += @("PFX_PASSPHRASE envvar not set") } +if ($ValidationErrors.Count -gt 0) { + Write-Warning "`n$($ValidationErrors -join "`n")" + throw "Env-Vars not set!" +} + +$msbuild = &"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe + +Push-Location $PSScriptRoot +& $msbuild /p:Configuration=Release /t:SignGuiExe + +if ($LASTEXITCODE -ne 0) { + throw "Can't sign msi" +} +exit 0 diff --git a/msi/SignInstaller.ps1 b/msi/SignInstaller.ps1 index 55501d6..f184e20 100644 --- a/msi/SignInstaller.ps1 +++ b/msi/SignInstaller.ps1 @@ -1,6 +1,6 @@ $ValidationErrors = @() if (-not (Test-Path env:PFX_THUMBPRINT) -or (-not $env:PFX_THUMBPRINT)) { $ValidationErrors += @("PFX_THUMBPRINT envvar not set") } -if (-not (Test-Path env:PFX_PASSPHRASE) -or (-not $env:PFX_THUMBPRINT)) { $ValidationErrors += @("PFX_PASSPHRASE envvar not set") } +if (-not (Test-Path env:PFX_PASSPHRASE) -or (-not $env:PFX_PASSPHRASE)) { $ValidationErrors += @("PFX_PASSPHRASE envvar not set") } if ($ValidationErrors.Count -gt 0) { Write-Warning "`n$($ValidationErrors -join "`n")" throw "Env-Vars not set!"