diff --git a/buildpack_linux.sh b/buildpack_linux.sh
new file mode 100755
index 0000000..623dd04
--- /dev/null
+++ b/buildpack_linux.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# This scripts builds the dynamic linked qt version using docker and then packs using appimage
+qtdeploy -docker build linux
+# qtdeploy -docker build windows_64_static
+
+cp -f ./deploy/linux/dero-wallet-gui ./dero-wallet-gui.appdir
+cp -rf ./deploy/linux/lib ./dero-wallet-gui.appdir/
+cp -rf ./deploy/linux/plugins ./dero-wallet-gui.appdir/
+cp -rf ./deploy/linux/qml ./dero-wallet-gui.appdir/
+
+#clean up debug files
+find ./dero-wallet-gui.appdir/ -name "*.so.debug" -type f -delete
+
+
+
+ARCH=x86_64 ~/Downloads/appimagetool-x86_64.AppImage dero-wallet-gui.appdir/ dero-wallet-gui-linux-x86_64.appimage
diff --git a/dero-wallet-gui.appdir/.DirIcon b/dero-wallet-gui.appdir/.DirIcon
new file mode 120000
index 0000000..27fff88
--- /dev/null
+++ b/dero-wallet-gui.appdir/.DirIcon
@@ -0,0 +1 @@
+dero-wallet-gui-icon.png
\ No newline at end of file
diff --git a/dero-wallet-gui.appdir/AppRun b/dero-wallet-gui.appdir/AppRun
new file mode 100755
index 0000000..757c103
--- /dev/null
+++ b/dero-wallet-gui.appdir/AppRun
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd "$(dirname "$0")"
+exec ./dero-wallet-gui.sh "$@"
diff --git a/dero-wallet-gui.appdir/dero-wallet-gui-icon.png b/dero-wallet-gui.appdir/dero-wallet-gui-icon.png
new file mode 100644
index 0000000..9f3a15a
Binary files /dev/null and b/dero-wallet-gui.appdir/dero-wallet-gui-icon.png differ
diff --git a/dero-wallet-gui.appdir/dero-wallet-gui.desktop b/dero-wallet-gui.appdir/dero-wallet-gui.desktop
new file mode 100644
index 0000000..4ea9fc8
--- /dev/null
+++ b/dero-wallet-gui.appdir/dero-wallet-gui.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=dero-wallet-gui-appimage
+Icon=dero-wallet-gui-icon
diff --git a/dero-wallet-gui.appdir/dero-wallet-gui.sh b/dero-wallet-gui.appdir/dero-wallet-gui.sh
new file mode 100755
index 0000000..3efc595
--- /dev/null
+++ b/dero-wallet-gui.appdir/dero-wallet-gui.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+appname=`basename $0 | sed s,\.sh$,,`
+
+dirname=`dirname $0`
+tmp="${dirname#?}"
+
+if [ "${dirname%$tmp}" != "/" ]; then
+dirname=$PWD/$dirname
+fi
+export LD_LIBRARY_PATH=$dirname/lib
+export QT_PLUGIN_PATH=$dirname/plugins
+export QML_IMPORT_PATH=$dirname/qml
+export QML2_IMPORT_PATH=$dirname/qml
+$dirname/$appname "$@"
diff --git a/gui.go b/gui.go
new file mode 100644
index 0000000..5be893f
--- /dev/null
+++ b/gui.go
@@ -0,0 +1,249 @@
+// Copyright 2017-2018 DERO Project. All rights reserved.
+// Use of this source code in any form is governed by RESEARCH license.
+// license can be found in the LICENSE file.
+// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// use this command to create logo ico for windows
+// convert images/dero-front-logo.png -define icon:auto-resize=16,48,64,128,256 -compress zip logo.ico
+// use mingw windres i686-w64-mingw32-windres icon.rc -o icon_windows_386.syso
+// use mingw windres x86_64-w64-mingw32-windres icon.rc -o icon_windows_amd64.syso
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "runtime"
+ "sync"
+
+ "github.com/therecipe/qt/core"
+ "github.com/therecipe/qt/gui"
+ "github.com/therecipe/qt/qml"
+ "github.com/therecipe/qt/quickcontrols2"
+)
+import "github.com/docopt/docopt-go"
+
+import "github.com/deroproject/derosuite/config"
+import "github.com/deroproject/derosuite/globals"
+import "github.com/deroproject/derosuite/walletapi"
+
+var command_line string = `dero-wallet-gui
+DERO Wallet gui: A secure, private blockchain with smart-contracts
+
+Usage:
+ dero-wallet-gui [--help] [--version] [--debug] [--testnet] [--noopengl] [--vmmode]
+ dero-wallet-gui -h | --help
+ dero-wallet-gui --version
+
+Options:
+ -h --help Show this screen.
+ --version Show version.
+ --debug Debug mode enabled, print log messages
+ --testnet Enable testnet mode
+ --noopengl Enable minimal UI using software rendering
+ --vmmode Enable minimal UI using software rendering`
+
+type CtxObject struct {
+ core.QObject
+
+ walletptr *walletapi.Wallet
+
+ _ string `property:"version"`
+
+ _ func() `constructor:"init"`
+
+ remote_server string `property:"remote_server"` // remote server
+ _ bool `property:"wallet_online"` // remote server
+
+ _ func(string) `signal:"setwalletonline,auto"` // used to set wallet online
+ _ func() `signal:"setwalletoffline,auto"` // used to set wallet offline
+
+ _ bool `property:"wallet_valid"` // is wallet valid and has been successfully opened
+ _ string `property:"wallet_address"` // wallet address
+ _ string `property:"someString"`
+
+ _ string `property:"initerr"` // used to track error when initially opening or creating database
+
+ _ func(string) `signal:"checkpassword,auto"` // used to check password
+ _ func(string, string) `signal:"setpassword,auto"` // used to set new password
+
+ // property related to to outgoing tx
+ _ string `property:"tx_hex"` // wallet address
+ _ string `property:"txid_hex"` // wallet address
+ _ string `property:"tx_total"`
+ _ string `property:"tx_transfer_amount"`
+ _ string `property:"tx_change"`
+ _ string `property:"tx_fees"`
+ _ string `property:"tx_relayed"`
+
+ _ func(string, string, string) `signal:"build_tx,auto"` // used to build up tx
+ _ func(string) `signal:"relay_tx,auto"` // used to relay tx
+
+ _ string `property:"seed"` // seed in localised language
+ _ func(string) `signal:"seed_language,auto"` // used to request seed in language
+
+ _ func(string, string) `signal:"openwallet,auto"` // used to openwallet
+ _ func(string, string) `signal:"createnewwallet,auto"` // used to openwallet
+ _ func(string, string, string) `signal:"recoverusingseedwords,auto"` // used to recover using seed words
+ _ func(string, string, string) `signal:"recoverusingkey,auto"` // used to recoverkey
+ _ func() `signal:"closewallet,auto"` // used to closewallet
+
+ height int64 `property:"height"` // wallet height
+ topoheight int64 `property:"topoheight"` // wallet topoheight
+ nwheight int64 `property:"nwheight"` // network height
+ nwtopoheight int64 `property:"nwtopoheight"` // network topoheight
+ _ string `property:"height_str"` // height localised string
+ _ string `property:"topoheight_str"` // topoheight localised string
+
+ _ string `property:"total_balance"` // wallet total balance
+ _ string `property:"unlocked_balance"` // wallet unlocked balance
+ _ string `property:"locked_balance"` // network locked balance
+
+ _ func() `signal:"clicked,auto"`
+ _ func(string) `signal:"sendString,auto"`
+
+ _ func(string) `signal:"addressVerify,auto"` // used to verify address
+ _ bool `property:"addressverified"` // is address verfied
+ _ bool `property:"addressintegrated"` // is address integrated
+ _ string `property:"addressipaymentid"` // integrated payment ID in hex form
+
+ _ func(string) `signal:"paymentidVerify,auto"` // used to verify payment id
+ _ bool `property:"paymentidverified"` // is payment id verfied
+
+ _ func(string) `signal:"amountVerify,auto"` // used to verify amount
+ _ bool `property:"amountverified"` // is amount verified
+
+ _ func() `signal:"genintegratedaddress,auto"` // used to verify amount
+ _ string `property:"integrated_32_address"` // integrated i32 address
+ _ string `property:"integrated_32_address_paymentid"` // integrated i32 address
+ _ string `property:"integrated_8_address"` // integrated i8 address
+ _ string `property:"integrated_8_address_paymentid"` // integrated i32 address
+
+ _ func(bool, bool, bool, int64) `signal:"reloadhistory,auto"` // used to reload history, available,in,out
+
+ _ []string `property:"historyListHeight"`
+ _ []string `property:"historyListTopoHeight"`
+ _ []string `property:"historyListTXID"`
+ _ []string `property:"historyListAmount"`
+ _ []string `property:"historyListPaymentID"`
+ _ []string `property:"historyListStatus"`
+ _ []string `property:"historyListUnlockTime"`
+ _ []string `property:"historyListOutDetails"` // contains json string
+
+ sync.Mutex
+}
+
+var count int
+
+func (t *CtxObject) init() {
+ global_object = t // capture reference to original object
+
+ /*
+ var err error
+ global_object.walletptr ,err = walletapi.Open_Encrypted_Wallet("/tmp/tmp2.db", "")
+ if err != nil {
+ fmt.Printf("Wallet opened successfully")
+ }
+
+ addr := global_object.walletptr.GetAddress()
+ global_object.SetWallet_address(addr.String())
+
+ global_object.SetWallet_valid(true) // mark wallet as valid
+ */
+
+ global_object.SetWallet_valid(false)
+
+ t.SetVersion(Version.String())
+
+ t.SetSomeString(fmt.Sprintf("%d times", count))
+
+}
+
+func (t *CtxObject) clicked() {
+ t.SetSomeString(fmt.Sprintf("%d times", count))
+ count++
+ fmt.Printf("clicked qml button\n")
+}
+
+func (t *CtxObject) sendString(a string) {
+ fmt.Println("sendString:", a)
+}
+
+var global_object *CtxObject
+var global_gui *gui.QGuiApplication
+
+func main() {
+
+ var err error
+ globals.Arguments, err = docopt.Parse(command_line, nil, true, "DERO atlantis wallet : work in progress", false)
+ //globals.Arguments, err = docopt.ParseArgs(command_line, os.Args[1:], "DERO daemon : work in progress")
+ if err != nil {
+ log.Fatalf("Error while parsing options err: %s\n", err)
+ }
+
+ globals.Init_rlog()
+ // parse arguments and setup testnet mainnet
+ globals.Initialize() // setup network and proxy
+ //globals.Logger.Infof("") // a dummy write is required to fully activate logrus
+
+ // all screen output must go through the readline
+ //globals.Logger.Out = l.Stdout()
+
+ if globals.Arguments["--noopengl"].(bool) == true || globals.Arguments["--vmmode"].(bool) == true { // setup software rendering if requested
+ os.Setenv("QT_QUICK_BACKEND", "software")
+ }
+
+ //QT_QUICK_BACKEND=software
+
+ globals.Logger.Infof("Arguments %+v", globals.Arguments)
+ globals.Logger.Infof("DERO GUI Wallet : %s This version is under heavy development, use it for testing/evaluations purpose only", Version.String())
+ globals.Logger.Infof("DERO Wallet API : %s This version is under heavy development, use it for testing/evaluations purpose only", config.Version.String())
+ globals.Logger.Infof("Copyright 2017-2018 DERO Project. All rights reserved.")
+ globals.Logger.Infof("OS:%s ARCH:%s GOMAXPROCS:%d", runtime.GOOS, runtime.GOARCH, runtime.GOMAXPROCS(0))
+ globals.Logger.Infof("Wallet in %s mode", globals.Config.Name)
+
+ core.QCoreApplication_SetApplicationName("DERO-WALLET-GUI")
+ core.QCoreApplication_SetOrganizationName("DERO PROJECT")
+ core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
+
+ guiptr := gui.NewQGuiApplication(len(os.Args), os.Args)
+
+ _ = guiptr
+ //guiptr.SetWindowIcon(gui.NewQIcon5("copy.svg"))
+ // guiptr.SetWindowIcon(gui.NewQIcon5(":/images/copy.svg"))
+ guiptr.SetWindowIcon(gui.NewQIcon5(":/images/dero-front-logo.png"))
+ /*var (
+ settings = core.NewQSettings5(nil)
+ style = quickcontrols2.QQuickStyle_Name()
+ )
+ if style != "" {
+ settings.SetValue("style", core.NewQVariant14(style))
+ } else {
+ quickcontrols2.QQuickStyle_SetStyle(settings.Value("style", core.NewQVariant14("")).ToString())
+ }*/
+
+ go update_heights_balances() // handle wallet in another goroutine
+
+ // use the material style
+ // the other inbuild styles are:
+ // Default, Fusion, Imagine, Universal
+ quickcontrols2.QQuickStyle_SetStyle("Material")
+
+ var engine = qml.NewQQmlApplicationEngine(nil)
+ engine.RootContext().SetContextProperty("ctxObject", NewCtxObject(nil))
+ engine.Load(core.NewQUrl3("qrc:/main.qml", 0))
+
+ gui.QGuiApplication_Exec()
+}
diff --git a/icon.rc b/icon.rc
new file mode 100644
index 0000000..48a36e0
--- /dev/null
+++ b/icon.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "logo.ico"
diff --git a/icon_windows_386.syso b/icon_windows_386.syso
new file mode 100644
index 0000000..2aa6e47
Binary files /dev/null and b/icon_windows_386.syso differ
diff --git a/icon_windows_amd64.syso b/icon_windows_amd64.syso
new file mode 100644
index 0000000..4c1e2f3
Binary files /dev/null and b/icon_windows_amd64.syso differ
diff --git a/images/+material/back.png b/images/+material/back.png
new file mode 100644
index 0000000..ebc1000
Binary files /dev/null and b/images/+material/back.png differ
diff --git a/images/+material/back@2x.png b/images/+material/back@2x.png
new file mode 100644
index 0000000..cf6163c
Binary files /dev/null and b/images/+material/back@2x.png differ
diff --git a/images/+material/back@3x.png b/images/+material/back@3x.png
new file mode 100644
index 0000000..96376a5
Binary files /dev/null and b/images/+material/back@3x.png differ
diff --git a/images/+material/back@4x.png b/images/+material/back@4x.png
new file mode 100644
index 0000000..578ac14
Binary files /dev/null and b/images/+material/back@4x.png differ
diff --git a/images/+material/drawer.png b/images/+material/drawer.png
new file mode 100644
index 0000000..615cc81
Binary files /dev/null and b/images/+material/drawer.png differ
diff --git a/images/+material/drawer@2x.png b/images/+material/drawer@2x.png
new file mode 100644
index 0000000..b1dd106
Binary files /dev/null and b/images/+material/drawer@2x.png differ
diff --git a/images/+material/drawer@3x.png b/images/+material/drawer@3x.png
new file mode 100644
index 0000000..289889b
Binary files /dev/null and b/images/+material/drawer@3x.png differ
diff --git a/images/+material/drawer@4x.png b/images/+material/drawer@4x.png
new file mode 100644
index 0000000..215e6a8
Binary files /dev/null and b/images/+material/drawer@4x.png differ
diff --git a/images/+material/menu.png b/images/+material/menu.png
new file mode 100644
index 0000000..f02429e
Binary files /dev/null and b/images/+material/menu.png differ
diff --git a/images/+material/menu@2x.png b/images/+material/menu@2x.png
new file mode 100644
index 0000000..9309ad9
Binary files /dev/null and b/images/+material/menu@2x.png differ
diff --git a/images/+material/menu@3x.png b/images/+material/menu@3x.png
new file mode 100644
index 0000000..7bddf71
Binary files /dev/null and b/images/+material/menu@3x.png differ
diff --git a/images/+material/menu@4x.png b/images/+material/menu@4x.png
new file mode 100644
index 0000000..e5c23a3
Binary files /dev/null and b/images/+material/menu@4x.png differ
diff --git a/images/arrow.png b/images/arrow.png
new file mode 100644
index 0000000..d81accb
Binary files /dev/null and b/images/arrow.png differ
diff --git a/images/arrow@2x.png b/images/arrow@2x.png
new file mode 100644
index 0000000..309c018
Binary files /dev/null and b/images/arrow@2x.png differ
diff --git a/images/arrow@3x.png b/images/arrow@3x.png
new file mode 100644
index 0000000..e146ecc
Binary files /dev/null and b/images/arrow@3x.png differ
diff --git a/images/arrow@4x.png b/images/arrow@4x.png
new file mode 100644
index 0000000..b2ad27f
Binary files /dev/null and b/images/arrow@4x.png differ
diff --git a/images/arrows.png b/images/arrows.png
new file mode 100644
index 0000000..d38b94a
Binary files /dev/null and b/images/arrows.png differ
diff --git a/images/arrows@2x.png b/images/arrows@2x.png
new file mode 100644
index 0000000..69b9342
Binary files /dev/null and b/images/arrows@2x.png differ
diff --git a/images/arrows@3x.png b/images/arrows@3x.png
new file mode 100644
index 0000000..7703252
Binary files /dev/null and b/images/arrows@3x.png differ
diff --git a/images/arrows@4x.png b/images/arrows@4x.png
new file mode 100644
index 0000000..66c1fac
Binary files /dev/null and b/images/arrows@4x.png differ
diff --git a/images/back.png b/images/back.png
new file mode 100644
index 0000000..db43e27
Binary files /dev/null and b/images/back.png differ
diff --git a/images/back@2x.png b/images/back@2x.png
new file mode 100644
index 0000000..c55ab31
Binary files /dev/null and b/images/back@2x.png differ
diff --git a/images/back@3x.png b/images/back@3x.png
new file mode 100644
index 0000000..b228eb8
Binary files /dev/null and b/images/back@3x.png differ
diff --git a/images/back@4x.png b/images/back@4x.png
new file mode 100644
index 0000000..dd157e7
Binary files /dev/null and b/images/back@4x.png differ
diff --git a/images/copy.svg b/images/copy.svg
new file mode 100644
index 0000000..aed2dc5
--- /dev/null
+++ b/images/copy.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/images/dero-front-logo.png b/images/dero-front-logo.png
new file mode 100644
index 0000000..9f3a15a
Binary files /dev/null and b/images/dero-front-logo.png differ
diff --git a/images/dero-front-logo@2x.png b/images/dero-front-logo@2x.png
new file mode 100644
index 0000000..ceb1a63
Binary files /dev/null and b/images/dero-front-logo@2x.png differ
diff --git a/images/dero-front-logo@3x.png b/images/dero-front-logo@3x.png
new file mode 100644
index 0000000..8dd3c0b
Binary files /dev/null and b/images/dero-front-logo@3x.png differ
diff --git a/images/dero-front-logo@4x.png b/images/dero-front-logo@4x.png
new file mode 100644
index 0000000..8477235
Binary files /dev/null and b/images/dero-front-logo@4x.png differ
diff --git a/images/drawer.png b/images/drawer.png
new file mode 100644
index 0000000..1e974ef
Binary files /dev/null and b/images/drawer.png differ
diff --git a/images/drawer@2x.png b/images/drawer@2x.png
new file mode 100644
index 0000000..eba3b6c
Binary files /dev/null and b/images/drawer@2x.png differ
diff --git a/images/drawer@3x.png b/images/drawer@3x.png
new file mode 100644
index 0000000..3584ed6
Binary files /dev/null and b/images/drawer@3x.png differ
diff --git a/images/drawer@4x.png b/images/drawer@4x.png
new file mode 100644
index 0000000..60d93af
Binary files /dev/null and b/images/drawer@4x.png differ
diff --git a/images/menu.png b/images/menu.png
new file mode 100644
index 0000000..a10473d
Binary files /dev/null and b/images/menu.png differ
diff --git a/images/menu@2x.png b/images/menu@2x.png
new file mode 100644
index 0000000..649c2a0
Binary files /dev/null and b/images/menu@2x.png differ
diff --git a/images/menu@3x.png b/images/menu@3x.png
new file mode 100644
index 0000000..9554b69
Binary files /dev/null and b/images/menu@3x.png differ
diff --git a/images/menu@4x.png b/images/menu@4x.png
new file mode 100644
index 0000000..187c171
Binary files /dev/null and b/images/menu@4x.png differ
diff --git a/images/qt-logo.png b/images/qt-logo.png
new file mode 100644
index 0000000..90e6f90
Binary files /dev/null and b/images/qt-logo.png differ
diff --git a/images/qt-logo@2x.png b/images/qt-logo@2x.png
new file mode 100644
index 0000000..22d111a
Binary files /dev/null and b/images/qt-logo@2x.png differ
diff --git a/images/qt-logo@3x.png b/images/qt-logo@3x.png
new file mode 100644
index 0000000..627746c
Binary files /dev/null and b/images/qt-logo@3x.png differ
diff --git a/images/qt-logo@4x.png b/images/qt-logo@4x.png
new file mode 100644
index 0000000..dc62286
Binary files /dev/null and b/images/qt-logo@4x.png differ
diff --git a/logo.ico b/logo.ico
new file mode 100644
index 0000000..9bfe8ac
Binary files /dev/null and b/logo.ico differ
diff --git a/main.qml b/main.qml
new file mode 100644
index 0000000..bd7766f
--- /dev/null
+++ b/main.qml
@@ -0,0 +1,1403 @@
+
+// Copyright 2017-2018 DERO Project. All rights reserved.
+// Use of this source code in any form is governed by RESEARCH license.
+// license can be found in the LICENSE file.
+// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 2.0
+import QtQuick.Controls.Material 2.0
+import QtQuick.Controls.Universal 2.0
+import Qt.labs.settings 1.0
+import QtQuick.Dialogs 1.0
+
+ApplicationWindow {
+ id: window
+ color: "#fffafafa"
+ width: 660
+ height: 520
+ visible: true
+ title: "DERO GUI Wallet (pre-alpha)"
+
+
+ Settings {
+ id: settings
+ property string style: "Material"
+ }
+
+ Material.background: "#fafafa"
+ property string dbname: ""
+
+
+ header: ToolBar {
+ Material.foreground: "black"
+
+ RowLayout {
+ spacing: 20
+ anchors.fill: parent
+
+ ToolButton {
+ /*contentItem: Image {
+ fillMode: Image.Pad
+ horizontalAlignment: Image.AlignHCenter
+ verticalAlignment: Image.AlignVCenter
+ source: stackView.depth > 1 ? "images/back.png" : "images/drawer.png"
+ }*/
+ text: "Logout"
+ //visible: stackView.depth > 1? true:false
+ visible: ctxObject.wallet_valid == true ? true : false
+ onClicked: {
+ ctxObject.closewallet()
+ titleLabel.text = "DERO GUI wallet"
+ // stackView.clear()
+ if (stackView.depth > 1) {
+ stackView.pop()
+ // listView.currentIndex = -1
+ } /* else {
+ drawer.open()
+ }*/
+ }
+ }
+
+ Label {
+ id: titleLabel
+ //text: listView.currentItem ? listView.currentItem.text : "DERO GUI Wallet"
+ font.pixelSize: 20
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ //anchors.horizontalCenter: parent.horizontalCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+
+ // text: page.swipeView.contentChildren[page.swipeView.currentIndex].title
+ }
+
+ ToolButton {
+ text: "MENU"
+ /*contentItem: Image {
+ fillMode: Image.Pad
+ horizontalAlignment: Image.AlignHCenter
+ verticalAlignment: Image.AlignVCenter
+ source: "qrc:/images/menu.png"
+ }*/
+ onClicked: optionsMenu.open()
+
+ Menu {
+ id: optionsMenu
+ x: parent.width - width
+ transformOrigin: Menu.TopRight
+
+ MenuItem {
+ text: "Settings"
+ onTriggered: settingsPopup.open()
+ }
+
+ MenuItem {
+ text: "Seed"
+ onTriggered: validateseedpasswordpopop.open()
+ height: ctxObject.wallet_valid == true ? implicitHeight : 0
+ }
+
+
+ MenuItem {
+ text: "Change Password"
+ onTriggered: changepasswordpopop.open()
+ height: ctxObject.wallet_valid == true ? implicitHeight : 0
+ }
+
+
+
+ MenuItem {
+ text: "Logout "
+ height: ctxObject.wallet_valid == true ? implicitHeight : 0
+
+ onTriggered: {
+ ctxObject.closewallet()
+ titleLabel.text = "DERO GUI wallet"
+ // stackView.clear()
+ if (stackView.depth > 1) {
+ stackView.pop()
+ // listView.currentIndex = -1
+ }
+ }
+ }
+
+ MenuItem {
+ text: "About"
+ onTriggered: aboutDialog.open()
+ }
+
+
+ MenuItem {
+ text: "Exit"
+
+ onTriggered: {
+ Qt.quit()
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ StackView {
+ id: stackView
+ anchors.fill: parent
+
+ initialItem: Pane {
+ id: pane
+
+ // anchors.fill: parent
+ Column {
+ spacing: 10
+ anchors.fill: parent
+
+ //Layout.fillWidth: true
+ //Layout.alignment: Qt.AlignHCenter
+ Rectangle {
+ id: logorect
+ width: 100
+ height: 100
+ //Layout.alignment: Qt.AlignHCenter
+ //anchors.left: parent.Left+100 //((parent.right - parent.left) - 100) /2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ // anchors.fill: parent
+ // anchors.centerIn: parent
+ Image {
+ id: logo
+ //width: pane.availableWidth / 2
+ // height: pane.availableHeight / 2
+
+ // horizontalAlignment: Image.AlignHCenter
+ width: 64
+ height: 64
+
+ anchors.fill: parent
+ anchors.centerIn: parent
+ // anchors.verticalCenterOffset: -50
+ fillMode: Image.PreserveAspectFit
+ source: "qrc:/images/dero-front-logo.png"
+ }
+ }
+
+ Rectangle {
+ id: placeholder
+ height: 100
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Button {
+ id: openexisting
+ text: "Open Existing DERO Wallet"
+ // anchors.centerIn: parent
+ anchors.topMargin: 40
+ // anchors.top: logorect.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ // Layout.horizontalAlignment: Qt.AlignHCenter
+ // Layout.alignment: Qt.AlignHCenter
+ onClicked: {
+ walletfileopendialog.open()
+ }
+
+ Material.foreground: Material.Primary
+ //Material.background: "transparent"
+ Material.elevation: 2
+
+
+ // Layout.preferredWidth: 0
+ // Layout.fillWidth: true
+ FileDialog {
+ id: walletfileopendialog
+
+ title: "Please choose DERO wallet db"
+ selectExisting: true
+ selectMultiple: false
+ folder: shortcuts.home
+ nameFilters: ["DERO wallet file (*.db)"]
+ onAccepted: {
+ console.log("You chose: " + walletfileopendialog.fileUrl)
+ window.dbname = walletfileopendialog.fileUrl.toString()
+ window.dbname = window.dbname.replace(
+ /^(file:\/{2})|(qrc:\/{2})|(http:\/{2})/,
+ "") // remove prefixed "file:///"
+ window.dbname = decodeURIComponent(
+ window.dbname) // unescape html codes like '%23' for '#'
+
+ console.log("window.dbname: " + window.dbname)
+ openpassworddialog.open()
+ // Qt.quit()
+ }
+ onRejected: {
+ console.log("Canceled")
+ // Qt.quit()
+ }
+ // Component.onCompleted: visible = true
+ }
+ }
+
+ Button {
+ id: createnew
+ text: "Create new DERO Wallet"
+
+ // anchors.top: openexisting.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ onClicked: {
+ walletfilenewdialog.open()
+ }
+
+ Material.foreground: Material.Primary
+ //Material.background: "transparent"
+ Material.elevation: 2
+
+
+ // Layout.preferredWidth: 0
+ // Layout.fillWidth: true
+ FileDialog {
+ id: walletfilenewdialog
+
+ title: "Please choose a folder to save wallet.db"
+ selectExisting: true
+ selectFolder: true
+ selectMultiple: false
+ folder: shortcuts.home
+ nameFilters: ["DERO wallet file (*.db)"]
+ onAccepted: {
+ console.log("You chose: folder " + walletfilenewdialog.folder)
+ console.log("You chose: file " + walletfilenewdialog.fileUrl)
+ window.dbname = walletfilenewdialog.folder.toString(
+ )
+ window.dbname = window.dbname.replace(
+ /^(file:\/{2})|(qrc:\/{2})|(http:\/{2})/,
+ "") // remove prefixed "file:///"
+ window.dbname = decodeURIComponent(
+ window.dbname) // unescape html codes like '%23' for '#
+ createnewpopup.open()
+ // Qt.quit()
+ }
+ onRejected: {
+ console.log("Canceled new wallet")
+ // Qt.quit()
+ }
+ // Component.onCompleted: visible = true
+ }
+ }
+
+ Button {
+ id: recoverseed
+ text: "Recover DERO Wallet using seed"
+ // anchors.top: createnew.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ onClicked: {
+ walletfilerecoverseeddialog.open()
+ }
+
+ Material.foreground: Material.Primary
+ //Material.background: "transparent"
+ Material.elevation: 2
+
+
+ // Layout.preferredWidth: 0
+ // Layout.fillWidth: true
+ FileDialog {
+ id: walletfilerecoverseeddialog
+
+ title: "Please choose a file to save wallet.db"
+ selectExisting: true
+ selectFolder: true
+ selectMultiple: false
+ folder: shortcuts.home
+ nameFilters: ["DERO wallet file (*.db)"]
+ onAccepted: {
+ console.log("You chose: " + walletfilerecoverseeddialog.folder)
+ window.dbname = walletfilerecoverseeddialog.folder.toString()
+ window.dbname = window.dbname.replace(
+ /^(file:\/{2})|(qrc:\/{2})|(http:\/{2})/,
+ "") // remove prefixed "file:///"
+ window.dbname = decodeURIComponent(
+ window.dbname) // unescape html codes like '%23' for '#
+ recoverseedwordspopup.open()
+ }
+ onRejected: {
+ console.log("Canceled")
+ // Qt.quit()
+ }
+ // Component.onCompleted: visible = true
+ }
+ }
+
+ Button {
+ id: recoverkey
+ // anchors.top: recoverseed.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Recover wallet using Key"
+ onClicked: {
+ walletfilerecoverkeydialog.open()
+ }
+
+ Material.foreground: Material.Primary
+ //Material.background: "transparent"
+ Material.elevation: 2
+
+
+ // Layout.preferredWidth: 0
+ // Layout.fillWidth: true
+ FileDialog {
+ id: walletfilerecoverkeydialog
+
+ title: "Please choose a file to save wallet.db"
+ selectExisting: true
+ selectFolder: true
+ selectMultiple: false
+ folder: shortcuts.home
+ nameFilters: ["DERO wallet file (*.db)"]
+ onAccepted: {
+ console.log("You chose: " + walletfilerecoverkeydialog.folder)
+ window.dbname = walletfilerecoverkeydialog.folder.toString()
+ window.dbname = window.dbname.replace(
+ /^(file:\/{2})|(qrc:\/{2})|(http:\/{2})/,
+ "") // remove prefixed "file:///"
+ window.dbname = decodeURIComponent(
+ window.dbname) // unescape html codes like '%23' for '#
+
+ recoverkeypopup.open()
+ // Qt.quit()
+ }
+ onRejected: {
+ console.log("Canceled")
+ // Qt.quit()
+ }
+ // Component.onCompleted: visible = true
+ }
+ }
+
+ /*Image {
+ id: arrow
+ source: "qrc:/images/arrow.png"
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ }*/
+ }
+
+ Label {
+ text: "© 2018, DERO Foundation. All rights reserved.\n"
+ + "Use of this program is governed under DERO research license.\n"
+ + "version " + ctxObject.version
+
+ // anchors.margins: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ //anchors.top: parent.bottom
+ //anchors.left: parent.left
+ //anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ horizontalAlignment: Label.AlignHCenter
+ //verticalAlignment: Label.AlignVCenter
+ wrapMode: Label.Wrap
+ }
+ }
+ }
+
+ Popup {
+ id: openpassworddialog
+ modal: true
+ focus: true
+ x: (window.width - width) / 2
+ y: (window.height - openpasswordColumn.height) / 2
+
+ width: Math.min(window.width, window.height) / 3 * 2
+ contentHeight: openpasswordColumn.height
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+ background: Rectangle { color: window.color; }
+
+ Column {
+ id: openpasswordColumn
+ spacing: 20
+
+ Label {
+ text: "Enter Password for " + window.dbname
+ width: openpassworddialog.width
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: openpassword
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Button {
+
+ text: "OK"
+
+ // isDefault: true
+ onClicked: {
+
+ console.log("dbname: " + dbname)
+ console.log("window.dbname: " + window.dbname)
+ ctxObject.initerr = ""
+ ctxObject.openwallet(window.dbname, openpassword.text)
+
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+ // if successfull
+ openpassworddialog.close()
+
+ // clean up text fields
+ openpassword.text = ""
+ stackView.push("qrc:/mainwallet.qml")
+ setwalletmode() // make wallet online/offline
+ }
+ }
+ }
+
+ Button {
+ text: "Cancel"
+ onClicked: {
+ openpassworddialog.close()
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: createnewpopup
+ modal: true
+ focus: true
+
+ x: (window.width - width) / 2
+ y: (window.height - createnewColumn.height) / 2
+ width: Math.min(window.width, window.height) / 3 * 2
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+ background: Rectangle { color: window.color; }
+
+ Column {
+ id: createnewColumn
+ spacing: 5
+
+ Label {
+ text: "Enter Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: createnewpass
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Label {
+
+ text: "Confirm Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: createnewpassconfirm
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "OK"
+ //isDefault: true
+ enabled: createnewpass.text == createnewpassconfirm.text ? true : false
+ onClicked: {
+
+ console.log("dbname: " + dbname)
+ console.log("window.dbname: " + window.dbname)
+
+ ctxObject.initerr = ""
+ ctxObject.createnewwallet(window.dbname, createnewpass.text)
+
+ if (ctxObject.initerr != "") {
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+ // if successfull
+ createnewpopup.close()
+
+
+ // clean up text fields
+ createnewpass.text = ""
+ createnewpassconfirm.text = ""
+ stackView.push("qrc:/mainwallet.qml")
+ seedPopup.open() // mandatory show seed
+ setwalletmode() // make wallet online/offline
+ }
+ }
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Cancel"
+ onClicked: {
+ createnewpopup.close()
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: recoverseedwordspopup
+ modal: true
+ focus: true
+
+ x: (window.width - width) / 2
+ y: (window.height - recoverseedwordsColumn.height) / 2
+ width: Math.min(window.width, window.height) / 3 * 2
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+ background: Rectangle { color: window.color; }
+
+ Column {
+ id: recoverseedwordsColumn
+ spacing: 5
+
+ Label {
+ text: "25 Seed Words"
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverseedwordstext
+ wrapMode: Label.Wrap
+ width: recoverseedwordspopup.width - 20
+ placeholderText: qsTr("25 seed words")
+ }
+
+ Label {
+ text: "Enter Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverseedwordspass
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Label {
+
+ text: "Confirm Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverseedwordspassconfirm
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "OK"
+ //isDefault: true
+ enabled: recoverseedwordspass.text
+ == recoverseedwordspassconfirm.text ? true : false
+ onClicked: {
+
+ console.log("dbname: " + dbname)
+ console.log("window.dbname: " + window.dbname)
+
+ ctxObject.initerr = ""
+ ctxObject.recoverusingseedwords(window.dbname,
+ recoverseedwordspass.text,
+ recoverseedwordstext.text)
+
+ if (ctxObject.initerr != "") {
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 5000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+ // if successfull
+ recoverseedwordspopup.close()
+
+ // clean up text fields
+ recoverseedwordstext.text = ""
+ recoverseedwordspass.text = ""
+ recoverseedwordspassconfirm.text = ""
+ stackView.push("qrc:/mainwallet.qml")
+ setwalletmode() // make wallet online/offline
+ }
+ }
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Cancel"
+ onClicked: {
+ recoverseedwordspopup.close()
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: recoverkeypopup
+ modal: true
+ focus: true
+
+ x: (window.width - width) / 2
+ y: (window.height - recoverkeyColumn.height) / 2
+ width: Math.min(window.width, window.height) / 3 * 2
+ // contentHeight: recoverkeyColumn.height
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+
+ background: Rectangle { color: window.color; }
+
+ Column {
+ id: recoverkeyColumn
+ spacing: 5
+
+ Label {
+ text: "Recover Key"
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverkeytext
+ wrapMode: Label.Wrap
+ width: recoverkeypopup.width - 20
+ placeholderText: qsTr("Recovery Key")
+ }
+
+ Label {
+ text: "Enter Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverkeypass
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Label {
+
+ text: "Confirm Password"
+ wrapMode: Label.Wrap
+ font.bold: true
+ }
+
+ TextField {
+ id: recoverkeypassconfirm
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "OK"
+ //isDefault: true
+ enabled: recoverkeypass.text == recoverkeypassconfirm.text ? true : false
+ onClicked: {
+
+ console.log("dbname: " + dbname)
+ console.log("window.dbname: " + window.dbname)
+
+ ctxObject.initerr = ""
+ ctxObject.recoverusingkey(window.dbname,
+ recoverkeypass.text,
+ recoverkeytext.text)
+
+ if (ctxObject.initerr != "") {
+
+ ToolTip.delay = -1
+ ToolTip.timeout = -1
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+ // if successfull
+ recoverkeypopup.close()
+
+ // clean up text fields
+ recoverkeytext.text = ""
+ recoverkeypass.text = ""
+ recoverkeypassconfirm.text = ""
+ stackView.push("qrc:/mainwallet.qml")
+ setwalletmode() // make wallet online/offline
+ }
+ }
+ }
+
+ Button {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Cancel"
+ onClicked: {
+ recoverkeypopup.close()
+ }
+ }
+ }
+ }
+
+ // this function will set the wallet mode, online or offline of custom server
+ function setwalletmode() {
+
+ if (ctxObject.wallet_valid == true) {
+
+
+ // change status if wallet is open
+ if (settings_online_remote.checked == true) {
+
+ if (ctxObject.remote_server == "") { // if empty choo
+ ctxObject.remote_server = remote_server.textAt(remote_server.currentIndex);
+ }
+
+ // wallet set custom remote server
+ ctxObject.setwalletonline(ctxObject.remote_server)
+ }
+
+ if (settings_online_local.checked == true) {
+ ctxObject.setwalletonline(ctxObject.remote_server)
+ }
+
+ // make sure wallet is offline
+ if (settings_online_remote.checked == false
+ && settings_online_local.checked == false) {
+ ctxObject.setwalletoffline()
+ }
+ }
+ }
+
+
+ /*
+ // custom combobox to fit in max width element
+ ComboBox {
+ id: control
+
+ property bool sizeToContents
+ property int modelWidth
+
+ width: (sizeToContents) ? modelWidth + 2*leftPadding + 2*rightPadding : implicitWidth
+
+ delegate: ItemDelegate {
+ width: control.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ font.family: control.font.family
+ font.pointSize: control.font.pointSize
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ TextMetrics {
+ id: textMetrics
+ }
+
+ onModelChanged: {
+ textMetrics.font = control.font
+ for(var i = 0; i < model.length; i++){
+ textMetrics.text = model[i]
+ modelWidth = Math.max(textMetrics.width, modelWidth)
+ }
+ }
+} */
+
+
+ Popup {
+ id: changepasswordpopop
+ modal: true
+ focus: true
+ x: (window.width - width) / 2
+ y: (window.height - changepasswordColumn.height) / 2
+
+ background: Rectangle { color: window.color; }
+
+ width: window.width * 4 / 5 // 80 %
+ contentHeight: changepasswordColumn.height
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+
+ Column {
+ id: changepasswordColumn
+ spacing: 10
+ width: parent.width
+
+ Text {
+ text: "Enter Current Password"
+ wrapMode: Label.Wrap
+ //font.bold: true
+ }
+
+ TextField {
+ id: currentpassword
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+
+ Text {
+ text: "Enter new password"
+ wrapMode: Label.Wrap
+ //font.bold: true
+ }
+
+ TextField {
+ id: newpassword
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ onTextChanged: {
+ if (newpassword.text === newpassword1.text) {
+ changepasswordokbutton.enabled = true;
+ } else {
+ changepasswordokbutton.enabled = false;
+ }
+ }
+ }
+
+ Text {
+ text: "Confirm new password"
+ wrapMode: Label.Wrap
+ //font.bold: true
+ }
+
+ TextField {
+ id: newpassword1
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ onTextChanged: {
+ if (newpassword.text === newpassword1.text) {
+ changepasswordokbutton.enabled = true;
+ } else {
+ changepasswordokbutton.enabled = false;
+ }
+ }
+ }
+
+ Row {
+ Button {
+ id: changepasswordokbutton
+
+ text: "OK"
+
+
+ // isDefault: true
+ onClicked: {
+
+ ctxObject.initerr = ""
+ ctxObject.checkpassword(currentpassword.text)
+
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 5000
+ ToolTip.text = "Invalid Password."
+
+ ToolTip.visible = true
+ } else {
+
+ ctxObject.initerr = ""
+
+ ctxObject.setpassword(currentpassword.text, newpassword.text)
+
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 5000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+
+
+ // clean up text fields
+ currentpassword.text = ""
+ newpassword.text = ""
+ newpassword1.text = ""
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 5000
+ ToolTip.text = "Password changed successfully."
+
+ ToolTip.visible = true
+
+ // if successfull
+ changepasswordpopop.close()
+
+
+
+ }
+ }
+ }
+ }
+ Text {
+ text: " "
+ }
+
+ Button {
+ text: "Cancel"
+ onClicked: {
+ changepasswordpopop.close()
+ }
+ }
+ }
+ }
+ }
+
+
+ Popup {
+ id: validateseedpasswordpopop
+ modal: true
+ focus: true
+ x: (window.width - width) / 2
+ y: (window.height - validateseedpasswordColumn.height) / 2
+
+ background: Rectangle { color: window.color; }
+
+ width: window.width * 4 / 5 // 80 %
+ contentHeight: validateseedpasswordColumn.height
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+
+ Column {
+ id: validateseedpasswordColumn
+ spacing: 10
+ width: parent.width
+
+
+ Text {
+ text: "Enter Password to confirm"
+ wrapMode: Label.Wrap
+ //font.bold: true
+ }
+
+ TextField {
+ id: validateseedpassword
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Row {
+ Button {
+
+ text: "OK"
+
+ // isDefault: true
+ onClicked: {
+
+ ctxObject.initerr = ""
+ ctxObject.checkpassword(validateseedpassword.text)
+
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = "Invalid Password."
+
+ ToolTip.visible = true
+ } else {
+
+ // clean up text fields
+ validateseedpassword.text = ""
+
+ // if successfull
+ validateseedpasswordpopop.close()
+
+ seedPopup.open()
+
+ }
+ }
+ }
+ Text {
+ text: " "
+ }
+
+ Button {
+ text: "Cancel"
+ onClicked: {
+ validateseedpasswordpopop.close()
+ }
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: seedPopup
+ x: (window.width - width) / 2
+ y: (window.height - height) / 2
+ width: window.width * 3 / 4
+ height: seedColumn.implicitHeight + topPadding + bottomPadding
+ modal: true
+ focus: true
+
+ background: Rectangle { color: window.color; }
+
+ onAboutToShow: {
+ // seed_language.currentIndex = 9
+ // seed_language.currentIndex = 0
+ ctxObject.seed_language(seed_language.textAt(0))
+ }
+ /*onClosed: {
+ seedlabel.text = ""
+ } */// try to clean seed from RAM
+
+ closePolicy: Popup.NoAutoClose
+ contentItem: Column {
+ id: seedColumn
+ width: seedPopup.width
+
+ spacing: 20
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ text: "Wallet SEED (Please keep this seed safe and secure. This can be used to restore your wallet.If seed is lost, you have LOST you wallet !!)"
+ font.bold: true
+ color: "red"
+ }
+
+ Label {
+ text: "Seed Language:"
+ }
+
+ ComboBox {
+ id: seed_language
+
+ property bool sizeToContents
+ property int modelWidth
+ //width: parent.width * 2/3
+ sizeToContents: true
+
+ width: (sizeToContents) ? modelWidth + 2 * leftPadding + 2
+ * rightPadding + 40 : implicitWidth
+
+ delegate: ItemDelegate {
+ width: seed_language.width
+ text: seed_language.textRole ? (Array.isArray(
+ seed_language.model) ? modelData[seed_language.textRole] : model[seed_language.textRole]) : modelData
+ font.weight: seed_language.currentIndex === index ? Font.DemiBold : Font.Normal
+ font.family: seed_language.font.family
+ font.pointSize: seed_language.font.pointSize
+ highlighted: seed_language.highlightedIndex === index
+ hoverEnabled: seed_language.hoverEnabled
+ }
+
+ TextMetrics {
+ id: textMetrics
+ }
+
+ onModelChanged: {
+ textMetrics.font = seed_language.font
+ for (var i = 0; i < model.length; i++) {
+ textMetrics.text = model[i]
+ modelWidth = Math.max(textMetrics.width, modelWidth)
+ }
+ }
+
+ model: ["English", "日本語", "简体中文 (中国)", "Nederlands", "Esperanto", "русский язык", "Español", "Português", "Français", "Deutsch", "Italiano"]
+ Component.onCompleted: {
+ currentIndex = 0
+ }
+ onActivated: {
+ ctxObject.seed_language(seed_language.textAt(currentIndex))
+ }
+ }
+
+ TextField {
+ id: seedlabel
+ width: parent.width //seedPopup.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ text: ctxObject.seed
+ }
+
+ RowLayout {
+ width: parent.width
+
+ Button {
+ text: "Ok"
+ onClicked: {
+ //seedlabel.text = ""
+ seedPopup.close()
+ }
+
+ Material.foreground: Material.primary
+ // Material.background: "transparent"
+ Material.elevation: 0
+
+ Layout.preferredWidth: 0
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: settingsPopup
+ x: (window.width - width) / 2
+ y: window.height / 6
+ width: Math.min(window.width, window.height) / 3 * 2
+ height: settingsColumn.implicitHeight + topPadding + bottomPadding
+ modal: true
+ focus: true
+ background: Rectangle { color: window.color; }
+
+ contentItem: ColumnLayout {
+ id: settingsColumn
+ spacing: 20
+
+ Label {
+ text: "Settings"
+ font.bold: true
+ }
+
+ Switch {
+ id: settings_online_remote
+ text: "Wallet Online (Remote)"
+ checked: true
+ onClicked: {
+ if (settings_online_remote.checked == true) {
+ ctxObject.remote_server = remote_server.textAt(
+ remote_server.currentIndex)
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 2000
+ ToolTip.text = "Will use remote server " + remote_server.textAt(
+ remote_server.currentIndex)
+
+ ToolTip.visible = true
+
+ setwalletmode()
+ } else {
+ setwalletmode()
+ }
+
+ console.log(remote_server.textAt(
+ remote_server.currentIndex))
+ }
+ }
+ Switch {
+ id: settings_online_local
+ text: "Wallet Online (local 127.0.0.1:20206)"
+ checked: false
+
+ onClicked: {
+ if (settings_online_remote.checked == false
+ && settings_online_local.checked == true) {
+ ctxObject.remote_server = "127.0.0.1:20206"
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 2000
+ ToolTip.text = "Will use local server"
+
+ ToolTip.visible = true
+
+ setwalletmode()
+ } else {
+ setwalletmode()
+ }
+ }
+ }
+
+ RowLayout {
+ spacing: 10
+
+ Label {
+ text: "Remote server:"
+ }
+
+ ComboBox {
+ id: remote_server
+ model: [ /*"http://localhost:20206/",*/ "https://rwallet.dero.io", "https://rwallet.dero.live", "https://rwallet1.dero.io","https://rwallet1.dero.live"]
+ Component.onCompleted: {
+ currentIndex = 0
+ }
+ onActivated: {
+ if (settings_online_remote.checked == true) {
+ ctxObject.remote_server = remote_server.textAt(
+ currentIndex)
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 2000
+ ToolTip.text = "Will use remote server " + remote_server.textAt(
+ currentIndex)
+
+ ToolTip.visible = true
+
+ setwalletmode()
+ }
+
+ console.log(remote_server.textAt(currentIndex))
+ }
+ Layout.fillWidth: true
+ }
+ }
+
+ RowLayout {
+ spacing: 10
+
+ Button {
+ id: okButton
+ text: "Ok"
+ onClicked: {
+ settingsPopup.close()
+ }
+
+ Material.foreground: Material.primary
+ Material.background: "transparent"
+ Material.elevation: 0
+
+ Layout.preferredWidth: 0
+ Layout.fillWidth: true
+ }
+ /*
+
+ Button {
+ id: cancelButton
+ text: "Cancel"
+ onClicked: {
+
+ }
+
+ Material.background: "transparent"
+ Material.elevation: 0
+
+ Layout.preferredWidth: 0
+ Layout.fillWidth: true
+ }*/
+ }
+ }
+ }
+
+
+
+ Popup {
+ id: aboutDialog
+ modal: true
+ focus: true
+ x: (window.width - width) / 2
+ //y: (window.height - aboutColumn.height) / 2
+ width: Math.min(window.width, window.height) / 10 * 9
+ contentHeight: aboutColumn.height
+
+ background: Rectangle { color: window.color; }
+
+
+
+ Column {
+ id: aboutColumn
+ spacing: 5
+
+
+ Button {
+ text: "OK"
+ onClicked: {
+ aboutDialog.close()
+ }
+ }
+
+ Label {
+ text: "About DERO GUI Wallet"
+ font.bold: true
+ }
+
+ Label {
+ width: aboutDialog.availableWidth
+ text: 'DERO is decentralized DAG(Directed Acyclic Graph) based blockchain with enhanced reliability, privacy, security, and usability.DERO is industry leading and the first blockchain to have bulletproofs, TLS encrypted Network.
DERO blockchain has the following salient features:' +
+ "
" +
+ "- DAG Based: No orphan blocks, No soft-forks.
"+
+ "- Extremely fast transactions with 2 minutes confirmation time.
"+
+ "- 12 Second Block time.
"+
+ "- SSL/TLS P2P Network.
"+
+ "- CryptoNote: Fully Encrypted Blockchain
"+
+ "- BulletProofs: Zero Knowledge range-proofs(NIZK).
"+
+ "- Ring signatures.
"+
+ "- Fully Auditable Supply.
"+
+ "- DERO blockchain is written from scratch in Golang.
"+
+ "- Developed and maintained by original developers.
"+
+ "
"+
+ '
Please visit DERO website for more information (support).'
+ wrapMode: Label.Wrap
+ font.pixelSize: 12
+ onLinkActivated: {
+ Qt.openUrlExternally(link)
+ }
+ }
+
+ Label {
+ width: aboutDialog.availableWidth
+ text: "This program is pre-alpha and is being used/deployed to evaluate QT framework (5.11) and therecipe GO QT bindings for its suitablity for particular purpose.
V" + ctxObject.version
+ wrapMode: Label.Wrap
+ font.pixelSize: 12
+ onLinkActivated: {
+ Qt.openUrlExternally(link)
+ }
+ }
+ }
+
+ }
+}
diff --git a/mainwallet.qml b/mainwallet.qml
new file mode 100644
index 0000000..2405e4e
--- /dev/null
+++ b/mainwallet.qml
@@ -0,0 +1,947 @@
+// Copyright 2017-2018 DERO Project. All rights reserved.
+// Use of this source code in any form is governed by RESEARCH license.
+// license can be found in the LICENSE file.
+// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import QtQuick 2.6
+import QtQuick.Controls 2.0
+
+Page {
+ id: page
+
+ Popup {
+ id: validatetemporarypasswordpopop
+ modal: true
+ focus: true
+ x: (window.width - width) / 2
+ y: (window.height - validatetemporarypasswordColumn.height) / 2
+
+ background: Rectangle {
+ color: window.color
+ }
+
+ width: swipeView.width * 4 / 5 // 80 %
+ contentHeight: validatetemporarypasswordColumn.height
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ }
+ }
+
+ Column {
+ id: validatetemporarypasswordColumn
+ spacing: 10
+ width: parent.width
+ Text {
+ width: parent.width
+ text: "Destination : " + "" + daddr.text + ""
+ wrapMode: Text.Wrap
+ }
+ Text {
+ text: "Transferring : " + "" + ctxObject.tx_transfer_amount + " DERO" + ""
+ wrapMode: Text.Wrap
+ }
+
+ Text {
+ width: parent.width
+ text: "TXID : " + "" + ctxObject.txid_hex + ""
+ wrapMode: Text.Wrap
+ }
+
+ Text {
+ text: "Total Amount Selected : " + "" + ctxObject.tx_total + " DERO" + ""
+ wrapMode: Text.Wrap
+ }
+
+ Text {
+ text: "Change (will come back) : " + "" + ctxObject.tx_change + " DERO" + ""
+ wrapMode: Text.Wrap
+ }
+
+ Text {
+ text: "Fees : " + "" + ctxObject.tx_fees + " DERO" + ""
+ wrapMode: Text.Wrap
+ }
+
+ Text {
+ text: "Enter Password to confirm"
+ wrapMode: Label.Wrap
+ //font.bold: true
+ }
+
+ TextField {
+ id: validatetemporarypassword
+ placeholderText: qsTr("Password")
+ echoMode: TextInput.Password //TextInput.PasswordEchoOnEdit
+ }
+
+ Row {
+ Button {
+
+ text: "Send Transaction"
+
+ // isDefault: true
+ onClicked: {
+
+ ctxObject.initerr = ""
+ ctxObject.checkpassword(validatetemporarypassword.text)
+
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = "Invalid Password."
+
+ ToolTip.visible = true
+ } else {
+ // if successfull
+ validatetemporarypasswordpopop.close()
+
+ // clean up text fields
+ validatetemporarypassword.text = ""
+
+ // sending transsaction
+ ctxObject.initerr = ""
+ ctxObject.relay_tx(ctxObject.tx_hex)
+
+ if (ctxObject.initerr == "") {
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = "Transaction " + ctxObject.txid_hex
+ + " relayed successfully"
+
+ ToolTip.visible = true
+ } else {
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ }
+ }
+ }
+ }
+ Text {
+ text: " "
+ }
+
+ Button {
+ text: "Cancel"
+ onClicked: {
+ validatetemporarypasswordpopop.close()
+ }
+ }
+ }
+ }
+ }
+
+ SwipeView {
+ id: swipeView
+ anchors.fill: parent
+
+ // anchors.top: parent.top
+ //anchors.left : parent.left
+ //anchors.right: parent.right
+ //anchors.bottom: anchors.bottom - 80 //TabBar.top
+ currentIndex: tabBar.currentIndex
+
+ onCurrentIndexChanged: {
+ // tabBar.currentIndex = currentIndex
+ switch (currentIndex) {
+ case 0:
+ titleLabel.text = qsTr("Send DERO")
+ break
+ case 1:
+ titleLabel.text = qsTr("Receive DERO")
+ break
+ case 2:
+ titleLabel.text = qsTr("Transaction History")
+ break
+ case 3:
+ titleLabel.text = qsTr("About DERO project")
+ break
+ case 4:
+ titleLabel.text = qsTr("Assets & Smart Contracts")
+ break
+ }
+ }
+
+ // enable vertical scrolling in send pane
+ Flickable {
+ id: listView
+ contentWidth: width
+ contentHeight: panesend.implicitHeight
+
+ ScrollBar.vertical: ScrollBar {
+ }
+
+ Pane {
+ id: panesend
+ width: swipeView.width
+ height: swipeView.height
+ property string title: "First"
+
+ Column {
+ //spacing: 10
+ width: parent.width
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ horizontalAlignment: Qt.AlignHCenter
+ text: "SEND DERO to another user"
+ }
+
+ Rectangle {
+ height: 20
+ color: "transparent"
+ width: parent.width
+ }
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "Destination Address"
+ }
+
+ TextField {
+ id: daddr
+ placeholderText: qsTr("Destination address")
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+
+ onTextChanged: {
+ ctxObject.addressVerify(daddr.text)
+
+ if (ctxObject.addressverified === true) {
+ // make it GREEN
+ console.log("green")
+ daddr.color = "green"
+ } else {
+ // make it RED
+ console.log("red")
+ daddr.color = "red"
+ }
+
+ if ((ctxObject.addressverified === true)
+ && (ctxObject.addressintegrated === true)) {
+ // make it GREEN
+ console.log("integrated")
+ sendpaymentid.text = ctxObject.addressipaymentid
+ sendpaymentid.readOnly = true
+ } else {
+ // make it RED
+ console.log("non-integrated")
+ sendpaymentid.text = ""
+ sendpaymentid.readOnly = false
+ }
+
+ // console.log("address textfield + " + daddr.text)
+ }
+ }
+
+ Rectangle {
+ height: 20
+ color: "transparent"
+ width: parent.width
+ }
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ //horizontalAlignment: Qt.AlignHCenter
+ text: "Amount (in DERO)"
+ }
+
+ TextField {
+ id: damount
+ placeholderText: qsTr("0.0")
+ selectByMouse: true
+
+ onTextChanged: {
+ ctxObject.amountVerify(text)
+ if (ctxObject.amountverified === true) {
+ // make it GREEN
+ color = "green"
+ } else {
+ // make it RED
+ color = "red"
+ }
+ }
+ }
+
+ Rectangle {
+ height: 20
+ color: "transparent"
+ width: parent.width
+ }
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "Payment ID (16 or 64 hex characters) Optional"
+ }
+
+ TextField {
+ id: sendpaymentid
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ placeholderText: qsTr("16 or 64 hex characters")
+
+ onTextChanged: {
+ ctxObject.paymentidVerify(sendpaymentid.text)
+
+ if (ctxObject.paymentidverified === true) {
+ // make it GREEN
+ console.log("green")
+ sendpaymentid.color = "green"
+ } else {
+ // make it RED
+ console.log("red")
+ sendpaymentid.color = "red"
+ }
+ }
+ }
+
+ Rectangle {
+ //height: 5
+ id: tmprectangle
+ color: "transparent"
+ width: parent.width
+ anchors.top: sendpaymentid.bottom
+
+ Button {
+
+ text: "Send NOW"
+ anchors.horizontalCenter: parent.horizontalCenter
+ // isDefault: true
+ onClicked: {
+
+ // build up a transaction so as it could be confirmed
+ ctxObject.initerr = ""
+ ctxObject.build_tx(daddr.text, damount.text,
+ sendpaymentid.text)
+
+ // if an error occured, display error
+ if (ctxObject.initerr != "") {
+ ToolTip.delay = -1
+ ToolTip.timeout = 10000
+ ToolTip.text = ctxObject.initerr
+
+ ToolTip.visible = true
+ } else {
+ // if successfull, confirm password before relaying
+ validatetemporarypasswordpopop.open()
+ }
+
+ console.log("Send NOW button clicked ")
+ }
+ }
+
+ Button {
+
+ text: "Donate"
+ anchors.right: parent.right
+ // isDefault: true
+ // anchors.horizontalCenter: Qt.AlignRight
+ onClicked: {
+
+ daddr.text = "dERoNgyutMJ1sEJEPY4WELLAVk1ov4euQQvXfWW7z4JgWCN77A8gy5pHp6fBAZasLUMhs4B7idoWMGzG1Dd6iho32972N6MzNZ"
+
+ ToolTip.delay = -1
+ ToolTip.timeout = 4000
+ ToolTip.text = "Thank you for donation to DERO foundation"
+ ToolTip.visible = true
+
+ //console.log("Donate button clicked ")
+ }
+ }
+ }
+
+ Row {
+ width: parent.width
+ anchors.top: tmprectangle.bottom
+ }
+
+ Rectangle {
+ height: 70
+ color: "transparent"
+ width: parent.width
+ }
+
+ /*
+
+TextField
+{
+ id: textInput
+ width: parent.width
+ placeholderText: qsTr("Filter")
+ selectByMouse: true
+
+
+ property int selectStart
+property int selectEnd
+property int curPos
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ hoverEnabled: true
+ onClicked: {
+ textInput.selectStart = textInput.selectionStart;
+ textInput.selectEnd = textInput.selectionEnd;
+ textInput.curPos = textInput.cursorPosition;
+ contextMenu.x = mouse.x;
+ contextMenu.y = mouse.y;
+ contextMenu.open();
+ textInput.cursorPosition = textInput.curPos;
+ textInput.select(textInput.selectStart,textInput.selectEnd);
+ }
+ onPressAndHold: {
+ if (mouse.source === Qt.MouseEventNotSynthesized) {
+ textInput.selectStart = textInput.selectionStart;
+ textInput.selectEnd = textInput.selectionEnd;
+ textInput.curPos = textInput.cursorPosition;
+ contextMenu.x = mouse.x;
+ contextMenu.y = mouse.y;
+ contextMenu.open();
+ textInput.cursorPosition = textInput.curPos;
+ textInput.select(textInput.selectStart,textInput.selectEnd);
+ }
+ }
+
+ Menu {
+ id: contextMenu
+ MenuItem {
+ text: "Cut"
+ onTriggered: {
+ textInput.cut()
+ }
+ }
+ MenuItem {
+ text: "Copy"
+ onTriggered: {
+ textInput.copy()
+ }
+ }
+ MenuItem {
+ text: "Paste"
+ onTriggered: {
+ textInput.paste()
+ }
+ }
+ }
+ }
+}
+
+ Image {
+ source: "qrc:/images/arrows.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ */
+ }
+ }
+ }
+
+ // enable vertical scrolling in send pane
+ Flickable {
+ contentWidth: width
+ contentHeight: panereceive.implicitHeight
+
+ ScrollBar.vertical: ScrollBar {
+ }
+
+ Pane {
+ id: panereceive
+ width: swipeView.width
+ height: swipeView.height
+
+ Column {
+ width: parent.width
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ horizontalAlignment: Qt.AlignHCenter
+ text: "Receive DERO from another user"
+ }
+
+ Row {
+ Label {
+ //width: parent.width
+ //wrapMode: Label.Wrap
+ //horizontalAlignment: Qt.AlignHCenter
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Your Address : " // + ctxObject.wallet_address
+ font.bold: true
+ }
+
+ Button {
+ anchors.verticalCenter: parent.verticalCenter
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "copy"
+
+ /* icon.color: "transparent" // not available in 5.8
+ icon.source: "qrc:/images/copy.svg"
+ */
+ onClicked: {
+ receive_addr.selectAll() // select everything
+ receive_addr.copy() // copy to clipboard
+ receive_addr.deselect() // deselect everything
+ console.log("Copy address clicked ")
+ }
+ }
+ }
+
+ TextField {
+ id: receive_addr
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ text: ctxObject.wallet_address
+ }
+
+ Button {
+
+ text: "Generate Address with Payment ID (Integrated Address)"
+ anchors.horizontalCenter: parent.horizontalCenter
+ // isDefault: true
+ onClicked: {
+ ctxObject.genintegratedaddress()
+ }
+ }
+
+ Row {
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Integrated Address Random32 : "
+ font.bold: true
+ }
+
+ Button {
+ anchors.verticalCenter: parent.verticalCenter
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "copy"
+ /* icon.color: "transparent" // not available in 5.8
+ icon.source: "qrc:/images/copy.svg"
+ */
+ // isDefault: true
+ onClicked: {
+ //ctxObject.genintegratedaddress()
+ receive_addr_32.selectAll() // select everything
+ receive_addr_32.copy() // copy to clipboard
+ receive_addr_32.deselect(
+ ) // deselect everything
+ console.log("Copy integrated address clicked ")
+ }
+ }
+ }
+
+ TextField {
+ id: receive_addr_32
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ text: ctxObject.integrated_32_address
+ }
+
+ Row {
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Integrated 32 byte payment id: "
+ font.bold: true
+ }
+
+ Button {
+ anchors.verticalCenter: parent.verticalCenter
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "copy"
+ /* icon.color: "transparent" // not available in 5.8
+ icon.source: "qrc:/images/copy.svg"
+ */
+ // isDefault: true
+ onClicked: {
+ //ctxObject.genintegratedaddress()
+ receive_addr_32_payment_id.selectAll(
+ ) // select everything
+ receive_addr_32_payment_id.copy(
+ ) // copy to clipboard
+ receive_addr_32_payment_id.deselect(
+ ) // deselect everything
+ console.log("Copy 32 byte payment ID clicked ")
+ }
+ }
+ }
+ TextField {
+ id: receive_addr_32_payment_id
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ text: ctxObject.integrated_32_address_paymentid
+ }
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "Integrated Address Random8 : "
+ font.bold: true
+ visible: false
+ }
+
+ TextField {
+ id: receive_addr_8
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ visible: false
+ text: ctxObject.integrated_8_address
+ }
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ // horizontalAlignment: Qt.AlignHCenter
+ text: "Integrated 8 byte payment id (Encrypted) : "
+ font.bold: true
+ visible: false
+ }
+
+ TextField {
+ id: receive_addr_8_payment_id
+ width: parent.width
+ wrapMode: TextField.Wrap
+ selectByMouse: true
+ readOnly: true
+ visible: false
+ text: ctxObject.integrated_8_address_paymentid
+ }
+ }
+ }
+ }
+
+ // enable vertical scrolling in send pane
+ Flickable {
+ contentWidth: width
+ contentHeight: panehistory.implicitHeight
+
+ ScrollBar.vertical: ScrollBar {
+ }
+
+ // shows history pane
+ Pane {
+ id: panehistory
+ width: swipeView.width
+ height: swipeView.height
+
+ Column {
+ width: parent.width
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ Switch {
+ id: incoming
+ text: "Show Incoming"
+ checked: true
+ }
+ Switch {
+ id: outgoing
+ text: "Show Outgoing"
+ checked: true
+ }
+ }
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Label {
+ text: "Show last"
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ SpinBox {
+ anchors.verticalCenter: parent.verticalCenter
+ id: limit
+ value: 50
+ stepSize: 10
+ from: 10
+ to: 5000
+ // width: itemWidth
+ // editable: true
+ }
+ }
+
+ Button {
+
+ id: reloadhistorybutton
+ text: "Reload transaction history"
+ anchors.horizontalCenter: parent.horizontalCenter
+ // isDefault: true
+ onClicked: {
+ ctxObject.reloadhistory(false, incoming.checked,
+ outgoing.checked,
+ limit.value)
+
+ // at this point all transaction history is setup in properties, now we set it up to list model
+ //transactionlistmodel.clear();
+ console.log("total elements txid ",
+ ctxObject.historyListTXID.length)
+ console.log("total elements ",
+ ctxObject.historyListHeight.length)
+ //console.log("details elements ", ctxObject.historyListOutDetails.length);
+ var i
+
+ var textdata
+ textdata = ""
+ for (i = 0; i < ctxObject.historyListHeight.length; i++) {
+
+ var txline
+ var maincolor
+
+ //console.log("i",i,"'",ctxObject.historyListOutDetails[i],"'");
+ if (ctxObject.historyListStatus[i] == "0") {
+ maincolor = "green"
+ } else {
+ maincolor = "red"
+ }
+
+ txline = (i + 1) + ". " + ""
+ + ctxObject.historyListHeight[i] + "/"
+ + ctxObject.historyListTopoHeight[i] + " "
+ + ctxObject.historyListAmount[i] + ' DERO ' + ctxObject.historyListTXID[i] + " " + "" + ctxObject.historyListPaymentID[i]
+ + "
" // + details
+
+ /* mobject = {"counter":i+1, "bheight": ctxObject.historyListHeight[i], "topoheight": ctxObject.historyListTopoHeight[i], "txid": ctxObject.historyListTXID[i], "amount" : ctxObject.historyListAmount[i],"payid": ctxObject.historyListPaymentID[i], "fcolor": ctxObject.historyListStatus[i] == "0" ? "green": "red", "unlock": ctxObject.historyListUnlockTime }
+
+ mobject["details"] = " ";*/
+
+ // if more details are available process them
+ if (ctxObject.historyListOutDetails[i].length > 50) {
+ // console.log(" histout" , ctxObject.historyListOutDetails[i]);
+ var det
+ try {
+ det = JSON.parse(
+ ctxObject.historyListOutDetails[i])
+
+ for (var j = 0; j < det.to.length; j++) {
+ //mobject["details"] = mobject["details"] + "Address: " + det.to[i] + " Amount: " + det.amount[i] + "\n";
+ txline = txline + "Address: " + det.to[j]
+ + " Amount: " + det.amount[j] + "
"
+ }
+
+ txline = txline + "Fees : " + det.fees + "
"
+ txline = txline + "Payment ID : "
+ + det.paymentid + "
"
+ txline = txline + "TX secret key : "
+ + det.tx_secret_key + "
"
+
+ // mobject["details"] = mobject["details"] + "Fees : " + det.fees + "\n";
+ // mobject["details"] = mobject["details"] + "Payment ID : " + det.paymentid + "\n";
+ // mobject["details"] = mobject["details"] + "TX secret key : " + det.tx_secret_key + "\n";
+ } catch (e) {
+ console.log("exception", e.name,
+ e.message)
+ }
+ // console.log("det jsonned ", det, JSON.stringify(det, null, 4) );
+ }
+
+ //transactionlistmodel.append(mobject);
+
+ // console.log(i, "cell height ", dummytextarea.contentHeight)
+ textdata = textdata + txline
+ }
+
+ historylog.text = textdata
+ }
+ }
+
+ TextArea {
+ id: historylog
+ width: swipeView.width //parent.cellWidth
+ wrapMode: TextArea.Wrap
+ selectByMouse: true
+ readOnly: true
+ font.family: "Monospace"
+ textFormat: TextArea.RichText
+ //text: counter+ " " + bheight +"/" + topoheight + " " + amount + ' DERO ' + txid + " "+ "" + payid +"" + details ;
+ //color:fcolor;
+ //anchors.horizontalCenter: parent.horizontalCenter
+ onLinkActivated: {
+ Qt.openUrlExternally(link)
+ console.log(link + " link activated")
+ }
+ }
+
+ // used to measure cell height
+ TextArea {
+ id: dummytextarea
+ width: swipeView.width
+ wrapMode: TextArea.Wrap
+ selectByMouse: true
+ visible: false
+ font.family: "Monospace"
+ textFormat: TextArea.RichText
+ text: "108272/111614 7.992500000000 DERO afe4379e7656667aafc223c98a24884624dbc5edb652644d920af2d3d92c5202 afe4379e7656667aafc223c98a24884624dbc5edb652644d920af2d3d92c5202 "
+ }
+ }
+ }
+ }
+
+ // enable vertical scrolling in send pane
+ Flickable {
+ contentWidth: width
+ contentHeight: aboutpane.implicitHeight
+
+ ScrollBar.vertical: ScrollBar {
+ }
+ Pane {
+ id: aboutpane
+ width: swipeView.width
+ height: swipeView.height
+
+ Column {
+ spacing: 40
+ width: parent.width
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ horizontalAlignment: Qt.AlignHCenter
+ text: "About DERO project"
+ }
+
+ Text {
+ width: parent.width
+ wrapMode: Text.Wrap
+ //horizontalAlignment: Qt.AlignHCenter
+ // font.family: "Monospace"
+
+ //textFormat: Text.RichText
+ text: 'DERO is decentralized DAG(Directed Acyclic Graph) based blockchain with enhanced reliability, privacy, security, and usability.DERO is industry leading and the first blockchain to have bulletproofs, TLS encrypted Network.
DERO blockchain has the following salient features:'
+ + " " + "- DAG Based: No orphan blocks, No soft-forks.
"
+ + "- Extremely fast transactions with 2 minutes confirmation time.
" + "- 12 Second Block time.
" + "- SSL/TLS P2P Network.
" + "- CryptoNote: Fully Encrypted Blockchain
" + "- BulletProofs: Zero Knowledge range-proofs(NIZK).
" + "- Ring signatures.
" + "- Fully Auditable Supply.
" + "- DERO blockchain is written from scratch in Golang.
" + "- Developed and maintained by original developers.
" + "
" + '
Please visit DERO website for more information (support).'
+
+ onLinkActivated: {
+ Qt.openUrlExternally(link)
+ }
+ }
+ }
+ }
+ }
+
+ Pane {
+ width: swipeView.width
+ height: swipeView.height
+
+ Column {
+ spacing: 40
+ width: parent.width
+
+ Label {
+ width: parent.width
+ wrapMode: Label.Wrap
+ horizontalAlignment: Qt.AlignHCenter
+ text: "ToDo Add more info..."
+ }
+ }
+ }
+ }
+
+ footer: Column {
+
+ TabBar {
+ id: tabBar
+ currentIndex: swipeView.currentIndex
+ width: parent.width
+
+ TabButton {
+ text: "Send"
+ onClicked: {
+ titleLabel.text = "Send DERO"
+ console.log(tabBar.height)
+ }
+ }
+ TabButton {
+ text: "Receive"
+ // onClicked: { titleLabel.text = "Receive DERO" }
+ }
+ TabButton {
+ text: "History"
+ // onClicked: { titleLabel.text = "Transaction History" }
+ }
+ TabButton {
+ text: "About"
+ // onClicked: { titleLabel.text = "DERO Balance" }
+ }
+ TabButton {
+
+ // text: "Donate"
+ text: "Smart Contracts/Assets"
+ }
+ }
+
+ Rectangle {
+ color: "lightgrey"
+ width: parent.width
+ height: height_tracker.height * 3
+
+ Column {
+ width: parent.width
+ Label {
+ id: height_tracker
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: ctxObject.height + "/" + ctxObject.nwheight
+
+ font.bold: true
+ horizontalAlignment: Label.AlignHCenter
+
+ // may be we can use a global timer
+ /* Timer {
+
+ interval: 1000
+ repeat: true
+ running: true
+ triggeredOnStart: true
+ onTriggered: {
+ console.log( "timer fired ", ctxObject.height + "/" + ctxObject.nwheight)
+ height_tracker.text = ctxObject.height + "/" + ctxObject.nwheight }
+ }*/
+ }
+
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Total : " + ctxObject.total_balance + " DERO"
+
+ font.bold: true
+ horizontalAlignment: Label.AlignHCenter
+ }
+
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Locked : " + ctxObject.locked_balance + " DERO"
+
+ font.bold: true
+ horizontalAlignment: Label.AlignHCenter
+ }
+ }
+ }
+ }
+}
diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf
new file mode 100644
index 0000000..f7c19b1
--- /dev/null
+++ b/qtquickcontrols2.conf
@@ -0,0 +1,11 @@
+[Controls]
+Style=Material
+
+[Material]
+Primary=#41cd52
+Accent=#41cd52
+Theme=Light
+
+[Universal]
+Accent=#41cd52
+Theme=Light
diff --git a/vendor/github.com/blang/semver/.travis.yml b/vendor/github.com/blang/semver/.travis.yml
new file mode 100644
index 0000000..102fb9a
--- /dev/null
+++ b/vendor/github.com/blang/semver/.travis.yml
@@ -0,0 +1,21 @@
+language: go
+matrix:
+ include:
+ - go: 1.4.3
+ - go: 1.5.4
+ - go: 1.6.3
+ - go: 1.7
+ - go: tip
+ allow_failures:
+ - go: tip
+install:
+- go get golang.org/x/tools/cmd/cover
+- go get github.com/mattn/goveralls
+script:
+- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci
+ -repotoken $COVERALLS_TOKEN
+- echo "Build examples" ; cd examples && go build
+- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .)
+env:
+ global:
+ secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw=
diff --git a/vendor/github.com/blang/semver/LICENSE b/vendor/github.com/blang/semver/LICENSE
new file mode 100644
index 0000000..5ba5c86
--- /dev/null
+++ b/vendor/github.com/blang/semver/LICENSE
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2014 Benedikt Lang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/vendor/github.com/blang/semver/README.md b/vendor/github.com/blang/semver/README.md
new file mode 100644
index 0000000..5ace9d1
--- /dev/null
+++ b/vendor/github.com/blang/semver/README.md
@@ -0,0 +1,194 @@
+semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/blang/semver)](https://goreportcard.com/report/github.com/blang/semver)
+======
+
+semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`.
+
+Usage
+-----
+```bash
+$ go get github.com/blang/semver
+```
+Note: Always vendor your dependencies or fix on a specific version tag.
+
+```go
+import github.com/blang/semver
+v1, err := semver.Make("1.0.0-beta")
+v2, err := semver.Make("2.0.0-beta")
+v1.Compare(v2)
+```
+
+Also check the [GoDocs](http://godoc.org/github.com/blang/semver).
+
+Why should I use this lib?
+-----
+
+- Fully spec compatible
+- No reflection
+- No regex
+- Fully tested (Coverage >99%)
+- Readable parsing/validation errors
+- Fast (See [Benchmarks](#benchmarks))
+- Only Stdlib
+- Uses values instead of pointers
+- Many features, see below
+
+
+Features
+-----
+
+- Parsing and validation at all levels
+- Comparator-like comparisons
+- Compare Helper Methods
+- InPlace manipulation
+- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1`
+- Wildcards `>=1.x`, `<=2.5.x`
+- Sortable (implements sort.Interface)
+- database/sql compatible (sql.Scanner/Valuer)
+- encoding/json compatible (json.Marshaler/Unmarshaler)
+
+Ranges
+------
+
+A `Range` is a set of conditions which specify which versions satisfy the range.
+
+A condition is composed of an operator and a version. The supported operators are:
+
+- `<1.0.0` Less than `1.0.0`
+- `<=1.0.0` Less than or equal to `1.0.0`
+- `>1.0.0` Greater than `1.0.0`
+- `>=1.0.0` Greater than or equal to `1.0.0`
+- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0`
+- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`.
+
+Note that spaces between the operator and the version will be gracefully tolerated.
+
+A `Range` can link multiple `Ranges` separated by space:
+
+Ranges can be linked by logical AND:
+
+ - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0`
+ - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2`
+
+Ranges can also be linked by logical OR:
+
+ - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x`
+
+AND has a higher precedence than OR. It's not possible to use brackets.
+
+Ranges can be combined by both AND and OR
+
+ - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
+
+Range usage:
+
+```
+v, err := semver.Parse("1.2.3")
+range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0")
+if range(v) {
+ //valid
+}
+
+```
+
+Example
+-----
+
+Have a look at full examples in [examples/main.go](examples/main.go)
+
+```go
+import github.com/blang/semver
+
+v, err := semver.Make("0.0.1-alpha.preview+123.github")
+fmt.Printf("Major: %d\n", v.Major)
+fmt.Printf("Minor: %d\n", v.Minor)
+fmt.Printf("Patch: %d\n", v.Patch)
+fmt.Printf("Pre: %s\n", v.Pre)
+fmt.Printf("Build: %s\n", v.Build)
+
+// Prerelease versions array
+if len(v.Pre) > 0 {
+ fmt.Println("Prerelease versions:")
+ for i, pre := range v.Pre {
+ fmt.Printf("%d: %q\n", i, pre)
+ }
+}
+
+// Build meta data array
+if len(v.Build) > 0 {
+ fmt.Println("Build meta data:")
+ for i, build := range v.Build {
+ fmt.Printf("%d: %q\n", i, build)
+ }
+}
+
+v001, err := semver.Make("0.0.1")
+// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE
+v001.GT(v) == true
+v.LT(v001) == true
+v.GTE(v) == true
+v.LTE(v) == true
+
+// Or use v.Compare(v2) for comparisons (-1, 0, 1):
+v001.Compare(v) == 1
+v.Compare(v001) == -1
+v.Compare(v) == 0
+
+// Manipulate Version in place:
+v.Pre[0], err = semver.NewPRVersion("beta")
+if err != nil {
+ fmt.Printf("Error parsing pre release version: %q", err)
+}
+
+fmt.Println("\nValidate versions:")
+v.Build[0] = "?"
+
+err = v.Validate()
+if err != nil {
+ fmt.Printf("Validation failed: %s\n", err)
+}
+```
+
+
+Benchmarks
+-----
+
+ BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op
+ BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op
+ BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op
+ BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op
+ BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op
+ BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op
+ BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op
+ BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op
+ BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op
+ BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op
+ BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op
+ BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op
+ BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op
+ BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op
+ BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op
+ BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op
+ BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op
+
+See benchmark cases at [semver_test.go](semver_test.go)
+
+
+Motivation
+-----
+
+I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like.
+
+
+Contribution
+-----
+
+Feel free to make a pull request. For bigger changes create a issue first to discuss about it.
+
+
+License
+-----
+
+See [LICENSE](LICENSE) file.
diff --git a/vendor/github.com/blang/semver/examples/main.go b/vendor/github.com/blang/semver/examples/main.go
new file mode 100644
index 0000000..f36c983
--- /dev/null
+++ b/vendor/github.com/blang/semver/examples/main.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+ "fmt"
+ "github.com/blang/semver"
+)
+
+func main() {
+ v, err := semver.Parse("0.0.1-alpha.preview.222+123.github")
+ if err != nil {
+ fmt.Printf("Error while parsing (not valid): %q", err)
+ }
+ fmt.Printf("Version to string: %q\n", v)
+
+ fmt.Printf("Major: %d\n", v.Major)
+ fmt.Printf("Minor: %d\n", v.Minor)
+ fmt.Printf("Patch: %d\n", v.Patch)
+
+ // Prerelease versions
+ if len(v.Pre) > 0 {
+ fmt.Println("Prerelease versions:")
+ for i, pre := range v.Pre {
+ fmt.Printf("%d: %q\n", i, pre)
+ }
+ }
+
+ // Build meta data
+ if len(v.Build) > 0 {
+ fmt.Println("Build meta data:")
+ for i, build := range v.Build {
+ fmt.Printf("%d: %q\n", i, build)
+ }
+ }
+
+ // Make == Parse (Value), New for Pointer
+ v001, err := semver.Make("0.0.1")
+
+ fmt.Println("\nUse Version.Compare for comparisons (-1, 0, 1):")
+ fmt.Printf("%q is greater than %q: Compare == %d\n", v001, v, v001.Compare(v))
+ fmt.Printf("%q is less than %q: Compare == %d\n", v, v001, v.Compare(v001))
+ fmt.Printf("%q is equal to %q: Compare == %d\n", v, v, v.Compare(v))
+
+ fmt.Println("\nUse comparison helpers returning booleans:")
+ fmt.Printf("%q is greater than %q: %t\n", v001, v, v001.GT(v))
+ fmt.Printf("%q is greater than equal %q: %t\n", v001, v, v001.GTE(v))
+ fmt.Printf("%q is greater than equal %q: %t\n", v, v, v.GTE(v))
+ fmt.Printf("%q is less than %q: %t\n", v, v001, v.LT(v001))
+ fmt.Printf("%q is less than equal %q: %t\n", v, v001, v.LTE(v001))
+ fmt.Printf("%q is less than equal %q: %t\n", v, v, v.LTE(v))
+
+ fmt.Println("\nManipulate Version in place:")
+ v.Pre[0], err = semver.NewPRVersion("beta")
+ if err != nil {
+ fmt.Printf("Error parsing pre release version: %q", err)
+ }
+ fmt.Printf("Version to string: %q\n", v)
+
+ fmt.Println("\nCompare Prerelease versions:")
+ pre1, _ := semver.NewPRVersion("123")
+ pre2, _ := semver.NewPRVersion("alpha")
+ pre3, _ := semver.NewPRVersion("124")
+ fmt.Printf("%q is less than %q: Compare == %d\n", pre1, pre2, pre1.Compare(pre2))
+ fmt.Printf("%q is greater than %q: Compare == %d\n", pre3, pre1, pre3.Compare(pre1))
+ fmt.Printf("%q is equal to %q: Compare == %d\n", pre1, pre1, pre1.Compare(pre1))
+
+ fmt.Println("\nValidate versions:")
+ v.Build[0] = "?"
+
+ err = v.Validate()
+ if err != nil {
+ fmt.Printf("Validation failed: %s\n", err)
+ }
+
+ fmt.Println("Create valid build meta data:")
+ b1, _ := semver.NewBuildVersion("build123")
+ v.Build[0] = b1
+ fmt.Printf("Version with new build version %q\n", v)
+
+ _, err = semver.NewBuildVersion("build?123")
+ if err != nil {
+ fmt.Printf("Create build version failed: %s\n", err)
+ }
+}
diff --git a/vendor/github.com/blang/semver/json.go b/vendor/github.com/blang/semver/json.go
new file mode 100644
index 0000000..a74bf7c
--- /dev/null
+++ b/vendor/github.com/blang/semver/json.go
@@ -0,0 +1,23 @@
+package semver
+
+import (
+ "encoding/json"
+)
+
+// MarshalJSON implements the encoding/json.Marshaler interface.
+func (v Version) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.String())
+}
+
+// UnmarshalJSON implements the encoding/json.Unmarshaler interface.
+func (v *Version) UnmarshalJSON(data []byte) (err error) {
+ var versionString string
+
+ if err = json.Unmarshal(data, &versionString); err != nil {
+ return
+ }
+
+ *v, err = Parse(versionString)
+
+ return
+}
diff --git a/vendor/github.com/blang/semver/json_test.go b/vendor/github.com/blang/semver/json_test.go
new file mode 100644
index 0000000..c635dea
--- /dev/null
+++ b/vendor/github.com/blang/semver/json_test.go
@@ -0,0 +1,49 @@
+package semver
+
+import (
+ "encoding/json"
+ "strconv"
+ "testing"
+)
+
+func TestJSONMarshal(t *testing.T) {
+ versionString := "3.1.4-alpha.1.5.9+build.2.6.5"
+ v, err := Parse(versionString)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ versionJSON, err := json.Marshal(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ quotedVersionString := strconv.Quote(versionString)
+
+ if string(versionJSON) != quotedVersionString {
+ t.Fatalf("JSON marshaled semantic version not equal: expected %q, got %q", quotedVersionString, string(versionJSON))
+ }
+}
+
+func TestJSONUnmarshal(t *testing.T) {
+ versionString := "3.1.4-alpha.1.5.9+build.2.6.5"
+ quotedVersionString := strconv.Quote(versionString)
+
+ var v Version
+ if err := json.Unmarshal([]byte(quotedVersionString), &v); err != nil {
+ t.Fatal(err)
+ }
+
+ if v.String() != versionString {
+ t.Fatalf("JSON unmarshaled semantic version not equal: expected %q, got %q", versionString, v.String())
+ }
+
+ badVersionString := strconv.Quote("3.1.4.1.5.9.2.6.5-other-digits-of-pi")
+ if err := json.Unmarshal([]byte(badVersionString), &v); err == nil {
+ t.Fatal("expected JSON unmarshal error, got nil")
+ }
+
+ if err := json.Unmarshal([]byte("3.1"), &v); err == nil {
+ t.Fatal("expected JSON unmarshal error, got nil")
+ }
+}
diff --git a/vendor/github.com/blang/semver/package.json b/vendor/github.com/blang/semver/package.json
new file mode 100644
index 0000000..1cf8ebd
--- /dev/null
+++ b/vendor/github.com/blang/semver/package.json
@@ -0,0 +1,17 @@
+{
+ "author": "blang",
+ "bugs": {
+ "URL": "https://github.com/blang/semver/issues",
+ "url": "https://github.com/blang/semver/issues"
+ },
+ "gx": {
+ "dvcsimport": "github.com/blang/semver"
+ },
+ "gxVersion": "0.10.0",
+ "language": "go",
+ "license": "MIT",
+ "name": "semver",
+ "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
+ "version": "3.5.1"
+}
+
diff --git a/vendor/github.com/blang/semver/range.go b/vendor/github.com/blang/semver/range.go
new file mode 100644
index 0000000..fca406d
--- /dev/null
+++ b/vendor/github.com/blang/semver/range.go
@@ -0,0 +1,416 @@
+package semver
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+type wildcardType int
+
+const (
+ noneWildcard wildcardType = iota
+ majorWildcard wildcardType = 1
+ minorWildcard wildcardType = 2
+ patchWildcard wildcardType = 3
+)
+
+func wildcardTypefromInt(i int) wildcardType {
+ switch i {
+ case 1:
+ return majorWildcard
+ case 2:
+ return minorWildcard
+ case 3:
+ return patchWildcard
+ default:
+ return noneWildcard
+ }
+}
+
+type comparator func(Version, Version) bool
+
+var (
+ compEQ comparator = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == 0
+ }
+ compNE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) != 0
+ }
+ compGT = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == 1
+ }
+ compGE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) >= 0
+ }
+ compLT = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == -1
+ }
+ compLE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) <= 0
+ }
+)
+
+type versionRange struct {
+ v Version
+ c comparator
+}
+
+// rangeFunc creates a Range from the given versionRange.
+func (vr *versionRange) rangeFunc() Range {
+ return Range(func(v Version) bool {
+ return vr.c(v, vr.v)
+ })
+}
+
+// Range represents a range of versions.
+// A Range can be used to check if a Version satisfies it:
+//
+// range, err := semver.ParseRange(">1.0.0 <2.0.0")
+// range(semver.MustParse("1.1.1") // returns true
+type Range func(Version) bool
+
+// OR combines the existing Range with another Range using logical OR.
+func (rf Range) OR(f Range) Range {
+ return Range(func(v Version) bool {
+ return rf(v) || f(v)
+ })
+}
+
+// AND combines the existing Range with another Range using logical AND.
+func (rf Range) AND(f Range) Range {
+ return Range(func(v Version) bool {
+ return rf(v) && f(v)
+ })
+}
+
+// ParseRange parses a range and returns a Range.
+// If the range could not be parsed an error is returned.
+//
+// Valid ranges are:
+// - "<1.0.0"
+// - "<=1.0.0"
+// - ">1.0.0"
+// - ">=1.0.0"
+// - "1.0.0", "=1.0.0", "==1.0.0"
+// - "!1.0.0", "!=1.0.0"
+//
+// A Range can consist of multiple ranges separated by space:
+// Ranges can be linked by logical AND:
+// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0"
+// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2
+//
+// Ranges can also be linked by logical OR:
+// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x"
+//
+// AND has a higher precedence than OR. It's not possible to use brackets.
+//
+// Ranges can be combined by both AND and OR
+//
+// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
+func ParseRange(s string) (Range, error) {
+ parts := splitAndTrim(s)
+ orParts, err := splitORParts(parts)
+ if err != nil {
+ return nil, err
+ }
+ expandedParts, err := expandWildcardVersion(orParts)
+ if err != nil {
+ return nil, err
+ }
+ var orFn Range
+ for _, p := range expandedParts {
+ var andFn Range
+ for _, ap := range p {
+ opStr, vStr, err := splitComparatorVersion(ap)
+ if err != nil {
+ return nil, err
+ }
+ vr, err := buildVersionRange(opStr, vStr)
+ if err != nil {
+ return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err)
+ }
+ rf := vr.rangeFunc()
+
+ // Set function
+ if andFn == nil {
+ andFn = rf
+ } else { // Combine with existing function
+ andFn = andFn.AND(rf)
+ }
+ }
+ if orFn == nil {
+ orFn = andFn
+ } else {
+ orFn = orFn.OR(andFn)
+ }
+
+ }
+ return orFn, nil
+}
+
+// splitORParts splits the already cleaned parts by '||'.
+// Checks for invalid positions of the operator and returns an
+// error if found.
+func splitORParts(parts []string) ([][]string, error) {
+ var ORparts [][]string
+ last := 0
+ for i, p := range parts {
+ if p == "||" {
+ if i == 0 {
+ return nil, fmt.Errorf("First element in range is '||'")
+ }
+ ORparts = append(ORparts, parts[last:i])
+ last = i + 1
+ }
+ }
+ if last == len(parts) {
+ return nil, fmt.Errorf("Last element in range is '||'")
+ }
+ ORparts = append(ORparts, parts[last:])
+ return ORparts, nil
+}
+
+// buildVersionRange takes a slice of 2: operator and version
+// and builds a versionRange, otherwise an error.
+func buildVersionRange(opStr, vStr string) (*versionRange, error) {
+ c := parseComparator(opStr)
+ if c == nil {
+ return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, ""))
+ }
+ v, err := Parse(vStr)
+ if err != nil {
+ return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err)
+ }
+
+ return &versionRange{
+ v: v,
+ c: c,
+ }, nil
+
+}
+
+// inArray checks if a byte is contained in an array of bytes
+func inArray(s byte, list []byte) bool {
+ for _, el := range list {
+ if el == s {
+ return true
+ }
+ }
+ return false
+}
+
+// splitAndTrim splits a range string by spaces and cleans whitespaces
+func splitAndTrim(s string) (result []string) {
+ last := 0
+ var lastChar byte
+ excludeFromSplit := []byte{'>', '<', '='}
+ for i := 0; i < len(s); i++ {
+ if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) {
+ if last < i-1 {
+ result = append(result, s[last:i])
+ }
+ last = i + 1
+ } else if s[i] != ' ' {
+ lastChar = s[i]
+ }
+ }
+ if last < len(s)-1 {
+ result = append(result, s[last:])
+ }
+
+ for i, v := range result {
+ result[i] = strings.Replace(v, " ", "", -1)
+ }
+
+ // parts := strings.Split(s, " ")
+ // for _, x := range parts {
+ // if s := strings.TrimSpace(x); len(s) != 0 {
+ // result = append(result, s)
+ // }
+ // }
+ return
+}
+
+// splitComparatorVersion splits the comparator from the version.
+// Input must be free of leading or trailing spaces.
+func splitComparatorVersion(s string) (string, string, error) {
+ i := strings.IndexFunc(s, unicode.IsDigit)
+ if i == -1 {
+ return "", "", fmt.Errorf("Could not get version from string: %q", s)
+ }
+ return strings.TrimSpace(s[0:i]), s[i:], nil
+}
+
+// getWildcardType will return the type of wildcard that the
+// passed version contains
+func getWildcardType(vStr string) wildcardType {
+ parts := strings.Split(vStr, ".")
+ nparts := len(parts)
+ wildcard := parts[nparts-1]
+
+ possibleWildcardType := wildcardTypefromInt(nparts)
+ if wildcard == "x" {
+ return possibleWildcardType
+ }
+
+ return noneWildcard
+}
+
+// createVersionFromWildcard will convert a wildcard version
+// into a regular version, replacing 'x's with '0's, handling
+// special cases like '1.x.x' and '1.x'
+func createVersionFromWildcard(vStr string) string {
+ // handle 1.x.x
+ vStr2 := strings.Replace(vStr, ".x.x", ".x", 1)
+ vStr2 = strings.Replace(vStr2, ".x", ".0", 1)
+ parts := strings.Split(vStr2, ".")
+
+ // handle 1.x
+ if len(parts) == 2 {
+ return vStr2 + ".0"
+ }
+
+ return vStr2
+}
+
+// incrementMajorVersion will increment the major version
+// of the passed version
+func incrementMajorVersion(vStr string) (string, error) {
+ parts := strings.Split(vStr, ".")
+ i, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return "", err
+ }
+ parts[0] = strconv.Itoa(i + 1)
+
+ return strings.Join(parts, "."), nil
+}
+
+// incrementMajorVersion will increment the minor version
+// of the passed version
+func incrementMinorVersion(vStr string) (string, error) {
+ parts := strings.Split(vStr, ".")
+ i, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return "", err
+ }
+ parts[1] = strconv.Itoa(i + 1)
+
+ return strings.Join(parts, "."), nil
+}
+
+// expandWildcardVersion will expand wildcards inside versions
+// following these rules:
+//
+// * when dealing with patch wildcards:
+// >= 1.2.x will become >= 1.2.0
+// <= 1.2.x will become < 1.3.0
+// > 1.2.x will become >= 1.3.0
+// < 1.2.x will become < 1.2.0
+// != 1.2.x will become < 1.2.0 >= 1.3.0
+//
+// * when dealing with minor wildcards:
+// >= 1.x will become >= 1.0.0
+// <= 1.x will become < 2.0.0
+// > 1.x will become >= 2.0.0
+// < 1.0 will become < 1.0.0
+// != 1.x will become < 1.0.0 >= 2.0.0
+//
+// * when dealing with wildcards without
+// version operator:
+// 1.2.x will become >= 1.2.0 < 1.3.0
+// 1.x will become >= 1.0.0 < 2.0.0
+func expandWildcardVersion(parts [][]string) ([][]string, error) {
+ var expandedParts [][]string
+ for _, p := range parts {
+ var newParts []string
+ for _, ap := range p {
+ if strings.Index(ap, "x") != -1 {
+ opStr, vStr, err := splitComparatorVersion(ap)
+ if err != nil {
+ return nil, err
+ }
+
+ versionWildcardType := getWildcardType(vStr)
+ flatVersion := createVersionFromWildcard(vStr)
+
+ var resultOperator string
+ var shouldIncrementVersion bool
+ switch opStr {
+ case ">":
+ resultOperator = ">="
+ shouldIncrementVersion = true
+ case ">=":
+ resultOperator = ">="
+ case "<":
+ resultOperator = "<"
+ case "<=":
+ resultOperator = "<"
+ shouldIncrementVersion = true
+ case "", "=", "==":
+ newParts = append(newParts, ">="+flatVersion)
+ resultOperator = "<"
+ shouldIncrementVersion = true
+ case "!=", "!":
+ newParts = append(newParts, "<"+flatVersion)
+ resultOperator = ">="
+ shouldIncrementVersion = true
+ }
+
+ var resultVersion string
+ if shouldIncrementVersion {
+ switch versionWildcardType {
+ case patchWildcard:
+ resultVersion, _ = incrementMinorVersion(flatVersion)
+ case minorWildcard:
+ resultVersion, _ = incrementMajorVersion(flatVersion)
+ }
+ } else {
+ resultVersion = flatVersion
+ }
+
+ ap = resultOperator + resultVersion
+ }
+ newParts = append(newParts, ap)
+ }
+ expandedParts = append(expandedParts, newParts)
+ }
+
+ return expandedParts, nil
+}
+
+func parseComparator(s string) comparator {
+ switch s {
+ case "==":
+ fallthrough
+ case "":
+ fallthrough
+ case "=":
+ return compEQ
+ case ">":
+ return compGT
+ case ">=":
+ return compGE
+ case "<":
+ return compLT
+ case "<=":
+ return compLE
+ case "!":
+ fallthrough
+ case "!=":
+ return compNE
+ }
+
+ return nil
+}
+
+// MustParseRange is like ParseRange but panics if the range cannot be parsed.
+func MustParseRange(s string) Range {
+ r, err := ParseRange(s)
+ if err != nil {
+ panic(`semver: ParseRange(` + s + `): ` + err.Error())
+ }
+ return r
+}
diff --git a/vendor/github.com/blang/semver/range_test.go b/vendor/github.com/blang/semver/range_test.go
new file mode 100644
index 0000000..fc11670
--- /dev/null
+++ b/vendor/github.com/blang/semver/range_test.go
@@ -0,0 +1,581 @@
+package semver
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type wildcardTypeTest struct {
+ input string
+ wildcardType wildcardType
+}
+
+type comparatorTest struct {
+ input string
+ comparator func(comparator) bool
+}
+
+func TestParseComparator(t *testing.T) {
+ compatorTests := []comparatorTest{
+ {">", testGT},
+ {">=", testGE},
+ {"<", testLT},
+ {"<=", testLE},
+ {"", testEQ},
+ {"=", testEQ},
+ {"==", testEQ},
+ {"!=", testNE},
+ {"!", testNE},
+ {"-", nil},
+ {"<==", nil},
+ {"<<", nil},
+ {">>", nil},
+ }
+
+ for _, tc := range compatorTests {
+ if c := parseComparator(tc.input); c == nil {
+ if tc.comparator != nil {
+ t.Errorf("Comparator nil for case %q\n", tc.input)
+ }
+ } else if !tc.comparator(c) {
+ t.Errorf("Invalid comparator for case %q\n", tc.input)
+ }
+ }
+}
+
+var (
+ v1 = MustParse("1.2.2")
+ v2 = MustParse("1.2.3")
+ v3 = MustParse("1.2.4")
+)
+
+func testEQ(f comparator) bool {
+ return f(v1, v1) && !f(v1, v2)
+}
+
+func testNE(f comparator) bool {
+ return !f(v1, v1) && f(v1, v2)
+}
+
+func testGT(f comparator) bool {
+ return f(v2, v1) && f(v3, v2) && !f(v1, v2) && !f(v1, v1)
+}
+
+func testGE(f comparator) bool {
+ return f(v2, v1) && f(v3, v2) && !f(v1, v2)
+}
+
+func testLT(f comparator) bool {
+ return f(v1, v2) && f(v2, v3) && !f(v2, v1) && !f(v1, v1)
+}
+
+func testLE(f comparator) bool {
+ return f(v1, v2) && f(v2, v3) && !f(v2, v1)
+}
+
+func TestSplitAndTrim(t *testing.T) {
+ tests := []struct {
+ i string
+ s []string
+ }{
+ {"1.2.3 1.2.3", []string{"1.2.3", "1.2.3"}},
+ {" 1.2.3 1.2.3 ", []string{"1.2.3", "1.2.3"}}, // Spaces
+ {" >= 1.2.3 <= 1.2.3 ", []string{">=1.2.3", "<=1.2.3"}}, // Spaces between operator and version
+ {"1.2.3 || >=1.2.3 <1.2.3", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
+ {" 1.2.3 || >=1.2.3 <1.2.3 ", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
+ }
+
+ for _, tc := range tests {
+ p := splitAndTrim(tc.i)
+ if !reflect.DeepEqual(p, tc.s) {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
+ }
+ }
+}
+
+func TestSplitComparatorVersion(t *testing.T) {
+ tests := []struct {
+ i string
+ p []string
+ }{
+ {">1.2.3", []string{">", "1.2.3"}},
+ {">=1.2.3", []string{">=", "1.2.3"}},
+ {"<1.2.3", []string{"<", "1.2.3"}},
+ {"<=1.2.3", []string{"<=", "1.2.3"}},
+ {"1.2.3", []string{"", "1.2.3"}},
+ {"=1.2.3", []string{"=", "1.2.3"}},
+ {"==1.2.3", []string{"==", "1.2.3"}},
+ {"!=1.2.3", []string{"!=", "1.2.3"}},
+ {"!1.2.3", []string{"!", "1.2.3"}},
+ {"error", nil},
+ }
+ for _, tc := range tests {
+ if op, v, err := splitComparatorVersion(tc.i); err != nil {
+ if tc.p != nil {
+ t.Errorf("Invalid for case %q: Expected %q, got error %q", tc.i, tc.p, err)
+ }
+ } else if op != tc.p[0] {
+ t.Errorf("Invalid operator for case %q: Expected %q, got: %q", tc.i, tc.p[0], op)
+ } else if v != tc.p[1] {
+ t.Errorf("Invalid version for case %q: Expected %q, got: %q", tc.i, tc.p[1], v)
+ }
+
+ }
+}
+
+func TestBuildVersionRange(t *testing.T) {
+ tests := []struct {
+ opStr string
+ vStr string
+ c func(comparator) bool
+ v string
+ }{
+ {">", "1.2.3", testGT, "1.2.3"},
+ {">=", "1.2.3", testGE, "1.2.3"},
+ {"<", "1.2.3", testLT, "1.2.3"},
+ {"<=", "1.2.3", testLE, "1.2.3"},
+ {"", "1.2.3", testEQ, "1.2.3"},
+ {"=", "1.2.3", testEQ, "1.2.3"},
+ {"==", "1.2.3", testEQ, "1.2.3"},
+ {"!=", "1.2.3", testNE, "1.2.3"},
+ {"!", "1.2.3", testNE, "1.2.3"},
+ {">>", "1.2.3", nil, ""}, // Invalid comparator
+ {"=", "invalid", nil, ""}, // Invalid version
+ }
+
+ for _, tc := range tests {
+ if r, err := buildVersionRange(tc.opStr, tc.vStr); err != nil {
+ if tc.c != nil {
+ t.Errorf("Invalid for case %q: Expected %q, got error %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tc.v, err)
+ }
+ } else if r == nil {
+ t.Errorf("Invalid for case %q: got nil", strings.Join([]string{tc.opStr, tc.vStr}, ""))
+ } else {
+ // test version
+ if tv := MustParse(tc.v); !r.v.EQ(tv) {
+ t.Errorf("Invalid for case %q: Expected version %q, got: %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tv, r.v)
+ }
+ // test comparator
+ if r.c == nil {
+ t.Errorf("Invalid for case %q: got nil comparator", strings.Join([]string{tc.opStr, tc.vStr}, ""))
+ continue
+ }
+ if !tc.c(r.c) {
+ t.Errorf("Invalid comparator for case %q\n", strings.Join([]string{tc.opStr, tc.vStr}, ""))
+ }
+ }
+ }
+
+}
+
+func TestSplitORParts(t *testing.T) {
+ tests := []struct {
+ i []string
+ o [][]string
+ }{
+ {[]string{">1.2.3", "||", "<1.2.3", "||", "=1.2.3"}, [][]string{
+ {">1.2.3"},
+ {"<1.2.3"},
+ {"=1.2.3"},
+ }},
+ {[]string{">1.2.3", "<1.2.3", "||", "=1.2.3"}, [][]string{
+ {">1.2.3", "<1.2.3"},
+ {"=1.2.3"},
+ }},
+ {[]string{">1.2.3", "||"}, nil},
+ {[]string{"||", ">1.2.3"}, nil},
+ }
+ for _, tc := range tests {
+ o, err := splitORParts(tc.i)
+ if err != nil && tc.o != nil {
+ t.Errorf("Unexpected error for case %q: %s", tc.i, err)
+ }
+ if !reflect.DeepEqual(tc.o, o) {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o)
+ }
+ }
+}
+
+func TestGetWildcardType(t *testing.T) {
+ wildcardTypeTests := []wildcardTypeTest{
+ {"x", majorWildcard},
+ {"1.x", minorWildcard},
+ {"1.2.x", patchWildcard},
+ {"fo.o.b.ar", noneWildcard},
+ }
+
+ for _, tc := range wildcardTypeTests {
+ o := getWildcardType(tc.input)
+ if o != tc.wildcardType {
+ t.Errorf("Invalid for case: %q: Expected %q, got: %q", tc.input, tc.wildcardType, o)
+ }
+ }
+}
+
+func TestCreateVersionFromWildcard(t *testing.T) {
+ tests := []struct {
+ i string
+ s string
+ }{
+ {"1.2.x", "1.2.0"},
+ {"1.x", "1.0.0"},
+ }
+
+ for _, tc := range tests {
+ p := createVersionFromWildcard(tc.i)
+ if p != tc.s {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
+ }
+ }
+}
+
+func TestIncrementMajorVersion(t *testing.T) {
+ tests := []struct {
+ i string
+ s string
+ }{
+ {"1.2.3", "2.2.3"},
+ {"1.2", "2.2"},
+ {"foo.bar", ""},
+ }
+
+ for _, tc := range tests {
+ p, _ := incrementMajorVersion(tc.i)
+ if p != tc.s {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
+ }
+ }
+}
+
+func TestIncrementMinorVersion(t *testing.T) {
+ tests := []struct {
+ i string
+ s string
+ }{
+ {"1.2.3", "1.3.3"},
+ {"1.2", "1.3"},
+ {"foo.bar", ""},
+ }
+
+ for _, tc := range tests {
+ p, _ := incrementMinorVersion(tc.i)
+ if p != tc.s {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
+ }
+ }
+}
+
+func TestExpandWildcardVersion(t *testing.T) {
+ tests := []struct {
+ i [][]string
+ o [][]string
+ }{
+ {[][]string{{"foox"}}, nil},
+ {[][]string{{">=1.2.x"}}, [][]string{{">=1.2.0"}}},
+ {[][]string{{"<=1.2.x"}}, [][]string{{"<1.3.0"}}},
+ {[][]string{{">1.2.x"}}, [][]string{{">=1.3.0"}}},
+ {[][]string{{"<1.2.x"}}, [][]string{{"<1.2.0"}}},
+ {[][]string{{"!=1.2.x"}}, [][]string{{"<1.2.0", ">=1.3.0"}}},
+ {[][]string{{">=1.x"}}, [][]string{{">=1.0.0"}}},
+ {[][]string{{"<=1.x"}}, [][]string{{"<2.0.0"}}},
+ {[][]string{{">1.x"}}, [][]string{{">=2.0.0"}}},
+ {[][]string{{"<1.x"}}, [][]string{{"<1.0.0"}}},
+ {[][]string{{"!=1.x"}}, [][]string{{"<1.0.0", ">=2.0.0"}}},
+ {[][]string{{"1.2.x"}}, [][]string{{">=1.2.0", "<1.3.0"}}},
+ {[][]string{{"1.x"}}, [][]string{{">=1.0.0", "<2.0.0"}}},
+ }
+
+ for _, tc := range tests {
+ o, _ := expandWildcardVersion(tc.i)
+ if !reflect.DeepEqual(tc.o, o) {
+ t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o)
+ }
+ }
+}
+
+func TestVersionRangeToRange(t *testing.T) {
+ vr := versionRange{
+ v: MustParse("1.2.3"),
+ c: compLT,
+ }
+ rf := vr.rangeFunc()
+ if !rf(MustParse("1.2.2")) || rf(MustParse("1.2.3")) {
+ t.Errorf("Invalid conversion to range func")
+ }
+}
+
+func TestRangeAND(t *testing.T) {
+ v := MustParse("1.2.2")
+ v1 := MustParse("1.2.1")
+ v2 := MustParse("1.2.3")
+ rf1 := Range(func(v Version) bool {
+ return v.GT(v1)
+ })
+ rf2 := Range(func(v Version) bool {
+ return v.LT(v2)
+ })
+ rf := rf1.AND(rf2)
+ if rf(v1) {
+ t.Errorf("Invalid rangefunc, accepted: %s", v1)
+ }
+ if rf(v2) {
+ t.Errorf("Invalid rangefunc, accepted: %s", v2)
+ }
+ if !rf(v) {
+ t.Errorf("Invalid rangefunc, did not accept: %s", v)
+ }
+}
+
+func TestRangeOR(t *testing.T) {
+ tests := []struct {
+ v Version
+ b bool
+ }{
+ {MustParse("1.2.0"), true},
+ {MustParse("1.2.2"), false},
+ {MustParse("1.2.4"), true},
+ }
+ v1 := MustParse("1.2.1")
+ v2 := MustParse("1.2.3")
+ rf1 := Range(func(v Version) bool {
+ return v.LT(v1)
+ })
+ rf2 := Range(func(v Version) bool {
+ return v.GT(v2)
+ })
+ rf := rf1.OR(rf2)
+ for _, tc := range tests {
+ if r := rf(tc.v); r != tc.b {
+ t.Errorf("Invalid for case %q: Expected %t, got %t", tc.v, tc.b, r)
+ }
+ }
+}
+
+func TestParseRange(t *testing.T) {
+ type tv struct {
+ v string
+ b bool
+ }
+ tests := []struct {
+ i string
+ t []tv
+ }{
+ // Simple expressions
+ {">1.2.3", []tv{
+ {"1.2.2", false},
+ {"1.2.3", false},
+ {"1.2.4", true},
+ }},
+ {">=1.2.3", []tv{
+ {"1.2.3", true},
+ {"1.2.4", true},
+ {"1.2.2", false},
+ }},
+ {"<1.2.3", []tv{
+ {"1.2.2", true},
+ {"1.2.3", false},
+ {"1.2.4", false},
+ }},
+ {"<=1.2.3", []tv{
+ {"1.2.2", true},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ }},
+ {"1.2.3", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ }},
+ {"=1.2.3", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ }},
+ {"==1.2.3", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ }},
+ {"!=1.2.3", []tv{
+ {"1.2.2", true},
+ {"1.2.3", false},
+ {"1.2.4", true},
+ }},
+ {"!1.2.3", []tv{
+ {"1.2.2", true},
+ {"1.2.3", false},
+ {"1.2.4", true},
+ }},
+ // Simple Expression errors
+ {">>1.2.3", nil},
+ {"!1.2.3", nil},
+ {"1.0", nil},
+ {"string", nil},
+ {"", nil},
+ {"fo.ob.ar.x", nil},
+ // AND Expressions
+ {">1.2.2 <1.2.4", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ }},
+ {"<1.2.2 <1.2.4", []tv{
+ {"1.2.1", true},
+ {"1.2.2", false},
+ {"1.2.3", false},
+ {"1.2.4", false},
+ }},
+ {">1.2.2 <1.2.5 !=1.2.4", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ {"1.2.5", false},
+ }},
+ {">1.2.2 <1.2.5 !1.2.4", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ {"1.2.5", false},
+ }},
+ // OR Expressions
+ {">1.2.2 || <1.2.4", []tv{
+ {"1.2.2", true},
+ {"1.2.3", true},
+ {"1.2.4", true},
+ }},
+ {"<1.2.2 || >1.2.4", []tv{
+ {"1.2.2", false},
+ {"1.2.3", false},
+ {"1.2.4", false},
+ }},
+ // Wildcard expressions
+ {">1.x", []tv{
+ {"0.1.9", false},
+ {"1.2.6", false},
+ {"1.9.0", false},
+ {"2.0.0", true},
+ }},
+ {">1.2.x", []tv{
+ {"1.1.9", false},
+ {"1.2.6", false},
+ {"1.3.0", true},
+ }},
+ // Combined Expressions
+ {">1.2.2 <1.2.4 || >=2.0.0", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ {"2.0.0", true},
+ {"2.0.1", true},
+ }},
+ {"1.x || >=2.0.x <2.2.x", []tv{
+ {"0.9.2", false},
+ {"1.2.2", true},
+ {"2.0.0", true},
+ {"2.1.8", true},
+ {"2.2.0", false},
+ }},
+ {">1.2.2 <1.2.4 || >=2.0.0 <3.0.0", []tv{
+ {"1.2.2", false},
+ {"1.2.3", true},
+ {"1.2.4", false},
+ {"2.0.0", true},
+ {"2.0.1", true},
+ {"2.9.9", true},
+ {"3.0.0", false},
+ }},
+ }
+
+ for _, tc := range tests {
+ r, err := ParseRange(tc.i)
+ if err != nil && tc.t != nil {
+ t.Errorf("Error parsing range %q: %s", tc.i, err)
+ continue
+ }
+ for _, tvc := range tc.t {
+ v := MustParse(tvc.v)
+ if res := r(v); res != tvc.b {
+ t.Errorf("Invalid for case %q matching %q: Expected %t, got: %t", tc.i, tvc.v, tvc.b, res)
+ }
+ }
+
+ }
+}
+
+func TestMustParseRange(t *testing.T) {
+ testCase := ">1.2.2 <1.2.4 || >=2.0.0 <3.0.0"
+ r := MustParseRange(testCase)
+ if !r(MustParse("1.2.3")) {
+ t.Errorf("Unexpected range behavior on MustParseRange")
+ }
+}
+
+func TestMustParseRange_panic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Errorf("Should have panicked")
+ }
+ }()
+ _ = MustParseRange("invalid version")
+}
+
+func BenchmarkRangeParseSimple(b *testing.B) {
+ const VERSION = ">1.0.0"
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ ParseRange(VERSION)
+ }
+}
+
+func BenchmarkRangeParseAverage(b *testing.B) {
+ const VERSION = ">=1.0.0 <2.0.0"
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ ParseRange(VERSION)
+ }
+}
+
+func BenchmarkRangeParseComplex(b *testing.B) {
+ const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ ParseRange(VERSION)
+ }
+}
+
+func BenchmarkRangeMatchSimple(b *testing.B) {
+ const VERSION = ">1.0.0"
+ r, _ := ParseRange(VERSION)
+ v := MustParse("2.0.0")
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ r(v)
+ }
+}
+
+func BenchmarkRangeMatchAverage(b *testing.B) {
+ const VERSION = ">=1.0.0 <2.0.0"
+ r, _ := ParseRange(VERSION)
+ v := MustParse("1.2.3")
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ r(v)
+ }
+}
+
+func BenchmarkRangeMatchComplex(b *testing.B) {
+ const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
+ r, _ := ParseRange(VERSION)
+ v := MustParse("5.0.1")
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ r(v)
+ }
+}
diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go
new file mode 100644
index 0000000..ec26aa0
--- /dev/null
+++ b/vendor/github.com/blang/semver/semver.go
@@ -0,0 +1,418 @@
+package semver
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const (
+ numbers string = "0123456789"
+ alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
+ alphanum = alphas + numbers
+)
+
+// SpecVersion is the latest fully supported spec version of semver
+var SpecVersion = Version{
+ Major: 2,
+ Minor: 0,
+ Patch: 0,
+}
+
+// Version represents a semver compatible version
+type Version struct {
+ Major uint64
+ Minor uint64
+ Patch uint64
+ Pre []PRVersion
+ Build []string //No Precedence
+}
+
+// Version to string
+func (v Version) String() string {
+ b := make([]byte, 0, 5)
+ b = strconv.AppendUint(b, v.Major, 10)
+ b = append(b, '.')
+ b = strconv.AppendUint(b, v.Minor, 10)
+ b = append(b, '.')
+ b = strconv.AppendUint(b, v.Patch, 10)
+
+ if len(v.Pre) > 0 {
+ b = append(b, '-')
+ b = append(b, v.Pre[0].String()...)
+
+ for _, pre := range v.Pre[1:] {
+ b = append(b, '.')
+ b = append(b, pre.String()...)
+ }
+ }
+
+ if len(v.Build) > 0 {
+ b = append(b, '+')
+ b = append(b, v.Build[0]...)
+
+ for _, build := range v.Build[1:] {
+ b = append(b, '.')
+ b = append(b, build...)
+ }
+ }
+
+ return string(b)
+}
+
+// Equals checks if v is equal to o.
+func (v Version) Equals(o Version) bool {
+ return (v.Compare(o) == 0)
+}
+
+// EQ checks if v is equal to o.
+func (v Version) EQ(o Version) bool {
+ return (v.Compare(o) == 0)
+}
+
+// NE checks if v is not equal to o.
+func (v Version) NE(o Version) bool {
+ return (v.Compare(o) != 0)
+}
+
+// GT checks if v is greater than o.
+func (v Version) GT(o Version) bool {
+ return (v.Compare(o) == 1)
+}
+
+// GTE checks if v is greater than or equal to o.
+func (v Version) GTE(o Version) bool {
+ return (v.Compare(o) >= 0)
+}
+
+// GE checks if v is greater than or equal to o.
+func (v Version) GE(o Version) bool {
+ return (v.Compare(o) >= 0)
+}
+
+// LT checks if v is less than o.
+func (v Version) LT(o Version) bool {
+ return (v.Compare(o) == -1)
+}
+
+// LTE checks if v is less than or equal to o.
+func (v Version) LTE(o Version) bool {
+ return (v.Compare(o) <= 0)
+}
+
+// LE checks if v is less than or equal to o.
+func (v Version) LE(o Version) bool {
+ return (v.Compare(o) <= 0)
+}
+
+// Compare compares Versions v to o:
+// -1 == v is less than o
+// 0 == v is equal to o
+// 1 == v is greater than o
+func (v Version) Compare(o Version) int {
+ if v.Major != o.Major {
+ if v.Major > o.Major {
+ return 1
+ }
+ return -1
+ }
+ if v.Minor != o.Minor {
+ if v.Minor > o.Minor {
+ return 1
+ }
+ return -1
+ }
+ if v.Patch != o.Patch {
+ if v.Patch > o.Patch {
+ return 1
+ }
+ return -1
+ }
+
+ // Quick comparison if a version has no prerelease versions
+ if len(v.Pre) == 0 && len(o.Pre) == 0 {
+ return 0
+ } else if len(v.Pre) == 0 && len(o.Pre) > 0 {
+ return 1
+ } else if len(v.Pre) > 0 && len(o.Pre) == 0 {
+ return -1
+ }
+
+ i := 0
+ for ; i < len(v.Pre) && i < len(o.Pre); i++ {
+ if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 {
+ continue
+ } else if comp == 1 {
+ return 1
+ } else {
+ return -1
+ }
+ }
+
+ // If all pr versions are the equal but one has further prversion, this one greater
+ if i == len(v.Pre) && i == len(o.Pre) {
+ return 0
+ } else if i == len(v.Pre) && i < len(o.Pre) {
+ return -1
+ } else {
+ return 1
+ }
+
+}
+
+// Validate validates v and returns error in case
+func (v Version) Validate() error {
+ // Major, Minor, Patch already validated using uint64
+
+ for _, pre := range v.Pre {
+ if !pre.IsNum { //Numeric prerelease versions already uint64
+ if len(pre.VersionStr) == 0 {
+ return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr)
+ }
+ if !containsOnly(pre.VersionStr, alphanum) {
+ return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr)
+ }
+ }
+ }
+
+ for _, build := range v.Build {
+ if len(build) == 0 {
+ return fmt.Errorf("Build meta data can not be empty %q", build)
+ }
+ if !containsOnly(build, alphanum) {
+ return fmt.Errorf("Invalid character(s) found in build meta data %q", build)
+ }
+ }
+
+ return nil
+}
+
+// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error
+func New(s string) (vp *Version, err error) {
+ v, err := Parse(s)
+ vp = &v
+ return
+}
+
+// Make is an alias for Parse, parses version string and returns a validated Version or error
+func Make(s string) (Version, error) {
+ return Parse(s)
+}
+
+// ParseTolerant allows for certain version specifications that do not strictly adhere to semver
+// specs to be parsed by this library. It does so by normalizing versions before passing them to
+// Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions
+// with only major and minor components specified
+func ParseTolerant(s string) (Version, error) {
+ s = strings.TrimSpace(s)
+ s = strings.TrimPrefix(s, "v")
+
+ // Split into major.minor.(patch+pr+meta)
+ parts := strings.SplitN(s, ".", 3)
+ if len(parts) < 3 {
+ if strings.ContainsAny(parts[len(parts)-1], "+-") {
+ return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data")
+ }
+ for len(parts) < 3 {
+ parts = append(parts, "0")
+ }
+ s = strings.Join(parts, ".")
+ }
+
+ return Parse(s)
+}
+
+// Parse parses version string and returns a validated Version or error
+func Parse(s string) (Version, error) {
+ if len(s) == 0 {
+ return Version{}, errors.New("Version string empty")
+ }
+
+ // Split into major.minor.(patch+pr+meta)
+ parts := strings.SplitN(s, ".", 3)
+ if len(parts) != 3 {
+ return Version{}, errors.New("No Major.Minor.Patch elements found")
+ }
+
+ // Major
+ if !containsOnly(parts[0], numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0])
+ }
+ if hasLeadingZeroes(parts[0]) {
+ return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0])
+ }
+ major, err := strconv.ParseUint(parts[0], 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ // Minor
+ if !containsOnly(parts[1], numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1])
+ }
+ if hasLeadingZeroes(parts[1]) {
+ return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1])
+ }
+ minor, err := strconv.ParseUint(parts[1], 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ v := Version{}
+ v.Major = major
+ v.Minor = minor
+
+ var build, prerelease []string
+ patchStr := parts[2]
+
+ if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 {
+ build = strings.Split(patchStr[buildIndex+1:], ".")
+ patchStr = patchStr[:buildIndex]
+ }
+
+ if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 {
+ prerelease = strings.Split(patchStr[preIndex+1:], ".")
+ patchStr = patchStr[:preIndex]
+ }
+
+ if !containsOnly(patchStr, numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr)
+ }
+ if hasLeadingZeroes(patchStr) {
+ return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr)
+ }
+ patch, err := strconv.ParseUint(patchStr, 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ v.Patch = patch
+
+ // Prerelease
+ for _, prstr := range prerelease {
+ parsedPR, err := NewPRVersion(prstr)
+ if err != nil {
+ return Version{}, err
+ }
+ v.Pre = append(v.Pre, parsedPR)
+ }
+
+ // Build meta data
+ for _, str := range build {
+ if len(str) == 0 {
+ return Version{}, errors.New("Build meta data is empty")
+ }
+ if !containsOnly(str, alphanum) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str)
+ }
+ v.Build = append(v.Build, str)
+ }
+
+ return v, nil
+}
+
+// MustParse is like Parse but panics if the version cannot be parsed.
+func MustParse(s string) Version {
+ v, err := Parse(s)
+ if err != nil {
+ panic(`semver: Parse(` + s + `): ` + err.Error())
+ }
+ return v
+}
+
+// PRVersion represents a PreRelease Version
+type PRVersion struct {
+ VersionStr string
+ VersionNum uint64
+ IsNum bool
+}
+
+// NewPRVersion creates a new valid prerelease version
+func NewPRVersion(s string) (PRVersion, error) {
+ if len(s) == 0 {
+ return PRVersion{}, errors.New("Prerelease is empty")
+ }
+ v := PRVersion{}
+ if containsOnly(s, numbers) {
+ if hasLeadingZeroes(s) {
+ return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s)
+ }
+ num, err := strconv.ParseUint(s, 10, 64)
+
+ // Might never be hit, but just in case
+ if err != nil {
+ return PRVersion{}, err
+ }
+ v.VersionNum = num
+ v.IsNum = true
+ } else if containsOnly(s, alphanum) {
+ v.VersionStr = s
+ v.IsNum = false
+ } else {
+ return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s)
+ }
+ return v, nil
+}
+
+// IsNumeric checks if prerelease-version is numeric
+func (v PRVersion) IsNumeric() bool {
+ return v.IsNum
+}
+
+// Compare compares two PreRelease Versions v and o:
+// -1 == v is less than o
+// 0 == v is equal to o
+// 1 == v is greater than o
+func (v PRVersion) Compare(o PRVersion) int {
+ if v.IsNum && !o.IsNum {
+ return -1
+ } else if !v.IsNum && o.IsNum {
+ return 1
+ } else if v.IsNum && o.IsNum {
+ if v.VersionNum == o.VersionNum {
+ return 0
+ } else if v.VersionNum > o.VersionNum {
+ return 1
+ } else {
+ return -1
+ }
+ } else { // both are Alphas
+ if v.VersionStr == o.VersionStr {
+ return 0
+ } else if v.VersionStr > o.VersionStr {
+ return 1
+ } else {
+ return -1
+ }
+ }
+}
+
+// PreRelease version to string
+func (v PRVersion) String() string {
+ if v.IsNum {
+ return strconv.FormatUint(v.VersionNum, 10)
+ }
+ return v.VersionStr
+}
+
+func containsOnly(s string, set string) bool {
+ return strings.IndexFunc(s, func(r rune) bool {
+ return !strings.ContainsRune(set, r)
+ }) == -1
+}
+
+func hasLeadingZeroes(s string) bool {
+ return len(s) > 1 && s[0] == '0'
+}
+
+// NewBuildVersion creates a new valid build version
+func NewBuildVersion(s string) (string, error) {
+ if len(s) == 0 {
+ return "", errors.New("Buildversion is empty")
+ }
+ if !containsOnly(s, alphanum) {
+ return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s)
+ }
+ return s, nil
+}
diff --git a/vendor/github.com/blang/semver/semver_test.go b/vendor/github.com/blang/semver/semver_test.go
new file mode 100644
index 0000000..b3e1fd4
--- /dev/null
+++ b/vendor/github.com/blang/semver/semver_test.go
@@ -0,0 +1,458 @@
+package semver
+
+import (
+ "testing"
+)
+
+func prstr(s string) PRVersion {
+ return PRVersion{s, 0, false}
+}
+
+func prnum(i uint64) PRVersion {
+ return PRVersion{"", i, true}
+}
+
+type formatTest struct {
+ v Version
+ result string
+}
+
+var formatTests = []formatTest{
+ {Version{1, 2, 3, nil, nil}, "1.2.3"},
+ {Version{0, 0, 1, nil, nil}, "0.0.1"},
+ {Version{0, 0, 1, []PRVersion{prstr("alpha"), prstr("preview")}, []string{"123", "456"}}, "0.0.1-alpha.preview+123.456"},
+ {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, []string{"123", "456"}}, "1.2.3-alpha.1+123.456"},
+ {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, nil}, "1.2.3-alpha.1"},
+ {Version{1, 2, 3, nil, []string{"123", "456"}}, "1.2.3+123.456"},
+ // Prereleases and build metadata hyphens
+ {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, []string{"123", "b-uild"}}, "1.2.3-alpha.b-eta+123.b-uild"},
+ {Version{1, 2, 3, nil, []string{"123", "b-uild"}}, "1.2.3+123.b-uild"},
+ {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, nil}, "1.2.3-alpha.b-eta"},
+}
+
+var tolerantFormatTests = []formatTest{
+ {Version{1, 2, 3, nil, nil}, "v1.2.3"},
+ {Version{1, 2, 3, nil, nil}, " 1.2.3 "},
+ {Version{1, 2, 0, nil, nil}, "1.2"},
+ {Version{1, 0, 0, nil, nil}, "1"},
+}
+
+func TestStringer(t *testing.T) {
+ for _, test := range formatTests {
+ if res := test.v.String(); res != test.result {
+ t.Errorf("Stringer, expected %q but got %q", test.result, res)
+ }
+ }
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range formatTests {
+ if v, err := Parse(test.result); err != nil {
+ t.Errorf("Error parsing %q: %q", test.result, err)
+ } else if comp := v.Compare(test.v); comp != 0 {
+ t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp)
+ } else if err := v.Validate(); err != nil {
+ t.Errorf("Error validating parsed version %q: %q", test.v, err)
+ }
+ }
+}
+
+func TestParseTolerant(t *testing.T) {
+ for _, test := range tolerantFormatTests {
+ if v, err := ParseTolerant(test.result); err != nil {
+ t.Errorf("Error parsing %q: %q", test.result, err)
+ } else if comp := v.Compare(test.v); comp != 0 {
+ t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp)
+ } else if err := v.Validate(); err != nil {
+ t.Errorf("Error validating parsed version %q: %q", test.v, err)
+ }
+ }
+}
+
+func TestMustParse(t *testing.T) {
+ _ = MustParse("32.2.1-alpha")
+}
+
+func TestMustParse_panic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Errorf("Should have panicked")
+ }
+ }()
+ _ = MustParse("invalid version")
+}
+
+func TestValidate(t *testing.T) {
+ for _, test := range formatTests {
+ if err := test.v.Validate(); err != nil {
+ t.Errorf("Error validating %q: %q", test.v, err)
+ }
+ }
+}
+
+type compareTest struct {
+ v1 Version
+ v2 Version
+ result int
+}
+
+var compareTests = []compareTest{
+ {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 0},
+ {Version{2, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 1},
+ {Version{0, 1, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 0},
+ {Version{0, 2, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 1},
+ {Version{0, 0, 1, nil, nil}, Version{0, 0, 1, nil, nil}, 0},
+ {Version{0, 0, 2, nil, nil}, Version{0, 0, 1, nil, nil}, 1},
+ {Version{1, 2, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 0},
+ {Version{2, 2, 4, nil, nil}, Version{1, 2, 4, nil, nil}, 1},
+ {Version{1, 3, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 1},
+ {Version{1, 2, 4, nil, nil}, Version{1, 2, 3, nil, nil}, 1},
+
+ // Spec Examples #11
+ {Version{1, 0, 0, nil, nil}, Version{2, 0, 0, nil, nil}, -1},
+ {Version{2, 0, 0, nil, nil}, Version{2, 1, 0, nil, nil}, -1},
+ {Version{2, 1, 0, nil, nil}, Version{2, 1, 1, nil, nil}, -1},
+
+ // Spec Examples #9
+ {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, 1},
+ {Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, -1},
+ {Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, Version{1, 0, 0, nil, nil}, -1},
+
+ // Ignore Build metadata
+ {Version{1, 0, 0, nil, []string{"1", "2", "3"}}, Version{1, 0, 0, nil, nil}, 0},
+}
+
+func TestCompare(t *testing.T) {
+ for _, test := range compareTests {
+ if res := test.v1.Compare(test.v2); res != test.result {
+ t.Errorf("Comparing %q : %q, expected %d but got %d", test.v1, test.v2, test.result, res)
+ }
+ //Test counterpart
+ if res := test.v2.Compare(test.v1); res != -test.result {
+ t.Errorf("Comparing %q : %q, expected %d but got %d", test.v2, test.v1, -test.result, res)
+ }
+ }
+}
+
+type wrongformatTest struct {
+ v *Version
+ str string
+}
+
+var wrongformatTests = []wrongformatTest{
+ {nil, ""},
+ {nil, "."},
+ {nil, "1."},
+ {nil, ".1"},
+ {nil, "a.b.c"},
+ {nil, "1.a.b"},
+ {nil, "1.1.a"},
+ {nil, "1.a.1"},
+ {nil, "a.1.1"},
+ {nil, ".."},
+ {nil, "1.."},
+ {nil, "1.1."},
+ {nil, "1..1"},
+ {nil, "1.1.+123"},
+ {nil, "1.1.-beta"},
+ {nil, "-1.1.1"},
+ {nil, "1.-1.1"},
+ {nil, "1.1.-1"},
+ // giant numbers
+ {nil, "20000000000000000000.1.1"},
+ {nil, "1.20000000000000000000.1"},
+ {nil, "1.1.20000000000000000000"},
+ {nil, "1.1.1-20000000000000000000"},
+ // Leading zeroes
+ {nil, "01.1.1"},
+ {nil, "001.1.1"},
+ {nil, "1.01.1"},
+ {nil, "1.001.1"},
+ {nil, "1.1.01"},
+ {nil, "1.1.001"},
+ {nil, "1.1.1-01"},
+ {nil, "1.1.1-001"},
+ {nil, "1.1.1-beta.01"},
+ {nil, "1.1.1-beta.001"},
+ {&Version{0, 0, 0, []PRVersion{prstr("!")}, nil}, "0.0.0-!"},
+ {&Version{0, 0, 0, nil, []string{"!"}}, "0.0.0+!"},
+ // empty prversion
+ {&Version{0, 0, 0, []PRVersion{prstr(""), prstr("alpha")}, nil}, "0.0.0-.alpha"},
+ // empty build meta data
+ {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{""}}, "0.0.0-alpha+"},
+ {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{"test", ""}}, "0.0.0-alpha+test."},
+}
+
+func TestWrongFormat(t *testing.T) {
+ for _, test := range wrongformatTests {
+
+ if res, err := Parse(test.str); err == nil {
+ t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res)
+ }
+
+ if test.v != nil {
+ if err := test.v.Validate(); err == nil {
+ t.Errorf("Validating wrong format version %q (%q), expected error", test.v, test.str)
+ }
+ }
+ }
+}
+
+var wrongTolerantFormatTests = []wrongformatTest{
+ {nil, "1.0+abc"},
+ {nil, "1.0-rc.1"},
+}
+
+func TestWrongTolerantFormat(t *testing.T) {
+ for _, test := range wrongTolerantFormatTests {
+ if res, err := ParseTolerant(test.str); err == nil {
+ t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res)
+ }
+ }
+}
+
+func TestCompareHelper(t *testing.T) {
+ v := Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}
+ v1 := Version{1, 0, 0, nil, nil}
+ if !v.EQ(v) {
+ t.Errorf("%q should be equal to %q", v, v)
+ }
+ if !v.Equals(v) {
+ t.Errorf("%q should be equal to %q", v, v)
+ }
+ if !v1.NE(v) {
+ t.Errorf("%q should not be equal to %q", v1, v)
+ }
+ if !v.GTE(v) {
+ t.Errorf("%q should be greater than or equal to %q", v, v)
+ }
+ if !v.LTE(v) {
+ t.Errorf("%q should be less than or equal to %q", v, v)
+ }
+ if !v.LT(v1) {
+ t.Errorf("%q should be less than %q", v, v1)
+ }
+ if !v.LTE(v1) {
+ t.Errorf("%q should be less than or equal %q", v, v1)
+ }
+ if !v.LE(v1) {
+ t.Errorf("%q should be less than or equal %q", v, v1)
+ }
+ if !v1.GT(v) {
+ t.Errorf("%q should be greater than %q", v1, v)
+ }
+ if !v1.GTE(v) {
+ t.Errorf("%q should be greater than or equal %q", v1, v)
+ }
+ if !v1.GE(v) {
+ t.Errorf("%q should be greater than or equal %q", v1, v)
+ }
+}
+
+func TestPreReleaseVersions(t *testing.T) {
+ p1, err := NewPRVersion("123")
+ if !p1.IsNumeric() {
+ t.Errorf("Expected numeric prversion, got %q", p1)
+ }
+ if p1.VersionNum != 123 {
+ t.Error("Wrong prversion number")
+ }
+ if err != nil {
+ t.Errorf("Not expected error %q", err)
+ }
+ p2, err := NewPRVersion("alpha")
+ if p2.IsNumeric() {
+ t.Errorf("Expected non-numeric prversion, got %q", p2)
+ }
+ if p2.VersionStr != "alpha" {
+ t.Error("Wrong prversion string")
+ }
+ if err != nil {
+ t.Errorf("Not expected error %q", err)
+ }
+}
+
+func TestBuildMetaDataVersions(t *testing.T) {
+ _, err := NewBuildVersion("123")
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ _, err = NewBuildVersion("build")
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ _, err = NewBuildVersion("test?")
+ if err == nil {
+ t.Error("Expected error, got none")
+ }
+
+ _, err = NewBuildVersion("")
+ if err == nil {
+ t.Error("Expected error, got none")
+ }
+}
+
+func TestNewHelper(t *testing.T) {
+ v, err := New("1.2.3")
+ if err != nil {
+ t.Fatalf("Unexpected error %q", err)
+ }
+
+ // New returns pointer
+ if v == nil {
+ t.Fatal("Version is nil")
+ }
+ if v.Compare(Version{1, 2, 3, nil, nil}) != 0 {
+ t.Fatal("Unexpected comparison problem")
+ }
+}
+
+func TestMakeHelper(t *testing.T) {
+ v, err := Make("1.2.3")
+ if err != nil {
+ t.Fatalf("Unexpected error %q", err)
+ }
+ if v.Compare(Version{1, 2, 3, nil, nil}) != 0 {
+ t.Fatal("Unexpected comparison problem")
+ }
+}
+
+func BenchmarkParseSimple(b *testing.B) {
+ const VERSION = "0.0.1"
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ Parse(VERSION)
+ }
+}
+
+func BenchmarkParseComplex(b *testing.B) {
+ const VERSION = "0.0.1-alpha.preview+123.456"
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ Parse(VERSION)
+ }
+}
+
+func BenchmarkParseAverage(b *testing.B) {
+ l := len(formatTests)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ Parse(formatTests[n%l].result)
+ }
+}
+
+func BenchmarkParseTolerantAverage(b *testing.B) {
+ l := len(tolerantFormatTests)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ ParseTolerant(tolerantFormatTests[n%l].result)
+ }
+}
+
+func BenchmarkStringSimple(b *testing.B) {
+ const VERSION = "0.0.1"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.String()
+ }
+}
+
+func BenchmarkStringLarger(b *testing.B) {
+ const VERSION = "11.15.2012"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.String()
+ }
+}
+
+func BenchmarkStringComplex(b *testing.B) {
+ const VERSION = "0.0.1-alpha.preview+123.456"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.String()
+ }
+}
+
+func BenchmarkStringAverage(b *testing.B) {
+ l := len(formatTests)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ formatTests[n%l].v.String()
+ }
+}
+
+func BenchmarkValidateSimple(b *testing.B) {
+ const VERSION = "0.0.1"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.Validate()
+ }
+}
+
+func BenchmarkValidateComplex(b *testing.B) {
+ const VERSION = "0.0.1-alpha.preview+123.456"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.Validate()
+ }
+}
+
+func BenchmarkValidateAverage(b *testing.B) {
+ l := len(formatTests)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ formatTests[n%l].v.Validate()
+ }
+}
+
+func BenchmarkCompareSimple(b *testing.B) {
+ const VERSION = "0.0.1"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.Compare(v)
+ }
+}
+
+func BenchmarkCompareComplex(b *testing.B) {
+ const VERSION = "0.0.1-alpha.preview+123.456"
+ v, _ := Parse(VERSION)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ v.Compare(v)
+ }
+}
+
+func BenchmarkCompareAverage(b *testing.B) {
+ l := len(compareTests)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ compareTests[n%l].v1.Compare((compareTests[n%l].v2))
+ }
+}
diff --git a/vendor/github.com/blang/semver/sort.go b/vendor/github.com/blang/semver/sort.go
new file mode 100644
index 0000000..e18f880
--- /dev/null
+++ b/vendor/github.com/blang/semver/sort.go
@@ -0,0 +1,28 @@
+package semver
+
+import (
+ "sort"
+)
+
+// Versions represents multiple versions.
+type Versions []Version
+
+// Len returns length of version collection
+func (s Versions) Len() int {
+ return len(s)
+}
+
+// Swap swaps two versions inside the collection by its indices
+func (s Versions) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Less checks if version at index i is less than version at index j
+func (s Versions) Less(i, j int) bool {
+ return s[i].LT(s[j])
+}
+
+// Sort sorts a slice of versions
+func Sort(versions []Version) {
+ sort.Sort(Versions(versions))
+}
diff --git a/vendor/github.com/blang/semver/sort_test.go b/vendor/github.com/blang/semver/sort_test.go
new file mode 100644
index 0000000..6889397
--- /dev/null
+++ b/vendor/github.com/blang/semver/sort_test.go
@@ -0,0 +1,30 @@
+package semver
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestSort(t *testing.T) {
+ v100, _ := Parse("1.0.0")
+ v010, _ := Parse("0.1.0")
+ v001, _ := Parse("0.0.1")
+ versions := []Version{v010, v100, v001}
+ Sort(versions)
+
+ correct := []Version{v001, v010, v100}
+ if !reflect.DeepEqual(versions, correct) {
+ t.Fatalf("Sort returned wrong order: %s", versions)
+ }
+}
+
+func BenchmarkSort(b *testing.B) {
+ v100, _ := Parse("1.0.0")
+ v010, _ := Parse("0.1.0")
+ v001, _ := Parse("0.0.1")
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ Sort([]Version{v010, v100, v001})
+ }
+}
diff --git a/vendor/github.com/blang/semver/sql.go b/vendor/github.com/blang/semver/sql.go
new file mode 100644
index 0000000..eb4d802
--- /dev/null
+++ b/vendor/github.com/blang/semver/sql.go
@@ -0,0 +1,30 @@
+package semver
+
+import (
+ "database/sql/driver"
+ "fmt"
+)
+
+// Scan implements the database/sql.Scanner interface.
+func (v *Version) Scan(src interface{}) (err error) {
+ var str string
+ switch src := src.(type) {
+ case string:
+ str = src
+ case []byte:
+ str = string(src)
+ default:
+ return fmt.Errorf("Version.Scan: cannot convert %T to string.", src)
+ }
+
+ if t, err := Parse(str); err == nil {
+ *v = t
+ }
+
+ return
+}
+
+// Value implements the database/sql/driver.Valuer interface.
+func (v Version) Value() (driver.Value, error) {
+ return v.String(), nil
+}
diff --git a/vendor/github.com/blang/semver/sql_test.go b/vendor/github.com/blang/semver/sql_test.go
new file mode 100644
index 0000000..ebf48b5
--- /dev/null
+++ b/vendor/github.com/blang/semver/sql_test.go
@@ -0,0 +1,38 @@
+package semver
+
+import (
+ "testing"
+)
+
+type scanTest struct {
+ val interface{}
+ shouldError bool
+ expected string
+}
+
+var scanTests = []scanTest{
+ {"1.2.3", false, "1.2.3"},
+ {[]byte("1.2.3"), false, "1.2.3"},
+ {7, true, ""},
+ {7e4, true, ""},
+ {true, true, ""},
+}
+
+func TestScanString(t *testing.T) {
+ for _, tc := range scanTests {
+ s := &Version{}
+ err := s.Scan(tc.val)
+ if tc.shouldError {
+ if err == nil {
+ t.Fatalf("Scan did not return an error on %v (%T)", tc.val, tc.val)
+ }
+ } else {
+ if err != nil {
+ t.Fatalf("Scan returned an unexpected error: %s (%T) on %v (%T)", tc.val, tc.val, tc.val, tc.val)
+ }
+ if val, _ := s.Value(); val != tc.expected {
+ t.Errorf("Wrong Value returned, expected %q, got %q", tc.expected, val)
+ }
+ }
+ }
+}
diff --git a/version.go b/version.go
new file mode 100644
index 0000000..b1faa86
--- /dev/null
+++ b/version.go
@@ -0,0 +1,23 @@
+// Copyright 2017-2018 DERO Project. All rights reserved.
+// Use of this source code in any form is governed by RESEARCH license.
+// license can be found in the LICENSE file.
+// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package main
+
+import "github.com/blang/semver"
+
+// right now it has to be manually changed
+// do we need to include git commitsha??
+var Version = semver.MustParse("0.0.2-1.alpha.atlantis+31072018")
diff --git a/wallet.qrc b/wallet.qrc
new file mode 100644
index 0000000..7fa38b2
--- /dev/null
+++ b/wallet.qrc
@@ -0,0 +1,48 @@
+
+
+ main.qml
+ mainwallet.qml
+ qtquickcontrols2.conf
+ images/arrow.png
+ images/arrow@2x.png
+ images/arrow@3x.png
+ images/arrow@4x.png
+ images/arrows.png
+ images/arrows@2x.png
+ images/arrows@3x.png
+ images/arrows@4x.png
+ images/back.png
+ images/back@2x.png
+ images/back@3x.png
+ images/back@4x.png
+ images/drawer.png
+ images/drawer@2x.png
+ images/drawer@3x.png
+ images/drawer@4x.png
+ images/menu.png
+ images/menu@2x.png
+ images/menu@3x.png
+ images/menu@4x.png
+ images/+material/back.png
+ images/+material/back@2x.png
+ images/+material/back@3x.png
+ images/+material/back@4x.png
+ images/+material/drawer.png
+ images/+material/drawer@2x.png
+ images/+material/drawer@3x.png
+ images/+material/drawer@4x.png
+ images/+material/menu.png
+ images/+material/menu@2x.png
+ images/+material/menu@3x.png
+ images/+material/menu@4x.png
+ images/copy.svg
+ images/qt-logo.png
+ images/qt-logo@2x.png
+ images/qt-logo@3x.png
+ images/qt-logo@4x.png
+ images/dero-front-logo.png
+ images/dero-front-logo@2x.png
+ images/dero-front-logo@3x.png
+ images/dero-front-logo@4x.png
+
+
diff --git a/walletapi_wrapper.go b/walletapi_wrapper.go
new file mode 100644
index 0000000..fa3d7bb
--- /dev/null
+++ b/walletapi_wrapper.go
@@ -0,0 +1,558 @@
+// Copyright 2017-2018 DERO Project. All rights reserved.
+// Use of this source code in any form is governed by RESEARCH license.
+// license can be found in the LICENSE file.
+// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package main
+
+import "fmt"
+import "time"
+import "runtime"
+import "strings"
+import "path/filepath"
+import "encoding/hex"
+import "encoding/json"
+import "github.com/deroproject/derosuite/walletapi"
+import "github.com/deroproject/derosuite/globals"
+import "github.com/deroproject/derosuite/crypto"
+import "github.com/deroproject/derosuite/address"
+import "github.com/deroproject/derosuite/transaction"
+
+// this goroutine continuously updates height/balances if a wallet is open
+func update_heights_balances() {
+
+ // counter := 0
+ for {
+ //time.Sleep(time.Second)
+ time.Sleep(100 * time.Millisecond)
+
+ if global_object != nil && global_object.walletptr != nil {
+ global_object.Lock()
+ //counter++
+ global_object.SetHeight(int64(global_object.walletptr.Get_Height()))
+ //global_object.SetHeight(int64(counter))
+ global_object.SetTopoheight(int64(global_object.walletptr.Get_TopoHeight()))
+
+ if global_object.walletptr.GetMode() {
+ global_object.SetNwheight(int64(global_object.walletptr.Get_Daemon_Height()))
+ } else {
+ global_object.SetNwheight(int64(0))
+ }
+
+ u, l := global_object.walletptr.Get_Balance()
+ global_object.SetTotal_balance(globals.FormatMoney12(l + u))
+ global_object.SetUnlocked_balance(globals.FormatMoney12(u))
+ global_object.SetLocked_balance(globals.FormatMoney12(l))
+
+ global_object.Unlock()
+ }
+ }
+}
+
+func (t *CtxObject) addressVerify(addr string) {
+ if global_object != nil && global_object.walletptr != nil {
+ addr, err := globals.ParseValidateAddress(addr)
+ if err == nil {
+ global_object.SetAddressverified(true)
+ if addr.IsIntegratedAddress() {
+ global_object.SetAddressintegrated(true)
+ global_object.SetAddressipaymentid(fmt.Sprintf("%x", addr.PaymentID))
+ } else {
+ global_object.SetAddressintegrated(false)
+ global_object.SetAddressipaymentid("")
+ }
+ return
+ } else {
+ global_object.SetAddressverified(false)
+ global_object.SetAddressintegrated(false)
+ // fmt.Println("addressVerify: %s err %s", addr, err)
+ return
+ }
+ }
+
+ global_object.SetAddressverified(false)
+ global_object.SetAddressintegrated(false)
+ //global_object.SetAddressipaymentid("")
+
+ // fmt.Println("addressVerify: %s err wallet not ready", addr)
+
+}
+
+func (t *CtxObject) paymentidVerify(payid string) {
+
+ // paymentid is 16 or 64 hex chars
+ lpayid := strings.TrimSpace(payid)
+
+ lpayid_raw, err := hex.DecodeString(lpayid)
+
+ if err != nil {
+ global_object.SetPaymentidverified(false)
+ return
+ }
+
+ switch len(lpayid_raw) {
+ case 0, 8, 32:
+ global_object.SetPaymentidverified(true)
+ return
+ default:
+ global_object.SetPaymentidverified(false)
+ }
+
+ global_object.SetPaymentidverified(false)
+
+}
+
+func (t *CtxObject) amountVerify(amountstr string) {
+
+ // paymentid is 16 or 64 hex chars
+ lamountstr := strings.TrimSpace(amountstr)
+
+ _, err := globals.ParseAmount(lamountstr)
+
+ if err != nil {
+ global_object.SetAmountverified(false)
+ return
+ }
+
+ global_object.SetAmountverified(true)
+
+}
+
+// generate and update all integrated addresses
+func (t *CtxObject) genintegratedaddress() {
+ if global_object != nil && global_object.walletptr != nil {
+
+ addr := global_object.walletptr.GetAddress()
+ i32 := global_object.walletptr.GetRandomIAddress32()
+ i8 := global_object.walletptr.GetRandomIAddress8()
+
+ global_object.SetWallet_address(addr.String())
+
+ global_object.SetIntegrated_32_address(i32.String())
+ global_object.SetIntegrated_32_address_paymentid(fmt.Sprintf("%X", i32.PaymentID))
+
+ global_object.SetIntegrated_8_address(i8.String())
+ global_object.SetIntegrated_8_address_paymentid(fmt.Sprintf("%X", i8.PaymentID))
+ }
+}
+
+// generate and update all integrated addresses
+func (t *CtxObject) reloadhistory(available, in, out bool, max_limit int64) {
+
+ var listheight []string
+ var listtopoheight []string
+
+ var listtxid []string
+ var listamount []string
+ var listpaymentid []string
+
+ var liststatus []string
+ var listunlocktime []string
+
+ var listdetails []string
+
+ defer func() {
+ global_object.SetHistoryListHeight(listheight)
+ global_object.SetHistoryListTopoHeight(listtopoheight)
+
+ global_object.SetHistoryListTXID(listtxid)
+ global_object.SetHistoryListAmount(listamount)
+ global_object.SetHistoryListPaymentID(listpaymentid)
+
+ global_object.SetHistoryListStatus(liststatus)
+ global_object.SetHistoryListUnlockTime(listunlocktime)
+
+ global_object.SetHistoryListOutDetails(listdetails)
+
+ }()
+
+ if global_object != nil && global_object.walletptr != nil {
+
+ min_height := uint64(0)
+ max_height := uint64(0)
+ pool := false
+ transfers := global_object.walletptr.Show_Transfers(available, in, out, pool, false, false, min_height, max_height) // receives sorted
+
+ if len(transfers) == 0 {
+ return
+ }
+
+ for i := range transfers {
+ if i < int(max_limit) { // only return max results
+
+ listheight = append(listheight, fmt.Sprintf("%d", transfers[i].Height))
+ listtopoheight = append(listtopoheight, fmt.Sprintf("%d", transfers[i].TopoHeight))
+
+ listtxid = append(listtxid, transfers[i].TXID.String())
+ listamount = append(listamount, globals.FormatMoney12(transfers[i].Amount))
+ listpaymentid = append(listpaymentid, fmt.Sprintf("%x ", transfers[i].PaymentID))
+
+ liststatus = append(liststatus, fmt.Sprintf("%d", transfers[i].Status))
+ listunlocktime = append(listunlocktime, fmt.Sprintf("%d", transfers[i].Unlock_Time))
+
+ outdetails := false
+ if transfers[i].Status == 1 { // if tx is outgoing, try to get object and serialize it if okay
+ details := global_object.walletptr.GetTXOutDetails(transfers[i].TXID)
+ if details.Fees != 0 { // if fees is not zero, we have good data, process it now
+ details_string, err := json.Marshal(&details)
+ if err == nil {
+ listdetails = append(listdetails, string(details_string))
+ outdetails = true
+
+ // fmt.Printf("go full deteail %d %d\n", i,transfers[i].Height)
+ }
+ }
+ }
+
+ if !outdetails {
+ listdetails = append(listdetails, " ") // empty strings have issues
+ // fmt.Printf("skipped deteail %d %d\n", i,transfers[i].Height)
+ }
+
+ }
+ }
+ }
+}
+
+// create wallet using recovery key
+func (t *CtxObject) recoverusingkey(filename, password, seed_key_string string) {
+
+ t.Lock()
+ defer t.Unlock()
+ //fmt.Printf("recoverusingkey file %s", filename)
+
+ if global_object != nil && global_object.walletptr != nil {
+ return
+ }
+
+ if runtime.GOOS == "windows" {
+ filename = strings.TrimPrefix(filename, "/")
+ filename = strings.TrimPrefix(filename, "\\")
+ }
+ var seedkey crypto.Key
+
+ seed_raw, err := hex.DecodeString(seed_key_string) // hex decode
+ if len(seed_key_string) != 64 || err != nil { //sanity check
+ global_object.SetIniterr("Key must be 64 chars hexadecimal chars")
+ return
+ }
+
+ copy(seedkey[:], seed_raw[:32])
+
+ walletptr, err := walletapi.Create_Encrypted_Wallet(filepath.Join(filename, "wallet.db"), password, seedkey)
+ if err != nil {
+ globals.Logger.Warnf("Error while recovering wallet using seed key err %s\n", err)
+ global_object.SetIniterr(fmt.Sprintf("Error while recovering wallet using key err %s", err))
+ return
+ }
+
+ // we are here means wallet opened successfully
+ t.Common_Wallet_Setup(walletptr)
+}
+
+// create wallet using recovery key
+func (t *CtxObject) recoverusingseedwords(filename, password, seed_key_string string) {
+
+ t.Lock()
+ defer t.Unlock()
+ // fmt.Printf("recoverusingkey file %s", filename)
+
+ if global_object != nil && global_object.walletptr != nil {
+ return
+ }
+
+ if runtime.GOOS == "windows" {
+ filename = strings.TrimPrefix(filename, "/")
+ filename = strings.TrimPrefix(filename, "\\")
+ }
+
+ walletptr, err := walletapi.Create_Encrypted_Wallet_From_Recovery_Words(filepath.Join(filename, "wallet.db"), password, seed_key_string)
+ if err != nil {
+ //globals.Logger.Warnf("Error while recovering wallet using seed words err %s\n", err)
+ global_object.SetIniterr(fmt.Sprintf("Error while recovering wallet using seed words err %s", err))
+ return
+ }
+
+ // we are here means wallet opened successfully
+ t.Common_Wallet_Setup(walletptr)
+}
+
+// create wallet using recovery key
+func (t *CtxObject) openwallet(filename, password string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+ return
+ }
+
+ if runtime.GOOS == "windows" {
+ filename = strings.TrimPrefix(filename, "/")
+ filename = strings.TrimPrefix(filename, "\\")
+ }
+
+ //fmt.Printf("openwallet file %s\n", filename)
+ walletptr, err := walletapi.Open_Encrypted_Wallet(filename, password)
+ if err != nil {
+ //globals.Logger.Warnf("Error while recovering wallet using seed key err %s\n", err)
+ global_object.SetIniterr(fmt.Sprintf("Error occurred while opening wallet file %s. err %s", filename, err))
+ return
+ }
+
+ // we are here means wallet opened successfully
+ t.Common_Wallet_Setup(walletptr)
+}
+
+// create new wallet
+func (t *CtxObject) createnewwallet(filename, password string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+ return
+ }
+
+ if runtime.GOOS == "windows" {
+ filename = strings.TrimPrefix(filename, "/")
+ filename = strings.TrimPrefix(filename, "\\")
+ }
+
+ //fmt.Printf("createnewwallet file %s", filename)
+ walletptr, err := walletapi.Create_Encrypted_Wallet_Random(filepath.Join(filename, "wallet.db"), password)
+ if err != nil {
+ //globals.Logger.Warnf("Error while recovering wallet using seed key err %s\n", err)
+ global_object.SetIniterr(fmt.Sprintf("Error occured while creating new wallet file %s. err %s", filename, err))
+ return
+ }
+
+ // we are here means wallet opened successfully
+ t.Common_Wallet_Setup(walletptr)
+}
+
+func (t *CtxObject) Common_Wallet_Setup(walletptr *walletapi.Wallet) {
+
+ global_object.walletptr = walletptr
+
+ addr := global_object.walletptr.GetAddress()
+ global_object.SetWallet_address(addr.String())
+
+ global_object.SetWallet_valid(true) // mark wallet as valid
+
+}
+
+// check whether users knows the current password or not
+func (t *CtxObject) checkpassword(password string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object == nil || global_object.walletptr == nil {
+ global_object.SetIniterr(fmt.Sprintf("Wallet not yet opened"))
+ return
+ }
+
+ if global_object.walletptr.Check_Password(password) {
+ global_object.SetIniterr("")
+ } else {
+ global_object.SetIniterr(fmt.Sprintf("Invalid Password"))
+ }
+
+}
+
+// set new wallet, password
+// password must have been checked before
+func (t *CtxObject) setpassword(oldpassword, password string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object == nil || global_object.walletptr == nil {
+ global_object.SetIniterr(fmt.Sprintf("Wallet not yet opened"))
+ return
+ }
+
+ if global_object.walletptr.Check_Password(oldpassword) {
+ global_object.SetIniterr("")
+ } else {
+ global_object.SetIniterr(fmt.Sprintf("Invalid Password"))
+ }
+
+ err := global_object.walletptr.Set_Encrypted_Wallet_Password(password)
+ if err != nil {
+ global_object.SetIniterr(fmt.Sprintf("Cannot set new password, err %s", err))
+ }
+}
+
+func (t *CtxObject) build_tx(destination, amount_str, paymentid string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object == nil || global_object.walletptr == nil {
+ global_object.SetIniterr(fmt.Sprintf("Wallet not yet opened"))
+ return
+ }
+
+ addr, err := globals.ParseValidateAddress(destination)
+ if err != nil {
+ global_object.SetIniterr(err.Error())
+ return
+ }
+
+ amount_to_transfer, err := globals.ParseAmount(amount_str)
+ if err != nil {
+ global_object.SetIniterr(err.Error())
+ return
+
+ }
+
+ lpayid := strings.TrimSpace(paymentid)
+
+ // if integrated address, payment id should be ignored
+ if fmt.Sprintf("%X", addr.PaymentID) == lpayid {
+ lpayid = ""
+ }
+
+ lpayid_raw, err := hex.DecodeString(lpayid)
+
+ if err != nil {
+ global_object.SetIniterr(err.Error())
+ return
+ }
+
+ switch len(lpayid_raw) {
+ case 0, 8, 32:
+ default:
+ global_object.SetIniterr(fmt.Sprintf("Invalid payment ID"))
+ return
+ }
+
+ addr_list := []address.Address{*addr}
+ amount_list := []uint64{amount_to_transfer} // transfer 50 dero, 2 dero
+ fees_per_kb := uint64(0) // fees must be calculated by walletapi
+
+ tx, inputs, input_sum, change, err := global_object.walletptr.Transfer(addr_list, amount_list, 0, lpayid, fees_per_kb, 0)
+ _ = inputs
+ if err != nil {
+ global_object.SetIniterr(fmt.Sprintf("Error while building Transaction err %s", err))
+ return
+
+ }
+
+ // now setup properties for qt to display some info and confirm
+ global_object.SetTx_hex(hex.EncodeToString(tx.Serialize()))
+ global_object.SetTxid_hex(tx.GetHash().String())
+ global_object.SetTx_total(globals.FormatMoney12(input_sum))
+ global_object.SetTx_transfer_amount(globals.FormatMoney12(amount_to_transfer))
+ global_object.SetTx_change(globals.FormatMoney12(change))
+ global_object.SetTx_fees(globals.FormatMoney12(tx.RctSignature.Get_TX_Fee()))
+
+ global_object.SetIniterr("") // mark as no error occurred
+}
+
+// create new wallet
+func (t *CtxObject) relay_tx(tx_hex string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object == nil || global_object.walletptr == nil {
+ global_object.SetIniterr(fmt.Sprintf("Wallet not yet opened"))
+ return
+ }
+
+ global_object.SetIniterr("") // this does NOT work, we must clean up the property from QML side, everywhere
+
+ tx_raw, err := hex.DecodeString(tx_hex)
+
+ if err != nil {
+ global_object.SetIniterr(err.Error())
+ return
+ }
+
+ // deserialize tx
+ var tx transaction.Transaction
+
+ err = tx.DeserializeHeader(tx_raw)
+
+ if err != nil {
+ global_object.SetIniterr(fmt.Sprintf("Error relaying TX, err %s", err))
+ return
+ }
+
+ err = global_object.walletptr.SendTransaction(&tx)
+
+ if err != nil {
+ global_object.SetIniterr(fmt.Sprintf("Error relaying TX, err %s", err))
+ return
+ }
+
+ // global_object.SetIniterr("TODO TX relaying not supported")
+}
+
+// set wallet online
+func (t *CtxObject) setwalletonline(wallet_server_address string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+ global_object.walletptr.SetDaemonAddress(wallet_server_address) // set remote mode
+ global_object.walletptr.SetOnlineMode()
+
+ }
+}
+
+// set wallet online
+func (t *CtxObject) setwalletoffline() {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+
+ global_object.walletptr.SetOfflineMode()
+
+ }
+}
+
+// create new wallet
+func (t *CtxObject) seed_language(lang string) {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+ global_object.SetSeed(global_object.walletptr.GetSeedinLanguage(lang))
+
+ return
+ }
+
+}
+
+// create new wallet
+func (t *CtxObject) closewallet() {
+ t.Lock()
+ defer t.Unlock()
+
+ if global_object != nil && global_object.walletptr != nil {
+ tmp := global_object.walletptr
+
+ global_object.SetWallet_valid(false)
+ global_object.SetWallet_address("")
+ global_object.walletptr = nil
+
+ global_object.SetIntegrated_32_address(" ")
+ global_object.SetIntegrated_32_address_paymentid(" ")
+
+ global_object.SetIntegrated_8_address(" ")
+ global_object.SetIntegrated_8_address_paymentid(" ")
+
+ tmp.Close_Encrypted_Wallet()
+ }
+
+}