[
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug.yml",
    "content": "name: Bug report\ndescription: Submit a new bug report.\nlabels: [bug]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ## This issue tracker is only for technical issues related to Vertcoin OCM.\n\n        * General Vertcoin questions and/or support requests should reach out in one of the Vertcoin forums. See more here https://vertcoin.org/community/.\n        * For reporting security issues, please reach out to the project maintainers or other members of the Vertcoin Github Organization\n\n        ----\n  - type: checkboxes\n    attributes:\n      label: Is there an existing issue for this?\n      description: Please search to see if an issue already exists for the bug you encountered.\n      options:\n      - label: I have searched the existing issues\n        required: true\n  - type: checkboxes\n    attributes:\n      label: Did you read [Common issues and fixes](https://github.com/vertcoin-project/one-click-miner-vnext/issues/618)?.\n      options:\n      - label: Yes / Not relevant\n        required: true\n  - type: textarea\n    id: current-behaviour\n    attributes:\n      label: Current behaviour\n      description: Tell us what went wrong. Add pictures if relevant.\n    validations:\n      required: true\n  - type: textarea\n    id: expected-behaviour\n    attributes:\n      label: Expected behaviour\n      description: Tell us what you expected to happen\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction-steps\n    attributes:\n      label: Steps to reproduce\n      description: |\n        Tell us how to reproduce your bug. Please attach related screenshots if necessary.\n        * Run-time or compile-time configuration options\n        * Actions taken\n    validations:\n      required: true\n  - type: textarea\n    id: logs\n    attributes:\n      label: Relevant log output\n      description: |\n        Please copy and paste any relevant log output or attach a debug.log file.\n\n        You can find the debug.log in your OCM's data directory: Windows: `%appdata%\\vertcoin-ocm`or Linux: `.vertcoin-ocm`\n\n        Please be aware that the debug log might contain identifying information.\n    validations:\n      required: false\n  - type: dropdown\n    attributes:\n      label: How did you obtain Vertcoin OCM?\n      multiple: false\n      options:\n        - Pre-built binaries\n        - Compiled from source\n        - Other\n    validations:\n      required: true\n  - type: input\n    id: ocm-version\n    attributes:\n      label: What version of Vertcoin OCM are you using?\n      description: When OCM is running, the version is listed at the bottom.\n      placeholder: e.g. v2.2-beta3 or master@e1bf547\n    validations:\n      required: true\n  - type: input\n    id: os\n    attributes:\n      label: Operating system and version\n      placeholder: e.g. \"Windows 10\" or \"Ubuntu 22.04 LTS\"\n    validations:\n      required: true\n  - type: textarea\n    id: machine-specs\n    attributes:\n      label: Machine specifications\n      description: |\n        What are the specifications of the host machine?\n        e.g. CPU and GPU\n\n        If building OCM from source please supply used versions of required dependencies.\n        eg. GO version, NPM version and NodeJS version.\n\n        For the GUI-related issue on Linux provide names and versions of a distro, a desktop environment and a graphical shell (if relevant).\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature_request.yml",
    "content": "name: Feature Request\ndescription: Suggest an idea for this project.\nlabels: [feature]\nbody:\n  - type: checkboxes\n    attributes:\n      label: Is there an existing feature request for this?\n      description: Please search to see if a feature request already exists.\n      options:\n      - label: I have searched for existing feature requests\n        required: true\n  - type: textarea\n    id: feature\n    attributes:\n      label: Please describe the feature you'd like to see added.\n      description: Attach screenshots or logs if applicable.\n    validations:\n      required: true\n  - type: textarea\n    id: related-problem\n    attributes:\n      label: Is your feature related to a problem, if so please describe it.\n      description: Attach screenshots or logs if applicable.\n    validations:\n      required: false\n  - type: textarea\n    id: solution\n    attributes:\n      label: Describe the solution you'd like\n    validations:\n      required: false\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Describe any alternatives you've considered\n    validations:\n      required: false\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Please leave any additional context\n    validations:\n      required: false"
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "content": "name: golangci-lint\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\npermissions:\n  contents: read\n  # Optional: allow read access to pull request. Use with `only-new-issues` option.\n  # pull-requests: read\nenv:\n  GOCACHE: /home/runner/work/go/pkg/build\n  GOPATH: /home/runner/work/go\n\njobs:\n  golangci:\n    name: lint\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Go\n        uses: actions/setup-go@v5\n        with:\n          go-version: '1.22.0' # The Go version to download (if necessary) and use.\n    \n      # Install all the dependencies\n      - name: Install dependencies\n        run: |\n          go mod tidy\n      - name: golangci-lint\n        uses: golangci/golangci-lint-action@v4\n        with:\n          # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version\n          version: v1.56.2\n      # Run build of the application\n      - name: Run build\n        run: go build . \n      "
  },
  {
    "path": ".gitignore",
    "content": "vertcoin-ocm\n*.zip\n.vscode/\nvertcoin-ocm.exe\n*.code-workspace\n*.exe\n*.manifest\n*.syso"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (C) 2019-2021 Gert-Jaap Glasbergen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# One-Click Miner\n\nThe One-Click Miner allows cryptocurrency enthusiasts to get into mining with minimal effort. When you download the One-Click Miner, you will be asked to provide a password for your (built in) wallet. It will then immediately commence mining.\n\nThis is a redevelopment of Vertcoin's [One Click Miner](https://github.com/vertcoin-project/one-click-miner).\n\nThis software is available for Windows and Linux.\n\n## FAQ\n\n### Which GPUs are supported?\n\nPlease refer to this list of [supported hardware.](https://github.com/CryptoGraphics/VerthashMiner#supported-hardware)\n\n### I have an error message that reads 'Failure to configure' or 'Checks failed'\n\nYou may need to add an exclusion to your antivirus / Windows Defender.  The data directory is located at `%AppData%\\vertcoin-ocm` on Windows or `~/.vertcoin-ocm` on Linux.\n\n### My GPU is supported but an error messages reads 'no compatible GPUs'\n\nUpdate your GPU drivers to the latest version.\n\n### My GPU is not being utilized\n\nThe OCM is using all of your GPU resources.  To verify, check CUDA usage for Nvidia or Compute 0/1 usage for AMD.\n\n## Building\n\nThe GUI of this MVP is based on [Wails](https://wails.app) and [Go](https://golang.org/).\n\nInstall the Wails [prerequisites](https://wails.app/gettingstarted/) for your platform, and then run:\n\n```bash\ngo get github.com/wailsapp/wails/cmd/wails\n```\n\nThen clone this repository, and inside its main folder, execute:\n\n```bash\nwails build\n```\n\n## Donations\n\nIf you want to support the further development of the One Click Miner, feel free to donate Vertcoin to [Vmnbtn5nnNbs1otuYa2LGBtEyFuarFY1f8](https://insight.vertcoin.org/address/Vmnbtn5nnNbs1otuYa2LGBtEyFuarFY1f8).\n"
  },
  {
    "path": "backend/backend.go",
    "content": "package backend\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/tidwall/buntdb\"\n\n\t\"github.com/btcsuite/btcd/wire\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/miners\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/pools\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/wallet\"\n\t\"github.com/wailsapp/wails\"\n)\n\ntype Backend struct {\n\truntime             *wails.Runtime\n\twal                 *wallet.Wallet\n\tsettings            *buntdb.DB\n\tpendingSweep        []*wire.MsgTx\n\tminerBinaries       []*miners.BinaryRunner\n\trapidFailures       []*miners.BinaryRunner\n\tpool                pools.Pool\n\trefreshBalanceChan  chan bool\n\trefreshHashChan     chan bool\n\trefreshRunningState chan bool\n\tstopMonitoring      chan bool\n\tstopHash            chan bool\n\tstopBalance         chan bool\n\tstopUpdate          chan bool\n\tstopRunningState    chan bool\n\tprerequisiteInstall chan bool\n\talreadyRunning      bool\n\tp2poolNodeSelected  bool\n}\n\nfunc NewBackend(alreadyRunning bool) (*Backend, error) {\n\tbackend := &Backend{\n\t\trefreshBalanceChan:  make(chan bool),\n\t\trefreshHashChan:     make(chan bool),\n\t\trefreshRunningState: make(chan bool),\n\t\tstopHash:            make(chan bool),\n\t\tstopBalance:         make(chan bool),\n\t\tstopRunningState:    make(chan bool),\n\t\tstopMonitoring:      make(chan bool),\n\t\tstopUpdate:          make(chan bool),\n\t\tprerequisiteInstall: make(chan bool),\n\t\tminerBinaries:       []*miners.BinaryRunner{},\n\t\trapidFailures:       []*miners.BinaryRunner{},\n\t}\n\n\tif alreadyRunning {\n\t\tbackend.alreadyRunning = true\n\t\treturn backend, nil\n\t}\n\n\tdb, err := buntdb.Open(filepath.Join(util.DataDirectory(), \"settings.db\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbackend.settings = db\n\treturn backend, nil\n}\n\nfunc (m *Backend) ResetPool() {\n\tm.pool = pools.GetPool(m.GetPool(), m.Address(), m.GetTestnet())\n}\n\nfunc (m *Backend) WailsInit(runtime *wails.Runtime) error {\n\t// Save runtime\n\tm.runtime = runtime\n\n\tgo m.PrerequisiteProxyLoop()\n\tgo m.UpdateLoop()\n\n\treturn nil\n}\n\nfunc (m *Backend) OpenDownloadUrl(url string) {\n\tutil.OpenBrowser(url)\n}\n\nfunc (m *Backend) AlreadyRunning() bool {\n\treturn m.alreadyRunning\n}\n\nfunc (m *Backend) Close() {\n\tm.runtime.Window.Close()\n}\n"
  },
  {
    "path": "backend/checks.go",
    "content": "package backend\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"time\"\n\n\tverthash \"github.com/gertjaap/verthash-go\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/miners\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc (m *Backend) PerformChecks() string {\n\tm.runtime.Events.Emit(\"checkStatus\", \"rapidfail\")\n\tif len(m.rapidFailures) > 0 {\n\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\tm.rapidFailures = make([]*miners.BinaryRunner, 0) // Clear the failures\n\t\treturn \"Rapid failures: Your GPU is likely incompatible; check FAQ for supported hardware. If compatible, GPU overclocks or antivirus may be the cause.\"\n\t}\n\n\tm.runtime.Events.Emit(\"checkStatus\", \"compatibility\")\n\terr := m.CheckGPUCompatibility()\n\tif err != nil {\n\t\ttracking.Track(tracking.TrackingRequest{\n\t\t\tCategory: \"PerformChecks\",\n\t\t\tAction:   \"CheckGPUCompatibilityError\",\n\t\t\tName:     err.Error(),\n\t\t})\n\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\treturn err.Error()\n\t}\n\n\tm.runtime.Events.Emit(\"checkStatus\", \"installing_miners\")\n\terr = m.InstallMinerBinaries()\n\tif err != nil {\n\t\ttracking.Track(tracking.TrackingRequest{\n\t\t\tCategory: \"PerformChecks\",\n\t\t\tAction:   \"InstallMinerBinariesError\",\n\t\t\tName:     err.Error(),\n\t\t})\n\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\treturn err.Error()\n\t}\n\n\tm.runtime.Events.Emit(\"checkStatus\", \"verthash\")\n\tverthashFile := filepath.Join(util.DataDirectory(), \"verthash.dat\")\n\n\tdoneChan := make(chan bool, 1)\n\tprogress := make(chan float64, 1)\n\n\tgo func() {\n\t\tif m.GetSkipVerthashExtendedVerify() {\n\t\t\terr = verthash.MakeVerthashDatafileIfNotExistsWithProgress(verthashFile, progress)\n\t\t} else {\n\t\t\terr = verthash.EnsureVerthashDatafileWithProgress(verthashFile, progress)\n\t\t}\n\t\tdoneChan <- true\n\t}()\n\n\tfor {\n\t\tdone := false\n\t\tselect {\n\t\tcase done = <-doneChan:\n\t\t\tbreak\n\t\tcase prog := <-progress:\n\t\t\tm.runtime.Events.Emit(\"verthashProgress\", prog*100)\n\t\t\tbreak\n\t\t}\n\t\tif done {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif err != nil {\n\t\terrorString := fmt.Sprintf(\"Failed to create or verify Verthash data file: %s\", err.Error())\n\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\treturn errorString\n\t}\n\n\tfor !m.p2poolNodeSelected {\n\t\ttime.Sleep(time.Second)\n\t}\n\tfor networks.Active.OCMBackend == \"\" {\n\t\ttime.Sleep(500 * time.Millisecond)\n\t}\n\n\targs := m.GetArgs()\n\n\tfor _, br := range m.minerBinaries {\n\t\terr := br.MinerImpl.Configure(args)\n\t\tif err != nil {\n\t\t\terrorString := fmt.Sprintf(\"Failure to configure %s: The data directory may have to be excluded from your antivirus. Check FAQ.\", br.MinerBinary.MainExecutableName)\n\t\t\ttracking.Track(tracking.TrackingRequest{\n\t\t\t\tCategory: \"PerformChecks\",\n\t\t\t\tAction:   \"ConfigureError\",\n\t\t\t\tName:     errorString,\n\t\t\t})\n\t\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\t\treturn errorString\n\t\t}\n\n\t\tif br.MinerImpl.AvailableGPUs() == 0 {\n\t\t\tm.runtime.Events.Emit(\"checkStatus\", \"Failed\")\n\t\t\treturn \"Miner software reported no compatible GPUs. Check FAQ for supported hardware and ensure your GPU drivers are up to date.\"\n\t\t}\n\t}\n\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"PerformChecks\",\n\t\tAction:   \"Success\",\n\t})\n\n\treturn \"ok\"\n}\n\nfunc (m *Backend) CheckGPUCompatibility() error {\n\tgpus := util.GetGPUs()\n\tcompat := 0\n\tgpustring := \"\"\n\tfor _, g := range gpus {\n\t\tif g.Type != util.GPUTypeOther {\n\t\t\tcompat++\n\t\t}\n\t\tif gpustring != \"\" {\n\t\t\tgpustring += \" / \"\n\t\t}\n\t\tgpustring += g.OSName\n\t}\n\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"EnumerateGPUs\",\n\t\tAction:   \"Success\",\n\t\tName:     gpustring,\n\t})\n\n\tif compat == 0 {\n\t\treturn fmt.Errorf(\"No compatible GPUs detected\\n\\nGPUs Found:\\n%s - Check FAQ for supported hardware and ensure your GPU drivers are up to date.\", gpustring)\n\t}\n\treturn nil\n}\n\nfunc (m *Backend) CreateMinerBinaries() ([]*miners.BinaryRunner, error) {\n\tbinaries := miners.GetMinerBinaries()\n\tgpus := util.GetGPUs()\n\tclosedSource := m.GetClosedSource()\n\ttestnet := m.GetTestnet()\n\tbrs := []*miners.BinaryRunner{}\n\tfor _, b := range binaries {\n\t\tmatch := false\n\t\tif b.Platform == runtime.GOOS {\n\t\t\tfor _, g := range gpus {\n\t\t\t\tif g.Type == b.GPUType {\n\t\t\t\t\tif b.ClosedSource == closedSource {\n\t\t\t\t\t\tif b.Testnet == testnet {\n\t\t\t\t\t\t\tmatch = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif match {\n\t\t\tif b.MultiGPUMiner {\n\t\t\t\talreadyPresent := false\n\t\t\t\tfor _, br := range brs {\n\t\t\t\t\tif br.MinerBinary.MainExecutableName == b.MainExecutableName {\n\t\t\t\t\t\talreadyPresent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif alreadyPresent {\n\t\t\t\t\tlogging.Debugf(\"Not adding already present multi-gpu binary [%s] again\\n\", b.MainExecutableName)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tlogging.Debugf(\"Found compatible binary [%s] for [%s/%d] (Closed source: %t)\\n\", b.MainExecutableName, b.Platform, b.GPUType, b.ClosedSource)\n\t\t\tbr, err := miners.NewBinaryRunner(b, m.prerequisiteInstall)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tbr.Debug = m.GetDebugging()\n\t\t\tbrs = append(brs, br)\n\t\t} else {\n\t\t\tlogging.Debugf(\"Found incompatible binary [%s] for [%s/%d] (Closed source: %t)\\n\", b.MainExecutableName, b.Platform, b.GPUType, b.ClosedSource)\n\t\t}\n\t}\n\n\tif len(brs) == 0 {\n\t\treturn nil, fmt.Errorf(\"Could not find compatible miner binaries - Check FAQ for supported hardware and ensure your GPU drivers are up to date.\")\n\t}\n\n\treturn brs, nil\n}\n\nfunc (m *Backend) InstallMinerBinaries() error {\n\tvar err error\n\tm.minerBinaries, err = m.CreateMinerBinaries()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, br := range m.minerBinaries {\n\t\terr := br.Install()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Will be run at startup\n// Additionally it can be run if the backend returns an error after startup\nfunc (m *Backend) BackendServerSelector() {\n\t// Pick a random backend off the list\n\tn := rand.Intn(len(networks.Active.BackendServers))\n\n\t// Run a simple check to see if the backend is up and returned data isn't nonsense\n\t// If the backend is bad, go through the list until a suitable one is found\n\tfor range networks.Active.BackendServers {\n\t\tb := util.CheckBackendStatus(networks.Active.BackendServers[n])\n\t\tif b {\n\t\t\t// If backend is up and return data other than 0, save it in networks.Active\n\t\t\tnetworks.Active.OCMBackend = networks.Active.BackendServers[n]\n\t\t\tlogging.Infof(\"Using backend: %s\\n\", networks.Active.OCMBackend)\n\t\t\treturn\n\t\t}\n\t\tn += 1\n\t\tif n == len(networks.Active.BackendServers) {\n\t\t\tn = 0\n\t\t}\n\t}\n\t// We'll only ever get here if all backends are unreachable..\n\tnetworks.Active.OCMBackend = networks.Active.BackendServers[0]\n\tlogging.Errorf(\"No working backend could be found..\\n\")\n}\n"
  },
  {
    "path": "backend/languages.go",
    "content": "package backend\n\nimport (\n\t\"github.com/cloudfoundry/jibber_jabber\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"golang.org/x/text/language\"\n)\n\nvar availableLanguages = []string{\n\t// First language is default. So\n\t// alphabetical order except for\n\t// this one\n\t\"en\",\n\t\"bg\",\n\t\"da\",\n\t\"de\",\n\t\"es\",\n\t\"fr\",\n\t\"hi\",\n\t\"hr\",\n\t\"it\",\n\t\"ja\",\n\t\"lt\",\n\t\"nl\",\n\t\"no\",\n\t\"pa\",\n\t\"pl\",\n\t\"pt\",\n\t\"ro\",\n\t\"ru\",\n\t\"sl\",\n\t\"sv\",\n\t\"tr\",\n\t\"zh\",\n}\n\nvar languageMatcher language.Matcher\n\nfunc init() {\n\ttags := []language.Tag{}\n\tfor _, l := range availableLanguages {\n\t\tt, err := language.Parse(l)\n\t\tif err == nil {\n\t\t\ttags = append(tags, t)\n\t\t}\n\t}\n\n\tlanguageMatcher = language.NewMatcher(tags)\n}\n\nfunc (m *Backend) GetLocale() string {\n\tuserLanguage, err := jibber_jabber.DetectIETF()\n\tif err != nil {\n\t\tlogging.Warnf(\"Could not determine locale, defaulting to English: %s\", err.Error())\n\t\treturn \"en\"\n\t}\n\n\tlogging.Infof(\"User IETF is %s\", userLanguage)\n\tuserTag, err := language.Parse(userLanguage)\n\tif err != nil {\n\t\tlogging.Warnf(\"Could not parse user IETF: %s\", err.Error())\n\t}\n\ttag, _, _ := languageMatcher.Match(userTag)\n\tlogging.Infof(\"Matched tag is %s\", tag.String())\n\tbase, _ := tag.Base()\n\tlogging.Infof(\"Returning locale %s\", base.String())\n\treturn base.String()\n}\n"
  },
  {
    "path": "backend/mining.go",
    "content": "package backend\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/miners\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc (m *Backend) GetArgs() miners.BinaryArguments {\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Mining\",\n\t\tAction:   \"Switch Pool\",\n\t\tName:     fmt.Sprintf(\"%v\", m.pool.GetName()),\n\t})\n\n\treturn miners.BinaryArguments{\n\t\tStratumUrl:       m.pool.GetStratumUrl(),\n\t\tStratumUsername:  m.pool.GetUsername(),\n\t\tStratumPassword:  m.pool.GetPassword(),\n\t\tEnableIntegrated: m.getSetting(\"enableIntegrated\"),\n\t}\n}\n\nfunc (m *Backend) GetPoolFee() string {\n\treturn fmt.Sprintf(\"%0.2f%%\", m.pool.GetFee())\n}\n\nfunc (m *Backend) GetPoolName() string {\n\treturn m.pool.GetName()\n}\n\nfunc (m *Backend) PayoutInformation() {\n\tm.pool.OpenBrowserPayoutInfo(m.Address())\n}\n\nfunc (m *Backend) StartMining() bool {\n\tlogging.Infof(\"Starting mining process...\")\n\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Mining\",\n\t\tAction:   \"Start\",\n\t})\n\n\targs := m.GetArgs()\n\n\tstartProcessMonitoring := make(chan bool)\n\n\tgo func() {\n\t\t<-startProcessMonitoring\n\t\tcontinueLoop := true\n\t\tfor continueLoop {\n\t\t\tnewMinerBinaries := make([]*miners.BinaryRunner, 0)\n\t\t\tfor _, br := range m.minerBinaries {\n\t\t\t\tif br.CheckRunning() == miners.RunningStateRapidFail {\n\t\t\t\t\tm.rapidFailures = append(m.rapidFailures, br)\n\t\t\t\t\tm.runtime.Events.Emit(\"minerRapidFail\", br.MinerBinary.MainExecutableName)\n\n\t\t\t\t} else {\n\t\t\t\t\tnewMinerBinaries = append(newMinerBinaries, br)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm.minerBinaries = newMinerBinaries\n\n\t\t\tselect {\n\t\t\tcase <-m.stopMonitoring:\n\t\t\t\tcontinueLoop = false\n\t\t\tcase <-time.After(time.Second):\n\t\t\t}\n\t\t}\n\t\tlogging.Infof(\"Stopped monitoring thread\")\n\t}()\n\n\tgo func() {\n\t\tcycles := 0\n\t\tnhr := util.GetNetHash()\n\t\tth := util.GetTipHeight()\n\t\tvar avgEarning float64\n\t\tcontinueLoop := true\n\t\tfor continueLoop {\n\t\t\tcycles++\n\t\t\tif cycles > 600 {\n\t\t\t\t// Don't refresh this every time since we refresh it every second\n\t\t\t\t// and this pulls from Insight. Every 600s is fine (~every 4 blocks)\n\t\t\t\tnhr = util.GetNetHash()\n\t\t\t\tth = util.GetTipHeight()\n\t\t\t\tcycles = 0\n\t\t\t}\n\t\t\thr := uint64(0)\n\t\t\tfor _, br := range m.minerBinaries {\n\t\t\t\thr += br.HashRate()\n\t\t\t}\n\t\t\thashrate := float64(hr) / float64(1000)\n\t\t\thashrateUnit := \"kH/s\"\n\t\t\tif hashrate > 1000 {\n\t\t\t\thashrate /= 1000\n\t\t\t\thashrateUnit = \"MH/s\"\n\t\t\t}\n\t\t\tif hashrate > 1000 {\n\t\t\t\thashrate /= 1000\n\t\t\t\thashrateUnit = \"GH/s\"\n\t\t\t}\n\t\t\tif hashrate > 1000 {\n\t\t\t\thashrate /= 1000\n\t\t\t\thashrateUnit = \"TH/s\"\n\t\t\t}\n\t\t\tm.runtime.Events.Emit(\"hashRate\", fmt.Sprintf(\"%0.2f %s\", hashrate, hashrateUnit))\n\n\t\t\tnetHash := float64(nhr) / float64(1000000000)\n\n\t\t\tm.runtime.Events.Emit(\"networkHashRate\", fmt.Sprintf(\"%0.2f %s\", netHash, hashrateUnit))\n\n\t\t\t// Avoids wrong estimates when the backend is unavailable\n\t\t\tif th != 0 && nhr != 0 {\n\t\t\t\tcoinsPerDay := util.GetCoinsPerDay(th)\n\t\t\t\tavgEarning = float64(hr) / float64(nhr) * float64(coinsPerDay)\n\t\t\t}\n\n\t\t\tm.runtime.Events.Emit(\"avgEarnings\", fmt.Sprintf(\"%0.2f VTC\", avgEarning))\n\n\t\t\tselect {\n\t\t\tcase <-m.stopHash:\n\t\t\t\tcontinueLoop = false\n\t\t\tcase <-m.refreshHashChan:\n\t\t\tcase <-time.After(time.Second):\n\t\t\t}\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tcontinueLoop := true\n\t\tvar pb uint64\n\t\tfor continueLoop {\n\t\t\tm.wal.Update()\n\t\t\tb, bi := m.wal.GetBalance()\n\t\t\tm.runtime.Events.Emit(\"balance\", fmt.Sprintf(\"%0.8f\", float64(b)/float64(100000000)))\n\t\t\tm.runtime.Events.Emit(\"balanceImmature\", fmt.Sprintf(\"%0.8f\", float64(bi)/float64(100000000)))\n\t\t\tlogging.Infof(\"Updating pending pool payout...\")\n\t\t\tnewPb := m.pool.GetPendingPayout()\n\t\t\tpb = newPb\n\t\t\tm.runtime.Events.Emit(\"balancePendingPool\", fmt.Sprintf(\"%0.8f\", float64(pb)/float64(100000000)))\n\t\t\tselect {\n\t\t\tcase <-m.stopBalance:\n\t\t\t\tcontinueLoop = false\n\t\t\tcase <-m.refreshBalanceChan:\n\t\t\tcase <-time.After(time.Minute * 5):\n\t\t\t}\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tcontinueLoop := true\n\t\tfor continueLoop {\n\n\t\t\trunningProcesses := 0\n\t\t\tfor _, br := range m.minerBinaries {\n\t\t\t\tif br.IsRunning() {\n\t\t\t\t\trunningProcesses++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm.runtime.Events.Emit(\"runningMiners\", runningProcesses)\n\n\t\t\ttimeout := time.Second * 1\n\t\t\tif runningProcesses > 0 {\n\t\t\t\ttimeout = time.Second * 10\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase <-m.stopRunningState:\n\t\t\t\tcontinueLoop = false\n\t\t\tcase <-m.refreshRunningState:\n\t\t\tcase <-time.After(timeout):\n\t\t\t}\n\t\t}\n\t}()\n\n\tfor _, br := range m.minerBinaries {\n\t\terr := br.Start(args)\n\t\tif err != nil {\n\t\t\tm.StopMining()\n\t\t\tlogging.Errorf(\"Failure to start %s: %s\\n\", br.MinerBinary.MainExecutableName, err.Error())\n\t\t\treturn false\n\t\t}\n\t}\n\n\tstartProcessMonitoring <- true\n\n\treturn true\n}\n\nfunc (m *Backend) RefreshBalance() {\n\n\tm.refreshBalanceChan <- true\n}\n\nfunc (m *Backend) RefreshHashrate() {\n\n\tm.refreshHashChan <- true\n}\n\nfunc (m *Backend) RefreshRunningState() {\n\n\tm.refreshRunningState <- true\n}\n\nfunc (m *Backend) StopMining() bool {\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Mining\",\n\t\tAction:   \"Stop\",\n\t})\n\tselect {\n\tcase m.stopMonitoring <- true:\n\tdefault:\n\t}\n\tlogging.Infof(\"Stopping mining process...\")\n\tfor _, br := range m.minerBinaries {\n\t\terr := br.Stop()\n\t\tif err != nil {\n\t\t\tlogging.Errorf(\"Error stopping miner: %s %v\", br.MinerBinary.MainExecutableName, err)\n\t\t}\n\t}\n\tselect {\n\tcase m.stopBalance <- true:\n\tdefault:\n\t}\n\tselect {\n\tcase m.stopHash <- true:\n\tdefault:\n\t}\n\tselect {\n\tcase m.stopRunningState <- true:\n\tdefault:\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "backend/p2pool.go",
    "content": "package backend\n\nimport (\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/ping\"\n)\n\nfunc (m *Backend) SelectP2PoolNode() {\n\tlogging.Infof(\"Finding best P2Pool node...\")\n\tping.GetSelectedNode(m.getSetting(\"testnet\"))\n\tlogging.Infof(\"Found best P2Pool node: %v\", ping.Selected.P2PoolURL)\n\tm.p2poolNodeSelected = true\n}\n"
  },
  {
    "path": "backend/settings.go",
    "content": "package backend\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strconv\"\n\n\t\"github.com/tidwall/buntdb\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/pools\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc (m *Backend) getSetting(name string) bool {\n\tsetting := \"0\"\n\terr := m.settings.View(func(tx *buntdb.Tx) error {\n\t\tv, err := tx.Get(name)\n\t\tsetting = v\n\t\treturn err\n\t})\n\tif err != nil {\n\t\tlogging.Errorf(\"Error in getSetting(%s): %v\", name, err)\n\t}\n\treturn setting == \"1\"\n}\n\nfunc (m *Backend) setSetting(name string, value bool) {\n\tsetting := \"0\"\n\tif value {\n\t\tsetting = \"1\"\n\t}\n\terr := m.settings.Update(func(tx *buntdb.Tx) error {\n\t\t_, _, err := tx.Set(name, setting, nil)\n\t\treturn err\n\t})\n\tif err != nil {\n\t\tlogging.Errorf(\"Error in setSetting(%s): %v\", name, err)\n\t}\n}\n\nfunc (m *Backend) setIntSetting(name string, value int) {\n\tsetting := fmt.Sprintf(\"%d\", value)\n\terr := m.settings.Update(func(tx *buntdb.Tx) error {\n\t\t_, _, err := tx.Set(name, setting, nil)\n\t\treturn err\n\t})\n\tif err != nil {\n\t\tlogging.Errorf(\"Error in setSetting(%s): %v\", name, err)\n\t}\n}\n\nfunc (m *Backend) getIntSetting(name string) int {\n\tsetting := \"0\"\n\terr := m.settings.View(func(tx *buntdb.Tx) error {\n\t\tv, err := tx.Get(name)\n\t\tsetting = v\n\t\treturn err\n\t})\n\tif err != nil {\n\t\tlogging.Errorf(\"Error in getSetting(%s): %v\", name, err)\n\t}\n\ti, _ := strconv.Atoi(setting)\n\treturn i\n}\n\nfunc (m *Backend) GetPool() int {\n\tpool := m.getIntSetting(\"pool\")\n\tif pool == 0 {\n\t\tif m.GetTestnet() {\n\t\t\treturn 2 // Default P2Pool on testnet\n\t\t}\n\t\t// Default to a random pool\n\t\tpools := pools.GetPools(m.Address(), m.GetTestnet())\n\t\tpool := pools[rand.Intn(len(pools))].GetID()\n\t\t// Save this setting immediately so that we don't get\n\t\t// a different random pool in future calls to GetPool().\n\t\tm.setIntSetting(\"pool\", pool)\n\t\treturn pool\n\t}\n\treturn pool\n}\n\nfunc (m *Backend) SetPool(pool int) {\n\tif m.GetPool() != pool {\n\t\tm.setIntSetting(\"pool\", pool)\n\t\tm.ResetPool()\n\t\tlogging.Infof(\"Calling WalletInitialized\\n\")\n\t\tm.WalletInitialized()\n\t\tlogging.Infof(\"Done!\")\n\t}\n}\n\nfunc (m *Backend) SetEnableIntegrated(enabled bool) {\n\tm.setSetting(\"enableIntegrated\", enabled)\n}\n\nfunc (m *Backend) GetEnableIntegrated() bool {\n\treturn m.getSetting(\"enableIntegrated\")\n}\n\ntype PoolChoice struct {\n\tID   int    `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\nfunc (m *Backend) GetPools() []PoolChoice {\n\tpc := make([]PoolChoice, 0)\n\tfor _, p := range pools.GetPools(m.Address(), m.GetTestnet()) {\n\t\tpc = append(pc, PoolChoice{\n\t\t\tID:   p.GetID(),\n\t\t\tName: fmt.Sprintf(\"%s (%0.2f%% fee)\", p.GetName(), p.GetFee()),\n\t\t})\n\t}\n\treturn pc\n}\n\nfunc (m *Backend) GetTestnet() bool {\n        return false // Testnet is not necessary - return false\n        //return m.getSetting(\"testnet\")\n}\n\nfunc (m *Backend) SetTestnet(newTestnet bool) {\n\tif m.GetTestnet() != newTestnet {\n\t\tlogging.Infof(\"Setting testnet to [%b]\\n\", newTestnet)\n\t\tm.setSetting(\"testnet\", newTestnet)\n\n\t\tlogging.Infof(\"Setting network to testnet=%b\\n\", newTestnet)\n\t\tnetworks.SetNetwork(newTestnet)\n\n\t\tlogging.Infof(\"Calling WalletInitialized\\n\")\n\t\tm.WalletInitialized()\n\t\tlogging.Infof(\"Done!\")\n\t}\n}\n\nfunc (m *Backend) GetSkipVerthashExtendedVerify() bool {\n\treturn false // Verification is default - return false\n\t//return m.getSetting(\"skipverthashverify\")\n}\n\nfunc (m *Backend) SetSkipVerthashExtendedVerify(newVerthashVerify bool) {\n\tlogging.Infof(\"Setting skip verthash verify to [%b]\\n\", newVerthashVerify)\n\tm.setSetting(\"skipverthashverify\", newVerthashVerify)\n}\n\nfunc (m *Backend) GetClosedSource() bool {\n\treturn false // No closed source Verthash miners - return false\n\t//return m.getSetting(\"closedsource\")\n}\n\nfunc (m *Backend) SetClosedSource(newClosedSource bool) {\n\tlogging.Infof(\"Setting closed source to [%b]\\n\", newClosedSource)\n\tm.setSetting(\"closedsource\", newClosedSource)\n}\n\nfunc (m *Backend) GetDebugging() bool {\n\treturn m.getSetting(\"debugging\")\n}\n\nfunc (m *Backend) SetDebugging(newDebugging bool) {\n\tlogging.Infof(\"Setting debugging to [%b]\\n\", newDebugging)\n\tm.setSetting(\"debugging\", newDebugging)\n}\n\nfunc (m *Backend) GetAutoStart() bool {\n\treturn util.GetAutoStart()\n}\n\nfunc (m *Backend) SetAutoStart(newAutoStart bool) {\n\tutil.SetAutoStart(newAutoStart)\n}\n\nfunc (m *Backend) GetVersion() string {\n\treturn tracking.GetVersion()\n}\n\nfunc (m *Backend) PrerequisiteProxyLoop() {\n\tfor pi := range m.prerequisiteInstall {\n\t\tsend := \"0\"\n\t\tif pi {\n\t\t\tsend = \"1\"\n\t\t}\n\t\tm.runtime.Events.Emit(\"prerequisiteInstall\", send)\n\t}\n}\n"
  },
  {
    "path": "backend/tracking.go",
    "content": "package backend\n\nimport (\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc (m *Backend) EnableTracking() {\n\ttracking.Enable()\n}\n\nfunc (m *Backend) DisableTracking() {\n\ttracking.Disable()\n}\n\nfunc (m *Backend) TrackingEnabled() string {\n\tif tracking.IsEnabled() {\n\t\treturn \"1\"\n\t}\n\treturn \"0\"\n}\n\nfunc (m *Backend) ReportIssue() {\n\tutil.OpenBrowser(\"https://github.com/vertcoin-project/one-click-miner-vnext/issues/new?assignees=&labels=bug&projects=&template=1-bug.yml\")\n}\n"
  },
  {
    "path": "backend/update.go",
    "content": "package backend\n\nimport (\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc (m *Backend) UpdateAvailable() bool {\n\tr, _ := util.GetLatestRelease()\n\n\tlastVersion := util.VersionStringToNumeric(r.Tag)\n\tmyVersion := util.VersionStringToNumeric(tracking.GetVersion())\n\n\treturn lastVersion > myVersion\n}\n\nfunc (m *Backend) VersionDetails() []string {\n\tr, _ := util.GetLatestRelease()\n\treturn []string{r.Tag, r.Body, r.URL}\n}\n\nfunc (m *Backend) UpdateLoop() {\n\tfor {\n\t\tstopUpdate := false\n\t\tselect {\n\t\tcase stopUpdate = <-m.stopUpdate:\n\t\tcase <-time.After(time.Second * 15):\n\t\t}\n\n\t\tif stopUpdate {\n\t\t\tbreak\n\t\t}\n\n\t\tm.runtime.Events.Emit(\"updateAvailable\", m.UpdateAvailable())\n\t}\n}\n"
  },
  {
    "path": "backend/wallet.go",
    "content": "package backend\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/keyfile\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/wallet\"\n)\n\nfunc (m *Backend) WalletInitialized() int {\n\tlogging.Infof(\"Checking wallet..\")\n\tcheckWallet := 0\n\tif keyfile.KeyFileValid() {\n\t\tcheckWallet = 1\n\t}\n\tscript, err := keyfile.GetScript()\n\tif err != nil {\n\t\tlogging.Errorf(\"Error initializing wallet: %s\", err.Error())\n\t}\n\twal, err := wallet.NewWallet(keyfile.GetAddress(), script)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error initializing wallet: %s\", err.Error())\n\t}\n\tm.wal = wal\n\tlogging.Infof(\"Wallet initialized: %d\", checkWallet)\n\treturn checkWallet\n}\n\nfunc (m *Backend) SendSweep(password string) []string {\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Sweep\",\n\t\tAction:   \"Send\",\n\t})\n\n\ttxids := make([]string, 0)\n\n\tif len(m.pendingSweep) == 0 {\n\t\t// Somehow user managed to press send without properly\n\t\t// preparing the sweep first\n\t\treturn []string{\"send_failed\"}\n\t}\n\n\tfor _, s := range m.pendingSweep {\n\t\terr := m.wal.SignMyInputs(s, password)\n\t\tif err != nil {\n\t\t\tlogging.Errorf(\"Error signing transaction: %s\", err.Error())\n\t\t\treturn []string{\"sign_failed\"}\n\t\t}\n\n\t\ttxHash, err := m.wal.Send(s)\n\t\tif err != nil {\n\t\t\tlogging.Errorf(\"Error sending transaction: %s\", err.Error())\n\t\t\treturn []string{\"send_failed\"}\n\t\t}\n\t\ttxids = append(txids, txHash)\n\t}\n\n\tm.pendingSweep = nil\n\n\tlogging.Debugf(\"Transaction(s) sent! TXIDs: %v\\n\", txids)\n\tm.refreshBalanceChan <- true\n\treturn txids\n\n}\n\nfunc (m *Backend) ShowTx(txid string) {\n\tutil.OpenBrowser(fmt.Sprintf(\"%stx/%s\", networks.Active.InsightURL, txid))\n}\n\ntype PrepareResult struct {\n\tFormattedAmount      string\n\tNumberOfTransactions int\n}\n\nfunc (m *Backend) PrepareSweep(addr string) string {\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Sweep\",\n\t\tAction:   \"Prepare\",\n\t})\n\n\tlogging.Debugf(\"Preparing sweep\")\n\n\ttxs, err := m.wal.PrepareSweep(addr)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error preparing sweep: %v\", err)\n\t\treturn err.Error()\n\t}\n\n\tm.pendingSweep = txs\n\tval := float64(0)\n\tfor _, tx := range txs {\n\t\tval += (float64(tx.TxOut[0].Value) / float64(100000000))\n\t}\n\n\tresult := PrepareResult{fmt.Sprintf(\"%0.8f VTC\", val), len(txs)}\n\tlogging.Debugf(\"Prepared sweep: %v\", result)\n\n\tm.runtime.Events.Emit(\"createTransactionResult\", result)\n\treturn \"\"\n}\n\nfunc (m *Backend) Address() string {\n\treturn keyfile.GetAddress()\n}\n\nfunc (m *Backend) InitWallet(password string) bool {\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Wallet\",\n\t\tAction:   \"Initialize\",\n\t})\n\n\terr := keyfile.CreateKeyFile(password)\n\tif err == nil {\n\t\tm.WalletInitialized()\n\t\tm.ResetPool()\n\t\treturn true\n\t}\n\tlogging.Errorf(\"Error: %s\", err.Error())\n\treturn false\n}\n"
  },
  {
    "path": "build.bat",
    "content": "@ECHO OFF\nIF NOT \"%~1\"==\"\" GOTO :BUILD\n\n:USAGE\nECHO Usage: %~nx0 version\nGOTO :EOF\n\n:BUILD\nSET ver=%1\ngit describe --always --long --dirty > %TEMP%\\git-version\nSET /p gitver=<%TEMP%\\git-version\nDEL %TEMP%\\git-version >nul 2>&1\nCD tracking\nREN version.go version.go.build\nECHO package tracking >> version.go\nECHO var version=\"%ver%-%gitver%\" >> version.go\nCD ..\nDEL build\\vertcoin-ocm.exe >nul 2>&1\nwails build\nECHO \"Sign the release assembly now on the windows machine if desired, then:\"\nPAUSE\nCD build \n7z -sdel -aou a vertcoin-ocm-%ver%-windows-x64.zip vertcoin-ocm.exe\nCD ..\nwails build -d\nECHO \"Sign the debug assembly now on the windows machine if desired, then:\"\nPAUSE\nCD build\n7z -sdel -aou a vertcoin-ocm-%ver%-windows-x64-debug.zip vertcoin-ocm.exe\nCD ..\nDEL *.syso *.manifest *.ico *.rc *.exe >nul 2>&1\nCD tracking\nDEL version.go >nul 2>&1\nREN version.go.build version.go\nCD ..\ngo clean"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\nGITVER=$(git describe --always --long --dirty)\nmv tracking/version.go tracking/version.go.dev\necho \"package tracking\" > tracking/version.go\necho \"var version=\\\"$1-$GITVER\\\"\" >> tracking/version.go\nwails build\ncd build\nzip ../vertcoin-ocm-$1-linux-x64.zip ./vertcoin-ocm\ncd ..\nwails build -d \ncd build\nzip ../vertcoin-ocm-$1-linux-x64-debug.zip ./vertcoin-ocm\ncd ..\nrm tracking/version.go\nmv tracking/version.go.dev tracking/version.go"
  },
  {
    "path": "frontend/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw*\n"
  },
  {
    "path": "frontend/README.md",
    "content": "# vue basic\n\n## Project setup\n\n```\nnpm install\n```\n\n### Compiles and hot-reloads for development\n\n```\nnpm run serve\n```\n\n### Compiles and minifies for production\n\n```\nnpm run build\n```\n\n### Run your tests\n\n```\nnpm run test\n```\n\n### Lints and fixes files\n\n```\nnpm run lint\n```\n\n### Customize configuration\n\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "frontend/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/app'\n  ]\n}\n"
  },
  {
    "path": "frontend/package.json",
    "content": "{\n  \"name\": \"vertcoin_one_click_miner\",\n  \"author\": \"Gert-Jaap Glasbergen<gertjaap@gertjaap.nl>\",\n  \"private\": true,\n  \"scripts\": {\n    \"preinstall\": \"npx npm-force-resolutions\",\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"@wailsapp/runtime\": \"^1.0.10\",\n    \"core-js\": \"^2.6.11\",\n    \"lodash\": \"^4.17.21\",\n    \"lodash.clonedeep\": \"^4.5.0\",\n    \"lodash.defaultsdeep\": \"^4.6.1\",\n    \"vue\": \"^2.6.11\",\n    \"vue-i18n\": \"^8.15.3\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"^4.5.15\",\n    \"@vue/cli-plugin-eslint\": \"^3.12.1\",\n    \"@vue/cli-service\": \"^4.5.15\",\n    \"babel-eslint\": \"^10.0.3\",\n    \"eslint\": \"^5.8.0\",\n    \"eslint-plugin-vue\": \"^5.2.3\",\n    \"eventsource-polyfill\": \"^0.9.6\",\n    \"highlight.js\": \"^10.4.1\",\n    \"vue-template-compiler\": \"^2.6.11\",\n    \"webpack-hot-middleware\": \"^2.24.3\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"env\": {\n      \"node\": true\n    },\n    \"extends\": [\n      \"plugin:vue/essential\",\n      \"eslint:recommended\"\n    ],\n    \"rules\": {},\n    \"parserOptions\": {\n      \"parser\": \"babel-eslint\"\n    }\n  },\n  \"postcss\": {\n    \"plugins\": {\n      \"autoprefixer\": {}\n    }\n  },\n  \"resolutions\": {\n    \"minimist\": \"1.2.3\",\n    \"mkdir\": \"0.5.3\"\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\",\n    \"not ie <= 8\"\n  ]\n}\n"
  },
  {
    "path": "frontend/package.json.md5",
    "content": "584b5614d6fc7dde9620d97ca74df594"
  },
  {
    "path": "frontend/src/App.vue",
    "content": "<template>\n  <div id=\"app\" unselectable=\"on\" onselectstart=\"return false;\">\n    <TabBar\n      v-on:send=\"switchToSend\"\n      v-on:wallet=\"switchToWallet\"\n      v-on:settings=\"switchToSettings\"\n      v-if=\"((screen === 'welcome' && manualStop) || screen !== 'welcome') && (screen !== 'checks' || tabBarVisible)\"\n    />\n    <Welcome v-if=\"screen === 'welcome'\" v-on:start-mining=\"switchToChecks\" />\n    <Checks v-if=\"screen === 'checks'\" v-on:mining=\"switchToMining\" v-on:checksFailed=\"showTabBar\" />\n    <Send v-if=\"screen === 'send'\" v-on:back=\"switchToMining\" v-on:cancel=\"switchToMining\" />\n    <Mining v-show=\"screen === 'mining'\" v-on:stop-mining=\"stopMining\" />\n    <Settings v-if=\"screen === 'settings'\" v-on:committed=\"restartMining\" />\n    <Update v-if=\"screen === 'update'\" v-on:back=\"restartMiningIfNotStopped\" />\n    <Tracking v-on:update=\"switchToUpdate\" />\n  </div>\n</template>\n\n<script>\nimport Welcome from \"./components/Welcome.vue\";\nimport Mining from \"./components/Mining.vue\";\nimport Checks from \"./components/Checks.vue\";\nimport Send from \"./components/Send.vue\";\nimport Settings from \"./components/Settings.vue\";\nimport TabBar from \"./components/TabBar.vue\";\nimport Tracking from \"./components/Tracking.vue\";\nimport Update from \"./components/Update.vue\";\n\nimport \"./assets/css/main.css\";\n\nexport default {\n  data() {\n    return {\n      screen: \"welcome\",\n      manualStop: false,\n      tabBarVisible: false\n    };\n  },\n  mounted() {\n    var self = this;\n    window.wails.Events.On(\"minerRapidFail\", () => {\n      window.backend.Backend.StopMining().then(() => {\n        self.switchToChecks();\n      });\n    });\n  },\n  methods: {\n    stopMining: function() {\n      this.manualStop = true;\n      this.switchToWelcome();\n    },\n    // Target for the wallet tab (meta between welcome (if stopped) and mining (if mining))\n    switchToWallet: function() {\n      var self = this;\n      if (this.tabBarVisible === true) {\n        this.tabBarVisible = false;\n        window.backend.Backend.StopMining().then(() => {\n          self.switchToChecks();\n        });\n      } else {\n        if (this.manualStop) {\n          this.switchToWelcome();\n        } else {\n          this.switchToMining();\n        }\n      }\n    },\n    showTabBar: function() {\n      this.tabBarVisible = true;\n    },\n    switchToChecks: function() {\n      this.screen = \"checks\";\n    },\n    switchToSettings: function() {\n      this.screen = \"settings\";\n    },\n    switchToSend: function() {\n      this.screen = \"send\";\n    },\n    switchToMining: function() {\n      this.manualStop = false;\n      this.screen = \"mining\";\n    },\n    switchToUpdate: function() {\n      this.screen = \"update\";\n    },\n    switchToWelcome: function() {\n      this.screen = \"welcome\";\n    },\n    restartMiningIfNotStopped: function() {\n      if(this.manualStop) {\n        this.switchToWelcome();\n      } else {\n        this.restartMining();\n      }\n    },\n    restartMining: function() {\n      var self = this;\n      window.backend.Backend.StopMining().then(() => {\n        self.switchToChecks();\n      });\n    }\n  },\n  name: \"app\",\n  components: {\n    Welcome,\n    Mining,\n    Checks,\n    Send,\n    TabBar,\n    Tracking,\n    Settings,\n    Update\n  }\n};\n</script>\n"
  },
  {
    "path": "frontend/src/assets/css/main.css",
    "content": "#app {\n  font-family: 'Montserrat', Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #eee;\n  -moz-user-select: none; \n  -webkit-user-select: none; \n  -ms-user-select:none; \n  user-select:none;\n  -o-user-select:none;\n  margin: 0px;\n  padding: 0px;\n  font-size: 14px;\n}\n\nselect {\n  font-family: 'Montserrat', Helvetica, Arial, sans-serif;\n  border: 2px solid #eee !important;\n  background: #191b1c !important;\n  color: #eee !important;\n  -webkit-appearance: none;\n  padding: 4px 10px;\n}\n\n\n/* ubuntu-regular - latin */\n/* montserrat-regular - latin */\n@font-face {\n  font-family: 'Montserrat';\n  font-style: normal;\n  font-weight: 400;\n  src: url('../fonts/montserrat-v13-latin-regular.eot'); /* IE9 Compat Modes */\n  src: local('Montserrat Regular'), local('Montserrat-Regular'),\n       url('../fonts/montserrat-v13-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n       url('../fonts/montserrat-v13-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */\n       url('../fonts/montserrat-v13-latin-regular.woff') format('woff'), /* Modern Browsers */\n       url('../fonts/montserrat-v13-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */\n       url('../fonts/montserrat-v13-latin-regular.svg#Montserrat') format('svg'); /* Legacy iOS */\n}\n\n\nhtml {\n  height: 100%;\n  overflow: hidden;\n  background-color: #191b1c;\n  background-size: 20px 20px;\n  padding: 0px; margin: 0px;\n  \n}\n\nbody {\n  padding: 0px; margin: 0px;\n}\n\n.logo {\n  width: 16em;\n}\n\n.col-6 {\n\twidth: 50%;\n\tfloat: left;\n}\n\ndiv.col-286 {\n  margin: 0px;\n  padding-left: 200px;\n  padding-right: 200px;\n  height: 100%;\n  width: 100%;\n  display: table-cell;\n  vertical-align: middle;\n  text-align: center;\n}\n\ndiv.col-settings {\n  height: 235px;\n  width: 80%;\n  margin-left: 10%;\n  vertical-align: middle;\n  text-align: center;\n  overflow-y: auto;\n  display: flex;\n  flex-basis: 1;\n}\n\ndiv.col-settings-sub {\n  padding: 20px;\n  width: 50%;\n  flex-grow: 1;\n}\n\ndiv.col-286.height-100 {\n  height: 100px;\n  display: inline;\n}\n\n\ndiv.col-wide {\n  margin: 0px;\n  padding-left: 50px;\n  padding-right: 50px;\n  height: 100%;\n  width: 100%;\n  display: table-cell;\n  vertical-align: middle;\n  text-align: center;\n}\ndiv.settings-container {\n  height: 348px;\n  width: 100%;\n  text-align: center;\n}\ndiv.container {\n  height: 348px;\n  width: 100%;\n  display: table;\n  text-align: center;\n}\n\na.button:hover {\n  opacity: 1.0;\n  transition: 500ms;\n}\na.button {\n\t  opacity: 0.6;\n    line-height: 45px;\n    background: #048652;\n    max-width: 286px;\n    height: 45px;\n    margin: 0 auto;\n    display: block;\n    color: white;\n    z-index: 500;\n    box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.15);\n    cursor: pointer;\n    font-weight: 400 !important;\n    text-align: center;\n    border-radius: 5px;\n}\n\na.link, a.inlineLink {\n    opacity: 0.6;\n    color: #048652;\n    cursor: pointer;\n    margin: 0 auto;\n    text-align: center;\n}\n\na.link { \n  display: block;\n}\n\na.inlineLink {\n  display: inline;\n}\n\ninput[type='text'], input[type='password'] {\n  border: 0px;\n  background-color: #202225;\n  color: white;\n  border-radius: 5px;\n  line-height: 45px;\n  padding: 0px 10px;\n  height: 45px;\n  width: 400px;\n  margin: 0 auto;\n  font-family: 'Montserrat', Helvetica, Arial, sans-serif;\n  font-size: 14px;\n}\n\np.error {\n  color: #900000;\n}\ninput.error {\n  border: 1px solid #900000;\n}\ninput.success {\n  border: 1px solid #048652;\n}\n\ninput:-moz-focusring {\n  color:transparent;\n  text-shadow:0 0 0 #000; /* your normal text color here */\n}\ninput:-moz-focusring * {\n  color:#000; /* your normal text color here */\n  text-shadow:none;\n}\n"
  },
  {
    "path": "frontend/src/components/Checks.vue",
    "content": "<template>\n  <div class=\"container\">\n    <div v-if=\"prerequisiteInstall\" class=\"col-286\">\n      <p>{{ $t(\"checks.prerequisite\") }}</p>\n    </div>\n    <div v-if=\"!prerequisiteInstall && checkStatus !== 'Failed'\" class=\"col-286\">\n      <p>{{checkStatus === null ? $t(\"checks.checking_mining_software\") : (checkStatus === 'Failed' ? 'Failed' : $t(\"checks.\" + checkStatus)) }}</p>\n      <div class=\"verthashProgress\" v-if=\"verthashProgress !== 0\">\n        <div class=\"progressBar\">\n          <div class=\"progress\" v-bind:style=\"{width: verthashProgress + '%'}\">&nbsp;</div>\n        </div>\n        <div class=\"progressText\">{{Math.floor(verthashProgress)}}%</div>\n      </div>\n    </div>\n    <div v-if=\"!prerequisiteInstall && checkStatus === 'Failed'\" class=\"col-wide\">\n      <div class=\"failureReason\" v-if=\"checkStatus === 'Failed'\">\n        {{ $t(\"checks.checks_failed\") }}:\n        <br />&nbsp;<br />\n        {{failureReason}}\n      </div>\n      <p v-if=\"!prerequisiteInstall && checkStatus === 'Failed'\">\n        <a class=\"button\" @click=\"check\">{{ $t('generic.retry') }}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      prerequisiteInstall: false,\n      checkStatus: null,\n      failureReason: \"\",\n      verthashProgress: 0,\n    };\n  },\n  mounted() {\n    this.check();\n    var self = this;\n    window.wails.Events.On(\"checkStatus\", result => {\n      self.checkStatus = result;\n    });\n    window.wails.Events.On(\"prerequisiteInstall\", result => {\n      self.prerequisiteInstall = result === \"1\";\n    });\n    window.wails.Events.On(\"verthashProgress\", result => {\n      self.verthashProgress = result;\n    })\n  },\n  methods: {\n    check: function() {\n      var self = this;\n\n      window.backend.Backend.PerformChecks().then(result => {\n        if (result === \"ok\") {\n          self.startMining();\n        } else {\n          self.$emit(\"checksFailed\");\n          self.failureReason = result;\n        }\n      });\n    },\n    startMining: function() {\n      var self = this;\n      window.backend.Backend.StartMining().then(() => {\n        self.$emit(\"mining\");\n      });\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\ndiv.failureReason {\n  height: 200px;\n  overflow-y: auto;\n  font-family: \"Courier New\", Courier, monospace;\n  color: red;\n  border: 1px solid red;\n  width: 600px;\n  margin: 0 auto;\n}\n\ndiv.verthashProgress {\n  margin: 0 auto;\n  width: 200px;\n}\n\ndiv.progressBar {\n  border: 1px solid #048652;\n  height: 10px;\n  width: 100%;\n  margin: 0px;\n  padding: 0px;\n  margin-bottom: 10px;\n}\n\ndiv.progress {\n  float:left;\n  background-color: #048652;\n  margin: 0px;\n  padding: 0px;\n  height: 10px; \n}\n</style>\n\n"
  },
  {
    "path": "frontend/src/components/Mining.vue",
    "content": "<template>\n  <div class=\"container\">\n    <div class=\"col-286\">\n      <p class=\"header\">{{$t('mining.spendable_balance')}}:</p>\n      <p class=\"spendableBalance\">\n        <a class=\"tiny\" @click=\"refreshBalance\">\n          <svg\n            width=\"16\"\n            height=\"16\"\n            version=\"1.1\"\n            id=\"Capa_1\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n            x=\"0px\"\n            y=\"0px\"\n            viewBox=\"0 0 458.186 458.186\"\n            style=\"enable-background:new 0 0 458.186 458.186;\"\n            xml:space=\"preserve\"\n          >\n            <g>\n              <g>\n                <path\n                  style=\"fill: #048652\"\n                  d=\"M445.651,201.95c-1.485-9.308-10.235-15.649-19.543-14.164c-9.308,1.485-15.649,10.235-14.164,19.543\n\t\t\t\t\t\t\t\t\t\tc0.016,0.102,0.033,0.203,0.051,0.304c17.38,102.311-51.47,199.339-153.781,216.719c-102.311,17.38-199.339-51.47-216.719-153.781\n\t\t\t\t\t\t\t\t\t\tS92.966,71.232,195.276,53.852c62.919-10.688,126.962,11.29,170.059,58.361l-75.605,25.19\n\t\t\t\t\t\t\t\t\t\tc-8.944,2.976-13.781,12.638-10.806,21.582c0.001,0.002,0.002,0.005,0.003,0.007c2.976,8.944,12.638,13.781,21.582,10.806\n\t\t\t\t\t\t\t\t\t\tc0.003-0.001,0.005-0.002,0.007-0.002l102.4-34.133c6.972-2.322,11.675-8.847,11.674-16.196v-102.4\n\t\t\t\t\t\t\t\t\t\tC414.59,7.641,406.949,0,397.523,0s-17.067,7.641-17.067,17.067v62.344C292.564-4.185,153.545-0.702,69.949,87.19\n\t\t\t\t\t\t\t\t\t\ts-80.114,226.911,7.779,310.508s226.911,80.114,310.508-7.779C435.905,339.799,457.179,270.152,445.651,201.95z\"\n                />\n              </g>\n            </g>\n          </svg>\n        </a>\n        &nbsp;{{balance}} VTC\n        <a class=\"tiny\" @click=\"copyAddress\" v-bind:title=\"$t('mining.copy_address')\">\n          <svg width=\"16\" height=\"16\" version=\"1.1\" id=\"Capa_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n          viewBox=\"0 0 368.008 368.008\" style=\"enable-background:new 0 0 368.008 368.008;\" xml:space=\"preserve\">\n            <g>\n              <g>\n                <path style=\"fill: #048652\" d=\"M368,88.004c0-1.032-0.224-2.04-0.6-2.976c-0.152-0.376-0.416-0.664-0.624-1.016c-0.272-0.456-0.472-0.952-0.832-1.352\n                  l-72.008-80c-1.512-1.688-3.672-2.656-5.944-2.656h-15.648c-0.232,0-0.472,0-0.704,0H151.992c-13.232,0-24,10.768-24,24v40H24\n                  c-13.232,0-24,10.768-24,24v256c0,13.232,10.768,24,24,24h192c13.232,0,24-10.768,24-24v-40h104c13.232,0,24-10.768,24-24v-175.96\n                  c0-0.016,0.008-0.024,0.008-0.04L368,88.004z M224,344.004c0,4.408-3.592,8-8,8H24c-4.408,0-8-3.592-8-8v-256c0-4.408,3.592-8,8-8\n                  h104v88c0,4.416,3.584,8,8,8h88V344.004z M224,160.004h-80v-80h4.688L224,155.324V160.004z M352,280.004c0,4.416-3.592,8-8,8H240\n                  v-119.64c0-0.12,0.008-0.24,0.008-0.36l-0.008-16c0,0,0-0.008,0-0.024c-0.008-2.12-0.832-4.04-2.184-5.464\n                  c0-0.016-0.024-0.016-0.016-0.016c0,0-0.008-0.008-0.008-0.016c-0.008,0-0.016-0.008-0.016-0.016\n                  c-0.032-0.032-0.072-0.072-0.112-0.112l-80-80c-1.504-1.504-3.544-2.352-5.664-2.352h-8.008v-40c0-4.408,3.592-8,8-8h112v88\n                  c0,4.416,3.584,8,8,8H352V280.004z M352,96.004h-72.008v-80h4.44L352,91.076V96.004z\"/>\n              </g>\n            </g>\n          </svg>\n        </a>\n      </p>\n      <p class=\"immatureBalance\" v-if=\"balanceImmature != '0.00000000'\">\n        (\n        <span style=\"opacity: 1\">{{balanceImmature}} VTC</span>\n        {{$t('mining.still_maturing')}})\n      </p>\n      <p class=\"poolBalance\" v-if=\"balancePendingPool != '0.00000000'\">\n        (\n        <span style=\"opacity: 1\">{{balancePendingPool}} VTC</span>\n        {{$t('mining.pending_pool_payout')}})\n      </p>\n<!--      <p class=\"poolBalance\" v-if=\"balancePendingPool == '0.00000000'\">-->\n<!--        {{$t('mining.pending_payout_info_unavailable')}}-->\n<!--      </p>-->\n      <p class=\"pool\">\n        <span style=\"opacity: 1\">{{$t('mining.active_pool')}}: {{activePool}} <span v-if=\"poolFee != '0.0%'\">({{$t('mining.pool_fee')}}: {{poolFee}})</span></span>\n        <br><a class=\"link\" @click=\"payoutInformation\">{{ $t('mining.payout_information') }}</a>\n      </p>\n      \n      <p class=\"spacer\">&nbsp;</p>\n      <p v-if=\"runningMiners === 0\">{{$t('mining.waiting_for_miners')}}</p>\n      <p v-if=\"runningMiners > 0\" class=\"header\">{{$t('mining.expected_earnings_24h')}}:</p>\n      <p\n        v-if=\"runningMiners > 0 && hashrate !== '0.00 MH/s'\"\n        class=\"earning\"\n      >~{{avgearn}} ({{hashrate}})</p>\n      <p\n        v-if=\"runningMiners > 0 && hashrate === '0.00 MH/s'\"\n        class=\"earning\"\n      >{{$t('mining.estimating')}}{{spinner}}</p>\n      <p>\n        <a class=\"button\" v-if=\"stopping\">{{spinner}}</a>\n        <a class=\"button\" @click=\"stop\" v-if=\"!stopping\">{{$t('mining.stop_mining')}}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      hashrate: \"0.00 MH/s\",\n      avgearn: \"0.00 VTC\",\n      netHash: \"\",\n      gpu: \"\",\n      testnet: false,\n      wallet: \"\",\n      balance: \"0.00000000\",\n      balanceImmature: \"0.00000000\",\n      balancePendingPool: \"0.00000000\",\n      runningMiners: 0,\n      spinner: \"...\",\n      stopping: false,\n      poolFee: \"0.0%\",\n      activePool: \"\",\n      address:\"\",\n    };\n  },\n  mounted() {\n    var self = this;\n    window.setInterval(() => {\n      var newSpinner = self.spinner + \".\";\n      if (newSpinner.length > 5) {\n        newSpinner = \".\";\n      }\n      self.spinner = newSpinner;\n    }, 1000);\n    window.backend.Backend.GetTestnet().then(result => {\n      self.testnet = result;\n    });\n    window.setInterval(() => {\n      window.backend.Backend.GetPoolName().then(result => {\n        self.activePool = result;\n      });\n      window.backend.Backend.GetPoolFee().then(result => {\n        self.poolFee = result;\n      });\n      window.backend.Backend.Address().then(result => {\n        self.address = result;\n      });\n    }, 5000);\n    window.backend.Backend.GetPoolName().then(result => {\n      self.activePool = result;\n    });\n    window.backend.Backend.GetPoolFee().then(result => {\n      self.poolFee = result;\n    });\n    window.wails.Events.On(\"hashRate\", result => {\n      self.hashrate = result;\n    });\n    window.wails.Events.On(\"runningMiners\", result => {\n      self.runningMiners = result;\n    });\n    window.wails.Events.On(\"networkHashRate\", result => {\n      self.netHash = result;\n    });\n    window.wails.Events.On(\"avgEarnings\", result => {\n      self.avgearn = result;\n    });\n    window.wails.Events.On(\"balance\", result => {\n      self.balance = result;\n    });\n    window.wails.Events.On(\"balanceImmature\", result => {\n      self.balanceImmature = result;\n    });\n    window.wails.Events.On(\"balancePendingPool\", result => {\n      self.balancePendingPool = result;\n    });\n    window.backend.Backend.RefreshBalance();\n    window.backend.Backend.RefreshHashrate();\n    window.backend.Backend.RefreshRunningState();\n  },\n  methods: {\n    stop: function() {\n      var self = this;\n      this.stopping = true;\n      window.backend.Backend.StopMining().then(() => {\n        self.stopping = false;\n        self.$emit(\"stop-mining\");\n      });\n    },\n    refreshBalance: function() {\n      window.backend.Backend.RefreshBalance();\n    },\n    copyAddress: function() {\n      var textArea = document.createElement(\"textarea\");\n      textArea.value = this.address;\n      // textArea.style.display = \"none\";\n      // Avoid scrolling to bottom\n      textArea.style.top = \"0\";\n      textArea.style.left = \"0\";\n      textArea.style.position = \"fixed\";\n    \n      document.body.appendChild(textArea);\n      textArea.focus();\n      textArea.select();\n    \n      try {\n        document.execCommand('copy');\n      } catch(e) {\n        // ignore\n      }\n    \n      document.body.removeChild(textArea);\n    },\n    sendMoney: function() {\n      this.$emit(\"send\");\n    },\n    payoutInformation: function() {\n      window.backend.Backend.PayoutInformation();\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\na.tiny:hover {\n  opacity: 1;\n  transition: 500ms;\n}\na.tiny {\n  opacity: 0.6;\n  background: transparent;\n  display: inline;\n  z-index: 500;\n  margin: 0px;\n  cursor: pointer;\n  border: 0px;\n}\n\np.spendableBalance,\np.earning {\n  margin: 0;\n  padding: 0;\n  font-size: 20px;\n}\np.immatureBalance,\np.poolBalance,\np.netHash {\n  margin: 0;\n  padding: 0;\n  font-size: 12px;\n  opacity: 0.6;\n}\np.spacer {\n  padding: 0px;\n  margin: 5px;\n}\np.header {\n  margin-bottom: 0;\n  padding-bottom: 5px;\n  opacity: 0.6;\n}\np.fork {\n  display: block;\n  border: 2px solid #d0a000;\n  color: #d0a000;\n  font-weight: bold;\n}\n\np.fork>a, p.fork>a:active, p.fork>a:visited {\n  color: #d0a000;\n  font-weight: bold;\n  padding: 5px;\n  cursor: pointer;\n}\n\na.link {\n  font-size: 14px;\n  opacity: 0.6;\n  text-decoration: underline;\n  cursor: pointer;\n}\n\n</style>\n"
  },
  {
    "path": "frontend/src/components/Send.vue",
    "content": "<template>\n  <div class=\"container\">\n    <div v-if=\"sendError === '' && sent === false\" class=\"col-286\">\n      <p v-if=\"receivedBalance === '0.00 VTC'\">{{ $t('sending.send_all_to') }}:</p>\n      <p\n        v-if=\"receivedBalance !== '0.00 VTC' && receivedTxCount === 1\"\n      >{{ $t('sending.youre_sending_x_to', { receivedBalance }) }}:</p>\n      <p\n        v-if=\"receivedBalance !== '0.00 VTC' && receivedTxCount > 1\"\n      >{{ $t('sending.youre_sending_x_in_y_txs_to', { receivedBalance, receivedTxCount }) }}:</p>\n      <p>\n        <input\n          :class=\"{error: (error !== ''), success: (error === '' && target !== '')}\"\n          @blur=\"recalculate()\"\n          type=\"text\"\n          v-model=\"target\"\n          v-bind:placeholder=\"$t('sending.receiver_address')\"\n        />\n      </p>\n      <p v-if=\"error != ''\" class=\"error\">{{error}}</p>\n      <p>\n        <input\n          type=\"password\"\n          v-model=\"password\"\n          v-bind:placeholder=\"$t('sending.wallet_password')\"\n          @keyup.enter=\"send\"\n        />\n      </p>\n      <p>\n        <a class=\"button\" @click=\"send\">{{ $t('sending.send') }}</a>\n      </p>\n    </div>\n    <div v-if=\"sent === true\" class=\"col-286\">\n      <svg\n        style=\"fill: #048652\"\n        width=\"57px\"\n        height=\"57px\"\n        viewBox=\"0 0 57 57\"\n        version=\"1.1\"\n        xmlns=\"http://www.w3.org/2000/svg\"\n        xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n      >\n        <!-- Generator: Sketch 55.2 (78181) - https://sketchapp.com -->\n        <title>Group</title>\n        <desc>Created with Sketch.</desc>\n        <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n          <g id=\"Sent\" transform=\"translate(-371.000000, -156.000000)\">\n            <g id=\"Group\" transform=\"translate(372.000000, 157.000000)\">\n              <g\n                id=\"noun_tick_1167345\"\n                transform=\"translate(13.152174, 17.336957)\"\n                fill=\"#1EA068\"\n                fill-rule=\"nonzero\"\n              >\n                <path\n                  d=\"M2.45108696,11.1195652 C2.0326087,10.6413043 1.25543478,10.5815217 0.777173913,11 C0.298913043,11.4184783 0.239130435,12.1956522 0.657608696,12.673913 C0.657608696,12.673913 0.717391304,12.7336957 0.717391304,12.7336957 L7.95108696,20.5652174 C8.19021739,20.8043478 8.48913043,20.923913 8.78804348,20.923913 C9.08695652,20.923913 9.38586957,20.8043478 9.625,20.5652174 L27.8586957,2.33152174 C28.3369565,1.85326087 28.3369565,1.13586957 27.8586957,0.657608696 C27.3804348,0.179347826 26.6630435,0.179347826 26.1847826,0.657608696 L8.84782609,17.9945652 L2.45108696,11.1195652 Z\"\n                  id=\"Path\"\n                />\n              </g>\n              <circle\n                id=\"Oval\"\n                stroke=\"#1EA068\"\n                stroke-width=\"1.19999993\"\n                cx=\"27.5\"\n                cy=\"27.5\"\n                r=\"27.5\"\n              />\n            </g>\n          </g>\n        </g>\n      </svg>\n      <p>{{ $t('sending.coins_sent') }}</p>\n      <p v-if=\"txids.length > 1\">\n        {{ $t('sending.view_trans_plural') }}:\n        <br />\n        <a\n          class=\"link\"\n          style=\"display: inline\"\n          v-for=\"(txid, idx) in txids\"\n          v-bind:key=\"txid\"\n          @click=\"showTx(txid)\"\n        >\n          <span v-if=\"idx > 0\">&nbsp;&nbsp;</span>\n          #{{idx+1}}\n        </a>\n      </p>\n      <p v-if=\"txids.length == 1\">\n        <a\n          class=\"link\"\n          style=\"display: inline\"\n          v-for=\"txid in txids\"\n          v-bind:key=\"txid\"\n          @click=\"showTx(txid)\"\n        >{{ $t('sending.view_trans_singular') }}</a>\n      </p>\n      <p>\n        <a class=\"link\" @click=\"back\">{{ $t('generic.back_to_wallet') }}</a>\n      </p>\n    </div>\n    <div v-if=\"sendError !== ''\" class=\"col-286\">\n      <p>{{ $t('sending.failed_to_send') }}</p>\n      <p>{{sendError}}</p>\n      <p>\n        <a class=\"button\" @click=\"retry\">{{ $t('generic.retry') }}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      invalidAddress: false,\n      target: \"\",\n      password: \"\",\n      receivedBalance: \"0.00 VTC\",\n      receivedTxCount: 0,\n      error: \"\",\n      sent: false,\n      sendError: \"\",\n      txids: []\n    };\n  },\n  mounted() {\n    var self = this;\n    window.wails.Events.On(\"createTransactionResult\", result => {\n      self.receivedBalance = result.FormattedAmount;\n      self.receivedTxCount = result.NumberOfTransactions;\n    });\n  },\n  methods: {\n    send: function() {\n      var self = this;\n      if (this.error !== \"\") {\n        this.sent = false;\n        this.txids = [];\n        this.sendError = this.error;\n        return;\n      }\n\n      if (this.password === \"\") {\n        this.sent = false;\n        this.txids = [];\n        this.sendError = this.$t(\"sending.password_required\");\n        return;\n      }\n\n      if (this.target === \"\") {\n        this.sent = false;\n        this.txids = [];\n        this.sendError = this.$t(\"sending.invalid_address\");\n        return;\n      }\n\n      window.backend.Backend.SendSweep(this.password).then(result => {\n        if (result.length === 1 && result[0].length !== 64) {\n          // Error!\n          self.sent = false;\n          self.txids = [];\n          self.sendError = self.$t(\"sending.\" + result[0]);\n        } else {\n          self.txids = result;\n          self.sent = true;\n          self.sendError = \"\";\n        }\n      });\n    },\n    recalculate() {\n      var self = this;\n      this.receivedBalance = \"0.00 VTC\";\n      this.invalidAddress = false;\n      window.backend.Backend.PrepareSweep(this.target).then(result => {\n        if (result !== \"\") {\n          self.receivedBalance = \"0.00 VTC\";\n          self.error = self.$t(\"sending.\" + result);\n        } else {\n          self.error = \"\";\n        }\n      });\n    },\n    back() {\n      this.$emit(\"back\");\n    },\n    retry() {\n      this.password = \"\";\n      this.receivedBalance = \"0.00 VTC\";\n      this.error = \"\";\n      this.sent = false;\n      this.txids = [];\n      this.sendError = \"\";\n      this.recalculate();\n    },\n    showTx(txid) {\n      window.backend.Backend.ShowTx(txid);\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\n</style>\n"
  },
  {
    "path": "frontend/src/components/Settings.vue",
    "content": "<template>\n  <div class=\"settings-container\">\n    <div class=\"col-settings\" v-if=\"!showWarning\">\n      <div class=\"col-settings-sub\">\n        <p style=\"text-align: left\" >\n          <input type=\"checkbox\" v-model=\"debugging\" />\n          {{ $t(\"settings.enable_debug\") }}\n          <br />\n          <span class=\"subtext\">{{ $t(\"settings.enable_debug_sub\") }}</span>\n        </p>\n        <p style=\"text-align: left\">\n          <input type=\"checkbox\" v-model=\"autoStart\" />\n          {{ $t(\"settings.auto_start\") }}\n          <br />\n          <span class=\"subtext\">{{ $t(\"settings.auto_start_sub\") }}</span>\n        </p>\n      </div>\n      <div class=\"col-settings-sub\">\n        <!-- <p style=\"text-align: left\">\n          <input type=\"checkbox\" v-model=\"testnet\" />\n          {{ $t(\"settings.testnet\") }}\n          <br />\n          <span class=\"subtext\">{{ $t(\"settings.testnet_sub\") }}</span>\n        </p> -->\n        <p style=\"text-align: left\">\n          <input type=\"checkbox\" v-model=\"enableIntegrated\" />\n          {{ $t(\"settings.enable_integrated\") }}\n          <br />\n          <span class=\"subtext\">{{ $t(\"settings.enable_integrated_sub\") }}</span>\n        </p>\n        <p style=\"text-align: left\">\n          {{ $t(\"settings.pool\") }}:\n          <br />\n          <select style=\"width: 100%\" name=\"pool\" v-model=\"poolID\">\n            <option v-for=\"option in pools\" v-bind:value=\"option.id\" v-bind:key=\"option.id\">\n                {{ option.name }}\n            </option>\n          </select>\n        </p>\n      </div>\n    </div>\n    <div class=\"col-286 height-100\" v-if=\"!showWarning\">\n      <p>\n        <a class=\"button\" @click=\"save\">{{ $t(\"settings.save_n_restart\") }}</a>\n      </p>\n    </div>\n    <div class=\"col-286\" v-if=\"showWarning\">\n      <div class=\"warning\" v-if=\"closedSourceMiner && showWarning\">\n        <p>{{ $t(\"settings.closed_source_warning\") }}</p>\n      </div>\n       <p>\n        <a class=\"button\" @click=\"toggleWarning\">{{ $t(\"generic.close\") }}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      closedSourceMiner: false,\n      debugging: false,\n      autoStart: false,\n      enableIntegrated: true,\n      showWarning: false,\n      testnet: false,\n      poolID: -1,\n      pools: [],\n    };\n  },\n  created() {\n    var self = this;\n    window.backend.Backend.GetClosedSource().then(result => {\n      self.closedSourceMiner = result;\n      window.backend.Backend.GetAutoStart().then(result => {\n        self.autoStart = result;\n        window.backend.Backend.GetDebugging().then(result => {\n          self.debugging = result;\n          window.backend.Backend.GetTestnet().then(result => {\n          self.testnet = result;\n            window.backend.Backend.GetPools().then(result => {\n              self.pools = result;\n              window.backend.Backend.GetPool().then(result => {\n                self.poolID = result;\n                window.backend.Backend.GetEnableIntegrated().then(result => {\n                  self.enableIntegrated = result;\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n    \n    \n   \n    \n  },\n  methods: {\n    toggleWarning: function() {\n      this.showWarning = !this.showWarning;\n      var self = this;\n      setTimeout(() => { self.showWarning = false; }, 5000);\n    },\n    save: function() {\n      var self = this;\n      window.backend.Backend.SetClosedSource(this.closedSourceMiner).then(() => {\n          window.backend.Backend.SetDebugging(self.debugging).then(() => {\n            window.backend.Backend.SetAutoStart(self.autoStart).then(() => {\n              window.backend.Backend.SetTestnet(self.testnet).then(() => {\n                window.backend.Backend.SetPool(self.poolID).then(() => {\n                  window.backend.Backend.SetEnableIntegrated(self.enableIntegrated).then( () => {\n                    self.$emit(\"committed\");\n                  });\n                });\n              });\n            });\n          });\n        }\n      );\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\ndiv.warning {\n  border: 2px solid #d0a000;\n  color: #d0a000;\n  width: 100%;\n  padding: 5px 10px;\n  text-align: justify;\n  line-height: 10pt;\n  font-size: 10pt;\n}\na.warning {\n  display: block; \n  float:right;\n  color: #d0a000;\n  cursor: pointer;\n  text-decoration: underline;\n}\ndiv.warning p {\n  margin: 0px;\n  padding: 0px;\n}\nspan.subtext {\n  opacity: 0.6;\n  font-size: 8pt;\n}\n</style>\n"
  },
  {
    "path": "frontend/src/components/TabBar.vue",
    "content": "<template>\n  <div class=\"tabBar\">\n    <div class=\"tabs\">\n      <div\n        :class=\"{tab : true, active: $parent.screen === 'mining' || $parent.screen === 'welcome'}\"\n      >\n        <a @click=\"wallet\">{{ $t('tabbar.wallet') }}</a>\n      </div>\n      <div :class=\"{tab : true, active: $parent.screen === 'send'}\">\n        <a @click=\"send\">{{ $t('tabbar.send_coins') }}</a>\n      </div>\n      <div :class=\"{tab : true, active: $parent.screen === 'settings'}\">\n        <a @click=\"settings\">{{ $t('tabbar.settings') }}</a>\n      </div>\n    </div>\n    <div style=\"float: right\" v-if=\"testnet\">\n      <div class=\"testnet\">TESTNET</div>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      testnet: false\n    };\n  },\n  mounted() {\n    var self = this;\n    window.backend.Backend.GetTestnet().then(result => {\n      self.testnet = result;\n    })\n  },\n  methods: {\n    send: function() {\n      this.$emit(\"send\");\n    },\n    wallet: function() {\n      this.$emit(\"wallet\");\n    },\n    settings: function() {\n      this.$emit(\"settings\");\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\ndiv.tabBar {\n  position: relative;\n  height: 58px;\n  background-color: rgba(255, 255, 255, 0.1);\n  width: 100%;\n  margin: 0px;\n  padding: 0px;\n}\n\ndiv.tabs {\n  width: 500px;\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  height: 20px;\n  margin-left: -250px;\n  margin-top: -10px;\n  padding: 0px;\n}\n\ndiv.tab {\n  width: 33%;\n  margin: 0px;\n  padding: 0px;\n  float: left;\n  color: white;\n  opacity: 0.6;\n  text-align: center;\n}\n\ndiv.tab.active {\n  opacity: 1;\n}\n\na {\n  cursor: pointer;\n}\n\n\ndiv.testnet {\n  height: 38px;\n  color: #ff0000;\n  border: 1px solid #ff0000;\n  font-weight: bold;\n  padding-left: 10px;\n  padding-right: 10px;\n  font-size: 20px;\n  margin-top: 10px;\n  margin-right: 20px;\n  line-height: 38px;\n  text-align: center;\n  width: 100px;\n}\n</style>\n"
  },
  {
    "path": "frontend/src/components/Tracking.vue",
    "content": "<template>\n  <div class=\"tracking\">\n    <p v-if=\"tracking\">\n      OCM v{{version}}\n      <span v-if=\"updateAvailable\">\n        -\n        <a @click=\"update\">{{ $t('tracking.update_available') }}</a>\n      </span> -\n      <span>{{ $t('tracking.tracking_enabled') }}.&nbsp;</span>\n      <a @click=\"disableTracking\">{{ $t('tracking.disable_tracking') }}</a> -\n      <a @click=\"reportIssue\">{{ $t('tracking.report_issue') }}</a>\n    </p>\n    <p v-if=\"!tracking\">\n      OCM v{{version}}\n      <span v-if=\"updateAvailable\">\n        -\n        <a @click=\"update\">{{ $t('tracking.update_available') }}</a>\n      </span> -\n      <span>{{ $t('tracking.tracking_disabled') }}.&nbsp;</span>\n      <a @click=\"enableTracking\">{{ $t('tracking.enable_tracking') }}</a>\n      <span>\n        &nbsp;-\n        <a @click=\"reportIssue\">{{ $t('tracking.report_issue') }}</a>\n      </span>\n    </p>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      tracking: false,\n      version: \"dev\",\n      updateAvailable: false\n    };\n  },\n  mounted() {\n    var self = this;\n    window.backend.Backend.TrackingEnabled().then(result => {\n      self.tracking = result === \"1\";\n    });\n    window.backend.Backend.GetVersion().then(result => {\n      self.version = result;\n    });\n    window.backend.Backend.UpdateAvailable().then(result => {\n      self.updateAvailable = result;\n    });\n    window.wails.Events.On(\"updateAvailable\", result => {\n      self.updateAvailable = result;\n    });\n  },\n  methods: {\n    update: function() {\n      this.$emit(\"update\");\n    },\n    reportIssue: function() {\n      window.backend.Backend.ReportIssue();\n    },\n    enableTracking: function() {\n      this.tracking = true;\n      window.backend.Backend.EnableTracking();\n    },\n    disableTracking: function() {\n      this.tracking = false;\n      window.backend.Backend.DisableTracking();\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\ndiv.tracking {\n  position: absolute;\n  bottom: 10px;\n  width: 100%;\n  text-align: center;\n  margin: 0px;\n  padding: 0px;\n}\ndiv.tracking p {\n  font-size: 10px;\n}\ndiv.tracking p span {\n  opacity: 0.6;\n}\n\ndiv.tracking p a {\n  opacity: 1;\n  text-decoration: underline;\n  cursor: pointer;\n}\n</style>\n"
  },
  {
    "path": "frontend/src/components/Update.vue",
    "content": "<template>\n  <div class=\"container\">\n    <div class=\"col-wide\">\n      <p>{{ $t('update.new_version_available') }}: {{version}}</p>\n      <div class=\"releaseNotes\">\n        <pre>{{notes}}</pre>\n      </div>\n      <p>\n        <a class=\"button\" @click=\"download\">{{ $t('update.download') }}</a>\n      </p>\n      <p>\n        <a class=\"link\" @click=\"back\">{{ $t('generic.back_to_wallet') }}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      version: \"\",\n      notes: \"\",\n      downloadUrl: \"\"\n    };\n  },\n  mounted() {\n    var self = this;\n    window.backend.Backend.VersionDetails().then(result => {\n      self.version = result[0];\n      self.notes = result[1];\n      self.downloadUrl = result[2];\n    });\n  },\n  methods: {\n    back: function() {\n      this.$emit(\"back\");\n    },\n    download: function() {\n      window.backend.Backend.OpenDownloadUrl(this.downloadUrl);\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\ndiv.releaseNotes {\n  height: 130px;\n  overflow-y: auto;\n  font-family: \"Courier New\", Courier, monospace;\n  color: #eee;\n  border: 1px solid #eee;\n  width: 600px;\n  margin: 0 auto;\n}\n</style>\n"
  },
  {
    "path": "frontend/src/components/Welcome.vue",
    "content": "<template>\n  <div class=\"container\">\n    <div class=\"col-286\" v-if=\"alreadyRunning === false && walletInitialized === 0\">\n      <p>{{ $t(\"welcome.makeapassword\") }}</p>\n      <p class=\"error\" v-if=\"error !== ''\">{{error}}</p>\n      <p>\n        <input type=\"password\" v-model=\"password\" v-bind:placeholder=\"$t('welcome.password')\" />\n      </p>\n      <p>\n        <input\n          type=\"password\"\n          v-model=\"confirmPassword\"\n          v-bind:placeholder=\"$t('welcome.confirmpassword')\"\n          @keyup.enter=\"initAndStart\"\n        />\n      </p>\n      <p>\n        <a class=\"button\" @click=\"initAndStart\">{{ $t(\"welcome.startmining\") }}</a>\n      </p>\n    </div>\n    <div class=\"col-286\" v-if=\"alreadyRunning === false && walletInitialized === 1\">\n      <p>{{ $t(\"welcome.click_button_to_start\") }}</p>\n      <p>\n        <a class=\"button\" @click=\"start\">{{ $t(\"welcome.startmining\") }}</a>\n      </p>\n    </div>\n    <div class=\"col-286\" v-if=\"alreadyRunning === true\">\n      <p>{{ $t(\"welcome.alreadyrunning\") }}</p>\n      <p>\n        <a class=\"button\" @click=\"close\">{{ $t(\"generic.close\") }}</a>\n      </p>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      error: \"\",\n      alreadyRunning: false,\n      password: \"\",\n      confirmPassword: \"\",\n      walletInitialized: -1\n    };\n  },\n  created() {\n    var self = this;\n    window.backend.Backend.AlreadyRunning().then(result => {\n      self.alreadyRunning = result;\n      if (!result) {\n        window.backend.Backend.WalletInitialized().then(result => {\n          self.walletInitialized = result;\n          if (\n            self.walletInitialized === 1 &&\n            !(self.$parent.manualStop === true)\n          ) {\n            self.start();\n          }\n        });\n      }\n    });\n  },\n  methods: {\n    close: function() {\n      window.backend.Backend.Close();\n    },\n    initAndStart: function() {\n      this.error = \"\";\n      if (this.password === \"\") {\n        this.error = this.$t(\"welcome.password_cannot_be_empty\");\n        return;\n      }\n      if (this.password !== this.confirmPassword) {\n        this.error = this.$t(\"welcome.password_mismatch\");\n        return;\n      }\n\n      var self = this;\n\n      window.backend.Backend.InitWallet(this.password).then(result => {\n        if (result !== true) {\n          this.error = self.$t(\"welcome.error_initializing\");\n        } else {\n          self.start();\n        }\n      });\n    },\n    start: function() {\n      this.$emit(\"start-mining\");\n    }\n  }\n};\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\np.error {\n  color: red;\n}\n</style>\n"
  },
  {
    "path": "frontend/src/i18n/README.md",
    "content": "# Translation workflow\n\nIf you want to add a new translation to the Vertcoin OCM you can follow two tracks:\n\n## Create a pull-request (preferable)\n\nWe expect you're familiar with how to create pull requests. If you're not, check [this article](https://akrabat.com/the-beginners-guide-to-contributing-to-a-github-project/)\n\n### Step 1: Create a copy of the english base file\n\nOnce in your local fork branch, make a copy of `en.json` in this directory (`frontend/src/i18n`), and rename it to match your desired language (for instance, for German you'd rename it to `de.json`).\n\n### Step 2: Translate!\n\nTranslate all the strings in the javascript file. Only translate the values not the identifiers, so:\n\n```json\n{\n    \"generic\" : {\n        \"retry\" : \"Retry\",\n        \"back_to_wallet\" : \"Back to wallet\"\n    },\n    ...\n}\n```\n\nWould become\n\n```json\n{\n    \"generic\" : {\n        \"retry\" : \"Opnieuw proberen\",\n        \"back_to_wallet\" : \"Terug naar portemonnee\"\n    },\n    ...\n}\n```\n**NOTE: Special characters**\n\nThere are a couple of special characters that are not allowed in javascript string literals, including backslashes and double quotes. You need to escape them. But since they're not used at all in the English base text, it seems unlikely you'll need them. In case of doubt, you can escape them [here](https://www.freeformatter.com/json-escape.html)\n\n**NOTE: Character set**\n\nPlease ensure the JSON file is saved using an UTF-8 character set.\n\n### Step 3: Add language to frontend\n\nIn the file `frontend/src/main.js` there's a list of the translations imported - add your new language there - ensure the list remains in alphabetical order:\n\n```javascript\n// Import all locales\nimport locale_de from \"./i18n/de.json\"; // <-- this line is added\nimport locale_en from \"./i18n/en.json\";\nimport locale_nl from \"./i18n/nl.json\";\n```\n\nFurther down in the file, also add it to the list of languages injected to the i18n component - ensure the list remains in alphabetical order:\n\n```javascript\n    const i18n = new VueI18n({\n      locale: result, // set locale\n      messages : {\n        de: locale_de, // <-- this line is added\n        en: locale_en,\n        nl: locale_nl,\n      },\n    });\n```\n\n### Step 4: Add language to the backend\n\nThe host code running on the machine does the detection of the language and chooses the most appropriate one based on the user's locale. It needs to be made aware of the newly available language. Add this to the file `backend/languages.go` around line 9 - ensure the list remains in alphabetical order:\n\n```golang\nvar availableLanguages = []string{\n    \"de\", // <-- this line is added. Notice the comma on the end - it belongs there!\n\t\"en\",\n    \"nl\",\n}\n```\n\n### Step 5: Commit & Create PR\n\nYou're done. Add all files to a commit, push it to your personal fork and then create a pull request to the main OCM repository. Thanks a ton for your contribution in advance!\n\n## Alternative option (only if you fail at the above)\n\nThe alternative option is that you just download the `en.js` file, translate it locally, and open an issue including the translated file. Then I can include it for you. But if you're able to use the PR workflow, I would really appreciate and prefer you use that!"
  },
  {
    "path": "frontend/src/i18n/bg.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Опитайте отново\",\n        \"back_to_wallet\" : \"Обратно към портфейла\",\n        \"close\" : \"Затвори\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner вече работи. Не можете да го стартирате повече от веднъж.\",\n        \"click_button_to_start\" : \"Щракнете върху бутона по-долу, за да започнете отново да копаете.\",\n        \"startmining\" : \"Започнете да копаете!\",\n        \"makeapassword\" : \"Създайте парола за One-Click Miner портфейла. Не я губете.\",\n        \"password\" : \"Парола\",\n        \"confirmpassword\" : \"Потвърдете паролата\",\n        \"password_cannot_be_empty\" : \"Паролата не може да бъде празна\",\n        \"password_mismatch\" : \"Паролите не съвпадат\",\n        \"error_initializing\" : \"Нещо се обърка при инициализирането на портфейла\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Компонентите се инсталират. Може да видите изскачащ прозорец, който иска разрешения (може просто да мига в лентата на задачите)\",\n        \"checks_failed\" : \"Проверките се провалиха\",\n        \"checking_mining_software\" : \"Проверка на софтуера за копаене...\",\n        \"rapidfail\" : \"Проверка за бързи провали\",\n        \"compatibility\" : \"Проверка на съвместимостта на графичния процесор (GPU)...\",\n        \"installing_miners\" : \"Инсталиране на софтуер за копаене...\",\n        \"verthash\" : \"Проверка / създаване на Verthash файл с данни...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Достъпен баланс\",\n        \"still_maturing\" : \"Очаква потвърждение\",\n        \"pending_pool_payout\" : \"предстоящо изплащане на пула\",\n        \"pending_payout_info_unavailable\" : \"Моля, изчакайте информация за предстоящо изплащане\",\n        \"waiting_for_miners\" : \"Изчакайте стартирането на миньорите\",\n        \"expected_earnings_24h\" : \"Очаквани доходи (24 часа)\",\n        \"estimating\" : \"приблизително\",\n        \"stop_mining\" : \"Спрете Копаенето\",\n        \"active_pool\" : \"Активен басейн\",\n        \"pool_fee\" : \"такса\",\n        \"copy_address\" : \"Копирайте адреса на портфейла си\",\n        \"payout_information\" : \"Преглед на информацията за изплащане\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Изпратете всичките си изкопани монети на\",\n        \"youre_sending_x_to\" : \"Вие изпращате {receivedBalance} на\",\n        \"youre_sending_x_in_y_txs_to\" : \"Вие изпращате {receivedBalance} в {receivedTxCount} транзакции към\",\n        \"receiver_address\" : \"Адрес на получателя\",\n        \"wallet_password\" : \"Парола на One-Click Miner портфейла\",\n        \"send\" : \"Изпрати\",\n        \"coins_sent\" : \"Вашите монети са изпратени!\",\n        \"view_trans_plural\" : \"Преглед на транзакциите\",\n        \"view_trans_singular\" : \"Преглед на транзакцията\",\n        \"failed_to_send\" : \"Изпращането на вашите монети не бе успешно\",\n        \"password_required\" : \"Изисква се парола за портфейла\",\n        \"invalid_address\" : \"Невалиден адрес\",\n        \"script_failure\" : \"Грешка в скрипта\",\n        \"could_not_calculate_fee\" : \"Не може да се изчисли таксата\",\n        \"insufficient_funds\" : \"Недостатъчни средства\",\n        \"sign_failed\" : \"Транзакцията не може да бъде подписана. Проверете паролата.\",\n        \"send_failed\" : \"Транзакцията не може да бъде изпратена. Проверете debug.log за повече информация\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Активиране на отстраняване на грешки\",\n        \"enable_debug_sub\" : \"Включете изхода от миньорската конзола в дневника за отстраняване на грешки. Може значително да се увеличи размера на лог файла\",\n        \"auto_start\" : \"Автоматично стартиране\",\n        \"auto_start_sub\" : \"Стартиране на One-Click Miner когато влезете в компютъра си\",\n        \"closed_source\" : \"Използвайте миньори със затворен код\",\n        \"closed_source_sub\" : \"По-добър хешрейт, но неодитирани миньори, които може да носят такса за програмист\",\n        \"closed_source_warning\" : \"Избрали сте да използвате миньори със затворен код. Vertcoin не одобрява или поддържа тези миньори. Те не могат да бъдат одитирани върху тяхното съдържание и могат да съдържат функции, които увреждат компютъра ви.\",\n        \"enable_integrated\" : \"Копаене чрез вградената видеокарта\",\n        \"enable_integrated_sub\" : \"Миньорът ще използва вградена видео карта (ако е възможно)\",\n        \"testnet\":\"Режим тестова мрежа\",\n        \"testnet_sub\":\"Активира режим на тестова мрежа. Няма да добивате истински монети.\",\n        \"skipverthashverify\":\"Не проверявайте Verthash при стартиране.\",\n        \"skipverthashverify_sub\":\"Ще пропусне проверката на целостта на Verthash файла при стартиране (не се препоръчва)\",\n        \"save_n_restart\" : \"Запазване и Рестартиране\",\n        \"pool\": \"Минен басейн\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Портфейл\",\n        \"send_coins\" : \"Изпратете монети\",\n        \"settings\" : \"Настройки\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Налична актуализация\",\n        \"tracking_enabled\" : \"Вие анонимно споделяте статистически данни за използването на софтуера\",\n        \"disable_tracking\" : \"Деактивиране\",\n        \"tracking_disabled\" : \"Вие не споделяте статистически данни за използването на софтуера\",\n        \"enable_tracking\" : \"Активирайте ги, за да ни помогнете да подобрим вашето преживяване\",\n        \"report_issue\" : \"Подайте сигнал за проблем\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Налична нова версия\",\n        \"download\" : \"Изтегли\"\n    }\n}"
  },
  {
    "path": "frontend/src/i18n/da.json",
    "content": "{\r\n    \"generic\" : {\r\n        \"retry\" : \"Prøv igen\",\r\n        \"back_to_wallet\" : \"Tilbage til wallet\",\r\n        \"close\" : \"Luk\"\r\n    },\r\n    \"welcome\" : {\r\n        \"alreadyrunning\" : \"One-Click Miner kører allerede. Du kan kun gøre en ad gangen.\",\r\n        \"click_button_to_start\" : \"Tryk på knappen herunder for at starte med at mine igen.\",\r\n        \"startmining\" : \"Start med at mine!\",\r\n        \"makeapassword\" : \"Lav et password, glem det ikke!\",\r\n        \"password\" : \"Password\",\r\n        \"confirmpassword\" : \"Bekræft Password\",\r\n        \"password_cannot_be_empty\" : \"Password kan ikke være tomt\",\r\n        \"password_mismatch\" : \"De 2 Passwords er ikke ens\",\r\n        \"error_initializing\" : \"Noget gik galdt under indlæsning af wallet\"\r\n    },\r\n    \"checks\" : {\r\n        \"prerequisite\" : \"Installation af en påkrævet pakke er igang. Du ser måske en popup der anmoder om tilladelser (måske som noget der blinker i din taskbar)\",\r\n        \"checks_failed\" : \"Tjek fejlede\",\r\n        \"checking_mining_software\" : \"Kontrollerer mining software...\",\r\n        \"rapidfail\" : \"Kontrollerer for hurtigt opstående fejl\",\r\n        \"compatibility\" : \"Kontrollerer for GPU kompatibilitet...\",\r\n        \"installing_miners\" : \"Installerer mine software...\",\r\n        \"verthash\" : \"Verificerer / generere Verthash data fil...\"\r\n    },\r\n    \"mining\" : {\r\n        \"spendable_balance\" : \"Brugbar Balance\",\r\n        \"still_maturing\" : \"modner stadig\",\r\n        \"pending_pool_payout\" : \"afventende pooludbetaling\",\r\n        \"pending_payout_info_unavailable\" : \"Vent venligst for pool udbetalingsoplysninger\",\r\n        \"waiting_for_miners\" : \"Venter på at minerne starter\",\r\n        \"expected_earnings_24h\" : \"Forventet indtjening (24 timer)\",\r\n        \"estimating\" : \"estimerer\",\r\n        \"stop_mining\" : \"Stop med at mine\",\r\n        \"active_pool\" : \"Aktiv pool\",\r\n        \"pool_fee\" : \"gebyr\",\r\n        \"copy_address\" : \"Kopier din wallet adresse\",\r\n        \"payout_information\" : \"Se udbetalingsoplysninger\"\r\n    },\r\n    \"sending\" : {\r\n        \"send_all_to\" : \"Send alle dine minede coins til\",\r\n        \"youre_sending_x_to\" : \"Du sender {receivedBalance} til\",\r\n        \"youre_sending_x_in_y_txs_to\" : \"Du sender {receivedBalance} igennem {receivedTxCount} transaktioner til\",\r\n        \"receiver_address\" : \"Modtager Adresse\",\r\n        \"wallet_password\" : \"OCM Wallet Password\",\r\n        \"send\" : \"Send\",\r\n        \"coins_sent\" : \"Dine coins er blevet sendt!\",\r\n        \"view_trans_plural\" : \"Se transaktioner\",\r\n        \"view_trans_singular\" : \"Se transaktion\",\r\n        \"failed_to_send\" : \"Kunne ikke sende dine coins\",\r\n        \"password_required\" : \"Wallet password er påkrævet\",\r\n        \"invalid_address\" : \"Ugyldig adresse\",\r\n        \"script_failure\" : \"Script fejl\",\r\n        \"could_not_calculate_fee\" : \"Kunne ikke beregne gebyr\",\r\n        \"insufficient_funds\" : \"Utilstrækkelige midler\",\r\n        \"sign_failed\" : \"Kunne ikke underskrive transaktion. Tjek dit password.\",\r\n        \"send_failed\" : \"Kunne ikke sende transaktion. Check debug.log for mere information\"\r\n    },\r\n    \"settings\" : {\r\n        \"enable_debug\" : \"Aktiver debugging\",\r\n        \"enable_debug_sub\" : \"Inkludér minerens consol output i debug log. Kan gøre logfilerne temmeligt store\",\r\n        \"auto_start\" : \"Auto start\",\r\n        \"auto_start_sub\" : \"Start One-Click Miner når du logger på din computer\",\r\n        \"closed_source\" : \"Brug closed-source minere\",\r\n        \"closed_source_sub\" : \"Bedre hashrate, men uanmeldte minere der pådrager sig udvikler gebyr\",\r\n        \"closed_source_warning\" : \"Du har valgt at benytte closed-source miner(e). Vertcoin støtter og supporterer IKKE disse minere.  De kan ikke undersøges for indhold og kunne derfor benytte sig af funktioner der kan være skadelige for din computer.\",\r\n        \"enable_integrated\" : \"Brug indbygget grafik til at mine\",\r\n        \"enable_integrated_sub\" : \"Indbygget grafik vil blive brugt af mineren (hvis det er muligt)\",\r\n        \"testnet\": \"Testnet mode\",\r\n        \"testnet_sub\": \"Aktiver testnet. Du vil ikke mine rigtige coins.\",\r\n        \"skipverthashverify\": \"Stop med at verificere Verthash data fil under opstart\",\r\n        \"skipverthashverify_sub\": \"Spring verifikationen af verthash data filen over (ikke anbefalet)\",\r\n        \"save_n_restart\" : \"Gem & Genstart\",\r\n        \"pool\": \"Mining pool\"\r\n    },\r\n    \"tabbar\" : {\r\n        \"wallet\" : \"Wallet\",\r\n        \"send_coins\" : \"Send coins\",\r\n        \"settings\" : \"Indstillinger\"\r\n    },\r\n    \"tracking\": { \r\n        \"update_available\" : \"Opdatering tilgængelig\",\r\n        \"tracking_enabled\" : \"Du deler brugsstatistikker anonymt\",\r\n        \"disable_tracking\" : \"Slå deling af statistik fra\",\r\n        \"tracking_disabled\" : \"Du deler ikke brugsstatistikker\",\r\n        \"enable_tracking\" : \"Slå deling af statistik til for at hjælpe os med at forbedre din oplevelse\",\r\n        \"report_issue\" : \"Anmeld fejl eller problemer\"\r\n    },\r\n    \"update\" : {\r\n        \"new_version_available\" : \"Ny version er tilgængelig\",\r\n        \"download\" : \"Download\"\r\n    }\r\n}\r\n"
  },
  {
    "path": "frontend/src/i18n/de.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Wiederholen\",\n        \"back_to_wallet\" : \"Zurück zur Wallet\",\n        \"close\" : \"Schließen\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click-Miner wird bereits ausgeführt. Sie können ihn nicht mehr als einmal ausführen.\",\n        \"click_button_to_start\" : \"Klicken Sie auf die Schaltfläche unten, um das Mining erneut zu starten.\",\n        \"startmining\" : \"Mining starten!\",\n        \"makeapassword\" : \"Erstellen Sie ein Passwort. Verlieren Sie es nicht!\",\n        \"password\" : \"Passwort\",\n        \"confirmpassword\" : \"Passwort bestätigen\",\n        \"password_cannot_be_empty\" : \"Passwort darf nicht leer sein\",\n        \"password_mismatch\" : \"Passwörter stimmen nicht überein\",\n        \"error_initializing\" : \"Fehler beim Initialisieren der Wallet\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Voraussetzungen werden installiert. Möglicherweise wird ein Fenster angezeigt, in dem Sie nach Berechtigungen gefragt werden (möglicherweise blinkt es in der Taskleiste)\",\n        \"checks_failed\" : \"Überprüfung fehlgeschlagen\",\n        \"checking_mining_software\" : \"Mining-Software wird überprüft...\",\n        \"rapidfail\" : \"Auftreten von schnellen Ausfällen wird geprüft\",\n        \"compatibility\" : \"GPU-Kompatibilität wird überprüft...\",\n        \"installing_miners\" : \"Mining-Software wird installiert...\",\n        \"verthash\" : \"Verthash Daten werden angelegt/verifiziert...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Verfügbares Guthaben\",\n        \"still_maturing\" : \"reift noch\",\n        \"pending_pool_payout\" : \"ausstehende Pool-Auszahlung\",\n        \"pending_payout_info_unavailable\": \"Ausstehende Pool-Auszahlung wird abgerufen\",\n        \"waiting_for_miners\" : \"Warten auf Start des Miners\",\n        \"expected_earnings_24h\" : \"Voraussichtliche Einnahmen (24h)\",\n        \"estimating\" : \"am schätzen\",\n        \"stop_mining\" : \"Mining stoppen\",\n        \"active_pool\" : \"Aktiver Pool\",\n        \"pool_fee\" : \"Pool-Gebühr\",\n        \"copy_address\" : \"Wallet-Adresse kopieren\",\n        \"payout_information\" : \"Auszahlungsinformationen ansehen\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Senden Sie all Ihre Coins an\",\n        \"youre_sending_x_to\" : \"Sie senden {receivedBalance} Coins an\",\n        \"youre_sending_x_in_y_txs_to\" : \"Sie senden {receivedBalance} Coins in {receivedTxCount} Transaktionen an\",\n        \"receiver_address\" : \"Empfängeradresse\",\n        \"wallet_password\" : \"Wallet-Passwort\",\n        \"send\" : \"Senden\",\n        \"coins_sent\" : \"Ihre Coins wurden versendet!\",\n        \"view_trans_plural\" : \"Transaktionen anzeigen\",\n        \"view_trans_singular\" : \"Transaktion anzeigen\",\n        \"failed_to_send\" : \"Fehler beim Senden Ihrer Coins\",\n        \"password_required\" : \"Das Wallet-Passwort wird benötigt\",\n        \"invalid_address\" : \"Ungültige Adresse\",\n        \"script_failure\" : \"Skriptfehler\",\n        \"could_not_calculate_fee\" : \"Gebührenkalkulation fehlgeschlagen\",\n        \"insufficient_funds\" : \"unzureichende Mittel\",\n        \"sign_failed\" : \"Transaktion kann nicht signiert werden. Überprüfen Sie Ihr Passwort\",\n        \"send_failed\" : \"Transaktion fehlgeschlagen. Weitere Informationen finden Sie in debug.log\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Debuggen aktivieren\",\n        \"enable_debug_sub\" : \"Konsolenausgabe der Mining-Software in das Debugprotokoll mit aufnehmen. Kann die Größe Ihrer Protokolle erheblich erhöhen\",\n        \"auto_start\" : \"Auto-Start\",\n        \"auto_start_sub\" : \"One-Click-Miner bei der Anmeldung starten\",\n        \"closed_source\" : \"Proprietäre Mining-Software nutzen\",\n        \"closed_source_sub\" : \"Bessere Hash-Rate, aber ungeprüfte Miner mit Entwicklergebühr.\",\n        \"closed_source_warning\" : \"Sie haben sich für die Verwendung proprietärer Mining-Software entschieden. Vertcoin bietet keine Unterstützung an. Die Miner können nicht überprüft werden und enthalten möglicherweise Funktionen, die Ihren Computer beeinträchtigen.\",\n        \"enable_integrated\" : \"Auf integrierter Grafikkarte minen\",\n        \"enable_integrated_sub\" : \"Miner wird die Onboard-Grafikkarte verwenden (wenn möglich)\",\n        \"testnet\" : \"Testnet-Modus\",\n        \"testnet_sub\" : \"Aktiviert Testnet-Modus. Sie werden keine echten Coins minen.\",\n        \"skipverthashverify\" : \"Verthash-Überprüfung beim Start überspringen\",\n        \"skipverthashverify_sub\" : \"Die Prüfung der Datenintegrität der Verthash-Daten beim Start wird übersprungen (nicht empfohlen)\",\n        \"save_n_restart\" : \"Speichern & Neustarten\",\n        \"pool\" : \"Mining-Pool\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Wallet\",\n        \"send_coins\" : \"Coins senden\",\n        \"settings\" : \"Einstellungen\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Update verfügbar\",\n        \"tracking_enabled\" : \"Nutzungsstatistiken werden anonym geteilt\",\n        \"disable_tracking\" : \"Deaktivieren\",\n        \"tracking_disabled\" : \"Sie teilen keine Nutzungsstatistiken\",\n        \"enable_tracking\" : \"Aktivieren Sie diese Option, um uns bei der Verbesserung der Benutzerfreundlichkeit zu helfen\",\n        \"report_issue\" : \"Ein Problem melden\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Neue Version verfügbar\",\n        \"download\" : \"Herunterladen\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/en.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Retry\",\n        \"back_to_wallet\" : \"Back to wallet\",\n        \"close\" : \"Close\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"The One-Click Miner is already running. You can't run it more than once.\",\n        \"click_button_to_start\" : \"Click the button below to start mining again.\",\n        \"startmining\" : \"Start Mining!\",\n        \"makeapassword\" : \"Make an OCM Wallet password. Don't lose it.\",\n        \"password\" : \"Password\",\n        \"confirmpassword\" : \"Confirm Password\",\n        \"password_cannot_be_empty\" : \"Password cannot be empty\",\n        \"password_mismatch\" : \"Passwords do not match\",\n        \"error_initializing\" : \"Something went wrong initializing the wallet\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"A prerequisite is being installed. You might see a popup asking for permissions (could just be blinking in the taskbar)\",\n        \"checks_failed\" : \"Checks failed\",\n        \"checking_mining_software\" : \"Checking mining software...\",\n        \"rapidfail\" : \"Checking for rapid failure occurrences\",\n        \"compatibility\" : \"Checking GPU compatibility...\",\n        \"installing_miners\" : \"Installing mining software...\",\n        \"verthash\" : \"Verifying / creating Verthash data file...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Spendable Balance\",\n        \"still_maturing\" : \"still maturing\",\n        \"pending_pool_payout\" : \"pending pool payout\",\n        \"pending_payout_info_unavailable\" : \"Please wait for pending payout information\",\n        \"waiting_for_miners\" : \"Waiting for miners to start\",\n        \"expected_earnings_24h\" : \"Expected Earnings (24h)\",\n        \"estimating\" : \"estimating\",\n        \"stop_mining\" : \"Stop Mining\",\n        \"active_pool\" : \"Active pool\",\n        \"pool_fee\" : \"fee\",\n        \"copy_address\" : \"Copy your wallet address\",\n        \"payout_information\" : \"View payout information\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Send all your mined coins to\",\n        \"youre_sending_x_to\" : \"You're sending {receivedBalance} to\",\n        \"youre_sending_x_in_y_txs_to\" : \"You're sending {receivedBalance} in {receivedTxCount} transactions to\",\n        \"receiver_address\" : \"Receiver Address\",\n        \"wallet_password\" : \"OCM Wallet Password\",\n        \"send\" : \"Send\",\n        \"coins_sent\" : \"Your coins are sent!\",\n        \"view_trans_plural\" : \"View transactions\",\n        \"view_trans_singular\" : \"View transaction\",\n        \"failed_to_send\" : \"Failed to send your coins\",\n        \"password_required\" : \"Wallet password is required\",\n        \"invalid_address\" : \"Invalid address\",\n        \"script_failure\" : \"Script failure\",\n        \"could_not_calculate_fee\" : \"Could not calculate fee\",\n        \"insufficient_funds\" : \"Insufficient funds\",\n        \"sign_failed\" : \"Unable to sign transaction. Check password.\",\n        \"send_failed\" : \"Unable to send transaction. Check debug.log for more information\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Enable debugging\",\n        \"enable_debug_sub\" : \"Include the miner's console output in the debug log. Can grow your logs quite large\",\n        \"auto_start\" : \"Auto start\",\n        \"auto_start_sub\" : \"Start the One-Click Miner when you log in your computer\",\n        \"closed_source\" : \"Use closed-source miners\",\n        \"closed_source_sub\" : \"Better hashrate, but unaudited miners that incur a developer's fee\",\n        \"closed_source_warning\" : \"You have selected to use closed source miner(s). Vertcoin does not endorse or support these miners. They cannot be audited on their contents and could contain functions that harm your computer.\",\n        \"enable_integrated\" : \"Mine on integrated graphics\",\n        \"enable_integrated_sub\" : \"The miner will use onboard graphics (if possible)\",\n        \"testnet\":\"Testnet mode\",\n        \"testnet_sub\":\"Enables testnet mode. You will not be mining real coins.\",\n        \"skipverthashverify\":\"Don't verify Verthash on startup\",\n        \"skipverthashverify_sub\":\"Will skip verifying the file integrity of Verthash data on startup (not recommended)\",\n        \"save_n_restart\" : \"Save & Restart\",\n        \"pool\": \"Mining pool\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Wallet\",\n        \"send_coins\" : \"Send coins\",\n        \"settings\" : \"Settings\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Update available\",\n        \"tracking_enabled\" : \"You are anonymously sharing usage statistics\",\n        \"disable_tracking\" : \"Disable\",\n        \"tracking_disabled\" : \"You are not sharing usage statistics\",\n        \"enable_tracking\" : \"Enable these to help us improve your experience\",\n        \"report_issue\" : \"Report an issue\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"New version available\",\n        \"download\" : \"Download\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/es.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Reintentar\",\n        \"back_to_wallet\" : \"Volver a la billetera\",\n        \"close\" : \"Cerrar\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"El minero de un click ya se está ejecutando. Solo se permite una instancia del programa.\",\n        \"click_button_to_start\" : \"Haz click en el botón para empezar a minar de nuevo.\",\n        \"startmining\" : \"¡Empezar a minar!\",\n        \"makeapassword\" : \"Crea una contraseña para la billetera del minero de un click. No la pierdas.\",\n        \"password\" : \"Contraseña.\",\n        \"confirmpassword\" : \"Confirmar contraseña.\",\n        \"password_cannot_be_empty\" : \"La contraseña no puede estar vacía.\",\n        \"password_mismatch\" : \"Las contraseñas no coinciden.\",\n        \"error_initializing\" : \"Hubo un problema al iniciar la billetera.\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Un prerequisito está siendo instalado. Puede ser que veas una ventana emergente pidiendo permisos (podría estar parpadeando en la barra de tareas.)\",\n        \"checks_failed\" : \"Chequeos fallados\",\n        \"checking_mining_software\" : \"Chequeando el software de minería...\",\n        \"rapidfail\" : \"Comprobación de fallos rápidos\",\n        \"compatibility\" : \"Chequeando compatibilidad de la tarjeta gráfica...\",\n        \"installing_miners\" : \"Instalando software de minería...\",\n        \"verthash\" : \"Verificando / creando archivo de datos de Verthash.\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Saldo disponible\",\n        \"still_maturing\" : \"Todavía no puedes gastar tus monedas, se necesitan más confirmaciones de la red.\",\n        \"pending_pool_payout\" : \"Pago de la pool pendiente.\",\n        \"pending_payout_info_unavailable\" : \"Información de pago no disponible en este momento.\",\n        \"waiting_for_miners\" : \"Esperando a que los mineros empiecen.\",\n        \"expected_earnings_24h\" : \"Ganancias esperadas (24h).\",\n        \"estimating\" : \"Estimando\",\n        \"stop_mining\" : \"Dejar de minar.\",\n        \"active_pool\" : \"Pool activa.\",\n        \"pool_fee\" : \"Comisión.\",\n        \"copy_address\" : \"Copia la dirección de tu billetera.\",\n        \"payout_information\" : \"Mostrar la información del pago.\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Envia todas tus monedas minadas a\",\n        \"youre_sending_x_to\" : \"Estás enviando {receivedBalance} a\",\n        \"youre_sending_x_in_y_txs_to\" : \"Estás enviando {receivedBalance} en {receivedTxCount} transacciones a\",\n        \"receiver_address\" : \"Dirección del receptor\",\n        \"wallet_password\" : \"Contraseña de la billetera del minero de un click\",\n        \"send\" : \"Enviar\",\n        \"coins_sent\" : \"¡Tus monedas han sido enviadas!\",\n        \"view_trans_plural\" : \"Mostrar transacciones\",\n        \"view_trans_singular\" : \"Mostrar transacción\",\n        \"failed_to_send\" : \"Hubo un fallo al enviar tus monedas\",\n        \"password_required\" : \"La contraseña de la billetera es requerida\",\n        \"invalid_address\" : \"Dirección inválida\",\n        \"script_failure\" : \"Fallo de código\",\n        \"could_not_calculate_fee\" : \"No se pudo calcular la comisión\",\n        \"insufficient_funds\" : \"Fondos insuficientes\",\n        \"sign_failed\" : \"No se pudo firmar la transacción. Chequea la contraseña\",\n        \"send_failed\" : \"No se pudo enviar la transacción. Mira debug.log para más información\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Activar información de depuración\",\n        \"enable_debug_sub\" : \"Incluye las salidas del minero en la consola en el registro de depuración. Puede hacer que tus registros sean bastante grandes\",\n        \"auto_start\" : \"Empezar automáticamente\",\n        \"auto_start_sub\" : \"Empezar el minero de un click cuando inicias sesión en tu ordenador\",\n        \"closed_source\" : \"Usa mineros de código cerrado\",\n        \"closed_source_sub\" : \"Mejor rendimiento, pero mineros que no pueden ser inspeccionados y que sufren de una comisión de desarollo\",\n        \"closed_source_warning\" : \"Has seleccionado usar minero(s) de código cerrado. Vertcoin no respalda ni ayuda a estos mineros. Sus contenidos no pueden ser inspeccionados y podrían contener funciones que podrían dañar tu ordenador.\",\n        \"enable_integrated\" : \"Minar en gráficos integrados\",\n        \"enable_integrated_sub\" : \"El minero utilizará gráficos integrados (si es posible)\",\n        \"testnet\":\"Modo Testnet\",\n        \"testnet_sub\":\"Activa el modo Tesnet. No estarás minando monedas reales.\",\n        \"skipverthashverify\":\"No verificar Verthash al encender\",\n        \"skipverthashverify_sub\":\"Se saltará la verificación de la integridad de la información de Verthash al encender (no recomendado)\",\n        \"save_n_restart\" : \"Guardar y reiniciar\",\n        \"pool\": \"Pool de minería\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"billetera\",\n        \"send_coins\" : \"Enviar monedas\",\n        \"settings\" : \"Opciones\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Actualización disponible\",\n        \"tracking_enabled\" : \"Estás compartiendo datos de uso anónimamente\",\n        \"disable_tracking\" : \"Desactivar\",\n        \"tracking_disabled\" : \"No estás compartiendo datos de uso\",\n        \"enable_tracking\" : \"Activar el uso de datos compartidos para ayudarnos a mejorar tu experiencia\",\n        \"report_issue\" : \"Reportar un problema\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Nueva versión disponible\",\n        \"download\" : \"Descargar\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/fr.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Réessayer\",\n        \"back_to_wallet\" : \"Revenir au portefeuille\",\n        \"close\" : \"Fermer\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner est déjà en cours d'exécution. Vous ne pouvez pas l'exécuter plus d'une fois.\",\n        \"click_button_to_start\" : \"Cliquer sur le bouton ci-dessous pour redémarrer le minage.\",\n        \"startmining\" : \"Démarrer le minage !\",\n        \"makeapassword\" : \"Créer un mot de passe. Ne pas le perdre !\",\n        \"password\" : \"Mot de passe\",\n        \"confirmpassword\" : \"Confirmer le mot de passe\",\n        \"password_cannot_be_empty\" : \"Le mot de passe ne peut être vide\",\n        \"password_mismatch\" : \"Le mot de passe ne correspond pas\",\n        \"error_initializing\" : \"Erreur pendant l'initialisation du portefeuille\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Un prérequis est en cours d'installation. Vous pourriez voir une fenêtre demandant des autorisations (elle pourrait simplement clignoter dans la barre des tâches)\",\n        \"checks_failed\" : \"Les vérifications ont echoué\",\n        \"checking_mining_software\" : \"Vérification du logiciel de minage...\",\n        \"rapidfail\" : \"Vérification des occurrences d'échec rapide\",\n        \"compatibility\" : \"Vérification de la compatibilité GPU...\",\n        \"installing_miners\" : \"Installation du logiciel de minage...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Solde disponible\",\n        \"still_maturing\" : \"En cours de consolidation\",\n        \"pending_pool_payout\" : \"Paiement de la pool en attente\",\n        \"waiting_for_miners\" : \"En attente de mineurs pour démarrer\",\n        \"expected_earnings_24h\" : \"Bénéfices attendus (24h)\",\n        \"estimating\" : \"Estimation\",\n        \"stop_mining\" : \"Arrêt du minage\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Envoyer toute votre cryptomonnaie minée à\",\n        \"youre_sending_x_to\" : \"Vous envoyez {receivedBalance} à\",\n        \"youre_sending_x_in_y_txs_to\" : \"Vous envoyez {receivedBalance} en {receivedTxCount} transactions à\",\n        \"receiver_address\" : \"Adresse du destinataire\",\n        \"wallet_password\" : \"Mot de passe du portefeuille\",\n        \"send\" : \"Envoyer\",\n        \"coins_sent\" : \"Votre cryptomonnaie a été envoyée !\",\n        \"view_trans_plural\" : \"Voir les transactions\",\n        \"view_trans_singular\" : \"Voir la transaction\",\n        \"failed_to_send\" : \"Echec lors de l'envoi de votre cryptomonnaie\",\n        \"password_required\" : \"Le mot de passe du portefeuille est requis\",\n        \"invalid_address\" : \"Adresse invalide\",\n        \"script_failure\" : \"Script défectueux\",\n        \"could_not_calculate_fee\" : \"Calcul des frais impossible\",\n        \"insufficient_funds\" : \"Fonds insuffisants\",\n        \"sign_failed\" : \"Impossible de signer la transaction. Vérifiez votre mot de passe\",\n        \"send_failed\" : \"Transaction impossible. Vérifier debug.log pour plus d'informations\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Activer le débogage\",\n        \"enable_debug_sub\" : \"Inclure la sortie console du logiciel de minage dans le log de débogage. Peut augmenter considérablement la taille de vos logs\",\n        \"auto_start\" : \"Démarrage auto\",\n        \"auto_start_sub\" : \"Démarrer One-Click Miner quand vous vous connectez à votre ordinateur\",\n        \"closed_source\" : \"Utiliser des logiciels de minage propriétaires\",\n        \"closed_source_sub\" : \"Meilleur taux de hachage, mais logiciel de minage ne rétribuant pas les développeurs\",\n        \"closed_source_warning\" : \"Vous avez choisi d'utiliser des logiciels de minage propriétaires. Vertcoin n'en assure pas le support. Leur contenu ne peut pas être audité et pourrait comporter des fonctions qui endommagent votre ordinateur.\",\n        \"save_n_restart\" : \"Enregistrer & Redémarrer\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Portefeuille\",\n        \"send_coins\" : \"Envoyer de la cryptomonnaie\",\n        \"settings\" : \"Paramètres\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Mise à jour disponible\",\n        \"tracking_enabled\" : \"Vous partagez anonymement vos statistiques d'utilisation\",\n        \"disable_tracking\" : \"Désactiver\",\n        \"tracking_disabled\" : \"Vous ne partagez pas vos statistiques d'utilisation\",\n        \"enable_tracking\" : \"Activer cette option pour nous permettre d'améliorer votre expérience utilisateur\",\n        \"report_issue\" : \"Signaler un problème\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Nouvelle version disponible\",\n        \"download\" : \"Télécharger\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/hi.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"पुन: प्रयास\",\n        \"back_to_wallet\" : \"वापस वॉलेट में\",\n        \"close\" : \"बंद करे\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"वन-क्लिक माइनर पहले से ही चल रहा है। आप इसे एक से अधिक बार नहीं चला सकते।\",\n        \"click_button_to_start\" : \"फिर से खनन शुरू करने के लिए नीचे दिए गए बटन पर क्लिक करें।\",\n        \"startmining\" : \"खनन शुरू करो!\",\n        \"makeapassword\" : \"एक पासवर्ड बनाएं। इसे खोना नहीं है।\",\n        \"password\" : \"पारण शब्द\",\n        \"confirmpassword\" : \"पासवर्ड की पुष्टि कीजिये\",\n        \"password_cannot_be_empty\" : \"पासवर्ड खाली नहीं हो सकता\",\n        \"password_mismatch\" : \"पासवर्ड मेल नहीं खाते\",\n        \"error_initializing\" : \"वॉलेट को शुरू करने में कुछ गलत हुआ\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"एक शर्त लगाई जा रही है। आप एक पॉपअप अनुमति के लिए पूछ सकते हैं (बस टास्कबार में निमिष हो सकता है)\",\n        \"checks_failed\" : \"जाँच विफल\",\n        \"checking_mining_software\" : \"खनन सॉफ्टवेयर की जाँच करना...\",\n        \"rapidfail\" : \"तेजी से विफलता की घटनाओं के लिए जाँच\",\n        \"compatibility\" : \"ग्राफिक्स प्रोसेसिंग यूनिट संगतता की जाँच करना...\",\n        \"installing_miners\" : \"खनन सॉफ्टवेयर स्थापित करना...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"व्यय करने योग्य शेष\",\n        \"still_maturing\" : \"अभी भी परिपक्व हो रहा है\",\n        \"pending_pool_payout\" : \"लंबित पूल भुगतान\",\n        \"waiting_for_miners\" : \"खनिकों के शुरू होने का इंतजार\",\n        \"expected_earnings_24h\" : \"अपेक्षित कमाई (चौबीस घंटे)\",\n        \"estimating\" : \"का आकलन\",\n        \"stop_mining\" : \"खनन बंद करो\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"करने के लिए अपने सभी खनन सिक्के भेजें\",\n        \"youre_sending_x_to\" : \"आप भेज रहे हैं {receivedBalance} सेवा मेरे\",\n        \"youre_sending_x_in_y_txs_to\" : \"आप भेज रहे हैं {receivedBalance} में {receivedTxCount} लेन-देन\",\n        \"receiver_address\" : \"रिसीवर का पता\",\n        \"wallet_password\" : \"वॉलेट पासवर्ड\",\n        \"send\" : \"भेजना\",\n        \"coins_sent\" : \"आपके सिक्के भेजे हैं\",\n        \"view_trans_plural\" : \"लेन-देन देखें\",\n        \"view_trans_singular\" : \"लेन-देन देखें\",\n        \"failed_to_send\" : \"अपने सिक्के भेजने में विफल\",\n        \"password_required\" : \"वॉलेट पासवर्ड की आवश्यकता है\",\n        \"invalid_address\" : \"गलत पता\",\n        \"script_failure\" : \"स्क्रिप्ट की विफलता\",\n        \"could_not_calculate_fee\" : \"शुल्क की गणना नहीं कर सका\",\n        \"insufficient_funds\" : \"अपर्याप्त कोष\",\n        \"sign_failed\" : \"लेन-देन पर हस्ताक्षर करने में असमर्थ। अपना पासवर्ड जांचें\",\n        \"send_failed\" : \"लेनदेन भेजने में असमर्थ। अधिक जानकारी के लिए debug.log की जाँच करें\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"डिबगिंग सक्षम करें\",\n        \"enable_debug_sub\" : \"डिबग लॉग में माइनर के कंसोल आउटपुट को शामिल करें। अपने लॉग को काफी बड़ा कर सकते हैं\",\n        \"auto_start\" : \"ऑटो स्टार्ट\",\n        \"auto_start_sub\" : \"जब आप अपने कंप्यूटर में लॉग इन करते हैं तो वन-क्लिक माइनर शुरू करें\",\n        \"closed_source\" : \"बंद-स्रोत खनिक का उपयोग करें\",\n        \"closed_source_sub\" : \"बेहतर हैशेट, लेकिन अघोषित खनिक जो एक डेवलपर के शुल्क को बढ़ाते हैं\",\n        \"closed_source_warning\" : \"आपने बंद स्रोत खननकर्ता का उपयोग करने के लिए चुना है। Vertcoin इन खनिकों का समर्थन या समर्थन नहीं करता है। उनकी सामग्री पर उनका ऑडिट नहीं किया जा सकता है और इसमें आपके कंप्यूटर को नुकसान पहुंचाने वाले कार्य हो सकते हैं।\",\n        \"save_n_restart\" : \"सहेजें और पुनरारंभ करें\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"बटुआ\",\n        \"send_coins\" : \"सिक्के भेजें\",\n        \"settings\" : \"सेटिंग्स\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"अपडेट उपलब्ध\",\n        \"tracking_enabled\" : \"आप गुमनाम रूप से उपयोग के आंकड़े साझा कर रहे हैं\",\n        \"disable_tracking\" : \"अक्षम\",\n        \"tracking_disabled\" : \"आप उपयोग के आंकड़े साझा नहीं कर रहे हैं\",\n        \"enable_tracking\" : \"अपने अनुभव को बेहतर बनाने में हमारी सहायता करने के लिए इन्हें सक्षम करें\",\n        \"report_issue\" : \"मामले की रिपोर्ट करें\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"नया संस्करण उपलब्ध है\",\n        \"download\" : \"डाउनलोड\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/hr.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Pokušajte ponovno\",\n        \"back_to_wallet\" : \"Natrag na novčanik\",\n        \"close\" : \"Zatvoriti\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner već radi. Ne možete ga pokrenuti više od jednom.\",\n        \"click_button_to_start\" : \"Pritisnite dugme ispod da ponovno započnete sa rudarenjem.\",\n        \"startmining\" : \"Započnite sa rudarenjem!\",\n        \"makeapassword\" : \"Kreirajte lozinku. Nemojte ju izgubiti.\",\n        \"password\" : \"Lozinka\",\n        \"confirmpassword\" : \"Potvrdite lozinku\",\n        \"password_cannot_be_empty\" : \"Polje za lozinku ne može biti prazno\",\n        \"password_mismatch\" : \"Lozinke se ne podudaraju\",\n        \"error_initializing\" : \"Pogreška kod učitavanja novčanika\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Skidanje preduvjetnih datoteka. Mogućnost iskakanja skočnog prozora za dopuštenja (može treperiti u alatnoj traci)\",\n        \"checks_failed\" : \"Provjera neuspješna\",\n        \"checking_mining_software\" : \"Provjera softvera za rudarenje...\",\n        \"rapidfail\" : \"Provjera učestalosti neuspješnih radnji\",\n        \"compatibility\" : \"Provjera kompatibilnosti grafičke kartice...\",\n        \"installing_miners\" : \"Instalacija softvera za rudarenje...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Dostupan iznos\",\n        \"still_maturing\" : \"nedozrelo\",\n        \"pending_pool_payout\" : \"očekivana pool isplata\",\n        \"waiting_for_miners\" : \"Čekanje da softver za rudarenje započne sa radom\",\n        \"expected_earnings_24h\" : \"Očekivana zarada(24h)\",\n        \"estimating\" : \"Vršim procjenu\",\n        \"stop_mining\" : \"Zaustavi rudarenje\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Pošalji sve izrudarene novčiće na\",\n        \"youre_sending_x_to\" : \"Šaljete {receivedBalance} na\",\n        \"youre_sending_x_in_y_txs_to\" : \"Šaljete {receivedBalance} u {receivedTxCount} transakcija na\",\n        \"receiver_address\" : \"Adresa primatelja\",\n        \"wallet_password\" : \"Lozinka novčanika\",\n        \"send\" : \"Pošalji\",\n        \"coins_sent\" : \"Vaši novčići su poslani!\",\n        \"view_trans_plural\" : \"Vidi transakciju\",\n        \"view_trans_singular\" : \"Vidi transakcije\",\n        \"failed_to_send\" : \"Neuspješno slanje vaših novčića\",\n        \"password_required\" : \"Potrebna je lozinka novčanika\",\n        \"invalid_address\" : \"Nepostojeća adresa\",\n        \"script_failure\" : \"Greška skripte\",\n        \"could_not_calculate_fee\" : \"Nije moguće izračunati naknadu\",\n        \"insufficient_funds\" : \"Nedostatna sredstva\",\n        \"sign_failed\" : \"Nije moguće potpisati transakciju. Provjerite zaporku\",\n        \"send_failed\" : \"Nije moguće poslati transakciju. Provjerite debug.log za više informacija\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Omogući otklanjanje bugova\",\n        \"enable_debug_sub\" : \"Omogući izvoz logova konzole softvera za rudarenje u log za otklanjanje bugova. Veličina loga može se znatno povećati\",\n        \"auto_start\" : \"Automatski početak\",\n        \"auto_start_sub\" : \"Pokreni One-Click Miner kada se logiraš na računalo\",\n        \"closed_source\" : \"Koristi softver za rudarenje zatvorenog koda\",\n        \"closed_source_sub\" : \"Bolji hashrate, ali neocijenjeni softver za rudarenje može uključivati naknadu za razvojne inženjere\",\n        \"closed_source_warning\" : \"Odlučili ste koristiti softver(e) za rudarenje zatvorenog koda. Vertcoin ne odobrava i ne podržava njihovu upotrebu. Ne može se provjeriti njihov sadržaj i potencijalno mogu sadržavati funkcije koje mogu oštetiti vaše računalo.\",\n        \"save_n_restart\" : \"Spremi i ponovno pokreni\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Novčanik\",\n        \"send_coins\" : \"Pošalji novčiće\",\n        \"settings\" : \"Postavke\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Nova inačica je dostupna\",\n        \"tracking_enabled\" : \"Anonimno dijelite vašu statistiku o korištenju\",\n        \"disable_tracking\" : \"Onemogući\",\n        \"tracking_disabled\" : \"Ne dijelite statistiku o korištenju\",\n        \"enable_tracking\" : \"Omogućite i pomognite nam da unaprijedimo korisničko iskustvo\",\n        \"report_issue\" : \"Prijavite problem\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Nova verzija je dostupna\",\n        \"download\" : \"Skidanje\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/it.json",
    "content": "{\r\n    \"generic\" : {\r\n        \"retry\" : \"Riprova\",\r\n        \"back_to_wallet\" : \"Torna al portafoglio\",\r\n        \"close\" : \"Chiudi\"\r\n    },\r\n    \"welcome\" : {\r\n        \"alreadyrunning\" : \"One-Click Miner è già in esecuzione. Non puoi eseguirlo più di una volta.\",\r\n        \"click_button_to_start\" : \"Fai clic sul pulsante sottostante per ricominciare a minare.\",\r\n        \"startmining\" : \"Inizia a Minare!\",\r\n        \"makeapassword\" : \"Crea una password per il portafoglio OCM. Non perderla.\",\r\n        \"password\" : \"Password\",\r\n        \"confirmpassword\" : \"Conferma Password\",\r\n        \"password_cannot_be_empty\" : \"La password non può essere vuota\",\r\n        \"password_mismatch\" : \"Le password non corrispondono\",\r\n        \"error_initializing\" : \"Qualcosa è andato storto nell'inizializzazione del portafoglio\"\r\n    },\r\n    \"checks\" : {\r\n        \"prerequisite\" : \"Un prerequisito sta venendo installato. Potresti vedere un popup che richiede dei permessi (potrebbe anche solo lampeggiare nella barra delle applicazioni)\",\r\n        \"checks_failed\" : \"Controlli falliti\",\r\n        \"checking_mining_software\" : \"Controllo del software di mining...\",\r\n        \"rapidfail\" : \"Controllo di occorrenze di fallimento rapido\",\r\n        \"compatibility\" : \"Controllo di compatibilità della GPU...\",\r\n        \"installing_miners\" : \"Installazione del software di mining...\",\r\n        \"verthash\" : \"Verifica / creazione del file di dati Verthash...\"\r\n    },\r\n    \"mining\" : {\r\n        \"spendable_balance\" : \"Saldo Disponibile\",\r\n        \"still_maturing\" : \"non ancora maturato\",\r\n        \"pending_pool_payout\" : \"pagamento del pool in sospeso\",\r\n        \"pending_payout_info_unavailable\" : \"Perfavore attendi le informazioni sul pagamento in sospeso\",\r\n        \"waiting_for_miners\" : \"In attesa che i miner si avviino\",\r\n        \"expected_earnings_24h\" : \"Guadagno Previsto (24h)\",\r\n        \"estimating\" : \"calcolo in corso\",\r\n        \"stop_mining\" : \"Smetti di Minare\",\r\n        \"active_pool\" : \"Pool attiva\",\r\n        \"pool_fee\" : \"tassa\",\r\n        \"copy_address\" : \"Copia l'indirizzo del tuo portafoglio\",\r\n        \"payout_information\" : \"Visualizza le informazioni di pagamento\"\r\n    },\r\n    \"sending\" : {\r\n        \"send_all_to\" : \"Invia tutte le tue monete minate a\",\r\n        \"youre_sending_x_to\" : \"Stai inviando {receivedBalance} a\",\r\n        \"youre_sending_x_in_y_txs_to\" : \"Stai inviando {receivedBalance} in {receivedTxCount} transazioni a\",\r\n        \"receiver_address\" : \"Indirizzo del Destinatario\",\r\n        \"wallet_password\" : \"Password del Portafoglio OCM\",\r\n        \"send\" : \"Invia\",\r\n        \"coins_sent\" : \"Le tue monete sono state inviate!\",\r\n        \"view_trans_plural\" : \"Visualizza le transazioni\",\r\n        \"view_trans_singular\" : \"Visualizza la transazione\",\r\n        \"failed_to_send\" : \"Fallito l'invio delle tue monete\",\r\n        \"password_required\" : \"La password del portafoglio è obbligatoria\",\r\n        \"invalid_address\" : \"Indirizzo non valido\",\r\n        \"script_failure\" : \"Fallimento nello script\",\r\n        \"could_not_calculate_fee\" : \"Impossibile calcolare la tassa\",\r\n        \"insufficient_funds\" : \"Fondi insufficienti\",\r\n        \"sign_failed\" : \"Non è stato possibile firmare la transazione. Controlla la password\",\r\n        \"send_failed\" : \"Non è stato possibile inviare la transazione. Controlla debug.log per ulteriori informazioni\"\r\n    },\r\n    \"settings\" : {\r\n        \"enable_debug\" : \"Abilita il debug\",\r\n        \"enable_debug_sub\" : \"Includi l'output della console del miner nel log di debug. Può far aumentare di molto la dimensione dei tuoi log\",\r\n        \"auto_start\" : \"Avvio automatico\",\r\n        \"auto_start_sub\" : \"Avvia One-Click Miner quando esegui l'accesso al tuo computer\",\r\n        \"closed_source\" : \"Usa miner closed-source\",\r\n        \"closed_source_sub\" : \"Miglior hashrate, ma miner non certificati che incorrono in una tassa per gli sviluppatori\",\r\n        \"closed_source_warning\" : \"Hai scelto di usare uno o più miner closed-source. Vertcoin non approva né supporta questi miner. Non possono essere controllati sui loro contenuti e potrebbero contenere funzioni dannose per il tuo computer.\",\r\n        \"enable_integrated\" : \"Mina con la grafica integrata\",\r\n        \"enable_integrated_sub\" : \"Il miner userà la grafica a bordo (se possibile)\",\r\n        \"testnet\" : \"Modalità testnet\",\r\n        \"testnet_sub\" : \"Abilita la modalità testnet. Non minerai monete reali.\",\r\n        \"skipverthashverify\" : \"Non verificare Verthash all'avvio\",\r\n        \"skipverthashverify_sub\" : \"Salta la verifica di integrità del file dei dati di Verthash all'avvio (non raccomandato)\",\r\n        \"save_n_restart\" : \"Salva e Riavvia\",\r\n        \"pool\" : \"Pool di mining\"\r\n    },\r\n    \"tabbar\" : {\r\n        \"wallet\" : \"Portafoglio\",\r\n        \"send_coins\" : \"Invia monete\",\r\n        \"settings\" : \"Impostazioni\"\r\n    },\r\n    \"tracking\": { \r\n        \"update_available\" : \"Aggiornamento disponibile\",\r\n        \"tracking_enabled\" : \"Stai condividendo in modo anonimo le statistiche sull'utilizzo\",\r\n        \"disable_tracking\" : \"Disabilita\",\r\n        \"tracking_disabled\" : \"Non stai condividendo le statistiche sull'utilizzo\",\r\n        \"enable_tracking\" : \"Abilitane la condivisione per aiutarci a migliorare la tua esperienza\",\r\n        \"report_issue\" : \"Segnala un problema\"\r\n    },\r\n    \"update\" : {\r\n        \"new_version_available\" : \"Nuova versione disponibile\",\r\n        \"download\" : \"Scarica\"\r\n    }\r\n}\r\n"
  },
  {
    "path": "frontend/src/i18n/ja.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"再試行をする\",\n        \"back_to_wallet\" : \"ウォレットに戻る\",\n        \"close\" : \"閉じる\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"ワンクリックマイナーはすでに実行中です。複数回実行することはできません。\",\n        \"click_button_to_start\" : \"下のボタンをクリックして、マイニングを再開してください。\",\n        \"startmining\" : \"マイニングを始める！\",\n        \"makeapassword\" : \"入力するパスワードを無くさないでください。\",\n        \"password\" : \"パスワード\",\n        \"confirmpassword\" : \"パスワード（確認用）\",\n        \"password_cannot_be_empty\" : \"パスワードは空にできません\",\n        \"password_mismatch\" : \"新パスワードと再入力パスワードが一致しません\",\n        \"error_initializing\" : \"ウォレットの初期化中に問題が発生しました\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"前提条件がインストールされています。許可を求めてポップアップが表示されるかもしれません (またはタスクバーで点滅している可能性があります)\",\n        \"checks_failed\" : \"チェック失敗\",\n        \"checking_mining_software\" : \"マイニングソフトウェアの確認中...\",\n        \"rapidfail\" : \"迅速な障害発生の確認中\",\n        \"compatibility\" : \"GPUの互換性を確認中...\",\n        \"installing_miners\" : \"マイニングソフトウェアのインストール中...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"消費可能残高\",\n        \"still_maturing\" : \"まだ成熟している\",\n        \"pending_pool_payout\" : \"保留中のプールの支払い\",\n        \"waiting_for_miners\" : \"マイナーが始まるのを待っている\",\n        \"expected_earnings_24h\" : \"予想収益 (24時間)\",\n        \"estimating\" : \"見積もり\",\n        \"stop_mining\" : \"マイニングをやめる\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"にあなたの採掘したコインをすべて送る\",\n        \"youre_sending_x_to\" : \"に{receivedBalance}を送っています\",\n        \"youre_sending_x_in_y_txs_to\" : \"{receivedTxCount}トランザクションで{receivedBalance}をに送信しています\",\n        \"receiver_address\" : \"受信者アドレス\",\n        \"wallet_password\" : \"ウォレットパスワード\",\n        \"send\" : \"送る\",\n        \"coins_sent\" : \"あなたのコインが送られました!\",\n        \"view_trans_plural\" : \"取引を見る\",\n        \"view_trans_singular\" : \"取引を見る\",\n        \"failed_to_send\" : \"コインを送信できませんでした\",\n        \"password_required\" : \"ウォレットパスワードが必要です\",\n        \"invalid_address\" : \"無効なアドレス\",\n        \"script_failure\" : \"スクリプトの失敗\",\n        \"could_not_calculate_fee\" : \"料金を計算できませんでした\",\n        \"insufficient_funds\" : \"残高不足\",\n        \"sign_failed\" : \"トランザクションに署名できません。 パスワードを確認してください\",\n        \"send_failed\" : \"取引を送信できません。 詳細についてはdebug.logを確認してください\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"デバッグを有効にする\",\n        \"enable_debug_sub\" : \"マイナーのコンソール出力をデバッグログに含めます。ログをかなり大きくすることができます\",\n        \"auto_start\" : \"自動スタート\",\n        \"auto_start_sub\" : \"コンピュータにログインしたらワンクリックマイナーを起動する\",\n        \"closed_source\" : \"クローズドソースマイナーを使用する\",\n        \"closed_source_sub\" : \"ハッシュレートは向上していますが、開発者の費用がかかる未監査のマイナー\",\n        \"closed_source_warning\" : \"クローズドソースマイナーを使用することを選択しました。ヴァートコインはこれらのマイナーを支持しません。内容を監査することはできず、コンピュータに害を及ぼす機能が含まれている可能性があります。\",\n        \"save_n_restart\" : \"保存して再起動\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"ウォレット\",\n        \"send_coins\" : \"コインを送る\",\n        \"settings\" : \"設定\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"アップデート利用可能\",\n        \"tracking_enabled\" : \"利用統計を匿名で共有しています\",\n        \"disable_tracking\" : \"無効にする\",\n        \"tracking_disabled\" : \"利用統計を共有していません\",\n        \"enable_tracking\" : \"これらを有効にして利用体験の改善を行いさせるのを助けてください\",\n        \"report_issue\" : \"問題を報告する\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"新バージョン利用可能\",\n        \"download\" : \"ダウンロード\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/lt.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Bandyti iš naujo\",\n        \"back_to_wallet\" : \"Grįžti į piniginę\",\n        \"close\" : \"Uždaryti\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner jau yra paleistas. Jūs negalite jo paleisti daugiau nei vieną kartą.\",\n        \"click_button_to_start\" : \"Spauskite žemiau esantį mygtuką norint ir vėl pradėti kasimą.\",\n        \"startmining\" : \"Pradėti kasimą!\",\n        \"makeapassword\" : \"Sugalvokite OCM piniginės slaptažodį. Nepamirškite jo.\",\n        \"password\" : \"Slaptažodis\",\n        \"confirmpassword\" : \"Patvirtinti slaptažodį\",\n        \"password_cannot_be_empty\" : \"Slaptažodžio laukelis negali būti tuščias\",\n        \"password_mismatch\" : \"Slaptažodžiai nesutampa\",\n        \"error_initializing\" : \"Įvyko klaida inicijuojant piniginę\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Diegiami būtiniausi leidimai. Galite išvysti iššokantį langą prašantį leidimo (gali mirgsėti užduočių juostoje)\",\n        \"checks_failed\" : \"Patikros nepavyko\",\n        \"checking_mining_software\" : \"Tikrinama kasimui skirta programinė įranga...\",\n        \"rapidfail\" : \"Tikrinama ar nėra gedimų\",\n        \"compatibility\" : \"Tikrinamas vaizdo plokštės suderinamumas...\",\n        \"installing_miners\" : \"Įdiegiama kasimui skirta programinė įranga...\",\n        \"verthash\" : \"Tikrinamas / kuriamas Verthash duomenų failas...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Išleidžiamas balansas\",\n        \"still_maturing\" : \"vis dar bręsta\",\n        \"pending_pool_payout\" : \"laukiamas pool išmokėjimas\",\n        \"pending_payout_info_unavailable\" : \"Prašome palaukti laukiamo pool išmokėjimo informacijos\",\n        \"waiting_for_miners\" : \"Waiting for miners to start\",\n        \"expected_earnings_24h\" : \"Numatomas uždarbis (24h)\",\n        \"estimating\" : \"vertinama\",\n        \"stop_mining\" : \"Stabdyti kasimą\",\n        \"active_pool\" : \"Aktyvus pool\",\n        \"pool_fee\" : \"mokestis\",\n        \"copy_address\" : \"Kopijuoti jūsų piniginės adresą\",\n        \"payout_information\" : \"Peržiūrėti išmokėjimo informaciją\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Siųsti visas jūsų iškastas monetas į\",\n        \"youre_sending_x_to\" : \"Jūs siunčiate {receivedBalance} į\",\n        \"youre_sending_x_in_y_txs_to\" : \"Jūs siunčiate {receivedBalance} per {receivedTxCount} pervedimus į\",\n        \"receiver_address\" : \"Gavėjo adresas\",\n        \"wallet_password\" : \"OCM piniginės slaptažodis\",\n        \"send\" : \"Siųsti\",\n        \"coins_sent\" : \"Jūsų monetos išsiųstos!\",\n        \"view_trans_plural\" : \"Peržiūrėti pavedimus\",\n        \"view_trans_singular\" : \"Peržiūrėti pavedimą\",\n        \"failed_to_send\" : \"Monetų išsiuntimas nesėkmingas\",\n        \"password_required\" : \"Būtina nurodyti piniginės slaptažodį\",\n        \"invalid_address\" : \"Neteisingas adresas\",\n        \"script_failure\" : \"Script gedimas\",\n        \"could_not_calculate_fee\" : \"Negalime apskaičiuoti mokeščio\",\n        \"insufficient_funds\" : \"Nepakanka lėšų\",\n        \"sign_failed\" : \"Negalite patvirtinti pavedimo. Patikrinkite slaptažodį.\",\n        \"send_failed\" : \"Negalite išsiųsti pavedimo. Patikrinkite debug.log norint sužinoti daugiau\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Įgalinti derinimą\",\n        \"enable_debug_sub\" : \"Įtraukti kasimo programinės įrangos konsolės išvestį į derinimo žurnalą. Žurnalas gali užaugti gana didelis\",\n        \"auto_start\" : \"Automatinis paleidimas\",\n        \"auto_start_sub\" : \"Paleisti One-Click Miner kai tik prisijungiate prie kompiuterio\",\n        \"closed_source\" : \"Naudoti uždaro kodo programine įranga\",\n        \"closed_source_sub\" : \"Greitesnis kasimas, bet galimi papildomi kasimo mokeščiai\",\n        \"closed_source_warning\" : \"Jūs pasirinkote uždaro kodo programine įranga kasimui. Vertcoin neskatina ir nepalaiko tokios programinės įrangos. Ji negali būti patikrinta ir gali turėti kompiuteriui žalingų funkcijų.\",\n        \"enable_integrated\" : \"Kasti su integruota vaizdo plokšte\",\n        \"enable_integrated_sub\" : \"Kasimo programinė įranga naudos integruota vaizdo plokšte (jei įmanoma)\",\n        \"testnet\":\"Testnet režimas\",\n        \"testnet_sub\":\"Aktyvuoja testnet režimą, kuriame kasite netikras monetas.\",\n        \"skipverthashverify\":\"Paleidžiant netikrinti Verthash\",\n        \"skipverthashverify_sub\":\"Praleisite Verthash duomenų failo patikrinimą paleidžiant programą (nerekomenduojama)\",\n        \"save_n_restart\" : \"Išsaugoti ir perkrauti\",\n        \"pool\": \"Kasėjų pool\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Piniginė\",\n        \"send_coins\" : \"Siųsti monetas\",\n        \"settings\" : \"Nustatymai\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Galimas atnaujinimas\",\n        \"tracking_enabled\" : \"Jūs anonimiškai dalinaties naudojimosi statistika\",\n        \"disable_tracking\" : \"Išjungti\",\n        \"tracking_disabled\" : \"Jūs nesidalinate naudojimosi statistika\",\n        \"enable_tracking\" : \"Aktyvuokite naudojimosi statistika ir padėkite mums pagerinti jūsų patirtį\",\n        \"report_issue\" : \"Pranešti apie problemą\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Prieinama nauja versija\",\n        \"download\" : \"Atsiųsti\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/nl.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Opnieuw proberen\",\n        \"back_to_wallet\" : \"Terug naar portemonnee\",\n        \"close\" : \"Sluiten\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"De One-Click Miner is al actief. Je kunt 'm niet meer dan een keer draaien.\",\n        \"click_button_to_start\" : \"Klik op de knop om te beginnen met minen.\",\n        \"startmining\" : \"Begin met minen!\",\n        \"makeapassword\" : \"Kies een wachtwoord. Raak het niet kwijt.\",\n        \"password\" : \"Wachtwoord\",\n        \"confirmpassword\" : \"Bevestig Wachtwoord\",\n        \"password_cannot_be_empty\" : \"Wachtwoord mag niet leeg zijn\",\n        \"password_mismatch\" : \"Wachtwoorden komen niet overeen\",\n        \"error_initializing\" : \"Er ging iets mis met het initialiseren van de portemonnee\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Er wordt software geinstalleerd die nodig is voor de OCM. Je zou een pop-up kunnen krijgen die om toestemming vraagt (zou slechts in de taakbalk kunnen knipperen)\",\n        \"checks_failed\" : \"Controles mislukt\",\n        \"checking_mining_software\" : \"Miner software controleren...\",\n        \"rapidfail\" : \"Controleren op het voorkomen van herhaaldelijke fouten\",\n        \"compatibility\" : \"Compatibiliteit van grafische kaart controleren...\",\n        \"installing_miners\" : \"Miner software installeren...\",\n        \"verthash\" : \"Verifieren / creëren Verthash data file...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Besteedbaar saldo\",\n        \"still_maturing\" : \"In ontwikkeling\",\n        \"pending_pool_payout\" : \"saldo in afwachting bij mining-pool\",\n        \"waiting_for_miners\" : \"Wacht tot de miner software opstart\",\n        \"expected_earnings_24h\" : \"Verwachte inkomsten (24u)\",\n        \"estimating\" : \"berekenen\",\n        \"stop_mining\" : \"Stop minen\",\n        \"active_pool\" : \"Actieve pool\",\n        \"pool_fee\" : \"Vergoeding\",\n        \"copy_address\" : \"Kopieer je portemonnee adres\",\n        \"payout_information\" : \"Bekijk uitbetaling informatie\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Verstuur al je coins naar\",\n        \"youre_sending_x_to\" : \"Je gaat {receivedBalance} versturen naar\",\n        \"youre_sending_x_in_y_txs_to\" : \"Je gaat in {receivedTxCount} transacties {receivedBalance} versturen naar\",\n        \"receiver_address\" : \"Adres van ontvanger\",\n        \"wallet_password\" : \"Wachtwoord van je OCM portomonnee\",\n        \"send\" : \"Versturen\",\n        \"coins_sent\" : \"Je coins zijn verstuurd!\",\n        \"view_trans_plural\" : \"Bekijk transacties\",\n        \"view_trans_singular\" : \"Bekijk transactie\",\n        \"failed_to_send\" : \"Je coins versturen is mislukt\",\n        \"password_required\" : \"Wachtwoord van je portomonnee is verplicht\",\n        \"invalid_address\" : \"Ongeldig adres\",\n        \"script_failure\" : \"Scriptfout\",\n        \"could_not_calculate_fee\" : \"Kon transactiekosten niet berekenen\",\n        \"insufficient_funds\" : \"Onvoldoende saldo\",\n        \"sign_failed\" : \"Kon de transactie niet ondertekenen. Controleer het wachtwoord.\",\n        \"send_failed\" : \"Kon de transactie niet versturen. Controleer debug.log voor meer informatie\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Schakel foutopsporing in\",\n        \"enable_debug_sub\" : \"Hiermee wordt de uitvoer van de miner software in de debug.log opgenomen. Kan de log bestanden groot maken!\",\n        \"auto_start\" : \"Automatisch starten\",\n        \"auto_start_sub\" : \"Start de One-Click Miner als je inlogt op je computer\",\n        \"closed_source\" : \"Gebruik miners zonder open broncode\",\n        \"closed_source_sub\" : \"Betere prestaties, maar de software is niet gecontroleerd en je betaalt een percentage aan de ontwikkelaars\",\n        \"closed_source_warning\" : \"Je hebt ervoor gekozen om miners zonder open broncode te gebruiken. Vertcoin ondersteund deze miners niet en raad ze niet aan. De software kan niet op inhoud gecontroleerd worden en kan functies bevatten die je computer beschadigen.\",\n        \"enable_integrated\" : \"Minen op geïntegreerde graphics\",\n        \"enable_integrated_sub\" : \"De miner gebruikt de geïntegreerde graphics (indien mogelijk)\",\n        \"testnet\":\"Testnet modus\",\n        \"testnet_sub\":\"Schakelt testnet modus in. Je gaat geen echte coins minen.\",\n        \"skipverthashverify\":\"Verifieer Verthash niet bij opstarten\",\n        \"skipverthashverify_sub\":\"Zal het verifiëren van de bestandsintegriteit van Verthash-gegevens bij het opstarten overslaan (niet aanbevolen)\",\n        \"save_n_restart\" : \"Opslaan & Herstarten\",\n        \"pool\": \"Mining pool\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Portemonnee\",\n        \"send_coins\" : \"Verstuur coins\",\n        \"settings\" : \"Instellingen\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Update beschikbaar\",\n        \"tracking_enabled\" : \"Je deelt anonieme gebruiksstatistieken\",\n        \"disable_tracking\" : \"Schakel uit\",\n        \"tracking_disabled\" : \"Je deelt geen gebruiksstatistieken\",\n        \"enable_tracking\" : \"Schakel in om ons te helpen je gebruikservaring te verbeteren\",\n        \"report_issue\" : \"Meld een probleem\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Nieuwe versie beschikbaar\",\n        \"download\" : \"Downloaden\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/no.json",
    "content": "{\n  \"generic\": {\n    \"retry\": \"Prøv igjen\",\n    \"back_to_wallet\": \"tilbake til lommebok\",\n    \"close\": \"Lukk\"\n  },\n  \"welcome\": {\n    \"alreadyrunning\": \"One-Click Miner kjører allerede. Du kan ikke starte et nytt program mens det er et annet i gang.\",\n    \"click_button_to_start\": \"Klikk på knappen under for å gjenoppta utvinning.\",\n    \"startmining\": \"Start å utvinne!\",\n    \"makeapassword\": \"Lag et passord. Ikke mist det.\",\n    \"password\": \"Passord\",\n    \"confirmpassword\": \"Bekreft passord\",\n    \"password_cannot_be_empty\": \"Passord kan ikke stå tomt\",\n    \"password_mismatch\": \"Passordene er ikke identiske\",\n    \"error_initializing\": \"Noe feilet under initialiseringen av lommeboka\"\n  },\n  \"checks\": {\n    \"prerequisite\": \"Et nødvendig komponent installeres. Underveis kan du se et popup-vindu som spør om tillatelse (Det kan også bare blinke på oppgavelinjen)\",\n    \"checks_failed\": \"Kontrolleringen feilet\",\n    \"checking_mining_software\": \"Kontrollerer utvinnings-programmet...\",\n    \"rapidfail\": \"Sjekker for hyppige feil\",\n    \"compatibility\": \"Sjekker CPU kompatibilitet...\",\n    \"installing_miners\": \"Installerer utvinnings-programvare...\"\n  },\n  \"mining\": {\n    \"spendable_balance\": \"Tilgjengelig saldo\",\n    \"still_maturing\": \"Under modning\",\n    \"pending_pool_payout\": \"Avventende pool-utbetaling\",\n    \"waiting_for_miners\": \"Venter på at utvinnere starter\",\n    \"expected_earnings_24h\": \"Forventet gevinst (24t)\",\n    \"estimating\": \"Estimerer\",\n    \"stop_mining\": \"Stopp utvinning\"\n  },\n  \"sending\": {\n    \"send_all_to\": \"Send alle utvunnede kryptomynter til\",\n    \"youre_sending_x_to\": \"Du sender {beløp} til\",\n    \"youre_sending_x_in_y_txs_to\": \"Du sender {receivedBalance} i {receivedTxCount} transaksjon til\",\n    \"receiver_address\": \"Mottaksadresse\",\n    \"wallet_password\": \"Lommebokpassord\",\n    \"send\": \"Send\",\n    \"coins_sent\": \"Dine kryptomynter er sendt!\",\n    \"view_trans_plural\": \"Se transaksjoner\",\n    \"view_trans_singular\": \"Se transaksjon\",\n    \"failed_to_send\": \"Sending av kryptomynter mislyktes\",\n    \"password_required\": \"Passord for lommebok er påkrevd\",\n    \"invalid_address\": \"Ugyldig addresse\",\n    \"script_failure\": \"Script feilet\",\n    \"could_not_calculate_fee\": \"Kunne ikke regne ut beløp\",\n    \"insufficient_funds\": \"Ikke tilstrekkelige midler\",\n    \"sign_failed\" : \"Kan ikke signere transaksjonen. Sjekk passordet ditt\",\n    \"send_failed\": \"Kunne ikke gjennomføre transaksjonen. Sjekk debug.log for mer informasjon\"\n  },\n  \"settings\": {\n    \"enable_debug\": \"Aktiver debugging\",\n    \"enable_debug_sub\": \"Inkluder OCMs utdata i feilsøkingsloggen. Kan gjøre loggene en del større\",\n    \"auto_start\": \"Automatisk start\",\n    \"auto_start_sub\": \"Start One-Click Miner når du logger på maskinen\",\n    \"closed_source\": \"Bruk utvinningsprogramvare med stengt kildekode\",\n    \"closed_source_sub\": \"Bedre hashrate, men ukjente utvinnerprogramvareutvikleren kan ha en avgift for å utvinne\",\n    \"closed_source_warning\": \"Du har valgt å bruke utvinningsprogramvare(r) med lukket kildekode. Vertcoin støtter eller verifiserer ikke disse utvinnerne. Deres kildekode kan ikke verifiseres eller godkjennes, og de kan inneholde funksjoner som skader din datamaskin.\",\n    \"save_n_restart\": \"Lagre og start på nytt\"\n  },\n  \"tabbar\": {\n    \"wallet\": \"Lommebok\",\n    \"send_coins\": \"Send kryptomynter\",\n    \"settings\": \"Innstillinger\"\n  },\n  \"tracking\": {\n    \"update_available\": \"Oppdatering tilgjengelig\",\n    \"tracking_enabled\": \"Du deler brukerstatistikken anonymt\",\n    \"disable_tracking\": \"Deaktiver\",\n    \"tracking_disabled\": \"Du deler ikke brukerstatistikk\",\n    \"enable_tracking\": \"Aktiver tracking for å hjelpe oss å bedre din brukeropplevelse\",\n    \"report_issue\": \"Rapporter et problem\"\n  },\n  \"update\": {\n    \"new_version_available\": \"Ny versjon er tilgjengelig\",\n    \"download\": \"Last ned\"\n  }\n}"
  },
  {
    "path": "frontend/src/i18n/pa.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"ਦੁਬਾਰਾ  ਕੋਸ਼ਿਸ਼  ਕਰੋ\",\n        \"back_to_wallet\" : \"ਵਾਪਸ  ਬਟੂਆ  ਵੱਲ\",\n        \"close\" : \"ਨੇੜੇ\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"ਇਕ ਕਲਿਕ ਖੋਜਕਾਰ ਪਹਿਲਾਂ ਹੀ ਚੱਲ ਰਿਹਾ ਹੈ. ਤੁਸੀਂ ਇਸ ਨੂੰ ਇਕ ਤੋਂ ਵੱਧ ਵਾਰ ਨਹੀਂ ਚਲਾ ਸਕਦੇ.\",\n        \"click_button_to_start\" : \"ਦੁਬਾਰਾ ਮਾਈਨਿੰਗ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਹੇਠਾਂ ਦਿੱਤੇ ਬਟਨ ਤੇ ਕਲਿਕ ਕਰੋ.\",\n        \"startmining\" : \"ਮਾਈਨਿੰਗ ਸ਼ੁਰੂ ਕਰੋ\",\n        \"makeapassword\" : \"ਇੱਕ ਪਾਸਵਰਡ ਬਣਾਓ ਇਸ ਨੂੰ ਨਾ ਗੁਆਓ\",\n        \"password\" : \"ਪਾਸਵਰਡ\",\n        \"confirmpassword\" : \"ਪਾਸਵਰਡ ਪੱਕਾ ਕਰੋ\",\n        \"password_cannot_be_empty\" : \"ਪਾਸਵਰਡ ਖਾਲੀ ਨਹੀਂ ਹੋ ਸਕਦਾ\",\n        \"password_mismatch\" : \"ਪਾਸਵਰਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ\",\n        \"error_initializing\" : \"ਵਾਲਿਟ ਨੂੰ ਸ਼ੁਰੂ ਕਰਦਿਆਂ ਕੁਝ ਗਲਤ ਹੋਇਆ\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"ਇੱਕ ਜ਼ਰੂਰਤ ਲਗਾਈ ਜਾ ਰਹੀ ਹੈ. ਤੁਸੀਂ ਇਕ ਪੌਪ-ਅਪ ਨੂੰ ਅਨੁਮਤੀ ਮੰਗਦੇ ਹੋਏ ਵੇਖ ਸਕਦੇ ਹੋ (ਸਿਰਫ ਟਾਸਕਬਾਰ ਵਿਚ ਝਪਕਣਾ ਹੋ ਸਕਦਾ ਹੈ)\",\n        \"checks_failed\" : \"ਜਾਂਚ ਅਸਫਲ\",\n        \"checking_mining_software\" : \"ਮਾਈਨਿੰਗ ਸਾੱਫਟਵੇਅਰ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ\",\n        \"rapidfail\" : \"ਤੇਜ਼ੀ ਨਾਲ ਅਸਫਲ ਹੋਣ ਦੀਆਂ ਘਟਨਾਵਾਂ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ\",\n        \"compatibility\" : \"ਗ੍ਰਾਫਿਕਸ ਪ੍ਰੋਸੈਸਿੰਗ ਯੂਨਿਟ ਅਨੁਕੂਲਤਾ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ\",\n        \"installing_miners\" : \"ਮਾਈਨਿੰਗ ਸਾੱਫਟਵੇਅਰ ਸਥਾਪਤ ਕਰ ਰਿਹਾ ਹੈ...\",\n        \"verthash\" : \"ਪੁਸ਼ਟੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ / ਵਰਥਸ਼ ਫਾਈਲ ਬਣਾਉਣਾ\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"ਖਰਚ ਕਰਨ ਵਾਲਾ ਸੰਤੁਲਨ\",\n        \"still_maturing\" : \"ਅਜੇ ਵੀ  ਸਿਆਣਾ\",\n        \"pending_pool_payout\" : \"ਬਕਾਇਆ ਪੂਲ ਦਾ ਭੁਗਤਾਨ\",\n        \"pending_payout_info_unavailable\" : \"ਕਿਰਪਾ ਕਰਕੇ ਬਕਾਇਆ ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ ਦੀ ਉਡੀਕ ਕਰੋ\",\n        \"waiting_for_miners\" : \"ਸ਼ੁਰੂਆਤ ਕਰਨ ਲਈ ਖੋਜਕਾਰ ਦੀ ਉਡੀਕ\",\n        \"expected_earnings_24h\" : \"ਉਮੀਦ ਕੀਤੀ ਕਮਾਈ (ਚੋਵੀ ਘੰਟੇ)\",\n        \"estimating\" : \"ਅਨੁਮਾਨ ਲਗਾਉਣਾ\",\n        \"stop_mining\" : \"ਮਾਈਨਿੰਗ ਰੋਕੋ\",\n        \"active_pool\" : \"ਕਿਰਿਆਸ਼ੀਲ ਪੂਲ\",\n        \"pool_fee\" : \"ਕਰ\",\n        \"copy_address\" : \"ਆਪਣੇ ਵਾਲਿਟ ਪਤੇ ਨੂੰ ਕਾਪੀ ਕਰੋ\",\n        \"payout_information\" : \"ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ ਵੇਖੋ\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"ਆਪਣੇ ਸਾਰੇ ਮਾਈਨ ਕੀਤੇ ਸਿੱਕੇ ਭੇਜੋ\",\n        \"youre_sending_x_to\" : \"ਤੁਸੀਂ ਭੇਜ ਰਹੇ ਹੋ {receivedBalance} ਨੂੰ\",\n        \"youre_sending_x_in_y_txs_to\" : \"ਤੁਸੀਂ ਭੇਜ ਰਹੇ ਹੋ {receivedBalance} ਵਿੱਚ {receivedTxCount} ਨੂੰ ਲੈਣ-ਦੇਣ\",\n        \"receiver_address\" : \"ਪ੍ਰਾਪਤ ਕਰਨ ਵਾਲਾ ਪਤਾ\",\n        \"wallet_password\" : \"ਵਾਲਿਟ ਪਾਸਵਰਡ\",\n        \"send\" : \"ਭੇਜੋ\",\n        \"coins_sent\" : \"ਤੁਹਾਡੇ ਸਿੱਕੇ ਭੇਜੇ ਗਏ ਹਨ\",\n        \"view_trans_plural\" : \"ਲੈਣ-ਦੇਣ ਵੇਖੋ\",\n        \"view_trans_singular\" : \"ਲੈਣ-ਦੇਣ ਵੇਖੋ\",\n        \"failed_to_send\" : \"ਤੁਹਾਡੇ ਸਿੱਕੇ ਭੇਜਣ ਵਿੱਚ ਅਸਫਲ\",\n        \"password_required\" : \"ਵਾਲਿਟ ਦਾ ਪਾਸਵਰਡ ਲੋੜੀਂਦਾ ਹੈ\",\n        \"invalid_address\" : \"ਅਵੈਧ ਪਤਾ\",\n        \"script_failure\" : \"ਸਕ੍ਰਿਪਟ ਅਸਫਲ\",\n        \"could_not_calculate_fee\" : \"ਫੀਸ ਦੀ ਗਣਨਾ ਨਹੀਂ ਕਰ ਸਕਿਆ\",\n        \"insufficient_funds\" : \"ਨਾਕਾਫ਼ੀ ਫੰਡ\",\n        \"sign_failed\" : \"ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਤੇ ਦਸਤਖਤ ਕਰਨ ਵਿੱਚ ਅਸਮਰੱਥ. ਆਪਣੇ ਪਾਸਵਰਡ ਦੀ ਜਾਂਚ ਕਰੋ\",\n       \"send_failed\" : \"ਲੈਣਦੇਣ ਭੇਜਣ ਵਿੱਚ ਅਸਮਰੱਥ. ਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ ਡੀਬੱਗ.ਲੱਗ ਚੈੱਕ ਕਰੋ\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"ਡੀਬੱਗਿੰਗ ਡੀਬੱਗ\",\n        \"enable_debug_sub\" : \"ਡੀਬੱਗ ਲੌਗ ਵਿੱਚ ਖਨਕ ਦੀ ਕੰਸੋਲ ਆਉਟਪੁੱਟ ਸ਼ਾਮਲ ਕਰੋ. ਤੁਹਾਡੇ ਲੌਗਸ ਕਾਫ਼ੀ ਵੱਡੇ ਹੋ ਸਕਦੇ ਹਨ\",\n        \"auto_start\" : \"ਆਟੋ ਸਟਾਰਟt\",\n        \"auto_start_sub\" : \"ਜਦੋਂ ਤੁਸੀਂ ਆਪਣੇ ਕੰਪਿ inਟਰ ਤੇ ਲੌਗ ਇਨ ਕਰਦੇ ਹੋ ਤਾਂ ਵਨ-ਕਲਿਕ ਖਨਕ ਚਾਲੂ ਕਰੋ\",\n        \"closed_source\" : \"ਬੰਦ ਸਰੋਤ ਖੋਜਕਰਤਾ\",\n        \"closed_source_sub\" : \"ਬਿਹਤਰ ਹੈਸ਼ਰੇਟ, ਪਰ ਅਣਚਾਹੇ ਖਨਕ ਜੋ ਇੱਕ ਵਿਕਾਸਕਰਤਾ ਦੀ ਫੀਸ ਲੈਂਦੇ ਹਨ\",\n        \"closed_source_warning\" : \"ਤੁਸੀਂ ਬੰਦ ਸਰੋਤ ਖਨਕ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਚੋਣ ਕੀਤੀ ਹੈ. ਵਰਟਕੋਇਨ ਇਨ੍ਹਾਂ ਮਾਈਨਰਾਂ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਦਿੰਦਾ. ਉਨ੍ਹਾਂ ਦੀ ਸਮਗਰੀ 'ਤੇ ਆਡਿਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਅਤੇ ਦੇ ਫੰਕਸ਼ਨ ਹੋ ਸਕਦੇ ਹਨ ਜੋ ਤੁਹਾਡੇ ਕੰਪਿcਟਰ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚਾ ਸਕਦੇ ਹਨ\",\n        \"enable_integrated\" : \"ਏਕੀਕ੍ਰਿਤ ਗਰਾਫਿਕਸ 'ਤੇ ਮੇਰਾ\",\n        \"enable_integrated_sub\" : \"ਖਨਕ ਆਨਬੋਰਡ ਗ੍ਰਾਫਿਕਸ ਦੀ ਵਰਤੋਂ ਕਰੇਗਾ (ਜੇ ਮੁਮਕਿਨ)\",\n        \"testnet\":\"ਟੈਸਟਨੈੱਟ ਮੋਡ\",\n        \"testnet_sub\":\"ਟੈਸਟਨੈੱਟ ਮੋਡ ਨੂੰ ਸਮਰੱਥ ਬਣਾਉਂਦਾ ਹੈ. ਤੁਸੀਂ ਅਸਲੀ ਸਿੱਕਿਆਂ ਦੀ ਖੁਦਾਈ ਨਹੀਂ ਕਰੋਗੇ.\",\n        \"skipverthashverify\":\"ਪੁਸ਼ਟੀ ਨਾ ਕਰੋ ਵਰਥਸ਼ ਸ਼ੁਰੂ 'ਤੇ\",\n        \"skipverthashverify_sub\":\"ਦੀ ਫਾਈਲ ਇਕਸਾਰਤਾ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨਾ ਛੱਡ ਦਿੱਤਾ ਜਾਵੇਗਾ ਵਰਥਸ਼ ਸ਼ੁਰੂਆਤ 'ਤੇ ਡਾਟਾ (ਦੀ ਸਿਫਾਰਸ਼ ਨਹੀਂ ਕੀਤੀ ਜਾਂਦੀ)\",\n        \"save_n_restart\" : \"ਸੇਵ ਅਤੇ ਰੀਸਟਾਰਟ\",\n        \"pool\": \"ਮਾਈਨਿੰਗ ਪੂਲ\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"ਬਟੂਆ\",\n        \"send_coins\" : \"ਸਿੱਕੇ ਭੇਜੋ\",\n        \"settings\" : \"ਸੈਟਿੰਗਜ਼\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"ਅਪਡੇਟ ਉਪਲਬਧ ਹੈ\",\n        \"tracking_enabled\" : \"ਤੁਸੀਂ ਅਗਿਆਤ ਤੌਰ ਤੇ ਵਰਤੋਂ ਦੇ ਅੰਕੜੇ ਸਾਂਝੇ ਕਰ ਰਹੇ ਹੋ\",\n        \"disable_tracking\" : \"ਅਯੋਗ\",\n        \"tracking_disabled\" : \"ਤੁਸੀਂ ਵਰਤੋਂ ਦੇ ਅੰਕੜਿਆਂ ਨੂੰ ਸਾਂਝਾ ਨਹੀਂ ਕਰ ਰਹੇ\",\n        \"enable_tracking\" : \"ਆਪਣੇ ਤਜ਼ਰਬੇ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿਚ ਸਾਡੀ ਸਹਾਇਤਾ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਨੂੰ ਸਮਰੱਥ ਕਰੋ\",\n        \"report_issue\" : \"ਇੱਕ ਮੁੱਦੇ ਦੀ ਰਿਪੋਰਟ ਕਰੋ\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"ਨਵਾਂ ਵਰਜਨ ਉਪਲਬਧ ਹੈ\",\n        \"download\" : \"ਡਾ .ਨਲੋਡ\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/pl.json",
    "content": "﻿{\r\n    \"generic\" : {\r\n        \"retry\" : \"Ponów\",\r\n        \"back_to_wallet\" : \"Wróć do portfela\",\r\n        \"close\" : \"Zamknij\"\r\n    },\r\n    \"welcome\" : {\r\n        \"alreadyrunning\" : \"One-Click Miner jest już uruchomiony. Nie możesz uruchomić kolejnego.\",\r\n        \"click_button_to_start\" : \"Naciśnij przycisk poniżej, aby rozpocząć kopanie.\",\r\n        \"startmining\" : \"Start kopania!\",\r\n        \"makeapassword\" : \"Utwórz hasło. Nie zapomnij go.\",\r\n        \"password\" : \"Hasło\",\r\n        \"confirmpassword\" : \"Potwierdź hasło\",\r\n        \"password_cannot_be_empty\" : \"Hasło nie może być puste\",\r\n        \"password_mismatch\" : \"Hasła nie pasują do siebie\",\r\n        \"error_initializing\" : \"Coś poszło nie tak podczas inicjalizacji portfela\"\r\n    },\r\n    \"checks\" : {\r\n        \"prerequisite\" : \"Instalowanie dodatków. Może pojawić się prośba o nadanie uprawnień (podświetlona na pasku zadań)\",\r\n        \"checks_failed\" : \"Sprawdzenie zakończyło się niepowodzeniem\",\r\n        \"checking_mining_software\" : \"Sprawdzanie oprogramowania do kopania...\",\r\n        \"rapidfail\" : \"Sprawdzanie komunikatów o błędach\",\r\n        \"compatibility\" : \"Sprawdzanie kompatybilności karty graficznej...\",\r\n        \"installing_miners\" : \"Instalowanie oprogramowania...\",\r\n        \"verthash\" : \"Weryfikowanie / Tworzenie pliku danych Verthash...\"\r\n    },\r\n    \"mining\" : {\r\n        \"spendable_balance\" : \"Kwota do wydania\",\r\n        \"still_maturing\" : \"nadal dojrzewa\",\r\n        \"pending_pool_payout\" : \"wypłata w trakcie\",\r\n        \"pending_payout_info_unavailable\" : \"Poczekaj na informacje o oczekujących wypłatach\",\r\n        \"waiting_for_miners\" : \"Oczekiwanie na uruchomienie kopania\",\r\n        \"expected_earnings_24h\" : \"Oczekiwany dochód (24h)\",\r\n        \"estimating\" : \"około\",\r\n        \"stop_mining\" : \"Zatrzymaj kopanie\",\r\n        \"active_pool\" : \"Aktywna kopalnia\",\r\n        \"pool_fee\" : \"Prowizja\",\r\n        \"copy_address\" : \"Kopiuj adres swojego portfela\"\r\n    },\r\n    \"sending\" : {\r\n        \"send_all_to\" : \"Wyślij wszystkie monety do\",\r\n        \"youre_sending_x_to\" : \"Wysyłasz {receivedBalance} do\",\r\n        \"youre_sending_x_in_y_txs_to\" : \"Wysyłasz {receivedBalance} w {receivedTxCount} transakcjach do\",\r\n        \"receiver_address\" : \"Adres odbiorcy\",\r\n        \"wallet_password\" : \"Hasło portfela\",\r\n        \"send\" : \"Wyślij\",\r\n        \"coins_sent\" : \"Monety wysłane!\",\r\n        \"view_trans_plural\" : \"Zobacz transakcje\",\r\n        \"view_trans_singular\" : \"Zobacz transakcję\",\r\n        \"failed_to_send\" : \"Wysyłka monet nieudana\",\r\n        \"password_required\" : \"Podaj hasło do portfela\",\r\n        \"invalid_address\" : \"Błędny adres\",\r\n        \"script_failure\" : \"Błąd skryptu\",\r\n        \"could_not_calculate_fee\" : \"Obliczenie prowizji nie powiodło się\",\r\n        \"insufficient_funds\" : \"Za mało środków\",\r\n        \"sign_failed\" : \"Nie można podpisać transakcji. Sprawdź swoje hasło.\",\r\n        \"send_failed\" : \"Wysyłka nieudana. Więcej informacji w pliku debug.log\"\r\n    },\r\n    \"settings\" : {\r\n        \"enable_debug\" : \"Włącz debugging\",\r\n        \"enable_debug_sub\" : \"Dołącz komunikaty z kopania do pliku debug.log. Plik może zrobić się duży\",\r\n        \"auto_start\" : \"Automatyczne uruchamianie\",\r\n        \"auto_start_sub\" : \"Uruchom One-Click Miner kiedy uruchamiasz komputer\",\r\n        \"closed_source\" : \"Używaj górników typu closed-source\",\r\n        \"closed_source_sub\" : \"Większa wydajność, ale oprogramowanie może pobierać dodatkową opłatę dla jego autora\",\r\n        \"closed_source_warning\" : \"Zaznaczyłeś używanie górników typu closed-source. Vertcoin nie popiera i nie wspiera tych górników. Ich kod źródłowy nie jest publicznie dostępny i nie można sprawdzić, czy nie zawierają szkodliwego oprogramowania.\",\r\n        \"enable_integrated\" : \"Kop na zintegrowanych kartach graficznych\",\r\n        \"enable_integrated_sub\" : \"Zintegrowane karty graficzne będą wykorzystywane do kopania (jeśli możliwe)\",\r\n        \"testnet\" : \"Tryb Testnet\",\r\n        \"testnet_sub\" : \"Włącza tryb Testnet. Nie będziesz kopał prawdziwych monet.\",\r\n        \"skipverthashverify\" : \"Nie weryfikuj Verthash podczas uruchamiania\",\r\n        \"skipverthashverify_sub\" : \"Weryfikacja integralności pliku verthash.dat podczas uruchamiania zostanie pominięta (niezalecane)\",\r\n        \"save_n_restart\" : \"Zapisz i Wznów\",\r\n        \"pool\" : \"Kopalnia\"\r\n    },\r\n    \"tabbar\" : {\r\n        \"wallet\" : \"Portfel\",\r\n        \"send_coins\" : \"Wyślij monety\",\r\n        \"settings\" : \"Ustawienia\"\r\n    },\r\n    \"tracking\": { \r\n        \"update_available\" : \"Dostępne uaktualnienie\",\r\n        \"tracking_enabled\" : \"Udostępnianie statystyk włączone\",\r\n        \"disable_tracking\" : \"Wyłącz\",\r\n        \"tracking_disabled\" : \"Udostępnianie statystyk wyłączone\",\r\n        \"enable_tracking\" : \"Włącz statystyki, by pomóc nam w rozwoju programu\",\r\n        \"report_issue\" : \"Zgłoś problem z programem\"\r\n    },\r\n    \"update\" : {\r\n        \"new_version_available\" : \"Dostępna nowa wersja\",\r\n        \"download\" : \"Pobierz\"\r\n    }\r\n}\r\n"
  },
  {
    "path": "frontend/src/i18n/pt.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Tentar novamente\",\n        \"back_to_wallet\" : \"Regressar à carteira\",\n        \"close\" : \"Fechar\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"O One-Click Miner já está em execução. Não pode executá-lo mais do que uma vez.\",\n        \"click_button_to_start\" : \"Clique no botão abaixo para iniciar a mineração novamente.\",\n        \"startmining\" : \"Começar a Minar!\",\n        \"makeapassword\" : \"Faça uma palavra-passe para a Carteira do OCM. Não a perca!\",\n        \"password\" : \"Palavra-passe\",\n        \"confirmpassword\" : \"Confirme a palavra-passe\",\n        \"password_cannot_be_empty\" : \"É necessário inserir uma palavra-passe\",\n        \"password_mismatch\" : \"As palavras-passe não coincidem\",\n        \"error_initializing\" : \"Houve um erro ao iniciar a carteira\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Os pré-requisitos estão a ser instalados. Podem haver popups a pedir permissões (poderá ser um icon a piscar na barra de trefas)\",\n        \"checks_failed\" : \"As verificações falharam\",\n        \"checking_mining_software\" : \"A verificar o sfotware de mineração...\",\n        \"rapidfail\" : \"A verificar ocorrências de falhas rápidas\",\n        \"compatibility\" : \"A verificar a compatibilidade da GPU...\",\n        \"installing_miners\" : \"A instalar o software de mineração...\",\n        \"verthash\" : \"A verificar / criar o ficheiro de dados do Verthash...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Quantia disponível\",\n        \"still_maturing\" : \"aguarda confirmações\",\n        \"pending_pool_payout\" : \"pagamento pela pool pendente\",\n        \"pending_payout_info_unavailable\" : \"Espere pela informação sobre os pagamentos pendentes\",\n        \"waiting_for_miners\" : \"Esperando pela inicialização dos mineiros\",\n        \"expected_earnings_24h\" : \"Ganhos Esperados (24h)\",\n        \"estimating\" : \"a estimar\",\n        \"stop_mining\" : \"Parar de Minar\",\n        \"active_pool\" : \"Pool ativa\",\n        \"pool_fee\" : \"taxa\",\n        \"copy_address\" : \"Copiar o endereço da sua carteira\",\n        \"payout_information\" : \"Ver informação do pagamento\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Envie todas as suas moedas minadas para\",\n        \"youre_sending_x_to\" : \"Está a enviar {receivedBalance} para\",\n        \"youre_sending_x_in_y_txs_to\" : \"Está a enviar {receivedBalance} em {receivedTxCount} transações para\",\n        \"receiver_address\" : \"Endereço do Destinatário\",\n        \"wallet_password\" : \"Palavra-passe da Carteira do OCM\",\n        \"send\" : \"Enviar\",\n        \"coins_sent\" : \"As suas moedas foram enviadas!\",\n        \"view_trans_plural\" : \"Ver transações\",\n        \"view_trans_singular\" : \"Ver transação\",\n        \"failed_to_send\" : \"Ocorreu um erro ao tentar enviar as suas moedas\",\n        \"password_required\" : \"A palavra-passe da carteira é necessária\",\n        \"invalid_address\" : \"Endereço inválido\",\n        \"script_failure\" : \"Erro no script\",\n        \"could_not_calculate_fee\" : \"Não foi possível calcular a taxa\",\n        \"insufficient_funds\" : \"Montante disponível insuficiente\",\n        \"sign_failed\" : \"Não foi possível assinar a transação. Verifique sua palavra-passe\",\n        \"send_failed\" : \"Não foi possível efetuar a transação. Veja o debug.log para mais informações.\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Ativar o debugging\",\n        \"enable_debug_sub\" : \"Incluir o output da consola dos mineiros no debug.log. Isto pode aumentar bastante o tamanho dos logs\",\n        \"auto_start\" : \"Iniciar automaticamente\",\n        \"auto_start_sub\" : \"Iniciar o One-Click Miner ao iniciar sessão no computador\",\n        \"closed_source\" : \"Utilizar mineiros que são closed-source\",\n        \"closed_source_sub\" : \"Têm melhor hashrate, mas são mineiros não examinados e têm taxas de utilização\",\n        \"closed_source_warning\" : \"Selecionou a utilização de mineiros closed-source. O Vertcoin não apoia ou suporta estes mineiros. O seu conteúdo não pode ser verificado e, por isso, podem conter funções que podem afetar o seu computador.\",\n        \"enable_integrated\" : \"Minerar na placa gráfica integrada\",\n        \"enable_integrated_sub\" : \"O minerador usará a placa gráfica integrada (se possível)\",\n        \"testnet\":\"Modo de teste de rede\",\n        \"testnet_sub\":\"Ativar modo de teste de rede. Você não estará minerando moedas reais.\",\n        \"skipverthashverify\":\"Não verificar o Verthash na inicialização\",\n        \"skipverthashverify_sub\":\"Irá pular a verificação da integridade do arquivo dos dados do Verthash na inicialização (não recomendado)\",\n        \"save_n_restart\" : \"Gravar & Reiniciar\",\n        \"pool\": \"Pool de Mineração\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Carteira\",\n        \"send_coins\" : \"Enviar moedas\",\n        \"settings\" : \"Configurações\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Atualização disponível\",\n        \"tracking_enabled\" : \"Está a partilhar estatísticas de utilização anonimamente\",\n        \"disable_tracking\" : \"Desativar\",\n        \"tracking_disabled\" : \"Não está a partilhar estatísticas de mineração\",\n        \"enable_tracking\" : \"Ative-as para que possamos melhorar a sua experiência\",\n        \"report_issue\" : \"Reportar um problema\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Nova versão disponível\",\n        \"download\" : \"Descarregar\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/ro.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Încearcă din nou\",\n        \"back_to_wallet\" : \"Înapoi la portofel\",\n        \"close\" : \"Închide\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"Minerul One-Click este deja pornit. Poți să îl pornești doar o singură dată.\",\n        \"click_button_to_start\" : \"Apasă pe butonul de mai jos pentru a reîncepe să minezi.\",\n        \"startmining\" : \"Începe să minezi!\",\n        \"makeapassword\" : \"Creează o parolă. Nu o pierde.\",\n        \"password\" : \"Parolă\",\n        \"confirmpassword\" : \"Confirmă parola\",\n        \"password_cannot_be_empty\" : \"Câmpul Parolă nu poate fi gol\",\n        \"password_mismatch\" : \"Parolele trebuie să fie identice\",\n        \"error_initializing\" : \"A apărut o eroare la inițializarea portofelului.\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Se instalează un pachet software necesar. Este posibil să apară o fereastră care cere permisiuni (verifică dacă îți clipește în bara de activități)\",\n        \"checks_failed\" : \"Verificări eșuate\",\n        \"checking_mining_software\" : \"Se verifică software-ul de minare...\",\n        \"rapidfail\" : \"Se verifică dacă există erori rapide (i.e. programul se oprește imediat după ce a pornit)\",\n        \"compatibility\" : \"Se verifică compatibilitatea cu placa grafică...\",\n        \"installing_miners\" : \"Se instalează software-ul de minare...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Balanță disponibilă\",\n        \"still_maturing\" : \"în curs de maturizare\",\n        \"pending_pool_payout\" : \"plată de la pool în curs de efectuare\",\n        \"waiting_for_miners\" : \"Se așteaptă pornirea minerilor\",\n        \"expected_earnings_24h\" : \"Câștiguri așteptate (24h)\",\n        \"estimating\" : \"se estimează\",\n        \"stop_mining\" : \"Oprește minarea\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Trimite toate monedele minate către\",\n        \"youre_sending_x_to\" : \"Vei trimite {receivedBalance} către\",\n        \"youre_sending_x_in_y_txs_to\" : \"Vei trimite {receivedBalance} în {receivedTxCount} tranzacții către\",\n        \"receiver_address\" : \"Adresa destinatarului\",\n        \"wallet_password\" : \"Parola portofelului\",\n        \"send\" : \"Trimite\",\n        \"coins_sent\" : \"Monedele au fost trimise!\",\n        \"view_trans_plural\" : \"Vizualizare tranzacții\",\n        \"view_trans_singular\" : \"Vizualizare tranzacție\",\n        \"failed_to_send\" : \"Monedele nu au putut fi trimise!\",\n        \"password_required\" : \"Trebuie să introduci parola portofelului\",\n        \"invalid_address\" : \"Adresă invalidă\",\n        \"script_failure\" : \"Eroare de script\",\n        \"could_not_calculate_fee\" : \"Taxa pe tranzacție nu a putut fi calculată\",\n        \"insufficient_funds\" : \"Fonduri insuficiente\",\n        \"sign_failed\":\"Imposibil de semnat tranzacția. Verificați parola\",\n        \"send_failed\" : \"Nu se poate trimite tranzacția. Verifică fișierul debug.log pentru informații suplimentare\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Activează depanarea\",\n        \"enable_debug_sub\" : \"Include textul din consola minerului în logul de depanare. Aceast lucru poate duce la o creștere semnificativă a dimensiunii logurilor\",\n        \"auto_start\" : \"Pornire automată\",\n        \"auto_start_sub\" : \"Pornește Minerul One-Click când te loghezi pe calculator\",\n        \"closed_source\" : \"Folosește mineri closed-source\",\n        \"closed_source_sub\" : \"Au hashrate mai bun, dar sunt mineri neauditați care trimit o taxă către dezvoltator\",\n        \"closed_source_warning\" : \"Ai ales să folosești mineri closed-source. Vertcoin nu este afiliat cu acești mineri și nu oferă suport pentru ei. Conținutul lor nu poate fi auditat și ar putea include funcționalități dăunătoare pentru calculatorul tău.\",\n        \"save_n_restart\" : \"Salvează și repornește\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Portofel\",\n        \"send_coins\" : \"Trimite monede\",\n        \"settings\" : \"Setări\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Actualizare disponibilă\",\n        \"tracking_enabled\" : \"Împărtășești statistici de utilizare în mod anonim\",\n        \"disable_tracking\" : \"Dezactivează\",\n        \"tracking_disabled\" : \"Nu împărtășești statistici de utilizare\",\n        \"enable_tracking\" : \"Activează această setare pentru a ne ajuta să îți oferim o experiență mai bună\",\n        \"report_issue\" : \"Raportează o problemă\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"O nouă versiune este disponibilă\",\n        \"download\" : \"Descarcă\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/ru.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Попробовать снова\",\n        \"back_to_wallet\" : \"Вернуться в кошелёк\",\n        \"close\" : \"Закрыть\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner уже запущен. Вы не можете запустить его более одного раза.\",\n        \"click_button_to_start\" : \"Нажмите кнопку ниже, чтобы начать майнинг снова.\",\n        \"startmining\" : \"Начать майнинг!\",\n        \"makeapassword\" : \"Создайте пароль. Не потеряйте его!\",\n        \"password\" : \"Пароль\",\n        \"confirmpassword\" : \"Подтвердите пароль\",\n        \"password_cannot_be_empty\" : \"Пароль не может быть пустым\",\n        \"password_mismatch\" : \"Пароли не совпадают\",\n        \"error_initializing\" : \"Что-то пошло не так при инициализации кошелька\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Компоненты устанавливаются. Вы можете увидеть всплывающее окно с запросом разрешений (оно может просто мигать на панели задач)\",\n        \"checks_failed\" : \"Сбой при проверке\",\n        \"checking_mining_software\" : \"Проверка майнеров...\",\n        \"rapidfail\" : \"Проверка случаев быстрой неисправности\",\n        \"compatibility\" : \"Проверка совместимости GPU...\",\n        \"installing_miners\" : \"Установка майнеров...\",\n        \"verthash\" : \"Проверка / создание файла данных Verthash ...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Доступный баланс\",\n        \"still_maturing\" : \"Ожидает подтверждений\",\n        \"pending_pool_payout\" : \"Ожидание выплаты с пула\",\n        \"pending_payout_info_unavailable\" : \"Дождитесь информации об ожидающих выплатах\",\n        \"waiting_for_miners\" : \"Ждем майнеры для старта\",\n        \"expected_earnings_24h\" : \"Ожидаемый доход (24Ч)\",\n        \"estimating\" : \"идет расчет\",\n        \"stop_mining\" : \"Закончить майнинг\",\n        \"active_pool\" : \"Активный пул\",\n        \"pool_fee\" : \"комиссия\",\n        \"copy_address\" : \"Скопировать адрес кошелька\",\n        \"payout_information\" : \"Посмотреть информацию о выплатах\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Отправить всю криптовалюту на\",\n        \"youre_sending_x_to\" : \"Вы отправляете {receivedBalance} на\",\n        \"youre_sending_x_in_y_txs_to\" : \"Вы отправляете {receivedBalance} в {receivedTxCount} транзакции на\",\n        \"receiver_address\" : \"Адрес получателя\",\n        \"wallet_password\" : \"Пароль от кошелька\",\n        \"send\" : \"Отправить\",\n        \"coins_sent\" : \"Криптовалюта отправлена!\",\n        \"view_trans_plural\" : \"Просмотр транзакций\",\n        \"view_trans_singular\" : \"Просмотр транзакции\",\n        \"failed_to_send\" : \"Не удалось отправить криптовалюту\",\n        \"password_required\" : \"Необходим пароль от кошелёка\",\n        \"invalid_address\" : \"Неправильный адрес\",\n        \"script_failure\" : \"Ошибка скрипта\",\n        \"could_not_calculate_fee\" : \"Не удалось рассчитать комиссию\",\n        \"insufficient_funds\" : \"Недостаточно средств\",\n        \"sign_failed\" : \"Невозможно подписать транзакцию. Проверьте пароль.\",\n        \"send_failed\" : \"Невозможно отправить транзакцию. Проверьте debug.log для получения дополнительной информации\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Включить отладку\",\n        \"enable_debug_sub\" : \"Включите вывод из консоли майнера в журнал отладки. Может значительно увеличить размер файла журнала\",\n        \"auto_start\" : \"Авто Старт\",\n        \"auto_start_sub\" : \"Запускать One-Click Miner при загрузке компьютера\",\n        \"closed_source\" : \"Использовать проприетарные майнеры\",\n        \"closed_source_sub\" : \"Лучший хэшрейт, но некоторые майнеры могут взымать комиссию разработчикам\",\n        \"closed_source_warning\" : \"Вы решили использовать проприетарные майнеры. Vertcoin не оказывает поддержку этих майнеров. Их содержание не может быть проверено и может включать функции, которые повреждают ваш компьютер.\",\n        \"enable_integrated\" : \"Майнить на встроенной видеокарте\",\n        \"enable_integrated_sub\" : \"Майнер будет использовать встроенную видеокарту (если возможно)\",\n        \"testnet\" : \"Режим тестовой сети\",\n        \"testnet_sub\" : \"Включен режим тестовой сети. Вы не получите реальную криптовалюту.\",\n        \"skipverthashverify\" : \"Не проверять файл данных Verthash при запуске\",\n        \"skipverthashverify_sub\" : \"Пропустить проверку целостности файла Verthash.dat при запуске (не рекомендуется)\",\n        \"save_n_restart\" : \"Сохранить и перезапустить\",\n        \"pool\": \"Пул для майнинга\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Кошелёк\",\n        \"send_coins\" : \"Отправить криптовалюту\",\n        \"settings\" : \"Настройки\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Доступно обновление\",\n        \"tracking_enabled\" : \"Вы анонимно делитесь статистикой использования майнера\",\n        \"disable_tracking\" : \"Запретить\",\n        \"tracking_disabled\" : \"Вы не делитесь статистикой использования майнера\",\n        \"enable_tracking\" : \"Включить эту опцию, чтобы помочь нам улучшить майнер\",\n        \"report_issue\" : \"Сообщить о проблеме\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Доступна новая версия\",\n        \"download\" : \"Скачать\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/sl.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Poskusi znova\",\n        \"back_to_wallet\" : \"Nazaj v denarnico\",\n        \"close\":\"Zapri\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"One-Click Miner že teče. Ne morete ga zagnati več kot enkrat.\",\n        \"click_button_to_start\" : \"Za ponoven začetek rudarjenja pritisni spodnji gumb.\",\n        \"startmining\" : \"Začni rudariti!\",\n        \"makeapassword\" : \"Ustvari geslo. Ne izgubi ga!\",\n        \"password\" : \"Geslo\",\n        \"confirmpassword\" : \"Potrdi geslo\",\n        \"password_cannot_be_empty\" : \"Polje geslo ne sme biti prazno\",\n        \"password_mismatch\" : \"Geslo se ne ujema\",\n        \"error_initializing\" : \"Napaka pri nalaganju denarnice\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Nameščanje predpogojnih datotek. Morda boste videli pojavno okno, ki zahteva dovoljenja (lahko samo utripa v opravilni vrstici)\",\n        \"checks_failed\" : \"Preverjanje neuspešno\",\n        \"checking_mining_software\" : \"Preverjanje programske opreme za rudarstvo ...\",\n        \"rapidfail\" : \"Preverjanje hitrih okvar\",\n        \"compatibility\" : \"Preverjanje združljivosti grafične kartice ...\",\n        \"installing_miners\" : \"Nameščanje rudarske programske opreme ...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Razpoložljivi znesek\",\n        \"still_maturing\" : \"v fazi zorenja\",\n        \"pending_pool_payout\" : \"čakajoče pool izplačilo\",\n        \"waiting_for_miners\" : \"Čakanje na rudarsko programsko opremo za začetek dela\",\n        \"expected_earnings_24h\" : \"Pričakovani zaslužek (24h)\",\n        \"estimating\" : \"ocenjevanje\",\n        \"stop_mining\" : \"Prekini rudarjenje\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Pošlji vse izrudarjene kovance na\",\n        \"youre_sending_x_to\" : \"Pošiljaš {receivedBalance} na\",\n        \"youre_sending_x_in_y_txs_to\" : \"Pošiljaš {receivedBalance} v {receivedTxCount} transakcij na\",\n        \"receiver_address\" : \"Naslov prejemnika\",\n        \"wallet_password\" : \"Geslo denarnice\",\n        \"send\" : \"Pošlji\",\n        \"coins_sent\" : \"Kovanci so poslani!\",\n        \"view_trans_plural\" : \"Ogled transakcij\",\n        \"view_trans_singular\" : \"Ogled transakcije\",\n        \"failed_to_send\" : \"Kovancev ni bilo mogoče poslati\",\n        \"password_required\" : \"Potrebno je geslo za denarnico\",\n        \"invalid_address\" : \"Napačen naslov\",\n        \"script_failure\" : \"Napaka skripte\",\n        \"could_not_calculate_fee\" : \"Ni bilo mogoče izračunati pristojbine\",\n        \"insufficient_funds\" : \"Nezadostna sredstva\",\n        \"sign_failed\":\"Transakcije ni mogoče podpisati. Preverite geslo\",\n        \"send_failed\" : \"Transakcije ni bilo mogoče poslati. Poglej debug.log za več informacij\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Omogoči iskanje napak\",\n        \"enable_debug_sub\" : \"Omogoči izvoz dnevnikov konzol rudarske programske opreme v dnevnik za odstranjevanje hroščev. Velikost dnevnika se lahko znatno poveča\",\n        \"auto_start\" : \"Samodejni zagon\",\n        \"auto_start_sub\" : \"Zaženi One-Click Miner, ko se prijaviš v računalnik.\",\n        \"closed_source\" : \"Uporabi zaprto programsko opremo za rudarstvo\",\n        \"closed_source_sub\" : \"Boljši hashrate, vendar neocenjena programska opema, ki lahko vključuje pristojbino za razvojne inženirje\",\n        \"closed_source_warning\" : \"Izbrali ste zaprto programsko opremo za rudarstvo. Vertcoin ne odobrava ali podpira njihovo uporabo. Ne more se preveriti njihovo vsebino tako, da lahko potencijalno vsebuje funkcije, ki lahko poškoduje vaš računalnik.\",\n        \"save_n_restart\" : \"Shrani & Znova zaženi\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Denarnica\",\n        \"send_coins\" : \"Pošlji kovance\",\n        \"settings\" : \"Nastavitve\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Posodobitev je na voljo\",\n        \"tracking_enabled\" : \"Anonimno izmenjujete statistične podatke o uporabi\",\n        \"disable_tracking\" : \"Onemogoči\",\n        \"tracking_disabled\" : \"Ne delite statistike o uporabi\",\n        \"enable_tracking\" : \"Omogočite jih, da bi nam pomagali izboljšati vaše izkušnje\",\n        \"report_issue\" : \"Prijavite težavo\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Na voljo je nova različica\",\n        \"download\" : \"Prenos\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/sv.json",
    "content": "{\n  \"generic\": {\n    \"retry\": \"Försök igen\",\n    \"back_to_wallet\": \"Tillbaka till plånboken\",\n    \"close\": \"Stäng\"\n  },\n  \"welcome\": {\n    \"alreadyrunning\": \"One-Click Miner har redan startats. Du kan bara köra en instans åt gången.\",\n    \"click_button_to_start\": \"Klicka på knappen nedan för att börja mina igen.\",\n    \"startmining\": \"Börja Mina!\",\n    \"makeapassword\": \"Skapa ett lösenord. Tappa inte bort det.\",\n    \"password\": \"Lösenord\",\n    \"confirmpassword\": \"Bekräfta lösenord\",\n    \"password_cannot_be_empty\": \"Du måste ange ett lösenord\",\n    \"password_mismatch\": \"Lösenorden matchar inte\",\n    \"error_initializing\": \"Något gick fel under initialisering av plånboken\"\n  },\n  \"checks\": {\n    \"prerequisite\": \"Mjukvara som krävs av One-Click Miner installeras. Du kanske kommer se en popup som ber om behörigheter (kanske bara blinkar i aktivitetsfältet)\",\n    \"checks_failed\": \"Kontrollerna misslyckades\",\n    \"checking_mining_software\": \"Kontrollerar mining mjukvaran...\",\n    \"rapidfail\": \"Kontrollerar för förekomsten av fel\",\n    \"compatibility\": \"Kontrollerar GPU-kompatibilitet...\",\n    \"installing_miners\": \"Installera mining mjukvara...\",\n    \"verthash\": \"Verifierar / skapar Verthash data fil...\"\n  },\n  \"mining\": {\n    \"spendable_balance\": \"Spenderbart saldo\",\n    \"still_maturing\": \"mognar fortfarande\",\n    \"pending_pool_payout\": \"väntande poolutbetalning\",\n    \"pending_payout_info_unavailable\": \"Var vänlig vänta på utbetalnings information\",\n    \"waiting_for_miners\": \"Väntar på att miningen ska börja\",\n    \"expected_earnings_24h\": \"Förväntade intäkter (24h)\",\n    \"estimating\": \"beräknar\",\n    \"stop_mining\": \"Sluta Mina\",\n    \"active_pool\": \"Aktiv pool\",\n    \"pool_fee\": \"avgift\",\n    \"copy_address\": \"Kopiera din plånboks address\",\n    \"payout_information\": \"Visa utbetalnings information\"\n  },\n  \"sending\": {\n    \"send_all_to\": \"Skicka dina minade mynt till\",\n    \"youre_sending_x_to\": \"Du skickar {receivedBalance} till\",\n    \"youre_sending_x_in_y_txs_to\": \"Du skickar {receivedBalance} i {receivedTxCount} transaktion till\",\n    \"receiver_address\": \"Mottagaradress\",\n    \"wallet_password\": \"Plånbokslösenord\",\n    \"send\": \"Skicka\",\n    \"coins_sent\": \"Dina mynt har skickats!\",\n    \"view_trans_plural\": \"Visa transaktioner\",\n    \"view_trans_singular\": \"Visa transaktion\",\n    \"failed_to_send\": \"Det gick inte att skicka dina mynt\",\n    \"password_required\": \"Plånbokslösenord krävs\",\n    \"invalid_address\": \"Ogiltig adress\",\n    \"script_failure\": \"Script fel\",\n    \"could_not_calculate_fee\": \"Kunde inte beräkna avgift\",\n    \"insufficient_funds\": \"Otillräckliga saldo\",\n    \"sign_failed\": \"Det gick inte att skriva under transaktion. Kontrollera ditt lösenord\",\n    \"send_failed\": \"Det gick inte att skicka transaktion. Kontrollera debug.log filen för mer information\"\n  },\n  \"settings\": {\n    \"enable_debug\": \"Aktivera felsökning\",\n    \"enable_debug_sub\": \"Inkludera mining mjukvarans utdata i felsökningsloggen. Kan gör att loggfilen växer snabbt\",\n    \"auto_start\": \"Autostart\",\n    \"auto_start_sub\": \"Starta One-Click Miner när du loggar in på din dator\",\n    \"closed_source\": \"Använd mining mjukvara med stängd källkod (Proprietär programvara)\",\n    \"closed_source_sub\": \"Ger bättre hashrate, men källkoden är ej granskad och mjukvaran har en avgift till utvecklaren\",\n    \"closed_source_warning\": \"Du har valt att använda mining mjukvara med sluten källkod. Vertcoin stöder inte denna mjukvara. Källkoden kan inte granskas och kan inehålla delar som skadar din dator.\",\n    \"enable_integrated\": \"Använd integrerat grafikkort (iGPU) för att mina\",\n    \"enable_integrated_sub\": \"Kommer att använda integrerat grafikkort (om möjligt)\",\n    \"testnet\": \"Testnet läge\",\n    \"testnet_sub\": \"Aktivera testnet läge. Du kommer inte mina riktiga mynt.\",\n    \"skipverthashverify\": \"Verifiera inte verthash under start\",\n    \"skipverthashverify_sub\": \"Kommer inte att verifiera verthash data file under uppstart (rekomenderas inte)\",\n    \"save_n_restart\": \"Spara & starta om\",\n    \"pool\": \"Mining pool\"\n  },\n  \"tabbar\": {\n    \"wallet\": \"Plånbok\",\n    \"send_coins\": \"Skicka mynt\",\n    \"settings\": \"Inställningar\"\n  },\n  \"tracking\": {\n    \"update_available\": \"Uppdatering tillgänglig\",\n    \"tracking_enabled\": \"Du delar anonym användningsstatistik\",\n    \"disable_tracking\": \"Inaktivera\",\n    \"tracking_disabled\": \"Du delar inte användningsstatistik\",\n    \"enable_tracking\": \"Aktivera dessa för att hjälpa oss förbättra One-Click Miner\",\n    \"report_issue\": \"Rapportera ett problem\"\n  },\n  \"update\": {\n    \"new_version_available\": \"Ny version tillgänglig\",\n    \"download\": \"Ladda ner\"\n  }\n}"
  },
  {
    "path": "frontend/src/i18n/tr.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"Tekrar dene\",\n        \"back_to_wallet\" : \"Cüzdana dön\",\n        \"close\" : \"Kapat\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"Tek-tıkta-madencilik zaten çalışıyor. Birden fazla açamazsınız.\",\n        \"click_button_to_start\" : \"Madenciliğe devam etmek için butona tıklayın.\",\n        \"startmining\" : \"Madenciliğe Başla!\",\n        \"makeapassword\" : \"Bir şifre oluşturun. Bu şifreyi unutmayın!\",\n        \"password\" : \"Şifre\",\n        \"confirmpassword\" : \"Şifreyi tekrar gir\",\n        \"password_cannot_be_empty\" : \"Şifreyi boş bırakamazsınız\",\n        \"password_mismatch\" : \"Şifreler eşleşmiyor\",\n        \"error_initializing\" : \"Cüzdanı başlatırken bir şeyler ters gitti.\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"Gerekli bir program yükleniyor. İzin isteyen bir pencere açılabilir (ya da görev çubuğunuz renk değiştirebilir)\",\n        \"checks_failed\" : \"Kontroller başarısız oldu.\",\n        \"checking_mining_software\" : \"Madencilik yazılımı kontrol ediliyor...\",\n        \"rapidfail\" : \"Ani oluşan hatalar kontrol ediliyor...\",\n        \"compatibility\" : \"GPU uyumluluğu kontrol ediliyor...\",\n        \"installing_miners\" : \"Madencilik yazılımı yükleniyor...\",\n        \"verthash\" : \"Verthash dosyası onaylanıyor / oluşturuluyor...\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"Harcanabilir Bakiye\",\n        \"still_maturing\" : \"Olgunlaşmakta olan:\",\n        \"pending_pool_payout\" : \"havuz ödemesi bekleniyor\",\n        \"pending_payout_info_unavailable\" : \"Beklenen ödeme bilgisi için lütfen bekleyin...\",\n        \"waiting_for_miners\" : \"Madencinin başlaması bekleniyor\",\n        \"expected_earnings_24h\" : \"Tahmini Kazanç (24 saat)\",\n        \"estimating\" : \"Tahmin ediliyor...\",\n        \"stop_mining\" : \"Madenciliği durdur\",\n        \"active_pool\" : \"Aktif havuz\",\n        \"pool_fee\" : \"Havuz komisyonu\",\n        \"copy_address\" : \"Cüzdan adresinizi kopyalayın\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"Kazdığım tüm coinleri şu adrese gönder:\",\n        \"youre_sending_x_to\" : \"Bu adrese {receivedBalance} adet coin yolluyorsunuz;\",\n        \"youre_sending_x_in_y_txs_to\" : \"Bu adrese {receivedBalance} adet coini {receivedTxCount} adet transferle yolluyorsunuz \",\n        \"receiver_address\" : \"Alıcı Adresi\",\n        \"wallet_password\" : \"Cüzdan Şifresi\",\n        \"send\" : \"Gönder\",\n        \"coins_sent\" : \"Coinleriniz gönderildi!\",\n        \"view_trans_plural\" : \"Transferleri görüntüle\",\n        \"view_trans_singular\" : \"Transferi görüntüle\",\n        \"failed_to_send\" : \"Coinleriniz gönderilemedi\",\n        \"password_required\" : \"Cüzdan şifresini giriniz.\",\n        \"invalid_address\" : \"Geçersiz adres.\",\n        \"script_failure\" : \"Script başarısız oldu.\",\n        \"could_not_calculate_fee\" : \"Komisyon hesaplanamadı\",\n        \"insufficient_funds\" : \"Yetersiz bakiye\",\n        \"sign_failed\" : \"Transfer imzalanamadı. Şifreyi kontrol ediniz.\",\n        \"send_failed\" : \"Transfer yapılamadı. Daha fazla bilgi için debug.log inceleyiniz.\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"Debugging'i aktif et\",\n        \"enable_debug_sub\" : \"Madenci konsolunun çıktılarını debug.log'a dahil et. Log boyutu çok büyüyebilir\",\n        \"auto_start\" : \"Otomatik başlat\",\n        \"auto_start_sub\" : \"Madenciyi bilgisayar açıldığında otomatik başlat\",\n        \"closed_source\" : \"Kapalı kaynak kodlu madenci yazılımlarını kullan\",\n        \"closed_source_sub\" : \"Daha iyi hashrate alırsınız, fakat yazılımın geliştiricisi sizden komisyon alır\",\n        \"closed_source_warning\" : \"Kapalı kaynak kodlu madenci yazılımı kullanmayı seçtiniz. Vertcoin bu yazılımları desteklemez. İçerikleri bilinemez ve bilgisayarınıza zarar verebilecek yazılımlar içerebilir.\",\n        \"testnet\":\"Testnet modu\",\n        \"testnet_sub\":\"Testnet modunu aktifleştirir. Kazılan coinler gerçek değildir.\",\n        \"skipverthashverify\":\"Başlangıçta Verthash'i doğrulama\",\n        \"skipverthashverify_sub\":\"Başlangıçta Verthash dosyasının bütünlüğünü doğrulamayı atlayacak (önerilmez)\",\n        \"save_n_restart\" : \"Kaydet ve Yeniden Başlat\",\n        \"pool\": \"Madenci havuzu\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"Cüzdan\",\n        \"send_coins\" : \"Coin gönder\",\n        \"settings\" : \"Ayarlar\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"Yeni bir güncelleme var.\",\n        \"tracking_enabled\" : \"Anonim olarak kullanıcı istatistiği gönderiyorsunuz\",\n        \"disable_tracking\" : \"Deaktive et\",\n        \"tracking_disabled\" : \"Kullanım istatistiği yollamıyorsunuz\",\n        \"enable_tracking\" : \"Kullanıcı deneyimini geliştirmemize yardımcı olmak için aktif edin\",\n        \"report_issue\" : \"Sorun bildir\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"Yeni bir versiyon mevcut\",\n        \"download\" : \"İndir\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/i18n/zh.json",
    "content": "{\n    \"generic\" : {\n        \"retry\" : \"再试一次\",\n        \"back_to_wallet\" : \"返回钱包\",\n        \"close\" : \"关闭\"\n    },\n    \"welcome\" : {\n        \"alreadyrunning\" : \"一键式矿工《One-Click Miner》 已经在运行。你不能多次运行它。\",\n        \"click_button_to_start\" : \"点击下面的按钮再次开始挖矿。\",\n        \"startmining\" : \"开始挖矿!\",\n        \"makeapassword\" : \"请输入密码。不要丢失你的密码。\",\n        \"password\" : \"密码\",\n        \"confirmpassword\" : \"确认密码\",\n        \"password_cannot_be_empty\" : \"请输入密码\",\n        \"password_mismatch\" : \"密码不一致\",\n        \"error_initializing\" : \"初始化中发生了故障\"\n    },\n    \"checks\" : {\n        \"prerequisite\" : \"先行程序已运行，你可能看到弹窗弹出询问权限（可能只在任务栏中闪动）\",\n        \"checks_failed\" : \"检查失败\",\n        \"checking_mining_software\" : \"检查挖矿软件。。。\",\n        \"rapidfail\" : \"检查是否发生快速失败\",\n        \"compatibility\" : \"检查GPU兼容性。。。\",\n        \"installing_miners\" : \"安装挖矿软件。。。\"\n    },\n    \"mining\" : {\n        \"spendable_balance\" : \"可花费余额\",\n        \"still_maturing\" : \"还在成熟中\",\n        \"pending_pool_payout\" : \"等待矿池支出\",\n        \"waiting_for_miners\" : \"等待矿工开始\",\n        \"expected_earnings_24h\" : \"预期收益（24小时）\",\n        \"estimating\" : \"估计中\",\n        \"stop_mining\" : \"停止挖矿\"\n    },\n    \"sending\" : {\n        \"send_all_to\" : \"发送你所有挖矿的币到\",\n        \"youre_sending_x_to\" : \"你正在发送 {receivedBalance} 给\",\n        \"youre_sending_x_in_y_txs_to\" : \"你将在 {receivedTxCount} 的交易中发送 {receivedBalance}\",\n        \"receiver_address\" : \"接收地址\",\n        \"wallet_password\" : \"钱包密码\",\n        \"send\" : \"发送\",\n        \"coins_sent\" : \"你的币被发送了！\",\n        \"view_trans_plural\" : \"查看交易信息\",\n        \"view_trans_singular\" : \"查看交易信息\",\n        \"failed_to_send\" : \"发送币失败了\",\n        \"password_required\" : \"请输入钱包密码\",\n        \"invalid_address\" : \"无效地址\",\n        \"script_failure\" : \"脚本失败\",\n        \"could_not_calculate_fee\" : \"无法计算费用\",\n        \"insufficient_funds\" : \"不足资金\",\n        \"sign_failed\":\"无法签署交易。 检查密码\",\n    \"send_failed\" : \"无法发送交易。查看debug.log以获取更多的信息\"\n    },\n    \"settings\" : {\n        \"enable_debug\" : \"启用调试\",\n        \"enable_debug_sub\" : \"在调试日志中包含矿工的控制台输出。可以使你的日志变得很大。\",\n        \"auto_start\" : \"自动开始\",\n        \"auto_start_sub\" : \"登陆电脑时启动一键式矿工《One-Click Miner》\",\n        \"closed_source\" : \"使用闭源的矿工\",\n        \"closed_source_sub\" : \"更好的哈希率，但是未经审核的矿工会产生开发人员的费用\",\n        \"closed_source_warning\" : \"你选择使用闭源的矿工。绿币（VTC）不支持这些矿工。他们无法对其内容进行审核并且可能包含损害你的电脑的功能。\",\n        \"save_n_restart\" : \"保存及重启\"\n    },\n    \"tabbar\" : {\n        \"wallet\" : \"钱包\",\n        \"send_coins\" : \"发送币\",\n        \"settings\" : \"设置\"\n    },\n    \"tracking\": { \n        \"update_available\" : \"更新可用\",\n        \"tracking_enabled\" : \"你是匿名共享使用情况统计信息\",\n        \"disable_tracking\" : \"停用\",\n        \"tracking_disabled\" : \"你没有共享使用情况统计信息\",\n        \"enable_tracking\" : \"启用这些可以帮我们改善你的应用体验\",\n        \"report_issue\" : \"报告问题\"\n    },\n    \"update\" : {\n        \"new_version_available\" : \"新版本可用\",\n        \"download\" : \"下载\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/main.js",
    "content": "import Vue from \"vue\";\nimport App from \"./App.vue\";\nimport VueI18n from \"vue-i18n\";\nimport * as Wails from \"@wailsapp/runtime\"\n\nVue.use(VueI18n);\nVue.config.productionTip = false;\nVue.config.devtools = true;\n\n// Import all locales\nimport locale_bg from \"./i18n/bg.json\";\nimport locale_da from \"./i18n/da.json\";\nimport locale_de from \"./i18n/de.json\";\nimport locale_en from \"./i18n/en.json\";\nimport locale_es from \"./i18n/es.json\";\nimport locale_fr from \"./i18n/fr.json\";\nimport locale_hi from \"./i18n/hi.json\";\nimport locale_hr from \"./i18n/hr.json\";\nimport locale_it from \"./i18n/it.json\";\nimport locale_ja from \"./i18n/ja.json\";\nimport locale_lt from \"./i18n/lt.json\";\nimport locale_nl from \"./i18n/nl.json\";\nimport locale_no from \"./i18n/no.json\";\nimport locale_pa from \"./i18n/pa.json\";\nimport locale_pl from \"./i18n/pl.json\";\nimport locale_pt from \"./i18n/pt.json\";\nimport locale_ro from \"./i18n/ro.json\";\nimport locale_ru from \"./i18n/ru.json\";\nimport locale_sl from \"./i18n/sl.json\";\nimport locale_sv from \"./i18n/sv.json\";\nimport locale_tr from \"./i18n/tr.json\";\nimport locale_zh from \"./i18n/zh.json\";\n\nWails.Init(() => {\n    window.backend.Backend.GetLocale().then(result => {\n\n        const i18n = new VueI18n({\n            locale: result, // set locale\n            fallbackLocale: 'en',\n            messages: {\n\t\tbg: locale_bg,\n                da: locale_da,\n                de: locale_de,\n                en: locale_en,\n                es: locale_es,\n                fr: locale_fr,\n                hi: locale_hi,\n                hr: locale_hr,\n                it: locale_it,\n                ja: locale_ja,\n\t\tlt: locale_lt,\n                nl: locale_nl,\n                no: locale_no,\n                pa: locale_pa,\n                pl: locale_pl,\n                pt: locale_pt,\n                ro: locale_ro,\n                ru: locale_ru,\n                sl: locale_sl,\n                sv: locale_sv,\n\t\ttr: locale_tr,\n                zh: locale_zh,\n            },\n        });\n        \n        new Vue({\n            i18n,\n            render: h => h(App)\n        }).$mount(\"#app\");\n    });\n});\n"
  },
  {
    "path": "frontend/vue.config.js",
    "content": "let cssConfig = {};\n\nif (process.env.NODE_ENV == \"production\") {\n  cssConfig = {\n    extract: {\n      filename: \"[name].css\",\n      chunkFilename: \"[name].css\"\n    }\n  };\n}\n\nmodule.exports = {\n  chainWebpack: config => {\n    let limit = 9999999999999999;\n    config.module\n      .rule(\"images\")\n      .test(/\\.(png|gif|jpg)(\\?.*)?$/i)\n      .use(\"url-loader\")\n      .loader(\"url-loader\")\n      .tap(options => Object.assign(options, { limit: limit }));\n    config.module\n      .rule(\"fonts\")\n      .test(/\\.(woff2?|eot|ttf|otf|svg)(\\?.*)?$/i)\n      .use(\"url-loader\")\n      .loader(\"url-loader\")\n      .options({\n        limit: limit\n      });\n  },\n  css: cssConfig,\n  configureWebpack: {\n    output: {\n      filename: \"[name].js\"\n    },\n    optimization: {\n      splitChunks: false\n    }\n  },\n  devServer: {\n    disableHostCheck: true,\n    host: \"localhost\"\n  }\n};\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/vertcoin-project/one-click-miner-vnext\n\ngo 1.22\n\nrequire (\n\tgithub.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a\n\tgithub.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd\n\tgithub.com/btcsuite/btcd/btcec/v2 v2.3.2\n\tgithub.com/btcsuite/btcd/btcutil v1.1.5\n\tgithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0\n\tgithub.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941\n\tgithub.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21\n\tgithub.com/gertjaap/verthash-go v0.0.0-20210205201258-234a3a9698d1\n\tgithub.com/go-ping/ping v1.1.0\n\tgithub.com/marcsauter/single v0.0.0-20201009143647-9f8d81240be2\n\tgithub.com/tidwall/buntdb v1.3.0\n\tgithub.com/wailsapp/wails v1.16.9\n\tgolang.org/x/crypto v0.20.0\n\tgolang.org/x/text v0.14.0\n)\n\nrequire (\n\tgithub.com/Masterminds/semver v1.5.0 // indirect\n\tgithub.com/abadojack/whatlanggo v1.0.1 // indirect\n\tgithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect\n\tgithub.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect\n\tgithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect\n\tgithub.com/fatih/color v1.16.0 // indirect\n\tgithub.com/go-playground/colors v1.2.0 // indirect\n\tgithub.com/google/uuid v1.2.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.1 // indirect\n\tgithub.com/jackmordaunt/icns v1.0.0 // indirect\n\tgithub.com/kennygrant/sanitize v1.2.4 // indirect\n\tgithub.com/leaanthony/slicer v1.6.0 // indirect\n\tgithub.com/leaanthony/spinner v0.5.3 // indirect\n\tgithub.com/leaanthony/synx v0.1.0 // indirect\n\tgithub.com/leaanthony/wincursor v0.1.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect\n\tgithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/sirupsen/logrus v1.9.3 // indirect\n\tgithub.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba // indirect\n\tgithub.com/tidwall/btree v1.7.0 // indirect\n\tgithub.com/tidwall/gjson v1.17.1 // indirect\n\tgithub.com/tidwall/grect v0.1.4 // indirect\n\tgithub.com/tidwall/match v1.1.1 // indirect\n\tgithub.com/tidwall/pretty v1.2.0 // indirect\n\tgithub.com/tidwall/rtred v0.1.2 // indirect\n\tgithub.com/tidwall/tinyqueue v0.1.1 // indirect\n\tgolang.org/x/image v0.15.0 // indirect\n\tgolang.org/x/net v0.21.0 // indirect\n\tgolang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect\n\tgolang.org/x/sys v0.17.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=\ngithub.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=\ngithub.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4=\ngithub.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=\ngithub.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=\ngithub.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=\ngithub.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw=\ngithub.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=\ngithub.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=\ngithub.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=\ngithub.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=\ngithub.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=\ngithub.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=\ngithub.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941 h1:kij1x2aL7VE6gtx8KMIt8PGPgI5GV9LgtHFG5KaEMPY=\ngithub.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=\ngithub.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=\ngithub.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=\ngithub.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gertjaap/verthash-go v0.0.0-20210205201258-234a3a9698d1 h1:vSHBMfat507JbiOZdNICsiCUmoydc3oLzkOTIb/s+DY=\ngithub.com/gertjaap/verthash-go v0.0.0-20210205201258-234a3a9698d1/go.mod h1:YNFDXNhMlbkK6pJhNpLWgXWgsU+ISV8AWGdLC7RFlho=\ngithub.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=\ngithub.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=\ngithub.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=\ngithub.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=\ngithub.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=\ngithub.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=\ngithub.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=\ngithub.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=\ngithub.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=\ngithub.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=\ngithub.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=\ngithub.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=\ngithub.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=\ngithub.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=\ngithub.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=\ngithub.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=\ngithub.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=\ngithub.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=\ngithub.com/marcsauter/single v0.0.0-20201009143647-9f8d81240be2 h1:TyUcIW0tpCQzV4Hpe9jF3p590EQFnMQV3sv6DhoxV6Q=\ngithub.com/marcsauter/single v0.0.0-20201009143647-9f8d81240be2/go.mod h1:uUA07IN7rYmbr5YlZM5nDVLyoxiqqpprFlXBrjqI24A=\ngithub.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=\ngithub.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=\ngithub.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba h1:2DHfQOxcpWdGf5q5IzCUFPNvRX9Icf+09RvQK2VnJq0=\ngithub.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk=\ngithub.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=\ngithub.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=\ngithub.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=\ngithub.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=\ngithub.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA=\ngithub.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=\ngithub.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=\ngithub.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=\ngithub.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=\ngithub.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=\ngithub.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=\ngithub.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=\ngithub.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=\ngithub.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=\ngithub.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=\ngithub.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=\ngithub.com/wailsapp/wails v1.16.9 h1:H0jWILvWU1I3y2MgqwIPjMfD95/nQP9qAuqAsadYaOs=\ngithub.com/wailsapp/wails v1.16.9/go.mod h1:R4AAEWp6K4c0nIMHj5jmr+WQ4yXTfzLXbQoXbg2vEHM=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=\ngolang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=\ngolang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=\ngolang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=\ngolang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "keyfile/keyfile.go",
    "content": "package keyfile\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/btcsuite/btcd/btcec/v2\"\n\t\"github.com/btcsuite/btcd/btcutil\"\n\t\"github.com/btcsuite/btcd/btcutil/base58\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n\t\"golang.org/x/crypto/nacl/secretbox\"\n\t\"golang.org/x/crypto/scrypt\"\n)\n\n// KeyFileValid returns true if there is a valid initialized keyfile\n// available\nfunc KeyFileValid() bool {\n\treturn len(loadPublicKey()) == 33\n}\n\nfunc CreateKeyFile(pass string) error {\n\tfilename := keyFile()\n\n\t// Create random key\n\tpriv32 := new([32]byte)\n\t_, err := rand.Read(priv32[:])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Derive pubkey\n\t_, pub := btcec.PrivKeyFromBytes(priv32[:])\n\n\tsalt := new([24]byte) // salt for scrypt / nonce for secretbox\n\tdk32 := new([32]byte) // derived key from scrypt\n\n\t//get 24 random bytes for scrypt salt (and secretbox nonce)\n\t_, err = rand.Read(salt[:])\n\tif err != nil {\n\t\treturn err\n\t}\n\t// next use the pass and salt to make a 32-byte derived key\n\tdk, err := scrypt.Key([]byte(pass), salt[:], 16384, 8, 1, 32)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcopy(dk32[:], dk[:])\n\n\tenckey := append(salt[:], secretbox.Seal(nil, priv32[:], salt, dk32)...)\n\treturn os.WriteFile(filename, append(pub.SerializeCompressed(), enckey...), 0600)\n}\n\nfunc keyFile() string {\n\treturn filepath.Join(util.DataDirectory(), \"keyfile.hex\")\n}\n\nfunc loadPublicKey() []byte {\n\tfilename := keyFile()\n\tb, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.Infof(\"Error reading keyfile: %s\", err.Error())\n\t\treturn []byte{}\n\t}\n\tif len(b) != 105 {\n\t\tlogging.Infof(\"Keyfile had wrong length. Expected 129, got %d\", len(b))\n\t\treturn []byte{}\n\t}\n\tret := make([]byte, 33)\n\tcopy(ret, b[:33])\n\tb = nil\n\treturn ret\n}\n\nfunc GetPublicKey() []byte {\n\tpub := loadPublicKey()\n\treturn pub\n}\n\nfunc GetAddress() string {\n\tpub := loadPublicKey()\n\treturn base58.CheckEncode(btcutil.Hash160(pub), networks.Active.Base58P2PKHVersion)\n}\n\nfunc GetScript() ([]byte, error) {\n\tpub := loadPublicKey()\n\treturn txscript.NewScriptBuilder().AddOp(txscript.OP_DUP).\n\t\tAddOp(txscript.OP_HASH160).AddData(btcutil.Hash160(pub)).\n\t\tAddOp(txscript.OP_EQUALVERIFY).AddOp(txscript.OP_CHECKSIG).Script()\n}\n\nfunc LoadPrivateKey(password string) ([]byte, error) {\n\tfilename := keyFile()\n\tkeyfile, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\tif len(keyfile) != 105 {\n\t\treturn []byte{}, fmt.Errorf(\"Key length error for %s \", filename)\n\t}\n\n\tenckey := keyfile[33:]\n\t// enckey is actually encrypted, get derived key from pass and salt\n\t// first extract salt\n\tsalt := new([24]byte)      // salt (also nonce for secretbox)\n\tdk32 := new([32]byte)      // derived key array\n\tcopy(salt[:], enckey[:24]) // first 24 bytes are scrypt salt/box nonce\n\n\tdk, err := scrypt.Key([]byte(password), salt[:], 16384, 8, 1, 32) // derive key\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\tcopy(dk32[:], dk[:]) // copy into fixed size array\n\n\t// nonce for secretbox is the same as scrypt salt.  Seems fine.  Really.\n\tpriv, worked := secretbox.Open(nil, enckey[24:], salt, dk32)\n\tif !worked {\n\t\treturn []byte{}, fmt.Errorf(\"Decryption failed for %s \", filename)\n\t}\n\n\treturn priv, nil\n}\n\nfunc TestPassword(password string) bool {\n\tpriv, err := LoadPrivateKey(password)\n\tif err != nil {\n\t\treturn false\n\t}\n\t_, pub := btcec.PrivKeyFromBytes(priv)\n\treturn bytes.Equal(loadPublicKey(), pub.SerializeCompressed())\n}\n"
  },
  {
    "path": "logging/log.go",
    "content": "package logging\n\n// Log Levels:\n// 3: DebugLevel prints Panics, Fatals, Errors, Warnings, Infos and Debugs\n// 2: InfoLevel  prints Panics, Fatals, Errors, Warnings and Info\n// 1: WarnLevel  prints Panics, Fatals, Errors and Warnings\n// 0: ErrorLevel prints Panics, Fatals and Errors\n// Default is level 0\n// Code for tagging logs:\n// Debug -> Useful debugging information\n// Info  -> Something noteworthy happened\n// Warn  -> You should probably take a look at this\n// Error -> Something failed but I'm not quitting\n// Fatal -> Bye\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\ntype LogLevel int\n\nconst (\n\tLogLevelError   LogLevel = 0\n\tLogLevelWarning LogLevel = 1\n\tLogLevelInfo    LogLevel = 2\n\tLogLevelDebug   LogLevel = 3\n)\n\nvar logLevel = LogLevelError // the default\n\nfunc SetLogLevel(newLevel int) {\n\tlogLevel = LogLevel(newLevel)\n}\n\nfunc SetLogFile(logFile io.Writer) {\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)\n\t_, err := os.Stdout.Write([]byte(\"\\n\"))\n\tif err == nil {\n\t\tlog.SetOutput(io.MultiWriter(os.Stdout, logFile))\n\t} else {\n\t\tlog.SetOutput(logFile)\n\t}\n}\n\nfunc getPrefix(level string) string {\n\treturn fmt.Sprintf(\"[%s]\", level)\n}\n\nfunc Fatalln(args ...interface{}) {\n\tlog.Fatalln(args...)\n}\n\nfunc Fatalf(format string, args ...interface{}) {\n\tlog.Fatalf(format, args...)\n}\n\nfunc Fatal(args ...interface{}) {\n\tlog.Fatal(args...)\n}\n\nfunc Debugf(format string, args ...interface{}) {\n\tif logLevel >= LogLevelDebug {\n\t\tlog.Printf(fmt.Sprintf(\"%s %s\", getPrefix(\"DEBUG\"), format), args...)\n\t}\n}\n\nfunc Infof(format string, args ...interface{}) {\n\tif logLevel >= LogLevelInfo {\n\t\tlog.Printf(fmt.Sprintf(\"%s %s\", getPrefix(\"INFO\"), format), args...)\n\t}\n}\n\nfunc Warnf(format string, args ...interface{}) {\n\tif logLevel >= LogLevelWarning {\n\t\tlog.Printf(fmt.Sprintf(\"%s %s\", getPrefix(\"WARN\"), format), args...)\n\t}\n}\n\nfunc Errorf(format string, args ...interface{}) {\n\tif logLevel >= LogLevelError {\n\t\tlog.Printf(fmt.Sprintf(\"%s %s\", getPrefix(\"ERROR\"), format), args...)\n\t}\n}\n\nfunc Debugln(args ...interface{}) {\n\tif logLevel >= LogLevelDebug {\n\t\targs = append([]interface{}{getPrefix(\"DEBUG\")}, args...)\n\t\tlog.Println(args...)\n\t}\n}\n\nfunc Infoln(args ...interface{}) {\n\tif logLevel >= LogLevelInfo {\n\t\targs = append([]interface{}{getPrefix(\"INFO\")}, args...)\n\t\tlog.Println(args...)\n\t}\n}\n\nfunc Warnln(args ...interface{}) {\n\tif logLevel >= LogLevelWarning {\n\t\targs = append([]interface{}{getPrefix(\"WARN\")}, args...)\n\t\tlog.Println(args...)\n\t}\n}\n\nfunc Errorln(args ...interface{}) {\n\tif logLevel >= LogLevelError {\n\t\targs = append([]interface{}{getPrefix(\"ERROR\")}, args...)\n\t\tlog.Println(args...)\n\t}\n}\n\nfunc Debug(args ...interface{}) {\n\tif logLevel >= LogLevelDebug {\n\t\targs = append([]interface{}{getPrefix(\"DEBUG\")}, args...)\n\t\tlog.Print(args...)\n\t}\n}\n\nfunc Info(args ...interface{}) {\n\tif logLevel >= LogLevelInfo {\n\t\targs = append([]interface{}{getPrefix(\"INFO\")}, args...)\n\t\tlog.Print(args...)\n\t}\n}\n\nfunc Warn(args ...interface{}) {\n\tif logLevel >= LogLevelWarning {\n\t\targs = append([]interface{}{getPrefix(\"WARN\")}, args...)\n\t\tlog.Print(args...)\n\t}\n}\n\nfunc Error(args ...interface{}) {\n\tif logLevel >= LogLevelError {\n\t\targs = append([]interface{}{getPrefix(\"ERROR\")}, args...)\n\t\tlog.Print(args...)\n\t}\n}\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime/debug\"\n\n\t_ \"embed\"\n\n\t\"github.com/marcsauter/single\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/backend\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/tracking\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n\t\"github.com/wailsapp/wails\"\n)\n\n//nolint:all\n//go:embed frontend/dist/app.js\nvar js string\n\n//nolint:all\n//go:embed frontend/dist/app.css\nvar css string\n\nfunc main() {\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\t// Reopen log file, since it's closed now!\n\t\t\tlogging.SetLogLevel(int(logging.LogLevelDebug))\n\t\t\tlogFilePath := filepath.Join(util.DataDirectory(), \"debug.log\")\n\t\t\tlogFile, _ := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)\n\t\t\tlogging.SetLogFile(logFile)\n\t\t\tdefer logFile.Close()\n\t\t\tlogging.Errorf(\"%v\\n%s\\n\", err, string(debug.Stack()))\n\n\t\t\ttracking.Track(tracking.TrackingRequest{\n\t\t\t\tCategory: \"Lifecycle\",\n\t\t\t\tAction:   \"Crash\",\n\t\t\t\tName:     fmt.Sprintf(\"%v\", err),\n\t\t\t})\n\n\t\t}\n\t}()\n\n\ttracking.StartTracker()\n\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Lifecycle\",\n\t\tAction:   \"Startup\",\n\t\tName:     fmt.Sprintf(\"OCM/%s\", tracking.GetVersion()),\n\t})\n\n\tlogging.SetLogLevel(int(logging.LogLevelDebug))\n\tif _, err := os.Stat(util.DataDirectory()); os.IsNotExist(err) {\n\t\tlogging.Infof(\"Creating data directory\")\n\t\terr = os.MkdirAll(util.DataDirectory(), 0700)\n\t\tif err != nil && !os.IsExist(err) {\n\t\t\tlogging.Errorf(\"Error creating data directory, cannot continue\")\n\t\t\tos.Exit(1)\n\t\t}\n\t}\n\n\tlogFilePath := filepath.Join(util.DataDirectory(), \"debug.log\")\n\tlogFile, _ := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)\n\tlogging.SetLogFile(logFile)\n\tdefer logFile.Close()\n\n\tlog.Printf(\"OCM v%s Started up\\n\", tracking.GetVersion())\n\n\tapp := wails.CreateApp(&wails.AppConfig{\n\t\tWidth:  800,\n\t\tHeight: 400,\n\t\tTitle:  \"Vertcoin One Click Miner\",\n\t\tJS:     js,\n\t\tCSS:    css,\n\t\tColour: \"#131313\",\n\t})\n\n\talreadyRunning := false\n\ts := single.New(\"vertcoin-ocm\")\n\tif err := s.CheckLock(); err != nil && err == single.ErrAlreadyRunning {\n\t\talreadyRunning = true\n\t} else if err == nil {\n\t\tdefer func() {\n\t\t\terr := s.TryUnlock()\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error unlocking OCM: %v\", err)\n\t\t\t}\n\t\t}()\n\t}\n\n\tbackend, err := backend.NewBackend(alreadyRunning)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error creating Backend: %s\", err.Error())\n\t\tpanic(err)\n\t}\n\tnetworks.SetNetwork(backend.GetTestnet())\n\n\tgo backend.BackendServerSelector()\n\tgo backend.SelectP2PoolNode()\n\n\tbackend.ResetPool()\n\tapp.Bind(backend)\n\terr = app.Run()\n\tif err != nil {\n\t\tlogging.Errorf(\"Error running app: %v\", err)\n\t}\n\tbackend.StopMining()\n\n\ttracking.Track(tracking.TrackingRequest{\n\t\tCategory: \"Lifecycle\",\n\t\tAction:   \"Shutdown\",\n\t})\n\n\ttracking.Stop()\n}\n"
  },
  {
    "path": "miners/ccminer.go",
    "content": "package miners\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\n// Compile time assertion on interface\nvar _ MinerImpl = &CCMinerImpl{}\n\ntype CCMinerImpl struct {\n\tbinaryRunner  *BinaryRunner\n\thashRates     map[int64]uint64\n\thashRatesLock sync.Mutex\n\tgpuCount      int8\n}\n\nfunc NewCCMinerImpl(br *BinaryRunner) MinerImpl {\n\treturn &CCMinerImpl{binaryRunner: br, hashRates: map[int64]uint64{}, hashRatesLock: sync.Mutex{}}\n}\n\nfunc (l *CCMinerImpl) Configure(args BinaryArguments) error {\n\treturn nil\n}\n\nfunc (l *CCMinerImpl) ParseOutput(line string) {\n\tif l.binaryRunner.Debug {\n\t\tlogging.Debugf(\"[ccminer] %s\\n\", line)\n\t}\n\tline = strings.TrimSpace(line)\n\n\tif strings.Contains(line, \"GPU #\") && strings.HasSuffix(line, \")\") {\n\t\tstartCountIdx := strings.Index(line, \"GPU #\") + 5\n\t\tgpuCountString := line[startCountIdx : startCountIdx+1]\n\t\tgpuCount64, _ := strconv.ParseInt(gpuCountString, 10, 8)\n\t\tl.gpuCount = int8(gpuCount64) + 1\n\t\tlogging.Debugf(\"Set GPU Count to %d\", l.gpuCount)\n\t}\n\n\tif strings.Contains(line, \"GPU #\") && strings.HasSuffix(line, \"H/s\") {\n\t\tstartDeviceIdx := strings.Index(line, \"GPU #\")\n\t\tendDeviceIdx := strings.Index(line[startDeviceIdx:], \":\")\n\t\tdeviceIdxString := line[startDeviceIdx+5 : startDeviceIdx+endDeviceIdx]\n\t\tdeviceIdx, err := strconv.ParseInt(deviceIdxString, 10, 64)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tstartMHs := strings.LastIndex(line, \", \")\n\t\tif startMHs > -1 {\n\t\t\thashRateUnit := strings.ToUpper(line[len(line)-4 : len(line)-3])\n\t\t\tline = line[startMHs+2 : len(line)-5]\n\t\t\tf, err := strconv.ParseFloat(line, 64)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error parsing hashrate: %s\\n\", err.Error())\n\t\t\t}\n\t\t\tif hashRateUnit == \"K\" {\n\t\t\t\tf = f * 1000\n\t\t\t} else if hashRateUnit == \"M\" {\n\t\t\t\tf = f * 1000 * 1000\n\t\t\t} else if hashRateUnit == \"G\" {\n\t\t\t\tf = f * 1000 * 1000 * 1000\n\t\t\t}\n\n\t\t\tl.hashRatesLock.Lock()\n\t\t\tl.hashRates[deviceIdx] = uint64(f)\n\t\t\tl.hashRatesLock.Unlock()\n\t\t}\n\t}\n}\n\nfunc (l *CCMinerImpl) HashRate() uint64 {\n\ttotalHash := uint64(0)\n\tl.hashRatesLock.Lock()\n\tfor _, h := range l.hashRates {\n\t\ttotalHash += h\n\t}\n\tl.hashRatesLock.Unlock()\n\treturn totalHash\n}\n\nfunc (l *CCMinerImpl) ConstructCommandlineArgs(args BinaryArguments) []string {\n\treturn []string{\"--max-log-rate\", \"0\", \"--no-color\", \"-a\", \"lyra2v3\", \"-o\", args.StratumUrl, \"-u\", args.StratumUsername, \"-p\", args.StratumPassword}\n}\n\nfunc (l *CCMinerImpl) AvailableGPUs() int8 {\n\terr := l.binaryRunner.launch([]string{\"-n\"}, false)\n\tif err != nil {\n\t\treturn 0\n\t}\n\terr = l.binaryRunner.cmd.Wait()\n\tif err != nil {\n\t\treturn 0\n\t}\n\t// Output is caught by ParseOuput function above and this will set the gpuCount accordingly\n\treturn l.gpuCount\n}\n"
  },
  {
    "path": "miners/cryptodredge.go",
    "content": "package miners\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\n// Compile time assertion on interface\nvar _ MinerImpl = &CryptoDredgeMinerImpl{}\n\ntype CryptoDredgeMinerImpl struct {\n\tbinaryRunner  *BinaryRunner\n\thashRates     map[int64]uint64\n\thashRatesLock sync.Mutex\n\tgpuCount      int8\n}\n\nfunc NewCryptoDredgeMinerImpl(br *BinaryRunner) MinerImpl {\n\treturn &CryptoDredgeMinerImpl{binaryRunner: br, hashRates: map[int64]uint64{}, hashRatesLock: sync.Mutex{}}\n}\n\nfunc (l *CryptoDredgeMinerImpl) Configure(args BinaryArguments) error {\n\treturn nil\n}\n\nfunc (l *CryptoDredgeMinerImpl) ParseOutput(line string) {\n\tif l.binaryRunner.Debug {\n\t\tlogging.Debugf(\"[cryptodredge] %s\\n\", line)\n\t}\n\tline = strings.TrimSpace(line)\n\n\tif strings.Contains(line, \"INFO  - GPU\") && strings.Contains(line, \"MB\") {\n\t\tstartCountIdx := strings.Index(line, \"INFO  - GPU\") + 11\n\t\tgpuCountString := line[startCountIdx : startCountIdx+1]\n\t\tgpuCount64, _ := strconv.ParseInt(gpuCountString, 10, 8)\n\t\tl.gpuCount = int8(gpuCount64) + 1\n\t\tlogging.Debugf(\"Set GPU Count to %d\", l.gpuCount)\n\t}\n\tif strings.Contains(line, \"INFO  - GPU\") && strings.Contains(line, \"H/s\") {\n\t\tstartDeviceIdx := strings.Index(line, \"INFO  - GPU\")\n\t\tendDeviceIdx := strings.Index(line[startDeviceIdx+9:], \" \")\n\t\tdeviceIdxString := line[startDeviceIdx+11 : startDeviceIdx+9+endDeviceIdx]\n\t\tdeviceIdx, err := strconv.ParseInt(deviceIdxString, 10, 64)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tendMHs := strings.Index(line, \"H/s\")\n\t\tif endMHs > -1 {\n\t\t\thashRateUnit := strings.ToUpper(line[endMHs-1 : endMHs])\n\t\t\tline = line[:endMHs-1]\n\t\t\tline = line[strings.LastIndex(line, \" \")+1:]\n\t\t\tline = strings.ReplaceAll(line, \",\", \".\")\n\t\t\tf, err := strconv.ParseFloat(line, 64)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error parsing hashrate: %s\\n\", err.Error())\n\t\t\t}\n\t\t\tif hashRateUnit == \"K\" {\n\t\t\t\tf = f * 1000\n\t\t\t} else if hashRateUnit == \"M\" {\n\t\t\t\tf = f * 1000 * 1000\n\t\t\t} else if hashRateUnit == \"G\" {\n\t\t\t\tf = f * 1000 * 1000 * 1000\n\t\t\t}\n\n\t\t\tl.hashRatesLock.Lock()\n\t\t\tl.hashRates[deviceIdx] = uint64(f)\n\t\t\tl.hashRatesLock.Unlock()\n\t\t}\n\t}\n}\n\nfunc (l *CryptoDredgeMinerImpl) HashRate() uint64 {\n\ttotalHash := uint64(0)\n\tl.hashRatesLock.Lock()\n\tfor _, h := range l.hashRates {\n\t\ttotalHash += h\n\t}\n\tl.hashRatesLock.Unlock()\n\treturn totalHash\n}\n\nfunc (l *CryptoDredgeMinerImpl) ConstructCommandlineArgs(args BinaryArguments) []string {\n\treturn []string{\"--intensity\", \"5\", \"--no-color\", \"-a\", \"lyra2v3\", \"-o\", args.StratumUrl, \"-u\", args.StratumUsername, \"-p\", args.StratumPassword}\n}\n\nfunc (l *CryptoDredgeMinerImpl) AvailableGPUs() int8 {\n\terr := l.binaryRunner.launch([]string{}, false)\n\tif err != nil {\n\t\treturn 0\n\t}\n\ttime.Sleep(time.Second)\n\terr = l.binaryRunner.Stop()\n\tif err != nil {\n\t\treturn 0\n\t}\n\t// Output is caught by ParseOuput function above and this will set the gpuCount accordingly\n\treturn l.gpuCount\n}\n"
  },
  {
    "path": "miners/lyclminer.go",
    "content": "package miners\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\n// Compile time assertion on interface\nvar _ MinerImpl = &LyclMinerImpl{}\n\ntype LyclMinerImpl struct {\n\tbinaryRunner  *BinaryRunner\n\thashRates     map[int64]uint64\n\thashRatesLock sync.Mutex\n}\n\nfunc NewLyclMinerImpl(br *BinaryRunner) MinerImpl {\n\treturn &LyclMinerImpl{binaryRunner: br, hashRates: map[int64]uint64{}, hashRatesLock: sync.Mutex{}}\n}\n\nfunc (l *LyclMinerImpl) Configure(args BinaryArguments) error {\n\tos.Remove(filepath.Join(util.DataDirectory(), \"lyclMiner_tmpl.conf\"))\n\terr := l.binaryRunner.launch([]string{\"-g\", filepath.Join(util.DataDirectory(), \"lyclMiner_tmpl.conf\")}, false)\n\terr2 := l.binaryRunner.cmd.Wait()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err2 != nil {\n\t\treturn err2\n\t}\n\n\tif !l.binaryRunner.cmd.ProcessState.Success() {\n\t\treturn fmt.Errorf(\"Was unable to configure lyclMiner. Exit code %d\", l.binaryRunner.cmd.ProcessState.ExitCode())\n\t}\n\n\tin, err := os.Open(filepath.Join(util.DataDirectory(), \"lyclMiner_tmpl.conf\"))\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn err\n\t}\n\tdefer in.Close()\n\n\tos.Remove(filepath.Join(util.DataDirectory(), \"lyclMiner.conf\"))\n\tout, err := os.Create(filepath.Join(util.DataDirectory(), \"lyclMiner.conf\"))\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn err\n\t}\n\tdefer func() {\n\t\terr := out.Close()\n\t\tif err != nil {\n\t\t\tlogging.Error(err)\n\t\t}\n\t}()\n\n\tscanner := bufio.NewScanner(in)\n\tskip := false\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.HasPrefix(line, \"#\") {\n\t\t\tskip = false\n\t\t}\n\t\tif strings.HasPrefix(line, \"<Connection\") {\n\t\t\t_, err = out.WriteString(fmt.Sprintf(\"<Connection Url = \\\"%s\\\"\\n\\tUsername = \\\"%s\\\"\\n\\tPassword = \\\"%s\\\"\\n\\tAlgorithm = \\\"Lyra2REv3\\\">\\n\\n\", args.StratumUrl, args.StratumUsername, args.StratumPassword))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tskip = true\n\t\t}\n\t\tif !skip {\n\t\t\t_, err = out.WriteString(fmt.Sprintf(\"%s\\n\", line))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (l *LyclMinerImpl) ParseOutput(line string) {\n\tif l.binaryRunner.Debug {\n\t\tlogging.Debugf(\"[lyclMiner] %s\\n\", line)\n\t}\n\tline = strings.TrimSpace(line)\n\tif strings.Contains(line, \"Device #\") && strings.HasSuffix(line, \"H/s\") {\n\t\tstartDeviceIdx := strings.Index(line, \"Device #\")\n\t\tendDeviceIdx := strings.Index(line[startDeviceIdx:], \":\")\n\t\tdeviceIdxString := line[startDeviceIdx+8 : startDeviceIdx+endDeviceIdx]\n\t\tdeviceIdx, err := strconv.ParseInt(deviceIdxString, 10, 64)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tstartMHs := strings.LastIndex(line, \", \")\n\t\tif startMHs > -1 {\n\t\t\thashRateUnit := strings.ToUpper(line[len(line)-4 : len(line)-3])\n\t\t\tline = line[startMHs+2 : len(line)-5]\n\t\t\tf, err := strconv.ParseFloat(line, 64)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error parsing hashrate: %s\\n\", err.Error())\n\t\t\t}\n\t\t\tif hashRateUnit == \"K\" {\n\t\t\t\tf = f * 1000\n\t\t\t} else if hashRateUnit == \"M\" {\n\t\t\t\tf = f * 1000 * 1000\n\t\t\t} else if hashRateUnit == \"G\" {\n\t\t\t\tf = f * 1000 * 1000 * 1000\n\t\t\t}\n\t\t\tl.hashRatesLock.Lock()\n\t\t\tl.hashRates[deviceIdx] = uint64(f)\n\t\t\tl.hashRatesLock.Unlock()\n\t\t}\n\t}\n}\n\nfunc (l *LyclMinerImpl) HashRate() uint64 {\n\ttotalHash := uint64(0)\n\tl.hashRatesLock.Lock()\n\tfor _, h := range l.hashRates {\n\t\ttotalHash += h\n\t}\n\tl.hashRatesLock.Unlock()\n\treturn totalHash\n}\n\nfunc (l *LyclMinerImpl) ConstructCommandlineArgs(args BinaryArguments) []string {\n\treturn []string{filepath.Join(util.DataDirectory(), \"lyclMiner.conf\")}\n}\n\nfunc (l *LyclMinerImpl) AvailableGPUs() int8 {\n\ttmpCfg := filepath.Join(util.DataDirectory(), \"lyclMiner_tmp.conf\")\n\terr := l.binaryRunner.launch([]string{\"-g\", tmpCfg}, false)\n\terr2 := l.binaryRunner.cmd.Wait()\n\tif err != nil {\n\t\treturn 0\n\t}\n\tif err2 != nil {\n\t\treturn 0\n\t}\n\n\tif !l.binaryRunner.cmd.ProcessState.Success() {\n\t\treturn 0\n\t}\n\n\tin, err := os.Open(filepath.Join(util.DataDirectory(), \"lyclMiner_tmpl.conf\"))\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn 0\n\t}\n\tgpu := int8(0)\n\tscanner := bufio.NewScanner(in)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.HasPrefix(line, \"<Device\") {\n\t\t\tgpu++\n\t\t}\n\t}\n\tin.Close()\n\tos.Remove(tmpCfg)\n\treturn gpu\n}\n"
  },
  {
    "path": "miners/miners.go",
    "content": "package miners\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/prerequisites\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\ntype MinerBinary struct {\n\tPlatform           string   `json:\"platform\"`\n\tGpuPlatformString  string   `json:\"gpuplatform\"`\n\tUrl                string   `json:\"url\"`\n\tPrerequisites      []string `json:\"minerPreRequisites\"`\n\tHash               string   `json:\"sha256\"`\n\tMainExecutableName string   `json:\"mainExecutableName\"`\n\tClosedSource       bool     `json:\"closedSource\"`\n\tTestnet            bool     `json:\"testnet\"`\n\tMultiGPUMiner      bool     `json:\"multiGPUMiner\"`\n\tEnableIntegrated   bool     `json:\"enableIntegrated\"`\n\tGPUType            util.GPUType\n}\n\nfunc GetMinerBinaries() []MinerBinary {\n\tbinaries := []MinerBinary{}\n\terr := util.GetJson(\"https://raw.githubusercontent.com/vertcoin-project/one-click-miner-vnext/master/miners.json\", &binaries)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching miner binaries: %v\", err)\n\t\treturn binaries\n\t}\n\tfor i := range binaries {\n\t\tif binaries[i].GpuPlatformString == \"AMD\" {\n\t\t\tbinaries[i].GPUType = util.GPUTypeAMD\n\t\t} else if binaries[i].GpuPlatformString == \"NVIDIA\" {\n\t\t\tbinaries[i].GPUType = util.GPUTypeNVidia\n\t\t} else if binaries[i].GpuPlatformString == \"INTEL\" {\n\t\t\tbinaries[i].GPUType = util.GPUTypeIntel\n\t\t} else {\n\t\t\tlogging.Warnf(\"Found unrecognized platform [%s] in miners.json\\n\", binaries[i].GpuPlatformString)\n\t\t}\n\t}\n\treturn binaries\n}\n\ntype MinerImpl interface {\n\tParseOutput(line string)\n\tConfigure(args BinaryArguments) error\n\tHashRate() uint64\n\tConstructCommandlineArgs(args BinaryArguments) []string\n\tAvailableGPUs() int8\n}\n\nfunc NewBinaryRunner(m MinerBinary, prerequisiteInstall chan bool) (*BinaryRunner, error) {\n\tbr := &BinaryRunner{MinerBinary: m, lastStarted: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), prerequisiteInstall: prerequisiteInstall}\n\tif strings.HasPrefix(m.MainExecutableName, \"lycl\") {\n\t\tbr.MinerImpl = NewLyclMinerImpl(br)\n\t} else if strings.HasPrefix(m.MainExecutableName, \"ccminer\") {\n\t\tbr.MinerImpl = NewCCMinerImpl(br)\n\t} else if strings.HasPrefix(m.MainExecutableName, \"teamred\") {\n\t\tbr.MinerImpl = NewTeamRedMinerImpl(br)\n\t} else if strings.HasPrefix(m.MainExecutableName, \"CryptoDredge\") {\n\t\tbr.MinerImpl = NewCryptoDredgeMinerImpl(br)\n\t} else if strings.HasPrefix(m.MainExecutableName, \"VerthashMiner\") {\n\t\tbr.MinerImpl = NewVerthashMinerImpl(br)\n\t} else {\n\t\treturn nil, fmt.Errorf(\"Could not determine implementation for miner binary\")\n\t}\n\treturn br, nil\n}\n\ntype BinaryArguments struct {\n\tStratumUrl       string\n\tStratumUsername  string\n\tStratumPassword  string\n\tEnableIntegrated bool\n}\n\ntype BinaryRunner struct {\n\tMinerBinary         MinerBinary\n\tMinerImpl           MinerImpl\n\tcmd                 *exec.Cmd\n\tDebug               bool\n\trunning             bool\n\tlastStarted         time.Time\n\trapidFails          int\n\tusedArgs            BinaryArguments\n\tprerequisiteInstall chan bool\n}\n\nfunc (b *BinaryRunner) logPrefix() string {\n\treturn fmt.Sprintf(\"[Miner %s/%d]\", b.MinerBinary.Platform, b.MinerBinary.GPUType)\n}\n\nfunc (b *BinaryRunner) Stop() error {\n\n\tif b.cmd == nil {\n\t\t// not started (yet)\n\t\treturn nil\n\t}\n\t// Windows doesn't support Interrupt\n\tif runtime.GOOS == \"windows\" {\n\t\t_ = b.cmd.Process.Signal(os.Kill)\n\t\treturn nil\n\t}\n\n\tgo func() {\n\t\ttime.Sleep(15 * time.Second)\n\t\t_ = b.cmd.Process.Signal(os.Kill)\n\t}()\n\terr := b.cmd.Process.Signal(os.Interrupt)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb.WaitUntilStopped()\n\treturn nil\n}\n\nfunc (b *BinaryRunner) WaitUntilStopped() {\n\tstopped := make(chan bool)\n\tgo func() {\n\t\tfor {\n\t\t\tif !b.running {\n\t\t\t\tstopped <- true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t<-time.After(time.Second)\n\t\t}\n\t}()\n\t<-stopped\n}\n\nfunc (b *BinaryRunner) IsRunning() bool {\n\treturn b.running\n}\n\nfunc (b *BinaryRunner) Install() error {\n\t// Check prerequisites\n\tfor _, p := range b.MinerBinary.Prerequisites {\n\t\terr := prerequisites.Install(p, b.prerequisiteInstall)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check if the archive is available and it has the right SHA sum. Download if not\n\terr := b.ensureAvailable()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Always re-unpack the archive to ensure no one tampered with the file on disk.\n\terr = b.unpack()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype RunningState int\n\nconst (\n\tRunningStateRunning    RunningState = 0\n\tRunningStateRestarting RunningState = 1\n\tRunningStateRapidFail  RunningState = 2\n)\n\nfunc (b *BinaryRunner) CheckRunning() RunningState {\n\tif !b.IsRunning() {\n\t\tlogging.Infof(\"Miner [%s] stopped running.\", b.MinerBinary.MainExecutableName)\n\t\tif time.Since(b.lastStarted).Seconds() < 10 {\n\t\t\t// Rapid fail\n\t\t\tb.rapidFails++\n\t\t\tif b.rapidFails > 3 {\n\t\t\t\tlogging.Infof(\"Miner [%s] is rapidly failing, not restarting it.\", b.MinerBinary.MainExecutableName)\n\t\t\t\treturn RunningStateRapidFail\n\t\t\t}\n\t\t}\n\n\t\tlogging.Infof(\"Restarting miner [%s]\", b.MinerBinary.MainExecutableName)\n\t\terr := b.restart()\n\t\tif err != nil {\n\t\t\tlogging.Errorf(\"Error restarting miner: %v\", err)\n\t\t}\n\t\treturn RunningStateRestarting\n\t}\n\treturn RunningStateRunning\n}\n\nfunc (b *BinaryRunner) HashRate() uint64 {\n\treturn b.MinerImpl.HashRate()\n}\n\nfunc (b *BinaryRunner) restart() error {\n\tb.lastStarted = time.Now()\n\treturn b.launch(b.MinerImpl.ConstructCommandlineArgs(b.usedArgs), true)\n}\n\nfunc (b *BinaryRunner) Start(args BinaryArguments) error {\n\terr := b.Install()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb.usedArgs = args\n\tb.lastStarted = time.Now()\n\tb.rapidFails = 0\n\n\t// Check if there is a compatible GPU!\n\tif b.MinerImpl.AvailableGPUs() == 0 {\n\t\treturn fmt.Errorf(\"err_no_gpus\")\n\t}\n\n\t// Always do a fresh unpack of the executable to ensure there's been no funny\n\t// business. EnsureAvailable already checked the SHA hash.\n\terr = b.launch(b.MinerImpl.ConstructCommandlineArgs(args), true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (b *BinaryRunner) unpackDir() string {\n\treturn filepath.Join(util.DataDirectory(), \"miners\", fmt.Sprintf(\"unpacked-%s\", b.MinerBinary.Hash))\n}\n\nfunc (b *BinaryRunner) downloadPath() string {\n\treturn filepath.Join(util.DataDirectory(), \"miners\", b.MinerBinary.Hash)\n}\n\nfunc (b *BinaryRunner) launch(params []string, wait bool) error {\n\texePath := b.findExecutable()\n\tif exePath == \"\" {\n\t\treturn fmt.Errorf(\"Cannot find main miner binary in unpack folder\")\n\t}\n\tlogging.Debugf(\"Launching %s %v\\n\", exePath, params)\n\tb.cmd = exec.Command(exePath, params...)\n\tutil.PrepareBackgroundCommand(b.cmd)\n\tb.cmd.Dir = filepath.Dir(exePath)\n\tr, w := io.Pipe()\n\tgo func(b *BinaryRunner, rd io.Reader) {\n\t\tbr := bufio.NewReader(rd)\n\n\t\tfor {\n\t\t\tl, _, e := br.ReadLine()\n\t\t\tif e != nil {\n\t\t\t\tlogging.Debugf(\"%sError on readline from stdout/err: %s\", b.logPrefix(), e.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\tb.MinerImpl.ParseOutput(string(l))\n\t\t}\n\t}(b, r)\n\tb.cmd.Stderr = w\n\tb.cmd.Stdout = w\n\terr := b.cmd.Start()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif wait {\n\t\tb.running = true\n\t\tgo func() {\n\t\t\terr := b.cmd.Wait()\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error in miner: %v\", err)\n\t\t\t}\n\t\t\tb.running = false\n\t\t}()\n\t}\n\treturn nil\n}\n\nfunc (b *BinaryRunner) unpack() error {\n\tunpackDir := b.unpackDir()\n\n\tif _, err := os.Stat(unpackDir); !os.IsNotExist(err) {\n\t\tlogging.Debugf(\"%sRemoving unpack directory\", b.logPrefix())\n\t\ttime.Sleep(1 * time.Second) // Necessary on Windows to avoid permission error\n\t\terr = os.RemoveAll(unpackDir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif _, err := os.Stat(unpackDir); os.IsNotExist(err) {\n\t\tlogging.Debugf(\"%s(Re)creating unpack directory\", b.logPrefix())\n\t\terr = os.MkdirAll(unpackDir, 0755)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tarchive := b.downloadPath()\n\tif strings.HasSuffix(b.MinerBinary.Url, \".zip\") {\n\t\treturn util.UnpackZip(archive, unpackDir)\n\t} else if strings.HasSuffix(b.MinerBinary.Url, \".tar.gz\") || strings.HasSuffix(b.MinerBinary.Url, \".tgz\") {\n\t\treturn util.UnpackTar(archive, unpackDir)\n\t}\n\n\treturn fmt.Errorf(\"Unknown archive format, cannot unpack: %s\", b.MinerBinary.Url)\n}\n\nfunc (b *BinaryRunner) findExecutable() string {\n\tmainExecutablePath := \"\"\n\terr := filepath.Walk(b.unpackDir(),\n\t\tfunc(path string, info os.FileInfo, err error) error {\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif info.Name() == b.MinerBinary.MainExecutableName {\n\t\t\t\tmainExecutablePath = path\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\tif err != nil {\n\t\tlogging.Errorf(\"Error finding executable: %v\", err)\n\t}\n\treturn mainExecutablePath\n}\n\nfunc (b *BinaryRunner) ensureAvailable() error {\n\tfreshDownload := false\n\t_ = os.Mkdir(filepath.Join(util.DataDirectory(), \"miners\"), 0700)\n\tnodePath := b.downloadPath()\n\t_, err := os.Stat(nodePath)\n\tif os.IsNotExist(err) {\n\t\tlogging.Debugf(\"%sBinary not found, downloading...\", b.logPrefix())\n\t\tfreshDownload = true\n\t\terr := b.download()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if err != nil {\n\t\treturn err\n\t} else {\n\t\tlogging.Debugf(\"%sDaemon file already exists\", b.logPrefix())\n\t}\n\n\tshaSum, err := util.ShaSum(nodePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\texpectedHash, _ := hex.DecodeString(b.MinerBinary.Hash)\n\tif !bytes.Equal(shaSum, expectedHash) {\n\t\tlogging.Warnf(\"%sHash differs: [%x] vs [%s]\", b.logPrefix(), shaSum, b.MinerBinary.Hash)\n\t\tif !freshDownload {\n\t\t\terr = os.Remove(nodePath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn b.ensureAvailable()\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"%sFreshly downloaded node did not have correct SHA256 hash\", b.logPrefix())\n\t\t\tlogging.Error(err)\n\t\t\treturn err\n\t\t}\n\t}\n\n\tlogging.Debugf(\"%sDaemon file is available and correct\", b.logPrefix())\n\treturn nil\n}\n\nfunc (b *BinaryRunner) download() error {\n\tnodePath := b.downloadPath()\n\n\tresp, err := http.Get(b.MinerBinary.Url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\t// Create the file\n\tout, err := os.Create(nodePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer out.Close()\n\n\t// Write the body to file\n\t_, err = io.Copy(out, resp.Body)\n\tlogging.Debugf(\"%sDaemon file downloaded\", b.logPrefix())\n\treturn err\n}\n"
  },
  {
    "path": "miners/teamredminer.go",
    "content": "package miners\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\n// Compile time assertion on interface\nvar _ MinerImpl = &TeamRedMinerImpl{}\n\ntype TeamRedMinerImpl struct {\n\tbinaryRunner  *BinaryRunner\n\thashRates     map[int64]uint64\n\thashRatesLock sync.Mutex\n\tgpuCount      int8\n}\n\nfunc NewTeamRedMinerImpl(br *BinaryRunner) MinerImpl {\n\treturn &TeamRedMinerImpl{binaryRunner: br, hashRates: map[int64]uint64{}, hashRatesLock: sync.Mutex{}}\n}\n\nfunc (l *TeamRedMinerImpl) Configure(args BinaryArguments) error {\n\treturn nil\n}\n\nfunc (l *TeamRedMinerImpl) ParseOutput(line string) {\n\tif l.binaryRunner.Debug {\n\t\tlogging.Debugf(\"[teamRedMiner] %s\\n\", line)\n\t}\n\tline = strings.TrimSpace(line)\n\tif strings.Contains(line, \"] Detected\") && strings.Contains(line, \"devices, \") {\n\t\tstartCountIdx := strings.Index(line, \"] Detected \") + 11\n\t\tgpuCountString := line[startCountIdx : startCountIdx+1]\n\t\tlogging.Debugf(\"GPUCountString: %s\", gpuCountString)\n\t\tgpuCount64, _ := strconv.ParseInt(gpuCountString, 10, 8)\n\t\tl.gpuCount = int8(gpuCount64)\n\t\tlogging.Debugf(\"Set GPU Count to %d\", l.gpuCount)\n\t}\n\tif strings.Contains(line, \"] GPU \") && strings.Contains(line, \"lyra2rev3\") {\n\t\tstartDeviceIdx := strings.Index(line, \"] GPU \")\n\t\tendDeviceIdx := strings.Index(line[startDeviceIdx:], \"[\")\n\t\tdeviceIdxString := line[startDeviceIdx+6 : startDeviceIdx+endDeviceIdx-1]\n\t\tdeviceIdx, err := strconv.ParseInt(deviceIdxString, 10, 64)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tstartMHs := strings.Index(line, \"lyra2rev3: \")\n\t\tif startMHs > -1 {\n\t\t\tendMHs := strings.Index(line[startMHs:], \"h/s\")\n\t\t\thashRateUnit := strings.ToUpper(line[startMHs+endMHs-1 : startMHs+endMHs])\n\t\t\tline = line[startMHs+11 : startMHs+endMHs-1]\n\t\t\tf, err := strconv.ParseFloat(line, 64)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error parsing hashrate: %s\\n\", err.Error())\n\t\t\t}\n\t\t\tif hashRateUnit == \"K\" {\n\t\t\t\tf = f * 1000\n\t\t\t} else if hashRateUnit == \"M\" {\n\t\t\t\tf = f * 1000 * 1000\n\t\t\t} else if hashRateUnit == \"G\" {\n\t\t\t\tf = f * 1000 * 1000 * 1000\n\t\t\t}\n\t\t\tl.hashRatesLock.Lock()\n\t\t\tl.hashRates[deviceIdx] = uint64(f)\n\t\t\tl.hashRatesLock.Unlock()\n\t\t}\n\t}\n}\n\nfunc (l *TeamRedMinerImpl) HashRate() uint64 {\n\ttotalHash := uint64(0)\n\tl.hashRatesLock.Lock()\n\tfor _, h := range l.hashRates {\n\t\ttotalHash += h\n\t}\n\tl.hashRatesLock.Unlock()\n\treturn totalHash\n}\n\nfunc (l *TeamRedMinerImpl) ConstructCommandlineArgs(args BinaryArguments) []string {\n\treturn []string{\"--log_interval=10\", \"--disable_colors\", \"-a\", \"lyra2rev3\", \"-o\", args.StratumUrl, \"-u\", args.StratumUsername, \"-p\", args.StratumPassword}\n}\n\nfunc (l *TeamRedMinerImpl) AvailableGPUs() int8 {\n\terr := l.binaryRunner.launch([]string{\"--list_devices\"}, false)\n\tif err != nil {\n\t\treturn 0\n\t}\n\terr = l.binaryRunner.cmd.Wait()\n\tif err != nil {\n\t\treturn 0\n\t}\n\t// Output is caught by ParseOuput function above and this will set the gpuCount accordingly\n\treturn l.gpuCount\n}\n"
  },
  {
    "path": "miners/verthashminer.go",
    "content": "package miners\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\n// Compile time assertion on interface\nvar _ MinerImpl = &VerthashMinerImpl{}\n\nvar cfgPath = \"verthash-miner-tmpl.conf\"\n\ntype VerthashMinerImpl struct {\n\tbinaryRunner  *BinaryRunner\n\tclhashRates   map[int64]uint64\n\tcuhashRates   map[int64]uint64\n\thashRatesLock sync.Mutex\n}\n\nfunc (l *VerthashMinerImpl) generateTempConf() error {\n\tos.Remove(filepath.Join(util.DataDirectory(), cfgPath))\n\terr := l.binaryRunner.launch([]string{\"--gen-conf\", filepath.Join(util.DataDirectory(), cfgPath)}, false)\n\tvar err2 error\n\tif l.binaryRunner.cmd != nil {\n\t\terr2 = l.binaryRunner.cmd.Wait()\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err2 != nil {\n\t\treturn err2\n\t}\n\treturn nil\n}\n\nfunc NewVerthashMinerImpl(br *BinaryRunner) MinerImpl {\n\treturn &VerthashMinerImpl{binaryRunner: br, clhashRates: map[int64]uint64{}, cuhashRates: map[int64]uint64{}, hashRatesLock: sync.Mutex{}}\n}\n\nfunc (l *VerthashMinerImpl) Configure(args BinaryArguments) error {\n\terr := l.generateTempConf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !l.binaryRunner.cmd.ProcessState.Success() {\n\t\treturn fmt.Errorf(\"Was unable to configure VerthashMiner. Exit code %d\", l.binaryRunner.cmd.ProcessState.ExitCode())\n\t}\n\n\tin, err := os.Open(filepath.Join(util.DataDirectory(), \"verthash-miner-tmpl.conf\"))\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn err\n\t}\n\tdefer in.Close()\n\n\tos.Remove(filepath.Join(util.DataDirectory(), \"verthash-miner.conf\"))\n\tout, err := os.Create(filepath.Join(util.DataDirectory(), \"verthash-miner.conf\"))\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn err\n\t}\n\tdefer func() {\n\t\terr := out.Close()\n\t\tif err != nil {\n\t\t\tlogging.Error(err)\n\t\t}\n\t}()\n\n\tvar parsedDevices map[int]util.VerthashMinerDeviceConfig\n\n\tscanner := bufio.NewScanner(in)\n\tskip := false\n\tinsideDeviceBlock := false\n\tdeviceBlockStr := \"\"\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.HasPrefix(line, \"#\") {\n\t\t\tskip = false\n\t\t}\n\t\tif strings.HasPrefix(line, \"<Connection\") {\n\t\t\t_, err = out.WriteString(fmt.Sprintf(\"<Connection Url = \\\"%s\\\"\\n\\tUsername = \\\"%s\\\"\\n\\tPassword = \\\"%s\\\"\\n\\tAlgorithm = \\\"Verthash\\\">\\n\\n\", args.StratumUrl, args.StratumUsername, args.StratumPassword))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tskip = true\n\t\t}\n\t\tif strings.HasPrefix(line, \"<Global\") {\n\t\t\t_, err = out.WriteString(fmt.Sprintf(\"<Global Debug=\\\"false\\\" VerthashDataFileVerification=\\\"false\\\" VerthashDataFile=\\\"%s\\\">\\n\\n\", filepath.Join(util.DataDirectory(), \"verthash.dat\")))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tskip = true\n\t\t}\n\n\t\tif strings.Contains(line, \"OpenCL device config\") || strings.Contains(line, \"CUDA Device config\") {\n\t\t\tlogging.Debug(\"Entering device block\")\n\t\t\tinsideDeviceBlock = true\n\t\t} else if insideDeviceBlock {\n\t\t\tdeviceBlockStr += line + \"\\n\"\n\t\t}\n\n\t\tif strings.Contains(line, \"#-#-#-#-#-#-#-#-#-#-#-\") && insideDeviceBlock {\n\t\t\tinsideDeviceBlock = false\n\t\t\tparsedDevices = util.ParseVerthashMinerDeviceCfg(deviceBlockStr)\n\t\t\tlogging.Debug(\"Exiting device block\")\n\t\t\tlogging.Debug(parsedDevices[0])\n\t\t\tdeviceBlockStr = \"\"\n\t\t}\n\n\t\tif strings.HasPrefix(line, \"<CL_Device\") {\n\t\t\twords := strings.SplitAfter(line, \" \")\n\t\t\tthisDeviceIndexNumber, _ := strconv.Atoi(strings.Trim(words[3], \"\\\"\"))\n\n\t\t\tif device, ok := parsedDevices[thisDeviceIndexNumber]; ok {\n\t\t\t\tif strings.Contains(device.Platform, \"Intel\") && !args.EnableIntegrated {\n\t\t\t\t\tlogging.Debug(\"Intel disabled.\")\n\t\t\t\t\tskip = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !skip {\n\t\t\t_, err = out.WriteString(fmt.Sprintf(\"%s\\n\", line))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (l *VerthashMinerImpl) ParseOutput(line string) {\n\tif l.binaryRunner.Debug {\n\t\tlogging.Debugf(\"[VerthashMiner] %s\\n\", line)\n\t}\n\tline = strings.TrimSpace(line)\n\tif strings.Contains(line, \"_device(\") && strings.HasSuffix(line, \"H/s\") {\n\t\tstartMHs := strings.LastIndex(line, \": \")\n\t\tif startMHs > -1 {\n\t\t\tdeviceIdxStart := strings.Index(line, \"_device(\") + 8\n\t\t\tdeviceTypeStart := strings.Index(line, \"_device(\") - 2\n\t\t\tdeviceIdxEnd := strings.Index(line[deviceIdxStart:], \")\")\n\t\t\tdeviceIdxString := line[deviceIdxStart : deviceIdxStart+deviceIdxEnd]\n\t\t\tdeviceIdx, _ := strconv.ParseInt(deviceIdxString, 10, 64)\n\t\t\tdeviceType := line[deviceTypeStart : deviceTypeStart+2]\n\n\t\t\thashRateUnit := strings.ToUpper(line[len(line)-4 : len(line)-3])\n\t\t\tline = line[startMHs+2 : len(line)-5]\n\t\t\tf, err := strconv.ParseFloat(line, 64)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error parsing hashrate: %s\\n\", err.Error())\n\t\t\t}\n\t\t\tif hashRateUnit == \"K\" {\n\t\t\t\tf = f * 1000\n\t\t\t} else if hashRateUnit == \"M\" {\n\t\t\t\tf = f * 1000 * 1000\n\t\t\t} else if hashRateUnit == \"G\" {\n\t\t\t\tf = f * 1000 * 1000 * 1000\n\t\t\t}\n\n\t\t\tl.hashRatesLock.Lock()\n\t\t\tif deviceType == \"cu\" {\n\t\t\t\tl.cuhashRates[deviceIdx] = uint64(f)\n\t\t\t} else {\n\t\t\t\tl.clhashRates[deviceIdx] = uint64(f)\n\t\t\t}\n\t\t\tl.hashRatesLock.Unlock()\n\t\t}\n\t}\n}\n\nfunc (l *VerthashMinerImpl) HashRate() uint64 {\n\ttotalHash := uint64(0)\n\tl.hashRatesLock.Lock()\n\tfor _, h := range l.cuhashRates {\n\t\ttotalHash += h\n\t}\n\tfor _, h := range l.clhashRates {\n\t\ttotalHash += h\n\t}\n\tl.hashRatesLock.Unlock()\n\n\treturn totalHash\n}\n\nfunc (l *VerthashMinerImpl) ConstructCommandlineArgs(args BinaryArguments) []string {\n\treturn []string{\"--conf\", filepath.Join(util.DataDirectory(), \"verthash-miner.conf\")}\n}\n\nfunc (l *VerthashMinerImpl) AvailableGPUs() int8 {\n\tlogging.Debugf(\"AvailableGPUs called\\n\")\n\ttmpCfg := filepath.Join(util.DataDirectory(), \"verthash-miner-tmp.conf\")\n\terr := l.binaryRunner.launch([]string{\"--gen-conf\", tmpCfg}, false)\n\terr2 := l.binaryRunner.cmd.Wait()\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn 0\n\t}\n\tif err2 != nil {\n\t\tlogging.Error(err)\n\t\treturn 0\n\t}\n\n\tif !l.binaryRunner.cmd.ProcessState.Success() {\n\t\tlogging.Errorf(\"Process state: %d\", l.binaryRunner.cmd.ProcessState)\n\t\treturn 0\n\t}\n\n\tin, err := os.Open(tmpCfg)\n\tif err != nil {\n\t\tlogging.Error(err)\n\t\treturn 0\n\t}\n\tgpu := int8(0)\n\tscanner := bufio.NewScanner(in)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.HasPrefix(line, \"<CL_Device\") {\n\t\t\tgpu++\n\t\t}\n\t\tif strings.HasPrefix(line, \"<CU_Device\") {\n\t\t\tgpu++\n\t\t}\n\t}\n\tin.Close()\n\tos.Remove(tmpCfg)\n\treturn gpu\n}\n"
  },
  {
    "path": "miners.json",
    "content": "[\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"AMD\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"INTEL\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"NVIDIA\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"AMD\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"minerPrerequisites\" : [\n            \"amddriverlinux\"\n        ],\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"INTEL\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"NVIDIA\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : false,\n        \"blockHeightMin\": 1499999,\n        \"blockHeightMax\": -1,\n        \"minerPrerequisites\" : [\n            \"nvidiadriverlinux\"\n        ],\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"AMD\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"INTEL\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"windows\",\n        \"gpuplatform\" : \"NVIDIA\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-windows.zip\",\n        \"sha256\" : \"e5af5ab19154f6ee57db22645a43200336e8017865c71505ae669af19243449e\",\n        \"mainExecutableName\" : \"VerthashMiner.exe\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"AMD\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"minerPrerequisites\" : [\n            \"amddriverlinux\"\n        ],\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"INTEL\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"multiGPUMiner\": true\n    },\n    {\n        \"platform\": \"linux\",\n        \"gpuplatform\" : \"NVIDIA\",\n        \"url\" : \"https://github.com/CryptoGraphics/VerthashMiner/releases/download/0.7.2/VerthashMiner-0.7.2-CUDA11-linux.tar.gz\",\n        \"sha256\" : \"a7c3e6b0a7a937eb9e9d88de24a16a7b13f518d858fffd07694a21bc724d9a8c\",\n        \"mainExecutableName\" : \"VerthashMiner\",\n        \"closedSource\" : false,\n        \"testnet\" : true,\n        \"minerPrerequisites\" : [\n            \"nvidiadriverlinux\"\n        ],\n        \"multiGPUMiner\": true\n    }\n]\n"
  },
  {
    "path": "networks/networks.go",
    "content": "package networks\n\ntype Network struct {\n\tBase58P2PKHVersion byte\n\tBase58P2SHVersion  byte\n\tInsightURL         string\n\tBech32Prefix       string\n\tP2ProxyStratum     string\n\tP2ProxyURL         string\n\tWalletDB           string\n\tOCMBackend         string\n\tBackendServers     []string\n}\n\nvar Active Network\n\nfunc SetNetwork(testnet bool) {\n\tif testnet {\n\t\tActive = Network{\n\t\t\tBase58P2PKHVersion: 74,\n\t\t\tBase58P2SHVersion:  196,\n\t\t\tInsightURL:         \"https://vtc-insight-testnet.gertjaap.org/\",\n\t\t\tBech32Prefix:       \"tvtc\",\n\t\t\tP2ProxyStratum:     \"stratum+tcp://p2proxy-testnet.gertjaap.org:9171\",\n\t\t\tP2ProxyURL:         \"https://p2proxy-testnet.gertjaap.org/\",\n\t\t\tWalletDB:           \"wallet-testnet.db\",\n\t\t}\n\t} else {\n\t\tActive = Network{\n\t\t\tBase58P2PKHVersion: 71,\n\t\t\tBase58P2SHVersion:  5,\n\t\t\tInsightURL:         \"https://insight.vertcoin.org/\",\n\t\t\tBech32Prefix:       \"vtc\",\n\t\t\tP2ProxyStratum:     \"stratum+tcp://p2proxy.vertcoin.org:9171\",\n\t\t\tP2ProxyURL:         \"https://p2proxy.vertcoin.org/\",\n\t\t\tWalletDB:           \"wallet-testnet.db\",\n\t\t\tBackendServers: []string{\n\t\t\t\t\"https://ocmbackend.javerity.com/\",\n\t\t\t\t\"https://ocmbackend.mindcraftblocks.com/\"},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "p2pool_nodes.json",
    "content": "[\n\t{\n\t\t\"Hostname\": \"mindcraftblocks.com\",\n\t\t\"Stratum\":  \"stratum+tcp://mindcraftblocks.com:9171\",\n\t\t\"URL\":      \"http://mindcraftblocks.com:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"vtc-fl.javerity.com\",\n\t\t\"Stratum\":  \"stratum+tcp://vtc-fl.javerity.com:9171\",\n\t\t\"URL\":      \"http://vtc-fl.javerity.com:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"vtc-ca.javerity.com\",\n\t\t\"Stratum\":  \"stratum+tcp://vtc-ca.javerity.com:9171\",\n\t\t\"URL\":      \"http://vtc-ca.javerity.com:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"p2p-usa.xyz\",\n\t\t\"Stratum\":  \"stratum+tcp://p2p-usa.xyz:9171\",\n\t\t\"URL\":      \"http://p2p-usa.xyz:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"p2p-ekb.xyz\",\n\t\t\"Stratum\":  \"stratum+tcp://p2p-ekb.xyz:9171\",\n\t\t\"URL\":      \"http://p2p-ekb.xyz:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"p2p-spb.xyz\",\n\t\t\"Stratum\":  \"stratum+tcp://p2p-spb.xyz:9171\",\n\t\t\"URL\":      \"http://p2p-spb.xyz:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"p2p-south.xyz\",\n\t\t\"Stratum\":  \"stratum+tcp://p2p-south.xyz:9171\",\n\t\t\"URL\":      \"http://p2p-south.xyz:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"boofpool.ddns.net\",\n\t\t\"Stratum\":  \"stratum+tcp://boofpool.ddns.net:9171\",\n\t\t\"URL\":      \"http://boofpool.ddns.net:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"vtc-ut.myangelprints.com\",\n\t\t\"Stratum\":  \"stratum+tcp://vtc-ut.myangelprints.com:9171\",\n\t\t\"URL\":      \"http://vtc-ut.myangelprints.com:9171/\"\n\t},\n\t{\n\t\t\"Hostname\": \"vtc-brn.webhop.me\",\n\t\t\"Stratum\":  \"stratum+tcp://vtc-brn.webhop.me:9171\",\n\t\t\"URL\":      \"http://vtc-brn.webhop.me:9171/\"\n\t}\n]\n"
  },
  {
    "path": "ping/ping.go",
    "content": "package ping\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-ping/ping\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\ntype Conditions struct {\n\tMaxFee      float64\n\tMaxMiners   int\n\tMaxNextPing time.Duration\n\tPingPackets int\n\tPingTimeout time.Duration\n}\n\nvar Set = Conditions{\n\tMaxFee:      2,\n\tMaxMiners:   35,\n\tMaxNextPing: 25 * time.Millisecond, //Prevents the miner from using a node with too high latency compared to other nodes. Should prevent the miner from using nodes outside of their region\n\tPingPackets: 2,\n\tPingTimeout: 2000000000,\n}\n\ntype SelectedNode struct {\n\tP2PoolStratum string\n\tP2PoolURL     string\n}\n\ntype Nodes struct {\n\tHostname string `json:\"Hostname\"`\n\tStratum  string `json:\"Stratum\"`\n\tURL      string `json:\"URL\"`\n\tPingTime time.Duration\n}\n\nvar Selected SelectedNode\n\nfunc GetSelectedNode(testnet bool) {\n\tif testnet {\n\t\tSelected = SelectedNode{\n\t\t\tP2PoolStratum: networks.Active.P2ProxyStratum,\n\t\t\tP2PoolURL:     networks.Active.P2ProxyURL,\n\t\t}\n\t} else {\n\t\tselector()\n\t}\n}\n\nfunc selector() {\n\t_, err := GetNodeInformation(\"http://127.0.0.1:9171/\")\n\tif err == nil {\n\t\tlogging.Infof(\"Selected local p2pool node\\n\")\n\t\tSelected = SelectedNode{\n\t\t\tP2PoolStratum: \"stratum+tcp://127.0.0.1:9171\",\n\t\t\tP2PoolURL:     \"http://127.0.0.1:9171/\",\n\t\t}\n\t} else {\n\t\tlogging.Infof(\"No local node detected, selecting other public nodes\\n\")\n\n\t\tNodeList := []Nodes{}\n\t\terr = util.GetJson(\"https://raw.githubusercontent.com/vertcoin-project/one-click-miner-vnext/master/p2pool_nodes.json\", &NodeList)\n\n\t\t//If there's an error fetching the node list the user will just be pointed to p2proxy\n\t\tif err != nil {\n\t\t\tlogging.Warnf(\"P2pool nodes could not be fetched, using p2proxy as failover\\n\")\n\t\t\tSelected = SelectedNode{\n\t\t\t\tP2PoolStratum: \"stratum+tcp://vtc-ca.javerity.com:9171\",\n\t\t\t\tP2PoolURL:     \"http://vtc-ca.javerity.com:9171/\",\n\t\t\t}\n\t\t}\n\n\t\terr = PingNodes(NodeList)\n\t\tif err != nil {\n\t\t\tlogging.Warnf(\"Nodes could not be pinged, selecting random node\\n\")\n\t\t\trandInt := rand.Intn(len(NodeList))\n\t\t\tSelected = SelectedNode{\n\t\t\t\tP2PoolStratum: NodeList[randInt].Stratum,\n\t\t\t\tP2PoolURL:     NodeList[randInt].URL,\n\t\t\t}\n\t\t\tlogging.Infof(\"%s has been randomly selected\\n\", NodeList[randInt].Hostname)\n\t\t} else {\n\n\t\t\tsort.Slice(NodeList, func(i, j int) bool {\n\t\t\t\treturn NodeList[i].PingTime < NodeList[j].PingTime\n\t\t\t})\n\n\t\t\tfor i := 0; i < len(NodeList); i++ {\n\t\t\t\tif NodeList[i].PingTime == 0 { // We need to skip nodes with a pingTime of 0ms, they're either not active or they're not responding to pings and OCM will select it if it responds to the following requests.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnodeInformation, _ := GetNodeInformation(NodeList[i].URL)\n\t\t\t\tfee := CheckFee(nodeInformation)\n\t\t\t\tif fee {\n\t\t\t\t\tcurrentMiners := CheckCurrentMiners(nodeInformation)\n\t\t\t\t\tif currentMiners {\n\t\t\t\t\t\tSelected = SelectedNode{\n\t\t\t\t\t\t\tP2PoolStratum: NodeList[i].Stratum,\n\t\t\t\t\t\t\tP2PoolURL:     NodeList[i].URL,\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlogging.Infof(\"%s selected, fulfilled all requirements\\n\", NodeList[i].Hostname)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} else { //If the node fulfills the max fee requirement but there is more than the set MaxNextping to the next node it will select the current\n\t\t\t\t\t\tdetermineNextPingTime := NodeList[i+1].PingTime\n\t\t\t\t\t\tdetermineNextPingTime -= NodeList[i].PingTime\n\t\t\t\t\t\tif determineNextPingTime > Set.MaxNextPing {\n\t\t\t\t\t\t\tSelected = SelectedNode{\n\t\t\t\t\t\t\t\tP2PoolStratum: NodeList[i].Stratum,\n\t\t\t\t\t\t\t\tP2PoolURL:     NodeList[i].URL,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlogging.Infof(\"%s selected, next node has too high ping time\\n\", NodeList[i].Hostname)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlogging.Warnf(\"%s had more than %v miners, trying new inorder to retain efficiency\\n\", NodeList[i].Hostname, Set.MaxMiners)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlogging.Warnf(\"%s is either unreachable or had more than a %f fee, trying new\\n\", NodeList[i].Hostname, Set.MaxFee)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc PingNodes(NodeList []Nodes) error {\n\tvar wg sync.WaitGroup\n\tvar errPing error\n\tfor i := 0; i < len(NodeList); i++ {\n\t\twg.Add(1)\n\n\t\tgo func(NodeList []Nodes) {\n\t\t\tdefer wg.Done()\n\n\t\t\tpinger, err := ping.NewPinger(NodeList[i].Hostname)\n\t\t\tpinger.SetPrivileged(true)       //This line is needed for windows because of ICMP\n\t\t\tpinger.Timeout = Set.PingTimeout //Sets the time for which the pinger will timeout regardless of how many packets there has been recieved\n\t\t\tif err != nil {\n\t\t\t\tlogging.Warn(\"Error: Check if you are connected to the internet\")\n\t\t\t\tlogging.Warn(err)\n\t\t\t\terrPing = err\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpinger.Count = Set.PingPackets //Number of packets to be sent to each node\n\t\t\terr = pinger.Run()\n\t\t\tif err != nil {\n\t\t\t\tlogging.Warn(\"Error: Check if you are connected to the internet\")\n\t\t\t\tlogging.Warn(err)\n\t\t\t\terrPing = err\n\t\t\t\treturn\n\t\t\t}\n\t\t\tNodeList[i].PingTime = pinger.Statistics().AvgRtt\n\t\t\tlogging.Infof(\"%s: %v \\n\", NodeList[i].Hostname, NodeList[i].PingTime)\n\t\t}(NodeList)\n\t}\n\twg.Wait()\n\tif errPing != nil {\n\t\treturn errPing\n\t}\n\treturn nil\n}\n\n// Instead of making a http request to the node each time we need to get information, we do it once and then reuse the collected data.\nfunc GetNodeInformation(NodeURL string) (jsonPayload map[string]interface{}, err error) {\n\terr = util.GetJson(fmt.Sprintf(\"%slocal_stats\", NodeURL), &jsonPayload)\n\tif err != nil {\n\t\tif NodeURL != \"http://127.0.0.1:9171/\" {\n\t\t\tlogging.Errorf(\"Unable to fetch node information\\n\", err.Error())\n\t\t}\n\t\treturn jsonPayload, err\n\t}\n\treturn jsonPayload, nil\n}\n\nfunc CheckFee(jsonPayload map[string]interface{}) bool {\n\tfee, ok := jsonPayload[\"fee\"].(float64)\n\tif !ok {\n\t\treturn false\n\t}\n\tdonationFee, ok := jsonPayload[\"donation_proportion\"].(float64)\n\tif !ok {\n\t\treturn false\n\t}\n\tfee += donationFee\n\treturn fee <= Set.MaxFee\n}\n\n// To ensure efficiency of the selected p2pool node a limit of miners has been put in place, returns true if the number is equal to Maxminers or below\nfunc CheckCurrentMiners(jsonPayload map[string]interface{}) bool {\n\tcurrentMiners, _ := jsonPayload[\"miner_hash_rates\"].(string)\n\treturn len(currentMiners) <= Set.MaxMiners\n}\n"
  },
  {
    "path": "pools/miningpoolsweden.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &MiningpoolSweden{}\n\ntype MiningpoolSweden struct {\n\tAddress           string\n\tLastFetchedPayout time.Time\n\tLastPayout        uint64\n}\n\nfunc NewMiningpoolSweden(addr string) *MiningpoolSweden {\n\treturn &MiningpoolSweden{Address: addr}\n}\n\nfunc (p *MiningpoolSweden) GetPendingPayout() uint64 {\n\tjsonPayload := map[string]interface{}{}\n\terr := util.GetJson(fmt.Sprintf(\"https://api.miningpoolsweden.eu/api/pools/vert1/miners/%s\", p.Address), &jsonPayload)\n\tif err != nil {\n\t\treturn 0\n\t}\n\tvtc, ok := jsonPayload[\"pendingBalance\"].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\tvtc *= 100000000\n\treturn uint64(vtc)\n}\n\nfunc (p *MiningpoolSweden) GetStratumUrl() string {\n\treturn \"stratum+tcp://vtc.miningpoolsweden.eu:3052\"\n}\n\nfunc (p *MiningpoolSweden) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *MiningpoolSweden) GetPassword() string {\n\treturn \"x\"\n}\n\nfunc (p *MiningpoolSweden) GetID() int {\n\treturn 9\n}\n\nfunc (p *MiningpoolSweden) GetName() string {\n\treturn \"MiningpoolSweden.eu\"\n}\n\nfunc (p *MiningpoolSweden) GetFee() float64 {\n\treturn 0.6\n}\n\nfunc (p *MiningpoolSweden) OpenBrowserPayoutInfo(addr string) {\n\tutil.OpenBrowser(fmt.Sprintf(\"https://miningpoolsweden.eu/?#vert1/dashboard?address=%s\", addr))\n}\n"
  },
  {
    "path": "pools/p2pool.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/ping\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &P2Pool{}\n\ntype P2Pool struct {\n\tAddress           string\n\tLastFetchedPayout time.Time\n\tLastPayout        uint64\n\tLastFetchedFee    time.Time\n\tLastFee           float64\n}\n\nfunc NewP2Pool(addr string) *P2Pool {\n\treturn &P2Pool{Address: addr}\n}\n\nfunc (p *P2Pool) GetPendingPayout() uint64 {\n\tif time.Since(p.LastFetchedPayout) > time.Minute*2 {\n\t\tjsonPayload := map[string]interface{}{}\n\t\terr := util.GetJson(fmt.Sprintf(\"%scurrent_payouts\", ping.Selected.P2PoolURL), &jsonPayload)\n\t\tif err != nil {\n\t\t\tlogging.Warnf(\"Unable to fetch p2pool payouts: %s\", err.Error())\n\t\t\tp.LastPayout = 0\n\t\t}\n\t\taddress := p.Address\n\t\tvtc, ok := jsonPayload[address].(float64)\n\t\tif !ok {\n\t\t\tp.LastFetchedPayout = time.Now()\n\t\t\tp.LastPayout = 0\n\t\t}\n\t\tvtc *= 100000000\n\t\tp.LastFetchedPayout = time.Now()\n\t\tp.LastPayout = uint64(vtc)\n\t}\n\treturn p.LastPayout\n}\n\nfunc (p *P2Pool) GetStratumUrl() string {\n\treturn ping.Selected.P2PoolStratum\n}\n\nfunc (p *P2Pool) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *P2Pool) GetPassword() string {\n\treturn \"x\"\n}\n\nfunc (p *P2Pool) GetID() int {\n\treturn 2\n}\n\nfunc (p *P2Pool) GetName() string {\n\treturn \"P2Pool\"\n}\n\nfunc (p *P2Pool) GetFee() (fee float64) {\n\tif time.Since(p.LastFetchedFee) > time.Minute*30 {\n\t\tjsonPayload := map[string]interface{}{}\n\t\terr := util.GetJson(fmt.Sprintf(\"%slocal_stats\", ping.Selected.P2PoolURL), &jsonPayload)\n\t\tif err != nil {\n\t\t\tlogging.Warnf(\"Unable to fetch p2pool fee: %s\", err.Error())\n\t\t\treturn 2.0\n\t\t}\n\t\tfee, ok := jsonPayload[\"fee\"].(float64)\n\t\tif !ok {\n\t\t\treturn 2.0\n\t\t}\n\t\tdonationFee, ok := jsonPayload[\"donation_proportion\"].(float64)\n\t\tif !ok {\n\t\t\treturn 2.0\n\t\t}\n\t\tfee += donationFee\n\t\tp.LastFetchedFee = time.Now()\n\t\tp.LastFee = float64(fee)\n\t}\n\treturn p.LastFee\n}\n\nfunc (p *P2Pool) OpenBrowserPayoutInfo(addr string) {\n\tutil.OpenBrowser(ping.Selected.P2PoolURL)\n}\n"
  },
  {
    "path": "pools/p2proxy.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &P2Proxy{}\n\ntype P2Proxy struct {\n\tAddress string\n}\n\nfunc NewP2Proxy(addr string) *P2Proxy {\n\treturn &P2Proxy{Address: addr}\n}\n\nfunc (p *P2Proxy) GetPendingPayout() uint64 {\n\tjsonPayload := map[string]interface{}{}\n\terr := util.GetJson(fmt.Sprintf(\"%sapi/balance?address=%s\", networks.Active.P2ProxyURL, p.Address), &jsonPayload)\n\tif err != nil {\n\t\treturn 0\n\t}\n\tvtc, ok := jsonPayload[p.Address].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\tvtc *= 100000000\n\treturn uint64(vtc)\n}\n\nfunc (p *P2Proxy) GetStratumUrl() string {\n\treturn networks.Active.P2ProxyStratum\n}\n\nfunc (p *P2Proxy) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *P2Proxy) GetPassword() string {\n\treturn \"x\"\n}\n\nfunc (p *P2Proxy) GetID() int {\n\treturn 1\n}\n\nfunc (p *P2Proxy) GetName() string {\n\treturn \"P2Proxy\"\n}\n\nfunc (p *P2Proxy) GetFee() float64 {\n\treturn 1.00\n}\n\nfunc (p *P2Proxy) OpenBrowserPayoutInfo(addr string) {}\n"
  },
  {
    "path": "pools/pool.go",
    "content": "package pools\n\ntype Pool interface {\n\tGetPendingPayout() uint64\n\tGetStratumUrl() string\n\tGetUsername() string\n\tGetPassword() string\n\tGetName() string\n\tGetID() int\n\tGetFee() float64\n\tOpenBrowserPayoutInfo(addr string)\n}\n\nfunc GetPools(addr string, testnet bool) []Pool {\n\tif testnet {\n\t\treturn []Pool{\n\t\t\tNewP2Proxy(addr),\n\t\t}\n\t}\n\treturn []Pool{\n\t\tNewZergpool(addr),\n\t\tNewSuprnova(addr),\n\t\tNewP2Pool(addr),\n\t\tNewzpool(addr),\n\t\tNewMiningpoolSweden(addr),\n\t}\n}\n\nfunc GetPool(pool int, addr string, testnet bool) Pool {\n\tpools := GetPools(addr, testnet)\n\tfor _, p := range pools {\n\t\tif p.GetID() == pool {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn pools[0]\n}\n"
  },
  {
    "path": "pools/suprnova.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &Suprnova{}\n\ntype Suprnova struct {\n\tAddress           string\n\tLastFetchedPayout time.Time\n\tLastPayout        uint64\n}\n\nfunc NewSuprnova(addr string) *Suprnova {\n\treturn &Suprnova{Address: addr}\n}\n\nfunc (p *Suprnova) GetPendingPayout() uint64 {\n\tjsonPayload := map[string]interface{}{}\n\terr := util.GetJson(fmt.Sprintf(\"https://vtc.suprnova.cc/index.php?page=api&action=getuserbalance&api_key=%s\", p.Address), &jsonPayload)\n\tif err != nil {\n\t\treturn 0\n\t}\n\tel, ok := jsonPayload[\"getuserbalance\"].(map[string]interface{})\n\tif !ok {\n\t\treturn 0\n\t}\n\tel, ok = el[\"data\"].(map[string]interface{})\n\tif !ok {\n\t\treturn 0\n\t}\n\n\tconfirmed, ok := el[\"confirmed\"].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\n\tunconfirmed, ok := el[\"unconfirmed\"].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\n\tvtc := confirmed + unconfirmed\n\tvtc *= 100000000\n\treturn uint64(vtc)\n}\n\nfunc (p *Suprnova) GetStratumUrl() string {\n\treturn \"stratum+tcp://vtc.suprnova.cc:1776\"\n}\n\nfunc (p *Suprnova) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *Suprnova) GetPassword() string {\n\treturn \"x\"\n}\n\nfunc (p *Suprnova) GetID() int {\n\treturn 4\n}\n\nfunc (p *Suprnova) GetName() string {\n\treturn \"Suprnova.cc\"\n}\n\nfunc (p *Suprnova) GetFee() float64 {\n\treturn 1.00\n}\n\nfunc (p *Suprnova) OpenBrowserPayoutInfo(addr string) {\n\tutil.OpenBrowser(fmt.Sprintf(\"https://vtc.suprnova.cc/index.php?page=anondashboard&user=%s\", addr))\n}\n"
  },
  {
    "path": "pools/zergpool.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &Zergpool{}\n\ntype Zergpool struct {\n\tAddress           string\n\tLastFetchedPayout time.Time\n\tLastPayout        uint64\n}\n\nfunc NewZergpool(addr string) *Zergpool {\n\treturn &Zergpool{Address: addr}\n}\n\nfunc (p *Zergpool) GetPendingPayout() uint64 {\n\tjsonPayload := map[string]interface{}{}\n\terr := util.GetJson(fmt.Sprintf(\"https://api.zergpool.com:8443/api/wallet?address=%s\", p.Address), &jsonPayload)\n\tif err != nil {\n\t\treturn 0\n\t}\n\tvtc, ok := jsonPayload[\"unpaid\"].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\tvtc *= 100000000\n\treturn uint64(vtc)\n}\n\nfunc (p *Zergpool) GetStratumUrl() string {\n\treturn \"stratum+tcp://verthash.mine.zergpool.com:4534\"\n}\n\nfunc (p *Zergpool) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *Zergpool) GetPassword() string {\n\treturn \"c=VTC,mc=VTC\"\n}\n\nfunc (p *Zergpool) GetID() int {\n\treturn 5\n}\n\nfunc (p *Zergpool) GetName() string {\n\treturn \"Zergpool.com\"\n}\n\nfunc (p *Zergpool) GetFee() float64 {\n\treturn 0.50\n}\n\nfunc (p *Zergpool) OpenBrowserPayoutInfo(addr string) {\n\tutil.OpenBrowser(fmt.Sprintf(\"https://zergpool.com/?address=%s\", addr))\n}\n"
  },
  {
    "path": "pools/zpool.go",
    "content": "package pools\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nvar _ Pool = &zpool{}\n\ntype zpool struct {\n\tAddress           string\n\tLastFetchedPayout time.Time\n\tLastPayout        uint64\n}\n\nfunc Newzpool(addr string) *zpool {\n\treturn &zpool{Address: addr}\n}\n\nfunc (p *zpool) GetPendingPayout() uint64 {\n\tjsonPayload := map[string]interface{}{}\n\terr := util.GetJson(fmt.Sprintf(\"https://zpool.ca/api/wallet?address=%s\", p.Address), &jsonPayload)\n\tif err != nil {\n\t\treturn 0\n\t}\n\tvtc, ok := jsonPayload[\"unpaid\"].(float64)\n\tif !ok {\n\t\treturn 0\n\t}\n\tvtc *= 100000000\n\treturn uint64(vtc)\n}\n\nfunc (p *zpool) GetStratumUrl() string {\n\treturn \"stratum+tcp://verthash.mine.zpool.ca:6144\"\n}\n\nfunc (p *zpool) GetUsername() string {\n\treturn p.Address\n}\n\nfunc (p *zpool) GetPassword() string {\n\treturn \"c=VTC,zap=VTC\"\n}\n\nfunc (p *zpool) GetID() int {\n\treturn 6\n}\n\nfunc (p *zpool) GetName() string {\n\treturn \"Zpool.ca\"\n}\n\nfunc (p *zpool) GetFee() float64 {\n\treturn 0.50\n}\n\nfunc (p *zpool) OpenBrowserPayoutInfo(addr string) {\n\tutil.OpenBrowser(fmt.Sprintf(\"https://zpool.ca/wallet/%s\", addr))\n}\n"
  },
  {
    "path": "prerequisites/amdgpudriver.go",
    "content": "package prerequisites\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nfunc checkAmdgpuDriverInstalled() error {\n\tif runtime.GOOS == \"linux\" {\n\t\tInfo := exec.Command(\"lsmod\")\n\t\tHistory, _ := Info.Output()\n\t\tlines := strings.Split(string(History), \"\\n\")\n\t\tfor _, l := range lines {\n\t\t\tif strings.Contains(l, \"amdgpu\") {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"AMD GPU Driver is not installed. You need to install it in order to run the miner\")\n\t}\n\n\t// If we don't know, assume OK\n\treturn nil\n}\n"
  },
  {
    "path": "prerequisites/msvcrt2013.go",
    "content": "package prerequisites\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\nfunc vcrt2013Installed() bool {\n\tsearchPath := strings.Split(os.Getenv(\"PATH\"), \";\")\n\tfor _, p := range searchPath {\n\t\tsearch := filepath.Join(p, \"MSVCR120.dll\")\n\t\tif _, err := os.Stat(search); !os.IsNotExist(err) {\n\t\t\treturn true\n\t\t}\n\t}\n\tlogging.Infof(\"Visual C++ Redistributable is not found\\n\")\n\treturn false\n}\n\nfunc installVCRT2013(install chan bool) error {\n\tif vcrt2013Installed() {\n\t\treturn nil\n\t}\n\n\tinstall <- true\n\n\terr := downloadVCRT2013()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = checkVCRT2013Hash()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinstaller := exec.Command(vcrt2013DownloadPath(), \"/q\", \"/norestart\")\n\terr = installer.Run()\n\tinstall <- false\n\treturn err\n}\n\nfunc vcrt2013DownloadPath() string {\n\tdownloadDir := filepath.Join(util.DataDirectory(), \"prerequisites\")\n\tdownloadPath := filepath.Join(downloadDir, \"vcredist_x64.exe\")\n\terr := os.MkdirAll(downloadDir, 0755)\n\tif err != nil && !os.IsExist(err) {\n\t\tlogging.Errorf(\"Could not create download dir for msvcrt: %v\", err)\n\t}\n\treturn downloadPath\n}\n\nfunc checkVCRT2013Hash() error {\n\texpectedHash, _ := hex.DecodeString(\"e554425243e3e8ca1cd5fe550db41e6fa58a007c74fad400274b128452f38fb8\")\n\trealHash, err := util.ShaSum(vcrt2013DownloadPath())\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !bytes.Equal(realHash, expectedHash) {\n\t\treturn fmt.Errorf(\"Hash of downloaded VCRT runtime installer does not match\")\n\t}\n\treturn nil\n}\n\nfunc downloadVCRT2013() error {\n\n\tresp, err := http.Get(\"https://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\t// Create the file\n\tout, err := os.Create(vcrt2013DownloadPath())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer out.Close()\n\n\t// Write the body to file\n\t_, err = io.Copy(out, resp.Body)\n\treturn err\n}\n"
  },
  {
    "path": "prerequisites/nvidiadriver.go",
    "content": "package prerequisites\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nfunc checkNvidiaDriverInstalled() error {\n\tif runtime.GOOS == \"linux\" {\n\t\tInfo := exec.Command(\"lsmod\")\n\t\tHistory, _ := Info.Output()\n\t\tlines := strings.Split(string(History), \"\\n\")\n\t\tfor _, l := range lines {\n\t\t\tif strings.Contains(l, \"nvidia\") {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"NVidia Driver is not installed. You need to install it in order to run the miner\")\n\t}\n\n\t// If we don't know, assume OK\n\treturn nil\n}\n"
  },
  {
    "path": "prerequisites/prerequisites.go",
    "content": "package prerequisites\n\nimport (\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\nfunc Install(name string, install chan bool) error {\n\tlogging.Infof(\"Installing prerequisite [%s]\\n\", name)\n\tswitch name {\n\tcase \"msvcrt2013\":\n\t\treturn installVCRT2013(install)\n\tcase \"amddriverlinux\":\n\t\treturn checkAmdgpuDriverInstalled()\n\tcase \"nvidiadriverlinux\":\n\t\treturn checkNvidiaDriverInstalled()\n\tdefault:\n\t\tlogging.Warnf(\"Unknown prerequisite requested: %s\", name)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "project.json",
    "content": "{\n \"name\": \"Vertcoin One Click Miner\",\n \"description\": \"Enter your project description\",\n \"author\": {\n  \"name\": \"Gert-Jaap Glasbergen\",\n  \"email\": \"gertjaap@gertjaap.org\"\n },\n \"version\": \"0.1.0\",\n \"binaryname\": \"vertcoin-ocm\",\n \"frontend\": {\n  \"dir\": \"frontend\",\n  \"install\": \"npm install\",\n  \"build\": \"npm run build\",\n  \"bridge\": \"src\",\n  \"serve\": \"npm run serve\"\n }\n}"
  },
  {
    "path": "tracking/matomo.go",
    "content": "package tracking\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\ntype TrackingRequest struct {\n\tCategory string\n\tAction   string\n\tName     string\n}\n\nvar trackChan chan TrackingRequest\nvar trackingEnabled bool\nvar waitGroup sync.WaitGroup\n\nfunc Enable() {\n\ttrackingEnabled = true\n\tsaveState()\n}\n\nfunc IsEnabled() bool {\n\treturn trackingEnabled\n}\n\nfunc Disable() {\n\ttrackingEnabled = false\n\tsaveState()\n}\n\nfunc loadState() {\n\tdat, err := os.ReadFile(filepath.Join(util.DataDirectory(), \"tracking\"))\n\tif err != nil {\n\t\tEnable()\n\t\treturn\n\t}\n\ttrackingEnabled = (string(dat) == \"1\")\n}\n\nfunc saveState() {\n\tvalue := \"1\"\n\tif !trackingEnabled {\n\t\tvalue = \"0\"\n\t}\n\terr := os.WriteFile(filepath.Join(util.DataDirectory(), \"tracking\"), []byte(value), 0644)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error writing tracking state: %v\", err)\n\t}\n}\n\nfunc StartTracker() {\n\tmatomoClient := &http.Client{Timeout: 2 * time.Second}\n\ttrackChan = make(chan TrackingRequest, 100)\n\twaitGroup = sync.WaitGroup{}\n\tloadState()\n\tnew := true\n\twaitGroup.Add(1)\n\tgo func() {\n\t\tfor t := range trackChan {\n\t\t\tif !trackingEnabled {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treq, err := http.NewRequest(\"GET\", \"https://analytics.javerity.com/matomo.php\", nil)\n\t\t\tif err != nil {\n\t\t\t\tlog.Print(err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tq := req.URL.Query()\n\t\t\tq.Add(\"idsite\", \"3\")\n\t\t\tq.Add(\"rec\", \"1\")\n\t\t\tif new {\n\t\t\t\tnew = false\n\t\t\t\tq.Add(\"new_visit\", \"1\")\n\t\t\t}\n\t\t\tq.Add(\"action_name\", fmt.Sprintf(\"%s/%s\", t.Category, t.Action))\n\t\t\tq.Add(\"e_c\", t.Category)\n\t\t\tq.Add(\"e_a\", t.Action)\n\t\t\tq.Add(\"e_n\", t.Name)\n\t\t\tq.Add(\"ua\", userAgent())\n\t\t\tq.Add(\"_id\", visitorId())\n\t\t\treq.URL.RawQuery = q.Encode()\n\n\t\t\tr, err := matomoClient.Do(req)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Warnf(\"Error sending tracking data: %v\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif r.Body != nil {\n\t\t\t\tr.Body.Close()\n\t\t\t}\n\t\t}\n\t\twaitGroup.Done()\n\t}()\n}\n\nfunc Stop() {\n\tclose(trackChan)\n\twaitGroup.Wait()\n}\n\nfunc Track(req TrackingRequest) {\n\ttrackChan <- req\n}\n\nvar vId string\n\nfunc visitorId() string {\n\tif vId == \"\" {\n\t\tdat, err := os.ReadFile(filepath.Join(util.DataDirectory(), \"unique_id\"))\n\t\tif err != nil {\n\t\t\tdat = make([]byte, 8)\n\t\t\t_, err := rand.Read(dat)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error reading random ID: %v\", err)\n\t\t\t}\n\t\t\terr = os.WriteFile(filepath.Join(util.DataDirectory(), \"unique_id\"), dat, 0644)\n\t\t\tif err != nil {\n\t\t\t\tlogging.Errorf(\"Error writing random ID: %v\", err)\n\t\t\t}\n\n\t\t}\n\t\tvId = strings.ToUpper(hex.EncodeToString(dat))\n\t}\n\treturn vId\n}\n\nvar ua string\n\nfunc userAgent() string {\n\tif ua == \"\" {\n\t\tua = fmt.Sprintf(\"OCM/%s %s/%s\", GetVersion(), runtime.GOOS, runtime.GOARCH)\n\t}\n\treturn ua\n}\n\nfunc GetVersion() string {\n\treturn version\n}\n"
  },
  {
    "path": "tracking/version.go",
    "content": "package tracking\n\nvar version = \"0.0-alpha1\" // Fixed dev version - always updates available\n"
  },
  {
    "path": "util/autostart.go",
    "content": "package util\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/ProtonMail/go-autostart\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\nvar app *autostart.App\nvar fullPath string\nvar oldFullPathFile string\n\nfunc init() {\n\tfullPath, _ = filepath.Abs(os.Args[0])\n\toldFullPath := \"\"\n\toldFullPathFile = filepath.Join(DataDirectory(), \"auto_start\")\n\tif FileExists(oldFullPathFile) {\n\t\toldFullPathBytes, err := os.ReadFile(oldFullPath)\n\t\tif err != nil {\n\t\t\toldFullPath = string(oldFullPathBytes)\n\t\t}\n\t}\n\tapp = &autostart.App{\n\t\tName:        \"vertcoin-ocm\",\n\t\tDisplayName: \"Vertcoin One-Click miner\",\n\t\tExec:        []string{fullPath},\n\t}\n\n\tif oldFullPath != \"\" && oldFullPath != fullPath {\n\t\toldApp := &autostart.App{\n\t\t\tName:        \"vertcoin-ocm\",\n\t\t\tDisplayName: \"Vertcoin One-Click miner\",\n\t\t\tExec:        []string{oldFullPath},\n\t\t}\n\t\tif oldApp.IsEnabled() {\n\t\t\t// We enabled autostart on a different location. Move it to the current\n\t\t\t// full executable path. Disable it on the old path and move to the new.\n\t\t\tlogging.Debugf(\"Autostart was enabled on a different location.\\nOld location: %s\\nNew location: %s\\nMoving it.\", oldFullPath, fullPath)\n\t\t\terr := oldApp.Disable()\n\t\t\tif err == nil {\n\t\t\t\terr := app.Enable()\n\t\t\t\tif err == nil {\n\t\t\t\t\terr = os.WriteFile(oldFullPathFile, []byte(fullPath), 0644)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlogging.Errorf(\"Writing outstart file failed: %v\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc GetAutoStart() bool {\n\treturn app.IsEnabled()\n}\n\nfunc SetAutoStart(autoStart bool) string {\n\tif autoStart {\n\t\terr := app.Enable()\n\t\tif err != nil {\n\t\t\treturn err.Error()\n\t\t}\n\t\t// Store the full path we created the autostart for, so we can\n\t\t// re-enable it on a new path when someone decides to download\n\t\t// an update to a different location.\n\t\terr = os.WriteFile(oldFullPathFile, []byte(fullPath), 0644)\n\t\tif err != nil {\n\t\t\treturn err.Error()\n\t\t}\n\t} else {\n\t\terr := app.Disable()\n\t\tif err != nil {\n\t\t\treturn err.Error()\n\t\t}\n\t\terr = os.Remove(oldFullPathFile)\n\t\tif err != nil {\n\t\t\treturn err.Error()\n\t\t}\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "util/bech32/bech32.go",
    "content": "package bech32\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// charset is the sequence of ascii characters that make up the bech32\n// alphabet.  Each character represents a 5-bit squashed byte.\n// q = 0b00000, p = 0b00001, z = 0b00010, and so on.\nconst charset = \"qpzry9x8gf2tvdw0s3jn54khce6mua7l\"\n\n// inverseCharset is a mapping of 8-bit ascii characters to the charset\n// positions.  Both uppercase and lowercase ascii are mapped to the 5-bit\n// position values.\nvar inverseCharset = [256]int8{\n\t-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\t-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\t-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\t15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,\n\t-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,\n\t1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,\n\t-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,\n\t1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}\n\n// Bytes8to5 extends a byte slice into a longer, padded byte slice of 5-bit elements\n// where the high 3 bits are all 0.\nfunc Bytes8to5(input []byte) []byte {\n\t// no way to triger an error going from 8 to 5\n\toutput, _ := ByteSquasher(input, 8, 5)\n\treturn output\n}\n\n// Bytes5to8 goes from squashed bytes to full height bytes\nfunc Bytes5to8(input []byte) ([]byte, error) {\n\treturn ByteSquasher(input, 5, 8)\n}\n\n// ByteSquasher squashes full-width (8-bit) bytes into \"squashed\" 5-bit bytes,\n// and vice versa.  It can operate on other widths but in this package only\n// goes 5 to 8 and back again.  It can return an error if the squashed input\n// you give it isn't actually squashed, or if there is padding (trailing q characters)\n// when going from 5 to 8\nfunc ByteSquasher(input []byte, inputWidth, outputWidth uint32) ([]byte, error) {\n\tvar bitstash, accumulator uint32\n\tvar output []byte\n\tmaxOutputValue := uint32((1 << outputWidth) - 1)\n\tfor i, c := range input {\n\t\tif c>>inputWidth != 0 {\n\t\t\treturn nil, fmt.Errorf(\"byte %d (%x) high bits set\", i, c)\n\t\t}\n\t\taccumulator = (accumulator << inputWidth) | uint32(c)\n\t\tbitstash += inputWidth\n\t\tfor bitstash >= outputWidth {\n\t\t\tbitstash -= outputWidth\n\t\t\toutput = append(output,\n\t\t\t\tbyte((accumulator>>bitstash)&maxOutputValue))\n\t\t}\n\t}\n\t// pad if going from 8 to 5\n\tif inputWidth == 8 && outputWidth == 5 {\n\t\tif bitstash != 0 {\n\t\t\toutput = append(output,\n\t\t\t\tbyte((accumulator << (outputWidth - bitstash) & maxOutputValue)))\n\t\t}\n\t} else if bitstash >= inputWidth ||\n\t\t((accumulator<<(outputWidth-bitstash))&maxOutputValue) != 0 {\n\t\t// no pad from 5 to 8 allowed\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"invalid padding from %d to %d bits\", inputWidth, outputWidth)\n\t}\n\treturn output, nil\n}\n\n// SquashedBytesToString swaps 5-bit bytes with a string of the corresponding letters\nfunc SquashedBytesToString(input []byte) (string, error) {\n\tvar s string\n\tfor i, c := range input {\n\t\tif c&0xe0 != 0 {\n\t\t\treturn \"\", fmt.Errorf(\"high bits set at position %d: %x\", i, c)\n\t\t}\n\t\ts += string(charset[c])\n\t}\n\treturn s, nil\n}\n\n// StringToSquashedBytes uses the inverseCharset to switch from the characters\n// back to 5-bit squashed bytes.\nfunc StringToSquashedBytes(input string) ([]byte, error) {\n\tb := make([]byte, len(input))\n\tfor i, c := range input {\n\t\tif inverseCharset[c] == -1 {\n\t\t\treturn nil, fmt.Errorf(\"contains invalid character %s\", string(c))\n\t\t}\n\t\tb[i] = byte(inverseCharset[c])\n\t}\n\treturn b, nil\n}\n\n// PolyMod takes a byte slice and returns the 32-bit BCH checksum.\n// Note that the input bytes to PolyMod need to be squashed to 5-bits tall\n// before being used in this function.  And this function will not error,\n// but instead return an unusable checksum, if you give it full-height bytes.\nfunc PolyMod(values []byte) uint32 {\n\n\t// magic generator uint32s\n\tgen := []uint32{\n\t\t0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3,\n\t}\n\n\t// start with 1\n\tchk := uint32(1)\n\n\tfor _, v := range values {\n\t\ttop := chk >> 25\n\t\tchk = (chk&0x1ffffff)<<5 ^ uint32(v)\n\t\tfor i, g := range gen {\n\t\t\tif (top>>uint8(i))&1 == 1 {\n\t\t\t\tchk ^= g\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chk\n}\n\n// HRPExpand turns the human redable part into 5bit-bytes for later processing\nfunc HRPExpand(input string) []byte {\n\toutput := make([]byte, (len(input)*2)+1)\n\n\t// first half is the input string shifted down 5 bits.\n\t// not much is going on there in terms of data / entropy\n\tfor i, c := range input {\n\t\toutput[i] = uint8(c) >> 5\n\t}\n\t// then there's a 0 byte separator\n\t// don't need to set 0 byte in the middle, as it starts out that way\n\n\t// second half is the input string, with the top 3 bits zeroed.\n\t// most of the data / entropy will live here.\n\tfor i, c := range input {\n\t\toutput[i+len(input)+1] = uint8(c) & 0x1f\n\t}\n\treturn output\n}\n\n// create checksum makes a 6-shortbyte checksum from the HRP and data parts\nfunc CreateChecksum(hrp string, data []byte) []byte {\n\tvalues := append(HRPExpand(hrp), data...)\n\t// put 6 zero bytes on at the end\n\tvalues = append(values, make([]byte, 6)...)\n\t//get checksum for whole slice\n\n\t// flip the LSB of the checksum data after creating it\n\tchecksum := PolyMod(values) ^ 1\n\n\tfor i := 0; i < 6; i++ {\n\t\t// note that this is NOT the same as converting 8 to 5\n\t\t// this is it's own expansion to 6 bytes from 4, chopping\n\t\t// off the MSBs.\n\t\tvalues[(len(values)-6)+i] = byte(checksum>>(5*(5-uint32(i)))) & 0x1f\n\t}\n\n\treturn values[len(values)-6:]\n}\n\nfunc VerifyChecksum(hrp string, data []byte) bool {\n\tvalues := append(HRPExpand(hrp), data...)\n\tchecksum := PolyMod(values)\n\t// make sure it's 1 (from the LSB flip in CreateChecksum\n\treturn checksum == 1\n}\n\n// Encode takes regular bytes of data, and an hrp prefix, and returns the\n// bech32 encoded string.  It doesn't do any segwit specific encoding.\nfunc Encode(hrp string, data []byte) string {\n\tfiveData := Bytes8to5(data)\n\treturn EncodeSquashed(hrp, fiveData)\n}\n\n// EncodeSquashed takes the hrp prefix, as well as byte data that has already\n// been squashed to 5-bits high, and returns the bech32 encoded string.\n// It does not return an error; if you give it non-squashed data it will return\n// an empty string.\nfunc EncodeSquashed(hrp string, data []byte) string {\n\tcombined := append(data, CreateChecksum(hrp, data)...)\n\n\t// Should be squashed, return empty string if it's not.\n\tdataString, err := SquashedBytesToString(combined)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn hrp + \"1\" + dataString\n}\n\n// Decode takes a bech32 encoded string and returns the hrp and the full-height\n// data.  Can error out for various reasons, mostly problems in the string given.\n// Doesn't do anything segwit specific.\nfunc Decode(adr string) (string, []byte, error) {\n\thrp, squashedData, err := DecodeSquashed(adr)\n\tif err != nil {\n\t\treturn hrp, nil, err\n\t}\n\tdata, err := Bytes5to8(squashedData)\n\tif err != nil {\n\t\treturn hrp, nil, err\n\t}\n\treturn hrp, data, nil\n}\n\n// DecodeSquashed is the same as Decode, but will return squashed 5-bit high\n// data.\nfunc DecodeSquashed(adr string) (string, []byte, error) {\n\n\t// make an all lowercase and all uppercase version of the input string\n\tlowAdr := strings.ToLower(adr)\n\thighAdr := strings.ToUpper(adr)\n\n\t// if there's mixed case, that's not OK\n\tif adr != lowAdr && adr != highAdr {\n\t\treturn \"\", nil, fmt.Errorf(\"mixed case address\")\n\t}\n\n\t// default to lowercase\n\tadr = lowAdr\n\n\t// find the last \"1\" and split there\n\tsplitLoc := strings.LastIndex(adr, \"1\")\n\tif splitLoc == -1 {\n\t\treturn \"\", nil, fmt.Errorf(\"1 separator not present in address\")\n\t}\n\n\t// hrp comes before the split\n\thrp := adr[0:splitLoc]\n\n\t// get squashed data\n\tdata, err := StringToSquashedBytes(adr[splitLoc+1:])\n\tif err != nil {\n\t\treturn hrp, nil, err\n\t}\n\n\t// make sure checksum works\n\tsumOK := VerifyChecksum(hrp, data)\n\tif !sumOK {\n\t\treturn hrp, nil, fmt.Errorf(\"Checksum invalid\")\n\t}\n\n\t// chop off checksum to return only payload\n\tdata = data[:len(data)-6]\n\n\treturn hrp, data, nil\n}\n\n// Segwit addresses can't be used in Encode and Decode directly, because the\n// witness version is special and doesn't get squashed.  GetHRP gets the\n// HRP without checking any validity.\nfunc GetHRP(adr string) (string, error) {\n\tsplitLoc := strings.LastIndex(adr, \"1\")\n\tif splitLoc == -1 {\n\t\treturn \"\", fmt.Errorf(\"1 separator not present in address\")\n\t}\n\treturn adr[0:splitLoc], nil\n}\n\n// SegWitAddressEncode takes an hrp and data and gives back a segwit address.\n// The data that goes in should be the full pkscript from the txout, including the\n// version byte and the pushdata byte.\nfunc SegWitAddressEncode(hrp string, data []byte) (string, error) {\n\n\tif len(data) < 4 {\n\t\treturn \"\", fmt.Errorf(\"data too short (%d bytes)\", len(data))\n\t}\n\t// first byte is the version number.  that shouldn't be more than\n\t// 16, so only 4 bits, doesn't need to be squashed\n\tversion := data[0]\n\t// the next byte is the length.  make sure it's right\n\tlength := data[1]\n\n\t// the rest of the data is real data and needs to be squashed\n\tdata = data[2:]\n\n\tif int(length) != len(data) {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"push byte / payload length mismatch: %d, %d\", length, len(data))\n\t}\n\n\t// allow alts\n\t//\tif hrp != \"bc\" && hrp != \"tb\" {\n\t//\t\treturn \"\", fmt.Errorf(\"prefix %s is not bitcoin or testnet\", hrp)\n\t//\t}\n\t// 1 byte programs are not ok.  Also 40 bytes should be enough for anyone.\n\tif len(data) < 2 || len(data) > 40 {\n\t\treturn \"\", fmt.Errorf(\"Data length %d out of bounds\", len(data))\n\t}\n\t// Better get all your features in soon; only 16 possible script versions.\n\tif version > 16 {\n\t\treturn \"\", fmt.Errorf(\"Invalid witness program version %d\", data[0])\n\t}\n\t// version 0 scripts can only be 20 bytes (p2wpkh) or 32 bytes (p2wsh)\n\tif version == 0 && len(data) != 20 && len(data) != 32 {\n\t\treturn \"\", fmt.Errorf(\"expect 20 or 32 byte v0 witprog, got %d\", len(data))\n\t}\n\n\t// squash payload data\n\tsquashedData := Bytes8to5(data)\n\t// prepend version byte\n\tsquashedData = append([]byte{version}, squashedData...)\n\n\taddress := EncodeSquashed(hrp, squashedData)\n\n\treturn address, nil\n}\n\n// SegWitAddressDecode takes a segwit address and returns the pkscript that\n// can go directly into the txout.  (includes version byte and data push byte)\nfunc SegWitAddressDecode(adr string) ([]byte, error) {\n\t_, squashedData, err := DecodeSquashed(adr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// the segwit version byte is directly put into a 5bit squashed byte\n\t// since it maxes out at 16, wasting ~1 byte instead of 4.\n\n\tversion := squashedData[0]\n\tdata, err := Bytes5to8(squashedData[1:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Allow alts\n\t//\tif hrp != \"bc\" && hrp != \"tb\" {\n\t//\t\treturn nil, fmt.Errorf(\"prefix %s is not bitcoin or testnet\", hrp)\n\t//\t}\n\tif len(data) < 2 || len(data) > 40 {\n\t\treturn nil, fmt.Errorf(\"Data length %d out of bounds\", len(data))\n\t}\n\n\tif version > 16 {\n\t\treturn nil, fmt.Errorf(\"Invalid witness program version %d\", data[0])\n\t}\n\tif version == 0 && len(data) != 20 && len(data) != 32 {\n\t\treturn nil, fmt.Errorf(\"expect 20 or 32 byte v0 witprog, got %d\", len(data))\n\t}\n\n\t// first give version byte, then push length\n\tif version > 0 {\n\t\tversion |= 0x80\n\t}\n\toutputScript := append([]byte{version}, byte(len(data)))\n\toutputScript = append(outputScript, data...)\n\n\treturn outputScript, nil\n}\n\n// SegWitV0Encode takes an hrp prefix string and a 20 or 32 byte witness program\n// hash, and turns it into a version 0 address.  (it puts the 0 and pushdata in\n// for you.\nfunc SegWitV0Encode(hrp string, data []byte) (string, error) {\n\tif len(data) != 20 && len(data) != 32 {\n\t\treturn \"\", fmt.Errorf(\"Invalid data length %d, expect 20 or 32\", len(data))\n\t}\n\tscript := []byte{0, byte(len(data))}\n\tscript = append(script, data...)\n\treturn SegWitAddressEncode(hrp, script)\n}\n"
  },
  {
    "path": "util/gpus.go",
    "content": "package util\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\ntype GPUType int\n\nconst (\n\tGPUTypeOther  GPUType = 0\n\tGPUTypeAMD    GPUType = 1\n\tGPUTypeNVidia GPUType = 2\n\tGPUTypeIntel  GPUType = 3\n)\n\ntype GPU struct {\n\tOSName string\n\tType   GPUType\n}\n\ntype KnownGPU struct {\n\tRegExPattern string\n\tType         GPUType\n\tRegExp       *regexp.Regexp\n}\n\nvar gpusCache []GPU\nvar gpusCached = false\n\nvar knownGPUs = []KnownGPU{\n\t/*KnownGPU{\"Radeon( \\\\(TM\\\\))?( RX)? (Vega|[4-5][6-9]0)\", GPUTypeAMD, nil},\n\tKnownGPU{\"AMD Radeon\\\\(TM\\\\) R[79] Graphics\", GPUTypeAMD, nil},\n\tKnownGPU{\"AMD Radeon VII\", GPUTypeAMD, nil},\n\tKnownGPU{\"NVIDIA P[0-9]{3}-[0-9]{3}\", GPUTypeNVidia, nil},\n\tKnownGPU{\"NVIDIA GeForce (RTX )?(GTX )?(10|16|20|[7-9])[0-9]{2}( ti)?(MX)?\", GPUTypeNVidia, nil},\n\tKnownGPU{\"Advanced Micro Devices, Inc. \\\\[AMD/ATI\\\\] .*\", GPUTypeAMD, nil},*/\n\tKnownGPU{\".*NVIDIA.*\", GPUTypeNVidia, nil},\n\tKnownGPU{\".*AMD.*\", GPUTypeAMD, nil},\n\tKnownGPU{\".*Intel.*\", GPUTypeIntel, nil},\n\tKnownGPU{\".*Radeon.*\", GPUTypeAMD, nil},\n}\n\nfunc init() {\n\tif os.Getenv(\"OCM_VIRTUALBOX\") == \"1\" {\n\t\tknownGPUs = append(knownGPUs, KnownGPU{\".*VirtualBox.*\", GPUTypeIntel, nil})\n\t}\n\n\tfor i := range knownGPUs {\n\t\tknownGPUs[i].RegExp, _ = regexp.Compile(knownGPUs[i].RegExPattern)\n\t}\n}\n\nfunc GetGPUsFromStrings(names []string) []GPU {\n\tgpus := []GPU{}\n\tfor _, n := range names {\n\t\tfound := false\n\t\tfor _, k := range knownGPUs {\n\t\t\tif k.RegExp.Match([]byte(n)) {\n\t\t\t\tlogging.Debugf(\"GPU [%s] matched regex [%s]\\n\", n, k.RegExp)\n\t\t\t\tgpus = append(gpus, GPU{n, k.Type})\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tlogging.Debugf(\"Unmatched GPU: [%s]\\n\", n)\n\t\t\tgpus = append(gpus, GPU{n, GPUTypeOther})\n\t\t}\n\t}\n\treturn gpus\n}\n\nfunc GetGPUs() []GPU {\n\tif !gpusCached {\n\t\tgpus := []string{}\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tinfo := exec.Command(\"cmd\", \"/C\", \"wmic path win32_VideoController get name\")\n\t\t\tPrepareBackgroundCommand(info)\n\t\t\thistory, _ := info.Output()\n\t\t\tpossibleGpus := strings.Split(string(history), \"\\n\")\n\t\t\tfor _, g := range possibleGpus {\n\t\t\t\tg = strings.Trim(g, \"\\r \")\n\t\t\t\tif g != \"\" && g != \"Name\" {\n\t\t\t\t\tgpus = append(gpus, g)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if runtime.GOOS == \"linux\" {\n\t\t\tInfo := exec.Command(\"lspci\")\n\t\t\tHistory, _ := Info.Output()\n\t\t\tlines := strings.Split(string(History), \"\\n\")\n\t\t\tfor _, l := range lines {\n\t\t\t\tvgaIdx := strings.Index(l, \"VGA compatible: \")\n\t\t\t\tif vgaIdx > -1 {\n\t\t\t\t\tgpus = append(gpus, l[vgaIdx+16:])\n\t\t\t\t}\n\n\t\t\t\tvgaIdx = strings.Index(l, \"VGA compatible controller: \")\n\t\t\t\tif vgaIdx > -1 {\n\t\t\t\t\tgpus = append(gpus, l[vgaIdx+27:])\n\t\t\t\t}\n\n\t\t\t\tvgaIdx = strings.Index(l, \"3D controller: \")\n\t\t\t\tif vgaIdx > -1 {\n\t\t\t\t\tgpus = append(gpus, l[vgaIdx+15:])\n\t\t\t\t}\n\t\t\t}\n\t\t} else if runtime.GOOS == \"darwin\" {\n\t\t\tInfo := exec.Command(\"system_profiler\", \"SPDisplaysDataType\")\n\t\t\tHistory, _ := Info.Output()\n\t\t\tlines := strings.Split(string(History), \"\\n\")\n\t\t\tfor _, l := range lines {\n\t\t\t\tcsIdx := strings.Index(l, \"Chipset Model: \")\n\t\t\t\tif csIdx > -1 {\n\t\t\t\t\tgpus = append(gpus, l[csIdx+15:])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgpusCache = GetGPUsFromStrings(gpus)\n\t\tgpusCached = true\n\t}\n\treturn gpusCache\n}\n"
  },
  {
    "path": "util/gpus_test.go",
    "content": "package util\n\nimport (\n\t\"log\"\n\t\"testing\"\n)\n\nfunc TestNvidia(t *testing.T) {\n\tgpus := []string{\"NVIDIA something\", \"NVIDIA GeForce 930MX\", \"NVIDIA GeForce GTX 1660 Ti\", \"NVIDIA GeForce RTX 2070\", \"NVIDIA P106-100\", \"NVIDIA Corporation GM107 [GeForce GTX 750 Ti] (rev a2)\"}\n\tg := GetGPUsFromStrings(gpus)\n\tfor i, gpu := range g {\n\t\tif gpu.Type != GPUTypeNVidia {\n\t\t\tlog.Printf(\"Did not detect %s as NVIDIA!\", gpus[i])\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n\nfunc TestAMD(t *testing.T) {\n\tgpus := []string{\"AMD something\", \"Radeon something\", \"Radeon (TM) RX 480 Graphics\", \"AMD Radeon(TM) R7 Graphics\", \"Radeon RX 480\", \"Radeon (TM) RX 560 Graphics\"}\n\tg := GetGPUsFromStrings(gpus)\n\tfor _, gpu := range g {\n\t\tif gpu.Type != GPUTypeAMD {\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n\nfunc TestInvalid(t *testing.T) {\n\tgpus := []string{\"Intel Integrated Graphics\"}\n\tg := GetGPUsFromStrings(gpus)\n\tfor _, gpu := range g {\n\t\tif gpu.Type != GPUTypeOther {\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/miners_linux.go",
    "content": "// +build !windows\n\npackage util\n\nimport (\n\t\"os/exec\"\n)\n\nfunc PrepareBackgroundCommand(cmd *exec.Cmd) {\n\n}\n"
  },
  {
    "path": "util/miners_windows.go",
    "content": "// +build windows\n\npackage util\n\nimport (\n\t\"os/exec\"\n\t\"syscall\"\n)\n\nfunc PrepareBackgroundCommand(cmd *exec.Cmd) {\n\tcmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}\n}\n"
  },
  {
    "path": "util/util.go",
    "content": "package util\n\nimport (\n\t\"archive/tar\"\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/big\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/btcsuite/fastsha256\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n)\n\nconst APP_NAME string = \"vertcoin-ocm\"\n\nfunc DataDirectory() string {\n\tif runtime.GOOS == \"windows\" {\n\t\treturn filepath.Join(os.Getenv(\"APPDATA\"), APP_NAME)\n\t} else if runtime.GOOS == \"darwin\" {\n\t\treturn filepath.Join(os.Getenv(\"HOME\"), \"Library\", \"Application Support\", APP_NAME)\n\t} else if runtime.GOOS == \"linux\" {\n\t\treturn filepath.Join(os.Getenv(\"HOME\"), fmt.Sprintf(\".%s\", strings.ToLower(APP_NAME)))\n\t}\n\treturn \".\"\n}\n\nfunc ReplaceInFile(file string, find string, replace string) error {\n\tinput, err := os.ReadFile(file)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toutput := bytes.Replace(input, []byte(find), []byte(replace), -1)\n\n\tif err = os.WriteFile(file, output, 0666); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype BlocksResponse struct {\n\tBlocks     []Block           `json:\"blocks\"`\n\tPagination InsightPagination `json:\"pagination\"`\n}\n\ntype InsightPagination struct {\n\tNext string `json:\"next\"`\n\tPrev string `json:\"prev\"`\n}\n\ntype Block struct {\n\tHash   string `json:\"hash\"`\n\tHeight int64  `json:\"height\"`\n}\n\ntype BlockResponse struct {\n\tBits uint32 `json:\"bits\"`\n}\n\ntype getInfoResponse struct {\n\tDifficulty       float64 `json:\"difficulty\"`\n\tTipHeight        int64   `json:\"tipHeight\"`\n\tBackendTipHeight int64   `json:\"backendTipHeight\"`\n}\n\ntype VerthashMinerDeviceConfig struct {\n\tDeviceIndex int\n\tPCIeBus     string\n\tOpenCL      bool\n\tName        string\n\tPlatform    string\n}\n\n// Returns true if backend is good\nfunc CheckBackendStatus(backend string) bool {\n\tinfo := getInfoResponse{}\n\turl := fmt.Sprintf(\"%sinfo\", backend)\n\terr := GetJson(url, &info)\n\tif err != nil {\n\t\tlogging.Errorf(\"Backend server failed to respond: %v\", err)\n\t\treturn false\n\t}\n\t// If any of the following are 0, backend server has a problem\n\tif info.BackendTipHeight == 0 {\n\t\treturn false\n\t}\n\tif info.TipHeight == 0 {\n\t\treturn false\n\t}\n\tif info.Difficulty == 0 {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc GetDifficulty() float64 {\n\tinfo := getInfoResponse{}\n\turl := fmt.Sprintf(\"%sinfo\", networks.Active.OCMBackend)\n\terr := GetJson(url, &info)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching difficulty: %v\", err)\n\t}\n\treturn info.Difficulty\n}\n\nfunc GetTipHeight() int64 {\n\tinfo := getInfoResponse{}\n\turl := fmt.Sprintf(\"%sinfo\", networks.Active.OCMBackend)\n\terr := GetJson(url, &info)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching tip height: %v\", err)\n\t}\n\treturn info.TipHeight\n}\n\nfunc GetNetHash() uint64 {\n\tdifficulty := big.NewFloat(GetDifficulty())\n\tfactor := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(48), nil)\n\tnetHash := difficulty.Mul(difficulty, big.NewFloat(0).SetInt(factor))\n\tu, _ := netHash.Quo(netHash, big.NewFloat(9830250)).Uint64() // 0xffff * blocktime in seconds\n\tlogging.Debugf(\"Nethash: %d\", u)\n\n\treturn u\n}\n\nfunc GetCoinsPerDay(th int64) float64 {\n\thalvings := th / 840000 // Vertcoin undergoes a halving event every 840000 blocks\n\n\tif halvings >= 32 { // Vertcoin will undergo 32 halvings before zero emission\n\t\treturn 0\n\t}\n\tif halvings == 0 {\n\t\treturn 28800\n\t}\n\n\tcpd := float64(28800)\n\n\tfor i := int64(0); i < halvings; i++ {\n\t\tcpd = cpd / 2\n\t}\n\treturn cpd\n}\n\nvar jsonClient = &http.Client{Timeout: 60 * time.Second}\n\nfunc FileExists(filename string) bool {\n\tinfo, err := os.Stat(filename)\n\tif os.IsNotExist(err) {\n\t\treturn false\n\t}\n\treturn !info.IsDir()\n}\n\nfunc GetJson(url string, target interface{}) error {\n\tr, err := jsonClient.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Body.Close()\n\n\treturn json.NewDecoder(r.Body).Decode(target)\n}\n\nfunc PostJson(url string, payload interface{}, target interface{}) error {\n\tvar b bytes.Buffer\n\terr := json.NewEncoder(&b).Encode(payload)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr, err := jsonClient.Post(url, \"application/json\", bytes.NewBuffer(b.Bytes()))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Body.Close()\n\n\tbodyBytes, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlogging.Infof(\"POST JSON response: %s\", string(bodyBytes))\n\n\tbuf := bytes.NewBuffer(bodyBytes)\n\treturn json.NewDecoder(buf).Decode(target)\n}\n\nfunc OpenBrowser(url string) {\n\tvar err error\n\n\tswitch runtime.GOOS {\n\tcase \"linux\":\n\t\terr = exec.Command(\"xdg-open\", url).Start()\n\tcase \"windows\":\n\t\terr = exec.Command(\"rundll32\", \"url.dll,FileProtocolHandler\", url).Start()\n\tcase \"darwin\":\n\t\terr = exec.Command(\"open\", url).Start()\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported platform\")\n\t}\n\tif err != nil {\n\t\tlogging.Error(err)\n\t}\n}\n\nfunc UnpackZip(archive, unpackPath string) error {\n\tr, err := zip.OpenReader(archive)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Close()\n\n\tfor _, f := range r.File {\n\n\t\ttargetPath := filepath.Join(unpackPath, f.Name)\n\n\t\t// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE\n\t\tif !strings.HasPrefix(targetPath, filepath.Clean(unpackPath)+string(os.PathSeparator)) {\n\t\t\treturn fmt.Errorf(\"%s: illegal file path\", targetPath)\n\t\t}\n\n\t\tif f.FileInfo().IsDir() {\n\t\t\t// Make Folder\n\t\t\terr = os.MkdirAll(targetPath, os.ModePerm)\n\t\t\tif err != nil && !os.IsExist(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\terr := os.MkdirAll(filepath.Dir(targetPath), 0755)\n\t\tif err != nil && !os.IsExist(err) {\n\t\t\treturn err\n\t\t}\n\t\toutFile, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer outFile.Close()\n\t\trc, err := f.Open()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer rc.Close()\n\n\t\t_, err = io.Copy(outFile, rc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc UnpackTar(archive, unpackPath string) error {\n\tf, err := os.Open(archive)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tgzf, err := gzip.NewReader(f)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttarReader := tar.NewReader(gzf)\n\n\tfor {\n\t\theader, err := tarReader.Next()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tos.Exit(1)\n\t\t}\n\n\t\tname := header.Name\n\n\t\tswitch header.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tcontinue\n\t\tcase tar.TypeReg:\n\t\t\ttargetPath := filepath.Join(unpackPath, name)\n\t\t\terr = os.MkdirAll(filepath.Dir(targetPath), 0755)\n\t\t\tif err != nil && !os.IsExist(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\toutFile, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer outFile.Close()\n\t\t\t_, err = io.Copy(outFile, tarReader)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc ShaSum(file string) ([]byte, error) {\n\th := fastsha256.New()\n\tfp, err := os.Open(file)\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\tdefer fp.Close()\n\tbuf := make([]byte, 4096)\n\n\tfor {\n\t\tn, err := fp.Read(buf)\n\n\t\tif err != nil && err != io.EOF {\n\t\t\treturn []byte{}, err\n\t\t}\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else {\n\t\t\th.Write(buf[:n])\n\t\t}\n\t}\n\treturn h.Sum(nil), nil\n}\n\nfunc ParseVerthashMinerDeviceCfg(cfg string) map[int]VerthashMinerDeviceConfig {\n\tlines := strings.Split(cfg, \"\\n\")\n\tdeviceCFG := VerthashMinerDeviceConfig{}\n\tallDeviceCFG := make(map[int]VerthashMinerDeviceConfig)\n\tplatforms := make(map[int]string)\n\n\t// line 0 will always have the platform type\n\tif strings.Contains(lines[0], \"OpenCL\") {\n\t\tdeviceCFG.OpenCL = true\n\t} else {\n\t\tdeviceCFG.OpenCL = false\n\t}\n\n\tlines = lines[1:] //dont need to process the first line anymore...\n\n\tisGettingDeviceInfo := false\n\tisGettingPlatformInfo := false\n\tfor _, line := range lines {\n\n\t\tif strings.Contains(line, \"Available platforms\") {\n\t\t\tisGettingPlatformInfo = true\n\t\t}\n\t\tif strings.Contains(line, \"Available devices\") {\n\t\t\tisGettingPlatformInfo = false\n\t\t}\n\n\t\tif isGettingPlatformInfo && strings.Contains(line, \"Platform name\") {\n\t\t\tparsedNum, _ := strconv.Atoi(string(line[2]))\n\n\t\t\tplatforms[parsedNum-1] = strings.TrimSpace(strings.Split(line, \": \")[1])\n\t\t}\n\n\t\tif strings.Contains(line, \"DeviceIndex:\") {\n\t\t\t// if we were already getting info, save that device and start again\n\t\t\tif isGettingDeviceInfo {\n\t\t\t\tallDeviceCFG[deviceCFG.DeviceIndex] = deviceCFG\n\t\t\t\tdeviceCFG = VerthashMinerDeviceConfig{}\n\t\t\t}\n\t\t\tisGettingDeviceInfo = true\n\t\t\ttmpStr := strings.SplitAfter(line, \" \")\n\n\t\t\t// in order to capture negative / 2 digit numbers\n\t\t\tdeviceCFG.DeviceIndex, _ = strconv.Atoi(strings.TrimSpace(tmpStr[len(tmpStr)-1]))\n\t\t}\n\n\t\tif isGettingDeviceInfo && strings.Contains(line, \"Name:\") {\n\t\t\tdeviceCFG.Name = strings.TrimSpace(strings.SplitAfter(line, \":\")[1])\n\t\t}\n\n\t\tif isGettingDeviceInfo && strings.Contains(line, \"PCIeBusId:\") {\n\t\t\ttmpStr := strings.SplitAfter(line, \" \")\n\n\t\t\tdeviceCFG.PCIeBus = strings.TrimSpace(tmpStr[len(tmpStr)-1])\n\t\t}\n\n\t\tif isGettingDeviceInfo && strings.Contains(line, \"Platform index:\") {\n\t\t\ttmpStr := strings.SplitAfter(line, \": \")\n\n\t\t\tplatformIdx, _ := strconv.Atoi(strings.TrimSpace(tmpStr[len(tmpStr)-1]))\n\n\t\t\tdeviceCFG.Platform = platforms[platformIdx]\n\t\t}\n\n\t\tif isGettingDeviceInfo && strings.Contains(line, \"#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\") {\n\t\t\tisGettingDeviceInfo = false\n\t\t}\n\t}\n\n\tallDeviceCFG[deviceCFG.DeviceIndex] = deviceCFG\n\tdeviceCFG = VerthashMinerDeviceConfig{}\n\n\treturn allDeviceCFG\n}\n"
  },
  {
    "path": "util/versioncheck.go",
    "content": "package util\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n)\n\ntype GithubRelease struct {\n\tURL        string `json:\"html_url\"`\n\tTag        string `json:\"tag_name\"`\n\tBody       string `json:\"body\"`\n\tDraft      bool   `json:\"draft\"`\n\tPrerelease bool   `json:\"prerelease\"`\n}\n\nvar releases []GithubRelease\n\nfunc init() {\n\terr := GetJson(\"https://api.github.com/repos/vertcoin-project/one-click-miner-vnext/releases\", &releases)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching releases: %v\", err)\n\t}\n}\n\nfunc GetLatestRelease() (GithubRelease, error) {\n\tfor _, r := range releases {\n\t\tif !r.Draft {\n\t\t\treturn r, nil\n\t\t}\n\t}\n\treturn GithubRelease{}, fmt.Errorf(\"No release found\")\n}\n\nfunc VersionStringToNumeric(ver string) int64 {\n\tverNum := int64(0)\n\t// split off suffix\n\tsuffix := \"\"\n\tsuffixIdx := strings.Index(ver, \"-\")\n\tif suffixIdx > -1 {\n\t\tsuffix = ver[suffixIdx+1:]\n\t\tver = ver[:suffixIdx]\n\n\t\t// Chop off possible git commit hash and \"-dirty\"\n\t\tsuffixIdx = strings.Index(suffix, \"-\")\n\t\tif suffixIdx > -1 {\n\t\t\tsuffix = suffix[:suffixIdx]\n\t\t}\n\t}\n\n\tif len(suffix) > 0 {\n\t\tif strings.Contains(suffix, \"alpha\") {\n\t\t\tverNum += -999\n\t\t\tsuffix = strings.ReplaceAll(suffix, \"alpha\", \"\")\n\t\t}\n\t\tif strings.Contains(suffix, \"beta\") {\n\t\t\tverNum += -899\n\t\t\tsuffix = strings.ReplaceAll(suffix, \"beta\", \"\")\n\t\t}\n\t\tsuffixVal, _ := strconv.Atoi(suffix)\n\t\tverNum += int64(suffixVal)\n\t}\n\n\tversionParts := strings.Split(ver, \".\")\n\tmultiplier := int64(100000000)\n\tfor _, v := range versionParts {\n\t\tverVal, _ := strconv.Atoi(v)\n\t\tverNum += (int64(verVal) * multiplier)\n\t\tmultiplier /= 100\n\t}\n\n\treturn verNum\n}\n"
  },
  {
    "path": "util/versioncheck_test.go",
    "content": "package util\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestVersionStrings(t *testing.T) {\n\ttestStrings := []string{\"0.1-alpha1\", \"0.1.1\", \"0.2.1\", \"1.0-alpha1\", \"1.0\", \"0.1-alpha22-abe3f3b-dirty\"}\n\tfor _, s := range testStrings {\n\t\tfmt.Printf(\"%s = %d\\n\", s, VersionStringToNumeric(s))\n\t}\n}\n"
  },
  {
    "path": "wallet/signsend.go",
    "content": "package wallet\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/btcsuite/btcd/btcec/v2\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/btcsuite/btcd/wire\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/keyfile\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n)\n\n// SignMyInputs finds the inputs in a transaction that came from our own wallet, and signs them with our private keys.\n// Will modify the transaction in place, but will ignore inputs that we can't sign and leave them unsigned.\nfunc (w *Wallet) SignMyInputs(tx *wire.MsgTx, password string) error {\n\n\t// For now using only P2PKH signing - since we generate\n\t// a legacy address. Will have to use segwit stuff at some point\n\n\t// generate tx-wide hashCache for segwit stuff\n\t// might not be needed (non-witness) but make it anyway\n\t// hCache := txscript.NewTxSigHashes(tx)\n\n\t// make the stashes for signatures / witnesses\n\tsigStash := make([][]byte, len(tx.TxIn))\n\n\t// get key\n\tprivBytes, err := keyfile.LoadPrivateKey(password)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpriv, _ := btcec.PrivKeyFromBytes(privBytes)\n\n\tfor i := range tx.TxIn {\n\t\tsigStash[i], err = txscript.SignatureScript(tx, i, w.Script, txscript.SigHashAll, priv, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// swap sigs into sigScripts in txins\n\tfor i, txin := range tx.TxIn {\n\t\tif sigStash[i] != nil {\n\t\t\ttxin.SignatureScript = sigStash[i]\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype txSend struct {\n\tRawTx string `json:\"rawtx\"`\n}\n\ntype txSendReply struct {\n\tTxId string `json:\"txid\"`\n}\n\nfunc (w *Wallet) Send(tx *wire.MsgTx) (string, error) {\n\tvar b bytes.Buffer\n\terr := tx.Serialize(&b)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ts := txSend{\n\t\tRawTx: hex.EncodeToString(b.Bytes()),\n\t}\n\n\tr := txSendReply{}\n\n\terr = util.PostJson(fmt.Sprintf(\"%stx\", networks.Active.OCMBackend), s, &r)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn r.TxId, err\n}\n"
  },
  {
    "path": "wallet/sigops.go",
    "content": "package wallet\n\nimport (\n\t\"github.com/btcsuite/btcd/btcutil\"\n\t\"github.com/btcsuite/btcd/txscript\"\n)\n\nvar WitnessScaleFactor = 4\n\n// CountSigOps returns the number of signature operations for all transaction\n// input and output scripts in the provided transaction.  This uses the\n// quicker, but imprecise, signature operation counting mechanism from\n// txscript.\nfunc CountSigOps(tx *btcutil.Tx) int {\n\tmsgTx := tx.MsgTx()\n\n\t// Accumulate the number of signature operations in all transaction\n\t// inputs.\n\ttotalSigOps := 0\n\tfor _, txIn := range msgTx.TxIn {\n\t\tnumSigOps := txscript.GetSigOpCount(txIn.SignatureScript)\n\t\ttotalSigOps += numSigOps\n\t}\n\n\t// Accumulate the number of signature operations in all transaction\n\t// outputs.\n\tfor _, txOut := range msgTx.TxOut {\n\t\tnumSigOps := txscript.GetSigOpCount(txOut.PkScript)\n\t\ttotalSigOps += numSigOps\n\t}\n\n\treturn totalSigOps\n}\n\nfunc (w *Wallet) GetSigOpCost(tx *btcutil.Tx, pkScript []byte, isCoinBaseTx bool, bip16, segWit bool) (int, error) {\n\tnumSigOps := CountSigOps(tx) * WitnessScaleFactor\n\tif bip16 {\n\t\tnumP2SHSigOps, err := w.CountP2SHSigOps(tx, isCoinBaseTx)\n\t\tif err != nil {\n\t\t\treturn 0, nil\n\t\t}\n\t\tnumSigOps += (numP2SHSigOps * WitnessScaleFactor)\n\t}\n\n\tif segWit && !isCoinBaseTx {\n\t\tmsgTx := tx.MsgTx()\n\t\tfor _, txIn := range msgTx.TxIn {\n\t\t\twitness := txIn.Witness\n\t\t\tsigScript := txIn.SignatureScript\n\t\t\tnumSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)\n\t\t}\n\n\t}\n\n\treturn numSigOps, nil\n}\n\n// CountP2SHSigOps returns the number of signature operations for all input\n// transactions which are of the pay-to-script-hash type.  This uses the\n// precise, signature operation counting mechanism from the script engine which\n// requires access to the input transaction scripts.\nfunc (w *Wallet) CountP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool) (int, error) {\n\t// We never spend P2SH in OCM, so this can be disabled\n\treturn 0, nil\n\t/*\n\t\t// Coinbase transactions have no interesting inputs.\n\t\tif isCoinBaseTx {\n\t\t\treturn 0, nil\n\t\t}\n\n\t\t// Accumulate the number of signature operations in all transaction\n\t\t// inputs.\n\t\tmsgTx := tx.MsgTx()\n\t\ttotalSigOps := 0\n\t\tfor txInIndex, txIn := range msgTx.TxIn {\n\t\t\t// Ensure the referenced input transaction is available.\n\t\t\tutxo := w.GetUtxo(txIn.PreviousOutPoint.Hash.String(), uint(txIn.PreviousOutPoint.Index))\n\t\t\tif utxo.TxID == \"\" {\n\t\t\t\tstr := fmt.Sprintf(\"output %v referenced from \"+\n\t\t\t\t\t\"transaction %s:%d either does not exist or \"+\n\t\t\t\t\t\"has already been spent\", txIn.PreviousOutPoint,\n\t\t\t\t\ttx.Hash(), txInIndex)\n\t\t\t\treturn 0, fmt.Errorf(str)\n\t\t\t}\n\n\t\t\t// We're only interested in pay-to-script-hash types, so skip\n\t\t\t// this input if it's not one.\n\t\t\tpkScript, _ := hex.DecodeString(utxo.ScriptPubKey)\n\t\t\tif !txscript.IsPayToScriptHash(pkScript) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Count the precise number of signature operations in the\n\t\t\t// referenced public key script.\n\t\t\tsigScript := txIn.SignatureScript\n\t\t\tnumSigOps := txscript.GetPreciseSigOpCount(sigScript, pkScript,\n\t\t\t\ttrue)\n\n\t\t\t// We could potentially overflow the accumulator so check for\n\t\t\t// overflow.\n\t\t\tlastSigOps := totalSigOps\n\t\t\ttotalSigOps += numSigOps\n\t\t\tif totalSigOps < lastSigOps {\n\t\t\t\tstr := fmt.Sprintf(\"the public key script from output \"+\n\t\t\t\t\t\"%v contains too many signature operations - \"+\n\t\t\t\t\t\"overflow\", txIn.PreviousOutPoint)\n\t\t\t\treturn 0, fmt.Errorf(str)\n\t\t\t}\n\t\t}\n\n\t\treturn totalSigOps, nil*/\n}\n"
  },
  {
    "path": "wallet/wallet.go",
    "content": "package wallet\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/btcsuite/btcd/btcutil\"\n\t\"github.com/btcsuite/btcd/btcutil/base58\"\n\t\"github.com/btcsuite/btcd/chaincfg/chainhash\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/btcsuite/btcd/wire\"\n\t\"github.com/tidwall/buntdb\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/logging\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/networks\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util\"\n\t\"github.com/vertcoin-project/one-click-miner-vnext/util/bech32\"\n)\n\ntype Wallet struct {\n\tAddress   string\n\tScript    []byte\n\tSpendable uint64\n\tMaturing  uint64\n\tdb        *buntdb.DB\n}\n\ntype Utxo struct {\n\tTxID   string `json:\"txid\"`\n\tVout   uint   `json:\"vout\"`\n\tAmount uint64 `json:\"satoshis\"`\n}\n\n// Insight's limit is 100kB HEX (so 50kB raw bytes) - limiting this to 45kB. Once we have\n// better backends (an insight that performs better and allows higher limits, an integrated\n// full node or just using Vertcoin Core) we can scale this up.\nvar maxTxSize = 45000\n\nfunc NewWallet(addr string, script []byte) (*Wallet, error) {\n\tlogging.Infof(\"Initializing wallet %s\", addr)\n\tdb, err := buntdb.Open(filepath.Join(util.DataDirectory(), networks.Active.WalletDB))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Wallet{Address: addr, Script: script, db: db}, nil\n}\n\nfunc (w *Wallet) Utxos() ([]Utxo, error) {\n\tutxos := []Utxo{}\n\terr := util.GetJson(fmt.Sprintf(\"%sutxos/%x\", networks.Active.OCMBackend, w.Script), &utxos)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching UTXOs from OCM Backend: %s\", err.Error())\n\t\treturn utxos, err\n\t}\n\treturn utxos, nil\n}\n\nfunc (w *Wallet) PrepareSweep(addr string) ([]*wire.MsgTx, error) {\n\tutxos, err := w.Utxos()\n\tif err != nil {\n\t\treturn nil, errors.New(\"backend_failure\")\n\t}\n\tretArr := make([]*wire.MsgTx, 0)\n\tfor {\n\t\ttx := wire.NewMsgTx(2)\n\t\ttotalIn := uint64(0)\n\t\tfor _, u := range utxos {\n\t\t\talreadyIncluded := false\n\t\t\tfor _, t := range retArr {\n\t\t\t\tfor _, i := range t.TxIn {\n\t\t\t\t\tif i.PreviousOutPoint.Hash.String() == u.TxID && i.PreviousOutPoint.Index == uint32(u.Vout) {\n\t\t\t\t\t\talreadyIncluded = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif alreadyIncluded {\n\t\t\t\tlogging.Debugf(\"UTXO Already Included: %v\", u)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttotalIn += u.Amount\n\t\t\th, _ := chainhash.NewHashFromStr(u.TxID)\n\t\t\ttx.AddTxIn(wire.NewTxIn(wire.NewOutPoint(h, uint32(u.Vout)), w.Script, nil))\n\t\t}\n\n\t\tif len(tx.TxIn) == 0 {\n\t\t\tlogging.Warnf(\"Trying to sweep with zero UTXOs\")\n\t\t\treturn nil, errors.New(\"insufficient_funds\")\n\t\t}\n\n\t\thash, version, err := base58.CheckDecode(addr)\n\t\tif err == nil && version == networks.Active.Base58P2PKHVersion {\n\t\t\tpubKeyHash := hash\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t\t}\n\t\t\tif len(pubKeyHash) != 20 {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t\t}\n\t\t\tp2pkhScript, err := txscript.NewScriptBuilder().AddOp(txscript.OP_DUP).\n\t\t\t\tAddOp(txscript.OP_HASH160).AddData(pubKeyHash).\n\t\t\t\tAddOp(txscript.OP_EQUALVERIFY).AddOp(txscript.OP_CHECKSIG).Script()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"script_failure\")\n\t\t\t}\n\t\t\ttx.AddTxOut(wire.NewTxOut(0, p2pkhScript))\n\t\t} else if err == nil && version == networks.Active.Base58P2SHVersion {\n\t\t\tscriptHash := hash\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t\t}\n\t\t\tif len(scriptHash) != 20 {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t\t}\n\t\t\tp2shScript, err := txscript.NewScriptBuilder().AddOp(txscript.OP_HASH160).AddData(scriptHash).AddOp(txscript.OP_EQUAL).Script()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"script_failure\")\n\t\t\t}\n\t\t\ttx.AddTxOut(wire.NewTxOut(0, p2shScript))\n\t\t} else if strings.HasPrefix(addr, fmt.Sprintf(\"%s1\", networks.Active.Bech32Prefix)) {\n\t\t\tscript, err := bech32.SegWitAddressDecode(addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t\t}\n\t\t\ttx.AddTxOut(wire.NewTxOut(int64(totalIn), script))\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"invalid_address\")\n\t\t}\n\n\t\tfor i := range tx.TxIn {\n\t\t\ttx.TxIn[i].SignatureScript = make([]byte, 107) // add dummy signature to properly calculate size\n\t\t}\n\n\t\t// Weight = (stripped_size * 4) + witness_size formula,\n\t\t// using only serialization with and without witness data. As witness_size\n\t\t// is equal to total_size - stripped_size, this formula is identical to:\n\t\t// weight = (stripped_size * 3) + total_size.\n\t\tlogging.Debugf(\"Transaction raw serialize size is %d\\n\", tx.SerializeSize())\n\t\tlogging.Debugf(\"Transaction serialize size stripped is %d\\n\", tx.SerializeSizeStripped())\n\n\t\tchunked := false\n\t\t// Chunk if needed\n\t\tif tx.SerializeSize() > maxTxSize {\n\t\t\tchunked = true\n\t\t\t// Remove some extra inputs so we have enough for the next TX to remain valid, we\n\t\t\t// want to have enough money to create an output with enough value\n\t\t\tvalueRemoved := uint64(0)\n\t\t\tfor tx.SerializeSize() > maxTxSize || valueRemoved < 100000 {\n\t\t\t\tfor _, u := range utxos {\n\t\t\t\t\tif u.TxID == tx.TxIn[len(tx.TxIn)-1].PreviousOutPoint.Hash.String() &&\n\t\t\t\t\t\tuint32(u.Vout) == tx.TxIn[len(tx.TxIn)-1].PreviousOutPoint.Index {\n\t\t\t\t\t\ttotalIn -= u.Amount\n\t\t\t\t\t\tvalueRemoved += u.Amount\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttx.TxIn = tx.TxIn[:len(tx.TxIn)-1]\n\t\t\t}\n\t\t}\n\n\t\ttxWeight := (tx.SerializeSizeStripped() * 3) + tx.SerializeSize()\n\t\tlogging.Debugf(\"Transaction weight is %d\\n\", txWeight)\n\t\tbtcTx := btcutil.NewTx(tx)\n\n\t\tsigOpCost, err := w.GetSigOpCost(btcTx, w.Script, false, true, true)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could_not_calculate_fee\")\n\t\t}\n\t\tlogging.Debugf(\"Transaction sigop cost is %d\\n\", sigOpCost)\n\n\t\tvSize := (math.Max(float64(txWeight), float64(sigOpCost*20)) + float64(3)) / float64(4)\n\t\tlogging.Debugf(\"Transaction vSize is %.4f\\n\", vSize)\n\t\tvSizeInt := uint64(vSize + float64(0.5)) // Round Up\n\t\tlogging.Debugf(\"Transaction vSizeInt is %d\\n\", vSizeInt)\n\n\t\tfee := uint64(vSizeInt * 100)\n\t\tlogging.Debugf(\"Setting fee to %d\\n\", fee)\n\n\t\t// empty out the dummy sigs\n\t\tfor i := range tx.TxIn {\n\t\t\ttx.TxIn[i].SignatureScript = nil\n\t\t}\n\n\t\ttx.TxOut[0].Value = int64(totalIn - fee)\n\t\tif tx.TxOut[0].Value < 50000 {\n\t\t\treturn nil, fmt.Errorf(\"insufficient_funds\")\n\t\t}\n\t\tretArr = append(retArr, tx)\n\n\t\tif !chunked {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn retArr, nil\n}\n\nfunc DirectWPKHScriptFromPKH(pkh [20]byte) []byte {\n\tbuilder := txscript.NewScriptBuilder()\n\tbuilder.AddOp(txscript.OP_0).AddData(pkh[:])\n\tb, _ := builder.Script()\n\treturn b\n}\n\ntype BalanceResponse struct {\n\tSpendable uint64 `json:\"confirmed\"`\n\tMaturing  uint64 `json:\"maturing\"`\n}\n\n// Update will reload balance from the backend\nfunc (w *Wallet) Update() {\n\tbal := BalanceResponse{}\n\terr := util.GetJson(fmt.Sprintf(\"%sbalance/%x\", networks.Active.OCMBackend, w.Script), &bal)\n\tif err != nil {\n\t\tlogging.Errorf(\"Error fetching balance from backend: %s\", err.Error())\n\t\treturn\n\t}\n\tw.Spendable = bal.Spendable\n\tw.Maturing = bal.Maturing\n}\n\n// GetBalance will scan the utxos in the wallet and return\n// two values: mature and immature balance. Mining outputs\n// need to wait for 101 confirmations before being allowed\n// to spend\nfunc (w *Wallet) GetBalance() (bal uint64, balImmature uint64) {\n\treturn w.Spendable, w.Maturing\n}\n"
  }
]